Compare commits
140 Commits
pull-gtk-4
...
pull-usb-5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
840a178c94 | ||
|
|
409951f552 | ||
|
|
2d03b49c3f | ||
|
|
e44a90c596 | ||
|
|
33bbd75a7c | ||
|
|
5538937368 | ||
|
|
6954a1cd97 | ||
|
|
15e3611e1c | ||
|
|
db302f8f93 | ||
|
|
6619bc5c55 | ||
|
|
103db49a10 | ||
|
|
286226a479 | ||
|
|
a63f9f85e3 | ||
|
|
323a8771cf | ||
|
|
2237094d96 | ||
|
|
1c70aa6264 | ||
|
|
f727d0e621 | ||
|
|
b5cde1da0a | ||
|
|
177311157c | ||
|
|
7633378d5f | ||
|
|
c29f9a0a29 | ||
|
|
f318cec6ad | ||
|
|
377a44ec8f | ||
|
|
3933443e38 | ||
|
|
19525524a7 | ||
|
|
f32cdad55d | ||
|
|
9449fdf61f | ||
|
|
00a29f3ddc | ||
|
|
85acfa9c38 | ||
|
|
1090b9c6cc | ||
|
|
2eef0bf821 | ||
|
|
014406b510 | ||
|
|
0ff644a786 | ||
|
|
cb1fa941c1 | ||
|
|
a50c0f5133 | ||
|
|
52e60cdd34 | ||
|
|
2f2a00aec9 | ||
|
|
a65f1de982 | ||
|
|
f502cfc207 | ||
|
|
a0618a1990 | ||
|
|
6cd8a2649a | ||
|
|
7e09797c29 | ||
|
|
aca3f40b37 | ||
|
|
9225d739e7 | ||
|
|
2c8dd31863 | ||
|
|
2c7ffc414d | ||
|
|
90e496386f | ||
|
|
8c6afa6ab1 | ||
|
|
00892383c9 | ||
|
|
d4a2dc675b | ||
|
|
8bcbf37caa | ||
|
|
abf1172fc6 | ||
|
|
c2b820fe58 | ||
|
|
ccd380876b | ||
|
|
c6138aabfb | ||
|
|
5149e557d7 | ||
|
|
a9e8aeb375 | ||
|
|
b825025f08 | ||
|
|
a056c9faa4 | ||
|
|
3d4299f425 | ||
|
|
dc73dfd4bc | ||
|
|
edd8824cd4 | ||
|
|
e81864a109 | ||
|
|
de61d14fa7 | ||
|
|
667b1cdd4e | ||
|
|
9e4177ad6d | ||
|
|
dc0c8aaf2c | ||
|
|
ae7ab46aa8 | ||
|
|
6f4724672c | ||
|
|
38d195aa05 | ||
|
|
95f72aa90a | ||
|
|
d82b78e48b | ||
|
|
3d9e69a238 | ||
|
|
cae1f6f3e6 | ||
|
|
81d8a5ee19 | ||
|
|
c6e310d938 | ||
|
|
d8918df577 | ||
|
|
4ec4f0bd56 | ||
|
|
dfeb5fe770 | ||
|
|
929f8b5550 | ||
|
|
8bf56493f1 | ||
|
|
661f7fa4b0 | ||
|
|
851627352c | ||
|
|
50212d6346 | ||
|
|
c2b9af1d6c | ||
|
|
940973ae0b | ||
|
|
8611224a7b | ||
|
|
482f38b948 | ||
|
|
590e5dd98f | ||
|
|
f12d048a52 | ||
|
|
3c99afc779 | ||
|
|
9878d173f5 | ||
|
|
8c6c047899 | ||
|
|
92b3eeadd9 | ||
|
|
edc2438512 | ||
|
|
21e2db7260 | ||
|
|
80fc7b1755 | ||
|
|
5450466394 | ||
|
|
cd82b6fb4d | ||
|
|
715c3f60ef | ||
|
|
28ec11bc88 | ||
|
|
2d968ffbae | ||
|
|
afbc0dd649 | ||
|
|
f516a5cc05 | ||
|
|
0a9077ea14 | ||
|
|
775478418a | ||
|
|
50329d3418 | ||
|
|
efcc87d9ae | ||
|
|
7dc176bce4 | ||
|
|
9bc1a1d817 | ||
|
|
f2ccc311df | ||
|
|
093de72b9c | ||
|
|
800b0e814b | ||
|
|
9a4fb6aa19 | ||
|
|
e792933ce1 | ||
|
|
06f6e12491 | ||
|
|
6a2b3d89fa | ||
|
|
05edc26c61 | ||
|
|
e81a982aa5 | ||
|
|
6cd7db3d92 | ||
|
|
d1dec5ef55 | ||
|
|
6bbad7a91e | ||
|
|
50fc89e7b1 | ||
|
|
bcb7652e8d | ||
|
|
d359db00e6 | ||
|
|
80189035de | ||
|
|
0453099b7d | ||
|
|
a13d448968 | ||
|
|
3636226ae4 | ||
|
|
6a450df9b8 | ||
|
|
9854202b57 | ||
|
|
577a67234d | ||
|
|
55519a4b24 | ||
|
|
f85e3457ce | ||
|
|
9c269f6d7b | ||
|
|
dffacd4654 | ||
|
|
20c50a955f | ||
|
|
bd7ce902ab | ||
|
|
e20c016e32 | ||
|
|
dc491cfc14 |
3
Makefile
3
Makefile
@@ -133,6 +133,7 @@ dummy := $(call unnest-vars,, \
|
||||
stub-obj-y \
|
||||
util-obj-y \
|
||||
qga-obj-y \
|
||||
qga-vss-dll-obj-y \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
common-obj-y \
|
||||
@@ -376,7 +377,7 @@ endif
|
||||
ifneq ($(CONFIG_MODULES),)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)"
|
||||
for s in $(patsubst %.mo,%$(DSOSUF),$(modules-m)); do \
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $$s "$(DESTDIR)$(qemu_moddir)/$${s//\//-}"; \
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $$s "$(DESTDIR)$(qemu_moddir)/$$(echo $$s | tr / -)"; \
|
||||
done
|
||||
endif
|
||||
ifneq ($(HELPERS-y),)
|
||||
|
||||
@@ -148,16 +148,26 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->extent_blocks = 1 + (le32_to_cpu(bochs.extent) - 1) / 512;
|
||||
|
||||
s->extent_size = le32_to_cpu(bochs.extent);
|
||||
if (s->extent_size == 0) {
|
||||
error_setg(errp, "Extent size may not be zero");
|
||||
return -EINVAL;
|
||||
if (s->extent_size < BDRV_SECTOR_SIZE) {
|
||||
/* bximage actually never creates extents smaller than 4k */
|
||||
error_setg(errp, "Extent size must be at least 512");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
} else if (!is_power_of_2(s->extent_size)) {
|
||||
error_setg(errp, "Extent size %" PRIu32 " is not a power of two",
|
||||
s->extent_size);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
} else if (s->extent_size > 0x800000) {
|
||||
error_setg(errp, "Extent size %" PRIu32 " is too large",
|
||||
s->extent_size);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (s->catalog_size < bs->total_sectors / s->extent_size) {
|
||||
if (s->catalog_size < DIV_ROUND_UP(bs->total_sectors,
|
||||
s->extent_size / BDRV_SECTOR_SIZE))
|
||||
{
|
||||
error_setg(errp, "Catalog size is too small for this disk size");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
|
||||
@@ -1233,6 +1233,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
iscsi_readcapacity_sync(iscsilun, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
|
||||
|
||||
@@ -1876,6 +1876,10 @@ void qmp_block_commit(const char *device,
|
||||
*/
|
||||
BlockdevOnError on_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||
|
||||
if (!has_speed) {
|
||||
speed = 0;
|
||||
}
|
||||
|
||||
/* drain all i/o before commits */
|
||||
bdrv_drain_all();
|
||||
|
||||
|
||||
5
configure
vendored
5
configure
vendored
@@ -1448,7 +1448,10 @@ done
|
||||
if test "$stack_protector" != "no" ; then
|
||||
gcc_flags="-fstack-protector-strong -fstack-protector-all"
|
||||
for flag in $gcc_flags; do
|
||||
if compile_prog "-Werror $flag" "" ; then
|
||||
# We need to check both a compile and a link, since some compiler
|
||||
# setups fail only on a .c->.o compile and some only at link time
|
||||
if do_cc $QEMU_CFLAGS -Werror $flag -c -o $TMPO $TMPC &&
|
||||
compile_prog "-Werror $flag" ""; then
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $flag"
|
||||
LIBTOOLFLAGS="$LIBTOOLFLAGS -Wc,$flag"
|
||||
break
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
CONFIG_USB_TABLET_WACOM=y
|
||||
CONFIG_USB_STORAGE_BOT=y
|
||||
CONFIG_USB_STORAGE_UAS=y
|
||||
CONFIG_USB_STORAGE_MTP=y
|
||||
CONFIG_USB_SMARTCARD=y
|
||||
CONFIG_USB_AUDIO=y
|
||||
CONFIG_USB_SERIAL=y
|
||||
|
||||
@@ -1626,6 +1626,26 @@ uint64 float32_to_uint64(float32 a STATUS_PARAM)
|
||||
return roundAndPackUint64(aSign, aSig64, aSigExtra STATUS_VAR);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the single-precision floating-point value
|
||||
| `a' to the 64-bit unsigned integer format. The conversion is
|
||||
| performed according to the IEC/IEEE Standard for Binary Floating-Point
|
||||
| Arithmetic, except that the conversion is always rounded toward zero. If
|
||||
| `a' is a NaN, the largest unsigned integer is returned. Otherwise, if the
|
||||
| conversion overflows, the largest unsigned integer is returned. If the
|
||||
| 'a' is negative, the result is rounded and zero is returned; values that do
|
||||
| not round to zero will raise the inexact flag.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
uint64 float32_to_uint64_round_to_zero(float32 a STATUS_PARAM)
|
||||
{
|
||||
signed char current_rounding_mode = STATUS(float_rounding_mode);
|
||||
set_float_rounding_mode(float_round_to_zero STATUS_VAR);
|
||||
int64_t v = float32_to_uint64(a STATUS_VAR);
|
||||
set_float_rounding_mode(current_rounding_mode STATUS_VAR);
|
||||
return v;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the single-precision floating-point value
|
||||
| `a' to the 64-bit two's complement integer format. The conversion is
|
||||
|
||||
@@ -43,6 +43,19 @@ static void cubieboard_init(QEMUMachineInitArgs *args)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
object_property_set_int(OBJECT(&s->a10->timer), 32768, "clk0-freq", &err);
|
||||
if (err != NULL) {
|
||||
error_report("Couldn't set clk0 frequency: %s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
object_property_set_int(OBJECT(&s->a10->timer), 24000000, "clk1-freq",
|
||||
&err);
|
||||
if (err != NULL) {
|
||||
error_report("Couldn't set clk1 frequency: %s", error_get_pretty(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
object_property_set_bool(OBJECT(s->a10), true, "realized", &err);
|
||||
if (err != NULL) {
|
||||
error_report("Couldn't realize Allwinner A10: %s",
|
||||
|
||||
@@ -225,8 +225,10 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
|
||||
if (s->tsr_retry <= 0) {
|
||||
if (s->fcr & UART_FCR_FE) {
|
||||
s->tsr = fifo8_is_empty(&s->xmit_fifo) ?
|
||||
0 : fifo8_pop(&s->xmit_fifo);
|
||||
if (fifo8_is_empty(&s->xmit_fifo)) {
|
||||
return FALSE;
|
||||
}
|
||||
s->tsr = fifo8_pop(&s->xmit_fifo);
|
||||
if (!s->xmit_fifo.num) {
|
||||
s->lsr |= UART_LSR_THRE;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; under version 2 of the License.
|
||||
* the Free Software Foundation; either version 2 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|
||||
@@ -391,7 +391,7 @@ static void build_append_int(GArray *table, uint32_t value)
|
||||
build_append_byte(table, 0x01); /* OneOp */
|
||||
} else if (value <= 0xFF) {
|
||||
build_append_value(table, value, 1);
|
||||
} else if (value <= 0xFFFFF) {
|
||||
} else if (value <= 0xFFFF) {
|
||||
build_append_value(table, value, 2);
|
||||
} else {
|
||||
build_append_value(table, value, 4);
|
||||
|
||||
@@ -93,7 +93,7 @@ Scope(\_SB) {
|
||||
}
|
||||
|
||||
Device(CPU_HOTPLUG_RESOURCE_DEVICE) {
|
||||
Name(_HID, "ACPI0004")
|
||||
Name(_HID, EisaId("PNP0A06"))
|
||||
|
||||
Name(_CRS, ResourceTemplate() {
|
||||
IO(Decode16, CPU_STATUS_BASE, CPU_STATUS_BASE, 0, CPU_STATUS_LEN)
|
||||
|
||||
@@ -3,12 +3,12 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
||||
0x53,
|
||||
0x44,
|
||||
0x54,
|
||||
0x85,
|
||||
0x80,
|
||||
0x11,
|
||||
0x0,
|
||||
0x0,
|
||||
0x1,
|
||||
0x8b,
|
||||
0x60,
|
||||
0x42,
|
||||
0x58,
|
||||
0x50,
|
||||
@@ -31,8 +31,8 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
||||
0x4e,
|
||||
0x54,
|
||||
0x4c,
|
||||
0x23,
|
||||
0x8,
|
||||
0x15,
|
||||
0x11,
|
||||
0x13,
|
||||
0x20,
|
||||
0x10,
|
||||
@@ -4010,7 +4010,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
||||
0x53,
|
||||
0x1,
|
||||
0x10,
|
||||
0x47,
|
||||
0x42,
|
||||
0x11,
|
||||
0x5f,
|
||||
0x53,
|
||||
@@ -4243,7 +4243,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
||||
0x60,
|
||||
0x5b,
|
||||
0x82,
|
||||
0x2e,
|
||||
0x29,
|
||||
0x50,
|
||||
0x52,
|
||||
0x45,
|
||||
@@ -4253,16 +4253,11 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
||||
0x48,
|
||||
0x49,
|
||||
0x44,
|
||||
0xd,
|
||||
0xc,
|
||||
0x41,
|
||||
0x43,
|
||||
0x50,
|
||||
0x49,
|
||||
0x30,
|
||||
0x30,
|
||||
0x30,
|
||||
0x34,
|
||||
0x0,
|
||||
0xd0,
|
||||
0xa,
|
||||
0x6,
|
||||
0x8,
|
||||
0x5f,
|
||||
0x43,
|
||||
|
||||
@@ -3,12 +3,12 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
||||
0x53,
|
||||
0x44,
|
||||
0x54,
|
||||
0xd7,
|
||||
0xd2,
|
||||
0x1c,
|
||||
0x0,
|
||||
0x0,
|
||||
0x1,
|
||||
0x3e,
|
||||
0x13,
|
||||
0x42,
|
||||
0x58,
|
||||
0x50,
|
||||
@@ -31,8 +31,8 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
||||
0x4e,
|
||||
0x54,
|
||||
0x4c,
|
||||
0x23,
|
||||
0x8,
|
||||
0x15,
|
||||
0x11,
|
||||
0x13,
|
||||
0x20,
|
||||
0x10,
|
||||
@@ -6959,7 +6959,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
||||
0x53,
|
||||
0x1,
|
||||
0x10,
|
||||
0x47,
|
||||
0x42,
|
||||
0x11,
|
||||
0x5f,
|
||||
0x53,
|
||||
@@ -7192,7 +7192,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
||||
0x60,
|
||||
0x5b,
|
||||
0x82,
|
||||
0x2e,
|
||||
0x29,
|
||||
0x50,
|
||||
0x52,
|
||||
0x45,
|
||||
@@ -7202,16 +7202,11 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
||||
0x48,
|
||||
0x49,
|
||||
0x44,
|
||||
0xd,
|
||||
0xc,
|
||||
0x41,
|
||||
0x43,
|
||||
0x50,
|
||||
0x49,
|
||||
0x30,
|
||||
0x30,
|
||||
0x30,
|
||||
0x34,
|
||||
0x0,
|
||||
0xd0,
|
||||
0xa,
|
||||
0x6,
|
||||
0x8,
|
||||
0x5f,
|
||||
0x43,
|
||||
|
||||
@@ -1602,7 +1602,7 @@ static bool cmd_smart(IDEState *s, uint8_t cmd)
|
||||
case 2: /* extended self test */
|
||||
s->smart_selftest_count++;
|
||||
if (s->smart_selftest_count > 21) {
|
||||
s->smart_selftest_count = 0;
|
||||
s->smart_selftest_count = 1;
|
||||
}
|
||||
n = 2 + (s->smart_selftest_count - 1) * 24;
|
||||
s->smart_selftest_data[n] = s->sector;
|
||||
|
||||
@@ -23,11 +23,20 @@
|
||||
static void aw_a10_pic_update(AwA10PICState *s)
|
||||
{
|
||||
uint8_t i;
|
||||
int irq = 0, fiq = 0;
|
||||
int irq = 0, fiq = 0, pending;
|
||||
|
||||
s->vector = 0;
|
||||
|
||||
for (i = 0; i < AW_A10_PIC_REG_NUM; i++) {
|
||||
irq |= s->irq_pending[i] & ~s->mask[i];
|
||||
fiq |= s->select[i] & s->irq_pending[i] & ~s->mask[i];
|
||||
|
||||
if (!s->vector) {
|
||||
pending = ffs(s->irq_pending[i] & ~s->mask[i]);
|
||||
if (pending) {
|
||||
s->vector = (i * 32 + pending - 1) * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qemu_set_irq(s->parent_irq, !!irq);
|
||||
@@ -40,6 +49,8 @@ static void aw_a10_pic_set_irq(void *opaque, int irq, int level)
|
||||
|
||||
if (level) {
|
||||
set_bit(irq % 32, (void *)&s->irq_pending[irq / 32]);
|
||||
} else {
|
||||
clear_bit(irq % 32, (void *)&s->irq_pending[irq / 32]);
|
||||
}
|
||||
aw_a10_pic_update(s);
|
||||
}
|
||||
@@ -84,9 +95,6 @@ static void aw_a10_pic_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
uint8_t index = (offset & 0xc) / 4;
|
||||
|
||||
switch (offset) {
|
||||
case AW_A10_PIC_VECTOR:
|
||||
s->vector = value & ~0x3;
|
||||
break;
|
||||
case AW_A10_PIC_BASE_ADDR:
|
||||
s->base_addr = value & ~0x3;
|
||||
case AW_A10_PIC_PROTECT:
|
||||
@@ -96,7 +104,11 @@ static void aw_a10_pic_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
s->nmi = value;
|
||||
break;
|
||||
case AW_A10_PIC_IRQ_PENDING ... AW_A10_PIC_IRQ_PENDING + 8:
|
||||
s->irq_pending[index] &= ~value;
|
||||
/*
|
||||
* The register is read-only; nevertheless, Linux (including
|
||||
* the version originally shipped by Allwinner) pretends to
|
||||
* write to the register. Just ignore it.
|
||||
*/
|
||||
break;
|
||||
case AW_A10_PIC_FIQ_PENDING ... AW_A10_PIC_FIQ_PENDING + 8:
|
||||
s->fiq_pending[index] &= ~value;
|
||||
|
||||
@@ -19,102 +19,155 @@
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
#ifdef ZYNQ_ARM_SLCR_ERR_DEBUG
|
||||
#define DB_PRINT(...) do { \
|
||||
fprintf(stderr, ": %s: ", __func__); \
|
||||
fprintf(stderr, ## __VA_ARGS__); \
|
||||
} while (0);
|
||||
#else
|
||||
#define DB_PRINT(...)
|
||||
#ifndef ZYNQ_SLCR_ERR_DEBUG
|
||||
#define ZYNQ_SLCR_ERR_DEBUG 0
|
||||
#endif
|
||||
|
||||
#define DB_PRINT(...) do { \
|
||||
if (ZYNQ_SLCR_ERR_DEBUG) { \
|
||||
fprintf(stderr, ": %s: ", __func__); \
|
||||
fprintf(stderr, ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define XILINX_LOCK_KEY 0x767b
|
||||
#define XILINX_UNLOCK_KEY 0xdf0d
|
||||
|
||||
#define R_PSS_RST_CTRL_SOFT_RST 0x1
|
||||
|
||||
typedef enum {
|
||||
ARM_PLL_CTRL,
|
||||
DDR_PLL_CTRL,
|
||||
IO_PLL_CTRL,
|
||||
PLL_STATUS,
|
||||
ARM_PPL_CFG,
|
||||
DDR_PLL_CFG,
|
||||
IO_PLL_CFG,
|
||||
PLL_BG_CTRL,
|
||||
PLL_MAX
|
||||
} PLLValues;
|
||||
enum {
|
||||
SCL = 0x000 / 4,
|
||||
LOCK,
|
||||
UNLOCK,
|
||||
LOCKSTA,
|
||||
|
||||
typedef enum {
|
||||
ARM_CLK_CTRL,
|
||||
DDR_CLK_CTRL,
|
||||
DCI_CLK_CTRL,
|
||||
APER_CLK_CTRL,
|
||||
USB0_CLK_CTRL,
|
||||
USB1_CLK_CTRL,
|
||||
GEM0_RCLK_CTRL,
|
||||
GEM1_RCLK_CTRL,
|
||||
GEM0_CLK_CTRL,
|
||||
GEM1_CLK_CTRL,
|
||||
SMC_CLK_CTRL,
|
||||
LQSPI_CLK_CTRL,
|
||||
SDIO_CLK_CTRL,
|
||||
UART_CLK_CTRL,
|
||||
SPI_CLK_CTRL,
|
||||
CAN_CLK_CTRL,
|
||||
CAN_MIOCLK_CTRL,
|
||||
DBG_CLK_CTRL,
|
||||
PCAP_CLK_CTRL,
|
||||
TOPSW_CLK_CTRL,
|
||||
CLK_MAX
|
||||
} ClkValues;
|
||||
ARM_PLL_CTRL = 0x100 / 4,
|
||||
DDR_PLL_CTRL,
|
||||
IO_PLL_CTRL,
|
||||
PLL_STATUS,
|
||||
ARM_PLL_CFG,
|
||||
DDR_PLL_CFG,
|
||||
IO_PLL_CFG,
|
||||
|
||||
typedef enum {
|
||||
CLK_CTRL,
|
||||
THR_CTRL,
|
||||
THR_CNT,
|
||||
THR_STA,
|
||||
FPGA_MAX
|
||||
} FPGAValues;
|
||||
ARM_CLK_CTRL = 0x120 / 4,
|
||||
DDR_CLK_CTRL,
|
||||
DCI_CLK_CTRL,
|
||||
APER_CLK_CTRL,
|
||||
USB0_CLK_CTRL,
|
||||
USB1_CLK_CTRL,
|
||||
GEM0_RCLK_CTRL,
|
||||
GEM1_RCLK_CTRL,
|
||||
GEM0_CLK_CTRL,
|
||||
GEM1_CLK_CTRL,
|
||||
SMC_CLK_CTRL,
|
||||
LQSPI_CLK_CTRL,
|
||||
SDIO_CLK_CTRL,
|
||||
UART_CLK_CTRL,
|
||||
SPI_CLK_CTRL,
|
||||
CAN_CLK_CTRL,
|
||||
CAN_MIOCLK_CTRL,
|
||||
DBG_CLK_CTRL,
|
||||
PCAP_CLK_CTRL,
|
||||
TOPSW_CLK_CTRL,
|
||||
|
||||
typedef enum {
|
||||
SYNC_CTRL,
|
||||
SYNC_STATUS,
|
||||
BANDGAP_TRIP,
|
||||
CC_TEST,
|
||||
PLL_PREDIVISOR,
|
||||
CLK_621_TRUE,
|
||||
PICTURE_DBG,
|
||||
PICTURE_DBG_UCNT,
|
||||
PICTURE_DBG_LCNT,
|
||||
MISC_MAX
|
||||
} MiscValues;
|
||||
#define FPGA_CTRL_REGS(n, start) \
|
||||
FPGA ## n ## _CLK_CTRL = (start) / 4, \
|
||||
FPGA ## n ## _THR_CTRL, \
|
||||
FPGA ## n ## _THR_CNT, \
|
||||
FPGA ## n ## _THR_STA,
|
||||
FPGA_CTRL_REGS(0, 0x170)
|
||||
FPGA_CTRL_REGS(1, 0x180)
|
||||
FPGA_CTRL_REGS(2, 0x190)
|
||||
FPGA_CTRL_REGS(3, 0x1a0)
|
||||
|
||||
typedef enum {
|
||||
PSS,
|
||||
DDDR,
|
||||
DMAC = 3,
|
||||
USB,
|
||||
GEM,
|
||||
SDIO,
|
||||
SPI,
|
||||
CAN,
|
||||
I2C,
|
||||
UART,
|
||||
GPIO,
|
||||
LQSPI,
|
||||
SMC,
|
||||
OCM,
|
||||
DEVCI,
|
||||
FPGA,
|
||||
A9_CPU,
|
||||
RS_AWDT,
|
||||
RST_REASON,
|
||||
RST_REASON_CLR,
|
||||
REBOOT_STATUS,
|
||||
BOOT_MODE,
|
||||
RESET_MAX
|
||||
} ResetValues;
|
||||
BANDGAP_TRIP = 0x1b8 / 4,
|
||||
PLL_PREDIVISOR = 0x1c0 / 4,
|
||||
CLK_621_TRUE,
|
||||
|
||||
PSS_RST_CTRL = 0x200 / 4,
|
||||
DDR_RST_CTRL,
|
||||
TOPSW_RESET_CTRL,
|
||||
DMAC_RST_CTRL,
|
||||
USB_RST_CTRL,
|
||||
GEM_RST_CTRL,
|
||||
SDIO_RST_CTRL,
|
||||
SPI_RST_CTRL,
|
||||
CAN_RST_CTRL,
|
||||
I2C_RST_CTRL,
|
||||
UART_RST_CTRL,
|
||||
GPIO_RST_CTRL,
|
||||
LQSPI_RST_CTRL,
|
||||
SMC_RST_CTRL,
|
||||
OCM_RST_CTRL,
|
||||
FPGA_RST_CTRL = 0x240 / 4,
|
||||
A9_CPU_RST_CTRL,
|
||||
|
||||
RS_AWDT_CTRL = 0x24c / 4,
|
||||
RST_REASON,
|
||||
|
||||
REBOOT_STATUS = 0x258 / 4,
|
||||
BOOT_MODE,
|
||||
|
||||
APU_CTRL = 0x300 / 4,
|
||||
WDT_CLK_SEL,
|
||||
|
||||
TZ_DMA_NS = 0x440 / 4,
|
||||
TZ_DMA_IRQ_NS,
|
||||
TZ_DMA_PERIPH_NS,
|
||||
|
||||
PSS_IDCODE = 0x530 / 4,
|
||||
|
||||
DDR_URGENT = 0x600 / 4,
|
||||
DDR_CAL_START = 0x60c / 4,
|
||||
DDR_REF_START = 0x614 / 4,
|
||||
DDR_CMD_STA,
|
||||
DDR_URGENT_SEL,
|
||||
DDR_DFI_STATUS,
|
||||
|
||||
MIO = 0x700 / 4,
|
||||
#define MIO_LENGTH 54
|
||||
|
||||
MIO_LOOPBACK = 0x804 / 4,
|
||||
MIO_MST_TRI0,
|
||||
MIO_MST_TRI1,
|
||||
|
||||
SD0_WP_CD_SEL = 0x830 / 4,
|
||||
SD1_WP_CD_SEL,
|
||||
|
||||
LVL_SHFTR_EN = 0x900 / 4,
|
||||
OCM_CFG = 0x910 / 4,
|
||||
|
||||
CPU_RAM = 0xa00 / 4,
|
||||
|
||||
IOU = 0xa30 / 4,
|
||||
|
||||
DMAC_RAM = 0xa50 / 4,
|
||||
|
||||
AFI0 = 0xa60 / 4,
|
||||
AFI1 = AFI0 + 3,
|
||||
AFI2 = AFI1 + 3,
|
||||
AFI3 = AFI2 + 3,
|
||||
#define AFI_LENGTH 3
|
||||
|
||||
OCM = 0xa90 / 4,
|
||||
|
||||
DEVCI_RAM = 0xaa0 / 4,
|
||||
|
||||
CSG_RAM = 0xab0 / 4,
|
||||
|
||||
GPIOB_CTRL = 0xb00 / 4,
|
||||
GPIOB_CFG_CMOS18,
|
||||
GPIOB_CFG_CMOS25,
|
||||
GPIOB_CFG_CMOS33,
|
||||
GPIOB_CFG_HSTL = 0xb14 / 4,
|
||||
GPIOB_DRVR_BIAS_CTRL,
|
||||
|
||||
DDRIOB = 0xb40 / 4,
|
||||
#define DDRIOB_LENGTH 14
|
||||
};
|
||||
|
||||
#define ZYNQ_SLCR_MMIO_SIZE 0x1000
|
||||
#define ZYNQ_SLCR_NUM_REGS (ZYNQ_SLCR_MMIO_SIZE / 4)
|
||||
|
||||
#define TYPE_ZYNQ_SLCR "xilinx,zynq_slcr"
|
||||
#define ZYNQ_SLCR(obj) OBJECT_CHECK(ZynqSLCRState, (obj), TYPE_ZYNQ_SLCR)
|
||||
@@ -124,42 +177,7 @@ typedef struct ZynqSLCRState {
|
||||
|
||||
MemoryRegion iomem;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint16_t scl;
|
||||
uint16_t lockval;
|
||||
uint32_t pll[PLL_MAX]; /* 0x100 - 0x11C */
|
||||
uint32_t clk[CLK_MAX]; /* 0x120 - 0x16C */
|
||||
uint32_t fpga[4][FPGA_MAX]; /* 0x170 - 0x1AC */
|
||||
uint32_t misc[MISC_MAX]; /* 0x1B0 - 0x1D8 */
|
||||
uint32_t reset[RESET_MAX]; /* 0x200 - 0x25C */
|
||||
uint32_t apu_ctrl; /* 0x300 */
|
||||
uint32_t wdt_clk_sel; /* 0x304 */
|
||||
uint32_t tz_ocm[3]; /* 0x400 - 0x408 */
|
||||
uint32_t tz_ddr; /* 0x430 */
|
||||
uint32_t tz_dma[3]; /* 0x440 - 0x448 */
|
||||
uint32_t tz_misc[3]; /* 0x450 - 0x458 */
|
||||
uint32_t tz_fpga[2]; /* 0x484 - 0x488 */
|
||||
uint32_t dbg_ctrl; /* 0x500 */
|
||||
uint32_t pss_idcode; /* 0x530 */
|
||||
uint32_t ddr[8]; /* 0x600 - 0x620 - 0x604-missing */
|
||||
uint32_t mio[54]; /* 0x700 - 0x7D4 */
|
||||
uint32_t mio_func[4]; /* 0x800 - 0x810 */
|
||||
uint32_t sd[2]; /* 0x830 - 0x834 */
|
||||
uint32_t lvl_shftr_en; /* 0x900 */
|
||||
uint32_t ocm_cfg; /* 0x910 */
|
||||
uint32_t cpu_ram[8]; /* 0xA00 - 0xA1C */
|
||||
uint32_t iou[7]; /* 0xA30 - 0xA48 */
|
||||
uint32_t dmac_ram; /* 0xA50 */
|
||||
uint32_t afi[4][3]; /* 0xA60 - 0xA8C */
|
||||
uint32_t ocm[3]; /* 0xA90 - 0xA98 */
|
||||
uint32_t devci_ram; /* 0xAA0 */
|
||||
uint32_t csg_ram; /* 0xAB0 */
|
||||
uint32_t gpiob[12]; /* 0xB00 - 0xB2C */
|
||||
uint32_t ddriob[14]; /* 0xB40 - 0xB74 */
|
||||
};
|
||||
uint8_t data[0x1000];
|
||||
};
|
||||
uint32_t regs[ZYNQ_SLCR_NUM_REGS];
|
||||
} ZynqSLCRState;
|
||||
|
||||
static void zynq_slcr_reset(DeviceState *d)
|
||||
@@ -169,177 +187,169 @@ static void zynq_slcr_reset(DeviceState *d)
|
||||
|
||||
DB_PRINT("RESET\n");
|
||||
|
||||
s->lockval = 1;
|
||||
s->regs[LOCKSTA] = 1;
|
||||
/* 0x100 - 0x11C */
|
||||
s->pll[ARM_PLL_CTRL] = 0x0001A008;
|
||||
s->pll[DDR_PLL_CTRL] = 0x0001A008;
|
||||
s->pll[IO_PLL_CTRL] = 0x0001A008;
|
||||
s->pll[PLL_STATUS] = 0x0000003F;
|
||||
s->pll[ARM_PPL_CFG] = 0x00014000;
|
||||
s->pll[DDR_PLL_CFG] = 0x00014000;
|
||||
s->pll[IO_PLL_CFG] = 0x00014000;
|
||||
s->regs[ARM_PLL_CTRL] = 0x0001A008;
|
||||
s->regs[DDR_PLL_CTRL] = 0x0001A008;
|
||||
s->regs[IO_PLL_CTRL] = 0x0001A008;
|
||||
s->regs[PLL_STATUS] = 0x0000003F;
|
||||
s->regs[ARM_PLL_CFG] = 0x00014000;
|
||||
s->regs[DDR_PLL_CFG] = 0x00014000;
|
||||
s->regs[IO_PLL_CFG] = 0x00014000;
|
||||
|
||||
/* 0x120 - 0x16C */
|
||||
s->clk[ARM_CLK_CTRL] = 0x1F000400;
|
||||
s->clk[DDR_CLK_CTRL] = 0x18400003;
|
||||
s->clk[DCI_CLK_CTRL] = 0x01E03201;
|
||||
s->clk[APER_CLK_CTRL] = 0x01FFCCCD;
|
||||
s->clk[USB0_CLK_CTRL] = s->clk[USB1_CLK_CTRL] = 0x00101941;
|
||||
s->clk[GEM0_RCLK_CTRL] = s->clk[GEM1_RCLK_CTRL] = 0x00000001;
|
||||
s->clk[GEM0_CLK_CTRL] = s->clk[GEM1_CLK_CTRL] = 0x00003C01;
|
||||
s->clk[SMC_CLK_CTRL] = 0x00003C01;
|
||||
s->clk[LQSPI_CLK_CTRL] = 0x00002821;
|
||||
s->clk[SDIO_CLK_CTRL] = 0x00001E03;
|
||||
s->clk[UART_CLK_CTRL] = 0x00003F03;
|
||||
s->clk[SPI_CLK_CTRL] = 0x00003F03;
|
||||
s->clk[CAN_CLK_CTRL] = 0x00501903;
|
||||
s->clk[DBG_CLK_CTRL] = 0x00000F03;
|
||||
s->clk[PCAP_CLK_CTRL] = 0x00000F01;
|
||||
s->regs[ARM_CLK_CTRL] = 0x1F000400;
|
||||
s->regs[DDR_CLK_CTRL] = 0x18400003;
|
||||
s->regs[DCI_CLK_CTRL] = 0x01E03201;
|
||||
s->regs[APER_CLK_CTRL] = 0x01FFCCCD;
|
||||
s->regs[USB0_CLK_CTRL] = s->regs[USB1_CLK_CTRL] = 0x00101941;
|
||||
s->regs[GEM0_RCLK_CTRL] = s->regs[GEM1_RCLK_CTRL] = 0x00000001;
|
||||
s->regs[GEM0_CLK_CTRL] = s->regs[GEM1_CLK_CTRL] = 0x00003C01;
|
||||
s->regs[SMC_CLK_CTRL] = 0x00003C01;
|
||||
s->regs[LQSPI_CLK_CTRL] = 0x00002821;
|
||||
s->regs[SDIO_CLK_CTRL] = 0x00001E03;
|
||||
s->regs[UART_CLK_CTRL] = 0x00003F03;
|
||||
s->regs[SPI_CLK_CTRL] = 0x00003F03;
|
||||
s->regs[CAN_CLK_CTRL] = 0x00501903;
|
||||
s->regs[DBG_CLK_CTRL] = 0x00000F03;
|
||||
s->regs[PCAP_CLK_CTRL] = 0x00000F01;
|
||||
|
||||
/* 0x170 - 0x1AC */
|
||||
s->fpga[0][CLK_CTRL] = s->fpga[1][CLK_CTRL] = s->fpga[2][CLK_CTRL] =
|
||||
s->fpga[3][CLK_CTRL] = 0x00101800;
|
||||
s->fpga[0][THR_STA] = s->fpga[1][THR_STA] = s->fpga[2][THR_STA] =
|
||||
s->fpga[3][THR_STA] = 0x00010000;
|
||||
s->regs[FPGA0_CLK_CTRL] = s->regs[FPGA1_CLK_CTRL] = s->regs[FPGA2_CLK_CTRL]
|
||||
= s->regs[FPGA3_CLK_CTRL] = 0x00101800;
|
||||
s->regs[FPGA0_THR_STA] = s->regs[FPGA1_THR_STA] = s->regs[FPGA2_THR_STA]
|
||||
= s->regs[FPGA3_THR_STA] = 0x00010000;
|
||||
|
||||
/* 0x1B0 - 0x1D8 */
|
||||
s->misc[BANDGAP_TRIP] = 0x0000001F;
|
||||
s->misc[PLL_PREDIVISOR] = 0x00000001;
|
||||
s->misc[CLK_621_TRUE] = 0x00000001;
|
||||
s->regs[BANDGAP_TRIP] = 0x0000001F;
|
||||
s->regs[PLL_PREDIVISOR] = 0x00000001;
|
||||
s->regs[CLK_621_TRUE] = 0x00000001;
|
||||
|
||||
/* 0x200 - 0x25C */
|
||||
s->reset[FPGA] = 0x01F33F0F;
|
||||
s->reset[RST_REASON] = 0x00000040;
|
||||
s->regs[FPGA_RST_CTRL] = 0x01F33F0F;
|
||||
s->regs[RST_REASON] = 0x00000040;
|
||||
|
||||
s->regs[BOOT_MODE] = 0x00000001;
|
||||
|
||||
/* 0x700 - 0x7D4 */
|
||||
for (i = 0; i < 54; i++) {
|
||||
s->mio[i] = 0x00001601;
|
||||
s->regs[MIO + i] = 0x00001601;
|
||||
}
|
||||
for (i = 2; i <= 8; i++) {
|
||||
s->mio[i] = 0x00000601;
|
||||
s->regs[MIO + i] = 0x00000601;
|
||||
}
|
||||
|
||||
/* MIO_MST_TRI0, MIO_MST_TRI1 */
|
||||
s->mio_func[2] = s->mio_func[3] = 0xFFFFFFFF;
|
||||
s->regs[MIO_MST_TRI0] = s->regs[MIO_MST_TRI1] = 0xFFFFFFFF;
|
||||
|
||||
s->cpu_ram[0] = s->cpu_ram[1] = s->cpu_ram[3] =
|
||||
s->cpu_ram[4] = s->cpu_ram[7] = 0x00010101;
|
||||
s->cpu_ram[2] = s->cpu_ram[5] = 0x01010101;
|
||||
s->cpu_ram[6] = 0x00000001;
|
||||
s->regs[CPU_RAM + 0] = s->regs[CPU_RAM + 1] = s->regs[CPU_RAM + 3]
|
||||
= s->regs[CPU_RAM + 4] = s->regs[CPU_RAM + 7]
|
||||
= 0x00010101;
|
||||
s->regs[CPU_RAM + 2] = s->regs[CPU_RAM + 5] = 0x01010101;
|
||||
s->regs[CPU_RAM + 6] = 0x00000001;
|
||||
|
||||
s->iou[0] = s->iou[1] = s->iou[2] = s->iou[3] = 0x09090909;
|
||||
s->iou[4] = s->iou[5] = 0x00090909;
|
||||
s->iou[6] = 0x00000909;
|
||||
s->regs[IOU + 0] = s->regs[IOU + 1] = s->regs[IOU + 2] = s->regs[IOU + 3]
|
||||
= 0x09090909;
|
||||
s->regs[IOU + 4] = s->regs[IOU + 5] = 0x00090909;
|
||||
s->regs[IOU + 6] = 0x00000909;
|
||||
|
||||
s->dmac_ram = 0x00000009;
|
||||
s->regs[DMAC_RAM] = 0x00000009;
|
||||
|
||||
s->afi[0][0] = s->afi[0][1] = 0x09090909;
|
||||
s->afi[1][0] = s->afi[1][1] = 0x09090909;
|
||||
s->afi[2][0] = s->afi[2][1] = 0x09090909;
|
||||
s->afi[3][0] = s->afi[3][1] = 0x09090909;
|
||||
s->afi[0][2] = s->afi[1][2] = s->afi[2][2] = s->afi[3][2] = 0x00000909;
|
||||
s->regs[AFI0 + 0] = s->regs[AFI0 + 1] = 0x09090909;
|
||||
s->regs[AFI1 + 0] = s->regs[AFI1 + 1] = 0x09090909;
|
||||
s->regs[AFI2 + 0] = s->regs[AFI2 + 1] = 0x09090909;
|
||||
s->regs[AFI3 + 0] = s->regs[AFI3 + 1] = 0x09090909;
|
||||
s->regs[AFI0 + 2] = s->regs[AFI1 + 2] = s->regs[AFI2 + 2]
|
||||
= s->regs[AFI3 + 2] = 0x00000909;
|
||||
|
||||
s->ocm[0] = 0x01010101;
|
||||
s->ocm[1] = s->ocm[2] = 0x09090909;
|
||||
s->regs[OCM + 0] = 0x01010101;
|
||||
s->regs[OCM + 1] = s->regs[OCM + 2] = 0x09090909;
|
||||
|
||||
s->devci_ram = 0x00000909;
|
||||
s->csg_ram = 0x00000001;
|
||||
s->regs[DEVCI_RAM] = 0x00000909;
|
||||
s->regs[CSG_RAM] = 0x00000001;
|
||||
|
||||
s->ddriob[0] = s->ddriob[1] = s->ddriob[2] = s->ddriob[3] = 0x00000e00;
|
||||
s->ddriob[4] = s->ddriob[5] = s->ddriob[6] = 0x00000e00;
|
||||
s->ddriob[12] = 0x00000021;
|
||||
s->regs[DDRIOB + 0] = s->regs[DDRIOB + 1] = s->regs[DDRIOB + 2]
|
||||
= s->regs[DDRIOB + 3] = 0x00000e00;
|
||||
s->regs[DDRIOB + 4] = s->regs[DDRIOB + 5] = s->regs[DDRIOB + 6]
|
||||
= 0x00000e00;
|
||||
s->regs[DDRIOB + 12] = 0x00000021;
|
||||
}
|
||||
|
||||
static inline uint32_t zynq_slcr_read_imp(void *opaque,
|
||||
hwaddr offset)
|
||||
{
|
||||
ZynqSLCRState *s = (ZynqSLCRState *)opaque;
|
||||
|
||||
static bool zynq_slcr_check_offset(hwaddr offset, bool rnw)
|
||||
{
|
||||
switch (offset) {
|
||||
case 0x0: /* SCL */
|
||||
return s->scl;
|
||||
case 0x4: /* LOCK */
|
||||
case 0x8: /* UNLOCK */
|
||||
DB_PRINT("Reading SCLR_LOCK/UNLOCK is not enabled\n");
|
||||
return 0;
|
||||
case 0x0C: /* LOCKSTA */
|
||||
return s->lockval;
|
||||
case 0x100 ... 0x11C:
|
||||
return s->pll[(offset - 0x100) / 4];
|
||||
case 0x120 ... 0x16C:
|
||||
return s->clk[(offset - 0x120) / 4];
|
||||
case 0x170 ... 0x1AC:
|
||||
return s->fpga[0][(offset - 0x170) / 4];
|
||||
case 0x1B0 ... 0x1D8:
|
||||
return s->misc[(offset - 0x1B0) / 4];
|
||||
case 0x200 ... 0x258:
|
||||
return s->reset[(offset - 0x200) / 4];
|
||||
case 0x25c:
|
||||
return 1;
|
||||
case 0x300:
|
||||
return s->apu_ctrl;
|
||||
case 0x304:
|
||||
return s->wdt_clk_sel;
|
||||
case 0x400 ... 0x408:
|
||||
return s->tz_ocm[(offset - 0x400) / 4];
|
||||
case 0x430:
|
||||
return s->tz_ddr;
|
||||
case 0x440 ... 0x448:
|
||||
return s->tz_dma[(offset - 0x440) / 4];
|
||||
case 0x450 ... 0x458:
|
||||
return s->tz_misc[(offset - 0x450) / 4];
|
||||
case 0x484 ... 0x488:
|
||||
return s->tz_fpga[(offset - 0x484) / 4];
|
||||
case 0x500:
|
||||
return s->dbg_ctrl;
|
||||
case 0x530:
|
||||
return s->pss_idcode;
|
||||
case 0x600 ... 0x620:
|
||||
if (offset == 0x604) {
|
||||
goto bad_reg;
|
||||
}
|
||||
return s->ddr[(offset - 0x600) / 4];
|
||||
case 0x700 ... 0x7D4:
|
||||
return s->mio[(offset - 0x700) / 4];
|
||||
case 0x800 ... 0x810:
|
||||
return s->mio_func[(offset - 0x800) / 4];
|
||||
case 0x830 ... 0x834:
|
||||
return s->sd[(offset - 0x830) / 4];
|
||||
case 0x900:
|
||||
return s->lvl_shftr_en;
|
||||
case 0x910:
|
||||
return s->ocm_cfg;
|
||||
case 0xA00 ... 0xA1C:
|
||||
return s->cpu_ram[(offset - 0xA00) / 4];
|
||||
case 0xA30 ... 0xA48:
|
||||
return s->iou[(offset - 0xA30) / 4];
|
||||
case 0xA50:
|
||||
return s->dmac_ram;
|
||||
case 0xA60 ... 0xA8C:
|
||||
return s->afi[0][(offset - 0xA60) / 4];
|
||||
case 0xA90 ... 0xA98:
|
||||
return s->ocm[(offset - 0xA90) / 4];
|
||||
case 0xAA0:
|
||||
return s->devci_ram;
|
||||
case 0xAB0:
|
||||
return s->csg_ram;
|
||||
case 0xB00 ... 0xB2C:
|
||||
return s->gpiob[(offset - 0xB00) / 4];
|
||||
case 0xB40 ... 0xB74:
|
||||
return s->ddriob[(offset - 0xB40) / 4];
|
||||
case LOCK:
|
||||
case UNLOCK:
|
||||
case DDR_CAL_START:
|
||||
case DDR_REF_START:
|
||||
return !rnw; /* Write only */
|
||||
case LOCKSTA:
|
||||
case FPGA0_THR_STA:
|
||||
case FPGA1_THR_STA:
|
||||
case FPGA2_THR_STA:
|
||||
case FPGA3_THR_STA:
|
||||
case BOOT_MODE:
|
||||
case PSS_IDCODE:
|
||||
case DDR_CMD_STA:
|
||||
case DDR_DFI_STATUS:
|
||||
case PLL_STATUS:
|
||||
return rnw;/* read only */
|
||||
case SCL:
|
||||
case ARM_PLL_CTRL ... IO_PLL_CTRL:
|
||||
case ARM_PLL_CFG ... IO_PLL_CFG:
|
||||
case ARM_CLK_CTRL ... TOPSW_CLK_CTRL:
|
||||
case FPGA0_CLK_CTRL ... FPGA0_THR_CNT:
|
||||
case FPGA1_CLK_CTRL ... FPGA1_THR_CNT:
|
||||
case FPGA2_CLK_CTRL ... FPGA2_THR_CNT:
|
||||
case FPGA3_CLK_CTRL ... FPGA3_THR_CNT:
|
||||
case BANDGAP_TRIP:
|
||||
case PLL_PREDIVISOR:
|
||||
case CLK_621_TRUE:
|
||||
case PSS_RST_CTRL ... A9_CPU_RST_CTRL:
|
||||
case RS_AWDT_CTRL:
|
||||
case RST_REASON:
|
||||
case REBOOT_STATUS:
|
||||
case APU_CTRL:
|
||||
case WDT_CLK_SEL:
|
||||
case TZ_DMA_NS ... TZ_DMA_PERIPH_NS:
|
||||
case DDR_URGENT:
|
||||
case DDR_URGENT_SEL:
|
||||
case MIO ... MIO + MIO_LENGTH - 1:
|
||||
case MIO_LOOPBACK ... MIO_MST_TRI1:
|
||||
case SD0_WP_CD_SEL:
|
||||
case SD1_WP_CD_SEL:
|
||||
case LVL_SHFTR_EN:
|
||||
case OCM_CFG:
|
||||
case CPU_RAM:
|
||||
case IOU:
|
||||
case DMAC_RAM:
|
||||
case AFI0 ... AFI3 + AFI_LENGTH - 1:
|
||||
case OCM:
|
||||
case DEVCI_RAM:
|
||||
case CSG_RAM:
|
||||
case GPIOB_CTRL ... GPIOB_CFG_CMOS33:
|
||||
case GPIOB_CFG_HSTL:
|
||||
case GPIOB_DRVR_BIAS_CTRL:
|
||||
case DDRIOB ... DDRIOB + DDRIOB_LENGTH - 1:
|
||||
return true;
|
||||
default:
|
||||
bad_reg:
|
||||
DB_PRINT("Bad register offset 0x%x\n", (int)offset);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t zynq_slcr_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
uint32_t ret = zynq_slcr_read_imp(opaque, offset);
|
||||
ZynqSLCRState *s = opaque;
|
||||
offset /= 4;
|
||||
uint32_t ret = s->regs[offset];
|
||||
|
||||
DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret);
|
||||
if (!zynq_slcr_check_offset(offset, true)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid read access to "
|
||||
" addr %" HWADDR_PRIx "\n", offset * 4);
|
||||
}
|
||||
|
||||
DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx32 "\n", offset * 4, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -347,148 +357,55 @@ static void zynq_slcr_write(void *opaque, hwaddr offset,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
ZynqSLCRState *s = (ZynqSLCRState *)opaque;
|
||||
offset /= 4;
|
||||
|
||||
DB_PRINT("offset: %08x data: %08x\n", (unsigned)offset, (unsigned)val);
|
||||
DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx64 "\n", offset * 4, val);
|
||||
|
||||
if (!zynq_slcr_check_offset(offset, false)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "zynq_slcr: Invalid write access to "
|
||||
"addr %" HWADDR_PRIx "\n", offset * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (offset) {
|
||||
case 0x00: /* SCL */
|
||||
s->scl = val & 0x1;
|
||||
return;
|
||||
case 0x4: /* SLCR_LOCK */
|
||||
case SCL:
|
||||
s->regs[SCL] = val & 0x1;
|
||||
return;
|
||||
case LOCK:
|
||||
if ((val & 0xFFFF) == XILINX_LOCK_KEY) {
|
||||
DB_PRINT("XILINX LOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
|
||||
(unsigned)val & 0xFFFF);
|
||||
s->lockval = 1;
|
||||
s->regs[LOCKSTA] = 1;
|
||||
} else {
|
||||
DB_PRINT("WRONG XILINX LOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
|
||||
(int)offset, (unsigned)val & 0xFFFF);
|
||||
}
|
||||
return;
|
||||
case 0x8: /* SLCR_UNLOCK */
|
||||
case UNLOCK:
|
||||
if ((val & 0xFFFF) == XILINX_UNLOCK_KEY) {
|
||||
DB_PRINT("XILINX UNLOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
|
||||
(unsigned)val & 0xFFFF);
|
||||
s->lockval = 0;
|
||||
s->regs[LOCKSTA] = 0;
|
||||
} else {
|
||||
DB_PRINT("WRONG XILINX UNLOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
|
||||
(int)offset, (unsigned)val & 0xFFFF);
|
||||
}
|
||||
return;
|
||||
case 0xc: /* LOCKSTA */
|
||||
DB_PRINT("Writing SCLR_LOCKSTA is not enabled\n");
|
||||
}
|
||||
|
||||
if (!s->regs[LOCKSTA]) {
|
||||
s->regs[offset / 4] = val;
|
||||
} else {
|
||||
DB_PRINT("SCLR registers are locked. Unlock them first\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->lockval) {
|
||||
switch (offset) {
|
||||
case 0x100 ... 0x11C:
|
||||
if (offset == 0x10C) {
|
||||
goto bad_reg;
|
||||
}
|
||||
s->pll[(offset - 0x100) / 4] = val;
|
||||
break;
|
||||
case 0x120 ... 0x16C:
|
||||
s->clk[(offset - 0x120) / 4] = val;
|
||||
break;
|
||||
case 0x170 ... 0x1AC:
|
||||
s->fpga[0][(offset - 0x170) / 4] = val;
|
||||
break;
|
||||
case 0x1B0 ... 0x1D8:
|
||||
s->misc[(offset - 0x1B0) / 4] = val;
|
||||
break;
|
||||
case 0x200 ... 0x25C:
|
||||
if (offset == 0x250) {
|
||||
goto bad_reg;
|
||||
}
|
||||
s->reset[(offset - 0x200) / 4] = val;
|
||||
if (offset == 0x200 && (val & R_PSS_RST_CTRL_SOFT_RST)) {
|
||||
qemu_system_reset_request();
|
||||
}
|
||||
break;
|
||||
case 0x300:
|
||||
s->apu_ctrl = val;
|
||||
break;
|
||||
case 0x304:
|
||||
s->wdt_clk_sel = val;
|
||||
break;
|
||||
case 0x400 ... 0x408:
|
||||
s->tz_ocm[(offset - 0x400) / 4] = val;
|
||||
break;
|
||||
case 0x430:
|
||||
s->tz_ddr = val;
|
||||
break;
|
||||
case 0x440 ... 0x448:
|
||||
s->tz_dma[(offset - 0x440) / 4] = val;
|
||||
break;
|
||||
case 0x450 ... 0x458:
|
||||
s->tz_misc[(offset - 0x450) / 4] = val;
|
||||
break;
|
||||
case 0x484 ... 0x488:
|
||||
s->tz_fpga[(offset - 0x484) / 4] = val;
|
||||
break;
|
||||
case 0x500:
|
||||
s->dbg_ctrl = val;
|
||||
break;
|
||||
case 0x530:
|
||||
s->pss_idcode = val;
|
||||
break;
|
||||
case 0x600 ... 0x620:
|
||||
if (offset == 0x604) {
|
||||
goto bad_reg;
|
||||
}
|
||||
s->ddr[(offset - 0x600) / 4] = val;
|
||||
break;
|
||||
case 0x700 ... 0x7D4:
|
||||
s->mio[(offset - 0x700) / 4] = val;
|
||||
break;
|
||||
case 0x800 ... 0x810:
|
||||
s->mio_func[(offset - 0x800) / 4] = val;
|
||||
break;
|
||||
case 0x830 ... 0x834:
|
||||
s->sd[(offset - 0x830) / 4] = val;
|
||||
break;
|
||||
case 0x900:
|
||||
s->lvl_shftr_en = val;
|
||||
break;
|
||||
case 0x910:
|
||||
break;
|
||||
case 0xA00 ... 0xA1C:
|
||||
s->cpu_ram[(offset - 0xA00) / 4] = val;
|
||||
break;
|
||||
case 0xA30 ... 0xA48:
|
||||
s->iou[(offset - 0xA30) / 4] = val;
|
||||
break;
|
||||
case 0xA50:
|
||||
s->dmac_ram = val;
|
||||
break;
|
||||
case 0xA60 ... 0xA8C:
|
||||
s->afi[0][(offset - 0xA60) / 4] = val;
|
||||
break;
|
||||
case 0xA90:
|
||||
s->ocm[0] = val;
|
||||
break;
|
||||
case 0xAA0:
|
||||
s->devci_ram = val;
|
||||
break;
|
||||
case 0xAB0:
|
||||
s->csg_ram = val;
|
||||
break;
|
||||
case 0xB00 ... 0xB2C:
|
||||
if (offset == 0xB20 || offset == 0xB2C) {
|
||||
goto bad_reg;
|
||||
}
|
||||
s->gpiob[(offset - 0xB00) / 4] = val;
|
||||
break;
|
||||
case 0xB40 ... 0xB74:
|
||||
s->ddriob[(offset - 0xB40) / 4] = val;
|
||||
break;
|
||||
default:
|
||||
bad_reg:
|
||||
DB_PRINT("Bad register write %x <= %08x\n", (int)offset,
|
||||
(unsigned)val);
|
||||
switch (offset) {
|
||||
case PSS_RST_CTRL:
|
||||
if (val & R_PSS_RST_CTRL_SOFT_RST) {
|
||||
qemu_system_reset_request();
|
||||
}
|
||||
} else {
|
||||
DB_PRINT("SCLR registers are locked. Unlock them first\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,23 +415,22 @@ static const MemoryRegionOps slcr_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int zynq_slcr_init(SysBusDevice *dev)
|
||||
static void zynq_slcr_init(Object *obj)
|
||||
{
|
||||
ZynqSLCRState *s = ZYNQ_SLCR(dev);
|
||||
ZynqSLCRState *s = ZYNQ_SLCR(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &slcr_ops, s, "slcr", 0x1000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
return 0;
|
||||
memory_region_init_io(&s->iomem, obj, &slcr_ops, s, "slcr",
|
||||
ZYNQ_SLCR_MMIO_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_zynq_slcr = {
|
||||
.name = "zynq_slcr",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.minimum_version_id_old = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8_ARRAY(data, ZynqSLCRState, 0x1000),
|
||||
VMSTATE_UINT32_ARRAY(regs, ZynqSLCRState, ZYNQ_SLCR_NUM_REGS),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
@@ -522,9 +438,7 @@ static const VMStateDescription vmstate_zynq_slcr = {
|
||||
static void zynq_slcr_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
sdc->init = zynq_slcr_init;
|
||||
dc->vmsd = &vmstate_zynq_slcr;
|
||||
dc->reset = zynq_slcr_reset;
|
||||
}
|
||||
@@ -534,6 +448,7 @@ static const TypeInfo zynq_slcr_info = {
|
||||
.name = TYPE_ZYNQ_SLCR,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(ZynqSLCRState),
|
||||
.instance_init = zynq_slcr_init,
|
||||
};
|
||||
|
||||
static void zynq_slcr_register_types(void)
|
||||
|
||||
@@ -27,11 +27,11 @@ static uint8_t padding[60];
|
||||
static void mii_set_link(RTL8201CPState *mii, bool link_ok)
|
||||
{
|
||||
if (link_ok) {
|
||||
mii->bmsr |= MII_BMSR_LINK_ST;
|
||||
mii->bmsr |= MII_BMSR_LINK_ST | MII_BMSR_AN_COMP;
|
||||
mii->anlpar |= MII_ANAR_TXFD | MII_ANAR_10FD | MII_ANAR_10 |
|
||||
MII_ANAR_CSMACD;
|
||||
} else {
|
||||
mii->bmsr &= ~MII_BMSR_LINK_ST;
|
||||
mii->bmsr &= ~(MII_BMSR_LINK_ST | MII_BMSR_AN_COMP);
|
||||
mii->anlpar = MII_ANAR_TX;
|
||||
}
|
||||
}
|
||||
@@ -391,9 +391,11 @@ static void aw_emac_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
break;
|
||||
case EMAC_INT_CTL_REG:
|
||||
s->int_ctl = value;
|
||||
aw_emac_update_irq(s);
|
||||
break;
|
||||
case EMAC_INT_STA_REG:
|
||||
s->int_sta &= ~value;
|
||||
aw_emac_update_irq(s);
|
||||
break;
|
||||
case EMAC_MAC_MADR_REG:
|
||||
s->phy_target = value;
|
||||
|
||||
@@ -1093,7 +1093,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
|
||||
uint32_t phy_addr, reg_num;
|
||||
|
||||
phy_addr = (retval & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
|
||||
if (phy_addr == BOARD_PHY_ADDRESS) {
|
||||
if (phy_addr == BOARD_PHY_ADDRESS || phy_addr == 0) {
|
||||
reg_num = (retval & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
|
||||
retval &= 0xFFFF0000;
|
||||
retval |= gem_phy_read(s, reg_num);
|
||||
@@ -1193,7 +1193,7 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
||||
uint32_t phy_addr, reg_num;
|
||||
|
||||
phy_addr = (val & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
|
||||
if (phy_addr == BOARD_PHY_ADDRESS) {
|
||||
if (phy_addr == BOARD_PHY_ADDRESS || phy_addr == 0) {
|
||||
reg_num = (val & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
|
||||
gem_phy_write(s, reg_num, val);
|
||||
}
|
||||
|
||||
@@ -677,7 +677,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
|
||||
if (mac_data.entries <= MAC_TABLE_ENTRIES - in_use) {
|
||||
s = iov_to_buf(iov, iov_cnt, 0, &macs[in_use * ETH_ALEN],
|
||||
mac_data.entries * ETH_ALEN);
|
||||
if (s != mac_data.entries * ETH_ALEN) {
|
||||
|
||||
@@ -52,6 +52,9 @@
|
||||
#define VMXNET3_DEVICE_VERSION 0x1
|
||||
#define VMXNET3_DEVICE_REVISION 0x1
|
||||
|
||||
/* Number of interrupt vectors for non-MSIx modes */
|
||||
#define VMXNET3_MAX_NMSIX_INTRS (1)
|
||||
|
||||
/* Macros for rings descriptors access */
|
||||
#define VMXNET3_READ_TX_QUEUE_DESCR8(dpa, field) \
|
||||
(vmw_shmem_ld8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
|
||||
@@ -1305,6 +1308,51 @@ static bool vmxnet3_verify_intx(VMXNET3State *s, int intx)
|
||||
(pci_get_byte(s->parent_obj.config + PCI_INTERRUPT_PIN) - 1));
|
||||
}
|
||||
|
||||
static void vmxnet3_validate_interrupt_idx(bool is_msix, int idx)
|
||||
{
|
||||
int max_ints = is_msix ? VMXNET3_MAX_INTRS : VMXNET3_MAX_NMSIX_INTRS;
|
||||
if (idx >= max_ints) {
|
||||
hw_error("Bad interrupt index: %d\n", idx);
|
||||
}
|
||||
}
|
||||
|
||||
static void vmxnet3_validate_interrupts(VMXNET3State *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
VMW_CFPRN("Verifying event interrupt index (%d)", s->event_int_idx);
|
||||
vmxnet3_validate_interrupt_idx(s->msix_used, s->event_int_idx);
|
||||
|
||||
for (i = 0; i < s->txq_num; i++) {
|
||||
int idx = s->txq_descr[i].intr_idx;
|
||||
VMW_CFPRN("Verifying TX queue %d interrupt index (%d)", i, idx);
|
||||
vmxnet3_validate_interrupt_idx(s->msix_used, idx);
|
||||
}
|
||||
|
||||
for (i = 0; i < s->rxq_num; i++) {
|
||||
int idx = s->rxq_descr[i].intr_idx;
|
||||
VMW_CFPRN("Verifying RX queue %d interrupt index (%d)", i, idx);
|
||||
vmxnet3_validate_interrupt_idx(s->msix_used, idx);
|
||||
}
|
||||
}
|
||||
|
||||
static void vmxnet3_validate_queues(VMXNET3State *s)
|
||||
{
|
||||
/*
|
||||
* txq_num and rxq_num are total number of queues
|
||||
* configured by guest. These numbers must not
|
||||
* exceed corresponding maximal values.
|
||||
*/
|
||||
|
||||
if (s->txq_num > VMXNET3_DEVICE_MAX_TX_QUEUES) {
|
||||
hw_error("Bad TX queues number: %d\n", s->txq_num);
|
||||
}
|
||||
|
||||
if (s->rxq_num > VMXNET3_DEVICE_MAX_RX_QUEUES) {
|
||||
hw_error("Bad RX queues number: %d\n", s->rxq_num);
|
||||
}
|
||||
}
|
||||
|
||||
static void vmxnet3_activate_device(VMXNET3State *s)
|
||||
{
|
||||
int i;
|
||||
@@ -1351,7 +1399,7 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
||||
VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.misc.numRxQueues);
|
||||
|
||||
VMW_CFPRN("Number of TX/RX queues %u/%u", s->txq_num, s->rxq_num);
|
||||
assert(s->txq_num <= VMXNET3_DEVICE_MAX_TX_QUEUES);
|
||||
vmxnet3_validate_queues(s);
|
||||
|
||||
qdescr_table_pa =
|
||||
VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.misc.queueDescPA);
|
||||
@@ -1447,6 +1495,8 @@ static void vmxnet3_activate_device(VMXNET3State *s)
|
||||
sizeof(s->rxq_descr[i].rxq_stats));
|
||||
}
|
||||
|
||||
vmxnet3_validate_interrupts(s);
|
||||
|
||||
/* Make sure everything is in place before device activation */
|
||||
smp_wmb();
|
||||
|
||||
@@ -2005,7 +2055,6 @@ vmxnet3_cleanup_msix(VMXNET3State *s)
|
||||
}
|
||||
}
|
||||
|
||||
#define VMXNET3_MSI_NUM_VECTORS (1)
|
||||
#define VMXNET3_MSI_OFFSET (0x50)
|
||||
#define VMXNET3_USE_64BIT (true)
|
||||
#define VMXNET3_PER_VECTOR_MASK (false)
|
||||
@@ -2016,7 +2065,7 @@ vmxnet3_init_msi(VMXNET3State *s)
|
||||
PCIDevice *d = PCI_DEVICE(s);
|
||||
int res;
|
||||
|
||||
res = msi_init(d, VMXNET3_MSI_OFFSET, VMXNET3_MSI_NUM_VECTORS,
|
||||
res = msi_init(d, VMXNET3_MSI_OFFSET, VMXNET3_MAX_NMSIX_INTRS,
|
||||
VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK);
|
||||
if (0 > res) {
|
||||
VMW_WRPRN("Failed to initialize MSI, error %d", res);
|
||||
@@ -2342,6 +2391,9 @@ static int vmxnet3_post_load(void *opaque, int version_id)
|
||||
}
|
||||
}
|
||||
|
||||
vmxnet3_validate_queues(s);
|
||||
vmxnet3_validate_interrupts(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -145,9 +145,9 @@ static uint64_t raven_io_read(void *opaque, hwaddr addr,
|
||||
if (size == 1) {
|
||||
return buf[0];
|
||||
} else if (size == 2) {
|
||||
return lduw_p(buf);
|
||||
return lduw_le_p(buf);
|
||||
} else if (size == 4) {
|
||||
return ldl_p(buf);
|
||||
return ldl_le_p(buf);
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
@@ -164,9 +164,9 @@ static void raven_io_write(void *opaque, hwaddr addr,
|
||||
if (size == 1) {
|
||||
buf[0] = val;
|
||||
} else if (size == 2) {
|
||||
stw_p(buf, val);
|
||||
stw_le_p(buf, val);
|
||||
} else if (size == 4) {
|
||||
stl_p(buf, val);
|
||||
stl_le_p(buf, val);
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
@@ -649,7 +649,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
|
||||
input = (qemu_irq *)env->irq_inputs;
|
||||
irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
|
||||
irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
|
||||
env->spr[SPR_BOOKE_PIR] = cs->cpu_index = i;
|
||||
env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
|
||||
env->mpic_iack = MPC8544_CCSRBAR_BASE +
|
||||
MPC8544_MPIC_REGS_OFFSET + 0xa0;
|
||||
|
||||
|
||||
92
hw/ppc/ppc.c
92
hw/ppc/ppc.c
@@ -620,6 +620,13 @@ static void cpu_ppc_tb_start (CPUPPCState *env)
|
||||
}
|
||||
}
|
||||
|
||||
bool ppc_decr_clear_on_delivery(CPUPPCState *env)
|
||||
{
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL;
|
||||
return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
|
||||
}
|
||||
|
||||
static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
|
||||
{
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
@@ -677,6 +684,11 @@ static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu)
|
||||
ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
|
||||
}
|
||||
|
||||
static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu)
|
||||
{
|
||||
ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
|
||||
}
|
||||
|
||||
static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
|
||||
{
|
||||
/* Raise it */
|
||||
@@ -684,11 +696,16 @@ static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
|
||||
ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
|
||||
}
|
||||
|
||||
static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu)
|
||||
{
|
||||
ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
|
||||
}
|
||||
|
||||
static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
|
||||
QEMUTimer *timer,
|
||||
void (*raise_excp)(PowerPCCPU *),
|
||||
uint32_t decr, uint32_t value,
|
||||
int is_excp)
|
||||
void (*raise_excp)(void *),
|
||||
void (*lower_excp)(PowerPCCPU *),
|
||||
uint32_t decr, uint32_t value)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
ppc_tb_t *tb_env = env->tb_env;
|
||||
@@ -702,59 +719,74 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC
|
||||
* interrupt.
|
||||
*
|
||||
* If we get a really small DEC value, we can assume that by the time we
|
||||
* handled it we should inject an interrupt already.
|
||||
*
|
||||
* On MSB level based DEC implementations the MSB always means the interrupt
|
||||
* is pending, so raise it on those.
|
||||
*
|
||||
* On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
|
||||
* an edge interrupt, so raise it here too.
|
||||
*/
|
||||
if ((value < 3) ||
|
||||
((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && (value & 0x80000000)) ||
|
||||
((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && (value & 0x80000000)
|
||||
&& !(decr & 0x80000000))) {
|
||||
(*raise_excp)(cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
/* On MSB level based systems a 0 for the MSB stops interrupt delivery */
|
||||
if (!(value & 0x80000000) && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
|
||||
(*lower_excp)(cpu);
|
||||
}
|
||||
|
||||
/* Calculate the next timer event */
|
||||
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
|
||||
if (is_excp) {
|
||||
next += *nextp - now;
|
||||
}
|
||||
if (next == now) {
|
||||
next++;
|
||||
}
|
||||
*nextp = next;
|
||||
|
||||
/* Adjust timer */
|
||||
timer_mod(timer, next);
|
||||
|
||||
/* If we set a negative value and the decrementer was positive, raise an
|
||||
* exception.
|
||||
*/
|
||||
if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED)
|
||||
&& (value & 0x80000000)
|
||||
&& !(decr & 0x80000000)) {
|
||||
(*raise_excp)(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr,
|
||||
uint32_t value, int is_excp)
|
||||
uint32_t value)
|
||||
{
|
||||
ppc_tb_t *tb_env = cpu->env.tb_env;
|
||||
|
||||
__cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
|
||||
&cpu_ppc_decr_excp, decr, value, is_excp);
|
||||
tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr,
|
||||
value);
|
||||
}
|
||||
|
||||
void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value)
|
||||
{
|
||||
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
||||
|
||||
_cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, 0);
|
||||
_cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value);
|
||||
}
|
||||
|
||||
static void cpu_ppc_decr_cb(void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu = opaque;
|
||||
|
||||
_cpu_ppc_store_decr(cpu, 0x00000000, 0xFFFFFFFF, 1);
|
||||
cpu_ppc_decr_excp(cpu);
|
||||
}
|
||||
|
||||
static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr,
|
||||
uint32_t value, int is_excp)
|
||||
uint32_t value)
|
||||
{
|
||||
ppc_tb_t *tb_env = cpu->env.tb_env;
|
||||
|
||||
if (tb_env->hdecr_timer != NULL) {
|
||||
__cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
|
||||
&cpu_ppc_hdecr_excp, hdecr, value, is_excp);
|
||||
tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
|
||||
hdecr, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -762,14 +794,14 @@ void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value)
|
||||
{
|
||||
PowerPCCPU *cpu = ppc_env_get_cpu(env);
|
||||
|
||||
_cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 0);
|
||||
_cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value);
|
||||
}
|
||||
|
||||
static void cpu_ppc_hdecr_cb(void *opaque)
|
||||
{
|
||||
PowerPCCPU *cpu = opaque;
|
||||
|
||||
_cpu_ppc_store_hdecr(cpu, 0x00000000, 0xFFFFFFFF, 1);
|
||||
cpu_ppc_hdecr_excp(cpu);
|
||||
}
|
||||
|
||||
static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value)
|
||||
@@ -792,8 +824,8 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
|
||||
* if a decrementer exception is pending when it enables msr_ee at startup,
|
||||
* it's not ready to handle it...
|
||||
*/
|
||||
_cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0);
|
||||
_cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0);
|
||||
_cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||
_cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||
cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
|
||||
}
|
||||
|
||||
@@ -806,6 +838,10 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
|
||||
tb_env = g_malloc0(sizeof(ppc_tb_t));
|
||||
env->tb_env = tb_env;
|
||||
tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
|
||||
if (env->insns_flags & PPC_SEGMENT_64B) {
|
||||
/* All Book3S 64bit CPUs implement level based DEC logic */
|
||||
tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
|
||||
}
|
||||
/* Create new timer */
|
||||
tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu);
|
||||
if (0) {
|
||||
|
||||
@@ -65,9 +65,9 @@ static void spin_reset(void *opaque)
|
||||
for (i = 0; i < MAX_CPUS; i++) {
|
||||
SpinInfo *info = &s->spin[i];
|
||||
|
||||
info->pir = i;
|
||||
info->r3 = i;
|
||||
info->addr = 1;
|
||||
stl_p(&info->pir, i);
|
||||
stq_p(&info->r3, i);
|
||||
stq_p(&info->addr, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,15 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/timer/allwinner-a10-pit.h"
|
||||
|
||||
static void a10_pit_update_irq(AwA10PITState *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
|
||||
qemu_set_irq(s->irq[i], !!(s->irq_status & s->irq_enable & (1 << i)));
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t a10_pit_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
AwA10PITState *s = AW_A10_PIT(opaque);
|
||||
@@ -65,6 +74,22 @@ static uint64_t a10_pit_read(void *opaque, hwaddr offset, unsigned size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void a10_pit_set_freq(AwA10PITState *s, int index)
|
||||
{
|
||||
uint32_t prescaler, source, source_freq;
|
||||
|
||||
prescaler = 1 << extract32(s->control[index], 4, 3);
|
||||
source = extract32(s->control[index], 2, 2);
|
||||
source_freq = s->clk_freq[source];
|
||||
|
||||
if (source_freq) {
|
||||
ptimer_set_freq(s->timer[index], source_freq / prescaler);
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid clock source %u\n",
|
||||
__func__, source);
|
||||
}
|
||||
}
|
||||
|
||||
static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
@@ -74,9 +99,11 @@ static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
switch (offset) {
|
||||
case AW_A10_PIT_TIMER_IRQ_EN:
|
||||
s->irq_enable = value;
|
||||
a10_pit_update_irq(s);
|
||||
break;
|
||||
case AW_A10_PIT_TIMER_IRQ_ST:
|
||||
s->irq_status &= ~value;
|
||||
a10_pit_update_irq(s);
|
||||
break;
|
||||
case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE_END:
|
||||
index = offset & 0xf0;
|
||||
@@ -85,6 +112,7 @@ static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
switch (offset & 0x0f) {
|
||||
case AW_A10_PIT_TIMER_CONTROL:
|
||||
s->control[index] = value;
|
||||
a10_pit_set_freq(s, index);
|
||||
if (s->control[index] & AW_A10_PIT_TIMER_RELOAD) {
|
||||
ptimer_set_count(s->timer[index], s->interval[index]);
|
||||
}
|
||||
@@ -150,6 +178,14 @@ static const MemoryRegionOps a10_pit_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static Property a10_pit_properties[] = {
|
||||
DEFINE_PROP_UINT32("clk0-freq", AwA10PITState, clk_freq[0], 0),
|
||||
DEFINE_PROP_UINT32("clk1-freq", AwA10PITState, clk_freq[1], 0),
|
||||
DEFINE_PROP_UINT32("clk2-freq", AwA10PITState, clk_freq[2], 0),
|
||||
DEFINE_PROP_UINT32("clk3-freq", AwA10PITState, clk_freq[3], 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_a10_pit = {
|
||||
.name = "a10.pit",
|
||||
.version_id = 1,
|
||||
@@ -178,11 +214,14 @@ static void a10_pit_reset(DeviceState *dev)
|
||||
|
||||
s->irq_enable = 0;
|
||||
s->irq_status = 0;
|
||||
a10_pit_update_irq(s);
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
s->control[i] = AW_A10_PIT_DEFAULT_CLOCK;
|
||||
s->interval[i] = 0;
|
||||
s->count[i] = 0;
|
||||
ptimer_stop(s->timer[i]);
|
||||
a10_pit_set_freq(s, i);
|
||||
}
|
||||
s->watch_dog_mode = 0;
|
||||
s->watch_dog_control = 0;
|
||||
@@ -193,18 +232,17 @@ static void a10_pit_reset(DeviceState *dev)
|
||||
|
||||
static void a10_pit_timer_cb(void *opaque)
|
||||
{
|
||||
AwA10PITState *s = AW_A10_PIT(opaque);
|
||||
uint8_t i;
|
||||
AwA10TimerContext *tc = opaque;
|
||||
AwA10PITState *s = tc->container;
|
||||
uint8_t i = tc->index;
|
||||
|
||||
for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
|
||||
if (s->control[i] & AW_A10_PIT_TIMER_EN) {
|
||||
s->irq_status |= 1 << i;
|
||||
if (s->control[i] & AW_A10_PIT_TIMER_MODE) {
|
||||
ptimer_stop(s->timer[i]);
|
||||
s->control[i] &= ~AW_A10_PIT_TIMER_EN;
|
||||
}
|
||||
qemu_irq_pulse(s->irq[i]);
|
||||
if (s->control[i] & AW_A10_PIT_TIMER_EN) {
|
||||
s->irq_status |= 1 << i;
|
||||
if (s->control[i] & AW_A10_PIT_TIMER_MODE) {
|
||||
ptimer_stop(s->timer[i]);
|
||||
s->control[i] &= ~AW_A10_PIT_TIMER_EN;
|
||||
}
|
||||
a10_pit_update_irq(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,9 +261,12 @@ static void a10_pit_init(Object *obj)
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
|
||||
bh[i] = qemu_bh_new(a10_pit_timer_cb, s);
|
||||
AwA10TimerContext *tc = &s->timer_context[i];
|
||||
|
||||
tc->container = s;
|
||||
tc->index = i;
|
||||
bh[i] = qemu_bh_new(a10_pit_timer_cb, tc);
|
||||
s->timer[i] = ptimer_init(bh[i]);
|
||||
ptimer_set_freq(s->timer[i], 240000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,6 +275,7 @@ static void a10_pit_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = a10_pit_reset;
|
||||
dc->props = a10_pit_properties;
|
||||
dc->desc = "allwinner a10 timer";
|
||||
dc->vmsd = &vmstate_a10_pit;
|
||||
}
|
||||
|
||||
@@ -346,11 +346,13 @@ static void cadence_ttc_write(void *opaque, hwaddr offset,
|
||||
case 0x34:
|
||||
case 0x38:
|
||||
s->reg_match[0] = value & 0xffff;
|
||||
break;
|
||||
|
||||
case 0x3c: /* match register */
|
||||
case 0x40:
|
||||
case 0x44:
|
||||
s->reg_match[1] = value & 0xffff;
|
||||
break;
|
||||
|
||||
case 0x48: /* match register */
|
||||
case 0x4c:
|
||||
|
||||
@@ -26,6 +26,10 @@ common-obj-y += ccid-card-passthru.o
|
||||
common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_POSIX),y)
|
||||
common-obj-$(CONFIG_USB_STORAGE_MTP) += dev-mtp.o
|
||||
endif
|
||||
|
||||
# usb redirection
|
||||
common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ typedef struct msos_compat_hdr {
|
||||
typedef struct msos_compat_func {
|
||||
uint8_t bFirstInterfaceNumber;
|
||||
uint8_t reserved_1;
|
||||
uint8_t compatibleId[8];
|
||||
char compatibleId[8];
|
||||
uint8_t subCompatibleId[8];
|
||||
uint8_t reserved_2[6];
|
||||
} QEMU_PACKED msos_compat_func;
|
||||
@@ -59,6 +59,10 @@ static int usb_desc_msos_compat(const USBDesc *desc, uint8_t *dest)
|
||||
func = (void *)(dest + length);
|
||||
func->bFirstInterfaceNumber = 0;
|
||||
func->reserved_1 = 0x01;
|
||||
if (desc->msos->CompatibleID) {
|
||||
snprintf(func->compatibleId, sizeof(func->compatibleId),
|
||||
"%s", desc->msos->CompatibleID);
|
||||
}
|
||||
length += sizeof(*func);
|
||||
count++;
|
||||
|
||||
|
||||
@@ -184,6 +184,7 @@ struct USBDescOther {
|
||||
};
|
||||
|
||||
struct USBDescMSOS {
|
||||
const char *CompatibleID;
|
||||
const wchar_t *Label;
|
||||
bool SelectiveSuspendEnabled;
|
||||
};
|
||||
|
||||
1103
hw/usb/dev-mtp.c
Normal file
1103
hw/usb/dev-mtp.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -162,3 +162,55 @@
|
||||
#define stw(p, v) stw_data(p, v)
|
||||
#define stl(p, v) stl_data(p, v)
|
||||
#define stq(p, v) stq_data(p, v)
|
||||
|
||||
/**
|
||||
* tlb_vaddr_to_host:
|
||||
* @env: CPUArchState
|
||||
* @addr: guest virtual address to look up
|
||||
* @access_type: 0 for read, 1 for write, 2 for execute
|
||||
* @mmu_idx: MMU index to use for lookup
|
||||
*
|
||||
* Look up the specified guest virtual index in the TCG softmmu TLB.
|
||||
* If the TLB contains a host virtual address suitable for direct RAM
|
||||
* access, then return it. Otherwise (TLB miss, TLB entry is for an
|
||||
* I/O access, etc) return NULL.
|
||||
*
|
||||
* This is the equivalent of the initial fast-path code used by
|
||||
* TCG backends for guest load and store accesses.
|
||||
*/
|
||||
static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
|
||||
int access_type, int mmu_idx)
|
||||
{
|
||||
int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
CPUTLBEntry *tlbentry = &env->tlb_table[mmu_idx][index];
|
||||
target_ulong tlb_addr;
|
||||
uintptr_t haddr;
|
||||
|
||||
switch (access_type) {
|
||||
case 0:
|
||||
tlb_addr = tlbentry->addr_read;
|
||||
break;
|
||||
case 1:
|
||||
tlb_addr = tlbentry->addr_write;
|
||||
break;
|
||||
case 2:
|
||||
tlb_addr = tlbentry->addr_code;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if ((addr & TARGET_PAGE_MASK)
|
||||
!= (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
/* TLB entry is for a different page */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tlb_addr & ~TARGET_PAGE_MASK) {
|
||||
/* IO access */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
haddr = addr + env->tlb_table[mmu_idx][index].addend;
|
||||
return (void *)haddr;
|
||||
}
|
||||
|
||||
@@ -342,6 +342,7 @@ uint32 float32_to_uint32( float32 STATUS_PARAM );
|
||||
uint32 float32_to_uint32_round_to_zero( float32 STATUS_PARAM );
|
||||
int64 float32_to_int64( float32 STATUS_PARAM );
|
||||
uint64 float32_to_uint64(float32 STATUS_PARAM);
|
||||
uint64 float32_to_uint64_round_to_zero(float32 STATUS_PARAM);
|
||||
int64 float32_to_int64_round_to_zero( float32 STATUS_PARAM );
|
||||
float64 float32_to_float64( float32 STATUS_PARAM );
|
||||
floatx80 float32_to_floatx80( float32 STATUS_PARAM );
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; under version 2 of the License.
|
||||
* the Free Software Foundation; either version 2 of the License,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|
||||
@@ -144,6 +144,7 @@
|
||||
#define MII_BMSR_10T_FD (1 << 12)
|
||||
#define MII_BMSR_10T_HD (1 << 11)
|
||||
#define MII_BMSR_MFPS (1 << 6)
|
||||
#define MII_BMSR_AN_COMP (1 << 5)
|
||||
#define MII_BMSR_AUTONEG (1 << 3)
|
||||
#define MII_BMSR_LINK_ST (1 << 2)
|
||||
|
||||
|
||||
@@ -44,6 +44,9 @@ struct ppc_tb_t {
|
||||
#define PPC_DECR_ZERO_TRIGGERED (1 << 3) /* Decr interrupt triggered when
|
||||
* the decrementer reaches zero.
|
||||
*/
|
||||
#define PPC_DECR_UNDERFLOW_LEVEL (1 << 4) /* Decr interrupt active when
|
||||
* the most significant bit is 1.
|
||||
*/
|
||||
|
||||
uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
|
||||
clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq);
|
||||
|
||||
@@ -35,13 +35,22 @@
|
||||
|
||||
#define AW_A10_PIT_DEFAULT_CLOCK 0x4
|
||||
|
||||
typedef struct AwA10PITState {
|
||||
typedef struct AwA10PITState AwA10PITState;
|
||||
|
||||
typedef struct AwA10TimerContext {
|
||||
AwA10PITState *container;
|
||||
int index;
|
||||
} AwA10TimerContext;
|
||||
|
||||
struct AwA10PITState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
qemu_irq irq[AW_A10_PIT_TIMER_NR];
|
||||
ptimer_state * timer[AW_A10_PIT_TIMER_NR];
|
||||
AwA10TimerContext timer_context[AW_A10_PIT_TIMER_NR];
|
||||
MemoryRegion iomem;
|
||||
uint32_t clk_freq[4];
|
||||
|
||||
uint32_t irq_enable;
|
||||
uint32_t irq_status;
|
||||
@@ -53,6 +62,6 @@ typedef struct AwA10PITState {
|
||||
uint32_t count_lo;
|
||||
uint32_t count_hi;
|
||||
uint32_t count_ctl;
|
||||
} AwA10PITState;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -441,7 +441,7 @@ static int kvm_physical_sync_dirty_bitmap(MemoryRegionSection *section)
|
||||
|
||||
d.slot = mem->slot;
|
||||
|
||||
if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) < 0) {
|
||||
if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) {
|
||||
DPRINTF("ioctl failed %d\n", errno);
|
||||
ret = -1;
|
||||
break;
|
||||
|
||||
@@ -483,17 +483,17 @@ static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
|
||||
addr = env->regs[2];
|
||||
|
||||
if (get_user_u64(oldval, env->regs[0])) {
|
||||
env->cp15.c6_data = env->regs[0];
|
||||
env->exception.vaddress = env->regs[0];
|
||||
goto segv;
|
||||
};
|
||||
|
||||
if (get_user_u64(newval, env->regs[1])) {
|
||||
env->cp15.c6_data = env->regs[1];
|
||||
env->exception.vaddress = env->regs[1];
|
||||
goto segv;
|
||||
};
|
||||
|
||||
if (get_user_u64(val, addr)) {
|
||||
env->cp15.c6_data = addr;
|
||||
env->exception.vaddress = addr;
|
||||
goto segv;
|
||||
}
|
||||
|
||||
@@ -501,7 +501,7 @@ static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
|
||||
val = newval;
|
||||
|
||||
if (put_user_u64(val, addr)) {
|
||||
env->cp15.c6_data = addr;
|
||||
env->exception.vaddress = addr;
|
||||
goto segv;
|
||||
};
|
||||
|
||||
@@ -523,7 +523,7 @@ segv:
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
info._sifields._sigfault._addr = env->cp15.c6_data;
|
||||
info._sifields._sigfault._addr = env->exception.vaddress;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
|
||||
end_exclusive();
|
||||
@@ -620,14 +620,14 @@ static int do_strex(CPUARMState *env)
|
||||
abort();
|
||||
}
|
||||
if (segv) {
|
||||
env->cp15.c6_data = addr;
|
||||
env->exception.vaddress = addr;
|
||||
goto done;
|
||||
}
|
||||
if (size == 3) {
|
||||
uint32_t valhi;
|
||||
segv = get_user_u32(valhi, addr + 4);
|
||||
if (segv) {
|
||||
env->cp15.c6_data = addr + 4;
|
||||
env->exception.vaddress = addr + 4;
|
||||
goto done;
|
||||
}
|
||||
val = deposit64(val, 32, 32, valhi);
|
||||
@@ -650,14 +650,14 @@ static int do_strex(CPUARMState *env)
|
||||
break;
|
||||
}
|
||||
if (segv) {
|
||||
env->cp15.c6_data = addr;
|
||||
env->exception.vaddress = addr;
|
||||
goto done;
|
||||
}
|
||||
if (size == 3) {
|
||||
val = env->regs[(env->exclusive_info >> 12) & 0xf];
|
||||
segv = put_user_u32(val, addr + 4);
|
||||
if (segv) {
|
||||
env->cp15.c6_data = addr + 4;
|
||||
env->exception.vaddress = addr + 4;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
@@ -832,12 +832,14 @@ void cpu_loop(CPUARMState *env)
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_STREX:
|
||||
if (!do_strex(env)) {
|
||||
break;
|
||||
}
|
||||
/* fall through for segv */
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
addr = env->cp15.c6_insn;
|
||||
goto do_segv;
|
||||
case EXCP_DATA_ABORT:
|
||||
addr = env->cp15.c6_data;
|
||||
do_segv:
|
||||
addr = env->exception.vaddress;
|
||||
{
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
@@ -865,12 +867,6 @@ void cpu_loop(CPUARMState *env)
|
||||
if (do_kernel_trap(env))
|
||||
goto error;
|
||||
break;
|
||||
case EXCP_STREX:
|
||||
if (do_strex(env)) {
|
||||
addr = env->cp15.c6_data;
|
||||
goto do_segv;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||
@@ -933,7 +929,7 @@ static int do_strex_a64(CPUARMState *env)
|
||||
abort();
|
||||
}
|
||||
if (segv) {
|
||||
env->cp15.c6_data = addr;
|
||||
env->exception.vaddress = addr;
|
||||
goto error;
|
||||
}
|
||||
if (val != env->exclusive_val) {
|
||||
@@ -946,7 +942,7 @@ static int do_strex_a64(CPUARMState *env)
|
||||
segv = get_user_u64(val, addr + 8);
|
||||
}
|
||||
if (segv) {
|
||||
env->cp15.c6_data = addr + (size == 2 ? 4 : 8);
|
||||
env->exception.vaddress = addr + (size == 2 ? 4 : 8);
|
||||
goto error;
|
||||
}
|
||||
if (val != env->exclusive_high) {
|
||||
@@ -981,7 +977,7 @@ static int do_strex_a64(CPUARMState *env)
|
||||
segv = put_user_u64(val, addr + 8);
|
||||
}
|
||||
if (segv) {
|
||||
env->cp15.c6_data = addr + (size == 2 ? 4 : 8);
|
||||
env->exception.vaddress = addr + (size == 2 ? 4 : 8);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
@@ -1037,12 +1033,14 @@ void cpu_loop(CPUARMState *env)
|
||||
info._sifields._sigfault._addr = env->pc;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_STREX:
|
||||
if (!do_strex_a64(env)) {
|
||||
break;
|
||||
}
|
||||
/* fall through for segv */
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
addr = env->cp15.c6_insn;
|
||||
goto do_segv;
|
||||
case EXCP_DATA_ABORT:
|
||||
addr = env->cp15.c6_data;
|
||||
do_segv:
|
||||
addr = env->exception.vaddress;
|
||||
info.si_signo = SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
@@ -1060,12 +1058,6 @@ void cpu_loop(CPUARMState *env)
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP_STREX:
|
||||
if (do_strex_a64(env)) {
|
||||
addr = env->cp15.c6_data;
|
||||
goto do_segv;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
|
||||
trapnr);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
|
||||
implementation for certain IBM POWER hardware. The sources are at
|
||||
https://github.com/aik/SLOF, and the image currently in qemu is
|
||||
built from git tag qemu-slof-20140304.
|
||||
built from git tag qemu-slof-20140404.
|
||||
|
||||
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
|
||||
legacy x86 software to communicate with an attached serial console as
|
||||
|
||||
BIN
pc-bios/slof.bin
BIN
pc-bios/slof.bin
Binary file not shown.
@@ -75,10 +75,13 @@ static void errmsg_dialog(DWORD err, const char *text, const char *opt = "")
|
||||
|
||||
#define chk(status) _chk(hr, status, "Failed to " #status, out)
|
||||
|
||||
#if !defined(__MINGW64_VERSION_MAJOR) || !defined(__MINGW64_VERSION_MINOR) || \
|
||||
__MINGW64_VERSION_MAJOR * 100 + __MINGW64_VERSION_MINOR < 301
|
||||
void __stdcall _com_issue_error(HRESULT hr)
|
||||
{
|
||||
errmsg(hr, "Unexpected error in COM");
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
HRESULT put_Value(ICatalogObject *pObj, LPCWSTR name, T val)
|
||||
|
||||
@@ -1225,7 +1225,8 @@ Object *object_resolve_path_component(Object *parent, const gchar *part)
|
||||
}
|
||||
|
||||
if (object_property_is_link(prop)) {
|
||||
return *(Object **)prop->opaque;
|
||||
LinkProperty *lprop = prop->opaque;
|
||||
return *lprop->child;
|
||||
} else if (object_property_is_child(prop)) {
|
||||
return prop->opaque;
|
||||
} else {
|
||||
|
||||
Submodule roms/SLOF updated: af6b7bf587...c90b50b505
@@ -116,6 +116,7 @@ typedef struct ARMCPU {
|
||||
uint32_t reset_fpsid;
|
||||
uint32_t mvfr0;
|
||||
uint32_t mvfr1;
|
||||
uint32_t mvfr2;
|
||||
uint32_t ctr;
|
||||
uint32_t reset_sctlr;
|
||||
uint32_t id_pfr0;
|
||||
@@ -147,9 +148,12 @@ typedef struct ARMCPU {
|
||||
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
|
||||
*/
|
||||
uint32_t ccsidr[16];
|
||||
uint32_t reset_cbar;
|
||||
uint64_t reset_cbar;
|
||||
uint32_t reset_auxcr;
|
||||
bool reset_hivecs;
|
||||
/* DCZ blocksize, in log_2(words), ie low 4 bits of DCZID_EL0 */
|
||||
uint32_t dcz_blocksize;
|
||||
uint64_t rvbar;
|
||||
} ARMCPU;
|
||||
|
||||
#define TYPE_AARCH64_CPU "aarch64-cpu"
|
||||
@@ -196,10 +200,10 @@ void arm_gt_ptimer_cb(void *opaque);
|
||||
void arm_gt_vtimer_cb(void *opaque);
|
||||
|
||||
#ifdef TARGET_AARCH64
|
||||
void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
|
||||
fprintf_function cpu_fprintf, int flags);
|
||||
int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
|
||||
void aarch64_cpu_do_interrupt(CPUState *cs);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "internals.h"
|
||||
#include "qemu-common.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
@@ -87,6 +88,7 @@ static void arm_cpu_reset(CPUState *s)
|
||||
env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid;
|
||||
env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0;
|
||||
env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1;
|
||||
env->vfp.xregs[ARM_VFP_MVFR2] = cpu->mvfr2;
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
|
||||
env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
|
||||
@@ -99,8 +101,16 @@ static void arm_cpu_reset(CPUState *s)
|
||||
env->pstate = PSTATE_MODE_EL0t;
|
||||
/* Userspace expects access to CTL_EL0 and the cache ops */
|
||||
env->cp15.c1_sys |= SCTLR_UCT | SCTLR_UCI;
|
||||
/* and to the FP/Neon instructions */
|
||||
env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3);
|
||||
#else
|
||||
env->pstate = PSTATE_MODE_EL1h;
|
||||
env->pc = cpu->rvbar;
|
||||
#endif
|
||||
} else {
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/* Userspace expects access to cp10 and cp11 for FP/Neon */
|
||||
env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 4, 0xf);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -252,16 +262,20 @@ static void arm_cpu_initfn(Object *obj)
|
||||
}
|
||||
|
||||
static Property arm_cpu_reset_cbar_property =
|
||||
DEFINE_PROP_UINT32("reset-cbar", ARMCPU, reset_cbar, 0);
|
||||
DEFINE_PROP_UINT64("reset-cbar", ARMCPU, reset_cbar, 0);
|
||||
|
||||
static Property arm_cpu_reset_hivecs_property =
|
||||
DEFINE_PROP_BOOL("reset-hivecs", ARMCPU, reset_hivecs, false);
|
||||
|
||||
static Property arm_cpu_rvbar_property =
|
||||
DEFINE_PROP_UINT64("rvbar", ARMCPU, rvbar, 0);
|
||||
|
||||
static void arm_cpu_post_init(Object *obj)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(obj);
|
||||
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_CBAR)) {
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_CBAR) ||
|
||||
arm_feature(&cpu->env, ARM_FEATURE_CBAR_RO)) {
|
||||
qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_cbar_property,
|
||||
&error_abort);
|
||||
}
|
||||
@@ -270,6 +284,11 @@ static void arm_cpu_post_init(Object *obj)
|
||||
qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_hivecs_property,
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
|
||||
qdev_property_add_static(DEVICE(obj), &arm_cpu_rvbar_property,
|
||||
&error_abort);
|
||||
}
|
||||
}
|
||||
|
||||
static void arm_cpu_finalizefn(Object *obj)
|
||||
@@ -331,6 +350,9 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
set_feature(env, ARM_FEATURE_V7MP);
|
||||
set_feature(env, ARM_FEATURE_PXN);
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_CBAR_RO)) {
|
||||
set_feature(env, ARM_FEATURE_CBAR);
|
||||
}
|
||||
|
||||
if (cpu->reset_hivecs) {
|
||||
cpu->reset_sctlr |= (1 << 13);
|
||||
@@ -417,7 +439,7 @@ static void arm1026_initfn(Object *obj)
|
||||
ARMCPRegInfo ifar = {
|
||||
.name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
|
||||
.access = PL1_RW,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c6_insn),
|
||||
.fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
|
||||
.resetvalue = 0
|
||||
};
|
||||
define_one_arm_cp_reg(cpu, &ifar);
|
||||
@@ -722,7 +744,7 @@ static void cortex_a15_initfn(Object *obj)
|
||||
set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
|
||||
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||
set_feature(&cpu->env, ARM_FEATURE_CBAR);
|
||||
set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
|
||||
set_feature(&cpu->env, ARM_FEATURE_LPAE);
|
||||
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15;
|
||||
cpu->midr = 0x412fc0f1;
|
||||
|
||||
@@ -111,11 +111,6 @@ typedef struct ARMGenericTimer {
|
||||
#define GTIMER_VIRT 1
|
||||
#define NUM_GTIMERS 2
|
||||
|
||||
/* Scale factor for generic timers, ie number of ns per tick.
|
||||
* This gives a 62.5MHz timer.
|
||||
*/
|
||||
#define GTIMER_SCALE 16
|
||||
|
||||
typedef struct CPUARMState {
|
||||
/* Regs for current mode. */
|
||||
uint32_t regs[16];
|
||||
@@ -148,7 +143,7 @@ typedef struct CPUARMState {
|
||||
uint32_t spsr;
|
||||
|
||||
/* Banked registers. */
|
||||
uint32_t banked_spsr[6];
|
||||
uint64_t banked_spsr[6];
|
||||
uint32_t banked_r13[6];
|
||||
uint32_t banked_r14[6];
|
||||
|
||||
@@ -165,7 +160,10 @@ typedef struct CPUARMState {
|
||||
uint32_t GE; /* cpsr[19:16] */
|
||||
uint32_t thumb; /* cpsr[5]. 0 = arm mode, 1 = thumb mode. */
|
||||
uint32_t condexec_bits; /* IT bits. cpsr[15:10,26:25]. */
|
||||
uint32_t daif; /* exception masks, in the bits they are in in PSTATE */
|
||||
uint64_t daif; /* exception masks, in the bits they are in in PSTATE */
|
||||
|
||||
uint64_t elr_el1; /* AArch64 ELR_EL1 */
|
||||
uint64_t sp_el[2]; /* AArch64 banked stack pointers */
|
||||
|
||||
/* System control coprocessor (cp15) */
|
||||
struct {
|
||||
@@ -184,13 +182,13 @@ typedef struct CPUARMState {
|
||||
uint32_t c2_insn; /* MPU instruction cachable bits. */
|
||||
uint32_t c3; /* MMU domain access control register
|
||||
MPU write buffer control. */
|
||||
uint32_t c5_insn; /* Fault status registers. */
|
||||
uint32_t c5_data;
|
||||
uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
|
||||
uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
|
||||
uint32_t ifsr_el2; /* Fault status registers. */
|
||||
uint64_t esr_el1;
|
||||
uint32_t c6_region[8]; /* MPU base/size registers. */
|
||||
uint32_t c6_insn; /* Fault address registers. */
|
||||
uint32_t c6_data;
|
||||
uint32_t c7_par; /* Translation result. */
|
||||
uint32_t c7_par_hi; /* Translation result, high 32 bits */
|
||||
uint64_t far_el1; /* Fault address registers. */
|
||||
uint64_t par_el1; /* Translation result. */
|
||||
uint32_t c9_insn; /* Cache lockdown registers. */
|
||||
uint32_t c9_data;
|
||||
uint32_t c9_pmcr; /* performance monitor control register */
|
||||
@@ -202,7 +200,7 @@ typedef struct CPUARMState {
|
||||
uint64_t mair_el1;
|
||||
uint64_t c12_vbar; /* vector base address register */
|
||||
uint32_t c13_fcse; /* FCSE PID. */
|
||||
uint32_t c13_context; /* Context ID. */
|
||||
uint64_t contextidr_el1; /* Context ID. */
|
||||
uint64_t tpidr_el0; /* User RW Thread register. */
|
||||
uint64_t tpidrro_el0; /* User RO Thread register. */
|
||||
uint64_t tpidr_el1; /* Privileged Thread register. */
|
||||
@@ -238,6 +236,21 @@ typedef struct CPUARMState {
|
||||
int pending_exception;
|
||||
} v7m;
|
||||
|
||||
/* Information associated with an exception about to be taken:
|
||||
* code which raises an exception must set cs->exception_index and
|
||||
* the relevant parts of this structure; the cpu_do_interrupt function
|
||||
* will then set the guest-visible registers as part of the exception
|
||||
* entry process.
|
||||
*/
|
||||
struct {
|
||||
uint32_t syndrome; /* AArch64 format syndrome register */
|
||||
uint32_t fsr; /* AArch32 format fault status register info */
|
||||
uint64_t vaddress; /* virtual addr associated with exception, if any */
|
||||
/* If we implement EL2 we will also need to store information
|
||||
* about the intermediate physical address for stage 2 faults.
|
||||
*/
|
||||
} exception;
|
||||
|
||||
/* Thumb-2 EE state. */
|
||||
uint32_t teecr;
|
||||
uint32_t teehbr;
|
||||
@@ -322,11 +335,7 @@ typedef struct CPUARMState {
|
||||
#include "cpu-qom.h"
|
||||
|
||||
ARMCPU *cpu_arm_init(const char *cpu_model);
|
||||
void arm_translate_init(void);
|
||||
void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
|
||||
int cpu_arm_exec(CPUARMState *s);
|
||||
int bank_number(int mode);
|
||||
void switch_mode(CPUARMState *, int);
|
||||
uint32_t do_arm_semihosting(CPUARMState *env);
|
||||
|
||||
static inline bool is_a64(CPUARMState *env)
|
||||
@@ -425,6 +434,7 @@ int arm_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
|
||||
* Only these are valid when in AArch64 mode; in
|
||||
* AArch32 mode SPSRs are basically CPSR-format.
|
||||
*/
|
||||
#define PSTATE_SP (1U)
|
||||
#define PSTATE_M (0xFU)
|
||||
#define PSTATE_nRW (1U << 4)
|
||||
#define PSTATE_F (1U << 6)
|
||||
@@ -548,17 +558,6 @@ static inline void vfp_set_fpcr(CPUARMState *env, uint32_t val)
|
||||
vfp_set_fpscr(env, new_fpscr);
|
||||
}
|
||||
|
||||
enum arm_fprounding {
|
||||
FPROUNDING_TIEEVEN,
|
||||
FPROUNDING_POSINF,
|
||||
FPROUNDING_NEGINF,
|
||||
FPROUNDING_ZERO,
|
||||
FPROUNDING_TIEAWAY,
|
||||
FPROUNDING_ODD
|
||||
};
|
||||
|
||||
int arm_rmode_to_sf(int rmode);
|
||||
|
||||
enum arm_cpu_mode {
|
||||
ARM_CPU_MODE_USR = 0x10,
|
||||
ARM_CPU_MODE_FIQ = 0x11,
|
||||
@@ -572,6 +571,7 @@ enum arm_cpu_mode {
|
||||
/* VFP system registers. */
|
||||
#define ARM_VFP_FPSID 0
|
||||
#define ARM_VFP_FPSCR 1
|
||||
#define ARM_VFP_MVFR2 5
|
||||
#define ARM_VFP_MVFR1 6
|
||||
#define ARM_VFP_MVFR0 7
|
||||
#define ARM_VFP_FPEXC 8
|
||||
@@ -630,6 +630,7 @@ enum arm_features {
|
||||
ARM_FEATURE_V8_AES, /* implements AES part of v8 Crypto Extensions */
|
||||
ARM_FEATURE_CBAR, /* has cp15 CBAR */
|
||||
ARM_FEATURE_CRC, /* ARMv8 CRC instructions */
|
||||
ARM_FEATURE_CBAR_RO, /* has cp15 CBAR and it is read-only */
|
||||
};
|
||||
|
||||
static inline int arm_feature(CPUARMState *env, int feature)
|
||||
@@ -763,7 +764,8 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
|
||||
#define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
|
||||
#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
|
||||
#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
|
||||
#define ARM_LAST_SPECIAL ARM_CP_CURRENTEL
|
||||
#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
|
||||
#define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
|
||||
/* Used only as a terminator for ARMCPRegInfo lists */
|
||||
#define ARM_CP_SENTINEL 0xffff
|
||||
/* Mask of only the flag bits in a type field */
|
||||
@@ -1109,10 +1111,14 @@ static inline int cpu_mmu_index (CPUARMState *env)
|
||||
#define ARM_TBFLAG_CONDEXEC_MASK (0xff << ARM_TBFLAG_CONDEXEC_SHIFT)
|
||||
#define ARM_TBFLAG_BSWAP_CODE_SHIFT 16
|
||||
#define ARM_TBFLAG_BSWAP_CODE_MASK (1 << ARM_TBFLAG_BSWAP_CODE_SHIFT)
|
||||
#define ARM_TBFLAG_CPACR_FPEN_SHIFT 17
|
||||
#define ARM_TBFLAG_CPACR_FPEN_MASK (1 << ARM_TBFLAG_CPACR_FPEN_SHIFT)
|
||||
|
||||
/* Bit usage when in AArch64 state */
|
||||
#define ARM_TBFLAG_AA64_EL_SHIFT 0
|
||||
#define ARM_TBFLAG_AA64_EL_MASK (0x3 << ARM_TBFLAG_AA64_EL_SHIFT)
|
||||
#define ARM_TBFLAG_AA64_FPEN_SHIFT 2
|
||||
#define ARM_TBFLAG_AA64_FPEN_MASK (1 << ARM_TBFLAG_AA64_FPEN_SHIFT)
|
||||
|
||||
/* some convenience accessor macros */
|
||||
#define ARM_TBFLAG_AARCH64_STATE(F) \
|
||||
@@ -1131,16 +1137,25 @@ static inline int cpu_mmu_index (CPUARMState *env)
|
||||
(((F) & ARM_TBFLAG_CONDEXEC_MASK) >> ARM_TBFLAG_CONDEXEC_SHIFT)
|
||||
#define ARM_TBFLAG_BSWAP_CODE(F) \
|
||||
(((F) & ARM_TBFLAG_BSWAP_CODE_MASK) >> ARM_TBFLAG_BSWAP_CODE_SHIFT)
|
||||
#define ARM_TBFLAG_CPACR_FPEN(F) \
|
||||
(((F) & ARM_TBFLAG_CPACR_FPEN_MASK) >> ARM_TBFLAG_CPACR_FPEN_SHIFT)
|
||||
#define ARM_TBFLAG_AA64_EL(F) \
|
||||
(((F) & ARM_TBFLAG_AA64_EL_MASK) >> ARM_TBFLAG_AA64_EL_SHIFT)
|
||||
#define ARM_TBFLAG_AA64_FPEN(F) \
|
||||
(((F) & ARM_TBFLAG_AA64_FPEN_MASK) >> ARM_TBFLAG_AA64_FPEN_SHIFT)
|
||||
|
||||
static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
target_ulong *cs_base, int *flags)
|
||||
{
|
||||
int fpen = extract32(env->cp15.c1_coproc, 20, 2);
|
||||
|
||||
if (is_a64(env)) {
|
||||
*pc = env->pc;
|
||||
*flags = ARM_TBFLAG_AARCH64_STATE_MASK
|
||||
| (arm_current_pl(env) << ARM_TBFLAG_AA64_EL_SHIFT);
|
||||
if (fpen == 3 || (fpen == 1 && arm_current_pl(env) != 0)) {
|
||||
*flags |= ARM_TBFLAG_AA64_FPEN_MASK;
|
||||
}
|
||||
} else {
|
||||
int privmode;
|
||||
*pc = env->regs[15];
|
||||
@@ -1157,9 +1172,13 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
if (privmode) {
|
||||
*flags |= ARM_TBFLAG_PRIV_MASK;
|
||||
}
|
||||
if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
|
||||
if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)
|
||||
|| arm_el_is_aa64(env, 1)) {
|
||||
*flags |= ARM_TBFLAG_VFPEN_MASK;
|
||||
}
|
||||
if (fpen == 3 || (fpen == 1 && arm_current_pl(env) != 0)) {
|
||||
*flags |= ARM_TBFLAG_CPACR_FPEN_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
*cs_base = 0;
|
||||
|
||||
@@ -32,6 +32,104 @@ static inline void set_feature(CPUARMState *env, int feature)
|
||||
env->features |= 1ULL << feature;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static uint64_t a57_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
/* Number of processors is in [25:24]; otherwise we RAZ */
|
||||
return (smp_cpus - 1) << 24;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const ARMCPRegInfo cortexa57_cp_reginfo[] = {
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
{ .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2,
|
||||
.access = PL1_RW, .readfn = a57_l2ctlr_read,
|
||||
.writefn = arm_cp_write_ignore },
|
||||
{ .name = "L2CTLR",
|
||||
.cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 2,
|
||||
.access = PL1_RW, .readfn = a57_l2ctlr_read,
|
||||
.writefn = arm_cp_write_ignore },
|
||||
#endif
|
||||
{ .name = "L2ECTLR_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 3,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "L2ECTLR",
|
||||
.cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 3,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "L2ACTLR", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 1, .crn = 15, .crm = 0, .opc2 = 0,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 0,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "CPUACTLR",
|
||||
.cp = 15, .opc1 = 0, .crm = 15,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 },
|
||||
{ .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 1,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "CPUECTLR",
|
||||
.cp = 15, .opc1 = 1, .crm = 15,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 },
|
||||
{ .name = "CPUMERRSR_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 2,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "CPUMERRSR",
|
||||
.cp = 15, .opc1 = 2, .crm = 15,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 },
|
||||
{ .name = "L2MERRSR_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 1, .crn = 15, .crm = 2, .opc2 = 3,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
|
||||
{ .name = "L2MERRSR",
|
||||
.cp = 15, .opc1 = 3, .crm = 15,
|
||||
.access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
static void aarch64_a57_initfn(Object *obj)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(obj);
|
||||
|
||||
set_feature(&cpu->env, ARM_FEATURE_V8);
|
||||
set_feature(&cpu->env, ARM_FEATURE_VFP4);
|
||||
set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
|
||||
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
||||
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
||||
set_feature(&cpu->env, ARM_FEATURE_AARCH64);
|
||||
set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
|
||||
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
|
||||
cpu->midr = 0x411fd070;
|
||||
cpu->reset_fpsid = 0x41034070;
|
||||
cpu->mvfr0 = 0x10110222;
|
||||
cpu->mvfr1 = 0x12111111;
|
||||
cpu->mvfr2 = 0x00000043;
|
||||
cpu->ctr = 0x8444c004;
|
||||
cpu->reset_sctlr = 0x00c50838;
|
||||
cpu->id_pfr0 = 0x00000131;
|
||||
cpu->id_pfr1 = 0x00011011;
|
||||
cpu->id_dfr0 = 0x03010066;
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
cpu->id_mmfr0 = 0x10101105;
|
||||
cpu->id_mmfr1 = 0x40000000;
|
||||
cpu->id_mmfr2 = 0x01260000;
|
||||
cpu->id_mmfr3 = 0x02102211;
|
||||
cpu->id_isar0 = 0x02101110;
|
||||
cpu->id_isar1 = 0x13112111;
|
||||
cpu->id_isar2 = 0x21232042;
|
||||
cpu->id_isar3 = 0x01112131;
|
||||
cpu->id_isar4 = 0x00011142;
|
||||
cpu->id_aa64pfr0 = 0x00002222;
|
||||
cpu->id_aa64dfr0 = 0x10305106;
|
||||
cpu->id_aa64isar0 = 0x00010000;
|
||||
cpu->id_aa64mmfr0 = 0x00001124;
|
||||
cpu->clidr = 0x0a200023;
|
||||
cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
|
||||
cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
|
||||
cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */
|
||||
cpu->dcz_blocksize = 4; /* 64 bytes */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
static void aarch64_any_initfn(Object *obj)
|
||||
{
|
||||
@@ -41,11 +139,11 @@ static void aarch64_any_initfn(Object *obj)
|
||||
set_feature(&cpu->env, ARM_FEATURE_VFP4);
|
||||
set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
|
||||
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
||||
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
||||
set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
|
||||
set_feature(&cpu->env, ARM_FEATURE_V7MP);
|
||||
set_feature(&cpu->env, ARM_FEATURE_AARCH64);
|
||||
cpu->ctr = 0x80030003; /* 32 byte I and D cacheline size, VIPT icache */
|
||||
cpu->dcz_blocksize = 7; /* 512 bytes */
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -56,6 +154,7 @@ typedef struct ARMCPUInfo {
|
||||
} ARMCPUInfo;
|
||||
|
||||
static const ARMCPUInfo aarch64_cpus[] = {
|
||||
{ .name = "cortex-a57", .initfn = aarch64_a57_initfn },
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
{ .name = "any", .initfn = aarch64_any_initfn },
|
||||
#endif
|
||||
@@ -73,18 +172,22 @@ static void aarch64_cpu_finalizefn(Object *obj)
|
||||
static void aarch64_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
/*
|
||||
* TODO: this will need updating for system emulation,
|
||||
* when the core may be in AArch32 mode.
|
||||
/* It's OK to look at env for the current mode here, because it's
|
||||
* never possible for an AArch64 TB to chain to an AArch32 TB.
|
||||
* (Otherwise we would need to use synchronize_from_tb instead.)
|
||||
*/
|
||||
cpu->env.pc = value;
|
||||
if (is_a64(&cpu->env)) {
|
||||
cpu->env.pc = value;
|
||||
} else {
|
||||
cpu->env.regs[15] = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void aarch64_cpu_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
CPUClass *cc = CPU_CLASS(oc);
|
||||
|
||||
cc->dump_state = aarch64_cpu_dump_state;
|
||||
cc->do_interrupt = aarch64_cpu_do_interrupt;
|
||||
cc->set_pc = aarch64_cpu_set_pc;
|
||||
cc->gdb_read_register = aarch64_cpu_gdb_read_register;
|
||||
cc->gdb_write_register = aarch64_cpu_gdb_write_register;
|
||||
|
||||
@@ -32,10 +32,8 @@ int aarch64_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
switch (n) {
|
||||
case 31:
|
||||
return gdb_get_reg64(mem_buf, env->xregs[31]);
|
||||
break;
|
||||
case 32:
|
||||
return gdb_get_reg64(mem_buf, env->pc);
|
||||
break;
|
||||
case 33:
|
||||
return gdb_get_reg32(mem_buf, pstate_read(env));
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "qemu/host-utils.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "internals.h"
|
||||
|
||||
/* C2.4.7 Multiply and divide */
|
||||
/* special cases for 0 and LLONG_MIN are mandated by the standard */
|
||||
@@ -436,3 +437,78 @@ float32 HELPER(fcvtx_f64_to_f32)(float64 a, CPUARMState *env)
|
||||
set_float_exception_flags(exflags, fpst);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Handle a CPU exception. */
|
||||
void aarch64_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
CPUARMState *env = &cpu->env;
|
||||
target_ulong addr = env->cp15.c12_vbar;
|
||||
int i;
|
||||
|
||||
if (arm_current_pl(env) == 0) {
|
||||
if (env->aarch64) {
|
||||
addr += 0x400;
|
||||
} else {
|
||||
addr += 0x600;
|
||||
}
|
||||
} else if (pstate_read(env) & PSTATE_SP) {
|
||||
addr += 0x200;
|
||||
}
|
||||
|
||||
arm_log_exception(cs->exception_index);
|
||||
qemu_log_mask(CPU_LOG_INT, "...from EL%d\n", arm_current_pl(env));
|
||||
if (qemu_loglevel_mask(CPU_LOG_INT)
|
||||
&& !excp_is_internal(cs->exception_index)) {
|
||||
qemu_log_mask(CPU_LOG_INT, "...with ESR 0x%" PRIx32 "\n",
|
||||
env->exception.syndrome);
|
||||
}
|
||||
|
||||
env->cp15.esr_el1 = env->exception.syndrome;
|
||||
env->cp15.far_el1 = env->exception.vaddress;
|
||||
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
case EXCP_DATA_ABORT:
|
||||
qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n",
|
||||
env->cp15.far_el1);
|
||||
break;
|
||||
case EXCP_BKPT:
|
||||
case EXCP_UDEF:
|
||||
case EXCP_SWI:
|
||||
break;
|
||||
case EXCP_IRQ:
|
||||
addr += 0x80;
|
||||
break;
|
||||
case EXCP_FIQ:
|
||||
addr += 0x100;
|
||||
break;
|
||||
default:
|
||||
cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
|
||||
}
|
||||
|
||||
if (is_a64(env)) {
|
||||
env->banked_spsr[0] = pstate_read(env);
|
||||
env->sp_el[arm_current_pl(env)] = env->xregs[31];
|
||||
env->xregs[31] = env->sp_el[1];
|
||||
env->elr_el1 = env->pc;
|
||||
} else {
|
||||
env->banked_spsr[0] = cpsr_read(env);
|
||||
if (!env->thumb) {
|
||||
env->cp15.esr_el1 |= 1 << 25;
|
||||
}
|
||||
env->elr_el1 = env->regs[15];
|
||||
|
||||
for (i = 0; i < 15; i++) {
|
||||
env->xregs[i] = env->regs[i];
|
||||
}
|
||||
|
||||
env->condexec_bits = 0;
|
||||
}
|
||||
|
||||
pstate_write(env, PSTATE_DAIF | PSTATE_MODE_EL1h);
|
||||
env->aarch64 = 1;
|
||||
|
||||
env->pc = addr;
|
||||
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,7 +48,8 @@ DEF_HELPER_FLAGS_2(usad8, TCG_CALL_NO_RWG_SE, i32, i32, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE,
|
||||
i32, i32, i32, i32)
|
||||
DEF_HELPER_2(exception, void, env, i32)
|
||||
DEF_HELPER_2(exception_internal, void, env, i32)
|
||||
DEF_HELPER_3(exception_with_syndrome, void, env, i32, i32)
|
||||
DEF_HELPER_1(wfi, void, env)
|
||||
DEF_HELPER_1(wfe, void, env)
|
||||
|
||||
@@ -58,13 +59,14 @@ DEF_HELPER_1(cpsr_read, i32, env)
|
||||
DEF_HELPER_3(v7m_msr, void, env, i32, i32)
|
||||
DEF_HELPER_2(v7m_mrs, i32, env, i32)
|
||||
|
||||
DEF_HELPER_2(access_check_cp_reg, void, env, ptr)
|
||||
DEF_HELPER_3(access_check_cp_reg, void, env, ptr, i32)
|
||||
DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
|
||||
DEF_HELPER_2(get_cp_reg, i32, env, ptr)
|
||||
DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
|
||||
DEF_HELPER_2(get_cp_reg64, i64, env, ptr)
|
||||
|
||||
DEF_HELPER_3(msr_i_pstate, void, env, i32, i32)
|
||||
DEF_HELPER_1(exception_return, void, env)
|
||||
|
||||
DEF_HELPER_2(get_r13_banked, i32, env, i32)
|
||||
DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
|
||||
@@ -514,6 +516,7 @@ DEF_HELPER_4(crypto_aesmc, void, env, i32, i32, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
|
||||
DEF_HELPER_2(dc_zva, void, env, i64)
|
||||
|
||||
#ifdef TARGET_AARCH64
|
||||
#include "helper-a64.h"
|
||||
|
||||
267
target-arm/internals.h
Normal file
267
target-arm/internals.h
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* QEMU ARM CPU -- internal functions and types
|
||||
*
|
||||
* Copyright (c) 2014 Linaro Ltd
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see
|
||||
* <http://www.gnu.org/licenses/gpl-2.0.html>
|
||||
*
|
||||
* This header defines functions, types, etc which need to be shared
|
||||
* between different source files within target-arm/ but which are
|
||||
* private to it and not required by the rest of QEMU.
|
||||
*/
|
||||
|
||||
#ifndef TARGET_ARM_INTERNALS_H
|
||||
#define TARGET_ARM_INTERNALS_H
|
||||
|
||||
static inline bool excp_is_internal(int excp)
|
||||
{
|
||||
/* Return true if this exception number represents a QEMU-internal
|
||||
* exception that will not be passed to the guest.
|
||||
*/
|
||||
return excp == EXCP_INTERRUPT
|
||||
|| excp == EXCP_HLT
|
||||
|| excp == EXCP_DEBUG
|
||||
|| excp == EXCP_HALTED
|
||||
|| excp == EXCP_EXCEPTION_EXIT
|
||||
|| excp == EXCP_KERNEL_TRAP
|
||||
|| excp == EXCP_STREX;
|
||||
}
|
||||
|
||||
/* Exception names for debug logging; note that not all of these
|
||||
* precisely correspond to architectural exceptions.
|
||||
*/
|
||||
static const char * const excnames[] = {
|
||||
[EXCP_UDEF] = "Undefined Instruction",
|
||||
[EXCP_SWI] = "SVC",
|
||||
[EXCP_PREFETCH_ABORT] = "Prefetch Abort",
|
||||
[EXCP_DATA_ABORT] = "Data Abort",
|
||||
[EXCP_IRQ] = "IRQ",
|
||||
[EXCP_FIQ] = "FIQ",
|
||||
[EXCP_BKPT] = "Breakpoint",
|
||||
[EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
|
||||
[EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
|
||||
[EXCP_STREX] = "QEMU intercept of STREX",
|
||||
};
|
||||
|
||||
static inline void arm_log_exception(int idx)
|
||||
{
|
||||
if (qemu_loglevel_mask(CPU_LOG_INT)) {
|
||||
const char *exc = NULL;
|
||||
|
||||
if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
|
||||
exc = excnames[idx];
|
||||
}
|
||||
if (!exc) {
|
||||
exc = "unknown";
|
||||
}
|
||||
qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Scale factor for generic timers, ie number of ns per tick.
|
||||
* This gives a 62.5MHz timer.
|
||||
*/
|
||||
#define GTIMER_SCALE 16
|
||||
|
||||
int bank_number(int mode);
|
||||
void switch_mode(CPUARMState *, int);
|
||||
void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
|
||||
void arm_translate_init(void);
|
||||
|
||||
enum arm_fprounding {
|
||||
FPROUNDING_TIEEVEN,
|
||||
FPROUNDING_POSINF,
|
||||
FPROUNDING_NEGINF,
|
||||
FPROUNDING_ZERO,
|
||||
FPROUNDING_TIEAWAY,
|
||||
FPROUNDING_ODD
|
||||
};
|
||||
|
||||
int arm_rmode_to_sf(int rmode);
|
||||
|
||||
static inline void update_spsel(CPUARMState *env, uint32_t imm)
|
||||
{
|
||||
/* Update PSTATE SPSel bit; this requires us to update the
|
||||
* working stack pointer in xregs[31].
|
||||
*/
|
||||
if (!((imm ^ env->pstate) & PSTATE_SP)) {
|
||||
return;
|
||||
}
|
||||
env->pstate = deposit32(env->pstate, 0, 1, imm);
|
||||
|
||||
/* EL0 has no access rights to update SPSel, and this code
|
||||
* assumes we are updating SP for EL1 while running as EL1.
|
||||
*/
|
||||
assert(arm_current_pl(env) == 1);
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
/* Switch from using SP_EL0 to using SP_ELx */
|
||||
env->sp_el[0] = env->xregs[31];
|
||||
env->xregs[31] = env->sp_el[1];
|
||||
} else {
|
||||
/* Switch from SP_EL0 to SP_ELx */
|
||||
env->sp_el[1] = env->xregs[31];
|
||||
env->xregs[31] = env->sp_el[0];
|
||||
}
|
||||
}
|
||||
|
||||
/* Valid Syndrome Register EC field values */
|
||||
enum arm_exception_class {
|
||||
EC_UNCATEGORIZED = 0x00,
|
||||
EC_WFX_TRAP = 0x01,
|
||||
EC_CP15RTTRAP = 0x03,
|
||||
EC_CP15RRTTRAP = 0x04,
|
||||
EC_CP14RTTRAP = 0x05,
|
||||
EC_CP14DTTRAP = 0x06,
|
||||
EC_ADVSIMDFPACCESSTRAP = 0x07,
|
||||
EC_FPIDTRAP = 0x08,
|
||||
EC_CP14RRTTRAP = 0x0c,
|
||||
EC_ILLEGALSTATE = 0x0e,
|
||||
EC_AA32_SVC = 0x11,
|
||||
EC_AA32_HVC = 0x12,
|
||||
EC_AA32_SMC = 0x13,
|
||||
EC_AA64_SVC = 0x15,
|
||||
EC_AA64_HVC = 0x16,
|
||||
EC_AA64_SMC = 0x17,
|
||||
EC_SYSTEMREGISTERTRAP = 0x18,
|
||||
EC_INSNABORT = 0x20,
|
||||
EC_INSNABORT_SAME_EL = 0x21,
|
||||
EC_PCALIGNMENT = 0x22,
|
||||
EC_DATAABORT = 0x24,
|
||||
EC_DATAABORT_SAME_EL = 0x25,
|
||||
EC_SPALIGNMENT = 0x26,
|
||||
EC_AA32_FPTRAP = 0x28,
|
||||
EC_AA64_FPTRAP = 0x2c,
|
||||
EC_SERROR = 0x2f,
|
||||
EC_BREAKPOINT = 0x30,
|
||||
EC_BREAKPOINT_SAME_EL = 0x31,
|
||||
EC_SOFTWARESTEP = 0x32,
|
||||
EC_SOFTWARESTEP_SAME_EL = 0x33,
|
||||
EC_WATCHPOINT = 0x34,
|
||||
EC_WATCHPOINT_SAME_EL = 0x35,
|
||||
EC_AA32_BKPT = 0x38,
|
||||
EC_VECTORCATCH = 0x3a,
|
||||
EC_AA64_BKPT = 0x3c,
|
||||
};
|
||||
|
||||
#define ARM_EL_EC_SHIFT 26
|
||||
#define ARM_EL_IL_SHIFT 25
|
||||
#define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
|
||||
|
||||
/* Utility functions for constructing various kinds of syndrome value.
|
||||
* Note that in general we follow the AArch64 syndrome values; in a
|
||||
* few cases the value in HSR for exceptions taken to AArch32 Hyp
|
||||
* mode differs slightly, so if we ever implemented Hyp mode then the
|
||||
* syndrome value would need some massaging on exception entry.
|
||||
* (One example of this is that AArch64 defaults to IL bit set for
|
||||
* exceptions which don't specifically indicate information about the
|
||||
* trapping instruction, whereas AArch32 defaults to IL bit clear.)
|
||||
*/
|
||||
static inline uint32_t syn_uncategorized(void)
|
||||
{
|
||||
return (EC_UNCATEGORIZED << ARM_EL_EC_SHIFT) | ARM_EL_IL;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_aa64_svc(uint32_t imm16)
|
||||
{
|
||||
return (EC_AA64_SVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
|
||||
}
|
||||
|
||||
static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_thumb)
|
||||
{
|
||||
return (EC_AA32_SVC << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
|
||||
| (is_thumb ? 0 : ARM_EL_IL);
|
||||
}
|
||||
|
||||
static inline uint32_t syn_aa64_bkpt(uint32_t imm16)
|
||||
{
|
||||
return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
|
||||
}
|
||||
|
||||
static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_thumb)
|
||||
{
|
||||
return (EC_AA32_BKPT << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
|
||||
| (is_thumb ? 0 : ARM_EL_IL);
|
||||
}
|
||||
|
||||
static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2,
|
||||
int crn, int crm, int rt,
|
||||
int isread)
|
||||
{
|
||||
return (EC_SYSTEMREGISTERTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL
|
||||
| (op0 << 20) | (op2 << 17) | (op1 << 14) | (crn << 10) | (rt << 5)
|
||||
| (crm << 1) | isread;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2,
|
||||
int crn, int crm, int rt, int isread,
|
||||
bool is_thumb)
|
||||
{
|
||||
return (EC_CP14RTTRAP << ARM_EL_EC_SHIFT)
|
||||
| (is_thumb ? 0 : ARM_EL_IL)
|
||||
| (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
|
||||
| (crn << 10) | (rt << 5) | (crm << 1) | isread;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_cp15_rt_trap(int cv, int cond, int opc1, int opc2,
|
||||
int crn, int crm, int rt, int isread,
|
||||
bool is_thumb)
|
||||
{
|
||||
return (EC_CP15RTTRAP << ARM_EL_EC_SHIFT)
|
||||
| (is_thumb ? 0 : ARM_EL_IL)
|
||||
| (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
|
||||
| (crn << 10) | (rt << 5) | (crm << 1) | isread;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_cp14_rrt_trap(int cv, int cond, int opc1, int crm,
|
||||
int rt, int rt2, int isread,
|
||||
bool is_thumb)
|
||||
{
|
||||
return (EC_CP14RRTTRAP << ARM_EL_EC_SHIFT)
|
||||
| (is_thumb ? 0 : ARM_EL_IL)
|
||||
| (cv << 24) | (cond << 20) | (opc1 << 16)
|
||||
| (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm,
|
||||
int rt, int rt2, int isread,
|
||||
bool is_thumb)
|
||||
{
|
||||
return (EC_CP15RRTTRAP << ARM_EL_EC_SHIFT)
|
||||
| (is_thumb ? 0 : ARM_EL_IL)
|
||||
| (cv << 24) | (cond << 20) | (opc1 << 16)
|
||||
| (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_thumb)
|
||||
{
|
||||
return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
|
||||
| (is_thumb ? 0 : ARM_EL_IL)
|
||||
| (cv << 24) | (cond << 20);
|
||||
}
|
||||
|
||||
static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
|
||||
{
|
||||
return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
|
||||
| (ea << 9) | (s1ptw << 7) | fsc;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_data_abort(int same_el, int ea, int cm, int s1ptw,
|
||||
int wnr, int fsc)
|
||||
{
|
||||
return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
|
||||
| (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "sysemu/kvm.h"
|
||||
#include "kvm_arm.h"
|
||||
#include "cpu.h"
|
||||
#include "internals.h"
|
||||
#include "hw/arm/arm.h"
|
||||
|
||||
static inline void set_feature(uint64_t *features, int feature)
|
||||
@@ -294,6 +295,14 @@ typedef struct Reg {
|
||||
offsetof(CPUARMState, vfp.xregs[ARM_VFP_##R]) \
|
||||
}
|
||||
|
||||
/* Like COREREG, but handle fields which are in a uint64_t in CPUARMState. */
|
||||
#define COREREG64(KERNELNAME, QEMUFIELD) \
|
||||
{ \
|
||||
KVM_REG_ARM | KVM_REG_SIZE_U32 | \
|
||||
KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(KERNELNAME), \
|
||||
offsetoflow32(CPUARMState, QEMUFIELD) \
|
||||
}
|
||||
|
||||
static const Reg regs[] = {
|
||||
/* R0_usr .. R14_usr */
|
||||
COREREG(usr_regs.uregs[0], regs[0]),
|
||||
@@ -314,16 +323,16 @@ static const Reg regs[] = {
|
||||
/* R13, R14, SPSR for SVC, ABT, UND, IRQ banks */
|
||||
COREREG(svc_regs[0], banked_r13[1]),
|
||||
COREREG(svc_regs[1], banked_r14[1]),
|
||||
COREREG(svc_regs[2], banked_spsr[1]),
|
||||
COREREG64(svc_regs[2], banked_spsr[1]),
|
||||
COREREG(abt_regs[0], banked_r13[2]),
|
||||
COREREG(abt_regs[1], banked_r14[2]),
|
||||
COREREG(abt_regs[2], banked_spsr[2]),
|
||||
COREREG64(abt_regs[2], banked_spsr[2]),
|
||||
COREREG(und_regs[0], banked_r13[3]),
|
||||
COREREG(und_regs[1], banked_r14[3]),
|
||||
COREREG(und_regs[2], banked_spsr[3]),
|
||||
COREREG64(und_regs[2], banked_spsr[3]),
|
||||
COREREG(irq_regs[0], banked_r13[4]),
|
||||
COREREG(irq_regs[1], banked_r14[4]),
|
||||
COREREG(irq_regs[2], banked_spsr[4]),
|
||||
COREREG64(irq_regs[2], banked_spsr[4]),
|
||||
/* R8_fiq .. R14_fiq and SPSR_fiq */
|
||||
COREREG(fiq_regs[0], fiq_regs[0]),
|
||||
COREREG(fiq_regs[1], fiq_regs[1]),
|
||||
@@ -332,7 +341,7 @@ static const Reg regs[] = {
|
||||
COREREG(fiq_regs[4], fiq_regs[4]),
|
||||
COREREG(fiq_regs[5], banked_r13[5]),
|
||||
COREREG(fiq_regs[6], banked_r14[5]),
|
||||
COREREG(fiq_regs[7], banked_spsr[5]),
|
||||
COREREG64(fiq_regs[7], banked_spsr[5]),
|
||||
/* R15 */
|
||||
COREREG(usr_regs.uregs[15], regs[15]),
|
||||
/* VFP system registers */
|
||||
|
||||
@@ -121,8 +121,24 @@ int kvm_arch_put_registers(CPUState *cs, int level)
|
||||
}
|
||||
}
|
||||
|
||||
/* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
|
||||
* QEMU side we keep the current SP in xregs[31] as well.
|
||||
*/
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->sp_el[1] = env->xregs[31];
|
||||
} else {
|
||||
env->sp_el[0] = env->xregs[31];
|
||||
}
|
||||
|
||||
reg.id = AARCH64_CORE_REG(regs.sp);
|
||||
reg.addr = (uintptr_t) &env->xregs[31];
|
||||
reg.addr = (uintptr_t) &env->sp_el[0];
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg.id = AARCH64_CORE_REG(sp_el1);
|
||||
reg.addr = (uintptr_t) &env->sp_el[1];
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
@@ -144,10 +160,23 @@ int kvm_arch_put_registers(CPUState *cs, int level)
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg.id = AARCH64_CORE_REG(elr_el1);
|
||||
reg.addr = (uintptr_t) &env->elr_el1;
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < KVM_NR_SPSR; i++) {
|
||||
reg.id = AARCH64_CORE_REG(spsr[i]);
|
||||
reg.addr = (uintptr_t) &env->banked_spsr[i - 1];
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO:
|
||||
* SP_EL1
|
||||
* ELR_EL1
|
||||
* SPSR[]
|
||||
* FP state
|
||||
* system registers
|
||||
*/
|
||||
@@ -174,7 +203,14 @@ int kvm_arch_get_registers(CPUState *cs)
|
||||
}
|
||||
|
||||
reg.id = AARCH64_CORE_REG(regs.sp);
|
||||
reg.addr = (uintptr_t) &env->xregs[31];
|
||||
reg.addr = (uintptr_t) &env->sp_el[0];
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg.id = AARCH64_CORE_REG(sp_el1);
|
||||
reg.addr = (uintptr_t) &env->sp_el[1];
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
@@ -188,6 +224,15 @@ int kvm_arch_get_registers(CPUState *cs)
|
||||
}
|
||||
pstate_write(env, val);
|
||||
|
||||
/* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
|
||||
* QEMU side we keep the current SP in xregs[31] as well.
|
||||
*/
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->xregs[31] = env->sp_el[1];
|
||||
} else {
|
||||
env->xregs[31] = env->sp_el[0];
|
||||
}
|
||||
|
||||
reg.id = AARCH64_CORE_REG(regs.pc);
|
||||
reg.addr = (uintptr_t) &env->pc;
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
||||
@@ -195,6 +240,22 @@ int kvm_arch_get_registers(CPUState *cs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg.id = AARCH64_CORE_REG(elr_el1);
|
||||
reg.addr = (uintptr_t) &env->elr_el1;
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < KVM_NR_SPSR; i++) {
|
||||
reg.id = AARCH64_CORE_REG(spsr[i]);
|
||||
reg.addr = (uintptr_t) &env->banked_spsr[i - 1];
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: other registers */
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -222,9 +222,9 @@ static int cpu_post_load(void *opaque, int version_id)
|
||||
|
||||
const VMStateDescription vmstate_arm_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 14,
|
||||
.minimum_version_id = 14,
|
||||
.minimum_version_id_old = 14,
|
||||
.version_id = 17,
|
||||
.minimum_version_id = 17,
|
||||
.minimum_version_id_old = 17,
|
||||
.pre_save = cpu_pre_save,
|
||||
.post_load = cpu_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
@@ -238,11 +238,13 @@ const VMStateDescription vmstate_arm_cpu = {
|
||||
.offset = 0,
|
||||
},
|
||||
VMSTATE_UINT32(env.spsr, ARMCPU),
|
||||
VMSTATE_UINT32_ARRAY(env.banked_spsr, ARMCPU, 6),
|
||||
VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 6),
|
||||
VMSTATE_UINT32_ARRAY(env.banked_r13, ARMCPU, 6),
|
||||
VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6),
|
||||
VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
|
||||
VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
|
||||
VMSTATE_UINT64(env.elr_el1, ARMCPU),
|
||||
VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 2),
|
||||
/* The length-check must come before the arrays to avoid
|
||||
* incoming data possibly overflowing the array.
|
||||
*/
|
||||
@@ -257,6 +259,9 @@ const VMStateDescription vmstate_arm_cpu = {
|
||||
VMSTATE_UINT64(env.exclusive_val, ARMCPU),
|
||||
VMSTATE_UINT64(env.exclusive_high, ARMCPU),
|
||||
VMSTATE_UINT64(env.features, ARMCPU),
|
||||
VMSTATE_UINT32(env.exception.syndrome, ARMCPU),
|
||||
VMSTATE_UINT32(env.exception.fsr, ARMCPU),
|
||||
VMSTATE_UINT64(env.exception.vaddress, ARMCPU),
|
||||
VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU),
|
||||
VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
#include "cpu.h"
|
||||
#include "helper.h"
|
||||
#include "internals.h"
|
||||
|
||||
#define SIGNBIT (uint32_t)0x80000000
|
||||
#define SIGNBIT64 ((uint64_t)1 << 63)
|
||||
@@ -243,14 +244,33 @@ void HELPER(wfe)(CPUARMState *env)
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
void HELPER(exception)(CPUARMState *env, uint32_t excp)
|
||||
/* Raise an internal-to-QEMU exception. This is limited to only
|
||||
* those EXCP values which are special cases for QEMU to interrupt
|
||||
* execution and not to be used for exceptions which are passed to
|
||||
* the guest (those must all have syndrome information and thus should
|
||||
* use exception_with_syndrome).
|
||||
*/
|
||||
void HELPER(exception_internal)(CPUARMState *env, uint32_t excp)
|
||||
{
|
||||
CPUState *cs = CPU(arm_env_get_cpu(env));
|
||||
|
||||
assert(excp_is_internal(excp));
|
||||
cs->exception_index = excp;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
/* Raise an exception with the specified syndrome register value */
|
||||
void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp,
|
||||
uint32_t syndrome)
|
||||
{
|
||||
CPUState *cs = CPU(arm_env_get_cpu(env));
|
||||
|
||||
assert(!excp_is_internal(excp));
|
||||
cs->exception_index = excp;
|
||||
env->exception.syndrome = syndrome;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
uint32_t HELPER(cpsr_read)(CPUARMState *env)
|
||||
{
|
||||
return cpsr_read(env) & ~CPSR_EXEC;
|
||||
@@ -293,17 +313,17 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
|
||||
}
|
||||
}
|
||||
|
||||
void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip)
|
||||
void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome)
|
||||
{
|
||||
const ARMCPRegInfo *ri = rip;
|
||||
switch (ri->accessfn(env, ri)) {
|
||||
case CP_ACCESS_OK:
|
||||
return;
|
||||
case CP_ACCESS_TRAP:
|
||||
env->exception.syndrome = syndrome;
|
||||
break;
|
||||
case CP_ACCESS_TRAP_UNCATEGORIZED:
|
||||
/* These cases will eventually need to generate different
|
||||
* syndrome information.
|
||||
*/
|
||||
env->exception.syndrome = syn_uncategorized();
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
@@ -351,7 +371,7 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
|
||||
|
||||
switch (op) {
|
||||
case 0x05: /* SPSel */
|
||||
env->pstate = deposit32(env->pstate, 0, 1, imm);
|
||||
update_spsel(env, imm);
|
||||
break;
|
||||
case 0x1e: /* DAIFSet */
|
||||
env->daif |= (imm << 6) & PSTATE_DAIF;
|
||||
@@ -364,6 +384,66 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
|
||||
}
|
||||
}
|
||||
|
||||
void HELPER(exception_return)(CPUARMState *env)
|
||||
{
|
||||
uint32_t spsr = env->banked_spsr[0];
|
||||
int new_el, i;
|
||||
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->sp_el[1] = env->xregs[31];
|
||||
} else {
|
||||
env->sp_el[0] = env->xregs[31];
|
||||
}
|
||||
|
||||
env->exclusive_addr = -1;
|
||||
|
||||
if (spsr & PSTATE_nRW) {
|
||||
env->aarch64 = 0;
|
||||
new_el = 0;
|
||||
env->uncached_cpsr = 0x10;
|
||||
cpsr_write(env, spsr, ~0);
|
||||
for (i = 0; i < 15; i++) {
|
||||
env->regs[i] = env->xregs[i];
|
||||
}
|
||||
|
||||
env->regs[15] = env->elr_el1 & ~0x1;
|
||||
} else {
|
||||
new_el = extract32(spsr, 2, 2);
|
||||
if (new_el > 1) {
|
||||
/* Return to unimplemented EL */
|
||||
goto illegal_return;
|
||||
}
|
||||
if (extract32(spsr, 1, 1)) {
|
||||
/* Return with reserved M[1] bit set */
|
||||
goto illegal_return;
|
||||
}
|
||||
if (new_el == 0 && (spsr & PSTATE_SP)) {
|
||||
/* Return to EL1 with M[0] bit set */
|
||||
goto illegal_return;
|
||||
}
|
||||
env->aarch64 = 1;
|
||||
pstate_write(env, spsr);
|
||||
env->xregs[31] = env->sp_el[new_el];
|
||||
env->pc = env->elr_el1;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
illegal_return:
|
||||
/* Illegal return events of various kinds have architecturally
|
||||
* mandated behaviour:
|
||||
* restore NZCV and DAIF from SPSR_ELx
|
||||
* set PSTATE.IL
|
||||
* restore PC from ELR_ELx
|
||||
* no change to exception level, execution state or stack pointer
|
||||
*/
|
||||
env->pstate |= PSTATE_IL;
|
||||
env->pc = env->elr_el1;
|
||||
spsr &= PSTATE_NZCV | PSTATE_DAIF;
|
||||
spsr |= pstate_read(env) & ~(PSTATE_NZCV | PSTATE_DAIF);
|
||||
pstate_write(env, spsr);
|
||||
}
|
||||
|
||||
/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
|
||||
The only way to do that in TCG is a conditional branch, which clobbers
|
||||
all our temporaries. For now implement these as helper functions. */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "internals.h"
|
||||
#include "disas/disas.h"
|
||||
#include "tcg-op.h"
|
||||
#include "qemu/log.h"
|
||||
@@ -182,12 +183,23 @@ static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
|
||||
/* Set NZCV flags from the high 4 bits of var. */
|
||||
#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)
|
||||
|
||||
static void gen_exception(int excp)
|
||||
static void gen_exception_internal(int excp)
|
||||
{
|
||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||
tcg_gen_movi_i32(tmp, excp);
|
||||
gen_helper_exception(cpu_env, tmp);
|
||||
tcg_temp_free_i32(tmp);
|
||||
TCGv_i32 tcg_excp = tcg_const_i32(excp);
|
||||
|
||||
assert(excp_is_internal(excp));
|
||||
gen_helper_exception_internal(cpu_env, tcg_excp);
|
||||
tcg_temp_free_i32(tcg_excp);
|
||||
}
|
||||
|
||||
static void gen_exception(int excp, uint32_t syndrome)
|
||||
{
|
||||
TCGv_i32 tcg_excp = tcg_const_i32(excp);
|
||||
TCGv_i32 tcg_syn = tcg_const_i32(syndrome);
|
||||
|
||||
gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn);
|
||||
tcg_temp_free_i32(tcg_syn);
|
||||
tcg_temp_free_i32(tcg_excp);
|
||||
}
|
||||
|
||||
static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
|
||||
@@ -899,6 +911,33 @@ static inline void gen_set_pc_im(DisasContext *s, target_ulong val)
|
||||
tcg_gen_movi_i32(cpu_R[15], val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gen_set_condexec (DisasContext *s)
|
||||
{
|
||||
if (s->condexec_mask) {
|
||||
uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
|
||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||
tcg_gen_movi_i32(tmp, val);
|
||||
store_cpu_field(tmp, condexec_bits);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
|
||||
{
|
||||
gen_set_condexec(s);
|
||||
gen_set_pc_im(s, s->pc - offset);
|
||||
gen_exception_internal(excp);
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
static void gen_exception_insn(DisasContext *s, int offset, int excp, int syn)
|
||||
{
|
||||
gen_set_condexec(s);
|
||||
gen_set_pc_im(s, s->pc - offset);
|
||||
gen_exception(excp, syn);
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
/* Force a TB lookup after an instruction that changes the CPU state. */
|
||||
static inline void gen_lookup_tb(DisasContext *s)
|
||||
{
|
||||
@@ -2913,14 +2952,25 @@ static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
||||
if (!arm_feature(env, ARM_FEATURE_VFP))
|
||||
return 1;
|
||||
|
||||
/* FIXME: this access check should not take precedence over UNDEF
|
||||
* for invalid encodings; we will generate incorrect syndrome information
|
||||
* for attempts to execute invalid vfp/neon encodings with FP disabled.
|
||||
*/
|
||||
if (!s->cpacr_fpen) {
|
||||
gen_exception_insn(s, 4, EXCP_UDEF,
|
||||
syn_fp_access_trap(1, 0xe, s->thumb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!s->vfp_enabled) {
|
||||
/* VFP disabled. Only allow fmxr/fmrx to/from some control regs. */
|
||||
if ((insn & 0x0fe00fff) != 0x0ee00a10)
|
||||
return 1;
|
||||
rn = (insn >> 16) & 0xf;
|
||||
if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC
|
||||
&& rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0)
|
||||
if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC && rn != ARM_VFP_MVFR2
|
||||
&& rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (extract32(insn, 28, 4) == 0xf) {
|
||||
@@ -3066,6 +3116,11 @@ static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
||||
gen_helper_vfp_get_fpscr(tmp, cpu_env);
|
||||
}
|
||||
break;
|
||||
case ARM_VFP_MVFR2:
|
||||
if (!arm_feature(env, ARM_FEATURE_V8)) {
|
||||
return 1;
|
||||
}
|
||||
/* fall through */
|
||||
case ARM_VFP_MVFR0:
|
||||
case ARM_VFP_MVFR1:
|
||||
if (IS_USER(s)
|
||||
@@ -3912,25 +3967,6 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
|
||||
s->is_jmp = DISAS_UPDATE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gen_set_condexec (DisasContext *s)
|
||||
{
|
||||
if (s->condexec_mask) {
|
||||
uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
|
||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||
tcg_gen_movi_i32(tmp, val);
|
||||
store_cpu_field(tmp, condexec_bits);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_exception_insn(DisasContext *s, int offset, int excp)
|
||||
{
|
||||
gen_set_condexec(s);
|
||||
gen_set_pc_im(s, s->pc - offset);
|
||||
gen_exception(excp);
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
static void gen_nop_hint(DisasContext *s, int val)
|
||||
{
|
||||
switch (val) {
|
||||
@@ -4212,6 +4248,16 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
||||
TCGv_i32 tmp2;
|
||||
TCGv_i64 tmp64;
|
||||
|
||||
/* FIXME: this access check should not take precedence over UNDEF
|
||||
* for invalid encodings; we will generate incorrect syndrome information
|
||||
* for attempts to execute invalid vfp/neon encodings with FP disabled.
|
||||
*/
|
||||
if (!s->cpacr_fpen) {
|
||||
gen_exception_insn(s, 4, EXCP_UDEF,
|
||||
syn_fp_access_trap(1, 0xe, s->thumb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!s->vfp_enabled)
|
||||
return 1;
|
||||
VFP_DREG_D(rd, insn);
|
||||
@@ -4934,6 +4980,16 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
|
||||
TCGv_i32 tmp, tmp2, tmp3, tmp4, tmp5;
|
||||
TCGv_i64 tmp64;
|
||||
|
||||
/* FIXME: this access check should not take precedence over UNDEF
|
||||
* for invalid encodings; we will generate incorrect syndrome information
|
||||
* for attempts to execute invalid vfp/neon encodings with FP disabled.
|
||||
*/
|
||||
if (!s->cpacr_fpen) {
|
||||
gen_exception_insn(s, 4, EXCP_UDEF,
|
||||
syn_fp_access_trap(1, 0xe, s->thumb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!s->vfp_enabled)
|
||||
return 1;
|
||||
q = (insn & (1 << 6)) != 0;
|
||||
@@ -6861,10 +6917,53 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
||||
* runtime; this may result in an exception.
|
||||
*/
|
||||
TCGv_ptr tmpptr;
|
||||
TCGv_i32 tcg_syn;
|
||||
uint32_t syndrome;
|
||||
|
||||
/* Note that since we are an implementation which takes an
|
||||
* exception on a trapped conditional instruction only if the
|
||||
* instruction passes its condition code check, we can take
|
||||
* advantage of the clause in the ARM ARM that allows us to set
|
||||
* the COND field in the instruction to 0xE in all cases.
|
||||
* We could fish the actual condition out of the insn (ARM)
|
||||
* or the condexec bits (Thumb) but it isn't necessary.
|
||||
*/
|
||||
switch (cpnum) {
|
||||
case 14:
|
||||
if (is64) {
|
||||
syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
|
||||
isread, s->thumb);
|
||||
} else {
|
||||
syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm,
|
||||
rt, isread, s->thumb);
|
||||
}
|
||||
break;
|
||||
case 15:
|
||||
if (is64) {
|
||||
syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
|
||||
isread, s->thumb);
|
||||
} else {
|
||||
syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm,
|
||||
rt, isread, s->thumb);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* ARMv8 defines that only coprocessors 14 and 15 exist,
|
||||
* so this can only happen if this is an ARMv7 or earlier CPU,
|
||||
* in which case the syndrome information won't actually be
|
||||
* guest visible.
|
||||
*/
|
||||
assert(!arm_feature(env, ARM_FEATURE_V8));
|
||||
syndrome = syn_uncategorized();
|
||||
break;
|
||||
}
|
||||
|
||||
gen_set_pc_im(s, s->pc);
|
||||
tmpptr = tcg_const_ptr(ri);
|
||||
gen_helper_access_check_cp_reg(cpu_env, tmpptr);
|
||||
tcg_syn = tcg_const_i32(syndrome);
|
||||
gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn);
|
||||
tcg_temp_free_ptr(tmpptr);
|
||||
tcg_temp_free_i32(tcg_syn);
|
||||
}
|
||||
|
||||
/* Handle special cases first */
|
||||
@@ -7116,7 +7215,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
|
||||
tcg_gen_extu_i32_i64(cpu_exclusive_test, addr);
|
||||
tcg_gen_movi_i32(cpu_exclusive_info,
|
||||
size | (rd << 4) | (rt << 8) | (rt2 << 12));
|
||||
gen_exception_insn(s, 4, EXCP_STREX);
|
||||
gen_exception_internal_insn(s, 4, EXCP_STREX);
|
||||
}
|
||||
#else
|
||||
static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
|
||||
@@ -7626,6 +7725,8 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
|
||||
store_reg(s, rd, tmp);
|
||||
break;
|
||||
case 7:
|
||||
{
|
||||
int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4);
|
||||
/* SMC instruction (op1 == 3)
|
||||
and undefined instructions (op1 == 0 || op1 == 2)
|
||||
will trap */
|
||||
@@ -7634,8 +7735,9 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
|
||||
}
|
||||
/* bkpt */
|
||||
ARCH(5);
|
||||
gen_exception_insn(s, 4, EXCP_BKPT);
|
||||
gen_exception_insn(s, 4, EXCP_BKPT, syn_aa32_bkpt(imm16, false));
|
||||
break;
|
||||
}
|
||||
case 0x8: /* signed multiply */
|
||||
case 0xa:
|
||||
case 0xc:
|
||||
@@ -8328,27 +8430,39 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
|
||||
if (insn & (1 << 5))
|
||||
gen_swap_half(tmp2);
|
||||
gen_smul_dual(tmp, tmp2);
|
||||
if (insn & (1 << 6)) {
|
||||
/* This subtraction cannot overflow. */
|
||||
tcg_gen_sub_i32(tmp, tmp, tmp2);
|
||||
} else {
|
||||
/* This addition cannot overflow 32 bits;
|
||||
* however it may overflow considered as a signed
|
||||
* operation, in which case we must set the Q flag.
|
||||
*/
|
||||
gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
|
||||
}
|
||||
tcg_temp_free_i32(tmp2);
|
||||
if (insn & (1 << 22)) {
|
||||
/* smlald, smlsld */
|
||||
TCGv_i64 tmp64_2;
|
||||
|
||||
tmp64 = tcg_temp_new_i64();
|
||||
tmp64_2 = tcg_temp_new_i64();
|
||||
tcg_gen_ext_i32_i64(tmp64, tmp);
|
||||
tcg_gen_ext_i32_i64(tmp64_2, tmp2);
|
||||
tcg_temp_free_i32(tmp);
|
||||
tcg_temp_free_i32(tmp2);
|
||||
if (insn & (1 << 6)) {
|
||||
tcg_gen_sub_i64(tmp64, tmp64, tmp64_2);
|
||||
} else {
|
||||
tcg_gen_add_i64(tmp64, tmp64, tmp64_2);
|
||||
}
|
||||
tcg_temp_free_i64(tmp64_2);
|
||||
gen_addq(s, tmp64, rd, rn);
|
||||
gen_storeq_reg(s, rd, rn, tmp64);
|
||||
tcg_temp_free_i64(tmp64);
|
||||
} else {
|
||||
/* smuad, smusd, smlad, smlsd */
|
||||
if (insn & (1 << 6)) {
|
||||
/* This subtraction cannot overflow. */
|
||||
tcg_gen_sub_i32(tmp, tmp, tmp2);
|
||||
} else {
|
||||
/* This addition cannot overflow 32 bits;
|
||||
* however it may overflow considered as a
|
||||
* signed operation, in which case we must set
|
||||
* the Q flag.
|
||||
*/
|
||||
gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
|
||||
}
|
||||
tcg_temp_free_i32(tmp2);
|
||||
if (rd != 15)
|
||||
{
|
||||
tmp2 = load_reg(s, rd);
|
||||
@@ -8642,11 +8756,12 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
|
||||
case 0xf:
|
||||
/* swi */
|
||||
gen_set_pc_im(s, s->pc);
|
||||
s->svc_imm = extract32(insn, 0, 24);
|
||||
s->is_jmp = DISAS_SWI;
|
||||
break;
|
||||
default:
|
||||
illegal_op:
|
||||
gen_exception_insn(s, 4, EXCP_UDEF);
|
||||
gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -10457,9 +10572,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
break;
|
||||
|
||||
case 0xe: /* bkpt */
|
||||
{
|
||||
int imm8 = extract32(insn, 0, 8);
|
||||
ARCH(5);
|
||||
gen_exception_insn(s, 2, EXCP_BKPT);
|
||||
gen_exception_insn(s, 2, EXCP_BKPT, syn_aa32_bkpt(imm8, true));
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xa: /* rev */
|
||||
ARCH(6);
|
||||
@@ -10576,6 +10694,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
if (cond == 0xf) {
|
||||
/* swi */
|
||||
gen_set_pc_im(s, s->pc);
|
||||
s->svc_imm = extract32(insn, 0, 8);
|
||||
s->is_jmp = DISAS_SWI;
|
||||
break;
|
||||
}
|
||||
@@ -10611,11 +10730,11 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
}
|
||||
return;
|
||||
undef32:
|
||||
gen_exception_insn(s, 4, EXCP_UDEF);
|
||||
gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized());
|
||||
return;
|
||||
illegal_op:
|
||||
undef:
|
||||
gen_exception_insn(s, 2, EXCP_UDEF);
|
||||
gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized());
|
||||
}
|
||||
|
||||
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
|
||||
@@ -10665,6 +10784,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
|
||||
#endif
|
||||
dc->cpacr_fpen = ARM_TBFLAG_CPACR_FPEN(tb->flags);
|
||||
dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
|
||||
dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
|
||||
dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
|
||||
@@ -10736,7 +10856,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
||||
if (dc->pc >= 0xffff0000) {
|
||||
/* We always get here via a jump, so know we are not in a
|
||||
conditional execution block. */
|
||||
gen_exception(EXCP_KERNEL_TRAP);
|
||||
gen_exception_internal(EXCP_KERNEL_TRAP);
|
||||
dc->is_jmp = DISAS_UPDATE;
|
||||
break;
|
||||
}
|
||||
@@ -10744,7 +10864,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
||||
if (dc->pc >= 0xfffffff0 && IS_M(env)) {
|
||||
/* We always get here via a jump, so know we are not in a
|
||||
conditional execution block. */
|
||||
gen_exception(EXCP_EXCEPTION_EXIT);
|
||||
gen_exception_internal(EXCP_EXCEPTION_EXIT);
|
||||
dc->is_jmp = DISAS_UPDATE;
|
||||
break;
|
||||
}
|
||||
@@ -10753,7 +10873,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
||||
if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
|
||||
QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
|
||||
if (bp->pc == dc->pc) {
|
||||
gen_exception_insn(dc, 0, EXCP_DEBUG);
|
||||
gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
|
||||
/* Advance PC so that clearing the breakpoint will
|
||||
invalidate this TB. */
|
||||
dc->pc += 2;
|
||||
@@ -10833,9 +10953,9 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
||||
if (dc->condjmp) {
|
||||
gen_set_condexec(dc);
|
||||
if (dc->is_jmp == DISAS_SWI) {
|
||||
gen_exception(EXCP_SWI);
|
||||
gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
|
||||
} else {
|
||||
gen_exception(EXCP_DEBUG);
|
||||
gen_exception_internal(EXCP_DEBUG);
|
||||
}
|
||||
gen_set_label(dc->condlabel);
|
||||
}
|
||||
@@ -10845,11 +10965,11 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
||||
}
|
||||
gen_set_condexec(dc);
|
||||
if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
|
||||
gen_exception(EXCP_SWI);
|
||||
gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
|
||||
} else {
|
||||
/* FIXME: Single stepping a WFI insn will not halt
|
||||
the CPU. */
|
||||
gen_exception(EXCP_DEBUG);
|
||||
gen_exception_internal(EXCP_DEBUG);
|
||||
}
|
||||
} else {
|
||||
/* While branches must always occur at the end of an IT block,
|
||||
@@ -10881,7 +11001,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
||||
gen_helper_wfe(cpu_env);
|
||||
break;
|
||||
case DISAS_SWI:
|
||||
gen_exception(EXCP_SWI);
|
||||
gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
|
||||
break;
|
||||
}
|
||||
if (dc->condjmp) {
|
||||
@@ -10939,6 +11059,11 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
|
||||
int i;
|
||||
uint32_t psr;
|
||||
|
||||
if (is_a64(env)) {
|
||||
aarch64_cpu_dump_state(cs, f, cpu_fprintf, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
for(i=0;i<16;i++) {
|
||||
cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
|
||||
if ((i % 4) == 3)
|
||||
|
||||
@@ -20,13 +20,26 @@ typedef struct DisasContext {
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
int user;
|
||||
#endif
|
||||
int vfp_enabled;
|
||||
bool cpacr_fpen; /* FP enabled via CPACR.FPEN */
|
||||
bool vfp_enabled; /* FP enabled via FPSCR.EN */
|
||||
int vec_len;
|
||||
int vec_stride;
|
||||
/* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
|
||||
* so that top level loop can generate correct syndrome information.
|
||||
*/
|
||||
uint32_t svc_imm;
|
||||
int aarch64;
|
||||
int current_pl;
|
||||
GHashTable *cp_regs;
|
||||
uint64_t features; /* CPU features bits */
|
||||
/* Because unallocated encodings generate different exception syndrome
|
||||
* information from traps due to FP being disabled, we can't do a single
|
||||
* "is fp access disabled" check at a high level in the decode tree.
|
||||
* To help in catching bugs where the access check was forgotten in some
|
||||
* code path, we set this flag when the access check is done, and assert
|
||||
* that it is set at the point where we actually touch the FP regs.
|
||||
*/
|
||||
bool fp_access_checked;
|
||||
#define TMP_A64_MAX 16
|
||||
int tmp_a64_count;
|
||||
TCGv_i64 tmp_a64[TMP_A64_MAX];
|
||||
@@ -59,6 +72,8 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
|
||||
TranslationBlock *tb,
|
||||
bool search_pc);
|
||||
void gen_a64_set_pc_im(uint64_t val);
|
||||
void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
|
||||
fprintf_function cpu_fprintf, int flags);
|
||||
#else
|
||||
static inline void a64_translate_init(void)
|
||||
{
|
||||
@@ -73,6 +88,12 @@ static inline void gen_intermediate_code_internal_a64(ARMCPU *cpu,
|
||||
static inline void gen_a64_set_pc_im(uint64_t val)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
|
||||
fprintf_function cpu_fprintf,
|
||||
int flags)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void arm_gen_test_cc(int cc, int label);
|
||||
|
||||
@@ -1133,6 +1133,7 @@ uint64_t cpu_ppc_load_atbl (CPUPPCState *env);
|
||||
uint32_t cpu_ppc_load_atbu (CPUPPCState *env);
|
||||
void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value);
|
||||
void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value);
|
||||
bool ppc_decr_clear_on_delivery(CPUPPCState *env);
|
||||
uint32_t cpu_ppc_load_decr (CPUPPCState *env);
|
||||
void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value);
|
||||
uint32_t cpu_ppc_load_hdecr (CPUPPCState *env);
|
||||
|
||||
@@ -723,7 +723,6 @@ void ppc_hw_interrupt(CPUPPCState *env)
|
||||
if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
|
||||
/* Hypervisor decrementer exception */
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
|
||||
return;
|
||||
}
|
||||
@@ -767,7 +766,9 @@ void ppc_hw_interrupt(CPUPPCState *env)
|
||||
}
|
||||
/* Decrementer exception */
|
||||
if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
|
||||
if (ppc_decr_clear_on_delivery(env)) {
|
||||
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
|
||||
}
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1782,11 +1782,19 @@ typedef union _ppc_vsr_t {
|
||||
float64 f64[2];
|
||||
} ppc_vsr_t;
|
||||
|
||||
#if defined(HOST_WORDS_BIGENDIAN)
|
||||
#define VsrW(i) u32[i]
|
||||
#define VsrD(i) u64[i]
|
||||
#else
|
||||
#define VsrW(i) u32[3-(i)]
|
||||
#define VsrD(i) u64[1-(i)]
|
||||
#endif
|
||||
|
||||
static void getVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
|
||||
{
|
||||
if (n < 32) {
|
||||
vsr->f64[0] = env->fpr[n];
|
||||
vsr->u64[1] = env->vsr[n];
|
||||
vsr->VsrD(0) = env->fpr[n];
|
||||
vsr->VsrD(1) = env->vsr[n];
|
||||
} else {
|
||||
vsr->u64[0] = env->avr[n-32].u64[0];
|
||||
vsr->u64[1] = env->avr[n-32].u64[1];
|
||||
@@ -1796,8 +1804,8 @@ static void getVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
|
||||
static void putVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
|
||||
{
|
||||
if (n < 32) {
|
||||
env->fpr[n] = vsr->f64[0];
|
||||
env->vsr[n] = vsr->u64[1];
|
||||
env->fpr[n] = vsr->VsrD(0);
|
||||
env->vsr[n] = vsr->VsrD(1);
|
||||
} else {
|
||||
env->avr[n-32].u64[0] = vsr->u64[0];
|
||||
env->avr[n-32].u64[1] = vsr->u64[1];
|
||||
@@ -1812,7 +1820,7 @@ static void putVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
|
||||
* op - operation (add or sub)
|
||||
* nels - number of elements (1, 2 or 4)
|
||||
* tp - type (float32 or float64)
|
||||
* fld - vsr_t field (f32 or f64)
|
||||
* fld - vsr_t field (VsrD(*) or VsrW(*))
|
||||
* sfprf - set FPRF
|
||||
*/
|
||||
#define VSX_ADD_SUB(name, op, nels, tp, fld, sfprf, r2sp) \
|
||||
@@ -1829,44 +1837,44 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \
|
||||
for (i = 0; i < nels; i++) { \
|
||||
float_status tstat = env->fp_status; \
|
||||
set_float_exception_flags(0, &tstat); \
|
||||
xt.fld[i] = tp##_##op(xa.fld[i], xb.fld[i], &tstat); \
|
||||
xt.fld = tp##_##op(xa.fld, xb.fld, &tstat); \
|
||||
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
|
||||
\
|
||||
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
|
||||
if (tp##_is_infinity(xa.fld[i]) && tp##_is_infinity(xb.fld[i])) {\
|
||||
if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \
|
||||
} else if (tp##_is_signaling_nan(xa.fld[i]) || \
|
||||
tp##_is_signaling_nan(xb.fld[i])) { \
|
||||
} else if (tp##_is_signaling_nan(xa.fld) || \
|
||||
tp##_is_signaling_nan(xb.fld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (r2sp) { \
|
||||
xt.fld[i] = helper_frsp(env, xt.fld[i]); \
|
||||
xt.fld = helper_frsp(env, xt.fld); \
|
||||
} \
|
||||
\
|
||||
if (sfprf) { \
|
||||
helper_compute_fprf(env, xt.fld[i], sfprf); \
|
||||
helper_compute_fprf(env, xt.fld, sfprf); \
|
||||
} \
|
||||
} \
|
||||
putVSR(xT(opcode), &xt, env); \
|
||||
helper_float_check_status(env); \
|
||||
}
|
||||
|
||||
VSX_ADD_SUB(xsadddp, add, 1, float64, f64, 1, 0)
|
||||
VSX_ADD_SUB(xsaddsp, add, 1, float64, f64, 1, 1)
|
||||
VSX_ADD_SUB(xvadddp, add, 2, float64, f64, 0, 0)
|
||||
VSX_ADD_SUB(xvaddsp, add, 4, float32, f32, 0, 0)
|
||||
VSX_ADD_SUB(xssubdp, sub, 1, float64, f64, 1, 0)
|
||||
VSX_ADD_SUB(xssubsp, sub, 1, float64, f64, 1, 1)
|
||||
VSX_ADD_SUB(xvsubdp, sub, 2, float64, f64, 0, 0)
|
||||
VSX_ADD_SUB(xvsubsp, sub, 4, float32, f32, 0, 0)
|
||||
VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0)
|
||||
VSX_ADD_SUB(xsaddsp, add, 1, float64, VsrD(0), 1, 1)
|
||||
VSX_ADD_SUB(xvadddp, add, 2, float64, VsrD(i), 0, 0)
|
||||
VSX_ADD_SUB(xvaddsp, add, 4, float32, VsrW(i), 0, 0)
|
||||
VSX_ADD_SUB(xssubdp, sub, 1, float64, VsrD(0), 1, 0)
|
||||
VSX_ADD_SUB(xssubsp, sub, 1, float64, VsrD(0), 1, 1)
|
||||
VSX_ADD_SUB(xvsubdp, sub, 2, float64, VsrD(i), 0, 0)
|
||||
VSX_ADD_SUB(xvsubsp, sub, 4, float32, VsrW(i), 0, 0)
|
||||
|
||||
/* VSX_MUL - VSX floating point multiply
|
||||
* op - instruction mnemonic
|
||||
* nels - number of elements (1, 2 or 4)
|
||||
* tp - type (float32 or float64)
|
||||
* fld - vsr_t field (f32 or f64)
|
||||
* fld - vsr_t field (VsrD(*) or VsrW(*))
|
||||
* sfprf - set FPRF
|
||||
*/
|
||||
#define VSX_MUL(op, nels, tp, fld, sfprf, r2sp) \
|
||||
@@ -1883,25 +1891,25 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
for (i = 0; i < nels; i++) { \
|
||||
float_status tstat = env->fp_status; \
|
||||
set_float_exception_flags(0, &tstat); \
|
||||
xt.fld[i] = tp##_mul(xa.fld[i], xb.fld[i], &tstat); \
|
||||
xt.fld = tp##_mul(xa.fld, xb.fld, &tstat); \
|
||||
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
|
||||
\
|
||||
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
|
||||
if ((tp##_is_infinity(xa.fld[i]) && tp##_is_zero(xb.fld[i])) || \
|
||||
(tp##_is_infinity(xb.fld[i]) && tp##_is_zero(xa.fld[i]))) { \
|
||||
if ((tp##_is_infinity(xa.fld) && tp##_is_zero(xb.fld)) || \
|
||||
(tp##_is_infinity(xb.fld) && tp##_is_zero(xa.fld))) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf); \
|
||||
} else if (tp##_is_signaling_nan(xa.fld[i]) || \
|
||||
tp##_is_signaling_nan(xb.fld[i])) { \
|
||||
} else if (tp##_is_signaling_nan(xa.fld) || \
|
||||
tp##_is_signaling_nan(xb.fld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (r2sp) { \
|
||||
xt.fld[i] = helper_frsp(env, xt.fld[i]); \
|
||||
xt.fld = helper_frsp(env, xt.fld); \
|
||||
} \
|
||||
\
|
||||
if (sfprf) { \
|
||||
helper_compute_fprf(env, xt.fld[i], sfprf); \
|
||||
helper_compute_fprf(env, xt.fld, sfprf); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
@@ -1909,16 +1917,16 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
helper_float_check_status(env); \
|
||||
}
|
||||
|
||||
VSX_MUL(xsmuldp, 1, float64, f64, 1, 0)
|
||||
VSX_MUL(xsmulsp, 1, float64, f64, 1, 1)
|
||||
VSX_MUL(xvmuldp, 2, float64, f64, 0, 0)
|
||||
VSX_MUL(xvmulsp, 4, float32, f32, 0, 0)
|
||||
VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0)
|
||||
VSX_MUL(xsmulsp, 1, float64, VsrD(0), 1, 1)
|
||||
VSX_MUL(xvmuldp, 2, float64, VsrD(i), 0, 0)
|
||||
VSX_MUL(xvmulsp, 4, float32, VsrW(i), 0, 0)
|
||||
|
||||
/* VSX_DIV - VSX floating point divide
|
||||
* op - instruction mnemonic
|
||||
* nels - number of elements (1, 2 or 4)
|
||||
* tp - type (float32 or float64)
|
||||
* fld - vsr_t field (f32 or f64)
|
||||
* fld - vsr_t field (VsrD(*) or VsrW(*))
|
||||
* sfprf - set FPRF
|
||||
*/
|
||||
#define VSX_DIV(op, nels, tp, fld, sfprf, r2sp) \
|
||||
@@ -1935,27 +1943,27 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
for (i = 0; i < nels; i++) { \
|
||||
float_status tstat = env->fp_status; \
|
||||
set_float_exception_flags(0, &tstat); \
|
||||
xt.fld[i] = tp##_div(xa.fld[i], xb.fld[i], &tstat); \
|
||||
xt.fld = tp##_div(xa.fld, xb.fld, &tstat); \
|
||||
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
|
||||
\
|
||||
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
|
||||
if (tp##_is_infinity(xa.fld[i]) && tp##_is_infinity(xb.fld[i])) { \
|
||||
if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf); \
|
||||
} else if (tp##_is_zero(xa.fld[i]) && \
|
||||
tp##_is_zero(xb.fld[i])) { \
|
||||
} else if (tp##_is_zero(xa.fld) && \
|
||||
tp##_is_zero(xb.fld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf); \
|
||||
} else if (tp##_is_signaling_nan(xa.fld[i]) || \
|
||||
tp##_is_signaling_nan(xb.fld[i])) { \
|
||||
} else if (tp##_is_signaling_nan(xa.fld) || \
|
||||
tp##_is_signaling_nan(xb.fld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (r2sp) { \
|
||||
xt.fld[i] = helper_frsp(env, xt.fld[i]); \
|
||||
xt.fld = helper_frsp(env, xt.fld); \
|
||||
} \
|
||||
\
|
||||
if (sfprf) { \
|
||||
helper_compute_fprf(env, xt.fld[i], sfprf); \
|
||||
helper_compute_fprf(env, xt.fld, sfprf); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
@@ -1963,16 +1971,16 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
helper_float_check_status(env); \
|
||||
}
|
||||
|
||||
VSX_DIV(xsdivdp, 1, float64, f64, 1, 0)
|
||||
VSX_DIV(xsdivsp, 1, float64, f64, 1, 1)
|
||||
VSX_DIV(xvdivdp, 2, float64, f64, 0, 0)
|
||||
VSX_DIV(xvdivsp, 4, float32, f32, 0, 0)
|
||||
VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0)
|
||||
VSX_DIV(xsdivsp, 1, float64, VsrD(0), 1, 1)
|
||||
VSX_DIV(xvdivdp, 2, float64, VsrD(i), 0, 0)
|
||||
VSX_DIV(xvdivsp, 4, float32, VsrW(i), 0, 0)
|
||||
|
||||
/* VSX_RE - VSX floating point reciprocal estimate
|
||||
* op - instruction mnemonic
|
||||
* nels - number of elements (1, 2 or 4)
|
||||
* tp - type (float32 or float64)
|
||||
* fld - vsr_t field (f32 or f64)
|
||||
* fld - vsr_t field (VsrD(*) or VsrW(*))
|
||||
* sfprf - set FPRF
|
||||
*/
|
||||
#define VSX_RE(op, nels, tp, fld, sfprf, r2sp) \
|
||||
@@ -1986,17 +1994,17 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
helper_reset_fpstatus(env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
if (unlikely(tp##_is_signaling_nan(xb.fld[i]))) { \
|
||||
if (unlikely(tp##_is_signaling_nan(xb.fld))) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
|
||||
} \
|
||||
xt.fld[i] = tp##_div(tp##_one, xb.fld[i], &env->fp_status); \
|
||||
xt.fld = tp##_div(tp##_one, xb.fld, &env->fp_status); \
|
||||
\
|
||||
if (r2sp) { \
|
||||
xt.fld[i] = helper_frsp(env, xt.fld[i]); \
|
||||
xt.fld = helper_frsp(env, xt.fld); \
|
||||
} \
|
||||
\
|
||||
if (sfprf) { \
|
||||
helper_compute_fprf(env, xt.fld[0], sfprf); \
|
||||
helper_compute_fprf(env, xt.fld, sfprf); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
@@ -2004,16 +2012,16 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
helper_float_check_status(env); \
|
||||
}
|
||||
|
||||
VSX_RE(xsredp, 1, float64, f64, 1, 0)
|
||||
VSX_RE(xsresp, 1, float64, f64, 1, 1)
|
||||
VSX_RE(xvredp, 2, float64, f64, 0, 0)
|
||||
VSX_RE(xvresp, 4, float32, f32, 0, 0)
|
||||
VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0)
|
||||
VSX_RE(xsresp, 1, float64, VsrD(0), 1, 1)
|
||||
VSX_RE(xvredp, 2, float64, VsrD(i), 0, 0)
|
||||
VSX_RE(xvresp, 4, float32, VsrW(i), 0, 0)
|
||||
|
||||
/* VSX_SQRT - VSX floating point square root
|
||||
* op - instruction mnemonic
|
||||
* nels - number of elements (1, 2 or 4)
|
||||
* tp - type (float32 or float64)
|
||||
* fld - vsr_t field (f32 or f64)
|
||||
* fld - vsr_t field (VsrD(*) or VsrW(*))
|
||||
* sfprf - set FPRF
|
||||
*/
|
||||
#define VSX_SQRT(op, nels, tp, fld, sfprf, r2sp) \
|
||||
@@ -2029,23 +2037,23 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
for (i = 0; i < nels; i++) { \
|
||||
float_status tstat = env->fp_status; \
|
||||
set_float_exception_flags(0, &tstat); \
|
||||
xt.fld[i] = tp##_sqrt(xb.fld[i], &tstat); \
|
||||
xt.fld = tp##_sqrt(xb.fld, &tstat); \
|
||||
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
|
||||
\
|
||||
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
|
||||
if (tp##_is_neg(xb.fld[i]) && !tp##_is_zero(xb.fld[i])) { \
|
||||
if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \
|
||||
} else if (tp##_is_signaling_nan(xb.fld[i])) { \
|
||||
} else if (tp##_is_signaling_nan(xb.fld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (r2sp) { \
|
||||
xt.fld[i] = helper_frsp(env, xt.fld[i]); \
|
||||
xt.fld = helper_frsp(env, xt.fld); \
|
||||
} \
|
||||
\
|
||||
if (sfprf) { \
|
||||
helper_compute_fprf(env, xt.fld[i], sfprf); \
|
||||
helper_compute_fprf(env, xt.fld, sfprf); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
@@ -2053,16 +2061,16 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
helper_float_check_status(env); \
|
||||
}
|
||||
|
||||
VSX_SQRT(xssqrtdp, 1, float64, f64, 1, 0)
|
||||
VSX_SQRT(xssqrtsp, 1, float64, f64, 1, 1)
|
||||
VSX_SQRT(xvsqrtdp, 2, float64, f64, 0, 0)
|
||||
VSX_SQRT(xvsqrtsp, 4, float32, f32, 0, 0)
|
||||
VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0)
|
||||
VSX_SQRT(xssqrtsp, 1, float64, VsrD(0), 1, 1)
|
||||
VSX_SQRT(xvsqrtdp, 2, float64, VsrD(i), 0, 0)
|
||||
VSX_SQRT(xvsqrtsp, 4, float32, VsrW(i), 0, 0)
|
||||
|
||||
/* VSX_RSQRTE - VSX floating point reciprocal square root estimate
|
||||
* op - instruction mnemonic
|
||||
* nels - number of elements (1, 2 or 4)
|
||||
* tp - type (float32 or float64)
|
||||
* fld - vsr_t field (f32 or f64)
|
||||
* fld - vsr_t field (VsrD(*) or VsrW(*))
|
||||
* sfprf - set FPRF
|
||||
*/
|
||||
#define VSX_RSQRTE(op, nels, tp, fld, sfprf, r2sp) \
|
||||
@@ -2078,24 +2086,24 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
for (i = 0; i < nels; i++) { \
|
||||
float_status tstat = env->fp_status; \
|
||||
set_float_exception_flags(0, &tstat); \
|
||||
xt.fld[i] = tp##_sqrt(xb.fld[i], &tstat); \
|
||||
xt.fld[i] = tp##_div(tp##_one, xt.fld[i], &tstat); \
|
||||
xt.fld = tp##_sqrt(xb.fld, &tstat); \
|
||||
xt.fld = tp##_div(tp##_one, xt.fld, &tstat); \
|
||||
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
|
||||
\
|
||||
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
|
||||
if (tp##_is_neg(xb.fld[i]) && !tp##_is_zero(xb.fld[i])) { \
|
||||
if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \
|
||||
} else if (tp##_is_signaling_nan(xb.fld[i])) { \
|
||||
} else if (tp##_is_signaling_nan(xb.fld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (r2sp) { \
|
||||
xt.fld[i] = helper_frsp(env, xt.fld[i]); \
|
||||
xt.fld = helper_frsp(env, xt.fld); \
|
||||
} \
|
||||
\
|
||||
if (sfprf) { \
|
||||
helper_compute_fprf(env, xt.fld[i], sfprf); \
|
||||
helper_compute_fprf(env, xt.fld, sfprf); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
@@ -2103,16 +2111,16 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
helper_float_check_status(env); \
|
||||
}
|
||||
|
||||
VSX_RSQRTE(xsrsqrtedp, 1, float64, f64, 1, 0)
|
||||
VSX_RSQRTE(xsrsqrtesp, 1, float64, f64, 1, 1)
|
||||
VSX_RSQRTE(xvrsqrtedp, 2, float64, f64, 0, 0)
|
||||
VSX_RSQRTE(xvrsqrtesp, 4, float32, f32, 0, 0)
|
||||
VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0)
|
||||
VSX_RSQRTE(xsrsqrtesp, 1, float64, VsrD(0), 1, 1)
|
||||
VSX_RSQRTE(xvrsqrtedp, 2, float64, VsrD(i), 0, 0)
|
||||
VSX_RSQRTE(xvrsqrtesp, 4, float32, VsrW(i), 0, 0)
|
||||
|
||||
/* VSX_TDIV - VSX floating point test for divide
|
||||
* op - instruction mnemonic
|
||||
* nels - number of elements (1, 2 or 4)
|
||||
* tp - type (float32 or float64)
|
||||
* fld - vsr_t field (f32 or f64)
|
||||
* fld - vsr_t field (VsrD(*) or VsrW(*))
|
||||
* emin - minimum unbiased exponent
|
||||
* emax - maximum unbiased exponent
|
||||
* nbits - number of fraction bits
|
||||
@@ -2129,28 +2137,28 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
getVSR(xB(opcode), &xb, env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
if (unlikely(tp##_is_infinity(xa.fld[i]) || \
|
||||
tp##_is_infinity(xb.fld[i]) || \
|
||||
tp##_is_zero(xb.fld[i]))) { \
|
||||
if (unlikely(tp##_is_infinity(xa.fld) || \
|
||||
tp##_is_infinity(xb.fld) || \
|
||||
tp##_is_zero(xb.fld))) { \
|
||||
fe_flag = 1; \
|
||||
fg_flag = 1; \
|
||||
} else { \
|
||||
int e_a = ppc_##tp##_get_unbiased_exp(xa.fld[i]); \
|
||||
int e_b = ppc_##tp##_get_unbiased_exp(xb.fld[i]); \
|
||||
int e_a = ppc_##tp##_get_unbiased_exp(xa.fld); \
|
||||
int e_b = ppc_##tp##_get_unbiased_exp(xb.fld); \
|
||||
\
|
||||
if (unlikely(tp##_is_any_nan(xa.fld[i]) || \
|
||||
tp##_is_any_nan(xb.fld[i]))) { \
|
||||
if (unlikely(tp##_is_any_nan(xa.fld) || \
|
||||
tp##_is_any_nan(xb.fld))) { \
|
||||
fe_flag = 1; \
|
||||
} else if ((e_b <= emin) || (e_b >= (emax-2))) { \
|
||||
fe_flag = 1; \
|
||||
} else if (!tp##_is_zero(xa.fld[i]) && \
|
||||
} else if (!tp##_is_zero(xa.fld) && \
|
||||
(((e_a - e_b) >= emax) || \
|
||||
((e_a - e_b) <= (emin+1)) || \
|
||||
(e_a <= (emin+nbits)))) { \
|
||||
fe_flag = 1; \
|
||||
} \
|
||||
\
|
||||
if (unlikely(tp##_is_zero_or_denormal(xb.fld[i]))) { \
|
||||
if (unlikely(tp##_is_zero_or_denormal(xb.fld))) { \
|
||||
/* XB is not zero because of the above check and */ \
|
||||
/* so must be denormalized. */ \
|
||||
fg_flag = 1; \
|
||||
@@ -2161,15 +2169,15 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \
|
||||
}
|
||||
|
||||
VSX_TDIV(xstdivdp, 1, float64, f64, -1022, 1023, 52)
|
||||
VSX_TDIV(xvtdivdp, 2, float64, f64, -1022, 1023, 52)
|
||||
VSX_TDIV(xvtdivsp, 4, float32, f32, -126, 127, 23)
|
||||
VSX_TDIV(xstdivdp, 1, float64, VsrD(0), -1022, 1023, 52)
|
||||
VSX_TDIV(xvtdivdp, 2, float64, VsrD(i), -1022, 1023, 52)
|
||||
VSX_TDIV(xvtdivsp, 4, float32, VsrW(i), -126, 127, 23)
|
||||
|
||||
/* VSX_TSQRT - VSX floating point test for square root
|
||||
* op - instruction mnemonic
|
||||
* nels - number of elements (1, 2 or 4)
|
||||
* tp - type (float32 or float64)
|
||||
* fld - vsr_t field (f32 or f64)
|
||||
* fld - vsr_t field (VsrD(*) or VsrW(*))
|
||||
* emin - minimum unbiased exponent
|
||||
* emax - maximum unbiased exponent
|
||||
* nbits - number of fraction bits
|
||||
@@ -2186,25 +2194,25 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
getVSR(xB(opcode), &xb, env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
if (unlikely(tp##_is_infinity(xb.fld[i]) || \
|
||||
tp##_is_zero(xb.fld[i]))) { \
|
||||
if (unlikely(tp##_is_infinity(xb.fld) || \
|
||||
tp##_is_zero(xb.fld))) { \
|
||||
fe_flag = 1; \
|
||||
fg_flag = 1; \
|
||||
} else { \
|
||||
int e_b = ppc_##tp##_get_unbiased_exp(xb.fld[i]); \
|
||||
int e_b = ppc_##tp##_get_unbiased_exp(xb.fld); \
|
||||
\
|
||||
if (unlikely(tp##_is_any_nan(xb.fld[i]))) { \
|
||||
if (unlikely(tp##_is_any_nan(xb.fld))) { \
|
||||
fe_flag = 1; \
|
||||
} else if (unlikely(tp##_is_zero(xb.fld[i]))) { \
|
||||
} else if (unlikely(tp##_is_zero(xb.fld))) { \
|
||||
fe_flag = 1; \
|
||||
} else if (unlikely(tp##_is_neg(xb.fld[i]))) { \
|
||||
} else if (unlikely(tp##_is_neg(xb.fld))) { \
|
||||
fe_flag = 1; \
|
||||
} else if (!tp##_is_zero(xb.fld[i]) && \
|
||||
} else if (!tp##_is_zero(xb.fld) && \
|
||||
(e_b <= (emin+nbits))) { \
|
||||
fe_flag = 1; \
|
||||
} \
|
||||
\
|
||||
if (unlikely(tp##_is_zero_or_denormal(xb.fld[i]))) { \
|
||||
if (unlikely(tp##_is_zero_or_denormal(xb.fld))) { \
|
||||
/* XB is not zero because of the above check and */ \
|
||||
/* therefore must be denormalized. */ \
|
||||
fg_flag = 1; \
|
||||
@@ -2215,15 +2223,15 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \
|
||||
}
|
||||
|
||||
VSX_TSQRT(xstsqrtdp, 1, float64, f64, -1022, 52)
|
||||
VSX_TSQRT(xvtsqrtdp, 2, float64, f64, -1022, 52)
|
||||
VSX_TSQRT(xvtsqrtsp, 4, float32, f32, -126, 23)
|
||||
VSX_TSQRT(xstsqrtdp, 1, float64, VsrD(0), -1022, 52)
|
||||
VSX_TSQRT(xvtsqrtdp, 2, float64, VsrD(i), -1022, 52)
|
||||
VSX_TSQRT(xvtsqrtsp, 4, float32, VsrW(i), -126, 23)
|
||||
|
||||
/* VSX_MADD - VSX floating point muliply/add variations
|
||||
* op - instruction mnemonic
|
||||
* nels - number of elements (1, 2 or 4)
|
||||
* tp - type (float32 or float64)
|
||||
* fld - vsr_t field (f32 or f64)
|
||||
* fld - vsr_t field (VsrD(*) or VsrW(*))
|
||||
* maddflgs - flags for the float*muladd routine that control the
|
||||
* various forms (madd, msub, nmadd, nmsub)
|
||||
* afrm - A form (1=A, 0=M)
|
||||
@@ -2259,43 +2267,43 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
/* Avoid double rounding errors by rounding the intermediate */ \
|
||||
/* result to odd. */ \
|
||||
set_float_rounding_mode(float_round_to_zero, &tstat); \
|
||||
xt_out.fld[i] = tp##_muladd(xa.fld[i], b->fld[i], c->fld[i], \
|
||||
xt_out.fld = tp##_muladd(xa.fld, b->fld, c->fld, \
|
||||
maddflgs, &tstat); \
|
||||
xt_out.fld[i] |= (get_float_exception_flags(&tstat) & \
|
||||
xt_out.fld |= (get_float_exception_flags(&tstat) & \
|
||||
float_flag_inexact) != 0; \
|
||||
} else { \
|
||||
xt_out.fld[i] = tp##_muladd(xa.fld[i], b->fld[i], c->fld[i], \
|
||||
xt_out.fld = tp##_muladd(xa.fld, b->fld, c->fld, \
|
||||
maddflgs, &tstat); \
|
||||
} \
|
||||
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
|
||||
\
|
||||
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
|
||||
if (tp##_is_signaling_nan(xa.fld[i]) || \
|
||||
tp##_is_signaling_nan(b->fld[i]) || \
|
||||
tp##_is_signaling_nan(c->fld[i])) { \
|
||||
if (tp##_is_signaling_nan(xa.fld) || \
|
||||
tp##_is_signaling_nan(b->fld) || \
|
||||
tp##_is_signaling_nan(c->fld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
|
||||
tstat.float_exception_flags &= ~float_flag_invalid; \
|
||||
} \
|
||||
if ((tp##_is_infinity(xa.fld[i]) && tp##_is_zero(b->fld[i])) || \
|
||||
(tp##_is_zero(xa.fld[i]) && tp##_is_infinity(b->fld[i]))) { \
|
||||
xt_out.fld[i] = float64_to_##tp(fload_invalid_op_excp(env, \
|
||||
if ((tp##_is_infinity(xa.fld) && tp##_is_zero(b->fld)) || \
|
||||
(tp##_is_zero(xa.fld) && tp##_is_infinity(b->fld))) { \
|
||||
xt_out.fld = float64_to_##tp(fload_invalid_op_excp(env, \
|
||||
POWERPC_EXCP_FP_VXIMZ, sfprf), &env->fp_status); \
|
||||
tstat.float_exception_flags &= ~float_flag_invalid; \
|
||||
} \
|
||||
if ((tstat.float_exception_flags & float_flag_invalid) && \
|
||||
((tp##_is_infinity(xa.fld[i]) || \
|
||||
tp##_is_infinity(b->fld[i])) && \
|
||||
tp##_is_infinity(c->fld[i]))) { \
|
||||
((tp##_is_infinity(xa.fld) || \
|
||||
tp##_is_infinity(b->fld)) && \
|
||||
tp##_is_infinity(c->fld))) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (r2sp) { \
|
||||
xt_out.fld[i] = helper_frsp(env, xt_out.fld[i]); \
|
||||
xt_out.fld = helper_frsp(env, xt_out.fld); \
|
||||
} \
|
||||
\
|
||||
if (sfprf) { \
|
||||
helper_compute_fprf(env, xt_out.fld[i], sfprf); \
|
||||
helper_compute_fprf(env, xt_out.fld, sfprf); \
|
||||
} \
|
||||
} \
|
||||
putVSR(xT(opcode), &xt_out, env); \
|
||||
@@ -2307,41 +2315,41 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
#define NMADD_FLGS float_muladd_negate_result
|
||||
#define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
|
||||
|
||||
VSX_MADD(xsmaddadp, 1, float64, f64, MADD_FLGS, 1, 1, 0)
|
||||
VSX_MADD(xsmaddmdp, 1, float64, f64, MADD_FLGS, 0, 1, 0)
|
||||
VSX_MADD(xsmsubadp, 1, float64, f64, MSUB_FLGS, 1, 1, 0)
|
||||
VSX_MADD(xsmsubmdp, 1, float64, f64, MSUB_FLGS, 0, 1, 0)
|
||||
VSX_MADD(xsnmaddadp, 1, float64, f64, NMADD_FLGS, 1, 1, 0)
|
||||
VSX_MADD(xsnmaddmdp, 1, float64, f64, NMADD_FLGS, 0, 1, 0)
|
||||
VSX_MADD(xsnmsubadp, 1, float64, f64, NMSUB_FLGS, 1, 1, 0)
|
||||
VSX_MADD(xsnmsubmdp, 1, float64, f64, NMSUB_FLGS, 0, 1, 0)
|
||||
VSX_MADD(xsmaddadp, 1, float64, VsrD(0), MADD_FLGS, 1, 1, 0)
|
||||
VSX_MADD(xsmaddmdp, 1, float64, VsrD(0), MADD_FLGS, 0, 1, 0)
|
||||
VSX_MADD(xsmsubadp, 1, float64, VsrD(0), MSUB_FLGS, 1, 1, 0)
|
||||
VSX_MADD(xsmsubmdp, 1, float64, VsrD(0), MSUB_FLGS, 0, 1, 0)
|
||||
VSX_MADD(xsnmaddadp, 1, float64, VsrD(0), NMADD_FLGS, 1, 1, 0)
|
||||
VSX_MADD(xsnmaddmdp, 1, float64, VsrD(0), NMADD_FLGS, 0, 1, 0)
|
||||
VSX_MADD(xsnmsubadp, 1, float64, VsrD(0), NMSUB_FLGS, 1, 1, 0)
|
||||
VSX_MADD(xsnmsubmdp, 1, float64, VsrD(0), NMSUB_FLGS, 0, 1, 0)
|
||||
|
||||
VSX_MADD(xsmaddasp, 1, float64, f64, MADD_FLGS, 1, 1, 1)
|
||||
VSX_MADD(xsmaddmsp, 1, float64, f64, MADD_FLGS, 0, 1, 1)
|
||||
VSX_MADD(xsmsubasp, 1, float64, f64, MSUB_FLGS, 1, 1, 1)
|
||||
VSX_MADD(xsmsubmsp, 1, float64, f64, MSUB_FLGS, 0, 1, 1)
|
||||
VSX_MADD(xsnmaddasp, 1, float64, f64, NMADD_FLGS, 1, 1, 1)
|
||||
VSX_MADD(xsnmaddmsp, 1, float64, f64, NMADD_FLGS, 0, 1, 1)
|
||||
VSX_MADD(xsnmsubasp, 1, float64, f64, NMSUB_FLGS, 1, 1, 1)
|
||||
VSX_MADD(xsnmsubmsp, 1, float64, f64, NMSUB_FLGS, 0, 1, 1)
|
||||
VSX_MADD(xsmaddasp, 1, float64, VsrD(0), MADD_FLGS, 1, 1, 1)
|
||||
VSX_MADD(xsmaddmsp, 1, float64, VsrD(0), MADD_FLGS, 0, 1, 1)
|
||||
VSX_MADD(xsmsubasp, 1, float64, VsrD(0), MSUB_FLGS, 1, 1, 1)
|
||||
VSX_MADD(xsmsubmsp, 1, float64, VsrD(0), MSUB_FLGS, 0, 1, 1)
|
||||
VSX_MADD(xsnmaddasp, 1, float64, VsrD(0), NMADD_FLGS, 1, 1, 1)
|
||||
VSX_MADD(xsnmaddmsp, 1, float64, VsrD(0), NMADD_FLGS, 0, 1, 1)
|
||||
VSX_MADD(xsnmsubasp, 1, float64, VsrD(0), NMSUB_FLGS, 1, 1, 1)
|
||||
VSX_MADD(xsnmsubmsp, 1, float64, VsrD(0), NMSUB_FLGS, 0, 1, 1)
|
||||
|
||||
VSX_MADD(xvmaddadp, 2, float64, f64, MADD_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvmaddmdp, 2, float64, f64, MADD_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvmsubadp, 2, float64, f64, MSUB_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvmsubmdp, 2, float64, f64, MSUB_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvnmaddadp, 2, float64, f64, NMADD_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvnmaddmdp, 2, float64, f64, NMADD_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvnmsubadp, 2, float64, f64, NMSUB_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvnmsubmdp, 2, float64, f64, NMSUB_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvmaddadp, 2, float64, VsrD(i), MADD_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvmaddmdp, 2, float64, VsrD(i), MADD_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvmsubadp, 2, float64, VsrD(i), MSUB_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvmsubmdp, 2, float64, VsrD(i), MSUB_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvnmaddadp, 2, float64, VsrD(i), NMADD_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvnmaddmdp, 2, float64, VsrD(i), NMADD_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvnmsubadp, 2, float64, VsrD(i), NMSUB_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvnmsubmdp, 2, float64, VsrD(i), NMSUB_FLGS, 0, 0, 0)
|
||||
|
||||
VSX_MADD(xvmaddasp, 4, float32, f32, MADD_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvmaddmsp, 4, float32, f32, MADD_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvmsubasp, 4, float32, f32, MSUB_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvmsubmsp, 4, float32, f32, MSUB_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvnmaddasp, 4, float32, f32, NMADD_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvnmaddmsp, 4, float32, f32, NMADD_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvnmsubasp, 4, float32, f32, NMSUB_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvnmsubmsp, 4, float32, f32, NMSUB_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvmaddasp, 4, float32, VsrW(i), MADD_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvmaddmsp, 4, float32, VsrW(i), MADD_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvmsubasp, 4, float32, VsrW(i), MSUB_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvmsubmsp, 4, float32, VsrW(i), MSUB_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvnmaddasp, 4, float32, VsrW(i), NMADD_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvnmaddmsp, 4, float32, VsrW(i), NMADD_FLGS, 0, 0, 0)
|
||||
VSX_MADD(xvnmsubasp, 4, float32, VsrW(i), NMSUB_FLGS, 1, 0, 0)
|
||||
VSX_MADD(xvnmsubmsp, 4, float32, VsrW(i), NMSUB_FLGS, 0, 0, 0)
|
||||
|
||||
#define VSX_SCALAR_CMP(op, ordered) \
|
||||
void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
@@ -2352,10 +2360,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
getVSR(xA(opcode), &xa, env); \
|
||||
getVSR(xB(opcode), &xb, env); \
|
||||
\
|
||||
if (unlikely(float64_is_any_nan(xa.f64[0]) || \
|
||||
float64_is_any_nan(xb.f64[0]))) { \
|
||||
if (float64_is_signaling_nan(xa.f64[0]) || \
|
||||
float64_is_signaling_nan(xb.f64[0])) { \
|
||||
if (unlikely(float64_is_any_nan(xa.VsrD(0)) || \
|
||||
float64_is_any_nan(xb.VsrD(0)))) { \
|
||||
if (float64_is_signaling_nan(xa.VsrD(0)) || \
|
||||
float64_is_signaling_nan(xb.VsrD(0))) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
|
||||
} \
|
||||
if (ordered) { \
|
||||
@@ -2363,9 +2371,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
} \
|
||||
cc = 1; \
|
||||
} else { \
|
||||
if (float64_lt(xa.f64[0], xb.f64[0], &env->fp_status)) { \
|
||||
if (float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status)) { \
|
||||
cc = 8; \
|
||||
} else if (!float64_le(xa.f64[0], xb.f64[0], &env->fp_status)) { \
|
||||
} else if (!float64_le(xa.VsrD(0), xb.VsrD(0), \
|
||||
&env->fp_status)) { \
|
||||
cc = 4; \
|
||||
} else { \
|
||||
cc = 2; \
|
||||
@@ -2390,7 +2399,7 @@ VSX_SCALAR_CMP(xscmpudp, 0)
|
||||
* op - operation (max or min)
|
||||
* nels - number of elements (1, 2 or 4)
|
||||
* tp - type (float32 or float64)
|
||||
* fld - vsr_t field (f32 or f64)
|
||||
* fld - vsr_t field (VsrD(*) or VsrW(*))
|
||||
*/
|
||||
#define VSX_MAX_MIN(name, op, nels, tp, fld) \
|
||||
void helper_##name(CPUPPCState *env, uint32_t opcode) \
|
||||
@@ -2403,9 +2412,9 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \
|
||||
getVSR(xT(opcode), &xt, env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
xt.fld[i] = tp##_##op(xa.fld[i], xb.fld[i], &env->fp_status); \
|
||||
if (unlikely(tp##_is_signaling_nan(xa.fld[i]) || \
|
||||
tp##_is_signaling_nan(xb.fld[i]))) { \
|
||||
xt.fld = tp##_##op(xa.fld, xb.fld, &env->fp_status); \
|
||||
if (unlikely(tp##_is_signaling_nan(xa.fld) || \
|
||||
tp##_is_signaling_nan(xb.fld))) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
|
||||
} \
|
||||
} \
|
||||
@@ -2414,18 +2423,18 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \
|
||||
helper_float_check_status(env); \
|
||||
}
|
||||
|
||||
VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, f64)
|
||||
VSX_MAX_MIN(xvmaxdp, maxnum, 2, float64, f64)
|
||||
VSX_MAX_MIN(xvmaxsp, maxnum, 4, float32, f32)
|
||||
VSX_MAX_MIN(xsmindp, minnum, 1, float64, f64)
|
||||
VSX_MAX_MIN(xvmindp, minnum, 2, float64, f64)
|
||||
VSX_MAX_MIN(xvminsp, minnum, 4, float32, f32)
|
||||
VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0))
|
||||
VSX_MAX_MIN(xvmaxdp, maxnum, 2, float64, VsrD(i))
|
||||
VSX_MAX_MIN(xvmaxsp, maxnum, 4, float32, VsrW(i))
|
||||
VSX_MAX_MIN(xsmindp, minnum, 1, float64, VsrD(0))
|
||||
VSX_MAX_MIN(xvmindp, minnum, 2, float64, VsrD(i))
|
||||
VSX_MAX_MIN(xvminsp, minnum, 4, float32, VsrW(i))
|
||||
|
||||
/* VSX_CMP - VSX floating point compare
|
||||
* op - instruction mnemonic
|
||||
* nels - number of elements (1, 2 or 4)
|
||||
* tp - type (float32 or float64)
|
||||
* fld - vsr_t field (f32 or f64)
|
||||
* fld - vsr_t field (VsrD(*) or VsrW(*))
|
||||
* cmp - comparison operation
|
||||
* svxvc - set VXVC bit
|
||||
*/
|
||||
@@ -2442,23 +2451,23 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
getVSR(xT(opcode), &xt, env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
if (unlikely(tp##_is_any_nan(xa.fld[i]) || \
|
||||
tp##_is_any_nan(xb.fld[i]))) { \
|
||||
if (tp##_is_signaling_nan(xa.fld[i]) || \
|
||||
tp##_is_signaling_nan(xb.fld[i])) { \
|
||||
if (unlikely(tp##_is_any_nan(xa.fld) || \
|
||||
tp##_is_any_nan(xb.fld))) { \
|
||||
if (tp##_is_signaling_nan(xa.fld) || \
|
||||
tp##_is_signaling_nan(xb.fld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
|
||||
} \
|
||||
if (svxvc) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \
|
||||
} \
|
||||
xt.fld[i] = 0; \
|
||||
xt.fld = 0; \
|
||||
all_true = 0; \
|
||||
} else { \
|
||||
if (tp##_##cmp(xb.fld[i], xa.fld[i], &env->fp_status) == 1) { \
|
||||
xt.fld[i] = -1; \
|
||||
if (tp##_##cmp(xb.fld, xa.fld, &env->fp_status) == 1) { \
|
||||
xt.fld = -1; \
|
||||
all_false = 0; \
|
||||
} else { \
|
||||
xt.fld[i] = 0; \
|
||||
xt.fld = 0; \
|
||||
all_true = 0; \
|
||||
} \
|
||||
} \
|
||||
@@ -2471,18 +2480,12 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
helper_float_check_status(env); \
|
||||
}
|
||||
|
||||
VSX_CMP(xvcmpeqdp, 2, float64, f64, eq, 0)
|
||||
VSX_CMP(xvcmpgedp, 2, float64, f64, le, 1)
|
||||
VSX_CMP(xvcmpgtdp, 2, float64, f64, lt, 1)
|
||||
VSX_CMP(xvcmpeqsp, 4, float32, f32, eq, 0)
|
||||
VSX_CMP(xvcmpgesp, 4, float32, f32, le, 1)
|
||||
VSX_CMP(xvcmpgtsp, 4, float32, f32, lt, 1)
|
||||
|
||||
#if defined(HOST_WORDS_BIGENDIAN)
|
||||
#define JOFFSET 0
|
||||
#else
|
||||
#define JOFFSET 1
|
||||
#endif
|
||||
VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0)
|
||||
VSX_CMP(xvcmpgedp, 2, float64, VsrD(i), le, 1)
|
||||
VSX_CMP(xvcmpgtdp, 2, float64, VsrD(i), lt, 1)
|
||||
VSX_CMP(xvcmpeqsp, 4, float32, VsrW(i), eq, 0)
|
||||
VSX_CMP(xvcmpgesp, 4, float32, VsrW(i), le, 1)
|
||||
VSX_CMP(xvcmpgtsp, 4, float32, VsrW(i), lt, 1)
|
||||
|
||||
/* VSX_CVT_FP_TO_FP - VSX floating point/floating point conversion
|
||||
* op - instruction mnemonic
|
||||
@@ -2503,7 +2506,6 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
getVSR(xT(opcode), &xt, env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
int j = 2*i + JOFFSET; \
|
||||
xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
|
||||
if (unlikely(stp##_is_signaling_nan(xb.sfld))) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
|
||||
@@ -2519,10 +2521,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
helper_float_check_status(env); \
|
||||
}
|
||||
|
||||
VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, f64[i], f32[j], 1)
|
||||
VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, f32[j], f64[i], 1)
|
||||
VSX_CVT_FP_TO_FP(xvcvdpsp, 2, float64, float32, f64[i], f32[j], 0)
|
||||
VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, f32[j], f64[i], 0)
|
||||
VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1)
|
||||
VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, VsrW(0), VsrD(0), 1)
|
||||
VSX_CVT_FP_TO_FP(xvcvdpsp, 2, float64, float32, VsrD(i), VsrW(2*i), 0)
|
||||
VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, VsrW(2*i), VsrD(i), 0)
|
||||
|
||||
uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb)
|
||||
{
|
||||
@@ -2547,10 +2549,9 @@ uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb)
|
||||
* ttp - target type (int32, uint32, int64 or uint64)
|
||||
* sfld - source vsr_t field
|
||||
* tfld - target vsr_t field
|
||||
* jdef - definition of the j index (i or 2*i)
|
||||
* rnan - resulting NaN
|
||||
*/
|
||||
#define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, jdef, rnan) \
|
||||
#define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, rnan) \
|
||||
void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
{ \
|
||||
ppc_vsr_t xt, xb; \
|
||||
@@ -2560,7 +2561,6 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
getVSR(xT(opcode), &xt, env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
int j = jdef; \
|
||||
if (unlikely(stp##_is_any_nan(xb.sfld))) { \
|
||||
if (stp##_is_signaling_nan(xb.sfld)) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
|
||||
@@ -2568,7 +2568,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \
|
||||
xt.tfld = rnan; \
|
||||
} else { \
|
||||
xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
|
||||
xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, \
|
||||
&env->fp_status); \
|
||||
if (env->fp_status.float_exception_flags & float_flag_invalid) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \
|
||||
} \
|
||||
@@ -2579,27 +2580,23 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
helper_float_check_status(env); \
|
||||
}
|
||||
|
||||
VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, f64[j], u64[i], i, \
|
||||
VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \
|
||||
0x8000000000000000ULL)
|
||||
VSX_CVT_FP_TO_INT(xscvdpsxws, 1, float64, int32, f64[i], u32[j], \
|
||||
2*i + JOFFSET, 0x80000000U)
|
||||
VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, f64[j], u64[i], i, 0ULL)
|
||||
VSX_CVT_FP_TO_INT(xscvdpuxws, 1, float64, uint32, f64[i], u32[j], \
|
||||
2*i + JOFFSET, 0U)
|
||||
VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, f64[j], u64[i], i, \
|
||||
0x8000000000000000ULL)
|
||||
VSX_CVT_FP_TO_INT(xvcvdpsxws, 2, float64, int32, f64[i], u32[j], \
|
||||
2*i + JOFFSET, 0x80000000U)
|
||||
VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, f64[j], u64[i], i, 0ULL)
|
||||
VSX_CVT_FP_TO_INT(xvcvdpuxws, 2, float64, uint32, f64[i], u32[j], \
|
||||
2*i + JOFFSET, 0U)
|
||||
VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, f32[j], u64[i], \
|
||||
2*i + JOFFSET, 0x8000000000000000ULL)
|
||||
VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, f32[j], u32[j], i, \
|
||||
VSX_CVT_FP_TO_INT(xscvdpsxws, 1, float64, int32, VsrD(0), VsrW(1), \
|
||||
0x80000000U)
|
||||
VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, f32[j], u64[i], \
|
||||
2*i + JOFFSET, 0ULL)
|
||||
VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, f32[j], u32[i], i, 0U)
|
||||
VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, VsrD(0), VsrD(0), 0ULL)
|
||||
VSX_CVT_FP_TO_INT(xscvdpuxws, 1, float64, uint32, VsrD(0), VsrW(1), 0U)
|
||||
VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, VsrD(i), VsrD(i), \
|
||||
0x8000000000000000ULL)
|
||||
VSX_CVT_FP_TO_INT(xvcvdpsxws, 2, float64, int32, VsrD(i), VsrW(2*i), \
|
||||
0x80000000U)
|
||||
VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, VsrD(i), VsrD(i), 0ULL)
|
||||
VSX_CVT_FP_TO_INT(xvcvdpuxws, 2, float64, uint32, VsrD(i), VsrW(2*i), 0U)
|
||||
VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, VsrW(2*i), VsrD(i), \
|
||||
0x8000000000000000ULL)
|
||||
VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, VsrW(i), VsrW(i), 0x80000000U)
|
||||
VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2*i), VsrD(i), 0ULL)
|
||||
VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), 0U)
|
||||
|
||||
/* VSX_CVT_INT_TO_FP - VSX integer to floating point conversion
|
||||
* op - instruction mnemonic
|
||||
@@ -2611,7 +2608,7 @@ VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, f32[j], u32[i], i, 0U)
|
||||
* jdef - definition of the j index (i or 2*i)
|
||||
* sfprf - set FPRF
|
||||
*/
|
||||
#define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, jdef, sfprf, r2sp) \
|
||||
#define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf, r2sp) \
|
||||
void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
{ \
|
||||
ppc_vsr_t xt, xb; \
|
||||
@@ -2621,7 +2618,6 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
getVSR(xT(opcode), &xt, env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
int j = jdef; \
|
||||
xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
|
||||
if (r2sp) { \
|
||||
xt.tfld = helper_frsp(env, xt.tfld); \
|
||||
@@ -2635,22 +2631,18 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
helper_float_check_status(env); \
|
||||
}
|
||||
|
||||
VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, u64[j], f64[i], i, 1, 0)
|
||||
VSX_CVT_INT_TO_FP(xscvuxddp, 1, uint64, float64, u64[j], f64[i], i, 1, 0)
|
||||
VSX_CVT_INT_TO_FP(xscvsxdsp, 1, int64, float64, u64[j], f64[i], i, 1, 1)
|
||||
VSX_CVT_INT_TO_FP(xscvuxdsp, 1, uint64, float64, u64[j], f64[i], i, 1, 1)
|
||||
VSX_CVT_INT_TO_FP(xvcvsxddp, 2, int64, float64, u64[j], f64[i], i, 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvuxddp, 2, uint64, float64, u64[j], f64[i], i, 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvsxwdp, 2, int32, float64, u32[j], f64[i], \
|
||||
2*i + JOFFSET, 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvuxwdp, 2, uint64, float64, u32[j], f64[i], \
|
||||
2*i + JOFFSET, 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvsxdsp, 2, int64, float32, u64[i], f32[j], \
|
||||
2*i + JOFFSET, 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvuxdsp, 2, uint64, float32, u64[i], f32[j], \
|
||||
2*i + JOFFSET, 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvsxwsp, 4, int32, float32, u32[j], f32[i], i, 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, u32[j], f32[i], i, 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0)
|
||||
VSX_CVT_INT_TO_FP(xscvuxddp, 1, uint64, float64, VsrD(0), VsrD(0), 1, 0)
|
||||
VSX_CVT_INT_TO_FP(xscvsxdsp, 1, int64, float64, VsrD(0), VsrD(0), 1, 1)
|
||||
VSX_CVT_INT_TO_FP(xscvuxdsp, 1, uint64, float64, VsrD(0), VsrD(0), 1, 1)
|
||||
VSX_CVT_INT_TO_FP(xvcvsxddp, 2, int64, float64, VsrD(i), VsrD(i), 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvuxddp, 2, uint64, float64, VsrD(i), VsrD(i), 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvsxwdp, 2, int32, float64, VsrW(2*i), VsrD(i), 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvuxwdp, 2, uint64, float64, VsrW(2*i), VsrD(i), 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvsxdsp, 2, int64, float32, VsrD(i), VsrW(2*i), 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvuxdsp, 2, uint64, float32, VsrD(i), VsrW(2*i), 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvsxwsp, 4, int32, float32, VsrW(i), VsrW(i), 0, 0)
|
||||
VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, VsrW(i), VsrW(i), 0, 0)
|
||||
|
||||
/* For "use current rounding mode", define a value that will not be one of
|
||||
* the existing rounding model enums.
|
||||
@@ -2662,7 +2654,7 @@ VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, u32[j], f32[i], i, 0, 0)
|
||||
* op - instruction mnemonic
|
||||
* nels - number of elements (1, 2 or 4)
|
||||
* tp - type (float32 or float64)
|
||||
* fld - vsr_t field (f32 or f64)
|
||||
* fld - vsr_t field (VsrD(*) or VsrW(*))
|
||||
* rmode - rounding mode
|
||||
* sfprf - set FPRF
|
||||
*/
|
||||
@@ -2679,14 +2671,14 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
} \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
if (unlikely(tp##_is_signaling_nan(xb.fld[i]))) { \
|
||||
if (unlikely(tp##_is_signaling_nan(xb.fld))) { \
|
||||
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
|
||||
xt.fld[i] = tp##_snan_to_qnan(xb.fld[i]); \
|
||||
xt.fld = tp##_snan_to_qnan(xb.fld); \
|
||||
} else { \
|
||||
xt.fld[i] = tp##_round_to_int(xb.fld[i], &env->fp_status); \
|
||||
xt.fld = tp##_round_to_int(xb.fld, &env->fp_status); \
|
||||
} \
|
||||
if (sfprf) { \
|
||||
helper_compute_fprf(env, xt.fld[i], sfprf); \
|
||||
helper_compute_fprf(env, xt.fld, sfprf); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
@@ -2702,23 +2694,23 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||
helper_float_check_status(env); \
|
||||
}
|
||||
|
||||
VSX_ROUND(xsrdpi, 1, float64, f64, float_round_nearest_even, 1)
|
||||
VSX_ROUND(xsrdpic, 1, float64, f64, FLOAT_ROUND_CURRENT, 1)
|
||||
VSX_ROUND(xsrdpim, 1, float64, f64, float_round_down, 1)
|
||||
VSX_ROUND(xsrdpip, 1, float64, f64, float_round_up, 1)
|
||||
VSX_ROUND(xsrdpiz, 1, float64, f64, float_round_to_zero, 1)
|
||||
VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_nearest_even, 1)
|
||||
VSX_ROUND(xsrdpic, 1, float64, VsrD(0), FLOAT_ROUND_CURRENT, 1)
|
||||
VSX_ROUND(xsrdpim, 1, float64, VsrD(0), float_round_down, 1)
|
||||
VSX_ROUND(xsrdpip, 1, float64, VsrD(0), float_round_up, 1)
|
||||
VSX_ROUND(xsrdpiz, 1, float64, VsrD(0), float_round_to_zero, 1)
|
||||
|
||||
VSX_ROUND(xvrdpi, 2, float64, f64, float_round_nearest_even, 0)
|
||||
VSX_ROUND(xvrdpic, 2, float64, f64, FLOAT_ROUND_CURRENT, 0)
|
||||
VSX_ROUND(xvrdpim, 2, float64, f64, float_round_down, 0)
|
||||
VSX_ROUND(xvrdpip, 2, float64, f64, float_round_up, 0)
|
||||
VSX_ROUND(xvrdpiz, 2, float64, f64, float_round_to_zero, 0)
|
||||
VSX_ROUND(xvrdpi, 2, float64, VsrD(i), float_round_nearest_even, 0)
|
||||
VSX_ROUND(xvrdpic, 2, float64, VsrD(i), FLOAT_ROUND_CURRENT, 0)
|
||||
VSX_ROUND(xvrdpim, 2, float64, VsrD(i), float_round_down, 0)
|
||||
VSX_ROUND(xvrdpip, 2, float64, VsrD(i), float_round_up, 0)
|
||||
VSX_ROUND(xvrdpiz, 2, float64, VsrD(i), float_round_to_zero, 0)
|
||||
|
||||
VSX_ROUND(xvrspi, 4, float32, f32, float_round_nearest_even, 0)
|
||||
VSX_ROUND(xvrspic, 4, float32, f32, FLOAT_ROUND_CURRENT, 0)
|
||||
VSX_ROUND(xvrspim, 4, float32, f32, float_round_down, 0)
|
||||
VSX_ROUND(xvrspip, 4, float32, f32, float_round_up, 0)
|
||||
VSX_ROUND(xvrspiz, 4, float32, f32, float_round_to_zero, 0)
|
||||
VSX_ROUND(xvrspi, 4, float32, VsrW(i), float_round_nearest_even, 0)
|
||||
VSX_ROUND(xvrspic, 4, float32, VsrW(i), FLOAT_ROUND_CURRENT, 0)
|
||||
VSX_ROUND(xvrspim, 4, float32, VsrW(i), float_round_down, 0)
|
||||
VSX_ROUND(xvrspip, 4, float32, VsrW(i), float_round_up, 0)
|
||||
VSX_ROUND(xvrspiz, 4, float32, VsrW(i), float_round_to_zero, 0)
|
||||
|
||||
uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb)
|
||||
{
|
||||
|
||||
@@ -101,7 +101,7 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value,
|
||||
hreg_compute_hflags(env);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (unlikely(msr_pow == 1)) {
|
||||
if ((*env->check_pow)(env)) {
|
||||
if (!env->pending_interrupts && (*env->check_pow)(env)) {
|
||||
cs->halted = 1;
|
||||
excp = EXCP_HALTED;
|
||||
}
|
||||
|
||||
@@ -6699,6 +6699,8 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
|
||||
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
|
||||
POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
|
||||
POWERPC_FLAG_BUS_CLK;
|
||||
pcc->l1_dcache_size = 0x8000;
|
||||
pcc->l1_icache_size = 0x10000;
|
||||
}
|
||||
|
||||
static int check_pow_970FX (CPUPPCState *env)
|
||||
@@ -6791,6 +6793,8 @@ POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data)
|
||||
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
|
||||
POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
|
||||
POWERPC_FLAG_BUS_CLK;
|
||||
pcc->l1_dcache_size = 0x8000;
|
||||
pcc->l1_icache_size = 0x10000;
|
||||
}
|
||||
|
||||
static int check_pow_970MP (CPUPPCState *env)
|
||||
@@ -6877,6 +6881,8 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data)
|
||||
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
|
||||
POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
|
||||
POWERPC_FLAG_BUS_CLK;
|
||||
pcc->l1_dcache_size = 0x8000;
|
||||
pcc->l1_icache_size = 0x10000;
|
||||
}
|
||||
|
||||
static void init_proc_power5plus(CPUPPCState *env)
|
||||
@@ -6967,6 +6973,8 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
|
||||
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
|
||||
POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
|
||||
POWERPC_FLAG_BUS_CLK;
|
||||
pcc->l1_dcache_size = 0x8000;
|
||||
pcc->l1_icache_size = 0x10000;
|
||||
}
|
||||
|
||||
static void init_proc_POWER7 (CPUPPCState *env)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,17 +17,23 @@
|
||||
#undef TCG_TARGET_STACK_GROWSUP
|
||||
|
||||
typedef enum {
|
||||
TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3, TCG_REG_X4,
|
||||
TCG_REG_X5, TCG_REG_X6, TCG_REG_X7, TCG_REG_X8, TCG_REG_X9,
|
||||
TCG_REG_X10, TCG_REG_X11, TCG_REG_X12, TCG_REG_X13, TCG_REG_X14,
|
||||
TCG_REG_X15, TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19,
|
||||
TCG_REG_X20, TCG_REG_X21, TCG_REG_X22, TCG_REG_X23, TCG_REG_X24,
|
||||
TCG_REG_X25, TCG_REG_X26, TCG_REG_X27, TCG_REG_X28,
|
||||
TCG_REG_FP, /* frame pointer */
|
||||
TCG_REG_LR, /* link register */
|
||||
TCG_REG_SP, /* stack pointer or zero register */
|
||||
TCG_REG_XZR = TCG_REG_SP /* same register number */
|
||||
/* program counter is not directly accessible! */
|
||||
TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3,
|
||||
TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7,
|
||||
TCG_REG_X8, TCG_REG_X9, TCG_REG_X10, TCG_REG_X11,
|
||||
TCG_REG_X12, TCG_REG_X13, TCG_REG_X14, TCG_REG_X15,
|
||||
TCG_REG_X16, TCG_REG_X17, TCG_REG_X18, TCG_REG_X19,
|
||||
TCG_REG_X20, TCG_REG_X21, TCG_REG_X22, TCG_REG_X23,
|
||||
TCG_REG_X24, TCG_REG_X25, TCG_REG_X26, TCG_REG_X27,
|
||||
TCG_REG_X28, TCG_REG_X29, TCG_REG_X30,
|
||||
|
||||
/* X31 is either the stack pointer or zero, depending on context. */
|
||||
TCG_REG_SP = 31,
|
||||
TCG_REG_XZR = 31,
|
||||
|
||||
/* Aliases. */
|
||||
TCG_REG_FP = TCG_REG_X29,
|
||||
TCG_REG_LR = TCG_REG_X30,
|
||||
TCG_AREG0 = TCG_REG_X19,
|
||||
} TCGReg;
|
||||
|
||||
#define TCG_TARGET_NB_REGS 32
|
||||
@@ -92,11 +98,7 @@ typedef enum {
|
||||
#define TCG_TARGET_HAS_muluh_i64 1
|
||||
#define TCG_TARGET_HAS_mulsh_i64 1
|
||||
|
||||
enum {
|
||||
TCG_AREG0 = TCG_REG_X19,
|
||||
};
|
||||
|
||||
#define TCG_TARGET_HAS_new_ldst 0
|
||||
#define TCG_TARGET_HAS_new_ldst 1
|
||||
|
||||
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
|
||||
{
|
||||
|
||||
@@ -394,7 +394,8 @@ check-block: $(patsubst %,check-%, $(check-block-y))
|
||||
check: check-qapi-schema check-unit check-qtest
|
||||
check-clean:
|
||||
$(MAKE) -C tests/tcg clean
|
||||
rm -rf $(check-unit-y) $(check-qtest-i386-y) $(check-qtest-x86_64-y) $(check-qtest-sparc64-y) $(check-qtest-sparc-y) tests/*.o $(QEMU_IOTESTS_HELPERS-y)
|
||||
rm -rf $(check-unit-y) tests/*.o $(QEMU_IOTESTS_HELPERS-y)
|
||||
rm -rf $(sort $(foreach target,$(SYSEMU_TARGET_LIST), $(check-qtest-$(target)-y)))
|
||||
|
||||
clean: check-clean
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -69,10 +69,14 @@ _use_sample_img empty.bochs.bz2
|
||||
poke_file "$TEST_IMG" "$disk_size_offset" "\x00\xc0\x0f\x00\x00\x00\x00\x7f"
|
||||
{ $QEMU_IO -c "read 2T 4k" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
_use_sample_img empty.bochs.bz2
|
||||
poke_file "$TEST_IMG" "$catalog_size_offset" "\x10\x00\x00\x00"
|
||||
{ $QEMU_IO -c "read 0xfbe00 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
echo "== Negative extent size =="
|
||||
_use_sample_img empty.bochs.bz2
|
||||
poke_file "$TEST_IMG" "$extent_size_offset" "\xff\xff\xff\xff"
|
||||
poke_file "$TEST_IMG" "$extent_size_offset" "\x00\x00\x00\x80"
|
||||
{ $QEMU_IO -c "read 768k 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
|
||||
|
||||
echo
|
||||
|
||||
@@ -15,12 +15,14 @@ no file open, try 'help open'
|
||||
== Too small catalog bitmap for image size ==
|
||||
qemu-io: can't open device TEST_DIR/empty.bochs: Catalog size is too small for this disk size
|
||||
no file open, try 'help open'
|
||||
qemu-io: can't open device TEST_DIR/empty.bochs: Catalog size is too small for this disk size
|
||||
no file open, try 'help open'
|
||||
|
||||
== Negative extent size ==
|
||||
qemu-io: can't open device TEST_DIR/empty.bochs: Extent size 4294967295 is too large
|
||||
qemu-io: can't open device TEST_DIR/empty.bochs: Extent size 2147483648 is too large
|
||||
no file open, try 'help open'
|
||||
|
||||
== Zero extent size ==
|
||||
qemu-io: can't open device TEST_DIR/empty.bochs: Extent size may not be zero
|
||||
qemu-io: can't open device TEST_DIR/empty.bochs: Extent size must be at least 512
|
||||
no file open, try 'help open'
|
||||
*** done
|
||||
|
||||
21
trace-events
21
trace-events
@@ -433,6 +433,27 @@ usb_uas_tmf_abort_task(int addr, uint16_t tag, uint16_t task_tag) "dev %d, tag 0
|
||||
usb_uas_tmf_logical_unit_reset(int addr, uint16_t tag, int lun) "dev %d, tag 0x%x, lun %d"
|
||||
usb_uas_tmf_unsupported(int addr, uint16_t tag, uint32_t function) "dev %d, tag 0x%x, function 0x%x"
|
||||
|
||||
# hw/usb/dev-mtp.c
|
||||
usb_mtp_reset(int addr) "dev %d"
|
||||
usb_mtp_command(int dev, uint16_t code, uint32_t trans, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4) "dev %d, code 0x%x, trans 0x%x, args 0x%x, 0x%x, 0x%x, 0x%x, 0x%x"
|
||||
usb_mtp_success(int dev, uint32_t trans, uint32_t arg0, uint32_t arg1) "dev %d, trans 0x%x, args 0x%x, 0x%x"
|
||||
usb_mtp_error(int dev, uint16_t code, uint32_t trans, uint32_t arg0, uint32_t arg1) "dev %d, code 0x%x, trans 0x%x, args 0x%x, 0x%x"
|
||||
usb_mtp_data_in(int dev, uint32_t trans, uint32_t len) "dev %d, trans 0x%x, len %d"
|
||||
usb_mtp_data_out(int dev, uint32_t trans, uint32_t len) "dev %d, trans 0x%x, len %d"
|
||||
usb_mtp_xfer(int dev, uint32_t ep, uint32_t dlen, uint32_t plen) "dev %d, ep %d, %d/%d"
|
||||
usb_mtp_nak(int dev, uint32_t ep) "dev %d, ep %d"
|
||||
usb_mtp_stall(int dev, const char *reason) "dev %d, reason: %s"
|
||||
usb_mtp_op_get_device_info(int dev) "dev %d"
|
||||
usb_mtp_op_open_session(int dev) "dev %d"
|
||||
usb_mtp_op_close_session(int dev) "dev %d"
|
||||
usb_mtp_op_get_storage_ids(int dev) "dev %d"
|
||||
usb_mtp_op_get_storage_info(int dev) "dev %d"
|
||||
usb_mtp_op_get_num_objects(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
|
||||
usb_mtp_op_get_object_handles(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
|
||||
usb_mtp_op_get_object_info(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
|
||||
usb_mtp_op_get_object(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
|
||||
usb_mtp_op_get_partial_object(int dev, uint32_t handle, const char *path, uint32_t offset, uint32_t length) "dev %d, handle 0x%x, path %s, off %d, len %d"
|
||||
|
||||
# hw/usb/host-libusb.c
|
||||
usb_host_open_started(int bus, int addr) "dev %d:%d"
|
||||
usb_host_open_success(int bus, int addr) "dev %d:%d"
|
||||
|
||||
19
ui/gtk.c
19
ui/gtk.c
@@ -476,8 +476,15 @@ static void gd_change_runstate(void *opaque, int running, RunState state)
|
||||
|
||||
static void gd_mouse_mode_change(Notifier *notify, void *data)
|
||||
{
|
||||
gd_update_cursor(container_of(notify, GtkDisplayState, mouse_mode_notifier),
|
||||
FALSE);
|
||||
GtkDisplayState *s;
|
||||
|
||||
s = container_of(notify, GtkDisplayState, mouse_mode_notifier);
|
||||
/* release the grab at switching to absolute mode */
|
||||
if (qemu_input_is_absolute() && gd_is_grab_active(s)) {
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
|
||||
FALSE);
|
||||
}
|
||||
gd_update_cursor(s, FALSE);
|
||||
}
|
||||
|
||||
/** GTK Events **/
|
||||
@@ -685,6 +692,14 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
|
||||
GtkDisplayState *s = opaque;
|
||||
InputButton btn;
|
||||
|
||||
/* implicitly grab the input at the first click in the relative mode */
|
||||
if (button->button == 1 && button->type == GDK_BUTTON_PRESS &&
|
||||
!qemu_input_is_absolute() && !gd_is_grab_active(s)) {
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
|
||||
TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (button->button == 1) {
|
||||
btn = INPUT_BUTTON_LEFT;
|
||||
} else if (button->button == 2) {
|
||||
|
||||
21
ui/sdl2.c
21
ui/sdl2.c
@@ -278,7 +278,7 @@ static void sdl_hide_cursor(void)
|
||||
SDL_ShowCursor(1);
|
||||
SDL_SetCursor(sdl_cursor_hidden);
|
||||
} else {
|
||||
SDL_ShowCursor(0);
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,6 +289,7 @@ static void sdl_show_cursor(void)
|
||||
}
|
||||
|
||||
if (!qemu_input_is_absolute()) {
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
SDL_ShowCursor(1);
|
||||
if (guest_cursor &&
|
||||
(gui_grab || qemu_input_is_absolute() || absolute_enabled)) {
|
||||
@@ -403,13 +404,17 @@ static void sdl_send_mouse_event(struct sdl2_state *scon, int dx, int dy,
|
||||
}
|
||||
qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_X, off_x + x, max_w);
|
||||
qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_Y, off_y + y, max_h);
|
||||
} else if (guest_cursor) {
|
||||
x -= guest_x;
|
||||
y -= guest_y;
|
||||
guest_x += x;
|
||||
guest_y += y;
|
||||
qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_X, x);
|
||||
qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_Y, y);
|
||||
} else {
|
||||
if (guest_cursor) {
|
||||
x -= guest_x;
|
||||
y -= guest_y;
|
||||
guest_x += x;
|
||||
guest_y += y;
|
||||
dx = x;
|
||||
dy = y;
|
||||
}
|
||||
qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_X, dx);
|
||||
qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_Y, dy);
|
||||
}
|
||||
qemu_input_event_sync();
|
||||
}
|
||||
|
||||
@@ -549,6 +549,10 @@ static int interface_client_monitors_config(QXLInstance *sin,
|
||||
QemuUIInfo info;
|
||||
int rc;
|
||||
|
||||
if (!mc) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: multihead is tricky due to the way
|
||||
* spice has multihead implemented.
|
||||
|
||||
25
user-exec.c
25
user-exec.c
@@ -465,16 +465,29 @@ int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
struct ucontext *uc = puc;
|
||||
uint64_t pc;
|
||||
int is_write = 0; /* XXX how to determine? */
|
||||
uintptr_t pc = uc->uc_mcontext.pc;
|
||||
uint32_t insn = *(uint32_t *)pc;
|
||||
bool is_write;
|
||||
|
||||
pc = uc->uc_mcontext.pc;
|
||||
return handle_cpu_signal(pc, (uint64_t)info->si_addr,
|
||||
/* XXX: need kernel patch to get write flag faster. */
|
||||
is_write = ( (insn & 0xbfff0000) == 0x0c000000 /* C3.3.1 */
|
||||
|| (insn & 0xbfe00000) == 0x0c800000 /* C3.3.2 */
|
||||
|| (insn & 0xbfdf0000) == 0x0d000000 /* C3.3.3 */
|
||||
|| (insn & 0xbfc00000) == 0x0d800000 /* C3.3.4 */
|
||||
|| (insn & 0x3f400000) == 0x08000000 /* C3.3.6 */
|
||||
|| (insn & 0x3bc00000) == 0x39000000 /* C3.3.13 */
|
||||
|| (insn & 0x3fc00000) == 0x3d800000 /* ... 128bit */
|
||||
/* Ingore bits 10, 11 & 21, controlling indexing. */
|
||||
|| (insn & 0x3bc00000) == 0x38000000 /* C3.3.8-12 */
|
||||
|| (insn & 0x3fe00000) == 0x3c800000 /* ... 128bit */
|
||||
/* Ignore bits 23 & 24, controlling indexing. */
|
||||
|| (insn & 0x3a400000) == 0x28000000); /* C3.3.7,14-16 */
|
||||
|
||||
return handle_cpu_signal(pc, (uintptr_t)info->si_addr,
|
||||
is_write, &uc->uc_sigmask, puc);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user