summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2010-02-24 16:06:15 -0300
committerMarcelo Tosatti <mtosatti@redhat.com>2010-02-24 16:06:15 -0300
commitc4b1eb2bb335c2c70967acb0c1a61fd737d3fc1b (patch)
tree6ee1305897a0651bc18cbd04fb6654c0edb5eff7
parent9e49066b3dd6b659fc04eb4375e016dcb9492dce (diff)
parentb5ec5ce0e39d6e7ea707d5604a5f6d567dfd2f48 (diff)
Merge commit 'b5ec5ce0e39d6e7ea707d5604a5f6d567dfd2f48' into upstream-merge
* commit 'b5ec5ce0e39d6e7ea707d5604a5f6d567dfd2f48': Add cpu model configuration support.. add close callback for tty-based char device Fix lost serial TX interrupts. Report receive overruns. tcg/ppc: Fix typo apc_pci: simplify using rwhandler apb_pci: minor cleanup Update OpenBIOS images to r683 Fix arm-softmmu compile tcg/ppc64: Use C90 style comments tcg/ppc: Implement some of the optional ops tcg: fix build on 32-bit hppa, ppc and sparc hosts PL181 write fix Allow const QemuOptDesc cris: Add CRISv10 gdbstub support. cris: Mask interrupts on dslots for CRISv10. microblaze: Improve brk emulation. microblaze: Dont segfault when singlestepping first insn. target-sparc: fix --enable-debug build tcg: fix assertion with --enable-debug Conflicts: target-i386/helper.c Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--Makefile6
-rw-r--r--gdbstub.c36
-rw-r--r--hw/apb_pci.c80
-rw-r--r--hw/pl181.c29
-rw-r--r--hw/serial.c28
-rw-r--r--linux-user/main.c8
-rw-r--r--net.c2
-rw-r--r--pc-bios/README4
-rw-r--r--pc-bios/openbios-ppcbin312124 -> 307924 bytes
-rw-r--r--pc-bios/openbios-sparc32bin217668 -> 217668 bytes
-rw-r--r--pc-bios/openbios-sparc64bin1065880 -> 1065880 bytes
-rw-r--r--qemu-char.c17
-rw-r--r--qemu-config.c49
-rw-r--r--qemu-config.h1
-rw-r--r--qemu-option.c6
-rw-r--r--qemu-option.h2
-rw-r--r--sysconfigs/target/target-x86_64.conf86
-rw-r--r--target-cris/translate_v10.c4
-rw-r--r--target-i386/cpu.h9
-rw-r--r--target-i386/helper.c460
-rw-r--r--target-microblaze/op_helper.c6
-rw-r--r--target-microblaze/translate.c19
-rw-r--r--target-sparc/translate.c22
-rw-r--r--tcg/hppa/tcg-target.c1
-rw-r--r--tcg/ppc/tcg-target.c82
-rw-r--r--tcg/ppc/tcg-target.h16
-rw-r--r--tcg/ppc64/tcg-target.h36
-rw-r--r--tcg/sparc/tcg-target.c4
-rw-r--r--tcg/tcg-opc.h5
-rw-r--r--vl.c9
30 files changed, 811 insertions, 216 deletions
diff --git a/Makefile b/Makefile
index c9731fb7f..296f50009 100644
--- a/Makefile
+++ b/Makefile
@@ -205,7 +205,11 @@ ifdef CONFIG_POSIX
$(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
endif
-install: all $(if $(BUILD_DOCS),install-doc)
+install-sysconfig:
+ $(INSTALL_DIR) "$(sysconfdir)/qemu"
+ $(INSTALL_DATA) sysconfigs/target/target-x86_64.conf "$(sysconfdir)/qemu"
+
+install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig
$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
ifneq ($(TOOLS),)
$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
diff --git a/gdbstub.c b/gdbstub.c
index c61981dc2..6e61eddaf 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1250,10 +1250,46 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
#define NUM_CORE_REGS 49
+static int
+read_register_crisv10(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 15) {
+ GET_REG32(env->regs[n]);
+ }
+
+ if (n == 15) {
+ GET_REG32(env->pc);
+ }
+
+ if (n < 32) {
+ switch (n) {
+ case 16:
+ GET_REG8(env->pregs[n - 16]);
+ break;
+ case 17:
+ GET_REG8(env->pregs[n - 16]);
+ break;
+ case 20:
+ case 21:
+ GET_REG16(env->pregs[n - 16]);
+ break;
+ default:
+ if (n >= 23) {
+ GET_REG32(env->pregs[n - 16]);
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
{
uint8_t srs;
+ if (env->pregs[PR_VR] < 32)
+ return read_register_crisv10(env, mem_buf, n);
+
srs = env->pregs[PR_SRS];
if (n < 16) {
GET_REG32(env->regs[n]);
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index ebfcd4153..324e74eec 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -29,6 +29,7 @@
#include "sysbus.h"
#include "pci.h"
#include "pci_host.h"
+#include "rwhandler.h"
#include "apb_pci.h"
/* debug APB */
@@ -65,6 +66,7 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
typedef struct APBState {
SysBusDevice busdev;
PCIHostState host_state;
+ ReadWriteHandler pci_config_handler;
uint32_t iommu[4];
uint32_t pci_control[16];
uint32_t pci_irq_map[8];
@@ -183,82 +185,28 @@ static CPUReadMemoryFunc * const apb_config_read[] = {
&apb_config_readl,
};
-static void apb_pci_config_write(APBState *s, target_phys_addr_t addr,
+static void apb_pci_config_write(ReadWriteHandler *h, pcibus_t addr,
uint32_t val, int size)
{
+ APBState *s = container_of(h, APBState, pci_config_handler);
+
+ val = qemu_bswap_len(val, size);
APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
- pci_data_write(s->host_state.bus, (addr & 0x00ffffff) | (1u << 31), val,
- size);
+ pci_data_write(s->host_state.bus, addr, val, size);
}
-static uint32_t apb_pci_config_read(APBState *s, target_phys_addr_t addr,
+static uint32_t apb_pci_config_read(ReadWriteHandler *h, pcibus_t addr,
int size)
{
uint32_t ret;
+ APBState *s = container_of(h, APBState, pci_config_handler);
- ret = pci_data_read(s->host_state.bus, (addr & 0x00ffffff) | (1u << 31),
- size);
+ ret = pci_data_read(s->host_state.bus, addr, size);
+ ret = qemu_bswap_len(ret, size);
APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, ret);
return ret;
}
-static void apb_pci_config_writel(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- APBState *s = opaque;
-
- apb_pci_config_write(s, addr, bswap32(val), 4);
-}
-
-static void apb_pci_config_writew(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- APBState *s = opaque;
-
- apb_pci_config_write(s, addr, bswap16(val), 2);
-}
-
-static void apb_pci_config_writeb(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- APBState *s = opaque;
-
- apb_pci_config_write(s, addr, val, 1);
-}
-
-static uint32_t apb_pci_config_readl(void *opaque, target_phys_addr_t addr)
-{
- APBState *s = opaque;
-
- return bswap32(apb_pci_config_read(s, addr, 4));
-}
-
-static uint32_t apb_pci_config_readw(void *opaque, target_phys_addr_t addr)
-{
- APBState *s = opaque;
-
- return bswap16(apb_pci_config_read(s, addr, 2));
-}
-
-static uint32_t apb_pci_config_readb(void *opaque, target_phys_addr_t addr)
-{
- APBState *s = opaque;
-
- return apb_pci_config_read(s, addr, 1);
-}
-
-static CPUWriteMemoryFunc * const apb_pci_config_writes[] = {
- &apb_pci_config_writeb,
- &apb_pci_config_writew,
- &apb_pci_config_writel,
-};
-
-static CPUReadMemoryFunc * const apb_pci_config_reads[] = {
- &apb_pci_config_readb,
- &apb_pci_config_readw,
- &apb_pci_config_readl,
-};
-
static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
@@ -455,8 +403,10 @@ static int pci_pbm_init_device(SysBusDevice *dev)
pci_apb_iowrite, s);
sysbus_init_mmio(dev, 0x10000ULL, pci_ioport);
/* pci_config */
- pci_config = cpu_register_io_memory(apb_pci_config_reads,
- apb_pci_config_writes, s);
+ s->pci_config_handler.read = apb_pci_config_read;
+ s->pci_config_handler.write = apb_pci_config_write;
+ pci_config = cpu_register_io_memory_simple(&s->pci_config_handler);
+ assert(pci_config >= 0);
sysbus_init_mmio(dev, 0x1000000ULL, pci_config);
/* mem_data */
pci_mem_data = pci_host_data_register_mmio(&s->host_state);
diff --git a/hw/pl181.c b/hw/pl181.c
index 728205305..192405333 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -182,39 +182,40 @@ error:
static void pl181_fifo_run(pl181_state *s)
{
uint32_t bits;
- uint32_t value;
+ uint32_t value = 0;
int n;
- int limit;
int is_read;
is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
&& !s->linux_hack) {
- limit = is_read ? PL181_FIFO_LEN : 0;
- n = 0;
- value = 0;
- while (s->datacnt && s->fifo_len != limit) {
- if (is_read) {
+ if (is_read) {
+ n = 0;
+ while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
value |= (uint32_t)sd_read_data(s->card) << (n * 8);
+ s->datacnt--;
n++;
if (n == 4) {
pl181_fifo_push(s, value);
- value = 0;
n = 0;
+ value = 0;
}
- } else {
+ }
+ if (n != 0) {
+ pl181_fifo_push(s, value);
+ }
+ } else { /* write */
+ n = 0;
+ while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
if (n == 0) {
value = pl181_fifo_pop(s);
n = 4;
}
+ n--;
+ s->datacnt--;
sd_write_data(s->card, value & 0xff);
value >>= 8;
- n--;
}
- s->datacnt--;
- }
- if (n && is_read) {
- pl181_fifo_push(s, value);
}
}
s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
diff --git a/hw/serial.c b/hw/serial.c
index e7538ac8c..df67383d0 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -169,11 +169,19 @@ static int fifo_put(SerialState *s, int fifo, uint8_t chr)
{
SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
- f->data[f->head++] = chr;
+ /* Receive overruns do not overwrite FIFO contents. */
+ if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH) {
- if (f->head == UART_FIFO_LENGTH)
- f->head = 0;
- f->count++;
+ f->data[f->head++] = chr;
+
+ if (f->head == UART_FIFO_LENGTH)
+ f->head = 0;
+ }
+
+ if (f->count < UART_FIFO_LENGTH)
+ f->count++;
+ else if (fifo == RECV_FIFO)
+ s->lsr |= UART_LSR_OE;
return 1;
}
@@ -533,8 +541,10 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
break;
case 2:
ret = s->iir;
+ if (ret & UART_IIR_THRI) {
s->thr_ipending = 0;
- serial_update_irq(s);
+ serial_update_irq(s);
+ }
break;
case 3:
ret = s->lcr;
@@ -544,9 +554,9 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
break;
case 5:
ret = s->lsr;
- /* Clear break interrupt */
- if (s->lsr & UART_LSR_BI) {
- s->lsr &= ~UART_LSR_BI;
+ /* Clear break and overrun interrupts */
+ if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
+ s->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
serial_update_irq(s);
}
break;
@@ -629,6 +639,8 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size)
/* call the timeout receive callback in 4 char transmit time */
qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4);
} else {
+ if (s->lsr & UART_LSR_DR)
+ s->lsr |= UART_LSR_OE;
s->rbr = buf[0];
s->lsr |= UART_LSR_DR;
}
diff --git a/linux-user/main.c b/linux-user/main.c
index a0d8ce734..1189dda60 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2553,6 +2553,10 @@ int main(int argc, char **argv, char **envp)
}
cpu_model = NULL;
+#if defined(cpudef_setup)
+ cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
+#endif
+
optind = 1;
for(;;) {
if (optind >= argc)
@@ -2624,8 +2628,8 @@ int main(int argc, char **argv, char **envp)
cpu_model = argv[optind++];
if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
/* XXX: implement xxx_cpu_list for targets that still miss it */
-#if defined(cpu_list)
- cpu_list(stdout, &fprintf);
+#if defined(cpu_list_id)
+ cpu_list_id(stdout, &fprintf, "");
#endif
exit(1);
}
diff --git a/net.c b/net.c
index 88934dfff..a1bf49fa9 100644
--- a/net.c
+++ b/net.c
@@ -840,7 +840,7 @@ typedef int (*net_client_init_func)(QemuOpts *opts,
/* magic number, but compiler will warn if too small */
#define NET_MAX_DESC 20
-static struct {
+static const struct {
const char *type;
net_client_init_func init;
QemuOptDesc desc[NET_MAX_DESC];
diff --git a/pc-bios/README b/pc-bios/README
index 057092269..ee6872316 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -14,8 +14,8 @@
- OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
firmware implementation. The goal is to implement a 100% IEEE
1275-1994 (referred to as Open Firmware) compliant firmware.
- The included images for PowerPC (for 32 and 64 bit PPC CPUs) are built from
- OpenBIOS SVN revision 640, Sparc64 images from r665 and Sparc32 from r666.
+ The included images for PowerPC (for 32 and 64 bit PPC CPUs),
+ Sparc32 and Sparc64 are built from OpenBIOS SVN revision 683.
- The PXE roms come from Rom-o-Matic gPXE 0.9.9 with BANNER_TIMEOUT=0
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index 1bcfed302..b82ce2c37 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index aafb04146..4f2f45f2c 100644
--- a/pc-bios/openbios-sparc32
+++ b/pc-bios/openbios-sparc32
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index 437d24635..632f9380d 100644
--- a/pc-bios/openbios-sparc64
+++ b/pc-bios/openbios-sparc64
Binary files differ
diff --git a/qemu-char.c b/qemu-char.c
index 75dbf6685..416949221 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1173,6 +1173,22 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
return 0;
}
+static void qemu_chr_close_tty(CharDriverState *chr)
+{
+ FDCharDriver *s = chr->opaque;
+ int fd = -1;
+
+ if (s) {
+ fd = s->fd_in;
+ }
+
+ fd_chr_close(chr);
+
+ if (fd >= 0) {
+ close(fd);
+ }
+}
+
static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
{
const char *filename = qemu_opt_get(opts, "path");
@@ -1190,6 +1206,7 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
return NULL;
}
chr->chr_ioctl = tty_serial_ioctl;
+ chr->chr_close = qemu_chr_close_tty;
return chr;
}
#else /* ! __linux__ && ! __sun__ */
diff --git a/qemu-config.c b/qemu-config.c
index 2caf76c93..6cecf3341 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -246,6 +246,54 @@ QemuOptsList qemu_mon_opts = {
},
};
+QemuOptsList qemu_cpudef_opts = {
+ .name = "cpudef",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
+ .desc = {
+ {
+ .name = "name",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "level",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "vendor",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "family",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "model",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "stepping",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "feature_edx", /* cpuid 0000_0001.edx */
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "feature_ecx", /* cpuid 0000_0001.ecx */
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "extfeature_edx", /* cpuid 8000_0001.edx */
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "extfeature_ecx", /* cpuid 8000_0001.ecx */
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "xlevel",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "model_id",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "vendor_override",
+ .type = QEMU_OPT_NUMBER,
+ },
+ { /* end of list */ }
+ },
+};
+
static QemuOptsList *lists[] = {
&qemu_drive_opts,
&qemu_chardev_opts,
@@ -255,6 +303,7 @@ static QemuOptsList *lists[] = {
&qemu_rtc_opts,
&qemu_global_opts,
&qemu_mon_opts,
+ &qemu_cpudef_opts,
NULL,
};
diff --git a/qemu-config.h b/qemu-config.h
index dd89ae468..b335c4292 100644
--- a/qemu-config.h
+++ b/qemu-config.h
@@ -9,6 +9,7 @@ extern QemuOptsList qemu_net_opts;
extern QemuOptsList qemu_rtc_opts;
extern QemuOptsList qemu_global_opts;
extern QemuOptsList qemu_mon_opts;
+extern QemuOptsList qemu_cpudef_opts;
int qemu_set_option(const char *str);
int qemu_global_option(const char *str);
diff --git a/qemu-option.c b/qemu-option.c
index a52a4c4a0..de40bffc7 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -470,7 +470,7 @@ struct QemuOpt {
const char *name;
const char *str;
- QemuOptDesc *desc;
+ const QemuOptDesc *desc;
union {
int boolean;
uint64_t uint;
@@ -565,7 +565,7 @@ static void qemu_opt_del(QemuOpt *opt)
int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
{
QemuOpt *opt;
- QemuOptDesc *desc = opts->list->desc;
+ const QemuOptDesc *desc = opts->list->desc;
int i;
for (i = 0; desc[i].name != NULL; i++) {
@@ -777,7 +777,7 @@ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *fi
/* Validate parsed opts against descriptions where no
* descriptions were provided in the QemuOptsList.
*/
-int qemu_opts_validate(QemuOpts *opts, QemuOptDesc *desc)
+int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc)
{
QemuOpt *opt;
diff --git a/qemu-option.h b/qemu-option.h
index 666b666b3..f3f1de755 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -115,7 +115,7 @@ int qemu_opts_set(QemuOptsList *list, const char *id,
const char *name, const char *value);
const char *qemu_opts_id(QemuOpts *opts);
void qemu_opts_del(QemuOpts *opts);
-int qemu_opts_validate(QemuOpts *opts, QemuOptDesc *desc);
+int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc);
int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname);
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname);
diff --git a/sysconfigs/target/target-x86_64.conf b/sysconfigs/target/target-x86_64.conf
new file mode 100644
index 000000000..43ad282b5
--- /dev/null
+++ b/sysconfigs/target/target-x86_64.conf
@@ -0,0 +1,86 @@
+# x86 CPU MODELS
+
+[cpudef]
+ name = "Conroe"
+ level = "2"
+ vendor = "GenuineIntel"
+ family = "6"
+ model = "2"
+ stepping = "3"
+ feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36"
+ feature_ecx = "sse3 ssse3"
+ extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx"
+ extfeature_ecx = "lahf_lm"
+ xlevel = "0x8000000A"
+ model_id = "Intel Celeron_4x0 (Conroe/Merom Class Core 2)"
+
+[cpudef]
+ name = "Penryn"
+ level = "2"
+ vendor = "GenuineIntel"
+ family = "6"
+ model = "2"
+ stepping = "3"
+ feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36"
+ feature_ecx = "sse3 cx16 ssse3 sse4.1"
+ extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx"
+ extfeature_ecx = "lahf_lm"
+ xlevel = "0x8000000A"
+ model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)"
+
+[cpudef]
+ name = "Nehalem"
+ level = "2"
+ vendor = "GenuineIntel"
+ family = "6"
+ model = "2"
+ stepping = "3"
+ feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36"
+ feature_ecx = "sse3 cx16 ssse3 sse4.1 sse4.2 popcnt"
+ extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx"
+ extfeature_ecx = "lahf_lm"
+ xlevel = "0x8000000A"
+ model_id = "Intel Core i7 9xx (Nehalem Class Core i7)"
+
+[cpudef]
+ name = "Opteron_G1"
+ level = "5"
+ vendor = "AuthenticAMD"
+ family = "15"
+ model = "6"
+ stepping = "1"
+ feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36"
+ feature_ecx = "sse3"
+ extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx"
+# extfeature_ecx = ""
+ xlevel = "0x80000008"
+ model_id = "AMD Opteron 240 (Gen 1 Class Opteron)"
+
+[cpudef]
+ name = "Opteron_G2"
+ level = "5"
+ vendor = "AuthenticAMD"
+ family = "15"
+ model = "6"
+ stepping = "1"
+ feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36"
+ feature_ecx = "sse3 cx16"
+ extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx rdtscp"
+ extfeature_ecx = "svm lahf_lm"
+ xlevel = "0x80000008"
+ model_id = "AMD Opteron 22xx (Gen 2 Class Opteron)"
+
+[cpudef]
+ name = "Opteron_G3"
+ level = "5"
+ vendor = "AuthenticAMD"
+ family = "15"
+ model = "6"
+ stepping = "1"
+ feature_edx = "sse2 sse fxsr mmx pat cmov pge sep apic cx8 mce pae msr tsc pse de fpu mtrr clflush mca pse36"
+ feature_ecx = "sse3 cx16 monitor popcnt"
+ extfeature_edx = "fxsr mmx pat cmov pge apic cx8 mce pae msr tsc pse de fpu lm syscall nx rdtscp"
+ extfeature_ecx = "svm sse4a abm misalignsse lahf_lm"
+ xlevel = "0x80000008"
+ model_id = "AMD Opteron 23xx (Gen 3 Class Opteron)"
+
diff --git a/target-cris/translate_v10.c b/target-cris/translate_v10.c
index 9a29c5117..9abf1a837 100644
--- a/target-cris/translate_v10.c
+++ b/target-cris/translate_v10.c
@@ -1187,6 +1187,10 @@ static unsigned int crisv10_decoder(DisasContext *dc)
dc->cpustate_changed = 1;
}
+ /* CRISv10 locks out interrupts on dslots. */
+ if (dc->delayed_branch == 2) {
+ cris_lock_irq(dc);
+ }
return insn_len;
}
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 7d0bbd012..b64bd02a2 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -741,8 +741,10 @@ typedef struct CPUX86State {
CPUX86State *cpu_x86_init(const char *cpu_model);
int cpu_x86_exec(CPUX86State *s);
void cpu_x86_close(CPUX86State *s);
-void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt,
- ...));
+void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ const char *optarg);
+void x86_cpudef_setup(void);
+
int cpu_get_pic_interrupt(CPUX86State *s);
/* MSDOS compatibility mode FPU exception support */
void cpu_set_ferr(CPUX86State *s);
@@ -894,7 +896,8 @@ uint64_t cpu_get_tsc(CPUX86State *env);
#define cpu_exec cpu_x86_exec
#define cpu_gen_code cpu_x86_gen_code
#define cpu_signal_handler cpu_x86_signal_handler
-#define cpu_list x86_cpu_list
+#define cpu_list_id x86_cpu_list
+#define cpudef_setup x86_cpudef_setup
#define CPU_SAVE_VERSION 12
diff --git a/target-i386/helper.c b/target-i386/helper.c
index f9d63f6ab..73381e294 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -31,33 +31,52 @@
#include "qemu-kvm.h"
//#define DEBUG_MMU
+#include "qemu-option.h"
+#include "qemu-config.h"
/* feature flags taken from "Intel Processor Identification and the CPUID
- * Instruction" and AMD's "CPUID Specification". In cases of disagreement
- * about feature names, the Linux name is used. */
+ * Instruction" and AMD's "CPUID Specification". In cases of disagreement
+ * between feature naming conventions, aliases may be added.
+ */
static const char *feature_name[] = {
- "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, NULL, "ds" /* Intel dts */, "acpi", "mmx",
- "fxsr", "sse", "sse2", "ss", "ht" /* Intel htt */, "tm", "ia64", "pbe",
+ "fpu", "vme", "de", "pse",
+ "tsc", "msr", "pae", "mce",
+ "cx8", "apic", NULL, "sep",
+ "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */,
+ NULL, "ds" /* Intel dts */, "acpi", "mmx",
+ "fxsr", "sse", "sse2", "ss",
+ "ht" /* Intel htt */, "tm", "ia64", "pbe",
};
static const char *ext_feature_name[] = {
- "pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est",
- "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
- NULL, NULL, "dca", NULL, NULL, "x2apic", NULL, "popcnt",
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, "hypervisor",
+ "pni|sse3" /* Intel,AMD sse3 */, NULL, NULL, "monitor",
+ "ds_cpl", "vmx", NULL /* Linux smx */, "est",
+ "tm2", "ssse3", "cid", NULL,
+ NULL, "cx16", "xtpr", NULL,
+ NULL, NULL, "dca", "sse4.1|sse4_1",
+ "sse4.2|sse4_2", "x2apic", NULL, "popcnt",
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "hypervisor",
};
static const char *ext2_feature_name[] = {
- "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mtrr", "pge", "mca", "cmov",
- "pat", "pse36", NULL, NULL /* Linux mp */, "nx" /* Intel xd */, NULL, "mmxext", "mmx",
- "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp", NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
+ "fpu", "vme", "de", "pse",
+ "tsc", "msr", "pae", "mce",
+ "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall",
+ "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", NULL, NULL /* Linux mp */,
+ "nx" /* Intel xd */, NULL, "mmxext", "mmx",
+ "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp",
+ NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
};
static const char *ext3_feature_name[] = {
- "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
- "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL, "skinit", "wdt", NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */,
+ "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
+ "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL,
+ "skinit", "wdt", NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
};
static const char *kvm_feature_name[] = {
@@ -67,47 +86,99 @@ static const char *kvm_feature_name[] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
+/* collects per-function cpuid data
+ */
+typedef struct model_features_t {
+ uint32_t *guest_feat;
+ uint32_t *host_feat;
+ uint32_t check_feat;
+ const char **flag_names;
+ uint32_t cpuid;
+ } model_features_t;
+
+int check_cpuid = 0;
+int enforce_cpuid = 0;
+
+static void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax,
+ uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
+
+#define iswhite(c) ((c) && ((c) <= ' ' || '~' < (c)))
+
+/* general substring compare of *[s1..e1) and *[s2..e2). sx is start of
+ * a substring. ex if !NULL points to the first char after a substring,
+ * otherwise the string is assumed to sized by a terminating nul.
+ * Return lexical ordering of *s1:*s2.
+ */
+static int sstrcmp(const char *s1, const char *e1, const char *s2,
+ const char *e2)
+{
+ for (;;) {
+ if (!*s1 || !*s2 || *s1 != *s2)
+ return (*s1 - *s2);
+ ++s1, ++s2;
+ if (s1 == e1 && s2 == e2)
+ return (0);
+ else if (s1 == e1)
+ return (*s2);
+ else if (s2 == e2)
+ return (*s1);
+ }
+}
+
+/* compare *[s..e) to *altstr. *altstr may be a simple string or multiple
+ * '|' delimited (possibly empty) strings in which case search for a match
+ * within the alternatives proceeds left to right. Return 0 for success,
+ * non-zero otherwise.
+ */
+static int altcmp(const char *s, const char *e, const char *altstr)
+{
+ const char *p, *q;
+
+ for (q = p = altstr; ; ) {
+ while (*p && *p != '|')
+ ++p;
+ if ((q == p && !*s) || (q != p && !sstrcmp(s, e, q, p)))
+ return (0);
+ if (!*p)
+ return (1);
+ else
+ q = ++p;
+ }
+}
+
+/* search featureset for flag *[s..e), if found set corresponding bit in
+ * *pval and return success, otherwise return zero
+ */
+static int lookup_feature(uint32_t *pval, const char *s, const char *e,
+ const char **featureset)
+{
+ uint32_t mask;
+ const char **ppc;
+
+ for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc)
+ if (*ppc && !altcmp(s, e, *ppc)) {
+ *pval |= mask;
+ break;
+ }
+ return (mask ? 1 : 0);
+}
+
static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
uint32_t *ext_features,
uint32_t *ext2_features,
uint32_t *ext3_features,
uint32_t *kvm_features)
{
- int i;
- int found = 0;
-
- for ( i = 0 ; i < 32 ; i++ )
- if (feature_name[i] && !strcmp (flagname, feature_name[i])) {
- *features |= 1 << i;
- found = 1;
- }
- for ( i = 0 ; i < 32 ; i++ )
- if (ext_feature_name[i] && !strcmp (flagname, ext_feature_name[i])) {
- *ext_features |= 1 << i;
- found = 1;
- }
- for ( i = 0 ; i < 32 ; i++ )
- if (ext2_feature_name[i] && !strcmp (flagname, ext2_feature_name[i])) {
- *ext2_features |= 1 << i;
- found = 1;
- }
- for ( i = 0 ; i < 32 ; i++ )
- if (ext3_feature_name[i] && !strcmp (flagname, ext3_feature_name[i])) {
- *ext3_features |= 1 << i;
- found = 1;
- }
- for ( i = 0 ; i < 32 ; i++ )
- if (kvm_feature_name[i] && !strcmp (flagname, kvm_feature_name[i])) {
- *kvm_features |= 1 << i;
- found = 1;
- }
-
- if (!found) {
- fprintf(stderr, "CPU feature %s not found\n", flagname);
- }
+ if (!lookup_feature(features, flagname, NULL, feature_name) &&
+ !lookup_feature(ext_features, flagname, NULL, ext_feature_name) &&
+ !lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) &&
+ !lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) &&
+ !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name))
+ fprintf(stderr, "CPU feature %s not found\n", flagname);
}
typedef struct x86_def_t {
+ struct x86_def_t *next;
const char *name;
uint32_t level;
uint32_t vendor1, vendor2, vendor3;
@@ -118,6 +189,7 @@ typedef struct x86_def_t {
uint32_t xlevel;
char model_id[48];
int vendor_override;
+ uint32_t flags;
} x86_def_t;
#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -131,7 +203,14 @@ typedef struct x86_def_t {
CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
CPUID_PAE | CPUID_SEP | CPUID_APIC)
-static x86_def_t x86_defs[] = {
+
+/* maintains list of cpu model definitions
+ */
+static x86_def_t *x86_defs = {NULL};
+
+/* built-in cpu model definitions (deprecated)
+ */
+static x86_def_t builtin_x86_defs[] = {
#ifdef TARGET_X86_64
{
.name = "qemu64",
@@ -336,9 +415,6 @@ static x86_def_t x86_defs[] = {
},
};
-static void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax,
- uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
-
static int cpu_x86_fill_model_id(char *str)
{
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
@@ -384,6 +460,51 @@ static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
return 0;
}
+static int unavailable_host_feature(struct model_features_t *f, uint32_t mask)
+{
+ int i;
+
+ for (i = 0; i < 32; ++i)
+ if (1 << i & mask) {
+ fprintf(stderr, "warning: host cpuid %04x_%04x lacks requested"
+ " flag '%s' [0x%08x]\n",
+ f->cpuid >> 16, f->cpuid & 0xffff,
+ f->flag_names[i] ? f->flag_names[i] : "[reserved]", mask);
+ break;
+ }
+ return 0;
+}
+
+/* best effort attempt to inform user requested cpu flags aren't making
+ * their way to the guest. Note: ft[].check_feat ideally should be
+ * specified via a guest_def field to suppress report of extraneous flags.
+ */
+static int check_features_against_host(x86_def_t *guest_def)
+{
+ x86_def_t host_def;
+ uint32_t mask;
+ int rv, i;
+ struct model_features_t ft[] = {
+ {&guest_def->features, &host_def.features,
+ ~0, feature_name, 0x00000000},
+ {&guest_def->ext_features, &host_def.ext_features,
+ ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001},
+ {&guest_def->ext2_features, &host_def.ext2_features,
+ ~PPRO_FEATURES, ext2_feature_name, 0x80000000},
+ {&guest_def->ext3_features, &host_def.ext3_features,
+ ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}};
+
+ cpu_x86_fill_host(&host_def);
+ for (rv = 0, i = 0; i < sizeof (ft) / sizeof (ft[0]); ++i)
+ for (mask = 1; mask; mask <<= 1)
+ if (ft[i].check_feat & mask && *ft[i].guest_feat & mask &&
+ !(*ft[i].host_feat & mask)) {
+ unavailable_host_feature(&ft[i], mask);
+ rv = 1;
+ }
+ return rv;
+}
+
static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
{
unsigned int i;
@@ -395,13 +516,9 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0, minus_kvm_features = 0;
uint32_t numvalue;
- def = NULL;
- for (i = 0; i < ARRAY_SIZE(x86_defs); i++) {
- if (strcmp(name, x86_defs[i].name) == 0) {
- def = &x86_defs[i];
+ for (def = x86_defs; def; def = def->next)
+ if (!strcmp(name, def->name))
break;
- }
- }
if (kvm_enabled() && strcmp(name, "host") == 0) {
cpu_x86_fill_host(x86_cpu_def);
} else if (!def) {
@@ -490,6 +607,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
fprintf(stderr, "unrecognized feature %s\n", featurestr);
goto error;
}
+ } else if (!strcmp(featurestr, "check")) {
+ check_cpuid = 1;
+ } else if (!strcmp(featurestr, "enforce")) {
+ check_cpuid = enforce_cpuid = 1;
} else {
fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
goto error;
@@ -506,6 +627,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
x86_cpu_def->ext2_features &= ~minus_ext2_features;
x86_cpu_def->ext3_features &= ~minus_ext3_features;
x86_cpu_def->kvm_features &= ~minus_kvm_features;
+ if (check_cpuid) {
+ if (check_features_against_host(x86_cpu_def) && enforce_cpuid)
+ goto error;
+ }
free(s);
return 0;
@@ -514,12 +639,97 @@ error:
return -1;
}
-void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+/* generate a composite string into buf of all cpuid names in featureset
+ * selected by fbits. indicate truncation at bufsize in the event of overflow.
+ * if flags, suppress names undefined in featureset.
+ */
+static void listflags(char *buf, int bufsize, uint32_t fbits,
+ const char **featureset, uint32_t flags)
{
- unsigned int i;
+ const char **p = &featureset[31];
+ char *q, *b, bit;
+ int nc;
+
+ b = 4 <= bufsize ? buf + (bufsize -= 3) - 1 : NULL;
+ *buf = '\0';
+ for (q = buf, bit = 31; fbits && bufsize; --p, fbits &= ~(1 << bit), --bit)
+ if (fbits & 1 << bit && (*p || !flags)) {
+ if (*p)
+ nc = snprintf(q, bufsize, "%s%s", q == buf ? "" : " ", *p);
+ else
+ nc = snprintf(q, bufsize, "%s[%d]", q == buf ? "" : " ", bit);
+ if (bufsize <= nc) {
+ if (b)
+ sprintf(b, "...");
+ return;
+ }
+ q += nc;
+ bufsize -= nc;
+ }
+}
- for (i = 0; i < ARRAY_SIZE(x86_defs); i++)
- (*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name);
+/* generate CPU information:
+ * -? list model names
+ * -?model list model names/IDs
+ * -?dump output all model (x86_def_t) data
+ * -?cpuid list all recognized cpuid flag names
+ */
+void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ const char *optarg)
+{
+ unsigned char model = !strcmp("?model", optarg);
+ unsigned char dump = !strcmp("?dump", optarg);
+ unsigned char cpuid = !strcmp("?cpuid", optarg);
+ x86_def_t *def;
+ char buf[256];
+
+ if (cpuid) {
+ (*cpu_fprintf)(f, "Recognized CPUID flags:\n");
+ listflags(buf, sizeof (buf), (uint32_t)~0, feature_name, 1);
+ (*cpu_fprintf)(f, " f_edx: %s\n", buf);
+ listflags(buf, sizeof (buf), (uint32_t)~0, ext_feature_name, 1);
+ (*cpu_fprintf)(f, " f_ecx: %s\n", buf);
+ listflags(buf, sizeof (buf), (uint32_t)~0, ext2_feature_name, 1);
+ (*cpu_fprintf)(f, " extf_edx: %s\n", buf);
+ listflags(buf, sizeof (buf), (uint32_t)~0, ext3_feature_name, 1);
+ (*cpu_fprintf)(f, " extf_ecx: %s\n", buf);
+ return;
+ }
+ for (def = x86_defs; def; def = def->next) {
+ snprintf(buf, sizeof (buf), def->flags ? "[%s]": "%s", def->name);
+ if (model || dump) {
+ (*cpu_fprintf)(f, "x86 %16s %-48s\n", buf, def->model_id);
+ } else {
+ (*cpu_fprintf)(f, "x86 %16s\n", buf);
+ }
+ if (dump) {
+ memcpy(buf, &def->vendor1, sizeof (def->vendor1));
+ memcpy(buf + 4, &def->vendor2, sizeof (def->vendor2));
+ memcpy(buf + 8, &def->vendor3, sizeof (def->vendor3));
+ buf[12] = '\0';
+ (*cpu_fprintf)(f,
+ " family %d model %d stepping %d level %d xlevel 0x%x"
+ " vendor \"%s\"\n",
+ def->family, def->model, def->stepping, def->level,
+ def->xlevel, buf);
+ listflags(buf, sizeof (buf), def->features, feature_name, 0);
+ (*cpu_fprintf)(f, " feature_edx %08x (%s)\n", def->features,
+ buf);
+ listflags(buf, sizeof (buf), def->ext_features, ext_feature_name,
+ 0);
+ (*cpu_fprintf)(f, " feature_ecx %08x (%s)\n", def->ext_features,
+ buf);
+ listflags(buf, sizeof (buf), def->ext2_features, ext2_feature_name,
+ 0);
+ (*cpu_fprintf)(f, " extfeature_edx %08x (%s)\n",
+ def->ext2_features, buf);
+ listflags(buf, sizeof (buf), def->ext3_features, ext3_feature_name,
+ 0);
+ (*cpu_fprintf)(f, " extfeature_ecx %08x (%s)\n",
+ def->ext3_features, buf);
+ (*cpu_fprintf)(f, "\n");
+ }
+ }
}
static int cpu_x86_register (CPUX86State *env, const char *cpu_model)
@@ -568,6 +778,128 @@ static int cpu_x86_register (CPUX86State *env, const char *cpu_model)
return 0;
}
+#if !defined(CONFIG_LINUX_USER)
+/* copy vendor id string to 32 bit register, nul pad as needed
+ */
+static void cpyid(const char *s, uint32_t *id)
+{
+ char *d = (char *)id;
+ char i;
+
+ for (i = sizeof (*id); i--; )
+ *d++ = *s ? *s++ : '\0';
+}
+
+/* interpret radix and convert from string to arbitrary scalar,
+ * otherwise flag failure
+ */
+#define setscalar(pval, str, perr) \
+{ \
+ char *pend; \
+ unsigned long ul; \
+ \
+ ul = strtoul(str, &pend, 0); \
+ *str && !*pend ? (*pval = ul) : (*perr = 1); \
+}
+
+/* map cpuid options to feature bits, otherwise return failure
+ * (option tags in *str are delimited by whitespace)
+ */
+static void setfeatures(uint32_t *pval, const char *str,
+ const char **featureset, int *perr)
+{
+ const char *p, *q;
+
+ for (q = p = str; *p || *q; q = p) {
+ while (iswhite(*p))
+ q = ++p;
+ while (*p && !iswhite(*p))
+ ++p;
+ if (!*q && !*p)
+ return;
+ if (!lookup_feature(pval, q, p, featureset)) {
+ fprintf(stderr, "error: feature \"%.*s\" not available in set\n",
+ (int)(p - q), q);
+ *perr = 1;
+ return;
+ }
+ }
+}
+
+/* map config file options to x86_def_t form
+ */
+static int cpudef_setfield(const char *name, const char *str, void *opaque)
+{
+ x86_def_t *def = opaque;
+ int err = 0;
+
+ if (!strcmp(name, "name")) {
+ def->name = strdup(str);
+ } else if (!strcmp(name, "model_id")) {
+ strncpy(def->model_id, str, sizeof (def->model_id));
+ } else if (!strcmp(name, "level")) {
+ setscalar(&def->level, str, &err)
+ } else if (!strcmp(name, "vendor")) {
+ cpyid(&str[0], &def->vendor1);
+ cpyid(&str[4], &def->vendor2);
+ cpyid(&str[8], &def->vendor3);
+ } else if (!strcmp(name, "family")) {
+ setscalar(&def->family, str, &err)
+ } else if (!strcmp(name, "model")) {
+ setscalar(&def->model, str, &err)
+ } else if (!strcmp(name, "stepping")) {
+ setscalar(&def->stepping, str, &err)
+ } else if (!strcmp(name, "feature_edx")) {
+ setfeatures(&def->features, str, feature_name, &err);
+ } else if (!strcmp(name, "feature_ecx")) {
+ setfeatures(&def->ext_features, str, ext_feature_name, &err);
+ } else if (!strcmp(name, "extfeature_edx")) {
+ setfeatures(&def->ext2_features, str, ext2_feature_name, &err);
+ } else if (!strcmp(name, "extfeature_ecx")) {
+ setfeatures(&def->ext3_features, str, ext3_feature_name, &err);
+ } else if (!strcmp(name, "xlevel")) {
+ setscalar(&def->xlevel, str, &err)
+ } else {
+ fprintf(stderr, "error: unknown option [%s = %s]\n", name, str);
+ return (1);
+ }
+ if (err) {
+ fprintf(stderr, "error: bad option value [%s = %s]\n", name, str);
+ return (1);
+ }
+ return (0);
+}
+
+/* register config file entry as x86_def_t
+ */
+static int cpudef_register(QemuOpts *opts, void *opaque)
+{
+ x86_def_t *def = qemu_mallocz(sizeof (x86_def_t));
+
+ qemu_opt_foreach(opts, cpudef_setfield, def, 1);
+ def->next = x86_defs;
+ x86_defs = def;
+ return (0);
+}
+#endif /* !CONFIG_LINUX_USER */
+
+/* register "cpudef" models defined in configuration file. Here we first
+ * preload any built-in definitions
+ */
+void x86_cpudef_setup(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
+ builtin_x86_defs[i].next = x86_defs;
+ builtin_x86_defs[i].flags = 1;
+ x86_defs = &builtin_x86_defs[i];
+ }
+#if !defined(CONFIG_LINUX_USER)
+ qemu_opts_foreach(&qemu_cpudef_opts, cpudef_register, NULL, 0);
+#endif
+}
+
/* NOTE: must be called outside the CPU execute loop */
void cpu_reset(CPUX86State *env)
{
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index af89dcfa6..8a9cea2f2 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -251,6 +251,12 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
int is_asi, int size)
{
CPUState *saved_env;
+
+ if (!cpu_single_env) {
+ /* XXX: ??? */
+ return;
+ }
+
/* XXX: hack to restore env in all cases, even if not called from
generated code */
saved_env = env;
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index 583f09d7b..ca54e2c30 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -993,6 +993,7 @@ static void dec_bcc(DisasContext *dc)
static void dec_br(DisasContext *dc)
{
unsigned int dslot, link, abs;
+ int mem_index = cpu_mmu_index(dc->env);
dslot = dc->ir & (1 << 20);
abs = dc->ir & (1 << 19);
@@ -1016,11 +1017,19 @@ static void dec_br(DisasContext *dc)
if (abs) {
tcg_gen_movi_tl(env_btaken, 1);
tcg_gen_mov_tl(env_btarget, *(dec_alu_op_b(dc)));
- if (link && !(dc->tb_flags & IMM_FLAG)
- && (dc->imm == 8 || dc->imm == 0x18))
- t_gen_raise_exception(dc, EXCP_BREAK);
- if (dc->imm == 0)
- t_gen_raise_exception(dc, EXCP_DEBUG);
+ if (link && !dslot) {
+ if (!(dc->tb_flags & IMM_FLAG) && (dc->imm == 8 || dc->imm == 0x18))
+ t_gen_raise_exception(dc, EXCP_BREAK);
+ if (dc->imm == 0) {
+ if ((dc->tb_flags & MSR_EE_FLAG) && mem_index == MMU_USER_IDX) {
+ tcg_gen_movi_tl(cpu_SR[SR_ESR], ESR_EC_PRIVINSN);
+ t_gen_raise_exception(dc, EXCP_HW_EXCP);
+ return;
+ }
+
+ t_gen_raise_exception(dc, EXCP_DEBUG);
+ }
+ }
} else {
if (!dc->type_b || (dc->tb_flags & IMM_FLAG)) {
tcg_gen_movi_tl(env_btaken, 1);
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 7e9f0cfe7..b7d2a324c 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -1663,27 +1663,27 @@ static inline TCGv get_src2(unsigned int insn, TCGv def)
#ifdef TARGET_SPARC64
static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env)
{
- TCGv r_tl = tcg_temp_new();
+ TCGv_i32 r_tl = tcg_temp_new_i32();
/* load env->tl into r_tl */
- {
- TCGv_i32 r_tl_tmp = tcg_temp_new_i32();
- tcg_gen_ld_i32(r_tl_tmp, cpu_env, offsetof(CPUSPARCState, tl));
- tcg_gen_ext_i32_tl(r_tl, r_tl_tmp);
- tcg_temp_free_i32(r_tl_tmp);
- }
+ tcg_gen_ld_i32(r_tl, cpu_env, offsetof(CPUSPARCState, tl));
/* tl = [0 ... MAXTL_MASK] where MAXTL_MASK must be power of 2 */
- tcg_gen_andi_tl(r_tl, r_tl, MAXTL_MASK);
+ tcg_gen_andi_i32(r_tl, r_tl, MAXTL_MASK);
/* calculate offset to current trap state from env->ts, reuse r_tl */
- tcg_gen_muli_tl(r_tl, r_tl, sizeof (trap_state));
+ tcg_gen_muli_i32(r_tl, r_tl, sizeof (trap_state));
tcg_gen_addi_ptr(r_tsptr, cpu_env, offsetof(CPUState, ts));
/* tsptr = env->ts[env->tl & MAXTL_MASK] */
- tcg_gen_add_ptr(r_tsptr, r_tsptr, r_tl);
+ {
+ TCGv_ptr r_tl_tmp = tcg_temp_new_ptr();
+ tcg_gen_ext_i32_ptr(r_tl_tmp, r_tl);
+ tcg_gen_add_ptr(r_tsptr, r_tsptr, r_tl_tmp);
+ tcg_temp_free_i32(r_tl_tmp);
+ }
- tcg_temp_free(r_tl);
+ tcg_temp_free_i32(r_tl);
}
#endif
diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c
index ddce60c81..4677971e7 100644
--- a/tcg/hppa/tcg-target.c
+++ b/tcg/hppa/tcg-target.c
@@ -936,7 +936,6 @@ static const TCGTargetOpDef hppa_op_defs[] = {
{ INDEX_op_qemu_ld16u, { "r", "L", "L" } },
{ INDEX_op_qemu_ld16s, { "r", "L", "L" } },
{ INDEX_op_qemu_ld32u, { "r", "L", "L" } },
- { INDEX_op_qemu_ld32s, { "r", "L", "L" } },
{ INDEX_op_qemu_ld64, { "r", "r", "L", "L" } },
{ INDEX_op_qemu_st8, { "L", "L", "L" } },
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index 903b69ff0..96cc46190 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -333,6 +333,7 @@ static int tcg_target_const_match(tcg_target_long val,
#define STWU OPCD(37)
#define RLWINM OPCD(21)
+#define RLWNM OPCD(23)
#define BCLR XO19( 16)
#define BCCTR XO19(528)
@@ -369,6 +370,9 @@ static int tcg_target_const_match(tcg_target_long val,
#define NEG XO31(104)
#define MFCR XO31( 19)
#define CNTLZW XO31( 26)
+#define NOR XO31(124)
+#define ANDC XO31( 60)
+#define ORC XO31(412)
#define LBZX XO31( 87)
#define LHZX XO31(279)
@@ -1468,6 +1472,12 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
else
tcg_out32 (s, XOR | SAB (args[1], args[0], args[2]));
break;
+ case INDEX_op_andc_i32:
+ tcg_out32 (s, ANDC | SAB (args[1], args[0], args[2]));
+ break;
+ case INDEX_op_orc_i32:
+ tcg_out32 (s, ORC | SAB (args[1], args[0], args[2]));
+ break;
case INDEX_op_mul_i32:
if (const_args[2]) {
@@ -1549,6 +1559,45 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
else
tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2]));
break;
+ case INDEX_op_rotl_i32:
+ {
+ int op = 0
+ | RA (args[0])
+ | RS (args[1])
+ | MB (0)
+ | ME (31)
+ | (const_args[2] ? RLWINM | SH (args[2])
+ : RLWNM | RB (args[2]))
+ ;
+ tcg_out32 (s, op);
+ }
+ break;
+ case INDEX_op_rotr_i32:
+ if (const_args[2]) {
+ if (!args[2]) {
+ tcg_out_mov (s, args[0], args[1]);
+ }
+ else {
+ tcg_out32 (s, RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (32 - args[2])
+ | MB (0)
+ | ME (31)
+ );
+ }
+ }
+ else {
+ tcg_out32 (s, ADDI | RT (0) | RA (args[2]) | 0xffe0);
+ tcg_out32 (s, RLWNM
+ | RA (args[0])
+ | RS (args[1])
+ | RB (0)
+ | MB (0)
+ | ME (31)
+ );
+ }
+ break;
case INDEX_op_add2_i32:
if (args[0] == args[3] || args[0] == args[5]) {
@@ -1591,6 +1640,10 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
tcg_out32 (s, NEG | RT (args[0]) | RA (args[1]));
break;
+ case INDEX_op_not_i32:
+ tcg_out32 (s, NOR | SAB (args[1], args[0], args[0]));
+ break;
+
case INDEX_op_qemu_ld8u:
tcg_out_qemu_ld(s, args, 0);
break;
@@ -1625,9 +1678,27 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
case INDEX_op_ext8s_i32:
tcg_out32 (s, EXTSB | RS (args[1]) | RA (args[0]));
break;
+ case INDEX_op_ext8u_i32:
+ tcg_out32 (s, RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (0)
+ | MB (24)
+ | ME (31)
+ );
+ break;
case INDEX_op_ext16s_i32:
tcg_out32 (s, EXTSH | RS (args[1]) | RA (args[0]));
break;
+ case INDEX_op_ext16u_i32:
+ tcg_out32 (s, RLWINM
+ | RA (args[0])
+ | RS (args[1])
+ | SH (0)
+ | MB (16)
+ | ME (31)
+ );
+ break;
case INDEX_op_setcond_i32:
tcg_out_setcond (s, args[3], args[0], args[1], args[2], const_args[2]);
@@ -1676,6 +1747,9 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ INDEX_op_shr_i32, { "r", "r", "ri" } },
{ INDEX_op_sar_i32, { "r", "r", "ri" } },
+ { INDEX_op_rotl_i32, { "r", "r", "ri" } },
+ { INDEX_op_rotr_i32, { "r", "r", "ri" } },
+
{ INDEX_op_brcond_i32, { "r", "ri" } },
{ INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } },
@@ -1683,6 +1757,10 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ INDEX_op_brcond2_i32, { "r", "r", "r", "r" } },
{ INDEX_op_neg_i32, { "r", "r" } },
+ { INDEX_op_not_i32, { "r", "r" } },
+
+ { INDEX_op_andc_i32, { "r", "r", "r" } },
+ { INDEX_op_orc_i32, { "r", "r", "r" } },
{ INDEX_op_setcond_i32, { "r", "r", "ri" } },
{ INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } },
@@ -1693,7 +1771,6 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ INDEX_op_qemu_ld16u, { "r", "L" } },
{ INDEX_op_qemu_ld16s, { "r", "L" } },
{ INDEX_op_qemu_ld32u, { "r", "L" } },
- { INDEX_op_qemu_ld32s, { "r", "L" } },
{ INDEX_op_qemu_ld64, { "r", "r", "L" } },
{ INDEX_op_qemu_st8, { "K", "K" } },
@@ -1706,7 +1783,6 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ INDEX_op_qemu_ld16u, { "r", "L", "L" } },
{ INDEX_op_qemu_ld16s, { "r", "L", "L" } },
{ INDEX_op_qemu_ld32u, { "r", "L", "L" } },
- { INDEX_op_qemu_ld32s, { "r", "L", "L" } },
{ INDEX_op_qemu_ld64, { "r", "L", "L", "L" } },
{ INDEX_op_qemu_st8, { "K", "K", "K" } },
@@ -1716,7 +1792,9 @@ static const TCGTargetOpDef ppc_op_defs[] = {
#endif
{ INDEX_op_ext8s_i32, { "r", "r" } },
+ { INDEX_op_ext8u_i32, { "r", "r" } },
{ INDEX_op_ext16s_i32, { "r", "r" } },
+ { INDEX_op_ext16u_i32, { "r", "r" } },
{ -1 },
};
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index 71bc7c1d0..0c71a1103 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -78,17 +78,17 @@ enum {
/* optional instructions */
#define TCG_TARGET_HAS_div_i32
-// #define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_rot_i32
#define TCG_TARGET_HAS_ext8s_i32
#define TCG_TARGET_HAS_ext16s_i32
-// #define TCG_TARGET_HAS_ext8u_i32
-// #define TCG_TARGET_HAS_ext16u_i32
-// #define TCG_TARGET_HAS_bswap16_i32
-// #define TCG_TARGET_HAS_bswap32_i32
-// #define TCG_TARGET_HAS_not_i32
+#define TCG_TARGET_HAS_ext8u_i32
+#define TCG_TARGET_HAS_ext16u_i32
+/* #define TCG_TARGET_HAS_bswap16_i32 */
+/* #define TCG_TARGET_HAS_bswap32_i32 */
+#define TCG_TARGET_HAS_not_i32
#define TCG_TARGET_HAS_neg_i32
-// #define TCG_TARGET_HAS_andc_i32
-// #define TCG_TARGET_HAS_orc_i32
+#define TCG_TARGET_HAS_andc_i32
+#define TCG_TARGET_HAS_orc_i32
#define TCG_AREG0 TCG_REG_R27
#define TCG_AREG1 TCG_REG_R24
diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h
index 8f7891b78..f5de6421f 100644
--- a/tcg/ppc64/tcg-target.h
+++ b/tcg/ppc64/tcg-target.h
@@ -69,33 +69,33 @@ enum {
/* optional instructions */
#define TCG_TARGET_HAS_div_i32
-// #define TCG_TARGET_HAS_rot_i32
+/* #define TCG_TARGET_HAS_rot_i32 */
#define TCG_TARGET_HAS_ext8s_i32
#define TCG_TARGET_HAS_ext16s_i32
-// #define TCG_TARGET_HAS_ext8u_i32
-// #define TCG_TARGET_HAS_ext16u_i32
-// #define TCG_TARGET_HAS_bswap16_i32
-// #define TCG_TARGET_HAS_bswap32_i32
-// #define TCG_TARGET_HAS_not_i32
+/* #define TCG_TARGET_HAS_ext8u_i32 */
+/* #define TCG_TARGET_HAS_ext16u_i32 */
+/* #define TCG_TARGET_HAS_bswap16_i32 */
+/* #define TCG_TARGET_HAS_bswap32_i32 */
+/* #define TCG_TARGET_HAS_not_i32 */
#define TCG_TARGET_HAS_neg_i32
-// #define TCG_TARGET_HAS_andc_i32
-// #define TCG_TARGET_HAS_orc_i32
+/* #define TCG_TARGET_HAS_andc_i32 */
+/* #define TCG_TARGET_HAS_orc_i32 */
#define TCG_TARGET_HAS_div_i64
-// #define TCG_TARGET_HAS_rot_i64
+/* #define TCG_TARGET_HAS_rot_i64 */
#define TCG_TARGET_HAS_ext8s_i64
#define TCG_TARGET_HAS_ext16s_i64
#define TCG_TARGET_HAS_ext32s_i64
-// #define TCG_TARGET_HAS_ext8u_i64
-// #define TCG_TARGET_HAS_ext16u_i64
-// #define TCG_TARGET_HAS_ext32u_i64
-// #define TCG_TARGET_HAS_bswap16_i64
-// #define TCG_TARGET_HAS_bswap32_i64
-// #define TCG_TARGET_HAS_bswap64_i64
-// #define TCG_TARGET_HAS_not_i64
+/* #define TCG_TARGET_HAS_ext8u_i64 */
+/* #define TCG_TARGET_HAS_ext16u_i64 */
+/* #define TCG_TARGET_HAS_ext32u_i64 */
+/* #define TCG_TARGET_HAS_bswap16_i64 */
+/* #define TCG_TARGET_HAS_bswap32_i64 */
+/* #define TCG_TARGET_HAS_bswap64_i64 */
+/* #define TCG_TARGET_HAS_not_i64 */
#define TCG_TARGET_HAS_neg_i64
-// #define TCG_TARGET_HAS_andc_i64
-// #define TCG_TARGET_HAS_orc_i64
+/* #define TCG_TARGET_HAS_andc_i64 */
+/* #define TCG_TARGET_HAS_orc_i64 */
#define TCG_AREG0 TCG_REG_R27
#define TCG_AREG1 TCG_REG_R24
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index 891b8c4d5..d4ddaa79b 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -1319,9 +1319,11 @@ static inline void tcg_out_op(TCGContext *s, int opc, const TCGArg *args,
case INDEX_op_qemu_ld32u:
tcg_out_qemu_ld(s, args, 2);
break;
+#if TCG_TARGET_REG_BITS == 64
case INDEX_op_qemu_ld32s:
tcg_out_qemu_ld(s, args, 2 | 4);
break;
+#endif
case INDEX_op_qemu_st8:
tcg_out_qemu_st(s, args, 0);
break;
@@ -1471,7 +1473,9 @@ static const TCGTargetOpDef sparc_op_defs[] = {
{ INDEX_op_qemu_ld16u, { "r", "L" } },
{ INDEX_op_qemu_ld16s, { "r", "L" } },
{ INDEX_op_qemu_ld32u, { "r", "L" } },
+#if TCG_TARGET_REG_BITS == 64
{ INDEX_op_qemu_ld32s, { "r", "L" } },
+#endif
{ INDEX_op_qemu_st8, { "L", "L" } },
{ INDEX_op_qemu_st16, { "L", "L" } },
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index 34cdba5b5..01fea1e50 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -236,11 +236,6 @@ DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
DEF2(qemu_ld32u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif
#if TARGET_LONG_BITS == 32
-DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-#else
-DEF2(qemu_ld32s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-#endif
-#if TARGET_LONG_BITS == 32
DEF2(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#else
DEF2(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
diff --git a/vl.c b/vl.c
index 9babbfb53..729c95589 100644
--- a/vl.c
+++ b/vl.c
@@ -4976,6 +4976,9 @@ int main(int argc, char **argv, char **envp)
fclose(fp);
}
}
+#if defined(cpudef_setup)
+ cpudef_setup(); /* parse cpu definitions in target config file */
+#endif
/* second pass of option parsing */
optind = 1;
@@ -5009,8 +5012,10 @@ int main(int argc, char **argv, char **envp)
/* hw initialization will check this */
if (*optarg == '?') {
/* XXX: implement xxx_cpu_list for targets that still miss it */
-#if defined(cpu_list)
- cpu_list(stdout, &fprintf);
+#if defined(cpu_list_id)
+ cpu_list_id(stdout, &fprintf, optarg);
+#elif defined(cpu_list)
+ cpu_list(stdout, &fprintf); /* deprecated */
#endif
exit(0);
} else {