* Asynchronous dump-guest-memory from Peter

* improved logging with -D -daemonize from Dimitris
 * more address_space_* optimization from Gonglei
 * TCG xsave/xrstor thinko fix
 * chardev bugfix and documentation patch
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQEcBAABCAAGBQJWzxnbAAoJEL/70l94x66DlfkIAJyo9kOareVLOnAE8ccayghk
 0SbU1ZR9etgdeH4vZIUKzFzSg86pnqqub/w9yxgNG35PsiXVOnzgYSv6W1qsXdVE
 v32u6c+vWHvHc3cCOFI5+6nURftf2+p/vB2VFXiI23VUbhs22UAjXsUdfbp321X5
 Krme2fxk0kmwPHoKiyek0qiXa8nt0fiuFzU7DN7gTQMoDFaDEqvcULlNJHUFnep+
 M1yQfhSzrD97bafPwmIDU0LejJxrzR6phuzWedugU1tay6y3pD85wQqHdFI7fn/o
 dC4F+vg41Lc/5jKUgRMpe5FmX4VM+DvRdYgZZsp9/SkBM7DuL7crhVWVwvQj82Y=
 =8BvG
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging

* Asynchronous dump-guest-memory from Peter
* improved logging with -D -daemonize from Dimitris
* more address_space_* optimization from Gonglei
* TCG xsave/xrstor thinko fix
* chardev bugfix and documentation patch

# gpg: Signature made Thu 25 Feb 2016 15:12:27 GMT using RSA key ID 78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>"
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>"

* remotes/bonzini/tags/for-upstream:
  target-i386: fix confusion in xcr0 bit position vs. mask
  chardev: Properly initialize ChardevCommon components
  memory: Remove unreachable return statement
  memory: optimize qemu_get_ram_ptr and qemu_ram_ptr_length
  exec: store RAMBlock pointer into memory region
  log: Redirect stderr to logfile if deamonized
  dump-guest-memory: add qmp event DUMP_COMPLETED
  Dump: add hmp command "info dump"
  Dump: add qmp command "query-dump"
  DumpState: adding total_size and written_size fields
  dump-guest-memory: add "detach" support
  dump-guest-memory: disable dump when in INMIGRATE state
  dump-guest-memory: introduce dump_process() helper function.
  dump-guest-memory: add dump_in_progress() helper function
  dump-guest-memory: using static DumpState, add DumpStatus
  dump-guest-memory: add "detach" flag for QMP/HMP interfaces.
  dump-guest-memory: cleanup: removing dump_{error|cleanup}().
  scripts/kvm/kvm_stat: Fix missing right parantheses and ".format(...)"
  qemu-options.hx: Improve documentation of chardev multiplexing mode

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-02-25 15:30:57 +00:00
commit 586fc27e6a
31 changed files with 563 additions and 164 deletions

View file

@ -220,6 +220,24 @@ Data:
},
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
DUMP_COMPLETED
--------------
Emitted when the guest has finished one memory dump.
Data:
- "result": DumpQueryResult type described in qapi-schema.json
- "error": Error message when dump failed. This is only a
human-readable string provided when dump failed. It should not be
parsed in any way (json-string, optional)
Example:
{ "event": "DUMP_COMPLETED",
"data": {"result": {"total": 1090650112, "status": "completed",
"completed": 1090650112} } }
GUEST_PANICKED
--------------

215
dump.c
View file

