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