From 6675d7e1fb3a2cc9d94e5376f090c5fc77327629 Mon Sep 17 00:00:00 2001 From: Able Date: Wed, 17 Nov 2021 08:42:54 -0600 Subject: [PATCH] clean up the build system and add riscv support --- ableos/.cargo/config.toml | 2 + ableos/src/arch/riscv/asm/boot.asm | 58 ---------------- ableos/src/arch/riscv/asm/trap.asm | 8 --- ableos/src/arch/riscv/drivers/graphics.rs | 31 +++++++++ ableos/src/arch/riscv/drivers/mod.rs | 2 + ableos/src/arch/riscv/drivers/serial.rs | 11 +++ .../opensbi-riscv64-generic-fw_jump.bin | Bin 0 -> 75096 bytes ableos/src/arch/riscv/init.rs | 1 + ableos/src/arch/riscv/mod.rs | 46 +++++++++++++ ableos/src/arch/riscv/virt.lds | 64 ++++++++++++++++++ ableos/src/arch/x86_64/mod.rs | 10 ++- ableos/src/driver_traits/graphics.rs | 11 ++- ableos/src/kmain.rs | 5 +- ableos/src/lib.rs | 12 ++-- ableos/src/print.rs | 5 +- repbuild/src/main.rs | 30 +++----- 16 files changed, 197 insertions(+), 99 deletions(-) delete mode 100644 ableos/src/arch/riscv/asm/boot.asm delete mode 100644 ableos/src/arch/riscv/asm/trap.asm create mode 100644 ableos/src/arch/riscv/drivers/graphics.rs create mode 100644 ableos/src/arch/riscv/drivers/mod.rs create mode 100644 ableos/src/arch/riscv/drivers/serial.rs create mode 100755 ableos/src/arch/riscv/firmwear/opensbi-riscv64-generic-fw_jump.bin create mode 100644 ableos/src/arch/riscv/init.rs create mode 100644 ableos/src/arch/riscv/mod.rs create mode 100644 ableos/src/arch/riscv/virt.lds diff --git a/ableos/.cargo/config.toml b/ableos/.cargo/config.toml index 35263758..75f0784c 100644 --- a/ableos/.cargo/config.toml +++ b/ableos/.cargo/config.toml @@ -9,3 +9,5 @@ build-std = ["core", "compiler_builtins"] [target.'cfg(target_arch = "x86_64")'] # --quiet suppresses warning messages from the bootimage crate runner = "bootimage runner --quiet" +[target.riscv64gc-unknown-none-elf] +rustflags = "-C link-arg=-T../ableos/src/arch/riscv/virt.lds" diff --git a/ableos/src/arch/riscv/asm/boot.asm b/ableos/src/arch/riscv/asm/boot.asm deleted file mode 100644 index 2259f6c0..00000000 --- a/ableos/src/arch/riscv/asm/boot.asm +++ /dev/null @@ -1,58 +0,0 @@ -.S -# bootloader for SoS -# Stephen Marz -# 8 February 2019 -.option norvc -.section .data - -.section .text.init -.global _start -_start: - # Any hardware threads (hart) that are not bootstrapping - # need to wait for an IPI - csrr t0, mhartid - bnez t0, 3f - # SATP should be zero, but let's make sure - csrw satp, zero -.option push -.option norelax - la gp, _global_pointer -.option pop - - # The BSS section is expected to be zero - la a0, _bss_start - la a1, _bss_end - bgeu a0, a1, 2f -1: - sd zero, (a0) - addi a0, a0, 8 - bltu a0, a1, 1b -2: - - - -3: - wfi - j 3b - -# Control registers, set the stack, mstatus, mepc, -# and mtvec to return to the main function. -# li t5, 0xffff; -# csrw medeleg, t5 -# csrw mideleg, t5 -la sp, _stack -# We use mret here so that the mstatus register -# is properly updated. -li t0, (0b11 << 11) | (1 << 7) | (1 << 3) -csrw mstatus, t0 -la t1, kernel_main -csrw mepc, t1 -la t2, asm_trap_vector -csrw mtvec, t2 -li t3, (1 << 3) | (1 << 7) | (1 << 11) -csrw mie, t3 -la ra, 4f -mret -4: - wfi - j 4b diff --git a/ableos/src/arch/riscv/asm/trap.asm b/ableos/src/arch/riscv/asm/trap.asm deleted file mode 100644 index 60e9351f..00000000 --- a/ableos/src/arch/riscv/asm/trap.asm +++ /dev/null @@ -1,8 +0,0 @@ -# trap.S -# Assembly-level trap handler. -.section .text -.global asm_trap_vector -asm_trap_vector: - # We get here when the CPU is interrupted - # for any reason. - mret diff --git a/ableos/src/arch/riscv/drivers/graphics.rs b/ableos/src/arch/riscv/drivers/graphics.rs new file mode 100644 index 00000000..66ad297e --- /dev/null +++ b/ableos/src/arch/riscv/drivers/graphics.rs @@ -0,0 +1,31 @@ +use crate::driver_traits::graphics::{Graphics, Point, Rgb}; + +pub struct GraphicsBuffer; + +#[allow(unused)] +impl Graphics for GraphicsBuffer { + fn put_line(coords_start: Point, coords_end: Point, thickness: u32, color: Rgb) { + todo!() + } + fn put_rect(coords_start: Point, coords_end: Point, color: Rgb) { + todo!() + } + fn put_circle(coords: Point, radius: u32) { + todo!() + } + fn put_triangle(coords_1: Point, coords_2: Point, coords_3: Point, thickness: u32, color: Rgb) { + todo!(); + } + fn put_pixel(coords: Point, color: Rgb) { + todo!() + } + fn paint_cursor(coords: Point) { + todo!() + } + fn hide_cursor() {} + fn show_cursor() {} + fn draw() {} + fn clear() { + todo!() + } +} diff --git a/ableos/src/arch/riscv/drivers/mod.rs b/ableos/src/arch/riscv/drivers/mod.rs new file mode 100644 index 00000000..b832ebf9 --- /dev/null +++ b/ableos/src/arch/riscv/drivers/mod.rs @@ -0,0 +1,2 @@ +pub mod graphics; +pub mod serial; diff --git a/ableos/src/arch/riscv/drivers/serial.rs b/ableos/src/arch/riscv/drivers/serial.rs new file mode 100644 index 00000000..da9bc6cd --- /dev/null +++ b/ableos/src/arch/riscv/drivers/serial.rs @@ -0,0 +1,11 @@ +#[macro_export] +macro_rules! serial_print { + ($($arg:tt)*) => {}; +} +/// Prints to the host through the serial interface, appending a newline. +#[macro_export] +macro_rules! serial_println { + () => {}; + ($fmt:expr) => {}; + ($fmt:expr, $($arg:tt)*) => {}; +} diff --git a/ableos/src/arch/riscv/firmwear/opensbi-riscv64-generic-fw_jump.bin b/ableos/src/arch/riscv/firmwear/opensbi-riscv64-generic-fw_jump.bin new file mode 100755 index 0000000000000000000000000000000000000000..099967f723c2b6f63fbf39a2bdbdf2fc46d1eab4 GIT binary patch literal 75096 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 ! { + #[rustfmt::skip] + asm!(" + csrw sie, zero + csrci sstatus, 2 + + .option push + .option norelax + lla gp, __global_pointer$ + .option pop + + lla sp, __tmp_stack_top + + lla t0, __bss_start + lla t1, __bss_end + + 1: + beq t0, t1, 2f + sd zero, (t0) + addi t0, t0, 8 + j 1b + + 2: + j {} + ", + sym _start, options(noreturn)); +} + +extern "C" fn _start() -> ! { + let uart_data = 0x10000000 as *mut u8; + for c in b"Hello, world!\n" { + unsafe { uart_data.write_volatile(*c) }; + } + + sloop() +} + +pub fn sloop() -> ! { + loop { + unsafe { asm!("nop") }; + } +} diff --git a/ableos/src/arch/riscv/virt.lds b/ableos/src/arch/riscv/virt.lds new file mode 100644 index 00000000..c471c85e --- /dev/null +++ b/ableos/src/arch/riscv/virt.lds @@ -0,0 +1,64 @@ +OUTPUT_ARCH(riscv64gc) + +ENTRY(_boot); + + +SECTIONS { + . = 0x80200000; + .text : { + PROVIDE(__text_start = .); + PROVIDE(KERNEL_START = .); + *(.init.boot) + *(.init.rust) + *(.text .text.*) + . = ALIGN(4K); + PROVIDE(__text_end = .); + } + + .data : { + PROVIDE(__data_start = .); + *(.data .data.* .rodata .rodata.*) + . = ALIGN(8); + PROVIDE(__tmp_stack_bottom = .); + . += 1024 * 1024 * 4; + PROVIDE(__tmp_stack_top = .); + . += 4096; + PROVIDE(__scratch_stack = .); + . = ALIGN(8); + } + + . = ALIGN(8); + + .sdata : { + PROVIDE(__global_pointer$ = .); + *(.sdata .sdata.*) + . = ALIGN(4K); + PROVIDE(__data_end = .); + } + + PROVIDE(__bss_start = .); + .sbss : { + *(.sbss .sbss.*); + } + + .bss : { + *(.bss .bss.*) + } + . = ALIGN(4K); + PROVIDE(__bss_end = .); + + .tdata : { + . = ALIGN(4K); + PROVIDE(__tdata_start = .); + + *(.tdata .tdata.*) + + . = ALIGN(4K); + PROVIDE(__tdata_end = .); + } + + . = ALIGN(2M); + PROVIDE(KERNEL_END = .); + + /DISCARD/ : { *(.eh_frame_hdr .eh_frame) } +} diff --git a/ableos/src/arch/x86_64/mod.rs b/ableos/src/arch/x86_64/mod.rs index 3aec32e1..f38307c9 100644 --- a/ableos/src/arch/x86_64/mod.rs +++ b/ableos/src/arch/x86_64/mod.rs @@ -11,6 +11,10 @@ pub extern "C" fn _start() -> ! { #[allow(unused)] pub fn shutdown() -> ! { + unsafe { + cpuio::outw(0x2000, 0x604); + } + sloop(); } @@ -21,7 +25,7 @@ pub fn sloop() -> ! { } #[cfg(test)] pub fn test_runner(tests: &[&dyn Fn()]) { - for test in tests { - test(); - } + for test in tests { + test(); + } } diff --git a/ableos/src/driver_traits/graphics.rs b/ableos/src/driver_traits/graphics.rs index c95178c4..88fde1a9 100644 --- a/ableos/src/driver_traits/graphics.rs +++ b/ableos/src/driver_traits/graphics.rs @@ -1,9 +1,16 @@ #![allow(unused)] pub enum GModes { - Vga800x600, - Custom(u16, u16), + Vga800x600, + Custom(u16, u16), } pub type GCoord = usize; + +// TODO remap to a bitmasked u32 +/* REASON: More effecient memory wise so less overhead on the wasm memory +Current: u32+u32+u32 +Proposed: u32 with bitmaps +*/ + pub struct Rgb { pub r: u32, pub g: u32, diff --git a/ableos/src/kmain.rs b/ableos/src/kmain.rs index 0a87b507..f917606c 100644 --- a/ableos/src/kmain.rs +++ b/ableos/src/kmain.rs @@ -33,8 +33,9 @@ pub extern "C" fn kernel_main() { AES::init_rng(); */ - + #[cfg(not(target_arch = "riscv64"))] println!("init"); + { use crate::experiments::mail::MailBoxes; let mut x = MailBoxes::new(); @@ -44,7 +45,7 @@ pub extern "C" fn kernel_main() { } // stack_overflow(); - + // crate::arch::shutdown(); loop {} } // TODO: reimplement for the random handler diff --git a/ableos/src/lib.rs b/ableos/src/lib.rs index 33f58281..6ca5156d 100644 --- a/ableos/src/lib.rs +++ b/ableos/src/lib.rs @@ -8,6 +8,7 @@ #![reexport_test_harness_main = "test_main"] #![feature(custom_test_frameworks)] #![test_runner(crate::arch::test_runner)] +#![feature(naked_functions)] #[cfg(target_arch = "arm")] #[path = "arch/aarch32/mod.rs"] mod arch; @@ -19,18 +20,21 @@ mod arch; #[cfg(target_arch = "x86_64")] #[path = "arch/x86_64/mod.rs"] mod arch; -#[cfg(target_arch = "mips")] -#[path = "arch/ps_portable/mod.rs"] +#[cfg(target_arch = "riscv64")] +#[path = "arch/riscv/mod.rs"] mod arch; #[macro_use] pub mod print; + +use arch::drivers::serial; + +mod driver_traits; +mod experiments; #[cfg(not(target_arch = "mips"))] // pub mod allocator; mod kmain; #[cfg(not(target_arch = "mips"))] mod panic; -mod driver_traits; -mod experiments; pub use experiments::server; pub mod keyboard; pub mod relib; diff --git a/ableos/src/print.rs b/ableos/src/print.rs index 8579f70f..f47c61ad 100644 --- a/ableos/src/print.rs +++ b/ableos/src/print.rs @@ -30,7 +30,10 @@ impl core::fmt::Write for Stdout { kprint!("{}", s); Ok(()) } - + #[cfg(target_arch = "riscv64")] + fn write_str(&mut self, s: &str) -> Result<(), Error> { + Ok(()) + } #[cfg(target_arch = "mips")] fn write_str(&mut self, s: &str) -> Result<(), Error> { use psp::dprint; diff --git a/repbuild/src/main.rs b/repbuild/src/main.rs index 78e05b76..3cdad2d4 100644 --- a/repbuild/src/main.rs +++ b/repbuild/src/main.rs @@ -12,6 +12,7 @@ enum Command { machine: Option, }, } + #[derive(clap::ArgEnum, Debug, Clone)] enum MachineType { X86, @@ -56,29 +57,16 @@ fn main() -> anyhow::Result<()> { .run()?; #[rustfmt::skip] xshell::cmd!( - " - qemu-system-riscv64 - -machine virt - -cpu rv64 - -smp 8 - -m 128M - -bios opensbi-riscv64-generic-fw_jump.bin - -kernel blog_os/target/riscv64gc-unknown-none-elf/release/blog_os - - " - ) - .run()?; + "qemu-system-riscv64 + -machine virt + -cpu rv64 + -smp 8 + -m 128M + -bios src/arch/riscv/firmwear/opensbi-riscv64-generic-fw_jump.bin + -kernel target/riscv64gc-unknown-none-elf/release/ableos" + ).run()?; } } - /* - #[rustfmt::skip] - xshell::cmd!(" - qemu-system-x86_64 - -drive format=raw,file=../../ableos/target/x86_64-ableos/release/bootimage-ableos.bin - {debug_log...} - " - ).run()?; - */ } }