* 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:
		
						commit
						586fc27e6a
					
				| 
						 | 
				
			
			@ -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
								
								
								
								
							
							
						
						
									
										215
									
								
								dump.c
								
								
								
								
							| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										46
									
								
								exec.c
								
								
								
								
							
							
						
						
									
										46
									
								
								exec.c
								
								
								
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
								
								
								
								
							
							
						
						
									
										26
									
								
								hmp.c
								
								
								
								
							| 
						 | 
				
			
			@ -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
								
								
								
								
							
							
						
						
									
										1
									
								
								hmp.h
								
								
								
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								memory.c
								
								
								
								
							
							
						
						
									
										3
									
								
								memory.c
								
								
								
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
        /* In case -D is given do not redirect stderr to /dev/null */
 | 
			
		||||
        if (!qemu_logfile) {
 | 
			
		||||
            dup2(fd, 2);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        close(fd);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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' } }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
								
								
								
								
							
							
						
						
									
										14
									
								
								qmp.c
								
								
								
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								ui/console.c
								
								
								
								
							
							
						
						
									
										20
									
								
								ui/console.c
								
								
								
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								util/log.c
								
								
								
								
							
							
						
						
									
										11
									
								
								util/log.c
								
								
								
								
							| 
						 | 
				
			
			@ -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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue