Test infrastructure

- serial port
- harnesses using qemu
This commit is contained in:
Guillaume DIDIER 2019-10-21 13:10:53 +02:00
parent 5a528f7508
commit e010900715
17 changed files with 1735 additions and 78 deletions

View File

@ -14,7 +14,12 @@
<sourceFolder url="file://$MODULE_DIR$/vga_buffer/examples" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/vga_buffer/examples" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/vga_buffer/tests" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/vga_buffer/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/vga_buffer/benches" isTestSource="true" /> <sourceFolder url="file://$MODULE_DIR$/vga_buffer/benches" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/polling_serial/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/polling_serial/examples" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/polling_serial/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/polling_serial/benches" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/kernel/target" /> <excludeFolder url="file://$MODULE_DIR$/kernel/target" />
<excludeFolder url="file://$MODULE_DIR$/polling_serial/target" />
<excludeFolder url="file://$MODULE_DIR$/target" /> <excludeFolder url="file://$MODULE_DIR$/target" />
<excludeFolder url="file://$MODULE_DIR$/vga_buffer/target" /> <excludeFolder url="file://$MODULE_DIR$/vga_buffer/target" />
</content> </content>

View File

@ -11,22 +11,23 @@
<component name="CargoProjects"> <component name="CargoProjects">
<cargoProject FILE="$PROJECT_DIR$/Cargo.toml" /> <cargoProject FILE="$PROJECT_DIR$/Cargo.toml" />
<cargoProject FILE="$PROJECT_DIR$/vga_buffer/Cargo.toml" /> <cargoProject FILE="$PROJECT_DIR$/vga_buffer/Cargo.toml" />
<cargoProject FILE="$PROJECT_DIR$/polling_serial/Cargo.toml" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="7ddf063a-3554-4ac7-a5a5-6e243077d67d" name="Default Changelist" comment=""> <list default="true" id="7ddf063a-3554-4ac7-a5a5-6e243077d67d" name="Default Changelist" comment="">
<change afterPath="$PROJECT_DIR$/src/main.rs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/scripts/qemu.sh" afterDir="false" />
<change afterPath="$PROJECT_DIR$/vga_buffer/Cargo.toml" afterDir="false" /> <change afterPath="$PROJECT_DIR$/scripts/run.sh" afterDir="false" />
<change afterPath="$PROJECT_DIR$/vga_buffer/src/lib.rs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/lib.rs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/x86_64-D.TinctoriusAzureus.json" afterDir="false" /> <change afterPath="$PROJECT_DIR$/tests/basic_boot.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.cargo/config" beforeDir="false" afterPath="$PROJECT_DIR$/.cargo/config" afterDir="false" /> <change afterPath="$PROJECT_DIR$/tests/panic_test.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/DendrobatesTinctoriusAzureus.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/DendrobatesTinctoriusAzureus.iml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/DendrobatesTinctoriusAzureus.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/DendrobatesTinctoriusAzureus.iml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Cargo.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.lock" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Cargo.lock" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.lock" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Cargo.toml" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.toml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Cargo.toml" beforeDir="false" afterPath="$PROJECT_DIR$/Cargo.toml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/kernel/Cargo.toml" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/scripts/bochsrc" beforeDir="false" afterPath="$PROJECT_DIR$/scripts/bochsrc" afterDir="false" />
<change beforePath="$PROJECT_DIR$/kernel/src/main.rs" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/scripts/gdb.sh" beforeDir="false" afterPath="$PROJECT_DIR$/scripts/gdb.sh" afterDir="false" />
<change beforePath="$PROJECT_DIR$/x86_64-D.TinctoriusAzureaus.json" beforeDir="false" /> <change beforePath="$PROJECT_DIR$/src/main.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/vga_buffer/src/lib.rs" beforeDir="false" afterPath="$PROJECT_DIR$/vga_buffer/src/lib.rs" afterDir="false" />
</list> </list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" /> <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
@ -63,7 +64,7 @@
<property name="nodejs_package_manager_path" value="npm" /> <property name="nodejs_package_manager_path" value="npm" />
<property name="org.rust.cargo.project.model.PROJECT_DISCOVERY" value="true" /> <property name="org.rust.cargo.project.model.PROJECT_DISCOVERY" value="true" />
<property name="org.rust.hideDetachedFileNotifications/Volumes/Pepins/Users/guillaumedidier/Documents/Etudes/PhD/CPUDissector/DendrobatesTinctoriusAzureus/vga_buffer/src/lib.rs" value="true" /> <property name="org.rust.hideDetachedFileNotifications/Volumes/Pepins/Users/guillaumedidier/Documents/Etudes/PhD/CPUDissector/DendrobatesTinctoriusAzureus/vga_buffer/src/lib.rs" value="true" />
<property name="settings.editor.selected.configurable" value="language.rust.cargo" /> <property name="settings.editor.selected.configurable" value="preferences.pluginManager" />
</component> </component>
<component name="RunAnythingCache"> <component name="RunAnythingCache">
<option name="myCommands"> <option name="myCommands">
@ -197,7 +198,12 @@
<workItem from="1570003006617" duration="2487000" /> <workItem from="1570003006617" duration="2487000" />
<workItem from="1570093731306" duration="4682000" /> <workItem from="1570093731306" duration="4682000" />
<workItem from="1570347619224" duration="2476000" /> <workItem from="1570347619224" duration="2476000" />
<workItem from="1570370780740" duration="3966000" /> <workItem from="1570370780740" duration="4210000" />
<workItem from="1570375267802" duration="92000" />
<workItem from="1570433057328" duration="6409000" />
<workItem from="1570608718907" duration="7852000" />
<workItem from="1571642236432" duration="2984000" />
<workItem from="1571649030007" duration="1556000" />
</task> </task>
<task id="LOCAL-00001" summary="Add CLion config files"> <task id="LOCAL-00001" summary="Add CLion config files">
<created>1569934966982</created> <created>1569934966982</created>

