Merge remote-tracking branch 'sstabellini/disk_io' into staging
* sstabellini/disk_io:
xen_disk: when using AIO flush after the operation is completed
xen_disk: open disk with BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO
diff --git a/Makefile b/Makefile
index 1bc3cb0..d8e1f36 100644
--- a/Makefile
+++ b/Makefile
@@ -173,6 +173,7 @@
$(qapi-obj-y): $(GENERATED_HEADERS)
qapi-dir := $(BUILD_DIR)/qapi-generated
qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
+qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
gen-out-type = $(subst .,-,$(suffix $@))
@@ -347,28 +348,29 @@
qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@," GEN $@")
+POD2MAN = pod2man --utf8
qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
- pod2man --section=1 --center=" " --release=" " qemu.pod > $@, \
+ $(POD2MAN) --section=1 --center=" " --release=" " qemu.pod > $@, \
" GEN $@")
qemu-img.1: qemu-img.texi qemu-img-cmds.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-img.pod && \
- pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@, \
+ $(POD2MAN) --section=1 --center=" " --release=" " qemu-img.pod > $@, \
" GEN $@")
fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< fsdev/virtfs-proxy-helper.pod && \
- pod2man --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \
+ $(POD2MAN) --section=1 --center=" " --release=" " fsdev/virtfs-proxy-helper.pod > $@, \
" GEN $@")
qemu-nbd.8: qemu-nbd.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-nbd.pod && \
- pod2man --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
+ $(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
" GEN $@")
dvi: qemu-doc.dvi qemu-tech.dvi
diff --git a/Makefile.target b/Makefile.target
index 63cf769..44b2e83 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -81,8 +81,10 @@
libobj-$(CONFIG_TCG_INTERPRETER) += tci.o
libobj-y += fpu/softfloat.o
ifneq ($(TARGET_BASE_ARCH), sparc)
+ifneq ($(TARGET_BASE_ARCH), alpha)
libobj-y += op_helper.o
endif
+endif
libobj-y += helper.o
ifeq ($(TARGET_BASE_ARCH), i386)
libobj-y += cpuid.o
@@ -96,6 +98,7 @@
endif
libobj-$(TARGET_SPARC) += int32_helper.o
libobj-$(TARGET_SPARC64) += int64_helper.o
+libobj-$(TARGET_ALPHA) += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
libobj-y += disas.o
libobj-$(CONFIG_TCI_DIS) += tci-dis.o
diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt
index 9d30a8c..1ba916c 100644
--- a/QMP/qmp-spec.txt
+++ b/QMP/qmp-spec.txt
@@ -209,13 +209,27 @@
capabilities array (section '2.2 Server Greeting'). Thus, Clients can check
that array and enable the capabilities they support.
-Additionally, Clients must not assume any particular:
+The QMP Server performs a type check on the arguments to a command. It
+generates an error if a value does not have the expected type for its
+key, or if it does not understand a key that the Client included. The
+strictness of the Server catches wrong assumptions of Clients about
+the Server's schema. Clients can assume that, when such validation
+errors occur, they will be reported before the command generated any
+side effect.
-- Size of json-objects or length of json-arrays
+However, Clients must not assume any particular:
+
+- Length of json-arrays
+- Size of json-objects; in particular, future versions of QEMU may add
+ new keys and Clients should be able to ignore them.
- Order of json-object members or json-array elements
- Amount of errors generated by a command, that is, new errors can be added
to any existing command in newer versions of the Server
+Of course, the Server does guarantee to send valid JSON. But apart from
+this, a Client should be "conservative in what they send, and liberal in
+what they accept".
+
6. Downstream extension of QMP
------------------------------
diff --git a/configure b/configure
index 8b4e3c1..14ef738 100755
--- a/configure
+++ b/configure
@@ -3608,7 +3608,7 @@
esac
case "$target_arch2" in
- sparc*)
+ alpha | sparc*)
echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak
;;
esac
diff --git a/def-helper.h b/def-helper.h
index 0e70c31..b98ff69 100644
--- a/def-helper.h
+++ b/def-helper.h
@@ -39,6 +39,7 @@
#endif
#define dh_alias_ptr ptr
#define dh_alias_void void
+#define dh_alias_noreturn noreturn
#define dh_alias_env ptr
#define dh_alias(t) glue(dh_alias_, t)
@@ -52,36 +53,42 @@
#define dh_ctype_tl target_ulong
#define dh_ctype_ptr void *
#define dh_ctype_void void
+#define dh_ctype_noreturn void QEMU_NORETURN
#define dh_ctype_env CPUArchState *
#define dh_ctype(t) dh_ctype_##t
/* We can't use glue() here because it falls foul of C preprocessor
recursive expansion rules. */
#define dh_retvar_decl0_void void
+#define dh_retvar_decl0_noreturn void
#define dh_retvar_decl0_i32 TCGv_i32 retval
#define dh_retvar_decl0_i64 TCGv_i64 retval
#define dh_retvar_decl0_ptr TCGv_ptr retval
#define dh_retvar_decl0(t) glue(dh_retvar_decl0_, dh_alias(t))
#define dh_retvar_decl_void
+#define dh_retvar_decl_noreturn
#define dh_retvar_decl_i32 TCGv_i32 retval,
#define dh_retvar_decl_i64 TCGv_i64 retval,
#define dh_retvar_decl_ptr TCGv_ptr retval,
#define dh_retvar_decl(t) glue(dh_retvar_decl_, dh_alias(t))
#define dh_retvar_void TCG_CALL_DUMMY_ARG
+#define dh_retvar_noreturn TCG_CALL_DUMMY_ARG
#define dh_retvar_i32 GET_TCGV_i32(retval)
#define dh_retvar_i64 GET_TCGV_i64(retval)
#define dh_retvar_ptr GET_TCGV_ptr(retval)
#define dh_retvar(t) glue(dh_retvar_, dh_alias(t))
#define dh_is_64bit_void 0
+#define dh_is_64bit_noreturn 0
#define dh_is_64bit_i32 0
#define dh_is_64bit_i64 1
#define dh_is_64bit_ptr (TCG_TARGET_REG_BITS == 64)
#define dh_is_64bit(t) glue(dh_is_64bit_, dh_alias(t))
#define dh_is_signed_void 0
+#define dh_is_signed_noreturn 0
#define dh_is_signed_i32 0
#define dh_is_signed_s32 1
#define dh_is_signed_i64 0
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 5831e37..ad11767 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -194,11 +194,11 @@
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
{
- GenericList *i;
+ GenericList *i, **prev = (GenericList **)obj;
visit_start_list(m, name, errp);
- for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
+ for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) {
UserDefOneList *native_i = (UserDefOneList *)i;
visit_type_UserDefOne(m, &native_i->value, NULL, errp);
}
diff --git a/elf.h b/elf.h
index 2e05d34..36bcac4 100644
--- a/elf.h
+++ b/elf.h
@@ -216,6 +216,7 @@
#define ELF_ST_BIND(x) ((x) >> 4)
#define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf)
+#define ELF_ST_INFO(bind, type) (((bind) << 4) | ((type) & 0xf))
#define ELF32_ST_BIND(x) ELF_ST_BIND(x)
#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x)
#define ELF64_ST_BIND(x) ELF_ST_BIND(x)
@@ -345,6 +346,21 @@
#define R_MIPS_HIVENDOR 127
+/* SUN SPARC specific definitions. */
+
+/* Values for Elf64_Ehdr.e_flags. */
+
+#define EF_SPARCV9_MM 3
+#define EF_SPARCV9_TSO 0
+#define EF_SPARCV9_PSO 1
+#define EF_SPARCV9_RMO 2
+#define EF_SPARC_LEDATA 0x800000 /* little endian data */
+#define EF_SPARC_EXT_MASK 0xFFFF00
+#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */
+#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */
+#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */
+#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */
+
/*
* Sparc ELF relocation types
*/
diff --git a/exec.c b/exec.c
index 265e895..6731ab8 100644
--- a/exec.c
+++ b/exec.c
@@ -636,6 +636,7 @@
cpu_gen_init();
code_gen_alloc(tb_size);
code_gen_ptr = code_gen_buffer;
+ tcg_register_jit(code_gen_buffer, code_gen_buffer_size);
page_init();
#if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE)
/* There's no guest base to take into account, so go ahead and
diff --git a/gdbstub.c b/gdbstub.c
index f4e97f7..6a7e2c4 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -284,7 +284,6 @@
RS_GETLINE,
RS_CHKSUM1,
RS_CHKSUM2,
- RS_SYSCALL,
};
typedef struct GDBState {
CPUArchState *c_cpu; /* current CPU for step/continue ops */
@@ -304,6 +303,8 @@
CharDriverState *chr;
CharDriverState *mon_chr;
#endif
+ char syscall_buf[256];
+ gdb_syscall_complete_cb current_syscall_cb;
} GDBState;
/* By default use no IRQs and no timers while single stepping so as to
@@ -346,8 +347,6 @@
}
#endif
-static gdb_syscall_complete_cb gdb_current_syscall_cb;
-
static enum {
GDB_SYS_UNKNOWN,
GDB_SYS_ENABLED,
@@ -2097,8 +2096,10 @@
if (*p == ',')
p++;
type = *p;
- if (gdb_current_syscall_cb)
- gdb_current_syscall_cb(s->c_cpu, ret, err);
+ if (s->current_syscall_cb) {
+ s->current_syscall_cb(s->c_cpu, ret, err);
+ s->current_syscall_cb = NULL;
+ }
if (type == 'C') {
put_packet(s, "T02");
} else {
@@ -2398,7 +2399,12 @@
const char *type;
int ret;
- if (running || s->state == RS_INACTIVE || s->state == RS_SYSCALL) {
+ if (running || s->state == RS_INACTIVE) {
+ return;
+ }
+ /* Is there a GDB syscall waiting to be sent? */
+ if (s->current_syscall_cb) {
+ put_packet(s, s->syscall_buf);
return;
}
switch (state) {
@@ -2468,8 +2474,8 @@
void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
{
va_list va;
- char buf[256];
char *p;
+ char *p_end;
target_ulong addr;
uint64_t i64;
GDBState *s;
@@ -2477,14 +2483,13 @@
s = gdbserver_state;
if (!s)
return;
- gdb_current_syscall_cb = cb;
- s->state = RS_SYSCALL;
+ s->current_syscall_cb = cb;
#ifndef CONFIG_USER_ONLY
vm_stop(RUN_STATE_DEBUG);
#endif
- s->state = RS_IDLE;
va_start(va, fmt);
- p = buf;
+ p = s->syscall_buf;
+ p_end = &s->syscall_buf[sizeof(s->syscall_buf)];
*(p++) = 'F';
while (*fmt) {
if (*fmt == '%') {
@@ -2492,17 +2497,17 @@
switch (*fmt++) {
case 'x':
addr = va_arg(va, target_ulong);
- p += snprintf(p, &buf[sizeof(buf)] - p, TARGET_FMT_lx, addr);
+ p += snprintf(p, p_end - p, TARGET_FMT_lx, addr);
break;
case 'l':
if (*(fmt++) != 'x')
goto bad_format;
i64 = va_arg(va, uint64_t);
- p += snprintf(p, &buf[sizeof(buf)] - p, "%" PRIx64, i64);
+ p += snprintf(p, p_end - p, "%" PRIx64, i64);
break;
case 's':
addr = va_arg(va, target_ulong);
- p += snprintf(p, &buf[sizeof(buf)] - p, TARGET_FMT_lx "/%x",
+ p += snprintf(p, p_end - p, TARGET_FMT_lx "/%x",
addr, va_arg(va, int));
break;
default:
@@ -2517,10 +2522,16 @@
}
*p = 0;
va_end(va);
- put_packet(s, buf);
#ifdef CONFIG_USER_ONLY
+ put_packet(s, s->syscall_buf);
gdb_handlesig(s->c_cpu, 0);
#else
+ /* In this case wait to send the syscall packet until notification that
+ the CPU has stopped. This must be done because if the packet is sent
+ now the reply from the syscall request could be received while the CPU
+ is still in the running state, which can cause packets to be dropped
+ and state transition 'T' packets to be sent while the syscall is still
+ being processed. */
cpu_exit(s->c_cpu);
#endif
}
@@ -2919,6 +2930,7 @@
s->chr = chr;
s->state = chr ? RS_IDLE : RS_INACTIVE;
s->mon_chr = mon_chr;
+ s->current_syscall_cb = NULL;
return 0;
}
diff --git a/hw/blizzard.c b/hw/blizzard.c
index c7d844d..29074c4 100644
--- a/hw/blizzard.c
+++ b/hw/blizzard.c
@@ -937,9 +937,7 @@
{
BlizzardState *s = (BlizzardState *) opaque;
- if (cswitch) {
- blizzard_update_display(opaque);
- }
+ blizzard_update_display(opaque);
if (s && ds_get_data(s->state))
ppm_save(filename, s->state->surface);
}
diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c
index f172093..4a08e9d 100644
--- a/hw/omap_lcdc.c
+++ b/hw/omap_lcdc.c
@@ -267,9 +267,8 @@
static void omap_screen_dump(void *opaque, const char *filename, bool cswitch)
{
struct omap_lcd_panel_s *omap_lcd = opaque;
- if (cswitch) {
- omap_update_display(opaque);
- }
+
+ omap_update_display(opaque);
if (omap_lcd && ds_get_data(omap_lcd->state))
ppm_save(filename, ds_get_data(omap_lcd->state),
omap_lcd->width, omap_lcd->height,
diff --git a/hw/vga.c b/hw/vga.c
index 6dc98f6..f80860c 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -2415,7 +2415,7 @@
if (cswitch) {
vga_invalidate_display(s);
- vga_hw_update();
}
+ vga_hw_update();
ppm_save(filename, s->ds->surface);
}
diff --git a/hw/xen_console.c b/hw/xen_console.c
index edcb31c..3794b19 100644
--- a/hw/xen_console.c
+++ b/hw/xen_console.c
@@ -248,6 +248,9 @@
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+ if (!xendev->dev) {
+ return;
+ }
if (con->chr)
qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
xen_be_unbind_evtchn(&con->xendev);
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 9cb0253..9719395 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -726,6 +726,7 @@
if (!blkdev->dinfo) {
/* close/delete only if we created it ourself */
bdrv_close(blkdev->bs);
+ bdrv_detach_dev(blkdev->bs, blkdev);
bdrv_delete(blkdev->bs);
}
blkdev->bs = NULL;
diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c
index bdc3c79..802cae3 100644
--- a/libcacard/vcard_emul_nss.c
+++ b/libcacard/vcard_emul_nss.c
@@ -682,8 +682,19 @@
SECMODModule *module = (SECMODModule *)arg;
do {
+ /*
+ * XXX - the latency value doesn't matter one bit. you only get no
+ * blocking (flags |= CKF_DONT_BLOCK) or PKCS11_WAIT_LATENCY (==500),
+ * hard coded in coolkey. And it isn't coolkey's fault - the timeout
+ * value we pass get's dropped on the floor before C_WaitForSlotEvent
+ * is called.
+ */
slot = SECMOD_WaitForAnyTokenEvent(module, 0, 500);
if (slot == NULL) {
+ /* this could be just a no event indication */
+ if (PORT_GetError() == SEC_ERROR_NO_EVENT) {
+ continue;
+ }
break;
}
vreader = vcard_emul_find_vreader_from_slot(slot);
@@ -994,10 +1005,10 @@
SECMOD_GetReadLock(module_lock);
for (mlp = module_list; mlp; mlp = mlp->next) {
SECMODModule *module = mlp->module;
- PRBool has_emul_slots = PR_FALSE;
- if (module == NULL) {
- continue;
+ /* Ignore the internal module */
+ if (module == NULL || module == SECMOD_GetInternalModule()) {
+ continue;
}
for (i = 0; i < module->slotCount; i++) {
@@ -1007,15 +1018,22 @@
if (slot == NULL || !PK11_IsRemovable(slot) || !PK11_IsHW(slot)) {
continue;
}
+ if (strcmp("E-Gate 0 0", PK11_GetSlotName(slot)) == 0) {
+ /*
+ * coolkey <= 1.1.0-20 emulates this reader if it can't find
+ * any hardware readers. This causes problems, warn user of
+ * problems.
+ */
+ fprintf(stderr, "known bad coolkey version - see "
+ "https://bugzilla.redhat.com/show_bug.cgi?id=802435\n");
+ continue;
+ }
vreader_emul = vreader_emul_new(slot, options->hw_card_type,
options->hw_type_params);
vreader = vreader_new(PK11_GetSlotName(slot), vreader_emul,
vreader_emul_delete);
vreader_add_reader(vreader);
- has_readers = PR_TRUE;
- has_emul_slots = PR_TRUE;
-
if (PK11_IsPresent(slot)) {
VCard *vcard;
vcard = vcard_emul_mirror_card(vreader);
@@ -1024,12 +1042,10 @@
vcard_free(vcard);
}
}
- if (has_emul_slots) {
- vcard_emul_new_event_thread(module);
- }
+ vcard_emul_new_event_thread(module);
}
SECMOD_ReleaseReadLock(module_lock);
- nss_emul_init = has_readers;
+ nss_emul_init = PR_TRUE;
return VCARD_EMUL_OK;
}
diff --git a/monitor.c b/monitor.c
index 2ff1e0b..8946a10 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4157,6 +4157,9 @@
case 'O':
assert(flags & QMP_ACCEPT_UNKNOWNS);
break;
+ case 'q':
+ /* Any QObject can be passed. */
+ break;
case '/':
case '.':
/*
diff --git a/qapi-schema-test.json b/qapi-schema-test.json
index 8c7f9f7..9eae350 100644
--- a/qapi-schema-test.json
+++ b/qapi-schema-test.json
@@ -8,7 +8,7 @@
# for testing nested structs
{ 'type': 'UserDefOne',
- 'data': { 'integer': 'int', 'string': 'str' } }
+ 'data': { 'integer': 'int', 'string': 'str', '*enum1': 'EnumOne' } }
{ 'type': 'UserDefTwo',
'data': { 'string': 'str',
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index e6b6152..74386b9 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -22,16 +22,17 @@
typedef struct StackObject
{
- const QObject *obj;
- const QListEntry *entry;
+ QObject *obj;
+ const QListEntry *entry;
+ GHashTable *h;
} StackObject;
struct QmpInputVisitor
{
Visitor visitor;
- QObject *obj;
StackObject stack[QIV_STACK_SIZE];
int nb_stack;
+ bool strict;
};
static QmpInputVisitor *to_qiv(Visitor *v)
@@ -39,21 +40,18 @@
return container_of(v, QmpInputVisitor, visitor);
}
-static const QObject *qmp_input_get_object(QmpInputVisitor *qiv,
- const char *name)
+static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
+ const char *name)
{
- const QObject *qobj;
-
- if (qiv->nb_stack == 0) {
- qobj = qiv->obj;
- } else {
- qobj = qiv->stack[qiv->nb_stack - 1].obj;
- }
+ QObject *qobj = qiv->stack[qiv->nb_stack - 1].obj;
if (qobj) {
if (name && qobject_type(qobj) == QTYPE_QDICT) {
+ if (qiv->stack[qiv->nb_stack - 1].h) {
+ g_hash_table_remove(qiv->stack[qiv->nb_stack - 1].h, name);
+ }
return qdict_get(qobject_to_qdict(qobj), name);
- } else if (qiv->nb_stack > 0 && qobject_type(qobj) == QTYPE_QLIST) {
+ } else if (qiv->stack[qiv->nb_stack - 1].entry) {
return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
}
}
@@ -61,34 +59,57 @@
return qobj;
}
-static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
+static void qdict_add_key(const char *key, QObject *obj, void *opaque)
{
- qiv->stack[qiv->nb_stack].obj = obj;
- if (qobject_type(obj) == QTYPE_QLIST) {
- qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
- }
- qiv->nb_stack++;
+ GHashTable *h = opaque;
+ g_hash_table_insert(h, (gpointer) key, NULL);
+}
+
+static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
+{
+ GHashTable *h;
if (qiv->nb_stack >= QIV_STACK_SIZE) {
error_set(errp, QERR_BUFFER_OVERRUN);
return;
}
+
+ qiv->stack[qiv->nb_stack].obj = obj;
+ qiv->stack[qiv->nb_stack].entry = NULL;
+ qiv->stack[qiv->nb_stack].h = NULL;
+
+ if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
+ h = g_hash_table_new(g_str_hash, g_str_equal);
+ qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
+ qiv->stack[qiv->nb_stack].h = h;
+ }
+
+ qiv->nb_stack++;
}
static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
{
- qiv->nb_stack--;
- if (qiv->nb_stack < 0) {
- error_set(errp, QERR_BUFFER_OVERRUN);
- return;
+ GHashTableIter iter;
+ gpointer key;
+
+ if (qiv->strict && qiv->stack[qiv->nb_stack - 1].h) {
+ g_hash_table_iter_init(&iter, qiv->stack[qiv->nb_stack - 1].h);
+ if (g_hash_table_iter_next(&iter, &key, NULL)) {
+ error_set(errp, QERR_QMP_EXTRA_MEMBER, (char *) key);
+ }
+ g_hash_table_unref(qiv->stack[qiv->nb_stack - 1].h);
}
+
+ assert(qiv->nb_stack > 0);
+ qiv->nb_stack--;
}
static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
const char *name, size_t size, Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
+ Error *err = NULL;
if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -96,8 +117,9 @@
return;
}
- qmp_input_push(qiv, qobj, errp);
- if (error_is_set(errp)) {
+ qmp_input_push(qiv, qobj, &err);
+ if (err) {
+ error_propagate(errp, err);
return;
}
@@ -116,7 +138,7 @@
static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -133,18 +155,24 @@
QmpInputVisitor *qiv = to_qiv(v);
GenericList *entry;
StackObject *so = &qiv->stack[qiv->nb_stack - 1];
+ bool first;
+
+ if (so->entry == NULL) {
+ so->entry = qlist_first(qobject_to_qlist(so->obj));
+ first = true;
+ } else {
+ so->entry = qlist_next(so->entry);
+ first = false;
+ }
if (so->entry == NULL) {
return NULL;
}
entry = g_malloc0(sizeof(*entry));
- if (*list) {
- so->entry = qlist_next(so->entry);
- if (so->entry == NULL) {
- g_free(entry);
- return NULL;
- }
+ if (first) {
+ *list = entry;
+ } else {
(*list)->next = entry;
}
@@ -162,7 +190,7 @@
Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -177,7 +205,7 @@
Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -192,7 +220,7 @@
Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -207,7 +235,7 @@
Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -222,7 +250,7 @@
const char *name, Error **errp)
{
QmpInputVisitor *qiv = to_qiv(v);
- const QObject *qobj = qmp_input_get_object(qiv, name);
+ QObject *qobj = qmp_input_get_object(qiv, name);
if (!qobj) {
*present = false;
@@ -239,7 +267,7 @@
void qmp_input_visitor_cleanup(QmpInputVisitor *v)
{
- qobject_decref(v->obj);
+ qobject_decref(v->stack[0].obj);
g_free(v);
}
@@ -261,8 +289,18 @@
v->visitor.type_number = qmp_input_type_number;
v->visitor.start_optional = qmp_input_start_optional;
- v->obj = obj;
- qobject_incref(v->obj);
+ qmp_input_push(v, obj, NULL);
+ qobject_incref(obj);
+
+ return v;
+}
+
+QmpInputVisitor *qmp_input_visitor_new_strict(QObject *obj)
+{
+ QmpInputVisitor *v;
+
+ v = qmp_input_visitor_new(obj);
+ v->strict = true;
return v;
}
diff --git a/qapi/qmp-input-visitor.h b/qapi/qmp-input-visitor.h
index 3f798f0..e0a48a5 100644
--- a/qapi/qmp-input-visitor.h
+++ b/qapi/qmp-input-visitor.h
@@ -20,6 +20,8 @@
typedef struct QmpInputVisitor QmpInputVisitor;
QmpInputVisitor *qmp_input_visitor_new(QObject *obj);
+QmpInputVisitor *qmp_input_visitor_new_strict(QObject *obj);
+
void qmp_input_visitor_cleanup(QmpInputVisitor *v);
Visitor *qmp_input_get_visitor(QmpInputVisitor *v);
diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
index e0697b0..2bce9d5 100644
--- a/qapi/qmp-output-visitor.c
+++ b/qapi/qmp-output-visitor.c
@@ -199,14 +199,16 @@
{
QStackEntry *e, *tmp;
+ /* The bottom QStackEntry, if any, owns the root QObject. See the
+ * qmp_output_push_obj() invocations in qmp_output_add_obj(). */
+ QObject *root = QTAILQ_EMPTY(&v->stack) ? NULL : qmp_output_first(v);
+
QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
QTAILQ_REMOVE(&v->stack, e, node);
- if (e->value) {
- qobject_decref(e->value);
- }
g_free(e);
}
+ qobject_decref(root);
g_free(v);
}
diff --git a/qemu-options.hx b/qemu-options.hx
index daefce3..662f571 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -288,13 +288,21 @@
ETEXI
DEF("global", HAS_ARG, QEMU_OPTION_global,
- "-global driver.property=value\n"
+ "-global driver.prop=value\n"
" set a global default for a driver property\n",
QEMU_ARCH_ALL)
STEXI
-@item -global
+@item -global @var{driver}.@var{prop}=@var{value}
@findex -global
-TODO
+Set default value of @var{driver}'s property @var{prop} to @var{value}, e.g.:
+
+@example
+qemu -global ide-drive.physical_block_size=4096 -drive file=file,if=ide,index=0,media=disk
+@end example
+
+In particular, you can use this to set driver properties for devices which are
+created automatically by the machine model. To create a device which is not
+created automatically and set properties on it, use -@option{device}.
ETEXI
DEF("mtdblock", HAS_ARG, QEMU_OPTION_mtdblock,
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 7b2be2f..faf970d 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -12,29 +12,30 @@
*/
#include <glib.h>
-
-#if defined(__linux__)
-#include <mntent.h>
-#include <linux/fs.h>
-
-#if defined(__linux__) && defined(FIFREEZE)
-#define CONFIG_FSFREEZE
-#endif
-#endif
-
#include <sys/types.h>
#include <sys/ioctl.h>
-#include <ifaddrs.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#include <sys/wait.h>
#include "qga/guest-agent-core.h"
#include "qga-qmp-commands.h"
#include "qerror.h"
#include "qemu-queue.h"
#include "host-utils.h"
+#if defined(__linux__)
+#include <mntent.h>
+#include <linux/fs.h>
+#include <ifaddrs.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <sys/wait.h>
+
+#if defined(__linux__) && defined(FIFREEZE)
+#define CONFIG_FSFREEZE
+#endif
+#endif
+
+#if defined(__linux__)
+/* TODO: use this in place of all post-fork() fclose(std*) callers */
static void reopen_fd_to_null(int fd)
{
int nullfd;
@@ -50,6 +51,7 @@
close(nullfd);
}
}
+#endif /* defined(__linux__) */
void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
{
@@ -309,7 +311,11 @@
QTAILQ_INIT(&guest_file_state.filehandles);
}
+/* linux-specific implementations. avoid this if at all possible. */
+#if defined(__linux__)
+
#if defined(CONFIG_FSFREEZE)
+
static void disable_logging(void)
{
ga_disable_logging(ga_state);
@@ -505,38 +511,7 @@
}
}
}
-#else
-/*
- * Return status of freeze/thaw
- */
-GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
-{
- error_set(err, QERR_UNSUPPORTED);
-
- return 0;
-}
-
-/*
- * Walk list of mounted file systems in the guest, and freeze the ones which
- * are real local file systems.
- */
-int64_t qmp_guest_fsfreeze_freeze(Error **err)
-{
- error_set(err, QERR_UNSUPPORTED);
-
- return 0;
-}
-
-/*
- * Walk list of frozen file systems in the guest, and thaw them.
- */
-int64_t qmp_guest_fsfreeze_thaw(Error **err)
-{
- error_set(err, QERR_UNSUPPORTED);
-
- return 0;
-}
-#endif
+#endif /* CONFIG_FSFREEZE */
#define LINUX_SYS_STATE_FILE "/sys/power/state"
#define SUSPEND_SUPPORTED 0
@@ -904,6 +879,52 @@
return NULL;
}
+#else /* defined(__linux__) */
+
+GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
+{
+ error_set(err, QERR_UNSUPPORTED);
+
+ return 0;
+}
+
+int64_t qmp_guest_fsfreeze_freeze(Error **err)
+{
+ error_set(err, QERR_UNSUPPORTED);
+
+ return 0;
+}
+
+int64_t qmp_guest_fsfreeze_thaw(Error **err)
+{
+ error_set(err, QERR_UNSUPPORTED);
+
+ return 0;
+}
+
+void qmp_guest_suspend_disk(Error **err)
+{
+ error_set(err, QERR_UNSUPPORTED);
+}
+
+void qmp_guest_suspend_ram(Error **err)
+{
+ error_set(err, QERR_UNSUPPORTED);
+}
+
+void qmp_guest_suspend_hybrid(Error **err)
+{
+ error_set(err, QERR_UNSUPPORTED);
+}
+
+GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
+{
+ error_set(errp, QERR_UNSUPPORTED);
+ return NULL;
+}
+
+#endif
+
/* register init/cleanup routines for stateful command groups */
void ga_command_state_init(GAState *s, GACommandState *cs)
{
diff --git a/qmp-commands.hx b/qmp-commands.hx
index c626ba8..9447871 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -708,7 +708,7 @@
},
{
.name = "transaction",
- .args_type = "actions:O",
+ .args_type = "actions:q",
.mhandler.cmd_new = qmp_marshal_input_transaction,
},
@@ -2125,7 +2125,7 @@
{
.name = "qom-set",
- .args_type = "path:s,property:s,opts:O",
+ .args_type = "path:s,property:s,value:q",
.mhandler.cmd_new = qmp_qom_set,
},
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 3aabf61..0b4f0a0 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -42,7 +42,7 @@
return mcgen('''
%(ret_type)s qmp_%(name)s(%(args)sError **errp);
''',
- ret_type=c_type(ret_type), name=c_var(name), args=arglist).strip()
+ ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip()
def gen_sync_call(name, args, ret_type, indent=0):
ret = ""
@@ -59,7 +59,7 @@
%(retval)sqmp_%(name)s(%(args)serrp);
''',
- name=c_var(name), args=arglist, retval=retval).rstrip()
+ name=c_fun(name), args=arglist, retval=retval).rstrip()
if ret_type:
ret += "\n" + mcgen(''''
if (!error_is_set(errp)) {
@@ -74,7 +74,7 @@
def gen_marshal_output_call(name, ret_type):
if not ret_type:
return ""
- return "qmp_marshal_output_%s(retval, ret, errp);" % c_var(name)
+ return "qmp_marshal_output_%s(retval, ret, errp);" % c_fun(name)
def gen_visitor_output_containers_decl(ret_type):
ret = ""
@@ -140,7 +140,7 @@
''')
else:
ret += mcgen('''
-mi = qmp_input_visitor_new(%(obj)s);
+mi = qmp_input_visitor_new_strict(%(obj)s);
v = qmp_input_get_visitor(mi);
''',
obj=obj)
@@ -198,16 +198,16 @@
qapi_dealloc_visitor_cleanup(md);
}
''',
- c_ret_type=c_type(ret_type), c_name=c_var(name),
+ c_ret_type=c_type(ret_type), c_name=c_fun(name),
visitor=type_visitor(ret_type))
return ret
def gen_marshal_input_decl(name, args, ret_type, middle_mode):
if middle_mode:
- return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_var(name)
+ return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_fun(name)
else:
- return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_var(name)
+ return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_fun(name)
@@ -298,7 +298,7 @@
registry += mcgen('''
qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s);
''',
- name=cmd['command'], c_name=c_var(cmd['command']))
+ name=cmd['command'], c_name=c_fun(cmd['command']))
pop_indent()
ret = mcgen('''
static void qmp_init_marshal(void)
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 727fb77..4a734f5 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -100,7 +100,7 @@
%(abbrev)s_%(value)s = %(i)d,
''',
abbrev=de_camel_case(name).upper(),
- value=c_var(value).upper(),
+ value=c_fun(value).upper(),
i=i)
i += 1
@@ -126,7 +126,7 @@
%(c_type)s %(c_name)s;
''',
c_type=c_type(typeinfo[key]),
- c_name=c_var(key))
+ c_name=c_fun(key))
ret += mcgen('''
};
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 54117d4..8d4e94a 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -61,7 +61,13 @@
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
{
+ if (error_is_set(errp)) {
+ return;
+ }
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), errp);
+ if (obj && !*obj) {
+ goto end;
+ }
''',
name=name)
push_indent()
@@ -69,6 +75,7 @@
pop_indent()
ret += mcgen('''
+end:
visit_end_struct(m, errp);
}
''')
@@ -79,11 +86,14 @@
void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
{
- GenericList *i, **head = (GenericList **)obj;
+ GenericList *i, **prev = (GenericList **)obj;
+ if (error_is_set(errp)) {
+ return;
+ }
visit_start_list(m, name, errp);
- for (*head = i = visit_next_list(m, head, errp); i; i = visit_next_list(m, &i, errp)) {
+ for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) {
%(name)sList *native_i = (%(name)sList *)i;
visit_type_%(name)s(m, &native_i->value, NULL, errp);
}
@@ -112,7 +122,13 @@
{
Error *err = NULL;
+ if (error_is_set(errp)) {
+ return;
+ }
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
+ if (obj && !*obj) {
+ goto end;
+ }
visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err);
if (err) {
error_propagate(errp, err);
@@ -129,9 +145,9 @@
break;
''',
abbrev = de_camel_case(name).upper(),
- enum = de_camel_case(key).upper(),
+ enum = c_fun(de_camel_case(key)).upper(),
c_type=members[key],
- c_name=c_var(key))
+ c_name=c_fun(key))
ret += mcgen('''
default:
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 6e05469..e062336 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -131,7 +131,10 @@
return new_name
def c_var(name):
- return '_'.join(name.split('-')).lstrip("*")
+ return name.replace('-', '_').lstrip("*")
+
+def c_fun(name):
+ return c_var(name).replace('.', '_')
def c_list_type(name):
return '%sList' % name
diff --git a/scripts/qemu-gdb.py b/scripts/qemu-gdb.py
new file mode 100644
index 0000000..8a0f305
--- /dev/null
+++ b/scripts/qemu-gdb.py
@@ -0,0 +1,89 @@
+#!/usr/bin/python
+
+# GDB debugging support
+#
+# Copyright 2012 Red Hat, Inc. and/or its affiliates
+#
+# Authors:
+# Avi Kivity <avi@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2. See
+# the COPYING file in the top-level directory.
+#
+# Contributions after 2012-01-13 are licensed under the terms of the
+# GNU GPL, version 2 or (at your option) any later version.
+
+
+import gdb
+
+def isnull(ptr):
+ return ptr == gdb.Value(0).cast(ptr.type)
+
+def int128(p):
+ return long(p['lo']) + (long(p['hi']) << 64)
+
+class QemuCommand(gdb.Command):
+ '''Prefix for QEMU debug support commands'''
+ def __init__(self):
+ gdb.Command.__init__(self, 'qemu', gdb.COMMAND_DATA,
+ gdb.COMPLETE_NONE, True)
+
+class MtreeCommand(gdb.Command):
+ '''Display the memory tree hierarchy'''
+ def __init__(self):
+ gdb.Command.__init__(self, 'qemu mtree', gdb.COMMAND_DATA,
+ gdb.COMPLETE_NONE)
+ self.queue = []
+ def invoke(self, arg, from_tty):
+ self.seen = set()
+ self.queue_root('address_space_memory')
+ self.queue_root('address_space_io')
+ self.process_queue()
+ def queue_root(self, varname):
+ ptr = gdb.parse_and_eval(varname)['root']
+ self.queue.append(ptr)
+ def process_queue(self):
+ while self.queue:
+ ptr = self.queue.pop(0)
+ if long(ptr) in self.seen:
+ continue
+ self.print_item(ptr)
+ def print_item(self, ptr, offset = gdb.Value(0), level = 0):
+ self.seen.add(long(ptr))
+ addr = ptr['addr']
+ addr += offset
+ size = int128(ptr['size'])
+ alias = ptr['alias']
+ klass = ''
+ if not isnull(alias):
+ klass = ' (alias)'
+ elif not isnull(ptr['ops']):
+ klass = ' (I/O)'
+ elif bool(ptr['ram']):
+ klass = ' (RAM)'
+ gdb.write('%s%016x-%016x %s%s (@ %s)\n'
+ % (' ' * level,
+ long(addr),
+ long(addr + (size - 1)),
+ ptr['name'].string(),
+ klass,
+ ptr,
+ ),
+ gdb.STDOUT)
+ if not isnull(alias):
+ gdb.write('%s alias: %s@%016x (@ %s)\n' %
+ (' ' * level,
+ alias['name'].string(),
+ ptr['alias_offset'],
+ alias,
+ ),
+ gdb.STDOUT)
+ self.queue.append(alias)
+ subregion = ptr['subregions']['tqh_first']
+ level += 1
+ while not isnull(subregion):
+ self.print_item(subregion, addr, level)
+ subregion = subregion['subregions_link']['tqe_next']
+
+QemuCommand()
+MtreeCommand()
diff --git a/scripts/texi2pod.pl b/scripts/texi2pod.pl
index 9ed056a..94097fb 100755
--- a/scripts/texi2pod.pl
+++ b/scripts/texi2pod.pl
@@ -36,6 +36,7 @@
$inf = "";
$ibase = "";
@ipath = ();
+$encoding = undef;
while ($_ = shift) {
if (/^-D(.*)$/) {
@@ -97,6 +98,12 @@
/^\@setfilename\s+([^.]+)/ and $fn = $1, next;
/^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next;
+ # Look for document encoding
+ /^\@documentencoding\s+([^.]+)/ and do {
+ $encoding = $1 unless defined $encoding;
+ next;
+ };
+
# Identify a man title but keep only the one we are interested in.
/^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do {
if (exists $defs{$1}) {
@@ -336,6 +343,8 @@
die "No filename or title\n" unless defined $fn && defined $tl;
+print "=encoding $encoding\n\n" if defined $encoding;
+
$sects{NAME} = "$fn \- $tl\n";
$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 48c0fdc..6c5d28b 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -234,7 +234,6 @@
uint8_t fpcr_exc_mask;
uint8_t fpcr_dyn_round;
uint8_t fpcr_flush_to_zero;
- uint8_t fpcr_dnz;
uint8_t fpcr_dnod;
uint8_t fpcr_undz;
@@ -434,6 +433,9 @@
int mmu_idx);
#define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault
void do_interrupt (CPUAlphaState *env);
+void do_restore_state(CPUAlphaState *, void *retaddr);
+void QEMU_NORETURN dynamic_excp(CPUAlphaState *, void *, int, int);
+void QEMU_NORETURN arith_excp(CPUAlphaState *, void *, int, uint64_t);
uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env);
void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val);
diff --git a/target-alpha/fpu_helper.c b/target-alpha/fpu_helper.c
new file mode 100644
index 0000000..dda1103
--- /dev/null
+++ b/target-alpha/fpu_helper.c
@@ -0,0 +1,822 @@
+/*
+ * Helpers for floating point instructions.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "cpu.h"
+#include "helper.h"
+#include "softfloat.h"
+
+#define FP_STATUS (env->fp_status)
+
+
+void helper_setroundmode(CPUAlphaState *env, uint32_t val)
+{
+ set_float_rounding_mode(val, &FP_STATUS);
+}
+
+void helper_setflushzero(CPUAlphaState *env, uint32_t val)
+{
+ set_flush_to_zero(val, &FP_STATUS);
+}
+
+void helper_fp_exc_clear(CPUAlphaState *env)
+{
+ set_float_exception_flags(0, &FP_STATUS);
+}
+
+uint32_t helper_fp_exc_get(CPUAlphaState *env)
+{
+ return get_float_exception_flags(&FP_STATUS);
+}
+
+static inline void inline_fp_exc_raise(CPUAlphaState *env, void *retaddr,
+ uint32_t exc, uint32_t regno)
+{
+ if (exc) {
+ uint32_t hw_exc = 0;
+
+ if (exc & float_flag_invalid) {
+ hw_exc |= EXC_M_INV;
+ }
+ if (exc & float_flag_divbyzero) {
+ hw_exc |= EXC_M_DZE;
+ }
+ if (exc & float_flag_overflow) {
+ hw_exc |= EXC_M_FOV;
+ }
+ if (exc & float_flag_underflow) {
+ hw_exc |= EXC_M_UNF;
+ }
+ if (exc & float_flag_inexact) {
+ hw_exc |= EXC_M_INE;
+ }
+
+ arith_excp(env, retaddr, hw_exc, 1ull << regno);
+ }
+}
+
+/* Raise exceptions for ieee fp insns without software completion.
+ In that case there are no exceptions that don't trap; the mask
+ doesn't apply. */
+void helper_fp_exc_raise(CPUAlphaState *env, uint32_t exc, uint32_t regno)
+{
+ inline_fp_exc_raise(env, GETPC(), exc, regno);
+}
+
+/* Raise exceptions for ieee fp insns with software completion. */
+void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t exc, uint32_t regno)
+{
+ if (exc) {
+ env->fpcr_exc_status |= exc;
+ exc &= ~env->fpcr_exc_mask;
+ inline_fp_exc_raise(env, GETPC(), exc, regno);
+ }
+}
+
+/* Input handing without software completion. Trap for all
+ non-finite numbers. */
+void helper_ieee_input(CPUAlphaState *env, uint64_t val)
+{
+ uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
+ uint64_t frac = val & 0xfffffffffffffull;
+
+ if (exp == 0) {
+ /* Denormals without DNZ set raise an exception. */
+ if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
+ arith_excp(env, GETPC(), EXC_M_UNF, 0);
+ }
+ } else if (exp == 0x7ff) {
+ /* Infinity or NaN. */
+ /* ??? I'm not sure these exception bit flags are correct. I do
+ know that the Linux kernel, at least, doesn't rely on them and
+ just emulates the insn to figure out what exception to use. */
+ arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0);
+ }
+}
+
+/* Similar, but does not trap for infinities. Used for comparisons. */
+void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
+{
+ uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
+ uint64_t frac = val & 0xfffffffffffffull;
+
+ if (exp == 0) {
+ /* Denormals without DNZ set raise an exception. */
+ if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
+ arith_excp(env, GETPC(), EXC_M_UNF, 0);
+ }
+ } else if (exp == 0x7ff && frac) {
+ /* NaN. */
+ arith_excp(env, GETPC(), EXC_M_INV, 0);
+ }
+}
+
+/* F floating (VAX) */
+static uint64_t float32_to_f(float32 fa)
+{
+ uint64_t r, exp, mant, sig;
+ CPU_FloatU a;
+
+ a.f = fa;
+ sig = ((uint64_t)a.l & 0x80000000) << 32;
+ exp = (a.l >> 23) & 0xff;
+ mant = ((uint64_t)a.l & 0x007fffff) << 29;
+
+ if (exp == 255) {
+ /* NaN or infinity */
+ r = 1; /* VAX dirty zero */
+ } else if (exp == 0) {
+ if (mant == 0) {
+ /* Zero */
+ r = 0;
+ } else {
+ /* Denormalized */
+ r = sig | ((exp + 1) << 52) | mant;
+ }
+ } else {
+ if (exp >= 253) {
+ /* Overflow */
+ r = 1; /* VAX dirty zero */
+ } else {
+ r = sig | ((exp + 2) << 52);
+ }
+ }
+
+ return r;
+}
+
+static float32 f_to_float32(CPUAlphaState *env, void *retaddr, uint64_t a)
+{
+ uint32_t exp, mant_sig;
+ CPU_FloatU r;
+
+ exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f);
+ mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff);
+
+ if (unlikely(!exp && mant_sig)) {
+ /* Reserved operands / Dirty zero */
+ dynamic_excp(env, retaddr, EXCP_OPCDEC, 0);
+ }
+
+ if (exp < 3) {
+ /* Underflow */
+ r.l = 0;
+ } else {
+ r.l = ((exp - 2) << 23) | mant_sig;
+ }
+
+ return r.f;
+}
+
+uint32_t helper_f_to_memory(uint64_t a)
+{
+ uint32_t r;
+ r = (a & 0x00001fffe0000000ull) >> 13;
+ r |= (a & 0x07ffe00000000000ull) >> 45;
+ r |= (a & 0xc000000000000000ull) >> 48;
+ return r;
+}
+
+uint64_t helper_memory_to_f(uint32_t a)
+{
+ uint64_t r;
+ r = ((uint64_t)(a & 0x0000c000)) << 48;
+ r |= ((uint64_t)(a & 0x003fffff)) << 45;
+ r |= ((uint64_t)(a & 0xffff0000)) << 13;
+ if (!(a & 0x00004000)) {
+ r |= 0x7ll << 59;
+ }
+ return r;
+}
+
+/* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong. We should
+ either implement VAX arithmetic properly or just signal invalid opcode. */
+
+uint64_t helper_addf(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = f_to_float32(env, GETPC(), a);
+ fb = f_to_float32(env, GETPC(), b);
+ fr = float32_add(fa, fb, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+uint64_t helper_subf(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = f_to_float32(env, GETPC(), a);
+ fb = f_to_float32(env, GETPC(), b);
+ fr = float32_sub(fa, fb, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+uint64_t helper_mulf(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = f_to_float32(env, GETPC(), a);
+ fb = f_to_float32(env, GETPC(), b);
+ fr = float32_mul(fa, fb, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+uint64_t helper_divf(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = f_to_float32(env, GETPC(), a);
+ fb = f_to_float32(env, GETPC(), b);
+ fr = float32_div(fa, fb, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+uint64_t helper_sqrtf(CPUAlphaState *env, uint64_t t)
+{
+ float32 ft, fr;
+
+ ft = f_to_float32(env, GETPC(), t);
+ fr = float32_sqrt(ft, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+
+/* G floating (VAX) */
+static uint64_t float64_to_g(float64 fa)
+{
+ uint64_t r, exp, mant, sig;
+ CPU_DoubleU a;
+
+ a.d = fa;
+ sig = a.ll & 0x8000000000000000ull;
+ exp = (a.ll >> 52) & 0x7ff;
+ mant = a.ll & 0x000fffffffffffffull;
+
+ if (exp == 2047) {
+ /* NaN or infinity */
+ r = 1; /* VAX dirty zero */
+ } else if (exp == 0) {
+ if (mant == 0) {
+ /* Zero */
+ r = 0;
+ } else {
+ /* Denormalized */
+ r = sig | ((exp + 1) << 52) | mant;
+ }
+ } else {
+ if (exp >= 2045) {
+ /* Overflow */
+ r = 1; /* VAX dirty zero */
+ } else {
+ r = sig | ((exp + 2) << 52);
+ }
+ }
+
+ return r;
+}
+
+static float64 g_to_float64(CPUAlphaState *env, void *retaddr, uint64_t a)
+{
+ uint64_t exp, mant_sig;
+ CPU_DoubleU r;
+
+ exp = (a >> 52) & 0x7ff;
+ mant_sig = a & 0x800fffffffffffffull;
+
+ if (!exp && mant_sig) {
+ /* Reserved operands / Dirty zero */
+ dynamic_excp(env, retaddr, EXCP_OPCDEC, 0);
+ }
+
+ if (exp < 3) {
+ /* Underflow */
+ r.ll = 0;
+ } else {
+ r.ll = ((exp - 2) << 52) | mant_sig;
+ }
+
+ return r.d;
+}
+
+uint64_t helper_g_to_memory(uint64_t a)
+{
+ uint64_t r;
+ r = (a & 0x000000000000ffffull) << 48;
+ r |= (a & 0x00000000ffff0000ull) << 16;
+ r |= (a & 0x0000ffff00000000ull) >> 16;
+ r |= (a & 0xffff000000000000ull) >> 48;
+ return r;
+}
+
+uint64_t helper_memory_to_g(uint64_t a)
+{
+ uint64_t r;
+ r = (a & 0x000000000000ffffull) << 48;
+ r |= (a & 0x00000000ffff0000ull) << 16;
+ r |= (a & 0x0000ffff00000000ull) >> 16;
+ r |= (a & 0xffff000000000000ull) >> 48;
+ return r;
+}
+
+uint64_t helper_addg(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+ fr = float64_add(fa, fb, &FP_STATUS);
+ return float64_to_g(fr);
+}
+
+uint64_t helper_subg(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+ fr = float64_sub(fa, fb, &FP_STATUS);
+ return float64_to_g(fr);
+}
+
+uint64_t helper_mulg(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+ fr = float64_mul(fa, fb, &FP_STATUS);
+ return float64_to_g(fr);
+}
+
+uint64_t helper_divg(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+ fr = float64_div(fa, fb, &FP_STATUS);
+ return float64_to_g(fr);
+}
+
+uint64_t helper_sqrtg(CPUAlphaState *env, uint64_t a)
+{
+ float64 fa, fr;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fr = float64_sqrt(fa, &FP_STATUS);
+ return float64_to_g(fr);
+}
+
+
+/* S floating (single) */
+
+/* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */
+static inline uint64_t float32_to_s_int(uint32_t fi)
+{
+ uint32_t frac = fi & 0x7fffff;
+ uint32_t sign = fi >> 31;
+ uint32_t exp_msb = (fi >> 30) & 1;
+ uint32_t exp_low = (fi >> 23) & 0x7f;
+ uint32_t exp;
+
+ exp = (exp_msb << 10) | exp_low;
+ if (exp_msb) {
+ if (exp_low == 0x7f) {
+ exp = 0x7ff;
+ }
+ } else {
+ if (exp_low != 0x00) {
+ exp |= 0x380;
+ }
+ }
+
+ return (((uint64_t)sign << 63)
+ | ((uint64_t)exp << 52)
+ | ((uint64_t)frac << 29));
+}
+
+static inline uint64_t float32_to_s(float32 fa)
+{
+ CPU_FloatU a;
+ a.f = fa;
+ return float32_to_s_int(a.l);
+}
+
+static inline uint32_t s_to_float32_int(uint64_t a)
+{
+ return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
+}
+
+static inline float32 s_to_float32(uint64_t a)
+{
+ CPU_FloatU r;
+ r.l = s_to_float32_int(a);
+ return r.f;
+}
+
+uint32_t helper_s_to_memory(uint64_t a)
+{
+ return s_to_float32_int(a);
+}
+
+uint64_t helper_memory_to_s(uint32_t a)
+{
+ return float32_to_s_int(a);
+}
+
+uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = s_to_float32(a);
+ fb = s_to_float32(b);
+ fr = float32_add(fa, fb, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = s_to_float32(a);
+ fb = s_to_float32(b);
+ fr = float32_sub(fa, fb, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = s_to_float32(a);
+ fb = s_to_float32(b);
+ fr = float32_mul(fa, fb, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float32 fa, fb, fr;
+
+ fa = s_to_float32(a);
+ fb = s_to_float32(b);
+ fr = float32_div(fa, fb, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
+{
+ float32 fa, fr;
+
+ fa = s_to_float32(a);
+ fr = float32_sqrt(fa, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+
+/* T floating (double) */
+static inline float64 t_to_float64(uint64_t a)
+{
+ /* Memory format is the same as float64 */
+ CPU_DoubleU r;
+ r.ll = a;
+ return r.d;
+}
+
+static inline uint64_t float64_to_t(float64 fa)
+{
+ /* Memory format is the same as float64 */
+ CPU_DoubleU r;
+ r.d = fa;
+ return r.ll;
+}
+
+uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+ fr = float64_add(fa, fb, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+ fr = float64_sub(fa, fb, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+ fr = float64_mul(fa, fb, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb, fr;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+ fr = float64_div(fa, fb, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
+{
+ float64 fa, fr;
+
+ fa = t_to_float64(a);
+ fr = float64_sqrt(fa, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+/* Comparisons */
+uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+
+ if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+
+ if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+
+ if (float64_le(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = t_to_float64(a);
+ fb = t_to_float64(b);
+
+ if (float64_lt(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t helper_cmpgeq(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+
+ if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t helper_cmpgle(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+
+ if (float64_le(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+uint64_t helper_cmpglt(CPUAlphaState *env, uint64_t a, uint64_t b)
+{
+ float64 fa, fb;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fb = g_to_float64(env, GETPC(), b);
+
+ if (float64_lt(fa, fb, &FP_STATUS)) {
+ return 0x4000000000000000ULL;
+ } else {
+ return 0;
+ }
+}
+
+/* Floating point format conversion */
+uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
+{
+ float64 fa;
+ float32 fr;
+
+ fa = t_to_float64(a);
+ fr = float64_to_float32(fa, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
+{
+ float32 fa;
+ float64 fr;
+
+ fa = s_to_float32(a);
+ fr = float32_to_float64(fa, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
+{
+ float32 fr = int64_to_float32(a, &FP_STATUS);
+ return float32_to_s(fr);
+}
+
+/* Implement float64 to uint64 conversion without saturation -- we must
+ supply the truncated result. This behaviour is used by the compiler
+ to get unsigned conversion for free with the same instruction.
+
+ The VI flag is set when overflow or inexact exceptions should be raised. */
+
+static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
+ int roundmode, int VI)
+{
+ uint64_t frac, ret = 0;
+ uint32_t exp, sign, exc = 0;
+ int shift;
+
+ sign = (a >> 63);
+ exp = (uint32_t)(a >> 52) & 0x7ff;
+ frac = a & 0xfffffffffffffull;
+
+ if (exp == 0) {
+ if (unlikely(frac != 0)) {
+ goto do_underflow;
+ }
+ } else if (exp == 0x7ff) {
+ exc = (frac ? float_flag_invalid : VI ? float_flag_overflow : 0);
+ } else {
+ /* Restore implicit bit. */
+ frac |= 0x10000000000000ull;
+
+ shift = exp - 1023 - 52;
+ if (shift >= 0) {
+ /* In this case the number is so large that we must shift
+ the fraction left. There is no rounding to do. */
+ if (shift < 63) {
+ ret = frac << shift;
+ if (VI && (ret >> shift) != frac) {
+ exc = float_flag_overflow;
+ }
+ }
+ } else {
+ uint64_t round;
+
+ /* In this case the number is smaller than the fraction as
+ represented by the 52 bit number. Here we must think
+ about rounding the result. Handle this by shifting the
+ fractional part of the number into the high bits of ROUND.
+ This will let us efficiently handle round-to-nearest. */
+ shift = -shift;
+ if (shift < 63) {
+ ret = frac >> shift;
+ round = frac << (64 - shift);
+ } else {
+ /* The exponent is so small we shift out everything.
+ Leave a sticky bit for proper rounding below. */
+ do_underflow:
+ round = 1;
+ }
+
+ if (round) {
+ exc = (VI ? float_flag_inexact : 0);
+ switch (roundmode) {
+ case float_round_nearest_even:
+ if (round == (1ull << 63)) {
+ /* Fraction is exactly 0.5; round to even. */
+ ret += (ret & 1);
+ } else if (round > (1ull << 63)) {
+ ret += 1;
+ }
+ break;
+ case float_round_to_zero:
+ break;
+ case float_round_up:
+ ret += 1 - sign;
+ break;
+ case float_round_down:
+ ret += sign;
+ break;
+ }
+ }
+ }
+ if (sign) {
+ ret = -ret;
+ }
+ }
+ if (unlikely(exc)) {
+ float_raise(exc, &FP_STATUS);
+ }
+
+ return ret;
+}
+
+uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
+{
+ return inline_cvttq(env, a, FP_STATUS.float_rounding_mode, 1);
+}
+
+uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
+{
+ return inline_cvttq(env, a, float_round_to_zero, 0);
+}
+
+uint64_t helper_cvttq_svic(CPUAlphaState *env, uint64_t a)
+{
+ return inline_cvttq(env, a, float_round_to_zero, 1);
+}
+
+uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
+{
+ float64 fr = int64_to_float64(a, &FP_STATUS);
+ return float64_to_t(fr);
+}
+
+uint64_t helper_cvtqf(CPUAlphaState *env, uint64_t a)
+{
+ float32 fr = int64_to_float32(a, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+uint64_t helper_cvtgf(CPUAlphaState *env, uint64_t a)
+{
+ float64 fa;
+ float32 fr;
+
+ fa = g_to_float64(env, GETPC(), a);
+ fr = float64_to_float32(fa, &FP_STATUS);
+ return float32_to_f(fr);
+}
+
+uint64_t helper_cvtgq(CPUAlphaState *env, uint64_t a)
+{
+ float64 fa = g_to_float64(env, GETPC(), a);
+ return float64_to_int64_round_to_zero(fa, &FP_STATUS);
+}
+
+uint64_t helper_cvtqg(CPUAlphaState *env, uint64_t a)
+{
+ float64 fr;
+ fr = int64_to_float64(a, &FP_STATUS);
+ return float64_to_g(fr);
+}
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 3f2e7c3..765e650 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -23,6 +23,7 @@
#include "cpu.h"
#include "softfloat.h"
+#include "helper.h"
uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env)
{
@@ -81,7 +82,7 @@
break;
}
- if (env->fpcr_dnz) {
+ if (env->fp_status.flush_inputs_to_zero) {
r |= FPCR_DNZ;
}
if (env->fpcr_dnod) {
@@ -150,17 +151,25 @@
}
env->fpcr_dyn_round = t;
- env->fpcr_flush_to_zero
- = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
-
- env->fpcr_dnz = (val & FPCR_DNZ) != 0;
env->fpcr_dnod = (val & FPCR_DNOD) != 0;
env->fpcr_undz = (val & FPCR_UNDZ) != 0;
+ env->fpcr_flush_to_zero = env->fpcr_dnod & env->fpcr_undz;
+ env->fp_status.flush_inputs_to_zero = (val & FPCR_DNZ) != 0;
+}
+
+uint64_t helper_load_fpcr(CPUAlphaState *env)
+{
+ return cpu_alpha_load_fpcr(env);
+}
+
+void helper_store_fpcr(CPUAlphaState *env, uint64_t val)
+{
+ cpu_alpha_store_fpcr(env, val);
}
#if defined(CONFIG_USER_ONLY)
-int cpu_alpha_handle_mmu_fault (CPUAlphaState *env, target_ulong address, int rw,
- int mmu_idx)
+int cpu_alpha_handle_mmu_fault(CPUAlphaState *env, target_ulong address,
+ int rw, int mmu_idx)
{
env->exception_index = EXCP_MMFAULT;
env->trap_arg0 = address;
@@ -484,3 +493,41 @@
}
cpu_fprintf(f, "\n");
}
+
+void do_restore_state(CPUAlphaState *env, void *retaddr)
+{
+ uintptr_t pc = (uintptr_t)retaddr;
+ if (pc) {
+ TranslationBlock *tb = tb_find_pc(pc);
+ if (tb) {
+ cpu_restore_state(tb, env, pc);
+ }
+ }
+}
+
+/* This should only be called from translate, via gen_excp.
+ We expect that ENV->PC has already been updated. */
+void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error)
+{
+ env->exception_index = excp;
+ env->error_code = error;
+ cpu_loop_exit(env);
+}
+
+/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
+void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, void *retaddr,
+ int excp, int error)
+{
+ env->exception_index = excp;
+ env->error_code = error;
+ do_restore_state(env, retaddr);
+ cpu_loop_exit(env);
+}
+
+void QEMU_NORETURN arith_excp(CPUAlphaState *env, void *retaddr,
+ int exc, uint64_t mask)
+{
+ env->trap_arg0 = exc;
+ env->trap_arg1 = mask;
+ dynamic_excp(env, retaddr, EXCP_ARITH, 0);
+}
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index b693cee..a184def 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -1,14 +1,14 @@
#include "def-helper.h"
-DEF_HELPER_2(excp, void, int, int)
-DEF_HELPER_FLAGS_0(load_pcc, TCG_CALL_CONST | TCG_CALL_PURE, i64)
+DEF_HELPER_3(excp, noreturn, env, int, int)
+DEF_HELPER_FLAGS_1(load_pcc, TCG_CALL_CONST | TCG_CALL_PURE, i64, env)
-DEF_HELPER_2(addqv, i64, i64, i64)
-DEF_HELPER_2(addlv, i64, i64, i64)
-DEF_HELPER_2(subqv, i64, i64, i64)
-DEF_HELPER_2(sublv, i64, i64, i64)
-DEF_HELPER_2(mullv, i64, i64, i64)
-DEF_HELPER_2(mulqv, i64, i64, i64)
+DEF_HELPER_3(addqv, i64, env, i64, i64)
+DEF_HELPER_3(addlv, i64, env, i64, i64)
+DEF_HELPER_3(subqv, i64, env, i64, i64)
+DEF_HELPER_3(sublv, i64, env, i64, i64)
+DEF_HELPER_3(mullv, i64, env, i64, i64)
+DEF_HELPER_3(mulqv, i64, env, i64, i64)
DEF_HELPER_FLAGS_2(umulh, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
DEF_HELPER_FLAGS_1(ctpop, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
@@ -34,90 +34,89 @@
DEF_HELPER_FLAGS_1(unpkbl, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
DEF_HELPER_FLAGS_1(unpkbw, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
-DEF_HELPER_FLAGS_0(load_fpcr, TCG_CALL_CONST | TCG_CALL_PURE, i64)
-DEF_HELPER_FLAGS_1(store_fpcr, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(load_fpcr, TCG_CALL_CONST | TCG_CALL_PURE, i64, env)
+DEF_HELPER_FLAGS_2(store_fpcr, TCG_CALL_CONST, void, env, i64)
DEF_HELPER_FLAGS_1(f_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64)
DEF_HELPER_FLAGS_1(memory_to_f, TCG_CALL_CONST | TCG_CALL_PURE, i64, i32)
-DEF_HELPER_FLAGS_2(addf, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(subf, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(mulf, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(divf, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_1(sqrtf, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_3(addf, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(subf, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(mulf, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(divf, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_2(sqrtf, TCG_CALL_CONST, i64, env, i64)
DEF_HELPER_FLAGS_1(g_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
DEF_HELPER_FLAGS_1(memory_to_g, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64)
-DEF_HELPER_FLAGS_2(addg, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(subg, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(mulg, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(divg, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_1(sqrtg, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_3(addg, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(subg, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(mulg, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(divg, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_2(sqrtg, TCG_CALL_CONST, i64, env, i64)
DEF_HELPER_FLAGS_1(s_to_memory, TCG_CALL_CONST | TCG_CALL_PURE, i32, i64)
DEF_HELPER_FLAGS_1(memory_to_s, TCG_CALL_CONST | TCG_CALL_PURE, i64, i32)
-DEF_HELPER_FLAGS_2(adds, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(subs, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(muls, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(divs, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_1(sqrts, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_3(adds, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(subs, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(muls, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(divs, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_2(sqrts, TCG_CALL_CONST, i64, env, i64)
-DEF_HELPER_FLAGS_2(addt, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(subt, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(mult, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_2(divt, TCG_CALL_CONST, i64, i64, i64)
-DEF_HELPER_FLAGS_1(sqrtt, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_3(addt, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(subt, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(mult, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(divt, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_2(sqrtt, TCG_CALL_CONST, i64, env, i64)
-DEF_HELPER_FLAGS_2(cmptun, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(cmpteq, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(cmptle, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(cmptlt, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(cmpgeq, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(cmpgle, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(cmpglt, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
+DEF_HELPER_FLAGS_3(cmptun, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(cmpteq, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(cmptle, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(cmptlt, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(cmpgeq, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(cmpgle, TCG_CALL_CONST, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(cmpglt, TCG_CALL_CONST, i64, env, i64, i64)
-DEF_HELPER_FLAGS_1(cvtts, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtst, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtqs, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtqt, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtqf, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtgf, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtgq, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvtqg, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_2(cvtts, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtst, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtqs, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtqt, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtqf, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtgf, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtgq, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvtqg, TCG_CALL_CONST, i64, env, i64)
-DEF_HELPER_FLAGS_1(cvttq, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvttq_c, TCG_CALL_CONST, i64, i64)
-DEF_HELPER_FLAGS_1(cvttq_svic, TCG_CALL_CONST, i64, i64)
+DEF_HELPER_FLAGS_2(cvttq, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvttq_c, TCG_CALL_CONST, i64, env, i64)
+DEF_HELPER_FLAGS_2(cvttq_svic, TCG_CALL_CONST, i64, env, i64)
-DEF_HELPER_FLAGS_1(setroundmode, TCG_CALL_CONST, void, i32)
-DEF_HELPER_FLAGS_1(setflushzero, TCG_CALL_CONST, void, i32)
-DEF_HELPER_FLAGS_0(fp_exc_clear, TCG_CALL_CONST, void)
-DEF_HELPER_FLAGS_0(fp_exc_get, TCG_CALL_CONST | TCG_CALL_PURE, i32)
-DEF_HELPER_2(fp_exc_raise, void, i32, i32)
-DEF_HELPER_2(fp_exc_raise_s, void, i32, i32)
+DEF_HELPER_FLAGS_2(setroundmode, TCG_CALL_CONST, void, env, i32)
+DEF_HELPER_FLAGS_2(setflushzero, TCG_CALL_CONST, void, env, i32)
+DEF_HELPER_FLAGS_1(fp_exc_clear, TCG_CALL_CONST, void, env)
+DEF_HELPER_FLAGS_1(fp_exc_get, TCG_CALL_CONST | TCG_CALL_PURE, i32, env)
+DEF_HELPER_3(fp_exc_raise, void, env, i32, i32)
+DEF_HELPER_3(fp_exc_raise_s, void, env, i32, i32)
-DEF_HELPER_1(ieee_input, i64, i64)
-DEF_HELPER_1(ieee_input_cmp, i64, i64)
-DEF_HELPER_1(ieee_input_s, i64, i64)
+DEF_HELPER_2(ieee_input, void, env, i64)
+DEF_HELPER_2(ieee_input_cmp, void, env, i64)
#if !defined (CONFIG_USER_ONLY)
-DEF_HELPER_1(hw_ret, void, i64)
+DEF_HELPER_2(hw_ret, void, env, i64)
DEF_HELPER_1(ldl_phys, i64, i64)
DEF_HELPER_1(ldq_phys, i64, i64)
-DEF_HELPER_1(ldl_l_phys, i64, i64)
-DEF_HELPER_1(ldq_l_phys, i64, i64)
+DEF_HELPER_2(ldl_l_phys, i64, env, i64)
+DEF_HELPER_2(ldq_l_phys, i64, env, i64)
DEF_HELPER_2(stl_phys, void, i64, i64)
DEF_HELPER_2(stq_phys, void, i64, i64)
-DEF_HELPER_2(stl_c_phys, i64, i64, i64)
-DEF_HELPER_2(stq_c_phys, i64, i64, i64)
+DEF_HELPER_3(stl_c_phys, i64, env, i64, i64)
+DEF_HELPER_3(stq_c_phys, i64, env, i64, i64)
-DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void)
-DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_1(tbia, TCG_CALL_CONST, void, env)
+DEF_HELPER_FLAGS_2(tbis, TCG_CALL_CONST, void, env, i64)
DEF_HELPER_1(halt, void, i64);
DEF_HELPER_FLAGS_0(get_time, TCG_CALL_CONST, i64)
-DEF_HELPER_FLAGS_1(set_alarm, TCG_CALL_CONST, void, i64)
+DEF_HELPER_FLAGS_2(set_alarm, TCG_CALL_CONST, void, env, i64)
#endif
#include "def-helper.h"
diff --git a/target-alpha/int_helper.c b/target-alpha/int_helper.c
new file mode 100644
index 0000000..1d832f0
--- /dev/null
+++ b/target-alpha/int_helper.c
@@ -0,0 +1,319 @@
+/*
+ * Helpers for integer and multimedia instructions.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "cpu.h"
+#include "helper.h"
+#include "host-utils.h"
+
+
+uint64_t helper_umulh(uint64_t op1, uint64_t op2)
+{
+ uint64_t tl, th;
+ mulu64(&tl, &th, op1, op2);
+ return th;
+}
+
+uint64_t helper_ctpop(uint64_t arg)
+{
+ return ctpop64(arg);
+}
+
+uint64_t helper_ctlz(uint64_t arg)
+{
+ return clz64(arg);
+}
+
+uint64_t helper_cttz(uint64_t arg)
+{
+ return ctz64(arg);
+}
+
+static inline uint64_t byte_zap(uint64_t op, uint8_t mskb)
+{
+ uint64_t mask;
+
+ mask = 0;
+ mask |= ((mskb >> 0) & 1) * 0x00000000000000FFULL;
+ mask |= ((mskb >> 1) & 1) * 0x000000000000FF00ULL;
+ mask |= ((mskb >> 2) & 1) * 0x0000000000FF0000ULL;
+ mask |= ((mskb >> 3) & 1) * 0x00000000FF000000ULL;
+ mask |= ((mskb >> 4) & 1) * 0x000000FF00000000ULL;
+ mask |= ((mskb >> 5) & 1) * 0x0000FF0000000000ULL;
+ mask |= ((mskb >> 6) & 1) * 0x00FF000000000000ULL;
+ mask |= ((mskb >> 7) & 1) * 0xFF00000000000000ULL;
+
+ return op & ~mask;
+}
+
+uint64_t helper_zap(uint64_t val, uint64_t mask)
+{
+ return byte_zap(val, mask);
+}
+
+uint64_t helper_zapnot(uint64_t val, uint64_t mask)
+{
+ return byte_zap(val, ~mask);
+}
+
+uint64_t helper_cmpbge(uint64_t op1, uint64_t op2)
+{
+ uint8_t opa, opb, res;
+ int i;
+
+ res = 0;
+ for (i = 0; i < 8; i++) {
+ opa = op1 >> (i * 8);
+ opb = op2 >> (i * 8);
+ if (opa >= opb) {
+ res |= 1 << i;
+ }
+ }
+ return res;
+}
+
+uint64_t helper_minub8(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ uint8_t opa, opb, opr;
+ int i;
+
+ for (i = 0; i < 8; ++i) {
+ opa = op1 >> (i * 8);
+ opb = op2 >> (i * 8);
+ opr = opa < opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 8);
+ }
+ return res;
+}
+
+uint64_t helper_minsb8(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ int8_t opa, opb;
+ uint8_t opr;
+ int i;
+
+ for (i = 0; i < 8; ++i) {
+ opa = op1 >> (i * 8);
+ opb = op2 >> (i * 8);
+ opr = opa < opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 8);
+ }
+ return res;
+}
+
+uint64_t helper_minuw4(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ uint16_t opa, opb, opr;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ opa = op1 >> (i * 16);
+ opb = op2 >> (i * 16);
+ opr = opa < opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 16);
+ }
+ return res;
+}
+
+uint64_t helper_minsw4(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ int16_t opa, opb;
+ uint16_t opr;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ opa = op1 >> (i * 16);
+ opb = op2 >> (i * 16);
+ opr = opa < opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 16);
+ }
+ return res;
+}
+
+uint64_t helper_maxub8(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ uint8_t opa, opb, opr;
+ int i;
+
+ for (i = 0; i < 8; ++i) {
+ opa = op1 >> (i * 8);
+ opb = op2 >> (i * 8);
+ opr = opa > opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 8);
+ }
+ return res;
+}
+
+uint64_t helper_maxsb8(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ int8_t opa, opb;
+ uint8_t opr;
+ int i;
+
+ for (i = 0; i < 8; ++i) {
+ opa = op1 >> (i * 8);
+ opb = op2 >> (i * 8);
+ opr = opa > opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 8);
+ }
+ return res;
+}
+
+uint64_t helper_maxuw4(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ uint16_t opa, opb, opr;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ opa = op1 >> (i * 16);
+ opb = op2 >> (i * 16);
+ opr = opa > opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 16);
+ }
+ return res;
+}
+
+uint64_t helper_maxsw4(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ int16_t opa, opb;
+ uint16_t opr;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ opa = op1 >> (i * 16);
+ opb = op2 >> (i * 16);
+ opr = opa > opb ? opa : opb;
+ res |= (uint64_t)opr << (i * 16);
+ }
+ return res;
+}
+
+uint64_t helper_perr(uint64_t op1, uint64_t op2)
+{
+ uint64_t res = 0;
+ uint8_t opa, opb, opr;
+ int i;
+
+ for (i = 0; i < 8; ++i) {
+ opa = op1 >> (i * 8);
+ opb = op2 >> (i * 8);
+ if (opa >= opb) {
+ opr = opa - opb;
+ } else {
+ opr = opb - opa;
+ }
+ res += opr;
+ }
+ return res;
+}
+
+uint64_t helper_pklb(uint64_t op1)
+{
+ return (op1 & 0xff) | ((op1 >> 24) & 0xff00);
+}
+
+uint64_t helper_pkwb(uint64_t op1)
+{
+ return ((op1 & 0xff)
+ | ((op1 >> 8) & 0xff00)
+ | ((op1 >> 16) & 0xff0000)
+ | ((op1 >> 24) & 0xff000000));
+}
+
+uint64_t helper_unpkbl(uint64_t op1)
+{
+ return (op1 & 0xff) | ((op1 & 0xff00) << 24);
+}
+
+uint64_t helper_unpkbw(uint64_t op1)
+{
+ return ((op1 & 0xff)
+ | ((op1 & 0xff00) << 8)
+ | ((op1 & 0xff0000) << 16)
+ | ((op1 & 0xff000000) << 24));
+}
+
+uint64_t helper_addqv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
+{
+ uint64_t tmp = op1;
+ op1 += op2;
+ if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
+ }
+ return op1;
+}
+
+uint64_t helper_addlv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
+{
+ uint64_t tmp = op1;
+ op1 = (uint32_t)(op1 + op2);
+ if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
+ }
+ return op1;
+}
+
+uint64_t helper_subqv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
+{
+ uint64_t res;
+ res = op1 - op2;
+ if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
+ }
+ return res;
+}
+
+uint64_t helper_sublv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
+{
+ uint32_t res;
+ res = op1 - op2;
+ if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
+ }
+ return res;
+}
+
+uint64_t helper_mullv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
+{
+ int64_t res = (int64_t)op1 * (int64_t)op2;
+
+ if (unlikely((int32_t)res != res)) {
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
+ }
+ return (int64_t)((int32_t)res);
+}
+
+uint64_t helper_mulqv(CPUAlphaState *env, uint64_t op1, uint64_t op2)
+{
+ uint64_t tl, th;
+
+ muls64(&tl, &th, op1, op2);
+ /* If th != 0 && th != -1, then we had an overflow */
+ if (unlikely((th + 1) > 1)) {
+ arith_excp(env, GETPC(), EXC_M_IOV, 0);
+ }
+ return tl;
+}
diff --git a/target-alpha/mem_helper.c b/target-alpha/mem_helper.c
new file mode 100644
index 0000000..dd5ca49
--- /dev/null
+++ b/target-alpha/mem_helper.c
@@ -0,0 +1,151 @@
+/*
+ * Helpers for loads and stores
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "cpu.h"
+#include "helper.h"
+
+
+/* Softmmu support */
+#ifndef CONFIG_USER_ONLY
+
+uint64_t helper_ldl_phys(uint64_t p)
+{
+ return (int32_t)ldl_phys(p);
+}
+
+uint64_t helper_ldq_phys(uint64_t p)
+{
+ return ldq_phys(p);
+}
+
+uint64_t helper_ldl_l_phys(CPUAlphaState *env, uint64_t p)
+{
+ env->lock_addr = p;
+ return env->lock_value = (int32_t)ldl_phys(p);
+}
+
+uint64_t helper_ldq_l_phys(CPUAlphaState *env, uint64_t p)
+{
+ env->lock_addr = p;
+ return env->lock_value = ldq_phys(p);
+}
+
+void helper_stl_phys(uint64_t p, uint64_t v)
+{
+ stl_phys(p, v);
+}
+
+void helper_stq_phys(uint64_t p, uint64_t v)
+{
+ stq_phys(p, v);
+}
+
+uint64_t helper_stl_c_phys(CPUAlphaState *env, uint64_t p, uint64_t v)
+{
+ uint64_t ret = 0;
+
+ if (p == env->lock_addr) {
+ int32_t old = ldl_phys(p);
+ if (old == (int32_t)env->lock_value) {
+ stl_phys(p, v);
+ ret = 1;
+ }
+ }
+ env->lock_addr = -1;
+
+ return ret;
+}
+
+uint64_t helper_stq_c_phys(CPUAlphaState *env, uint64_t p, uint64_t v)
+{
+ uint64_t ret = 0;
+
+ if (p == env->lock_addr) {
+ uint64_t old = ldq_phys(p);
+ if (old == env->lock_value) {
+ stq_phys(p, v);
+ ret = 1;
+ }
+ }
+ env->lock_addr = -1;
+
+ return ret;
+}
+
+static void do_unaligned_access(CPUAlphaState *env, target_ulong addr,
+ int is_write, int is_user, void *retaddr)
+{
+ uint64_t pc;
+ uint32_t insn;
+
+ do_restore_state(env, retaddr);
+
+ pc = env->pc;
+ insn = cpu_ldl_code(env, pc);
+
+ env->trap_arg0 = addr;
+ env->trap_arg1 = insn >> 26; /* opcode */
+ env->trap_arg2 = (insn >> 21) & 31; /* dest regno */
+ env->exception_index = EXCP_UNALIGN;
+ env->error_code = 0;
+ cpu_loop_exit(env);
+}
+
+void cpu_unassigned_access(CPUAlphaState *env, target_phys_addr_t addr,
+ int is_write, int is_exec, int unused, int size)
+{
+ env->trap_arg0 = addr;
+ env->trap_arg1 = is_write;
+ dynamic_excp(env, NULL, EXCP_MCHK, 0);
+}
+
+#include "softmmu_exec.h"
+
+#define MMUSUFFIX _mmu
+#define ALIGNED_ONLY
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+ NULL, it means that the function was called in C code (i.e. not
+ from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill(CPUAlphaState *env, target_ulong addr, int is_write,
+ int mmu_idx, void *retaddr)
+{
+ int ret;
+
+ ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx);
+ if (unlikely(ret != 0)) {
+ do_restore_state(env, retaddr);
+ /* Exception index and error code are already set */
+ cpu_loop_exit(env);
+ }
+}
+#endif /* CONFIG_USER_ONLY */
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
deleted file mode 100644
index c77f009..0000000
--- a/target-alpha/op_helper.c
+++ /dev/null
@@ -1,1379 +0,0 @@
-/*
- * Alpha emulation cpu micro-operations helpers for qemu.
- *
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * 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 "cpu.h"
-#include "dyngen-exec.h"
-#include "host-utils.h"
-#include "softfloat.h"
-#include "helper.h"
-#include "sysemu.h"
-#include "qemu-timer.h"
-
-#define FP_STATUS (env->fp_status)
-
-/*****************************************************************************/
-/* Exceptions processing helpers */
-
-/* This should only be called from translate, via gen_excp.
- We expect that ENV->PC has already been updated. */
-void QEMU_NORETURN helper_excp(int excp, int error)
-{
- env->exception_index = excp;
- env->error_code = error;
- cpu_loop_exit(env);
-}
-
-static void do_restore_state(void *retaddr)
-{
- unsigned long pc = (unsigned long)retaddr;
-
- if (pc) {
- TranslationBlock *tb = tb_find_pc(pc);
- if (tb) {
- cpu_restore_state(tb, env, pc);
- }
- }
-}
-
-/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
-static void QEMU_NORETURN dynamic_excp(int excp, int error)
-{
- env->exception_index = excp;
- env->error_code = error;
- do_restore_state(GETPC());
- cpu_loop_exit(env);
-}
-
-static void QEMU_NORETURN arith_excp(int exc, uint64_t mask)
-{
- env->trap_arg0 = exc;
- env->trap_arg1 = mask;
- dynamic_excp(EXCP_ARITH, 0);
-}
-
-uint64_t helper_load_pcc (void)
-{
-#ifndef CONFIG_USER_ONLY
- /* In system mode we have access to a decent high-resolution clock.
- In order to make OS-level time accounting work with the RPCC,
- present it with a well-timed clock fixed at 250MHz. */
- return (((uint64_t)env->pcc_ofs << 32)
- | (uint32_t)(qemu_get_clock_ns(vm_clock) >> 2));
-#else
- /* In user-mode, vm_clock doesn't exist. Just pass through the host cpu
- clock ticks. Also, don't bother taking PCC_OFS into account. */
- return (uint32_t)cpu_get_real_ticks();
-#endif
-}
-
-uint64_t helper_load_fpcr (void)
-{
- return cpu_alpha_load_fpcr (env);
-}
-
-void helper_store_fpcr (uint64_t val)
-{
- cpu_alpha_store_fpcr (env, val);
-}
-
-uint64_t helper_addqv (uint64_t op1, uint64_t op2)
-{
- uint64_t tmp = op1;
- op1 += op2;
- if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
- arith_excp(EXC_M_IOV, 0);
- }
- return op1;
-}
-
-uint64_t helper_addlv (uint64_t op1, uint64_t op2)
-{
- uint64_t tmp = op1;
- op1 = (uint32_t)(op1 + op2);
- if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
- arith_excp(EXC_M_IOV, 0);
- }
- return op1;
-}
-
-uint64_t helper_subqv (uint64_t op1, uint64_t op2)
-{
- uint64_t res;
- res = op1 - op2;
- if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
- arith_excp(EXC_M_IOV, 0);
- }
- return res;
-}
-
-uint64_t helper_sublv (uint64_t op1, uint64_t op2)
-{
- uint32_t res;
- res = op1 - op2;
- if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
- arith_excp(EXC_M_IOV, 0);
- }
- return res;
-}
-
-uint64_t helper_mullv (uint64_t op1, uint64_t op2)
-{
- int64_t res = (int64_t)op1 * (int64_t)op2;
-
- if (unlikely((int32_t)res != res)) {
- arith_excp(EXC_M_IOV, 0);
- }
- return (int64_t)((int32_t)res);
-}
-
-uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
-{
- uint64_t tl, th;
-
- muls64(&tl, &th, op1, op2);
- /* If th != 0 && th != -1, then we had an overflow */
- if (unlikely((th + 1) > 1)) {
- arith_excp(EXC_M_IOV, 0);
- }
- return tl;
-}
-
-uint64_t helper_umulh (uint64_t op1, uint64_t op2)
-{
- uint64_t tl, th;
-
- mulu64(&tl, &th, op1, op2);
- return th;
-}
-
-uint64_t helper_ctpop (uint64_t arg)
-{
- return ctpop64(arg);
-}
-
-uint64_t helper_ctlz (uint64_t arg)
-{
- return clz64(arg);
-}
-
-uint64_t helper_cttz (uint64_t arg)
-{
- return ctz64(arg);
-}
-
-static inline uint64_t byte_zap(uint64_t op, uint8_t mskb)
-{
- uint64_t mask;
-
- mask = 0;
- mask |= ((mskb >> 0) & 1) * 0x00000000000000FFULL;
- mask |= ((mskb >> 1) & 1) * 0x000000000000FF00ULL;
- mask |= ((mskb >> 2) & 1) * 0x0000000000FF0000ULL;
- mask |= ((mskb >> 3) & 1) * 0x00000000FF000000ULL;
- mask |= ((mskb >> 4) & 1) * 0x000000FF00000000ULL;
- mask |= ((mskb >> 5) & 1) * 0x0000FF0000000000ULL;
- mask |= ((mskb >> 6) & 1) * 0x00FF000000000000ULL;
- mask |= ((mskb >> 7) & 1) * 0xFF00000000000000ULL;
-
- return op & ~mask;
-}
-
-uint64_t helper_zap(uint64_t val, uint64_t mask)
-{
- return byte_zap(val, mask);
-}
-
-uint64_t helper_zapnot(uint64_t val, uint64_t mask)
-{
- return byte_zap(val, ~mask);
-}
-
-uint64_t helper_cmpbge (uint64_t op1, uint64_t op2)
-{
- uint8_t opa, opb, res;
- int i;
-
- res = 0;
- for (i = 0; i < 8; i++) {
- opa = op1 >> (i * 8);
- opb = op2 >> (i * 8);
- if (opa >= opb)
- res |= 1 << i;
- }
- return res;
-}
-
-uint64_t helper_minub8 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- uint8_t opa, opb, opr;
- int i;
-
- for (i = 0; i < 8; ++i) {
- opa = op1 >> (i * 8);
- opb = op2 >> (i * 8);
- opr = opa < opb ? opa : opb;
- res |= (uint64_t)opr << (i * 8);
- }
- return res;
-}
-
-uint64_t helper_minsb8 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- int8_t opa, opb;
- uint8_t opr;
- int i;
-
- for (i = 0; i < 8; ++i) {
- opa = op1 >> (i * 8);
- opb = op2 >> (i * 8);
- opr = opa < opb ? opa : opb;
- res |= (uint64_t)opr << (i * 8);
- }
- return res;
-}
-
-uint64_t helper_minuw4 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- uint16_t opa, opb, opr;
- int i;
-
- for (i = 0; i < 4; ++i) {
- opa = op1 >> (i * 16);
- opb = op2 >> (i * 16);
- opr = opa < opb ? opa : opb;
- res |= (uint64_t)opr << (i * 16);
- }
- return res;
-}
-
-uint64_t helper_minsw4 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- int16_t opa, opb;
- uint16_t opr;
- int i;
-
- for (i = 0; i < 4; ++i) {
- opa = op1 >> (i * 16);
- opb = op2 >> (i * 16);
- opr = opa < opb ? opa : opb;
- res |= (uint64_t)opr << (i * 16);
- }
- return res;
-}
-
-uint64_t helper_maxub8 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- uint8_t opa, opb, opr;
- int i;
-
- for (i = 0; i < 8; ++i) {
- opa = op1 >> (i * 8);
- opb = op2 >> (i * 8);
- opr = opa > opb ? opa : opb;
- res |= (uint64_t)opr << (i * 8);
- }
- return res;
-}
-
-uint64_t helper_maxsb8 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- int8_t opa, opb;
- uint8_t opr;
- int i;
-
- for (i = 0; i < 8; ++i) {
- opa = op1 >> (i * 8);
- opb = op2 >> (i * 8);
- opr = opa > opb ? opa : opb;
- res |= (uint64_t)opr << (i * 8);
- }
- return res;
-}
-
-uint64_t helper_maxuw4 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- uint16_t opa, opb, opr;
- int i;
-
- for (i = 0; i < 4; ++i) {
- opa = op1 >> (i * 16);
- opb = op2 >> (i * 16);
- opr = opa > opb ? opa : opb;
- res |= (uint64_t)opr << (i * 16);
- }
- return res;
-}
-
-uint64_t helper_maxsw4 (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- int16_t opa, opb;
- uint16_t opr;
- int i;
-
- for (i = 0; i < 4; ++i) {
- opa = op1 >> (i * 16);
- opb = op2 >> (i * 16);
- opr = opa > opb ? opa : opb;
- res |= (uint64_t)opr << (i * 16);
- }
- return res;
-}
-
-uint64_t helper_perr (uint64_t op1, uint64_t op2)
-{
- uint64_t res = 0;
- uint8_t opa, opb, opr;
- int i;
-
- for (i = 0; i < 8; ++i) {
- opa = op1 >> (i * 8);
- opb = op2 >> (i * 8);
- if (opa >= opb)
- opr = opa - opb;
- else
- opr = opb - opa;
- res += opr;
- }
- return res;
-}
-
-uint64_t helper_pklb (uint64_t op1)
-{
- return (op1 & 0xff) | ((op1 >> 24) & 0xff00);
-}
-
-uint64_t helper_pkwb (uint64_t op1)
-{
- return ((op1 & 0xff)
- | ((op1 >> 8) & 0xff00)
- | ((op1 >> 16) & 0xff0000)
- | ((op1 >> 24) & 0xff000000));
-}
-
-uint64_t helper_unpkbl (uint64_t op1)
-{
- return (op1 & 0xff) | ((op1 & 0xff00) << 24);
-}
-
-uint64_t helper_unpkbw (uint64_t op1)
-{
- return ((op1 & 0xff)
- | ((op1 & 0xff00) << 8)
- | ((op1 & 0xff0000) << 16)
- | ((op1 & 0xff000000) << 24));
-}
-
-/* Floating point helpers */
-
-void helper_setroundmode (uint32_t val)
-{
- set_float_rounding_mode(val, &FP_STATUS);
-}
-
-void helper_setflushzero (uint32_t val)
-{
- set_flush_to_zero(val, &FP_STATUS);
-}
-
-void helper_fp_exc_clear (void)
-{
- set_float_exception_flags(0, &FP_STATUS);
-}
-
-uint32_t helper_fp_exc_get (void)
-{
- return get_float_exception_flags(&FP_STATUS);
-}
-
-/* Raise exceptions for ieee fp insns without software completion.
- In that case there are no exceptions that don't trap; the mask
- doesn't apply. */
-void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
-{
- if (exc) {
- uint32_t hw_exc = 0;
-
- if (exc & float_flag_invalid) {
- hw_exc |= EXC_M_INV;
- }
- if (exc & float_flag_divbyzero) {
- hw_exc |= EXC_M_DZE;
- }
- if (exc & float_flag_overflow) {
- hw_exc |= EXC_M_FOV;
- }
- if (exc & float_flag_underflow) {
- hw_exc |= EXC_M_UNF;
- }
- if (exc & float_flag_inexact) {
- hw_exc |= EXC_M_INE;
- }
-
- arith_excp(hw_exc, 1ull << regno);
- }
-}
-
-/* Raise exceptions for ieee fp insns with software completion. */
-void helper_fp_exc_raise_s(uint32_t exc, uint32_t regno)
-{
- if (exc) {
- env->fpcr_exc_status |= exc;
-
- exc &= ~env->fpcr_exc_mask;
- if (exc) {
- helper_fp_exc_raise(exc, regno);
- }
- }
-}
-
-/* Input remapping without software completion. Handle denormal-map-to-zero
- and trap for all other non-finite numbers. */
-uint64_t helper_ieee_input(uint64_t val)
-{
- uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
- uint64_t frac = val & 0xfffffffffffffull;
-
- if (exp == 0) {
- if (frac != 0) {
- /* If DNZ is set flush denormals to zero on input. */
- if (env->fpcr_dnz) {
- val &= 1ull << 63;
- } else {
- arith_excp(EXC_M_UNF, 0);
- }
- }
- } else if (exp == 0x7ff) {
- /* Infinity or NaN. */
- /* ??? I'm not sure these exception bit flags are correct. I do
- know that the Linux kernel, at least, doesn't rely on them and
- just emulates the insn to figure out what exception to use. */
- arith_excp(frac ? EXC_M_INV : EXC_M_FOV, 0);
- }
- return val;
-}
-
-/* Similar, but does not trap for infinities. Used for comparisons. */
-uint64_t helper_ieee_input_cmp(uint64_t val)
-{
- uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
- uint64_t frac = val & 0xfffffffffffffull;
-
- if (exp == 0) {
- if (frac != 0) {
- /* If DNZ is set flush denormals to zero on input. */
- if (env->fpcr_dnz) {
- val &= 1ull << 63;
- } else {
- arith_excp(EXC_M_UNF, 0);
- }
- }
- } else if (exp == 0x7ff && frac) {
- /* NaN. */
- arith_excp(EXC_M_INV, 0);
- }
- return val;
-}
-
-/* Input remapping with software completion enabled. All we have to do
- is handle denormal-map-to-zero; all other inputs get exceptions as
- needed from the actual operation. */
-uint64_t helper_ieee_input_s(uint64_t val)
-{
- if (env->fpcr_dnz) {
- uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
- if (exp == 0) {
- val &= 1ull << 63;
- }
- }
- return val;
-}
-
-/* F floating (VAX) */
-static inline uint64_t float32_to_f(float32 fa)
-{
- uint64_t r, exp, mant, sig;
- CPU_FloatU a;
-
- a.f = fa;
- sig = ((uint64_t)a.l & 0x80000000) << 32;
- exp = (a.l >> 23) & 0xff;
- mant = ((uint64_t)a.l & 0x007fffff) << 29;
-
- if (exp == 255) {
- /* NaN or infinity */
- r = 1; /* VAX dirty zero */
- } else if (exp == 0) {
- if (mant == 0) {
- /* Zero */
- r = 0;
- } else {
- /* Denormalized */
- r = sig | ((exp + 1) << 52) | mant;
- }
- } else {
- if (exp >= 253) {
- /* Overflow */
- r = 1; /* VAX dirty zero */
- } else {
- r = sig | ((exp + 2) << 52);
- }
- }
-
- return r;
-}
-
-static inline float32 f_to_float32(uint64_t a)
-{
- uint32_t exp, mant_sig;
- CPU_FloatU r;
-
- exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f);
- mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff);
-
- if (unlikely(!exp && mant_sig)) {
- /* Reserved operands / Dirty zero */
- dynamic_excp(EXCP_OPCDEC, 0);
- }
-
- if (exp < 3) {
- /* Underflow */
- r.l = 0;
- } else {
- r.l = ((exp - 2) << 23) | mant_sig;
- }
-
- return r.f;
-}
-
-uint32_t helper_f_to_memory (uint64_t a)
-{
- uint32_t r;
- r = (a & 0x00001fffe0000000ull) >> 13;
- r |= (a & 0x07ffe00000000000ull) >> 45;
- r |= (a & 0xc000000000000000ull) >> 48;
- return r;
-}
-
-uint64_t helper_memory_to_f (uint32_t a)
-{
- uint64_t r;
- r = ((uint64_t)(a & 0x0000c000)) << 48;
- r |= ((uint64_t)(a & 0x003fffff)) << 45;
- r |= ((uint64_t)(a & 0xffff0000)) << 13;
- if (!(a & 0x00004000))
- r |= 0x7ll << 59;
- return r;
-}
-
-/* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong. We should
- either implement VAX arithmetic properly or just signal invalid opcode. */
-
-uint64_t helper_addf (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = f_to_float32(a);
- fb = f_to_float32(b);
- fr = float32_add(fa, fb, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-uint64_t helper_subf (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = f_to_float32(a);
- fb = f_to_float32(b);
- fr = float32_sub(fa, fb, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-uint64_t helper_mulf (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = f_to_float32(a);
- fb = f_to_float32(b);
- fr = float32_mul(fa, fb, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-uint64_t helper_divf (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = f_to_float32(a);
- fb = f_to_float32(b);
- fr = float32_div(fa, fb, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-uint64_t helper_sqrtf (uint64_t t)
-{
- float32 ft, fr;
-
- ft = f_to_float32(t);
- fr = float32_sqrt(ft, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-
-/* G floating (VAX) */
-static inline uint64_t float64_to_g(float64 fa)
-{
- uint64_t r, exp, mant, sig;
- CPU_DoubleU a;
-
- a.d = fa;
- sig = a.ll & 0x8000000000000000ull;
- exp = (a.ll >> 52) & 0x7ff;
- mant = a.ll & 0x000fffffffffffffull;
-
- if (exp == 2047) {
- /* NaN or infinity */
- r = 1; /* VAX dirty zero */
- } else if (exp == 0) {
- if (mant == 0) {
- /* Zero */
- r = 0;
- } else {
- /* Denormalized */
- r = sig | ((exp + 1) << 52) | mant;
- }
- } else {
- if (exp >= 2045) {
- /* Overflow */
- r = 1; /* VAX dirty zero */
- } else {
- r = sig | ((exp + 2) << 52);
- }
- }
-
- return r;
-}
-
-static inline float64 g_to_float64(uint64_t a)
-{
- uint64_t exp, mant_sig;
- CPU_DoubleU r;
-
- exp = (a >> 52) & 0x7ff;
- mant_sig = a & 0x800fffffffffffffull;
-
- if (!exp && mant_sig) {
- /* Reserved operands / Dirty zero */
- dynamic_excp(EXCP_OPCDEC, 0);
- }
-
- if (exp < 3) {
- /* Underflow */
- r.ll = 0;
- } else {
- r.ll = ((exp - 2) << 52) | mant_sig;
- }
-
- return r.d;
-}
-
-uint64_t helper_g_to_memory (uint64_t a)
-{
- uint64_t r;
- r = (a & 0x000000000000ffffull) << 48;
- r |= (a & 0x00000000ffff0000ull) << 16;
- r |= (a & 0x0000ffff00000000ull) >> 16;
- r |= (a & 0xffff000000000000ull) >> 48;
- return r;
-}
-
-uint64_t helper_memory_to_g (uint64_t a)
-{
- uint64_t r;
- r = (a & 0x000000000000ffffull) << 48;
- r |= (a & 0x00000000ffff0000ull) << 16;
- r |= (a & 0x0000ffff00000000ull) >> 16;
- r |= (a & 0xffff000000000000ull) >> 48;
- return r;
-}
-
-uint64_t helper_addg (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
- fr = float64_add(fa, fb, &FP_STATUS);
- return float64_to_g(fr);
-}
-
-uint64_t helper_subg (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
- fr = float64_sub(fa, fb, &FP_STATUS);
- return float64_to_g(fr);
-}
-
-uint64_t helper_mulg (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
- fr = float64_mul(fa, fb, &FP_STATUS);
- return float64_to_g(fr);
-}
-
-uint64_t helper_divg (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
- fr = float64_div(fa, fb, &FP_STATUS);
- return float64_to_g(fr);
-}
-
-uint64_t helper_sqrtg (uint64_t a)
-{
- float64 fa, fr;
-
- fa = g_to_float64(a);
- fr = float64_sqrt(fa, &FP_STATUS);
- return float64_to_g(fr);
-}
-
-
-/* S floating (single) */
-
-/* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */
-static inline uint64_t float32_to_s_int(uint32_t fi)
-{
- uint32_t frac = fi & 0x7fffff;
- uint32_t sign = fi >> 31;
- uint32_t exp_msb = (fi >> 30) & 1;
- uint32_t exp_low = (fi >> 23) & 0x7f;
- uint32_t exp;
-
- exp = (exp_msb << 10) | exp_low;
- if (exp_msb) {
- if (exp_low == 0x7f)
- exp = 0x7ff;
- } else {
- if (exp_low != 0x00)
- exp |= 0x380;
- }
-
- return (((uint64_t)sign << 63)
- | ((uint64_t)exp << 52)
- | ((uint64_t)frac << 29));
-}
-
-static inline uint64_t float32_to_s(float32 fa)
-{
- CPU_FloatU a;
- a.f = fa;
- return float32_to_s_int(a.l);
-}
-
-static inline uint32_t s_to_float32_int(uint64_t a)
-{
- return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
-}
-
-static inline float32 s_to_float32(uint64_t a)
-{
- CPU_FloatU r;
- r.l = s_to_float32_int(a);
- return r.f;
-}
-
-uint32_t helper_s_to_memory (uint64_t a)
-{
- return s_to_float32_int(a);
-}
-
-uint64_t helper_memory_to_s (uint32_t a)
-{
- return float32_to_s_int(a);
-}
-
-uint64_t helper_adds (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = s_to_float32(a);
- fb = s_to_float32(b);
- fr = float32_add(fa, fb, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-uint64_t helper_subs (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = s_to_float32(a);
- fb = s_to_float32(b);
- fr = float32_sub(fa, fb, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-uint64_t helper_muls (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = s_to_float32(a);
- fb = s_to_float32(b);
- fr = float32_mul(fa, fb, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-uint64_t helper_divs (uint64_t a, uint64_t b)
-{
- float32 fa, fb, fr;
-
- fa = s_to_float32(a);
- fb = s_to_float32(b);
- fr = float32_div(fa, fb, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-uint64_t helper_sqrts (uint64_t a)
-{
- float32 fa, fr;
-
- fa = s_to_float32(a);
- fr = float32_sqrt(fa, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-
-/* T floating (double) */
-static inline float64 t_to_float64(uint64_t a)
-{
- /* Memory format is the same as float64 */
- CPU_DoubleU r;
- r.ll = a;
- return r.d;
-}
-
-static inline uint64_t float64_to_t(float64 fa)
-{
- /* Memory format is the same as float64 */
- CPU_DoubleU r;
- r.d = fa;
- return r.ll;
-}
-
-uint64_t helper_addt (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
- fr = float64_add(fa, fb, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-uint64_t helper_subt (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
- fr = float64_sub(fa, fb, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-uint64_t helper_mult (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
- fr = float64_mul(fa, fb, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-uint64_t helper_divt (uint64_t a, uint64_t b)
-{
- float64 fa, fb, fr;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
- fr = float64_div(fa, fb, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-uint64_t helper_sqrtt (uint64_t a)
-{
- float64 fa, fr;
-
- fa = t_to_float64(a);
- fr = float64_sqrt(fa, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-/* Comparisons */
-uint64_t helper_cmptun (uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
-
- if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
- return 0x4000000000000000ULL;
- } else {
- return 0;
- }
-}
-
-uint64_t helper_cmpteq(uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
-
- if (float64_eq_quiet(fa, fb, &FP_STATUS))
- return 0x4000000000000000ULL;
- else
- return 0;
-}
-
-uint64_t helper_cmptle(uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
-
- if (float64_le(fa, fb, &FP_STATUS))
- return 0x4000000000000000ULL;
- else
- return 0;
-}
-
-uint64_t helper_cmptlt(uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = t_to_float64(a);
- fb = t_to_float64(b);
-
- if (float64_lt(fa, fb, &FP_STATUS))
- return 0x4000000000000000ULL;
- else
- return 0;
-}
-
-uint64_t helper_cmpgeq(uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
-
- if (float64_eq_quiet(fa, fb, &FP_STATUS))
- return 0x4000000000000000ULL;
- else
- return 0;
-}
-
-uint64_t helper_cmpgle(uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
-
- if (float64_le(fa, fb, &FP_STATUS))
- return 0x4000000000000000ULL;
- else
- return 0;
-}
-
-uint64_t helper_cmpglt(uint64_t a, uint64_t b)
-{
- float64 fa, fb;
-
- fa = g_to_float64(a);
- fb = g_to_float64(b);
-
- if (float64_lt(fa, fb, &FP_STATUS))
- return 0x4000000000000000ULL;
- else
- return 0;
-}
-
-/* Floating point format conversion */
-uint64_t helper_cvtts (uint64_t a)
-{
- float64 fa;
- float32 fr;
-
- fa = t_to_float64(a);
- fr = float64_to_float32(fa, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-uint64_t helper_cvtst (uint64_t a)
-{
- float32 fa;
- float64 fr;
-
- fa = s_to_float32(a);
- fr = float32_to_float64(fa, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-uint64_t helper_cvtqs (uint64_t a)
-{
- float32 fr = int64_to_float32(a, &FP_STATUS);
- return float32_to_s(fr);
-}
-
-/* Implement float64 to uint64 conversion without saturation -- we must
- supply the truncated result. This behaviour is used by the compiler
- to get unsigned conversion for free with the same instruction.
-
- The VI flag is set when overflow or inexact exceptions should be raised. */
-
-static inline uint64_t helper_cvttq_internal(uint64_t a, int roundmode, int VI)
-{
- uint64_t frac, ret = 0;
- uint32_t exp, sign, exc = 0;
- int shift;
-
- sign = (a >> 63);
- exp = (uint32_t)(a >> 52) & 0x7ff;
- frac = a & 0xfffffffffffffull;
-
- if (exp == 0) {
- if (unlikely(frac != 0)) {
- goto do_underflow;
- }
- } else if (exp == 0x7ff) {
- exc = (frac ? float_flag_invalid : VI ? float_flag_overflow : 0);
- } else {
- /* Restore implicit bit. */
- frac |= 0x10000000000000ull;
-
- shift = exp - 1023 - 52;
- if (shift >= 0) {
- /* In this case the number is so large that we must shift
- the fraction left. There is no rounding to do. */
- if (shift < 63) {
- ret = frac << shift;
- if (VI && (ret >> shift) != frac) {
- exc = float_flag_overflow;
- }
- }
- } else {
- uint64_t round;
-
- /* In this case the number is smaller than the fraction as
- represented by the 52 bit number. Here we must think
- about rounding the result. Handle this by shifting the
- fractional part of the number into the high bits of ROUND.
- This will let us efficiently handle round-to-nearest. */
- shift = -shift;
- if (shift < 63) {
- ret = frac >> shift;
- round = frac << (64 - shift);
- } else {
- /* The exponent is so small we shift out everything.
- Leave a sticky bit for proper rounding below. */
- do_underflow:
- round = 1;
- }
-
- if (round) {
- exc = (VI ? float_flag_inexact : 0);
- switch (roundmode) {
- case float_round_nearest_even:
- if (round == (1ull << 63)) {
- /* Fraction is exactly 0.5; round to even. */
- ret += (ret & 1);
- } else if (round > (1ull << 63)) {
- ret += 1;
- }
- break;
- case float_round_to_zero:
- break;
- case float_round_up:
- ret += 1 - sign;
- break;
- case float_round_down:
- ret += sign;
- break;
- }
- }
- }
- if (sign) {
- ret = -ret;
- }
- }
- if (unlikely(exc)) {
- float_raise(exc, &FP_STATUS);
- }
-
- return ret;
-}
-
-uint64_t helper_cvttq(uint64_t a)
-{
- return helper_cvttq_internal(a, FP_STATUS.float_rounding_mode, 1);
-}
-
-uint64_t helper_cvttq_c(uint64_t a)
-{
- return helper_cvttq_internal(a, float_round_to_zero, 0);
-}
-
-uint64_t helper_cvttq_svic(uint64_t a)
-{
- return helper_cvttq_internal(a, float_round_to_zero, 1);
-}
-
-uint64_t helper_cvtqt (uint64_t a)
-{
- float64 fr = int64_to_float64(a, &FP_STATUS);
- return float64_to_t(fr);
-}
-
-uint64_t helper_cvtqf (uint64_t a)
-{
- float32 fr = int64_to_float32(a, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-uint64_t helper_cvtgf (uint64_t a)
-{
- float64 fa;
- float32 fr;
-
- fa = g_to_float64(a);
- fr = float64_to_float32(fa, &FP_STATUS);
- return float32_to_f(fr);
-}
-
-uint64_t helper_cvtgq (uint64_t a)
-{
- float64 fa = g_to_float64(a);
- return float64_to_int64_round_to_zero(fa, &FP_STATUS);
-}
-
-uint64_t helper_cvtqg (uint64_t a)
-{
- float64 fr;
- fr = int64_to_float64(a, &FP_STATUS);
- return float64_to_g(fr);
-}
-
-/* PALcode support special instructions */
-#if !defined (CONFIG_USER_ONLY)
-void helper_hw_ret (uint64_t a)
-{
- env->pc = a & ~3;
- env->intr_flag = 0;
- env->lock_addr = -1;
- if ((a & 1) == 0) {
- env->pal_mode = 0;
- swap_shadow_regs(env);
- }
-}
-
-void helper_tbia(void)
-{
- tlb_flush(env, 1);
-}
-
-void helper_tbis(uint64_t p)
-{
- tlb_flush_page(env, p);
-}
-
-void helper_halt(uint64_t restart)
-{
- if (restart) {
- qemu_system_reset_request();
- } else {
- qemu_system_shutdown_request();
- }
-}
-
-uint64_t helper_get_time(void)
-{
- return qemu_get_clock_ns(rtc_clock);
-}
-
-void helper_set_alarm(uint64_t expire)
-{
- if (expire) {
- env->alarm_expire = expire;
- qemu_mod_timer(env->alarm_timer, expire);
- } else {
- qemu_del_timer(env->alarm_timer);
- }
-}
-#endif
-
-/*****************************************************************************/
-/* Softmmu support */
-#if !defined (CONFIG_USER_ONLY)
-uint64_t helper_ldl_phys(uint64_t p)
-{
- return (int32_t)ldl_phys(p);
-}
-
-uint64_t helper_ldq_phys(uint64_t p)
-{
- return ldq_phys(p);
-}
-
-uint64_t helper_ldl_l_phys(uint64_t p)
-{
- env->lock_addr = p;
- return env->lock_value = (int32_t)ldl_phys(p);
-}
-
-uint64_t helper_ldq_l_phys(uint64_t p)
-{
- env->lock_addr = p;
- return env->lock_value = ldl_phys(p);
-}
-
-void helper_stl_phys(uint64_t p, uint64_t v)
-{
- stl_phys(p, v);
-}
-
-void helper_stq_phys(uint64_t p, uint64_t v)
-{
- stq_phys(p, v);
-}
-
-uint64_t helper_stl_c_phys(uint64_t p, uint64_t v)
-{
- uint64_t ret = 0;
-
- if (p == env->lock_addr) {
- int32_t old = ldl_phys(p);
- if (old == (int32_t)env->lock_value) {
- stl_phys(p, v);
- ret = 1;
- }
- }
- env->lock_addr = -1;
-
- return ret;
-}
-
-uint64_t helper_stq_c_phys(uint64_t p, uint64_t v)
-{
- uint64_t ret = 0;
-
- if (p == env->lock_addr) {
- uint64_t old = ldq_phys(p);
- if (old == env->lock_value) {
- stq_phys(p, v);
- ret = 1;
- }
- }
- env->lock_addr = -1;
-
- return ret;
-}
-
-static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
- int is_user, void *retaddr)
-{
- uint64_t pc;
- uint32_t insn;
-
- do_restore_state(retaddr);
-
- pc = env->pc;
- insn = ldl_code(pc);
-
- env->trap_arg0 = addr;
- env->trap_arg1 = insn >> 26; /* opcode */
- env->trap_arg2 = (insn >> 21) & 31; /* dest regno */
- helper_excp(EXCP_UNALIGN, 0);
-}
-
-void QEMU_NORETURN cpu_unassigned_access(CPUAlphaState *env1,
- target_phys_addr_t addr, int is_write,
- int is_exec, int unused, int size)
-{
- env = env1;
- env->trap_arg0 = addr;
- env->trap_arg1 = is_write;
- dynamic_excp(EXCP_MCHK, 0);
-}
-
-#include "softmmu_exec.h"
-
-#define MMUSUFFIX _mmu
-#define ALIGNED_ONLY
-
-#define SHIFT 0
-#include "softmmu_template.h"
-
-#define SHIFT 1
-#include "softmmu_template.h"
-
-#define SHIFT 2
-#include "softmmu_template.h"
-
-#define SHIFT 3
-#include "softmmu_template.h"
-
-/* try to fill the TLB and return an exception if error. If retaddr is
- NULL, it means that the function was called in C code (i.e. not
- from generated code or from helper.c) */
-/* XXX: fix it to restore all registers */
-void tlb_fill(CPUAlphaState *env1, target_ulong addr, int is_write, int mmu_idx,
- void *retaddr)
-{
- CPUAlphaState *saved_env;
- int ret;
-
- saved_env = env;
- env = env1;
- ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx);
- if (unlikely(ret != 0)) {
- do_restore_state(retaddr);
- /* Exception index and error code are already set */
- cpu_loop_exit(env);
- }
- env = saved_env;
-}
-#endif
diff --git a/target-alpha/sys_helper.c b/target-alpha/sys_helper.c
new file mode 100644
index 0000000..40ca49c
--- /dev/null
+++ b/target-alpha/sys_helper.c
@@ -0,0 +1,87 @@
+/*
+ * Helpers for system instructions.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "cpu.h"
+#include "helper.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+
+
+uint64_t helper_load_pcc(CPUAlphaState *env)
+{
+#ifndef CONFIG_USER_ONLY
+ /* In system mode we have access to a decent high-resolution clock.
+ In order to make OS-level time accounting work with the RPCC,
+ present it with a well-timed clock fixed at 250MHz. */
+ return (((uint64_t)env->pcc_ofs << 32)
+ | (uint32_t)(qemu_get_clock_ns(vm_clock) >> 2));
+#else
+ /* In user-mode, vm_clock doesn't exist. Just pass through the host cpu
+ clock ticks. Also, don't bother taking PCC_OFS into account. */
+ return (uint32_t)cpu_get_real_ticks();
+#endif
+}
+
+/* PALcode support special instructions */
+#ifndef CONFIG_USER_ONLY
+void helper_hw_ret(CPUAlphaState *env, uint64_t a)
+{
+ env->pc = a & ~3;
+ env->intr_flag = 0;
+ env->lock_addr = -1;
+ if ((a & 1) == 0) {
+ env->pal_mode = 0;
+ swap_shadow_regs(env);
+ }
+}
+
+void helper_tbia(CPUAlphaState *env)
+{
+ tlb_flush(env, 1);
+}
+
+void helper_tbis(CPUAlphaState *env, uint64_t p)
+{
+ tlb_flush_page(env, p);
+}
+
+void helper_halt(uint64_t restart)
+{
+ if (restart) {
+ qemu_system_reset_request();
+ } else {
+ qemu_system_shutdown_request();
+ }
+}
+
+uint64_t helper_get_time(void)
+{
+ return qemu_get_clock_ns(rtc_clock);
+}
+
+void helper_set_alarm(CPUAlphaState *env, uint64_t expire)
+{
+ if (expire) {
+ env->alarm_expire = expire;
+ qemu_mod_timer(env->alarm_timer, expire);
+ } else {
+ qemu_del_timer(env->alarm_timer);
+ }
+}
+#endif /* CONFIG_USER_ONLY */
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index b51fe5c..1f4565d 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -149,7 +149,7 @@
tmp1 = tcg_const_i32(exception);
tmp2 = tcg_const_i32(error_code);
- gen_helper_excp(tmp1, tmp2);
+ gen_helper_excp(cpu_env, tmp1, tmp2);
tcg_temp_free_i32(tmp2);
tcg_temp_free_i32(tmp1);
}
@@ -611,7 +611,8 @@
tcg_gen_movi_i32(tmp, float_round_down);
break;
case QUAL_RM_D:
- tcg_gen_ld8u_i32(tmp, cpu_env, offsetof(CPUAlphaState, fpcr_dyn_round));
+ tcg_gen_ld8u_i32(tmp, cpu_env,
+ offsetof(CPUAlphaState, fpcr_dyn_round));
break;
}
@@ -641,7 +642,8 @@
tmp = tcg_temp_new_i32();
if (fn11) {
/* Underflow is enabled, use the FPCR setting. */
- tcg_gen_ld8u_i32(tmp, cpu_env, offsetof(CPUAlphaState, fpcr_flush_to_zero));
+ tcg_gen_ld8u_i32(tmp, cpu_env,
+ offsetof(CPUAlphaState, fpcr_flush_to_zero));
} else {
/* Underflow is disabled, force flush-to-zero. */
tcg_gen_movi_i32(tmp, 1);
@@ -659,15 +661,19 @@
static TCGv gen_ieee_input(int reg, int fn11, int is_cmp)
{
- TCGv val = tcg_temp_new();
+ TCGv val;
if (reg == 31) {
- tcg_gen_movi_i64(val, 0);
- } else if (fn11 & QUAL_S) {
- gen_helper_ieee_input_s(val, cpu_fir[reg]);
- } else if (is_cmp) {
- gen_helper_ieee_input_cmp(val, cpu_fir[reg]);
+ val = tcg_const_i64(0);
} else {
- gen_helper_ieee_input(val, cpu_fir[reg]);
+ if ((fn11 & QUAL_S) == 0) {
+ if (is_cmp) {
+ gen_helper_ieee_input_cmp(cpu_env, cpu_fir[reg]);
+ } else {
+ gen_helper_ieee_input(cpu_env, cpu_fir[reg]);
+ }
+ }
+ val = tcg_temp_new();
+ tcg_gen_mov_i64(val, cpu_fir[reg]);
}
return val;
}
@@ -680,7 +686,7 @@
offsetof(CPUAlphaState, fp_status.float_exception_flags));
tcg_temp_free_i32(zero);
#else
- gen_helper_fp_exc_clear();
+ gen_helper_fp_exc_clear(cpu_env);
#endif
}
@@ -698,7 +704,7 @@
tcg_gen_ld8u_i32(exc, cpu_env,
offsetof(CPUAlphaState, fp_status.float_exception_flags));
#else
- gen_helper_fp_exc_get(exc);
+ gen_helper_fp_exc_get(exc, cpu_env);
#endif
if (ignore) {
@@ -713,9 +719,9 @@
reg = tcg_const_i32(rc + 32);
if (fn11 & QUAL_S) {
- gen_helper_fp_exc_raise_s(exc, reg);
+ gen_helper_fp_exc_raise_s(cpu_env, exc, reg);
} else {
- gen_helper_fp_exc_raise(exc, reg);
+ gen_helper_fp_exc_raise(cpu_env, exc, reg);
}
tcg_temp_free_i32(reg);
@@ -784,20 +790,20 @@
gen_fcvtql(rb, rc);
}
-#define FARITH2(name) \
-static inline void glue(gen_f, name)(int rb, int rc) \
-{ \
- if (unlikely(rc == 31)) { \
- return; \
- } \
- if (rb != 31) { \
- gen_helper_ ## name (cpu_fir[rc], cpu_fir[rb]); \
- } else { \
- TCGv tmp = tcg_const_i64(0); \
- gen_helper_ ## name (cpu_fir[rc], tmp); \
- tcg_temp_free(tmp); \
- } \
-}
+#define FARITH2(name) \
+ static inline void glue(gen_f, name)(int rb, int rc) \
+ { \
+ if (unlikely(rc == 31)) { \
+ return; \
+ } \
+ if (rb != 31) { \
+ gen_helper_ ## name(cpu_fir[rc], cpu_env, cpu_fir[rb]); \
+ } else { \
+ TCGv tmp = tcg_const_i64(0); \
+ gen_helper_ ## name(cpu_fir[rc], cpu_env, tmp); \
+ tcg_temp_free(tmp); \
+ } \
+ }
/* ??? VAX instruction qualifiers ignored. */
FARITH2(sqrtf)
@@ -807,7 +813,8 @@
FARITH2(cvtqf)
FARITH2(cvtqg)
-static void gen_ieee_arith2(DisasContext *ctx, void (*helper)(TCGv, TCGv),
+static void gen_ieee_arith2(DisasContext *ctx,
+ void (*helper)(TCGv, TCGv_ptr, TCGv),
int rb, int rc, int fn11)
{
TCGv vb;
@@ -823,7 +830,7 @@
gen_fp_exc_clear();
vb = gen_ieee_input(rb, fn11, 0);
- helper(cpu_fir[rc], vb);
+ helper(cpu_fir[rc], cpu_env, vb);
tcg_temp_free(vb);
gen_fp_exc_raise(rc, fn11);
@@ -859,18 +866,18 @@
also do not have integer overflow enabled. Special case that. */
switch (fn11) {
case QUAL_RM_C:
- gen_helper_cvttq_c(cpu_fir[rc], vb);
+ gen_helper_cvttq_c(cpu_fir[rc], cpu_env, vb);
break;
case QUAL_V | QUAL_RM_C:
case QUAL_S | QUAL_V | QUAL_RM_C:
ignore = float_flag_inexact;
/* FALLTHRU */
case QUAL_S | QUAL_V | QUAL_I | QUAL_RM_C:
- gen_helper_cvttq_svic(cpu_fir[rc], vb);
+ gen_helper_cvttq_svic(cpu_fir[rc], cpu_env, vb);
break;
default:
gen_qual_roundmode(ctx, fn11);
- gen_helper_cvttq(cpu_fir[rc], vb);
+ gen_helper_cvttq(cpu_fir[rc], cpu_env, vb);
ignore |= (fn11 & QUAL_V ? 0 : float_flag_overflow);
ignore |= (fn11 & QUAL_I ? 0 : float_flag_inexact);
break;
@@ -880,7 +887,8 @@
gen_fp_exc_raise_ignore(rc, fn11, ignore);
}
-static void gen_ieee_intcvt(DisasContext *ctx, void (*helper)(TCGv, TCGv),
+static void gen_ieee_intcvt(DisasContext *ctx,
+ void (*helper)(TCGv, TCGv_ptr, TCGv),
int rb, int rc, int fn11)
{
TCGv vb;
@@ -904,10 +912,10 @@
inexact handling is requested. */
if (fn11 & QUAL_I) {
gen_fp_exc_clear();
- helper(cpu_fir[rc], vb);
+ helper(cpu_fir[rc], cpu_env, vb);
gen_fp_exc_raise(rc, fn11);
} else {
- helper(cpu_fir[rc], vb);
+ helper(cpu_fir[rc], cpu_env, vb);
}
if (rb == 31) {
@@ -999,34 +1007,34 @@
gen_cpys_internal(ra, rb, rc, 0, 0xFFF0000000000000ULL);
}
-#define FARITH3(name) \
-static inline void glue(gen_f, name)(int ra, int rb, int rc) \
-{ \
- TCGv va, vb; \
- \
- if (unlikely(rc == 31)) { \
- return; \
- } \
- if (ra == 31) { \
- va = tcg_const_i64(0); \
- } else { \
- va = cpu_fir[ra]; \
- } \
- if (rb == 31) { \
- vb = tcg_const_i64(0); \
- } else { \
- vb = cpu_fir[rb]; \
- } \
- \
- gen_helper_ ## name (cpu_fir[rc], va, vb); \
- \
- if (ra == 31) { \
- tcg_temp_free(va); \
- } \
- if (rb == 31) { \
- tcg_temp_free(vb); \
- } \
-}
+#define FARITH3(name) \
+ static inline void glue(gen_f, name)(int ra, int rb, int rc) \
+ { \
+ TCGv va, vb; \
+ \
+ if (unlikely(rc == 31)) { \
+ return; \
+ } \
+ if (ra == 31) { \
+ va = tcg_const_i64(0); \
+ } else { \
+ va = cpu_fir[ra]; \
+ } \
+ if (rb == 31) { \
+ vb = tcg_const_i64(0); \
+ } else { \
+ vb = cpu_fir[rb]; \
+ } \
+ \
+ gen_helper_ ## name(cpu_fir[rc], cpu_env, va, vb); \
+ \
+ if (ra == 31) { \
+ tcg_temp_free(va); \
+ } \
+ if (rb == 31) { \
+ tcg_temp_free(vb); \
+ } \
+ }
/* ??? VAX instruction qualifiers ignored. */
FARITH3(addf)
@@ -1042,7 +1050,7 @@
FARITH3(cmpgle)
static void gen_ieee_arith3(DisasContext *ctx,
- void (*helper)(TCGv, TCGv, TCGv),
+ void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv),
int ra, int rb, int rc, int fn11)
{
TCGv va, vb;
@@ -1059,7 +1067,7 @@
va = gen_ieee_input(ra, fn11, 0);
vb = gen_ieee_input(rb, fn11, 0);
- helper(cpu_fir[rc], va, vb);
+ helper(cpu_fir[rc], cpu_env, va, vb);
tcg_temp_free(va);
tcg_temp_free(vb);
@@ -1082,7 +1090,7 @@
IEEE_ARITH3(divt)
static void gen_ieee_compare(DisasContext *ctx,
- void (*helper)(TCGv, TCGv, TCGv),
+ void (*helper)(TCGv, TCGv_ptr, TCGv, TCGv),
int ra, int rb, int rc, int fn11)
{
TCGv va, vb;
@@ -1097,7 +1105,7 @@
va = gen_ieee_input(ra, fn11, 1);
vb = gen_ieee_input(rb, fn11, 1);
- helper(cpu_fir[rc], va, vb);
+ helper(cpu_fir[rc], cpu_env, va, vb);
tcg_temp_free(va);
tcg_temp_free(vb);
@@ -1388,14 +1396,8 @@
tcg_temp_free(tmp1); \
} \
}
-ARITH3(cmpbge)
-ARITH3(addlv)
-ARITH3(sublv)
-ARITH3(addqv)
-ARITH3(subqv)
ARITH3(umulh)
-ARITH3(mullv)
-ARITH3(mulqv)
+ARITH3(cmpbge)
ARITH3(minub8)
ARITH3(minsb8)
ARITH3(minuw4)
@@ -1406,6 +1408,43 @@
ARITH3(maxsw4)
ARITH3(perr)
+/* Code to call arith3 helpers */
+#define ARITH3_EX(name) \
+ static inline void glue(gen_, name)(int ra, int rb, int rc, \
+ int islit, uint8_t lit) \
+ { \
+ if (unlikely(rc == 31)) { \
+ return; \
+ } \
+ if (ra != 31) { \
+ if (islit) { \
+ TCGv tmp = tcg_const_i64(lit); \
+ gen_helper_ ## name(cpu_ir[rc], cpu_env, \
+ cpu_ir[ra], tmp); \
+ tcg_temp_free(tmp); \
+ } else { \
+ gen_helper_ ## name(cpu_ir[rc], cpu_env, \
+ cpu_ir[ra], cpu_ir[rb]); \
+ } \
+ } else { \
+ TCGv tmp1 = tcg_const_i64(0); \
+ if (islit) { \
+ TCGv tmp2 = tcg_const_i64(lit); \
+ gen_helper_ ## name(cpu_ir[rc], cpu_env, tmp1, tmp2); \
+ tcg_temp_free(tmp2); \
+ } else { \
+ gen_helper_ ## name(cpu_ir[rc], cpu_env, tmp1, cpu_ir[rb]); \
+ } \
+ tcg_temp_free(tmp1); \
+ } \
+ }
+ARITH3_EX(addlv)
+ARITH3_EX(sublv)
+ARITH3_EX(addqv)
+ARITH3_EX(subqv)
+ARITH3_EX(mullv)
+ARITH3_EX(mulqv)
+
#define MVIOP2(name) \
static inline void glue(gen_, name)(int rb, int rc) \
{ \
@@ -1643,12 +1682,12 @@
switch (regno) {
case 255:
/* TBIA */
- gen_helper_tbia();
+ gen_helper_tbia(cpu_env);
break;
case 254:
/* TBIS */
- gen_helper_tbis(tmp);
+ gen_helper_tbis(cpu_env, tmp);
break;
case 253:
@@ -1664,7 +1703,7 @@
case 251:
/* ALARM */
- gen_helper_set_alarm(tmp);
+ gen_helper_set_alarm(cpu_env, tmp);
break;
default:
@@ -2674,17 +2713,17 @@
case 0x024:
/* MT_FPCR */
if (likely(ra != 31))
- gen_helper_store_fpcr(cpu_fir[ra]);
+ gen_helper_store_fpcr(cpu_env, cpu_fir[ra]);
else {
TCGv tmp = tcg_const_i64(0);
- gen_helper_store_fpcr(tmp);
+ gen_helper_store_fpcr(cpu_env, tmp);
tcg_temp_free(tmp);
}
break;
case 0x025:
/* MF_FPCR */
if (likely(ra != 31))
- gen_helper_load_fpcr(cpu_fir[ra]);
+ gen_helper_load_fpcr(cpu_fir[ra], cpu_env);
break;
case 0x02A:
/* FCMOVEQ */
@@ -2758,11 +2797,11 @@
if (ra != 31) {
if (use_icount) {
gen_io_start();
- gen_helper_load_pcc(cpu_ir[ra]);
+ gen_helper_load_pcc(cpu_ir[ra], cpu_env);
gen_io_end();
ret = EXIT_PC_STALE;
} else {
- gen_helper_load_pcc(cpu_ir[ra]);
+ gen_helper_load_pcc(cpu_ir[ra], cpu_env);
}
}
break;
@@ -2832,11 +2871,11 @@
break;
case 0x2:
/* Longword physical access with lock (hw_ldl_l/p) */
- gen_helper_ldl_l_phys(cpu_ir[ra], addr);
+ gen_helper_ldl_l_phys(cpu_ir[ra], cpu_env, addr);
break;
case 0x3:
/* Quadword physical access with lock (hw_ldq_l/p) */
- gen_helper_ldq_l_phys(cpu_ir[ra], addr);
+ gen_helper_ldq_l_phys(cpu_ir[ra], cpu_env, addr);
break;
case 0x4:
/* Longword virtual PTE fetch (hw_ldl/v) */
@@ -3108,10 +3147,10 @@
emulation PALcode, so continue to accept it. */
TCGv tmp = tcg_temp_new();
tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUAlphaState, exc_addr));
- gen_helper_hw_ret(tmp);
+ gen_helper_hw_ret(cpu_env, tmp);
tcg_temp_free(tmp);
} else {
- gen_helper_hw_ret(cpu_ir[rb]);
+ gen_helper_hw_ret(cpu_env, cpu_ir[rb]);
}
ret = EXIT_PC_UPDATED;
break;
@@ -3145,11 +3184,11 @@
break;
case 0x2:
/* Longword physical access with lock */
- gen_helper_stl_c_phys(val, addr, val);
+ gen_helper_stl_c_phys(val, cpu_env, addr, val);
break;
case 0x3:
/* Quadword physical access with lock */
- gen_helper_stq_c_phys(val, addr, val);
+ gen_helper_stq_c_phys(val, cpu_env, addr, val);
break;
case 0x4:
/* Longword virtual access */
@@ -3385,7 +3424,7 @@
}
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
gen_io_start();
- insn = ldl_code(ctx.pc);
+ insn = cpu_ldl_code(env, ctx.pc);
num_insns++;
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
@@ -3513,7 +3552,8 @@
#if defined (CONFIG_USER_ONLY)
env->ps = PS_USER_MODE;
cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
- | FPCR_UNFD | FPCR_INED | FPCR_DNOD));
+ | FPCR_UNFD | FPCR_INED | FPCR_DNOD
+ | FPCR_DYN_NORMAL));
#endif
env->lock_addr = -1;
env->fen = 1;
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 442f684..76fb451 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -1,7 +1,7 @@
#include "def-helper.h"
-DEF_HELPER_2(raise_exception_err, void, i32, int)
-DEF_HELPER_1(raise_exception, void, i32)
+DEF_HELPER_2(raise_exception_err, noreturn, i32, int)
+DEF_HELPER_1(raise_exception, noreturn, i32)
#ifdef TARGET_MIPS64
DEF_HELPER_3(ldl, tl, tl, tl, int)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 3a20731..ce01225 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -2292,7 +2292,8 @@
#if !defined(CONFIG_USER_ONLY)
-static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
+static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
+ int is_user, void *retaddr);
#define MMUSUFFIX _mmu
#define ALIGNED_ONLY
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 1025752..885ad45 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -699,8 +699,9 @@
void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit);
trap_state* cpu_tsptr(CPUSPARCState* env);
#endif
-void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write,
- int is_user, void *retaddr);
+void QEMU_NORETURN do_unaligned_access(CPUSPARCState *env, target_ulong addr,
+ int is_write, int is_user,
+ void *retaddr);
#define TB_FLAG_FPU_ENABLED (1 << 4)
#define TB_FLAG_AM_ENABLED (1 << 5)
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index c4d6225..e3c7fdd 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -78,7 +78,7 @@
DEF_HELPER_1(fcmpeq_fcc2, void, env)
DEF_HELPER_1(fcmpeq_fcc3, void, env)
#endif
-DEF_HELPER_2(raise_exception, void, env, int)
+DEF_HELPER_2(raise_exception, noreturn, env, int)
#define F_HELPER_0_1(name) DEF_HELPER_1(f ## name, void, env)
DEF_HELPER_3(faddd, f64, env, f64, f64)
diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c
index 11fb9f5..cb73c44 100644
--- a/target-sparc/mmu_helper.c
+++ b/target-sparc/mmu_helper.c
@@ -150,18 +150,17 @@
case 3: /* Reserved */
return (3 << 8) | (4 << 2);
case 2: /* L3 PTE */
- page_offset = (address & TARGET_PAGE_MASK) &
- (TARGET_PAGE_SIZE - 1);
+ page_offset = 0;
}
*page_size = TARGET_PAGE_SIZE;
break;
case 2: /* L2 PTE */
- page_offset = address & 0x3ffff;
+ page_offset = address & 0x3f000;
*page_size = 0x40000;
}
break;
case 2: /* L1 PTE */
- page_offset = address & 0xffffff;
+ page_offset = address & 0xfff000;
*page_size = 0x1000000;
}
}
@@ -206,11 +205,11 @@
target_ulong page_size;
int error_code = 0, prot, access_index;
+ address &= TARGET_PAGE_MASK;
error_code = get_physical_address(env, &paddr, &prot, &access_index,
address, rw, mmu_idx, &page_size);
+ vaddr = address;
if (error_code == 0) {
- vaddr = address & TARGET_PAGE_MASK;
- paddr &= TARGET_PAGE_MASK;
#ifdef DEBUG_MMU
printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
TARGET_FMT_lx "\n", address, paddr, vaddr);
@@ -230,7 +229,6 @@
permissions. If no mapping is available, redirect accesses to
neverland. Fake/overridden mappings will be flushed when
switching to normal mode. */
- vaddr = address & TARGET_PAGE_MASK;
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
return 0;
@@ -704,17 +702,16 @@
int cpu_sparc_handle_mmu_fault(CPUSPARCState *env, target_ulong address, int rw,
int mmu_idx)
{
- target_ulong virt_addr, vaddr;
+ target_ulong vaddr;
target_phys_addr_t paddr;
target_ulong page_size;
int error_code = 0, prot, access_index;
+ address &= TARGET_PAGE_MASK;
error_code = get_physical_address(env, &paddr, &prot, &access_index,
address, rw, mmu_idx, &page_size);
if (error_code == 0) {
- virt_addr = address & TARGET_PAGE_MASK;
- vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
- (TARGET_PAGE_SIZE - 1));
+ vaddr = address;
trace_mmu_helper_mmu_fault(address, paddr, mmu_idx, env->tl,
env->dmmu.mmu_primary_context,
diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c
index e579ef0..2885212 100644
--- a/tcg/hppa/tcg-target.c
+++ b/tcg/hppa/tcg-target.c
@@ -336,7 +336,7 @@
#define INSN_COMIBF (INSN_OP(0x23))
/* supplied by libgcc */
-extern void *__canonicalize_funcptr_for_compare(void *);
+extern void *__canonicalize_funcptr_for_compare(const void *);
static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
{
@@ -628,7 +628,7 @@
tcg_out_shd(s, ret, arg, temp, 8); /* ret = DCBA */
}
-static void tcg_out_call(TCGContext *s, void *func)
+static void tcg_out_call(TCGContext *s, const void *func)
{
tcg_target_long val, hi, lo, disp;
@@ -1661,23 +1661,18 @@
TCG_REG_R18
};
+#define FRAME_SIZE ((-TCG_TARGET_CALL_STACK_OFFSET \
+ + TCG_TARGET_STATIC_CALL_ARGS_SIZE \
+ + ARRAY_SIZE(tcg_target_callee_save_regs) * 4 \
+ + CPU_TEMP_BUF_NLONGS * sizeof(long) \
+ + TCG_TARGET_STACK_ALIGN - 1) \
+ & -TCG_TARGET_STACK_ALIGN)
+
static void tcg_target_qemu_prologue(TCGContext *s)
{
int frame_size, i;
- /* Allocate space for the fixed frame marker. */
- frame_size = -TCG_TARGET_CALL_STACK_OFFSET;
- frame_size += TCG_TARGET_STATIC_CALL_ARGS_SIZE;
-
- /* Allocate space for the saved registers. */
- frame_size += ARRAY_SIZE(tcg_target_callee_save_regs) * 4;
-
- /* Allocate space for the TCG temps. */
- frame_size += CPU_TEMP_BUF_NLONGS * sizeof(long);
-
- /* Align the allocated space. */
- frame_size = ((frame_size + TCG_TARGET_STACK_ALIGN - 1)
- & -TCG_TARGET_STACK_ALIGN);
+ frame_size = FRAME_SIZE;
/* The return address is stored in the caller's frame. */
tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_CALL_STACK, -20);
@@ -1752,3 +1747,81 @@
tcg_add_target_add_op_defs(hppa_op_defs);
}
+
+typedef struct {
+ uint32_t len __attribute__((aligned((sizeof(void *)))));
+ uint32_t id;
+ uint8_t version;
+ char augmentation[1];
+ uint8_t code_align;
+ uint8_t data_align;
+ uint8_t return_column;
+} DebugFrameCIE;
+
+typedef struct {
+ uint32_t len __attribute__((aligned((sizeof(void *)))));
+ uint32_t cie_offset;
+ tcg_target_long func_start __attribute__((packed));
+ tcg_target_long func_len __attribute__((packed));
+ uint8_t def_cfa[4];
+ uint8_t ret_ofs[3];
+ uint8_t reg_ofs[ARRAY_SIZE(tcg_target_callee_save_regs) * 2];
+} DebugFrameFDE;
+
+typedef struct {
+ DebugFrameCIE cie;
+ DebugFrameFDE fde;
+} DebugFrame;
+
+#define ELF_HOST_MACHINE EM_PARISC
+#define ELF_HOST_FLAGS EFA_PARISC_1_1
+
+/* ??? BFD (and thus GDB) wants very much to distinguish between HPUX
+ and other extensions. We don't really care, but if we don't set this
+ to *something* then the object file won't be properly matched. */
+#define ELF_OSABI ELFOSABI_LINUX
+
+static DebugFrame debug_frame = {
+ .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+ .cie.id = -1,
+ .cie.version = 1,
+ .cie.code_align = 1,
+ .cie.data_align = 1,
+ .cie.return_column = 2,
+
+ .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
+ .fde.def_cfa = {
+ 0x12, 30, /* DW_CFA_def_cfa_sf sp, ... */
+ (-FRAME_SIZE & 0x7f) | 0x80, /* ... sleb128 -FRAME_SIZE */
+ (-FRAME_SIZE >> 7) & 0x7f
+ },
+ .fde.ret_ofs = {
+ 0x11, 2, (-20 / 4) & 0x7f /* DW_CFA_offset_extended_sf r2, 20 */
+ },
+ .fde.reg_ofs = {
+ /* This must match the ordering in tcg_target_callee_save_regs. */
+ 0x80 + 4, 0, /* DW_CFA_offset r4, 0 */
+ 0x80 + 5, 4, /* DW_CFA_offset r5, 4 */
+ 0x80 + 6, 8, /* DW_CFA_offset r6, 8 */
+ 0x80 + 7, 12, /* ... */
+ 0x80 + 8, 16,
+ 0x80 + 9, 20,
+ 0x80 + 10, 24,
+ 0x80 + 11, 28,
+ 0x80 + 12, 32,
+ 0x80 + 13, 36,
+ 0x80 + 14, 40,
+ 0x80 + 15, 44,
+ 0x80 + 16, 48,
+ 0x80 + 17, 52,
+ 0x80 + 18, 56,
+ }
+};
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+ debug_frame.fde.func_start = (tcg_target_long) buf;
+ debug_frame.fde.func_len = buf_size;
+
+ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
+}
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 43a51a1..871a7e7 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -1989,22 +1989,29 @@
#endif
};
+/* Compute frame size via macros, to share between tcg_target_qemu_prologue
+ and tcg_register_jit. */
+
+#define PUSH_SIZE \
+ ((1 + ARRAY_SIZE(tcg_target_callee_save_regs)) \
+ * (TCG_TARGET_REG_BITS / 8))
+
+#define FRAME_SIZE \
+ ((PUSH_SIZE \
+ + TCG_STATIC_CALL_ARGS_SIZE \
+ + CPU_TEMP_BUF_NLONGS * sizeof(long) \
+ + TCG_TARGET_STACK_ALIGN - 1) \
+ & ~(TCG_TARGET_STACK_ALIGN - 1))
+
/* Generate global QEMU prologue and epilogue code */
static void tcg_target_qemu_prologue(TCGContext *s)
{
- int i, frame_size, push_size, stack_addend;
+ int i, stack_addend;
/* TB prologue */
/* Reserve some stack space, also for TCG temps. */
- push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
- push_size *= TCG_TARGET_REG_BITS / 8;
-
- frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE +
- CPU_TEMP_BUF_NLONGS * sizeof(long);
- frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
- ~(TCG_TARGET_STACK_ALIGN - 1);
- stack_addend = frame_size - push_size;
+ stack_addend = FRAME_SIZE - PUSH_SIZE;
tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE,
CPU_TEMP_BUF_NLONGS * sizeof(long));
@@ -2070,3 +2077,92 @@
tcg_add_target_add_op_defs(x86_op_defs);
}
+
+typedef struct {
+ uint32_t len __attribute__((aligned((sizeof(void *)))));
+ uint32_t id;
+ uint8_t version;
+ char augmentation[1];
+ uint8_t code_align;
+ uint8_t data_align;
+ uint8_t return_column;
+} DebugFrameCIE;
+
+typedef struct {
+ uint32_t len __attribute__((aligned((sizeof(void *)))));
+ uint32_t cie_offset;
+ tcg_target_long func_start __attribute__((packed));
+ tcg_target_long func_len __attribute__((packed));
+ uint8_t def_cfa[4];
+ uint8_t reg_ofs[14];
+} DebugFrameFDE;
+
+typedef struct {
+ DebugFrameCIE cie;
+ DebugFrameFDE fde;
+} DebugFrame;
+
+#if TCG_TARGET_REG_BITS == 64
+#define ELF_HOST_MACHINE EM_X86_64
+static DebugFrame debug_frame = {
+ .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+ .cie.id = -1,
+ .cie.version = 1,
+ .cie.code_align = 1,
+ .cie.data_align = 0x78, /* sleb128 -8 */
+ .cie.return_column = 16,
+
+ .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
+ .fde.def_cfa = {
+ 12, 7, /* DW_CFA_def_cfa %rsp, ... */
+ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */
+ (FRAME_SIZE >> 7)
+ },
+ .fde.reg_ofs = {
+ 0x90, 1, /* DW_CFA_offset, %rip, -8 */
+ /* The following ordering must match tcg_target_callee_save_regs. */
+ 0x86, 2, /* DW_CFA_offset, %rbp, -16 */
+ 0x83, 3, /* DW_CFA_offset, %rbx, -24 */
+ 0x8c, 4, /* DW_CFA_offset, %r12, -32 */
+ 0x8d, 5, /* DW_CFA_offset, %r13, -40 */
+ 0x8e, 6, /* DW_CFA_offset, %r14, -48 */
+ 0x8f, 7, /* DW_CFA_offset, %r15, -56 */
+ }
+};
+#else
+#define ELF_HOST_MACHINE EM_386
+static DebugFrame debug_frame = {
+ .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+ .cie.id = -1,
+ .cie.version = 1,
+ .cie.code_align = 1,
+ .cie.data_align = 0x7c, /* sleb128 -4 */
+ .cie.return_column = 8,
+
+ .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
+ .fde.def_cfa = {
+ 12, 4, /* DW_CFA_def_cfa %esp, ... */
+ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */
+ (FRAME_SIZE >> 7)
+ },
+ .fde.reg_ofs = {
+ 0x88, 1, /* DW_CFA_offset, %eip, -4 */
+ /* The following ordering must match tcg_target_callee_save_regs. */
+ 0x85, 2, /* DW_CFA_offset, %ebp, -8 */
+ 0x83, 3, /* DW_CFA_offset, %ebx, -12 */
+ 0x86, 4, /* DW_CFA_offset, %esi, -16 */
+ 0x87, 5, /* DW_CFA_offset, %edi, -20 */
+ }
+};
+#endif
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+ /* We're expecting a 2 byte uleb128 encoded value. */
+ assert(FRAME_SIZE >> 14 == 0);
+
+ debug_frame.fde.func_start = (tcg_target_long) buf;
+ debug_frame.fde.func_len = buf_size;
+
+ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
+}
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index 491c979..247a278 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -1624,3 +1624,66 @@
tcg_regset_set_reg(s->reserved_regs, TCG_REG_O7);
tcg_add_target_add_op_defs(sparc_op_defs);
}
+
+#if TCG_TARGET_REG_BITS == 64
+# define ELF_HOST_MACHINE EM_SPARCV9
+#elif defined(__sparc_v8plus__)
+# define ELF_HOST_MACHINE EM_SPARC32PLUS
+# define ELF_HOST_FLAGS EF_SPARC_32PLUS
+#else
+# define ELF_HOST_MACHINE EM_SPARC
+#endif
+
+typedef struct {
+ uint32_t len __attribute__((aligned((sizeof(void *)))));
+ uint32_t id;
+ uint8_t version;
+ char augmentation[1];
+ uint8_t code_align;
+ uint8_t data_align;
+ uint8_t return_column;
+} DebugFrameCIE;
+
+typedef struct {
+ uint32_t len __attribute__((aligned((sizeof(void *)))));
+ uint32_t cie_offset;
+ tcg_target_long func_start __attribute__((packed));
+ tcg_target_long func_len __attribute__((packed));
+ uint8_t def_cfa[TCG_TARGET_REG_BITS == 64 ? 4 : 2];
+ uint8_t win_save;
+ uint8_t ret_save[3];
+} DebugFrameFDE;
+
+typedef struct {
+ DebugFrameCIE cie;
+ DebugFrameFDE fde;
+} DebugFrame;
+
+static DebugFrame debug_frame = {
+ .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+ .cie.id = -1,
+ .cie.version = 1,
+ .cie.code_align = 1,
+ .cie.data_align = -sizeof(void *) & 0x7f,
+ .cie.return_column = 15, /* o7 */
+
+ .fde.len = sizeof(DebugFrameFDE)-4, /* length after .len member */
+ .fde.def_cfa = {
+#if TCG_TARGET_REG_BITS == 64
+ 12, 30, /* DW_CFA_def_cfa i6, 2047 */
+ (2047 & 0x7f) | 0x80, (2047 >> 7)
+#else
+ 13, 30 /* DW_CFA_def_cfa_register i6 */
+#endif
+ },
+ .fde.win_save = 0x2d, /* DW_CFA_GNU_window_save */
+ .fde.ret_save = { 9, 15, 31 }, /* DW_CFA_register o7, i7 */
+};
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+ debug_frame.fde.func_start = (tcg_target_long) buf;
+ debug_frame.fde.func_len = buf_size;
+
+ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
+}
diff --git a/tcg/tcg.c b/tcg/tcg.c
index ccfcd1a..ab589c7 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -28,6 +28,9 @@
#include "config.h"
+/* Define to jump the ELF file used to communicate with GDB. */
+#undef DEBUG_JIT
+
#if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG)
/* define it to suppress various consistency checks (faster) */
#define NDEBUG
@@ -45,6 +48,18 @@
#include "cpu.h"
#include "tcg-op.h"
+
+#if TCG_TARGET_REG_BITS == 64
+# define ELF_CLASS ELFCLASS64
+#else
+# define ELF_CLASS ELFCLASS32
+#endif
+#ifdef HOST_WORDS_BIGENDIAN
+# define ELF_DATA ELFDATA2MSB
+#else
+# define ELF_DATA ELFDATA2LSB
+#endif
+
#include "elf.h"
#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
@@ -57,6 +72,10 @@
static void patch_reloc(uint8_t *code_ptr, int type,
tcg_target_long value, tcg_target_long addend);
+static void tcg_register_jit_int(void *buf, size_t size,
+ void *debug_frame, size_t debug_frame_size)
+ __attribute__((unused));
+
/* Forward declarations for functions declared and used in tcg-target.c. */
static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str);
static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
@@ -2231,3 +2250,267 @@
cpu_fprintf(f, "[TCG profiler not compiled]\n");
}
#endif
+
+#ifdef ELF_HOST_MACHINE
+/* In order to use this feature, the backend needs to do three things:
+
+ (1) Define ELF_HOST_MACHINE to indicate both what value to
+ put into the ELF image and to indicate support for the feature.
+
+ (2) Define tcg_register_jit. This should create a buffer containing
+ the contents of a .debug_frame section that describes the post-
+ prologue unwind info for the tcg machine.
+
+ (3) Call tcg_register_jit_int, with the constructed .debug_frame.
+*/
+
+/* Begin GDB interface. THE FOLLOWING MUST MATCH GDB DOCS. */
+typedef enum {
+ JIT_NOACTION = 0,
+ JIT_REGISTER_FN,
+ JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry {
+ struct jit_code_entry *next_entry;
+ struct jit_code_entry *prev_entry;
+ const void *symfile_addr;
+ uint64_t symfile_size;
+};
+
+struct jit_descriptor {
+ uint32_t version;
+ uint32_t action_flag;
+ struct jit_code_entry *relevant_entry;
+ struct jit_code_entry *first_entry;
+};
+
+void __jit_debug_register_code(void) __attribute__((noinline));
+void __jit_debug_register_code(void)
+{
+ asm("");
+}
+
+/* Must statically initialize the version, because GDB may check
+ the version before we can set it. */
+struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+/* End GDB interface. */
+
+static int find_string(const char *strtab, const char *str)
+{
+ const char *p = strtab + 1;
+
+ while (1) {
+ if (strcmp(p, str) == 0) {
+ return p - strtab;
+ }
+ p += strlen(p) + 1;
+ }
+}
+
+static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
+ void *debug_frame, size_t debug_frame_size)
+{
+ struct __attribute__((packed)) DebugInfo {
+ uint32_t len;
+ uint16_t version;
+ uint32_t abbrev;
+ uint8_t ptr_size;
+ uint8_t cu_die;
+ uint16_t cu_lang;
+ uintptr_t cu_low_pc;
+ uintptr_t cu_high_pc;
+ uint8_t fn_die;
+ char fn_name[16];
+ uintptr_t fn_low_pc;
+ uintptr_t fn_high_pc;
+ uint8_t cu_eoc;
+ };
+
+ struct ElfImage {
+ ElfW(Ehdr) ehdr;
+ ElfW(Phdr) phdr;
+ ElfW(Shdr) shdr[7];
+ ElfW(Sym) sym[2];
+ struct DebugInfo di;
+ uint8_t da[24];
+ char str[80];
+ };
+
+ struct ElfImage *img;
+
+ static const struct ElfImage img_template = {
+ .ehdr = {
+ .e_ident[EI_MAG0] = ELFMAG0,
+ .e_ident[EI_MAG1] = ELFMAG1,
+ .e_ident[EI_MAG2] = ELFMAG2,
+ .e_ident[EI_MAG3] = ELFMAG3,
+ .e_ident[EI_CLASS] = ELF_CLASS,
+ .e_ident[EI_DATA] = ELF_DATA,
+ .e_ident[EI_VERSION] = EV_CURRENT,
+ .e_type = ET_EXEC,
+ .e_machine = ELF_HOST_MACHINE,
+ .e_version = EV_CURRENT,
+ .e_phoff = offsetof(struct ElfImage, phdr),
+ .e_shoff = offsetof(struct ElfImage, shdr),
+ .e_ehsize = sizeof(ElfW(Shdr)),
+ .e_phentsize = sizeof(ElfW(Phdr)),
+ .e_phnum = 1,
+ .e_shentsize = sizeof(ElfW(Shdr)),
+ .e_shnum = ARRAY_SIZE(img->shdr),
+ .e_shstrndx = ARRAY_SIZE(img->shdr) - 1,
+#ifdef ELF_HOST_FLAGS
+ .e_flags = ELF_HOST_FLAGS,
+#endif
+#ifdef ELF_OSABI
+ .e_ident[EI_OSABI] = ELF_OSABI,
+#endif
+ },
+ .phdr = {
+ .p_type = PT_LOAD,
+ .p_flags = PF_X,
+ },
+ .shdr = {
+ [0] = { .sh_type = SHT_NULL },
+ /* Trick: The contents of code_gen_buffer are not present in
+ this fake ELF file; that got allocated elsewhere. Therefore
+ we mark .text as SHT_NOBITS (similar to .bss) so that readers
+ will not look for contents. We can record any address. */
+ [1] = { /* .text */
+ .sh_type = SHT_NOBITS,
+ .sh_flags = SHF_EXECINSTR | SHF_ALLOC,
+ },
+ [2] = { /* .debug_info */
+ .sh_type = SHT_PROGBITS,
+ .sh_offset = offsetof(struct ElfImage, di),
+ .sh_size = sizeof(struct DebugInfo),
+ },
+ [3] = { /* .debug_abbrev */
+ .sh_type = SHT_PROGBITS,
+ .sh_offset = offsetof(struct ElfImage, da),
+ .sh_size = sizeof(img->da),
+ },
+ [4] = { /* .debug_frame */
+ .sh_type = SHT_PROGBITS,
+ .sh_offset = sizeof(struct ElfImage),
+ },
+ [5] = { /* .symtab */
+ .sh_type = SHT_SYMTAB,
+ .sh_offset = offsetof(struct ElfImage, sym),
+ .sh_size = sizeof(img->sym),
+ .sh_info = 1,
+ .sh_link = ARRAY_SIZE(img->shdr) - 1,
+ .sh_entsize = sizeof(ElfW(Sym)),
+ },
+ [6] = { /* .strtab */
+ .sh_type = SHT_STRTAB,
+ .sh_offset = offsetof(struct ElfImage, str),
+ .sh_size = sizeof(img->str),
+ }
+ },
+ .sym = {
+ [1] = { /* code_gen_buffer */
+ .st_info = ELF_ST_INFO(STB_GLOBAL, STT_FUNC),
+ .st_shndx = 1,
+ }
+ },
+ .di = {
+ .len = sizeof(struct DebugInfo) - 4,
+ .version = 2,
+ .ptr_size = sizeof(void *),
+ .cu_die = 1,
+ .cu_lang = 0x8001, /* DW_LANG_Mips_Assembler */
+ .fn_die = 2,
+ .fn_name = "code_gen_buffer"
+ },
+ .da = {
+ 1, /* abbrev number (the cu) */
+ 0x11, 1, /* DW_TAG_compile_unit, has children */
+ 0x13, 0x5, /* DW_AT_language, DW_FORM_data2 */
+ 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */
+ 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */
+ 0, 0, /* end of abbrev */
+ 2, /* abbrev number (the fn) */
+ 0x2e, 0, /* DW_TAG_subprogram, no children */
+ 0x3, 0x8, /* DW_AT_name, DW_FORM_string */
+ 0x11, 0x1, /* DW_AT_low_pc, DW_FORM_addr */
+ 0x12, 0x1, /* DW_AT_high_pc, DW_FORM_addr */
+ 0, 0, /* end of abbrev */
+ 0 /* no more abbrev */
+ },
+ .str = "\0" ".text\0" ".debug_info\0" ".debug_abbrev\0"
+ ".debug_frame\0" ".symtab\0" ".strtab\0" "code_gen_buffer",
+ };
+
+ /* We only need a single jit entry; statically allocate it. */
+ static struct jit_code_entry one_entry;
+
+ uintptr_t buf = (uintptr_t)buf_ptr;
+ size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
+
+ img = g_malloc(img_size);
+ *img = img_template;
+ memcpy(img + 1, debug_frame, debug_frame_size);
+
+ img->phdr.p_vaddr = buf;
+ img->phdr.p_paddr = buf;
+ img->phdr.p_memsz = buf_size;
+
+ img->shdr[1].sh_name = find_string(img->str, ".text");
+ img->shdr[1].sh_addr = buf;
+ img->shdr[1].sh_size = buf_size;
+
+ img->shdr[2].sh_name = find_string(img->str, ".debug_info");
+ img->shdr[3].sh_name = find_string(img->str, ".debug_abbrev");
+
+ img->shdr[4].sh_name = find_string(img->str, ".debug_frame");
+ img->shdr[4].sh_size = debug_frame_size;
+
+ img->shdr[5].sh_name = find_string(img->str, ".symtab");
+ img->shdr[6].sh_name = find_string(img->str, ".strtab");
+
+ img->sym[1].st_name = find_string(img->str, "code_gen_buffer");
+ img->sym[1].st_value = buf;
+ img->sym[1].st_size = buf_size;
+
+ img->di.cu_low_pc = buf;
+ img->di.cu_high_pc = buf_size;
+ img->di.fn_low_pc = buf;
+ img->di.fn_high_pc = buf_size;
+
+#ifdef DEBUG_JIT
+ /* Enable this block to be able to debug the ELF image file creation.
+ One can use readelf, objdump, or other inspection utilities. */
+ {
+ FILE *f = fopen("/tmp/qemu.jit", "w+b");
+ if (f) {
+ if (fwrite(img, img_size, 1, f) != img_size) {
+ /* Avoid stupid unused return value warning for fwrite. */
+ }
+ fclose(f);
+ }
+ }
+#endif
+
+ one_entry.symfile_addr = img;
+ one_entry.symfile_size = img_size;
+
+ __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+ __jit_debug_descriptor.relevant_entry = &one_entry;
+ __jit_debug_descriptor.first_entry = &one_entry;
+ __jit_debug_register_code();
+}
+#else
+/* No support for the feature. Provide the entry point expected by exec.c,
+ and implement the internal function we declared earlier. */
+
+static void tcg_register_jit_int(void *buf, size_t size,
+ void *debug_frame, size_t debug_frame_size)
+{
+}
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+}
+#endif /* ELF_HOST_MACHINE */
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 5f6c647..a83bdddb 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -586,3 +586,5 @@
# define tcg_qemu_tb_exec(env, tb_ptr) \
((tcg_target_ulong (*)(void *, void *))code_gen_prologue)(env, tb_ptr)
#endif
+
+void tcg_register_jit(void *buf, size_t buf_size);
diff --git a/test-qmp-commands.c b/test-qmp-commands.c
index fa5a7bd..60cbf01 100644
--- a/test-qmp-commands.c
+++ b/test-qmp-commands.c
@@ -46,7 +46,6 @@
resp = qmp_dispatch(QOBJECT(req));
assert(resp != NULL);
assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
- g_print("\nresp: %s\n", qstring_get_str(qobject_to_json(resp)));
qobject_decref(resp);
QDECREF(req);
@@ -63,7 +62,6 @@
resp = qmp_dispatch(QOBJECT(req));
assert(resp != NULL);
assert(qdict_haskey(qobject_to_qdict(resp), "error"));
- g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp)));
qobject_decref(resp);
QDECREF(req);
@@ -92,7 +90,6 @@
resp = qmp_dispatch(QOBJECT(req));
assert(resp != NULL);
assert(!qdict_haskey(qobject_to_qdict(resp), "error"));
- g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp)));
qobject_decref(resp);
QDECREF(req);
diff --git a/test-qmp-input-strict.c b/test-qmp-input-strict.c
new file mode 100644
index 0000000..f6df8cb
--- /dev/null
+++ b/test-qmp-input-strict.c
@@ -0,0 +1,234 @@
+/*
+ * QMP Input Visitor unit-tests (strict mode).
+ *
+ * Copyright (C) 2011-2012 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ * Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <stdarg.h>
+
+#include "qapi/qmp-input-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestInputVisitorData {
+ QObject *obj;
+ QmpInputVisitor *qiv;
+} TestInputVisitorData;
+
+static void validate_teardown(TestInputVisitorData *data,
+ const void *unused)
+{
+ qobject_decref(data->obj);
+ data->obj = NULL;
+
+ if (data->qiv) {
+ qmp_input_visitor_cleanup(data->qiv);
+ data->qiv = NULL;
+ }
+}
+
+/* This is provided instead of a test setup function so that the JSON
+ string used by the tests are kept in the test functions (and not
+ int main()) */
+static GCC_FMT_ATTR(2, 3)
+Visitor *validate_test_init(TestInputVisitorData *data,
+ const char *json_string, ...)
+{
+ Visitor *v;
+ va_list ap;
+
+ va_start(ap, json_string);
+ data->obj = qobject_from_jsonv(json_string, &ap);
+ va_end(ap);
+
+ g_assert(data->obj != NULL);
+
+ data->qiv = qmp_input_visitor_new_strict(data->obj);
+ g_assert(data->qiv != NULL);
+
+ v = qmp_input_get_visitor(data->qiv);
+ g_assert(v != NULL);
+
+ return v;
+}
+
+typedef struct TestStruct
+{
+ int64_t integer;
+ bool boolean;
+ char *string;
+} TestStruct;
+
+static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
+ const char *name, Error **errp)
+{
+ visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
+ errp);
+
+ visit_type_int(v, &(*obj)->integer, "integer", errp);
+ visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
+ visit_type_str(v, &(*obj)->string, "string", errp);
+
+ visit_end_struct(v, errp);
+}
+
+static void test_validate_struct(TestInputVisitorData *data,
+ const void *unused)
+{
+ TestStruct *p = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
+
+ visit_type_TestStruct(v, &p, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_free(p->string);
+ g_free(p);
+}
+
+static void test_validate_struct_nested(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefNested *udp = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}");
+
+ visit_type_UserDefNested(v, &udp, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ qapi_free_UserDefNested(udp);
+}
+
+static void test_validate_list(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefOneList *head = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
+
+ visit_type_UserDefOneList(v, &head, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ qapi_free_UserDefOneList(head);
+}
+
+static void test_validate_union(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefUnion *tmp = NULL;
+ Visitor *v;
+ Error *errp = NULL;
+
+ v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 } }");
+
+ visit_type_UserDefUnion(v, &tmp, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ qapi_free_UserDefUnion(tmp);
+}
+
+static void test_validate_fail_struct(TestInputVisitorData *data,
+ const void *unused)
+{
+ TestStruct *p = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }");
+
+ visit_type_TestStruct(v, &p, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ if (p) {
+ g_free(p->string);
+ }
+ g_free(p);
+}
+
+static void test_validate_fail_struct_nested(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefNested *udp = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}");
+
+ visit_type_UserDefNested(v, &udp, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ qapi_free_UserDefNested(udp);
+}
+
+static void test_validate_fail_list(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefOneList *head = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]");
+
+ visit_type_UserDefOneList(v, &head, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ qapi_free_UserDefOneList(head);
+}
+
+static void test_validate_fail_union(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefUnion *tmp = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = validate_test_init(data, "{ 'type': 'b', 'data' : { 'integer': 42 }, 'extra': 'yyy' }");
+
+ visit_type_UserDefUnion(v, &tmp, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ qapi_free_UserDefUnion(tmp);
+}
+
+static void validate_test_add(const char *testpath,
+ TestInputVisitorData *data,
+ void (*test_func)(TestInputVisitorData *data, const void *user_data))
+{
+ g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
+ validate_teardown);
+}
+
+int main(int argc, char **argv)
+{
+ TestInputVisitorData testdata;
+
+ g_test_init(&argc, &argv, NULL);
+
+ validate_test_add("/visitor/input-strict/pass/struct",
+ &testdata, test_validate_struct);
+ validate_test_add("/visitor/input-strict/pass/struct-nested",
+ &testdata, test_validate_struct_nested);
+ validate_test_add("/visitor/input-strict/pass/list",
+ &testdata, test_validate_list);
+ validate_test_add("/visitor/input-strict/pass/union",
+ &testdata, test_validate_union);
+ validate_test_add("/visitor/input-strict/fail/struct",
+ &testdata, test_validate_fail_struct);
+ validate_test_add("/visitor/input-strict/fail/struct-nested",
+ &testdata, test_validate_fail_struct_nested);
+ validate_test_add("/visitor/input-strict/fail/list",
+ &testdata, test_validate_fail_list);
+ validate_test_add("/visitor/input-strict/fail/union",
+ &testdata, test_validate_fail_union);
+
+ g_test_run();
+
+ return 0;
+}
diff --git a/test-qmp-input-visitor.c b/test-qmp-input-visitor.c
index 1996e49..c30fdc4 100644
--- a/test-qmp-input-visitor.c
+++ b/test-qmp-input-visitor.c
@@ -258,6 +258,23 @@
visitor_input_teardown);
}
+static void test_visitor_in_errors(TestInputVisitorData *data,
+ const void *unused)
+{
+ TestStruct *p = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', 'string': -42 }");
+
+ visit_type_TestStruct(v, &p, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ g_assert(p->string == NULL);
+
+ g_free(p->string);
+ g_free(p);
+}
+
int main(int argc, char **argv)
{
TestInputVisitorData in_visitor_data;
@@ -282,6 +299,8 @@
&in_visitor_data, test_visitor_in_list);
input_visitor_test_add("/visitor/input/union",
&in_visitor_data, test_visitor_in_union);
+ input_visitor_test_add("/visitor/input/errors",
+ &in_visitor_data, test_visitor_in_errors);
g_test_run();
diff --git a/test-qmp-output-visitor.c b/test-qmp-output-visitor.c
index 4d6c4d4..24a6359 100644
--- a/test-qmp-output-visitor.c
+++ b/test-qmp-output-visitor.c
@@ -274,6 +274,24 @@
qapi_free_UserDefNested(ud2);
}
+static void test_visitor_out_struct_errors(TestOutputVisitorData *data,
+ const void *unused)
+{
+ EnumOne bad_values[] = { ENUM_ONE_MAX, -1 };
+ UserDefOne u = { 0 }, *pu = &u;
+ Error *errp;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
+ errp = NULL;
+ u.has_enum1 = true;
+ u.enum1 = bad_values[i];
+ visit_type_UserDefOne(data->ov, &pu, "unused", &errp);
+ g_assert(error_is_set(&errp) == true);
+ error_free(errp);
+ }
+}
+
typedef struct TestStructList
{
TestStruct *value;
@@ -444,6 +462,8 @@
&out_visitor_data, test_visitor_out_struct);
output_visitor_test_add("/visitor/output/struct-nested",
&out_visitor_data, test_visitor_out_struct_nested);
+ output_visitor_test_add("/visitor/output/struct-errors",
+ &out_visitor_data, test_visitor_out_struct_errors);
output_visitor_test_add("/visitor/output/list",
&out_visitor_data, test_visitor_out_list);
output_visitor_test_add("/visitor/output/list-qapi-free",
diff --git a/tests/Makefile b/tests/Makefile
index c78ade1..2a2fff7 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -3,6 +3,7 @@
CHECKS = check-qdict check-qfloat check-qint check-qstring check-qlist
CHECKS += check-qjson test-qmp-output-visitor test-qmp-input-visitor
CHECKS += test-string-input-visitor test-string-output-visitor test-coroutine
+CHECKS += test-qmp-commands
CHECKS += $(SRC_PATH)/tests/qemu-iotests-quick.sh
check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS)
@@ -15,9 +16,9 @@
check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y)
test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y)
-test-qmp-input-visitor.o test-qmp-output-visitor.o \
+test-qmp-input-visitor.o test-qmp-output-visitor.o test-qmp-input-strict.o \
test-string-input-visitor.o test-string-output-visitor.o \
- test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
+ test-qmp-commands.o: QEMU_CFLAGS += -I $(qapi-dir)
$(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
@@ -36,6 +37,9 @@
test-string-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
test-string-input-visitor: test-string-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+test-qmp-input-strict.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
+test-qmp-input-strict: test-qmp-input-strict.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+
test-qmp-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
test-qmp-output-visitor: test-qmp-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
diff --git a/trace-events b/trace-events
index 70f059d..db2cd39 100644
--- a/trace-events
+++ b/trace-events
@@ -726,7 +726,7 @@
# hw/qxl.c
disable qxl_interface_set_mm_time(int qid, uint32_t mm_time) "%d %d"
disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u"
-qxl_create_guest_primary(int qid, uint32_t width, uint32_t height, uint64_t mem, uint32_t format, uint32_t position) "%d %dx%d mem=%lx %d,%d"
+qxl_create_guest_primary(int qid, uint32_t width, uint32_t height, uint64_t mem, uint32_t format, uint32_t position) "%d %ux%u mem=%" PRIx64 " %u,%u"
qxl_create_guest_primary_rest(int qid, int32_t stride, uint32_t type, uint32_t flags) "%d %d,%d,%d"
qxl_destroy_primary(int qid) "%d"
qxl_enter_vga_mode(int qid) "%d"
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 28d6d4a..cb8a7ad 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -80,8 +80,8 @@
if (async != QXL_SYNC) {
spice_qxl_add_memslot_async(&ssd->qxl, memslot,
- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
- QXL_IO_MEMSLOT_ADD_ASYNC));
+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+ QXL_IO_MEMSLOT_ADD_ASYNC));
} else {
ssd->worker->add_memslot(ssd->worker, memslot);
}
@@ -100,8 +100,8 @@
trace_qemu_spice_create_primary_surface(ssd->qxl.id, id, surface, async);
if (async != QXL_SYNC) {
spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface,
- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
- QXL_IO_CREATE_PRIMARY_ASYNC));
+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+ QXL_IO_CREATE_PRIMARY_ASYNC));
} else {
ssd->worker->create_primary_surface(ssd->worker, id, surface);
}
@@ -113,8 +113,8 @@
trace_qemu_spice_destroy_primary_surface(ssd->qxl.id, id, async);
if (async != QXL_SYNC) {
spice_qxl_destroy_primary_surface_async(&ssd->qxl, id,
- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
- QXL_IO_DESTROY_PRIMARY_ASYNC));
+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+ QXL_IO_DESTROY_PRIMARY_ASYNC));
} else {
ssd->worker->destroy_primary_surface(ssd->worker, id);
}
@@ -168,7 +168,7 @@
drawable->bbox = ssd->dirty;
drawable->clip.type = SPICE_CLIP_TYPE_NONE;
drawable->effect = QXL_EFFECT_OPAQUE;
- drawable->release_info.id = (intptr_t)update;
+ drawable->release_info.id = (uintptr_t)update;
drawable->type = QXL_DRAW_COPY;
drawable->surfaces_dest[0] = -1;
drawable->surfaces_dest[1] = -1;
@@ -179,7 +179,7 @@
+ time_space.tv_nsec / 1000 / 1000;
drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT;
- drawable->u.copy.src_bitmap = (intptr_t)image;
+ drawable->u.copy.src_bitmap = (uintptr_t)image;
drawable->u.copy.src_area.right = bw;
drawable->u.copy.src_area.bottom = bh;
@@ -189,7 +189,7 @@
image->bitmap.stride = bw * 4;
image->descriptor.width = image->bitmap.x = bw;
image->descriptor.height = image->bitmap.y = bh;
- image->bitmap.data = (intptr_t)(update->bitmap);
+ image->bitmap.data = (uintptr_t)(update->bitmap);
image->bitmap.palette = 0;
image->bitmap.format = SPICE_BITMAP_FMT_32BIT;
@@ -210,7 +210,7 @@
}
cmd->type = QXL_CMD_DRAW;
- cmd->data = (intptr_t)drawable;
+ cmd->data = (uintptr_t)drawable;
memset(&ssd->dirty, 0, sizeof(ssd->dirty));
return update;
@@ -254,7 +254,7 @@
surface.mouse_mode = true;
surface.flags = 0;
surface.type = 0;
- surface.mem = (intptr_t)ssd->buf;
+ surface.mem = (uintptr_t)ssd->buf;
surface.group_id = MEMSLOT_GROUP_HOST;
qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC);
diff --git a/vl.c b/vl.c
index 112b0e0..0fccf50 100644
--- a/vl.c
+++ b/vl.c
@@ -3196,7 +3196,7 @@
cpudef_init();
if (cpu_model && *cpu_model == '?') {
- list_cpus(stdout, &fprintf, optarg);
+ list_cpus(stdout, &fprintf, cpu_model);
exit(0);
}