summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xconfigure6
m---------dtc0
-rw-r--r--hmp.c18
-rw-r--r--hw/core/Makefile.objs1
-rw-r--r--hw/core/loader-fit.c325
-rw-r--r--hw/core/loader.c7
-rw-r--r--hw/intc/mips_gic.c56
-rw-r--r--hw/misc/mips_cmgcr.c17
-rw-r--r--hw/pci-host/Makefile.objs1
-rw-r--r--hw/pci-host/xilinx-pcie.c328
-rw-r--r--hw/timer/mips_gictimer.c5
-rw-r--r--include/hw/loader-fit.h41
-rw-r--r--include/hw/loader.h6
-rw-r--r--include/hw/misc/mips_cmgcr.h3
-rw-r--r--include/hw/pci-host/xilinx-pcie.h68
-rw-r--r--include/hw/timer/mips_gictimer.h1
-rw-r--r--iothread.c3
-rw-r--r--monitor.c42
-rw-r--r--qapi-schema.json15
-rw-r--r--target/i386/monitor.c16
-rw-r--r--target/mips/cpu.h1
-rw-r--r--target/mips/translate.c10
-rw-r--r--target/ppc/monitor.c4
-rw-r--r--target/sh4/monitor.c5
-rw-r--r--target/sparc/monitor.c4
-rw-r--r--target/xtensa/monitor.c4
26 files changed, 940 insertions, 47 deletions
diff --git a/configure b/configure
index 1c9655e639..4b68861992 100755
--- a/configure
+++ b/configure
@@ -3396,11 +3396,11 @@ fi
if test "$fdt" != "no" ; then
fdt_libs="-lfdt"
# explicitly check for libfdt_env.h as it is missing in some stable installs
- # and test for required functions to make sure we are on a version >= 1.4.0
+ # and test for required functions to make sure we are on a version >= 1.4.2
cat > $TMPC << EOF
#include <libfdt.h>
#include <libfdt_env.h>
-int main(void) { fdt_get_property_by_offset(0, 0, 0); return 0; }
+int main(void) { fdt_first_subnode(0, 0); return 0; }
EOF
if compile_prog "" "$fdt_libs" ; then
# system DTC is good - use it
@@ -3418,7 +3418,7 @@ EOF
fdt_libs="-L\$(BUILD_DIR)/dtc/libfdt $fdt_libs"
elif test "$fdt" = "yes" ; then
# have neither and want - prompt for system/submodule install
- error_exit "DTC (libfdt) version >= 1.4.0 not present. Your options:" \
+ error_exit "DTC (libfdt) version >= 1.4.2 not present. Your options:" \
" (1) Preferred: Install the DTC (libfdt) devel package" \
" (2) Fetch the DTC submodule, using:" \
" git submodule update --init dtc"
diff --git a/dtc b/dtc
-Subproject 65cc4d2748a2c2e6f27f1cf39e07a5dbabd80eb
+Subproject ec02b34c05be04f249ffaaca4b666f5246877de
diff --git a/hmp.c b/hmp.c
index 2bc4f062bb..aba728f0de 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1014,8 +1014,14 @@ void hmp_memsave(Monitor *mon, const QDict *qdict)
const char *filename = qdict_get_str(qdict, "filename");
uint64_t addr = qdict_get_int(qdict, "val");
Error *err = NULL;
+ int cpu_index = monitor_get_cpu_index();
- qmp_memsave(addr, size, filename, true, monitor_get_cpu_index(), &err);
+ if (cpu_index < 0) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
+
+ qmp_memsave(addr, size, filename, true, cpu_index, &err);
hmp_handle_error(mon, &err);
}
@@ -1552,6 +1558,7 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
BlockIOThrottle throttle = {
+ .has_device = true,
.device = (char *) qdict_get_str(qdict, "device"),
.bps = qdict_get_int(qdict, "bps"),
.bps_rd = qdict_get_int(qdict, "bps_rd"),
@@ -2148,10 +2155,15 @@ void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
{
IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
IOThreadInfoList *info;
+ IOThreadInfo *value;
for (info = info_list; info; info = info->next) {
- monitor_printf(mon, "%s: thread_id=%" PRId64 "\n",
- info->value->id, info->value->thread_id);
+ value = info->value;
+ monitor_printf(mon, "%s:\n", value->id);
+ monitor_printf(mon, " thread_id=%" PRId64 "\n", value->thread_id);
+ monitor_printf(mon, " poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
+ monitor_printf(mon, " poll-grow=%" PRId64 "\n", value->poll_grow);
+ monitor_printf(mon, " poll-shrink=%" PRId64 "\n", value->poll_shrink);
}
qapi_free_IOThreadInfoList(info_list);
diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index 7f8c9dc659..91450b2eab 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -13,6 +13,7 @@ common-obj-$(CONFIG_PTIMER) += ptimer.o
common-obj-$(CONFIG_SOFTMMU) += sysbus.o
common-obj-$(CONFIG_SOFTMMU) += machine.o
common-obj-$(CONFIG_SOFTMMU) += loader.o
+common-obj-$(CONFIG_FITLOADER) += loader-fit.o
common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
common-obj-$(CONFIG_SOFTMMU) += register.o
common-obj-$(CONFIG_SOFTMMU) += or-irq.o
diff --git a/hw/core/loader-fit.c b/hw/core/loader-fit.c
new file mode 100644
index 0000000000..0c4a7207f4
--- /dev/null
+++ b/hw/core/loader-fit.c
@@ -0,0 +1,325 @@
+/*
+ * Flattened Image Tree loader.
+ *
+ * Copyright (c) 2016 Imagination Technologies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "exec/address-spaces.h"
+#include "exec/memory.h"
+#include "hw/loader.h"
+#include "hw/loader-fit.h"
+#include "qemu/cutils.h"
+#include "qemu/error-report.h"
+#include "sysemu/device_tree.h"
+#include "sysemu/sysemu.h"
+
+#include <libfdt.h>
+#include <zlib.h>
+
+#define FIT_LOADER_MAX_PATH (128)
+
+static const void *fit_load_image_alloc(const void *itb, const char *name,
+ int *poff, size_t *psz)
+{
+ const void *data;
+ const char *comp;
+ void *uncomp_data;
+ char path[FIT_LOADER_MAX_PATH];
+ int off, sz;
+ ssize_t uncomp_len;
+
+ snprintf(path, sizeof(path), "/images/%s", name);
+
+ off = fdt_path_offset(itb, path);
+ if (off < 0) {
+ return NULL;
+ }
+ if (poff) {
+ *poff = off;
+ }
+
+ data = fdt_getprop(itb, off, "data", &sz);
+ if (!data) {
+ return NULL;
+ }
+
+ comp = fdt_getprop(itb, off, "compression", NULL);
+ if (!comp || !strcmp(comp, "none")) {
+ if (psz) {
+ *psz = sz;
+ }
+ uncomp_data = g_malloc(sz);
+ memmove(uncomp_data, data, sz);
+ return uncomp_data;
+ }
+
+ if (!strcmp(comp, "gzip")) {
+ uncomp_len = UBOOT_MAX_GUNZIP_BYTES;
+ uncomp_data = g_malloc(uncomp_len);
+
+ uncomp_len = gunzip(uncomp_data, uncomp_len, (void *) data, sz);
+ if (uncomp_len < 0) {
+ error_printf("unable to decompress %s image\n", name);
+ g_free(uncomp_data);
+ return NULL;
+ }
+
+ data = g_realloc(uncomp_data, uncomp_len);
+ if (psz) {
+ *psz = uncomp_len;
+ }
+ return data;
+ }
+
+ error_printf("unknown compression '%s'\n", comp);
+ return NULL;
+}
+
+static int fit_image_addr(const void *itb, int img, const char *name,
+ hwaddr *addr)
+{
+ const void *prop;
+ int len;
+
+ prop = fdt_getprop(itb, img, name, &len);
+ if (!prop) {
+ return -ENOENT;
+ }
+
+ switch (len) {
+ case 4:
+ *addr = fdt32_to_cpu(*(fdt32_t *)prop);
+ return 0;
+ case 8:
+ *addr = fdt64_to_cpu(*(fdt64_t *)prop);
+ return 0;
+ default:
+ error_printf("invalid %s address length %d\n", name, len);
+ return -EINVAL;
+ }
+}
+
+static int fit_load_kernel(const struct fit_loader *ldr, const void *itb,
+ int cfg, void *opaque, hwaddr *pend)
+{
+ const char *name;
+ const void *data;
+ const void *load_data;
+ hwaddr load_addr, entry_addr;
+ int img_off, err;
+ size_t sz;
+ int ret;
+
+ name = fdt_getprop(itb, cfg, "kernel", NULL);
+ if (!name) {
+ error_printf("no kernel specified by FIT configuration\n");
+ return -EINVAL;
+ }
+
+ load_data = data = fit_load_image_alloc(itb, name, &img_off, &sz);
+ if (!data) {
+ error_printf("unable to load kernel image from FIT\n");
+ return -EINVAL;
+ }
+
+ err = fit_image_addr(itb, img_off, "load", &load_addr);
+ if (err) {
+ error_printf("unable to read kernel load address from FIT\n");
+ ret = err;
+ goto out;
+ }
+
+ err = fit_image_addr(itb, img_off, "entry", &entry_addr);
+ if (err) {
+ error_printf("unable to read kernel entry address from FIT\n");
+ ret = err;
+ goto out;
+ }
+
+ if (ldr->kernel_filter) {
+ load_data = ldr->kernel_filter(opaque, data, &load_addr, &entry_addr);
+ }
+
+ if (pend) {
+ *pend = load_addr + sz;
+ }
+
+ load_addr = ldr->addr_to_phys(opaque, load_addr);
+ rom_add_blob_fixed(name, load_data, sz, load_addr);
+
+ ret = 0;
+out:
+ g_free((void *) data);
+ if (data != load_data) {
+ g_free((void *) load_data);
+ }
+ return ret;
+}
+
+static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
+ int cfg, void *opaque, const void *match_data,
+ hwaddr kernel_end)
+{
+ const char *name;
+ const void *data;
+ const void *load_data;
+ hwaddr load_addr;
+ int img_off, err;
+ size_t sz;
+ int ret;
+
+ name = fdt_getprop(itb, cfg, "fdt", NULL);
+ if (!name) {
+ return 0;
+ }
+
+ load_data = data = fit_load_image_alloc(itb, name, &img_off, &sz);
+ if (!data) {
+ error_printf("unable to load FDT image from FIT\n");
+ return -EINVAL;
+ }
+
+ err = fit_image_addr(itb, img_off, "load", &load_addr);
+ if (err == -ENOENT) {
+ load_addr = ROUND_UP(kernel_end, 64 * K_BYTE) + (10 * M_BYTE);
+ } else if (err) {
+ ret = err;
+ goto out;
+ }
+
+ if (ldr->fdt_filter) {
+ load_data = ldr->fdt_filter(opaque, data, match_data, &load_addr);
+ }
+
+ load_addr = ldr->addr_to_phys(opaque, load_addr);
+ sz = fdt_totalsize(load_data);
+ rom_add_blob_fixed(name, load_data, sz, load_addr);
+
+ ret = 0;
+out:
+ g_free((void *) data);
+ if (data != load_data) {
+ g_free((void *) load_data);
+ }
+ return ret;
+}
+
+static bool fit_cfg_compatible(const void *itb, int cfg, const char *compat)
+{
+ const void *fdt;
+ const char *fdt_name;
+ bool ret;
+
+ fdt_name = fdt_getprop(itb, cfg, "fdt", NULL);
+ if (!fdt_name) {
+ return false;
+ }
+
+ fdt = fit_load_image_alloc(itb, fdt_name, NULL, NULL);
+ if (!fdt) {
+ return false;
+ }
+
+ if (fdt_check_header(fdt)) {
+ ret = false;
+ goto out;
+ }
+
+ if (fdt_node_check_compatible(fdt, 0, compat)) {
+ ret = false;
+ goto out;
+ }
+
+ ret = true;
+out:
+ g_free((void *) fdt);
+ return ret;
+}
+
+int load_fit(const struct fit_loader *ldr, const char *filename, void *opaque)
+{
+ const struct fit_loader_match *match;
+ const void *itb, *match_data = NULL;
+ const char *def_cfg_name;
+ char path[FIT_LOADER_MAX_PATH];
+ int itb_size, configs, cfg_off, off, err;
+ hwaddr kernel_end;
+ int ret;
+
+ itb = load_device_tree(filename, &itb_size);
+ if (!itb) {
+ return -EINVAL;
+ }
+
+ configs = fdt_path_offset(itb, "/configurations");
+ if (configs < 0) {
+ ret = configs;
+ goto out;
+ }
+
+ cfg_off = -FDT_ERR_NOTFOUND;
+
+ if (ldr->matches) {
+ for (match = ldr->matches; match->compatible; match++) {
+ off = fdt_first_subnode(itb, configs);
+ while (off >= 0) {
+ if (fit_cfg_compatible(itb, off, match->compatible)) {
+ cfg_off = off;
+ match_data = match->data;
+ break;
+ }
+
+ off = fdt_next_subnode(itb, off);
+ }
+
+ if (cfg_off >= 0) {
+ break;
+ }
+ }
+ }
+
+ if (cfg_off < 0) {
+ def_cfg_name = fdt_getprop(itb, configs, "default", NULL);
+ if (def_cfg_name) {
+ snprintf(path, sizeof(path), "/configurations/%s", def_cfg_name);
+ cfg_off = fdt_path_offset(itb, path);
+ }
+ }
+
+ if (cfg_off < 0) {
+ /* couldn't find a configuration to use */
+ ret = cfg_off;
+ goto out;
+ }
+
+ err = fit_load_kernel(ldr, itb, cfg_off, opaque, &kernel_end);
+ if (err) {
+ ret = err;
+ goto out;
+ }
+
+ err = fit_load_fdt(ldr, itb, cfg_off, opaque, match_data, kernel_end);
+ if (err) {
+ ret = err;
+ goto out;
+ }
+
+ ret = 0;
+out:
+ g_free((void *) itb);
+ return ret;
+}
diff --git a/hw/core/loader.c b/hw/core/loader.c
index ee5abd6eb7..8b980e91fb 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -527,12 +527,7 @@ static void zfree(void *x, void *addr)
#define DEFLATED 8
-/* This is the usual maximum in uboot, so if a uImage overflows this, it would
- * overflow on real hardware too. */
-#define UBOOT_MAX_GUNZIP_BYTES (64 << 20)
-
-static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
- size_t srclen)
+ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, size_t srclen)
{
z_stream s;
ssize_t dstbytes;
diff --git a/hw/intc/mips_gic.c b/hw/intc/mips_gic.c
index 6e257730f8..15e6e40f9f 100644
--- a/hw/intc/mips_gic.c
+++ b/hw/intc/mips_gic.c
@@ -20,31 +20,29 @@
#include "kvm_mips.h"
#include "hw/intc/mips_gic.h"
-static void mips_gic_set_vp_irq(MIPSGICState *gic, int vp, int pin, int level)
+static void mips_gic_set_vp_irq(MIPSGICState *gic, int vp, int pin)
{
- int ored_level = level;
+ int ored_level = 0;
int i;
/* ORing pending registers sharing same pin */
- if (!ored_level) {
- for (i = 0; i < gic->num_irq; i++) {
- if ((gic->irq_state[i].map_pin & GIC_MAP_MSK) == pin &&
- gic->irq_state[i].map_vp == vp &&
- gic->irq_state[i].enabled) {
- ored_level |= gic->irq_state[i].pending;
- }
- if (ored_level) {
- /* no need to iterate all interrupts */
- break;
- }
+ for (i = 0; i < gic->num_irq; i++) {
+ if ((gic->irq_state[i].map_pin & GIC_MAP_MSK) == pin &&
+ gic->irq_state[i].map_vp == vp &&
+ gic->irq_state[i].enabled) {
+ ored_level |= gic->irq_state[i].pending;
}
- if (((gic->vps[vp].compare_map & GIC_MAP_MSK) == pin) &&
- (gic->vps[vp].mask & GIC_VP_MASK_CMP_MSK)) {
- /* ORing with local pending register (count/compare) */
- ored_level |= (gic->vps[vp].pend & GIC_VP_MASK_CMP_MSK) >>
- GIC_VP_MASK_CMP_SHF;
+ if (ored_level) {
+ /* no need to iterate all interrupts */
+ break;
}
}
+ if (((gic->vps[vp].compare_map & GIC_MAP_MSK) == pin) &&
+ (gic->vps[vp].mask & GIC_VP_MASK_CMP_MSK)) {
+ /* ORing with local pending register (count/compare) */
+ ored_level |= (gic->vps[vp].pend & GIC_VP_MASK_CMP_MSK) >>
+ GIC_VP_MASK_CMP_SHF;
+ }
if (kvm_enabled()) {
kvm_mips_set_ipi_interrupt(mips_env_get_cpu(gic->vps[vp].env),
pin + GIC_CPU_PIN_OFFSET,
@@ -55,21 +53,27 @@ static void mips_gic_set_vp_irq(MIPSGICState *gic, int vp, int pin, int level)
}
}
-static void gic_set_irq(void *opaque, int n_IRQ, int level)
+static void gic_update_pin_for_irq(MIPSGICState *gic, int n_IRQ)
{
- MIPSGICState *gic = (MIPSGICState *) opaque;
int vp = gic->irq_state[n_IRQ].map_vp;
int pin = gic->irq_state[n_IRQ].map_pin & GIC_MAP_MSK;
+ if (vp < 0 || vp >= gic->num_vps) {
+ return;
+ }
+ mips_gic_set_vp_irq(gic, vp, pin);
+}
+
+static void gic_set_irq(void *opaque, int n_IRQ, int level)
+{
+ MIPSGICState *gic = (MIPSGICState *) opaque;
+
gic->irq_state[n_IRQ].pending = (uint8_t) level;
if (!gic->irq_state[n_IRQ].enabled) {
/* GIC interrupt source disabled */
return;
}
- if (vp < 0 || vp >= gic->num_vps) {
- return;
- }
- mips_gic_set_vp_irq(gic, vp, pin, level);
+ gic_update_pin_for_irq(gic, n_IRQ);
}
#define OFFSET_CHECK(c) \
@@ -209,7 +213,7 @@ static void gic_timer_store_vp_compare(MIPSGICState *gic, uint32_t vp_index,
gic->vps[vp_index].pend &= ~(1 << GIC_LOCAL_INT_COMPARE);
if (gic->vps[vp_index].compare_map & GIC_MAP_TO_PIN_MSK) {
uint32_t pin = (gic->vps[vp_index].compare_map & GIC_MAP_MSK);
- mips_gic_set_vp_irq(gic, vp_index, pin, 0);
+ mips_gic_set_vp_irq(gic, vp_index, pin);
}
mips_gictimer_store_vp_compare(gic->gic_timer, vp_index, compare);
}
@@ -286,6 +290,7 @@ static void gic_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
OFFSET_CHECK((base + size * 8) <= gic->num_irq);
for (i = 0; i < size * 8; i++) {
gic->irq_state[base + i].enabled &= !((data >> i) & 1);
+ gic_update_pin_for_irq(gic, base + i);
}
break;
case GIC_SH_WEDGE_OFS:
@@ -305,6 +310,7 @@ static void gic_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
OFFSET_CHECK((base + size * 8) <= gic->num_irq);
for (i = 0; i < size * 8; i++) {
gic->irq_state[base + i].enabled |= (data >> i) & 1;
+ gic_update_pin_for_irq(gic, base + i);
}
break;
case GIC_SH_MAP0_PIN_OFS ... GIC_SH_MAP255_PIN_OFS:
diff --git a/hw/misc/mips_cmgcr.c b/hw/misc/mips_cmgcr.c
index b3ba16694e..a1edb53f95 100644
--- a/hw/misc/mips_cmgcr.c
+++ b/hw/misc/mips_cmgcr.c
@@ -29,6 +29,20 @@ static inline bool is_gic_connected(MIPSGCRState *s)
return s->gic_mr != NULL;
}
+static inline void update_gcr_base(MIPSGCRState *gcr, uint64_t val)
+{
+ CPUState *cpu;
+ MIPSCPU *mips_cpu;
+
+ gcr->gcr_base = val & GCR_BASE_GCRBASE_MSK;
+ memory_region_set_address(&gcr->iomem, gcr->gcr_base);
+
+ CPU_FOREACH(cpu) {
+ mips_cpu = MIPS_CPU(cpu);
+ mips_cpu->env.CP0_CMGCRBase = gcr->gcr_base >> 4;
+ }
+}
+
static inline void update_cpc_base(MIPSGCRState *gcr, uint64_t val)
{
if (is_cpc_connected(gcr)) {
@@ -117,6 +131,9 @@ static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
MIPSGCRVPState *other_vps = &gcr->vps[current_vps->other];
switch (addr) {
+ case GCR_BASE_OFS:
+ update_gcr_base(gcr, data);
+ break;
case GCR_GIC_BASE_OFS:
update_gic_base(gcr, data);
break;
diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs
index 45f1f0ebab..9c7909cf44 100644
--- a/hw/pci-host/Makefile.objs
+++ b/hw/pci-host/Makefile.objs
@@ -16,3 +16,4 @@ common-obj-$(CONFIG_FULONG) += bonito.o
common-obj-$(CONFIG_PCI_PIIX) += piix.o
common-obj-$(CONFIG_PCI_Q35) += q35.o
common-obj-$(CONFIG_PCI_GENERIC) += gpex.o
+common-obj-$(CONFIG_PCI_XILINX) += xilinx-pcie.o
diff --git a/hw/pci-host/xilinx-pcie.c b/hw/pci-host/xilinx-pcie.c
new file mode 100644
index 0000000000..8b71e2d950
--- /dev/null
+++ b/hw/pci-host/xilinx-pcie.c
@@ -0,0 +1,328 @@
+/*
+ * Xilinx PCIe host controller emulation.
+ *
+ * Copyright (c) 2016 Imagination Technologies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/pci-host/xilinx-pcie.h"
+
+enum root_cfg_reg {
+ /* Interrupt Decode Register */
+ ROOTCFG_INTDEC = 0x138,
+
+ /* Interrupt Mask Register */
+ ROOTCFG_INTMASK = 0x13c,
+ /* INTx Interrupt Received */
+#define ROOTCFG_INTMASK_INTX (1 << 16)
+ /* MSI Interrupt Received */
+#define ROOTCFG_INTMASK_MSI (1 << 17)
+
+ /* PHY Status/Control Register */
+ ROOTCFG_PSCR = 0x144,
+ /* Link Up */
+#define ROOTCFG_PSCR_LINK_UP (1 << 11)
+
+ /* Root Port Status/Control Register */
+ ROOTCFG_RPSCR = 0x148,
+ /* Bridge Enable */
+#define ROOTCFG_RPSCR_BRIDGEEN (1 << 0)
+ /* Interrupt FIFO Not Empty */
+#define ROOTCFG_RPSCR_INTNEMPTY (1 << 18)
+ /* Interrupt FIFO Overflow */
+#define ROOTCFG_RPSCR_INTOVF (1 << 19)
+
+ /* Root Port Interrupt FIFO Read Register 1 */
+ ROOTCFG_RPIFR1 = 0x158,
+#define ROOTCFG_RPIFR1_INT_LANE_SHIFT 27
+#define ROOTCFG_RPIFR1_INT_ASSERT_SHIFT 29
+#define ROOTCFG_RPIFR1_INT_VALID_SHIFT 31
+ /* Root Port Interrupt FIFO Read Register 2 */
+ ROOTCFG_RPIFR2 = 0x15c,
+};
+
+static void xilinx_pcie_update_intr(XilinxPCIEHost *s,
+ uint32_t set, uint32_t clear)
+{
+ int level;
+
+ s->intr |= set;
+ s->intr &= ~clear;
+
+ if (s->intr_fifo_r != s->intr_fifo_w) {
+ s->intr |= ROOTCFG_INTMASK_INTX;
+ }
+
+ level = !!(s->intr & s->intr_mask);
+ qemu_set_irq(s->irq, level);
+}
+
+static void xilinx_pcie_queue_intr(XilinxPCIEHost *s,
+ uint32_t fifo_reg1, uint32_t fifo_reg2)
+{
+ XilinxPCIEInt *intr;
+ unsigned int new_w;
+
+ new_w = (s->intr_fifo_w + 1) % ARRAY_SIZE(s->intr_fifo);
+ if (new_w == s->intr_fifo_r) {
+ s->rpscr |= ROOTCFG_RPSCR_INTOVF;
+ return;
+ }
+
+ intr = &s->intr_fifo[s->intr_fifo_w];
+ s->intr_fifo_w = new_w;
+
+ intr->fifo_reg1 = fifo_reg1;
+ intr->fifo_reg2 = fifo_reg2;
+
+ xilinx_pcie_update_intr(s, ROOTCFG_INTMASK_INTX, 0);
+}
+
+static void xilinx_pcie_set_irq(void *opaque, int irq_num, int level)
+{
+ XilinxPCIEHost *s = XILINX_PCIE_HOST(opaque);
+
+ xilinx_pcie_queue_intr(s,
+ (irq_num << ROOTCFG_RPIFR1_INT_LANE_SHIFT) |
+ (level << ROOTCFG_RPIFR1_INT_ASSERT_SHIFT) |
+ (1 << ROOTCFG_RPIFR1_INT_VALID_SHIFT),
+ 0);
+}
+
+static void xilinx_pcie_host_realize(DeviceState *dev, Error **errp)
+{
+ PCIHostState *pci = PCI_HOST_BRIDGE(dev);
+ XilinxPCIEHost *s = XILINX_PCIE_HOST(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev);
+
+ snprintf(s->name, sizeof(s->name), "pcie%u", s->bus_nr);
+
+ /* PCI configuration space */
+ pcie_host_mmcfg_init(pex, s->cfg_size);
+
+ /* MMIO region */
+ memory_region_init(&s->mmio, OBJECT(s), "mmio", UINT64_MAX);
+ memory_region_set_enabled(&s->mmio, false);
+
+ /* dummy I/O region */
+ memory_region_init_ram(&s->io, OBJECT(s), "io", 16, NULL);
+ memory_region_set_enabled(&s->io, false);
+
+ /* interrupt out */
+ qdev_init_gpio_out_named(dev, &s->irq, "interrupt_out", 1);
+
+ sysbus_init_mmio(sbd, &pex->mmio);
+ sysbus_init_mmio(sbd, &s->mmio);
+
+ pci->bus = pci_register_bus(dev, s->name, xilinx_pcie_set_irq,
+ pci_swizzle_map_irq_fn, s, &s->mmio,
+ &s->io, 0, 4, TYPE_PCIE_BUS);
+
+ qdev_set_parent_bus(DEVICE(&s->root), BUS(pci->bus));
+ qdev_init_nofail(DEVICE(&s->root));
+}
+
+static const char *xilinx_pcie_host_root_bus_path(PCIHostState *host_bridge,
+ PCIBus *rootbus)
+{
+ return "0000:00";
+}
+
+static void xilinx_pcie_host_init(Object *obj)
+{
+ XilinxPCIEHost *s = XILINX_PCIE_HOST(obj);
+ XilinxPCIERoot *root = &s->root;
+
+ object_initialize(root, sizeof(*root), TYPE_XILINX_PCIE_ROOT);
+ object_property_add_child(obj, "root", OBJECT(root), NULL);
+ qdev_prop_set_uint32(DEVICE(root), "addr", PCI_DEVFN(0, 0));
+ qdev_prop_set_bit(DEVICE(root), "multifunction", false);
+}
+
+static Property xilinx_pcie_host_props[] = {
+ DEFINE_PROP_UINT32("bus_nr", XilinxPCIEHost, bus_nr, 0),
+ DEFINE_PROP_SIZE("cfg_base", XilinxPCIEHost, cfg_base, 0),
+ DEFINE_PROP_SIZE("cfg_size", XilinxPCIEHost, cfg_size, 32 << 20),
+ DEFINE_PROP_SIZE("mmio_base", XilinxPCIEHost, mmio_base, 0),
+ DEFINE_PROP_SIZE("mmio_size", XilinxPCIEHost, mmio_size, 1 << 20),
+ DEFINE_PROP_BOOL("link_up", XilinxPCIEHost, link_up, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_pcie_host_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
+
+ hc->root_bus_path = xilinx_pcie_host_root_bus_path;
+ dc->realize = xilinx_pcie_host_realize;
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->fw_name = "pci";
+ dc->props = xilinx_pcie_host_props;
+}
+
+static const TypeInfo xilinx_pcie_host_info = {
+ .name = TYPE_XILINX_PCIE_HOST,
+ .parent = TYPE_PCIE_HOST_BRIDGE,
+ .instance_size = sizeof(XilinxPCIEHost),
+ .instance_init = xilinx_pcie_host_init,
+ .class_init = xilinx_pcie_host_class_init,
+};
+
+static uint32_t xilinx_pcie_root_config_read(PCIDevice *d,
+ uint32_t address, int len)
+{
+ XilinxPCIEHost *s = XILINX_PCIE_HOST(OBJECT(d)->parent);
+ uint32_t val;
+
+ switch (address) {
+ case ROOTCFG_INTDEC:
+ val = s->intr;
+ break;
+ case ROOTCFG_INTMASK:
+ val = s->intr_mask;
+ break;
+ case ROOTCFG_PSCR:
+ val = s->link_up ? ROOTCFG_PSCR_LINK_UP : 0;
+ break;
+ case ROOTCFG_RPSCR:
+ if (s->intr_fifo_r != s->intr_fifo_w) {
+ s->rpscr &= ~ROOTCFG_RPSCR_INTNEMPTY;
+ } else {
+ s->rpscr |= ROOTCFG_RPSCR_INTNEMPTY;
+ }
+ val = s->rpscr;
+ break;
+ case ROOTCFG_RPIFR1:
+ if (s->intr_fifo_w == s->intr_fifo_r) {
+ /* FIFO empty */
+ val = 0;
+ } else {
+ val = s->intr_fifo[s->intr_fifo_r].fifo_reg1;
+ }
+ break;
+ case ROOTCFG_RPIFR2:
+ if (s->intr_fifo_w == s->intr_fifo_r) {
+ /* FIFO empty */
+ val = 0;
+ } else {
+ val = s->intr_fifo[s->intr_fifo_r].fifo_reg2;
+ }
+ break;
+ default:
+ val = pci_default_read_config(d, address, len);
+ break;
+ }
+ return val;
+}
+
+static void xilinx_pcie_root_config_write(PCIDevice *d, uint32_t address,
+ uint32_t val, int len)
+{
+ XilinxPCIEHost *s = XILINX_PCIE_HOST(OBJECT(d)->parent);
+ switch (address) {
+ case ROOTCFG_INTDEC:
+ xilinx_pcie_update_intr(s, 0, val);
+ break;
+ case ROOTCFG_INTMASK:
+ s->intr_mask = val;
+ xilinx_pcie_update_intr(s, 0, 0);
+ break;
+ case ROOTCFG_RPSCR:
+ s->rpscr &= ~ROOTCFG_RPSCR_BRIDGEEN;
+ s->rpscr |= val & ROOTCFG_RPSCR_BRIDGEEN;
+ memory_region_set_enabled(&s->mmio, val & ROOTCFG_RPSCR_BRIDGEEN);
+
+ if (val & ROOTCFG_INTMASK_INTX) {
+ s->rpscr &= ~ROOTCFG_INTMASK_INTX;
+ }
+ break;
+ case ROOTCFG_RPIFR1:
+ case ROOTCFG_RPIFR2:
+ if (s->intr_fifo_w == s->intr_fifo_r) {
+ /* FIFO empty */
+ return;
+ } else {
+ s->intr_fifo_r = (s->intr_fifo_r + 1) % ARRAY_SIZE(s->intr_fifo);
+ }
+ break;
+ default:
+ pci_default_write_config(d, address, val, len);
+ break;
+ }
+}
+
+static int xilinx_pcie_root_init(PCIDevice *dev)
+{
+ BusState *bus = qdev_get_parent_bus(DEVICE(dev));
+ XilinxPCIEHost *s = XILINX_PCIE_HOST(bus->parent);
+
+ pci_set_word(dev->config + PCI_COMMAND,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ pci_set_word(dev->config + PCI_MEMORY_BASE, s->mmio_base >> 16);
+ pci_set_word(dev->config + PCI_MEMORY_LIMIT,
+ ((s->mmio_base + s->mmio_size - 1) >> 16) & 0xfff0);
+
+ pci_bridge_initfn(dev, TYPE_PCI_BUS);
+
+ if (pcie_endpoint_cap_v1_init(dev, 0x80) < 0) {
+ hw_error("Failed to initialize PCIe capability");
+ }
+
+ return 0;
+}
+
+static void xilinx_pcie_root_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->desc = "Xilinx AXI-PCIe Host Bridge";
+ k->vendor_id = PCI_VENDOR_ID_XILINX;
+ k->device_id = 0x7021;
+ k->revision = 0;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+ k->is_express = true;
+ k->is_bridge = true;
+ k->init = xilinx_pcie_root_init;
+ k->exit = pci_bridge_exitfn;
+ dc->reset = pci_bridge_reset;
+ k->config_read = xilinx_pcie_root_config_read;
+ k->config_write = xilinx_pcie_root_config_write;
+ /*
+ * PCI-facing part of the host bridge, not usable without the
+ * host-facing part, which can't be device_add'ed, yet.
+ */
+ dc->cannot_instantiate_with_device_add_yet = true;
+}
+
+static const TypeInfo xilinx_pcie_root_info = {
+ .name = TYPE_XILINX_PCIE_ROOT,
+ .parent = TYPE_PCI_BRIDGE,
+ .instance_size = sizeof(XilinxPCIERoot),
+ .class_init = xilinx_pcie_root_class_init,
+};
+
+static void xilinx_pcie_register(void)
+{
+ type_register_static(&xilinx_pcie_root_info);
+ type_register_static(&xilinx_pcie_host_info);
+}
+
+type_init(xilinx_pcie_register)
diff --git a/hw/timer/mips_gictimer.c b/hw/timer/mips_gictimer.c
index 3698889475..f5c5806724 100644
--- a/hw/timer/mips_gictimer.c
+++ b/hw/timer/mips_gictimer.c
@@ -14,6 +14,11 @@
#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
+uint32_t mips_gictimer_get_freq(MIPSGICTimerState *gic)
+{
+ return NANOSECONDS_PER_SECOND / TIMER_PERIOD;
+}
+
static void gic_vptimer_update(MIPSGICTimerState *gictimer,
uint32_t vp_index, uint64_t now)
{
diff --git a/include/hw/loader-fit.h b/include/hw/loader-fit.h
new file mode 100644
index 0000000000..9e2a068a20
--- /dev/null
+++ b/include/hw/loader-fit.h
@@ -0,0 +1,41 @@
+/*
+ * Flattened Image Tree loader.
+ *
+ * Copyright (c) 2016 Imagination Technologies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_LOADER_FIT_H
+#define HW_LOADER_FIT_H
+
+#include <exec/hwaddr.h>
+
+struct fit_loader_match {
+ const char *compatible;
+ const void *data;
+};
+
+struct fit_loader {
+ const struct fit_loader_match *matches;
+ hwaddr (*addr_to_phys)(void *opaque, uint64_t addr);
+ const void *(*fdt_filter)(void *opaque, const void *fdt,
+ const void *match_data, hwaddr *load_addr);
+ const void *(*kernel_filter)(void *opaque, const void *kernel,
+ hwaddr *load_addr, hwaddr *entry_addr);
+};
+
+int load_fit(const struct fit_loader *ldr, const char *filename, void *opaque);
+
+#endif /* HW_LOADER_FIT_H */
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 0dbd8d6bf3..40c4153e58 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -164,6 +164,8 @@ int load_uimage(const char *filename, hwaddr *ep,
*/
int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz);
+ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, size_t srclen);
+
ssize_t read_targphys(const char *name,
int fd, hwaddr dst_addr, size_t nbytes);
void pstrcpy_targphys(const char *name,
@@ -214,4 +216,8 @@ void hmp_info_roms(Monitor *mon, const QDict *qdict);
int rom_add_vga(const char *file);
int rom_add_option(const char *file, int32_t bootindex);
+/* This is the usual maximum in uboot, so if a uImage overflows this, it would
+ * overflow on real hardware too. */
+#define UBOOT_MAX_GUNZIP_BYTES (64 << 20)
+
#endif
diff --git a/include/hw/misc/mips_cmgcr.h b/include/hw/misc/mips_cmgcr.h
index a209d91ded..c9dfcb4b84 100644
--- a/include/hw/misc/mips_cmgcr.h
+++ b/include/hw/misc/mips_cmgcr.h
@@ -41,6 +41,9 @@
#define GCR_L2_CONFIG_BYPASS_SHF 20
#define GCR_L2_CONFIG_BYPASS_MSK ((0x1ULL) << GCR_L2_CONFIG_BYPASS_SHF)
+/* GCR_BASE register fields */
+#define GCR_BASE_GCRBASE_MSK 0xffffffff8000ULL
+
/* GCR_GIC_BASE register fields */
#define GCR_GIC_BASE_GICEN_MSK 1
#define GCR_GIC_BASE_GICBASE_MSK 0xFFFFFFFE0000ULL
diff --git a/include/hw/pci-host/xilinx-pcie.h b/include/hw/pci-host/xilinx-pcie.h
new file mode 100644
index 0000000000..bec66b27c5
--- /dev/null
+++ b/include/hw/pci-host/xilinx-pcie.h
@@ -0,0 +1,68 @@
+/*
+ * Xilinx PCIe host controller emulation.
+ *
+ * Copyright (c) 2016 Imagination Technologies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_XILINX_PCIE_H
+#define HW_XILINX_PCIE_H
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/pci/pcie_host.h"
+
+#define TYPE_XILINX_PCIE_HOST "xilinx-pcie-host"
+#define XILINX_PCIE_HOST(obj) \
+ OBJECT_CHECK(XilinxPCIEHost, (obj), TYPE_XILINX_PCIE_HOST)
+
+#define TYPE_XILINX_PCIE_ROOT "xilinx-pcie-root"
+#define XILINX_PCIE_ROOT(obj) \
+ OBJECT_CHECK(XilinxPCIERoot, (obj), TYPE_XILINX_PCIE_ROOT)
+
+typedef struct XilinxPCIERoot {
+ PCIBridge parent_obj;
+} XilinxPCIERoot;
+
+typedef struct XilinxPCIEInt {
+ uint32_t fifo_reg1;
+ uint32_t fifo_reg2;
+} XilinxPCIEInt;
+
+typedef struct XilinxPCIEHost {
+ PCIExpressHost parent_obj;
+
+ char name[16];
+
+ uint32_t bus_nr;
+ uint64_t cfg_base, cfg_size;
+ uint64_t mmio_base, mmio_size;
+ bool link_up;
+ qemu_irq irq;
+
+ MemoryRegion mmio, io;
+
+ XilinxPCIERoot root;
+
+ uint32_t intr;
+ uint32_t intr_mask;
+ XilinxPCIEInt intr_fifo[16];
+ unsigned int intr_fifo_r, intr_fifo_w;
+ uint32_t rpscr;
+} XilinxPCIEHost;
+
+#endif /* HW_XILINX_PCIE_H */
diff --git a/include/hw/timer/mips_gictimer.h b/include/hw/timer/mips_gictimer.h
index c8bc5d2541..c7ca6c821d 100644
--- a/include/hw/timer/mips_gictimer.h
+++ b/include/hw/timer/mips_gictimer.h
@@ -31,6 +31,7 @@ struct MIPSGICTimerState {
MIPSGICTimerCB *cb;
};
+uint32_t mips_gictimer_get_freq(MIPSGICTimerState *gic);
uint32_t mips_gictimer_get_sh_count(MIPSGICTimerState *gic);
void mips_gictimer_store_sh_count(MIPSGICTimerState *gic, uint64_t count);
uint32_t mips_gictimer_get_vp_compare(MIPSGICTimerState *gictimer,
diff --git a/iothread.c b/iothread.c
index 257b01d5f1..beeb870534 100644
--- a/iothread.c
+++ b/iothread.c
@@ -268,6 +268,9 @@ static int query_one_iothread(Object *object, void *opaque)
info = g_new0(IOThreadInfo, 1);
info->id = iothread_get_id(iothread);
info->thread_id = iothread->thread_id;
+ info->poll_max_ns = iothread->poll_max_ns;
+ info->poll_grow = iothread->poll_grow;
+ info->poll_shrink = iothread->poll_shrink;
elem = g_new0(IOThreadInfoList, 1);
elem->value = info;
diff --git a/monitor.c b/monitor.c
index 18bf2f8e4a..ead4c633fb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1026,6 +1026,9 @@ int monitor_set_cpu(int cpu_index)
CPUState *mon_get_cpu(void)
{
if (!cur_mon->mon_cpu) {
+ if (!first_cpu) {
+ return NULL;
+ }
monitor_set_cpu(first_cpu->cpu_index);
}
cpu_synchronize_state(cur_mon->mon_cpu);
@@ -1034,17 +1037,27 @@ CPUState *mon_get_cpu(void)
CPUArchState *mon_get_cpu_env(void)
{
- return mon_get_cpu()->env_ptr;
+ CPUState *cs = mon_get_cpu();
+
+ return cs ? cs->env_ptr : NULL;
}
int monitor_get_cpu_index(void)
{
- return mon_get_cpu()->cpu_index;
+ CPUState *cs = mon_get_cpu();
+
+ return cs ? cs->cpu_index : UNASSIGNED_CPU_INDEX;
}
static void hmp_info_registers(Monitor *mon, const QDict *qdict)
{
- cpu_dump_state(mon_get_cpu(), (FILE *)mon, monitor_fprintf, CPU_DUMP_FPU);
+ CPUState *cs = mon_get_cpu();
+
+ if (!cs) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
+ cpu_dump_state(cs, (FILE *)mon, monitor_fprintf, CPU_DUMP_FPU);
}
static void hmp_info_jit(Monitor *mon, const QDict *qdict)
@@ -1077,7 +1090,13 @@ static void hmp_info_history(Monitor *mon, const QDict *qdict)
static void hmp_info_cpustats(Monitor *mon, const QDict *qdict)
{
- cpu_dump_statistics(mon_get_cpu(), (FILE *)mon, &monitor_fprintf, 0);
+ CPUState *cs = mon_get_cpu();
+
+ if (!cs) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
+ cpu_dump_statistics(cs, (FILE *)mon, &monitor_fprintf, 0);
}
static void hmp_info_trace_events(Monitor *mon, const QDict *qdict)
@@ -1236,6 +1255,12 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize,
int l, line_size, i, max_digits, len;
uint8_t buf[16];
uint64_t v;
+ CPUState *cs = mon_get_cpu();
+
+ if (!cs && (format == 'i' || !is_physical)) {
+ monitor_printf(mon, "Can not dump without CPU\n");
+ return;
+ }
if (format == 'i') {
int flags = 0;
@@ -1265,7 +1290,7 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize,
flags = msr_le << 16;
flags |= env->bfd_mach;
#endif
- monitor_disas(mon, mon_get_cpu(), addr, count, is_physical, flags);
+ monitor_disas(mon, cs, addr, count, is_physical, flags);
return;
}
@@ -1304,7 +1329,7 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize,
if (is_physical) {
cpu_physical_memory_read(addr, buf, l);
} else {
- if (cpu_memory_rw_debug(mon_get_cpu(), addr, buf, l, 0) < 0) {
+ if (cpu_memory_rw_debug(cs, addr, buf, l, 0) < 0) {
monitor_printf(mon, " Cannot access memory\n");
break;
}
@@ -2189,11 +2214,12 @@ expr_error(Monitor *mon, const char *fmt, ...)
static int get_monitor_def(target_long *pval, const char *name)
{
const MonitorDef *md = target_monitor_defs();
+ CPUState *cs = mon_get_cpu();
void *ptr;
uint64_t tmp = 0;
int ret;
- if (md == NULL) {
+ if (cs == NULL || md == NULL) {
return -1;
}
@@ -2220,7 +2246,7 @@ static int get_monitor_def(target_long *pval, const char *name)
}
}
- ret = target_get_monitor_def(mon_get_cpu(), name, &tmp);
+ ret = target_get_monitor_def(cs, name, &tmp);
if (!ret) {
*pval = (target_long) tmp;
}
diff --git a/qapi-schema.json b/qapi-schema.json
index e9a6364b7d..f6ca18c3be 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1427,10 +1427,23 @@
#
# @thread-id: ID of the underlying host thread
#
+# @poll-max-ns: maximum polling time in ns, 0 means polling is disabled
+# (since 2.9)
+#
+# @poll-grow: how many ns will be added to polling time, 0 means that it's not
+# configured (since 2.9)
+#
+# @poll-shrink: how many ns will be removed from polling time, 0 means that
+# it's not configured (since 2.9)
+#
# Since: 2.0
##
{ 'struct': 'IOThreadInfo',
- 'data': {'id': 'str', 'thread-id': 'int'} }
+ 'data': {'id': 'str',
+ 'thread-id': 'int',
+ 'poll-max-ns': 'int',
+ 'poll-grow': 'int',
+ 'poll-shrink': 'int' } }
##
# @query-iothreads:
diff --git a/target/i386/monitor.c b/target/i386/monitor.c
index 468aa073bc..77ead60437 100644
--- a/target/i386/monitor.c
+++ b/target/i386/monitor.c
@@ -210,6 +210,10 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict)
CPUArchState *env;
env = mon_get_cpu_env();
+ if (!env) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
if (!(env->cr[0] & CR0_PG_MASK)) {
monitor_printf(mon, "PG disabled\n");
@@ -529,6 +533,10 @@ void hmp_info_mem(Monitor *mon, const QDict *qdict)
CPUArchState *env;
env = mon_get_cpu_env();
+ if (!env) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
if (!(env->cr[0] & CR0_PG_MASK)) {
monitor_printf(mon, "PG disabled\n");
@@ -624,7 +632,13 @@ const MonitorDef *target_monitor_defs(void)
void hmp_info_local_apic(Monitor *mon, const QDict *qdict)
{
- x86_cpu_dump_local_apic_state(mon_get_cpu(), (FILE *)mon, monitor_fprintf,
+ CPUState *cs = mon_get_cpu();
+
+ if (!cs) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
+ x86_cpu_dump_local_apic_state(cs, (FILE *)mon, monitor_fprintf,
CPU_DUMP_FPU);
}
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index e1c78f55ec..4a4747af25 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -815,6 +815,7 @@ int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc);
#define cpu_init(cpu_model) CPU(cpu_mips_init(cpu_model))
bool cpu_supports_cps_smp(const char *cpu_model);
+bool cpu_supports_isa(const char *cpu_model, unsigned int isa);
void cpu_set_exception_base(int vp_index, target_ulong address);
/* TODO QOM'ify CPU reset and remove */
diff --git a/target/mips/translate.c b/target/mips/translate.c
index 7f8ecf42c2..8b4a072ecb 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -20233,6 +20233,16 @@ bool cpu_supports_cps_smp(const char *cpu_model)
return (def->CP0_Config3 & (1 << CP0C3_CMGCR)) != 0;
}
+bool cpu_supports_isa(const char *cpu_model, unsigned int isa)
+{
+ const mips_def_t *def = cpu_mips_find_by_name(cpu_model);
+ if (!def) {
+ return false;
+ }
+
+ return (def->insn_flags & isa) != 0;
+}
+
void cpu_set_exception_base(int vp_index, target_ulong address)
{
MIPSCPU *vp = MIPS_CPU(qemu_get_cpu(vp_index));
diff --git a/target/ppc/monitor.c b/target/ppc/monitor.c
index c2d0806dd1..b8f30e9eaf 100644
--- a/target/ppc/monitor.c
+++ b/target/ppc/monitor.c
@@ -62,6 +62,10 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict)
{
CPUArchState *env1 = mon_get_cpu_env();
+ if (!env1) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1);
}
diff --git a/target/sh4/monitor.c b/target/sh4/monitor.c
index 426e5d4914..4c7f36c9cc 100644
--- a/target/sh4/monitor.c
+++ b/target/sh4/monitor.c
@@ -44,6 +44,11 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict)
CPUArchState *env = mon_get_cpu_env();
int i;
+ if (!env) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
+
monitor_printf (mon, "ITLB:\n");
for (i = 0 ; i < ITLB_SIZE ; i++)
print_tlb (mon, i, &env->itlb[i]);
diff --git a/target/sparc/monitor.c b/target/sparc/monitor.c
index 7cc1b0f87f..f3ca524ae9 100644
--- a/target/sparc/monitor.c
+++ b/target/sparc/monitor.c
@@ -32,6 +32,10 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict)
{
CPUArchState *env1 = mon_get_cpu_env();
+ if (!env1) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1);
}
diff --git a/target/xtensa/monitor.c b/target/xtensa/monitor.c
index f3fa4cd278..2ee2b5b23e 100644
--- a/target/xtensa/monitor.c
+++ b/target/xtensa/monitor.c
@@ -31,5 +31,9 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict)
{
CPUArchState *env1 = mon_get_cpu_env();
+ if (!env1) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1);
}