Skip to content

Commit bc21ed0

Browse files
committed
Update testing infrastructure, add x86test for io.rs
1 parent fd97c21 commit bc21ed0

File tree

17 files changed

+227
-115
lines changed

17 files changed

+227
-115
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ matrix:
2323

2424
# Linux
2525
- env: TARGET=i686-unknown-linux-gnu DISABLE_TESTS=1
26-
- env: TARGET=x86_64-unknown-linux-gnu DISABLE_TESTS=1
26+
- env: TARGET=x86_64-unknown-linux-gnu
2727

2828
# OSX
2929
- env: TARGET=i686-apple-darwin DISABLE_TESTS=1

Cargo.toml

+7-4
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ edition = '2018'
2626

2727
[features]
2828
performance-counter = ["phf", "phf_codegen", "csv", "serde_json"]
29-
30-
#[[test]]
31-
#name = "no_std_build"
32-
#harness = false
29+
# Note we have to choose between regular tests and x86test at the moment, so we use features
30+
# (limitation in https://github.com/rust-lang/rust/issues/50297)
31+
# Run user-space tests, i.e. regular #[test]
32+
utest = []
33+
# Run VM tests, i.e., the #[x86test] ones
34+
vmtest = []
3335

3436
[[test]]
3537
name = "kvm"
@@ -53,3 +55,4 @@ features = ["core"]
5355
klogger = { git = "https://github.com/gz/rust-klogger.git", features = ["use_ioports"] }
5456
x86test = { path = "x86test" }
5557
libc = "0.2.*"
58+

README.md

+12
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ Currently supports
2121

2222
This library depends on libcore so it can be used in kernel level code.
2323

24+
## Testing
25+
26+
We use two forms of tests for the crate. Regular tests with `#[test]` than run in as a regular process
27+
and `#[x86test]` tests that run in a VM (and require a privileged execution environment).
28+
29+
```
30+
# To execute x86tests run:
31+
$ RUSTFLAGS="-C relocation-model=dynamic-no-pic -C code-model=kernel" RUST_BACKTRACE=1 cargo test --features vmtest
32+
33+
# To execute the regular tests, run:
34+
$ cargo test --features utest
35+
```
2436
## Features
2537

2638
* performance-counter: Includes the performance counter information. Note this feature

ci/script.sh

+6-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
set -ex
44

5-
# TODO This is the "test phase", tweak it as you see fit
5+
# This is the "test phase", tweak it as you see fit
66
main() {
77
cross build --target $TARGET
88
cross build --target $TARGET --release
@@ -11,11 +11,12 @@ main() {
1111
return
1212
fi
1313

14-
cross test --target $TARGET
15-
cross test --target $TARGET --release
14+
# Run user-space tests
15+
cross test --target $TARGET --features utest
16+
cross test --target $TARGET --release --features utest
1617

17-
cross run --target $TARGET
18-
cross run --target $TARGET --release
18+
# Run KVM tests
19+
RUSTFLAGS="-C relocation-model=dynamic-no-pic -C code-model=kernel" RUST_BACKTRACE=1 cross test --target $TARGET --features vmtest
1920
}
2021

2122
# we don't run the "test phase" when doing deploys

src/bits64/paging.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,7 @@ impl PTEntry {
11651165
is_instruction_fetching_disabled, PTFlags::XD);
11661166
}
11671167

