Test infrastructure
- serial port - harnesses using qemu
This commit is contained in:
parent
5a528f7508
commit
e010900715
@ -14,7 +14,12 @@
|
||||
<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/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$/polling_serial/target" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vga_buffer/target" />
|
||||
</content>
|
||||
|
@ -11,22 +11,23 @@
|
||||
<component name="CargoProjects">
|
||||
<cargoProject FILE="$PROJECT_DIR$/Cargo.toml" />
|
||||
<cargoProject FILE="$PROJECT_DIR$/vga_buffer/Cargo.toml" />
|
||||
<cargoProject FILE="$PROJECT_DIR$/polling_serial/Cargo.toml" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<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$/vga_buffer/Cargo.toml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/vga_buffer/src/lib.rs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/x86_64-D.TinctoriusAzureus.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.cargo/config" beforeDir="false" afterPath="$PROJECT_DIR$/.cargo/config" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/scripts/qemu.sh" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/scripts/run.sh" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/lib.rs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/tests/basic_boot.rs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/tests/panic_test.rs" 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$/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$/kernel/Cargo.toml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/kernel/src/main.rs" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/x86_64-D.TinctoriusAzureaus.json" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/scripts/bochsrc" beforeDir="false" afterPath="$PROJECT_DIR$/scripts/bochsrc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/scripts/gdb.sh" beforeDir="false" afterPath="$PROJECT_DIR$/scripts/gdb.sh" afterDir="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>
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
@ -63,7 +64,7 @@
|
||||
<property name="nodejs_package_manager_path" value="npm" />
|
||||
<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="settings.editor.selected.configurable" value="language.rust.cargo" />
|
||||
<property name="settings.editor.selected.configurable" value="preferences.pluginManager" />
|
||||
</component>
|
||||
<component name="RunAnythingCache">
|
||||
<option name="myCommands">
|
||||
@ -197,7 +198,12 @@
|
||||
<workItem from="1570003006617" duration="2487000" />
|
||||
<workItem from="1570093731306" duration="4682000" />
|
||||
<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 id="LOCAL-00001" summary="Add CLion config files">
|
||||
<created>1569934966982</created>
|
||||
|
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -26,7 +26,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
[[package]]
|
||||
name = "bootloader"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"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"
|
||||
version = "0.1.0"
|
||||
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",
|
||||
"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)",
|
||||
]
|
||||
|
||||
@ -58,6 +59,15 @@ name = "nodrop"
|
||||
version = "0.1.13"
|
||||
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]]
|
||||
name = "spin"
|
||||
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.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 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 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"
|
||||
|
17
Cargo.toml
17
Cargo.toml
@ -2,6 +2,7 @@
|
||||
|
||||
members = [
|
||||
"vga_buffer",
|
||||
"polling_serial",
|
||||
]
|
||||
|
||||
[package]
|
||||
@ -11,19 +12,33 @@ authors = ["Guillaume DIDIER <guillaume.didier.2014@polytechnique.org>"]
|
||||
edition = "2018"
|
||||
|
||||
[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
|
||||
|
||||
[dependencies]
|
||||
x86_64 = "0.7.5"
|
||||
vga_buffer = { path = "vga_buffer" }
|
||||
polling_serial = { path = "polling_serial" }
|
||||
volatile = "0.2.6"
|
||||
|
||||
[dependencies.bootloader]
|
||||
version = "^0.8.1"
|
||||
features = ["sse"]
|
||||
|
||||
[patch.crates-io]
|
||||
bootloader = { path = "../bootloader" }
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
debug = 2
|
||||
|
||||
[[test]]
|
||||
name = "panic_test"
|
||||
harness = false
|
||||
|
15
polling_serial/Cargo.toml
Normal file
15
polling_serial/Cargo.toml
Normal 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
171
polling_serial/src/lib.rs
Normal 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)*));
|
||||
}
|
@ -857,7 +857,7 @@ debugger_log: -
|
||||
# com4: enabled=1, mode=pipe-client, 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
1262
scripts/bochsrc-solstice
Normal file
File diff suppressed because it is too large
Load Diff
3
scripts/disassemble.sh
Executable file
3
scripts/disassemble.sh
Executable 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
0
scripts/gdb.sh
Normal file → Executable file
2
scripts/qemu.sh
Executable file
2
scripts/qemu.sh
Executable 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
2
scripts/run.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
./scripts/$2.sh $1
|
76
src/lib.rs
Normal file
76
src/lib.rs
Normal 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]");
|
||||
}
|
132
src/main.rs
132
src/main.rs
@ -3,30 +3,30 @@
|
||||
|
||||
#![no_std] // This is a free standing program
|
||||
#![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::panic::PanicInfo; // required for custom panic handler
|
||||
use core::panic::PanicInfo;
|
||||
use vga_buffer; // required for custom panic handler
|
||||
|
||||
use x86_64;
|
||||
|
||||
use vga_buffer;
|
||||
|
||||
// Custom panic handler, required for freestanding program
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo) -> ! {
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
serial_println!("{}", info);
|
||||
println!("{}", info);
|
||||
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
|
||||
#[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: 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 ?
|
||||
x86_64::instructions::bochs_breakpoint();
|
||||
let c = a * d;
|
||||
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;
|
||||
// x86_64::instructions::bochs_breakpoint();
|
||||
panic!("Ooops Sorry");
|
||||
}
|
||||
|
||||
#[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 {
|
||||
for (i, &byte) in NO.iter().enumerate() {
|
||||
unsafe {
|
||||
*vga_buffer.offset(i as isize * 2) = byte;
|
||||
*vga_buffer.offset(i as isize * 2 + 1) = 0xb;
|
||||
serial_println!("[fail]");
|
||||
}
|
||||
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();
|
||||
|
||||
writeln!(
|
||||
vga_buffer::WRITER.lock(),
|
||||
"The numbers are {} and {}",
|
||||
42,
|
||||
1.0 / 3.0
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
writeln!(
|
||||
vga_buffer::WRITER.lock(),
|
||||
"a is {}, b is {}, c is {}, d is {}",
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
d
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
loop {}
|
||||
}
|
||||
//#[test_case]
|
||||
//fn failing_assertion() {
|
||||
// print!("trivial assertion... ");
|
||||
// serial_print!("trivial assertion... ");
|
||||
// assert_eq!(1, 1);
|
||||
// println!("[ok]");
|
||||
// serial_println!("[ok]");
|
||||
//}
|
||||
|
28
tests/basic_boot.rs
Normal file
28
tests/basic_boot.rs
Normal 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
26
tests/panic_test.rs
Normal 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 {}
|
||||
}
|
@ -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! {
|
||||
pub static ref WRITER: Mutex<Writer> = Mutex::new(Writer::new(
|
||||
ColorCode::new(ForegroundColor::Yellow, Color::Blue),
|
||||
|
Loading…
Reference in New Issue
Block a user