*.tp
*.vr
*.d
-
- *.[oa]
+ *.o
*~
+
+i386-dm/Makefile
+i386-dm/config.mak
+i386-dm/qemu-dm
+qemu-img-xen
+dyngen-xen
+dist
LIBS+=$(AIOLIBS)
- all: $(TOOLS) $(DOCS) recurse-all
+ ifdef CONFIG_SOLARIS
+ LIBS+=-lsocket -lnsl -lresolv
+ endif
+
+ ifdef CONFIG_WIN32
+ LIBS+=-lwinmm -lws2_32 -liphlpapi
+ endif
- subdir-%: libqemu_common.a
+ all: $(TOOLS) $(DOCS) recurse-all
+
+ SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
+
-subdir-%: dyngen$(EXESUF)
++subdir-%:
$(MAKE) -C $(subst subdir-,,$@) all
- recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
+ $(filter %-softmmu,$(SUBDIR_RULES)): libqemu_common.a
+ $(filter %-user,$(SUBDIR_RULES)): libqemu_user.a
+
+ recurse-all: $(SUBDIR_RULES)
+tapdisk-ioemu: CPPFLAGS += -I$(XEN_ROOT)/tools/libxc
+tapdisk-ioemu: CPPFLAGS += -I$(XEN_ROOT)/tools/blktap/lib
+tapdisk-ioemu: CPPFLAGS += -I$(XEN_ROOT)/tools/xenstore
+tapdisk-ioemu: CPPFLAGS += -I$(XEN_ROOT)/tools/include
+tapdisk-ioemu: tapdisk-ioemu.c cutils.c block.c block-raw.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c block-qcow2.c hw/xen_blktap.c osdep.c
+ $(CC) -DQEMU_TOOL $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS)
+
#######################################################################
# BLOCK_OBJS is code used by both qemu system emulation and qemu-img
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+ qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o osdep.o $(BLOCK_OBJS)
+ $(CC) $(LDFLAGS) -o $@ $^ -lz $(LIBS)
+
# dyngen host tool
-dyngen$(EXESUF): dyngen.c osdep.o
+dyngen$(EXESUF): dyngen.o osdep.o
$(HOST_CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^
clean:
main.o: CFLAGS+=-p
endif
+-include hooks.mak
+all: $(PROGS)
+
$(QEMU_PROG): $(OBJS) ../libqemu_common.a libqemu.a
- $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS) $(BRLAPI_LIBS)
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS) $(BRLAPI_LIBS) $(VDE_LIBS)
endif # !CONFIG_USER_ONLY
/***********************************************************/
/* Unix AIO using POSIX AIO */
+#ifndef NO_AIO
typedef struct RawAIOCB {
BlockDriverAIOCB common;
+ int fd;
struct aiocb aiocb;
struct RawAIOCB *next;
+ int ret;
} RawAIOCB;
- static int aio_sig_num = SIGUSR2;
- static RawAIOCB *first_aio; /* AIO issued */
- static int aio_initialized = 0;
- static int aio_sig_pipe[2];
-
- static void aio_signal_handler(int signum)
+ typedef struct PosixAioState
{
- int e;
- e = errno;
- write(aio_sig_pipe[1],"",1); /* ignore errors as they should be EAGAIN */
- #ifndef QEMU_IMG
- CPUState *env = cpu_single_env;
- if (env) {
- /* stop the currently executing cpu because a timer occured */
- cpu_interrupt(env, CPU_INTERRUPT_EXIT);
- #ifdef USE_KQEMU
- if (env->kqemu_enabled) {
- kqemu_cpu_interrupt(env);
- }
- #endif
- }
- #endif
- errno = e;
- }
-
- static void qemu_aio_sig_pipe_read(void *opaque_ignored) {
- qemu_aio_poll();
- }
+ int rfd, wfd;
+ RawAIOCB *first_aio;
+ } PosixAioState;
- void qemu_aio_init(void)
+ static int raw_fd_pool_get(BDRVRawState *s)
{
- struct sigaction act;
- int ret;
+ int i;
- ret = pipe(aio_sig_pipe);
- if (ret) { perror("qemu_aio_init pipe failed"); exit(-1); }
- fcntl(aio_sig_pipe[0], F_SETFL, O_NONBLOCK);
- fcntl(aio_sig_pipe[1], F_SETFL, O_NONBLOCK);
+ for (i = 0; i < RAW_FD_POOL_SIZE; i++) {
+ /* already in use */
+ if (s->fd_pool[i] != -1)
+ continue;
- #ifndef QEMU_IMG
- ret = qemu_set_fd_handler2(aio_sig_pipe[0], NULL,
- qemu_aio_sig_pipe_read, NULL, NULL);
- if (ret) {
- fputs("qemu_aio_init set_fd_handler failed\n",stderr);
- exit(-1);
+ /* try to dup file descriptor */
+ s->fd_pool[i] = dup(s->fd);
+ if (s->fd_pool[i] != -1)
+ return s->fd_pool[i];
}
- #endif
- aio_initialized = 1;
+ /* we couldn't dup the file descriptor so just use the main one */
+ return s->fd;
+ }
- sigfillset(&act.sa_mask);
- act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
- act.sa_handler = aio_signal_handler;
- sigaction(aio_sig_num, &act, NULL);
+ static void raw_fd_pool_put(RawAIOCB *acb)
+ {
+ BDRVRawState *s = acb->common.bs->opaque;
+ int i;
- #if defined(__GLIBC__) && defined(__linux__)
- {
- /* XXX: aio thread exit seems to hang on RedHat 9 and this init
- seems to fix the problem. */
- struct aioinit ai;
- memset(&ai, 0, sizeof(ai));
- ai.aio_threads = 1;
- ai.aio_num = 1;
- ai.aio_idle_time = 365 * 100000;
- aio_init(&ai);
+ for (i = 0; i < RAW_FD_POOL_SIZE; i++) {
+ if (s->fd_pool[i] == acb->fd) {
+ close(s->fd_pool[i]);
+ s->fd_pool[i] = -1;
+ }
}
- #endif
}
- void qemu_aio_poll(void)
+ static void posix_aio_read(void *opaque)
{
+ PosixAioState *s = opaque;
RawAIOCB *acb, **pacb;
int ret;
+ ssize_t len;
- /* eat any pending signal notifications */
- {
- char dummy_buf[16];
- read(aio_sig_pipe[0],dummy_buf,sizeof(dummy_buf));
- }
+ do {
+ char byte;
+
+ len = read(s->rfd, &byte, 1);
+ if (len == -1 && errno == EINTR)
+ continue;
+ if (len == -1 && errno == EAGAIN)
+ break;
+ } while (len == -1);
for(;;) {
- pacb = &first_aio;
+ pacb = &s->first_aio;
for(;;) {
acb = *pacb;
if (!acb)
pacb = &acb->next;
}
}
+#endif
+ #else /* CONFIG_AIO */
+ static int posix_aio_init(void)
+ {
+ return 0;
+ }
+ #endif /* CONFIG_AIO */
+
+ static void raw_close_fd_pool(BDRVRawState *s)
+ {
+ int i;
+
+ for (i = 0; i < RAW_FD_POOL_SIZE; i++) {
+ if (s->fd_pool[i] != -1) {
+ close(s->fd_pool[i]);
+ s->fd_pool[i] = -1;
+ }
+ }
+ }
+
static void raw_close(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
.bdrv_aio_flush = raw_aio_flush,
.aiocb_size = sizeof(RawAIOCB),
#endif
- .protocol_name = "file",
++ /* .protocol_name = "file", // removed upstream, try removing it here -iwj */
.bdrv_pread = raw_pread,
.bdrv_pwrite = raw_pwrite,
.bdrv_truncate = raw_truncate,
;;
--disable-sdl) sdl="no"
;;
- --enable-coreaudio) coreaudio="yes"
+ --disable-opengl) opengl="no"
+ ;;
+ --fmod-lib=*) fmod_lib="$optarg"
;;
- --enable-alsa) alsa="yes"
+ --fmod-inc=*) fmod_inc="$optarg"
;;
- --enable-esd) esd="yes"
+ --oss-lib=*) oss_lib="$optarg"
;;
- --enable-dsound) dsound="yes"
+ --audio-card-list=*) audio_card_list=`echo "$optarg" | sed -e 's/,/ /g'`
;;
- --enable-fmod) fmod="yes"
+ --audio-drv-list=*) audio_drv_list="$optarg"
;;
- --fmod-lib=*) fmod_lib="$optarg"
+ --enable-sparse) sparse="yes"
;;
- --fmod-inc=*) fmod_inc="$optarg"
+ --disable-sparse) sparse="no"
;;
--disable-vnc-tls) vnc_tls="no"
;;
fi
##########################################
- ##########################################
- # alsa sound support libraries
+# OpenGL test
+
+if test -z "$opengl" && test "$sdl" = "yes"
+then
+cat > $TMPC << EOF
+#include <SDL_opengl.h>
+#ifndef GL_TEXTURE_RECTANGLE_ARB
+#error "Opengl doesn't support GL_TEXTURE_RECTANGLE_ARB"
+#endif
+int main( void ) { return (int) glGetString(GL_EXTENSIONS); }
+EOF
+if $cc $ARCH_CFLAGS -o $TMPE `$sdl_config --cflags --libs 2> /dev/null` -I/usr/include/GL $TMPC -lXext -lGL 2> /dev/null
+then
+opengl="yes"
+else
+opengl="no"
+fi
+fi
+
+ # Sound support libraries probe
- if test "$alsa" = "yes" ; then
- cat > $TMPC << EOF
- #include <alsa/asoundlib.h>
- int main(void) { snd_pcm_t **handle; return snd_pcm_close(*handle); }
+ audio_drv_probe()
+ {
+ drv=$1
+ hdr=$2
+ lib=$3
+ exp=$4
+ cfl=$5
+ cat > $TMPC << EOF
+ #include <$hdr>
+ int main(void) { $exp }
EOF
- if $cc $ARCH_CFLAGS -o $TMPE $TMPC -lasound 2> /dev/null ; then
- :
- else
- echo
- echo "Error: Could not find alsa"
- echo "Make sure to have the alsa libs and headers installed."
- echo
- exit 1
- fi
- fi
+ if $cc $ARCH_CFLAGS $cfl -o $TMPE $TMPC $lib 2> /dev/null ; then
+ :
+ else
+ echo
+ echo "Error: $drv check failed"
+ echo "Make sure to have the $drv libs and headers installed."
+ echo
+ exit 1
+ fi
+ }
+
+ audio_drv_list=`echo "$audio_drv_list" | sed -e 's/,/ /g'`
+ for drv in $audio_drv_list; do
+ case $drv in
+ alsa)
+ audio_drv_probe $drv alsa/asoundlib.h -lasound \
+ "snd_pcm_t **handle; return snd_pcm_close(*handle);"
+ ;;
+
+ fmod)
+ if test -z $fmod_lib || test -z $fmod_inc; then
+ echo
+ echo "Error: You must specify path to FMOD library and headers"
+ echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so"
+ echo
+ exit 1
+ fi
+ audio_drv_probe $drv fmod.h $fmod_lib "return FSOUND_GetVersion();" "-I $fmod_inc"
+ ;;
+
+ esd)
+ audio_drv_probe $drv esd.h -lesd 'return esd_play_stream(0, 0, "", 0);'
+ ;;
+
+ pa)
+ audio_drv_probe $drv pulse/simple.h -lpulse-simple \
+ "pa_simple *s = NULL; pa_simple_free(s); return 0;"
+ ;;
+
+ oss|sdl|core|wav|dsound)
+ # XXX: Probes for CoreAudio, DirectSound, SDL(?)
+ ;;
+
+ *)
+ echo "$audio_possible_drivers" | grep -q "\<$drv\>" || {
+ echo
+ echo "Error: Unknown driver '$drv' selected"
+ echo "Possible drivers are: $audio_possible_drivers"
+ echo
+ exit 1
+ }
+ ;;
+ esac
+ done
##########################################
# BrlAPI probe
if test "$sdl" != "no" ; then
echo "SDL static link $sdl_static"
fi
+echo "OpenGL support $opengl"
echo "curses support $curses"
echo "mingw32 support $mingw32"
- echo "Audio support $audio"
- echo "Adlib support $adlib"
- echo "AC97 support $ac97"
- echo "GUS support $gus"
- echo "CoreAudio support $coreaudio"
- echo "ALSA support $alsa"
- echo "EsounD support $esd"
- echo "DSound support $dsound"
- if test "$fmod" = "yes"; then
- if test -z $fmod_lib || test -z $fmod_inc; then
- echo
- echo "Error: You must specify path to FMOD library and headers"
- echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so"
- echo
- exit 1
- fi
- fmod_support=" (lib='$fmod_lib' include='$fmod_inc')"
- else
- fmod_support=""
- fi
- echo "FMOD support $fmod $fmod_support"
- echo "OSS support $oss"
+ echo "Audio drivers $audio_drv_list"
+ echo "Extra audio cards $audio_card_list"
+ echo "Mixer emulation $mixemu"
echo "VNC TLS support $vnc_tls"
if test "$vnc_tls" = "yes" ; then
echo " TLS CFLAGS $vnc_tls_cflags"
void vga_hw_screen_dump(const char *filename)
{
- /* There is currently no was of specifying which screen we want to dump,
- so always dump the dirst one. */
+ TextConsole *previous_active_console;
+
+ previous_active_console = active_console;
+ active_console = consoles[0];
+ /* There is currently no way of specifying which screen we want to dump,
+ so always dump the first one. */
if (consoles[0]->hw_screen_dump)
consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
+ active_console = previous_active_console;
}
-void vga_hw_text_update(console_ch_t *chardata)
-{
- if (active_console && active_console->hw_text_update)
- active_console->hw_text_update(active_console->hw, chardata);
-}
-
/* convert a RGBA color to a color index usable in graphic primitives */
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
{
s = consoles[index];
if (s) {
active_console = s;
- if (s->text_console) {
- if (s->console_type != TEXT_CONSOLE && s->g_width && s->g_height
- && (s->g_width != s->ds->width || s->g_height != s->ds->height))
- dpy_resize(s->ds, s->g_width, s->g_height);
- vga_hw_invalidate();
++ if (s->console_type == TEXT_CONSOLE) {
+ if (s->g_width != s->ds->width ||
+ s->g_height != s->ds->height) {
+ s->g_width = s->ds->width;
+ s->g_height = s->ds->height;
+ text_console_resize(s);
+ }
+ console_refresh(s);
+ } else {
+ vga_hw_invalidate();
+ }
}
}
} else {
/* HACK: Put graphical consoles before text consoles. */
for (i = nb_consoles; i > 0; i--) {
- if (!consoles[i - 1]->text_console)
- if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
++ if (!consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
break;
consoles[i] = consoles[i - 1];
}
int is_graphic_console(void)
{
- return !active_console->text_console;
+ return active_console && active_console->console_type == GRAPHIC_CONSOLE;
}
- void set_color_table(DisplayState *ds)
+ int is_fixedsize_console(void)
+ {
+ return active_console && active_console->console_type != TEXT_CONSOLE;
+ }
+
+ void console_color_init(DisplayState *ds)
{
int i, j;
- for (j = 0; j < 2; j++) {
- for (i = 0; i < 8; i++) {
- color_table[j][i] = col_expand(ds,
- vga_get_color(ds, color_table_rgb[j][i]));
- }
+ for(j = 0; j < 2; j++) {
+ for(i = 0; i < 8; i++) {
+ color_table[j][i] =
+ col_expand(ds, vga_get_color(ds, color_table_rgb[j][i]));
+ }
}
}
if (!color_inited) {
color_inited = 1;
- set_color_table(ds);
- console_color_init(s->ds);
++ console_color_init(ds);
}
s->y_displayed = 0;
s->y_base = 0;
int width;
int height;
void *opaque;
+ uint32_t *palette;
struct QEMUTimer *gui_timer;
uint64_t gui_timer_interval;
- int idle;
-
+ int idle; /* there is nothing to update (window invisible), set by vnc/sdl */
+ int shared_buf;
void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
void (*dpy_resize)(struct DisplayState *s, int w, int h);
int dst_x, int dst_y, int w, int h);
void (*dpy_fill)(struct DisplayState *s, int x, int y,
int w, int h, uint32_t c);
- void (*mouse_set)(int x, int y, int on);
- void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y,
- uint8_t *image, uint8_t *mask);
+ void (*dpy_text_cursor)(struct DisplayState *s, int x, int y);
};
static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
{
s->dpy_resize(s, w, h);
}
-
+static inline void dpy_resize_shared(DisplayState *s, int w, int h, int depth, int linesize, void *pixels)
+{
+ s->dpy_resize_shared(s, w, h, depth, linesize, pixels);
+}
+ static inline void dpy_cursor(DisplayState *s, int x, int y)
+ {
+ if (s->dpy_text_cursor)
+ s->dpy_text_cursor(s, x, y);
+ }
typedef unsigned long console_ch_t;
+ static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
+ {
+ cpu_to_le32wu((uint32_t *) dest, ch);
+ }
typedef void (*vga_hw_update_ptr)(void *);
typedef void (*vga_hw_invalidate_ptr)(void *);
void vga_hw_update(void);
void vga_hw_invalidate(void);
void vga_hw_screen_dump(const char *filename);
-void vga_hw_text_update(console_ch_t *chardata);
int is_graphic_console(void);
+ int is_fixedsize_console(void);
CharDriverState *text_console_init(DisplayState *ds, const char *p);
void console_select(unsigned int index);
- void set_color_table(DisplayState *ds);
+ void console_color_init(DisplayState *ds);
+ void qemu_console_resize(QEMUConsole *console, int width, int height);
+ void qemu_console_copy(QEMUConsole *console, int src_x, int src_y,
+ int dst_x, int dst_y, int w, int h);
/* sdl.c */
-void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
+void sdl_display_init(DisplayState *ds, int full_screen, int no_frame, int opengl_enabled);
/* cocoa.m */
void cocoa_display_init(DisplayState *ds, int full_screen);
#endif
-#if defined(CONFIG_USER_ONLY)
++#if defined(CONFIG_DM)
++static inline int can_do_io(CPUState *env) { return 1; }
++#endif
++
+#if defined(CONFIG_USER_ONLY) || defined(CONFIG_DM)
static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr)
{
return addr;
#include <assert.h>
#include <stddef.h> /* offsetof */
++#include <stdbool.h>
#include "hw.h"
#include "pci.h"
#include "net.h"
#define INT_MASK 0x0100
#define DRVR_INT 0x0200 /* Driver generated interrupt. */
--typedef unsigned char bool;
--
/* Offsets to the various registers.
All accesses need not be longword aligned. */
enum speedo_offsets {
return;
}
- if (!s->bs) return; /* yikes */
+ if (!s->bs) return; /* ouch! (see ide_flush_cb) */
+ if (!s->bs) return; /* yikes */
+
n = s->io_buffer_size >> 9;
sector_num = ide_get_sector(s);
if (n > 0) {
return;
}
- if (!s->bs) return; /* yikes */
+ if (!s->bs) return; /* ouch! (see ide_flush_cb) */
+ if (!s->bs) return; /* yikes */
+
n = s->io_buffer_size >> 9;
sector_num = ide_get_sector(s);
if (n > 0) {
IDEState *s = bm->ide_if;
int data_offset, n;
- if (!s->bs) return; /* yikes */
+ if (!s->bs) return; /* ouch! (see ide_flush_cb) */
+ if (!s->bs) return; /* yikes */
+
if (ret < 0) {
ide_atapi_io_error(s, ret);
goto eot;
IDEState *s = opaque;
uint64_t nb_sectors;
- if (!s->bs) return; /* yikes */
+ if (!s->bs) return; /* ouch! (see ide_flush_cb) */
+ if (!s->bs) return; /* yikes */
+
/* XXX: send interrupt too */
bdrv_get_geometry(s->bs, &nb_sectors);
s->nb_sectors = nb_sectors;
IDEState *s = ((IDEState *)opaque)->cur_drive;
uint8_t *p;
+ /* PIO data access allowed only when DRQ bit is set */
+ if (!(s->status & DRQ_STAT))
+ return;
+ buffered_pio_write(s, addr, 2);
+
p = s->data_ptr;
*(uint16_t *)p = le16_to_cpu(val);
p += 2;
IDEState *s = ((IDEState *)opaque)->cur_drive;
uint8_t *p;
int ret;
+
+ /* PIO data access allowed only when DRQ bit is set */
+ if (!(s->status & DRQ_STAT))
+ return 0;
+ buffered_pio_read(s, addr, 2);
+
p = s->data_ptr;
ret = cpu_to_le16(*(uint16_t *)p);
p += 2;
IDEState *s = ((IDEState *)opaque)->cur_drive;
uint8_t *p;
+ /* PIO data access allowed only when DRQ bit is set */
+ if (!(s->status & DRQ_STAT))
+ return;
+ buffered_pio_write(s, addr, 4);
+
p = s->data_ptr;
*(uint32_t *)p = le32_to_cpu(val);
p += 4;
uint8_t *p;
int ret;
+ /* PIO data access allowed only when DRQ bit is set */
+ if (!(s->status & DRQ_STAT))
+ return 0;
+ buffered_pio_read(s, addr, 4);
+
p = s->data_ptr;
ret = cpu_to_le32(*(uint32_t *)p);
p += 4;
pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[0x2c] = 0x53; /* subsystem vendor: XenSource */
+ pci_conf[0x2d] = 0x58;
+ pci_conf[0x2e] = 0x01; /* subsystem device */
+ pci_conf[0x2f] = 0x00;
+ qemu_register_reset(piix3_reset, d);
piix3_reset(d);
pci_register_io_region((PCIDevice *)d, 4, 0x10,
pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[0x2c] = 0x53; /* subsystem vendor: XenSource */
+ pci_conf[0x2d] = 0x58;
+ pci_conf[0x2e] = 0x01; /* subsystem device */
+ pci_conf[0x2f] = 0x00;
+ qemu_register_reset(piix3_reset, d);
piix3_reset(d);
pci_register_io_region((PCIDevice *)d, 4, 0x10,
--- /dev/null
- #include "audio/sys-queue.h"
+/*
+ * Copyright (c) 2007, Neocleus Corporation.
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PASSTHROUGH_H__
+#define __PASSTHROUGH_H__
+
+#include "hw.h"
+#include "pci.h"
+#include "pci/header.h"
+#include "pci/pci.h"
+#include "exec-all.h"
++#include "sys-queue.h"
+
+/* Log acesss */
+#define PT_LOGGING_ENABLED
+
+#ifdef PT_LOGGING_ENABLED
+#define PT_LOG(_f, _a...) fprintf(logfile, "%s: " _f, __func__, ##_a)
+#else
+#define PT_LOG(_f, _a...)
+#endif
+
+/* Some compilation flags */
+// #define PT_DEBUG_PCI_CONFIG_ACCESS
+
+#define PT_MACHINE_IRQ_AUTO (0xFFFFFFFF)
+#define PT_VIRT_DEVFN_AUTO (-1)
+
+/* Misc PCI constants that should be moved to a separate library :) */
+#define PCI_CONFIG_SIZE (256)
+#define PCI_EXP_DEVCAP_FLR (1 << 28)
+#define PCI_EXP_DEVCTL_FLR (1 << 15)
+#define PCI_BAR_ENTRIES (6)
+
+/* because the current version of libpci (2.2.0) doesn't define these ID,
+ * so we define Capability ID here.
+ */
+#ifndef PCI_CAP_ID_HOTPLUG
+/* SHPC Capability List Item reg group */
+#define PCI_CAP_ID_HOTPLUG 0x0C
+#endif
+
+#ifndef PCI_CAP_ID_SSVID
+/* Subsystem ID and Subsystem Vendor ID Capability List Item reg group */
+#define PCI_CAP_ID_SSVID 0x0D
+#endif
+
+#ifndef PCI_MSI_FLAGS_MASK_BIT
+/* interrupt masking & reporting supported */
+#define PCI_MSI_FLAGS_MASK_BIT 0x0100
+#endif
+
+#ifndef PCI_EXP_TYPE_PCIE_BRIDGE
+/* PCI/PCI-X to PCIE Bridge */
+#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8
+#endif
+
+#ifndef PCI_EXP_TYPE_ROOT_INT_EP
+/* Root Complex Integrated Endpoint */
+#define PCI_EXP_TYPE_ROOT_INT_EP 0x9
+#endif
+
+#ifndef PCI_EXP_TYPE_ROOT_EC
+/* Root Complex Event Collector */
+#define PCI_EXP_TYPE_ROOT_EC 0xa
+#endif
+
+#define PT_INVALID_REG 0xFFFFFFFF /* invalid register value */
+#define PT_BAR_ALLF 0xFFFFFFFF /* BAR ALLF value */
+#define PT_BAR_MEM_RO_MASK 0x0000000F /* BAR ReadOnly mask(Memory) */
+#define PT_BAR_MEM_EMU_MASK 0xFFFFFFF0 /* BAR emul mask(Memory) */
+#define PT_BAR_IO_RO_MASK 0x00000003 /* BAR ReadOnly mask(I/O) */
+#define PT_BAR_IO_EMU_MASK 0xFFFFFFFC /* BAR emul mask(I/O) */
+enum {
+ PT_BAR_FLAG_MEM = 0, /* Memory type BAR */
+ PT_BAR_FLAG_IO, /* I/O type BAR */
+ PT_BAR_FLAG_UPPER, /* upper 64bit BAR */
+ PT_BAR_FLAG_UNUSED, /* unused BAR */
+};
+enum {
+ GRP_TYPE_HARDWIRED = 0, /* 0 Hardwired reg group */
+ GRP_TYPE_EMU, /* emul reg group */
+};
+
+#define PT_GET_EMUL_SIZE(flag, r_size) do { \
+ if (flag == PT_BAR_FLAG_MEM) {\
+ r_size = (((r_size) + XC_PAGE_SIZE - 1) & ~(XC_PAGE_SIZE - 1)); \
+ }\
+} while(0)
+
+
+struct pt_region {
+ /* Virtual phys base & size */
+ uint32_t e_physbase;
+ uint32_t e_size;
+ /* Index of region in qemu */
+ uint32_t memory_index;
+ /* BAR flag */
+ uint32_t bar_flag;
+ /* Translation of the emulated address */
+ union {
+ uint64_t maddr;
+ uint64_t pio_base;
+ uint64_t u;
+ } access;
+};
+
+struct pt_msi_info {
+ uint32_t flags;
+ int pirq; /* guest pirq corresponding */
+ uint32_t addr_lo; /* guest message address */
+ uint32_t addr_hi; /* guest message upper address */
+ uint16_t data; /* guest message data */
+};
+
+struct msix_entry_info {
+ int pirq; /* -1 means unmapped */
+ int flags; /* flags indicting whether MSI ADDR or DATA is updated */
+ uint32_t io_mem[4];
+};
+
+struct pt_msix_info {
+ int enabled;
+ int total_entries;
+ int bar_index;
+ uint64_t table_base;
+ uint32_t table_off;
+ uint64_t mmio_base_addr;
+ int mmio_index;
+ int fd;
+ void *phys_iomem_base;
+ struct msix_entry_info msix_entry[0];
+};
+
+/*
+ This structure holds the context of the mapping functions
+ and data that is relevant for qemu device management.
+*/
+struct pt_dev {
+ PCIDevice dev;
+ struct pci_dev *pci_dev; /* libpci struct */
+ struct pt_region bases[PCI_NUM_REGIONS]; /* Access regions */
+ LIST_HEAD (reg_grp_tbl_listhead, pt_reg_grp_tbl) reg_grp_tbl_head;
+ /* emul reg group list */
+ struct pt_msi_info *msi; /* MSI virtualization */
+ struct pt_msix_info *msix; /* MSI-X virtualization */
+};
+
+/* Used for formatting PCI BDF into cf8 format */
+struct pci_config_cf8 {
+ union {
+ unsigned int value;
+ struct {
+ unsigned int reserved1:2;
+ unsigned int reg:6;
+ unsigned int func:3;
+ unsigned int dev:5;
+ unsigned int bus:8;
+ unsigned int reserved2:7;
+ unsigned int enable:1;
+ };
+ };
+};
+
+/* emul reg group management table */
+struct pt_reg_grp_tbl {
+ /* emul reg group list */
+ LIST_ENTRY (pt_reg_grp_tbl) entries;
+ /* emul reg group info table */
+ struct pt_reg_grp_info_tbl *reg_grp;
+ /* emul reg group base offset */
+ uint32_t base_offset;
+ /* emul reg group size */
+ uint8_t size;
+ /* emul reg management table list */
+ LIST_HEAD (reg_tbl_listhead, pt_reg_tbl) reg_tbl_head;
+};
+
+/* emul reg group size initialize method */
+typedef uint8_t (*pt_reg_size_init) (struct pt_dev *ptdev,
+ struct pt_reg_grp_info_tbl *grp_reg,
+ uint32_t base_offset);
+/* emul reg group infomation table */
+struct pt_reg_grp_info_tbl {
+ /* emul reg group ID */
+ uint8_t grp_id;
+ /* emul reg group type */
+ uint8_t grp_type;
+ /* emul reg group size */
+ uint8_t grp_size;
+ /* emul reg get size method */
+ pt_reg_size_init size_init;
+ /* emul reg info table */
+ struct pt_reg_info_tbl *emu_reg_tbl;
+};
+
+/* emul reg management table */
+struct pt_reg_tbl {
+ /* emul reg table list */
+ LIST_ENTRY (pt_reg_tbl) entries;
+ /* emul reg info table */
+ struct pt_reg_info_tbl *reg;
+ /* emul reg value */
+ uint32_t data;
+};
+
+/* emul reg initialize method */
+typedef uint32_t (*conf_reg_init) (struct pt_dev *ptdev,
+ struct pt_reg_info_tbl *reg,
+ uint32_t real_offset);
+/* emul reg long write method */
+typedef int (*conf_dword_write) (struct pt_dev *ptdev,
+ struct pt_reg_tbl *cfg_entry,
+ uint32_t *value,
+ uint32_t dev_value,
+ uint32_t valid_mask);
+/* emul reg word write method */
+typedef int (*conf_word_write) (struct pt_dev *ptdev,
+ struct pt_reg_tbl *cfg_entry,
+ uint16_t *value,
+ uint16_t dev_value,
+ uint16_t valid_mask);
+/* emul reg byte write method */
+typedef int (*conf_byte_write) (struct pt_dev *ptdev,
+ struct pt_reg_tbl *cfg_entry,
+ uint8_t *value,
+ uint8_t dev_value,
+ uint8_t valid_mask);
+/* emul reg long read methods */
+typedef int (*conf_dword_read) (struct pt_dev *ptdev,
+ struct pt_reg_tbl *cfg_entry,
+ uint32_t *value,
+ uint32_t valid_mask);
+/* emul reg word read method */
+typedef int (*conf_word_read) (struct pt_dev *ptdev,
+ struct pt_reg_tbl *cfg_entry,
+ uint16_t *value,
+ uint16_t valid_mask);
+/* emul reg byte read method */
+typedef int (*conf_byte_read) (struct pt_dev *ptdev,
+ struct pt_reg_tbl *cfg_entry,
+ uint8_t *value,
+ uint8_t valid_mask);
+
+/* emul reg infomation table */
+struct pt_reg_info_tbl {
+ /* reg relative offset */
+ uint32_t offset;
+ /* reg size */
+ uint32_t size;
+ /* reg initial value */
+ uint32_t init_val;
+ /* reg read only field mask (ON:RO/ROS, OFF:other) */
+ uint32_t ro_mask;
+ /* reg emulate field mask (ON:emu, OFF:passthrough) */
+ uint32_t emu_mask;
+ /* emul reg initialize method */
+ conf_reg_init init;
+ union {
+ struct {
+ /* emul reg long write method */
+ conf_dword_write write;
+ /* emul reg long read method */
+ conf_dword_read read;
+ } dw;
+ struct {
+ /* emul reg word write method */
+ conf_word_write write;
+ /* emul reg word read method */
+ conf_word_read read;
+ } w;
+ struct {
+ /* emul reg byte write method */
+ conf_byte_write write;
+ /* emul reg byte read method */
+ conf_byte_read read;
+ } b;
+ } u;
+};
+
+#endif /* __PASSTHROUGH_H__ */
+
#include "smbus.h"
#include "boards.h"
#include "console.h"
+#include "exec-all.h"
+
+#include "xen_platform.h"
+ #include "fw_cfg.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
{
CPUState *env = first_cpu;
- if (!level)
- return;
-
- while (env) {
- if (apic_accept_pic_intr(env))
- apic_local_deliver(env, APIC_LINT0);
- env = env->next_cpu;
+ if (env->apic_state) {
+ while (env) {
+ if (apic_accept_pic_intr(env))
+ apic_deliver_pic_intr(env, level);
+ env = env->next_cpu;
+ }
+ } else {
+ if (level)
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ else
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
}
}
+#else
+#define pic_irq_request 0 /* see i386-dm/i8259.c:i8259_init */
+#endif /* !CONFIG_DM */
/* PC cmos mappings */
prot_addr = 0x100000;
}
-#if 0
+#if 1
fprintf(stderr,
- "qemu: real_addr = %#zx\n"
- "qemu: cmdline_addr = %#zx\n"
- "qemu: prot_addr = %#zx\n",
- (size_t)real_addr,
- (size_t)cmdline_addr,
- (size_t)prot_addr);
+ "qemu: real_addr = 0x" TARGET_FMT_plx "\n"
+ "qemu: cmdline_addr = 0x" TARGET_FMT_plx "\n"
+ "qemu: prot_addr = 0x" TARGET_FMT_plx "\n",
+ real_addr,
+ cmdline_addr,
+ prot_addr);
#endif
- /* highest address for loading the initrd */
- if (protocol >= 0x203)
- initrd_max = ldl_p(header+0x22c);
- else
- initrd_max = 0x37ffffff;
+ /* Special pages are placed at end of low RAM: pick an arbitrary one and
+ * subtract a suitably large amount of padding (64kB) to skip BIOS data. */
+ xc_get_hvm_param(xc_handle, domid, HVM_PARAM_BUFIOREQ_PFN, &end_low_ram);
+ end_low_ram = (end_low_ram << 12) - (64*1024);
- if (initrd_max >= ram_size-ACPI_DATA_SIZE)
- initrd_max = ram_size-ACPI_DATA_SIZE-1;
+ /* highest address for loading the initrd */
+ initrd_max = (protocol >= 0x203) ? ldl_p(header+0x22c) : 0x37ffffff;
+ initrd_max = MIN(initrd_max, (uint32_t)end_low_ram);
/* kernel command line */
pstrcpy_targphys(cmdline_addr, 4096, kernel_cmdline);
fprintf(stderr, "Unable to find x86 CPU definition\n");
exit(1);
}
+#ifndef CONFIG_DM
if (i != 0)
- env->hflags |= HF_HALTED_MASK;
+ env->halted = 1;
if (smp_cpus > 1) {
/* XXX: enable it in all cases */
env->cpuid_features |= CPUID_APIC;
}
- register_savevm("cpu", i, 4, cpu_save, cpu_load, env);
+#endif /* !CONFIG_DM */
qemu_register_reset(main_cpu_reset, env);
if (pci_enabled) {
apic_init(env);
vmport_init();
+#ifndef CONFIG_DM
/* allocate RAM */
- ram_addr = qemu_ram_alloc(ram_size);
- cpu_register_physical_memory(0, below_4g_mem_size, ram_addr);
+ ram_addr = qemu_ram_alloc(0xa0000);
+ cpu_register_physical_memory(0, 0xa0000, ram_addr);
+
+ /* Allocate, even though we won't register, so we don't break the
+ * phys_ram_base + PA assumption. This range includes vga (0xa0000 - 0xc0000),
+ * and some bios areas, which will be registered later
+ */
+ ram_addr = qemu_ram_alloc(0x100000 - 0xa0000);
+ ram_addr = qemu_ram_alloc(below_4g_mem_size - 0x100000);
+ cpu_register_physical_memory(0x100000,
+ below_4g_mem_size - 0x100000,
+ ram_addr);
/* above 4giga memory allocation */
if (above_4g_mem_size > 0) {
}
}
+#ifdef CONFIG_PASSTHROUGH
+ /* Pass-through Initialization
+ * init libpci even direct_pci is null, as can hotplug a dev runtime
+ */
+ if ( pci_enabled )
+ {
+ rc = pt_init(pci_bus, direct_pci);
+ if ( rc < 0 )
+ {
+ fprintf(logfile, "Error: Initialization failed for pass-through devices\n");
+ exit(1);
+ }
+ }
+#endif
+
rtc_state = rtc_init(0x70, i8259[8]);
+ qemu_register_boot_set(pc_boot_set, rtc_state);
+
register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
};
QEMUMachine isapc_machine = {
- "isapc",
- "ISA-only PC",
- pc_init_isa,
- VGA_RAM_SIZE + PC_MAX_BIOS_SIZE,
+ .name = "isapc",
+ .desc = "ISA-only PC",
+ .init = pc_init_isa,
+ .ram_require = VGA_RAM_SIZE + PC_MAX_BIOS_SIZE,
+ .max_cpus = 1,
};
+
+
+
+
+/*
+ * Evil helper for non-relocatable kernels
+ *
+ * So it works out like this:
+ *
+ * 0x100000 - Xen HVM firmware lives here. Kernel wants to boot here
+ *
+ * You can't both live there and HVM firmware is needed first, thus
+ * our plan is
+ *
+ * 0x200000 - kernel is loaded here by QEMU
+ * 0x200000+kernel_size - helper code is put here by QEMU
+ *
+ * code32_switch in kernel header is set to point at out helper
+ * code at 0x200000+kernel_size
+ *
+ * Our helper basically does memmove(0x100000,0x200000,kernel_size)
+ * and then jmps to 0x1000000.
+ *
+ * So we've overwritten the HVM firmware (which was no longer
+ * needed) and the non-relocatable kernel can happily boot
+ * at its usual address.
+ *
+ * Simple, eh ?
+ *
+ * Well the assembler needed to do this is fairly short:
+ *
+ * # Load segments
+ * cld
+ * cli
+ * movl $0x18,%eax
+ * mov %ax,%ds
+ * mov %ax,%es
+ * mov %ax,%fs
+ * mov %ax,%gs
+ * mov %ax,%ss
+ *
+ * # Move the kernel into position
+ * xor %edx,%edx
+ *_doloop:
+ * movzbl 0x600000(%edx),%eax
+ * mov %al,0x100000(%edx)
+ * add $0x1,%edx
+ * cmp $0x500000,%edx
+ * jne _doloop
+ *
+ * # start kernel
+ * xorl %ebx,%ebx
+ * mov $0x100000,%ecx
+ * jmp *%ecx
+ *
+ */
+static void setup_relocator(target_phys_addr_t addr, target_phys_addr_t src, target_phys_addr_t dst, size_t len)
+{
+ /* Now this assembler corresponds to follow machine code, with our args from QEMU spliced in :-) */
+ unsigned char buf[] = {
+ /* Load segments */
+ 0xfc, /* cld */
+ 0xfa, /* cli */
+ 0xb8, 0x18, 0x00, 0x00, 0x00, /* mov $0x18,%eax */
+ 0x8e, 0xd8, /* mov %eax,%ds */
+ 0x8e, 0xc0, /* mov %eax,%es */
+ 0x8e, 0xe0, /* mov %eax,%fs */
+ 0x8e, 0xe8, /* mov %eax,%gs */
+ 0x8e, 0xd0, /* mov %eax,%ss */
+ 0x31, 0xd2, /* xor %edx,%edx */
+
+ /* Move the kernel into position */
+ 0x0f, 0xb6, 0x82, (src&0xff), ((src>>8)&0xff), ((src>>16)&0xff), ((src>>24)&0xff), /* movzbl $src(%edx),%eax */
+ 0x88, 0x82, (dst&0xff), ((dst>>8)&0xff), ((dst>>16)&0xff), ((dst>>24)&0xff), /* mov %al,$dst(%edx) */
+ 0x83, 0xc2, 0x01, /* add $0x1,%edx */
+ 0x81, 0xfa, (len&0xff), ((len>>8)&0xff), ((len>>16)&0xff), ((len>>24)&0xff), /* cmp $len,%edx */
+ 0x75, 0xe8, /* jne 13 <_doloop> */
+
+ /* Start kernel */
+ 0x31, 0xdb, /* xor %ebx,%ebx */
+ 0xb9, (dst&0xff), ((dst>>8)&0xff), ((dst>>16)&0xff), ((dst>>24)&0xff), /* mov $dst,%ecx */
+ 0xff, 0xe1, /* jmp *%ecx */
+ };
+ cpu_physical_memory_rw(addr, buf, sizeof(buf), 1);
+ fprintf(stderr, "qemu: helper at 0x%x of size %d bytes, to move kernel of %d bytes from 0x%x to 0x%x\n",
+ (int)addr, (int)sizeof(buf), (int)len, (int)src, (int)dst);
+}
+
+
+static void xen_relocator_hook(target_phys_addr_t *prot_addr_upd,
+ uint16_t protocol,
+ const uint8_t header[], int kernel_size,
+ target_phys_addr_t real_addr, int real_size)
+{
+ target_phys_addr_t prot_addr = *prot_addr_upd;
+
+ /* Urgh, Xen's HVM firmware lives at 0x100000, but that's also the
+ * address Linux wants to start life at prior to relocatable support
+ */
+ fprintf(stderr, "checking need for relocation, header protocol: %x\n",
+ protocol);
+
+ if (prot_addr != 0x10000) { /* old low kernels are OK */
+ target_phys_addr_t reloc_prot_addr = 0x200000;
+
+ if (protocol >= 0x205 && (header[0x234] & 1)) {
+ /* Relocatable automatically */
+ stl_phys(real_addr+0x214, reloc_prot_addr);
+ fprintf(stderr, "qemu: kernel is relocatable\n");
+ } else {
+ /* Setup a helper which moves kernel back to
+ * its expected addr after firmware has got out
+ * of the way. We put a helper at reloc_prot_addr+kernel_size.
+ * It moves kernel from reloc_prot_addr to prot_addr and
+ * then jumps to prot_addr. Yes this is sick.
+ */
+ fprintf(stderr, "qemu: kernel is NOT relocatable\n");
+ stl_phys(real_addr+0x214, reloc_prot_addr + kernel_size);
+ setup_relocator(reloc_prot_addr + kernel_size, reloc_prot_addr, prot_addr, kernel_size);
+ }
+ fprintf(stderr, "qemu: loading kernel protected mode (%x bytes) at %#zx\n",
+ kernel_size, (size_t)reloc_prot_addr);
+ fprintf(stderr, "qemu: loading kernel real mode (%x bytes) at %#zx\n",
+ real_size, (size_t)real_addr);
+ *prot_addr_upd = reloc_prot_addr;
+ }
+}
+
+#ifdef CONFIG_DM
+
+void vmport_init(void) { }
+int apic_init(CPUX86State *env) { return 0; }
+
+#endif /* CONFIG_DM */
DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len));
}
- while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
+ if (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
{
- free(s->cplus_txbuffer);
- s->cplus_txbuffer = NULL;
- s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
- s->cplus_txbuffer = qemu_realloc(s->cplus_txbuffer, s->cplus_txbuffer_len);
++ free(s->cplus_txbuffer);
++ s->cplus_txbuffer = NULL;
- DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space exceeded: %d\n", s->cplus_txbuffer_offset + txsize));
- DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len));
++ DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space exceeded: %d\n", s->cplus_txbuffer_offset + txsize));
}
if (!s->cplus_txbuffer)
s->cplus_txbuffer_len = 0;
s->cplus_txbuffer_offset = 0;
- register_savevm("rtl8139", -1, 3, rtl8139_save, rtl8139_load, s);
+ instance = pci_bus_num(bus) << 8 | s->pci_dev->devfn;
+ register_savevm("rtl8139", instance, 3, rtl8139_save, rtl8139_load, s);
- #if RTL8139_ONBOARD_TIMER
+ #ifdef RTL8139_ONBOARD_TIMER
s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s);
qemu_mod_timer(s->timer,
int kind;
int protocol;
int idle;
- int changed;
+ void *datain_opaque;
+ void (*datain)(void *);
} USBHIDState;
/* mostly the same values as the Bochs USB Mouse device */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
-static void usb_hid_changed(USBHIDState *hs)
++static void usb_notify_datain_cb(USBHIDState *hs)
+ {
- hs->changed = 1;
-
+ if (hs->datain)
+ hs->datain(hs->datain_opaque);
+ }
+
-static void usb_mouse_event(void *opaque,
- int dx1, int dy1, int dz1, int buttons_state)
-{
- USBHIDState *hs = opaque;
- USBMouseState *s = &hs->ptr;
-
- s->dx += dx1;
- s->dy += dy1;
- s->dz += dz1;
- s->buttons_state = buttons_state;
-
- usb_hid_changed(hs);
+static void usb_pointer_event_clear(USBPointerEvent *e, int buttons) {
+ e->xdx = e->ydy = e->dz = 0;
+ e->buttons_state = buttons;
}
-static void usb_tablet_event(void *opaque,
- int x, int y, int dz, int buttons_state)
-{
- USBHIDState *hs = opaque;
- USBMouseState *s = &hs->ptr;
+static void usb_pointer_event_combine(USBPointerEvent *e, int xyrel,
+ int x1, int y1, int z1) {
+ if (xyrel) {
+ e->xdx += x1;
+ e->ydy += y1;
+ } else {
+ e->xdx = x1;
+ e->ydy = y1;
+ }
+ e->dz += z1;
+}
- s->x = x;
- s->y = y;
- s->dz += dz;
- s->buttons_state = buttons_state;
+static void usb_pointer_event(void *hs_v, int x1, int y1, int z1,
+ int buttons_state) {
+ /* We combine events where feasible to keep the queue small.
+ * We shouldn't combine anything with the first event with
+ * a particular button state, as that would change the
+ * location of the button state change. */
+ USBHIDState *hs= hs_v;
+ USBPointerState *s = &hs->ptr;
+ unsigned use_slot= (s->tail-1) & QUEUEINDEXMASK;
+ unsigned previous_slot= (use_slot-1) & QUEUEINDEXMASK;
+
+ if (s->tail == s->head) {
+ use_slot= s->tail;
+ QUEUE_INCR(s->tail);
+ usb_pointer_event_clear(&s->queue[use_slot], buttons_state);
+ } else if (use_slot == s->head ||
+ s->queue[use_slot].buttons_state != buttons_state ||
+ s->queue[previous_slot].buttons_state != buttons_state) {
+ /* can't or shouldn't combine this event with previous one */
+ use_slot= s->tail;
+ QUEUE_INCR(s->tail);
+ if (use_slot == s->head) {
+ /* queue full, oh well, discard something */
+ s->head++; s->head &= QUEUEINDEXMASK;
+ /* but we preserve the relative motions */
+ usb_pointer_event_combine(&s->queue[s->head], s->xyrel,
+ s->queue[use_slot].xdx,
+ s->queue[use_slot].ydy,
+ s->queue[use_slot].dz);
+ }
+ usb_pointer_event_clear(&s->queue[use_slot], buttons_state);
+ }
+ usb_pointer_event_combine(&s->queue[use_slot],s->xyrel, x1,y1,z1);
+
- usb_hid_changed(hs);
++ usb_notify_datain_cb(hs);
}
static void usb_keyboard_event(void *opaque, int keycode)
hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
s->modifiers &= ~(1 << 8);
+ s->changed = 1;
++ usb_notify_datain_cb(hs);
+
switch (hid_code) {
case 0x00:
return;
if (s->key[i] == hid_code) {
s->key[i] = s->key[-- s->keys];
s->key[s->keys] = 0x00;
- return;
- usb_hid_changed(hs);
+ break;
}
+ if (i < 0)
+ return;
} else {
for (i = s->keys - 1; i >= 0; i --)
if (s->key[i] == hid_code)
- return;
- if (s->keys < sizeof(s->key))
- s->key[s->keys ++] = hid_code;
+ break;
+ if (i < 0) {
+ if (s->keys < sizeof(s->key))
+ s->key[s->keys ++] = hid_code;
+ } else
+ return;
}
-
- usb_hid_changed(hs);
}
static inline int int_clamp(int val, int vmin, int vmax)
s->mouse_grabbed = 1;
}
- dx = int_clamp(s->dx, -127, 127);
- dy = int_clamp(s->dy, -127, 127);
- dz = int_clamp(s->dz, -127, 127);
+ if (s->head == s->tail)
+ /* use the last report */
+ s->head = (s->head - 1) & QUEUEINDEXMASK;
+
+ e = &s->queue[s->head];
- dz = int_clamp(e->dz, -127, 127);
- s->dx -= dx;
- s->dy -= dy;
- s->dz -= dz;
++ dz = int_clamp(e->dz, -128, 127);
- dx = int_clamp(e->xdx, -127, 127);
- dy = int_clamp(e->ydy, -127, 127);
+ if (s->xyrel) {
++ dx = int_clamp(e->xdx, -128, 127);
++ dy = int_clamp(e->ydy, -128, 127);
+ e->xdx -= dx;
+ e->ydy -= dy;
+ } else {
+ dx = e->xdx;
+ dy = e->ydy;
+ }
/* Appears we have to invert the wheel direction */
dz = 0 - dz;
- b = 0;
- if (s->buttons_state & MOUSE_EVENT_LBUTTON)
- b |= 0x01;
- if (s->buttons_state & MOUSE_EVENT_RBUTTON)
- b |= 0x02;
- if (s->buttons_state & MOUSE_EVENT_MBUTTON)
- b |= 0x04;
-
- l = 0;
- if (len > l)
- buf[l ++] = b;
- if (len > l)
- buf[l ++] = dx;
- if (len > l)
- buf[l ++] = dy;
- if (len > l)
- buf[l ++] = dz;
- return l;
-}
-
-static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len)
-{
- int dz, b, l;
- USBMouseState *s = &hs->ptr;
-
- if (!s->mouse_grabbed) {
- s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs,
- 1, "QEMU USB Tablet");
- s->mouse_grabbed = 1;
+ if (!(e->dz ||
+ (s->xyrel && (e->xdx || e->ydy)))) {
+ /* that deals with this event */
+ QUEUE_INCR(s->head);
}
- dz = int_clamp(s->dz, -127, 127);
- s->dz -= dz;
-
+ /* Appears we have to invert the wheel direction */
+ dz = 0 - dz;
++
b = 0;
- if (s->buttons_state & MOUSE_EVENT_LBUTTON)
+ if (e->buttons_state & MOUSE_EVENT_LBUTTON)
b |= 0x01;
- if (s->buttons_state & MOUSE_EVENT_RBUTTON)
+ if (e->buttons_state & MOUSE_EVENT_RBUTTON)
b |= 0x02;
- if (s->buttons_state & MOUSE_EVENT_MBUTTON)
+ if (e->buttons_state & MOUSE_EVENT_MBUTTON)
b |= 0x04;
- buf[0] = b;
- buf[1] = s->x & 0xff;
- buf[2] = s->x >> 8;
- buf[3] = s->y & 0xff;
- buf[4] = s->y >> 8;
- buf[5] = dz;
- l = 6;
+ switch (hs->kind) {
+ case USB_MOUSE:
+ l = 0;
+ if (len > l)
+ buf[l ++] = b;
+ if (len > l)
+ buf[l ++] = dx;
+ if (len > l)
+ buf[l ++] = dy;
+ if (len > l)
+ buf[l ++] = dz;
+ break;
+
+ case USB_TABLET:
+ /* Appears we have to invert the wheel direction */
+ dz = 0 - dz;
+
+ buf[0] = b;
+ buf[1] = dx & 0xff;
+ buf[2] = dx >> 8;
+ buf[3] = dy & 0xff;
+ buf[4] = dy >> 8;
+ buf[5] = dz;
+ l = 6;
+ break;
+
+ default:
+ abort();
+ }
return l;
}
max_len = ((td->token >> 21) + 1) & 0x7ff;
pid = td->token & 0xff;
- if (completion && (s->async_qh || s->async_frame_addr)) {
- ret = s->usb_packet.len;
- if (ret >= 0) {
- len = ret;
- if (len > max_len) {
- len = max_len;
- ret = USB_RET_BABBLE;
- }
- if (len > 0) {
- /* write the data back */
- cpu_physical_memory_write(td->buffer, s->usb_buf, len);
- }
- } else {
- len = 0;
- }
- s->async_qh = 0;
- s->async_frame_addr = 0;
- } else if (!completion) {
- s->usb_packet.pid = pid;
- s->usb_packet.devaddr = (td->token >> 8) & 0x7f;
- s->usb_packet.devep = (td->token >> 15) & 0xf;
- s->usb_packet.data = s->usb_buf;
- s->usb_packet.len = max_len;
- s->usb_packet.complete_cb = uhci_async_complete_packet;
- s->usb_packet.complete_opaque = s;
- switch(pid) {
- case USB_TOKEN_OUT:
- case USB_TOKEN_SETUP:
- cpu_physical_memory_read(td->buffer, s->usb_buf, max_len);
- ret = uhci_broadcast_packet(s, &s->usb_packet);
- len = max_len;
- break;
- case USB_TOKEN_IN:
- ret = uhci_broadcast_packet(s, &s->usb_packet);
- if (ret >= 0) {
- len = ret;
- if (len > max_len) {
- len = max_len;
- ret = USB_RET_BABBLE;
- }
- if (len > 0) {
- /* write the data back */
- cpu_physical_memory_write(td->buffer, s->usb_buf, len);
- }
- } else {
- len = 0;
- }
- break;
- default:
- /* invalid pid : frame interrupted */
- s->status |= UHCI_STS_HCPERR;
- uhci_update_irq(s);
- ret = -1;
- goto out;
- }
- }
+ ret = async->packet.len;
- if (ret == USB_RET_ASYNC) {
- return 2;
- }
- if (td->ctrl & TD_CTRL_IOC)
- *int_mask |= 0x01;
-
if (td->ctrl & TD_CTRL_IOS)
td->ctrl &= ~TD_CTRL_ACTIVE;
- if (ret >= 0) {
- td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
- /* The NAK bit may have been set by a previous frame, so clear it
- here. The docs are somewhat unclear, but win2k relies on this
- behavior. */
- td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
- if (pid == USB_TOKEN_IN &&
- (td->ctrl & TD_CTRL_SPD) &&
- len < max_len) {
+
+ if (ret < 0)
+ goto out;
+
+ len = async->packet.len;
+ td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
+
+ /* The NAK bit may have been set by a previous frame, so clear it
+ here. The docs are somewhat unclear, but win2k relies on this
+ behavior. */
+ td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
+
+ if (pid == USB_TOKEN_IN) {
+ if (len > max_len) {
+ len = max_len;
+ ret = USB_RET_BABBLE;
+ goto out;
+ }
+
+ if (len > 0) {
+ /* write the data back */
+ cpu_physical_memory_write(td->buffer, async->buffer, len);
+ }
+
+ if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
*int_mask |= 0x02;
/* short packet: do not update QH */
- return 1;
+ dprintf("uhci: short packet. td 0x%x token 0x%x\n", async->td, async->token);
- goto out;
- } else {
- /* success */
- ret = 0;
- goto out;
+ ret = 1;
++ goto out_update_ioc;
}
- } else {
- switch(ret) {
- default:
- case USB_RET_NODEV:
- do_timeout:
- td->ctrl |= TD_CTRL_TIMEOUT;
- err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;
- if (err != 0) {
- err--;
- if (err == 0) {
- td->ctrl &= ~TD_CTRL_ACTIVE;
- s->status |= UHCI_STS_USBERR;
- uhci_update_irq(s);
- }
- }
- td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |
- (err << TD_CTRL_ERROR_SHIFT);
- ret = 1;
- goto out;
- case USB_RET_NAK:
- td->ctrl |= TD_CTRL_NAK;
- if (pid == USB_TOKEN_SETUP)
- goto do_timeout;
- ret = 1;
- goto out;
- case USB_RET_STALL:
- td->ctrl |= TD_CTRL_STALL;
- td->ctrl &= ~TD_CTRL_ACTIVE;
- ret = 1;
- goto out;
- case USB_RET_BABBLE:
- td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
+ }
+
+ /* success */
- return 0;
++ ret = 0;
++ goto out_update_ioc;
+
+ out:
+ switch(ret) {
+ case USB_RET_STALL:
+ td->ctrl |= TD_CTRL_STALL;
+ td->ctrl &= ~TD_CTRL_ACTIVE;
- return 1;
++ ret = 1;
++ goto out_update_ioc;
+
+ case USB_RET_BABBLE:
+ td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
+ td->ctrl &= ~TD_CTRL_ACTIVE;
+ /* frame interrupted */
- return -1;
++ ret = -1;
++ goto out_update_ioc;
+
+ case USB_RET_NAK:
+ td->ctrl |= TD_CTRL_NAK;
+ if (pid == USB_TOKEN_SETUP)
+ break;
- return 1;
++ ret = 1;
++ goto out_update_ioc;
+
+ case USB_RET_NODEV:
+ default:
+ break;
+ }
+
+ /* Retry the TD if error count is not zero */
+
+ td->ctrl |= TD_CTRL_TIMEOUT;
+ err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;
+ if (err != 0) {
+ err--;
+ if (err == 0) {
td->ctrl &= ~TD_CTRL_ACTIVE;
- /* frame interrupted */
- ret = -1;
- goto out;
+ s->status |= UHCI_STS_USBERR;
+ uhci_update_irq(s);
}
}
-
- out:
- /* If TD is inactive and IOC bit set to 1 then update int_mask */
- if ((td->ctrl & TD_CTRL_IOC) && (!(td->ctrl & TD_CTRL_ACTIVE))) {
+ td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |
+ (err << TD_CTRL_ERROR_SHIFT);
- return 1;
++ ret = 1;
++
++ out_update_ioc:
++ if ((td->ctrl & TD_CTRL_IOC) && !(td->ctrl &= ~TD_CTRL_ACTIVE))
+ *int_mask |= 0x01;
- }
+ return ret;
}
- static void uhci_async_complete_packet(USBPacket * packet, void *opaque)
+ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *int_mask)
+ {
+ UHCIAsync *async;
+ int len = 0, max_len;
+ uint8_t pid;
+
+ /* Is active ? */
+ if (!(td->ctrl & TD_CTRL_ACTIVE))
+ return 1;
+
+ async = uhci_async_find_td(s, addr, td->token);
+ if (async) {
+ /* Already submitted */
+ async->valid = 32;
+
+ if (!async->done)
+ return 1;
+
+ uhci_async_unlink(s, async);
+ goto done;
+ }
+
+ /* Allocate new packet */
+ async = uhci_async_alloc(s);
+ if (!async)
+ return 1;
+
+ async->valid = 10;
+ async->td = addr;
+ async->token = td->token;
+
+ max_len = ((td->token >> 21) + 1) & 0x7ff;
+ pid = td->token & 0xff;
+
+ async->packet.pid = pid;
+ async->packet.devaddr = (td->token >> 8) & 0x7f;
+ async->packet.devep = (td->token >> 15) & 0xf;
+ async->packet.data = async->buffer;
+ async->packet.len = max_len;
+ async->packet.complete_cb = uhci_async_complete;
+ async->packet.complete_opaque = s;
+
+ switch(pid) {
+ case USB_TOKEN_OUT:
+ case USB_TOKEN_SETUP:
+ cpu_physical_memory_read(td->buffer, async->buffer, max_len);
+ len = uhci_broadcast_packet(s, &async->packet);
+ if (len >= 0)
+ len = max_len;
+ break;
+
+ case USB_TOKEN_IN:
+ len = uhci_broadcast_packet(s, &async->packet);
+ break;
+
+ default:
+ /* invalid pid : frame interrupted */
+ uhci_async_free(s, async);
+ s->status |= UHCI_STS_HCPERR;
+ uhci_update_irq(s);
+ return -1;
+ }
+
+ if (len == USB_RET_ASYNC) {
+ uhci_async_link(s, async);
+ return 2;
+ }
+
+ async->packet.len = len;
+
+ done:
+ len = uhci_complete_td(s, td, async, int_mask);
+ uhci_async_free(s, async);
+ return len;
+ }
+
+ static void uhci_async_complete(USBPacket *packet, void *opaque)
{
UHCIState *s = opaque;
- UHCI_QH qh;
+ UHCIAsync *async = (UHCIAsync *) packet;
+
+ dprintf("uhci: async complete. td 0x%x token 0x%x\n", async->td, async->token);
+
+ async->done = 1;
+
+ uhci_process_frame(s);
+ }
+
+ static int is_valid(uint32_t link)
+ {
+ return (link & 1) == 0;
+ }
+
+ static int is_qh(uint32_t link)
+ {
+ return (link & 2) != 0;
+ }
+
+ static int depth_first(uint32_t link)
+ {
+ return (link & 4) != 0;
+ }
+
+ /* QH DB used for detecting QH loops */
+ #define UHCI_MAX_QUEUES 128
+ typedef struct {
+ uint32_t addr[UHCI_MAX_QUEUES];
+ int count;
+ } QhDb;
+
+ static void qhdb_reset(QhDb *db)
+ {
+ db->count = 0;
+ }
+
+ /* Add QH to DB. Returns 1 if already present or DB is full. */
+ static int qhdb_insert(QhDb *db, uint32_t addr)
+ {
+ int i;
+ for (i = 0; i < db->count; i++)
+ if (db->addr[i] == addr)
+ return 1;
+
+ if (db->count >= UHCI_MAX_QUEUES)
+ return 1;
+
+ db->addr[db->count++] = addr;
+ return 0;
+ }
+
+ static void uhci_process_frame(UHCIState *s)
+ {
+ uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
+ uint32_t curr_qh;
+ int cnt, ret;
UHCI_TD td;
- uint32_t link;
- uint32_t old_td_ctrl;
- uint32_t val;
- uint32_t frame_addr;
- int ret;
+ UHCI_QH qh;
+ QhDb qhdb;
+
+ frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);
+
+ dprintf("uhci: processing frame %d addr 0x%x\n" , s->frnum, frame_addr);
+
+ cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4);
+ le32_to_cpus(&link);
+
+ int_mask = 0;
+ curr_qh = 0;
+
+ qhdb_reset(&qhdb);
+
+ for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) {
+ if (is_qh(link)) {
+ /* QH */
+
+ if (qhdb_insert(&qhdb, link)) {
+ /*
+ * We're going in circles. Which is not a bug because
+ * HCD is allowed to do that as part of the BW management.
+ * In our case though it makes no sense to spin here. Sync transations
+ * are already done, and async completion handler will re-process
+ * the frame when something is ready.
+ */
+ dprintf("uhci: detected loop. qh 0x%x\n", link);
+ break;
+ }
+
+ cpu_physical_memory_read(link & ~0xf, (uint8_t *) &qh, sizeof(qh));
+ le32_to_cpus(&qh.link);
+ le32_to_cpus(&qh.el_link);
- /* Handle async isochronous packet completion */
- frame_addr = s->async_frame_addr;
- if (frame_addr) {
- cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4);
- le32_to_cpus(&link);
+ dprintf("uhci: QH 0x%x load. link 0x%x elink 0x%x\n",
+ link, qh.link, qh.el_link);
- cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td));
+ if (!is_valid(qh.el_link)) {
+ /* QH w/o elements */
+ curr_qh = 0;
+ link = qh.link;
+ } else {
+ /* QH with elements */
+ curr_qh = link;
+ link = qh.el_link;
+ }
+ continue;
+ }
+
+ /* TD */
+ cpu_physical_memory_read(link & ~0xf, (uint8_t *) &td, sizeof(td));
le32_to_cpus(&td.link);
le32_to_cpus(&td.ctrl);
le32_to_cpus(&td.token);
#include "pc.h"
#include "pci.h"
#include "vga_int.h"
-#include "pixel_ops.h"
++//<<<<<<< HEAD/hw/vga.c
+#include <sys/mman.h>
+#include "sysemu.h"
+#include "qemu-xen.h"
+#include "exec-all.h"
++//=======
++//#include "pixel_ops.h"
+ #include "qemu-timer.h"
++//>>>>>>> 3df1a17b0ab8a8be4e3c9d6b2fa0812c652520f1/hw/vga.c
//#define DEBUG_VGA
//#define DEBUG_VGA_MEM
s->get_bpp = vga_get_bpp;
s->get_offsets = vga_get_offsets;
s->get_resolution = vga_get_resolution;
- s->update = vga_update_display;
- s->invalidate = vga_invalidate_display;
- s->screen_dump = vga_screen_dump;
- s->text_update = vga_update_text;
+ graphic_console_init(s->ds, vga_update_display, vga_invalidate_display,
- vga_screen_dump, NULL, s);
++ vga_screen_dump, vga_update_text, s);
+
+ vga_bios_init(s);
+ switch (vga_retrace_method) {
+ case VGA_RETRACE_DUMB:
+ s->retrace = vga_dumb_retrace;
+ s->update_retrace_info = vga_dumb_update_retrace_info;
+ break;
+
+ case VGA_RETRACE_PRECISE:
+ s->retrace = vga_precise_retrace;
+ s->update_retrace_info = vga_precise_update_retrace_info;
+ memset(&s->retrace_info, 0, sizeof (s->retrace_info));
+ break;
+ }
}
/* used by both ISA and PCI */
#define CH_ATTR_SIZE (160 * 100)
#define VGA_MAX_HEIGHT 2048
+ struct vga_precise_retrace {
+ int64_t ticks_per_char;
+ int64_t total_chars;
+ int htotal;
+ int hstart;
+ int hend;
+ int vstart;
+ int vend;
+ int freq;
+ };
+
+ union vga_retrace {
+ struct vga_precise_retrace precise;
+ };
+
+ struct VGAState;
+ typedef uint8_t (* vga_retrace_fn)(struct VGAState *s);
+ typedef void (* vga_update_retrace_info_fn)(struct VGAState *s);
+
#define VGA_STATE_COMMON \
uint8_t *vram_ptr; \
+ xen_pfn_t *vram_mfns; \
+ uint64_t stolen_vram_addr; /* Address of stolen RAM */ \
unsigned long vram_offset; \
unsigned int vram_size; \
unsigned long bios_offset; \
--- /dev/null
- int interrupt_request;
-
+/*
+ * i386 virtual CPU header
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef CPU_I386_H
+#define CPU_I386_H
+
+#include "config.h"
+
+struct CPUX86State;
+
+#ifdef TARGET_X86_64
+#define TARGET_LONG_BITS 64
+#else
+/* #define TARGET_LONG_BITS 32 */
+#define TARGET_LONG_BITS 64 /* for Qemu map cache */
+#endif
+
+/* target supports implicit self modifying code */
+#define TARGET_HAS_SMC
+/* support for self modifying code even if the modified instruction is
+ close to the modifying instruction */
+#define TARGET_HAS_PRECISE_SMC
+
+/* MMU modes definitions
+ */
+/* We aren't handling the MMU in Qemu; all the addresses we deal with
+ * are guest physical. So as far as qemu
+ * is concerned there is only the one MMU mode.
+ */
+#define NB_MMU_MODES 1
+#define MMU_MODE0_SUFFIX _xen
+static inline int cpu_mmu_index(struct CPUX86State *env) { return 0; }
+
+#include "cpu-defs.h"
+
+#ifdef CONFIG_SOFTFLOAT
+#include "softfloat.h"
+#endif
+
+#if defined(__i386__) && !defined(CONFIG_SOFTMMU)
+#define USE_CODE_COPY
+#endif
+
+#ifdef CONFIG_SOFTFLOAT
+#ifdef USE_X86LDOUBLE
+typedef floatx80 CPU86_LDouble;
+#else
+typedef float64 CPU86_LDouble;
+#endif
+#endif
+
+typedef struct SegmentCache {
+ uint32_t selector;
+ target_ulong base;
+ uint32_t limit;
+ uint32_t flags;
+} SegmentCache;
+
+/* Empty for now */
+typedef struct CPUX86State {
+ uint32_t a20_mask;
+
+ CPU_COMMON
+} CPUX86State;
+
+CPUX86State *cpu_x86_init(const char *cpu_model);
+int cpu_x86_exec(CPUX86State *s);
+void cpu_x86_close(CPUX86State *s);
+int cpu_get_pic_interrupt(CPUX86State *s);
+/* MSDOS compatibility mode FPU exception support */
+void cpu_set_ferr(CPUX86State *s);
+
+void cpu_x86_set_a20(CPUX86State *env, int a20_state);
+
+/* used to debug */
+#define X86_DUMP_FPU 0x0001 /* dump FPU state too */
+#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */
+
+#ifndef IN_OP_I386
+void cpu_x86_outb(CPUX86State *env, int addr, int val);
+void cpu_x86_outw(CPUX86State *env, int addr, int val);
+void cpu_x86_outl(CPUX86State *env, int addr, int val);
+int cpu_x86_inb(CPUX86State *env, int addr);
+int cpu_x86_inw(CPUX86State *env, int addr);
+int cpu_x86_inl(CPUX86State *env, int addr);
+#endif
+
+/* helper2.c */
+int main_loop(void);
+
+#if defined(__i386__) || defined(__x86_64__)
+#define TARGET_PAGE_BITS 12
+#elif defined(__ia64__)
+#define TARGET_PAGE_BITS 14
+#endif
+
+#define CPUState CPUX86State
+#define cpu_init cpu_x86_init
+#define cpu_exec cpu_x86_exec
+#define cpu_gen_code cpu_x86_gen_code
+#define cpu_signal_handler cpu_x86_signal_handler
+
+#include "cpu-all.h"
+
+#endif /* CPU_I386_H */
--- /dev/null
- ram_addr_t ram_size;
+/*
+ * virtual page mapping and translated block handling
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "config.h"
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/types.h>
+#include <sys/mman.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "hw.h"
+#include "qemu-xen.h"
+
+//#define DEBUG_TB_INVALIDATE
+//#define DEBUG_FLUSH
+//#define DEBUG_TLB
+
+/* make various TB consistency checks */
+//#define DEBUG_TB_CHECK
+//#define DEBUG_TLB_CHECK
+
+#ifndef CONFIG_DM
+/* threshold to flush the translated code buffer */
+#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
+
+#define SMC_BITMAP_USE_THRESHOLD 10
+
+#define MMAP_AREA_START 0x00000000
+#define MMAP_AREA_END 0xa8000000
+
+TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
+TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
+TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
+int nb_tbs;
+/* any access to the tbs or the page table must use this lock */
+spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
+
+uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
+uint8_t *code_gen_ptr;
+#endif /* !CONFIG_DM */
+
++int use_icount = 0;
++int64_t qemu_icount;
+ram_addr_t phys_ram_size;
- CPULogItem cpu_log_items[] = {
+int phys_ram_fd;
+uint8_t *phys_ram_base;
+uint8_t *phys_ram_dirty;
+
+CPUState *first_cpu;
+/* current CPU in the current thread. It is only valid inside
+ cpu_exec() */
+CPUState *cpu_single_env;
+
+typedef struct PageDesc {
+ /* list of TBs intersecting this ram page */
+ TranslationBlock *first_tb;
+ /* in order to optimize self modifying code, we count the number
+ of lookups we do to a given page to use a bitmap */
+ unsigned int code_write_count;
+ uint8_t *code_bitmap;
+#if defined(CONFIG_USER_ONLY)
+ unsigned long flags;
+#endif
+} PageDesc;
+
+typedef struct PhysPageDesc {
+ /* offset in host memory of the page + io_index in the low 12 bits */
+ unsigned long phys_offset;
+} PhysPageDesc;
+
+typedef struct VirtPageDesc {
+ /* physical address of code page. It is valid only if 'valid_tag'
+ matches 'virt_valid_tag' */
+ target_ulong phys_addr;
+ unsigned int valid_tag;
+#if !defined(CONFIG_SOFTMMU)
+ /* original page access rights. It is valid only if 'valid_tag'
+ matches 'virt_valid_tag' */
+ unsigned int prot;
+#endif
+} VirtPageDesc;
+
+#define L2_BITS 10
+#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
+
+#define L1_SIZE (1 << L1_BITS)
+#define L2_SIZE (1 << L2_BITS)
+
+unsigned long qemu_real_host_page_size;
+unsigned long qemu_host_page_bits;
+unsigned long qemu_host_page_size;
+unsigned long qemu_host_page_mask;
+
+/* io memory support */
+CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
+CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+void *io_mem_opaque[IO_MEM_NB_ENTRIES];
+static int io_mem_nb = 1;
+
+/* log support */
+FILE *logfile;
+int loglevel;
+
++void cpu_exec_init_all(unsigned long tb_size)
++{
++}
++
+void cpu_exec_init(CPUState *env)
+{
+ CPUState **penv;
+ int cpu_index;
+
+ env->next_cpu = NULL;
+ penv = &first_cpu;
+ cpu_index = 0;
+ while (*penv != NULL) {
+ penv = (CPUState **)&(*penv)->next_cpu;
+ cpu_index++;
+ }
+ env->cpu_index = cpu_index;
+ *penv = env;
+
+ /* alloc dirty bits array */
+ phys_ram_dirty = qemu_malloc(phys_ram_size >> TARGET_PAGE_BITS);
+}
+
+/* enable or disable low levels log */
+void cpu_set_log(int log_flags)
+{
+ loglevel = log_flags;
+ if (!logfile)
+ logfile = stderr;
+}
+
+void cpu_set_log_filename(const char *filename)
+{
+ logfile = fopen(filename, "w");
+ if (!logfile) {
+ perror(filename);
+ _exit(1);
+ }
+#if !defined(CONFIG_SOFTMMU)
+ /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
+ {
+ static uint8_t logfile_buf[4096];
+ setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
+ }
+#else
+ setvbuf(logfile, NULL, _IOLBF, 0);
+#endif
+ dup2(fileno(logfile), 1);
+ dup2(fileno(logfile), 2);
+}
+
+/* mask must never be zero, except for A20 change call */
+void cpu_interrupt(CPUState *env, int mask)
+{
+ env->interrupt_request |= mask;
+}
+
+void cpu_reset_interrupt(CPUState *env, int mask)
+{
+ env->interrupt_request &= ~mask;
+}
+
- CPULogItem *item;
++const CPULogItem cpu_log_items[] = {
+ { CPU_LOG_TB_OUT_ASM, "out_asm",
+ "show generated host assembly code for each compiled TB" },
+ { CPU_LOG_TB_IN_ASM, "in_asm",
+ "show target assembly code for each compiled TB" },
+ { CPU_LOG_TB_OP, "op",
+ "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
+#ifdef TARGET_I386
+ { CPU_LOG_TB_OP_OPT, "op_opt",
+ "show micro ops after optimization for each compiled TB" },
+#endif
+ { CPU_LOG_INT, "int",
+ "show interrupts/exceptions in short format" },
+ { CPU_LOG_EXEC, "exec",
+ "show trace before each executed TB (lots of logs)" },
+ { CPU_LOG_TB_CPU, "cpu",
+ "show CPU state before bloc translation" },
+#ifdef TARGET_I386
+ { CPU_LOG_PCALL, "pcall",
+ "show protected mode far calls/returns/exceptions" },
+#endif
+#ifdef DEBUG_IOPORT
+ { CPU_LOG_IOPORT, "ioport",
+ "show all i/o ports accesses" },
+#endif
+ { 0, NULL, NULL },
+};
+
+static int cmp1(const char *s1, int n, const char *s2)
+{
+ if (strlen(s2) != n)
+ return 0;
+ return memcmp(s1, s2, n) == 0;
+}
+
+/* takes a comma separated list of log masks. Return 0 if error. */
+int cpu_str_to_log_mask(const char *str)
+{
++ const CPULogItem *item;
+ int mask;
+ const char *p, *p1;
+
+ p = str;
+ mask = 0;
+ for(;;) {
+ p1 = strchr(p, ',');
+ if (!p1)
+ p1 = p + strlen(p);
+ if(cmp1(p,p1-p,"all")) {
+ for(item = cpu_log_items; item->mask != 0; item++) {
+ mask |= item->mask;
+ }
+ } else {
+ for(item = cpu_log_items; item->mask != 0; item++) {
+ if (cmp1(p, p1 - p, item->name))
+ goto found;
+ }
+ return 0;
+ }
+ found:
+ mask |= item->mask;
+ if (*p1 != ',')
+ break;
+ p = p1 + 1;
+ }
+ return mask;
+}
+
+void cpu_abort(CPUState *env, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "qemu: fatal: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ abort();
+}
+
+
+/* XXX: Simple implementation. Fix later */
+#define MAX_MMIO 32
+struct mmio_space {
+ target_phys_addr_t start;
+ unsigned long size;
+ unsigned long io_index;
+} mmio[MAX_MMIO];
+unsigned long mmio_cnt;
+
+/* register physical memory. 'size' must be a multiple of the target
+ page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
+ io memory page */
+void cpu_register_physical_memory(target_phys_addr_t start_addr,
+ unsigned long size,
+ unsigned long phys_offset)
+{
+ int i;
+
+ for (i = 0; i < mmio_cnt; i++) {
+ if(mmio[i].start == start_addr) {
+ mmio[i].io_index = phys_offset;
+ mmio[i].size = size;
+ return;
+ }
+ }
+
+ if (mmio_cnt == MAX_MMIO) {
+ fprintf(logfile, "too many mmio regions\n");
+ exit(-1);
+ }
+
+ mmio[mmio_cnt].io_index = phys_offset;
+ mmio[mmio_cnt].start = start_addr;
+ mmio[mmio_cnt++].size = size;
+}
+
+/* mem_read and mem_write are arrays of functions containing the
+ function to access byte (index 0), word (index 1) and dword (index
+ 2). All functions must be supplied. If io_index is non zero, the
+ corresponding io zone is modified. If it is zero, a new io zone is
+ allocated. The return value can be used with
+ cpu_register_physical_memory(). (-1) is returned if error. */
+int cpu_register_io_memory(int io_index,
+ CPUReadMemoryFunc **mem_read,
+ CPUWriteMemoryFunc **mem_write,
+ void *opaque)
+{
+ int i;
+
+ if (io_index <= 0) {
+ if (io_index >= IO_MEM_NB_ENTRIES)
+ return -1;
+ io_index = io_mem_nb++;
+ } else {
+ if (io_index >= IO_MEM_NB_ENTRIES)
+ return -1;
+ }
+
+ for(i = 0;i < 3; i++) {
+ io_mem_read[io_index][i] = mem_read[i];
+ io_mem_write[io_index][i] = mem_write[i];
+ }
+ io_mem_opaque[io_index] = opaque;
+ return io_index << IO_MEM_SHIFT;
+}
+
+CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
+{
+ return io_mem_write[io_index >> IO_MEM_SHIFT];
+}
+
+CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
+{
+ return io_mem_read[io_index >> IO_MEM_SHIFT];
+}
+
+#ifdef __ia64__
+
+#define __ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory")
+#define ia64_sync_i() asm volatile (";; sync.i" ::: "memory")
+#define ia64_srlz_i() asm volatile (";; srlz.i ;;" ::: "memory")
+
+/* IA64 has seperate I/D cache, with coherence maintained by DMA controller.
+ * So to emulate right behavior that guest OS is assumed, we need to flush
+ * I/D cache here.
+ */
+static void sync_icache(uint8_t *address, int len)
+{
+ unsigned long addr = (unsigned long)address;
+ unsigned long end = addr + len;
+
+ for (addr &= ~(32UL-1); addr < end; addr += 32UL)
+ __ia64_fc(addr);
+
+ ia64_sync_i();
+ ia64_srlz_i();
+}
+#endif
+
+/* physical memory access (slow version, mainly for debug) */
+#if defined(CONFIG_USER_ONLY)
+void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
+ int len, int is_write)
+{
+ int l, flags;
+ target_ulong page;
+
+ while (len > 0) {
+ page = addr & TARGET_PAGE_MASK;
+ l = (page + TARGET_PAGE_SIZE) - addr;
+ if (l > len)
+ l = len;
+ flags = page_get_flags(page);
+ if (!(flags & PAGE_VALID))
+ return;
+ if (is_write) {
+ if (!(flags & PAGE_WRITE))
+ return;
+ memcpy((uint8_t *)addr, buf, len);
+ } else {
+ if (!(flags & PAGE_READ))
+ return;
+ memcpy(buf, (uint8_t *)addr, len);
+ }
+ len -= l;
+ buf += l;
+ addr += l;
+ }
+}
+#else
+
+int iomem_index(target_phys_addr_t addr)
+{
+ int i;
+
+ for (i = 0; i < mmio_cnt; i++) {
+ unsigned long start, end;
+
+ start = mmio[i].start;
+ end = mmio[i].start + mmio[i].size;
+
+ if ((addr >= start) && (addr < end)){
+ return (mmio[i].io_index >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+ }
+ }
+ return 0;
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+#define phys_ram_addr(x) (qemu_map_cache(x))
+#elif defined(__ia64__)
+#define phys_ram_addr(x) (((x) < ram_size) ? (phys_ram_base + (x)) : NULL)
+#endif
+
+unsigned long *logdirty_bitmap;
+unsigned long logdirty_bitmap_size;
+
+/*
+ * Replace the standard byte memcpy with a word memcpy for appropriately sized
+ * memory copy operations. Some users (USB-UHCI) can not tolerate the possible
+ * word tearing that can result from a guest concurrently writing a memory
+ * structure while the qemu device model is modifying the same location.
+ * Forcing a word-sized read/write prevents the guest from seeing a partially
+ * written word-sized atom.
+ */
+#if defined(__x86_64__) || defined(__i386__)
+static void memcpy_words(void *dst, void *src, size_t n)
+{
+ asm volatile (
+ " movl %%edx,%%ecx \n"
+#ifdef __x86_64__
+ " shrl $3,%%ecx \n"
+ " rep movsq \n"
+ " test $4,%%edx \n"
+ " jz 1f \n"
+ " movsl \n"
+#else /* __i386__ */
+ " shrl $2,%%ecx \n"
+ " rep movsl \n"
+#endif
+ "1: test $2,%%edx \n"
+ " jz 1f \n"
+ " movsw \n"
+ "1: test $1,%%edx \n"
+ " jz 1f \n"
+ " movsb \n"
+ "1: \n"
+ : "+S" (src), "+D" (dst) : "d" (n) : "ecx", "memory" );
+}
+#else
+static void memcpy_words(void *dst, void *src, size_t n)
+{
+ /* Some architectures do not like unaligned accesses. */
+ if (((unsigned long)dst | (unsigned long)src) & 3) {
+ memcpy(dst, src, n);
+ return;
+ }
+
+ while (n >= sizeof(uint32_t)) {
+ *((uint32_t *)dst) = *((uint32_t *)src);
+ dst = ((uint32_t *)dst) + 1;
+ src = ((uint32_t *)src) + 1;
+ n -= sizeof(uint32_t);
+ }
+
+ if (n & 2) {
+ *((uint16_t *)dst) = *((uint16_t *)src);
+ dst = ((uint16_t *)dst) + 1;
+ src = ((uint16_t *)src) + 1;
+ }
+
+ if (n & 1) {
+ *((uint8_t *)dst) = *((uint8_t *)src);
+ dst = ((uint8_t *)dst) + 1;
+ src = ((uint8_t *)src) + 1;
+ }
+}
+#endif
+
+void cpu_physical_memory_rw(target_phys_addr_t _addr, uint8_t *buf,
+ int _len, int is_write)
+{
+ target_phys_addr_t addr = _addr;
+ int len = _len;
+ int l, io_index;
+ uint8_t *ptr;
+ uint32_t val;
+
+ mapcache_lock();
+
+ while (len > 0) {
+ /* How much can we copy before the next page boundary? */
+ l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK);
+ if (l > len)
+ l = len;
+
+ io_index = iomem_index(addr);
+ if (is_write) {
+ if (io_index) {
+ if (l >= 4 && ((addr & 3) == 0)) {
+ /* 32 bit read access */
+ val = ldl_raw(buf);
+ io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+ l = 4;
+ } else if (l >= 2 && ((addr & 1) == 0)) {
+ /* 16 bit read access */
+ val = lduw_raw(buf);
+ io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
+ l = 2;
+ } else {
+ /* 8 bit access */
+ val = ldub_raw(buf);
+ io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
+ l = 1;
+ }
+ } else if ((ptr = phys_ram_addr(addr)) != NULL) {
+ /* Writing to RAM */
+ memcpy_words(ptr, buf, l);
+#ifndef CONFIG_STUBDOM
+ if (logdirty_bitmap != NULL) {
+ /* Record that we have dirtied this frame */
+ unsigned long pfn = addr >> TARGET_PAGE_BITS;
+ if (pfn / 8 >= logdirty_bitmap_size) {
+ fprintf(logfile, "dirtying pfn %lx >= bitmap "
+ "size %lx\n", pfn, logdirty_bitmap_size * 8);
+ } else {
+ logdirty_bitmap[pfn / HOST_LONG_BITS]
+ |= 1UL << pfn % HOST_LONG_BITS;
+ }
+ }
+#endif
+#ifdef __ia64__
+ sync_icache(ptr, l);
+#endif
+ }
+ } else {
+ if (io_index) {
+ if (l >= 4 && ((addr & 3) == 0)) {
+ /* 32 bit read access */
+ val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+ stl_raw(buf, val);
+ l = 4;
+ } else if (l >= 2 && ((addr & 1) == 0)) {
+ /* 16 bit read access */
+ val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
+ stw_raw(buf, val);
+ l = 2;
+ } else {
+ /* 8 bit access */
+ val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
+ stb_raw(buf, val);
+ l = 1;
+ }
+ } else if ((ptr = phys_ram_addr(addr)) != NULL) {
+ /* Reading from RAM */
+ memcpy_words(buf, ptr, l);
+ } else {
+ /* Neither RAM nor known MMIO space */
+ memset(buf, 0xff, len);
+ }
+ }
+ len -= l;
+ buf += l;
+ addr += l;
+ }
+
+#ifdef CONFIG_STUBDOM
+ if (logdirty_bitmap != NULL)
+ xc_hvm_modified_memory(xc_handle, domid, _addr >> TARGET_PAGE_BITS,
+ ((_addr + _len + TARGET_PAGE_SIZE - 1) >> TARGET_PAGE_BITS)
+ - (_addr >> TARGET_PAGE_BITS));
+#endif
+
+ mapcache_unlock();
+}
+#endif
+
+/* virtual memory access for debug */
+int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
+ uint8_t *buf, int len, int is_write)
+{
+ int l;
+ target_ulong page, phys_addr;
+
+ while (len > 0) {
+ page = addr & TARGET_PAGE_MASK;
+ phys_addr = cpu_get_phys_page_debug(env, page);
+ /* if no physical page mapped, return an error */
+ if (phys_addr == -1)
+ return -1;
+ l = (page + TARGET_PAGE_SIZE) - addr;
+ if (l > len)
+ l = len;
+ cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
+ buf, l, is_write);
+ len -= l;
+ buf += l;
+ addr += l;
+ }
+ return 0;
+}
+
+void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
+ int dirty_flags)
+{
+ unsigned long length;
+ int i, mask, len;
+ uint8_t *p;
+
+ start &= TARGET_PAGE_MASK;
+ end = TARGET_PAGE_ALIGN(end);
+
+ length = end - start;
+ if (length == 0)
+ return;
+ mask = ~dirty_flags;
+ p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
+ len = length >> TARGET_PAGE_BITS;
+ for(i = 0; i < len; i++)
+ p[i] &= mask;
+
+ return;
+}
+
+
+/* Unoptimised in Xen DM, nicked from git
+ * aab33094073678d459ccaac5c60ea7533e8d1d8e */
+uint32_t ldub_phys(target_phys_addr_t addr)
+{
+ uint8_t val;
+ cpu_physical_memory_read(addr, &val, 1);
+ return val;
+}
+uint32_t lduw_phys(target_phys_addr_t addr)
+{
+ uint16_t val;
+ cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
+ return tswap16(val);
+}
+uint64_t ldq_phys(target_phys_addr_t addr)
+{
+ uint64_t val;
+ cpu_physical_memory_read(addr, (uint8_t *)&val, 8);
+ return tswap64(val);
+}
+void stb_phys(target_phys_addr_t addr, uint32_t val)
+{
+ uint8_t v = val;
+ cpu_physical_memory_write(addr, &v, 1);
+}
+void stw_phys(target_phys_addr_t addr, uint32_t val)
+{
+ uint16_t v = tswap16(val);
+ cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
+}
+void stq_phys(target_phys_addr_t addr, uint64_t val)
+{
+ val = tswap64(val);
+ cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
+}
+
+/* stubs which we hope (think!) are OK for Xen DM */
+void stl_phys(target_phys_addr_t addr, uint32_t val)
+{
+ val = tswap32(val);
+ cpu_physical_memory_write(addr, (const uint8_t *)&val, 4);
+}
+void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
+{
+ stl_phys(addr, val);
+}
+uint32_t ldl_phys(target_phys_addr_t addr)
+{
+ uint32_t val;
+ cpu_physical_memory_read(addr, (uint8_t *)&val, 4);
+ return tswap32(val);
+}
+
+void cpu_physical_memory_write_rom(target_phys_addr_t addr,
+ const uint8_t *buf, int len) {
+ return cpu_physical_memory_write(addr,buf,len);
+}
+
+/* stub out various functions for Xen DM */
+void dump_exec_info(FILE *f,
+ int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) {
+}
+void monitor_disas(CPUState *env,
+ target_ulong pc, int nb_insn, int is_physical, int flags) {
+}
+void irq_info(void) { }
+void pic_info(void) { }
--- /dev/null
- BAD_LIBOBJS += translate-all.o
+
+BAD_LIBOBJS += exec.o cpu-exec.o tcg%.o translate.o host-utils.o
++BAD_LIBOBJS += translate-all.o op_helper.o
+BAD_LIBOBJS += fpu/%.o helper.o disas.o
+
+LIBOBJS := $(filter-out $(BAD_LIBOBJS), $(LIBOBJS))
//#define DEBUG
//#define DEBUG_COMPLETION
- #ifndef offsetof
- #define offsetof(type, field) ((size_t) &((type *)0)->field)
- #endif
++#undef TARGET_I386
+
/*
* Supported types:
*
--- /dev/null
+ /*
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ /* Locking primitives. Most of this code should be redundant -
+ system emulation doesn't need/use locking, NPTL userspace uses
+ pthread mutexes, and non-NPTL userspace isn't threadsafe anyway.
+ In either case a spinlock is probably the wrong kind of lock.
+ Spinlocks are only good if you know annother CPU has the lock and is
+ likely to release it soon. In environments where you have more threads
+ than physical CPUs (the extreme case being a single CPU host) a spinlock
+ simply wastes CPU until the OS decides to preempt it. */
+ #if defined(USE_NPTL)
+
+ #include <pthread.h>
+ #define spin_lock pthread_mutex_lock
+ #define spin_unlock pthread_mutex_unlock
+ #define spinlock_t pthread_mutex_t
+ #define SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER
+
++#elif defined(CONFIG_STUBDOM)
++
++#include <spinlock.h>
++
+ #else
+
+ #if defined(__hppa__)
+
+ typedef int spinlock_t[4];
+
+ #define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 }
+
+ static inline void resetlock (spinlock_t *p)
+ {
+ (*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1;
+ }
+
+ #else
+
+ typedef int spinlock_t;
+
+ #define SPIN_LOCK_UNLOCKED 0
+
+ static inline void resetlock (spinlock_t *p)
+ {
+ *p = SPIN_LOCK_UNLOCKED;
+ }
+
+ #endif
+
+ #if defined(__powerpc__)
+ static inline int testandset (int *p)
+ {
+ int ret;
+ __asm__ __volatile__ (
+ "0: lwarx %0,0,%1\n"
+ " xor. %0,%3,%0\n"
+ " bne 1f\n"
+ " stwcx. %2,0,%1\n"
+ " bne- 0b\n"
+ "1: "
+ : "=&r" (ret)
+ : "r" (p), "r" (1), "r" (0)
+ : "cr0", "memory");
+ return ret;
+ }
+ #elif defined(__i386__)
+ static inline int testandset (int *p)
+ {
+ long int readval = 0;
+
+ __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
+ : "+m" (*p), "+a" (readval)
+ : "r" (1)
+ : "cc");
+ return readval;
+ }
+ #elif defined(__x86_64__)
+ static inline int testandset (int *p)
+ {
+ long int readval = 0;
+
+ __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
+ : "+m" (*p), "+a" (readval)
+ : "r" (1)
+ : "cc");
+ return readval;
+ }
+ #elif defined(__s390__)
+ static inline int testandset (int *p)
+ {
+ int ret;
+
+ __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
+ " jl 0b"
+ : "=&d" (ret)
+ : "r" (1), "a" (p), "0" (*p)
+ : "cc", "memory" );
+ return ret;
+ }
+ #elif defined(__alpha__)
+ static inline int testandset (int *p)
+ {
+ int ret;
+ unsigned long one;
+
+ __asm__ __volatile__ ("0: mov 1,%2\n"
+ " ldl_l %0,%1\n"
+ " stl_c %2,%1\n"
+ " beq %2,1f\n"
+ ".subsection 2\n"
+ "1: br 0b\n"
+ ".previous"
+ : "=r" (ret), "=m" (*p), "=r" (one)
+ : "m" (*p));
+ return ret;
+ }
+ #elif defined(__sparc__)
+ static inline int testandset (int *p)
+ {
+ int ret;
+
+ __asm__ __volatile__("ldstub [%1], %0"
+ : "=r" (ret)
+ : "r" (p)
+ : "memory");
+
+ return (ret ? 1 : 0);
+ }
+ #elif defined(__arm__)
+ static inline int testandset (int *spinlock)
+ {
+ register unsigned int ret;
+ __asm__ __volatile__("swp %0, %1, [%2]"
+ : "=r"(ret)
+ : "0"(1), "r"(spinlock));
+
+ return ret;
+ }
+ #elif defined(__mc68000)
+ static inline int testandset (int *p)
+ {
+ char ret;
+ __asm__ __volatile__("tas %1; sne %0"
+ : "=r" (ret)
+ : "m" (p)
+ : "cc","memory");
+ return ret;
+ }
+ #elif defined(__hppa__)
+
+ /* Because malloc only guarantees 8-byte alignment for malloc'd data,
+ and GCC only guarantees 8-byte alignment for stack locals, we can't
+ be assured of 16-byte alignment for atomic lock data even if we
+ specify "__attribute ((aligned(16)))" in the type declaration. So,
+ we use a struct containing an array of four ints for the atomic lock
+ type and dynamically select the 16-byte aligned int from the array
+ for the semaphore. */
+ #define __PA_LDCW_ALIGNMENT 16
+ static inline void *ldcw_align (void *p) {
+ unsigned long a = (unsigned long)p;
+ a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1);
+ return (void *)a;
+ }
+
+ static inline int testandset (spinlock_t *p)
+ {
+ unsigned int ret;
+ p = ldcw_align(p);
+ __asm__ __volatile__("ldcw 0(%1),%0"
+ : "=r" (ret)
+ : "r" (p)
+ : "memory" );
+ return !ret;
+ }
+
+ #elif defined(__ia64)
+
+ #include <ia64intrin.h>
+
+ static inline int testandset (int *p)
+ {
+ return __sync_lock_test_and_set (p, 1);
+ }
+ #elif defined(__mips__)
+ static inline int testandset (int *p)
+ {
+ int ret;
+
+ __asm__ __volatile__ (
+ " .set push \n"
+ " .set noat \n"
+ " .set mips2 \n"
+ "1: li $1, 1 \n"
+ " ll %0, %1 \n"
+ " sc $1, %1 \n"
+ " beqz $1, 1b \n"
+ " .set pop "
+ : "=r" (ret), "+R" (*p)
+ :
+ : "memory");
+
+ return ret;
+ }
+ #else
+ #error unimplemented CPU support
+ #endif
+
+ #if defined(CONFIG_USER_ONLY)
+ static inline void spin_lock(spinlock_t *lock)
+ {
+ while (testandset(lock));
+ }
+
+ static inline void spin_unlock(spinlock_t *lock)
+ {
+ resetlock(lock);
+ }
+
+ static inline int spin_trylock(spinlock_t *lock)
+ {
+ return !testandset(lock);
+ }
+ #else
+ static inline void spin_lock(spinlock_t *lock)
+ {
+ }
+
+ static inline void spin_unlock(spinlock_t *lock)
+ {
+ }
+
+ static inline int spin_trylock(spinlock_t *lock)
+ {
+ return 1;
+ }
+ #endif
+
+ #endif
+QEMU_ROOT ?= ..
-include ../config-host.mak
+ VPATH=$(SRC_PATH)/tests
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
#CFLAGS+=-msse2
#include "hw/pc.h"
#include "hw/audiodev.h"
#include "hw/isa.h"
+#include "hw/pci.h"
#include "hw/baum.h"
+ #include "hw/bt.h"
#include "net.h"
#include "console.h"
#include "sysemu.h"
#include <mmsystem.h>
#define getopt_long_only getopt_long
#define memalign(align, size) malloc(size)
+#define NO_UNIX_SOCKETS 1
#endif
- #include "qemu_socket.h"
-
#ifdef CONFIG_SDL
#ifdef __APPLE__
#include <SDL/SDL.h>
/* XXX: use a two level table to limit memory usage */
#define MAX_IOPORTS 65536
+/* Max number of PCI emulation */
+#define MAX_PCI_EMULATION 32
+
const char *bios_dir = CONFIG_QEMU_SHAREDIR;
const char *bios_name = NULL;
- void *ioport_opaque[MAX_IOPORTS];
- IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
- IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
+ static void *ioport_opaque[MAX_IOPORTS];
+ static IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
+ static IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
/* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
to store the VM snapshots */
DriveInfo drives_table[MAX_DRIVES+1];
int graphic_height = 600;
int graphic_depth = 15;
#endif
- int full_screen = 0;
- int no_frame = 0;
+ static int full_screen = 0;
+ static int no_frame = 0;
int no_quit = 0;
+#ifdef CONFIG_OPENGL
+int opengl_enabled = 1;
+#else
+int opengl_enabled = 0;
+#endif
+static const char *direct_pci;
+static int nb_pci_emulation = 0;
+static char pci_emulation_config_text[MAX_PCI_EMULATION][256];
+PCI_EMULATION_INFO *PciEmulationInfoHead = NULL;
CharDriverState *serial_hds[MAX_SERIAL_PORTS];
CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
#ifdef TARGET_I386
static VLANState *first_vlan;
int smp_cpus = 1;
const char *vnc_display;
- #if defined(TARGET_SPARC)
- #define MAX_CPUS 16
- #elif defined(TARGET_I386)
- #define MAX_CPUS 255
- #else
- #define MAX_CPUS 1
- #endif
+int vncunused;
int acpi_enabled = 1;
int fd_bootchk = 1;
int no_reboot = 0;
#endif /* _WIN32 */
+ /* Correlation between real and virtual time is always going to be
+ fairly approximate, so ignore small variation.
+ When the guest is idle real and virtual time will be aligned in
+ the IO wait loop. */
+ #define ICOUNT_WOBBLE (QEMU_TIMER_BASE / 10)
+
+ static void icount_adjust(void)
+ {
+ int64_t cur_time;
+ int64_t cur_icount;
+ int64_t delta;
+ static int64_t last_delta;
+ /* If the VM is not running, then do nothing. */
+ if (!vm_running)
+ return;
+
+ cur_time = cpu_get_clock();
+ cur_icount = qemu_get_clock(vm_clock);
+ delta = cur_icount - cur_time;
+ /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */
+ if (delta > 0
+ && last_delta + ICOUNT_WOBBLE < delta * 2
+ && icount_time_shift > 0) {
+ /* The guest is getting too far ahead. Slow time down. */
+ icount_time_shift--;
+ }
+ if (delta < 0
+ && last_delta - ICOUNT_WOBBLE > delta * 2
+ && icount_time_shift < MAX_ICOUNT_SHIFT) {
+ /* The guest is getting too far behind. Speed time up. */
+ icount_time_shift++;
+ }
+ last_delta = delta;
+ qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
+ }
+
+ static void icount_adjust_rt(void * opaque)
+ {
+ qemu_mod_timer(icount_rt_timer,
+ qemu_get_clock(rt_clock) + 1000);
+ icount_adjust();
+ }
+
+ static void icount_adjust_vm(void * opaque)
+ {
+ qemu_mod_timer(icount_vm_timer,
+ qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10);
+ icount_adjust();
+ }
+
+ static void init_icount_adjust(void)
+ {
+ /* Have both realtime and virtual time triggers for speed adjustment.
+ The realtime trigger catches emulated time passing too slowly,
+ the virtual time trigger catches emulated time passing too fast.
+ Realtime triggers occur even when idle, so use them less frequently
+ than VM triggers. */
+ icount_rt_timer = qemu_new_timer(rt_clock, icount_adjust_rt, NULL);
+ qemu_mod_timer(icount_rt_timer,
+ qemu_get_clock(rt_clock) + 1000);
+ icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL);
+ qemu_mod_timer(icount_vm_timer,
+ qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10);
+ }
+
static struct qemu_alarm_timer alarm_timers[] = {
#ifndef _WIN32
-#ifdef __linux__
+#if defined(__linux__) && !defined(CONFIG_DM)
{"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer,
dynticks_stop_timer, dynticks_rearm_timer, NULL},
/* HPET - if available - is preferred */
}
#endif
- #if defined(__linux__) || defined(__sun__) || defined(__NetBSD__) || defined(__OpenBSD__)
- static int pty_getname(struct CharDriverState *chr, char *buf, size_t len) {
+ #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
+ || defined(__NetBSD__) || defined(__OpenBSD__)
+
+ typedef struct {
+ int fd;
+ int connected;
+ int polling;
+ int read_bytes;
+ QEMUTimer *timer;
+ } PtyCharDriver;
+
+ static void pty_chr_update_read_handler(CharDriverState *chr);
+ static void pty_chr_state(CharDriverState *chr, int connected);
+
+ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ {
+ PtyCharDriver *s = chr->opaque;
+
+ if (!s->connected) {
+ /* guest sends data, check for (re-)connect */
+ pty_chr_update_read_handler(chr);
+ return 0;
+ }
+ return qemu_write(s->fd, buf, len);
+ }
+
+ static int pty_chr_read_poll(void *opaque)
+ {
+ CharDriverState *chr = opaque;
+ PtyCharDriver *s = chr->opaque;
+
+ s->read_bytes = qemu_chr_can_read(chr);
+ return s->read_bytes;
+ }
+
+ static void pty_chr_read(void *opaque)
+ {
+ CharDriverState *chr = opaque;
+ PtyCharDriver *s = chr->opaque;
+ int size, len;
+ uint8_t buf[1024];
+
+ len = sizeof(buf);
+ if (len > s->read_bytes)
+ len = s->read_bytes;
+ if (len == 0)
+ return;
+ size = read(s->fd, buf, len);
+ if ((size == -1 && errno == EIO) ||
+ (size == 0)) {
+ pty_chr_state(chr, 0);
+ return;
+ }
+ if (size > 0) {
+ pty_chr_state(chr, 1);
+ qemu_chr_read(chr, buf, size);
+ }
+ }
+
+ static void pty_chr_update_read_handler(CharDriverState *chr)
+ {
+ PtyCharDriver *s = chr->opaque;
+
+ qemu_set_fd_handler2(s->fd, pty_chr_read_poll,
+ pty_chr_read, NULL, chr);
+ s->polling = 1;
+ /*
+ * Short timeout here: just need wait long enougth that qemu makes
+ * it through the poll loop once. When reconnected we want a
+ * short timeout so we notice it almost instantly. Otherwise
+ * read() gives us -EIO instantly, making pty_chr_state() reset the
+ * timeout to the normal (much longer) poll interval before the
+ * timer triggers.
+ */
+ qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 10);
+ }
+
+ static void pty_chr_state(CharDriverState *chr, int connected)
+ {
+ PtyCharDriver *s = chr->opaque;
+
+ if (!connected) {
+ qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+ s->connected = 0;
+ s->polling = 0;
+ /* (re-)connect poll interval for idle guests: once per second.
+ * We check more frequently in case the guests sends data to
+ * the virtual device linked to our pty. */
+ qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
+ } else {
+ if (!s->connected)
+ qemu_chr_reset(chr);
+ s->connected = 1;
+ }
+ }
+
+ static void pty_chr_timer(void *opaque)
+ {
+ struct CharDriverState *chr = opaque;
+ PtyCharDriver *s = chr->opaque;
+
+ if (s->connected)
+ return;
+ if (s->polling) {
+ /* If we arrive here without polling being cleared due
+ * read returning -EIO, then we are (re-)connected */
+ pty_chr_state(chr, 1);
+ return;
+ }
+
+ /* Next poll ... */
+ pty_chr_update_read_handler(chr);
+ }
+
++static int pty_chr_getname(struct CharDriverState *chr, char *buf, size_t len) {
+ char *name;
+ FDCharDriver *s = chr->opaque;
+
+ name = ptsname(s->fd_in);
+ if (!name) return -1;
+ return snprintf(buf,len, "pty %s", name);
+}
+
+ static void pty_chr_close(struct CharDriverState *chr)
+ {
+ PtyCharDriver *s = chr->opaque;
+
+ qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+ close(s->fd);
+ qemu_free(s);
+ }
+
static CharDriverState *qemu_chr_open_pty(void)
{
- struct termios tty;
- int master_fd, slave_fd;
CharDriverState *chr;
+ PtyCharDriver *s;
+ struct termios tty;
+ int slave_fd;
+ #if defined(__OpenBSD__)
+ char pty_name[PATH_MAX];
+ #define q_ptsname(x) pty_name
+ #else
+ char *pty_name = NULL;
+ #define q_ptsname(x) ptsname(x)
+ #endif
+
+ chr = qemu_mallocz(sizeof(CharDriverState));
+ if (!chr)
+ return NULL;
+ s = qemu_mallocz(sizeof(PtyCharDriver));
+ if (!s) {
+ qemu_free(chr);
+ return NULL;
+ }
- if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) < 0) {
+ if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
return NULL;
}
/* Set raw attributes on the pty. */
cfmakeraw(&tty);
tcsetattr(slave_fd, TCSAFLUSH, &tty);
+ close(slave_fd);
+
+ fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
+
+ chr->opaque = s;
+ chr->chr_write = pty_chr_write;
+ chr->chr_update_read_handler = pty_chr_update_read_handler;
+ chr->chr_close = pty_chr_close;
++ chr->chr_getname = pty_chr_getname;
+
+ s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr);
- fprintf(stderr, "char device redirected to %s\n", ptsname(master_fd));
- chr = qemu_chr_open_fd(master_fd, master_fd);
- chr->chr_getname = pty_getname;
return chr;
}
if (is_listen) {
/* allow fast reuse */
-#ifndef _WIN32
+#ifndef NO_UNIX_SOCKETS
if (is_unix) {
char path[109];
- strncpy(path, uaddr.sun_path, 108);
- path[108] = 0;
+ pstrcpy(path, sizeof(path), uaddr.sun_path);
unlink(path);
} else
#endif
/***********************************************************/
/* ram save/restore */
- static void ram_save(QEMUFile *f, void *opaque) { }
+#ifdef CONFIG_DM
++static int ram_save_live(QEMUFile *f, int stage, void *opaque) { return 0; }
+static int ram_load(QEMUFile *f, void *opaque, int version_id) { return 0; }
+#else /* !CONFIG_DM */
+
static int ram_get_page(QEMUFile *f, uint8_t *buf, int len)
{
int v;
return 0;
}
+#endif /* !CONFIG_DM */
+
+ void qemu_service_io(void)
+ {
+ CPUState *env = cpu_single_env;
+ if (env) {
+ cpu_interrupt(env, CPU_INTERRUPT_EXIT);
+ #ifdef USE_KQEMU
+ if (env->kqemu_enabled) {
+ kqemu_cpu_interrupt(env);
+ }
+ #endif
+ }
+ }
+
/***********************************************************/
/* bottom halves (can be seen as timers which expire ASAP) */
QEMU_OPTION_bios,
QEMU_OPTION_k,
QEMU_OPTION_localtime,
- QEMU_OPTION_cirrusvga,
- QEMU_OPTION_vmsvga,
QEMU_OPTION_g,
- QEMU_OPTION_std_vga,
+ QEMU_OPTION_vga,
QEMU_OPTION_echr,
QEMU_OPTION_monitor,
+ QEMU_OPTION_domainname,
QEMU_OPTION_serial,
QEMU_OPTION_parallel,
QEMU_OPTION_loadvm,
{ "g", 1, QEMU_OPTION_g },
#endif
{ "localtime", 0, QEMU_OPTION_localtime },
- { "std-vga", 0, QEMU_OPTION_std_vga },
+ { "vga", HAS_ARG, QEMU_OPTION_vga },
{ "echr", HAS_ARG, QEMU_OPTION_echr },
{ "monitor", HAS_ARG, QEMU_OPTION_monitor },
+ { "domain-name", 1, QEMU_OPTION_domainname },
{ "serial", HAS_ARG, QEMU_OPTION_serial },
{ "parallel", HAS_ARG, QEMU_OPTION_parallel },
{ "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
const char *usb_devices[MAX_USB_CMDLINE];
int usb_devices_index;
int fds[2];
+#ifndef CONFIG_STUBDOM
+ struct rlimit rl;
+#endif
+ int tb_size;
const char *pid_file = NULL;
VLANState *vlan;
+ int autostart;
+ logfile = stderr; /* initial value */
+
+#if !defined(__sun__) && !defined(CONFIG_STUBDOM)
+ /* Maximise rlimits. Needed where default constraints are tight (*BSD). */
+ if (getrlimit(RLIMIT_STACK, &rl) != 0) {
+ perror("getrlimit(RLIMIT_STACK)");
+ exit(1);
+ }
+ rl.rlim_cur = rl.rlim_max;
+ if (setrlimit(RLIMIT_STACK, &rl) != 0)
+ perror("setrlimit(RLIMIT_STACK)");
+ if (getrlimit(RLIMIT_DATA, &rl) != 0) {
+ perror("getrlimit(RLIMIT_DATA)");
+ exit(1);
+ }
+ rl.rlim_cur = rl.rlim_max;
+ if (setrlimit(RLIMIT_DATA, &rl) != 0)
+ perror("setrlimit(RLIMIT_DATA)");
+ rl.rlim_cur = RLIM_INFINITY;
+ rl.rlim_max = RLIM_INFINITY;
+ if (setrlimit(RLIMIT_RSS, &rl) != 0)
+ perror("setrlimit(RLIMIT_RSS)");
+ rl.rlim_cur = RLIM_INFINITY;
+ rl.rlim_max = RLIM_INFINITY;
+ if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0)
+ perror("setrlimit(RLIMIT_MEMLOCK)");
+ #endif
+
LIST_INIT (&vm_change_state_head);
#ifndef _WIN32
{
linux_boot = (kernel_filename != NULL);
net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
+#ifndef CONFIG_DM
+ /* XXX: this should not be: some embedded targets just have flash */
if (!linux_boot && net_boot == 0 &&
- nb_drives_opt == 0)
+ !machine->nodisk_ok && nb_drives_opt == 0)
help(1);
+#endif /*!CONFIG_DM*/
+ if (!linux_boot && *kernel_cmdline != '\0') {
+ fprintf(stderr, "-append only allowed with -kernel option\n");
+ exit(1);
+ }
+
+ if (!linux_boot && initrd_filename != NULL) {
+ fprintf(stderr, "-initrd only allowed with -kernel option\n");
+ exit(1);
+ }
+
/* boot to floppy or the default cd if no hard disk defined yet */
if (!boot_devices[0]) {
boot_devices = "cad";
fprintf(stderr, "Could not allocate physical memory\n");
exit(1);
}
+#endif
+ /* init the dynamic translator */
+ cpu_exec_init_all(tb_size * 1024 * 1024);
+
bdrv_init();
+ xc_handle = xc_interface_open();
+#ifdef CONFIG_STUBDOM
+ {
+ char *domid_s, *msg;
+ if ((msg = xenbus_read(XBT_NIL, "domid", &domid_s)))
+ fprintf(stderr,"Can not read our own domid: %s\n", msg);
+ else
+ xenstore_parse_domain_config(atoi(domid_s));
+ }
+#else
+ xenstore_parse_domain_config(domid);
+#endif /* CONFIG_STUBDOM */
+
/* we always create the cdrom drive, even if no disk is there */
+#ifndef CONFIG_DM
if (nb_drives_opt < MAX_DRIVES)
drive_add(NULL, CDROM_ALIAS);
+#endif
/* we always create at least one floppy */
if (sscanf(vc->info_str, "tap: ifname=%63s ", ifname) == 1 &&
s->down_script[0])
- launch_script(s->down_script, ifname, s->fd);
+ launch_script(s->down_script, ifname, s->script_arg, s->fd);
}
+ #if defined(CONFIG_VDE)
+ if (vc->fd_read == vde_from_qemu) {
+ VDEState *s = vc->opaque;
+ vde_close(s->vde);
+ }
+ #endif
}
}
#endif
// #define _VNC_DEBUG 1
- #if _VNC_DEBUG
+ #ifdef _VNC_DEBUG
#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
--#if CONFIG_VNC_TLS && _VNC_DEBUG >= 2
++#if defined(CONFIG_VNC_TLS) && _VNC_DEBUG >= 2
/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
static void vnc_debug_gnutls_log(int level, const char* str) {
VNC_DEBUG("%d %s", level, str);
char *x509key;
#endif
char challenge[VNC_AUTH_CHALLENGE_SIZE];
+ int switchbpp;
- #if CONFIG_VNC_TLS
+ #ifdef CONFIG_VNC_TLS
int wiremode;
gnutls_session_t tls_session;
#endif
}
return 0;
}
+#endif
-static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+static void set_bits_in_row(VncState *vs, uint64_t *row,
+ int x, int y, int w, int h)
{
- VncState *vs = ds->opaque;
- int i;
+ int x1, x2;
+ uint64_t mask;
+
+ if (w == 0)
+ return;
+
+ x1 = X2DP_DOWN(vs, x);
+ x2 = X2DP_UP(vs, x + w);
+
+ if (X2DP_UP(vs, w) != DIRTY_PIXEL_BITS)
+ mask = ((1ULL << (x2 - x1)) - 1) << x1;
+ else
+ mask = ~(0ULL);
h += y;
+ if (h > vs->ds->height)
+ h = vs->ds->height;
+ for (; y < h; y++)
+ row[y] |= mask;
+}
- /* round x down to ensure the loop only spans one 16-pixel block per,
- iteration. otherwise, if (x % 16) != 0, the last iteration may span
- two 16-pixel blocks but we only mark the first as dirty
- */
- w += (x % 16);
- x -= (x % 16);
+static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
+{
+ VncState *vs = ds->opaque;
- w = MIN(x + w, vs->width) - x;
+ x = MIN(x, vs->width);
+ y = MIN(y, vs->height);
- for (; y < h; y++)
- for (i = 0; i < w; i += 16)
- vnc_set_bit(vs->dirty_row[y], (x + i) / 16);
++ w = MIN(x, vs->width - x);
+ h = MIN(h, vs->height);
+
+ set_bits_in_row(vs, vs->dirty_row, x, y, w, h);
}
static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
vnc_write_s32(vs, encoding);
}
- static int mult_overflows(int x, int y)
- {
- if (x<=0 || y<=0 || x>=INT_MAX/y)
- return 1;
- else return 0;
- }
-
-static void vnc_dpy_resize(DisplayState *ds, int w, int h)
+static void vnc_dpy_resize_shared(DisplayState *ds, int w, int h, int depth, int linesize, void *pixels)
{
+ static int allocated;
int size_changed;
VncState *vs = ds->opaque;
+ int o;
- ds->data = qemu_realloc(ds->data, w * h * vs->depth);
- vs->old_data = qemu_realloc(vs->old_data, w * h * vs->depth);
+ vnc_colourdepth(ds, depth);
- if (mult_overflows(w, h) || mult_overflows(w*h, vs->depth) ||
- mult_overflows(h, sizeof(vs->dirty_row[0]))) {
- fprintf(stderr, "vnc: suspicious vnc_dpy_resize arguments"
- " (w=%d h=%d depth=%d linesize=%d vs->depth=%d), exiting\n",
- w, h, depth, linesize, vs->depth);
- exit(1);
- }
+ if (!ds->shared_buf) {
+ ds->linesize = w * vs->depth;
+ if (allocated)
- ds->data = realloc(ds->data, h * ds->linesize);
++ ds->data = qemu_realloc(ds->data, h * ds->linesize);
+ else
+ ds->data = malloc(h * ds->linesize);
+ allocated = 1;
+ } else {
+ ds->linesize = linesize;
+ if (allocated) {
+ free(ds->data);
+ allocated = 0;
+ }
+ }
- vs->old_data = realloc(vs->old_data, h * ds->linesize);
- vs->dirty_row = realloc(vs->dirty_row, h * sizeof(vs->dirty_row[0]));
- vs->update_row = realloc(vs->update_row, h * sizeof(vs->dirty_row[0]));
++ vs->old_data = qemu_realloc(vs->old_data, h * ds->linesize);
++ vs->dirty_row = qemu_realloc(vs->dirty_row, h * sizeof(vs->dirty_row[0]));
++ vs->update_row = qemu_realloc(vs->update_row, h * sizeof(vs->dirty_row[0]));
- if (ds->data == NULL || vs->old_data == NULL) {
+ if (ds->data == NULL || vs->old_data == NULL ||
+ vs->dirty_row == NULL || vs->update_row == NULL) {
fprintf(stderr, "vnc: memory allocation failed\n");
exit(1);
}
vs->ds->idle = 1;
buffer_reset(&vs->input);
buffer_reset(&vs->output);
- vs->need_update = 0;
+ free_queue(vs);
+ vs->update_requested = 0;
- #if CONFIG_VNC_TLS
+ #ifdef CONFIG_VNC_TLS
if (vs->tls_session) {
gnutls_deinit(vs->tls_session);
vs->tls_session = NULL;
(data[offset + 2] << 8) | data[offset + 3]);
}
- #if CONFIG_VNC_TLS
+ #ifdef CONFIG_VNC_TLS
-static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
- const void *data,
- size_t len) {
+ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
+ const void *data,
+ size_t len) {
struct VncState *vs = (struct VncState *)transport;
int ret;
if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
return 0;
- #if _VNC_DEBUG == 2
-#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
++#if defined(_VNC_DEBUG) && _VNC_DEBUG == 2
gnutls_global_set_log_level(10);
gnutls_global_set_log_function(vnc_debug_gnutls_log);
#endif
vs->ds->data = NULL;
vs->ds->dpy_update = vnc_dpy_update;
vs->ds->dpy_resize = vnc_dpy_resize;
+ vs->ds->dpy_setdata = vnc_dpy_setdata;
+ vs->ds->dpy_resize_shared = vnc_dpy_resize_shared;
vs->ds->dpy_refresh = NULL;
- vnc_colordepth(vs->ds, 32);
- vnc_dpy_resize(vs->ds, 640, 400);
+ vs->ds->width = 640;
+ vs->ds->height = 400;
+ vs->ds->linesize = 640 * 4;
+ vnc_dpy_resize_shared(ds, ds->width, ds->height, 24, ds->linesize, NULL);
}
- #if CONFIG_VNC_TLS
+ #ifdef CONFIG_VNC_TLS
static int vnc_set_x509_credential(VncState *vs,
const char *certdir,
const char *filename,
vs->csock = -1;
buffer_reset(&vs->input);
buffer_reset(&vs->output);
- vs->need_update = 0;
+ free_queue(vs);
+ vs->update_requested = 0;
- #if CONFIG_VNC_TLS
+ #ifdef CONFIG_VNC_TLS
if (vs->tls_session) {
gnutls_deinit(vs->tls_session);
vs->tls_session = NULL;
VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
const char *options;
int password = 0;
- #if CONFIG_VNC_TLS
- int reverse = 0;
+ #ifdef CONFIG_VNC_TLS
int tls = 0, x509 = 0;
#endif
options++;
if (strncmp(options, "password", 8) == 0) {
password = 1; /* Require password auth */
- } else if (strncmp(options, "reverse", 7) == 0) {
- reverse = 1;
+ } else if (strncmp(options, "switchbpp", 9) == 0) {
+ vs->switchbpp = 1;
- #if CONFIG_VNC_TLS
+ #ifdef CONFIG_VNC_TLS
} else if (strncmp(options, "tls", 3) == 0) {
tls = 1; /* Require TLS */
} else if (strncmp(options, "x509", 4) == 0) {
--- /dev/null
-
- #ifdef bool
- # define XEN_CONFIG_HOST_BOOL_WAS_DEFINED 1
- #else
- # define bool xen_bool
- #endif
+#ifdef __MINIOS__
+#define CONFIG_STUBDOM
+#define NO_AIO 1
+#define NO_UNIX_SOCKETS 1
+#endif
+
+extern char domain_name[64];
+extern int domid, domid_backend;
+
+#include <errno.h>
- #ifndef XEN_CONFIG_HOST_BOOL_WAS_DEFINED
- # undef bool
- #endif
-
++#include <stdbool.h>
+
+#include "xenctrl.h"
+#include "xs.h"
+#ifndef CONFIG_STUBDOM
+#include "blktaplib.h"
+#endif
+
+#define BIOS_SIZE ((256 + 64) * 1024)
+
+#undef CONFIG_GDBSTUB
+
+void main_loop_prepare(void);
+
+extern int xc_handle;
+extern int xen_pause_requested;
+extern int vcpus;
+
+#define DEFAULT_NETWORK_SCRIPT "/etc/xen/qemu-ifup"
+#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/xen/qemu-ifdown"
+
+void xenstore_parse_domain_config(int domid);
+void xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen);
+#ifdef CONFIG_STUBDOM
+extern struct BlockDriver bdrv_vbd;
+#endif
+struct CharDriverState;
+void xenstore_store_serial_port_info(int i, struct CharDriverState *chr,
+ const char *devname);
++
++extern unsigned long *logdirty_bitmap;
++extern unsigned long logdirty_bitmap_size;
--- /dev/null
+QEMU_ROOT ?= .
+XEN_ROOT ?= $(QEMU_ROOT)/../xen-unstable.hg
+include $(XEN_ROOT)/tools/Rules.mk
+
+ifdef CONFIG_STUBDOM
+TARGET_DIRS=i386-stubdom
+else
+TARGET_DIRS=i386-dm
+endif
+
++SUBDIR_RULES=subdir-$(TARGET_DIRS)
++subdir-$(TARGET_DIRS): libqemu_common.a
++
+-include $(QEMU_ROOT)/xen-hooks.mak
--- /dev/null
+CPPFLAGS+= -I$(XEN_ROOT)/tools/libxc
+CPPFLAGS+= -I$(XEN_ROOT)/tools/xenstore
+CPPFLAGS+= -I$(XEN_ROOT)/tools/include
+
+SSE2 := $(call cc-option,-msse2,)
+ifeq ($(SSE2),-msse2)
+CFLAGS += -DUSE_SSE2=1 -msse2
+endif
+
+QEMU_PROG=qemu-dm
+
+CFLAGS += -Wno-unused -Wno-declaration-after-statement
+
+ifeq (,$(shell $(CC) -Wno-pointer-sign -E - </dev/null >/dev/null || echo x))
+CFLAGS += -Wno-pointer-sign
+endif
+
+CFLAGS += $(CMDLINE_CFLAGS)
+
+LIBS += -L$(XEN_ROOT)/tools/libxc -lxenctrl -lxenguest
+LIBS += -L$(XEN_ROOT)/tools/xenstore -lxenstore
+
+LDFLAGS := $(CFLAGS) $(LDFLAGS)
+
+OBJS += piix4acpi.o
+OBJS += xenstore.o
+OBJS += xen_platform.o
+OBJS += xen_machine_fv.o
+OBJS += xen_machine_pv.o
+OBJS += xenfb.o
+OBJS += xen_console.o
+OBJS += xen_machine_fv.o
+OBJS += exec-dm.o
+OBJS += pci_emulation.o
++OBJS += helper2.o
+
+ifdef CONFIG_STUBDOM
+CPPFLAGS += $(TARGET_CPPFLAGS)
+CONFIG_SDL=
+CONFIG_AUDIO=
+OBJS += xenfbfront.o
+else
+CPPFLAGS+= -I$(XEN_ROOT)/tools/blktap/lib
+LIBS += -L$(XEN_ROOT)/tools/blktap/lib -lblktap
+OBJS += xen_blktap.o
+OBJS += tpm_tis.o
+endif
+
+ifdef CONFIG_STUBDOM
+CONFIG_PASSTHROUGH=1
+else
+ ifeq (,$(wildcard /usr/include/pci))
+$(warning *** pciutils-dev package not found - missing /usr/include/pci)
+$(warning *** PCI passthrough capability has been disabled)
+ else
+CONFIG_PASSTHROUGH=1
+ endif
+endif
+
+ifdef CONFIG_PASSTHROUGH
+OBJS+= pass-through.o pt-msi.o
+LIBS += -lpci
+CFLAGS += -DCONFIG_PASSTHROUGH
+$(info *** PCI passthrough capability has been enabled ***)
+endif
+
+BAD_OBJS += gdbstub.o acpi.o apic.o
+BAD_OBJS += vmmouse.o vmport.o tcg* helper.o
+
+OBJS := $(filter-out $(BAD_OBJS), $(OBJS))
+
+EXESUF=-xen
+
+datadir := $(subst qemu,xen/qemu,$(datadir))
+docdir := $(subst qemu,xen/qemu,$(docdir))
+mandir := $(subst share/man,share/xen/man,$(mandir))
+
+configdir := /etc/xen
--- /dev/null
- /* forward declarations of things in vl.c */
-
- static int qemu_savevm_state(QEMUFile *f);
- static int qemu_loadvm_state(QEMUFile *f);
-
+/*
+ * We #include this from vl.c.
+ *
+ * This is a bit yucky, but it means that the line numbers and other
+ * textual differences in vl.c remain small.
+ */
+/* There is no need for multiple-inclusion protection since
+ * there is only one place where this file is included. */
+
+#include "qemu-xen.h"
+
+/* We use simpler state save/load functions for Xen */
+
+void do_savevm(const char *name)
+{
+ QEMUFile *f;
+ int saved_vm_running, ret;
+
+ f = qemu_fopen(name, "wb");
+
+ /* ??? Should this occur after vm_stop? */
+ qemu_aio_flush();
+
+ saved_vm_running = vm_running;
+ vm_stop(0);
+
+ if (!f) {
+ fprintf(logfile, "Failed to open savevm file '%s'\n", name);
+ goto the_end;
+ }
+
+ ret = qemu_savevm_state(f);
+ qemu_fclose(f);
+
+ if (ret < 0)
+ fprintf(logfile, "Error %d while writing VM to savevm file '%s'\n",
+ ret, name);
+
+ the_end:
+ if (saved_vm_running)
+ vm_start();
+
+ return;
+}
+void do_loadvm(const char *name)
+{
+ QEMUFile *f;
+ int saved_vm_running, ret;
+
+ /* Flush all IO requests so they don't interfere with the new state. */
+ qemu_aio_flush();
+
+ saved_vm_running = vm_running;
+ vm_stop(0);
+
+ /* restore the VM state */
+ f = qemu_fopen(name, "rb");
+ if (!f) {
+ fprintf(logfile, "Could not open VM state file\n");
+ goto the_end;
+ }
+
+ ret = qemu_loadvm_state(f);
+ qemu_fclose(f);
+ if (ret < 0) {
+ fprintf(logfile, "Error %d while loading savevm file '%s'\n",
+ ret, name);
+ goto the_end;
+ }
+
+#if 0
+ /* del tmp file */
+ if (unlink(name) == -1)
+ fprintf(stderr, "delete tmp qemu state file failed.\n");
+#endif
+
+
+ the_end:
+ if (saved_vm_running)
+ vm_start();
+}
+
+struct qemu_alarm_timer;
+static int unix_start_timer(struct qemu_alarm_timer *t) { return 0; }
+static void unix_stop_timer(struct qemu_alarm_timer *t) { }
+
+#ifdef CONFIG_STUBDOM
+#include <netfront.h>
+static int tap_open(char *ifname, int ifname_size)
+{
+ char nodename[64];
+ static int num = 1; // 0 is for our own TCP/IP networking
+ snprintf(nodename, sizeof(nodename), "device/vif/%d", num++);
+ return netfront_tap_open(nodename);
+}
+
+#undef DEFAULT_NETWORK_SCRIPT
+#define DEFAULT_NETWORK_SCRIPT ""
+#undef DEFAULT_NETWORK_DOWN_SCRIPT
+#define DEFAULT_NETWORK_DOWN_SCRIPT ""
+#endif
+
--- /dev/null
- unsigned long *logdirty_bitmap = NULL;
- unsigned long logdirty_bitmap_size;
- extern int vga_ram_size, bios_size;
-
+/*
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2006 Christian Limpach
+ * Copyright (C) 2006 XenSource Ltd.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu-char.h"
+
+#include "block_int.h"
+#include <unistd.h>
+#ifndef CONFIG_STUBDOM
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#include "exec-all.h"
+#include "sysemu.h"
+
+#include "hw.h"
+#include "pci.h"
+#include "qemu-timer.h"
+#include "qemu-xen.h"
+
+struct xs_handle *xsh = NULL;
+static char *media_filename[MAX_DRIVES+1];
+static QEMUTimer *insert_timer = NULL;
+
+#define UWAIT_MAX (30*1000000) /* thirty seconds */
+#define UWAIT (100000) /* 1/10th second */
+
+static int pasprintf(char **buf, const char *fmt, ...)
+{
+ va_list ap;
+ int ret = 0;
+
+ if (*buf)
+ free(*buf);
+ va_start(ap, fmt);
+ if (vasprintf(buf, fmt, ap) == -1) {
+ buf = NULL;
+ ret = -1;
+ }
+ va_end(ap);
+ return ret;
+}
+
+static void insert_media(void *opaque)
+{
+ int i;
+ BlockDriverState *bs;
+
+ for (i = 0; i < MAX_DRIVES + 1; i++) {
+ bs = drives_table[i].bdrv;
+ if (media_filename[i] && bs && bs->filename[0] == '\0') {
+ bdrv_open2(bs, media_filename[i], 0, &bdrv_raw);
+ pstrcpy(bs->filename, sizeof(bs->filename), media_filename[i]);
+ free(media_filename[i]);
+ media_filename[i] = NULL;
+ }
+ }
+}
+
+void xenstore_check_new_media_present(int timeout)
+{
+
+ if (insert_timer == NULL)
+ insert_timer = qemu_new_timer(rt_clock, insert_media, NULL);
+ qemu_mod_timer(insert_timer, qemu_get_clock(rt_clock) + timeout);
+}
+
+static void waitForDevice(char *fn)
+{
+ struct stat sbuf;
+ int status;
+ int uwait = UWAIT_MAX;
+
+ do {
+ status = stat(fn, &sbuf);
+ if (!status) break;
+ usleep(UWAIT);
+ uwait -= UWAIT;
+ } while (uwait > 0);
+
+ return;
+}
+
+static int any_hdN;
+
+static int parse_drive_name(const char *dev, DriveInfo *out) {
+ /* alway sleaves out->bdrv unchanged */
+ /* on success, returns 0 and fills in out->type, ->bus, ->unit */
+ /* if drive name not understood, returns -1 and *out may be garbage */
+ int ch, max, per_bus;
+
+ /* Change xvdN to look like hdN */
+ if (!any_hdN && !strncmp(dev, "xvd", 3) && strlen(dev) == 4) {
+ ch = dev[3];
+ fprintf(logfile, "Using %s for guest's hd%c\n", dev, ch);
+ out->type = IF_IDE;
+ } else if (!strncmp(dev, "hd", 2) && strlen(dev) == 3) {
+ ch = dev[2];
+ out->type = IF_IDE;
+ } else if (!strncmp(dev, "sd", 2) && strlen(dev) == 3) {
+ ch = dev[2];
+ out->type = IF_SCSI;
+ } else {
+ fprintf(stderr, "qemu: ignoring not-understood drive `%s'\n", dev);
+ return -1;
+ }
+
+ if (out->type == IF_SCSI) {
+ max = MAX_SCSI_DEVS;
+ per_bus = max;
+ } else {
+ max = 4;
+ per_bus = 2;
+ }
+
+ ch = ch - 'a';
+ if (ch >= max) {
+ fprintf(stderr, "qemu: drive `%s' out of range\n", dev);
+ return -1;
+ }
+
+ out->bus = ch / per_bus;
+ out->unit = ch % per_bus;
+
+ return 0;
+}
+
+static int drive_name_to_index(const char *name) {
+ DriveInfo tmp;
+ int ret;
+
+ ret = parse_drive_name(name, &tmp); if (ret) return -1;
+ ret = drive_get_index(tmp.type, tmp.bus, tmp.unit);
+ return ret;
+}
+
+static void xenstore_get_backend_path(char **backend, const char *devtype,
+ const char *frontend_dompath,
+ int frontend_domid,
+ const char *inst_danger) {
+ /* On entry: *backend will be passed to free()
+ * On succcess: *backend will be from malloc
+ * On failure: *backend==0
+ */
+ char *bpath=0;
+ char *frontend_path=0;
+ char *backend_dompath=0;
+ char *expected_backend=0;
+ char *frontend_backend_path=0;
+ char *backend_frontend_path=0;
+ char *frontend_doublecheck=0;
+ int len;
+ const char *frontend_idpath_slash;
+
+ /* clear out return value for if we error out */
+ free(*backend);
+ *backend = 0;
+
+ if (strchr(inst_danger,'/')) {
+ fprintf(logfile, "xenstore_get_backend_path inst_danger has slash"
+ " which is forbidden (devtype %s)\n", devtype);
+ goto out;
+ }
+
+ if (pasprintf(&frontend_path, "%s/device/%s/%s",
+ frontend_dompath, devtype, inst_danger)
+ == -1) goto out;
+
+ if (pasprintf(&frontend_backend_path, "%s/backend",
+ frontend_path)
+ == -1) goto out;
+
+ bpath = xs_read(xsh, XBT_NULL, frontend_backend_path, &len);
+
+ /* now we must check that the backend is intended for use
+ * by this frontend, since the frontend's /backend xenstore node
+ * is writeable by the untrustworthy guest. */
+
+ backend_dompath = xs_get_domain_path(xsh, domid_backend);
+ if (!backend_dompath) goto out;
+
+ const char *expected_devtypes[3];
+ const char **expected_devtype = expected_devtypes;
+
+ *expected_devtype++ = devtype;
+ if (!strcmp(devtype, "vbd")) *expected_devtype++ = "tap";
+ *expected_devtype = 0;
+ assert(expected_devtype <
+ expected_devtypes + ARRAY_SIZE(expected_devtypes));
+
+ for (expected_devtype = expected_devtypes;
+ *expected_devtype;
+ expected_devtype++) {
+
+ if (pasprintf(&expected_backend, "%s/backend/%s/%lu/%s",
+ backend_dompath, *expected_devtype,
+ frontend_domid, inst_danger)
+ == -1) goto out;
+
+ if (!strcmp(bpath, expected_backend))
+ goto found;
+ }
+
+ fprintf(stderr, "frontend `%s' devtype `%s' expected backend `%s'"
+ " got `%s', ignoring\n",
+ frontend_path, devtype, expected_backend, bpath);
+ errno = EINVAL;
+ goto out;
+
+ found:
+
+ if (pasprintf(&backend_frontend_path, "%s/frontend", bpath)
+ == -1) goto out;
+
+ frontend_doublecheck = xs_read(xsh, XBT_NULL, backend_frontend_path, &len);
+
+ if (strcmp(frontend_doublecheck, frontend_path)) {
+ fprintf(stderr, "frontend `%s' backend `%s' points to other frontend"
+ " `%s', ignoring\n", frontend_path, bpath, frontend_doublecheck);
+ errno = EINVAL;
+ goto out;
+ }
+
+ /* steal bpath */
+ *backend = bpath;
+ bpath = 0;
+
+ out:
+ free(bpath);
+ free(frontend_path);
+ free(backend_dompath);
+ free(expected_backend);
+ free(frontend_backend_path);
+ free(backend_frontend_path);
+ free(frontend_doublecheck);
+}
+
+const char *xenstore_get_guest_uuid(void) {
+#ifdef CONFIG_STUBDOM
+ return 0;
+#else
+
+ static char *already_computed;
+
+ xc_domaininfo_t info;
+ int xch = -1, r, i;
+ char *p;
+
+ if (already_computed)
+ return already_computed;
+
+ xch = xc_interface_open();
+ if (xch == -1) {
+ fprintf(logfile, "cannot get uuid - xc_interface_open() failed: %s\n",
+ strerror(errno));
+ goto out;
+ }
+ r = xc_domain_getinfolist(xch, domid, 1, &info);
+ if (r != 1) {
+ fprintf(logfile, "cannot get uuid - xc_domain_getinfolist() failed:"
+ " %s\n", strerror(errno));
+ goto out;
+ }
+ already_computed = malloc(37);
+ for (i = 0, p = already_computed; i < 16; i++, p += 2) {
+ if (i==4 || i==6 || i==8 || i==10)
+ *p++ = '-';
+ sprintf(p, "%02x", info.handle[i]);
+ }
+ close(xch);
+ return already_computed;
+
+ out:
+ if (xch != -1)
+ close(xch);
+
+ return 0;
+#endif
+}
+
+#define DIRECT_PCI_STR_LEN 160
+char direct_pci_str[DIRECT_PCI_STR_LEN];
+void xenstore_parse_domain_config(int hvm_domid)
+{
+ char **e_danger = NULL;
+ char *buf = NULL;
+ char *fpath = NULL, *bpath = NULL,
+ *dev = NULL, *params = NULL, *drv = NULL;
+ int i, any_hdN = 0, ret;
+ unsigned int len, num, hd_index, pci_devid = 0;
+ BlockDriverState *bs;
+ BlockDriver *format;
+
+ /* paths controlled by untrustworthy guest, and values read from them */
+ char *danger_path;
+ char *danger_buf = NULL;
+ char *danger_type = NULL;
+
+ for(i = 0; i < MAX_DRIVES + 1; i++)
+ media_filename[i] = NULL;
+
+ xenstore_get_guest_uuid();
+
+ xsh = xs_daemon_open();
+ if (xsh == NULL) {
+ fprintf(logfile, "Could not contact xenstore for domain config\n");
+ return;
+ }
+
+ danger_path = xs_get_domain_path(xsh, hvm_domid);
+ if (danger_path == NULL) {
+ fprintf(logfile, "xs_get_domain_path() error\n");
+ goto out;
+ }
+
+ if (pasprintf(&danger_buf, "%s/device/vbd", danger_path) == -1)
+ goto out;
+
+ e_danger = xs_directory(xsh, XBT_NULL, danger_buf, &num);
+ if (e_danger == NULL)
+ num = 0;
+
+ for (i = 0; i < num; i++) {
+ /* read the backend path */
+ xenstore_get_backend_path(&bpath, "vbd", danger_path, hvm_domid,
+ e_danger[i]);
+ if (bpath == NULL)
+ continue;
+ /* read the name of the device */
+ if (pasprintf(&buf, "%s/dev", bpath) == -1)
+ continue;
+ free(dev);
+ dev = xs_read(xsh, XBT_NULL, buf, &len);
+ if (dev == NULL)
+ continue;
+ if (!strncmp(dev, "hd", 2)) {
+ any_hdN = 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < num; i++) {
+ format = NULL; /* don't know what the format is yet */
+ /* read the backend path */
+ xenstore_get_backend_path(&bpath, "vbd", danger_path, hvm_domid, e_danger[i]);
+ if (bpath == NULL)
+ continue;
+ /* read the name of the device */
+ if (pasprintf(&buf, "%s/dev", bpath) == -1)
+ continue;
+ free(dev);
+ dev = xs_read(xsh, XBT_NULL, buf, &len);
+ if (dev == NULL)
+ continue;
+ if (nb_drives >= MAX_DRIVES) {
+ fprintf(stderr, "qemu: too many drives, skipping `%s'\n", dev);
+ continue;
+ }
+ ret = parse_drive_name(dev, &drives_table[nb_drives]);
+ if (ret)
+ continue;
+ /* read the type of the device */
+ if (pasprintf(&danger_buf, "%s/device/vbd/%s/device-type",
+ danger_path, e_danger[i]) == -1)
+ continue;
+ free(danger_type);
+ danger_type = xs_read(xsh, XBT_NULL, danger_buf, &len);
+ if (pasprintf(&buf, "%s/params", bpath) == -1)
+ continue;
+ free(params);
+ params = xs_read(xsh, XBT_NULL, buf, &len);
+ if (params == NULL)
+ continue;
+ /* read the name of the device */
+ if (pasprintf(&buf, "%s/type", bpath) == -1)
+ continue;
+ free(drv);
+ drv = xs_read(xsh, XBT_NULL, buf, &len);
+ if (drv == NULL)
+ continue;
+ /* Obtain blktap sub-type prefix */
+ if (!strcmp(drv, "tap") && params[0]) {
+ char *offset = strchr(params, ':');
+ if (!offset)
+ continue ;
+ free(drv);
+ drv = malloc(offset - params + 1);
+ memcpy(drv, params, offset - params);
+ drv[offset - params] = '\0';
+ if (!strcmp(drv, "aio"))
+ /* qemu does aio anyway if it can */
+ format = &bdrv_raw;
+ memmove(params, offset+1, strlen(offset+1)+1 );
+ fprintf(logfile, "Strip off blktap sub-type prefix to %s (drv '%s')\n", params, drv);
+ }
+ /* Prefix with /dev/ if needed */
+ if (!strcmp(drv, "phy") && params[0] != '/') {
+ char *newparams = malloc(5 + strlen(params) + 1);
+ sprintf(newparams, "/dev/%s", params);
+ free(params);
+ params = newparams;
+ format = &bdrv_raw;
+ }
+
+#if 0
+ /* Phantom VBDs are disabled because the use of paths
+ * from guest-controlled areas in xenstore is unsafe.
+ * Hopefully if they are really needed for something
+ * someone will shout and then we will find out what for.
+ */
+ /*
+ * check if device has a phantom vbd; the phantom is hooked
+ * to the frontend device (for ease of cleanup), so lookup
+ * the frontend device, and see if there is a phantom_vbd
+ * if there is, we will use resolution as the filename
+ */
+ if (pasprintf(&danger_buf, "%s/device/vbd/%s/phantom_vbd", path, e_danger[i]) == -1)
+ continue;
+ free(danger_fpath);
+ danger_fpath = xs_read(xsh, XBT_NULL, danger_buf, &len);
+ if (danger_fpath) {
+ if (pasprintf(&danger_buf, "%s/dev", danger_fpath) == -1)
+ continue;
+ free(params);
+ params_danger = xs_read(xsh, XBT_NULL, danger_buf , &len);
+ DANGER DANGER params is supposedly trustworthy but here
+ we read it from untrusted part of xenstore
+ if (params) {
+ /*
+ * wait for device, on timeout silently fail because we will
+ * fail to open below
+ */
+ waitForDevice(params);
+ }
+ }
+#endif
+
+ bs = bdrv_new(dev);
+ /* check if it is a cdrom */
+ if (danger_type && !strcmp(danger_type, "cdrom")) {
+ bdrv_set_type_hint(bs, BDRV_TYPE_CDROM);
+ if (pasprintf(&buf, "%s/params", bpath) != -1)
+ xs_watch(xsh, buf, dev);
+ }
+
+ /* open device now if media present */
+#ifdef CONFIG_STUBDOM
+ if (pasprintf(&danger_buf, "%s/device/vbd/%s", danger_path, e_danger[i]) == -1)
+ continue;
+ if (bdrv_open2(bs, danger_buf, 0 /* snapshot */, &bdrv_vbd) == 0) {
+ pstrcpy(bs->filename, sizeof(bs->filename), params);
+ } else
+#endif
+
+ if (params[0]) {
+ if (!format) {
+ if (!drv) {
+ fprintf(stderr, "qemu: type (image format) not specified for vbd '%s' or image '%s'\n", buf, params);
+ continue;
+ }
+ if (!strcmp(drv,"qcow")) {
+ /* autoguess qcow vs qcow2 */
+ } else if (!strcmp(drv,"file")) {
+ format = &bdrv_raw;
+ } else if (!strcmp(drv,"phy")) {
+ format = &bdrv_raw;
+ } else {
+ format = bdrv_find_format(drv);
+ if (!format) {
+ fprintf(stderr, "qemu: type (image format) '%s' unknown for vbd '%s' or image '%s'\n", drv, buf, params);
+ continue;
+ }
+ }
+ }
+ pstrcpy(bs->filename, sizeof(bs->filename), params);
+ if (bdrv_open2(bs, params, 0 /* snapshot */, format) < 0)
+ fprintf(stderr, "qemu: could not open vbd '%s' or hard disk image '%s' (drv '%s' format '%s')\n", buf, params, drv ? drv : "?", format ? format->format_name : "0");
+ }
+
+ drives_table[nb_drives].bdrv = bs;
+ nb_drives++;
+
+ }
+
+#ifdef CONFIG_STUBDOM
+ if (pasprintf(&danger_buf, "%s/device/vkbd", danger_path) == -1)
+ goto out;
+
+ free(e_danger);
+ e_danger = xs_directory(xsh, XBT_NULL, danger_buf, &num);
+
+ if (e_danger) {
+ for (i = 0; i < num; i++) {
+ if (pasprintf(&danger_buf, "%s/device/vkbd/%s", danger_path, e_danger[i]) == -1)
+ continue;
+ xenfb_connect_vkbd(danger_buf);
+ }
+ }
+
+ if (pasprintf(&danger_buf, "%s/device/vfb", danger_path) == -1)
+ goto out;
+
+ free(e_danger);
+ e_danger = xs_directory(xsh, XBT_NULL, danger_buf, &num);
+
+ if (e_danger) {
+ for (i = 0; i < num; i++) {
+ if (pasprintf(&danger_buf, "%s/device/vfb/%s", danger_path, e_danger[i]) == -1)
+ continue;
+ xenfb_connect_vfb(danger_buf);
+ }
+ }
+#endif
+
+
+ /* Set a watch for log-dirty requests from the migration tools */
+ if (pasprintf(&buf, "/local/domain/0/device-model/%u/logdirty/next-active",
+ domid) != -1) {
+ xs_watch(xsh, buf, "logdirty");
+ fprintf(logfile, "Watching %s\n", buf);
+ }
+
+ /* Set a watch for suspend requests from the migration tools */
+ if (pasprintf(&buf,
+ "/local/domain/0/device-model/%u/command", domid) != -1) {
+ xs_watch(xsh, buf, "dm-command");
+ fprintf(logfile, "Watching %s\n", buf);
+ }
+
+ /* get the pci pass-through parameter */
+ if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/num_devs",
+ hvm_domid, pci_devid) == -1)
+ goto out;
+
+ free(params);
+ params = xs_read(xsh, XBT_NULL, buf, &len);
+ if (params == NULL)
+ goto out;
+ num = atoi(params);
+
+ for ( i = 0; i < num; i++ ) {
+ if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/dev-%d",
+ hvm_domid, pci_devid, i) != -1) {
+ free(dev);
+ dev = xs_read(xsh, XBT_NULL, buf, &len);
+
+ if ( strlen(dev) + strlen(direct_pci_str) > DIRECT_PCI_STR_LEN ) {
+ fprintf(stderr, "qemu: too many pci pass-through devices\n");
+ memset(direct_pci_str, 0, DIRECT_PCI_STR_LEN);
+ goto out;
+ }
+
+ /* append to direct_pci_str */
+ if ( dev ) {
+ strcat(direct_pci_str, dev);
+ strcat(direct_pci_str, "-");
+ }
+ }
+ }
+
+ out:
+ free(danger_type);
+ free(params);
+ free(dev);
+ free(bpath);
+ free(buf);
+ free(danger_buf);
+ free(danger_path);
+ free(e_danger);
+ free(drv);
+ return;
+}
+
+int xenstore_fd(void)
+{
+ if (xsh)
+ return xs_fileno(xsh);
+ return -1;
+}
+
+void xenstore_process_logdirty_event(void)
+{
+#ifdef CONFIG_STUBDOM
+ /* XXX we just can't use shm. */
+ return;
+#else
+ char *act;
+ static char *active_path = NULL;
+ static char *next_active_path = NULL;
+ static char *seg = NULL;
+ unsigned int len;
+ int i;
+
+ if (!seg) {
+ char *path = NULL, *key_ascii, key_terminated[17] = {0,};
+ key_t key;
+ int shmid;
+
+ /* Find and map the shared memory segment for log-dirty bitmaps */
+ if (pasprintf(&path,
+ "/local/domain/0/device-model/%u/logdirty/key",
+ domid) == -1) {
+ fprintf(logfile, "Log-dirty: out of memory\n");
+ exit(1);
+ }
+
+ key_ascii = xs_read(xsh, XBT_NULL, path, &len);
+ free(path);
+
+ if (!key_ascii)
+ /* No key yet: wait for the next watch */
+ return;
+
+ strncpy(key_terminated, key_ascii, 16);
+ free(key_ascii);
+ key = (key_t) strtoull(key_terminated, NULL, 16);
+
+ /* Figure out how bit the log-dirty bitmaps are */
+ logdirty_bitmap_size = xc_memory_op(xc_handle,
+ XENMEM_maximum_gpfn, &domid) + 1;
+ logdirty_bitmap_size = ((logdirty_bitmap_size + HOST_LONG_BITS - 1)
+ / HOST_LONG_BITS); /* longs */
+ logdirty_bitmap_size *= sizeof (unsigned long); /* bytes */
+
+ /* Map the shared-memory segment */
+ fprintf(logfile, "%s: key=%16.16llx size=%lu\n", __FUNCTION__,
+ (unsigned long long)key, logdirty_bitmap_size);
+ shmid = shmget(key, 2 * logdirty_bitmap_size, S_IRUSR|S_IWUSR);
+ if (shmid == -1) {
+ fprintf(logfile, "Log-dirty: shmget failed: segment %16.16llx "
+ "(%s)\n", (unsigned long long)key, strerror(errno));
+ exit(1);
+ }
+
+ seg = shmat(shmid, NULL, 0);
+ if (seg == (void *)-1) {
+ fprintf(logfile, "Log-dirty: shmat failed: segment %16.16llx "
+ "(%s)\n", (unsigned long long)key, strerror(errno));
+ exit(1);
+ }
+
+ fprintf(logfile, "Log-dirty: mapped segment at %p\n", seg);
+
+ /* Double-check that the bitmaps are the size we expect */
+ if (logdirty_bitmap_size != *(uint32_t *)seg) {
+ fprintf(logfile, "Log-dirty: got %u, calc %lu\n",
+ *(uint32_t *)seg, logdirty_bitmap_size);
+ /* Stale key: wait for next watch */
+ shmdt(seg);
+ seg = NULL;
+ return;
+ }
+
+ /* Remember the paths for the next-active and active entries */
+ if (pasprintf(&active_path,
+ "/local/domain/0/device-model/%u/logdirty/active",
+ domid) == -1) {
+ fprintf(logfile, "Log-dirty: out of memory\n");
+ exit(1);
+ }
+ if (pasprintf(&next_active_path,
+ "/local/domain/0/device-model/%u/logdirty/next-active",
+ domid) == -1) {
+ fprintf(logfile, "Log-dirty: out of memory\n");
+ exit(1);
+ }
+ }
+
+ fprintf(logfile, "Triggered log-dirty buffer switch\n");
+
+ /* Read the required active buffer from the store */
+ act = xs_read(xsh, XBT_NULL, next_active_path, &len);
+ if (!act) {
+ fprintf(logfile, "Log-dirty: can't read next-active\n");
+ exit(1);
+ }
+
+ /* Switch buffers */
+ i = act[0] - '0';
+ if (i != 0 && i != 1) {
+ fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act);
+ exit(1);
+ }
+ logdirty_bitmap = (unsigned long *)(seg + i * logdirty_bitmap_size);
+
+ /* Ack that we've switched */
+ xs_write(xsh, XBT_NULL, active_path, act, len);
+ free(act);
+#endif
+}
+
+
+/* Accept state change commands from the control tools */
+static void xenstore_process_dm_command_event(void)
+{
+ char *path = NULL, *command = NULL, *par = NULL;
+ unsigned int len;
+
+ if (pasprintf(&path,
+ "/local/domain/0/device-model/%u/command", domid) == -1) {
+ fprintf(logfile, "out of memory reading dm command\n");
+ goto out;
+ }
+ command = xs_read(xsh, XBT_NULL, path, &len);
+ if (!command)
+ goto out;
+
+ if (!strncmp(command, "save", len)) {
+ fprintf(logfile, "dm-command: pause and save state\n");
+ xen_pause_requested = 1;
+ } else if (!strncmp(command, "continue", len)) {
+ fprintf(logfile, "dm-command: continue after state save\n");
+ xen_pause_requested = 0;
+#ifdef CONFIG_PASSTHROUGH
+ } else if (!strncmp(command, "pci-rem", len)) {
+ fprintf(logfile, "dm-command: hot remove pass-through pci dev \n");
+
+ if (pasprintf(&path,
+ "/local/domain/0/device-model/%u/parameter", domid) == -1) {
+ fprintf(logfile, "out of memory reading dm command parameter\n");
+ goto out;
+ }
+ par = xs_read(xsh, XBT_NULL, path, &len);
+ if (!par)
+ goto out;
+
+ do_pci_del(par);
+ free(par);
+ } else if (!strncmp(command, "pci-ins", len)) {
+ fprintf(logfile, "dm-command: hot insert pass-through pci dev \n");
+
+ if (pasprintf(&path,
+ "/local/domain/0/device-model/%u/parameter", domid) == -1) {
+ fprintf(logfile, "out of memory reading dm command parameter\n");
+ goto out;
+ }
+ par = xs_read(xsh, XBT_NULL, path, &len);
+ if (!par)
+ goto out;
+
+ do_pci_add(par);
+ free(par);
+#endif
+ } else {
+ fprintf(logfile, "dm-command: unknown command\"%*s\"\n", len, command);
+ }
+
+ out:
+ free(path);
+ free(command);
+}
+
+void xenstore_record_dm(char *subpath, char *state)
+{
+ char *path = NULL;
+
+ if (pasprintf(&path,
+ "/local/domain/0/device-model/%u/%s", domid, subpath) == -1) {
+ fprintf(logfile, "out of memory recording dm \n");
+ goto out;
+ }
+ if (!xs_write(xsh, XBT_NULL, path, state, strlen(state)))
+ fprintf(logfile, "error recording dm \n");
+
+ out:
+ free(path);
+}
+
+void xenstore_record_dm_state(char *state)
+{
+ xenstore_record_dm("state", state);
+}
+
+void xenstore_process_event(void *opaque)
+{
+ char **vec, *offset, *bpath = NULL, *buf = NULL, *drv = NULL, *image = NULL;
+ unsigned int len, num, hd_index;
+
+ vec = xs_read_watch(xsh, &num);
+ if (!vec)
+ return;
+
+ if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
+ xenstore_process_logdirty_event();
+ goto out;
+ }
+
+ if (!strcmp(vec[XS_WATCH_TOKEN], "dm-command")) {
+ xenstore_process_dm_command_event();
+ goto out;
+ }
+
+ if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
+ strlen(vec[XS_WATCH_TOKEN]) != 3)
+ goto out;
+
+ hd_index = drive_name_to_index(vec[XS_WATCH_TOKEN]);
+ if (hd_index == -1) {
+ fprintf(stderr,"medium change watch on `%s' -"
+ " unknown device, ignored\n", vec[XS_WATCH_TOKEN]);
+ goto out;
+ }
+
+ image = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len);
+
+ fprintf(stderr,"medium change watch on `%s' (index: %d): %s\n",
+ vec[XS_WATCH_TOKEN], hd_index, image ? image : "<none>");
+
+ if (image == NULL)
+ goto out; /* gone */
+
+ /* Strip off blktap sub-type prefix */
+ bpath = strdup(vec[XS_WATCH_PATH]);
+ if (bpath == NULL)
+ goto out;
+ if ((offset = strrchr(bpath, '/')) != NULL)
+ *offset = '\0';
+ if (pasprintf(&buf, "%s/type", bpath) == -1)
+ goto out;
+ drv = xs_read(xsh, XBT_NULL, buf, &len);
+ if (drv && !strcmp(drv, "tap") && ((offset = strchr(image, ':')) != NULL))
+ memmove(image, offset+1, strlen(offset+1)+1);
+
+ if (!strcmp(image, drives_table[hd_index].bdrv->filename))
+ goto out; /* identical */
+
+ drives_table[hd_index].bdrv->filename[0] = '\0';
+ bdrv_close(drives_table[hd_index].bdrv);
+ if (media_filename[hd_index]) {
+ free(media_filename[hd_index]);
+ media_filename[hd_index] = NULL;
+ }
+
+ if (image[0]) {
+ media_filename[hd_index] = strdup(image);
+ xenstore_check_new_media_present(5000);
+ }
+
+ out:
+ free(drv);
+ free(buf);
+ free(bpath);
+ free(image);
+ free(vec);
+}
+
+void xenstore_write_vncport(int display)
+{
+ char *buf = NULL, *path;
+ char *portstr = NULL;
+
+ if (xsh == NULL)
+ return;
+
+ path = xs_get_domain_path(xsh, domid);
+ if (path == NULL) {
+ fprintf(logfile, "xs_get_domain_path() error\n");
+ goto out;
+ }
+
+ if (pasprintf(&buf, "%s/console/vnc-port", path) == -1)
+ goto out;
+
+ if (pasprintf(&portstr, "%d", display) == -1)
+ goto out;
+
+ if (xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)) == 0)
+ fprintf(logfile, "xs_write() vncport failed\n");
+
+ out:
+ free(portstr);
+ free(buf);
+}
+
+void xenstore_write_vslots(char *vslots)
+{
+ char *path = NULL;
+ int pci_devid = 0;
+
+ if (pasprintf(&path,
+ "/local/domain/0/backend/pci/%u/%u/vslots", domid, pci_devid) == -1) {
+ fprintf(logfile, "out of memory when updating vslots.\n");
+ goto out;
+ }
+ if (!xs_write(xsh, XBT_NULL, path, vslots, strlen(vslots)))
+ fprintf(logfile, "error updating vslots \n");
+
+ out:
+ free(path);
+}
+
+void xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen)
+{
+ char *buf = NULL, *path, *uuid = NULL, *passwd = NULL;
+ unsigned int i, len;
+
+ pwbuf[0] = '\0';
+
+ if (xsh == NULL)
+ return;
+
+ path = xs_get_domain_path(xsh, domid);
+ if (path == NULL) {
+ fprintf(logfile, "xs_get_domain_path() error. domid %d.\n", domid);
+ return;
+ }
+
+ pasprintf(&buf, "%s/vm", path);
+ free(path);
+ uuid = xs_read(xsh, XBT_NULL, buf, &len);
+ if (uuid == NULL) {
+ fprintf(logfile, "xs_read(): uuid get error. %s.\n", buf);
+ free(buf);
+ return;
+ }
+
+ pasprintf(&buf, "%s/vncpasswd", uuid);
+ free(uuid);
+ passwd = xs_read(xsh, XBT_NULL, buf, &len);
+ if (passwd == NULL) {
+ fprintf(logfile, "xs_read(): vncpasswd get error. %s.\n", buf);
+ free(buf);
+ return;
+ }
+
+ if (len >= pwbuflen)
+ {
+ fprintf(logfile, "xenstore_read_vncpasswd(): truncated password to avoid buffer overflow\n");
+ len = pwbuflen - 1;
+ }
+
+ for (i=0; i<len; i++)
+ pwbuf[i] = passwd[i];
+ pwbuf[len] = '\0';
+ passwd[0] = '\0';
+ if (xs_write(xsh, XBT_NULL, buf, passwd, 1) == 0)
+ fprintf(logfile, "xs_write() vncpasswd failed.\n");
+
+ free(passwd);
+ free(buf);
+}
+
+
+/*
+ * get all device instances of a certain type
+ */
+char **xenstore_domain_get_devices_danger(struct xs_handle *handle,
+ const char *devtype, unsigned int *num)
+{
+ char *path;
+ char *buf = NULL;
+ char **e = NULL;
+
+ path = xs_get_domain_path(handle, domid);
+ if (path == NULL)
+ goto out;
+
+ if (pasprintf(&buf, "%s/device/%s", path,devtype) == -1)
+ goto out;
+
+ e = xs_directory(handle, XBT_NULL, buf, num);
+
+ out:
+ free(path);
+ free(buf);
+ return e;
+}
+
+/*
+ * Check whether a domain has devices of the given type
+ */
+int xenstore_domain_has_devtype_danger(struct xs_handle *handle,
+ const char *devtype)
+{
+ int rc = 0;
+ unsigned int num;
+ char **e = xenstore_domain_get_devices_danger(handle, devtype, &num);
+ if (e)
+ rc = 1;
+ free(e);
+ return rc;
+}
+
+/*
+ * Function that creates a path to a variable of an instance of a
+ * certain device
+ */
+static char *get_device_variable_path(const char *devtype,
+ const char *inst_danger,
+ const char *var)
+{
+ char *buf = NULL;
+ if (strchr(inst_danger,'/')) {
+ fprintf(logfile, "get_device_variable_path inst_danger has slash"
+ " which is forbidden (devtype %s)\n", devtype);
+ return NULL;
+ }
+
+ if (pasprintf(&buf, "/local/domain/%d/backend/%s/%d/%s/%s",
+ domid_backend,
+ devtype,
+ domid,
+ inst_danger /* safe now */,
+ var) == -1) {
+ free(buf);
+ buf = NULL;
+ }
+ return buf;
+}
+
+char *xenstore_backend_read_variable(struct xs_handle *handle,
+ const char *devtype,
+ const char *inst_danger,
+ const char *var)
+{
+ char *value = NULL;
+ char *buf = NULL;
+ unsigned int len;
+
+ buf = get_device_variable_path(devtype, inst_danger, var);
+ if (NULL == buf)
+ goto out;
+
+ value = xs_read(handle, XBT_NULL, buf, &len);
+
+ free(buf);
+
+ out:
+ return value;
+}
+
+/*
+ Read the hotplug status variable from the backend given the type
+ of device and its instance.
+*/
+char *xenstore_read_hotplug_status(struct xs_handle *handle,
+ const char *devtype,
+ const char *inst_danger)
+{
+ return xenstore_backend_read_variable(handle, devtype, inst_danger,
+ "hotplug-status");
+}
+
+/*
+ Subscribe to the hotplug status of a device given the type of device and
+ its instance.
+ In case an error occurrs, a negative number is returned.
+ */
+int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle,
+ const char *devtype,
+ const char *inst_danger,
+ const char *token)
+{
+ int rc = 0;
+ char *path = get_device_variable_path(devtype, inst_danger, "hotplug-status");
+
+ if (path == NULL)
+ return -1;
+
+ if (0 == xs_watch(handle, path, token))
+ rc = -2;
+
+ free(path);
+
+ return rc;
+}
+
+/*
+ * Unsubscribe from a subscription to the status of a hotplug variable of
+ * a device.
+ */
+int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle,
+ const char *devtype,
+ const char *inst_danger,
+ const char *token)
+{
+ int rc = 0;
+ char *path;
+ path = get_device_variable_path(devtype, inst_danger, "hotplug-status");
+ if (path == NULL)
+ return -1;
+
+ if (0 == xs_unwatch(handle, path, token))
+ rc = -2;
+
+ free(path);
+
+ return rc;
+}
+
+static char *xenstore_vm_key_path(int domid, char *key) {
+ const char *uuid;
+ char *buf = NULL;
+
+ if (xsh == NULL)
+ return NULL;
+
+ uuid = xenstore_get_guest_uuid();
+ if (!uuid) return NULL;
+
+ if (pasprintf(&buf, "/vm/%s/%s", uuid, key) == -1)
+ return NULL;
+ return buf;
+}
+
+char *xenstore_vm_read(int domid, char *key, unsigned int *len)
+{
+ char *path = NULL, *value = NULL;
+
+ path = xenstore_vm_key_path(domid, key);
+
+ value = xs_read(xsh, XBT_NULL, path, len);
+ if (value == NULL) {
+ fprintf(logfile, "xs_read(%s): read error\n", path);
+ goto out;
+ }
+
+ out:
+ free(path);
+ return value;
+}
+
+int xenstore_vm_write(int domid, char *key, char *value)
+{
+ char *path = NULL;
+ int rc = -1;
+
+ path = xenstore_vm_key_path(domid, key);
+
+ rc = xs_write(xsh, XBT_NULL, path, value, strlen(value));
+ if (rc == 0) {
+ fprintf(logfile, "xs_write(%s, %s): write error\n", path, key);
+ goto out;
+ }
+
+ out:
+ free(path);
+ return rc;
+}
+
+
+/*
+ * Create a store entry for a device (e.g., monitor, serial/parallel lines).
+ * The entry is <domain-path><storeString>/tty and the value is the name
+ * of the pty associated with the device.
+ */
+static int store_dev_info(const char *devName, int domid,
+ CharDriverState *cState, const char *storeString)
+{
+#ifdef CONFIG_STUBDOM
+ fprintf(logfile, "can't store dev %s name for domid %d in %s from a stub domain\n", devName, domid, storeString);
+ return ENOSYS;
+#else
+ int xc_handle;
+ struct xs_handle *xs;
+ char *path;
+ char *newpath;
+ char *pts;
+ char namebuf[128];
+ int ret;
+
+ /*
+ * Only continue if we're talking to a pty
+ */
+ if (!cState->chr_getname) return 0;
+ ret = cState->chr_getname(cState, namebuf, sizeof(namebuf));
+ if (ret < 0) {
+ fprintf(logfile, "ptsname failed (for '%s'): %s\n",
+ storeString, strerror(errno));
+ return 0;
+ }
+ if (memcmp(namebuf, "pty ", 4)) return 0;
+ pts = namebuf + 4;
+
+ /* We now have everything we need to set the xenstore entry. */
+ xs = xs_daemon_open();
+ if (xs == NULL) {
+ fprintf(logfile, "Could not contact XenStore\n");
+ return -1;
+ }
+
+ xc_handle = xc_interface_open();
+ if (xc_handle == -1) {
+ fprintf(logfile, "xc_interface_open() error\n");
+ return -1;
+ }
+
+ path = xs_get_domain_path(xs, domid);
+ if (path == NULL) {
+ fprintf(logfile, "xs_get_domain_path() error\n");
+ return -1;
+ }
+ newpath = realloc(path, (strlen(path) + strlen(storeString) +
+ strlen("/tty") + 1));
+ if (newpath == NULL) {
+ free(path); /* realloc errors leave old block */
+ fprintf(logfile, "realloc error\n");
+ return -1;
+ }
+ path = newpath;
+
+ strcat(path, storeString);
+ strcat(path, "/tty");
+ if (!xs_write(xs, XBT_NULL, path, pts, strlen(pts))) {
+ fprintf(logfile, "xs_write for '%s' fail", storeString);
+ return -1;
+ }
+
+ free(path);
+ xs_daemon_close(xs);
+ close(xc_handle);
+
+ return 0;
+#endif
+}
+
+void xenstore_store_serial_port_info(int i, CharDriverState *chr,
+ const char *devname) {
+ char buf[16];
+
+ snprintf(buf, sizeof(buf), "/serial/%d", i);
+ store_dev_info(devname, domid, chr, buf);
+ if (i == 0) /* serial 0 is also called the console */
+ store_dev_info(devname, domid, chr, "/console");
+}