qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Jan Kiszka <jan.kiszka@siemens.com>
To: Liu Sheng <liusheng@linux.vnet.ibm.com>
Cc: aliguori@us.ibm.com, kvm@vger.kernel.org, mtosatti@redhat.com,
	qemu-devel@nongnu.org, xiaoguangrong@linux.vnet.ibm.com,
	avi@redhat.com
Subject: Re: [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu
Date: Fri, 07 Sep 2012 10:50:51 +0200	[thread overview]
Message-ID: <5049B56B.20707@siemens.com> (raw)
In-Reply-To: <1347006389-543-4-git-send-email-liusheng@linux.vnet.ibm.com>

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 <xiaoguangrong@linux.vnet.ibm.com>");
> 
> 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 <liusheng@linux.vnet.ibm.com>
> ---
>  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

  reply	other threads:[~2012-09-07  8:51 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-09-07  8:26 [Qemu-devel] [PATCH 0/3] support kvm readonly memory slot in qemu Liu Sheng
2012-09-07  8:26 ` [Qemu-devel] [PATCH 1/3] set the readonly property of rom memory region in pc Liu Sheng
2012-09-07  8:26 ` [Qemu-devel] [PATCH 2/3] update kvm related the head file from kernel Liu Sheng
2012-09-07  8:49   ` Jan Kiszka
2012-09-07  9:39     ` Xiao Guangrong
2012-09-07 10:17       ` Jan Kiszka
2012-09-07  8:26 ` [Qemu-devel] [PATCH 3/3] support readonly memory feature in qemu Liu Sheng
2012-09-07  8:50   ` Jan Kiszka [this message]
2012-09-09 15:45     ` Avi Kivity
2012-09-10  9:25       ` Jan Kiszka
2012-09-11  3:02         ` Kevin O'Connor
2012-09-11 15:31           ` Jan Kiszka
2012-09-11 16:15             ` Anthony Liguori
2012-09-11 16:33               ` Jan Kiszka
2012-09-12  0:01               ` Kevin O'Connor
2012-09-09 15:42   ` Avi Kivity

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5049B56B.20707@siemens.com \
    --to=jan.kiszka@siemens.com \
    --cc=aliguori@us.ibm.com \
    --cc=avi@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=liusheng@linux.vnet.ibm.com \
    --cc=mtosatti@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=xiaoguangrong@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).