From patchwork Thu Mar 14 11:03:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yury Kotov X-Patchwork-Id: 10852627 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 311AC1575 for ; Thu, 14 Mar 2019 11:19:03 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 19A4628739 for ; Thu, 14 Mar 2019 11:19:03 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0D07129EA3; Thu, 14 Mar 2019 11:19:03 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.7 required=2.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D219A28739 for ; Thu, 14 Mar 2019 11:19:01 +0000 (UTC) Received: from localhost ([127.0.0.1]:34460 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h4OO5-0000rh-3i for patchwork-qemu-devel@patchwork.kernel.org; Thu, 14 Mar 2019 07:19:01 -0400 Received: from eggs.gnu.org ([209.51.188.92]:53747) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1h4OMY-00085h-Br for qemu-devel@nongnu.org; Thu, 14 Mar 2019 07:17:28 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1h4O9d-0007EY-FP for qemu-devel@nongnu.org; Thu, 14 Mar 2019 07:04:06 -0400 Received: from forwardcorp1j.cmail.yandex.net ([5.255.227.105]:51290) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1h4O9b-00078Z-9d for qemu-devel@nongnu.org; Thu, 14 Mar 2019 07:04:04 -0400 Received: from mxbackcorp1o.mail.yandex.net (mxbackcorp1o.mail.yandex.net [IPv6:2a02:6b8:0:1a2d::301]) by forwardcorp1j.cmail.yandex.net (Yandex) with ESMTP id E1B702150E; Thu, 14 Mar 2019 14:03:54 +0300 (MSK) Received: from smtpcorp1p.mail.yandex.net (smtpcorp1p.mail.yandex.net [2a02:6b8:0:1472:2741:0:8b6:10]) by mxbackcorp1o.mail.yandex.net (nwsmtp/Yandex) with ESMTP id wKTF77q6PH-3sQOaKCC; Thu, 14 Mar 2019 14:03:54 +0300 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex-team.ru; s=default; t=1552561434; bh=H7D+o3yF/gvkWXFk77U3a+YdTMbdAUPmufFXiiaytas=; h=Message-Id:Date:Subject:To:From:Cc; b=jW/lKZ1gUq3zZKJ6BJfJPgJxZ2PVzgQKMj9k9Jx1X1qLM05tyFkgwVJ5Qs4EJSmf/ QIrqF9wmUK0oitqJdq1KRCGbLWEczZJ9pTSmH3P4s0etrEfyYrCI0z54LVM4nVzlxU PXJ3nYXvx0GRKg7szw4QNKUNVrBb/eyBd/RRIL9c= Authentication-Results: mxbackcorp1o.mail.yandex.net; dkim=pass header.i=@yandex-team.ru Received: from dynamic-red.dhcp.yndx.net (dynamic-red.dhcp.yndx.net [2a02:6b8:0:40c:a196:9619:6556:ea2f]) by smtpcorp1p.mail.yandex.net (nwsmtp/Yandex) with ESMTPSA id kutq5HAXGV-3rOOIg9N; Thu, 14 Mar 2019 14:03:54 +0300 (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (Client certificate not present) From: Yury Kotov To: "Dr. David Alan Gilbert" , Eduardo Habkost , Igor Mammedov , Richard Henderson , Paolo Bonzini , Juan Quintela , Markus Armbruster Date: Thu, 14 Mar 2019 14:03:47 +0300 Message-Id: <20190314110347.7533-1-yury-kotov@yandex-team.ru> X-Mailer: git-send-email 2.21.0 MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 5.255.227.105 Subject: [Qemu-devel] [RFC PATCH] QEMU may write to system_memory before guest starts X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: qemu-devel@nongnu.org, "wrfsh@yandex-team.ru" Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP This patch isn't intended to merge. Just to reproduce a problem. The test for x-ignore-shread capability fails on aarch64 + tcg: Memory content inconsistency at 44c00000 first_byte = 2 last_byte = 1 current = d1 hit_edge = 1 Memory content inconsistency at 44c01000 first_byte = 2 last_byte = 1 current = 77 hit_edge = 1 I expected that QEMU doesn't write to guest RAM until VM starts, but it happens in this test. By this patch I found what causes this problem. Backtrace: 0 0x00007fb9e40affea in __memcpy_avx_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S:118 1 0x000055f4a296dd84 in address_space_write_rom_internal () at exec.c:3458 2 0x000055f4a296de3a in address_space_write_rom () at exec.c:3479 3 0x000055f4a2d519ff in rom_reset () at hw/core/loader.c:1101 4 0x000055f4a2d475ec in qemu_devices_reset () at hw/core/reset.c:69 5 0x000055f4a2c90a28 in qemu_system_reset () at vl.c:1675 6 0x000055f4a2c9851d in main () at vl.c:4552 To fix this particular we can skip these writes for the first system_reset if -incoming is set. But I'm not sure how to fix this problem in general. May be to introduce a contract which forbids to write to system_ram in such case? What do you think? Signed-off-by: Yury Kotov --- backends/hostmem-file.c | 2 +- exec.c | 15 +++++++++++++-- include/exec/cpu-common.h | 2 ++ include/exec/memory.h | 3 +++ include/qemu/mmap-alloc.h | 2 +- migration/ram.c | 2 ++ util/mmap-alloc.c | 6 ++++-- util/oslib-posix.c | 2 +- vl.c | 8 ++++++++ 9 files changed, 35 insertions(+), 7 deletions(-) diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index ce54788048..146fa2bc70 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -61,7 +61,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), name, backend->size, fb->align, - (backend->share ? RAM_SHARED : 0) | + (backend->share ? (RAM_SHARED | RAM_READONLY) : 0) | (fb->is_pmem ? RAM_PMEM : 0), fb->mem_path, errp); g_free(name); diff --git a/exec.c b/exec.c index 1d4f3784d6..cd86e9b837 100644 --- a/exec.c +++ b/exec.c @@ -1863,7 +1863,7 @@ static void *file_ram_alloc(RAMBlock *block, } area = qemu_ram_mmap(fd, memory, block->mr->align, - block->flags & RAM_SHARED); + block->flags & RAM_SHARED, block->flags & RAM_READONLY); if (area == MAP_FAILED) { error_setg_errno(errp, errno, "unable to map backing store for guest RAM"); @@ -2259,7 +2259,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, int64_t file_size; /* Just support these ram flags by now. */ - assert((ram_flags & ~(RAM_SHARED | RAM_PMEM)) == 0); + assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_READONLY)) == 0); if (xen_enabled()) { error_setg(errp, "-mem-path not supported with Xen"); @@ -2485,6 +2485,17 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length) } } } + +void qemu_ram_unprotect_all(void) +{ + RAMBlock *block; + rcu_read_lock(); + RAMBLOCK_FOREACH(block) { + int ret = mprotect(block->host, block->max_length, PROT_READ | PROT_WRITE); + assert(ret == 0); + } + rcu_read_unlock(); +} #endif /* !_WIN32 */ /* Return a host pointer to ram allocated with qemu_ram_alloc. diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index cef8b88a2a..2ad875be06 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -63,6 +63,8 @@ typedef void CPUWriteMemoryFunc(void *opaque, hwaddr addr, uint32_t value); typedef uint32_t CPUReadMemoryFunc(void *opaque, hwaddr addr); void qemu_ram_remap(ram_addr_t addr, ram_addr_t length); +void qemu_ram_unprotect_all(void); + /* This should not be used by devices. */ ram_addr_t qemu_ram_addr_from_host(void *ptr); RAMBlock *qemu_ram_block_by_name(const char *name); diff --git a/include/exec/memory.h b/include/exec/memory.h index 1625913f84..b1cb5a48d7 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -126,6 +126,9 @@ typedef struct IOMMUNotifier IOMMUNotifier; /* RAM is a persistent kind memory */ #define RAM_PMEM (1 << 5) +/* RAM is readonly*/ +#define RAM_READONLY (1 << 6) + static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn, IOMMUNotifierFlag flags, hwaddr start, hwaddr end, diff --git a/include/qemu/mmap-alloc.h b/include/qemu/mmap-alloc.h index ef04f0ed5b..f704d9b7e3 100644 --- a/include/qemu/mmap-alloc.h +++ b/include/qemu/mmap-alloc.h @@ -7,7 +7,7 @@ size_t qemu_fd_getpagesize(int fd); size_t qemu_mempath_getpagesize(const char *mem_path); -void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared); +void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared, bool readonly); void qemu_ram_munmap(int fd, void *ptr, size_t size); diff --git a/migration/ram.c b/migration/ram.c index 35bd6213e9..252fc80e6c 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4211,6 +4211,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) */ rcu_read_lock(); + qemu_ram_unprotect_all(); + if (postcopy_running) { ret = ram_load_postcopy(f); } diff --git a/util/mmap-alloc.c b/util/mmap-alloc.c index 8565885420..7dc194d909 100644 --- a/util/mmap-alloc.c +++ b/util/mmap-alloc.c @@ -75,9 +75,10 @@ size_t qemu_mempath_getpagesize(const char *mem_path) return getpagesize(); } -void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared) +void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared, bool readonly) { int flags; + int prots; int guardfd; size_t offset; size_t pagesize; @@ -128,9 +129,10 @@ void *qemu_ram_mmap(int fd, size_t size, size_t align, bool shared) flags = MAP_FIXED; flags |= fd == -1 ? MAP_ANONYMOUS : 0; flags |= shared ? MAP_SHARED : MAP_PRIVATE; + prots = PROT_READ | (readonly ? 0 : PROT_WRITE); offset = QEMU_ALIGN_UP((uintptr_t)guardptr, align) - (uintptr_t)guardptr; - ptr = mmap(guardptr + offset, size, PROT_READ | PROT_WRITE, flags, fd, 0); + ptr = mmap(guardptr + offset, size, prots, flags, fd, 0); if (ptr == MAP_FAILED) { munmap(guardptr, total); diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 37c5854b9c..c57466f8d9 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -203,7 +203,7 @@ void *qemu_memalign(size_t alignment, size_t size) void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared) { size_t align = QEMU_VMALLOC_ALIGN; - void *ptr = qemu_ram_mmap(-1, size, align, shared); + void *ptr = qemu_ram_mmap(-1, size, align, shared, false); if (ptr == MAP_FAILED) { return NULL; diff --git a/vl.c b/vl.c index 4c5cc0d8ad..2cc675ad21 100644 --- a/vl.c +++ b/vl.c @@ -2950,6 +2950,12 @@ static void register_global_properties(MachineState *ms) user_register_global_props(); } +static void unprotect_ram(void *opaque) +{ + error_report(__func__); + qemu_ram_unprotect_all(); +} + int main(int argc, char **argv, char **envp) { int i; @@ -4537,6 +4543,8 @@ int main(int argc, char **argv, char **envp) replay_start(); + qemu_register_reset(unprotect_ram, NULL); + /* This checkpoint is required by replay to separate prior clock reading from the other reads, because timer polling functions query clock values from the log. */