Skip to content
This repository was archived by the owner on Nov 28, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions asm.S
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#if __riscv_xlen == 64
# define XLEN_WORD .8byte
# define STORE sd
# define LOAD ld
# define LOG_REGBYTES 3
#else
# define XLEN_WORD .4byte
# define STORE sw
# define LOAD lw
# define LOG_REGBYTES 2
Expand Down Expand Up @@ -46,6 +48,17 @@ _abs_start:
.cfi_startproc
.cfi_undefined ra

la t0, boot_args
STORE a0, 0*REGBYTES(t0)
STORE a1, 1*REGBYTES(t0)
STORE a2, 2*REGBYTES(t0)
STORE a3, 3*REGBYTES(t0)
STORE a4, 4*REGBYTES(t0)
STORE a5, 5*REGBYTES(t0)
STORE a6, 6*REGBYTES(t0)
STORE a7, 7*REGBYTES(t0)
fence rw, rw

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not confident about this (single) fence, or about using plain reads in fn boot_arguments.

At first I started emulating the behavior of AtomicUsize: https://rust.godbolt.org/z/3djWjhPcG. But why is the fence instruction placed before stores and after loads? I’d expected fences to be between things in order to separate them.

On the Rust size I ended up with this, since AtomicUsize is disabled on targets without the A extension. The portable-atomic crate would be another option for doing the same.

/// Simulate AtomicUsize::load(Ordering::Acquire)
unsafe fn atomic_load(ptr: *const usize) -> usize {
    let value;

    // Only lw v.s. ld changes but asm! wants a string literal
    #[cfg(target_pointer_width = "32")]
    core::arch::asm!(
        "fence r, rw",
        "lw {value}, 0({ptr})",
        ptr = in(reg) ptr,
        value = out(reg) value,
    );
    #[cfg(not(target_pointer_width = "32"))]
    core::arch::asm!(
        "fence r, rw",
        "ld {value}, 0({ptr})",
        ptr = in(reg) ptr,
        value = out(reg) value,
    );
    value
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Position of fence instructions depends on the ordering. With SeqCst you get fences before and after the load.


csrw mie, 0
csrw mip, 0

Expand Down Expand Up @@ -117,6 +130,21 @@ _abs_start:

.cfi_endproc

/*
Space to save the value of argument registers at boot
*/
.section .data
.global boot_args
boot_args:
XLEN_WORD 0 // a0
XLEN_WORD 0 // a1
XLEN_WORD 0 // a2
XLEN_WORD 0 // a3
XLEN_WORD 0 // a4
XLEN_WORD 0 // a5
XLEN_WORD 0 // a6
XLEN_WORD 0 // a7

/*
Trap entry point (_start_trap)

Expand Down
Binary file modified bin/riscv32i-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv32ic-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv32if-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv32ifc-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv32ifd-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv32ifdc-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv32im-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv32imc-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv32imf-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv32imfc-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv32imfd-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv32imfdc-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv64i-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv64ic-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv64if-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv64ifc-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv64ifd-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv64ifdc-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv64im-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv64imc-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv64imf-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv64imfc-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv64imfd-unknown-none-elf.a
Binary file not shown.
Binary file modified bin/riscv64imfdc-unknown-none-elf.a
Binary file not shown.
13 changes: 13 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,13 @@ extern "C" {

// Initial values of the .data section (stored in Flash)
static _sidata: u32;

static boot_args: [usize; ARGUMENT_REGISTERS_COUNT];
}

/// a0 to a7
const ARGUMENT_REGISTERS_COUNT: usize = 8;

/// Rust entry point (_start_rust)
///
/// Zeros bss section, initializes data section and calls main. This function
Expand Down Expand Up @@ -389,6 +394,14 @@ pub unsafe extern "C" fn start_rust() -> ! {
main();
}

/// Returns the value an argument register had when this firmware was first booted.
///
/// Some of these registers may have values passed by the previous boot stage:
/// <https://doc.coreboot.org/arch/riscv/index.html#stage-handoff-protocol>
pub fn boot_argument(index: usize) -> Option<usize> {
unsafe { boot_args.get(index).copied() }
}

/// Registers saved in trap handler
#[allow(missing_docs)]
#[repr(C)]
Expand Down