On 9/24/2026 6:20 AM, Jim Mattson wrote:
I hadn't anticipated the need for this special-case, and it's more
intrusive than just returning the number of bytes read.

I see now that it's complicated to match the behavior of the
emulator's __do_insn_fetch_bytes(). You could clamp the number of
bytes to read up-front to deal with the end of the address space, but
you would still need a second call to handle the wrap.  Something like
the following (mangled by my MUA):

static unsigned int __kvm_fetch_guest_virt(struct kvm_vcpu *vcpu, gva_t addr,
   void *val, unsigned int bytes)
{
struct x86_exception exception = {};
unsigned int bytes_read;
u64 access = PFERR_FETCH_MASK;

if (kvm_x86_call(get_cpl)(vcpu) == 3)
access |= PFERR_USER_MASK;

kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access,
   &exception, &bytes_read);
return bytes_read;
}

unsigned int kvm_fetch_guest_virt(struct kvm_vcpu *vcpu, gva_t addr,
  void *val, unsigned int bytes)
{
unsigned int first, bytes_read;
bool wraps;
u64 avail;

/* An instruction-sized fetch can wrap at most once. */
if (WARN_ON_ONCE(bytes > X86_MAX_INSTRUCTION_LENGTH))
return 0;

if (!is_64_bit_mode(vcpu)) {
addr = (u32)addr;
avail = BIT_ULL(32) - addr;
wraps = true;
} else if (is_noncanonical_address(addr, vcpu, 0)) {
return 0;
} else if (addr < BIT_ULL(63)) {
avail = BIT_ULL(vcpu_virt_addr_bits(vcpu) - 1) - addr;
wraps = false;
} else {
avail = -addr;
wraps = true;
}

first = min_t(u64, bytes, avail);
bytes_read = __kvm_fetch_guest_virt(vcpu, addr, val, first);

if (wraps && bytes_read == first && first < bytes)
bytes_read += __kvm_fetch_guest_virt(vcpu, 0, val + first,
     bytes - first);

return bytes_read;
}

I think this solution may be worse than what you have now, but I will
defer to Sean. Maybe he will have a better idea. (Maybe my suggestion
to return the number of bytes read was misguided.)

Reviewed-by: Jim Mattson<[email protected]>

Thanks, Jim, for the suggestion and review.

Hi Sean, what do you think?

Thanks,
Tina

Reply via email to