Skip to content

Commit

Permalink
feat: add 64-bit RISC-V support
Browse files Browse the repository at this point in the history
Usage with QEMU is similar to the x86 version:
The loader is passed via "-kernel" and the application via "-initrd".

Co-authored-by: Martin Kröning <[email protected]>
Signed-off-by: Martin Kröning <[email protected]>
  • Loading branch information
simonschoening and mkroening committed Aug 11, 2023
1 parent 910c125 commit 076dd18
Show file tree
Hide file tree
Showing 12 changed files with 461 additions and 3 deletions.
26 changes: 24 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ jobs:
name: Run
strategy:
matrix:
target: [x86_64, x86_64-uefi, x86_64-fc, aarch64]
target: [x86_64, x86_64-uefi, x86_64-fc, aarch64, riscv64]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Install QEMU, NASM (ubuntu)
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install qemu-system-x86 qemu-system-arm nasm
sudo apt-get install qemu-system-x86 qemu-system-arm qemu-system-misc nasm
- name: Install QEMU, NASM (macos)
if: matrix.os == 'macos-latest'
run: |
Expand Down Expand Up @@ -96,6 +96,17 @@ jobs:
-display none -serial stdio -semihosting \
-kernel target/aarch64/debug/rusty-loader \
-device guest-loader,addr=0x48000000,initrd=data/aarch64/hello_world
- name: Run loader (riscv64)
if: matrix.target == 'riscv64'
run: |
qemu-system-riscv64 \
-machine virt \
-cpu rv64 \
-smp 1 \
-m 32M \
-display none -serial stdio \
-kernel target/riscv64/debug/rusty-loader \
-initrd data/riscv64/hello_world
- name: Build (release)
run: cargo xtask build --target ${{ matrix.target }} --release
- name: Run loader (release, x86_64)
Expand Down Expand Up @@ -123,3 +134,14 @@ jobs:
-display none -serial stdio -semihosting \
-kernel target/aarch64/release/rusty-loader \
-device guest-loader,addr=0x48000000,initrd=data/aarch64/hello_world
- name: Run loader (release, riscv64)
if: matrix.target == 'riscv64'
run: |
qemu-system-riscv64 \
-machine virt \
-cpu rv64 \
-smp 1 \
-m 32M \
-display none -serial stdio \
-kernel target/riscv64/release/rusty-loader \
-initrd data/riscv64/hello_world
92 changes: 92 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ goblin = { version = "0.7", default-features = false, features = ["elf64"] }
uefi = "0.24"
uefi-services = "0.21"

[target.'cfg(target_arch = "riscv64")'.dependencies]
fdt = "0.1"
naked-function = "0.1"
riscv = "0.10"
sbi = "0.2"
sptr = "0.3"

[build-dependencies]
cc = "1.0"
nasm-rs = "0.2"
Expand Down
3 changes: 3 additions & 0 deletions data/riscv64/hello_world
Git LFS file not shown
5 changes: 5 additions & 0 deletions src/arch/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
#[cfg(target_arch = "aarch64")]
pub use crate::arch::aarch64::*;
#[cfg(target_arch = "riscv64")]
pub use crate::arch::riscv64::*;
#[cfg(target_arch = "x86_64")]
pub use crate::arch::x86_64::*;

#[cfg(target_arch = "aarch64")]
pub mod aarch64;

#[cfg(target_arch = "riscv64")]
pub mod riscv64;

#[cfg(target_arch = "x86_64")]
pub mod x86_64;
87 changes: 87 additions & 0 deletions src/arch/riscv64/address_range.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// TODO: Move this into its own crate.
#![allow(dead_code)]

use core::cmp::Ordering;
use core::fmt;
use core::ops::Range;

use align_address::Align;

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct AddressRange {
start: usize,
end: usize,
}

impl AddressRange {
pub fn new(start: usize, end: usize) -> Option<Self> {
(start <= end).then_some(Self { start, end })
}

pub fn from_start_len(start: usize, len: usize) -> Self {
Self {
start,
end: start + len,
}
}

pub fn overlaps(self, other: Self) -> bool {
self.partial_cmp(&other).is_none()
}

pub fn next(self, len: usize) -> Self {
Self::from_start_len(self.end, len)
}

pub fn align_to(self, align: usize) -> Self {
Self {
start: self.start.align_down(align),
end: self.end.align_up(align),
}
}

pub fn start(self) -> usize {
self.start
}

pub fn end(self) -> usize {
self.end
}

pub fn len(self) -> usize {
self.end - self.start
}
}

#[derive(Debug)]
pub struct TryFromRangeError(());

impl<T> TryFrom<Range<*const T>> for AddressRange {
type Error = TryFromRangeError;

fn try_from(value: Range<*const T>) -> Result<Self, Self::Error> {
Self::new(value.start as usize, value.end as usize).ok_or(TryFromRangeError(()))
}
}

impl fmt::Display for AddressRange {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { start, end } = self;
let len = self.len();
write!(f, "{start:#x}..{end:#x} (len = {len:#10x})")
}
}

impl PartialOrd for AddressRange {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
if self.end <= other.start {
Some(Ordering::Less)
} else if self.start >= other.end {
Some(Ordering::Greater)
} else if self == other {
Some(Ordering::Equal)
} else {
None
}
}
}
28 changes: 28 additions & 0 deletions src/arch/riscv64/link.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
ENTRY(_start)
phys = 0x0000000080200000;

SECTIONS
{
kernel_start = phys;
.text phys : AT(ADDR(.text)) {
*(.text._start)
*(.text.*)
}
.rodata ALIGN(4096) : AT(ADDR(.rodata)) {
*(.rodata)
*(.rodata.*)
}
.data ALIGN(4096) : AT(ADDR(.data)) {
*(.data)
*(.data.*)
}
.bss ALIGN(4096) : AT(ADDR(.bss)) {
*(.bss)
*(.bss.*)
}
.sbss ALIGN(4096) : AT(ADDR(.sbss)) {
*(.sbss)
*(.sbss.*)
}
kernel_end = .;
}
Loading

0 comments on commit 076dd18

Please sign in to comment.