diff options
| author | 6eanut <jiakaiPeanut@gmail.com> | 2026-01-08 10:04:33 +0800 |
|---|---|---|
| committer | Alexander Potapenko <glider@google.com> | 2026-01-20 09:02:10 +0000 |
| commit | 06648d9ccf5ec6f9453ef09b0fdbdebf020ee0f8 (patch) | |
| tree | 870fdbadb35555247853ecb3ae94a400b36d077c /executor/common_kvm_riscv64.h | |
| parent | 300ecf9e8fcda4e7a0cef8249ca1d6d1394ca4f1 (diff) | |
executor, sys/linux, pkg: enable syz_kvm_setup_cpu for riscv64
This patch implements syz_kvm_setup_cpu for riscv64 architecture.
The pseudo-syscall accepts VM fd, vCPU fd, host memory, and guest code
as parameters. Additional parameters (ntext, flags, opts, nopt) are
included for interface consistency with other architectures but are
currently unused on riscv64.
Implementation:
- Set up guest memory via KVM_SET_USER_MEMORY_REGION
- Copy guest code to guest memory
- Initialize guest registers to enable code execution in S-mode
- Return 0 on success, -1 on failure
Testing:
A test file syz_kvm_setup_cpu_riscv64 is included in sys/linux/test/
to verify basic functionality.
Known limitations:
- ifuzz is not yet compatible with riscv64. Temporary workaround: set
text[riscv64] to TextTarget and return nil in createTargetIfuzzConfig
for riscv64 to ensure generateText and mutateText work correctly.
This patch also adds support for KVM_GET_ONE_REG ioctl.
Diffstat (limited to 'executor/common_kvm_riscv64.h')
| -rw-r--r-- | executor/common_kvm_riscv64.h | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/executor/common_kvm_riscv64.h b/executor/common_kvm_riscv64.h new file mode 100644 index 000000000..dcccd6dad --- /dev/null +++ b/executor/common_kvm_riscv64.h @@ -0,0 +1,157 @@ +// Copyright 2026 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +#ifndef EXECUTOR_COMMON_KVM_RISCV64_H +#define EXECUTOR_COMMON_KVM_RISCV64_H + +// This file is shared between executor and csource package. + +// Implementation of syz_kvm_setup_cpu pseudo-syscall. + +#include <stdint.h> +#include <string.h> +#include <sys/ioctl.h> + +struct kvm_text { + uintptr_t type; + const void* text; + uintptr_t size; +}; + +// Construct RISC-V register id for KVM. +#define RISCV_CORE_REG(idx) (KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_CORE | (idx)) +#define RISCV_CSR_REG(idx) (KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_CSR | (idx)) + +// Represent CSR indices in the kvm_riscv_csr structure. +enum riscv_csr_index { + CSR_SSTATUS = 0, + CSR_SIE, + CSR_STVEC, + CSR_SSCRATCH, + CSR_SEPC, + CSR_SCAUSE, + CSR_STVAL, + CSR_SIP, + CSR_SATP, + CSR_SCOUNTEREN, + CSR_SENVCFG +}; + +// Represent CORE register indices in the kvm_riscv_core structure. +enum riscv_core_index { + CORE_PC = 0x00, + CORE_RA, + CORE_SP, + CORE_GP, + CORE_TP, + CORE_T0, + CORE_T1, + CORE_T2, + CORE_S0, + CORE_S1, + CORE_A0, + CORE_A1, + CORE_A2, + CORE_A3, + CORE_A4, + CORE_A5, + CORE_A6, + CORE_A7, + CORE_S2, + CORE_S3, + CORE_S4, + CORE_S5, + CORE_S6, + CORE_S7, + CORE_S8, + CORE_S9, + CORE_S10, + CORE_S11, + CORE_T3, + CORE_T4, + CORE_T5, + CORE_T6, + // Store the privilege mode: 1=S-mode, 0=U-mode. + CORE_MODE +}; + +// Indicate the Supervisor Previous Privilege mode. +#define SSTATUS_SPP (1UL << 8) +// Indicate the Supervisor Previous Interrupt Enable state. +#define SSTATUS_SPIE (1UL << 5) +// Indicate the Supervisor Interrupt Enable state. +#define SSTATUS_SIE (1UL << 1) + +// Define the starting physical address for the guest code. +#define CODE_START 0x80000000ULL + +// Set a single register value for the specified CPU file descriptor. +static inline int kvm_set_reg(int cpufd, unsigned long id, unsigned long value) +{ + struct kvm_one_reg reg = { + .id = id, + .addr = (unsigned long)&value, + }; + return ioctl(cpufd, KVM_SET_ONE_REG, ®); +} + +// 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]) +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) +{ + const int vmfd = a0; + const int cpufd = a1; + char* const host_mem = (char*)a2; + const struct kvm_text* const text_array_ptr = (struct kvm_text*)a3; + + const uintptr_t page_size = 4096; + const uintptr_t guest_pages = 24; + const uintptr_t guest_mem_size = guest_pages * page_size; + + // Install guest memory. + for (uintptr_t i = 0; i < guest_pages; i++) { + struct kvm_userspace_memory_region mem = { + .slot = (unsigned int)i, + .flags = 0, + .guest_phys_addr = CODE_START + i * page_size, + .memory_size = page_size, + .userspace_addr = + (uintptr_t)(host_mem + i * page_size), + }; + + if (ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &mem)) + return -1; + } + + // Copy guest code. + const void* text = 0; + uintptr_t size = 0; + NONFAILING(text = text_array_ptr[0].text); + NONFAILING(size = text_array_ptr[0].size); + if (size > guest_mem_size) + size = guest_mem_size; + memcpy(host_mem, text, size); + + // Initialize VCPU registers. + // Set PC (program counter) to start of code. + if (kvm_set_reg(cpufd, RISCV_CORE_REG(CORE_PC), CODE_START)) + return -1; + // Set SP (stack pointer) at end of memory, reserving space for stack. + unsigned long stack_top = CODE_START + guest_mem_size - page_size; + if (kvm_set_reg(cpufd, RISCV_CORE_REG(CORE_SP), stack_top)) + return -1; + // Set privilege mode to S-mode. + if (kvm_set_reg(cpufd, RISCV_CORE_REG(CORE_MODE), 1)) + return -1; + // Set SSTATUS CSR with SPP and SPIE. + unsigned long sstatus = SSTATUS_SPP | SSTATUS_SPIE; + if (kvm_set_reg(cpufd, RISCV_CSR_REG(CSR_SSTATUS), sstatus)) + return -1; + // Set STVEC. + unsigned long stvec = CODE_START + page_size; + if (kvm_set_reg(cpufd, RISCV_CSR_REG(CSR_STVEC), stvec)) + return -1; + + return 0; +} + +#endif // EXECUTOR_COMMON_KVM_RISCV64_H
\ No newline at end of file |