@ -25,6 +25,7 @@
#include "sysemu/cpus.h"
#include "qapi/qmp/qerror.h"
#include "qmp-commands.h"
#include "qapi-event.h"
#include <zlib.h>
#ifdef CONFIG_LZO
@ -82,12 +83,6 @@ static int dump_cleanup(DumpState *s)
return 0;
}
static void dump_error(DumpState *s, const char *reason, Error **errp)
{
dump_cleanup(s);
error_setg(errp, "%s", reason);
}
static int fd_write_vmcore(const void *buf, size_t size, void *opaque)
{
DumpState *s = opaque;
@ -128,7 +123,7 @@ static void write_elf64_header(DumpState *s, Error **errp)
ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf header", errp);
error_setg(errp, "dump: failed to write elf header");
}
}
@ -159,7 +154,7 @@ static void write_elf32_header(DumpState *s, Error **errp)
ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf header", errp);
error_setg(errp, "dump: failed to write elf header");
}
}
@ -182,7 +177,7 @@ static void write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
if (ret < 0) {
dump_error(s, "dump: failed to write program header table", errp);
error_setg(errp, "dump: failed to write program header table");
}
}
@ -205,7 +200,7 @@ static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
if (ret < 0) {
dump_error(s, "dump: failed to write program header table", errp);
error_setg(errp, "dump: failed to write program header table");
}
}
@ -225,7 +220,7 @@ static void write_elf64_note(DumpState *s, Error **errp)
ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
if (ret < 0) {
dump_error(s, "dump: failed to write program header table", errp);
error_setg(errp, "dump: failed to write program header table");
}
}
@ -245,7 +240,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
id = cpu_index(cpu);
ret = cpu_write_elf64_note(f, cpu, id, s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf notes", errp);
error_setg(errp, "dump: failed to write elf notes");
return;
}
}
@ -253,7 +248,7 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
CPU_FOREACH(cpu) {
ret = cpu_write_elf64_qemunote(f, cpu, s);
if (ret < 0) {
dump_error(s, "dump: failed to write CPU status", errp);
error_setg(errp, "dump: failed to write CPU status");
return;
}
}
@ -275,7 +270,7 @@ static void write_elf32_note(DumpState *s, Error **errp)
ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
if (ret < 0) {
dump_error(s, "dump: failed to write program header table", errp);
error_setg(errp, "dump: failed to write program header table");
}
}
@ -290,7 +285,7 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s,
id = cpu_index(cpu);
ret = cpu_write_elf32_note(f, cpu, id, s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf notes", errp);
error_setg(errp, "dump: failed to write elf notes");
return;
}
}
@ -298,7 +293,7 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s,
CPU_FOREACH(cpu) {
ret = cpu_write_elf32_qemunote(f, cpu, s);
if (ret < 0) {
dump_error(s, "dump: failed to write CPU status", errp);
error_setg(errp, "dump: failed to write CPU status");
return;
}
}
@ -326,7 +321,7 @@ static void write_elf_section(DumpState *s, int type, Error **errp)
ret = fd_write_vmcore(&shdr, shdr_size, s);
if (ret < 0) {
dump_error(s, "dump: failed to write section header table", errp);
error_setg(errp, "dump: failed to write section header table");
}
}
@ -336,7 +331,9 @@ static void write_data(DumpState *s, void *buf, int length, Error **errp)
ret = fd_write_vmcore(buf, length, s);
if (ret < 0) {
dump_error(s, "dump: failed to save memory", errp);
error_setg(errp, "dump: failed to save memory");
} else {
s->written_size += length;
}
}
@ -568,11 +565,6 @@ static void dump_begin(DumpState *s, Error **errp)
}
}
static void dump_completed(DumpState *s)
{
dump_cleanup(s);
}
static int get_next_block(DumpState *s, GuestPhysBlock *block)
{
while (1) {
@ -624,8 +616,6 @@ static void dump_iterate(DumpState *s, Error **errp)
}
} while (!get_next_block(s, block));
dump_completed(s);
}
static void create_vmcore(DumpState *s, Error **errp)
@ -765,7 +755,7 @@ static void create_header32(DumpState *s, Error **errp)
dh->status = cpu_to_dump32(s, status);
if (write_buffer(s->fd, 0, dh, size) < 0) {
dump_error(s, "dump: failed to write disk dump header", errp);
error_setg(errp, "dump: failed to write disk dump header");
goto out;
}
@ -784,7 +774,7 @@ static void create_header32(DumpState *s, Error **errp)
if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
block_size, kh, size) < 0) {
dump_error(s, "dump: failed to write kdump sub header", errp);
error_setg(errp, "dump: failed to write kdump sub header");
goto out;
}
@ -800,7 +790,7 @@ static void create_header32(DumpState *s, Error **errp)
}
if (write_buffer(s->fd, offset_note, s->note_buf,
s->note_size) < 0) {
dump_error(s, "dump: failed to write notes", errp);
error_setg(errp, "dump: failed to write notes");
goto out;
}
@ -865,7 +855,7 @@ static void create_header64(DumpState *s, Error **errp)
dh->status = cpu_to_dump32(s, status);
if (write_buffer(s->fd, 0, dh, size) < 0) {
dump_error(s, "dump: failed to write disk dump header", errp);
error_setg(errp, "dump: failed to write disk dump header");
goto out;
}
@ -884,7 +874,7 @@ static void create_header64(DumpState *s, Error **errp)
if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
block_size, kh, size) < 0) {
dump_error(s, "dump: failed to write kdump sub header", errp);
error_setg(errp, "dump: failed to write kdump sub header");
goto out;
}
@ -901,7 +891,7 @@ static void create_header64(DumpState *s, Error **errp)
if (write_buffer(s->fd, offset_note, s->note_buf,
s->note_size) < 0) {
dump_error(s, "dump: failed to write notes", errp);
error_setg(errp, "dump: failed to write notes");
goto out;
}
@ -1087,7 +1077,7 @@ static void write_dump_bitmap(DumpState *s, Error **errp)
while (get_next_page(&block_iter, &pfn, NULL, s)) {
ret = set_dump_bitmap(last_pfn, pfn, true, dump_bitmap_buf, s);
if (ret < 0) {
dump_error(s, "dump: failed to set dump_bitmap", errp);
error_setg(errp, "dump: failed to set dump_bitmap");
goto out;
}
@ -1104,7 +1094,7 @@ static void write_dump_bitmap(DumpState *s, Error **errp)
ret = set_dump_bitmap(last_pfn, last_pfn + bits_per_buf, false,
dump_bitmap_buf, s);
if (ret < 0) {
dump_error(s, "dump: failed to sync dump_bitmap", errp);
error_setg(errp, "dump: failed to sync dump_bitmap");
goto out;
}
}
@ -1237,7 +1227,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
ret = write_cache(&page_data, buf, s->dump_info.page_size, false);
g_free(buf);
if (ret < 0) {
dump_error(s, "dump: failed to write page data (zero page)", errp);
error_setg(errp, "dump: failed to write page data (zero page)");
goto out;
}
@ -1253,7 +1243,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor),
false);
if (ret < 0) {
dump_error(s, "dump: failed to write page desc", errp);
error_setg(errp, "dump: failed to write page desc");
goto out;
}
} else {
@ -1278,7 +1268,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
ret = write_cache(&page_data, buf_out, size_out, false);
if (ret < 0) {
dump_error(s, "dump: failed to write page data", errp);
error_setg(errp, "dump: failed to write page data");
goto out;
}
#ifdef CONFIG_LZO
@ -1291,7 +1281,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
ret = write_cache(&page_data, buf_out, size_out, false);
if (ret < 0) {
dump_error(s, "dump: failed to write page data", errp);
error_setg(errp, "dump: failed to write page data");
goto out;
}
#endif
@ -1305,7 +1295,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
ret = write_cache(&page_data, buf_out, size_out, false);
if (ret < 0) {
dump_error(s, "dump: failed to write page data", errp);
error_setg(errp, "dump: failed to write page data");
goto out;
}
#endif
@ -1321,7 +1311,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
ret = write_cache(&page_data, buf,
s->dump_info.page_size, false);
if (ret < 0) {
dump_error(s, "dump: failed to write page data", errp);
error_setg(errp, "dump: failed to write page data");
goto out;
}
}
@ -1333,20 +1323,21 @@ static void write_dump_pages(DumpState *s, Error **errp)
ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false);
if (ret < 0) {
dump_error(s, "dump: failed to write page desc", errp);
error_setg(errp, "dump: failed to write page desc");
goto out;
}
}
s->written_size += s->dump_info.page_size;
}
ret = write_cache(&page_desc, NULL, 0, true);
if (ret < 0) {
dump_error(s, "dump: failed to sync cache for page_desc", errp);
error_setg(errp, "dump: failed to sync cache for page_desc");
goto out;
}
ret = write_cache(&page_data, NULL, 0, true);
if (ret < 0) {
dump_error(s, "dump: failed to sync cache for page_data", errp);
error_setg(errp, "dump: failed to sync cache for page_data");
goto out;
}
@ -1390,7 +1381,7 @@ static void create_kdump_vmcore(DumpState *s, Error **errp)
ret = write_start_flat_header(s->fd);
if (ret < 0) {
dump_error(s, "dump: failed to write start flat header", errp);
error_setg(errp, "dump: failed to write start flat header");
return;
}
@ -1414,11 +1405,9 @@ static void create_kdump_vmcore(DumpState *s, Error **errp)
ret = write_end_flat_header(s->fd);
if (ret < 0) {
dump_error(s, "dump: failed to write end flat header", errp);
error_setg(errp, "dump: failed to write end flat header");
return;
}
dump_completed(s);
}
static ram_addr_t get_start_block(DumpState *s)
@ -1457,6 +1446,44 @@ static void get_max_mapnr(DumpState *s)
s->max_mapnr = dump_paddr_to_pfn(s, last_block->target_end);
}
static DumpState dump_state_global = { .status = DUMP_STATUS_NONE };
static void dump_state_prepare(DumpState *s)
{
/* zero the struct, setting status to active */
*s = (DumpState) { .status = DUMP_STATUS_ACTIVE };
}
bool dump_in_progress(void)
{
DumpState *state = &dump_state_global;
return (atomic_read(&state->status) == DUMP_STATUS_ACTIVE);
}
/* calculate total size of memory to be dumped (taking filter into
* acoount.) */
static int64_t dump_calculate_size(DumpState *s)
{
GuestPhysBlock *block;
int64_t size = 0, total = 0, left = 0, right = 0;
QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
if (s->has_filter) {
/* calculate the overlapped region. */
left = MAX(s->begin, block->target_start);
right = MIN(s->begin + s->length, block->target_end);
size = right - left;
size = size > 0 ? size : 0;
} else {
/* count the whole region in */
size = (block->target_end - block->target_start);
}
total += size;
}
return total;
}
static void dump_init(DumpState *s, int fd, bool has_format,
DumpGuestMemoryFormat format, bool paging, bool has_filter,
int64_t begin, int64_t length, Error **errp)
@ -1466,6 +1493,10 @@ static void dump_init(DumpState *s, int fd, bool has_format,
Error *err = NULL;
int ret;
s->has_format = has_format;
s->format = format;
s->written_size = 0;
/* kdump-compressed is conflict with paging and filter */
if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
assert(!paging && !has_filter);
@ -1496,6 +1527,10 @@ static void dump_init(DumpState *s, int fd, bool has_format,
guest_phys_blocks_init(&s->guest_phys_blocks);
guest_phys_blocks_append(&s->guest_phys_blocks);
s->total_size = dump_calculate_size(s);
#ifdef DEBUG_DUMP_GUEST_MEMORY
fprintf(stderr, "DUMP: total memory to dump: %lu\n", s->total_size);
#endif
s->start = get_start_block(s);
if (s->start == -1) {
@ -1624,8 +1659,60 @@ cleanup:
dump_cleanup(s);
}
void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
int64_t begin, bool has_length,
/* this operation might be time consuming. */
static void dump_process(DumpState *s, Error **errp)
{
Error *local_err = NULL;
DumpQueryResult *result = NULL;
if (s->has_format && s->format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
create_kdump_vmcore(s, &local_err);
} else {
create_vmcore(s, &local_err);
}
/* make sure status is written after written_size updates */
smp_wmb();
atomic_set(&s->status,
(local_err ? DUMP_STATUS_FAILED : DUMP_STATUS_COMPLETED));
/* send DUMP_COMPLETED message (unconditionally) */
result = qmp_query_dump(NULL);
/* should never fail */
assert(result);
qapi_event_send_dump_completed(result, !!local_err, (local_err ? \
error_get_pretty(local_err) : NULL),
&error_abort);
qapi_free_DumpQueryResult(result);
error_propagate(errp, local_err);
dump_cleanup(s);
}
static void *dump_thread(void *data)
{
Error *err = NULL;
DumpState *s = (DumpState *)data;
dump_process(s, &err);
error_free(err);
return NULL;
}
DumpQueryResult *qmp_query_dump(Error **errp)
{
DumpQueryResult *result = g_new(DumpQueryResult, 1);
DumpState *state = &dump_state_global;
result->status = atomic_read(&state->status);
/* make sure we are reading status and written_size in order */
smp_rmb();
result->completed = state->written_size;
result->total = state->total_size;
return result;
}
void qmp_dump_guest_memory(bool paging, const char *file,
bool has_detach, bool detach,
bool has_begin, int64_t begin, bool has_length,
int64_t length, bool has_format,
DumpGuestMemoryFormat format, Error **errp)
{
@ -1633,6 +1720,19 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
int fd = -1;
DumpState *s;
Error *local_err = NULL;
bool detach_p = false;
if (runstate_check(RUN_STATE_INMIGRATE)) {
error_setg(errp, "Dump not allowed during incoming migration.");
return;
}
/* if there is a dump in background, we should wait until the dump
* finished */
if (dump_in_progress()) {
error_setg(errp, "There is a dump in process, please wait.");
return;
}
/*
* kdump-compressed format need the whole memory dumped, so paging or
@ -1652,6 +1752,9 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
error_setg(errp, QERR_MISSING_PARAMETER, "begin");
return;
}
if (has_detach) {
detach_p = detach;
}
/* check whether lzo/snappy is supported */
#ifndef CONFIG_LZO
@ -1690,23 +1793,25 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
return;
}
s = g_malloc0(sizeof(DumpState));
s = &dump_state_global;
dump_state_prepare(s);
dump_init(s, fd, has_format, format, paging, has_begin,
begin, length, &local_err);
if (local_err) {
g_free(s);
error_propagate(errp, local_err);
atomic_set(&s->status, DUMP_STATUS_FAILED);
return;
}
if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
create_kdump_vmcore(s, errp);
if (detach_p) {
/* detached dump */
qemu_thread_create(&s->dump_thread, "dump_thread", dump_thread,
s, QEMU_THREAD_DETACHED);
} else {
create_vmcore(s, errp);
/* sync dump */
dump_process(s, errp);
}
g_free(s);
}
DumpGuestMemoryCapability *qmp_query_dump_guest_memory_capability(Error **errp)

48
exec.c
View file

@ -1717,6 +1717,8 @@ ram_addr_t qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
error_propagate(errp, local_err);
return -1;
}
mr->ram_block = new_block;
return addr;
}
@ -1866,9 +1868,13 @@ void *qemu_get_ram_block_host_ptr(ram_addr_t addr)
*
* Called within RCU critical section.
*/
void *qemu_get_ram_ptr(ram_addr_t addr)
void *qemu_get_ram_ptr(RAMBlock *ram_block, ram_addr_t addr)
{
RAMBlock *block = qemu_get_ram_block(addr);
RAMBlock *block = ram_block;
if (block == NULL) {
block = qemu_get_ram_block(addr);
}
if (xen_enabled() && block->host == NULL) {
/* We need to check if the requested address is in the RAM
@ -1889,15 +1895,18 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
*
* Called within RCU critical section.
*/
static void *qemu_ram_ptr_length(ram_addr_t addr, hwaddr *size)
static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr,
hwaddr *size)
{
RAMBlock *block;
RAMBlock *block = ram_block;
ram_addr_t offset_inside_block;
if (*size == 0) {
return NULL;
}
block = qemu_get_ram_block(addr);
if (block == NULL) {
block = qemu_get_ram_block(addr);
}
offset_inside_block = addr - block->offset;
*size = MIN(*size, block->max_length - offset_inside_block);
@ -2025,13 +2034,13 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
}
switch (size) {
case 1:
stb_p(qemu_get_ram_ptr(ram_addr), val);
stb_p(qemu_get_ram_ptr(NULL, ram_addr), val);
break;
case 2:
stw_p(qemu_get_ram_ptr(ram_addr), val);
stw_p(qemu_get_ram_ptr(NULL, ram_addr), val);
break;
case 4:
stl_p(qemu_get_ram_ptr(ram_addr), val);
stl_p(qemu_get_ram_ptr(NULL, ram_addr), val);
break;
default:
abort();
@ -2607,7 +2616,7 @@ static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr,
} else {
addr1 += memory_region_get_ram_addr(mr);
/* RAM case */
ptr = qemu_get_ram_ptr(addr1);
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
memcpy(ptr, buf, l);
invalidate_and_set_dirty(mr, addr1, l);
}
@ -2698,7 +2707,7 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
}
} else {
/* RAM case */
ptr = qemu_get_ram_ptr(mr->ram_addr + addr1);
ptr = qemu_get_ram_ptr(mr->ram_block, mr->ram_addr + addr1);
memcpy(buf, ptr, l);
}
@ -2783,7 +2792,7 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
} else {
addr1 += memory_region_get_ram_addr(mr);
/* ROM/RAM case */
ptr = qemu_get_ram_ptr(addr1);
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
switch (type) {
case WRITE_DATA:
memcpy(ptr, buf, l);
@ -2995,7 +3004,7 @@ void *address_space_map(AddressSpace *as,
memory_region_ref(mr);
*plen = done;
ptr = qemu_ram_ptr_length(raddr + base, plen);
ptr = qemu_ram_ptr_length(mr->ram_block, raddr + base, plen);
rcu_read_unlock();
return ptr;
@ -3079,7 +3088,8 @@ static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr,
#endif
} else {
/* RAM case */
ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(mr)
ptr = qemu_get_ram_ptr(mr->ram_block,
(memory_region_get_ram_addr(mr)
& TARGET_PAGE_MASK)
+ addr1);
switch (endian) {
@ -3174,7 +3184,8 @@ static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr,
#endif
} else {
/* RAM case */
ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(mr)
ptr = qemu_get_ram_ptr(mr->ram_block,
(memory_region_get_ram_addr(mr)
& TARGET_PAGE_MASK)
+ addr1);
switch (endian) {
@ -3289,7 +3300,8 @@ static inline uint32_t address_space_lduw_internal(AddressSpace *as,
#endif
} else {
/* RAM case */
ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(mr)
ptr = qemu_get_ram_ptr(mr->ram_block,
(memory_region_get_ram_addr(mr)
& TARGET_PAGE_MASK)
+ addr1);
switch (endian) {
@ -3374,7 +3386,7 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val,
r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
} else {
addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
ptr = qemu_get_ram_ptr(addr1);
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
stl_p(ptr, val);
dirty_log_mask = memory_region_get_dirty_log_mask(mr);
@ -3429,7 +3441,7 @@ static inline void address_space_stl_internal(AddressSpace *as,
} else {
/* RAM case */
addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
ptr = qemu_get_ram_ptr(addr1);
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
switch (endian) {
case DEVICE_LITTLE_ENDIAN:
stl_le_p(ptr, val);
@ -3539,7 +3551,7 @@ static inline void address_space_stw_internal(AddressSpace *as,
} else {
/* RAM case */
addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
ptr = qemu_get_ram_ptr(addr1);
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
switch (endian) {
case DEVICE_LITTLE_ENDIAN:
stw_le_p(ptr, val);

View file

@ -784,6 +784,20 @@ STEXI
@item info skeys @var{address}
@findex skeys
Display the value of a storage key (s390 only)
ETEXI
{
.name = "dump",
.args_type = "",
.params = "",
.help = "Display the latest dump status",
.mhandler.cmd = hmp_info_dump,
},
STEXI
@item info dump
@findex dump
Display the latest dump status.
ETEXI
STEXI

View file

@ -1056,10 +1056,11 @@ ETEXI
{
.name = "dump-guest-memory",
.args_type = "paging:-p,zlib:-z,lzo:-l,snappy:-s,filename:F,begin:i?,length:i?",
.params = "[-p] [-z|-l|-s] filename [begin length]",
.args_type = "paging:-p,detach:-d,zlib:-z,lzo:-l,snappy:-s,filename:F,begin:i?,length:i?",
.params = "[-p] [-d] [-z|-l|-s] filename [begin length]",
.help = "dump guest memory into file 'filename'.\n\t\t\t"
"-p: do paging to get guest's memory mapping.\n\t\t\t"
"-d: return immediately (do not wait for completion).\n\t\t\t"
"-z: dump in kdump-compressed format, with zlib compression.\n\t\t\t"
"-l: dump in kdump-compressed format, with lzo compression.\n\t\t\t"
"-s: dump in kdump-compressed format, with snappy compression.\n\t\t\t"

26
hmp.c
View file

@ -1599,8 +1599,10 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
const char *file = qdict_get_str(qdict, "filename");
bool has_begin = qdict_haskey(qdict, "begin");
bool has_length = qdict_haskey(qdict, "length");
bool has_detach = qdict_haskey(qdict, "detach");
int64_t begin = 0;
int64_t length = 0;
bool detach = false;
enum DumpGuestMemoryFormat dump_format = DUMP_GUEST_MEMORY_FORMAT_ELF;
char *prot;
@ -1628,11 +1630,14 @@ void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict)
if (has_length) {
length = qdict_get_int(qdict, "length");
}
if (has_detach) {
detach = qdict_get_bool(qdict, "detach");
}
prot = g_strconcat("file:", file, NULL);
qmp_dump_guest_memory(paging, prot, has_begin, begin, has_length, length,
true, dump_format, &err);
qmp_dump_guest_memory(paging, prot, true, detach, has_begin, begin,
has_length, length, true, dump_format, &err);
hmp_handle_error(mon, &err);
g_free(prot);
}
@ -2358,3 +2363,20 @@ void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict)
qapi_free_RockerOfDpaGroupList(list);
}
void hmp_info_dump(Monitor *mon, const QDict *qdict)
{
DumpQueryResult *result = qmp_query_dump(NULL);
assert(result && result->status < DUMP_STATUS__MAX);
monitor_printf(mon, "Status: %s\n", DumpStatus_lookup[result->status]);
if (result->status == DUMP_STATUS_ACTIVE) {
float percent = 0;
assert(result->total != 0);
percent = 100.0 * result->completed / result->total;
monitor_printf(mon, "Finished: %.2f %%\n", percent);
}
qapi_free_DumpQueryResult(result);
}

1
hmp.h
View file

@ -131,5 +131,6 @@ void hmp_rocker(Monitor *mon, const QDict *qdict);
void hmp_rocker_ports(Monitor *mon, const QDict *qdict);
void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict);
void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict);
void hmp_info_dump(Monitor *mon, const QDict *qdict);
#endif

View file

@ -31,6 +31,7 @@
#include "qemu/notify.h"
#include "qom/object.h"
#include "qemu/rcu.h"
#include "qemu/typedefs.h"
#define MAX_PHYS_ADDR_SPACE_BITS 62
#define MAX_PHYS_ADDR (((hwaddr)1 << MAX_PHYS_ADDR_SPACE_BITS) - 1)
@ -169,6 +170,7 @@ struct MemoryRegion {
bool global_locking;
uint8_t dirty_log_mask;
ram_addr_t ram_addr;
RAMBlock *ram_block;
Object *owner;
const MemoryRegionIOMMUOps *iommu_ops;
@ -1386,7 +1388,7 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
MemoryRegion *mr);
MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr,
MemTxAttrs attrs, uint8_t *buf, int len);
void *qemu_get_ram_ptr(ram_addr_t addr);
void *qemu_get_ram_ptr(RAMBlock *ram_block, ram_addr_t addr);
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
{
@ -1395,8 +1397,6 @@ static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
} else {
return memory_region_is_ram(mr) || memory_region_is_romd(mr);
}
return false;
}
/**
@ -1427,7 +1427,7 @@ MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
mr = address_space_translate(as, addr, &addr1, &l, false);
if (len == l && memory_access_is_direct(mr, false)) {
addr1 += memory_region_get_ram_addr(mr);
ptr = qemu_get_ram_ptr(addr1);
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
memcpy(buf, ptr, len);
} else {
result = address_space_read_continue(as, addr, attrs, buf, len,

View file

@ -493,4 +493,8 @@ int parse_debug_env(const char *name, int max, int initial);
const char *qemu_ether_ntoa(const MACAddr *mac);
void page_size_init(void);
/* returns non-zero if dump is in progress, otherwise zero is
* returned. */
bool dump_in_progress(void);
#endif

View file

@ -90,12 +90,6 @@ static inline void qemu_log_close(void)
}
}
/* Set up a new log file */
static inline void qemu_log_set_file(FILE *f)
{
qemu_logfile = f;
}
/* define log items */
typedef struct QEMULogItem {
int mask;

View file

@ -114,6 +114,16 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
void (*init)(struct CharDriverState *s),
Error **errp);
/**
* @qemu_chr_parse_common:
*
* Parse the common options available to all character backends.
*
* @opts the options that still need parsing
* @backend a new backend
*/
void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend);
/**
* @qemu_chr_new:
*

View file

@ -38,6 +38,7 @@
#include "sysemu/dump-arch.h"
#include "sysemu/memory_mapping.h"
#include "qapi-types.h"
typedef struct QEMU_PACKED MakedumpfileHeader {
char signature[16]; /* = "makedumpfile" */
@ -176,6 +177,20 @@ typedef struct DumpState {
off_t offset_page; /* offset of page part in vmcore */
size_t num_dumpable; /* number of page that can be dumped */
uint32_t flag_compress; /* indicate the compression format */
DumpStatus status; /* current dump status */
bool has_format; /* whether format is provided */
DumpGuestMemoryFormat format; /* valid only if has_format == true */
QemuThread dump_thread; /* thread for detached dump */
int64_t total_size; /* total memory size (in bytes) to
* be dumped. When filter is
* enabled, this will only count
* those to be written. */
int64_t written_size; /* written memory size (in bytes),
* this could be used to calculate
* how much work we have
* finished. */
} DumpState;
uint16_t cpu_to_dump16(DumpState *s, uint16_t val);

View file

@ -16,6 +16,7 @@
#include "qemu/queue.h"
#include "qemu/typedefs.h"
#include "exec/memory.h"
typedef struct GuestPhysBlock {
/* visible to guest, reflects PCI hole, etc */
@ -27,6 +28,9 @@ typedef struct GuestPhysBlock {
/* points into host memory */
uint8_t *host_addr;
/* points to the MemoryRegion that this block belongs to */
MemoryRegion *mr;
QTAILQ_ENTRY(GuestPhysBlock) next;
} GuestPhysBlock;

View file

@ -912,6 +912,7 @@ void memory_region_init(MemoryRegion *mr,
}
mr->name = g_strdup(name);
mr->owner = owner;
mr->ram_block = NULL;
if (name) {
char *escaped_name = memory_region_escape_name(name);
@ -1569,7 +1570,7 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr)
mr = mr->alias;
}
assert(mr->ram_addr != RAM_ADDR_INVALID);
ptr = qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK);
ptr = qemu_get_ram_ptr(mr->ram_block, mr->ram_addr & TARGET_PAGE_MASK);
rcu_read_unlock();
return ptr + offset;

