Skip to content
This repository was archived by the owner on Nov 15, 2022. It is now read-only.

Commit 44ead41

Browse files
committed
RAMList: Upstream dirty tracking implementation.
This modifies the implementation of dirty RAM tracking to follow the upstream implementation, which uses 3 parallel bitmap arrays instead of a single one merging all components. Change-Id: I75c418444310f159973840aa765db65294859702
1 parent 206910b commit 44ead41

File tree

13 files changed

+538
-204
lines changed

13 files changed

+538
-204
lines changed

Makefile.target

+2
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ common_LOCAL_SRC_FILES := \
311311
android/opengles.c \
312312
android/user-events-qemu.c \
313313
hw/core/loader.c \
314+
util/bitmap.c \
315+
util/bitops.c \
314316
ui/keymaps.c \
315317
util/qemu-timer-common.c \
316318
util/iov.c \

arch_init.c

+10-7
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,14 @@ static int ram_save_block(QEMUFile *f)
126126
current_addr = block->offset + offset;
127127

128128
do {
129-
if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) {
129+
if (cpu_physical_memory_get_dirty(current_addr, TARGET_PAGE_SIZE,
130+
DIRTY_MEMORY_MIGRATION)) {
130131
uint8_t *p;
131132
int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
132133

133134
cpu_physical_memory_reset_dirty(current_addr,
134-
current_addr + TARGET_PAGE_SIZE,
135-
MIGRATION_DIRTY_FLAG);
135+
TARGET_PAGE_SIZE,
136+
DIRTY_MEMORY_MIGRATION);
136137

137138
p = block->host + offset;
138139

@@ -188,7 +189,8 @@ static ram_addr_t ram_save_remaining(void)
188189
ram_addr_t addr;
189190
for (addr = block->offset; addr < block->offset + block->length;
190191
addr += TARGET_PAGE_SIZE) {
191-
if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) {
192+
if (cpu_physical_memory_get_dirty(addr, TARGET_PAGE_SIZE,
193+
DIRTY_MEMORY_MIGRATION)) {
192194
count++;
193195
}
194196
}
@@ -279,9 +281,10 @@ int ram_save_live(QEMUFile *f, int stage, void *opaque)
279281
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
280282
for (addr = block->offset; addr < block->offset + block->length;
281283
addr += TARGET_PAGE_SIZE) {
282-
if (!cpu_physical_memory_get_dirty(addr,
283-
MIGRATION_DIRTY_FLAG)) {
284-
cpu_physical_memory_set_dirty(addr);
284+
if (!cpu_physical_memory_get_dirty(addr, TARGET_PAGE_SIZE,
285+
DIRTY_MEMORY_MIGRATION)) {
286+
cpu_physical_memory_set_dirty_flag(
287+
addr, DIRTY_MEMORY_MIGRATION);
285288
}
286289
}
287290
}

cputlb.c

+24-5
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,16 @@ void tlb_flush_page(CPUArchState *env, target_ulong addr)
118118
can be detected */
119119
void tlb_protect_code(ram_addr_t ram_addr)
120120
{
121-
cpu_physical_memory_reset_dirty(ram_addr,
122-
ram_addr + TARGET_PAGE_SIZE,
123-
CODE_DIRTY_FLAG);
121+
cpu_physical_memory_reset_dirty(ram_addr, TARGET_PAGE_SIZE,
122+
DIRTY_MEMORY_CODE);
124123
}
125124

126125
/* update the TLB so that writes in physical page 'phys_addr' are no longer
127126
tested for self modifying code */
128127
void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr,
129128
target_ulong vaddr)
130129
{
131-
cpu_physical_memory_set_dirty_flags(ram_addr, CODE_DIRTY_FLAG);
130+
cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE);
132131
}
133132

134133
static bool tlb_is_dirty_ram(CPUTLBEntry *tlbe)
@@ -150,6 +149,26 @@ void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start,
150149
}
151150
}
152151

