* KVM error improvement from Laurent
* CONFIG_PARALLEL fix from Mirek * Atomic/optimized dirty bitmap access from myself and Stefan * BUILD_DIR convenience/bugfix from Peter C * Memory leak fix from Shannon * SMM improvements (though still TCG only) from myself and Gerd, acked by mst -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAABCAAGBQJVceAwAAoJEL/70l94x66Dyz4H/RHS/OUGo6HOwG1FZ4l8RxRl FY+pwJqinxFyGySmMLVHEeQCsIfxgi8bOmuWblG7sdt245nhMIj2jglyEOCUA3RN Q9qxQr6QyXBWiwK4bfB7xI1z3/mc8cVvuxjtkLaBMa16A4MXMunWCDcyhsX9/0Vw VySgTgBbn5AyY5x58TbkB7Tl6hMZgxF0yNwU6IGQvP079dgREAL2tzR1Wk8kPC80 ltLWlrwTAzF2km5m6rmstpMeZ/XIaq3DD2LU03SyUhefMsYowGKK+7Boo4lHpVm9 XAlxflahN7VGtQuno5RpYNNSzGqSJgqu5X5JxCMnbWdPi4sX3bijQdcUhW3/0oo= =KPIz -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging * KVM error improvement from Laurent * CONFIG_PARALLEL fix from Mirek * Atomic/optimized dirty bitmap access from myself and Stefan * BUILD_DIR convenience/bugfix from Peter C * Memory leak fix from Shannon * SMM improvements (though still TCG only) from myself and Gerd, acked by mst # gpg: Signature made Fri Jun 5 18:45:20 2015 BST using RSA key ID 78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: (62 commits) update Linux headers from kvm/next atomics: add explicit compiler fence in __atomic memory barriers ich9: implement SMI_LOCK q35: implement TSEG q35: add test for SMRAM.D_LCK q35: implement SMRAM.D_LCK q35: add config space wmask for SMRAM and ESMRAMC q35: fix ESMRAMC default q35: implement high SMRAM hw/i386: remove smram_update target-i386: use memory API to implement SMRAM hw/i386: add a separate region that tracks the SMRAME bit target-i386: create a separate AddressSpace for each CPU vl: run "late" notifiers immediately qom: add object_property_add_const_link vl: allow full-blown QemuOpts syntax for -global pflash_cfi01: add secure property pflash_cfi01: change to new-style MMIO accessors pflash_cfi01: change big-endian property to BIT type target-i386: wake up processors that receive an SMI ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						ee09f84e6b
					
				| @ -1,5 +1,7 @@ | ||||
| # -*- Mode: makefile -*-
 | ||||
| 
 | ||||
| BUILD_DIR?=$(CURDIR)/.. | ||||
| 
 | ||||
| include ../config-host.mak | ||||
| include config-target.mak | ||||
| include config-devices.mak | ||||
|  | ||||
							
								
								
									
										46
									
								
								arch_init.c
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								arch_init.c
									
									
									
									
									
								
							| @ -609,52 +609,10 @@ ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr, | ||||
|     return (next - base) << TARGET_PAGE_BITS; | ||||
| } | ||||
| 
 | ||||
| static inline bool migration_bitmap_set_dirty(ram_addr_t addr) | ||||
| { | ||||
|     bool ret; | ||||
|     int nr = addr >> TARGET_PAGE_BITS; | ||||
| 
 | ||||
|     ret = test_and_set_bit(nr, migration_bitmap); | ||||
| 
 | ||||
|     if (!ret) { | ||||
|         migration_dirty_pages++; | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static void migration_bitmap_sync_range(ram_addr_t start, ram_addr_t length) | ||||
| { | ||||
|     ram_addr_t addr; | ||||
|     unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS); | ||||
| 
 | ||||
|     /* 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 = ~migration_bitmap[k]; | ||||
|                 migration_bitmap[k] |= src[k]; | ||||
|                 new_dirty &= src[k]; | ||||
|                 migration_dirty_pages += 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)) { | ||||
|                 cpu_physical_memory_reset_dirty(start + addr, | ||||
|                                                 TARGET_PAGE_SIZE, | ||||
|                                                 DIRTY_MEMORY_MIGRATION); | ||||
|                 migration_bitmap_set_dirty(start + addr); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     migration_dirty_pages += | ||||
|         cpu_physical_memory_sync_dirty_bitmap(migration_bitmap, start, length); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -108,10 +108,6 @@ void cpu_list_unlock(void) | ||||
| /***********************************************************/ | ||||
| /* CPUX86 core interface */ | ||||
| 
 | ||||
| void cpu_smm_update(CPUX86State *env) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| uint64_t cpu_get_tsc(CPUX86State *env) | ||||
| { | ||||
|     return cpu_get_real_ticks(); | ||||
|  | ||||
							
								
								
									
										84
									
								
								cpus.c
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								cpus.c
									
									
									
									
									
								
							| @ -105,6 +105,7 @@ static bool all_cpu_threads_idle(void) | ||||
| 
 | ||||
| /* Protected by TimersState seqlock */ | ||||
| 
 | ||||
| static bool icount_sleep = true; | ||||
| static int64_t vm_clock_warp_start = -1; | ||||
| /* Conversion factor from emulated instructions to virtual clock ticks.  */ | ||||
| static int icount_time_shift; | ||||
| @ -393,15 +394,18 @@ void qemu_clock_warp(QEMUClockType type) | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL timer now. | ||||
|      * This ensures that the deadline for the timer is computed correctly below. | ||||
|      * This also makes sure that the insn counter is synchronized before the | ||||
|      * CPU starts running, in case the CPU is woken by an event other than | ||||
|      * the earliest QEMU_CLOCK_VIRTUAL timer. | ||||
|      */ | ||||
|     icount_warp_rt(NULL); | ||||
|     timer_del(icount_warp_timer); | ||||
|     if (icount_sleep) { | ||||
|         /*
 | ||||
|          * If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL timer now. | ||||
|          * This ensures that the deadline for the timer is computed correctly | ||||
|          * below. | ||||
|          * This also makes sure that the insn counter is synchronized before | ||||
|          * the CPU starts running, in case the CPU is woken by an event other | ||||
|          * than the earliest QEMU_CLOCK_VIRTUAL timer. | ||||
|          */ | ||||
|         icount_warp_rt(NULL); | ||||
|         timer_del(icount_warp_timer); | ||||
|     } | ||||
|     if (!all_cpu_threads_idle()) { | ||||
|         return; | ||||
|     } | ||||
| @ -415,6 +419,11 @@ void qemu_clock_warp(QEMUClockType type) | ||||
|     clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT); | ||||
|     deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); | ||||
|     if (deadline < 0) { | ||||
|         static bool notified; | ||||
|         if (!icount_sleep && !notified) { | ||||
|             error_report("WARNING: icount sleep disabled and no active timers"); | ||||
|             notified = true; | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
| @ -425,23 +434,35 @@ void qemu_clock_warp(QEMUClockType type) | ||||
|          * interrupt to wake it up, but the interrupt never comes because | ||||
|          * the vCPU isn't running any insns and thus doesn't advance the | ||||
|          * QEMU_CLOCK_VIRTUAL. | ||||
|          * | ||||
|          * An extreme solution for this problem would be to never let VCPUs | ||||
|          * sleep in icount mode if there is a pending QEMU_CLOCK_VIRTUAL | ||||
|          * timer; rather time could just advance to the next QEMU_CLOCK_VIRTUAL | ||||
|          * event.  Instead, we do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL | ||||
|          * after some "real" time, (related to the time left until the next | ||||
|          * event) has passed. The QEMU_CLOCK_VIRTUAL_RT clock will do this. | ||||
|          * This avoids that the warps are visible externally; for example, | ||||
|          * you will not be sending network packets continuously instead of | ||||
|          * every 100ms. | ||||
|          */ | ||||
|         seqlock_write_lock(&timers_state.vm_clock_seqlock); | ||||
|         if (vm_clock_warp_start == -1 || vm_clock_warp_start > clock) { | ||||
|             vm_clock_warp_start = clock; | ||||
|         if (!icount_sleep) { | ||||
|             /*
 | ||||
|              * We never let VCPUs sleep in no sleep icount mode. | ||||
|              * If there is a pending QEMU_CLOCK_VIRTUAL timer we just advance | ||||
|              * to the next QEMU_CLOCK_VIRTUAL event and notify it. | ||||
|              * It is useful when we want a deterministic execution time, | ||||
|              * isolated from host latencies. | ||||
|              */ | ||||
|             seqlock_write_lock(&timers_state.vm_clock_seqlock); | ||||
|             timers_state.qemu_icount_bias += deadline; | ||||
|             seqlock_write_unlock(&timers_state.vm_clock_seqlock); | ||||
|             qemu_clock_notify(QEMU_CLOCK_VIRTUAL); | ||||
|         } else { | ||||
|             /*
 | ||||
|              * We do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL after some | ||||
|              * "real" time, (related to the time left until the next event) has | ||||
|              * passed. The QEMU_CLOCK_VIRTUAL_RT clock will do this. | ||||
|              * This avoids that the warps are visible externally; for example, | ||||
|              * you will not be sending network packets continuously instead of | ||||
|              * every 100ms. | ||||
|              */ | ||||
|             seqlock_write_lock(&timers_state.vm_clock_seqlock); | ||||
|             if (vm_clock_warp_start == -1 || vm_clock_warp_start > clock) { | ||||
|                 vm_clock_warp_start = clock; | ||||
|             } | ||||
|             seqlock_write_unlock(&timers_state.vm_clock_seqlock); | ||||
|             timer_mod_anticipate(icount_warp_timer, clock + deadline); | ||||
|         } | ||||
|         seqlock_write_unlock(&timers_state.vm_clock_seqlock); | ||||
|         timer_mod_anticipate(icount_warp_timer, clock + deadline); | ||||
|     } else if (deadline == 0) { | ||||
|         qemu_clock_notify(QEMU_CLOCK_VIRTUAL); | ||||
|     } | ||||
| @ -504,9 +525,18 @@ void configure_icount(QemuOpts *opts, Error **errp) | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     icount_sleep = qemu_opt_get_bool(opts, "sleep", true); | ||||
|     if (icount_sleep) { | ||||
|         icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, | ||||
|                                          icount_warp_rt, NULL); | ||||
|     } | ||||
| 
 | ||||
|     icount_align_option = qemu_opt_get_bool(opts, "align", false); | ||||
|     icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, | ||||
|                                      icount_warp_rt, NULL); | ||||
| 
 | ||||
|     if (icount_align_option && !icount_sleep) { | ||||
|         error_setg(errp, "align=on and sleep=no are incompatible"); | ||||
|     } | ||||
|     if (strcmp(option, "auto") != 0) { | ||||
|         errno = 0; | ||||
|         icount_time_shift = strtol(option, &rem_str, 0); | ||||
| @ -517,6 +547,8 @@ void configure_icount(QemuOpts *opts, Error **errp) | ||||
|         return; | ||||
|     } else if (icount_align_option) { | ||||
|         error_setg(errp, "shift=auto and align=on are incompatible"); | ||||
|     } else if (!icount_sleep) { | ||||
|         error_setg(errp, "shift=auto and sleep=no are incompatible"); | ||||
|     } | ||||
| 
 | ||||
|     use_icount = 2; | ||||
|  | ||||
							
								
								
									
										7
									
								
								cputlb.c
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								cputlb.c
									
									
									
									
									
								
							| @ -125,14 +125,13 @@ void tlb_flush_page(CPUState *cpu, target_ulong addr) | ||||
|    can be detected */ | ||||
| void tlb_protect_code(ram_addr_t ram_addr) | ||||
| { | ||||
|     cpu_physical_memory_reset_dirty(ram_addr, TARGET_PAGE_SIZE, | ||||
|                                     DIRTY_MEMORY_CODE); | ||||
|     cpu_physical_memory_test_and_clear_dirty(ram_addr, TARGET_PAGE_SIZE, | ||||
|                                              DIRTY_MEMORY_CODE); | ||||
| } | ||||
| 
 | ||||
| /* update the TLB so that writes in physical page 'phys_addr' are no longer
 | ||||
|    tested for self modifying code */ | ||||
| void tlb_unprotect_code_phys(CPUState *cpu, ram_addr_t ram_addr, | ||||
|                              target_ulong vaddr) | ||||
| void tlb_unprotect_code(ram_addr_t ram_addr) | ||||
| { | ||||
|     cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE); | ||||
| } | ||||
|  | ||||
							
								
								
									
										123
									
								
								exec.c
									
									
									
									
									
								
							
							
						
						
									
										123
									
								
								exec.c
									
									
									
									
									
								
							| @ -59,8 +59,6 @@ | ||||
| //#define DEBUG_SUBPAGE
 | ||||
| 
 | ||||
| #if !defined(CONFIG_USER_ONLY) | ||||
| static bool in_migration; | ||||
| 
 | ||||