View file

@ -178,6 +178,7 @@ void guest_phys_blocks_free(GuestPhysBlockList *list)
QTAILQ_FOREACH_SAFE(p, &list->head, next, q) {
QTAILQ_REMOVE(&list->head, p, next);
memory_region_unref(p->mr);
g_free(p);
}
list->num = 0;
@ -241,6 +242,8 @@ static void guest_phys_blocks_region_add(MemoryListener *listener,
block->target_start = target_start;
block->target_end = target_end;
block->host_addr = host_addr;
block->mr = section->mr;
memory_region_ref(section->mr);
QTAILQ_INSERT_TAIL(&g->list->head, block, next);
++g->list->num;

View file

@ -37,6 +37,7 @@
#include "qemu-options.h"
#include "qemu/rcu.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
#ifdef CONFIG_LINUX
#include <sys/prctl.h>
@ -275,7 +276,10 @@ void os_setup_post(void)
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
/* In case -D is given do not redirect stderr to /dev/null */
if (!qemu_logfile) {
dup2(fd, 2);
}
close(fd);

View file

@ -2195,6 +2195,10 @@
# 2. fd: the protocol starts with "fd:", and the following string
# is the fd's name.
#
# @detach: #optional if true, QMP will return immediately rather than
# waiting for the dump to finish. The user can track progress
# using "query-dump". (since 2.6).
#
# @begin: #optional if specified, the starting physical address.
#
# @length: #optional if specified, the memory size, in bytes. If you don't
@ -2211,8 +2215,56 @@
# Since: 1.2
##
{ 'command': 'dump-guest-memory',
'data': { 'paging': 'bool', 'protocol': 'str', '*begin': 'int',
'*length': 'int', '*format': 'DumpGuestMemoryFormat' } }
'data': { 'paging': 'bool', 'protocol': 'str', '*detach': 'bool',
'*begin': 'int', '*length': 'int',
'*format': 'DumpGuestMemoryFormat'} }
##
# @DumpStatus
#
# Describe the status of a long-running background guest memory dump.
#
# @none: no dump-guest-memory has started yet.
#
# @active: there is one dump running in background.
#
# @completed: the last dump has finished successfully.
#
# @failed: the last dump has failed.
#
# Since 2.6
##
{ 'enum': 'DumpStatus',
'data': [ 'none', 'active', 'completed', 'failed' ] }
##
# @DumpQueryResult
#
# The result format for 'query-dump'.
#
# @status: enum of @DumpStatus, which shows current dump status
#
# @completed: bytes written in latest dump (uncompressed)
#
# @total: total bytes to be written in latest dump (uncompressed)
#
# Since 2.6
##
{ 'struct': 'DumpQueryResult',
'data': { 'status': 'DumpStatus',
'completed': 'int',
'total': 'int' } }
##
# @query-dump
#
# Query latest dump status.
#
# Returns: A @DumpStatus object showing the dump status.
#
# Since: 2.6
##
{ 'command': 'query-dump', 'returns': 'DumpQueryResult' }
##
# @DumpGuestMemoryCapability:

