Keyboard shortcuts

Press ← or β†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Appendix D. SBI Call Reference

Supervisor Binary Interface (SBI) Quick Reference


πŸ’‘ Usage Guide: This appendix is your β€œAPI manual” for S-mode calling M-mode services. When you forget whether a7 is EID or FID, flip right here.


🎯 SBI Calling Convention Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    S-mode (Kernel/OS)                           β”‚
β”‚                                                                 β”‚
β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”‚
β”‚    β”‚   a7    β”‚ β”‚   a6    β”‚ β”‚ a0-a5   β”‚ β”‚  ecall  β”‚             β”‚
β”‚    β”‚  EID    β”‚ β”‚  FID    β”‚ β”‚  Args   β”‚ β”‚ ──────► β”‚             β”‚
β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜             β”‚
β”‚       β”‚           β”‚           β”‚                                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚       β–Ό           β–Ό           β–Ό                                 β”‚
β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β”‚
β”‚    β”‚         Trap to M-mode (OpenSBI)        β”‚                 β”‚
β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
β”‚       β”‚                                                         β”‚
β”‚       β–Ό                                                         β”‚
β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                     β”‚
β”‚    β”‚   a0    β”‚ β”‚   a1    β”‚                                     β”‚
β”‚    β”‚ Error   β”‚ β”‚ Value   β”‚                                     β”‚
β”‚    β”‚  Code   β”‚ β”‚(Return) β”‚                                     β”‚
β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                     β”‚
β”‚                                                                 β”‚
β”‚                    M-mode (OpenSBI Firmware)                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Memory Aid: a7 = EID (Which Extension), a6 = FID (Which Function)


πŸ“‹ Common EID Quick Reference

EID (Hex)EID (ASCII)NamePurposeCommon FID
0x10β€”BaseQuery SBI version/vendor0=version, 3=probe Extension
0x54494D45β€œTIME”TimerSet Timer interrupt0=set_timer
0x735049β€œsPI”IPICross-core interrupt0=send_ipi
0x52464E43β€œRFNC”RFENCERemote TLB flush0-6 (various fences)
0x4442434Eβ€œDBCN”Debug ConsoleDebug output0=write, 1=read
0x48534Dβ€œHSM”Hart State MgmtStart/stop Hart0=start, 1=stop

πŸ› οΈ Common SBI Wrappers (Copy-Paste Ready)

sbi_call Universal Interface

struct sbiret {
    long error;
    long value;
};

static inline struct sbiret sbi_call(long eid, long fid,
    long a0, long a1, long a2, long a3, long a4, long a5)
{
    struct sbiret ret;
    register long r_a0 asm("a0") = a0;
    register long r_a1 asm("a1") = a1;
    register long r_a2 asm("a2") = a2;
    register long r_a3 asm("a3") = a3;
    register long r_a4 asm("a4") = a4;
    register long r_a5 asm("a5") = a5;
    register long r_a6 asm("a6") = fid;
    register long r_a7 asm("a7") = eid;

    asm volatile("ecall"
        : "+r"(r_a0), "+r"(r_a1)
        : "r"(r_a2), "r"(r_a3), "r"(r_a4), "r"(r_a5), "r"(r_a6), "r"(r_a7)
        : "memory");

    ret.error = r_a0;
    ret.value = r_a1;
    return ret;
}

Common Function Wrappers

// 1. Set Timer Interrupt (Most commonly used!)
static inline void sbi_set_timer(uint64_t stime_value) {
    sbi_call(0x54494D45, 0, stime_value, 0, 0, 0, 0, 0);
}

// 2. Write a character (Debug Console)
static inline void sbi_debug_console_write_byte(char c) {
    sbi_call(0x4442434E, 2, c, 0, 0, 0, 0, 0);
}

// 3. Query SBI version
static inline long sbi_get_spec_version(void) {
    struct sbiret ret = sbi_call(0x10, 0, 0, 0, 0, 0, 0, 0);
    return ret.value;
}