| /* ram_list is read under rcu_read_lock()/rcu_read_unlock().  Writes
 | ||||
|  * are protected by the ramlist lock. | ||||
|  */ | ||||
| @ -173,17 +171,22 @@ static void phys_map_node_reserve(PhysPageMap *map, unsigned nodes) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static uint32_t phys_map_node_alloc(PhysPageMap *map) | ||||
| static uint32_t phys_map_node_alloc(PhysPageMap *map, bool leaf) | ||||
| { | ||||
|     unsigned i; | ||||
|     uint32_t ret; | ||||
|     PhysPageEntry e; | ||||
|     PhysPageEntry *p; | ||||
| 
 | ||||
|     ret = map->nodes_nb++; | ||||
|     p = map->nodes[ret]; | ||||
|     assert(ret != PHYS_MAP_NODE_NIL); | ||||
|     assert(ret != map->nodes_nb_alloc); | ||||
| 
 | ||||
|     e.skip = leaf ? 0 : 1; | ||||
|     e.ptr = leaf ? PHYS_SECTION_UNASSIGNED : PHYS_MAP_NODE_NIL; | ||||
|     for (i = 0; i < P_L2_SIZE; ++i) { | ||||
|         map->nodes[ret][i].skip = 1; | ||||
|         map->nodes[ret][i].ptr = PHYS_MAP_NODE_NIL; | ||||
|         memcpy(&p[i], &e, sizeof(e)); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| @ -193,21 +196,12 @@ static void phys_page_set_level(PhysPageMap *map, PhysPageEntry *lp, | ||||
|                                 int level) | ||||
| { | ||||
|     PhysPageEntry *p; | ||||
|     int i; | ||||
|     hwaddr step = (hwaddr)1 << (level * P_L2_BITS); | ||||
| 
 | ||||
|     if (lp->skip && lp->ptr == PHYS_MAP_NODE_NIL) { | ||||
|         lp->ptr = phys_map_node_alloc(map); | ||||
|         p = map->nodes[lp->ptr]; | ||||
|         if (level == 0) { | ||||
|             for (i = 0; i < P_L2_SIZE; i++) { | ||||
|                 p[i].skip = 0; | ||||
|                 p[i].ptr = PHYS_SECTION_UNASSIGNED; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         p = map->nodes[lp->ptr]; | ||||
|         lp->ptr = phys_map_node_alloc(map, level == 0); | ||||
|     } | ||||
|     p = map->nodes[lp->ptr]; | ||||
|     lp = &p[(*index >> (level * P_L2_BITS)) & (P_L2_SIZE - 1)]; | ||||
| 
 | ||||
|     while (*nb && lp < &p[P_L2_SIZE]) { | ||||
| @ -858,21 +852,27 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length) | ||||
| } | ||||
| 
 | ||||
| /* Note: start and end must be within the same ram block.  */ | ||||
| void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length, | ||||
|                                      unsigned client) | ||||
| bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start, | ||||
|                                               ram_addr_t length, | ||||
|                                               unsigned client) | ||||
| { | ||||
|     if (length == 0) | ||||
|         return; | ||||
|     cpu_physical_memory_clear_dirty_range_type(start, length, client); | ||||
|     unsigned long end, page; | ||||
|     bool dirty; | ||||
| 
 | ||||
|     if (tcg_enabled()) { | ||||
|     if (length == 0) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS; | ||||
|     page = start >> TARGET_PAGE_BITS; | ||||
|     dirty = bitmap_test_and_clear_atomic(ram_list.dirty_memory[client], | ||||
|                                          page, end - page); | ||||
| 
 | ||||
|     if (dirty && tcg_enabled()) { | ||||
|         tlb_reset_dirty_range_all(start, length); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void cpu_physical_memory_set_dirty_tracking(bool enable) | ||||
| { | ||||
|     in_migration = enable; | ||||
|     return dirty; | ||||
| } | ||||
| 
 | ||||
| /* Called from RCU critical section */ | ||||
| @ -1362,7 +1362,8 @@ int qemu_ram_resize(ram_addr_t base, ram_addr_t newsize, Error **errp) | ||||
| 
 | ||||
|     cpu_physical_memory_clear_dirty_range(block->offset, block->used_length); | ||||
|     block->used_length = newsize; | ||||
|     cpu_physical_memory_set_dirty_range(block->offset, block->used_length); | ||||
|     cpu_physical_memory_set_dirty_range(block->offset, block->used_length, | ||||
|                                         DIRTY_CLIENTS_ALL); | ||||
|     memory_region_set_size(block->mr, newsize); | ||||
|     if (block->resized) { | ||||
|         block->resized(block->idstr, newsize, block->host); | ||||
| @ -1436,7 +1437,8 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp) | ||||
|        } | ||||
|     } | ||||
|     cpu_physical_memory_set_dirty_range(new_block->offset, | ||||
|                                         new_block->used_length); | ||||
|                                         new_block->used_length, | ||||
|                                         DIRTY_CLIENTS_ALL); | ||||
| 
 | ||||
|     if (new_block->host) { | ||||
|         qemu_ram_setup_dump(new_block->host, new_block->max_length); | ||||
| @ -1824,7 +1826,11 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr, | ||||
|     default: | ||||
|         abort(); | ||||
|     } | ||||
|     cpu_physical_memory_set_dirty_range_nocode(ram_addr, size); | ||||
|     /* Set both VGA and migration bits for simplicity and to remove
 | ||||
|      * the notdirty callback faster. | ||||
|      */ | ||||
|     cpu_physical_memory_set_dirty_range(ram_addr, size, | ||||
|                                         DIRTY_CLIENTS_NOCODE); | ||||
|     /* we remove the notdirty callback only if the code has been
 | ||||
|        flushed */ | ||||
|     if (!cpu_physical_memory_is_clean(ram_addr)) { | ||||
| @ -2165,22 +2171,6 @@ static void tcg_commit(MemoryListener *listener) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void core_log_global_start(MemoryListener *listener) | ||||
| { | ||||
|     cpu_physical_memory_set_dirty_tracking(true); | ||||
| } | ||||
| 
 | ||||
| static void core_log_global_stop(MemoryListener *listener) | ||||
| { | ||||
|     cpu_physical_memory_set_dirty_tracking(false); | ||||
| } | ||||
| 
 | ||||
| static MemoryListener core_memory_listener = { | ||||
|     .log_global_start = core_log_global_start, | ||||
|     .log_global_stop = core_log_global_stop, | ||||
|     .priority = 1, | ||||
| }; | ||||
| 
 | ||||
| void address_space_init_dispatch(AddressSpace *as) | ||||
| { | ||||
|     as->dispatch = NULL; | ||||
| @ -2220,8 +2210,6 @@ static void memory_map_init(void) | ||||
|     memory_region_init_io(system_io, NULL, &unassigned_io_ops, NULL, "io", | ||||
|                           65536); | ||||
|     address_space_init(&address_space_io, system_io, "I/O"); | ||||
| 
 | ||||
|     memory_listener_register(&core_memory_listener, &address_space_memory); | ||||
| } | ||||
| 
 | ||||
| MemoryRegion *get_system_memory(void) | ||||
| @ -2279,14 +2267,23 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr, | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| static void invalidate_and_set_dirty(hwaddr addr, | ||||
| static void invalidate_and_set_dirty(MemoryRegion *mr, hwaddr addr, | ||||
|                                      hwaddr length) | ||||
| { | ||||
|     if (cpu_physical_memory_range_includes_clean(addr, length)) { | ||||
|         tb_invalidate_phys_range(addr, addr + length, 0); | ||||
|         cpu_physical_memory_set_dirty_range_nocode(addr, length); | ||||
|     uint8_t dirty_log_mask = memory_region_get_dirty_log_mask(mr); | ||||
|     /* No early return if dirty_log_mask is or becomes 0, because
 | ||||
|      * cpu_physical_memory_set_dirty_range will still call | ||||
|      * xen_modified_memory. | ||||
|      */ | ||||
|     if (dirty_log_mask) { | ||||
|         dirty_log_mask = | ||||
|             cpu_physical_memory_range_includes_clean(addr, length, dirty_log_mask); | ||||
|     } | ||||
|     xen_modified_memory(addr, length); | ||||
|     if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) { | ||||
|         tb_invalidate_phys_range(addr, addr + length); | ||||
|         dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE); | ||||
|     } | ||||
|     cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask); | ||||
| } | ||||
| 
 | ||||
| static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr) | ||||
| @ -2371,7 +2368,7 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs, | ||||
|                 /* RAM case */ | ||||
|                 ptr = qemu_get_ram_ptr(addr1); | ||||
|                 memcpy(ptr, buf, l); | ||||
|                 invalidate_and_set_dirty(addr1, l); | ||||
|                 invalidate_and_set_dirty(mr, addr1, l); | ||||
|             } | ||||
|         } else { | ||||
|             if (!memory_access_is_direct(mr, is_write)) { | ||||
| @ -2468,7 +2465,7 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as, | ||||
|             switch (type) { | ||||
|             case WRITE_DATA: | ||||
|                 memcpy(ptr, buf, l); | ||||
|                 invalidate_and_set_dirty(addr1, l); | ||||
|                 invalidate_and_set_dirty(mr, addr1, l); | ||||
|                 break; | ||||
|             case FLUSH_CACHE: | ||||
|                 flush_icache_range((uintptr_t)ptr, (uintptr_t)ptr + l); | ||||
| @ -2693,7 +2690,7 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len, | ||||
|         mr = qemu_ram_addr_from_host(buffer, &addr1); | ||||
|         assert(mr != NULL); | ||||
|         if (is_write) { | ||||
|             invalidate_and_set_dirty(addr1, access_len); | ||||
|             invalidate_and_set_dirty(mr, addr1, access_len); | ||||
|         } | ||||
|         if (xen_enabled()) { | ||||
|             xen_invalidate_map_cache_entry(buffer); | ||||
| @ -3022,6 +3019,7 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val, | ||||
|     hwaddr l = 4; | ||||
|     hwaddr addr1; | ||||
|     MemTxResult r; | ||||
|     uint8_t dirty_log_mask; | ||||
| 
 | ||||
|     rcu_read_lock(); | ||||
|     mr = address_space_translate(as, addr, &addr1, &l, | ||||
| @ -3033,14 +3031,9 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val, | ||||
|         ptr = qemu_get_ram_ptr(addr1); | ||||
|         stl_p(ptr, val); | ||||
| 
 | ||||
|         if (unlikely(in_migration)) { | ||||
|             if (cpu_physical_memory_is_clean(addr1)) { | ||||
|                 /* invalidate code */ | ||||
|                 tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); | ||||
|                 /* set dirty bit */ | ||||
|                 cpu_physical_memory_set_dirty_range_nocode(addr1, 4); | ||||
|             } | ||||
|         } | ||||
|         dirty_log_mask = memory_region_get_dirty_log_mask(mr); | ||||
|         dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE); | ||||
|         cpu_physical_memory_set_dirty_range(addr1, 4, dirty_log_mask); | ||||
|         r = MEMTX_OK; | ||||
|     } | ||||
|     if (result) { | ||||
| @ -3096,7 +3089,7 @@ static inline void address_space_stl_internal(AddressSpace *as, | ||||
|             stl_p(ptr, val); | ||||
|             break; | ||||
|         } | ||||
|         invalidate_and_set_dirty(addr1, 4); | ||||
|         invalidate_and_set_dirty(mr, addr1, 4); | ||||
|         r = MEMTX_OK; | ||||
|     } | ||||
|     if (result) { | ||||
| @ -3200,7 +3193,7 @@ static inline void address_space_stw_internal(AddressSpace *as, | ||||
|             stw_p(ptr, val); | ||||
|             break; | ||||
|         } | ||||
|         invalidate_and_set_dirty(addr1, 2); | ||||
|         invalidate_and_set_dirty(mr, addr1, 2); | ||||
|         r = MEMTX_OK; | ||||
|     } | ||||
|     if (result) { | ||||
|  | ||||
| @ -94,7 +94,8 @@ static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val, | ||||
|     ICH9LPCPMRegs *pm = opaque; | ||||
|     switch (addr) { | ||||
|     case 0: | ||||
|         pm->smi_en = val; | ||||
|         pm->smi_en &= ~pm->smi_en_wmask; | ||||
|         pm->smi_en |= (val & pm->smi_en_wmask); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| @ -198,6 +199,7 @@ static void pm_reset(void *opaque) | ||||
|          * support SMM mode. */ | ||||
|         pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN; | ||||
|     } | ||||
|     pm->smi_en_wmask = ~0; | ||||
| 
 | ||||
|     acpi_update_sci(&pm->acpi_regs, pm->irq); | ||||
| } | ||||
|  | ||||
| @ -525,7 +525,7 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name, | ||||
|     qdev_prop_set_uint64(dev, "sector-length", VEXPRESS_FLASH_SECT_SIZE); | ||||
|     qdev_prop_set_uint8(dev, "width", 4); | ||||
|     qdev_prop_set_uint8(dev, "device-width", 2); | ||||
|     qdev_prop_set_uint8(dev, "big-endian", 0); | ||||
|     qdev_prop_set_bit(dev, "big-endian", false); | ||||
|     qdev_prop_set_uint16(dev, "id0", 0x89); | ||||
|     qdev_prop_set_uint16(dev, "id1", 0x18); | ||||
|     qdev_prop_set_uint16(dev, "id2", 0x00); | ||||
|  | ||||
| @ -555,7 +555,7 @@ static void create_one_flash(const char *name, hwaddr flashbase, | ||||
|     qdev_prop_set_uint64(dev, "sector-length", sectorlength); | ||||
|     qdev_prop_set_uint8(dev, "width", 4); | ||||
|     qdev_prop_set_uint8(dev, "device-width", 2); | ||||
|     qdev_prop_set_uint8(dev, "big-endian", 0); | ||||
|     qdev_prop_set_bit(dev, "big-endian", false); | ||||
|     qdev_prop_set_uint16(dev, "id0", 0x89); | ||||
|     qdev_prop_set_uint16(dev, "id1", 0x18); | ||||
|     qdev_prop_set_uint16(dev, "id2", 0x00); | ||||
|  | ||||
| @ -64,6 +64,9 @@ do {                                                        \ | ||||
| #define TYPE_CFI_PFLASH01 "cfi.pflash01" | ||||
| #define CFI_PFLASH01(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH01) | ||||
| 
 | ||||
| #define PFLASH_BE          0 | ||||
| #define PFLASH_SECURE      1 | ||||
| 
 | ||||
| struct pflash_t { | ||||
|     /*< private >*/ | ||||
|     SysBusDevice parent_obj; | ||||
| @ -75,7 +78,7 @@ struct pflash_t { | ||||
|     uint8_t bank_width; | ||||
|     uint8_t device_width; /* If 0, device width not specified. */ | ||||
|     uint8_t max_device_width;  /* max device width in bytes */ | ||||
|     uint8_t be; | ||||
|     uint32_t features; | ||||
|     uint8_t wcycle; /* if 0, the flash is read normally */ | ||||
|     int ro; | ||||
|     uint8_t cmd; | ||||
| @ -235,12 +238,57 @@ static uint32_t pflash_devid_query(pflash_t *pfl, hwaddr offset) | ||||
|     return resp; | ||||
| } | ||||
| 
 | ||||
| static uint32_t pflash_data_read(pflash_t *pfl, hwaddr offset, | ||||
|                                  int width, int be) | ||||
| { | ||||
|     uint8_t *p; | ||||
|     uint32_t ret; | ||||
| 
 | ||||
|     p = pfl->storage; | ||||
|     switch (width) { | ||||
|     case 1: | ||||
|         ret = p[offset]; | ||||
|         DPRINTF("%s: data offset " TARGET_FMT_plx " %02x\n", | ||||
|                 __func__, offset, ret); | ||||
|         break; | ||||
|     case 2: | ||||
|         if (be) { | ||||
|             ret = p[offset] << 8; | ||||
|             ret |= p[offset + 1]; | ||||
|         } else { | ||||
|             ret = p[offset]; | ||||
|             ret |= p[offset + 1] << 8; | ||||
|         } | ||||
|         DPRINTF("%s: data offset " TARGET_FMT_plx " %04x\n", | ||||
|                 __func__, offset, ret); | ||||
|         break; | ||||
|     case 4: | ||||
|         if (be) { | ||||
|             ret = p[offset] << 24; | ||||
|             ret |= p[offset + 1] << 16; | ||||
|             ret |= p[offset + 2] << 8; | ||||
|             ret |= p[offset + 3]; | ||||
|         } else { | ||||
|             ret = p[offset]; | ||||
|             ret |= p[offset + 1] << 8; | ||||
|             ret |= p[offset + 2] << 16; | ||||
|             ret |= p[offset + 3] << 24; | ||||
|         } | ||||
|         DPRINTF("%s: data offset " TARGET_FMT_plx " %08x\n", | ||||
|                 __func__, offset, ret); | ||||
|         break; | ||||
|     default: | ||||
|         DPRINTF("BUG in %s\n", __func__); | ||||
|         abort(); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, | ||||
|                              int width, int be) | ||||
| { | ||||
|     hwaddr boff; | ||||
|     uint32_t ret; | ||||
|     uint8_t *p; | ||||
| 
 | ||||
|     ret = -1; | ||||
| 
 | ||||
| @ -257,43 +305,7 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, | ||||
|         /* fall through to read code */ | ||||
|     case 0x00: | ||||
|         /* Flash area read */ | ||||
|         p = pfl->storage; | ||||
|         switch (width) { | ||||
|         case 1: | ||||
|             ret = p[offset]; | ||||
|             DPRINTF("%s: data offset " TARGET_FMT_plx " %02x\n", | ||||
|                     __func__, offset, ret); | ||||
|             break; | ||||
|         case 2: | ||||
|             if (be) { | ||||
|                 ret = p[offset] << 8; | ||||
|                 ret |= p[offset + 1]; | ||||
|             } else { | ||||
|                 ret = p[offset]; | ||||
|                 ret |= p[offset + 1] << 8; | ||||
|             } | ||||
|             DPRINTF("%s: data offset " TARGET_FMT_plx " %04x\n", | ||||
|                     __func__, offset, ret); | ||||
|             break; | ||||
|         case 4: | ||||
|             if (be) { | ||||
|                 ret = p[offset] << 24; | ||||
|                 ret |= p[offset + 1] << 16; | ||||
|                 ret |= p[offset + 2] << 8; | ||||
|                 ret |= p[offset + 3]; | ||||
|             } else { | ||||
|                 ret = p[offset]; | ||||
|                 ret |= p[offset + 1] << 8; | ||||
|                 ret |= p[offset + 2] << 16; | ||||
|                 ret |= p[offset + 3] << 24; | ||||
|             } | ||||
|             DPRINTF("%s: data offset " TARGET_FMT_plx " %08x\n", | ||||
|                     __func__, offset, ret); | ||||
|             break; | ||||
|         default: | ||||
|             DPRINTF("BUG in %s\n", __func__); | ||||
|         } | ||||
| 
 | ||||
|         ret = pflash_data_read(pfl, offset, width, be); | ||||
|         break; | ||||
|     case 0x10: /* Single byte program */ | ||||
|     case 0x20: /* Block erase */ | ||||
| @ -648,101 +660,37 @@ static void pflash_write(pflash_t *pfl, hwaddr offset, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static uint32_t pflash_readb_be(void *opaque, hwaddr addr) | ||||
| { | ||||
|     return pflash_read(opaque, addr, 1, 1); | ||||
| } | ||||
| 
 | ||||
| static uint32_t pflash_readb_le(void *opaque, hwaddr addr) | ||||
| { | ||||
|     return pflash_read(opaque, addr, 1, 0); | ||||
| } | ||||
| 
 | ||||
| static uint32_t pflash_readw_be(void *opaque, hwaddr addr) | ||||
| static MemTxResult pflash_mem_read_with_attrs(void *opaque, hwaddr addr, uint64_t *value, | ||||
|                                               unsigned len, MemTxAttrs attrs) | ||||
| { | ||||
|     pflash_t *pfl = opaque; | ||||
|     bool be = !!(pfl->features & (1 << PFLASH_BE)); | ||||
| 
 | ||||
|     return pflash_read(pfl, addr, 2, 1); | ||||
|     if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) { | ||||
|         *value = pflash_data_read(opaque, addr, len, be); | ||||
|     } else { | ||||
|         *value = pflash_read(opaque, addr, len, be); | ||||
|     } | ||||
|     return MEMTX_OK; | ||||
| } | ||||
| 
 | ||||
| static uint32_t pflash_readw_le(void *opaque, hwaddr addr) | ||||
| static MemTxResult pflash_mem_write_with_attrs(void *opaque, hwaddr addr, uint64_t value, | ||||
|                                                unsigned len, MemTxAttrs attrs) | ||||
| { | ||||
|     pflash_t *pfl = opaque; | ||||
|     bool be = !!(pfl->features & (1 << PFLASH_BE)); | ||||
| 
 | ||||
|     return pflash_read(pfl, addr, 2, 0); | ||||
|     if ((pfl->features & (1 << PFLASH_SECURE)) && !attrs.secure) { | ||||
|         return MEMTX_ERROR; | ||||
|     } else { | ||||
|         pflash_write(opaque, addr, value, len, be); | ||||
|         return MEMTX_OK; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static uint32_t pflash_readl_be(void *opaque, hwaddr addr) | ||||
| { | ||||
|     pflash_t *pfl = opaque; | ||||
| 
 | ||||
|     return pflash_read(pfl, addr, 4, 1); | ||||
| } | ||||
| 
 | ||||
| static uint32_t pflash_readl_le(void *opaque, hwaddr addr) | ||||
| { | ||||
|     pflash_t *pfl = opaque; | ||||
| 
 | ||||
|     return pflash_read(pfl, addr, 4, 0); | ||||
| } | ||||
| 
 | ||||
| static void pflash_writeb_be(void *opaque, hwaddr addr, | ||||
|                              uint32_t value) | ||||
| { | ||||
|     pflash_write(opaque, addr, value, 1, 1); | ||||
| } | ||||
| 
 | ||||
| static void pflash_writeb_le(void *opaque, hwaddr addr, | ||||
|                              uint32_t value) | ||||
| { | ||||
|     pflash_write(opaque, addr, value, 1, 0); | ||||
| } | ||||
| 
 | ||||
| static void pflash_writew_be(void *opaque, hwaddr addr, | ||||
|                              uint32_t value) | ||||
| { | ||||
|     pflash_t *pfl = opaque; | ||||
| 
 | ||||
|     pflash_write(pfl, addr, value, 2, 1); | ||||
| } | ||||
| 
 | ||||
| static void pflash_writew_le(void *opaque, hwaddr addr, | ||||
|                              uint32_t value) | ||||
| { | ||||
|     pflash_t *pfl = opaque; | ||||
| 
 | ||||
|     pflash_write(pfl, addr, value, 2, 0); | ||||
| } | ||||
| 
 | ||||
| static void pflash_writel_be(void *opaque, hwaddr addr, | ||||
|                              uint32_t value) | ||||
| { | ||||
|     pflash_t *pfl = opaque; | ||||
| 
 | ||||
|     pflash_write(pfl, addr, value, 4, 1); | ||||
| } | ||||
| 
 | ||||
| static void pflash_writel_le(void *opaque, hwaddr addr, | ||||
|                              uint32_t value) | ||||
| { | ||||
|     pflash_t *pfl = opaque; | ||||
| 
 | ||||
|     pflash_write(pfl, addr, value, 4, 0); | ||||
| } | ||||
| 
 | ||||
| static const MemoryRegionOps pflash_cfi01_ops_be = { | ||||
|     .old_mmio = { | ||||
|         .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, }, | ||||
|         .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, }, | ||||
|     }, | ||||
|     .endianness = DEVICE_NATIVE_ENDIAN, | ||||
| }; | ||||
| 
 | ||||
| static const MemoryRegionOps pflash_cfi01_ops_le = { | ||||
|     .old_mmio = { | ||||
|         .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, }, | ||||
|         .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, }, | ||||
|     }, | ||||
| static const MemoryRegionOps pflash_cfi01_ops = { | ||||
|     .read_with_attrs = pflash_mem_read_with_attrs, | ||||
|     .write_with_attrs = pflash_mem_write_with_attrs, | ||||
|     .endianness = DEVICE_NATIVE_ENDIAN, | ||||
| }; | ||||
| 
 | ||||
| @ -773,7 +721,8 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) | ||||
| 
 | ||||
|     memory_region_init_rom_device( | ||||
|         &pfl->mem, OBJECT(dev), | ||||
|         pfl->be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl, | ||||
|         &pflash_cfi01_ops, | ||||
|         pfl, | ||||
|         pfl->name, total_len, &local_err); | ||||
|     if (local_err) { | ||||
|         error_propagate(errp, local_err); | ||||
| @ -925,7 +874,8 @@ static Property pflash_cfi01_properties[] = { | ||||
|     DEFINE_PROP_UINT8("width", struct pflash_t, bank_width, 0), | ||||
|     DEFINE_PROP_UINT8("device-width", struct pflash_t, device_width, 0), | ||||
|     DEFINE_PROP_UINT8("max-device-width", struct pflash_t, max_device_width, 0), | ||||
|     DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0), | ||||
|     DEFINE_PROP_BIT("big-endian", struct pflash_t, features, PFLASH_BE, 0), | ||||
|     DEFINE_PROP_BIT("secure", struct pflash_t, features, PFLASH_SECURE, 0), | ||||
|     DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0), | ||||
|     DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0), | ||||
|     DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0), | ||||
| @ -975,7 +925,7 @@ pflash_t *pflash_cfi01_register(hwaddr base, | ||||
|     qdev_prop_set_uint32(dev, "num-blocks", nb_blocs); | ||||
|     qdev_prop_set_uint64(dev, "sector-length", sector_len); | ||||
|     qdev_prop_set_uint8(dev, "width", bank_width); | ||||
|     qdev_prop_set_uint8(dev, "big-endian", !!be); | ||||
|     qdev_prop_set_bit(dev, "big-endian", !!be); | ||||
|     qdev_prop_set_uint16(dev, "id0", id0); | ||||
|     qdev_prop_set_uint16(dev, "id1", id1); | ||||
|     qdev_prop_set_uint16(dev, "id2", id2); | ||||
|  | ||||
| @ -641,28 +641,3 @@ static void parallel_register_types(void) | ||||
| } | ||||
| 
 | ||||
| type_init(parallel_register_types) | ||||
| 
 | ||||
| static void parallel_init(ISABus *bus, int index, CharDriverState *chr) | ||||
| { | ||||
|     DeviceState *dev; | ||||
|     ISADevice *isadev; | ||||
| 
 | ||||
|     isadev = isa_create(bus, "isa-parallel"); | ||||
|     dev = DEVICE(isadev); | ||||
|     qdev_prop_set_uint32(dev, "index", index); | ||||
|     qdev_prop_set_chr(dev, "chardev", chr); | ||||
|     qdev_init_nofail(dev); | ||||
| } | ||||
| 
 | ||||
| void parallel_hds_isa_init(ISABus *bus, int n) | ||||
| { | ||||
|     int i; | ||||
| 
 | ||||
|     assert(n <= MAX_PARALLEL_PORTS); | ||||
| 
 | ||||
|     for (i = 0; i < n; i++) { | ||||
|         if (parallel_hds[i]) { | ||||
|             parallel_init(bus, i, parallel_hds[i]); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -106,6 +106,7 @@ static void cg3_update_display(void *opaque) | ||||
|     pix = memory_region_get_ram_ptr(&s->vram_mem); | ||||
|     data = (uint32_t *)surface_data(surface); | ||||
| 
 | ||||
|     memory_region_sync_dirty_bitmap(&s->vram_mem); | ||||
|     for (y = 0; y < height; y++) { | ||||
|         int update = s->full_update; | ||||
| 
 | ||||
| @ -309,6 +310,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp) | ||||
| 
 | ||||
|     memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size, | ||||
|                            &error_abort); | ||||
|     memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA); | ||||
|     vmstate_register_ram_global(&s->vram_mem); | ||||
|     sysbus_init_mmio(sbd, &s->vram_mem); | ||||
| 
 | ||||
|  | ||||
| @ -1109,6 +1109,12 @@ static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void exynos4210_fimd_invalidate(void *opaque) | ||||
| { | ||||
|     Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; | ||||
|     s->invalidate = true; | ||||
| } | ||||
| 
 | ||||
| /* Updates specified window's MemorySection based on values of WINCON,
 | ||||
|  * VIDOSDA, VIDOSDB, VIDWADDx and SHADOWCON registers */ | ||||
| static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win) | ||||
| @ -1136,7 +1142,11 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win) | ||||
|     /* TODO: add .exit and unref the region there.  Not needed yet since sysbus
 | ||||
|      * does not support hot-unplug. | ||||
|      */ | ||||
|     memory_region_unref(w->mem_section.mr); | ||||
|     if (w->mem_section.mr) { | ||||
|         memory_region_set_log(w->mem_section.mr, false, DIRTY_MEMORY_VGA); | ||||
|         memory_region_unref(w->mem_section.mr); | ||||
|     } | ||||
| 
 | ||||
|     w->mem_section = memory_region_find(sysbus_address_space(sbd), | ||||
|                                         fb_start_addr, w->fb_len); | ||||
|     assert(w->mem_section.mr); | ||||
| @ -1162,6 +1172,8 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win) | ||||
|         cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0); | ||||
|         goto error_return; | ||||
|     } | ||||
|     memory_region_set_log(w->mem_section.mr, true, DIRTY_MEMORY_VGA); | ||||
|     exynos4210_fimd_invalidate(s); | ||||
|     return; | ||||
| 
 | ||||
| error_return: | ||||
| @ -1224,12 +1236,6 @@ static void exynos4210_fimd_update_irq(Exynos4210fimdState *s) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void exynos4210_fimd_invalidate(void *opaque) | ||||
| { | ||||
|     Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; | ||||
|     s->invalidate = true; | ||||
| } | ||||
| 
 | ||||