152+
void cpu_tlb_reset_dirty_all(ram_addr_t start1, ram_addr_t length)
153+
{
154+
CPUState *cpu;
155+
CPUArchState *env;
156+
157+
CPU_FOREACH(cpu) {
158+
int mmu_idx;
159+
160+
env = cpu->env_ptr;
161+
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
162+
unsigned int i;
163+
164+
for (i = 0; i < CPU_TLB_SIZE; i++) {
165+
tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
166+
start1, length);
167+
}
168+
}
169+
}
170+
}
171+
153172
static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
154173
{
155174
if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY)) {
@@ -288,7 +307,7 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
288307
/* Write access calls the I/O callback. */
289308
te->addr_write = address | TLB_MMIO;
290309
} else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
291-
!cpu_physical_memory_is_dirty(pd)) {
310+
cpu_physical_memory_is_clean(pd)) {
292311
te->addr_write = address | TLB_NOTDIRTY;
293312
} else {
294313
te->addr_write = address;

exec.c

+65-84
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "hw/hw.h"
4040
#include "hw/qdev.h"
4141
#include "hw/xen/xen.h"
42+
#include "qemu/bitmap.h"
4243
#include "qemu/osdep.h"
4344
#include "qemu/tls.h"
4445
#include "sysemu/kvm.h"
@@ -49,6 +50,7 @@
4950
#if defined(CONFIG_USER_ONLY)
5051
#include <qemu.h>
5152
#endif
53+
#include "translate-all.h"
5254

5355
//#define DEBUG_SUBPAGE
5456

@@ -532,41 +534,28 @@ static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
532534
return block;
533535
}
534536

535-
/* Note: start and end must be within the same ram block. */
536-
void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
537-
int dirty_flags)
537+
static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length)
538538
{
539-
unsigned long length, start1;
540-
int i;
539+
ram_addr_t end = TARGET_PAGE_ALIGN(start + length);
541540

542541
start &= TARGET_PAGE_MASK;
543-
end = TARGET_PAGE_ALIGN(end);
544542

545-
length = end - start;
543+
RAMBlock* block = qemu_get_ram_block(start);
544+
assert(block == qemu_get_ram_block(end - 1));
545+
uintptr_t start1 = (uintptr_t)block->host + (start - block->offset);
546+
cpu_tlb_reset_dirty_all(start1, length);
547+
}
548+
549+
/* Note: start and end must be within the same ram block. */
550+
void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length,
551+
unsigned client)
552+
{
546553
if (length == 0)
547554
return;
548-
cpu_physical_memory_mask_dirty_range(start, length, dirty_flags);
549-
550-
/* we modify the TLB cache so that the dirty bit will be set again
551-
when accessing the range */
552-
start1 = (unsigned long)qemu_safe_ram_ptr(start);
553-
/* Chek that we don't span multiple blocks - this breaks the
554-
address comparisons below. */
555-
if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
556-
!= (end - 1) - start) {
557-
abort();
558-
}
555+
cpu_physical_memory_clear_dirty_range(start, length, client);
559556

560-
CPUState *cpu;
561-
CPU_FOREACH(cpu) {
562-
int mmu_idx;
563-
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
564-
for(i = 0; i < CPU_TLB_SIZE; i++) {
565-
CPUArchState* env = cpu->env_ptr;
566-
tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
567-
start1, length);
568-
}
569-
}
557+
if (tcg_enabled()) {
558+
tlb_reset_dirty_range_all(start, length);
570559
}
571560
}
572561