15
Cargo.lock generated
View File

@ -26,7 +26,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "bootloader" name = "bootloader"
version = "0.8.1" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -40,8 +39,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "dendrobates_tinctoreus_azureus" name = "dendrobates_tinctoreus_azureus"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bootloader 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "bootloader 0.8.1",
"polling_serial 0.1.0",
"vga_buffer 0.1.0", "vga_buffer 0.1.0",
"volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"x86_64 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", "x86_64 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -58,6 +59,15 @@ name = "nodrop"
version = "0.1.13" version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "polling_serial"
version = "0.1.0"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"x86_64 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.5.2" version = "0.5.2"
@ -99,7 +109,6 @@ dependencies = [
"checksum bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a165d606cf084741d4ac3a28fb6e9b1eb0bd31f6cd999098cfddb0b2ab381dc0" "checksum bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a165d606cf084741d4ac3a28fb6e9b1eb0bd31f6cd999098cfddb0b2ab381dc0"
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" "checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2" "checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2"
"checksum bootloader 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "45dd858bd74a742ec0fe887722952c263abd0825aa8d33a3704917a97d7bd41e"
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"

View File

@ -2,6 +2,7 @@
members = [ members = [
"vga_buffer", "vga_buffer",
"polling_serial",
] ]
[package] [package]
@ -11,19 +12,33 @@ authors = ["Guillaume DIDIER <guillaume.didier.2014@polytechnique.org>"]
edition = "2018" edition = "2018"
[package.metadata.bootimage] [package.metadata.bootimage]
run-command = ["./scripts/bochs.sh", "{}"] #run-command = ["./scripts/bochs.sh", "{}"]
run-command = ["./scripts/run.sh", "{}"]
test-args = ["qemu"]
run-args = ["bochs"]
#run-command = ["qemu-system-x86_64", "-drive", "format=raw,file={}"]
#test-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04"]
test-success-exit-code = 33 # (0x10 << 1) | 1
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
x86_64 = "0.7.5" x86_64 = "0.7.5"
vga_buffer = { path = "vga_buffer" } vga_buffer = { path = "vga_buffer" }
polling_serial = { path = "polling_serial" }
volatile = "0.2.6"
[dependencies.bootloader] [dependencies.bootloader]
version = "^0.8.1" version = "^0.8.1"
features = ["sse"] features = ["sse"]
[patch.crates-io]
bootloader = { path = "../bootloader" }
[profile.dev] [profile.dev]
opt-level = 0 opt-level = 0
debug = 2 debug = 2
[[test]]
name = "panic_test"
harness = false

15
polling_serial/Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
name = "polling_serial"
version = "0.1.0"
authors = ["Guillaume DIDIER <guillaume.didier.2014@polytechnique.org>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
x86_64 = "0.7.5"
spin = "0.5.2"
[dependencies.lazy_static]
version = "1.0"
features = ["spin_no_std"]

171
polling_serial/src/lib.rs Normal file
View File

@ -0,0 +1,171 @@
// A quick and dirty crate for serial I/O inspired by rust-os-dev/uart and code in
// gamozolab/orange_slice
//
// Supports Write but also polling which may be useful
// Note : Swicthing to interrupt driven read could be interesting but should not be mandatory
#![no_std]
extern crate x86_64;
use core::fmt;
use lazy_static::lazy_static;
use spin::Mutex;
use x86_64::instructions::port::Port;
pub struct SerialPort {
/// Data register.
/// Reading this registers read from the Receive buffer.
/// Writing to this register writes to the Transmit buffer.
data: Port<u8>, // 0
/// Interrupt Enable Register.
int_en: Port<u8>, // 1
/// Interrupt Identification and FIFO control registers
fifo_ctrl: Port<u8>, // 2
/// Line Control Register. The most significant bit of this register is the DLAB.
line_ctrl: Port<u8>, // 3
/// Modem Control Register.
modem_ctrl: Port<u8>, // 4
/// Line Status Register.
line_status: Port<u8>, // 5
/// Modem Status Register.
modem_status: Port<u8>, // 6
/// Scratch Register.
scratch: Port<u8>, // 7
}
const SCRATCH_VALUE: u8 = 0x42;
const DISBALE_INTERRUPTS: u8 = 0x00;
const DLAB: u8 = 0x80;
const DIVISOR: u16 = 0x03;
const PARITY_MODE: u8 = 0x03;
const FIFO14: u8 = 0xC7;
const RTS_BST: u8 = 0x0B;
const READY_TO_SEND: u8 = 0x20;
const READY_TO_READ: u8 = 0x01;
impl SerialPort {
/// Tries to create and initialize a serial port on the given base port
/// Will return None if the serial port doesn't work
/// Unsafe as calling this on an arbitrary port that's not serial port has serious consequences
pub unsafe fn init_new(base: u16) -> Option<SerialPort> {
let mut p = SerialPort {
data: Port::new(base),
int_en: Port::new(base + 1),
fifo_ctrl: Port::new(base + 2),
line_ctrl: Port::new(base + 3),
modem_ctrl: Port::new(base + 4),
line_status: Port::new(base + 5),
modem_status: Port::new(base + 6),
scratch: Port::new(base + 7),
};
// scratchpad test
p.scratch.write(SCRATCH_VALUE);
if p.scratch.read() != SCRATCH_VALUE {
return None;
}
// disable all interrupts
p.int_en.write(DISBALE_INTERRUPTS);
// enable DLAB to set the divisor
p.line_ctrl.write(DLAB);
// set the divisor hi and lo
p.data.write(DIVISOR as u8);
p.int_en.write((DIVISOR >> 8) as u8);
// clear DLAB
// set mode to 8 bits No parity 1 stop bit (8-N-1)
p.line_ctrl.write(PARITY_MODE);
// Set-up FIFOs depth 14 just in case
p.fifo_ctrl.write(FIFO14);
// Set up RTS DSR
p.modem_ctrl.write(RTS_BST);
Some(p)
}
pub fn send(&mut self, byte: u8) {
unsafe {
while self.line_status.read() & READY_TO_SEND == 0 {}
self.data.write(byte);
}
}
pub fn try_read(&mut self) -> Option<u8> {
unsafe {
if self.line_status.read() & READY_TO_READ == 0 {
None
} else {
Some(self.data.read())
}
}
}
pub fn read(&mut self) -> u8 {
unsafe {
while self.line_status.read() & READY_TO_READ == 0 {}
self.data.read()
}
}
}
impl fmt::Write for SerialPort {
fn write_str(&mut self, s: &str) -> fmt::Result {
for byte in s.bytes() {
self.send(byte);
}
Ok(())
}
}
lazy_static! {
pub static ref SERIAL1: Mutex<SerialPort> = {
let mut serial_port = unsafe { SerialPort::init_new(0x3F8).unwrap() };
Mutex::new(serial_port)
};
}
#[doc(hidden)]
pub fn _print(args: ::core::fmt::Arguments) {
use core::fmt::Write;
SERIAL1
.lock()
.write_fmt(args)
.expect("Printing to serial failed");
}
/// Prints to the host through the serial interface.
#[macro_export]
macro_rules! serial_print {
($($arg:tt)*) => {
$crate::_print(format_args!($($arg)*));
};
}
/// Prints to the host through the serial interface, appending a newline.
#[macro_export]
macro_rules! serial_println {
() => ($crate::serial_print!("\n"));
($fmt:expr) => ($crate::serial_print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => ($crate::serial_print!(
concat!($fmt, "\n"), $($arg)*));
}

View File

@ -857,7 +857,7 @@ debugger_log: -
# com4: enabled=1, mode=pipe-client, dev=\\.\pipe\mypipe # com4: enabled=1, mode=pipe-client, dev=\\.\pipe\mypipe
# com4: enabled=1, mode=pipe-server, dev=\\.\pipe\mypipe # com4: enabled=1, mode=pipe-server, dev=\\.\pipe\mypipe
#======================================================================= #=======================================================================
#com1: enabled=1, mode=term, dev=/dev/ttyp9 com1: enabled=1, mode=term, dev=/dev/stdin
#======================================================================= #=======================================================================

1262
scripts/bochsrc-solstice Normal file

File diff suppressed because it is too large Load Diff

3
scripts/disassemble.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
# TODO: Use LLVM tools?
x86_64-elf-objdump --no-show-raw-insn -d -Mintel ${1:-target/x86_64-solstice/debug/solstice} | source-highlight -s asm -f esc256 | less

0
scripts/gdb.sh Normal file → Executable file
View File

2
scripts/qemu.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
qemu-system-x86_64 -drive format=raw,file="$1" -device isa-debug-exit,iobase=0xf4,iosize=0x04 -serial stdio -display none

2
scripts/run.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
./scripts/$2.sh $1

76
src/lib.rs Normal file
View File

@ -0,0 +1,76 @@
#![no_std]
#![cfg_attr(test, no_main)]
#![feature(custom_test_frameworks)]
#![test_runner(crate::test_runner)]
#![reexport_test_harness_main = "test_main"]
use core::panic::PanicInfo;
use polling_serial::{serial_print, serial_println};
use vga_buffer::{print, println};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum QemuExitCode {
Success = 0x10,
Failed = 0x11,
}
// Custom panic handler, required for freestanding program
pub fn test_panic_handler(info: &PanicInfo) -> ! {
serial_println!("[failed]\n");
serial_println!("Error: {}\n", info);
exit_qemu(QemuExitCode::Failed);
}
// Assumes isa-debug-device at 0xf4, of size 4
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);
}
loop {}
}
pub fn test_runner(tests: &[&dyn Fn()]) {
println!("Running {} tests", tests.len());
serial_println!("Running {} tests", tests.len());
for test in tests {
test();
}
exit_qemu(QemuExitCode::Success);
}
#[cfg(test)]
#[no_mangle]
pub extern "C" fn _start() -> ! {
test_main();
loop {}
}
#[cfg(test)]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
test_panic_handler(info)
}
#[test_case]
fn trivial_assertion() {
print!("trivial assertion... ");
serial_print!("trivial assertion... ");
assert_eq!(1, 1);
println!("[ok]");
serial_println!("[ok]");
}
#[test_case]
fn printf_test() {
serial_print!("Testing VGA print/println... ");
println!("Are frogs blue?");
print!("Yes\n");
serial_println!("[ok]");
}