| static void exynos4210_update_resolution(Exynos4210fimdState *s) | ||||
| { | ||||
|     DisplaySurface *surface = qemu_console_surface(s->console); | ||||
|  | ||||
| @ -63,6 +63,10 @@ void framebuffer_update_display( | ||||
|     assert(mem_section.offset_within_address_space == base); | ||||
| 
 | ||||
|     memory_region_sync_dirty_bitmap(mem); | ||||
|     if (!memory_region_is_logging(mem, DIRTY_MEMORY_VGA)) { | ||||
|         invalidate = true; | ||||
|     } | ||||
| 
 | ||||
|     src_base = cpu_physical_memory_map(base, &src_len, 0); | ||||
|     /* If we can't map the framebuffer then bail.  We could try harder,
 | ||||
|        but it's not really worth it as dirty flag tracking will probably | ||||
|  | ||||
| @ -260,6 +260,7 @@ static void g364fb_update_display(void *opaque) | ||||
|         qemu_console_resize(s->con, s->width, s->height); | ||||
|     } | ||||
| 
 | ||||
|     memory_region_sync_dirty_bitmap(&s->mem_vram); | ||||
|     if (s->ctla & CTLA_FORCE_BLANK) { | ||||
|         g364fb_draw_blank(s); | ||||
|     } else if (s->depth == 8) { | ||||
| @ -489,7 +490,7 @@ static void g364fb_init(DeviceState *dev, G364State *s) | ||||
|     memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram", | ||||
|                                s->vram_size, s->vram); | ||||
|     vmstate_register_ram(&s->mem_vram, dev); | ||||
|     memory_region_set_coalescing(&s->mem_vram); | ||||
|     memory_region_set_log(&s->mem_vram, true, DIRTY_MEMORY_VGA); | ||||
| } | ||||
| 
 | ||||
| #define TYPE_G364 "sysbus-g364" | ||||
|  | ||||
| @ -1322,6 +1322,7 @@ static void sm501_draw_crt(SM501State * s) | ||||
|     } | ||||
| 
 | ||||
|     /* draw each line according to conditions */ | ||||
|     memory_region_sync_dirty_bitmap(&s->local_mem_region); | ||||
|     for (y = 0; y < height; y++) { | ||||
| 	int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0; | ||||
| 	int update = full_update || update_hwc; | ||||
| @ -1412,6 +1413,7 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base, | ||||
|     memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local", | ||||
|                            local_mem_bytes, &error_abort); | ||||
|     vmstate_register_ram_global(&s->local_mem_region); | ||||
|     memory_region_set_log(&s->local_mem_region, true, DIRTY_MEMORY_VGA); | ||||
|     s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region); | ||||
|     memory_region_add_subregion(address_space_mem, base, &s->local_mem_region); | ||||
| 
 | ||||
|  | ||||
| @ -353,6 +353,7 @@ static void tcx_update_display(void *opaque) | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     memory_region_sync_dirty_bitmap(&ts->vram_mem); | ||||
|     for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE) { | ||||
|         if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE, | ||||
|                                     DIRTY_MEMORY_VGA)) { | ||||
| @ -446,6 +447,7 @@ static void tcx24_update_display(void *opaque) | ||||
|     dd = surface_stride(surface); | ||||
|     ds = 1024; | ||||
| 
 | ||||
|     memory_region_sync_dirty_bitmap(&ts->vram_mem); | ||||
|     for (y = 0; y < ts->height; page += TARGET_PAGE_SIZE, | ||||
|             page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) { | ||||
|         if (tcx24_check_dirty(ts, page, page24, cpage)) { | ||||
| @ -1006,6 +1008,7 @@ static void tcx_realizefn(DeviceState *dev, Error **errp) | ||||
|     memory_region_init_ram(&s->vram_mem, OBJECT(s), "tcx.vram", | ||||
|                            s->vram_size * (1 + 4 + 4), &error_abort); | ||||
|     vmstate_register_ram_global(&s->vram_mem); | ||||
|     memory_region_set_log(&s->vram_mem, true, DIRTY_MEMORY_VGA); | ||||
|     vram_base = memory_region_get_ram_ptr(&s->vram_mem); | ||||
| 
 | ||||
|     /* 10/ROM : FCode ROM */ | ||||
|  | ||||
| @ -1124,7 +1124,7 @@ static void vmsvga_update_display(void *opaque) | ||||
|      * Is it more efficient to look at vram VGA-dirty bits or wait | ||||
|      * for the driver to issue SVGA_CMD_UPDATE? | ||||
|      */ | ||||
|     if (memory_region_is_logging(&s->vga.vram)) { | ||||
|     if (memory_region_is_logging(&s->vga.vram, DIRTY_MEMORY_VGA)) { | ||||
|         vga_sync_dirty_bitmap(&s->vga); | ||||
|         dirty = memory_region_get_dirty(&s->vga.vram, 0, | ||||
|             surface_stride(surface) * surface_height(surface), | ||||
|  | ||||
							
								
								
									
										21
									
								
								hw/i386/pc.c
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								hw/i386/pc.c
									
									
									
									
									
								
							| @ -164,27 +164,6 @@ uint64_t cpu_get_tsc(CPUX86State *env) | ||||
|     return cpu_get_ticks(); | ||||
| } | ||||
| 
 | ||||
| /* SMM support */ | ||||
| 
 | ||||
| static cpu_set_smm_t smm_set; | ||||
| static void *smm_arg; | ||||
| 
 | ||||
| void cpu_smm_register(cpu_set_smm_t callback, void *arg) | ||||
| { | ||||
|     assert(smm_set == NULL); | ||||
|     assert(smm_arg == NULL); | ||||
|     smm_set = callback; | ||||
|     smm_arg = arg; | ||||
| } | ||||
| 
 | ||||
| void cpu_smm_update(CPUX86State *env) | ||||
| { | ||||
|     if (smm_set && smm_arg && CPU(x86_env_get_cpu(env)) == first_cpu) { | ||||
|         smm_set(!!(env->hflags & HF_SMM_MASK), smm_arg); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* IRQ handling */ | ||||
| int cpu_get_pic_interrupt(CPUX86State *env) | ||||
| { | ||||
|  | ||||
| @ -21,6 +21,7 @@ | ||||
| #include "hw/sysbus.h" | ||||
| #include "sysemu/sysemu.h" | ||||
| #include "hw/isa/isa.h" | ||||
| #include "hw/i386/pc.h" | ||||
| 
 | ||||
| static ISABus *isabus; | ||||
| 
 | ||||
| @ -267,3 +268,28 @@ MemoryRegion *isa_address_space_io(ISADevice *dev) | ||||
| } | ||||
| 
 | ||||
| type_init(isabus_register_types) | ||||
| 
 | ||||
| static void parallel_init(ISABus *bus, int index, CharDriverState *chr) | ||||
| { | ||||
|     DeviceState *dev; | ||||
|     ISADevice *isadev; | ||||
| 
 | ||||
|     isadev = isa_create(bus, "isa-parallel"); | ||||
|     dev = DEVICE(isadev); | ||||
|     qdev_prop_set_uint32(dev, "index", index); | ||||
|     qdev_prop_set_chr(dev, "chardev", chr); | ||||
|     qdev_init_nofail(dev); | ||||
| } | ||||
| 
 | ||||
| void parallel_hds_isa_init(ISABus *bus, int n) | ||||
| { | ||||
|     int i; | ||||
| 
 | ||||
|     assert(n <= MAX_PARALLEL_PORTS); | ||||
| 
 | ||||
|     for (i = 0; i < n; i++) { | ||||
|         if (parallel_hds[i]) { | ||||
|             parallel_init(bus, i, parallel_hds[i]); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -407,12 +407,28 @@ static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rbca_old) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* config:GEN_PMCON* */ | ||||
| static void | ||||
| ich9_lpc_pmcon_update(ICH9LPCState *lpc) | ||||
| { | ||||
|     uint16_t gen_pmcon_1 = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1); | ||||
|     uint16_t wmask; | ||||
| 
 | ||||
|     if (gen_pmcon_1 & ICH9_LPC_GEN_PMCON_1_SMI_LOCK) { | ||||
|         wmask = pci_get_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1); | ||||
|         wmask &= ~ICH9_LPC_GEN_PMCON_1_SMI_LOCK; | ||||
|         pci_set_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1, wmask); | ||||
|         lpc->pm.smi_en_wmask &= ~1; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static int ich9_lpc_post_load(void *opaque, int version_id) | ||||
| { | ||||
|     ICH9LPCState *lpc = opaque; | ||||
| 
 | ||||
|     ich9_lpc_pmbase_update(lpc); | ||||
|     ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */); | ||||
|     ich9_lpc_pmcon_update(lpc); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| @ -435,6 +451,9 @@ static void ich9_lpc_config_write(PCIDevice *d, | ||||
|     if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) { | ||||
|         pci_bus_fire_intx_routing_notifier(lpc->d.bus); | ||||
|     } | ||||
|     if (ranges_overlap(addr, len, ICH9_LPC_GEN_PMCON_1, 8)) { | ||||
|         ich9_lpc_pmcon_update(lpc); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void ich9_lpc_reset(DeviceState *qdev) | ||||
|  | ||||
| @ -31,26 +31,6 @@ | ||||
| #include "sysemu/sysemu.h" | ||||
| #include "hw/pci-host/pam.h" | ||||
| 
 | ||||
| void smram_update(MemoryRegion *smram_region, uint8_t smram, | ||||
|                   uint8_t smm_enabled) | ||||
| { | ||||
|     bool smram_enabled; | ||||
| 
 | ||||
|     smram_enabled = ((smm_enabled && (smram & SMRAM_G_SMRAME)) || | ||||
|                         (smram & SMRAM_D_OPEN)); | ||||
|     memory_region_set_enabled(smram_region, !smram_enabled); | ||||
| } | ||||
| 
 | ||||
| void smram_set_smm(uint8_t *host_smm_enabled, int smm, uint8_t smram, | ||||
|                    MemoryRegion *smram_region) | ||||
| { | ||||
|     uint8_t smm_enabled = (smm != 0); | ||||
|     if (*host_smm_enabled != smm_enabled) { | ||||
|         *host_smm_enabled = smm_enabled; | ||||
|         smram_update(smram_region, smram, *host_smm_enabled); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void init_pam(DeviceState *dev, MemoryRegion *ram_memory, | ||||
|               MemoryRegion *system_memory, MemoryRegion *pci_address_space, | ||||
|               PAMMemoryRegion *mem, uint32_t start, uint32_t size) | ||||
|  | ||||
| @ -105,7 +105,7 @@ struct PCII440FXState { | ||||
|     MemoryRegion *ram_memory; | ||||
|     PAMMemoryRegion pam_regions[13]; | ||||
|     MemoryRegion smram_region; | ||||
|     uint8_t smm_enabled; | ||||
|     MemoryRegion smram, low_smram; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| @ -138,18 +138,10 @@ static void i440fx_update_memory_mappings(PCII440FXState *d) | ||||
|         pam_update(&d->pam_regions[i], i, | ||||
|                    pd->config[I440FX_PAM + ((i + 1) / 2)]); | ||||
|     } | ||||
|     smram_update(&d->smram_region, pd->config[I440FX_SMRAM], d->smm_enabled); | ||||
|     memory_region_transaction_commit(); | ||||
| } | ||||
| 
 | ||||
| static void i440fx_set_smm(int val, void *arg) | ||||
| { | ||||
|     PCII440FXState *d = arg; | ||||
|     PCIDevice *pd = PCI_DEVICE(d); | ||||
| 
 | ||||
|     memory_region_transaction_begin(); | ||||
|     smram_set_smm(&d->smm_enabled, val, pd->config[I440FX_SMRAM], | ||||
|                   &d->smram_region); | ||||
|     memory_region_set_enabled(&d->smram_region, | ||||
|                               !(pd->config[I440FX_SMRAM] & SMRAM_D_OPEN)); | ||||
|     memory_region_set_enabled(&d->smram, | ||||
|                               pd->config[I440FX_SMRAM] & SMRAM_G_SMRAME); | ||||
|     memory_region_transaction_commit(); | ||||
| } | ||||
| 
 | ||||
| @ -172,12 +164,13 @@ static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id) | ||||
|     PCII440FXState *d = opaque; | ||||
|     PCIDevice *pd = PCI_DEVICE(d); | ||||
|     int ret, i; | ||||
|     uint8_t smm_enabled; | ||||
| 
 | ||||
|     ret = pci_device_load(pd, f); | ||||
|     if (ret < 0) | ||||
|         return ret; | ||||
|     i440fx_update_memory_mappings(d); | ||||
|     qemu_get_8s(f, &d->smm_enabled); | ||||
|     qemu_get_8s(f, &smm_enabled); | ||||
| 
 | ||||
|     if (version_id == 2) { | ||||
|         for (i = 0; i < PIIX_NUM_PIRQS; i++) { | ||||
| @ -205,7 +198,10 @@ static const VMStateDescription vmstate_i440fx = { | ||||
|     .post_load = i440fx_post_load, | ||||
|     .fields = (VMStateField[]) { | ||||
|         VMSTATE_PCI_DEVICE(parent_obj, PCII440FXState), | ||||
|         VMSTATE_UINT8(smm_enabled, PCII440FXState), | ||||
|         /* Used to be smm_enabled, which was basically always zero because
 | ||||
|          * SeaBIOS hardly uses SMM.  SMRAM is now handled by CPU code. | ||||
|          */ | ||||
|         VMSTATE_UNUSED(1), | ||||
|         VMSTATE_END_OF_LIST() | ||||
|     } | ||||
| }; | ||||
| @ -297,11 +293,7 @@ static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) | ||||
| 
 | ||||
| static void i440fx_realize(PCIDevice *dev, Error **errp) | ||||
| { | ||||
|     PCII440FXState *d = I440FX_PCI_DEVICE(dev); | ||||
| 
 | ||||
|     dev->config[I440FX_SMRAM] = 0x02; | ||||
| 
 | ||||
|     cpu_smm_register(&i440fx_set_smm, d); | ||||
| } | ||||
| 
 | ||||
| PCIBus *i440fx_init(PCII440FXState **pi440fx_state, | ||||
| @ -346,11 +338,23 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, | ||||
|     pc_pci_as_mapping_init(OBJECT(f), f->system_memory, | ||||
|                            f->pci_address_space); | ||||
| 
 | ||||
|     /* if *disabled* show SMRAM to all CPUs */ | ||||
|     memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region", | ||||
|                              f->pci_address_space, 0xa0000, 0x20000); | ||||
|     memory_region_add_subregion_overlap(f->system_memory, 0xa0000, | ||||
|                                         &f->smram_region, 1); | ||||
|     memory_region_set_enabled(&f->smram_region, false); | ||||
|     memory_region_set_enabled(&f->smram_region, true); | ||||
| 
 | ||||
|     /* smram, as seen by SMM CPUs */ | ||||
|     memory_region_init(&f->smram, OBJECT(d), "smram", 1ull << 32); | ||||
|     memory_region_set_enabled(&f->smram, true); | ||||
|     memory_region_init_alias(&f->low_smram, OBJECT(d), "smram-low", | ||||
|                              f->ram_memory, 0xa0000, 0x20000); | ||||
|     memory_region_set_enabled(&f->low_smram, true); | ||||
|     memory_region_add_subregion(&f->smram, 0xa0000, &f->low_smram); | ||||
|     object_property_add_const_link(qdev_get_machine(), "smram", | ||||
|                                    OBJECT(&f->smram), &error_abort); | ||||
| 
 | ||||
|     init_pam(dev, f->ram_memory, f->system_memory, f->pci_address_space, | ||||
|              &f->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE); | ||||
|     for (i = 0; i < 12; ++i) { | ||||
|  | ||||
| @ -198,6 +198,28 @@ static const TypeInfo q35_host_info = { | ||||
|  * MCH D0:F0 | ||||
|  */ | ||||
| 
 | ||||
| static uint64_t tseg_blackhole_read(void *ptr, hwaddr reg, unsigned size) | ||||
| { | ||||
|     return 0xffffffff; | ||||
| } | ||||
| 
 | ||||
| static void tseg_blackhole_write(void *opaque, hwaddr addr, uint64_t val, | ||||
|                                  unsigned width) | ||||
| { | ||||
|     /* nothing */ | ||||
| } | ||||
| 
 | ||||
| static const MemoryRegionOps tseg_blackhole_ops = { | ||||
|     .read = tseg_blackhole_read, | ||||
|     .write = tseg_blackhole_write, | ||||
|     .endianness = DEVICE_NATIVE_ENDIAN, | ||||
|     .valid.min_access_size = 1, | ||||
|     .valid.max_access_size = 4, | ||||
|     .impl.min_access_size = 4, | ||||
|     .impl.max_access_size = 4, | ||||
|     .endianness = DEVICE_LITTLE_ENDIAN, | ||||
| }; | ||||
| 
 | ||||
| /* PCIe MMCFG */ | ||||
| static void mch_update_pciexbar(MCHPCIState *mch) | ||||
| { | ||||
| @ -266,21 +288,70 @@ static void mch_update_pam(MCHPCIState *mch) | ||||
| static void mch_update_smram(MCHPCIState *mch) | ||||
| { | ||||
|     PCIDevice *pd = PCI_DEVICE(mch); | ||||
|     bool h_smrame = (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME); | ||||
|     uint32_t tseg_size; | ||||
| 
 | ||||
|     /* implement SMRAM.D_LCK */ | ||||
|     if (pd->config[MCH_HOST_BRIDGE_SMRAM] & MCH_HOST_BRIDGE_SMRAM_D_LCK) { | ||||
|         pd->config[MCH_HOST_BRIDGE_SMRAM] &= ~MCH_HOST_BRIDGE_SMRAM_D_OPEN; | ||||
|         pd->wmask[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_WMASK_LCK; | ||||
|         pd->wmask[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_WMASK_LCK; | ||||
|     } | ||||
| 
 | ||||
|     memory_region_transaction_begin(); | ||||
|     smram_update(&mch->smram_region, pd->config[MCH_HOST_BRIDGE_SMRAM], | ||||
|                     mch->smm_enabled); | ||||
|     memory_region_transaction_commit(); | ||||
| } | ||||
| 
 | ||||
| static void mch_set_smm(int smm, void *arg) | ||||
| { | ||||
|     MCHPCIState *mch = arg; | ||||
|     PCIDevice *pd = PCI_DEVICE(mch); | ||||
|     if (pd->config[MCH_HOST_BRIDGE_SMRAM] & SMRAM_D_OPEN) { | ||||
|         /* Hide (!) low SMRAM if H_SMRAME = 1 */ | ||||
|         memory_region_set_enabled(&mch->smram_region, h_smrame); | ||||
|         /* Show high SMRAM if H_SMRAME = 1 */ | ||||
|         memory_region_set_enabled(&mch->open_high_smram, h_smrame); | ||||
|     } else { | ||||
|         /* Hide high SMRAM and low SMRAM */ | ||||
|         memory_region_set_enabled(&mch->smram_region, true); | ||||
|         memory_region_set_enabled(&mch->open_high_smram, false); | ||||
|     } | ||||
| 
 | ||||
|     if (pd->config[MCH_HOST_BRIDGE_SMRAM] & SMRAM_G_SMRAME) { | ||||
|         memory_region_set_enabled(&mch->low_smram, !h_smrame); | ||||
|         memory_region_set_enabled(&mch->high_smram, h_smrame); | ||||
|     } else { | ||||
|         memory_region_set_enabled(&mch->low_smram, false); | ||||
|         memory_region_set_enabled(&mch->high_smram, false); | ||||
|     } | ||||
| 
 | ||||
|     if (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & MCH_HOST_BRIDGE_ESMRAMC_T_EN) { | ||||
|         switch (pd->config[MCH_HOST_BRIDGE_ESMRAMC] & | ||||
|                 MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) { | ||||
|         case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB: | ||||
|             tseg_size = 1024 * 1024; | ||||
|             break; | ||||
|         case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB: | ||||
|             tseg_size = 1024 * 1024 * 2; | ||||
|             break; | ||||
|         case MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_8MB: | ||||
|             tseg_size = 1024 * 1024 * 8; | ||||
|             break; | ||||
|         default: | ||||
|             tseg_size = 0; | ||||
|             break; | ||||
|         } | ||||
|     } else { | ||||
|         tseg_size = 0; | ||||
|     } | ||||
|     memory_region_del_subregion(mch->system_memory, &mch->tseg_blackhole); | ||||
|     memory_region_set_enabled(&mch->tseg_blackhole, tseg_size); | ||||
|     memory_region_set_size(&mch->tseg_blackhole, tseg_size); | ||||
|     memory_region_add_subregion_overlap(mch->system_memory, | ||||
|                                         mch->below_4g_mem_size - tseg_size, | ||||
|                                         &mch->tseg_blackhole, 1); | ||||
| 
 | ||||
|     memory_region_set_enabled(&mch->tseg_window, tseg_size); | ||||
|     memory_region_set_size(&mch->tseg_window, tseg_size); | ||||
|     memory_region_set_address(&mch->tseg_window, | ||||
|                               mch->below_4g_mem_size - tseg_size); | ||||
|     memory_region_set_alias_offset(&mch->tseg_window, | ||||
|                                    mch->below_4g_mem_size - tseg_size); | ||||
| 
 | ||||
|     memory_region_transaction_begin(); | ||||
|     smram_set_smm(&mch->smm_enabled, smm, pd->config[MCH_HOST_BRIDGE_SMRAM], | ||||
|                     &mch->smram_region); | ||||
|     memory_region_transaction_commit(); | ||||
| } | ||||
| 
 | ||||
| @ -289,7 +360,6 @@ static void mch_write_config(PCIDevice *d, | ||||
| { | ||||
|     MCHPCIState *mch = MCH_PCI_DEVICE(d); | ||||
| 
 | ||||
|     /* XXX: implement SMRAM.D_LOCK */ | ||||
|     pci_default_write_config(d, address, val, len); | ||||
| 
 | ||||
|     if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PAM0, | ||||
| @ -329,7 +399,10 @@ static const VMStateDescription vmstate_mch = { | ||||
|     .post_load = mch_post_load, | ||||
|     .fields = (VMStateField[]) { | ||||
|         VMSTATE_PCI_DEVICE(parent_obj, MCHPCIState), | ||||
|         VMSTATE_UINT8(smm_enabled, MCHPCIState), | ||||
|         /* Used to be smm_enabled, which was basically always zero because
 | ||||
|          * SeaBIOS hardly uses SMM.  SMRAM is now handled by CPU code. | ||||
|          */ | ||||
|         VMSTATE_UNUSED(1), | ||||
|         VMSTATE_END_OF_LIST() | ||||
|     } | ||||
| }; | ||||
| @ -343,6 +416,9 @@ static void mch_reset(DeviceState *qdev) | ||||
|                  MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT); | ||||
| 
 | ||||
|     d->config[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT; | ||||
|     d->config[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_DEFAULT; | ||||
|     d->wmask[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_WMASK; | ||||
|     d->wmask[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_WMASK; | ||||
| 
 | ||||
|     mch_update(mch); | ||||
| } | ||||
| @ -399,13 +475,47 @@ static void mch_realize(PCIDevice *d, Error **errp) | ||||
|     pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory, | ||||
|                            mch->pci_address_space); | ||||
| 
 | ||||
|     /* smram */ | ||||
|     cpu_smm_register(&mch_set_smm, mch); | ||||
|     /* if *disabled* show SMRAM to all CPUs */ | ||||
|     memory_region_init_alias(&mch->smram_region, OBJECT(mch), "smram-region", | ||||
|                              mch->pci_address_space, 0xa0000, 0x20000); | ||||
|     memory_region_add_subregion_overlap(mch->system_memory, 0xa0000, | ||||
|                                         &mch->smram_region, 1); | ||||
|     memory_region_set_enabled(&mch->smram_region, false); | ||||
|     memory_region_set_enabled(&mch->smram_region, true); | ||||
| 
 | ||||
|     memory_region_init_alias(&mch->open_high_smram, OBJECT(mch), "smram-open-high", | ||||
|                              mch->ram_memory, 0xa0000, 0x20000); | ||||
|     memory_region_add_subregion_overlap(mch->system_memory, 0xfeda0000, | ||||
|                                         &mch->open_high_smram, 1); | ||||
|     memory_region_set_enabled(&mch->open_high_smram, false); | ||||
| 
 | ||||
|     /* smram, as seen by SMM CPUs */ | ||||
|     memory_region_init(&mch->smram, OBJECT(mch), "smram", 1ull << 32); | ||||
|     memory_region_set_enabled(&mch->smram, true); | ||||
|     memory_region_init_alias(&mch->low_smram, OBJECT(mch), "smram-low", | ||||
|                              mch->ram_memory, 0xa0000, 0x20000); | ||||
|     memory_region_set_enabled(&mch->low_smram, true); | ||||
|     memory_region_add_subregion(&mch->smram, 0xa0000, &mch->low_smram); | ||||
|     memory_region_init_alias(&mch->high_smram, OBJECT(mch), "smram-high", | ||||
|                              mch->ram_memory, 0xa0000, 0x20000); | ||||
|     memory_region_set_enabled(&mch->high_smram, true); | ||||
|     memory_region_add_subregion(&mch->smram, 0xfeda0000, &mch->high_smram); | ||||
| 
 | ||||
|     memory_region_init_io(&mch->tseg_blackhole, OBJECT(mch), | ||||
|                           &tseg_blackhole_ops, NULL, | ||||
|                           "tseg-blackhole", 0); | ||||
|     memory_region_set_enabled(&mch->tseg_blackhole, false); | ||||
|     memory_region_add_subregion_overlap(mch->system_memory, | ||||
|                                         mch->below_4g_mem_size, | ||||
|                                         &mch->tseg_blackhole, 1); | ||||
| 
 | ||||
|     memory_region_init_alias(&mch->tseg_window, OBJECT(mch), "tseg-window", | ||||
|                              mch->ram_memory, mch->below_4g_mem_size, 0); | ||||
|     memory_region_set_enabled(&mch->tseg_window, false); | ||||
|     memory_region_add_subregion(&mch->smram, mch->below_4g_mem_size, | ||||
|                                 &mch->tseg_window); | ||||
|     object_property_add_const_link(qdev_get_machine(), "smram", | ||||
|                                    OBJECT(&mch->smram), &error_abort); | ||||
| 
 | ||||
|     init_pam(DEVICE(mch), mch->ram_memory, mch->system_memory, | ||||
|              mch->pci_address_space, &mch->pam_regions[0], | ||||
|              PAM_BIOS_BASE, PAM_BIOS_SIZE); | ||||
|  | ||||
| @ -42,7 +42,7 @@ static void *vring_map(MemoryRegion **mr, hwaddr phys, hwaddr len, | ||||
|     } | ||||
| 
 | ||||
|     /* Ignore regions with dirty logging, we cannot mark them dirty */ | ||||
|     if (memory_region_is_logging(section.mr)) { | ||||
|     if (memory_region_get_dirty_log_mask(section.mr)) { | ||||
|         goto out; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -416,7 +416,8 @@ static void vhost_set_memory(MemoryListener *listener, | ||||
|                                          memory_listener); | ||||
|     hwaddr start_addr = section->offset_within_address_space; | ||||
|     ram_addr_t size = int128_get64(section->size); | ||||
|     bool log_dirty = memory_region_is_logging(section->mr); | ||||
|     bool log_dirty = | ||||
|         memory_region_get_dirty_log_mask(section->mr) & ~(1 << DIRTY_MEMORY_MIGRATION); | ||||
|     int s = offsetof(struct vhost_memory, regions) + | ||||
|         (dev->mem->nregions + 1) * sizeof dev->mem->regions[0]; | ||||
|     void *ram; | ||||
| @ -675,13 +676,15 @@ static void vhost_log_global_stop(MemoryListener *listener) | ||||
| } | ||||
| 
 | ||||
| static void vhost_log_start(MemoryListener *listener, | ||||
|                             MemoryRegionSection *section) | ||||
|                             MemoryRegionSection *section, | ||||
|                             int old, int new) | ||||
| { | ||||
|     /* FIXME: implement */ | ||||
| } | ||||
| 
 | ||||
| static void vhost_log_stop(MemoryListener *listener, | ||||
|                            MemoryRegionSection *section) | ||||
|                            MemoryRegionSection *section, | ||||
|                            int old, int new) | ||||
| { | ||||
|     /* FIXME: implement */ | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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); | ||||
| @ -591,11 +593,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, 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, in which the DIRTY_MEMORY_* constants | ||||
|  * are the bit indices. | ||||
|  * | ||||
|  * @mr: the memory region being queried | ||||
|  */ | ||||
| bool memory_region_is_logging(MemoryRegion *mr); | ||||
| uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr); | ||||
| 
 | ||||
| /**
 | ||||
|  * memory_region_is_rom: check whether a memory region is ROM | ||||
| @ -647,8 +661,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); | ||||
| 
 | ||||
|  | ||||
| @ -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) | ||||
| @ -56,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) | ||||
| { | ||||
| @ -68,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, | ||||
| @ -86,44 +89,52 @@ 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_get_clean(start, length, DIRTY_MEMORY_VGA); | ||||
|     bool code = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_CODE); | ||||
|     bool migration = | ||||
|         cpu_physical_memory_get_clean(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, | ||||
|                                                       unsigned client) | ||||
| { | ||||
|     assert(client < DIRTY_MEMORY_NUM); | ||||
|     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); | ||||
|     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, | ||||
|                                                        ram_addr_t length) | ||||
|                                                        ram_addr_t length, | ||||
|                                                        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; | ||||
|     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_atomic(d[DIRTY_MEMORY_MIGRATION], page, end - page); | ||||
|     } | ||||
|     if (unlikely(mask & (1 << DIRTY_MEMORY_VGA))) { | ||||
|         bitmap_set_atomic(d[DIRTY_MEMORY_VGA], page, end - page); | ||||
|     } | ||||
|     if (unlikely(mask & (1 << DIRTY_MEMORY_CODE))) { | ||||
|         bitmap_set_atomic(d[DIRTY_MEMORY_CODE], page, end - page); | ||||
|     } | ||||
|     xen_modified_memory(start, length); | ||||
| } | ||||
| 
 | ||||
| @ -149,14 +160,18 @@ 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; | ||||
|                 ram_list.dirty_memory[DIRTY_MEMORY_CODE][page + k] |= temp; | ||||
|                 atomic_or(&d[DIRTY_MEMORY_MIGRATION][page + k], temp); | ||||
|                 atomic_or(&d[DIRTY_MEMORY_VGA][page + k], temp); | ||||
|                 if (tcg_enabled()) { | ||||
|                     atomic_or(&d[DIRTY_MEMORY_CODE][page + k], temp); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         xen_modified_memory(start, pages); | ||||
|         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. | ||||
| @ -171,7 +186,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); | ||||
|                                        TARGET_PAGE_SIZE * hpratio, clients); | ||||
|                 } while (c != 0); | ||||
|             } | ||||
|         } | ||||
| @ -179,29 +194,60 @@ 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, | ||||
|                                                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 bits = atomic_xchg(&src[k], 0); | ||||
|                 unsigned long new_dirty; | ||||
|                 new_dirty = ~dest[k]; | ||||
|                 dest[k] |= bits; | ||||
|                 new_dirty &= bits; | ||||
|                 num_dirty += ctpopl(new_dirty); | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) { | ||||
|             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++; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return num_dirty; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| @ -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 */ | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
|  | ||||
| @ -86,10 +86,6 @@ 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 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); | ||||
|  | ||||
| @ -52,9 +52,10 @@ typedef struct MCHPCIState { | ||||
|     MemoryRegion *system_memory; | ||||
|     MemoryRegion *address_space_io; | ||||
|     PAMMemoryRegion pam_regions[13]; | ||||
|     MemoryRegion smram_region; | ||||
|     MemoryRegion smram_region, open_high_smram; | ||||
|     MemoryRegion smram, low_smram, high_smram; | ||||
|     MemoryRegion tseg_blackhole, tseg_window; | ||||
|     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; | ||||
| @ -127,8 +128,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_DEFAULT          ((uint8_t)0x2) | ||||
| #define MCH_HOST_BRIDGE_SMRAM_SIZE             2 | ||||
| #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,18 +139,36 @@ 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_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_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 << 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)) | ||||
| #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) | ||||
| #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) | ||||
| #define MCH_HOST_BRIDGE_ESMRAMC_WMASK_LCK     0 | ||||
| 
 | ||||
| /* D1:F0 PCIE* port*/ | ||||
| #define MCH_PCIE_DEV                           1 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -39,7 +39,9 @@ | ||||
|  * 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_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 | ||||
|  */ | ||||
| 
 | ||||
| @ -226,7 +228,9 @@ 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, | ||||
|  | ||||
| @ -16,6 +16,7 @@ | ||||
| #include <assert.h> | ||||
| 
 | ||||
| #include "host-utils.h" | ||||
| #include "atomic.h" | ||||
| 
 | ||||
| #define BITS_PER_BYTE           CHAR_BIT | ||||
| #define BITS_PER_LONG           (sizeof (unsigned long) * BITS_PER_BYTE) | ||||
| @ -38,6 +39,19 @@ static inline void set_bit(long nr, unsigned long *addr) | ||||
|     *p  |= mask; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * 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 | ||||
|  | ||||
| @ -1289,6 +1289,24 @@ void object_property_add_alias(Object *obj, const char *name, | ||||
|                                Object *target_obj, const char *target_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<TYPE> 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 | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										85
									
								
								kvm-all.c
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								kvm-all.c
									
									
									
									
									
								
							| @ -83,7 +83,6 @@ struct KVMState | ||||
|     struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; | ||||
|     bool coalesced_flush_in_progress; | ||||
|     int broken_set_mem_region; | ||||
|     int migration_log; | ||||
|     int vcpu_events; | ||||
|     int robust_singlestep; | ||||
|     int debugregs; | ||||
| @ -234,9 +233,6 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) | ||||
|     mem.guest_phys_addr = slot->start_addr; | ||||
|     mem.userspace_addr = (unsigned long)slot->ram; | ||||
|     mem.flags = slot->flags; | ||||
|     if (s->migration_log) { | ||||
|         mem.flags |= KVM_MEM_LOG_DIRTY_PAGES; | ||||
|     } | ||||
| 
 | ||||
|     if (slot->memory_size && mem.flags & KVM_MEM_READONLY) { | ||||
|         /* Set the slot size to 0 before setting the slot to the desired
 | ||||
| @ -317,10 +313,6 @@ static int kvm_slot_dirty_pages_log_change(KVMSlot *mem, bool log_dirty) | ||||
|     mem->flags = flags; | ||||
| 
 | ||||
|     /* If nothing changed effectively, no need to issue ioctl */ | ||||
|     if (s->migration_log) { | ||||
|         flags |= KVM_MEM_LOG_DIRTY_PAGES; | ||||
|     } | ||||
| 
 | ||||
|     if (flags == old_flags) { | ||||
|         return 0; | ||||
|     } | ||||
| @ -335,19 +327,22 @@ static int kvm_dirty_pages_log_change(hwaddr phys_addr, | ||||
|     KVMSlot *mem = kvm_lookup_matching_slot(s, phys_addr, phys_addr + size); | ||||
| 
 | ||||
|     if (mem == NULL)  { | ||||
|         fprintf(stderr, "BUG: %s: invalid parameters " TARGET_FMT_plx "-" | ||||
|                 TARGET_FMT_plx "\n", __func__, phys_addr, | ||||
|                 (hwaddr)(phys_addr + size - 1)); | ||||
|         return -EINVAL; | ||||
|         return 0; | ||||
|     } else { | ||||
|         return kvm_slot_dirty_pages_log_change(mem, log_dirty); | ||||
|     } | ||||
|     return kvm_slot_dirty_pages_log_change(mem, log_dirty); | ||||
| } | ||||
| 
 | ||||
| static void kvm_log_start(MemoryListener *listener, | ||||
|                           MemoryRegionSection *section) | ||||
|                           MemoryRegionSection *section, | ||||
|                           int old, int new) | ||||
| { | ||||
|     int r; | ||||
| 
 | ||||
|     if (old != 0) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     r = kvm_dirty_pages_log_change(section->offset_within_address_space, | ||||
|                                    int128_get64(section->size), true); | ||||
|     if (r < 0) { | ||||
| @ -356,10 +351,15 @@ static void kvm_log_start(MemoryListener *listener, | ||||
| } | ||||
| 
 | ||||
| static void kvm_log_stop(MemoryListener *listener, | ||||
|                           MemoryRegionSection *section) | ||||
|                           MemoryRegionSection *section, | ||||
|                           int old, int new) | ||||
| { | ||||
|     int r; | ||||
| 
 | ||||
|     if (new != 0) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     r = kvm_dirty_pages_log_change(section->offset_within_address_space, | ||||
|                                    int128_get64(section->size), false); | ||||
|     if (r < 0) { | ||||
| @ -367,31 +367,6 @@ static void kvm_log_stop(MemoryListener *listener, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static int kvm_set_migration_log(bool enable) | ||||
| { | ||||
|     KVMState *s = kvm_state; | ||||
|     KVMSlot *mem; | ||||
|     int i, err; | ||||
| 
 | ||||
|     s->migration_log = enable; | ||||
| 
 | ||||
|     for (i = 0; i < s->nr_slots; i++) { | ||||
|         mem = &s->slots[i]; | ||||
| 
 | ||||
|         if (!mem->memory_size) { | ||||
|             continue; | ||||
|         } | ||||
|         if (!!(mem->flags & KVM_MEM_LOG_DIRTY_PAGES) == enable) { | ||||
|             continue; | ||||
|         } | ||||
|         err = kvm_set_user_memory_region(s, mem); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /* get kvm's dirty pages bitmap and update qemu's */ | ||||
| static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section, | ||||
|                                          unsigned long *bitmap) | ||||
| @ -663,7 +638,7 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) | ||||
|     KVMSlot *mem, old; | ||||
|     int err; | ||||
|     MemoryRegion *mr = section->mr; | ||||
|     bool log_dirty = memory_region_is_logging(mr); | ||||
|     bool log_dirty = memory_region_get_dirty_log_mask(mr) != 0; | ||||
|     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; | ||||
| @ -715,7 +690,7 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) | ||||
| 
 | ||||
|         old = *mem; | ||||
| 
 | ||||
|         if ((mem->flags & KVM_MEM_LOG_DIRTY_PAGES) || s->migration_log) { | ||||
|         if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { | ||||
|             kvm_physical_sync_dirty_bitmap(section); | ||||
|         } | ||||
| 
 | ||||
| @ -844,22 +819,6 @@ static void kvm_log_sync(MemoryListener *listener, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void kvm_log_global_start(struct MemoryListener *listener) | ||||
| { | ||||
|     int r; | ||||
| 
 | ||||
|     r = kvm_set_migration_log(1); | ||||
|     assert(r >= 0); | ||||
| } | ||||
| 
 | ||||
| static void kvm_log_global_stop(struct MemoryListener *listener) | ||||
| { | ||||
|     int r; | ||||
| 
 | ||||
|     r = kvm_set_migration_log(0); | ||||
|     assert(r >= 0); | ||||
| } | ||||
| 
 | ||||
| static void kvm_mem_ioeventfd_add(MemoryListener *listener, | ||||
|                                   MemoryRegionSection *section, | ||||
|                                   bool match_data, uint64_t data, | ||||
| @ -935,8 +894,6 @@ static MemoryListener kvm_memory_listener = { | ||||
|     .log_start = kvm_log_start, | ||||
|     .log_stop = kvm_log_stop, | ||||
|     .log_sync = kvm_log_sync, | ||||
|     .log_global_start = kvm_log_global_start, | ||||
|     .log_global_stop = kvm_log_global_stop, | ||||
|     .eventfd_add = kvm_mem_ioeventfd_add, | ||||
|     .eventfd_del = kvm_mem_ioeventfd_del, | ||||
|     .coalesced_mmio_add = kvm_coalesce_mmio_region, | ||||
| @ -1828,6 +1785,14 @@ int kvm_cpu_exec(CPUState *cpu) | ||||
|             } | ||||
|             fprintf(stderr, "error: kvm run failed %s\n", | ||||
|                     strerror(-run_ret)); | ||||
| #ifdef TARGET_PPC | ||||
|             if (run_ret == -EBUSY) { | ||||
|                 fprintf(stderr, | ||||
|                         "This is probably because your SMT is enabled.\n" | ||||
|                         "VCPU can only run on primary threads with all " | ||||
|                         "secondary threads offline.\n"); | ||||
|             } | ||||
| #endif | ||||
|             ret = -1; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
| @ -106,6 +106,8 @@ struct kvm_ioapic_state { | ||||
| #define KVM_IRQCHIP_IOAPIC       2 | ||||
| #define KVM_NR_IRQCHIPS          3 | ||||
| 
 | ||||
| #define KVM_RUN_X86_SMM		 (1 << 0) | ||||
| 
 | ||||
| /* for KVM_GET_REGS and KVM_SET_REGS */ | ||||
| struct kvm_regs { | ||||
| 	/* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ | ||||
| @ -281,6 +283,7 @@ struct kvm_reinject_control { | ||||
| #define KVM_VCPUEVENT_VALID_NMI_PENDING	0x00000001 | ||||
| #define KVM_VCPUEVENT_VALID_SIPI_VECTOR	0x00000002 | ||||
| #define KVM_VCPUEVENT_VALID_SHADOW	0x00000004 | ||||
| #define KVM_VCPUEVENT_VALID_SMM		0x00000008 | ||||
| 
 | ||||
| /* Interrupt shadow states */ | ||||
| #define KVM_X86_SHADOW_INT_MOV_SS	0x01 | ||||
| @ -309,7 +312,13 @@ struct kvm_vcpu_events { | ||||
| 	} nmi; | ||||
| 	__u32 sipi_vector; | ||||
| 	__u32 flags; | ||||
| 	__u32 reserved[10]; | ||||
| 	struct { | ||||
| 		__u8 smm; | ||||
| 		__u8 pending; | ||||
| 		__u8 smm_inside_nmi; | ||||
| 		__u8 latched_init; | ||||
| 	} smi; | ||||
| 	__u32 reserved[9]; | ||||
| }; | ||||
| 
 | ||||
| /* for KVM_GET/SET_DEBUGREGS */ | ||||
| @ -345,4 +354,7 @@ struct kvm_xcrs { | ||||
| struct kvm_sync_regs { | ||||
| }; | ||||
| 
 | ||||
| #define KVM_QUIRK_LINT0_REENABLED	(1 << 0) | ||||
| #define KVM_QUIRK_CD_NW_CLEARED		(1 << 1) | ||||
| 
 | ||||
| #endif /* _ASM_X86_KVM_H */ | ||||
|  | ||||
| @ -202,7 +202,7 @@ struct kvm_run { | ||||
| 	__u32 exit_reason; | ||||
| 	__u8 ready_for_interrupt_injection; | ||||
| 	__u8 if_flag; | ||||
| 	__u8 padding2[2]; | ||||
| 	__u16 flags; | ||||
| 
 | ||||
| 	/* in (pre_kvm_run), out (post_kvm_run) */ | ||||
| 	__u64 cr8; | ||||
| @ -814,6 +814,9 @@ struct kvm_ppc_smmu_info { | ||||
| #define KVM_CAP_S390_INJECT_IRQ 113 | ||||
| #define KVM_CAP_S390_IRQ_STATE 114 | ||||
| #define KVM_CAP_PPC_HWRNG 115 | ||||
| #define KVM_CAP_DISABLE_QUIRKS 116 | ||||
| #define KVM_CAP_X86_SMM 117 | ||||
| #define KVM_CAP_MULTI_ADDRESS_SPACE 118 | ||||
| 
 | ||||
| #ifdef KVM_CAP_IRQ_ROUTING | ||||
| 
 | ||||
| @ -1199,6 +1202,8 @@ struct kvm_s390_ucas_mapping { | ||||
| /* Available with KVM_CAP_S390_IRQ_STATE */ | ||||
| #define KVM_S390_SET_IRQ_STATE	  _IOW(KVMIO, 0xb5, struct kvm_s390_irq_state) | ||||
| #define KVM_S390_GET_IRQ_STATE	  _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state) | ||||
| /* Available with KVM_CAP_X86_SMM */ | ||||
| #define KVM_SMI                   _IO(KVMIO,   0xb7) | ||||
| 
 | ||||
| #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0) | ||||
| #define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1) | ||||
|  | ||||
| @ -215,10 +215,6 @@ void cpu_list_unlock(void) | ||||
| /***********************************************************/ | ||||
| /* CPUX86 core interface */ | ||||
| 
 | ||||
| void cpu_smm_update(CPUX86State *env) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| uint64_t cpu_get_tsc(CPUX86State *env) | ||||
| { | ||||
|     return cpu_get_real_ticks(); | ||||
|  | ||||
| @ -30,6 +30,7 @@ | ||||
| 
 | ||||
| #include "qemu.h" | ||||
| #include "qemu-common.h" | ||||
| #include "translate-all.h" | ||||
| 
 | ||||
| //#define DEBUG_MMAP
 | ||||
| 
 | ||||
| @ -574,7 +575,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, | ||||
|     page_dump(stdout); | ||||
|     printf("\n"); | ||||
| #endif | ||||
|     tb_invalidate_phys_range(start, start + len, 0); | ||||
|     tb_invalidate_phys_range(start, start + len); | ||||
|     mmap_unlock(); | ||||
|     return start; | ||||
| fail: | ||||
| @ -679,7 +680,7 @@ int target_munmap(abi_ulong start, abi_ulong len) | ||||
| 
 | ||||
|     if (ret == 0) { | ||||
|         page_set_flags(start, start + len, 0); | ||||
|         tb_invalidate_phys_range(start, start + len, 0); | ||||
|         tb_invalidate_phys_range(start, start + len); | ||||
|     } | ||||
|     mmap_unlock(); | ||||
|     return ret; | ||||
| @ -758,7 +759,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, | ||||
|         page_set_flags(old_addr, old_addr + old_size, 0); | ||||
|         page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); | ||||
|     } | ||||
|     tb_invalidate_phys_range(new_addr, new_addr + new_size, 0); | ||||
|     tb_invalidate_phys_range(new_addr, new_addr + new_size); | ||||
|     mmap_unlock(); | ||||
|     return new_addr; | ||||
| } | ||||
|  | ||||
							
								
								
									
										81
									
								
								memory.c
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								memory.c
									
									
									
									
									
								
							| @ -28,6 +28,8 @@ | ||||
| 
 | ||||
| //#define DEBUG_UNASSIGNED
 | ||||
| 
 | ||||
| #define RAM_ADDR_INVALID (~(ram_addr_t)0) | ||||
| 
 | ||||
| static unsigned memory_region_transaction_depth; | ||||
| static bool memory_region_update_pending; | ||||
| static bool ioeventfd_update_pending; | ||||
| @ -152,7 +154,7 @@ static bool memory_listener_match(MemoryListener *listener, | ||||
|     } while (0) | ||||
| 
 | ||||
| /* No need to ref/unref .mr, the FlatRange keeps it alive.  */ | ||||
| #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback)            \ | ||||
| #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback, _args...)  \ | ||||
|     MEMORY_LISTENER_CALL(callback, dir, (&(MemoryRegionSection) {       \ | ||||
|         .mr = (fr)->mr,                                                 \ | ||||
|         .address_space = (as),                                          \ | ||||
| @ -160,7 +162,7 @@ static bool memory_listener_match(MemoryListener *listener, | ||||
|         .size = (fr)->addr.size,                                        \ | ||||
|         .offset_within_address_space = int128_get64((fr)->addr.start),  \ | ||||
|         .readonly = (fr)->readonly,                                     \ | ||||
|               })) | ||||
|               }), ##_args) | ||||
| 
 | ||||
| struct CoalescedMemoryRange { | ||||
|     AddrRange addr; | ||||
| @ -588,7 +590,7 @@ static void render_memory_region(FlatView *view, | ||||
|     remain = clip.size; | ||||
| 
 | ||||
|     fr.mr = mr; | ||||
|     fr.dirty_log_mask = mr->dirty_log_mask; | ||||
|     fr.dirty_log_mask = memory_region_get_dirty_log_mask(mr); | ||||
|     fr.romd_mode = mr->romd_mode; | ||||
|     fr.readonly = readonly; | ||||
| 
 | ||||
| @ -774,10 +776,15 @@ static void address_space_update_topology_pass(AddressSpace *as, | ||||
| 
 | ||||
|             if (adding) { | ||||
|                 MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_nop); | ||||
|                 if (frold->dirty_log_mask && !frnew->dirty_log_mask) { | ||||
|                     MEMORY_LISTENER_UPDATE_REGION(frnew, as, Reverse, log_stop); | ||||
|                 } else if (frnew->dirty_log_mask && !frold->dirty_log_mask) { | ||||
|                     MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, log_start); | ||||
|                 if (frnew->dirty_log_mask & ~frold->dirty_log_mask) { | ||||
|                     MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, log_start, | ||||
|                                                   frold->dirty_log_mask, | ||||
|                                                   frnew->dirty_log_mask); | ||||
|                 } | ||||
|                 if (frold->dirty_log_mask & ~frnew->dirty_log_mask) { | ||||
|                     MEMORY_LISTENER_UPDATE_REGION(frnew, as, Reverse, log_stop, | ||||
|                                                   frold->dirty_log_mask, | ||||
|                                                   frnew->dirty_log_mask); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
| @ -1002,6 +1009,7 @@ static void memory_region_initfn(Object *obj) | ||||
|     ObjectProperty *op; | ||||
| 
 | ||||
|     mr->ops = &unassigned_mem_ops; | ||||
|     mr->ram_addr = RAM_ADDR_INVALID; | ||||
|     mr->enabled = true; | ||||
|     mr->romd_mode = true; | ||||
|     mr->destructor = memory_region_destructor_none; | ||||
| @ -1193,7 +1201,6 @@ void memory_region_init_io(MemoryRegion *mr, | ||||
|     mr->ops = ops; | ||||
|     mr->opaque = opaque; | ||||
|     mr->terminates = true; | ||||
|     mr->ram_addr = ~(ram_addr_t)0; | ||||
| } | ||||
| 
 | ||||
| void memory_region_init_ram(MemoryRegion *mr, | ||||
| @ -1207,6 +1214,7 @@ void memory_region_init_ram(MemoryRegion *mr, | ||||
|     mr->terminates = true; | ||||
|     mr->destructor = memory_region_destructor_ram; | ||||
|     mr->ram_addr = qemu_ram_alloc(size, mr, errp); | ||||
|     mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; | ||||
| } | ||||
| 
 | ||||
| void memory_region_init_resizeable_ram(MemoryRegion *mr, | ||||
| @ -1224,6 +1232,7 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr, | ||||
|     mr->terminates = true; | ||||
|     mr->destructor = memory_region_destructor_ram; | ||||
|     mr->ram_addr = qemu_ram_alloc_resizeable(size, max_size, resized, mr, errp); | ||||
|     mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef __linux__ | ||||
| @ -1240,6 +1249,7 @@ void memory_region_init_ram_from_file(MemoryRegion *mr, | ||||
|     mr->terminates = true; | ||||
|     mr->destructor = memory_region_destructor_ram; | ||||
|     mr->ram_addr = qemu_ram_alloc_from_file(size, mr, share, path, errp); | ||||
|     mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| @ -1253,6 +1263,7 @@ void memory_region_init_ram_ptr(MemoryRegion *mr, | ||||
|     mr->ram = true; | ||||
|     mr->terminates = true; | ||||
|     mr->destructor = memory_region_destructor_ram_from_ptr; | ||||
|     mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0; | ||||
| 
 | ||||
|     /* qemu_ram_alloc_from_ptr cannot fail with ptr != NULL.  */ | ||||
|     assert(ptr != NULL); | ||||
| @ -1389,9 +1400,18 @@ bool memory_region_is_skip_dump(MemoryRegion *mr) | ||||
|     return mr->skip_dump; | ||||
| } | ||||
| 
 | ||||
| bool memory_region_is_logging(MemoryRegion *mr) | ||||
| uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr) | ||||
| { | ||||
|     return mr->dirty_log_mask; | ||||
|     uint8_t mask = mr->dirty_log_mask; | ||||
|     if (global_dirty_log) { | ||||
|         mask |= (1 << DIRTY_MEMORY_MIGRATION); | ||||
|     } | ||||
|     return mask; | ||||
| } | ||||
| 
 | ||||
| bool memory_region_is_logging(MemoryRegion *mr, uint8_t client) | ||||
| { | ||||
|     return memory_region_get_dirty_log_mask(mr) & (1 << client); | ||||
| } | ||||
| 
 | ||||
| bool memory_region_is_rom(MemoryRegion *mr) | ||||
| @ -1425,6 +1445,7 @@ void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) | ||||
| { | ||||
|     uint8_t mask = 1 << client; | ||||
| 
 | ||||
|     assert(client == DIRTY_MEMORY_VGA); | ||||
|     memory_region_transaction_begin(); | ||||
|     mr->dirty_log_mask = (mr->dirty_log_mask & ~mask) | (log * mask); | ||||
|     memory_region_update_pending |= mr->enabled; | ||||
| @ -1434,27 +1455,24 @@ void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) | ||||
| bool memory_region_get_dirty(MemoryRegion *mr, hwaddr addr, | ||||
|                              hwaddr size, unsigned client) | ||||
| { | ||||
|     assert(mr->terminates); | ||||
|     assert(mr->ram_addr != RAM_ADDR_INVALID); | ||||
|     return cpu_physical_memory_get_dirty(mr->ram_addr + addr, size, client); | ||||
| } | ||||
| 
 | ||||
| void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr, | ||||
|                              hwaddr size) | ||||
| { | ||||
|     assert(mr->terminates); | ||||
|     cpu_physical_memory_set_dirty_range(mr->ram_addr + addr, size); | ||||
|     assert(mr->ram_addr != RAM_ADDR_INVALID); | ||||
|     cpu_physical_memory_set_dirty_range(mr->ram_addr + addr, size, | ||||
|                                         memory_region_get_dirty_log_mask(mr)); | ||||
| } | ||||
| 
 | ||||
| bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr, | ||||
|                                         hwaddr size, unsigned client) | ||||
| { | ||||
|     bool ret; | ||||
|     assert(mr->terminates); | ||||
|     ret = cpu_physical_memory_get_dirty(mr->ram_addr + addr, size, client); | ||||
|     if (ret) { | ||||
|         cpu_physical_memory_reset_dirty(mr->ram_addr + addr, size, client); | ||||
|     } | ||||
|     return ret; | ||||
|     assert(mr->ram_addr != RAM_ADDR_INVALID); | ||||
|     return cpu_physical_memory_test_and_clear_dirty(mr->ram_addr + addr, | ||||
|                                                     size, client); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -1497,8 +1515,9 @@ void memory_region_rom_device_set_romd(MemoryRegion *mr, bool romd_mode) | ||||
| void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr, | ||||
|                                hwaddr size, unsigned client) | ||||
| { | ||||
|     assert(mr->terminates); | ||||
|     cpu_physical_memory_reset_dirty(mr->ram_addr + addr, size, client); | ||||
|     assert(mr->ram_addr != RAM_ADDR_INVALID); | ||||
|     cpu_physical_memory_test_and_clear_dirty(mr->ram_addr + addr, size, | ||||
|                                              client); | ||||
| } | ||||
| 
 | ||||
| int memory_region_get_fd(MemoryRegion *mr) | ||||
| @ -1507,7 +1526,7 @@ int memory_region_get_fd(MemoryRegion *mr) | ||||
|         return memory_region_get_fd(mr->alias); | ||||
|     } | ||||
| 
 | ||||
|     assert(mr->terminates); | ||||
|     assert(mr->ram_addr != RAM_ADDR_INVALID); | ||||
| 
 | ||||
|     return qemu_get_ram_fd(mr->ram_addr & TARGET_PAGE_MASK); | ||||
| } | ||||
| @ -1518,14 +1537,14 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr) | ||||
|         return memory_region_get_ram_ptr(mr->alias) + mr->alias_offset; | ||||
|     } | ||||
| 
 | ||||
|     assert(mr->terminates); | ||||
|     assert(mr->ram_addr != RAM_ADDR_INVALID); | ||||
| 
 | ||||
|     return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK); | ||||
| } | ||||
| 
 | ||||
| void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp) | ||||
| { | ||||
|     assert(mr->terminates); | ||||
|     assert(mr->ram_addr != RAM_ADDR_INVALID); | ||||
| 
 | ||||
|     qemu_ram_resize(mr->ram_addr, newsize, errp); | ||||
| } | ||||
| @ -1947,12 +1966,24 @@ void address_space_sync_dirty_bitmap(AddressSpace *as) | ||||
| void memory_global_dirty_log_start(void) | ||||
| { | ||||
|     global_dirty_log = true; | ||||
| 
 | ||||
|     MEMORY_LISTENER_CALL_GLOBAL(log_global_start, Forward); | ||||
| 
 | ||||
|     /* Refresh DIRTY_LOG_MIGRATION bit.  */ | ||||
|     memory_region_transaction_begin(); | ||||
|     memory_region_update_pending = true; | ||||
|     memory_region_transaction_commit(); | ||||
| } | ||||
| 
 | ||||
| void memory_global_dirty_log_stop(void) | ||||
| { | ||||
|     global_dirty_log = false; | ||||
| 
 | ||||
|     /* Refresh DIRTY_LOG_MIGRATION bit.  */ | ||||
|     memory_region_transaction_begin(); | ||||
|     memory_region_update_pending = true; | ||||
|     memory_region_transaction_commit(); | ||||
| 
 | ||||
|     MEMORY_LISTENER_CALL_GLOBAL(log_global_stop, Reverse); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -822,15 +822,19 @@ int qemu_global_option(const char *str) | ||||
|     QemuOpts *opts; | ||||
|     int rc, offset; | ||||
| 
 | ||||
|     rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset); | ||||
|     if (rc < 2 || str[offset] != '=') { | ||||
|         error_report("can't parse: \"%s\"", str); | ||||
|     rc = sscanf(str, "%63[^.=].%63[^=]%n", driver, property, &offset); | ||||
|     if (rc == 2 && str[offset] == '=') { | ||||
|         opts = qemu_opts_create(&qemu_global_opts, NULL, 0, &error_abort); | ||||
|         qemu_opt_set(opts, "driver", driver, &error_abort); | ||||
|         qemu_opt_set(opts, "property", property, &error_abort); | ||||
|         qemu_opt_set(opts, "value", str + offset + 1, &error_abort); | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     opts = qemu_opts_parse(&qemu_global_opts, str, false); | ||||
|     if (!opts) { | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     opts = qemu_opts_create(&qemu_global_opts, NULL, 0, &error_abort); | ||||
|     qemu_opt_set(opts, "driver", driver, &error_abort); | ||||
|     qemu_opt_set(opts, "property", property, &error_abort); | ||||
|     qemu_opt_set(opts, "value", str + offset + 1, &error_abort); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
							
								
								
									
										21
									
								
								qemu-nbd.c
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								qemu-nbd.c
									
									
									
									
									
								
							| @ -53,6 +53,7 @@ static int persistent = 0; | ||||
| static enum { RUNNING, TERMINATE, TERMINATING, TERMINATED } state; | ||||
| static int shared = 1; | ||||
| static int nb_fds; | ||||
| static int server_fd; | ||||
| 
 | ||||
| static void usage(const char *name) | ||||
| { | ||||
| @ -340,7 +341,7 @@ out: | ||||
|     return (void *) EXIT_FAILURE; | ||||
| } | ||||
| 
 | ||||
| static int nbd_can_accept(void *opaque) | ||||
| static int nbd_can_accept(void) | ||||
| { | ||||
|     return nb_fds < shared; | ||||
| } | ||||
| @ -351,19 +352,21 @@ static void nbd_export_closed(NBDExport *exp) | ||||
|     state = TERMINATED; | ||||
| } | ||||
| 
 | ||||
| static void nbd_update_server_fd_handler(int fd); | ||||
| 
 | ||||
| static void nbd_client_closed(NBDClient *client) | ||||
| { | ||||
|     nb_fds--; | ||||
|     if (nb_fds == 0 && !persistent && state == RUNNING) { | ||||
|         state = TERMINATE; | ||||
|     } | ||||
|     nbd_update_server_fd_handler(server_fd); | ||||
|     qemu_notify_event(); | ||||
|     nbd_client_put(client); | ||||
| } | ||||
| 
 | ||||
| static void nbd_accept(void *opaque) | ||||
| { | ||||
|     int server_fd = (uintptr_t) opaque; | ||||
|     struct sockaddr_in addr; | ||||
|     socklen_t addr_len = sizeof(addr); | ||||
| 
 | ||||
| @ -380,12 +383,22 @@ static void nbd_accept(void *opaque) | ||||
| 
 | ||||
|     if (nbd_client_new(exp, fd, nbd_client_closed)) { | ||||
|         nb_fds++; | ||||
|         nbd_update_server_fd_handler(server_fd); | ||||
|     } else { | ||||
|         shutdown(fd, 2); | ||||
|         close(fd); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void nbd_update_server_fd_handler(int fd) | ||||
| { | ||||
|     if (nbd_can_accept()) { | ||||
|         qemu_set_fd_handler(fd, nbd_accept, NULL, (void *)(uintptr_t)fd); | ||||
|     } else { | ||||
|         qemu_set_fd_handler(fd, NULL, NULL, NULL); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
|     BlockBackend *blk; | ||||
| @ -761,8 +774,8 @@ int main(int argc, char **argv) | ||||
|         memset(&client_thread, 0, sizeof(client_thread)); | ||||
|     } | ||||
| 
 | ||||
|     qemu_set_fd_handler2(fd, nbd_can_accept, nbd_accept, NULL, | ||||
|                          (void *)(uintptr_t)fd); | ||||
|     server_fd = fd; | ||||
|     nbd_update_server_fd_handler(fd); | ||||
| 
 | ||||
|     /* now when the initialization is (almost) complete, chdir("/")
 | ||||
|      * to free any busy filesystems */ | ||||
|  | ||||
| @ -171,11 +171,13 @@ Set parameter @var{arg} for item @var{id} of type @var{group}\n" | ||||
| ETEXI | ||||
| 
 | ||||
| DEF("global", HAS_ARG, QEMU_OPTION_global, | ||||
|     "-global driver.prop=value\n" | ||||
|     "-global driver.property=value\n" | ||||
|     "-global driver=driver,property=property,value=value\n" | ||||
|     "                set a global default for a driver property\n", | ||||
|     QEMU_ARCH_ALL) | ||||
| STEXI | ||||
| @item -global @var{driver}.@var{prop}=@var{value} | ||||
| @itemx -global driver=@var{driver},property=@var{property},value=@var{value} | ||||
| @findex -global | ||||
| Set default value of @var{driver}'s property @var{prop} to @var{value}, e.g.: | ||||
| 
 | ||||
| @ -186,6 +188,9 @@ qemu-system-i386 -global ide-drive.physical_block_size=4096 -drive file=file,if= | ||||
| In particular, you can use this to set driver properties for devices which are  | ||||
| created automatically by the machine model. To create a device which is not  | ||||
| created automatically and set properties on it, use -@option{device}. | ||||
| 
 | ||||
| The two syntaxes are equivalent.  The longer one works for drivers whose name | ||||
| contains a dot. | ||||
| ETEXI | ||||
| 
 | ||||
| DEF("boot", HAS_ARG, QEMU_OPTION_boot, | ||||
| @ -3099,9 +3104,10 @@ re-inject them. | ||||
| ETEXI | ||||
| 
 | ||||
| DEF("icount", HAS_ARG, QEMU_OPTION_icount, \ | ||||
|     "-icount [shift=N|auto][,align=on|off]\n" \ | ||||
|     "-icount [shift=N|auto][,align=on|off][,sleep=no]\n" \ | ||||
|     "                enable virtual instruction counter with 2^N clock ticks per\n" \ | ||||
|     "                instruction and enable aligning the host and virtual clocks\n", QEMU_ARCH_ALL) | ||||
|     "                instruction, enable aligning the host and virtual clocks\n" \ | ||||
|     "                or disable real time cpu sleeping\n", QEMU_ARCH_ALL) | ||||
| STEXI | ||||
| @item -icount [shift=@var{N}|auto] | ||||
| @findex -icount | ||||
| @ -3110,6 +3116,13 @@ instruction every 2^@var{N} ns of virtual time.  If @code{auto} is specified | ||||
| then the virtual cpu speed will be automatically adjusted to keep virtual | ||||
| time within a few seconds of real time. | ||||
| 
 | ||||
| When the virtual cpu is sleeping, the virtual time will advance at default | ||||
| speed unless @option{sleep=no} is specified. | ||||
| With @option{sleep=no}, the virtual time will jump to the next timer deadline | ||||
| instantly whenever the virtual cpu goes to sleep mode and will not advance | ||||
| if no timer is enabled. This behavior give deterministic execution times from | ||||
| the guest point of view. | ||||
| 
 | ||||
| Note that while this option can give deterministic behavior, it does not | ||||
| provide cycle accurate emulation.  Modern CPUs contain superscalar out of | ||||
| order cores with complex cache hierarchies.  The number of instructions | ||||
|  | ||||
							
								
								
									
										16
									
								
								qom/object.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								qom/object.c
									
									
									
									
									
								
							| @ -1266,6 +1266,22 @@ out: | ||||
|     g_free(full_type); | ||||
| } | ||||
| 
 | ||||
| void object_property_add_const_link(Object *obj, const char *name, | ||||
|                                     Object *target, Error **errp) | ||||
| { | ||||
|     char *link_type; | ||||
|     ObjectProperty *op; | ||||
| 
 | ||||
|     link_type = g_strdup_printf("link<%s>", object_get_typename(target)); | ||||
|     op = object_property_add(obj, name, link_type, | ||||
|                              object_get_child_property, NULL, | ||||
|                              NULL, target, errp); | ||||
|     if (op != NULL) { | ||||
|         op->resolve = object_resolve_child_property; | ||||
|     } | ||||
|     g_free(link_type); | ||||
| } | ||||
| 
 | ||||
| gchar *object_get_canonical_path_component(Object *obj) | ||||
| { | ||||
|     ObjectProperty *prop = NULL; | ||||
|  | ||||
| @ -5,5 +5,3 @@ obj-y += gdbstub.o | ||||
| obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o | ||||
| obj-$(CONFIG_KVM) += kvm.o | ||||
| obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o | ||||
| obj-$(CONFIG_LINUX_USER) += ioport-user.o | ||||
| obj-$(CONFIG_BSD_USER) += ioport-user.o | ||||
|  | ||||
| @ -23,6 +23,7 @@ | ||||
| #include "qom/cpu.h" | ||||
| #include "cpu.h" | ||||
| #include "qapi/error.h" | ||||
| #include "qemu/notify.h" | ||||
| 
 | ||||
| #ifdef TARGET_X86_64 | ||||
| #define TYPE_X86_CPU "x86_64-cpu" | ||||
| @ -111,6 +112,8 @@ typedef struct X86CPU { | ||||
|     /* in order to simplify APIC support, we leave this pointer to the
 | ||||
|        user */ | ||||
|     struct DeviceState *apic_state; | ||||
|     struct MemoryRegion *cpu_as_root, *cpu_as_mem, *smram; | ||||
|     Notifier machine_done; | ||||
| } X86CPU; | ||||
| 
 | ||||
| static inline X86CPU *x86_env_get_cpu(CPUX86State *env) | ||||
|  | ||||
| @ -44,6 +44,7 @@ | ||||
| #include "hw/qdev-properties.h" | ||||
| #include "hw/cpu/icc_bus.h" | ||||
| #ifndef CONFIG_USER_ONLY | ||||
| #include "exec/address-spaces.h" | ||||
| #include "hw/xen/xen.h" | ||||
| #include "hw/i386/apic_internal.h" | ||||
| #endif | ||||
| @ -2750,6 +2751,21 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) | ||||
|     object_property_set_bool(OBJECT(cpu->apic_state), true, "realized", | ||||
|                              errp); | ||||
| } | ||||
| 
 | ||||
| static void x86_cpu_machine_done(Notifier *n, void *unused) | ||||
| { | ||||
|     X86CPU *cpu = container_of(n, X86CPU, machine_done); | ||||
|     MemoryRegion *smram = | ||||
|         (MemoryRegion *) object_resolve_path("/machine/smram", NULL); | ||||
| 
 | ||||
|     if (smram) { | ||||
|         cpu->smram = g_new(MemoryRegion, 1); | ||||
|         memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram", | ||||
|                                  smram, 0, 1ull << 32); | ||||
|         memory_region_set_enabled(cpu->smram, false); | ||||
|         memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->smram, 1); | ||||
|     } | ||||
| } | ||||
| #else | ||||
| static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) | ||||
| { | ||||
| @ -2811,6 +2827,32 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) | ||||
| #endif | ||||
| 
 | ||||
|     mce_init(cpu); | ||||
| 
 | ||||
| #ifndef CONFIG_USER_ONLY | ||||
|     if (tcg_enabled()) { | ||||
|         cpu->cpu_as_mem = g_new(MemoryRegion, 1); | ||||
|         cpu->cpu_as_root = g_new(MemoryRegion, 1); | ||||
|         cs->as = g_new(AddressSpace, 1); | ||||
| 
 | ||||
|         /* Outer container... */ | ||||
|         memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull); | ||||
|         memory_region_set_enabled(cpu->cpu_as_root, true); | ||||
| 
 | ||||
|         /* ... with two regions inside: normal system memory with low
 | ||||
|          * priority, and... | ||||
|          */ | ||||
|         memory_region_init_alias(cpu->cpu_as_mem, OBJECT(cpu), "memory", | ||||
|                                  get_system_memory(), 0, ~0ull); | ||||
|         memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0); | ||||
|         memory_region_set_enabled(cpu->cpu_as_mem, true); | ||||
|         address_space_init(cs->as, cpu->cpu_as_root, "CPU"); | ||||
| 
 | ||||
|         /* ... SMRAM with higher priority, linked from /machine/smram.  */ | ||||
|         cpu->machine_done.notify = x86_cpu_machine_done; | ||||
|         qemu_add_machine_init_done_notifier(&cpu->machine_done); | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|     qemu_init_vcpu(cs); | ||||
| 
 | ||||
|     /* Only Intel CPUs support hyperthreading. Even though QEMU fixes this
 | ||||
| @ -2834,6 +2876,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) | ||||
|     cpu_reset(cs); | ||||
| 
 | ||||
|     xcc->parent_realize(dev, &local_err); | ||||
| 
 | ||||
| out: | ||||
|     if (local_err != NULL) { | ||||
|         error_propagate(errp, local_err); | ||||
| @ -3063,7 +3106,9 @@ static bool x86_cpu_has_work(CPUState *cs) | ||||
|            (cs->interrupt_request & (CPU_INTERRUPT_NMI | | ||||
|                                      CPU_INTERRUPT_INIT | | ||||
|                                      CPU_INTERRUPT_SIPI | | ||||
|                                      CPU_INTERRUPT_MCE)); | ||||
|                                      CPU_INTERRUPT_MCE)) || | ||||
|            ((cs->interrupt_request & CPU_INTERRUPT_SMI) && | ||||
|             !(env->hflags & HF_SMM_MASK)); | ||||
| } | ||||
| 
 | ||||
| static Property x86_cpu_properties[] = { | ||||
|  | ||||
| @ -180,15 +180,17 @@ | ||||
| 
 | ||||
| /* hflags2 */ | ||||
| 
 | ||||
| #define HF2_GIF_SHIFT        0 /* if set CPU takes interrupts */ | ||||
| #define HF2_HIF_SHIFT        1 /* value of IF_MASK when entering SVM */ | ||||
| #define HF2_NMI_SHIFT        2 /* CPU serving NMI */ | ||||
| #define HF2_VINTR_SHIFT      3 /* value of V_INTR_MASKING bit */ | ||||
| #define HF2_GIF_SHIFT            0 /* if set CPU takes interrupts */ | ||||
| #define HF2_HIF_SHIFT            1 /* value of IF_MASK when entering SVM */ | ||||
| #define HF2_NMI_SHIFT            2 /* CPU serving NMI */ | ||||
| #define HF2_VINTR_SHIFT          3 /* value of V_INTR_MASKING bit */ | ||||
| #define HF2_SMM_INSIDE_NMI_SHIFT 4 /* CPU serving SMI nested inside NMI */ | ||||
| 
 | ||||
| #define HF2_GIF_MASK          (1 << HF2_GIF_SHIFT) | ||||
| #define HF2_HIF_MASK          (1 << HF2_HIF_SHIFT) | ||||
| #define HF2_NMI_MASK          (1 << HF2_NMI_SHIFT) | ||||
| #define HF2_VINTR_MASK        (1 << HF2_VINTR_SHIFT) | ||||
| #define HF2_GIF_MASK            (1 << HF2_GIF_SHIFT) | ||||
| #define HF2_HIF_MASK            (1 << HF2_HIF_SHIFT) | ||||
| #define HF2_NMI_MASK            (1 << HF2_NMI_SHIFT) | ||||
| #define HF2_VINTR_MASK          (1 << HF2_VINTR_SHIFT) | ||||
| #define HF2_SMM_INSIDE_NMI_MASK (1 << HF2_SMM_INSIDE_NMI_SHIFT) | ||||
| 
 | ||||
| #define CR0_PE_SHIFT 0 | ||||
| #define CR0_MP_SHIFT 1 | ||||
| @ -1105,6 +1107,18 @@ int x86_cpu_handle_mmu_fault(CPUState *cpu, vaddr addr, | ||||
|                              int is_write, int mmu_idx); | ||||
| void x86_cpu_set_a20(X86CPU *cpu, int a20_state); | ||||
| 
 | ||||
| #ifndef CONFIG_USER_ONLY | ||||
| uint8_t x86_ldub_phys(CPUState *cs, hwaddr addr); | ||||
| uint32_t x86_lduw_phys(CPUState *cs, hwaddr addr); | ||||
| uint32_t x86_ldl_phys(CPUState *cs, hwaddr addr); | ||||
| uint64_t x86_ldq_phys(CPUState *cs, hwaddr addr); | ||||
| void x86_stb_phys(CPUState *cs, hwaddr addr, uint8_t val); | ||||
| void x86_stl_phys_notdirty(CPUState *cs, hwaddr addr, uint32_t val); | ||||
| void x86_stw_phys(CPUState *cs, hwaddr addr, uint32_t val); | ||||
| void x86_stl_phys(CPUState *cs, hwaddr addr, uint32_t val); | ||||
| void x86_stq_phys(CPUState *cs, hwaddr addr, uint64_t val); | ||||
| #endif | ||||
| 
 | ||||
| static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index) | ||||
| { | ||||
|     return (dr7 >> (index * 2)) & 1; | ||||
| @ -1143,7 +1157,6 @@ void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3); | ||||
| void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4); | ||||
| 
 | ||||
| /* hw/pc.c */ | ||||
| void cpu_smm_update(CPUX86State *env); | ||||
| uint64_t cpu_get_tsc(CPUX86State *env); | ||||
| 
 | ||||
| #define TARGET_PAGE_BITS 12 | ||||
| @ -1292,6 +1305,11 @@ static inline void cpu_load_efer(CPUX86State *env, uint64_t val) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static inline MemTxAttrs cpu_get_mem_attrs(CPUX86State *env) | ||||
| { | ||||
|     return ((MemTxAttrs) { .secure = (env->hflags & HF_SMM_MASK) != 0 }); | ||||
| } | ||||
| 
 | ||||
| /* fpu_helper.c */ | ||||
| void cpu_set_mxcsr(CPUX86State *env, uint32_t val); | ||||
| void cpu_set_fpuc(CPUX86State *env, uint16_t val); | ||||
| @ -1304,7 +1322,9 @@ void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1); | ||||
| /* seg_helper.c */ | ||||
| void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw); | ||||
| 
 | ||||
| /* smm_helper.c */ | ||||
| void do_smm_enter(X86CPU *cpu); | ||||
| void cpu_smm_update(X86CPU *cpu); | ||||
| 
 | ||||
| void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); | ||||
| 
 | ||||
|  | ||||
| @ -565,7 +565,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, | ||||
| 
 | ||||
|             pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & | ||||
|                 env->a20_mask; | ||||
|             pml4e = ldq_phys(cs->as, pml4e_addr); | ||||
|             pml4e = x86_ldq_phys(cs, pml4e_addr); | ||||
|             if (!(pml4e & PG_PRESENT_MASK)) { | ||||
|                 goto do_fault; | ||||
|             } | ||||
| @ -574,12 +574,12 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, | ||||
|             } | ||||
|             if (!(pml4e & PG_ACCESSED_MASK)) { | ||||
|                 pml4e |= PG_ACCESSED_MASK; | ||||
|                 stl_phys_notdirty(cs->as, pml4e_addr, pml4e); | ||||
|                 x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); | ||||
|             } | ||||
|             ptep = pml4e ^ PG_NX_MASK; | ||||
|             pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & | ||||
|                 env->a20_mask; | ||||
|             pdpe = ldq_phys(cs->as, pdpe_addr); | ||||
|             pdpe = x86_ldq_phys(cs, pdpe_addr); | ||||
|             if (!(pdpe & PG_PRESENT_MASK)) { | ||||
|                 goto do_fault; | ||||
|             } | ||||
| @ -589,7 +589,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, | ||||
|             ptep &= pdpe ^ PG_NX_MASK; | ||||
|             if (!(pdpe & PG_ACCESSED_MASK)) { | ||||
|                 pdpe |= PG_ACCESSED_MASK; | ||||
|                 stl_phys_notdirty(cs->as, pdpe_addr, pdpe); | ||||
|                 x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); | ||||
|             } | ||||
|             if (pdpe & PG_PSE_MASK) { | ||||
|                 /* 1 GB page */ | ||||
| @ -604,7 +604,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, | ||||
|             /* XXX: load them when cr3 is loaded ? */ | ||||
|             pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & | ||||
|                 env->a20_mask; | ||||
|             pdpe = ldq_phys(cs->as, pdpe_addr); | ||||
|             pdpe = x86_ldq_phys(cs, pdpe_addr); | ||||
|             if (!(pdpe & PG_PRESENT_MASK)) { | ||||
|                 goto do_fault; | ||||
|             } | ||||
| @ -617,7 +617,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, | ||||
| 
 | ||||
|         pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & | ||||
|             env->a20_mask; | ||||
|         pde = ldq_phys(cs->as, pde_addr); | ||||
|         pde = x86_ldq_phys(cs, pde_addr); | ||||
|         if (!(pde & PG_PRESENT_MASK)) { | ||||
|             goto do_fault; | ||||
|         } | ||||
| @ -635,11 +635,11 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, | ||||
|         /* 4 KB page */ | ||||
|         if (!(pde & PG_ACCESSED_MASK)) { | ||||
|             pde |= PG_ACCESSED_MASK; | ||||
|             stl_phys_notdirty(cs->as, pde_addr, pde); | ||||
|             x86_stl_phys_notdirty(cs, pde_addr, pde); | ||||
|         } | ||||
|         pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & | ||||
|             env->a20_mask; | ||||
|         pte = ldq_phys(cs->as, pte_addr); | ||||
|         pte = x86_ldq_phys(cs, pte_addr); | ||||
|         if (!(pte & PG_PRESENT_MASK)) { | ||||
|             goto do_fault; | ||||
|         } | ||||
| @ -655,7 +655,7 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, | ||||
|         /* page directory entry */ | ||||
|         pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & | ||||
|             env->a20_mask; | ||||
|         pde = ldl_phys(cs->as, pde_addr); | ||||
|         pde = x86_ldl_phys(cs, pde_addr); | ||||
|         if (!(pde & PG_PRESENT_MASK)) { | ||||
|             goto do_fault; | ||||
|         } | ||||
| @ -676,13 +676,13 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, | ||||
| 
 | ||||
|         if (!(pde & PG_ACCESSED_MASK)) { | ||||
|             pde |= PG_ACCESSED_MASK; | ||||
|             stl_phys_notdirty(cs->as, pde_addr, pde); | ||||
|             x86_stl_phys_notdirty(cs, pde_addr, pde); | ||||
|         } | ||||
| 
 | ||||
|         /* page directory entry */ | ||||
|         pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & | ||||
|             env->a20_mask; | ||||
|         pte = ldl_phys(cs->as, pte_addr); | ||||
|         pte = x86_ldl_phys(cs, pte_addr); | ||||
|         if (!(pte & PG_PRESENT_MASK)) { | ||||
|             goto do_fault; | ||||
|         } | ||||
| @ -737,7 +737,7 @@ do_check_protect_pse36: | ||||
|         if (is_dirty) { | ||||
|             pte |= PG_DIRTY_MASK; | ||||
|         } | ||||
|         stl_phys_notdirty(cs->as, pte_addr, pte); | ||||
|         x86_stl_phys_notdirty(cs, pte_addr, pte); | ||||
|     } | ||||
| 
 | ||||
|     /* the page can be put in the TLB */ | ||||
| @ -771,7 +771,8 @@ do_check_protect_pse36: | ||||
|     page_offset = vaddr & (page_size - 1); | ||||
|     paddr = pte + page_offset; | ||||
| 
 | ||||
|     tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size); | ||||
|     tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env), | ||||
|                             prot, mmu_idx, page_size); | ||||
|     return 0; | ||||
|  do_fault_rsvd: | ||||
|     error_code |= PG_ERROR_RSVD_MASK; | ||||
| @ -788,7 +789,7 @@ do_check_protect_pse36: | ||||
|         error_code |= PG_ERROR_I_D_MASK; | ||||
|     if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) { | ||||
|         /* cr2 is not modified in case of exceptions */ | ||||
|         stq_phys(cs->as, | ||||
|         x86_stq_phys(cs, | ||||
|                  env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), | ||||
|                  addr); | ||||
|     } else { | ||||
| @ -827,13 +828,13 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) | ||||
|             } | ||||
|             pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & | ||||
|                 env->a20_mask; | ||||
|             pml4e = ldq_phys(cs->as, pml4e_addr); | ||||
|             pml4e = x86_ldq_phys(cs, pml4e_addr); | ||||
|             if (!(pml4e & PG_PRESENT_MASK)) { | ||||
|                 return -1; | ||||
|             } | ||||
|             pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + | ||||
|                          (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask; | ||||
|             pdpe = ldq_phys(cs->as, pdpe_addr); | ||||
|             pdpe = x86_ldq_phys(cs, pdpe_addr); | ||||
|             if (!(pdpe & PG_PRESENT_MASK)) { | ||||
|                 return -1; | ||||
|             } | ||||
| @ -848,14 +849,14 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) | ||||
|         { | ||||
|             pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & | ||||
|                 env->a20_mask; | ||||
|             pdpe = ldq_phys(cs->as, pdpe_addr); | ||||
|             pdpe = x86_ldq_phys(cs, pdpe_addr); | ||||
|             if (!(pdpe & PG_PRESENT_MASK)) | ||||
|                 return -1; | ||||
|         } | ||||
| 
 | ||||
|         pde_addr = ((pdpe & PG_ADDRESS_MASK) + | ||||
|                     (((addr >> 21) & 0x1ff) << 3)) & env->a20_mask; | ||||
|         pde = ldq_phys(cs->as, pde_addr); | ||||
|         pde = x86_ldq_phys(cs, pde_addr); | ||||
|         if (!(pde & PG_PRESENT_MASK)) { | ||||
|             return -1; | ||||
|         } | ||||
| @ -868,7 +869,7 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) | ||||
|             pte_addr = ((pde & PG_ADDRESS_MASK) + | ||||
|                         (((addr >> 12) & 0x1ff) << 3)) & env->a20_mask; | ||||
|             page_size = 4096; | ||||
|             pte = ldq_phys(cs->as, pte_addr); | ||||
|             pte = x86_ldq_phys(cs, pte_addr); | ||||
|         } | ||||
|         if (!(pte & PG_PRESENT_MASK)) { | ||||
|             return -1; | ||||
| @ -878,7 +879,7 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) | ||||
| 
 | ||||
|         /* page directory entry */ | ||||
|         pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask; | ||||
|         pde = ldl_phys(cs->as, pde_addr); | ||||
|         pde = x86_ldl_phys(cs, pde_addr); | ||||
|         if (!(pde & PG_PRESENT_MASK)) | ||||
|             return -1; | ||||
|         if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { | ||||
| @ -887,7 +888,7 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) | ||||
|         } else { | ||||
|             /* page directory entry */ | ||||
|             pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask; | ||||
|             pte = ldl_phys(cs->as, pte_addr); | ||||
|             pte = x86_ldl_phys(cs, pte_addr); | ||||
|             if (!(pte & PG_PRESENT_MASK)) { | ||||
|                 return -1; | ||||
|             } | ||||
| @ -1276,3 +1277,95 @@ void x86_cpu_exec_exit(CPUState *cs) | ||||
| 
 | ||||
|     env->eflags = cpu_compute_eflags(env); | ||||
| } | ||||
| 
 | ||||
| #ifndef CONFIG_USER_ONLY | ||||
| uint8_t x86_ldub_phys(CPUState *cs, hwaddr addr) | ||||
| { | ||||
|     X86CPU *cpu = X86_CPU(cs); | ||||
|     CPUX86State *env = &cpu->env; | ||||
| 
 | ||||
|     return address_space_ldub(cs->as, addr, | ||||
|                               cpu_get_mem_attrs(env), | ||||
|                               NULL); | ||||
| } | ||||
| 
 | ||||
| uint32_t x86_lduw_phys(CPUState *cs, hwaddr addr) | ||||
| { | ||||
|     X86CPU *cpu = X86_CPU(cs); | ||||
|     CPUX86State *env = &cpu->env; | ||||
| 
 | ||||
|     return address_space_lduw(cs->as, addr, | ||||
|                               cpu_get_mem_attrs(env), | ||||
|                               NULL); | ||||
| } | ||||
| 
 | ||||
| uint32_t x86_ldl_phys(CPUState *cs, hwaddr addr) | ||||
| { | ||||
|     X86CPU *cpu = X86_CPU(cs); | ||||
|     CPUX86State *env = &cpu->env; | ||||
| 
 | ||||
|     return address_space_ldl(cs->as, addr, | ||||
|                              cpu_get_mem_attrs(env), | ||||
|                              NULL); | ||||
| } | ||||
| 
 | ||||
| uint64_t x86_ldq_phys(CPUState *cs, hwaddr addr) | ||||
| { | ||||
|     X86CPU *cpu = X86_CPU(cs); | ||||
|     CPUX86State *env = &cpu->env; | ||||
| 
 | ||||
|     return address_space_ldq(cs->as, addr, | ||||
|                              cpu_get_mem_attrs(env), | ||||
|                              NULL); | ||||
| } | ||||
| 
 | ||||
| void x86_stb_phys(CPUState *cs, hwaddr addr, uint8_t val) | ||||
| { | ||||
|     X86CPU *cpu = X86_CPU(cs); | ||||
|     CPUX86State *env = &cpu->env; | ||||
| 
 | ||||
|     address_space_stb(cs->as, addr, val, | ||||
|                       cpu_get_mem_attrs(env), | ||||
|                       NULL); | ||||
| } | ||||
| 
 | ||||
| void x86_stl_phys_notdirty(CPUState *cs, hwaddr addr, uint32_t val) | ||||
| { | ||||
|     X86CPU *cpu = X86_CPU(cs); | ||||
|     CPUX86State *env = &cpu->env; | ||||
| 
 | ||||
|     address_space_stl_notdirty(cs->as, addr, val, | ||||
|                                cpu_get_mem_attrs(env), | ||||
|                                NULL); | ||||
| } | ||||
| 
 | ||||
| void x86_stw_phys(CPUState *cs, hwaddr addr, uint32_t val) | ||||
| { | ||||
|     X86CPU *cpu = X86_CPU(cs); | ||||
|     CPUX86State *env = &cpu->env; | ||||
| 
 | ||||
|     address_space_stw(cs->as, addr, val, | ||||
|                       cpu_get_mem_attrs(env), | ||||
|                       NULL); | ||||
| } | ||||
| 
 | ||||
| void x86_stl_phys(CPUState *cs, hwaddr addr, uint32_t val) | ||||
| { | ||||
|     X86CPU *cpu = X86_CPU(cs); | ||||
|     CPUX86State *env = &cpu->env; | ||||
| 
 | ||||
|     address_space_stl(cs->as, addr, val, | ||||
|                       cpu_get_mem_attrs(env), | ||||
|                       NULL); | ||||
| } | ||||
| 
 | ||||
| void x86_stq_phys(CPUState *cs, hwaddr addr, uint64_t val) | ||||
| { | ||||
|     X86CPU *cpu = X86_CPU(cs); | ||||
|     CPUX86State *env = &cpu->env; | ||||
| 
 | ||||
|     address_space_stq(cs->as, addr, val, | ||||
|                       cpu_get_mem_attrs(env), | ||||
|                       NULL); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -86,12 +86,12 @@ DEF_HELPER_1(wrmsr, void, env) | ||||
| DEF_HELPER_2(check_iob, void, env, i32) | ||||
| DEF_HELPER_2(check_iow, void, env, i32) | ||||
| DEF_HELPER_2(check_iol, void, env, i32) | ||||
| DEF_HELPER_2(outb, void, i32, i32) | ||||
| DEF_HELPER_1(inb, tl, i32) | ||||
| DEF_HELPER_2(outw, void, i32, i32) | ||||
| DEF_HELPER_1(inw, tl, i32) | ||||
| DEF_HELPER_2(outl, void, i32, i32) | ||||
| DEF_HELPER_1(inl, tl, i32) | ||||
| DEF_HELPER_3(outb, void, env, i32, i32) | ||||
| DEF_HELPER_2(inb, tl, env, i32) | ||||
| DEF_HELPER_3(outw, void, env, i32, i32) | ||||
| DEF_HELPER_2(inw, tl, env, i32) | ||||
| DEF_HELPER_3(outl, void, env, i32, i32) | ||||
| DEF_HELPER_2(inl, tl, env, i32) | ||||
| 
 | ||||
| DEF_HELPER_3(svm_check_intercept_param, void, env, i32, i64) | ||||
| DEF_HELPER_3(vmexit, void, env, i32, i64) | ||||
|  | ||||
| @ -1,60 +0,0 @@ | ||||
| /*
 | ||||
|  *  qemu user ioport functions | ||||
|  * | ||||
|  *  Copyright (c) 2003-2008 Fabrice Bellard | ||||
|  * | ||||
|  *  This program is free software; you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation; either version 2 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  This program is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| #include "qemu.h" | ||||
| #include "qemu-common.h" | ||||
| #include "exec/ioport.h" | ||||
| 
 | ||||
| void cpu_outb(pio_addr_t addr, uint8_t val) | ||||
| { | ||||
|     fprintf(stderr, "outb: port=0x%04"FMT_pioaddr", data=%02"PRIx8"\n", | ||||
|             addr, val); | ||||
| } | ||||
| 
 | ||||
| void cpu_outw(pio_addr_t addr, uint16_t val) | ||||
| { | ||||
|     fprintf(stderr, "outw: port=0x%04"FMT_pioaddr", data=%04"PRIx16"\n", | ||||
|             addr, val); | ||||
| } | ||||
| 
 | ||||
| void cpu_outl(pio_addr_t addr, uint32_t val) | ||||
| { | ||||
|     fprintf(stderr, "outl: port=0x%04"FMT_pioaddr", data=%08"PRIx32"\n", | ||||
|             addr, val); | ||||
| } | ||||
| 
 | ||||
| uint8_t cpu_inb(pio_addr_t addr) | ||||
| { | ||||
|     fprintf(stderr, "inb: port=0x%04"FMT_pioaddr"\n", addr); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| uint16_t cpu_inw(pio_addr_t addr) | ||||
| { | ||||
|     fprintf(stderr, "inw: port=0x%04"FMT_pioaddr"\n", addr); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| uint32_t cpu_inl(pio_addr_t addr) | ||||
| { | ||||
|     fprintf(stderr, "inl: port=0x%04"FMT_pioaddr"\n", addr); | ||||
|     return 0; | ||||
| } | ||||
| @ -2259,7 +2259,7 @@ MemTxAttrs kvm_arch_post_run(CPUState *cpu, struct kvm_run *run) | ||||
|     } | ||||
|     cpu_set_apic_tpr(x86_cpu->apic_state, run->cr8); | ||||
|     cpu_set_apic_base(x86_cpu->apic_state, run->apic_base); | ||||
|     return MEMTXATTRS_UNSPECIFIED; | ||||
|     return cpu_get_mem_attrs(env); | ||||
| } | ||||
| 
 | ||||
| int kvm_arch_process_async_events(CPUState *cs) | ||||
|  | ||||
| @ -372,6 +372,9 @@ static int cpu_post_load(void *opaque, int version_id) | ||||
|     } | ||||
|     tlb_flush(cs, 1); | ||||
| 
 | ||||
|     if (tcg_enabled()) { | ||||
|         cpu_smm_update(cpu); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -18,38 +18,71 @@ | ||||
|  */ | ||||
| 
 | ||||
| #include "cpu.h" | ||||
| #include "exec/ioport.h" | ||||
| #include "exec/helper-proto.h" | ||||
| #include "exec/cpu_ldst.h" | ||||
| #include "exec/address-spaces.h" | ||||
| 
 | ||||
| void helper_outb(uint32_t port, uint32_t data) | ||||
| void helper_outb(CPUX86State *env, uint32_t port, uint32_t data) | ||||
| { | ||||
|     cpu_outb(port, data & 0xff); | ||||
| #ifdef CONFIG_USER_ONLY | ||||
|     fprintf(stderr, "outb: port=0x%04x, data=%02x\n", port, data); | ||||
| #else | ||||
|     address_space_stb(&address_space_io, port, data, | ||||
|                       cpu_get_mem_attrs(env), NULL); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| target_ulong helper_inb(uint32_t port) | ||||
| target_ulong helper_inb(CPUX86State *env, uint32_t port) | ||||
| { | ||||
|     return cpu_inb(port); | ||||
| #ifdef CONFIG_USER_ONLY | ||||
|     fprintf(stderr, "inb: port=0x%04x\n", port); | ||||
|     return 0; | ||||
| #else | ||||
|     return address_space_ldub(&address_space_io, port, | ||||
|                               cpu_get_mem_attrs(env), NULL); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void helper_outw(uint32_t port, uint32_t data) | ||||
| void helper_outw(CPUX86State *env, uint32_t port, uint32_t data) | ||||
| { | ||||
|     cpu_outw(port, data & 0xffff); | ||||
| #ifdef CONFIG_USER_ONLY | ||||
|     fprintf(stderr, "outw: port=0x%04x, data=%04x\n", port, data); | ||||
| #else | ||||
|     address_space_stw(&address_space_io, port, data, | ||||
|                       cpu_get_mem_attrs(env), NULL); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| target_ulong helper_inw(uint32_t port) | ||||
| target_ulong helper_inw(CPUX86State *env, uint32_t port) | ||||
| { | ||||
|     return cpu_inw(port); | ||||
| #ifdef CONFIG_USER_ONLY | ||||
|     fprintf(stderr, "inw: port=0x%04x\n", port); | ||||
|     return 0; | ||||
| #else | ||||
|     return address_space_lduw(&address_space_io, port, | ||||
|                               cpu_get_mem_attrs(env), NULL); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void helper_outl(uint32_t port, uint32_t data) | ||||
| void helper_outl(CPUX86State *env, uint32_t port, uint32_t data) | ||||
| { | ||||
|     cpu_outl(port, data); | ||||
| #ifdef CONFIG_USER_ONLY | ||||
|     fprintf(stderr, "outw: port=0x%04x, data=%08x\n", port, data); | ||||
| #else | ||||
|     address_space_stl(&address_space_io, port, data, | ||||
|                       cpu_get_mem_attrs(env), NULL); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| target_ulong helper_inl(uint32_t port) | ||||
| target_ulong helper_inl(CPUX86State *env, uint32_t port) | ||||
| { | ||||
|     return cpu_inl(port); | ||||
| #ifdef CONFIG_USER_ONLY | ||||
|     fprintf(stderr, "inl: port=0x%04x\n", port); | ||||
|     return 0; | ||||
| #else | ||||
|     return address_space_ldl(&address_space_io, port, | ||||
|                              cpu_get_mem_attrs(env), NULL); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void helper_into(CPUX86State *env, int next_eip_addend) | ||||
|  | ||||
| @ -1144,7 +1144,7 @@ static void handle_even_inj(CPUX86State *env, int intno, int is_int, | ||||
|                             int error_code, int is_hw, int rm) | ||||
| { | ||||
|     CPUState *cs = CPU(x86_env_get_cpu(env)); | ||||
|     uint32_t event_inj = ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, | ||||
|     uint32_t event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                                           control.event_inj)); | ||||
| 
 | ||||
|     if (!(event_inj & SVM_EVTINJ_VALID)) { | ||||
| @ -1158,11 +1158,11 @@ static void handle_even_inj(CPUX86State *env, int intno, int is_int, | ||||
|         event_inj = intno | type | SVM_EVTINJ_VALID; | ||||
|         if (!rm && exception_has_error_code(intno)) { | ||||
|             event_inj |= SVM_EVTINJ_VALID_ERR; | ||||
|             stl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, | ||||
|             x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                              control.event_inj_err), | ||||
|                      error_code); | ||||
|         } | ||||
|         stl_phys(cs->as, | ||||
|         x86_stl_phys(cs, | ||||
|                  env->vm_vmcb + offsetof(struct vmcb, control.event_inj), | ||||
|                  event_inj); | ||||
|     } | ||||
| @ -1240,11 +1240,11 @@ static void do_interrupt_all(X86CPU *cpu, int intno, int is_int, | ||||
| #if !defined(CONFIG_USER_ONLY) | ||||
|     if (env->hflags & HF_SVMI_MASK) { | ||||
|         CPUState *cs = CPU(cpu); | ||||
|         uint32_t event_inj = ldl_phys(cs->as, env->vm_vmcb + | ||||
|         uint32_t event_inj = x86_ldl_phys(cs, env->vm_vmcb + | ||||
|                                       offsetof(struct vmcb, | ||||
|                                                control.event_inj)); | ||||
| 
 | ||||
|         stl_phys(cs->as, | ||||
|         x86_stl_phys(cs, | ||||
|                  env->vm_vmcb + offsetof(struct vmcb, control.event_inj), | ||||
|                  event_inj & ~SVM_EVTINJ_VALID); | ||||
|     } | ||||
| @ -1339,7 +1339,7 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) | ||||
|             int intno; | ||||
|             /* FIXME: this should respect TPR */ | ||||
|             cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR, 0); | ||||
|             intno = ldl_phys(cs->as, env->vm_vmcb | ||||
|             intno = x86_ldl_phys(cs, env->vm_vmcb | ||||
|                              + offsetof(struct vmcb, control.int_vector)); | ||||
|             qemu_log_mask(CPU_LOG_TB_IN_ASM, | ||||
|                           "Servicing virtual hardware INT=0x%02x\n", intno); | ||||
|  | ||||
| @ -40,6 +40,16 @@ void helper_rsm(CPUX86State *env) | ||||
| #define SMM_REVISION_ID 0x00020000 | ||||
| #endif | ||||
| 
 | ||||
| void cpu_smm_update(X86CPU *cpu) | ||||
| { | ||||
|     CPUX86State *env = &cpu->env; | ||||
|     bool smm_enabled = (env->hflags & HF_SMM_MASK); | ||||
| 
 | ||||
|     if (cpu->smram) { | ||||
|         memory_region_set_enabled(cpu->smram, smm_enabled); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void do_smm_enter(X86CPU *cpu) | ||||
| { | ||||
|     CPUX86State *env = &cpu->env; | ||||
| @ -52,7 +62,12 @@ void do_smm_enter(X86CPU *cpu) | ||||
|     log_cpu_state_mask(CPU_LOG_INT, CPU(cpu), CPU_DUMP_CCOP); | ||||
| 
 | ||||
|     env->hflags |= HF_SMM_MASK; | ||||
|     cpu_smm_update(env); | ||||
|     if (env->hflags2 & HF2_NMI_MASK) { | ||||
|         env->hflags2 |= HF2_SMM_INSIDE_NMI_MASK; | ||||
|     } else { | ||||
|         env->hflags2 |= HF2_NMI_MASK; | ||||
|     } | ||||
|     cpu_smm_update(cpu); | ||||
| 
 | ||||
|     sm_state = env->smbase + 0x8000; | ||||
| 
 | ||||
| @ -60,83 +75,83 @@ void do_smm_enter(X86CPU *cpu) | ||||
|     for (i = 0; i < 6; i++) { | ||||
|         dt = &env->segs[i]; | ||||
|         offset = 0x7e00 + i * 16; | ||||
|         stw_phys(cs->as, sm_state + offset, dt->selector); | ||||
|         stw_phys(cs->as, sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff); | ||||
|         stl_phys(cs->as, sm_state + offset + 4, dt->limit); | ||||
|         stq_phys(cs->as, sm_state + offset + 8, dt->base); | ||||
|         x86_stw_phys(cs, sm_state + offset, dt->selector); | ||||
|         x86_stw_phys(cs, sm_state + offset + 2, (dt->flags >> 8) & 0xf0ff); | ||||
|         x86_stl_phys(cs, sm_state + offset + 4, dt->limit); | ||||
|         x86_stq_phys(cs, sm_state + offset + 8, dt->base); | ||||
|     } | ||||
| 
 | ||||
|     stq_phys(cs->as, sm_state + 0x7e68, env->gdt.base); | ||||
|     stl_phys(cs->as, sm_state + 0x7e64, env->gdt.limit); | ||||
|     x86_stq_phys(cs, sm_state + 0x7e68, env->gdt.base); | ||||
|     x86_stl_phys(cs, sm_state + 0x7e64, env->gdt.limit); | ||||
| 
 | ||||
|     stw_phys(cs->as, sm_state + 0x7e70, env->ldt.selector); | ||||
|     stq_phys(cs->as, sm_state + 0x7e78, env->ldt.base); | ||||
|     stl_phys(cs->as, sm_state + 0x7e74, env->ldt.limit); | ||||
|     stw_phys(cs->as, sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff); | ||||
|     x86_stw_phys(cs, sm_state + 0x7e70, env->ldt.selector); | ||||
|     x86_stq_phys(cs, sm_state + 0x7e78, env->ldt.base); | ||||
|     x86_stl_phys(cs, sm_state + 0x7e74, env->ldt.limit); | ||||
|     x86_stw_phys(cs, sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff); | ||||
| 
 | ||||
|     stq_phys(cs->as, sm_state + 0x7e88, env->idt.base); | ||||
|     stl_phys(cs->as, sm_state + 0x7e84, env->idt.limit); | ||||
|     x86_stq_phys(cs, sm_state + 0x7e88, env->idt.base); | ||||
|     x86_stl_phys(cs, sm_state + 0x7e84, env->idt.limit); | ||||
| 
 | ||||
|     stw_phys(cs->as, sm_state + 0x7e90, env->tr.selector); | ||||
|     stq_phys(cs->as, sm_state + 0x7e98, env->tr.base); | ||||
|     stl_phys(cs->as, sm_state + 0x7e94, env->tr.limit); | ||||
|     stw_phys(cs->as, sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff); | ||||
|     x86_stw_phys(cs, sm_state + 0x7e90, env->tr.selector); | ||||
|     x86_stq_phys(cs, sm_state + 0x7e98, env->tr.base); | ||||
|     x86_stl_phys(cs, sm_state + 0x7e94, env->tr.limit); | ||||
|     x86_stw_phys(cs, sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff); | ||||
| 
 | ||||
|     stq_phys(cs->as, sm_state + 0x7ed0, env->efer); | ||||
|     x86_stq_phys(cs, sm_state + 0x7ed0, env->efer); | ||||
| 
 | ||||
|     stq_phys(cs->as, sm_state + 0x7ff8, env->regs[R_EAX]); | ||||
|     stq_phys(cs->as, sm_state + 0x7ff0, env->regs[R_ECX]); | ||||
|     stq_phys(cs->as, sm_state + 0x7fe8, env->regs[R_EDX]); | ||||
|     stq_phys(cs->as, sm_state + 0x7fe0, env->regs[R_EBX]); | ||||
|     stq_phys(cs->as, sm_state + 0x7fd8, env->regs[R_ESP]); | ||||
|     stq_phys(cs->as, sm_state + 0x7fd0, env->regs[R_EBP]); | ||||
|     stq_phys(cs->as, sm_state + 0x7fc8, env->regs[R_ESI]); | ||||
|     stq_phys(cs->as, sm_state + 0x7fc0, env->regs[R_EDI]); | ||||
|     x86_stq_phys(cs, sm_state + 0x7ff8, env->regs[R_EAX]); | ||||
|     x86_stq_phys(cs, sm_state + 0x7ff0, env->regs[R_ECX]); | ||||
|     x86_stq_phys(cs, sm_state + 0x7fe8, env->regs[R_EDX]); | ||||
|     x86_stq_phys(cs, sm_state + 0x7fe0, env->regs[R_EBX]); | ||||
|     x86_stq_phys(cs, sm_state + 0x7fd8, env->regs[R_ESP]); | ||||
|     x86_stq_phys(cs, sm_state + 0x7fd0, env->regs[R_EBP]); | ||||
|     x86_stq_phys(cs, sm_state + 0x7fc8, env->regs[R_ESI]); | ||||
|     x86_stq_phys(cs, sm_state + 0x7fc0, env->regs[R_EDI]); | ||||
|     for (i = 8; i < 16; i++) { | ||||
|         stq_phys(cs->as, sm_state + 0x7ff8 - i * 8, env->regs[i]); | ||||
|         x86_stq_phys(cs, sm_state + 0x7ff8 - i * 8, env->regs[i]); | ||||
|     } | ||||
|     stq_phys(cs->as, sm_state + 0x7f78, env->eip); | ||||
|     stl_phys(cs->as, sm_state + 0x7f70, cpu_compute_eflags(env)); | ||||
|     stl_phys(cs->as, sm_state + 0x7f68, env->dr[6]); | ||||
|     stl_phys(cs->as, sm_state + 0x7f60, env->dr[7]); | ||||
|     x86_stq_phys(cs, sm_state + 0x7f78, env->eip); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f70, cpu_compute_eflags(env)); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f68, env->dr[6]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f60, env->dr[7]); | ||||
| 
 | ||||
|     stl_phys(cs->as, sm_state + 0x7f48, env->cr[4]); | ||||
|     stq_phys(cs->as, sm_state + 0x7f50, env->cr[3]); | ||||
|     stl_phys(cs->as, sm_state + 0x7f58, env->cr[0]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f48, env->cr[4]); | ||||
|     x86_stq_phys(cs, sm_state + 0x7f50, env->cr[3]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f58, env->cr[0]); | ||||
| 
 | ||||
|     stl_phys(cs->as, sm_state + 0x7efc, SMM_REVISION_ID); | ||||
|     stl_phys(cs->as, sm_state + 0x7f00, env->smbase); | ||||
|     x86_stl_phys(cs, sm_state + 0x7efc, SMM_REVISION_ID); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f00, env->smbase); | ||||
| #else | ||||
|     stl_phys(cs->as, sm_state + 0x7ffc, env->cr[0]); | ||||
|     stl_phys(cs->as, sm_state + 0x7ff8, env->cr[3]); | ||||
|     stl_phys(cs->as, sm_state + 0x7ff4, cpu_compute_eflags(env)); | ||||
|     stl_phys(cs->as, sm_state + 0x7ff0, env->eip); | ||||
|     stl_phys(cs->as, sm_state + 0x7fec, env->regs[R_EDI]); | ||||
|     stl_phys(cs->as, sm_state + 0x7fe8, env->regs[R_ESI]); | ||||
|     stl_phys(cs->as, sm_state + 0x7fe4, env->regs[R_EBP]); | ||||
|     stl_phys(cs->as, sm_state + 0x7fe0, env->regs[R_ESP]); | ||||
|     stl_phys(cs->as, sm_state + 0x7fdc, env->regs[R_EBX]); | ||||
|     stl_phys(cs->as, sm_state + 0x7fd8, env->regs[R_EDX]); | ||||
|     stl_phys(cs->as, sm_state + 0x7fd4, env->regs[R_ECX]); | ||||
|     stl_phys(cs->as, sm_state + 0x7fd0, env->regs[R_EAX]); | ||||
|     stl_phys(cs->as, sm_state + 0x7fcc, env->dr[6]); | ||||
|     stl_phys(cs->as, sm_state + 0x7fc8, env->dr[7]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7ffc, env->cr[0]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7ff8, env->cr[3]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7ff4, cpu_compute_eflags(env)); | ||||
|     x86_stl_phys(cs, sm_state + 0x7ff0, env->eip); | ||||
|     x86_stl_phys(cs, sm_state + 0x7fec, env->regs[R_EDI]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7fe8, env->regs[R_ESI]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7fe4, env->regs[R_EBP]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7fe0, env->regs[R_ESP]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7fdc, env->regs[R_EBX]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7fd8, env->regs[R_EDX]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7fd4, env->regs[R_ECX]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7fd0, env->regs[R_EAX]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7fcc, env->dr[6]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7fc8, env->dr[7]); | ||||
| 
 | ||||
|     stl_phys(cs->as, sm_state + 0x7fc4, env->tr.selector); | ||||
|     stl_phys(cs->as, sm_state + 0x7f64, env->tr.base); | ||||
|     stl_phys(cs->as, sm_state + 0x7f60, env->tr.limit); | ||||
|     stl_phys(cs->as, sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff); | ||||
|     x86_stl_phys(cs, sm_state + 0x7fc4, env->tr.selector); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f64, env->tr.base); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f60, env->tr.limit); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff); | ||||
| 
 | ||||
|     stl_phys(cs->as, sm_state + 0x7fc0, env->ldt.selector); | ||||
|     stl_phys(cs->as, sm_state + 0x7f80, env->ldt.base); | ||||
|     stl_phys(cs->as, sm_state + 0x7f7c, env->ldt.limit); | ||||
|     stl_phys(cs->as, sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff); | ||||
|     x86_stl_phys(cs, sm_state + 0x7fc0, env->ldt.selector); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f80, env->ldt.base); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f7c, env->ldt.limit); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff); | ||||
| 
 | ||||
|     stl_phys(cs->as, sm_state + 0x7f74, env->gdt.base); | ||||
|     stl_phys(cs->as, sm_state + 0x7f70, env->gdt.limit); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f74, env->gdt.base); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f70, env->gdt.limit); | ||||
| 
 | ||||
|     stl_phys(cs->as, sm_state + 0x7f58, env->idt.base); | ||||
|     stl_phys(cs->as, sm_state + 0x7f54, env->idt.limit); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f58, env->idt.base); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f54, env->idt.limit); | ||||
| 
 | ||||
