X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=arch_init.c;h=92de1bde495dea2c7ee3c5e5c433618b7060559e;hb=86cd7b2d486b6c80df41f48dffbdcc055a85faa1;hp=4351d304a8ab75df3193b288b8faf33aa412352f;hpb=b23a9a5cad356cdc8e25d4be72e53096a27ea722;p=qemu.git diff --git a/arch_init.c b/arch_init.c index 4351d304a..92de1bde4 100644 --- a/arch_init.c +++ b/arch_init.c @@ -35,20 +35,20 @@ #include "qemu/bitmap.h" #include "sysemu/arch_init.h" #include "audio/audio.h" -#include "hw/pc.h" +#include "hw/i386/pc.h" #include "hw/pci/pci.h" -#include "hw/audiodev.h" +#include "hw/audio/audio.h" #include "sysemu/kvm.h" #include "migration/migration.h" -#include "exec/gdbstub.h" -#include "hw/smbios.h" +#include "hw/i386/smbios.h" #include "exec/address-spaces.h" -#include "hw/pcspk.h" +#include "hw/audio/pcspk.h" #include "migration/page_cache.h" #include "qemu/config-file.h" #include "qmp-commands.h" #include "trace.h" #include "exec/cpu-all.h" +#include "hw/acpi/acpi.h" #ifdef DEBUG_ARCH_INIT #define DPRINTF(fmt, ...) \ @@ -85,6 +85,8 @@ int graphic_depth = 15; #define QEMU_ARCH QEMU_ARCH_MICROBLAZE #elif defined(TARGET_MIPS) #define QEMU_ARCH QEMU_ARCH_MIPS +#elif defined(TARGET_MOXIE) +#define QEMU_ARCH QEMU_ARCH_MOXIE #elif defined(TARGET_OPENRISC) #define QEMU_ARCH QEMU_ARCH_OPENRISC #elif defined(TARGET_PPC) @@ -114,26 +116,6 @@ const uint32_t arch_type = QEMU_ARCH; #define RAM_SAVE_FLAG_CONTINUE 0x20 #define RAM_SAVE_FLAG_XBZRLE 0x40 -#ifdef __ALTIVEC__ -#include -#define VECTYPE vector unsigned char -#define SPLAT(p) vec_splat(vec_ld(0, p), 0) -#define ALL_EQ(v1, v2) vec_all_eq(v1, v2) -/* altivec.h may redefine the bool macro as vector type. - * Reset it to POSIX semantics. */ -#undef bool -#define bool _Bool -#elif defined __SSE2__ -#include -#define VECTYPE __m128i -#define SPLAT(p) _mm_set1_epi8(*(p)) -#define ALL_EQ(v1, v2) (_mm_movemask_epi8(_mm_cmpeq_epi8(v1, v2)) == 0xFFFF) -#else -#define VECTYPE unsigned long -#define SPLAT(p) (*(p) * (~0UL / 255)) -#define ALL_EQ(v1, v2) ((v1) == (v2)) -#endif - static struct defconfig_file { const char *filename; @@ -160,23 +142,14 @@ int qemu_read_default_config_files(bool userconfig) return ret; } } - + return 0; } -static int is_dup_page(uint8_t *page) +static inline bool is_zero_page(uint8_t *p) { - VECTYPE *p = (VECTYPE *)page; - VECTYPE val = SPLAT(page); - int i; - - for (i = 0; i < TARGET_PAGE_SIZE / sizeof(VECTYPE); i++) { - if (!ALL_EQ(val, p[i])) { - return 0; - } - } - - return 1; + return buffer_find_nonzero_offset(p, TARGET_PAGE_SIZE) == + TARGET_PAGE_SIZE; } /* struct contains XBZRLE cache and a static page @@ -210,6 +183,7 @@ int64_t xbzrle_cache_resize(int64_t new_size) /* accounting for migration statistics */ typedef struct AccountingInfo { uint64_t dup_pages; + uint64_t skipped_pages; uint64_t norm_pages; uint64_t iterations; uint64_t xbzrle_bytes; @@ -235,6 +209,16 @@ uint64_t dup_mig_pages_transferred(void) return acct_info.dup_pages; } +uint64_t skipped_mig_bytes_transferred(void) +{ + return acct_info.skipped_pages * TARGET_PAGE_SIZE; +} + +uint64_t skipped_mig_pages_transferred(void) +{ + return acct_info.skipped_pages; +} + uint64_t norm_mig_bytes_transferred(void) { return acct_info.norm_pages * TARGET_PAGE_SIZE; @@ -265,16 +249,21 @@ uint64_t xbzrle_mig_pages_overflow(void) return acct_info.xbzrle_overflows; } -static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset, - int cont, int flag) +static size_t save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset, + int cont, int flag) { - qemu_put_be64(f, offset | cont | flag); - if (!cont) { - qemu_put_byte(f, strlen(block->idstr)); - qemu_put_buffer(f, (uint8_t *)block->idstr, - strlen(block->idstr)); - } + size_t size; + + qemu_put_be64(f, offset | cont | flag); + size = 8; + if (!cont) { + qemu_put_byte(f, strlen(block->idstr)); + qemu_put_buffer(f, (uint8_t *)block->idstr, + strlen(block->idstr)); + size += 1 + strlen(block->idstr); + } + return size; } #define ENCODING_FLAG_XBZRLE 0x1 @@ -288,8 +277,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, if (!cache_is_cached(XBZRLE.cache, current_addr)) { if (!last_stage) { - cache_insert(XBZRLE.cache, current_addr, - g_memdup(current_data, TARGET_PAGE_SIZE)); + cache_insert(XBZRLE.cache, current_addr, current_data); } acct_info.xbzrle_cache_miss++; return -1; @@ -321,11 +309,11 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, } /* Send XBZRLE based compressed page */ - save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_XBZRLE); + bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_XBZRLE); qemu_put_byte(f, ENCODING_FLAG_XBZRLE); qemu_put_be16(f, encoded_len); qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len); - bytes_sent = encoded_len + 1 + 2; + bytes_sent += encoded_len + 1 + 2; acct_info.xbzrle_pages++; acct_info.xbzrle_bytes += bytes_sent; @@ -336,23 +324,35 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, /* This is the last block that we have visited serching for dirty pages */ static RAMBlock *last_seen_block; +/* This is the last block from where we have sent data */ +static RAMBlock *last_sent_block; static ram_addr_t last_offset; static unsigned long *migration_bitmap; static uint64_t migration_dirty_pages; static uint32_t last_version; +static bool ram_bulk_stage; -static inline bool migration_bitmap_test_and_reset_dirty(MemoryRegion *mr, - ram_addr_t offset) +static inline +ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr, + ram_addr_t start) { - bool ret; - int nr = (mr->ram_addr + offset) >> TARGET_PAGE_BITS; + unsigned long base = mr->ram_addr >> TARGET_PAGE_BITS; + unsigned long nr = base + (start >> TARGET_PAGE_BITS); + unsigned long size = base + (int128_get64(mr->size) >> TARGET_PAGE_BITS); - ret = test_and_clear_bit(nr, migration_bitmap); + unsigned long next; + + if (ram_bulk_stage && nr > base) { + next = nr + 1; + } else { + next = find_next_bit(migration_bitmap, size, nr); + } - if (ret) { + if (next < size) { + clear_bit(next, migration_bitmap); migration_dirty_pages--; } - return ret; + return (next - base) << TARGET_PAGE_BITS; } static inline bool migration_bitmap_set_dirty(MemoryRegion *mr, @@ -369,6 +369,8 @@ static inline bool migration_bitmap_set_dirty(MemoryRegion *mr, return ret; } +/* Needs iothread lock! */ + static void migration_bitmap_sync(void) { RAMBlock *block; @@ -388,13 +390,12 @@ static void migration_bitmap_sync(void) QTAILQ_FOREACH(block, &ram_list.blocks, next) { for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) { - if (memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE, - DIRTY_MEMORY_MIGRATION)) { + if (memory_region_test_and_clear_dirty(block->mr, + addr, TARGET_PAGE_SIZE, + DIRTY_MEMORY_MIGRATION)) { migration_bitmap_set_dirty(block->mr, addr); } } - memory_region_reset_dirty(block->mr, 0, block->length, - DIRTY_MEMORY_MIGRATION); } trace_migration_bitmap_sync_end(migration_dirty_pages - num_dirty_pages_init); @@ -405,6 +406,7 @@ static void migration_bitmap_sync(void) if (end_time > start_time + 1000) { s->dirty_pages_rate = num_dirty_pages_period * 1000 / (end_time - start_time); + s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE; start_time = end_time; num_dirty_pages_period = 0; } @@ -413,37 +415,58 @@ static void migration_bitmap_sync(void) /* * ram_save_block: Writes a page of memory to the stream f * - * Returns: 0: if the page hasn't changed - * -1: if there are no more dirty pages - * n: the amount of bytes written in other case + * Returns: The number of bytes written. + * 0 means no dirty pages */ static int ram_save_block(QEMUFile *f, bool last_stage) { RAMBlock *block = last_seen_block; ram_addr_t offset = last_offset; - int bytes_sent = -1; + bool complete_round = false; + int bytes_sent = 0; MemoryRegion *mr; ram_addr_t current_addr; if (!block) block = QTAILQ_FIRST(&ram_list.blocks); - do { + while (true) { mr = block->mr; - if (migration_bitmap_test_and_reset_dirty(mr, offset)) { + offset = migration_bitmap_find_and_reset_dirty(mr, offset); + if (complete_round && block == last_seen_block && + offset >= last_offset) { + break; + } + if (offset >= block->length) { + offset = 0; + block = QTAILQ_NEXT(block, next); + if (!block) { + block = QTAILQ_FIRST(&ram_list.blocks); + complete_round = true; + ram_bulk_stage = false; + } + } else { uint8_t *p; - int cont = (block == last_seen_block) ? + int cont = (block == last_sent_block) ? RAM_SAVE_FLAG_CONTINUE : 0; p = memory_region_get_ram_ptr(mr) + offset; - if (is_dup_page(p)) { + /* In doubt sent page as normal */ + bytes_sent = -1; + if (is_zero_page(p)) { acct_info.dup_pages++; - save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_COMPRESS); - qemu_put_byte(f, *p); - bytes_sent = 1; - } else if (migrate_use_xbzrle()) { + if (!ram_bulk_stage) { + bytes_sent = save_block_hdr(f, block, offset, cont, + RAM_SAVE_FLAG_COMPRESS); + qemu_put_byte(f, 0); + bytes_sent++; + } else { + acct_info.skipped_pages++; + bytes_sent = 0; + } + } else if (!ram_bulk_stage && migrate_use_xbzrle()) { current_addr = block->offset + offset; bytes_sent = save_xbzrle_page(f, p, current_addr, block, offset, cont, last_stage); @@ -452,29 +475,21 @@ static int ram_save_block(QEMUFile *f, bool last_stage) } } - /* either we didn't send yet (we may have had XBZRLE overflow) */ + /* XBZRLE overflow or normal page */ if (bytes_sent == -1) { - save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE); - qemu_put_buffer(f, p, TARGET_PAGE_SIZE); - bytes_sent = TARGET_PAGE_SIZE; + bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE); + qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE); + bytes_sent += TARGET_PAGE_SIZE; acct_info.norm_pages++; } /* if page is unmodified, continue to the next */ - if (bytes_sent != 0) { + if (bytes_sent > 0) { + last_sent_block = block; break; } } - - offset += TARGET_PAGE_SIZE; - if (offset >= block->length) { - offset = 0; - block = QTAILQ_NEXT(block, next); - if (!block) - block = QTAILQ_FIRST(&ram_list.blocks); - } - } while (block != last_seen_block || offset != last_offset); - + } last_seen_block = block; last_offset = offset; @@ -535,8 +550,10 @@ static void ram_migration_cancel(void *opaque) static void reset_ram_globals(void) { last_seen_block = NULL; + last_sent_block = NULL; last_offset = 0; last_version = ram_list.version; + ram_bulk_stage = true; } #define MAX_WAIT 50 /* ms, half buffered_file limit */ @@ -550,10 +567,6 @@ static int ram_save_setup(QEMUFile *f, void *opaque) bitmap_set(migration_bitmap, 0, ram_pages); migration_dirty_pages = ram_pages; - qemu_mutex_lock_ramlist(); - bytes_transferred = 0; - reset_ram_globals(); - if (migrate_use_xbzrle()) { XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() / TARGET_PAGE_SIZE, @@ -567,8 +580,14 @@ static int ram_save_setup(QEMUFile *f, void *opaque) acct_clear(); } + qemu_mutex_lock_iothread(); + qemu_mutex_lock_ramlist(); + bytes_transferred = 0; + reset_ram_globals(); + memory_global_dirty_log_start(); migration_bitmap_sync(); + qemu_mutex_unlock_iothread(); qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE); @@ -589,6 +608,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) int ret; int i; int64_t t0; + int total_sent = 0; qemu_mutex_lock_ramlist(); @@ -603,10 +623,10 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) bytes_sent = ram_save_block(f, false); /* no more blocks to sent */ - if (bytes_sent < 0) { + if (bytes_sent == 0) { break; } - bytes_transferred += bytes_sent; + total_sent += bytes_sent; acct_info.iterations++; /* we want to check in the 1st loop, just in case it was the 1st time and we had to sync the dirty bitmap. @@ -624,21 +644,24 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) i++; } + qemu_mutex_unlock_ramlist(); + if (ret < 0) { + bytes_transferred += total_sent; return ret; } - qemu_mutex_unlock_ramlist(); qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + total_sent += 8; + bytes_transferred += total_sent; - return i; + return total_sent; } static int ram_save_complete(QEMUFile *f, void *opaque) { - migration_bitmap_sync(); - qemu_mutex_lock_ramlist(); + migration_bitmap_sync(); /* try transferring iterative blocks of memory */ @@ -648,7 +671,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque) bytes_sent = ram_save_block(f, true); /* no more blocks to sent */ - if (bytes_sent < 0) { + if (bytes_sent == 0) { break; } bytes_transferred += bytes_sent; @@ -668,7 +691,9 @@ static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size) remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE; if (remaining_size < max_size) { + qemu_mutex_lock_iothread(); migration_bitmap_sync(); + qemu_mutex_unlock_iothread(); remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE; } return remaining_size; @@ -830,9 +855,6 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, host, TARGET_PAGE_SIZE); } else if (flags & RAM_SAVE_FLAG_XBZRLE) { - if (!migrate_use_xbzrle()) { - return -EINVAL; - } void *host = host_from_stream_offset(f, addr, flags); if (!host) { return -EINVAL; @@ -1081,11 +1103,16 @@ int qemu_uuid_parse(const char *str, uint8_t *uuid) return 0; } -void do_acpitable_option(const char *optarg) +void do_acpitable_option(const QemuOpts *opts) { #ifdef TARGET_I386 - if (acpi_table_add(optarg) < 0) { - fprintf(stderr, "Wrong acpi table provided\n"); + Error *err = NULL; + + acpi_table_add(opts, &err); + if (err) { + fprintf(stderr, "Wrong acpi table provided: %s\n", + error_get_pretty(err)); + error_free(err); exit(1); } #endif