View File

@ -3,30 +3,30 @@
#![no_std] // This is a free standing program #![no_std] // This is a free standing program
#![no_main] // This has no crt0 #![no_main] // This has no crt0
#![feature(custom_test_frameworks)]
#![test_runner(dendrobates_tinctoreus_azureus::test_runner)]
#![reexport_test_harness_main = "test_main"]
use polling_serial::{serial_print, serial_println};
use vga_buffer::{print, println};
use core::fmt::Write; use core::fmt::Write;
use core::panic::PanicInfo; // required for custom panic handler use core::panic::PanicInfo;
use vga_buffer; // required for custom panic handler
use x86_64; use x86_64;
use vga_buffer;
// Custom panic handler, required for freestanding program // Custom panic handler, required for freestanding program
#[cfg(not(test))]
#[panic_handler] #[panic_handler]
fn panic(_info: &PanicInfo) -> ! { fn panic(info: &PanicInfo) -> ! {
serial_println!("{}", info);
println!("{}", info);
loop {} loop {}
loop {
println!("{}", info);
}
} }
// static greeting string, for hello world kernel
static HELLO: &[u8] = b"Hello Blue Frog!";
static YES: &[u8] = b"yes";
static NO: &[u8] = b"no";
static a: f64 = 420.0;
static b: f64 = 42.0;
static d: f64 = 0.1;
// Kernel entry point // Kernel entry point
#[no_mangle] #[no_mangle]
@ -34,53 +34,73 @@ pub extern "C" fn _start() -> ! {
// TODO: Take care of cpuid stuff and set-up all floating point exetnsions // TODO: Take care of cpuid stuff and set-up all floating point exetnsions
// TODO: We may also need to enable debug registers ? // TODO: We may also need to enable debug registers ?
let vga_buffer = 0xb8000 as *mut u8; println!("Hello Blue Frog");
#[cfg(test)]
test_main();
for (i, &byte) in HELLO.iter().enumerate() {
unsafe {
*vga_buffer.offset(i as isize * 2) = byte;
*vga_buffer.offset(i as isize * 2 + 1) = 0xb;
}
}
// magic break ? // magic break ?
x86_64::instructions::bochs_breakpoint(); // x86_64::instructions::bochs_breakpoint();
let c = a * d; panic!("Ooops Sorry");
x86_64::instructions::bochs_breakpoint();
if b == c {
for (i, &byte) in YES.iter().enumerate() {
unsafe {
*vga_buffer.offset(i as isize * 2) = byte;
*vga_buffer.offset(i as isize * 2 + 1) = 0xb;
} }
#[cfg(test)]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
use dendrobates_tinctoreus_azureus::test_panic_handler;
test_panic_handler(info);
} }
#[test_case]
fn float_test() {
serial_println!("Testing float computations...");
use volatile::Volatile;
// Make a few floating points test;
let vf: f32 = 84798.0;
let vd: f64 = 0.828494623655914;
let a: Volatile<f32> = Volatile::new(42.0);
let b: Volatile<f32> = Volatile::new(2019.);
let rf = a.read() * b.read();
let c: Volatile<f64> = Volatile::new(15.410);
let d: Volatile<f64> = Volatile::new(18.600);
let rd = c.read() / d.read();
serial_print!(
" {:?} * {:?} = {:?} expected {:?}...",
a.read(),
b.read(),
rf,
vf
);
if (rf == vf) {
serial_println!("[ok]");
} else { } else {
for (i, &byte) in NO.iter().enumerate() { serial_println!("[fail]");
unsafe {
*vga_buffer.offset(i as isize * 2) = byte;
*vga_buffer.offset(i as isize * 2 + 1) = 0xb;
} }
serial_print!(
" {:?} / {:?} = {:?} expected {:?}...",
c.read(),
d.read(),
rd,
vd
);
if (rd == vd) {
serial_println!("[ok]");
} else {
serial_println!("[fail]");
} }
assert_eq!(rf, vf);
assert_eq!(rd, vd);
serial_println!("Testing float computations... [ok]");
} }
x86_64::instructions::bochs_breakpoint(); //#[test_case]
//fn failing_assertion() {
writeln!( // print!("trivial assertion... ");
vga_buffer::WRITER.lock(), // serial_print!("trivial assertion... ");
"The numbers are {} and {}", // assert_eq!(1, 1);
42, // println!("[ok]");
1.0 / 3.0 // serial_println!("[ok]");
) //}
.unwrap();
writeln!(
vga_buffer::WRITER.lock(),
"a is {}, b is {}, c is {}, d is {}",
a,
b,
c,
d
)
.unwrap();
loop {}
}