1168-
#[cfg(test)]
1168+
#[cfg(all(test, feature = "utest"))]
11691169
mod test {
11701170
use super::*;
11711171

src/io.rs

+72-41
Original file line numberDiff line numberDiff line change
@@ -42,50 +42,81 @@ pub unsafe fn inl(port: u16) -> u32 {
4242
ret
4343
}
4444

45-
/// Write 8-bit array to port
46-
#[inline]
47-
pub unsafe fn outsb(port: u16, buf: &[u8]) {
48-
asm!("rep outsb (%esi), %dx"
49-
:: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr())
50-
: "ecx", "edi");
51-
}
45+
#[cfg(all(test, feature = "vmtest"))]
46+
mod x86testing {
47+
use super::*;
48+
use x86test::*;
5249

53-
/// Read 8-bit array from port
54-
#[inline]
55-
pub unsafe fn insb(port: u16, buf: &mut [u8]) {
56-
asm!("rep insb %dx, (%edi)"
57-
:: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr())
58-
: "ecx", "edi" : "volatile");
59-
}
50+
#[x86test(ioport(0x0, 0xaf))]
51+
fn check_outb() {
52+
unsafe {
53+
outb(0x0, 0xaf);
54+
// hypervisor will fail here if port 0x0 doesn't see 0xaf
55+
}
56+
}
6057

61-
/// Write 16-bit array to port
62-
#[inline]
63-
pub unsafe fn outsw(port: u16, buf: &[u16]) {
64-
asm!("rep outsw (%esi), %dx"
65-
:: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr())
66-
: "ecx", "edi");
67-
}
58+
#[x86test(ioport(0x0, 0xaf))]
59+
#[should_panic]
60+
fn check_outb_wrong_value() {
61+
unsafe {
62+
outb(0x0, 0xff);
63+
}
64+
}
6865

69-
/// Read 16-bit array from port
70-
#[inline]
71-
pub unsafe fn insw(port: u16, buf: &mut [u16]) {
72-
asm!("rep insw %dx, (%edi)"
73-
:: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr())
74-
: "ecx", "edi" : "volatile");
75-
}
66+
#[x86test(ioport(0x1, 0xad))]
67+
fn check_inb() {
68+
unsafe {
69+
kassert!(
70+
inb(0x1) == 0xad,
71+
"`inb` instruction didn't read the correct value"
72+
);
73+
}
74+
}
7675

77-
/// Write 32-bit array to port
78-
#[inline]
79-
pub unsafe fn outsl(port: u16, buf: &[u32]) {
80-
asm!("rep outsl (%esi), %dx"
81-
:: "{ecx}"(buf.len()), "{dx}"(port), "{esi}"(buf.as_ptr())
82-
: "ecx", "edi");
83-
}
76+
#[x86test(ioport(0x2, 0xad))]
77+
#[should_panic]
78+
fn check_inb_wrong_port() {
79+
unsafe {
80+
kassert!(
81+
inb(0x1) == 0xad,
82+
"`inb` instruction didn't read the correct value"
83+
);
84+
}
85+
}
8486

85-
/// Read 32-bit array from port
86-
#[inline]
87-
pub unsafe fn insl(port: u16, buf: &mut [u32]) {
88-
asm!("rep insl %dx, (%edi)"
89-
:: "{ecx}"(buf.len()), "{dx}"(port), "{edi}"(buf.as_ptr())
90-
: "ecx", "edi" : "volatile");
87+
#[x86test(ioport(0x2, 0x99))]
88+
fn check_outw() {
89+
unsafe {
90+
super::outw(0x2, 0x99);
91+
// hypervisor will fail here if port 0x2 doesn't see 0x99
92+
}
93+
}
94+
95+
#[x86test(ioport(0x3, 0xfefe))]
96+
fn check_inw() {
97+
unsafe {
98+
kassert!(
99+
inw(0x3) == 0xfefe,
100+
"`inw` instruction didn't read the correct value"
101+
);
102+
}
103+
}
104+
105+
#[x86test(ioport(0x5, 0xbeefaaaa))]
106+
fn check_outl() {
107+
unsafe {
108+
outl(0x5, 0xbeefaaaa);
109+
// hypervisor will fail here if port 0x5 doesn't see 0xbeefaaaa
110+
}
111+
}
112+
113+
#[x86test(ioport(0x4, 0xdeadbeef))]
114+
fn check_inl() {
115+
unsafe {
116+
kassert!(
117+
inl(0x4) == 0xdeadbeef,
118+
"`inl` instruction didn't read the correct value"
119+
);
120+
}
121+
}
91122
}

