diff options
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 @@ -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); } } @@ -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 */ @@ -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) { @@ -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 @@ -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); @@ -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; } @@ -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; @@ -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; @@ -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? */ @@ -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", @@ -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); @@ -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) @@ -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))) { @@ -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 @@ -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 @@ -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 @@ -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, @@ -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 @@ -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 Binary files differnew file mode 100644 index 000000000..c78e2544c --- /dev/null +++ b/pc-bios/bamboo.dtb 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, ®s); + 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, ®s); + 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, ®s); + 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 */ @@ -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++) { @@ -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)); |