// 4. Probe if Extension is supported
static inline long sbi_probe_extension(long eid) {
    struct sbiret ret = sbi_call(0x10, 3, eid, 0, 0, 0, 0, 0);
    return ret.value;  // 0 = not supported, non-0 = supported
}

⚠️ Common Pitfalls

Pitfall 1: EID and FID Order Confused

Symptom: SBI call returns SBI_ERR_NOT_SUPPORTED.

Cause: a7 and a6 are swapped.

// ❌ Wrong: EID and FID swapped
register long a6 asm("a6") = 0x10;        // Should be FID
register long a7 asm("a7") = 0;           // Should be EID

// βœ… Correct: a7=EID, a6=FID
register long a6 asm("a6") = 0;           // FID = 0 (get_spec_version)
register long a7 asm("a7") = 0x10;        // EID = 0x10 (Base Extension)

Pitfall 2: Forgetting to Check Error Code

Symptom: SBI call fails but program continues, causing hard-to-trace subsequent errors.

// ❌ Wrong: Ignoring error code
sbi_set_timer(next_time);

// βœ… Correct: Check error
struct sbiret ret = sbi_call(0x54494D45, 0, next_time, 0, 0, 0, 0, 0);
if (ret.error != 0) {
    panic("sbi_set_timer failed: %ld", ret.error);
}

This appendix provides a comprehensive reference for RISC-V SBI (Supervisor Binary Interface) calls. SBI defines the standard interface between supervisor mode (S-mode) software and machine mode (M-mode) firmware, enabling portable operating systems across different RISC-V platforms.


D.1 SBI Calling Convention

Register Usage

Input Registers:

RegisterPurpose
a7Extension ID (EID)
a6Function ID (FID)
a0Parameter 0 / Return value
a1Parameter 1 / Return value (optional)
a2Parameter 2
a3Parameter 3
a4Parameter 4
a5Parameter 5

Output Registers:

RegisterPurpose
a0Error code (0 = success, negative = error)
a1Return value (function-specific)

Preserved Registers: All registers except a0 and a1 are preserved across SBI calls.

Invocation

// S-mode code invokes SBI using ecall instruction
register unsigned long a0 asm("a0") = param0;
register unsigned long a1 asm("a1") = param1;
register unsigned long a6 asm("a6") = function_id;
register unsigned long a7 asm("a7") = extension_id;

asm volatile("ecall"
             : "+r"(a0), "+r"(a1)
             : "r"(a6), "r"(a7)
             : "memory");

// a0 contains error code, a1 contains return value

D.2 SBI Error Codes

CodeNameDescription
0SBI_SUCCESSOperation completed successfully
-1SBI_ERR_FAILEDOperation failed
-2SBI_ERR_NOT_SUPPORTEDFunction not supported
-3SBI_ERR_INVALID_PARAMInvalid parameter
-4SBI_ERR_DENIEDPermission denied
-5SBI_ERR_INVALID_ADDRESSInvalid address
-6SBI_ERR_ALREADY_AVAILABLEResource already available
-7SBI_ERR_ALREADY_STARTEDAlready started
-8SBI_ERR_ALREADY_STOPPEDAlready stopped

D.3 Base Extension (EID = 0x10)

Purpose: Query SBI implementation details and supported extensions.

D.3.1 Get SBI Specification Version (FID = 0)

Returns: SBI specification version.

  • a1[31:24]: Major version
  • a1[23:0]: Minor version
long sbi_get_spec_version(void) {
    register unsigned long a0 asm("a0");
    register unsigned long a1 asm("a1");
    register unsigned long a6 asm("a6") = 0;
    register unsigned long a7 asm("a7") = 0x10;
    
    asm volatile("ecall" : "=r"(a0), "=r"(a1) : "r"(a6), "r"(a7) : "memory");
    return a1;  // Version in a1
}

D.3.2 Get SBI Implementation ID (FID = 1)

Returns: Implementation ID.

IDImplementation
0Berkeley Boot Loader (BBL)
1OpenSBI
2Xvisor
3KVM
4RustSBI
5Diosix

