* configure fix for environment variables (Daniel)

* fix memory leaks (Alex)
 * x86_64 MTTCG fixes (Emilio)
 * introduce atomic64 (Emilio)
 * Fix for virtio hang (Fam, myself)
 * SH serial port fix (Geert)
 * Deprecate rotation_rate for scsi-block (Fam)
 * Extend memory-backend-file availability to all POSIX hosts (Hikaru)
 * Memory API cleanups and fixes (Igor, Li Qiang, Peter, Philippe)
 * MSI/IOMMU fix (Jan)
 * Socket reconnection fixes (Marc-André)
 * icount fixes (Emilio, myself)
 * QSP fixes for Coverity (myself)
 * Some record/replay improovements (Pavel)
 * Packed struct fixes (Peter)
 * Windows dump fixes and elf2dmp (Viktor)
 * kbmclock fix (Yongji)
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQEcBAABAgAGBQJbs6coAAoJEL/70l94x66DaL0IAISiRZcm7SMFTUafivyzQ9Ao
 vk2SZ64/BUmDI5q5t30NGiVkMzAc0qDunRSqD4FnIvhGl8phFSSYqaN28JFLe4l1
 JhX7FdLQgeevYY35hEPjpCEOAR7WD116/NaZ/UZ+7zZ4Z+CtcCEXZefb4dD9vijj
 M/rH7vXJsulSb7q2Np3hhbai/GL7ZvNURaHOXZpuPE2aJGAcSXhYtAbGHPJ4NKgn
 qjP3AGTose8cRD0u5smY0JnyL5vcF606+dupIUsnciDC3wF1SPusTMwLRLoEGNA4
 lmxTdGbxvvM1TDu/mY70WYXJ2ujC9Suhj1jkftgDTWRZqwQ9N/B4eB2JcQ9WbhQ=
 =SzeA
 -----END PGP SIGNATURE-----

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

* configure fix for environment variables (Daniel)
* fix memory leaks (Alex)
* x86_64 MTTCG fixes (Emilio)
* introduce atomic64 (Emilio)
* Fix for virtio hang (Fam, myself)
* SH serial port fix (Geert)
* Deprecate rotation_rate for scsi-block (Fam)
* Extend memory-backend-file availability to all POSIX hosts (Hikaru)
* Memory API cleanups and fixes (Igor, Li Qiang, Peter, Philippe)
* MSI/IOMMU fix (Jan)
* Socket reconnection fixes (Marc-André)
* icount fixes (Emilio, myself)
* QSP fixes for Coverity (myself)
* Some record/replay improovements (Pavel)
* Packed struct fixes (Peter)
* Windows dump fixes and elf2dmp (Viktor)
* kbmclock fix (Yongji)

# gpg: Signature made Tue 02 Oct 2018 18:13:12 BST
# gpg:                using RSA key BFFBD25F78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>"
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>"
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* remotes/bonzini/tags/for-upstream: (80 commits)
  hw/scsi/mptendian: Avoid taking address of fields in packed structs
  cpus: fix TCG kick timer leak
  docs/devel/memory.txt: Document _with_attrs accessors
  hw/nvram/fw_cfg: Use memberwise copy of MemoryRegionOps struct
  memory: Remove old_mmio accessors
  memory: Fix access_with_adjusted_size(small size) on big-endian memory regions
  memory: Refactor common shifting code from accessors
  memory: Use MAKE_64BIT_MASK()
  virtio: do not take address of packed members
  replay: replay BH for IDE trim operation
  hostmem-file: make available memory-backend-file on POSIX-based hosts
  target/i386: fix translation for icount mode
  hvf: drop unused variable
  qom/object: add some interface asserts
  accel/tcg: Remove dead code
  lsi53c895a: convert to trace-events
  scsi-block: Deprecate rotation_rate
  kvmclock: run KVM_KVMCLOCK_CTRL ioctl in vcpu thread
  MAINTAINERS: add myself as elf2dmp maintainer
  contrib: add elf2dmp tool
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-10-02 18:27:18 +01:00
commit dafd950536
100 changed files with 4825 additions and 2188 deletions

View File

@ -1903,6 +1903,11 @@ S: Maintained
F: include/qemu/iova-tree.h
F: util/iova-tree.c
elf2dmp
M: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
S: Maintained
F: contrib/elf2dmp/
Usermode Emulation
------------------
Overall

View File