View file

@ -369,3 +369,19 @@
##
{ 'event': 'MEM_UNPLUG_ERROR',
'data': { 'device': 'str', 'msg': 'str' } }
##
# @DUMP_COMPLETED
#
# Emitted when background dump has completed
#
# @result: DumpQueryResult type described in qapi-schema.json.
#
# @error: #optional human-readable error string that provides
# hint on why dump failed. Only presents on failure. The
# user should not try to interpret the error string.
#
# Since: 2.6
##
{ 'event': 'DUMP_COMPLETED' ,
'data': { 'result': 'DumpQueryResult', '*error': 'str' } }

View file

@ -3490,7 +3490,7 @@ fail:
return NULL;
}
static void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
{
const char *logfile = qemu_opt_get(opts, "logfile");

View file

@ -158,7 +158,8 @@ TODO (no longer available)
* pcsys_introduction:: Introduction
* pcsys_quickstart:: Quick Start
* sec_invocation:: Invocation
* pcsys_keys:: Keys
* pcsys_keys:: Keys in the graphical frontends
* mux_keys:: Keys in the character backend multiplexer
* pcsys_monitor:: QEMU Monitor
* disk_images:: Disk Images
* pcsys_network:: Network emulation
@ -272,7 +273,7 @@ targets do not need a disk image.
@c man end
@node pcsys_keys
@section Keys
@section Keys in the graphical frontends
@c man begin OPTIONS
@ -322,15 +323,23 @@ Toggle mouse and keyboard grab.
In the virtual consoles, you can use @key{Ctrl-Up}, @key{Ctrl-Down},
@key{Ctrl-PageUp} and @key{Ctrl-PageDown} to move in the back log.
@kindex Ctrl-a h
During emulation, if you are using the @option{-nographic} option, use
@key{Ctrl-a h} to get terminal commands:
@c man end
@node mux_keys
@section Keys in the character backend multiplexer
@c man begin OPTIONS
During emulation, if you are using a character backend multiplexer
(which is the default if you are using @option{-nographic}) then
several commands are available via an escape sequence. These
key sequences all start with an escape character, which is @key{Ctrl-a}
by default, but can be changed with @option{-echr}. The list below assumes
you're using the default.
@table @key
@item Ctrl-a h
@kindex Ctrl-a h
@item Ctrl-a ?
@kindex Ctrl-a ?
Print this help
@item Ctrl-a x
@kindex Ctrl-a x
@ -346,10 +355,11 @@ Toggle console timestamps
Send break (magic sysrq in Linux)
@item Ctrl-a c
@kindex Ctrl-a c
Switch between console and monitor
Rotate between the frontends connected to the multiplexer (usually
this switches between the monitor and the console)
@item Ctrl-a Ctrl-a
@kindex Ctrl-a a
Send Ctrl-a
@kindex Ctrl-a Ctrl-a
Send the escape character to the frontend
@end table
@c man end

View file

@ -2166,8 +2166,49 @@ All devices must have an id, which can be any string up to 127 characters long.
It is used to uniquely identify this device in other command line directives.
A character device may be used in multiplexing mode by multiple front-ends.
The key sequence of @key{Control-a} and @key{c} will rotate the input focus
between attached front-ends. Specify @option{mux=on} to enable this mode.
Specify @option{mux=on} to enable this mode.
A multiplexer is a "1:N" device, and here the "1" end is your specified chardev
backend, and the "N" end is the various parts of QEMU that can talk to a chardev.
If you create a chardev with @option{id=myid} and @option{mux=on}, QEMU will
create a multiplexer with your specified ID, and you can then configure multiple
front ends to use that chardev ID for their input/output. Up to four different
front ends can be connected to a single multiplexed chardev. (Without
multiplexing enabled, a chardev can only be used by a single front end.)
For instance you could use this to allow a single stdio chardev to be used by
two serial ports and the QEMU monitor:
@example
-chardev stdio,mux=on,id=char0 \
-mon chardev=char0,mode=readline,default \
-serial chardev:char0 \
-serial chardev:char0
@end example
You can have more than one multiplexer in a system configuration; for instance
you could have a TCP port multiplexed between UART 0 and UART 1, and stdio
multiplexed between the QEMU monitor and a parallel port:
@example
-chardev stdio,mux=on,id=char0 \
-mon chardev=char0,mode=readline,default \
-parallel chardev:char0 \
-chardev tcp,...,mux=on,id=char1 \
-serial chardev:char1 \
-serial chardev:char1
@end example
When you're using a multiplexed character device, some escape sequences are
interpreted in the input. @xref{mux_keys, Keys in the character backend
multiplexer}.
Note that some other command line options may implicitly create multiplexed
character backends; for instance @option{-serial mon:stdio} creates a
multiplexed stdio backend connected to the serial port and the QEMU monitor,
and @option{-nographic} also multiplexes the console and the monitor to
stdio.
There is currently no support for multiplexing in the other direction
(where a single QEMU front end takes input and output from multiple chardevs).
Every backend supports the @option{logfile} option, which supplies the path
to a file to record all data transmitted via the backend. The @option{logappend}

View file

@ -838,8 +838,8 @@ EQMP
{
.name = "dump-guest-memory",
.args_type = "paging:b,protocol:s,begin:i?,end:i?,format:s?",
.params = "-p protocol [begin] [length] [format]",
.args_type = "paging:b,protocol:s,detach:b?,begin:i?,end:i?,format:s?",
.params = "-p protocol [-d] [begin] [length] [format]",
.help = "dump guest memory to file",
.mhandler.cmd_new = qmp_marshal_dump_guest_memory,
},
@ -855,6 +855,9 @@ Arguments:
- "paging": do paging to get guest's memory mapping (json-bool)
- "protocol": destination file(started with "file:") or destination file
descriptor (started with "fd:") (json-string)
- "detach": if specified, command will return immediately, without waiting
for the dump to finish. The user can track progress using
"query-dump". (json-bool)
- "begin": the starting physical address. It's optional, and should be specified
with length together (json-int)
- "length": the memory size, in bytes. It's optional, and should be specified
@ -892,6 +895,30 @@ Example:
<- { "return": { "formats":
["elf", "kdump-zlib", "kdump-lzo", "kdump-snappy"] }
EQMP
{
.name = "query-dump",
.args_type = "",
.params = "",
.help = "query background dump status",
.mhandler.cmd_new = qmp_marshal_query_dump,
},
SQMP
query-dump
----------
Query background dump status.
Arguments: None.
Example:
-> { "execute": "query-dump" }
<- { "return": { "status": "active", "completed": 1024000,
"total": 2048000 } }
EQMP
#if defined TARGET_S390X

14
qmp.c
View file

@ -103,6 +103,13 @@ void qmp_quit(Error **errp)
void qmp_stop(Error **errp)
{
/* if there is a dump in background, we should wait until the dump
* finished */
if (dump_in_progress()) {
error_setg(errp, "There is a dump in process, please wait.");
return;
}
if (runstate_check(RUN_STATE_INMIGRATE)) {
autostart = 0;
} else {
@ -175,6 +182,13 @@ void qmp_cont(Error **errp)
BlockBackend *blk;
BlockDriverState *bs;
/* if there is a dump in background, we should wait until the dump
* finished */
if (dump_in_progress()) {
error_setg(errp, "There is a dump in process, please wait.");
return;
}
if (runstate_needs_reset()) {
error_setg(errp, "Resetting the Virtual Machine is required");
return;

View file

@ -796,11 +796,12 @@ def check_access(options):
sys.stderr.write("Please enable CONFIG_TRACING in your kernel "
"when using the option -t (default).\n"
"If it is enabled, make {0} readable by the "
"current user.\n")
"current user.\n"
.format(PATH_DEBUGFS_TRACING))
if options.tracepoints:
sys.exit(1)
sys.stderr.write("Falling back to debugfs statistics!\n"
sys.stderr.write("Falling back to debugfs statistics!\n")
options.debugfs = True
sleep(5)

View file

@ -366,26 +366,30 @@ static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend,
Error **errp)
{
const char *name = qemu_opt_get(opts, "name");
ChardevSpiceChannel *spicevmc;
if (name == NULL) {
error_setg(errp, "chardev: spice channel: no name given");
return;
}
backend->u.spicevmc = g_new0(ChardevSpiceChannel, 1);
backend->u.spicevmc->type = g_strdup(name);
spicevmc = backend->u.spicevmc = g_new0(ChardevSpiceChannel, 1);
qemu_chr_parse_common(opts, qapi_ChardevSpiceChannel_base(spicevmc));
spicevmc->type = g_strdup(name);
}
static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
Error **errp)
{
const char *name = qemu_opt_get(opts, "name");
ChardevSpicePort *spiceport;
if (name == NULL) {
error_setg(errp, "chardev: spice port: no name given");
return;
}
backend->u.spiceport = g_new0(ChardevSpicePort, 1);
backend->u.spiceport->fqdn = g_strdup(name);
spiceport = backend->u.spiceport = g_new0(ChardevSpicePort, 1);
qemu_chr_parse_common(opts, qapi_ChardevSpicePort_base(spiceport));
spiceport->fqdn = g_strdup(name);
}
static void register_types(void)

View file

@ -470,19 +470,26 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
#undef REGISTER
const ExtSaveArea x86_ext_save_areas[] = {
[2] = { .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX,
[XSTATE_YMM_BIT] =
{ .feature = FEAT_1_ECX, .bits = CPUID_EXT_AVX,
.offset = 0x240, .size = 0x100 },
[3] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
[XSTATE_BNDREGS_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
.offset = 0x3c0, .size = 0x40 },
[4] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
[XSTATE_BNDCSR_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_MPX,
.offset = 0x400, .size = 0x40 },
[5] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
[XSTATE_OPMASK_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
.offset = 0x440, .size = 0x40 },
[6] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
[XSTATE_ZMM_Hi256_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
.offset = 0x480, .size = 0x200 },
[7] = { .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
[XSTATE_Hi16_ZMM_BIT] =
{ .feature = FEAT_7_0_EBX, .bits = CPUID_7_0_EBX_AVX512F,
.offset = 0x680, .size = 0x400 },
[9] = { .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU,
[XSTATE_PKRU_BIT] =
{ .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU,
.offset = 0xA80, .size = 0x8 },
};
@ -2480,7 +2487,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx = MAX(*ecx, esa->offset + esa->size);
}
}
*eax |= ena_mask & (XSTATE_FP | XSTATE_SSE);
*eax |= ena_mask & (XSTATE_FP_MASK | XSTATE_SSE_MASK);
*ebx = *ecx;
} else if (count == 1) {
*eax = env->features[FEAT_XSAVE];
@ -2714,15 +2721,15 @@ static void x86_cpu_reset(CPUState *s)
cpu_watchpoint_remove_all(s, BP_CPU);
cr4 = 0;
xcr0 = XSTATE_FP;
xcr0 = XSTATE_FP_MASK;
#ifdef CONFIG_USER_ONLY
/* Enable all the features for user-mode. */
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
xcr0 |= XSTATE_SSE;
xcr0 |= XSTATE_SSE_MASK;
}
if (env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_MPX) {
xcr0 |= XSTATE_BNDREGS | XSTATE_BNDCSR;
xcr0 |= XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK;
}
if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
cr4 |= CR4_OSFXSR_MASK | CR4_OSXSAVE_MASK;

View file

@ -404,16 +404,25 @@
#define MSR_IA32_BNDCFGS 0x00000d90
#define MSR_IA32_XSS 0x00000da0
#define XSTATE_FP (1ULL << 0)
#define XSTATE_SSE (1ULL << 1)
#define XSTATE_YMM (1ULL << 2)
#define XSTATE_BNDREGS (1ULL << 3)
#define XSTATE_BNDCSR (1ULL << 4)
#define XSTATE_OPMASK (1ULL << 5)
#define XSTATE_ZMM_Hi256 (1ULL << 6)
#define XSTATE_Hi16_ZMM (1ULL << 7)
#define XSTATE_PKRU (1ULL << 9)
#define XSTATE_FP_BIT 0
#define XSTATE_SSE_BIT 1
#define XSTATE_YMM_BIT 2
#define XSTATE_BNDREGS_BIT 3
#define XSTATE_BNDCSR_BIT 4
#define XSTATE_OPMASK_BIT 5
#define XSTATE_ZMM_Hi256_BIT 6
#define XSTATE_Hi16_ZMM_BIT 7
#define XSTATE_PKRU_BIT 9
#define XSTATE_FP_MASK (1ULL << XSTATE_FP_BIT)
#define XSTATE_SSE_MASK (1ULL << XSTATE_SSE_BIT)
#define XSTATE_YMM_MASK (1ULL << XSTATE_YMM_BIT)
#define XSTATE_BNDREGS_MASK (1ULL << XSTATE_BNDREGS_BIT)
#define XSTATE_BNDCSR_MASK (1ULL << XSTATE_BNDCSR_BIT)
#define XSTATE_OPMASK_MASK (1ULL << XSTATE_OPMASK_BIT)
#define XSTATE_ZMM_Hi256_MASK (1ULL << XSTATE_ZMM_Hi256_BIT)
#define XSTATE_Hi16_ZMM_MASK (1ULL << XSTATE_Hi16_ZMM_BIT)
#define XSTATE_PKRU_MASK (1ULL << XSTATE_PKRU_BIT)
/* CPUID feature words */
typedef enum FeatureWord {

View file

@ -1215,7 +1215,7 @@ static uint64_t get_xinuse(CPUX86State *env)
indicate in use. That said, the state of BNDREGS is important
enough to track in HFLAGS, so we might as well use that here. */
if ((env->hflags & HF_MPX_IU_MASK) == 0) {
inuse &= ~XSTATE_BNDREGS;
inuse &= ~XSTATE_BNDREGS_MASK;
}
return inuse;
}
@ -1239,22 +1239,22 @@ static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm,
rfbm &= env->xcr0;
opt &= rfbm;
if (opt & XSTATE_FP) {
if (opt & XSTATE_FP_MASK) {
do_xsave_fpu(env, ptr, ra);
}
if (rfbm & XSTATE_SSE) {
if (rfbm & XSTATE_SSE_MASK) {
/* Note that saving MXCSR is not suppressed by XSAVEOPT. */
do_xsave_mxcsr(env, ptr, ra);
}
if (opt & XSTATE_SSE) {
if (opt & XSTATE_SSE_MASK) {
do_xsave_sse(env, ptr, ra);
}
if (opt & XSTATE_BNDREGS) {
target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS].offset;
if (opt & XSTATE_BNDREGS_MASK) {
target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS_BIT].offset;
do_xsave_bndregs(env, ptr + off, ra);
}
if (opt & XSTATE_BNDCSR) {
target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR].offset;
if (opt & XSTATE_BNDCSR_MASK) {
target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR_BIT].offset;
do_xsave_bndcsr(env, ptr + off, ra);
}
@ -1399,19 +1399,19 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
raise_exception_ra(env, EXCP0D_GPF, ra);
}
if (rfbm & XSTATE_FP) {
if (xstate_bv & XSTATE_FP) {
if (rfbm & XSTATE_FP_MASK) {
if (xstate_bv & XSTATE_FP_MASK) {
do_xrstor_fpu(env, ptr, ra);
} else {
helper_fninit(env);
memset(env->fpregs, 0, sizeof(env->fpregs));
}
}
if (rfbm & XSTATE_SSE) {
if (rfbm & XSTATE_SSE_MASK) {
/* Note that the standard form of XRSTOR loads MXCSR from memory
whether or not the XSTATE_BV bit is set. */
do_xrstor_mxcsr(env, ptr, ra);
if (xstate_bv & XSTATE_SSE) {
if (xstate_bv & XSTATE_SSE_MASK) {
do_xrstor_sse(env, ptr, ra);
} else {
/* ??? When AVX is implemented, we may have to be more
@ -1419,9 +1419,9 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
memset(env->xmm_regs, 0, sizeof(env->xmm_regs));
}
}
if (rfbm & XSTATE_BNDREGS) {
if (xstate_bv & XSTATE_BNDREGS) {
target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS].offset;
if (rfbm & XSTATE_BNDREGS_MASK) {
if (xstate_bv & XSTATE_BNDREGS_MASK) {
target_ulong off = x86_ext_save_areas[XSTATE_BNDREGS_BIT].offset;
do_xrstor_bndregs(env, ptr + off, ra);
env->hflags |= HF_MPX_IU_MASK;
} else {
@ -1429,9 +1429,9 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
env->hflags &= ~HF_MPX_IU_MASK;
}
}
if (rfbm & XSTATE_BNDCSR) {
if (xstate_bv & XSTATE_BNDCSR) {
target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR].offset;
if (rfbm & XSTATE_BNDCSR_MASK) {
if (xstate_bv & XSTATE_BNDCSR_MASK) {
target_ulong off = x86_ext_save_areas[XSTATE_BNDCSR_BIT].offset;
do_xrstor_bndcsr(env, ptr + off, ra);
} else {
memset(&env->bndcs_regs, 0, sizeof(env->bndcs_regs));
@ -1470,7 +1470,7 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask)
}
/* Only XCR0 is defined at present; the FPU may not be disabled. */
if (ecx != 0 || (mask & XSTATE_FP) == 0) {
if (ecx != 0 || (mask & XSTATE_FP_MASK) == 0) {
goto do_gpf;
}
@ -1482,7 +1482,8 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask)
}
/* Disallow enabling only half of MPX. */
if ((mask ^ (mask * (XSTATE_BNDCSR / XSTATE_BNDREGS))) & XSTATE_BNDCSR) {
if ((mask ^ (mask * (XSTATE_BNDCSR_MASK / XSTATE_BNDREGS_MASK)))
& XSTATE_BNDCSR_MASK) {
goto do_gpf;
}

View file

@ -36,7 +36,7 @@ void cpu_sync_bndcs_hflags(CPUX86State *env)
}
if ((env->cr[4] & CR4_OSXSAVE_MASK)
&& (env->xcr0 & XSTATE_BNDCSR)
&& (env->xcr0 & XSTATE_BNDCSR_MASK)
&& (bndcsr & BNDCFG_ENABLE)) {
hflags |= HF_MPX_EN_MASK;
} else {

View file

@ -2060,31 +2060,33 @@ static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
Error **errp)
{
int val;
ChardevVC *vc;
backend->u.vc = g_new0(ChardevVC, 1);
vc = backend->u.vc = g_new0(ChardevVC, 1);
qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
val = qemu_opt_get_number(opts, "width", 0);
if (val != 0) {
backend->u.vc->has_width = true;
backend->u.vc->width = val;
vc->has_width = true;
vc->width = val;
}
val = qemu_opt_get_number(opts, "height", 0);
if (val != 0) {
backend->u.vc->has_height = true;
backend->u.vc->height = val;
vc->has_height = true;
vc->height = val;
}
val = qemu_opt_get_number(opts, "cols", 0);
if (val != 0) {
backend->u.vc->has_cols = true;
backend->u.vc->cols = val;
vc->has_cols = true;
vc->cols = val;
}
val = qemu_opt_get_number(opts, "rows", 0);
if (val != 0) {
backend->u.vc->has_rows = true;
backend->u.vc->rows = val;
vc->has_rows = true;
vc->rows = val;
}
}

View file

@ -56,13 +56,20 @@ void do_qemu_set_log(int log_flags, bool use_own_buffers)
#ifdef CONFIG_TRACE_LOG
qemu_loglevel |= LOG_TRACE;
#endif
if (qemu_loglevel && !qemu_logfile) {
if ((qemu_loglevel || is_daemonized()) && !qemu_logfile) {
if (logfilename) {
qemu_logfile = fopen(logfilename, log_append ? "a" : "w");
if (!qemu_logfile) {
perror(logfilename);
_exit(1);
}
/* In case we are a daemon redirect stderr to logfile */
if (is_daemonized()) {
dup2(fileno(qemu_logfile), STDERR_FILENO);
fclose(qemu_logfile);
/* This will skip closing logfile in qemu_log_close() */
qemu_logfile = stderr;
}
} else {
/* Default to stderr if no log file specified */
qemu_logfile = stderr;
@ -82,7 +89,7 @@ void do_qemu_set_log(int log_flags, bool use_own_buffers)
log_append = 1;
}
}
if (!qemu_loglevel && qemu_logfile) {
if (!qemu_loglevel && !is_daemonized() && qemu_logfile) {
qemu_log_close();
}
}