D.3.3 Get SBI Implementation Version (FID = 2)

Returns: Implementation-specific version number.

D.3.4 Probe SBI Extension (FID = 3)

Parameters:

  • a0: Extension ID to probe

Returns:

  • a1: 0 = not available, 1 = available
long sbi_probe_extension(long extension_id) {
    register unsigned long a0 asm("a0") = extension_id;
    register unsigned long a1 asm("a1");
    register unsigned long a6 asm("a6") = 3;
    register unsigned long a7 asm("a7") = 0x10;
    
    asm volatile("ecall" : "+r"(a0), "=r"(a1) : "r"(a6), "r"(a7) : "memory");
    return a1;
}

D.3.5 Get Machine Vendor ID (FID = 4)

Returns: mvendorid CSR value.

D.3.6 Get Machine Architecture ID (FID = 5)

Returns: marchid CSR value.

D.3.7 Get Machine Implementation ID (FID = 6)

Returns: mimpid CSR value.


D.4 Timer Extension (EID = 0x54494D45 β€œTIME”)

Purpose: Program timer interrupts.

D.4.1 Set Timer (FID = 0)

Parameters:

  • a0: Timer value (absolute time in ticks)

Description: Programs the timer to fire at the specified time. Clears pending timer interrupt.

void sbi_set_timer(uint64_t stime_value) {
    register unsigned long a0 asm("a0") = stime_value;
    register unsigned long a6 asm("a6") = 0;
    register unsigned long a7 asm("a7") = 0x54494D45;
    
    asm volatile("ecall" : "+r"(a0) : "r"(a6), "r"(a7) : "memory");
}

// Usage: Set timer to fire in 1 second (assuming 10 MHz timebase)
uint64_t current_time;
asm volatile("rdtime %0" : "=r"(current_time));
sbi_set_timer(current_time + 10000000);

D.5 IPI Extension (EID = 0x735049 β€œsPI”)

Purpose: Send inter-processor interrupts.

D.5.1 Send IPI (FID = 0)

Parameters:

  • a0: Hart mask (bitmap of target harts)
  • a1: Hart mask base (base hart ID for the mask)

Description: Sends supervisor software interrupt to specified harts.

long sbi_send_ipi(unsigned long hart_mask, unsigned long hart_mask_base) {
    register unsigned long a0 asm("a0") = hart_mask;
    register unsigned long a1 asm("a1") = hart_mask_base;
    register unsigned long a6 asm("a6") = 0;
    register unsigned long a7 asm("a7") = 0x735049;

    asm volatile("ecall" : "+r"(a0), "+r"(a1) : "r"(a6), "r"(a7) : "memory");
    return a0;
}

// Usage: Send IPI to harts 1, 2, 3
sbi_send_ipi(0b1110, 0);  // Bits 1, 2, 3 set, base = 0

// Send IPI to hart 65 (bit 1 of mask, base = 64)
sbi_send_ipi(0b10, 64);

D.6 RFENCE Extension (EID = 0x52464E43 β€œRFNC”)

Purpose: Remote fence operations for TLB and instruction cache synchronization.

D.6.1 Remote FENCE.I (FID = 0)

Parameters:

  • a0: Hart mask
  • a1: Hart mask base

Description: Execute FENCE.I on remote harts.

long sbi_remote_fence_i(unsigned long hart_mask, unsigned long hart_mask_base) {
    register unsigned long a0 asm("a0") = hart_mask;
    register unsigned long a1 asm("a1") = hart_mask_base;
    register unsigned long a6 asm("a6") = 0;
    register unsigned long a7 asm("a7") = 0x52464E43;

    asm volatile("ecall" : "+r"(a0), "+r"(a1) : "r"(a6), "r"(a7) : "memory");
    return a0;
}

D.6.2 Remote SFENCE.VMA (FID = 1)

Parameters:

  • a0: Hart mask
  • a1: Hart mask base
  • a2: Start address (virtual address)
  • a3: Size (number of pages)

Description: Execute SFENCE.VMA on remote harts for specified address range.

