Skip to content

Commit 2fa2bb8

Browse files
committed
executor, sys/linux, pkg: enable syz_kvm_setup_cpu for riscv64
1 parent bc54aa9 commit 2fa2bb8

File tree

7 files changed

+211
-1
lines changed

7 files changed

+211
-1
lines changed

executor/common_kvm_riscv64.h

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
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

executor/common_linux.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3216,6 +3216,8 @@ static long syz_mount_image(
32163216
#include "common_kvm_arm64.h"
32173217
#elif GOARCH_ppc64 || GOARCH_ppc64le
32183218
#include "common_kvm_ppc64.h"
3219+
#elif GOARCH_riscv64
3220+
#include "common_kvm_riscv64.h"
32193221
#elif SYZ_EXECUTOR || __NR_syz_kvm_setup_cpu
32203222
static 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)
32213223
{

pkg/compiler/types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ var typeText = &typeDesc{
641641

642642
var typeArgTextType = &typeArg{
643643
Kind: kindIdent,
644-
Names: []string{"target", "x86_real", "x86_16", "x86_32", "x86_64", "arm64", "ppc64"},
644+
Names: []string{"target", "x86_real", "x86_16", "x86_32", "x86_64", "arm64", "ppc64", "riscv64"},
645645
}
646646

647647
func genTextType(t *ast.Type) prog.TextKind {
@@ -660,6 +660,8 @@ func genTextType(t *ast.Type) prog.TextKind {
660660
return prog.TextArm64
661661
case "ppc64":
662662
return prog.TextPpc64
663+
case "riscv64":
664+
return prog.TextTarget
663665
default:
664666
panic(fmt.Sprintf("unknown text type %q", t.Ident))
665667
}

pkg/vminfo/linux_syscalls.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@ func linuxSyzKvmSupported(ctx *checkContext, call *prog.Syscall) string {
196196
if ctx.target.Arch == targets.PPC64LE {
197197
return ""
198198
}
199+
case "syz_kvm_setup_cpu$riscv64":
200+
if ctx.target.Arch == targets.RiscV64 {
201+
return ""
202+
}
199203
}
200204
return unsupportedArch
201205
}

sys/linux/dev_kvm.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,17 @@ kvm_one_reg [
350350
arm64_sve kvm_one_reg_arm64_range[0x6080000000150000:0x6080000000150620]
351351
arm64_sve_vls kvm_one_reg_arm64_range[0x606000000015ffff]
352352
other kvm_one_reg_other
353+
# For riscv64
354+
riscv64_config kvm_one_reg_riscv64[kvm_regs_riscv64_config]
355+
riscv64_core kvm_one_reg_riscv64[kvm_regs_riscv64_core]
356+
riscv64_csr kvm_one_reg_riscv64[kvm_regs_riscv64_csr]
353357
]
354358

359+
type kvm_one_reg_riscv64[FTYPE] {
360+
id flags[FTYPE, int64]
361+
addr ptr64[inout, int64]
362+
}
363+
355364
type kvm_one_reg_arm64[FTYPE] {
356365
id flags[FTYPE, int64]
357366
addr ptr64[inout, int64]
@@ -623,3 +632,8 @@ kvm_regs_arm64_sys = 0x6030000000138002, 0x6030000000138010, 0x6030000000138012,
623632
# Extra registers that KVM_GET_REG_LIST prints on QEMU
624633
kvm_regs_arm64_extra = 0x603000000013c01b, 0x603000000013c01f, 0x603000000013c022, 0x603000000013c023, 0x603000000013c025, 0x603000000013c026, 0x603000000013c027, 0x603000000013c02a, 0x603000000013c02b, 0x603000000013c02e, 0x603000000013c02f, 0x603000000013c033, 0x603000000013c034, 0x603000000013c035, 0x603000000013c036, 0x603000000013c037, 0x603000000013c03b, 0x603000000013c03c, 0x603000000013c03d, 0x603000000013c03e, 0x603000000013c03f, 0x603000000013c103, 0x603000000013c512, 0x603000000013c513
625634
# End of register descriptions generated by tools/arm64/registers.go
635+
636+
# for riscv64, https://elixir.bootlin.com/linux/v6.19-rc4/source/Documentation/virt/kvm/api.rst#L2765
637+
kvm_regs_riscv64_config = 0x8030000000100000
638+
kvm_regs_riscv64_core = 0x8030000000200000, 0x8030000000200001, 0x8030000000200002, 0x8030000000200003, 0x8030000000200004, 0x8030000000200005, 0x8030000000200006, 0x8030000000200007, 0x8030000000200008, 0x8030000000200009, 0x803000000020000a, 0x803000000020000b, 0x803000000020000c, 0x803000000020000d, 0x803000000020000e, 0x803000000020000f, 0x8030000000200010, 0x8030000000200011, 0x8030000000200012, 0x8030000000200013, 0x8030000000200014, 0x8030000000200015, 0x8030000000200016, 0x8030000000200017, 0x8030000000200018, 0x8030000000200019, 0x803000000020001a, 0x803000000020001b, 0x803000000020001c, 0x803000000020001d, 0x803000000020001e, 0x803000000020001f, 0x8030000000200020
639+
kvm_regs_riscv64_csr = 0x8030000000300000, 0x8030000000300001, 0x8030000000300002, 0x8030000000300003, 0x8030000000300004, 0x8030000000300005, 0x8030000000300006, 0x8030000000300007, 0x8030000000300008

sys/linux/dev_kvm_riscv64.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,11 @@ ioctl$KVM_SET_GUEST_DEBUG_riscv64(fd fd_kvmcpu, cmd const[KVM_SET_GUEST_DEBUG],
1212
kvm_guest_debug_arch_riscv64 {
1313
reg array[int64, 8]
1414
}
15+
16+
syz_kvm_setup_cpu$riscv64(fd fd_kvmvm, cpufd fd_kvmcpu, usermem vma[24], text ptr[in, array[kvm_text_riscv64, 1]])
17+
18+
kvm_text_riscv64 {
19+
type const[0, intptr]
20+
text ptr[in, text[riscv64]]
21+
size len[text, intptr]
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#
2+
# requires: arch=riscv64
3+
#
4+
5+
r0 = openat$kvm(0xffffffffffffff9c, &(0x7f0000000000), 0x0, 0x0)
6+
r1 = ioctl$KVM_CREATE_VM(r0, AUTO, 0x0)
7+
r2 = ioctl$KVM_CREATE_VCPU(r1, AUTO, 0x0)
8+
9+
# Set the register
10+
# 0x04200513, li a0, 0x42 (addi a0, zero, 0x42)
11+
# 0x06300593, li a1, 0x63 (addi a1, zero, 0x63)
12+
# Load the MMIO address to t1 (without affecting a0, a1)
13+
# 0x40000337, lui t1, 0x40000 (load 20 bits high to t1)
14+
# Read from the MMIO address (this triggers KVM_EXIT_MMIO)
15+
# 0x00032683, lw a3, 0(t1) (read from address 0x40000000 to a3)
16+
syz_kvm_setup_cpu$riscv64(r1, r2, &(0x7f0000fe8000/0x180000)=nil,&(0x7f0000000000)=[{0x0, &(0x7f0000001000)="13052004930530063703004083260300", 0xf}])
17+
18+
ioctl$KVM_RUN(r2, AUTO, 0x0)
19+
20+
ioctl$KVM_GET_ONE_REG(r2, AUTO, &AUTO=@riscv64_core={0x803000000200000a, &AUTO})
21+
ioctl$KVM_GET_ONE_REG(r2, AUTO, &AUTO=@riscv64_config={0x8030000001000000, &AUTO})
22+
ioctl$KVM_GET_ONE_REG(r2, AUTO, &AUTO=@riscv64_csr={0x8030000003000000, &AUTO})

0 commit comments

Comments
 (0)