|     for (i = 0; i < 6; i++) { | ||||
|         dt = &env->segs[i]; | ||||
| @ -145,15 +160,15 @@ void do_smm_enter(X86CPU *cpu) | ||||
|         } else { | ||||
|             offset = 0x7f2c + (i - 3) * 12; | ||||
|         } | ||||
|         stl_phys(cs->as, sm_state + 0x7fa8 + i * 4, dt->selector); | ||||
|         stl_phys(cs->as, sm_state + offset + 8, dt->base); | ||||
|         stl_phys(cs->as, sm_state + offset + 4, dt->limit); | ||||
|         stl_phys(cs->as, sm_state + offset, (dt->flags >> 8) & 0xf0ff); | ||||
|         x86_stl_phys(cs, sm_state + 0x7fa8 + i * 4, dt->selector); | ||||
|         x86_stl_phys(cs, sm_state + offset + 8, dt->base); | ||||
|         x86_stl_phys(cs, sm_state + offset + 4, dt->limit); | ||||
|         x86_stl_phys(cs, sm_state + offset, (dt->flags >> 8) & 0xf0ff); | ||||
|     } | ||||
|     stl_phys(cs->as, sm_state + 0x7f14, env->cr[4]); | ||||
|     x86_stl_phys(cs, sm_state + 0x7f14, env->cr[4]); | ||||
| 
 | ||||