@ -415,6 +415,7 @@ dummy := $(call unnest-vars,, \
chardev-obj-y \
util-obj-y \
qga-obj-y \
elf2dmp-obj-y \
ivshmem-client-obj-y \
ivshmem-server-obj-y \
libvhost-user-obj-y \
@ -710,6 +711,10 @@ ifneq ($(EXESUF),)
qemu-ga: qemu-ga$(EXESUF) $(QGA_VSS_PROVIDER) $(QEMU_GA_MSI)
endif
elf2dmp: LIBS = $(CURL_LIBS)
elf2dmp: $(elf2dmp-obj-y)
$(call LINK, $^)
ifdef CONFIG_IVSHMEM
ivshmem-client$(EXESUF): $(ivshmem-client-obj-y) $(COMMON_LDADDS)
$(call LINK, $^)

View File

@ -186,6 +186,7 @@ qga-vss-dll-obj-y = qga/
######################################################################
# contrib
elf2dmp-obj-y = contrib/elf2dmp/
ivshmem-client-obj-$(CONFIG_IVSHMEM) = contrib/ivshmem-client/
ivshmem-server-obj-$(CONFIG_IVSHMEM) = contrib/ivshmem-server/
libvhost-user-obj-y = contrib/libvhost-user/

View File

@ -2009,15 +2009,6 @@ void tb_invalidate_phys_page_fast(struct page_collection *pages,
{
PageDesc *p;
#if 0
if (1) {
qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
cpu_single_env->mem_io_vaddr, len,
cpu_single_env->eip,
cpu_single_env->eip +
(intptr_t)cpu_single_env->segs[R_CS].base);
}
#endif
assert_memory_lock();
p = page_find(start >> TARGET_PAGE_BITS);

View File

@ -34,6 +34,8 @@ void translator_loop_temp_check(DisasContextBase *db)
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
CPUState *cpu, TranslationBlock *tb)
{
int bp_insn = 0;
/* Initialize DisasContext */
db->tb = tb;
db->pc_first = tb->pc;
@ -71,11 +73,13 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
/* Pass breakpoint hits to target for further processing */
if (unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
if (!db->singlestep_enabled
&& unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
CPUBreakpoint *bp;
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
if (bp->pc == db->pc_next) {
if (ops->breakpoint_check(db, cpu, bp)) {
bp_insn = 1;
break;
}
}
@ -118,7 +122,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
/* Emit code to exit the TB, as indicated by db->is_jmp. */
ops->tb_stop(db, cpu);
gen_tb_end(db->tb, db->num_insns);
gen_tb_end(db->tb, db->num_insns - bp_insn);
/* The disas_log hook may use these values rather than recompute. */
db->tb->size = db->pc_next - db->pc_first;

View File

@ -4,7 +4,7 @@ common-obj-$(CONFIG_POSIX) += rng-random.o
common-obj-$(CONFIG_TPM) += tpm.o
common-obj-y += hostmem.o hostmem-ram.o
common-obj-$(CONFIG_LINUX) += hostmem-file.o
common-obj-$(CONFIG_POSIX) += hostmem-file.o
common-obj-y += cryptodev.o
common-obj-y += cryptodev-builtin.o

View File

@ -51,7 +51,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
error_setg(errp, "mem-path property not set");
return;
}
#ifndef CONFIG_LINUX
#ifndef CONFIG_POSIX
error_setg(errp, "-mem-path not supported on this host");
#else
if (!host_memory_backend_mr_inited(backend)) {

View File

@ -140,18 +140,22 @@ memfd_backend_class_init(ObjectClass *oc, void *data)
bc->alloc = memfd_backend_memory_alloc;
object_class_property_add_bool(oc, "hugetlb",
memfd_backend_get_hugetlb,
memfd_backend_set_hugetlb,
&error_abort);
object_class_property_add(oc, "hugetlbsize", "int",
memfd_backend_get_hugetlbsize,
memfd_backend_set_hugetlbsize,
NULL, NULL, &error_abort);
object_class_property_add_bool(oc, "seal",
memfd_backend_get_seal,
memfd_backend_set_seal,
&error_abort);
if (qemu_memfd_check(MFD_HUGETLB)) {
object_class_property_add_bool(oc, "hugetlb",
memfd_backend_get_hugetlb,
memfd_backend_set_hugetlb,
&error_abort);
object_class_property_add(oc, "hugetlbsize", "int",
memfd_backend_get_hugetlbsize,
memfd_backend_set_hugetlbsize,
NULL, NULL, &error_abort);
}
if (qemu_memfd_check(MFD_ALLOW_SEALING)) {
object_class_property_add_bool(oc, "seal",
memfd_backend_get_seal,
memfd_backend_set_seal,
&error_abort);
}
}
static const TypeInfo memfd_backend_info = {
@ -164,7 +168,9 @@ static const TypeInfo memfd_backend_info = {
static void register_types(void)
{
type_register_static(&memfd_backend_info);
if (qemu_memfd_check(0)) {
type_register_static(&memfd_backend_info);
}
}
type_init(register_types);

View File

@ -31,10 +31,6 @@
#include "chardev/char-io.h"
#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
|| defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
|| defined(__GLIBC__)
typedef struct {
Chardev parent;
QIOChannel *ioc;
@ -299,5 +295,3 @@ static void register_types(void)
}
type_init(register_types);
#endif

View File

@ -32,7 +32,6 @@
#include "qapi/error.h"
#include "qapi/clone-visitor.h"
#include "qapi/qapi-visit-sockets.h"
#include "sysemu/sysemu.h"
#include "chardev/char-io.h"
@ -354,6 +353,15 @@ static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond)
return qio_channel_create_watch(s->ioc, cond);
}
static void remove_hup_source(SocketChardev *s)
{
if (s->hup_source != NULL) {
g_source_destroy(s->hup_source);
g_source_unref(s->hup_source);
s->hup_source = NULL;
}
}
static void tcp_chr_free_connection(Chardev *chr)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
@ -368,11 +376,7 @@ static void tcp_chr_free_connection(Chardev *chr)
s->read_msgfds_num = 0;
}
if (s->hup_source != NULL) {
g_source_destroy(s->hup_source);
g_source_unref(s->hup_source);
s->hup_source = NULL;
}
remove_hup_source(s);
tcp_set_msgfds(chr, NULL, 0);
remove_fd_in_watch(chr);
@ -541,6 +545,27 @@ static char *sockaddr_to_str(struct sockaddr_storage *ss, socklen_t ss_len,
}
}
static void update_ioc_handlers(SocketChardev *s)
{
Chardev *chr = CHARDEV(s);
if (!s->connected) {
return;
}
remove_fd_in_watch(chr);
chr->gsource = io_add_watch_poll(chr, s->ioc,
tcp_chr_read_poll,
tcp_chr_read, chr,
chr->gcontext);
remove_hup_source(s);
s->hup_source = qio_channel_create_watch(s->ioc, G_IO_HUP);
g_source_set_callback(s->hup_source, (GSourceFunc)tcp_chr_hup,
chr, NULL);
g_source_attach(s->hup_source, chr->gcontext);
}
static void tcp_chr_connect(void *opaque)
{
Chardev *chr = CHARDEV(opaque);
@ -553,16 +578,7 @@ static void tcp_chr_connect(void *opaque)
s->is_listen, s->is_telnet);
s->connected = 1;
chr->gsource = io_add_watch_poll(chr, s->ioc,
tcp_chr_read_poll,
tcp_chr_read,
chr, chr->gcontext);
s->hup_source = qio_channel_create_watch(s->ioc, G_IO_HUP);
g_source_set_callback(s->hup_source, (GSourceFunc)tcp_chr_hup,
chr, NULL);
g_source_attach(s->hup_source, chr->gcontext);
update_ioc_handlers(s);
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
}
@ -593,17 +609,7 @@ static void tcp_chr_update_read_handler(Chardev *chr)
tcp_chr_telnet_init(CHARDEV(s));
}
if (!s->connected) {
return;
}
remove_fd_in_watch(chr);
if (s->ioc) {
chr->gsource = io_add_watch_poll(chr, s->ioc,
tcp_chr_read_poll,
tcp_chr_read, chr,
chr->gcontext);
}
update_ioc_handlers(s);
}
static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
@ -724,11 +730,6 @@ static void tcp_chr_tls_init(Chardev *chr)
Error *err = NULL;
gchar *name;
if (!machine_init_done) {
/* This will be postponed to machine_done notifier */
return;
}
if (s->is_listen) {
tioc = qio_channel_tls_new_server(
s->ioc, s->tls_creds,
@ -1011,8 +1012,9 @@ static void qmp_chardev_open_socket(Chardev *chr,
s->reconnect_time = reconnect;
}
/* If reconnect_time is set, will do that in chr_machine_done. */
if (!s->reconnect_time) {
if (s->reconnect_time) {
tcp_chr_connect_async(chr);
} else {
if (s->is_listen) {
char *name;
s->listener = qio_net_listener_new();
@ -1161,21 +1163,6 @@ char_socket_get_connected(Object *obj, Error **errp)
return s->connected;
}
static int tcp_chr_machine_done_hook(Chardev *chr)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
if (s->reconnect_time) {
tcp_chr_connect_async(chr);
}
if (s->ioc && s->tls_creds) {
tcp_chr_tls_init(chr);
}
return 0;
}
static void char_socket_class_init(ObjectClass *oc, void *data)
{
ChardevClass *cc = CHARDEV_CLASS(oc);
@ -1191,7 +1178,6 @@ static void char_socket_class_init(ObjectClass *oc, void *data)
cc->chr_add_client = tcp_chr_add_client;
cc->chr_add_watch = tcp_chr_add_watch;
cc->chr_update_read_handler = tcp_chr_update_read_handler;
cc->chr_machine_done = tcp_chr_machine_done_hook;
object_class_property_add(oc, "addr", "SocketAddress",
char_socket_get_addr, NULL,

45
configure vendored
View File

@ -5721,6 +5721,9 @@ if test "$want_tools" = "yes" ; then
if [ "$ivshmem" = "yes" ]; then
tools="ivshmem-client\$(EXESUF) ivshmem-server\$(EXESUF) $tools"
fi
if [ "$posix" = "yes" ] && [ "$curl" = "yes" ]; then
tools="elf2dmp $tools"
fi
fi
if test "$softmmu" = yes ; then
if test "$linux" = yes; then
@ -7024,12 +7027,14 @@ TARGET_ABI_DIR=""
case "$target_name" in
i386)
mttcg="yes"
gdb_xml_files="i386-32bit.xml i386-32bit-core.xml i386-32bit-sse.xml"
target_compiler=$cross_cc_i386
target_compiler_cflags=$cross_cc_ccflags_i386
;;
x86_64)
TARGET_BASE_ARCH=i386
mttcg="yes"
gdb_xml_files="i386-64bit.xml i386-64bit-core.xml i386-64bit-sse.xml"
target_compiler=$cross_cc_x86_64
;;
@ -7527,6 +7532,46 @@ cat <<EOD >config.status
# Compiler output produced by configure, useful for debugging
# configure, is in config.log if it exists.
EOD
preserve_env() {
envname=$1
eval envval=\$$envname
if test -n "$envval"
then
echo "$envname='$envval'" >> config.status
echo "export $envname" >> config.status
else
echo "unset $envname" >> config.status
fi
}
# Preserve various env variables that influence what
# features/build target configure will detect
preserve_env AR
preserve_env AS
preserve_env CC
preserve_env CPP
preserve_env CXX
preserve_env INSTALL
preserve_env LD
preserve_env LD_LIBRARY_PATH
preserve_env LIBTOOL
preserve_env MAKE
preserve_env NM
preserve_env OBJCOPY
preserve_env PATH
preserve_env PKG_CONFIG
preserve_env PKG_CONFIG_LIBDIR
preserve_env PKG_CONFIG_PATH
preserve_env PYTHON
preserve_env SDL_CONFIG
preserve_env SDL2_CONFIG
preserve_env SMBD
preserve_env STRIP
preserve_env WINDRES
printf "exec" >>config.status
printf " '%s'" "$0" "$@" >>config.status
echo ' "$@"' >>config.status

View File

@ -0,0 +1 @@
elf2dmp-obj-y = main.o addrspace.o download.o pdb.o qemu_elf.o

233
contrib/elf2dmp/addrspace.c Normal file
View File

@ -0,0 +1,233 @@
/*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
*
*/
#include "qemu/osdep.h"
#include "addrspace.h"
static struct pa_block *pa_space_find_block(struct pa_space *ps, uint64_t pa)
{
size_t i;
for (i = 0; i < ps->block_nr; i++) {
if (ps->block[i].paddr <= pa &&
pa <= ps->block[i].paddr + ps->block[i].size) {
return ps->block + i;
}
}
return NULL;
}
static uint8_t *pa_space_resolve(struct pa_space *ps, uint64_t pa)
{
struct pa_block *block = pa_space_find_block(ps, pa);
if (!block) {
return NULL;
}
return block->addr + (pa - block->paddr);
}
int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
{
Elf64_Half phdr_nr = elf_getphdrnum(qemu_elf->map);
Elf64_Phdr *phdr = elf64_getphdr(qemu_elf->map);
size_t block_i = 0;
size_t i;
ps->block_nr = 0;
for (i = 0; i < phdr_nr; i++) {
if (phdr[i].p_type == PT_LOAD) {
ps->block_nr++;
}
}
ps->block = malloc(sizeof(*ps->block) * ps->block_nr);
if (!ps->block) {
return 1;
}
for (i = 0; i < phdr_nr; i++) {
if (phdr[i].p_type == PT_LOAD) {
ps->block[block_i] = (struct pa_block) {
.addr = (uint8_t *)qemu_elf->map + phdr[i].p_offset,
.paddr = phdr[i].p_paddr,
.size = phdr[i].p_filesz,
};
block_i++;
}
}
return 0;
}
void pa_space_destroy(struct pa_space *ps)
{
ps->block_nr = 0;
free(ps->block);
}
void va_space_set_dtb(struct va_space *vs, uint64_t dtb)
{
vs->dtb = dtb & 0x00ffffffffff000;
}
void va_space_create(struct va_space *vs, struct pa_space *ps, uint64_t dtb)
{
vs->ps = ps;
va_space_set_dtb(vs, dtb);
}
static uint64_t get_pml4e(struct va_space *vs, uint64_t va)
{
uint64_t pa = (vs->dtb & 0xffffffffff000) | ((va & 0xff8000000000) >> 36);
return *(uint64_t *)pa_space_resolve(vs->ps, pa);
}
static uint64_t get_pdpi(struct va_space *vs, uint64_t va, uint64_t pml4e)
{
uint64_t pdpte_paddr = (pml4e & 0xffffffffff000) |
((va & 0x7FC0000000) >> 27);
return *(uint64_t *)pa_space_resolve(vs->ps, pdpte_paddr);
}
static uint64_t pde_index(uint64_t va)
{
return (va >> 21) & 0x1FF;
}
static uint64_t pdba_base(uint64_t pdpe)
{
return pdpe & 0xFFFFFFFFFF000;
}
static uint64_t get_pgd(struct va_space *vs, uint64_t va, uint64_t pdpe)
{
uint64_t pgd_entry = pdba_base(pdpe) + pde_index(va) * 8;
return *(uint64_t *)pa_space_resolve(vs->ps, pgd_entry);
}
static uint64_t pte_index(uint64_t va)
{
return (va >> 12) & 0x1FF;
}
static uint64_t ptba_base(uint64_t pde)
{
return pde & 0xFFFFFFFFFF000;
}
static uint64_t get_pte(struct va_space *vs, uint64_t va, uint64_t pgd)
{
uint64_t pgd_val = ptba_base(pgd) + pte_index(va) * 8;
return *(uint64_t *)pa_space_resolve(vs->ps, pgd_val);
}
static uint64_t get_paddr(uint64_t va, uint64_t pte)
{
return (pte & 0xFFFFFFFFFF000) | (va & 0xFFF);
}
static bool is_present(uint64_t entry)
{
return entry & 0x1;
}
static bool page_size_flag(uint64_t entry)
{
return entry & (1 << 7);
}
static uint64_t get_1GB_paddr(uint64_t va, uint64_t pdpte)
{
return (pdpte & 0xfffffc0000000) | (va & 0x3fffffff);
}
static uint64_t get_2MB_paddr(uint64_t va, uint64_t pgd_entry)
{
return (pgd_entry & 0xfffffffe00000) | (va & 0x00000001fffff);
}
static uint64_t va_space_va2pa(struct va_space *vs, uint64_t va)
{
uint64_t pml4e, pdpe, pgd, pte;
pml4e = get_pml4e(vs, va);
if (!is_present(pml4e)) {
return INVALID_PA;
}
pdpe = get_pdpi(vs, va, pml4e);
if (!is_present(pdpe)) {
return INVALID_PA;
}
if (page_size_flag(pdpe)) {
return get_1GB_paddr(va, pdpe);
}
pgd = get_pgd(vs, va, pdpe);
if (!is_present(pgd)) {
return INVALID_PA;
}
if (page_size_flag(pgd)) {
return get_2MB_paddr(va, pgd);
}
pte = get_pte(vs, va, pgd);
if (!is_present(pte)) {
return INVALID_PA;
}
return get_paddr(va, pte);
}
void *va_space_resolve(struct va_space *vs, uint64_t va)
{
uint64_t pa = va_space_va2pa(vs, va);
if (pa == INVALID_PA) {
return NULL;
}
return pa_space_resolve(vs->ps, pa);
}
int va_space_rw(struct va_space *vs, uint64_t addr,
void *buf, size_t size, int is_write)
{
while (size) {
uint64_t page = addr & PFN_MASK;
size_t s = (page + PAGE_SIZE) - addr;
void *ptr;
s = (s > size) ? size : s;
ptr = va_space_resolve(vs, addr);
if (!ptr) {
return 1;
}
if (is_write) {
memcpy(ptr, buf, s);
} else {
memcpy(buf, ptr, s);
}
size -= s;
buf = (uint8_t *)buf + s;
addr += s;
}
return 0;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
*
*/
#ifndef ADDRSPACE_H
#define ADDRSPACE_H
#include "qemu_elf.h"
#define PAGE_BITS 12
#define PAGE_SIZE (1ULL << PAGE_BITS)
#define PFN_MASK (~(PAGE_SIZE - 1))
#define INVALID_PA UINT64_MAX
struct pa_block {
uint8_t *addr;
uint64_t paddr;
uint64_t size;
};
struct pa_space {
size_t block_nr;
struct pa_block *block;
};
struct va_space {
uint64_t dtb;
struct pa_space *ps;
};
int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf);
void pa_space_destroy(struct pa_space *ps);
void va_space_create(struct va_space *vs, struct pa_space *ps, uint64_t dtb);
void va_space_set_dtb(struct va_space *vs, uint64_t dtb);
void *va_space_resolve(struct va_space *vs, uint64_t va);
int va_space_rw(struct va_space *vs, uint64_t addr,
void *buf, size_t size, int is_write);
#endif /* ADDRSPACE_H */

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
*
*/
#include "qemu/osdep.h"
#include <curl/curl.h>
#include "download.h"
int download_url(const char *name, const char *url)
{
int err = 0;
FILE *file;
CURL *curl = curl_easy_init();
if (!curl) {
return 1;
}
file = fopen(name, "wb");
if (!file) {
err = 1;
goto out_curl;
}
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
if (curl_easy_perform(curl) != CURLE_OK) {
err = 1;
fclose(file);
unlink(name);
goto out_curl;
}
err = fclose(file);
out_curl:
curl_easy_cleanup(curl);
return err;
}

View File

@ -0,0 +1,13 @@
/*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
*
*/
#ifndef DOWNLOAD_H
#define DOWNLOAD_H
int download_url(const char *name, const char *url);
#endif /* DOWNLOAD_H */

13
contrib/elf2dmp/err.h Normal file
View File

@ -0,0 +1,13 @@
/*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
*
*/
#ifndef ERR_H
#define ERR_H
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#endif /* ERR_H */

194
contrib/elf2dmp/kdbg.h Normal file
View File

@ -0,0 +1,194 @@
/*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
*
*/
#ifndef KDBG_H
#define KDBG_H
typedef struct DBGKD_GET_VERSION64 {
uint16_t MajorVersion;
uint16_t MinorVersion;
uint8_t ProtocolVersion;
uint8_t KdSecondaryVersion;
uint16_t Flags;
uint16_t MachineType;
uint8_t MaxPacketType;
uint8_t MaxStateChange;
uint8_t MaxManipulate;
uint8_t Simulation;
uint16_t Unused[1];
uint64_t KernBase;
uint64_t PsLoadedModuleList;
uint64_t DebuggerDataList;
} DBGKD_GET_VERSION64;
typedef struct DBGKD_DEBUG_DATA_HEADER64 {
struct LIST_ENTRY64 {
struct LIST_ENTRY64 *Flink;
struct LIST_ENTRY64 *Blink;
} List;
uint32_t OwnerTag;
uint32_t Size;
} DBGKD_DEBUG_DATA_HEADER64;
typedef struct KDDEBUGGER_DATA64 {
DBGKD_DEBUG_DATA_HEADER64 Header;
uint64_t KernBase;
uint64_t BreakpointWithStatus;
uint64_t SavedContext;
uint16_t ThCallbackStack;
uint16_t NextCallback;
uint16_t FramePointer;
uint16_t PaeEnabled:1;
uint64_t KiCallUserMode;
uint64_t KeUserCallbackDispatcher;
uint64_t PsLoadedModuleList;
uint64_t PsActiveProcessHead;
uint64_t PspCidTable;
uint64_t ExpSystemResourcesList;
uint64_t ExpPagedPoolDescriptor;
uint64_t ExpNumberOfPagedPools;
uint64_t KeTimeIncrement;
uint64_t KeBugCheckCallbackListHead;
uint64_t KiBugcheckData;
uint64_t IopErrorLogListHead;
uint64_t ObpRootDirectoryObject;
uint64_t ObpTypeObjectType;
uint64_t MmSystemCacheStart;
uint64_t MmSystemCacheEnd;
uint64_t MmSystemCacheWs;
uint64_t MmPfnDatabase;
uint64_t MmSystemPtesStart;
uint64_t MmSystemPtesEnd;
uint64_t MmSubsectionBase;
uint64_t MmNumberOfPagingFiles;
uint64_t MmLowestPhysicalPage;
uint64_t MmHighestPhysicalPage;
uint64_t MmNumberOfPhysicalPages;
uint64_t MmMaximumNonPagedPoolInBytes;
uint64_t MmNonPagedSystemStart;
uint64_t MmNonPagedPoolStart;
uint64_t MmNonPagedPoolEnd;
uint64_t MmPagedPoolStart;
uint64_t MmPagedPoolEnd;
uint64_t MmPagedPoolInformation;
uint64_t MmPageSize;
uint64_t MmSizeOfPagedPoolInBytes;
uint64_t MmTotalCommitLimit;
uint64_t MmTotalCommittedPages;
uint64_t MmSharedCommit;
uint64_t MmDriverCommit;
uint64_t MmProcessCommit;
uint64_t MmPagedPoolCommit;
uint64_t MmExtendedCommit;
uint64_t MmZeroedPageListHead;
uint64_t MmFreePageListHead;
uint64_t MmStandbyPageListHead;
uint64_t MmModifiedPageListHead;
uint64_t MmModifiedNoWritePageListHead;
uint64_t MmAvailablePages;
uint64_t MmResidentAvailablePages;
uint64_t PoolTrackTable;
uint64_t NonPagedPoolDescriptor;
uint64_t MmHighestUserAddress;
uint64_t MmSystemRangeStart;
uint64_t MmUserProbeAddress;
uint64_t KdPrintCircularBuffer;
uint64_t KdPrintCircularBufferEnd;
uint64_t KdPrintWritePointer;
uint64_t KdPrintRolloverCount;
uint64_t MmLoadedUserImageList;
/* NT 5.1 Addition */
uint64_t NtBuildLab;
uint64_t KiNormalSystemCall;
/* NT 5.0 hotfix addition */
uint64_t KiProcessorBlock;
uint64_t MmUnloadedDrivers;
uint64_t MmLastUnloadedDriver;
uint64_t MmTriageActionTaken;
uint64_t MmSpecialPoolTag;
uint64_t KernelVerifier;
uint64_t MmVerifierData;
uint64_t MmAllocatedNonPagedPool;
uint64_t MmPeakCommitment;
uint64_t MmTotalCommitLimitMaximum;
uint64_t CmNtCSDVersion;
/* NT 5.1 Addition */
uint64_t MmPhysicalMemoryBlock;
uint64_t MmSessionBase;
uint64_t MmSessionSize;
uint64_t MmSystemParentTablePage;
/* Server 2003 addition */
uint64_t MmVirtualTranslationBase;
uint16_t OffsetKThreadNextProcessor;
uint16_t OffsetKThreadTeb;
uint16_t OffsetKThreadKernelStack;
uint16_t OffsetKThreadInitialStack;
uint16_t OffsetKThreadApcProcess;
uint16_t OffsetKThreadState;
uint16_t OffsetKThreadBStore;
uint16_t OffsetKThreadBStoreLimit;
uint16_t SizeEProcess;
uint16_t OffsetEprocessPeb;
uint16_t OffsetEprocessParentCID;
uint16_t OffsetEprocessDirectoryTableBase;
uint16_t SizePrcb;
uint16_t OffsetPrcbDpcRoutine;
uint16_t OffsetPrcbCurrentThread;
uint16_t OffsetPrcbMhz;
uint16_t OffsetPrcbCpuType;
uint16_t OffsetPrcbVendorString;
uint16_t OffsetPrcbProcStateContext;
uint16_t OffsetPrcbNumber;
uint16_t SizeEThread;
uint64_t KdPrintCircularBufferPtr;
uint64_t KdPrintBufferSize;
uint64_t KeLoaderBlock;
uint16_t SizePcr;
uint16_t OffsetPcrSelfPcr;
uint16_t OffsetPcrCurrentPrcb;
uint16_t OffsetPcrContainedPrcb;
uint16_t OffsetPcrInitialBStore;
uint16_t OffsetPcrBStoreLimit;
uint16_t OffsetPcrInitialStack;
uint16_t OffsetPcrStackLimit;
uint16_t OffsetPrcbPcrPage;
uint16_t OffsetPrcbProcStateSpecialReg;
uint16_t GdtR0Code;
uint16_t GdtR0Data;
uint16_t GdtR0Pcr;
uint16_t GdtR3Code;
uint16_t GdtR3Data;
uint16_t GdtR3Teb;
uint16_t GdtLdt;
uint16_t GdtTss;
uint16_t Gdt64R3CmCode;
uint16_t Gdt64R3CmTeb;
uint64_t IopNumTriageDumpDataBlocks;
uint64_t IopTriageDumpDataBlocks;
/* Longhorn addition */
uint64_t VfCrashDataBlock;
uint64_t MmBadPagesDetected;
uint64_t MmZeroedPageSingleBitErrorsDetected;
/* Windows 7 addition */
uint64_t EtwpDebuggerData;
uint16_t OffsetPrcbContext;
} KDDEBUGGER_DATA64;
#endif /* KDBG_H */

589
contrib/elf2dmp/main.c Normal file
View File

@ -0,0 +1,589 @@
/*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
*
*/
#include "qemu/osdep.h"
#include "err.h"
#include "addrspace.h"
#include "pe.h"
#include "pdb.h"
#include "kdbg.h"
#include "download.h"
#include "qemu/win_dump_defs.h"
#define SYM_URL_BASE "https://msdl.microsoft.com/download/symbols/"
#define PDB_NAME "ntkrnlmp.pdb"
#define INITIAL_MXCSR 0x1f80
typedef struct idt_desc {
uint16_t offset1; /* offset bits 0..15 */
uint16_t selector;
uint8_t ist;
uint8_t type_attr;
uint16_t offset2; /* offset bits 16..31 */
uint32_t offset3; /* offset bits 32..63 */
uint32_t rsrvd;
} __attribute__ ((packed)) idt_desc_t;
static uint64_t idt_desc_addr(idt_desc_t desc)
{
return (uint64_t)desc.offset1 | ((uint64_t)desc.offset2 << 16) |
((uint64_t)desc.offset3 << 32);
}
static const uint64_t SharedUserData = 0xfffff78000000000;
#define KUSD_OFFSET_SUITE_MASK 0x2d0
#define KUSD_OFFSET_PRODUCT_TYPE 0x264
#define SYM_RESOLVE(base, r, s) ((s = pdb_resolve(base, r, #s)),\
s ? printf(#s" = 0x%016lx\n", s) : eprintf("Failed to resolve "#s"\n"), s)
static uint64_t rol(uint64_t x, uint64_t y)
{
return (x << y) | (x >> (64 - y));
}
/*
* Decoding algorithm can be found in Volatility project
*/
static void kdbg_decode(uint64_t *dst, uint64_t *src, size_t size,
uint64_t kwn, uint64_t kwa, uint64_t kdbe)
{
size_t i;
assert(size % sizeof(uint64_t) == 0);
for (i = 0; i < size / sizeof(uint64_t); i++) {
uint64_t block;
block = src[i];
block = rol(block ^ kwn, (uint8_t)kwn);
block = __builtin_bswap64(block ^ kdbe) ^ kwa;
dst[i] = block;
}
}
static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb,
struct va_space *vs, uint64_t KdDebuggerDataBlock)
{
const char OwnerTag[4] = "KDBG";
KDDEBUGGER_DATA64 *kdbg = NULL;
DBGKD_DEBUG_DATA_HEADER64 kdbg_hdr;
bool decode = false;
uint64_t kwn, kwa, KdpDataBlockEncoded;
if (va_space_rw(vs,
KdDebuggerDataBlock + offsetof(KDDEBUGGER_DATA64, Header),
&kdbg_hdr, sizeof(kdbg_hdr), 0)) {
eprintf("Failed to extract KDBG header\n");
return NULL;
}
if (memcmp(&kdbg_hdr.OwnerTag, OwnerTag, sizeof(OwnerTag))) {
uint64_t KiWaitNever, KiWaitAlways;
decode = true;
if (!SYM_RESOLVE(KernBase, pdb, KiWaitNever) ||
!SYM_RESOLVE(KernBase, pdb, KiWaitAlways) ||
!SYM_RESOLVE(KernBase, pdb, KdpDataBlockEncoded)) {
return NULL;
}
if (va_space_rw(vs, KiWaitNever, &kwn, sizeof(kwn), 0) ||
va_space_rw(vs, KiWaitAlways, &kwa, sizeof(kwa), 0)) {
return NULL;
}
printf("[KiWaitNever] = 0x%016lx\n", kwn);
printf("[KiWaitAlways] = 0x%016lx\n", kwa);
/*
* If KDBG header can be decoded, KDBG size is available
* and entire KDBG can be decoded.
*/
printf("Decoding KDBG header...\n");
kdbg_decode((uint64_t *)&kdbg_hdr, (uint64_t *)&kdbg_hdr,
sizeof(kdbg_hdr), kwn, kwa, KdpDataBlockEncoded);
printf("Owner tag is \'%.4s\'\n", (char *)&kdbg_hdr.OwnerTag);
if (memcmp(&kdbg_hdr.OwnerTag, OwnerTag, sizeof(OwnerTag))) {
eprintf("Failed to decode KDBG header\n");
return NULL;
}
}
kdbg = malloc(kdbg_hdr.Size);
if (!kdbg) {
return NULL;
}
if (va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 0)) {
eprintf("Failed to extract entire KDBG\n");
return NULL;
}
if (!decode) {
return kdbg;
}
printf("Decoding KdDebuggerDataBlock...\n");
kdbg_decode((uint64_t *)kdbg, (uint64_t *)kdbg, kdbg_hdr.Size,
kwn, kwa, KdpDataBlockEncoded);
va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 1);
return kdbg;
}
static void win_context_init_from_qemu_cpu_state(WinContext *ctx,
QEMUCPUState *s)
{
WinContext win_ctx = (WinContext){
.ContextFlags = WIN_CTX_X64 | WIN_CTX_INT | WIN_CTX_SEG | WIN_CTX_CTL,
.MxCsr = INITIAL_MXCSR,
.SegCs = s->cs.selector,
.SegSs = s->ss.selector,
.SegDs = s->ds.selector,
.SegEs = s->es.selector,
.SegFs = s->fs.selector,
.SegGs = s->gs.selector,
.EFlags = (uint32_t)s->rflags,
.Rax = s->rax,
.Rbx = s->rbx,
.Rcx = s->rcx,
.Rdx = s->rdx,
.Rsp = s->rsp,
.Rbp = s->rbp,
.Rsi = s->rsi,
.Rdi = s->rdi,
.R8 = s->r8,
.R9 = s->r9,
.R10 = s->r10,
.R11 = s->r11,
.R12 = s->r12,
.R13 = s->r13,
.R14 = s->r14,
.R15 = s->r15,
.Rip = s->rip,
.FltSave = {
.MxCsr = INITIAL_MXCSR,
},
};
*ctx = win_ctx;
}
/*
* Finds paging-structure hierarchy base,
* if previously set doesn't give access to kernel structures
*/
static int fix_dtb(struct va_space *vs, QEMU_Elf *qe)
{
/*
* Firstly, test previously set DTB.
*/
if (va_space_resolve(vs, SharedUserData)) {
return 0;
}
/*
* Secondly, find CPU which run system task.
*/
size_t i;
for (i = 0; i < qe->state_nr; i++) {
QEMUCPUState *s = qe->state[i];
if (is_system(s)) {
va_space_set_dtb(vs, s->cr[3]);
printf("DTB 0x%016lx has been found from CPU #%zu"
" as system task CR3\n", vs->dtb, i);
return !(va_space_resolve(vs, SharedUserData));
}
}
/*
* Thirdly, use KERNEL_GS_BASE from CPU #0 as PRCB address and
* CR3 as [Prcb+0x7000]
*/
if (qe->has_kernel_gs_base) {
QEMUCPUState *s = qe->state[0];
uint64_t Prcb = s->kernel_gs_base;
uint64_t *cr3 = va_space_resolve(vs, Prcb + 0x7000);
if (!cr3) {
return 1;
}
va_space_set_dtb(vs, *cr3);
printf("DirectoryTableBase = 0x%016lx has been found from CPU #0"
" as interrupt handling CR3\n", vs->dtb);
return !(va_space_resolve(vs, SharedUserData));
}
return 1;
}
static int fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
struct va_space *vs, uint64_t KdDebuggerDataBlock,
KDDEBUGGER_DATA64 *kdbg, uint64_t KdVersionBlock, int nr_cpus)
{
uint32_t *suite_mask = va_space_resolve(vs, SharedUserData +
KUSD_OFFSET_SUITE_MASK);
int32_t *product_type = va_space_resolve(vs, SharedUserData +
KUSD_OFFSET_PRODUCT_TYPE);
DBGKD_GET_VERSION64 kvb;
WinDumpHeader64 h;
size_t i;
QEMU_BUILD_BUG_ON(KUSD_OFFSET_SUITE_MASK >= PAGE_SIZE);
QEMU_BUILD_BUG_ON(KUSD_OFFSET_PRODUCT_TYPE >= PAGE_SIZE);
if (!suite_mask || !product_type) {
return 1;
}
if (va_space_rw(vs, KdVersionBlock, &kvb, sizeof(kvb), 0)) {
eprintf("Failed to extract KdVersionBlock\n");
return 1;
}
h = (WinDumpHeader64) {
.Signature = "PAGE",
.ValidDump = "DU64",
.MajorVersion = kvb.MajorVersion,
.MinorVersion = kvb.MinorVersion,
.DirectoryTableBase = vs->dtb,
.PfnDatabase = kdbg->MmPfnDatabase,
.PsLoadedModuleList = kdbg->PsLoadedModuleList,
.PsActiveProcessHead = kdbg->PsActiveProcessHead,
.MachineImageType = kvb.MachineType,
.NumberProcessors = nr_cpus,
.BugcheckCode = LIVE_SYSTEM_DUMP,
.KdDebuggerDataBlock = KdDebuggerDataBlock,
.DumpType = 1,
.Comment = "Hello from elf2dmp!",
.SuiteMask = *suite_mask,
.ProductType = *product_type,
.SecondaryDataState = kvb.KdSecondaryVersion,
.PhysicalMemoryBlock = (WinDumpPhyMemDesc64) {
.NumberOfRuns = ps->block_nr,
},
.RequiredDumpSpace = sizeof(h),
};
for (i = 0; i < ps->block_nr; i++) {
h.PhysicalMemoryBlock.NumberOfPages += ps->block[i].size / PAGE_SIZE;
h.PhysicalMemoryBlock.Run[i] = (WinDumpPhyMemRun64) {
.BasePage = ps->block[i].paddr / PAGE_SIZE,
.PageCount = ps->block[i].size / PAGE_SIZE,
};
}
h.RequiredDumpSpace += h.PhysicalMemoryBlock.NumberOfPages << PAGE_BITS;
*hdr = h;
return 0;
}
static int fill_context(KDDEBUGGER_DATA64 *kdbg,
struct va_space *vs, QEMU_Elf *qe)
{
int i;
for (i = 0; i < qe->state_nr; i++) {
uint64_t Prcb;
uint64_t Context;
WinContext ctx;
QEMUCPUState *s = qe->state[i];
if (va_space_rw(vs, kdbg->KiProcessorBlock + sizeof(Prcb) * i,
&Prcb, sizeof(Prcb), 0)) {
eprintf("Failed to read CPU #%d PRCB location\n", i);
return 1;
}
if (va_space_rw(vs, Prcb + kdbg->OffsetPrcbContext,
&Context, sizeof(Context), 0)) {
eprintf("Failed to read CPU #%d ContextFrame location\n", i);
return 1;
}
printf("Filling context for CPU #%d...\n", i);
win_context_init_from_qemu_cpu_state(&ctx, s);
if (va_space_rw(vs, Context, &ctx, sizeof(ctx), 1)) {
eprintf("Failed to fill CPU #%d context\n", i);
return 1;
}
}
return 0;
}
static int write_dump(struct pa_space *ps,
WinDumpHeader64 *hdr, const char *name)
{
FILE *dmp_file = fopen(name, "wb");
size_t i;
if (!dmp_file) {
eprintf("Failed to open output file \'%s\'\n", name);
return 1;
}
printf("Writing header to file...\n");
if (fwrite(hdr, sizeof(*hdr), 1, dmp_file) != 1) {
eprintf("Failed to write dump header\n");
fclose(dmp_file);
return 1;
}
for (i = 0; i < ps->block_nr; i++) {
struct pa_block *b = &ps->block[i];
printf("Writing block #%zu/%zu to file...\n", i, ps->block_nr);
if (fwrite(b->addr, b->size, 1, dmp_file) != 1) {
eprintf("Failed to write dump header\n");
fclose(dmp_file);
return 1;
}
}
return fclose(dmp_file);
}
static int pe_get_pdb_symstore_hash(uint64_t base, void *start_addr,
char *hash, struct va_space *vs)
{
const char e_magic[2] = "MZ";
const char Signature[4] = "PE\0\0";
const char sign_rsds[4] = "RSDS";
IMAGE_DOS_HEADER *dos_hdr = start_addr;
IMAGE_NT_HEADERS64 nt_hdrs;
IMAGE_FILE_HEADER *file_hdr = &nt_hdrs.FileHeader;
IMAGE_OPTIONAL_HEADER64 *opt_hdr = &nt_hdrs.OptionalHeader;
IMAGE_DATA_DIRECTORY *data_dir = nt_hdrs.OptionalHeader.DataDirectory;
IMAGE_DEBUG_DIRECTORY debug_dir;
OMFSignatureRSDS rsds;
char *pdb_name;
size_t pdb_name_sz;
size_t i;
QEMU_BUILD_BUG_ON(sizeof(*dos_hdr) >= PAGE_SIZE);
if (memcmp(&dos_hdr->e_magic, e_magic, sizeof(e_magic))) {
return 1;
}
if (va_space_rw(vs, base + dos_hdr->e_lfanew,
&nt_hdrs, sizeof(nt_hdrs), 0)) {
return 1;
}
if (memcmp(&nt_hdrs.Signature, Signature, sizeof(Signature)) ||
file_hdr->Machine != 0x8664 || opt_hdr->Magic != 0x020b) {
return 1;
}
printf("Debug Directory RVA = 0x%016x\n",
data_dir[IMAGE_FILE_DEBUG_DIRECTORY].VirtualAddress);
if (va_space_rw(vs,
base + data_dir[IMAGE_FILE_DEBUG_DIRECTORY].VirtualAddress,
&debug_dir, sizeof(debug_dir), 0)) {
return 1;
}
if (debug_dir.Type != IMAGE_DEBUG_TYPE_CODEVIEW) {
return 1;
}
if (va_space_rw(vs,
base + debug_dir.AddressOfRawData,
&rsds, sizeof(rsds), 0)) {
return 1;
}
printf("CodeView signature is \'%.4s\'\n", rsds.Signature);
if (memcmp(&rsds.Signature, sign_rsds, sizeof(sign_rsds))) {
return 1;
}
pdb_name_sz = debug_dir.SizeOfData - sizeof(rsds);
pdb_name = malloc(pdb_name_sz);
if (!pdb_name) {
return 1;
}
if (va_space_rw(vs, base + debug_dir.AddressOfRawData +
offsetof(OMFSignatureRSDS, name), pdb_name, pdb_name_sz, 0)) {
free(pdb_name);
return 1;
}
printf("PDB name is \'%s\', \'%s\' expected\n", pdb_name, PDB_NAME);
if (strcmp(pdb_name, PDB_NAME)) {
eprintf("Unexpected PDB name, it seems the kernel isn't found\n");
free(pdb_name);
return 1;
}
free(pdb_name);
sprintf(hash, "%.08x%.04x%.04x%.02x%.02x", rsds.guid.a, rsds.guid.b,
rsds.guid.c, rsds.guid.d[0], rsds.guid.d[1]);
hash += 20;
for (i = 0; i < 6; i++, hash += 2) {
sprintf(hash, "%.02x", rsds.guid.e[i]);
}
sprintf(hash, "%.01x", rsds.age);
return 0;
}
int main(int argc, char *argv[])
{
int err = 0;
QEMU_Elf qemu_elf;
struct pa_space ps;
struct va_space vs;
QEMUCPUState *state;
idt_desc_t first_idt_desc;
uint64_t KernBase;
void *nt_start_addr = NULL;
WinDumpHeader64 header;
char pdb_hash[34];
char pdb_url[] = SYM_URL_BASE PDB_NAME
"/0123456789ABCDEF0123456789ABCDEFx/" PDB_NAME;
struct pdb_reader pdb;
uint64_t KdDebuggerDataBlock;
KDDEBUGGER_DATA64 *kdbg;
uint64_t KdVersionBlock;
if (argc != 3) {
eprintf("usage:\n\t%s elf_file dmp_file\n", argv[0]);
return 1;
}
if (QEMU_Elf_init(&qemu_elf, argv[1])) {
eprintf("Failed to initialize QEMU ELF dump\n");
return 1;
}
if (pa_space_create(&ps, &qemu_elf)) {
eprintf("Failed to initialize physical address space\n");
err = 1;
goto out_elf;
}
state = qemu_elf.state[0];
printf("CPU #0 CR3 is 0x%016lx\n", state->cr[3]);
va_space_create(&vs, &ps, state->cr[3]);
if (fix_dtb(&vs, &qemu_elf)) {
eprintf("Failed to find paging base\n");
err = 1;
goto out_elf;
}
printf("CPU #0 IDT is at 0x%016lx\n", state->idt.base);
if (va_space_rw(&vs, state->idt.base,
&first_idt_desc, sizeof(first_idt_desc), 0)) {
eprintf("Failed to get CPU #0 IDT[0]\n");
err = 1;
goto out_ps;
}
printf("CPU #0 IDT[0] -> 0x%016lx\n", idt_desc_addr(first_idt_desc));
KernBase = idt_desc_addr(first_idt_desc) & ~(PAGE_SIZE - 1);
printf("Searching kernel downwards from 0x%16lx...\n", KernBase);
for (; KernBase >= 0xfffff78000000000; KernBase -= PAGE_SIZE) {
nt_start_addr = va_space_resolve(&vs, KernBase);
if (!nt_start_addr) {
continue;
}
if (*(uint16_t *)nt_start_addr == 0x5a4d) { /* MZ */
break;
}
}
printf("KernBase = 0x%16lx, signature is \'%.2s\'\n", KernBase,
(char *)nt_start_addr);
if (pe_get_pdb_symstore_hash(KernBase, nt_start_addr, pdb_hash, &vs)) {
eprintf("Failed to get PDB symbol store hash\n");
err = 1;
goto out_ps;
}
sprintf(pdb_url, "%s%s/%s/%s", SYM_URL_BASE, PDB_NAME, pdb_hash, PDB_NAME);
printf("PDB URL is %s\n", pdb_url);
if (download_url(PDB_NAME, pdb_url)) {
eprintf("Failed to download PDB file\n");
err = 1;
goto out_ps;
}
if (pdb_init_from_file(PDB_NAME, &pdb)) {
eprintf("Failed to initialize PDB reader\n");
err = 1;
goto out_pdb_file;
}
if (!SYM_RESOLVE(KernBase, &pdb, KdDebuggerDataBlock) ||
!SYM_RESOLVE(KernBase, &pdb, KdVersionBlock)) {
err = 1;
goto out_pdb;
}
kdbg = get_kdbg(KernBase, &pdb, &vs, KdDebuggerDataBlock);
if (!kdbg) {
err = 1;
goto out_pdb;
}
if (fill_header(&header, &ps, &vs, KdDebuggerDataBlock, kdbg,
KdVersionBlock, qemu_elf.state_nr)) {
err = 1;
goto out_pdb;
}
if (fill_context(kdbg, &vs, &qemu_elf)) {
err = 1;
goto out_pdb;
}
if (write_dump(&ps, &header, argv[2])) {
eprintf("Failed to save dump\n");
err = 1;
goto out_kdbg;
}
out_kdbg:
free(kdbg);
out_pdb:
pdb_exit(&pdb);
out_pdb_file:
unlink(PDB_NAME);
out_ps:
pa_space_destroy(&ps);
out_elf:
QEMU_Elf_exit(&qemu_elf);
return err;
}

322
contrib/elf2dmp/pdb.c Normal file
View File

