sbi/
base.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2022 repnop
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at https://mozilla.org/MPL/2.0/.

use crate::{ecall0, ecall1};

/// Base extension ID
pub const EXTENSION_ID: usize = 0x10;

/// SBI specification version implemented by the SBI implementation
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SbiSpecVersion {
    /// Major version number
    pub major: usize,
    /// Minor version number
    pub minor: usize,
}

/// Retrieve the SBI specification version
pub fn spec_version() -> SbiSpecVersion {
    let value = unsafe { ecall0(EXTENSION_ID, 0).unwrap() };
    SbiSpecVersion {
        major: (value >> 24) & 0x7f,
        minor: value & 0xff_ffff,
    }
}

/// SBI implementation name
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SbiImplId {
    BerkeleyBootLoader,
    OpenSbi,
    Xvisor,
    Kvm,
    RustSbi,
    Diosix,
    Coffer,
    Other(usize),
}

impl SbiImplId {
    /// Convert to the `usize` implementation ID value
    pub fn into_usize(self) -> usize {
        match self {
            SbiImplId::BerkeleyBootLoader => 0,
            SbiImplId::OpenSbi => 1,
            SbiImplId::Xvisor => 2,
            SbiImplId::Kvm => 3,
            SbiImplId::RustSbi => 4,
            SbiImplId::Diosix => 5,
            SbiImplId::Coffer => 6,
            SbiImplId::Other(n) => n,
        }
    }

    fn from_usize(n: usize) -> Self {
        match n {
            0 => SbiImplId::BerkeleyBootLoader,
            1 => SbiImplId::OpenSbi,
            2 => SbiImplId::Xvisor,
            3 => SbiImplId::Kvm,
            4 => SbiImplId::RustSbi,
            5 => SbiImplId::Diosix,
            6 => SbiImplId::Coffer,
            n => SbiImplId::Other(n),
        }
    }
}

/// Retrieve the SBI implementation ID
pub fn impl_id() -> SbiImplId {
    let value = unsafe { ecall0(EXTENSION_ID, 1).unwrap() };
    SbiImplId::from_usize(value)
}

/// Retrieve the SBI implementation's version. The encoding of this version
/// number is specific to the SBI implementation.
pub fn impl_version() -> usize {
    unsafe { ecall0(EXTENSION_ID, 2).unwrap() }
}

/// Extension availability information returned by `probe_extension`
#[derive(Debug, Clone, Copy)]
pub enum ExtensionAvailability {
    /// The extension is available, along with its extension-specific non-zero
    /// value
    Available(core::num::NonZeroUsize),
    /// The extension is unavailable
    Unavailable,
}

impl ExtensionAvailability {
    /// Helper method for converting `ExtensionAvailability` to a bool
    pub fn is_available(self) -> bool {
        match self {
            ExtensionAvailability::Available(_) => true,
            ExtensionAvailability::Unavailable => false,
        }
    }
}

/// Probe the availability of the extension ID `id`
pub fn probe_extension(id: usize) -> ExtensionAvailability {
    let value = unsafe { ecall1(id, EXTENSION_ID, 3).unwrap() };

    match value {
        0 => ExtensionAvailability::Unavailable,
        n => ExtensionAvailability::Available(unsafe { core::num::NonZeroUsize::new_unchecked(n) }),
    }
}

/// Retrieve the value of `mvendorid` CSR
pub fn mvendorid() -> usize {
    unsafe { ecall0(EXTENSION_ID, 4).unwrap() }
}

/// Retrieve the value of the `marchid` CSR
pub fn marchid() -> usize {
    unsafe { ecall0(EXTENSION_ID, 5).unwrap() }
}

/// Retrieve the value of the `mimpid` CSR
pub fn mimpid() -> usize {
    unsafe { ecall0(EXTENSION_ID, 6).unwrap() }
}