|     stl_phys(cs->as, sm_state + 0x7efc, SMM_REVISION_ID); | ||||
|     stl_phys(cs->as, sm_state + 0x7ef8, env->smbase); | ||||
|     x86_stl_phys(cs, sm_state + 0x7efc, SMM_REVISION_ID); | ||||
|     x86_stl_phys(cs, sm_state + 0x7ef8, env->smbase); | ||||
| #endif | ||||
|     /* init SMM cpu state */ | ||||
| 
 | ||||
| @ -172,22 +187,22 @@ void do_smm_enter(X86CPU *cpu) | ||||
|     cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase, | ||||
|                            0xffffffff, | ||||
|                            DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | | ||||
|                            DESC_A_MASK); | ||||
|                            DESC_G_MASK | DESC_A_MASK); | ||||
|     cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffffffff, | ||||
|                            DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | | ||||
|                            DESC_A_MASK); | ||||
|                            DESC_G_MASK | DESC_A_MASK); | ||||
|     cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffffffff, | ||||
|                            DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | | ||||
|                            DESC_A_MASK); | ||||
|                            DESC_G_MASK | DESC_A_MASK); | ||||
|     cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, | ||||
|                            DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | | ||||
|                            DESC_A_MASK); | ||||
|                            DESC_G_MASK | DESC_A_MASK); | ||||
|     cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, | ||||
|                            DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | | ||||
|                            DESC_A_MASK); | ||||
|                            DESC_G_MASK | DESC_A_MASK); | ||||
|     cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, | ||||
|                            DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | | ||||
|                            DESC_A_MASK); | ||||
|                            DESC_G_MASK | DESC_A_MASK); | ||||
| } | ||||
| 
 | ||||