@ -0,0 +1,322 @@
/*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* Based on source of Wine project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "qemu/osdep.h"
#include "pdb.h"
#include "err.h"
static uint32_t pdb_get_file_size(const struct pdb_reader *r, unsigned idx)
{
return r->ds.toc->file_size[idx];
}
static pdb_seg *get_seg_by_num(struct pdb_reader *r, size_t n)
{
size_t i = 0;
char *ptr;
for (ptr = r->segs; (ptr < r->segs + r->segs_size); ) {
i++;
ptr += 8;
if (i == n) {
break;
}
ptr += sizeof(pdb_seg);
}
return (pdb_seg *)ptr;
}
uint64_t pdb_find_public_v3_symbol(struct pdb_reader *r, const char *name)
{
size_t size = pdb_get_file_size(r, r->symbols->gsym_file);
int length;
const union codeview_symbol *sym;
const uint8_t *root = r->modimage;
size_t i;
for (i = 0; i < size; i += length) {
sym = (const void *)(root + i);
length = sym->generic.len + 2;
if (!sym->generic.id || length < 4) {
break;
}
if (sym->generic.id == S_PUB_V3 &&
!strcmp(name, sym->public_v3.name)) {
pdb_seg *segment = get_seg_by_num(r, sym->public_v3.segment);
uint32_t sect_rva = segment->dword[1];
uint64_t rva = sect_rva + sym->public_v3.offset;
printf("%s: 0x%016x(%d:\'%.8s\') + 0x%08x = 0x%09lx\n", name,
sect_rva, sym->public_v3.segment,
((char *)segment - 8), sym->public_v3.offset, rva);
return rva;
}
}
return 0;
}
uint64_t pdb_resolve(uint64_t img_base, struct pdb_reader *r, const char *name)
{
uint64_t rva = pdb_find_public_v3_symbol(r, name);
if (!rva) {
return 0;
}
return img_base + rva;
}
static void pdb_reader_ds_exit(struct pdb_reader *r)
{
free(r->ds.toc);
}
static void pdb_exit_symbols(struct pdb_reader *r)
{
free(r->modimage);
free(r->symbols);
}
static void pdb_exit_segments(struct pdb_reader *r)
{
free(r->segs);
}
static void *pdb_ds_read(const PDB_DS_HEADER *header,
const uint32_t *block_list, int size)
{
int i, nBlocks;
uint8_t *buffer;
if (!size) {
return NULL;
}
nBlocks = (size + header->block_size - 1) / header->block_size;
buffer = malloc(nBlocks * header->block_size);
if (!buffer) {
return NULL;
}
for (i = 0; i < nBlocks; i++) {
memcpy(buffer + i * header->block_size, (const char *)header +
block_list[i] * header->block_size, header->block_size);
}
return buffer;
}
static void *pdb_ds_read_file(struct pdb_reader* r, uint32_t file_number)
{
const uint32_t *block_list;
uint32_t block_size;
const uint32_t *file_size;
size_t i;
if (!r->ds.toc || file_number >= r->ds.toc->num_files) {
return NULL;
}
file_size = r->ds.toc->file_size;
r->file_used[file_number / 32] |= 1 << (file_number % 32);
if (file_size[file_number] == 0 || file_size[file_number] == 0xFFFFFFFF) {
return NULL;
}
block_list = file_size + r->ds.toc->num_files;
block_size = r->ds.header->block_size;
for (i = 0; i < file_number; i++) {
block_list += (file_size[i] + block_size - 1) / block_size;
}
return pdb_ds_read(r->ds.header, block_list, file_size[file_number]);
}
static int pdb_init_segments(struct pdb_reader *r)
{
char *segs;
unsigned stream_idx = r->sidx.segments;
segs = pdb_ds_read_file(r, stream_idx);
if (!segs) {
return 1;
}
r->segs = segs;
r->segs_size = pdb_get_file_size(r, stream_idx);
return 0;
}
static int pdb_init_symbols(struct pdb_reader *r)
{
int err = 0;
PDB_SYMBOLS *symbols;
PDB_STREAM_INDEXES *sidx = &r->sidx;
memset(sidx, -1, sizeof(*sidx));
symbols = pdb_ds_read_file(r, 3);
if (!symbols) {
return 1;
}
r->symbols = symbols;
if (symbols->stream_index_size != sizeof(PDB_STREAM_INDEXES)) {
err = 1;
goto out_symbols;
}
memcpy(sidx, (const char *)symbols + sizeof(PDB_SYMBOLS) +
symbols->module_size + symbols->offset_size +
symbols->hash_size + symbols->srcmodule_size +
symbols->pdbimport_size + symbols->unknown2_size, sizeof(*sidx));
/* Read global symbol table */
r->modimage = pdb_ds_read_file(r, symbols->gsym_file);
if (!r->modimage) {
err = 1;
goto out_symbols;
}
return 0;
out_symbols:
free(symbols);
return err;
}
static int pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
{
memset(r->file_used, 0, sizeof(r->file_used));
r->ds.header = hdr;
r->ds.toc = pdb_ds_read(hdr, (uint32_t *)((uint8_t *)hdr +
hdr->toc_page * hdr->block_size), hdr->toc_size);
if (!r->ds.toc) {
return 1;
}
return 0;
}
static int pdb_reader_init(struct pdb_reader *r, void *data)
{
int err = 0;
const char pdb7[] = "Microsoft C/C++ MSF 7.00";
if (memcmp(data, pdb7, sizeof(pdb7) - 1)) {
return 1;
}
if (pdb_reader_ds_init(r, data)) {
return 1;
}
r->ds.root = pdb_ds_read_file(r, 1);
if (!r->ds.root) {
err = 1;
goto out_ds;
}
if (pdb_init_symbols(r)) {
err = 1;
goto out_root;
}
if (pdb_init_segments(r)) {
err = 1;
goto out_sym;
}
return 0;
out_sym:
pdb_exit_symbols(r);
out_root:
free(r->ds.root);
out_ds:
pdb_reader_ds_exit(r);
return err;
}
static void pdb_reader_exit(struct pdb_reader *r)
{
pdb_exit_segments(r);
pdb_exit_symbols(r);
free(r->ds.root);
pdb_reader_ds_exit(r);
}
int pdb_init_from_file(const char *name, struct pdb_reader *reader)
{
int err = 0;
int fd;
void *map;
struct stat st;
fd = open(name, O_RDONLY, 0);
if (fd == -1) {
eprintf("Failed to open PDB file \'%s\'\n", name);
return 1;
}
reader->fd = fd;
fstat(fd, &st);
reader->file_size = st.st_size;
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED) {
eprintf("Failed to map PDB file\n");
err = 1;
goto out_fd;
}
if (pdb_reader_init(reader, map)) {
err = 1;
goto out_unmap;
}
return 0;
out_unmap:
munmap(map, st.st_size);
out_fd:
close(fd);
return err;
}
void pdb_exit(struct pdb_reader *reader)
{
munmap(reader->ds.header, reader->file_size);
close(reader->fd);
pdb_reader_exit(reader);
}

241
contrib/elf2dmp/pdb.h Normal file
View File

@ -0,0 +1,241 @@
/*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
*
*/
#ifndef PDB_H
#define PDB_H
#include <stdint.h>
#include <stdlib.h>
typedef struct GUID {
unsigned int Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
} GUID;
struct PDB_FILE {
uint32_t size;
uint32_t unknown;
};
typedef struct PDB_DS_HEADER {
char signature[32];
uint32_t block_size;
uint32_t unknown1;
uint32_t num_pages;
uint32_t toc_size;
uint32_t unknown2;
uint32_t toc_page;
} PDB_DS_HEADER;
typedef struct PDB_DS_TOC {
uint32_t num_files;
uint32_t file_size[1];
} PDB_DS_TOC;
typedef struct PDB_DS_ROOT {
uint32_t Version;
uint32_t TimeDateStamp;
uint32_t Age;
GUID guid;
uint32_t cbNames;
char names[1];
} PDB_DS_ROOT;
typedef struct PDB_TYPES_OLD {
uint32_t version;
uint16_t first_index;
uint16_t last_index;
uint32_t type_size;
uint16_t file;
uint16_t pad;
} PDB_TYPES_OLD;
typedef struct PDB_TYPES {
uint32_t version;
uint32_t type_offset;
uint32_t first_index;
uint32_t last_index;
uint32_t type_size;
uint16_t file;
uint16_t pad;
uint32_t hash_size;
uint32_t hash_base;
uint32_t hash_offset;
uint32_t hash_len;
uint32_t search_offset;
uint32_t search_len;
uint32_t unknown_offset;
uint32_t unknown_len;
} PDB_TYPES;
typedef struct PDB_SYMBOL_RANGE {
uint16_t segment;
uint16_t pad1;
uint32_t offset;
uint32_t size;
uint32_t characteristics;
uint16_t index;
uint16_t pad2;
} PDB_SYMBOL_RANGE;
typedef struct PDB_SYMBOL_RANGE_EX {
uint16_t segment;
uint16_t pad1;
uint32_t offset;
uint32_t size;
uint32_t characteristics;
uint16_t index;
uint16_t pad2;
uint32_t timestamp;
uint32_t unknown;
} PDB_SYMBOL_RANGE_EX;
typedef struct PDB_SYMBOL_FILE {
uint32_t unknown1;
PDB_SYMBOL_RANGE range;
uint16_t flag;
uint16_t file;
uint32_t symbol_size;
uint32_t lineno_size;
uint32_t unknown2;
uint32_t nSrcFiles;
uint32_t attribute;
char filename[1];
} PDB_SYMBOL_FILE;
typedef struct PDB_SYMBOL_FILE_EX {
uint32_t unknown1;
PDB_SYMBOL_RANGE_EX range;
uint16_t flag;
uint16_t file;
uint32_t symbol_size;
uint32_t lineno_size;
uint32_t unknown2;
uint32_t nSrcFiles;
uint32_t attribute;
uint32_t reserved[2];
char filename[1];
} PDB_SYMBOL_FILE_EX;
typedef struct PDB_SYMBOL_SOURCE {
uint16_t nModules;
uint16_t nSrcFiles;
uint16_t table[1];
} PDB_SYMBOL_SOURCE;
typedef struct PDB_SYMBOL_IMPORT {
uint32_t unknown1;
uint32_t unknown2;
uint32_t TimeDateStamp;
uint32_t Age;
char filename[1];
} PDB_SYMBOL_IMPORT;
typedef struct PDB_SYMBOLS_OLD {
uint16_t hash1_file;
uint16_t hash2_file;
uint16_t gsym_file;
uint16_t pad;
uint32_t module_size;
uint32_t offset_size;
uint32_t hash_size;
uint32_t srcmodule_size;
} PDB_SYMBOLS_OLD;
typedef struct PDB_SYMBOLS {
uint32_t signature;
uint32_t version;
uint32_t unknown;
uint32_t hash1_file;
uint32_t hash2_file;
uint16_t gsym_file;
uint16_t unknown1;
uint32_t module_size;
uint32_t offset_size;
uint32_t hash_size;
uint32_t srcmodule_size;
uint32_t pdbimport_size;
uint32_t resvd0;
uint32_t stream_index_size;
uint32_t unknown2_size;
uint16_t resvd3;
uint16_t machine;
uint32_t resvd4;
} PDB_SYMBOLS;
typedef struct {
uint16_t FPO;
uint16_t unk0;
uint16_t unk1;
uint16_t unk2;
uint16_t unk3;
uint16_t segments;
} PDB_STREAM_INDEXES_OLD;
typedef struct {
uint16_t FPO;
uint16_t unk0;
uint16_t unk1;
uint16_t unk2;
uint16_t unk3;
uint16_t segments;
uint16_t unk4;
uint16_t unk5;
uint16_t unk6;
uint16_t FPO_EXT;
uint16_t unk7;
} PDB_STREAM_INDEXES;
union codeview_symbol {
struct {
int16_t len;
int16_t id;
} generic;
struct {
int16_t len;
int16_t id;
uint32_t symtype;
uint32_t offset;
uint16_t segment;
char name[1];
} public_v3;
};
#define S_PUB_V3 0x110E
typedef struct pdb_seg {
uint32_t dword[8];
} __attribute__ ((packed)) pdb_seg;
#define IMAGE_FILE_MACHINE_I386 0x014c
#define IMAGE_FILE_MACHINE_AMD64 0x8664
struct pdb_reader {
int fd;
size_t file_size;
struct {
PDB_DS_HEADER *header;
PDB_DS_TOC *toc;
PDB_DS_ROOT *root;
} ds;
uint32_t file_used[1024];
PDB_SYMBOLS *symbols;
PDB_STREAM_INDEXES sidx;
uint8_t *modimage;
char *segs;
size_t segs_size;
};
int pdb_init_from_file(const char *name, struct pdb_reader *reader);
void pdb_exit(struct pdb_reader *reader);
uint64_t pdb_resolve(uint64_t img_base, struct pdb_reader *r, const char *name);
uint64_t pdb_find_public_v3_symbol(struct pdb_reader *reader, const char *name);
#endif /* PDB_H */

121
contrib/elf2dmp/pe.h Normal file
View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
*
*/
#ifndef PE_H
#define PE_H
#include <stdint.h>
typedef struct IMAGE_DOS_HEADER {
uint16_t e_magic; /* 0x00: MZ Header signature */
uint16_t e_cblp; /* 0x02: Bytes on last page of file */
uint16_t e_cp; /* 0x04: Pages in file */
uint16_t e_crlc; /* 0x06: Relocations */
uint16_t e_cparhdr; /* 0x08: Size of header in paragraphs */
uint16_t e_minalloc; /* 0x0a: Minimum extra paragraphs needed */
uint16_t e_maxalloc; /* 0x0c: Maximum extra paragraphs needed */
uint16_t e_ss; /* 0x0e: Initial (relative) SS value */
uint16_t e_sp; /* 0x10: Initial SP value */
uint16_t e_csum; /* 0x12: Checksum */
uint16_t e_ip; /* 0x14: Initial IP value */
uint16_t e_cs; /* 0x16: Initial (relative) CS value */
uint16_t e_lfarlc; /* 0x18: File address of relocation table */
uint16_t e_ovno; /* 0x1a: Overlay number */
uint16_t e_res[4]; /* 0x1c: Reserved words */
uint16_t e_oemid; /* 0x24: OEM identifier (for e_oeminfo) */
uint16_t e_oeminfo; /* 0x26: OEM information; e_oemid specific */
uint16_t e_res2[10]; /* 0x28: Reserved words */
uint32_t e_lfanew; /* 0x3c: Offset to extended header */
} __attribute__ ((packed)) IMAGE_DOS_HEADER;
typedef struct IMAGE_FILE_HEADER {
uint16_t Machine;
uint16_t NumberOfSections;
uint32_t TimeDateStamp;
uint32_t PointerToSymbolTable;
uint32_t NumberOfSymbols;
uint16_t SizeOfOptionalHeader;
uint16_t Characteristics;
} __attribute__ ((packed)) IMAGE_FILE_HEADER;
typedef struct IMAGE_DATA_DIRECTORY {
uint32_t VirtualAddress;
uint32_t Size;
} __attribute__ ((packed)) IMAGE_DATA_DIRECTORY;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
typedef struct IMAGE_OPTIONAL_HEADER64 {
uint16_t Magic; /* 0x20b */
uint8_t MajorLinkerVersion;
uint8_t MinorLinkerVersion;
uint32_t SizeOfCode;
uint32_t SizeOfInitializedData;
uint32_t SizeOfUninitializedData;
uint32_t AddressOfEntryPoint;
uint32_t BaseOfCode;
uint64_t ImageBase;
uint32_t SectionAlignment;
uint32_t FileAlignment;
uint16_t MajorOperatingSystemVersion;
uint16_t MinorOperatingSystemVersion;
uint16_t MajorImageVersion;
uint16_t MinorImageVersion;
uint16_t MajorSubsystemVersion;
uint16_t MinorSubsystemVersion;
uint32_t Win32VersionValue;
uint32_t SizeOfImage;
uint32_t SizeOfHeaders;
uint32_t CheckSum;
uint16_t Subsystem;
uint16_t DllCharacteristics;
uint64_t SizeOfStackReserve;
uint64_t SizeOfStackCommit;
uint64_t SizeOfHeapReserve;
uint64_t SizeOfHeapCommit;
uint32_t LoaderFlags;
uint32_t NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} __attribute__ ((packed)) IMAGE_OPTIONAL_HEADER64;
typedef struct IMAGE_NT_HEADERS64 {
uint32_t Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} __attribute__ ((packed)) IMAGE_NT_HEADERS64;
#define IMAGE_FILE_DEBUG_DIRECTORY 6
typedef struct IMAGE_DEBUG_DIRECTORY {
uint32_t Characteristics;
uint32_t TimeDateStamp;
uint16_t MajorVersion;
uint16_t MinorVersion;
uint32_t Type;
uint32_t SizeOfData;
uint32_t AddressOfRawData;
uint32_t PointerToRawData;
} __attribute__ ((packed)) IMAGE_DEBUG_DIRECTORY;
#define IMAGE_DEBUG_TYPE_CODEVIEW 2
typedef struct guid_t {
uint32_t a;
uint16_t b;
uint16_t c;
uint8_t d[2];
uint8_t e[6];
} __attribute__ ((packed)) guid_t;
typedef struct OMFSignatureRSDS {
char Signature[4];
guid_t guid;
uint32_t age;
char name[];
} __attribute__ ((packed)) OMFSignatureRSDS;
#endif /* PE_H */

164
contrib/elf2dmp/qemu_elf.c Normal file
View File

@ -0,0 +1,164 @@
/*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
*
*/
#include "qemu/osdep.h"
#include "err.h"
#include "qemu_elf.h"
#define QEMU_NOTE_NAME "QEMU"
#ifndef ROUND_UP
#define ROUND_UP(n, d) (((n) + (d) - 1) & -(0 ? (n) : (d)))
#endif
#ifndef DIV_ROUND_UP
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#endif
#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \
((DIV_ROUND_UP((hdr_size), 4) + \
DIV_ROUND_UP((name_size), 4) + \
DIV_ROUND_UP((desc_size), 4)) * 4)
int is_system(QEMUCPUState *s)
{
return s->gs.base >> 63;
}
static char *nhdr_get_name(Elf64_Nhdr *nhdr)
{
return (char *)nhdr + ROUND_UP(sizeof(*nhdr), 4);
}
static void *nhdr_get_desc(Elf64_Nhdr *nhdr)
{
return nhdr_get_name(nhdr) + ROUND_UP(nhdr->n_namesz, 4);
}
static Elf64_Nhdr *nhdr_get_next(Elf64_Nhdr *nhdr)
{
return (void *)((uint8_t *)nhdr + ELF_NOTE_SIZE(sizeof(*nhdr),
nhdr->n_namesz, nhdr->n_descsz));
}
Elf64_Phdr *elf64_getphdr(void *map)
{
Elf64_Ehdr *ehdr = map;
Elf64_Phdr *phdr = (void *)((uint8_t *)map + ehdr->e_phoff);
return phdr;
}
Elf64_Half elf_getphdrnum(void *map)
{
Elf64_Ehdr *ehdr = map;
return ehdr->e_phnum;
}
static int init_states(QEMU_Elf *qe)
{
Elf64_Phdr *phdr = elf64_getphdr(qe->map);
Elf64_Nhdr *start = (void *)((uint8_t *)qe->map + phdr[0].p_offset);
Elf64_Nhdr *end = (void *)((uint8_t *)start + phdr[0].p_memsz);
Elf64_Nhdr *nhdr;
size_t cpu_nr = 0;
if (phdr[0].p_type != PT_NOTE) {
eprintf("Failed to find PT_NOTE\n");
return 1;
}
qe->has_kernel_gs_base = 1;
for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
QEMUCPUState *state = nhdr_get_desc(nhdr);
if (state->size < sizeof(*state)) {
eprintf("CPU #%zu: QEMU CPU state size %u doesn't match\n",
cpu_nr, state->size);
/*
* We assume either every QEMU CPU state has KERNEL_GS_BASE or
* no one has.
*/
qe->has_kernel_gs_base = 0;
}
cpu_nr++;
}
}
printf("%zu CPU states has been found\n", cpu_nr);
qe->state = malloc(sizeof(*qe->state) * cpu_nr);
if (!qe->state) {
return 1;
}
cpu_nr = 0;
for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
qe->state[cpu_nr] = nhdr_get_desc(nhdr);
cpu_nr++;
}
}
qe->state_nr = cpu_nr;
return 0;
}
static void exit_states(QEMU_Elf *qe)
{
free(qe->state);
}
int QEMU_Elf_init(QEMU_Elf *qe, const char *filename)
{
int err = 0;
struct stat st;
qe->fd = open(filename, O_RDONLY, 0);
if (qe->fd == -1) {
eprintf("Failed to open ELF dump file \'%s\'\n", filename);
return 1;
}
fstat(qe->fd, &st);
qe->size = st.st_size;
qe->map = mmap(NULL, qe->size, PROT_READ | PROT_WRITE,
MAP_PRIVATE, qe->fd, 0);
if (qe->map == MAP_FAILED) {
eprintf("Failed to map ELF file\n");
err = 1;
goto out_fd;
}
if (init_states(qe)) {
eprintf("Failed to extract QEMU CPU states\n");
err = 1;
goto out_unmap;
}
return 0;
out_unmap:
munmap(qe->map, qe->size);
out_fd:
close(qe->fd);
return err;
}
void QEMU_Elf_exit(QEMU_Elf *qe)
{
exit_states(qe);
munmap(qe->map, qe->size);
close(qe->fd);
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
*
*/
#ifndef QEMU_ELF_H
#define QEMU_ELF_H
#include <stdint.h>
#include <elf.h>
typedef struct QEMUCPUSegment {
uint32_t selector;
uint32_t limit;
uint32_t flags;
uint32_t pad;
uint64_t base;
} QEMUCPUSegment;
typedef struct QEMUCPUState {
uint32_t version;
uint32_t size;
uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
uint64_t rip, rflags;
QEMUCPUSegment cs, ds, es, fs, gs, ss;
QEMUCPUSegment ldt, tr, gdt, idt;
uint64_t cr[5];
uint64_t kernel_gs_base;
} QEMUCPUState;
int is_system(QEMUCPUState *s);
typedef struct QEMU_Elf {
int fd;
size_t size;
void *map;
QEMUCPUState **state;
size_t state_nr;
int has_kernel_gs_base;
} QEMU_Elf;
int QEMU_Elf_init(QEMU_Elf *qe, const char *filename);
void QEMU_Elf_exit(QEMU_Elf *qe);
Elf64_Phdr *elf64_getphdr(void *map);
Elf64_Half elf_getphdrnum(void *map);
#endif /* QEMU_ELF_H */

84
cpus.c
View File

@ -245,21 +245,27 @@ static int64_t cpu_get_icount_executed(CPUState *cpu)
* account executed instructions. This is done by the TCG vCPU
* thread so the main-loop can see time has moved forward.
*/
void cpu_update_icount(CPUState *cpu)
static void cpu_update_icount_locked(CPUState *cpu)
{
int64_t executed = cpu_get_icount_executed(cpu);
cpu->icount_budget -= executed;
#ifndef CONFIG_ATOMIC64
atomic_set_i64(&timers_state.qemu_icount,
timers_state.qemu_icount + executed);
}
/*
* Update the global shared timer_state.qemu_icount to take into
* account executed instructions. This is done by the TCG vCPU
* thread so the main-loop can see time has moved forward.
*/
void cpu_update_icount(CPUState *cpu)
{
seqlock_write_lock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
#endif
atomic_set__nocheck(&timers_state.qemu_icount,
timers_state.qemu_icount + executed);
#ifndef CONFIG_ATOMIC64
cpu_update_icount_locked(cpu);
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
#endif
}
static int64_t cpu_get_icount_raw_locked(void)
@ -272,16 +278,17 @@ static int64_t cpu_get_icount_raw_locked(void)
exit(1);
}
/* Take into account what has run */
cpu_update_icount(cpu);
cpu_update_icount_locked(cpu);
}
/* The read is protected by the seqlock, so __nocheck is okay. */
return atomic_read__nocheck(&timers_state.qemu_icount);
/* The read is protected by the seqlock, but needs atomic64 to avoid UB */
return atomic_read_i64(&timers_state.qemu_icount);
}
static int64_t cpu_get_icount_locked(void)
{
int64_t icount = cpu_get_icount_raw_locked();
return atomic_read__nocheck(&timers_state.qemu_icount_bias) + cpu_icount_to_ns(icount);
return atomic_read_i64(&timers_state.qemu_icount_bias) +
cpu_icount_to_ns(icount);
}
int64_t cpu_get_icount_raw(void)
@ -454,9 +461,9 @@ static void icount_adjust(void)
timers_state.icount_time_shift + 1);
}
last_delta = delta;
atomic_set__nocheck(&timers_state.qemu_icount_bias,
cur_icount - (timers_state.qemu_icount
<< timers_state.icount_time_shift));
atomic_set_i64(&timers_state.qemu_icount_bias,
cur_icount - (timers_state.qemu_icount
<< timers_state.icount_time_shift));
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
}
@ -516,8 +523,8 @@ static void icount_warp_rt(void)
int64_t delta = clock - cur_icount;
warp_delta = MIN(warp_delta, delta);
}
atomic_set__nocheck(&timers_state.qemu_icount_bias,
timers_state.qemu_icount_bias + warp_delta);
atomic_set_i64(&timers_state.qemu_icount_bias,
timers_state.qemu_icount_bias + warp_delta);
}
timers_state.vm_clock_warp_start = -1;
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
@ -548,8 +555,8 @@ void qtest_clock_warp(int64_t dest)
seqlock_write_lock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
atomic_set__nocheck(&timers_state.qemu_icount_bias,
timers_state.qemu_icount_bias + warp);
atomic_set_i64(&timers_state.qemu_icount_bias,
timers_state.qemu_icount_bias + warp);
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
@ -576,18 +583,29 @@ void qemu_start_warp_timer(void)
return;
}
/* warp clock deterministically in record/replay mode */
if (!replay_checkpoint(CHECKPOINT_CLOCK_WARP_START)) {
return;
}
if (replay_mode != REPLAY_MODE_PLAY) {
if (!all_cpu_threads_idle()) {
return;
}
if (!all_cpu_threads_idle()) {
return;
}
if (qtest_enabled()) {
/* When testing, qtest commands advance icount. */
return;
}
if (qtest_enabled()) {
/* When testing, qtest commands advance icount. */
return;
replay_checkpoint(CHECKPOINT_CLOCK_WARP_START);
} else {
/* warp clock deterministically in record/replay mode */
if (!replay_checkpoint(CHECKPOINT_CLOCK_WARP_START)) {
/* vCPU is sleeping and warp can't be started.
It is probably a race condition: notification sent
to vCPU was processed in advance and vCPU went to sleep.
Therefore we have to wake it up for doing someting. */
if (replay_has_checkpoint()) {
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
}
return;
}
}
/* We want to use the earliest deadline from ALL vm_clocks */
@ -620,8 +638,8 @@ void qemu_start_warp_timer(void)
*/
seqlock_write_lock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
atomic_set__nocheck(&timers_state.qemu_icount_bias,
timers_state.qemu_icount_bias + deadline);
atomic_set_i64(&timers_state.qemu_icount_bias,
timers_state.qemu_icount_bias + deadline);
seqlock_write_unlock(&timers_state.vm_clock_seqlock,
&timers_state.vm_clock_lock);
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
@ -823,6 +841,7 @@ int cpu_throttle_get_percentage(void)
void cpu_ticks_init(void)
{
seqlock_init(&timers_state.vm_clock_seqlock);
qemu_spin_init(&timers_state.vm_clock_lock);
vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
throttle_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT,
cpu_throttle_timer_tick, NULL);
@ -964,6 +983,8 @@ static void start_tcg_kick_timer(void)
if (!tcg_kick_vcpu_timer && CPU_NEXT(first_cpu)) {
tcg_kick_vcpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
kick_tcg_thread, NULL);
}
if (tcg_kick_vcpu_timer && !timer_pending(tcg_kick_vcpu_timer)) {
timer_mod(tcg_kick_vcpu_timer, qemu_tcg_next_kick());
}
}
@ -971,9 +992,8 @@ static void start_tcg_kick_timer(void)
static void stop_tcg_kick_timer(void)
{
assert(!mttcg_enabled);
if (tcg_kick_vcpu_timer) {
if (tcg_kick_vcpu_timer && timer_pending(tcg_kick_vcpu_timer)) {
timer_del(tcg_kick_vcpu_timer);
tcg_kick_vcpu_timer = NULL;
}
}

View File

@ -326,8 +326,15 @@ visible as the pci-hole alias clips it to a 0.5GB range.
MMIO Operations
---------------
MMIO regions are provided with ->read() and ->write() callbacks; in addition
various constraints can be supplied to control how these callbacks are called:
MMIO regions are provided with ->read() and ->write() callbacks,
which are sufficient for most devices. Some devices change behaviour
based on the attributes used for the memory transaction, or need
to be able to respond that the access should provoke a bus error
rather than completing successfully; those devices can use the
->read_with_attrs() and ->write_with_attrs() callbacks instead.
In addition various constraints can be supplied to control how these
callbacks are called:
- .valid.min_access_size, .valid.max_access_size define the access sizes
(in bytes) which the device accepts; accesses outside this range will
@ -342,5 +349,3 @@ various constraints can be supplied to control how these callbacks are called:
- .impl.unaligned specifies that the *implementation* supports unaligned
accesses; if false, unaligned accesses will be emulated by two aligned
accesses.
- .old_mmio eases the porting of code that was formerly using
cpu_register_io_memory(). It should not be used in new code.

4
exec.c
View File

@ -1734,7 +1734,7 @@ long qemu_getrampagesize(void)
}
#endif
#ifdef __linux__
#ifdef CONFIG_POSIX
static int64_t get_file_size(int fd)
{
int64_t size = lseek(fd, 0, SEEK_END);
@ -2230,7 +2230,7 @@ static void ram_block_add(RAMBlock *new_block, Error **errp, bool shared)
}
}
#ifdef __linux__
#ifdef CONFIG_POSIX
RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
uint32_t ram_flags, int fd,
Error **errp)

View File

