aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2008-12-23 18:52:56 +0200
committerAvi Kivity <avi@redhat.com>2008-12-23 18:52:56 +0200
commit1f073a17638ec332c86f0d065caebf9c7555686d (patch)
tree6853b18e1c4df4ec851d606426b4b56cf78ffd88
parent13d909cd10c6a04acf9bc46fd5d89785a2514e97 (diff)
parent8fa211e881ff386f8555c113b409aa3373dca7e1 (diff)
Merge branch 'qemu-cvs'kvm-82rc1
Conflicts: qemu/Makefile qemu/Makefile.target qemu/configure qemu/hw/pc.c qemu/hw/pc.h qemu/hw/pci.c qemu/hw/virtio-net.c qemu/net.c qemu/net.h qemu/pc-bios/bios.bin qemu/pc-bios/vgabios-cirrus.bin qemu/pc-bios/vgabios.bin qemu/target-ppc/helper.c qemu/vl.c Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--.gitignore2
-rw-r--r--Makefile2
-rw-r--r--Makefile.target16
-rw-r--r--audio/audio.c8
-rw-r--r--audio/fmodaudio.c4
-rwxr-xr-xconfigure28
-rw-r--r--cpu-exec.c3
-rw-r--r--darwin-user/commpage.c4
-rw-r--r--darwin-user/syscall.c4
-rw-r--r--device_tree.c114
-rw-r--r--device_tree.h26
-rw-r--r--fpu/softfloat-native.c15
-rw-r--r--fpu/softfloat-native.h56
-rw-r--r--fpu/softfloat-specialize.h18
-rw-r--r--fpu/softfloat.c58
-rw-r--r--fpu/softfloat.h70
-rw-r--r--gdbstub.c266
-rw-r--r--gdbstub.h3
-rw-r--r--hw/ac97.c4
-rw-r--r--hw/acpi.c23
-rw-r--r--hw/apic.c7
-rw-r--r--hw/boards.h1
-rw-r--r--hw/dma.c6
-rw-r--r--hw/e1000.c8
-rw-r--r--hw/etraxfs_timer.c2
-rw-r--r--hw/fdc.c2
-rw-r--r--hw/hpet.c586
-rw-r--r--hw/hpet_emul.h85
-rw-r--r--hw/i8254.c21
-rw-r--r--hw/iommu.c17
-rw-r--r--hw/max7310.c6
-rw-r--r--hw/mc146818rtc.c29
-rw-r--r--hw/nseries.c4
-rw-r--r--hw/pc.c12
-rw-r--r--hw/pc.h7
-rw-r--r--hw/pci.c16
-rw-r--r--hw/pci.h20
-rw-r--r--hw/ppc405.h5
-rw-r--r--hw/ppc405_uc.c345
-rw-r--r--hw/ppc440.c103
-rw-r--r--hw/ppc440.h20
-rw-r--r--hw/ppc440_bamboo.c190
-rw-r--r--hw/ppc4xx.h10
-rw-r--r--hw/ppc4xx_devs.c383
-rw-r--r--hw/ppc_oldworld.c23
-rw-r--r--hw/rc4030.c4
-rw-r--r--hw/sb16.c6
-rw-r--r--hw/sh_intc.c9
-rw-r--r--hw/sh_intc.h2
-rw-r--r--hw/slavio_misc.c12
-rw-r--r--hw/sm501.c2
-rw-r--r--hw/sparc32_dma.c7
-rw-r--r--hw/sun4u.c29
-rw-r--r--hw/usb-net.c5
-rw-r--r--hw/virtio-net.c4
-rw-r--r--hw/vmware_vga.c2
-rw-r--r--kvm-all.c17
-rw-r--r--kvm.h1
-rw-r--r--libfdt_env.h41
-rw-r--r--linux-user/main.c4
-rw-r--r--linux-user/mmap.c19
-rw-r--r--linux-user/signal.c65
-rw-r--r--linux-user/strace.c2
-rw-r--r--linux-user/syscall.c22
-rw-r--r--mips-dis.c6
-rw-r--r--monitor.c20
-rw-r--r--net.c71
-rw-r--r--net.h14
-rw-r--r--pc-bios/README33
-rw-r--r--pc-bios/bamboo.dtbbin0 -> 3179 bytes
-rw-r--r--pc-bios/bamboo.dts234
-rw-r--r--pc-bios/bios-pq/0001_bx-qemu.patch11
-rw-r--r--pc-bios/bios-pq/0002_e820-high-mem.patch (renamed from pc-bios/bios.diff)64
-rw-r--r--pc-bios/bios-pq/0003_smp-startup-poll.patch21
-rw-r--r--pc-bios/bios-pq/0005_hpet.patch190
-rw-r--r--pc-bios/bios-pq/HEAD1
-rw-r--r--pc-bios/bios-pq/series4
-rw-r--r--pc-bios/vgabios-pq/HEAD1
-rw-r--r--pc-bios/vgabios-pq/series0
-rw-r--r--pc-bios/vgabios.diff896
-rw-r--r--pci-ids.txt30
-rw-r--r--qemu-kvm.h3
-rw-r--r--target-arm/cpu.h10
-rw-r--r--target-arm/helper.c62
-rw-r--r--target-arm/helpers.h2
-rw-r--r--target-arm/translate.c95
-rw-r--r--target-cris/translate.c4
-rw-r--r--target-i386/helper.c4
-rw-r--r--target-mips/cpu.h19
-rw-r--r--target-mips/exec.h15
-rw-r--r--target-mips/helper.c4
-rw-r--r--target-mips/machine.c291
-rw-r--r--target-mips/op_helper.c6
-rw-r--r--target-mips/translate_init.c4
-rw-r--r--target-ppc/cpu.h2
-rw-r--r--target-ppc/exec.h6
-rw-r--r--target-ppc/helper.c6
-rw-r--r--target-ppc/kvm.c204
-rw-r--r--target-ppc/kvm_ppc.c110
-rw-r--r--target-ppc/kvm_ppc.h15
-rw-r--r--target-ppc/machine.c1
-rw-r--r--target-ppc/op_helper.c265
-rw-r--r--target-ppc/translate.c67
-rw-r--r--target-ppc/translate_init.c6
-rw-r--r--target-sh4/translate.c4
-rw-r--r--target-sparc/cpu.h3
-rw-r--r--target-sparc/helper.c4
-rw-r--r--tcg/ppc/tcg-target.c2
-rw-r--r--tcg/ppc64/tcg-target.c2
-rw-r--r--vl.c28
-rw-r--r--vnc.c9
111 files changed, 3991 insertions, 1743 deletions
diff --git a/.gitignore b/.gitignore
index 0f4af35a1..6fdc7e701 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,3 +32,5 @@ qemu-nbd.pod
*.d
.pc
patches
+pc-bios/bios-pq/status
+pc-bios/vgabios-pq/status
diff --git a/Makefile b/Makefile
index 745851dd5..8422281ef 100644
--- a/Makefile
+++ b/Makefile
@@ -226,7 +226,7 @@ common de-ch es fo fr-ca hu ja mk nl-be pt sl tr
ifdef INSTALL_BLOBS
BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
video.x openbios-sparc32 openbios-sparc64 pxe-ne2k_pci.bin \
-pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin
+pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin bamboo.dtb
BLOBS += extboot.bin
else
BLOBS=
diff --git a/Makefile.target b/Makefile.target
index a30457085..f58015b1a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -606,6 +606,9 @@ endif #CONFIG_BSD_USER
ifndef CONFIG_USER_ONLY
OBJS=vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o
+# virtio has to be here due to weird dependency between PCI and virtio-net.
+# need to fix this properly
+OBJS+=virtio.o virtio-blk.o virtio-balloon.o virtio-net.o
OBJS+=fw_cfg.o
ifdef CONFIG_KVM
OBJS+=kvm.o kvm-all.o
@@ -700,7 +703,7 @@ ifeq ($(TARGET_BASE_ARCH), i386)
OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
-OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o
+OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
OBJS+= extboot.o
# virtio support
OBJS+= virtio.o virtio-blk.o virtio-balloon.o
@@ -736,9 +739,14 @@ OBJS+= heathrow_pic.o grackle_pci.o ppc_oldworld.o
OBJS+= unin_pci.o ppc_chrp.o
# PowerPC 4xx boards
OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
-# virtio support
-OBJS+= virtio.o virtio-blk.o virtio-balloon.o
-OBJS+= virtio-net.o
+OBJS+= ppc440.o ppc440_bamboo.o
+ifdef FDT_LIBS
+OBJS+= device_tree.o
+LIBS+= $(FDT_LIBS)
+endif
+ifdef CONFIG_KVM
+OBJS+= kvm_ppc.o
+endif
endif
ifeq ($(TARGET_BASE_ARCH), mips)
OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
diff --git a/audio/audio.c b/audio/audio.c
index a449609bb..762c2e342 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1556,7 +1556,7 @@ void AUD_help (void)
size_t i;
audio_process_options ("AUDIO", audio_options);
- for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
struct audio_driver *d = drvtab[i];
if (d->options) {
audio_process_options (d->name, d->options);
@@ -1569,7 +1569,7 @@ void AUD_help (void)
printf ("Available drivers:\n");
- for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
struct audio_driver *d = drvtab[i];
printf ("Name: %s\n", d->name);
@@ -1746,7 +1746,7 @@ AudioState *AUD_init (void)
if (drvname) {
int found = 0;
- for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
if (!strcmp (drvname, drvtab[i]->name)) {
done = !audio_driver_init (s, drvtab[i]);
found = 1;
@@ -1761,7 +1761,7 @@ AudioState *AUD_init (void)
}
if (!done) {
- for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+ for (i = 0; !done && i < ARRAY_SIZE (drvtab); i++) {
if (drvtab[i]->can_be_default) {
done = !audio_driver_init (s, drvtab[i]);
}
diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c
index 4be4ab658..0becd3bde 100644
--- a/audio/fmodaudio.c
+++ b/audio/fmodaudio.c
@@ -564,7 +564,7 @@ static void *fmod_audio_init (void)
if (drv) {
int found = 0;
- for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
if (!strcmp (drv, drvtab[i].name)) {
output_type = drvtab[i].type;
found = 1;
@@ -574,7 +574,7 @@ static void *fmod_audio_init (void)
if (!found) {
dolog ("Unknown FMOD driver `%s'\n", drv);
dolog ("Valid drivers:\n");
- for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
dolog (" %s\n", drvtab[i].name);
}
}
diff --git a/configure b/configure
index 468896e4f..d7dd10647 100755
--- a/configure
+++ b/configure
@@ -121,6 +121,7 @@ kvm_cap_device_assignment="no"
kerneldir=""
aix="no"
blobs="yes"
+fdt="yes"
signalfd="no"
eventfd="no"
cpu_emulation="yes"
@@ -1018,6 +1019,18 @@ if $cc $ARCH_CFLAGS -o $TMPE $TMPC > /dev/null 2> /dev/null ; then
fi
##########################################
+# fdt probe
+if test "$fdt" = "yes" ; then
+ fdt=no
+ cat > $TMPC << EOF
+int main(void) { return 0; }
+EOF
+ if $cc $ARCH_CFLAGS -o $TMPE ${OS_CFLAGS} $TMPC -lfdt 2> /dev/null ; then
+ fdt=yes
+ fi
+fi
+
+##########################################
# signalfd probe
cat > $TMPC << EOF
#define _GNU_SOURCE
@@ -1141,6 +1154,7 @@ echo "vde support $vde"
echo "AIO support $aio"
echo "Install blobs $blobs"
echo "KVM support $kvm"
+echo "fdt support $fdt"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -1160,7 +1174,7 @@ config_h="config-host.h"
test -f $config_h && mv $config_h ${config_h}~
echo "# Automatically generated by configure - do not modify" > $config_mak
-echo -n "# Configured with:" >> $config_mak
+printf "# Configured with:" >> $config_mak
printf " '%s'" "$0" "$@" >> $config_mak
echo >> $config_mak
echo "/* Automatically generated by configure - do not modify */" > $config_h
@@ -1431,6 +1445,10 @@ fi
if test "$iovec" = "yes" ; then
echo "#define HAVE_IOVEC 1" >> $config_h
fi
+if test "$fdt" = "yes" ; then
+ echo "#define HAVE_FDT 1" >> $config_h
+ echo "FDT_LIBS=-lfdt" >> $config_mak
+fi
if test "$signalfd" = "yes" ; then
echo "#define CONFIG_signalfd 1" >> $config_h
fi
@@ -1694,7 +1712,11 @@ case "$target_cpu" in
echo "#define TARGET_ARCH \"ppcemb\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
echo "#define TARGET_PPCEMB 1" >> $config_h
- configure_kvm
+ if test "$kvm" = "yes" ; then
+ echo "CONFIG_KVM=yes" >> $config_mak
+ echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
+ echo "#define CONFIG_KVM 1" >> $config_h
+ fi
;;
ppc64)
echo "TARGET_ARCH=ppc64" >> $config_mak
@@ -1784,6 +1806,8 @@ if test "$target_cpu" = "arm" \
-o "$target_cpu" = "mips64el" \
-o "$target_cpu" = "ppc" \
-o "$target_cpu" = "ppc64" \
+ -o "$target_cpu" = "ppc64abi32" \
+ -o "$target_cpu" = "ppcemb" \
-o "$target_cpu" = "sparc" \
-o "$target_cpu" = "sparc64" \
-o "$target_cpu" = "sparc32plus"; then
diff --git a/cpu-exec.c b/cpu-exec.c
index 66f173fbf..447cd93b2 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -90,6 +90,7 @@ void cpu_resume_from_signal(CPUState *env1, void *puc)
#endif
}
#endif
+ env->exception_index = -1;
longjmp(env->jmp_env, 1);
}
@@ -1021,7 +1022,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
- do_raise_exception_err(env->exception_index, env->error_code);
+ cpu_loop_exit();
} else {
/* activate soft MMU for this block */
cpu_resume_from_signal(env, puc);
diff --git a/darwin-user/commpage.c b/darwin-user/commpage.c
index 78a14130a..722887292 100644
--- a/darwin-user/commpage.c
+++ b/darwin-user/commpage.c
@@ -191,7 +191,7 @@ void commpage_init(void)
/* XXX: commpage data not handled */
- for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++)
+ for(i = 0; i < ARRAY_SIZE(commpage_entries); i++)
install_commpage_backdoor_for_entry(commpage_entries[i]);
#else
/* simply map our pages so they can be executed
@@ -329,7 +329,7 @@ do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
num = num-COMMPAGE_START-2;
- for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++) {
+ for(i = 0; i < ARRAY_SIZE(commpage_entries); i++) {
if( num == commpage_code_num(&commpage_entries[i]) )
{
DPRINTF("commpage: %s %s\n", commpage_entries[i].name, commpage_is_indirect(&commpage_entries[i]) ? "[indirect]" : "[direct]");
diff --git a/darwin-user/syscall.c b/darwin-user/syscall.c
index 8bf365d4b..58ead95f1 100644
--- a/darwin-user/syscall.c
+++ b/darwin-user/syscall.c
@@ -135,7 +135,7 @@ void static inline print_description_msg_header(mach_msg_header_t *hdr)
{ 4241876, "lu_message_reply_id" }, /* lookupd */
};
- for(i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) {
+ for(i = 0; i < ARRAY_SIZE(msg_name); i++) {
if(msg_name[i].number == hdr->msgh_id)
{
name = msg_name[i].name;
@@ -210,7 +210,7 @@ static inline void print_mach_msg_return(mach_msg_return_t ret)
DPRINTF("MACH_MSG_SUCCESS\n");
else
{
- for( i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) {
+ for( i = 0; i < ARRAY_SIZE(msg_name); i++) {
if(msg_name[i].code == ret) {
DPRINTF("%s\n", msg_name[i].name);
found = 1;
diff --git a/device_tree.c b/device_tree.c
new file mode 100644
index 000000000..22386829d
--- /dev/null
+++ b/device_tree.c
@@ -0,0 +1,114 @@
+/*
+ * Functions to help device tree manipulation using libfdt.
+ * It also provides functions to read entries from device tree proc
+ * interface.
+ *
+ * Copyright 2008 IBM Corporation.
+ * Authors: Jerone Young <jyoung5@us.ibm.com>
+ * Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "device_tree.h"
+
+#include <libfdt.h>
+
+void *load_device_tree(const char *filename_path, void *load_addr)
+{
+ int dt_file_size;
+ int dt_file_load_size;
+ int new_dt_size;
+ int ret;
+ void *dt_file = NULL;
+ void *fdt;
+
+ dt_file_size = get_image_size(filename_path);
+ if (dt_file_size < 0) {
+ printf("Unable to get size of device tree file '%s'\n",
+ filename_path);
+ goto fail;
+ }
+
+ /* First allocate space in qemu for device tree */
+ dt_file = qemu_mallocz(dt_file_size);
+ if (dt_file == NULL) {
+ printf("Unable to allocate memory in qemu for device tree\n");
+ goto fail;
+ }
+
+ dt_file_load_size = load_image(filename_path, dt_file);
+
+ /* Second we place new copy of 2x size in guest memory
+ * This give us enough room for manipulation.
+ */
+ new_dt_size = dt_file_size * 2;
+
+ fdt = load_addr;
+ ret = fdt_open_into(dt_file, fdt, new_dt_size);
+ if (ret) {
+ printf("Unable to copy device tree in memory\n");
+ goto fail;
+ }
+
+ /* Check sanity of device tree */
+ if (fdt_check_header(fdt)) {
+ printf ("Device tree file loaded into memory is invalid: %s\n",
+ filename_path);
+ goto fail;
+ }
+ /* free qemu memory with old device tree */
+ qemu_free(dt_file);
+ return fdt;
+
+fail:
+ qemu_free(dt_file);
+ return NULL;
+}
+
+int qemu_devtree_setprop(void *fdt, const char *node_path,
+ const char *property, uint32_t *val_array, int size)
+{
+ int offset;
+
+ offset = fdt_path_offset(fdt, node_path);
+ if (offset < 0)
+ return offset;
+
+ return fdt_setprop(fdt, offset, property, val_array, size);
+}
+
+int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
+ const char *property, uint32_t val)
+{
+ int offset;
+
+ offset = fdt_path_offset(fdt, node_path);
+ if (offset < 0)
+ return offset;
+
+ return fdt_setprop_cell(fdt, offset, property, val);
+}
+
+int qemu_devtree_setprop_string(void *fdt, const char *node_path,
+ const char *property, const char *string)
+{
+ int offset;
+
+ offset = fdt_path_offset(fdt, node_path);
+ if (offset < 0)
+ return offset;
+
+ return fdt_setprop_string(fdt, offset, property, string);
+}
diff --git a/device_tree.h b/device_tree.h
new file mode 100644
index 000000000..9e6ef3d8e
--- /dev/null
+++ b/device_tree.h
@@ -0,0 +1,26 @@
+/*
+ * Header with function prototypes to help device tree manipulation using
+ * libfdt. It also provides functions to read entries from device tree proc
+ * interface.
+ *
+ * Copyright 2008 IBM Corporation.
+ * Authors: Jerone Young <jyoung5@us.ibm.com>
+ * Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#ifndef __DEVICE_TREE_H__
+#define __DEVICE_TREE_H__
+
+void *load_device_tree(const char *filename_path, void *load_addr);
+
+int qemu_devtree_setprop(void *fdt, const char *node_path,
+ const char *property, uint32_t *val_array, int size);
+int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
+ const char *property, uint32_t val);
+int qemu_devtree_setprop_string(void *fdt, const char *node_path,
+ const char *property, const char *string);
+
+#endif /* __DEVICE_TREE_H__ */
diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c
index cd88113f9..7273ae5b4 100644
--- a/fpu/softfloat-native.c
+++ b/fpu/softfloat-native.c
@@ -431,7 +431,7 @@ int float64_is_nan( float64 a1 )
u.f = a1;
a = u.i;
- return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
+ return ( LIT64( 0xFFF0000000000000 ) < (bits64) ( a<<1 ) );
}
@@ -507,6 +507,19 @@ int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
int floatx80_is_signaling_nan( floatx80 a1)
{
floatx80u u;
+ uint64_t aLow;
+ u.f = a1;
+
+ aLow = u.i.low & ~ LIT64( 0x4000000000000000 );
+ return
+ ( ( u.i.high & 0x7FFF ) == 0x7FFF )
+ && (bits64) ( aLow<<1 )
+ && ( u.i.low == aLow );
+}
+
+int floatx80_is_nan( floatx80 a1 )
+{
+ floatx80u u;
u.f = a1;
return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( u.i.low<<1 );
}
diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h
index 817a2a813..cf2da4c25 100644
--- a/fpu/softfloat-native.h
+++ b/fpu/softfloat-native.h
@@ -140,9 +140,9 @@ enum {
#endif
typedef struct float_status {
- signed char float_rounding_mode;
+ int float_rounding_mode;
#ifdef FLOATX80
- signed char floatx80_rounding_precision;
+ int floatx80_rounding_precision;
#endif
} float_status;
@@ -258,6 +258,23 @@ INLINE float32 float32_chs(float32 a)
return -a;
}
+INLINE float32 float32_is_infinity(float32 a)
+{
+ return fpclassify(a) == FP_INFINITE;
+}
+
+INLINE float32 float32_is_neg(float32 a)
+{
+ float32u u;
+ u.f = a;
+ return u.i >> 31;
+}
+
+INLINE float32 float32_is_zero(float32 a)
+{
+ return fpclassify(a) == FP_ZERO;
+}
+
INLINE float32 float32_scalbn(float32 a, int n)
{
return scalbnf(a, n);
@@ -350,6 +367,23 @@ INLINE float64 float64_chs(float64 a)
return -a;
}
+INLINE float64 float64_is_infinity(float64 a)
+{
+ return fpclassify(a) == FP_INFINITE;
+}
+
+INLINE float64 float64_is_neg(float64 a)
+{
+ float64u u;
+ u.f = a;
+ return u.i >> 63;
+}
+
+INLINE float64 float64_is_zero(float64 a)
+{
+ return fpclassify(a) == FP_ZERO;
+}
+
INLINE float64 float64_scalbn(float64 a, int n)
{
return scalbn(a, n);
@@ -425,6 +459,7 @@ INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
int floatx80_is_signaling_nan( floatx80 );
+int floatx80_is_nan( floatx80 );
INLINE floatx80 floatx80_abs(floatx80 a)
{
@@ -436,6 +471,23 @@ INLINE floatx80 floatx80_chs(floatx80 a)
return -a;
}
+INLINE floatx80 floatx80_is_infinity(floatx80 a)
+{
+ return fpclassify(a) == FP_INFINITE;
+}
+
+INLINE floatx80 floatx80_is_neg(floatx80 a)
+{
+ floatx80u u;
+ u.f = a;
+ return u.i.high >> 15;
+}
+
+INLINE floatx80 floatx80_is_zero(floatx80 a)
+{
+ return fpclassify(a) == FP_ZERO;
+}
+
INLINE floatx80 floatx80_scalbn(floatx80 a, int n)
{
return scalbnl(a, n);
diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 166b91369..d279210ae 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -144,6 +144,9 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
bits32 av, bv, res;
+ if ( STATUS(default_nan_mode) )
+ return float32_default_nan;
+
aIsNaN = float32_is_nan( a );
aIsSignalingNaN = float32_is_signaling_nan( a );
bIsNaN = float32_is_nan( b );
@@ -276,6 +279,9 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
bits64 av, bv, res;
+ if ( STATUS(default_nan_mode) )
+ return float64_default_nan;
+
aIsNaN = float64_is_nan( a );
aIsSignalingNaN = float64_is_signaling_nan( a );
bIsNaN = float64_is_nan( b );
@@ -412,6 +418,12 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+ if ( STATUS(default_nan_mode) ) {
+ a.low = floatx80_default_nan_low;
+ a.high = floatx80_default_nan_high;
+ return a;
+ }
+
aIsNaN = floatx80_is_nan( a );
aIsSignalingNaN = floatx80_is_signaling_nan( a );
bIsNaN = floatx80_is_nan( b );
@@ -532,6 +544,12 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+ if ( STATUS(default_nan_mode) ) {
+ a.low = float128_default_nan_low;
+ a.high = float128_default_nan_high;
+ return a;
+ }
+
aIsNaN = float128_is_nan( a );
aIsSignalingNaN = float128_is_signaling_nan( a );
bIsNaN = float128_is_nan( b );
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 3988bd109..3d5169db9 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -30,6 +30,8 @@ these four paragraphs for those parts of this code that are retained.
=============================================================================*/
+/* FIXME: Flush-To-Zero only effects results. Denormal inputs should also
+ be flushed to zero. */
#include "softfloat.h"
/*----------------------------------------------------------------------------
@@ -294,6 +296,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P
return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 ));
}
if ( zExp < 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 );
isTiny =
( STATUS(float_detect_tininess) == float_tininess_before_rounding )
|| ( zExp < -1 )
@@ -457,6 +460,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P
return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 ));
}
if ( zExp < 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 );
isTiny =
( STATUS(float_detect_tininess) == float_tininess_before_rounding )
|| ( zExp < -1 )
@@ -635,6 +639,7 @@ static floatx80
goto overflow;
}
if ( zExp <= 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloatx80( zSign, 0, 0 );
isTiny =
( STATUS(float_detect_tininess) == float_tininess_before_rounding )
|| ( zExp < 0 )
@@ -965,6 +970,7 @@ static float128
return packFloat128( zSign, 0x7FFF, 0, 0 );
}
if ( zExp < 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
isTiny =
( STATUS(float_detect_tininess) == float_tininess_before_rounding )
|| ( zExp < -1 )
@@ -1637,7 +1643,10 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR );
return a;
}
- if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
+ if ( aExp == 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 );
+ return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
+ }
zSig = 0x40000000 + aSig + bSig;
zExp = aExp;
goto roundAndPack;
@@ -2595,7 +2604,10 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR );
return a;
}
- if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
+ if ( aExp == 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 );
+ return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
+ }
zSig = LIT64( 0x4000000000000000 ) + aSig + bSig;
zExp = aExp;
goto roundAndPack;
@@ -4597,7 +4609,10 @@ static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM
return a;
}
add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
- if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 );
+ if ( aExp == 0 ) {
+ if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
+ return packFloat128( zSign, 0, zSig0, zSig1 );
+ }
zSig2 = 0;
zSig0 |= LIT64( 0x0002000000000000 );
zExp = aExp;
@@ -5479,8 +5494,14 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
if ( aExp == 0xFF ) {
return a;
}
- aExp += n;
- return roundAndPackFloat32( aSign, aExp, aSig STATUS_VAR );
+ if ( aExp != 0 )
+ aSig |= 0x00800000;
+ else if ( aSig == 0 )
+ return a;
+
+ aExp += n - 1;
+ aSig <<= 7;
+ return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR );
}
float64 float64_scalbn( float64 a, int n STATUS_PARAM )
@@ -5496,8 +5517,14 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
if ( aExp == 0x7FF ) {
return a;
}
- aExp += n;
- return roundAndPackFloat64( aSign, aExp, aSig STATUS_VAR );
+ if ( aExp != 0 )
+ aSig |= LIT64( 0x0010000000000000 );
+ else if ( aSig == 0 )
+ return a;
+
+ aExp += n - 1;
+ aSig <<= 10;
+ return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR );
}
#ifdef FLOATX80
@@ -5514,9 +5541,12 @@ floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
if ( aExp == 0x7FF ) {
return a;
}
+ if (aExp == 0 && aSig == 0)
+ return a;
+
aExp += n;
- return roundAndPackFloatx80( STATUS(floatx80_rounding_precision),
- aSign, aExp, aSig, 0 STATUS_VAR );
+ return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision),
+ aSign, aExp, aSig, 0 STATUS_VAR );
}
#endif
@@ -5534,8 +5564,14 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM )
if ( aExp == 0x7FFF ) {
return a;
}
- aExp += n;
- return roundAndPackFloat128( aSign, aExp, aSig0, aSig1, 0 STATUS_VAR );
+ if ( aExp != 0 )
+ aSig0 |= LIT64( 0x0001000000000000 );
+ else if ( aSig0 == 0 && aSig1 == 0 )
+ return a;
+
+ aExp += n - 1;
+ return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1
+ STATUS_VAR );
}
#endif
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 8b28c1787..b46d63ca6 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -190,10 +190,20 @@ typedef struct float_status {
#ifdef FLOATX80
signed char floatx80_rounding_precision;
#endif
+ flag flush_to_zero;
+ flag default_nan_mode;
} float_status;
void set_float_rounding_mode(int val STATUS_PARAM);
void set_float_exception_flags(int val STATUS_PARAM);
+INLINE void set_flush_to_zero(flag val STATUS_PARAM)
+{
+ STATUS(flush_to_zero) = val;
+}
+INLINE void set_default_nan_mode(flag val STATUS_PARAM)
+{
+ STATUS(default_nan_mode) = val;
+}
INLINE int get_float_exception_flags(float_status *status)
{
return STATUS(float_exception_flags);
@@ -281,6 +291,21 @@ INLINE float32 float32_chs(float32 a)
return make_float32(float32_val(a) ^ 0x80000000);
}
+INLINE int float32_is_infinity(float32 a)
+{
+ return (float32_val(a) & 0x7fffffff) == 0x7f800000;
+}
+
+INLINE int float32_is_neg(float32 a)
+{
+ return float32_val(a) >> 31;
+}
+
+INLINE int float32_is_zero(float32 a)
+{
+ return (float32_val(a) & 0x7fffffff) == 0;
+}
+
#define float32_zero make_float32(0)
/*----------------------------------------------------------------------------
@@ -335,6 +360,21 @@ INLINE float64 float64_chs(float64 a)
return make_float64(float64_val(a) ^ 0x8000000000000000LL);
}
+INLINE int float64_is_infinity(float64 a)
+{
+ return (float64_val(a) & 0x7fffffffffffffffLL ) == 0x7ff0000000000000LL;
+}
+
+INLINE int float64_is_neg(float64 a)
+{
+ return float64_val(a) >> 63;
+}
+
+INLINE int float64_is_zero(float64 a)
+{
+ return (float64_val(a) & 0x7fffffffffffffffLL) == 0;
+}
+
#define float64_zero make_float64(0)
#ifdef FLOATX80
@@ -384,6 +424,21 @@ INLINE floatx80 floatx80_chs(floatx80 a)
return a;
}
+INLINE int floatx80_is_infinity(floatx80 a)
+{
+ return (a.high & 0x7fff) == 0x7fff && a.low == 0;
+}
+
+INLINE int floatx80_is_neg(floatx80 a)
+{
+ return a.high >> 15;
+}
+
+INLINE int floatx80_is_zero(floatx80 a)
+{
+ return (a.high & 0x7fff) == 0 && a.low == 0;
+}
+
#endif
#ifdef FLOAT128
@@ -435,6 +490,21 @@ INLINE float128 float128_chs(float128 a)
return a;
}
+INLINE int float128_is_infinity(float128 a)
+{
+ return (a.high & 0x7fffffffffffffffLL) == 0x7fff000000000000LL && a.low == 0;
+}
+
+INLINE int float128_is_neg(float128 a)
+{
+ return a.high >> 63;
+}
+
+INLINE int float128_is_zero(float128 a)
+{
+ return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0;
+}
+
#endif
#else /* CONFIG_SOFTFLOAT */
diff --git a/gdbstub.c b/gdbstub.c
index ba6de5f9a..4d99efd45 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -39,18 +39,213 @@
#define MAX_PACKET_LENGTH 4096
#include "qemu_socket.h"
-#ifdef _WIN32
-/* XXX: these constants may be independent of the host ones even for Unix */
-#ifndef SIGTRAP
-#define SIGTRAP 5
-#endif
-#ifndef SIGINT
-#define SIGINT 2
-#endif
+
+
+enum {
+ GDB_SIGNAL_0 = 0,
+ GDB_SIGNAL_INT = 2,
+ GDB_SIGNAL_TRAP = 5,
+ GDB_SIGNAL_UNKNOWN = 143
+};
+
+#ifdef CONFIG_USER_ONLY
+
+/* Map target signal numbers to GDB protocol signal numbers and vice
+ * versa. For user emulation's currently supported systems, we can
+ * assume most signals are defined.
+ */
+
+static int gdb_signal_table[] = {
+ 0,
+ TARGET_SIGHUP,
+ TARGET_SIGINT,
+ TARGET_SIGQUIT,
+ TARGET_SIGILL,
+ TARGET_SIGTRAP,
+ TARGET_SIGABRT,
+ -1, /* SIGEMT */
+ TARGET_SIGFPE,
+ TARGET_SIGKILL,
+ TARGET_SIGBUS,
+ TARGET_SIGSEGV,
+ TARGET_SIGSYS,
+ TARGET_SIGPIPE,
+ TARGET_SIGALRM,
+ TARGET_SIGTERM,
+ TARGET_SIGURG,
+ TARGET_SIGSTOP,
+ TARGET_SIGTSTP,
+ TARGET_SIGCONT,
+ TARGET_SIGCHLD,
+ TARGET_SIGTTIN,
+ TARGET_SIGTTOU,
+ TARGET_SIGIO,
+ TARGET_SIGXCPU,
+ TARGET_SIGXFSZ,
+ TARGET_SIGVTALRM,
+ TARGET_SIGPROF,
+ TARGET_SIGWINCH,
+ -1, /* SIGLOST */
+ TARGET_SIGUSR1,
+ TARGET_SIGUSR2,
+ TARGET_SIGPWR,
+ -1, /* SIGPOLL */
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ __SIGRTMIN + 1,
+ __SIGRTMIN + 2,
+ __SIGRTMIN + 3,
+ __SIGRTMIN + 4,
+ __SIGRTMIN + 5,
+ __SIGRTMIN + 6,
+ __SIGRTMIN + 7,
+ __SIGRTMIN + 8,
+ __SIGRTMIN + 9,
+ __SIGRTMIN + 10,
+ __SIGRTMIN + 11,
+ __SIGRTMIN + 12,
+ __SIGRTMIN + 13,
+ __SIGRTMIN + 14,
+ __SIGRTMIN + 15,
+ __SIGRTMIN + 16,
+ __SIGRTMIN + 17,
+ __SIGRTMIN + 18,
+ __SIGRTMIN + 19,
+ __SIGRTMIN + 20,
+ __SIGRTMIN + 21,
+ __SIGRTMIN + 22,
+ __SIGRTMIN + 23,
+ __SIGRTMIN + 24,
+ __SIGRTMIN + 25,
+ __SIGRTMIN + 26,
+ __SIGRTMIN + 27,
+ __SIGRTMIN + 28,
+ __SIGRTMIN + 29,
+ __SIGRTMIN + 30,
+ __SIGRTMIN + 31,
+ -1, /* SIGCANCEL */
+ __SIGRTMIN,
+ __SIGRTMIN + 32,
+ __SIGRTMIN + 33,
+ __SIGRTMIN + 34,
+ __SIGRTMIN + 35,
+ __SIGRTMIN + 36,
+ __SIGRTMIN + 37,
+ __SIGRTMIN + 38,
+ __SIGRTMIN + 39,
+ __SIGRTMIN + 40,
+ __SIGRTMIN + 41,
+ __SIGRTMIN + 42,
+ __SIGRTMIN + 43,
+ __SIGRTMIN + 44,
+ __SIGRTMIN + 45,
+ __SIGRTMIN + 46,
+ __SIGRTMIN + 47,
+ __SIGRTMIN + 48,
+ __SIGRTMIN + 49,
+ __SIGRTMIN + 50,
+ __SIGRTMIN + 51,
+ __SIGRTMIN + 52,
+ __SIGRTMIN + 53,
+ __SIGRTMIN + 54,
+ __SIGRTMIN + 55,
+ __SIGRTMIN + 56,
+ __SIGRTMIN + 57,
+ __SIGRTMIN + 58,
+ __SIGRTMIN + 59,
+ __SIGRTMIN + 60,
+ __SIGRTMIN + 61,
+ __SIGRTMIN + 62,
+ __SIGRTMIN + 63,
+ __SIGRTMIN + 64,
+ __SIGRTMIN + 65,
+ __SIGRTMIN + 66,
+ __SIGRTMIN + 67,
+ __SIGRTMIN + 68,
+ __SIGRTMIN + 69,
+ __SIGRTMIN + 70,
+ __SIGRTMIN + 71,
+ __SIGRTMIN + 72,
+ __SIGRTMIN + 73,
+ __SIGRTMIN + 74,
+ __SIGRTMIN + 75,
+ __SIGRTMIN + 76,
+ __SIGRTMIN + 77,
+ __SIGRTMIN + 78,
+ __SIGRTMIN + 79,
+ __SIGRTMIN + 80,
+ __SIGRTMIN + 81,
+ __SIGRTMIN + 82,
+ __SIGRTMIN + 83,
+ __SIGRTMIN + 84,
+ __SIGRTMIN + 85,
+ __SIGRTMIN + 86,
+ __SIGRTMIN + 87,
+ __SIGRTMIN + 88,
+ __SIGRTMIN + 89,
+ __SIGRTMIN + 90,
+ __SIGRTMIN + 91,
+ __SIGRTMIN + 92,
+ __SIGRTMIN + 93,
+ __SIGRTMIN + 94,
+ __SIGRTMIN + 95,
+ -1, /* SIGINFO */
+ -1, /* UNKNOWN */
+ -1, /* DEFAULT */
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1
+};
#else
-#include <signal.h>
+/* In system mode we only need SIGINT and SIGTRAP; other signals
+ are not yet supported. */
+
+enum {
+ TARGET_SIGINT = 2,
+ TARGET_SIGTRAP = 5
+};
+
+static int gdb_signal_table[] = {
+ -1,
+ -1,
+ TARGET_SIGINT,
+ -1,
+ -1,
+ TARGET_SIGTRAP
+};
#endif
+#ifdef CONFIG_USER_ONLY
+static int target_signal_to_gdb (int sig)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE (gdb_signal_table); i++)
+ if (gdb_signal_table[i] == sig)
+ return i;
+ return GDB_SIGNAL_UNKNOWN;
+}
+#endif
+
+static int gdb_signal_to_target (int sig)
+{
+ if (sig < ARRAY_SIZE (gdb_signal_table))
+ return gdb_signal_table[sig];
+ else
+ return -1;
+}
+
//#define DEBUG_GDB
typedef struct GDBRegisterState {
@@ -1305,7 +1500,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
switch(ch) {
case '?':
/* TODO: Make this return the correct value for user-mode. */
- snprintf(buf, sizeof(buf), "T%02xthread:%02x;", SIGTRAP,
+ snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
s->c_cpu->cpu_index+1);
put_packet(s, buf);
/* Remove all the breakpoints when this query is issued,
@@ -1338,10 +1533,13 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
s->c_cpu->pc = addr;
#endif
}
+ s->signal = 0;
gdb_continue(s);
return RS_IDLE;
case 'C':
- s->signal = strtoul(p, (char **)&p, 16);
+ s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16));
+ if (s->signal == -1)
+ s->signal = 0;
gdb_continue(s);
return RS_IDLE;
case 'k':
@@ -1704,16 +1902,16 @@ static void gdb_vm_stopped(void *opaque, int reason)
}
snprintf(buf, sizeof(buf),
"T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
- SIGTRAP, env->cpu_index+1, type,
+ GDB_SIGNAL_TRAP, env->cpu_index+1, type,
env->watchpoint_hit->vaddr);
put_packet(s, buf);
env->watchpoint_hit = NULL;
return;
}
tb_flush(env);
- ret = SIGTRAP;
+ ret = GDB_SIGNAL_TRAP;
} else if (reason == EXCP_INTERRUPT) {
- ret = SIGINT;
+ ret = GDB_SIGNAL_INT;
} else {
ret = 0;
}
@@ -1865,6 +2063,19 @@ static void gdb_read_byte(GDBState *s, int ch)
#ifdef CONFIG_USER_ONLY
int
+gdb_queuesig (void)
+{
+ GDBState *s;
+
+ s = gdbserver_state;
+
+ if (gdbserver_fd < 0 || s->fd < 0)
+ return 0;
+ else
+ return 1;
+}
+
+int
gdb_handlesig (CPUState *env, int sig)
{
GDBState *s;
@@ -1881,7 +2092,7 @@ gdb_handlesig (CPUState *env, int sig)
if (sig != 0)
{
- snprintf(buf, sizeof(buf), "S%02x", sig);
+ snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb (sig));
put_packet(s, buf);
}
/* put_packet() might have detected that the peer terminated the
@@ -1927,6 +2138,19 @@ void gdb_exit(CPUState *env, int code)
put_packet(s, buf);
}
+/* Tell the remote gdb that the process has exited due to SIG. */
+void gdb_signalled(CPUState *env, int sig)
+{
+ GDBState *s;
+ char buf[4];
+
+ s = gdbserver_state;
+ if (gdbserver_fd < 0 || s->fd < 0)
+ return;
+
+ snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig));
+ put_packet(s, buf);
+}
static void gdb_accept(void)
{
@@ -2008,6 +2232,18 @@ int gdbserver_start(int port)
gdb_accept();
return 0;
}
+
+/* Disable gdb stub for child processes. */
+void gdbserver_fork(CPUState *env)
+{
+ GDBState *s = gdbserver_state;
+ if (s->fd < 0)
+ return;
+ close(s->fd);
+ s->fd = -1;
+ cpu_breakpoint_remove_all(env, BP_GDB);
+ cpu_watchpoint_remove_all(env, BP_GDB);
+}
#else
static int gdb_chr_can_receive(void *opaque)
{
diff --git a/gdbstub.h b/gdbstub.h
index e17ac90f3..5740041c7 100644
--- a/gdbstub.h
+++ b/gdbstub.h
@@ -17,9 +17,12 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...);
int use_gdb_syscalls(void);
void gdb_set_stop_cpu(CPUState *env);
#ifdef CONFIG_USER_ONLY
+int gdb_queuesig (void);
int gdb_handlesig (CPUState *, int);
void gdb_exit(CPUState *, int);
+void gdb_signalled(CPUState *, int);
int gdbserver_start(int);
+void gdbserver_fork(CPUState *);
#else
int gdbserver_start(const char *port);
#endif
diff --git a/hw/ac97.c b/hw/ac97.c
index c30e89407..dc9a165a3 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1196,7 +1196,7 @@ static void ac97_save (QEMUFile *f, void *opaque)
qemu_put_be32s (f, &s->glob_sta);
qemu_put_be32s (f, &s->cas);
- for (i = 0; i < sizeof (s->bm_regs) / sizeof (s->bm_regs[0]); ++i) {
+ for (i = 0; i < ARRAY_SIZE (s->bm_regs); ++i) {
AC97BusMasterRegs *r = &s->bm_regs[i];
qemu_put_be32s (f, &r->bdbar);
qemu_put_8s (f, &r->civ);
@@ -1235,7 +1235,7 @@ static int ac97_load (QEMUFile *f, void *opaque, int version_id)
qemu_get_be32s (f, &s->glob_sta);
qemu_get_be32s (f, &s->cas);
- for (i = 0; i < sizeof (s->bm_regs) / sizeof (s->bm_regs[0]); ++i) {
+ for (i = 0; i < ARRAY_SIZE (s->bm_regs); ++i) {
AC97BusMasterRegs *r = &s->bm_regs[i];
qemu_get_be32s (f, &r->bdbar);
qemu_get_8s (f, &r->civ);
diff --git a/hw/acpi.c b/hw/acpi.c
index 5458e54c0..0ff8851b5 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -55,6 +55,8 @@ typedef struct PIIX4PMState {
qemu_irq irq;
} PIIX4PMState;
+#define RSM_STS (1 << 15)
+#define PWRBTN_STS (1 << 8)
#define RTC_EN (1 << 10)
#define PWRBTN_EN (1 << 8)
#define GBL_EN (1 << 5)
@@ -153,6 +155,14 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
case 0: /* soft power off */
qemu_system_shutdown_request();
break;
+ case 1:
+ /* RSM_STS should be set on resume. Pretend that resume
+ was caused by power button */
+ s->pmsts |= (RSM_STS | PWRBTN_STS);
+ qemu_system_reset_request();
+#if defined(TARGET_I386)
+ cmos_set_s3_resume();
+#endif
default:
break;
}
@@ -473,6 +483,17 @@ static int pm_load(QEMUFile* f,void* opaque,int version_id)
return 0;
}
+static void piix4_reset(void *opaque)
+{
+ PIIX4PMState *s = opaque;
+ uint8_t *pci_conf = s->dev.config;
+
+ pci_conf[0x58] = 0;
+ pci_conf[0x59] = 0;
+ pci_conf[0x5a] = 0;
+ pci_conf[0x5b] = 0;
+}
+
i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
qemu_irq sci_irq)
{
@@ -536,6 +557,8 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
s->smbus = i2c_init_bus();
s->irq = sci_irq;
+ qemu_register_reset(piix4_reset, s);
+
return s->smbus;
}
diff --git a/hw/apic.c b/hw/apic.c
index 665727620..eb4d51992 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -1055,6 +1055,13 @@ void ioapic_set_irq(void *opaque, int vector, int level)
{
IOAPICState *s = opaque;
+ /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
+ * to GSI 2. GSI maps to ioapic 1-1. This is not
+ * the cleanest way of doing it but it should work. */
+
+ if (vector == 0)
+ vector = 2;
+
if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
uint32_t mask = 1 << vector;
uint64_t entry = s->ioredtbl[vector];
diff --git a/hw/boards.h b/hw/boards.h
index fae6d198b..d2b26c695 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -40,6 +40,7 @@ extern QEMUMachine core99_machine;
extern QEMUMachine heathrow_machine;
extern QEMUMachine ref405ep_machine;
extern QEMUMachine taihu_machine;
+extern QEMUMachine bamboo_machine;
/* mips_r4k.c */
extern QEMUMachine mips_machine;
diff --git a/hw/dma.c b/hw/dma.c
index b247a0cd8..e58ab6dd2 100644
--- a/hw/dma.c
+++ b/hw/dma.c
@@ -37,8 +37,6 @@
#define ldebug(...)
#endif
-#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
-
struct dma_regs {
int now[2];
uint16_t base[2];
@@ -479,7 +477,7 @@ static void dma_init2(struct dma_cont *d, int base, int dshift,
register_ioport_write (base + (i << dshift), 1, 1, write_chan, d);
register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
}
- for (i = 0; i < LENOFA (page_port_list); i++) {
+ for (i = 0; i < ARRAY_SIZE (page_port_list); i++) {
register_ioport_write (page_base + page_port_list[i], 1, 1,
write_page, d);
register_ioport_read (page_base + page_port_list[i], 1, 1,
@@ -499,7 +497,7 @@ static void dma_init2(struct dma_cont *d, int base, int dshift,
}
qemu_register_reset(dma_reset, d);
dma_reset(d);
- for (i = 0; i < LENOFA (d->regs); ++i) {
+ for (i = 0; i < ARRAY_SIZE (d->regs); ++i) {
d->regs[i].transfer_handler = dma_phony_handler;
}
}
diff --git a/hw/e1000.c b/hw/e1000.c
index aed3f9a8e..b0050b0d2 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -764,7 +764,7 @@ static uint32_t (*macreg_readops[])(E1000State *, int) = {
[MTA ... MTA+127] = &mac_readreg,
[VFTA ... VFTA+127] = &mac_readreg,
};
-enum { NREADOPS = sizeof(macreg_readops) / sizeof(*macreg_readops) };
+enum { NREADOPS = ARRAY_SIZE(macreg_readops) };
#define putreg(x) [x] = mac_writereg
static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
@@ -780,7 +780,7 @@ static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
[MTA ... MTA+127] = &mac_writereg,
[VFTA ... VFTA+127] = &mac_writereg,
};
-enum { NWRITEOPS = sizeof(macreg_writeops) / sizeof(*macreg_writeops) };
+enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
static void
e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -855,13 +855,13 @@ static const int mac_regtosave[] = {
TDT, TORH, TORL, TOTH, TOTL, TPR, TPT, TXDCTL, WUFC,
VET,
};
-enum { MAC_NSAVE = sizeof mac_regtosave/sizeof *mac_regtosave };
+enum { MAC_NSAVE = ARRAY_SIZE(mac_regtosave) };
static const struct {
int size;
int array0;
} mac_regarraystosave[] = { {32, RA}, {128, MTA}, {128, VFTA} };
-enum { MAC_NARRAYS = sizeof mac_regarraystosave/sizeof *mac_regarraystosave };
+enum { MAC_NARRAYS = ARRAY_SIZE(mac_regarraystosave) };
static void
nic_save(QEMUFile *f, void *opaque)
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index ea0009aa8..a895ed38f 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -96,7 +96,7 @@ static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
D(printf ("R_TMR1_DATA\n"));
break;
case R_TIME:
- r = qemu_get_clock(vm_clock) * 10;
+ r = qemu_get_clock(vm_clock) / 10;
break;
case RW_INTR_MASK:
r = t->rw_intr_mask;
diff --git a/hw/fdc.c b/hw/fdc.c
index 26ff18425..b1b4bc7d0 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1851,7 +1851,7 @@ static fdctrl_t *fdctrl_init_common (qemu_irq irq, int dma_chann,
int i, j;
/* Fill 'command_to_handler' lookup table */
- for (i = sizeof(handlers)/sizeof(handlers[0]) - 1; i >= 0; i--) {
+ for (i = ARRAY_SIZE(handlers) - 1; i >= 0; i--) {
for (j = 0; j < sizeof(command_to_handler); j++) {
if ((j & handlers[i].mask) == handlers[i].value)
command_to_handler[j] = i;
diff --git a/hw/hpet.c b/hw/hpet.c
new file mode 100644
index 000000000..6b2cb3842
--- /dev/null
+++ b/hw/hpet.c
@@ -0,0 +1,586 @@
+/*
+ * High Precisition Event Timer emulation
+ *
+ * Copyright (c) 2007 Alexander Graf
+ * Copyright (c) 2008 IBM Corporation
+ *
+ * Authors: Beth Kon <bkon@us.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * *****************************************************************
+ *
+ * This driver attempts to emulate an HPET device in software.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "console.h"
+#include "qemu-timer.h"
+#include "hpet_emul.h"
+
+//#define HPET_DEBUG
+#ifdef HPET_DEBUG
+#define dprintf printf
+#else
+#define dprintf(...)
+#endif
+
+static HPETState *hpet_statep;
+
+uint32_t hpet_in_legacy_mode(void)
+{
+ if (hpet_statep)
+ return hpet_statep->config & HPET_CFG_LEGACY;
+ else
+ return 0;
+}
+
+static uint32_t timer_int_route(struct HPETTimer *timer)
+{
+ uint32_t route;
+ route = (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
+ return route;
+}
+
+static uint32_t hpet_enabled(void)
+{
+ return hpet_statep->config & HPET_CFG_ENABLE;
+}
+
+static uint32_t timer_is_periodic(HPETTimer *t)
+{
+ return t->config & HPET_TN_PERIODIC;
+}
+
+static uint32_t timer_enabled(HPETTimer *t)
+{
+ return t->config & HPET_TN_ENABLE;
+}
+
+static uint32_t hpet_time_after(uint64_t a, uint64_t b)
+{
+ return ((int32_t)(b) - (int32_t)(a) < 0);
+}
+
+static uint32_t hpet_time_after64(uint64_t a, uint64_t b)
+{
+ return ((int64_t)(b) - (int64_t)(a) < 0);
+}
+
+static uint64_t ticks_to_ns(uint64_t value)
+{
+ return (muldiv64(value, HPET_CLK_PERIOD, FS_PER_NS));
+}
+
+static uint64_t ns_to_ticks(uint64_t value)
+{
+ return (muldiv64(value, FS_PER_NS, HPET_CLK_PERIOD));
+}
+
+static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask)
+{
+ new &= mask;
+ new |= old & ~mask;
+ return new;
+}
+
+static int activating_bit(uint64_t old, uint64_t new, uint64_t mask)
+{
+ return (!(old & mask) && (new & mask));
+}
+
+static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask)
+{
+ return ((old & mask) && !(new & mask));
+}
+
+static uint64_t hpet_get_ticks(void)
+{
+ uint64_t ticks;
+ ticks = ns_to_ticks(qemu_get_clock(vm_clock) + hpet_statep->hpet_offset);
+ return ticks;
+}
+
+/*
+ * calculate diff between comparator value and current ticks
+ */
+static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current)
+{
+
+ if (t->config & HPET_TN_32BIT) {
+ uint32_t diff, cmp;
+ cmp = (uint32_t)t->cmp;
+ diff = cmp - (uint32_t)current;
+ diff = (int32_t)diff > 0 ? diff : (uint32_t)0;
+ return (uint64_t)diff;
+ } else {
+ uint64_t diff, cmp;
+ cmp = t->cmp;
+ diff = cmp - current;
+ diff = (int64_t)diff > 0 ? diff : (uint64_t)0;
+ return diff;
+ }
+}
+
+static void update_irq(struct HPETTimer *timer)
+{
+ qemu_irq irq;
+ int route;
+
+ if (timer->tn <= 1 && hpet_in_legacy_mode()) {
+ /* if LegacyReplacementRoute bit is set, HPET specification requires
+ * timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
+ * timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
+ */
+ if (timer->tn == 0) {
+ irq=timer->state->irqs[0];
+ } else
+ irq=timer->state->irqs[8];
+ } else {
+ route=timer_int_route(timer);
+ irq=timer->state->irqs[route];
+ }
+ if (timer_enabled(timer) && hpet_enabled()) {
+ qemu_irq_pulse(irq);
+ }
+}
+
+static void hpet_save(QEMUFile *f, void *opaque)
+{
+ HPETState *s = opaque;
+ int i;
+ qemu_put_be64s(f, &s->config);
+ qemu_put_be64s(f, &s->isr);
+ /* save current counter value */
+ s->hpet_counter = hpet_get_ticks();
+ qemu_put_be64s(f, &s->hpet_counter);
+
+ for (i = 0; i < HPET_NUM_TIMERS; i++) {
+ qemu_put_8s(f, &s->timer[i].tn);
+ qemu_put_be64s(f, &s->timer[i].config);
+ qemu_put_be64s(f, &s->timer[i].cmp);
+ qemu_put_be64s(f, &s->timer[i].fsb);
+ qemu_put_be64s(f, &s->timer[i].period);
+ qemu_put_8s(f, &s->timer[i].wrap_flag);
+ if (s->timer[i].qemu_timer) {
+ qemu_put_timer(f, s->timer[i].qemu_timer);
+ }
+ }
+}
+
+static int hpet_load(QEMUFile *f, void *opaque, int version_id)
+{
+ HPETState *s = opaque;
+ int i;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_be64s(f, &s->config);
+ qemu_get_be64s(f, &s->isr);
+ qemu_get_be64s(f, &s->hpet_counter);
+ /* Recalculate the offset between the main counter and guest time */
+ s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock);
+
+ for (i = 0; i < HPET_NUM_TIMERS; i++) {
+ qemu_get_8s(f, &s->timer[i].tn);
+ qemu_get_be64s(f, &s->timer[i].config);
+ qemu_get_be64s(f, &s->timer[i].cmp);
+ qemu_get_be64s(f, &s->timer[i].fsb);
+ qemu_get_be64s(f, &s->timer[i].period);
+ qemu_get_8s(f, &s->timer[i].wrap_flag);
+ if (s->timer[i].qemu_timer) {
+ qemu_get_timer(f, s->timer[i].qemu_timer);
+ }
+ }
+ return 0;
+}
+
+/*
+ * timer expiration callback
+ */
+static void hpet_timer(void *opaque)
+{
+ HPETTimer *t = (HPETTimer*)opaque;
+ uint64_t diff;
+
+ uint64_t period = t->period;
+ uint64_t cur_tick = hpet_get_ticks();
+
+ if (timer_is_periodic(t) && period != 0) {
+ if (t->config & HPET_TN_32BIT) {
+ while (hpet_time_after(cur_tick, t->cmp))
+ t->cmp = (uint32_t)(t->cmp + t->period);
+ } else
+ while (hpet_time_after64(cur_tick, t->cmp))
+ t->cmp += period;
+
+ diff = hpet_calculate_diff(t, cur_tick);
+ qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock)
+ + (int64_t)ticks_to_ns(diff));
+ } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
+ if (t->wrap_flag) {
+ diff = hpet_calculate_diff(t, cur_tick);
+ qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock)
+ + (int64_t)ticks_to_ns(diff));
+ t->wrap_flag = 0;
+ }
+ }
+ update_irq(t);
+}
+
+static void hpet_set_timer(HPETTimer *t)
+{
+ uint64_t diff;
+ uint32_t wrap_diff; /* how many ticks until we wrap? */
+ uint64_t cur_tick = hpet_get_ticks();
+
+ /* whenever new timer is being set up, make sure wrap_flag is 0 */
+ t->wrap_flag = 0;
+ diff = hpet_calculate_diff(t, cur_tick);
+
+ /* hpet spec says in one-shot 32-bit mode, generate an interrupt when
+ * counter wraps in addition to an interrupt with comparator match.
+ */
+ if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
+ wrap_diff = 0xffffffff - (uint32_t)cur_tick;
+ if (wrap_diff < (uint32_t)diff) {
+ diff = wrap_diff;
+ t->wrap_flag = 1;
+ }
+ }
+ qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock)
+ + (int64_t)ticks_to_ns(diff));
+}
+
+static void hpet_del_timer(HPETTimer *t)
+{
+ qemu_del_timer(t->qemu_timer);
+}
+
+#ifdef HPET_DEBUG
+static uint32_t hpet_ram_readb(void *opaque, target_phys_addr_t addr)
+{
+ printf("qemu: hpet_read b at %" PRIx64 "\n", addr);
+ return 0;
+}
+
+static uint32_t hpet_ram_readw(void *opaque, target_phys_addr_t addr)
+{
+ printf("qemu: hpet_read w at %" PRIx64 "\n", addr);
+ return 0;
+}
+#endif
+
+static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr)
+{
+ HPETState *s = (HPETState *)opaque;
+ uint64_t cur_tick, index;
+
+ dprintf("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr);
+ index = addr;
+ /*address range of all TN regs*/
+ if (index >= 0x100 && index <= 0x3ff) {
+ uint8_t timer_id = (addr - 0x100) / 0x20;
+ if (timer_id > HPET_NUM_TIMERS - 1) {
+ printf("qemu: timer id out of range\n");
+ return 0;
+ }
+ HPETTimer *timer = &s->timer[timer_id];
+
+ switch ((addr - 0x100) % 0x20) {
+ case HPET_TN_CFG:
+ return timer->config;
+ case HPET_TN_CFG + 4: // Interrupt capabilities
+ return timer->config >> 32;
+ case HPET_TN_CMP: // comparator register
+ return timer->cmp;
+ case HPET_TN_CMP + 4:
+ return timer->cmp >> 32;
+ case HPET_TN_ROUTE:
+ return timer->fsb >> 32;
+ default:
+ dprintf("qemu: invalid hpet_ram_readl\n");
+ break;
+ }
+ } else {
+ switch (index) {
+ case HPET_ID:
+ return s->capability;
+ case HPET_PERIOD:
+ return s->capability >> 32;
+ case HPET_CFG:
+ return s->config;
+ case HPET_CFG + 4:
+ dprintf("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n");
+ return 0;
+ case HPET_COUNTER:
+ if (hpet_enabled())
+ cur_tick = hpet_get_ticks();
+ else
+ cur_tick = s->hpet_counter;
+ dprintf("qemu: reading counter = %" PRIx64 "\n", cur_tick);
+ return cur_tick;
+ case HPET_COUNTER + 4:
+ if (hpet_enabled())
+ cur_tick = hpet_get_ticks();
+ else
+ cur_tick = s->hpet_counter;
+ dprintf("qemu: reading counter + 4 = %" PRIx64 "\n", cur_tick);
+ return cur_tick >> 32;
+ case HPET_STATUS:
+ return s->isr;
+ default:
+ dprintf("qemu: invalid hpet_ram_readl\n");
+ break;
+ }
+ }
+ return 0;
+}
+
+#ifdef HPET_DEBUG
+static void hpet_ram_writeb(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ printf("qemu: invalid hpet_write b at %" PRIx64 " = %#x\n",
+ addr, value);
+}
+
+static void hpet_ram_writew(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ printf("qemu: invalid hpet_write w at %" PRIx64 " = %#x\n",
+ addr, value);
+}
+#endif
+
+static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ int i;
+ HPETState *s = (HPETState *)opaque;
+ uint64_t old_val, new_val, index;
+
+ dprintf("qemu: Enter hpet_ram_writel at %" PRIx64 " = %#x\n", addr, value);
+ index = addr;
+ old_val = hpet_ram_readl(opaque, addr);
+ new_val = value;
+
+ /*address range of all TN regs*/
+ if (index >= 0x100 && index <= 0x3ff) {
+ uint8_t timer_id = (addr - 0x100) / 0x20;
+ dprintf("qemu: hpet_ram_writel timer_id = %#x \n", timer_id);
+ HPETTimer *timer = &s->timer[timer_id];
+
+ switch ((addr - 0x100) % 0x20) {
+ case HPET_TN_CFG:
+ dprintf("qemu: hpet_ram_writel HPET_TN_CFG\n");
+ timer->config = hpet_fixup_reg(new_val, old_val, 0x3e4e);
+ if (new_val & HPET_TN_32BIT) {
+ timer->cmp = (uint32_t)timer->cmp;
+ timer->period = (uint32_t)timer->period;
+ }
+ if (new_val & HPET_TIMER_TYPE_LEVEL) {
+ printf("qemu: level-triggered hpet not supported\n");
+ exit (-1);
+ }
+
+ break;
+ case HPET_TN_CFG + 4: // Interrupt capabilities
+ dprintf("qemu: invalid HPET_TN_CFG+4 write\n");
+ break;
+ case HPET_TN_CMP: // comparator register
+ dprintf("qemu: hpet_ram_writel HPET_TN_CMP \n");
+ if (timer->config & HPET_TN_32BIT)
+ new_val = (uint32_t)new_val;
+ if (!timer_is_periodic(timer) ||
+ (timer->config & HPET_TN_SETVAL))
+ timer->cmp = (timer->cmp & 0xffffffff00000000ULL)
+ | new_val;
+ else {
+ /*
+ * FIXME: Clamp period to reasonable min value?
+ * Clamp period to reasonable max value
+ */
+ new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
+ timer->period = (timer->period & 0xffffffff00000000ULL)
+ | new_val;
+ }
+ timer->config &= ~HPET_TN_SETVAL;
+ if (hpet_enabled())
+ hpet_set_timer(timer);
+ break;
+ case HPET_TN_CMP + 4: // comparator register high order
+ dprintf("qemu: hpet_ram_writel HPET_TN_CMP + 4\n");
+ if (!timer_is_periodic(timer) ||
+ (timer->config & HPET_TN_SETVAL))
+ timer->cmp = (timer->cmp & 0xffffffffULL)
+ | new_val << 32;
+ else {
+ /*
+ * FIXME: Clamp period to reasonable min value?
+ * Clamp period to reasonable max value
+ */
+ new_val &= (timer->config
+ & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
+ timer->period = (timer->period & 0xffffffffULL)
+ | new_val << 32;
+ }
+ timer->config &= ~HPET_TN_SETVAL;
+ if (hpet_enabled())
+ hpet_set_timer(timer);
+ break;
+ case HPET_TN_ROUTE + 4:
+ dprintf("qemu: hpet_ram_writel HPET_TN_ROUTE + 4\n");
+ break;
+ default:
+ dprintf("qemu: invalid hpet_ram_writel\n");
+ break;
+ }
+ return;
+ } else {
+ switch (index) {
+ case HPET_ID:
+ return;
+ case HPET_CFG:
+ s->config = hpet_fixup_reg(new_val, old_val, 0x3);
+ if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
+ /* Enable main counter and interrupt generation. */
+ s->hpet_offset = ticks_to_ns(s->hpet_counter)
+ - qemu_get_clock(vm_clock);
+ for (i = 0; i < HPET_NUM_TIMERS; i++)
+ if ((&s->timer[i])->cmp != ~0ULL)
+ hpet_set_timer(&s->timer[i]);
+ }
+ else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
+ /* Halt main counter and disable interrupt generation. */
+ s->hpet_counter = hpet_get_ticks();
+ for (i = 0; i < HPET_NUM_TIMERS; i++)
+ hpet_del_timer(&s->timer[i]);
+ }
+ /* i8254 and RTC are disabled when HPET is in legacy mode */
+ if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
+ hpet_pit_disable();
+ } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
+ hpet_pit_enable();
+ }
+ break;
+ case HPET_CFG + 4:
+ dprintf("qemu: invalid HPET_CFG+4 write \n");
+ break;
+ case HPET_STATUS:
+ /* FIXME: need to handle level-triggered interrupts */
+ break;
+ case HPET_COUNTER:
+ if (hpet_enabled())
+ printf("qemu: Writing counter while HPET enabled!\n");
+ s->hpet_counter = (s->hpet_counter & 0xffffffff00000000ULL)
+ | value;
+ dprintf("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n",
+ value, s->hpet_counter);
+ break;
+ case HPET_COUNTER + 4:
+ if (hpet_enabled())
+ printf("qemu: Writing counter while HPET enabled!\n");
+ s->hpet_counter = (s->hpet_counter & 0xffffffffULL)
+ | (((uint64_t)value) << 32);
+ dprintf("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n",
+ value, s->hpet_counter);
+ break;
+ default:
+ dprintf("qemu: invalid hpet_ram_writel\n");
+ break;
+ }
+ }
+}
+
+static CPUReadMemoryFunc *hpet_ram_read[] = {
+#ifdef HPET_DEBUG
+ hpet_ram_readb,
+ hpet_ram_readw,
+#else
+ NULL,
+ NULL,
+#endif
+ hpet_ram_readl,
+};
+
+static CPUWriteMemoryFunc *hpet_ram_write[] = {
+#ifdef HPET_DEBUG
+ hpet_ram_writeb,
+ hpet_ram_writew,
+#else
+ NULL,
+ NULL,
+#endif
+ hpet_ram_writel,
+};
+
+static void hpet_reset(void *opaque) {
+ HPETState *s = opaque;
+ int i;
+ static int count = 0;
+
+ for (i=0; i<HPET_NUM_TIMERS; i++) {
+ HPETTimer *timer = &s->timer[i];
+ hpet_del_timer(timer);
+ timer->tn = i;
+ timer->cmp = ~0ULL;
+ timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
+ /* advertise availability of irqs 5,10,11 */
+ timer->config |= 0x00000c20ULL << 32;
+ timer->state = s;
+ timer->period = 0ULL;
+ timer->wrap_flag = 0;
+ }
+
+ s->hpet_counter = 0ULL;
+ s->hpet_offset = 0ULL;
+ /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
+ s->capability = 0x8086a201ULL;
+ s->capability |= ((HPET_CLK_PERIOD) << 32);
+ if (count > 0)
+ /* we don't enable pit when hpet_reset is first called (by hpet_init)
+ * because hpet is taking over for pit here. On subsequent invocations,
+ * hpet_reset is called due to system reset. At this point control must
+ * be returned to pit until SW reenables hpet.
+ */
+ hpet_pit_enable();
+ count = 1;
+}
+
+
+void hpet_init(qemu_irq *irq) {
+ int i, iomemtype;
+ HPETState *s;
+
+ dprintf ("hpet_init\n");
+
+ s = qemu_mallocz(sizeof(HPETState));
+ hpet_statep = s;
+ s->irqs = irq;
+ for (i=0; i<HPET_NUM_TIMERS; i++) {
+ HPETTimer *timer = &s->timer[i];
+ timer->qemu_timer = qemu_new_timer(vm_clock, hpet_timer, timer);
+ }
+ hpet_reset(s);
+ register_savevm("hpet", -1, 1, hpet_save, hpet_load, s);
+ qemu_register_reset(hpet_reset, s);
+ /* HPET Area */
+ iomemtype = cpu_register_io_memory(0, hpet_ram_read,
+ hpet_ram_write, s);
+ cpu_register_physical_memory(HPET_BASE, 0x400, iomemtype);
+}
diff --git a/hw/hpet_emul.h b/hw/hpet_emul.h
new file mode 100644
index 000000000..fbe7a4453
--- /dev/null
+++ b/hw/hpet_emul.h
@@ -0,0 +1,85 @@
+/*
+ * QEMU Emulated HPET support
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ * Beth Kon <bkon@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef QEMU_HPET_EMUL_H
+#define QEMU_HPET_EMUL_H
+
+#define HPET_BASE 0xfed00000
+#define HPET_CLK_PERIOD 10000000ULL /* 10000000 femtoseconds == 10ns*/
+
+#define FS_PER_NS 1000000
+#define HPET_NUM_TIMERS 3
+#define HPET_TIMER_TYPE_LEVEL 1
+#define HPET_TIMER_TYPE_EDGE 0
+#define HPET_TIMER_DELIVERY_APIC 0
+#define HPET_TIMER_DELIVERY_FSB 1
+#define HPET_TIMER_CAP_FSB_INT_DEL (1 << 15)
+#define HPET_TIMER_CAP_PER_INT (1 << 4)
+
+#define HPET_CFG_ENABLE 0x001
+#define HPET_CFG_LEGACY 0x002
+
+#define HPET_ID 0x000
+#define HPET_PERIOD 0x004
+#define HPET_CFG 0x010
+#define HPET_STATUS 0x020
+#define HPET_COUNTER 0x0f0
+#define HPET_TN_CFG 0x000
+#define HPET_TN_CMP 0x008
+#define HPET_TN_ROUTE 0x010
+
+
+#define HPET_TN_ENABLE 0x004
+#define HPET_TN_PERIODIC 0x008
+#define HPET_TN_PERIODIC_CAP 0x010
+#define HPET_TN_SIZE_CAP 0x020
+#define HPET_TN_SETVAL 0x040
+#define HPET_TN_32BIT 0x100
+#define HPET_TN_INT_ROUTE_MASK 0x3e00
+#define HPET_TN_INT_ROUTE_SHIFT 9
+#define HPET_TN_INT_ROUTE_CAP_SHIFT 32
+#define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U
+
+struct HPETState;
+typedef struct HPETTimer { /* timers */
+ uint8_t tn; /*timer number*/
+ QEMUTimer *qemu_timer;
+ struct HPETState *state;
+ /* Memory-mapped, software visible timer registers */
+ uint64_t config; /* configuration/cap */
+ uint64_t cmp; /* comparator */
+ uint64_t fsb; /* FSB route, not supported now */
+ /* Hidden register state */
+ uint64_t period; /* Last value written to comparator */
+ uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit
+ * mode. Next pop will be actual timer expiration.
+ */
+} HPETTimer;
+
+typedef struct HPETState {
+ uint64_t hpet_offset;
+ qemu_irq *irqs;
+ HPETTimer timer[HPET_NUM_TIMERS];
+
+ /* Memory-mapped, software visible registers */
+ uint64_t capability; /* capabilities */
+ uint64_t config; /* configuration */
+ uint64_t isr; /* interrupt status reg */
+ uint64_t hpet_counter; /* main counter */
+} HPETState;
+
+#if defined TARGET_I386 || defined TARGET_X86_64
+extern uint32_t hpet_in_legacy_mode(void);
+extern void hpet_init(qemu_irq *irq);
+#endif
+
+#endif
diff --git a/hw/i8254.c b/hw/i8254.c
index 69eb889c1..e6be0cd3c 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -459,6 +459,27 @@ void pit_reset(void *opaque)
}
}
+/* When HPET is operating in legacy mode, i8254 timer0 is disabled */
+void hpet_pit_disable(void) {
+ PITChannelState *s;
+ s = &pit_state.channels[0];
+ qemu_del_timer(s->irq_timer);
+}
+
+/* When HPET is reset or leaving legacy mode, it must reenable i8254
+ * timer 0
+ */
+
+void hpet_pit_enable(void)
+{
+ PITState *pit = &pit_state;
+ PITChannelState *s;
+ s = &pit->channels[0];
+ s->mode = 3;
+ s->gate = 1;
+ pit_load_count(s, 0);
+}
+
PITState *pit_init(int base, qemu_irq irq)
{
PITState *pit = &pit_state;
diff --git a/hw/iommu.c b/hw/iommu.c
index ee9b78c87..82a493288 100644
--- a/hw/iommu.c
+++ b/hw/iommu.c
@@ -78,6 +78,19 @@ do { printf("IOMMU: " fmt , ##args); } while (0)
#define IOMMU_AFAR (0x1004 >> 2)
+#define IOMMU_AER (0x1008 >> 2) /* Arbiter Enable Register */
+#define IOMMU_AER_EN_P0_ARB 0x00000001 /* MBus master 0x8 (Always 1) */
+#define IOMMU_AER_EN_P1_ARB 0x00000002 /* MBus master 0x9 */
+#define IOMMU_AER_EN_P2_ARB 0x00000004 /* MBus master 0xa */
+#define IOMMU_AER_EN_P3_ARB 0x00000008 /* MBus master 0xb */
+#define IOMMU_AER_EN_0 0x00010000 /* SBus slot 0 */
+#define IOMMU_AER_EN_1 0x00020000 /* SBus slot 1 */
+#define IOMMU_AER_EN_2 0x00040000 /* SBus slot 2 */
+#define IOMMU_AER_EN_3 0x00080000 /* SBus slot 3 */
+#define IOMMU_AER_EN_F 0x00100000 /* SBus on-board */
+#define IOMMU_AER_SBW 0x80000000 /* S-to-M asynchronous writes */
+#define IOMMU_AER_MASK 0x801f000f
+
#define IOMMU_SBCFG0 (0x1010 >> 2) /* SBUS configration per-slot */
#define IOMMU_SBCFG1 (0x1014 >> 2) /* SBUS configration per-slot */
#define IOMMU_SBCFG2 (0x1018 >> 2) /* SBUS configration per-slot */
@@ -196,6 +209,9 @@ static void iommu_mem_writel(void *opaque, target_phys_addr_t addr,
s->regs[saddr] = val;
qemu_irq_lower(s->irq);
break;
+ case IOMMU_AER:
+ s->regs[saddr] = (val & IOMMU_AER_MASK) | IOMMU_AER_EN_P0_ARB;
+ break;
case IOMMU_AFSR:
s->regs[saddr] = (val & IOMMU_AFSR_MASK) | IOMMU_AFSR_RESV;
qemu_irq_lower(s->irq);
@@ -344,6 +360,7 @@ static void iommu_reset(void *opaque)
s->regs[IOMMU_CTRL] = s->version;
s->regs[IOMMU_ARBEN] = IOMMU_MID;
s->regs[IOMMU_AFSR] = IOMMU_AFSR_RESV;
+ s->regs[IOMMU_AER] = IOMMU_AER_EN_P0_ARB | IOMMU_AER_EN_P1_ARB;
s->regs[IOMMU_MASK_ID] = IOMMU_TS_MASK;
qemu_irq_lower(s->irq);
}
diff --git a/hw/max7310.c b/hw/max7310.c
index 2816611a8..ee5758103 100644
--- a/hw/max7310.c
+++ b/hw/max7310.c
@@ -180,7 +180,7 @@ static int max7310_load(QEMUFile *f, void *opaque, int version_id)
static void max7310_gpio_set(void *opaque, int line, int level)
{
struct max7310_s *s = (struct max7310_s *) opaque;
- if (line >= sizeof(s->handler) / sizeof(*s->handler) || line < 0)
+ if (line >= ARRAY_SIZE(s->handler) || line < 0)
hw_error("bad GPIO line");
if (level)
@@ -199,7 +199,7 @@ struct i2c_slave *max7310_init(i2c_bus *bus)
s->i2c.recv = max7310_rx;
s->i2c.send = max7310_tx;
s->gpio_in = qemu_allocate_irqs(max7310_gpio_set, s,
- sizeof(s->handler) / sizeof(*s->handler));
+ ARRAY_SIZE(s->handler));
max7310_reset(&s->i2c);
@@ -217,7 +217,7 @@ qemu_irq *max7310_gpio_in_get(i2c_slave *i2c)
void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler)
{
struct max7310_s *s = (struct max7310_s *) i2c;
- if (line >= sizeof(s->handler) / sizeof(*s->handler) || line < 0)
+ if (line >= ARRAY_SIZE(s->handler) || line < 0)
hw_error("bad GPIO line");
s->handler[line] = handler;
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index ac41a947b..faf847dca 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -26,6 +26,7 @@
#include "sysemu.h"
#include "pc.h"
#include "isa.h"
+#include "hpet_emul.h"
//#define DEBUG_CMOS
@@ -69,6 +70,18 @@ struct RTCState {
QEMUTimer *second_timer2;
};
+static void rtc_irq_raise(qemu_irq irq) {
+ /* When HPET is operating in legacy mode, RTC interrupts are disabled
+ * We block qemu_irq_raise, but not qemu_irq_lower, in case legacy
+ * mode is established while interrupt is raised. We want it to
+ * be lowered in any case
+ */
+#if defined TARGET_I386 || defined TARGET_X86_64
+ if (!hpet_in_legacy_mode())
+#endif
+ qemu_irq_raise(irq);
+}
+
static void rtc_set_time(RTCState *s);
static void rtc_copy_date(RTCState *s);
@@ -78,8 +91,14 @@ static void rtc_timer_update(RTCState *s, int64_t current_time)
int64_t cur_clock, next_irq_clock;
period_code = s->cmos_data[RTC_REG_A] & 0x0f;
- if (period_code != 0 &&
- (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
+#if defined TARGET_I386 || defined TARGET_X86_64
+ /* disable periodic timer if hpet is in legacy mode, since interrupts are
+ * disabled anyway.
+ */
+ if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && !hpet_in_legacy_mode()) {
+#else
+ if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
+#endif
if (period_code <= 2)
period_code += 7;
/* period in 32 Khz cycles */
@@ -100,7 +119,7 @@ static void rtc_periodic_timer(void *opaque)
rtc_timer_update(s, s->next_periodic_time);
s->cmos_data[RTC_REG_C] |= 0xc0;
- qemu_irq_raise(s->irq);
+ rtc_irq_raise(s->irq);
}
static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
@@ -319,14 +338,14 @@ static void rtc_update_second2(void *opaque)
s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
s->cmos_data[RTC_REG_C] |= 0xa0;
- qemu_irq_raise(s->irq);
+ rtc_irq_raise(s->irq);
}
}
/* update ended interrupt */
if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
s->cmos_data[RTC_REG_C] |= 0x90;
- qemu_irq_raise(s->irq);
+ rtc_irq_raise(s->irq);
}
/* clear update in progress bit */
diff --git a/hw/nseries.c b/hw/nseries.c
index 80fd9e81d..925e89cf5 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -432,7 +432,7 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
cpu_abort(cpu_single_env, "%s: FIXME: bad SPI word width %i\n",
__FUNCTION__, len);
- if (s->p >= sizeof(s->resp) / sizeof(*s->resp))
+ if (s->p >= ARRAY_SIZE(s->resp))
ret = 0;
else
ret = s->resp[s->p ++];
@@ -840,7 +840,7 @@ static void n800_setup_nolo_tags(void *sram_base)
/* OMAP STI console? Pin out settings? */
ADD_TAG(0x6e01, 414);
- for (i = 0; i < sizeof(n800_pinout) / 4; i ++)
+ for (i = 0; i < ARRAY_SIZE(n800_pinout); i ++)
stl_raw(v ++, n800_pinout[i]);
/* Kernel memsize? */
diff --git a/hw/pc.c b/hw/pc.c
index 2924b2a9e..2d7e7f00e 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -35,6 +35,7 @@
#include "fw_cfg.h"
#include "virtio-blk.h"
#include "virtio-balloon.h"
+#include "hpet_emul.h"
#include "device-assignment.h"
#include "qemu-kvm.h"
@@ -1037,6 +1038,9 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
#endif
pit = pit_init(0x40, i8259[0]);
pcspk_init(pit);
+ if (!no_hpet) {
+ hpet_init(i8259);
+ }
if (pci_enabled) {
pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
}
@@ -1215,6 +1219,14 @@ static void pc_init_isa(ram_addr_t ram_size, int vga_ram_size,
initrd_filename, 0, cpu_model);
}
+/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
+ BIOS will read it and start S3 resume at POST Entry */
+void cmos_set_s3_resume(void)
+{
+ if (rtc_state)
+ rtc_set_memory(rtc_state, 0xF, 0xFE);
+}
+
QEMUMachine pc_machine = {
.name = "pc",
.desc = "Standard PC",
diff --git a/hw/pc.h b/hw/pc.h
index 4df4a0e6a..e9ddd4dd3 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -64,6 +64,9 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time);
PITState *kvm_pit_init(int base, qemu_irq irq);
+void hpet_pit_disable(void);
+void hpet_pit_enable(void);
+
/* vmport.c */
void vmport_init(void);
void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque);
@@ -86,6 +89,7 @@ RTCState *rtc_init(int base, qemu_irq irq);
RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq);
void rtc_set_memory(RTCState *s, int addr, int val);
void rtc_set_date(RTCState *s, const struct tm *tm);
+void cmos_set_s3_resume(void);
/* pc.c */
extern int fd_bootchk;
@@ -101,6 +105,9 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
void acpi_bios_init(void);
+/* hpet.c */
+extern int no_hpet;
+
/* pcspk.c */
void pcspk_init(PITState *);
int pcspk_audio_init(AudioState *, qemu_irq *pic);
diff --git a/hw/pci.c b/hw/pci.c
index 01b39fa4d..8589dfa8c 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -25,9 +25,9 @@
#include "pci.h"
#include "console.h"
#include "net.h"
+#include "virtio-net.h"
#include "pc.h"
#include "qemu-kvm.h"
-#include "virtio-net.h"
//#define DEBUG_PCI
@@ -427,6 +427,7 @@ void pci_default_write_config(PCIDevice *d,
case 0x0b:
case 0x0e:
case 0x10 ... 0x27: /* base */
+ case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */
case 0x30 ... 0x33: /* rom */
case 0x3d:
can_write = 0;
@@ -448,6 +449,7 @@ void pci_default_write_config(PCIDevice *d,
case 0x0a:
case 0x0b:
case 0x0e:
+ case 0x2c ... 0x2f: /* read-only subsystem ID & vendor ID */
case 0x38 ... 0x3b: /* rom */
case 0x3d:
can_write = 0;
@@ -459,6 +461,18 @@ void pci_default_write_config(PCIDevice *d,
break;
}
if (can_write) {
+ /* Mask out writes to reserved bits in registers */
+ switch (addr) {
+ case 0x05:
+ val &= ~PCI_COMMAND_RESERVED_MASK_HI;
+ break;
+ case 0x06:
+ val &= ~PCI_STATUS_RESERVED_MASK_LO;
+ break;
+ case 0x07:
+ val &= ~PCI_STATUS_RESERVED_MASK_HI;
+ break;
+ }
d->config[addr] = val;
}
if (++addr > 0xff)
diff --git a/hw/pci.h b/hw/pci.h
index f6f417ec2..1f33819fe 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -58,6 +58,26 @@ typedef struct PCIIORegion {
#define PCI_MIN_GNT 0x3e /* 8 bits */
#define PCI_MAX_LAT 0x3f /* 8 bits */
+/* Bits in the PCI Status Register (PCI 2.3 spec) */
+#define PCI_STATUS_RESERVED1 0x007
+#define PCI_STATUS_INT_STATUS 0x008
+#define PCI_STATUS_CAPABILITIES 0x010
+#define PCI_STATUS_66MHZ 0x020
+#define PCI_STATUS_RESERVED2 0x040
+#define PCI_STATUS_FAST_BACK 0x080
+#define PCI_STATUS_DEVSEL 0x600
+
+#define PCI_STATUS_RESERVED_MASK_LO (PCI_STATUS_RESERVED1 | \
+ PCI_STATUS_INT_STATUS | PCI_STATUS_CAPABILITIES | \
+ PCI_STATUS_66MHZ | PCI_STATUS_RESERVED2 | PCI_STATUS_FAST_BACK)
+
+#define PCI_STATUS_RESERVED_MASK_HI (PCI_STATUS_DEVSEL >> 8)
+
+/* Bits in the PCI Command Register (PCI 2.3 spec) */
+#define PCI_COMMAND_RESERVED 0xf800
+
+#define PCI_COMMAND_RESERVED_MASK_HI (PCI_COMMAND_RESERVED >> 8)
+
struct PCIDevice {
/* PCI config space */
uint8_t config[256];
diff --git a/hw/ppc405.h b/hw/ppc405.h
index e03217016..eebcef30c 100644
--- a/hw/ppc405.h
+++ b/hw/ppc405.h
@@ -66,11 +66,6 @@ void ppc4xx_pob_init (CPUState *env);
/* OPB arbitrer */
void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio,
target_phys_addr_t offset);
-/* SDRAM controller */
-void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
- target_phys_addr_t *ram_bases,
- target_phys_addr_t *ram_sizes,
- int do_init);
/* Peripheral controller */
void ppc405_ebc_init (CPUState *env);
/* DMA controller */
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
index 25bcfd82f..9275416a1 100644
--- a/hw/ppc405_uc.c
+++ b/hw/ppc405_uc.c
@@ -401,347 +401,6 @@ void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio,
/* XXX: TODO */
/*****************************************************************************/
-/* SDRAM controller */
-typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
-struct ppc4xx_sdram_t {
- uint32_t addr;
- int nbanks;
- target_phys_addr_t ram_bases[4];
- target_phys_addr_t ram_sizes[4];
- uint32_t besr0;
- uint32_t besr1;
- uint32_t bear;
- uint32_t cfg;
- uint32_t status;
- uint32_t rtr;
- uint32_t pmit;
- uint32_t bcr[4];
- uint32_t tr;
- uint32_t ecccfg;
- uint32_t eccesr;
- qemu_irq irq;
-};
-
-enum {
- SDRAM0_CFGADDR = 0x010,
- SDRAM0_CFGDATA = 0x011,
-};
-
-/* XXX: TOFIX: some patches have made this code become inconsistent:
- * there are type inconsistencies, mixing target_phys_addr_t, target_ulong
- * and uint32_t
- */
-static uint32_t sdram_bcr (target_phys_addr_t ram_base,
- target_phys_addr_t ram_size)
-{
- uint32_t bcr;
-
- switch (ram_size) {
- case (4 * 1024 * 1024):
- bcr = 0x00000000;
- break;
- case (8 * 1024 * 1024):
- bcr = 0x00020000;
- break;
- case (16 * 1024 * 1024):
- bcr = 0x00040000;
- break;
- case (32 * 1024 * 1024):
- bcr = 0x00060000;
- break;
- case (64 * 1024 * 1024):
- bcr = 0x00080000;
- break;
- case (128 * 1024 * 1024):
- bcr = 0x000A0000;
- break;
- case (256 * 1024 * 1024):
- bcr = 0x000C0000;
- break;
- default:
- printf("%s: invalid RAM size " PADDRX "\n", __func__, ram_size);
- return 0x00000000;
- }
- bcr |= ram_base & 0xFF800000;
- bcr |= 1;
-
- return bcr;
-}
-
-static always_inline target_phys_addr_t sdram_base (uint32_t bcr)
-{
- return bcr & 0xFF800000;
-}
-
-static target_ulong sdram_size (uint32_t bcr)
-{
- target_ulong size;
- int sh;
-
- sh = (bcr >> 17) & 0x7;
- if (sh == 7)
- size = -1;
- else
- size = (4 * 1024 * 1024) << sh;
-
- return size;
-}
-
-static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled)
-{
- if (*bcrp & 0x00000001) {
- /* Unmap RAM */
-#ifdef DEBUG_SDRAM
- printf("%s: unmap RAM area " PADDRX " " ADDRX "\n",
- __func__, sdram_base(*bcrp), sdram_size(*bcrp));
-#endif
- cpu_register_physical_memory(sdram_base(*bcrp), sdram_size(*bcrp),
- IO_MEM_UNASSIGNED);
- }
- *bcrp = bcr & 0xFFDEE001;
- if (enabled && (bcr & 0x00000001)) {
-#ifdef DEBUG_SDRAM
- printf("%s: Map RAM area " PADDRX " " ADDRX "\n",
- __func__, sdram_base(bcr), sdram_size(bcr));
-#endif
- cpu_register_physical_memory(sdram_base(bcr), sdram_size(bcr),
- sdram_base(bcr) | IO_MEM_RAM);
- }
-}
-
-static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
-{
- int i;
-
- for (i = 0; i < sdram->nbanks; i++) {
- if (sdram->ram_sizes[i] != 0) {
- sdram_set_bcr(&sdram->bcr[i],
- sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
- 1);
- } else {
- sdram_set_bcr(&sdram->bcr[i], 0x00000000, 0);
- }
- }
-}
-
-static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
-{
- int i;
-
- for (i = 0; i < sdram->nbanks; i++) {
-#ifdef DEBUG_SDRAM
- printf("%s: Unmap RAM area " PADDRX " " ADDRX "\n",
- __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
-#endif
- cpu_register_physical_memory(sdram_base(sdram->bcr[i]),
- sdram_size(sdram->bcr[i]),
- IO_MEM_UNASSIGNED);
- }
-}
-
-static target_ulong dcr_read_sdram (void *opaque, int dcrn)
-{
- ppc4xx_sdram_t *sdram;
- target_ulong ret;
-
- sdram = opaque;
- switch (dcrn) {
- case SDRAM0_CFGADDR:
- ret = sdram->addr;
- break;
- case SDRAM0_CFGDATA:
- switch (sdram->addr) {
- case 0x00: /* SDRAM_BESR0 */
- ret = sdram->besr0;
- break;
- case 0x08: /* SDRAM_BESR1 */
- ret = sdram->besr1;
- break;
- case 0x10: /* SDRAM_BEAR */
- ret = sdram->bear;
- break;
- case 0x20: /* SDRAM_CFG */
- ret = sdram->cfg;
- break;
- case 0x24: /* SDRAM_STATUS */
- ret = sdram->status;
- break;
- case 0x30: /* SDRAM_RTR */
- ret = sdram->rtr;
- break;
- case 0x34: /* SDRAM_PMIT */
- ret = sdram->pmit;
- break;
- case 0x40: /* SDRAM_B0CR */
- ret = sdram->bcr[0];
- break;
- case 0x44: /* SDRAM_B1CR */
- ret = sdram->bcr[1];
- break;
- case 0x48: /* SDRAM_B2CR */
- ret = sdram->bcr[2];
- break;
- case 0x4C: /* SDRAM_B3CR */
- ret = sdram->bcr[3];
- break;
- case 0x80: /* SDRAM_TR */
- ret = -1; /* ? */
- break;
- case 0x94: /* SDRAM_ECCCFG */
- ret = sdram->ecccfg;
- break;
- case 0x98: /* SDRAM_ECCESR */
- ret = sdram->eccesr;
- break;
- default: /* Error */
- ret = -1;
- break;
- }
- break;
- default:
- /* Avoid gcc warning */
- ret = 0x00000000;
- break;
- }
-
- return ret;
-}
-
-static void dcr_write_sdram (void *opaque, int dcrn, target_ulong val)
-{
- ppc4xx_sdram_t *sdram;
-
- sdram = opaque;
- switch (dcrn) {
- case SDRAM0_CFGADDR:
- sdram->addr = val;
- break;
- case SDRAM0_CFGDATA:
- switch (sdram->addr) {
- case 0x00: /* SDRAM_BESR0 */
- sdram->besr0 &= ~val;
- break;
- case 0x08: /* SDRAM_BESR1 */
- sdram->besr1 &= ~val;
- break;
- case 0x10: /* SDRAM_BEAR */
- sdram->bear = val;
- break;
- case 0x20: /* SDRAM_CFG */
- val &= 0xFFE00000;
- if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
-#ifdef DEBUG_SDRAM
- printf("%s: enable SDRAM controller\n", __func__);
-#endif
- /* validate all RAM mappings */
- sdram_map_bcr(sdram);
- sdram->status &= ~0x80000000;
- } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
-#ifdef DEBUG_SDRAM
- printf("%s: disable SDRAM controller\n", __func__);
-#endif
- /* invalidate all RAM mappings */
- sdram_unmap_bcr(sdram);
- sdram->status |= 0x80000000;
- }
- if (!(sdram->cfg & 0x40000000) && (val & 0x40000000))
- sdram->status |= 0x40000000;
- else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000))
- sdram->status &= ~0x40000000;
- sdram->cfg = val;
- break;
- case 0x24: /* SDRAM_STATUS */
- /* Read-only register */
- break;
- case 0x30: /* SDRAM_RTR */
- sdram->rtr = val & 0x3FF80000;
- break;
- case 0x34: /* SDRAM_PMIT */
- sdram->pmit = (val & 0xF8000000) | 0x07C00000;
- break;
- case 0x40: /* SDRAM_B0CR */
- sdram_set_bcr(&sdram->bcr[0], val, sdram->cfg & 0x80000000);
- break;
- case 0x44: /* SDRAM_B1CR */
- sdram_set_bcr(&sdram->bcr[1], val, sdram->cfg & 0x80000000);
- break;
- case 0x48: /* SDRAM_B2CR */
- sdram_set_bcr(&sdram->bcr[2], val, sdram->cfg & 0x80000000);
- break;
- case 0x4C: /* SDRAM_B3CR */
- sdram_set_bcr(&sdram->bcr[3], val, sdram->cfg & 0x80000000);
- break;
- case 0x80: /* SDRAM_TR */
- sdram->tr = val & 0x018FC01F;
- break;
- case 0x94: /* SDRAM_ECCCFG */
- sdram->ecccfg = val & 0x00F00000;
- break;
- case 0x98: /* SDRAM_ECCESR */
- val &= 0xFFF0F000;
- if (sdram->eccesr == 0 && val != 0)
- qemu_irq_raise(sdram->irq);
- else if (sdram->eccesr != 0 && val == 0)
- qemu_irq_lower(sdram->irq);
- sdram->eccesr = val;
- break;
- default: /* Error */
- break;
- }
- break;
- }
-}
-
-static void sdram_reset (void *opaque)
-{
- ppc4xx_sdram_t *sdram;
-
- sdram = opaque;
- sdram->addr = 0x00000000;
- sdram->bear = 0x00000000;
- sdram->besr0 = 0x00000000; /* No error */
- sdram->besr1 = 0x00000000; /* No error */
- sdram->cfg = 0x00000000;
- sdram->ecccfg = 0x00000000; /* No ECC */
- sdram->eccesr = 0x00000000; /* No error */
- sdram->pmit = 0x07C00000;
- sdram->rtr = 0x05F00000;
- sdram->tr = 0x00854009;
- /* We pre-initialize RAM banks */
- sdram->status = 0x00000000;
- sdram->cfg = 0x00800000;
- sdram_unmap_bcr(sdram);
-}
-
-void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
- target_phys_addr_t *ram_bases,
- target_phys_addr_t *ram_sizes,
- int do_init)
-{
- ppc4xx_sdram_t *sdram;
-
- sdram = qemu_mallocz(sizeof(ppc4xx_sdram_t));
- if (sdram != NULL) {
- sdram->irq = irq;
- sdram->nbanks = nbanks;
- memset(sdram->ram_bases, 0, 4 * sizeof(target_phys_addr_t));
- memcpy(sdram->ram_bases, ram_bases,
- nbanks * sizeof(target_phys_addr_t));
- memset(sdram->ram_sizes, 0, 4 * sizeof(target_phys_addr_t));
- memcpy(sdram->ram_sizes, ram_sizes,
- nbanks * sizeof(target_phys_addr_t));
- sdram_reset(sdram);
- qemu_register_reset(&sdram_reset, sdram);
- ppc_dcr_register(env, SDRAM0_CFGADDR,
- sdram, &dcr_read_sdram, &dcr_write_sdram);
- ppc_dcr_register(env, SDRAM0_CFGDATA,
- sdram, &dcr_read_sdram, &dcr_write_sdram);
- if (do_init)
- sdram_map_bcr(sdram);
- }
-}
-
-/*****************************************************************************/
/* Peripheral controller */
typedef struct ppc4xx_ebc_t ppc4xx_ebc_t;
struct ppc4xx_ebc_t {
@@ -2571,7 +2230,7 @@ CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
*picp = pic;
/* SDRAM controller */
- ppc405_sdram_init(env, pic[14], 1, ram_bases, ram_sizes, do_init);
+ ppc4xx_sdram_init(env, pic[14], 1, ram_bases, ram_sizes, do_init);
offset = 0;
for (i = 0; i < 4; i++)
offset += ram_sizes[i];
@@ -2929,7 +2588,7 @@ CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
*picp = pic;
/* SDRAM controller */
/* XXX 405EP has no ECC interrupt */
- ppc405_sdram_init(env, pic[17], 2, ram_bases, ram_sizes, do_init);
+ ppc4xx_sdram_init(env, pic[17], 2, ram_bases, ram_sizes, do_init);
offset = 0;
for (i = 0; i < 2; i++)
offset += ram_sizes[i];
diff --git a/hw/ppc440.c b/hw/ppc440.c
new file mode 100644
index 000000000..00d82e4be
--- /dev/null
+++ b/hw/ppc440.c
@@ -0,0 +1,103 @@
+/*
+ * Qemu PowerPC 440 chip emulation
+ *
+ * Copyright 2007 IBM Corporation.
+ * Authors:
+ * Jerone Young <jyoung5@us.ibm.com>
+ * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ * Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include "hw.h"
+#include "isa.h"
+#include "ppc.h"
+#include "ppc4xx.h"
+#include "ppc440.h"
+#include "ppc405.h"
+#include "sysemu.h"
+#include "kvm.h"
+
+#define PPC440EP_PCI_CONFIG 0xeec00000
+#define PPC440EP_PCI_INTACK 0xeed00000
+#define PPC440EP_PCI_SPECIAL 0xeed00000
+#define PPC440EP_PCI_REGS 0xef400000
+#define PPC440EP_PCI_IO 0xe8000000
+#define PPC440EP_PCI_IOLEN 0x00010000
+
+#define PPC440EP_SDRAM_NR_BANKS 4
+
+static const unsigned int ppc440ep_sdram_bank_sizes[] = {
+ 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
+};
+
+CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
+ const unsigned int pci_irq_nrs[4], int do_init)
+{
+ target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS];
+ target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS];
+ CPUState *env;
+ ppc4xx_mmio_t *mmio;
+ qemu_irq *pic;
+ qemu_irq *irqs;
+ qemu_irq *pci_irqs;
+
+ env = cpu_ppc_init("440EP");
+ if (!env && kvm_enabled()) {
+ /* XXX Since qemu doesn't yet emulate 440, we just say it's a 405.
+ * Since KVM doesn't use qemu's CPU emulation it seems to be working
+ * OK. */
+ env = cpu_ppc_init("405");
+ }
+ if (!env) {
+ fprintf(stderr, "Unable to initialize CPU!\n");
+ exit(1);
+ }
+
+ ppc_dcr_init(env, NULL, NULL);
+
+ /* interrupt controller */
+ irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+ irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+ irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+ pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+
+ /* SDRAM controller */
+ memset(ram_bases, 0, sizeof(ram_bases));
+ memset(ram_sizes, 0, sizeof(ram_sizes));
+ *ram_size = ppc4xx_sdram_adjust(*ram_size, PPC440EP_SDRAM_NR_BANKS,
+ ram_bases, ram_sizes,
+ ppc440ep_sdram_bank_sizes);
+ /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
+ ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_bases,
+ ram_sizes, do_init);
+
+ /* PCI */
+ pci_irqs = qemu_malloc(sizeof(qemu_irq) * 4);
+ pci_irqs[0] = pic[pci_irq_nrs[0]];
+ pci_irqs[1] = pic[pci_irq_nrs[1]];
+ pci_irqs[2] = pic[pci_irq_nrs[2]];
+ pci_irqs[3] = pic[pci_irq_nrs[3]];
+ *pcip = ppc4xx_pci_init(env, pci_irqs,
+ PPC440EP_PCI_CONFIG,
+ PPC440EP_PCI_INTACK,
+ PPC440EP_PCI_SPECIAL,
+ PPC440EP_PCI_REGS);
+ if (!*pcip)
+ printf("couldn't create PCI controller!\n");
+
+ isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
+
+ /* MMIO -- most "miscellaneous" devices live above 0xef600000. */
+ mmio = ppc4xx_mmio_init(env, 0xef600000);
+
+ if (serial_hds[0])
+ ppc405_serial_init(env, mmio, 0x300, pic[0], serial_hds[0]);
+
+ if (serial_hds[1])
+ ppc405_serial_init(env, mmio, 0x400, pic[1], serial_hds[1]);
+
+ return env;
+}
diff --git a/hw/ppc440.h b/hw/ppc440.h
new file mode 100644
index 000000000..b6843eb85
--- /dev/null
+++ b/hw/ppc440.h
@@ -0,0 +1,20 @@
+/*
+ * Qemu PowerPC 440 board emualtion
+ *
+ * Copyright 2007 IBM Corporation.
+ * Authors: Jerone Young <jyoung5@us.ibm.com>
+ * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the GNU GPL licence version 2 or later
+ *
+ */
+
+#ifndef QEMU_PPC440_H
+#define QEMU_PPC440_H
+
+#include "hw.h"
+
+CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
+ const unsigned int pci_irq_nrs[4], int do_init);
+
+#endif
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
new file mode 100644
index 000000000..a6fc75823
--- /dev/null
+++ b/hw/ppc440_bamboo.c
@@ -0,0 +1,190 @@
+/*
+ * Qemu PowerPC 440 Bamboo board emulation
+ *
+ * Copyright 2007 IBM Corporation.
+ * Authors:
+ * Jerone Young <jyoung5@us.ibm.com>
+ * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ * Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include "config.h"
+#include "qemu-common.h"
+#include "net.h"
+#include "hw.h"
+#include "pci.h"
+#include "virtio-blk.h"
+#include "boards.h"
+#include "sysemu.h"
+#include "ppc440.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
+#include "device_tree.h"
+
+#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
+
+static void *bamboo_load_device_tree(void *addr,
+ uint32_t ramsize,
+ target_phys_addr_t initrd_base,
+ target_phys_addr_t initrd_size,
+ const char *kernel_cmdline)
+{
+ void *fdt = NULL;
+#ifdef HAVE_FDT
+ uint32_t mem_reg_property[] = { 0, 0, ramsize };
+ char *path;
+ int pathlen;
+ int ret;
+
+ pathlen = snprintf(NULL, 0, "%s/%s", bios_dir, BINARY_DEVICE_TREE_FILE) + 1;
+ path = qemu_malloc(pathlen);
+ if (path == NULL)
+ return NULL;
+
+ snprintf(path, pathlen, "%s/%s", bios_dir, BINARY_DEVICE_TREE_FILE);
+
+ fdt = load_device_tree(path, addr);
+ free(path);
+ if (fdt == NULL)
+ goto out;
+
+ /* Manipulate device tree in memory. */
+
+ ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
+ sizeof(mem_reg_property));
+ if (ret < 0)
+ fprintf(stderr, "couldn't set /memory/reg\n");
+
+ ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+ initrd_base);
+ if (ret < 0)
+ fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
+
+ ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ (initrd_base + initrd_size));
+ if (ret < 0)
+ fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
+
+ ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
+ kernel_cmdline);
+ if (ret < 0)
+ fprintf(stderr, "couldn't set /chosen/bootargs\n");
+
+ if (kvm_enabled())
+ kvmppc_fdt_update(fdt);
+
+out:
+#endif
+
+ return fdt;
+}
+
+static void bamboo_init(ram_addr_t ram_size, int vga_ram_size,
+ const char *boot_device, DisplayState *ds,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
+ NICInfo *nd;
+ PCIBus *pcibus;
+ CPUState *env;
+ uint64_t elf_entry;
+ uint64_t elf_lowaddr;
+ target_ulong entry = 0;
+ target_ulong loadaddr = 0;
+ target_long kernel_size = 0;
+ target_ulong initrd_base = 0;
+ target_long initrd_size = 0;
+ target_ulong dt_base = 0;
+ void *fdt;
+ int i;
+
+ /* Setup CPU. */
+ env = ppc440ep_init(&ram_size, &pcibus, pci_irq_nrs, 1);
+
+ if (pcibus) {
+ int unit_id = 0;
+
+ /* Add virtio block devices. */
+ while ((i = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) {
+ virtio_blk_init(pcibus, drives_table[i].bdrv);
+ unit_id++;
+ }
+
+ /* Register network interfaces. */
+ for (i = 0; i < nb_nics; i++) {
+ nd = &nd_table[i];
+ if (!nd->model) {
+ /* There are no PCI NICs on the Bamboo board, but there are
+ * PCI slots, so we can pick model whatever we want. */
+ nd->model = "e1000";
+ }
+ pci_nic_init(pcibus, nd, -1);
+ }
+ }
+
+ /* Load kernel. */
+ if (kernel_filename) {
+ kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
+ if (kernel_size < 0) {
+ kernel_size = load_elf(kernel_filename, 0, &elf_entry, &elf_lowaddr,
+ NULL);
+ entry = elf_entry;
+ loadaddr = elf_lowaddr;
+ }
+ /* XXX try again as binary */
+ if (kernel_size < 0) {
+ fprintf(stderr, "qemu: could not load kernel '%s'\n",
+ kernel_filename);
+ exit(1);
+ }
+ }
+
+ /* Load initrd. */
+ if (initrd_filename) {
+ initrd_base = kernel_size + loadaddr;
+ initrd_size = load_image(initrd_filename, phys_ram_base + initrd_base);
+
+ if (initrd_size < 0) {
+ fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+ initrd_filename);
+ exit(1);
+ }
+ }
+
+ /* If we're loading a kernel directly, we must load the device tree too. */
+ if (kernel_filename) {
+ if (initrd_base)
+ dt_base = initrd_base + initrd_size;
+ else
+ dt_base = kernel_size + loadaddr;
+
+ fdt = bamboo_load_device_tree(phys_ram_base + dt_base, ram_size,
+ initrd_base, initrd_size, kernel_cmdline);
+ if (fdt == NULL) {
+ fprintf(stderr, "couldn't load device tree\n");
+ exit(1);
+ }
+
+ /* Set initial guest state. */
+ env->gpr[1] = (16<<20) - 8;
+ env->gpr[3] = dt_base;
+ env->nip = entry;
+ /* XXX we currently depend on KVM to create some initial TLB entries. */
+ }
+
+ if (kvm_enabled())
+ kvmppc_init();
+}
+
+QEMUMachine bamboo_machine = {
+ .name = "bamboo",
+ .desc = "bamboo",
+ .init = bamboo_init,
+ .ram_require = 8<<20 | RAMSIZE_FIXED,
+};
diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h
index 4d60f6c38..25a91bdf8 100644
--- a/hw/ppc4xx.h
+++ b/hw/ppc4xx.h
@@ -51,6 +51,16 @@ enum {
qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
uint32_t dcr_base, int has_ssr, int has_vr);
+ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
+ target_phys_addr_t ram_bases[],
+ target_phys_addr_t ram_sizes[],
+ const unsigned int sdram_bank_sizes[]);
+
+void ppc4xx_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
+ target_phys_addr_t *ram_bases,
+ target_phys_addr_t *ram_sizes,
+ int do_init);
+
PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
target_phys_addr_t config_space,
target_phys_addr_t int_ack,
diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c
index ff6701191..939e0669e 100644
--- a/hw/ppc4xx_devs.c
+++ b/hw/ppc4xx_devs.c
@@ -532,3 +532,386 @@ qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
}
+
+/*****************************************************************************/
+/* SDRAM controller */
+typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
+struct ppc4xx_sdram_t {
+ uint32_t addr;
+ int nbanks;
+ target_phys_addr_t ram_bases[4];
+ target_phys_addr_t ram_sizes[4];
+ uint32_t besr0;
+ uint32_t besr1;
+ uint32_t bear;
+ uint32_t cfg;
+ uint32_t status;
+ uint32_t rtr;
+ uint32_t pmit;
+ uint32_t bcr[4];
+ uint32_t tr;
+ uint32_t ecccfg;
+ uint32_t eccesr;
+ qemu_irq irq;
+};
+
+enum {
+ SDRAM0_CFGADDR = 0x010,
+ SDRAM0_CFGDATA = 0x011,
+};
+
+/* XXX: TOFIX: some patches have made this code become inconsistent:
+ * there are type inconsistencies, mixing target_phys_addr_t, target_ulong
+ * and uint32_t
+ */
+static uint32_t sdram_bcr (target_phys_addr_t ram_base,
+ target_phys_addr_t ram_size)
+{
+ uint32_t bcr;
+
+ switch (ram_size) {
+ case (4 * 1024 * 1024):
+ bcr = 0x00000000;
+ break;
+ case (8 * 1024 * 1024):
+ bcr = 0x00020000;
+ break;
+ case (16 * 1024 * 1024):
+ bcr = 0x00040000;
+ break;
+ case (32 * 1024 * 1024):
+ bcr = 0x00060000;
+ break;
+ case (64 * 1024 * 1024):
+ bcr = 0x00080000;
+ break;
+ case (128 * 1024 * 1024):
+ bcr = 0x000A0000;
+ break;
+ case (256 * 1024 * 1024):
+ bcr = 0x000C0000;
+ break;
+ default:
+ printf("%s: invalid RAM size " PADDRX "\n", __func__, ram_size);
+ return 0x00000000;
+ }
+ bcr |= ram_base & 0xFF800000;
+ bcr |= 1;
+
+ return bcr;
+}
+
+static always_inline target_phys_addr_t sdram_base (uint32_t bcr)
+{
+ return bcr & 0xFF800000;
+}
+
+static target_ulong sdram_size (uint32_t bcr)
+{
+ target_ulong size;
+ int sh;
+
+ sh = (bcr >> 17) & 0x7;
+ if (sh == 7)
+ size = -1;
+ else
+ size = (4 * 1024 * 1024) << sh;
+
+ return size;
+}
+
+static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled)
+{
+ if (*bcrp & 0x00000001) {
+ /* Unmap RAM */
+#ifdef DEBUG_SDRAM
+ printf("%s: unmap RAM area " PADDRX " " ADDRX "\n",
+ __func__, sdram_base(*bcrp), sdram_size(*bcrp));
+#endif
+ cpu_register_physical_memory(sdram_base(*bcrp), sdram_size(*bcrp),
+ IO_MEM_UNASSIGNED);
+ }
+ *bcrp = bcr & 0xFFDEE001;
+ if (enabled && (bcr & 0x00000001)) {
+#ifdef DEBUG_SDRAM
+ printf("%s: Map RAM area " PADDRX " " ADDRX "\n",
+ __func__, sdram_base(bcr), sdram_size(bcr));
+#endif
+ cpu_register_physical_memory(sdram_base(bcr), sdram_size(bcr),
+ sdram_base(bcr) | IO_MEM_RAM);
+ }
+}
+
+static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
+{
+ int i;
+
+ for (i = 0; i < sdram->nbanks; i++) {
+ if (sdram->ram_sizes[i] != 0) {
+ sdram_set_bcr(&sdram->bcr[i],
+ sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
+ 1);
+ } else {
+ sdram_set_bcr(&sdram->bcr[i], 0x00000000, 0);
+ }
+ }
+}
+
+static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
+{
+ int i;
+
+ for (i = 0; i < sdram->nbanks; i++) {
+#ifdef DEBUG_SDRAM
+ printf("%s: Unmap RAM area " PADDRX " " ADDRX "\n",
+ __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
+#endif
+ cpu_register_physical_memory(sdram_base(sdram->bcr[i]),
+ sdram_size(sdram->bcr[i]),
+ IO_MEM_UNASSIGNED);
+ }
+}
+
+static target_ulong dcr_read_sdram (void *opaque, int dcrn)
+{
+ ppc4xx_sdram_t *sdram;
+ target_ulong ret;
+
+ sdram = opaque;
+ switch (dcrn) {
+ case SDRAM0_CFGADDR:
+ ret = sdram->addr;
+ break;
+ case SDRAM0_CFGDATA:
+ switch (sdram->addr) {
+ case 0x00: /* SDRAM_BESR0 */
+ ret = sdram->besr0;
+ break;
+ case 0x08: /* SDRAM_BESR1 */
+ ret = sdram->besr1;
+ break;
+ case 0x10: /* SDRAM_BEAR */
+ ret = sdram->bear;
+ break;
+ case 0x20: /* SDRAM_CFG */
+ ret = sdram->cfg;
+ break;
+ case 0x24: /* SDRAM_STATUS */
+ ret = sdram->status;
+ break;
+ case 0x30: /* SDRAM_RTR */
+ ret = sdram->rtr;
+ break;
+ case 0x34: /* SDRAM_PMIT */
+ ret = sdram->pmit;
+ break;
+ case 0x40: /* SDRAM_B0CR */
+ ret = sdram->bcr[0];
+ break;
+ case 0x44: /* SDRAM_B1CR */
+ ret = sdram->bcr[1];
+ break;
+ case 0x48: /* SDRAM_B2CR */
+ ret = sdram->bcr[2];
+ break;
+ case 0x4C: /* SDRAM_B3CR */
+ ret = sdram->bcr[3];
+ break;
+ case 0x80: /* SDRAM_TR */
+ ret = -1; /* ? */
+ break;
+ case 0x94: /* SDRAM_ECCCFG */
+ ret = sdram->ecccfg;
+ break;
+ case 0x98: /* SDRAM_ECCESR */
+ ret = sdram->eccesr;
+ break;
+ default: /* Error */
+ ret = -1;
+ break;
+ }
+ break;
+ default:
+ /* Avoid gcc warning */
+ ret = 0x00000000;
+ break;
+ }
+
+ return ret;
+}
+
+static void dcr_write_sdram (void *opaque, int dcrn, target_ulong val)
+{
+ ppc4xx_sdram_t *sdram;
+
+ sdram = opaque;
+ switch (dcrn) {
+ case SDRAM0_CFGADDR:
+ sdram->addr = val;
+ break;
+ case SDRAM0_CFGDATA:
+ switch (sdram->addr) {
+ case 0x00: /* SDRAM_BESR0 */
+ sdram->besr0 &= ~val;
+ break;
+ case 0x08: /* SDRAM_BESR1 */
+ sdram->besr1 &= ~val;
+ break;
+ case 0x10: /* SDRAM_BEAR */
+ sdram->bear = val;
+ break;
+ case 0x20: /* SDRAM_CFG */
+ val &= 0xFFE00000;
+ if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
+#ifdef DEBUG_SDRAM
+ printf("%s: enable SDRAM controller\n", __func__);
+#endif
+ /* validate all RAM mappings */
+ sdram_map_bcr(sdram);
+ sdram->status &= ~0x80000000;
+ } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
+#ifdef DEBUG_SDRAM
+ printf("%s: disable SDRAM controller\n", __func__);
+#endif
+ /* invalidate all RAM mappings */
+ sdram_unmap_bcr(sdram);
+ sdram->status |= 0x80000000;
+ }
+ if (!(sdram->cfg & 0x40000000) && (val & 0x40000000))
+ sdram->status |= 0x40000000;
+ else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000))
+ sdram->status &= ~0x40000000;
+ sdram->cfg = val;
+ break;
+ case 0x24: /* SDRAM_STATUS */
+ /* Read-only register */
+ break;
+ case 0x30: /* SDRAM_RTR */
+ sdram->rtr = val & 0x3FF80000;
+ break;
+ case 0x34: /* SDRAM_PMIT */
+ sdram->pmit = (val & 0xF8000000) | 0x07C00000;
+ break;
+ case 0x40: /* SDRAM_B0CR */
+ sdram_set_bcr(&sdram->bcr[0], val, sdram->cfg & 0x80000000);
+ break;
+ case 0x44: /* SDRAM_B1CR */
+ sdram_set_bcr(&sdram->bcr[1], val, sdram->cfg & 0x80000000);
+ break;
+ case 0x48: /* SDRAM_B2CR */
+ sdram_set_bcr(&sdram->bcr[2], val, sdram->cfg & 0x80000000);
+ break;
+ case 0x4C: /* SDRAM_B3CR */
+ sdram_set_bcr(&sdram->bcr[3], val, sdram->cfg & 0x80000000);
+ break;
+ case 0x80: /* SDRAM_TR */
+ sdram->tr = val & 0x018FC01F;
+ break;
+ case 0x94: /* SDRAM_ECCCFG */
+ sdram->ecccfg = val & 0x00F00000;
+ break;
+ case 0x98: /* SDRAM_ECCESR */
+ val &= 0xFFF0F000;
+ if (sdram->eccesr == 0 && val != 0)
+ qemu_irq_raise(sdram->irq);
+ else if (sdram->eccesr != 0 && val == 0)
+ qemu_irq_lower(sdram->irq);
+ sdram->eccesr = val;
+ break;
+ default: /* Error */
+ break;
+ }
+ break;
+ }
+}
+
+static void sdram_reset (void *opaque)
+{
+ ppc4xx_sdram_t *sdram;
+
+ sdram = opaque;
+ sdram->addr = 0x00000000;
+ sdram->bear = 0x00000000;
+ sdram->besr0 = 0x00000000; /* No error */
+ sdram->besr1 = 0x00000000; /* No error */
+ sdram->cfg = 0x00000000;
+ sdram->ecccfg = 0x00000000; /* No ECC */
+ sdram->eccesr = 0x00000000; /* No error */
+ sdram->pmit = 0x07C00000;
+ sdram->rtr = 0x05F00000;
+ sdram->tr = 0x00854009;
+ /* We pre-initialize RAM banks */
+ sdram->status = 0x00000000;
+ sdram->cfg = 0x00800000;
+ sdram_unmap_bcr(sdram);
+}
+
+void ppc4xx_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
+ target_phys_addr_t *ram_bases,
+ target_phys_addr_t *ram_sizes,
+ int do_init)
+{
+ ppc4xx_sdram_t *sdram;
+
+ sdram = qemu_mallocz(sizeof(ppc4xx_sdram_t));
+ if (sdram != NULL) {
+ sdram->irq = irq;
+ sdram->nbanks = nbanks;
+ memset(sdram->ram_bases, 0, 4 * sizeof(target_phys_addr_t));
+ memcpy(sdram->ram_bases, ram_bases,
+ nbanks * sizeof(target_phys_addr_t));
+ memset(sdram->ram_sizes, 0, 4 * sizeof(target_phys_addr_t));
+ memcpy(sdram->ram_sizes, ram_sizes,
+ nbanks * sizeof(target_phys_addr_t));
+ sdram_reset(sdram);
+ qemu_register_reset(&sdram_reset, sdram);
+ ppc_dcr_register(env, SDRAM0_CFGADDR,
+ sdram, &dcr_read_sdram, &dcr_write_sdram);
+ ppc_dcr_register(env, SDRAM0_CFGDATA,
+ sdram, &dcr_read_sdram, &dcr_write_sdram);
+ if (do_init)
+ sdram_map_bcr(sdram);
+ }
+}
+
+/* Fill in consecutive SDRAM banks with 'ram_size' bytes of memory.
+ *
+ * sdram_bank_sizes[] must be 0-terminated.
+ *
+ * The 4xx SDRAM controller supports a small number of banks, and each bank
+ * must be one of a small set of sizes. The number of banks and the supported
+ * sizes varies by SoC. */
+ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
+ target_phys_addr_t ram_bases[],
+ target_phys_addr_t ram_sizes[],
+ const unsigned int sdram_bank_sizes[])
+{
+ ram_addr_t ram_end = 0;
+ int i;
+ int j;
+
+ for (i = 0; i < nr_banks; i++) {
+ for (j = 0; sdram_bank_sizes[j] != 0; j++) {
+ unsigned int bank_size = sdram_bank_sizes[j];
+
+ if (bank_size <= ram_size) {
+ ram_bases[i] = ram_end;
+ ram_sizes[i] = bank_size;
+ ram_end += bank_size;
+ ram_size -= bank_size;
+ break;
+ }
+ }
+
+ if (!ram_size) {
+ /* No need to use the remaining banks. */
+ break;
+ }
+ }
+
+ if (ram_size)
+ printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n",
+ (int)(ram_end >> 20));
+
+ return ram_end;
+}
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 02655962f..c8ef97a58 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -34,6 +34,7 @@
#include "boards.h"
#define MAX_IDE_BUS 2
+#define VGA_BIOS_SIZE 65536
/* temporary frame buffer OSI calls for the video.x driver. The right
solution is to modify the driver to use VGA PCI I/Os */
@@ -116,7 +117,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
nvram_t nvram;
m48t59_t *m48t59;
int linux_boot, i;
- unsigned long bios_offset, vga_bios_offset;
+ ram_addr_t ram_offset, vga_ram_offset, bios_offset, vga_bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
PCIBus *pci_bus;
MacIONVRAMState *nvr;
@@ -132,7 +133,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
/* init CPUs */
if (cpu_model == NULL)
- cpu_model = "default";
+ cpu_model = "G3";
for (i = 0; i < smp_cpus; i++) {
env = cpu_init(cpu_model);
if (!env) {
@@ -154,10 +155,14 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
}
/* allocate RAM */
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+ ram_offset = qemu_ram_alloc(ram_size);
+ cpu_register_physical_memory(0, ram_size, ram_offset);
+
+ /* allocate VGA RAM */
+ vga_ram_offset = qemu_ram_alloc(vga_ram_size);
/* allocate and load BIOS */
- bios_offset = ram_size + vga_ram_size;
+ bios_offset = qemu_ram_alloc(BIOS_SIZE);
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
@@ -166,7 +171,6 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
cpu_abort(env, "qemu: could not load PowerPC bios '%s'\n", buf);
exit(1);
}
- bios_size = (bios_size + 0xfff) & ~0xfff;
if (bios_size > 0x00080000) {
/* As the NVRAM is located at 0xFFF04000, we cannot use 1 MB BIOSes */
cpu_abort(env, "G3BW Mac hardware can not handle 1 MB BIOS\n");
@@ -175,7 +179,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
bios_size, bios_offset | IO_MEM_ROM);
/* allocate and load VGA BIOS */
- vga_bios_offset = bios_offset + bios_size;
+ vga_bios_offset = qemu_ram_alloc(VGA_BIOS_SIZE);
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8);
if (vga_bios_size < 0) {
@@ -193,7 +197,6 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
vga_bios_size);
vga_bios_size += 8;
}
- vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff;
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
@@ -278,8 +281,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
}
pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
pci_bus = pci_grackle_init(0xfec00000, pic);
- pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
- ram_size, vga_ram_size,
+ pci_vga_init(pci_bus, ds, phys_ram_base + vga_ram_offset,
+ vga_ram_offset, vga_ram_size,
vga_bios_offset, vga_bios_size);
/* XXX: suppress that */
@@ -369,6 +372,6 @@ QEMUMachine heathrow_machine = {
.name = "g3bw",
.desc = "Heathrow based PowerMAC",
.init = ppc_heathrow_init,
- .ram_require = BIOS_SIZE + VGA_RAM_SIZE,
+ .ram_require = BIOS_SIZE + VGA_BIOS_SIZE + VGA_RAM_SIZE,
.max_cpus = MAX_CPUS,
};
diff --git a/hw/rc4030.c b/hw/rc4030.c
index 54f9adfa3..89cec6e3b 100644
--- a/hw/rc4030.c
+++ b/hw/rc4030.c
@@ -269,7 +269,7 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
static int current = 0;
target_phys_addr_t dest = 0 + dests[current];
uint8_t buf;
- current = (current + 1) % (sizeof(dests)/sizeof(dests[0]));
+ current = (current + 1) % (ARRAY_SIZE(dests));
buf = s->cache_bwin - 1;
cpu_physical_memory_rw(dest, &buf, 1, 1);
}
@@ -403,7 +403,7 @@ static void update_jazz_irq(rc4030State *s)
if (s->isr_jazz != 0) {
uint32_t irq = 0;
printf("jazz pending:");
- for (irq = 0; irq < sizeof(irq_names)/sizeof(irq_names[0]); irq++) {
+ for (irq = 0; irq < ARRAY_SIZE(irq_names); irq++) {
if (s->isr_jazz & (1 << irq)) {
printf(" %s", irq_names[irq]);
if (!(s->imr_jazz & (1 << irq))) {
diff --git a/hw/sb16.c b/hw/sb16.c
index 8a0fafe63..ad246ea3c 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -27,8 +27,6 @@
#include "isa.h"
#include "qemu-timer.h"
-#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
-
#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
/* #define DEBUG */
@@ -1440,11 +1438,11 @@ int SB16_init (AudioState *audio, qemu_irq *pic)
dolog ("warning: Could not create auxiliary timer\n");
}
- for (i = 0; i < LENOFA (dsp_write_ports); i++) {
+ for (i = 0; i < ARRAY_SIZE (dsp_write_ports); i++) {
register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s);
}
- for (i = 0; i < LENOFA (dsp_read_ports); i++) {
+ for (i = 0; i < ARRAY_SIZE (dsp_read_ports); i++) {
register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s);
}
diff --git a/hw/sh_intc.c b/hw/sh_intc.c
index 136e7dd21..9039e555d 100644
--- a/hw/sh_intc.c
+++ b/hw/sh_intc.c
@@ -17,7 +17,6 @@
//#define DEBUG_INTC_SOURCES
#define INTC_A7(x) ((x) & 0x1fffffff)
-#define INTC_ARRAY(x) (sizeof(x) / sizeof(x[0]))
void sh_intc_toggle_source(struct intc_source *source,
int enable_adj, int assert_adj)
@@ -327,7 +326,7 @@ static void sh_intc_register_source(struct intc_desc *desc,
for (i = 0; i < desc->nr_mask_regs; i++) {
struct intc_mask_reg *mr = desc->mask_regs + i;
- for (k = 0; k < INTC_ARRAY(mr->enum_ids); k++) {
+ for (k = 0; k < ARRAY_SIZE(mr->enum_ids); k++) {
if (mr->enum_ids[k] != source)
continue;
@@ -342,7 +341,7 @@ static void sh_intc_register_source(struct intc_desc *desc,
for (i = 0; i < desc->nr_prio_regs; i++) {
struct intc_prio_reg *pr = desc->prio_regs + i;
- for (k = 0; k < INTC_ARRAY(pr->enum_ids); k++) {
+ for (k = 0; k < ARRAY_SIZE(pr->enum_ids); k++) {
if (pr->enum_ids[k] != source)
continue;
@@ -357,7 +356,7 @@ static void sh_intc_register_source(struct intc_desc *desc,
for (i = 0; i < nr_groups; i++) {
struct intc_group *gr = groups + i;
- for (k = 0; k < INTC_ARRAY(gr->enum_ids); k++) {
+ for (k = 0; k < ARRAY_SIZE(gr->enum_ids); k++) {
if (gr->enum_ids[k] != source)
continue;
@@ -400,7 +399,7 @@ void sh_intc_register_sources(struct intc_desc *desc,
s = sh_intc_source(desc, gr->enum_id);
s->next_enum_id = gr->enum_ids[0];
- for (k = 1; k < INTC_ARRAY(gr->enum_ids); k++) {
+ for (k = 1; k < ARRAY_SIZE(gr->enum_ids); k++) {
if (!gr->enum_ids[k])
continue;
diff --git a/hw/sh_intc.h b/hw/sh_intc.h
index 4e36f007d..a9750ae9b 100644
--- a/hw/sh_intc.h
+++ b/hw/sh_intc.h
@@ -32,7 +32,7 @@ struct intc_prio_reg {
unsigned long value;
};
-#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
+#define _INTC_ARRAY(a) a, ARRAY_SIZE(a)
struct intc_source {
unsigned short vect;
diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c
index 55cb26ddd..2c383ca6e 100644
--- a/hw/slavio_misc.c
+++ b/hw/slavio_misc.c
@@ -324,8 +324,7 @@ static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
default:
break;
}
- MISC_DPRINTF("Read system control reg 0x" TARGET_FMT_plx " = %x\n", addr,
- ret);
+ MISC_DPRINTF("Read system control %08x\n", ret);
return ret;
}
@@ -334,8 +333,7 @@ static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
{
MiscState *s = opaque;
- MISC_DPRINTF("Write system control reg 0x" TARGET_FMT_plx " = %x\n", addr,
- val);
+ MISC_DPRINTF("Write system control %08x\n", val);
switch (addr) {
case 0:
if (val & SYS_RESET) {
@@ -372,8 +370,7 @@ static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
default:
break;
}
- MISC_DPRINTF("Read diagnostic LED reg 0x" TARGET_FMT_plx " = %x\n", addr,
- ret);
+ MISC_DPRINTF("Read diagnostic LED %04x\n", ret);
return ret;
}
@@ -382,8 +379,7 @@ static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
{
MiscState *s = opaque;
- MISC_DPRINTF("Write diagnostic LED reg 0x" TARGET_FMT_plx " = %x\n", addr,
- val);
+ MISC_DPRINTF("Write diagnostic LED %04x\n", val & 0xffff);
switch (addr) {
case 0:
s->leds = val;
diff --git a/hw/sm501.c b/hw/sm501.c
index 54d176b83..0d6b08b84 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -514,7 +514,7 @@ static uint32_t get_local_mem_size_index(uint32_t size)
uint32_t norm_size = 0;
int i, index = 0;
- for (i = 0; i < sizeof(sm501_mem_local_size)/sizeof(uint32_t); i++) {
+ for (i = 0; i < ARRAY_SIZE(sm501_mem_local_size); i++) {
uint32_t new_size = sm501_mem_local_size[i];
if (new_size >= size) {
if (norm_size == 0 || norm_size > new_size) {
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index e12216d60..354b5519a 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -45,6 +45,9 @@ do { printf("DMA: " fmt , ##args); } while (0)
#define DMA_REGS 4
#define DMA_SIZE (4 * sizeof(uint32_t))
+/* We need the mask, because one instance of the device is not page
+ aligned (ledma, start address 0x0010) */
+#define DMA_MASK (DMA_SIZE - 1)
#define DMA_VER 0xa0000000
#define DMA_INTR 1
@@ -156,7 +159,7 @@ static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr)
DMAState *s = opaque;
uint32_t saddr;
- saddr = addr >> 2;
+ saddr = (addr & DMA_MASK) >> 2;
DPRINTF("read dmareg " TARGET_FMT_plx ": 0x%8.8x\n", addr,
s->dmaregs[saddr]);
@@ -168,7 +171,7 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
DMAState *s = opaque;
uint32_t saddr;
- saddr = addr >> 2;
+ saddr = (addr & DMA_MASK) >> 2;
DPRINTF("write dmareg " TARGET_FMT_plx ": 0x%8.8x -> 0x%8.8x\n", addr,
s->dmaregs[saddr], val);
switch (saddr) {
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 271d3515b..0c1e1a24c 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -57,6 +57,9 @@
#define MAX_PILS 16
+#define TICK_INT_DIS 0x8000000000000000ULL
+#define TICK_MAX 0x7fffffffffffffffULL
+
struct hwdef {
const char * const default_cpu_model;
uint16_t machine_id;
@@ -269,11 +272,14 @@ static void main_cpu_reset(void *opaque)
CPUState *env = s->env;
cpu_reset(env);
- ptimer_set_limit(env->tick, 0x7fffffffffffffffULL, 1);
+ env->tick_cmpr = TICK_INT_DIS | 0;
+ ptimer_set_limit(env->tick, TICK_MAX, 1);
ptimer_run(env->tick, 0);
- ptimer_set_limit(env->stick, 0x7fffffffffffffffULL, 1);
+ env->stick_cmpr = TICK_INT_DIS | 0;
+ ptimer_set_limit(env->stick, TICK_MAX, 1);
ptimer_run(env->stick, 0);
- ptimer_set_limit(env->hstick, 0x7fffffffffffffffULL, 1);
+ env->hstick_cmpr = TICK_INT_DIS | 0;
+ ptimer_set_limit(env->hstick, TICK_MAX, 1);
ptimer_run(env->hstick, 0);
env->gregs[1] = 0; // Memory start
env->gregs[2] = ram_size; // Memory size
@@ -286,24 +292,29 @@ static void tick_irq(void *opaque)
{
CPUState *env = opaque;
- env->softint |= SOFTINT_TIMER;
- cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ if (!(env->tick_cmpr & TICK_INT_DIS)) {
+ env->softint |= SOFTINT_TIMER;
+ cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ }
}
static void stick_irq(void *opaque)
{
CPUState *env = opaque;
- env->softint |= SOFTINT_TIMER;
- cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ if (!(env->stick_cmpr & TICK_INT_DIS)) {
+ env->softint |= SOFTINT_STIMER;
+ cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ }
}
static void hstick_irq(void *opaque)
{
CPUState *env = opaque;
- env->softint |= SOFTINT_TIMER;
- cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ if (!(env->hstick_cmpr & TICK_INT_DIS)) {
+ cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ }
}
void cpu_tick_set_count(void *opaque, uint64_t count)
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 82005af56..f16a0a540 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -628,14 +628,13 @@ static int ndis_query(USBNetState *s, uint32_t oid,
uint8_t *inbuf, unsigned int inlen, uint8_t *outbuf,
size_t outlen)
{
- unsigned int i, count;
+ unsigned int i;
switch (oid) {
/* general oids (table 4-1) */
/* mandatory */
case OID_GEN_SUPPORTED_LIST:
- count = sizeof(oid_supported_list) / sizeof(uint32_t);
- for (i = 0; i < count; i++)
+ for (i = 0; i < ARRAY_SIZE(oid_supported_list); i++)
((le32 *) outbuf)[i] = cpu_to_le32(oid_supported_list[i]);
return sizeof(oid_supported_list);
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index da2e83586..ef8f59181 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -179,7 +179,7 @@ static int iov_fill(struct iovec *iov, int iovcnt, const void *buf, int count)
}
static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
- const void *buf, int size, int hdr_len)
+ const void *buf, size_t size, size_t hdr_len)
{
struct virtio_net_hdr *hdr = iov[0].iov_base;
int offset = 0;
@@ -208,7 +208,7 @@ static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
{
VirtIONet *n = opaque;
struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;
- int hdr_len, offset, i;
+ size_t hdr_len, offset, i;
if (!do_virtio_net_can_receive(n, size))
return;
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index f7be907a3..e30d03fde 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -817,7 +817,7 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
s->guest = value;
#ifdef VERBOSE
if (value >= GUEST_OS_BASE && value < GUEST_OS_BASE +
- sizeof(vmsvga_guest_id) / sizeof(*vmsvga_guest_id))
+ ARRAY_SIZE(vmsvga_guest_id))
printf("%s: guest runs %s.\n", __FUNCTION__,
vmsvga_guest_id[value - GUEST_OS_BASE]);
#endif
diff --git a/kvm-all.c b/kvm-all.c
index dad80df58..9fb295ce6 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -141,6 +141,21 @@ err:
return ret;
}
+int kvm_sync_vcpus(void)
+{
+ CPUState *env;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ int ret;
+
+ ret = kvm_arch_put_registers(env);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* dirty pages logging control
*/
@@ -639,9 +654,9 @@ int kvm_vcpu_ioctl(CPUState *env, int type, ...)
int kvm_has_sync_mmu(void)
{
+#ifdef KVM_CAP_SYNC_MMU
KVMState *s = kvm_state;
-#ifdef KVM_CAP_SYNC_MMU
if (kvm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_SYNC_MMU) > 0)
return 1;
#endif
diff --git a/kvm.h b/kvm.h
index 537f41348..eeed3dcaa 100644
--- a/kvm.h
+++ b/kvm.h
@@ -33,6 +33,7 @@ struct kvm_run;
int kvm_init(int smp_cpus);
int kvm_init_vcpu(CPUState *env);
+int kvm_sync_vcpus(void);
int kvm_cpu_exec(CPUState *env);
diff --git a/libfdt_env.h b/libfdt_env.h
new file mode 100644
index 000000000..e154b8ef1
--- /dev/null
+++ b/libfdt_env.h
@@ -0,0 +1,41 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corp. 2008
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ */
+
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <endian.h>
+#include <byteswap.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define fdt32_to_cpu(x) (x)
+#define cpu_to_fdt32(x) (x)
+#define fdt64_to_cpu(x) (x)
+#define cpu_to_fdt64(x) (x)
+#else
+#define fdt32_to_cpu(x) (bswap_32((x)))
+#define cpu_to_fdt32(x) (bswap_32((x)))
+#define fdt64_to_cpu(x) (bswap_64((x)))
+#define cpu_to_fdt64(x) (bswap_64((x)))
+#endif
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/linux-user/main.c b/linux-user/main.c
index 3d2d4e5d5..cc9f53dea 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -163,6 +163,7 @@ void fork_end(int child)
pthread_cond_init(&exclusive_cond, NULL);
pthread_cond_init(&exclusive_resume, NULL);
pthread_mutex_init(&tb_lock, NULL);
+ gdbserver_fork(thread_env);
} else {
pthread_mutex_unlock(&exclusive_lock);
pthread_mutex_unlock(&tb_lock);
@@ -255,6 +256,9 @@ void fork_start(void)
void fork_end(int child)
{
+ if (child) {
+ gdbserver_fork(thread_env);
+ }
}
#endif
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 00a941e33..ead1112ac 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -24,6 +24,8 @@
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
+#include <linux/mman.h>
+#include <linux/unistd.h>
#include "qemu.h"
#include "qemu-common.h"
@@ -546,10 +548,11 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
mmap_lock();
-#if defined(MREMAP_FIXED)
if (flags & MREMAP_FIXED)
- host_addr = mremap(g2h(old_addr), old_size, new_size,
- flags, new_addr);
+ host_addr = (void *) syscall(__NR_mremap, g2h(old_addr),
+ old_size, new_size,
+ flags,
+ new_addr);
else if (flags & MREMAP_MAYMOVE) {
abi_ulong mmap_start;
@@ -559,11 +562,11 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
errno = ENOMEM;
host_addr = MAP_FAILED;
} else
- host_addr = mremap(g2h(old_addr), old_size, new_size,
- flags | MREMAP_FIXED, g2h(mmap_start));
- } else
-#endif
- {
+ host_addr = (void *) syscall(__NR_mremap, g2h(old_addr),
+ old_size, new_size,
+ flags | MREMAP_FIXED,
+ g2h(mmap_start));
+ } else {
host_addr = mremap(g2h(old_addr), old_size, new_size, flags);
/* Check if address fits target address space */
if ((unsigned long)host_addr + new_size > (abi_ulong)-1) {
diff --git a/linux-user/signal.c b/linux-user/signal.c
index e0f6aaf73..5e3052209 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -264,6 +264,26 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
(void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
}
+static int fatal_signal (int sig)
+{
+ switch (sig) {
+ case TARGET_SIGCHLD:
+ case TARGET_SIGURG:
+ case TARGET_SIGWINCH:
+ /* Ignored by default. */
+ return 0;
+ case TARGET_SIGCONT:
+ case TARGET_SIGSTOP:
+ case TARGET_SIGTSTP:
+ case TARGET_SIGTTIN:
+ case TARGET_SIGTTOU:
+ /* Job control signals. */
+ return 0;
+ default:
+ return 1;
+ }
+}
+
void signal_init(void)
{
struct sigaction act;
@@ -298,10 +318,12 @@ void signal_init(void)
}
/* If there's already a handler installed then something has
gone horribly wrong, so don't even try to handle that case. */
- /* Install some handlers for our own use. */
- if (host_sig == SIGSEGV || host_sig == SIGBUS) {
+ /* Install some handlers for our own use. We need at least
+ SIGSEGV and SIGBUS, to detect exceptions. We can not just
+ trap all signals because it affects syscall interrupt
+ behavior. But do trap all default-fatal signals. */
+ if (fatal_signal (i))
sigaction(host_sig, &act, NULL);
- }
}
}
@@ -332,6 +354,7 @@ static void __attribute((noreturn)) force_sig(int sig)
fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
sig, strsignal(host_sig));
#if 1
+ gdb_signalled(thread_env, sig);
_exit(-host_sig);
#else
{
@@ -353,14 +376,16 @@ int queue_signal(CPUState *env, int sig, target_siginfo_t *info)
struct emulated_sigtable *k;
struct sigqueue *q, **pq;
abi_ulong handler;
+ int queue;
#if defined(DEBUG_SIGNAL)
fprintf(stderr, "queue_signal: sig=%d\n",
sig);
#endif
k = &ts->sigtab[sig - 1];
+ queue = gdb_queuesig ();
handler = sigact_table[sig - 1]._sa_handler;
- if (handler == TARGET_SIG_DFL) {
+ if (!queue && handler == TARGET_SIG_DFL) {
if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
kill(getpid(),SIGSTOP);
return 0;
@@ -374,10 +399,10 @@ int queue_signal(CPUState *env, int sig, target_siginfo_t *info)
} else {
return 0; /* indicate ignored */
}
- } else if (handler == TARGET_SIG_IGN) {
+ } else if (!queue && handler == TARGET_SIG_IGN) {
/* ignore signal */
return 0;
- } else if (handler == TARGET_SIG_ERR) {
+ } else if (!queue && handler == TARGET_SIG_ERR) {
force_sig(sig);
} else {
pq = &k->first;
@@ -417,7 +442,8 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
/* the CPU emulator uses some host signals to detect exceptions,
we we forward to it some signals */
- if (host_signum == SIGSEGV || host_signum == SIGBUS) {
+ if ((host_signum == SIGSEGV || host_signum == SIGBUS)
+ && info->si_code == SI_KERNEL) {
if (cpu_signal_handler(host_signum, info, puc))
return;
}
@@ -544,7 +570,10 @@ int do_sigaction(int sig, const struct target_sigaction *act,
if (k->_sa_handler == TARGET_SIG_IGN) {
act1.sa_sigaction = (void *)SIG_IGN;
} else if (k->_sa_handler == TARGET_SIG_DFL) {
- act1.sa_sigaction = (void *)SIG_DFL;
+ if (fatal_signal (sig))
+ act1.sa_sigaction = host_signal_handler;
+ else
+ act1.sa_sigaction = (void *)SIG_DFL;
} else {
act1.sa_sigaction = host_signal_handler;
}
@@ -3107,17 +3136,21 @@ void process_pending_signals(CPUState *cpu_env)
sig = gdb_handlesig (cpu_env, sig);
if (!sig) {
- fprintf (stderr, "Lost signal\n");
- abort();
+ sa = NULL;
+ handler = TARGET_SIG_IGN;
+ } else {
+ sa = &sigact_table[sig - 1];
+ handler = sa->_sa_handler;
}
- sa = &sigact_table[sig - 1];
- handler = sa->_sa_handler;
if (handler == TARGET_SIG_DFL) {
- /* default handler : ignore some signal. The other are fatal */
- if (sig != TARGET_SIGCHLD &&
- sig != TARGET_SIGURG &&
- sig != TARGET_SIGWINCH) {
+ /* default handler : ignore some signal. The other are job control or fatal */
+ if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) {
+ kill(getpid(),SIGSTOP);
+ } else if (sig != TARGET_SIGCHLD &&
+ sig != TARGET_SIGURG &&
+ sig != TARGET_SIGWINCH &&
+ sig != TARGET_SIGCONT) {
force_sig(sig);
}
} else if (handler == TARGET_SIG_IGN) {
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 116726c55..b4caffe1b 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -263,7 +263,7 @@ static const struct syscallname scnames[] = {
#include "strace.list"
};
-static int nsyscalls = sizeof(scnames)/sizeof(struct syscallname);
+static int nsyscalls = ARRAY_SIZE(scnames);
/*
* The public interface to this module.
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 73427abb3..bd60494bc 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2960,17 +2960,17 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
return -EINVAL;
fork_start();
ret = fork();
-#if defined(USE_NPTL)
- /* There is a race condition here. The parent process could
- theoretically read the TID in the child process before the child
- tid is set. This would require using either ptrace
- (not implemented) or having *_tidptr to point at a shared memory
- mapping. We can't repeat the spinlock hack used above because
- the child process gets its own copy of the lock. */
if (ret == 0) {
+ /* Child Process. */
cpu_clone_regs(env, newsp);
fork_end(1);
- /* Child Process. */
+#if defined(USE_NPTL)
+ /* There is a race condition here. The parent process could
+ theoretically read the TID in the child process before the child
+ tid is set. This would require using either ptrace
+ (not implemented) or having *_tidptr to point at a shared memory
+ mapping. We can't repeat the spinlock hack used above because
+ the child process gets its own copy of the lock. */
if (flags & CLONE_CHILD_SETTID)
put_user_u32(gettid(), child_tidptr);
if (flags & CLONE_PARENT_SETTID)
@@ -2979,14 +2979,10 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
if (flags & CLONE_SETTLS)
cpu_set_tls (env, newtls);
/* TODO: Implement CLONE_CHILD_CLEARTID. */
+#endif
} else {
fork_end(0);
}
-#else
- if (ret == 0) {
- cpu_clone_regs(env, newsp);
- }
-#endif
}
return ret;
}
diff --git a/mips-dis.c b/mips-dis.c
index 5b0b247b3..10b0fead4 100644
--- a/mips-dis.c
+++ b/mips-dis.c
@@ -3272,7 +3272,7 @@ choose_arch_by_number (unsigned long mach)
return c;
}
-void
+static void
set_default_mips_dis_options (struct disassemble_info *info)
{
const struct mips_arch_choice *chosen_arch;
@@ -3321,7 +3321,7 @@ set_default_mips_dis_options (struct disassemble_info *info)
#endif
}
-void
+static void
parse_mips_dis_option (const char *option, unsigned int len)
{
unsigned int i, optionlen, vallen;
@@ -4809,7 +4809,6 @@ print_mips16_insn_arg (char type,
abort ();
}
}
-#endif
void
print_mips_disassembler_options (FILE *stream)
@@ -4863,3 +4862,4 @@ with the -M switch (multiple options should be separated by commas):\n"));
fprintf (stream, _("\n"));
}
+#endif
diff --git a/monitor.c b/monitor.c
index 0fa8547cd..6cbab46b8 100644
--- a/monitor.c
+++ b/monitor.c
@@ -254,6 +254,13 @@ static void do_info_name(void)
term_printf("%s\n", qemu_name);
}
+#if defined(TARGET_I386)
+static void do_info_hpet(void)
+{
+ term_printf("HPET is %s by QEMU\n", (no_hpet) ? "disabled" : "enabled");
+}
+#endif
+
static void do_info_uuid(void)
{
term_printf(UUID_FMT "\n", qemu_uuid[0], qemu_uuid[1], qemu_uuid[2],
@@ -1421,6 +1428,15 @@ static void do_inject_nmi(int cpu_index)
}
#endif
+static void do_info_status(void)
+{
+ if (vm_running)
+ term_printf("VM status: running\n");
+ else
+ term_printf("VM status: paused\n");
+}
+
+
static void do_balloon(int value)
{
ram_addr_t target = value;
@@ -1568,6 +1584,8 @@ static const term_cmd_t info_cmds[] = {
"", "show virtual to physical memory mappings", },
{ "mem", "", mem_info,
"", "show the active virtual memory mappings", },
+ { "hpet", "", do_info_hpet,
+ "", "show state of HPET", },
#endif
{ "jit", "", do_info_jit,
"", "show dynamic compiler info", },
@@ -1585,6 +1603,8 @@ static const term_cmd_t info_cmds[] = {
"", "show capture information" },
{ "snapshots", "", do_info_snapshots,
"", "show the currently saved VM snapshots" },
+ { "status", "", do_info_status,
+ "", "show the current VM status (running|paused)" },
{ "pcmcia", "", pcmcia_info,
"", "show guest PCMCIA status" },
{ "mice", "", do_info_mice,
diff --git a/net.c b/net.c
index 926dee22e..ee6619372 100644
--- a/net.c
+++ b/net.c
@@ -122,14 +122,6 @@
// FIXME: #include "qemu-kvm.h"
-#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
-#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
-#ifdef __sun__
-#define SMBD_COMMAND "/usr/sfw/sbin/smbd"
-#else
-#define SMBD_COMMAND "/usr/sbin/smbd"
-#endif
-
static VLANState *first_vlan;
/***********************************************************/
@@ -376,20 +368,19 @@ int qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size)
return ret;
}
-
static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
- int iovcnt)
+ int iovcnt)
{
- char buffer[4096];
+ uint8_t buffer[4096];
size_t offset = 0;
int i;
for (i = 0; i < iovcnt; i++) {
- size_t len;
+ size_t len;
- len = MIN(sizeof(buffer) - offset, iov[i].iov_len);
- memcpy(buffer + offset, iov[i].iov_base, len);
- offset += len;
+ len = MIN(sizeof(buffer) - offset, iov[i].iov_len);
+ memcpy(buffer + offset, iov[i].iov_base, len);
+ offset += len;
}
vc->fd_read(vc->opaque, buffer, offset);
@@ -398,24 +389,24 @@ static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
}
ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov,
- int iovcnt)
+ int iovcnt)
{
VLANState *vlan = vc1->vlan;
VLANClientState *vc;
ssize_t max_len = 0;
for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
- ssize_t len = 0;
+ ssize_t len = 0;
- if (vc == vc1)
- continue;
+ if (vc == vc1)
+ continue;
- if (vc->fd_readv)
- len = vc->fd_readv(vc->opaque, iov, iovcnt);
- else if (vc->fd_read)
- len = vc_sendv_compat(vc, iov, iovcnt);
+ if (vc->fd_readv)
+ len = vc->fd_readv(vc->opaque, iov, iovcnt);
+ else if (vc->fd_read)
+ len = vc_sendv_compat(vc, iov, iovcnt);
- max_len = MAX(max_len, len);
+ max_len = MAX(max_len, len);
}
return max_len;
@@ -652,8 +643,9 @@ typedef struct TAPState {
unsigned int using_vnet_hdr : 1;
} TAPState;
-static ssize_t tap_writev(void *opaque, const struct iovec *iov,
- int iovcnt)
+#ifdef HAVE_IOVEC
+static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov,
+ int iovcnt)
{
TAPState *s = opaque;
ssize_t len;
@@ -664,31 +656,8 @@ static ssize_t tap_writev(void *opaque, const struct iovec *iov,
return len;
}
-
-static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov,
- int iovcnt)
-{
-#ifdef IFF_VNET_HDR
- TAPState *s = opaque;
-
- if (s->has_vnet_hdr && !s->using_vnet_hdr) {
- struct iovec *iov_copy;
- struct virtio_net_hdr hdr = { 0, };
-
- iov_copy = alloca(sizeof(struct iovec) * (iovcnt + 1));
-
- iov_copy[0].iov_base = &hdr;
- iov_copy[0].iov_len = sizeof(hdr);
-
- memcpy(&iov_copy[1], iov, sizeof(struct iovec) * iovcnt);
-
- return tap_writev(opaque, iov_copy, iovcnt + 1);
- }
#endif
- return tap_writev(opaque, iov, iovcnt);
-}
-
static void tap_receive(void *opaque, const uint8_t *buf, int size)
{
struct iovec iov[2];
@@ -709,7 +678,7 @@ static void tap_receive(void *opaque, const uint8_t *buf, int size)
iov[i].iov_len = size;
i++;
- tap_writev(opaque, iov, i);
+ tap_receive_iov(opaque, iov, i);
}
static int tap_can_send(void *opaque)
@@ -865,7 +834,9 @@ static TAPState *net_tap_fd_init(VLANState *vlan, int fd, int vnet_hdr)
s->fd = fd;
s->has_vnet_hdr = vnet_hdr != 0;
s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s);
+#ifdef HAVE_IOVEC
s->vc->fd_readv = tap_receive_iov;
+#endif
#ifdef TUNSETOFFLOAD
s->vc->set_offload = tap_set_offload;
#endif
diff --git a/net.h b/net.h
index ff11c910b..91324dfc9 100644
--- a/net.h
+++ b/net.h
@@ -1,7 +1,7 @@
#ifndef QEMU_NET_H
#define QEMU_NET_H
-#include <sys/uio.h>
+#include "qemu-common.h"
/* VLANs support */
@@ -38,9 +38,9 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan,
void *opaque);
void qemu_del_vlan_client(VLANClientState *vc);
int qemu_can_send_packet(VLANClientState *vc);
-int qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov,
- int iovcnt);
+ int iovcnt);
+int qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
void qemu_handler_true(void *opaque);
void do_info_network(void);
@@ -94,4 +94,12 @@ void net_cleanup(void);
int slirp_is_inited(void);
void net_client_check(void);
+#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
+#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
+#ifdef __sun__
+#define SMBD_COMMAND "/usr/sfw/sbin/smbd"
+#else
+#define SMBD_COMMAND "/usr/sbin/smbd"
+#endif
+
#endif
diff --git a/pc-bios/README b/pc-bios/README
index ac8fc4726..665bd7d59 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -1,8 +1,35 @@
-- The PC BIOS comes from the Bochs project
- (http://bochs.sourceforge.net/). A patch from bios.diff was applied.
+- The PC BIOS comes from the Bochs project (http://bochs.sourceforge.net/).
+ The patches in bios-pq have been applied. The binary is based on the revision
+ in bios-pq/HEAD with the patches in bios-pq/series applied. The git repo
+ that HEAD refers to is located at
+ git://git.kernel.org/pub/scm/virt/bochs/bochs.git
+
+ To build these use the following instructions:
+ using guilt:
+ $ export QEMUSRC=/path/to/qemu/svn
+ $ git clone git://git.kernel.org/pub/scm/virt/bochs/bochs.git
+ $ cd bochs
+ $ git checkout -b qemu-bios $(cat $QEMUSRC/pc-bios/bios-pq/HEAD)
+
+ $ mkdir -p .git/patches
+ $ ln -s $QEMUSRC/pc-bios/bios-pq .git/patches/qemu-bios
+ $ touch .git/patches/qemu-bios/status
+ $ guilt push -a
+ $ ./configure
+ $ cd bios
+ $ make
+ $ cp BIOS-bochs-latest $QEMUSRC/pc-bios/bios.bin
+
+ or alternatively (after the git checkout):
+ $ for p in $(cat $QEMUSRC/pc-bios/bios-pq/series); do git am $p; done
+ $ ./configure
+ $ make bios
- The VGA BIOS and the Cirrus VGA BIOS come from the LGPL VGA bios
- project (http://www.nongnu.org/vgabios/).
+ project (http://www.nongnu.org/vgabios/). The binary is based on the revision
+ in vgabios-pq/HEAD with the patches in vgabios-pq/series applied. The git
+ repo that HEAD refers to is located at
+ git://git.kernel.org/pub/scm/virt/vgabios/vgabios.git
- The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is
available at http://perso.magic.fr/l_indien/OpenHackWare/index.htm.
diff --git a/pc-bios/bamboo.dtb b/pc-bios/bamboo.dtb
new file mode 100644
index 000000000..c78e2544c
--- /dev/null
+++ b/pc-bios/bamboo.dtb
Binary files differ
diff --git a/pc-bios/bamboo.dts b/pc-bios/bamboo.dts
new file mode 100644
index 000000000..655442ca6
--- /dev/null
+++ b/pc-bios/bamboo.dts
@@ -0,0 +1,234 @@
+/*
+ * Device Tree Source for AMCC Bamboo
+ *
+ * Copyright (c) 2006, 2007 IBM Corp.
+ * Josh Boyer <jwboyer@linux.vnet.ibm.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ model = "amcc,bamboo";
+ compatible = "amcc,bamboo";
+ dcr-parent = <&/cpus/cpu@0>;
+
+ aliases {
+ serial0 = &UART0;
+ serial1 = &UART1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ model = "PowerPC,440EP";
+ reg = <0>;
+ clock-frequency = <1fca0550>;
+ timebase-frequency = <017d7840>;
+ i-cache-line-size = <20>;
+ d-cache-line-size = <20>;
+ i-cache-size = <8000>;
+ d-cache-size = <8000>;
+ dcr-controller;
+ dcr-access-method = "native";
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0 9000000>;
+ };
+
+ UIC0: interrupt-controller0 {
+ compatible = "ibm,uic-440ep","ibm,uic";
+ interrupt-controller;
+ cell-index = <0>;
+ dcr-reg = <0c0 009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ };
+/*
+ UIC1: interrupt-controller1 {
+ compatible = "ibm,uic-440ep","ibm,uic";
+ interrupt-controller;
+ cell-index = <1>;
+ dcr-reg = <0d0 009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <1e 4 1f 4>;
+ interrupt-parent = <&UIC0>;
+ };
+*/
+
+ SDR0: sdr {
+ compatible = "ibm,sdr-440ep";
+ dcr-reg = <00e 002>;
+ };
+
+ CPR0: cpr {
+ compatible = "ibm,cpr-440ep";
+ dcr-reg = <00c 002>;
+ };
+
+ plb {
+ compatible = "ibm,plb-440ep", "ibm,plb-440gp", "ibm,plb4";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges;
+ clock-frequency = <07f28154>;
+
+ SDRAM0: sdram {
+ compatible = "ibm,sdram-440ep", "ibm,sdram-405gp";
+ dcr-reg = <010 2>;
+ };
+
+ DMA0: dma {
+ compatible = "ibm,dma-440ep", "ibm,dma-440gp";
+ dcr-reg = <100 027>;
+ };
+
+ POB0: opb {
+ compatible = "ibm,opb-440ep", "ibm,opb-440gp", "ibm,opb";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /* Bamboo is oddball in the 44x world and doesn't use the ERPN
+ * bits.
+ */
+ ranges = <00000000 0 00000000 80000000
+ 80000000 0 80000000 80000000>;
+ /* interrupt-parent = <&UIC1>; */
+ interrupts = <7 4>;
+ clock-frequency = <03f940aa>;
+
+ EBC0: ebc {
+ compatible = "ibm,ebc-440ep", "ibm,ebc-440gp", "ibm,ebc";
+ dcr-reg = <012 2>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-frequency = <03f940aa>;
+ interrupts = <5 1>;
+ /* interrupt-parent = <&UIC1>; */
+ };
+
+ UART0: serial@ef600300 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <ef600300 8>;
+ virtual-reg = <ef600300>;
+ clock-frequency = <00a8c000>;
+ current-speed = <1c200>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0 4>;
+ };
+
+ UART1: serial@ef600400 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <ef600400 8>;
+ virtual-reg = <ef600400>;
+ clock-frequency = <00a8c000>;
+ current-speed = <0>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <1 4>;
+ };
+/*
+ UART2: serial@ef600500 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <ef600500 8>;
+ virtual-reg = <ef600500>;
+ clock-frequency = <0>;
+ current-speed = <0>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <3 4>;
+ };
+
+ UART3: serial@ef600600 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <ef600600 8>;
+ virtual-reg = <ef600600>;
+ clock-frequency = <0>;
+ current-speed = <0>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <4 4>;
+ };
+
+*/
+ IIC0: i2c@ef600700 {
+ device_type = "i2c";
+ compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic";
+ reg = <ef600700 14>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <2 4>;
+ };
+
+ IIC1: i2c@ef600800 {
+ device_type = "i2c";
+ compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic";
+ reg = <ef600800 14>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <7 4>;
+ };
+
+ ZMII0: emac-zmii@ef600d00 {
+ device_type = "zmii-interface";
+ compatible = "ibm,zmii-440ep", "ibm,zmii-440gp", "ibm,zmii";
+ reg = <ef600d00 c>;
+ };
+
+ };
+
+ PCI0: pci@ec000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb440ep-pci", "ibm,plb-pci";
+ primary;
+ reg = <0 eec00000 8 /* Config space access */
+ 0 eed00000 4 /* IACK */
+ 0 eed00000 4 /* Special cycle */
+ 0 ef400000 40>; /* Internal registers */
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed. Chip supports a second
+ * IO range but we don't use it for now
+ */
+ ranges = <02000000 0 a0000000 0 a0000000 0 20000000
+ 01000000 0 00000000 0 e8000000 0 00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <42000000 0 0 0 0 0 80000000>;
+
+ /* Bamboo has all 4 IRQ pins tied together per slot */
+ interrupt-map-mask = <f800 0 0 0>;
+ interrupt-map = <
+ /* IDSEL 1 */
+ 0800 0 0 0 &UIC0 1c 8
+
+ /* IDSEL 2 */
+ 1000 0 0 0 &UIC0 1b 8
+
+ /* IDSEL 3 */
+ 1800 0 0 0 &UIC0 1a 8
+
+ /* IDSEL 4 */
+ 2000 0 0 0 &UIC0 19 8
+ >;
+ };
+
+ };
+
+ chosen {
+ linux,stdout-path = "/plb/opb/serial@ef600300";
+ };
+};
diff --git a/pc-bios/bios-pq/0001_bx-qemu.patch b/pc-bios/bios-pq/0001_bx-qemu.patch
new file mode 100644
index 000000000..ffca6b9ae
--- /dev/null
+++ b/pc-bios/bios-pq/0001_bx-qemu.patch
@@ -0,0 +1,11 @@
+--- bochs-2.3.7.orig/bios/rombios.h
++++ bochs-2.3.7/bios/rombios.h
+@@ -19,7 +19,7 @@
+ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ /* define it to include QEMU specific code */
+-//#define BX_QEMU
++#define BX_QEMU
+
+ #ifndef LEGACY
+ # define BX_ROMBIOS32 1
diff --git a/pc-bios/bios.diff b/pc-bios/bios-pq/0002_e820-high-mem.patch
index da510db80..2886e8566 100644
--- a/pc-bios/bios.diff
+++ b/pc-bios/bios-pq/0002_e820-high-mem.patch
@@ -1,17 +1,16 @@
---- bochs-2.3.7.orig/bios/rombios.h
-+++ bochs-2.3.7/bios/rombios.h
-@@ -19,7 +19,7 @@
- // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
- /* define it to include QEMU specific code */
--//#define BX_QEMU
-+#define BX_QEMU
-
- #ifndef LEGACY
- # define BX_ROMBIOS32 1
---- bochs-2.3.7.orig/bios/rombios.c
-+++ bochs-2.3.7/bios/rombios.c
-@@ -4404,22 +4404,25 @@
+From: Izik Eidus <izike@qumranet.com>
+
+add support to memory above the pci hole
+
+the new memory region is mapped after address 0x100000000,
+the bios take the size of the memory after the 0x100000000 from
+three new cmos bytes.
+
+diff --git a/bios/rombios.c b/bios/rombios.c
+index 1be0816..b70f249 100644
+--- a/bios/rombios.c
++++ b/bios/rombios.c
+@@ -4442,22 +4442,25 @@ BX_DEBUG_INT15("case default:\n");
#endif // BX_USE_PS2_MOUSE
@@ -40,7 +39,7 @@
write_word(ES, DI+14, 0x0000);
write_word(ES, DI+16, type);
-@@ -4432,7 +4435,9 @@
+@@ -4470,7 +4473,9 @@ int15_function32(regs, ES, DS, FLAGS)
Bit16u ES, DS, FLAGS;
{
Bit32u extended_memory_size=0; // 64bits long
@@ -50,7 +49,7 @@
BX_DEBUG_INT15("int15 AX=%04x\n",regs.u.r16.ax);
-@@ -4506,11 +4511,18 @@
+@@ -4544,11 +4549,18 @@ ASM_END
extended_memory_size += (1L * 1024 * 1024);
}
@@ -65,21 +64,21 @@
{
case 0:
set_e820_range(ES, regs.u.r16.di,
-- 0x0000000L, 0x0009fc00L, 1);
-+ 0x0000000L, 0x0009fc00L, 0, 0, 1);
+- 0x0000000L, 0x0009f000L, 1);
++ 0x0000000L, 0x0009f000L, 0, 0, 1);
regs.u.r32.ebx = 1;
regs.u.r32.eax = 0x534D4150;
regs.u.r32.ecx = 0x14;
-@@ -4519,7 +4531,7 @@
+@@ -4557,7 +4569,7 @@ ASM_END
break;
case 1:
set_e820_range(ES, regs.u.r16.di,
-- 0x0009fc00L, 0x000a0000L, 2);
-+ 0x0009fc00L, 0x000a0000L, 0, 0, 2);
+- 0x0009f000L, 0x000a0000L, 2);
++ 0x0009f000L, 0x000a0000L, 0, 0, 2);
regs.u.r32.ebx = 2;
regs.u.r32.eax = 0x534D4150;
regs.u.r32.ecx = 0x14;
-@@ -4528,7 +4540,7 @@
+@@ -4566,7 +4578,7 @@ ASM_END
break;
case 2:
set_e820_range(ES, regs.u.r16.di,
@@ -88,7 +87,7 @@
regs.u.r32.ebx = 3;
regs.u.r32.eax = 0x534D4150;
regs.u.r32.ecx = 0x14;
-@@ -4539,7 +4551,7 @@
+@@ -4577,7 +4589,7 @@ ASM_END
#if BX_ROMBIOS32
set_e820_range(ES, regs.u.r16.di,
0x00100000L,
@@ -97,7 +96,7 @@
regs.u.r32.ebx = 4;
#else
set_e820_range(ES, regs.u.r16.di,
-@@ -4555,7 +4567,7 @@
+@@ -4593,7 +4605,7 @@ ASM_END
case 4:
set_e820_range(ES, regs.u.r16.di,
extended_memory_size - ACPI_DATA_SIZE,
@@ -106,7 +105,7 @@
regs.u.r32.ebx = 5;
regs.u.r32.eax = 0x534D4150;
regs.u.r32.ecx = 0x14;
-@@ -4565,7 +4577,20 @@
+@@ -4603,7 +4615,20 @@ ASM_END
case 5:
/* 256KB BIOS area at the end of 4 GB */
set_e820_range(ES, regs.u.r16.di,
@@ -128,18 +127,3 @@
regs.u.r32.ebx = 0;
regs.u.r32.eax = 0x534D4150;
regs.u.r32.ecx = 0x14;
---- bochs-2.3.7.orig/bios/rombios32.c
-+++ bochs-2.3.7/bios/rombios32.c
-@@ -479,7 +479,12 @@
- sipi_vector = AP_BOOT_ADDR >> 12;
- writel(APIC_BASE + APIC_ICR_LOW, 0x000C4600 | sipi_vector);
-
-+#ifndef BX_QEMU
- delay_ms(10);
-+#else
-+ while (cmos_readb(0x5f) + 1 != readw((void *)CPU_COUNT_ADDR))
-+ ;
-+#endif
-
- smp_cpus = readw((void *)CPU_COUNT_ADDR);
- }
diff --git a/pc-bios/bios-pq/0003_smp-startup-poll.patch b/pc-bios/bios-pq/0003_smp-startup-poll.patch
new file mode 100644
index 000000000..cd1a3ff03
--- /dev/null
+++ b/pc-bios/bios-pq/0003_smp-startup-poll.patch
@@ -0,0 +1,21 @@
+From: Avi Kivity <avi@qumranet.com>
+
+instead of timing out, wait until all cpus are up
+
+diff --git a/bios/rombios32.c b/bios/rombios32.c
+index ef98a41..05ba40d 100644
+--- a/bios/rombios32.c
++++ b/bios/rombios32.c
+@@ -512,7 +512,12 @@ void smp_probe(void)
+ sipi_vector = AP_BOOT_ADDR >> 12;
+ writel(APIC_BASE + APIC_ICR_LOW, 0x000C4600 | sipi_vector);
+
++#ifndef BX_QEMU
+ delay_ms(10);
++#else
++ while (cmos_readb(0x5f) + 1 != readw(&smp_cpus))
++ ;
++#endif
+ }
+ BX_INFO("Found %d cpu(s)\n", readw(&smp_cpus));
+ }
diff --git a/pc-bios/bios-pq/0005_hpet.patch b/pc-bios/bios-pq/0005_hpet.patch
new file mode 100644
index 000000000..9347cb501
--- /dev/null
+++ b/pc-bios/bios-pq/0005_hpet.patch
@@ -0,0 +1,190 @@
+BOCHS BIOS changes to support HPET in QEMU.
+
+Signed-off-by Beth Kon <eak@us.ibm.com>
+
+Index: bochs-2.3.7/bios/acpi-dsdt.dsl
+===================================================================
+--- bochs-2.3.7.orig/bios/acpi-dsdt.dsl 2008-10-15 12:39:14.000000000 -0500
++++ bochs-2.3.7/bios/acpi-dsdt.dsl 2008-10-28 07:58:40.000000000 -0500
+@@ -159,6 +159,26 @@
+ Return (MEMP)
+ }
+ }
++#ifdef BX_QEMU
++ Device(HPET) {
++ Name(_HID, EISAID("PNP0103"))
++ Name(_UID, 0)
++ Method (_STA, 0, NotSerialized) {
++ Return(0x0F)
++ }
++ Name(_CRS, ResourceTemplate() {
++ DWordMemory(
++ ResourceConsumer, PosDecode, MinFixed, MaxFixed,
++ NonCacheable, ReadWrite,
++ 0x00000000,
++ 0xFED00000,
++ 0xFED003FF,
++ 0x00000000,
++ 0x00000400 /* 1K memory: FED00000 - FED003FF */
++ )
++ })
++ }
++#endif
+ }
+
+ Scope(\_SB.PCI0) {
+Index: bochs-2.3.7/bios/rombios32.c
+===================================================================
+--- bochs-2.3.7.orig/bios/rombios32.c 2008-10-15 12:39:36.000000000 -0500
++++ bochs-2.3.7/bios/rombios32.c 2008-11-12 14:41:41.000000000 -0600
+@@ -1087,7 +1087,11 @@
+ struct rsdt_descriptor_rev1
+ {
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
++#ifdef BX_QEMU
++ uint32_t table_offset_entry [4]; /* Array of pointers to other */
++#else
+ uint32_t table_offset_entry [3]; /* Array of pointers to other */
++#endif
+ /* ACPI tables */
+ };
+
+@@ -1227,6 +1231,32 @@
+ #endif
+ };
+
++#ifdef BX_QEMU
++/*
++ * * ACPI 2.0 Generic Address Space definition.
++ * */
++struct acpi_20_generic_address {
++ uint8_t address_space_id;
++ uint8_t register_bit_width;
++ uint8_t register_bit_offset;
++ uint8_t reserved;
++ uint64_t address;
++};
++
++/*
++ * * HPET Description Table
++ * */
++struct acpi_20_hpet {
++ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
++ uint32_t timer_block_id;
++ struct acpi_20_generic_address addr;
++ uint8_t hpet_number;
++ uint16_t min_tick;
++ uint8_t page_protect;
++};
++#define ACPI_HPET_ADDRESS 0xFED00000UL
++#endif
++
+ struct madt_io_apic
+ {
+ APIC_HEADER_DEF
+@@ -1237,6 +1267,17 @@
+ * lines start */
+ };
+
++#ifdef BX_QEMU
++struct madt_int_override
++{
++ APIC_HEADER_DEF
++ uint8_t bus; /* Identifies ISA Bus */
++ uint8_t source; /* Bus-relative interrupt source */
++ uint32_t gsi; /* GSI that source will signal */
++ uint16_t flags; /* MPS INTI flags */
++};
++#endif
++
+ #include "acpi-dsdt.hex"
+
+ static inline uint16_t cpu_to_le16(uint16_t x)
+@@ -1342,6 +1383,10 @@
+ struct facs_descriptor_rev1 *facs;
+ struct multiple_apic_table *madt;
+ uint8_t *dsdt, *ssdt;
++#ifdef BX_QEMU
++ struct acpi_20_hpet *hpet;
++ uint32_t hpet_addr;
++#endif
+ uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr, ssdt_addr;
+ uint32_t acpi_tables_size, madt_addr, madt_size;
+ int i;
+@@ -1384,10 +1429,21 @@
+ madt_addr = addr;
+ madt_size = sizeof(*madt) +
+ sizeof(struct madt_processor_apic) * smp_cpus +
++#ifdef BX_QEMU
++ sizeof(struct madt_io_apic) + sizeof(struct madt_int_override);
++#else
+ sizeof(struct madt_io_apic);
++#endif
+ madt = (void *)(addr);
+ addr += madt_size;
+
++#ifdef BX_QEMU
++ addr = (addr + 7) & ~7;
++ hpet_addr = addr;
++ hpet = (void *)(addr);
++ addr += sizeof(*hpet);
++#endif
++
+ acpi_tables_size = addr - base_addr;
+
+ BX_INFO("ACPI tables: RSDP addr=0x%08lx ACPI DATA addr=0x%08lx size=0x%x\n",
+@@ -1410,6 +1466,9 @@
+ rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr);
+ rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr);
+ rsdt->table_offset_entry[2] = cpu_to_le32(ssdt_addr);
++#ifdef BX_QEMU
++ rsdt->table_offset_entry[3] = cpu_to_le32(hpet_addr);
++#endif
+ acpi_build_table_header((struct acpi_table_header *)rsdt,
+ "RSDT", sizeof(*rsdt), 1);
+
+@@ -1448,6 +1507,9 @@
+ {
+ struct madt_processor_apic *apic;
+ struct madt_io_apic *io_apic;
++#ifdef BX_QEMU
++ struct madt_int_override *int_override;
++#endif
+
+ memset(madt, 0, madt_size);
+ madt->local_apic_address = cpu_to_le32(0xfee00000);
+@@ -1467,10 +1529,34 @@
+ io_apic->io_apic_id = smp_cpus;
+ io_apic->address = cpu_to_le32(0xfec00000);
+ io_apic->interrupt = cpu_to_le32(0);
++#ifdef BX_QEMU
++ io_apic++;
++
++ int_override = (void *)io_apic;
++ int_override->type = APIC_XRUPT_OVERRIDE;
++ int_override->length = sizeof(*int_override);
++ int_override->bus = cpu_to_le32(0);
++ int_override->source = cpu_to_le32(0);
++ int_override->gsi = cpu_to_le32(2);
++ int_override->flags = cpu_to_le32(0);
++#endif
+
+ acpi_build_table_header((struct acpi_table_header *)madt,
+ "APIC", madt_size, 1);
+ }
++
++#ifdef BX_QEMU
++ /* HPET */
++ memset(hpet, 0, sizeof(*hpet));
++ /* Note timer_block_id value must be kept in sync with value advertised by
++ * emulated hpet
++ */
++ hpet->timer_block_id = cpu_to_le32(0x8086a201);
++ hpet->addr.address = cpu_to_le32(ACPI_HPET_ADDRESS);
++ acpi_build_table_header((struct acpi_table_header *)hpet,
++ "HPET", sizeof(*hpet), 1);
++#endif
++
+ }
+
+ /* SMBIOS entry point -- must be written to a 16-bit aligned address
diff --git a/pc-bios/bios-pq/HEAD b/pc-bios/bios-pq/HEAD
new file mode 100644
index 000000000..928a2334b
--- /dev/null
+++ b/pc-bios/bios-pq/HEAD
@@ -0,0 +1 @@
+370a7e0d8419bc05192d766c11b7221e5ffc0f75
diff --git a/pc-bios/bios-pq/series b/pc-bios/bios-pq/series
new file mode 100644
index 000000000..0e7558c47
--- /dev/null
+++ b/pc-bios/bios-pq/series
@@ -0,0 +1,4 @@
+0001_bx-qemu.patch
+0002_e820-high-mem.patch
+0003_smp-startup-poll.patch
+0005_hpet.patch
diff --git a/pc-bios/vgabios-pq/HEAD b/pc-bios/vgabios-pq/HEAD
new file mode 100644
index 000000000..83fa6f79d
--- /dev/null
+++ b/pc-bios/vgabios-pq/HEAD
@@ -0,0 +1 @@
+86ccbd96bf82d046d219141ac56cd4b26256889b
diff --git a/pc-bios/vgabios-pq/series b/pc-bios/vgabios-pq/series
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/pc-bios/vgabios-pq/series
diff --git a/pc-bios/vgabios.diff b/pc-bios/vgabios.diff
deleted file mode 100644
index 661c032e4..000000000
--- a/pc-bios/vgabios.diff
+++ /dev/null
@@ -1,896 +0,0 @@
-Index: Makefile
-===================================================================
-RCS file: /sources/vgabios/vgabios/Makefile,v
-retrieving revision 1.17
-diff -u -w -r1.17 Makefile
---- Makefile 6 Mar 2005 13:06:47 -0000 1.17
-+++ Makefile 14 Jun 2006 00:51:06 -0000
-@@ -22,7 +22,7 @@
- cirrus-bios: vgabios-cirrus.bin vgabios-cirrus.debug.bin
-
- clean:
-- /bin/rm -f biossums *.o *.s *.ld86 \
-+ /bin/rm -f biossums vbetables-gen vbetables.h *.o *.s *.ld86 \
- temp.awk.* vgabios*.orig _vgabios_* _vgabios-debug_* core vgabios*.bin vgabios*.txt $(RELEASE).bin *.bak
-
- dist-clean: clean
-@@ -79,3 +79,9 @@
-
- biossums: biossums.c
- $(CC) -o biossums biossums.c
-+
-+vbetables-gen: vbetables-gen.c
-+ $(CC) -o vbetables-gen vbetables-gen.c
-+
-+vbetables.h: vbetables-gen
-+ ./vbetables-gen > $@
-Index: clext.c
-===================================================================
-RCS file: /sources/vgabios/vgabios/clext.c,v
-retrieving revision 1.10
-diff -u -w -r1.10 clext.c
---- clext.c 25 Mar 2006 10:19:15 -0000 1.10
-+++ clext.c 14 Jun 2006 00:51:06 -0000
-@@ -544,6 +544,13 @@
- cirrus_set_video_mode_extended:
- call cirrus_switch_mode
- pop ax ;; mode
-+ test al, #0x80
-+ jnz cirrus_set_video_mode_extended_1
-+ push ax
-+ mov ax, #0xffff ; set to 0xff to keep win 2K happy
-+ call cirrus_clear_vram
-+ pop ax
-+cirrus_set_video_mode_extended_1:
- and al, #0x7f
-
- push ds
-@@ -1011,6 +1018,13 @@
- jnz cirrus_vesa_02h_3
- call cirrus_enable_16k_granularity
- cirrus_vesa_02h_3:
-+ test bx, #0x8000 ;; no clear
-+ jnz cirrus_vesa_02h_4
-+ push ax
-+ xor ax,ax
-+ call cirrus_clear_vram
-+ pop ax
-+cirrus_vesa_02h_4:
- pop ax
- push ds
- #ifdef CIRRUS_VESA3_PMINFO
-@@ -1479,6 +1493,38 @@
- pop bx
- ret
-
-+cirrus_clear_vram:
-+ pusha
-+ push es
-+ mov si, ax
-+
-+ call cirrus_enable_16k_granularity
-+ call cirrus_extbios_85h
-+ shl al, #2
-+ mov bl, al
-+ xor ah,ah
-+cirrus_clear_vram_1:
-+ mov al, #0x09
-+ mov dx, #0x3ce
-+ out dx, ax
-+ push ax
-+ mov cx, #0xa000
-+ mov es, cx
-+ xor di, di
-+ mov ax, si
-+ mov cx, #8192
-+ cld
-+ rep
-+ stosw
-+ pop ax
-+ inc ah
-+ cmp ah, bl
-+ jne cirrus_clear_vram_1
-+
-+ pop es
-+ popa
-+ ret
-+
- cirrus_extbios_handlers:
- ;; 80h
- dw cirrus_extbios_80h
-Index: vbe.c
-===================================================================
-RCS file: /sources/vgabios/vgabios/vbe.c,v
-retrieving revision 1.48
-diff -u -w -r1.48 vbe.c
---- vbe.c 26 Dec 2005 19:50:26 -0000 1.48
-+++ vbe.c 14 Jun 2006 00:51:07 -0000
-@@ -118,21 +118,114 @@
- .word VBE_VESA_MODE_END_OF_LIST
- #endif
-
-+ .align 2
- vesa_pm_start:
- dw vesa_pm_set_window - vesa_pm_start
-- dw vesa_pm_set_display_strt - vesa_pm_start
-+ dw vesa_pm_set_display_start - vesa_pm_start
- dw vesa_pm_unimplemented - vesa_pm_start
-- dw 0
-+ dw vesa_pm_io_ports_table - vesa_pm_start
-+vesa_pm_io_ports_table:
-+ dw VBE_DISPI_IOPORT_INDEX
-+ dw VBE_DISPI_IOPORT_INDEX + 1
-+ dw VBE_DISPI_IOPORT_DATA
-+ dw VBE_DISPI_IOPORT_DATA + 1
-+ dw 0xffff
-+ dw 0xffff
-
- USE32
- vesa_pm_set_window:
-- mov ax, #0x4f05
-- int #0x10
-+ cmp bx, #0x00
-+ je vesa_pm_set_display_window1
-+ mov ax, #0x0100
-+ ret
-+vesa_pm_set_display_window1:
-+ mov ax, dx
-+ push dx
-+ push ax
-+ mov dx, # VBE_DISPI_IOPORT_INDEX
-+ mov ax, # VBE_DISPI_INDEX_BANK
-+ out dx, ax
-+ pop ax
-+ mov dx, # VBE_DISPI_IOPORT_DATA
-+ out dx, ax
-+ pop dx
-+ mov ax, #0x004f
- ret
-
- vesa_pm_set_display_start:
-- mov ax, #0x4f07
-- int #0x10
-+ cmp bl, #0x80
-+ je vesa_pm_set_display_start1
-+ cmp bl, #0x00
-+ je vesa_pm_set_display_start1
-+ mov ax, #0x0100
-+ ret
-+vesa_pm_set_display_start1:
-+; convert offset to (X, Y) coordinate
-+; (would be simpler to change Bochs VBE API...)
-+ push eax
-+ push ecx
-+ push edx
-+ push esi
-+ push edi
-+ shl edx, #16
-+ and ecx, #0xffff
-+ or ecx, edx
-+ shl ecx, #2
-+ mov eax, ecx
-+
-+ push eax
-+ mov dx, # VBE_DISPI_IOPORT_INDEX
-+ mov ax, # VBE_DISPI_INDEX_VIRT_WIDTH
-+ out dx, ax
-+ mov dx, # VBE_DISPI_IOPORT_DATA
-+ in ax, dx
-+ movzx ecx, ax
-+
-+ mov dx, # VBE_DISPI_IOPORT_INDEX
-+ mov ax, # VBE_DISPI_INDEX_BPP
-+ out dx, ax
-+ mov dx, # VBE_DISPI_IOPORT_DATA
-+ in ax, dx
-+ movzx esi, ax
-+ pop eax
-+
-+ add esi, #7
-+ shr esi, #3
-+ imul ecx, esi
-+ xor edx, edx
-+ div ecx
-+ mov edi, eax
-+ mov eax, edx
-+ xor edx, edx
-+ div esi
-+
-+ push dx
-+ push ax
-+ mov dx, # VBE_DISPI_IOPORT_INDEX
-+ mov ax, # VBE_DISPI_INDEX_X_OFFSET
-+ out dx, ax
-+ pop ax
-+ mov dx, # VBE_DISPI_IOPORT_DATA
-+ out dx, ax
-+ pop dx
-+
-+ mov ax, di
-+ push dx
-+ push ax
-+ mov dx, # VBE_DISPI_IOPORT_INDEX
-+ mov ax, # VBE_DISPI_INDEX_Y_OFFSET
-+ out dx, ax
-+ pop ax
-+ mov dx, # VBE_DISPI_IOPORT_DATA
-+ out dx, ax
-+ pop dx
-+
-+ pop edi
-+ pop esi
-+ pop edx
-+ pop ecx
-+ pop eax
-+ mov ax, #0x004f
- ret
-
- vesa_pm_unimplemented:
-@@ -835,6 +928,64 @@
- ASM_END
-
-
-+Bit16u vbe_biosfn_read_video_state_size()
-+{
-+ return 9 * 2;
-+}
-+
-+void vbe_biosfn_save_video_state(ES, BX)
-+ Bit16u ES; Bit16u BX;
-+{
-+ Bit16u enable, i;
-+
-+ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
-+ enable = inw(VBE_DISPI_IOPORT_DATA);
-+ write_word(ES, BX, enable);
-+ BX += 2;
-+ if (!(enable & VBE_DISPI_ENABLED))
-+ return;
-+ for(i = VBE_DISPI_INDEX_XRES; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
-+ if (i != VBE_DISPI_INDEX_ENABLE) {
-+ outw(VBE_DISPI_IOPORT_INDEX, i);
-+ write_word(ES, BX, inw(VBE_DISPI_IOPORT_DATA));
-+ BX += 2;
-+ }
-+ }
-+}
-+
-+
-+void vbe_biosfn_restore_video_state(ES, BX)
-+ Bit16u ES; Bit16u BX;
-+{
-+ Bit16u enable, i;
-+
-+ enable = read_word(ES, BX);
-+ BX += 2;
-+
-+ if (!(enable & VBE_DISPI_ENABLED)) {
-+ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
-+ outw(VBE_DISPI_IOPORT_DATA, enable);
-+ } else {
-+ outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
-+ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
-+ BX += 2;
-+ outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
-+ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
-+ BX += 2;
-+ outw(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
-+ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
-+ BX += 2;
-+ outw(VBE_DISPI_IOPORT_INDEX,VBE_DISPI_INDEX_ENABLE);
-+ outw(VBE_DISPI_IOPORT_DATA, enable);
-+
-+ for(i = VBE_DISPI_INDEX_BANK; i <= VBE_DISPI_INDEX_Y_OFFSET; i++) {
-+ outw(VBE_DISPI_IOPORT_INDEX, i);
-+ outw(VBE_DISPI_IOPORT_DATA, read_word(ES, BX));
-+ BX += 2;
-+ }
-+ }
-+}
-+
- /** Function 04h - Save/Restore State
- *
- * Input:
-@@ -849,10 +1000,48 @@
- * BX = Number of 64-byte blocks to hold the state buffer (if DL=00h)
- *
- */
--void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX)
-+void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX)
-+Bit16u *AX; Bit16u CX; Bit16u DX; Bit16u ES; Bit16u *BX;
- {
--}
-+ Bit16u ss=get_SS();
-+ Bit16u result, val;
-
-+ result = 0x4f;
-+ switch(GET_DL()) {
-+ case 0x00:
-+ val = biosfn_read_video_state_size2(CX);
-+#ifdef DEBUG
-+ printf("VGA state size=%x\n", val);
-+#endif
-+ if (CX & 8)
-+ val += vbe_biosfn_read_video_state_size();
-+ write_word(ss, BX, val);
-+ break;
-+ case 0x01:
-+ val = read_word(ss, BX);
-+ val = biosfn_save_video_state(CX, ES, val);
-+#ifdef DEBUG
-+ printf("VGA save_state offset=%x\n", val);
-+#endif
-+ if (CX & 8)
-+ vbe_biosfn_save_video_state(ES, val);
-+ break;
-+ case 0x02:
-+ val = read_word(ss, BX);
-+ val = biosfn_restore_video_state(CX, ES, val);
-+#ifdef DEBUG
-+ printf("VGA restore_state offset=%x\n", val);
-+#endif
-+ if (CX & 8)
-+ vbe_biosfn_restore_video_state(ES, val);
-+ break;
-+ default:
-+ // function failed
-+ result = 0x100;
-+ break;
-+ }
-+ write_word(ss, AX, result);
-+}
-
- /** Function 05h - Display Window Control
- *
-@@ -1090,7 +1279,7 @@
- */
- ASM_START
- vbe_biosfn_return_protected_mode_interface:
-- test bx, bx
-+ test bl, bl
- jnz _fail
- mov di, #0xc000
- mov es, di
-Index: vbe.h
-===================================================================
-RCS file: /sources/vgabios/vgabios/vbe.h,v
-retrieving revision 1.24
-diff -u -w -r1.24 vbe.h
---- vbe.h 9 May 2004 20:31:31 -0000 1.24
-+++ vbe.h 14 Jun 2006 00:51:07 -0000
-@@ -14,7 +14,7 @@
- void vbe_biosfn_return_controller_information(AX, ES, DI);
- void vbe_biosfn_return_mode_information(AX, CX, ES, DI);
- void vbe_biosfn_set_mode(AX, BX, ES, DI);
--void vbe_biosfn_save_restore_state(AX, DL, CX, ES, BX);
-+void vbe_biosfn_save_restore_state(AX, CX, DX, ES, BX);
- void vbe_biosfn_set_get_palette_data(AX);
- void vbe_biosfn_return_protected_mode_interface(AX);
-
-@@ -151,6 +151,12 @@
- Bit8u Reserved[189];
- } ModeInfoBlock;
-
-+typedef struct ModeInfoListItem
-+{
-+ Bit16u mode;
-+ ModeInfoBlockCompact info;
-+} ModeInfoListItem;
-+
- // VBE Return Status Info
- // AL
- #define VBE_RETURN_STATUS_SUPPORTED 0x4F
-@@ -193,6 +199,10 @@
- #define VBE_VESA_MODE_1280X1024X1555 0x119
- #define VBE_VESA_MODE_1280X1024X565 0x11A
- #define VBE_VESA_MODE_1280X1024X888 0x11B
-+#define VBE_VESA_MODE_1600X1200X8 0x11C
-+#define VBE_VESA_MODE_1600X1200X1555 0x11D
-+#define VBE_VESA_MODE_1600X1200X565 0x11E
-+#define VBE_VESA_MODE_1600X1200X888 0x11F
-
- // BOCHS/PLEX86 'own' mode numbers
- #define VBE_OWN_MODE_320X200X8888 0x140
-@@ -202,6 +212,12 @@
- #define VBE_OWN_MODE_1024X768X8888 0x144
- #define VBE_OWN_MODE_1280X1024X8888 0x145
- #define VBE_OWN_MODE_320X200X8 0x146
-+#define VBE_OWN_MODE_1600X1200X8888 0x147
-+#define VBE_OWN_MODE_1152X864X8 0x148
-+#define VBE_OWN_MODE_1152X864X1555 0x149
-+#define VBE_OWN_MODE_1152X864X565 0x14a
-+#define VBE_OWN_MODE_1152X864X888 0x14b
-+#define VBE_OWN_MODE_1152X864X8888 0x14c
-
- #define VBE_VESA_MODE_END_OF_LIST 0xFFFF
-
-@@ -259,7 +275,7 @@
- // like 0xE0000000
-
-
-- #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 4
-+ #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 8
-
- #define VBE_DISPI_BANK_ADDRESS 0xA0000
- #define VBE_DISPI_BANK_SIZE_KB 64
-Index: vgabios.c
-===================================================================
-RCS file: /sources/vgabios/vgabios/vgabios.c,v
-retrieving revision 1.64
-diff -u -w -r1.64 vgabios.c
---- vgabios.c 25 Mar 2006 10:19:16 -0000 1.64
-+++ vgabios.c 14 Jun 2006 00:51:07 -0000
-@@ -109,8 +109,8 @@
- static void biosfn_write_string();
- static void biosfn_read_state_info();
- static void biosfn_read_video_state_size();
--static void biosfn_save_video_state();
--static void biosfn_restore_video_state();
-+static Bit16u biosfn_save_video_state();
-+static Bit16u biosfn_restore_video_state();
- extern Bit8u video_save_pointer_table[];
-
- // This is for compiling with gcc2 and gcc3
-@@ -748,12 +748,7 @@
- vbe_biosfn_set_mode(&AX,BX,ES,DI);
- break;
- case 0x04:
-- //FIXME
--#ifdef DEBUG
-- unimplemented();
--#endif
-- // function failed
-- AX=0x100;
-+ vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
- break;
- case 0x09:
- //FIXME
-@@ -3138,23 +3133,215 @@
- }
-
- // --------------------------------------------------------------------------------------------
--static void biosfn_read_video_state_size (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX;
-+// --------------------------------------------------------------------------------------------
-+static Bit16u biosfn_read_video_state_size2 (CX)
-+ Bit16u CX;
- {
--#ifdef DEBUG
-- unimplemented();
--#endif
-+ Bit16u size;
-+ size = 0;
-+ if (CX & 1) {
-+ size += 0x46;
-+ }
-+ if (CX & 2) {
-+ size += (5 + 8 + 5) * 2 + 6;
-+ }
-+ if (CX & 4) {
-+ size += 3 + 256 * 3 + 1;
- }
--static void biosfn_save_video_state (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX;
-+ return size;
-+}
-+
-+static void biosfn_read_video_state_size (CX, BX)
-+ Bit16u CX; Bit16u *BX;
- {
--#ifdef DEBUG
-- unimplemented();
--#endif
-+ Bit16u ss=get_SS();
-+ write_word(ss, BX, biosfn_read_video_state_size2(CX));
- }
--static void biosfn_restore_video_state (CX,ES,BX) Bit16u CX;Bit16u ES;Bit16u BX;
-+
-+static Bit16u biosfn_save_video_state (CX,ES,BX)
-+ Bit16u CX;Bit16u ES;Bit16u BX;
- {
--#ifdef DEBUG
-- unimplemented();
--#endif
-+ Bit16u i, v, crtc_addr, ar_index;
-+
-+ crtc_addr = read_word(BIOSMEM_SEG, BIOSMEM_CRTC_ADDRESS);
-+ if (CX & 1) {
-+ write_byte(ES, BX, inb(VGAREG_SEQU_ADDRESS)); BX++;
-+ write_byte(ES, BX, inb(crtc_addr)); BX++;
-+ write_byte(ES, BX, inb(VGAREG_GRDC_ADDRESS)); BX++;
-+ inb(VGAREG_ACTL_RESET);
-+ ar_index = inb(VGAREG_ACTL_ADDRESS);
-+ write_byte(ES, BX, ar_index); BX++;
-+ write_byte(ES, BX, inb(VGAREG_READ_FEATURE_CTL)); BX++;
-+
-+ for(i=1;i<=4;i++){
-+ outb(VGAREG_SEQU_ADDRESS, i);
-+ write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
-+ }
-+ outb(VGAREG_SEQU_ADDRESS, 0);
-+ write_byte(ES, BX, inb(VGAREG_SEQU_DATA)); BX++;
-+
-+ for(i=0;i<=0x18;i++) {
-+ outb(crtc_addr,i);
-+ write_byte(ES, BX, inb(crtc_addr+1)); BX++;
-+ }
-+
-+ for(i=0;i<=0x13;i++) {
-+ inb(VGAREG_ACTL_RESET);
-+ outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
-+ write_byte(ES, BX, inb(VGAREG_ACTL_READ_DATA)); BX++;
-+ }
-+ inb(VGAREG_ACTL_RESET);
-+
-+ for(i=0;i<=8;i++) {
-+ outb(VGAREG_GRDC_ADDRESS,i);
-+ write_byte(ES, BX, inb(VGAREG_GRDC_DATA)); BX++;
-+ }
-+
-+ write_word(ES, BX, crtc_addr); BX+= 2;
-+
-+ /* XXX: read plane latches */
-+ write_byte(ES, BX, 0); BX++;
-+ write_byte(ES, BX, 0); BX++;
-+ write_byte(ES, BX, 0); BX++;
-+ write_byte(ES, BX, 0); BX++;
-+ }
-+ if (CX & 2) {
-+ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)); BX++;
-+ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_NB_COLS)); BX += 2;
-+ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE)); BX += 2;
-+ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS)); BX += 2;
-+ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS)); BX++;
-+ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)); BX += 2;
-+ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)); BX++;
-+ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES)); BX++;
-+ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)); BX++;
-+ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE)); BX += 2;
-+ for(i=0;i<8;i++) {
-+ write_word(ES, BX, read_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i));
-+ BX += 2;
-+ }
-+ write_word(ES, BX, read_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START)); BX += 2;
-+ write_byte(ES, BX, read_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); BX++;
-+ /* current font */
-+ write_word(ES, BX, read_word(0, 0x1f * 4)); BX += 2;
-+ write_word(ES, BX, read_word(0, 0x1f * 4 + 2)); BX += 2;
-+ write_word(ES, BX, read_word(0, 0x43 * 4)); BX += 2;
-+ write_word(ES, BX, read_word(0, 0x43 * 4 + 2)); BX += 2;
-+ }
-+ if (CX & 4) {
-+ /* XXX: check this */
-+ write_byte(ES, BX, inb(VGAREG_DAC_STATE)); BX++; /* read/write mode dac */
-+ write_byte(ES, BX, inb(VGAREG_DAC_WRITE_ADDRESS)); BX++; /* pix address */
-+ write_byte(ES, BX, inb(VGAREG_PEL_MASK)); BX++;
-+ // Set the whole dac always, from 0
-+ outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
-+ for(i=0;i<256*3;i++) {
-+ write_byte(ES, BX, inb(VGAREG_DAC_DATA)); BX++;
-+ }
-+ write_byte(ES, BX, 0); BX++; /* color select register */
-+ }
-+ return BX;
-+}
-+
-+static Bit16u biosfn_restore_video_state (CX,ES,BX)
-+ Bit16u CX;Bit16u ES;Bit16u BX;
-+{
-+ Bit16u i, crtc_addr, v, addr1, ar_index;
-+
-+ if (CX & 1) {
-+ // Reset Attribute Ctl flip-flop
-+ inb(VGAREG_ACTL_RESET);
-+
-+ crtc_addr = read_word(ES, BX + 0x40);
-+ addr1 = BX;
-+ BX += 5;
-+
-+ for(i=1;i<=4;i++){
-+ outb(VGAREG_SEQU_ADDRESS, i);
-+ outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
-+ }
-+ outb(VGAREG_SEQU_ADDRESS, 0);
-+ outb(VGAREG_SEQU_DATA, read_byte(ES, BX)); BX++;
-+
-+ // Disable CRTC write protection
-+ outw(crtc_addr,0x0011);
-+ // Set CRTC regs
-+ for(i=0;i<=0x18;i++) {
-+ if (i != 0x11) {
-+ outb(crtc_addr,i);
-+ outb(crtc_addr+1, read_byte(ES, BX));
-+ }
-+ BX++;
-+ }
-+ // select crtc base address
-+ v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
-+ if (crtc_addr = 0x3d4)
-+ v |= 0x01;
-+ outb(VGAREG_WRITE_MISC_OUTPUT, v);
-+
-+ // enable write protection if needed
-+ outb(crtc_addr, 0x11);
-+ outb(crtc_addr+1, read_byte(ES, BX - 0x18 + 0x11));
-+
-+ // Set Attribute Ctl
-+ ar_index = read_byte(ES, addr1 + 0x03);
-+ inb(VGAREG_ACTL_RESET);
-+ for(i=0;i<=0x13;i++) {
-+ outb(VGAREG_ACTL_ADDRESS, i | (ar_index & 0x20));
-+ outb(VGAREG_ACTL_WRITE_DATA, read_byte(ES, BX)); BX++;
-+ }
-+ outb(VGAREG_ACTL_ADDRESS, ar_index);
-+ inb(VGAREG_ACTL_RESET);
-+
-+ for(i=0;i<=8;i++) {
-+ outb(VGAREG_GRDC_ADDRESS,i);
-+ outb(VGAREG_GRDC_DATA, read_byte(ES, BX)); BX++;
-+ }
-+ BX += 2; /* crtc_addr */
-+ BX += 4; /* plane latches */
-+
-+ outb(VGAREG_SEQU_ADDRESS, read_byte(ES, addr1)); addr1++;
-+ outb(crtc_addr, read_byte(ES, addr1)); addr1++;
-+ outb(VGAREG_GRDC_ADDRESS, read_byte(ES, addr1)); addr1++;
-+ addr1++;
-+ outb(crtc_addr - 0x4 + 0xa, read_byte(ES, addr1)); addr1++;
-+ }
-+ if (CX & 2) {
-+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE, read_byte(ES, BX)); BX++;
-+ write_word(BIOSMEM_SEG,BIOSMEM_NB_COLS, read_word(ES, BX)); BX += 2;
-+ write_word(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE, read_word(ES, BX)); BX += 2;
-+ write_word(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS, read_word(ES, BX)); BX += 2;
-+ write_byte(BIOSMEM_SEG,BIOSMEM_NB_ROWS, read_byte(ES, BX)); BX++;
-+ write_word(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT, read_word(ES, BX)); BX += 2;
-+ write_byte(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL, read_byte(ES, BX)); BX++;
-+ write_byte(BIOSMEM_SEG,BIOSMEM_SWITCHES, read_byte(ES, BX)); BX++;
-+ write_byte(BIOSMEM_SEG,BIOSMEM_MODESET_CTL, read_byte(ES, BX)); BX++;
-+ write_word(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE, read_word(ES, BX)); BX += 2;
-+ for(i=0;i<8;i++) {
-+ write_word(BIOSMEM_SEG, BIOSMEM_CURSOR_POS+2*i, read_word(ES, BX));
-+ BX += 2;
-+ }
-+ write_word(BIOSMEM_SEG,BIOSMEM_CURRENT_START, read_word(ES, BX)); BX += 2;
-+ write_byte(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE, read_byte(ES, BX)); BX++;
-+ /* current font */
-+ write_word(0, 0x1f * 4, read_word(ES, BX)); BX += 2;
-+ write_word(0, 0x1f * 4 + 2, read_word(ES, BX)); BX += 2;
-+ write_word(0, 0x43 * 4, read_word(ES, BX)); BX += 2;
-+ write_word(0, 0x43 * 4 + 2, read_word(ES, BX)); BX += 2;
-+ }
-+ if (CX & 4) {
-+ BX++;
-+ v = read_byte(ES, BX); BX++;
-+ outb(VGAREG_PEL_MASK, read_byte(ES, BX)); BX++;
-+ // Set the whole dac always, from 0
-+ outb(VGAREG_DAC_WRITE_ADDRESS,0x00);
-+ for(i=0;i<256*3;i++) {
-+ outb(VGAREG_DAC_DATA, read_byte(ES, BX)); BX++;
-+ }
-+ BX++;
-+ outb(VGAREG_DAC_WRITE_ADDRESS, v);
-+ }
-+ return BX;
- }
-
- // ============================================================================================
-diff -u -w vbetables-gen.c
---- vbetables-gen.c 1970-01-01 01:00:00.000000000 +0100
-+++ vbetables-gen.c 2006-06-14 00:52:18.000000000 +0200
-@@ -0,0 +1,217 @@
-+/* Generate the VGABIOS VBE Tables */
-+#include <stdlib.h>
-+#include <stdio.h>
-+
-+typedef struct {
-+ int width;
-+ int height;
-+ int depth;
-+ int mode;
-+} ModeInfo;
-+
-+ModeInfo modes[] = {
-+ /* standard VESA modes */
-+{ 640, 400, 8 , 0x100},
-+{ 640, 480, 8 , 0x101},
-+{ 800, 600, 4 , 0x102},
-+{ 800, 600, 8 , 0x103},
-+ //{ 1024, 768, 4 , 0x104},
-+{ 1024, 768, 8 , 0x105},
-+ //{ 1280, 1024, 4 , 0x106},
-+{ 1280, 1024, 8 , 0x107},
-+{ 320, 200, 15 , 0x10D},
-+{ 320, 200, 16 , 0x10E},
-+{ 320, 200, 24 , 0x10F},
-+{ 640, 480, 15 , 0x110},
-+{ 640, 480, 16 , 0x111},
-+{ 640, 480, 24 , 0x112},
-+{ 800, 600, 15 , 0x113},
-+{ 800, 600, 16 , 0x114},
-+{ 800, 600, 24 , 0x115},
-+{ 1024, 768, 15 , 0x116},
-+{ 1024, 768, 16 , 0x117},
-+{ 1024, 768, 24 , 0x118},
-+{ 1280, 1024, 15 , 0x119},
-+{ 1280, 1024, 16 , 0x11A},
-+{ 1280, 1024, 24 , 0x11B},
-+{ 1600, 1200, 8 , 0x11C},
-+{ 1600, 1200, 15 , 0x11D},
-+{ 1600, 1200, 16 , 0x11E},
-+{ 1600, 1200, 24 , 0x11F},
-+
-+ /* BOCHS/PLE, 86 'own' mode numbers */
-+{ 320, 200, 32 , 0x140},
-+{ 640, 400, 32 , 0x141},
-+{ 640, 480, 32 , 0x142},
-+{ 800, 600, 32 , 0x143},
-+{ 1024, 768, 32 , 0x144},
-+{ 1280, 1024, 32 , 0x145},
-+{ 320, 200, 8 , 0x146},
-+{ 1600, 1200, 32 , 0x147},
-+{ 1152, 864, 8 , 0x148},
-+{ 1152, 864, 15 , 0x149},
-+{ 1152, 864, 16 , 0x14a},
-+{ 1152, 864, 24 , 0x14b},
-+{ 1152, 864, 32 , 0x14c},
-+{ 0, },
-+};
-+
-+int main(int argc, char **argv)
-+{
-+ const ModeInfo *pm;
-+ int pitch, r_size, r_pos, g_size, g_pos, b_size, b_pos, a_size, a_pos;
-+ const char *str;
-+
-+ printf("/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT EDIT */\n");
-+ printf("static ModeInfoListItem mode_info_list[]=\n");
-+ printf("{\n");
-+ for(pm = modes; pm->mode != 0; pm++) {
-+ printf("{ 0x%04x, /* %dx%dx%d */\n",
-+ pm->mode, pm->width, pm->height, pm->depth);
-+ printf("{ /*Bit16u ModeAttributes*/ %s,\n",
-+ "VBE_MODE_ATTRIBUTE_SUPPORTED | "
-+ "VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE | "
-+ "VBE_MODE_ATTRIBUTE_COLOR_MODE | "
-+ "VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE | "
-+ "VBE_MODE_ATTRIBUTE_GRAPHICS_MODE");
-+
-+ printf("/*Bit8u WinAAttributes*/ %s,\n",
-+ "VBE_WINDOW_ATTRIBUTE_RELOCATABLE | "
-+ "VBE_WINDOW_ATTRIBUTE_READABLE | "
-+ "VBE_WINDOW_ATTRIBUTE_WRITEABLE");
-+
-+ printf("/*Bit8u WinBAttributes*/ %d,\n", 0);
-+
-+ printf("/*Bit16u WinGranularity*/ %s,\n", "VBE_DISPI_BANK_SIZE_KB");
-+
-+ printf("/*Bit16u WinSize*/ %s,\n", "VBE_DISPI_BANK_SIZE_KB");
-+
-+ printf("/*Bit16u WinASegment*/ %s,\n", "VGAMEM_GRAPH");
-+
-+ printf("/*Bit16u WinBSegment*/ 0x%04x,\n", 0);
-+
-+ printf("/*Bit32u WinFuncPtr*/ %d,\n", 0);
-+
-+ if (pm->depth == 4)
-+ pitch = (pm->width + 7) / 8;
-+ else
-+ pitch = pm->width * ((pm->depth + 7) / 8);
-+ printf("/*Bit16u BytesPerScanLine*/ %d,\n", pitch);
-+
-+ // Mandatory information for VBE 1.2 and above
-+ printf("/*Bit16u XResolution*/ %d,\n", pm->width);
-+ printf("/*Bit16u YResolution*/ %d,\n", pm->height);
-+ printf("/*Bit8u XCharSize*/ %d,\n", 8);
-+ printf("/*Bit8u YCharSize*/ %d,\n", 16);
-+ if (pm->depth == 4) {
-+ printf("/*Bit8u NumberOfPlanes*/ %d,\n", 4);
-+ printf("/*Bit8u BitsPerPixel*/ %d,\n", pm->depth);
-+ } else {
-+ printf("/*Bit8u NumberOfPlanes*/ %d,\n", 1);
-+ printf("/*Bit8u BitsPerPixel*/ %d,\n", pm->depth);
-+ }
-+ printf("/*Bit8u NumberOfBanks*/ %d,\n",
-+ (pm->height * pitch + 65535) / 65536);
-+
-+ if (pm->depth == 4)
-+ str = "VBE_MEMORYMODEL_PLANAR";
-+ else if (pm->depth == 8)
-+ str = "VBE_MEMORYMODEL_PACKED_PIXEL";
-+ else
-+ str = "VBE_MEMORYMODEL_DIRECT_COLOR";
-+ printf("/*Bit8u MemoryModel*/ %s,\n", str);
-+ printf("/*Bit8u BankSize*/ %d,\n", 0);
-+ /* XXX: check */
-+ printf("/*Bit8u NumberOfImagePages*/ %d,\n", 0);
-+ printf("/*Bit8u Reserved_page*/ %d,\n", 0);
-+
-+ // Direct Color fields (required for direct/6 and YUV/7 memory models)
-+ switch(pm->depth) {
-+ case 15:
-+ r_size = 5;
-+ r_pos = 10;
-+ g_size = 5;
-+ g_pos = 5;
-+ b_size = 5;
-+ b_pos = 0;
-+ a_size = 1;
-+ a_pos = 15;
-+ break;
-+ case 16:
-+ r_size = 5;
-+ r_pos = 11;
-+ g_size = 6;
-+ g_pos = 5;
-+ b_size = 5;
-+ b_pos = 0;
-+ a_size = 0;
-+ a_pos = 0;
-+ break;
-+ case 24:
-+ r_size = 8;
-+ r_pos = 16;
-+ g_size = 8;
-+ g_pos = 8;
-+ b_size = 8;
-+ b_pos = 0;
-+ a_size = 0;
-+ a_pos = 0;
-+ break;
-+ case 32:
-+ r_size = 8;
-+ r_pos = 16;
-+ g_size = 8;
-+ g_pos = 8;
-+ b_size = 8;
-+ b_pos = 0;
-+ a_size = 8;
-+ a_pos = 24;
-+ break;
-+ default:
-+ r_size = 0;
-+ r_pos = 0;
-+ g_size = 0;
-+ g_pos = 0;
-+ b_size = 0;
-+ b_pos = 0;
-+ a_size = 0;
-+ a_pos = 0;
-+ break;
-+ }
-+
-+ printf("/*Bit8u RedMaskSize*/ %d,\n", r_size);
-+ printf("/*Bit8u RedFieldPosition*/ %d,\n", r_pos);
-+ printf("/*Bit8u GreenMaskSize*/ %d,\n", g_size);
-+ printf("/*Bit8u GreenFieldPosition*/ %d,\n", g_pos);
-+ printf("/*Bit8u BlueMaskSize*/ %d,\n", b_size);
-+ printf("/*Bit8u BlueFieldPosition*/ %d,\n", b_pos);
-+ printf("/*Bit8u RsvdMaskSize*/ %d,\n", a_size);
-+ printf("/*Bit8u RsvdFieldPosition*/ %d,\n", a_pos);
-+ printf("/*Bit8u DirectColorModeInfo*/ %d,\n", 0);
-+
-+// Mandatory information for VBE 2.0 and above
-+ printf("/*Bit32u PhysBasePtr*/ %s,\n",
-+ "VBE_DISPI_LFB_PHYSICAL_ADDRESS");
-+ printf("/*Bit32u OffScreenMemOffset*/ %d,\n", 0);
-+ printf("/*Bit16u OffScreenMemSize*/ %d,\n", 0);
-+ // Mandatory information for VBE 3.0 and above
-+ printf("/*Bit16u LinBytesPerScanLine*/ %d,\n", pitch);
-+ printf("/*Bit8u BnkNumberOfPages*/ %d,\n", 0);
-+ printf("/*Bit8u LinNumberOfPages*/ %d,\n", 0);
-+ printf("/*Bit8u LinRedMaskSize*/ %d,\n", r_size);
-+ printf("/*Bit8u LinRedFieldPosition*/ %d,\n", r_pos);
-+ printf("/*Bit8u LinGreenMaskSize*/ %d,\n", g_size);
-+ printf("/*Bit8u LinGreenFieldPosition*/ %d,\n", g_pos);
-+ printf("/*Bit8u LinBlueMaskSize*/ %d,\n", b_size);
-+ printf("/*Bit8u LinBlueFieldPosition*/ %d,\n", b_pos);
-+ printf("/*Bit8u LinRsvdMaskSize*/ %d,\n", a_size);
-+ printf("/*Bit8u LinRsvdFieldPosition*/ %d,\n", a_pos);
-+ printf("/*Bit32u MaxPixelClock*/ %d,\n", 0);
-+ printf("} },\n");
-+ }
-+ printf("{ VBE_VESA_MODE_END_OF_LIST,\n");
-+ printf("{ 0,\n");
-+ printf("} },\n");
-+ printf("};\n");
-+ return 0;
-+}
diff --git a/pci-ids.txt b/pci-ids.txt
new file mode 100644
index 000000000..57d817519
--- /dev/null
+++ b/pci-ids.txt
@@ -0,0 +1,30 @@
+
+PCI IDs for qemu
+================
+
+Red Hat, Inc. donates a part of its device ID range to qemu, to be used for
+virtual devices. The vendor ID is 1af4 (formerly Qumranet ID).
+
+The 1000 -> 10ff device ID range is used for VirtIO devices.
+
+The 1100 device ID is used as PCI Subsystem ID for existing hardware
+devices emulated by qemu.
+
+All other device IDs are reserved.
+
+
+VirtIO Device IDs
+-----------------
+
+1af4:1000 network device
+1af4:1001 block device
+1af4:1002 balloon device
+
+1af4:1003 Reserved.
+ to Contact Gerd Hoffmann <kraxel@redhat.com> to get a
+1af4:10ef device ID assigned for your new virtio device.
+
+1af4:10f0 Available for experimental usage without registration. Must get
+ to official ID when the code leaves the test lab (i.e. when seeking
+1af4:10ff upstream merge or shipping a distro/product) to avoid conflicts.
+
diff --git a/qemu-kvm.h b/qemu-kvm.h
index 154ff6338..bd8a9e89b 100644
--- a/qemu-kvm.h
+++ b/qemu-kvm.h
@@ -198,4 +198,7 @@ void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_a
int kvm_log_start(target_phys_addr_t phys_addr, target_phys_addr_t len);
int kvm_log_stop(target_phys_addr_t phys_addr, target_phys_addr_t len);
+
+static inline int kvm_sync_vcpus(void) { return 0; }
+
#endif
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index d6cb1162c..ab101c9d7 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -100,6 +100,9 @@ typedef struct CPUARMState {
struct {
uint32_t c0_cpuid;
uint32_t c0_cachetype;
+ uint32_t c0_ccsid[16]; /* Cache size. */
+ uint32_t c0_clid; /* Cache level. */
+ uint32_t c0_cssel; /* Cache size selection. */
uint32_t c0_c1[8]; /* Feature registers. */
uint32_t c0_c2[8]; /* Instruction set registers. */
uint32_t c1_sys; /* System control register. */
@@ -151,6 +154,10 @@ typedef struct CPUARMState {
void *opaque;
} cp[15];
+ /* Thumb-2 EE state. */
+ uint32_t teecr;
+ uint32_t teehbr;
+
/* Internal CPU feature flags. */
uint32_t features;
@@ -329,7 +336,8 @@ enum arm_features {
ARM_FEATURE_NEON,
ARM_FEATURE_DIV,
ARM_FEATURE_M, /* Microcontroller profile. */
- ARM_FEATURE_OMAPCP /* OMAP specific CP15 ops handling. */
+ ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */
+ ARM_FEATURE_THUMB2EE
};
static inline int arm_feature(CPUARMState *env, int feature)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index a9b31e5d6..81663c8f3 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -88,12 +88,17 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
set_feature(env, ARM_FEATURE_VFP);
set_feature(env, ARM_FEATURE_VFP3);
set_feature(env, ARM_FEATURE_NEON);
+ set_feature(env, ARM_FEATURE_THUMB2EE);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t));
- env->cp15.c0_cachetype = 0x1dd20d2;
+ env->cp15.c0_cachetype = 0x82048004;
+ env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3;
+ env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
+ env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
+ env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
break;
case ARM_CPUID_CORTEXM3:
set_feature(env, ARM_FEATURE_V6);
@@ -110,6 +115,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
set_feature(env, ARM_FEATURE_VFP);
set_feature(env, ARM_FEATURE_VFP3);
set_feature(env, ARM_FEATURE_NEON);
+ set_feature(env, ARM_FEATURE_THUMB2EE);
set_feature(env, ARM_FEATURE_DIV);
break;
case ARM_CPUID_TI915T:
@@ -900,12 +906,16 @@ static inline int check_ap(CPUState *env, int ap, int domain, int access_type,
return PAGE_READ | PAGE_WRITE;
case 3:
return PAGE_READ | PAGE_WRITE;
- case 4: case 7: /* Reserved. */
+ case 4: /* Reserved. */
return 0;
case 5:
return is_user ? 0 : prot_ro;
case 6:
return prot_ro;
+ case 7:
+ if (!arm_feature (env, ARM_FEATURE_V7))
+ return 0;
+ return prot_ro;
default:
abort();
}
@@ -1085,6 +1095,12 @@ static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type,
if (xn && access_type == 2)
goto do_fault;
+ /* The simplified model uses AP[0] as an access control bit. */
+ if ((env->cp15.c1_sys & (1 << 29)) && (ap & 1) == 0) {
+ /* Access flag fault. */
+ code = (code == 15) ? 6 : 3;
+ goto do_fault;
+ }
*prot = check_ap(env, ap, domain, access_type, is_user);
if (!*prot) {
/* Access permission fault. */
@@ -1309,15 +1325,16 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
crm = insn & 0xf;
switch ((insn >> 16) & 0xf) {
case 0:
- if (((insn >> 21) & 7) == 2) {
- /* ??? Select cache level. Ignore. */
- return;
- }
/* ID codes. */
if (arm_feature(env, ARM_FEATURE_XSCALE))
break;
if (arm_feature(env, ARM_FEATURE_OMAPCP))
break;
+ if (arm_feature(env, ARM_FEATURE_V7)
+ && op1 == 2 && crm == 0 && op2 == 0) {
+ env->cp15.c0_cssel = val & 0xf;
+ break;
+ }
goto bad_reg;
case 1: /* System configuration. */
if (arm_feature(env, ARM_FEATURE_OMAPCP))
@@ -1636,9 +1653,22 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
goto bad_reg;
if (crm != 0)
goto bad_reg;
- if (arm_feature(env, ARM_FEATURE_XSCALE))
+ if (!arm_feature(env, ARM_FEATURE_V7))
+ return 0;
+
+ switch (op2) {
+ case 0:
+ return env->cp15.c0_ccsid[env->cp15.c0_cssel];
+ case 1:
+ return env->cp15.c0_clid;
+ case 7:
+ return 0;
+ }
+ goto bad_reg;
+ case 2:
+ if (op2 != 0 || crm != 0)
goto bad_reg;
- return 0;
+ return env->cp15.c0_cssel;
default:
goto bad_reg;
}
@@ -2304,10 +2334,13 @@ void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val)
}
set_float_rounding_mode(i, &env->vfp.fp_status);
}
+ if (changed & (1 << 24))
+ set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status);
+ if (changed & (1 << 25))
+ set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status);
i = vfp_exceptbits_to_host((val >> 8) & 0x1f);
set_float_exception_flags(i, &env->vfp.fp_status);
- /* XXX: FZ and DN are not implemented. */
}
#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
@@ -2512,7 +2545,7 @@ ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \
ftype tmp; \
tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(x), \
&env->vfp.fp_status); \
- return ftype##_scalbn(tmp, shift, &env->vfp.fp_status); \
+ return ftype##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \
} \
ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \
{ \
@@ -2585,3 +2618,12 @@ uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUState *env)
tmp = float32_scalbn(tmp, 31, s);
return float32_to_int32(tmp, s);
}
+
+void HELPER(set_teecr)(CPUState *env, uint32_t val)
+{
+ val &= 1;
+ if (env->teecr != val) {
+ env->teecr = val;
+ tb_flush(env);
+ }
+}
diff --git a/target-arm/helpers.h b/target-arm/helpers.h
index 67207cb49..01175e157 100644
--- a/target-arm/helpers.h
+++ b/target-arm/helpers.h
@@ -453,4 +453,6 @@ DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32)
DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32)
DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32)
+DEF_HELPER_2(set_teecr, void, env, i32)
+
#include "def-helper.h"
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 0650bc3a2..2b5e5c8dd 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -3001,6 +3001,10 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 21:
case 22:
case 23:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
/* Source and destination the same. */
gen_mov_F0_vreg(dp, rd);
break;
@@ -3120,22 +3124,22 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 20: /* fshto */
if (!arm_feature(env, ARM_FEATURE_VFP3))
return 1;
- gen_vfp_shto(dp, rm);
+ gen_vfp_shto(dp, 16 - rm);
break;
case 21: /* fslto */
if (!arm_feature(env, ARM_FEATURE_VFP3))
return 1;
- gen_vfp_slto(dp, rm);
+ gen_vfp_slto(dp, 32 - rm);
break;
case 22: /* fuhto */
if (!arm_feature(env, ARM_FEATURE_VFP3))
return 1;
- gen_vfp_uhto(dp, rm);
+ gen_vfp_uhto(dp, 16 - rm);
break;
case 23: /* fulto */
if (!arm_feature(env, ARM_FEATURE_VFP3))
return 1;
- gen_vfp_ulto(dp, rm);
+ gen_vfp_ulto(dp, 32 - rm);
break;
case 24: /* ftoui */
gen_vfp_toui(dp);
@@ -3152,22 +3156,22 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 28: /* ftosh */
if (!arm_feature(env, ARM_FEATURE_VFP3))
return 1;
- gen_vfp_tosh(dp, rm);
+ gen_vfp_tosh(dp, 16 - rm);
break;
case 29: /* ftosl */
if (!arm_feature(env, ARM_FEATURE_VFP3))
return 1;
- gen_vfp_tosl(dp, rm);
+ gen_vfp_tosl(dp, 32 - rm);
break;
case 30: /* ftouh */
if (!arm_feature(env, ARM_FEATURE_VFP3))
return 1;
- gen_vfp_touh(dp, rm);
+ gen_vfp_touh(dp, 16 - rm);
break;
case 31: /* ftoul */
if (!arm_feature(env, ARM_FEATURE_VFP3))
return 1;
- gen_vfp_toul(dp, rm);
+ gen_vfp_toul(dp, 32 - rm);
break;
default: /* undefined */
printf ("rn:%d\n", rn);
@@ -5532,6 +5536,71 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
return 0;
}
+static int disas_cp14_read(CPUState * env, DisasContext *s, uint32_t insn)
+{
+ int crn = (insn >> 16) & 0xf;
+ int crm = insn & 0xf;
+ int op1 = (insn >> 21) & 7;
+ int op2 = (insn >> 5) & 7;
+ int rt = (insn >> 12) & 0xf;
+ TCGv tmp;
+
+ if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
+ if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
+ /* TEECR */
+ if (IS_USER(s))
+ return 1;
+ tmp = load_cpu_field(teecr);
+ store_reg(s, rt, tmp);
+ return 0;
+ }
+ if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
+ /* TEEHBR */
+ if (IS_USER(s) && (env->teecr & 1))
+ return 1;
+ tmp = load_cpu_field(teehbr);
+ store_reg(s, rt, tmp);
+ return 0;
+ }
+ }
+ fprintf(stderr, "Unknown cp14 read op1:%d crn:%d crm:%d op2:%d\n",
+ op1, crn, crm, op2);
+ return 1;
+}
+
+static int disas_cp14_write(CPUState * env, DisasContext *s, uint32_t insn)
+{
+ int crn = (insn >> 16) & 0xf;
+ int crm = insn & 0xf;
+ int op1 = (insn >> 21) & 7;
+ int op2 = (insn >> 5) & 7;
+ int rt = (insn >> 12) & 0xf;
+ TCGv tmp;
+
+ if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
+ if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
+ /* TEECR */
+ if (IS_USER(s))
+ return 1;
+ tmp = load_reg(s, rt);
+ gen_helper_set_teecr(cpu_env, tmp);
+ dead_tmp(tmp);
+ return 0;
+ }
+ if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
+ /* TEEHBR */
+ if (IS_USER(s) && (env->teecr & 1))
+ return 1;
+ tmp = load_reg(s, rt);
+ store_cpu_field(tmp, teehbr);
+ return 0;
+ }
+ }
+ fprintf(stderr, "Unknown cp14 write op1:%d crn:%d crm:%d op2:%d\n",
+ op1, crn, crm, op2);
+ return 1;
+}
+
static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn)
{
int cpnum;
@@ -5553,9 +5622,19 @@ static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn)
case 10:
case 11:
return disas_vfp_insn (env, s, insn);
+ case 14:
+ /* Coprocessors 7-15 are architecturally reserved by ARM.
+ Unfortunately Intel decided to ignore this. */
+ if (arm_feature(env, ARM_FEATURE_XSCALE))
+ goto board;
+ if (insn & (1 << 20))
+ return disas_cp14_read(env, s, insn);
+ else
+ return disas_cp14_write(env, s, insn);
case 15:
return disas_cp15_insn (env, s, insn);
default:
+ board:
/* Unknown coprocessor. See if the board has hooked it. */
return disas_cp_insn (env, s, insn);
}
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 242ef9c10..d4328f046 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -612,7 +612,7 @@ static inline void t_gen_swapr(TCGv d, TCGv s)
tcg_gen_shli_tl(t, org_s, bitrev[0].shift);
tcg_gen_andi_tl(d, t, bitrev[0].mask);
- for (i = 1; i < sizeof bitrev / sizeof bitrev[0]; i++) {
+ for (i = 1; i < ARRAY_SIZE(bitrev); i++) {
if (bitrev[i].shift >= 0) {
tcg_gen_shli_tl(t, org_s, bitrev[i].shift);
} else {
@@ -3158,7 +3158,7 @@ cris_decoder(DisasContext *dc)
dc->postinc = EXTRACT_FIELD(dc->ir, 10, 10);
/* Large switch for all insns. */
- for (i = 0; i < sizeof decinfo / sizeof decinfo[0]; i++) {
+ for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits)
{
insn_len = decinfo[i].dec(dc);
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 1c5b85caf..1c544d766 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -278,7 +278,7 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
int family = -1, model = -1, stepping = -1;
def = NULL;
- for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) {
+ for (i = 0; i < ARRAY_SIZE(x86_defs); i++) {
if (strcmp(name, x86_defs[i].name) == 0) {
def = &x86_defs[i];
break;
@@ -368,7 +368,7 @@ void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{
unsigned int i;
- for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++)
+ for (i = 0; i < ARRAY_SIZE(x86_defs); i++)
(*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name);
}
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 86a768025..3fa0c3817 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -561,9 +561,26 @@ enum {
int cpu_mips_exec(CPUMIPSState *s);
CPUMIPSState *cpu_mips_init(const char *cpu_model);
-uint32_t cpu_mips_get_clock (void);
+//~ uint32_t cpu_mips_get_clock (void);
int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc);
+/* mips_timer.c */
+uint32_t cpu_mips_get_random (CPUState *env);
+uint32_t cpu_mips_get_count (CPUState *env);
+void cpu_mips_store_count (CPUState *env, uint32_t value);
+void cpu_mips_store_compare (CPUState *env, uint32_t value);
+void cpu_mips_start_count(CPUState *env);
+void cpu_mips_stop_count(CPUState *env);
+
+/* mips_int.c */
+void cpu_mips_update_irq (CPUState *env);
+
+/* helper.c */
+int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+ int mmu_idx, int is_softmmu);
+void do_interrupt (CPUState *env);
+void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra);
+
static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
{
env->active_tc.PC = tb->pc;
diff --git a/target-mips/exec.h b/target-mips/exec.h
index 8ab64370f..07eb62fd3 100644
--- a/target-mips/exec.h
+++ b/target-mips/exec.h
@@ -24,21 +24,6 @@ void fpu_dump_state(CPUState *env, FILE *f,
int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
int flags);
-int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
- int mmu_idx, int is_softmmu);
-void do_interrupt (CPUState *env);
-void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra);
-
-void do_raise_exception_err (uint32_t exception, int error_code);
-void do_raise_exception (uint32_t exception);
-
-uint32_t cpu_mips_get_random (CPUState *env);
-uint32_t cpu_mips_get_count (CPUState *env);
-void cpu_mips_store_count (CPUState *env, uint32_t value);
-void cpu_mips_store_compare (CPUState *env, uint32_t value);
-void cpu_mips_start_count(CPUState *env);
-void cpu_mips_stop_count(CPUState *env);
-void cpu_mips_update_irq (CPUState *env);
void cpu_mips_clock_init (CPUState *env);
void cpu_mips_tlb_flush (CPUState *env, int flush_global);
diff --git a/target-mips/helper.c b/target-mips/helper.c
index 9340ad012..283bd4d2e 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -220,10 +220,6 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
}
}
-void cpu_mips_init_mmu (CPUState *env)
-{
-}
-
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int mmu_idx, int is_softmmu)
{
diff --git a/target-mips/machine.c b/target-mips/machine.c
index 15ce73cd4..543778dc5 100644
--- a/target-mips/machine.c
+++ b/target-mips/machine.c
@@ -1,6 +1,8 @@
#include "hw/hw.h"
#include "hw/boards.h"
+#include "exec-all.h"
+
void register_machines(void)
{
qemu_register_machine(&mips_malta_machine);
@@ -10,11 +12,300 @@ void register_machines(void)
qemu_register_machine(&mips_machine);
}
+static void save_tc(QEMUFile *f, TCState *tc)
+{
+ int i;
+
+ /* Save active TC */
+ for(i = 0; i < 32; i++)
+ qemu_put_betls(f, &tc->gpr[i]);
+ qemu_put_betls(f, &tc->PC);
+ for(i = 0; i < MIPS_DSP_ACC; i++)
+ qemu_put_betls(f, &tc->HI[i]);
+ for(i = 0; i < MIPS_DSP_ACC; i++)
+ qemu_put_betls(f, &tc->LO[i]);
+ for(i = 0; i < MIPS_DSP_ACC; i++)
+ qemu_put_betls(f, &tc->ACX[i]);
+ qemu_put_betls(f, &tc->DSPControl);
+ qemu_put_sbe32s(f, &tc->CP0_TCStatus);
+ qemu_put_sbe32s(f, &tc->CP0_TCBind);
+ qemu_put_betls(f, &tc->CP0_TCHalt);
+ qemu_put_betls(f, &tc->CP0_TCContext);
+ qemu_put_betls(f, &tc->CP0_TCSchedule);
+ qemu_put_betls(f, &tc->CP0_TCScheFBack);
+ qemu_put_sbe32s(f, &tc->CP0_Debug_tcstatus);
+}
+
+static void save_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
+{
+ int i;
+
+ for(i = 0; i < 32; i++)
+ qemu_put_be64s(f, &fpu->fpr[i].d);
+ qemu_put_s8s(f, &fpu->fp_status.float_detect_tininess);
+ qemu_put_s8s(f, &fpu->fp_status.float_rounding_mode);
+ qemu_put_s8s(f, &fpu->fp_status.float_exception_flags);
+ qemu_put_be32s(f, &fpu->fcr0);
+ qemu_put_be32s(f, &fpu->fcr31);
+}
+
void cpu_save(QEMUFile *f, void *opaque)
{
+ CPUState *env = opaque;
+ int i;
+
+ /* Save active TC */
+ save_tc(f, &env->active_tc);
+
+ /* Save active FPU */
+ save_fpu(f, &env->active_fpu);
+
+ /* Save MVP */
+ qemu_put_sbe32s(f, &env->mvp->CP0_MVPControl);
+ qemu_put_sbe32s(f, &env->mvp->CP0_MVPConf0);
+ qemu_put_sbe32s(f, &env->mvp->CP0_MVPConf1);
+
+ /* Save TLB */
+ qemu_put_be32s(f, &env->tlb->nb_tlb);
+ qemu_put_be32s(f, &env->tlb->tlb_in_use);
+ for(i = 0; i < MIPS_TLB_MAX; i++) {
+ uint16_t flags = ((env->tlb->mmu.r4k.tlb[i].G << 10) |
+ (env->tlb->mmu.r4k.tlb[i].C0 << 7) |
+ (env->tlb->mmu.r4k.tlb[i].C1 << 4) |
+ (env->tlb->mmu.r4k.tlb[i].V0 << 3) |
+ (env->tlb->mmu.r4k.tlb[i].V1 << 2) |
+ (env->tlb->mmu.r4k.tlb[i].D0 << 1) |
+ (env->tlb->mmu.r4k.tlb[i].D1 << 0));
+
+ qemu_put_betls(f, &env->tlb->mmu.r4k.tlb[i].VPN);
+ qemu_put_be32s(f, &env->tlb->mmu.r4k.tlb[i].PageMask);
+ qemu_put_8s(f, &env->tlb->mmu.r4k.tlb[i].ASID);
+ qemu_put_be16s(f, &flags);
+ qemu_put_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[0]);
+ qemu_put_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[1]);
+ }
+
+ /* Save CPU metastate */
+ qemu_put_be32s(f, &env->current_tc);
+ qemu_put_be32s(f, &env->current_fpu);
+ qemu_put_sbe32s(f, &env->error_code);
+ qemu_put_be32s(f, &env->hflags);
+ qemu_put_betls(f, &env->btarget);
+ qemu_put_sbe32s(f, &env->bcond);
+
+ /* Save remaining CP1 registers */
+ qemu_put_sbe32s(f, &env->CP0_Index);
+ qemu_put_sbe32s(f, &env->CP0_Random);
+ qemu_put_sbe32s(f, &env->CP0_VPEControl);
+ qemu_put_sbe32s(f, &env->CP0_VPEConf0);
+ qemu_put_sbe32s(f, &env->CP0_VPEConf1);
+ qemu_put_betls(f, &env->CP0_YQMask);
+ qemu_put_betls(f, &env->CP0_VPESchedule);
+ qemu_put_betls(f, &env->CP0_VPEScheFBack);
+ qemu_put_sbe32s(f, &env->CP0_VPEOpt);
+ qemu_put_betls(f, &env->CP0_EntryLo0);
+ qemu_put_betls(f, &env->CP0_EntryLo1);
+ qemu_put_betls(f, &env->CP0_Context);
+ qemu_put_sbe32s(f, &env->CP0_PageMask);
+ qemu_put_sbe32s(f, &env->CP0_PageGrain);
+ qemu_put_sbe32s(f, &env->CP0_Wired);
+ qemu_put_sbe32s(f, &env->CP0_SRSConf0);
+ qemu_put_sbe32s(f, &env->CP0_SRSConf1);
+ qemu_put_sbe32s(f, &env->CP0_SRSConf2);
+ qemu_put_sbe32s(f, &env->CP0_SRSConf3);
+ qemu_put_sbe32s(f, &env->CP0_SRSConf4);
+ qemu_put_sbe32s(f, &env->CP0_HWREna);
+ qemu_put_betls(f, &env->CP0_BadVAddr);
+ qemu_put_sbe32s(f, &env->CP0_Count);
+ qemu_put_betls(f, &env->CP0_EntryHi);
+ qemu_put_sbe32s(f, &env->CP0_Compare);
+ qemu_put_sbe32s(f, &env->CP0_Status);
+ qemu_put_sbe32s(f, &env->CP0_IntCtl);
+ qemu_put_sbe32s(f, &env->CP0_SRSCtl);
+ qemu_put_sbe32s(f, &env->CP0_SRSMap);
+ qemu_put_sbe32s(f, &env->CP0_Cause);
+ qemu_put_betls(f, &env->CP0_EPC);
+ qemu_put_sbe32s(f, &env->CP0_PRid);
+ qemu_put_sbe32s(f, &env->CP0_EBase);
+ qemu_put_sbe32s(f, &env->CP0_Config0);
+ qemu_put_sbe32s(f, &env->CP0_Config1);
+ qemu_put_sbe32s(f, &env->CP0_Config2);
+ qemu_put_sbe32s(f, &env->CP0_Config3);
+ qemu_put_sbe32s(f, &env->CP0_Config6);
+ qemu_put_sbe32s(f, &env->CP0_Config7);
+ qemu_put_betls(f, &env->CP0_LLAddr);
+ for(i = 0; i < 8; i++)
+ qemu_put_betls(f, &env->CP0_WatchLo[i]);
+ for(i = 0; i < 8; i++)
+ qemu_put_sbe32s(f, &env->CP0_WatchHi[i]);
+ qemu_put_betls(f, &env->CP0_XContext);
+ qemu_put_sbe32s(f, &env->CP0_Framemask);
+ qemu_put_sbe32s(f, &env->CP0_Debug);
+ qemu_put_betls(f, &env->CP0_DEPC);
+ qemu_put_sbe32s(f, &env->CP0_Performance0);
+ qemu_put_sbe32s(f, &env->CP0_TagLo);
+ qemu_put_sbe32s(f, &env->CP0_DataLo);
+ qemu_put_sbe32s(f, &env->CP0_TagHi);
+ qemu_put_sbe32s(f, &env->CP0_DataHi);
+ qemu_put_betls(f, &env->CP0_ErrorEPC);
+ qemu_put_sbe32s(f, &env->CP0_DESAVE);
+
+ /* Save inactive TC state */
+ for (i = 0; i < MIPS_SHADOW_SET_MAX; i++)
+ save_tc(f, &env->tcs[i]);
+ for (i = 0; i < MIPS_FPU_MAX; i++)
+ save_fpu(f, &env->fpus[i]);
+}
+
+static void load_tc(QEMUFile *f, TCState *tc)
+{
+ int i;
+
+ /* Save active TC */
+ for(i = 0; i < 32; i++)
+ qemu_get_betls(f, &tc->gpr[i]);
+ qemu_get_betls(f, &tc->PC);
+ for(i = 0; i < MIPS_DSP_ACC; i++)
+ qemu_get_betls(f, &tc->HI[i]);
+ for(i = 0; i < MIPS_DSP_ACC; i++)
+ qemu_get_betls(f, &tc->LO[i]);
+ for(i = 0; i < MIPS_DSP_ACC; i++)
+ qemu_get_betls(f, &tc->ACX[i]);
+ qemu_get_betls(f, &tc->DSPControl);
+ qemu_get_sbe32s(f, &tc->CP0_TCStatus);
+ qemu_get_sbe32s(f, &tc->CP0_TCBind);
+ qemu_get_betls(f, &tc->CP0_TCHalt);
+ qemu_get_betls(f, &tc->CP0_TCContext);
+ qemu_get_betls(f, &tc->CP0_TCSchedule);
+ qemu_get_betls(f, &tc->CP0_TCScheFBack);
+ qemu_get_sbe32s(f, &tc->CP0_Debug_tcstatus);
+}
+
+static void load_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
+{
+ int i;
+
+ for(i = 0; i < 32; i++)
+ qemu_get_be64s(f, &fpu->fpr[i].d);
+ qemu_get_s8s(f, &fpu->fp_status.float_detect_tininess);
+ qemu_get_s8s(f, &fpu->fp_status.float_rounding_mode);
+ qemu_get_s8s(f, &fpu->fp_status.float_exception_flags);
+ qemu_get_be32s(f, &fpu->fcr0);
+ qemu_get_be32s(f, &fpu->fcr31);
}
int cpu_load(QEMUFile *f, void *opaque, int version_id)
{
+ CPUState *env = opaque;
+ int i;
+
+ if (version_id != 3)
+ return -EINVAL;
+
+ /* Load active TC */
+ load_tc(f, &env->active_tc);
+
+ /* Load active FPU */
+ load_fpu(f, &env->active_fpu);
+
+ /* Load MVP */
+ qemu_get_sbe32s(f, &env->mvp->CP0_MVPControl);
+ qemu_get_sbe32s(f, &env->mvp->CP0_MVPConf0);
+ qemu_get_sbe32s(f, &env->mvp->CP0_MVPConf1);
+
+ /* Load TLB */
+ qemu_get_be32s(f, &env->tlb->nb_tlb);
+ qemu_get_be32s(f, &env->tlb->tlb_in_use);
+ for(i = 0; i < MIPS_TLB_MAX; i++) {
+ uint16_t flags;
+
+ qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].VPN);
+ qemu_get_be32s(f, &env->tlb->mmu.r4k.tlb[i].PageMask);
+ qemu_get_8s(f, &env->tlb->mmu.r4k.tlb[i].ASID);
+ qemu_get_be16s(f, &flags);
+ env->tlb->mmu.r4k.tlb[i].G = (flags >> 10) & 1;
+ env->tlb->mmu.r4k.tlb[i].C0 = (flags >> 7) & 3;
+ env->tlb->mmu.r4k.tlb[i].C1 = (flags >> 4) & 3;
+ env->tlb->mmu.r4k.tlb[i].V0 = (flags >> 3) & 1;
+ env->tlb->mmu.r4k.tlb[i].V1 = (flags >> 2) & 1;
+ env->tlb->mmu.r4k.tlb[i].D0 = (flags >> 1) & 1;
+ env->tlb->mmu.r4k.tlb[i].D1 = (flags >> 0) & 1;
+ qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[0]);
+ qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[1]);
+ }
+
+ /* Load CPU metastate */
+ qemu_get_be32s(f, &env->current_tc);
+ qemu_get_be32s(f, &env->current_fpu);
+ qemu_get_sbe32s(f, &env->error_code);
+ qemu_get_be32s(f, &env->hflags);
+ qemu_get_betls(f, &env->btarget);
+ qemu_get_sbe32s(f, &env->bcond);
+
+ /* Load remaining CP1 registers */
+ qemu_get_sbe32s(f, &env->CP0_Index);
+ qemu_get_sbe32s(f, &env->CP0_Random);
+ qemu_get_sbe32s(f, &env->CP0_VPEControl);
+ qemu_get_sbe32s(f, &env->CP0_VPEConf0);
+ qemu_get_sbe32s(f, &env->CP0_VPEConf1);
+ qemu_get_betls(f, &env->CP0_YQMask);
+ qemu_get_betls(f, &env->CP0_VPESchedule);
+ qemu_get_betls(f, &env->CP0_VPEScheFBack);
+ qemu_get_sbe32s(f, &env->CP0_VPEOpt);
+ qemu_get_betls(f, &env->CP0_EntryLo0);
+ qemu_get_betls(f, &env->CP0_EntryLo1);
+ qemu_get_betls(f, &env->CP0_Context);
+ qemu_get_sbe32s(f, &env->CP0_PageMask);
+ qemu_get_sbe32s(f, &env->CP0_PageGrain);
+ qemu_get_sbe32s(f, &env->CP0_Wired);
+ qemu_get_sbe32s(f, &env->CP0_SRSConf0);
+ qemu_get_sbe32s(f, &env->CP0_SRSConf1);
+ qemu_get_sbe32s(f, &env->CP0_SRSConf2);
+ qemu_get_sbe32s(f, &env->CP0_SRSConf3);
+ qemu_get_sbe32s(f, &env->CP0_SRSConf4);
+ qemu_get_sbe32s(f, &env->CP0_HWREna);
+ qemu_get_betls(f, &env->CP0_BadVAddr);
+ qemu_get_sbe32s(f, &env->CP0_Count);
+ qemu_get_betls(f, &env->CP0_EntryHi);
+ qemu_get_sbe32s(f, &env->CP0_Compare);
+ qemu_get_sbe32s(f, &env->CP0_Status);
+ qemu_get_sbe32s(f, &env->CP0_IntCtl);
+ qemu_get_sbe32s(f, &env->CP0_SRSCtl);
+ qemu_get_sbe32s(f, &env->CP0_SRSMap);
+ qemu_get_sbe32s(f, &env->CP0_Cause);
+ qemu_get_betls(f, &env->CP0_EPC);
+ qemu_get_sbe32s(f, &env->CP0_PRid);
+ qemu_get_sbe32s(f, &env->CP0_EBase);
+ qemu_get_sbe32s(f, &env->CP0_Config0);
+ qemu_get_sbe32s(f, &env->CP0_Config1);
+ qemu_get_sbe32s(f, &env->CP0_Config2);
+ qemu_get_sbe32s(f, &env->CP0_Config3);
+ qemu_get_sbe32s(f, &env->CP0_Config6);
+ qemu_get_sbe32s(f, &env->CP0_Config7);
+ qemu_get_betls(f, &env->CP0_LLAddr);
+ for(i = 0; i < 8; i++)
+ qemu_get_betls(f, &env->CP0_WatchLo[i]);
+ for(i = 0; i < 8; i++)
+ qemu_get_sbe32s(f, &env->CP0_WatchHi[i]);
+ qemu_get_betls(f, &env->CP0_XContext);
+ qemu_get_sbe32s(f, &env->CP0_Framemask);
+ qemu_get_sbe32s(f, &env->CP0_Debug);
+ qemu_get_betls(f, &env->CP0_DEPC);
+ qemu_get_sbe32s(f, &env->CP0_Performance0);
+ qemu_get_sbe32s(f, &env->CP0_TagLo);
+ qemu_get_sbe32s(f, &env->CP0_DataLo);
+ qemu_get_sbe32s(f, &env->CP0_TagHi);
+ qemu_get_sbe32s(f, &env->CP0_DataHi);
+ qemu_get_betls(f, &env->CP0_ErrorEPC);
+ qemu_get_sbe32s(f, &env->CP0_DESAVE);
+
+ /* Load inactive TC state */
+ for (i = 0; i < MIPS_SHADOW_SET_MAX; i++)
+ load_tc(f, &env->tcs[i]);
+ for (i = 0; i < MIPS_FPU_MAX; i++)
+ load_fpu(f, &env->fpus[i]);
+
+ /* XXX: ensure compatiblity for halted bit ? */
+ tlb_flush(env, 1);
return 0;
}
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 27f58c2be..4433fde25 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -54,7 +54,8 @@ void do_interrupt_restart (void)
}
}
-void do_restore_state (void *pc_ptr)
+#if !defined(CONFIG_USER_ONLY)
+static void do_restore_state (void *pc_ptr)
{
TranslationBlock *tb;
unsigned long pc = (unsigned long) pc_ptr;
@@ -64,6 +65,7 @@ void do_restore_state (void *pc_ptr)
cpu_restore_state (tb, env, pc, NULL);
}
}
+#endif
target_ulong do_clo (target_ulong t0)
{
@@ -1356,7 +1358,6 @@ void do_mtc0_status_irqraise_debug(void)
{
fprintf(logfile, "Raise pending IRQs\n");
}
-#endif /* !CONFIG_USER_ONLY */
/* MIPS MT functions */
target_ulong do_mftgpr(uint32_t sel)
@@ -1495,6 +1496,7 @@ target_ulong do_evpe(target_ulong t0)
return t0;
}
+#endif /* !CONFIG_USER_ONLY */
void do_fork(target_ulong t0, target_ulong t1)
{
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index 0026cd06f..5041d70b3 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -421,7 +421,7 @@ static const mips_def_t *cpu_mips_find_by_name (const char *name)
{
int i;
- for (i = 0; i < sizeof(mips_defs) / sizeof(mips_defs[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(mips_defs); i++) {
if (strcasecmp(name, mips_defs[i].name) == 0) {
return &mips_defs[i];
}
@@ -433,7 +433,7 @@ void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{
int i;
- for (i = 0; i < sizeof(mips_defs) / sizeof(mips_defs[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(mips_defs); i++) {
(*cpu_fprintf)(f, "MIPS '%s'\n",
mips_defs[i].name);
}
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 2c565e656..221f516c6 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -603,7 +603,7 @@ struct CPUPPCState {
ppc_avr_t avr[32];
uint32_t vscr;
/* SPE registers */
- target_ulong spe_acc;
+ uint64_t spe_acc;
float_status spe_status;
uint32_t spe_fscr;
diff --git a/target-ppc/exec.h b/target-ppc/exec.h
index e9c7e65fc..8db2bfa2a 100644
--- a/target-ppc/exec.h
+++ b/target-ppc/exec.h
@@ -27,12 +27,10 @@
#include "cpu.h"
#include "exec-all.h"
-/* For normal operations, precise emulation should not be needed */
-//#define USE_PRECISE_EMULATION 1
-#define USE_PRECISE_EMULATION 0
+/* Precise emulation is needed to correctly emulate exception flags */
+#define USE_PRECISE_EMULATION 1
register struct CPUPPCState *env asm(AREG0);
-#define TDX "%016" PRIx64
#if !defined(CONFIG_USER_ONLY)
#include "softmmu_exec.h"
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 7a08f4ba7..4676d50d8 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -29,7 +29,7 @@
#include "exec-all.h"
#include "helper_regs.h"
#include "qemu-common.h"
-#include "qemu-kvm.h"
+#include "kvm.h"
//#define DEBUG_MMU
//#define DEBUG_BATS
@@ -2921,8 +2921,10 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model)
env->cpu_model_str = cpu_model;
cpu_ppc_register_internal(env, def);
cpu_ppc_reset(env);
+
if (kvm_enabled())
- kvm_init_vcpu(env);
+ kvm_init_vcpu(env);
+
return env;
}
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
new file mode 100644
index 000000000..acbb1abd2
--- /dev/null
+++ b/target-ppc/kvm.c
@@ -0,0 +1,204 @@
+/*
+ * PowerPC implementation of KVM hooks
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ * Jerone Young <jyoung5@us.ibm.com>
+ * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ * Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <linux/kvm.h>
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
+#include "cpu.h"
+#include "device_tree.h"
+
+//#define DEBUG_KVM
+
+#ifdef DEBUG_KVM
+#define dprintf(fmt, ...) \
+ do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+ do { } while (0)
+#endif
+
+int kvm_arch_init(KVMState *s, int smp_cpus)
+{
+ return 0;
+}
+
+int kvm_arch_init_vcpu(CPUState *cenv)
+{
+ return 0;
+}
+
+int kvm_arch_put_registers(CPUState *env)
+{
+ struct kvm_regs regs;
+ int ret;
+ int i;
+
+ ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
+ if (ret < 0)
+ return ret;
+
+ regs.ctr = env->ctr;
+ regs.lr = env->lr;
+ regs.xer = env->xer;
+ regs.msr = env->msr;
+ regs.pc = env->nip;
+
+ regs.srr0 = env->spr[SPR_SRR0];
+ regs.srr1 = env->spr[SPR_SRR1];
+
+ regs.sprg0 = env->spr[SPR_SPRG0];
+ regs.sprg1 = env->spr[SPR_SPRG1];
+ regs.sprg2 = env->spr[SPR_SPRG2];
+ regs.sprg3 = env->spr[SPR_SPRG3];
+ regs.sprg4 = env->spr[SPR_SPRG4];
+ regs.sprg5 = env->spr[SPR_SPRG5];
+ regs.sprg6 = env->spr[SPR_SPRG6];
+ regs.sprg7 = env->spr[SPR_SPRG7];
+
+ for (i = 0;i < 32; i++)
+ regs.gpr[i] = env->gpr[i];
+
+ ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, &regs);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+int kvm_arch_get_registers(CPUState *env)
+{
+ struct kvm_regs regs;
+ uint32_t i, ret;
+
+ ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
+ if (ret < 0)
+ return ret;
+
+ env->ctr = regs.ctr;
+ env->lr = regs.lr;
+ env->xer = regs.xer;
+ env->msr = regs.msr;
+ env->nip = regs.pc;
+
+ env->spr[SPR_SRR0] = regs.srr0;
+ env->spr[SPR_SRR1] = regs.srr1;
+
+ env->spr[SPR_SPRG0] = regs.sprg0;
+ env->spr[SPR_SPRG1] = regs.sprg1;
+ env->spr[SPR_SPRG2] = regs.sprg2;
+ env->spr[SPR_SPRG3] = regs.sprg3;
+ env->spr[SPR_SPRG4] = regs.sprg4;
+ env->spr[SPR_SPRG5] = regs.sprg5;
+ env->spr[SPR_SPRG6] = regs.sprg6;
+ env->spr[SPR_SPRG7] = regs.sprg7;
+
+ for (i = 0;i < 32; i++)
+ env->gpr[i] = regs.gpr[i];
+
+ return 0;
+}
+
+int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
+{
+ int r;
+ unsigned irq;
+
+ /* PowerPC Qemu tracks the various core input pins (interrupt, critical
+ * interrupt, reset, etc) in PPC-specific env->irq_input_state. */
+ if (run->ready_for_interrupt_injection &&
+ (env->interrupt_request & CPU_INTERRUPT_HARD) &&
+ (env->irq_input_state & (1<<PPC40x_INPUT_INT)))
+ {
+ /* For now KVM disregards the 'irq' argument. However, in the
+ * future KVM could cache it in-kernel to avoid a heavyweight exit
+ * when reading the UIC.
+ */
+ irq = -1U;
+
+ dprintf("injected interrupt %d\n", irq);
+ r = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &irq);
+ if (r < 0)
+ printf("cpu %d fail inject %x\n", env->cpu_index, irq);
+ }
+
+ /* We don't know if there are more interrupts pending after this. However,
+ * the guest will return to userspace in the course of handling this one
+ * anyways, so we will get a chance to deliver the rest. */
+ return 0;
+}
+
+int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
+{
+ return 0;
+}
+
+static int kvmppc_handle_halt(CPUState *env)
+{
+ if (!(env->interrupt_request & CPU_INTERRUPT_HARD) && (msr_ee)) {
+ env->halted = 1;
+ env->exception_index = EXCP_HLT;
+ }
+
+ return 1;
+}
+
+/* map dcr access to existing qemu dcr emulation */
+static int kvmppc_handle_dcr_read(CPUState *env, uint32_t dcrn, uint32_t *data)
+{
+ if (ppc_dcr_read(env->dcr_env, dcrn, data) < 0)
+ fprintf(stderr, "Read to unhandled DCR (0x%x)\n", dcrn);
+
+ return 1;
+}
+
+static int kvmppc_handle_dcr_write(CPUState *env, uint32_t dcrn, uint32_t data)
+{
+ if (ppc_dcr_write(env->dcr_env, dcrn, data) < 0)
+ fprintf(stderr, "Write to unhandled DCR (0x%x)\n", dcrn);
+
+ return 1;
+}
+
+int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
+{
+ int ret = 0;
+
+ switch (run->exit_reason) {
+ case KVM_EXIT_DCR:
+ if (run->dcr.is_write) {
+ dprintf("handle dcr write\n");
+ ret = kvmppc_handle_dcr_write(env, run->dcr.dcrn, run->dcr.data);
+ } else {
+ dprintf("handle dcr read\n");
+ ret = kvmppc_handle_dcr_read(env, run->dcr.dcrn, &run->dcr.data);
+ }
+ break;
+ case KVM_EXIT_HLT:
+ dprintf("handle halt\n");
+ ret = kvmppc_handle_halt(env);
+ break;
+ }
+
+ return ret;
+}
+
diff --git a/target-ppc/kvm_ppc.c b/target-ppc/kvm_ppc.c
new file mode 100644
index 000000000..0caa5b98c
--- /dev/null
+++ b/target-ppc/kvm_ppc.c
@@ -0,0 +1,110 @@
+/*
+ * PowerPC KVM support
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors:
+ * Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu-timer.h"
+#include "kvm_ppc.h"
+#include "device_tree.h"
+
+#define PROC_DEVTREE_PATH "/proc/device-tree"
+
+static QEMUTimer *kvmppc_timer;
+static unsigned int kvmppc_timer_rate;
+
+#ifdef HAVE_FDT
+static int kvmppc_read_host_property(const char *node_path, const char *prop,
+ void *val, size_t len)
+{
+ char *path;
+ FILE *f;
+ int ret;
+ int pathlen;
+
+ pathlen = snprintf(NULL, 0, "%s/%s/%s", PROC_DEVTREE_PATH, node_path, prop)
+ + 1;
+ path = qemu_malloc(pathlen);
+ if (path == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ snprintf(path, pathlen, "%s/%s/%s", PROC_DEVTREE_PATH, node_path, prop);
+
+ f = fopen(path, "rb");
+ if (f == NULL) {
+ ret = errno;
+ goto free;
+ }
+
+ len = fread(val, len, 1, f);
+ if (len != 1) {
+ ret = ferror(f);
+ goto close;
+ }
+
+close:
+ fclose(f);
+free:
+ free(path);
+out:
+ return ret;
+}
+
+static int kvmppc_copy_host_cell(void *fdt, const char *node, const char *prop)
+{
+ uint32_t cell;
+ int ret;
+
+ ret = kvmppc_read_host_property(node, prop, &cell, sizeof(cell));
+ if (ret < 0) {
+ fprintf(stderr, "couldn't read host %s/%s\n", node, prop);
+ goto out;
+ }
+
+ ret = qemu_devtree_setprop_cell(fdt, node, prop, cell);
+ if (ret < 0) {
+ fprintf(stderr, "couldn't set guest %s/%s\n", node, prop);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+void kvmppc_fdt_update(void *fdt)
+{
+ /* Copy data from the host device tree into the guest. Since the guest can
+ * directly access the timebase without host involvement, we must expose
+ * the correct frequencies. */
+ kvmppc_copy_host_cell(fdt, "/cpus/cpu@0", "clock-frequency");
+ kvmppc_copy_host_cell(fdt, "/cpus/cpu@0", "timebase-frequency");
+}
+#endif
+
+static void kvmppc_timer_hack(void *opaque)
+{
+ qemu_service_io();
+ qemu_mod_timer(kvmppc_timer, qemu_get_clock(vm_clock) + kvmppc_timer_rate);
+}
+
+void kvmppc_init(void)
+{
+ /* XXX The only reason KVM yields control back to qemu is device IO. Since
+ * an idle guest does no IO, qemu's device model will never get a chance to
+ * run. So, until Qemu gains IO threads, we create this timer to ensure
+ * that the device model gets a chance to run. */
+ kvmppc_timer_rate = ticks_per_sec / 10;
+ kvmppc_timer = qemu_new_timer(vm_clock, &kvmppc_timer_hack, NULL);
+ qemu_mod_timer(kvmppc_timer, qemu_get_clock(vm_clock) + kvmppc_timer_rate);
+}
+
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
new file mode 100644
index 000000000..e536a881e
--- /dev/null
+++ b/target-ppc/kvm_ppc.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2008 IBM Corporation.
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#ifndef __KVM_PPC_H__
+#define __KVM_PPC_H__
+
+void kvmppc_init(void);
+void kvmppc_fdt_update(void *fdt);
+
+#endif /* __KVM_PPC_H__ */
diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index be0cbe1c2..ea2257b1c 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -8,6 +8,7 @@ void register_machines(void)
qemu_register_machine(&prep_machine);
qemu_register_machine(&ref405ep_machine);
qemu_register_machine(&taihu_machine);
+ qemu_register_machine(&bamboo_machine);
}
void cpu_save(QEMUFile *f, void *opaque)
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 7cd589a1e..1b0fe7e98 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -554,15 +554,6 @@ uint32_t helper_float64_to_float32(uint64_t arg)
return f.l;
}
-static always_inline int fpisneg (float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- return u.ll >> 63 != 0;
-}
-
static always_inline int isden (float64 d)
{
CPU_DoubleU u;
@@ -572,53 +563,13 @@ static always_inline int isden (float64 d)
return ((u.ll >> 52) & 0x7FF) == 0;
}
-static always_inline int iszero (float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- return (u.ll & ~0x8000000000000000ULL) == 0;
-}
-
-static always_inline int isinfinity (float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- return ((u.ll >> 52) & 0x7FF) == 0x7FF &&
- (u.ll & 0x000FFFFFFFFFFFFFULL) == 0;
-}
-
-#ifdef CONFIG_SOFTFLOAT
-static always_inline int isfinite (float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- return (((u.ll >> 52) & 0x7FF) != 0x7FF);
-}
-
-static always_inline int isnormal (float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- uint32_t exp = (u.ll >> 52) & 0x7FF;
- return ((0 < exp) && (exp < 0x7FF));
-}
-#endif
-
uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
{
CPU_DoubleU farg;
int isneg;
int ret;
farg.ll = arg;
- isneg = fpisneg(farg.d);
+ isneg = float64_is_neg(farg.d);
if (unlikely(float64_is_nan(farg.d))) {
if (float64_is_signaling_nan(farg.d)) {
/* Signaling NaN: flags are undefined */
@@ -627,14 +578,14 @@ uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
/* Quiet NaN */
ret = 0x11;
}
- } else if (unlikely(isinfinity(farg.d))) {
+ } else if (unlikely(float64_is_infinity(farg.d))) {
/* +/- infinity */
if (isneg)
ret = 0x09;
else
ret = 0x05;
} else {
- if (iszero(farg.d)) {
+ if (float64_is_zero(farg.d)) {
/* +/- zero */
if (isneg)
ret = 0x12;
@@ -671,15 +622,13 @@ static always_inline uint64_t fload_invalid_op_excp (int op)
int ve;
ve = fpscr_ve;
- if (op & POWERPC_EXCP_FP_VXSNAN) {
- /* Operation on signaling NaN */
+ switch (op) {
+ case POWERPC_EXCP_FP_VXSNAN:
env->fpscr |= 1 << FPSCR_VXSNAN;
- }
- if (op & POWERPC_EXCP_FP_VXSOFT) {
- /* Software-defined condition */
+ break;
+ case POWERPC_EXCP_FP_VXSOFT:
env->fpscr |= 1 << FPSCR_VXSOFT;
- }
- switch (op & ~(POWERPC_EXCP_FP_VXSOFT | POWERPC_EXCP_FP_VXSNAN)) {
+ break;
case POWERPC_EXCP_FP_VXISI:
/* Magnitude subtraction of infinities */
env->fpscr |= 1 << FPSCR_VXISI;
@@ -718,7 +667,7 @@ static always_inline uint64_t fload_invalid_op_excp (int op)
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
if (ve == 0) {
/* Set the result to quiet NaN */
- ret = UINT64_MAX;
+ ret = 0xFFF8000000000000ULL;
env->fpscr &= ~(0xF << FPSCR_FPCC);
env->fpscr |= 0x11 << FPSCR_FPCC;
}
@@ -729,7 +678,7 @@ static always_inline uint64_t fload_invalid_op_excp (int op)
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
if (ve == 0) {
/* Set the result to quiet NaN */
- ret = UINT64_MAX;
+ ret = 0xFFF8000000000000ULL;
env->fpscr &= ~(0xF << FPSCR_FPCC);
env->fpscr |= 0x11 << FPSCR_FPCC;
}
@@ -748,7 +697,7 @@ static always_inline uint64_t fload_invalid_op_excp (int op)
return ret;
}
-static always_inline uint64_t float_zero_divide_excp (uint64_t arg1, uint64_t arg2)
+static always_inline void float_zero_divide_excp (void)
{
env->fpscr |= 1 << FPSCR_ZX;
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
@@ -761,12 +710,7 @@ static always_inline uint64_t float_zero_divide_excp (uint64_t arg1, uint64_t ar
helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
}
- } else {
- /* Set the result to infinity */
- arg1 = ((arg1 ^ arg2) & 0x8000000000000000ULL);
- arg1 |= 0x7FFULL << 52;
}
- return arg1;
}
static always_inline void float_overflow_excp (void)
@@ -1020,7 +964,9 @@ void helper_float_check_status (void)
helper_raise_exception_err(env->exception_index, env->error_code);
} else {
int status = get_float_exception_flags(&env->fp_status);
- if (status & float_flag_overflow) {
+ if (status & float_flag_divbyzero) {
+ float_zero_divide_excp();
+ } else if (status & float_flag_overflow) {
float_overflow_excp();
} else if (status & float_flag_underflow) {
float_underflow_excp();
@@ -1057,12 +1003,12 @@ uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
float64_is_signaling_nan(farg2.d))) {
/* sNaN addition */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (likely(isfinite(farg1.d) || isfinite(farg2.d) ||
- fpisneg(farg1.d) == fpisneg(farg2.d))) {
- farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
- } else {
+ } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
+ float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
/* Magnitude subtraction of infinities */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
}
#else
farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
@@ -1083,12 +1029,12 @@ uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
float64_is_signaling_nan(farg2.d))) {
/* sNaN subtraction */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (likely(isfinite(farg1.d) || isfinite(farg2.d) ||
- fpisneg(farg1.d) != fpisneg(farg2.d))) {
- farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
- } else {
+ } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
+ float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
/* Magnitude subtraction of infinities */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
}
}
#else
@@ -1109,8 +1055,8 @@ uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
float64_is_signaling_nan(farg2.d))) {
/* sNaN multiplication */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely((isinfinity(farg1.d) && iszero(farg2.d)) ||
- (iszero(farg1.d) && isinfinity(farg2.d)))) {
+ } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
} else {
@@ -1134,17 +1080,12 @@ uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
float64_is_signaling_nan(farg2.d))) {
/* sNaN division */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(isinfinity(farg1.d) && isinfinity(farg2.d))) {
+ } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
/* Division of infinity by infinity */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
- } else if (unlikely(iszero(farg2.d))) {
- if (iszero(farg1.d)) {
- /* Division of zero by zero */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
- } else {
- /* Division by zero */
- farg1.ll = float_zero_divide_excp(farg1.d, farg2.d);
- }
+ } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
+ /* Division of zero by zero */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
} else {
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
}
@@ -1194,7 +1135,7 @@ uint64_t helper_fctiw (uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
+ } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
@@ -1218,7 +1159,7 @@ uint64_t helper_fctiwz (uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
+ } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
@@ -1251,7 +1192,7 @@ uint64_t helper_fctid (uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
+ } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
@@ -1269,7 +1210,7 @@ uint64_t helper_fctidz (uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
+ } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
@@ -1288,7 +1229,7 @@ static always_inline uint64_t do_fri (uint64_t arg, int rounding_mode)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN round */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
+ } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
/* qNan / infinity round */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
@@ -1334,6 +1275,10 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
} else {
#ifdef FLOAT128
/* This is the way the PowerPC specification defines it */
@@ -1342,9 +1287,15 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
+ float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+ ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
+ farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ }
#else
/* This is OK on x86 hosts */
farg1.d = (farg1.d * farg2.d) + farg3.d;
@@ -1371,6 +1322,10 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
} else {
#ifdef FLOAT128
/* This is the way the PowerPC specification defines it */
@@ -1379,9 +1334,15 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
+ float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+ ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
+ farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ }
#else
/* This is OK on x86 hosts */
farg1.d = (farg1.d * farg2.d) - farg3.d;
@@ -1408,6 +1369,10 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
} else {
#if USE_PRECISE_EMULATION
#ifdef FLOAT128
@@ -1417,9 +1382,15 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
- farg1.d= float128_to_float64(ft0_128, &env->fp_status);
+ if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
+ float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+ ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
+ farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ }
#else
/* This is OK on x86 hosts */
farg1.d = (farg1.d * farg2.d) + farg3.d;
@@ -1448,6 +1419,10 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
} else {
#if USE_PRECISE_EMULATION
#ifdef FLOAT128
@@ -1457,9 +1432,15 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
+ float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+ ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
+ farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ }
#else
/* This is OK on x86 hosts */
farg1.d = (farg1.d * farg2.d) - farg3.d;
@@ -1505,7 +1486,7 @@ uint64_t helper_fsqrt (uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN square root */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(fpisneg(farg.d) && !iszero(farg.d))) {
+ } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Square root of a negative nonzero number */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
} else {
@@ -1517,29 +1498,15 @@ uint64_t helper_fsqrt (uint64_t arg)
/* fre - fre. */
uint64_t helper_fre (uint64_t arg)
{
- CPU_DoubleU farg;
+ CPU_DoubleU fone, farg;
+ fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(iszero(farg.d))) {
- /* Zero reciprocal */
- farg.ll = float_zero_divide_excp(1.0, farg.d);
- } else if (likely(isnormal(farg.d))) {
- farg.d = float64_div(1.0, farg.d, &env->fp_status);
} else {
- if (farg.ll == 0x8000000000000000ULL) {
- farg.ll = 0xFFF0000000000000ULL;
- } else if (farg.ll == 0x0000000000000000ULL) {
- farg.ll = 0x7FF0000000000000ULL;
- } else if (float64_is_nan(farg.d)) {
- farg.ll = 0x7FF8000000000000ULL;
- } else if (fpisneg(farg.d)) {
- farg.ll = 0x8000000000000000ULL;
- } else {
- farg.ll = 0x0000000000000000ULL;
- }
+ farg.d = float64_div(fone.d, farg.d, &env->fp_status);
}
return farg.d;
}
@@ -1547,34 +1514,18 @@ uint64_t helper_fre (uint64_t arg)
/* fres - fres. */
uint64_t helper_fres (uint64_t arg)
{
- CPU_DoubleU farg;
+ CPU_DoubleU fone, farg;
+ float32 f32;
+ fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(iszero(farg.d))) {
- /* Zero reciprocal */
- farg.ll = float_zero_divide_excp(1.0, farg.d);
- } else if (likely(isnormal(farg.d))) {
-#if USE_PRECISE_EMULATION
- farg.d = float64_div(1.0, farg.d, &env->fp_status);
- farg.d = float64_to_float32(farg.d, &env->fp_status);
-#else
- farg.d = float32_div(1.0, farg.d, &env->fp_status);
-#endif
} else {
- if (farg.ll == 0x8000000000000000ULL) {
- farg.ll = 0xFFF0000000000000ULL;
- } else if (farg.ll == 0x0000000000000000ULL) {
- farg.ll = 0x7FF0000000000000ULL;
- } else if (float64_is_nan(farg.d)) {
- farg.ll = 0x7FF8000000000000ULL;
- } else if (fpisneg(farg.d)) {
- farg.ll = 0x8000000000000000ULL;
- } else {
- farg.ll = 0x0000000000000000ULL;
- }
+ farg.d = float64_div(fone.d, farg.d, &env->fp_status);
+ f32 = float64_to_float32(farg.d, &env->fp_status);
+ farg.d = float32_to_float64(f32, &env->fp_status);
}
return farg.ll;
}
@@ -1582,30 +1533,22 @@ uint64_t helper_fres (uint64_t arg)
/* frsqrte - frsqrte. */
uint64_t helper_frsqrte (uint64_t arg)
{
- CPU_DoubleU farg;
+ CPU_DoubleU fone, farg;
+ float32 f32;
+ fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal square root */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- } else if (unlikely(fpisneg(farg.d) && !iszero(farg.d))) {
+ } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Reciprocal square root of a negative nonzero number */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
- } else if (likely(isnormal(farg.d))) {
- farg.d = float64_sqrt(farg.d, &env->fp_status);
- farg.d = float32_div(1.0, farg.d, &env->fp_status);
} else {
- if (farg.ll == 0x8000000000000000ULL) {
- farg.ll = 0xFFF0000000000000ULL;
- } else if (farg.ll == 0x0000000000000000ULL) {
- farg.ll = 0x7FF0000000000000ULL;
- } else if (float64_is_nan(farg.d)) {
- farg.ll |= 0x000FFFFFFFFFFFFFULL;
- } else if (fpisneg(farg.d)) {
- farg.ll = 0x7FF8000000000000ULL;
- } else {
- farg.ll = 0x0000000000000000ULL;
- }
+ farg.d = float64_sqrt(farg.d, &env->fp_status);
+ farg.d = float64_div(fone.d, farg.d, &env->fp_status);
+ f32 = float64_to_float32(farg.d, &env->fp_status);
+ farg.d = float32_to_float64(f32, &env->fp_status);
}
return farg.ll;
}
@@ -1617,7 +1560,7 @@ uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
farg1.ll = arg1;
- if (!fpisneg(farg1.d) || iszero(farg1.d))
+ if (!float64_is_neg(farg1.d) || float64_is_zero(farg1.d))
return arg2;
else
return arg3;
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 4c4f9efdb..80a08b18b 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -2072,6 +2072,8 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type) \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
+ /* NIP cannot be restored if the memory exception comes from an helper */ \
+ gen_update_nip(ctx, ctx->nip - 4); \
gen_reset_fpstatus(); \
gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], \
cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); \
@@ -2093,6 +2095,8 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type) \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
+ /* NIP cannot be restored if the memory exception comes from an helper */ \
+ gen_update_nip(ctx, ctx->nip - 4); \
gen_reset_fpstatus(); \
gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], \
cpu_fpr[rB(ctx->opcode)]); \
@@ -2113,6 +2117,8 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type) \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
+ /* NIP cannot be restored if the memory exception comes from an helper */ \
+ gen_update_nip(ctx, ctx->nip - 4); \
gen_reset_fpstatus(); \
gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], \
cpu_fpr[rC(ctx->opcode)]); \
@@ -2133,6 +2139,8 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
+ /* NIP cannot be restored if the memory exception comes from an helper */ \
+ gen_update_nip(ctx, ctx->nip - 4); \
gen_reset_fpstatus(); \
gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); \
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \
@@ -2146,6 +2154,8 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type) \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
+ /* NIP cannot be restored if the memory exception comes from an helper */ \
+ gen_update_nip(ctx, ctx->nip - 4); \
gen_reset_fpstatus(); \
gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); \
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \
@@ -2175,6 +2185,8 @@ GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES)
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);
@@ -2193,6 +2205,8 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0);
@@ -2204,6 +2218,8 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);
@@ -2249,30 +2265,34 @@ GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
/* fcmpo */
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
{
- TCGv crf;
+ TCGv_i32 crf;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
crf = tcg_const_i32(crfD(ctx->opcode));
gen_helper_fcmpo(cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], crf);
- tcg_temp_free(crf);
+ tcg_temp_free_i32(crf);
gen_helper_float_check_status();
}
/* fcmpu */
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
{
- TCGv crf;
+ TCGv_i32 crf;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
crf = tcg_const_i32(crfD(ctx->opcode));
gen_helper_fcmpu(cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], crf);
- tcg_temp_free(crf);
+ tcg_temp_free_i32(crf);
gen_helper_float_check_status();
}
@@ -2340,7 +2360,10 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
crb = 31 - crbD(ctx->opcode);
gen_reset_fpstatus();
if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
- TCGv_i32 t0 = tcg_const_i32(crb);
+ TCGv_i32 t0;
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ t0 = tcg_const_i32(crb);
gen_helper_fpscr_clrbit(t0);
tcg_temp_free_i32(t0);
}
@@ -2362,7 +2385,10 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
gen_reset_fpstatus();
/* XXX: we pretend we can only do IEEE floating-point computations */
if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
- TCGv_i32 t0 = tcg_const_i32(crb);
+ TCGv_i32 t0;
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ t0 = tcg_const_i32(crb);
gen_helper_fpscr_setbit(t0);
tcg_temp_free_i32(t0);
}
@@ -2382,6 +2408,8 @@ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
t0 = tcg_const_i32(FM(ctx->opcode));
gen_helper_store_fpscr(cpu_fpr[rB(ctx->opcode)], t0);
@@ -2406,6 +2434,8 @@ GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
}
bf = crbD(ctx->opcode) >> 2;
sh = 7 - bf;
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
t0 = tcg_const_i64(FPIMM(ctx->opcode) << (4 * sh));
t1 = tcg_const_i32(1 << sh);
@@ -6053,6 +6083,13 @@ GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
/*** Altivec vector extension ***/
/* Altivec registers moves */
+static always_inline TCGv_ptr gen_avr_ptr(int reg)
+{
+ TCGv_ptr r = tcg_temp_new();
+ tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, avr[reg]));
+ return r;
+}
+
#define GEN_VR_LDX(name, opc2, opc3) \
GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC) \
{ \
@@ -6109,6 +6146,24 @@ GEN_VR_STX(svx, 0x07, 0x07);
/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
GEN_VR_STX(svxl, 0x07, 0x0F);
+/* Logical operations */
+#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3) \
+GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC) \
+{ \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ tcg_op(cpu_avrh[rD(ctx->opcode)], cpu_avrh[rA(ctx->opcode)], cpu_avrh[rB(ctx->opcode)]); \
+ tcg_op(cpu_avrl[rD(ctx->opcode)], cpu_avrl[rA(ctx->opcode)], cpu_avrl[rB(ctx->opcode)]); \
+}
+
+GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16);
+GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17);
+GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18);
+GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19);
+GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20);
+
/*** SPE extension ***/
/* Register moves */
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 0ce81ed73..3f01e66f6 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9455,7 +9455,7 @@ static const ppc_def_t *ppc_find_by_pvr (uint32_t pvr)
int i, best, match, best_match, max;
ret = NULL;
- max = sizeof(ppc_defs) / sizeof(ppc_def_t);
+ max = ARRAY_SIZE(ppc_defs);
best = -1;
pvr_rev = pvr & 0xFFFF;
/* We want all specified bits to match */
@@ -9510,7 +9510,7 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name)
return ppc_find_by_pvr(strtoul(name, NULL, 16));
}
ret = NULL;
- max = sizeof(ppc_defs) / sizeof(ppc_def_t);
+ max = ARRAY_SIZE(ppc_defs);
for (i = 0; i < max; i++) {
if (strcasecmp(name, ppc_defs[i].name) == 0) {
ret = &ppc_defs[i];
@@ -9525,7 +9525,7 @@ void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{
int i, max;
- max = sizeof(ppc_defs) / sizeof(ppc_def_t);
+ max = ARRAY_SIZE(ppc_defs);
for (i = 0; i < max; i++) {
(*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n",
ppc_defs[i].name, ppc_defs[i].pvr);
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index 2d3981c2a..ac67fc84b 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -240,7 +240,7 @@ static const sh4_def_t *cpu_sh4_find_by_name(const char *name)
if (strcasecmp(name, "any") == 0)
return &sh4_defs[0];
- for (i = 0; i < sizeof(sh4_defs) / sizeof(*sh4_defs); i++)
+ for (i = 0; i < ARRAY_SIZE(sh4_defs); i++)
if (strcasecmp(name, sh4_defs[i].name) == 0)
return &sh4_defs[i];
@@ -251,7 +251,7 @@ void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{
int i;
- for (i = 0; i < sizeof(sh4_defs) / sizeof(*sh4_defs); i++)
+ for (i = 0; i < ARRAY_SIZE(sh4_defs); i++)
(*cpu_fprintf)(f, "%s\n", sh4_defs[i].name);
}
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 93c1be59f..905cf16b2 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -330,7 +330,8 @@ typedef struct CPUSPARCState {
uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr;
void *hstick; // UA 2005
uint32_t softint;
-#define SOFTINT_TIMER 1
+#define SOFTINT_TIMER 1
+#define SOFTINT_STIMER (1 << 16)
#endif
sparc_def_t *def;
} CPUSPARCState;
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index f222e3a2c..cdc44ebae 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -1240,7 +1240,7 @@ static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
long long iu_version;
uint32_t fpu_version, mmu_version, nwindows;
- for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) {
+ for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
if (strcasecmp(name, sparc_defs[i].name) == 0) {
def = &sparc_defs[i];
}
@@ -1336,7 +1336,7 @@ void sparc_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{
unsigned int i;
- for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) {
+ for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
(*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
sparc_defs[i].name,
sparc_defs[i].iu_version,
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index 021c89f68..40cf01c34 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -212,7 +212,7 @@ static void patch_reloc(uint8_t *code_ptr, int type,
/* maximum number of register used for input function arguments */
static int tcg_target_get_call_iarg_regs_count(int flags)
{
- return sizeof (tcg_target_call_iarg_regs) / sizeof (tcg_target_call_iarg_regs[0]);
+ return ARRAY_SIZE (tcg_target_call_iarg_regs);
}
/* parse target specific constraints */
diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
index 5ccb2f4e6..1a3b9a571 100644
--- a/tcg/ppc64/tcg-target.c
+++ b/tcg/ppc64/tcg-target.c
@@ -199,7 +199,7 @@ static void patch_reloc (uint8_t *code_ptr, int type,
/* maximum number of register used for input function arguments */
static int tcg_target_get_call_iarg_regs_count (int flags)
{
- return sizeof (tcg_target_call_iarg_regs) / sizeof (tcg_target_call_iarg_regs[0]);
+ return ARRAY_SIZE (tcg_target_call_iarg_regs);
}
/* parse target specific constraints */
diff --git a/vl.c b/vl.c
index d82fac2a4..99d1dd9c6 100644
--- a/vl.c
+++ b/vl.c
@@ -153,14 +153,6 @@
#include "qemu-kvm.h"
-#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
-#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
-#ifdef __sun__
-#define SMBD_COMMAND "/usr/sfw/sbin/smbd"
-#else
-#define SMBD_COMMAND "/usr/sbin/smbd"
-#endif
-
//#define DEBUG_UNUSED_IOPORT
//#define DEBUG_IOPORT
//#define DEBUG_NET
@@ -231,6 +223,7 @@ int assigned_devices_index;
int smp_cpus = 1;
const char *vnc_display;
int acpi_enabled = 1;
+int no_hpet = 0;
int fd_bootchk = 1;
int no_reboot = 0;
int no_shutdown = 0;
@@ -1077,7 +1070,7 @@ static void configure_alarms(char const *opt)
{
int i;
int cur = 0;
- int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1;
+ int count = ARRAY_SIZE(alarm_timers) - 1;
char *arg;
char *name;
struct qemu_alarm_timer tmp;
@@ -4088,6 +4081,7 @@ static void help(int exitcode)
#endif
#ifdef TARGET_I386
"-no-acpi disable ACPI\n"
+ "-no-hpet disable HPET\n"
#endif
#ifdef CONFIG_CURSES
"-curses use a curses/ncurses interface instead of SDL\n"
@@ -4203,6 +4197,7 @@ enum {
QEMU_OPTION_smp,
QEMU_OPTION_vnc,
QEMU_OPTION_no_acpi,
+ QEMU_OPTION_no_hpet,
QEMU_OPTION_curses,
QEMU_OPTION_no_kvm,
QEMU_OPTION_no_kvm_irqchip,
@@ -4338,6 +4333,7 @@ static const QEMUOption qemu_options[] = {
/* temporary options */
{ "usb", 0, QEMU_OPTION_usb },
{ "no-acpi", 0, QEMU_OPTION_no_acpi },
+ { "no-hpet", 0, QEMU_OPTION_no_hpet },
{ "no-reboot", 0, QEMU_OPTION_no_reboot },
{ "no-shutdown", 0, QEMU_OPTION_no_shutdown },
{ "show-cursor", 0, QEMU_OPTION_show_cursor },
@@ -5311,6 +5307,9 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_no_acpi:
acpi_enabled = 0;
break;
+ case QEMU_OPTION_no_hpet:
+ no_hpet = 1;
+ break;
case QEMU_OPTION_no_reboot:
no_reboot = 1;
break;
@@ -5799,6 +5798,17 @@ int main(int argc, char **argv, char **envp)
current_machine = machine;
+ /* Set KVM's vcpu state to qemu's initial CPUState. */
+ if (kvm_enabled()) {
+ int ret;
+
+ ret = kvm_sync_vcpus();
+ if (ret < 0) {
+ fprintf(stderr, "failed to initialize vcpus\n");
+ exit(1);
+ }
+ }
+
/* init USB devices */
if (usb_enabled) {
for(i = 0; i < usb_devices_index; i++) {
diff --git a/vnc.c b/vnc.c
index 3a7d76234..575fd6898 100644
--- a/vnc.c
+++ b/vnc.c
@@ -1503,10 +1503,13 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
if (len == 1)
return 4;
- if (len == 4)
- return 4 + (read_u16(data, 2) * 4);
+ if (len == 4) {
+ limit = read_u16(data, 2);
+ if (limit > 0)
+ return 4 + (limit * 4);
+ } else
+ limit = read_u16(data, 2);
- limit = read_u16(data, 2);
for (i = 0; i < limit; i++) {
int32_t val = read_s32(data, 4 + (i * 4));
memcpy(data + 4 + (i * 4), &val, sizeof(val));