88
99// Implementation of syz_kvm_setup_cpu pseudo-syscall.
1010
11- #include "common_kvm.h"
12- #include "kvm.h"
1311#include <stdint.h>
1412#include <string.h>
1513#include <sys/ioctl.h>
1614
15+ #include "common_kvm.h"
16+ #include "kvm.h"
17+
1718#if SYZ_EXECUTOR || __NR_syz_kvm_setup_syzos_vm || __NR_syz_kvm_add_vcpu
1819#include "common_kvm_riscv64_syzos.h"
1920#endif
@@ -101,6 +102,10 @@ struct kvm_text {
101102#endif
102103
103104#if SYZ_EXECUTOR || __NR_syz_kvm_setup_cpu || __NR_syz_kvm_setup_syzos_vm || __NR_syz_kvm_add_vcpu
105+ // The exception vector table setup and SBI invocation here follow the
106+ // implementation in Linux kselftest KVM RISC-V tests.
107+ // See https://elixir.bootlin.com/linux/v6.19-rc5/source/tools/testing/selftests/kvm/lib/riscv/processor.c#L337 .
108+
104109#define KVM_RISCV_SELFTESTS_SBI_EXT 0x08FFFFFF
105110#define KVM_RISCV_SELFTESTS_SBI_UNEXP 1
106111
@@ -116,14 +121,14 @@ struct sbiret sbi_ecall(unsigned long arg0, unsigned long arg1,
116121{
117122 struct sbiret ret ;
118123
119- register uintptr_t a0 asm("a0" ) = ( uintptr_t )( arg0 ) ;
120- register uintptr_t a1 asm("a1" ) = ( uintptr_t )( arg1 ) ;
121- register uintptr_t a2 asm("a2" ) = ( uintptr_t )( arg2 ) ;
122- register uintptr_t a3 asm("a3" ) = ( uintptr_t )( arg3 ) ;
123- register uintptr_t a4 asm("a4" ) = ( uintptr_t )( arg4 ) ;
124- register uintptr_t a5 asm("a5" ) = ( uintptr_t )( arg5 ) ;
125- register uintptr_t a6 asm("a6" ) = ( uintptr_t )( fid ) ;
126- register uintptr_t a7 asm("a7" ) = ( uintptr_t )( ext ) ;
124+ register unsigned long a0 asm("a0" ) = arg0 ;
125+ register unsigned long a1 asm("a1" ) = arg1 ;
126+ register unsigned long a2 asm("a2" ) = arg2 ;
127+ register unsigned long a3 asm("a3" ) = arg3 ;
128+ register unsigned long a4 asm("a4" ) = arg4 ;
129+ register unsigned long a5 asm("a5" ) = arg5 ;
130+ register unsigned long a6 asm("a6" ) = fid ;
131+ register unsigned long a7 asm("a7" ) = ext ;
127132 asm volatile ("ecall"
128133 : "+r" (a0 ), "+r" (a1 )
129134 : "r" (a2 ), "r" (a3 ), "r" (a4 ), "r" (a5 ), "r" (a6 ), "r" (a7 )
@@ -143,8 +148,6 @@ __attribute__((used)) __attribute((__aligned__(16))) static void guest_unexp_tra
143148#endif
144149
145150#if SYZ_EXECUTOR || __NR_syz_kvm_setup_cpu
146- // Define the starting physical address for the guest code.
147- #define CODE_START 0x80000000ULL
148151
149152// syz_kvm_setup_cpu$riscv64(fd fd_kvmvm, cpufd fd_kvmcpu, usermem vma[24], text ptr[in, array[kvm_text_riscv64, 1]], ntext len[text], flags const[0], opts ptr[in, array[kvm_setup_opt_riscv64, 1]], nopt len[opts])
150153static volatile long syz_kvm_setup_cpu (volatile long a0 , volatile long a1 , volatile long a2 , volatile long a3 , volatile long a4 , volatile long a5 , volatile long a6 , volatile long a7 )
@@ -163,7 +166,7 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat
163166 struct kvm_userspace_memory_region mem = {
164167 .slot = (unsigned int )i ,
165168 .flags = 0 ,
166- .guest_phys_addr = CODE_START + i * page_size ,
169+ .guest_phys_addr = RISCV64_ADDR_USER_CODE + i * page_size ,
167170 .memory_size = page_size ,
168171 .userspace_addr =
169172 (uintptr_t )(host_mem + i * page_size ),
@@ -185,10 +188,10 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat
185188
186189 // Initialize VCPU registers.
187190 // Set PC (program counter) to start of code.
188- if (kvm_set_reg (cpufd , RISCV_CORE_REG (CORE_PC ), CODE_START ))
191+ if (kvm_set_reg (cpufd , RISCV_CORE_REG (CORE_PC ), RISCV64_ADDR_USER_CODE ))
189192 return -1 ;
190193 // Set SP (stack pointer) at end of memory, reserving space for stack.
191- unsigned long stack_top = CODE_START + guest_mem_size - page_size ;
194+ unsigned long stack_top = RISCV64_ADDR_USER_CODE + guest_mem_size - page_size ;
192195 if (kvm_set_reg (cpufd , RISCV_CORE_REG (CORE_SP ), stack_top ))
193196 return -1 ;
194197 // Set privilege mode to S-mode.
@@ -199,7 +202,7 @@ static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volat
199202 if (kvm_set_reg (cpufd , RISCV_CSR_REG (CSR_SSTATUS ), sstatus ))
200203 return -1 ;
201204 // Set STVEC.
202- unsigned long stvec = CODE_START + page_size ;
205+ unsigned long stvec = RISCV64_ADDR_USER_CODE + page_size ;
203206 if (kvm_set_reg (cpufd , RISCV_CSR_REG (CSR_STVEC ), stvec ))
204207 return -1 ;
205208 // Set GP.
@@ -276,8 +279,8 @@ static void vm_set_user_memory_region(int vmfd, uint32 slot, uint32 flags, uint6
276279#define AUIPC_OPCODE 0x17
277280#define AUIPC_OPCODE_MASK 0x7f
278281
279- // Code loading SyzOS into guest memory does not handle data relocations (see
280- // https://github.com/google/syzkaller/issues/5565), so SyzOS will crash soon after encountering an
282+ // Code loading SYZOS into guest memory does not handle data relocations (see
283+ // https://github.com/google/syzkaller/issues/5565), so SYZOS will crash soon after encountering an
281284// AUIPC instruction. Detect these instructions to catch regressions early.
282285// The most common reason for using data relocaions is accessing global variables and constants.
283286// Sometimes the compiler may choose to emit a read-only constant to zero-initialize a structure
@@ -287,15 +290,15 @@ static void validate_guest_code(void* mem, size_t size)
287290 uint32 * insns = (uint32 * )mem ;
288291 for (size_t i = 0 ; i < size / 4 ; i ++ ) {
289292 if ((insns [i ] & AUIPC_OPCODE_MASK ) == AUIPC_OPCODE )
290- fail ("AUIPC instruction detected in SyzOS , exiting" );
293+ fail ("AUIPC instruction detected in SYZOS , exiting" );
291294 }
292295}
293296
294297static void install_syzos_code (void * host_mem , size_t mem_size )
295298{
296299 size_t size = (char * )& __stop_guest - (char * )& __start_guest ;
297300 if (size > mem_size )
298- fail ("SyzOS size exceeds guest memory" );
301+ fail ("SYZOS size exceeds guest memory" );
299302 memcpy (host_mem , & __start_guest , size );
300303 validate_guest_code (host_mem , size );
301304}
0 commit comments