@ -150,7 +150,8 @@ static void clipper_init(MachineState *machine)
}
if (initrd_filename) {
long initrd_base, initrd_size;
long initrd_base;
int64_t initrd_size;
initrd_size = get_image_size(initrd_filename);
if (initrd_size < 0) {

View File

@ -506,10 +506,13 @@ static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
d - &s->chan[0], val >> 16, (val & 0xffff));
break;
case ES1370_REG_ADC_FRAMEADR:
d += 2;
goto frameadr;
case ES1370_REG_DAC1_FRAMEADR:
case ES1370_REG_DAC2_FRAMEADR:
case ES1370_REG_ADC_FRAMEADR:
d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3;
frameadr:
d->frame_addr = val;
ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val);
break;
@ -521,10 +524,13 @@ static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
lwarn ("writing to phantom frame address %#x\n", val);
break;
case ES1370_REG_ADC_FRAMECNT:
d += 2;
goto framecnt;
case ES1370_REG_DAC1_FRAMECNT:
case ES1370_REG_DAC2_FRAMECNT:
case ES1370_REG_ADC_FRAMECNT:
d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3;
framecnt:
d->frame_cnt = val;
d->leftover = 0;
ldebug ("chan %td frame count %d, buffer size %d\n",

View File

@ -345,9 +345,9 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
default:
case 0:
if (s->lcr & UART_LCR_DLAB) {
if (size == 2) {
if (size == 1) {
s->divider = (s->divider & 0xff00) | val;
} else if (size == 4) {
} else {
s->divider = val;
}
serial_update_parameters(s);

View File

@ -29,6 +29,7 @@
#include "hw/sh4/sh.h"
#include "chardev/char-fe.h"
#include "qapi/error.h"
#include "qemu/timer.h"
//#define DEBUG_SERIAL
@ -63,6 +64,8 @@ typedef struct {
int rtrg;
CharBackend chr;
QEMUTimer *fifo_timeout_timer;
uint64_t etu; /* Elementary Time Unit (ns) */
qemu_irq eri;
qemu_irq rxi;
@ -314,6 +317,16 @@ static int sh_serial_can_receive1(void *opaque)
return sh_serial_can_receive(s);
}
static void sh_serial_timeout_int(void *opaque)
{
sh_serial_state *s = opaque;
s->flags |= SH_SERIAL_FLAG_RDF;
if (s->scr & (1 << 6) && s->rxi) {
qemu_set_irq(s->rxi, 1);
}
}
static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
{
sh_serial_state *s = opaque;
@ -330,8 +343,12 @@ static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
if (s->rx_cnt >= s->rtrg) {
s->flags |= SH_SERIAL_FLAG_RDF;
if (s->scr & (1 << 6) && s->rxi) {
timer_del(s->fifo_timeout_timer);
qemu_set_irq(s->rxi, 1);
}
} else {
timer_mod(s->fifo_timeout_timer,
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
}
}
}
@ -402,6 +419,9 @@ void sh_serial_init(MemoryRegion *sysmem,
sh_serial_event, NULL, s, NULL, true);
}
s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
sh_serial_timeout_int, s);
s->etu = NANOSECONDS_PER_SECOND / 9600;
s->eri = eri_source;
s->rxi = rxi_source;
s->txi = txi_source;

View File

@ -667,9 +667,9 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f)
/* The config space (ignored on the far end in current versions) */
get_config(vdev, (uint8_t *)&config);
qemu_put_be16s(f, &config.cols);
qemu_put_be16s(f, &config.rows);
qemu_put_be32s(f, &config.max_nr_ports);
qemu_put_be16(f, config.cols);
qemu_put_be16(f, config.rows);
qemu_put_be32(f, config.max_nr_ports);
/* The ports map */
max_nr_ports = s->serial.max_virtserial_ports;

View File

