* Thread Sanitizer fixes (Alex)
* Coverity fixes (David) * test-qht fixes (Emilio) * QOM interface for info irq/info pic (Hervé) * -rtc clock=rt fix (Junlian) * mux chardev fixes (Marc-André) * nicer report on death by signal (Michal) * qemu-tech TLC (Paolo) * MSI support for edu device (Peter) * qemu-nbd --offset fix (Tomáš) -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQExBAABCAAbBQJX98xmFBxwYm9uemluaUByZWRoYXQuY29tAAoJEL/70l94x66D IXsH/idLNlBzbrGhcuZOXEAd4fCyCyhXGMuOAGJXLHgv+EfiqrJ9z4HTn44czdh7 rJuQDYeDrfl36zc0n8weY7JSEsorCq+JBDomFUFodmCrFUIue2jXYOK6pt5LUrQM OTyruQMKHD316SnJFOK8Tkxi5DrAHNRs+ynDcm+IoB65KE9YgBcBWuEJ03mF9cHi 5sb/SBEqfL49gVlnFXBDTRgXXwA5axS7xKd4+7CWtbVFvJxurImjywGqKI5G/dmC TJyP+Dty4iNjFP1E0VvfL6ETovncZlfe4Hx1b971pll/ec88jGL0brqQMPjACrWh TyLXLN9oTbEKuDxx1Nh23xRFh+c= =sgtZ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging * Thread Sanitizer fixes (Alex) * Coverity fixes (David) * test-qht fixes (Emilio) * QOM interface for info irq/info pic (Hervé) * -rtc clock=rt fix (Junlian) * mux chardev fixes (Marc-André) * nicer report on death by signal (Michal) * qemu-tech TLC (Paolo) * MSI support for edu device (Peter) * qemu-nbd --offset fix (Tomáš) # gpg: Signature made Fri 07 Oct 2016 17:25:10 BST # gpg: using RSA key 0xBFFBD25F78C7AE83 # 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: (39 commits) qemu-doc: merge qemu-tech and qemu-doc qemu-tech: rewrite some parts qemu-tech: reorganize content qemu-tech: move TCG test documentation to tests/tcg/README qemu-tech: move user mode emulation features from qemu-tech qemu-tech: document lazy condition code evaluation in cpu.h qemu-tech: move text from qemu-tech to tcg/README qemu-doc: drop installation and compilation notes qemu-doc: replace introduction with the one from the internals manual qemu-tech: drop index test-qht: perform lookups under rcu_read_lock qht: fix unlock-after-free segfault upon resizing qht: simplify qht_reset_size qemu-nbd: Shrink image size by specified offset qemu_kill_report: Report PID name too util: Introduce qemu_get_pid_name char: update read handler in all cases char: use a fixed idx for child muxed chr i8259: give ISA device when registering ISA ioports .travis.yml: add gcc sanitizer build ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
86e121ae75
2
.gitignore
vendored
2
.gitignore
vendored
@ -39,9 +39,7 @@
|
||||
/qmp-introspect.[ch]
|
||||
/qmp-marshal.c
|
||||
/qemu-doc.html
|
||||
/qemu-tech.html
|
||||
/qemu-doc.info
|
||||
/qemu-tech.info
|
||||
/qemu-img
|
||||
/qemu-nbd
|
||||
/qemu-options.def
|
||||
|
45
.travis.yml
45
.travis.yml
@ -9,6 +9,7 @@ cache: ccache
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
# Build dependencies
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
@ -89,6 +90,7 @@ matrix:
|
||||
- env: CONFIG=""
|
||||
os: osx
|
||||
compiler: clang
|
||||
# Plain Trusty Build
|
||||
- env: CONFIG=""
|
||||
sudo: required
|
||||
addons:
|
||||
@ -99,3 +101,46 @@ matrix:
|
||||
- sudo apt-get build-dep -qq qemu
|
||||
- wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
|
||||
- git submodule update --init --recursive
|
||||
# Using newer GCC with sanitizers
|
||||
- addons:
|
||||
apt:
|
||||
sources:
|
||||
# PPAs for newer toolchains
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
# Extra toolchains
|
||||
- gcc-5
|
||||
- g++-5
|
||||
# Build dependencies
|
||||
- libaio-dev
|
||||
- libattr1-dev
|
||||
- libbrlapi-dev
|
||||
- libcap-ng-dev
|
||||
- libgnutls-dev
|
||||
- libgtk-3-dev
|
||||
- libiscsi-dev
|
||||
- liblttng-ust-dev
|
||||
- libnfs-dev
|
||||
- libncurses5-dev
|
||||
- libnss3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng12-dev
|
||||
- librados-dev
|
||||
- libsdl1.2-dev
|
||||
- libseccomp-dev
|
||||
- libspice-protocol-dev
|
||||
- libspice-server-dev
|
||||
- libssh2-1-dev
|
||||
- liburcu-dev
|
||||
- libusb-1.0-0-dev
|
||||
- libvte-2.90-dev
|
||||
- sparse
|
||||
- uuid-dev
|
||||
language: generic
|
||||
compiler: none
|
||||
env:
|
||||
- COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5
|
||||
- CONFIG="--cc=gcc-5 --cxx=g++-5 --disable-pie --disable-linux-user --with-coroutine=gthread"
|
||||
- TEST_CMD=""
|
||||
before_script:
|
||||
- ./configure ${CONFIG} --extra-cflags="-g3 -O0 -fsanitize=thread -fuse-ld=gold" || cat config.log
|
||||
|
13
Makefile
13
Makefile
@ -93,7 +93,7 @@ LIBS+=-lz $(LIBS_TOOLS)
|
||||
HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
|
||||
|
||||
ifdef BUILD_DOCS
|
||||
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
|
||||
DOCS=qemu-doc.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
|
||||
ifdef CONFIG_VIRTFS
|
||||
DOCS+=fsdev/virtfs-proxy-helper.1
|
||||
endif
|
||||
@ -398,7 +398,6 @@ distclean: clean
|
||||
rm -f qemu-doc.vr
|
||||
rm -f config.log
|
||||
rm -f linux-headers/asm
|
||||
rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
|
||||
for d in $(TARGET_DIRS); do \
|
||||
rm -rf $$d || exit 1 ; \
|
||||
done
|
||||
@ -434,7 +433,7 @@ endif
|
||||
|
||||
install-doc: $(DOCS)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) qemu-doc.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) $(SRC_PATH)/docs/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
ifdef CONFIG_POSIX
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||
@ -592,10 +591,10 @@ qemu-ga.8: qemu-ga.texi
|
||||
$(POD2MAN) --section=8 --center=" " --release=" " qemu-ga.pod > $@, \
|
||||
"GEN","$@")
|
||||
|
||||
dvi: qemu-doc.dvi qemu-tech.dvi
|
||||
html: qemu-doc.html qemu-tech.html
|
||||
info: qemu-doc.info qemu-tech.info
|
||||
pdf: qemu-doc.pdf qemu-tech.pdf
|
||||
dvi: qemu-doc.dvi
|
||||
html: qemu-doc.html
|
||||
info: qemu-doc.info
|
||||
pdf: qemu-doc.pdf
|
||||
|
||||
qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
|
||||
qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \
|
||||
|
2
README
2
README
@ -42,8 +42,6 @@ of other UNIX targets. The simple steps to build QEMU are:
|
||||
../configure
|
||||
make
|
||||
|
||||
Complete details of the process for building and configuring QEMU for
|
||||
all supported host platforms can be found in the qemu-tech.html file.
|
||||
Additional information can also be found online via the QEMU website:
|
||||
|
||||
http://qemu-project.org/Hosts/Linux
|
||||
|
@ -192,7 +192,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
||||
/* We were asked to stop executing TBs (probably a pending
|
||||
* interrupt. We've now stopped, so clear the flag.
|
||||
*/
|
||||
cpu->tcg_exit_req = 0;
|
||||
atomic_set(&cpu->tcg_exit_req, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -490,8 +490,8 @@ static inline void cpu_handle_interrupt(CPUState *cpu,
|
||||
*last_tb = NULL;
|
||||
}
|
||||
}
|
||||
if (unlikely(cpu->exit_request || replay_has_interrupt())) {
|
||||
cpu->exit_request = 0;
|
||||
if (unlikely(atomic_read(&cpu->exit_request) || replay_has_interrupt())) {
|
||||
atomic_set(&cpu->exit_request, 0);
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
@ -503,7 +503,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
{
|
||||
uintptr_t ret;
|
||||
|
||||
if (unlikely(cpu->exit_request)) {
|
||||
if (unlikely(atomic_read(&cpu->exit_request))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ size == 8 for the rest.
|
||||
|
||||
0x20 (RW) : status register, bitwise OR
|
||||
0x01 -- computing factorial (RO)
|
||||
0x80 -- raise interrupt 0x01 after finishing factorial computation
|
||||
0x80 -- raise interrupt after finishing factorial computation
|
||||
|
||||
0x24 (RO) : interrupt status register
|
||||
It contains values which raised the interrupt (see interrupt raise
|
||||
@ -87,6 +87,11 @@ An IRQ is generated when written to the interrupt raise register. The value
|
||||
appears in interrupt status register when the interrupt is raised and has to
|
||||
be written to the interrupt acknowledge register to lower it.
|
||||
|
||||
The device supports both INTx and MSI interrupt. By default, INTx is
|
||||
used. Even if the driver disabled INTx and only uses MSI, it still
|
||||
needs to update the acknowledge register at the end of the IRQ handler
|
||||
routine.
|
||||
|
||||
DMA controller
|
||||
--------------
|
||||
One has to specify, source, destination, size, and start the transfer. One
|
||||
|
@ -172,20 +172,12 @@ STEXI
|
||||
Show the command line history.
|
||||
ETEXI
|
||||
|
||||
#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_MIPS) || \
|
||||
defined(TARGET_LM32) || (defined(TARGET_SPARC) && !defined(TARGET_SPARC64))
|
||||
{
|
||||
.name = "irq",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the interrupts statistics (if available)",
|
||||
#ifdef TARGET_SPARC
|
||||
.cmd = sun4m_hmp_info_irq,
|
||||
#elif defined(TARGET_LM32)
|
||||
.cmd = lm32_hmp_info_irq,
|
||||
#else
|
||||
.cmd = hmp_info_irq,
|
||||
#endif
|
||||
},
|
||||
|
||||
STEXI
|
||||
@ -198,16 +190,9 @@ ETEXI
|
||||
.name = "pic",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show i8259 (PIC) state",
|
||||
#ifdef TARGET_SPARC
|
||||
.cmd = sun4m_hmp_info_pic,
|
||||
#elif defined(TARGET_LM32)
|
||||
.cmd = lm32_hmp_info_pic,
|
||||
#else
|
||||
.help = "show PIC state",
|
||||
.cmd = hmp_info_pic,
|
||||
#endif
|
||||
},
|
||||
#endif
|
||||
|
||||
STEXI
|
||||
@item info pic
|
||||
|
65
hmp.c
65
hmp.c
@ -36,6 +36,7 @@
|
||||
#include "qemu-io.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/intc/intc.h"
|
||||
|
||||
#ifdef CONFIG_SPICE
|
||||
#include <spice/enums.h>
|
||||
@ -787,6 +788,70 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static int hmp_info_irq_foreach(Object *obj, void *opaque)
|
||||
{
|
||||
InterruptStatsProvider *intc;
|
||||
InterruptStatsProviderClass *k;
|
||||
Monitor *mon = opaque;
|
||||
|
||||
if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) {
|
||||
intc = INTERRUPT_STATS_PROVIDER(obj);
|
||||
k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj);
|
||||
uint64_t *irq_counts;
|
||||
unsigned int nb_irqs, i;
|
||||
if (k->get_statistics &&
|
||||
k->get_statistics(intc, &irq_counts, &nb_irqs)) {
|
||||
if (nb_irqs > 0) {
|
||||
monitor_printf(mon, "IRQ statistics for %s:\n",
|
||||
object_get_typename(obj));
|
||||
for (i = 0; i < nb_irqs; i++) {
|
||||
if (irq_counts[i] > 0) {
|
||||
monitor_printf(mon, "%2d: %" PRId64 "\n", i,
|
||||
irq_counts[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
monitor_printf(mon, "IRQ statistics not available for %s.\n",
|
||||
object_get_typename(obj));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hmp_info_irq(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
object_child_foreach_recursive(object_get_root(),
|
||||
hmp_info_irq_foreach, mon);
|
||||
}
|
||||
|
||||
static int hmp_info_pic_foreach(Object *obj, void *opaque)
|
||||
{
|
||||
InterruptStatsProvider *intc;
|
||||
InterruptStatsProviderClass *k;
|
||||
Monitor *mon = opaque;
|
||||
|
||||
if (object_dynamic_cast(obj, TYPE_INTERRUPT_STATS_PROVIDER)) {
|
||||
intc = INTERRUPT_STATS_PROVIDER(obj);
|
||||
k = INTERRUPT_STATS_PROVIDER_GET_CLASS(obj);
|
||||
if (k->print_info) {
|
||||
k->print_info(intc, mon);
|
||||
} else {
|
||||
monitor_printf(mon, "Interrupt controller information not available for %s.\n",
|
||||
object_get_typename(obj));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hmp_info_pic(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
object_child_foreach_recursive(object_get_root(),
|
||||
hmp_info_pic_foreach, mon);
|
||||
}
|
||||
|
||||
void hmp_info_pci(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
PciInfoList *info_list, *info;
|
||||
|
2
hmp.h
2
hmp.h
@ -36,6 +36,8 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_vnc(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_spice(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_balloon(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_irq(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_pic(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_pci(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_block_jobs(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_tpm(Monitor *mon, const QDict *qdict);
|
||||
|
@ -143,10 +143,10 @@ static void amdvi_assign_andq(AMDVIState *s, hwaddr addr, uint64_t val)
|
||||
|
||||
static void amdvi_generate_msi_interrupt(AMDVIState *s)
|
||||
{
|
||||
MSIMessage msg;
|
||||
MemTxAttrs attrs;
|
||||
|
||||
attrs.requester_id = pci_requester_id(&s->pci.dev);
|
||||
MSIMessage msg = {};
|
||||
MemTxAttrs attrs = {
|
||||
.requester_id = pci_requester_id(&s->pci.dev)
|
||||
};
|
||||
|
||||
if (msi_enabled(&s->pci.dev)) {
|
||||
msg = msi_get_message(&s->pci.dev, 0);
|
||||
@ -185,7 +185,7 @@ static void amdvi_setevent_bits(uint64_t *buffer, uint64_t value, int start,
|
||||
int length)
|
||||
{
|
||||
int index = start / 64, bitpos = start % 64;
|
||||
uint64_t mask = ((1 << length) - 1) << bitpos;
|
||||
uint64_t mask = MAKE_64BIT_MASK(start, length);
|
||||
buffer[index] &= ~mask;
|
||||
buffer[index] |= (value << bitpos) & mask;
|
||||
}
|
||||
@ -333,8 +333,8 @@ static void amdvi_update_iotlb(AMDVIState *s, uint16_t devid,
|
||||
uint64_t gpa, IOMMUTLBEntry to_cache,
|
||||
uint16_t domid)
|
||||
{
|
||||
AMDVIIOTLBEntry *entry = g_malloc(sizeof(*entry));
|
||||
uint64_t *key = g_malloc(sizeof(key));
|
||||
AMDVIIOTLBEntry *entry = g_new(AMDVIIOTLBEntry, 1);
|
||||
uint64_t *key = g_new(uint64_t, 1);
|
||||
uint64_t gfn = gpa >> AMDVI_PAGE_SHIFT_4K;
|
||||
|
||||
/* don't cache erroneous translations */
|
||||
@ -1135,6 +1135,7 @@ static void amdvi_reset(DeviceState *dev)
|
||||
|
||||
static void amdvi_realize(DeviceState *dev, Error **err)
|
||||
{
|
||||
int ret = 0;
|
||||
AMDVIState *s = AMD_IOMMU_DEVICE(dev);
|
||||
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev);
|
||||
PCIBus *bus = PC_MACHINE(qdev_get_machine())->bus;
|
||||
@ -1147,8 +1148,11 @@ static void amdvi_realize(DeviceState *dev, Error **err)
|
||||
object_property_set_bool(OBJECT(&s->pci), true, "realized", err);
|
||||
s->capab_offset = pci_add_capability(&s->pci.dev, AMDVI_CAPAB_ID_SEC, 0,
|
||||
AMDVI_CAPAB_SIZE);
|
||||
pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE);
|
||||
pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE);
|
||||
assert(s->capab_offset > 0);
|
||||
ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_MSI, 0, AMDVI_CAPAB_REG_SIZE);
|
||||
assert(ret > 0);
|
||||
ret = pci_add_capability(&s->pci.dev, PCI_CAP_ID_HT, 0, AMDVI_CAPAB_REG_SIZE);
|
||||
assert(ret > 0);
|
||||
|
||||
/* set up MMIO */
|
||||
memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio",
|
||||
|
@ -18,6 +18,7 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
|
||||
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o
|
||||
common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_its_common.o
|
||||
common-obj-$(CONFIG_OPENPIC) += openpic.o
|
||||
common-obj-y += intc.o
|
||||
|
||||
obj-$(CONFIG_APIC) += apic.o apic_common.o
|
||||
obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/isa/i8259_internal.h"
|
||||
#include "hw/intc/intc.h"
|
||||
|
||||
/* debug PIC */
|
||||
//#define DEBUG_PIC
|
||||
@ -251,6 +252,35 @@ static void pic_reset(DeviceState *dev)
|
||||
pic_init_reset(s);
|
||||
}
|
||||
|
||||
static bool pic_get_statistics(InterruptStatsProvider *obj,
|
||||
uint64_t **irq_counts, unsigned int *nb_irqs)
|
||||
{
|
||||
PICCommonState *s = PIC_COMMON(obj);
|
||||
|
||||
if (s->master) {
|
||||
#ifdef DEBUG_IRQ_COUNT
|
||||
*irq_counts = irq_count;
|
||||
*nb_irqs = ARRAY_SIZE(irq_count);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
*irq_counts = NULL;
|
||||
*nb_irqs = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void pic_print_info(InterruptStatsProvider *obj, Monitor *mon)
|
||||
{
|
||||
PICCommonState *s = PIC_COMMON(obj);
|
||||
monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
|
||||
"irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
|
||||
s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add,
|
||||
s->irq_base, s->read_reg_select, s->elcr,
|
||||
s->special_fully_nested_mode);
|
||||
}
|
||||
|
||||
static void pic_ioport_write(void *opaque, hwaddr addr64,
|
||||
uint64_t val64, unsigned size)
|
||||
{
|
||||
@ -431,42 +461,6 @@ static void pic_realize(DeviceState *dev, Error **errp)
|
||||
pc->parent_realize(dev, errp);
|
||||
}
|
||||
|
||||
void hmp_info_pic(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
int i;
|
||||
PICCommonState *s;
|
||||
|
||||
if (!isa_pic) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
s = i == 0 ? PIC_COMMON(isa_pic) : slave_pic;
|
||||
monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
|
||||
"irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
|
||||
i, s->irr, s->imr, s->isr, s->priority_add,
|
||||
s->irq_base, s->read_reg_select, s->elcr,
|
||||
s->special_fully_nested_mode);
|
||||
}
|
||||
}
|
||||
|
||||
void hmp_info_irq(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
#ifndef DEBUG_IRQ_COUNT
|
||||
monitor_printf(mon, "irq statistic code not compiled.\n");
|
||||
#else
|
||||
int i;
|
||||
int64_t count;
|
||||
|
||||
monitor_printf(mon, "IRQ statistics:\n");
|
||||
for (i = 0; i < 16; i++) {
|
||||
count = irq_count[i];
|
||||
if (count > 0) {
|
||||
monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
|
||||
{
|
||||
qemu_irq *irq_set;
|
||||
@ -503,10 +497,13 @@ static void i8259_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PICClass *k = PIC_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
|
||||
|
||||
k->parent_realize = dc->realize;
|
||||
dc->realize = pic_realize;
|
||||
dc->reset = pic_reset;
|
||||
ic->get_statistics = pic_get_statistics;
|
||||
ic->print_info = pic_print_info;
|
||||
}
|
||||
|
||||
static const TypeInfo i8259_info = {
|
||||
@ -515,6 +512,10 @@ static const TypeInfo i8259_info = {
|
||||
.parent = TYPE_PIC_COMMON,
|
||||
.class_init = i8259_class_init,
|
||||
.class_size = sizeof(PICClass),
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_INTERRUPT_STATS_PROVIDER },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static void pic_register_types(void)
|
||||
|
@ -70,10 +70,11 @@ static int pic_dispatch_post_load(void *opaque, int version_id)
|
||||
static void pic_common_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PICCommonState *s = PIC_COMMON(dev);
|
||||
ISADevice *isa = ISA_DEVICE(dev);
|
||||
|
||||
isa_register_ioport(NULL, &s->base_io, s->iobase);
|
||||
isa_register_ioport(isa, &s->base_io, s->iobase);
|
||||
if (s->elcr_addr != -1) {
|
||||
isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
|
||||
isa_register_ioport(isa, &s->elcr_io, s->elcr_addr);
|
||||
}
|
||||
|
||||
qdev_set_legacy_instance_id(dev, s->iobase, 1);
|
||||
|
41
hw/intc/intc.c
Normal file
41
hw/intc/intc.c
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* QEMU Generic Interrupt Controller
|
||||
*
|
||||
* Copyright (c) 2016 Hervé Poussineau
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/intc/intc.h"
|
||||
#include "qemu/module.h"
|
||||
|
||||
static const TypeInfo intctrl_info = {
|
||||
.name = TYPE_INTERRUPT_STATS_PROVIDER,
|
||||
.parent = TYPE_INTERFACE,
|
||||
.class_size = sizeof(InterruptStatsProviderClass),
|
||||
};
|
||||
|
||||
static void intc_register_types(void)
|
||||
{
|
||||
type_register_static(&intctrl_info);
|
||||
}
|
||||
|
||||
type_init(intc_register_types)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "hw/sysbus.h"
|
||||
#include "trace.h"
|
||||
#include "hw/lm32/lm32_pic.h"
|
||||
#include "hw/intc/intc.h"
|
||||
|
||||
#define TYPE_LM32_PIC "lm32-pic"
|
||||
#define LM32_PIC(obj) OBJECT_CHECK(LM32PicState, (obj), TYPE_LM32_PIC)
|
||||
@ -38,39 +39,10 @@ struct LM32PicState {
|
||||
uint32_t irq_state;
|
||||
|
||||
/* statistics */
|
||||
uint32_t stats_irq_count[32];
|
||||
uint64_t stats_irq_count[32];
|
||||
};
|
||||
typedef struct LM32PicState LM32PicState;
|
||||
|
||||
static LM32PicState *pic;
|
||||
void lm32_hmp_info_pic(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
if (pic == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n",
|
||||
pic->im, pic->ip, pic->irq_state);
|
||||
}
|
||||
|
||||
void lm32_hmp_info_irq(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
int i;
|
||||
uint32_t count;
|
||||
|
||||
if (pic == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "IRQ statistics:\n");
|
||||
for (i = 0; i < 32; i++) {
|
||||
count = pic->stats_irq_count[i];
|
||||
if (count > 0) {
|
||||
monitor_printf(mon, "%2d: %u\n", i, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void update_irq(LM32PicState *s)
|
||||
{
|
||||
s->ip |= s->irq_state;
|
||||
@ -152,6 +124,22 @@ static void pic_reset(DeviceState *d)
|
||||
}
|
||||
}
|
||||
|
||||
static bool lm32_get_statistics(InterruptStatsProvider *obj,
|
||||
uint64_t **irq_counts, unsigned int *nb_irqs)
|
||||
{
|
||||
LM32PicState *s = LM32_PIC(obj);
|
||||
*irq_counts = s->stats_irq_count;
|
||||
*nb_irqs = ARRAY_SIZE(s->stats_irq_count);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void lm32_print_info(InterruptStatsProvider *obj, Monitor *mon)
|
||||
{
|
||||
LM32PicState *s = LM32_PIC(obj);
|
||||
monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n",
|
||||
s->im, s->ip, s->irq_state);
|
||||
}
|
||||
|
||||
static void lm32_pic_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
@ -160,19 +148,17 @@ static void lm32_pic_init(Object *obj)
|
||||
|
||||
qdev_init_gpio_in(dev, irq_handler, 32);
|
||||
sysbus_init_irq(sbd, &s->parent_irq);
|
||||
|
||||
pic = s;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_lm32_pic = {
|
||||
.name = "lm32-pic",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(im, LM32PicState),
|
||||
VMSTATE_UINT32(ip, LM32PicState),
|
||||
VMSTATE_UINT32(irq_state, LM32PicState),
|
||||
VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32),
|
||||
VMSTATE_UINT64_ARRAY(stats_irq_count, LM32PicState, 32),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
@ -180,9 +166,12 @@ static const VMStateDescription vmstate_lm32_pic = {
|
||||
static void lm32_pic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
|
||||
|
||||
dc->reset = pic_reset;
|
||||
dc->vmsd = &vmstate_lm32_pic;
|
||||
ic->get_statistics = lm32_get_statistics;
|
||||
ic->print_info = lm32_print_info;
|
||||
}
|
||||
|
||||
static const TypeInfo lm32_pic_info = {
|
||||
@ -191,6 +180,10 @@ static const TypeInfo lm32_pic_info = {
|
||||
.instance_size = sizeof(LM32PicState),
|
||||
.instance_init = lm32_pic_init,
|
||||
.class_init = lm32_pic_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_INTERRUPT_STATS_PROVIDER },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static void lm32_pic_register_types(void)
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "hw/sparc/sun4m.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/intc/intc.h"
|
||||
#include "trace.h"
|
||||
|
||||
//#define DEBUG_IRQ_COUNT
|
||||
@ -210,38 +211,6 @@ static const MemoryRegionOps slavio_intctlm_mem_ops = {
|
||||
},
|
||||
};
|
||||
|
||||
void slavio_pic_info(Monitor *mon, DeviceState *dev)
|
||||
{
|
||||
SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CPUS; i++) {
|
||||
monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
|
||||
s->slaves[i].intreg_pending);
|
||||
}
|
||||
monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
|
||||
s->intregm_pending, s->intregm_disabled);
|
||||
}
|
||||
|
||||
void slavio_irq_info(Monitor *mon, DeviceState *dev)
|
||||
{
|
||||
#ifndef DEBUG_IRQ_COUNT
|
||||
monitor_printf(mon, "irq statistic code not compiled.\n");
|
||||
#else
|
||||
SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev);
|
||||
int i;
|
||||
int64_t count;
|
||||
|
||||
s = SLAVIO_INTCTL(dev);
|
||||
monitor_printf(mon, "IRQ statistics:\n");
|
||||
for (i = 0; i < 32; i++) {
|
||||
count = s->irq_count[i];
|
||||
if (count > 0)
|
||||
monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static const uint32_t intbit_to_level[] = {
|
||||
2, 3, 5, 7, 9, 11, 13, 2, 3, 5, 7, 9, 11, 13, 12, 12,
|
||||
6, 13, 4, 10, 8, 9, 11, 0, 0, 0, 0, 15, 15, 15, 15, 0,
|
||||
@ -418,6 +387,31 @@ static void slavio_intctl_reset(DeviceState *d)
|
||||
slavio_check_interrupts(s, 0);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_IRQ_COUNT
|
||||
static bool slavio_intctl_get_statistics(InterruptStatsProvider *obj,
|
||||
uint64_t **irq_counts,
|
||||
unsigned int *nb_irqs)
|
||||
{
|
||||
SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
|
||||
*irq_counts = s->irq_count;
|
||||
*nb_irqs = ARRAY_SIZE(s->irq_count);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void slavio_intctl_print_info(InterruptStatsProvider *obj, Monitor *mon)
|
||||
{
|
||||
SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CPUS; i++) {
|
||||
monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
|
||||
s->slaves[i].intreg_pending);
|
||||
}
|
||||
monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
|
||||
s->intregm_pending, s->intregm_disabled);
|
||||
}
|
||||
|
||||
static void slavio_intctl_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
@ -449,9 +443,14 @@ static void slavio_intctl_init(Object *obj)
|
||||
static void slavio_intctl_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
|
||||
|
||||
dc->reset = slavio_intctl_reset;
|
||||
dc->vmsd = &vmstate_intctl;
|
||||
#ifdef DEBUG_IRQ_COUNT
|
||||
ic->get_statistics = slavio_intctl_get_statistics;
|
||||
#endif
|
||||
ic->print_info = slavio_intctl_print_info;
|
||||
}
|
||||
|
||||
static const TypeInfo slavio_intctl_info = {
|
||||
@ -460,6 +459,10 @@ static const TypeInfo slavio_intctl_info = {
|
||||
.instance_size = sizeof(SLAVIO_INTCTLState),
|
||||
.instance_init = slavio_intctl_init,
|
||||
.class_init = slavio_intctl_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_INTERRUPT_STATS_PROVIDER },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static void slavio_intctl_register_types(void)
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/msi.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/main-loop.h" /* iothread mutex */
|
||||
#include "qapi/visitor.h"
|
||||
@ -69,11 +70,20 @@ typedef struct {
|
||||
uint64_t dma_mask;
|
||||
} EduState;
|
||||
|
||||
static bool edu_msi_enabled(EduState *edu)
|
||||
{
|
||||
return msi_enabled(&edu->pdev);
|
||||
}
|
||||
|
||||
static void edu_raise_irq(EduState *edu, uint32_t val)
|
||||
{
|
||||
edu->irq_status |= val;
|
||||
if (edu->irq_status) {
|
||||
pci_set_irq(&edu->pdev, 1);
|
||||
if (edu_msi_enabled(edu)) {
|
||||
msi_notify(&edu->pdev, 0);
|
||||
} else {
|
||||
pci_set_irq(&edu->pdev, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,7 +91,7 @@ static void edu_lower_irq(EduState *edu, uint32_t val)
|
||||
{
|
||||
edu->irq_status &= ~val;
|
||||
|
||||
if (!edu->irq_status) {
|
||||
if (!edu->irq_status && !edu_msi_enabled(edu)) {
|
||||
pci_set_irq(&edu->pdev, 0);
|
||||
}
|
||||
}
|
||||
@ -342,6 +352,10 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp)
|
||||
|
||||
pci_config_set_interrupt_pin(pci_conf, 1);
|
||||
|
||||
if (msi_init(pdev, 0, 1, true, false, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu,
|
||||
"edu-mmio", 1 << 20);
|
||||
pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio);
|
||||
|
@ -159,20 +159,6 @@ static void nvram_init(Nvram *nvram, uint8_t *macaddr,
|
||||
}
|
||||
}
|
||||
|
||||
static DeviceState *slavio_intctl;
|
||||
|
||||
void sun4m_hmp_info_pic(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
if (slavio_intctl)
|
||||
slavio_pic_info(mon, slavio_intctl);
|
||||
}
|
||||
|
||||
void sun4m_hmp_info_irq(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
if (slavio_intctl)
|
||||
slavio_irq_info(mon, slavio_intctl);
|
||||
}
|
||||
|
||||
void cpu_check_irqs(CPUSPARCState *env)
|
||||
{
|
||||
CPUState *cs;
|
||||
@ -873,6 +859,7 @@ static void dummy_fdc_tc(void *opaque, int irq, int level)
|
||||
static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
|
||||
MachineState *machine)
|
||||
{
|
||||
DeviceState *slavio_intctl;
|
||||
const char *cpu_model = machine->cpu_model;
|
||||
unsigned int i;
|
||||
void *iommu, *espdma, *ledma, *nvram;
|
||||
|
@ -717,11 +717,18 @@ static void rtc_set_date_from_host(ISADevice *dev)
|
||||
rtc_set_cmos(s, &tm);
|
||||
}
|
||||
|
||||
static void rtc_pre_save(void *opaque)
|
||||
{
|
||||
RTCState *s = opaque;
|
||||
|
||||
rtc_update_time(s);
|
||||
}
|
||||
|
||||
static int rtc_post_load(void *opaque, int version_id)
|
||||
{
|
||||
RTCState *s = opaque;
|
||||
|
||||
if (version_id <= 2) {
|
||||
if (version_id <= 2 || rtc_clock == QEMU_CLOCK_REALTIME) {
|
||||
rtc_set_time(s);
|
||||
s->offset = 0;
|
||||
check_update_timer(s);
|
||||
@ -764,6 +771,7 @@ static const VMStateDescription vmstate_rtc = {
|
||||
.name = "mc146818rtc",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = rtc_pre_save,
|
||||
.post_load = rtc_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BUFFER(cmos_data, RTCState),
|
||||
|
@ -181,8 +181,6 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq);
|
||||
qemu_irq *kvm_i8259_init(ISABus *bus);
|
||||
int pic_read_irq(DeviceState *d);
|
||||
int pic_get_output(DeviceState *d);
|
||||
void hmp_info_pic(Monitor *mon, const QDict *qdict);
|
||||
void hmp_info_irq(Monitor *mon, const QDict *qdict);
|
||||
|
||||
/* ioapic.c */
|
||||
|
||||
|
33
include/hw/intc/intc.h
Normal file
33
include/hw/intc/intc.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef INTC_H
|
||||
#define INTC_H
|
||||
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_INTERRUPT_STATS_PROVIDER "intctrl"
|
||||
|
||||
#define INTERRUPT_STATS_PROVIDER_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(InterruptStatsProviderClass, (klass), \
|
||||
TYPE_INTERRUPT_STATS_PROVIDER)
|
||||
#define INTERRUPT_STATS_PROVIDER_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(InterruptStatsProviderClass, (obj), \
|
||||
TYPE_INTERRUPT_STATS_PROVIDER)
|
||||
#define INTERRUPT_STATS_PROVIDER(obj) \
|
||||
INTERFACE_CHECK(InterruptStatsProvider, (obj), \
|
||||
TYPE_INTERRUPT_STATS_PROVIDER)
|
||||
|
||||
typedef struct InterruptStatsProvider {
|
||||
Object parent;
|
||||
} InterruptStatsProvider;
|
||||
|
||||
typedef struct InterruptStatsProviderClass {
|
||||
InterfaceClass parent;
|
||||
|
||||
/* The returned pointer and statistics must remain valid until
|
||||
* the BQL is next dropped.
|
||||
*/
|
||||
bool (*get_statistics)(InterruptStatsProvider *obj, uint64_t **irq_counts,
|
||||
unsigned int *nb_irqs);
|
||||
void (*print_info)(InterruptStatsProvider *obj, Monitor *mon);
|
||||
} InterruptStatsProviderClass;
|
||||
|
||||
#endif
|
@ -8,7 +8,4 @@ uint32_t lm32_pic_get_im(DeviceState *d);
|
||||
void lm32_pic_set_ip(DeviceState *d, uint32_t ip);
|
||||
void lm32_pic_set_im(DeviceState *d, uint32_t im);
|
||||
|
||||
void lm32_hmp_info_pic(Monitor *mon, const QDict *qdict);
|
||||
void lm32_hmp_info_irq(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#endif /* QEMU_HW_LM32_PIC_H */
|
||||
|
@ -24,14 +24,6 @@ static inline void sparc_iommu_memory_write(void *opaque,
|
||||
sparc_iommu_memory_rw(opaque, addr, buf, len, 1);
|
||||
}
|
||||
|
||||
/* slavio_intctl.c */
|
||||
void slavio_pic_info(Monitor *mon, DeviceState *dev);
|
||||
void slavio_irq_info(Monitor *mon, DeviceState *dev);
|
||||
|
||||
/* sun4m.c */
|
||||
void sun4m_hmp_info_pic(Monitor *mon, const QDict *qdict);
|
||||
void sun4m_hmp_info_irq(Monitor *mon, const QDict *qdict);
|
||||
|
||||
/* sparc32_dma.c */
|
||||
#include "hw/sparc/sparc32_dma.h"
|
||||
|
||||
|
@ -82,7 +82,7 @@
|
||||
*/
|
||||
#if defined(__SANITIZE_THREAD__)
|
||||
#define smp_read_barrier_depends() ({ barrier(); __atomic_thread_fence(__ATOMIC_CONSUME); })
|
||||
#elsif defined(__alpha__)
|
||||
#elif defined(__alpha__)
|
||||
#define smp_read_barrier_depends() asm volatile("mb":::"memory")
|
||||
#else
|
||||
#define smp_read_barrier_depends() barrier()
|
||||
@ -92,6 +92,12 @@
|
||||
/* Weak atomic operations prevent the compiler moving other
|
||||
* loads/stores past the atomic operation load/store. However there is
|
||||
* no explicit memory barrier for the processor.
|
||||
*
|
||||
* The C11 memory model says that variables that are accessed from
|
||||
* different threads should at least be done with __ATOMIC_RELAXED
|
||||
* primitives or the result is undefined. Generally this has little to
|
||||
* no effect on the generated code but not using the atomic primitives
|
||||
* will get flagged by sanitizers as a violation.
|
||||
*/
|
||||
#define atomic_read(ptr) \
|
||||
({ \
|
||||
|
@ -387,6 +387,16 @@ void os_mem_prealloc(int fd, char *area, size_t sz, Error **errp);
|
||||
|
||||
int qemu_read_password(char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* qemu_get_pid_name:
|
||||
* @pid: pid of a process
|
||||
*
|
||||
* For given @pid fetch its name. Caller is responsible for
|
||||
* freeing the string when no longer needed.
|
||||
* Returns allocated string on success, NULL on failure.
|
||||
*/
|
||||
char *qemu_get_pid_name(pid_t pid);
|
||||
|
||||
/**
|
||||
* qemu_fork:
|
||||
*
|
||||
|
@ -31,7 +31,7 @@ static inline void seqlock_init(QemuSeqLock *sl)
|
||||
/* Lock out other writers and update the count. */
|
||||
static inline void seqlock_write_begin(QemuSeqLock *sl)
|
||||
{
|
||||
++sl->sequence;
|
||||
atomic_set(&sl->sequence, sl->sequence + 1);
|
||||
|
||||
/* Write sequence before updating other fields. */
|
||||
smp_wmb();
|
||||
@ -42,7 +42,7 @@ static inline void seqlock_write_end(QemuSeqLock *sl)
|
||||
/* Write other fields before finalizing sequence. */
|
||||
smp_wmb();
|
||||
|
||||
++sl->sequence;
|
||||
atomic_set(&sl->sequence, sl->sequence + 1);
|
||||
}
|
||||
|
||||
static inline unsigned seqlock_read_begin(QemuSeqLock *sl)
|
||||
|
@ -92,6 +92,7 @@ struct CharDriverState {
|
||||
int explicit_be_open;
|
||||
int avail_connections;
|
||||
int is_mux;
|
||||
int mux_idx;
|
||||
guint fd_in_tag;
|
||||
QemuOpts *opts;
|
||||
bool replay;
|
||||
|
@ -7476,13 +7476,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
break;
|
||||
}
|
||||
|
||||
cpu_list_lock();
|
||||
|
||||
if (CPU_NEXT(first_cpu)) {
|
||||
TaskState *ts;
|
||||
|
||||
cpu_list_lock();
|
||||
/* Remove the CPU from the list. */
|
||||
QTAILQ_REMOVE(&cpus, cpu, node);
|
||||
|
||||
cpu_list_unlock();
|
||||
|
||||
ts = cpu->opaque;
|
||||
if (ts->child_tidptr) {
|
||||
put_user_u32(0, ts->child_tidptr);
|
||||
@ -7495,6 +7498,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
rcu_unregister_thread();
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
cpu_list_unlock();
|
||||
#ifdef TARGET_GPROF
|
||||
_mcleanup();
|
||||
#endif
|
||||
|
@ -81,12 +81,6 @@
|
||||
#include "qemu/cutils.h"
|
||||
#include "qapi/qmp/dispatch.h"
|
||||
|
||||
/* for hmp_info_irq/pic */
|
||||
#if defined(TARGET_SPARC)
|
||||
#include "hw/sparc/sun4m.h"
|
||||
#endif
|
||||
#include "hw/lm32/lm32_pic.h"
|
||||
|
||||
#if defined(TARGET_S390X)
|
||||
#include "hw/s390x/storage-keys.h"
|
||||
#endif
|
||||
|
24
qemu-char.c
24
qemu-char.c
@ -165,6 +165,7 @@ CharDriverState *qemu_chr_alloc(ChardevCommon *backend, Error **errp)
|
||||
CharDriverState *chr = g_malloc0(sizeof(CharDriverState));
|
||||
qemu_mutex_init(&chr->chr_write_lock);
|
||||
|
||||
chr->mux_idx = -1;
|
||||
if (backend->has_logfile) {
|
||||
int flags = O_WRONLY | O_CREAT;
|
||||
if (backend->has_logappend &&
|
||||
@ -468,7 +469,7 @@ void qemu_chr_add_handlers_full(CharDriverState *s,
|
||||
s->chr_read = fd_read;
|
||||
s->chr_event = fd_event;
|
||||
s->handler_opaque = opaque;
|
||||
if (fe_open && s->chr_update_read_handler) {
|
||||
if (s->chr_update_read_handler) {
|
||||
s->chr_update_read_handler(s, context);
|
||||
}
|
||||
|
||||
@ -738,17 +739,25 @@ static void mux_chr_update_read_handler(CharDriverState *chr,
|
||||
GMainContext *context)
|
||||
{
|
||||
MuxDriver *d = chr->opaque;
|
||||
int idx;
|
||||
|
||||
if (d->mux_cnt >= MAX_MUX) {
|
||||
fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
|
||||
return;
|
||||
}
|
||||
d->ext_opaque[d->mux_cnt] = chr->handler_opaque;
|
||||
d->chr_can_read[d->mux_cnt] = chr->chr_can_read;
|
||||
d->chr_read[d->mux_cnt] = chr->chr_read;
|
||||
d->chr_event[d->mux_cnt] = chr->chr_event;
|
||||
|
||||
if (chr->mux_idx == -1) {
|
||||
chr->mux_idx = d->mux_cnt++;
|
||||
}
|
||||
|
||||
idx = chr->mux_idx;
|
||||
d->ext_opaque[idx] = chr->handler_opaque;
|
||||
d->chr_can_read[idx] = chr->chr_can_read;
|
||||
d->chr_read[idx] = chr->chr_read;
|
||||
d->chr_event[idx] = chr->chr_event;
|
||||
|
||||
/* Fix up the real driver with mux routines */
|
||||
if (d->mux_cnt == 0) {
|
||||
if (d->mux_cnt == 1) {
|
||||
qemu_chr_add_handlers_full(d->drv, mux_chr_can_read,
|
||||
mux_chr_read,
|
||||
mux_chr_event,
|
||||
@ -757,8 +766,7 @@ static void mux_chr_update_read_handler(CharDriverState *chr,
|
||||
if (d->focus != -1) {
|
||||
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
|
||||
}
|
||||
d->focus = d->mux_cnt;
|
||||
d->mux_cnt++;
|
||||
d->focus = idx;
|
||||
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
|
||||
}
|
||||
|
||||
|
352
qemu-doc.texi
352
qemu-doc.texi
@ -32,11 +32,10 @@
|
||||
|
||||
@menu
|
||||
* Introduction::
|
||||
* Installation::
|
||||
* QEMU PC System emulator::
|
||||
* QEMU System emulator for non PC targets::
|
||||
* QEMU User space emulator::
|
||||
* compilation:: Compilation from the sources
|
||||
* Implementation notes::
|
||||
* License::
|
||||
* Index::
|
||||
@end menu
|
||||
@ -57,98 +56,69 @@
|
||||
QEMU is a FAST! processor emulator using dynamic translation to
|
||||
achieve good emulation speed.
|
||||
|
||||
@cindex operating modes
|
||||
QEMU has two operating modes:
|
||||
|
||||
@itemize
|
||||
@cindex operating modes
|
||||
|
||||
@item
|
||||
@cindex system emulation
|
||||
Full system emulation. In this mode, QEMU emulates a full system (for
|
||||
@item Full system emulation. In this mode, QEMU emulates a full system (for
|
||||
example a PC), including one or several processors and various
|
||||
peripherals. It can be used to launch different Operating Systems
|
||||
without rebooting the PC or to debug system code.
|
||||
|
||||
@item
|
||||
@cindex user mode emulation
|
||||
User mode emulation. In this mode, QEMU can launch
|
||||
@item User mode emulation. In this mode, QEMU can launch
|
||||
processes compiled for one CPU on another CPU. It can be used to
|
||||
launch the Wine Windows API emulator (@url{http://www.winehq.org}) or
|
||||
to ease cross-compilation and cross-debugging.
|
||||
|
||||
@end itemize
|
||||
|
||||
QEMU can run without a host kernel driver and yet gives acceptable
|
||||
performance.
|
||||
QEMU has the following features:
|
||||
|
||||
For system emulation, the following hardware targets are supported:
|
||||
@itemize
|
||||
@cindex emulated target systems
|
||||
@cindex supported target systems
|
||||
@item PC (x86 or x86_64 processor)
|
||||
@item ISA PC (old style PC without PCI bus)
|
||||
@item PREP (PowerPC processor)
|
||||
@item G3 Beige PowerMac (PowerPC processor)
|
||||
@item Mac99 PowerMac (PowerPC processor, in progress)
|
||||
@item Sun4m/Sun4c/Sun4d (32-bit Sparc processor)
|
||||
@item Sun4u/Sun4v (64-bit Sparc processor, in progress)
|
||||
@item Malta board (32-bit and 64-bit MIPS processors)
|
||||
@item MIPS Magnum (64-bit MIPS processor)
|
||||
@item ARM Integrator/CP (ARM)
|
||||
@item ARM Versatile baseboard (ARM)
|
||||
@item ARM RealView Emulation/Platform baseboard (ARM)
|
||||
@item Spitz, Akita, Borzoi, Terrier and Tosa PDAs (PXA270 processor)
|
||||
@item Luminary Micro LM3S811EVB (ARM Cortex-M3)
|
||||
@item Luminary Micro LM3S6965EVB (ARM Cortex-M3)
|
||||
@item Freescale MCF5208EVB (ColdFire V2).
|
||||
@item Arnewsh MCF5206 evaluation board (ColdFire V2).
|
||||
@item Palm Tungsten|E PDA (OMAP310 processor)
|
||||
@item N800 and N810 tablets (OMAP2420 processor)
|
||||
@item MusicPal (MV88W8618 ARM processor)
|
||||
@item Gumstix "Connex" and "Verdex" motherboards (PXA255/270).
|
||||
@item Siemens SX1 smartphone (OMAP310 processor)
|
||||
@item AXIS-Devboard88 (CRISv32 ETRAX-FS).
|
||||
@item Petalogix Spartan 3aDSP1800 MMU ref design (MicroBlaze).
|
||||
@item Avnet LX60/LX110/LX200 boards (Xtensa)
|
||||
@item QEMU can run without a host kernel driver and yet gives acceptable
|
||||
performance. It uses dynamic translation to native code for reasonable speed,
|
||||
with support for self-modifying code and precise exceptions.
|
||||
|
||||
@item It is portable to several operating systems (GNU/Linux, *BSD, Mac OS X,
|
||||
Windows) and architectures.
|
||||
|
||||
@item It performs accurate software emulation of the FPU.
|
||||
@end itemize
|
||||
|
||||
@cindex supported user mode targets
|
||||
For user emulation, x86 (32 and 64 bit), PowerPC (32 and 64 bit),
|
||||
ARM, MIPS (32 bit only), Sparc (32 and 64 bit),
|
||||
Alpha, ColdFire(m68k), CRISv32 and MicroBlaze CPUs are supported.
|
||||
QEMU user mode emulation has the following features:
|
||||
@itemize
|
||||
@item Generic Linux system call converter, including most ioctls.
|
||||
|
||||
@node Installation
|
||||
@chapter Installation
|
||||
@item clone() emulation using native CPU clone() to use Linux scheduler for threads.
|
||||
|
||||
If you want to compile QEMU yourself, see @ref{compilation}.
|
||||
@item Accurate signal handling by remapping host signals to target signals.
|
||||
@end itemize
|
||||
|
||||
@menu
|
||||
* install_linux:: Linux
|
||||
* install_windows:: Windows
|
||||
* install_mac:: Macintosh
|
||||
@end menu
|
||||
QEMU full system emulation has the following features:
|
||||
@itemize
|
||||
@item
|
||||
QEMU uses a full software MMU for maximum portability.
|
||||
|
||||
@node install_linux
|
||||
@section Linux
|
||||
@cindex installation (Linux)
|
||||
@item
|
||||
QEMU can optionally use an in-kernel accelerator, like kvm. The accelerators
|
||||
execute most of the guest code natively, while
|
||||
continuing to emulate the rest of the machine.
|
||||
|
||||
If a precompiled package is available for your distribution - you just
|
||||
have to install it. Otherwise, see @ref{compilation}.
|
||||
@item
|
||||
Various hardware devices can be emulated and in some cases, host
|
||||
devices (e.g. serial and parallel ports, USB, drives) can be used
|
||||
transparently by the guest Operating System. Host device passthrough
|
||||
can be used for talking to external physical peripherals (e.g. a
|
||||
webcam, modem or tape drive).
|
||||
|
||||
@node install_windows
|
||||
@section Windows
|
||||
@cindex installation (Windows)
|
||||
@item
|
||||
Symmetric multiprocessing (SMP) support. Currently, an in-kernel
|
||||
accelerator is required to use more than one host CPU for emulation.
|
||||
|
||||
Download the experimental binary installer at
|
||||
@url{http://www.free.oszoo.org/@/download.html}.
|
||||
TODO (no longer available)
|
||||
@end itemize
|
||||
|
||||
@node install_mac
|
||||
@section Mac OS X
|
||||
|
||||
Download the experimental binary installer at
|
||||
@url{http://www.free.oszoo.org/@/download.html}.
|
||||
TODO (no longer available)
|
||||
|
||||
@node QEMU PC System emulator
|
||||
@chapter QEMU PC System emulator
|
||||
@ -2660,6 +2630,7 @@ so should only be used with trusted guest OS.
|
||||
|
||||
@menu
|
||||
* Supported Operating Systems ::
|
||||
* Features::
|
||||
* Linux User space emulator::
|
||||
* BSD User space emulator ::
|
||||
@end menu
|
||||
@ -2676,6 +2647,39 @@ Linux (referred as qemu-linux-user)
|
||||
BSD (referred as qemu-bsd-user)
|
||||
@end itemize
|
||||
|
||||
@node Features
|
||||
@section Features
|
||||
|
||||
QEMU user space emulation has the following notable features:
|
||||
|
||||
@table @strong
|
||||
@item System call translation:
|
||||
QEMU includes a generic system call translator. This means that
|
||||
the parameters of the system calls can be converted to fix
|
||||
endianness and 32/64-bit mismatches between hosts and targets.
|
||||
IOCTLs can be converted too.
|
||||
|
||||
@item POSIX signal handling:
|
||||
QEMU can redirect to the running program all signals coming from
|
||||
the host (such as @code{SIGALRM}), as well as synthesize signals from
|
||||
virtual CPU exceptions (for example @code{SIGFPE} when the program
|
||||
executes a division by zero).
|
||||
|
||||
QEMU relies on the host kernel to emulate most signal system
|
||||
calls, for example to emulate the signal mask. On Linux, QEMU
|
||||
supports both normal and real-time signals.
|
||||
|
||||
@item Threading:
|
||||
On Linux, QEMU can emulate the @code{clone} syscall and create a real
|
||||
host thread (with a separate virtual CPU) for each emulated thread.
|
||||
Note that not all targets currently emulate atomic operations correctly.
|
||||
x86 and ARM use a global lock in order to preserve their semantics.
|
||||
@end table
|
||||
|
||||
QEMU was conceived so that ultimately it can emulate itself. Although
|
||||
it is not very useful, it is an important test to show the power of the
|
||||
emulator.
|
||||
|
||||
@node Linux User space emulator
|
||||
@section Linux User space emulator
|
||||
|
||||
@ -2945,220 +2949,8 @@ Act as if the host page size was 'pagesize' bytes
|
||||
Run the emulation in single step mode.
|
||||
@end table
|
||||
|
||||
@node compilation
|
||||
@chapter Compilation from the sources
|
||||
|
||||
@menu
|
||||
* Linux/Unix::
|
||||
* Windows::
|
||||
* Cross compilation for Windows with Linux::
|
||||
* Mac OS X::
|
||||
* Make targets::
|
||||
@end menu
|
||||
|
||||
@node Linux/Unix
|
||||
@section Linux/Unix
|
||||
|
||||
@subsection Compilation
|
||||
|
||||
First you must decompress the sources:
|
||||
@example
|
||||
cd /tmp
|
||||
tar zxvf qemu-x.y.z.tar.gz
|
||||
cd qemu-x.y.z
|
||||
@end example
|
||||
|
||||
Then you configure QEMU and build it (usually no options are needed):
|
||||
@example
|
||||
./configure
|
||||
make
|
||||
@end example
|
||||
|
||||
Then type as root user:
|
||||
@example
|
||||
make install
|
||||
@end example
|
||||
to install QEMU in @file{/usr/local}.
|
||||
|
||||
@node Windows
|
||||
@section Windows
|
||||
|
||||
@itemize
|
||||
@item Install the current versions of MSYS and MinGW from
|
||||
@url{http://www.mingw.org/}. You can find detailed installation
|
||||
instructions in the download section and the FAQ.
|
||||
|
||||
@item Download
|
||||
the MinGW development library of SDL 1.2.x
|
||||
(@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from
|
||||
@url{http://www.libsdl.org}. Unpack it in a temporary place and
|
||||
edit the @file{sdl-config} script so that it gives the
|
||||
correct SDL directory when invoked.
|
||||
|
||||
@item Install the MinGW version of zlib and make sure
|
||||
@file{zlib.h} and @file{libz.dll.a} are in
|
||||
MinGW's default header and linker search paths.
|
||||
|
||||
@item Extract the current version of QEMU.
|
||||
|
||||
@item Start the MSYS shell (file @file{msys.bat}).
|
||||
|
||||
@item Change to the QEMU directory. Launch @file{./configure} and
|
||||
@file{make}. If you have problems using SDL, verify that
|
||||
@file{sdl-config} can be launched from the MSYS command line.
|
||||
|
||||
@item You can install QEMU in @file{Program Files/QEMU} by typing
|
||||
@file{make install}. Don't forget to copy @file{SDL.dll} in
|
||||
@file{Program Files/QEMU}.
|
||||
|
||||
@end itemize
|
||||
|
||||
@node Cross compilation for Windows with Linux
|
||||
@section Cross compilation for Windows with Linux
|
||||
|
||||
@itemize
|
||||
@item
|
||||
Install the MinGW cross compilation tools available at
|
||||
@url{http://www.mingw.org/}.
|
||||
|
||||
@item Download
|
||||
the MinGW development library of SDL 1.2.x
|
||||
(@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from
|
||||
@url{http://www.libsdl.org}. Unpack it in a temporary place and
|
||||
edit the @file{sdl-config} script so that it gives the
|
||||
correct SDL directory when invoked. Set up the @code{PATH} environment
|
||||
variable so that @file{sdl-config} can be launched by
|
||||
the QEMU configuration script.
|
||||
|
||||
@item Install the MinGW version of zlib and make sure
|
||||
@file{zlib.h} and @file{libz.dll.a} are in
|
||||
MinGW's default header and linker search paths.
|
||||
|
||||
@item
|
||||
Configure QEMU for Windows cross compilation:
|
||||
@example
|
||||
PATH=/usr/i686-pc-mingw32/sys-root/mingw/bin:$PATH ./configure --cross-prefix='i686-pc-mingw32-'
|
||||
@end example
|
||||
The example assumes @file{sdl-config} is installed under @file{/usr/i686-pc-mingw32/sys-root/mingw/bin} and
|
||||
MinGW cross compilation tools have names like @file{i686-pc-mingw32-gcc} and @file{i686-pc-mingw32-strip}.
|
||||
We set the @code{PATH} environment variable to ensure the MinGW version of @file{sdl-config} is used and
|
||||
use --cross-prefix to specify the name of the cross compiler.
|
||||
You can also use --prefix to set the Win32 install path which defaults to @file{c:/Program Files/QEMU}.
|
||||
|
||||
Under Fedora Linux, you can run:
|
||||
@example
|
||||
yum -y install mingw32-gcc mingw32-SDL mingw32-zlib
|
||||
@end example
|
||||
to get a suitable cross compilation environment.
|
||||
|
||||
@item You can install QEMU in the installation directory by typing
|
||||
@code{make install}. Don't forget to copy @file{SDL.dll} and @file{zlib1.dll} into the
|
||||
installation directory.
|
||||
|
||||
@end itemize
|
||||
|
||||
Wine can be used to launch the resulting qemu-system-i386.exe
|
||||
and all other qemu-system-@var{target}.exe compiled for Win32.
|
||||
|
||||
@node Mac OS X
|
||||
@section Mac OS X
|
||||
|
||||
System Requirements:
|
||||
@itemize
|
||||
@item Mac OS 10.5 or higher
|
||||
@item The clang compiler shipped with Xcode 4.2 or higher,
|
||||
or GCC 4.3 or higher
|
||||
@end itemize
|
||||
|
||||
Additional Requirements (install in order):
|
||||
@enumerate
|
||||
@item libffi: @uref{https://sourceware.org/libffi/}
|
||||
@item gettext: @uref{http://www.gnu.org/software/gettext/}
|
||||
@item glib: @uref{http://ftp.gnome.org/pub/GNOME/sources/glib/}
|
||||
@item pkg-config: @uref{http://www.freedesktop.org/wiki/Software/pkg-config/}
|
||||
@item autoconf: @uref{http://www.gnu.org/software/autoconf/autoconf.html}
|
||||
@item automake: @uref{http://www.gnu.org/software/automake/}
|
||||
@item pixman: @uref{http://www.pixman.org/}
|
||||
@end enumerate
|
||||
|
||||
* You may find it easiest to get these from a third-party packager
|
||||
such as Homebrew, Macports, or Fink.
|
||||
|
||||
After downloading the QEMU source code, double-click it to expand it.
|
||||
|
||||
Then configure and make QEMU:
|
||||
@example
|
||||
./configure
|
||||
make
|
||||
@end example
|
||||
|
||||
If you have a recent version of Mac OS X (OSX 10.7 or better
|
||||
with Xcode 4.2 or better) we recommend building QEMU with the
|
||||
default compiler provided by Apple, for your version of Mac OS X
|
||||
(which will be 'clang'). The configure script will
|
||||
automatically pick this.
|
||||
|
||||
Note: If after the configure step you see a message like this:
|
||||
@example
|
||||
ERROR: Your compiler does not support the __thread specifier for
|
||||
Thread-Local Storage (TLS). Please upgrade to a version that does.
|
||||
@end example
|
||||
you may have to build your own version of gcc from source. Expect that to take
|
||||
several hours. More information can be found here:
|
||||
@uref{https://gcc.gnu.org/install/} @*
|
||||
|
||||
These are some of the third party binaries of gcc available for download:
|
||||
@itemize
|
||||
@item Homebrew: @uref{http://brew.sh/}
|
||||
@item @uref{https://www.litebeam.net/gcc/gcc_472.pkg}
|
||||
@item @uref{http://www.macports.org/ports.php?by=name&substr=gcc}
|
||||
@end itemize
|
||||
|
||||
You can have several versions of GCC on your system. To specify a certain version,
|
||||
use the --cc and --cxx options.
|
||||
@example
|
||||
./configure --cxx=<path of your c++ compiler> --cc=<path of your c compiler> <other options>
|
||||
@end example
|
||||
|
||||
@node Make targets
|
||||
@section Make targets
|
||||
|
||||
@table @code
|
||||
|
||||
@item make
|
||||
@item make all
|
||||
Make everything which is typically needed.
|
||||
|
||||
@item install
|
||||
TODO
|
||||
|
||||
@item install-doc
|
||||
TODO
|
||||
|
||||
@item make clean
|
||||
Remove most files which were built during make.
|
||||
|
||||
@item make distclean
|
||||
Remove everything which was built during make.
|
||||
|
||||
@item make dvi
|
||||
@item make html
|
||||
@item make info
|
||||
@item make pdf
|
||||
Create documentation in dvi, html, info or pdf format.
|
||||
|
||||
@item make cscope
|
||||
TODO
|
||||
|
||||
@item make defconfig
|
||||
(Re-)create some build configuration files.
|
||||
User made changes will be overwritten.
|
||||
|
||||
@item tar
|
||||
@item tarbin
|
||||
TODO
|
||||
|
||||
@end table
|
||||
@include qemu-tech.texi
|
||||
|
||||
@node License
|
||||
@appendix License
|
||||
|
@ -901,6 +901,14 @@ int main(int argc, char **argv)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (dev_offset >= fd_size) {
|
||||
error_report("Offset (%lld) has to be smaller than the image size "
|
||||
"(%lld)",
|
||||
(long long int)dev_offset, (long long int)fd_size);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
fd_size -= dev_offset;
|
||||
|
||||
if (partition != -1) {
|
||||
ret = find_partition(blk, partition, &dev_offset, &fd_size);
|
||||
if (ret < 0) {
|
||||
|
573
qemu-tech.texi
573
qemu-tech.texi
@ -1,146 +1,27 @@
|
||||
\input texinfo @c -*- texinfo -*-
|
||||
@c %**start of header
|
||||
@setfilename qemu-tech.info
|
||||
|
||||
@documentlanguage en
|
||||
@documentencoding UTF-8
|
||||
|
||||
@settitle QEMU Internals
|
||||
@exampleindent 0
|
||||
@paragraphindent 0
|
||||
@c %**end of header
|
||||
|
||||
@ifinfo
|
||||
@direntry
|
||||
* QEMU Internals: (qemu-tech). The QEMU Emulator Internals.
|
||||
@end direntry
|
||||
@end ifinfo
|
||||
|
||||
@iftex
|
||||
@titlepage
|
||||
@sp 7
|
||||
@center @titlefont{QEMU Internals}
|
||||
@sp 3
|
||||
@end titlepage
|
||||
@end iftex
|
||||
|
||||
@ifnottex
|
||||
@node Top
|
||||
@top
|
||||
@node Implementation notes
|
||||
@appendix Implementation notes
|
||||
|
||||
@menu
|
||||
* Introduction::
|
||||
* QEMU Internals::
|
||||
* Regression Tests::
|
||||
* Index::
|
||||
* CPU emulation::
|
||||
* Translator Internals::
|
||||
* QEMU compared to other emulators::
|
||||
* Bibliography::
|
||||
@end menu
|
||||
@end ifnottex
|
||||
|
||||
@contents
|
||||
|
||||
@node Introduction
|
||||
@chapter Introduction
|
||||
@node CPU emulation
|
||||
@section CPU emulation
|
||||
|
||||
@menu
|
||||
* intro_features:: Features
|
||||
* intro_x86_emulation:: x86 and x86-64 emulation
|
||||
* intro_arm_emulation:: ARM emulation
|
||||
* intro_mips_emulation:: MIPS emulation
|
||||
* intro_ppc_emulation:: PowerPC emulation
|
||||
* intro_sparc_emulation:: Sparc32 and Sparc64 emulation
|
||||
* intro_xtensa_emulation:: Xtensa emulation
|
||||
* intro_other_emulation:: Other CPU emulation
|
||||
* x86:: x86 and x86-64 emulation
|
||||
* ARM:: ARM emulation
|
||||
* MIPS:: MIPS emulation
|
||||
* PPC:: PowerPC emulation
|
||||
* SPARC:: Sparc32 and Sparc64 emulation
|
||||
* Xtensa:: Xtensa emulation
|
||||
@end menu
|
||||
|
||||
@node intro_features
|
||||
@section Features
|
||||
|
||||
QEMU is a FAST! processor emulator using a portable dynamic
|
||||
translator.
|
||||
|
||||
QEMU has two operating modes:
|
||||
|
||||
@itemize @minus
|
||||
|
||||
@item
|
||||
Full system emulation. In this mode (full platform virtualization),
|
||||
QEMU emulates a full system (usually a PC), including a processor and
|
||||
various peripherals. It can be used to launch several different
|
||||
Operating Systems at once without rebooting the host machine or to
|
||||
debug system code.
|
||||
|
||||
@item
|
||||
User mode emulation. In this mode (application level virtualization),
|
||||
QEMU can launch processes compiled for one CPU on another CPU, however
|
||||
the Operating Systems must match. This can be used for example to ease
|
||||
cross-compilation and cross-debugging.
|
||||
@end itemize
|
||||
|
||||
As QEMU requires no host kernel driver to run, it is very safe and
|
||||
easy to use.
|
||||
|
||||
QEMU generic features:
|
||||
|
||||
@itemize
|
||||
|
||||
@item User space only or full system emulation.
|
||||
|
||||
@item Using dynamic translation to native code for reasonable speed.
|
||||
|
||||
@item
|
||||
Working on x86, x86_64 and PowerPC32/64 hosts. Being tested on ARM,
|
||||
S390x, Sparc32 and Sparc64.
|
||||
|
||||
@item Self-modifying code support.
|
||||
|
||||
@item Precise exceptions support.
|
||||
|
||||
@item
|
||||
Floating point library supporting both full software emulation and
|
||||
native host FPU instructions.
|
||||
|
||||
@end itemize
|
||||
|
||||
QEMU user mode emulation features:
|
||||
@itemize
|
||||
@item Generic Linux system call converter, including most ioctls.
|
||||
|
||||
@item clone() emulation using native CPU clone() to use Linux scheduler for threads.
|
||||
|
||||
@item Accurate signal handling by remapping host signals to target signals.
|
||||
@end itemize
|
||||
|
||||
Linux user emulator (Linux host only) can be used to launch the Wine
|
||||
Windows API emulator (@url{http://www.winehq.org}). A BSD user emulator for BSD
|
||||
hosts is under development. It would also be possible to develop a
|
||||
similar user emulator for Solaris.
|
||||
|
||||
QEMU full system emulation features:
|
||||
@itemize
|
||||
@item
|
||||
QEMU uses a full software MMU for maximum portability.
|
||||
|
||||
@item
|
||||
QEMU can optionally use an in-kernel accelerator, like kvm. The accelerators
|
||||
execute some of the guest code natively, while
|
||||
continuing to emulate the rest of the machine.
|
||||
|
||||
@item
|
||||
Various hardware devices can be emulated and in some cases, host
|
||||
devices (e.g. serial and parallel ports, USB, drives) can be used
|
||||
transparently by the guest Operating System. Host device passthrough
|
||||
can be used for talking to external physical peripherals (e.g. a
|
||||
webcam, modem or tape drive).
|
||||
|
||||
@item
|
||||
Symmetric multiprocessing (SMP) even on a host with a single CPU. On a
|
||||
SMP host system, QEMU can use only one CPU fully due to difficulty in
|
||||
implementing atomic memory accesses efficiently.
|
||||
|
||||
@end itemize
|
||||
|
||||
@node intro_x86_emulation
|
||||
@section x86 and x86-64 emulation
|
||||
@node x86
|
||||
@subsection x86 and x86-64 emulation
|
||||
|
||||
QEMU x86 target features:
|
||||
|
||||
@ -174,8 +55,8 @@ normal use.
|
||||
|
||||
@end itemize
|
||||
|
||||
@node intro_arm_emulation
|
||||
@section ARM emulation
|
||||
@node ARM
|
||||
@subsection ARM emulation
|
||||
|
||||
@itemize
|
||||
|
||||
@ -187,8 +68,8 @@ normal use.
|
||||
|
||||
@end itemize
|
||||
|
||||
@node intro_mips_emulation
|
||||
@section MIPS emulation
|
||||
@node MIPS
|
||||
@subsection MIPS emulation
|
||||
|
||||
@itemize
|
||||
|
||||
@ -214,8 +95,8 @@ Current QEMU limitations:
|
||||
|
||||
@end itemize
|
||||
|
||||
@node intro_ppc_emulation
|
||||
@section PowerPC emulation
|
||||
@node PPC
|
||||
@subsection PowerPC emulation
|
||||
|
||||
@itemize
|
||||
|
||||
@ -226,8 +107,8 @@ FPU and MMU.
|
||||
|
||||
@end itemize
|
||||
|
||||
@node intro_sparc_emulation
|
||||
@section Sparc32 and Sparc64 emulation
|
||||
@node SPARC
|
||||
@subsection Sparc32 and Sparc64 emulation
|
||||
|
||||
@itemize
|
||||
|
||||
@ -254,8 +135,8 @@ Current QEMU limitations:
|
||||
|
||||
@end itemize
|
||||
|
||||
@node intro_xtensa_emulation
|
||||
@section Xtensa emulation
|
||||
@node Xtensa
|
||||
@subsection Xtensa emulation
|
||||
|
||||
@itemize
|
||||
|
||||
@ -279,42 +160,108 @@ may be created from overlay with minimal amount of hand-written code.
|
||||
|
||||
@end itemize
|
||||
|
||||
@node intro_other_emulation
|
||||
@section Other CPU emulation
|
||||
@node Translator Internals
|
||||
@section Translator Internals
|
||||
|
||||
In addition to the above, QEMU supports emulation of other CPUs with
|
||||
varying levels of success. These are:
|
||||
QEMU is a dynamic translator. When it first encounters a piece of code,
|
||||
it converts it to the host instruction set. Usually dynamic translators
|
||||
are very complicated and highly CPU dependent. QEMU uses some tricks
|
||||
which make it relatively easily portable and simple while achieving good
|
||||
performances.
|
||||
|
||||
@itemize
|
||||
QEMU's dynamic translation backend is called TCG, for "Tiny Code
|
||||
Generator". For more information, please take a look at @code{tcg/README}.
|
||||
|
||||
@item
|
||||
Alpha
|
||||
@item
|
||||
CRIS
|
||||
@item
|
||||
M68k
|
||||
@item
|
||||
SH4
|
||||
@end itemize
|
||||
Some notable features of QEMU's dynamic translator are:
|
||||
|
||||
@node QEMU Internals
|
||||
@chapter QEMU Internals
|
||||
@table @strong
|
||||
|
||||
@menu
|
||||
* QEMU compared to other emulators::
|
||||
* Portable dynamic translation::
|
||||
* Condition code optimisations::
|
||||
* CPU state optimisations::
|
||||
* Translation cache::
|
||||
* Direct block chaining::
|
||||
* Self-modifying code and translated code invalidation::
|
||||
* Exception support::
|
||||
* MMU emulation::
|
||||
* Device emulation::
|
||||
* Hardware interrupts::
|
||||
* User emulation specific details::
|
||||
* Bibliography::
|
||||
@end menu
|
||||
@item CPU state optimisations:
|
||||
The target CPUs have many internal states which change the way it
|
||||
evaluates instructions. In order to achieve a good speed, the
|
||||
translation phase considers that some state information of the virtual
|
||||
CPU cannot change in it. The state is recorded in the Translation
|
||||
Block (TB). If the state changes (e.g. privilege level), a new TB will
|
||||
be generated and the previous TB won't be used anymore until the state
|
||||
matches the state recorded in the previous TB. The same idea can be applied
|
||||
to other aspects of the CPU state. For example, on x86, if the SS,
|
||||
DS and ES segments have a zero base, then the translator does not even
|
||||
generate an addition for the segment base.
|
||||
|
||||
@item Direct block chaining:
|
||||
After each translated basic block is executed, QEMU uses the simulated
|
||||
Program Counter (PC) and other cpu state information (such as the CS
|
||||
segment base value) to find the next basic block.
|
||||
|
||||
In order to accelerate the most common cases where the new simulated PC
|
||||
is known, QEMU can patch a basic block so that it jumps directly to the
|
||||
next one.
|
||||
|
||||
The most portable code uses an indirect jump. An indirect jump makes
|
||||
it easier to make the jump target modification atomic. On some host
|
||||
architectures (such as x86 or PowerPC), the @code{JUMP} opcode is
|
||||
directly patched so that the block chaining has no overhead.
|
||||
|
||||
@item Self-modifying code and translated code invalidation:
|
||||
Self-modifying code is a special challenge in x86 emulation because no
|
||||
instruction cache invalidation is signaled by the application when code
|
||||
is modified.
|
||||
|
||||
User-mode emulation marks a host page as write-protected (if it is
|
||||
not already read-only) every time translated code is generated for a
|
||||
basic block. Then, if a write access is done to the page, Linux raises
|
||||
a SEGV signal. QEMU then invalidates all the translated code in the page
|
||||
and enables write accesses to the page. For system emulation, write
|
||||
protection is achieved through the software MMU.
|
||||
|
||||
Correct translated code invalidation is done efficiently by maintaining
|
||||
a linked list of every translated block contained in a given page. Other
|
||||
linked lists are also maintained to undo direct block chaining.
|
||||
|
||||
On RISC targets, correctly written software uses memory barriers and
|
||||
cache flushes, so some of the protection above would not be
|
||||
necessary. However, QEMU still requires that the generated code always
|
||||
matches the target instructions in memory in order to handle
|
||||
exceptions correctly.
|
||||
|
||||
@item Exception support:
|
||||
longjmp() is used when an exception such as division by zero is
|
||||
encountered.
|
||||
|
||||
The host SIGSEGV and SIGBUS signal handlers are used to get invalid
|
||||
memory accesses. QEMU keeps a map from host program counter to
|
||||
target program counter, and looks up where the exception happened
|
||||
based on the host program counter at the exception point.
|
||||
|
||||
On some targets, some bits of the virtual CPU's state are not flushed to the
|
||||
memory until the end of the translation block. This is done for internal
|
||||
emulation state that is rarely accessed directly by the program and/or changes
|
||||
very often throughout the execution of a translation block---this includes
|
||||
condition codes on x86, delay slots on SPARC, conditional execution on
|
||||
ARM, and so on. This state is stored for each target instruction, and
|
||||
looked up on exceptions.
|
||||
|
||||
@item MMU emulation:
|
||||
For system emulation QEMU uses a software MMU. In that mode, the MMU
|
||||
virtual to physical address translation is done at every memory
|
||||
access.
|
||||
|
||||
QEMU uses an address translation cache (TLB) to speed up the translation.
|
||||
In order to avoid flushing the translated code each time the MMU
|
||||
mappings change, all caches in QEMU are physically indexed. This
|
||||
means that each basic block is indexed with its physical address.
|
||||
|
||||
In order to avoid invalidating the basic block chain when MMU mappings
|
||||
change, chaining is only performed when the destination of the jump
|
||||
shares a page with the basic block that is performing the jump.
|
||||
|
||||
The MMU can also distinguish RAM and ROM memory areas from MMIO memory
|
||||
areas. Access is faster for RAM and ROM because the translation cache also
|
||||
hosts the offset between guest address and host memory. Accessing MMIO
|
||||
memory areas instead calls out to C code for device emulation.
|
||||
Finally, the MMU helps tracking dirty pages and pages pointed to by
|
||||
translation blocks.
|
||||
@end table
|
||||
|
||||
@node QEMU compared to other emulators
|
||||
@section QEMU compared to other emulators
|
||||
@ -367,240 +314,6 @@ VirtualBox [9], Xen [10] and KVM [11] are based on QEMU. QEMU-SystemC
|
||||
[12] uses QEMU to simulate a system where some hardware devices are
|
||||
developed in SystemC.
|
||||
|
||||
@node Portable dynamic translation
|
||||
@section Portable dynamic translation
|
||||
|
||||
QEMU is a dynamic translator. When it first encounters a piece of code,
|
||||
it converts it to the host instruction set. Usually dynamic translators
|
||||
are very complicated and highly CPU dependent. QEMU uses some tricks
|
||||
which make it relatively easily portable and simple while achieving good
|
||||
performances.
|
||||
|
||||
After the release of version 0.9.1, QEMU switched to a new method of
|
||||
generating code, Tiny Code Generator or TCG. TCG relaxes the
|
||||
dependency on the exact version of the compiler used. The basic idea
|
||||
is to split every target instruction into a couple of RISC-like TCG
|
||||
ops (see @code{target-i386/translate.c}). Some optimizations can be
|
||||
performed at this stage, including liveness analysis and trivial
|
||||
constant expression evaluation. TCG ops are then implemented in the
|
||||
host CPU back end, also known as TCG target (see
|
||||
@code{tcg/i386/tcg-target.inc.c}). For more information, please take a
|
||||
look at @code{tcg/README}.
|
||||
|
||||
@node Condition code optimisations
|
||||
@section Condition code optimisations
|
||||
|
||||
Lazy evaluation of CPU condition codes (@code{EFLAGS} register on x86)
|
||||
is important for CPUs where every instruction sets the condition
|
||||
codes. It tends to be less important on conventional RISC systems
|
||||
where condition codes are only updated when explicitly requested. On
|
||||
Sparc64, costly update of both 32 and 64 bit condition codes can be
|
||||
avoided with lazy evaluation.
|
||||
|
||||
Instead of computing the condition codes after each x86 instruction,
|
||||
QEMU just stores one operand (called @code{CC_SRC}), the result
|
||||
(called @code{CC_DST}) and the type of operation (called
|
||||
@code{CC_OP}). When the condition codes are needed, the condition
|
||||
codes can be calculated using this information. In addition, an
|
||||
optimized calculation can be performed for some instruction types like
|
||||
conditional branches.
|
||||
|
||||
@code{CC_OP} is almost never explicitly set in the generated code
|
||||
because it is known at translation time.
|
||||
|
||||
The lazy condition code evaluation is used on x86, m68k, cris and
|
||||
Sparc. ARM uses a simplified variant for the N and Z flags.
|
||||
|
||||
@node CPU state optimisations
|
||||
@section CPU state optimisations
|
||||
|
||||
The target CPUs have many internal states which change the way it
|
||||
evaluates instructions. In order to achieve a good speed, the
|
||||
translation phase considers that some state information of the virtual
|
||||
CPU cannot change in it. The state is recorded in the Translation
|
||||
Block (TB). If the state changes (e.g. privilege level), a new TB will
|
||||
be generated and the previous TB won't be used anymore until the state
|
||||
matches the state recorded in the previous TB. For example, if the SS,
|
||||
DS and ES segments have a zero base, then the translator does not even
|
||||
generate an addition for the segment base.
|
||||
|
||||
[The FPU stack pointer register is not handled that way yet].
|
||||
|
||||
@node Translation cache
|
||||
@section Translation cache
|
||||
|
||||
A 32 MByte cache holds the most recently used translations. For
|
||||
simplicity, it is completely flushed when it is full. A translation unit
|
||||
contains just a single basic block (a block of x86 instructions
|
||||
terminated by a jump or by a virtual CPU state change which the
|
||||
translator cannot deduce statically).
|
||||
|
||||
@node Direct block chaining
|
||||
@section Direct block chaining
|
||||
|
||||
After each translated basic block is executed, QEMU uses the simulated
|
||||
Program Counter (PC) and other cpu state information (such as the CS
|
||||
segment base value) to find the next basic block.
|
||||
|
||||
In order to accelerate the most common cases where the new simulated PC
|
||||
is known, QEMU can patch a basic block so that it jumps directly to the
|
||||
next one.
|
||||
|
||||
The most portable code uses an indirect jump. An indirect jump makes
|
||||
it easier to make the jump target modification atomic. On some host
|
||||
architectures (such as x86 or PowerPC), the @code{JUMP} opcode is
|
||||
directly patched so that the block chaining has no overhead.
|
||||
|
||||
@node Self-modifying code and translated code invalidation
|
||||
@section Self-modifying code and translated code invalidation
|
||||
|
||||
Self-modifying code is a special challenge in x86 emulation because no
|
||||
instruction cache invalidation is signaled by the application when code
|
||||
is modified.
|
||||
|
||||
When translated code is generated for a basic block, the corresponding
|
||||
host page is write protected if it is not already read-only. Then, if
|
||||
a write access is done to the page, Linux raises a SEGV signal. QEMU
|
||||
then invalidates all the translated code in the page and enables write
|
||||
accesses to the page.
|
||||
|
||||
Correct translated code invalidation is done efficiently by maintaining
|
||||
a linked list of every translated block contained in a given page. Other
|
||||
linked lists are also maintained to undo direct block chaining.
|
||||
|
||||
On RISC targets, correctly written software uses memory barriers and
|
||||
cache flushes, so some of the protection above would not be
|
||||
necessary. However, QEMU still requires that the generated code always
|
||||
matches the target instructions in memory in order to handle
|
||||
exceptions correctly.
|
||||
|
||||
@node Exception support
|
||||
@section Exception support
|
||||
|
||||
longjmp() is used when an exception such as division by zero is
|
||||
encountered.
|
||||
|
||||
The host SIGSEGV and SIGBUS signal handlers are used to get invalid
|
||||
memory accesses. The simulated program counter is found by
|
||||
retranslating the corresponding basic block and by looking where the
|
||||
host program counter was at the exception point.
|
||||
|
||||
The virtual CPU cannot retrieve the exact @code{EFLAGS} register because
|
||||
in some cases it is not computed because of condition code
|
||||
optimisations. It is not a big concern because the emulated code can
|
||||
still be restarted in any cases.
|
||||
|
||||
@node MMU emulation
|
||||
@section MMU emulation
|
||||
|
||||
For system emulation QEMU supports a soft MMU. In that mode, the MMU
|
||||
virtual to physical address translation is done at every memory
|
||||
access. QEMU uses an address translation cache to speed up the
|
||||
translation.
|
||||
|
||||
In order to avoid flushing the translated code each time the MMU
|
||||
mappings change, QEMU uses a physically indexed translation cache. It
|
||||
means that each basic block is indexed with its physical address.
|
||||
|
||||
When MMU mappings change, only the chaining of the basic blocks is
|
||||
reset (i.e. a basic block can no longer jump directly to another one).
|
||||
|
||||
@node Device emulation
|
||||
@section Device emulation
|
||||
|
||||
Systems emulated by QEMU are organized by boards. At initialization
|
||||
phase, each board instantiates a number of CPUs, devices, RAM and
|
||||
ROM. Each device in turn can assign I/O ports or memory areas (for
|
||||
MMIO) to its handlers. When the emulation starts, an access to the
|
||||
ports or MMIO memory areas assigned to the device causes the
|
||||
corresponding handler to be called.
|
||||
|
||||
RAM and ROM are handled more optimally, only the offset to the host
|
||||
memory needs to be added to the guest address.
|
||||
|
||||
The video RAM of VGA and other display cards is special: it can be
|
||||
read or written directly like RAM, but write accesses cause the memory
|
||||
to be marked with VGA_DIRTY flag as well.
|
||||
|
||||
QEMU supports some device classes like serial and parallel ports, USB,
|
||||
drives and network devices, by providing APIs for easier connection to
|
||||
the generic, higher level implementations. The API hides the
|
||||
implementation details from the devices, like native device use or
|
||||
advanced block device formats like QCOW.
|
||||
|
||||
Usually the devices implement a reset method and register support for
|
||||
saving and loading of the device state. The devices can also use
|
||||
timers, especially together with the use of bottom halves (BHs).
|
||||
|
||||
@node Hardware interrupts
|
||||
@section Hardware interrupts
|
||||
|
||||
In order to be faster, QEMU does not check at every basic block if a
|
||||
hardware interrupt is pending. Instead, the user must asynchronously
|
||||
call a specific function to tell that an interrupt is pending. This
|
||||
function resets the chaining of the currently executing basic
|
||||
block. It ensures that the execution will return soon in the main loop
|
||||
of the CPU emulator. Then the main loop can test if the interrupt is
|
||||
pending and handle it.
|
||||
|
||||
@node User emulation specific details
|
||||
@section User emulation specific details
|
||||
|
||||
@subsection Linux system call translation
|
||||
|
||||
QEMU includes a generic system call translator for Linux. It means that
|
||||
the parameters of the system calls can be converted to fix the
|
||||
endianness and 32/64 bit issues. The IOCTLs are converted with a generic
|
||||
type description system (see @file{ioctls.h} and @file{thunk.c}).
|
||||
|
||||
QEMU supports host CPUs which have pages bigger than 4KB. It records all
|
||||
the mappings the process does and try to emulated the @code{mmap()}
|
||||
system calls in cases where the host @code{mmap()} call would fail
|
||||
because of bad page alignment.
|
||||
|
||||
@subsection Linux signals
|
||||
|
||||
Normal and real-time signals are queued along with their information
|
||||
(@code{siginfo_t}) as it is done in the Linux kernel. Then an interrupt
|
||||
request is done to the virtual CPU. When it is interrupted, one queued
|
||||
signal is handled by generating a stack frame in the virtual CPU as the
|
||||
Linux kernel does. The @code{sigreturn()} system call is emulated to return
|
||||
from the virtual signal handler.
|
||||
|
||||
Some signals (such as SIGALRM) directly come from the host. Other
|
||||
signals are synthesized from the virtual CPU exceptions such as SIGFPE
|
||||
when a division by zero is done (see @code{main.c:cpu_loop()}).
|
||||
|
||||
The blocked signal mask is still handled by the host Linux kernel so
|
||||
that most signal system calls can be redirected directly to the host
|
||||
Linux kernel. Only the @code{sigaction()} and @code{sigreturn()} system
|
||||
calls need to be fully emulated (see @file{signal.c}).
|
||||
|
||||
@subsection clone() system call and threads
|
||||
|
||||
The Linux clone() system call is usually used to create a thread. QEMU
|
||||
uses the host clone() system call so that real host threads are created
|
||||
for each emulated thread. One virtual CPU instance is created for each
|
||||
thread.
|
||||
|
||||
The virtual x86 CPU atomic operations are emulated with a global lock so
|
||||
that their semantic is preserved.
|
||||
|
||||
Note that currently there are still some locking issues in QEMU. In
|
||||
particular, the translated cache flush is not protected yet against
|
||||
reentrancy.
|
||||
|
||||
@subsection Self-virtualization
|
||||
|
||||
QEMU was conceived so that ultimately it can emulate itself. Although
|
||||
it is not very useful, it is an important test to show the power of the
|
||||
emulator.
|
||||
|
||||
Achieving self-virtualization is not easy because there may be address
|
||||
space conflicts. QEMU user emulators solve this problem by being an
|
||||
executable ELF shared object as the ld-linux.so ELF interpreter. That
|
||||
way, it can be relocated at load time.
|
||||
|
||||
@node Bibliography
|
||||
@section Bibliography
|
||||
|
||||
@ -656,43 +369,3 @@ Kernel Based Virtual Machine (KVM).
|
||||
QEMU-SystemC, a hardware co-simulator.
|
||||
|
||||
@end table
|
||||
|
||||
@node Regression Tests
|
||||
@chapter Regression Tests
|
||||
|
||||
In the directory @file{tests/}, various interesting testing programs
|
||||
are available. They are used for regression testing.
|
||||
|
||||
@menu
|
||||
* test-i386::
|
||||
* linux-test::
|
||||
@end menu
|
||||
|
||||
@node test-i386
|
||||
@section @file{test-i386}
|
||||
|
||||
This program executes most of the 16 bit and 32 bit x86 instructions and
|
||||
generates a text output. It can be compared with the output obtained with
|
||||
a real CPU or another emulator. The target @code{make test} runs this
|
||||
program and a @code{diff} on the generated output.
|
||||
|
||||
The Linux system call @code{modify_ldt()} is used to create x86 selectors
|
||||
to test some 16 bit addressing and 32 bit with segmentation cases.
|
||||
|
||||
The Linux system call @code{vm86()} is used to test vm86 emulation.
|
||||
|
||||
Various exceptions are raised to test most of the x86 user space
|
||||
exception reporting.
|
||||
|
||||
@node linux-test
|
||||
@section @file{linux-test}
|
||||
|
||||
This program tests various Linux system calls. It is used to verify
|
||||
that the system call parameters are correctly converted between target
|
||||
and host CPUs.
|
||||
|
||||
@node Index
|
||||
@chapter Index
|
||||
@printindex cp
|
||||
|
||||
@bye
|
||||
|
3
qemu.nsi
3
qemu.nsi
@ -171,10 +171,8 @@ SectionEnd
|
||||
Section "Documentation" SectionDoc
|
||||
SetOutPath "$INSTDIR"
|
||||
File "${BINDIR}\qemu-doc.html"
|
||||
File "${BINDIR}\qemu-tech.html"
|
||||
CreateDirectory "$SMPROGRAMS\${PRODUCT}"
|
||||
CreateShortCut "$SMPROGRAMS\${PRODUCT}\User Documentation.lnk" "$INSTDIR\qemu-doc.html" "" "$INSTDIR\qemu-doc.html" 0
|
||||
CreateShortCut "$SMPROGRAMS\${PRODUCT}\Technical Documentation.lnk" "$INSTDIR\qemu-tech.html" "" "$INSTDIR\qemu-tech.html" 0
|
||||
SectionEnd
|
||||
!endif
|
||||
|
||||
@ -219,7 +217,6 @@ Section "Uninstall"
|
||||
Delete "$INSTDIR\qemu.exe"
|
||||
Delete "$INSTDIR\qemu-system-*.exe"
|
||||
Delete "$INSTDIR\qemu-doc.html"
|
||||
Delete "$INSTDIR\qemu-tech.html"
|
||||
RMDir /r "$INSTDIR\keymaps"
|
||||
RMDir /r "$INSTDIR\share"
|
||||
; Remove generated files
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/base64.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/atomic.h"
|
||||
|
||||
/* Maximum captured guest-exec out_data/err_data - 16MB */
|
||||
#define GUEST_EXEC_MAX_OUTPUT (16*1024*1024)
|
||||
@ -82,7 +83,7 @@ struct GuestExecIOData {
|
||||
guchar *data;
|
||||
gsize size;
|
||||
gsize length;
|
||||
gint closed;
|
||||
bool closed;
|
||||
bool truncated;
|
||||
const char *name;
|
||||
};
|
||||
@ -93,7 +94,7 @@ struct GuestExecInfo {
|
||||
int64_t pid_numeric;
|
||||
gint status;
|
||||
bool has_output;
|
||||
gint finished;
|
||||
bool finished;
|
||||
GuestExecIOData in;
|
||||
GuestExecIOData out;
|
||||
GuestExecIOData err;
|
||||
@ -156,13 +157,13 @@ GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **err)
|
||||
|
||||
ges = g_new0(GuestExecStatus, 1);
|
||||
|
||||
bool finished = g_atomic_int_get(&gei->finished);
|
||||
bool finished = atomic_mb_read(&gei->finished);
|
||||
|
||||
/* need to wait till output channels are closed
|
||||
* to be sure we captured all output at this point */
|
||||
if (gei->has_output) {
|
||||
finished = finished && g_atomic_int_get(&gei->out.closed);
|
||||
finished = finished && g_atomic_int_get(&gei->err.closed);
|
||||
finished = finished && atomic_mb_read(&gei->out.closed);
|
||||
finished = finished && atomic_mb_read(&gei->err.closed);
|
||||
}
|
||||
|
||||
ges->exited = finished;
|
||||
@ -264,7 +265,7 @@ static void guest_exec_child_watch(GPid pid, gint status, gpointer data)
|
||||
(int32_t)gpid_to_int64(pid), (uint32_t)status);
|
||||
|
||||
gei->status = status;
|
||||
gei->finished = true;
|
||||
atomic_mb_set(&gei->finished, true);
|
||||
|
||||
g_spawn_close_pid(pid);
|
||||
}
|
||||
@ -320,7 +321,7 @@ static gboolean guest_exec_input_watch(GIOChannel *ch,
|
||||
done:
|
||||
g_io_channel_shutdown(ch, true, NULL);
|
||||
g_io_channel_unref(ch);
|
||||
g_atomic_int_set(&p->closed, 1);
|
||||
atomic_mb_set(&p->closed, true);
|
||||
g_free(p->data);
|
||||
|
||||
return false;
|
||||
@ -374,7 +375,7 @@ static gboolean guest_exec_output_watch(GIOChannel *ch,
|
||||
close:
|
||||
g_io_channel_shutdown(ch, true, NULL);
|
||||
g_io_channel_unref(ch);
|
||||
g_atomic_int_set(&p->closed, 1);
|
||||
atomic_mb_set(&p->closed, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
10
qom/cpu.c
10
qom/cpu.c
@ -120,10 +120,10 @@ void cpu_reset_interrupt(CPUState *cpu, int mask)
|
||||
|
||||
void cpu_exit(CPUState *cpu)
|
||||
{
|
||||
cpu->exit_request = 1;
|
||||
atomic_set(&cpu->exit_request, 1);
|
||||
/* Ensure cpu_exec will see the exit request after TCG has exited. */
|
||||
smp_wmb();
|
||||
cpu->tcg_exit_req = 1;
|
||||
atomic_set(&cpu->tcg_exit_req, 1);
|
||||
}
|
||||
|
||||
int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
|
||||
@ -253,6 +253,7 @@ void cpu_reset(CPUState *cpu)
|
||||
static void cpu_common_reset(CPUState *cpu)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
int i;
|
||||
|
||||
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
|
||||
qemu_log("CPU Reset (CPU %d)\n", cpu->cpu_index);
|
||||
@ -268,7 +269,10 @@ static void cpu_common_reset(CPUState *cpu)
|
||||
cpu->can_do_io = 1;
|
||||
cpu->exception_index = -1;
|
||||
cpu->crash_occurred = false;
|
||||
memset(cpu->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof(void *));
|
||||
|
||||
for (i = 0; i < TB_JMP_CACHE_SIZE; ++i) {
|
||||
atomic_set(&cpu->tb_jmp_cache[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static bool cpu_common_has_work(CPUState *cs)
|
||||
|
15
qom/object.c
15
qom/object.c
@ -614,7 +614,7 @@ Object *object_dynamic_cast_assert(Object *obj, const char *typename,
|
||||
Object *inst;
|
||||
|
||||
for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) {
|
||||
if (obj->class->object_cast_cache[i] == typename) {
|
||||
if (atomic_read(&obj->class->object_cast_cache[i]) == typename) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -631,10 +631,10 @@ Object *object_dynamic_cast_assert(Object *obj, const char *typename,
|
||||
|
||||
if (obj && obj == inst) {
|
||||
for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
|
||||
obj->class->object_cast_cache[i - 1] =
|
||||
obj->class->object_cast_cache[i];
|
||||
atomic_set(&obj->class->object_cast_cache[i - 1],
|
||||
atomic_read(&obj->class->object_cast_cache[i]));
|
||||
}
|
||||
obj->class->object_cast_cache[i - 1] = typename;
|
||||
atomic_set(&obj->class->object_cast_cache[i - 1], typename);
|
||||
}
|
||||
|
||||
out:
|
||||
@ -704,7 +704,7 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
|
||||
int i;
|
||||
|
||||
for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) {
|
||||
if (class->class_cast_cache[i] == typename) {
|
||||
if (atomic_read(&class->class_cast_cache[i]) == typename) {
|
||||
ret = class;
|
||||
goto out;
|
||||
}
|
||||
@ -725,9 +725,10 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
|
||||
#ifdef CONFIG_QOM_CAST_DEBUG
|
||||
if (class && ret == class) {
|
||||
for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
|
||||
class->class_cast_cache[i - 1] = class->class_cast_cache[i];
|
||||
atomic_set(&class->class_cast_cache[i - 1],
|
||||
atomic_read(&class->class_cast_cache[i]));
|
||||
}
|
||||
class->class_cast_cache[i - 1] = typename;
|
||||
atomic_set(&class->class_cast_cache[i - 1], typename);
|
||||
}
|
||||
out:
|
||||
#endif
|
||||
|
@ -223,6 +223,13 @@ int cpu_cris_signal_handler(int host_signum, void *pinfo,
|
||||
void cris_initialize_tcg(void);
|
||||
void cris_initialize_crisv10_tcg(void);
|
||||
|
||||
/* Instead of computing the condition codes after each CRIS instruction,
|
||||
* QEMU just stores one operand (called CC_SRC), the result
|
||||
* (called CC_DEST) and the type of operation (called CC_OP). When the
|
||||
* condition codes are needed, the condition codes can be calculated
|
||||
* using this information. Condition codes are not generated if they
|
||||
* are only needed for conditional branches.
|
||||
*/
|
||||
enum {
|
||||
CC_OP_DYNAMIC, /* Use env->cc_op */
|
||||
CC_OP_FLAGS,
|
||||
|
@ -698,6 +698,13 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
|
||||
/* Use a clearer name for this. */
|
||||
#define CPU_INTERRUPT_INIT CPU_INTERRUPT_RESET
|
||||
|
||||
/* Instead of computing the condition codes after each x86 instruction,
|
||||
* QEMU just stores one operand (called CC_SRC), the result
|
||||
* (called CC_DST) and the type of operation (called CC_OP). When the
|
||||
* condition codes are needed, the condition codes can be calculated
|
||||
* using this information. Condition codes are not generated if they
|
||||
* are only needed for conditional branches.
|
||||
*/
|
||||
typedef enum {
|
||||
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
|
||||
CC_OP_EFLAGS, /* all cc are explicitly computed, CC_SRC = flags */
|
||||
|
@ -154,6 +154,14 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc);
|
||||
void cpu_m68k_flush_flags(CPUM68KState *, int);
|
||||
|
||||
|
||||
/* Instead of computing the condition codes after each m68k instruction,
|
||||
* QEMU just stores one operand (called CC_SRC), the result
|
||||
* (called CC_DEST) and the type of operation (called CC_OP). When the
|
||||
* condition codes are needed, the condition codes can be calculated
|
||||
* using this information. Condition codes are not generated if they
|
||||
* are only needed for conditional branches.
|
||||
*/
|
||||
enum {
|
||||
CC_OP_DYNAMIC, /* Use env->cc_op */
|
||||
CC_OP_FLAGS, /* CC_DEST = CVZN, CC_SRC = unused */
|
||||
|
@ -671,6 +671,13 @@ ObjectClass *s390_cpu_class_by_name(const char *name);
|
||||
|
||||
/* CC optimization */
|
||||
|
||||
/* Instead of computing the condition codes after each x86 instruction,
|
||||
* QEMU just stores the result (called CC_DST), the type of operation
|
||||
* (called CC_OP) and whatever operands are needed (CC_SRC and possibly
|
||||
* CC_VR). When the condition codes are needed, the condition codes can
|
||||
* be calculated using this information. Condition codes are not generated
|
||||
* if they are only needed for conditional branches.
|
||||
*/
|
||||
enum cc_op {
|
||||
CC_OP_CONST0 = 0, /* CC is 0 */
|
||||
CC_OP_CONST1, /* CC is 1 */
|
||||
|
@ -102,6 +102,11 @@
|
||||
#define CC_DST (env->cc_dst)
|
||||
#define CC_OP (env->cc_op)
|
||||
|
||||
/* Even though lazy evaluation of CPU condition codes tends to be less
|
||||
* important on RISC systems where condition codes are only updated
|
||||
* when explicitly requested, SPARC uses it to update 32-bit and 64-bit
|
||||
* condition codes.
|
||||
*/
|
||||
enum {
|
||||
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
|
||||
CC_OP_FLAGS, /* all cc are back in status register */
|
||||
|
@ -8,6 +8,11 @@ in the QOP code generator written by Paul Brook.
|
||||
|
||||
2) Definitions
|
||||
|
||||
TCG receives RISC-like "TCG ops" and performs some optimizations on them,
|
||||
including liveness analysis and trivial constant expression
|
||||
evaluation. TCG ops are then implemented in the host CPU back end,
|
||||
also known as the TCG "target".
|
||||
|
||||
The TCG "target" is the architecture for which we generate the
|
||||
code. It is of course not the same as the "target" of QEMU which is
|
||||
the emulated architecture. As TCG started as a generic C backend used
|
||||
|
@ -468,9 +468,8 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x,
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Return 2 if the condition can't be simplified, and the result
|
||||
|
76
tests/tcg/README
Normal file
76
tests/tcg/README
Normal file
@ -0,0 +1,76 @@
|
||||
This directory contains various interesting programs for
|
||||
regression testing.
|
||||
|
||||
The target "make test" runs the programs and, if applicable,
|
||||
runs "diff" to detect mismatches between output on the host and
|
||||
output on QEMU.
|
||||
|
||||
i386
|
||||
====
|
||||
|
||||
test-i386
|
||||
---------
|
||||
|
||||
This program executes most of the 16 bit and 32 bit x86 instructions and
|
||||
generates a text output, for comparison with the output obtained with
|
||||
a real CPU or another emulator.
|
||||
|
||||
The Linux system call modify_ldt() is used to create x86 selectors
|
||||
to test some 16 bit addressing and 32 bit with segmentation cases.
|
||||
|
||||
The Linux system call vm86() is used to test vm86 emulation.
|
||||
|
||||
Various exceptions are raised to test most of the x86 user space
|
||||
exception reporting.
|
||||
|
||||
linux-test
|
||||
----------
|
||||
|
||||
This program tests various Linux system calls. It is used to verify
|
||||
that the system call parameters are correctly converted between target
|
||||
and host CPUs.
|
||||
|
||||
test-i386-fprem
|
||||
---------------
|
||||
|
||||
runcom
|
||||
------
|
||||
|
||||
test-mmap
|
||||
---------
|
||||
|
||||
sha1
|
||||
----
|
||||
|
||||
hello-i386
|
||||
----------
|
||||
|
||||
|
||||
ARM
|
||||
===
|
||||
|
||||
hello-arm
|
||||
---------
|
||||
|
||||
test-arm-iwmmxt
|
||||
---------------
|
||||
|
||||
MIPS
|
||||
====
|
||||
|
||||
hello-mips
|
||||
----------
|
||||
|
||||
hello-mipsel
|
||||
------------
|
||||
|
||||
CRIS
|
||||
====
|
||||
The testsuite for CRIS is in tests/tcg/cris. You can run it
|
||||
with "make test-cris".
|
||||
|
||||
LM32
|
||||
====
|
||||
The testsuite for LM32 is in tests/tcg/cris. You can run it
|
||||
with "make test-lm32".
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/qht.h"
|
||||
#include "qemu/rcu.h"
|
||||
|
||||
#define N 5000
|
||||
|
||||
@ -51,6 +52,7 @@ static void check(int a, int b, bool expected)
|
||||
struct qht_stats stats;
|
||||
int i;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = a; i < b; i++) {
|
||||
void *p;
|
||||
uint32_t hash;
|
||||
@ -61,6 +63,8 @@ static void check(int a, int b, bool expected)
|
||||
p = qht_lookup(&ht, is_equal, &val, hash);
|
||||
g_assert_true(!!p == expected);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
qht_statistics_init(&ht, &stats);
|
||||
if (stats.used_head_buckets) {
|
||||
g_assert_cmpfloat(qdist_avg(&stats.chain), >=, 1.0);
|
||||
|
@ -814,7 +814,6 @@ QemuCocoaView *cocoaView;
|
||||
- (void)doToggleFullScreen:(id)sender;
|
||||
- (void)toggleFullScreen:(id)sender;
|
||||
- (void)showQEMUDoc:(id)sender;
|
||||
- (void)showQEMUTec:(id)sender;
|
||||
- (void)zoomToFit:(id) sender;
|
||||
- (void)displayConsole:(id)sender;
|
||||
- (void)pauseQEMU:(id)sender;
|
||||
@ -998,13 +997,6 @@ QemuCocoaView *cocoaView;
|
||||
[self openDocumentation: @"qemu-doc.html"];
|
||||
}
|
||||
|
||||
- (void)showQEMUTec:(id)sender
|
||||
{
|
||||
COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
|
||||
|
||||
[self openDocumentation: @"qemu-tech.html"];
|
||||
}
|
||||
|
||||
/* Stretches video to fit host monitor size */
|
||||
- (void)zoomToFit:(id) sender
|
||||
{
|
||||
@ -1335,7 +1327,6 @@ int main (int argc, const char * argv[]) {
|
||||
// Help menu
|
||||
menu = [[NSMenu alloc] initWithTitle:@"Help"];
|
||||
[menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help
|
||||
[menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help
|
||||
menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
|
||||
[menuItem setSubmenu:menu];
|
||||
[[NSApp mainMenu] addItem:menuItem];
|
||||
|
@ -46,6 +46,7 @@
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/sysctl.h>
|
||||
#include <libutil.h>
|
||||
#endif
|
||||
|
||||
#include "qemu/mmap-alloc.h"
|
||||
@ -434,6 +435,32 @@ int qemu_read_password(char *buf, int buf_size)
|
||||
}
|
||||
|
||||
|
||||
char *qemu_get_pid_name(pid_t pid)
|
||||
{
|
||||
char *name = NULL;
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
/* BSDs don't have /proc, but they provide a nice substitute */
|
||||
struct kinfo_proc *proc = kinfo_getproc(pid);
|
||||
|
||||
if (proc) {
|
||||
name = g_strdup(proc->ki_comm);
|
||||
free(proc);
|
||||
}
|
||||
#else
|
||||
/* Assume a system with reasonable procfs */
|
||||
char *pid_path;
|
||||
size_t len;
|
||||
|
||||
pid_path = g_strdup_printf("/proc/%d/cmdline", pid);
|
||||
g_file_get_contents(pid_path, &name, &len, NULL);
|
||||
g_free(pid_path);
|
||||
#endif
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
pid_t qemu_fork(Error **errp)
|
||||
{
|
||||
sigset_t oldmask, newmask;
|
||||
|
@ -575,6 +575,13 @@ int qemu_read_password(char *buf, int buf_size)
|
||||
}
|
||||
|
||||
|
||||
char *qemu_get_pid_name(pid_t pid)
|
||||
{
|
||||
/* XXX Implement me */
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
pid_t qemu_fork(Error **errp)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
|
65
util/qht.c
65
util/qht.c
@ -133,7 +133,8 @@ struct qht_map {
|
||||
/* trigger a resize when n_added_buckets > n_buckets / div */
|
||||
#define QHT_NR_ADDED_BUCKETS_THRESHOLD_DIV 8
|
||||
|
||||
static void qht_do_resize(struct qht *ht, struct qht_map *new);
|
||||
static void qht_do_resize_reset(struct qht *ht, struct qht_map *new,
|
||||
bool reset);
|
||||
static void qht_grow_maybe(struct qht *ht);
|
||||
|
||||
#ifdef QHT_DEBUG
|
||||
@ -379,7 +380,7 @@ static void qht_bucket_reset__locked(struct qht_bucket *head)
|
||||
if (b->pointers[i] == NULL) {
|
||||
goto done;
|
||||
}
|
||||
b->hashes[i] = 0;
|
||||
atomic_set(&b->hashes[i], 0);
|
||||
atomic_set(&b->pointers[i], NULL);
|
||||
}
|
||||
b = b->next;
|
||||
@ -408,12 +409,21 @@ void qht_reset(struct qht *ht)
|
||||
qht_map_unlock_buckets(map);
|
||||
}
|
||||
|
||||
static inline void qht_do_resize(struct qht *ht, struct qht_map *new)
|
||||
{
|
||||
qht_do_resize_reset(ht, new, false);
|
||||
}
|
||||
|
||||
static inline void qht_do_resize_and_reset(struct qht *ht, struct qht_map *new)
|
||||
{
|
||||
qht_do_resize_reset(ht, new, true);
|
||||
}
|
||||
|
||||
bool qht_reset_size(struct qht *ht, size_t n_elems)
|
||||
{
|
||||
struct qht_map *new;
|
||||
struct qht_map *new = NULL;
|
||||
struct qht_map *map;
|
||||
size_t n_buckets;
|
||||
bool resize = false;
|
||||
|
||||
n_buckets = qht_elems_to_buckets(n_elems);
|
||||
|
||||
@ -421,18 +431,11 @@ bool qht_reset_size(struct qht *ht, size_t n_elems)
|
||||
map = ht->map;
|
||||
if (n_buckets != map->n_buckets) {
|
||||
new = qht_map_create(n_buckets);
|
||||
resize = true;
|
||||
}
|
||||
|
||||
qht_map_lock_buckets(map);
|
||||
qht_map_reset__all_locked(map);
|
||||
if (resize) {
|
||||
qht_do_resize(ht, new);
|
||||
}
|
||||
qht_map_unlock_buckets(map);
|
||||
qht_do_resize_and_reset(ht, new);
|
||||
qemu_mutex_unlock(&ht->lock);
|
||||
|
||||
return resize;
|
||||
return !!new;
|
||||
}
|
||||
|
||||
static inline
|
||||
@ -444,7 +447,7 @@ void *qht_do_lookup(struct qht_bucket *head, qht_lookup_func_t func,
|
||||
|
||||
do {
|
||||
for (i = 0; i < QHT_BUCKET_ENTRIES; i++) {
|
||||
if (b->hashes[i] == hash) {
|
||||
if (atomic_read(&b->hashes[i]) == hash) {
|
||||
/* The pointer is dereferenced before seqlock_read_retry,
|
||||
* so (unlike qht_insert__locked) we need to use
|
||||
* atomic_rcu_read here.
|
||||
@ -538,8 +541,8 @@ static bool qht_insert__locked(struct qht *ht, struct qht_map *map,
|
||||
if (new) {
|
||||
atomic_rcu_set(&prev->next, b);
|
||||
}
|
||||
b->hashes[i] = hash;
|
||||
/* smp_wmb() implicit in seqlock_write_begin. */
|
||||
atomic_set(&b->hashes[i], hash);
|
||||
atomic_set(&b->pointers[i], p);
|
||||
seqlock_write_end(&head->sequence);
|
||||
return true;
|
||||
@ -561,9 +564,7 @@ static __attribute__((noinline)) void qht_grow_maybe(struct qht *ht)
|
||||
if (qht_map_needs_resize(map)) {
|
||||
struct qht_map *new = qht_map_create(map->n_buckets * 2);
|
||||
|
||||
qht_map_lock_buckets(map);
|
||||
qht_do_resize(ht, new);
|
||||
qht_map_unlock_buckets(map);
|
||||
}
|
||||
qemu_mutex_unlock(&ht->lock);
|
||||
}
|
||||
@ -607,10 +608,10 @@ qht_entry_move(struct qht_bucket *to, int i, struct qht_bucket *from, int j)
|
||||
qht_debug_assert(to->pointers[i]);
|
||||
qht_debug_assert(from->pointers[j]);
|
||||
|
||||
to->hashes[i] = from->hashes[j];
|
||||
atomic_set(&to->hashes[i], from->hashes[j]);
|
||||
atomic_set(&to->pointers[i], from->pointers[j]);
|
||||
|
||||
from->hashes[j] = 0;
|
||||
atomic_set(&from->hashes[j], 0);
|
||||
atomic_set(&from->pointers[j], NULL);
|
||||
}
|
||||
|
||||
@ -739,24 +740,31 @@ static void qht_map_copy(struct qht *ht, void *p, uint32_t hash, void *userp)
|
||||
}
|
||||
|
||||
/*
|
||||
* Call with ht->lock and all bucket locks held.
|
||||
*
|
||||
* Creating the @new map here would add unnecessary delay while all the locks
|
||||
* are held--holding up the bucket locks is particularly bad, since no writes
|
||||
* can occur while these are held. Thus, we let callers create the new map,
|
||||
* hopefully without the bucket locks held.
|
||||
* Atomically perform a resize and/or reset.
|
||||
* Call with ht->lock held.
|
||||
*/
|
||||
static void qht_do_resize(struct qht *ht, struct qht_map *new)
|
||||
static void qht_do_resize_reset(struct qht *ht, struct qht_map *new, bool reset)
|
||||
{
|
||||
struct qht_map *old;
|
||||
|
||||
old = ht->map;
|
||||
g_assert_cmpuint(new->n_buckets, !=, old->n_buckets);
|
||||
qht_map_lock_buckets(old);
|
||||
|
||||
if (reset) {
|
||||
qht_map_reset__all_locked(old);
|
||||
}
|
||||
|
||||
if (new == NULL) {
|
||||
qht_map_unlock_buckets(old);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert_cmpuint(new->n_buckets, !=, old->n_buckets);
|
||||
qht_map_iter__all_locked(ht, old, qht_map_copy, new);
|
||||
qht_map_debug__all_locked(new);
|
||||
|
||||
atomic_rcu_set(&ht->map, new);
|
||||
qht_map_unlock_buckets(old);
|
||||
call_rcu(old, qht_map_destroy, rcu);
|
||||
}
|
||||
|
||||
@ -768,12 +776,9 @@ bool qht_resize(struct qht *ht, size_t n_elems)
|
||||
qemu_mutex_lock(&ht->lock);
|
||||
if (n_buckets != ht->map->n_buckets) {
|
||||
struct qht_map *new;
|
||||
struct qht_map *old = ht->map;
|
||||
|
||||
new = qht_map_create(n_buckets);
|
||||
qht_map_lock_buckets(old);
|
||||
qht_do_resize(ht, new);
|
||||
qht_map_unlock_buckets(old);
|
||||
ret = true;
|
||||
}
|
||||
qemu_mutex_unlock(&ht->lock);
|
||||
|
8
vl.c
8
vl.c
@ -1675,8 +1675,12 @@ static void qemu_kill_report(void)
|
||||
*/
|
||||
error_report("terminating on signal %d", shutdown_signal);
|
||||
} else {
|
||||
error_report("terminating on signal %d from pid " FMT_pid,
|
||||
shutdown_signal, shutdown_pid);
|
||||
char *shutdown_cmd = qemu_get_pid_name(shutdown_pid);
|
||||
|
||||
error_report("terminating on signal %d from pid " FMT_pid " (%s)",
|
||||
shutdown_signal, shutdown_pid,
|
||||
shutdown_cmd ? shutdown_cmd : "<unknown process>");
|
||||
g_free(shutdown_cmd);
|
||||
}
|
||||
shutdown_signal = -1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user