aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpus.c52
-rw-r--r--device_tree.c30
-rw-r--r--device_tree.h4
-rw-r--r--docs/usb-storage.txt2
-rw-r--r--hw/arm-misc.h2
-rw-r--r--hw/arm/Makefile.objs2
-rw-r--r--hw/arm_boot.c46
-rw-r--r--hw/exynos4210.c27
-rw-r--r--hw/exynos4210.h3
-rw-r--r--hw/exynos4210_i2c.c334
-rw-r--r--hw/exynos4210_rtc.c7
-rw-r--r--hw/mfi.h92
-rw-r--r--hw/pl011.c4
-rw-r--r--hw/ppce500_spin.c2
-rw-r--r--hw/qdev.h11
-rw-r--r--hw/spapr_pci.c2
-rw-r--r--hw/vexpress.c13
-rw-r--r--monitor.c16
-rw-r--r--qemu-common.h1
-rw-r--r--qemu-options.hx4
-rwxr-xr-xscripts/simpletrace.py116
-rw-r--r--scripts/tracetool/backend/simple.py90
-rw-r--r--target-i386/cpu.c2
-rw-r--r--trace/control.c3
-rw-r--r--trace/simple.c271
-rw-r--r--trace/simple.h40
26 files changed, 879 insertions, 297 deletions
diff --git a/cpus.c b/cpus.c
index b182b3d7d9..756e6245fd 100644
--- a/cpus.c
+++ b/cpus.c
@@ -61,6 +61,32 @@
static CPUArchState *next_cpu;
+static bool cpu_thread_is_idle(CPUArchState *env)
+{
+ if (env->stop || env->queued_work_first) {
+ return false;
+ }
+ if (env->stopped || !runstate_is_running()) {
+ return true;
+ }
+ if (!env->halted || qemu_cpu_has_work(env) || kvm_irqchip_in_kernel()) {
+ return false;
+ }
+ return true;
+}
+
+static bool all_cpu_threads_idle(void)
+{
+ CPUArchState *env;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ if (!cpu_thread_is_idle(env)) {
+ return false;
+ }
+ }
+ return true;
+}
+
/***********************************************************/
/* guest cycle counter */
@@ -433,32 +459,6 @@ static int cpu_can_run(CPUArchState *env)
return 1;
}
-static bool cpu_thread_is_idle(CPUArchState *env)
-{
- if (env->stop || env->queued_work_first) {
- return false;
- }
- if (env->stopped || !runstate_is_running()) {
- return true;
- }
- if (!env->halted || qemu_cpu_has_work(env) || kvm_irqchip_in_kernel()) {
- return false;
- }
- return true;
-}
-
-bool all_cpu_threads_idle(void)
-{
- CPUArchState *env;
-
- for (env = first_cpu; env != NULL; env = env->next_cpu) {
- if (!cpu_thread_is_idle(env)) {
- return false;
- }
- }
- return true;
-}
-
static void cpu_handle_guest_debug(CPUArchState *env)
{
gdb_set_stop_cpu(env);
diff --git a/device_tree.c b/device_tree.c
index b366fddeaf..d7a9b6bb89 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -178,6 +178,36 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path,
return r;
}
+const void *qemu_devtree_getprop(void *fdt, const char *node_path,
+ const char *property, int *lenp)
+{
+ int len;
+ const void *r;
+ if (!lenp) {
+ lenp = &len;
+ }
+ r = fdt_getprop(fdt, findnode_nofail(fdt, node_path), property, lenp);
+ if (!r) {
+ fprintf(stderr, "%s: Couldn't get %s/%s: %s\n", __func__,
+ node_path, property, fdt_strerror(*lenp));
+ exit(1);
+ }
+ return r;
+}
+
+uint32_t qemu_devtree_getprop_cell(void *fdt, const char *node_path,
+ const char *property)
+{
+ int len;
+ const uint32_t *p = qemu_devtree_getprop(fdt, node_path, property, &len);
+ if (len != 4) {
+ fprintf(stderr, "%s: %s/%s not 4 bytes long (not a cell?)\n",
+ __func__, node_path, property);
+ exit(1);
+ }
+ return be32_to_cpu(*p);
+}
+
uint32_t qemu_devtree_get_phandle(void *fdt, const char *path)
{
uint32_t r;
diff --git a/device_tree.h b/device_tree.h
index 2244270b2d..f7a3e6cfc5 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -28,6 +28,10 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path,
int qemu_devtree_setprop_phandle(void *fdt, const char *node_path,
const char *property,
const char *target_node_path);
+const void *qemu_devtree_getprop(void *fdt, const char *node_path,
+ const char *property, int *lenp);
+uint32_t qemu_devtree_getprop_cell(void *fdt, const char *node_path,
+ const char *property);
uint32_t qemu_devtree_get_phandle(void *fdt, const char *path);
uint32_t qemu_devtree_alloc_phandle(void *fdt);
int qemu_devtree_nop_node(void *fdt, const char *node_path);
diff --git a/docs/usb-storage.txt b/docs/usb-storage.txt
index ff9755920d..e58e849d4d 100644
--- a/docs/usb-storage.txt
+++ b/docs/usb-storage.txt
@@ -2,7 +2,7 @@
qemu usb storage emulation
--------------------------
-Qemu has two emulations for usb storage devices.
+QEMU has two emulations for usb storage devices.
Number one emulates the classic bulk-only transport protocol which is
used by 99% of the usb sticks on the marked today and is called
diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index 1f96229d3c..bdd8fecc99 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -25,7 +25,7 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
/* arm_boot.c */
struct arm_boot_info {
- int ram_size;
+ uint64_t ram_size;
const char *kernel_filename;
const char *kernel_cmdline;
const char *initrd_filename;
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 236786eb5a..c413780784 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -11,7 +11,7 @@ obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
-obj-y += exynos4210_rtc.o
+obj-y += exynos4210_rtc.o exynos4210_i2c.o
obj-y += arm_l2x0.o
obj-y += arm_mptimer.o a15mpcore.o
obj-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index a1e6ddbc1c..a6e9143662 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -216,11 +216,12 @@ static void set_kernel_args_old(const struct arm_boot_info *info)
static int load_dtb(target_phys_addr_t addr, const struct arm_boot_info *binfo)
{
#ifdef CONFIG_FDT
- uint32_t mem_reg_property[] = { cpu_to_be32(binfo->loader_start),
- cpu_to_be32(binfo->ram_size) };
+ uint32_t *mem_reg_property;
+ uint32_t mem_reg_propsize;
void *fdt = NULL;
char *filename;
int size, rc;
+ uint32_t acells, scells, hival;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename);
if (!filename) {
@@ -236,8 +237,36 @@ static int load_dtb(target_phys_addr_t addr, const struct arm_boot_info *binfo)
}
g_free(filename);
+ acells = qemu_devtree_getprop_cell(fdt, "/", "#address-cells");
+ scells = qemu_devtree_getprop_cell(fdt, "/", "#size-cells");
+ if (acells == 0 || scells == 0) {
+ fprintf(stderr, "dtb file invalid (#address-cells or #size-cells 0)\n");
+ return -1;
+ }
+
+ mem_reg_propsize = acells + scells;
+ mem_reg_property = g_new0(uint32_t, mem_reg_propsize);
+ mem_reg_property[acells - 1] = cpu_to_be32(binfo->loader_start);
+ hival = cpu_to_be32(binfo->loader_start >> 32);
+ if (acells > 1) {
+ mem_reg_property[acells - 2] = hival;
+ } else if (hival != 0) {
+ fprintf(stderr, "qemu: dtb file not compatible with "
+ "RAM start address > 4GB\n");
+ exit(1);
+ }
+ mem_reg_property[acells + scells - 1] = cpu_to_be32(binfo->ram_size);
+ hival = cpu_to_be32(binfo->ram_size >> 32);
+ if (scells > 1) {
+ mem_reg_property[acells + scells - 2] = hival;
+ } else if (hival != 0) {
+ fprintf(stderr, "qemu: dtb file not compatible with "
+ "RAM size > 4GB\n");
+ exit(1);
+ }
+
rc = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
- sizeof(mem_reg_property));
+ mem_reg_propsize * sizeof(uint32_t));
if (rc < 0) {
fprintf(stderr, "couldn't set /memory/reg\n");
}
@@ -357,7 +386,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
if (kernel_size < 0) {
entry = info->loader_start + KERNEL_LOAD_ADDR;
kernel_size = load_image_targphys(info->kernel_filename, entry,
- ram_size - KERNEL_LOAD_ADDR);
+ info->ram_size - KERNEL_LOAD_ADDR);
is_linux = 1;
}
if (kernel_size < 0) {
@@ -371,7 +400,8 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
initrd_size = load_image_targphys(info->initrd_filename,
info->loader_start
+ INITRD_LOAD_ADDR,
- ram_size - INITRD_LOAD_ADDR);
+ info->ram_size
+ - INITRD_LOAD_ADDR);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initrd '%s'\n",
info->initrd_filename);
@@ -398,6 +428,12 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
bootloader[5] = dtb_start;
} else {
bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR;
+ if (info->ram_size >= (1ULL << 32)) {
+ fprintf(stderr, "qemu: RAM size must be less than 4GB to boot"
+ " Linux kernel using ATAGS (try passing a device tree"
+ " using -dtb)\n");
+ exit(1);
+ }
}
bootloader[6] = entry;
for (n = 0; n < sizeof(bootloader) / 4; n++) {
diff --git a/hw/exynos4210.c b/hw/exynos4210.c
index 7c58c906de..00d4db8871 100644
--- a/hw/exynos4210.c
+++ b/hw/exynos4210.c
@@ -39,6 +39,13 @@
/* MCT */
#define EXYNOS4210_MCT_BASE_ADDR 0x10050000
+/* I2C */
+#define EXYNOS4210_I2C_SHIFT 0x00010000
+#define EXYNOS4210_I2C_BASE_ADDR 0x13860000
+/* Interrupt Group of External Interrupt Combiner for I2C */
+#define EXYNOS4210_I2C_INTG 27
+#define EXYNOS4210_HDMI_INTG 16
+
/* UART's definitions */
#define EXYNOS4210_UART0_BASE_ADDR 0x13800000
#define EXYNOS4210_UART1_BASE_ADDR 0x13810000
@@ -283,6 +290,26 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
s->irq_table[exynos4210_get_irq(35, 3)]);
sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR);
+ /*** I2C ***/
+ for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) {
+ uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n;
+ qemu_irq i2c_irq;
+
+ if (n < 8) {
+ i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)];
+ } else {
+ i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)];
+ }
+
+ dev = qdev_create(NULL, "exynos4210.i2c");
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ sysbus_connect_irq(busdev, 0, i2c_irq);
+ sysbus_mmio_map(busdev, 0, addr);
+ s->i2c_if[n] = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
+ }
+
+
/*** UARTs ***/
exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
EXYNOS4210_UART0_FIFO_SIZE, 0, NULL,
diff --git a/hw/exynos4210.h b/hw/exynos4210.h
index 9b1ae4c8b1..a43ba3aedc 100644
--- a/hw/exynos4210.h
+++ b/hw/exynos4210.h
@@ -74,6 +74,8 @@
#define EXYNOS4210_EXT_GIC_NIRQ (160-32)
#define EXYNOS4210_INT_GIC_NIRQ 64
+#define EXYNOS4210_I2C_NUMBER 9
+
typedef struct Exynos4210Irq {
qemu_irq int_combiner_irq[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ];
qemu_irq ext_combiner_irq[EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ];
@@ -95,6 +97,7 @@ typedef struct Exynos4210State {
MemoryRegion dram1_mem;
MemoryRegion boot_secondary;
MemoryRegion bootreg_mem;
+ i2c_bus *i2c_if[EXYNOS4210_I2C_NUMBER];
} Exynos4210State;
void exynos4210_write_secondary(ARMCPU *cpu,
diff --git a/hw/exynos4210_i2c.c b/hw/exynos4210_i2c.c
new file mode 100644
index 0000000000..3f72a5c464
--- /dev/null
+++ b/hw/exynos4210_i2c.c
@@ -0,0 +1,334 @@
+/*
+ * Exynos4210 I2C Bus Serial Interface Emulation
+ *
+ * Copyright (C) 2012 Samsung Electronics Co Ltd.
+ * Maksim Kozlov, <m.kozlov@samsung.com>
+ * Igor Mitsyanko, <i.mitsyanko@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu-timer.h"
+#include "sysbus.h"
+#include "i2c.h"
+
+#ifndef EXYNOS4_I2C_DEBUG
+#define EXYNOS4_I2C_DEBUG 0
+#endif
+
+#define TYPE_EXYNOS4_I2C "exynos4210.i2c"
+#define EXYNOS4_I2C(obj) \
+ OBJECT_CHECK(Exynos4210I2CState, (obj), TYPE_EXYNOS4_I2C)
+
+/* Exynos4210 I2C memory map */
+#define EXYNOS4_I2C_MEM_SIZE 0x14
+#define I2CCON_ADDR 0x00 /* control register */
+#define I2CSTAT_ADDR 0x04 /* control/status register */
+#define I2CADD_ADDR 0x08 /* address register */
+#define I2CDS_ADDR 0x0c /* data shift register */
+#define I2CLC_ADDR 0x10 /* line control register */
+
+#define I2CCON_ACK_GEN (1 << 7)
+#define I2CCON_INTRS_EN (1 << 5)
+#define I2CCON_INT_PEND (1 << 4)
+
+#define EXYNOS4_I2C_MODE(reg) (((reg) >> 6) & 3)
+#define I2C_IN_MASTER_MODE(reg) (((reg) >> 6) & 2)
+#define I2CMODE_MASTER_Rx 0x2
+#define I2CMODE_MASTER_Tx 0x3
+#define I2CSTAT_LAST_BIT (1 << 0)
+#define I2CSTAT_OUTPUT_EN (1 << 4)
+#define I2CSTAT_START_BUSY (1 << 5)
+
+
+#if EXYNOS4_I2C_DEBUG
+#define DPRINT(fmt, args...) \
+ do { fprintf(stderr, "QEMU I2C: "fmt, ## args); } while (0)
+
+static const char *exynos4_i2c_get_regname(unsigned offset)
+{
+ switch (offset) {
+ case I2CCON_ADDR:
+ return "I2CCON";
+ case I2CSTAT_ADDR:
+ return "I2CSTAT";
+ case I2CADD_ADDR:
+ return "I2CADD";
+ case I2CDS_ADDR:
+ return "I2CDS";
+ case I2CLC_ADDR:
+ return "I2CLC";
+ default:
+ return "[?]";
+ }
+}
+
+#else
+#define DPRINT(fmt, args...) do { } while (0)
+#endif
+
+typedef struct Exynos4210I2CState {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ i2c_bus *bus;
+ qemu_irq irq;
+
+ uint8_t i2ccon;
+ uint8_t i2cstat;
+ uint8_t i2cadd;
+ uint8_t i2cds;
+ uint8_t i2clc;
+ bool scl_free;
+} Exynos4210I2CState;
+
+static inline void exynos4210_i2c_raise_interrupt(Exynos4210I2CState *s)
+{
+ if (s->i2ccon & I2CCON_INTRS_EN) {
+ s->i2ccon |= I2CCON_INT_PEND;
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static void exynos4210_i2c_data_receive(void *opaque)
+{
+ Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
+ int ret;
+
+ s->i2cstat &= ~I2CSTAT_LAST_BIT;
+ s->scl_free = false;
+ ret = i2c_recv(s->bus);
+ if (ret < 0 && (s->i2ccon & I2CCON_ACK_GEN)) {
+ s->i2cstat |= I2CSTAT_LAST_BIT; /* Data is not acknowledged */
+ } else {
+ s->i2cds = ret;
+ }
+ exynos4210_i2c_raise_interrupt(s);
+}
+
+static void exynos4210_i2c_data_send(void *opaque)
+{
+ Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
+
+ s->i2cstat &= ~I2CSTAT_LAST_BIT;
+ s->scl_free = false;
+ if (i2c_send(s->bus, s->i2cds) < 0 && (s->i2ccon & I2CCON_ACK_GEN)) {
+ s->i2cstat |= I2CSTAT_LAST_BIT;
+ }
+ exynos4210_i2c_raise_interrupt(s);
+}
+
+static uint64_t exynos4210_i2c_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
+ uint8_t value;
+
+ switch (offset) {
+ case I2CCON_ADDR:
+ value = s->i2ccon;
+ break;
+ case I2CSTAT_ADDR:
+ value = s->i2cstat;
+ break;
+ case I2CADD_ADDR:
+ value = s->i2cadd;
+ break;
+ case I2CDS_ADDR:
+ value = s->i2cds;
+ s->scl_free = true;
+ if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx &&
+ (s->i2cstat & I2CSTAT_START_BUSY) &&
+ !(s->i2ccon & I2CCON_INT_PEND)) {
+ exynos4210_i2c_data_receive(s);
+ }
+ break;
+ case I2CLC_ADDR:
+ value = s->i2clc;
+ break;
+ default:
+ value = 0;
+ DPRINT("ERROR: Bad read offset 0x%x\n", (unsigned int)offset);
+ break;
+ }
+
+ DPRINT("read %s [0x%02x] -> 0x%02x\n", exynos4_i2c_get_regname(offset),
+ (unsigned int)offset, value);
+ return value;
+}
+
+static void exynos4210_i2c_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
+ uint8_t v = value & 0xff;
+
+ DPRINT("write %s [0x%02x] <- 0x%02x\n", exynos4_i2c_get_regname(offset),
+ (unsigned int)offset, v);
+
+ switch (offset) {
+ case I2CCON_ADDR:
+ s->i2ccon = (v & ~I2CCON_INT_PEND) | (s->i2ccon & I2CCON_INT_PEND);
+ if ((s->i2ccon & I2CCON_INT_PEND) && !(v & I2CCON_INT_PEND)) {
+ s->i2ccon &= ~I2CCON_INT_PEND;
+ qemu_irq_lower(s->irq);
+ if (!(s->i2ccon & I2CCON_INTRS_EN)) {
+ s->i2cstat &= ~I2CSTAT_START_BUSY;
+ }
+
+ if (s->i2cstat & I2CSTAT_START_BUSY) {
+ if (s->scl_free) {
+ if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx) {
+ exynos4210_i2c_data_send(s);
+ } else if (EXYNOS4_I2C_MODE(s->i2cstat) ==
+ I2CMODE_MASTER_Rx) {
+ exynos4210_i2c_data_receive(s);
+ }
+ } else {
+ s->i2ccon |= I2CCON_INT_PEND;
+ qemu_irq_raise(s->irq);
+ }
+ }
+ }
+ break;
+ case I2CSTAT_ADDR:
+ s->i2cstat =
+ (s->i2cstat & I2CSTAT_START_BUSY) | (v & ~I2CSTAT_START_BUSY);
+
+ if (!(s->i2cstat & I2CSTAT_OUTPUT_EN)) {
+ s->i2cstat &= ~I2CSTAT_START_BUSY;
+ s->scl_free = true;
+ qemu_irq_lower(s->irq);
+ break;
+ }
+
+ /* Nothing to do if in i2c slave mode */
+ if (!I2C_IN_MASTER_MODE(s->i2cstat)) {
+ break;
+ }
+
+ if (v & I2CSTAT_START_BUSY) {
+ s->i2cstat &= ~I2CSTAT_LAST_BIT;
+ s->i2cstat |= I2CSTAT_START_BUSY; /* Line is busy */
+ s->scl_free = false;
+
+ /* Generate start bit and send slave address */
+ if (i2c_start_transfer(s->bus, s->i2cds >> 1, s->i2cds & 0x1) &&
+ (s->i2ccon & I2CCON_ACK_GEN)) {
+ s->i2cstat |= I2CSTAT_LAST_BIT;
+ } else if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx) {
+ exynos4210_i2c_data_receive(s);
+ }
+ exynos4210_i2c_raise_interrupt(s);
+ } else {
+ i2c_end_transfer(s->bus);
+ if (!(s->i2ccon & I2CCON_INT_PEND)) {
+ s->i2cstat &= ~I2CSTAT_START_BUSY;
+ }
+ s->scl_free = true;
+ }
+ break;
+ case I2CADD_ADDR:
+ if ((s->i2cstat & I2CSTAT_OUTPUT_EN) == 0) {
+ s->i2cadd = v;
+ }
+ break;
+ case I2CDS_ADDR:
+ if (s->i2cstat & I2CSTAT_OUTPUT_EN) {
+ s->i2cds = v;
+ s->scl_free = true;
+ if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx &&
+ (s->i2cstat & I2CSTAT_START_BUSY) &&
+ !(s->i2ccon & I2CCON_INT_PEND)) {
+ exynos4210_i2c_data_send(s);
+ }
+ }
+ break;
+ case I2CLC_ADDR:
+ s->i2clc = v;
+ break;
+ default:
+ DPRINT("ERROR: Bad write offset 0x%x\n", (unsigned int)offset);
+ break;
+ }
+}
+
+static const MemoryRegionOps exynos4210_i2c_ops = {
+ .read = exynos4210_i2c_read,
+ .write = exynos4210_i2c_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription exynos4210_i2c_vmstate = {
+ .name = TYPE_EXYNOS4_I2C,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(i2ccon, Exynos4210I2CState),
+ VMSTATE_UINT8(i2cstat, Exynos4210I2CState),
+ VMSTATE_UINT8(i2cds, Exynos4210I2CState),
+ VMSTATE_UINT8(i2cadd, Exynos4210I2CState),
+ VMSTATE_UINT8(i2clc, Exynos4210I2CState),
+ VMSTATE_BOOL(scl_free, Exynos4210I2CState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void exynos4210_i2c_reset(DeviceState *d)
+{
+ Exynos4210I2CState *s = EXYNOS4_I2C(d);
+
+ s->i2ccon = 0x00;
+ s->i2cstat = 0x00;
+ s->i2cds = 0xFF;
+ s->i2clc = 0x00;
+ s->i2cadd = 0xFF;
+ s->scl_free = true;
+}
+
+static int exynos4210_i2c_realize(SysBusDevice *dev)
+{
+ Exynos4210I2CState *s = EXYNOS4_I2C(dev);
+
+ memory_region_init_io(&s->iomem, &exynos4210_i2c_ops, s, TYPE_EXYNOS4_I2C,
+ EXYNOS4_I2C_MEM_SIZE);
+ sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_irq(dev, &s->irq);
+ s->bus = i2c_init_bus(&dev->qdev, "i2c");
+ return 0;
+}
+
+static void exynos4210_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ dc->vmsd = &exynos4210_i2c_vmstate;
+ dc->reset = exynos4210_i2c_reset;
+ sbdc->init = exynos4210_i2c_realize;
+}
+
+static const TypeInfo exynos4210_i2c_type_info = {
+ .name = TYPE_EXYNOS4_I2C,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Exynos4210I2CState),
+ .class_init = exynos4210_i2c_class_init,
+};
+
+static void exynos4210_i2c_register_types(void)
+{
+ type_register_static(&exynos4210_i2c_type_info);
+}
+
+type_init(exynos4210_i2c_register_types)
diff --git a/hw/exynos4210_rtc.c b/hw/exynos4210_rtc.c
index f78102049b..42a4ddc327 100644
--- a/hw/exynos4210_rtc.c
+++ b/hw/exynos4210_rtc.c
@@ -142,7 +142,7 @@ static const VMStateDescription vmstate_exynos4210_rtc_state = {
};
#define BCD3DIGITS(x) \
- ((uint32_t)to_bcd((uint8_t)x) + \
+ ((uint32_t)to_bcd((uint8_t)(x % 100)) + \
((uint32_t)to_bcd((uint8_t)((x % 1000) / 100)) << 8))
static void check_alarm_raise(Exynos4210RTCState *s)
@@ -510,10 +510,7 @@ static void exynos4210_rtc_reset(DeviceState *d)
{
Exynos4210RTCState *s = (Exynos4210RTCState *)d;
- struct tm tm;
-
- qemu_get_timedate(&tm, 0);
- s->current_tm = tm;
+ qemu_get_timedate(&s->current_tm, 0);
DPRINTF("Get time from host: %d-%d-%d %2d:%02d:%02d\n",
s->current_tm.tm_year, s->current_tm.tm_mon, s->current_tm.tm_mday,
diff --git a/hw/mfi.h b/hw/mfi.h
index 8a821623e0..3045d4eb6e 100644
--- a/hw/mfi.h
+++ b/hw/mfi.h
@@ -435,24 +435,24 @@ typedef enum {
struct mfi_sg32 {
uint32_t addr;
uint32_t len;
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_sg64 {
uint64_t addr;
uint32_t len;
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_sg_skinny {
uint64_t addr;
uint32_t len;
uint32_t flag;
-} __attribute__ ((packed));
+} QEMU_PACKED;
union mfi_sgl {
struct mfi_sg32 sg32[1];
struct mfi_sg64 sg64[1];
struct mfi_sg_skinny sg_skinny[1];
-} __attribute__ ((packed));
+} QEMU_PACKED;
/* Message frames. All messages have a common header */
struct mfi_frame_header {
@@ -468,7 +468,7 @@ struct mfi_frame_header {
uint16_t flags;
uint16_t timeout;
uint32_t data_len;
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_init_frame {
struct mfi_frame_header header;
@@ -487,7 +487,7 @@ struct mfi_io_frame {
uint32_t lba_lo;
uint32_t lba_hi;
union mfi_sgl sgl;
-} __attribute__ ((packed));
+} QEMU_PACKED;
#define MFI_PASS_FRAME_SIZE 48
struct mfi_pass_frame {
@@ -496,7 +496,7 @@ struct mfi_pass_frame {
uint32_t sense_addr_hi;
uint8_t cdb[16];
union mfi_sgl sgl;
-} __attribute__ ((packed));
+} QEMU_PACKED;
#define MFI_DCMD_FRAME_SIZE 40
struct mfi_dcmd_frame {
@@ -504,7 +504,7 @@ struct mfi_dcmd_frame {
uint32_t opcode;
uint8_t mbox[MFI_MBOX_SIZE];
union mfi_sgl sgl;
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_abort_frame {
struct mfi_frame_header header;
@@ -512,7 +512,7 @@ struct mfi_abort_frame {
uint32_t abort_mfi_addr_lo;
uint32_t abort_mfi_addr_hi;
uint32_t reserved1[6];
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_smp_frame {
struct mfi_frame_header header;
@@ -521,7 +521,7 @@ struct mfi_smp_frame {
struct mfi_sg32 sg32[2];
struct mfi_sg64 sg64[2];
} sgl;
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_stp_frame {
struct mfi_frame_header header;
@@ -531,7 +531,7 @@ struct mfi_stp_frame {
struct mfi_sg32 sg32[2];
struct mfi_sg64 sg64[2];
} sgl;
-} __attribute__ ((packed));
+} QEMU_PACKED;
union mfi_frame {
struct mfi_frame_header header;
@@ -563,7 +563,7 @@ struct mfi_init_qinfo {
uint32_t pi_addr_hi;
uint32_t ci_addr_lo;
uint32_t ci_addr_hi;
-} __attribute__ ((packed));
+} QEMU_PACKED;
/* Controller properties */
struct mfi_ctrl_props {
@@ -626,7 +626,7 @@ struct mfi_ctrl_props {
* is spun down (0=use FW defaults)
*/
uint8_t reserved[24];
-} __attribute__ ((packed));
+} QEMU_PACKED;
/* PCI information about the card. */
struct mfi_info_pci {
@@ -635,7 +635,7 @@ struct mfi_info_pci {
uint16_t subvendor;
uint16_t subdevice;
uint8_t reserved[24];
-} __attribute__ ((packed));
+} QEMU_PACKED;
/* Host (front end) interface information */
struct mfi_info_host {
@@ -647,7 +647,7 @@ struct mfi_info_host {
uint8_t reserved[6];
uint8_t port_count;
uint64_t port_addr[8];
-} __attribute__ ((packed));
+} QEMU_PACKED;
/* Device (back end) interface information */
struct mfi_info_device {
@@ -659,7 +659,7 @@ struct mfi_info_device {
uint8_t reserved[6];
uint8_t port_count;
uint64_t port_addr[8];
-} __attribute__ ((packed));
+} QEMU_PACKED;
/* Firmware component information */
struct mfi_info_component {
@@ -667,7 +667,7 @@ struct mfi_info_component {
char version[32];
char build_date[16];
char build_time[16];
-} __attribute__ ((packed));
+} QEMU_PACKED;
/* Controller default settings */
struct mfi_defaults {
@@ -710,7 +710,7 @@ struct mfi_defaults {
uint8_t fde_only;
uint8_t delay_during_post;
uint8_t resv[19];
-} __attribute__ ((packed));
+} QEMU_PACKED;
/* Controller default settings */
struct mfi_bios_data {
@@ -722,7 +722,7 @@ struct mfi_bios_data {
uint8_t expose_all_drives;
uint8_t reserved[56];
uint8_t check_sum;
-} __attribute__ ((packed));
+} QEMU_PACKED;
/* SAS (?) controller info, returned from MFI_DCMD_CTRL_GETINFO. */
struct mfi_ctrl_info {
@@ -807,7 +807,7 @@ struct mfi_ctrl_info {
uint8_t min;
uint8_t max;
uint8_t reserved[2];
- } __attribute__ ((packed)) stripe_sz_ops;
+ } QEMU_PACKED stripe_sz_ops;
uint32_t pd_ops;
#define MFI_INFO_PDOPS_FORCE_ONLINE 0x01
@@ -826,7 +826,7 @@ struct mfi_ctrl_info {
struct mfi_ctrl_props properties;
char package_version[0x60];
uint8_t pad[0x800 - 0x6a0];
-} __attribute__ ((packed));
+} QEMU_PACKED;
/* keep track of an event. */
union mfi_evt {
@@ -836,7 +836,7 @@ union mfi_evt {
int8_t class;
} members;
uint32_t word;
-} __attribute__ ((packed));
+} QEMU_PACKED;
/* event log state. */
struct mfi_evt_log_state {
@@ -845,24 +845,24 @@ struct mfi_evt_log_state {
uint32_t clear_seq_num;
uint32_t shutdown_seq_num;
uint32_t boot_seq_num;
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_progress {
uint16_t progress;
uint16_t elapsed_seconds;
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_evt_ld {
uint16_t target_id;
uint8_t ld_index;
uint8_t reserved;
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_evt_pd {
uint16_t device_id;
uint8_t enclosure_index;
uint8_t slot_number;
-} __attribute__ ((packed));
+} QEMU_PACKED;
/* event detail, returned from MFI_DCMD_CTRL_EVENT_WAIT. */
struct mfi_evt_detail {
@@ -982,13 +982,13 @@ struct mfi_evt_detail {
} args;
char description[128];
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_evt_list {
uint32_t count;
uint32_t reserved;
struct mfi_evt_detail event[1];
-} __attribute__ ((packed));
+} QEMU_PACKED;
union mfi_pd_ref {
struct {
@@ -996,7 +996,7 @@ union mfi_pd_ref {
uint16_t seq_num;
} v;
uint32_t ref;
-} __attribute__ ((packed));
+} QEMU_PACKED;
union mfi_pd_ddf_type {
struct {
@@ -1016,7 +1016,7 @@ union mfi_pd_ddf_type {
uint32_t reserved;
} non_disk;
uint32_t type;
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_pd_progress {
uint32_t active;
@@ -1027,7 +1027,7 @@ struct mfi_pd_progress {
struct mfi_progress patrol;
struct mfi_progress clear;
struct mfi_progress reserved[4];
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_pd_info {
union mfi_pd_ref ref;
@@ -1062,7 +1062,7 @@ struct mfi_pd_info {
uint8_t unusable_in_current_config;
uint8_t vpd_page83_ext[64];
uint8_t reserved[512-358];
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_pd_address {
uint16_t device_id;
@@ -1072,14 +1072,14 @@ struct mfi_pd_address {
uint8_t scsi_dev_type;
uint8_t connect_port_bitmap;
uint64_t sas_addr[2];
-} __attribute__ ((packed));
+} QEMU_PACKED;
#define MFI_MAX_SYS_PDS 240
struct mfi_pd_list {
uint32_t size;
uint32_t count;
struct mfi_pd_address addr[MFI_MAX_SYS_PDS];
-} __attribute__ ((packed));
+} QEMU_PACKED;
union mfi_ld_ref {
struct {
@@ -1088,7 +1088,7 @@ union mfi_ld_ref {
uint16_t seq;
} v;
uint32_t ref;
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_ld_list {
uint32_t ld_count;
@@ -1099,7 +1099,7 @@ struct mfi_ld_list {
uint8_t reserved2[3];
uint64_t size;
} ld_list[MFI_MAX_LD];
-} __attribute__ ((packed));
+} QEMU_PACKED;
enum mfi_ld_access {
MFI_LD_ACCESS_RW = 0,
@@ -1136,7 +1136,7 @@ struct mfi_ld_props {
uint8_t current_cache_policy;
uint8_t no_bgi;
uint8_t reserved[7];
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_ld_params {
uint8_t primary_raid_level;
@@ -1149,7 +1149,7 @@ struct mfi_ld_params {
uint8_t init_state;
uint8_t is_consistent;
uint8_t reserved[23];
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_ld_progress {
uint32_t active;
@@ -1162,21 +1162,21 @@ struct mfi_ld_progress {
struct mfi_progress fgi;
struct mfi_progress recon;
struct mfi_progress reserved[4];
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_span {
uint64_t start_block;
uint64_t num_blocks;
uint16_t array_ref;
uint8_t reserved[6];
-} __attribute__ ((packed));
+} QEMU_PACKED;
#define MFI_MAX_SPAN_DEPTH 8
struct mfi_ld_config {
struct mfi_ld_props properties;
struct mfi_ld_params params;
struct mfi_span span[MFI_MAX_SPAN_DEPTH];
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_ld_info {
struct mfi_ld_config ld_config;
@@ -1187,7 +1187,7 @@ struct mfi_ld_info {
uint8_t reserved1[1];
uint8_t vpd_page83[64];
uint8_t reserved2[16];
-} __attribute__ ((packed));
+} QEMU_PACKED;
union mfi_spare_type {
uint8_t flags;
@@ -1195,7 +1195,7 @@ union mfi_spare_type {
#define MFI_SPARE_IS_REVERTABLE (1 << 1)
#define MFI_SPARE_IS_ENCL_AFFINITY (1 << 2)
uint8_t type;
-} __attribute__ ((packed));
+} QEMU_PACKED;
#define MFI_MAX_ARRAYS 16
struct mfi_spare {
@@ -1204,7 +1204,7 @@ struct mfi_spare {
uint8_t reserved[2];
uint8_t array_count;
uint16_t array_refd[MFI_MAX_ARRAYS];
-} __attribute__ ((packed));
+} QEMU_PACKED;
#define MFI_MAX_ROW_SIZE 32
struct mfi_array {
@@ -1221,7 +1221,7 @@ struct mfi_array {
uint8_t slot;
} encl;
} pd[MFI_MAX_ROW_SIZE];
-} __attribute__ ((packed));
+} QEMU_PACKED;
struct mfi_config_data {
uint32_t size;
@@ -1237,7 +1237,7 @@ struct mfi_config_data {
struct mfi_ld_config ld[];
struct mfi_spare spare[];
*/
-} __attribute__ ((packed));
+} QEMU_PACKED;
#define MFI_SCSI_MAX_TARGETS 128
#define MFI_SCSI_MAX_LUNS 8
diff --git a/hw/pl011.c b/hw/pl011.c
index 8a5a8f554a..3245702df0 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -78,7 +78,9 @@ static uint64_t pl011_read(void *opaque, target_phys_addr_t offset,
if (s->read_count == s->read_trigger - 1)
s->int_level &= ~ PL011_INT_RX;
pl011_update(s);
- qemu_chr_accept_input(s->chr);
+ if (s->chr) {
+ qemu_chr_accept_input(s->chr);
+ }
return c;
case 1: /* UARTCR */
return 0;
diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c
index fddf2197a9..c5b8e051ec 100644
--- a/hw/ppce500_spin.c
+++ b/hw/ppce500_spin.c
@@ -40,7 +40,7 @@ typedef struct spin_info {
uint32_t resv;
uint32_t pir;
uint64_t reserved;
-} __attribute__ ((packed)) SpinInfo;
+} QEMU_PACKED SpinInfo;
typedef struct spin_state {
SysBusDevice busdev;
diff --git a/hw/qdev.h b/hw/qdev.h
index 247dd1eb39..a2cbd9dba0 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -78,12 +78,6 @@ struct DeviceState {
int alias_required_for_version;
};
-/*
- * This callback is used to create Open Firmware device path in accordance with
- * OF spec http://forthworks.com/standards/of1275.pdf. Indicidual bus bindings
- * can be found here http://playground.sun.com/1275/bindings/.
- */
-
#define TYPE_BUS "bus"
#define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
#define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS)
@@ -95,6 +89,11 @@ struct BusClass {
/* FIXME first arg should be BusState */
void (*print_dev)(Monitor *mon, DeviceState *dev, int indent);
char *(*get_dev_path)(DeviceState *dev);
+ /*
+ * This callback is used to create Open Firmware device path in accordance
+ * with OF spec http://forthworks.com/standards/of1275.pdf. Individual bus
+ * bindings can be found at http://playground.sun.com/1275/bindings/.
+ */
char *(*get_fw_dev_path)(DeviceState *dev);
int (*reset)(BusState *bus);
};
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index 47ba5ff770..b2e4f785ea 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -418,7 +418,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
uint64_t child;
uint64_t parent;
uint64_t size;
- } __attribute__((packed)) ranges[] = {
+ } QEMU_PACKED ranges[] = {
{
cpu_to_be32(b_ss(1)), cpu_to_be64(0),
cpu_to_be64(phb->io_win_addr),
diff --git a/hw/vexpress.c b/hw/vexpress.c
index 8072c5ada9..b2dc8a5ab3 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -284,9 +284,16 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard,
cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
}
- if (ram_size > 0x80000000) {
- fprintf(stderr, "vexpress-a15: cannot model more than 2GB RAM\n");
- exit(1);
+ {
+ /* We have to use a separate 64 bit variable here to avoid the gcc
+ * "comparison is always false due to limited range of data type"
+ * warning if we are on a host where ram_addr_t is 32 bits.
+ */
+ uint64_t rsz = ram_size;
+ if (rsz > (30ULL * 1024 * 1024 * 1024)) {
+ fprintf(stderr, "vexpress-a15: cannot model more than 30GB RAM\n");
+ exit(1);
+ }
}
memory_region_init_ram(ram, "vexpress.highmem", ram_size);
diff --git a/monitor.c b/monitor.c
index 09aa3cdf52..49dccfe854 100644
--- a/monitor.c
+++ b/monitor.c
@@ -941,13 +941,6 @@ static void do_info_cpu_stats(Monitor *mon)
}
#endif
-#if defined(CONFIG_TRACE_SIMPLE)
-static void do_info_trace(Monitor *mon)
-{
- st_print_trace((FILE *)mon, &monitor_fprintf);
-}
-#endif
-
static void do_trace_print_events(Monitor *mon)
{
trace_print_events((FILE *)mon, &monitor_fprintf);
@@ -2689,15 +2682,6 @@ static mon_cmd_t info_cmds[] = {
.help = "show roms",
.mhandler.info = do_info_roms,
},
-#if defined(CONFIG_TRACE_SIMPLE)
- {
- .name = "trace",
- .args_type = "",
- .params = "",
- .help = "show current contents of trace buffer",
- .mhandler.info = do_info_trace,
- },
-#endif
{
.name = "trace-events",
.args_type = "",
diff --git a/qemu-common.h b/qemu-common.h
index 09676f529f..7c8dac80a2 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -293,7 +293,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id);
void qemu_cpu_kick(void *env);
void qemu_cpu_kick_self(void);
int qemu_cpu_is_self(void *env);
-bool all_cpu_threads_idle(void);
/* work queue */
struct qemu_work_item {
diff --git a/qemu-options.hx b/qemu-options.hx
index 97245a335c..dc68e15033 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1439,7 +1439,7 @@ Forward guest TCP connections to the IP address @var{server} on port @var{port}
to the character device @var{dev} or to a program executed by @var{cmd:command}
which gets spawned for each connection. This option can be given multiple times.
-You can either use a chardev directly and have that one used throughout Qemu's
+You can either use a chardev directly and have that one used throughout QEMU's
lifetime, like in the following example:
@example
@@ -1449,7 +1449,7 @@ qemu -net user,guestfwd=tcp:10.0.2.100:1234-tcp:10.10.1.1:4321 [...]
@end example
Or you can execute a command on every TCP connection established by the guest,
-so that Qemu behaves similar to an inetd process for that virtual server:
+so that QEMU behaves similar to an inetd process for that virtual server:
@example
# call "netcat 10.10.1.1 4321" on every TCP connection to 10.0.2.100:1234
diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py
index f55e5e63f9..9b4419f7c3 100755
--- a/scripts/simpletrace.py
+++ b/scripts/simpletrace.py
@@ -12,53 +12,69 @@
import struct
import re
import inspect
+from tracetool import _read_events, Event
+from tracetool.backend.simple import is_string
header_event_id = 0xffffffffffffffff
header_magic = 0xf2b177cb0aa429b4
-header_version = 0
dropped_event_id = 0xfffffffffffffffe
-trace_fmt = '=QQQQQQQQ'
-trace_len = struct.calcsize(trace_fmt)
-event_re = re.compile(r'(disable\s+)?([a-zA-Z0-9_]+)\(([^)]*)\).*')
+log_header_fmt = '=QQQ'
+rec_header_fmt = '=QQII'
-def parse_events(fobj):
- """Parse a trace-events file into {event_num: (name, arg1, ...)}."""
-
- def get_argnames(args):
- """Extract argument names from a parameter list."""
- return tuple(arg.split()[-1].lstrip('*') for arg in args.split(','))
-
- events = {dropped_event_id: ('dropped', 'count')}
- event_num = 0
- for line in fobj:
- m = event_re.match(line.strip())
- if m is None:
- continue
-
- disable, name, args = m.groups()
- events[event_num] = (name,) + get_argnames(args)
- event_num += 1
- return events
+def read_header(fobj, hfmt):
+ '''Read a trace record header'''
+ hlen = struct.calcsize(hfmt)
+ hdr = fobj.read(hlen)
+ if len(hdr) != hlen:
+ return None
+ return struct.unpack(hfmt, hdr)
-def read_record(fobj):
+def get_record(edict, rechdr, fobj):
"""Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6)."""
- s = fobj.read(trace_len)
- if len(s) != trace_len:
+ if rechdr is None:
return None
- return struct.unpack(trace_fmt, s)
+ rec = (rechdr[0], rechdr[1])
+ if rechdr[0] != dropped_event_id:
+ event_id = rechdr[0]
+ event = edict[event_id]
+ for type, name in event.args:
+ if is_string(type):
+ l = fobj.read(4)
+ (len,) = struct.unpack('=L', l)
+ s = fobj.read(len)
+ rec = rec + (s,)
+ else:
+ (value,) = struct.unpack('=Q', fobj.read(8))
+ rec = rec + (value,)
+ else:
+ (value,) = struct.unpack('=Q', fobj.read(8))
+ rec = rec + (value,)
+ return rec
+
+
+def read_record(edict, fobj):
+ """Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6)."""
+ rechdr = read_header(fobj, rec_header_fmt)
+ return get_record(edict, rechdr, fobj) # return tuple of record elements
-def read_trace_file(fobj):
+def read_trace_file(edict, fobj):
"""Deserialize trace records from a file, yielding record tuples (event_num, timestamp, arg1, ..., arg6)."""
- header = read_record(fobj)
+ header = read_header(fobj, log_header_fmt)
if header is None or \
header[0] != header_event_id or \
- header[1] != header_magic or \
- header[2] != header_version:
- raise ValueError('not a trace file or incompatible version')
+ header[1] != header_magic:
+ raise ValueError('Not a valid trace file!')
+ if header[2] != 0 and \
+ header[2] != 2:
+ raise ValueError('Unknown version of tracelog format!')
+
+ log_version = header[2]
+ if log_version == 0:
+ raise ValueError('Older log format, not supported with this Qemu release!')
while True:
- rec = read_record(fobj)
+ rec = read_record(edict, fobj)
if rec is None:
break
@@ -89,16 +105,29 @@ class Analyzer(object):
def process(events, log, analyzer):
"""Invoke an analyzer on each event in a log."""
if isinstance(events, str):
- events = parse_events(open(events, 'r'))
+ events = _read_events(open(events, 'r'))
if isinstance(log, str):
log = open(log, 'rb')
+ enabled_events = []
+ dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)")
+ edict = {dropped_event_id: dropped_event}
+
+ for e in events:
+ if 'disable' not in e.properties:
+ enabled_events.append(e)
+ for num, event in enumerate(enabled_events):
+ edict[num] = event
+
def build_fn(analyzer, event):
- fn = getattr(analyzer, event[0], None)
+ if isinstance(event, str):
+ return analyzer.catchall
+
+ fn = getattr(analyzer, event.name, None)
if fn is None:
return analyzer.catchall
- event_argcount = len(event) - 1
+ event_argcount = len(event.args)
fn_argcount = len(inspect.getargspec(fn)[0]) - 1
if fn_argcount == event_argcount + 1:
# Include timestamp as first argument
@@ -109,9 +138,9 @@ def process(events, log, analyzer):
analyzer.begin()
fn_cache = {}
- for rec in read_trace_file(log):
+ for rec in read_trace_file(edict, log):
event_num = rec[0]
- event = events[event_num]
+ event = edict[event_num]
if event_num not in fn_cache:
fn_cache[event_num] = build_fn(analyzer, event)
fn_cache[event_num](event, rec)
@@ -128,7 +157,7 @@ def run(analyzer):
sys.stderr.write('usage: %s <trace-events> <trace-file>\n' % sys.argv[0])
sys.exit(1)
- events = parse_events(open(sys.argv[1], 'r'))
+ events = _read_events(open(sys.argv[1], 'r'))
process(events, sys.argv[2], analyzer)
if __name__ == '__main__':
@@ -137,15 +166,20 @@ if __name__ == '__main__':
self.last_timestamp = None
def catchall(self, event, rec):
+ i = 1
timestamp = rec[1]
if self.last_timestamp is None:
self.last_timestamp = timestamp
delta_ns = timestamp - self.last_timestamp
self.last_timestamp = timestamp
- fields = [event[0], '%0.3f' % (delta_ns / 1000.0)]
- for i in xrange(1, len(event)):
- fields.append('%s=0x%x' % (event[i], rec[i + 1]))
+ fields = [event.name, '%0.3f' % (delta_ns / 1000.0)]
+ for type, name in event.args:
+ if is_string(type):
+ fields.append('%s=%s' % (name, rec[i + 1]))
+ else:
+ fields.append('%s=0x%x' % (name, rec[i + 1]))
+ i += 1
print ' '.join(fields)
run(Formatter())
diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py
index fbb5717c66..c7e47d6d72 100644
--- a/scripts/tracetool/backend/simple.py
+++ b/scripts/tracetool/backend/simple.py
@@ -15,9 +15,16 @@ __email__ = "stefanha@linux.vnet.ibm.com"
from tracetool import out
+def is_string(arg):
+ strtype = ('const char*', 'char*', 'const char *', 'char *')
+ if arg.lstrip().startswith(strtype):
+ return True
+ else:
+ return False
def c(events):
out('#include "trace.h"',
+ '#include "trace/simple.h"',
'',
'TraceEvent trace_list[] = {')
@@ -26,30 +33,75 @@ def c(events):
name = e.name,
)
- out('};')
+ out('};',
+ '')
+
+ for num, event in enumerate(events):
+ out('void trace_%(name)s(%(args)s)',
+ '{',
+ ' TraceBufferRecord rec;',
+ name = event.name,
+ args = event.args,
+ )
+ sizes = []
+ for type_, name in event.args:
+ if is_string(type_):
+ out(' size_t arg%(name)s_len = %(name)s ? MIN(strlen(%(name)s), MAX_TRACE_STRLEN) : 0;',
+ name = name,
+ )
+ strsizeinfo = "4 + arg%s_len" % name
+ sizes.append(strsizeinfo)
+ else:
+ sizes.append("8")
+ sizestr = " + ".join(sizes)
+ if len(event.args) == 0:
+ sizestr = '0'
+
+
+ out('',
+ ' if (!trace_list[%(event_id)s].state) {',
+ ' return;',
+ ' }',
+ '',
+ ' if (trace_record_start(&rec, %(event_id)s, %(size_str)s)) {',
+ ' return; /* Trace Buffer Full, Event Dropped ! */',
+ ' }',
+ event_id = num,
+ size_str = sizestr,
+ )
+
+ if len(event.args) > 0:
+ for type_, name in event.args:
+ # string
+ if is_string(type_):
+ out(' trace_record_write_str(&rec, %(name)s, arg%(name)s_len);',
+ name = name,
+ )
+ # pointer var (not string)
+ elif type_.endswith('*'):
+ out(' trace_record_write_u64(&rec, (uint64_t)(uint64_t *)%(name)s);',
+ name = name,
+ )
+ # primitive data type
+ else:
+ out(' trace_record_write_u64(&rec, (uint64_t)%(name)s);',
+ name = name,
+ )
+
+ out(' trace_record_finish(&rec);',
+ '}',
+ '')
+
def h(events):
out('#include "trace/simple.h"',
'')
- for num, e in enumerate(events):
- if len(e.args):
- argstr = e.args.names()
- arg_prefix = ', (uint64_t)(uintptr_t)'
- cast_args = arg_prefix + arg_prefix.join(argstr)
- simple_args = (str(num) + cast_args)
- else:
- simple_args = str(num)
-
- out('static inline void trace_%(name)s(%(args)s)',
- '{',
- ' trace%(argc)d(%(trace_args)s);',
- '}',
- name = e.name,
- args = e.args,
- argc = len(e.args),
- trace_args = simple_args,
+ for event in events:
+ out('void trace_%(name)s(%(args)s);',
+ name = event.name,
+ args = event.args,
)
-
+ out('')
out('#define NR_TRACE_EVENTS %d' % len(events))
out('extern TraceEvent trace_list[NR_TRACE_EVENTS];')
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index b3bcbacd76..6b9659f9e7 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -50,7 +50,7 @@ static const char *ext_feature_name[] = {
"ds_cpl", "vmx", "smx", "est",
"tm2", "ssse3", "cid", NULL,
"fma", "cx16", "xtpr", "pdcm",
- NULL, NULL, "dca", "sse4.1|sse4_1",
+ NULL, "pcid", "dca", "sse4.1|sse4_1",
"sse4.2|sse4_2", "x2apic", "movbe", "popcnt",
"tsc-deadline", "aes", "xsave", "osxsave",
"avx", NULL, NULL, "hypervisor",
diff --git a/trace/control.c b/trace/control.c
index 4c5527d20a..22d5863eeb 100644
--- a/trace/control.c
+++ b/trace/control.c
@@ -27,6 +27,9 @@ void trace_backend_init_events(const char *fname)
size_t len = strlen(line_buf);
if (len > 1) { /* skip empty lines */
line_buf[len - 1] = '\0';
+ if ('#' == line_buf[0]) { /* skip commented lines */
+ continue;
+ }
if (!trace_event_set_state(line_buf, true)) {
fprintf(stderr,
"error: trace event '%s' does not exist\n", line_buf);
diff --git a/trace/simple.c b/trace/simple.c
index b4a3c6e950..b700ea317c 100644
--- a/trace/simple.c
+++ b/trace/simple.c
@@ -27,7 +27,7 @@
#define HEADER_MAGIC 0xf2b177cb0aa429b4ULL
/** Trace file version number, bump if format changes */
-#define HEADER_VERSION 0
+#define HEADER_VERSION 2
/** Records were dropped event ID */
#define DROPPED_EVENT_ID (~(uint64_t)0 - 1)
@@ -35,23 +35,6 @@
/** Trace record is valid */
#define TRACE_RECORD_VALID ((uint64_t)1 << 63)
-/** Trace buffer entry */
-typedef struct {
- uint64_t event;
- uint64_t timestamp_ns;
- uint64_t x1;
- uint64_t x2;
- uint64_t x3;
- uint64_t x4;
- uint64_t x5;
- uint64_t x6;
-} TraceRecord;
-
-enum {
- TRACE_BUF_LEN = 4096,
- TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4,
-};
-
/*
* Trace records are written out by a dedicated thread. The thread waits for
* records to become available, writes them out, and then waits again.
@@ -62,11 +45,48 @@ static GCond *trace_empty_cond;
static bool trace_available;
static bool trace_writeout_enabled;
-static TraceRecord trace_buf[TRACE_BUF_LEN];
+enum {
+ TRACE_BUF_LEN = 4096 * 64,
+ TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4,
+};
+
+uint8_t trace_buf[TRACE_BUF_LEN];
static unsigned int trace_idx;
+static unsigned int writeout_idx;
+static uint64_t dropped_events;
static FILE *trace_fp;
static char *trace_file_name = NULL;
+/* * Trace buffer entry */
+typedef struct {
+ uint64_t event; /* TraceEventID */
+ uint64_t timestamp_ns;
+ uint32_t length; /* in bytes */
+ uint32_t reserved; /* unused */
+ uint8_t arguments[];
+} TraceRecord;
+
+typedef struct {
+ uint64_t header_event_id; /* HEADER_EVENT_ID */
+ uint64_t header_magic; /* HEADER_MAGIC */
+ uint64_t header_version; /* HEADER_VERSION */
+} TraceRecordHeader;
+
+
+static void read_from_buffer(unsigned int idx, void *dataptr, size_t size);
+static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size);
+
+static void clear_buffer_range(unsigned int idx, size_t len)
+{
+ uint32_t num = 0;
+ while (num < len) {
+ if (idx >= TRACE_BUF_LEN) {
+ idx = idx % TRACE_BUF_LEN;
+ }
+ trace_buf[idx++] = 0;
+ num++;
+ }
+}
/**
* Read a trace record from the trace buffer
*
@@ -75,16 +95,30 @@ static char *trace_file_name = NULL;
*
* Returns false if the record is not valid.
*/
-static bool get_trace_record(unsigned int idx, TraceRecord *record)
+static bool get_trace_record(unsigned int idx, TraceRecord **recordptr)
{
- if (!(trace_buf[idx].event & TRACE_RECORD_VALID)) {
+ uint64_t event_flag = 0;
+ TraceRecord record;
+ /* read the event flag to see if its a valid record */
+ read_from_buffer(idx, &record, sizeof(event_flag));
+
+ if (!(record.event & TRACE_RECORD_VALID)) {
return false;
}
- __sync_synchronize(); /* read memory barrier before accessing record */
-
- *record = trace_buf[idx];
- record->event &= ~TRACE_RECORD_VALID;
+ smp_rmb(); /* read memory barrier before accessing record */
+ /* read the record header to know record length */
+ read_from_buffer(idx, &record, sizeof(TraceRecord));
+ *recordptr = malloc(record.length); /* dont use g_malloc, can deadlock when traced */
+ /* make a copy of record to avoid being overwritten */
+ read_from_buffer(idx, *recordptr, record.length);
+ smp_rmb(); /* memory barrier before clearing valid flag */
+ (*recordptr)->event &= ~TRACE_RECORD_VALID;
+ /* clear the trace buffer range for consumed record otherwise any byte
+ * with its MSB set may be considered as a valid event id when the writer
+ * thread crosses this range of buffer again.
+ */
+ clear_buffer_range(idx, record.length);
return true;
}
@@ -120,29 +154,39 @@ static void wait_for_trace_records_available(void)
static gpointer writeout_thread(gpointer opaque)
{
- TraceRecord record;
- unsigned int writeout_idx = 0;
- unsigned int num_available, idx;
+ TraceRecord *recordptr;
+ union {
+ TraceRecord rec;
+ uint8_t bytes[sizeof(TraceRecord) + sizeof(uint64_t)];
+ } dropped;
+ unsigned int idx = 0;
+ uint64_t dropped_count;
size_t unused __attribute__ ((unused));
for (;;) {
wait_for_trace_records_available();
- num_available = trace_idx - writeout_idx;
- if (num_available > TRACE_BUF_LEN) {
- record = (TraceRecord){
- .event = DROPPED_EVENT_ID,
- .x1 = num_available,
- };
- unused = fwrite(&record, sizeof(record), 1, trace_fp);
- writeout_idx += num_available;
+ if (dropped_events) {
+ dropped.rec.event = DROPPED_EVENT_ID,
+ dropped.rec.timestamp_ns = get_clock();
+ dropped.rec.length = sizeof(TraceRecord) + sizeof(dropped_events),
+ dropped.rec.reserved = 0;
+ while (1) {
+ dropped_count = dropped_events;
+ if (g_atomic_int_compare_and_exchange((gint *)&dropped_events,
+ dropped_count, 0)) {
+ break;
+ }
+ }
+ memcpy(dropped.rec.arguments, &dropped_count, sizeof(uint64_t));
+ unused = fwrite(&dropped.rec, dropped.rec.length, 1, trace_fp);
}
- idx = writeout_idx % TRACE_BUF_LEN;
- while (get_trace_record(idx, &record)) {
- trace_buf[idx].event = 0; /* clear valid bit */
- unused = fwrite(&record, sizeof(record), 1, trace_fp);
- idx = ++writeout_idx % TRACE_BUF_LEN;
+ while (get_trace_record(idx, &recordptr)) {
+ unused = fwrite(recordptr, recordptr->length, 1, trace_fp);
+ writeout_idx += recordptr->length;
+ free(recordptr); /* dont use g_free, can deadlock when traced */
+ idx = writeout_idx % TRACE_BUF_LEN;
}
fflush(trace_fp);
@@ -150,73 +194,93 @@ static gpointer writeout_thread(gpointer opaque)
return NULL;
}
-static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
- uint64_t x4, uint64_t x5, uint64_t x6)
+void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val)
{
- unsigned int idx;
- uint64_t timestamp;
-
- if (!trace_list[event].state) {
- return;
- }
-
- timestamp = get_clock();
-#if GLIB_CHECK_VERSION(2, 30, 0)
- idx = g_atomic_int_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN;
-#else
- idx = g_atomic_int_exchange_and_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN;
-#endif
- trace_buf[idx] = (TraceRecord){
- .event = event,
- .timestamp_ns = timestamp,
- .x1 = x1,
- .x2 = x2,
- .x3 = x3,
- .x4 = x4,
- .x5 = x5,
- .x6 = x6,
- };
- __sync_synchronize(); /* write barrier before marking as valid */
- trace_buf[idx].event |= TRACE_RECORD_VALID;
-
- if ((idx + 1) % TRACE_BUF_FLUSH_THRESHOLD == 0) {
- flush_trace_file(false);
- }
+ rec->rec_off = write_to_buffer(rec->rec_off, &val, sizeof(uint64_t));
}
-void trace0(TraceEventID event)
+void trace_record_write_str(TraceBufferRecord *rec, const char *s, uint32_t slen)
{
- trace(event, 0, 0, 0, 0, 0, 0);
+ /* Write string length first */
+ rec->rec_off = write_to_buffer(rec->rec_off, &slen, sizeof(slen));
+ /* Write actual string now */
+ rec->rec_off = write_to_buffer(rec->rec_off, (void*)s, slen);
}
-void trace1(TraceEventID event, uint64_t x1)
+int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasize)
{
- trace(event, x1, 0, 0, 0, 0, 0);
-}
+ unsigned int idx, rec_off, old_idx, new_idx;
+ uint32_t rec_len = sizeof(TraceRecord) + datasize;
+ uint64_t timestamp_ns = get_clock();
+
+ while (1) {
+ old_idx = trace_idx;
+ smp_rmb();
+ new_idx = old_idx + rec_len;
+
+ if (new_idx - writeout_idx > TRACE_BUF_LEN) {
+ /* Trace Buffer Full, Event dropped ! */
+ g_atomic_int_inc((gint *)&dropped_events);
+ return -ENOSPC;
+ }
-void trace2(TraceEventID event, uint64_t x1, uint64_t x2)
-{
- trace(event, x1, x2, 0, 0, 0, 0);
-}
+ if (g_atomic_int_compare_and_exchange((gint *)&trace_idx,
+ old_idx, new_idx)) {
+ break;
+ }
+ }
-void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3)
-{
- trace(event, x1, x2, x3, 0, 0, 0);
+ idx = old_idx % TRACE_BUF_LEN;
+ /* To check later if threshold crossed */
+ rec->next_tbuf_idx = new_idx % TRACE_BUF_LEN;
+
+ rec_off = idx;
+ rec_off = write_to_buffer(rec_off, (uint8_t*)&event, sizeof(event));
+ rec_off = write_to_buffer(rec_off, (uint8_t*)&timestamp_ns, sizeof(timestamp_ns));
+ rec_off = write_to_buffer(rec_off, (uint8_t*)&rec_len, sizeof(rec_len));
+
+ rec->tbuf_idx = idx;
+ rec->rec_off = (idx + sizeof(TraceRecord)) % TRACE_BUF_LEN;
+ return 0;
}
-void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4)
+static void read_from_buffer(unsigned int idx, void *dataptr, size_t size)
{
- trace(event, x1, x2, x3, x4, 0, 0);
+ uint8_t *data_ptr = dataptr;
+ uint32_t x = 0;
+ while (x < size) {
+ if (idx >= TRACE_BUF_LEN) {
+ idx = idx % TRACE_BUF_LEN;
+ }
+ data_ptr[x++] = trace_buf[idx++];
+ }
}
-void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5)
+static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size)
{
- trace(event, x1, x2, x3, x4, x5, 0);
+ uint8_t *data_ptr = dataptr;
+ uint32_t x = 0;
+ while (x < size) {
+ if (idx >= TRACE_BUF_LEN) {
+ idx = idx % TRACE_BUF_LEN;
+ }
+ trace_buf[idx++] = data_ptr[x++];
+ }
+ return idx; /* most callers wants to know where to write next */
}
-void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6)
+void trace_record_finish(TraceBufferRecord *rec)
{
- trace(event, x1, x2, x3, x4, x5, x6);
+ uint8_t temp_rec[sizeof(TraceRecord)];
+ TraceRecord *record = (TraceRecord *) temp_rec;
+ read_from_buffer(rec->tbuf_idx, temp_rec, sizeof(TraceRecord));
+ smp_wmb(); /* write barrier before marking as valid */
+ record->event |= TRACE_RECORD_VALID;
+ write_to_buffer(rec->tbuf_idx, temp_rec, sizeof(TraceRecord));
+
+ if ((trace_idx - writeout_idx) > TRACE_BUF_FLUSH_THRESHOLD) {
+ flush_trace_file(false);
+ }
}
void st_set_trace_file_enabled(bool enable)
@@ -231,10 +295,11 @@ void st_set_trace_file_enabled(bool enable)
flush_trace_file(true);
if (enable) {
- static const TraceRecord header = {
- .event = HEADER_EVENT_ID,
- .timestamp_ns = HEADER_MAGIC,
- .x1 = HEADER_VERSION,
+ static const TraceRecordHeader header = {
+ .header_event_id = HEADER_EVENT_ID,
+ .header_magic = HEADER_MAGIC,
+ /* Older log readers will check for version at next location */
+ .header_version = HEADER_VERSION,
};
trace_fp = fopen(trace_file_name, "wb");
@@ -291,24 +356,6 @@ void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream,
trace_file_name, trace_fp ? "on" : "off");
}
-void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
-{
- unsigned int i;
-
- for (i = 0; i < TRACE_BUF_LEN; i++) {
- TraceRecord record;
-
- if (!get_trace_record(i, &record)) {
- continue;
- }
- stream_printf(stream, "Event %" PRIu64 " : %" PRIx64 " %" PRIx64
- " %" PRIx64 " %" PRIx64 " %" PRIx64 " %" PRIx64 "\n",
- record.event, record.x1, record.x2,
- record.x3, record.x4, record.x5,
- record.x6);
- }
-}
-
void st_flush_trace_buffer(void)
{
flush_trace_file(true);
diff --git a/trace/simple.h b/trace/simple.h
index 466e75b4ff..7e521c1e1f 100644
--- a/trace/simple.h
+++ b/trace/simple.h
@@ -22,17 +22,41 @@ typedef struct {
bool state;
} TraceEvent;
-void trace0(TraceEventID event);
-void trace1(TraceEventID event, uint64_t x1);
-void trace2(TraceEventID event, uint64_t x1, uint64_t x2);
-void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3);
-void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4);
-void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5);
-void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6);
-void st_print_trace(FILE *stream, fprintf_function stream_printf);
void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf);
void st_set_trace_file_enabled(bool enable);
bool st_set_trace_file(const char *file);
void st_flush_trace_buffer(void);
+typedef struct {
+ unsigned int tbuf_idx;
+ unsigned int next_tbuf_idx;
+ unsigned int rec_off;
+} TraceBufferRecord;
+
+/* Note for hackers: Make sure MAX_TRACE_LEN < sizeof(uint32_t) */
+#define MAX_TRACE_STRLEN 512
+/**
+ * Initialize a trace record and claim space for it in the buffer
+ *
+ * @arglen number of bytes required for arguments
+ */
+int trace_record_start(TraceBufferRecord *rec, TraceEventID id, size_t arglen);
+
+/**
+ * Append a 64-bit argument to a trace record
+ */
+void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val);
+
+/**
+ * Append a string argument to a trace record
+ */
+void trace_record_write_str(TraceBufferRecord *rec, const char *s, uint32_t slen);
+
+/**
+ * Mark a trace record completed
+ *
+ * Don't append any more arguments to the trace record after calling this.
+ */
+void trace_record_finish(TraceBufferRecord *rec);
+
#endif /* TRACE_SIMPLE_H */