1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
6 #include <arch/exception.h>
9 #include <console/uart.h>
10 #include <commonlib/helpers.h>
12 static uintptr_t send_ipi(uintptr_t *pmask
, intptr_t type
)
14 uintptr_t mask
= mprv_read_uintptr_t(pmask
);
15 for (int i
= 0; mask
; i
++) {
17 OTHER_HLS(i
)->ipi_pending
|= type
;
18 /* send soft interrupt to target hart */
26 static uintptr_t sbi_set_timer(uint64_t when
)
28 clear_csr(mip
, MIP_STIP
);
29 set_csr(mie
, MIP_MTIP
);
30 *(HLS()->timecmp
) = when
;
34 #if CONFIG(CONSOLE_SERIAL)
35 static uintptr_t sbi_console_putchar(uint8_t ch
)
37 uart_tx_byte(CONFIG_UART_FOR_CONSOLE
, ch
);
41 static uintptr_t sbi_console_getchar(void)
43 return uart_rx_byte(CONFIG_UART_FOR_CONSOLE
);
47 static uintptr_t sbi_clear_ipi(void)
49 clear_csr(mip
, MIP_SSIP
);
53 static void print_sbi_trap(uintptr_t trap
)
57 printk(BIOS_EMERG
, "SBI_SHUTDOWN\n");
59 case SBI_REMOTE_SFENCE_VMA_ASID
:
60 printk(BIOS_EMERG
, "SBI_REMOTE_SFENCE_VMA_ASID\n");
62 case SBI_REMOTE_SFENCE_VMA
:
63 printk(BIOS_EMERG
, "SBI_REMOTE_SFENCE_VMA\n");
65 case SBI_REMOTE_FENCE_I
:
66 printk(BIOS_EMERG
, "SBI_REMOTE_FENCE_I\n");
69 printk(BIOS_EMERG
, "SBI_SEND_IPI\n");
72 printk(BIOS_EMERG
, "SBI_CLEAR_IPI\n");
74 case SBI_CONSOLE_GETCHAR
:
75 printk(BIOS_EMERG
, "SBI_CONSOLE_GETCHAR\n");
77 case SBI_CONSOLE_PUTCHAR
:
78 printk(BIOS_EMERG
, "SBI_CONSOLE_PUTCHAR\n");
81 printk(BIOS_EMERG
, "SBI_SET_TIMER\n");
83 case SBI_BASE_EXTENSION
:
84 printk(BIOS_EMERG
, "SBI_BASE_EXTENSION\n");
87 printk(BIOS_EMERG
, "%lx is an unknown SBI trap\n", trap
);
93 * These are the default SBI extension values.
94 * They can be overridden, by specialized code,
95 * but since this is a GPL SBI, it may be better
96 * that they evolve as we extend this SBI.
97 * over time, the will be updated.
99 int sbi_features
[] = {1, 0, 0, 0, 0, 0, 0};
102 * sbi is triggered by the s-mode ecall
103 * parameter : register a0 a1 a2
104 * function : register a7
105 * return : register a0
107 void handle_sbi(struct trapframe
*tf
)
110 uintptr_t sbiret
= 0;
111 uintptr_t arg0
= tf
->gpr
[10];
112 __maybe_unused
uintptr_t arg1
= tf
->gpr
[11];
113 uintptr_t fid
= tf
->gpr
[16];
114 uintptr_t eid
= tf
->gpr
[17];
115 uintptr_t retpc
= read_csr(mepc
) + 4;
119 #if __riscv_xlen == 32
120 ret
= sbi_set_timer(arg0
+ ((uint64_t)arg1
<< 32));
122 ret
= sbi_set_timer(arg0
);
125 #if CONFIG(CONSOLE_SERIAL)
126 case SBI_CONSOLE_PUTCHAR
:
127 ret
= sbi_console_putchar(arg0
);
129 case SBI_CONSOLE_GETCHAR
:
130 ret
= sbi_console_getchar();
134 ret
= sbi_clear_ipi();
137 ret
= send_ipi((uintptr_t *)arg0
, IPI_SOFT
);
139 case SBI_REMOTE_FENCE_I
:
140 ret
= send_ipi((uintptr_t *)arg0
, IPI_FENCE_I
);
142 case SBI_REMOTE_SFENCE_VMA
:
143 ret
= send_ipi((uintptr_t *)arg0
, IPI_SFENCE_VMA
);
145 case SBI_REMOTE_SFENCE_VMA_ASID
:
146 ret
= send_ipi((uintptr_t *)arg0
, IPI_SFENCE_VMA_ASID
);
149 ret
= send_ipi((uintptr_t *)arg0
, IPI_SHUTDOWN
);
151 case SBI_BASE_EXTENSION
:
152 /* zero is an allowed return value for most features,
153 * and the only required one is feature 0.
154 * So this test will return legal values
155 * for all possible values of fid.
157 if (fid
< ARRAY_SIZE(sbi_features
))
158 ret
= sbi_features
[fid
];
162 printk(BIOS_EMERG
, "SBI: %lx: ENOSYS\n", fid
);
163 sbiret
= -SBI_ENOSYS
;
166 tf
->gpr
[10] = sbiret
;
169 write_csr(mepc
, retpc
);