long sbi_remote_sfence_vma(unsigned long hart_mask, unsigned long hart_mask_base,
                           unsigned long start_addr, unsigned long size) {
    register unsigned long a0 asm("a0") = hart_mask;
    register unsigned long a1 asm("a1") = hart_mask_base;
    register unsigned long a2 asm("a2") = start_addr;
    register unsigned long a3 asm("a3") = size;
    register unsigned long a6 asm("a6") = 1;
    register unsigned long a7 asm("a7") = 0x52464E43;

    asm volatile("ecall" : "+r"(a0), "+r"(a1)
                 : "r"(a2), "r"(a3), "r"(a6), "r"(a7) : "memory");
    return a0;
}

// Usage: Flush TLB for address range on all harts
sbi_remote_sfence_vma(~0UL, 0, 0x80000000, 4096);  // Flush 1 page

D.6.3 Remote SFENCE.VMA with ASID (FID = 2)

Parameters:

  • a0: Hart mask
  • a1: Hart mask base
  • a2: Start address
  • a3: Size
  • a4: ASID

Description: Execute SFENCE.VMA with ASID on remote harts.

long sbi_remote_sfence_vma_asid(unsigned long hart_mask, unsigned long hart_mask_base,
                                unsigned long start_addr, unsigned long size,
                                unsigned long asid) {
    register unsigned long a0 asm("a0") = hart_mask;
    register unsigned long a1 asm("a1") = hart_mask_base;
    register unsigned long a2 asm("a2") = start_addr;
    register unsigned long a3 asm("a3") = size;
    register unsigned long a4 asm("a4") = asid;
    register unsigned long a6 asm("a6") = 2;
    register unsigned long a7 asm("a7") = 0x52464E43;

    asm volatile("ecall" : "+r"(a0), "+r"(a1)
                 : "r"(a2), "r"(a3), "r"(a4), "r"(a6), "r"(a7) : "memory");
    return a0;
}

D.6.4 Remote HFENCE.GVMA (FID = 3)

Parameters:

  • a0: Hart mask
  • a1: Hart mask base
  • a2: Guest physical address
  • a3: Size

Description: Execute HFENCE.GVMA on remote harts (hypervisor extension).

D.6.5 Remote HFENCE.GVMA with VMID (FID = 4)

Parameters:

  • a0: Hart mask
  • a1: Hart mask base
  • a2: Guest physical address
  • a3: Size
  • a4: VMID

Description: Execute HFENCE.GVMA with VMID on remote harts.

D.6.6 Remote HFENCE.VVMA (FID = 5)

Parameters:

  • a0: Hart mask
  • a1: Hart mask base
  • a2: Guest virtual address
  • a3: Size

Description: Execute HFENCE.VVMA on remote harts.

D.6.7 Remote HFENCE.VVMA with ASID (FID = 6)

Parameters:

  • a0: Hart mask
  • a1: Hart mask base
  • a2: Guest virtual address
  • a3: Size
  • a4: ASID

Description: Execute HFENCE.VVMA with ASID on remote harts.


D.7 Hart State Management Extension (EID = 0x48534D β€œHSM”)

Purpose: Manage hart lifecycle (start, stop, suspend).

D.7.1 Hart Start (FID = 0)

Parameters:

  • a0: Hart ID
  • a1: Start address (physical address)
  • a2: Opaque parameter (passed to hart in a1)

Returns: SBI_SUCCESS or error code

Description: Start the specified hart at the given address.

long sbi_hart_start(unsigned long hartid, unsigned long start_addr,
                    unsigned long opaque) {
    register unsigned long a0 asm("a0") = hartid;
    register unsigned long a1 asm("a1") = start_addr;
    register unsigned long a2 asm("a2") = opaque;
    register unsigned long a6 asm("a6") = 0;
    register unsigned long a7 asm("a7") = 0x48534D;

    asm volatile("ecall" : "+r"(a0), "+r"(a1)
                 : "r"(a2), "r"(a6), "r"(a7) : "memory");
    return a0;
}