@@ -603,7 +592,7 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
603592
p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
604593
+ tlb_entry->addend);
605594
ram_addr = qemu_ram_addr_from_host_nofail(p);
606-
if (!cpu_physical_memory_is_dirty(ram_addr)) {
595+
if (cpu_physical_memory_is_clean(ram_addr)) {
607596
tlb_entry->addr_write |= TLB_NOTDIRTY;
608597
}
609598
}
@@ -1079,6 +1068,9 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
10791068
ram_addr_t size, void *host)
10801069
{
10811070
RAMBlock *block, *new_block;
1071+
ram_addr_t old_ram_size, new_ram_size;
1072+
1073+
old_ram_size = last_ram_offset() >> TARGET_PAGE_BITS;
10821074

10831075
size = TARGET_PAGE_ALIGN(size);
10841076
new_block = g_malloc0(sizeof(*new_block));
@@ -1166,11 +1158,17 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
11661158
ram_list.version++;
11671159
qemu_mutex_unlock_ramlist();
11681160

1169-
ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
1170-
last_ram_offset() >> TARGET_PAGE_BITS);
1171-
memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
1172-
0xff, size >> TARGET_PAGE_BITS);
1173-
//cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff);
1161+
new_ram_size = last_ram_offset() >> TARGET_PAGE_BITS;
1162+
1163+
if (new_ram_size > old_ram_size) {
1164+
int i;
1165+
for (i = 0; i < DIRTY_MEMORY_NUM; i++) {
1166+
ram_list.dirty_memory[i] =
1167+
bitmap_zero_extend(ram_list.dirty_memory[i],
1168+
old_ram_size, new_ram_size);
1169+
}
1170+
}
1171+
cpu_physical_memory_set_dirty_range(new_block->offset, size);
11741172

11751173
qemu_ram_setup_dump(new_block->host, size);
11761174
//qemu_madvise(new_block->host, size, QEMU_MADV_HUGEPAGE);
@@ -1463,61 +1461,52 @@ static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
14631461
static void notdirty_mem_writeb(void *opaque, hwaddr ram_addr,
14641462
uint32_t val)
14651463
{
1466-
int dirty_flags;
1467-
dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
1468-
if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1469-
#if !defined(CONFIG_USER_ONLY)
1464+
if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) {
14701465
tb_invalidate_phys_page_fast0(ram_addr, 1);
1471-
dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
1472-
#endif
14731466
}
14741467
stb_p(qemu_get_ram_ptr(ram_addr), val);
1475-
dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1476-
cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
1468+
cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_MIGRATION);
1469+
cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_VGA);
14771470
/* we remove the notdirty callback only if the code has been
14781471
flushed */
1479-
if (dirty_flags == 0xff)
1480-
tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1472+
if (!cpu_physical_memory_is_clean(ram_addr)) {
1473+
CPUArchState *env = current_cpu->env_ptr;
1474+
tlb_set_dirty(env, env->mem_io_vaddr);
1475+
}
14811476
}
14821477

14831478
static void notdirty_mem_writew(void *opaque, hwaddr ram_addr,
14841479
uint32_t val)
14851480
{
1486-
int dirty_flags;
1487-
dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
1488-
if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1489-
#if !defined(CONFIG_USER_ONLY)
1490-
tb_invalidate_phys_page_fast0(ram_addr, 2);
1491-
dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
1492-
#endif
1481+
if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) {
1482+
tb_invalidate_phys_page_fast0(ram_addr, 1);
14931483
}
14941484
stw_p(qemu_get_ram_ptr(ram_addr), val);
1495-
dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1496-
cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
1485+
cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_MIGRATION);
1486+
cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_VGA);
14971487
/* we remove the notdirty callback only if the code has been
14981488
flushed */
1499-
if (dirty_flags == 0xff)
1500-
tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1489+
if (!cpu_physical_memory_is_clean(ram_addr)) {
1490+
CPUArchState *env = current_cpu->env_ptr;
1491+
tlb_set_dirty(env, env->mem_io_vaddr);
1492+
}
15011493
}
15021494

15031495
static void notdirty_mem_writel(void *opaque, hwaddr ram_addr,
15041496
uint32_t val)
15051497
{
1506-
int dirty_flags;
1507-
dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
1508-
if (!(dirty_flags & CODE_DIRTY_FLAG)) {
1509-
#if !defined(CONFIG_USER_ONLY)
1510-
tb_invalidate_phys_page_fast0(ram_addr, 4);
1511-
dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
1512-
#endif
1498+
if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) {
1499+
tb_invalidate_phys_page_fast0(ram_addr, 1);
15131500
}
15141501
stl_p(qemu_get_ram_ptr(ram_addr), val);
1515-
dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
1516-
cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
1502+
cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_MIGRATION);
1503+
cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_VGA);
15171504
/* we remove the notdirty callback only if the code has been
15181505
flushed */
1519-
if (dirty_flags == 0xff)
1520-
tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
1506+
if (!cpu_physical_memory_is_clean(ram_addr)) {
1507+
CPUArchState *env = current_cpu->env_ptr;
1508+
tlb_set_dirty(env, env->mem_io_vaddr);
1509+
}
15211510
}
15221511

