mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-12 23:58:38 +00:00
Merge remote branch 'origin/master' into pci
This commit is contained in:
commit
6107ff1292
2
Makefile
2
Makefile
@ -205,7 +205,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 \
|
||||
vgabios-stdvga.bin vgabios-vmware.bin \
|
||||
vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
|
||||
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
|
||||
gpxe-eepro100-80861209.rom \
|
||||
pxe-e1000.bin \
|
||||
|
@ -219,6 +219,7 @@ obj-i386-y += vmmouse.o vmport.o hpet.o applesmc.o
|
||||
obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
|
||||
obj-i386-y += debugcon.o multiboot.o
|
||||
obj-i386-y += pc_piix.o
|
||||
obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
|
||||
|
||||
# shared objects
|
||||
obj-ppc-y = ppc.o
|
||||
|
@ -182,6 +182,70 @@ Example:
|
||||
"host": "127.0.0.1", "sasl_username": "luiz" } },
|
||||
"timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
|
||||
|
||||
SPICE_CONNECTED, SPICE_DISCONNECTED
|
||||
-----------------------------------
|
||||
|
||||
Emitted when a SPICE client connects or disconnects.
|
||||
|
||||
Data:
|
||||
|
||||
- "server": Server information (json-object)
|
||||
- "host": IP address (json-string)
|
||||
- "port": port number (json-string)
|
||||
- "family": address family (json-string, "ipv4" or "ipv6")
|
||||
- "client": Client information (json-object)
|
||||
- "host": IP address (json-string)
|
||||
- "port": port number (json-string)
|
||||
- "family": address family (json-string, "ipv4" or "ipv6")
|
||||
|
||||
Example:
|
||||
|
||||
{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
|
||||
"event": "SPICE_CONNECTED",
|
||||
"data": {
|
||||
"server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
|
||||
"client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
|
||||
}}
|
||||
|
||||
|
||||
SPICE_INITIALIZED
|
||||
-----------------
|
||||
|
||||
Emitted after initial handshake and authentication takes place (if any)
|
||||
and the SPICE channel is up'n'running
|
||||
|
||||
Data:
|
||||
|
||||
- "server": Server information (json-object)
|
||||
- "host": IP address (json-string)
|
||||
- "port": port number (json-string)
|
||||
- "family": address family (json-string, "ipv4" or "ipv6")
|
||||
- "auth": authentication method (json-string, optional)
|
||||
- "client": Client information (json-object)
|
||||
- "host": IP address (json-string)
|
||||
- "port": port number (json-string)
|
||||
- "family": address family (json-string, "ipv4" or "ipv6")
|
||||
- "connection-id": spice connection id. All channels with the same id
|
||||
belong to the same spice session (json-int)
|
||||
- "channel-type": channel type. "1" is the main control channel, filter for
|
||||
this one if you want track spice sessions only (json-int)
|
||||
- "channel-id": channel id. Usually "0", might be different needed when
|
||||
multiple channels of the same type exist, such as multiple
|
||||
display channels in a multihead setup (json-int)
|
||||
- "tls": whevener the channel is encrypted (json-bool)
|
||||
|
||||
Example:
|
||||
|
||||
{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
|
||||
"event": "SPICE_INITIALIZED",
|
||||
"data": {"server": {"auth": "spice", "port": "5921",
|
||||
"family": "ipv4", "host": "127.0.0.1"},
|
||||
"client": {"port": "49004", "family": "ipv4", "channel-type": 3,
|
||||
"connection-id": 1804289383, "host": "127.0.0.1",
|
||||
"channel-id": 0, "tls": true}
|
||||
}}
|
||||
|
||||
|
||||
WATCHDOG
|
||||
--------
|
||||
|
||||
|
81
arm-semi.c
81
arm-semi.c
@ -373,45 +373,64 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* Build a commandline from the original argv. */
|
||||
{
|
||||
char **arg = ts->info->host_argv;
|
||||
int len = ARG(1);
|
||||
/* lock the buffer on the ARM side */
|
||||
char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0);
|
||||
char *arm_cmdline_buffer;
|
||||
const char *host_cmdline_buffer;
|
||||
|
||||
if (!cmdline_buffer)
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
unsigned int i;
|
||||
unsigned int arm_cmdline_len = ARG(1);
|
||||
unsigned int host_cmdline_len =
|
||||
ts->info->arg_end-ts->info->arg_start;
|
||||
|
||||
s = cmdline_buffer;
|
||||
while (*arg && len > 2) {
|
||||
int n = strlen(*arg);
|
||||
|
||||
if (s != cmdline_buffer) {
|
||||
*(s++) = ' ';
|
||||
len--;
|
||||
}
|
||||
if (n >= len)
|
||||
n = len - 1;
|
||||
memcpy(s, *arg, n);
|
||||
s += n;
|
||||
len -= n;
|
||||
arg++;
|
||||
if (!arm_cmdline_len || host_cmdline_len > arm_cmdline_len) {
|
||||
return -1; /* not enough space to store command line */
|
||||
}
|
||||
/* Null terminate the string. */
|
||||
*s = 0;
|
||||
len = s - cmdline_buffer;
|
||||
|
||||
/* Unlock the buffer on the ARM side. */
|
||||
unlock_user(cmdline_buffer, ARG(0), len);
|
||||
if (!host_cmdline_len) {
|
||||
/* We special-case the "empty command line" case (argc==0).
|
||||
Just provide the terminating 0. */
|
||||
arm_cmdline_buffer = lock_user(VERIFY_WRITE, ARG(0), 1, 0);
|
||||
arm_cmdline_buffer[0] = 0;
|
||||
unlock_user(arm_cmdline_buffer, ARG(0), 1);
|
||||
|
||||
/* Adjust the commandline length argument. */
|
||||
SET_ARG(1, len);
|
||||
/* Adjust the commandline length argument. */
|
||||
SET_ARG(1, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return success if commandline fit into buffer. */
|
||||
return *arg ? -1 : 0;
|
||||
/* lock the buffers on the ARM side */
|
||||
arm_cmdline_buffer =
|
||||
lock_user(VERIFY_WRITE, ARG(0), host_cmdline_len, 0);
|
||||
host_cmdline_buffer =
|
||||
lock_user(VERIFY_READ, ts->info->arg_start,
|
||||
host_cmdline_len, 1);
|
||||
|
||||
if (arm_cmdline_buffer && host_cmdline_buffer)
|
||||
{
|
||||
/* the last argument is zero-terminated;
|
||||
no need for additional termination */
|
||||
memcpy(arm_cmdline_buffer, host_cmdline_buffer,
|
||||
host_cmdline_len);
|
||||
|
||||
/* separate arguments by white spaces */
|
||||
for (i = 0; i < host_cmdline_len-1; i++) {
|
||||
if (arm_cmdline_buffer[i] == 0) {
|
||||
arm_cmdline_buffer[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust the commandline length argument. */
|
||||
SET_ARG(1, host_cmdline_len-1);
|
||||
}
|
||||
|
||||
/* Unlock the buffers on the ARM side. */
|
||||
unlock_user(arm_cmdline_buffer, ARG(0), host_cmdline_len);
|
||||
unlock_user((void*)host_cmdline_buffer, ts->info->arg_start, 0);
|
||||
|
||||
/* Return success if we could return a commandline. */
|
||||
return (arm_cmdline_buffer && host_cmdline_buffer) ? 0 : -1;
|
||||
}
|
||||
#else
|
||||
return -1;
|
||||
return -1;
|
||||
#endif
|
||||
case SYS_HEAPINFO:
|
||||
{
|
||||
|
@ -318,7 +318,7 @@ static int alsa_write (SWVoiceOut *sw, void *buf, int len)
|
||||
return audio_pcm_sw_write (sw, buf, len);
|
||||
}
|
||||
|
||||
static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
|
||||
static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
|
||||
{
|
||||
switch (fmt) {
|
||||
case AUD_FMT_S8:
|
||||
@ -328,16 +328,36 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
|
||||
return SND_PCM_FORMAT_U8;
|
||||
|
||||
case AUD_FMT_S16:
|
||||
return SND_PCM_FORMAT_S16_LE;
|
||||
if (endianness) {
|
||||
return SND_PCM_FORMAT_S16_BE;
|
||||
}
|
||||
else {
|
||||
return SND_PCM_FORMAT_S16_LE;
|
||||
}
|
||||
|
||||
case AUD_FMT_U16:
|
||||
return SND_PCM_FORMAT_U16_LE;
|
||||
if (endianness) {
|
||||
return SND_PCM_FORMAT_U16_BE;
|
||||
}
|
||||
else {
|
||||
return SND_PCM_FORMAT_U16_LE;
|
||||
}
|
||||
|
||||
case AUD_FMT_S32:
|
||||
return SND_PCM_FORMAT_S32_LE;
|
||||
if (endianness) {
|
||||
return SND_PCM_FORMAT_S32_BE;
|
||||
}
|
||||
else {
|
||||
return SND_PCM_FORMAT_S32_LE;
|
||||
}
|
||||
|
||||
case AUD_FMT_U32:
|
||||
return SND_PCM_FORMAT_U32_LE;
|
||||
if (endianness) {
|
||||
return SND_PCM_FORMAT_U32_BE;
|
||||
}
|
||||
else {
|
||||
return SND_PCM_FORMAT_U32_LE;
|
||||
}
|
||||
|
||||
default:
|
||||
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
||||
@ -809,7 +829,7 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
|
||||
snd_pcm_t *handle;
|
||||
struct audsettings obt_as;
|
||||
|
||||
req.fmt = aud_to_alsafmt (as->fmt);
|
||||
req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
|
||||
req.freq = as->freq;
|
||||
req.nchannels = as->nchannels;
|
||||
req.period_size = conf.period_size_out;
|
||||
@ -918,7 +938,7 @@ static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
|
||||
snd_pcm_t *handle;
|
||||
struct audsettings obt_as;
|
||||
|
||||
req.fmt = aud_to_alsafmt (as->fmt);
|
||||
req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
|
||||
req.freq = as->freq;
|
||||
req.nchannels = as->nchannels;
|
||||
req.period_size = conf.period_size_in;
|
||||
|
@ -117,9 +117,12 @@ static int no_run_in (HWVoiceIn *hw)
|
||||
|
||||
static int no_read (SWVoiceIn *sw, void *buf, int size)
|
||||
{
|
||||
/* use custom code here instead of audio_pcm_sw_read() to avoid
|
||||
* useless resampling/mixing */
|
||||
int samples = size >> sw->info.shift;
|
||||
int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
|
||||
int to_clear = audio_MIN (samples, total);
|
||||
sw->total_hw_samples_acquired += total;
|
||||
audio_pcm_info_clear_buf (&sw->info, buf, to_clear);
|
||||
return to_clear << sw->info.shift;
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ static int oss_write (SWVoiceOut *sw, void *buf, int len)
|
||||
return audio_pcm_sw_write (sw, buf, len);
|
||||
}
|
||||
|
||||
static int aud_to_ossfmt (audfmt_e fmt)
|
||||
static int aud_to_ossfmt (audfmt_e fmt, int endianness)
|
||||
{
|
||||
switch (fmt) {
|
||||
case AUD_FMT_S8:
|
||||
@ -171,10 +171,20 @@ static int aud_to_ossfmt (audfmt_e fmt)
|
||||
return AFMT_U8;
|
||||
|
||||
case AUD_FMT_S16:
|
||||
return AFMT_S16_LE;
|
||||
if (endianness) {
|
||||
return AFMT_S16_BE;
|
||||
}
|
||||
else {
|
||||
return AFMT_S16_LE;
|
||||
}
|
||||
|
||||
case AUD_FMT_U16:
|
||||
return AFMT_U16_LE;
|
||||
if (endianness) {
|
||||
return AFMT_U16_BE;
|
||||
}
|
||||
else {
|
||||
return AFMT_U16_LE;
|
||||
}
|
||||
|
||||
default:
|
||||
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
||||
@ -516,7 +526,7 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
|
||||
|
||||
oss->fd = -1;
|
||||
|
||||
req.fmt = aud_to_ossfmt (as->fmt);
|
||||
req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
|
||||
req.freq = as->freq;
|
||||
req.nchannels = as->nchannels;
|
||||
req.fragsize = conf.fragsize;
|
||||
@ -682,7 +692,7 @@ static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
|
||||
|
||||
oss->fd = -1;
|
||||
|
||||
req.fmt = aud_to_ossfmt (as->fmt);
|
||||
req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
|
||||
req.freq = as->freq;
|
||||
req.nchannels = as->nchannels;
|
||||
req.fragsize = conf.fragsize;
|
||||
|
5
block.c
5
block.c
@ -2859,13 +2859,8 @@ int bdrv_img_create(const char *filename, const char *fmt,
|
||||
if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
|
||||
if (backing_file && backing_file->value.s) {
|
||||
uint64_t size;
|
||||
const char *fmt = NULL;
|
||||
char buf[32];
|
||||
|
||||
if (backing_fmt && backing_fmt->value.s) {
|
||||
fmt = backing_fmt->value.s;
|
||||
}
|
||||
|
||||
bs = bdrv_new("");
|
||||
|
||||
ret = bdrv_open(bs, backing_file->value.s, flags, drv);
|
||||
|
@ -176,8 +176,6 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
|
||||
|
||||
retval = prepare_binprm(&bprm);
|
||||
|
||||
infop->host_argv = argv;
|
||||
|
||||
if(retval>=0) {
|
||||
if (bprm.buf[0] == 0x7f
|
||||
&& bprm.buf[1] == 'E'
|
||||
|
@ -50,7 +50,6 @@ struct image_info {
|
||||
abi_ulong entry;
|
||||
abi_ulong code_offset;
|
||||
abi_ulong data_offset;
|
||||
char **host_argv;
|
||||
int personality;
|
||||
};
|
||||
|
||||
|
15
bswap.h
15
bswap.h
@ -144,6 +144,7 @@ CPU_CONVERT(le, 64, uint64_t)
|
||||
|
||||
#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v)
|
||||
#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
|
||||
#define cpu_to_be64wu(p, v) cpu_to_be64w(p, v)
|
||||
|
||||
#else
|
||||
|
||||
@ -201,6 +202,20 @@ static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
|
||||
p1[3] = v & 0xff;
|
||||
}
|
||||
|
||||
static inline void cpu_to_be64wu(uint64_t *p, uint64_t v)
|
||||
{
|
||||
uint8_t *p1 = (uint8_t *)p;
|
||||
|
||||
p1[0] = v >> 56;
|
||||
p1[1] = v >> 48;
|
||||
p1[2] = v >> 40;
|
||||
p1[3] = v >> 32;
|
||||
p1[4] = v >> 24;
|
||||
p1[5] = v >> 16;
|
||||
p1[6] = v >> 8;
|
||||
p1[7] = v & 0xff;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
|
18
configure
vendored
18
configure
vendored
@ -2075,6 +2075,21 @@ if compile_prog "$ARCH_CFLAGS" "" ; then
|
||||
fallocate=yes
|
||||
fi
|
||||
|
||||
# check for sync_file_range
|
||||
sync_file_range=no
|
||||
cat > $TMPC << EOF
|
||||
#include <fcntl.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
sync_file_range(0, 0, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "$ARCH_CFLAGS" "" ; then
|
||||
sync_file_range=yes
|
||||
fi
|
||||
|
||||
# check for dup3
|
||||
dup3=no
|
||||
cat > $TMPC << EOF
|
||||
@ -2613,6 +2628,9 @@ fi
|
||||
if test "$fallocate" = "yes" ; then
|
||||
echo "CONFIG_FALLOCATE=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$sync_file_range" = "yes" ; then
|
||||
echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$dup3" = "yes" ; then
|
||||
echo "CONFIG_DUP3=y" >> $config_host_mak
|
||||
fi
|
||||
|
@ -329,7 +329,7 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
|
||||
{
|
||||
if (!(ch & 0xff))
|
||||
ch |= ' ';
|
||||
cpu_to_le32wu((uint32_t *) dest, ch);
|
||||
*dest = ch;
|
||||
}
|
||||
|
||||
typedef void (*vga_hw_update_ptr)(void *);
|
||||
@ -369,6 +369,7 @@ void vnc_display_init(DisplayState *ds);
|
||||
void vnc_display_close(DisplayState *ds);
|
||||
int vnc_display_open(DisplayState *ds, const char *display);
|
||||
int vnc_display_password(DisplayState *ds, const char *password);
|
||||
int vnc_display_pw_expire(DisplayState *ds, time_t expires);
|
||||
void do_info_vnc_print(Monitor *mon, const QObject *data);
|
||||
void do_info_vnc(Monitor *mon, QObject **ret_data);
|
||||
char *vnc_display_local_addr(DisplayState *ds);
|
||||
|
@ -454,11 +454,7 @@ int cpu_exec(CPUState *env1)
|
||||
}
|
||||
#elif defined(TARGET_MIPS)
|
||||
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
cpu_mips_hw_interrupts_pending(env) &&
|
||||
(env->CP0_Status & (1 << CP0St_IE)) &&
|
||||
!(env->CP0_Status & (1 << CP0St_EXL)) &&
|
||||
!(env->CP0_Status & (1 << CP0St_ERL)) &&
|
||||
!(env->hflags & MIPS_HFLAG_DM)) {
|
||||
cpu_mips_hw_interrupts_pending(env)) {
|
||||
/* Raise it */
|
||||
env->exception_index = EXCP_EXT_INTERRUPT;
|
||||
env->error_code = 0;
|
||||
|
@ -177,7 +177,7 @@ static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc)
|
||||
|
||||
static inline unsigned int tb_phys_hash_func(tb_page_addr_t pc)
|
||||
{
|
||||
return pc & (CODE_GEN_PHYS_HASH_SIZE - 1);
|
||||
return (pc >> 2) & (CODE_GEN_PHYS_HASH_SIZE - 1);
|
||||
}
|
||||
|
||||
TranslationBlock *tb_alloc(target_ulong pc);
|
||||
@ -204,9 +204,7 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr
|
||||
#elif defined(__arm__)
|
||||
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
|
||||
{
|
||||
#if QEMU_GNUC_PREREQ(4, 1)
|
||||
void __clear_cache(char *beg, char *end);
|
||||
#else
|
||||
#if !QEMU_GNUC_PREREQ(4, 1)
|
||||
register unsigned long _beg __asm ("a1");
|
||||
register unsigned long _end __asm ("a2");
|
||||
register unsigned long _flg __asm ("a3");
|
||||
@ -218,7 +216,7 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr
|
||||
| (((addr - (jmp_addr + 8)) >> 2) & 0xffffff);
|
||||
|
||||
#if QEMU_GNUC_PREREQ(4, 1)
|
||||
__clear_cache((char *) jmp_addr, (char *) jmp_addr + 4);
|
||||
__builtin___clear_cache((char *) jmp_addr, (char *) jmp_addr + 4);
|
||||
#else
|
||||
/* flush icache */
|
||||
_beg = jmp_addr;
|
||||
|
3
exec.c
3
exec.c
@ -517,7 +517,8 @@ static void code_gen_alloc(unsigned long tb_size)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
|
||||
|| defined(__DragonFly__) || defined(__OpenBSD__)
|
||||
{
|
||||
int flags;
|
||||
void *addr = NULL;
|
||||
|
@ -254,7 +254,7 @@ int float32_is_signaling_nan( float32 a1)
|
||||
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
|
||||
}
|
||||
|
||||
int float32_is_nan( float32 a1 )
|
||||
int float32_is_quiet_nan( float32 a1 )
|
||||
{
|
||||
float32u u;
|
||||
uint64_t a;
|
||||
@ -411,7 +411,7 @@ int float64_is_signaling_nan( float64 a1)
|
||||
|
||||
}
|
||||
|
||||
int float64_is_nan( float64 a1 )
|
||||
int float64_is_quiet_nan( float64 a1 )
|
||||
{
|
||||
float64u u;
|
||||
uint64_t a;
|
||||
@ -504,7 +504,7 @@ int floatx80_is_signaling_nan( floatx80 a1)
|
||||
&& ( u.i.low == aLow );
|
||||
}
|
||||
|
||||
int floatx80_is_nan( floatx80 a1 )
|
||||
int floatx80_is_quiet_nan( floatx80 a1 )
|
||||
{
|
||||
floatx80u u;
|
||||
u.f = a1;
|
||||
|
@ -242,7 +242,7 @@ INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM)
|
||||
int float32_compare( float32, float32 STATUS_PARAM );
|
||||
int float32_compare_quiet( float32, float32 STATUS_PARAM );
|
||||
int float32_is_signaling_nan( float32 );
|
||||
int float32_is_nan( float32 );
|
||||
int float32_is_quiet_nan( float32 );
|
||||
|
||||
INLINE float32 float32_abs(float32 a)
|
||||
{
|
||||
@ -351,7 +351,7 @@ INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM)
|
||||
int float64_compare( float64, float64 STATUS_PARAM );
|
||||
int float64_compare_quiet( float64, float64 STATUS_PARAM );
|
||||
int float64_is_signaling_nan( float64 );
|
||||
int float64_is_nan( float64 );
|
||||
int float64_is_quiet_nan( float64 );
|
||||
|
||||
INLINE float64 float64_abs(float64 a)
|
||||
{
|
||||
@ -455,7 +455,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 );
|
||||
int floatx80_is_quiet_nan( floatx80 );
|
||||
|
||||
INLINE floatx80 floatx80_abs(floatx80 a)
|
||||
{
|
||||
|
@ -30,7 +30,7 @@ these four paragraphs for those parts of this code that are retained.
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#if defined(TARGET_MIPS) || defined(TARGET_HPPA)
|
||||
#if defined(TARGET_MIPS)
|
||||
#define SNAN_BIT_IS_ONE 1
|
||||
#else
|
||||
#define SNAN_BIT_IS_ONE 0
|
||||
@ -61,10 +61,8 @@ typedef struct {
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if defined(TARGET_SPARC)
|
||||
#define float32_default_nan make_float32(0x7FFFFFFF)
|
||||
#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
|
||||
#define float32_default_nan make_float32(0x7FC00000)
|
||||
#elif defined(TARGET_HPPA)
|
||||
#define float32_default_nan make_float32(0x7FA00000)
|
||||
#elif SNAN_BIT_IS_ONE
|
||||
#define float32_default_nan make_float32(0x7FBFFFFF)
|
||||
#else
|
||||
@ -76,7 +74,7 @@ typedef struct {
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float32_is_nan( float32 a_ )
|
||||
int float32_is_quiet_nan( float32 a_ )
|
||||
{
|
||||
uint32_t a = float32_val(a_);
|
||||
#if SNAN_BIT_IS_ONE
|
||||
@ -109,13 +107,17 @@ int float32_is_signaling_nan( float32 a_ )
|
||||
float32 float32_maybe_silence_nan( float32 a_ )
|
||||
{
|
||||
if (float32_is_signaling_nan(a_)) {
|
||||
uint32_t a = float32_val(a_);
|
||||
#if SNAN_BIT_IS_ONE
|
||||
a &= ~(1 << 22);
|
||||
# if defined(TARGET_MIPS)
|
||||
return float32_default_nan;
|
||||
# else
|
||||
# error Rules for silencing a signaling NaN are target-specific
|
||||
# endif
|
||||
#else
|
||||
bits32 a = float32_val(a_);
|
||||
a |= (1 << 22);
|
||||
#endif
|
||||
return make_float32(a);
|
||||
#endif
|
||||
}
|
||||
return a_;
|
||||
}
|
||||
@ -152,6 +154,118 @@ static float32 commonNaNToFloat32( commonNaNT a )
|
||||
return float32_default_nan;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Select which NaN to propagate for a two-input operation.
|
||||
| IEEE754 doesn't specify all the details of this, so the
|
||||
| algorithm is target-specific.
|
||||
| The routine is passed various bits of information about the
|
||||
| two NaNs and should return 0 to select NaN a and 1 for NaN b.
|
||||
| Note that signalling NaNs are always squashed to quiet NaNs
|
||||
| by the caller, by calling floatXX_maybe_silence_nan() before
|
||||
| returning them.
|
||||
|
|
||||
| aIsLargerSignificand is only valid if both a and b are NaNs
|
||||
| of some kind, and is true if a has the larger significand,
|
||||
| or if both a and b have the same significand but a is
|
||||
| positive but b is negative. It is only needed for the x87
|
||||
| tie-break rule.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(TARGET_ARM)
|
||||
static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
||||
flag aIsLargerSignificand)
|
||||
{
|
||||
/* ARM mandated NaN propagation rules: take the first of:
|
||||
* 1. A if it is signaling
|
||||
* 2. B if it is signaling
|
||||
* 3. A (quiet)
|
||||
* 4. B (quiet)
|
||||
* A signaling NaN is always quietened before returning it.
|
||||
*/
|
||||
if (aIsSNaN) {
|
||||
return 0;
|
||||
} else if (bIsSNaN) {
|
||||
return 1;
|
||||
} else if (aIsQNaN) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#elif defined(TARGET_MIPS)
|
||||
static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
||||
flag aIsLargerSignificand)
|
||||
{
|
||||
/* According to MIPS specifications, if one of the two operands is
|
||||
* a sNaN, a new qNaN has to be generated. This is done in
|
||||
* floatXX_maybe_silence_nan(). For qNaN inputs the specifications
|
||||
* says: "When possible, this QNaN result is one of the operand QNaN
|
||||
* values." In practice it seems that most implementations choose
|
||||
* the first operand if both operands are qNaN. In short this gives
|
||||
* the following rules:
|
||||
* 1. A if it is signaling
|
||||
* 2. B if it is signaling
|
||||
* 3. A (quiet)
|
||||
* 4. B (quiet)
|
||||
* A signaling NaN is always silenced before returning it.
|
||||
*/
|
||||
if (aIsSNaN) {
|
||||
return 0;
|
||||
} else if (bIsSNaN) {
|
||||
return 1;
|
||||
} else if (aIsQNaN) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#elif defined(TARGET_PPC)
|
||||
static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
||||
flag aIsLargerSignificand)
|
||||
{
|
||||
/* PowerPC propagation rules:
|
||||
* 1. A if it sNaN or qNaN
|
||||
* 2. B if it sNaN or qNaN
|
||||
* A signaling NaN is always silenced before returning it.
|
||||
*/
|
||||
if (aIsSNaN || aIsQNaN) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
||||
flag aIsLargerSignificand)
|
||||
{
|
||||
/* This implements x87 NaN propagation rules:
|
||||
* SNaN + QNaN => return the QNaN
|
||||
* two SNaNs => return the one with the larger significand, silenced
|
||||
* two QNaNs => return the one with the larger significand
|
||||
* SNaN and a non-NaN => return the SNaN, silenced
|
||||
* QNaN and a non-NaN => return the QNaN
|
||||
*
|
||||
* If we get down to comparing significands and they are the same,
|
||||
* return the NaN with the positive sign bit (if any).
|
||||
*/
|
||||
if (aIsSNaN) {
|
||||
if (bIsSNaN) {
|
||||
return aIsLargerSignificand ? 0 : 1;
|
||||
}
|
||||
return bIsQNaN ? 1 : 0;
|
||||
}
|
||||
else if (aIsQNaN) {
|
||||
if (bIsSNaN || !bIsQNaN)
|
||||
return 0;
|
||||
else {
|
||||
return aIsLargerSignificand ? 0 : 1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Takes two single-precision floating-point values `a' and `b', one of which
|
||||
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
|
||||
@ -160,47 +274,36 @@ static float32 commonNaNToFloat32( commonNaNT a )
|
||||
|
||||
static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
bits32 av, bv, res;
|
||||
flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
|
||||
flag aIsLargerSignificand;
|
||||
bits32 av, bv;
|
||||
|
||||
if ( STATUS(default_nan_mode) )
|
||||
return float32_default_nan;
|
||||
|
||||
aIsNaN = float32_is_nan( a );
|
||||
aIsQuietNaN = float32_is_quiet_nan( a );
|
||||
aIsSignalingNaN = float32_is_signaling_nan( a );
|
||||
bIsNaN = float32_is_nan( b );
|
||||
bIsQuietNaN = float32_is_quiet_nan( b );
|
||||
bIsSignalingNaN = float32_is_signaling_nan( b );
|
||||
av = float32_val(a);
|
||||
bv = float32_val(b);
|
||||
#if SNAN_BIT_IS_ONE
|
||||
av &= ~0x00400000;
|
||||
bv &= ~0x00400000;
|
||||
#else
|
||||
av |= 0x00400000;
|
||||
bv |= 0x00400000;
|
||||
#endif
|
||||
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
|
||||
if ( aIsSignalingNaN ) {
|
||||
if ( bIsSignalingNaN ) goto returnLargerSignificand;
|
||||
res = bIsNaN ? bv : av;
|
||||
|
||||
if ((bits32)(av<<1) < (bits32)(bv<<1)) {
|
||||
aIsLargerSignificand = 0;
|
||||
} else if ((bits32)(bv<<1) < (bits32)(av<<1)) {
|
||||
aIsLargerSignificand = 1;
|
||||
} else {
|
||||
aIsLargerSignificand = (av < bv) ? 1 : 0;
|
||||
}
|
||||
else if ( aIsNaN ) {
|
||||
if ( bIsSignalingNaN || ! bIsNaN )
|
||||
res = av;
|
||||
else {
|
||||
returnLargerSignificand:
|
||||
if ( (bits32) ( av<<1 ) < (bits32) ( bv<<1 ) )
|
||||
res = bv;
|
||||
else if ( (bits32) ( bv<<1 ) < (bits32) ( av<<1 ) )
|
||||
res = av;
|
||||
else
|
||||
res = ( av < bv ) ? av : bv;
|
||||
}
|
||||
|
||||
if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
|
||||
aIsLargerSignificand)) {
|
||||
return float32_maybe_silence_nan(b);
|
||||
} else {
|
||||
return float32_maybe_silence_nan(a);
|
||||
}
|
||||
else {
|
||||
res = bv;
|
||||
}
|
||||
return make_float32(res);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@ -208,10 +311,8 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
|
||||
*----------------------------------------------------------------------------*/
|
||||
#if defined(TARGET_SPARC)
|
||||
#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF ))
|
||||
#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
|
||||
#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 ))
|
||||
#elif defined(TARGET_HPPA)
|
||||
#define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 ))
|
||||
#elif SNAN_BIT_IS_ONE
|
||||
#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF ))
|
||||
#else
|
||||
@ -223,7 +324,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float64_is_nan( float64 a_ )
|
||||
int float64_is_quiet_nan( float64 a_ )
|
||||
{
|
||||
bits64 a = float64_val(a_);
|
||||
#if SNAN_BIT_IS_ONE
|
||||
@ -260,13 +361,17 @@ int float64_is_signaling_nan( float64 a_ )
|
||||
float64 float64_maybe_silence_nan( float64 a_ )
|
||||
{
|
||||
if (float64_is_signaling_nan(a_)) {
|
||||
bits64 a = float64_val(a_);
|
||||
#if SNAN_BIT_IS_ONE
|
||||
a &= ~LIT64( 0x0008000000000000 );
|
||||
# if defined(TARGET_MIPS)
|
||||
return float64_default_nan;
|
||||
# else
|
||||
# error Rules for silencing a signaling NaN are target-specific
|
||||
# endif
|
||||
#else
|
||||
bits64 a = float64_val(a_);
|
||||
a |= LIT64( 0x0008000000000000 );
|
||||
#endif
|
||||
return make_float64(a);
|
||||
#endif
|
||||
}
|
||||
return a_;
|
||||
}
|
||||
@ -314,47 +419,36 @@ static float64 commonNaNToFloat64( commonNaNT a )
|
||||
|
||||
static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
bits64 av, bv, res;
|
||||
flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
|
||||
flag aIsLargerSignificand;
|
||||
bits64 av, bv;
|
||||
|
||||
if ( STATUS(default_nan_mode) )
|
||||
return float64_default_nan;
|
||||
|
||||
aIsNaN = float64_is_nan( a );
|
||||
aIsQuietNaN = float64_is_quiet_nan( a );
|
||||
aIsSignalingNaN = float64_is_signaling_nan( a );
|
||||
bIsNaN = float64_is_nan( b );
|
||||
bIsQuietNaN = float64_is_quiet_nan( b );
|
||||
bIsSignalingNaN = float64_is_signaling_nan( b );
|
||||
av = float64_val(a);
|
||||
bv = float64_val(b);
|
||||
#if SNAN_BIT_IS_ONE
|
||||
av &= ~LIT64( 0x0008000000000000 );
|
||||
bv &= ~LIT64( 0x0008000000000000 );
|
||||
#else
|
||||
av |= LIT64( 0x0008000000000000 );
|
||||
bv |= LIT64( 0x0008000000000000 );
|
||||
#endif
|
||||
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
|
||||
if ( aIsSignalingNaN ) {
|
||||
if ( bIsSignalingNaN ) goto returnLargerSignificand;
|
||||
res = bIsNaN ? bv : av;
|
||||
|
||||
if ((bits64)(av<<1) < (bits64)(bv<<1)) {
|
||||
aIsLargerSignificand = 0;
|
||||
} else if ((bits64)(bv<<1) < (bits64)(av<<1)) {
|
||||
aIsLargerSignificand = 1;
|
||||
} else {
|
||||
aIsLargerSignificand = (av < bv) ? 1 : 0;
|
||||
}
|
||||
else if ( aIsNaN ) {
|
||||
if ( bIsSignalingNaN || ! bIsNaN )
|
||||
res = av;
|
||||
else {
|
||||
returnLargerSignificand:
|
||||
if ( (bits64) ( av<<1 ) < (bits64) ( bv<<1 ) )
|
||||
res = bv;
|
||||
else if ( (bits64) ( bv<<1 ) < (bits64) ( av<<1 ) )
|
||||
res = av;
|
||||
else
|
||||
res = ( av < bv ) ? av : bv;
|
||||
}
|
||||
|
||||
if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
|
||||
aIsLargerSignificand)) {
|
||||
return float64_maybe_silence_nan(b);
|
||||
} else {
|
||||
return float64_maybe_silence_nan(a);
|
||||
}
|
||||
else {
|
||||
res = bv;
|
||||
}
|
||||
return make_float64(res);
|
||||
}
|
||||
|
||||
#ifdef FLOATX80
|
||||
@ -377,7 +471,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
|
||||
| quiet NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int floatx80_is_nan( floatx80 a )
|
||||
int floatx80_is_quiet_nan( floatx80 a )
|
||||
{
|
||||
#if SNAN_BIT_IS_ONE
|
||||
bits64 aLow;
|
||||
@ -412,6 +506,29 @@ int floatx80_is_signaling_nan( floatx80 a )
|
||||
#endif
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns a quiet NaN if the extended double-precision floating point value
|
||||
| `a' is a signaling NaN; otherwise returns `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
floatx80 floatx80_maybe_silence_nan( floatx80 a )
|
||||
{
|
||||
if (floatx80_is_signaling_nan(a)) {
|
||||
#if SNAN_BIT_IS_ONE
|
||||
# if defined(TARGET_MIPS)
|
||||
a.low = floatx80_default_nan_low;
|
||||
a.high = floatx80_default_nan_high;
|
||||
# else
|
||||
# error Rules for silencing a signaling NaN are target-specific
|
||||
# endif
|
||||
#else
|
||||
a.low |= LIT64( 0xC000000000000000 );
|
||||
return a;
|
||||
#endif
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the extended double-precision floating-
|
||||
| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
|
||||
@ -454,7 +571,8 @@ static floatx80 commonNaNToFloatx80( commonNaNT a )
|
||||
|
||||
static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
|
||||
flag aIsLargerSignificand;
|
||||
|
||||
if ( STATUS(default_nan_mode) ) {
|
||||
a.low = floatx80_default_nan_low;
|
||||
@ -462,31 +580,26 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
return a;
|
||||
}
|
||||
|
||||
aIsNaN = floatx80_is_nan( a );
|
||||
aIsQuietNaN = floatx80_is_quiet_nan( a );
|
||||
aIsSignalingNaN = floatx80_is_signaling_nan( a );
|
||||
bIsNaN = floatx80_is_nan( b );
|
||||
bIsQuietNaN = floatx80_is_quiet_nan( b );
|
||||
bIsSignalingNaN = floatx80_is_signaling_nan( b );
|
||||
#if SNAN_BIT_IS_ONE
|
||||
a.low &= ~LIT64( 0xC000000000000000 );
|
||||
b.low &= ~LIT64( 0xC000000000000000 );
|
||||
#else
|
||||
a.low |= LIT64( 0xC000000000000000 );
|
||||
b.low |= LIT64( 0xC000000000000000 );
|
||||
#endif
|
||||
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
|
||||
if ( aIsSignalingNaN ) {
|
||||
if ( bIsSignalingNaN ) goto returnLargerSignificand;
|
||||
return bIsNaN ? b : a;
|
||||
|
||||
if (a.low < b.low) {
|
||||
aIsLargerSignificand = 0;
|
||||
} else if (b.low < a.low) {
|
||||
aIsLargerSignificand = 1;
|
||||
} else {
|
||||
aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
|
||||
}
|
||||
else if ( aIsNaN ) {
|
||||
if ( bIsSignalingNaN || ! bIsNaN ) return a;
|
||||
returnLargerSignificand:
|
||||
if ( a.low < b.low ) return b;
|
||||
if ( b.low < a.low ) return a;
|
||||
return ( a.high < b.high ) ? a : b;
|
||||
}
|
||||
else {
|
||||
return b;
|
||||
|
||||
if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
|
||||
aIsLargerSignificand)) {
|
||||
return floatx80_maybe_silence_nan(b);
|
||||
} else {
|
||||
return floatx80_maybe_silence_nan(a);
|
||||
}
|
||||
}
|
||||
|
||||
@ -511,7 +624,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
|
||||
| NaN; otherwise returns 0.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
int float128_is_nan( float128 a )
|
||||
int float128_is_quiet_nan( float128 a )
|
||||
{
|
||||
#if SNAN_BIT_IS_ONE
|
||||
return
|
||||
@ -542,6 +655,29 @@ int float128_is_signaling_nan( float128 a )
|
||||
#endif
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns a quiet NaN if the quadruple-precision floating point value `a' is
|
||||
| a signaling NaN; otherwise returns `a'.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
float128 float128_maybe_silence_nan( float128 a )
|
||||
{
|
||||
if (float128_is_signaling_nan(a)) {
|
||||
#if SNAN_BIT_IS_ONE
|
||||
# if defined(TARGET_MIPS)
|
||||
a.low = float128_default_nan_low;
|
||||
a.high = float128_default_nan_high;
|
||||
# else
|
||||
# error Rules for silencing a signaling NaN are target-specific
|
||||
# endif
|
||||
#else
|
||||
a.high |= LIT64( 0x0000800000000000 );
|
||||
return a;
|
||||
#endif
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Returns the result of converting the quadruple-precision floating-point NaN
|
||||
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
|
||||
@ -580,7 +716,8 @@ static float128 commonNaNToFloat128( commonNaNT a )
|
||||
|
||||
static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
|
||||
{
|
||||
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
|
||||
flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
|
||||
flag aIsLargerSignificand;
|
||||
|
||||
if ( STATUS(default_nan_mode) ) {
|
||||
a.low = float128_default_nan_low;
|
||||
@ -588,31 +725,26 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
|
||||
return a;
|
||||
}
|
||||
|
||||
aIsNaN = float128_is_nan( a );
|
||||
aIsQuietNaN = float128_is_quiet_nan( a );
|
||||
aIsSignalingNaN = float128_is_signaling_nan( a );
|
||||
bIsNaN = float128_is_nan( b );
|
||||
bIsQuietNaN = float128_is_quiet_nan( b );
|
||||
bIsSignalingNaN = float128_is_signaling_nan( b );
|
||||
#if SNAN_BIT_IS_ONE
|
||||
a.high &= ~LIT64( 0x0000800000000000 );
|
||||
b.high &= ~LIT64( 0x0000800000000000 );
|
||||
#else
|
||||
a.high |= LIT64( 0x0000800000000000 );
|
||||
b.high |= LIT64( 0x0000800000000000 );
|
||||
#endif
|
||||
|
||||
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
|
||||
if ( aIsSignalingNaN ) {
|
||||
if ( bIsSignalingNaN ) goto returnLargerSignificand;
|
||||
return bIsNaN ? b : a;
|
||||
|
||||
if (lt128(a.high<<1, a.low, b.high<<1, b.low)) {
|
||||
aIsLargerSignificand = 0;
|
||||
} else if (lt128(b.high<<1, b.low, a.high<<1, a.low)) {
|
||||
aIsLargerSignificand = 1;
|
||||
} else {
|
||||
aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
|
||||
}
|
||||
else if ( aIsNaN ) {
|
||||
if ( bIsSignalingNaN || ! bIsNaN ) return a;
|
||||
returnLargerSignificand:
|
||||
if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b;
|
||||
if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a;
|
||||
return ( a.high < b.high ) ? a : b;
|
||||
}
|
||||
else {
|
||||
return b;
|
||||
|
||||
if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
|
||||
aIsLargerSignificand)) {
|
||||
return float128_maybe_silence_nan(b);
|
||||
} else {
|
||||
return float128_maybe_silence_nan(a);
|
||||
}
|
||||
}
|
||||
|
||||
|
104
fpu/softfloat.c
104
fpu/softfloat.c
@ -30,8 +30,6 @@ 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"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
@ -203,6 +201,21 @@ INLINE flag extractFloat32Sign( float32 a )
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| If `a' is denormal and we are in flush-to-zero mode then set the
|
||||
| input-denormal exception and return zero. Otherwise just return the value.
|
||||
*----------------------------------------------------------------------------*/
|
||||
static float32 float32_squash_input_denormal(float32 a STATUS_PARAM)
|
||||
{
|
||||
if (STATUS(flush_inputs_to_zero)) {
|
||||
if (extractFloat32Exp(a) == 0 && extractFloat32Frac(a) != 0) {
|
||||
float_raise(float_flag_input_denormal STATUS_VAR);
|
||||
return make_float32(float32_val(a) & 0x80000000);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Normalizes the subnormal single-precision floating-point value represented
|
||||
| by the denormalized significand `aSig'. The normalized exponent and
|
||||
@ -367,6 +380,21 @@ INLINE flag extractFloat64Sign( float64 a )
|
||||
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| If `a' is denormal and we are in flush-to-zero mode then set the
|
||||
| input-denormal exception and return zero. Otherwise just return the value.
|
||||
*----------------------------------------------------------------------------*/
|
||||
static float64 float64_squash_input_denormal(float64 a STATUS_PARAM)
|
||||
{
|
||||
if (STATUS(flush_inputs_to_zero)) {
|
||||
if (extractFloat64Exp(a) == 0 && extractFloat64Frac(a) != 0) {
|
||||
float_raise(float_flag_input_denormal STATUS_VAR);
|
||||
return make_float64(float64_val(a) & (1ULL << 63));
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Normalizes the subnormal double-precision floating-point value represented
|
||||
| by the denormalized significand `aSig'. The normalized exponent and
|
||||
@ -1298,6 +1326,7 @@ int32 float32_to_int32( float32 a STATUS_PARAM )
|
||||
bits32 aSig;
|
||||
bits64 aSig64;
|
||||
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
aSign = extractFloat32Sign( a );
|
||||
@ -1327,6 +1356,7 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM )
|
||||
int16 aExp, shiftCount;
|
||||
bits32 aSig;
|
||||
int32 z;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
@ -1418,6 +1448,7 @@ int64 float32_to_int64( float32 a STATUS_PARAM )
|
||||
int16 aExp, shiftCount;
|
||||
bits32 aSig;
|
||||
bits64 aSig64, aSigExtra;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
@ -1455,6 +1486,7 @@ int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM )
|
||||
bits32 aSig;
|
||||
bits64 aSig64;
|
||||
int64 z;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
@ -1496,6 +1528,7 @@ float64 float32_to_float64( float32 a STATUS_PARAM )
|
||||
flag aSign;
|
||||
int16 aExp;
|
||||
bits32 aSig;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
@ -1528,6 +1561,7 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM )
|
||||
int16 aExp;
|
||||
bits32 aSig;
|
||||
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
aSign = extractFloat32Sign( a );
|
||||
@ -1561,6 +1595,7 @@ float128 float32_to_float128( float32 a STATUS_PARAM )
|
||||
int16 aExp;
|
||||
bits32 aSig;
|
||||
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
aSign = extractFloat32Sign( a );
|
||||
@ -1593,6 +1628,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM)
|
||||
bits32 lastBitMask, roundBitsMask;
|
||||
int8 roundingMode;
|
||||
bits32 z;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aExp = extractFloat32Exp( a );
|
||||
if ( 0x96 <= aExp ) {
|
||||
@ -1796,6 +1832,8 @@ static float32 subFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
|
||||
float32 float32_add( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
b = float32_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
aSign = extractFloat32Sign( a );
|
||||
bSign = extractFloat32Sign( b );
|
||||
@ -1817,6 +1855,8 @@ float32 float32_add( float32 a, float32 b STATUS_PARAM )
|
||||
float32 float32_sub( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
b = float32_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
aSign = extractFloat32Sign( a );
|
||||
bSign = extractFloat32Sign( b );
|
||||
@ -1843,6 +1883,9 @@ float32 float32_mul( float32 a, float32 b STATUS_PARAM )
|
||||
bits64 zSig64;
|
||||
bits32 zSig;
|
||||
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
b = float32_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
aSign = extractFloat32Sign( a );
|
||||
@ -1900,6 +1943,8 @@ float32 float32_div( float32 a, float32 b STATUS_PARAM )
|
||||
flag aSign, bSign, zSign;
|
||||
int16 aExp, bExp, zExp;
|
||||
bits32 aSig, bSig, zSig;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
b = float32_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
@ -1966,6 +2011,8 @@ float32 float32_rem( float32 a, float32 b STATUS_PARAM )
|
||||
bits64 aSig64, bSig64, q64;
|
||||
bits32 alternateASig;
|
||||
sbits32 sigMean;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
b = float32_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
@ -2062,6 +2109,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM )
|
||||
int16 aExp, zExp;
|
||||
bits32 aSig, zSig;
|
||||
bits64 rem, term;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
@ -2148,6 +2196,7 @@ float32 float32_exp2( float32 a STATUS_PARAM )
|
||||
bits32 aSig;
|
||||
float64 r, x, xn;
|
||||
int i;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
@ -2194,6 +2243,7 @@ float32 float32_log2( float32 a STATUS_PARAM )
|
||||
int16 aExp;
|
||||
bits32 aSig, zSig, i;
|
||||
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
aSign = extractFloat32Sign( a );
|
||||
@ -2238,6 +2288,8 @@ float32 float32_log2( float32 a STATUS_PARAM )
|
||||
|
||||
int float32_eq( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
b = float32_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||
@ -2263,6 +2315,8 @@ int float32_le( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits32 av, bv;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
b = float32_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||
@ -2289,6 +2343,8 @@ int float32_lt( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits32 av, bv;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
b = float32_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||
@ -2315,6 +2371,8 @@ int float32_lt( float32 a, float32 b STATUS_PARAM )
|
||||
int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
bits32 av, bv;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
b = float32_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||
@ -2339,6 +2397,8 @@ int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits32 av, bv;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
b = float32_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||
@ -2368,6 +2428,8 @@ int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits32 av, bv;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
b = float32_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|
||||
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
|
||||
@ -2401,6 +2463,7 @@ int32 float64_to_int32( float64 a STATUS_PARAM )
|
||||
flag aSign;
|
||||
int16 aExp, shiftCount;
|
||||
bits64 aSig;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
@ -2429,6 +2492,7 @@ int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM )
|
||||
int16 aExp, shiftCount;
|
||||
bits64 aSig, savedASig;
|
||||
int32 z;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
@ -2525,6 +2589,7 @@ int64 float64_to_int64( float64 a STATUS_PARAM )
|
||||
flag aSign;
|
||||
int16 aExp, shiftCount;
|
||||
bits64 aSig, aSigExtra;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
@ -2568,6 +2633,7 @@ int64 float64_to_int64_round_to_zero( float64 a STATUS_PARAM )
|
||||
int16 aExp, shiftCount;
|
||||
bits64 aSig;
|
||||
int64 z;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
@ -2617,6 +2683,7 @@ float32 float64_to_float32( float64 a STATUS_PARAM )
|
||||
int16 aExp;
|
||||
bits64 aSig;
|
||||
bits32 zSig;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
@ -2694,6 +2761,7 @@ bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM)
|
||||
bits32 mask;
|
||||
bits32 increment;
|
||||
int8 roundingMode;
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
@ -2788,6 +2856,7 @@ floatx80 float64_to_floatx80( float64 a STATUS_PARAM )
|
||||
int16 aExp;
|
||||
bits64 aSig;
|
||||
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
aSign = extractFloat64Sign( a );
|
||||
@ -2822,6 +2891,7 @@ float128 float64_to_float128( float64 a STATUS_PARAM )
|
||||
int16 aExp;
|
||||
bits64 aSig, zSig0, zSig1;
|
||||
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
aSign = extractFloat64Sign( a );
|
||||
@ -2855,6 +2925,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM )
|
||||
bits64 lastBitMask, roundBitsMask;
|
||||
int8 roundingMode;
|
||||
bits64 z;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aExp = extractFloat64Exp( a );
|
||||
if ( 0x433 <= aExp ) {
|
||||
@ -3071,6 +3142,8 @@ static float64 subFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
|
||||
float64 float64_add( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
b = float64_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
aSign = extractFloat64Sign( a );
|
||||
bSign = extractFloat64Sign( b );
|
||||
@ -3092,6 +3165,8 @@ float64 float64_add( float64 a, float64 b STATUS_PARAM )
|
||||
float64 float64_sub( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
b = float64_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
aSign = extractFloat64Sign( a );
|
||||
bSign = extractFloat64Sign( b );
|
||||
@ -3116,6 +3191,9 @@ float64 float64_mul( float64 a, float64 b STATUS_PARAM )
|
||||
int16 aExp, bExp, zExp;
|
||||
bits64 aSig, bSig, zSig0, zSig1;
|
||||
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
b = float64_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
aSign = extractFloat64Sign( a );
|
||||
@ -3175,6 +3253,8 @@ float64 float64_div( float64 a, float64 b STATUS_PARAM )
|
||||
bits64 aSig, bSig, zSig;
|
||||
bits64 rem0, rem1;
|
||||
bits64 term0, term1;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
b = float64_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
@ -3246,6 +3326,8 @@ float64 float64_rem( float64 a, float64 b STATUS_PARAM )
|
||||
bits64 q, alternateASig;
|
||||
sbits64 sigMean;
|
||||
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
b = float64_squash_input_denormal(b STATUS_VAR);
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
aSign = extractFloat64Sign( a );
|
||||
@ -3328,6 +3410,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM )
|
||||
int16 aExp, zExp;
|
||||
bits64 aSig, zSig, doubleZSig;
|
||||
bits64 rem0, rem1, term0, term1;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
@ -3377,6 +3460,7 @@ float64 float64_log2( float64 a STATUS_PARAM )
|
||||
flag aSign, zSign;
|
||||
int16 aExp;
|
||||
bits64 aSig, aSig0, aSig1, zSig, i;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
@ -3422,6 +3506,8 @@ float64 float64_log2( float64 a STATUS_PARAM )
|
||||
int float64_eq( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
bits64 av, bv;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
b = float64_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||
@ -3448,6 +3534,8 @@ int float64_le( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits64 av, bv;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
b = float64_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||
@ -3475,6 +3563,8 @@ int float64_lt( float64 a, float64 b STATUS_PARAM )
|
||||
flag aSign, bSign;
|
||||
bits64 av, bv;
|
||||
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
b = float64_squash_input_denormal(b STATUS_VAR);
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||
) {
|
||||
@ -3500,6 +3590,8 @@ int float64_lt( float64 a, float64 b STATUS_PARAM )
|
||||
int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
bits64 av, bv;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
b = float64_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||
@ -3524,6 +3616,8 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits64 av, bv;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
b = float64_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||
@ -3553,6 +3647,8 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
|
||||
{
|
||||
flag aSign, bSign;
|
||||
bits64 av, bv;
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
b = float64_squash_input_denormal(b STATUS_VAR);
|
||||
|
||||
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|
||||
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
|
||||
@ -5833,6 +5929,8 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \
|
||||
{ \
|
||||
flag aSign, bSign; \
|
||||
bits ## s av, bv; \
|
||||
a = float ## s ## _squash_input_denormal(a STATUS_VAR); \
|
||||
b = float ## s ## _squash_input_denormal(b STATUS_VAR); \
|
||||
\
|
||||
if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) && \
|
||||
extractFloat ## s ## Frac( a ) ) || \
|
||||
@ -5929,6 +6027,7 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
|
||||
int16 aExp;
|
||||
bits32 aSig;
|
||||
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
aSig = extractFloat32Frac( a );
|
||||
aExp = extractFloat32Exp( a );
|
||||
aSign = extractFloat32Sign( a );
|
||||
@ -5952,6 +6051,7 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
|
||||
int16 aExp;
|
||||
bits64 aSig;
|
||||
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
aSig = extractFloat64Frac( a );
|
||||
aExp = extractFloat64Exp( a );
|
||||
aSign = extractFloat64Sign( a );
|
||||
|
@ -180,7 +180,8 @@ enum {
|
||||
float_flag_divbyzero = 4,
|
||||
float_flag_overflow = 8,
|
||||
float_flag_underflow = 16,
|
||||
float_flag_inexact = 32
|
||||
float_flag_inexact = 32,
|
||||
float_flag_input_denormal = 64
|
||||
};
|
||||
|
||||
typedef struct float_status {
|
||||
@ -190,7 +191,10 @@ typedef struct float_status {
|
||||
#ifdef FLOATX80
|
||||
signed char floatx80_rounding_precision;
|
||||
#endif
|
||||
/* should denormalised results go to zero and set the inexact flag? */
|
||||
flag flush_to_zero;
|
||||
/* should denormalised inputs go to zero and set the input_denormal flag? */
|
||||
flag flush_inputs_to_zero;
|
||||
flag default_nan_mode;
|
||||
} float_status;
|
||||
|
||||
@ -200,6 +204,10 @@ INLINE void set_flush_to_zero(flag val STATUS_PARAM)
|
||||
{
|
||||
STATUS(flush_to_zero) = val;
|
||||
}
|
||||
INLINE void set_flush_inputs_to_zero(flag val STATUS_PARAM)
|
||||
{
|
||||
STATUS(flush_inputs_to_zero) = val;
|
||||
}
|
||||
INLINE void set_default_nan_mode(flag val STATUS_PARAM)
|
||||
{
|
||||
STATUS(default_nan_mode) = val;
|
||||
@ -287,18 +295,24 @@ int float32_le_quiet( float32, float32 STATUS_PARAM );
|
||||
int float32_lt_quiet( float32, float32 STATUS_PARAM );
|
||||
int float32_compare( float32, float32 STATUS_PARAM );
|
||||
int float32_compare_quiet( float32, float32 STATUS_PARAM );
|
||||
int float32_is_nan( float32 );
|
||||
int float32_is_quiet_nan( float32 );
|
||||
int float32_is_signaling_nan( float32 );
|
||||
float32 float32_maybe_silence_nan( float32 );
|
||||
float32 float32_scalbn( float32, int STATUS_PARAM );
|
||||
|
||||
INLINE float32 float32_abs(float32 a)
|
||||
{
|
||||
/* Note that abs does *not* handle NaN specially, nor does
|
||||
* it flush denormal inputs to zero.
|
||||
*/
|
||||
return make_float32(float32_val(a) & 0x7fffffff);
|
||||
}
|
||||
|
||||
INLINE float32 float32_chs(float32 a)
|
||||
{
|
||||
/* Note that chs does *not* handle NaN specially, nor does
|
||||
* it flush denormal inputs to zero.
|
||||
*/
|
||||
return make_float32(float32_val(a) ^ 0x80000000);
|
||||
}
|
||||
|
||||
@ -367,18 +381,24 @@ int float64_le_quiet( float64, float64 STATUS_PARAM );
|
||||
int float64_lt_quiet( float64, float64 STATUS_PARAM );
|
||||
int float64_compare( float64, float64 STATUS_PARAM );
|
||||
int float64_compare_quiet( float64, float64 STATUS_PARAM );
|
||||
int float64_is_nan( float64 a );
|
||||
int float64_is_quiet_nan( float64 a );
|
||||
int float64_is_signaling_nan( float64 );
|
||||
float64 float64_maybe_silence_nan( float64 );
|
||||
float64 float64_scalbn( float64, int STATUS_PARAM );
|
||||
|
||||
INLINE float64 float64_abs(float64 a)
|
||||
{
|
||||
/* Note that abs does *not* handle NaN specially, nor does
|
||||
* it flush denormal inputs to zero.
|
||||
*/
|
||||
return make_float64(float64_val(a) & 0x7fffffffffffffffLL);
|
||||
}
|
||||
|
||||
INLINE float64 float64_chs(float64 a)
|
||||
{
|
||||
/* Note that chs does *not* handle NaN specially, nor does
|
||||
* it flush denormal inputs to zero.
|
||||
*/
|
||||
return make_float64(float64_val(a) ^ 0x8000000000000000LL);
|
||||
}
|
||||
|
||||
@ -437,8 +457,9 @@ int floatx80_lt( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
|
||||
int floatx80_is_nan( floatx80 );
|
||||
int floatx80_is_quiet_nan( floatx80 );
|
||||
int floatx80_is_signaling_nan( floatx80 );
|
||||
floatx80 floatx80_maybe_silence_nan( floatx80 );
|
||||
floatx80 floatx80_scalbn( floatx80, int STATUS_PARAM );
|
||||
|
||||
INLINE floatx80 floatx80_abs(floatx80 a)
|
||||
@ -468,6 +489,11 @@ INLINE int floatx80_is_zero(floatx80 a)
|
||||
return (a.high & 0x7fff) == 0 && a.low == 0;
|
||||
}
|
||||
|
||||
INLINE int floatx80_is_any_nan(floatx80 a)
|
||||
{
|
||||
return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FLOAT128
|
||||
@ -503,8 +529,9 @@ int float128_le_quiet( float128, float128 STATUS_PARAM );
|
||||
int float128_lt_quiet( float128, float128 STATUS_PARAM );
|
||||
int float128_compare( float128, float128 STATUS_PARAM );
|
||||
int float128_compare_quiet( float128, float128 STATUS_PARAM );
|
||||
int float128_is_nan( float128 );
|
||||
int float128_is_quiet_nan( float128 );
|
||||
int float128_is_signaling_nan( float128 );
|
||||
float128 float128_maybe_silence_nan( float128 );
|
||||
float128 float128_scalbn( float128, int STATUS_PARAM );
|
||||
|
||||
INLINE float128 float128_abs(float128 a)
|
||||
@ -534,6 +561,12 @@ INLINE int float128_is_zero(float128 a)
|
||||
return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0;
|
||||
}
|
||||
|
||||
INLINE int float128_is_any_nan(float128 a)
|
||||
{
|
||||
return ((a.high >> 48) & 0x7fff) == 0x7fff &&
|
||||
((a.low != 0) || ((a.high & 0xffffffffffffLL) != 0));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else /* CONFIG_SOFTFLOAT */
|
||||
|
@ -1176,6 +1176,60 @@ STEXI
|
||||
@item block_passwd @var{device} @var{password}
|
||||
@findex block_passwd
|
||||
Set the encrypted device @var{device} password to @var{password}
|
||||
ETEXI
|
||||
|
||||
{
|
||||
.name = "set_password",
|
||||
.args_type = "protocol:s,password:s,connected:s?",
|
||||
.params = "protocol password action-if-connected",
|
||||
.help = "set spice/vnc password",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = set_password,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@item set_password [ vnc | spice ] password [ action-if-connected ]
|
||||
@findex set_password
|
||||
|
||||
Change spice/vnc password. Use zero to make the password stay valid
|
||||
forever. @var{action-if-connected} specifies what should happen in
|
||||
case a connection is established: @var{fail} makes the password change
|
||||
fail. @var{disconnect} changes the password and disconnects the
|
||||
client. @var{keep} changes the password and keeps the connection up.
|
||||
@var{keep} is the default.
|
||||
ETEXI
|
||||
|
||||
{
|
||||
.name = "expire_password",
|
||||
.args_type = "protocol:s,time:s",
|
||||
.params = "protocol time",
|
||||
.help = "set spice/vnc password expire-time",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = expire_password,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@item expire_password [ vnc | spice ] expire-time
|
||||
@findex expire_password
|
||||
|
||||
Specify when a password for spice/vnc becomes
|
||||
invalid. @var{expire-time} accepts:
|
||||
|
||||
@table @var
|
||||
@item now
|
||||
Invalidate password instantly.
|
||||
|
||||
@item never
|
||||
Password stays valid forever.
|
||||
|
||||
@item +nsec
|
||||
Password stays valid for @var{nsec} seconds starting now.
|
||||
|
||||
@item nsec
|
||||
Password is invalidated at the given time. @var{nsec} are the seconds
|
||||
passed since 1970, i.e. unix epoch.
|
||||
|
||||
@end table
|
||||
ETEXI
|
||||
|
||||
{
|
||||
@ -1215,7 +1269,7 @@ show i8259 (PIC) state
|
||||
@item info pci
|
||||
show emulated PCI device info
|
||||
@item info tlb
|
||||
show virtual to physical memory mappings (i386 only)
|
||||
show virtual to physical memory mappings (i386, SH4 and SPARC only)
|
||||
@item info mem
|
||||
show the active virtual memory mappings (i386 only)
|
||||
@item info jit
|
||||
|
@ -765,7 +765,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
|
||||
return val;
|
||||
}
|
||||
|
||||
static void apic_send_msi(target_phys_addr_t addr, uint32 data)
|
||||
static void apic_send_msi(target_phys_addr_t addr, uint32_t data)
|
||||
{
|
||||
uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
|
||||
uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
|
||||
|
179
hw/cirrus_vga.c
179
hw/cirrus_vga.c
@ -673,46 +673,47 @@ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
|
||||
|
||||
static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
{
|
||||
int sx, sy;
|
||||
int dx, dy;
|
||||
int width, height;
|
||||
int depth;
|
||||
int sx = 0, sy = 0;
|
||||
int dx = 0, dy = 0;
|
||||
int depth = 0;
|
||||
int notify = 0;
|
||||
|
||||
depth = s->vga.get_bpp(&s->vga) / 8;
|
||||
s->vga.get_resolution(&s->vga, &width, &height);
|
||||
/* make sure to only copy if it's a plain copy ROP */
|
||||
if (*s->cirrus_rop == cirrus_bitblt_rop_fwd_src ||
|
||||
*s->cirrus_rop == cirrus_bitblt_rop_bkwd_src) {
|
||||
|
||||
/* extra x, y */
|
||||
sx = (src % ABS(s->cirrus_blt_srcpitch)) / depth;
|
||||
sy = (src / ABS(s->cirrus_blt_srcpitch));
|
||||
dx = (dst % ABS(s->cirrus_blt_dstpitch)) / depth;
|
||||
dy = (dst / ABS(s->cirrus_blt_dstpitch));
|
||||
int width, height;
|
||||
|
||||
/* normalize width */
|
||||
w /= depth;
|
||||
depth = s->vga.get_bpp(&s->vga) / 8;
|
||||
s->vga.get_resolution(&s->vga, &width, &height);
|
||||
|
||||
/* if we're doing a backward copy, we have to adjust
|
||||
our x/y to be the upper left corner (instead of the lower
|
||||
right corner) */
|
||||
if (s->cirrus_blt_dstpitch < 0) {
|
||||
sx -= (s->cirrus_blt_width / depth) - 1;
|
||||
dx -= (s->cirrus_blt_width / depth) - 1;
|
||||
sy -= s->cirrus_blt_height - 1;
|
||||
dy -= s->cirrus_blt_height - 1;
|
||||
/* extra x, y */
|
||||
sx = (src % ABS(s->cirrus_blt_srcpitch)) / depth;
|
||||
sy = (src / ABS(s->cirrus_blt_srcpitch));
|
||||
dx = (dst % ABS(s->cirrus_blt_dstpitch)) / depth;
|
||||
dy = (dst / ABS(s->cirrus_blt_dstpitch));
|
||||
|
||||
/* normalize width */
|
||||
w /= depth;
|
||||
|
||||
/* if we're doing a backward copy, we have to adjust
|
||||
our x/y to be the upper left corner (instead of the lower
|
||||
right corner) */
|
||||
if (s->cirrus_blt_dstpitch < 0) {
|
||||
sx -= (s->cirrus_blt_width / depth) - 1;
|
||||
dx -= (s->cirrus_blt_width / depth) - 1;
|
||||
sy -= s->cirrus_blt_height - 1;
|
||||
dy -= s->cirrus_blt_height - 1;
|
||||
}
|
||||
|
||||
/* are we in the visible portion of memory? */
|
||||
if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
|
||||
(sx + w) <= width && (sy + h) <= height &&
|
||||
(dx + w) <= width && (dy + h) <= height) {
|
||||
notify = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* are we in the visible portion of memory? */
|
||||
if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
|
||||
(sx + w) <= width && (sy + h) <= height &&
|
||||
(dx + w) <= width && (dy + h) <= height) {
|
||||
notify = 1;
|
||||
}
|
||||
|
||||
/* make to sure only copy if it's a plain copy ROP */
|
||||
if (*s->cirrus_rop != cirrus_bitblt_rop_fwd_src &&
|
||||
*s->cirrus_rop != cirrus_bitblt_rop_bkwd_src)
|
||||
notify = 0;
|
||||
|
||||
/* we have to flush all pending changes so that the copy
|
||||
is generated at the appropriate moment in time */
|
||||
if (notify)
|
||||
@ -2003,30 +2004,20 @@ static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
|
||||
static uint32_t cirrus_vga_mem_readw(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t v;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
v = cirrus_vga_mem_readb(opaque, addr) << 8;
|
||||
v |= cirrus_vga_mem_readb(opaque, addr + 1);
|
||||
#else
|
||||
|
||||
v = cirrus_vga_mem_readb(opaque, addr);
|
||||
v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t v;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
v = cirrus_vga_mem_readb(opaque, addr) << 24;
|
||||
v |= cirrus_vga_mem_readb(opaque, addr + 1) << 16;
|
||||
v |= cirrus_vga_mem_readb(opaque, addr + 2) << 8;
|
||||
v |= cirrus_vga_mem_readb(opaque, addr + 3);
|
||||
#else
|
||||
|
||||
v = cirrus_vga_mem_readb(opaque, addr);
|
||||
v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
|
||||
v |= cirrus_vga_mem_readb(opaque, addr + 2) << 16;
|
||||
v |= cirrus_vga_mem_readb(opaque, addr + 3) << 24;
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -2097,28 +2088,16 @@ static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
|
||||
|
||||
static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
cirrus_vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
|
||||
cirrus_vga_mem_writeb(opaque, addr + 1, val & 0xff);
|
||||
#else
|
||||
cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
|
||||
cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
cirrus_vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
|
||||
cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
|
||||
cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
|
||||
cirrus_vga_mem_writeb(opaque, addr + 3, val & 0xff);
|
||||
#else
|
||||
cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
|
||||
cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
|
||||
cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
|
||||
cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
|
||||
#endif
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc * const cirrus_vga_mem_read[3] = {
|
||||
@ -2340,30 +2319,20 @@ static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr)
|
||||
static uint32_t cirrus_linear_readw(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t v;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
v = cirrus_linear_readb(opaque, addr) << 8;
|
||||
v |= cirrus_linear_readb(opaque, addr + 1);
|
||||
#else
|
||||
|
||||
v = cirrus_linear_readb(opaque, addr);
|
||||
v |= cirrus_linear_readb(opaque, addr + 1) << 8;
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
static uint32_t cirrus_linear_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t v;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
v = cirrus_linear_readb(opaque, addr) << 24;
|
||||
v |= cirrus_linear_readb(opaque, addr + 1) << 16;
|
||||
v |= cirrus_linear_readb(opaque, addr + 2) << 8;
|
||||
v |= cirrus_linear_readb(opaque, addr + 3);
|
||||
#else
|
||||
|
||||
v = cirrus_linear_readb(opaque, addr);
|
||||
v |= cirrus_linear_readb(opaque, addr + 1) << 8;
|
||||
v |= cirrus_linear_readb(opaque, addr + 2) << 16;
|
||||
v |= cirrus_linear_readb(opaque, addr + 3) << 24;
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -2411,29 +2380,17 @@ static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr,
|
||||
static void cirrus_linear_writew(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
cirrus_linear_writeb(opaque, addr, (val >> 8) & 0xff);
|
||||
cirrus_linear_writeb(opaque, addr + 1, val & 0xff);
|
||||
#else
|
||||
cirrus_linear_writeb(opaque, addr, val & 0xff);
|
||||
cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
cirrus_linear_writeb(opaque, addr, (val >> 24) & 0xff);
|
||||
cirrus_linear_writeb(opaque, addr + 1, (val >> 16) & 0xff);
|
||||
cirrus_linear_writeb(opaque, addr + 2, (val >> 8) & 0xff);
|
||||
cirrus_linear_writeb(opaque, addr + 3, val & 0xff);
|
||||
#else
|
||||
cirrus_linear_writeb(opaque, addr, val & 0xff);
|
||||
cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
|
||||
cirrus_linear_writeb(opaque, addr + 2, (val >> 16) & 0xff);
|
||||
cirrus_linear_writeb(opaque, addr + 3, (val >> 24) & 0xff);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -2468,30 +2425,20 @@ static uint32_t cirrus_linear_bitblt_readb(void *opaque, target_phys_addr_t addr
|
||||
static uint32_t cirrus_linear_bitblt_readw(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t v;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
v = cirrus_linear_bitblt_readb(opaque, addr) << 8;
|
||||
v |= cirrus_linear_bitblt_readb(opaque, addr + 1);
|
||||
#else
|
||||
|
||||
v = cirrus_linear_bitblt_readb(opaque, addr);
|
||||
v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
static uint32_t cirrus_linear_bitblt_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t v;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
v = cirrus_linear_bitblt_readb(opaque, addr) << 24;
|
||||
v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 16;
|
||||
v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 8;
|
||||
v |= cirrus_linear_bitblt_readb(opaque, addr + 3);
|
||||
#else
|
||||
|
||||
v = cirrus_linear_bitblt_readb(opaque, addr);
|
||||
v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
|
||||
v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 16;
|
||||
v |= cirrus_linear_bitblt_readb(opaque, addr + 3) << 24;
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -2512,29 +2459,17 @@ static void cirrus_linear_bitblt_writeb(void *opaque, target_phys_addr_t addr,
|
||||
static void cirrus_linear_bitblt_writew(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
cirrus_linear_bitblt_writeb(opaque, addr, (val >> 8) & 0xff);
|
||||
cirrus_linear_bitblt_writeb(opaque, addr + 1, val & 0xff);
|
||||
#else
|
||||
cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
|
||||
cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cirrus_linear_bitblt_writel(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
cirrus_linear_bitblt_writeb(opaque, addr, (val >> 24) & 0xff);
|
||||
cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 16) & 0xff);
|
||||
cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 8) & 0xff);
|
||||
cirrus_linear_bitblt_writeb(opaque, addr + 3, val & 0xff);
|
||||
#else
|
||||
cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
|
||||
cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
|
||||
cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 16) & 0xff);
|
||||
cirrus_linear_bitblt_writeb(opaque, addr + 3, (val >> 24) & 0xff);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -2841,30 +2776,20 @@ static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr)
|
||||
static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t v;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
v = cirrus_mmio_readb(opaque, addr) << 8;
|
||||
v |= cirrus_mmio_readb(opaque, addr + 1);
|
||||
#else
|
||||
|
||||
v = cirrus_mmio_readb(opaque, addr);
|
||||
v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t v;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
v = cirrus_mmio_readb(opaque, addr) << 24;
|
||||
v |= cirrus_mmio_readb(opaque, addr + 1) << 16;
|
||||
v |= cirrus_mmio_readb(opaque, addr + 2) << 8;
|
||||
v |= cirrus_mmio_readb(opaque, addr + 3);
|
||||
#else
|
||||
|
||||
v = cirrus_mmio_readb(opaque, addr);
|
||||
v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
|
||||
v |= cirrus_mmio_readb(opaque, addr + 2) << 16;
|
||||
v |= cirrus_mmio_readb(opaque, addr + 3) << 24;
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -2885,29 +2810,17 @@ static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr,
|
||||
static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
cirrus_mmio_writeb(opaque, addr, (val >> 8) & 0xff);
|
||||
cirrus_mmio_writeb(opaque, addr + 1, val & 0xff);
|
||||
#else
|
||||
cirrus_mmio_writeb(opaque, addr, val & 0xff);
|
||||
cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
cirrus_mmio_writeb(opaque, addr, (val >> 24) & 0xff);
|
||||
cirrus_mmio_writeb(opaque, addr + 1, (val >> 16) & 0xff);
|
||||
cirrus_mmio_writeb(opaque, addr + 2, (val >> 8) & 0xff);
|
||||
cirrus_mmio_writeb(opaque, addr + 3, val & 0xff);
|
||||
#else
|
||||
cirrus_mmio_writeb(opaque, addr, val & 0xff);
|
||||
cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
|
||||
cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff);
|
||||
cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -3077,7 +2990,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
|
||||
|
||||
s->vga.vga_io_memory = cpu_register_io_memory(cirrus_vga_mem_read,
|
||||
cirrus_vga_mem_write, s,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
|
||||
s->vga.vga_io_memory);
|
||||
qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
|
||||
@ -3085,18 +2998,18 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
|
||||
/* I/O handler for LFB */
|
||||
s->cirrus_linear_io_addr =
|
||||
cpu_register_io_memory(cirrus_linear_read, cirrus_linear_write, s,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
|
||||
/* I/O handler for LFB */
|
||||
s->cirrus_linear_bitblt_io_addr =
|
||||
cpu_register_io_memory(cirrus_linear_bitblt_read,
|
||||
cirrus_linear_bitblt_write, s,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
|
||||
/* I/O handler for memory-mapped I/O */
|
||||
s->cirrus_mmio_io_addr =
|
||||
cpu_register_io_memory(cirrus_mmio_read, cirrus_mmio_write, s,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
|
||||
s->real_vram_size =
|
||||
(s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024;
|
||||
|
14
hw/hw.h
14
hw/hw.h
@ -528,6 +528,17 @@ extern const VMStateInfo vmstate_info_unused_buffer;
|
||||
.start = (_start), \
|
||||
}
|
||||
|
||||
#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _start, _field_size) { \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
||||
.field_exists = (_test), \
|
||||
.size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\
|
||||
.info = &vmstate_info_buffer, \
|
||||
.flags = VMS_VBUFFER|VMS_POINTER, \
|
||||
.offset = offsetof(_state, _field), \
|
||||
.start = (_start), \
|
||||
}
|
||||
|
||||
#define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
||||
@ -745,6 +756,9 @@ extern const VMStateDescription vmstate_i2c_slave;
|
||||
#define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size) \
|
||||
VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size)
|
||||
|
||||
#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size) \
|
||||
VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, 0, _size)
|
||||
|
||||
#define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size) \
|
||||
VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size)
|
||||
|
||||
|
97
hw/pc.c
97
hw/pc.c
@ -40,6 +40,7 @@
|
||||
#include "sysbus.h"
|
||||
#include "sysemu.h"
|
||||
#include "blockdev.h"
|
||||
#include "ui/qemu-spice.h"
|
||||
|
||||
/* output Bochs bios info messages */
|
||||
//#define DEBUG_BIOS
|
||||
@ -410,11 +411,92 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||
qemu_register_reset(pc_cmos_init_late, &arg);
|
||||
}
|
||||
|
||||
/* port 92 stuff: could be split off */
|
||||
typedef struct Port92State {
|
||||
ISADevice dev;
|
||||
uint8_t outport;
|
||||
qemu_irq *a20_out;
|
||||
} Port92State;
|
||||
|
||||
static void port92_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
Port92State *s = opaque;
|
||||
|
||||
DPRINTF("port92: write 0x%02x\n", val);
|
||||
s->outport = val;
|
||||
qemu_set_irq(*s->a20_out, (val >> 1) & 1);
|
||||
if (val & 1) {
|
||||
qemu_system_reset_request();
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t port92_read(void *opaque, uint32_t addr)
|
||||
{
|
||||
Port92State *s = opaque;
|
||||
uint32_t ret;
|
||||
|
||||
ret = s->outport;
|
||||
DPRINTF("port92: read 0x%02x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void port92_init(ISADevice *dev, qemu_irq *a20_out)
|
||||
{
|
||||
Port92State *s = DO_UPCAST(Port92State, dev, dev);
|
||||
|
||||
s->a20_out = a20_out;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_port92_isa = {
|
||||
.name = "port92",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT8(outport, Port92State),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void port92_reset(DeviceState *d)
|
||||
{
|
||||
Port92State *s = container_of(d, Port92State, dev.qdev);
|
||||
|
||||
s->outport &= ~1;
|
||||
}
|
||||
|
||||
static int port92_initfn(ISADevice *dev)
|
||||
{
|
||||
Port92State *s = DO_UPCAST(Port92State, dev, dev);
|
||||
|
||||
register_ioport_read(0x92, 1, 1, port92_read, s);
|
||||
register_ioport_write(0x92, 1, 1, port92_write, s);
|
||||
isa_init_ioport(dev, 0x92);
|
||||
s->outport = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ISADeviceInfo port92_info = {
|
||||
.qdev.name = "port92",
|
||||
.qdev.size = sizeof(Port92State),
|
||||
.qdev.vmsd = &vmstate_port92_isa,
|
||||
.qdev.no_user = 1,
|
||||
.qdev.reset = port92_reset,
|
||||
.init = port92_initfn,
|
||||
};
|
||||
|
||||
static void port92_register(void)
|
||||
{
|
||||
isa_qdev_register(&port92_info);
|
||||
}
|
||||
device_init(port92_register)
|
||||
|
||||
static void handle_a20_line_change(void *opaque, int irq, int level)
|
||||
{
|
||||
CPUState *cpu = opaque;
|
||||
|
||||
/* XXX: send to all CPUs ? */
|
||||
/* XXX: add logic to handle multiple A20 line sources */
|
||||
cpu_x86_set_a20(cpu, level);
|
||||
}
|
||||
|
||||
@ -992,6 +1074,13 @@ void pc_vga_init(PCIBus *pci_bus)
|
||||
pci_vmsvga_init(pci_bus);
|
||||
else
|
||||
fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
|
||||
#ifdef CONFIG_SPICE
|
||||
} else if (qxl_enabled) {
|
||||
if (pci_bus)
|
||||
pci_create_simple(pci_bus, -1, "qxl-vga");
|
||||
else
|
||||
fprintf(stderr, "%s: qxl: no PCI bus\n", __FUNCTION__);
|
||||
#endif
|
||||
} else if (std_vga_enabled) {
|
||||
if (pci_bus) {
|
||||
pci_vga_init(pci_bus);
|
||||
@ -1019,7 +1108,7 @@ void pc_basic_device_init(qemu_irq *isa_irq,
|
||||
PITState *pit;
|
||||
qemu_irq rtc_irq = NULL;
|
||||
qemu_irq *a20_line;
|
||||
ISADevice *i8042;
|
||||
ISADevice *i8042, *port92;
|
||||
qemu_irq *cpu_exit_irq;
|
||||
|
||||
register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
|
||||
@ -1053,10 +1142,12 @@ void pc_basic_device_init(qemu_irq *isa_irq,
|
||||
}
|
||||
}
|
||||
|
||||
a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 1);
|
||||
a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
|
||||
i8042 = isa_create_simple("i8042");
|
||||
i8042_setup_a20_line(i8042, a20_line);
|
||||
i8042_setup_a20_line(i8042, &a20_line[0]);
|
||||
vmmouse_init(i8042);
|
||||
port92 = isa_create_simple("port92");
|
||||
port92_init(port92, &a20_line[1]);
|
||||
|
||||
cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
|
||||
DMA_init(0, cpu_exit_irq);
|
||||
|
19
hw/pckbd.c
19
hw/pckbd.c
@ -211,10 +211,8 @@ static void kbd_queue(KBDState *s, int b, int aux)
|
||||
ps2_queue(s->kbd, b);
|
||||
}
|
||||
|
||||
static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
static void outport_write(KBDState *s, uint32_t val)
|
||||
{
|
||||
KBDState *s = opaque;
|
||||
|
||||
DPRINTF("kbd: write outport=0x%02x\n", val);
|
||||
s->outport = val;
|
||||
if (s->a20_out) {
|
||||
@ -225,16 +223,6 @@ static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t ioport92_read(void *opaque, uint32_t addr)
|
||||
{
|
||||
KBDState *s = opaque;
|
||||
uint32_t ret;
|
||||
|
||||
ret = s->outport;
|
||||
DPRINTF("kbd: read outport=0x%02x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
KBDState *s = opaque;
|
||||
@ -357,7 +345,7 @@ static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
|
||||
kbd_queue(s, val, 1);
|
||||
break;
|
||||
case KBD_CCMD_WRITE_OUTPORT:
|
||||
ioport92_write(s, 0, val);
|
||||
outport_write(s, val);
|
||||
break;
|
||||
case KBD_CCMD_WRITE_MOUSE:
|
||||
ps2_write_mouse(s->mouse, val);
|
||||
@ -489,9 +477,6 @@ static int i8042_initfn(ISADevice *dev)
|
||||
register_ioport_read(0x64, 1, 1, kbd_read_status, s);
|
||||
register_ioport_write(0x64, 1, 1, kbd_write_command, s);
|
||||
isa_init_ioport(dev, 0x64);
|
||||
register_ioport_read(0x92, 1, 1, ioport92_read, s);
|
||||
register_ioport_write(0x92, 1, 1, ioport92_write, s);
|
||||
isa_init_ioport(dev, 0x92);
|
||||
|
||||
s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
|
||||
s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
|
||||
|
248
hw/qxl-logger.c
Normal file
248
hw/qxl-logger.c
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* qxl command logging -- for debug purposes
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* maintained by Gerd Hoffmann <kraxel@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qxl.h"
|
||||
|
||||
static const char *qxl_type[] = {
|
||||
[ QXL_CMD_NOP ] = "nop",
|
||||
[ QXL_CMD_DRAW ] = "draw",
|
||||
[ QXL_CMD_UPDATE ] = "update",
|
||||
[ QXL_CMD_CURSOR ] = "cursor",
|
||||
[ QXL_CMD_MESSAGE ] = "message",
|
||||
[ QXL_CMD_SURFACE ] = "surface",
|
||||
};
|
||||
|
||||
static const char *qxl_draw_type[] = {
|
||||
[ QXL_DRAW_NOP ] = "nop",
|
||||
[ QXL_DRAW_FILL ] = "fill",
|
||||
[ QXL_DRAW_OPAQUE ] = "opaque",
|
||||
[ QXL_DRAW_COPY ] = "copy",
|
||||
[ QXL_COPY_BITS ] = "copy-bits",
|
||||
[ QXL_DRAW_BLEND ] = "blend",
|
||||
[ QXL_DRAW_BLACKNESS ] = "blackness",
|
||||
[ QXL_DRAW_WHITENESS ] = "whitemess",
|
||||
[ QXL_DRAW_INVERS ] = "invers",
|
||||
[ QXL_DRAW_ROP3 ] = "rop3",
|
||||
[ QXL_DRAW_STROKE ] = "stroke",
|
||||
[ QXL_DRAW_TEXT ] = "text",
|
||||
[ QXL_DRAW_TRANSPARENT ] = "transparent",
|
||||
[ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend",
|
||||
};
|
||||
|
||||
static const char *qxl_draw_effect[] = {
|
||||
[ QXL_EFFECT_BLEND ] = "blend",
|
||||
[ QXL_EFFECT_OPAQUE ] = "opaque",
|
||||
[ QXL_EFFECT_REVERT_ON_DUP ] = "revert-on-dup",
|
||||
[ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup",
|
||||
[ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup",
|
||||
[ QXL_EFFECT_NOP_ON_DUP ] = "nop-on-dup",
|
||||
[ QXL_EFFECT_NOP ] = "nop",
|
||||
[ QXL_EFFECT_OPAQUE_BRUSH ] = "opaque-brush",
|
||||
};
|
||||
|
||||
static const char *qxl_surface_cmd[] = {
|
||||
[ QXL_SURFACE_CMD_CREATE ] = "create",
|
||||
[ QXL_SURFACE_CMD_DESTROY ] = "destroy",
|
||||
};
|
||||
|
||||
static const char *spice_surface_fmt[] = {
|
||||
[ SPICE_SURFACE_FMT_INVALID ] = "invalid",
|
||||
[ SPICE_SURFACE_FMT_1_A ] = "alpha/1",
|
||||
[ SPICE_SURFACE_FMT_8_A ] = "alpha/8",
|
||||
[ SPICE_SURFACE_FMT_16_555 ] = "555/16",
|
||||
[ SPICE_SURFACE_FMT_16_565 ] = "565/16",
|
||||
[ SPICE_SURFACE_FMT_32_xRGB ] = "xRGB/32",
|
||||
[ SPICE_SURFACE_FMT_32_ARGB ] = "ARGB/32",
|
||||
};
|
||||
|
||||
static const char *qxl_cursor_cmd[] = {
|
||||
[ QXL_CURSOR_SET ] = "set",
|
||||
[ QXL_CURSOR_MOVE ] = "move",
|
||||
[ QXL_CURSOR_HIDE ] = "hide",
|
||||
[ QXL_CURSOR_TRAIL ] = "trail",
|
||||
};
|
||||
|
||||
static const char *spice_cursor_type[] = {
|
||||
[ SPICE_CURSOR_TYPE_ALPHA ] = "alpha",
|
||||
[ SPICE_CURSOR_TYPE_MONO ] = "mono",
|
||||
[ SPICE_CURSOR_TYPE_COLOR4 ] = "color4",
|
||||
[ SPICE_CURSOR_TYPE_COLOR8 ] = "color8",
|
||||
[ SPICE_CURSOR_TYPE_COLOR16 ] = "color16",
|
||||
[ SPICE_CURSOR_TYPE_COLOR24 ] = "color24",
|
||||
[ SPICE_CURSOR_TYPE_COLOR32 ] = "color32",
|
||||
};
|
||||
|
||||
static const char *qxl_v2n(const char *n[], size_t l, int v)
|
||||
{
|
||||
if (v >= l || !n[v]) {
|
||||
return "???";
|
||||
}
|
||||
return n[v];
|
||||
}
|
||||
#define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value)
|
||||
|
||||
static void qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id)
|
||||
{
|
||||
QXLImage *image;
|
||||
QXLImageDescriptor *desc;
|
||||
|
||||
image = qxl_phys2virt(qxl, addr, group_id);
|
||||
desc = &image->descriptor;
|
||||
fprintf(stderr, " (id %" PRIx64 " type %d flags %d width %d height %d",
|
||||
desc->id, desc->type, desc->flags, desc->width, desc->height);
|
||||
switch (desc->type) {
|
||||
case SPICE_IMAGE_TYPE_BITMAP:
|
||||
fprintf(stderr, ", fmt %d flags %d x %d y %d stride %d"
|
||||
" palette %" PRIx64 " data %" PRIx64,
|
||||
image->bitmap.format, image->bitmap.flags,
|
||||
image->bitmap.x, image->bitmap.y,
|
||||
image->bitmap.stride,
|
||||
image->bitmap.palette, image->bitmap.data);
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, ")");
|
||||
}
|
||||
|
||||
static void qxl_log_rect(QXLRect *rect)
|
||||
{
|
||||
fprintf(stderr, " %dx%d+%d+%d",
|
||||
rect->right - rect->left,
|
||||
rect->bottom - rect->top,
|
||||
rect->left, rect->top);
|
||||
}
|
||||
|
||||
static void qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy, int group_id)
|
||||
{
|
||||
fprintf(stderr, " src %" PRIx64,
|
||||
copy->src_bitmap);
|
||||
qxl_log_image(qxl, copy->src_bitmap, group_id);
|
||||
fprintf(stderr, " area");
|
||||
qxl_log_rect(©->src_area);
|
||||
fprintf(stderr, " rop %d", copy->rop_descriptor);
|
||||
}
|
||||
|
||||
static void qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id)
|
||||
{
|
||||
fprintf(stderr, ": surface_id %d type %s effect %s",
|
||||
draw->surface_id,
|
||||
qxl_name(qxl_draw_type, draw->type),
|
||||
qxl_name(qxl_draw_effect, draw->effect));
|
||||
switch (draw->type) {
|
||||
case QXL_DRAW_COPY:
|
||||
qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw,
|
||||
int group_id)
|
||||
{
|
||||
fprintf(stderr, ": type %s effect %s",
|
||||
qxl_name(qxl_draw_type, draw->type),
|
||||
qxl_name(qxl_draw_effect, draw->effect));
|
||||
if (draw->bitmap_offset) {
|
||||
fprintf(stderr, ": bitmap %d",
|
||||
draw->bitmap_offset);
|
||||
qxl_log_rect(&draw->bitmap_area);
|
||||
}
|
||||
switch (draw->type) {
|
||||
case QXL_DRAW_COPY:
|
||||
qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd)
|
||||
{
|
||||
fprintf(stderr, ": %s id %d",
|
||||
qxl_name(qxl_surface_cmd, cmd->type),
|
||||
cmd->surface_id);
|
||||
if (cmd->type == QXL_SURFACE_CMD_CREATE) {
|
||||
fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)",
|
||||
cmd->u.surface_create.width,
|
||||
cmd->u.surface_create.height,
|
||||
cmd->u.surface_create.stride,
|
||||
qxl_name(spice_surface_fmt, cmd->u.surface_create.format),
|
||||
qxl->guest_surfaces.count, qxl->guest_surfaces.max);
|
||||
}
|
||||
if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
|
||||
fprintf(stderr, " (count %d)", qxl->guest_surfaces.count);
|
||||
}
|
||||
}
|
||||
|
||||
void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id)
|
||||
{
|
||||
QXLCursor *cursor;
|
||||
|
||||
fprintf(stderr, ": %s",
|
||||
qxl_name(qxl_cursor_cmd, cmd->type));
|
||||
switch (cmd->type) {
|
||||
case QXL_CURSOR_SET:
|
||||
fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64,
|
||||
cmd->u.set.position.x,
|
||||
cmd->u.set.position.y,
|
||||
cmd->u.set.visible ? "yes" : "no",
|
||||
cmd->u.set.shape);
|
||||
cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
|
||||
fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d"
|
||||
" unique 0x%" PRIx64 " data-size %d",
|
||||
qxl_name(spice_cursor_type, cursor->header.type),
|
||||
cursor->header.width, cursor->header.height,
|
||||
cursor->header.hot_spot_x, cursor->header.hot_spot_y,
|
||||
cursor->header.unique, cursor->data_size);
|
||||
break;
|
||||
case QXL_CURSOR_MOVE:
|
||||
fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
|
||||
{
|
||||
bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
|
||||
void *data;
|
||||
|
||||
if (!qxl->cmdlog) {
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "qxl-%d/%s:", qxl->id, ring);
|
||||
fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
|
||||
qxl_name(qxl_type, ext->cmd.type),
|
||||
compat ? "(compat)" : "");
|
||||
|
||||
data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
|
||||
switch (ext->cmd.type) {
|
||||
case QXL_CMD_DRAW:
|
||||
if (!compat) {
|
||||
qxl_log_cmd_draw(qxl, data, ext->group_id);
|
||||
} else {
|
||||
qxl_log_cmd_draw_compat(qxl, data, ext->group_id);
|
||||
}
|
||||
break;
|
||||
case QXL_CMD_SURFACE:
|
||||
qxl_log_cmd_surface(qxl, data);
|
||||
break;
|
||||
case QXL_CMD_CURSOR:
|
||||
qxl_log_cmd_cursor(qxl, data, ext->group_id);
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
226
hw/qxl-render.c
Normal file
226
hw/qxl-render.c
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
* qxl local rendering (aka display on sdl/vnc)
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* maintained by Gerd Hoffmann <kraxel@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 or
|
||||
* (at your option) version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qxl.h"
|
||||
|
||||
static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect)
|
||||
{
|
||||
uint8_t *src = qxl->guest_primary.data;
|
||||
uint8_t *dst = qxl->guest_primary.flipped;
|
||||
int len, i;
|
||||
|
||||
src += (qxl->guest_primary.surface.height - rect->top - 1) *
|
||||
qxl->guest_primary.stride;
|
||||
dst += rect->top * qxl->guest_primary.stride;
|
||||
src += rect->left * qxl->guest_primary.bytes_pp;
|
||||
dst += rect->left * qxl->guest_primary.bytes_pp;
|
||||
len = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;
|
||||
|
||||
for (i = rect->top; i < rect->bottom; i++) {
|
||||
memcpy(dst, src, len);
|
||||
dst += qxl->guest_primary.stride;
|
||||
src -= qxl->guest_primary.stride;
|
||||
}
|
||||
}
|
||||
|
||||
void qxl_render_resize(PCIQXLDevice *qxl)
|
||||
{
|
||||
QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
|
||||
|
||||
qxl->guest_primary.stride = sc->stride;
|
||||
qxl->guest_primary.resized++;
|
||||
switch (sc->format) {
|
||||
case SPICE_SURFACE_FMT_16_555:
|
||||
qxl->guest_primary.bytes_pp = 2;
|
||||
qxl->guest_primary.bits_pp = 15;
|
||||
break;
|
||||
case SPICE_SURFACE_FMT_16_565:
|
||||
qxl->guest_primary.bytes_pp = 2;
|
||||
qxl->guest_primary.bits_pp = 16;
|
||||
break;
|
||||
case SPICE_SURFACE_FMT_32_xRGB:
|
||||
case SPICE_SURFACE_FMT_32_ARGB:
|
||||
qxl->guest_primary.bytes_pp = 4;
|
||||
qxl->guest_primary.bits_pp = 32;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__,
|
||||
qxl->guest_primary.surface.format);
|
||||
qxl->guest_primary.bytes_pp = 4;
|
||||
qxl->guest_primary.bits_pp = 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void qxl_render_update(PCIQXLDevice *qxl)
|
||||
{
|
||||
VGACommonState *vga = &qxl->vga;
|
||||
QXLRect dirty[32], update;
|
||||
void *ptr;
|
||||
int i;
|
||||
|
||||
if (qxl->guest_primary.resized) {
|
||||
qxl->guest_primary.resized = 0;
|
||||
|
||||
if (qxl->guest_primary.flipped) {
|
||||
qemu_free(qxl->guest_primary.flipped);
|
||||
qxl->guest_primary.flipped = NULL;
|
||||
}
|
||||
qemu_free_displaysurface(vga->ds);
|
||||
|
||||
qxl->guest_primary.data = qemu_get_ram_ptr(qxl->vga.vram_offset);
|
||||
if (qxl->guest_primary.stride < 0) {
|
||||
/* spice surface is upside down -> need extra buffer to flip */
|
||||
qxl->guest_primary.stride = -qxl->guest_primary.stride;
|
||||
qxl->guest_primary.flipped = qemu_malloc(qxl->guest_primary.surface.width *
|
||||
qxl->guest_primary.stride);
|
||||
ptr = qxl->guest_primary.flipped;
|
||||
} else {
|
||||
ptr = qxl->guest_primary.data;
|
||||
}
|
||||
dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n",
|
||||
__FUNCTION__,
|
||||
qxl->guest_primary.surface.width,
|
||||
qxl->guest_primary.surface.height,
|
||||
qxl->guest_primary.stride,
|
||||
qxl->guest_primary.bytes_pp,
|
||||
qxl->guest_primary.bits_pp,
|
||||
qxl->guest_primary.flipped ? "yes" : "no");
|
||||
vga->ds->surface =
|
||||
qemu_create_displaysurface_from(qxl->guest_primary.surface.width,
|
||||
qxl->guest_primary.surface.height,
|
||||
qxl->guest_primary.bits_pp,
|
||||
qxl->guest_primary.stride,
|
||||
ptr);
|
||||
dpy_resize(vga->ds);
|
||||
}
|
||||
|
||||
if (!qxl->guest_primary.commands) {
|
||||
return;
|
||||
}
|
||||
qxl->guest_primary.commands = 0;
|
||||
|
||||
update.left = 0;
|
||||
update.right = qxl->guest_primary.surface.width;
|
||||
update.top = 0;
|
||||
update.bottom = qxl->guest_primary.surface.height;
|
||||
|
||||
memset(dirty, 0, sizeof(dirty));
|
||||
qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update,
|
||||
dirty, ARRAY_SIZE(dirty), 1);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dirty); i++) {
|
||||
if (qemu_spice_rect_is_empty(dirty+i)) {
|
||||
break;
|
||||
}
|
||||
if (qxl->guest_primary.flipped) {
|
||||
qxl_flip(qxl, dirty+i);
|
||||
}
|
||||
dpy_update(vga->ds,
|
||||
dirty[i].left, dirty[i].top,
|
||||
dirty[i].right - dirty[i].left,
|
||||
dirty[i].bottom - dirty[i].top);
|
||||
}
|
||||
}
|
||||
|
||||
static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
|
||||
{
|
||||
QEMUCursor *c;
|
||||
uint8_t *image, *mask;
|
||||
int size;
|
||||
|
||||
c = cursor_alloc(cursor->header.width, cursor->header.height);
|
||||
c->hot_x = cursor->header.hot_spot_x;
|
||||
c->hot_y = cursor->header.hot_spot_y;
|
||||
switch (cursor->header.type) {
|
||||
case SPICE_CURSOR_TYPE_ALPHA:
|
||||
size = cursor->header.width * cursor->header.height * sizeof(uint32_t);
|
||||
memcpy(c->data, cursor->chunk.data, size);
|
||||
if (qxl->debug > 2) {
|
||||
cursor_print_ascii_art(c, "qxl/alpha");
|
||||
}
|
||||
break;
|
||||
case SPICE_CURSOR_TYPE_MONO:
|
||||
mask = cursor->chunk.data;
|
||||
image = mask + cursor_get_mono_bpl(c) * c->width;
|
||||
cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask);
|
||||
if (qxl->debug > 2) {
|
||||
cursor_print_ascii_art(c, "qxl/mono");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: not implemented: type %d\n",
|
||||
__FUNCTION__, cursor->header.type);
|
||||
goto fail;
|
||||
}
|
||||
return c;
|
||||
|
||||
fail:
|
||||
cursor_put(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* called from spice server thread context only */
|
||||
void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
|
||||
{
|
||||
QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
|
||||
QXLCursor *cursor;
|
||||
QEMUCursor *c;
|
||||
int x = -1, y = -1;
|
||||
|
||||
if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) {
|
||||
fprintf(stderr, "%s", __FUNCTION__);
|
||||
qxl_log_cmd_cursor(qxl, cmd, ext->group_id);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
switch (cmd->type) {
|
||||
case QXL_CURSOR_SET:
|
||||
x = cmd->u.set.position.x;
|
||||
y = cmd->u.set.position.y;
|
||||
cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
|
||||
if (cursor->chunk.data_size != cursor->data_size) {
|
||||
fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
c = qxl_cursor(qxl, cursor);
|
||||
if (c == NULL) {
|
||||
c = cursor_builtin_left_ptr();
|
||||
}
|
||||
qemu_mutex_lock_iothread();
|
||||
qxl->ssd.ds->cursor_define(c);
|
||||
qxl->ssd.ds->mouse_set(x, y, 1);
|
||||
qemu_mutex_unlock_iothread();
|
||||
cursor_put(c);
|
||||
break;
|
||||
case QXL_CURSOR_MOVE:
|
||||
x = cmd->u.position.x;
|
||||
y = cmd->u.position.y;
|
||||
qemu_mutex_lock_iothread();
|
||||
qxl->ssd.ds->mouse_set(x, y, 1);
|
||||
qemu_mutex_unlock_iothread();
|
||||
break;
|
||||
}
|
||||
}
|
112
hw/qxl.h
Normal file
112
hw/qxl.h
Normal file
@ -0,0 +1,112 @@
|
||||
#include "qemu-common.h"
|
||||
|
||||
#include "console.h"
|
||||
#include "hw.h"
|
||||
#include "pci.h"
|
||||
#include "vga_int.h"
|
||||
|
||||
#include "ui/qemu-spice.h"
|
||||
#include "ui/spice-display.h"
|
||||
|
||||
enum qxl_mode {
|
||||
QXL_MODE_UNDEFINED,
|
||||
QXL_MODE_VGA,
|
||||
QXL_MODE_COMPAT, /* spice 0.4.x */
|
||||
QXL_MODE_NATIVE,
|
||||
};
|
||||
|
||||
typedef struct PCIQXLDevice {
|
||||
PCIDevice pci;
|
||||
SimpleSpiceDisplay ssd;
|
||||
int id;
|
||||
uint32_t debug;
|
||||
uint32_t guestdebug;
|
||||
uint32_t cmdlog;
|
||||
enum qxl_mode mode;
|
||||
uint32_t cmdflags;
|
||||
int generation;
|
||||
uint32_t revision;
|
||||
|
||||
int32_t num_memslots;
|
||||
int32_t num_surfaces;
|
||||
|
||||
struct guest_slots {
|
||||
QXLMemSlot slot;
|
||||
void *ptr;
|
||||
uint64_t size;
|
||||
uint64_t delta;
|
||||
uint32_t active;
|
||||
} guest_slots[NUM_MEMSLOTS];
|
||||
|
||||
struct guest_primary {
|
||||
QXLSurfaceCreate surface;
|
||||
uint32_t commands;
|
||||
uint32_t resized;
|
||||
int32_t stride;
|
||||
uint32_t bits_pp;
|
||||
uint32_t bytes_pp;
|
||||
uint8_t *data, *flipped;
|
||||
} guest_primary;
|
||||
|
||||
struct surfaces {
|
||||
QXLPHYSICAL cmds[NUM_SURFACES];
|
||||
uint32_t count;
|
||||
uint32_t max;
|
||||
} guest_surfaces;
|
||||
QXLPHYSICAL guest_cursor;
|
||||
|
||||
/* thread signaling */
|
||||
pthread_t main;
|
||||
int pipe[2];
|
||||
|
||||
/* ram pci bar */
|
||||
QXLRam *ram;
|
||||
VGACommonState vga;
|
||||
uint32_t num_free_res;
|
||||
QXLReleaseInfo *last_release;
|
||||
uint32_t last_release_offset;
|
||||
uint32_t oom_running;
|
||||
|
||||
/* rom pci bar */
|
||||
QXLRom shadow_rom;
|
||||
QXLRom *rom;
|
||||
QXLModes *modes;
|
||||
uint32_t rom_size;
|
||||
uint64_t rom_offset;
|
||||
|
||||
/* vram pci bar */
|
||||
uint32_t vram_size;
|
||||
uint64_t vram_offset;
|
||||
|
||||
/* io bar */
|
||||
uint32_t io_base;
|
||||
|
||||
/* spice 0.4 loadvm compatibility */
|
||||
void *worker_data;
|
||||
uint32_t worker_data_size;
|
||||
} PCIQXLDevice;
|
||||
|
||||
#define PANIC_ON(x) if ((x)) { \
|
||||
printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \
|
||||
exit(-1); \
|
||||
}
|
||||
|
||||
#define dprint(_qxl, _level, _fmt, ...) \
|
||||
do { \
|
||||
if (_qxl->debug >= _level) { \
|
||||
fprintf(stderr, "qxl-%d: ", _qxl->id); \
|
||||
fprintf(stderr, _fmt, ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* qxl.c */
|
||||
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
|
||||
|
||||
/* qxl-logger.c */
|
||||
void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
|
||||
void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
|
||||
|
||||
/* qxl-render.c */
|
||||
void qxl_render_resize(PCIQXLDevice *qxl);
|
||||
void qxl_render_update(PCIQXLDevice *qxl);
|
||||
void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
|
@ -17,6 +17,8 @@
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "virtio-net.h"
|
||||
|
||||
#define VIRTIO_DEV_OFFS_TYPE 0 /* 8 bits */
|
||||
#define VIRTIO_DEV_OFFS_NUM_VQ 1 /* 8 bits */
|
||||
#define VIRTIO_DEV_OFFS_FEATURE_LEN 2 /* 8 bits */
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "hw.h"
|
||||
#include "block.h"
|
||||
#include "blockdev.h"
|
||||
#include "sysemu.h"
|
||||
#include "net.h"
|
||||
#include "boards.h"
|
||||
|
@ -670,6 +670,8 @@ static void sh7750_mmct_writel(void *opaque, target_phys_addr_t addr,
|
||||
/* do nothing */
|
||||
break;
|
||||
case MM_ITLB_ADDR:
|
||||
cpu_sh4_write_mmaped_itlb_addr(s->cpu, addr, mem_value);
|
||||
break;
|
||||
case MM_ITLB_DATA:
|
||||
/* XXXXX */
|
||||
abort();
|
||||
|
@ -44,7 +44,7 @@
|
||||
/* We need the mask, because one instance of the device is not page
|
||||
aligned (ledma, start address 0x0010) */
|
||||
#define DMA_MASK (DMA_SIZE - 1)
|
||||
/* ledma has more than 4 registers, Solaris reads the 5th one */
|
||||
/* OBP says 0x20 bytes for ledma, the extras are aliased to espdma */
|
||||
#define DMA_ETH_SIZE (8 * sizeof(uint32_t))
|
||||
#define DMA_MAX_REG_OFFSET (2 * DMA_SIZE - 1)
|
||||
|
||||
@ -170,7 +170,10 @@ static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr)
|
||||
uint32_t saddr;
|
||||
|
||||
if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
|
||||
return 0; /* extra mystery register(s) */
|
||||
/* aliased to espdma, but we can't get there from here */
|
||||
/* buggy driver if using undocumented behavior, just return 0 */
|
||||
trace_sparc32_dma_mem_readl(addr, 0);
|
||||
return 0;
|
||||
}
|
||||
saddr = (addr & DMA_MASK) >> 2;
|
||||
trace_sparc32_dma_mem_readl(addr, s->dmaregs[saddr]);
|
||||
@ -183,7 +186,9 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
uint32_t saddr;
|
||||
|
||||
if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
|
||||
return; /* extra mystery register(s) */
|
||||
/* aliased to espdma, but we can't get there from here */
|
||||
trace_sparc32_dma_mem_writel(addr, 0, val);
|
||||
return;
|
||||
}
|
||||
saddr = (addr & DMA_MASK) >> 2;
|
||||
trace_sparc32_dma_mem_writel(addr, s->dmaregs[saddr], val);
|
||||
|
6
hw/vga.c
6
hw/vga.c
@ -2073,14 +2073,14 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
|
||||
|
||||
if (full_update) {
|
||||
for (i = 0; i < size; src ++, dst ++, i ++)
|
||||
console_write_ch(dst, VMEM2CHTYPE(*src));
|
||||
console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
|
||||
|
||||
dpy_update(s->ds, 0, 0, width, height);
|
||||
} else {
|
||||
c_max = 0;
|
||||
|
||||
for (i = 0; i < size; src ++, dst ++, i ++) {
|
||||
console_write_ch(&val, VMEM2CHTYPE(*src));
|
||||
console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
|
||||
if (*dst != val) {
|
||||
*dst = val;
|
||||
c_max = i;
|
||||
@ -2089,7 +2089,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
|
||||
}
|
||||
c_min = i;
|
||||
for (; i < size; src ++, dst ++, i ++) {
|
||||
console_write_ch(&val, VMEM2CHTYPE(*src));
|
||||
console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
|
||||
if (*dst != val) {
|
||||
*dst = val;
|
||||
c_max = i;
|
||||
|
@ -106,7 +106,7 @@ typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s);
|
||||
typedef struct VGACommonState {
|
||||
uint8_t *vram_ptr;
|
||||
ram_addr_t vram_offset;
|
||||
unsigned int vram_size;
|
||||
uint32_t vram_size;
|
||||
uint32_t lfb_addr;
|
||||
uint32_t lfb_end;
|
||||
uint32_t map_addr;
|
||||
|
@ -53,7 +53,7 @@ static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data)
|
||||
30, 28, 26, 24, 22, 20, 18, 16,
|
||||
14, 12, 10, 8, 6, 4, 2, 0
|
||||
};
|
||||
int64 timeout;
|
||||
int64_t timeout;
|
||||
|
||||
ib700_debug("addr = %x, data = %x\n", addr, data);
|
||||
|
||||
|
@ -199,21 +199,21 @@ static unsigned int PerformComparison(const unsigned int opcode)
|
||||
{
|
||||
case typeSingle:
|
||||
//printk("single.\n");
|
||||
if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
|
||||
if (float32_is_any_nan(fpa11->fpreg[Fn].fSingle))
|
||||
goto unordered;
|
||||
rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
|
||||
break;
|
||||
|
||||
case typeDouble:
|
||||
//printk("double.\n");
|
||||
if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
|
||||
if (float64_is_any_nan(fpa11->fpreg[Fn].fDouble))
|
||||
goto unordered;
|
||||
rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
|
||||
break;
|
||||
|
||||
case typeExtended:
|
||||
//printk("extended.\n");
|
||||
if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
|
||||
if (floatx80_is_any_nan(fpa11->fpreg[Fn].fExtended))
|
||||
goto unordered;
|
||||
rFn = fpa11->fpreg[Fn].fExtended;
|
||||
break;
|
||||
@ -225,7 +225,7 @@ static unsigned int PerformComparison(const unsigned int opcode)
|
||||
{
|
||||
//printk("Fm is a constant: #%d.\n",Fm);
|
||||
rFm = getExtendedConstant(Fm);
|
||||
if (floatx80_is_nan(rFm))
|
||||
if (floatx80_is_any_nan(rFm))
|
||||
goto unordered;
|
||||
}
|
||||
else
|
||||
@ -235,21 +235,21 @@ static unsigned int PerformComparison(const unsigned int opcode)
|
||||
{
|
||||
case typeSingle:
|
||||
//printk("single.\n");
|
||||
if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
|
||||
if (float32_is_any_nan(fpa11->fpreg[Fm].fSingle))
|
||||
goto unordered;
|
||||
rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
|
||||
break;
|
||||
|
||||
case typeDouble:
|
||||
//printk("double.\n");
|
||||
if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
|
||||
if (float64_is_any_nan(fpa11->fpreg[Fm].fDouble))
|
||||
goto unordered;
|
||||
rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
|
||||
break;
|
||||
|
||||
case typeExtended:
|
||||
//printk("extended.\n");
|
||||
if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
|
||||
if (floatx80_is_any_nan(fpa11->fpreg[Fm].fExtended))
|
||||
goto unordered;
|
||||
rFm = fpa11->fpreg[Fm].fExtended;
|
||||
break;
|
||||
|
@ -76,6 +76,10 @@
|
||||
#ifdef FIGETBSZ
|
||||
IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG))
|
||||
#endif
|
||||
#ifdef FS_IOC_FIEMAP
|
||||
IOCTL_SPECIAL(FS_IOC_FIEMAP, IOC_W | IOC_R, do_ioctl_fs_ioc_fiemap,
|
||||
MK_PTR(MK_STRUCT(STRUCT_fiemap)))
|
||||
#endif
|
||||
|
||||
IOCTL(SIOCATMARK, 0, TYPE_NULL)
|
||||
IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
|
||||
|
@ -174,8 +174,6 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
|
||||
|
||||
retval = prepare_binprm(bprm);
|
||||
|
||||
infop->host_argv = argv;
|
||||
|
||||
if(retval>=0) {
|
||||
if (bprm->buf[0] == 0x7f
|
||||
&& bprm->buf[1] == 'E'
|
||||
|
@ -50,7 +50,6 @@ struct image_info {
|
||||
abi_ulong saved_auxv;
|
||||
abi_ulong arg_start;
|
||||
abi_ulong arg_end;
|
||||
char **host_argv;
|
||||
int personality;
|
||||
};
|
||||
|
||||
|
@ -1518,3 +1518,9 @@
|
||||
#ifdef TARGET_NR_utimensat
|
||||
{ TARGET_NR_utimensat, "utimensat", NULL, print_utimensat, NULL },
|
||||
#endif
|
||||
#ifdef TARGET_NR_sync_file_range
|
||||
{ TARGET_NR_sync_file_range, "sync_file_range", NULL, NULL, NULL },
|
||||
#endif
|
||||
#ifdef TARGET_NR_sync_file_range2
|
||||
{ TARGET_NR_sync_file_range2, "sync_file_range2", NULL, NULL, NULL },
|
||||
#endif
|
||||
|
@ -83,6 +83,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
|
||||
#include <linux/kd.h>
|
||||
#include <linux/mtio.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vt.h>
|
||||
#include "linux_loop.h"
|
||||
@ -2965,13 +2966,19 @@ enum {
|
||||
#undef STRUCT
|
||||
#undef STRUCT_SPECIAL
|
||||
|
||||
typedef struct IOCTLEntry {
|
||||
typedef struct IOCTLEntry IOCTLEntry;
|
||||
|
||||
typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
|
||||
int fd, abi_long cmd, abi_long arg);
|
||||
|
||||
struct IOCTLEntry {
|
||||
unsigned int target_cmd;
|
||||
unsigned int host_cmd;
|
||||
const char *name;
|
||||
int access;
|
||||
do_ioctl_fn *do_ioctl;
|
||||
const argtype arg_type[5];
|
||||
} IOCTLEntry;
|
||||
};
|
||||
|
||||
#define IOC_R 0x0001
|
||||
#define IOC_W 0x0002
|
||||
@ -2979,9 +2986,98 @@ typedef struct IOCTLEntry {
|
||||
|
||||
#define MAX_STRUCT_SIZE 4096
|
||||
|
||||
/* So fiemap access checks don't overflow on 32 bit systems.
|
||||
* This is very slightly smaller than the limit imposed by
|
||||
* the underlying kernel.
|
||||
*/
|
||||
#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap)) \
|
||||
/ sizeof(struct fiemap_extent))
|
||||
|
||||
static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
|
||||
int fd, abi_long cmd, abi_long arg)
|
||||
{
|
||||
/* The parameter for this ioctl is a struct fiemap followed
|
||||
* by an array of struct fiemap_extent whose size is set
|
||||
* in fiemap->fm_extent_count. The array is filled in by the
|
||||
* ioctl.
|
||||
*/
|
||||
int target_size_in, target_size_out;
|
||||
struct fiemap *fm;
|
||||
const argtype *arg_type = ie->arg_type;
|
||||
const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
|
||||
void *argptr, *p;
|
||||
abi_long ret;
|
||||
int i, extent_size = thunk_type_size(extent_arg_type, 0);
|
||||
uint32_t outbufsz;
|
||||
int free_fm = 0;
|
||||
|
||||
assert(arg_type[0] == TYPE_PTR);
|
||||
assert(ie->access == IOC_RW);
|
||||
arg_type++;
|
||||
target_size_in = thunk_type_size(arg_type, 0);
|
||||
argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
|
||||
if (!argptr) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
|
||||
unlock_user(argptr, arg, 0);
|
||||
fm = (struct fiemap *)buf_temp;
|
||||
if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
|
||||
outbufsz = sizeof (*fm) +
|
||||
(sizeof(struct fiemap_extent) * fm->fm_extent_count);
|
||||
|
||||
if (outbufsz > MAX_STRUCT_SIZE) {
|
||||
/* We can't fit all the extents into the fixed size buffer.
|
||||
* Allocate one that is large enough and use it instead.
|
||||
*/
|
||||
fm = malloc(outbufsz);
|
||||
if (!fm) {
|
||||
return -TARGET_ENOMEM;
|
||||
}
|
||||
memcpy(fm, buf_temp, sizeof(struct fiemap));
|
||||
free_fm = 1;
|
||||
}
|
||||
ret = get_errno(ioctl(fd, ie->host_cmd, fm));
|
||||
if (!is_error(ret)) {
|
||||
target_size_out = target_size_in;
|
||||
/* An extent_count of 0 means we were only counting the extents
|
||||
* so there are no structs to copy
|
||||
*/
|
||||
if (fm->fm_extent_count != 0) {
|
||||
target_size_out += fm->fm_mapped_extents * extent_size;
|
||||
}
|
||||
argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
|
||||
if (!argptr) {
|
||||
ret = -TARGET_EFAULT;
|
||||
} else {
|
||||
/* Convert the struct fiemap */
|
||||
thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
|
||||
if (fm->fm_extent_count != 0) {
|
||||
p = argptr + target_size_in;
|
||||
/* ...and then all the struct fiemap_extents */
|
||||
for (i = 0; i < fm->fm_mapped_extents; i++) {
|
||||
thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
|
||||
THUNK_TARGET);
|
||||
p += extent_size;
|
||||
}
|
||||
}
|
||||
unlock_user(argptr, arg, target_size_out);
|
||||
}
|
||||
}
|
||||
if (free_fm) {
|
||||
free(fm);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static IOCTLEntry ioctl_entries[] = {
|
||||
#define IOCTL(cmd, access, ...) \
|
||||
{ TARGET_ ## cmd, cmd, #cmd, access, { __VA_ARGS__ } },
|
||||
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
|
||||
#define IOCTL_SPECIAL(cmd, access, dofn, ...) \
|
||||
{ TARGET_ ## cmd, cmd, #cmd, access, dofn, { __VA_ARGS__ } },
|
||||
#include "ioctls.h"
|
||||
{ 0, 0, },
|
||||
};
|
||||
@ -3011,6 +3107,10 @@ static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
|
||||
#if defined(DEBUG)
|
||||
gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
|
||||
#endif
|
||||
if (ie->do_ioctl) {
|
||||
return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
|
||||
}
|
||||
|
||||
switch(arg_type[0]) {
|
||||
case TYPE_NULL:
|
||||
/* no argument */
|
||||
@ -7364,6 +7464,29 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
case TARGET_NR_fallocate:
|
||||
ret = get_errno(fallocate(arg1, arg2, arg3, arg4));
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_SYNC_FILE_RANGE)
|
||||
#if defined(TARGET_NR_sync_file_range)
|
||||
case TARGET_NR_sync_file_range:
|
||||
#if TARGET_ABI_BITS == 32
|
||||
ret = get_errno(sync_file_range(arg1, target_offset64(arg2, arg3),
|
||||
target_offset64(arg4, arg5), arg6));
|
||||
#else
|
||||
ret = get_errno(sync_file_range(arg1, arg2, arg3, arg4));
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
#if defined(TARGET_NR_sync_file_range2)
|
||||
case TARGET_NR_sync_file_range2:
|
||||
/* This is like sync_file_range but the arguments are reordered */
|
||||
#if TARGET_ABI_BITS == 32
|
||||
ret = get_errno(sync_file_range(arg1, target_offset64(arg3, arg4),
|
||||
target_offset64(arg5, arg6), arg2));
|
||||
#else
|
||||
ret = get_errno(sync_file_range(arg1, arg3, arg4, arg2));
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
default:
|
||||
unimplemented:
|
||||
|
@ -783,6 +783,7 @@ struct target_pollfd {
|
||||
#define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */
|
||||
#define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */
|
||||
#define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */
|
||||
#define TARGET_FS_IOC_FIEMAP TARGET_IOWR('f',11,struct fiemap)
|
||||
|
||||
/* cdrom commands */
|
||||
#define TARGET_CDROMPAUSE 0x5301 /* Pause Audio Operation */
|
||||
|
@ -165,3 +165,19 @@ STRUCT(vt_stat,
|
||||
TYPE_SHORT, /* v_active */
|
||||
TYPE_SHORT, /* v_signal */
|
||||
TYPE_SHORT) /* v_state */
|
||||
|
||||
STRUCT(fiemap_extent,
|
||||
TYPE_ULONGLONG, /* fe_logical */
|
||||
TYPE_ULONGLONG, /* fe_physical */
|
||||
TYPE_ULONGLONG, /* fe_length */
|
||||
MK_ARRAY(TYPE_ULONGLONG, 2), /* fe_reserved64[2] */
|
||||
TYPE_INT, /* fe_flags */
|
||||
MK_ARRAY(TYPE_INT, 3)) /* fe_reserved[3] */
|
||||
|
||||
STRUCT(fiemap,
|
||||
TYPE_ULONGLONG, /* fm_start */
|
||||
TYPE_ULONGLONG, /* fm_length */
|
||||
TYPE_INT, /* fm_flags */
|
||||
TYPE_INT, /* fm_mapped_extents */
|
||||
TYPE_INT, /* fm_extent_count */
|
||||
TYPE_INT) /* fm_reserved */
|
||||
|
141
monitor.c
141
monitor.c
@ -34,6 +34,7 @@
|
||||
#include "net.h"
|
||||
#include "net/slirp.h"
|
||||
#include "qemu-char.h"
|
||||
#include "ui/qemu-spice.h"
|
||||
#include "sysemu.h"
|
||||
#include "monitor.h"
|
||||
#include "readline.h"
|
||||
@ -59,6 +60,7 @@
|
||||
#ifdef CONFIG_SIMPLE_TRACE
|
||||
#include "trace.h"
|
||||
#endif
|
||||
#include "ui/qemu-spice.h"
|
||||
|
||||
//#define DEBUG
|
||||
//#define DEBUG_COMPLETION
|
||||
@ -457,6 +459,15 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
|
||||
case QEVENT_WATCHDOG:
|
||||
event_name = "WATCHDOG";
|
||||
break;
|
||||
case QEVENT_SPICE_CONNECTED:
|
||||
event_name = "SPICE_CONNECTED";
|
||||
break;
|
||||
case QEVENT_SPICE_INITIALIZED:
|
||||
event_name = "SPICE_INITIALIZED";
|
||||
break;
|
||||
case QEVENT_SPICE_DISCONNECTED:
|
||||
event_name = "SPICE_DISCONNECTED";
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
@ -1063,6 +1074,105 @@ static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
const char *protocol = qdict_get_str(qdict, "protocol");
|
||||
const char *password = qdict_get_str(qdict, "password");
|
||||
const char *connected = qdict_get_try_str(qdict, "connected");
|
||||
int disconnect_if_connected = 0;
|
||||
int fail_if_connected = 0;
|
||||
int rc;
|
||||
|
||||
if (connected) {
|
||||
if (strcmp(connected, "fail") == 0) {
|
||||
fail_if_connected = 1;
|
||||
} else if (strcmp(connected, "disconnect") == 0) {
|
||||
disconnect_if_connected = 1;
|
||||
} else if (strcmp(connected, "keep") == 0) {
|
||||
/* nothing */
|
||||
} else {
|
||||
qerror_report(QERR_INVALID_PARAMETER, "connected");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(protocol, "spice") == 0) {
|
||||
if (!using_spice) {
|
||||
/* correct one? spice isn't a device ,,, */
|
||||
qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
|
||||
return -1;
|
||||
}
|
||||
rc = qemu_spice_set_passwd(password, fail_if_connected,
|
||||
disconnect_if_connected);
|
||||
if (rc != 0) {
|
||||
qerror_report(QERR_SET_PASSWD_FAILED);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(protocol, "vnc") == 0) {
|
||||
if (fail_if_connected || disconnect_if_connected) {
|
||||
/* vnc supports "connected=keep" only */
|
||||
qerror_report(QERR_INVALID_PARAMETER, "connected");
|
||||
return -1;
|
||||
}
|
||||
rc = vnc_display_password(NULL, password);
|
||||
if (rc != 0) {
|
||||
qerror_report(QERR_SET_PASSWD_FAILED);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
qerror_report(QERR_INVALID_PARAMETER, "protocol");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
const char *protocol = qdict_get_str(qdict, "protocol");
|
||||
const char *whenstr = qdict_get_str(qdict, "time");
|
||||
time_t when;
|
||||
int rc;
|
||||
|
||||
if (strcmp(whenstr, "now")) {
|
||||
when = 0;
|
||||
} else if (strcmp(whenstr, "never")) {
|
||||
when = TIME_MAX;
|
||||
} else if (whenstr[0] == '+') {
|
||||
when = time(NULL) + strtoull(whenstr+1, NULL, 10);
|
||||
} else {
|
||||
when = strtoull(whenstr, NULL, 10);
|
||||
}
|
||||
|
||||
if (strcmp(protocol, "spice") == 0) {
|
||||
if (!using_spice) {
|
||||
/* correct one? spice isn't a device ,,, */
|
||||
qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
|
||||
return -1;
|
||||
}
|
||||
rc = qemu_spice_set_pw_expire(when);
|
||||
if (rc != 0) {
|
||||
qerror_report(QERR_SET_PASSWD_FAILED);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(protocol, "vnc") == 0) {
|
||||
rc = vnc_display_pw_expire(NULL, when);
|
||||
if (rc != 0) {
|
||||
qerror_report(QERR_SET_PASSWD_FAILED);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
qerror_report(QERR_INVALID_PARAMETER, "protocol");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int do_screen_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
vga_hw_screen_dump(qdict_get_str(qdict, "filename"));
|
||||
@ -2272,6 +2382,15 @@ static void tlb_info(Monitor *mon)
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_SPARC)
|
||||
static void tlb_info(Monitor *mon)
|
||||
{
|
||||
CPUState *env1 = mon_get_cpu();
|
||||
|
||||
dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void do_info_kvm_print(Monitor *mon, const QObject *data)
|
||||
{
|
||||
QDict *qdict;
|
||||
@ -2744,7 +2863,7 @@ static const mon_cmd_t info_cmds[] = {
|
||||
.user_print = do_pci_info_print,
|
||||
.mhandler.info_new = do_pci_info,
|
||||
},
|
||||
#if defined(TARGET_I386) || defined(TARGET_SH4)
|
||||
#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC)
|
||||
{
|
||||
.name = "tlb",
|
||||
.args_type = "",
|
||||
@ -2850,6 +2969,16 @@ static const mon_cmd_t info_cmds[] = {
|
||||
.user_print = do_info_vnc_print,
|
||||
.mhandler.info_new = do_info_vnc,
|
||||
},
|
||||
#if defined(CONFIG_SPICE)
|
||||
{
|
||||
.name = "spice",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the spice server status",
|
||||
.user_print = do_info_spice_print,
|
||||
.mhandler.info_new = do_info_spice,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.name = "name",
|
||||
.args_type = "",
|
||||
@ -3037,6 +3166,16 @@ static const mon_cmd_t qmp_query_cmds[] = {
|
||||
.user_print = do_info_vnc_print,
|
||||
.mhandler.info_new = do_info_vnc,
|
||||
},
|
||||
#if defined(CONFIG_SPICE)
|
||||
{
|
||||
.name = "spice",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "show the spice server status",
|
||||
.user_print = do_info_spice_print,
|
||||
.mhandler.info_new = do_info_spice,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.name = "name",
|
||||
.args_type = "",
|
||||
|
@ -32,6 +32,9 @@ typedef enum MonitorEvent {
|
||||
QEVENT_BLOCK_IO_ERROR,
|
||||
QEVENT_RTC_CHANGE,
|
||||
QEVENT_WATCHDOG,
|
||||
QEVENT_SPICE_CONNECTED,
|
||||
QEVENT_SPICE_INITIALIZED,
|
||||
QEVENT_SPICE_DISCONNECTED,
|
||||
QEVENT_MAX,
|
||||
} MonitorEvent;
|
||||
|
||||
|
@ -43,8 +43,8 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required
|
||||
char *dev;
|
||||
struct stat s;
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
/* if no ifname is given, always start the search from tap0. */
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
|
||||
/* if no ifname is given, always start the search from tap0/tun0. */
|
||||
int i;
|
||||
char dname[100];
|
||||
|
||||
@ -52,7 +52,11 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required
|
||||
if (*ifname) {
|
||||
snprintf(dname, sizeof dname, "/dev/%s", ifname);
|
||||
} else {
|
||||
#if defined(__OpenBSD__)
|
||||
snprintf(dname, sizeof dname, "/dev/tun%d", i);
|
||||
#else
|
||||
snprintf(dname, sizeof dname, "/dev/tap%d", i);
|
||||
#endif
|
||||
}
|
||||
TFR(fd = open(dname, O_RDWR));
|
||||
if (fd >= 0) {
|
||||
|
BIN
pc-bios/vgabios-qxl.bin
Normal file
BIN
pc-bios/vgabios-qxl.bin
Normal file
Binary file not shown.
@ -50,6 +50,9 @@ typedef struct DeviceState DeviceState;
|
||||
#if !defined(ENOTSUP)
|
||||
#define ENOTSUP 4096
|
||||
#endif
|
||||
#ifndef TIME_MAX
|
||||
#define TIME_MAX LONG_MAX
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_IOVEC
|
||||
#define CONFIG_IOVEC
|
||||
|
@ -162,6 +162,7 @@ TODO (no longer available)
|
||||
* pcsys_monitor:: QEMU Monitor
|
||||
* disk_images:: Disk Images
|
||||
* pcsys_network:: Network emulation
|
||||
* pcsys_other_devs:: Other Devices
|
||||
* direct_linux_boot:: Direct Linux Boot
|
||||
* pcsys_usb:: USB emulation
|
||||
* vnc_security:: VNC security
|
||||
@ -202,7 +203,7 @@ Intel 82801AA AC97 Audio compatible sound card
|
||||
@item
|
||||
Intel HD Audio Controller and HDA codec
|
||||
@item
|
||||
Adlib(OPL2) - Yamaha YM3812 compatible chip
|
||||
Adlib (OPL2) - Yamaha YM3812 compatible chip
|
||||
@item
|
||||
Gravis Ultrasound GF1 sound card
|
||||
@item
|
||||
@ -222,7 +223,7 @@ VGA BIOS.
|
||||
|
||||
QEMU uses YM3812 emulation by Tatsuyuki Satoh.
|
||||
|
||||
QEMU uses GUS emulation(GUSEMU32 @url{http://www.deinmeister.de/gusemu/})
|
||||
QEMU uses GUS emulation (GUSEMU32 @url{http://www.deinmeister.de/gusemu/})
|
||||
by Tibor "TS" Schütz.
|
||||
|
||||
Not that, by default, GUS shares IRQ(7) with parallel ports and so
|
||||
@ -715,6 +716,7 @@ Using the @option{-net socket} option, it is possible to make VLANs
|
||||
that span several QEMU instances. See @ref{sec_invocation} to have a
|
||||
basic example.
|
||||
|
||||
@node pcsys_other_devs
|
||||
@section Other Devices
|
||||
|
||||
@subsection Inter-VM Shared Memory device
|
||||
@ -832,7 +834,7 @@ Standard USB keyboard. Will override the PS/2 keyboard (if present).
|
||||
Serial converter. This emulates an FTDI FT232BM chip connected to host character
|
||||
device @var{dev}. The available character devices are the same as for the
|
||||
@code{-serial} option. The @code{vendorid} and @code{productid} options can be
|
||||
used to override the default 0403:6001. For instance,
|
||||
used to override the default 0403:6001. For instance,
|
||||
@example
|
||||
usb_add serial:productid=FA00:tcp:192.168.0.2:4444
|
||||
@end example
|
||||
@ -1047,7 +1049,7 @@ qemu [...OPTIONS...] -vnc :1,tls,x509,sasl -monitor stdio
|
||||
|
||||
The GNU TLS packages provides a command called @code{certtool} which can
|
||||
be used to generate certificates and keys in PEM format. At a minimum it
|
||||
is neccessary to setup a certificate authority, and issue certificates to
|
||||
is necessary to setup a certificate authority, and issue certificates to
|
||||
each server. If using certificates for authentication, then each client
|
||||
will also need to be issued a certificate. The recommendation is for the
|
||||
server to keep its certificates in either @code{/etc/pki/qemu} or for
|
||||
@ -1190,7 +1192,7 @@ keytab: /etc/qemu/krb5.tab
|
||||
For this to work the administrator of your KDC must generate a Kerberos
|
||||
principal for the server, with a name of 'qemu/somehost.example.com@@EXAMPLE.COM'
|
||||
replacing 'somehost.example.com' with the fully qualified host name of the
|
||||
machine running QEMU, and 'EXAMPLE.COM' with the Keberos Realm.
|
||||
machine running QEMU, and 'EXAMPLE.COM' with the Kerberos Realm.
|
||||
|
||||
Other configurations will be left as an exercise for the reader. It should
|
||||
be noted that only Digest-MD5 and GSSAPI provides a SSF layer for data
|
||||
@ -1772,7 +1774,7 @@ enabled in the kernel, and expect 512M RAM. Kernels for The PBX-A9 board
|
||||
should have CONFIG_SPARSEMEM enabled, CONFIG_REALVIEW_HIGH_PHYS_OFFSET
|
||||
disabled and expect 1024M RAM.
|
||||
|
||||
The following devices are emuilated:
|
||||
The following devices are emulated:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
@ -1872,7 +1874,7 @@ Secure Digital card connected to OMAP MMC/SD host
|
||||
@item
|
||||
Three OMAP on-chip UARTs and on-chip STI debugging console
|
||||
@item
|
||||
A Bluetooth(R) transciever and HCI connected to an UART
|
||||
A Bluetooth(R) transceiver and HCI connected to an UART
|
||||
@item
|
||||
Mentor Graphics "Inventra" dual-role USB controller embedded in a TI
|
||||
TUSB6010 chip - only USB host mode is supported
|
||||
@ -1934,7 +1936,7 @@ MV88W8618 audio controller, WM8750 CODEC and mixer
|
||||
@end itemize
|
||||
|
||||
The Siemens SX1 models v1 and v2 (default) basic emulation.
|
||||
The emulaton includes the following elements:
|
||||
The emulation includes the following elements:
|
||||
|
||||
@itemize @minus
|
||||
@item
|
||||
@ -2190,7 +2192,7 @@ Set the x86 stack size in bytes (default=524288)
|
||||
Select CPU model (-cpu ? for list and additional feature selection)
|
||||
@item -ignore-environment
|
||||
Start with an empty environment. Without this option,
|
||||
the inital environment is a copy of the caller's environment.
|
||||
the initial environment is a copy of the caller's environment.
|
||||
@item -E @var{var}=@var{value}
|
||||
Set environment @var{var} to @var{value}.
|
||||
@item -U @var{var}
|
||||
@ -2201,7 +2203,7 @@ the address region required by guest applications is reserved on the host.
|
||||
This option is currently only supported on some hosts.
|
||||
@item -R size
|
||||
Pre-allocate a guest virtual address space of the given size (in bytes).
|
||||
"G", "M", and "k" suffixes may be used when specifying the size.
|
||||
"G", "M", and "k" suffixes may be used when specifying the size.
|
||||
@end table
|
||||
|
||||
Debug options:
|
||||
@ -2420,7 +2422,7 @@ Set the library root path (default=/)
|
||||
Set the stack size in bytes (default=524288)
|
||||
@item -ignore-environment
|
||||
Start with an empty environment. Without this option,
|
||||
the inital environment is a copy of the caller's environment.
|
||||
the initial environment is a copy of the caller's environment.
|
||||
@item -E @var{var}=@var{value}
|
||||
Set environment @var{var} to @var{value}.
|
||||
@item -U @var{var}
|
||||
@ -2493,7 +2495,7 @@ correct SDL directory when invoked.
|
||||
|
||||
@item Install the MinGW version of zlib and make sure
|
||||
@file{zlib.h} and @file{libz.dll.a} are in
|
||||
MingGW's default header and linker search paths.
|
||||
MinGW's default header and linker search paths.
|
||||
|
||||
@item Extract the current version of QEMU.
|
||||
|
||||
@ -2528,7 +2530,7 @@ the QEMU configuration script.
|
||||
|
||||
@item Install the MinGW version of zlib and make sure
|
||||
@file{zlib.h} and @file{libz.dll.a} are in
|
||||
MingGW's default header and linker search paths.
|
||||
MinGW's default header and linker search paths.
|
||||
|
||||
@item
|
||||
Configure QEMU for Windows cross compilation:
|
||||
@ -2537,7 +2539,7 @@ PATH=/usr/i686-pc-mingw32/sys-root/mingw/bin:$PATH ./configure --cross-prefix='i
|
||||
@end example
|
||||
The example assumes @file{sdl-config} is installed under @file{/usr/i686-pc-mingw32/sys-root/mingw/bin} and
|
||||
MinGW cross compilation tools have names like @file{i686-pc-mingw32-gcc} and @file{i686-pc-mingw32-strip}.
|
||||
We set the @code{PATH} environment variable to ensure the MingW version of @file{sdl-config} is used and
|
||||
We set the @code{PATH} environment variable to ensure the MinGW version of @file{sdl-config} is used and
|
||||
use --cross-prefix to specify the name of the cross compiler.
|
||||
You can also use --prefix to set the Win32 install path which defaults to @file{c:/Program Files/Qemu}.
|
||||
|
||||
|
@ -751,7 +751,7 @@ Rotate graphical output 90 deg left (only PXA LCD).
|
||||
ETEXI
|
||||
|
||||
DEF("vga", HAS_ARG, QEMU_OPTION_vga,
|
||||
"-vga [std|cirrus|vmware|xenfb|none]\n"
|
||||
"-vga [std|cirrus|vmware|qxl|xenfb|none]\n"
|
||||
" select video card type\n", QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@item -vga @var{type}
|
||||
@ -772,6 +772,10 @@ this option.
|
||||
VMWare SVGA-II compatible adapter. Use it if you have sufficiently
|
||||
recent XFree86/XOrg server or Windows guest with a driver for this
|
||||
card.
|
||||
@item qxl
|
||||
QXL paravirtual graphic card. It is VGA compatible (including VESA
|
||||
2.0 VBE support). Works best with qxl guest drivers installed though.
|
||||
Recommended choice when using the spice protocol.
|
||||
@item none
|
||||
Disable VGA card.
|
||||
@end table
|
||||
|
@ -516,7 +516,7 @@ timers, especially together with the use of bottom halves (BHs).
|
||||
@section Hardware interrupts
|
||||
|
||||
In order to be faster, QEMU does not check at every basic block if an
|
||||
hardware interrupt is pending. Instead, the user must asynchrously
|
||||
hardware interrupt is pending. Instead, the user must asynchronously
|
||||
call a specific function to tell that an interrupt is pending. This
|
||||
function resets the chaining of the currently executing basic
|
||||
block. It ensures that the execution will return soon in the main loop
|
||||
@ -548,7 +548,7 @@ Linux kernel does. The @code{sigreturn()} system call is emulated to return
|
||||
from the virtual signal handler.
|
||||
|
||||
Some signals (such as SIGALRM) directly come from the host. Other
|
||||
signals are synthetized from the virtual CPU exceptions such as SIGFPE
|
||||
signals are synthesized from the virtual CPU exceptions such as SIGFPE
|
||||
when a division by zero is done (see @code{main.c:cpu_loop()}).
|
||||
|
||||
The blocked signal mask is still handled by the host Linux kernel so
|
||||
|
@ -50,7 +50,8 @@ static void __attribute__((constructor)) init_get_clock(void)
|
||||
{
|
||||
use_rt_clock = 0;
|
||||
#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
|
||||
|| defined(__DragonFly__) || defined(__FreeBSD_kernel__)
|
||||
|| defined(__DragonFly__) || defined(__FreeBSD_kernel__) \
|
||||
|| defined(__OpenBSD__)
|
||||
{
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
|
||||
|
129
qmp-commands.hx
129
qmp-commands.hx
@ -510,7 +510,7 @@ Set maximum speed for migrations.
|
||||
|
||||
Arguments:
|
||||
|
||||
- "value": maximum speed, in bytes per second (json-number)
|
||||
- "value": maximum speed, in bytes per second (json-int)
|
||||
|
||||
Example:
|
||||
|
||||
@ -735,6 +735,63 @@ Example:
|
||||
"password": "12345" } }
|
||||
<- { "return": {} }
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "set_password",
|
||||
.args_type = "protocol:s,password:s,connected:s?",
|
||||
.params = "protocol password action-if-connected",
|
||||
.help = "set spice/vnc password",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = set_password,
|
||||
},
|
||||
|
||||
SQMP
|
||||
set_password
|
||||
------------
|
||||
|
||||
Set the password for vnc/spice protocols.
|
||||
|
||||
Arguments:
|
||||
|
||||
- "protocol": protocol name (json-string)
|
||||
- "password": password (json-string)
|
||||
- "connected": [ keep | disconnect | fail ] (josn-string, optional)
|
||||
|
||||
Example:
|
||||
|
||||
-> { "execute": "set_password", "arguments": { "protocol": "vnc",
|
||||
"password": "secret" } }
|
||||
<- { "return": {} }
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "expire_password",
|
||||
.args_type = "protocol:s,time:s",
|
||||
.params = "protocol time",
|
||||
.help = "set spice/vnc password expire-time",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = expire_password,
|
||||
},
|
||||
|
||||
SQMP
|
||||
expire_password
|
||||
---------------
|
||||
|
||||
Set the password expire time for vnc/spice protocols.
|
||||
|
||||
Arguments:
|
||||
|
||||
- "protocol": protocol name (json-string)
|
||||
- "time": [ now | never | +secs | secs ] (json-string)
|
||||
|
||||
Example:
|
||||
|
||||
-> { "execute": "expire_password", "arguments": { "protocol": "vnc",
|
||||
"time": "+60" } }
|
||||
<- { "return": {} }
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
@ -1438,6 +1495,76 @@ Example:
|
||||
|
||||
EQMP
|
||||
|
||||
SQMP
|
||||
query-spice
|
||||
-----------
|
||||
|
||||
Show SPICE server information.
|
||||
|
||||
Return a json-object with server information. Connected clients are returned
|
||||
as a json-array of json-objects.
|
||||
|
||||
The main json-object contains the following:
|
||||
|
||||
- "enabled": true or false (json-bool)
|
||||
- "host": server's IP address (json-string)
|
||||
- "port": server's port number (json-int, optional)
|
||||
- "tls-port": server's port number (json-int, optional)
|
||||
- "auth": authentication method (json-string)
|
||||
- Possible values: "none", "spice"
|
||||
- "channels": a json-array of all active channels clients
|
||||
|
||||
Channels are described by a json-object, each one contain the following:
|
||||
|
||||
- "host": client's IP address (json-string)
|
||||
- "family": address family (json-string)
|
||||
- Possible values: "ipv4", "ipv6", "unix", "unknown"
|
||||
- "port": client's port number (json-string)
|
||||
- "connection-id": spice connection id. All channels with the same id
|
||||
belong to the same spice session (json-int)
|
||||
- "channel-type": channel type. "1" is the main control channel, filter for
|
||||
this one if you want track spice sessions only (json-int)
|
||||
- "channel-id": channel id. Usually "0", might be different needed when
|
||||
multiple channels of the same type exist, such as multiple
|
||||
display channels in a multihead setup (json-int)
|
||||
- "tls": whevener the channel is encrypted (json-bool)
|
||||
|
||||
Example:
|
||||
|
||||
-> { "execute": "query-spice" }
|
||||
<- {
|
||||
"return": {
|
||||
"enabled": true,
|
||||
"auth": "spice",
|
||||
"port": 5920,
|
||||
"tls-port": 5921,
|
||||
"host": "0.0.0.0",
|
||||
"channels": [
|
||||
{
|
||||
"port": "54924",
|
||||
"family": "ipv4",
|
||||
"channel-type": 1,
|
||||
"connection-id": 1804289383,
|
||||
"host": "127.0.0.1",
|
||||
"channel-id": 0,
|
||||
"tls": true
|
||||
},
|
||||
{
|
||||
"port": "36710",
|
||||
"family": "ipv4",
|
||||
"channel-type": 4,
|
||||
"connection-id": 1804289383,
|
||||
"host": "127.0.0.1",
|
||||
"channel-id": 0,
|
||||
"tls": false
|
||||
},
|
||||
[ ... more channels follow ... ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
EQMP
|
||||
|
||||
SQMP
|
||||
query-name
|
||||
----------
|
||||
|
@ -92,13 +92,13 @@ static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
|
||||
}
|
||||
|
||||
static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
|
||||
const struct in_addr **preq_addr)
|
||||
struct in_addr *preq_addr)
|
||||
{
|
||||
const uint8_t *p, *p_end;
|
||||
int len, tag;
|
||||
|
||||
*pmsg_type = 0;
|
||||
*preq_addr = NULL;
|
||||
preq_addr->s_addr = htonl(0L);
|
||||
|
||||
p = bp->bp_vend;
|
||||
p_end = p + DHCP_OPT_LEN;
|
||||
@ -124,8 +124,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
|
||||
*pmsg_type = p[0];
|
||||
break;
|
||||
case RFC2132_REQ_ADDR:
|
||||
if (len >= 4)
|
||||
*preq_addr = (struct in_addr *)p;
|
||||
if (len >= 4) {
|
||||
memcpy(&(preq_addr->s_addr), p, 4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -133,8 +134,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
|
||||
p += len;
|
||||
}
|
||||
}
|
||||
if (*pmsg_type == DHCPREQUEST && !*preq_addr && bp->bp_ciaddr.s_addr) {
|
||||
*preq_addr = &bp->bp_ciaddr;
|
||||
if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) &&
|
||||
bp->bp_ciaddr.s_addr) {
|
||||
memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4);
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,15 +146,15 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
|
||||
struct mbuf *m;
|
||||
struct bootp_t *rbp;
|
||||
struct sockaddr_in saddr, daddr;
|
||||
const struct in_addr *preq_addr;
|
||||
struct in_addr preq_addr;
|
||||
int dhcp_msg_type, val;
|
||||
uint8_t *q;
|
||||
|
||||
/* extract exact DHCP msg type */
|
||||
dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
|
||||
DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
|
||||
if (preq_addr)
|
||||
DPRINTF(" req_addr=%08x\n", ntohl(preq_addr->s_addr));
|
||||
if (preq_addr.s_addr != htonl(0L))
|
||||
DPRINTF(" req_addr=%08x\n", ntohl(preq_addr.s_addr));
|
||||
else
|
||||
DPRINTF("\n");
|
||||
|
||||
@ -175,10 +177,10 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
|
||||
memset(rbp, 0, sizeof(struct bootp_t));
|
||||
|
||||
if (dhcp_msg_type == DHCPDISCOVER) {
|
||||
if (preq_addr) {
|
||||
bc = request_addr(slirp, preq_addr, slirp->client_ethaddr);
|
||||
if (preq_addr.s_addr != htonl(0L)) {
|
||||
bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr);
|
||||
if (bc) {
|
||||
daddr.sin_addr = *preq_addr;
|
||||
daddr.sin_addr = preq_addr;
|
||||
}
|
||||
}
|
||||
if (!bc) {
|
||||
@ -190,10 +192,10 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
|
||||
}
|
||||
}
|
||||
memcpy(bc->macaddr, slirp->client_ethaddr, 6);
|
||||
} else if (preq_addr) {
|
||||
bc = request_addr(slirp, preq_addr, slirp->client_ethaddr);
|
||||
} else if (preq_addr.s_addr != htonl(0L)) {
|
||||
bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr);
|
||||
if (bc) {
|
||||
daddr.sin_addr = *preq_addr;
|
||||
daddr.sin_addr = preq_addr;
|
||||
memcpy(bc->macaddr, slirp->client_ethaddr, 6);
|
||||
} else {
|
||||
daddr.sin_addr.s_addr = 0;
|
||||
|
3
sysemu.h
3
sysemu.h
@ -104,7 +104,7 @@ extern int incoming_expected;
|
||||
extern int bios_size;
|
||||
|
||||
typedef enum {
|
||||
VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB
|
||||
VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
|
||||
} VGAInterfaceType;
|
||||
|
||||
extern int vga_interface_type;
|
||||
@ -112,6 +112,7 @@ extern int vga_interface_type;
|
||||
#define std_vga_enabled (vga_interface_type == VGA_STD)
|
||||
#define xenfb_enabled (vga_interface_type == VGA_XENFB)
|
||||
#define vmsvga_enabled (vga_interface_type == VGA_VMWARE)
|
||||
#define qxl_enabled (vga_interface_type == VGA_QXL)
|
||||
|
||||
extern int graphic_width;
|
||||
extern int graphic_height;
|
||||
|
@ -904,7 +904,7 @@ uint64_t helper_cmptun (uint64_t a, uint64_t b)
|
||||
fa = t_to_float64(a);
|
||||
fb = t_to_float64(b);
|
||||
|
||||
if (float64_is_nan(fa) || float64_is_nan(fb))
|
||||
if (float64_is_quiet_nan(fa) || float64_is_quiet_nan(fb))
|
||||
return 0x4000000000000000ULL;
|
||||
else
|
||||
return 0;
|
||||
|
@ -76,6 +76,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
|
||||
memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
|
||||
memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
|
||||
env->cp15.c0_cachetype = 0x1dd20d2;
|
||||
env->cp15.c1_sys = 0x00050078;
|
||||
break;
|
||||
case ARM_CPUID_ARM11MPCORE:
|
||||
set_feature(env, ARM_FEATURE_V6);
|
||||
@ -109,6 +110,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
|
||||
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. */
|
||||
env->cp15.c1_sys = 0x00c50078;
|
||||
break;
|
||||
case ARM_CPUID_CORTEXA9:
|
||||
set_feature(env, ARM_FEATURE_V6);
|
||||
@ -130,6 +132,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
|
||||
env->cp15.c0_clid = (1 << 27) | (1 << 24) | 3;
|
||||
env->cp15.c0_ccsid[0] = 0xe00fe015; /* 16k L1 dcache. */
|
||||
env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
|
||||
env->cp15.c1_sys = 0x00c50078;
|
||||
break;
|
||||
case ARM_CPUID_CORTEXM3:
|
||||
set_feature(env, ARM_FEATURE_V6);
|
||||
@ -1084,22 +1087,26 @@ static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type,
|
||||
}
|
||||
code = 15;
|
||||
}
|
||||
if (xn && access_type == 2)
|
||||
goto do_fault;
|
||||
if (domain == 3) {
|
||||
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
} else {
|
||||
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. */
|
||||
goto do_fault;
|
||||
}
|
||||
if (!xn) {
|
||||
*prot |= PAGE_EXEC;
|
||||
/* 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. */
|
||||
goto do_fault;
|
||||
}
|
||||
if (!xn) {
|
||||
*prot |= PAGE_EXEC;
|
||||
}
|
||||
}
|
||||
*phys_ptr = phys_addr;
|
||||
return 0;
|
||||
@ -2235,6 +2242,8 @@ static inline int vfp_exceptbits_from_host(int host_bits)
|
||||
target_bits |= 8;
|
||||
if (host_bits & float_flag_inexact)
|
||||
target_bits |= 0x10;
|
||||
if (host_bits & float_flag_input_denormal)
|
||||
target_bits |= 0x80;
|
||||
return target_bits;
|
||||
}
|
||||
|
||||
@ -2271,6 +2280,8 @@ static inline int vfp_exceptbits_to_host(int target_bits)
|
||||
host_bits |= float_flag_underflow;
|
||||
if (target_bits & 0x10)
|
||||
host_bits |= float_flag_inexact;
|
||||
if (target_bits & 0x80)
|
||||
host_bits |= float_flag_input_denormal;
|
||||
return host_bits;
|
||||
}
|
||||
|
||||
@ -2303,12 +2314,14 @@ void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val)
|
||||
}
|
||||
set_float_rounding_mode(i, &env->vfp.fp_status);
|
||||
}
|
||||
if (changed & (1 << 24))
|
||||
if (changed & (1 << 24)) {
|
||||
set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status);
|
||||
set_flush_inputs_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);
|
||||
i = vfp_exceptbits_to_host(val);
|
||||
set_float_exception_flags(i, &env->vfp.fp_status);
|
||||
}
|
||||
|
||||
|
@ -560,8 +560,6 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
|
||||
if (val) {
|
||||
val = ~(uint64_t)0;
|
||||
SET_QC();
|
||||
} else {
|
||||
val = 0;
|
||||
}
|
||||
} else if (shift <= -64) {
|
||||
val = 0;
|
||||
@ -582,9 +580,15 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
|
||||
int8_t tmp; \
|
||||
tmp = (int8_t)src2; \
|
||||
if (tmp >= (ssize_t)sizeof(src1) * 8) { \
|
||||
if (src1) \
|
||||
if (src1) { \
|
||||
SET_QC(); \
|
||||
dest = src1 >> 31; \
|
||||
dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)); \
|
||||
if (src1 > 0) { \
|
||||
dest--; \
|
||||
} \
|
||||
} else { \
|
||||
dest = src1; \
|
||||
} \
|
||||
} else if (tmp <= -(ssize_t)sizeof(src1) * 8) { \
|
||||
dest = src1 >> 31; \
|
||||
} else if (tmp < 0) { \
|
||||
@ -593,7 +597,10 @@ uint64_t HELPER(neon_qshl_u64)(CPUState *env, uint64_t val, uint64_t shiftop)
|
||||
dest = src1 << tmp; \
|
||||
if ((dest >> tmp) != src1) { \
|
||||
SET_QC(); \
|
||||
dest = src2 >> 31; \
|
||||
dest = (uint32_t)(1 << (sizeof(src1) * 8 - 1)); \
|
||||
if (src1 > 0) { \
|
||||
dest--; \
|
||||
} \
|
||||
} \
|
||||
}} while (0)
|
||||
NEON_VOP_ENV(qshl_s8, neon_s8, 4)
|
||||
@ -608,9 +615,9 @@ uint64_t HELPER(neon_qshl_s64)(CPUState *env, uint64_t valop, uint64_t shiftop)
|
||||
if (shift >= 64) {
|
||||
if (val) {
|
||||
SET_QC();
|
||||
val = (val >> 63) & ~SIGNBIT64;
|
||||
val = (val >> 63) ^ ~SIGNBIT64;
|
||||
}
|
||||
} else if (shift <= 64) {
|
||||
} else if (shift <= -64) {
|
||||
val >>= 63;
|
||||
} else if (shift < 0) {
|
||||
val >>= -shift;
|
||||
|
@ -250,13 +250,9 @@ static void gen_rev16(TCGv var)
|
||||
/* Byteswap low halfword and sign extend. */
|
||||
static void gen_revsh(TCGv var)
|
||||
{
|
||||
TCGv tmp = new_tmp();
|
||||
tcg_gen_shri_i32(tmp, var, 8);
|
||||
tcg_gen_andi_i32(tmp, tmp, 0x00ff);
|
||||
tcg_gen_shli_i32(var, var, 8);
|
||||
tcg_gen_ext8s_i32(var, var);
|
||||
tcg_gen_or_i32(var, var, tmp);
|
||||
dead_tmp(tmp);
|
||||
tcg_gen_ext16u_i32(var, var);
|
||||
tcg_gen_bswap16_i32(var, var);
|
||||
tcg_gen_ext16s_i32(var, var);
|
||||
}
|
||||
|
||||
/* Unsigned bitfield extract. */
|
||||
@ -291,11 +287,32 @@ static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask)
|
||||
tcg_gen_or_i32(dest, base, val);
|
||||
}
|
||||
|
||||
/* Round the top 32 bits of a 64-bit value. */
|
||||
static void gen_roundqd(TCGv a, TCGv b)
|
||||
/* Return (b << 32) + a. Mark inputs as dead */
|
||||
static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv b)
|
||||
{
|
||||
tcg_gen_shri_i32(a, a, 31);
|
||||
tcg_gen_add_i32(a, a, b);
|
||||
TCGv_i64 tmp64 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_extu_i32_i64(tmp64, b);
|
||||
dead_tmp(b);
|
||||
tcg_gen_shli_i64(tmp64, tmp64, 32);
|
||||
tcg_gen_add_i64(a, tmp64, a);
|
||||
|
||||
tcg_temp_free_i64(tmp64);
|
||||
return a;
|
||||
}
|
||||
|
||||
/* Return (b << 32) - a. Mark inputs as dead. */
|
||||
static TCGv_i64 gen_subq_msw(TCGv_i64 a, TCGv b)
|
||||
{
|
||||
TCGv_i64 tmp64 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_extu_i32_i64(tmp64, b);
|
||||
dead_tmp(b);
|
||||
tcg_gen_shli_i64(tmp64, tmp64, 32);
|
||||
tcg_gen_sub_i64(a, tmp64, a);
|
||||
|
||||
tcg_temp_free_i64(tmp64);
|
||||
return a;
|
||||
}
|
||||
|
||||
/* FIXME: Most targets have native widening multiplication.
|
||||
@ -329,22 +346,6 @@ static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
|
||||
return tmp1;
|
||||
}
|
||||
|
||||
/* Signed 32x32->64 multiply. */
|
||||
static void gen_imull(TCGv a, TCGv b)
|
||||
{
|
||||
TCGv_i64 tmp1 = tcg_temp_new_i64();
|
||||
TCGv_i64 tmp2 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_ext_i32_i64(tmp1, a);
|
||||
tcg_gen_ext_i32_i64(tmp2, b);
|
||||
tcg_gen_mul_i64(tmp1, tmp1, tmp2);
|
||||
tcg_temp_free_i64(tmp2);
|
||||
tcg_gen_trunc_i64_i32(a, tmp1);
|
||||
tcg_gen_shri_i64(tmp1, tmp1, 32);
|
||||
tcg_gen_trunc_i64_i32(b, tmp1);
|
||||
tcg_temp_free_i64(tmp1);
|
||||
}
|
||||
|
||||
/* Swap low and high halfwords. */
|
||||
static void gen_swap_half(TCGv var)
|
||||
{
|
||||
@ -4240,9 +4241,9 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
|
||||
case 9: /* VQSHL */
|
||||
if (u) {
|
||||
gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
|
||||
cpu_V0, cpu_V0);
|
||||
cpu_V1, cpu_V0);
|
||||
} else {
|
||||
gen_helper_neon_qshl_s64(cpu_V1, cpu_env,
|
||||
gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
|
||||
cpu_V1, cpu_V0);
|
||||
}
|
||||
break;
|
||||
@ -6641,26 +6642,38 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||
gen_logic_CC(tmp);
|
||||
store_reg(s, rd, tmp);
|
||||
break;
|
||||
default:
|
||||
/* 64 bit mul */
|
||||
case 4:
|
||||
/* 64 bit mul double accumulate (UMAAL) */
|
||||
ARCH(6);
|
||||
tmp = load_reg(s, rs);
|
||||
tmp2 = load_reg(s, rm);
|
||||
if (insn & (1 << 22))
|
||||
tmp64 = gen_muls_i64_i32(tmp, tmp2);
|
||||
else
|
||||
tmp64 = gen_mulu_i64_i32(tmp, tmp2);
|
||||
if (insn & (1 << 21)) /* mult accumulate */
|
||||
gen_addq(s, tmp64, rn, rd);
|
||||
if (!(insn & (1 << 23))) { /* double accumulate */
|
||||
ARCH(6);
|
||||
gen_addq_lo(s, tmp64, rn);
|
||||
gen_addq_lo(s, tmp64, rd);
|
||||
}
|
||||
if (insn & (1 << 20))
|
||||
gen_logicq_cc(tmp64);
|
||||
tmp64 = gen_mulu_i64_i32(tmp, tmp2);
|
||||
gen_addq_lo(s, tmp64, rn);
|
||||
gen_addq_lo(s, tmp64, rd);
|
||||
gen_storeq_reg(s, rn, rd, tmp64);
|
||||
tcg_temp_free_i64(tmp64);
|
||||
break;
|
||||
case 8: case 9: case 10: case 11:
|
||||
case 12: case 13: case 14: case 15:
|
||||
/* 64 bit mul: UMULL, UMLAL, SMULL, SMLAL. */
|
||||
tmp = load_reg(s, rs);
|
||||
tmp2 = load_reg(s, rm);
|
||||
if (insn & (1 << 22)) {
|
||||
tmp64 = gen_muls_i64_i32(tmp, tmp2);
|
||||
} else {
|
||||
tmp64 = gen_mulu_i64_i32(tmp, tmp2);
|
||||
}
|
||||
if (insn & (1 << 21)) { /* mult accumulate */
|
||||
gen_addq(s, tmp64, rn, rd);
|
||||
}
|
||||
if (insn & (1 << 20)) {
|
||||
gen_logicq_cc(tmp64);
|
||||
}
|
||||
gen_storeq_reg(s, rn, rd, tmp64);
|
||||
tcg_temp_free_i64(tmp64);
|
||||
break;
|
||||
default:
|
||||
goto illegal_op;
|
||||
}
|
||||
} else {
|
||||
rn = (insn >> 16) & 0xf;
|
||||
@ -6945,23 +6958,25 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
|
||||
tmp = load_reg(s, rm);
|
||||
tmp2 = load_reg(s, rs);
|
||||
if (insn & (1 << 20)) {
|
||||
/* Signed multiply most significant [accumulate]. */
|
||||
/* Signed multiply most significant [accumulate].
|
||||
(SMMUL, SMMLA, SMMLS) */
|
||||
tmp64 = gen_muls_i64_i32(tmp, tmp2);
|
||||
if (insn & (1 << 5))
|
||||
|
||||
if (rd != 15) {
|
||||
tmp = load_reg(s, rd);
|
||||
if (insn & (1 << 6)) {
|
||||
tmp64 = gen_subq_msw(tmp64, tmp);
|
||||
} else {
|
||||
tmp64 = gen_addq_msw(tmp64, tmp);
|
||||
}
|
||||
}
|
||||
if (insn & (1 << 5)) {
|
||||
tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
|
||||
}
|
||||
tcg_gen_shri_i64(tmp64, tmp64, 32);
|
||||
tmp = new_tmp();
|
||||
tcg_gen_trunc_i64_i32(tmp, tmp64);
|
||||
tcg_temp_free_i64(tmp64);
|
||||
if (rd != 15) {
|
||||
tmp2 = load_reg(s, rd);
|
||||
if (insn & (1 << 6)) {
|
||||
tcg_gen_sub_i32(tmp, tmp, tmp2);
|
||||
} else {
|
||||
tcg_gen_add_i32(tmp, tmp, tmp2);
|
||||
}
|
||||
dead_tmp(tmp2);
|
||||
}
|
||||
store_reg(s, rn, tmp);
|
||||
} else {
|
||||
if (insn & (1 << 5))
|
||||
@ -7832,24 +7847,23 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
|
||||
dead_tmp(tmp2);
|
||||
}
|
||||
break;
|
||||
case 5: case 6: /* 32 * 32 -> 32msb */
|
||||
gen_imull(tmp, tmp2);
|
||||
if (insn & (1 << 5)) {
|
||||
gen_roundqd(tmp, tmp2);
|
||||
dead_tmp(tmp2);
|
||||
} else {
|
||||
dead_tmp(tmp);
|
||||
tmp = tmp2;
|
||||
}
|
||||
case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
|
||||
tmp64 = gen_muls_i64_i32(tmp, tmp2);
|
||||
if (rs != 15) {
|
||||
tmp2 = load_reg(s, rs);
|
||||
if (insn & (1 << 21)) {
|
||||
tcg_gen_add_i32(tmp, tmp, tmp2);
|
||||
tmp = load_reg(s, rs);
|
||||
if (insn & (1 << 20)) {
|
||||
tmp64 = gen_addq_msw(tmp64, tmp);
|
||||
} else {
|
||||
tcg_gen_sub_i32(tmp, tmp2, tmp);
|
||||
tmp64 = gen_subq_msw(tmp64, tmp);
|
||||
}
|
||||
dead_tmp(tmp2);
|
||||
}
|
||||
if (insn & (1 << 4)) {
|
||||
tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
|
||||
}
|
||||
tcg_gen_shri_i64(tmp64, tmp64, 32);
|
||||
tmp = new_tmp();
|
||||
tcg_gen_trunc_i64_i32(tmp, tmp64);
|
||||
tcg_temp_free_i64(tmp64);
|
||||
break;
|
||||
case 7: /* Unsigned sum of absolute differences. */
|
||||
gen_helper_usad8(tmp, tmp, tmp2);
|
||||
|
@ -577,20 +577,15 @@ static inline void t_gen_swapr(TCGv d, TCGv s)
|
||||
|
||||
static void t_gen_cc_jmp(TCGv pc_true, TCGv pc_false)
|
||||
{
|
||||
TCGv btaken;
|
||||
int l1;
|
||||
|
||||
l1 = gen_new_label();
|
||||
btaken = tcg_temp_new();
|
||||
|
||||
/* Conditional jmp. */
|
||||
tcg_gen_mov_tl(btaken, env_btaken);
|
||||
tcg_gen_mov_tl(env_pc, pc_false);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, btaken, 0, l1);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1);
|
||||
tcg_gen_mov_tl(env_pc, pc_true);
|
||||
gen_set_label(l1);
|
||||
|
||||
tcg_temp_free(btaken);
|
||||
}
|
||||
|
||||
static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
|
||||
@ -1134,7 +1129,7 @@ static void cris_store_direct_jmp(DisasContext *dc)
|
||||
/* Store the direct jmp state into the cpu-state. */
|
||||
if (dc->jmp == JMP_DIRECT) {
|
||||
tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
|
||||
tcg_gen_movi_tl(env_btaken, 1);
|
||||
dc->jmp = JMP_INDIRECT;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1144,17 +1139,11 @@ static void cris_prepare_cc_branch (DisasContext *dc,
|
||||
/* This helps us re-schedule the micro-code to insns in delay-slots
|
||||
before the actual jump. */
|
||||
dc->delayed_branch = 2;
|
||||
dc->jmp = JMP_DIRECT;
|
||||
dc->jmp_pc = dc->pc + offset;
|
||||
|
||||
if (cond != CC_A)
|
||||
{
|
||||
dc->jmp = JMP_INDIRECT;
|
||||
gen_tst_cc (dc, env_btaken, cond);
|
||||
tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
|
||||
} else {
|
||||
/* Allow chaining. */
|
||||
dc->jmp = JMP_DIRECT;
|
||||
}
|
||||
gen_tst_cc (dc, env_btaken, cond);
|
||||
tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
|
||||
}
|
||||
|
||||
|
||||
@ -1166,8 +1155,7 @@ static inline void cris_prepare_jmp (DisasContext *dc, unsigned int type)
|
||||
before the actual jump. */
|
||||
dc->delayed_branch = 2;
|
||||
dc->jmp = type;
|
||||
if (type == JMP_INDIRECT)
|
||||
tcg_gen_movi_tl(env_btaken, 1);
|
||||
tcg_gen_movi_tl(env_btaken, 1);
|
||||
}
|
||||
|
||||
static void gen_load64(DisasContext *dc, TCGv_i64 dst, TCGv addr)
|
||||
@ -3320,8 +3308,24 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
if (tb->flags & 7)
|
||||
t_gen_mov_env_TN(dslot,
|
||||
tcg_const_tl(0));
|
||||
if (dc->cpustate_changed || !dc->flagx_known
|
||||
|| (dc->flags_x != (tb->flags & X_FLAG))) {
|
||||
cris_store_direct_jmp(dc);
|
||||
}
|
||||
if (dc->jmp == JMP_DIRECT) {
|
||||
dc->is_jmp = DISAS_NEXT;
|
||||
int l1;
|
||||
|
||||
l1 = gen_new_label();
|
||||
cris_evaluate_flags(dc);
|
||||
|
||||
/* Conditional jmp. */
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ,
|
||||
env_btaken, 0, l1);
|
||||
gen_goto_tb(dc, 1, dc->jmp_pc);
|
||||
gen_set_label(l1);
|
||||
gen_goto_tb(dc, 0, dc->pc);
|
||||
dc->is_jmp = DISAS_TB_JUMP;
|
||||
dc->jmp = JMP_NOJMP;
|
||||
} else {
|
||||
t_gen_cc_jmp(env_btarget,
|
||||
tcg_const_tl(dc->pc));
|
||||
@ -3341,16 +3345,10 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
&& (dc->pc < next_page_start)
|
||||
&& num_insns < max_insns);
|
||||
|
||||
if (dc->tb_flags != orig_flags) {
|
||||
dc->cpustate_changed = 1;
|
||||
}
|
||||
|
||||
if (dc->clear_locked_irq)
|
||||
t_gen_mov_env_TN(locked_irq, tcg_const_tl(0));
|
||||
|
||||
npc = dc->pc;
|
||||
if (dc->jmp == JMP_DIRECT && !dc->delayed_branch)
|
||||
npc = dc->jmp_pc;
|
||||
|
||||
if (tb->cflags & CF_LAST_IO)
|
||||
gen_io_end();
|
||||
|
@ -737,10 +737,10 @@ typedef struct CPUX86State {
|
||||
user */
|
||||
struct DeviceState *apic_state;
|
||||
|
||||
uint64 mcg_cap;
|
||||
uint64 mcg_status;
|
||||
uint64 mcg_ctl;
|
||||
uint64 mce_banks[MCE_BANKS_DEF*4];
|
||||
uint64_t mcg_cap;
|
||||
uint64_t mcg_status;
|
||||
uint64_t mcg_ctl;
|
||||
uint64_t mce_banks[MCE_BANKS_DEF*4];
|
||||
|
||||
uint64_t tsc_aux;
|
||||
|
||||
|
@ -175,12 +175,12 @@ cpu_x86_dump_seg_cache(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
|
||||
#ifdef TARGET_X86_64
|
||||
if (env->hflags & HF_CS64_MASK) {
|
||||
cpu_fprintf(f, "%-3s=%04x %016" PRIx64 " %08x %08x", name,
|
||||
sc->selector, sc->base, sc->limit, sc->flags);
|
||||
sc->selector, sc->base, sc->limit, sc->flags & 0x00ffff00);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
cpu_fprintf(f, "%-3s=%04x %08x %08x %08x", name, sc->selector,
|
||||
(uint32_t)sc->base, sc->limit, sc->flags);
|
||||
(uint32_t)sc->base, sc->limit, sc->flags & 0x00ffff00);
|
||||
}
|
||||
|
||||
if (!(env->hflags & HF_PE_MASK) || !(sc->flags & DESC_P_MASK))
|
||||
|
@ -614,10 +614,10 @@ float64 HELPER(sub_cmp_f64)(CPUState *env, float64 a, float64 b)
|
||||
/* ??? Should flush denormals to zero. */
|
||||
float64 res;
|
||||
res = float64_sub(a, b, &env->fp_status);
|
||||
if (float64_is_nan(res)) {
|
||||
if (float64_is_quiet_nan(res)) {
|
||||
/* +/-inf compares equal against itself, but sub returns nan. */
|
||||
if (!float64_is_nan(a)
|
||||
&& !float64_is_nan(b)) {
|
||||
if (!float64_is_quiet_nan(a)
|
||||
&& !float64_is_quiet_nan(b)) {
|
||||
res = float64_zero;
|
||||
if (float64_lt_quiet(a, res, &env->fp_status))
|
||||
res = float64_chs(res);
|
||||
|
@ -308,7 +308,7 @@ uint32_t helper_fcmp_un(uint32_t a, uint32_t b)
|
||||
r = 1;
|
||||
}
|
||||
|
||||
if (float32_is_nan(fa.f) || float32_is_nan(fb.f)) {
|
||||
if (float32_is_quiet_nan(fa.f) || float32_is_quiet_nan(fb.f)) {
|
||||
r = 1;
|
||||
}
|
||||
|
||||
|
@ -752,9 +752,8 @@ static void dec_bit(DisasContext *dc)
|
||||
static inline void sync_jmpstate(DisasContext *dc)
|
||||
{
|
||||
if (dc->jmp == JMP_DIRECT) {
|
||||
dc->jmp = JMP_INDIRECT;
|
||||
tcg_gen_movi_tl(env_btaken, 1);
|
||||
tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
|
||||
dc->jmp = JMP_INDIRECT;
|
||||
tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -976,11 +975,13 @@ static void dec_bcc(DisasContext *dc)
|
||||
int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend. */
|
||||
|
||||
tcg_gen_movi_tl(env_btarget, dc->pc + offset);
|
||||
dc->jmp = JMP_DIRECT;
|
||||
dc->jmp_pc = dc->pc + offset;
|
||||
} else {
|
||||
dc->jmp = JMP_INDIRECT;
|
||||
tcg_gen_movi_tl(env_btarget, dc->pc);
|
||||
tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc)));
|
||||
}
|
||||
dc->jmp = JMP_INDIRECT;
|
||||
eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0));
|
||||
}
|
||||
|
||||
@ -1028,6 +1029,7 @@ static void dec_br(DisasContext *dc)
|
||||
if (dec_alu_op_b_is_small_imm(dc)) {
|
||||
dc->jmp = JMP_DIRECT;
|
||||
dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm);
|
||||
tcg_gen_movi_tl(env_btaken, 1);
|
||||
} else {
|
||||
tcg_gen_movi_tl(env_btaken, 1);
|
||||
tcg_gen_movi_tl(env_btarget, dc->pc);
|
||||
@ -1130,6 +1132,7 @@ static void dec_rts(DisasContext *dc)
|
||||
} else
|
||||
LOG_DIS("rts ir=%x\n", dc->ir);
|
||||
|
||||
dc->jmp = JMP_INDIRECT;
|
||||
tcg_gen_movi_tl(env_btaken, 1);
|
||||
tcg_gen_add_tl(env_btarget, cpu_R[dc->ra], *(dec_alu_op_b(dc)));
|
||||
}
|
||||
@ -1370,6 +1373,9 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
dc->is_jmp = DISAS_NEXT;
|
||||
dc->jmp = 0;
|
||||
dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
|
||||
if (dc->delayed_branch) {
|
||||
dc->jmp = JMP_INDIRECT;
|
||||
}
|
||||
dc->pc = pc_start;
|
||||
dc->singlestep_enabled = env->singlestep_enabled;
|
||||
dc->cpustate_changed = 0;
|
||||
@ -1441,9 +1447,21 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
/* Clear the delay slot flag. */
|
||||
dc->tb_flags &= ~D_FLAG;
|
||||
/* If it is a direct jump, try direct chaining. */
|
||||
if (dc->jmp != JMP_DIRECT) {
|
||||
if (dc->jmp == JMP_INDIRECT) {
|
||||
eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc));
|
||||
dc->is_jmp = DISAS_JUMP;
|
||||
} else if (dc->jmp == JMP_DIRECT) {
|
||||
int l1;
|
||||
|
||||
t_sync_flags(dc);
|
||||
l1 = gen_new_label();
|
||||
/* Conditional jmp. */
|
||||
tcg_gen_brcondi_tl(TCG_COND_NE, env_btaken, 0, l1);
|
||||
gen_goto_tb(dc, 1, dc->pc);
|
||||
gen_set_label(l1);
|
||||
gen_goto_tb(dc, 0, dc->jmp_pc);
|
||||
|
||||
dc->is_jmp = DISAS_TB_JUMP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -532,6 +532,14 @@ static inline int cpu_mips_hw_interrupts_pending(CPUState *env)
|
||||
int32_t status;
|
||||
int r;
|
||||
|
||||
if (!(env->CP0_Status & (1 << CP0St_IE)) ||
|
||||
(env->CP0_Status & (1 << CP0St_EXL)) ||
|
||||
(env->CP0_Status & (1 << CP0St_ERL)) ||
|
||||
(env->hflags & MIPS_HFLAG_DM)) {
|
||||
/* Interrupts are disabled */
|
||||
return 0;
|
||||
}
|
||||
|
||||
pending = env->CP0_Cause & CP0Ca_IP_mask;
|
||||
status = env->CP0_Status & CP0Ca_IP_mask;
|
||||
|
||||
|
@ -19,10 +19,22 @@ register struct CPUMIPSState *env asm(AREG0);
|
||||
|
||||
static inline int cpu_has_work(CPUState *env)
|
||||
{
|
||||
return (env->interrupt_request &
|
||||
(CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER));
|
||||
}
|
||||
int has_work = 0;
|
||||
|
||||
/* It is implementation dependent if non-enabled interrupts
|
||||
wake-up the CPU, however most of the implementations only
|
||||
check for interrupts that can be taken. */
|
||||
if ((env->interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
cpu_mips_hw_interrupts_pending(env)) {
|
||||
has_work = 1;
|
||||
}
|
||||
|
||||
if (env->interrupt_request & CPU_INTERRUPT_TIMER) {
|
||||
has_work = 1;
|
||||
}
|
||||
|
||||
return has_work;
|
||||
}
|
||||
|
||||
static inline int cpu_halted(CPUState *env)
|
||||
{
|
||||
|
@ -154,10 +154,10 @@ DEF_HELPER_2(mttlo, void, tl, i32)
|
||||
DEF_HELPER_2(mtthi, void, tl, i32)
|
||||
DEF_HELPER_2(mttacx, void, tl, i32)
|
||||
DEF_HELPER_1(mttdsp, void, tl)
|
||||
DEF_HELPER_1(dmt, tl, tl)
|
||||
DEF_HELPER_1(emt, tl, tl)
|
||||
DEF_HELPER_1(dvpe, tl, tl)
|
||||
DEF_HELPER_1(evpe, tl, tl)
|
||||
DEF_HELPER_0(dmt, tl)
|
||||
DEF_HELPER_0(emt, tl)
|
||||
DEF_HELPER_0(dvpe, tl)
|
||||
DEF_HELPER_0(evpe, tl)
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
/* microMIPS functions */
|
||||
|
@ -1554,40 +1554,28 @@ void helper_mttdsp(target_ulong arg1)
|
||||
}
|
||||
|
||||
/* MIPS MT functions */
|
||||
target_ulong helper_dmt(target_ulong arg1)
|
||||
target_ulong helper_dmt(void)
|
||||
{
|
||||
// TODO
|
||||
arg1 = 0;
|
||||
// rt = arg1
|
||||
|
||||
return arg1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
target_ulong helper_emt(target_ulong arg1)
|
||||
target_ulong helper_emt(void)
|
||||
{
|
||||
// TODO
|
||||
arg1 = 0;
|
||||
// rt = arg1
|
||||
|
||||
return arg1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
target_ulong helper_dvpe(target_ulong arg1)
|
||||
target_ulong helper_dvpe(void)
|
||||
{
|
||||
// TODO
|
||||
arg1 = 0;
|
||||
// rt = arg1
|
||||
|
||||
return arg1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
target_ulong helper_evpe(target_ulong arg1)
|
||||
target_ulong helper_evpe(void)
|
||||
{
|
||||
// TODO
|
||||
arg1 = 0;
|
||||
// rt = arg1
|
||||
|
||||
return arg1;
|
||||
return 0;
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
@ -2889,10 +2877,10 @@ static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
|
||||
{
|
||||
if (float64_is_signaling_nan(a) ||
|
||||
float64_is_signaling_nan(b) ||
|
||||
(sig && (float64_is_nan(a) || float64_is_nan(b)))) {
|
||||
(sig && (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)))) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1;
|
||||
} else if (float64_is_nan(a) || float64_is_nan(b)) {
|
||||
} else if (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@ -2947,10 +2935,10 @@ static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
|
||||
{
|
||||
if (float32_is_signaling_nan(a) ||
|
||||
float32_is_signaling_nan(b) ||
|
||||
(sig && (float32_is_nan(a) || float32_is_nan(b)))) {
|
||||
(sig && (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)))) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1;
|
||||
} else if (float32_is_nan(a) || float32_is_nan(b)) {
|
||||
} else if (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -12033,22 +12033,22 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
|
||||
switch (op2) {
|
||||
case OPC_DMT:
|
||||
check_insn(env, ctx, ASE_MT);
|
||||
gen_helper_dmt(t0, t0);
|
||||
gen_helper_dmt(t0);
|
||||
gen_store_gpr(t0, rt);
|
||||
break;
|
||||
case OPC_EMT:
|
||||
check_insn(env, ctx, ASE_MT);
|
||||
gen_helper_emt(t0, t0);
|
||||
gen_helper_emt(t0);
|
||||
gen_store_gpr(t0, rt);
|
||||
break;
|
||||
case OPC_DVPE:
|
||||
check_insn(env, ctx, ASE_MT);
|
||||
gen_helper_dvpe(t0, t0);
|
||||
gen_helper_dvpe(t0);
|
||||
gen_store_gpr(t0, rt);
|
||||
break;
|
||||
case OPC_EVPE:
|
||||
check_insn(env, ctx, ASE_MT);
|
||||
gen_helper_evpe(t0, t0);
|
||||
gen_helper_evpe(t0);
|
||||
gen_store_gpr(t0, rt);
|
||||
break;
|
||||
case OPC_DI:
|
||||
|
@ -26,9 +26,6 @@
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
|
||||
/* Precise emulation is needed to correctly emulate exception flags */
|
||||
#define USE_PRECISE_EMULATION 1
|
||||
|
||||
register struct CPUPPCState *env asm(AREG0);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
@ -546,7 +546,7 @@ uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
|
||||
int ret;
|
||||
farg.ll = arg;
|
||||
isneg = float64_is_neg(farg.d);
|
||||
if (unlikely(float64_is_nan(farg.d))) {
|
||||
if (unlikely(float64_is_quiet_nan(farg.d))) {
|
||||
if (float64_is_signaling_nan(farg.d)) {
|
||||
/* Signaling NaN: flags are undefined */
|
||||
ret = 0x00;
|
||||
@ -643,7 +643,7 @@ static 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 = 0xFFF8000000000000ULL;
|
||||
ret = 0x7FF8000000000000ULL;
|
||||
env->fpscr &= ~(0xF << FPSCR_FPCC);
|
||||
env->fpscr |= 0x11 << FPSCR_FPCC;
|
||||
}
|
||||
@ -654,7 +654,7 @@ static 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 = 0xFFF8000000000000ULL;
|
||||
ret = 0x7FF8000000000000ULL;
|
||||
env->fpscr &= ~(0xF << FPSCR_FPCC);
|
||||
env->fpscr |= 0x11 << FPSCR_FPCC;
|
||||
}
|
||||
@ -974,7 +974,7 @@ uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
|
||||
|
||||
farg1.ll = arg1;
|
||||
farg2.ll = arg2;
|
||||
#if USE_PRECISE_EMULATION
|
||||
|
||||
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
||||
float64_is_signaling_nan(farg2.d))) {
|
||||
/* sNaN addition */
|
||||
@ -986,9 +986,7 @@ uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
|
||||
} else {
|
||||
farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
|
||||
}
|
||||
#else
|
||||
farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
|
||||
#endif
|
||||
|
||||
return farg1.ll;
|
||||
}
|
||||
|
||||
@ -999,8 +997,7 @@ uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
|
||||
|
||||
farg1.ll = arg1;
|
||||
farg2.ll = arg2;
|
||||
#if USE_PRECISE_EMULATION
|
||||
{
|
||||
|
||||
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
||||
float64_is_signaling_nan(farg2.d))) {
|
||||
/* sNaN subtraction */
|
||||
@ -1012,10 +1009,7 @@ uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
|
||||
} else {
|
||||
farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
|
||||
}
|
||||
}
|
||||
#else
|
||||
farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
|
||||
#endif
|
||||
|
||||
return farg1.ll;
|
||||
}
|
||||
|
||||
@ -1026,7 +1020,7 @@ uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
|
||||
|
||||
farg1.ll = arg1;
|
||||
farg2.ll = arg2;
|
||||
#if USE_PRECISE_EMULATION
|
||||
|
||||
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
||||
float64_is_signaling_nan(farg2.d))) {
|
||||
/* sNaN multiplication */
|
||||
@ -1038,9 +1032,7 @@ uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
|
||||
} else {
|
||||
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
|
||||
}
|
||||
#else
|
||||
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
|
||||
#endif
|
||||
|
||||
return farg1.ll;
|
||||
}
|
||||
|
||||
@ -1051,7 +1043,7 @@ uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
|
||||
|
||||
farg1.ll = arg1;
|
||||
farg2.ll = arg2;
|
||||
#if USE_PRECISE_EMULATION
|
||||
|
||||
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
||||
float64_is_signaling_nan(farg2.d))) {
|
||||
/* sNaN division */
|
||||
@ -1065,9 +1057,7 @@ uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
|
||||
} else {
|
||||
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
|
||||
}
|
||||
#else
|
||||
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
|
||||
#endif
|
||||
|
||||
return farg1.ll;
|
||||
}
|
||||
|
||||
@ -1111,17 +1101,15 @@ 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) || float64_is_infinity(farg.d))) {
|
||||
} else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
|
||||
/* qNan / infinity conversion */
|
||||
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
|
||||
} else {
|
||||
farg.ll = float64_to_int32(farg.d, &env->fp_status);
|
||||
#if USE_PRECISE_EMULATION
|
||||
/* XXX: higher bits are not supposed to be significant.
|
||||
* to make tests easier, return the same as a real PowerPC 750
|
||||
*/
|
||||
farg.ll |= 0xFFF80000ULL << 32;
|
||||
#endif
|
||||
}
|
||||
return farg.ll;
|
||||
}
|
||||
@ -1135,17 +1123,15 @@ 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) || float64_is_infinity(farg.d))) {
|
||||
} else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
|
||||
/* qNan / infinity conversion */
|
||||
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
|
||||
} else {
|
||||
farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
|
||||
#if USE_PRECISE_EMULATION
|
||||
/* XXX: higher bits are not supposed to be significant.
|
||||
* to make tests easier, return the same as a real PowerPC 750
|
||||
*/
|
||||
farg.ll |= 0xFFF80000ULL << 32;
|
||||
#endif
|
||||
}
|
||||
return farg.ll;
|
||||
}
|
||||
@ -1168,7 +1154,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) || float64_is_infinity(farg.d))) {
|
||||
} else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
|
||||
/* qNan / infinity conversion */
|
||||
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
|
||||
} else {
|
||||
@ -1186,7 +1172,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) || float64_is_infinity(farg.d))) {
|
||||
} else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
|
||||
/* qNan / infinity conversion */
|
||||
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
|
||||
} else {
|
||||
@ -1205,7 +1191,7 @@ static 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) || float64_is_infinity(farg.d))) {
|
||||
} else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
|
||||
/* qNan / infinity round */
|
||||
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
|
||||
} else {
|
||||
@ -1245,7 +1231,7 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
|
||||
farg1.ll = arg1;
|
||||
farg2.ll = arg2;
|
||||
farg3.ll = arg3;
|
||||
#if USE_PRECISE_EMULATION
|
||||
|
||||
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
||||
float64_is_signaling_nan(farg2.d) ||
|
||||
float64_is_signaling_nan(farg3.d))) {
|
||||
@ -1277,10 +1263,7 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
|
||||
farg1.d = (farg1.d * farg2.d) + farg3.d;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
|
||||
farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
|
||||
#endif
|
||||
|
||||
return farg1.ll;
|
||||
}
|
||||
|
||||
@ -1292,7 +1275,7 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
|
||||
farg1.ll = arg1;
|
||||
farg2.ll = arg2;
|
||||
farg3.ll = arg3;
|
||||
#if USE_PRECISE_EMULATION
|
||||
|
||||
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
||||
float64_is_signaling_nan(farg2.d) ||
|
||||
float64_is_signaling_nan(farg3.d))) {
|
||||
@ -1324,10 +1307,6 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
|
||||
farg1.d = (farg1.d * farg2.d) - farg3.d;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
|
||||
farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
|
||||
#endif
|
||||
return farg1.ll;
|
||||
}
|
||||
|
||||
@ -1350,7 +1329,6 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
|
||||
/* Multiplication of zero by infinity */
|
||||
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
|
||||
} else {
|
||||
#if USE_PRECISE_EMULATION
|
||||
#ifdef FLOAT128
|
||||
/* This is the way the PowerPC specification defines it */
|
||||
float128 ft0_128, ft1_128;
|
||||
@ -1371,11 +1349,7 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
|
||||
/* This is OK on x86 hosts */
|
||||
farg1.d = (farg1.d * farg2.d) + farg3.d;
|
||||
#endif
|
||||
#else
|
||||
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
|
||||
farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
|
||||
#endif
|
||||
if (likely(!float64_is_nan(farg1.d)))
|
||||
if (likely(!float64_is_quiet_nan(farg1.d)))
|
||||
farg1.d = float64_chs(farg1.d);
|
||||
}
|
||||
return farg1.ll;
|
||||
@ -1400,7 +1374,6 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
|
||||
/* Multiplication of zero by infinity */
|
||||
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
|
||||
} else {
|
||||
#if USE_PRECISE_EMULATION
|
||||
#ifdef FLOAT128
|
||||
/* This is the way the PowerPC specification defines it */
|
||||
float128 ft0_128, ft1_128;
|
||||
@ -1421,11 +1394,7 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
|
||||
/* This is OK on x86 hosts */
|
||||
farg1.d = (farg1.d * farg2.d) - farg3.d;
|
||||
#endif
|
||||
#else
|
||||
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
|
||||
farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
|
||||
#endif
|
||||
if (likely(!float64_is_nan(farg1.d)))
|
||||
if (likely(!float64_is_quiet_nan(farg1.d)))
|
||||
farg1.d = float64_chs(farg1.d);
|
||||
}
|
||||
return farg1.ll;
|
||||
@ -1438,7 +1407,6 @@ uint64_t helper_frsp (uint64_t arg)
|
||||
float32 f32;
|
||||
farg.ll = arg;
|
||||
|
||||
#if USE_PRECISE_EMULATION
|
||||
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
||||
/* sNaN square root */
|
||||
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
@ -1446,10 +1414,6 @@ uint64_t helper_frsp (uint64_t arg)
|
||||
f32 = float64_to_float32(farg.d, &env->fp_status);
|
||||
farg.d = float32_to_float64(f32, &env->fp_status);
|
||||
}
|
||||
#else
|
||||
f32 = float64_to_float32(farg.d, &env->fp_status);
|
||||
farg.d = float32_to_float64(f32, &env->fp_status);
|
||||
#endif
|
||||
return farg.ll;
|
||||
}
|
||||
|
||||
@ -1533,7 +1497,7 @@ uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
|
||||
|
||||
farg1.ll = arg1;
|
||||
|
||||
if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d))
|
||||
if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_quiet_nan(farg1.d))
|
||||
return arg2;
|
||||
else
|
||||
return arg3;
|
||||
@ -1546,8 +1510,8 @@ void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
|
||||
farg1.ll = arg1;
|
||||
farg2.ll = arg2;
|
||||
|
||||
if (unlikely(float64_is_nan(farg1.d) ||
|
||||
float64_is_nan(farg2.d))) {
|
||||
if (unlikely(float64_is_quiet_nan(farg1.d) ||
|
||||
float64_is_quiet_nan(farg2.d))) {
|
||||
ret = 0x01UL;
|
||||
} else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
|
||||
ret = 0x08UL;
|
||||
@ -1575,8 +1539,8 @@ void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
|
||||
farg1.ll = arg1;
|
||||
farg2.ll = arg2;
|
||||
|
||||
if (unlikely(float64_is_nan(farg1.d) ||
|
||||
float64_is_nan(farg2.d))) {
|
||||
if (unlikely(float64_is_quiet_nan(farg1.d) ||
|
||||
float64_is_quiet_nan(farg2.d))) {
|
||||
ret = 0x01UL;
|
||||
} else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
|
||||
ret = 0x08UL;
|
||||
@ -1938,7 +1902,7 @@ target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_
|
||||
/* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
|
||||
* execute the following block. */
|
||||
#define DO_HANDLE_NAN(result, x) \
|
||||
if (float32_is_nan(x) || float32_is_signaling_nan(x)) { \
|
||||
if (float32_is_any_nan(x)) { \
|
||||
CPU_FloatU __f; \
|
||||
__f.f = x; \
|
||||
__f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
|
||||
@ -2283,8 +2247,7 @@ void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
||||
float_status s = env->vec_status; \
|
||||
set_float_rounding_mode(float_round_to_zero, &s); \
|
||||
for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
|
||||
if (float32_is_nan(b->f[i]) || \
|
||||
float32_is_signaling_nan(b->f[i])) { \
|
||||
if (float32_is_any_nan(b->f[i])) { \
|
||||
r->element[i] = 0; \
|
||||
} else { \
|
||||
float64 t = float32_to_float64(b->f[i], &s); \
|
||||
@ -3132,7 +3095,7 @@ static inline int32_t efsctsi(uint32_t val)
|
||||
|
||||
u.l = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float32_is_nan(u.f)))
|
||||
if (unlikely(float32_is_quiet_nan(u.f)))
|
||||
return 0;
|
||||
|
||||
return float32_to_int32(u.f, &env->vec_status);
|
||||
@ -3144,7 +3107,7 @@ static inline uint32_t efsctui(uint32_t val)
|
||||
|
||||
u.l = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float32_is_nan(u.f)))
|
||||
if (unlikely(float32_is_quiet_nan(u.f)))
|
||||
return 0;
|
||||
|
||||
return float32_to_uint32(u.f, &env->vec_status);
|
||||
@ -3156,7 +3119,7 @@ static inline uint32_t efsctsiz(uint32_t val)
|
||||
|
||||
u.l = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float32_is_nan(u.f)))
|
||||
if (unlikely(float32_is_quiet_nan(u.f)))
|
||||
return 0;
|
||||
|
||||
return float32_to_int32_round_to_zero(u.f, &env->vec_status);
|
||||
@ -3168,7 +3131,7 @@ static inline uint32_t efsctuiz(uint32_t val)
|
||||
|
||||
u.l = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float32_is_nan(u.f)))
|
||||
if (unlikely(float32_is_quiet_nan(u.f)))
|
||||
return 0;
|
||||
|
||||
return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
|
||||
@ -3205,7 +3168,7 @@ static inline uint32_t efsctsf(uint32_t val)
|
||||
|
||||
u.l = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float32_is_nan(u.f)))
|
||||
if (unlikely(float32_is_quiet_nan(u.f)))
|
||||
return 0;
|
||||
tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
|
||||
u.f = float32_mul(u.f, tmp, &env->vec_status);
|
||||
@ -3220,7 +3183,7 @@ static inline uint32_t efsctuf(uint32_t val)
|
||||
|
||||
u.l = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float32_is_nan(u.f)))
|
||||
if (unlikely(float32_is_quiet_nan(u.f)))
|
||||
return 0;
|
||||
tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
|
||||
u.f = float32_mul(u.f, tmp, &env->vec_status);
|
||||
@ -3474,7 +3437,7 @@ uint32_t helper_efdctsi (uint64_t val)
|
||||
|
||||
u.ll = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float64_is_nan(u.d)))
|
||||
if (unlikely(float64_is_quiet_nan(u.d)))
|
||||
return 0;
|
||||
|
||||
return float64_to_int32(u.d, &env->vec_status);
|
||||
@ -3486,7 +3449,7 @@ uint32_t helper_efdctui (uint64_t val)
|
||||
|
||||
u.ll = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float64_is_nan(u.d)))
|
||||
if (unlikely(float64_is_quiet_nan(u.d)))
|
||||
return 0;
|
||||
|
||||
return float64_to_uint32(u.d, &env->vec_status);
|
||||
@ -3498,7 +3461,7 @@ uint32_t helper_efdctsiz (uint64_t val)
|
||||
|
||||
u.ll = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float64_is_nan(u.d)))
|
||||
if (unlikely(float64_is_quiet_nan(u.d)))
|
||||
return 0;
|
||||
|
||||
return float64_to_int32_round_to_zero(u.d, &env->vec_status);
|
||||
@ -3510,7 +3473,7 @@ uint64_t helper_efdctsidz (uint64_t val)
|
||||
|
||||
u.ll = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float64_is_nan(u.d)))
|
||||
if (unlikely(float64_is_quiet_nan(u.d)))
|
||||
return 0;
|
||||
|
||||
return float64_to_int64_round_to_zero(u.d, &env->vec_status);
|
||||
@ -3522,7 +3485,7 @@ uint32_t helper_efdctuiz (uint64_t val)
|
||||
|
||||
u.ll = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float64_is_nan(u.d)))
|
||||
if (unlikely(float64_is_quiet_nan(u.d)))
|
||||
return 0;
|
||||
|
||||
return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
|
||||
@ -3534,7 +3497,7 @@ uint64_t helper_efdctuidz (uint64_t val)
|
||||
|
||||
u.ll = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float64_is_nan(u.d)))
|
||||
if (unlikely(float64_is_quiet_nan(u.d)))
|
||||
return 0;
|
||||
|
||||
return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
|
||||
@ -3571,7 +3534,7 @@ uint32_t helper_efdctsf (uint64_t val)
|
||||
|
||||
u.ll = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float64_is_nan(u.d)))
|
||||
if (unlikely(float64_is_quiet_nan(u.d)))
|
||||
return 0;
|
||||
tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
|
||||
u.d = float64_mul(u.d, tmp, &env->vec_status);
|
||||
@ -3586,7 +3549,7 @@ uint32_t helper_efdctuf (uint64_t val)
|
||||
|
||||
u.ll = val;
|
||||
/* NaN are not treated the same way IEEE 754 does */
|
||||
if (unlikely(float64_is_nan(u.d)))
|
||||
if (unlikely(float64_is_quiet_nan(u.d)))
|
||||
return 0;
|
||||
tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
|
||||
u.d = float64_mul(u.d, tmp, &env->vec_status);
|
||||
|
@ -7751,10 +7751,10 @@ static inline void gen_evfsabs(DisasContext *ctx)
|
||||
return;
|
||||
}
|
||||
#if defined(TARGET_PPC64)
|
||||
tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000080000000LL);
|
||||
tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000080000000LL);
|
||||
#else
|
||||
tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x80000000);
|
||||
tcg_gen_andi_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
|
||||
tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x80000000);
|
||||
tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
|
||||
#endif
|
||||
}
|
||||
static inline void gen_evfsnabs(DisasContext *ctx)
|
||||
@ -7764,10 +7764,10 @@ static inline void gen_evfsnabs(DisasContext *ctx)
|
||||
return;
|
||||
}
|
||||
#if defined(TARGET_PPC64)
|
||||
tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
|
||||
tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
|
||||
#else
|
||||
tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
|
||||
tcg_gen_ori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
|
||||
tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
|
||||
tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
|
||||
#endif
|
||||
}
|
||||
static inline void gen_evfsneg(DisasContext *ctx)
|
||||
@ -7777,10 +7777,10 @@ static inline void gen_evfsneg(DisasContext *ctx)
|
||||
return;
|
||||
}
|
||||
#if defined(TARGET_PPC64)
|
||||
tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
|
||||
tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
|
||||
#else
|
||||
tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
|
||||
tcg_gen_xori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
|
||||
tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
|
||||
tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -7832,7 +7832,7 @@ static inline void gen_efsabs(DisasContext *ctx)
|
||||
gen_exception(ctx, POWERPC_EXCP_APU);
|
||||
return;
|
||||
}
|
||||
tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL);
|
||||
tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL);
|
||||
}
|
||||
static inline void gen_efsnabs(DisasContext *ctx)
|
||||
{
|
||||
@ -7840,7 +7840,7 @@ static inline void gen_efsnabs(DisasContext *ctx)
|
||||
gen_exception(ctx, POWERPC_EXCP_APU);
|
||||
return;
|
||||
}
|
||||
tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
|
||||
tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
|
||||
}
|
||||
static inline void gen_efsneg(DisasContext *ctx)
|
||||
{
|
||||
@ -7848,7 +7848,7 @@ static inline void gen_efsneg(DisasContext *ctx)
|
||||
gen_exception(ctx, POWERPC_EXCP_APU);
|
||||
return;
|
||||
}
|
||||
tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
|
||||
tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
|
||||
}
|
||||
|
||||
/* Conversion */
|
||||
@ -7901,9 +7901,10 @@ static inline void gen_efdabs(DisasContext *ctx)
|
||||
return;
|
||||
}
|
||||
#if defined(TARGET_PPC64)
|
||||
tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000000000000LL);
|
||||
tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000000000000LL);
|
||||
#else
|
||||
tcg_gen_andi_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
|
||||
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
|
||||
tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
|
||||
#endif
|
||||
}
|
||||
static inline void gen_efdnabs(DisasContext *ctx)
|
||||
@ -7913,9 +7914,10 @@ static inline void gen_efdnabs(DisasContext *ctx)
|
||||
return;
|
||||
}
|
||||
#if defined(TARGET_PPC64)
|
||||
tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
|
||||
tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
|
||||
#else
|
||||
tcg_gen_ori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
|
||||
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
|
||||
tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
|
||||
#endif
|
||||
}
|
||||
static inline void gen_efdneg(DisasContext *ctx)
|
||||
@ -7925,9 +7927,10 @@ static inline void gen_efdneg(DisasContext *ctx)
|
||||
return;
|
||||
}
|
||||
#if defined(TARGET_PPC64)
|
||||
tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
|
||||
tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
|
||||
#else
|
||||
tcg_gen_xori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
|
||||
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
|
||||
tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ int kvm_arch_put_registers(CPUState *env, int level)
|
||||
|
||||
int kvm_arch_get_registers(CPUState *env)
|
||||
{
|
||||
uint32_t ret;
|
||||
int ret;
|
||||
struct kvm_regs regs;
|
||||
int i;
|
||||
|
||||
|
@ -36,7 +36,7 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
cpu_fprintf(f, "F%02d=%016lx", i, env->fregs[i]);
|
||||
cpu_fprintf(f, "F%02d=%016lx", i, (long)env->fregs[i].i);
|
||||
if ((i % 4) == 3) {
|
||||
cpu_fprintf(f, "\n");
|
||||
} else {
|
||||
|
@ -172,6 +172,8 @@ void do_interrupt(CPUSH4State * env);
|
||||
void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void cpu_sh4_invalidate_tlb(CPUSH4State *s);
|
||||
void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr,
|
||||
uint32_t mem_value);
|
||||
void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
|
||||
uint32_t mem_value);
|
||||
#endif
|
||||
|
@ -280,35 +280,40 @@ static void increment_urc(CPUState * env)
|
||||
env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10);
|
||||
}
|
||||
|
||||
/* Find itlb entry - update itlb from utlb if necessary and asked for
|
||||
/* Copy and utlb entry into itlb
|
||||
Return entry
|
||||
*/
|
||||
static int copy_utlb_entry_itlb(CPUState *env, int utlb)
|
||||
{
|
||||
int itlb;
|
||||
|
||||
tlb_t * ientry;
|
||||
itlb = itlb_replacement(env);
|
||||
ientry = &env->itlb[itlb];
|
||||
if (ientry->v) {
|
||||
tlb_flush_page(env, ientry->vpn << 10);
|
||||
}
|
||||
*ientry = env->utlb[utlb];
|
||||
update_itlb_use(env, itlb);
|
||||
return itlb;
|
||||
}
|
||||
|
||||
/* Find itlb entry
|
||||
Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE
|
||||
Update the itlb from utlb if update is not 0
|
||||
*/
|
||||
static int find_itlb_entry(CPUState * env, target_ulong address,
|
||||
int use_asid, int update)
|
||||
int use_asid)
|
||||
{
|
||||
int e, n;
|
||||
int e;
|
||||
|
||||
e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid);
|
||||
if (e == MMU_DTLB_MULTIPLE)
|
||||
if (e == MMU_DTLB_MULTIPLE) {
|
||||
e = MMU_ITLB_MULTIPLE;
|
||||
else if (e == MMU_DTLB_MISS && update) {
|
||||
e = find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
|
||||
if (e >= 0) {
|
||||
tlb_t * ientry;
|
||||
n = itlb_replacement(env);
|
||||
ientry = &env->itlb[n];
|
||||
if (ientry->v) {
|
||||
tlb_flush_page(env, ientry->vpn << 10);
|
||||
}
|
||||
*ientry = env->utlb[e];
|
||||
e = n;
|
||||
} else if (e == MMU_DTLB_MISS)
|
||||
e = MMU_ITLB_MISS;
|
||||
} else if (e == MMU_DTLB_MISS)
|
||||
} else if (e == MMU_DTLB_MISS) {
|
||||
e = MMU_ITLB_MISS;
|
||||
if (e >= 0)
|
||||
} else if (e >= 0) {
|
||||
update_itlb_use(env, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -340,13 +345,31 @@ static int get_mmu_address(CPUState * env, target_ulong * physical,
|
||||
use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
|
||||
|
||||
if (rw == 2) {
|
||||
n = find_itlb_entry(env, address, use_asid, 1);
|
||||
n = find_itlb_entry(env, address, use_asid);
|
||||
if (n >= 0) {
|
||||
matching = &env->itlb[n];
|
||||
if (!(env->sr & SR_MD) && !(matching->pr & 2))
|
||||
n = MMU_ITLB_VIOLATION;
|
||||
else
|
||||
*prot = PAGE_EXEC;
|
||||
} else {
|
||||
n = find_utlb_entry(env, address, use_asid);
|
||||
if (n >= 0) {
|
||||
n = copy_utlb_entry_itlb(env, n);
|
||||
matching = &env->itlb[n];
|
||||
if (!(env->sr & SR_MD) && !(matching->pr & 2)) {
|
||||
n = MMU_ITLB_VIOLATION;
|
||||
} else {
|
||||
*prot = PAGE_READ | PAGE_EXEC;
|
||||
if ((matching->pr & 1) && matching->d) {
|
||||
*prot |= PAGE_WRITE;
|
||||
}
|
||||
}
|
||||
} else if (n == MMU_DTLB_MULTIPLE) {
|
||||
n = MMU_ITLB_MULTIPLE;
|
||||
} else if (n == MMU_DTLB_MISS) {
|
||||
n = MMU_ITLB_MISS;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
n = find_utlb_entry(env, address, use_asid);
|
||||
@ -544,6 +567,25 @@ void cpu_load_tlb(CPUSH4State * env)
|
||||
tlb_flush(s, 1);
|
||||
}
|
||||
|
||||
void cpu_sh4_write_mmaped_itlb_addr(CPUSH4State *s, target_phys_addr_t addr,
|
||||
uint32_t mem_value)
|
||||
{
|
||||
uint32_t vpn = (mem_value & 0xfffffc00) >> 10;
|
||||
uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
|
||||
uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
|
||||
|
||||
int index = (addr & 0x00003f00) >> 8;
|
||||
tlb_t * entry = &s->itlb[index];
|
||||
if (entry->v) {
|
||||
/* Overwriting valid entry in itlb. */
|
||||
target_ulong address = entry->vpn << 10;
|
||||
tlb_flush_page(s, address);
|
||||
}
|
||||
entry->asid = asid;
|
||||
entry->vpn = vpn;
|
||||
entry->v = v;
|
||||
}
|
||||
|
||||
void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
|
||||
uint32_t mem_value)
|
||||
{
|
||||
|
@ -448,7 +448,7 @@ int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw
|
||||
int mmu_idx, int is_softmmu);
|
||||
#define cpu_handle_mmu_fault cpu_sparc_handle_mmu_fault
|
||||
target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev);
|
||||
void dump_mmu(CPUSPARCState *env);
|
||||
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env);
|
||||
|
||||
/* translate.c */
|
||||
void gen_intermediate_code_init(CPUSPARCState *env);
|
||||
|
@ -320,47 +320,45 @@ target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MMU
|
||||
void dump_mmu(CPUState *env)
|
||||
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
|
||||
{
|
||||
target_ulong va, va1, va2;
|
||||
unsigned int n, m, o;
|
||||
target_phys_addr_t pde_ptr, pa;
|
||||
uint32_t pde;
|
||||
|
||||
printf("MMU dump:\n");
|
||||
pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
|
||||
pde = ldl_phys(pde_ptr);
|
||||
printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
|
||||
(target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
|
||||
(*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
|
||||
(target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
|
||||
for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
|
||||
pde = mmu_probe(env, va, 2);
|
||||
if (pde) {
|
||||
pa = cpu_get_phys_page_debug(env, va);
|
||||
printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
|
||||
" PDE: " TARGET_FMT_lx "\n", va, pa, pde);
|
||||
(*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
|
||||
" PDE: " TARGET_FMT_lx "\n", va, pa, pde);
|
||||
for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
|
||||
pde = mmu_probe(env, va1, 1);
|
||||
if (pde) {
|
||||
pa = cpu_get_phys_page_debug(env, va1);
|
||||
printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
|
||||
" PDE: " TARGET_FMT_lx "\n", va1, pa, pde);
|
||||
(*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
|
||||
TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
|
||||
va1, pa, pde);
|
||||
for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
|
||||
pde = mmu_probe(env, va2, 0);
|
||||
if (pde) {
|
||||
pa = cpu_get_phys_page_debug(env, va2);
|
||||
printf(" VA: " TARGET_FMT_lx ", PA: "
|
||||
TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n",
|
||||
va2, pa, pde);
|
||||
(*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
|
||||
TARGET_FMT_plx " PTE: "
|
||||
TARGET_FMT_lx "\n",
|
||||
va2, pa, pde);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("MMU dump ends\n");
|
||||
}
|
||||
#endif /* DEBUG_MMU */
|
||||
|
||||
#else /* !TARGET_SPARC64 */
|
||||
|
||||
@ -622,18 +620,19 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MMU
|
||||
void dump_mmu(CPUState *env)
|
||||
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
|
||||
{
|
||||
unsigned int i;
|
||||
const char *mask;
|
||||
|
||||
printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n",
|
||||
env->dmmu.mmu_primary_context, env->dmmu.mmu_secondary_context);
|
||||
(*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
|
||||
PRId64 "\n",
|
||||
env->dmmu.mmu_primary_context,
|
||||
env->dmmu.mmu_secondary_context);
|
||||
if ((env->lsu & DMMU_E) == 0) {
|
||||
printf("DMMU disabled\n");
|
||||
(*cpu_fprintf)(f, "DMMU disabled\n");
|
||||
} else {
|
||||
printf("DMMU dump:\n");
|
||||
(*cpu_fprintf)(f, "DMMU dump\n");
|
||||
for (i = 0; i < 64; i++) {
|
||||
switch ((env->dtlb[i].tte >> 61) & 3) {
|
||||
default:
|
||||
@ -651,24 +650,25 @@ void dump_mmu(CPUState *env)
|
||||
break;
|
||||
}
|
||||
if ((env->dtlb[i].tte & 0x8000000000000000ULL) != 0) {
|
||||
printf("[%02u] VA: %" PRIx64 ", PA: %" PRIx64
|
||||
", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
|
||||
i,
|
||||
env->dtlb[i].tag & (uint64_t)~0x1fffULL,
|
||||
env->dtlb[i].tte & (uint64_t)0x1ffffffe000ULL,
|
||||
mask,
|
||||
env->dtlb[i].tte & 0x4? "priv": "user",
|
||||
env->dtlb[i].tte & 0x2? "RW": "RO",
|
||||
env->dtlb[i].tte & 0x40? "locked": "unlocked",
|
||||
env->dtlb[i].tag & (uint64_t)0x1fffULL,
|
||||
TTE_IS_GLOBAL(env->dtlb[i].tte)? "global" : "local");
|
||||
(*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
|
||||
", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
|
||||
i,
|
||||
env->dtlb[i].tag & (uint64_t)~0x1fffULL,
|
||||
env->dtlb[i].tte & (uint64_t)0x1ffffffe000ULL,
|
||||
mask,
|
||||
env->dtlb[i].tte & 0x4? "priv": "user",
|
||||
env->dtlb[i].tte & 0x2? "RW": "RO",
|
||||
env->dtlb[i].tte & 0x40? "locked": "unlocked",
|
||||
env->dtlb[i].tag & (uint64_t)0x1fffULL,
|
||||
TTE_IS_GLOBAL(env->dtlb[i].tte)?
|
||||
"global" : "local");
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((env->lsu & IMMU_E) == 0) {
|
||||
printf("IMMU disabled\n");
|
||||
(*cpu_fprintf)(f, "IMMU disabled\n");
|
||||
} else {
|
||||
printf("IMMU dump:\n");
|
||||
(*cpu_fprintf)(f, "IMMU dump\n");
|
||||
for (i = 0; i < 64; i++) {
|
||||
switch ((env->itlb[i].tte >> 61) & 3) {
|
||||
default:
|
||||
@ -686,21 +686,21 @@ void dump_mmu(CPUState *env)
|
||||
break;
|
||||
}
|
||||
if ((env->itlb[i].tte & 0x8000000000000000ULL) != 0) {
|
||||
printf("[%02u] VA: %" PRIx64 ", PA: %" PRIx64
|
||||
", %s, %s, %s, ctx %" PRId64 " %s\n",
|
||||
i,
|
||||
env->itlb[i].tag & (uint64_t)~0x1fffULL,
|
||||
env->itlb[i].tte & (uint64_t)0x1ffffffe000ULL,
|
||||
mask,
|
||||
env->itlb[i].tte & 0x4? "priv": "user",
|
||||
env->itlb[i].tte & 0x40? "locked": "unlocked",
|
||||
env->itlb[i].tag & (uint64_t)0x1fffULL,
|
||||
TTE_IS_GLOBAL(env->itlb[i].tte)? "global" : "local");
|
||||
(*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
|
||||
", %s, %s, %s, ctx %" PRId64 " %s\n",
|
||||
i,
|
||||
env->itlb[i].tag & (uint64_t)~0x1fffULL,
|
||||
env->itlb[i].tte & (uint64_t)0x1ffffffe000ULL,
|
||||
mask,
|
||||
env->itlb[i].tte & 0x4? "priv": "user",
|
||||
env->itlb[i].tte & 0x40? "locked": "unlocked",
|
||||
env->itlb[i].tag & (uint64_t)0x1fffULL,
|
||||
TTE_IS_GLOBAL(env->itlb[i].tte)?
|
||||
"global" : "local");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG_MMU */
|
||||
|
||||
#endif /* TARGET_SPARC64 */
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
@ -37,7 +37,9 @@ DEF_HELPER_0(save, void)
|
||||
DEF_HELPER_0(restore, void)
|
||||
DEF_HELPER_1(flush, void, tl)
|
||||
DEF_HELPER_2(udiv, tl, tl, tl)
|
||||
DEF_HELPER_2(udiv_cc, tl, tl, tl)
|
||||
DEF_HELPER_2(sdiv, tl, tl, tl)
|
||||
DEF_HELPER_2(sdiv_cc, tl, tl, tl)
|
||||
DEF_HELPER_2(stdf, void, tl, int)
|
||||
DEF_HELPER_2(lddf, void, tl, int)
|
||||
DEF_HELPER_2(ldqf, void, tl, int)
|
||||
|
@ -180,7 +180,7 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
|
||||
replace_tlb_entry(&tlb[i], 0, 0, env1);
|
||||
#ifdef DEBUG_MMU
|
||||
DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
|
||||
dump_mmu(env1);
|
||||
dump_mmu(stdout, fprintf, env1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -198,7 +198,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
|
||||
replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
|
||||
#ifdef DEBUG_MMU
|
||||
DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
|
||||
dump_mmu(env1);
|
||||
dump_mmu(stdout, fprintf, env1);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
@ -217,7 +217,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
|
||||
#ifdef DEBUG_MMU
|
||||
DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
|
||||
strmmu, (replace_used?"used":"unused"), i);
|
||||
dump_mmu(env1);
|
||||
dump_mmu(stdout, fprintf, env1);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
@ -1959,7 +1959,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_MMU
|
||||
dump_mmu(env);
|
||||
dump_mmu(stdout, fprintf, env);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
@ -2011,7 +2011,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
|
||||
reg, oldreg, env->mmuregs[reg]);
|
||||
}
|
||||
#ifdef DEBUG_MMU
|
||||
dump_mmu(env);
|
||||
dump_mmu(stdout, fprintf, env);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
@ -2912,7 +2912,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
|
||||
DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
|
||||
oldreg, env->lsu);
|
||||
#ifdef DEBUG_MMU
|
||||
dump_mmu(env);
|
||||
dump_mmu(stdout, fprintf, env1);
|
||||
#endif
|
||||
tlb_flush(env, 1);
|
||||
}
|
||||
@ -2957,7 +2957,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
|
||||
PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
|
||||
}
|
||||
#ifdef DEBUG_MMU
|
||||
dump_mmu(env);
|
||||
dump_mmu(stdout, fprintf, env);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
@ -2974,7 +2974,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
|
||||
|
||||
#ifdef DEBUG_MMU
|
||||
DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
|
||||
dump_mmu(env);
|
||||
dump_mmu(stdout, fprintf, env);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
@ -3030,7 +3030,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
|
||||
PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
|
||||
}
|
||||
#ifdef DEBUG_MMU
|
||||
dump_mmu(env);
|
||||
dump_mmu(stdout, fprintf, env);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
@ -3045,7 +3045,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
|
||||
|
||||
#ifdef DEBUG_MMU
|
||||
DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
|
||||
dump_mmu(env);
|
||||
dump_mmu(stdout, fprintf, env);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
@ -3300,8 +3300,9 @@ void helper_rett(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
target_ulong helper_udiv(target_ulong a, target_ulong b)
|
||||
static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc)
|
||||
{
|
||||
int overflow = 0;
|
||||
uint64_t x0;
|
||||
uint32_t x1;
|
||||
|
||||
@ -3314,16 +3315,31 @@ target_ulong helper_udiv(target_ulong a, target_ulong b)
|
||||
|
||||
x0 = x0 / x1;
|
||||
if (x0 > 0xffffffff) {
|
||||
env->cc_src2 = 1;
|
||||
return 0xffffffff;
|
||||
} else {
|
||||
env->cc_src2 = 0;
|
||||
return x0;
|
||||
x0 = 0xffffffff;
|
||||
overflow = 1;
|
||||
}
|
||||
|
||||
if (cc) {
|
||||
env->cc_dst = x0;
|
||||
env->cc_src2 = overflow;
|
||||
env->cc_op = CC_OP_DIV;
|
||||
}
|
||||
return x0;
|
||||
}
|
||||
|
||||
target_ulong helper_sdiv(target_ulong a, target_ulong b)
|
||||
target_ulong helper_udiv(target_ulong a, target_ulong b)
|
||||
{
|
||||
return helper_udiv_common(a, b, 0);
|
||||
}
|
||||
|
||||
target_ulong helper_udiv_cc(target_ulong a, target_ulong b)
|
||||
{
|
||||
return helper_udiv_common(a, b, 1);
|
||||
}
|
||||
|
||||
static target_ulong helper_sdiv_common(target_ulong a, target_ulong b, int cc)
|
||||
{
|
||||
int overflow = 0;
|
||||
int64_t x0;
|
||||
int32_t x1;
|
||||
|
||||
@ -3336,12 +3352,26 @@ target_ulong helper_sdiv(target_ulong a, target_ulong b)
|
||||
|
||||
x0 = x0 / x1;
|
||||
if ((int32_t) x0 != x0) {
|
||||
env->cc_src2 = 1;
|
||||
return x0 < 0? 0x80000000: 0x7fffffff;
|
||||
} else {
|
||||
env->cc_src2 = 0;
|
||||
return x0;
|
||||
x0 = x0 < 0 ? 0x80000000: 0x7fffffff;
|
||||
overflow = 1;
|
||||
}
|
||||
|
||||
if (cc) {
|
||||
env->cc_dst = x0;
|
||||
env->cc_src2 = overflow;
|
||||
env->cc_op = CC_OP_DIV;
|
||||
}
|
||||
return x0;
|
||||
}
|
||||
|
||||
target_ulong helper_sdiv(target_ulong a, target_ulong b)
|
||||
{
|
||||
return helper_sdiv_common(a, b, 0);
|
||||
}
|
||||
|
||||
target_ulong helper_sdiv_cc(target_ulong a, target_ulong b)
|
||||
{
|
||||
return helper_sdiv_common(a, b, 1);
|
||||
}
|
||||
|
||||
void helper_stdf(target_ulong addr, int mem_idx)
|
||||
|
@ -3162,20 +3162,20 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||
#endif
|
||||
case 0xe: /* udiv */
|
||||
CHECK_IU_FEATURE(dc, DIV);
|
||||
gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2);
|
||||
if (xop & 0x10) {
|
||||
tcg_gen_mov_tl(cpu_cc_dst, cpu_dst);
|
||||
tcg_gen_movi_i32(cpu_cc_op, CC_OP_DIV);
|
||||
gen_helper_udiv_cc(cpu_dst, cpu_src1, cpu_src2);
|
||||
dc->cc_op = CC_OP_DIV;
|
||||
} else {
|
||||
gen_helper_udiv(cpu_dst, cpu_src1, cpu_src2);
|
||||
}
|
||||
break;
|
||||
case 0xf: /* sdiv */
|
||||
CHECK_IU_FEATURE(dc, DIV);
|
||||
gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2);
|
||||
if (xop & 0x10) {
|
||||
tcg_gen_mov_tl(cpu_cc_dst, cpu_dst);
|
||||
tcg_gen_movi_i32(cpu_cc_op, CC_OP_DIV);
|
||||
gen_helper_sdiv_cc(cpu_dst, cpu_src1, cpu_src2);
|
||||
dc->cc_op = CC_OP_DIV;
|
||||
} else {
|
||||
gen_helper_sdiv(cpu_dst, cpu_src1, cpu_src2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
10
tcg/README
10
tcg/README
@ -75,11 +75,11 @@ destroyed, but local temporaries and globals are preserved.
|
||||
* Helpers:
|
||||
|
||||
Using the tcg_gen_helper_x_y it is possible to call any function
|
||||
taking i32, i64 or pointer types. By default, before calling an helper,
|
||||
taking i32, i64 or pointer types. By default, before calling a helper,
|
||||
all globals are stored at their canonical location and it is assumed
|
||||
that the function can modify them. This can be overriden by the
|
||||
that the function can modify them. This can be overridden by the
|
||||
TCG_CALL_CONST function modifier. By default, the helper is allowed to
|
||||
modify the CPU state or raise an exception. This can be overriden by
|
||||
modify the CPU state or raise an exception. This can be overridden by
|
||||
the TCG_CALL_PURE function modifier, in which case the call to the
|
||||
function is removed if the return value is not used.
|
||||
|
||||
@ -364,7 +364,7 @@ formed from two 32-bit arguments. The result is a 32-bit value.
|
||||
|
||||
********* QEMU specific operations
|
||||
|
||||
* tb_exit t0
|
||||
* exit_tb t0
|
||||
|
||||
Exit the current TB and return the value t0 (word type).
|
||||
|
||||
@ -488,7 +488,7 @@ register.
|
||||
the speed of the translation.
|
||||
|
||||
- Don't hesitate to use helpers for complicated or seldom used target
|
||||
intructions. There is little performance advantage in using TCG to
|
||||
instructions. There is little performance advantage in using TCG to
|
||||
implement target instructions taking more than about twenty TCG
|
||||
instructions.
|
||||
|
||||
|
@ -113,12 +113,25 @@ static const int tcg_target_call_oarg_regs[2] = {
|
||||
TCG_REG_R0, TCG_REG_R1
|
||||
};
|
||||
|
||||
static inline void reloc_abs32(void *code_ptr, tcg_target_long target)
|
||||
{
|
||||
*(uint32_t *) code_ptr = target;
|
||||
}
|
||||
|
||||
static inline void reloc_pc24(void *code_ptr, tcg_target_long target)
|
||||
{
|
||||
uint32_t offset = ((target - ((tcg_target_long) code_ptr + 8)) >> 2);
|
||||
|
||||
*(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & ~0xffffff)
|
||||
| (offset & 0xffffff);
|
||||
}
|
||||
|
||||
static void patch_reloc(uint8_t *code_ptr, int type,
|
||||
tcg_target_long value, tcg_target_long addend)
|
||||
{
|
||||
switch (type) {
|
||||
case R_ARM_ABS32:
|
||||
*(uint32_t *) code_ptr = value;
|
||||
reloc_abs32(code_ptr, value);
|
||||
break;
|
||||
|
||||
case R_ARM_CALL:
|
||||
@ -127,8 +140,7 @@ static void patch_reloc(uint8_t *code_ptr, int type,
|
||||
tcg_abort();
|
||||
|
||||
case R_ARM_PC24:
|
||||
*(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & 0xff000000) |
|
||||
(((value - ((tcg_target_long) code_ptr + 8)) >> 2) & 0xffffff);
|
||||
reloc_pc24(code_ptr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -394,35 +406,38 @@ static inline void tcg_out_dat_imm(TCGContext *s,
|
||||
}
|
||||
|
||||
static inline void tcg_out_movi32(TCGContext *s,
|
||||
int cond, int rd, int32_t arg)
|
||||
int cond, int rd, uint32_t arg)
|
||||
{
|
||||
/* TODO: This is very suboptimal, we can easily have a constant
|
||||
* pool somewhere after all the instructions. */
|
||||
|
||||
if (arg < 0 && arg > -0x100)
|
||||
return tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff);
|
||||
|
||||
if (use_armv7_instructions) {
|
||||
if ((int)arg < 0 && (int)arg >= -0x100) {
|
||||
tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff);
|
||||
} else if (use_armv7_instructions) {
|
||||
/* use movw/movt */
|
||||
/* movw */
|
||||
tcg_out32(s, (cond << 28) | 0x03000000 | (rd << 12)
|
||||
| ((arg << 4) & 0x000f0000) | (arg & 0xfff));
|
||||
if (arg & 0xffff0000)
|
||||
if (arg & 0xffff0000) {
|
||||
/* movt */
|
||||
tcg_out32(s, (cond << 28) | 0x03400000 | (rd << 12)
|
||||
| ((arg >> 12) & 0x000f0000) | ((arg >> 16) & 0xfff));
|
||||
} else {
|
||||
tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0, arg & 0xff);
|
||||
if (arg & 0x0000ff00)
|
||||
tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd,
|
||||
((arg >> 8) & 0xff) | 0xc00);
|
||||
if (arg & 0x00ff0000)
|
||||
tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd,
|
||||
((arg >> 16) & 0xff) | 0x800);
|
||||
if (arg & 0xff000000)
|
||||
tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd,
|
||||
((arg >> 24) & 0xff) | 0x400);
|
||||
}
|
||||
} else {
|
||||
int opc = ARITH_MOV;
|
||||
int rn = 0;
|
||||
|
||||
do {
|
||||
int i, rot;
|
||||
|
||||
i = ctz32(arg) & ~1;
|
||||
rot = ((32 - i) << 7) & 0xf00;
|
||||
tcg_out_dat_imm(s, cond, opc, rd, rn, ((arg >> i) & 0xff) | rot);
|
||||
arg &= ~(0xff << i);
|
||||
|
||||
opc = ARITH_ORR;
|
||||
rn = rd;
|
||||
} while (arg);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tcg_out_mul32(TCGContext *s,
|
||||
@ -1031,7 +1046,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
|
||||
}
|
||||
|
||||
label_ptr = (void *) s->code_ptr;
|
||||
tcg_out_b(s, COND_EQ, 8);
|
||||
tcg_out_b_noaddr(s, COND_EQ);
|
||||
|
||||
/* TODO: move this code to where the constants pool will be */
|
||||
if (addr_reg != TCG_REG_R0) {
|
||||
@ -1076,7 +1091,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
|
||||
break;
|
||||
}
|
||||
|
||||
*label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
|
||||
reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
|
||||
#else /* !CONFIG_SOFTMMU */
|
||||
if (GUEST_BASE) {
|
||||
uint32_t offset = GUEST_BASE;
|
||||
@ -1236,7 +1251,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
|
||||
tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg2);
|
||||
tcg_out_st32_rwb(s, COND_EQ, TCG_REG_R0, TCG_REG_R1, addr_reg);
|
||||
tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg);
|
||||
tcg_out_st32_12(s, COND_EQ, data_reg, TCG_REG_R1, 4);
|
||||
tcg_out_st32_12(s, COND_EQ, TCG_REG_R0, TCG_REG_R1, 4);
|
||||
} else {
|
||||
tcg_out_st32_rwb(s, COND_EQ, data_reg, TCG_REG_R1, addr_reg);
|
||||
tcg_out_st32_12(s, COND_EQ, data_reg2, TCG_REG_R1, 4);
|
||||
@ -1245,7 +1260,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
|
||||
}
|
||||
|
||||
label_ptr = (void *) s->code_ptr;
|
||||
tcg_out_b(s, COND_EQ, 8);
|
||||
tcg_out_b_noaddr(s, COND_EQ);
|
||||
|
||||
/* TODO: move this code to where the constants pool will be */
|
||||
tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
|
||||
@ -1317,7 +1332,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
|
||||
if (opc == 3)
|
||||
tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
|
||||
|
||||
*label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
|
||||
reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
|
||||
#else /* !CONFIG_SOFTMMU */
|
||||
if (GUEST_BASE) {
|
||||
uint32_t offset = GUEST_BASE;
|
||||
@ -1399,7 +1414,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||
/* Direct jump method */
|
||||
#if defined(USE_DIRECT_JUMP)
|
||||
s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
|
||||
tcg_out_b(s, COND_AL, 8);
|
||||
tcg_out_b_noaddr(s, COND_AL);
|
||||
#else
|
||||
tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
|
||||
s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
|
||||
|
@ -1329,7 +1329,7 @@ static inline void tcg_out_bswap32(TCGContext *s, TCGArg ret, TCGArg arg)
|
||||
|
||||
static inline void tcg_out_bswap64(TCGContext *s, TCGArg ret, TCGArg arg)
|
||||
{
|
||||
tcg_out_bundle(s, mII,
|
||||
tcg_out_bundle(s, miI,
|
||||
tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
|
||||
tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0),
|
||||
tcg_opc_i3 (TCG_REG_P0, OPC_MUX1_I3, ret, arg, 0xb));
|
||||
|
@ -352,7 +352,7 @@ static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int i
|
||||
static inline void tcg_out_opc_br(TCGContext *s, int opc, int rt, int rs)
|
||||
{
|
||||
/* We need to keep the offset unchanged for retranslation */
|
||||
uint16_t offset = (uint16_t)(*(uint32_t *) &s->code_ptr);
|
||||
uint16_t offset = (uint16_t)(*(uint32_t *) s->code_ptr);
|
||||
|
||||
tcg_out_opc_imm(s, opc, rt, rs, offset);
|
||||
}
|
||||
|
@ -32,10 +32,18 @@ void qemu_spice_input_init(void);
|
||||
void qemu_spice_audio_init(void);
|
||||
void qemu_spice_display_init(DisplayState *ds);
|
||||
int qemu_spice_add_interface(SpiceBaseInstance *sin);
|
||||
int qemu_spice_set_passwd(const char *passwd,
|
||||
bool fail_if_connected, bool disconnect_if_connected);
|
||||
int qemu_spice_set_pw_expire(time_t expires);
|
||||
|
||||
void do_info_spice_print(Monitor *mon, const QObject *data);
|
||||
void do_info_spice(Monitor *mon, QObject **ret_data);
|
||||
|
||||
#else /* CONFIG_SPICE */
|
||||
|
||||
#define using_spice 0
|
||||
#define qemu_spice_set_passwd(_p, _f1, _f2) (-1)
|
||||
#define qemu_spice_set_pw_expire(_e) (-1)
|
||||
|
||||
#endif /* CONFIG_SPICE */
|
||||
|
||||
|
261
ui/spice-core.c
261
ui/spice-core.c
@ -18,16 +18,26 @@
|
||||
#include <spice.h>
|
||||
#include <spice-experimental.h>
|
||||
|
||||
#include <netdb.h>
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu-spice.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "qemu-x509.h"
|
||||
#include "qemu_socket.h"
|
||||
#include "qint.h"
|
||||
#include "qbool.h"
|
||||
#include "qstring.h"
|
||||
#include "qjson.h"
|
||||
#include "monitor.h"
|
||||
|
||||
/* core bits */
|
||||
|
||||
static SpiceServer *spice_server;
|
||||
static const char *auth = "spice";
|
||||
static char *auth_passwd;
|
||||
static time_t auth_expires = TIME_MAX;
|
||||
int using_spice = 0;
|
||||
|
||||
struct SpiceTimer {
|
||||
@ -121,6 +131,118 @@ static void watch_remove(SpiceWatch *watch)
|
||||
qemu_free(watch);
|
||||
}
|
||||
|
||||
#if SPICE_INTERFACE_CORE_MINOR >= 3
|
||||
|
||||
typedef struct ChannelList ChannelList;
|
||||
struct ChannelList {
|
||||
SpiceChannelEventInfo *info;
|
||||
QTAILQ_ENTRY(ChannelList) link;
|
||||
};
|
||||
static QTAILQ_HEAD(, ChannelList) channel_list = QTAILQ_HEAD_INITIALIZER(channel_list);
|
||||
|
||||
static void channel_list_add(SpiceChannelEventInfo *info)
|
||||
{
|
||||
ChannelList *item;
|
||||
|
||||
item = qemu_mallocz(sizeof(*item));
|
||||
item->info = info;
|
||||
QTAILQ_INSERT_TAIL(&channel_list, item, link);
|
||||
}
|
||||
|
||||
static void channel_list_del(SpiceChannelEventInfo *info)
|
||||
{
|
||||
ChannelList *item;
|
||||
|
||||
QTAILQ_FOREACH(item, &channel_list, link) {
|
||||
if (item->info != info) {
|
||||
continue;
|
||||
}
|
||||
QTAILQ_REMOVE(&channel_list, item, link);
|
||||
qemu_free(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void add_addr_info(QDict *dict, struct sockaddr *addr, int len)
|
||||
{
|
||||
char host[NI_MAXHOST], port[NI_MAXSERV];
|
||||
const char *family;
|
||||
|
||||
getnameinfo(addr, len, host, sizeof(host), port, sizeof(port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
family = inet_strfamily(addr->sa_family);
|
||||
|
||||
qdict_put(dict, "host", qstring_from_str(host));
|
||||
qdict_put(dict, "port", qstring_from_str(port));
|
||||
qdict_put(dict, "family", qstring_from_str(family));
|
||||
}
|
||||
|
||||
static void add_channel_info(QDict *dict, SpiceChannelEventInfo *info)
|
||||
{
|
||||
int tls = info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS;
|
||||
|
||||
qdict_put(dict, "connection-id", qint_from_int(info->connection_id));
|
||||
qdict_put(dict, "channel-type", qint_from_int(info->type));
|
||||
qdict_put(dict, "channel-id", qint_from_int(info->id));
|
||||
qdict_put(dict, "tls", qbool_from_int(tls));
|
||||
}
|
||||
|
||||
static QList *channel_list_get(void)
|
||||
{
|
||||
ChannelList *item;
|
||||
QList *list;
|
||||
QDict *dict;
|
||||
|
||||
list = qlist_new();
|
||||
QTAILQ_FOREACH(item, &channel_list, link) {
|
||||
dict = qdict_new();
|
||||
add_addr_info(dict, &item->info->paddr, item->info->plen);
|
||||
add_channel_info(dict, item->info);
|
||||
qlist_append(list, dict);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static void channel_event(int event, SpiceChannelEventInfo *info)
|
||||
{
|
||||
static const int qevent[] = {
|
||||
[ SPICE_CHANNEL_EVENT_CONNECTED ] = QEVENT_SPICE_CONNECTED,
|
||||
[ SPICE_CHANNEL_EVENT_INITIALIZED ] = QEVENT_SPICE_INITIALIZED,
|
||||
[ SPICE_CHANNEL_EVENT_DISCONNECTED ] = QEVENT_SPICE_DISCONNECTED,
|
||||
};
|
||||
QDict *server, *client;
|
||||
QObject *data;
|
||||
|
||||
client = qdict_new();
|
||||
add_addr_info(client, &info->paddr, info->plen);
|
||||
|
||||
server = qdict_new();
|
||||
add_addr_info(server, &info->laddr, info->llen);
|
||||
|
||||
if (event == SPICE_CHANNEL_EVENT_INITIALIZED) {
|
||||
qdict_put(server, "auth", qstring_from_str(auth));
|
||||
add_channel_info(client, info);
|
||||
channel_list_add(info);
|
||||
}
|
||||
if (event == SPICE_CHANNEL_EVENT_DISCONNECTED) {
|
||||
channel_list_del(info);
|
||||
}
|
||||
|
||||
data = qobject_from_jsonf("{ 'client': %p, 'server': %p }",
|
||||
QOBJECT(client), QOBJECT(server));
|
||||
monitor_protocol_event(qevent[event], data);
|
||||
qobject_decref(data);
|
||||
}
|
||||
|
||||
#else /* SPICE_INTERFACE_CORE_MINOR >= 3 */
|
||||
|
||||
static QList *channel_list_get(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* SPICE_INTERFACE_CORE_MINOR >= 3 */
|
||||
|
||||
static SpiceCoreInterface core_interface = {
|
||||
.base.type = SPICE_INTERFACE_CORE,
|
||||
.base.description = "qemu core services",
|
||||
@ -135,6 +257,10 @@ static SpiceCoreInterface core_interface = {
|
||||
.watch_add = watch_add,
|
||||
.watch_update_mask = watch_update_mask,
|
||||
.watch_remove = watch_remove,
|
||||
|
||||
#if SPICE_INTERFACE_CORE_MINOR >= 3
|
||||
.channel_event = channel_event,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* config string parsing */
|
||||
@ -204,6 +330,92 @@ static const char *wan_compression_names[] = {
|
||||
|
||||
/* functions for the rest of qemu */
|
||||
|
||||
static void info_spice_iter(QObject *obj, void *opaque)
|
||||
{
|
||||
QDict *client;
|
||||
Monitor *mon = opaque;
|
||||
|
||||
client = qobject_to_qdict(obj);
|
||||
monitor_printf(mon, "Channel:\n");
|
||||
monitor_printf(mon, " address: %s:%s%s\n",
|
||||
qdict_get_str(client, "host"),
|
||||
qdict_get_str(client, "port"),
|
||||
qdict_get_bool(client, "tls") ? " [tls]" : "");
|
||||
monitor_printf(mon, " session: %" PRId64 "\n",
|
||||
qdict_get_int(client, "connection-id"));
|
||||
monitor_printf(mon, " channel: %d:%d\n",
|
||||
(int)qdict_get_int(client, "channel-type"),
|
||||
(int)qdict_get_int(client, "channel-id"));
|
||||
}
|
||||
|
||||
void do_info_spice_print(Monitor *mon, const QObject *data)
|
||||
{
|
||||
QDict *server;
|
||||
QList *channels;
|
||||
const char *host;
|
||||
int port;
|
||||
|
||||
server = qobject_to_qdict(data);
|
||||
if (qdict_get_bool(server, "enabled") == 0) {
|
||||
monitor_printf(mon, "Server: disabled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
monitor_printf(mon, "Server:\n");
|
||||
host = qdict_get_str(server, "host");
|
||||
port = qdict_get_try_int(server, "port", -1);
|
||||
if (port != -1) {
|
||||
monitor_printf(mon, " address: %s:%d\n", host, port);
|
||||
}
|
||||
port = qdict_get_try_int(server, "tls-port", -1);
|
||||
if (port != -1) {
|
||||
monitor_printf(mon, " address: %s:%d [tls]\n", host, port);
|
||||
}
|
||||
monitor_printf(mon, " auth: %s\n", qdict_get_str(server, "auth"));
|
||||
|
||||
channels = qdict_get_qlist(server, "channels");
|
||||
if (qlist_empty(channels)) {
|
||||
monitor_printf(mon, "Channels: none\n");
|
||||
} else {
|
||||
qlist_iter(channels, info_spice_iter, mon);
|
||||
}
|
||||
}
|
||||
|
||||
void do_info_spice(Monitor *mon, QObject **ret_data)
|
||||
{
|
||||
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head);
|
||||
QDict *server;
|
||||
QList *clist;
|
||||
const char *addr;
|
||||
int port, tls_port;
|
||||
|
||||
if (!spice_server) {
|
||||
*ret_data = qobject_from_jsonf("{ 'enabled': false }");
|
||||
return;
|
||||
}
|
||||
|
||||
addr = qemu_opt_get(opts, "addr");
|
||||
port = qemu_opt_get_number(opts, "port", 0);
|
||||
tls_port = qemu_opt_get_number(opts, "tls-port", 0);
|
||||
clist = channel_list_get();
|
||||
|
||||
server = qdict_new();
|
||||
qdict_put(server, "enabled", qbool_from_int(true));
|
||||
qdict_put(server, "auth", qstring_from_str(auth));
|
||||
qdict_put(server, "host", qstring_from_str(addr ? addr : "0.0.0.0"));
|
||||
if (port) {
|
||||
qdict_put(server, "port", qint_from_int(port));
|
||||
}
|
||||
if (tls_port) {
|
||||
qdict_put(server, "tls-port", qint_from_int(tls_port));
|
||||
}
|
||||
if (clist) {
|
||||
qdict_put(server, "channels", clist);
|
||||
}
|
||||
|
||||
*ret_data = QOBJECT(server);
|
||||
}
|
||||
|
||||
static int add_channel(const char *name, const char *value, void *opaque)
|
||||
{
|
||||
int security = 0;
|
||||
@ -316,6 +528,7 @@ void qemu_spice_init(void)
|
||||
spice_server_set_ticket(spice_server, password, 0, 0, 0);
|
||||
}
|
||||
if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) {
|
||||
auth = "none";
|
||||
spice_server_set_noauth(spice_server);
|
||||
}
|
||||
|
||||
@ -370,9 +583,57 @@ void qemu_spice_init(void)
|
||||
|
||||
int qemu_spice_add_interface(SpiceBaseInstance *sin)
|
||||
{
|
||||
if (!spice_server) {
|
||||
if (QTAILQ_FIRST(&qemu_spice_opts.head) != NULL) {
|
||||
fprintf(stderr, "Oops: spice configured but not active\n");
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
* Create a spice server instance.
|
||||
* It does *not* listen on the network.
|
||||
* It handles QXL local rendering only.
|
||||
*
|
||||
* With a command line like '-vnc :0 -vga qxl' you'll end up here.
|
||||
*/
|
||||
spice_server = spice_server_new();
|
||||
spice_server_init(spice_server, &core_interface);
|
||||
}
|
||||
return spice_server_add_interface(spice_server, sin);
|
||||
}
|
||||
|
||||
static int qemu_spice_set_ticket(bool fail_if_conn, bool disconnect_if_conn)
|
||||
{
|
||||
time_t lifetime, now = time(NULL);
|
||||
char *passwd;
|
||||
|
||||
if (now < auth_expires) {
|
||||
passwd = auth_passwd;
|
||||
lifetime = (auth_expires - now);
|
||||
if (lifetime > INT_MAX) {
|
||||
lifetime = INT_MAX;
|
||||
}
|
||||
} else {
|
||||
passwd = NULL;
|
||||
lifetime = 1;
|
||||
}
|
||||
return spice_server_set_ticket(spice_server, passwd, lifetime,
|
||||
fail_if_conn, disconnect_if_conn);
|
||||
}
|
||||
|
||||
int qemu_spice_set_passwd(const char *passwd,
|
||||
bool fail_if_conn, bool disconnect_if_conn)
|
||||
{
|
||||
free(auth_passwd);
|
||||
auth_passwd = strdup(passwd);
|
||||
return qemu_spice_set_ticket(fail_if_conn, disconnect_if_conn);
|
||||
}
|
||||
|
||||
int qemu_spice_set_pw_expire(time_t expires)
|
||||
{
|
||||
auth_expires = expires;
|
||||
return qemu_spice_set_ticket(false, false);
|
||||
}
|
||||
|
||||
static void spice_register_config(void)
|
||||
{
|
||||
qemu_add_opts(&qemu_spice_opts);
|
||||
|
44
ui/vnc.c
44
ui/vnc.c
@ -2082,18 +2082,15 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
|
||||
unsigned char response[VNC_AUTH_CHALLENGE_SIZE];
|
||||
int i, j, pwlen;
|
||||
unsigned char key[8];
|
||||
time_t now = time(NULL);
|
||||
|
||||
if (!vs->vd->password || !vs->vd->password[0]) {
|
||||
VNC_DEBUG("No password configured on server");
|
||||
vnc_write_u32(vs, 1); /* Reject auth */
|
||||
if (vs->minor >= 8) {
|
||||
static const char err[] = "Authentication failed";
|
||||
vnc_write_u32(vs, sizeof(err));
|
||||
vnc_write(vs, err, sizeof(err));
|
||||
}
|
||||
vnc_flush(vs);
|
||||
vnc_client_error(vs);
|
||||
return 0;
|
||||
goto reject;
|
||||
}
|
||||
if (vs->vd->expires < now) {
|
||||
VNC_DEBUG("Password is expired");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
|
||||
@ -2109,14 +2106,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
|
||||
/* Compare expected vs actual challenge response */
|
||||
if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
|
||||
VNC_DEBUG("Client challenge reponse did not match\n");
|
||||
vnc_write_u32(vs, 1); /* Reject auth */
|
||||
if (vs->minor >= 8) {
|
||||
static const char err[] = "Authentication failed";
|
||||
vnc_write_u32(vs, sizeof(err));
|
||||
vnc_write(vs, err, sizeof(err));
|
||||
}
|
||||
vnc_flush(vs);
|
||||
vnc_client_error(vs);
|
||||
goto reject;
|
||||
} else {
|
||||
VNC_DEBUG("Accepting VNC challenge response\n");
|
||||
vnc_write_u32(vs, 0); /* Accept auth */
|
||||
@ -2125,6 +2115,17 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
|
||||
start_client_init(vs);
|
||||
}
|
||||
return 0;
|
||||
|
||||
reject:
|
||||
vnc_write_u32(vs, 1); /* Reject auth */
|
||||
if (vs->minor >= 8) {
|
||||
static const char err[] = "Authentication failed";
|
||||
vnc_write_u32(vs, sizeof(err));
|
||||
vnc_write(vs, err, sizeof(err));
|
||||
}
|
||||
vnc_flush(vs);
|
||||
vnc_client_error(vs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void start_auth_vnc(VncState *vs)
|
||||
@ -2436,6 +2437,7 @@ void vnc_display_init(DisplayState *ds)
|
||||
|
||||
vs->ds = ds;
|
||||
QTAILQ_INIT(&vs->clients);
|
||||
vs->expires = TIME_MAX;
|
||||
|
||||
if (keyboard_layout)
|
||||
vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
|
||||
@ -2507,6 +2509,14 @@ int vnc_display_password(DisplayState *ds, const char *password)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vnc_display_pw_expire(DisplayState *ds, time_t expires)
|
||||
{
|
||||
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
|
||||
|
||||
vs->expires = expires;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *vnc_display_local_addr(DisplayState *ds)
|
||||
{
|
||||
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
|
||||
|
1
ui/vnc.h
1
ui/vnc.h
@ -120,6 +120,7 @@ struct VncDisplay
|
||||
|
||||
char *display;
|
||||
char *password;
|
||||
time_t expires;
|
||||
int auth;
|
||||
bool lossy;
|
||||
#ifdef CONFIG_VNC_TLS
|
||||
|
83
usb-bsd.c
83
usb-bsd.c
@ -306,14 +306,15 @@ USBDevice *usb_host_device_open(const char *devname)
|
||||
{
|
||||
struct usb_device_info bus_info, dev_info;
|
||||
USBDevice *d = NULL;
|
||||
USBHostDevice *dev;
|
||||
USBHostDevice *dev, *ret = NULL;
|
||||
char ctlpath[PATH_MAX + 1];
|
||||
char buspath[PATH_MAX + 1];
|
||||
int bfd, dfd, bus, address, i;
|
||||
int ugendebug = UGEN_DEBUG_LEVEL;
|
||||
|
||||
if (usb_host_find_device(&bus, &address, devname) < 0)
|
||||
return NULL;
|
||||
if (usb_host_find_device(&bus, &address, devname) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
snprintf(buspath, PATH_MAX, "/dev/usb%d", bus);
|
||||
|
||||
@ -323,7 +324,7 @@ USBDevice *usb_host_device_open(const char *devname)
|
||||
printf("usb_host_device_open: failed to open usb bus - %s\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
return NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bus_info.udi_addr = address;
|
||||
@ -332,7 +333,7 @@ USBDevice *usb_host_device_open(const char *devname)
|
||||
printf("usb_host_device_open: failed to grab bus information - %s\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
return NULL;
|
||||
goto fail_bfd;
|
||||
}
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
||||
@ -350,46 +351,52 @@ USBDevice *usb_host_device_open(const char *devname)
|
||||
ctlpath, strerror(errno));
|
||||
#endif
|
||||
}
|
||||
goto fail_dfd;
|
||||
}
|
||||
|
||||
if (dfd >= 0) {
|
||||
if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) {
|
||||
if (ioctl(dfd, USB_GET_DEVICEINFO, &dev_info) < 0) {
|
||||
#ifdef DEBUG
|
||||
printf("usb_host_device_open: failed to grab device info - %s\n",
|
||||
strerror(errno));
|
||||
printf("usb_host_device_open: failed to grab device info - %s\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
goto fail;
|
||||
}
|
||||
|
||||
d = usb_create(NULL /* FIXME */, "usb-host");
|
||||
dev = DO_UPCAST(USBHostDevice, dev, d);
|
||||
|
||||
if (dev_info.udi_speed == 1)
|
||||
dev->dev.speed = USB_SPEED_LOW - 1;
|
||||
else
|
||||
dev->dev.speed = USB_SPEED_FULL - 1;
|
||||
|
||||
if (strncmp(dev_info.udi_product, "product", 7) != 0)
|
||||
pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
|
||||
dev_info.udi_product);
|
||||
else
|
||||
snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
|
||||
"host:%s", devname);
|
||||
|
||||
pstrcpy(dev->devpath, sizeof(dev->devpath), "/dev/");
|
||||
pstrcat(dev->devpath, sizeof(dev->devpath), dev_info.udi_devnames[0]);
|
||||
|
||||
/* Mark the endpoints as not yet open */
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
|
||||
dev->ep_fd[i] = -1;
|
||||
|
||||
ioctl(dfd, USB_SETDEBUG, &ugendebug);
|
||||
|
||||
return (USBDevice *)dev;
|
||||
goto fail_dfd;
|
||||
}
|
||||
|
||||
d = usb_create(NULL /* FIXME */, "usb-host");
|
||||
dev = DO_UPCAST(USBHostDevice, dev, d);
|
||||
|
||||
if (dev_info.udi_speed == 1) {
|
||||
dev->dev.speed = USB_SPEED_LOW - 1;
|
||||
} else {
|
||||
dev->dev.speed = USB_SPEED_FULL - 1;
|
||||
}
|
||||
|
||||
if (strncmp(dev_info.udi_product, "product", 7) != 0) {
|
||||
pstrcpy(dev->dev.product_desc, sizeof(dev->dev.product_desc),
|
||||
dev_info.udi_product);
|
||||
} else {
|
||||
snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
|
||||
"host:%s", devname);
|
||||
}
|
||||
|
||||
pstrcpy(dev->devpath, sizeof(dev->devpath), "/dev/");
|
||||
pstrcat(dev->devpath, sizeof(dev->devpath), dev_info.udi_devnames[0]);
|
||||
|
||||
/* Mark the endpoints as not yet open */
|
||||
for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
|
||||
dev->ep_fd[i] = -1;
|
||||
}
|
||||
|
||||
ioctl(dfd, USB_SETDEBUG, &ugendebug);
|
||||
|
||||
ret = (USBDevice *)dev;
|
||||
|
||||
fail_dfd:
|
||||
close(dfd);
|
||||
fail_bfd:
|
||||
close(bfd);
|
||||
fail:
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct USBDeviceInfo usb_host_dev_info = {
|
||||
|
12
vl.c
12
vl.c
@ -759,8 +759,10 @@ char *get_boot_devices_list(uint32_t *size)
|
||||
}
|
||||
|
||||
if (i->suffix && devpath) {
|
||||
bootpath = qemu_malloc(strlen(devpath) + strlen(i->suffix) + 1);
|
||||
sprintf(bootpath, "%s%s", devpath, i->suffix);
|
||||
size_t bootpathlen = strlen(devpath) + strlen(i->suffix) + 1;
|
||||
|
||||
bootpath = qemu_malloc(bootpathlen);
|
||||
snprintf(bootpath, bootpathlen, "%s%s", devpath, i->suffix);
|
||||
qemu_free(devpath);
|
||||
} else if (devpath) {
|
||||
bootpath = devpath;
|
||||
@ -1502,6 +1504,8 @@ static void select_vgahw (const char *p)
|
||||
vga_interface_type = VGA_VMWARE;
|
||||
} else if (strstart(p, "xenfb", &opts)) {
|
||||
vga_interface_type = VGA_XENFB;
|
||||
} else if (strstart(p, "qxl", &opts)) {
|
||||
vga_interface_type = VGA_QXL;
|
||||
} else if (!strstart(p, "none", &opts)) {
|
||||
invalid_vga:
|
||||
fprintf(stderr, "Unknown vga type: %s\n", p);
|
||||
@ -2601,7 +2605,7 @@ int main(int argc, char **argv, char **envp)
|
||||
if (p != NULL) {
|
||||
*p++ = 0;
|
||||
if (strncmp(p, "process=", 8)) {
|
||||
fprintf(stderr, "Unknown subargument %s to -name", p);
|
||||
fprintf(stderr, "Unknown subargument %s to -name\n", p);
|
||||
exit(1);
|
||||
}
|
||||
p += 8;
|
||||
@ -3053,7 +3057,7 @@ int main(int argc, char **argv, char **envp)
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_SPICE
|
||||
if (using_spice) {
|
||||
if (using_spice && !qxl_enabled) {
|
||||
qemu_spice_display_init(ds);
|
||||
}
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user