blob: e5408288af21af121c9953bc0b65fd25a05ed043 [file] [log] [blame]
Xiang Wang22e0c562018-08-15 16:27:05 +08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2018 HardenedLinux
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <mcall.h>
17#include <stdint.h>
18#include <commonlib/compiler.h>
19#include <arch/exception.h>
20#include <sbi.h>
21#include <vm.h>
22#include <console/uart.h>
23#include <console/console.h>
24#include <commonlib/helpers.h>
25
26static uintptr_t send_ipi(uintptr_t *pmask, intptr_t type)
27{
28 uintptr_t mask = mprv_read_uintptr_t(pmask);
29 for (int i = 0; mask; i++) {
30 if (mask & 1) {
31 OTHER_HLS(i)->ipi_pending |= type;
32 /* send soft interrupt to target hart */
33 set_msip(i, 1);
34 }
35 mask = mask >> 1;
36 }
37 return 0;
38}
39
40static uintptr_t sbi_set_timer(uint64_t when)
41{
42 clear_csr(mip, MIP_STIP);
43 set_csr(mie, MIP_MTIP);
44 *(HLS()->timecmp) = when;
45 return 0;
46}
47
48#if IS_ENABLED(CONFIG_CONSOLE_SERIAL)
49static uintptr_t sbi_console_putchar(uint8_t ch)
50{
51 uart_tx_byte(CONFIG_UART_FOR_CONSOLE, ch);
52 return 0;
53}
54
55static uintptr_t sbi_console_getchar(void)
56{
57 return uart_rx_byte(CONFIG_UART_FOR_CONSOLE);
58}
59#endif
60
61static uintptr_t sbi_clear_ipi(void)
62{
63 clear_csr(mip, MIP_SSIP);
64 return 0;
65}
66
67
68/*
69 * sbi is triggered by the s-mode ecall
70 * parameter : register a0 a1 a2
71 * function : register a7
72 * return : register a0
73 */
74void handle_sbi(trapframe *tf)
75{
76 uintptr_t ret = 0;
77 uintptr_t arg0 = tf->gpr[10];
78 __unused uintptr_t arg1 = tf->gpr[11];
79 uintptr_t which = tf->gpr[17];
80
81 switch (which) {
82 case SBI_SET_TIMER:
83#if __riscv_xlen == 32
84 ret = sbi_set_timer(arg0 + ((uint64_t)arg1 << 32));
85#else
86 ret = sbi_set_timer(arg0);
87#endif
88 break;
89#if IS_ENABLED(CONFIG_CONSOLE_SERIAL)
90 case SBI_CONSOLE_PUTCHAR:
91 ret = sbi_console_putchar(arg0);
92 break;
93 case SBI_CONSOLE_GETCHAR:
94 ret = sbi_console_getchar();
95 break;
96#endif
97 case SBI_CLEAR_IPI:
98 ret = sbi_clear_ipi();
99 break;
100 case SBI_SEND_IPI:
101 ret = send_ipi((uintptr_t *)arg0, IPI_SOFT);
102 break;
103 case SBI_REMOTE_FENCE_I:
104 ret = send_ipi((uintptr_t *)arg0, IPI_FENCE_I);
105 break;
106 case SBI_REMOTE_SFENCE_VMA:
107 ret = send_ipi((uintptr_t *)arg0, IPI_SFENCE_VMA);
108 break;
109 case SBI_REMOTE_SFENCE_VMA_ASID:
110 ret = send_ipi((uintptr_t *)arg0, IPI_SFENCE_VMA_ASID);
111 break;
112 case SBI_SHUTDOWN:
113 ret = send_ipi((uintptr_t *)arg0, IPI_SHUTDOWN);
114 break;
115 default:
Jonathan Neuschäferecf25fd2018-12-11 17:53:17 +0100116 ret = -SBI_ENOSYS;
Xiang Wang22e0c562018-08-15 16:27:05 +0800117 break;
118 }
119 tf->gpr[10] = ret;
120 write_csr(mepc, read_csr(mepc) + 4);
121}