| void helper_rsm(CPUX86State *env) | ||||
| @ -200,91 +215,91 @@ void helper_rsm(CPUX86State *env) | ||||
| 
 | ||||
|     sm_state = env->smbase + 0x8000; | ||||
| #ifdef TARGET_X86_64 | ||||
|     cpu_load_efer(env, ldq_phys(cs->as, sm_state + 0x7ed0)); | ||||
|     cpu_load_efer(env, x86_ldq_phys(cs, sm_state + 0x7ed0)); | ||||
| 
 | ||||
|     env->gdt.base = ldq_phys(cs->as, sm_state + 0x7e68); | ||||
|     env->gdt.limit = ldl_phys(cs->as, sm_state + 0x7e64); | ||||
|     env->gdt.base = x86_ldq_phys(cs, sm_state + 0x7e68); | ||||
|     env->gdt.limit = x86_ldl_phys(cs, sm_state + 0x7e64); | ||||
| 
 | ||||
|     env->ldt.selector = lduw_phys(cs->as, sm_state + 0x7e70); | ||||
|     env->ldt.base = ldq_phys(cs->as, sm_state + 0x7e78); | ||||
|     env->ldt.limit = ldl_phys(cs->as, sm_state + 0x7e74); | ||||
|     env->ldt.flags = (lduw_phys(cs->as, sm_state + 0x7e72) & 0xf0ff) << 8; | ||||
|     env->ldt.selector = x86_lduw_phys(cs, sm_state + 0x7e70); | ||||
|     env->ldt.base = x86_ldq_phys(cs, sm_state + 0x7e78); | ||||
|     env->ldt.limit = x86_ldl_phys(cs, sm_state + 0x7e74); | ||||
|     env->ldt.flags = (x86_lduw_phys(cs, sm_state + 0x7e72) & 0xf0ff) << 8; | ||||
| 
 | ||||
|     env->idt.base = ldq_phys(cs->as, sm_state + 0x7e88); | ||||
|     env->idt.limit = ldl_phys(cs->as, sm_state + 0x7e84); | ||||
|     env->idt.base = x86_ldq_phys(cs, sm_state + 0x7e88); | ||||
|     env->idt.limit = x86_ldl_phys(cs, sm_state + 0x7e84); | ||||
| 
 | ||||
|     env->tr.selector = lduw_phys(cs->as, sm_state + 0x7e90); | ||||
|     env->tr.base = ldq_phys(cs->as, sm_state + 0x7e98); | ||||
|     env->tr.limit = ldl_phys(cs->as, sm_state + 0x7e94); | ||||
|     env->tr.flags = (lduw_phys(cs->as, sm_state + 0x7e92) & 0xf0ff) << 8; | ||||
|     env->tr.selector = x86_lduw_phys(cs, sm_state + 0x7e90); | ||||
|     env->tr.base = x86_ldq_phys(cs, sm_state + 0x7e98); | ||||
|     env->tr.limit = x86_ldl_phys(cs, sm_state + 0x7e94); | ||||
|     env->tr.flags = (x86_lduw_phys(cs, sm_state + 0x7e92) & 0xf0ff) << 8; | ||||
| 
 | ||||
