From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:47640) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UcWfz-0002Nc-50 for qemu-devel@nongnu.org; Wed, 15 May 2013 04:03:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UcWfs-0006kc-CD for qemu-devel@nongnu.org; Wed, 15 May 2013 04:03:07 -0400 Received: from mga01.intel.com ([192.55.52.88]:50865) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UcWfs-0006kY-3c for qemu-devel@nongnu.org; Wed, 15 May 2013 04:03:00 -0400 From: Jordan Justen Date: Wed, 15 May 2013 01:02:17 -0700 Message-Id: <1368604938-8587-4-git-send-email-jordan.l.justen@intel.com> In-Reply-To: <1368604938-8587-1-git-send-email-jordan.l.justen@intel.com> References: <1368604938-8587-1-git-send-email-jordan.l.justen@intel.com> Subject: [Qemu-devel] [PATCH v6 3/4] kvm: support using KVM_MEM_READONLY flag for regions List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Jordan Justen For readonly memory regions and rom devices that are readable, we make use of the KVM_MEM_READONLY. A slot that uses KVM_MEM_READONLY can be read from and code can execute from the region, but writes will exit to qemu. For rom devices that are not readable, we force the slot to be removed so reads or writes to the region will exit to qemu. (Note that a memory region in this state is not executable within kvm.) Signed-off-by: Jordan Justen Reviewed-by: Xiao Guangrong (v4) Reviewed-by: Paolo Bonzini --- kvm-all.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index 327ae12..aabb818 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -201,12 +201,18 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) mem.slot = slot->slot; mem.guest_phys_addr = slot->start_addr; - mem.memory_size = slot->memory_size; mem.userspace_addr = (unsigned long)slot->ram; mem.flags = slot->flags; if (s->migration_log) { mem.flags |= KVM_MEM_LOG_DIRTY_PAGES; } + if (mem.flags & KVM_MEM_READONLY) { + /* Set the slot size to 0 before setting the slot to the desired + * value. This is needed based on KVM commit 75d61fbc. */ + mem.memory_size = 0; + kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem); + } + mem.memory_size = slot->memory_size; return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem); } @@ -268,9 +274,14 @@ err: * dirty pages logging control */ -static int kvm_mem_flags(KVMState *s, bool log_dirty) +static int kvm_mem_flags(KVMState *s, bool log_dirty, bool readonly) { - return log_dirty ? KVM_MEM_LOG_DIRTY_PAGES : 0; + int flags = 0; + flags = log_dirty ? KVM_MEM_LOG_DIRTY_PAGES : 0; + if (readonly && kvm_readonly_mem_allowed) { + flags |= KVM_MEM_READONLY; + } + return flags; } static int kvm_slot_dirty_pages_log_change(KVMSlot *mem, bool log_dirty) @@ -281,7 +292,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) | kvm_mem_flags(s, log_dirty, false); mem->flags = flags; /* If nothing changed effectively, no need to issue ioctl */ @@ -619,6 +630,9 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) int err; MemoryRegion *mr = section->mr; bool log_dirty = memory_region_is_logging(mr); + bool readable = mr->readable; + bool writeable = !mr->readonly && !mr->rom_device; + bool readonly_flag = mr->readonly || memory_region_is_romd(mr); hwaddr start_addr = section->offset_within_address_space; ram_addr_t size = section->size; void *ram = NULL; @@ -638,7 +652,13 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) } if (!memory_region_is_ram(mr)) { - return; + if (writeable || !kvm_readonly_mem_allowed) { + return; + } else if (!readable) { + /* If the memory range is not readable, then we actually want + * to remove the kvm memory slot so all accesses will trap. */ + add = false; + } } ram = memory_region_get_ram_ptr(mr) + section->offset_within_region + delta; @@ -687,7 +707,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, log_dirty, readonly_flag); err = kvm_set_user_memory_region(s, mem); if (err) { @@ -708,7 +728,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, log_dirty, readonly_flag); err = kvm_set_user_memory_region(s, mem); if (err) { @@ -732,7 +752,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, log_dirty, readonly_flag); err = kvm_set_user_memory_region(s, mem); if (err) { @@ -754,7 +774,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, log_dirty, readonly_flag); err = kvm_set_user_memory_region(s, mem); if (err) { -- 1.7.10.4