1+ // Copyright 2026 syzkaller project authors. All rights reserved.
2+ // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
3+
4+ #ifndef EXECUTOR_COMMON_KVM_RISCV64_H
5+ #define EXECUTOR_COMMON_KVM_RISCV64_H
6+
7+ // This file is shared between executor and csource package.
8+
9+ // Implementation of syz_kvm_setup_cpu pseudo-syscall.
10+
11+ #include <stdint.h>
12+ #include <string.h>
13+ #include <sys/ioctl.h>
14+
15+ struct kvm_text {
16+ uintptr_t type ;
17+ const void * text ;
18+ uintptr_t size ;
19+ };
20+
21+ // RISC-V register ID construction macros
22+ #define RISCV_CORE_REG (idx ) (KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_CORE | (idx))
23+ #define RISCV_CSR_REG (idx ) (KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_CSR | (idx))
24+
25+ // CSR register indices in kvm_riscv_csr struct
26+ #define CSR_SSTATUS 0
27+ #define CSR_SIE 1
28+ #define CSR_STVEC 2
29+ #define CSR_SSCRATCH 3
30+ #define CSR_SEPC 4
31+ #define CSR_SCAUSE 5
32+ #define CSR_STVAL 6
33+ #define CSR_SIP 7
34+ #define CSR_SATP 8
35+
36+ // CORE register indices
37+ #define CORE_PC 0x00
38+ #define CORE_RA 0x01
39+ #define CORE_SP 0x02
40+ #define CORE_GP 0x03
41+ #define CORE_TP 0x04
42+ #define CORE_T0 0x05
43+ #define CORE_T1 0x06
44+ #define CORE_T2 0x07
45+ #define CORE_S0 0x08
46+ #define CORE_S1 0x09
47+ #define CORE_A0 0x0a
48+ #define CORE_A1 0x0b
49+ #define CORE_A2 0x0c
50+ #define CORE_A3 0x0d
51+ #define CORE_A4 0x0e
52+ #define CORE_A5 0x0f
53+ #define CORE_A6 0x10
54+ #define CORE_A7 0x11
55+ #define CORE_S2 0x12
56+ #define CORE_S3 0x13
57+ #define CORE_S4 0x14
58+ #define CORE_S5 0x15
59+ #define CORE_S6 0x16
60+ #define CORE_S7 0x17
61+ #define CORE_S8 0x18
62+ #define CORE_S9 0x19
63+ #define CORE_S10 0x1a
64+ #define CORE_S11 0x1b
65+ #define CORE_T3 0x1c
66+ #define CORE_T4 0x1d
67+ #define CORE_T5 0x1e
68+ #define CORE_T6 0x1f
69+ #define CORE_MODE 0x20 // Privilege mode: 1=S-mode, 0=U-mode
70+
71+ // SSTATUS register bit definitions
72+ #define SSTATUS_SPP (1UL << 8) // Previous privilege (0=User, 1=Supervisor)
73+ #define SSTATUS_SPIE (1UL << 5) // Previous interrupt enable
74+ #define SSTATUS_SIE (1UL << 1) // Supervisor interrupt enable
75+
76+ // Helper function to set a register
77+ static inline int kvm_set_reg (int cpufd , uint64_t id , uint64_t value )
78+ {
79+ struct kvm_one_reg reg = {
80+ .id = id ,
81+ .addr = (uint64_t )& value ,
82+ };
83+ return ioctl (cpufd , KVM_SET_ONE_REG , & reg );
84+ }
85+
86+ #define CODE_START 0x80000000ULL
87+
88+ // syz_kvm_setup_cpu$riscv64(fd fd_kvmvm, cpufd fd_kvmcpu, usermem vma[24], text ptr[in, array[kvm_text_riscv64, 1]])
89+ static volatile long syz_kvm_setup_cpu (volatile long a0 , volatile long a1 ,
90+ volatile long a2 , volatile long a3 )
91+ {
92+ const int vmfd = a0 ;
93+ const int cpufd = a1 ;
94+ char * const host_mem = (char * )a2 ;
95+ const struct kvm_text * const text_array_ptr = (struct kvm_text * )a3 ;
96+
97+ const uintptr_t page_size = SYZ_PAGE_SIZE ;
98+ const uintptr_t guest_pages = 24 ;
99+ const uintptr_t guest_mem_size = guest_pages * page_size ;
100+
101+ ioctl (vmfd , KVM_GET_API_VERSION , NULL );
102+
103+ // ---- 1. Install guest memory ----
104+ for (uintptr_t i = 0 ; i < guest_pages ; i ++ ) {
105+ struct kvm_userspace_memory_region mem = {
106+ .slot = (uint32_t )i ,
107+ .flags = 0 ,
108+ .guest_phys_addr = CODE_START + i * page_size ,
109+ .memory_size = page_size ,
110+ .userspace_addr =
111+ (uintptr_t )(host_mem + i * page_size ),
112+ };
113+
114+ if (ioctl (vmfd , KVM_SET_USER_MEMORY_REGION , & mem ))
115+ return -1 ;
116+ }
117+
118+ // ---- 2. Copy guest text ----
119+ const void * text = 0 ;
120+ uintptr_t size = 0 ;
121+
122+ NONFAILING (text = text_array_ptr [0 ].text );
123+ NONFAILING (size = text_array_ptr [0 ].size );
124+
125+ if (size > guest_mem_size )
126+ size = guest_mem_size ;
127+
128+ memcpy (host_mem , text , size );
129+
130+ // ---- 3. Initialize VCPU registers ----
131+
132+ // Set PC (program counter) to start of code
133+ if (kvm_set_reg (cpufd , RISCV_CORE_REG (CORE_PC ), CODE_START ))
134+ return -1 ;
135+
136+ // Set SP (stack pointer) at end of memory, reserving space for stack
137+ uint64_t stack_top = CODE_START + guest_mem_size - page_size ;
138+ if (kvm_set_reg (cpufd , RISCV_CORE_REG (CORE_SP ), stack_top ))
139+ return -1 ;
140+
141+ // Set privilege mode to S-mode (Supervisor mode)
142+ if (kvm_set_reg (cpufd , RISCV_CORE_REG (CORE_MODE ), 1 ))
143+ return -1 ;
144+
145+ // Set SSTATUS CSR with SPP (previous privilege) and SPIE (previous interrupt enable)
146+ uint64_t sstatus = SSTATUS_SPP | SSTATUS_SPIE ;
147+ if (kvm_set_reg (cpufd , RISCV_CSR_REG (CSR_SSTATUS ), sstatus ))
148+ return -1 ;
149+
150+ // Set STVEC (exception vector address)
151+ uint64_t stvec = CODE_START + page_size ;
152+ if (kvm_set_reg (cpufd , RISCV_CSR_REG (CSR_STVEC ), stvec ))
153+ return -1 ;
154+
155+ return 0 ;
156+ }
157+
158+ #endif // EXECUTOR_COMMON_KVM_RISCV64_H
0 commit comments