--- /dev/null
+[target.riscv64gc-unknown-none-elf]
+rustflags = ["-C", "link-args=-Tsrc/linker.ld --omagic"]
+# Add -S to wait for the debugger
+runner = """ qemu-system-riscv64
+ -machine virt
+ -cpu rv64
+ -m 128M
+ -s
+ -nographic
+ -serial mon:stdio
+ -bios """
+
+[build]
+target = "riscv64gc-unknown-none-elf"
+
+
--- /dev/null
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "bit_field"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "raw-cpuid"
+version = "10.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "riscv"
+version = "0.1.0"
+dependencies = [
+ "uart_16550",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
+
+[[package]]
+name = "uart_16550"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dc00444796f6c71f47c85397a35e9c4dbf9901902ac02386940d178e2b78687"
+dependencies = [
+ "bitflags",
+ "rustversion",
+ "x86",
+]
+
+[[package]]
+name = "x86"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385"
+dependencies = [
+ "bit_field",
+ "bitflags",
+ "raw-cpuid",
+]
--- /dev/null
+[package]
+name = "riscv"
+version = "0.1.0"
+edition = "2021"
+
+[build]
+target = "riscv64gc-unknown-none-elf"
+
+[dependencies]
+uart_16550 = "0.3.0"
+
+# We need to turn off panic unwinding
+# so we set the panic behavior to abort
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
--- /dev/null
+[toolchain]
+channel = "nightly"
--- /dev/null
+OUTPUT_ARCH(riscv)
+
+MEMORY {
+ RAM (wxa) : ORIGIN = 0x80000000, LENGTH = 128M
+}
+
+PHDRS {
+ text PT_LOAD;
+ data PT_LOAD;
+ bss PT_LOAD;
+}
+
+SECTIONS {
+ . = ORIGIN(RAM); # start at 0x8000_0000
+
+ .text : { # put code first
+ *(.text.init) # start with anything in the .text.init section
+ *(.text .text.*) # then put anything else in .text
+ } >RAM AT>RAM :text # put this section into the text segment
+
+ # we have to provide a pointer at the start of the rodata/data/bss area
+ # in order to facilitate linker relaxation. This is a process whereby the
+ # linker can use simpler instructions for variable accesses that exist within
+ # a 12-bit offset from the global pointer
+ PROVIDE(_global_pointer = .); # we have to provide the global_pointer at the beg
+
+ .rodata : { # next, read-only data
+ *(.rodata .rodata.*)
+ } >RAM AT>RAM :text # goes into the text segment as well (since instructions are generally read-only)
+
+ .data : { # and the data section
+ *(.sdata .sdata.*) *(.data .data.*)
+ } >RAM AT>RAM :data # this will go into the data segment
+
+ .bss :{ # finally, the BSS
+ PROVIDE(_bss_start = .); # define a variable for the start of this section
+ *(.sbss .sbss.*) *(.bss .bss.*)
+ PROVIDE(_bss_end = .); # ... and one at the end
+ } >RAM AT>RAM :bss # and this goes into the bss segment
+
+ # start the stack at the end of memory and let it grow downward
+ PROVIDE(_stack_top = ORIGIN(RAM) + LENGTH(RAM));
+}
+
+# make the linker error unless we provide a _start
+ENTRY(_start)
--- /dev/null
+#![no_std]
+#![no_main]
+#![feature(naked_functions)] // enable functions that are pure inline assembly
+
+use core::panic::PanicInfo;
+
+// cfg not test is set here because the analyzer and the test system
+// complained about the panic handler being doubly-defined
+#[cfg(not(test))]
+#[panic_handler]
+fn on_panic(_info: &PanicInfo) -> ! {
+ loop {}
+}
+
+/*
+ * Global entry point, specified in the linker script.
+ * Requires C-style linkage in order for the linker to identify the name
+ * of the function and place it at the entry point address.
+ *
+ * The main purpose here is to "initialize the runtime". In this case, this
+ * means setting up the global pointer for linker relaxation, establishing
+ * the stack, and zeroing-out the bss section
+ */
+#[naked]
+#[no_mangle] // C-style linkage needs an unmangled function
+#[link_section = ".text.init"]
+unsafe extern "C" fn _start() -> ! {
+ use core::arch::asm;
+ asm!(
+ // The linker will try to emit the `la` pseudo-instruction when it believes
+ // the referenced variable will be within a 12-bit offset of the _global_pointer,
+ // so we must initialize the `gp` register to this at runtime.
+ // (see the linker script file for more details)
+ ".option push",
+ ".option norelax",
+ "la gp, _global_pointer",
+ ".option pop",
+
+ // set the stack pointer
+ "la sp, _stack_top",
+
+ // clear the BSS section
+ "la t0, _bss_start",
+ "la t1, _bss_end",
+ "bgeu t0, t1, 2f",
+"1:",
+ "sb zero, 0(t0)",
+ "addi t0, t0, 1",
+ "bne t0, t1, 1b",
+"2:",
+
+ // "tail-call" to {entry} (call without saving a return address)
+ "tail {entry}",
+ entry = sym entry, // {entry} refers to the function [entry] below
+ options(noreturn) // we must handle "returning" from assembly
+ );
+}
+
+#[no_mangle] // Again, being mindful of the C calling convention
+extern "C" fn entry() -> ! {
+ use uart_16550::MmioSerialPort;
+ const SERIAL_BASE: usize = 0x1000_0000;
+ let mut serial_port = unsafe { MmioSerialPort::new(SERIAL_BASE) };
+ for byte in "KIT -- Hello World!\n".bytes() {
+ serial_port.send(byte)
+ }
+ loop {}
+}