|     env->regs[R_EAX] = ldq_phys(cs->as, sm_state + 0x7ff8); | ||||
|     env->regs[R_ECX] = ldq_phys(cs->as, sm_state + 0x7ff0); | ||||
|     env->regs[R_EDX] = ldq_phys(cs->as, sm_state + 0x7fe8); | ||||
|     env->regs[R_EBX] = ldq_phys(cs->as, sm_state + 0x7fe0); | ||||
|     env->regs[R_ESP] = ldq_phys(cs->as, sm_state + 0x7fd8); | ||||
|     env->regs[R_EBP] = ldq_phys(cs->as, sm_state + 0x7fd0); | ||||
|     env->regs[R_ESI] = ldq_phys(cs->as, sm_state + 0x7fc8); | ||||
|     env->regs[R_EDI] = ldq_phys(cs->as, sm_state + 0x7fc0); | ||||
|     env->regs[R_EAX] = x86_ldq_phys(cs, sm_state + 0x7ff8); | ||||
|     env->regs[R_ECX] = x86_ldq_phys(cs, sm_state + 0x7ff0); | ||||
|     env->regs[R_EDX] = x86_ldq_phys(cs, sm_state + 0x7fe8); | ||||
|     env->regs[R_EBX] = x86_ldq_phys(cs, sm_state + 0x7fe0); | ||||
|     env->regs[R_ESP] = x86_ldq_phys(cs, sm_state + 0x7fd8); | ||||
|     env->regs[R_EBP] = x86_ldq_phys(cs, sm_state + 0x7fd0); | ||||
|     env->regs[R_ESI] = x86_ldq_phys(cs, sm_state + 0x7fc8); | ||||
|     env->regs[R_EDI] = x86_ldq_phys(cs, sm_state + 0x7fc0); | ||||
|     for (i = 8; i < 16; i++) { | ||||
|         env->regs[i] = ldq_phys(cs->as, sm_state + 0x7ff8 - i * 8); | ||||
|         env->regs[i] = x86_ldq_phys(cs, sm_state + 0x7ff8 - i * 8); | ||||
|     } | ||||
|     env->eip = ldq_phys(cs->as, sm_state + 0x7f78); | ||||
|     cpu_load_eflags(env, ldl_phys(cs->as, sm_state + 0x7f70), | ||||
|     env->eip = x86_ldq_phys(cs, sm_state + 0x7f78); | ||||
|     cpu_load_eflags(env, x86_ldl_phys(cs, sm_state + 0x7f70), | ||||
|                     ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); | ||||
|     env->dr[6] = ldl_phys(cs->as, sm_state + 0x7f68); | ||||
|     env->dr[7] = ldl_phys(cs->as, sm_state + 0x7f60); | ||||
|     env->dr[6] = x86_ldl_phys(cs, sm_state + 0x7f68); | ||||
|     env->dr[7] = x86_ldl_phys(cs, sm_state + 0x7f60); | ||||
| 
 | ||||
|     cpu_x86_update_cr4(env, ldl_phys(cs->as, sm_state + 0x7f48)); | ||||
|     cpu_x86_update_cr3(env, ldq_phys(cs->as, sm_state + 0x7f50)); | ||||
|     cpu_x86_update_cr0(env, ldl_phys(cs->as, sm_state + 0x7f58)); | ||||
|     cpu_x86_update_cr4(env, x86_ldl_phys(cs, sm_state + 0x7f48)); | ||||
|     cpu_x86_update_cr3(env, x86_ldq_phys(cs, sm_state + 0x7f50)); | ||||
|     cpu_x86_update_cr0(env, x86_ldl_phys(cs, sm_state + 0x7f58)); | ||||
| 
 | ||||
|     for (i = 0; i < 6; i++) { | ||||
|         offset = 0x7e00 + i * 16; | ||||
|         cpu_x86_load_seg_cache(env, i, | ||||
|                                lduw_phys(cs->as, sm_state + offset), | ||||
|                                ldq_phys(cs->as, sm_state + offset + 8), | ||||
|                                ldl_phys(cs->as, sm_state + offset + 4), | ||||
|                                (lduw_phys(cs->as, sm_state + offset + 2) & | ||||
|                                x86_lduw_phys(cs, sm_state + offset), | ||||
|                                x86_ldq_phys(cs, sm_state + offset + 8), | ||||
|                                x86_ldl_phys(cs, sm_state + offset + 4), | ||||
|                                (x86_lduw_phys(cs, sm_state + offset + 2) & | ||||
|                                 0xf0ff) << 8); | ||||
|     } | ||||
| 
 | ||||
|     val = ldl_phys(cs->as, sm_state + 0x7efc); /* revision ID */ | ||||
|     val = x86_ldl_phys(cs, sm_state + 0x7efc); /* revision ID */ | ||||
|     if (val & 0x20000) { | ||||
|         env->smbase = ldl_phys(cs->as, sm_state + 0x7f00) & ~0x7fff; | ||||
|         env->smbase = x86_ldl_phys(cs, sm_state + 0x7f00) & ~0x7fff; | ||||
|     } | ||||
| #else | ||||
|     cpu_x86_update_cr0(env, ldl_phys(cs->as, sm_state + 0x7ffc)); | ||||
|     cpu_x86_update_cr3(env, ldl_phys(cs->as, sm_state + 0x7ff8)); | ||||
|     cpu_load_eflags(env, ldl_phys(cs->as, sm_state + 0x7ff4), | ||||
|     cpu_x86_update_cr0(env, x86_ldl_phys(cs, sm_state + 0x7ffc)); | ||||
|     cpu_x86_update_cr3(env, x86_ldl_phys(cs, sm_state + 0x7ff8)); | ||||
|     cpu_load_eflags(env, x86_ldl_phys(cs, sm_state + 0x7ff4), | ||||
|                     ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); | ||||
|     env->eip = ldl_phys(cs->as, sm_state + 0x7ff0); | ||||
|     env->regs[R_EDI] = ldl_phys(cs->as, sm_state + 0x7fec); | ||||
|     env->regs[R_ESI] = ldl_phys(cs->as, sm_state + 0x7fe8); | ||||
|     env->regs[R_EBP] = ldl_phys(cs->as, sm_state + 0x7fe4); | ||||
|     env->regs[R_ESP] = ldl_phys(cs->as, sm_state + 0x7fe0); | ||||
|     env->regs[R_EBX] = ldl_phys(cs->as, sm_state + 0x7fdc); | ||||
|     env->regs[R_EDX] = ldl_phys(cs->as, sm_state + 0x7fd8); | ||||
|     env->regs[R_ECX] = ldl_phys(cs->as, sm_state + 0x7fd4); | ||||
|     env->regs[R_EAX] = ldl_phys(cs->as, sm_state + 0x7fd0); | ||||
|     env->dr[6] = ldl_phys(cs->as, sm_state + 0x7fcc); | ||||
|     env->dr[7] = ldl_phys(cs->as, sm_state + 0x7fc8); | ||||
|     env->eip = x86_ldl_phys(cs, sm_state + 0x7ff0); | ||||
|     env->regs[R_EDI] = x86_ldl_phys(cs, sm_state + 0x7fec); | ||||
|     env->regs[R_ESI] = x86_ldl_phys(cs, sm_state + 0x7fe8); | ||||
|     env->regs[R_EBP] = x86_ldl_phys(cs, sm_state + 0x7fe4); | ||||
|     env->regs[R_ESP] = x86_ldl_phys(cs, sm_state + 0x7fe0); | ||||
|     env->regs[R_EBX] = x86_ldl_phys(cs, sm_state + 0x7fdc); | ||||
|     env->regs[R_EDX] = x86_ldl_phys(cs, sm_state + 0x7fd8); | ||||
|     env->regs[R_ECX] = x86_ldl_phys(cs, sm_state + 0x7fd4); | ||||
|     env->regs[R_EAX] = x86_ldl_phys(cs, sm_state + 0x7fd0); | ||||
|     env->dr[6] = x86_ldl_phys(cs, sm_state + 0x7fcc); | ||||
|     env->dr[7] = x86_ldl_phys(cs, sm_state + 0x7fc8); | ||||
| 
 | ||||
|     env->tr.selector = ldl_phys(cs->as, sm_state + 0x7fc4) & 0xffff; | ||||
|     env->tr.base = ldl_phys(cs->as, sm_state + 0x7f64); | ||||
|     env->tr.limit = ldl_phys(cs->as, sm_state + 0x7f60); | ||||
|     env->tr.flags = (ldl_phys(cs->as, sm_state + 0x7f5c) & 0xf0ff) << 8; | ||||
|     env->tr.selector = x86_ldl_phys(cs, sm_state + 0x7fc4) & 0xffff; | ||||
|     env->tr.base = x86_ldl_phys(cs, sm_state + 0x7f64); | ||||
|     env->tr.limit = x86_ldl_phys(cs, sm_state + 0x7f60); | ||||
|     env->tr.flags = (x86_ldl_phys(cs, sm_state + 0x7f5c) & 0xf0ff) << 8; | ||||
| 
 | ||||
|     env->ldt.selector = ldl_phys(cs->as, sm_state + 0x7fc0) & 0xffff; | ||||
|     env->ldt.base = ldl_phys(cs->as, sm_state + 0x7f80); | ||||
|     env->ldt.limit = ldl_phys(cs->as, sm_state + 0x7f7c); | ||||
|     env->ldt.flags = (ldl_phys(cs->as, sm_state + 0x7f78) & 0xf0ff) << 8; | ||||
|     env->ldt.selector = x86_ldl_phys(cs, sm_state + 0x7fc0) & 0xffff; | ||||
|     env->ldt.base = x86_ldl_phys(cs, sm_state + 0x7f80); | ||||
|     env->ldt.limit = x86_ldl_phys(cs, sm_state + 0x7f7c); | ||||
|     env->ldt.flags = (x86_ldl_phys(cs, sm_state + 0x7f78) & 0xf0ff) << 8; | ||||
| 
 | ||||
|     env->gdt.base = ldl_phys(cs->as, sm_state + 0x7f74); | ||||
|     env->gdt.limit = ldl_phys(cs->as, sm_state + 0x7f70); | ||||
|     env->gdt.base = x86_ldl_phys(cs, sm_state + 0x7f74); | ||||
|     env->gdt.limit = x86_ldl_phys(cs, sm_state + 0x7f70); | ||||
| 
 | ||||
|     env->idt.base = ldl_phys(cs->as, sm_state + 0x7f58); | ||||
|     env->idt.limit = ldl_phys(cs->as, sm_state + 0x7f54); | ||||
|     env->idt.base = x86_ldl_phys(cs, sm_state + 0x7f58); | ||||
|     env->idt.limit = x86_ldl_phys(cs, sm_state + 0x7f54); | ||||
| 
 | ||||
|     for (i = 0; i < 6; i++) { | ||||
|         if (i < 3) { | ||||
| @ -293,22 +308,26 @@ void helper_rsm(CPUX86State *env) | ||||
|             offset = 0x7f2c + (i - 3) * 12; | ||||
|         } | ||||
|         cpu_x86_load_seg_cache(env, i, | ||||
|                                ldl_phys(cs->as, | ||||
|                                x86_ldl_phys(cs, | ||||
|                                         sm_state + 0x7fa8 + i * 4) & 0xffff, | ||||
|                                ldl_phys(cs->as, sm_state + offset + 8), | ||||
|                                ldl_phys(cs->as, sm_state + offset + 4), | ||||
|                                (ldl_phys(cs->as, | ||||
|                                x86_ldl_phys(cs, sm_state + offset + 8), | ||||
|                                x86_ldl_phys(cs, sm_state + offset + 4), | ||||
|                                (x86_ldl_phys(cs, | ||||
|                                          sm_state + offset) & 0xf0ff) << 8); | ||||
|     } | ||||
|     cpu_x86_update_cr4(env, ldl_phys(cs->as, sm_state + 0x7f14)); | ||||
|     cpu_x86_update_cr4(env, x86_ldl_phys(cs, sm_state + 0x7f14)); | ||||
| 
 | ||||
|     val = ldl_phys(cs->as, sm_state + 0x7efc); /* revision ID */ | ||||
|     val = x86_ldl_phys(cs, sm_state + 0x7efc); /* revision ID */ | ||||
|     if (val & 0x20000) { | ||||
|         env->smbase = ldl_phys(cs->as, sm_state + 0x7ef8) & ~0x7fff; | ||||
|         env->smbase = x86_ldl_phys(cs, sm_state + 0x7ef8) & ~0x7fff; | ||||
|     } | ||||
| #endif | ||||
|     if ((env->hflags2 & HF2_SMM_INSIDE_NMI_MASK) == 0) { | ||||
|         env->hflags2 &= ~HF2_NMI_MASK; | ||||
|     } | ||||
|     env->hflags2 &= ~HF2_SMM_INSIDE_NMI_MASK; | ||||
|     env->hflags &= ~HF_SMM_MASK; | ||||
|     cpu_smm_update(env); | ||||
|     cpu_smm_update(cpu); | ||||
| 
 | ||||
|     qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n"); | ||||
|     log_cpu_state_mask(CPU_LOG_INT, CPU(cpu), CPU_DUMP_CCOP); | ||||
|  | ||||
| @ -87,13 +87,13 @@ static inline void svm_save_seg(CPUX86State *env, hwaddr addr, | ||||
| { | ||||
|     CPUState *cs = CPU(x86_env_get_cpu(env)); | ||||
| 
 | ||||
|     stw_phys(cs->as, addr + offsetof(struct vmcb_seg, selector), | ||||
|     x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, selector), | ||||
|              sc->selector); | ||||
|     stq_phys(cs->as, addr + offsetof(struct vmcb_seg, base), | ||||
|     x86_stq_phys(cs, addr + offsetof(struct vmcb_seg, base), | ||||
|              sc->base); | ||||
|     stl_phys(cs->as, addr + offsetof(struct vmcb_seg, limit), | ||||
|     x86_stl_phys(cs, addr + offsetof(struct vmcb_seg, limit), | ||||
|              sc->limit); | ||||
|     stw_phys(cs->as, addr + offsetof(struct vmcb_seg, attrib), | ||||
|     x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, attrib), | ||||
|              ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00)); | ||||
| } | ||||
| 
 | ||||
| @ -103,11 +103,11 @@ static inline void svm_load_seg(CPUX86State *env, hwaddr addr, | ||||
|     CPUState *cs = CPU(x86_env_get_cpu(env)); | ||||
|     unsigned int flags; | ||||
| 
 | ||||
|     sc->selector = lduw_phys(cs->as, | ||||
|     sc->selector = x86_lduw_phys(cs, | ||||
|                              addr + offsetof(struct vmcb_seg, selector)); | ||||
|     sc->base = ldq_phys(cs->as, addr + offsetof(struct vmcb_seg, base)); | ||||
|     sc->limit = ldl_phys(cs->as, addr + offsetof(struct vmcb_seg, limit)); | ||||
|     flags = lduw_phys(cs->as, addr + offsetof(struct vmcb_seg, attrib)); | ||||
|     sc->base = x86_ldq_phys(cs, addr + offsetof(struct vmcb_seg, base)); | ||||
|     sc->limit = x86_ldl_phys(cs, addr + offsetof(struct vmcb_seg, limit)); | ||||
|     flags = x86_lduw_phys(cs, addr + offsetof(struct vmcb_seg, attrib)); | ||||
|     sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12); | ||||
| } | ||||
| 
 | ||||
| @ -141,32 +141,32 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) | ||||
|     env->vm_vmcb = addr; | ||||
| 
 | ||||
|     /* save the current CPU state in the hsave page */ | ||||
|     stq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), | ||||
|     x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), | ||||
|              env->gdt.base); | ||||
|     stl_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), | ||||
|     x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), | ||||
|              env->gdt.limit); | ||||
| 
 | ||||
|     stq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, save.idtr.base), | ||||
|     x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.base), | ||||
|              env->idt.base); | ||||
|     stl_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), | ||||
|     x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), | ||||
|              env->idt.limit); | ||||
| 
 | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]); | ||||
| 
 | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_hsave + offsetof(struct vmcb, save.rflags), | ||||
|              cpu_compute_eflags(env)); | ||||
| 
 | ||||
| @ -179,30 +179,30 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) | ||||
|     svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ds), | ||||
|                  &env->segs[R_DS]); | ||||
| 
 | ||||
|     stq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, save.rip), | ||||
|     x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.rip), | ||||
|              env->eip + next_eip_addend); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_hsave + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_hsave + offsetof(struct vmcb, save.rax), env->regs[R_EAX]); | ||||
| 
 | ||||
|     /* load the interception bitmaps so we do not need to access the
 | ||||
|        vmcb in svm mode */ | ||||
|     env->intercept = ldq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, | ||||
|     env->intercept = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                                       control.intercept)); | ||||
|     env->intercept_cr_read = lduw_phys(cs->as, env->vm_vmcb + | ||||
|     env->intercept_cr_read = x86_lduw_phys(cs, env->vm_vmcb + | ||||
|                                        offsetof(struct vmcb, | ||||
|                                                 control.intercept_cr_read)); | ||||
|     env->intercept_cr_write = lduw_phys(cs->as, env->vm_vmcb + | ||||
|     env->intercept_cr_write = x86_lduw_phys(cs, env->vm_vmcb + | ||||
|                                         offsetof(struct vmcb, | ||||
|                                                  control.intercept_cr_write)); | ||||
|     env->intercept_dr_read = lduw_phys(cs->as, env->vm_vmcb + | ||||
|     env->intercept_dr_read = x86_lduw_phys(cs, env->vm_vmcb + | ||||
|                                        offsetof(struct vmcb, | ||||
|                                                 control.intercept_dr_read)); | ||||
|     env->intercept_dr_write = lduw_phys(cs->as, env->vm_vmcb + | ||||
|     env->intercept_dr_write = x86_lduw_phys(cs, env->vm_vmcb + | ||||
|                                         offsetof(struct vmcb, | ||||
|                                                  control.intercept_dr_write)); | ||||
|     env->intercept_exceptions = ldl_phys(cs->as, env->vm_vmcb + | ||||
|     env->intercept_exceptions = x86_ldl_phys(cs, env->vm_vmcb + | ||||
|                                          offsetof(struct vmcb, | ||||
|                                                   control.intercept_exceptions | ||||
|                                                   )); | ||||
| @ -210,35 +210,35 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) | ||||
|     /* enable intercepts */ | ||||
|     env->hflags |= HF_SVMI_MASK; | ||||
| 
 | ||||
|     env->tsc_offset = ldq_phys(cs->as, env->vm_vmcb + | ||||
|     env->tsc_offset = x86_ldq_phys(cs, env->vm_vmcb + | ||||
|                                offsetof(struct vmcb, control.tsc_offset)); | ||||
| 
 | ||||
|     env->gdt.base  = ldq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, | ||||
|     env->gdt.base  = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                                       save.gdtr.base)); | ||||
|     env->gdt.limit = ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, | ||||
|     env->gdt.limit = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                                       save.gdtr.limit)); | ||||
| 
 | ||||
|     env->idt.base  = ldq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, | ||||
|     env->idt.base  = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                                       save.idtr.base)); | ||||
|     env->idt.limit = ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, | ||||
|     env->idt.limit = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                                       save.idtr.limit)); | ||||
| 
 | ||||
|     /* clear exit_info_2 so we behave like the real hardware */ | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0); | ||||
| 
 | ||||
|     cpu_x86_update_cr0(env, ldq_phys(cs->as, | ||||
|     cpu_x86_update_cr0(env, x86_ldq_phys(cs, | ||||
|                                      env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                                              save.cr0))); | ||||
|     cpu_x86_update_cr4(env, ldq_phys(cs->as, | ||||
|     cpu_x86_update_cr4(env, x86_ldq_phys(cs, | ||||
|                                      env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                                              save.cr4))); | ||||
|     cpu_x86_update_cr3(env, ldq_phys(cs->as, | ||||
|     cpu_x86_update_cr3(env, x86_ldq_phys(cs, | ||||
|                                      env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                                              save.cr3))); | ||||
|     env->cr[2] = ldq_phys(cs->as, | ||||
|     env->cr[2] = x86_ldq_phys(cs, | ||||
|                           env->vm_vmcb + offsetof(struct vmcb, save.cr2)); | ||||
|     int_ctl = ldl_phys(cs->as, | ||||
|     int_ctl = x86_ldl_phys(cs, | ||||
|                        env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); | ||||
|     env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK); | ||||
|     if (int_ctl & V_INTR_MASKING_MASK) { | ||||
| @ -250,10 +250,10 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) | ||||
|     } | ||||
| 
 | ||||
|     cpu_load_efer(env, | ||||
|                   ldq_phys(cs->as, | ||||
|                   x86_ldq_phys(cs, | ||||
|                            env->vm_vmcb + offsetof(struct vmcb, save.efer))); | ||||
|     env->eflags = 0; | ||||
|     cpu_load_eflags(env, ldq_phys(cs->as, | ||||
|     cpu_load_eflags(env, x86_ldq_phys(cs, | ||||
|                                   env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                                           save.rflags)), | ||||
|                     ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); | ||||
| @ -267,21 +267,21 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) | ||||
|     svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds), | ||||
|                        R_DS); | ||||
| 
 | ||||
|     env->eip = ldq_phys(cs->as, | ||||
|     env->eip = x86_ldq_phys(cs, | ||||
|                         env->vm_vmcb + offsetof(struct vmcb, save.rip)); | ||||
| 
 | ||||
|     env->regs[R_ESP] = ldq_phys(cs->as, | ||||
|     env->regs[R_ESP] = x86_ldq_phys(cs, | ||||
|                                 env->vm_vmcb + offsetof(struct vmcb, save.rsp)); | ||||
|     env->regs[R_EAX] = ldq_phys(cs->as, | ||||
|     env->regs[R_EAX] = x86_ldq_phys(cs, | ||||
|                                 env->vm_vmcb + offsetof(struct vmcb, save.rax)); | ||||
|     env->dr[7] = ldq_phys(cs->as, | ||||
|     env->dr[7] = x86_ldq_phys(cs, | ||||
|                           env->vm_vmcb + offsetof(struct vmcb, save.dr7)); | ||||
|     env->dr[6] = ldq_phys(cs->as, | ||||
|     env->dr[6] = x86_ldq_phys(cs, | ||||
|                           env->vm_vmcb + offsetof(struct vmcb, save.dr6)); | ||||
| 
 | ||||
|     /* FIXME: guest state consistency checks */ | ||||
| 
 | ||||
|     switch (ldub_phys(cs->as, | ||||
|     switch (x86_ldub_phys(cs, | ||||
|                       env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) { | ||||
|     case TLB_CONTROL_DO_NOTHING: | ||||
|         break; | ||||
| @ -300,12 +300,12 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) | ||||
|     } | ||||
| 
 | ||||
|     /* maybe we need to inject an event */ | ||||
|     event_inj = ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, | ||||
|     event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                                  control.event_inj)); | ||||
|     if (event_inj & SVM_EVTINJ_VALID) { | ||||
|         uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK; | ||||
|         uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR; | ||||
|         uint32_t event_inj_err = ldl_phys(cs->as, env->vm_vmcb + | ||||
|         uint32_t event_inj_err = x86_ldl_phys(cs, env->vm_vmcb + | ||||
|                                           offsetof(struct vmcb, | ||||
|                                                    control.event_inj_err)); | ||||
| 
 | ||||
| @ -372,7 +372,7 @@ void helper_vmload(CPUX86State *env, int aflag) | ||||
| 
 | ||||
|     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx | ||||
|                   "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", | ||||
|                   addr, ldq_phys(cs->as, addr + offsetof(struct vmcb, | ||||
|                   addr, x86_ldq_phys(cs, addr + offsetof(struct vmcb, | ||||
|                                                           save.fs.base)), | ||||
|                   env->segs[R_FS].base); | ||||
| 
 | ||||
| @ -382,18 +382,18 @@ void helper_vmload(CPUX86State *env, int aflag) | ||||
|     svm_load_seg(env, addr + offsetof(struct vmcb, save.ldtr), &env->ldt); | ||||
| 
 | ||||
| #ifdef TARGET_X86_64 | ||||
|     env->kernelgsbase = ldq_phys(cs->as, addr + offsetof(struct vmcb, | ||||
|     env->kernelgsbase = x86_ldq_phys(cs, addr + offsetof(struct vmcb, | ||||
|                                                  save.kernel_gs_base)); | ||||
|     env->lstar = ldq_phys(cs->as, addr + offsetof(struct vmcb, save.lstar)); | ||||
|     env->cstar = ldq_phys(cs->as, addr + offsetof(struct vmcb, save.cstar)); | ||||
|     env->fmask = ldq_phys(cs->as, addr + offsetof(struct vmcb, save.sfmask)); | ||||
|     env->lstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.lstar)); | ||||
|     env->cstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.cstar)); | ||||
|     env->fmask = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.sfmask)); | ||||
| #endif | ||||
|     env->star = ldq_phys(cs->as, addr + offsetof(struct vmcb, save.star)); | ||||
|     env->sysenter_cs = ldq_phys(cs->as, | ||||
|     env->star = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.star)); | ||||
|     env->sysenter_cs = x86_ldq_phys(cs, | ||||
|                                 addr + offsetof(struct vmcb, save.sysenter_cs)); | ||||
|     env->sysenter_esp = ldq_phys(cs->as, addr + offsetof(struct vmcb, | ||||
|     env->sysenter_esp = x86_ldq_phys(cs, addr + offsetof(struct vmcb, | ||||
|                                                  save.sysenter_esp)); | ||||
|     env->sysenter_eip = ldq_phys(cs->as, addr + offsetof(struct vmcb, | ||||
|     env->sysenter_eip = x86_ldq_phys(cs, addr + offsetof(struct vmcb, | ||||
|                                                  save.sysenter_eip)); | ||||
| } | ||||
| 
 | ||||
| @ -412,7 +412,7 @@ void helper_vmsave(CPUX86State *env, int aflag) | ||||
| 
 | ||||
|     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx | ||||
|                   "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", | ||||
|                   addr, ldq_phys(cs->as, | ||||
|                   addr, x86_ldq_phys(cs, | ||||
|                                  addr + offsetof(struct vmcb, save.fs.base)), | ||||
|                   env->segs[R_FS].base); | ||||
| 
 | ||||
| @ -426,18 +426,18 @@ void helper_vmsave(CPUX86State *env, int aflag) | ||||
|                  &env->ldt); | ||||
| 
 | ||||
| #ifdef TARGET_X86_64 | ||||
|     stq_phys(cs->as, addr + offsetof(struct vmcb, save.kernel_gs_base), | ||||
|     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.kernel_gs_base), | ||||
|              env->kernelgsbase); | ||||
|     stq_phys(cs->as, addr + offsetof(struct vmcb, save.lstar), env->lstar); | ||||
|     stq_phys(cs->as, addr + offsetof(struct vmcb, save.cstar), env->cstar); | ||||
|     stq_phys(cs->as, addr + offsetof(struct vmcb, save.sfmask), env->fmask); | ||||
|     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.lstar), env->lstar); | ||||
|     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.cstar), env->cstar); | ||||
|     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sfmask), env->fmask); | ||||
| #endif | ||||
|     stq_phys(cs->as, addr + offsetof(struct vmcb, save.star), env->star); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.star), env->star); | ||||
|     x86_stq_phys(cs, | ||||
|              addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs); | ||||
|     stq_phys(cs->as, addr + offsetof(struct vmcb, save.sysenter_esp), | ||||
|     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_esp), | ||||
|              env->sysenter_esp); | ||||
|     stq_phys(cs->as, addr + offsetof(struct vmcb, save.sysenter_eip), | ||||
|     x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_eip), | ||||
|              env->sysenter_eip); | ||||
| } | ||||
| 
 | ||||
| @ -515,7 +515,7 @@ void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, | ||||
|     case SVM_EXIT_MSR: | ||||
|         if (env->intercept & (1ULL << (SVM_EXIT_MSR - SVM_EXIT_INTR))) { | ||||
|             /* FIXME: this should be read in at vmrun (faster this way?) */ | ||||
|             uint64_t addr = ldq_phys(cs->as, env->vm_vmcb + | ||||
|             uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb + | ||||
|                                      offsetof(struct vmcb, | ||||
|                                               control.msrpm_base_pa)); | ||||
|             uint32_t t0, t1; | ||||
| @ -541,7 +541,7 @@ void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, | ||||
|                 t1 = 0; | ||||
|                 break; | ||||
|             } | ||||
|             if (ldub_phys(cs->as, addr + t1) & ((1 << param) << t0)) { | ||||
|             if (x86_ldub_phys(cs, addr + t1) & ((1 << param) << t0)) { | ||||
|                 helper_vmexit(env, type, param); | ||||
|             } | ||||
|         } | ||||
| @ -567,13 +567,13 @@ void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param, | ||||
| 
 | ||||
