From dbddac6da01a13c9d5d162994a0a265173acecab Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 23 Mar 2015 10:31:53 +0100 Subject: memory: the only dirty memory flag for users is DIRTY_MEMORY_VGA DIRTY_MEMORY_MIGRATION is triggered by memory_global_dirty_log_start and memory_global_dirty_log_stop, so it cannot be used with memory_region_set_log. Specify this in the documentation and assert it. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include') diff --git a/include/exec/memory.h b/include/exec/memory.h index b61c84f..7b0929d 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -647,8 +647,7 @@ void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, * * @mr: the memory region being updated. * @log: whether dirty logging is to be enabled or disabled. - * @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or - * %DIRTY_MEMORY_VGA. + * @client: the user of the logging information; %DIRTY_MEMORY_VGA only. */ void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client); -- cgit v1.1 From 2d1a35bef0ed96b3f23535e459c552414ccdbafd Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 23 Mar 2015 10:50:57 +0100 Subject: memory: differentiate memory_region_is_logging and memory_region_get_dirty_log_mask For now memory regions only track DIRTY_MEMORY_VGA individually, but this will change soon. To support this, split memory_region_is_logging in two functions: one that returns a given bit from dirty_log_mask, and one that returns the entire mask. memory_region_is_logging gets an extra parameter so that the compiler flags misuse. While VGA-specific users (including the Xen listener!) will want to keep checking that bit, KVM and vhost check for "any bit except migration" (because migration is handled via the global start/stop listener callbacks). Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/exec/memory.h b/include/exec/memory.h index 7b0929d..156d506 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -591,11 +591,23 @@ const char *memory_region_name(const MemoryRegion *mr); /** * memory_region_is_logging: return whether a memory region is logging writes * - * Returns %true if the memory region is logging writes + * Returns %true if the memory region is logging writes for the given client * * @mr: the memory region being queried + * @client: the client being queried */ -bool memory_region_is_logging(MemoryRegion *mr); +bool memory_region_is_logging(MemoryRegion *mr, uint8_t client); + +/** + * memory_region_get_dirty_log_mask: return the clients for which a + * memory region is logging writes. + * + * Returns a bitmap of clients, which right now will be either 0 or + * (1 << DIRTY_MEMORY_VGA). + * + * @mr: the memory region being queried + */ +uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr); /** * memory_region_is_rom: check whether a memory region is ROM -- cgit v1.1 From b2dfd71c4843a762f2befe702adb249cf55baf66 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 25 Apr 2015 14:38:30 +0200 Subject: memory: prepare for multiple bits in the dirty log mask When the dirty log mask will also cover other bits than DIRTY_MEMORY_VGA, some listeners may be interested in the overall zero/non-zero value of the dirty log mask; others may be interested in the value of single bits. For this reason, always call log_start/log_stop if bits have respectively appeared or disappeared, and pass the old and new values of the dirty log mask so that listeners can distinguish the kinds of change. For example, KVM checks if dirty logging used to be completely disabled (in log_start) or is now completely disabled (in log_stop). On the other hand, Xen has to check manually if DIRTY_MEMORY_VGA changed, since that is the only bit it cares about. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/exec/memory.h b/include/exec/memory.h index 156d506..55dc11d 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -206,8 +206,10 @@ struct MemoryListener { void (*region_add)(MemoryListener *listener, MemoryRegionSection *section); void (*region_del)(MemoryListener *listener, MemoryRegionSection *section); void (*region_nop)(MemoryListener *listener, MemoryRegionSection *section); - void (*log_start)(MemoryListener *listener, MemoryRegionSection *section); - void (*log_stop)(MemoryListener *listener, MemoryRegionSection *section); + void (*log_start)(MemoryListener *listener, MemoryRegionSection *section, + int old, int new); + void (*log_stop)(MemoryListener *listener, MemoryRegionSection *section, + int old, int new); void (*log_sync)(MemoryListener *listener, MemoryRegionSection *section); void (*log_global_start)(MemoryListener *listener); void (*log_global_stop)(MemoryListener *listener); -- cgit v1.1 From 42af3e3a02f6d0c38c46465b7f0311eabf532f77 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Apr 2015 13:30:19 +0200 Subject: ui/console: remove dpy_gfx_update_dirty dpy_gfx_update_dirty expects DIRTY_MEMORY_VGA logging to be always on, but that will not be the case soon. Because it computes the memory region on the fly for every update (with memory_region_find), it cannot enable/disable logging by itself. We could always treat updates as invalidations if dirty logging is not enabled, assuming that the board will enable logging on the RAM region that includes the framebuffer. However, the function is unused, so just drop it. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/ui/console.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'include') diff --git a/include/ui/console.h b/include/ui/console.h index 6f7550e..06e4739 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -241,10 +241,6 @@ void dpy_text_resize(QemuConsole *con, int w, int h); void dpy_mouse_set(QemuConsole *con, int x, int y, int on); void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor); bool dpy_cursor_define_supported(QemuConsole *con); -void dpy_gfx_update_dirty(QemuConsole *con, - MemoryRegion *address_space, - uint64_t base, - bool invalidate); bool dpy_gfx_check_format(QemuConsole *con, pixman_format_code_t format); -- cgit v1.1 From 677e7805cf95f3b2bca8baf0888d1ebed7f0c606 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 23 Mar 2015 10:53:21 +0100 Subject: memory: track DIRTY_MEMORY_CODE in mr->dirty_log_mask DIRTY_MEMORY_CODE is only needed for TCG. By adding it directly to mr->dirty_log_mask, we avoid testing for TCG everywhere a region is checked for the enabled/disabled state of dirty logging. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/exec/memory.h b/include/exec/memory.h index 55dc11d..8ae004e 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -604,8 +604,8 @@ bool memory_region_is_logging(MemoryRegion *mr, uint8_t client); * memory_region_get_dirty_log_mask: return the clients for which a * memory region is logging writes. * - * Returns a bitmap of clients, which right now will be either 0 or - * (1 << DIRTY_MEMORY_VGA). + * Returns a bitmap of clients, in which the DIRTY_MEMORY_* constants + * are the bit indices. * * @mr: the memory region being queried */ -- cgit v1.1 From 49dfcec40349245ad365964468b67e132c3cedc7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 23 Mar 2015 11:35:19 +0100 Subject: ram_addr: tweaks to xen_modified_memory Invoke xen_modified_memory from cpu_physical_memory_set_dirty_range_nocode; it is akin to DIRTY_MEMORY_MIGRATION, so set it together with that bitmap. The remaining call from invalidate_and_set_dirty's "else" branch will go away soon. Second, fix the second argument to the function in the cpu_physical_memory_set_dirty_lebitmap call site. That function is only used by KVM, but it is better to be clean anyway. Acked-by: Stefano Stabellini Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/ram_addr.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index ff558a4..7f6e928 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -112,6 +112,7 @@ static inline void cpu_physical_memory_set_dirty_range_nocode(ram_addr_t start, page = start >> TARGET_PAGE_BITS; bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION], page, end - page); bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_VGA], page, end - page); + xen_modified_memory(start, length); } static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start, @@ -155,7 +156,7 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, ram_list.dirty_memory[DIRTY_MEMORY_CODE][page + k] |= temp; } } - xen_modified_memory(start, pages); + xen_modified_memory(start, pages << TARGET_PAGE_BITS); } else { /* * bitmap-traveling is faster than memory-traveling (for addr...) -- cgit v1.1 From 1652b974766401743879d78f796f44b8929b0787 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Apr 2015 14:15:48 +0200 Subject: exec: move functions to translate-all.h Remove them from the sundry exec-all.h header, since they are only used by the TCG runtime in exec.c and user-exec.c. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/exec-all.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'include') diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index b58cd47..2f7a4f1 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -90,11 +90,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, int cflags); void cpu_exec_init(CPUArchState *env); void QEMU_NORETURN cpu_loop_exit(CPUState *cpu); -int page_unprotect(target_ulong address, uintptr_t pc, void *puc); -void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, - int is_cpu_write_access); -void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end, - int is_cpu_write_access); + #if !defined(CONFIG_USER_ONLY) bool qemu_in_vcpu_thread(void); void cpu_reload_memory_map(CPUState *cpu); -- cgit v1.1 From 9564f52da7eb061326956ed9a468935e3352512d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Apr 2015 14:24:54 +0200 Subject: cputlb: remove useless arguments to tlb_unprotect_code_phys, rename These days modification of the TLB is done in notdirty_mem_write, so the virtual address and env pointer as unnecessary. The new name of the function, tlb_unprotect_code, is consistent with tlb_protect_code. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/cputlb.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include') diff --git a/include/exec/cputlb.h b/include/exec/cputlb.h index e0da9d7..360815e 100644 --- a/include/exec/cputlb.h +++ b/include/exec/cputlb.h @@ -22,8 +22,7 @@ #if !defined(CONFIG_USER_ONLY) /* cputlb.c */ void tlb_protect_code(ram_addr_t ram_addr); -void tlb_unprotect_code_phys(CPUState *cpu, ram_addr_t ram_addr, - target_ulong vaddr); +void tlb_unprotect_code(ram_addr_t ram_addr); void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start, uintptr_t length); void cpu_tlb_reset_dirty_all(ram_addr_t start1, ram_addr_t length); -- cgit v1.1 From 58d2707e8713ef17b89b8b4c9ce586c76655a385 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 23 Mar 2015 11:56:01 +0100 Subject: exec: pass client mask to cpu_physical_memory_set_dirty_range This cuts in half the cost of bitmap operations (which will become more expensive when made atomic) during migration on non-VRAM regions. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/ram_addr.h | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 7f6e928..5bbc7bb 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -41,6 +41,9 @@ void qemu_ram_free_from_ptr(ram_addr_t addr); int qemu_ram_resize(ram_addr_t base, ram_addr_t newsize, Error **errp); +#define DIRTY_CLIENTS_ALL ((1 << DIRTY_MEMORY_NUM) - 1) +#define DIRTY_CLIENTS_NOCODE (DIRTY_CLIENTS_ALL & ~(1 << DIRTY_MEMORY_CODE)) + static inline bool cpu_physical_memory_get_dirty(ram_addr_t start, ram_addr_t length, unsigned client) @@ -103,28 +106,23 @@ static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr, set_bit(addr >> TARGET_PAGE_BITS, ram_list.dirty_memory[client]); } -static inline void cpu_physical_memory_set_dirty_range_nocode(ram_addr_t start, - ram_addr_t length) -{ - unsigned long end, page; - - end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS; - page = start >> TARGET_PAGE_BITS; - bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION], page, end - page); - bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_VGA], page, end - page); - xen_modified_memory(start, length); -} - static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start, - ram_addr_t length) + ram_addr_t length, + uint8_t mask) { unsigned long end, page; end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS; page = start >> TARGET_PAGE_BITS; - bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION], page, end - page); - bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_VGA], page, end - page); - bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_CODE], page, end - page); + if (likely(mask & (1 << DIRTY_MEMORY_MIGRATION))) { + bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION], page, end - page); + } + if (unlikely(mask & (1 << DIRTY_MEMORY_VGA))) { + bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_VGA], page, end - page); + } + if (unlikely(mask & (1 << DIRTY_MEMORY_CODE))) { + bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_CODE], page, end - page); + } xen_modified_memory(start, length); } @@ -172,7 +170,8 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, addr = page_number * TARGET_PAGE_SIZE; ram_addr = start + addr; cpu_physical_memory_set_dirty_range(ram_addr, - TARGET_PAGE_SIZE * hpratio); + TARGET_PAGE_SIZE * hpratio, + DIRTY_CLIENTS_ALL); } while (c != 0); } } -- cgit v1.1 From 72b47e79cef36ed6ffc718f10e21001d7ec2a66f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Apr 2015 13:48:25 +0200 Subject: exec: invert return value of cpu_physical_memory_get_clean, rename While it is obvious that cpu_physical_memory_get_dirty returns true even if a single page is dirty, the same is not true for cpu_physical_memory_get_clean; one would expect that it returns true only if all the pages are clean, but it actually looks for even one clean page. (By contrast, the caller of that function, cpu_physical_memory_range_includes_clean, has a good name). To clarify, rename the function to cpu_physical_memory_all_dirty and return true if _all_ the pages are dirty. This is the opposite of the previous meaning, because "all are 1" is the same as "not (any is 0)", so we have to modify cpu_physical_memory_range_includes_clean as well. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/ram_addr.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 5bbc7bb..c221bd7 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -59,7 +59,7 @@ static inline bool cpu_physical_memory_get_dirty(ram_addr_t start, return next < end; } -static inline bool cpu_physical_memory_get_clean(ram_addr_t start, +static inline bool cpu_physical_memory_all_dirty(ram_addr_t start, ram_addr_t length, unsigned client) { @@ -71,7 +71,7 @@ static inline bool cpu_physical_memory_get_clean(ram_addr_t start, page = start >> TARGET_PAGE_BITS; next = find_next_zero_bit(ram_list.dirty_memory[client], end, page); - return next < end; + return next >= end; } static inline bool cpu_physical_memory_get_dirty_flag(ram_addr_t addr, @@ -92,10 +92,10 @@ static inline bool cpu_physical_memory_is_clean(ram_addr_t addr) static inline bool cpu_physical_memory_range_includes_clean(ram_addr_t start, ram_addr_t length) { - bool vga = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_VGA); - bool code = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_CODE); + bool vga = !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_VGA); + bool code = !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_CODE); bool migration = - cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_MIGRATION); + !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_MIGRATION); return vga || code || migration; } -- cgit v1.1 From e87f7778b64d4a6a78e16c288c7fdc6c15317d5f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 25 Mar 2015 15:21:39 +0100 Subject: exec: only check relevant bitmaps for cleanliness Most of the time, not all bitmaps have to be marked as dirty; do not do anything if the interesting ones are already dirty. Previously, any clean bitmap would have cause all the bitmaps to be marked dirty. In fact, unless running TCG most of the time bitmap operations need not be done at all, because memory_region_is_logging returns zero. In this case, skip the call to cpu_physical_memory_range_includes_clean altogether as well. With this patch, cpu_physical_memory_set_dirty_range is called unconditionally, so there need not be anymore a separate call to xen_modified_memory. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/ram_addr.h | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index c221bd7..3e42b4f 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -89,14 +89,25 @@ static inline bool cpu_physical_memory_is_clean(ram_addr_t addr) return !(vga && code && migration); } -static inline bool cpu_physical_memory_range_includes_clean(ram_addr_t start, - ram_addr_t length) +static inline uint8_t cpu_physical_memory_range_includes_clean(ram_addr_t start, + ram_addr_t length, + uint8_t mask) { - bool vga = !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_VGA); - bool code = !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_CODE); - bool migration = - !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_MIGRATION); - return vga || code || migration; + uint8_t ret = 0; + + if (mask & (1 << DIRTY_MEMORY_VGA) && + !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_VGA)) { + ret |= (1 << DIRTY_MEMORY_VGA); + } + if (mask & (1 << DIRTY_MEMORY_CODE) && + !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_CODE)) { + ret |= (1 << DIRTY_MEMORY_CODE); + } + if (mask & (1 << DIRTY_MEMORY_MIGRATION) && + !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_MIGRATION)) { + ret |= (1 << DIRTY_MEMORY_MIGRATION); + } + return ret; } static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr, -- cgit v1.1 From 9460dee4b2258e3990906fb34099481c8334c267 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 23 Mar 2015 11:41:32 +0100 Subject: memory: do not touch code dirty bitmap unless TCG is enabled cpu_physical_memory_set_dirty_lebitmap unconditionally syncs the DIRTY_MEMORY_CODE bitmap. This however is unused unless TCG is enabled. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/ram_addr.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 3e42b4f..9811010 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -162,11 +162,14 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION][page + k] |= temp; ram_list.dirty_memory[DIRTY_MEMORY_VGA][page + k] |= temp; - ram_list.dirty_memory[DIRTY_MEMORY_CODE][page + k] |= temp; + if (tcg_enabled()) { + ram_list.dirty_memory[DIRTY_MEMORY_CODE][page + k] |= temp; + } } } xen_modified_memory(start, pages << TARGET_PAGE_BITS); } else { + uint8_t clients = tcg_enabled() ? DIRTY_CLIENTS_ALL : DIRTY_CLIENTS_NOCODE; /* * bitmap-traveling is faster than memory-traveling (for addr...) * especially when most of the memory is not dirty. @@ -181,8 +184,7 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, addr = page_number * TARGET_PAGE_SIZE; ram_addr = start + addr; cpu_physical_memory_set_dirty_range(ram_addr, - TARGET_PAGE_SIZE * hpratio, - DIRTY_CLIENTS_ALL); + TARGET_PAGE_SIZE * hpratio, clients); } while (c != 0); } } -- cgit v1.1 From 9f02cfc84b85929947b32fe1674fbc6a429f332a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 2 Dec 2014 11:23:14 +0000 Subject: bitmap: add atomic set functions Use atomic_or() for atomic bitmaps where several threads may set bits at the same time. This avoids the race condition between threads loading an element, bitwise ORing, and then storing the element. When setting all bits in a word we can avoid atomic ops and instead just use an smp_mb() at the end. Most bitmap users don't need atomicity so introduce new functions. Signed-off-by: Stefan Hajnoczi Message-Id: <1417519399-3166-2-git-send-email-stefanha@redhat.com> [Avoid barrier in the single word case, use full barrier instead of write. - Paolo] Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/qemu/bitmap.h | 2 ++ include/qemu/bitops.h | 14 ++++++++++++++ 2 files changed, 16 insertions(+) (limited to 'include') diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h index f0273c9..3e0a4f3 100644 --- a/include/qemu/bitmap.h +++ b/include/qemu/bitmap.h @@ -39,6 +39,7 @@ * bitmap_empty(src, nbits) Are all bits zero in *src? * bitmap_full(src, nbits) Are all bits set in *src? * bitmap_set(dst, pos, nbits) Set specified bit area + * bitmap_set_atomic(dst, pos, nbits) Set specified bit area with atomic ops * bitmap_clear(dst, pos, nbits) Clear specified bit area * bitmap_find_next_zero_area(buf, len, pos, n, mask) Find bit free area */ @@ -226,6 +227,7 @@ static inline int bitmap_intersects(const unsigned long *src1, } void bitmap_set(unsigned long *map, long i, long len); +void bitmap_set_atomic(unsigned long *map, long i, long len); void bitmap_clear(unsigned long *map, long start, long nr); unsigned long bitmap_find_next_zero_area(unsigned long *map, unsigned long size, diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h index 8abdcf9..8164225 100644 --- a/include/qemu/bitops.h +++ b/include/qemu/bitops.h @@ -16,6 +16,7 @@ #include #include "host-utils.h" +#include "atomic.h" #define BITS_PER_BYTE CHAR_BIT #define BITS_PER_LONG (sizeof (unsigned long) * BITS_PER_BYTE) @@ -39,6 +40,19 @@ static inline void set_bit(long nr, unsigned long *addr) } /** + * set_bit_atomic - Set a bit in memory atomically + * @nr: the bit to set + * @addr: the address to start counting from + */ +static inline void set_bit_atomic(long nr, unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = addr + BIT_WORD(nr); + + atomic_or(p, mask); +} + +/** * clear_bit - Clears a bit in memory * @nr: Bit to clear * @addr: Address to start counting from -- cgit v1.1 From 36546e5b803f6e363906607307f27c489441fd15 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 2 Dec 2014 11:23:15 +0000 Subject: bitmap: add atomic test and clear The new bitmap_test_and_clear_atomic() function clears a range and returns whether or not the bits were set. Signed-off-by: Stefan Hajnoczi Message-Id: <1417519399-3166-3-git-send-email-stefanha@redhat.com> [Test before xchg; then a full barrier is needed at the end just like in the previous patch. The barrier can be avoided if we did at least one xchg. - Paolo] Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/qemu/bitmap.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h index 3e0a4f3..86dd9cd 100644 --- a/include/qemu/bitmap.h +++ b/include/qemu/bitmap.h @@ -41,6 +41,7 @@ * bitmap_set(dst, pos, nbits) Set specified bit area * bitmap_set_atomic(dst, pos, nbits) Set specified bit area with atomic ops * bitmap_clear(dst, pos, nbits) Clear specified bit area + * bitmap_test_and_clear_atomic(dst, pos, nbits) Test and clear area * bitmap_find_next_zero_area(buf, len, pos, n, mask) Find bit free area */ @@ -229,6 +230,7 @@ static inline int bitmap_intersects(const unsigned long *src1, void bitmap_set(unsigned long *map, long i, long len); void bitmap_set_atomic(unsigned long *map, long i, long len); void bitmap_clear(unsigned long *map, long start, long nr); +bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr); unsigned long bitmap_find_next_zero_area(unsigned long *map, unsigned long size, unsigned long start, -- cgit v1.1 From d114875b9a1c21162f69a12d72f69a22e7bab376 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 2 Dec 2014 11:23:16 +0000 Subject: memory: use atomic ops for setting dirty memory bits Use set_bit_atomic() and bitmap_set_atomic() so that multiple threads can dirty memory without race conditions. Signed-off-by: Stefan Hajnoczi Message-Id: <1417519399-3166-4-git-send-email-stefanha@redhat.com> Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/ram_addr.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 9811010..9f73076 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -114,7 +114,7 @@ static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr, unsigned client) { assert(client < DIRTY_MEMORY_NUM); - set_bit(addr >> TARGET_PAGE_BITS, ram_list.dirty_memory[client]); + set_bit_atomic(addr >> TARGET_PAGE_BITS, ram_list.dirty_memory[client]); } static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start, @@ -122,17 +122,18 @@ static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start, uint8_t mask) { unsigned long end, page; + unsigned long **d = ram_list.dirty_memory; end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS; page = start >> TARGET_PAGE_BITS; if (likely(mask & (1 << DIRTY_MEMORY_MIGRATION))) { - bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION], page, end - page); + bitmap_set_atomic(d[DIRTY_MEMORY_MIGRATION], page, end - page); } if (unlikely(mask & (1 << DIRTY_MEMORY_VGA))) { - bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_VGA], page, end - page); + bitmap_set_atomic(d[DIRTY_MEMORY_VGA], page, end - page); } if (unlikely(mask & (1 << DIRTY_MEMORY_CODE))) { - bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_CODE], page, end - page); + bitmap_set_atomic(d[DIRTY_MEMORY_CODE], page, end - page); } xen_modified_memory(start, length); } @@ -159,11 +160,12 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, for (k = 0; k < nr; k++) { if (bitmap[k]) { unsigned long temp = leul_to_cpu(bitmap[k]); + unsigned long **d = ram_list.dirty_memory; - ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION][page + k] |= temp; - ram_list.dirty_memory[DIRTY_MEMORY_VGA][page + k] |= temp; + atomic_or(&d[DIRTY_MEMORY_MIGRATION][page + k], temp); + atomic_or(&d[DIRTY_MEMORY_VGA][page + k], temp); if (tcg_enabled()) { - ram_list.dirty_memory[DIRTY_MEMORY_CODE][page + k] |= temp; + atomic_or(&d[DIRTY_MEMORY_CODE][page + k], temp); } } } -- cgit v1.1 From 20015f72bda7d2f356c43580a5542a659afedf83 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 2 Dec 2014 11:23:17 +0000 Subject: migration: move dirty bitmap sync to ram_addr.h The dirty memory bitmap is managed by ram_addr.h and copied to migration_bitmap[] periodically during live migration. Move the code to sync the bitmap to ram_addr.h where related code lives. Signed-off-by: Stefan Hajnoczi Message-Id: <1417519399-3166-5-git-send-email-stefanha@redhat.com> Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/ram_addr.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'include') diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 9f73076..63db371 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -218,5 +218,49 @@ static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start, void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length, unsigned client); +static inline +uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest, + ram_addr_t start, + ram_addr_t length) +{ + ram_addr_t addr; + unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS); + uint64_t num_dirty = 0; + + /* start address is aligned at the start of a word? */ + if (((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) { + int k; + int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS); + unsigned long *src = ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION]; + + for (k = page; k < page + nr; k++) { + if (src[k]) { + unsigned long new_dirty; + new_dirty = ~dest[k]; + dest[k] |= src[k]; + new_dirty &= src[k]; + num_dirty += ctpopl(new_dirty); + src[k] = 0; + } + } + } else { + for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) { + if (cpu_physical_memory_get_dirty(start + addr, + TARGET_PAGE_SIZE, + DIRTY_MEMORY_MIGRATION)) { + long k = (start + addr) >> TARGET_PAGE_BITS; + if (!test_and_set_bit(k, dest)) { + num_dirty++; + } + cpu_physical_memory_reset_dirty(start + addr, + TARGET_PAGE_SIZE, + DIRTY_MEMORY_MIGRATION); + } + } + } + + return num_dirty; +} + #endif #endif -- cgit v1.1 From 03eebc9e3246b9b3f5925aa41f7dfd7c1e467875 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 2 Dec 2014 11:23:18 +0000 Subject: memory: replace cpu_physical_memory_reset_dirty() with test-and-clear The cpu_physical_memory_reset_dirty() function is sometimes used together with cpu_physical_memory_get_dirty(). This is not atomic since two separate accesses to the dirty memory bitmap are made. Turn cpu_physical_memory_reset_dirty() and cpu_physical_memory_clear_dirty_range_type() into the atomic cpu_physical_memory_test_and_clear_dirty(). Signed-off-by: Stefan Hajnoczi Message-Id: <1417519399-3166-6-git-send-email-stefanha@redhat.com> Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/ram_addr.h | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 63db371..a2beea7 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -194,30 +194,19 @@ static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, } #endif /* not _WIN32 */ -static inline void cpu_physical_memory_clear_dirty_range_type(ram_addr_t start, - ram_addr_t length, - unsigned client) -{ - unsigned long end, page; - - assert(client < DIRTY_MEMORY_NUM); - end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS; - page = start >> TARGET_PAGE_BITS; - bitmap_clear(ram_list.dirty_memory[client], page, end - page); -} +bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start, + ram_addr_t length, + unsigned client); static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start, ram_addr_t length) { - cpu_physical_memory_clear_dirty_range_type(start, length, DIRTY_MEMORY_MIGRATION); - cpu_physical_memory_clear_dirty_range_type(start, length, DIRTY_MEMORY_VGA); - cpu_physical_memory_clear_dirty_range_type(start, length, DIRTY_MEMORY_CODE); + cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_MIGRATION); + cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_VGA); + cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_CODE); } -void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length, - unsigned client); - static inline uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest, ram_addr_t start, @@ -245,16 +234,14 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest, } } else { for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) { - if (cpu_physical_memory_get_dirty(start + addr, - TARGET_PAGE_SIZE, - DIRTY_MEMORY_MIGRATION)) { + if (cpu_physical_memory_test_and_clear_dirty( + start + addr, + TARGET_PAGE_SIZE, + DIRTY_MEMORY_MIGRATION)) { long k = (start + addr) >> TARGET_PAGE_BITS; if (!test_and_set_bit(k, dest)) { num_dirty++; } - cpu_physical_memory_reset_dirty(start + addr, - TARGET_PAGE_SIZE, - DIRTY_MEMORY_MIGRATION); } } } -- cgit v1.1 From 5f2cb94688bd0b2c88e0fc1ac3c4582965b7b106 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 2 Dec 2014 11:23:19 +0000 Subject: memory: make cpu_physical_memory_sync_dirty_bitmap() fully atomic The fast path of cpu_physical_memory_sync_dirty_bitmap() directly manipulates the dirty bitmap. Use atomic_xchg() to make the test-and-clear atomic. Signed-off-by: Stefan Hajnoczi Message-Id: <1417519399-3166-7-git-send-email-stefanha@redhat.com> [Only do xchg on nonzero words. - Paolo] Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/exec/ram_addr.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index a2beea7..c113f21 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -224,12 +224,12 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest, for (k = page; k < page + nr; k++) { if (src[k]) { + unsigned long bits = atomic_xchg(&src[k], 0); unsigned long new_dirty; new_dirty = ~dest[k]; - dest[k] |= src[k]; - new_dirty &= src[k]; + dest[k] |= bits; + new_dirty &= bits; num_dirty += ctpopl(new_dirty); - src[k] = 0; } } } else { -- cgit v1.1 From f794aa4a2fd772a3ec413c4e478cc23857cfee98 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 8 Apr 2015 14:52:04 +0200 Subject: target-i386: introduce cpu_get_mem_attrs Signed-off-by: Paolo Bonzini --- include/exec/memattrs.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h index 96dc440..f8537a8 100644 --- a/include/exec/memattrs.h +++ b/include/exec/memattrs.h @@ -29,7 +29,9 @@ typedef struct MemTxAttrs { * "didn't specify" if necessary. */ unsigned int unspecified:1; - /* ARM/AMBA TrustZone Secure access */ + /* ARM/AMBA: TrustZone Secure access + * x86: System Management Mode access + */ unsigned int secure:1; /* Memory access is usermode (unprivileged) */ unsigned int user:1; -- cgit v1.1 From fb9e7e334b54350e8e3b62bd7892b78f63a9d848 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 May 2015 18:29:00 +0200 Subject: qom: add object_property_add_const_link Suggested-by: Eduardo Habkost Signed-off-by: Paolo Bonzini --- include/qom/object.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'include') diff --git a/include/qom/object.h b/include/qom/object.h index d2d7748..0505f20 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1290,6 +1290,24 @@ void object_property_add_alias(Object *obj, const char *name, Error **errp); /** + * object_property_add_const_link: + * @obj: the object to add a property to + * @name: the name of the property + * @target: the object to be referred by the link + * @errp: if an error occurs, a pointer to an area to store the error + * + * Add an unmodifiable link for a property on an object. This function will + * add a property of type link where TYPE is the type of @target. + * + * The caller must ensure that @target stays alive as long as + * this property exists. In the case @target is a child of @obj, + * this will be the case. Otherwise, the caller is responsible for + * taking a reference. + */ +void object_property_add_const_link(Object *obj, const char *name, + Object *target, Error **errp); + +/** * object_property_set_description: * @obj: the object owning the property * @name: the name of the property -- cgit v1.1 From fe6567d5fddfb7501a352c5e080a9eecf7b89177 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 31 Mar 2015 14:10:22 +0200 Subject: hw/i386: add a separate region that tracks the SMRAME bit This region is exported at /machine/smram. It is "empty" if SMRAME=0 and points to SMRAM if SMRAME=1. The CPU will enable/disable it as it enters or exits SMRAM. While touching nearby code, the existing memory region setup was slightly inconsistent. The smram_region is *disabled* in order to open SMRAM (because the smram_region shows the low VRAM instead of the RAM at 0xa0000). Because SMRAM is closed at startup, the smram_region must be enabled when creating the i440fx or q35 devices. Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- include/hw/pci-host/q35.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 96d4cdc..4c9eacc 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -53,6 +53,7 @@ typedef struct MCHPCIState { MemoryRegion *address_space_io; PAMMemoryRegion pam_regions[13]; MemoryRegion smram_region; + MemoryRegion smram, low_smram; PcPciInfo pci_info; uint8_t smm_enabled; ram_addr_t below_4g_mem_size; -- cgit v1.1 From f809c605122df291bbb9004dc487bde0969134b5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 31 Mar 2015 14:12:25 +0200 Subject: target-i386: use memory API to implement SMRAM Remove cpu_smm_register and cpu_smm_update. Instead, each CPU address space gets an extra region which is an alias of /machine/smram. This extra region is enabled or disabled as the CPU enters/exits SMM. Signed-off-by: Paolo Bonzini --- include/hw/i386/pc.h | 1 - include/hw/pci-host/pam.h | 5 +---- include/hw/pci-host/q35.h | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) (limited to 'include') diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index bec6de1..86c5651 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -210,7 +210,6 @@ void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus); void pc_pci_device_init(PCIBus *pci_bus); typedef void (*cpu_set_smm_t)(int smm, void *arg); -void cpu_smm_register(cpu_set_smm_t callback, void *arg); void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name); diff --git a/include/hw/pci-host/pam.h b/include/hw/pci-host/pam.h index 4d03e4b..80dd605 100644 --- a/include/hw/pci-host/pam.h +++ b/include/hw/pci-host/pam.h @@ -86,10 +86,7 @@ typedef struct PAMMemoryRegion { unsigned current; } PAMMemoryRegion; -void smram_update(MemoryRegion *smram_region, uint8_t smram, - uint8_t smm_enabled); -void smram_set_smm(uint8_t *host_smm_enabled, int smm, uint8_t smram, - MemoryRegion *smram_region); +void smram_update(MemoryRegion *smram_region, uint8_t smram); void init_pam(DeviceState *dev, MemoryRegion *ram, MemoryRegion *system, MemoryRegion *pci, PAMMemoryRegion *mem, uint32_t start, uint32_t size); void pam_update(PAMMemoryRegion *mem, int idx, uint8_t val); diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 4c9eacc..17adeaa 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -55,7 +55,6 @@ typedef struct MCHPCIState { MemoryRegion smram_region; MemoryRegion smram, low_smram; PcPciInfo pci_info; - uint8_t smm_enabled; ram_addr_t below_4g_mem_size; ram_addr_t above_4g_mem_size; uint64_t pci_hole64_size; -- cgit v1.1 From 3de70c0899db2712a5ae321093aa6173d6f76706 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 31 Mar 2015 14:14:28 +0200 Subject: hw/i386: remove smram_update It's easier to inline it now that most of its work is done by the CPU (rather than the chipset) through /machine/smram and the memory API. Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- include/hw/pci-host/pam.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/hw/pci-host/pam.h b/include/hw/pci-host/pam.h index 80dd605..6116c63 100644 --- a/include/hw/pci-host/pam.h +++ b/include/hw/pci-host/pam.h @@ -86,7 +86,6 @@ typedef struct PAMMemoryRegion { unsigned current; } PAMMemoryRegion; -void smram_update(MemoryRegion *smram_region, uint8_t smram); void init_pam(DeviceState *dev, MemoryRegion *ram, MemoryRegion *system, MemoryRegion *pci, PAMMemoryRegion *mem, uint32_t start, uint32_t size); void pam_update(PAMMemoryRegion *mem, int idx, uint8_t val); -- cgit v1.1 From 64130fa4a1514ae7a580b8d46290a11784770600 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 31 Mar 2015 17:13:01 +0200 Subject: q35: implement high SMRAM When H_SMRAME is 1, low memory at 0xa0000 is left alone by SMM, and instead the chipset maps the 0xa0000-0xbffff window at 0xfeda0000-0xfedbffff. This affects both the "non-SMM" view controlled by D_OPEN and the SMM view controlled by G_SMRAME, so add two new MemoryRegions and toggle the enabled/disabled state of all four in mch_update_smram. Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- include/hw/pci-host/q35.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 17adeaa..0fff6a2 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -52,8 +52,8 @@ typedef struct MCHPCIState { MemoryRegion *system_memory; MemoryRegion *address_space_io; PAMMemoryRegion pam_regions[13]; - MemoryRegion smram_region; - MemoryRegion smram, low_smram; + MemoryRegion smram_region, open_high_smram; + MemoryRegion smram, low_smram, high_smram; PcPciInfo pci_info; ram_addr_t below_4g_mem_size; ram_addr_t above_4g_mem_size; @@ -127,7 +127,7 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_PAM_MASK ((uint8_t)0x3) #define MCH_HOST_BRIDGE_SMRAM 0x9d -#define MCH_HOST_BRIDGE_SMRAM_SIZE 1 +#define MCH_HOST_BRIDGE_SMRAM_SIZE 2 #define MCH_HOST_BRIDGE_SMRAM_DEFAULT ((uint8_t)0x2) #define MCH_HOST_BRIDGE_SMRAM_D_OPEN ((uint8_t)(1 << 6)) #define MCH_HOST_BRIDGE_SMRAM_D_CLS ((uint8_t)(1 << 5)) @@ -141,11 +141,11 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END 0x100000 #define MCH_HOST_BRIDGE_ESMRAMC 0x9e -#define MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 6)) -#define MCH_HOST_BRIDGE_ESMRAMC_E_SMERR ((uint8_t)(1 << 5)) -#define MCH_HOST_BRIDGE_ESMRAMC_SM_CACHE ((uint8_t)(1 << 4)) -#define MCH_HOST_BRIDGE_ESMRAMC_SM_L1 ((uint8_t)(1 << 3)) -#define MCH_HOST_BRIDGE_ESMRAMC_SM_L2 ((uint8_t)(1 << 2)) +#define MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 7)) +#define MCH_HOST_BRIDGE_ESMRAMC_E_SMERR ((uint8_t)(1 << 6)) +#define MCH_HOST_BRIDGE_ESMRAMC_SM_CACHE ((uint8_t)(1 << 5)) +#define MCH_HOST_BRIDGE_ESMRAMC_SM_L1 ((uint8_t)(1 << 4)) +#define MCH_HOST_BRIDGE_ESMRAMC_SM_L2 ((uint8_t)(1 << 3)) #define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK ((uint8_t)(0x3 << 1)) #define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB ((uint8_t)(0x0 << 1)) #define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB ((uint8_t)(0x1 << 1)) -- cgit v1.1 From 7744752402d11cebe4c1d4079dcd40d3145eb37b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 15 Apr 2015 16:43:24 +0200 Subject: q35: fix ESMRAMC default The cache bits in ESMRAMC are hardcoded to 1 (=disabled) according to the q35 mch specs. Add and use a define with this default. While being at it also update the SMRAM default to use the name (no code change, just makes things a bit more readable). Signed-off-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- include/hw/pci-host/q35.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 0fff6a2..d3c7bbb 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -128,7 +128,6 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_SMRAM 0x9d #define MCH_HOST_BRIDGE_SMRAM_SIZE 2 -#define MCH_HOST_BRIDGE_SMRAM_DEFAULT ((uint8_t)0x2) #define MCH_HOST_BRIDGE_SMRAM_D_OPEN ((uint8_t)(1 << 6)) #define MCH_HOST_BRIDGE_SMRAM_D_CLS ((uint8_t)(1 << 5)) #define MCH_HOST_BRIDGE_SMRAM_D_LCK ((uint8_t)(1 << 4)) @@ -139,6 +138,8 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_SMRAM_C_END 0xc0000 #define MCH_HOST_BRIDGE_SMRAM_C_SIZE 0x20000 #define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END 0x100000 +#define MCH_HOST_BRIDGE_SMRAM_DEFAULT \ + MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG #define MCH_HOST_BRIDGE_ESMRAMC 0x9e #define MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 7)) @@ -151,6 +152,10 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB ((uint8_t)(0x1 << 1)) #define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_8MB ((uint8_t)(0x2 << 1)) #define MCH_HOST_BRIDGE_ESMRAMC_T_EN ((uint8_t)1) +#define MCH_HOST_BRIDGE_ESMRAMC_DEFAULT \ + (MCH_HOST_BRIDGE_ESMRAMC_SM_CACHE | \ + MCH_HOST_BRIDGE_ESMRAMC_SM_L1 | \ + MCH_HOST_BRIDGE_ESMRAMC_SM_L2) /* D1:F0 PCIE* port*/ #define MCH_PCIE_DEV 1 -- cgit v1.1 From b66a67d7519cb7f980885af5391b1103c42e9b6d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 15 Apr 2015 16:48:12 +0200 Subject: q35: add config space wmask for SMRAM and ESMRAMC Not all bits in SMRAM and ESMRAMC can be changed by the guest. Add wmask defines accordingly and set them in mch_reset(). Signed-off-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- include/hw/pci-host/q35.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'include') diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index d3c7bbb..01b8492 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -140,6 +140,11 @@ typedef struct Q35PCIHost { #define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END 0x100000 #define MCH_HOST_BRIDGE_SMRAM_DEFAULT \ MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG +#define MCH_HOST_BRIDGE_SMRAM_WMASK \ + (MCH_HOST_BRIDGE_SMRAM_D_OPEN | \ + MCH_HOST_BRIDGE_SMRAM_D_CLS | \ + MCH_HOST_BRIDGE_SMRAM_D_LCK | \ + MCH_HOST_BRIDGE_SMRAM_G_SMRAME) #define MCH_HOST_BRIDGE_ESMRAMC 0x9e #define MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 7)) @@ -156,6 +161,10 @@ typedef struct Q35PCIHost { (MCH_HOST_BRIDGE_ESMRAMC_SM_CACHE | \ MCH_HOST_BRIDGE_ESMRAMC_SM_L1 | \ MCH_HOST_BRIDGE_ESMRAMC_SM_L2) +#define MCH_HOST_BRIDGE_ESMRAMC_WMASK \ + (MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME | \ + MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK | \ + MCH_HOST_BRIDGE_ESMRAMC_T_EN) /* D1:F0 PCIE* port*/ #define MCH_PCIE_DEV 1 -- cgit v1.1 From 68c77acfb18d28933f17b1c2a842bd936ce7223b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 14 Apr 2015 14:03:22 +0200 Subject: q35: implement SMRAM.D_LCK Once the SMRAM.D_LCK bit has been set by the guest several bits in SMRAM and ESMRAMC become readonly until the next machine reset. Implement this by updating the wmask accordingly when the guest sets the lock bit. As the lock it itself is locked down too we don't need to worry about the guest clearing the lock bit. Signed-off-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- include/hw/pci-host/q35.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 01b8492..113cbe8 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -145,6 +145,8 @@ typedef struct Q35PCIHost { MCH_HOST_BRIDGE_SMRAM_D_CLS | \ MCH_HOST_BRIDGE_SMRAM_D_LCK | \ MCH_HOST_BRIDGE_SMRAM_G_SMRAME) +#define MCH_HOST_BRIDGE_SMRAM_WMASK_LCK \ + MCH_HOST_BRIDGE_SMRAM_D_CLS #define MCH_HOST_BRIDGE_ESMRAMC 0x9e #define MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 7)) @@ -165,6 +167,7 @@ typedef struct Q35PCIHost { (MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME | \ MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK | \ MCH_HOST_BRIDGE_ESMRAMC_T_EN) +#define MCH_HOST_BRIDGE_ESMRAMC_WMASK_LCK 0 /* D1:F0 PCIE* port*/ #define MCH_PCIE_DEV 1 -- cgit v1.1 From bafc90bdc594a4d04db846bd8712bdcec59678a8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 20 Apr 2015 10:55:09 +0200 Subject: q35: implement TSEG TSEG provides larger amounts of SMRAM than the 128 KB available with legacy SMRAM and high SMRAM. Route access to tseg into nowhere when enabled, for both cpus and busmaster dma, and add tseg window to smram region, so cpus can access it in smm mode. Signed-off-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- include/hw/pci-host/q35.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h index 113cbe8..dbe6dc0 100644 --- a/include/hw/pci-host/q35.h +++ b/include/hw/pci-host/q35.h @@ -54,6 +54,7 @@ typedef struct MCHPCIState { PAMMemoryRegion pam_regions[13]; MemoryRegion smram_region, open_high_smram; MemoryRegion smram, low_smram, high_smram; + MemoryRegion tseg_blackhole, tseg_window; PcPciInfo pci_info; ram_addr_t below_4g_mem_size; ram_addr_t above_4g_mem_size; -- cgit v1.1 From 11e66a15a084cb0820dba13f4ea3b15b0512fd39 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 6 May 2015 10:58:30 +0200 Subject: ich9: implement SMI_LOCK Add write mask for the smi enable register, so we can disable write access to certain bits. Open all bits on reset. Disable write access to GBL_SMI_EN when SMI_LOCK (in ich9 lpc pci config space) is set. Write access to SMI_LOCK itself is disabled too. Signed-off-by: Gerd Hoffmann Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- include/hw/acpi/ich9.h | 1 + include/hw/i386/ich9.h | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'include') diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h index c2d3dba..77cc65c 100644 --- a/include/hw/acpi/ich9.h +++ b/include/hw/acpi/ich9.h @@ -39,6 +39,7 @@ typedef struct ICH9LPCPMRegs { MemoryRegion io_smi; uint32_t smi_en; + uint32_t smi_en_wmask; uint32_t smi_sts; qemu_irq irq; /* SCI */ diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h index f4e522c..a2cc15c 100644 --- a/include/hw/i386/ich9.h +++ b/include/hw/i386/ich9.h @@ -152,6 +152,12 @@ Object *ich9_lpc_find(void); #define ICH9_LPC_PIRQ_ROUT_MASK Q35_MASK(8, 3, 0) #define ICH9_LPC_PIRQ_ROUT_DEFAULT 0x80 +#define ICH9_LPC_GEN_PMCON_1 0xa0 +#define ICH9_LPC_GEN_PMCON_1_SMI_LOCK (1 << 4) +#define ICH9_LPC_GEN_PMCON_2 0xa2 +#define ICH9_LPC_GEN_PMCON_3 0xa4 +#define ICH9_LPC_GEN_PMCON_LOCK 0xa6 + #define ICH9_LPC_RCBA 0xf0 #define ICH9_LPC_RCBA_BA_MASK Q35_MASK(32, 31, 14) #define ICH9_LPC_RCBA_EN 0x1 -- cgit v1.1 From 3bbf572345c65813f86a8fc434ea1b23beb08e16 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 3 Jun 2015 14:21:20 +0200 Subject: atomics: add explicit compiler fence in __atomic memory barriers __atomic_thread_fence does not include a compiler barrier; in the C++11 memory model, fences take effect in combination with other atomic operations. GCC implements this by making __atomic_load and __atomic_store access memory as if the pointer was volatile, and leaves no trace whatsoever of acquire and release fences in the compiler's intermediate representation. In QEMU, we want memory barriers to act on all memory, but at the same time we would like to use __atomic_thread_fence for portability reasons. Add compiler barriers manually around the __atomic_thread_fence. Message-Id: <1433334080-14912-1-git-send-email-pbonzini@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini --- include/qemu/atomic.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index 98e05ca..bd2c075 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -99,7 +99,13 @@ #ifndef smp_wmb #ifdef __ATOMIC_RELEASE -#define smp_wmb() __atomic_thread_fence(__ATOMIC_RELEASE) +/* __atomic_thread_fence does not include a compiler barrier; instead, + * the barrier is part of __atomic_load/__atomic_store's "volatile-like" + * semantics. If smp_wmb() is a no-op, absence of the barrier means that + * the compiler is free to reorder stores on each side of the barrier. + * Add one here, and similarly in smp_rmb() and smp_read_barrier_depends(). + */ +#define smp_wmb() ({ barrier(); __atomic_thread_fence(__ATOMIC_RELEASE); barrier(); }) #else #define smp_wmb() __sync_synchronize() #endif @@ -107,7 +113,7 @@ #ifndef smp_rmb #ifdef __ATOMIC_ACQUIRE -#define smp_rmb() __atomic_thread_fence(__ATOMIC_ACQUIRE) +#define smp_rmb() ({ barrier(); __atomic_thread_fence(__ATOMIC_ACQUIRE); barrier(); }) #else #define smp_rmb() __sync_synchronize() #endif @@ -115,7 +121,7 @@ #ifndef smp_read_barrier_depends #ifdef __ATOMIC_CONSUME -#define smp_read_barrier_depends() __atomic_thread_fence(__ATOMIC_CONSUME) +#define smp_read_barrier_depends() ({ barrier(); __atomic_thread_fence(__ATOMIC_CONSUME); barrier(); }) #else #define smp_read_barrier_depends() barrier() #endif -- cgit v1.1 From 24a314269281a175b5540b3b6a8981ed2e8220e1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 4 Jun 2015 16:38:29 +0200 Subject: update Linux headers from kvm/next This is kvm.git commit 05ff30bb56c6b3d3000519d6e02ed35678ddae3b. Signed-off-by: Paolo Bonzini --- include/standard-headers/linux/virtio_ring.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/standard-headers/linux/virtio_ring.h b/include/standard-headers/linux/virtio_ring.h index cc647d6..6fe276f 100644 --- a/include/standard-headers/linux/virtio_ring.h +++ b/include/standard-headers/linux/virtio_ring.h @@ -155,7 +155,7 @@ static inline unsigned vring_size(unsigned int num, unsigned long align) } /* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */ -/* Assuming a given event_idx value from the other size, if +/* Assuming a given event_idx value from the other side, if * we have just incremented index from old to new_idx, * should we trigger an event? */ static inline int vring_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old) -- cgit v1.1