15231512
static CPUReadMemoryFunc * const error_mem_read[3] = {
@@ -1532,16 +1521,6 @@ static CPUWriteMemoryFunc * const notdirty_mem_write[3] = {
15321521
notdirty_mem_writel,
15331522
};
15341523

1535-
static void tb_check_watchpoint(CPUArchState* env)
1536-
{
1537-
TranslationBlock *tb = tb_find_pc(env->mem_io_pc);
1538-
if (!tb) {
1539-
cpu_abort(env, "check_watchpoint: could not find TB for "
1540-
"pc=%p", (void *)env->mem_io_pc);
1541-
}
1542-
cpu_restore_state(env, env->mem_io_pc);
1543-
tb_phys_invalidate(tb, -1);
1544-
}
15451524

15461525
/* Generate a debug exception if a watchpoint has been hit. */
15471526
static void check_watchpoint(int offset, int len_mask, int flags)
@@ -1919,11 +1898,12 @@ void cpu_physical_memory_rw(hwaddr addr, void *buf,
19191898
static void invalidate_and_set_dirty(hwaddr addr,
19201899
hwaddr length)
19211900
{
1922-
if (!cpu_physical_memory_is_dirty(addr)) {
1901+
if (cpu_physical_memory_is_clean(addr)) {
19231902
/* invalidate code */
19241903
tb_invalidate_phys_page_range(addr, addr + length, 0);
19251904
/* set dirty bit */
1926-
cpu_physical_memory_set_dirty_flags(addr, (0xff & ~CODE_DIRTY_FLAG));
1905+
cpu_physical_memory_set_dirty_flag(addr, DIRTY_MEMORY_VGA);
1906+
cpu_physical_memory_set_dirty_flag(addr, DIRTY_MEMORY_MIGRATION);
19271907
}
19281908
}
19291909

@@ -2435,12 +2415,13 @@ void stl_phys_notdirty(hwaddr addr, uint32_t val)
24352415
stl_p(ptr, val);
24362416

24372417
if (unlikely(in_migration)) {
2438-
if (!cpu_physical_memory_is_dirty(addr1)) {
2418+
if (cpu_physical_memory_is_clean(addr1)) {
24392419
/* invalidate code */
24402420
tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
24412421
/* set dirty bit */
2442-
cpu_physical_memory_set_dirty_flags(
2443-
addr1, (0xff & ~CODE_DIRTY_FLAG));
2422+
cpu_physical_memory_set_dirty_flag(addr1,
2423+
DIRTY_MEMORY_MIGRATION);
2424+
cpu_physical_memory_set_dirty_flag(addr1, DIRTY_MEMORY_VGA);
24442425
}
24452426
}
24462427
}
@@ -2596,12 +2577,12 @@ static inline void stw_phys_internal(hwaddr addr, uint32_t val,
25962577
stw_p(ptr, val);
25972578
break;
25982579
}
2599-
if (!cpu_physical_memory_is_dirty(addr1)) {
2580+
if (cpu_physical_memory_is_clean(addr1)) {
26002581
/* invalidate code */
26012582
tb_invalidate_phys_page_range(addr1, addr1 + 2, 0);
26022583
/* set dirty bit */
2603-
cpu_physical_memory_set_dirty_flags(addr1,
2604-
(0xff & ~CODE_DIRTY_FLAG));
2584+
cpu_physical_memory_set_dirty_flag(addr1, DIRTY_MEMORY_MIGRATION);
2585+
cpu_physical_memory_set_dirty_flag(addr1, DIRTY_MEMORY_VGA);
26052586
}
26062587
}
26072588
}

0 commit comments

Comments
 (0)