[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu
From: |
Jan Kiszka |
Subject: |
Re: [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu |
Date: |
Fri, 07 Sep 2012 10:50:51 +0200 |
User-agent: |
Mozilla/5.0 (X11; U; Linux i686 (x86_64); de; rv:1.8.1.12) Gecko/20080226 SUSE/2.0.0.12-1.1 Thunderbird/2.0.0.12 Mnenhy/0.7.5.666 |
On 2012-09-07 10:26, Liu Sheng wrote:
> as readonly memory is support in kvm, this patch supports this feature
> in qemu, mainly pluging the memory region with KVM_MEM_READONLY flag
> to kvm.
>
> this can be tested by a kernel module from the author of kvm readonly
> memory slot:
>
> static int rom_tester_probe(struct pci_dev *dev, const struct pci_device_id
> *id)
> {
> struct resource *res = &dev->resource[PCI_ROM_RESOURCE];
> char buf[6];
> size_t rom_size;
> char * __iomem map;
> int i;
>
> if (res->flags & (IORESOURCE_ROM_SHADOW | IORESOURCE_ROM_COPY |
> IORESOURCE_ROM_BIOS_COPY)) {
> dev_printk(KERN_INFO, &dev->dev, "skip ROM COPY.\n");
> return 0;
> }
>
> if (res->flags &
> (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY))
> dev_printk(KERN_INFO, &dev->dev, "rom tester\n");
>
> if (pci_enable_rom(dev)) {
> dev_printk(KERN_INFO, &dev->dev, "do not found Rom\n");
> goto exit;
> }
>
> map = pci_map_rom(dev, &rom_size);
> if (!map) {
> dev_printk(KERN_INFO, &dev->dev, "map rom fail.\n");
> goto disable_exit;
> }
>
> dev_printk(KERN_INFO, &dev->dev, "Rom map: %p [size: %lx],
> phsyc:%llx.\n",
> map, rom_size, pci_resource_start(dev, PCI_ROM_RESOURCE));
>
> if (rom_size < 6) {
> printk("map size < 6.\n");
> goto unmap_exit;
> }
>
> printk("The first 6 bytes:\n");
> for (i = 0; i < 6; i++) {
> buf[i] = map[i];
> printk("%x ", buf[i]);
> }
> printk("\n\n");
>
> memcpy(map, "KVMKVM", 6);
> if (!memcmp(map, "KVMKVM", 6)) {
> printk("Rom Test: fail.\n");
> goto unmap_exit;
> }
>
> for (i = 0; i < 6; i++)
> if (buf[i] != ((char *)map)[i]) {
> printk("The %d byte is changed: %x -> %x.\n",
> i, buf[i], map[i]);
> printk("Rom Test: fail.\n");
> goto unmap_exit;
> }
>
> printk("Rom Test: Okay.\n");
>
> unmap_exit:
> pci_unmap_rom(dev, map);
> disable_exit:
> pci_disable_rom(dev);
> exit:
> return 0;
> }
>
> static DEFINE_PCI_DEVICE_TABLE(rom_tester_tbl) = {
> { PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID)},
>
> {0,} /* 0 terminated list. */
> };
> MODULE_DEVICE_TABLE(pci, rom_tester_tbl);
>
> static struct pci_driver rom_tester = {
> .name = "pci-rom-tester",
> .id_table = rom_tester_tbl,
> .probe = rom_tester_probe,
> };
>
> static int __init pci_rom_test_init(void)
> {
> int rc;
>
> rc = pci_register_driver(&rom_tester);
> if (rc)
> return rc;
>
> return 0;
> }
>
> static void __exit pci_rom_test_exit(void)
> {
> pci_unregister_driver(&rom_tester);
> }
>
> module_init(pci_rom_test_init);
> module_exit(pci_rom_test_exit);
>
> MODULE_LICENSE("GPL");
> MODULE_AUTHOR("Xiao Guangrong <address@hidden>");
>
> we test it with the rom of Intel 82540EM Gigabit Ethernet Controller.
> 0. start qemu:
> qemu-system-x86_64 -enable-kvm -m 1G -smp 2 -hda fedora16.qcow2 \
> -nic nic,model=e1000,vlan=1,macadrr=52:00:12:34:56 \
> -net user,vlan=1
> 1. unbind the device:
> echo "0000:00:03.0" > /sys/bus/pci/devices/0000\:00\:03.0/driver/unbind
> 2. install the test kernel module, here we name it write_rom:
> modprobe write_rom
> 3. print dmesg to verify the result is ok or fail:
> dmesg
> 4. remove the test kernel module.
> rmmod write_rom
> 5. rebind the device to its driver, test if the nic still works:
> echo "0000:00:03.0" > /sys/bus/pci/drivers/e1000/bind
> open firefox and try some web page.
>
> when I use kvm without readonly memory slot, in step 2 it reports:
> Rom Test: fail. this means we can write to the memory region of a rom,
> which is quite not safe for the guest and host.
>
> when I use kvm with readonly memory slot, in step 2 it reports:
> Rom Test: Okay.
> and the error message prints out in host console:
> Guest is writing readonly memory, phys_addr: febc0000, len:4, data[0]:K,
> skip it
> Guest is writing readonly memory, phys_addr: febc0000, len:2, data[0]:V,
> skip it
> this is what we write "KVMKVM".
> this means write operation is not successful, and return back to qemu from
> kvm.
> thus we can make the rom real rom.
>
> Signed-off-by: Liu Sheng <address@hidden>
> ---
> kvm-all.c | 47 ++++++++++++++++++++++++++++++++++++-----------
> 1 files changed, 36 insertions(+), 11 deletions(-)
>
> diff --git a/kvm-all.c b/kvm-all.c
> index badf1d8..1b66183 100644
> --- a/kvm-all.c
> +++ b/kvm-all.c
> @@ -97,6 +97,9 @@ struct KVMState
> QTAILQ_HEAD(msi_hashtab, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE];
> bool direct_msi;
> #endif
> +#ifdef KVM_CAP_READONLY_MEM
> + int readonly_mem;
> +#endif
See comment on patch 2: Make sure that KVM_CAP_READONLY_MEM is always
defined and remove all these #ifdefs.
> };
>
> KVMState *kvm_state;
> @@ -261,9 +264,18 @@ err:
> * dirty pages logging control
> */
>
> -static int kvm_mem_flags(KVMState *s, bool log_dirty)
> +static int kvm_mem_flags(KVMState *s, MemoryRegion *mr)
> {
> - return log_dirty ? KVM_MEM_LOG_DIRTY_PAGES : 0;
> + int flags;
> + bool log_dirty = memory_region_is_logging(mr);
> + bool readonly = mr->readonly;
I suppose you want to add some memory_region_is_readonly(). And both
bools can be inlined into the checks below.
> + flags = log_dirty ? KVM_MEM_LOG_DIRTY_PAGES : 0;
> +#ifdef KVM_CAP_READONLY_MEM
> + if (s->readonly_mem) {
> + flags |= readonly ? KVM_MEM_READONLY : 0;
> + }
> +#endif
> + return flags;
> }
>
> static int kvm_slot_dirty_pages_log_change(KVMSlot *mem, bool log_dirty)
> @@ -274,7 +286,7 @@ static int kvm_slot_dirty_pages_log_change(KVMSlot *mem,
> bool log_dirty)
>
> old_flags = mem->flags;
>
> - flags = (mem->flags & ~mask) | kvm_mem_flags(s, log_dirty);
> + flags = (mem->flags & ~mask) | (log_dirty ? mask : 0);
> mem->flags = flags;
>
> /* If nothing changed effectively, no need to issue ioctl */
> @@ -622,7 +634,7 @@ static void kvm_set_phys_mem(MemoryRegionSection
> *section, bool add)
> mem->memory_size = old.memory_size;
> mem->start_addr = old.start_addr;
> mem->ram = old.ram;
> - mem->flags = kvm_mem_flags(s, log_dirty);
> + mem->flags = kvm_mem_flags(s, mr);
>
> err = kvm_set_user_memory_region(s, mem);
> if (err) {
> @@ -643,7 +655,7 @@ static void kvm_set_phys_mem(MemoryRegionSection
> *section, bool add)
> mem->memory_size = start_addr - old.start_addr;
> mem->start_addr = old.start_addr;
> mem->ram = old.ram;
> - mem->flags = kvm_mem_flags(s, log_dirty);
> + mem->flags = kvm_mem_flags(s, mr);
>
> err = kvm_set_user_memory_region(s, mem);
> if (err) {
> @@ -667,7 +679,7 @@ static void kvm_set_phys_mem(MemoryRegionSection
> *section, bool add)
> size_delta = mem->start_addr - old.start_addr;
> mem->memory_size = old.memory_size - size_delta;
> mem->ram = old.ram + size_delta;
> - mem->flags = kvm_mem_flags(s, log_dirty);
> + mem->flags = kvm_mem_flags(s, mr);
>
> err = kvm_set_user_memory_region(s, mem);
> if (err) {
> @@ -689,7 +701,7 @@ static void kvm_set_phys_mem(MemoryRegionSection
> *section, bool add)
> mem->memory_size = size;
> mem->start_addr = start_addr;
> mem->ram = ram;
> - mem->flags = kvm_mem_flags(s, log_dirty);
> + mem->flags = kvm_mem_flags(s, mr);
>
> err = kvm_set_user_memory_region(s, mem);
> if (err) {
> @@ -1393,6 +1405,10 @@ int kvm_init(void)
> s->direct_msi = (kvm_check_extension(s, KVM_CAP_SIGNAL_MSI) > 0);
> #endif
>
> +#ifdef KVM_CAP_READONLY_MEM
> + s->readonly_mem = kvm_check_extension(s, KVM_CAP_READONLY_MEM);
> +#endif
> +
> s->intx_set_mask = kvm_check_extension(s, KVM_CAP_PCI_2_3);
>
> ret = kvm_arch_init(s);
> @@ -1607,10 +1623,19 @@ int kvm_cpu_exec(CPUArchState *env)
> break;
> case KVM_EXIT_MMIO:
> DPRINTF("handle_mmio\n");
> - cpu_physical_memory_rw(run->mmio.phys_addr,
> - run->mmio.data,
> - run->mmio.len,
> - run->mmio.is_write);
> + if (run->mmio.write_readonly_mem) {
> + fprintf(stderr, "Guest is writing readonly memory, "
> + "phys_addr: %llx, len:%x, data[0]:%c, skip it.\n",
> + run->mmio.phys_addr,
> + run->mmio.len,
> + run->mmio.data[0]);
This should be DPRINTF.
> + } else {
> + cpu_physical_memory_rw(run->mmio.phys_addr,
> + run->mmio.data,
> + run->mmio.len,
> + run->mmio.is_write);
> + }
> +
> ret = 0;
> break;
> case KVM_EXIT_IRQ_WINDOW_OPEN:
>
Great to see this feature for KVM finally! I'm just afraid that this
will finally break good old isapc - due to broken Seabios. KVM used to
"unbreak" it as it didn't respect write protections. ;)
Jan
--
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux
- [Qemu-devel] [PATCH 0/3] support kvm readonly memory slot in qemu, Liu Sheng, 2012/09/07
- [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu, Liu Sheng, 2012/09/07
- Re: [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu,
Jan Kiszka <=
- Re: [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu, Avi Kivity, 2012/09/09
- Re: [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu, Jan Kiszka, 2012/09/10
- Re: [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu, Kevin O'Connor, 2012/09/10
- Re: [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu, Jan Kiszka, 2012/09/11
- Re: [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu, Anthony Liguori, 2012/09/11
- Re: [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu, Jan Kiszka, 2012/09/11
- Re: [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu, Kevin O'Connor, 2012/09/11
Re: [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu, Avi Kivity, 2012/09/09