src/irq.rs

+18-14
Original file line numberDiff line numberDiff line change
@@ -249,16 +249,6 @@ impl fmt::Display for PageFaultError {
249249
}
250250
}
251251

252-
#[test]
253-
fn bit_macro() {
254-
assert!(PageFaultError::PK.bits() == 0b100000);
255-
assert!(PageFaultError::ID.bits() == 0b10000);
256-
assert!(PageFaultError::RSVD.bits() == 0b1000);
257-
assert!(PageFaultError::US.bits() == 0b100);
258-
assert!(PageFaultError::WR.bits() == 0b10);
259-
assert!(PageFaultError::P.bits() == 0b1);
260-
}
261-
262252
/// Enable Interrupts.
263253
pub unsafe fn enable() {
264254
asm!("sti");
@@ -269,11 +259,25 @@ pub unsafe fn disable() {
269259
asm!("cli");
270260
}
271261

272-
/// Generate a software interrupt.
273-
/// This is a macro argument needs to be an immediate.
274-
#[macro_export]
275-
macro_rules! int {
262+
#[cfg(all(test, feature = "utest"))]
263+
mod test {
264+
use super::*;
265+
#[test]
266+
fn bit_macro() {
267+
assert!(PageFaultError::PK.bits() == 0b100000);
268+
assert!(PageFaultError::ID.bits() == 0b10000);
269+
assert!(PageFaultError::RSVD.bits() == 0b1000);
270+
assert!(PageFaultError::US.bits() == 0b100);
271+
assert!(PageFaultError::WR.bits() == 0b10);
272+
assert!(PageFaultError::P.bits() == 0b1);
273+
}
274+
275+
/// Generate a software interrupt.
276+
/// This is a macro argument needs to be an immediate.
277+
#[macro_export]
278+
macro_rules! int {
276279
($x:expr) => {{
277280
asm!("int $0" :: "N" ($x));
278281
}};
279282
}
283+
}

src/lib.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#![feature(const_fn, asm, repr_transparent)]
44
#![no_std]
55
#![cfg_attr(test, allow(unused_features))]
6+
#![cfg_attr(all(test, feature = "vmtest"), feature(custom_test_frameworks))]
7+
#![cfg_attr(all(test, feature = "vmtest"), test_runner(x86test::runner::runner))]
68

79
#[cfg(target_arch = "x86")]
810
pub(crate) use core::arch::x86 as arch;
@@ -54,6 +56,11 @@ mod std {
5456
pub use core::option;
5557
}
5658

59+
#[cfg(all(test, feature = "vmtest"))]
60+
extern crate klogger;
61+
#[cfg(all(test, feature = "vmtest"))]
62+
extern crate x86test;
63+
5764
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
5865
#[repr(u8)]
5966
/// x86 Protection levels
@@ -83,6 +90,20 @@ pub unsafe fn halt() {
8390
asm!("hlt" :::: "volatile");
8491
}
8592

93+
#[cfg(all(test, feature = "vmtest"))]
94+
mod x86testing {
95+
use super::*;
96+
use x86test::*;
97+
98+
#[x86test(should_halt)]
99+
fn should_halt() {
100+
unsafe { halt() }
101+
}
102+
103+
#[x86test]
104+
fn should_not_halt() {}
105+
}
106+
86107
/// Read Processor ID
87108
///
88109
/// Reads the value of the IA32_TSC_AUX MSR (address C0000103H)
@@ -97,7 +118,7 @@ pub unsafe fn rdpid() -> u64 {
97118
return pid;
98119
}
99120

100-
#[cfg(test)]
121+
#[cfg(all(test, feature = "utest"))]
101122
mod test {
102123
use super::*;
103124

src/random.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ pub unsafe fn rdseed_slice<T: RdSeed>(buffer: &mut [T]) -> bool {
177177
worked
178178
}
179179

180-
#[cfg(test)]
180+
#[cfg(all(test, feature = "utest"))]
181181
mod test {
182182
use super::*;
183183

src/segmentation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ pub fn gs() -> SegmentSelector {
603603
SegmentSelector::from_raw(segment)
604604
}
605605

606-
#[cfg(test)]
606+
#[cfg(all(test, feature = "utest"))]
607607
mod test {
608608
use super::*;
609609
use crate::Ring;

tests/kvm/bin.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@
55
// RUSTFLAGS="-C relocation-model=dynamic-no-pic -C code-model=kernel" RUST_BACKTRACE=1 cargo test --verbose --test kvm -- --nocapture
66

77
extern crate core;
8-
extern crate x86;
9-
#[macro_use]
108
extern crate klogger;
9+
extern crate x86;
1110

1211
extern crate x86test;
13-
use self::x86test::kassert;
14-
use self::x86test::kpanic;
15-
use self::x86test::x86test;
16-
use self::x86test::X86TestFn;
1712

13+
#[cfg(all(test, feature = "vmtest"))]
14+
use self::x86test::*;
15+
16+
#[cfg(all(test, feature = "vmtest"))]
1817
#[x86test(ioport(0x1, 0xfe))]
1918
fn use_the_port() {
2019
unsafe {
@@ -25,12 +24,14 @@ fn use_the_port() {
2524
}
2625
}
2726

27+
#[cfg(all(test, feature = "vmtest"))]
2828
#[x86test(ram(0x30000000, 0x31000000))]
2929
fn print_works() {
3030
sprint!("sprint!, ");
3131
sprintln!("sprintln! works");
3232
}
3333

34+
#[cfg(all(test, feature = "vmtest"))]
3435
#[x86test]
3536
#[should_panic]
3637
fn panic_test() {

x86test/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ x86test-types = { path = "x86test_types", version = "0.0.1" }
2121
kvm-sys = "0.3.0"
2222
x86 = "0.19"
2323
mmap = "0.1.1"
24-
log = "0.4"
24+
log = "0.4"
25+
klogger = { git = "https://github.com/gz/rust-klogger.git", features = ["use_ioports"] }

x86test/src/hypervisor/mod.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ pub(crate) fn handle_ioexit(
257257
printer: &mut SerialPrinter,
258258
) -> Result<IoHandleStatus, IoHandleError> {
259259
let io = unsafe { *run.io() };
260-
260+
//println!("io = {:?}", io);
261261
match io.direction {
262262
IoDirection::In => {
263263
let mut regs = cpu.get_regs().unwrap();
@@ -269,8 +269,8 @@ pub(crate) fn handle_ioexit(
269269
regs.rax = 0x20; // Mark serial line ready to write
270270
cpu.set_regs(&regs).unwrap();
271271
return Ok(IoHandleStatus::Handled);
272-
} else if io.port == meta.ioport_reads.0 {
273-
regs.rax = meta.ioport_reads.1 as u64;
272+
} else if io.port == meta.ioport_enable.0 {
273+
regs.rax = meta.ioport_enable.1 as u64;
274274
cpu.set_regs(&regs).unwrap();
275275
return Ok(IoHandleStatus::Handled);
276276
}
@@ -289,6 +289,8 @@ pub(crate) fn handle_ioexit(
289289
// The line unsafe { x86::shared::io::outw(0xf4, 0x00); }
290290
// is automatically inserted at the end of every test!
291291
return Ok(IoHandleStatus::TestSuccessful);
292+
} else if io.port == meta.ioport_enable.0 && regs.rax == meta.ioport_enable.1 as u64 {
293+
return Ok(IoHandleStatus::Handled);
292294
} else if io.port == 0xf4 {
293295
return Ok(IoHandleStatus::TestPanic(regs.rax as u8));
294296
}

0 commit comments

Comments
 (0)