// Usage: Start hart 1 at address 0x80200000
sbi_hart_start(1, 0x80200000, 0);

D.7.2 Hart Stop (FID = 1)

Parameters: None

Returns: Does not return on success

Description: Stop the current hart. Hart enters stopped state.

void sbi_hart_stop(void) {
    register unsigned long a6 asm("a6") = 1;
    register unsigned long a7 asm("a7") = 0x48534D;

    asm volatile("ecall" : : "r"(a6), "r"(a7) : "memory");
}

D.7.3 Hart Get Status (FID = 2)

Parameters:

  • a0: Hart ID

Returns:

  • a1: Hart status

Hart Status Values:

ValueStatus
0STARTED
1STOPPED
2START_PENDING
3STOP_PENDING
4SUSPENDED
5SUSPEND_PENDING
6RESUME_PENDING
long sbi_hart_get_status(unsigned long hartid) {
    register unsigned long a0 asm("a0") = hartid;
    register unsigned long a1 asm("a1");
    register unsigned long a6 asm("a6") = 2;
    register unsigned long a7 asm("a7") = 0x48534D;

    asm volatile("ecall" : "+r"(a0), "=r"(a1) : "r"(a6), "r"(a7) : "memory");
    return a1;
}

D.7.4 Hart Suspend (FID = 3)

Parameters:

  • a0: Suspend type
  • a1: Resume address
  • a2: Opaque parameter

Suspend Types:

ValueType
0x00000000RETENTIVE (retain state, low latency)
0x80000000NON_RETENTIVE (lose state, save/restore required)

D.8 System Reset Extension (EID = 0x53525354 β€œSRST”)

Purpose: System-wide reset and shutdown.

D.8.1 System Reset (FID = 0)

Parameters:

  • a0: Reset type
  • a1: Reset reason

Returns: Does not return on success

Reset Types:

ValueType
0x00000000SHUTDOWN
0x00000001COLD_REBOOT
0x00000002WARM_REBOOT

Reset Reasons:

ValueReason
0x00000000NO_REASON
0x00000001SYSTEM_FAILURE
void sbi_system_reset(unsigned long reset_type, unsigned long reset_reason) {
    register unsigned long a0 asm("a0") = reset_type;
    register unsigned long a1 asm("a1") = reset_reason;
    register unsigned long a6 asm("a6") = 0;
    register unsigned long a7 asm("a7") = 0x53525354;

    asm volatile("ecall" : : "r"(a0), "r"(a1), "r"(a6), "r"(a7) : "memory");
    __builtin_unreachable();
}

// Usage: Reboot the system
#define SBI_RESET_TYPE_COLD_REBOOT 1
#define SBI_RESET_REASON_NO_REASON 0
sbi_system_reset(SBI_RESET_TYPE_COLD_REBOOT, SBI_RESET_REASON_NO_REASON);

D.9 Performance Monitoring Unit Extension (EID = 0x504D55 β€œPMU”)

Purpose: Configure and read performance counters.

D.9.1 Get Number of Counters (FID = 0)

Returns:

  • a1: Number of counters

D.9.2 Get Counter Info (FID = 1)

Parameters:

  • a0: Counter index

Returns:

  • a1: Counter info

D.9.3 Configure Matching Counters (FID = 2)

Parameters:

  • a0: Counter index base
  • a1: Counter mask
  • a2: Config flags
  • a3: Event index
  • a4: Event data

Returns: Number of counters configured

D.9.4 Start Counters (FID = 3)

Parameters:

  • a0: Counter index base
  • a1: Counter mask
  • a2: Start flags
  • a3: Initial value

D.9.5 Stop Counters (FID = 4)

Parameters:

  • a0: Counter index base
  • a1: Counter mask
  • a2: Stop flags

D.9.6 Read Firmware Counter (FID = 5)

Parameters:

  • a0: Counter index

Returns:

  • a1: Counter value

D.10 Legacy Extensions (Deprecated)

Note: These extensions are deprecated but still widely used for compatibility.

D.10.1 Console Putchar (EID = 0x01)

