riscv_baremetal.git
31 hours agomonitor: implement IO for monitor console master
Kit Rhett Aultman [Thu, 17 Oct 2024 03:10:44 +0000 (23:10 -0400)]
monitor: implement IO for monitor console

This commit introduces the basic infrastructure for the monitor console,
specifically providing some basic line-oriented IO so that the monitor
(to be styled after Wozmon) can be written easily.

This refactors out some of the aspects of the UART code into a
UartConsole that can pe paired with a line-oriented "application".  This
also changes the creation of the TrapFrame into a heap allocation
through Box.  This is necessary because the UartConsole is owned by the
TrapFrame.  That sounds awkward, but the interrupt handler is currently
the only code path from the "outside world" to reach the UartConsole.
It's not possible to "plug in" the monitor if the TrapFrame is
statically initialized, so it instead comes from the heap.

Because both UartConsole and Monitor need to refer to one another in an
abstracted way, one can't really own the other.  The solution here is to
use Arc::new_cyclic so that reference counting can help the compiler
prove that memory won't leak.

The UART handling code is now a little awkward-looking; there's still a
global static Uart for the println!() macros but then an instantiated
UartConsole, too.  Longer-term, the goal will be to get rid of the
global Uart object and make the println!() macro part of a more
comprehensive console management system.

2 weeks agouart/trap/main: remove global read_uart fn
Kit Rhett Aultman [Sun, 29 Sep 2024 18:58:30 +0000 (14:58 -0400)]
uart/trap/main: remove global read_uart fn

The previous implementation of the UART interrupt handler relied on a
public global function, read_uart, in order to get data waiting in the
UART's registers.  This is an artifact of the Uart code which focuses on
having a single global Uart, largely so the println!() macros can work
with it.

It seems a bit awkward going forward having all possible read/write
points of the UART going through global functions; indeed, future code
would like to work simply by writing bytes or strings into interfaces
and not worrying about where it goes, so as a stepping stone on that
way, this commit refactors out the global read_uart( ) function and
replaces it with a scheme where the interrupt handler has its own
interface to the UART.

Having multiple Uart objects is fine for now but really only because we
know we're single-threading.  More ideal would be, in the future, for
each Uart to be a reference to a single Uart struct, since the Uart's
underlying implementation already has some amount of concurrency
control.  At the end of the day, there's one single UART on the system,
and we really want to create a situation where code writes into, say, a
Console interface instead of the Uart, and there's a "console manager"
deciding what's going to the UART and what isn't.

Baby steps, though.

5 weeks agoChange line terminator for println to \r\n
Kit Rhett Aultman [Sat, 7 Sep 2024 03:31:06 +0000 (23:31 -0400)]
Change line terminator for println to \r\n

The VT102 terminal emulation on minicom treats \r and \n as separate
operations, so this makes the logging print prettier there without
impacting the stdio serial of qemu either.

5 weeks agoRename console to uart
Kit Rhett Aultman [Sat, 7 Sep 2024 03:00:31 +0000 (23:00 -0400)]
Rename console to uart

The term "console" felt like a misnomer; the console is really just a
way to access the uart.  A more complete concept of "console" will
include line discipline and similar higher-level concepts.

This is all in preparation to switch over to using Minicom as the
standard interface.  As we head towards running this on hardware, it's
going to make more sense to make the serial terminal experience on
Minicom a good one.

6 weeks agotrap/console: centralize UART use under console.rs
Kit Rhett Aultman [Tue, 3 Sep 2024 03:01:07 +0000 (23:01 -0400)]
trap/console: centralize UART use under console.rs

This commit refactors the UART reading code so that all UART
interactions go through the MmioSerialPort in console.rs.  A previous
commit had the UART interrupt handler reading directly from the UART
because some sort of issue prevents calling CONSOLE.lock() outside of
the console crate.  However, it's fine to call this from functions
inside the console crate, so this commit implements a console_read()
function there which the trap vector can then call.

6 weeks agoconsole/main/trap: enable interrupts, handle UART interrupt
Kit Rhett Aultman [Mon, 2 Sep 2024 23:56:39 +0000 (19:56 -0400)]
console/main/trap: enable interrupts, handle UART interrupt

This commit enables interrupts and configures the RISC-V PLIC to deliver
interrupts for the UART (interrupt 10 for qemu).  To do this:

* mstatus and mie are configured for m-mode interrupts (mstatus also
  likely has s-mode turned on, but we won't use s-mode until we have
  to).
* The MmioSerialPort didn't have its init function called; doing so sets
  the interrupt enable bits on the UART.
* Configures the PLIC to deliver interrupt 10 on priority 1.
* Adds code to the exception handler to claim, handle, and complete the
  interrupt.

A few notes here:
* There's only one interrupt source right now...the UART.  So servicing
  the interrupt is done right in the handler.  There's no need to
  determine any other interrupt sources or worry about timing beyond
  this, for now.
* Because the MmioSerialPort was really mostly set up for the benefit of
  console output, it's not really set up to be used by the interrupt
  handler.  The code's a bit messy to ensure we read the pending byte
  and just echo it back to the terminal.  Future commits should address
  the awkwardness going on here.

6 weeks agoconsole.rs: write entire strings without a loop
Kit Rhett Aultman [Mon, 2 Sep 2024 23:45:48 +0000 (19:45 -0400)]
console.rs: write entire strings without a loop

The MmioSerialPort already has a write_str() function, so there's no
need to loop the bytes.

Actually, given that MmioSerialPort also has a fmt::Write trait, it's
possible that we don't actually need to implement it for Console at all.

6 weeks agomain.rs: minor whitespace cleanup
Kit Rhett Aultman [Mon, 2 Sep 2024 23:43:26 +0000 (19:43 -0400)]
main.rs: minor whitespace cleanup