@ -61,9 +61,10 @@
static int roms_loaded;
/* return the size or -1 if error */
int get_image_size(const char *filename)
int64_t get_image_size(const char *filename)
{
int fd, size;
int fd;
int64_t size;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;

View File

@ -191,7 +191,7 @@ static void machine_hppa_init(MachineState *machine)
if (initrd_filename) {
ram_addr_t initrd_base;
long initrd_size;
int64_t initrd_size;
initrd_size = get_image_size(initrd_filename);
if (initrd_size < 0) {

View File

@ -147,6 +147,15 @@ static void kvm_update_clock(KVMClockState *s)
s->clock_is_reliable = kvm_has_adjust_clock_stable();
}
static void do_kvmclock_ctrl(CPUState *cpu, run_on_cpu_data data)
{
int ret = kvm_vcpu_ioctl(cpu, KVM_KVMCLOCK_CTRL, 0);
if (ret && ret != -EINVAL) {
fprintf(stderr, "%s: %s\n", __func__, strerror(-ret));
}
}
static void kvmclock_vm_state_change(void *opaque, int running,
RunState state)
{
@ -183,13 +192,7 @@ static void kvmclock_vm_state_change(void *opaque, int running,
return;
}
CPU_FOREACH(cpu) {
ret = kvm_vcpu_ioctl(cpu, KVM_KVMCLOCK_CTRL, 0);
if (ret) {
if (ret != -EINVAL) {
fprintf(stderr, "%s: %s\n", __func__, strerror(-ret));
}
return;
}
run_on_cpu(cpu, do_kvmclock_ctrl, RUN_ON_CPU_NULL);
}
} else {

View File

@ -838,7 +838,8 @@ static void load_linux(PCMachineState *pcms,
FWCfgState *fw_cfg)
{
uint16_t protocol;
int setup_size, kernel_size, initrd_size = 0, cmdline_size;
int setup_size, kernel_size, cmdline_size;
int64_t initrd_size = 0;
int dtb_size, setup_data_offset;
uint32_t initrd_max;
uint8_t header[8192], *setup, *kernel, *initrd_data;
@ -974,6 +975,10 @@ static void load_linux(PCMachineState *pcms,
fprintf(stderr, "qemu: error reading initrd %s: %s\n",
initrd_filename, strerror(errno));
exit(1);
} else if (initrd_size >= initrd_max) {
fprintf(stderr, "qemu: initrd is too large, cannot support."
"(max: %"PRIu32", need %"PRId64")\n", initrd_max, initrd_size);
exit(1);
}
initrd_addr = (initrd_max-initrd_size) & ~4095;

View File

@ -35,6 +35,7 @@
#include "sysemu/block-backend.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "sysemu/replay.h"
#include "hw/ide/internal.h"
#include "trace.h"
@ -479,7 +480,7 @@ static void ide_issue_trim_cb(void *opaque, int ret)
done:
iocb->aiocb = NULL;
if (iocb->bh) {
qemu_bh_schedule(iocb->bh);
replay_bh_schedule_event(iocb->bh);
}
}

View File

@ -914,7 +914,12 @@ static void ps2_common_post_load(PS2State *s)
uint8_t tmp_data[PS2_QUEUE_SIZE];
/* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
size = (q->count < 0 || q->count > PS2_QUEUE_SIZE) ? 0 : q->count;
size = q->count;
if (q->count < 0) {
size = 0;
} else if (q->count > PS2_QUEUE_SIZE) {
size = PS2_QUEUE_SIZE;
}
/* move the queue elements to the start of data array */
for (i = 0; i < size; i++) {
@ -929,7 +934,6 @@ static void ps2_common_post_load(PS2State *s)
q->rptr = 0;
q->wptr = (size == PS2_QUEUE_SIZE) ? 0 : size;
q->count = size;
s->update_irq(s->update_arg, q->count != 0);
}
static void ps2_kbd_reset(void *opaque)

View File

@ -104,9 +104,9 @@ static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
static int64_t load_kernel (CPUMIPSState *env)
{
int64_t kernel_entry, kernel_low, kernel_high;
int64_t kernel_entry, kernel_low, kernel_high, initrd_size;
int index = 0;
long kernel_size, initrd_size;
long kernel_size;
ram_addr_t initrd_offset;
uint32_t *prom_buf;
long prom_size;
@ -150,7 +150,7 @@ static int64_t load_kernel (CPUMIPSState *env)
prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename);
if (initrd_size > 0) {
prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%" PRId64 " %s",
cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
loaderparams.kernel_cmdline);
} else {

View File

@ -995,8 +995,8 @@ static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
/* Kernel */
static int64_t load_kernel (void)
{
int64_t kernel_entry, kernel_high;
long kernel_size, initrd_size;
int64_t kernel_entry, kernel_high, initrd_size;
long kernel_size;
ram_addr_t initrd_offset;
int big_endian;
uint32_t *prom_buf;
@ -1070,7 +1070,7 @@ static int64_t load_kernel (void)
prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
if (initrd_size > 0) {
prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%" PRId64 " %s",
xlate_to_kseg0(NULL, initrd_offset), initrd_size,
loaderparams.kernel_cmdline);
} else {

View File

@ -58,9 +58,8 @@ typedef struct ResetData {
static int64_t load_kernel(void)
{
int64_t entry, kernel_high;
int64_t entry, kernel_high, initrd_size;
long kernel_size;
long initrd_size;
ram_addr_t initrd_offset;
int big_endian;

View File

@ -81,8 +81,8 @@ typedef struct ResetData {
static int64_t load_kernel(void)
{
const size_t params_size = 264;
int64_t entry, kernel_high;
long kernel_size, initrd_size;
int64_t entry, kernel_high, initrd_size;
long kernel_size;
ram_addr_t initrd_offset;
uint32_t *params_buf;
int big_endian;
@ -136,7 +136,7 @@ static int64_t load_kernel(void)
params_buf[1] = tswap32(0x12345678);
if (initrd_size > 0) {
snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%li %s",
snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%" PRId64 " %s",
cpu_mips_phys_to_kseg0(NULL, initrd_offset),
initrd_size, loaderparams.kernel_cmdline);
} else {

View File

@ -23,6 +23,11 @@ typedef struct ISADebugExitState {
MemoryRegion io;
} ISADebugExitState;
static uint64_t debug_exit_read(void *opaque, hwaddr addr, unsigned size)
{
return 0;
}
static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val,
unsigned width)
{
@ -30,6 +35,7 @@ static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val,
}
static const MemoryRegionOps debug_exit_ops = {
.read = debug_exit_read,
.write = debug_exit_write,
.valid.min_access_size = 1,
.valid.max_access_size = 4,

View File

@ -30,7 +30,8 @@
#include "qemu/main-loop.h" /* iothread mutex */
#include "qapi/visitor.h"
#define EDU(obj) OBJECT_CHECK(EduState, obj, "edu")
#define TYPE_PCI_EDU_DEVICE "edu"
#define EDU(obj) OBJECT_CHECK(EduState, obj, TYPE_PCI_EDU_DEVICE)
#define FACT_IRQ 0x00000001
#define DMA_IRQ 0x00000100
@ -414,7 +415,7 @@ static void pci_edu_register_types(void)
{ },
};
static const TypeInfo edu_info = {
.name = "edu",
.name = TYPE_PCI_EDU_DEVICE,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(EduState),
.instance_init = edu_instance_init,

View File

@ -105,7 +105,12 @@ static void hv_synic_test_dev_control(HypervTestDev *dev, uint32_t ctl,
}
}
static void hv_test_dev_control(void *opaque, hwaddr addr, uint64_t data,
static uint64_t hv_test_dev_read(void *opaque, hwaddr addr, unsigned size)
{
return 0;
}
static void hv_test_dev_write(void *opaque, hwaddr addr, uint64_t data,
uint32_t len)
{
HypervTestDev *dev = HYPERV_TEST_DEV(opaque);
@ -127,7 +132,8 @@ static void hv_test_dev_control(void *opaque, hwaddr addr, uint64_t data,
}
static const MemoryRegionOps synic_test_sint_ops = {
.write = hv_test_dev_control,
.read = hv_test_dev_read,
.write = hv_test_dev_write,
.valid.min_access_size = 4,
.valid.max_access_size = 4,
.endianness = DEVICE_LITTLE_ENDIAN,

View File

@ -58,7 +58,12 @@ typedef struct PCTestdev {
#define TESTDEV(obj) \
OBJECT_CHECK(PCTestdev, (obj), TYPE_TESTDEV)
static void test_irq_line(void *opaque, hwaddr addr, uint64_t data,
static uint64_t test_irq_line_read(void *opaque, hwaddr addr, unsigned size)
{
return 0;
}
static void test_irq_line_write(void *opaque, hwaddr addr, uint64_t data,
unsigned len)
{
PCTestdev *dev = opaque;
@ -68,7 +73,8 @@ static void test_irq_line(void *opaque, hwaddr addr, uint64_t data,
}
static const MemoryRegionOps test_irq_ops = {
.write = test_irq_line,
.read = test_irq_line_read,
.write = test_irq_line_write,
.valid.min_access_size = 1,
.valid.max_access_size = 1,
.endianness = DEVICE_LITTLE_ENDIAN,
@ -110,7 +116,12 @@ static const MemoryRegionOps test_ioport_byte_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void test_flush_page(void *opaque, hwaddr addr, uint64_t data,
static uint64_t test_flush_page_read(void *opaque, hwaddr addr, unsigned size)
{
return 0;
}
static void test_flush_page_write(void *opaque, hwaddr addr, uint64_t data,
unsigned len)
{
hwaddr page = 4096;
@ -126,7 +137,8 @@ static void test_flush_page(void *opaque, hwaddr addr, uint64_t data,
}
static const MemoryRegionOps test_flush_ops = {
.write = test_flush_page,
.read = test_flush_page_read,
.write = test_flush_page_write,
.valid.min_access_size = 4,
.valid.max_access_size = 4,
.endianness = DEVICE_LITTLE_ENDIAN,

View File

@ -54,8 +54,8 @@ typedef struct {
static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params)
{
uint64_t entry, kernel_low, kernel_high;
int64_t initrd_size;
long kernel_size;
long initrd_size;
ram_addr_t initrd_offset;
kernel_size = load_elf(loader_params->kernel_filename, NULL, NULL,

View File

@ -434,6 +434,11 @@ static bool fw_cfg_data_mem_valid(void *opaque, hwaddr addr,
return addr == 0;
}
static uint64_t fw_cfg_ctl_mem_read(void *opaque, hwaddr addr, unsigned size)
{
return 0;
}
static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
@ -468,6 +473,7 @@ static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
}
static const MemoryRegionOps fw_cfg_ctl_mem_ops = {
.read = fw_cfg_ctl_mem_read,
.write = fw_cfg_ctl_mem_write,
.endianness = DEVICE_BIG_ENDIAN,
.valid.accepts = fw_cfg_ctl_mem_valid,
@ -1109,12 +1115,7 @@ static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->ctl_iomem);
if (s->data_width > data_ops->valid.max_access_size) {
/* memberwise copy because the "old_mmio" member is const */
s->wide_data_ops.read = data_ops->read;
s->wide_data_ops.write = data_ops->write;
s->wide_data_ops.endianness = data_ops->endianness;
s->wide_data_ops.valid = data_ops->valid;
s->wide_data_ops.impl = data_ops->impl;
s->wide_data_ops = *data_ops;
s->wide_data_ops.valid.max_access_size = s->data_width;
s->wide_data_ops.impl.max_access_size = s->data_width;

View File

@ -20,20 +20,7 @@
#include "hw/scsi/scsi.h"
#include "sysemu/dma.h"
#include "qemu/log.h"
//#define DEBUG_LSI
//#define DEBUG_LSI_REG
#ifdef DEBUG_LSI
#define DPRINTF(fmt, ...) \
do { printf("lsi_scsi: " fmt , ## __VA_ARGS__); } while (0)
#define BADF(fmt, ...) \
do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
#else
#define DPRINTF(fmt, ...) do {} while(0)
#define BADF(fmt, ...) \
do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
#endif
#include "trace.h"
static const char *names[] = {
"SCNTL0", "SCNTL1", "SCNTL2", "SCNTL3", "SCID", "SXFER", "SDID", "GPREG",
@ -313,7 +300,7 @@ static inline int lsi_irq_on_rsl(LSIState *s)
static void lsi_soft_reset(LSIState *s)
{
DPRINTF("Reset\n");
trace_lsi_reset();
s->carry = 0;
s->msg_action = 0;
@ -484,15 +471,13 @@ static void lsi_update_irq(LSIState *s)
level = 1;
if (level != last_level) {
DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n",
level, s->dstat, s->sist1, s->sist0);
trace_lsi_update_irq(level, s->dstat, s->sist1, s->sist0);
last_level = level;
}
lsi_set_irq(s, level);
if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
DPRINTF("Handled IRQs & disconnected, looking for pending "
"processes\n");
trace_lsi_update_irq_disconnected();
QTAILQ_FOREACH(p, &s->queue, next) {
if (p->pending) {
lsi_reselect(s, p);
@ -508,8 +493,7 @@ static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
uint32_t mask0;
uint32_t mask1;
DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n",
stat1, stat0, s->sist1, s->sist0);
trace_lsi_script_scsi_interrupt(stat1, stat0, s->sist1, s->sist0);
s->sist0 |= stat0;
s->sist1 |= stat1;
/* Stop processor on fatal or unmasked interrupt. As a special hack
@ -527,7 +511,7 @@ static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
/* Stop SCRIPTS execution and raise a DMA interrupt. */
static void lsi_script_dma_interrupt(LSIState *s, int stat)
{
DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat);
trace_lsi_script_dma_interrupt(stat, s->dstat);
s->dstat |= stat;
lsi_update_irq(s);
lsi_stop_script(s);
@ -547,9 +531,9 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase)
} else {
s->dsp = (s->scntl2 & LSI_SCNTL2_WSR ? s->pmjad2 : s->pmjad1);
}
DPRINTF("Data phase mismatch jump to %08x\n", s->dsp);
trace_lsi_bad_phase_jump(s->dsp);
} else {
DPRINTF("Phase mismatch interrupt\n");
trace_lsi_bad_phase_interrupt();
lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
lsi_stop_script(s);
}
@ -576,7 +560,7 @@ static void lsi_disconnect(LSIState *s)
static void lsi_bad_selection(LSIState *s, uint32_t id)
{
DPRINTF("Selected absent target %d\n", id);
trace_lsi_bad_selection(id);
lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
lsi_disconnect(s);
}
@ -591,7 +575,7 @@ static void lsi_do_dma(LSIState *s, int out)
assert(s->current);
if (!s->current->dma_len) {
/* Wait until data is available. */
DPRINTF("DMA no data available\n");
trace_lsi_do_dma_unavailable();
return;
}
@ -611,7 +595,7 @@ static void lsi_do_dma(LSIState *s, int out)
else if (s->sbms)
addr |= ((uint64_t)s->sbms << 32);
DPRINTF("DMA addr=0x" DMA_ADDR_FMT " len=%d\n", addr, count);
trace_lsi_do_dma(addr, count);
s->csbc += count;
s->dnad += count;
s->dbc -= count;
@ -640,7 +624,7 @@ static void lsi_queue_command(LSIState *s)
{
lsi_request *p = s->current;
DPRINTF("Queueing tag=0x%x\n", p->tag);
trace_lsi_queue_command(p->tag);
assert(s->current != NULL);
assert(s->current->dma_len == 0);
QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
@ -654,9 +638,9 @@ static void lsi_queue_command(LSIState *s)
static void lsi_add_msg_byte(LSIState *s, uint8_t data)
{
if (s->msg_len >= LSI_MAX_MSGIN_LEN) {
BADF("MSG IN data too long\n");
trace_lsi_add_msg_byte_error();
} else {
DPRINTF("MSG IN 0x%02x\n", data);
trace_lsi_add_msg_byte(data);
s->msg[s->msg_len++] = data;
}
}
@ -676,7 +660,7 @@ static void lsi_reselect(LSIState *s, lsi_request *p)
if (!(s->dcntl & LSI_DCNTL_COM)) {
s->sfbr = 1 << (id & 0x7);
}
DPRINTF("Reselected target %d\n", id);
trace_lsi_reselect(id);
s->scntl1 |= LSI_SCNTL1_CON;
lsi_set_phase(s, PHASE_MI);
s->msg_action = p->out ? 2 : 3;
@ -732,7 +716,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
lsi_request *p = req->hba_private;
if (p->pending) {
BADF("Multiple IO pending for request %p\n", p);
trace_lsi_queue_req_error(p);
}
p->pending = len;
/* Reselect if waiting for it, or if reselection triggers an IRQ
@ -747,7 +731,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
lsi_reselect(s, p);
return 0;
} else {
DPRINTF("Queueing IO tag=0x%x\n", p->tag);
trace_lsi_queue_req(p->tag);
p->pending = len;
return 1;
}
@ -760,7 +744,7 @@ static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid
int out;
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
DPRINTF("Command complete status=%d\n", (int)status);
trace_lsi_command_complete(status);
s->status = status;
s->command_complete = 2;
if (s->waiting && s->dbc != 0) {
@ -795,7 +779,7 @@ static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
/* host adapter (re)connected */
DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, len);
trace_lsi_transfer_data(req->tag, len);
s->current->dma_len = len;
s->command_complete = 1;
if (s->waiting) {
@ -814,7 +798,7 @@ static void lsi_do_command(LSIState *s)
uint32_t id;
int n;
DPRINTF("Send command len=%d\n", s->dbc);
trace_lsi_do_command(s->dbc);
if (s->dbc > 16)
s->dbc = 16;
pci_dma_read(PCI_DEVICE(s), s->dnad, buf, s->dbc);
@ -862,9 +846,10 @@ static void lsi_do_command(LSIState *s)
static void lsi_do_status(LSIState *s)
{
uint8_t status;
DPRINTF("Get status len=%d status=%d\n", s->dbc, s->status);
if (s->dbc != 1)
BADF("Bad Status move\n");
trace_lsi_do_status(s->dbc, s->status);
if (s->dbc != 1) {
trace_lsi_do_status_error();
}
s->dbc = 1;
status = s->status;
s->sfbr = status;
@ -877,7 +862,7 @@ static void lsi_do_status(LSIState *s)
static void lsi_do_msgin(LSIState *s)
{
int len;
DPRINTF("Message in len=%d/%d\n", s->dbc, s->msg_len);
trace_lsi_do_msgin(s->dbc, s->msg_len);
s->sfbr = s->msg[0];
len = s->msg_len;
if (len > s->dbc)
@ -942,36 +927,36 @@ static void lsi_do_msgout(LSIState *s)
current_req = lsi_find_by_tag(s, current_tag);
}
DPRINTF("MSG out len=%d\n", s->dbc);
trace_lsi_do_msgout(s->dbc);
while (s->dbc) {
msg = lsi_get_msgbyte(s);
s->sfbr = msg;
switch (msg) {
case 0x04:
DPRINTF("MSG: Disconnect\n");
trace_lsi_do_msgout_disconnect();
lsi_disconnect(s);
break;
case 0x08:
DPRINTF("MSG: No Operation\n");
trace_lsi_do_msgout_noop();
lsi_set_phase(s, PHASE_CMD);
break;
case 0x01:
len = lsi_get_msgbyte(s);
msg = lsi_get_msgbyte(s);
(void)len; /* avoid a warning about unused variable*/
DPRINTF("Extended message 0x%x (len %d)\n", msg, len);
trace_lsi_do_msgout_extended(msg, len);
switch (msg) {
case 1:
DPRINTF("SDTR (ignored)\n");
trace_lsi_do_msgout_ignored("SDTR");
lsi_skip_msgbytes(s, 2);
break;
case 3:
DPRINTF("WDTR (ignored)\n");
trace_lsi_do_msgout_ignored("WDTR");
lsi_skip_msgbytes(s, 1);
break;
case 4:
DPRINTF("PPR (ignored)\n");
trace_lsi_do_msgout_ignored("PPR");
lsi_skip_msgbytes(s, 5);
break;
default:
@ -980,19 +965,20 @@ static void lsi_do_msgout(LSIState *s)
break;
case 0x20: /* SIMPLE queue */
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
DPRINTF("SIMPLE queue tag=0x%x\n", s->select_tag & 0xff);
trace_lsi_do_msgout_simplequeue(s->select_tag & 0xff);
break;
case 0x21: /* HEAD of queue */
BADF("HEAD queue not implemented\n");
qemu_log_mask(LOG_UNIMP, "lsi_scsi: HEAD queue not implemented\n");
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
break;
case 0x22: /* ORDERED queue */
BADF("ORDERED queue not implemented\n");
qemu_log_mask(LOG_UNIMP,
"lsi_scsi: ORDERED queue not implemented\n");
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
break;
case 0x0d:
/* The ABORT TAG message clears the current I/O process only. */
DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag);
trace_lsi_do_msgout_abort(current_tag);
if (current_req) {
scsi_req_cancel(current_req->req);
}
@ -1004,17 +990,17 @@ static void lsi_do_msgout(LSIState *s)
/* The ABORT message clears all I/O processes for the selecting
initiator on the specified logical unit of the target. */
if (msg == 0x06) {
DPRINTF("MSG: ABORT tag=0x%x\n", current_tag);
trace_lsi_do_msgout_abort(current_tag);
}
/* The CLEAR QUEUE message clears all I/O processes for all
initiators on the specified logical unit of the target. */
if (msg == 0x0e) {
DPRINTF("MSG: CLEAR QUEUE tag=0x%x\n", current_tag);
trace_lsi_do_msgout_clearqueue(current_tag);
}
/* The BUS DEVICE RESET message clears all I/O processes for all
initiators on all logical units of the target. */
if (msg == 0x0c) {
DPRINTF("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag);
trace_lsi_do_msgout_busdevicereset(current_tag);
}
/* clear the current I/O process */
@ -1042,14 +1028,14 @@ static void lsi_do_msgout(LSIState *s)
goto bad;
}
s->current_lun = msg & 7;
DPRINTF("Select LUN %d\n", s->current_lun);
trace_lsi_do_msgout_select(s->current_lun);
lsi_set_phase(s, PHASE_CMD);
break;
}
}
return;
bad:
BADF("Unimplemented message 0x%02x\n", msg);
qemu_log_mask(LOG_UNIMP, "Unimplemented message 0x%02x\n", msg);
lsi_set_phase(s, PHASE_MI);
lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */
s->msg_action = 0;
@ -1061,7 +1047,7 @@ static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
int n;
uint8_t buf[LSI_BUF_SIZE];
DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);
trace_lsi_memcpy(dest, src, count);
while (count) {
n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count;
lsi_mem_read(s, src, buf, n);
@ -1076,7 +1062,7 @@ static void lsi_wait_reselect(LSIState *s)
{
lsi_request *p;
DPRINTF("Wait Reselect\n");
trace_lsi_wait_reselect();
QTAILQ_FOREACH(p, &s->queue, next) {
if (p->pending) {
@ -1109,14 +1095,14 @@ again:
}
addr = read_dword(s, s->dsp + 4);
addr_high = 0;
DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);
trace_lsi_execute_script(s->dsp, insn, addr);
s->dsps = addr;
s->dcmd = insn >> 24;
s->dsp += 8;
switch (insn >> 30) {
case 0: /* Block move. */
if (s->sist1 & LSI_SIST1_STO) {
DPRINTF("Delayed select timeout\n");
trace_lsi_execute_script_blockmove_delayed();
lsi_stop_script(s);
break;
}
@ -1171,8 +1157,9 @@ again:
addr_high = s->dbms;
break;
default:
BADF("Illegal selector specified (0x%x > 0x15)"
" for 64-bit DMA block move", selector);
qemu_log_mask(LOG_GUEST_ERROR,
"lsi_scsi: Illegal selector specified (0x%x > 0x15) "
"for 64-bit DMA block move", selector);
break;
}
}
@ -1184,8 +1171,8 @@ again:
s->ia = s->dsp - 12;
}
if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
DPRINTF("Wrong phase got %d expected %d\n",
s->sstat1 & PHASE_MASK, (insn >> 24) & 7);
trace_lsi_execute_script_blockmove_badphase(s->sstat1 & PHASE_MASK,
(insn >> 24) & 7);
lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
break;
}
@ -1217,8 +1204,8 @@ again:
lsi_do_msgin(s);
break;
default:
BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK);
exit(1);
qemu_log_mask(LOG_UNIMP, "lsi_scsi: Unimplemented phase %d\n",
s->sstat1 & PHASE_MASK);
}
s->dfifo = s->dbc & 0xff;
s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3);
@ -1246,7 +1233,7 @@ again:
case 0: /* Select */
s->sdid = id;
if (s->scntl1 & LSI_SCNTL1_CON) {
DPRINTF("Already reselected, jumping to alternative address\n");
trace_lsi_execute_script_io_alreadyreselected();
s->dsp = s->dnad;
break;
}
@ -1256,8 +1243,8 @@ again:
lsi_bad_selection(s, id);
break;
}
DPRINTF("Selected target %d%s\n",
id, insn & (1 << 3) ? " ATN" : "");
trace_lsi_execute_script_io_selected(id,
insn & (1 << 3) ? " ATN" : "");
/* ??? Linux drivers compain when this is set. Maybe
it only applies in low-level mode (unimplemented).
lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
@ -1269,7 +1256,7 @@ again:
lsi_set_phase(s, PHASE_MO);
break;
case 1: /* Disconnect */
DPRINTF("Wait Disconnect\n");
trace_lsi_execute_script_io_disconnect();
s->scntl1 &= ~LSI_SCNTL1_CON;
break;
case 2: /* Wait Reselect */
@ -1278,7 +1265,7 @@ again:
}
break;
case 3: /* Set */
DPRINTF("Set%s%s%s%s\n",
trace_lsi_execute_script_io_set(
insn & (1 << 3) ? " ATN" : "",
insn & (1 << 6) ? " ACK" : "",
insn & (1 << 9) ? " TM" : "",
@ -1288,14 +1275,14 @@ again:
lsi_set_phase(s, PHASE_MO);
}
if (insn & (1 << 9)) {
BADF("Target mode not implemented\n");
exit(1);
qemu_log_mask(LOG_UNIMP,
"lsi_scsi: Target mode not implemented\n");
}
if (insn & (1 << 10))
s->carry = 1;
break;
case 4: /* Clear */
DPRINTF("Clear%s%s%s%s\n",
trace_lsi_execute_script_io_clear(
insn & (1 << 3) ? " ATN" : "",
insn & (1 << 6) ? " ACK" : "",
insn & (1 << 9) ? " TM" : "",
@ -1313,18 +1300,17 @@ again:
uint8_t data8;
int reg;
int operator;
#ifdef DEBUG_LSI
static const char *opcode_names[3] =
{"Write", "Read", "Read-Modify-Write"};
static const char *operator_names[8] =
{"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"};
#endif
reg = ((insn >> 16) & 0x7f) | (insn & 0x80);
data8 = (insn >> 8) & 0xff;
opcode = (insn >> 27) & 7;
operator = (insn >> 24) & 7;
DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n",
trace_lsi_execute_script_io_opcode(
opcode_names[opcode - 5], reg,
operator_names[operator], data8, s->sfbr,
(insn & (1 << 23)) ? " SFBR" : "");
@ -1404,21 +1390,21 @@ again:
int jmp;
if ((insn & 0x002e0000) == 0) {
DPRINTF("NOP\n");
trace_lsi_execute_script_tc_nop();
break;
}
if (s->sist1 & LSI_SIST1_STO) {
DPRINTF("Delayed select timeout\n");
trace_lsi_execute_script_tc_delayedselect_timeout();
lsi_stop_script(s);
break;
}
cond = jmp = (insn & (1 << 19)) != 0;
if (cond == jmp && (insn & (1 << 21))) {
DPRINTF("Compare carry %d\n", s->carry == jmp);
trace_lsi_execute_script_tc_compc(s->carry == jmp);
cond = s->carry != 0;
}
if (cond == jmp && (insn & (1 << 17))) {
DPRINTF("Compare phase %d %c= %d\n",
trace_lsi_execute_script_tc_compp(
(s->sstat1 & PHASE_MASK),
jmp ? '=' : '!',
((insn >> 24) & 7));
@ -1428,7 +1414,7 @@ again:
uint8_t mask;
mask = (~insn >> 8) & 0xff;
DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n",
trace_lsi_execute_script_tc_compd(
s->sfbr, mask, jmp ? '=' : '!', insn & mask);
cond = (s->sfbr & mask) == (insn & mask);
}
@ -1439,21 +1425,21 @@ again:
}
switch ((insn >> 27) & 7) {
case 0: /* Jump */
DPRINTF("Jump to 0x%08x\n", addr);
trace_lsi_execute_script_tc_jump(addr);
s->adder = addr;
s->dsp = addr;
break;
case 1: /* Call */
DPRINTF("Call 0x%08x\n", addr);
trace_lsi_execute_script_tc_call(addr);
s->temp = s->dsp;
s->dsp = addr;
break;
case 2: /* Return */
DPRINTF("Return to 0x%08x\n", s->temp);
trace_lsi_execute_script_tc_return(s->temp);
s->dsp = s->temp;
break;
case 3: /* Interrupt */
DPRINTF("Interrupt 0x%08x\n", s->dsps);
trace_lsi_execute_script_tc_interrupt(s->dsps);
if ((insn & (1 << 20)) != 0) {
s->istat0 |= LSI_ISTAT0_INTF;
lsi_update_irq(s);
@ -1462,12 +1448,12 @@ again:
}
break;
default:
DPRINTF("Illegal transfer control\n");
trace_lsi_execute_script_tc_illegal();
lsi_script_dma_interrupt(s, LSI_DSTAT_IID);
break;
}
} else {
DPRINTF("Control condition failed\n");
trace_lsi_execute_script_tc_cc_failed();
}
}
break;
@ -1495,13 +1481,12 @@ again:
reg = (insn >> 16) & 0xff;
if (insn & (1 << 24)) {
pci_dma_read(pci_dev, addr, data, n);
DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n,
addr, *(int *)data);
trace_lsi_execute_script_mm_load(reg, n, addr, *(int *)data);
for (i = 0; i < n; i++) {
lsi_reg_writeb(s, reg + i, data[i]);
}
} else {
DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr);
trace_lsi_execute_script_mm_store(reg, n, addr);
for (i = 0; i < n; i++) {
data[i] = lsi_reg_readb(s, reg + i);
}
@ -1515,8 +1500,10 @@ again:
assume this is the case and force an unexpected device disconnect.
This is apparently sufficient to beat the drivers into submission.
*/
if (!(s->sien0 & LSI_SIST0_UDC))
fprintf(stderr, "inf. loop with UDC masked\n");
if (!(s->sien0 & LSI_SIST0_UDC)) {
qemu_log_mask(LOG_GUEST_ERROR,
"lsi_scsi: inf. loop with UDC masked");
}
lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0);
lsi_disconnect(s);
} else if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) {
@ -1526,7 +1513,7 @@ again:
goto again;
}
}
DPRINTF("SCRIPTS execution stopped\n");
trace_lsi_execute_script_stop();
}
static uint8_t lsi_reg_readb(LSIState *s, int offset)
@ -1761,10 +1748,8 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset)
#undef CASE_GET_REG24
#undef CASE_GET_REG32
#ifdef DEBUG_LSI_REG
DPRINTF("Read reg %s %x = %02x\n",
offset < ARRAY_SIZE(names) ? names[offset] : "???", offset, ret);
#endif
trace_lsi_reg_read(offset < ARRAY_SIZE(names) ? names[offset] : "???",
offset, ret);
return ret;
}
@ -1782,21 +1767,22 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
#ifdef DEBUG_LSI_REG
DPRINTF("Write reg %s %x = %02x\n",
offset < ARRAY_SIZE(names) ? names[offset] : "???", offset, val);
#endif
trace_lsi_reg_write(offset < ARRAY_SIZE(names) ? names[offset] : "???",
offset, val);
switch (offset) {
case 0x00: /* SCNTL0 */
s->scntl0 = val;
if (val & LSI_SCNTL0_START) {
BADF("Start sequence not implemented\n");
qemu_log_mask(LOG_UNIMP,
"lsi_scsi: Start sequence not implemented\n");
}
break;
case 0x01: /* SCNTL1 */
s->scntl1 = val & ~LSI_SCNTL1_SST;
if (val & LSI_SCNTL1_IARB) {
BADF("Immediate Arbritration not implemented\n");
qemu_log_mask(LOG_UNIMP,
"lsi_scsi: Immediate Arbritration not implemented\n");
}
if (val & LSI_SCNTL1_RST) {
if (!(s->sstat0 & LSI_SSTAT0_RST)) {
@ -1823,7 +1809,8 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
break;
case 0x06: /* SDID */
if ((s->ssid & 0x80) && (val & 0xf) != (s->ssid & 0xf)) {
BADF("Destination ID does not match SSID\n");
qemu_log_mask(LOG_GUEST_ERROR,
"lsi_scsi: Destination ID does not match SSID\n");
}
s->sdid = val & 0xf;
break;
@ -1851,7 +1838,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
lsi_update_irq(s);
}
if (s->waiting == 1 && val & LSI_ISTAT0_SIGP) {
DPRINTF("Woken by SIGP\n");
trace_lsi_awoken();
s->waiting = 0;
s->dsp = s->dnad;
lsi_execute_script(s);
@ -1878,13 +1865,15 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
CASE_SET_REG32(temp, 0x1c)
case 0x21: /* CTEST4 */
if (val & 7) {
BADF("Unimplemented CTEST4-FBL 0x%x\n", val);
qemu_log_mask(LOG_UNIMP,
"lsi_scsi: Unimplemented CTEST4-FBL 0x%x\n", val);
}
s->ctest4 = val;
break;
case 0x22: /* CTEST5 */
if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) {
BADF("CTEST5 DMA increment not implemented\n");
qemu_log_mask(LOG_UNIMP,
"lsi_scsi: CTEST5 DMA increment not implemented\n");
}
s->ctest5 = val;
break;
@ -1941,7 +1930,8 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
break;
case 0x49: /* STIME1 */
if (val & 0xf) {
DPRINTF("General purpose timer not implemented\n");
qemu_log_mask(LOG_UNIMP,
"lsi_scsi: General purpose timer not implemented\n");
/* ??? Raising the interrupt immediately seems to be sufficient
to keep the FreeBSD driver happy. */
lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN);
@ -1958,13 +1948,15 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
break;
case 0x4e: /* STEST2 */
if (val & 1) {
BADF("Low level mode not implemented\n");
qemu_log_mask(LOG_UNIMP,
"lsi_scsi: Low level mode not implemented\n");
}
s->stest2 = val;
break;
case 0x4f: /* STEST3 */
if (val & 0x41) {
BADF("SCSI FIFO test mode not implemented\n");
qemu_log_mask(LOG_UNIMP,
"lsi_scsi: SCSI FIFO test mode not implemented\n");
}
s->stest3 = val;
break;

View File

@ -35,152 +35,155 @@
static void mptsas_fix_sgentry_endianness(MPISGEntry *sge)
{
le32_to_cpus(&sge->FlagsLength);
sge->FlagsLength = le32_to_cpu(sge->FlagsLength);
if (sge->FlagsLength & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
le64_to_cpus(&sge->u.Address64);
sge->u.Address64 = le64_to_cpu(sge->u.Address64);
} else {
le32_to_cpus(&sge->u.Address32);
sge->u.Address32 = le32_to_cpu(sge->u.Address32);
}
}
static void mptsas_fix_sgentry_endianness_reply(MPISGEntry *sge)
{
if (sge->FlagsLength & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
cpu_to_le64s(&sge->u.Address64);
sge->u.Address64 = cpu_to_le64(sge->u.Address64);
} else {
cpu_to_le32s(&sge->u.Address32);
sge->u.Address32 = cpu_to_le32(sge->u.Address32);
}
cpu_to_le32s(&sge->FlagsLength);
sge->FlagsLength = cpu_to_le32(sge->FlagsLength);
}
void mptsas_fix_scsi_io_endianness(MPIMsgSCSIIORequest *req)
{
le32_to_cpus(&req->MsgContext);
le32_to_cpus(&req->Control);
le32_to_cpus(&req->DataLength);
le32_to_cpus(&req->SenseBufferLowAddr);
req->MsgContext = le32_to_cpu(req->MsgContext);
req->Control = le32_to_cpu(req->Control);
req->DataLength = le32_to_cpu(req->DataLength);
req->SenseBufferLowAddr = le32_to_cpu(req->SenseBufferLowAddr);
}
void mptsas_fix_scsi_io_reply_endianness(MPIMsgSCSIIOReply *reply)
{
cpu_to_le32s(&reply->MsgContext);
cpu_to_le16s(&reply->IOCStatus);
cpu_to_le32s(&reply->IOCLogInfo);
cpu_to_le32s(&reply->TransferCount);
cpu_to_le32s(&reply->SenseCount);
cpu_to_le32s(&reply->ResponseInfo);
cpu_to_le16s(&reply->TaskTag);
reply->MsgContext = cpu_to_le32(reply->MsgContext);
reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
reply->TransferCount = cpu_to_le32(reply->TransferCount);
reply->SenseCount = cpu_to_le32(reply->SenseCount);
reply->ResponseInfo = cpu_to_le32(reply->ResponseInfo);
reply->TaskTag = cpu_to_le16(reply->TaskTag);
}
void mptsas_fix_scsi_task_mgmt_endianness(MPIMsgSCSITaskMgmt *req)
{
le32_to_cpus(&req->MsgContext);
le32_to_cpus(&req->TaskMsgContext);
req->MsgContext = le32_to_cpu(req->MsgContext);
req->TaskMsgContext = le32_to_cpu(req->TaskMsgContext);
}
void mptsas_fix_scsi_task_mgmt_reply_endianness(MPIMsgSCSITaskMgmtReply *reply)
{
cpu_to_le32s(&reply->MsgContext);
cpu_to_le16s(&reply->IOCStatus);
cpu_to_le32s(&reply->IOCLogInfo);
cpu_to_le32s(&reply->TerminationCount);
reply->MsgContext = cpu_to_le32(reply->MsgContext);
reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
reply->TerminationCount = cpu_to_le32(reply->TerminationCount);
}
void mptsas_fix_ioc_init_endianness(MPIMsgIOCInit *req)
{
le32_to_cpus(&req->MsgContext);
le16_to_cpus(&req->ReplyFrameSize);
le32_to_cpus(&req->HostMfaHighAddr);
le32_to_cpus(&req->SenseBufferHighAddr);
le32_to_cpus(&req->ReplyFifoHostSignalingAddr);
req->MsgContext = le32_to_cpu(req->MsgContext);
req->ReplyFrameSize = le16_to_cpu(req->ReplyFrameSize);
req->HostMfaHighAddr = le32_to_cpu(req->HostMfaHighAddr);
req->SenseBufferHighAddr = le32_to_cpu(req->SenseBufferHighAddr);
req->ReplyFifoHostSignalingAddr =
le32_to_cpu(req->ReplyFifoHostSignalingAddr);
mptsas_fix_sgentry_endianness(&req->HostPageBufferSGE);
le16_to_cpus(&req->MsgVersion);
le16_to_cpus(&req->HeaderVersion);
req->MsgVersion = le16_to_cpu(req->MsgVersion);
req->HeaderVersion = le16_to_cpu(req->HeaderVersion);
}
void mptsas_fix_ioc_init_reply_endianness(MPIMsgIOCInitReply *reply)
{
cpu_to_le32s(&reply->MsgContext);
cpu_to_le16s(&reply->IOCStatus);
cpu_to_le32s(&reply->IOCLogInfo);
reply->MsgContext = cpu_to_le32(reply->MsgContext);
reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
}
void mptsas_fix_ioc_facts_endianness(MPIMsgIOCFacts *req)
{
le32_to_cpus(&req->MsgContext);
req->MsgContext = le32_to_cpu(req->MsgContext);
}
void mptsas_fix_ioc_facts_reply_endianness(MPIMsgIOCFactsReply *reply)
{
cpu_to_le16s(&reply->MsgVersion);
cpu_to_le16s(&reply->HeaderVersion);
cpu_to_le32s(&reply->MsgContext);
cpu_to_le16s(&reply->IOCExceptions);
cpu_to_le16s(&reply->IOCStatus);
cpu_to_le32s(&reply->IOCLogInfo);
cpu_to_le16s(&reply->ReplyQueueDepth);
cpu_to_le16s(&reply->RequestFrameSize);
cpu_to_le16s(&reply->ProductID);
cpu_to_le32s(&reply->CurrentHostMfaHighAddr);
cpu_to_le16s(&reply->GlobalCredits);
cpu_to_le32s(&reply->CurrentSenseBufferHighAddr);
cpu_to_le16s(&reply->CurReplyFrameSize);
cpu_to_le32s(&reply->FWImageSize);
cpu_to_le32s(&reply->IOCCapabilities);
cpu_to_le16s(&reply->HighPriorityQueueDepth);
reply->MsgVersion = cpu_to_le16(reply->MsgVersion);
reply->HeaderVersion = cpu_to_le16(reply->HeaderVersion);
reply->MsgContext = cpu_to_le32(reply->MsgContext);
reply->IOCExceptions = cpu_to_le16(reply->IOCExceptions);
reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
reply->ReplyQueueDepth = cpu_to_le16(reply->ReplyQueueDepth);
reply->RequestFrameSize = cpu_to_le16(reply->RequestFrameSize);
reply->ProductID = cpu_to_le16(reply->ProductID);
reply->CurrentHostMfaHighAddr = cpu_to_le32(reply->CurrentHostMfaHighAddr);
reply->GlobalCredits = cpu_to_le16(reply->GlobalCredits);
reply->CurrentSenseBufferHighAddr =
cpu_to_le32(reply->CurrentSenseBufferHighAddr);
reply->CurReplyFrameSize = cpu_to_le16(reply->CurReplyFrameSize);
reply->FWImageSize = cpu_to_le32(reply->FWImageSize);
reply->IOCCapabilities = cpu_to_le32(reply->IOCCapabilities);
reply->HighPriorityQueueDepth = cpu_to_le16(reply->HighPriorityQueueDepth);
mptsas_fix_sgentry_endianness_reply(&reply->HostPageBufferSGE);
cpu_to_le32s(&reply->ReplyFifoHostSignalingAddr);
reply->ReplyFifoHostSignalingAddr =
cpu_to_le32(reply->ReplyFifoHostSignalingAddr);
}
void mptsas_fix_config_endianness(MPIMsgConfig *req)
{
le16_to_cpus(&req->ExtPageLength);
le32_to_cpus(&req->MsgContext);
le32_to_cpus(&req->PageAddress);
req->ExtPageLength = le16_to_cpu(req->ExtPageLength);
req->MsgContext = le32_to_cpu(req->MsgContext);
req->PageAddress = le32_to_cpu(req->PageAddress);
mptsas_fix_sgentry_endianness(&req->PageBufferSGE);
}
void mptsas_fix_config_reply_endianness(MPIMsgConfigReply *reply)
{
cpu_to_le16s(&reply->ExtPageLength);
cpu_to_le32s(&reply->MsgContext);
cpu_to_le16s(&reply->IOCStatus);
cpu_to_le32s(&reply->IOCLogInfo);
reply->ExtPageLength = cpu_to_le16(reply->ExtPageLength);
reply->MsgContext = cpu_to_le32(reply->MsgContext);
reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
}
void mptsas_fix_port_facts_endianness(MPIMsgPortFacts *req)
{
le32_to_cpus(&req->MsgContext);
req->MsgContext = le32_to_cpu(req->MsgContext);
}
void mptsas_fix_port_facts_reply_endianness(MPIMsgPortFactsReply *reply)
{
cpu_to_le32s(&reply->MsgContext);
cpu_to_le16s(&reply->IOCStatus);
cpu_to_le32s(&reply->IOCLogInfo);
cpu_to_le16s(&reply->MaxDevices);
cpu_to_le16s(&reply->PortSCSIID);
cpu_to_le16s(&reply->ProtocolFlags);
cpu_to_le16s(&reply->MaxPostedCmdBuffers);
cpu_to_le16s(&reply->MaxPersistentIDs);
cpu_to_le16s(&reply->MaxLanBuckets);
reply->MsgContext = cpu_to_le32(reply->MsgContext);
reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
reply->MaxDevices = cpu_to_le16(reply->MaxDevices);
reply->PortSCSIID = cpu_to_le16(reply->PortSCSIID);
reply->ProtocolFlags = cpu_to_le16(reply->ProtocolFlags);
reply->MaxPostedCmdBuffers = cpu_to_le16(reply->MaxPostedCmdBuffers);
reply->MaxPersistentIDs = cpu_to_le16(reply->MaxPersistentIDs);
reply->MaxLanBuckets = cpu_to_le16(reply->MaxLanBuckets);
}
void mptsas_fix_port_enable_endianness(MPIMsgPortEnable *req)
{
le32_to_cpus(&req->MsgContext);
req->MsgContext = le32_to_cpu(req->MsgContext);
}
void mptsas_fix_port_enable_reply_endianness(MPIMsgPortEnableReply *reply)
{
cpu_to_le32s(&reply->MsgContext);
cpu_to_le16s(&reply->IOCStatus);
cpu_to_le32s(&reply->IOCLogInfo);
reply->MsgContext = cpu_to_le32(reply->MsgContext);
reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
}
void mptsas_fix_event_notification_endianness(MPIMsgEventNotify *req)
{
le32_to_cpus(&req->MsgContext);
req->MsgContext = le32_to_cpu(req->MsgContext);
}
void mptsas_fix_event_notification_reply_endianness(MPIMsgEventNotifyReply *reply)
@ -188,16 +191,16 @@ void mptsas_fix_event_notification_reply_endianness(MPIMsgEventNotifyReply *repl
int length = reply->EventDataLength;
int i;
cpu_to_le16s(&reply->EventDataLength);
cpu_to_le32s(&reply->MsgContext);
cpu_to_le16s(&reply->IOCStatus);
cpu_to_le32s(&reply->IOCLogInfo);
cpu_to_le32s(&reply->Event);
cpu_to_le32s(&reply->EventContext);
reply->EventDataLength = cpu_to_le16(reply->EventDataLength);
reply->MsgContext = cpu_to_le32(reply->MsgContext);
reply->IOCStatus = cpu_to_le16(reply->IOCStatus);
reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo);
reply->Event = cpu_to_le32(reply->Event);
reply->EventContext = cpu_to_le32(reply->EventContext);
/* Really depends on the event kind. This will do for now. */
for (i = 0; i < length; i++) {
cpu_to_le32s(&reply->Data[i]);
reply->Data[i] = cpu_to_le32(reply->Data[i]);
}
}

View File

@ -2610,6 +2610,12 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp)
return;
}
if (s->rotation_rate) {
error_report_once("rotation_rate is specified for scsi-block but is "
"not implemented. This option is deprecated and will "
"be removed in a future version");
}
/* check we are using a driver managing SG_IO (version 3 and after) */
rc = blk_ioctl(s->qdev.conf.blk, SG_GET_VERSION_NUM, &sg_version);
if (rc < 0) {

View File

@ -229,3 +229,65 @@ spapr_vscsi_process_login(void) "Got login, sending response !"
spapr_vscsi_queue_cmd_no_drive(uint64_t lun) "Command for lun 0x%08" PRIx64 " with no drive"
spapr_vscsi_queue_cmd(uint32_t qtag, unsigned cdb, const char *cmd, int lun, int ret) "Queued command tag 0x%"PRIx32" CMD 0x%x=%s LUN %d ret: %d"
spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..."
# hw/scsi/lsi53c895a.c
lsi_reset(void) "Reset"
lsi_update_irq(int level, uint8_t dstat, uint8_t sist1, uint8_t sist0) "Update IRQ level %d dstat 0x%02x sist 0x%02x0x%02x"
lsi_update_irq_disconnected(void) "Handled IRQs & disconnected, looking for pending processes"
lsi_script_scsi_interrupt(uint8_t stat1, uint8_t stat0, uint8_t sist1, uint8_t sist0) "SCSI Interrupt 0x%02x0x%02x prev 0x%02x0x%02x"
lsi_script_dma_interrupt(uint8_t stat, uint8_t dstat) "DMA Interrupt 0x%x prev 0x%x"
lsi_bad_phase_jump(uint32_t dsp) "Data phase mismatch jump to 0x%"PRIX32
lsi_bad_phase_interrupt(void) "Phase mismatch interrupt"
lsi_bad_selection(uint32_t id) "Selected absent target %"PRIu32
lsi_do_dma_unavailable(void) "DMA no data available"
lsi_do_dma(uint64_t addr, int len) "DMA addr=0x%"PRIx64" len=%d"
lsi_queue_command(uint32_t tag) "Queueing tag=0x%"PRId32
lsi_add_msg_byte_error(void) "MSG IN data too long"
lsi_add_msg_byte(uint8_t data) "MSG IN 0x%02x"
lsi_reselect(int id) "Reselected target %d"
lsi_queue_req_error(void *p) "Multiple IO pending for request %p"
lsi_queue_req(uint32_t tag) "Queueing IO tag=0x%"PRIx32
lsi_command_complete(uint32_t status) "Command complete status=%"PRId32
lsi_transfer_data(uint32_t tag, uint32_t len) "Data ready tag=0x%"PRIx32" len=%"PRId32
lsi_do_command(uint32_t dbc) "Send command len=%"PRId32
lsi_do_status(uint32_t dbc, uint8_t status) "Get status len=%"PRId32" status=%d"
lsi_do_status_error(void) "Bad Status move"
lsi_do_msgin(uint32_t dbc, int len) "Message in len=%"PRId32" %d"
lsi_do_msgout(uint32_t dbc) "MSG out len=%"PRId32
lsi_do_msgout_disconnect(void) "MSG: Disconnect"
lsi_do_msgout_noop(void) "MSG: No Operation"
lsi_do_msgout_extended(uint8_t msg, uint8_t len) "Extended message 0x%x (len %d)"
lsi_do_msgout_ignored(const char *msg) "%s (ignored)"
lsi_do_msgout_simplequeue(uint8_t select_tag) "SIMPLE queue tag=0x%x"
lsi_do_msgout_abort(uint32_t tag) "MSG: ABORT TAG tag=0x%"PRId32
lsi_do_msgout_clearqueue(uint32_t tag) "MSG: CLEAR QUEUE tag=0x%"PRIx32
lsi_do_msgout_busdevicereset(uint32_t tag) "MSG: BUS DEVICE RESET tag=0x%"PRIx32
lsi_do_msgout_select(int id) "Select LUN %d"
lsi_memcpy(uint32_t dest, uint32_t src, int count) "memcpy dest 0x%"PRIx32" src 0x%"PRIx32" count %d"
lsi_wait_reselect(void) "Wait Reselect"
lsi_execute_script(uint32_t dsp, uint32_t insn, uint32_t addr) "SCRIPTS dsp=0x%"PRIx32" opcode 0x%"PRIx32" arg 0x%"PRIx32
lsi_execute_script_blockmove_delayed(void) "Delayed select timeout"
lsi_execute_script_blockmove_badphase(uint8_t phase, uint8_t expected) "Wrong phase got %d expected %d"
lsi_execute_script_io_alreadyreselected(void) "Already reselected, jumping to alternative address"
lsi_execute_script_io_selected(uint8_t id, const char *atn) "Selected target %d%s"
lsi_execute_script_io_disconnect(void) "Wait Disconnect"
lsi_execute_script_io_set(const char *atn, const char *ack, const char *tm, const char *cc) "Set%s%s%s%s"
lsi_execute_script_io_clear(const char *atn, const char *ack, const char *tm, const char *cc) "Clear%s%s%s%s"
lsi_execute_script_io_opcode(const char *opcode, int reg, const char *opname, uint8_t data8, uint32_t sfbr, const char *ssfbr) "%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s"
lsi_execute_script_tc_nop(void) "NOP"
lsi_execute_script_tc_delayedselect_timeout(void) "Delayed select timeout"
lsi_execute_script_tc_compc(int result) "Compare carry %d"
lsi_execute_script_tc_compp(uint8_t phase, int op, uint8_t insn_phase) "Compare phase %d %c= %d"
lsi_execute_script_tc_compd(uint32_t sfbr, uint8_t mask, int op, int result) "Compare data 0x%"PRIx32" & 0x%x %c= 0x%x"
lsi_execute_script_tc_jump(uint32_t addr) "Jump to 0x%"PRIx32
lsi_execute_script_tc_call(uint32_t addr) "Call 0x%"PRIx32
lsi_execute_script_tc_return(uint32_t addr) "Return to 0x%"PRIx32
lsi_execute_script_tc_interrupt(uint32_t addr) "Interrupt 0x%"PRIx32
lsi_execute_script_tc_illegal(void) "Illegal transfer control"
lsi_execute_script_tc_cc_failed(void) "Control condition failed"
lsi_execute_script_mm_load(int reg, int n, uint32_t addr, int data) "Load reg 0x%x size %d addr 0x%"PRIx32" = 0x%08x"
lsi_execute_script_mm_store(int reg, int n, uint32_t addr) "Store reg 0x%x size %d addr 0x%"PRIx32
lsi_execute_script_stop(void) "SCRIPTS execution stopped"
lsi_awoken(void) "Woken by SIGP"
lsi_reg_read(const char *name, int offset, uint8_t ret) "Read reg %s 0x%x = 0x%02x"
lsi_reg_write(const char *name, int offset, uint8_t val) "Write reg %s 0x%x = 0x%02x"

View File

@ -358,6 +358,10 @@ int virtio_queue_ready(VirtQueue *vq)
* Called within rcu_read_lock(). */
static int virtio_queue_empty_rcu(VirtQueue *vq)
{
if (unlikely(vq->vdev->broken)) {
return 1;
}
if (unlikely(!vq->vring.avail)) {
return 1;
}
@ -373,6 +377,10 @@ int virtio_queue_empty(VirtQueue *vq)
{
bool empty;
if (unlikely(vq->vdev->broken)) {
return 1;
}
if (unlikely(!vq->vring.avail)) {
return 1;
}

View File

@ -201,11 +201,6 @@ struct MemoryRegionOps {
*/
bool unaligned;
} impl;
/* If .read and .write are not present, old_mmio may be used for
* backwards compatibility with old mmio registration
*/
const MemoryRegionMmio old_mmio;
};
enum IOMMUMemoryRegionAttr {
@ -633,7 +628,7 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr,
uint64_t length,
void *host),
Error **errp);
#ifdef __linux__
#ifdef CONFIG_POSIX
/**
* memory_region_init_ram_from_file: Initialize RAM memory region with a

View File

@ -10,7 +10,7 @@
* Returns the size of the image file on success, -1 otherwise.
* On error, errno is also set as appropriate.
*/
int get_image_size(const char *filename);
int64_t get_image_size(const char *filename);
int load_image(const char *filename, uint8_t *addr); /* deprecated */
ssize_t load_image_size(const char *filename, void *addr, size_t size);

View File

@ -98,7 +98,7 @@
* We'd prefer not want to pull in everything else TCG related, so handle
* those few cases by hand.
*
* Note that x32 is fully detected with __x64_64__ + _ILP32, and that for
* Note that x32 is fully detected with __x86_64__ + _ILP32, and that for
* Sparc we always force the use of sparcv9 in configure.
*/
#if defined(__x86_64__) || defined(__sparc__)
@ -450,4 +450,38 @@
_oldn; \
})
/* Abstractions to access atomically (i.e. "once") i64/u64 variables */
#ifdef CONFIG_ATOMIC64
static inline int64_t atomic_read_i64(const int64_t *ptr)
{
/* use __nocheck because sizeof(void *) might be < sizeof(u64) */
return atomic_read__nocheck(ptr);
}
static inline uint64_t atomic_read_u64(const uint64_t *ptr)
{
return atomic_read__nocheck(ptr);
}
static inline void atomic_set_i64(int64_t *ptr, int64_t val)
{
atomic_set__nocheck(ptr, val);
}
static inline void atomic_set_u64(uint64_t *ptr, uint64_t val)
{
atomic_set__nocheck(ptr, val);
}
static inline void atomic64_init(void)
{
}
#else /* !CONFIG_ATOMIC64 */
int64_t atomic_read_i64(const int64_t *ptr);
uint64_t atomic_read_u64(const uint64_t *ptr);
void atomic_set_i64(int64_t *ptr, int64_t val);
void atomic_set_u64(uint64_t *ptr, uint64_t val);
void atomic64_init(void);
#endif /* !CONFIG_ATOMIC64 */
#endif /* QEMU_ATOMIC_H */

View File

@ -16,12 +16,28 @@
#define F_SEAL_WRITE 0x0008 /* prevent writes */
#endif
#ifndef MFD_CLOEXEC
#define MFD_CLOEXEC 0x0001U
#endif
#ifndef MFD_ALLOW_SEALING
#define MFD_ALLOW_SEALING 0x0002U
#endif
#ifndef MFD_HUGETLB
#define MFD_HUGETLB 0x0004U
#endif
#ifndef MFD_HUGE_SHIFT
#define MFD_HUGE_SHIFT 26
#endif
int qemu_memfd_create(const char *name, size_t size, bool hugetlb,
uint64_t hugetlbsize, unsigned int seals, Error **errp);
bool qemu_memfd_alloc_check(void);
void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals,
int *fd, Error **errp);
void qemu_memfd_free(void *ptr, size_t size, int fd);
bool qemu_memfd_check(void);
bool qemu_memfd_check(unsigned int flags);
#endif /* QEMU_MEMFD_H */

View File

@ -448,7 +448,8 @@ bool qemu_has_ofd_lock(void);
#define FMT_pid "%d"
#endif
int qemu_create_pidfile(const char *filename);
bool qemu_write_pidfile(const char *pidfile, Error **errp);
int qemu_get_thread_id(void);
#ifndef CONFIG_IOVEC
@ -570,6 +571,8 @@ extern uintptr_t qemu_real_host_page_size;
extern intptr_t qemu_real_host_page_mask;
extern int qemu_icache_linesize;
extern int qemu_icache_linesize_log;
extern int qemu_dcache_linesize;
extern int qemu_dcache_linesize_log;
#endif

View File

@ -48,6 +48,22 @@ extern QemuCondWaitFunc qemu_cond_wait_func;
#define qemu_mutex_trylock__raw(m) \
qemu_mutex_trylock_impl(m, __FILE__, __LINE__)
#ifdef __COVERITY__
/*
* Coverity is severely confused by the indirect function calls,
* hide them.
*/
#define qemu_mutex_lock(m) \
qemu_mutex_lock_impl(m, __FILE__, __LINE__);
#define qemu_mutex_trylock(m) \
qemu_mutex_trylock_impl(m, __FILE__, __LINE__);
#define qemu_rec_mutex_lock(m) \
qemu_rec_mutex_lock_impl(m, __FILE__, __LINE__);
#define qemu_rec_mutex_trylock(m) \
qemu_rec_mutex_trylock_impl(m, __FILE__, __LINE__);
#define qemu_cond_wait(c, m) \
qemu_cond_wait_impl(c, m, __FILE__, __LINE__);
#else
#define qemu_mutex_lock(m) ({ \
QemuMutexLockFunc _f = atomic_read(&qemu_mutex_lock_func); \
_f(m, __FILE__, __LINE__); \
@ -73,6 +89,7 @@ extern QemuCondWaitFunc qemu_cond_wait_func;
QemuCondWaitFunc _f = atomic_read(&qemu_cond_wait_func); \
_f(c, m, __FILE__, __LINE__); \
})
#endif
#define qemu_mutex_unlock(mutex) \
qemu_mutex_unlock_impl(mutex, __FILE__, __LINE__)

View File

@ -42,6 +42,14 @@
* In icount mode, this clock counts nanoseconds while the virtual
* machine is running. It is used to increase @QEMU_CLOCK_VIRTUAL
* while the CPUs are sleeping and thus not executing instructions.
*
* @QEMU_CLOCK_VIRTUAL_EXT: virtual clock for external subsystems
*
* The virtual clock only runs during the emulation. It stops
* when the virtual machine is stopped. The timers for this clock
* do not recorded in rr mode, therefore this clock could be used
* for the subsystems that operate outside the guest core.
*
*/
typedef enum {
@ -49,6 +57,7 @@ typedef enum {
QEMU_CLOCK_VIRTUAL = 1,
QEMU_CLOCK_HOST = 2,
QEMU_CLOCK_VIRTUAL_RT = 3,
QEMU_CLOCK_VIRTUAL_EXT = 4,
QEMU_CLOCK_MAX
} QEMUClockType;

View File

@ -0,0 +1,179 @@
/*
* Windows crashdump definitions
*
* Copyright (c) 2018 Virtuozzo International GmbH
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#ifndef QEMU_WIN_DUMP_DEFS_H
#define QEMU_WIN_DUMP_DEFS_H
typedef struct WinDumpPhyMemRun64 {
uint64_t BasePage;
uint64_t PageCount;
} QEMU_PACKED WinDumpPhyMemRun64;
typedef struct WinDumpPhyMemDesc64 {
uint32_t NumberOfRuns;
uint32_t unused;
uint64_t NumberOfPages;
WinDumpPhyMemRun64 Run[43];
} QEMU_PACKED WinDumpPhyMemDesc64;
typedef struct WinDumpExceptionRecord {
uint32_t ExceptionCode;
uint32_t ExceptionFlags;
uint64_t ExceptionRecord;
uint64_t ExceptionAddress;
uint32_t NumberParameters;
uint32_t unused;
uint64_t ExceptionInformation[15];
} QEMU_PACKED WinDumpExceptionRecord;
typedef struct WinDumpHeader64 {
char Signature[4];
char ValidDump[4];
uint32_t MajorVersion;
uint32_t MinorVersion;
uint64_t DirectoryTableBase;
uint64_t PfnDatabase;
uint64_t PsLoadedModuleList;
uint64_t PsActiveProcessHead;
uint32_t MachineImageType;
uint32_t NumberProcessors;
union {
struct {
uint32_t BugcheckCode;
uint32_t unused0;
uint64_t BugcheckParameter1;
uint64_t BugcheckParameter2;
uint64_t BugcheckParameter3;
uint64_t BugcheckParameter4;
};
uint8_t BugcheckData[40];
};
uint8_t VersionUser[32];
uint64_t KdDebuggerDataBlock;
union {
WinDumpPhyMemDesc64 PhysicalMemoryBlock;
uint8_t PhysicalMemoryBlockBuffer[704];
};
union {
uint8_t ContextBuffer[3000];
};
WinDumpExceptionRecord Exception;
uint32_t DumpType;
uint32_t unused1;
uint64_t RequiredDumpSpace;
uint64_t SystemTime;
char Comment[128];
uint64_t SystemUpTime;
uint32_t MiniDumpFields;
uint32_t SecondaryDataState;
uint32_t ProductType;
uint32_t SuiteMask;
uint32_t WriterStatus;
uint8_t unused2;
uint8_t KdSecondaryVersion;
uint8_t reserved[4018];
} QEMU_PACKED WinDumpHeader64;
#define KDBG_OWNER_TAG_OFFSET64 0x10
#define KDBG_MM_PFN_DATABASE_OFFSET64 0xC0
#define KDBG_KI_BUGCHECK_DATA_OFFSET64 0x88
#define KDBG_KI_PROCESSOR_BLOCK_OFFSET64 0x218
#define KDBG_OFFSET_PRCB_CONTEXT_OFFSET64 0x338
#define VMCOREINFO_ELF_NOTE_HDR_SIZE 24
#define WIN_CTX_X64 0x00100000L
#define WIN_CTX_CTL 0x00000001L
#define WIN_CTX_INT 0x00000002L
#define WIN_CTX_SEG 0x00000004L
#define WIN_CTX_FP 0x00000008L
#define WIN_CTX_DBG 0x00000010L
#define WIN_CTX_FULL (WIN_CTX_X64 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_FP)
#define WIN_CTX_ALL (WIN_CTX_FULL | WIN_CTX_SEG | WIN_CTX_DBG)
#define LIVE_SYSTEM_DUMP 0x00000161
typedef struct WinM128A {
uint64_t low;
int64_t high;
} QEMU_ALIGNED(16) WinM128A;
typedef struct WinContext {
uint64_t PHome[6];
uint32_t ContextFlags;
uint32_t MxCsr;
uint16_t SegCs;
uint16_t SegDs;
uint16_t SegEs;
uint16_t SegFs;
uint16_t SegGs;
uint16_t SegSs;
uint32_t EFlags;
uint64_t Dr0;
uint64_t Dr1;
uint64_t Dr2;
uint64_t Dr3;
uint64_t Dr6;
uint64_t Dr7;
uint64_t Rax;
uint64_t Rcx;
uint64_t Rdx;
uint64_t Rbx;
uint64_t Rsp;
uint64_t Rbp;
uint64_t Rsi;
uint64_t Rdi;
uint64_t R8;
uint64_t R9;
uint64_t R10;
uint64_t R11;
uint64_t R12;
uint64_t R13;
uint64_t R14;
uint64_t R15;
uint64_t Rip;
struct {
uint16_t ControlWord;
uint16_t StatusWord;
uint8_t TagWord;
uint8_t Reserved1;
uint16_t ErrorOpcode;
uint32_t ErrorOffset;
uint16_t ErrorSelector;
uint16_t Reserved2;
uint32_t DataOffset;
uint16_t DataSelector;
uint16_t Reserved3;
uint32_t MxCsr;
uint32_t MxCsr_Mask;
WinM128A FloatRegisters[8];
WinM128A XmmRegisters[16];
uint8_t Reserved4[96];
} FltSave;
WinM128A VectorRegister[26];
uint64_t VectorControl;
uint64_t DebugControl;
uint64_t LastBranchToRip;
uint64_t LastBranchFromRip;
uint64_t LastExceptionToRip;
uint64_t LastExceptionFromRip;
} QEMU_ALIGNED(16) WinContext;
#endif /* QEMU_WIN_DUMP_DEFS_H */

View File

@ -120,6 +120,9 @@ void replay_shutdown_request(ShutdownCause cause);
Returns 0 in PLAY mode if checkpoint was not found.
Returns 1 in all other cases. */
bool replay_checkpoint(ReplayCheckpoint checkpoint);
/*! Used to determine that checkpoint is pending.
Does not proceed to the next event in the log. */
bool replay_has_checkpoint(void);
/* Asynchronous events queue */

163
memory.c
View File

@ -374,6 +374,33 @@ static void adjust_endianness(MemoryRegion *mr, uint64_t *data, unsigned size)
}
}
static inline void memory_region_shift_read_access(uint64_t *value,
signed shift,
uint64_t mask,
uint64_t tmp)
{
if (shift >= 0) {
*value |= (tmp & mask) << shift;
} else {
*value |= (tmp & mask) >> -shift;
}
}
static inline uint64_t memory_region_shift_write_access(uint64_t *value,
signed shift,
uint64_t mask)
{
uint64_t tmp;
if (shift >= 0) {
tmp = (*value >> shift) & mask;
} else {
tmp = (*value << -shift) & mask;
}
return tmp;
}
static hwaddr memory_region_to_absolute_addr(MemoryRegion *mr, hwaddr offset)
{
MemoryRegion *root;
@ -396,37 +423,11 @@ static int get_cpu_index(void)
return -1;
}
static MemTxResult memory_region_oldmmio_read_accessor(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
uint64_t mask,
MemTxAttrs attrs)
{
uint64_t tmp;
tmp = mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr);
if (mr->subpage) {
trace_memory_region_subpage_read(get_cpu_index(), mr, addr, tmp, size);
} else if (mr == &io_mem_notdirty) {
/* Accesses to code which has previously been translated into a TB show
* up in the MMIO path, as accesses to the io_mem_notdirty
* MemoryRegion. */
trace_memory_region_tb_read(get_cpu_index(), addr, tmp, size);
} else if (TRACE_MEMORY_REGION_OPS_READ_ENABLED) {
hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size);
}
*value |= (tmp & mask) << shift;
return MEMTX_OK;
}
static MemTxResult memory_region_read_accessor(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
signed shift,
uint64_t mask,
MemTxAttrs attrs)
{
@ -444,7 +445,7 @@ static MemTxResult memory_region_read_accessor(MemoryRegion *mr,
hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size);
}
*value |= (tmp & mask) << shift;
memory_region_shift_read_access(value, shift, mask, tmp);
return MEMTX_OK;
}
@ -452,7 +453,7 @@ static MemTxResult memory_region_read_with_attrs_accessor(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
signed shift,
uint64_t mask,
MemTxAttrs attrs)
{
@ -471,47 +472,20 @@ static MemTxResult memory_region_read_with_attrs_accessor(MemoryRegion *mr,
hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size);
}
*value |= (tmp & mask) << shift;
memory_region_shift_read_access(value, shift, mask, tmp);
return r;
}
static MemTxResult memory_region_oldmmio_write_accessor(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
uint64_t mask,
MemTxAttrs attrs)
{
uint64_t tmp;
tmp = (*value >> shift) & mask;
if (mr->subpage) {
trace_memory_region_subpage_write(get_cpu_index(), mr, addr, tmp, size);
} else if (mr == &io_mem_notdirty) {
/* Accesses to code which has previously been translated into a TB show
* up in the MMIO path, as accesses to the io_mem_notdirty
* MemoryRegion. */
trace_memory_region_tb_write(get_cpu_index(), addr, tmp, size);
} else if (TRACE_MEMORY_REGION_OPS_WRITE_ENABLED) {
hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
trace_memory_region_ops_write(get_cpu_index(), mr, abs_addr, tmp, size);
}
mr->ops->old_mmio.write[ctz32(size)](mr->opaque, addr, tmp);
return MEMTX_OK;
}
static MemTxResult memory_region_write_accessor(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
signed shift,
uint64_t mask,
MemTxAttrs attrs)
{
uint64_t tmp;
uint64_t tmp = memory_region_shift_write_access(value, shift, mask);
tmp = (*value >> shift) & mask;
if (mr->subpage) {
trace_memory_region_subpage_write(get_cpu_index(), mr, addr, tmp, size);
} else if (mr == &io_mem_notdirty) {
@ -531,13 +505,12 @@ static MemTxResult memory_region_write_with_attrs_accessor(MemoryRegion *mr,
hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
signed shift,
uint64_t mask,
MemTxAttrs attrs)
{
uint64_t tmp;
uint64_t tmp = memory_region_shift_write_access(value, shift, mask);
tmp = (*value >> shift) & mask;
if (mr->subpage) {
trace_memory_region_subpage_write(get_cpu_index(), mr, addr, tmp, size);
} else if (mr == &io_mem_notdirty) {
@ -562,7 +535,7 @@ static MemTxResult access_with_adjusted_size(hwaddr addr,
hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
signed shift,
uint64_t mask,
MemTxAttrs attrs),
MemoryRegion *mr,
@ -582,7 +555,7 @@ static MemTxResult access_with_adjusted_size(hwaddr addr,
/* FIXME: support unaligned access? */
access_size = MAX(MIN(size, access_size_max), access_size_min);
access_mask = -1ULL >> (64 - access_size * 8);
access_mask = MAKE_64BIT_MASK(0, access_size * 8);
if (memory_region_big_endian(mr)) {
for (i = 0; i < size; i += access_size) {
r |= access_fn(mr, addr + i, value, access_size,
@ -1394,16 +1367,12 @@ static MemTxResult memory_region_dispatch_read1(MemoryRegion *mr,
mr->ops->impl.max_access_size,
memory_region_read_accessor,
mr, attrs);
} else if (mr->ops->read_with_attrs) {
} else {
return access_with_adjusted_size(addr, pval, size,
mr->ops->impl.min_access_size,
mr->ops->impl.max_access_size,
memory_region_read_with_attrs_accessor,
mr, attrs);
} else {
return access_with_adjusted_size(addr, pval, size, 1, 4,
memory_region_oldmmio_read_accessor,
mr, attrs);
}
}
@ -1475,17 +1444,13 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
mr->ops->impl.max_access_size,
memory_region_write_accessor, mr,
attrs);
} else if (mr->ops->write_with_attrs) {
} else {
return
access_with_adjusted_size(addr, &data, size,
mr->ops->impl.min_access_size,
mr->ops->impl.max_access_size,
memory_region_write_with_attrs_accessor,
mr, attrs);
} else {
return access_with_adjusted_size(addr, &data, size, 1, 4,
memory_region_oldmmio_write_accessor,
mr, attrs);
}
}
@ -1518,12 +1483,18 @@ void memory_region_init_ram_shared_nomigrate(MemoryRegion *mr,
bool share,
Error **errp)
{
Error *err = NULL;
memory_region_init(mr, owner, name, size);
mr->ram = true;
mr->terminates = true;
mr->destructor = memory_region_destructor_ram;
mr->ram_block = qemu_ram_alloc(size, share, mr, errp);
mr->ram_block = qemu_ram_alloc(size, share, mr, &err);
mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
if (err) {
mr->size = int128_zero();
object_unparent(OBJECT(mr));
error_propagate(errp, err);
}
}
void memory_region_init_resizeable_ram(MemoryRegion *mr,
@ -1536,16 +1507,22 @@ void memory_region_init_resizeable_ram(MemoryRegion *mr,
void *host),
Error **errp)
{
Error *err = NULL;
memory_region_init(mr, owner, name, size);
mr->ram = true;
mr->terminates = true;
mr->destructor = memory_region_destructor_ram;
mr->ram_block = qemu_ram_alloc_resizeable(size, max_size, resized,
mr, errp);
mr, &err);
mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
if (err) {
mr->size = int128_zero();
object_unparent(OBJECT(mr));
error_propagate(errp, err);
}
}
#ifdef __linux__
#ifdef CONFIG_POSIX
void memory_region_init_ram_from_file(MemoryRegion *mr,
struct Object *owner,
const char *name,
@ -1555,13 +1532,19 @@ void memory_region_init_ram_from_file(MemoryRegion *mr,
const char *path,
Error **errp)
{
Error *err = NULL;
memory_region_init(mr, owner, name, size);
mr->ram = true;
mr->terminates = true;
mr->destructor = memory_region_destructor_ram;
mr->align = align;
mr->ram_block = qemu_ram_alloc_from_file(size, mr, ram_flags, path, errp);
mr->ram_block = qemu_ram_alloc_from_file(size, mr, ram_flags, path, &err);
mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
if (err) {
mr->size = int128_zero();
object_unparent(OBJECT(mr));
error_propagate(errp, err);
}
}
void memory_region_init_ram_from_fd(MemoryRegion *mr,
@ -1572,14 +1555,20 @@ void memory_region_init_ram_from_fd(MemoryRegion *mr,
int fd,
Error **errp)
{
Error *err = NULL;
memory_region_init(mr, owner, name, size);
mr->ram = true;
mr->terminates = true;
mr->destructor = memory_region_destructor_ram;
mr->ram_block = qemu_ram_alloc_from_fd(size, mr,
share ? RAM_SHARED : 0,
fd, errp);
fd, &err);
mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
if (err) {
mr->size = int128_zero();
object_unparent(OBJECT(mr));
error_propagate(errp, err);
}
}
#endif
@ -1630,13 +1619,19 @@ void memory_region_init_rom_nomigrate(MemoryRegion *mr,
uint64_t size,
Error **errp)
{
Error *err = NULL;
memory_region_init(mr, owner, name, size);
mr->ram = true;
mr->readonly = true;
mr->terminates = true;
mr->destructor = memory_region_destructor_ram;
mr->ram_block = qemu_ram_alloc(size, false, mr, errp);
mr->ram_block = qemu_ram_alloc(size, false, mr, &err);
mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
if (err) {
mr->size = int128_zero();
object_unparent(OBJECT(mr));
error_propagate(errp, err);
}
}
void memory_region_init_rom_device_nomigrate(MemoryRegion *mr,
@ -1647,6 +1642,7 @@ void memory_region_init_rom_device_nomigrate(MemoryRegion *mr,
uint64_t size,
Error **errp)
{
Error *err = NULL;
assert(ops);
memory_region_init(mr, owner, name, size);
mr->ops = ops;
@ -1654,7 +1650,12 @@ void memory_region_init_rom_device_nomigrate(MemoryRegion *mr,
mr->terminates = true;
mr->rom_device = true;
mr->destructor = memory_region_destructor_ram;
mr->ram_block = qemu_ram_alloc(size, false, mr, errp);
mr->ram_block = qemu_ram_alloc(size, false, mr, &err);
if (err) {
mr->size = int128_zero();
object_unparent(OBJECT(mr));
error_propagate(errp, err);
}
}
void memory_region_init_iommu(void *_iommu_mr,

View File

@ -344,30 +344,6 @@ void os_set_line_buffering(void)
setvbuf(stdout, NULL, _IOLBF, 0);
}
int qemu_create_pidfile(const char *filename)
{
char buffer[128];
int len;
int fd;
fd = qemu_open(filename, O_RDWR | O_CREAT, 0600);
if (fd == -1) {
return -1;
}
if (lockf(fd, F_TLOCK, 0) == -1) {
close(fd);
return -1;
}
len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", getpid());
if (write(fd, buffer, len) != len) {
close(fd);
return -1;
}
/* keep pidfile open & locked forever */
return 0;
}
bool is_daemonized(void)
{
return daemonize;

View File

@ -97,28 +97,3 @@ int os_parse_cmd_args(int index, const char *optarg)
{
return -1;
}
int qemu_create_pidfile(const char *filename)
{
char buffer[128];
int len;
HANDLE file;
OVERLAPPED overlap;
BOOL ret;
memset(&overlap, 0, sizeof(overlap));
file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE) {
return -1;
}
len = snprintf(buffer, sizeof(buffer), "%d\n", getpid());
ret = WriteFile(file, (LPCVOID)buffer, (DWORD)len,
NULL, &overlap);
CloseHandle(file);
if (ret == 0) {
return -1;
}
return 0;
}

View File

@ -340,46 +340,6 @@ static FILE *ga_open_logfile(const char *logfile)
return f;
}
#ifndef _WIN32
static bool ga_open_pidfile(const char *pidfile)
{
int pidfd;
char pidstr[32];
pidfd = qemu_open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
if (pidfd == -1 || lockf(pidfd, F_TLOCK, 0)) {
g_critical("Cannot lock pid file, %s", strerror(errno));
if (pidfd != -1) {
close(pidfd);
}
return false;
}
if (ftruncate(pidfd, 0)) {
g_critical("Failed to truncate pid file");
goto fail;
}
snprintf(pidstr, sizeof(pidstr), "%d\n", getpid());
if (write(pidfd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
g_critical("Failed to write pid file");
goto fail;
}
/* keep pidfile open & locked forever */
return true;
fail:
unlink(pidfile);
close(pidfd);
return false;
}
#else /* _WIN32 */
static bool ga_open_pidfile(const char *pidfile)
{
return true;
}
#endif
static gint ga_strcmp(gconstpointer str1, gconstpointer str2)
{
return strcmp(str1, str2);
@ -479,8 +439,11 @@ void ga_unset_frozen(GAState *s)
ga_enable_logging(s);
g_warning("logging re-enabled due to filesystem unfreeze");
if (s->deferred_options.pid_filepath) {
if (!ga_open_pidfile(s->deferred_options.pid_filepath)) {
g_warning("failed to create/open pid file");
Error *err = NULL;
if (!qemu_write_pidfile(s->deferred_options.pid_filepath, &err)) {
g_warning("%s", error_get_pretty(err));
error_free(err);
}
s->deferred_options.pid_filepath = NULL;
}
@ -515,8 +478,11 @@ static void become_daemon(const char *pidfile)
}
if (pidfile) {
if (!ga_open_pidfile(pidfile)) {
g_critical("failed to create pidfile");
Error *err = NULL;
if (!qemu_write_pidfile(pidfile, &err)) {
g_critical("%s", error_get_pretty(err));
error_free(err);
exit(EXIT_FAILURE);
}
}

View File

@ -286,7 +286,14 @@ static void type_initialize(TypeImpl *ti)
if (ti->instance_size == 0) {
ti->abstract = true;
}
if (type_is_ancestor(ti, type_interface)) {
assert(ti->instance_size == 0);
assert(ti->abstract);
assert(!ti->instance_init);
assert(!ti->instance_post_init);
assert(!ti->instance_finalize);
assert(!ti->num_interfaces);
}
ti->class = g_malloc0(ti->class_size);
parent = type_get_parent(ti);

View File

@ -94,18 +94,6 @@ void replay_disable_events(void)
}
}
void replay_clear_events(void)
{
g_assert(replay_mutex_locked());
while (!QTAILQ_EMPTY(&events_list)) {
Event *event = QTAILQ_FIRST(&events_list);
QTAILQ_REMOVE(&events_list, event, events);
g_free(event);
}
}
/*! Adds specified async event to the queue */
void replay_add_event(ReplayAsyncEventKind event_kind,
void *opaque,
@ -308,7 +296,7 @@ void replay_init_events(void)
void replay_finish_events(void)
{
events_enabled = false;
replay_clear_events();
replay_flush_events();
}
bool replay_events_enabled(void)

View File

@ -142,8 +142,6 @@ void replay_init_events(void);
void replay_finish_events(void);
/*! Flushes events queue */
void replay_flush_events(void);
/*! Clears events list before loading new VM state */
void replay_clear_events(void);
/*! Returns true if there are any unsaved events in the queue */
bool replay_has_events(void);
/*! Saves events from queue into the file */

View File

@ -33,11 +33,18 @@ static int replay_pre_save(void *opaque)
static int replay_post_load(void *opaque, int version_id)
{
ReplayState *state = opaque;
fseek(replay_file, state->file_offset, SEEK_SET);
qemu_clock_set_last(QEMU_CLOCK_HOST, state->host_clock_last);
/* If this was a vmstate, saved in recording mode,
we need to initialize replay data fields. */
replay_fetch_data_kind();
if (replay_mode == REPLAY_MODE_PLAY) {
fseek(replay_file, state->file_offset, SEEK_SET);
qemu_clock_set_last(QEMU_CLOCK_HOST, state->host_clock_last);
/* If this was a vmstate, saved in recording mode,
we need to initialize replay data fields. */
replay_fetch_data_kind();
} else if (replay_mode == REPLAY_MODE_RECORD) {
/* This is only useful for loading the initial state.
Therefore reset all the counters. */
state->instructions_count = 0;
state->block_request_id = 0;
}
return 0;
}

View File

@ -224,6 +224,18 @@ out:
return res;
}
bool replay_has_checkpoint(void)
{
bool res = false;
if (replay_mode == REPLAY_MODE_PLAY) {
g_assert(replay_mutex_locked());
replay_account_executed_instructions();
res = EVENT_CHECKPOINT <= replay_state.data_kind
&& replay_state.data_kind <= EVENT_CHECKPOINT_LAST;
}
return res;
}
static void replay_enable(const char *fname, int mode)
{
const char *fmode = NULL;

View File

@ -117,39 +117,6 @@ QEMU_COPYRIGHT "\n"
, name);
}
static void write_pidfile(void)
{
int pidfd;
char pidstr[32];
pidfd = qemu_open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
if (pidfd == -1) {
error_report("Cannot open pid file, %s", strerror(errno));
exit(EXIT_FAILURE);
}
if (lockf(pidfd, F_TLOCK, 0)) {
error_report("Cannot lock pid file, %s", strerror(errno));
goto fail;
}
if (ftruncate(pidfd, 0)) {
error_report("Failed to truncate pid file");
goto fail;
}
snprintf(pidstr, sizeof(pidstr), "%d\n", getpid());
if (write(pidfd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
error_report("Failed to write pid file");
goto fail;
}
return;
fail:
unlink(pidfile);
close(pidfd);
exit(EXIT_FAILURE);
}
/* SG_IO support */
typedef struct PRHelperSGIOData {
@ -1080,8 +1047,11 @@ int main(int argc, char **argv)
}
}
if (daemonize || pidfile_specified)
write_pidfile();
if ((daemonize || pidfile_specified) &&
!qemu_write_pidfile(pidfile, &local_err)) {
error_report_err(local_err);
exit(EXIT_FAILURE);
}
#ifdef CONFIG_LIBCAP
if (drop_privileges() < 0) {

View File

@ -17,7 +17,7 @@ static void ra_timer_handler(void *opaque)
{
Slirp *slirp = opaque;
timer_mod(slirp->ra_timer,
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_EXT) + NDP_Interval);
ndp_send_ra(slirp);
}
@ -27,9 +27,10 @@ void icmp6_init(Slirp *slirp)
return;
}
slirp->ra_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, ra_timer_handler, slirp);
slirp->ra_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL_EXT,
ra_timer_handler, slirp);
timer_mod(slirp->ra_timer,
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_EXT) + NDP_Interval);
}
void icmp6_cleanup(Slirp *slirp)

