*/
#include <stdint.h>
#include <stdarg.h>
+#include <stdlib.h>
#ifndef _WIN32
#include <sys/types.h>
#include <sys/mman.h>
#include "net.h"
#include "gdbstub.h"
#include "hw/smbios.h"
+#include "exec-memory.h"
+#include "hw/pcspk.h"
#ifdef TARGET_SPARC
int graphic_width = 1024;
#define QEMU_ARCH QEMU_ARCH_I386
#elif defined(TARGET_M68K)
#define QEMU_ARCH QEMU_ARCH_M68K
+#elif defined(TARGET_LM32)
+#define QEMU_ARCH QEMU_ARCH_LM32
#elif defined(TARGET_MICROBLAZE)
#define QEMU_ARCH QEMU_ARCH_MICROBLAZE
#elif defined(TARGET_MIPS)
#define QEMU_ARCH QEMU_ARCH_SH4
#elif defined(TARGET_SPARC)
#define QEMU_ARCH QEMU_ARCH_SPARC
+#elif defined(TARGET_XTENSA)
+#define QEMU_ARCH QEMU_ARCH_XTENSA
#endif
const uint32_t arch_type = QEMU_ARCH;
/***********************************************************/
/* ram save/restore */
-#define RAM_SAVE_FLAG_FULL 0x01 /* Obsolete, not used anymore */
-#define RAM_SAVE_FLAG_COMPRESS 0x02
-#define RAM_SAVE_FLAG_MEM_SIZE 0x04
-#define RAM_SAVE_FLAG_PAGE 0x08
-#define RAM_SAVE_FLAG_EOS 0x10
-#define RAM_SAVE_FLAG_CONTINUE 0x20
+#define RAM_SAVE_FLAG_FULL 0x01 /* Obsolete, not used anymore */
+#define RAM_SAVE_FLAG_COMPRESS 0x02
+#define RAM_SAVE_FLAG_MEM_SIZE 0x04
+#define RAM_SAVE_FLAG_PAGE 0x08
+#define RAM_SAVE_FLAG_EOS 0x10
+#define RAM_SAVE_FLAG_CONTINUE 0x20
+
+#ifdef __ALTIVEC__
+#include <altivec.h>
+#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)
+#elif defined __SSE2__
+#include <emmintrin.h>
+#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 int is_dup_page(uint8_t *page, uint8_t ch)
+static int is_dup_page(uint8_t *page)
{
- uint32_t val = ch << 24 | ch << 16 | ch << 8 | ch;
- uint32_t *array = (uint32_t *)page;
+ VECTYPE *p = (VECTYPE *)page;
+ VECTYPE val = SPLAT(page);
int i;
- for (i = 0; i < (TARGET_PAGE_SIZE / 4); i++) {
- if (array[i] != val) {
+ for (i = 0; i < TARGET_PAGE_SIZE / sizeof(VECTYPE); i++) {
+ if (!ALL_EQ(val, p[i])) {
return 0;
}
}
return 1;
}
+static RAMBlock *last_block;
+static ram_addr_t last_offset;
+
static int ram_save_block(QEMUFile *f)
{
- static RAMBlock *last_block = NULL;
- static ram_addr_t last_offset = 0;
RAMBlock *block = last_block;
ram_addr_t offset = last_offset;
- ram_addr_t current_addr;
int bytes_sent = 0;
+ MemoryRegion *mr;
if (!block)
block = QLIST_FIRST(&ram_list.blocks);
- current_addr = block->offset + offset;
-
do {
- if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) {
+ mr = block->mr;
+ if (memory_region_get_dirty(mr, offset, TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_MIGRATION)) {
uint8_t *p;
int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
- cpu_physical_memory_reset_dirty(current_addr,
- current_addr + TARGET_PAGE_SIZE,
- MIGRATION_DIRTY_FLAG);
+ memory_region_reset_dirty(mr, offset, TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_MIGRATION);
- p = block->host + offset;
+ p = memory_region_get_ram_ptr(mr) + offset;
- if (is_dup_page(p, *p)) {
+ if (is_dup_page(p)) {
qemu_put_be64(f, offset | cont | RAM_SAVE_FLAG_COMPRESS);
if (!cont) {
qemu_put_byte(f, strlen(block->idstr));
if (!block)
block = QLIST_FIRST(&ram_list.blocks);
}
-
- current_addr = block->offset + offset;
-
- } while (current_addr != last_block->offset + last_offset);
+ } while (block != last_block || offset != last_offset);
last_block = block;
last_offset = offset;
QLIST_FOREACH(block, &ram_list.blocks, next) {
ram_addr_t addr;
- for (addr = block->offset; addr < block->offset + block->length;
- addr += TARGET_PAGE_SIZE) {
- if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG)) {
+ for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
+ if (memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_MIGRATION)) {
count++;
}
}
return total;
}
-int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
+static int block_compar(const void *a, const void *b)
+{
+ RAMBlock * const *ablock = a;
+ RAMBlock * const *bblock = b;
+
+ return strcmp((*ablock)->idstr, (*bblock)->idstr);
+}
+
+static void sort_ram_list(void)
+{
+ RAMBlock *block, *nblock, **blocks;
+ int n;
+ n = 0;
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ ++n;
+ }
+ blocks = g_malloc(n * sizeof *blocks);
+ n = 0;
+ QLIST_FOREACH_SAFE(block, &ram_list.blocks, next, nblock) {
+ blocks[n++] = block;
+ QLIST_REMOVE(block, next);
+ }
+ qsort(blocks, n, sizeof *blocks, block_compar);
+ while (--n >= 0) {
+ QLIST_INSERT_HEAD(&ram_list.blocks, blocks[n], next);
+ }
+ g_free(blocks);
+}
+
+int ram_save_live(QEMUFile *f, int stage, void *opaque)
{
ram_addr_t addr;
uint64_t bytes_transferred_last;
double bwidth = 0;
uint64_t expected_time = 0;
+ int ret;
if (stage < 0) {
- cpu_physical_memory_set_dirty_tracking(0);
+ memory_global_dirty_log_stop();
return 0;
}
- if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) {
- qemu_file_set_error(f);
- return 0;
- }
+ memory_global_sync_dirty_bitmap(get_system_memory());
if (stage == 1) {
RAMBlock *block;
bytes_transferred = 0;
+ last_block = NULL;
+ last_offset = 0;
+ sort_ram_list();
/* Make sure all dirty bits are set */
QLIST_FOREACH(block, &ram_list.blocks, next) {
- for (addr = block->offset; addr < block->offset + block->length;
- addr += TARGET_PAGE_SIZE) {
- if (!cpu_physical_memory_get_dirty(addr,
- MIGRATION_DIRTY_FLAG)) {
- cpu_physical_memory_set_dirty(addr);
+ for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
+ if (!memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_MIGRATION)) {
+ memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE);
}
}
}
- /* Enable dirty memory tracking */
- cpu_physical_memory_set_dirty_tracking(1);
+ memory_global_dirty_log_start();
qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE);
bytes_transferred_last = bytes_transferred;
bwidth = qemu_get_clock_ns(rt_clock);
- while (!qemu_file_rate_limit(f)) {
+ while ((ret = qemu_file_rate_limit(f)) == 0) {
int bytes_sent;
bytes_sent = ram_save_block(f);
}
}
+ if (ret < 0) {
+ return ret;
+ }
+
bwidth = qemu_get_clock_ns(rt_clock) - bwidth;
bwidth = (bytes_transferred - bytes_transferred_last) / bwidth;
while ((bytes_sent = ram_save_block(f)) != 0) {
bytes_transferred += bytes_sent;
}
- cpu_physical_memory_set_dirty_tracking(0);
+ memory_global_dirty_log_stop();
}
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
return NULL;
}
- return block->host + offset;
+ return memory_region_get_ram_ptr(block->mr) + offset;
}
len = qemu_get_byte(f);
QLIST_FOREACH(block, &ram_list.blocks, next) {
if (!strncmp(id, block->idstr, sizeof(id)))
- return block->host + offset;
+ return memory_region_get_ram_ptr(block->mr) + offset;
}
fprintf(stderr, "Can't find block %s!\n", id);
{
ram_addr_t addr;
int flags;
+ int error;
- if (version_id < 3 || version_id > 4) {
+ if (version_id < 4 || version_id > 4) {
return -EINVAL;
}
addr &= TARGET_PAGE_MASK;
if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
- if (version_id == 3) {
- if (addr != ram_bytes_total()) {
- return -EINVAL;
- }
- } else {
+ if (version_id == 4) {
/* Synchronize RAM block list */
char id[256];
ram_addr_t length;
}
if (!block) {
- if (!qemu_ram_alloc(NULL, id, length))
- return -ENOMEM;
+ fprintf(stderr, "Unknown ramblock \"%s\", cannot "
+ "accept migration\n", id);
+ return -EINVAL;
}
total_ram_bytes -= length;
void *host;
uint8_t ch;
- if (version_id == 3)
- host = qemu_get_ram_ptr(addr);
- else
- host = host_from_stream_offset(f, addr, flags);
+ host = host_from_stream_offset(f, addr, flags);
+ if (!host) {
+ return -EINVAL;
+ }
ch = qemu_get_byte(f);
memset(host, ch, TARGET_PAGE_SIZE);
#ifndef _WIN32
if (ch == 0 &&
(!kvm_enabled() || kvm_has_sync_mmu())) {
- madvise(host, TARGET_PAGE_SIZE, MADV_DONTNEED);
+ qemu_madvise(host, TARGET_PAGE_SIZE, QEMU_MADV_DONTNEED);
}
#endif
} else if (flags & RAM_SAVE_FLAG_PAGE) {
void *host;
- if (version_id == 3)
- host = qemu_get_ram_ptr(addr);
- else
- host = host_from_stream_offset(f, addr, flags);
+ host = host_from_stream_offset(f, addr, flags);
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
}
- if (qemu_file_has_error(f)) {
- return -EIO;
+ error = qemu_file_get_error(f);
+ if (error) {
+ return error;
}
} while (!(flags & RAM_SAVE_FLAG_EOS));
return 0;
}
-void qemu_service_io(void)
-{
- qemu_notify_event();
-}
-
#ifdef HAS_AUDIO
-struct soundhw soundhw[] = {
+struct soundhw {
+ const char *name;
+ const char *descr;
+ int enabled;
+ int isa;
+ union {
+ int (*init_isa) (ISABus *bus);
+ int (*init_pci) (PCIBus *bus);
+ } init;
+};
+
+static struct soundhw soundhw[] = {
#ifdef HAS_AUDIO_CHOICE
-#if defined(TARGET_I386) || defined(TARGET_MIPS)
+#ifdef CONFIG_PCSPK
{
"pcspk",
"PC speaker",
},
#endif
+#ifdef CONFIG_HDA
+ {
+ "hda",
+ "Intel HD Audio",
+ 0,
+ 0,
+ { .init_pci = intel_hda_and_codec_init }
+ },
+#endif
+
#endif /* HAS_AUDIO_CHOICE */
{ NULL, NULL, 0, 0, { NULL } }
}
}
}
+
+void audio_init(ISABus *isa_bus, PCIBus *pci_bus)
+{
+ struct soundhw *c;
+
+ for (c = soundhw; c->name; ++c) {
+ if (c->enabled) {
+ if (c->isa) {
+ if (isa_bus) {
+ c->init.init_isa(isa_bus);
+ }
+ } else {
+ if (pci_bus) {
+ c->init.init_pci(pci_bus);
+ }
+ }
+ }
+ }
+}
#else
void select_soundhw(const char *optarg)
{
}
+void audio_init(ISABus *isa_bus, PCIBus *pci_bus)
+{
+}
#endif
int qemu_uuid_parse(const char *str, uint8_t *uuid)
#endif
}
+int tcg_available(void)
+{
+ return 1;
+}
+
int kvm_available(void)
{
#ifdef CONFIG_KVM