A prior commit didn't have rustfmt run on it, so this commit is a
catchup on the whitespace nits left behind.

6 weeks agomain.rs: remove commented-out ecall code
Kit Rhett Aultman [Mon, 2 Sep 2024 23:31:18 +0000 (19:31 -0400)]
main.rs: remove commented-out ecall code

Before the commits supporting interrupts from the UART, it's worth
stopping to clean up a little bit.  This commented-out code to execute
ecall (which triggers an exception and thus exercises the exception
handler) isn't really needed going forward, so this commit drops it.

6 weeks agomain.rs: enable floating point
Kit Rhett Aultman [Mon, 2 Sep 2024 17:44:02 +0000 (13:44 -0400)]
main.rs: enable floating point

The trap frame already handles the floating point registers, but
floating point support was not enabled via the mstatus register.  This
didn't cause an issue on the Ubuntu 22.04 standard version of qemu, but
one built from nightly source will issue an illegal instruction
exception if floating point registers are accessed without the support
being enabled.

This commit fixes the issue by enabling floating point support from
early initialization.

7 weeks agotrap, main: implement trap handler
Kit Rhett Aultman [Sat, 24 Aug 2024 15:30:25 +0000 (11:30 -0400)]
trap, main: implement trap handler

This commit implements a trap handler, which handles a number of basic
exception cases and sets the code up for handling interrupts, which will
be really useful for making a serial console properly without relying on
looping.

Changes:
* trap.rs implements a TrapFrame struct and declares one in memory.
  This will allow the code to preserve registers and context without
  using the stack.
* trap.S implements the low-level parts of the trap handler, copying the
  general-purpose and floating-point registers, plus the trap cause and
  other context info, into the TrapFrame, and calls the Rust function
  m_trap.
* trap.rs implements m_trap, which performs dispatch based on the
  exception code and, if the exception is non-fatal, returns the address
  of the PC that the trap returns to (typically PC+4).
* main.rs expands the panic handler to log panic information to serial
  out so that fatal exceptions are logged.  It also adds the trap vector
  init code.

This particular method of performing traps is heavily inspired from
Stephen Marz' blog on bare metal Rust for RISC-V:
http://osblog.stephenmarz.com/ch4.html

2 months agomain: clean up logging
Kit Rhett Aultman [Sun, 30 Jun 2024 16:41:08 +0000 (12:41 -0400)]
main: clean up logging

A practice I've used for years is to prefix all logging statements with
my name in all-caps.  These provisional messages can then be easily
spotted and either kept (sans prefix) or removed.  In my haste, though,
I missed one.

3 months agoheap/linker/main: set up a heap allocator
Kit Rhett Aultman [Sun, 30 Jun 2024 16:38:01 +0000 (12:38 -0400)]
heap/linker/main: set up a heap allocator

This commit sets up a heap allocator.  Again, I cannot sufficiently
stress the usefulness of Meyer Zinn for getting things this far, and
much of what I needed to know about getting linker symbols propagated
into Rust code comes from:
https://meyerzinn.tech/posts/2023/03/08/p1-printing-and-allocating/

Meyer steps through the process of setting up the linked list allocator.
However, there's a buddy list allocator that can be used as a drop-in
replacement, and since this is a more common allocator scheme, and since
doing my own thing means writing my own code and getting more familiar
with Rust, it seemed a divergence worth taking.

3 months agoREADME.md: created README
Kit Rhett Aultman [Sun, 30 Jun 2024 05:26:12 +0000 (01:26 -0400)]
README.md: created README

Basic statement of goals, current requirements to run, and some notes.

3 months agomain/console: console abstraction and print macros
Kit Rhett Aultman [Sun, 30 Jun 2024 05:00:43 +0000 (01:00 -0400)]
main/console: console abstraction and print macros

This commit does a bit of a cleanup and re-org of the UART code so that
code doesn't need to create and carry around a reference to the UART to
print to the console.  This is now available through print!() and
println!()

As with the prior commit, this was heavily informed by Meyer Zinn's
excellent blog posts on bare-metal Rust, specifically this one:
https://meyerzinn.tech/posts/2023/03/08/p1-printing-and-allocating/

The idea here is to basically create a singleton Console object and then
only access it behind the print!() and println!() macros.  Since the
macros are designed to be used anywhere, they hide the interactions with
a global singleton which performs the debug outputs.

Even though I likely shouldn't have, I also did a rustfmt to clean up
syntax here.  Ah, well.

3 months agoHello world for qemu serial
Kit Rhett Aultman [Mon, 24 Jun 2024 04:06:17 +0000 (00:06 -0400)]
Hello world for qemu serial

This commit establishes the overall project structure needed for doing a bare
metal executive on RISC-V.  This currently supports the qemu risc64 emulator
because that is a target I can develop across multiple environments as I have
the free time.

This contains:
* Basic project structure
* rustc cross-compilation to riscv64-unknown-none-elf target
* Cargo integration for running qemu
* linking scripts for the qemu riscv64 virt "board" memory layout
* do-nothing panic handler
* _start function that contains the minimal RISC-V initialization: setting up
  the global pointer (gp), reserving a stack, and clearing the bss region
* Very simple use of the uart_16550 crate to print a "Hello world" message

This all came together mostly in an afternoon's work and wouldn't have been
possible without these exceptional resources:

"Running Rust code on RISC-V in Qemu"
https://meyerzinn.tech/posts/2023/03/05/running-rust-code-on-risc-v-in-qemu/

"RISC-V from scratch 2: Hardware layouts, linker scripts, and C runtimes"
https://twilco.github.io/riscv-from-scratch/2019/04/27/riscv-from-scratch-2.html