assemblyrustinline-assemblyriscv

Is this inline RISC-V Rust assembly correct?


So I'm trying to use the RISC-V SBI debug console extension of OpenSBI on Qemu using inline Rust assembly, but it isn't working. I've come to learn that the issue may be because of memory placement, but I'd still like to know if my assembly is correct to narrow my troubleshooting down, even if you don't know the SBI specification, I'd appreciate knowing if my general inline assembly format is correct:

pub fn debug_console_write(text: &str) -> SBIResult {
    let mut sbi_result = SBIResult::new();
    unsafe {
        asm!(
            "li a7, 0x4442434E", // Specifies SBI extension
            "li a6, 0x00", //  Specifies function ID in extension
            "lw a0, ({})", // Provides number of bytes in string
            "lw a1, ({})", // Provides pointer to string
            "li a2, 0", // Provides the high end of the pointers address which should always be 0
            "ecall", // Short for "enviroment call", in this case it's a call to the sbi
            in(reg) &text.len(), // Provides number of bytes in string
            in(reg) &text.as_ptr(), // Provides pointer to string
            lateout("a0") sbi_result.error, // Puts error value from sbi call into result struct
            lateout("a1") sbi_result.value, // Puts value value from sbi call into result struct
            out("a7") _, // Clobbering a7
            out("a6") _, // Clobbering a6
            out("a2") _, // Clobbering a2
            clobber_abi("system") // Clobbering everything else that the system specifcation specifies
        );
    }

    return sbi_result
}

Note that the error and value fields are both isize.


Solution

  • This works:

    pub fn debug_console_write(text: &str) -> SBIResult {
        let mut sbi_result = SBIResult::new();
        unsafe {
            asm!(
                "li a7, 0x4442434E", // Specifies SBI extension
                "li a6, 0x00", //  Specifies function ID in extension
                "li a2, 0", // Provides the high end of the pointers address which should always be 0
                "ecall", // Short for "enviroment call", in this case it's a call to the sbi
                lateout("a0") sbi_result.error, // Puts error value from sbi call into result struct
                lateout("a1") sbi_result.value, // Puts value value from sbi call into result struct
                in("a0") text.len(), // Provides number of bytes in string
                in("a1") text.as_ptr(), // Provides pointer to string
                clobber_abi("system")
            );
        }
    
        return sbi_result
    }
    

    I'm not sure if the previous one worked or not because of other issues, but I know this one does, for now at least.