diff --git a/exec.c b/exec.c index 95c4356c65..f4b9ef25f5 100644 --- a/exec.c +++ b/exec.c @@ -904,6 +904,13 @@ static long gethugepagesize(const char *path) return fs.f_bsize; } +static sigjmp_buf sigjump; + +static void sigbus_handler(int signal) +{ + siglongjmp(sigjump, 1); +} + static void *file_ram_alloc(RAMBlock *block, ram_addr_t memory, const char *path) @@ -913,9 +920,6 @@ static void *file_ram_alloc(RAMBlock *block, char *c; void *area; int fd; -#ifdef MAP_POPULATE - int flags; -#endif unsigned long hpagesize; hpagesize = gethugepagesize(path); @@ -963,21 +967,52 @@ static void *file_ram_alloc(RAMBlock *block, if (ftruncate(fd, memory)) perror("ftruncate"); -#ifdef MAP_POPULATE - /* NB: MAP_POPULATE won't exhaustively alloc all phys pages in the case - * MAP_PRIVATE is requested. For mem_prealloc we mmap as MAP_SHARED - * to sidestep this quirk. - */ - flags = mem_prealloc ? MAP_POPULATE | MAP_SHARED : MAP_PRIVATE; - area = mmap(0, memory, PROT_READ | PROT_WRITE, flags, fd, 0); -#else area = mmap(0, memory, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); -#endif if (area == MAP_FAILED) { perror("file_ram_alloc: can't mmap RAM pages"); close(fd); return (NULL); } + + if (mem_prealloc) { + int ret, i; + struct sigaction act, oldact; + sigset_t set, oldset; + + memset(&act, 0, sizeof(act)); + act.sa_handler = &sigbus_handler; + act.sa_flags = 0; + + ret = sigaction(SIGBUS, &act, &oldact); + if (ret) { + perror("file_ram_alloc: failed to install signal handler"); + exit(1); + } + + /* unblock SIGBUS */ + sigemptyset(&set); + sigaddset(&set, SIGBUS); + pthread_sigmask(SIG_UNBLOCK, &set, &oldset); + + if (sigsetjmp(sigjump, 1)) { + fprintf(stderr, "file_ram_alloc: failed to preallocate pages\n"); + exit(1); + } + + /* MAP_POPULATE silently ignores failures */ + for (i = 0; i < (memory/hpagesize)-1; i++) { + memset(area + (hpagesize*i), 0, 1); + } + + ret = sigaction(SIGBUS, &oldact, NULL); + if (ret) { + perror("file_ram_alloc: failed to reinstall signal handler"); + exit(1); + } + + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + } + block->fd = fd; return area; } diff --git a/kvm-all.c b/kvm-all.c index 4478969ed2..393775459d 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -72,7 +72,8 @@ typedef struct kvm_dirty_log KVMDirtyLog; struct KVMState { - KVMSlot slots[32]; + KVMSlot *slots; + int nr_slots; int fd; int vmfd; int coalesced_mmio; @@ -125,7 +126,7 @@ static KVMSlot *kvm_alloc_slot(KVMState *s) { int i; - for (i = 0; i < ARRAY_SIZE(s->slots); i++) { + for (i = 0; i < s->nr_slots; i++) { if (s->slots[i].memory_size == 0) { return &s->slots[i]; } @@ -141,7 +142,7 @@ static KVMSlot *kvm_lookup_matching_slot(KVMState *s, { int i; - for (i = 0; i < ARRAY_SIZE(s->slots); i++) { + for (i = 0; i < s->nr_slots; i++) { KVMSlot *mem = &s->slots[i]; if (start_addr == mem->start_addr && @@ -163,7 +164,7 @@ static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s, KVMSlot *found = NULL; int i; - for (i = 0; i < ARRAY_SIZE(s->slots); i++) { + for (i = 0; i < s->nr_slots; i++) { KVMSlot *mem = &s->slots[i]; if (mem->memory_size == 0 || @@ -185,7 +186,7 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram, { int i; - for (i = 0; i < ARRAY_SIZE(s->slots); i++) { + for (i = 0; i < s->nr_slots; i++) { KVMSlot *mem = &s->slots[i]; if (ram >= mem->ram && ram < mem->ram + mem->memory_size) { @@ -357,7 +358,7 @@ static int kvm_set_migration_log(int enable) s->migration_log = enable; - for (i = 0; i < ARRAY_SIZE(s->slots); i++) { + for (i = 0; i < s->nr_slots; i++) { mem = &s->slots[i]; if (!mem->memory_size) { @@ -1383,9 +1384,6 @@ int kvm_init(void) #ifdef KVM_CAP_SET_GUEST_DEBUG QTAILQ_INIT(&s->kvm_sw_breakpoints); #endif - for (i = 0; i < ARRAY_SIZE(s->slots); i++) { - s->slots[i].slot = i; - } s->vmfd = -1; s->fd = qemu_open("/dev/kvm", O_RDWR); if (s->fd == -1) { @@ -1409,6 +1407,19 @@ int kvm_init(void) goto err; } + s->nr_slots = kvm_check_extension(s, KVM_CAP_NR_MEMSLOTS); + + /* If unspecified, use the default value */ + if (!s->nr_slots) { + s->nr_slots = 32; + } + + s->slots = g_malloc0(s->nr_slots * sizeof(KVMSlot)); + + for (i = 0; i < s->nr_slots; i++) { + s->slots[i].slot = i; + } + /* check the vcpu limits */ soft_vcpus_limit = kvm_recommended_vcpus(s); hard_vcpus_limit = kvm_max_vcpus(s); @@ -1527,6 +1538,7 @@ err: if (s->fd != -1) { close(s->fd); } + g_free(s->slots); g_free(s); return ret; diff --git a/qemu-options.hx b/qemu-options.hx index 8b9426484d..eafc022ad0 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -228,7 +228,6 @@ STEXI Allocate guest RAM from a temporarily created file in @var{path}. ETEXI -#ifdef MAP_POPULATE DEF("mem-prealloc", 0, QEMU_OPTION_mem_prealloc, "-mem-prealloc preallocate guest memory (use with -mem-path)\n", QEMU_ARCH_ALL) @@ -237,7 +236,6 @@ STEXI @findex -mem-prealloc Preallocate memory when using -mem-path. ETEXI -#endif DEF("k", HAS_ARG, QEMU_OPTION_k, "-k language use keyboard layout (for example 'fr' for French)\n", diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 47af9a8816..bb98f6defc 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -335,7 +335,7 @@ typedef struct ExtSaveArea { static const ExtSaveArea ext_save_areas[] = { [2] = { .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX, - .offset = 0x100, .size = 0x240 }, + .offset = 0x240, .size = 0x100 }, }; const char *get_register_name_32(unsigned int reg) @@ -2227,8 +2227,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, const ExtSaveArea *esa = &ext_save_areas[count]; if ((env->features[esa->feature] & esa->bits) == esa->bits && (kvm_mask & (1 << count)) != 0) { - *eax = esa->offset; - *ebx = esa->size; + *eax = esa->size; + *ebx = esa->offset; } } break; diff --git a/vl.c b/vl.c index 668f0f3921..b0399de25f 100644 --- a/vl.c +++ b/vl.c @@ -188,9 +188,7 @@ static int display_remote; const char* keyboard_layout = NULL; ram_addr_t ram_size; const char *mem_path = NULL; -#ifdef MAP_POPULATE int mem_prealloc = 0; /* force preallocation of physical target memory */ -#endif int nb_nics; NICInfo nd_table[MAX_NICS]; int autostart; @@ -3211,11 +3209,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_mempath: mem_path = optarg; break; -#ifdef MAP_POPULATE case QEMU_OPTION_mem_prealloc: mem_prealloc = 1; break; -#endif case QEMU_OPTION_d: log_mask = optarg; break;