|     if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) { | ||||
|         /* FIXME: this should be read in at vmrun (faster this way?) */ | ||||
|         uint64_t addr = ldq_phys(cs->as, env->vm_vmcb + | ||||
|         uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb + | ||||
|                                  offsetof(struct vmcb, control.iopm_base_pa)); | ||||
|         uint16_t mask = (1 << ((param >> 4) & 7)) - 1; | ||||
| 
 | ||||
|         if (lduw_phys(cs->as, addr + port / 8) & (mask << (port & 7))) { | ||||
|         if (x86_lduw_phys(cs, addr + port / 8) & (mask << (port & 7))) { | ||||
|             /* next env->eip */ | ||||
|             stq_phys(cs->as, | ||||
|             x86_stq_phys(cs, | ||||
|                      env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), | ||||
|                      env->eip + next_eip_addend); | ||||
|             helper_vmexit(env, SVM_EXIT_IOIO, param | (port << 16)); | ||||
| @ -590,17 +590,17 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) | ||||
|     qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" | ||||
|                   PRIx64 ", " TARGET_FMT_lx ")!\n", | ||||
|                   exit_code, exit_info_1, | ||||
|                   ldq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, | ||||
|                   x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                                    control.exit_info_2)), | ||||
|                   env->eip); | ||||
| 
 | ||||
|     if (env->hflags & HF_INHIBIT_IRQ_MASK) { | ||||
|         stl_phys(cs->as, | ||||
|         x86_stl_phys(cs, | ||||
|                  env->vm_vmcb + offsetof(struct vmcb, control.int_state), | ||||
|                  SVM_INTERRUPT_SHADOW_MASK); | ||||
|         env->hflags &= ~HF_INHIBIT_IRQ_MASK; | ||||
|     } else { | ||||
|         stl_phys(cs->as, | ||||
|         x86_stl_phys(cs, | ||||
|                  env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0); | ||||
|     } | ||||
| 
 | ||||
| @ -614,50 +614,50 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) | ||||
|     svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ds), | ||||
|                  &env->segs[R_DS]); | ||||
| 
 | ||||
|     stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), | ||||
|     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), | ||||
|              env->gdt.base); | ||||
|     stl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), | ||||
|     x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), | ||||
|              env->gdt.limit); | ||||
| 
 | ||||
|     stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), | ||||
|     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), | ||||
|              env->idt.base); | ||||
|     stl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), | ||||
|     x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), | ||||
|              env->idt.limit); | ||||
| 
 | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]); | ||||
| 
 | ||||
|     int_ctl = ldl_phys(cs->as, | ||||
|     int_ctl = x86_ldl_phys(cs, | ||||
|                        env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); | ||||
|     int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK); | ||||
|     int_ctl |= env->v_tpr & V_TPR_MASK; | ||||
|     if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) { | ||||
|         int_ctl |= V_IRQ_MASK; | ||||
|     } | ||||
|     stl_phys(cs->as, | ||||
|     x86_stl_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl); | ||||
| 
 | ||||
|     stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.rflags), | ||||
|     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rflags), | ||||
|              cpu_compute_eflags(env)); | ||||
|     stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.rip), | ||||
|     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rip), | ||||
|              env->eip); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, save.rax), env->regs[R_EAX]); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]); | ||||
|     stq_phys(cs->as, | ||||
|     x86_stq_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]); | ||||
|     stb_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, save.cpl), | ||||
|     x86_stb_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cpl), | ||||
|              env->hflags & HF_CPL_MASK); | ||||
| 
 | ||||
|     /* Reload the host state from vm_hsave */ | ||||
| @ -668,32 +668,32 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) | ||||
|     cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ; | ||||
|     env->tsc_offset = 0; | ||||
| 
 | ||||
|     env->gdt.base  = ldq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, | ||||
|     env->gdt.base  = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb, | ||||
|                                                        save.gdtr.base)); | ||||
|     env->gdt.limit = ldl_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, | ||||
|     env->gdt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb, | ||||
|                                                        save.gdtr.limit)); | ||||
| 
 | ||||
|     env->idt.base  = ldq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, | ||||
|     env->idt.base  = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb, | ||||
|                                                        save.idtr.base)); | ||||
|     env->idt.limit = ldl_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, | ||||
|     env->idt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb, | ||||
|                                                        save.idtr.limit)); | ||||
| 
 | ||||
|     cpu_x86_update_cr0(env, ldq_phys(cs->as, | ||||
|     cpu_x86_update_cr0(env, x86_ldq_phys(cs, | ||||
|                                      env->vm_hsave + offsetof(struct vmcb, | ||||
|                                                               save.cr0)) | | ||||
|                        CR0_PE_MASK); | ||||
|     cpu_x86_update_cr4(env, ldq_phys(cs->as, | ||||
|     cpu_x86_update_cr4(env, x86_ldq_phys(cs, | ||||
|                                      env->vm_hsave + offsetof(struct vmcb, | ||||
|                                                               save.cr4))); | ||||
|     cpu_x86_update_cr3(env, ldq_phys(cs->as, | ||||
|     cpu_x86_update_cr3(env, x86_ldq_phys(cs, | ||||
|                                      env->vm_hsave + offsetof(struct vmcb, | ||||
|                                                               save.cr3))); | ||||
|     /* we need to set the efer after the crs so the hidden flags get
 | ||||
|        set properly */ | ||||
|     cpu_load_efer(env, ldq_phys(cs->as, env->vm_hsave + offsetof(struct vmcb, | ||||
|     cpu_load_efer(env, x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb, | ||||
|                                                          save.efer))); | ||||
|     env->eflags = 0; | ||||
|     cpu_load_eflags(env, ldq_phys(cs->as, | ||||
|     cpu_load_eflags(env, x86_ldq_phys(cs, | ||||
|                                   env->vm_hsave + offsetof(struct vmcb, | ||||
|                                                            save.rflags)), | ||||
|                     ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK | | ||||
| @ -708,33 +708,33 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) | ||||
|     svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ds), | ||||
|                        R_DS); | ||||
| 
 | ||||
|     env->eip = ldq_phys(cs->as, | ||||
|     env->eip = x86_ldq_phys(cs, | ||||
|                         env->vm_hsave + offsetof(struct vmcb, save.rip)); | ||||
|     env->regs[R_ESP] = ldq_phys(cs->as, env->vm_hsave + | ||||
|     env->regs[R_ESP] = x86_ldq_phys(cs, env->vm_hsave + | ||||
|                                 offsetof(struct vmcb, save.rsp)); | ||||
|     env->regs[R_EAX] = ldq_phys(cs->as, env->vm_hsave + | ||||
|     env->regs[R_EAX] = x86_ldq_phys(cs, env->vm_hsave + | ||||
|                                 offsetof(struct vmcb, save.rax)); | ||||
| 
 | ||||
|     env->dr[6] = ldq_phys(cs->as, | ||||
|     env->dr[6] = x86_ldq_phys(cs, | ||||
|                           env->vm_hsave + offsetof(struct vmcb, save.dr6)); | ||||
|     env->dr[7] = ldq_phys(cs->as, | ||||
|     env->dr[7] = x86_ldq_phys(cs, | ||||
|                           env->vm_hsave + offsetof(struct vmcb, save.dr7)); | ||||
| 
 | ||||
|     /* other setups */ | ||||
|     stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, control.exit_code), | ||||
|     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_code), | ||||
|              exit_code); | ||||
|     stq_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), | ||||
|     x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), | ||||
|              exit_info_1); | ||||
| 
 | ||||
|     stl_phys(cs->as, | ||||
|     x86_stl_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info), | ||||
|              ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, | ||||
|              x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                               control.event_inj))); | ||||
|     stl_phys(cs->as, | ||||
|     x86_stl_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err), | ||||
|              ldl_phys(cs->as, env->vm_vmcb + offsetof(struct vmcb, | ||||
|              x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, | ||||
|                                               control.event_inj_err))); | ||||
|     stl_phys(cs->as, | ||||
|     x86_stl_phys(cs, | ||||
|              env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0); | ||||
| 
 | ||||
|     env->hflags2 &= ~HF2_GIF_MASK; | ||||
|  | ||||
| @ -631,13 +631,13 @@ static void gen_helper_in_func(TCGMemOp ot, TCGv v, TCGv_i32 n) | ||||
| { | ||||
|     switch (ot) { | ||||
|     case MO_8: | ||||
|         gen_helper_inb(v, n); | ||||
|         gen_helper_inb(v, cpu_env, n); | ||||
|         break; | ||||
|     case MO_16: | ||||
|         gen_helper_inw(v, n); | ||||
|         gen_helper_inw(v, cpu_env, n); | ||||
|         break; | ||||
|     case MO_32: | ||||
|         gen_helper_inl(v, n); | ||||
|         gen_helper_inl(v, cpu_env, n); | ||||
|         break; | ||||
|     default: | ||||
|         tcg_abort(); | ||||
| @ -648,13 +648,13 @@ static void gen_helper_out_func(TCGMemOp ot, TCGv_i32 v, TCGv_i32 n) | ||||
| { | ||||
|     switch (ot) { | ||||
|     case MO_8: | ||||
|         gen_helper_outb(v, n); | ||||
|         gen_helper_outb(cpu_env, v, n); | ||||
|         break; | ||||
|     case MO_16: | ||||
|         gen_helper_outw(v, n); | ||||
|         gen_helper_outw(cpu_env, v, n); | ||||
|         break; | ||||
|     case MO_32: | ||||
|         gen_helper_outl(v, n); | ||||
|         gen_helper_outl(cpu_env, v, n); | ||||
|         break; | ||||
|     default: | ||||
|         tcg_abort(); | ||||
|  | ||||
| @ -174,6 +174,8 @@ gcov-files-i386-y += hw/usb/dev-storage.c | ||||
| check-qtest-i386-y += tests/usb-hcd-xhci-test$(EXESUF) | ||||
| gcov-files-i386-y += hw/usb/hcd-xhci.c | ||||
| check-qtest-i386-y += tests/pc-cpu-test$(EXESUF) | ||||
| check-qtest-i386-y += tests/q35-test$(EXESUF) | ||||
| gcov-files-i386-y += hw/pci-host/q35.c | ||||
| check-qtest-i386-$(CONFIG_LINUX) += tests/vhost-user-test$(EXESUF) | ||||
| check-qtest-x86_64-y = $(check-qtest-i386-y) | ||||
| gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c | ||||
| @ -355,6 +357,7 @@ tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) | ||||
| tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y) | ||||
| tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) | ||||
| tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y) | ||||
| tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y) | ||||
| tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y) | ||||
| tests/e1000-test$(EXESUF): tests/e1000-test.o | ||||
| tests/rtl8139-test$(EXESUF): tests/rtl8139-test.o $(libqos-pc-obj-y) | ||||
|  | ||||
							
								
								
									
										91
									
								
								tests/q35-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								tests/q35-test.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | ||||
| /*
 | ||||
|  * QTest testcase for Q35 northbridge | ||||
|  * | ||||
|  * Copyright (c) 2015 Red Hat, Inc. | ||||
|  * | ||||
|  * Author: Gerd Hoffmann <kraxel@redhat.com> | ||||
|  * | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||||
|  * See the COPYING file in the top-level directory. | ||||
|  */ | ||||
| 
 | ||||
| #include <glib.h> | ||||
| #include <string.h> | ||||
| #include "libqtest.h" | ||||
| #include "libqos/pci.h" | ||||
| #include "libqos/pci-pc.h" | ||||
| #include "qemu/osdep.h" | ||||
| #include "hw/pci-host/q35.h" | ||||
| 
 | ||||
| static void smram_set_bit(QPCIDevice *pcidev, uint8_t mask, bool enabled) | ||||
| { | ||||
|     uint8_t smram; | ||||
| 
 | ||||
|     smram = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM); | ||||
|     if (enabled) { | ||||
|         smram |= mask; | ||||
|     } else { | ||||
|         smram &= ~mask; | ||||
|     } | ||||
|     qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram); | ||||
| } | ||||
| 
 | ||||
| static bool smram_test_bit(QPCIDevice *pcidev, uint8_t mask) | ||||
| { | ||||
|     uint8_t smram; | ||||
| 
 | ||||
|     smram = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM); | ||||
|     return smram & mask; | ||||
| } | ||||
| 
 | ||||
| static void test_smram_lock(void) | ||||
| { | ||||
|     QPCIBus *pcibus; | ||||
|     QPCIDevice *pcidev; | ||||
|     QDict *response; | ||||
| 
 | ||||
|     pcibus = qpci_init_pc(); | ||||
|     g_assert(pcibus != NULL); | ||||
| 
 | ||||
|     pcidev = qpci_device_find(pcibus, 0); | ||||
|     g_assert(pcidev != NULL); | ||||
| 
 | ||||
|     /* check open is settable */ | ||||
|     smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false); | ||||
|     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false); | ||||
|     smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true); | ||||
|     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == true); | ||||
| 
 | ||||
|     /* lock, check open is cleared & not settable */ | ||||
|     smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_LCK, true); | ||||
|     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false); | ||||
|     smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true); | ||||
|     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false); | ||||
| 
 | ||||
|     /* reset */ | ||||
|     response = qmp("{'execute': 'system_reset', 'arguments': {} }"); | ||||
|     g_assert(response); | ||||
|     g_assert(!qdict_haskey(response, "error")); | ||||
|     QDECREF(response); | ||||
| 
 | ||||
|     /* check open is settable again */ | ||||
|     smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false); | ||||
|     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false); | ||||
|     smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true); | ||||
|     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == true); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
|     int ret; | ||||
| 
 | ||||
|     g_test_init(&argc, &argv, NULL); | ||||
| 
 | ||||
|     qtest_add_func("/q35/smram/lock", test_smram_lock); | ||||
| 
 | ||||
|     qtest_start("-M q35"); | ||||
|     ret = g_test_run(); | ||||
|     qtest_end(); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| @ -1042,11 +1042,10 @@ TranslationBlock *tb_gen_code(CPUState *cpu, | ||||
|  * access: the virtual CPU will exit the current TB if code is modified inside | ||||
|  * this TB. | ||||
|  */ | ||||
| void tb_invalidate_phys_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) | ||||
| { | ||||
|     while (start < end) { | ||||
|         tb_invalidate_phys_page_range(start, end, is_cpu_write_access); | ||||
|         tb_invalidate_phys_page_range(start, end, 0); | ||||
|         start &= TARGET_PAGE_MASK; | ||||
|         start += TARGET_PAGE_SIZE; | ||||
|     } | ||||
| @ -1083,12 +1082,6 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, | ||||
|     if (!p) { | ||||
|         return; | ||||
|     } | ||||
|     if (!p->code_bitmap && | ||||
|         ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD && | ||||
|         is_cpu_write_access) { | ||||
|         /* build code bitmap */ | ||||
|         build_page_bitmap(p); | ||||
|     } | ||||
| #if defined(TARGET_HAS_PRECISE_SMC) | ||||
|     if (cpu != NULL) { | ||||
|         env = cpu->env_ptr; | ||||
| @ -1158,9 +1151,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, | ||||
|     /* if no code remaining, no need to continue to use slow writes */ | ||||
|     if (!p->first_tb) { | ||||
|         invalidate_page_bitmap(p); | ||||
|         if (is_cpu_write_access) { | ||||
|             tlb_unprotect_code_phys(cpu, start, cpu->mem_io_vaddr); | ||||
|         } | ||||
|         tlb_unprotect_code(start); | ||||
|     } | ||||
| #endif | ||||
| #ifdef TARGET_HAS_PRECISE_SMC | ||||
| @ -1193,6 +1184,11 @@ void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len) | ||||
|     if (!p) { | ||||
|         return; | ||||
|     } | ||||
|     if (!p->code_bitmap && | ||||
|         ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD) { | ||||
|         /* build code bitmap */ | ||||
|         build_page_bitmap(p); | ||||
|     } | ||||
|     if (p->code_bitmap) { | ||||
|         unsigned int nr; | ||||
|         unsigned long b; | ||||
|  | ||||
| @ -21,6 +21,13 @@ | ||||
| 
 | ||||
| /* translate-all.c */ | ||||
| void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len); | ||||
| 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); | ||||
| void tb_check_watchpoint(CPUState *cpu); | ||||
| 
 | ||||
| #ifdef CONFIG_USER_ONLY | ||||
| int page_unprotect(target_ulong address, uintptr_t pc, void *puc); | ||||
| #endif | ||||
| 
 | ||||
| #endif /* TRANSLATE_ALL_H */ | ||||
|  | ||||
							
								
								
									
										61
									
								
								ui/console.c
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								ui/console.c
									
									
									
									
									
								
							| @ -1619,67 +1619,6 @@ bool dpy_cursor_define_supported(QemuConsole *con) | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Call dpy_gfx_update for all dirity scanlines.  Works for | ||||
|  * DisplaySurfaces backed by guest memory (i.e. the ones created | ||||
|  * using qemu_create_displaysurface_guestmem). | ||||
|  */ | ||||
| void dpy_gfx_update_dirty(QemuConsole *con, | ||||
|                           MemoryRegion *address_space, | ||||
|                           hwaddr base, | ||||
|                           bool invalidate) | ||||
| { | ||||
|     DisplaySurface *ds = qemu_console_surface(con); | ||||
|     int width = surface_stride(ds); | ||||
|     int height = surface_height(ds); | ||||
|     hwaddr size = width * height; | ||||
|     MemoryRegionSection mem_section; | ||||
|     MemoryRegion *mem; | ||||
|     ram_addr_t addr; | ||||
|     int first, last, i; | ||||
|     bool dirty; | ||||
| 
 | ||||
|     mem_section = memory_region_find(address_space, base, size); | ||||
|     mem = mem_section.mr; | ||||
|     if (int128_get64(mem_section.size) != size || | ||||
|         !memory_region_is_ram(mem_section.mr)) { | ||||
|         goto out; | ||||
|     } | ||||
|     assert(mem); | ||||
| 
 | ||||
|     memory_region_sync_dirty_bitmap(mem); | ||||
|     addr = mem_section.offset_within_region; | ||||
| 
 | ||||
|     first = -1; | ||||
|     last = -1; | ||||
|     for (i = 0; i < height; i++, addr += width) { | ||||
|         dirty = invalidate || | ||||
|             memory_region_get_dirty(mem, addr, width, DIRTY_MEMORY_VGA); | ||||
|         if (dirty) { | ||||
|             if (first == -1) { | ||||
|                 first = i; | ||||
|             } | ||||
|             last = i; | ||||
|         } | ||||
|         if (first != -1 && !dirty) { | ||||
|             assert(last != -1 && last >= first); | ||||
|             dpy_gfx_update(con, 0, first, surface_width(ds), | ||||
|                            last - first + 1); | ||||
|             first = -1; | ||||
|         } | ||||
|     } | ||||
|     if (first != -1) { | ||||
|         assert(last != -1 && last >= first); | ||||
|         dpy_gfx_update(con, 0, first, surface_width(ds), | ||||
|                        last - first + 1); | ||||
|     } | ||||
| 
 | ||||
|     memory_region_reset_dirty(mem, mem_section.offset_within_region, size, | ||||
|                               DIRTY_MEMORY_VGA); | ||||
| out: | ||||
|     memory_region_unref(mem); | ||||
| } | ||||
| 
 | ||||
| /***********************************************************/ | ||||
| /* register display */ | ||||
| 
 | ||||
|  | ||||
| @ -22,6 +22,7 @@ | ||||
| #include "tcg.h" | ||||
| #include "qemu/bitops.h" | ||||
| #include "exec/cpu_ldst.h" | ||||
| #include "translate-all.h" | ||||
| 
 | ||||
| #undef EAX | ||||
| #undef ECX | ||||
|  | ||||
| @ -11,6 +11,7 @@ | ||||
| 
 | ||||
| #include "qemu/bitops.h" | ||||
| #include "qemu/bitmap.h" | ||||
| #include "qemu/atomic.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * bitmaps provide an array of bits, implemented using an an | ||||
| @ -177,6 +178,43 @@ void bitmap_set(unsigned long *map, long start, long nr) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void bitmap_set_atomic(unsigned long *map, long start, long nr) | ||||
| { | ||||
|     unsigned long *p = map + BIT_WORD(start); | ||||
|     const long size = start + nr; | ||||
|     int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG); | ||||
|     unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start); | ||||
| 
 | ||||
|     /* First word */ | ||||
|     if (nr - bits_to_set > 0) { | ||||
|         atomic_or(p, mask_to_set); | ||||
|         nr -= bits_to_set; | ||||
|         bits_to_set = BITS_PER_LONG; | ||||
|         mask_to_set = ~0UL; | ||||
|         p++; | ||||
|     } | ||||
| 
 | ||||
|     /* Full words */ | ||||
|     if (bits_to_set == BITS_PER_LONG) { | ||||
|         while (nr >= BITS_PER_LONG) { | ||||
|             *p = ~0UL; | ||||
|             nr -= BITS_PER_LONG; | ||||
|             p++; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Last word */ | ||||
|     if (nr) { | ||||
|         mask_to_set &= BITMAP_LAST_WORD_MASK(size); | ||||
|         atomic_or(p, mask_to_set); | ||||
|     } else { | ||||
|         /* If we avoided the full barrier in atomic_or(), issue a
 | ||||
|          * barrier to account for the assignments in the while loop. | ||||
|          */ | ||||
|         smp_mb(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void bitmap_clear(unsigned long *map, long start, long nr) | ||||
| { | ||||
|     unsigned long *p = map + BIT_WORD(start); | ||||
| @ -197,6 +235,51 @@ 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 *p = map + BIT_WORD(start); | ||||
|     const long size = start + nr; | ||||
|     int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG); | ||||
|     unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start); | ||||
|     unsigned long dirty = 0; | ||||
|     unsigned long old_bits; | ||||
| 
 | ||||
|     /* First word */ | ||||
|     if (nr - bits_to_clear > 0) { | ||||
|         old_bits = atomic_fetch_and(p, ~mask_to_clear); | ||||
|         dirty |= old_bits & mask_to_clear; | ||||
|         nr -= bits_to_clear; | ||||
|         bits_to_clear = BITS_PER_LONG; | ||||
|         mask_to_clear = ~0UL; | ||||
|         p++; | ||||
|     } | ||||
| 
 | ||||
|     /* Full words */ | ||||
|     if (bits_to_clear == BITS_PER_LONG) { | ||||
|         while (nr >= BITS_PER_LONG) { | ||||
|             if (*p) { | ||||
|                 old_bits = atomic_xchg(p, 0); | ||||
|                 dirty |= old_bits; | ||||
|             } | ||||
|             nr -= BITS_PER_LONG; | ||||
|             p++; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Last word */ | ||||
|     if (nr) { | ||||
|         mask_to_clear &= BITMAP_LAST_WORD_MASK(size); | ||||
|         old_bits = atomic_fetch_and(p, ~mask_to_clear); | ||||
|         dirty |= old_bits & mask_to_clear; | ||||
|     } else { | ||||
|         if (!dirty) { | ||||
|             smp_mb(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return dirty != 0; | ||||
| } | ||||
| 
 | ||||
| #define ALIGN_MASK(x,mask)      (((x)+(mask))&~(mask)) | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
							
								
								
									
										9
									
								
								vl.c
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								vl.c
									
									
									
									
									
								
							| @ -468,6 +468,9 @@ static QemuOptsList qemu_icount_opts = { | ||||
|         }, { | ||||
|             .name = "align", | ||||
|             .type = QEMU_OPT_BOOL, | ||||
|         }, { | ||||
|             .name = "sleep", | ||||
|             .type = QEMU_OPT_BOOL, | ||||
|         }, | ||||
|         { /* end of list */ } | ||||
|     }, | ||||
| @ -2497,14 +2500,20 @@ static void qemu_run_exit_notifiers(void) | ||||
|     notifier_list_notify(&exit_notifiers, NULL); | ||||
| } | ||||
| 
 | ||||
| static bool machine_init_done; | ||||
| 
 | ||||
| void qemu_add_machine_init_done_notifier(Notifier *notify) | ||||
| { | ||||
|     notifier_list_add(&machine_init_done_notifiers, notify); | ||||
|     if (machine_init_done) { | ||||
|         notify->notify(notify, NULL); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void qemu_run_machine_init_done_notifiers(void) | ||||
| { | ||||
|     notifier_list_notify(&machine_init_done_notifiers, NULL); | ||||
|     machine_init_done = true; | ||||
| } | ||||
| 
 | ||||
| static const QEMUOption *lookup_opt(int argc, char **argv, | ||||
|  | ||||
							
								
								
									
										22
									
								
								xen-hvm.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								xen-hvm.c
									
									
									
									
									
								
							| @ -488,7 +488,7 @@ static void xen_set_memory(struct MemoryListener *listener, | ||||
|     XenIOState *state = container_of(listener, XenIOState, memory_listener); | ||||
|     hwaddr start_addr = section->offset_within_address_space; | ||||
|     ram_addr_t size = int128_get64(section->size); | ||||
|     bool log_dirty = memory_region_is_logging(section->mr); | ||||
|     bool log_dirty = memory_region_is_logging(section->mr, DIRTY_MEMORY_VGA); | ||||
|     hvmmem_type_t mem_type; | ||||
| 
 | ||||
|     if (section->mr == &ram_memory) { | ||||
| @ -646,21 +646,27 @@ static void xen_sync_dirty_bitmap(XenIOState *state, | ||||
| } | ||||
| 
 | ||||
| static void xen_log_start(MemoryListener *listener, | ||||
|                           MemoryRegionSection *section) | ||||
|                           MemoryRegionSection *section, | ||||
|                           int old, int new) | ||||
| { | ||||
|     XenIOState *state = container_of(listener, XenIOState, memory_listener); | ||||
| 
 | ||||
|     xen_sync_dirty_bitmap(state, section->offset_within_address_space, | ||||
|                           int128_get64(section->size)); | ||||
|     if (new & ~old & (1 << DIRTY_MEMORY_VGA)) { | ||||
|         xen_sync_dirty_bitmap(state, section->offset_within_address_space, | ||||
|                               int128_get64(section->size)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void xen_log_stop(MemoryListener *listener, MemoryRegionSection *section) | ||||
| static void xen_log_stop(MemoryListener *listener, MemoryRegionSection *section, | ||||
|                          int old, int new) | ||||
| { | ||||
|     XenIOState *state = container_of(listener, XenIOState, memory_listener); | ||||
| 
 | ||||
|     state->log_for_dirtybit = NULL; | ||||
|     /* Disable dirty bit tracking */ | ||||
|     xc_hvm_track_dirty_vram(xen_xc, xen_domid, 0, 0, NULL); | ||||
|     if (old & ~new & (1 << DIRTY_MEMORY_VGA)) { | ||||
|         state->log_for_dirtybit = NULL; | ||||
|         /* Disable dirty bit tracking */ | ||||
|         xc_hvm_track_dirty_vram(xen_xc, xen_domid, 0, 0, NULL); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void xen_log_sync(MemoryListener *listener, MemoryRegionSection *section) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Peter Maydell
						Peter Maydell