mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
@@ -1,5 +1,7 @@
|
||||
# -*- Mode: makefile -*-
|
||||
|
||||
BUILD_DIR?=$(CURDIR)/..
|
||||
|
||||
include ../config-host.mak
|
||||
include config-target.mak
|
||||
include config-devices.mak
|
||||
|
||||
+2
-44
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+3
-1
@@ -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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+77
-127
@@ -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
|
||||
|
||||
+2
-1
@@ -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),
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user