Parameters:

  • a0: Character to output
void sbi_console_putchar(int ch) {
    register unsigned long a0 asm("a0") = ch;
    register unsigned long a7 asm("a7") = 0x01;

    asm volatile("ecall" : "+r"(a0) : "r"(a7) : "memory");
}

D.10.2 Console Getchar (EID = 0x02)

Returns:

  • a0: Character read, or -1 if no character available
int sbi_console_getchar(void) {
    register unsigned long a0 asm("a0");
    register unsigned long a7 asm("a7") = 0x02;

    asm volatile("ecall" : "=r"(a0) : "r"(a7) : "memory");
    return a0;
}

D.10.3 Legacy Set Timer (EID = 0x00)

Parameters:

  • a0: Timer value

Note: Use Timer Extension (0x54494D45) instead.

D.10.4 Legacy Clear IPI (EID = 0x03)

Note: Deprecated. Clear sip.SSIP bit directly.

D.10.5 Legacy Send IPI (EID = 0x04)

Parameters:

  • a0: Hart mask pointer

Note: Use IPI Extension (0x735049) instead.

D.10.6 Legacy Remote FENCE.I (EID = 0x05)

Parameters:

  • a0: Hart mask pointer

Note: Use RFENCE Extension (0x52464E43) instead.

D.10.7 Legacy Remote SFENCE.VMA (EID = 0x06)

Parameters:

  • a0: Hart mask pointer
  • a1: Start address
  • a2: Size

Note: Use RFENCE Extension instead.

D.10.8 Legacy Remote SFENCE.VMA with ASID (EID = 0x07)

Parameters:

  • a0: Hart mask pointer
  • a1: Start address
  • a2: Size
  • a3: ASID

Note: Use RFENCE Extension instead.

D.10.9 Legacy System Shutdown (EID = 0x08)

Note: Use System Reset Extension (0x53525354) instead.


D.11 Extension ID Summary

EIDNameDescription
0x10BASEBase extension (version, probe)
0x54494D45TIMETimer programming
0x735049sPIInter-processor interrupts
0x52464E43RFNCRemote fence operations
0x48534DHSMHart state management
0x53525354SRSTSystem reset
0x504D55PMUPerformance monitoring
0x4442434EDBCNDebug console
0x53555350SUSPSystem suspend
0x43505043CPPCCollaborative Processor Performance Control
0x4E41434CNACLNested Acceleration

D.12 Common Usage Patterns

Early Boot Console Output

void early_printk(const char *str) {
    while (*str) {
        if (*str == '\n')
            sbi_console_putchar('\r');
        sbi_console_putchar(*str++);
    }
}

Timer-based Scheduling

void setup_timer_interrupt(uint64_t interval_us) {
    uint64_t current_time;
    asm volatile("rdtime %0" : "=r"(current_time));

    // Assuming 10 MHz timebase (100 ns per tick)
    uint64_t ticks = interval_us * 10;
    sbi_set_timer(current_time + ticks);

    // Enable supervisor timer interrupt
    csr_set(sie, SIE_STIE);
}

Multi-core Synchronization

void flush_tlb_all_harts(void) {
    // Flush TLB on all harts
    sbi_remote_sfence_vma(~0UL, 0, 0, ~0UL);
}

void wake_up_secondary_harts(void) {
    for (int i = 1; i < num_harts; i++) {
        sbi_hart_start(i, (unsigned long)secondary_start, 0);
    }
}

System Shutdown

void system_poweroff(void) {
    sbi_system_reset(0, 0);  // SHUTDOWN, NO_REASON
    while (1);  // Should never reach here
}

void system_reboot(void) {
    sbi_system_reset(1, 0);  // COLD_REBOOT, NO_REASON
    while (1);
}

D.13 References

  • SBI Specification: https://github.com/riscv-non-isa/riscv-sbi-doc
  • OpenSBI Documentation: https://github.com/riscv-software-src/opensbi
  • Linux RISC-V SBI Implementation: arch/riscv/kernel/sbi.c