View File

@ -5429,20 +5429,51 @@ static void x86_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
cpu->env.eip = tb->pc - tb->cs_base;
}
static bool x86_cpu_has_work(CPUState *cs)
int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request)
{
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
return ((cs->interrupt_request & (CPU_INTERRUPT_HARD |
CPU_INTERRUPT_POLL)) &&
(env->eflags & IF_MASK)) ||
(cs->interrupt_request & (CPU_INTERRUPT_NMI |
CPU_INTERRUPT_INIT |
CPU_INTERRUPT_SIPI |
CPU_INTERRUPT_MCE)) ||
((cs->interrupt_request & CPU_INTERRUPT_SMI) &&
!(env->hflags & HF_SMM_MASK));
#if !defined(CONFIG_USER_ONLY)
if (interrupt_request & CPU_INTERRUPT_POLL) {
return CPU_INTERRUPT_POLL;
}
#endif
if (interrupt_request & CPU_INTERRUPT_SIPI) {
return CPU_INTERRUPT_SIPI;
}
if (env->hflags2 & HF2_GIF_MASK) {
if ((interrupt_request & CPU_INTERRUPT_SMI) &&
!(env->hflags & HF_SMM_MASK)) {
return CPU_INTERRUPT_SMI;
} else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
!(env->hflags2 & HF2_NMI_MASK)) {
return CPU_INTERRUPT_NMI;
} else if (interrupt_request & CPU_INTERRUPT_MCE) {
return CPU_INTERRUPT_MCE;
} else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(((env->hflags2 & HF2_VINTR_MASK) &&
(env->hflags2 & HF2_HIF_MASK)) ||
(!(env->hflags2 & HF2_VINTR_MASK) &&
(env->eflags & IF_MASK &&
!(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
return CPU_INTERRUPT_HARD;
#if !defined(CONFIG_USER_ONLY)
} else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
(env->eflags & IF_MASK) &&
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
return CPU_INTERRUPT_VIRQ;
#endif
}
}
return 0;
}
static bool x86_cpu_has_work(CPUState *cs)
{
return x86_cpu_pending_interrupt(cs, cs->interrupt_request) != 0;
}
static void x86_disas_set_info(CPUState *cs, disassemble_info *info)

View File

@ -171,7 +171,7 @@ typedef enum X86Seg {
#define HF_AC_SHIFT 18 /* must be same as eflags */
#define HF_SMM_SHIFT 19 /* CPU in SMM mode */
#define HF_SVME_SHIFT 20 /* SVME enabled (copy of EFER.SVME) */
#define HF_SVMI_SHIFT 21 /* SVM intercepts are active */
#define HF_GUEST_SHIFT 21 /* SVM intercepts are active */
#define HF_OSFXSR_SHIFT 22 /* CR4.OSFXSR */
#define HF_SMAP_SHIFT 23 /* CR4.SMAP */
#define HF_IOBPT_SHIFT 24 /* an io breakpoint enabled */
@ -196,7 +196,7 @@ typedef enum X86Seg {
#define HF_AC_MASK (1 << HF_AC_SHIFT)
#define HF_SMM_MASK (1 << HF_SMM_SHIFT)
#define HF_SVME_MASK (1 << HF_SVME_SHIFT)
#define HF_SVMI_MASK (1 << HF_SVMI_SHIFT)
#define HF_GUEST_MASK (1 << HF_GUEST_SHIFT)
#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT)
#define HF_SMAP_MASK (1 << HF_SMAP_SHIFT)
#define HF_IOBPT_MASK (1 << HF_IOBPT_SHIFT)
@ -1327,7 +1327,9 @@ typedef struct CPUX86State {
bool tsc_valid;
int64_t tsc_khz;
int64_t user_tsc_khz; /* for sanity check only */
void *kvm_xsave_buf;
#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
void *xsave_buf;
#endif
#if defined(CONFIG_HVF)
HVFX86EmulatorState *hvf_emul;
#endif
@ -1485,6 +1487,7 @@ extern struct VMStateDescription vmstate_x86_cpu;
*/
void x86_cpu_do_interrupt(CPUState *cpu);
bool x86_cpu_exec_interrupt(CPUState *cpu, int int_req);
int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request);
int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
int cpuid, void *opaque);

View File

@ -53,7 +53,7 @@ static int check_exception(CPUX86State *env, int intno, int *error_code,
#if !defined(CONFIG_USER_ONLY)
if (env->old_exception == EXCP08_DBLE) {
if (env->hflags & HF_SVMI_MASK) {
if (env->hflags & HF_GUEST_MASK) {
cpu_vmexit(env, SVM_EXIT_SHUTDOWN, 0, retaddr); /* does not return */
}

View File

@ -2,6 +2,6 @@
These sources (and ../hvf-all.c) are adapted from Veertu Inc's vdhh (Veertu Desktop Hosted Hypervisor) (last known location: https://github.com/veertuinc/vdhh) with some minor changes, the most significant of which were:
1. Adapt to our current QEMU's `CPUState` structure and `address_space_rw` API; many struct members have been moved around (emulated x86 state, kvm_xsave_buf) due to historical differences + QEMU needing to handle more emulation targets.
1. Adapt to our current QEMU's `CPUState` structure and `address_space_rw` API; many struct members have been moved around (emulated x86 state, xsave_buf) due to historical differences + QEMU needing to handle more emulation targets.
2. Removal of `apic_page` and hyperv-related functionality.
3. More relaxed use of `qemu_mutex_lock_iothread`.

View File

@ -72,7 +72,6 @@
#include "sysemu/sysemu.h"
#include "target/i386/cpu.h"
pthread_rwlock_t mem_lock = PTHREAD_RWLOCK_INITIALIZER;
HVFState *hvf_state;
int hvf_disabled = 1;
@ -587,7 +586,7 @@ int hvf_init_vcpu(CPUState *cpu)
hvf_reset_vcpu(cpu);
x86cpu = X86_CPU(cpu);
x86cpu->env.kvm_xsave_buf = qemu_memalign(4096, 4096);
x86cpu->env.xsave_buf = qemu_memalign(4096, 4096);
hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_STAR, 1);
hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_LSTAR, 1);

View File

@ -75,7 +75,7 @@ void hvf_put_xsave(CPUState *cpu_state)
struct X86XSaveArea *xsave;
xsave = X86_CPU(cpu_state)->env.kvm_xsave_buf;
xsave = X86_CPU(cpu_state)->env.xsave_buf;
x86_cpu_xsave_all_areas(X86_CPU(cpu_state), xsave);
@ -163,7 +163,7 @@ void hvf_get_xsave(CPUState *cpu_state)
{
struct X86XSaveArea *xsave;
xsave = X86_CPU(cpu_state)->env.kvm_xsave_buf;
xsave = X86_CPU(cpu_state)->env.xsave_buf;
if (hv_vcpu_read_fpstate(cpu_state->hvf_fd, (void*)xsave, 4096)) {
abort();

View File

@ -1189,7 +1189,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
}
if (has_xsave) {
env->kvm_xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave));
env->xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave));
}
cpu->kvm_msr_buf = g_malloc0(MSR_BUF_SIZE);
@ -1639,7 +1639,7 @@ ASSERT_OFFSET(XSAVE_PKRU, pkru_state);
static int kvm_put_xsave(X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
X86XSaveArea *xsave = env->kvm_xsave_buf;
X86XSaveArea *xsave = env->xsave_buf;
if (!has_xsave) {
return kvm_put_fpu(cpu);
@ -2081,7 +2081,7 @@ static int kvm_get_fpu(X86CPU *cpu)
static int kvm_get_xsave(X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
X86XSaveArea *xsave = env->kvm_xsave_buf;
X86XSaveArea *xsave = env->xsave_buf;
int ret;
if (!has_xsave) {
@ -3669,6 +3669,10 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
MSIMessage src, dst;
X86IOMMUClass *class = X86_IOMMU_GET_CLASS(iommu);
if (!class->int_remap) {
return 0;
}
src.address = route->u.msi.address_hi;
src.address <<= VTD_MSI_ADDR_HI_SHIFT;
src.address |= route->u.msi.address_lo;

View File

@ -1244,7 +1244,7 @@ static void do_interrupt_all(X86CPU *cpu, int intno, int is_int,
}
if (env->cr[0] & CR0_PE_MASK) {
#if !defined(CONFIG_USER_ONLY)
if (env->hflags & HF_SVMI_MASK) {
if (env->hflags & HF_GUEST_MASK) {
handle_even_inj(env, intno, is_int, error_code, is_hw, 0);
}
#endif
@ -1259,7 +1259,7 @@ static void do_interrupt_all(X86CPU *cpu, int intno, int is_int,
}
} else {
#if !defined(CONFIG_USER_ONLY)
if (env->hflags & HF_SVMI_MASK) {
if (env->hflags & HF_GUEST_MASK) {
handle_even_inj(env, intno, is_int, error_code, is_hw, 1);
}
#endif
@ -1267,7 +1267,7 @@ static void do_interrupt_all(X86CPU *cpu, int intno, int is_int,
}
#if !defined(CONFIG_USER_ONLY)
if (env->hflags & HF_SVMI_MASK) {
if (env->hflags & HF_GUEST_MASK) {
CPUState *cs = CPU(cpu);
uint32_t event_inj = x86_ldl_phys(cs, env->vm_vmcb +
offsetof(struct vmcb,
@ -1319,74 +1319,66 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
bool ret = false;
int intno;
interrupt_request = x86_cpu_pending_interrupt(cs, interrupt_request);
if (!interrupt_request) {
return false;
}
/* Don't process multiple interrupt requests in a single call.
* This is required to make icount-driven execution deterministic.
*/
switch (interrupt_request) {
#if !defined(CONFIG_USER_ONLY)
if (interrupt_request & CPU_INTERRUPT_POLL) {
case CPU_INTERRUPT_POLL:
cs->interrupt_request &= ~CPU_INTERRUPT_POLL;
apic_poll_irq(cpu->apic_state);
/* Don't process multiple interrupt requests in a single call.
This is required to make icount-driven execution deterministic. */
return true;
}
break;
#endif
if (interrupt_request & CPU_INTERRUPT_SIPI) {
case CPU_INTERRUPT_SIPI:
do_cpu_sipi(cpu);
ret = true;
} else if (env->hflags2 & HF2_GIF_MASK) {
if ((interrupt_request & CPU_INTERRUPT_SMI) &&
!(env->hflags & HF_SMM_MASK)) {
cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0, 0);
cs->interrupt_request &= ~CPU_INTERRUPT_SMI;
do_smm_enter(cpu);
ret = true;
} else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
!(env->hflags2 & HF2_NMI_MASK)) {
cpu_svm_check_intercept_param(env, SVM_EXIT_NMI, 0, 0);
cs->interrupt_request &= ~CPU_INTERRUPT_NMI;
env->hflags2 |= HF2_NMI_MASK;
do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
ret = true;
} else if (interrupt_request & CPU_INTERRUPT_MCE) {
cs->interrupt_request &= ~CPU_INTERRUPT_MCE;
do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
ret = true;
} else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(((env->hflags2 & HF2_VINTR_MASK) &&
(env->hflags2 & HF2_HIF_MASK)) ||
(!(env->hflags2 & HF2_VINTR_MASK) &&
(env->eflags & IF_MASK &&
!(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
int intno;
cpu_svm_check_intercept_param(env, SVM_EXIT_INTR, 0, 0);
cs->interrupt_request &= ~(CPU_INTERRUPT_HARD |
CPU_INTERRUPT_VIRQ);
intno = cpu_get_pic_interrupt(env);
qemu_log_mask(CPU_LOG_TB_IN_ASM,
"Servicing hardware INT=0x%02x\n", intno);
do_interrupt_x86_hardirq(env, intno, 1);
/* ensure that no TB jump will be modified as
the program flow was changed */
ret = true;
break;
case CPU_INTERRUPT_SMI:
cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0, 0);
cs->interrupt_request &= ~CPU_INTERRUPT_SMI;
do_smm_enter(cpu);
break;
case CPU_INTERRUPT_NMI:
cpu_svm_check_intercept_param(env, SVM_EXIT_NMI, 0, 0);
cs->interrupt_request &= ~CPU_INTERRUPT_NMI;
env->hflags2 |= HF2_NMI_MASK;
do_interrupt_x86_hardirq(env, EXCP02_NMI, 1);
break;
case CPU_INTERRUPT_MCE:
cs->interrupt_request &= ~CPU_INTERRUPT_MCE;
do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0);
break;
case CPU_INTERRUPT_HARD:
cpu_svm_check_intercept_param(env, SVM_EXIT_INTR, 0, 0);
cs->interrupt_request &= ~(CPU_INTERRUPT_HARD |
CPU_INTERRUPT_VIRQ);
intno = cpu_get_pic_interrupt(env);
qemu_log_mask(CPU_LOG_TB_IN_ASM,
"Servicing hardware INT=0x%02x\n", intno);
do_interrupt_x86_hardirq(env, intno, 1);
break;
#if !defined(CONFIG_USER_ONLY)
} else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
(env->eflags & IF_MASK) &&
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
int intno;
/* FIXME: this should respect TPR */
cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR, 0, 0);
intno = x86_ldl_phys(cs, env->vm_vmcb
case CPU_INTERRUPT_VIRQ:
/* FIXME: this should respect TPR */
cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR, 0, 0);
intno = x86_ldl_phys(cs, env->vm_vmcb
+ offsetof(struct vmcb, control.int_vector));
qemu_log_mask(CPU_LOG_TB_IN_ASM,
"Servicing virtual hardware INT=0x%02x\n", intno);
do_interrupt_x86_hardirq(env, intno, 1);
cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
ret = true;
qemu_log_mask(CPU_LOG_TB_IN_ASM,
"Servicing virtual hardware INT=0x%02x\n", intno);
do_interrupt_x86_hardirq(env, intno, 1);
cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
break;
#endif
}
}
return ret;
/* Ensure that no TB jump will be modified as the program flow was changed. */
return true;
}
void helper_lldt(CPUX86State *env, int selector)

View File

@ -228,7 +228,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
}
/* enable intercepts */
env->hflags |= HF_SVMI_MASK;
env->hflags |= HF_GUEST_MASK;
env->tsc_offset = x86_ldq_phys(cs, env->vm_vmcb +
offsetof(struct vmcb, control.tsc_offset));
@ -503,7 +503,7 @@ void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
{
CPUState *cs = CPU(x86_env_get_cpu(env));
if (likely(!(env->hflags & HF_SVMI_MASK))) {
if (likely(!(env->hflags & HF_GUEST_MASK))) {
return;
}
switch (type) {
@ -697,7 +697,7 @@ void do_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
/* Reload the host state from vm_hsave */
env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
env->hflags &= ~HF_SVMI_MASK;
env->hflags &= ~HF_GUEST_MASK;
env->intercept = 0;
env->intercept_exceptions = 0;
cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ;

File diff suppressed because it is too large Load Diff

View File

@ -613,7 +613,7 @@ test-obj-y = tests/check-qnum.o tests/check-qstring.o tests/check-qdict.o \
tests/test-rcu-tailq.o \
tests/test-qdist.o tests/test-shift128.o \
tests/test-qht.o tests/qht-bench.o tests/test-qht-par.o \
tests/atomic_add-bench.o
tests/atomic_add-bench.o tests/atomic64-bench.o
$(test-obj-y): QEMU_INCLUDES += -Itests
QEMU_CFLAGS += -I$(SRC_PATH)/tests
@ -668,6 +668,7 @@ tests/test-qht-par$(EXESUF): tests/test-qht-par.o tests/qht-bench$(EXESUF) $(tes
tests/qht-bench$(EXESUF): tests/qht-bench.o $(test-util-obj-y)
tests/test-bufferiszero$(EXESUF): tests/test-bufferiszero.o $(test-util-obj-y)
tests/atomic_add-bench$(EXESUF): tests/atomic_add-bench.o $(test-util-obj-y)
tests/atomic64-bench$(EXESUF): tests/atomic64-bench.o $(test-util-obj-y)
tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\

171
tests/atomic64-bench.c Normal file
View File

@ -0,0 +1,171 @@
/*
* Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
*
* License: GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu/thread.h"
#include "qemu/host-utils.h"
#include "qemu/processor.h"
struct thread_info {
uint64_t r;
uint64_t accesses;
} QEMU_ALIGNED(64);
struct count {
int64_t i64;
} QEMU_ALIGNED(64);
static QemuThread *threads;
static struct thread_info *th_info;
static unsigned int n_threads = 1;
static unsigned int n_ready_threads;
static struct count *counts;
static unsigned int duration = 1;
static unsigned int range = 1024;
static bool test_start;
static bool test_stop;
static const char commands_string[] =
" -d = duration in seconds\n"
" -n = number of threads\n"
" -r = range (will be rounded up to pow2)";
static void usage_complete(char *argv[])
{
fprintf(stderr, "Usage: %s [options]\n", argv[0]);
fprintf(stderr, "options:\n%s\n", commands_string);
}
/*
* From: https://en.wikipedia.org/wiki/Xorshift
* This is faster than rand_r(), and gives us a wider range (RAND_MAX is only
* guaranteed to be >= INT_MAX).
*/
static uint64_t xorshift64star(uint64_t x)
{
x ^= x >> 12; /* a */
x ^= x << 25; /* b */
x ^= x >> 27; /* c */
return x * UINT64_C(2685821657736338717);
}
static void *thread_func(void *arg)
{
struct thread_info *info = arg;
atomic_inc(&n_ready_threads);
while (!atomic_read(&test_start)) {
cpu_relax();
}
while (!atomic_read(&test_stop)) {
unsigned int index;
info->r = xorshift64star(info->r);
index = info->r & (range - 1);
atomic_read_i64(&counts[index].i64);
info->accesses++;
}
return NULL;
}
static void run_test(void)
{
unsigned int remaining;
unsigned int i;
while (atomic_read(&n_ready_threads) != n_threads) {
cpu_relax();
}
atomic_set(&test_start, true);
do {
remaining = sleep(duration);
} while (remaining);
atomic_set(&test_stop, true);
for (i = 0; i < n_threads; i++) {
qemu_thread_join(&threads[i]);
}
}
static void create_threads(void)
{
unsigned int i;
threads = g_new(QemuThread, n_threads);
th_info = g_new(struct thread_info, n_threads);
counts = g_malloc0_n(range, sizeof(*counts));
for (i = 0; i < n_threads; i++) {
struct thread_info *info = &th_info[i];
info->r = (i + 1) ^ time(NULL);
info->accesses = 0;
qemu_thread_create(&threads[i], NULL, thread_func, info,
QEMU_THREAD_JOINABLE);
}
}
static void pr_params(void)
{
printf("Parameters:\n");
printf(" # of threads: %u\n", n_threads);
printf(" duration: %u\n", duration);
printf(" ops' range: %u\n", range);
}
static void pr_stats(void)
{
unsigned long long val = 0;
double tx;
int i;
for (i = 0; i < n_threads; i++) {
val += th_info[i].accesses;
}
tx = val / duration / 1e6;
printf("Results:\n");
printf("Duration: %u s\n", duration);
printf(" Throughput: %.2f Mops/s\n", tx);
printf(" Throughput/thread: %.2f Mops/s/thread\n", tx / n_threads);
}
static void parse_args(int argc, char *argv[])
{
int c;
for (;;) {
c = getopt(argc, argv, "hd:n:r:");
if (c < 0) {
break;
}
switch (c) {
case 'h':
usage_complete(argv);
exit(0);
case 'd':
duration = atoi(optarg);
break;
case 'n':
n_threads = atoi(optarg);
break;
case 'r':
range = pow2ceil(atoi(optarg));
break;
}
}
}
int main(int argc, char *argv[])
{
parse_args(argc, argv);
pr_params();
create_threads();
run_test();
pr_stats();
return 0;
}

View File

@ -307,7 +307,7 @@ static int socket_can_read_hello(void *opaque)
return 10;
}
static void char_socket_test_common(Chardev *chr)
static void char_socket_test_common(Chardev *chr, bool reconnect)
{
Chardev *chr_client;
QObject *addr;
@ -327,7 +327,8 @@ static void char_socket_test_common(Chardev *chr)
addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
qdict = qobject_to(QDict, addr);
port = qdict_get_str(qdict, "port");
tmp = g_strdup_printf("tcp:127.0.0.1:%s", port);
tmp = g_strdup_printf("tcp:127.0.0.1:%s%s", port,
reconnect ? ",reconnect=1" : "");
qobject_unref(qdict);
qemu_chr_fe_init(&be, chr, &error_abort);
@ -347,6 +348,12 @@ static void char_socket_test_common(Chardev *chr)
g_assert_cmpint(id, >, 0);
main_loop();
d.chr = chr_client;
id = g_idle_add(char_socket_test_idle, &d);
g_source_set_name_by_id(id, "test-idle");
g_assert_cmpint(id, >, 0);
main_loop();
g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
g_assert(object_property_get_bool(OBJECT(chr_client),
"connected", &error_abort));
@ -356,6 +363,7 @@ static void char_socket_test_common(Chardev *chr)
object_unparent(OBJECT(chr_client));
d.chr = chr;
d.conn_expected = false;
g_idle_add(char_socket_test_idle, &d);
main_loop();
@ -368,7 +376,15 @@ static void char_socket_basic_test(void)
{
Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
char_socket_test_common(chr);
char_socket_test_common(chr, false);
}
static void char_socket_reconnect_test(void)
{
Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
char_socket_test_common(chr, true);
}
@ -400,7 +416,7 @@ static void char_socket_fdpass_test(void)
qemu_opts_del(opts);
char_socket_test_common(chr);
char_socket_test_common(chr, false);
}
@ -819,6 +835,7 @@ int main(int argc, char **argv)
g_test_add_func("/char/file-fifo", char_file_fifo_test);
#endif
g_test_add_func("/char/socket/basic", char_socket_basic_test);
g_test_add_func("/char/socket/reconnect", char_socket_reconnect_test);
g_test_add_func("/char/socket/fdpass", char_socket_fdpass_test);
g_test_add_func("/char/udp", char_udp_test);
#ifdef HAVE_CHARDEV_SERIAL

View File

@ -33,8 +33,8 @@
static QemuMutex counts_mutex;
static long long n_reads = 0LL;
static long long n_updates = 0LL;
static long long n_reclaims = 0LL;
static long long n_nodes_removed = 0LL;
static int64_t n_reclaims;
static int64_t n_nodes_removed;
static long long n_nodes = 0LL;
static int g_test_in_charge = 0;
@ -104,7 +104,7 @@ static void reclaim_list_el(struct rcu_head *prcu)
struct list_element *el = container_of(prcu, struct list_element, rcu);
g_free(el);
/* Accessed only from call_rcu thread. */
n_reclaims++;
atomic_set_i64(&n_reclaims, n_reclaims + 1);
}
#if TEST_LIST_TYPE == 1
@ -232,7 +232,7 @@ static void *rcu_q_updater(void *arg)
qemu_mutex_lock(&counts_mutex);
n_nodes += n_nodes_local;
n_updates += n_updates_local;
n_nodes_removed += n_removed_local;
atomic_set_i64(&n_nodes_removed, n_nodes_removed + n_removed_local);
qemu_mutex_unlock(&counts_mutex);
return NULL;
}
@ -286,19 +286,21 @@ static void rcu_qtest(const char *test, int duration, int nreaders)
n_removed_local++;
}
qemu_mutex_lock(&counts_mutex);
n_nodes_removed += n_removed_local;
atomic_set_i64(&n_nodes_removed, n_nodes_removed + n_removed_local);
qemu_mutex_unlock(&counts_mutex);
synchronize_rcu();
while (n_nodes_removed > n_reclaims) {
while (atomic_read_i64(&n_nodes_removed) > atomic_read_i64(&n_reclaims)) {
g_usleep(100);
synchronize_rcu();
}
if (g_test_in_charge) {
g_assert_cmpint(n_nodes_removed, ==, n_reclaims);
g_assert_cmpint(atomic_read_i64(&n_nodes_removed), ==,
atomic_read_i64(&n_reclaims));
} else {
printf("%s: %d readers; 1 updater; nodes read: " \
"%lld, nodes removed: %lld; nodes reclaimed: %lld\n",
test, nthreadsrunning - 1, n_reads, n_nodes_removed, n_reclaims);
"%lld, nodes removed: %"PRIi64"; nodes reclaimed: %"PRIi64"\n",
test, nthreadsrunning - 1, n_reads,
atomic_read_i64(&n_nodes_removed), atomic_read_i64(&n_reclaims));
exit(0);
}
}

View File

@ -169,7 +169,7 @@ static char *get_qemu_cmd(TestServer *s,
int mem, enum test_memfd memfd, const char *mem_path,
const char *chr_opts, const char *extra)
{
if (memfd == TEST_MEMFD_AUTO && qemu_memfd_check()) {
if (memfd == TEST_MEMFD_AUTO && qemu_memfd_check(0)) {
memfd = TEST_MEMFD_YES;
}
@ -903,7 +903,7 @@ static void test_multiqueue(void)
s->queues = 2;
test_server_listen(s);
if (qemu_memfd_check()) {
if (qemu_memfd_check(0)) {
cmd = g_strdup_printf(
QEMU_CMD_MEMFD QEMU_CMD_CHR QEMU_CMD_NETDEV ",queues=%d "
"-device virtio-net-pci,netdev=net0,mq=on,vectors=%d",
@ -963,7 +963,7 @@ int main(int argc, char **argv)
/* run the main loop thread so the chardev may operate */
thread = g_thread_new(NULL, thread_function, loop);
if (qemu_memfd_check()) {
if (qemu_memfd_check(0)) {
qtest_add_data_func("/vhost-user/read-guest-mem/memfd",
GINT_TO_POINTER(TEST_MEMFD_YES),
test_read_guest_mem);

View File

@ -271,7 +271,7 @@ static void qemu_input_queue_process(void *opaque)
item = QTAILQ_FIRST(queue);
switch (item->type) {
case QEMU_INPUT_QUEUE_DELAY:
timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_EXT)
+ item->delay_ms);
return;
case QEMU_INPUT_QUEUE_EVENT:
@ -301,7 +301,7 @@ static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue,
queue_count++;
if (start_timer) {
timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_EXT)
+ item->delay_ms);
}
}
@ -448,8 +448,8 @@ void qemu_input_event_send_key_delay(uint32_t delay_ms)
}
if (!kbd_timer) {
kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_input_queue_process,
&kbd_queue);
kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL_EXT,
qemu_input_queue_process, &kbd_queue);
}
if (queue_count < queue_limit) {
qemu_input_queue_delay(&kbd_queue, kbd_timer,

View File

@ -3,6 +3,7 @@ util-obj-y += bufferiszero.o
util-obj-y += lockcnt.o
util-obj-y += aiocb.o async.o aio-wait.o thread-pool.o qemu-timer.o
util-obj-y += main-loop.o iohandler.o
util-obj-$(call lnot,$(CONFIG_ATOMIC64)) += atomic64.o
util-obj-$(CONFIG_POSIX) += aio-posix.o
util-obj-$(CONFIG_POSIX) += compatfd.o
util-obj-$(CONFIG_POSIX) += event_notifier-posix.o

83
util/atomic64.c Normal file
View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
*
* License: GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu/atomic.h"
#include "qemu/thread.h"
#ifdef CONFIG_ATOMIC64
#error This file must only be compiled if !CONFIG_ATOMIC64
#endif
/*
* When !CONFIG_ATOMIC64, we serialize both reads and writes with spinlocks.
* We use an array of spinlocks, with padding computed at run-time based on
* the host's dcache line size.
* We point to the array with a void * to simplify the padding's computation.
* Each spinlock is located every lock_size bytes.
*/
static void *lock_array;
static size_t lock_size;
/*
* Systems without CONFIG_ATOMIC64 are unlikely to have many cores, so we use a
* small array of locks.
*/
#define NR_LOCKS 16
static QemuSpin *addr_to_lock(const void *addr)
{
uintptr_t a = (uintptr_t)addr;
uintptr_t idx;
idx = a >> qemu_dcache_linesize_log;
idx ^= (idx >> 8) ^ (idx >> 16);
idx &= NR_LOCKS - 1;
return lock_array + idx * lock_size;
}
#define GEN_READ(name, type) \
type name(const type *ptr) \
{ \
QemuSpin *lock = addr_to_lock(ptr); \
type ret; \
\
qemu_spin_lock(lock); \
ret = *ptr; \
qemu_spin_unlock(lock); \
return ret; \
}
GEN_READ(atomic_read_i64, int64_t)
GEN_READ(atomic_read_u64, uint64_t)
#undef GEN_READ
#define GEN_SET(name, type) \
void name(type *ptr, type val) \
{ \
QemuSpin *lock = addr_to_lock(ptr); \
\
qemu_spin_lock(lock); \
*ptr = val; \
qemu_spin_unlock(lock); \
}
GEN_SET(atomic_set_i64, int64_t)
GEN_SET(atomic_set_u64, uint64_t)
#undef GEN_SET
void atomic64_init(void)
{
int i;
lock_size = ROUND_UP(sizeof(QemuSpin), qemu_dcache_linesize);
lock_array = qemu_memalign(qemu_dcache_linesize, lock_size * NR_LOCKS);
for (i = 0; i < NR_LOCKS; i++) {
QemuSpin *lock = lock_array + i * lock_size;
qemu_spin_init(lock);
}
}

View File

@ -7,9 +7,13 @@
*/
#include "qemu/osdep.h"
#include "qemu/host-utils.h"
#include "qemu/atomic.h"
int qemu_icache_linesize = 0;
int qemu_icache_linesize_log;
int qemu_dcache_linesize = 0;
int qemu_dcache_linesize_log;
/*
* Operating system specific detection mechanisms.
@ -172,6 +176,13 @@ static void __attribute__((constructor)) init_cache_info(void)
arch_cache_info(&isize, &dsize);
fallback_cache_info(&isize, &dsize);
assert((isize & (isize - 1)) == 0);
assert((dsize & (dsize - 1)) == 0);
qemu_icache_linesize = isize;
qemu_icache_linesize_log = ctz32(isize);
qemu_dcache_linesize = dsize;
qemu_dcache_linesize_log = ctz32(dsize);
atomic64_init();
}

View File

@ -45,22 +45,6 @@ static int memfd_create(const char *name, unsigned int flags)
}
#endif
#ifndef MFD_CLOEXEC
#define MFD_CLOEXEC 0x0001U
#endif
#ifndef MFD_ALLOW_SEALING
#define MFD_ALLOW_SEALING 0x0002U
#endif
#ifndef MFD_HUGETLB
#define MFD_HUGETLB 0x0004U
#endif
#ifndef MFD_HUGE_SHIFT
#define MFD_HUGE_SHIFT 26
#endif
int qemu_memfd_create(const char *name, size_t size, bool hugetlb,
uint64_t hugetlbsize, unsigned int seals, Error **errp)
{
@ -201,23 +185,16 @@ bool qemu_memfd_alloc_check(void)
*
* Check if host supports memfd.
*/
bool qemu_memfd_check(void)
bool qemu_memfd_check(unsigned int flags)
{
#ifdef CONFIG_LINUX
static int memfd_check = MEMFD_TODO;
int mfd = memfd_create("test", flags);
if (memfd_check == MEMFD_TODO) {
int mfd = memfd_create("test", 0);
if (mfd >= 0) {
memfd_check = MEMFD_OK;
close(mfd);
} else {
memfd_check = MEMFD_KO;
}
if (mfd >= 0) {
close(mfd);
return true;
}
return memfd_check == MEMFD_OK;
#else
return false;
#endif
return false;
}

View File

@ -88,6 +88,79 @@ int qemu_daemon(int nochdir, int noclose)
return daemon(nochdir, noclose);
}
bool qemu_write_pidfile(const char *path, Error **errp)
{
int fd;
char pidstr[32];
while (1) {
struct stat a, b;
struct flock lock = {
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
.l_len = 0,
};
fd = qemu_open(path, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
if (fd == -1) {
error_setg_errno(errp, errno, "Cannot open pid file");
return false;
}
if (fstat(fd, &b) < 0) {
error_setg_errno(errp, errno, "Cannot stat file");
goto fail_close;
}
if (fcntl(fd, F_SETLK, &lock)) {
error_setg_errno(errp, errno, "Cannot lock pid file");
goto fail_close;
}
/*
* Now make sure the path we locked is the same one that now
* exists on the filesystem.
*/
if (stat(path, &a) < 0) {
/*
* PID file disappeared, someone else must be racing with
* us, so try again.
*/
close(fd);
continue;
}
if (a.st_ino == b.st_ino) {
break;
}
/*
* PID file was recreated, someone else must be racing with
* us, so try again.
*/
close(fd);
}
if (ftruncate(fd, 0) < 0) {
error_setg_errno(errp, errno, "Failed to truncate pid file");
goto fail_unlink;
}
snprintf(pidstr, sizeof(pidstr), FMT_pid "\n", getpid());
if (write(fd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
error_setg(errp, "Failed to write pid file");
goto fail_unlink;
}
return true;
fail_unlink:
unlink(path);
fail_close:
close(fd);
return false;
}
void *qemu_oom_check(void *ptr)
{
if (ptr == NULL) {

View File

@ -776,3 +776,30 @@ ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
}
return ret;
}
bool qemu_write_pidfile(const char *filename, Error **errp)
{
char buffer[128];
int len;
HANDLE file;
OVERLAPPED overlap;
BOOL ret;
memset(&overlap, 0, sizeof(overlap));
file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE) {
error_setg(errp, "Failed to create PID file");
return false;
}
len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", (pid_t)getpid());
ret = WriteFile(file, (LPCVOID)buffer, (DWORD)len,
NULL, &overlap);
CloseHandle(file);
if (ret == 0) {
error_setg(errp, "Failed to write PID file");
return false;
}
return true;
}

View File

@ -496,6 +496,7 @@ bool timerlist_run_timers(QEMUTimerList *timer_list)
switch (timer_list->clock->type) {
case QEMU_CLOCK_REALTIME:
case QEMU_CLOCK_VIRTUAL_EXT:
break;
default:
case QEMU_CLOCK_VIRTUAL:
@ -597,6 +598,7 @@ int64_t qemu_clock_get_ns(QEMUClockType type)
return get_clock();
default:
case QEMU_CLOCK_VIRTUAL:
case QEMU_CLOCK_VIRTUAL_EXT:
if (use_icount) {
return cpu_get_icount();
} else {

View File

@ -84,13 +84,6 @@ struct QSPEntry {
uint64_t n_acqs;
uint64_t ns;
unsigned int n_objs; /* count of coalesced objs; only used for reporting */
#ifndef CONFIG_ATOMIC64
/*
* If we cannot update the counts atomically, then use a seqlock.
* We don't need an associated lock because the updates are thread-local.
*/
QemuSeqLock sequence;
#endif
};
typedef struct QSPEntry QSPEntry;
@ -344,47 +337,16 @@ static QSPEntry *qsp_entry_get(const void *obj, const char *file, int line,
return qsp_entry_find(&qsp_ht, &orig, hash);
}
/*
* @from is in the global hash table; read it atomically if the host
* supports it, otherwise use the seqlock.
*/
static void qsp_entry_aggregate(QSPEntry *to, const QSPEntry *from)
{
#ifdef CONFIG_ATOMIC64
to->ns += atomic_read__nocheck(&from->ns);
to->n_acqs += atomic_read__nocheck(&from->n_acqs);
#else
unsigned int version;
uint64_t ns, n_acqs;
do {
version = seqlock_read_begin(&from->sequence);
ns = atomic_read__nocheck(&from->ns);
n_acqs = atomic_read__nocheck(&from->n_acqs);
} while (seqlock_read_retry(&from->sequence, version));
to->ns += ns;
to->n_acqs += n_acqs;
#endif
}
/*
* @e is in the global hash table; it is only written to by the current thread,
* so we write to it atomically (as in "write once") to prevent torn reads.
* If the host doesn't support u64 atomics, use the seqlock.
*/
static inline void do_qsp_entry_record(QSPEntry *e, int64_t delta, bool acq)
{
#ifndef CONFIG_ATOMIC64
seqlock_write_begin(&e->sequence);
#endif
atomic_set__nocheck(&e->ns, e->ns + delta);
atomic_set_u64(&e->ns, e->ns + delta);
if (acq) {
atomic_set__nocheck(&e->n_acqs, e->n_acqs + 1);
atomic_set_u64(&e->n_acqs, e->n_acqs + 1);
}
#ifndef CONFIG_ATOMIC64
seqlock_write_end(&e->sequence);
#endif
}
static inline void qsp_entry_record(QSPEntry *e, int64_t delta)
@ -550,7 +512,12 @@ static void qsp_aggregate(void *p, uint32_t h, void *up)
hash = qsp_entry_no_thread_hash(e);
agg = qsp_entry_find(ht, e, hash);
qsp_entry_aggregate(agg, e);
/*
* The entry is in the global hash table; read from it atomically (as in
* "read once").
*/
agg->ns += atomic_read_u64(&e->ns);
agg->n_acqs += atomic_read_u64(&e->n_acqs);
}
static void qsp_iter_diff(void *p, uint32_t hash, void *htp)

25
vl.c
View File

@ -2560,6 +2560,16 @@ static void qemu_run_exit_notifiers(void)
notifier_list_notify(&exit_notifiers, NULL);
}
static const char *pid_file;
static Notifier qemu_unlink_pidfile_notifier;
static void qemu_unlink_pidfile(Notifier *n, void *data)
{
if (pid_file) {
unlink(pid_file);
}
}
bool machine_init_done;
void qemu_add_machine_init_done_notifier(Notifier *notify)
@ -2884,7 +2894,6 @@ int main(int argc, char **argv, char **envp)
const char *vga_model = NULL;
const char *qtest_chrdev = NULL;
const char *qtest_log = NULL;
const char *pid_file = NULL;
const char *incoming = NULL;
bool userconfig = true;
bool nographic = false;
@ -3906,11 +3915,14 @@ int main(int argc, char **argv, char **envp)
os_daemonize();
rcu_disable_atfork();
if (pid_file && qemu_create_pidfile(pid_file) != 0) {
error_report("could not acquire pid file: %s", strerror(errno));
if (pid_file && !qemu_write_pidfile(pid_file, &err)) {
error_reportf_err(err, "cannot create PID file: ");
exit(1);
}
qemu_unlink_pidfile_notifier.notify = qemu_unlink_pidfile;
qemu_add_exit_notifier(&qemu_unlink_pidfile_notifier);
if (qemu_init_main_loop(&main_loop_err)) {
error_report_err(main_loop_err);
exit(1);
@ -4523,9 +4535,7 @@ int main(int argc, char **argv, char **envp)
replay_checkpoint(CHECKPOINT_RESET);
qemu_system_reset(SHUTDOWN_CAUSE_NONE);
register_global_state();
if (replay_mode != REPLAY_MODE_NONE) {
replay_vmstate_init();
} else if (loadvm) {
if (loadvm) {
Error *local_err = NULL;
if (load_snapshot(loadvm, &local_err) < 0) {
error_report_err(local_err);
@ -4533,6 +4543,9 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
}
if (replay_mode != REPLAY_MODE_NONE) {
replay_vmstate_init();
}
qdev_prop_check_globals();
if (vmstate_dump_file) {

View File

@ -30,28 +30,32 @@ static size_t write_run(WinDumpPhyMemRun64 *run, int fd, Error **errp)
void *buf;
uint64_t addr = run->BasePage << TARGET_PAGE_BITS;
uint64_t size = run->PageCount << TARGET_PAGE_BITS;
uint64_t len = size;
uint64_t len, l;
size_t total = 0;
buf = cpu_physical_memory_map(addr, &len, false);
if (!buf) {
error_setg(errp, "win-dump: failed to map run");
return 0;
}
if (len != size) {
error_setg(errp, "win-dump: failed to map entire run");
len = 0;
goto out_unmap;
while (size) {
len = size;
buf = cpu_physical_memory_map(addr, &len, false);
if (!buf) {
error_setg(errp, "win-dump: failed to map physical range"
" 0x%016" PRIx64 "-0x%016" PRIx64, addr, addr + size - 1);
return 0;
}
l = qemu_write_full(fd, buf, len);
cpu_physical_memory_unmap(buf, addr, false, len);
if (l != len) {
error_setg(errp, QERR_IO_ERROR);
return 0;
}
addr += l;
size -= l;
total += l;
}
len = qemu_write_full(fd, buf, len);
if (len != size) {
error_setg(errp, QERR_IO_ERROR);
}
out_unmap:
cpu_physical_memory_unmap(buf, addr, false, len);
return len;
return total;
}
static void write_runs(DumpState *s, WinDumpHeader64 *h, Error **errp)

View File

@ -8,169 +8,11 @@
*
*/
typedef struct WinDumpPhyMemRun64 {
uint64_t BasePage;
uint64_t PageCount;
} QEMU_PACKED WinDumpPhyMemRun64;
#ifndef WIN_DUMP_H
#define WIN_DUMP_H
typedef struct WinDumpPhyMemDesc64 {
uint32_t NumberOfRuns;
uint32_t unused;
uint64_t NumberOfPages;
WinDumpPhyMemRun64 Run[43];
} QEMU_PACKED WinDumpPhyMemDesc64;
typedef struct WinDumpExceptionRecord {
uint32_t ExceptionCode;
uint32_t ExceptionFlags;
uint64_t ExceptionRecord;
uint64_t ExceptionAddress;
uint32_t NumberParameters;
uint32_t unused;
uint64_t ExceptionInformation[15];
} QEMU_PACKED WinDumpExceptionRecord;
typedef struct WinDumpHeader64 {
char Signature[4];
char ValidDump[4];
uint32_t MajorVersion;
uint32_t MinorVersion;
uint64_t DirectoryTableBase;
uint64_t PfnDatabase;
uint64_t PsLoadedModuleList;
uint64_t PsActiveProcessHead;
uint32_t MachineImageType;
uint32_t NumberProcessors;
union {
struct {
uint32_t BugcheckCode;
uint32_t unused0;
uint64_t BugcheckParameter1;
uint64_t BugcheckParameter2;
uint64_t BugcheckParameter3;
uint64_t BugcheckParameter4;
};
uint8_t BugcheckData[40];
};
uint8_t VersionUser[32];
uint64_t KdDebuggerDataBlock;
union {
WinDumpPhyMemDesc64 PhysicalMemoryBlock;
uint8_t PhysicalMemoryBlockBuffer[704];
};
union {
uint8_t ContextBuffer[3000];
};
WinDumpExceptionRecord Exception;
uint32_t DumpType;
uint32_t unused1;
uint64_t RequiredDumpSpace;
uint64_t SystemTime;
char Comment[128];
uint64_t SystemUpTime;
uint32_t MiniDumpFields;
uint32_t SecondaryDataState;
uint32_t ProductType;
uint32_t SuiteMask;
uint32_t WriterStatus;
uint8_t unused2;
uint8_t KdSecondaryVersion;
uint8_t reserved[4018];
} QEMU_PACKED WinDumpHeader64;
#include "qemu/win_dump_defs.h"
void create_win_dump(DumpState *s, Error **errp);
#define KDBG_OWNER_TAG_OFFSET64 0x10
#define KDBG_MM_PFN_DATABASE_OFFSET64 0xC0
#define KDBG_KI_BUGCHECK_DATA_OFFSET64 0x88
#define KDBG_KI_PROCESSOR_BLOCK_OFFSET64 0x218
#define KDBG_OFFSET_PRCB_CONTEXT_OFFSET64 0x338
#define VMCOREINFO_ELF_NOTE_HDR_SIZE 24
#define WIN_CTX_X64 0x00100000L
#define WIN_CTX_CTL 0x00000001L
#define WIN_CTX_INT 0x00000002L
#define WIN_CTX_SEG 0x00000004L
#define WIN_CTX_FP 0x00000008L
#define WIN_CTX_DBG 0x00000010L
#define WIN_CTX_FULL (WIN_CTX_X64 | WIN_CTX_CTL | WIN_CTX_INT | WIN_CTX_FP)
#define WIN_CTX_ALL (WIN_CTX_FULL | WIN_CTX_SEG | WIN_CTX_DBG)
#define LIVE_SYSTEM_DUMP 0x00000161
typedef struct WinM128A {
uint64_t low;
int64_t high;
} QEMU_ALIGNED(16) WinM128A;
typedef struct WinContext {
uint64_t PHome[6];
uint32_t ContextFlags;
uint32_t MxCsr;
uint16_t SegCs;
uint16_t SegDs;
uint16_t SegEs;
uint16_t SegFs;
uint16_t SegGs;
uint16_t SegSs;
uint32_t EFlags;
uint64_t Dr0;
uint64_t Dr1;
uint64_t Dr2;
uint64_t Dr3;
uint64_t Dr6;
uint64_t Dr7;
uint64_t Rax;
uint64_t Rcx;
uint64_t Rdx;
uint64_t Rbx;
uint64_t Rsp;
uint64_t Rbp;
uint64_t Rsi;
uint64_t Rdi;
uint64_t R8;
uint64_t R9;
uint64_t R10;
uint64_t R11;
uint64_t R12;
uint64_t R13;
uint64_t R14;
uint64_t R15;
uint64_t Rip;
struct {
uint16_t ControlWord;
uint16_t StatusWord;
uint8_t TagWord;
uint8_t Reserved1;
uint16_t ErrorOpcode;
uint32_t ErrorOffset;
uint16_t ErrorSelector;
uint16_t Reserved2;
uint32_t DataOffset;
uint16_t DataSelector;
uint16_t Reserved3;
uint32_t MxCsr;
uint32_t MxCsr_Mask;
WinM128A FloatRegisters[8];
WinM128A XmmRegisters[16];
uint8_t Reserved4[96];
} FltSave;
WinM128A VectorRegister[26];
uint64_t VectorControl;
uint64_t DebugControl;
uint64_t LastBranchToRip;
uint64_t LastBranchFromRip;
uint64_t LastExceptionToRip;
uint64_t LastExceptionFromRip;
} QEMU_ALIGNED(16) WinContext;
#endif /* WIN_DUMP_H */