从这一章节,我们开始对qemu disk IO部分源码进行简单的分析和总结
我们所阅读的qemu源码版本为2.3.0不同的版本源码会有所不同
先附上一些参考链接:
- Qemu Document
- [KVM学习笔记]qemu-kvm io线程
- KVM虚拟机IO处理过程(一) ----Guest VM I/O 处理过程
- KVM虚拟机IO处理过程(二) ----QEMU/KVM I/O 处理过程
- Kvm代码解析连载(二):io的虚拟化(代码版本:kvm-kmod-3.10.1)
- qemu-kvm0.12.1.2原生态读写
重点阅读kvm_handle_io
这个接口的定义位于kvm-all.c文件中1663~1674:
static void kvm_handle_io(uint16_t port, void *data, int direction, int size,
uint32_t count)
{
int i;
uint8_t *ptr = data;
for (i = 0; i < count; i++) {
address_space_rw(&address_space_io, port, ptr, size,
direction == KVM_EXIT_IO_OUT);
ptr += size;
}
}
继续往下深入到address_space_rw
该接口位于exec.c 的2307~2397
bool address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf,
int len, bool is_write)
{
hwaddr l;
uint8_t *ptr;
uint64_t val;
hwaddr addr1;
MemoryRegion *mr;
bool error = false;
while (len > 0) {
l = len;
mr = address_space_translate(as, addr, &addr1, &l, is_write);
if (is_write) {
if (!memory_access_is_direct(mr, is_write)) {
l = memory_access_size(mr, l, addr1);
/* XXX: could force current_cpu to NULL to avoid
potential bugs */
switch (l) {
case 8:
/* 64 bit write access */
val = ldq_p(buf);
error |= io_mem_write(mr, addr1, val, 8);
break;
case 4:
/* 32 bit write access */
val = ldl_p(buf);
error |= io_mem_write(mr, addr1, val, 4);
break;
case 2:
/* 16 bit write access */
val = lduw_p(buf);
error |= io_mem_write(mr, addr1, val, 2);
break;
case 1:
/* 8 bit write access */
val = ldub_p(buf);
error |= io_mem_write(mr, addr1, val, 1);
break;
default:
abort();
}
} else {
addr1 += memory_region_get_ram_addr(mr);
/* RAM case */
ptr = qemu_get_ram_ptr(addr1);
memcpy(ptr, buf, l);
invalidate_and_set_dirty(addr1, l);
}
} else {
if (!memory_access_is_direct(mr, is_write)) {
/* I/O case */
l = memory_access_size(mr, l, addr1);
switch (l) {
case 8:
/* 64 bit read access */
error |= io_mem_read(mr, addr1, &val, 8);
stq_p(buf, val);
break;
case 4:
/* 32 bit read access */
error |= io_mem_read(mr, addr1, &val, 4);
stl_p(buf, val);
break;
case 2:
/* 16 bit read access */
error |= io_mem_read(mr, addr1, &val, 2);
stw_p(buf, val);
break;
case 1:
/* 8 bit read access */
error |= io_mem_read(mr, addr1, &val, 1);
stb_p(buf, val);
break;
default:
abort();
}
} else {
/* RAM case */
ptr = qemu_get_ram_ptr(mr->ram_addr + addr1);
memcpy(buf, ptr, l);
}
}
len -= l;
buf += l;
addr += l;
}
return error;
}