1 /*
2 * Copyright (c) 2015 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <arch/riscv/sbi.h>
9
10 #include <stdbool.h>
11 #include <stdio.h>
12 #include <lk/debug.h>
13 #include <lk/trace.h>
14 #include <lk/err.h>
15 #include <arch/riscv.h>
16
17 #include "riscv_priv.h"
18
19 #if RISCV_S_MODE
20
21 // bitmap of locally detected SBI extensions
22 enum sbi_extension {
23 SBI_EXTENSION_TIMER = 1,
24 SBI_EXTENSION_IPI,
25 SBI_EXTENSION_RFENCE,
26 SBI_EXTENSION_HSM,
27 SBI_EXTENSION_SRST,
28 SBI_EXTENSION_PMU,
29 SBI_EXTENSION_DBCN,
30 SBI_EXTENSION_SUSP,
31 SBI_EXTENSION_CPPC,
32 SBI_EXTENSION_NACL,
33 SBI_EXTENSION_STA,
34 };
35
36 static uint sbi_ext;
37
38 // make a SBI call according to the SBI spec at https://github.com/riscv/riscv-sbi-doc
39 // args are passed a0-a5, a6 holds the function id, a7 holds the extension id
40 // return struct sbiret in a0, a1.
41 // all registers except for a0 and a1 are preserved.
42 #define _sbi_call(extension, function, arg0, arg1, arg2, arg3, arg4, arg5, ...) ({ \
43 register unsigned long a0 asm("a0") = (unsigned long)arg0; \
44 register unsigned long a1 asm("a1") = (unsigned long)arg1; \
45 register unsigned long a2 asm("a2") = (unsigned long)arg2; \
46 register unsigned long a3 asm("a3") = (unsigned long)arg3; \
47 register unsigned long a4 asm("a4") = (unsigned long)arg4; \
48 register unsigned long a5 asm("a5") = (unsigned long)arg5; \
49 register unsigned long a6 asm("a6") = (unsigned long)function; \
50 register unsigned long a7 asm("a7") = (unsigned long)extension; \
51 asm volatile ("ecall" \
52 : "+r" (a0), "+r" (a1) \
53 : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r"(a6), "r"(a7) \
54 : "memory"); \
55 (struct sbiret){ .error = a0, .value = a1 }; \
56 })
57 #define sbi_call(...) \
58 _sbi_call(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0)
59
sbi_ext_present(enum sbi_extension e)60 static inline bool sbi_ext_present(enum sbi_extension e) {
61 return sbi_ext & (1 << e);
62 }
63
sbi_generic_call_2(ulong extension,ulong function)64 struct sbiret sbi_generic_call_2(ulong extension, ulong function) {
65 return sbi_call(extension, function);
66 }
67
sbi_probe_extension(ulong extension)68 bool sbi_probe_extension(ulong extension) {
69 return sbi_call(SBI_PROBE_EXTENSION, extension).value != 0;
70 }
71
sbi_set_timer(uint64_t stime_value)72 void sbi_set_timer(uint64_t stime_value) {
73 // use the new IPI extension
74 if (likely(sbi_ext_present(SBI_EXTENSION_TIMER))) {
75 sbi_call(SBI_EXT_TIMER_SIG, 0, stime_value);
76 } else {
77 sbi_call(SBI_SET_TIMER, stime_value);
78 }
79 }
80
sbi_send_ipis(const unsigned long * hart_mask)81 void sbi_send_ipis(const unsigned long *hart_mask) {
82 // use the new IPI extension
83 if (likely(sbi_ext_present(SBI_EXTENSION_IPI))) {
84 sbi_call(SBI_EXT_IPI_SIG, 0, *hart_mask, -1);
85 } else {
86 // legacy ipi call
87 sbi_call(SBI_SEND_IPI, hart_mask);
88 }
89 }
90
sbi_clear_ipi(void)91 void sbi_clear_ipi(void) {
92 // deprecated, clear sip.SSIP directly
93 riscv_csr_clear(RISCV_CSR_XIP, RISCV_CSR_XIP_SIP);
94 //sbi_call(SBI_CLEAR_IPI);
95 }
96
sbi_boot_hart(uint hartid,paddr_t start_addr,ulong arg)97 status_t sbi_boot_hart(uint hartid, paddr_t start_addr, ulong arg) {
98 if (!sbi_ext_present(SBI_EXTENSION_HSM))
99 return ERR_NOT_IMPLEMENTED;
100
101 // try to use the HSM implementation to boot a cpu
102 struct sbiret ret = sbi_call(SBI_EXT_HSM_SIG, 0, hartid, start_addr, arg);
103 if (ret.error < 0) {
104 return ERR_INVALID_ARGS;
105 }
106
107 return NO_ERROR;
108 }
109
sbi_rfence_vma(const unsigned long * hart_mask,vaddr_t vma,size_t size)110 void sbi_rfence_vma(const unsigned long *hart_mask, vaddr_t vma, size_t size) {
111 // use the new IPI extension
112 if (likely(sbi_ext_present(SBI_EXTENSION_RFENCE))) {
113 sbi_call(SBI_EXT_RFENCE_SIG, 1, *hart_mask, 0, vma, size);
114 } else {
115 PANIC_UNIMPLEMENTED;
116 }
117 }
118
sbi_system_reset(uint32_t type,uint32_t reason)119 status_t sbi_system_reset(uint32_t type, uint32_t reason) {
120 if (likely(sbi_ext_present(SBI_EXTENSION_SRST))) {
121 ulong error = sbi_call(SBI_EXT_SRST_SIG, 0, type, reason).error;
122 if (error != 0) {
123 return ERR_GENERIC;
124 }
125 // we really shouldn't get here
126 return NO_ERROR;
127 } else {
128 return ERR_NOT_IMPLEMENTED;
129 }
130 }
131
sbi_early_init(void)132 void sbi_early_init(void) {
133 // read the presence of some features
134 sbi_ext |= sbi_probe_extension(SBI_EXT_TIMER_SIG) ? (1<<SBI_EXTENSION_TIMER) : 0;
135 sbi_ext |= sbi_probe_extension(SBI_EXT_IPI_SIG) ? (1<<SBI_EXTENSION_IPI) : 0;
136 sbi_ext |= sbi_probe_extension(SBI_EXT_RFENCE_SIG) ? (1<<SBI_EXTENSION_RFENCE) : 0;
137 sbi_ext |= sbi_probe_extension(SBI_EXT_HSM_SIG) ? (1<<SBI_EXTENSION_HSM) : 0;
138 sbi_ext |= sbi_probe_extension(SBI_EXT_SRST_SIG) ? (1<<SBI_EXTENSION_SRST) : 0;
139 sbi_ext |= sbi_probe_extension(SBI_EXT_PMU_SIG) ? (1<<SBI_EXTENSION_PMU) : 0;
140 sbi_ext |= sbi_probe_extension(SBI_EXT_DBCN_SIG) ? (1<<SBI_EXTENSION_DBCN) : 0;
141 sbi_ext |= sbi_probe_extension(SBI_EXT_SUSP_SIG) ? (1<<SBI_EXTENSION_SUSP) : 0;
142 sbi_ext |= sbi_probe_extension(SBI_EXT_CPPC_SIG) ? (1<<SBI_EXTENSION_CPPC) : 0;
143 sbi_ext |= sbi_probe_extension(SBI_EXT_NACL_SIG) ? (1<<SBI_EXTENSION_NACL) : 0;
144 sbi_ext |= sbi_probe_extension(SBI_EXT_STA_SIG) ? (1<<SBI_EXTENSION_STA) : 0;
145 }
146
sbi_init(void)147 void sbi_init(void) {
148 ulong version = sbi_generic_call_2(SBI_GET_SBI_SPEC_VERSION).value;
149 dprintf(INFO, "RISCV: SBI spec version %lu.%lu impl id %#lx version %#lx\n",
150 (version >> 24) & 0x7f, version & ((1UL<<24)-1),
151 sbi_generic_call_2(SBI_GET_SBI_IMPL_ID).value,
152 sbi_generic_call_2(SBI_GET_SBI_IMPL_VERSION).value);
153
154 // print the extensions detected
155 if (LK_DEBUGLEVEL >= INFO) {
156 dprintf(INFO, "RISCV: SBI extensions: ");
157 if (sbi_ext_present(SBI_EXTENSION_TIMER)) dprintf(INFO, "TIMER ");
158 if (sbi_ext_present(SBI_EXTENSION_IPI)) dprintf(INFO, "IPI ");
159 if (sbi_ext_present(SBI_EXTENSION_RFENCE)) dprintf(INFO, "RFENCE ");
160 if (sbi_ext_present(SBI_EXTENSION_HSM)) dprintf(INFO, "HSM ");
161 if (sbi_ext_present(SBI_EXTENSION_SRST)) dprintf(INFO, "SRST ");
162 if (sbi_ext_present(SBI_EXTENSION_PMU)) dprintf(INFO, "PMU ");
163 if (sbi_ext_present(SBI_EXTENSION_DBCN)) dprintf(INFO, "DBCN ");
164 if (sbi_ext_present(SBI_EXTENSION_SUSP)) dprintf(INFO, "SUSP ");
165 if (sbi_ext_present(SBI_EXTENSION_CPPC)) dprintf(INFO, "CPPC ");
166 if (sbi_ext_present(SBI_EXTENSION_NACL)) dprintf(INFO, "NACL ");
167 if (sbi_ext_present(SBI_EXTENSION_STA)) dprintf(INFO, "STA ");
168 dprintf(INFO, "\n");
169 }
170 }
171
172 #endif
173
174