memory: change dirty getting API to take a size
Instead of each device knowing or guessing the guest page size, just pass the desired size of dirtied memory area. Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
This commit is contained in:
parent
cb437e48ab
commit
cd7a45c95e
@ -141,7 +141,8 @@ static int ram_save_block(QEMUFile *f)
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
mr = block->mr;
|
mr = block->mr;
|
||||||
if (memory_region_get_dirty(mr, offset, DIRTY_MEMORY_MIGRATION)) {
|
if (memory_region_get_dirty(mr, offset, TARGET_PAGE_SIZE,
|
||||||
|
DIRTY_MEMORY_MIGRATION)) {
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
|
int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
|
||||||
|
|
||||||
@ -198,7 +199,7 @@ static ram_addr_t ram_save_remaining(void)
|
|||||||
QLIST_FOREACH(block, &ram_list.blocks, next) {
|
QLIST_FOREACH(block, &ram_list.blocks, next) {
|
||||||
ram_addr_t addr;
|
ram_addr_t addr;
|
||||||
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
|
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
|
||||||
if (memory_region_get_dirty(block->mr, addr,
|
if (memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
|
||||||
DIRTY_MEMORY_MIGRATION)) {
|
DIRTY_MEMORY_MIGRATION)) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@ -283,7 +284,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
|
|||||||
/* Make sure all dirty bits are set */
|
/* Make sure all dirty bits are set */
|
||||||
QLIST_FOREACH(block, &ram_list.blocks, next) {
|
QLIST_FOREACH(block, &ram_list.blocks, next) {
|
||||||
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
|
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
|
||||||
if (!memory_region_get_dirty(block->mr, addr,
|
if (!memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
|
||||||
DIRTY_MEMORY_MIGRATION)) {
|
DIRTY_MEMORY_MIGRATION)) {
|
||||||
memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE);
|
memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
@ -59,10 +59,21 @@ static inline int cpu_physical_memory_get_dirty_flags(ram_addr_t addr)
|
|||||||
return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS];
|
return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int cpu_physical_memory_get_dirty(ram_addr_t addr,
|
static inline int cpu_physical_memory_get_dirty(ram_addr_t start,
|
||||||
|
ram_addr_t length,
|
||||||
int dirty_flags)
|
int dirty_flags)
|
||||||
{
|
{
|
||||||
return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
|
int ret = 0;
|
||||||
|
uint8_t *p;
|
||||||
|
ram_addr_t addr, end;
|
||||||
|
|
||||||
|
end = TARGET_PAGE_ALIGN(start + length);
|
||||||
|
start &= TARGET_PAGE_MASK;
|
||||||
|
p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
|
||||||
|
for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
|
||||||
|
ret |= *p++ & dirty_flags;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void cpu_physical_memory_set_dirty(ram_addr_t addr)
|
static inline void cpu_physical_memory_set_dirty(ram_addr_t addr)
|
||||||
|
@ -87,15 +87,8 @@ void framebuffer_update_display(
|
|||||||
dest += i * dest_row_pitch;
|
dest += i * dest_row_pitch;
|
||||||
|
|
||||||
for (; i < rows; i++) {
|
for (; i < rows; i++) {
|
||||||
target_phys_addr_t dirty_offset;
|
dirty = memory_region_get_dirty(mem, addr, addr + src_width,
|
||||||
dirty = 0;
|
|
||||||
dirty_offset = 0;
|
|
||||||
while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) {
|
|
||||||
dirty |= memory_region_get_dirty(mem, addr + dirty_offset,
|
|
||||||
DIRTY_MEMORY_VGA);
|
DIRTY_MEMORY_VGA);
|
||||||
dirty_offset += TARGET_PAGE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dirty || invalidate) {
|
if (dirty || invalidate) {
|
||||||
fn(opaque, dest, src, cols, dest_col_pitch);
|
fn(opaque, dest, src, cols, dest_col_pitch);
|
||||||
if (first == -1)
|
if (first == -1)
|
||||||
|
@ -62,7 +62,8 @@ typedef struct G364State {
|
|||||||
|
|
||||||
static inline int check_dirty(G364State *s, ram_addr_t page)
|
static inline int check_dirty(G364State *s, ram_addr_t page)
|
||||||
{
|
{
|
||||||
return memory_region_get_dirty(&s->mem_vram, page, DIRTY_MEMORY_VGA);
|
return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
|
||||||
|
DIRTY_MEMORY_VGA);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void reset_dirty(G364State *s,
|
static inline void reset_dirty(G364State *s,
|
||||||
|
11
hw/sm501.c
11
hw/sm501.c
@ -1323,15 +1323,12 @@ static void sm501_draw_crt(SM501State * s)
|
|||||||
for (y = 0; y < height; y++) {
|
for (y = 0; y < height; y++) {
|
||||||
int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
|
int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
|
||||||
int update = full_update || update_hwc;
|
int update = full_update || update_hwc;
|
||||||
ram_addr_t page0 = offset & TARGET_PAGE_MASK;
|
ram_addr_t page0 = offset;
|
||||||
ram_addr_t page1 = (offset + width * src_bpp - 1) & TARGET_PAGE_MASK;
|
ram_addr_t page1 = offset + width * src_bpp - 1;
|
||||||
ram_addr_t page;
|
|
||||||
|
|
||||||
/* check dirty flags for each line */
|
/* check dirty flags for each line */
|
||||||
for (page = page0; page <= page1; page += TARGET_PAGE_SIZE)
|
update = memory_region_get_dirty(&s->local_mem_region, page0, page1,
|
||||||
if (memory_region_get_dirty(&s->local_mem_region, page,
|
DIRTY_MEMORY_VGA);
|
||||||
DIRTY_MEMORY_VGA))
|
|
||||||
update = 1;
|
|
||||||
|
|
||||||
/* draw line and change status */
|
/* draw line and change status */
|
||||||
if (update) {
|
if (update) {
|
||||||
|
17
hw/tcx.c
17
hw/tcx.c
@ -178,15 +178,13 @@ static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
|
|||||||
ram_addr_t cpage)
|
ram_addr_t cpage)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
unsigned int off;
|
|
||||||
|
|
||||||
ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
|
ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE,
|
||||||
for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
|
DIRTY_MEMORY_VGA);
|
||||||
ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
|
ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4,
|
||||||
DIRTY_MEMORY_VGA);
|
DIRTY_MEMORY_VGA);
|
||||||
ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
|
ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4,
|
||||||
DIRTY_MEMORY_VGA);
|
DIRTY_MEMORY_VGA);
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,7 +243,8 @@ static void tcx_update_display(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
|
for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
|
||||||
if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
|
if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
|
||||||
|
DIRTY_MEMORY_VGA)) {
|
||||||
if (y_start < 0)
|
if (y_start < 0)
|
||||||
y_start = y;
|
y_start = y;
|
||||||
if (page < page_min)
|
if (page < page_min)
|
||||||
|
17
hw/vga.c
17
hw/vga.c
@ -1742,17 +1742,10 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
|||||||
if (!(s->cr[0x17] & 2)) {
|
if (!(s->cr[0x17] & 2)) {
|
||||||
addr = (addr & ~0x8000) | ((y1 & 2) << 14);
|
addr = (addr & ~0x8000) | ((y1 & 2) << 14);
|
||||||
}
|
}
|
||||||
page0 = addr & TARGET_PAGE_MASK;
|
page0 = addr;
|
||||||
page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
|
page1 = addr + bwidth - 1;
|
||||||
update = full_update |
|
update = memory_region_get_dirty(&s->vram, page0, page1,
|
||||||
memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
|
DIRTY_MEMORY_VGA);
|
||||||
memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
|
|
||||||
if ((page1 - page0) > TARGET_PAGE_SIZE) {
|
|
||||||
/* if wide line, can use another page */
|
|
||||||
update |= memory_region_get_dirty(&s->vram,
|
|
||||||
page0 + TARGET_PAGE_SIZE,
|
|
||||||
DIRTY_MEMORY_VGA);
|
|
||||||
}
|
|
||||||
/* explicit invalidation for the hardware cursor */
|
/* explicit invalidation for the hardware cursor */
|
||||||
update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
|
update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
|
||||||
if (update) {
|
if (update) {
|
||||||
@ -1798,7 +1791,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
|||||||
if (page_max >= page_min) {
|
if (page_max >= page_min) {
|
||||||
memory_region_reset_dirty(&s->vram,
|
memory_region_reset_dirty(&s->vram,
|
||||||
page_min,
|
page_min,
|
||||||
page_max + TARGET_PAGE_SIZE - page_min,
|
page_max - page_min,
|
||||||
DIRTY_MEMORY_VGA);
|
DIRTY_MEMORY_VGA);
|
||||||
}
|
}
|
||||||
memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
|
memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
|
||||||
|
5
memory.c
5
memory.c
@ -1136,10 +1136,11 @@ void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
|
bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
|
||||||
unsigned client)
|
target_phys_addr_t size, unsigned client)
|
||||||
{
|
{
|
||||||
assert(mr->terminates);
|
assert(mr->terminates);
|
||||||
return cpu_physical_memory_get_dirty(mr->ram_addr + addr, 1 << client);
|
return cpu_physical_memory_get_dirty(mr->ram_addr + addr, size,
|
||||||
|
1 << client);
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
|
void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
|
||||||
|
9
memory.h
9
memory.h
@ -380,20 +380,21 @@ void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset);
|
|||||||
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client);
|
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* memory_region_get_dirty: Check whether a page is dirty for a specified
|
* memory_region_get_dirty: Check whether a range of bytes is dirty
|
||||||
* client.
|
* for a specified client.
|
||||||
*
|
*
|
||||||
* Checks whether a page has been written to since the last
|
* Checks whether a range of bytes has been written to since the last
|
||||||
* call to memory_region_reset_dirty() with the same @client. Dirty logging
|
* call to memory_region_reset_dirty() with the same @client. Dirty logging
|
||||||
* must be enabled.
|
* must be enabled.
|
||||||
*
|
*
|
||||||
* @mr: the memory region being queried.
|
* @mr: the memory region being queried.
|
||||||
* @addr: the address (relative to the start of the region) being queried.
|
* @addr: the address (relative to the start of the region) being queried.
|
||||||
|
* @size: the size of the range being queried.
|
||||||
* @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
|
* @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
|
||||||
* %DIRTY_MEMORY_VGA.
|
* %DIRTY_MEMORY_VGA.
|
||||||
*/
|
*/
|
||||||
bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
|
bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
|
||||||
unsigned client);
|
target_phys_addr_t size, unsigned client);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* memory_region_set_dirty: Mark a range of bytes as dirty in a memory region.
|
* memory_region_set_dirty: Mark a range of bytes as dirty in a memory region.
|
||||||
|
Loading…
Reference in New Issue
Block a user