Add qemu_ram_remap

qemu_ram_remap() unmaps the specified RAM pages, then re-maps these
pages again.  This is used by KVM HWPoison support to clear HWPoisoned
page tables across guest rebooting, so that a new page may be
allocated later to recover the memory error.

[ Jan: style fixlets, WIN32 fix ]

Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
This commit is contained in:
Huang Ying 2011-03-02 08:56:19 +01:00 committed by Marcelo Tosatti
parent 75d4949733
commit cd19cfa236
3 changed files with 67 additions and 1 deletions

View file

@ -863,10 +863,14 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
extern int phys_ram_fd; extern int phys_ram_fd;
extern ram_addr_t ram_size; extern ram_addr_t ram_size;
/* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */
#define RAM_PREALLOC_MASK (1 << 0)
typedef struct RAMBlock { typedef struct RAMBlock {
uint8_t *host; uint8_t *host;
ram_addr_t offset; ram_addr_t offset;
ram_addr_t length; ram_addr_t length;
uint32_t flags;
char idstr[256]; char idstr[256];
QLIST_ENTRY(RAMBlock) next; QLIST_ENTRY(RAMBlock) next;
#if defined(__linux__) && !defined(TARGET_S390X) #if defined(__linux__) && !defined(TARGET_S390X)

View file

@ -50,6 +50,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
ram_addr_t size, void *host); ram_addr_t size, void *host);
ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size); ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size);
void qemu_ram_free(ram_addr_t addr); void qemu_ram_free(ram_addr_t addr);
void qemu_ram_remap(ram_addr_t addr, ram_addr_t length);
/* This should only be used for ram local to a device. */ /* This should only be used for ram local to a device. */
void *qemu_get_ram_ptr(ram_addr_t addr); void *qemu_get_ram_ptr(ram_addr_t addr);
/* Same but slower, to use for migration, where the order of /* Same but slower, to use for migration, where the order of

63
exec.c
View file

@ -2867,6 +2867,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
if (host) { if (host) {
new_block->host = host; new_block->host = host;
new_block->flags |= RAM_PREALLOC_MASK;
} else { } else {
if (mem_path) { if (mem_path) {
#if defined (__linux__) && !defined(TARGET_S390X) #if defined (__linux__) && !defined(TARGET_S390X)
@ -2920,7 +2921,9 @@ void qemu_ram_free(ram_addr_t addr)
QLIST_FOREACH(block, &ram_list.blocks, next) { QLIST_FOREACH(block, &ram_list.blocks, next) {
if (addr == block->offset) { if (addr == block->offset) {
QLIST_REMOVE(block, next); QLIST_REMOVE(block, next);
if (mem_path) { if (block->flags & RAM_PREALLOC_MASK) {
;
} else if (mem_path) {
#if defined (__linux__) && !defined(TARGET_S390X) #if defined (__linux__) && !defined(TARGET_S390X)
if (block->fd) { if (block->fd) {
munmap(block->host, block->length); munmap(block->host, block->length);
@ -2943,6 +2946,64 @@ void qemu_ram_free(ram_addr_t addr)
} }
#ifndef _WIN32
void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
{
RAMBlock *block;
ram_addr_t offset;
int flags;
void *area, *vaddr;
QLIST_FOREACH(block, &ram_list.blocks, next) {
offset = addr - block->offset;
if (offset < block->length) {
vaddr = block->host + offset;
if (block->flags & RAM_PREALLOC_MASK) {
;
} else {
flags = MAP_FIXED;
munmap(vaddr, length);
if (mem_path) {
#if defined(__linux__) && !defined(TARGET_S390X)
if (block->fd) {
#ifdef MAP_POPULATE
flags |= mem_prealloc ? MAP_POPULATE | MAP_SHARED :
MAP_PRIVATE;
#else
flags |= MAP_PRIVATE;
#endif
area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
flags, block->fd, offset);
} else {
flags |= MAP_PRIVATE | MAP_ANONYMOUS;
area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
flags, -1, 0);
}
#endif
} else {
#if defined(TARGET_S390X) && defined(CONFIG_KVM)
flags |= MAP_SHARED | MAP_ANONYMOUS;
area = mmap(vaddr, length, PROT_EXEC|PROT_READ|PROT_WRITE,
flags, -1, 0);
#else
flags |= MAP_PRIVATE | MAP_ANONYMOUS;
area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
flags, -1, 0);
#endif
}
if (area != vaddr) {
fprintf(stderr, "Could not remap addr: %lx@%lx\n",
length, addr);
exit(1);
}
qemu_madvise(vaddr, length, QEMU_MADV_MERGEABLE);
}
return;
}
}
}
#endif /* !_WIN32 */
/* Return a host pointer to ram allocated with qemu_ram_alloc. /* Return a host pointer to ram allocated with qemu_ram_alloc.
With the exception of the softmmu code in this file, this should With the exception of the softmmu code in this file, this should
only be used for local memory (e.g. video ram) that the device owns, only be used for local memory (e.g. video ram) that the device owns,