28
tests/basic_boot.rs Normal file
View File

@ -0,0 +1,28 @@
#![no_std]
#![no_main]
#![feature(custom_test_frameworks)]
#![test_runner(dendrobates_tinctoreus_azureus::test_runner)]
#![reexport_test_harness_main = "test_main"]
use core::panic::PanicInfo;
use polling_serial::{serial_print, serial_println};
use vga_buffer::{print, 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) -> ! {
dendrobates_tinctoreus_azureus::test_panic_handler(info)
}
#[test_case]
fn test_println() {
serial_print!("test_println... ");
println!("test_println output");
serial_println!("[ok]");
}

26
tests/panic_test.rs Normal file
View File

@ -0,0 +1,26 @@
#![no_std]
#![no_main]
use core::panic::PanicInfo;
use dendrobates_tinctoreus_azureus::{exit_qemu, QemuExitCode};
use polling_serial::{serial_print, serial_println};
#[no_mangle]
pub extern "C" fn _start() -> ! {
should_fail();
serial_println!("[test did not panic]");
exit_qemu(QemuExitCode::Failed);
loop {}
}
fn should_fail() {
serial_print!("should_fail... ");
assert_eq!(0, 1);
}
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
serial_println!("[ok]");
exit_qemu(QemuExitCode::Success);
loop {}
}

View File

@ -266,6 +266,23 @@ impl fmt::Write for Writer {
} }
} }
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ($crate::_print(format_args!($($arg)*)));
}
#[macro_export]
macro_rules! println {
() => ($crate::print!("\n"));
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
}
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
use core::fmt::Write;
WRITER.lock().write_fmt(args).unwrap();
}
lazy_static! { lazy_static! {
pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer::new( pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer::new(
ColorCode::new(ForegroundColor::Yellow, Color::Blue), ColorCode::new(ForegroundColor::Yellow, Color::Blue),