summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2009-02-02 16:56:18 +0200
committerAvi Kivity <avi@redhat.com>2009-02-02 16:56:18 +0200
commit57ba4c938c1cb6e8cd7501338c9dbcbb62575a05 (patch)
tree5495664032071b4593959b9dd911e3d891830b54
parentkvm: external module: compatibility for hrtimer_expires_remaining() (diff)
parentReplace noreturn with QEMU_NORETURN (diff)
downloadqemu-kvm-57ba4c938c1cb6e8cd7501338c9dbcbb62575a05.tar.gz
qemu-kvm-57ba4c938c1cb6e8cd7501338c9dbcbb62575a05.tar.bz2
qemu-kvm-57ba4c938c1cb6e8cd7501338c9dbcbb62575a05.zip
Merge branch 'qemu-cvs'
Conflicts: qemu/hw/pci.c qemu/hw/virtio-blk.c qemu/target-i386/machine.c qemu/vl.c Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--.gitignore2
-rw-r--r--Makefile6
-rw-r--r--Makefile.target2
-rw-r--r--audio/audio.c3
-rw-r--r--audio/dsound_template.h2
-rw-r--r--block-qcow2.c55
-rw-r--r--block-raw-posix.c38
-rw-r--r--block-vpc.c512
-rw-r--r--block.c76
-rw-r--r--block.h10
-rw-r--r--bsd-user/mmap.c15
-rwxr-xr-xconfigure16
-rw-r--r--console.c81
-rw-r--r--console.h3
-rw-r--r--cpu-all.h55
-rw-r--r--cutils.c54
-rw-r--r--darwin-user/signal.c2
-rw-r--r--exec-all.h2
-rw-r--r--exec.c144
-rw-r--r--fpu/softfloat-native.c2
-rw-r--r--gdb-xml/power-altivec.xml57
-rw-r--r--gdb-xml/power-core.xml49
-rw-r--r--gdb-xml/power-fpu.xml44
-rw-r--r--gdb-xml/power-spe.xml45
-rw-r--r--gdb-xml/power64-core.xml49
-rw-r--r--gdbstub.c34
-rw-r--r--hw/ac97.c10
-rw-r--r--hw/acpi.c9
-rw-r--r--hw/apb_pci.c15
-rw-r--r--hw/axis_dev88.c2
-rw-r--r--hw/cirrus_vga.c12
-rw-r--r--hw/e1000.c7
-rw-r--r--hw/eepro100.c7
-rw-r--r--hw/es1370.c9
-rw-r--r--hw/fdc.c30
-rw-r--r--hw/fmopl.c2
-rw-r--r--hw/grackle_pci.c18
-rw-r--r--hw/gt64xxx.c9
-rw-r--r--hw/i8254.c3
-rw-r--r--hw/ide.c332
-rw-r--r--hw/lsi53c895a.c19
-rw-r--r--hw/mac_dbdma.c824
-rw-r--r--hw/mac_dbdma.h41
-rw-r--r--hw/macio.c9
-rw-r--r--hw/mc146818rtc.c16
-rw-r--r--hw/mips_jazz.c2
-rw-r--r--hw/mips_malta.c8
-rw-r--r--hw/mips_r4k.c8
-rw-r--r--hw/ne2000.c9
-rw-r--r--hw/openpic.c9
-rw-r--r--hw/pc.c2
-rw-r--r--hw/pc.h5
-rw-r--r--hw/pci.c13
-rw-r--r--hw/pci.h120
-rw-r--r--hw/pcnet.c7
-rw-r--r--hw/piix_pci.c27
-rw-r--r--hw/pl031.c1
-rw-r--r--hw/ppc4xx_pci.c11
-rw-r--r--hw/ppc_chrp.c13
-rw-r--r--hw/ppc_mac.h6
-rw-r--r--hw/ppc_oldworld.c29
-rw-r--r--hw/ppc_prep.c2
-rw-r--r--hw/prep_pci.c9
-rw-r--r--hw/ps2.c1
-rw-r--r--hw/r2d.c6
-rw-r--r--hw/rtl8139.c13
-rw-r--r--hw/scsi-disk.c168
-rw-r--r--hw/sh_pci.c25
-rw-r--r--hw/sun4u.c9
-rw-r--r--hw/unin_pci.c36
-rw-r--r--hw/usb-ohci.c11
-rw-r--r--hw/usb-uhci.c18
-rw-r--r--hw/versatile_pci.c9
-rw-r--r--hw/vga.c37
-rw-r--r--hw/virtio-balloon.c5
-rw-r--r--hw/virtio-blk.c175
-rw-r--r--hw/virtio-console.c8
-rw-r--r--hw/virtio-net.c9
-rw-r--r--hw/virtio.c17
-rw-r--r--hw/virtio.h5
-rw-r--r--hw/vmware_vga.c17
-rw-r--r--linux-user/envlist.c247
-rw-r--r--linux-user/envlist.h22
-rw-r--r--linux-user/main.c53
-rw-r--r--linux-user/mmap.c15
-rw-r--r--linux-user/path.c2
-rw-r--r--linux-user/qemu.h1
-rw-r--r--linux-user/signal.c10
-rw-r--r--linux-user/syscall.c75
-rw-r--r--linux-user/syscall_defs.h7
-rw-r--r--monitor.c12
-rw-r--r--net.c15
-rw-r--r--pci-ids.txt3
-rw-r--r--posix-aio-compat.c2
-rw-r--r--posix-aio-compat.h2
-rw-r--r--qemu-char.c4
-rw-r--r--qemu-common.h19
-rw-r--r--qemu-doc.texi530
-rw-r--r--qemu-img.c29
-rw-r--r--qemu-img.texi26
-rw-r--r--rules.mak12
-rw-r--r--sdl.c10
-rw-r--r--slirp/COPYRIGHT3
-rw-r--r--slirp/bootp.c2
-rw-r--r--slirp/cksum.c6
-rw-r--r--slirp/icmp_var.h6
-rw-r--r--slirp/ip.h6
-rw-r--r--slirp/ip_icmp.c6
-rw-r--r--slirp/ip_icmp.h6
-rw-r--r--slirp/ip_input.c6
-rw-r--r--slirp/ip_output.c6
-rw-r--r--slirp/mbuf.h6
-rw-r--r--slirp/tcp.h6
-rw-r--r--slirp/tcp_input.c6
-rw-r--r--slirp/tcp_output.c6
-rw-r--r--slirp/tcp_subr.c6
-rw-r--r--slirp/tcp_timer.c6
-rw-r--r--slirp/tcp_timer.h6
-rw-r--r--slirp/tcp_var.h6
-rw-r--r--slirp/tcpip.h6
-rw-r--r--slirp/udp.c6
-rw-r--r--slirp/udp.h6
-rw-r--r--sysemu.h6
-rw-r--r--target-arm/helper.c6
-rw-r--r--target-cris/mmu.h1
-rw-r--r--target-cris/translate.c7
-rw-r--r--target-i386/cpu.h32
-rw-r--r--target-i386/exec.h4
-rw-r--r--target-i386/helper.c7
-rw-r--r--target-i386/kvm.c4
-rw-r--r--target-i386/machine.c23
-rw-r--r--target-i386/op_helper.c108
-rw-r--r--target-m68k/helper.c5
-rw-r--r--target-mips/translate.c5
-rw-r--r--target-ppc/helper.c8
-rw-r--r--target-ppc/kvm_ppc.c2
-rw-r--r--target-ppc/kvm_ppc.h2
-rw-r--r--target-ppc/translate_init.c133
-rw-r--r--target-sh4/translate.c5
-rw-r--r--target-sparc/helper.c5
-rw-r--r--tcg/ppc/tcg-target.c5
-rw-r--r--vl.c343
-rw-r--r--vnc.c22
143 files changed, 4370 insertions, 1154 deletions
diff --git a/.gitignore b/.gitignore
index 6fdc7e701..773ce5128 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,7 +30,9 @@ qemu-nbd.pod
*.tp
*.vr
*.d
+*.o
.pc
patches
pc-bios/bios-pq/status
pc-bios/vgabios-pq/status
+.stgit-*
diff --git a/Makefile b/Makefile
index 648b84903..6b78adba9 100644
--- a/Makefile
+++ b/Makefile
@@ -39,7 +39,7 @@ all: $(TOOLS) $(DOCS) recurse-all
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
subdir-%:
- $(MAKE) -C $(subst subdir-,,$@) V="$(V)" all
+ $(call quiet-command,$(MAKE) -C $* V="$(V)" TARGET_DIR="$*/" all,)
$(filter %-softmmu,$(SUBDIR_RULES)): libqemu_common.a
$(filter %-user,$(SUBDIR_RULES)): libqemu_user.a
@@ -229,9 +229,9 @@ install-doc: $(DOCS)
$(INSTALL) -m 644 qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)"
ifndef CONFIG_WIN32
mkdir -p "$(DESTDIR)$(mandir)/man1"
- $(INSTALL) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
+ $(INSTALL) -m 644 qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
mkdir -p "$(DESTDIR)$(mandir)/man8"
- $(INSTALL) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
+ $(INSTALL) -m 644 qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
endif
install: all $(if $(BUILD_DOCS),install-doc)
diff --git a/Makefile.target b/Makefile.target
index 8f69af736..308191b7a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -369,7 +369,7 @@ CFLAGS+=-p
endif
OBJS= main.o syscall.o strace.o mmap.o signal.o path.o thunk.o \
- elfload.o linuxload.o uaccess.o
+ elfload.o linuxload.o uaccess.o envlist.o
LIBS+= $(AIOLIBS)
ifdef TARGET_HAS_BFLT
OBJS+= flatload.o
diff --git a/audio/audio.c b/audio/audio.c
index 762c2e342..e2635c001 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1622,7 +1622,8 @@ static int audio_driver_init (AudioState *s, struct audio_driver *drv)
}
}
-static void audio_vm_change_state_handler (void *opaque, int running)
+static void audio_vm_change_state_handler (void *opaque, int running,
+ int reason)
{
AudioState *s = opaque;
HWVoiceOut *hwo = NULL;
diff --git a/audio/dsound_template.h b/audio/dsound_template.h
index a594f080a..8b37d16a8 100644
--- a/audio/dsound_template.h
+++ b/audio/dsound_template.h
@@ -285,7 +285,9 @@ static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
}
#undef NAME
+#undef NAME2
#undef TYPE
#undef IFACE
#undef BUFPTR
#undef FIELD
+#undef FIELD2
diff --git a/block-qcow2.c b/block-qcow2.c
index d4556efa4..8a5b621de 100644
--- a/block-qcow2.c
+++ b/block-qcow2.c
@@ -143,6 +143,10 @@ typedef struct BDRVQcowState {
uint32_t crypt_method_header;
AES_KEY aes_encrypt_key;
AES_KEY aes_decrypt_key;
+
+ int64_t highest_alloc; /* highest cluester allocated (in clusters) */
+ int64_t nc_free; /* num of free clusters below highest_alloc */
+
uint64_t snapshots_offset;
int snapshots_size;
int nb_snapshots;
@@ -170,6 +174,8 @@ static void free_clusters(BlockDriverState *bs,
#ifdef DEBUG_ALLOC
static void check_refcounts(BlockDriverState *bs);
#endif
+static void scan_refcount(BlockDriverState *bs, int64_t *high, int64_t *free);
+
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
{
@@ -278,6 +284,8 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
if (refcount_init(bs) < 0)
goto fail;
+ scan_refcount(bs, &s->highest_alloc, &s->nc_free);
+
/* read the backing file name */
if (header.backing_file_offset != 0) {
len = header.backing_file_size;
@@ -1664,6 +1672,8 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
bdi->cluster_size = s->cluster_size;
bdi->vm_state_offset = (int64_t)s->l1_vm_state_index <<
(s->cluster_bits + s->l2_bits);
+ bdi->highest_alloc = s->highest_alloc << s->cluster_bits;
+ bdi->num_free_bytes = s->nc_free << s->cluster_bits;
return 0;
}
@@ -2206,6 +2216,39 @@ static int load_refcount_block(BlockDriverState *bs,
return 0;
}
+static void scan_refcount(BlockDriverState *bs, int64_t *high, int64_t *free)
+{
+ BDRVQcowState *s = bs->opaque;
+ int64_t refcnt_index, cluster_index, cluster_end, h = 0, f = 0;
+ int64_t tail = 0; /* do not count last consecutive free entries */
+
+ for (refcnt_index=0; refcnt_index < s->refcount_table_size; refcnt_index++){
+ if (s->refcount_table[refcnt_index] == 0) {
+ f += 1 << (s->cluster_bits - REFCOUNT_SHIFT);
+ tail += 1 << (s->cluster_bits - REFCOUNT_SHIFT);
+ continue;
+ }
+ cluster_index = refcnt_index << (s->cluster_bits - REFCOUNT_SHIFT);
+ cluster_end = (refcnt_index + 1) << (s->cluster_bits - REFCOUNT_SHIFT);
+ for ( ; cluster_index < cluster_end; cluster_index++) {
+ if (get_refcount(bs, cluster_index) == 0) {
+ f++;
+ tail++;
+ }
+ else {
+ h = cluster_index;
+ tail = 0;
+ }
+ }
+ }
+
+ f -= tail;
+ if (free)
+ *free = f;
+ if (high)
+ *high = (h+1);
+}
+
static int get_refcount(BlockDriverState *bs, int64_t cluster_index)
{
BDRVQcowState *s = bs->opaque;
@@ -2246,6 +2289,12 @@ retry:
size,
(s->free_cluster_index - nb_clusters) << s->cluster_bits);
#endif
+
+ if (s->highest_alloc < s->free_cluster_index) {
+ s->nc_free += (s->free_cluster_index - s->highest_alloc);
+ s->highest_alloc = s->free_cluster_index;
+ }
+
return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
}
@@ -2421,6 +2470,12 @@ static int update_cluster_refcount(BlockDriverState *bs,
block_index = cluster_index &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
+
+ if (refcount == 1 && addend == -1)
+ s->nc_free += 1;
+ else if (refcount == 0 && addend == 1)
+ s->nc_free -= 1;
+
refcount += addend;
if (refcount < 0 || refcount > 0xffff)
return -EINVAL;
diff --git a/block-raw-posix.c b/block-raw-posix.c
index 0c2578770..50685b6ff 100644
--- a/block-raw-posix.c
+++ b/block-raw-posix.c
@@ -577,7 +577,7 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
if (!acb)
return NULL;
acb->aiocb.aio_fildes = s->fd;
- acb->aiocb.sigev_signo = SIGUSR2;
+ acb->aiocb.ev_signo = SIGUSR2;
acb->aiocb.aio_buf = buf;
if (nb_sectors < 0)
acb->aiocb.aio_nbytes = -nb_sectors;
@@ -596,6 +596,24 @@ static void raw_aio_em_cb(void* opaque)
qemu_aio_release(acb);
}
+static void raw_aio_remove(RawAIOCB *acb)
+{
+ RawAIOCB **pacb;
+
+ /* remove the callback from the queue */
+ pacb = &posix_aio_state->first_aio;
+ for(;;) {
+ if (*pacb == NULL) {
+ break;
+ } else if (*pacb == acb) {
+ *pacb = acb->next;
+ qemu_aio_release(acb);
+ break;
+ }
+ pacb = &acb->next;
+ }
+}
+
static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
int64_t sector_num, uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
@@ -621,7 +639,7 @@ static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
if (!acb)
return NULL;
if (qemu_paio_read(&acb->aiocb) < 0) {
- qemu_aio_release(acb);
+ raw_aio_remove(acb);
return NULL;
}
return &acb->common;
@@ -652,7 +670,7 @@ static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
if (!acb)
return NULL;
if (qemu_paio_write(&acb->aiocb) < 0) {
- qemu_aio_release(acb);
+ raw_aio_remove(acb);
return NULL;
}
return &acb->common;
@@ -662,7 +680,6 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
{
int ret;
RawAIOCB *acb = (RawAIOCB *)blockacb;
- RawAIOCB **pacb;
ret = qemu_paio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
if (ret == QEMU_PAIO_NOTCANCELED) {
@@ -671,18 +688,7 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
while (qemu_paio_error(&acb->aiocb) == EINPROGRESS);
}
- /* remove the callback from the queue */
- pacb = &posix_aio_state->first_aio;
- for(;;) {
- if (*pacb == NULL) {
- break;
- } else if (*pacb == acb) {
- *pacb = acb->next;
- qemu_aio_release(acb);
- break;
- }
- pacb = &acb->next;
- }
+ raw_aio_remove(acb);
}
#else /* CONFIG_AIO */
static int posix_aio_init(void)
diff --git a/block-vpc.c b/block-vpc.c
index f76c45112..3eea506e7 100644
--- a/block-vpc.c
+++ b/block-vpc.c
@@ -2,6 +2,7 @@
* Block driver for Conectix/Microsoft Virtual PC images
*
* Copyright (c) 2005 Alex Beregszaszi
+ * Copyright (c) 2009 Kevin Wolf <kwolf@suse.de>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -30,46 +31,96 @@
//#define CACHE
+enum vhd_type {
+ VHD_FIXED = 2,
+ VHD_DYNAMIC = 3,
+ VHD_DIFFERENCING = 4,
+};
+
+// Seconds since Jan 1, 2000 0:00:00 (UTC)
+#define VHD_TIMESTAMP_BASE 946684800
+
// always big-endian
-struct vpc_subheader {
- char magic[8]; // "conectix" / "cxsparse"
- union {
- struct {
- uint32_t unk1[2];
- uint32_t unk2; // always zero?
- uint32_t subheader_offset;
- uint32_t unk3; // some size?
- char creator[4]; // "vpc "
- uint16_t major;
- uint16_t minor;
- char guest[4]; // "Wi2k"
- uint32_t unk4[7];
- uint8_t vnet_id[16]; // virtual network id, purpose unknown
- // next 16 longs are used, but dunno the purpose
- // next 6 longs unknown, following 7 long maybe a serial
- char padding[HEADER_SIZE - 84];
- } main;
- struct {
- uint32_t unk1[2]; // all bits set
- uint32_t unk2; // always zero?
- uint32_t pagetable_offset;
- uint32_t unk3;
- uint32_t pagetable_entries; // 32bit/entry
- uint32_t pageentry_size; // 512*8*512
- uint32_t nb_sectors;
- char padding[HEADER_SIZE - 40];
- } sparse;
- char padding[HEADER_SIZE - 8];
- } type;
+struct vhd_footer {
+ char creator[8]; // "conectix"
+ uint32_t features;
+ uint32_t version;
+
+ // Offset of next header structure, 0xFFFFFFFF if none
+ uint64_t data_offset;
+
+ // Seconds since Jan 1, 2000 0:00:00 (UTC)
+ uint32_t timestamp;
+
+ char creator_app[4]; // "vpc "
+ uint16_t major;
+ uint16_t minor;
+ char creator_os[4]; // "Wi2k"
+
+ uint64_t orig_size;
+ uint64_t size;
+
+ uint16_t cyls;
+ uint8_t heads;
+ uint8_t secs_per_cyl;
+
+ uint32_t type;
+
+ // Checksum of the Hard Disk Footer ("one's complement of the sum of all
+ // the bytes in the footer without the checksum field")
+ uint32_t checksum;
+
+ // UUID used to identify a parent hard disk (backing file)
+ uint8_t uuid[16];
+
+ uint8_t in_saved_state;
+};
+
+struct vhd_dyndisk_header {
+ char magic[8]; // "cxsparse"
+
+ // Offset of next header structure, 0xFFFFFFFF if none
+ uint64_t data_offset;
+
+ // Offset of the Block Allocation Table (BAT)
+ uint64_t table_offset;
+
+ uint32_t version;
+ uint32_t max_table_entries; // 32bit/entry
+
+ // 2 MB by default, must be a power of two
+ uint32_t block_size;
+
+ uint32_t checksum;
+ uint8_t parent_uuid[16];
+ uint32_t parent_timestamp;
+ uint32_t reserved;
+
+ // Backing file name (in UTF-16)
+ uint8_t parent_name[512];
+
+ struct {
+ uint32_t platform;
+ uint32_t data_space;
+ uint32_t data_length;
+ uint32_t reserved;
+ uint64_t data_offset;
+ } parent_locator[8];
};
typedef struct BDRVVPCState {
- int fd;
+ BlockDriverState *hd;
- int pagetable_entries;
+ uint8_t footer_buf[HEADER_SIZE];
+ uint64_t free_data_block_offset;
+ int max_table_entries;
uint32_t *pagetable;
+ uint64_t bat_offset;
+ uint64_t last_bitmap_offset;
+
+ uint32_t block_size;
+ uint32_t bitmap_size;
- uint32_t pageentry_size;
#ifdef CACHE
uint8_t *pageentry_u8;
uint32_t *pageentry_u32;
@@ -79,6 +130,18 @@ typedef struct BDRVVPCState {
#endif
} BDRVVPCState;
+static uint32_t vpc_checksum(uint8_t* buf, size_t size)
+{
+ uint32_t res = 0;
+ int i;
+
+ for (i = 0; i < size; i++)
+ res += buf[i];
+
+ return ~res;
+}
+
+
static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
{
if (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8))
@@ -89,46 +152,74 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVVPCState *s = bs->opaque;
- int fd, i;
- struct vpc_subheader header;
+ int ret, i;
+ struct vhd_footer* footer;
+ struct vhd_dyndisk_header* dyndisk_header;
+ uint8_t buf[HEADER_SIZE];
+ uint32_t checksum;
- fd = open(filename, O_RDONLY | O_BINARY);
- if (fd < 0)
- return -1;
+ ret = bdrv_file_open(&s->hd, filename, flags);
+ if (ret < 0)
+ return ret;
- bs->read_only = 1; // no write support yet
+ if (bdrv_pread(s->hd, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE)
+ goto fail;
- s->fd = fd;
+ footer = (struct vhd_footer*) s->footer_buf;
+ if (strncmp(footer->creator, "conectix", 8))
+ goto fail;
+
+ checksum = be32_to_cpu(footer->checksum);
+ footer->checksum = 0;
+ if (vpc_checksum(s->footer_buf, HEADER_SIZE) != checksum)
+ fprintf(stderr, "block-vpc: The header checksum of '%s' is "
+ "incorrect.\n", filename);
- if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
+ // The visible size of a image in Virtual PC depends on the geometry
+ // rather than on the size stored in the footer (the size in the footer
+ // is too large usually)
+ bs->total_sectors = (int64_t)
+ be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
+
+ if (bdrv_pread(s->hd, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE)
+ != HEADER_SIZE)
goto fail;
- if (strncmp(header.magic, "conectix", 8))
+ dyndisk_header = (struct vhd_dyndisk_header*) buf;
+
+ if (strncmp(dyndisk_header->magic, "cxsparse", 8))
goto fail;
- lseek(s->fd, be32_to_cpu(header.type.main.subheader_offset), SEEK_SET);
- if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
+
+ s->block_size = be32_to_cpu(dyndisk_header->block_size);
+ s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
+
+ s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
+ s->pagetable = qemu_malloc(s->max_table_entries * 4);
+ if (!s->pagetable)
goto fail;
- if (strncmp(header.magic, "cxsparse", 8))
- goto fail;
+ s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
+ if (bdrv_pread(s->hd, s->bat_offset, s->pagetable,
+ s->max_table_entries * 4) != s->max_table_entries * 4)
+ goto fail;
- bs->total_sectors = ((uint64_t)be32_to_cpu(header.type.sparse.pagetable_entries) *
- be32_to_cpu(header.type.sparse.pageentry_size)) / 512;
+ s->free_data_block_offset =
+ (s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
- lseek(s->fd, be32_to_cpu(header.type.sparse.pagetable_offset), SEEK_SET);
+ for (i = 0; i < s->max_table_entries; i++) {
+ be32_to_cpus(&s->pagetable[i]);
+ if (s->pagetable[i] != 0xFFFFFFFF) {
+ int64_t next = (512 * (int64_t) s->pagetable[i]) +
+ s->bitmap_size + s->block_size;
- s->pagetable_entries = be32_to_cpu(header.type.sparse.pagetable_entries);
- s->pagetable = qemu_malloc(s->pagetable_entries * 4);
- if (!s->pagetable)
- goto fail;
- if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
- s->pagetable_entries * 4)
- goto fail;
- for (i = 0; i < s->pagetable_entries; i++)
- be32_to_cpus(&s->pagetable[i]);
+ if (next> s->free_data_block_offset)
+ s->free_data_block_offset = next;
+ }
+ }
+
+ s->last_bitmap_offset = (int64_t) -1;
- s->pageentry_size = be32_to_cpu(header.type.sparse.pageentry_size);
#ifdef CACHE
s->pageentry_u8 = qemu_malloc(512);
if (!s->pageentry_u8)
@@ -140,25 +231,46 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
return 0;
fail:
- close(fd);
+ bdrv_delete(s->hd);
return -1;
}
-static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
+/*
+ * Returns the absolute byte offset of the given sector in the image file.
+ * If the sector is not allocated, -1 is returned instead.
+ *
+ * The parameter write must be 1 if the offset will be used for a write
+ * operation (the block bitmaps is updated then), 0 otherwise.
+ */
+static inline int64_t get_sector_offset(BlockDriverState *bs,
+ int64_t sector_num, int write)
{
BDRVVPCState *s = bs->opaque;
uint64_t offset = sector_num * 512;
uint64_t bitmap_offset, block_offset;
uint32_t pagetable_index, pageentry_index;
- pagetable_index = offset / s->pageentry_size;
- pageentry_index = (offset % s->pageentry_size) / 512;
+ pagetable_index = offset / s->block_size;
+ pageentry_index = (offset % s->block_size) / 512;
- if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
- return -1; // not allocated
+ if (pagetable_index >= s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff)
+ return -1; // not allocated
- bitmap_offset = 512 * s->pagetable[pagetable_index];
- block_offset = bitmap_offset + 512 + (512 * pageentry_index);
+ bitmap_offset = 512 * (uint64_t) s->pagetable[pagetable_index];
+ block_offset = bitmap_offset + s->bitmap_size + (512 * pageentry_index);
+
+ // We must ensure that we don't write to any sectors which are marked as
+ // unused in the bitmap. We get away with setting all bits in the block
+ // bitmap each time we write to a new block. This might cause Virtual PC to
+ // miss sparse read optimization, but it's not a problem in terms of
+ // correctness.
+ if (write && (s->last_bitmap_offset != bitmap_offset)) {
+ uint8_t bitmap[s->bitmap_size];
+
+ s->last_bitmap_offset = bitmap_offset;
+ memset(bitmap, 0xff, s->bitmap_size);
+ bdrv_pwrite(s->hd, bitmap_offset, bitmap, s->bitmap_size);
+ }
// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
// sector_num, pagetable_index, pageentry_index,
@@ -191,30 +303,275 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
return -1; // not allocated
#endif
#endif
- lseek(s->fd, block_offset, SEEK_SET);
+
+ return block_offset;
+}
+
+/*
+ * Writes the footer to the end of the image file. This is needed when the
+ * file grows as it overwrites the old footer
+ *
+ * Returns 0 on success and < 0 on error
+ */
+static int rewrite_footer(BlockDriverState* bs)
+{
+ int ret;
+ BDRVVPCState *s = bs->opaque;
+ int64_t offset = s->free_data_block_offset;
+
+ ret = bdrv_pwrite(s->hd, offset, s->footer_buf, HEADER_SIZE);
+ if (ret < 0)
+ return ret;
return 0;
}
+/*
+ * Allocates a new block. This involves writing a new footer and updating
+ * the Block Allocation Table to use the space at the old end of the image
+ * file (overwriting the old footer)
+ *
+ * Returns the sectors' offset in the image file on success and < 0 on error
+ */
+static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
+{
+ BDRVVPCState *s = bs->opaque;
+ int64_t bat_offset;
+ uint32_t index, bat_value;
+ int ret;
+ uint8_t bitmap[s->bitmap_size];
+
+ // Check if sector_num is valid
+ if ((sector_num < 0) || (sector_num > bs->total_sectors))
+ return -1;
+
+ // Write entry into in-memory BAT
+ index = (sector_num * 512) / s->block_size;
+ if (s->pagetable[index] != 0xFFFFFFFF)
+ return -1;
+
+ s->pagetable[index] = s->free_data_block_offset / 512;
+
+ // Initialize the block's bitmap
+ memset(bitmap, 0xff, s->bitmap_size);
+ bdrv_pwrite(s->hd, s->free_data_block_offset, bitmap, s->bitmap_size);
+
+ // Write new footer (the old one will be overwritten)
+ s->free_data_block_offset += s->block_size + s->bitmap_size;
+ ret = rewrite_footer(bs);
+ if (ret < 0)
+ goto fail;
+
+ // Write BAT entry to disk
+ bat_offset = s->bat_offset + (4 * index);
+ bat_value = be32_to_cpu(s->pagetable[index]);
+ ret = bdrv_pwrite(s->hd, bat_offset, &bat_value, 4);
+ if (ret < 0)
+ goto fail;
+
+ return get_sector_offset(bs, sector_num, 0);
+
+fail:
+ s->free_data_block_offset -= (s->block_size + s->bitmap_size);
+ return -1;
+}
+
static int vpc_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVVPCState *s = bs->opaque;
int ret;
+ int64_t offset;
while (nb_sectors > 0) {
- if (!seek_to_sector(bs, sector_num))
- {
- ret = read(s->fd, buf, 512);
- if (ret != 512)
- return -1;
- }
- else
+ offset = get_sector_offset(bs, sector_num, 0);
+
+ if (offset == -1) {
memset(buf, 0, 512);
+ } else {
+ ret = bdrv_pread(s->hd, offset, buf, 512);
+ if (ret != 512)
+ return -1;
+ }
+
+ nb_sectors--;
+ sector_num++;
+ buf += 512;
+ }
+ return 0;
+}
+
+static int vpc_write(BlockDriverState *bs, int64_t sector_num,
+ const uint8_t *buf, int nb_sectors)
+{
+ BDRVVPCState *s = bs->opaque;
+ int64_t offset;
+ int ret;
+
+ while (nb_sectors > 0) {
+ offset = get_sector_offset(bs, sector_num, 1);
+
+ if (offset == -1) {
+ offset = alloc_block(bs, sector_num);
+ if (offset < 0)
+ return -1;
+ }
+
+ ret = bdrv_pwrite(s->hd, offset, buf, 512);
+ if (ret != 512)
+ return -1;
+
nb_sectors--;
sector_num++;
buf += 512;
}
+
+ return 0;
+}
+
+
+/*
+ * Calculates the number of cylinders, heads and sectors per cylinder
+ * based on a given number of sectors. This is the algorithm described
+ * in the VHD specification.
+ *
+ * Note that the geometry doesn't always exactly match total_sectors but
+ * may round it down.
+ */
+static void calculate_geometry(int64_t total_sectors, uint16_t* cyls,
+ uint8_t* heads, uint8_t* secs_per_cyl)
+{
+ uint32_t cyls_times_heads;
+
+ if (total_sectors > 65535 * 16 * 255)
+ total_sectors = 65535 * 16 * 255;
+
+ if (total_sectors > 65535 * 16 * 63) {
+ *secs_per_cyl = 255;
+ *heads = 16;
+ cyls_times_heads = total_sectors / *secs_per_cyl;
+ } else {
+ *secs_per_cyl = 17;
+ cyls_times_heads = total_sectors / *secs_per_cyl;
+ *heads = (cyls_times_heads + 1023) / 1024;
+
+ if (*heads < 4)
+ *heads = 4;
+
+ if (cyls_times_heads >= (*heads * 1024) || *heads > 16) {
+ *secs_per_cyl = 31;
+ *heads = 16;
+ cyls_times_heads = total_sectors / *secs_per_cyl;
+ }
+
+ if (cyls_times_heads >= (*heads * 1024)) {
+ *secs_per_cyl = 63;
+ *heads = 16;
+ cyls_times_heads = total_sectors / *secs_per_cyl;
+ }
+ }
+
+ // Note: Rounding up deviates from the Virtual PC behaviour
+ // However, we need this to avoid truncating images in qemu-img convert
+ *cyls = (cyls_times_heads + *heads - 1) / *heads;
+}
+
+static int vpc_create(const char *filename, int64_t total_sectors,
+ const char *backing_file, int flags)
+{
+ uint8_t buf[1024];
+ struct vhd_footer* footer = (struct vhd_footer*) buf;
+ struct vhd_dyndisk_header* dyndisk_header =
+ (struct vhd_dyndisk_header*) buf;
+ int fd, i;
+ uint16_t cyls;
+ uint8_t heads;
+ uint8_t secs_per_cyl;
+ size_t block_size, num_bat_entries;
+
+ if (backing_file != NULL)
+ return -ENOTSUP;
+
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+ if (fd < 0)
+ return -EIO;
+
+ // Calculate matching total_size and geometry
+ calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl);
+ total_sectors = (int64_t) cyls * heads * secs_per_cyl;
+
+ // Prepare the Hard Disk Footer
+ memset(buf, 0, 1024);
+
+ strncpy(footer->creator, "conectix", 8);
+ // TODO Check if "qemu" creator_app is ok for VPC
+ strncpy(footer->creator_app, "qemu", 4);
+ strncpy(footer->creator_os, "Wi2k", 4);
+
+ footer->features = be32_to_cpu(0x02);
+ footer->version = be32_to_cpu(0x00010000);
+ footer->data_offset = be64_to_cpu(HEADER_SIZE);
+ footer->timestamp = be32_to_cpu(time(NULL) - VHD_TIMESTAMP_BASE);
+
+ // Version of Virtual PC 2007
+ footer->major = be16_to_cpu(0x0005);
+ footer->minor =be16_to_cpu(0x0003);
+
+ footer->orig_size = be64_to_cpu(total_sectors * 512);
+ footer->size = be64_to_cpu(total_sectors * 512);
+
+ footer->cyls = be16_to_cpu(cyls);
+ footer->heads = heads;
+ footer->secs_per_cyl = secs_per_cyl;
+
+ footer->type = be32_to_cpu(VHD_DYNAMIC);
+
+ // TODO uuid is missing
+
+ footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
+
+ // Write the footer (twice: at the beginning and at the end)
+ block_size = 0x200000;
+ num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
+
+ if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE)
+ return -EIO;
+
+ if (lseek(fd, 1536 + ((num_bat_entries * 4 + 511) & ~511), SEEK_SET) < 0)
+ return -EIO;
+ if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE)
+ return -EIO;
+
+ // Write the initial BAT
+ if (lseek(fd, 3 * 512, SEEK_SET) < 0)
+ return -EIO;
+
+ memset(buf, 0xFF, 512);
+ for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++)
+ if (write(fd, buf, 512) != 512)
+ return -EIO;
+
+
+ // Prepare the Dynamic Disk Header
+ memset(buf, 0, 1024);
+
+ strncpy(dyndisk_header->magic, "cxsparse", 8);
+
+ dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFF);
+ dyndisk_header->table_offset = be64_to_cpu(3 * 512);
+ dyndisk_header->version = be32_to_cpu(0x00010000);
+ dyndisk_header->block_size = be32_to_cpu(block_size);
+ dyndisk_header->max_table_entries = be32_to_cpu(num_bat_entries);
+
+ dyndisk_header->checksum = be32_to_cpu(vpc_checksum(buf, 1024));
+
+ // Write the header
+ if (lseek(fd, 512, SEEK_SET) < 0)
+ return -EIO;
+ if (write(fd, buf, 1024) != 1024)
+ return -EIO;
+
+ close(fd);
return 0;
}
@@ -225,7 +582,7 @@ static void vpc_close(BlockDriverState *bs)
#ifdef CACHE
qemu_free(s->pageentry_u8);
#endif
- close(s->fd);
+ bdrv_delete(s->hd);
}
BlockDriver bdrv_vpc = {
@@ -234,6 +591,7 @@ BlockDriver bdrv_vpc = {
vpc_probe,
vpc_open,
vpc_read,
- NULL,
+ vpc_write,
vpc_close,
+ vpc_create,
};
diff --git a/block.c b/block.c
index 62b1e934d..f6a11802d 100644
--- a/block.c
+++ b/block.c
@@ -1096,6 +1096,7 @@ void bdrv_info(void)
void bdrv_info_stats (void)
{
BlockDriverState *bs;
+ BlockDriverInfo bdi;
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
term_printf ("%s:"
@@ -1103,10 +1104,15 @@ void bdrv_info_stats (void)
" wr_bytes=%" PRIu64
" rd_operations=%" PRIu64
" wr_operations=%" PRIu64
- "\n",
+ ,
bs->device_name,
bs->rd_bytes, bs->wr_bytes,
bs->rd_ops, bs->wr_ops);
+ if (bdrv_get_info(bs, &bdi) == 0)
+ term_printf(" high=%" PRId64
+ " bytes_free=%" PRId64,
+ bdi.highest_alloc, bdi.num_free_bytes);
+ term_printf("\n");
}
}
@@ -1265,6 +1271,69 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn)
/**************************************************************/
/* async I/Os */
+typedef struct VectorTranslationState {
+ QEMUIOVector *iov;
+ uint8_t *bounce;
+ int is_write;
+ BlockDriverAIOCB *aiocb;
+ BlockDriverAIOCB *this_aiocb;
+} VectorTranslationState;
+
+static void bdrv_aio_rw_vector_cb(void *opaque, int ret)
+{
+ VectorTranslationState *s = opaque;
+
+ if (!s->is_write) {
+ qemu_iovec_from_buffer(s->iov, s->bounce, s->iov->size);
+ }
+ qemu_free(s->bounce);
+ s->this_aiocb->cb(s->this_aiocb->opaque, ret);
+ qemu_aio_release(s->this_aiocb);
+}
+
+static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
+ int64_t sector_num,
+ QEMUIOVector *iov,
+ int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque,
+ int is_write)
+
+{
+ VectorTranslationState *s = qemu_mallocz(sizeof(*s));
+ BlockDriverAIOCB *aiocb = qemu_aio_get(bs, cb, opaque);
+
+ s->this_aiocb = aiocb;
+ s->iov = iov;
+ s->bounce = qemu_memalign(512, nb_sectors * 512);
+ s->is_write = is_write;
+ if (is_write) {
+ qemu_iovec_to_buffer(s->iov, s->bounce);
+ s->aiocb = bdrv_aio_write(bs, sector_num, s->bounce, nb_sectors,
+ bdrv_aio_rw_vector_cb, s);
+ } else {
+ s->aiocb = bdrv_aio_read(bs, sector_num, s->bounce, nb_sectors,
+ bdrv_aio_rw_vector_cb, s);
+ }
+ return aiocb;
+}
+
+BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
+ QEMUIOVector *iov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ return bdrv_aio_rw_vector(bs, sector_num, iov, nb_sectors,
+ cb, opaque, 0);
+}
+
+BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
+ QEMUIOVector *iov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ return bdrv_aio_rw_vector(bs, sector_num, iov, nb_sectors,
+ cb, opaque, 1);
+}
+
BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
@@ -1313,6 +1382,11 @@ void bdrv_aio_cancel(BlockDriverAIOCB *acb)
{
BlockDriver *drv = acb->bs->drv;
+ if (acb->cb == bdrv_aio_rw_vector_cb) {
+ VectorTranslationState *s = acb->opaque;
+ acb = s->aiocb;
+ }
+
drv->bdrv_aio_cancel(acb);
}
diff --git a/block.h b/block.h
index c3314a1db..e1927dd1d 100644
--- a/block.h
+++ b/block.h
@@ -2,6 +2,7 @@
#define BLOCK_H
#include "qemu-aio.h"
+#include "qemu-common.h"
/* block.c */
typedef struct BlockDriver BlockDriver;
@@ -25,6 +26,8 @@ typedef struct BlockDriverInfo {
int cluster_size;
/* offset at which the VM state can be saved (0 if not possible) */
int64_t vm_state_offset;
+ int64_t highest_alloc; /* highest allocated block offset (in bytes) */
+ int64_t num_free_bytes; /* below highest_alloc */
} BlockDriverInfo;
typedef struct QEMUSnapshotInfo {
@@ -85,6 +88,13 @@ int bdrv_commit(BlockDriverState *bs);
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
+BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
+ QEMUIOVector *iov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque);
+BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
+ QEMUIOVector *iov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque);
+
BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index 9c0a76a3a..e916a6544 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -122,6 +122,21 @@ void qemu_free(void *ptr)
munmap(p, *p);
}
+void *qemu_realloc(void *ptr, size_t size)
+{
+ size_t old_size, copy;
+ void *new_ptr;
+
+ if (!ptr)
+ return qemu_malloc(size);
+ old_size = *(size_t *)((char *)ptr - 16);
+ copy = old_size < size ? old_size : size;
+ new_ptr = qemu_malloc(size);
+ memcpy(new_ptr, ptr, copy);
+ qemu_free(ptr);
+ return new_ptr;
+}
+
/* NOTE: all the constants are the HOST ones, but addresses are target. */
int target_mprotect(abi_ulong start, abi_ulong len, int prot)
{
diff --git a/configure b/configure
index 107699a2e..902bba383 100755
--- a/configure
+++ b/configure
@@ -249,11 +249,21 @@ oss_lib="-lossaudio"
Darwin)
bsd="yes"
darwin="yes"
+# on Leopard most of the system is 32-bit, so we have to ask the kernel it if we can run 64-bit userspace code
+is_x86_64=`sysctl -n hw.optional.x86_64`
+if [ "$is_x86_64" = "1" ]; then
+ cpu=x86_64
+fi
+if [ "$cpu" = "x86_64" ] ; then
+ OS_CFLAGS="-arch x86_64"
+ LDFLAGS="-arch x86_64"
+else
+ OS_CFLAGS="-mdynamic-no-pic"
+fi
darwin_user="yes"
cocoa="yes"
audio_drv_list="coreaudio"
audio_possible_drivers="coreaudio sdl fmod"
-OS_CFLAGS="-mdynamic-no-pic"
OS_LDFLAGS="-framework CoreFoundation -framework IOKit"
;;
SunOS)
@@ -1764,6 +1774,7 @@ case "$target_cpu" in
echo "TARGET_ARCH=ppc" >> $config_mak
echo "#define TARGET_ARCH \"ppc\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
+ gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
;;
ppcemb)
echo "TARGET_ARCH=ppcemb" >> $config_mak
@@ -1776,6 +1787,7 @@ case "$target_cpu" in
echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
echo "#define CONFIG_KVM 1" >> $config_h
fi
+ gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
;;
ppc64)
echo "TARGET_ARCH=ppc64" >> $config_mak
@@ -1783,6 +1795,7 @@ case "$target_cpu" in
echo "#define TARGET_ARCH \"ppc64\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
echo "#define TARGET_PPC64 1" >> $config_h
+ gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
;;
ppc64abi32)
echo "TARGET_ARCH=ppc64" >> $config_mak
@@ -1792,6 +1805,7 @@ case "$target_cpu" in
echo "#define TARGET_PPC 1" >> $config_h
echo "#define TARGET_PPC64 1" >> $config_h
echo "#define TARGET_ABI32 1" >> $config_h
+ gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml"
;;
sh4|sh4eb)
echo "TARGET_ARCH=sh4" >> $config_mak
diff --git a/console.c b/console.c
index dbb3b7010..68ac97065 100644
--- a/console.c
+++ b/console.c
@@ -1449,7 +1449,7 @@ void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
}
}
-static PixelFormat qemu_default_pixelformat(int bpp)
+PixelFormat qemu_different_endianness_pixelformat(int bpp)
{
PixelFormat pf;
@@ -1460,17 +1460,55 @@ static PixelFormat qemu_default_pixelformat(int bpp)
pf.depth = bpp == 32 ? 24 : bpp;
switch (bpp) {
- case 8:
- pf.rmask = 0x000000E0;
- pf.gmask = 0x0000001C;
- pf.bmask = 0x00000003;
- pf.rmax = 7;
- pf.gmax = 7;
- pf.bmax = 3;
- pf.rshift = 5;
- pf.gshift = 2;
- pf.bshift = 0;
+ case 24:
+ pf.rmask = 0x000000FF;
+ pf.gmask = 0x0000FF00;
+ pf.bmask = 0x00FF0000;
+ pf.rmax = 255;
+ pf.gmax = 255;
+ pf.bmax = 255;
+ pf.rshift = 0;
+ pf.gshift = 8;
+ pf.bshift = 16;
+ pf.rbits = 8;
+ pf.gbits = 8;
+ pf.bbits = 8;
break;
+ case 32:
+ pf.rmask = 0x0000FF00;
+ pf.gmask = 0x00FF0000;
+ pf.bmask = 0xFF000000;
+ pf.amask = 0x00000000;
+ pf.amax = 255;
+ pf.rmax = 255;
+ pf.gmax = 255;
+ pf.bmax = 255;
+ pf.ashift = 0;
+ pf.rshift = 8;
+ pf.gshift = 16;
+ pf.bshift = 24;
+ pf.rbits = 8;
+ pf.gbits = 8;
+ pf.bbits = 8;
+ pf.abits = 8;
+ break;
+ default:
+ break;
+ }
+ return pf;
+}
+
+PixelFormat qemu_default_pixelformat(int bpp)
+{
+ PixelFormat pf;
+
+ memset(&pf, 0x00, sizeof(PixelFormat));
+
+ pf.bits_per_pixel = bpp;
+ pf.bytes_per_pixel = bpp / 8;
+ pf.depth = bpp == 32 ? 24 : bpp;
+
+ switch (bpp) {
case 16:
pf.rmask = 0x0000F800;
pf.gmask = 0x000007E0;
@@ -1481,18 +1519,39 @@ static PixelFormat qemu_default_pixelformat(int bpp)
pf.rshift = 11;
pf.gshift = 5;
pf.bshift = 0;
+ pf.rbits = 5;
+ pf.gbits = 6;
+ pf.bbits = 5;
break;
case 24:
+ pf.rmask = 0x00FF0000;
+ pf.gmask = 0x0000FF00;
+ pf.bmask = 0x000000FF;
+ pf.rmax = 255;
+ pf.gmax = 255;
+ pf.bmax = 255;
+ pf.rshift = 16;
+ pf.gshift = 8;
+ pf.bshift = 0;
+ pf.rbits = 8;
+ pf.gbits = 8;
+ pf.bbits = 8;
case 32:
pf.rmask = 0x00FF0000;
pf.gmask = 0x0000FF00;
pf.bmask = 0x000000FF;
+ pf.amax = 255;
pf.rmax = 255;
pf.gmax = 255;
pf.bmax = 255;
+ pf.ashift = 24;
pf.rshift = 16;
pf.gshift = 8;
pf.bshift = 0;
+ pf.rbits = 8;
+ pf.gbits = 8;
+ pf.bbits = 8;
+ pf.abits = 8;
break;
default:
break;
diff --git a/console.h b/console.h
index 383ea1a39..4a2f06fbd 100644
--- a/console.h
+++ b/console.h
@@ -83,6 +83,7 @@ struct PixelFormat {
uint32_t rmask, gmask, bmask, amask;
uint8_t rshift, gshift, bshift, ashift;
uint8_t rmax, gmax, bmax, amax;
+ uint8_t rbits, gbits, bbits, abits;
};
struct DisplaySurface {
@@ -134,6 +135,8 @@ DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
int linesize, uint8_t *data);
void qemu_free_displaysurface(DisplaySurface *surface);
+PixelFormat qemu_different_endianness_pixelformat(int bpp);
+PixelFormat qemu_default_pixelformat(int bpp);
static inline int is_buffer_shared(DisplaySurface *surface)
{
diff --git a/cpu-all.h b/cpu-all.h
index 2b27ab81b..3d01ee6b2 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -753,7 +753,7 @@ void cpu_dump_statistics (CPUState *env, FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
int flags);
-void noreturn cpu_abort(CPUState *env, const char *fmt, ...)
+void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));
extern CPUState *first_cpu;
extern CPUState *cpu_single_env;
@@ -816,6 +816,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
#define CPU_LOG_PCALL (1 << 6)
#define CPU_LOG_IOPORT (1 << 7)
#define CPU_LOG_TB_CPU (1 << 8)
+#define CPU_LOG_RESET (1 << 9)
/* define log items */
typedef struct CPULogItem {
@@ -925,6 +926,14 @@ static inline void cpu_physical_memory_write(target_phys_addr_t addr,
{
cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
}
+void *cpu_physical_memory_map(target_phys_addr_t addr,
+ target_phys_addr_t *plen,
+ int is_write);
+void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
+ int is_write, target_phys_addr_t access_len);
+void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque));
+void cpu_unregister_map_client(void *cookie);
+
uint32_t ldub_phys(target_phys_addr_t addr);
uint32_t lduw_phys(target_phys_addr_t addr);
uint32_t ldl_phys(target_phys_addr_t addr);
@@ -990,30 +999,30 @@ void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
#if defined(_ARCH_PPC)
-static inline uint32_t get_tbl(void)
-{
- uint32_t tbl;
- asm volatile("mftb %0" : "=r" (tbl));
- return tbl;
-}
-
-static inline uint32_t get_tbu(void)
-{
- uint32_t tbl;
- asm volatile("mftbu %0" : "=r" (tbl));
- return tbl;
-}
-
static inline int64_t cpu_get_real_ticks(void)
{
- uint32_t l, h, h1;
- /* NOTE: we test if wrapping has occurred */
- do {
- h = get_tbu();
- l = get_tbl();
- h1 = get_tbu();
- } while (h != h1);
- return ((int64_t)h << 32) | l;
+ int64_t retval;
+#ifdef _ARCH_PPC64
+ /* This reads timebase in one 64bit go and includes Cell workaround from:
+ http://ozlabs.org/pipermail/linuxppc-dev/2006-October/027052.html
+ */
+ __asm__ __volatile__ (
+ "mftb %0\n\t"
+ "cmpwi %0,0\n\t"
+ "beq- $-8"
+ : "=r" (retval));
+#else
+ /* http://ozlabs.org/pipermail/linuxppc-dev/1999-October/003889.html */
+ unsigned long junk;
+ __asm__ __volatile__ (
+ "mftbu %1\n\t"
+ "mftb %L0\n\t"
+ "mftbu %0\n\t"
+ "cmpw %0,%1\n\t"
+ "bne $-16"
+ : "=r" (retval), "=r" (junk));
+#endif
+ return retval;
}
#elif defined(__i386__)
diff --git a/cutils.c b/cutils.c
index 280d0b168..6ee43580a 100644
--- a/cutils.c
+++ b/cutils.c
@@ -140,3 +140,57 @@ int qemu_fls(int i)
{
return 32 - clz32(i);
}
+
+/* io vectors */
+
+void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
+{
+ qiov->iov = qemu_malloc(alloc_hint * sizeof(struct iovec));
+ qiov->niov = 0;
+ qiov->nalloc = alloc_hint;
+ qiov->size = 0;
+}
+
+void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
+{
+ if (qiov->niov == qiov->nalloc) {
+ qiov->nalloc = 2 * qiov->nalloc + 1;
+ qiov->iov = qemu_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec));
+ }
+ qiov->iov[qiov->niov].iov_base = base;
+ qiov->iov[qiov->niov].iov_len = len;
+ qiov->size += len;
+ ++qiov->niov;
+}
+
+void qemu_iovec_destroy(QEMUIOVector *qiov)
+{
+ qemu_free(qiov->iov);
+}
+
+void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf)
+{
+ uint8_t *p = (uint8_t *)buf;
+ int i;
+
+ for (i = 0; i < qiov->niov; ++i) {
+ memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len);
+ p += qiov->iov[i].iov_len;
+ }
+}
+
+void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count)
+{
+ const uint8_t *p = (const uint8_t *)buf;
+ size_t copy;
+ int i;
+
+ for (i = 0; i < qiov->niov && count; ++i) {
+ copy = count;
+ if (copy > qiov->iov[i].iov_len)
+ copy = qiov->iov[i].iov_len;
+ memcpy(qiov->iov[i].iov_base, p, copy);
+ p += copy;
+ count -= copy;
+ }
+}
diff --git a/darwin-user/signal.c b/darwin-user/signal.c
index d32142547..ba41c2e61 100644
--- a/darwin-user/signal.c
+++ b/darwin-user/signal.c
@@ -133,7 +133,7 @@ static inline void free_sigqueue(struct sigqueue *q)
}
/* abort execution with signal */
-void noreturn force_sig(int sig)
+void QEMU_NORETURN force_sig(int sig)
{
int host_sig;
host_sig = target_to_host_signal(sig);
diff --git a/exec-all.h b/exec-all.h
index 1b28bbcf1..88f0321d2 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -85,7 +85,7 @@ TranslationBlock *tb_gen_code(CPUState *env,
target_ulong pc, target_ulong cs_base, int flags,
int cflags);
void cpu_exec_init(CPUState *env);
-void noreturn cpu_loop_exit(void);
+void QEMU_NORETURN cpu_loop_exit(void);
int page_unprotect(target_ulong address, unsigned long pc, void *puc);
void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
int is_cpu_write_access);
diff --git a/exec.c b/exec.c
index e2660f11c..095a3aa5b 100644
--- a/exec.c
+++ b/exec.c
@@ -1591,6 +1591,8 @@ const CPULogItem cpu_log_items[] = {
#ifdef TARGET_I386
{ CPU_LOG_PCALL, "pcall",
"show protected mode far calls/returns/exceptions" },
+ { CPU_LOG_RESET, "cpu_reset",
+ "show CPU state before CPU resets" },
#endif
#ifdef DEBUG_IOPORT
{ CPU_LOG_IOPORT, "ioport",
@@ -3105,6 +3107,148 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr,
}
}
+typedef struct {
+ void *buffer;
+ target_phys_addr_t addr;
+ target_phys_addr_t len;
+} BounceBuffer;
+
+static BounceBuffer bounce;
+
+typedef struct MapClient {
+ void *opaque;
+ void (*callback)(void *opaque);
+ LIST_ENTRY(MapClient) link;
+} MapClient;
+
+static LIST_HEAD(map_client_list, MapClient) map_client_list
+ = LIST_HEAD_INITIALIZER(map_client_list);
+
+void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque))
+{
+ MapClient *client = qemu_malloc(sizeof(*client));
+
+ client->opaque = opaque;
+ client->callback = callback;
+ LIST_INSERT_HEAD(&map_client_list, client, link);
+ return client;
+}
+
+void cpu_unregister_map_client(void *_client)
+{
+ MapClient *client = (MapClient *)_client;
+
+ LIST_REMOVE(client, link);
+}
+
+static void cpu_notify_map_clients(void)
+{
+ MapClient *client;
+
+ while (!LIST_EMPTY(&map_client_list)) {
+ client = LIST_FIRST(&map_client_list);
+ client->callback(client->opaque);
+ LIST_REMOVE(client, link);
+ }
+}
+
+/* Map a physical memory region into a host virtual address.
+ * May map a subset of the requested range, given by and returned in *plen.
+ * May return NULL if resources needed to perform the mapping are exhausted.
+ * Use only for reads OR writes - not for read-modify-write operations.
+ * Use cpu_register_map_client() to know when retrying the map operation is
+ * likely to succeed.
+ */
+void *cpu_physical_memory_map(target_phys_addr_t addr,
+ target_phys_addr_t *plen,
+ int is_write)
+{
+ target_phys_addr_t len = *plen;
+ target_phys_addr_t done = 0;
+ int l;
+ uint8_t *ret = NULL;
+ uint8_t *ptr;
+ target_phys_addr_t page;
+ unsigned long pd;
+ PhysPageDesc *p;
+ unsigned long addr1;
+
+ while (len > 0) {
+ page = addr & TARGET_PAGE_MASK;
+ l = (page + TARGET_PAGE_SIZE) - addr;
+ if (l > len)
+ l = len;
+ p = phys_page_find(page >> TARGET_PAGE_BITS);
+ if (!p) {
+ pd = IO_MEM_UNASSIGNED;
+ } else {
+ pd = p->phys_offset;
+ }
+
+ if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
+ if (done || bounce.buffer) {
+ break;
+ }
+ bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
+ bounce.addr = addr;
+ bounce.len = l;
+ if (!is_write) {
+ cpu_physical_memory_rw(addr, bounce.buffer, l, 0);
+ }
+ ptr = bounce.buffer;
+ } else {
+ addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
+ ptr = phys_ram_base + addr1;
+ }
+ if (!done) {
+ ret = ptr;
+ } else if (ret + done != ptr) {
+ break;
+ }
+
+ len -= l;
+ addr += l;
+ done += l;
+ }
+ *plen = done;
+ return ret;
+}
+
+/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
+ * Will also mark the memory as dirty if is_write == 1. access_len gives
+ * the amount of memory that was actually read or written by the caller.
+ */
+void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
+ int is_write, target_phys_addr_t access_len)
+{
+ if (buffer != bounce.buffer) {
+ if (is_write) {
+ unsigned long addr1 = (uint8_t *)buffer - phys_ram_base;
+ while (access_len) {
+ unsigned l;
+ l = TARGET_PAGE_SIZE;
+ if (l > access_len)
+ l = access_len;
+ if (!cpu_physical_memory_is_dirty(addr1)) {
+ /* invalidate code */
+ tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
+ /* set dirty bit */
+ phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
+ (0xff & ~CODE_DIRTY_FLAG);
+ }
+ addr1 += l;
+ access_len -= l;
+ }
+ }
+ return;
+ }
+ if (is_write) {
+ cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
+ }
+ qemu_free(bounce.buffer);
+ bounce.buffer = NULL;
+ cpu_notify_map_clients();
+}
/* warning: addr must be aligned */
uint32_t ldl_phys(target_phys_addr_t addr)
diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c
index 9eba03540..90fa8b944 100644
--- a/fpu/softfloat-native.c
+++ b/fpu/softfloat-native.c
@@ -54,7 +54,7 @@ ldexpl(long double x, int n) {
#if defined(_ARCH_PPC)
/* correct (but slow) PowerPC rint() (glibc version is incorrect) */
-double qemu_rint(double x)
+static double qemu_rint(double x)
{
double y = 4503599627370496.0;
if (fabs(x) >= y)
diff --git a/gdb-xml/power-altivec.xml b/gdb-xml/power-altivec.xml
new file mode 100644
index 000000000..84f4d27bc
--- /dev/null
+++ b/gdb-xml/power-altivec.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.altivec">
+ <vector id="v4f" type="ieee_single" count="4"/>
+ <vector id="v4i32" type="int32" count="4"/>
+ <vector id="v8i16" type="int16" count="8"/>
+ <vector id="v16i8" type="int8" count="16"/>
+ <union id="vec128">
+ <field name="uint128" type="uint128"/>
+ <field name="v4_float" type="v4f"/>
+ <field name="v4_int32" type="v4i32"/>
+ <field name="v8_int16" type="v8i16"/>
+ <field name="v16_int8" type="v16i8"/>
+ </union>
+
+ <reg name="vr0" bitsize="128" type="vec128"/>
+ <reg name="vr1" bitsize="128" type="vec128"/>
+ <reg name="vr2" bitsize="128" type="vec128"/>
+ <reg name="vr3" bitsize="128" type="vec128"/>
+ <reg name="vr4" bitsize="128" type="vec128"/>
+ <reg name="vr5" bitsize="128" type="vec128"/>
+ <reg name="vr6" bitsize="128" type="vec128"/>
+ <reg name="vr7" bitsize="128" type="vec128"/>
+ <reg name="vr8" bitsize="128" type="vec128"/>
+ <reg name="vr9" bitsize="128" type="vec128"/>
+ <reg name="vr10" bitsize="128" type="vec128"/>
+ <reg name="vr11" bitsize="128" type="vec128"/>
+ <reg name="vr12" bitsize="128" type="vec128"/>
+ <reg name="vr13" bitsize="128" type="vec128"/>
+ <reg name="vr14" bitsize="128" type="vec128"/>
+ <reg name="vr15" bitsize="128" type="vec128"/>
+ <reg name="vr16" bitsize="128" type="vec128"/>
+ <reg name="vr17" bitsize="128" type="vec128"/>
+ <reg name="vr18" bitsize="128" type="vec128"/>
+ <reg name="vr19" bitsize="128" type="vec128"/>
+ <reg name="vr20" bitsize="128" type="vec128"/>
+ <reg name="vr21" bitsize="128" type="vec128"/>
+ <reg name="vr22" bitsize="128" type="vec128"/>
+ <reg name="vr23" bitsize="128" type="vec128"/>
+ <reg name="vr24" bitsize="128" type="vec128"/>
+ <reg name="vr25" bitsize="128" type="vec128"/>
+ <reg name="vr26" bitsize="128" type="vec128"/>
+ <reg name="vr27" bitsize="128" type="vec128"/>
+ <reg name="vr28" bitsize="128" type="vec128"/>
+ <reg name="vr29" bitsize="128" type="vec128"/>
+ <reg name="vr30" bitsize="128" type="vec128"/>
+ <reg name="vr31" bitsize="128" type="vec128"/>
+
+ <reg name="vscr" bitsize="32" group="vector"/>
+ <reg name="vrsave" bitsize="32" group="vector"/>
+</feature>
diff --git a/gdb-xml/power-core.xml b/gdb-xml/power-core.xml
new file mode 100644
index 000000000..0c69e8c8a
--- /dev/null
+++ b/gdb-xml/power-core.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.core">
+ <reg name="r0" bitsize="32" type="uint32"/>
+ <reg name="r1" bitsize="32" type="uint32"/>
+ <reg name="r2" bitsize="32" type="uint32"/>
+ <reg name="r3" bitsize="32" type="uint32"/>
+ <reg name="r4" bitsize="32" type="uint32"/>
+ <reg name="r5" bitsize="32" type="uint32"/>
+ <reg name="r6" bitsize="32" type="uint32"/>
+ <reg name="r7" bitsize="32" type="uint32"/>
+ <reg name="r8" bitsize="32" type="uint32"/>
+ <reg name="r9" bitsize="32" type="uint32"/>
+ <reg name="r10" bitsize="32" type="uint32"/>
+ <reg name="r11" bitsize="32" type="uint32"/>
+ <reg name="r12" bitsize="32" type="uint32"/>
+ <reg name="r13" bitsize="32" type="uint32"/>
+ <reg name="r14" bitsize="32" type="uint32"/>
+ <reg name="r15" bitsize="32" type="uint32"/>
+ <reg name="r16" bitsize="32" type="uint32"/>
+ <reg name="r17" bitsize="32" type="uint32"/>
+ <reg name="r18" bitsize="32" type="uint32"/>
+ <reg name="r19" bitsize="32" type="uint32"/>
+ <reg name="r20" bitsize="32" type="uint32"/>
+ <reg name="r21" bitsize="32" type="uint32"/>
+ <reg name="r22" bitsize="32" type="uint32"/>
+ <reg name="r23" bitsize="32" type="uint32"/>
+ <reg name="r24" bitsize="32" type="uint32"/>
+ <reg name="r25" bitsize="32" type="uint32"/>
+ <reg name="r26" bitsize="32" type="uint32"/>
+ <reg name="r27" bitsize="32" type="uint32"/>
+ <reg name="r28" bitsize="32" type="uint32"/>
+ <reg name="r29" bitsize="32" type="uint32"/>
+ <reg name="r30" bitsize="32" type="uint32"/>
+ <reg name="r31" bitsize="32" type="uint32"/>
+
+ <reg name="pc" bitsize="32" type="code_ptr" regnum="64"/>
+ <reg name="msr" bitsize="32" type="uint32"/>
+ <reg name="cr" bitsize="32" type="uint32"/>
+ <reg name="lr" bitsize="32" type="code_ptr"/>
+ <reg name="ctr" bitsize="32" type="uint32"/>
+ <reg name="xer" bitsize="32" type="uint32"/>
+</feature>
diff --git a/gdb-xml/power-fpu.xml b/gdb-xml/power-fpu.xml
new file mode 100644
index 000000000..d1ca3a3d5
--- /dev/null
+++ b/gdb-xml/power-fpu.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.fpu">
+ <reg name="f0" bitsize="64" type="ieee_double"/>
+ <reg name="f1" bitsize="64" type="ieee_double"/>
+ <reg name="f2" bitsize="64" type="ieee_double"/>
+ <reg name="f3" bitsize="64" type="ieee_double"/>
+ <reg name="f4" bitsize="64" type="ieee_double"/>
+ <reg name="f5" bitsize="64" type="ieee_double"/>
+ <reg name="f6" bitsize="64" type="ieee_double"/>
+ <reg name="f7" bitsize="64" type="ieee_double"/>
+ <reg name="f8" bitsize="64" type="ieee_double"/>
+ <reg name="f9" bitsize="64" type="ieee_double"/>
+ <reg name="f10" bitsize="64" type="ieee_double"/>
+ <reg name="f11" bitsize="64" type="ieee_double"/>
+ <reg name="f12" bitsize="64" type="ieee_double"/>
+ <reg name="f13" bitsize="64" type="ieee_double"/>
+ <reg name="f14" bitsize="64" type="ieee_double"/>
+ <reg name="f15" bitsize="64" type="ieee_double"/>
+ <reg name="f16" bitsize="64" type="ieee_double"/>
+ <reg name="f17" bitsize="64" type="ieee_double"/>
+ <reg name="f18" bitsize="64" type="ieee_double"/>
+ <reg name="f19" bitsize="64" type="ieee_double"/>
+ <reg name="f20" bitsize="64" type="ieee_double"/>
+ <reg name="f21" bitsize="64" type="ieee_double"/>
+ <reg name="f22" bitsize="64" type="ieee_double"/>
+ <reg name="f23" bitsize="64" type="ieee_double"/>
+ <reg name="f24" bitsize="64" type="ieee_double"/>
+ <reg name="f25" bitsize="64" type="ieee_double"/>
+ <reg name="f26" bitsize="64" type="ieee_double"/>
+ <reg name="f27" bitsize="64" type="ieee_double"/>
+ <reg name="f28" bitsize="64" type="ieee_double"/>
+ <reg name="f29" bitsize="64" type="ieee_double"/>
+ <reg name="f30" bitsize="64" type="ieee_double"/>
+ <reg name="f31" bitsize="64" type="ieee_double"/>
+
+ <reg name="fpscr" bitsize="32" group="float"/>
+</feature>
diff --git a/gdb-xml/power-spe.xml b/gdb-xml/power-spe.xml
new file mode 100644
index 000000000..1ec15d66a
--- /dev/null
+++ b/gdb-xml/power-spe.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.spe">
+ <reg name="ev0h" bitsize="32"/>
+ <reg name="ev1h" bitsize="32"/>
+ <reg name="ev2h" bitsize="32"/>
+ <reg name="ev3h" bitsize="32"/>
+ <reg name="ev4h" bitsize="32"/>
+ <reg name="ev5h" bitsize="32"/>
+ <reg name="ev6h" bitsize="32"/>
+ <reg name="ev7h" bitsize="32"/>
+ <reg name="ev8h" bitsize="32"/>
+ <reg name="ev9h" bitsize="32"/>
+ <reg name="ev10h" bitsize="32"/>
+ <reg name="ev11h" bitsize="32"/>
+ <reg name="ev12h" bitsize="32"/>
+ <reg name="ev13h" bitsize="32"/>
+ <reg name="ev14h" bitsize="32"/>
+ <reg name="ev15h" bitsize="32"/>
+ <reg name="ev16h" bitsize="32"/>
+ <reg name="ev17h" bitsize="32"/>
+ <reg name="ev18h" bitsize="32"/>
+ <reg name="ev19h" bitsize="32"/>
+ <reg name="ev20h" bitsize="32"/>
+ <reg name="ev21h" bitsize="32"/>
+ <reg name="ev22h" bitsize="32"/>
+ <reg name="ev23h" bitsize="32"/>
+ <reg name="ev24h" bitsize="32"/>
+ <reg name="ev25h" bitsize="32"/>
+ <reg name="ev26h" bitsize="32"/>
+ <reg name="ev27h" bitsize="32"/>
+ <reg name="ev28h" bitsize="32"/>
+ <reg name="ev29h" bitsize="32"/>
+ <reg name="ev30h" bitsize="32"/>
+ <reg name="ev31h" bitsize="32"/>
+
+ <reg name="acc" bitsize="64"/>
+ <reg name="spefscr" bitsize="32"/>
+</feature>
diff --git a/gdb-xml/power64-core.xml b/gdb-xml/power64-core.xml
new file mode 100644
index 000000000..6cc153120
--- /dev/null
+++ b/gdb-xml/power64-core.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.power.core">
+ <reg name="r0" bitsize="64" type="uint64"/>
+ <reg name="r1" bitsize="64" type="uint64"/>
+ <reg name="r2" bitsize="64" type="uint64"/>
+ <reg name="r3" bitsize="64" type="uint64"/>
+ <reg name="r4" bitsize="64" type="uint64"/>
+ <reg name="r5" bitsize="64" type="uint64"/>
+ <reg name="r6" bitsize="64" type="uint64"/>
+ <reg name="r7" bitsize="64" type="uint64"/>
+ <reg name="r8" bitsize="64" type="uint64"/>
+ <reg name="r9" bitsize="64" type="uint64"/>
+ <reg name="r10" bitsize="64" type="uint64"/>
+ <reg name="r11" bitsize="64" type="uint64"/>
+ <reg name="r12" bitsize="64" type="uint64"/>
+ <reg name="r13" bitsize="64" type="uint64"/>
+ <reg name="r14" bitsize="64" type="uint64"/>
+ <reg name="r15" bitsize="64" type="uint64"/>
+ <reg name="r16" bitsize="64" type="uint64"/>
+ <reg name="r17" bitsize="64" type="uint64"/>
+ <reg name="r18" bitsize="64" type="uint64"/>
+ <reg name="r19" bitsize="64" type="uint64"/>
+ <reg name="r20" bitsize="64" type="uint64"/>
+ <reg name="r21" bitsize="64" type="uint64"/>
+ <reg name="r22" bitsize="64" type="uint64"/>
+ <reg name="r23" bitsize="64" type="uint64"/>
+ <reg name="r24" bitsize="64" type="uint64"/>
+ <reg name="r25" bitsize="64" type="uint64"/>
+ <reg name="r26" bitsize="64" type="uint64"/>
+ <reg name="r27" bitsize="64" type="uint64"/>
+ <reg name="r28" bitsize="64" type="uint64"/>
+ <reg name="r29" bitsize="64" type="uint64"/>
+ <reg name="r30" bitsize="64" type="uint64"/>
+ <reg name="r31" bitsize="64" type="uint64"/>
+
+ <reg name="pc" bitsize="64" type="code_ptr" regnum="64"/>
+ <reg name="msr" bitsize="64" type="uint64"/>
+ <reg name="cr" bitsize="32" type="uint32"/>
+ <reg name="lr" bitsize="64" type="code_ptr"/>
+ <reg name="ctr" bitsize="64" type="uint64"/>
+ <reg name="xer" bitsize="32" type="uint32"/>
+</feature>
diff --git a/gdbstub.c b/gdbstub.c
index 4f3bbbc94..e3d5bc9fa 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -621,7 +621,17 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int i)
#elif defined (TARGET_PPC)
+/* Old gdb always expects FP registers. Newer (xml-aware) gdb only
+ expects whatever the target description contains. Due to a
+ historical mishap the FP registers appear in between core integer
+ regs and PC, MSR, CR, and so forth. We hack round this by giving the
+ FP regs zero size when talking to a newer gdb. */
#define NUM_CORE_REGS 71
+#if defined (TARGET_PPC64)
+#define GDB_CORE_XML "power64-core.xml"
+#else
+#define GDB_CORE_XML "power-core.xml"
+#endif
static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
{
@@ -630,6 +640,8 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
GET_REGL(env->gpr[n]);
} else if (n < 64) {
/* fprs */
+ if (gdb_has_xml)
+ return 0;
stfq_p(mem_buf, env->fpr[n-32]);
return 8;
} else {
@@ -647,7 +659,12 @@ static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
case 67: GET_REGL(env->lr);
case 68: GET_REGL(env->ctr);
case 69: GET_REGL(env->xer);
- case 70: GET_REG32(0); /* fpscr */
+ case 70:
+ {
+ if (gdb_has_xml)
+ return 0;
+ GET_REG32(0); /* fpscr */
+ }
}
}
return 0;
@@ -661,6 +678,8 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
return sizeof(target_ulong);
} else if (n < 64) {
/* fprs */
+ if (gdb_has_xml)
+ return 0;
env->fpr[n-32] = ldfq_p(mem_buf);
return 8;
} else {
@@ -690,6 +709,8 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
return sizeof(target_ulong);
case 70:
/* fpscr */
+ if (gdb_has_xml)
+ return 0;
return 4;
}
}
@@ -1879,7 +1900,7 @@ void gdb_set_stop_cpu(CPUState *env)
}
#ifndef CONFIG_USER_ONLY
-static void gdb_vm_stopped(void *opaque, int reason)
+static void gdb_vm_state_change(void *opaque, int running, int reason)
{
GDBState *s = gdbserver_state;
CPUState *env = s->c_cpu;
@@ -1887,7 +1908,8 @@ static void gdb_vm_stopped(void *opaque, int reason)
const char *type;
int ret;
- if (s->state == RS_SYSCALL)
+ if (running || (reason != EXCP_DEBUG && reason != EXCP_INTERRUPT) ||
+ s->state == RS_SYSCALL)
return;
/* disable single step if it was enable */
@@ -1916,10 +1938,8 @@ static void gdb_vm_stopped(void *opaque, int reason)
}
tb_flush(env);
ret = GDB_SIGNAL_TRAP;
- } else if (reason == EXCP_INTERRUPT) {
- ret = GDB_SIGNAL_INT;
} else {
- ret = 0;
+ ret = GDB_SIGNAL_INT;
}
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, env->cpu_index+1);
put_packet(s, buf);
@@ -2312,7 +2332,7 @@ int gdbserver_start(const char *port)
gdbserver_state = s;
qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
gdb_chr_event, NULL);
- qemu_add_vm_stop_handler(gdb_vm_stopped, NULL);
+ qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
return 0;
}
#endif
diff --git a/hw/ac97.c b/hw/ac97.c
index dc9a165a3..ade271911 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1336,11 +1336,8 @@ int ac97_init (PCIBus *bus, AudioState *audio)
s = &d->ac97;
s->pci_dev = &d->dev;
c = d->dev.config;
- c[0x00] = 0x86; /* vid vendor id intel ro */
- c[0x01] = 0x80; /* intel */
-
- c[0x02] = 0x15; /* did device id 82801 ro */
- c[0x03] = 0x24; /* 82801aa */
+ pci_config_set_vendor_id(c, PCI_VENDOR_ID_INTEL); /* ro */
+ pci_config_set_device_id(c, PCI_DEVICE_ID_INTEL_82801AA_5); /* ro */
c[0x04] = 0x00; /* pcicmd pci command rw, ro */
c[0x05] = 0x00;
@@ -1350,8 +1347,7 @@ int ac97_init (PCIBus *bus, AudioState *audio)
c[0x08] = 0x01; /* rid revision ro */
c[0x09] = 0x00; /* pi programming interface ro */
- c[0x0a] = 0x01; /* scc sub class code ro */
- c[0x0b] = 0x04; /* bcc base class code ro */
+ pci_config_set_class(c, PCI_CLASS_MULTIMEDIA_AUDIO); /* ro */
c[0x0e] = 0x00; /* headtyp header type ro */
c[0x10] = 0x01; /* nabmar native audio mixer base
diff --git a/hw/acpi.c b/hw/acpi.c
index 86d030d20..b998225fe 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -505,16 +505,13 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
devfn, NULL, pm_write_config);
pm_state = s;
pci_conf = s->dev.config;
- pci_conf[0x00] = 0x86;
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x13;
- pci_conf[0x03] = 0x71;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_3);
pci_conf[0x06] = 0x80;
pci_conf[0x07] = 0x02;
pci_conf[0x08] = 0x03; // revision number
pci_conf[0x09] = 0x00;
- pci_conf[0x0a] = 0x80; // other bridge device
- pci_conf[0x0b] = 0x06; // bridge device
+ pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x3d] = 0x01; // interrupt pin 1
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index f222f3c0e..a179acde7 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -252,25 +252,24 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice),
0, NULL, NULL);
- d->config[0x00] = 0x8e; // vendor_id : Sun
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x00; // device_id
- d->config[0x03] = 0xa0;
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_SUN);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_SUN_SABRE);
d->config[0x04] = 0x06; // command = bus master, pci mem
d->config[0x05] = 0x00;
d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
d->config[0x07] = 0x03; // status = medium devsel
d->config[0x08] = 0x00; // revision
d->config[0x09] = 0x00; // programming i/f
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x0D] = 0x10; // latency_timer
d->config[0x0E] = 0x00; // header_type
/* APB secondary busses */
- *bus2 = pci_bridge_init(s->bus, 8, 0x108e5000, pci_apb_map_irq,
+ *bus2 = pci_bridge_init(s->bus, 8, PCI_VENDOR_ID_SUN,
+ PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
"Advanced PCI Bus secondary bridge 1");
- *bus3 = pci_bridge_init(s->bus, 9, 0x108e5000, pci_apb_map_irq,
+ *bus3 = pci_bridge_init(s->bus, 9, PCI_VENDOR_ID_SUN,
+ PCI_DEVICE_ID_SUN_SIMBA, pci_apb_map_irq,
"Advanced PCI Bus secondary bridge 2");
return s->bus;
}
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index 066b96944..e7fdc639e 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -252,7 +252,7 @@ static void main_cpu_reset(void *opaque)
static
void axisdev88_init (ram_addr_t ram_size, int vga_ram_size,
- const char *boot_device, DisplayState *ds,
+ const char *boot_device,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename, const char *cpu_model)
{
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index fe21c6822..84cf640da 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -174,8 +174,7 @@
#define CIRRUS_MMIO_LINEDRAW_MODE 0x39 // byte
#define CIRRUS_MMIO_BLTSTATUS 0x40 // byte
-// PCI 0x00: vendor, 0x02: device
-#define PCI_VENDOR_CIRRUS 0x1013
+// PCI 0x02: device
#define PCI_DEVICE_CLGD5462 0x00d0
#define PCI_DEVICE_CLGD5465 0x00d6
@@ -3385,13 +3384,10 @@ void pci_cirrus_vga_init(PCIBus *bus, uint8_t *vga_ram_base,
sizeof(PCICirrusVGAState),
-1, NULL, pci_cirrus_write_config);
pci_conf = d->dev.config;
- pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff);
- pci_conf[0x01] = (uint8_t) (PCI_VENDOR_CIRRUS >> 8);
- pci_conf[0x02] = (uint8_t) (device_id & 0xff);
- pci_conf[0x03] = (uint8_t) (device_id >> 8);
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CIRRUS);
+ pci_config_set_device_id(pci_conf, device_id);
pci_conf[0x04] = PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS;
- pci_conf[0x0a] = PCI_CLASS_SUB_VGA;
- pci_conf[0x0b] = PCI_CLASS_BASE_DISPLAY;
+ pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
pci_conf[0x0e] = PCI_CLASS_HEADERTYPE_00h;
/* setup VGA */
diff --git a/hw/e1000.c b/hw/e1000.c
index eaed351f1..fe155d428 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1063,13 +1063,12 @@ pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn)
pci_conf = d->dev.config;
memset(pci_conf, 0, 256);
- *(uint16_t *)(pci_conf+0x00) = cpu_to_le16(0x8086);
- *(uint16_t *)(pci_conf+0x02) = cpu_to_le16(E1000_DEVID);
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, E1000_DEVID);
*(uint16_t *)(pci_conf+0x04) = cpu_to_le16(0x0407);
*(uint16_t *)(pci_conf+0x06) = cpu_to_le16(0x0010);
pci_conf[0x08] = 0x03;
- pci_conf[0x0a] = 0x00; // ethernet network controller
- pci_conf[0x0b] = 0x02;
+ pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
pci_conf[0x0c] = 0x10;
pci_conf[0x3d] = 1; // interrupt pin 0
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 0061ea7e2..adc936a3f 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -422,9 +422,9 @@ static void pci_reset(EEPRO100State * s)
logout("%p\n", s);
/* PCI Vendor ID */
- PCI_CONFIG_16(PCI_VENDOR_ID, 0x8086);
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
/* PCI Device ID */
- PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209);
+ pci_config_set_device_id(pci_conf, 0x1209);
/* PCI Command */
PCI_CONFIG_16(PCI_COMMAND, 0x0000);
/* PCI Status */
@@ -433,8 +433,7 @@ static void pci_reset(EEPRO100State * s)
PCI_CONFIG_8(PCI_REVISION_ID, 0x08);
/* PCI Class Code */
PCI_CONFIG_8(0x09, 0x00);
- PCI_CONFIG_8(PCI_SUBCLASS_CODE, 0x00); // ethernet network controller
- PCI_CONFIG_8(PCI_CLASS_CODE, 0x02); // network controller
+ pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
/* PCI Cache Line Size */
/* check cache line size!!! */
//~ PCI_CONFIG_8(0x0c, 0x00);
diff --git a/hw/es1370.c b/hw/es1370.c
index bad237d21..50f5a552e 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -1031,13 +1031,10 @@ int es1370_init (PCIBus *bus, AudioState *audio)
}
c = d->dev.config;
- c[0x00] = 0x74;
- c[0x01] = 0x12;
- c[0x02] = 0x00;
- c[0x03] = 0x50;
+ pci_config_set_vendor_id(c, PCI_VENDOR_ID_ENSONIQ);
+ pci_config_set_device_id(c, PCI_DEVICE_ID_ENSONIQ_ES1370);
c[0x07] = 2 << 1;
- c[0x0a] = 0x01;
- c[0x0b] = 0x04;
+ pci_config_set_class(c, PCI_CLASS_MULTIMEDIA_AUDIO);
#if 1
c[0x2c] = 0x42;
diff --git a/hw/fdc.c b/hw/fdc.c
index b1b4bc7d0..5913be74e 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -53,8 +53,9 @@ do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ##args); } while (0)
#define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive))
/* Will always be a fixed parameter for us */
-#define FD_SECTOR_LEN 512
-#define FD_SECTOR_SC 2 /* Sector size code */
+#define FD_SECTOR_LEN 512
+#define FD_SECTOR_SC 2 /* Sector size code */
+#define FD_RESET_SENSEI_COUNT 4 /* Number of sense interrupts on RESET */
/* Floppy disk drive emulation */
typedef enum fdisk_type_t {
@@ -506,6 +507,7 @@ struct fdctrl_t {
int sun4m;
/* Floppy drives */
fdrive_t drives[MAX_FD];
+ int reset_sensei;
};
static uint32_t fdctrl_read (void *opaque, uint32_t reg)
@@ -763,6 +765,7 @@ static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status0)
qemu_set_irq(fdctrl->irq, 1);
fdctrl->sra |= FD_SRA_INTPEND;
}
+ fdctrl->reset_sensei = 0;
fdctrl->status0 = status0;
FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0);
}
@@ -793,6 +796,7 @@ static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq)
fdctrl_reset_fifo(fdctrl);
if (do_irq) {
fdctrl_raise_irq(fdctrl, FD_SR0_RDYCHG);
+ fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT;
}
}
@@ -1601,16 +1605,18 @@ static void fdctrl_handle_sense_interrupt_status (fdctrl_t *fdctrl, int directio
{
fdrive_t *cur_drv = get_cur_drv(fdctrl);
-#if 0
- fdctrl->fifo[0] =
- fdctrl->status0 | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
-#else
- /* XXX: status0 handling is broken for read/write
- commands, so we do this hack. It should be suppressed
- ASAP */
- fdctrl->fifo[0] =
- FD_SR0_SEEK | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
-#endif
+ if(fdctrl->reset_sensei > 0) {
+ fdctrl->fifo[0] =
+ FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl->reset_sensei;
+ fdctrl->reset_sensei--;
+ } else {
+ /* XXX: status0 handling is broken for read/write
+ commands, so we do this hack. It should be suppressed
+ ASAP */
+ fdctrl->fifo[0] =
+ FD_SR0_SEEK | (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
+ }
+
fdctrl->fifo[1] = cur_drv->track;
fdctrl_set_fifo(fdctrl, 2, 0);
fdctrl_reset_irq(fdctrl);
diff --git a/hw/fmopl.c b/hw/fmopl.c
index 67a23b699..52cf35e3f 100644
--- a/hw/fmopl.c
+++ b/hw/fmopl.c
@@ -31,7 +31,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
*/
-#define INLINE __inline
+#define INLINE static inline
#define HAS_YM3812 1
#include <stdio.h>
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index f875e5d23..516172791 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -144,25 +144,19 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data);
d = pci_register_device(s->bus, "Grackle host bridge", sizeof(PCIDevice),
0, NULL, NULL);
- d->config[0x00] = 0x57; // vendor_id
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x02; // device_id
- d->config[0x03] = 0x00;
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MOTOROLA);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_MOTOROLA_MPC106);
d->config[0x08] = 0x00; // revision
d->config[0x09] = 0x01;
- d->config[0x0a] = 0x00; // class_sub = host
- d->config[0x0b] = 0x06; // class_base = PCI_bridge
+ pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x0e] = 0x00; // header_type
#if 0
/* PCI2PCI bridge same values as PearPC - check this */
- d->config[0x00] = 0x11; // vendor_id
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x26; // device_id
- d->config[0x03] = 0x00;
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_DEC);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_DEC_21154);
d->config[0x08] = 0x02; // revision
- d->config[0x0a] = 0x04; // class_sub = pci2pci
- d->config[0x0b] = 0x06; // class_base = PCI_bridge
+ pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
d->config[0x0e] = 0x01; // header_type
d->config[0x18] = 0x0; // primary_bus
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index b6cd9714f..53014bcb4 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1136,10 +1136,8 @@ PCIBus *pci_gt64120_init(qemu_irq *pic)
/* FIXME: Malta specific hw assumptions ahead */
- d->config[0x00] = 0xab; /* vendor_id */
- d->config[0x01] = 0x11;
- d->config[0x02] = 0x20; /* device_id */
- d->config[0x03] = 0x46;
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MARVELL);
+ pci_config_set_device_id(d->config, 0x4620); /* device_id */
d->config[0x04] = 0x00;
d->config[0x05] = 0x00;
@@ -1148,8 +1146,7 @@ PCIBus *pci_gt64120_init(qemu_irq *pic)
d->config[0x08] = 0x10;
d->config[0x09] = 0x00;
- d->config[0x0A] = 0x00;
- d->config[0x0B] = 0x06;
+ pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x10] = 0x08;
d->config[0x14] = 0x08;
diff --git a/hw/i8254.c b/hw/i8254.c
index e6be0cd3c..41d1605cc 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -463,7 +463,8 @@ void pit_reset(void *opaque)
void hpet_pit_disable(void) {
PITChannelState *s;
s = &pit_state.channels[0];
- qemu_del_timer(s->irq_timer);
+ if (s->irq_timer)
+ qemu_del_timer(s->irq_timer);
}
/* When HPET is reset or leaving legacy mode, it must reenable i8254
diff --git a/hw/ide.c b/hw/ide.c
index b99a0c6fa..d5f4403e5 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -32,6 +32,7 @@
#include "qemu-timer.h"
#include "sysemu.h"
#include "ppc_mac.h"
+#include "mac_dbdma.h"
#include "sh.h"
/* debug IDE devices */
@@ -423,6 +424,7 @@ typedef struct IDEState {
int atapi_dma; /* true if dma is requested for the packet cmd */
/* ATA DMA state */
int io_buffer_size;
+ QEMUIOVector iovec;
/* PIO transfer handling */
int req_nb_sectors; /* number of sectors per interrupt */
EndTransferFunc *end_transfer_func;
@@ -437,6 +439,8 @@ typedef struct IDEState {
uint32_t mdata_size;
uint8_t *mdata_storage;
int media_changed;
+ /* for pmac */
+ int is_read;
} IDEState;
/* XXX: DVDs that could fit on a CD will be reported as a CD */
@@ -863,6 +867,66 @@ static void ide_sector_read(IDEState *s)
}
}
+
+/* return 0 if buffer completed */
+static int dma_buf_prepare(BMDMAState *bm, int is_write)
+{
+ IDEState *s = bm->ide_if;
+ struct {
+ uint32_t addr;
+ uint32_t size;
+ } prd;
+ int l, len;
+ void *mem;
+ target_phys_addr_t l1;
+
+ qemu_iovec_init(&s->iovec, s->nsector / (TARGET_PAGE_SIZE/512) + 1);
+ s->io_buffer_size = 0;
+ for(;;) {
+ if (bm->cur_prd_len == 0) {
+ /* end of table (with a fail safe of one page) */
+ if (bm->cur_prd_last ||
+ (bm->cur_addr - bm->addr) >= 4096)
+ return s->io_buffer_size != 0;
+ cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
+ bm->cur_addr += 8;
+ prd.addr = le32_to_cpu(prd.addr);
+ prd.size = le32_to_cpu(prd.size);
+ len = prd.size & 0xfffe;
+ if (len == 0)
+ len = 0x10000;
+ bm->cur_prd_len = len;
+ bm->cur_prd_addr = prd.addr;
+ bm->cur_prd_last = (prd.size & 0x80000000);
+ }
+ l = bm->cur_prd_len;
+ if (l > 0) {
+ l1 = l;
+ mem = cpu_physical_memory_map(bm->cur_prd_addr, &l1, is_write);
+ if (!mem) {
+ break;
+ }
+ qemu_iovec_add(&s->iovec, mem, l1);
+ bm->cur_prd_addr += l1;
+ bm->cur_prd_len -= l1;
+ s->io_buffer_size += l1;
+ }
+ }
+ return 1;
+}
+
+static void dma_buf_commit(IDEState *s, int is_write)
+{
+ int i;
+
+ for (i = 0; i < s->iovec.niov; ++i) {
+ cpu_physical_memory_unmap(s->iovec.iov[i].iov_base,
+ s->iovec.iov[i].iov_len, is_write,
+ s->iovec.iov[i].iov_len);
+ }
+ qemu_iovec_destroy(&s->iovec);
+}
+
static void ide_dma_error(IDEState *s)
{
ide_transfer_stop(s);
@@ -884,10 +948,12 @@ static int ide_handle_write_error(IDEState *s, int error, int op)
s->bmdma->status |= op;
vm_stop(0);
} else {
- if (op == BM_STATUS_DMA_RETRY)
+ if (op == BM_STATUS_DMA_RETRY) {
+ dma_buf_commit(s, 0);
ide_dma_error(s);
- else
+ } else {
ide_rw_error(s);
+ }
}
return 1;
@@ -941,6 +1007,39 @@ static int dma_buf_rw(BMDMAState *bm, int is_write)
return 1;
}
+typedef struct {
+ BMDMAState *bm;
+ void (*cb)(void *opaque, int ret);
+ QEMUBH *bh;
+} MapFailureContinuation;
+
+static void reschedule_dma(void *opaque)
+{
+ MapFailureContinuation *cont = opaque;
+
+ cont->cb(cont->bm, 0);
+ qemu_bh_delete(cont->bh);
+ qemu_free(cont);
+}
+
+static void continue_after_map_failure(void *opaque)
+{
+ MapFailureContinuation *cont = opaque;
+
+ cont->bh = qemu_bh_new(reschedule_dma, opaque);
+ qemu_bh_schedule(cont->bh);
+}
+
+static void wait_for_bounce_buffer(BMDMAState *bmdma,
+ void (*cb)(void *opaque, int ret))
+{
+ MapFailureContinuation *cont = qemu_malloc(sizeof(*cont));
+
+ cont->bm = bmdma;
+ cont->cb = cb;
+ cpu_register_map_client(cont, continue_after_map_failure);
+}
+
static void ide_read_dma_cb(void *opaque, int ret)
{
BMDMAState *bm = opaque;
@@ -949,6 +1048,7 @@ static void ide_read_dma_cb(void *opaque, int ret)
int64_t sector_num;
if (ret < 0) {
+ dma_buf_commit(s, 1);
ide_dma_error(s);
return;
}
@@ -956,11 +1056,10 @@ static void ide_read_dma_cb(void *opaque, int ret)
n = s->io_buffer_size >> 9;
sector_num = ide_get_sector(s);
if (n > 0) {
+ dma_buf_commit(s, 1);
sector_num += n;
ide_set_sector(s, sector_num);
s->nsector -= n;
- if (dma_buf_rw(bm, 1) == 0)
- goto eot;
}
/* end of transfer ? */
@@ -978,15 +1077,19 @@ static void ide_read_dma_cb(void *opaque, int ret)
/* launch next transfer */
n = s->nsector;
- if (n > IDE_DMA_BUF_SECTORS)
- n = IDE_DMA_BUF_SECTORS;
s->io_buffer_index = 0;
s->io_buffer_size = n * 512;
+ if (dma_buf_prepare(bm, 1) == 0)
+ goto eot;
+ if (!s->iovec.niov) {
+ wait_for_bounce_buffer(bm, ide_read_dma_cb);
+ return;
+ }
#ifdef DEBUG_AIO
printf("aio_read: sector_num=%" PRId64 " n=%d\n", sector_num, n);
#endif
- bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n,
- ide_read_dma_cb, bm);
+ bm->aiocb = bdrv_aio_readv(s->bs, sector_num, &s->iovec, n,
+ ide_read_dma_cb, bm);
ide_dma_submit_check(s, ide_read_dma_cb, bm);
}
@@ -995,6 +1098,7 @@ static void ide_sector_read_dma(IDEState *s)
s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
s->io_buffer_index = 0;
s->io_buffer_size = 0;
+ s->is_read = 1;
ide_dma_start(s, ide_read_dma_cb);
}
@@ -1053,7 +1157,7 @@ static void ide_sector_write(IDEState *s)
}
}
-static void ide_dma_restart_cb(void *opaque, int running)
+static void ide_dma_restart_cb(void *opaque, int running, int reason)
{
BMDMAState *bm = opaque;
if (!running)
@@ -1082,6 +1186,7 @@ static void ide_write_dma_cb(void *opaque, int ret)
n = s->io_buffer_size >> 9;
sector_num = ide_get_sector(s);
if (n > 0) {
+ dma_buf_commit(s, 0);
sector_num += n;
ide_set_sector(s, sector_num);
s->nsector -= n;
@@ -1100,20 +1205,20 @@ static void ide_write_dma_cb(void *opaque, int ret)
return;
}
- /* launch next transfer */
n = s->nsector;
- if (n > IDE_DMA_BUF_SECTORS)
- n = IDE_DMA_BUF_SECTORS;
- s->io_buffer_index = 0;
s->io_buffer_size = n * 512;
-
- if (dma_buf_rw(bm, 0) == 0)
+ /* launch next transfer */
+ if (dma_buf_prepare(bm, 0) == 0)
goto eot;
+ if (!s->iovec.niov) {
+ wait_for_bounce_buffer(bm, ide_write_dma_cb);
+ return;
+ }
#ifdef DEBUG_AIO
printf("aio_write: sector_num=%" PRId64 " n=%d\n", sector_num, n);
#endif
- bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n,
- ide_write_dma_cb, bm);
+ bm->aiocb = bdrv_aio_writev(s->bs, sector_num, &s->iovec, n,
+ ide_write_dma_cb, bm);
ide_dma_submit_check(s, ide_write_dma_cb, bm);
}
@@ -1122,6 +1227,7 @@ static void ide_sector_write_dma(IDEState *s)
s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
s->io_buffer_index = 0;
s->io_buffer_size = 0;
+ s->is_read = 0;
ide_dma_start(s, ide_write_dma_cb);
}
@@ -3242,16 +3348,13 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
NULL, NULL);
d->type = IDE_TYPE_CMD646;
pci_conf = d->dev.config;
- pci_conf[0x00] = 0x95; // CMD646
- pci_conf[0x01] = 0x10;
- pci_conf[0x02] = 0x46;
- pci_conf[0x03] = 0x06;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CMD);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_CMD_646);
pci_conf[0x08] = 0x07; // IDE controller revision
pci_conf[0x09] = 0x8f;
- pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
- pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
+ pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x51] = 0x04; // enable IDE0
@@ -3318,13 +3421,10 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
d->type = IDE_TYPE_PIIX3;
pci_conf = d->dev.config;
- pci_conf[0x00] = 0x86; // Intel
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x10;
- pci_conf[0x03] = 0x70;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371SB_1);
pci_conf[0x09] = 0x80; // legacy ATA mode
- pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
- pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
+ pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
pci_conf[0x0e] = 0x00; // header_type
qemu_register_reset(piix3_reset, d);
@@ -3361,13 +3461,10 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
d->type = IDE_TYPE_PIIX4;
pci_conf = d->dev.config;
- pci_conf[0x00] = 0x86; // Intel
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x11;
- pci_conf[0x03] = 0x71;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB);
pci_conf[0x09] = 0x80; // legacy ATA mode
- pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
- pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
+ pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
pci_conf[0x0e] = 0x00; // header_type
qemu_register_reset(piix3_reset, d);
@@ -3384,21 +3481,130 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
register_savevm("ide", 0, 2, pci_ide_save, pci_ide_load, d);
}
+#if defined(TARGET_PPC)
/***********************************************************/
/* MacIO based PowerPC IDE */
+typedef struct MACIOIDEState {
+ IDEState ide_if[2];
+ void *dbdma;
+ int stream_index;
+} MACIOIDEState;
+
+static int pmac_atapi_read(DBDMA_transfer *info, DBDMA_transfer_cb cb)
+{
+ MACIOIDEState *m = info->opaque;
+ IDEState *s = m->ide_if->cur_drive;
+ int ret;
+
+ if (s->lba == -1)
+ return 0;
+
+ info->buf_pos = 0;
+
+ while (info->buf_pos < info->len && s->packet_transfer_size > 0) {
+
+ ret = cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size);
+ if (ret < 0) {
+ ide_transfer_stop(s);
+ ide_atapi_io_error(s, ret);
+ return info->buf_pos;
+ }
+
+ info->buf = s->io_buffer + m->stream_index;
+
+ info->buf_len = s->cd_sector_size;
+ if (info->buf_pos + info->buf_len > info->len)
+ info->buf_len = info->len - info->buf_pos;
+
+ cb(info);
+
+ /* db-dma can ask for 512 bytes whereas block size is 2048... */
+
+ m->stream_index += info->buf_len;
+ s->lba += m->stream_index / s->cd_sector_size;
+ m->stream_index %= s->cd_sector_size;
+
+ info->buf_pos += info->buf_len;
+ s->packet_transfer_size -= info->buf_len;
+ }
+ if (s->packet_transfer_size <= 0) {
+ s->status = READY_STAT | SEEK_STAT;
+ s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO
+ | ATAPI_INT_REASON_CD;
+ ide_set_irq(s);
+ }
+
+ return info->buf_pos;
+}
+
+static int pmac_ide_transfer(DBDMA_transfer *info,
+ DBDMA_transfer_cb cb)
+{
+ MACIOIDEState *m = info->opaque;
+ IDEState *s = m->ide_if->cur_drive;
+ int64_t sector_num;
+ int ret, n;
+
+ if (s->is_cdrom)
+ return pmac_atapi_read(info, cb);
+
+ info->buf = s->io_buffer;
+ info->buf_pos = 0;
+ while (info->buf_pos < info->len && s->nsector > 0) {
+
+ sector_num = ide_get_sector(s);
+
+ n = s->nsector;
+ if (n > IDE_DMA_BUF_SECTORS)
+ n = IDE_DMA_BUF_SECTORS;
+
+ info->buf_len = n << 9;
+ if (info->buf_pos + info->buf_len > info->len)
+ info->buf_len = info->len - info->buf_pos;
+ n = info->buf_len >> 9;
+
+ if (s->is_read) {
+ ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
+ if (ret == 0)
+ cb(info);
+ } else {
+ cb(info);
+ ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
+ }
+
+ if (ret != 0) {
+ ide_rw_error(s);
+ return info->buf_pos;
+ }
+
+ info->buf_pos += n << 9;
+ ide_set_sector(s, sector_num + n);
+ s->nsector -= n;
+ }
+
+ if (s->nsector <= 0) {
+ s->status = READY_STAT | SEEK_STAT;
+ ide_set_irq(s);
+ }
+
+ return info->buf_pos;
+}
+
/* PowerMac IDE memory IO */
static void pmac_ide_writeb (void *opaque,
target_phys_addr_t addr, uint32_t val)
{
+ MACIOIDEState *d = opaque;
+
addr = (addr & 0xFFF) >> 4;
switch (addr) {
case 1 ... 7:
- ide_ioport_write(opaque, addr, val);
+ ide_ioport_write(d->ide_if, addr, val);
break;
case 8:
case 22:
- ide_cmd_write(opaque, 0, val);
+ ide_cmd_write(d->ide_if, 0, val);
break;
default:
break;
@@ -3408,15 +3614,16 @@ static void pmac_ide_writeb (void *opaque,
static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr)
{
uint8_t retval;
+ MACIOIDEState *d = opaque;
addr = (addr & 0xFFF) >> 4;
switch (addr) {
case 1 ... 7:
- retval = ide_ioport_read(opaque, addr);
+ retval = ide_ioport_read(d->ide_if, addr);
break;
case 8:
case 22:
- retval = ide_status_read(opaque, 0);
+ retval = ide_status_read(d->ide_if, 0);
break;
default:
retval = 0xFF;
@@ -3428,22 +3635,25 @@ static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr)
static void pmac_ide_writew (void *opaque,
target_phys_addr_t addr, uint32_t val)
{
+ MACIOIDEState *d = opaque;
+
addr = (addr & 0xFFF) >> 4;
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap16(val);
#endif
if (addr == 0) {
- ide_data_writew(opaque, 0, val);
+ ide_data_writew(d->ide_if, 0, val);
}
}
static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr)
{
uint16_t retval;
+ MACIOIDEState *d = opaque;
addr = (addr & 0xFFF) >> 4;
if (addr == 0) {
- retval = ide_data_readw(opaque, 0);
+ retval = ide_data_readw(d->ide_if, 0);
} else {
retval = 0xFFFF;
}
@@ -3456,22 +3666,25 @@ static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr)
static void pmac_ide_writel (void *opaque,
target_phys_addr_t addr, uint32_t val)
{
+ MACIOIDEState *d = opaque;
+
addr = (addr & 0xFFF) >> 4;
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
if (addr == 0) {
- ide_data_writel(opaque, 0, val);
+ ide_data_writel(d->ide_if, 0, val);
}
}
static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr)
{
uint32_t retval;
+ MACIOIDEState *d = opaque;
addr = (addr & 0xFFF) >> 4;
if (addr == 0) {
- retval = ide_data_readl(opaque, 0);
+ retval = ide_data_readl(d->ide_if, 0);
} else {
retval = 0xFFFFFFFF;
}
@@ -3495,7 +3708,8 @@ static CPUReadMemoryFunc *pmac_ide_read[] = {
static void pmac_ide_save(QEMUFile *f, void *opaque)
{
- IDEState *s = (IDEState *)opaque;
+ MACIOIDEState *d = opaque;
+ IDEState *s = d->ide_if;
uint8_t drive1_selected;
unsigned int i;
@@ -3512,7 +3726,8 @@ static void pmac_ide_save(QEMUFile *f, void *opaque)
static int pmac_ide_load(QEMUFile *f, void *opaque, int version_id)
{
- IDEState *s = (IDEState *)opaque;
+ MACIOIDEState *d = opaque;
+ IDEState *s = d->ide_if;
uint8_t drive1_selected;
unsigned int i;
@@ -3533,7 +3748,8 @@ static int pmac_ide_load(QEMUFile *f, void *opaque, int version_id)
static void pmac_ide_reset(void *opaque)
{
- IDEState *s = (IDEState *)opaque;
+ MACIOIDEState *d = opaque;
+ IDEState *s = d->ide_if;
ide_reset(&s[0]);
ide_reset(&s[1]);
@@ -3542,21 +3758,29 @@ static void pmac_ide_reset(void *opaque)
/* hd_table must contain 4 block drivers */
/* PowerMac uses memory mapped registers, not I/O. Return the memory
I/O index to access the ide. */
-int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq)
+int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq,
+ void *dbdma, int channel, qemu_irq dma_irq)
{
- IDEState *ide_if;
+ MACIOIDEState *d;
int pmac_ide_memory;
- ide_if = qemu_mallocz(sizeof(IDEState) * 2);
- ide_init2(&ide_if[0], hd_table[0], hd_table[1], irq);
+ d = qemu_mallocz(sizeof(MACIOIDEState));
+ ide_init2(d->ide_if, hd_table[0], hd_table[1], irq);
+
+ if (dbdma) {
+ d->dbdma = dbdma;
+ DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, d);
+ }
pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read,
- pmac_ide_write, &ide_if[0]);
- register_savevm("ide", 0, 1, pmac_ide_save, pmac_ide_load, &ide_if[0]);
- qemu_register_reset(pmac_ide_reset, &ide_if[0]);
- pmac_ide_reset(&ide_if[0]);
+ pmac_ide_write, d);
+ register_savevm("ide", 0, 1, pmac_ide_save, pmac_ide_load, d);
+ qemu_register_reset(pmac_ide_reset, d);
+ pmac_ide_reset(d);
+
return pmac_ide_memory;
}
+#endif /* TARGET_PPC */
/***********************************************************/
/* MMIO based ide port
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 6aec059d6..520f5d6cd 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -1977,6 +1977,7 @@ static int lsi_scsi_uninit(PCIDevice *d)
void *lsi_scsi_init(PCIBus *bus, int devfn)
{
LSIState *s;
+ uint8_t *pci_conf;
s = (LSIState *)pci_register_device(bus, "LSI53C895A SCSI HBA",
sizeof(*s), devfn, NULL, NULL);
@@ -1985,21 +1986,21 @@ void *lsi_scsi_init(PCIBus *bus, int devfn)
return NULL;
}
+ pci_conf = s->pci_dev.config;
+
/* PCI Vendor ID (word) */
- s->pci_dev.config[0x00] = 0x00;
- s->pci_dev.config[0x01] = 0x10;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_LSI_LOGIC);
/* PCI device ID (word) */
- s->pci_dev.config[0x02] = 0x12;
- s->pci_dev.config[0x03] = 0x00;
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_LSI_53C895A);
/* PCI base class code */
- s->pci_dev.config[0x0b] = 0x01;
+ pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_SCSI);
/* PCI subsystem ID */
- s->pci_dev.config[0x2e] = 0x00;
- s->pci_dev.config[0x2f] = 0x10;
+ pci_conf[0x2e] = 0x00;
+ pci_conf[0x2f] = 0x10;
/* PCI latency timer = 255 */
- s->pci_dev.config[0x0d] = 0xff;
+ pci_conf[0x0d] = 0xff;
/* Interrupt pin 1 */
- s->pci_dev.config[0x3d] = 0x01;
+ pci_conf[0x3d] = 0x01;
s->mmio_io_addr = cpu_register_io_memory(0, lsi_mmio_readfn,
lsi_mmio_writefn, s);
diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c
index 13fbd7bf8..a6ef479d2 100644
--- a/hw/mac_dbdma.c
+++ b/hw/mac_dbdma.c
@@ -3,6 +3,20 @@
*
* Copyright (c) 2005-2007 Fabrice Bellard
* Copyright (c) 2007 Jocelyn Mayer
+ * Copyright (c) 2009 Laurent Vivier
+ *
+ * some parts from linux-2.6.28, arch/powerpc/include/asm/dbdma.h
+ *
+ * Definitions for using the Apple Descriptor-Based DMA controller
+ * in Power Macintosh computers.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * some parts from mol 0.9.71
+ *
+ * Descriptor based DMA emulation
+ *
+ * Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +37,8 @@
* THE SOFTWARE.
*/
#include "hw.h"
-#include "ppc_mac.h"
+#include "isa.h"
+#include "mac_dbdma.h"
/* debug DBDMA */
//#define DEBUG_DBDMA
@@ -35,79 +50,830 @@ do { printf("DBDMA: " fmt , ##args); } while (0)
#define DBDMA_DPRINTF(fmt, args...)
#endif
-/* DBDMA: currently no op - should suffice right now */
+/*
+ */
+
+/*
+ * DBDMA control/status registers. All little-endian.
+ */
-static void dbdma_writeb (void *opaque,
- target_phys_addr_t addr, uint32_t value)
+#define DBDMA_CONTROL 0x00
+#define DBDMA_STATUS 0x01
+#define DBDMA_CMDPTR_HI 0x02
+#define DBDMA_CMDPTR_LO 0x03
+#define DBDMA_INTR_SEL 0x04
+#define DBDMA_BRANCH_SEL 0x05
+#define DBDMA_WAIT_SEL 0x06
+#define DBDMA_XFER_MODE 0x07
+#define DBDMA_DATA2PTR_HI 0x08
+#define DBDMA_DATA2PTR_LO 0x09
+#define DBDMA_RES1 0x0A
+#define DBDMA_ADDRESS_HI 0x0B
+#define DBDMA_BRANCH_ADDR_HI 0x0C
+#define DBDMA_RES2 0x0D
+#define DBDMA_RES3 0x0E
+#define DBDMA_RES4 0x0F
+
+#define DBDMA_REGS 16
+#define DBDMA_SIZE (DBDMA_REGS * sizeof(uint32_t))
+
+#define DBDMA_CHANNEL_SHIFT 7
+#define DBDMA_CHANNEL_SIZE (1 << DBDMA_CHANNEL_SHIFT)
+
+#define DBDMA_CHANNELS (0x1000 >> DBDMA_CHANNEL_SHIFT)
+
+/* Bits in control and status registers */
+
+#define RUN 0x8000
+#define PAUSE 0x4000
+#define FLUSH 0x2000
+#define WAKE 0x1000
+#define DEAD 0x0800
+#define ACTIVE 0x0400
+#define BT 0x0100
+#define DEVSTAT 0x00ff
+
+/*
+ * DBDMA command structure. These fields are all little-endian!
+ */
+
+typedef struct dbdma_cmd {
+ uint16_t req_count; /* requested byte transfer count */
+ uint16_t command; /* command word (has bit-fields) */
+ uint32_t phy_addr; /* physical data address */
+ uint32_t cmd_dep; /* command-dependent field */
+ uint16_t res_count; /* residual count after completion */
+ uint16_t xfer_status; /* transfer status */
+} dbdma_cmd;
+
+/* DBDMA command values in command field */
+
+#define COMMAND_MASK 0xf000
+#define OUTPUT_MORE 0x0000 /* transfer memory data to stream */
+#define OUTPUT_LAST 0x1000 /* ditto followed by end marker */
+#define INPUT_MORE 0x2000 /* transfer stream data to memory */
+#define INPUT_LAST 0x3000 /* ditto, expect end marker */
+#define STORE_WORD 0x4000 /* write word (4 bytes) to device reg */
+#define LOAD_WORD 0x5000 /* read word (4 bytes) from device reg */
+#define DBDMA_NOP 0x6000 /* do nothing */
+#define DBDMA_STOP 0x7000 /* suspend processing */
+
+/* Key values in command field */
+
+#define KEY_MASK 0x0700
+#define KEY_STREAM0 0x0000 /* usual data stream */
+#define KEY_STREAM1 0x0100 /* control/status stream */
+#define KEY_STREAM2 0x0200 /* device-dependent stream */
+#define KEY_STREAM3 0x0300 /* device-dependent stream */
+#define KEY_STREAM4 0x0400 /* reserved */
+#define KEY_REGS 0x0500 /* device register space */
+#define KEY_SYSTEM 0x0600 /* system memory-mapped space */
+#define KEY_DEVICE 0x0700 /* device memory-mapped space */
+
+/* Interrupt control values in command field */
+
+#define INTR_MASK 0x0030
+#define INTR_NEVER 0x0000 /* don't interrupt */
+#define INTR_IFSET 0x0010 /* intr if condition bit is 1 */
+#define INTR_IFCLR 0x0020 /* intr if condition bit is 0 */
+#define INTR_ALWAYS 0x0030 /* always interrupt */
+
+/* Branch control values in command field */
+
+#define BR_MASK 0x000c
+#define BR_NEVER 0x0000 /* don't branch */
+#define BR_IFSET 0x0004 /* branch if condition bit is 1 */
+#define BR_IFCLR 0x0008 /* branch if condition bit is 0 */
+#define BR_ALWAYS 0x000c /* always branch */
+
+/* Wait control values in command field */
+
+#define WAIT_MASK 0x0003
+#define WAIT_NEVER 0x0000 /* don't wait */
+#define WAIT_IFSET 0x0001 /* wait if condition bit is 1 */
+#define WAIT_IFCLR 0x0002 /* wait if condition bit is 0 */
+#define WAIT_ALWAYS 0x0003 /* always wait */
+
+typedef struct DBDMA_channel {
+ int channel;
+ uint32_t regs[DBDMA_REGS];
+ qemu_irq irq;
+ DBDMA_transfer io;
+ DBDMA_transfer_handler transfer_handler;
+ dbdma_cmd current;
+} DBDMA_channel;
+
+#ifdef DEBUG_DBDMA
+static void dump_dbdma_cmd(dbdma_cmd *cmd)
+{
+ printf("dbdma_cmd %p\n", cmd);
+ printf(" req_count 0x%04x\n", le16_to_cpu(cmd->req_count));
+ printf(" command 0x%04x\n", le16_to_cpu(cmd->command));
+ printf(" phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr));
+ printf(" cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep));
+ printf(" res_count 0x%04x\n", le16_to_cpu(cmd->res_count));
+ printf(" xfer_status 0x%04x\n", le16_to_cpu(cmd->xfer_status));
+}
+#else
+static void dump_dbdma_cmd(dbdma_cmd *cmd)
{
- DBDMA_DPRINTF("writeb 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
+}
+#endif
+static void dbdma_cmdptr_load(DBDMA_channel *ch)
+{
+ DBDMA_DPRINTF("dbdma_cmdptr_load 0x%08x\n",
+ be32_to_cpu(ch->regs[DBDMA_CMDPTR_LO]));
+ cpu_physical_memory_read(be32_to_cpu(ch->regs[DBDMA_CMDPTR_LO]),
+ (uint8_t*)&ch->current, sizeof(dbdma_cmd));
}
-static void dbdma_writew (void *opaque,
- target_phys_addr_t addr, uint32_t value)
+static void dbdma_cmdptr_save(DBDMA_channel *ch)
{
- DBDMA_DPRINTF("writew 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
+ DBDMA_DPRINTF("dbdma_cmdptr_save 0x%08x\n",
+ be32_to_cpu(ch->regs[DBDMA_CMDPTR_LO]));
+ DBDMA_DPRINTF("xfer_status 0x%08x res_count 0x%04x\n",
+ le16_to_cpu(ch->current.xfer_status),
+ le16_to_cpu(ch->current.res_count));
+ cpu_physical_memory_write(be32_to_cpu(ch->regs[DBDMA_CMDPTR_LO]),
+ (uint8_t*)&ch->current, sizeof(dbdma_cmd));
}
-static void dbdma_writel (void *opaque,
- target_phys_addr_t addr, uint32_t value)
+static void kill_channel(DBDMA_channel *ch)
{
- DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
+ DBDMA_DPRINTF("kill_channel\n");
+
+ ch->regs[DBDMA_STATUS] |= cpu_to_be32(DEAD);
+ ch->regs[DBDMA_STATUS] &= cpu_to_be32(~ACTIVE);
+
+ qemu_irq_raise(ch->irq);
+}
+
+static void conditional_interrupt(DBDMA_channel *ch)
+{
+ dbdma_cmd *current = &ch->current;
+ uint16_t intr;
+ uint16_t sel_mask, sel_value;
+ uint32_t status;
+ int cond;
+
+ DBDMA_DPRINTF("conditional_interrupt\n");
+
+ intr = be16_to_cpu(current->command) & INTR_MASK;
+
+ switch(intr) {
+ case INTR_NEVER: /* don't interrupt */
+ return;
+ case INTR_ALWAYS: /* always interrupt */
+ qemu_irq_raise(ch->irq);
+ return;
+ }
+
+ status = be32_to_cpu(ch->regs[DBDMA_STATUS]) & DEVSTAT;
+
+ sel_mask = (be32_to_cpu(ch->regs[DBDMA_INTR_SEL]) >> 16) & 0x0f;
+ sel_value = be32_to_cpu(ch->regs[DBDMA_INTR_SEL]) & 0x0f;
+
+ cond = (status & sel_mask) == (sel_value & sel_mask);
+
+ switch(intr) {
+ case INTR_IFSET: /* intr if condition bit is 1 */
+ if (cond)
+ qemu_irq_raise(ch->irq);
+ return;
+ case INTR_IFCLR: /* intr if condition bit is 0 */
+ if (!cond)
+ qemu_irq_raise(ch->irq);
+ return;
+ }
+}
+
+static int conditional_wait(DBDMA_channel *ch)
+{
+ dbdma_cmd *current = &ch->current;
+ uint16_t wait;
+ uint16_t sel_mask, sel_value;
+ uint32_t status;
+ int cond;
+
+ DBDMA_DPRINTF("conditional_wait\n");
+
+ wait = be16_to_cpu(current->command) & WAIT_MASK;
+
+ switch(wait) {
+ case WAIT_NEVER: /* don't wait */
+ return 0;
+ case WAIT_ALWAYS: /* always wait */
+ return 1;
+ }
+
+ status = be32_to_cpu(ch->regs[DBDMA_STATUS]) & DEVSTAT;
+
+ sel_mask = (be32_to_cpu(ch->regs[DBDMA_WAIT_SEL]) >> 16) & 0x0f;
+ sel_value = be32_to_cpu(ch->regs[DBDMA_WAIT_SEL]) & 0x0f;
+
+ cond = (status & sel_mask) == (sel_value & sel_mask);
+
+ switch(wait) {
+ case WAIT_IFSET: /* wait if condition bit is 1 */
+ if (cond)
+ return 1;
+ return 0;
+ case WAIT_IFCLR: /* wait if condition bit is 0 */
+ if (!cond)
+ return 1;
+ return 0;
+ }
+ return 0;
+}
+
+static void next(DBDMA_channel *ch)
+{
+ uint32_t cp;
+
+ ch->regs[DBDMA_STATUS] &= cpu_to_be32(~BT);
+
+ cp = be32_to_cpu(ch->regs[DBDMA_CMDPTR_LO]);
+ ch->regs[DBDMA_CMDPTR_LO] = cpu_to_be32(cp + sizeof(dbdma_cmd));
+ dbdma_cmdptr_load(ch);
+}
+
+static void branch(DBDMA_channel *ch)
+{
+ dbdma_cmd *current = &ch->current;
+
+ ch->regs[DBDMA_CMDPTR_LO] = current->cmd_dep;
+ ch->regs[DBDMA_STATUS] |= cpu_to_be32(BT);
+ dbdma_cmdptr_load(ch);
+}
+
+static void conditional_branch(DBDMA_channel *ch)
+{
+ dbdma_cmd *current = &ch->current;
+ uint16_t br;
+ uint16_t sel_mask, sel_value;
+ uint32_t status;
+ int cond;
+
+ DBDMA_DPRINTF("conditional_branch\n");
+
+ /* check if we must branch */
+
+ br = be16_to_cpu(current->command) & BR_MASK;
+
+ switch(br) {
+ case BR_NEVER: /* don't branch */
+ next(ch);
+ return;
+ case BR_ALWAYS: /* always branch */
+ branch(ch);
+ return;
+ }
+
+ status = be32_to_cpu(ch->regs[DBDMA_STATUS]) & DEVSTAT;
+
+ sel_mask = (be32_to_cpu(ch->regs[DBDMA_BRANCH_SEL]) >> 16) & 0x0f;
+ sel_value = be32_to_cpu(ch->regs[DBDMA_BRANCH_SEL]) & 0x0f;
+
+ cond = (status & sel_mask) == (sel_value & sel_mask);
+
+ switch(br) {
+ case BR_IFSET: /* branch if condition bit is 1 */
+ if (cond)
+ branch(ch);
+ else
+ next(ch);
+ return;
+ case BR_IFCLR: /* branch if condition bit is 0 */
+ if (!cond)
+ branch(ch);
+ else
+ next(ch);
+ return;
+ }
+}
+
+static int dbdma_read_memory(DBDMA_transfer *io)
+{
+ DBDMA_channel *ch = io->channel;
+ dbdma_cmd *current = &ch->current;
+
+ DBDMA_DPRINTF("DBDMA_read_memory\n");
+
+ cpu_physical_memory_read(le32_to_cpu(current->phy_addr) + io->buf_pos,
+ io->buf, io->buf_len);
+
+ return io->buf_len;
+}
+
+static int dbdma_write_memory(DBDMA_transfer *io)
+{
+ DBDMA_channel *ch = io->channel;
+ dbdma_cmd *current = &ch->current;
+
+ DBDMA_DPRINTF("DBDMA_write_memory\n");
+
+ cpu_physical_memory_write(le32_to_cpu(current->phy_addr) + io->buf_pos,
+ io->buf, io->buf_len);
+
+ return io->buf_len;
+}
+
+static int start_output(DBDMA_channel *ch, int key, uint32_t addr,
+ uint16_t req_count, int is_last)
+{
+ dbdma_cmd *current = &ch->current;
+ uint32_t n;
+
+ DBDMA_DPRINTF("start_output\n");
+
+ /* KEY_REGS, KEY_DEVICE and KEY_STREAM
+ * are not implemented in the mac-io chip
+ */
+
+ DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
+ if (!addr || key > KEY_STREAM3) {
+ kill_channel(ch);
+ return 0;
+ }
+
+ ch->io.buf = NULL;
+ ch->io.buf_pos = 0;
+ ch->io.buf_len = 0;
+ ch->io.len = req_count;
+ ch->io.is_last = is_last;
+ n = ch->transfer_handler(&ch->io, dbdma_read_memory);
+
+ if (conditional_wait(ch))
+ return 1;
+
+ current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS]));
+ current->res_count = cpu_to_le16(0);
+ dbdma_cmdptr_save(ch);
+
+ conditional_interrupt(ch);
+ conditional_branch(ch);
+
+ return 1;
+}
+
+static int start_input(DBDMA_channel *ch, int key, uint32_t addr,
+ uint16_t req_count, int is_last)
+{
+ dbdma_cmd *current = &ch->current;
+ uint32_t n;
+
+ DBDMA_DPRINTF("start_input\n");
+
+ /* KEY_REGS, KEY_DEVICE and KEY_STREAM
+ * are not implemented in the mac-io chip
+ */
+
+ if (!addr || key > KEY_STREAM3) {
+ kill_channel(ch);
+ return 0;
+ }
+
+ ch->io.buf = NULL;
+ ch->io.buf_pos = 0;
+ ch->io.buf_len = 0;
+ ch->io.len = req_count;
+ ch->io.is_last = is_last;
+ n = ch->transfer_handler(&ch->io, dbdma_write_memory);
+
+ if (conditional_wait(ch))
+ return 1;
+
+ current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS]));
+ current->res_count = cpu_to_le16(0);
+ dbdma_cmdptr_save(ch);
+
+ conditional_interrupt(ch);
+ conditional_branch(ch);
+
+ return 1;
+}
+
+static int load_word(DBDMA_channel *ch, int key, uint32_t addr,
+ uint16_t len)
+{
+ dbdma_cmd *current = &ch->current;
+ uint32_t val;
+
+ DBDMA_DPRINTF("load_word\n");
+
+ /* only implements KEY_SYSTEM */
+
+ if (key != KEY_SYSTEM) {
+ printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key);
+ kill_channel(ch);
+ return 0;
+ }
+
+ cpu_physical_memory_read(addr, (uint8_t*)&val, len);
+
+ if (len == 2)
+ val = (val << 16) | (current->cmd_dep & 0x0000ffff);
+ else if (len == 1)
+ val = (val << 24) | (current->cmd_dep & 0x00ffffff);
+
+ current->cmd_dep = val;
+
+ if (conditional_wait(ch))
+ return 1;
+
+ current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS]));
+ dbdma_cmdptr_save(ch);
+
+ conditional_interrupt(ch);
+ next(ch);
+
+ return 1;
+}
+
+static int store_word(DBDMA_channel *ch, int key, uint32_t addr,
+ uint16_t len)
+{
+ dbdma_cmd *current = &ch->current;
+ uint32_t val;
+
+ DBDMA_DPRINTF("store_word\n");
+
+ /* only implements KEY_SYSTEM */
+
+ if (key != KEY_SYSTEM) {
+ printf("DBDMA: STORE_WORD, unimplemented key %x\n", key);
+ kill_channel(ch);
+ return 0;
+ }
+
+ val = current->cmd_dep;
+ if (len == 2)
+ val >>= 16;
+ else if (len == 1)
+ val >>= 24;
+
+ cpu_physical_memory_write(addr, (uint8_t*)&val, len);
+
+ if (conditional_wait(ch))
+ return 1;
+
+ current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS]));
+ dbdma_cmdptr_save(ch);
+
+ conditional_interrupt(ch);
+ next(ch);
+
+ return 1;
+}
+
+static int nop(DBDMA_channel *ch)
+{
+ dbdma_cmd *current = &ch->current;
+
+ if (conditional_wait(ch))
+ return 1;
+
+ current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS]));
+ dbdma_cmdptr_save(ch);
+
+ conditional_interrupt(ch);
+ conditional_branch(ch);
+
+ return 1;
}
-static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr)
+static int stop(DBDMA_channel *ch)
{
- DBDMA_DPRINTF("readb 0x" TARGET_FMT_plx " => 0\n", addr);
+ ch->regs[DBDMA_STATUS] &= cpu_to_be32(~(ACTIVE|DEAD));
+
+ /* the stop command does not increment command pointer */
return 0;
}
-static uint32_t dbdma_readw (void *opaque, target_phys_addr_t addr)
+static int channel_run(DBDMA_channel *ch)
{
- DBDMA_DPRINTF("readw 0x" TARGET_FMT_plx " => 0\n", addr);
+ dbdma_cmd *current = &ch->current;
+ uint16_t cmd, key;
+ uint16_t req_count;
+ uint32_t phy_addr;
+
+ DBDMA_DPRINTF("channel_run\n");
+ dump_dbdma_cmd(current);
+
+ /* clear WAKE flag at command fetch */
+
+ ch->regs[DBDMA_STATUS] &= cpu_to_be32(~WAKE);
+
+ cmd = le16_to_cpu(current->command) & COMMAND_MASK;
+
+ switch (cmd) {
+ case DBDMA_NOP:
+ return nop(ch);
+
+ case DBDMA_STOP:
+ return stop(ch);
+ }
+
+ key = le16_to_cpu(current->command) & 0x0700;
+ req_count = le16_to_cpu(current->req_count);
+ phy_addr = le32_to_cpu(current->phy_addr);
+
+ if (key == KEY_STREAM4) {
+ printf("command %x, invalid key 4\n", cmd);
+ kill_channel(ch);
+ return 0;
+ }
+
+ switch (cmd) {
+ case OUTPUT_MORE:
+ return start_output(ch, key, phy_addr, req_count, 0);
+
+ case OUTPUT_LAST:
+ return start_output(ch, key, phy_addr, req_count, 1);
+
+ case INPUT_MORE:
+ return start_input(ch, key, phy_addr, req_count, 0);
+
+ case INPUT_LAST:
+ return start_input(ch, key, phy_addr, req_count, 1);
+ }
+
+ if (key < KEY_REGS) {
+ printf("command %x, invalid key %x\n", cmd, key);
+ key = KEY_SYSTEM;
+ }
+
+ /* for LOAD_WORD and STORE_WORD, req_count is on 3 bits
+ * and BRANCH is invalid
+ */
+
+ req_count = req_count & 0x0007;
+ if (req_count & 0x4) {
+ req_count = 4;
+ phy_addr &= ~3;
+ } else if (req_count & 0x2) {
+ req_count = 2;
+ phy_addr &= ~1;
+ } else
+ req_count = 1;
+
+ switch (cmd) {
+ case LOAD_WORD:
+ return load_word(ch, key, phy_addr, req_count);
+
+ case STORE_WORD:
+ return store_word(ch, key, phy_addr, req_count);
+ }
return 0;
}
+static QEMUBH *dbdma_bh;
+
+static void DBDMA_run (DBDMA_channel *ch)
+{
+ int channel;
+ int rearm = 0;
+
+ for (channel = 0; channel < DBDMA_CHANNELS; channel++, ch++) {
+ uint32_t status = be32_to_cpu(ch->regs[DBDMA_STATUS]);
+ if ((status & RUN) && (status & ACTIVE)) {
+ if (status & FLUSH)
+ while (channel_run(ch));
+ else if (channel_run(ch))
+ rearm = 1;
+ }
+ ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH);
+ }
+
+ if (rearm)
+ qemu_bh_schedule_idle(dbdma_bh);
+}
+
+static void DBDMA_run_bh(void *opaque)
+{
+ DBDMA_channel *ch = opaque;
+
+ DBDMA_DPRINTF("DBDMA_run_bh\n");
+
+ DBDMA_run(ch);
+}
+
+void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
+ DBDMA_transfer_handler transfer_handler,
+ void *opaque)
+{
+ DBDMA_channel *ch = ( DBDMA_channel *)dbdma + nchan;
+
+ DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan);
+
+ ch->irq = irq;
+ ch->channel = nchan;
+ ch->transfer_handler = transfer_handler;
+ ch->io.opaque = opaque;
+ ch->io.channel = ch;
+}
+
+void DBDMA_schedule(void)
+{
+ CPUState *env = cpu_single_env;
+ if (env)
+ cpu_interrupt(env, CPU_INTERRUPT_EXIT);
+}
+
+static void
+dbdma_control_write(DBDMA_channel *ch)
+{
+ uint16_t mask, value;
+ uint32_t status;
+
+ mask = (be32_to_cpu(ch->regs[DBDMA_CONTROL]) >> 16) & 0xffff;
+ value = be32_to_cpu(ch->regs[DBDMA_CONTROL]) & 0xffff;
+
+ value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT);
+
+ status = be32_to_cpu(ch->regs[DBDMA_STATUS]);
+
+ status = (value & mask) | (status & ~mask);
+
+ if (status & WAKE)
+ status |= ACTIVE;
+ if (status & RUN) {
+ status |= ACTIVE;
+ status &= ~DEAD;
+ }
+ if (status & PAUSE)
+ status &= ~ACTIVE;
+ if ((be32_to_cpu(ch->regs[DBDMA_STATUS]) & RUN) && !(status & RUN)) {
+ /* RUN is cleared */
+ status &= ~(ACTIVE|DEAD);
+ }
+
+ DBDMA_DPRINTF(" status 0x%08x\n", status);
+
+ ch->regs[DBDMA_STATUS] = cpu_to_be32(status);
+
+ if (status & ACTIVE) {
+ qemu_bh_schedule_idle(dbdma_bh);
+ if (status & FLUSH)
+ DBDMA_schedule();
+ }
+}
+
+static void dbdma_writel (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ int channel = addr >> DBDMA_CHANNEL_SHIFT;
+ DBDMA_channel *ch = (DBDMA_channel *)opaque + channel;
+ int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
+
+ DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
+ DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
+ (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
+
+ /* cmdptr cannot be modified if channel is RUN or ACTIVE */
+
+ if (reg == DBDMA_CMDPTR_LO &&
+ (ch->regs[DBDMA_STATUS] & cpu_to_be32(RUN | ACTIVE)))
+ return;
+
+ ch->regs[reg] = value;
+
+ switch(reg) {
+ case DBDMA_CONTROL:
+ dbdma_control_write(ch);
+ break;
+ case DBDMA_CMDPTR_LO:
+ /* 16-byte aligned */
+ ch->regs[DBDMA_CMDPTR_LO] &= cpu_to_be32(~0xf);
+ dbdma_cmdptr_load(ch);
+ break;
+ case DBDMA_STATUS:
+ case DBDMA_INTR_SEL:
+ case DBDMA_BRANCH_SEL:
+ case DBDMA_WAIT_SEL:
+ /* nothing to do */
+ break;
+ case DBDMA_XFER_MODE:
+ case DBDMA_CMDPTR_HI:
+ case DBDMA_DATA2PTR_HI:
+ case DBDMA_DATA2PTR_LO:
+ case DBDMA_ADDRESS_HI:
+ case DBDMA_BRANCH_ADDR_HI:
+ case DBDMA_RES1:
+ case DBDMA_RES2:
+ case DBDMA_RES3:
+ case DBDMA_RES4:
+ /* unused */
+ break;
+ }
+}
+
static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
{
- DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0\n", addr);
+ uint32_t value;
+ int channel = addr >> DBDMA_CHANNEL_SHIFT;
+ DBDMA_channel *ch = (DBDMA_channel *)opaque + channel;
+ int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
- return 0;
+ value = ch->regs[reg];
+
+ DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
+ DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
+ (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
+
+ switch(reg) {
+ case DBDMA_CONTROL:
+ value = 0;
+ break;
+ case DBDMA_STATUS:
+ case DBDMA_CMDPTR_LO:
+ case DBDMA_INTR_SEL:
+ case DBDMA_BRANCH_SEL:
+ case DBDMA_WAIT_SEL:
+ /* nothing to do */
+ break;
+ case DBDMA_XFER_MODE:
+ case DBDMA_CMDPTR_HI:
+ case DBDMA_DATA2PTR_HI:
+ case DBDMA_DATA2PTR_LO:
+ case DBDMA_ADDRESS_HI:
+ case DBDMA_BRANCH_ADDR_HI:
+ /* unused */
+ value = 0;
+ break;
+ case DBDMA_RES1:
+ case DBDMA_RES2:
+ case DBDMA_RES3:
+ case DBDMA_RES4:
+ /* reserved */
+ break;
+ }
+
+ return value;
}
static CPUWriteMemoryFunc *dbdma_write[] = {
- &dbdma_writeb,
- &dbdma_writew,
- &dbdma_writel,
+ NULL,
+ NULL,
+ dbdma_writel,
};
static CPUReadMemoryFunc *dbdma_read[] = {
- &dbdma_readb,
- &dbdma_readw,
- &dbdma_readl,
+ NULL,
+ NULL,
+ dbdma_readl,
};
static void dbdma_save(QEMUFile *f, void *opaque)
{
+ DBDMA_channel *s = opaque;
+ unsigned int i, j;
+
+ for (i = 0; i < DBDMA_CHANNELS; i++)
+ for (j = 0; j < DBDMA_REGS; j++)
+ qemu_put_be32s(f, &s[i].regs[j]);
}
static int dbdma_load(QEMUFile *f, void *opaque, int version_id)
{
- if (version_id != 1)
+ DBDMA_channel *s = opaque;
+ unsigned int i, j;
+
+ if (version_id != 2)
return -EINVAL;
+ for (i = 0; i < DBDMA_CHANNELS; i++)
+ for (j = 0; j < DBDMA_REGS; j++)
+ qemu_get_be32s(f, &s[i].regs[j]);
+
return 0;
}
static void dbdma_reset(void *opaque)
{
+ DBDMA_channel *s = opaque;
+ int i;
+
+ for (i = 0; i < DBDMA_CHANNELS; i++)
+ memset(s[i].regs, 0, DBDMA_SIZE);
}
-void dbdma_init (int *dbdma_mem_index)
+void* DBDMA_init (int *dbdma_mem_index)
{
- *dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL);
- register_savevm("dbdma", -1, 1, dbdma_save, dbdma_load, NULL);
- qemu_register_reset(dbdma_reset, NULL);
- dbdma_reset(NULL);
+ DBDMA_channel *s;
+
+ s = qemu_mallocz(sizeof(DBDMA_channel) * DBDMA_CHANNELS);
+ if (!s)
+ return NULL;
+
+ *dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, s);
+ register_savevm("dbdma", -1, 1, dbdma_save, dbdma_load, s);
+ qemu_register_reset(dbdma_reset, s);
+ dbdma_reset(s);
+
+ dbdma_bh = qemu_bh_new(DBDMA_run_bh, s);
+
+ return s;
}
diff --git a/hw/mac_dbdma.h b/hw/mac_dbdma.h
new file mode 100644
index 000000000..d1a02ed75
--- /dev/null
+++ b/hw/mac_dbdma.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2009 Laurent Vivier
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+typedef struct {
+ void *opaque;
+ void *channel;
+ int len;
+ int is_last;
+ void *buf;
+ int buf_pos;
+ int buf_len;
+} DBDMA_transfer;
+
+typedef int (*DBDMA_transfer_cb)(DBDMA_transfer *info);
+typedef int (*DBDMA_transfer_handler)(DBDMA_transfer *info,
+ DBDMA_transfer_cb cb);
+
+void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
+ DBDMA_transfer_handler transfer_handler,
+ void *opaque);
+void DBDMA_schedule(void);
+void* DBDMA_init (int *dbdma_mem_index);
diff --git a/hw/macio.c b/hw/macio.c
index 2a98dfb31..1333aa382 100644
--- a/hw/macio.c
+++ b/hw/macio.c
@@ -106,13 +106,10 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
macio_state->ide_mem_index[i] = -1;
/* Note: this code is strongly inspirated from the corresponding code
in PearPC */
- d->config[0x00] = 0x6b; // vendor_id
- d->config[0x01] = 0x10;
- d->config[0x02] = device_id;
- d->config[0x03] = device_id >> 8;
- d->config[0x0a] = 0x00; // class_sub = pci2pci
- d->config[0x0b] = 0xff; // class_base = bridge
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
+ pci_config_set_device_id(d->config, device_id);
+ pci_config_set_class(d->config, PCI_CLASS_OTHERS << 8);
d->config[0x0e] = 0x00; // header_type
d->config[0x3d] = 0x01; // interrupt on pin 1
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index cd57bf376..74d9e1f20 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -60,6 +60,7 @@ struct RTCState {
uint8_t cmos_data[128];
uint8_t cmos_index;
struct tm current_tm;
+ int base_year;
qemu_irq irq;
int it_shift;
/* periodic timer */
@@ -235,12 +236,13 @@ static void rtc_set_time(RTCState *s)
tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]) - 1;
tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
- tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;
+ tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year - 1900;
}
static void rtc_copy_date(RTCState *s)
{
const struct tm *tm = &s->current_tm;
+ int year;
s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
@@ -256,7 +258,10 @@ static void rtc_copy_date(RTCState *s)
s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday + 1);
s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
- s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
+ year = (tm->tm_year - s->base_year) % 100;
+ if (year < 0)
+ year += 100;
+ s->cmos_data[RTC_YEAR] = to_bcd(s, year);
}
/* month is between 0 and 11. */
@@ -522,7 +527,7 @@ static int rtc_load_td(QEMUFile *f, void *opaque, int version_id)
}
#endif
-RTCState *rtc_init(int base, qemu_irq irq)
+RTCState *rtc_init(int base, qemu_irq irq, int base_year)
{
RTCState *s;
@@ -536,6 +541,7 @@ RTCState *rtc_init(int base, qemu_irq irq)
s->cmos_data[RTC_REG_C] = 0x00;
s->cmos_data[RTC_REG_D] = 0x80;
+ s->base_year = base_year;
rtc_set_date_from_host(s);
s->periodic_timer = qemu_new_timer(vm_clock,
@@ -631,7 +637,8 @@ static CPUWriteMemoryFunc *rtc_mm_write[] = {
&cmos_mm_writel,
};
-RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq)
+RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
+ int base_year)
{
RTCState *s;
int io_memory;
@@ -646,6 +653,7 @@ RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq)
s->cmos_data[RTC_REG_C] = 0x00;
s->cmos_data[RTC_REG_D] = 0x80;
+ s->base_year = base_year;
rtc_set_date_from_host(s);
s->periodic_timer = qemu_new_timer(vm_clock,
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index eb4d15bcc..9bdb903ee 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -241,7 +241,7 @@ void mips_jazz_init (ram_addr_t ram_size, int vga_ram_size,
fdctrl_init(rc4030[1], 0, 1, 0x80003000, fds);
/* Real time clock */
- rtc_init(0x70, i8259[8]);
+ rtc_init(0x70, i8259[8], 1980);
s_rtc = cpu_register_io_memory(0, rtc_read, rtc_write, env);
cpu_register_physical_memory(0x80004000, 0x00001000, s_rtc);
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 9a41cdf94..b7afb2d9a 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -802,6 +802,12 @@ void mips_malta_init (ram_addr_t ram_size, int vga_ram_size,
qemu_register_reset(main_cpu_reset, env);
/* allocate RAM */
+ if (ram_size > (256 << 20)) {
+ fprintf(stderr,
+ "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n",
+ ((unsigned int)ram_size / (1 << 20)));
+ exit(1);
+ }
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
/* Map the bios at two physical locations, as on the real board. */
@@ -912,7 +918,7 @@ void mips_malta_init (ram_addr_t ram_size, int vga_ram_size,
/* Super I/O */
i8042_init(i8259[1], i8259[12], 0x60);
- rtc_state = rtc_init(0x70, i8259[8]);
+ rtc_state = rtc_init(0x70, i8259[8], 2000);
serial_init(0x3f8, i8259[4], 115200, serial_hds[0]);
serial_init(0x2f8, i8259[3], 115200, serial_hds[1]);
if (parallel_hds[0])
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 34b385329..ab0c110f0 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -178,6 +178,12 @@ void mips_r4k_init (ram_addr_t ram_size, int vga_ram_size,
qemu_register_reset(main_cpu_reset, env);
/* allocate RAM */
+ if (ram_size > (256 << 20)) {
+ fprintf(stderr,
+ "qemu: Too much memory for this machine: %d MB, maximum 256 MB\n",
+ ((unsigned int)ram_size / (1 << 20)));
+ exit(1);
+ }
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
if (!mips_qemu_iomemtype) {
@@ -229,7 +235,7 @@ void mips_r4k_init (ram_addr_t ram_size, int vga_ram_size,
/* The PIC is attached to the MIPS CPU INT0 pin */
i8259 = i8259_init(env->irq[2]);
- rtc_state = rtc_init(0x70, i8259[8]);
+ rtc_state = rtc_init(0x70, i8259[8], 2000);
/* Register 64 KB of ISA IO space at 0x14000000 */
isa_mmio_init(0x14000000, 0x00010000);
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 7c000176f..b2cdcb606 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -793,12 +793,9 @@ PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn)
return NULL;
pci_conf = d->dev.config;
- pci_conf[0x00] = 0xec; // Realtek 8029
- pci_conf[0x01] = 0x10;
- pci_conf[0x02] = 0x29;
- pci_conf[0x03] = 0x80;
- pci_conf[0x0a] = 0x00; // ethernet network controller
- pci_conf[0x0b] = 0x02;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REALTEK_RTL8029);
+ pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x3d] = 1; // interrupt pin 0
diff --git a/hw/openpic.c b/hw/openpic.c
index b8da4d702..e232c3203 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -1017,12 +1017,9 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
if (opp == NULL)
return NULL;
pci_conf = opp->pci_dev.config;
- pci_conf[0x00] = 0x14; // IBM MPIC2
- pci_conf[0x01] = 0x10;
- pci_conf[0x02] = 0xFF;
- pci_conf[0x03] = 0xFF;
- pci_conf[0x0a] = 0x80; // PIC
- pci_conf[0x0b] = 0x08;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2);
+ pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x3d] = 0x00; // no interrupt pin
diff --git a/hw/pc.c b/hw/pc.c
index 7d60e517e..8a52f4961 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1025,7 +1025,7 @@ vga_bios_error:
}
}
- rtc_state = rtc_init(0x70, i8259[8]);
+ rtc_state = rtc_init(0x70, i8259[8], 2000);
qemu_register_boot_set(pc_boot_set, rtc_state);
diff --git a/hw/pc.h b/hw/pc.h
index 54f865d50..2abf23fd9 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -87,8 +87,9 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
typedef struct RTCState RTCState;
-RTCState *rtc_init(int base, qemu_irq irq);
-RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq);
+RTCState *rtc_init(int base, qemu_irq irq, int base_year);
+RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
+ int base_year);
void rtc_set_memory(RTCState *s, int addr, int val);
void rtc_set_date(RTCState *s, const struct tm *tm);
void cmos_set_s3_resume(void);
diff --git a/hw/pci.c b/hw/pci.c
index 600490430..04aecc2d0 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -811,24 +811,23 @@ PCIDevice *pci_find_device(int bus_num, int slot)
return NULL;
}
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
+PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
pci_map_irq_fn map_irq, const char *name)
{
PCIBridge *s;
s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge),
devfn, NULL, pci_bridge_write_config);
- s->dev.config[0x00] = id >> 16;
- s->dev.config[0x01] = id >> 24;
- s->dev.config[0x02] = id; // device_id
- s->dev.config[0x03] = id >> 8;
+
+ pci_config_set_vendor_id(s->dev.config, vid);
+ pci_config_set_device_id(s->dev.config, did);
+
s->dev.config[0x04] = 0x06; // command = bus master, pci mem
s->dev.config[0x05] = 0x00;
s->dev.config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
s->dev.config[0x07] = 0x00; // status = fast devsel
s->dev.config[0x08] = 0x00; // revision
s->dev.config[0x09] = 0x00; // programming i/f
- s->dev.config[0x0A] = 0x04; // class_sub = PCI to PCI bridge
- s->dev.config[0x0B] = 0x06; // class_base = PCI_bridge
+ pci_config_set_class(s->dev.config, PCI_CLASS_BRIDGE_PCI);
s->dev.config[0x0D] = 0x10; // latency_timer
s->dev.config[0x0E] = 0x81; // header_type
s->dev.config[0x1E] = 0xa0; // secondary status
diff --git a/hw/pci.h b/hw/pci.h
index 7e4891129..157c45121 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -11,7 +11,104 @@
/* PCI bus */
extern target_phys_addr_t pci_mem_base;
-/* see pci-ids.txt */
+/* Device classes and subclasses */
+
+#define PCI_CLASS_STORAGE_SCSI 0x0100
+#define PCI_CLASS_STORAGE_IDE 0x0101
+#define PCI_CLASS_STORAGE_OTHER 0x0180
+
+#define PCI_CLASS_NETWORK_ETHERNET 0x0200
+
+#define PCI_CLASS_DISPLAY_VGA 0x0300
+#define PCI_CLASS_DISPLAY_OTHER 0x0380
+
+#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401
+
+#define PCI_CLASS_MEMORY_RAM 0x0500
+
+#define PCI_CLASS_SYSTEM_OTHER 0x0880
+
+#define PCI_CLASS_SERIAL_USB 0x0c03
+
+#define PCI_CLASS_BRIDGE_HOST 0x0600
+#define PCI_CLASS_BRIDGE_ISA 0x0601
+#define PCI_CLASS_BRIDGE_PCI 0x0604
+#define PCI_CLASS_BRIDGE_OTHER 0x0680
+
+#define PCI_CLASS_PROCESSOR_CO 0x0b40
+
+#define PCI_CLASS_OTHERS 0xff
+
+/* Vendors and devices. */
+
+#define PCI_VENDOR_ID_LSI_LOGIC 0x1000
+#define PCI_DEVICE_ID_LSI_53C895A 0x0012
+
+#define PCI_VENDOR_ID_DEC 0x1011
+#define PCI_DEVICE_ID_DEC_21154 0x0026
+
+#define PCI_VENDOR_ID_CIRRUS 0x1013
+
+#define PCI_VENDOR_ID_IBM 0x1014
+#define PCI_DEVICE_ID_IBM_OPENPIC2 0xffff
+
+#define PCI_VENDOR_ID_AMD 0x1022
+#define PCI_DEVICE_ID_AMD_LANCE 0x2000
+
+#define PCI_VENDOR_ID_HITACHI 0x1054
+
+#define PCI_VENDOR_ID_MOTOROLA 0x1057
+#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002
+#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801
+
+#define PCI_VENDOR_ID_APPLE 0x106b
+#define PCI_DEVICE_ID_APPLE_343S1201 0x0010
+#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI 0x001e
+#define PCI_DEVICE_ID_APPLE_UNI_N_PCI 0x001f
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020
+#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL 0x0022
+
+#define PCI_VENDOR_ID_SUN 0x108e
+#define PCI_DEVICE_ID_SUN_EBUS 0x1000
+#define PCI_DEVICE_ID_SUN_SIMBA 0x5000
+#define PCI_DEVICE_ID_SUN_SABRE 0xa000
+
+#define PCI_VENDOR_ID_CMD 0x1095
+#define PCI_DEVICE_ID_CMD_646 0x0646
+
+#define PCI_VENDOR_ID_REALTEK 0x10ec
+#define PCI_DEVICE_ID_REALTEK_RTL8029 0x8029
+#define PCI_DEVICE_ID_REALTEK_8139 0x8139
+
+#define PCI_VENDOR_ID_XILINX 0x10ee
+
+#define PCI_VENDOR_ID_MARVELL 0x11ab
+
+#define PCI_VENDOR_ID_QEMU 0x1234
+#define PCI_DEVICE_ID_QEMU_VGA 0x1111
+
+#define PCI_VENDOR_ID_ENSONIQ 0x1274
+#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000
+
+#define PCI_VENDOR_ID_VMWARE 0x15ad
+#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
+#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710
+#define PCI_DEVICE_ID_VMWARE_NET 0x0720
+#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730
+#define PCI_DEVICE_ID_VMWARE_IDE 0x1729
+
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_DEVICE_ID_INTEL_82441 0x1237
+#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415
+#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
+#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
+#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
+#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
+
+/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */
#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
#define PCI_SUBDEVICE_ID_QEMU 0x1100
@@ -19,6 +116,7 @@ extern target_phys_addr_t pci_mem_base;
#define PCI_DEVICE_ID_VIRTIO_NET 0x1000
#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001
#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002
+#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003
typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
uint32_t address, uint32_t data, int len);
@@ -136,9 +234,27 @@ PCIBus *pci_find_bus(int bus_num);
PCIDevice *pci_find_device(int bus_num, int slot);
void pci_info(void);
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
+PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
pci_map_irq_fn map_irq, const char *name);
+static inline void
+pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val)
+{
+ cpu_to_le16wu((uint16_t *)&pci_config[PCI_VENDOR_ID], val);
+}
+
+static inline void
+pci_config_set_device_id(uint8_t *pci_config, uint16_t val)
+{
+ cpu_to_le16wu((uint16_t *)&pci_config[PCI_DEVICE_ID], val);
+}
+
+static inline void
+pci_config_set_class(uint8_t *pci_config, uint16_t val)
+{
+ cpu_to_le16wu((uint16_t *)&pci_config[PCI_CLASS_DEVICE], val);
+}
+
/* lsi53c895a.c */
#define LSI_MAX_DEVS 7
void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id);
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 4598fc20a..8a7c010ee 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -2002,14 +2002,13 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
pci_conf = d->dev.config;
- *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022);
- *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000);
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE);
*(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007);
*(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280);
pci_conf[0x08] = 0x10;
pci_conf[0x09] = 0x00;
- pci_conf[0x0a] = 0x00; // ethernet network controller
- pci_conf[0x0b] = 0x02;
+ pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
pci_conf[0x0e] = 0x00; // header_type
*(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001);
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 2a4e265f4..74460e186 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -198,13 +198,10 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic)
d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0,
NULL, i440fx_write_config);
- d->config[0x00] = 0x86; // vendor_id
- d->config[0x01] = 0x80;
- d->config[0x02] = 0x37; // device_id
- d->config[0x03] = 0x12;
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_INTEL_82441);
d->config[0x08] = 0x02; // revision
- d->config[0x0a] = 0x00; // class_sub = host2pci
- d->config[0x0b] = 0x06; // class_base = PCI_bridge
+ pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x0e] = 0x00; // header_type
d->config[0x72] = 0x02; /* SMRAM */
@@ -353,12 +350,9 @@ int piix3_init(PCIBus *bus, int devfn)
piix3_dev = d;
pci_conf = d->config;
- pci_conf[0x00] = 0x86; // Intel
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
- pci_conf[0x03] = 0x70;
- pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
- pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371SB_0); // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+ pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
piix3_reset(d);
@@ -377,12 +371,9 @@ int piix4_init(PCIBus *bus, int devfn)
piix4_dev = d;
pci_conf = d->config;
- pci_conf[0x00] = 0x86; // Intel
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x10; // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
- pci_conf[0x03] = 0x71;
- pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
- pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_0); // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
+ pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
piix4_reset(d);
diff --git a/hw/pl031.c b/hw/pl031.c
index fb5f323cb..75bda7c27 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -36,7 +36,6 @@ typedef struct {
QEMUTimer *timer;
qemu_irq irq;
- uint64_t start_time;
uint32_t tick_offset;
uint32_t mr;
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index b21c2feff..574ec1913 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -366,6 +366,7 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
PPC4xxPCIState *controller;
int index;
static int ppc4xx_pci_id;
+ uint8_t *pci_conf;
controller = qemu_mallocz(sizeof(PPC4xxPCIState));
if (!controller)
@@ -378,12 +379,10 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
controller->pci_dev = pci_register_device(controller->pci_state.bus,
"host bridge", sizeof(PCIDevice),
0, NULL, NULL);
- controller->pci_dev->config[0x00] = 0x14; // vendor_id
- controller->pci_dev->config[0x01] = 0x10;
- controller->pci_dev->config[0x02] = 0x7f; // device_id
- controller->pci_dev->config[0x03] = 0x02;
- controller->pci_dev->config[0x0a] = 0x80; // class_sub = other bridge type
- controller->pci_dev->config[0x0b] = 0x06; // class_base = PCI_bridge
+ pci_conf = controller->pci_dev->config;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
+ pci_config_set_device_id(pci_conf, 0x027f); // device_id
+ pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
/* CFGADDR */
index = cpu_register_io_memory(0, pci4xx_cfgaddr_read,
diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c
index 64a613ce3..026b08bdc 100644
--- a/hw/ppc_chrp.c
+++ b/hw/ppc_chrp.c
@@ -25,6 +25,7 @@
#include "hw.h"
#include "ppc.h"
#include "ppc_mac.h"
+#include "mac_dbdma.h"
#include "nvram.h"
#include "pc.h"
#include "pci.h"
@@ -86,6 +87,7 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size,
int ppc_boot_device;
int index;
BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+ void *dbdma;
linux_boot = (kernel_filename != NULL);
@@ -280,9 +282,10 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size,
else
hd[i] = NULL;
}
+ dbdma = DBDMA_init(&dbdma_mem_index);
#if 1
- ide_mem_index[0] = pmac_ide_init(&hd[0], pic[0x13]);
- ide_mem_index[1] = pmac_ide_init(&hd[2], pic[0x14]);
+ ide_mem_index[0] = pmac_ide_init(&hd[0], pic[0x13], dbdma, 0x14, pic[0x01]);
+ ide_mem_index[1] = pmac_ide_init(&hd[2], pic[0x14], dbdma, 0x16, pic[0x02]);
#else
pci_cmd646_ide_init(pci_bus, &hd[0], 0);
#endif
@@ -292,10 +295,10 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size,
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
- dbdma_init(&dbdma_mem_index);
- macio_init(pci_bus, 0x0022, 0, pic_mem_index, dbdma_mem_index,
- cuda_mem_index, NULL, 2, ide_mem_index, escc_mem_index);
+ macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem_index,
+ dbdma_mem_index, cuda_mem_index, NULL, 2, ide_mem_index,
+ escc_mem_index);
if (usb_enabled) {
usb_ohci_init_pci(pci_bus, 3, -1);
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index cc70fb7dc..1fe5c5714 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -39,9 +39,6 @@
#define ESCC_CLOCK 3686400
-/* DBDMA */
-void dbdma_init (int *dbdma_mem_index);
-
/* Cuda */
void cuda_init (int *cuda_mem_index, qemu_irq irq);
@@ -51,7 +48,8 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, int pic_mem_index,
int nb_ide, int *ide_mem_index, int escc_mem_index);
/* NewWorld PowerMac IDE */
-int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq);
+int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq,
+ void *dbdma, int channel, qemu_irq dma_irq);
/* Heathrow PIC */
qemu_irq *heathrow_pic_init(int *pmem_index,
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index f60b174e3..1583c9116 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -25,6 +25,7 @@
#include "hw.h"
#include "ppc.h"
#include "ppc_mac.h"
+#include "mac_dbdma.h"
#include "nvram.h"
#include "pc.h"
#include "sysemu.h"
@@ -121,7 +122,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
m48t59_t *m48t59;
int linux_boot, i;
ram_addr_t ram_offset, vga_ram_offset, bios_offset, vga_bios_offset;
- uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
+ uint32_t kernel_base, initrd_base;
+ int32_t kernel_size, initrd_size;
PCIBus *pci_bus;
MacIONVRAMState *nvr;
int vga_bios_size, bios_size;
@@ -131,6 +133,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
int index;
void *fw_cfg;
+ void *dbdma;
linux_boot = (kernel_filename != NULL);
@@ -206,10 +209,16 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
}
if (linux_boot) {
+ uint64_t lowaddr = 0;
kernel_base = KERNEL_LOAD_ADDR;
- /* now we can load the kernel */
- kernel_size = load_elf(kernel_filename, kernel_base - 0xc0000000ULL,
- NULL, NULL, NULL);
+ /* Now we can load the kernel. The first step tries to load the kernel
+ supposing PhysAddr = 0x00000000. If that was wrong the kernel is
+ loaded again, the new PhysAddr being computed from lowaddr. */
+ kernel_size = load_elf(kernel_filename, kernel_base, NULL, &lowaddr, NULL);
+ if (kernel_size > 0 && lowaddr != KERNEL_LOAD_ADDR) {
+ kernel_size = load_elf(kernel_filename, (2 * kernel_base) - lowaddr,
+ NULL, 0, NULL);
+ }
if (kernel_size < 0)
kernel_size = load_aout(kernel_filename, kernel_base,
ram_size - kernel_base);
@@ -336,8 +345,11 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
hd[1] = NULL;
else
hd[1] = drives_table[index].bdrv;
+
+ dbdma = DBDMA_init(&dbdma_mem_index);
+
ide_mem_index[0] = -1;
- ide_mem_index[1] = pmac_ide_init(hd, pic[0x0D]);
+ ide_mem_index[1] = pmac_ide_init(hd, pic[0x0D], dbdma, 0x16, pic[0x02]);
/* cuda also initialize ADB */
cuda_init(&cuda_mem_index, pic[0x12]);
@@ -348,10 +360,9 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
nvr = macio_nvram_init(&nvram_mem_index, 0x2000);
pmac_format_nvram_partition(nvr, 0x2000);
- dbdma_init(&dbdma_mem_index);
-
- macio_init(pci_bus, 0x0010, 1, pic_mem_index, dbdma_mem_index,
- cuda_mem_index, nvr, 2, ide_mem_index, escc_mem_index);
+ macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem_index,
+ dbdma_mem_index, cuda_mem_index, nvr, 2, ide_mem_index,
+ escc_mem_index);
if (usb_enabled) {
usb_ohci_init_pci(pci_bus, 3, -1);
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 934d520d3..f9d0acc8b 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -659,7 +659,7 @@ static void ppc_prep_init (ram_addr_t ram_size, int vga_ram_size,
vga_ram_size, 0, 0);
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
// pit = pit_init(0x40, i8259[0]);
- rtc_init(0x70, i8259[8]);
+ rtc_init(0x70, i8259[8], 2000);
serial_init(0x3f8, i8259[4], 115200, serial_hds[0]);
nb_nics1 = nb_nics;
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index dd53f871a..205500564 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -155,13 +155,10 @@ PCIBus *pci_prep_init(qemu_irq *pic)
/* PCI host bridge */
d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven",
sizeof(PCIDevice), 0, NULL, NULL);
- d->config[0x00] = 0x57; // vendor_id : Motorola
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x01; // device_id : Raven
- d->config[0x03] = 0x48;
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MOTOROLA);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_MOTOROLA_RAVEN);
d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
d->config[0x0E] = 0x00; // header_type
diff --git a/hw/ps2.c b/hw/ps2.c
index 054b92f1e..fb7700523 100644
--- a/hw/ps2.c
+++ b/hw/ps2.c
@@ -497,6 +497,7 @@ static void ps2_reset(void *opaque)
q->rptr = 0;
q->wptr = 0;
q->count = 0;
+ s->update_irq(s->update_arg, 0);
}
static void ps2_common_save (QEMUFile *f, PS2State *s)
diff --git a/hw/r2d.c b/hw/r2d.c
index 09305f315..3901a7361 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -238,10 +238,8 @@ static void r2d_init(ram_addr_t ram_size, int vga_ram_size,
{
int kernel_size;
/* initialization which should be done by firmware */
- uint32_t bcr1 = 1 << 3; /* cs3 SDRAM */
- uint16_t bcr2 = 3 << (3 * 2); /* cs3 32-bit */
- cpu_physical_memory_write(SH7750_BCR1_A7, (uint8_t *)&bcr1, 4);
- cpu_physical_memory_write(SH7750_BCR2_A7, (uint8_t *)&bcr2, 2);
+ stl_phys(SH7750_BCR1, 1<<3); /* cs3 SDRAM */
+ stw_phys(SH7750_BCR2, 3<<(3*2)); /* cs3 32bit */
kernel_size = load_image(kernel_filename, phys_ram_base);
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 2527d9bfb..a29a87cad 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -1187,8 +1187,8 @@ static void rtl8139_reset(RTL8139State *s)
s->eeprom.contents[0] = 0x8129;
#if 1
// PCI vendor and device ID should be mirrored here
- s->eeprom.contents[1] = 0x10ec;
- s->eeprom.contents[2] = 0x8139;
+ s->eeprom.contents[1] = PCI_VENDOR_ID_REALTEK;
+ s->eeprom.contents[2] = PCI_DEVICE_ID_REALTEK_8139;
#endif
s->eeprom.contents[7] = s->macaddr[0] | s->macaddr[1] << 8;
@@ -3428,14 +3428,11 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn)
return NULL;
pci_conf = d->dev.config;
- pci_conf[0x00] = 0xec; /* Realtek 8139 */
- pci_conf[0x01] = 0x10;
- pci_conf[0x02] = 0x39;
- pci_conf[0x03] = 0x81;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REALTEK_8139);
pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */
pci_conf[0x08] = RTL8139_PCI_REVID; /* PCI revision ID; >=0x20 is for 8139C+ */
- pci_conf[0x0a] = 0x00; /* ethernet network controller */
- pci_conf[0x0b] = 0x02;
+ pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
pci_conf[0x0e] = 0x00; /* header_type */
pci_conf[0x3d] = 1; /* interrupt pin 0 */
pci_conf[0x34] = 0xdc;
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 744573e0d..c4d7d520b 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -42,19 +42,22 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
#define SCSI_DMA_BUF_SIZE 131072
#define SCSI_MAX_INQUIRY_LEN 256
+#define SCSI_REQ_STATUS_RETRY 0x01
+
typedef struct SCSIRequest {
SCSIDeviceState *dev;
uint32_t tag;
- /* ??? We should probably keep track of whether the data trasfer is
+ /* ??? We should probably keep track of whether the data transfer is
a read or a write. Currently we rely on the host getting it right. */
/* Both sector and sector_count are in terms of qemu 512 byte blocks. */
- int sector;
- int sector_count;
+ uint64_t sector;
+ uint32_t sector_count;
/* The amounnt of data in the buffer. */
int buf_len;
uint8_t *dma_buf;
BlockDriverAIOCB *aiocb;
struct SCSIRequest *next;
+ uint32_t status;
} SCSIRequest;
struct SCSIDeviceState
@@ -64,6 +67,7 @@ struct SCSIDeviceState
/* The qemu block layer uses a fixed 512 byte sector size.
This is the number of 512 byte blocks in a single scsi sector. */
int cluster_size;
+ uint64_t max_lba;
int sense;
int tcq;
/* Completion functions may be called from either scsi_{read,write}_data
@@ -92,6 +96,7 @@ static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag)
r->sector_count = 0;
r->buf_len = 0;
r->aiocb = NULL;
+ r->status = 0;
r->next = s->requests;
s->requests = r;
@@ -212,18 +217,42 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
r->sector_count -= n;
}
+static int scsi_handle_write_error(SCSIRequest *r, int error)
+{
+ BlockInterfaceErrorAction action = drive_get_onerror(r->dev->bdrv);
+
+ if (action == BLOCK_ERR_IGNORE)
+ return 0;
+
+ if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
+ || action == BLOCK_ERR_STOP_ANY) {
+ r->status |= SCSI_REQ_STATUS_RETRY;
+ vm_stop(0);
+ } else {
+ scsi_command_complete(r, STATUS_CHECK_CONDITION,
+ SENSE_HARDWARE_ERROR);
+ }
+
+ return 1;
+}
+
static void scsi_write_complete(void * opaque, int ret)
{
SCSIRequest *r = (SCSIRequest *)opaque;
SCSIDeviceState *s = r->dev;
uint32_t len;
+ uint32_t n;
+
+ r->aiocb = NULL;
if (ret) {
- fprintf(stderr, "scsi-disc: IO write error\n");
- exit(1);
+ if (scsi_handle_write_error(r, -ret))
+ return;
}
- r->aiocb = NULL;
+ n = r->buf_len / 512;
+ r->sector += n;
+ r->sector_count -= n;
if (r->sector_count == 0) {
scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
} else {
@@ -237,13 +266,30 @@ static void scsi_write_complete(void * opaque, int ret)
}
}
+static void scsi_write_request(SCSIRequest *r)
+{
+ SCSIDeviceState *s = r->dev;
+ uint32_t n;
+
+ n = r->buf_len / 512;
+ if (n) {
+ r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n,
+ scsi_write_complete, r);
+ if (r->aiocb == NULL)
+ scsi_command_complete(r, STATUS_CHECK_CONDITION,
+ SENSE_HARDWARE_ERROR);
+ } else {
+ /* Invoke completion routine to fetch data from host. */
+ scsi_write_complete(r, 0);
+ }
+}
+
/* Write data to a scsi device. Returns nonzero on failure.
The transfer may complete asynchronously. */
static int scsi_write_data(SCSIDevice *d, uint32_t tag)
{
SCSIDeviceState *s = d->state;
SCSIRequest *r;
- uint32_t n;
DPRINTF("Write data tag=0x%x\n", tag);
r = scsi_find_request(s, tag);
@@ -252,25 +298,31 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
return 1;
}
+
if (r->aiocb)
BADF("Data transfer already in progress\n");
- n = r->buf_len / 512;
- if (n) {
- r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n,
- scsi_write_complete, r);
- if (r->aiocb == NULL)
- scsi_command_complete(r, STATUS_CHECK_CONDITION,
- SENSE_HARDWARE_ERROR);
- r->sector += n;
- r->sector_count -= n;
- } else {
- /* Invoke completion routine to fetch data from host. */
- scsi_write_complete(r, 0);
- }
+
+ scsi_write_request(r);
return 0;
}
+static void scsi_dma_restart_cb(void *opaque, int running, int reason)
+{
+ SCSIDeviceState *s = opaque;
+ SCSIRequest *r = s->requests;
+ if (!running)
+ return;
+
+ while (r) {
+ if (r->status & SCSI_REQ_STATUS_RETRY) {
+ r->status &= ~SCSI_REQ_STATUS_RETRY;
+ scsi_write_request(r);
+ }
+ r = r->next;
+ }
+}
+
/* Return a pointer to the data buffer. */
static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
{
@@ -295,7 +347,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
{
SCSIDeviceState *s = d->state;
uint64_t nb_sectors;
- uint32_t lba;
+ uint64_t lba;
uint32_t len;
int cmdlen;
int is_write;
@@ -317,23 +369,29 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
switch (command >> 5) {
case 0:
- lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16);
+ lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
+ (((uint64_t) buf[1] & 0x1f) << 16);
len = buf[4];
cmdlen = 6;
break;
case 1:
case 2:
- lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
+ lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
+ ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
len = buf[8] | (buf[7] << 8);
cmdlen = 10;
break;
case 4:
- lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
+ lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
+ ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
+ ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
+ ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
cmdlen = 16;
break;
case 5:
- lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
+ lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
+ ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
cmdlen = 12;
break;
@@ -677,9 +735,15 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
/* The normal LEN field for this command is zero. */
memset(outbuf, 0, 8);
bdrv_get_geometry(s->bdrv, &nb_sectors);
+ nb_sectors /= s->cluster_size;
/* Returned value is the address of the last sector. */
if (nb_sectors) {
nb_sectors--;
+ /* Remember the new size for read/write sanity checking. */
+ s->max_lba = nb_sectors;
+ /* Clip to 2TB, instead of returning capacity modulo 2TB. */
+ if (nb_sectors > UINT32_MAX)
+ nb_sectors = UINT32_MAX;
outbuf[0] = (nb_sectors >> 24) & 0xff;
outbuf[1] = (nb_sectors >> 16) & 0xff;
outbuf[2] = (nb_sectors >> 8) & 0xff;
@@ -696,13 +760,19 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
break;
case 0x08:
case 0x28:
- DPRINTF("Read (sector %d, count %d)\n", lba, len);
+ case 0x88:
+ DPRINTF("Read (sector %lld, count %d)\n", lba, len);
+ if (lba > s->max_lba)
+ goto illegal_lba;
r->sector = lba * s->cluster_size;
r->sector_count = len * s->cluster_size;
break;
case 0x0a:
case 0x2a:
- DPRINTF("Write (sector %d, count %d)\n", lba, len);
+ case 0x8a:
+ DPRINTF("Write (sector %lld, count %d)\n", lba, len);
+ if (lba > s->max_lba)
+ goto illegal_lba;
r->sector = lba * s->cluster_size;
r->sector_count = len * s->cluster_size;
is_write = 1;
@@ -766,6 +836,40 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
if (buf[1] & 3)
goto fail;
break;
+ case 0x9e:
+ /* Service Action In subcommands. */
+ if ((buf[1] & 31) == 0x10) {
+ DPRINTF("SAI READ CAPACITY(16)\n");
+ memset(outbuf, 0, len);
+ bdrv_get_geometry(s->bdrv, &nb_sectors);
+ nb_sectors /= s->cluster_size;
+ /* Returned value is the address of the last sector. */
+ if (nb_sectors) {
+ nb_sectors--;
+ /* Remember the new size for read/write sanity checking. */
+ s->max_lba = nb_sectors;
+ outbuf[0] = (nb_sectors >> 56) & 0xff;
+ outbuf[1] = (nb_sectors >> 48) & 0xff;
+ outbuf[2] = (nb_sectors >> 40) & 0xff;
+ outbuf[3] = (nb_sectors >> 32) & 0xff;
+ outbuf[4] = (nb_sectors >> 24) & 0xff;
+ outbuf[5] = (nb_sectors >> 16) & 0xff;
+ outbuf[6] = (nb_sectors >> 8) & 0xff;
+ outbuf[7] = nb_sectors & 0xff;
+ outbuf[8] = 0;
+ outbuf[9] = 0;
+ outbuf[10] = s->cluster_size * 2;
+ outbuf[11] = 0;
+ /* Protection, exponent and lowest lba field left blank. */
+ r->buf_len = len;
+ } else {
+ scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY);
+ return 0;
+ }
+ break;
+ }
+ DPRINTF("Unsupported Service Action In\n");
+ goto fail;
case 0xa0:
DPRINTF("Report LUNs (len %d)\n", len);
if (len < 16)
@@ -782,6 +886,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
fail:
scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST);
return 0;
+ illegal_lba:
+ scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
+ return 0;
}
if (r->sector_count == 0 && r->buf_len == 0) {
scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
@@ -807,6 +914,7 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
{
SCSIDevice *d;
SCSIDeviceState *s;
+ uint64_t nb_sectors;
s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState));
s->bdrv = bdrv;
@@ -818,10 +926,16 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
} else {
s->cluster_size = 1;
}
+ bdrv_get_geometry(s->bdrv, &nb_sectors);
+ nb_sectors /= s->cluster_size;
+ if (nb_sectors)
+ nb_sectors--;
+ s->max_lba = nb_sectors;
strncpy(s->drive_serial_str, drive_get_serial(s->bdrv),
sizeof(s->drive_serial_str));
if (strlen(s->drive_serial_str) == 0)
pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0");
+ qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
d->state = s;
d->destroy = scsi_destroy;
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index 5524c5989..8e3fce00f 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -29,9 +29,6 @@
typedef struct {
PCIBus *bus;
PCIDevice *dev;
- uint32_t regbase;
- uint32_t iopbase;
- uint32_t membase;
uint32_t par;
uint32_t mbr;
uint32_t iobr;
@@ -181,20 +178,18 @@ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice),
-1, NULL, NULL);
- p->regbase = 0x1e200000;
- p->iopbase = 0x1e240000;
- p->membase = 0xfd000000;
reg = cpu_register_io_memory(0, sh_pci_reg.r, sh_pci_reg.w, p);
- mem = cpu_register_io_memory(0, sh_pci_mem.r, sh_pci_mem.w, p);
iop = cpu_register_io_memory(0, sh_pci_iop.r, sh_pci_iop.w, p);
- cpu_register_physical_memory(p->regbase, 0x224, reg);
- cpu_register_physical_memory(p->iopbase, 0x40000, iop);
- cpu_register_physical_memory(p->membase, 0x1000000, mem);
-
- p->dev->config[0x00] = 0x54; // HITACHI
- p->dev->config[0x01] = 0x10; //
- p->dev->config[0x02] = 0x0e; // SH7751R
- p->dev->config[0x03] = 0x35; //
+ mem = cpu_register_io_memory(0, sh_pci_mem.r, sh_pci_mem.w, p);
+ cpu_register_physical_memory(0x1e200000, 0x224, reg);
+ cpu_register_physical_memory(0x1e240000, 0x40000, iop);
+ cpu_register_physical_memory(0x1d000000, 0x1000000, mem);
+ cpu_register_physical_memory(0xfe200000, 0x224, reg);
+ cpu_register_physical_memory(0xfe240000, 0x40000, iop);
+ cpu_register_physical_memory(0xfd000000, 0x1000000, mem);
+
+ pci_config_set_vendor_id(p->dev->config, PCI_VENDOR_ID_HITACHI);
+ pci_config_set_device_id(p->dev->config, 0x350e); // SH7751R
p->dev->config[0x04] = 0x80;
p->dev->config[0x05] = 0x00;
p->dev->config[0x06] = 0x90;
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 59aee1b02..234df7a66 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -365,18 +365,15 @@ pci_ebus_init(PCIBus *bus, int devfn)
PCIDevice *s;
s = pci_register_device(bus, "EBUS", sizeof(*s), devfn, NULL, NULL);
- s->config[0x00] = 0x8e; // vendor_id : Sun
- s->config[0x01] = 0x10;
- s->config[0x02] = 0x00; // device_id
- s->config[0x03] = 0x10;
+ pci_config_set_vendor_id(s->config, PCI_VENDOR_ID_SUN);
+ pci_config_set_device_id(s->config, PCI_DEVICE_ID_SUN_EBUS);
s->config[0x04] = 0x06; // command = bus master, pci mem
s->config[0x05] = 0x00;
s->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
s->config[0x07] = 0x03; // status = medium devsel
s->config[0x08] = 0x01; // revision
s->config[0x09] = 0x00; // programming i/f
- s->config[0x0A] = 0x80; // class_sub = misc bridge
- s->config[0x0B] = 0x06; // class_base = PCI_bridge
+ pci_config_set_class(s->config, PCI_CLASS_BRIDGE_OTHER);
s->config[0x0D] = 0x0a; // latency_timer
s->config[0x0E] = 0x00; // header_type
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index a835e1723..3af2d5cee 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -174,13 +174,10 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data);
d = pci_register_device(s->bus, "Uni-north main", sizeof(PCIDevice),
11 << 3, NULL, NULL);
- d->config[0x00] = 0x6b; // vendor_id : Apple
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x1F; // device_id
- d->config[0x03] = 0x00;
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_PCI);
d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
d->config[0x0E] = 0x00; // header_type
@@ -190,13 +187,10 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
/* pci-to-pci bridge */
d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3,
NULL, NULL);
- d->config[0x00] = 0x11; // vendor_id : TI
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x26; // device_id
- d->config[0x03] = 0x00;
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_DEC);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_DEC_21154);
d->config[0x08] = 0x05; // revision
- d->config[0x0A] = 0x04; // class_sub = pci2pci
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x20; // latency_timer
d->config[0x0E] = 0x01; // header_type
@@ -229,13 +223,10 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3,
NULL, NULL);
- d->config[0x00] = 0x6b; // vendor_id : Apple
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x20; // device_id
- d->config[0x03] = 0x00;
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_AGP);
d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
d->config[0x0E] = 0x00; // header_type
@@ -254,13 +245,10 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
d = pci_register_device("Uni-north internal", sizeof(PCIDevice),
3, 11 << 3, NULL, NULL);
- d->config[0x00] = 0x6b; // vendor_id : Apple
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x1E; // device_id
- d->config[0x03] = 0x00;
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_I_PCI);
d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
+ pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
d->config[0x0E] = 0x00; // header_type
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index f35685dfd..6ddc2aae7 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1671,8 +1671,6 @@ static void ohci_mapfunc(PCIDevice *pci_dev, int i,
void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn)
{
OHCIPCIState *ohci;
- int vid = 0x106b;
- int did = 0x003f;
ohci = (OHCIPCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci),
devfn, NULL, NULL);
@@ -1681,13 +1679,10 @@ void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn)
return;
}
- ohci->pci_dev.config[0x00] = vid & 0xff;
- ohci->pci_dev.config[0x01] = (vid >> 8) & 0xff;
- ohci->pci_dev.config[0x02] = did & 0xff;
- ohci->pci_dev.config[0x03] = (did >> 8) & 0xff;
+ pci_config_set_vendor_id(ohci->pci_dev.config, PCI_VENDOR_ID_APPLE);
+ pci_config_set_device_id(ohci->pci_dev.config, 0x003f); // device_id
ohci->pci_dev.config[0x09] = 0x10; /* OHCI */
- ohci->pci_dev.config[0x0a] = 0x3;
- ohci->pci_dev.config[0x0b] = 0xc;
+ pci_config_set_class(ohci->pci_dev.config, PCI_CLASS_SERIAL_USB);
ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
usb_ohci_init(&ohci->state, num_ports, devfn, ohci->pci_dev.irq[0],
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index b90cf78c1..89b357ea7 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1080,14 +1080,11 @@ void usb_uhci_piix3_init(PCIBus *bus, int devfn)
"USB-UHCI", sizeof(UHCIState),
devfn, NULL, NULL);
pci_conf = s->dev.config;
- pci_conf[0x00] = 0x86;
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x20;
- pci_conf[0x03] = 0x70;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371SB_2);
pci_conf[0x08] = 0x01; // revision number
pci_conf[0x09] = 0x00;
- pci_conf[0x0a] = 0x03;
- pci_conf[0x0b] = 0x0c;
+ pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x3d] = 4; // interrupt pin 3
pci_conf[0x60] = 0x10; // release number
@@ -1117,14 +1114,11 @@ void usb_uhci_piix4_init(PCIBus *bus, int devfn)
"USB-UHCI", sizeof(UHCIState),
devfn, NULL, NULL);
pci_conf = s->dev.config;
- pci_conf[0x00] = 0x86;
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x12;
- pci_conf[0x03] = 0x71;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_2);
pci_conf[0x08] = 0x01; // revision number
pci_conf[0x09] = 0x00;
- pci_conf[0x0a] = 0x03;
- pci_conf[0x0b] = 0x0c;
+ pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x3d] = 4; // interrupt pin 3
pci_conf[0x60] = 0x10; // release number
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index 1f4c1f30f..dea04ea6d 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -124,19 +124,16 @@ PCIBus *pci_vpb_init(qemu_irq *pic, int irq, int realview)
isa_mmio_init(base + 0x03000000, 0x00100000);
}
- d->config[0x00] = 0xee; // vendor_id
- d->config[0x01] = 0x10;
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_XILINX);
/* Both boards have the same device ID. Oh well. */
- d->config[0x02] = 0x00; // device_id
- d->config[0x03] = 0x03;
+ pci_config_set_device_id(d->config, 0x0300); // device_id
d->config[0x04] = 0x00;
d->config[0x05] = 0x00;
d->config[0x06] = 0x20;
d->config[0x07] = 0x02;
d->config[0x08] = 0x00; // revision
d->config[0x09] = 0x00; // programming i/f
- d->config[0x0A] = 0x40; // class_sub = pci host
- d->config[0x0B] = 0x0b; // class_base = PCI_bridge
+ pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_CO);
d->config[0x0D] = 0x10; // latency_timer
return s;
diff --git a/hw/vga.c b/hw/vga.c
index d6926fd51..79c682fb2 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1246,7 +1246,15 @@ static void vga_get_text_resolution(VGAState *s, int *pwidth, int *pheight,
typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
-static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS];
+static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
+ rgb_to_pixel8_dup,
+ rgb_to_pixel15_dup,
+ rgb_to_pixel16_dup,
+ rgb_to_pixel32_dup,
+ rgb_to_pixel32bgr_dup,
+ rgb_to_pixel15bgr_dup,
+ rgb_to_pixel16bgr_dup,
+};
/*
* Text mode update
@@ -1513,16 +1521,6 @@ static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
vga_draw_line32_16bgr,
};
-static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
- rgb_to_pixel8_dup,
- rgb_to_pixel15_dup,
- rgb_to_pixel16_dup,
- rgb_to_pixel32_dup,
- rgb_to_pixel32bgr_dup,
- rgb_to_pixel15bgr_dup,
- rgb_to_pixel16bgr_dup,
-};
-
static int vga_get_bpp(VGAState *s)
{
int ret;
@@ -1625,12 +1623,19 @@ static void vga_draw_graphic(VGAState *s, int full_update)
disp_width != s->last_width ||
height != s->last_height ||
s->last_depth != depth) {
+#if defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
if (depth == 16 || depth == 32) {
+#else
+ if (depth == 32) {
+#endif
if (is_graphic_console()) {
qemu_free_displaysurface(s->ds->surface);
s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
s->line_offset,
s->vram_ptr + (s->start_addr * 4));
+#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
+ s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
+#endif
dpy_resize(s->ds);
} else {
qemu_console_resize(s->ds, disp_width, height);
@@ -2678,12 +2683,10 @@ int pci_vga_init(PCIBus *bus, uint8_t *vga_ram_base,
s->pci_dev = &d->dev;
pci_conf = d->dev.config;
- pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
- pci_conf[0x01] = 0x12;
- pci_conf[0x02] = 0x11;
- pci_conf[0x03] = 0x11;
- pci_conf[0x0a] = 0x00; // VGA controller
- pci_conf[0x0b] = 0x03;
+ // dummy VGA (same as Bochs ID)
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_QEMU);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_QEMU_VGA);
+ pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_VGA);
pci_conf[0x0e] = 0x00; // header_type
/* XXX: vga_ram_size must be a power of two */
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 24d387f31..668b20c28 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -175,8 +175,9 @@ void *virtio_balloon_init(PCIBus *bus)
s = (VirtIOBalloon *)virtio_init_pci(bus, "virtio-balloon",
PCI_VENDOR_ID_REDHAT_QUMRANET,
PCI_DEVICE_ID_VIRTIO_BALLOON,
- 0, VIRTIO_ID_BALLOON,
- 0x05, 0x00, 0x00,
+ PCI_VENDOR_ID_REDHAT_QUMRANET,
+ VIRTIO_ID_BALLOON,
+ PCI_CLASS_MEMORY_RAM, 0x00,
8, sizeof(VirtIOBalloon));
if (s == NULL)
return NULL;
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index bcc58548e..1c16c9e6f 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -11,6 +11,8 @@
*
*/
+#include <qemu-common.h>
+#include <sysemu.h>
#include "virtio-blk.h"
#include "block_int.h"
@@ -19,6 +21,7 @@ typedef struct VirtIOBlock
VirtIODevice vdev;
BlockDriverState *bs;
VirtQueue *vq;
+ void *rq;
} VirtIOBlock;
static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
@@ -34,12 +37,44 @@ typedef struct VirtIOBlockReq
struct virtio_blk_outhdr *out;
size_t size;
uint8_t *buffer;
+ struct VirtIOBlockReq *next;
} VirtIOBlockReq;
+static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
+{
+ VirtIOBlock *s = req->dev;
+
+ req->in->status = status;
+ virtqueue_push(s->vq, &req->elem, req->size + sizeof(*req->in));
+ virtio_notify(&s->vdev, s->vq);
+
+ qemu_free(req->buffer);
+ qemu_free(req);
+}
+
+static int virtio_blk_handle_write_error(VirtIOBlockReq *req, int error)
+{
+ BlockInterfaceErrorAction action = drive_get_onerror(req->dev->bs);
+ VirtIOBlock *s = req->dev;
+
+ if (action == BLOCK_ERR_IGNORE)
+ return 0;
+
+ if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
+ || action == BLOCK_ERR_STOP_ANY) {
+ req->next = s->rq;
+ s->rq = req;
+ vm_stop(0);
+ } else {
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+ }
+
+ return 1;
+}
+
static void virtio_blk_rw_complete(void *opaque, int ret)
{
VirtIOBlockReq *req = opaque;
- VirtIOBlock *s = req->dev;
/* Copy read data to the guest */
if (!ret && !(req->out->type & VIRTIO_BLK_T_OUT)) {
@@ -58,33 +93,71 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
len);
offset += len;
}
+ } else if (ret && (req->out->type & VIRTIO_BLK_T_OUT)) {
+ if (virtio_blk_handle_write_error(req, -ret))
+ return;
}
- req->in->status = ret ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
- virtqueue_push(s->vq, &req->elem, req->size + sizeof(*req->in));
- virtio_notify(&s->vdev, s->vq);
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+}
- qemu_free(req->buffer);
- qemu_free(req);
+static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
+{
+ VirtIOBlockReq *req = qemu_mallocz(sizeof(*req));
+ if (req != NULL)
+ req->dev = s;
+ return req;
}
static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
{
- VirtIOBlockReq *req;
+ VirtIOBlockReq *req = virtio_blk_alloc_request(s);
- req = qemu_mallocz(sizeof(*req));
- if (req == NULL)
- return NULL;
-
- req->dev = s;
- if (!virtqueue_pop(s->vq, &req->elem)) {
- qemu_free(req);
- return NULL;
+ if (req != NULL) {
+ if (!virtqueue_pop(s->vq, &req->elem)) {
+ qemu_free(req);
+ return NULL;
+ }
}
return req;
}
+static int virtio_blk_handle_write(VirtIOBlockReq *req)
+{
+ if (!req->buffer) {
+ size_t offset = 0;
+ int i;
+
+ for (i = 1; i < req->elem.out_num; i++)
+ req->size += req->elem.out_sg[i].iov_len;
+
+ req->buffer = qemu_memalign(512, req->size);
+ if (req->buffer == NULL) {
+ qemu_free(req);
+ return -1;
+ }
+
+ /* We copy the data from the SG list to avoid splitting up the request.
+ This helps performance a lot until we can pass full sg lists as AIO
+ operations */
+ for (i = 1; i < req->elem.out_num; i++) {
+ size_t len;
+
+ len = MIN(req->elem.out_sg[i].iov_len,
+ req->size - offset);
+ memcpy(req->buffer + offset,
+ req->elem.out_sg[i].iov_base,
+ len);
+ offset += len;
+ }
+ }
+
+ bdrv_aio_write(req->dev->bs, req->out->sector, req->buffer, req->size / 512,
+ virtio_blk_rw_complete, req);
+ return 0;
+}
+
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOBlock *s = to_virtio_blk(vdev);
@@ -115,36 +188,8 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
virtio_notify(vdev, vq);
qemu_free(req);
} else if (req->out->type & VIRTIO_BLK_T_OUT) {
- size_t offset;
-
- for (i = 1; i < req->elem.out_num; i++)
- req->size += req->elem.out_sg[i].iov_len;
-
- req->buffer = qemu_memalign(512, req->size);
- if (req->buffer == NULL) {
- qemu_free(req);
+ if (virtio_blk_handle_write(req) < 0)
break;
- }
-
- /* We copy the data from the SG list to avoid splitting up the request. This helps
- performance a lot until we can pass full sg lists as AIO operations */
- offset = 0;
- for (i = 1; i < req->elem.out_num; i++) {
- size_t len;
-
- len = MIN(req->elem.out_sg[i].iov_len,
- req->size - offset);
- memcpy(req->buffer + offset,
- req->elem.out_sg[i].iov_base,
- len);
- offset += len;
- }
-
- bdrv_aio_write(s->bs, req->out->sector,
- req->buffer,
- req->size / 512,
- virtio_blk_rw_complete,
- req);
} else {
for (i = 0; i < req->elem.in_num - 1; i++)
req->size += req->elem.in_sg[i].iov_len;
@@ -169,6 +214,22 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
*/
}
+static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason)
+{
+ VirtIOBlock *s = opaque;
+ VirtIOBlockReq *req = s->rq;
+
+ if (!running)
+ return;
+
+ s->rq = NULL;
+
+ while (req) {
+ virtio_blk_handle_write(req);
+ req = req->next;
+ }
+}
+
static void virtio_blk_reset(VirtIODevice *vdev)
{
/*
@@ -203,17 +264,32 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
static void virtio_blk_save(QEMUFile *f, void *opaque)
{
VirtIOBlock *s = opaque;
+ VirtIOBlockReq *req = s->rq;
+
virtio_save(&s->vdev, f);
+
+ while (req) {
+ qemu_put_sbyte(f, 1);
+ qemu_put_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
+ req = req->next;
+ }
+ qemu_put_sbyte(f, 0);
}
static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
{
VirtIOBlock *s = opaque;
- if (version_id != 1)
+ if (version_id != 2)
return -EINVAL;
virtio_load(&s->vdev, f);
+ while (qemu_get_sbyte(f)) {
+ VirtIOBlockReq *req = virtio_blk_alloc_request(s);
+ qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
+ req->next = s->rq;
+ s->rq = req->next;
+ }
return 0;
}
@@ -227,8 +303,9 @@ void *virtio_blk_init(PCIBus *bus, BlockDriverState *bs)
s = (VirtIOBlock *)virtio_init_pci(bus, "virtio-blk",
PCI_VENDOR_ID_REDHAT_QUMRANET,
PCI_DEVICE_ID_VIRTIO_BLOCK,
- 0, VIRTIO_ID_BLOCK,
- 0x01, 0x80, 0x00,
+ PCI_VENDOR_ID_REDHAT_QUMRANET,
+ VIRTIO_ID_BLOCK,
+ PCI_CLASS_STORAGE_OTHER, 0x00,
sizeof(struct virtio_blk_config), sizeof(VirtIOBlock));
if (!s)
return NULL;
@@ -237,13 +314,15 @@ void *virtio_blk_init(PCIBus *bus, BlockDriverState *bs)
s->vdev.get_features = virtio_blk_get_features;
s->vdev.reset = virtio_blk_reset;
s->bs = bs;
+ s->rq = NULL;
bs->devfn = s->vdev.pci_dev.devfn;
bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
bdrv_set_geometry_hint(s->bs, cylinders, heads, secs);
s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);
- register_savevm("virtio-blk", virtio_blk_id++, 1,
+ qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
+ register_savevm("virtio-blk", virtio_blk_id++, 2,
virtio_blk_save, virtio_blk_load, s);
return s;
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index deae76d0d..92455c850 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -126,9 +126,11 @@ void *virtio_console_init(PCIBus *bus, CharDriverState *chr)
VirtIOConsole *s;
s = (VirtIOConsole *)virtio_init_pci(bus, "virtio-console",
- 6900, 0x1003,
- 0, VIRTIO_ID_CONSOLE,
- 0x03, 0x80, 0x00,
+ PCI_VENDOR_ID_REDHAT_QUMRANET,
+ PCI_DEVICE_ID_VIRTIO_CONSOLE,
+ PCI_VENDOR_ID_REDHAT_QUMRANET,
+ VIRTIO_ID_CONSOLE,
+ PCI_CLASS_DISPLAY_OTHER, 0x00,
0, sizeof(VirtIOConsole));
if (s == NULL)
return NULL;
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 358c3825d..d09b5b70e 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -414,9 +414,12 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
VirtIONet *n;
static int virtio_net_id;
- n = (VirtIONet *)virtio_init_pci(bus, "virtio-net", 6900, 0x1000,
- 0, VIRTIO_ID_NET,
- 0x02, 0x00, 0x00,
+ n = (VirtIONet *)virtio_init_pci(bus, "virtio-net",
+ PCI_VENDOR_ID_REDHAT_QUMRANET,
+ PCI_DEVICE_ID_VIRTIO_NET,
+ PCI_VENDOR_ID_REDHAT_QUMRANET,
+ VIRTIO_ID_NET,
+ PCI_CLASS_NETWORK_ETHERNET, 0x00,
sizeof(struct virtio_net_config),
sizeof(VirtIONet));
if (!n)
diff --git a/hw/virtio.c b/hw/virtio.c
index 35f46696f..1433dc547 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -738,6 +738,9 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
void virtio_notify_config(VirtIODevice *vdev)
{
+ if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))
+ return;
+
vdev->isr |= 0x03;
virtio_update_irq(vdev);
}
@@ -808,9 +811,8 @@ void virtio_load(VirtIODevice *vdev, QEMUFile *f)
VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name,
uint16_t vendor, uint16_t device,
uint16_t subvendor, uint16_t subdevice,
- uint8_t class_code, uint8_t subclass_code,
- uint8_t pif, size_t config_size,
- size_t struct_size)
+ uint16_t class_code, uint8_t pif,
+ size_t config_size, size_t struct_size)
{
VirtIODevice *vdev;
PCIDevice *pci_dev;
@@ -830,16 +832,13 @@ VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name,
vdev->vq = qemu_mallocz(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
config = pci_dev->config;
- config[0x00] = vendor & 0xFF;
- config[0x01] = (vendor >> 8) & 0xFF;
- config[0x02] = device & 0xFF;
- config[0x03] = (device >> 8) & 0xFF;
+ pci_config_set_vendor_id(config, vendor);
+ pci_config_set_device_id(config, device);
config[0x08] = VIRTIO_PCI_ABI_VERSION;
config[0x09] = pif;
- config[0x0a] = subclass_code;
- config[0x0b] = class_code;
+ pci_config_set_class(config, class_code);
config[0x0e] = 0x00;
config[0x2c] = subvendor & 0xFF;
diff --git a/hw/virtio.h b/hw/virtio.h
index 83511e2cb..18c7a1a7c 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -92,9 +92,8 @@ struct VirtIODevice
VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name,
uint16_t vendor, uint16_t device,
uint16_t subvendor, uint16_t subdevice,
- uint8_t class_code, uint8_t subclass_code,
- uint8_t pif, size_t config_size,
- size_t struct_size);
+ uint16_t class_code, uint8_t pif,
+ size_t config_size, size_t struct_size);
VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
void (*handle_output)(VirtIODevice *,
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 950a98c15..d1cba28a3 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1204,14 +1204,6 @@ static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num,
iomemtype);
}
-#define PCI_VENDOR_ID_VMWARE 0x15ad
-#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
-#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710
-#define PCI_DEVICE_ID_VMWARE_NET 0x0720
-#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730
-#define PCI_DEVICE_ID_VMWARE_IDE 0x1729
-#define PCI_CLASS_BASE_DISPLAY 0x03
-#define PCI_CLASS_SUB_VGA 0x00
#define PCI_CLASS_HEADERTYPE_00h 0x00
void pci_vmsvga_init(PCIBus *bus, uint8_t *vga_ram_base,
@@ -1223,13 +1215,10 @@ void pci_vmsvga_init(PCIBus *bus, uint8_t *vga_ram_base,
s = (struct pci_vmsvga_state_s *)
pci_register_device(bus, "QEMUware SVGA",
sizeof(struct pci_vmsvga_state_s), -1, 0, 0);
- s->card.config[PCI_VENDOR_ID] = PCI_VENDOR_ID_VMWARE & 0xff;
- s->card.config[PCI_VENDOR_ID + 1] = PCI_VENDOR_ID_VMWARE >> 8;
- s->card.config[PCI_DEVICE_ID] = SVGA_PCI_DEVICE_ID & 0xff;
- s->card.config[PCI_DEVICE_ID + 1] = SVGA_PCI_DEVICE_ID >> 8;
+ pci_config_set_vendor_id(s->card.config, PCI_VENDOR_ID_VMWARE);
+ pci_config_set_device_id(s->card.config, SVGA_PCI_DEVICE_ID);
s->card.config[PCI_COMMAND] = 0x07; /* I/O + Memory */
- s->card.config[PCI_CLASS_DEVICE] = PCI_CLASS_SUB_VGA;
- s->card.config[0x0b] = PCI_CLASS_BASE_DISPLAY;
+ pci_config_set_class(s->card.config, PCI_CLASS_DISPLAY_VGA);
s->card.config[0x0c] = 0x08; /* Cache line size */
s->card.config[0x0d] = 0x40; /* Latency timer */
s->card.config[0x0e] = PCI_CLASS_HEADERTYPE_00h;
diff --git a/linux-user/envlist.c b/linux-user/envlist.c
new file mode 100644
index 000000000..e13c2d3e1
--- /dev/null
+++ b/linux-user/envlist.c
@@ -0,0 +1,247 @@
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "envlist.h"
+
+struct envlist_entry {
+ const char *ev_var; /* actual env value */
+ LIST_ENTRY(envlist_entry) ev_link;
+};
+
+struct envlist {
+ LIST_HEAD(, envlist_entry) el_entries; /* actual entries */
+ size_t el_count; /* number of entries */
+};
+
+static int envlist_parse(envlist_t *envlist,
+ const char *env, int (*)(envlist_t *, const char *));
+
+/*
+ * Allocates new envlist and returns pointer to that or
+ * NULL in case of error.
+ */
+envlist_t *
+envlist_create(void)
+{
+ envlist_t *envlist;
+
+ if ((envlist = malloc(sizeof (*envlist))) == NULL)
+ return (NULL);
+
+ LIST_INIT(&envlist->el_entries);
+ envlist->el_count = 0;
+
+ return (envlist);
+}
+
+/*
+ * Releases given envlist and its entries.
+ */
+void
+envlist_free(envlist_t *envlist)
+{
+ struct envlist_entry *entry;
+
+ assert(envlist != NULL);
+
+ while (envlist->el_entries.lh_first != NULL) {
+ entry = envlist->el_entries.lh_first;
+ LIST_REMOVE(entry, ev_link);
+
+ free((char *)entry->ev_var);
+ free(entry);
+ }
+ free(envlist);
+}
+
+/*
+ * Parses comma separated list of set/modify environment
+ * variable entries and updates given enlist accordingly.
+ *
+ * For example:
+ * envlist_parse(el, "HOME=foo,SHELL=/bin/sh");
+ *
+ * inserts/sets environment variables HOME and SHELL.
+ *
+ * Returns 0 on success, errno otherwise.
+ */
+int
+envlist_parse_set(envlist_t *envlist, const char *env)
+{
+ return (envlist_parse(envlist, env, &envlist_setenv));
+}
+
+/*
+ * Parses comma separated list of unset environment variable
+ * entries and removes given variables from given envlist.
+ *
+ * Returns 0 on success, errno otherwise.
+ */
+int
+envlist_parse_unset(envlist_t *envlist, const char *env)
+{
+ return (envlist_parse(envlist, env, &envlist_unsetenv));
+}
+
+/*
+ * Parses comma separated list of set, modify or unset entries
+ * and calls given callback for each entry.
+ *
+ * Returns 0 in case of success, errno otherwise.
+ */
+static int
+envlist_parse(envlist_t *envlist, const char *env,
+ int (*callback)(envlist_t *, const char *))
+{
+ char *tmpenv, *envvar;
+ char *envsave = NULL;
+
+ assert(callback != NULL);
+
+ if ((envlist == NULL) || (env == NULL))
+ return (EINVAL);
+
+ /*
+ * We need to make temporary copy of the env string
+ * as strtok_r(3) modifies it while it tokenizes.
+ */
+ if ((tmpenv = strdup(env)) == NULL)
+ return (errno);
+
+ envvar = strtok_r(tmpenv, ",", &envsave);
+ while (envvar != NULL) {
+ if ((*callback)(envlist, envvar) != 0) {
+ free(tmpenv);
+ return (errno);
+ }
+ envvar = strtok_r(NULL, ",", &envsave);
+ }
+
+ free(tmpenv);
+ return (0);
+}
+
+/*
+ * Sets environment value to envlist in similar manner
+ * than putenv(3).
+ *
+ * Returns 0 in success, errno otherwise.
+ */
+int
+envlist_setenv(envlist_t *envlist, const char *env)
+{
+ struct envlist_entry *entry = NULL;
+ const char *eq_sign;
+ size_t envname_len;
+
+ if ((envlist == NULL) || (env == NULL))
+ return (EINVAL);
+
+ /* find out first equals sign in given env */
+ if ((eq_sign = strchr(env, '=')) == NULL)
+ return (EINVAL);
+ envname_len = eq_sign - env + 1;
+
+ /*
+ * If there already exists variable with given name
+ * we remove and release it before allocating a whole
+ * new entry.
+ */
+ for (entry = envlist->el_entries.lh_first; entry != NULL;
+ entry = entry->ev_link.le_next) {
+ if (strncmp(entry->ev_var, env, envname_len) == 0)
+ break;
+ }
+
+ if (entry != NULL) {
+ LIST_REMOVE(entry, ev_link);
+ free((char *)entry->ev_var);
+ free(entry);
+ } else {
+ envlist->el_count++;
+ }
+
+ if ((entry = malloc(sizeof (*entry))) == NULL)
+ return (errno);
+ if ((entry->ev_var = strdup(env)) == NULL) {
+ free(entry);
+ return (errno);
+ }
+ LIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link);
+
+ return (0);
+}
+
+/*
+ * Removes given env value from envlist in similar manner
+ * than unsetenv(3). Returns 0 in success, errno otherwise.
+ */
+int
+envlist_unsetenv(envlist_t *envlist, const char *env)
+{
+ struct envlist_entry *entry;
+ size_t envname_len;
+
+ if ((envlist == NULL) || (env == NULL))
+ return (EINVAL);
+
+ /* env is not allowed to contain '=' */
+ if (strchr(env, '=') != NULL)
+ return (EINVAL);
+
+ /*
+ * Find out the requested entry and remove
+ * it from the list.
+ */
+ envname_len = strlen(env);
+ for (entry = envlist->el_entries.lh_first; entry != NULL;
+ entry = entry->ev_link.le_next) {
+ if (strncmp(entry->ev_var, env, envname_len) == 0)
+ break;
+ }
+ if (entry != NULL) {
+ LIST_REMOVE(entry, ev_link);
+ free((char *)entry->ev_var);
+ free(entry);
+
+ envlist->el_count--;
+ }
+ return (0);
+}
+
+/*
+ * Returns given envlist as array of strings (in same form that
+ * global variable environ is). Caller must free returned memory
+ * by calling free(3) for each element and for the array. Returned
+ * array and given envlist are not related (no common references).
+ *
+ * If caller provides count pointer, number of items in array is
+ * stored there. In case of error, NULL is returned and no memory
+ * is allocated.
+ */
+char **
+envlist_to_environ(const envlist_t *envlist, size_t *count)
+{
+ struct envlist_entry *entry;
+ char **env, **penv;
+
+ penv = env = malloc((envlist->el_count + 1) * sizeof (char *));
+ if (env == NULL)
+ return (NULL);
+
+ for (entry = envlist->el_entries.lh_first; entry != NULL;
+ entry = entry->ev_link.le_next) {
+ *(penv++) = strdup(entry->ev_var);
+ }
+ *penv = NULL; /* NULL terminate the list */
+
+ if (count != NULL)
+ *count = envlist->el_count;
+
+ return (env);
+}
diff --git a/linux-user/envlist.h b/linux-user/envlist.h
new file mode 100644
index 000000000..e76d4a101
--- /dev/null
+++ b/linux-user/envlist.h
@@ -0,0 +1,22 @@
+#ifndef ENVLIST_H
+#define ENVLIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct envlist envlist_t;
+
+extern envlist_t *envlist_create(void);
+extern void envlist_free(envlist_t *);
+extern int envlist_setenv(envlist_t *, const char *);
+extern int envlist_unsetenv(envlist_t *, const char *);
+extern int envlist_parse_set(envlist_t *, const char *);
+extern int envlist_parse_unset(envlist_t *, const char *);
+extern char **envlist_to_environ(const envlist_t *, size_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ENVLIST_H */
diff --git a/linux-user/main.c b/linux-user/main.c
index bf4f3a557..af38b3880 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -32,8 +32,13 @@
/* For tb_lock */
#include "exec-all.h"
+
+#include "envlist.h"
+
#define DEBUG_LOGFILE "/tmp/qemu.log"
+char *exec_path;
+
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
const char *cpu_vendor_string = NULL;
@@ -2187,6 +2192,8 @@ static void usage(void)
"-s size set the stack size in bytes (default=%ld)\n"
"-cpu model select CPU (-cpu ? for list)\n"
"-drop-ld-preload drop LD_PRELOAD for target process\n"
+ "-E var=value sets/modifies targets environment variable(s)\n"
+ "-U var unsets targets environment variable(s)\n"
"\n"
"Debug options:\n"
"-d options activate log (logfile=%s)\n"
@@ -2196,6 +2203,12 @@ static void usage(void)
"Environment variables:\n"
"QEMU_STRACE Print system calls and arguments similar to the\n"
" 'strace' program. Enable by setting to any value.\n"
+ "You can use -E and -U options to set/unset environment variables\n"
+ "for target process. It is possible to provide several variables\n"
+ "by repeating the option. For example:\n"
+ " -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
+ "Note that if you provide several changes to single variable\n"
+ "last change will stay in effect.\n"
,
TARGET_ARCH,
interp_prefix,
@@ -2230,8 +2243,8 @@ int main(int argc, char **argv, char **envp)
int optind;
const char *r;
int gdbstub_port = 0;
- int drop_ld_preload = 0, environ_count = 0;
- char **target_environ, **wrk, **dst;
+ char **target_environ, **wrk;
+ envlist_t *envlist = NULL;
if (argc <= 1)
usage();
@@ -2241,6 +2254,16 @@ int main(int argc, char **argv, char **envp)
/* init debug */
cpu_set_log_filename(DEBUG_LOGFILE);
+ if ((envlist = envlist_create()) == NULL) {
+ (void) fprintf(stderr, "Unable to allocate envlist\n");
+ exit(1);
+ }
+
+ /* add current environment into the list */
+ for (wrk = environ; *wrk != NULL; wrk++) {
+ (void) envlist_setenv(envlist, *wrk);
+ }
+
cpu_model = NULL;
optind = 1;
for(;;) {
@@ -2270,6 +2293,14 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
cpu_set_log(mask);
+ } else if (!strcmp(r, "E")) {
+ r = argv[optind++];
+ if (envlist_setenv(envlist, r) != 0)
+ usage();
+ } else if (!strcmp(r, "U")) {
+ r = argv[optind++];
+ if (envlist_unsetenv(envlist, r) != 0)
+ usage();
} else if (!strcmp(r, "s")) {
r = argv[optind++];
x86_stack_size = strtol(r, (char **)&r, 0);
@@ -2302,7 +2333,7 @@ int main(int argc, char **argv, char **envp)
_exit(1);
}
} else if (!strcmp(r, "drop-ld-preload")) {
- drop_ld_preload = 1;
+ (void) envlist_unsetenv(envlist, "LD_PRELOAD");
} else if (!strcmp(r, "strace")) {
do_strace = 1;
} else
@@ -2313,6 +2344,7 @@ int main(int argc, char **argv, char **envp)
if (optind >= argc)
usage();
filename = argv[optind];
+ exec_path = argv[optind];
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
@@ -2370,19 +2402,8 @@ int main(int argc, char **argv, char **envp)
do_strace = 1;
}
- wrk = environ;
- while (*(wrk++))
- environ_count++;
-
- target_environ = malloc((environ_count + 1) * sizeof(char *));
- if (!target_environ)
- abort();
- for (wrk = environ, dst = target_environ; *wrk; wrk++) {
- if (drop_ld_preload && !strncmp(*wrk, "LD_PRELOAD=", 11))
- continue;
- *(dst++) = strdup(*wrk);
- }
- *dst = NULL; /* NULL terminate target_environ */
+ target_environ = envlist_to_environ(envlist, NULL);
+ envlist_free(envlist);
if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
printf("Error loading %s\n", filename);
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 8e81cdec7..888b49140 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -123,6 +123,21 @@ void qemu_free(void *ptr)
munmap(p, *p);
}
+void *qemu_realloc(void *ptr, size_t size)
+{
+ size_t old_size, copy;
+ void *new_ptr;
+
+ if (!ptr)
+ return qemu_malloc(size);
+ old_size = *(size_t *)((char *)ptr - 16);
+ copy = old_size < size ? old_size : size;
+ new_ptr = qemu_malloc(size);
+ memcpy(new_ptr, ptr, copy);
+ qemu_free(ptr);
+ return new_ptr;
+}
+
/* NOTE: all the constants are the HOST ones, but addresses are target. */
int target_mprotect(abi_ulong start, abi_ulong len, int prot)
{
diff --git a/linux-user/path.c b/linux-user/path.c
index 27c7d5051..06b1f5fb6 100644
--- a/linux-user/path.c
+++ b/linux-user/path.c
@@ -152,7 +152,7 @@ const char *path(const char *name)
{
/* Only do absolute paths: quick and dirty, but should mostly be OK.
Could do relative by tracking cwd. */
- if (!base || name[0] != '/')
+ if (!base || !name || name[0] != '/')
return name;
return follow_path(base, name) ?: name;
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 9fddd0519..41375677f 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -120,6 +120,7 @@ typedef struct TaskState {
uint8_t stack[0];
} __attribute__((aligned(16))) TaskState;
+extern char *exec_path;
void init_task_state(TaskState *ts);
extern const char *qemu_uname_release;
diff --git a/linux-user/signal.c b/linux-user/signal.c
index a468d7a83..4f3741e91 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -349,7 +349,7 @@ static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
}
/* abort execution with signal */
-static void noreturn force_sig(int sig)
+static void QEMU_NORETURN force_sig(int sig)
{
int host_sig;
host_sig = target_to_host_signal(sig);
@@ -1399,7 +1399,7 @@ restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
return err;
}
-long do_sigreturn_v1(CPUState *env)
+static long do_sigreturn_v1(CPUState *env)
{
abi_ulong frame_addr;
struct sigframe_v1 *frame;
@@ -1469,7 +1469,7 @@ static int do_sigframe_return_v2(CPUState *env, target_ulong frame_addr,
return 0;
}
-long do_sigreturn_v2(CPUState *env)
+static long do_sigreturn_v2(CPUState *env)
{
abi_ulong frame_addr;
struct sigframe_v2 *frame;
@@ -1507,7 +1507,7 @@ long do_sigreturn(CPUState *env)
}
}
-long do_rt_sigreturn_v1(CPUState *env)
+static long do_rt_sigreturn_v1(CPUState *env)
{
abi_ulong frame_addr;
struct rt_sigframe_v1 *frame;
@@ -1548,7 +1548,7 @@ badframe:
return 0;
}
-long do_rt_sigreturn_v2(CPUState *env)
+static long do_rt_sigreturn_v2(CPUState *env)
{
abi_ulong frame_addr;
struct rt_sigframe_v2 *frame;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 5d787bb75..8d52099cb 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1140,11 +1140,19 @@ static abi_long do_socket(int domain, int type, int protocol)
return get_errno(socket(domain, type, protocol));
}
+/* MAX_SOCK_ADDR from linux/net/socket.c */
+#define MAX_SOCK_ADDR 128
+
/* do_bind() Must return target values and target errnos. */
static abi_long do_bind(int sockfd, abi_ulong target_addr,
socklen_t addrlen)
{
- void *addr = alloca(addrlen);
+ void *addr;
+
+ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ return -TARGET_EINVAL;
+
+ addr = alloca(addrlen);
target_to_host_sockaddr(addr, target_addr, addrlen);
return get_errno(bind(sockfd, addr, addrlen));
@@ -1154,7 +1162,12 @@ static abi_long do_bind(int sockfd, abi_ulong target_addr,
static abi_long do_connect(int sockfd, abi_ulong target_addr,
socklen_t addrlen)
{
- void *addr = alloca(addrlen);
+ void *addr;
+
+ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ return -TARGET_EINVAL;
+
+ addr = alloca(addrlen);
target_to_host_sockaddr(addr, target_addr, addrlen);
return get_errno(connect(sockfd, addr, addrlen));
@@ -1226,6 +1239,9 @@ static abi_long do_accept(int fd, abi_ulong target_addr,
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
+ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ return -TARGET_EINVAL;
+
addr = alloca(addrlen);
ret = get_errno(accept(fd, addr, &addrlen));
@@ -1248,6 +1264,9 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr,
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
+ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ return -TARGET_EINVAL;
+
addr = alloca(addrlen);
ret = get_errno(getpeername(fd, addr, &addrlen));
@@ -1267,9 +1286,15 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr,
void *addr;
abi_long ret;
+ if (target_addr == 0)
+ return get_errno(accept(fd, NULL, NULL));
+
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
+ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ return -TARGET_EINVAL;
+
addr = alloca(addrlen);
ret = get_errno(getsockname(fd, addr, &addrlen));
@@ -1305,6 +1330,9 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
void *host_msg;
abi_long ret;
+ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ return -TARGET_EINVAL;
+
host_msg = lock_user(VERIFY_READ, msg, len, 1);
if (!host_msg)
return -TARGET_EFAULT;
@@ -1337,6 +1365,10 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
ret = -TARGET_EFAULT;
goto fail;
}
+ if (addrlen < 0 || addrlen > MAX_SOCK_ADDR) {
+ ret = -TARGET_EINVAL;
+ goto fail;
+ }
addr = alloca(addrlen);
ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
} else {
@@ -3405,10 +3437,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = 0; /* avoid warning */
break;
case TARGET_NR_read:
- if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
- goto efault;
- ret = get_errno(read(arg1, p, arg3));
- unlock_user(p, arg2, ret);
+ if (arg3 == 0)
+ ret = 0;
+ else {
+ if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
+ goto efault;
+ ret = get_errno(read(arg1, p, arg3));
+ unlock_user(p, arg2, ret);
+ }
break;
case TARGET_NR_write:
if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
@@ -3909,10 +3945,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
goto unimplemented;
#endif
case TARGET_NR_acct:
- if (!(p = lock_user_string(arg1)))
- goto efault;
- ret = get_errno(acct(path(p)));
- unlock_user(p, arg1, 0);
+ if (arg1 == 0) {
+ ret = get_errno(acct(NULL));
+ } else {
+ if (!(p = lock_user_string(arg1)))
+ goto efault;
+ ret = get_errno(acct(path(p)));
+ unlock_user(p, arg1, 0);
+ }
break;
#ifdef TARGET_NR_umount2 /* not on alpha */
case TARGET_NR_umount2:
@@ -4370,13 +4410,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif
case TARGET_NR_readlink:
{
- void *p2;
+ void *p2, *temp;
p = lock_user_string(arg1);
p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
if (!p || !p2)
ret = -TARGET_EFAULT;
- else
- ret = get_errno(readlink(path(p), p2, arg3));
+ else {
+ if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
+ char real[PATH_MAX];
+ temp = realpath(exec_path,real);
+ ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
+ snprintf((char *)p2, arg3, "%s", real);
+ }
+ else
+ ret = get_errno(readlink(path(p), p2, arg3));
+ break;
+ }
unlock_user(p2, arg2, ret);
unlock_user(p, arg1, 0);
}
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 86c9d8282..7db7a8c1f 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -1141,7 +1141,7 @@ struct target_stat {
#endif
};
-struct target_stat64 {
+struct __attribute__((__packed__)) target_stat64 {
unsigned long long st_dev;
unsigned long long st_ino;
unsigned int st_mode;
@@ -1149,10 +1149,11 @@ struct target_stat64 {
unsigned int st_uid;
unsigned int st_gid;
unsigned long long st_rdev;
- unsigned short pad0;
+ unsigned long long __pad0;
long long st_size;
int st_blksize;
long long st_blocks; /* Number 512-byte blocks allocated. */
+ unsigned int __pad1;
int target_st_atime;
unsigned int target_st_atime_nsec;
int target_st_mtime;
@@ -1475,7 +1476,7 @@ struct target_stat {
/* This matches struct stat64 in glibc2.1, hence the absolutely
* insane amounts of padding around dev_t's.
*/
-struct target_stat64 {
+struct __attribute__((__packed__)) target_stat64 {
unsigned long long st_dev;
unsigned char __pad0[4];
diff --git a/monitor.c b/monitor.c
index 1bc46f461..c00ddac32 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1456,6 +1456,7 @@ static void do_info_balloon(void)
term_printf("balloon: actual=%d\n", (int)(actual >> 20));
}
+/* Please update qemu-doc.texi when adding or changing commands */
static const term_cmd_t term_cmds[] = {
{ "help|?", "s?", do_help,
"[cmd]", "show the help" },
@@ -1523,8 +1524,8 @@ static const term_cmd_t term_cmds[] = {
"path [frequency bits channels]",
"capture audio to a wave file (default frequency=44100 bits=16 channels=2)" },
#endif
- { "stopcapture", "i", do_stop_capture,
- "capture index", "stop capture" },
+ { "stopcapture", "i", do_stop_capture,
+ "capture index", "stop capture" },
{ "memsave", "lis", do_memory_save,
"addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'", },
{ "pmemsave", "lis", do_physical_memory_save,
@@ -1557,9 +1558,10 @@ static const term_cmd_t term_cmds[] = {
{ NULL, NULL, },
};
+/* Please update qemu-doc.texi when adding or changing commands */
static const term_cmd_t info_cmds[] = {
{ "version", "", do_info_version,
- "", "show the version of qemu" },
+ "", "show the version of QEMU" },
{ "network", "", do_info_network,
"", "show the network state" },
{ "chardev", "", qemu_chr_info,
@@ -1591,9 +1593,9 @@ static const term_cmd_t info_cmds[] = {
{ "jit", "", do_info_jit,
"", "show dynamic compiler info", },
{ "kqemu", "", do_info_kqemu,
- "", "show kqemu information", },
+ "", "show KQEMU information", },
{ "kvm", "", do_info_kvm,
- "", "show kvm information", },
+ "", "show KVM information", },
{ "usb", "", usb_info,
"", "show guest USB devices", },
{ "usbhost", "", usb_host_info,
diff --git a/net.c b/net.c
index 9841197c3..b4c92daa7 100644
--- a/net.c
+++ b/net.c
@@ -428,6 +428,16 @@ static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
return offset;
}
+static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt)
+{
+ size_t offset = 0;
+ int i;
+
+ for (i = 0; i < iovcnt; i++)
+ offset += iov[i].iov_len;
+ return offset;
+}
+
ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov,
int iovcnt)
{
@@ -435,12 +445,17 @@ ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov,
VLANClientState *vc;
ssize_t max_len = 0;
+ if (vc1->link_down)
+ return calc_iov_length(iov, iovcnt);
+
for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
ssize_t len = 0;
if (vc == vc1)
continue;
+ if (vc->link_down)
+ len = calc_iov_length(iov, iovcnt);
if (vc->fd_readv)
len = vc->fd_readv(vc->opaque, iov, iovcnt);
else if (vc->fd_read)
diff --git a/pci-ids.txt b/pci-ids.txt
index 57d817519..73125a8bd 100644
--- a/pci-ids.txt
+++ b/pci-ids.txt
@@ -19,8 +19,9 @@ VirtIO Device IDs
1af4:1000 network device
1af4:1001 block device
1af4:1002 balloon device
+1af4:1003 console device
-1af4:1003 Reserved.
+1af4:1004 Reserved.
to Contact Gerd Hoffmann <kraxel@redhat.com> to get a
1af4:10ef device ID assigned for your new virtio device.
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index ef76f74ac..f141cd9e1 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -94,7 +94,7 @@ static void *aio_thread(void *unused)
idle_threads++;
pthread_mutex_unlock(&lock);
- kill(getpid(), aiocb->sigev_signo);
+ kill(getpid(), aiocb->ev_signo);
}
idle_threads--;
diff --git a/posix-aio-compat.h b/posix-aio-compat.h
index 5eb17043e..0bc10f5e0 100644
--- a/posix-aio-compat.h
+++ b/posix-aio-compat.h
@@ -29,7 +29,7 @@ struct qemu_paiocb
int aio_fildes;
void *aio_buf;
size_t aio_nbytes;
- int sigev_signo;
+ int ev_signo;
off_t aio_offset;
/* private */
diff --git a/qemu-char.c b/qemu-char.c
index ac431c7c5..f8491878b 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -241,13 +241,13 @@ static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
if (term_timestamps_start == -1)
term_timestamps_start = ti;
ti -= term_timestamps_start;
- secs = ti / 1000000000;
+ secs = ti / 1000;
snprintf(buf1, sizeof(buf1),
"[%02d:%02d:%02d.%03d] ",
secs / 3600,
(secs / 60) % 60,
secs % 60,
- (int)((ti / 1000000) % 1000));
+ (int)(ti % 1000));
d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));
}
}
diff --git a/qemu-common.h b/qemu-common.h
index d6756a3d0..e8469dd8a 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -8,9 +8,9 @@
#include <windows.h>
#endif
-#define noreturn __attribute__ ((__noreturn__))
+#define QEMU_NORETURN __attribute__ ((__noreturn__))
-/* Hack around the mess dyngen-exec.h causes: We need noreturn in files that
+/* Hack around the mess dyngen-exec.h causes: We need QEMU_NORETURN in files that
cannot include the following headers without conflicts. This condition has
to be removed once dyngen is gone. */
#ifndef __DYNGEN_EXEC_H__
@@ -146,7 +146,7 @@ void *get_mmap_addr(unsigned long size);
/* Error handling. */
-void noreturn hw_error(const char *fmt, ...)
+void QEMU_NORETURN hw_error(const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 1, 2)));
/* IO callbacks. */
@@ -198,6 +198,19 @@ struct qemu_work_item {
int done;
};
+typedef struct QEMUIOVector {
+ struct iovec *iov;
+ int niov;
+ int nalloc;
+ size_t size;
+} QEMUIOVector;
+
+void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint);
+void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
+void qemu_iovec_destroy(QEMUIOVector *qiov);
+void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf);
+void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count);
+
#endif /* dyngen-exec.h hack */
#endif
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 02298f7d3..8fccdd4a0 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -221,13 +221,25 @@ usage: qemu [options] [@var{disk_image}]
@end example
@c man begin OPTIONS
-@var{disk_image} is a raw hard disk image for IDE hard disk 0.
+@var{disk_image} is a raw hard disk image for IDE hard disk 0. Some
+targets do not need a disk image.
General options:
@table @option
+@item -h
+Display help and exit
+
@item -M @var{machine}
Select the emulated @var{machine} (@code{-M ?} for list)
+@item -cpu @var{model}
+Select CPU model (-cpu ? for list and additional feature selection)
+
+@item -smp @var{n}
+Simulate an SMP system with @var{n} CPUs. On the PC target, up to 255
+CPUs are supported. On Sparc32 target, Linux limits the number of usable CPUs
+to 4.
+
@item -fda @var{file}
@item -fdb @var{file}
Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can
@@ -352,6 +364,15 @@ is interpreted like:
qemu -hda a -hdb b
@end example
+@item -mtdblock file
+Use 'file' as on-board Flash memory image.
+
+@item -sd file
+Use 'file' as SecureDigital card image.
+
+@item -pflash file
+Use 'file' as a parallel flash image.
+
@item -boot [a|c|d|n]
Boot on floppy (a), hard disk (c), CD-ROM (d), or Etherboot (n). Hard disk boot
is the default.
@@ -361,22 +382,27 @@ Write to temporary files instead of disk image files. In this case,
the raw disk image you use is not written back. You can however force
the write back by pressing @key{C-a s} (@pxref{disk_images}).
-@item -no-fd-bootchk
-Disable boot signature checking for floppy disks in Bochs BIOS. It may
-be needed to boot from old floppy disks.
-
@item -m @var{megs}
Set virtual RAM size to @var{megs} megabytes. Default is 128 MiB. Optionally,
a suffix of ``M'' or ``G'' can be used to signify a value in megabytes or
gigabytes respectively.
-@item -cpu @var{model}
-Select CPU model (-cpu ? for list and additional feature selection)
+@item -k @var{language}
-@item -smp @var{n}
-Simulate an SMP system with @var{n} CPUs. On the PC target, up to 255
-CPUs are supported. On Sparc32 target, Linux limits the number of usable CPUs
-to 4.
+Use keyboard layout @var{language} (for example @code{fr} for
+French). This option is only needed where it is not easy to get raw PC
+keycodes (e.g. on Macs, with some X11 servers or with a VNC
+display). You don't normally need to use it on PC/Linux or PC/Windows
+hosts.
+
+The available layouts are:
+@example
+ar de-ch es fo fr-ca hu ja mk no pt-br sv
+da en-gb et fr fr-ch is lt nl pl ru th
+de en-us fi fr-be hr it lv nl-be pt sl tr
+@end example
+
+The default is @code{en-us}.
@item -audio-help
@@ -403,45 +429,59 @@ require manually specifying clocking.
modprobe i810_audio clocking=48000
@end example
-@item -localtime
-Set the real time clock to local time (the default is to UTC
-time). This option is needed to have correct date in MS-DOS or
-Windows.
+@end table
-@item -startdate @var{date}
-Set the initial date of the real time clock. Valid formats for
-@var{date} are: @code{now} or @code{2006-06-17T16:01:21} or
-@code{2006-06-17}. The default value is @code{now}.
+USB options:
+@table @option
-@item -pidfile @var{file}
-Store the QEMU process PID in @var{file}. It is useful if you launch QEMU
-from a script.
+@item -usb
+Enable the USB driver (will be the default soon)
-@item -daemonize
-Daemonize the QEMU process after initialization. QEMU will not detach from
-standard IO until it is ready to receive connections on any of its devices.
-This option is a useful way for external programs to launch QEMU without having
-to cope with initialization race conditions.
+@item -usbdevice @var{devname}
+Add the USB device @var{devname}. @xref{usb_devices}.
-@item -win2k-hack
-Use it when installing Windows 2000 to avoid a disk full bug. After
-Windows 2000 is installed, you no longer need this option (this option
-slows down the IDE transfers).
+@table @code
-@item -rtc-td-hack
-Use it if you experience time drift problem in Windows with ACPI HAL.
-This option will try to figure out how many timer interrupts were not
-processed by the Windows guest and will re-inject them.
+@item mouse
+Virtual Mouse. This will override the PS/2 mouse emulation when activated.
-@item -option-rom @var{file}
-Load the contents of @var{file} as an option ROM.
-This option is useful to load things like EtherBoot.
+@item tablet
+Pointer device that uses absolute coordinates (like a touchscreen). This
+means qemu is able to report the mouse position without having to grab the
+mouse. Also overrides the PS/2 mouse emulation when activated.
+
+@item disk:[format=@var{format}]:file
+Mass storage device based on file. The optional @var{format} argument
+will be used rather than detecting the format. Can be used to specifiy
+format=raw to avoid interpreting an untrusted format header.
+
+@item host:bus.addr
+Pass through the host device identified by bus.addr (Linux only).
+
+@item host:vendor_id:product_id
+Pass through the host device identified by vendor_id:product_id (Linux only).
+
+@item serial:[vendorid=@var{vendor_id}][,productid=@var{product_id}]:@var{dev}
+Serial converter to host character device @var{dev}, see @code{-serial} for the
+available devices.
+
+@item braille
+Braille device. This will use BrlAPI to display the braille output on a real
+or fake device.
+
+@item net:options
+Network adapter that supports CDC ethernet and RNDIS protocols.
+
+@end table
@item -name @var{name}
Sets the @var{name} of the guest.
This name will be displayed in the SDL window caption.
The @var{name} will also be used for the VNC server.
+@item -uuid @var{uuid}
+Set system UUID.
+
@end table
Display options:
@@ -467,10 +507,43 @@ Do not use decorations for SDL windows and start them using the whole
available screen space. This makes the using QEMU in a dedicated desktop
workspace more convenient.
+@item -alt-grab
+
+Use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt).
+
@item -no-quit
Disable SDL window close capability.
+@item -sdl
+
+Enable SDL.
+
+@item -portrait
+
+Rotate graphical output 90 deg left (only PXA LCD).
+
+@item -vga @var{type}
+Select type of VGA card to emulate. Valid values for @var{type} are
+@table @code
+@item cirrus
+Cirrus Logic GD5446 Video card. All Windows versions starting from
+Windows 95 should recognize and use this graphic card. For optimal
+performances, use 16 bit color depth in the guest and the host OS.
+(This one is the default)
+@item std
+Standard VGA card with Bochs VBE extensions. If your guest OS
+supports the VESA 2.0 VBE extensions (e.g. Windows XP) and if you want
+to use high resolution modes (>= 1280x1024x16) then you should use
+this option.
+@item vmware
+VMWare SVGA-II compatible adapter. Use it if you have sufficiently
+recent XFree86/XOrg server or Windows guest with a driver for this
+card.
+@item none
+Disable VGA card.
+@end table
+
@item -full-screen
Start in full screen.
@@ -553,68 +626,6 @@ certificates.
@end table
-@item -k @var{language}
-
-Use keyboard layout @var{language} (for example @code{fr} for
-French). This option is only needed where it is not easy to get raw PC
-keycodes (e.g. on Macs, with some X11 servers or with a VNC
-display). You don't normally need to use it on PC/Linux or PC/Windows
-hosts.
-
-The available layouts are:
-@example
-ar de-ch es fo fr-ca hu ja mk no pt-br sv
-da en-gb et fr fr-ch is lt nl pl ru th
-de en-us fi fr-be hr it lv nl-be pt sl tr
-@end example
-
-The default is @code{en-us}.
-
-@end table
-
-USB options:
-@table @option
-
-@item -usb
-Enable the USB driver (will be the default soon)
-
-@item -usbdevice @var{devname}
-Add the USB device @var{devname}. @xref{usb_devices}.
-
-@table @code
-
-@item mouse
-Virtual Mouse. This will override the PS/2 mouse emulation when activated.
-
-@item tablet
-Pointer device that uses absolute coordinates (like a touchscreen). This
-means qemu is able to report the mouse position without having to grab the
-mouse. Also overrides the PS/2 mouse emulation when activated.
-
-@item disk:[format=@var{format}]:file
-Mass storage device based on file. The optional @var{format} argument
-will be used rather than detecting the format. Can be used to specifiy
-format=raw to avoid interpreting an untrusted format header.
-
-@item host:bus.addr
-Pass through the host device identified by bus.addr (Linux only).
-
-@item host:vendor_id:product_id
-Pass through the host device identified by vendor_id:product_id (Linux only).
-
-@item serial:[vendorid=@var{vendor_id}][,productid=@var{product_id}]:@var{dev}
-Serial converter to host character device @var{dev}, see @code{-serial} for the
-available devices.
-
-@item braille
-Braille device. This will use BrlAPI to display the braille output on a real
-or fake device.
-
-@item net:options
-Network adapter that supports CDC ethernet and RNDIS protocols.
-
-@end table
-
@end table
Network options:
@@ -864,6 +875,34 @@ Virtual wireless keyboard implementing the HIDP bluetooth profile.
@end table
+i386 target only:
+
+@table @option
+
+@item -win2k-hack
+Use it when installing Windows 2000 to avoid a disk full bug. After
+Windows 2000 is installed, you no longer need this option (this option
+slows down the IDE transfers).
+
+@item -rtc-td-hack
+Use it if you experience time drift problem in Windows with ACPI HAL.
+This option will try to figure out how many timer interrupts were not
+processed by the Windows guest and will re-inject them.
+
+@item -no-fd-bootchk
+Disable boot signature checking for floppy disks in Bochs BIOS. It may
+be needed to boot from old floppy disks.
+
+@item -no-acpi
+Disable ACPI (Advanced Configuration and Power Interface) support. Use
+it if your guest OS complains about ACPI problems (PC target machine
+only).
+
+@item -no-hpet
+Disable HPET support.
+
+@end table
+
Linux boot specific: When using these options, you can use a given
Linux kernel without installing it in the disk image. It can be useful
for easier testing of various kernels.
@@ -889,7 +928,7 @@ Redirect the virtual serial port to host character device
@var{dev}. The default device is @code{vc} in graphical mode and
@code{stdio} in non graphical mode.
-This option can be used several times to simulate up to 4 serials
+This option can be used several times to simulate up to 4 serial
ports.
Use @code{-serial none} to disable all serial ports.
@@ -1023,26 +1062,20 @@ serial port).
The default device is @code{vc} in graphical mode and @code{stdio} in
non graphical mode.
-@item -echr numeric_ascii_value
-Change the escape character used for switching to the monitor when using
-monitor and serial sharing. The default is @code{0x01} when using the
-@code{-nographic} option. @code{0x01} is equal to pressing
-@code{Control-a}. You can select a different character from the ascii
-control keys where 1 through 26 map to Control-a through Control-z. For
-instance you could use the either of the following to change the escape
-character to Control-t.
-@table @code
-@item -echr 0x14
-@item -echr 20
-@end table
+@item -pidfile @var{file}
+Store the QEMU process PID in @var{file}. It is useful if you launch QEMU
+from a script.
+
+@item -S
+Do not start CPU at startup (you must type 'c' in the monitor).
@item -s
Wait gdb connection to port 1234 (@pxref{gdb_usage}).
+
@item -p @var{port}
Change gdb connection port. @var{port} can be either a decimal number
to specify a TCP port, or a host device (same devices as the serial port).
-@item -S
-Do not start CPU at startup (you must type 'c' in the monitor).
+
@item -d
Output log in /tmp/qemu.log
@item -hdachs @var{c},@var{h},@var{s},[,@var{t}]
@@ -1052,32 +1085,22 @@ translation mode (@var{t}=none, lba or auto). Usually QEMU can guess
all those parameters. This option is useful for old MS-DOS disk
images.
-@item -L path
+@item -L @var{path}
Set the directory for the BIOS, VGA BIOS and keymaps.
-@item -vga @var{type}
-Select type of VGA card to emulate. Valid values for @var{type} are
-@table @code
-@item cirrus
-Cirrus Logic GD5446 Video card. All Windows versions starting from
-Windows 95 should recognize and use this graphic card. For optimal
-performances, use 16 bit color depth in the guest and the host OS.
-(This one is the default)
-@item std
-Standard VGA card with Bochs VBE extensions. If your guest OS
-supports the VESA 2.0 VBE extensions (e.g. Windows XP) and if you want
-to use high resolution modes (>= 1280x1024x16) then you should use
-this option.
-@item vmware
-VMWare SVGA-II compatible adapter. Use it if you have sufficiently
-recent XFree86/XOrg server or Windows guest with a driver for this
-card.
-@end table
+@item -bios @var{file}
+Set the filename for the BIOS.
-@item -no-acpi
-Disable ACPI (Advanced Configuration and Power Interface) support. Use
-it if your guest OS complains about ACPI problems (PC target machine
-only).
+@item -kernel-kqemu
+Enable KQEMU full virtualization (default is user mode only).
+
+@item -no-kqemu
+Disable KQEMU kernel module usage. KQEMU options are only available if
+KQEMU support is enabled when compiling.
+
+@item -enable-kvm
+Enable KVM full virtualization support. This option is only available
+if KVM support is enabled when compiling.
@item -no-reboot
Exit instead of rebooting.
@@ -1087,17 +1110,32 @@ Don't exit QEMU on guest shutdown, but instead only stop the emulation.
This allows for instance switching to monitor to commit changes to the
disk image.
-@item -loadvm file
+@item -loadvm @var{file}
Start right away with a saved state (@code{loadvm} in monitor)
-@item -semihosting
-Enable semihosting syscall emulation (ARM and M68K target machines only).
+@item -daemonize
+Daemonize the QEMU process after initialization. QEMU will not detach from
+standard IO until it is ready to receive connections on any of its devices.
+This option is a useful way for external programs to launch QEMU without having
+to cope with initialization race conditions.
-On ARM this implements the "Angel" interface.
-On M68K this implements the "ColdFire GDB" interface used by libgloss.
+@item -option-rom @var{file}
+Load the contents of @var{file} as an option ROM.
+This option is useful to load things like EtherBoot.
-Note that this allows guest direct access to the host filesystem,
-so should only be used with trusted guest OS.
+@item -clock @var{method}
+Force the use of the given methods for timer alarm. To see what timers
+are available use -clock ?.
+
+@item -localtime
+Set the real time clock to local time (the default is to UTC
+time). This option is needed to have correct date in MS-DOS or
+Windows.
+
+@item -startdate @var{date}
+Set the initial date of the real time clock. Valid formats for
+@var{date} are: @code{now} or @code{2006-06-17T16:01:21} or
+@code{2006-06-17}. The default value is @code{now}.
@item -icount [N|auto]
Enable virtual instruction counter. The virtual cpu will execute one
@@ -1109,6 +1147,20 @@ Note that while this option can give deterministic behavior, it does not
provide cycle accurate emulation. Modern CPUs contain superscalar out of
order cores with complex cache hierarchies. The number of instructions
executed often has little or no correlation with actual performance.
+
+@item -echr numeric_ascii_value
+Change the escape character used for switching to the monitor when using
+monitor and serial sharing. The default is @code{0x01} when using the
+@code{-nographic} option. @code{0x01} is equal to pressing
+@code{Control-a}. You can select a different character from the ascii
+control keys where 1 through 26 map to Control-a through Control-z. For
+instance you could use the either of the following to change the escape
+character to Control-t.
+@table @code
+@item -echr 0x14
+@item -echr 20
+@end table
+
@end table
@c man end
@@ -1146,13 +1198,14 @@ During emulation, if you are using the @option{-nographic} option, use
@table @key
@item Ctrl-a h
+@item Ctrl-a ?
Print this help
@item Ctrl-a x
Exit emulator
@item Ctrl-a s
Save disk data back to file (if -snapshot)
@item Ctrl-a t
-toggle console timestamps
+Toggle console timestamps
@item Ctrl-a b
Send break (magic sysrq in Linux)
@item Ctrl-a c
@@ -1211,26 +1264,68 @@ Commit changes to the disk images (if -snapshot is used).
Show various information about the system state.
@table @option
+@item info version
+show the version of QEMU
@item info network
show the various VLANs and the associated devices
+@item info chardev
+show the character devices
@item info block
show the block devices
+@item info block
+show block device statistics
@item info registers
show the cpu registers
+@item info cpus
+show infos for each CPU
@item info history
show the command line history
+@item info irq
+show the interrupts statistics (if available)
+@item info pic
+show i8259 (PIC) state
@item info pci
-show emulated PCI device
+show emulated PCI device info
+@item info tlb
+show virtual to physical memory mappings (i386 only)
+@item info mem
+show the active virtual memory mappings (i386 only)
+@item info hpet
+show state of HPET (i386 only)
+@item info kqemu
+show KQEMU information
+@item info kvm
+show KVM information
@item info usb
show USB devices plugged on the virtual USB hub
@item info usbhost
show all USB host devices
+@item info profile
+show profiling information
@item info capture
show information about active capturing
@item info snapshots
show list of VM snapshots
+@item info status
+show the current VM status (running|paused)
+@item info pcmcia
+show guest PCMCIA status
@item info mice
show which guest mouse is receiving events
+@item info vnc
+show the vnc server status
+@item info name
+show the current VM name
+@item info uuid
+show the current VM UUID
+@item info cpustats
+show CPU statistics
+@item info slirp
+show SLIRP statistics (if available)
+@item info migrate
+show migration status
+@item info balloon
+show balloon information
@end table
@item q or quit
@@ -1244,13 +1339,15 @@ Eject a removable medium (use -f to force it).
Change the configuration of a device.
@table @option
-@item change @var{diskdevice} @var{filename}
+@item change @var{diskdevice} @var{filename} [@var{format}]
Change the medium for a removable disk device to point to @var{filename}. eg
@example
(qemu) change ide1-cd0 /path/to/some.iso
@end example
+@var{format} is optional.
+
@item change vnc @var{display},@var{options}
Change the configuration of the VNC server. The valid syntax for @var{display}
and @var{options} are described at @ref{sec_invocation}. eg
@@ -1275,36 +1372,8 @@ Password: ********
@item screendump @var{filename}
Save screen into PPM image @var{filename}.
-@item mouse_move @var{dx} @var{dy} [@var{dz}]
-Move the active mouse to the specified coordinates @var{dx} @var{dy}
-with optional scroll axis @var{dz}.
-
-@item mouse_button @var{val}
-Change the active mouse button state @var{val} (1=L, 2=M, 4=R).
-
-@item mouse_set @var{index}
-Set which mouse device receives events at given @var{index}, index
-can be obtained with
-@example
-info mice
-@end example
-
-@item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]]
-Capture audio into @var{filename}. Using sample rate @var{frequency}
-bits per sample @var{bits} and number of channels @var{channels}.
-
-Defaults:
-@itemize @minus
-@item Sample rate = 44100 Hz - CD quality
-@item Bits = 16
-@item Number of channels = 2 - Stereo
-@end itemize
-
-@item stopcapture @var{index}
-Stop capture with a given @var{index}, index can be obtained with
-@example
-info capture
-@end example
+@item logfile @var{filename}
+Output logs to @var{filename}.
@item log @var{item1}[,...]
Activate logging of the specified items to @file{/tmp/qemu.log}.
@@ -1411,13 +1480,13 @@ intercepts at low level, such as @code{ctrl-alt-f1} in X Window.
Reset the system.
-@item boot_set @var{bootdevicelist}
+@item system_powerdown
-Define new values for the boot device list. Those values will override
-the values specified on the command line through the @code{-boot} option.
+Power down the system (if supported).
-The values that can be specified here depend on the machine type, but are
-the same that can be specified in the @code{-boot} command line option.
+@item sum @var{addr} @var{size}
+
+Compute the checksum of a memory region.
@item usb_add @var{devname}
@@ -1430,6 +1499,69 @@ Remove the USB device @var{devname} from the QEMU virtual USB
hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor
command @code{info usb} to see the devices you can remove.
+@item mouse_move @var{dx} @var{dy} [@var{dz}]
+Move the active mouse to the specified coordinates @var{dx} @var{dy}
+with optional scroll axis @var{dz}.
+
+@item mouse_button @var{val}
+Change the active mouse button state @var{val} (1=L, 2=M, 4=R).
+
+@item mouse_set @var{index}
+Set which mouse device receives events at given @var{index}, index
+can be obtained with
+@example
+info mice
+@end example
+
+@item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]]
+Capture audio into @var{filename}. Using sample rate @var{frequency}
+bits per sample @var{bits} and number of channels @var{channels}.
+
+Defaults:
+@itemize @minus
+@item Sample rate = 44100 Hz - CD quality
+@item Bits = 16
+@item Number of channels = 2 - Stereo
+@end itemize
+
+@item stopcapture @var{index}
+Stop capture with a given @var{index}, index can be obtained with
+@example
+info capture
+@end example
+
+@item memsave @var{addr} @var{size} @var{file}
+save to disk virtual memory dump starting at @var{addr} of size @var{size}.
+
+@item pmemsave @var{addr} @var{size} @var{file}
+save to disk physical memory dump starting at @var{addr} of size @var{size}.
+
+@item boot_set @var{bootdevicelist}
+
+Define new values for the boot device list. Those values will override
+the values specified on the command line through the @code{-boot} option.
+
+The values that can be specified here depend on the machine type, but are
+the same that can be specified in the @code{-boot} command line option.
+
+@item nmi @var{cpu}
+Inject an NMI on the given CPU.
+
+@item migrate [-d] @var{uri}
+Migrate to @var{uri} (using -d to not wait for completion).
+
+@item migrate_cancel
+Cancel the current VM migration.
+
+@item migrate_set_speed @var{value}
+Set maximum speed to @var{value} (in bytes) for migrations.
+
+@item balloon @var{value}
+Request VM to change its memory allocation to @var{value} (in MB).
+
+@item set_link @var{name} [up|down]
+Set link @var{name} up or down.
+
@end table
@subsection Integer expressions
@@ -2858,6 +2990,22 @@ Three on-chip UARTs
A Linux 2.6 test image is available on the QEMU web site. More
information is available in the QEMU mailing-list archive.
+@c man begin OPTIONS
+
+The following options are specific to the ARM emulation:
+
+@table @option
+
+@item -semihosting
+Enable semihosting syscall emulation.
+
+On ARM this implements the "Angel" interface.
+
+Note that this allows guest direct access to the host filesystem,
+so should only be used with trusted guest OS.
+
+@end table
+
@node ColdFire System emulator
@section ColdFire System emulator
@@ -2884,6 +3032,22 @@ MCF5206 ColdFire V2 Microprocessor.
Two on-chip UARTs.
@end itemize
+@c man begin OPTIONS
+
+The following options are specific to the ARM emulation:
+
+@table @option
+
+@item -semihosting
+Enable semihosting syscall emulation.
+
+On M68K this implements the "ColdFire GDB" interface used by libgloss.
+
+Note that this allows guest direct access to the host filesystem,
+so should only be used with trusted guest OS.
+
+@end table
+
@node QEMU User space emulator
@chapter QEMU User space emulator
diff --git a/qemu-img.c b/qemu-img.c
index 555ab5fc4..0bcbada56 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -34,7 +34,7 @@
/* Default to cache=writeback as data integrity is not important for qemu-tcg. */
#define BRDV_O_FLAGS BDRV_O_CACHE_WB
-static void noreturn error(const char *fmt, ...)
+static void QEMU_NORETURN error(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
@@ -50,6 +50,7 @@ static void format_print(void *opaque, const char *name)
printf(" %s", name);
}
+/* Please keep in synch with qemu-img.texi */
static void help(void)
{
printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
@@ -61,7 +62,7 @@ static void help(void)
" commit [-f fmt] filename\n"
" convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n"
" info [-f fmt] filename\n"
- " snapshot [-l|-a snapshot|-c snapshot|-d snapshot] filename\n"
+ " snapshot [-l | -a snapshot | -c snapshot | -d snapshot] filename\n"
"\n"
"Command parameters:\n"
" 'filename' is a disk image filename\n"
@@ -72,22 +73,24 @@ static void help(void)
" content as the input's base image, however the path, image format, etc may\n"
" differ\n"
" 'fmt' is the disk image format. It is guessed automatically in most cases\n"
- " 'size' is the disk image size in kilobytes. Optional suffixes 'M' (megabyte)\n"
- " and 'G' (gigabyte) are supported\n"
+ " 'size' is the disk image size in kilobytes. Optional suffixes\n"
+ " 'M' (megabyte, 1024 * 1024) and 'G' (gigabyte, 1024 * 1024 * 1024) are"
+ " supported any @code{k} or @code{K} is ignored\n"
" 'output_filename' is the destination disk image filename\n"
" 'output_fmt' is the destination format\n"
" '-c' indicates that target image must be compressed (qcow format only)\n"
" '-e' indicates that the target image must be encrypted (qcow format only)\n"
" '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n"
+ " '-h' with or without a command shows this help and lists the supported formats\n"
"\n"
- " Parameters to snapshot subcommand:\n"
- " 'snapshot' is the name of the snapshot to create, apply or delete\n"
- " '-a' applies a snapshot (revert disk to saved state)\n"
- " '-c' creates a snapshot\n"
- " '-d' deletes a snapshot\n"
- " '-l' lists all snapshots in the given image\n"
+ "Parameters to snapshot subcommand:\n"
+ " 'snapshot' is the name of the snapshot to create, apply or delete\n"
+ " '-a' applies a snapshot (revert disk to saved state)\n"
+ " '-c' creates a snapshot\n"
+ " '-d' deletes a snapshot\n"
+ " '-l' lists all snapshots in the given image\n"
);
- printf("\nSupported format:");
+ printf("\nSupported formats:");
bdrv_iterate_format(format_print, NULL);
printf("\n");
exit(1);
@@ -727,6 +730,10 @@ static int img_info(int argc, char **argv)
if (bdrv_get_info(bs, &bdi) >= 0) {
if (bdi.cluster_size != 0)
printf("cluster_size: %d\n", bdi.cluster_size);
+ if (bdi.highest_alloc)
+ printf("highest_alloc: %" PRId64 "\n", bdi.highest_alloc);
+ if (bdi.num_free_bytes)
+ printf("num_free_bytes: %" PRId64 "\n", bdi.num_free_bytes);
}
bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
if (backing_filename[0] != '\0') {
diff --git a/qemu-img.texi b/qemu-img.texi
index 1c0504bcf..a40f84168 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -12,6 +12,7 @@ The following commands are supported:
@item commit [-f @var{fmt}] @var{filename}
@item convert [-c] [-e] [-6] [-f @var{fmt}] [-O @var{output_fmt}] [-B @var{output_base_image}] @var{filename} [@var{filename2} [...]] @var{output_filename}
@item info [-f @var{fmt}] @var{filename}
+@item snapshot [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename}
@end table
Command parameters:
@@ -59,7 +60,8 @@ CD-ROM images present for example in the Knoppix CD-ROMs.
@item size
is the disk image size in kilobytes. Optional suffixes @code{M}
-(megabyte) and @code{G} (gigabyte) are supported
+(megabyte, 1024 * 1024) and @code{G} (gigabyte, 1024 * 1024 * 1024)
+are supported and any @code{k} or @code{K} is ignored.
@item output_filename
is the destination disk image filename
@@ -73,6 +75,24 @@ indicates that target image must be compressed (qcow format only)
indicates that the target image must be encrypted (qcow format only)
@item -6
indicates that the target image must use compatibility level 6 (vmdk format only)
+@item -h
+with or without a command shows help and lists the supported formats
+@end table
+
+Parameters to snapshot subcommand:
+
+@table @option
+
+@item snapshot
+is the name of the snapshot to create, apply or delete
+@item -a
+applies a snapshot (revert disk to saved state)
+@item -c
+creates a snapshot
+@item -d
+deletes a snapshot
+@item -l
+lists all snapshots in the given image
@end table
Command description:
@@ -115,6 +135,10 @@ Give information about the disk image @var{filename}. Use it in
particular to know the size reserved on disk which can be different
from the displayed size. If VM snapshots are stored in the disk image,
they are displayed too.
+
+@item snapshot [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot} ] @var{filename}
+
+List, apply, create or delete snapshots in image @var{filename}.
@end table
@c man end
diff --git a/rules.mak b/rules.mak
index a4955da9f..a75a93bdc 100644
--- a/rules.mak
+++ b/rules.mak
@@ -1,19 +1,19 @@
%.o: %.c
- $(call quiet-command,$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<,CC $@)
+ $(call quiet-command,$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<," CC $(TARGET_DIR)$@")
%.o: %.S
- $(call quiet-command,$(CC) $(CPPFLAGS) -c -o $@ $<,AS $@)
+ $(call quiet-command,$(CC) $(CPPFLAGS) -c -o $@ $<," AS $(TARGET_DIR)$@")
%.o: %.m
- $(call quiet-command,$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<,OBJC $@)
+ $(call quiet-command,$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@")
-LINK = $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(LIBS),LINK $@)
+LINK = $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)," LINK $(TARGET_DIR)$@")
%$(EXESUF): %.o
$(LINK)
%.a:
- $(call quiet-command,rm -f $@ && $(AR) rcs $@ $^,AR $@)
+ $(call quiet-command,rm -f $@ && $(AR) rcs $@ $^," AR $(TARGET_DIR)$@")
-quiet-command = $(if $(V),$1,@echo $2 && $1)
+quiet-command = $(if $(V),$1,$(if $(2),@echo $2 && $1, @$1))
diff --git a/sdl.c b/sdl.c
index 17869926d..cfdf85237 100644
--- a/sdl.c
+++ b/sdl.c
@@ -93,7 +93,9 @@ static void sdl_resize(DisplayState *ds)
if (gui_noframe)
flags |= SDL_NOFRAME;
- real_screen = SDL_SetVideoMode(ds_get_width(ds), ds_get_height(ds), 0, flags);
+ width = ds_get_width(ds);
+ height = ds_get_height(ds);
+ real_screen = SDL_SetVideoMode(width, height, 0, flags);
if (!real_screen) {
fprintf(stderr, "Could not open SDL display\n");
exit(1);
@@ -276,7 +278,8 @@ static void sdl_grab_start(void)
{
if (guest_cursor) {
SDL_SetCursor(guest_sprite);
- SDL_WarpMouse(guest_x, guest_y);
+ if (!kbd_mouse_is_absolute() && !absolute_enabled)
+ SDL_WarpMouse(guest_x, guest_y);
} else
sdl_hide_cursor();
@@ -547,7 +550,8 @@ static void sdl_mouse_warp(int x, int y, int on)
sdl_show_cursor();
if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
SDL_SetCursor(guest_sprite);
- SDL_WarpMouse(x, y);
+ if (!kbd_mouse_is_absolute() && !absolute_enabled)
+ SDL_WarpMouse(x, y);
}
} else if (gui_grab)
sdl_hide_cursor();
diff --git a/slirp/COPYRIGHT b/slirp/COPYRIGHT
index 3f331ee07..1bc83d497 100644
--- a/slirp/COPYRIGHT
+++ b/slirp/COPYRIGHT
@@ -25,9 +25,6 @@ The copyright terms and conditions:
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- 3. All advertising materials mentioning features or use of this software
- must display the following acknowledgment:
- This product includes software developed by Danny Gasparovski.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
diff --git a/slirp/bootp.c b/slirp/bootp.c
index bf704abf5..ca177f40c 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -191,6 +191,8 @@ static void bootp_reply(struct bootp_t *bp)
rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
+ daddr.sin_addr.s_addr = 0xffffffffu;
+
q = rbp->bp_vend;
memcpy(q, rfc1533_cookie, 4);
q += 4;
diff --git a/slirp/cksum.c b/slirp/cksum.c
index b98373b51..34977ffc0 100644
--- a/slirp/cksum.c
+++ b/slirp/cksum.c
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/icmp_var.h b/slirp/icmp_var.h
index cd865b797..99d4c9e6b 100644
--- a/slirp/icmp_var.h
+++ b/slirp/icmp_var.h
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/ip.h b/slirp/ip.h
index 3079f90f9..7a7a9b943 100644
--- a/slirp/ip.h
+++ b/slirp/ip.h
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index b3d4348bb..4b27facf1 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h
index 5cd9f7ffc..03301313e 100644
--- a/slirp/ip_icmp.h
+++ b/slirp/ip_icmp.h
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/ip_input.c b/slirp/ip_input.c
index 116ee4565..e7f275613 100644
--- a/slirp/ip_input.c
+++ b/slirp/ip_input.c
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/ip_output.c b/slirp/ip_output.c
index a8a6067bd..9538db989 100644
--- a/slirp/ip_output.c
+++ b/slirp/ip_output.c
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/mbuf.h b/slirp/mbuf.h
index f9f213255..552737347 100644
--- a/slirp/mbuf.h
+++ b/slirp/mbuf.h
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/tcp.h b/slirp/tcp.h
index 11150766d..40570326c 100644
--- a/slirp/tcp.h
+++ b/slirp/tcp.h
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index f324adb1d..d7805b530 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index dba4ed7a5..4a7bdbcee 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index 497b98822..b30dffdc6 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c
index 244bad6a8..47f01bb96 100644
--- a/slirp/tcp_timer.c
+++ b/slirp/tcp_timer.c
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/tcp_timer.h b/slirp/tcp_timer.h
index f251846b4..791ee49df 100644
--- a/slirp/tcp_timer.h
+++ b/slirp/tcp_timer.h
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/tcp_var.h b/slirp/tcp_var.h
index 99d18fdf1..d4af1c8d0 100644
--- a/slirp/tcp_var.h
+++ b/slirp/tcp_var.h
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/tcpip.h b/slirp/tcpip.h
index b98cdb30d..7974ce3d5 100644
--- a/slirp/tcpip.h
+++ b/slirp/tcpip.h
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/udp.c b/slirp/udp.c
index c9926181a..8d3bdd2ce 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/slirp/udp.h b/slirp/udp.h
index e2ca54645..51a07a2fc 100644
--- a/slirp/udp.h
+++ b/slirp/udp.h
@@ -10,11 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
diff --git a/sysemu.h b/sysemu.h
index 64e621753..f971d1b86 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -12,16 +12,12 @@ extern uint8_t qemu_uuid[];
#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
typedef struct vm_change_state_entry VMChangeStateEntry;
-typedef void VMChangeStateHandler(void *opaque, int running);
-typedef void VMStopHandler(void *opaque, int reason);
+typedef void VMChangeStateHandler(void *opaque, int running, int reason);
VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
void *opaque);
void qemu_del_vm_change_state_handler(VMChangeStateEntry *e);
-int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque);
-void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque);
-
void vm_start(void);
void vm_stop(int reason);
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 81663c8f3..26fd6d017 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -159,6 +159,12 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
void cpu_reset(CPUARMState *env)
{
uint32_t id;
+
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
id = env->cp15.c0_cpuid;
memset(env, 0, offsetof(CPUARMState, breakpoints));
if (id)
diff --git a/target-cris/mmu.h b/target-cris/mmu.h
index 1b9aff15b..aca531a3e 100644
--- a/target-cris/mmu.h
+++ b/target-cris/mmu.h
@@ -10,6 +10,7 @@ struct cris_mmu_result_t
int bf_vec;
};
+void cris_mmu_init(CPUState *env);
void cris_mmu_flush_pid(CPUState *env, uint32_t pid);
int cris_mmu_translate(struct cris_mmu_result_t *res,
CPUState *env, uint32_t vaddr,
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 2ff6fe2d3..288262d7b 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -36,6 +36,7 @@
#include "disas.h"
#include "tcg-op.h"
#include "helper.h"
+#include "mmu.h"
#include "crisv32-decode.h"
#include "qemu-common.h"
@@ -3458,6 +3459,11 @@ CPUCRISState *cpu_cris_init (const char *cpu_model)
void cpu_reset (CPUCRISState *env)
{
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
memset(env, 0, offsetof(CPUCRISState, breakpoints));
tlb_flush(env, 1);
@@ -3466,6 +3472,7 @@ void cpu_reset (CPUCRISState *env)
/* start in user mode with interrupts enabled. */
env->pregs[PR_CCS] |= U_FLAG | I_FLAG;
#else
+ cris_mmu_init(env);
env->pregs[PR_CCS] = 0;
#endif
}
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 944e386c1..28c86e57e 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -251,6 +251,11 @@
#define MSR_IA32_APICBASE_ENABLE (1<<11)
#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
+#define MSR_MTRRcap 0xfe
+#define MSR_MTRRcap_VCNT 8
+#define MSR_MTRRcap_FIXRANGE_SUPPORT (1 << 8)
+#define MSR_MTRRcap_WC_SUPPORTED (1 << 10)
+
#define MSR_IA32_SYSENTER_CS 0x174
#define MSR_IA32_SYSENTER_ESP 0x175
#define MSR_IA32_SYSENTER_EIP 0x176
@@ -261,8 +266,25 @@
#define MSR_IA32_PERF_STATUS 0x198
+#define MSR_MTRRphysBase(reg) (0x200 + 2 * (reg))
+#define MSR_MTRRphysMask(reg) (0x200 + 2 * (reg) + 1)
+
+#define MSR_MTRRfix64K_00000 0x250
+#define MSR_MTRRfix16K_80000 0x258
+#define MSR_MTRRfix16K_A0000 0x259
+#define MSR_MTRRfix4K_C0000 0x268
+#define MSR_MTRRfix4K_C8000 0x269
+#define MSR_MTRRfix4K_D0000 0x26a
+#define MSR_MTRRfix4K_D8000 0x26b
+#define MSR_MTRRfix4K_E0000 0x26c
+#define MSR_MTRRfix4K_E8000 0x26d
+#define MSR_MTRRfix4K_F0000 0x26e
+#define MSR_MTRRfix4K_F8000 0x26f
+
#define MSR_PAT 0x277
+#define MSR_MTRRdefType 0x2ff
+
#define MSR_EFER 0xc0000080
#define MSR_EFER_SCE (1 << 0)
@@ -629,6 +651,14 @@ typedef struct CPUX86State {
uint32_t cpuid_ext3_features;
uint32_t cpuid_apic_id;
+ /* MTRRs */
+ uint64_t mtrr_fixed[11];
+ uint64_t mtrr_deftype;
+ struct {
+ uint64_t base;
+ uint64_t mask;
+ } mtrr_var[8];
+
#ifdef USE_KQEMU
int kqemu_enabled;
int last_io_time;
@@ -806,7 +836,7 @@ static inline int cpu_get_time_fast(void)
#define cpu_signal_handler cpu_x86_signal_handler
#define cpu_list x86_cpu_list
-#define CPU_SAVE_VERSION 7
+#define CPU_SAVE_VERSION 8
/* MMU modes definitions */
#define MMU_MODE0_SUFFIX _kernel
diff --git a/target-i386/exec.h b/target-i386/exec.h
index 268982381..b51667a1f 100644
--- a/target-i386/exec.h
+++ b/target-i386/exec.h
@@ -63,8 +63,8 @@ void do_interrupt(int intno, int is_int, int error_code,
target_ulong next_eip, int is_hw);
void do_interrupt_user(int intno, int is_int, int error_code,
target_ulong next_eip);
-void noreturn raise_exception_err(int exception_index, int error_code);
-void noreturn raise_exception(int exception_index);
+void QEMU_NORETURN raise_exception_err(int exception_index, int error_code);
+void QEMU_NORETURN raise_exception(int exception_index);
void do_smm_enter(void);
/* n must be a constant to be efficient */
diff --git a/target-i386/helper.c b/target-i386/helper.c
index cda03900f..121651d12 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -57,7 +57,7 @@ static void add_flagname_to_bitmaps(char *flagname, uint32_t *features,
};
static const char *ext2_feature_name[] = {
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mttr", "pge", "mca", "cmov",
+ "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mtrr", "pge", "mca", "cmov",
"pat", "pse36", NULL, NULL /* Linux mp */, "nx" /* Intel xd */, NULL, "mmxext", "mmx",
"fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp", NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
};
@@ -425,6 +425,11 @@ void cpu_reset(CPUX86State *env)
{
int i;
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, X86_DUMP_FPU | X86_DUMP_CCOP);
+ }
+
memset(env, 0, offsetof(CPUX86State, breakpoints));
tlb_flush(env, 1);
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index f87bf36e8..ac215eba2 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -446,10 +446,6 @@ static int kvm_get_sregs(CPUState *env)
}
}
env->hflags = (env->hflags & HFLAG_COPY_MASK) | hflags;
- env->cc_src = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
- env->df = 1 - (2 * ((env->eflags >> 10) & 1));
- env->cc_op = CC_OP_EFLAGS;
- env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
return 0;
}
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 71c075185..a0062863e 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -140,6 +140,15 @@ void cpu_save(QEMUFile *f, void *opaque)
qemu_put_be32s(f, &env->intercept_exceptions);
qemu_put_8s(f, &env->v_tpr);
+ /* MTRRs */
+ for(i = 0; i < 11; i++)
+ qemu_put_be64s(f, &env->mtrr_fixed[i]);
+ qemu_put_be64s(f, &env->mtrr_deftype);
+ for(i = 0; i < 8; i++) {
+ qemu_put_be64s(f, &env->mtrr_var[i].base);
+ qemu_put_be64s(f, &env->mtrr_var[i].mask);
+ }
+
if (kvm_enabled()) {
for (i = 0; i < sizeof(env->interrupt_bitmap)/8 ; i++) {
qemu_put_be64s(f, &env->interrupt_bitmap[i]);
@@ -182,7 +191,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
int32_t a20_mask;
if (version_id != 3 && version_id != 4 && version_id != 5
- && version_id != 6 && version_id != 7)
+ && version_id != 6 && version_id != 7 && version_id != 8)
return -EINVAL;
for(i = 0; i < CPU_NB_REGS; i++)
qemu_get_betls(f, &env->regs[i]);
@@ -315,6 +324,18 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_be32s(f, &env->intercept_exceptions);
qemu_get_8s(f, &env->v_tpr);
}
+
+ if (version_id >= 8) {
+ /* MTRRs */
+ for(i = 0; i < 11; i++)
+ qemu_get_be64s(f, &env->mtrr_fixed[i]);
+ qemu_get_be64s(f, &env->mtrr_deftype);
+ for(i = 0; i < 8; i++) {
+ qemu_get_be64s(f, &env->mtrr_var[i].base);
+ qemu_get_be64s(f, &env->mtrr_var[i].mask);
+ }
+ }
+
/* XXX: ensure compatiblity for halted bit ? */
/* XXX: compute redundant hflags bits */
env->hflags = hflags;
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index dcbc361a0..c2eda864a 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -1251,6 +1251,9 @@ void do_interrupt(int intno, int is_int, int error_code,
}
}
+/* This should come from sysemu.h - if we could include it here... */
+void qemu_system_reset_request(void);
+
/*
* Check nested exceptions and change to double or triple fault if
* needed. It should only be called, if this is not an interrupt.
@@ -1267,8 +1270,18 @@ static int check_exception(int intno, int *error_code)
qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
env->old_exception, intno);
- if (env->old_exception == EXCP08_DBLE)
- cpu_abort(env, "triple fault");
+#if !defined(CONFIG_USER_ONLY)
+ if (env->old_exception == EXCP08_DBLE) {
+ if (env->hflags & HF_SVMI_MASK)
+ helper_vmexit(SVM_EXIT_SHUTDOWN, 0); /* does not return */
+
+ if (qemu_loglevel_mask(CPU_LOG_RESET))
+ fprintf(logfile, "Triple fault\n");
+
+ qemu_system_reset_request();
+ return EXCP_HLT;
+ }
+#endif
if ((first_contributory && second_contributory)
|| (env->old_exception == EXCP0E_PAGE &&
@@ -1290,8 +1303,8 @@ static int check_exception(int intno, int *error_code)
* EIP value AFTER the interrupt instruction. It is only relevant if
* is_int is TRUE.
*/
-static void noreturn raise_interrupt(int intno, int is_int, int error_code,
- int next_eip_addend)
+static void QEMU_NORETURN raise_interrupt(int intno, int is_int, int error_code,
+ int next_eip_addend)
{
if (!is_int) {
helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code);
@@ -3050,6 +3063,46 @@ void helper_wrmsr(void)
env->kernelgsbase = val;
break;
#endif
+ case MSR_MTRRphysBase(0):
+ case MSR_MTRRphysBase(1):
+ case MSR_MTRRphysBase(2):
+ case MSR_MTRRphysBase(3):
+ case MSR_MTRRphysBase(4):
+ case MSR_MTRRphysBase(5):
+ case MSR_MTRRphysBase(6):
+ case MSR_MTRRphysBase(7):
+ env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base = val;
+ break;
+ case MSR_MTRRphysMask(0):
+ case MSR_MTRRphysMask(1):
+ case MSR_MTRRphysMask(2):
+ case MSR_MTRRphysMask(3):
+ case MSR_MTRRphysMask(4):
+ case MSR_MTRRphysMask(5):
+ case MSR_MTRRphysMask(6):
+ case MSR_MTRRphysMask(7):
+ env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask = val;
+ break;
+ case MSR_MTRRfix64K_00000:
+ env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix64K_00000] = val;
+ break;
+ case MSR_MTRRfix16K_80000:
+ case MSR_MTRRfix16K_A0000:
+ env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1] = val;
+ break;
+ case MSR_MTRRfix4K_C0000:
+ case MSR_MTRRfix4K_C8000:
+ case MSR_MTRRfix4K_D0000:
+ case MSR_MTRRfix4K_D8000:
+ case MSR_MTRRfix4K_E0000:
+ case MSR_MTRRfix4K_E8000:
+ case MSR_MTRRfix4K_F0000:
+ case MSR_MTRRfix4K_F8000:
+ env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3] = val;
+ break;
+ case MSR_MTRRdefType:
+ env->mtrr_deftype = val;
+ break;
default:
/* XXX: exception ? */
break;
@@ -3122,6 +3175,53 @@ void helper_rdmsr(void)
}
break;
#endif
+ case MSR_MTRRphysBase(0):
+ case MSR_MTRRphysBase(1):
+ case MSR_MTRRphysBase(2):
+ case MSR_MTRRphysBase(3):
+ case MSR_MTRRphysBase(4):
+ case MSR_MTRRphysBase(5):
+ case MSR_MTRRphysBase(6):
+ case MSR_MTRRphysBase(7):
+ val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base;
+ break;
+ case MSR_MTRRphysMask(0):
+ case MSR_MTRRphysMask(1):
+ case MSR_MTRRphysMask(2):
+ case MSR_MTRRphysMask(3):
+ case MSR_MTRRphysMask(4):
+ case MSR_MTRRphysMask(5):
+ case MSR_MTRRphysMask(6):
+ case MSR_MTRRphysMask(7):
+ val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask;
+ break;
+ case MSR_MTRRfix64K_00000:
+ val = env->mtrr_fixed[0];
+ break;
+ case MSR_MTRRfix16K_80000:
+ case MSR_MTRRfix16K_A0000:
+ val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1];
+ break;
+ case MSR_MTRRfix4K_C0000:
+ case MSR_MTRRfix4K_C8000:
+ case MSR_MTRRfix4K_D0000:
+ case MSR_MTRRfix4K_D8000:
+ case MSR_MTRRfix4K_E0000:
+ case MSR_MTRRfix4K_E8000:
+ case MSR_MTRRfix4K_F0000:
+ case MSR_MTRRfix4K_F8000:
+ val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3];
+ break;
+ case MSR_MTRRdefType:
+ val = env->mtrr_deftype;
+ break;
+ case MSR_MTRRcap:
+ if (env->cpuid_features & CPUID_MTRR)
+ val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | MSR_MTRRcap_WC_SUPPORTED;
+ else
+ /* XXX: exception ? */
+ val = 0;
+ break;
default:
/* XXX: exception ? */
val = 0;
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index ce5669346..076ea353c 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -143,6 +143,11 @@ static int cpu_m68k_set_model(CPUM68KState *env, const char *name)
void cpu_reset(CPUM68KState *env)
{
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
memset(env, 0, offsetof(CPUM68KState, breakpoints));
#if !defined (CONFIG_USER_ONLY)
env->sr = 0x2700;
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 692ea6dc0..b447b983f 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -8489,6 +8489,11 @@ CPUMIPSState *cpu_mips_init (const char *cpu_model)
void cpu_reset (CPUMIPSState *env)
{
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
memset(env, 0, offsetof(CPUMIPSState, breakpoints));
tlb_flush(env, 1);
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 2bf765092..3bd1d45c8 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -2709,10 +2709,14 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr)
void cpu_ppc_reset (void *opaque)
{
- CPUPPCState *env;
+ CPUPPCState *env = opaque;
target_ulong msr;
- env = opaque;
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
msr = (target_ulong)0;
if (0) {
/* XXX: find a suitable condition to enable the hypervisor mode */
diff --git a/target-ppc/kvm_ppc.c b/target-ppc/kvm_ppc.c
index f7ce52b04..82c0f4209 100644
--- a/target-ppc/kvm_ppc.c
+++ b/target-ppc/kvm_ppc.c
@@ -22,7 +22,7 @@ static QEMUTimer *kvmppc_timer;
static unsigned int kvmppc_timer_rate;
#ifdef HAVE_FDT
-static int kvmppc_read_host_property(const char *node_path, const char *prop,
+int kvmppc_read_host_property(const char *node_path, const char *prop,
void *val, size_t len)
{
char *path;
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index e536a881e..3792ef725 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -11,5 +11,7 @@
void kvmppc_init(void);
void kvmppc_fdt_update(void *fdt);
+int kvmppc_read_host_property(const char *node_path, const char *prop,
+ void *val, size_t len);
#endif /* __KVM_PPC_H__ */
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 5008a3a60..dffb2f3fc 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -25,6 +25,7 @@
#include "dis-asm.h"
#include "host-utils.h"
+#include "gdbstub.h"
//#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR
@@ -9271,6 +9272,124 @@ static void dump_ppc_insns (CPUPPCState *env)
}
#endif
+static int gdb_get_float_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+ stfq_p(mem_buf, env->fpr[n]);
+ return 8;
+ }
+ if (n == 32) {
+ /* FPSCR not implemented */
+ memset(mem_buf, 0, 4);
+ return 4;
+ }
+ return 0;
+}
+
+static int gdb_set_float_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+ env->fpr[n] = ldfq_p(mem_buf);
+ return 8;
+ }
+ if (n == 32) {
+ /* FPSCR not implemented */
+ return 4;
+ }
+ return 0;
+}
+
+static int gdb_get_avr_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+#ifdef WORDS_BIGENDIAN
+ stq_p(mem_buf, env->avr[n].u64[0]);
+ stq_p(mem_buf+8, env->avr[n].u64[1]);
+#else
+ stq_p(mem_buf, env->avr[n].u64[1]);
+ stq_p(mem_buf+8, env->avr[n].u64[0]);
+#endif
+ return 16;
+ }
+ if (n == 33) {
+ stl_p(mem_buf, env->vscr);
+ return 4;
+ }
+ if (n == 34) {
+ stl_p(mem_buf, (uint32_t)env->spr[SPR_VRSAVE]);
+ return 4;
+ }
+ return 0;
+}
+
+static int gdb_set_avr_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+#ifdef WORDS_BIGENDIAN
+ env->avr[n].u64[0] = ldq_p(mem_buf);
+ env->avr[n].u64[1] = ldq_p(mem_buf+8);
+#else
+ env->avr[n].u64[1] = ldq_p(mem_buf);
+ env->avr[n].u64[0] = ldq_p(mem_buf+8);
+#endif
+ return 16;
+ }
+ if (n == 33) {
+ env->vscr = ldl_p(mem_buf);
+ return 4;
+ }
+ if (n == 34) {
+ env->spr[SPR_VRSAVE] = (target_ulong)ldl_p(mem_buf);
+ return 4;
+ }
+ return 0;
+}
+
+static int gdb_get_spe_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+#if defined(TARGET_PPC64)
+ stl_p(mem_buf, env->gpr[n] >> 32);
+#else
+ stl_p(mem_buf, env->gprh[n]);
+#endif
+ return 4;
+ }
+ if (n == 33) {
+ stq_p(mem_buf, env->spe_acc);
+ return 8;
+ }
+ if (n == 34) {
+ /* SPEFSCR not implemented */
+ memset(mem_buf, 0, 4);
+ return 4;
+ }
+ return 0;
+}
+
+static int gdb_set_spe_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 32) {
+#if defined(TARGET_PPC64)
+ target_ulong lo = (uint32_t)env->gpr[n];
+ target_ulong hi = (target_ulong)ldl_p(mem_buf) << 32;
+ env->gpr[n] = lo | hi;
+#else
+ env->gprh[n] = ldl_p(mem_buf);
+#endif
+ return 4;
+ }
+ if (n == 33) {
+ env->spe_acc = ldq_p(mem_buf);
+ return 8;
+ }
+ if (n == 34) {
+ /* SPEFSCR not implemented */
+ return 4;
+ }
+ return 0;
+}
+
int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
{
env->msr_mask = def->msr_mask;
@@ -9283,6 +9402,20 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
if (create_ppc_opcodes(env, def) < 0)
return -1;
init_ppc_proc(env, def);
+
+ if (def->insns_flags & PPC_FLOAT) {
+ gdb_register_coprocessor(env, gdb_get_float_reg, gdb_set_float_reg,
+ 33, "power-fpu.xml", 0);
+ }
+ if (def->insns_flags & PPC_ALTIVEC) {
+ gdb_register_coprocessor(env, gdb_get_avr_reg, gdb_set_avr_reg,
+ 34, "power-altivec.xml", 0);
+ }
+ if ((def->insns_flags & PPC_SPE) | (def->insns_flags & PPC_SPEFPU)) {
+ gdb_register_coprocessor(env, gdb_get_spe_reg, gdb_set_spe_reg,
+ 34, "power-spe.xml", 0);
+ }
+
#if defined(PPC_DUMP_CPU)
{
const char *mmu_model, *excp_model, *bus_model;
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index 9137e3801..6c9dff591 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -184,6 +184,11 @@ void cpu_dump_state(CPUState * env, FILE * f,
static void cpu_sh4_reset(CPUSH4State * env)
{
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
#if defined(CONFIG_USER_ONLY)
env->sr = 0;
#else
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index d34b83763..a27588085 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -639,6 +639,11 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
void cpu_reset(CPUSPARCState *env)
{
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
tlb_flush(env, 1);
env->cwp = 0;
env->wim = 1;
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index 40cf01c34..60563f736 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -109,7 +109,9 @@ static const int tcg_target_reg_alloc_order[] = {
TCG_REG_R11,
#endif
TCG_REG_R12,
+#ifndef __linux__
TCG_REG_R13,
+#endif
TCG_REG_R0,
TCG_REG_R1,
TCG_REG_R2,
@@ -1528,6 +1530,9 @@ void tcg_target_init(TCGContext *s)
#ifndef __APPLE__
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2);
#endif
+#ifdef __linux__
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13);
+#endif
tcg_add_target_add_op_defs(ppc_op_defs);
}
diff --git a/vl.c b/vl.c
index 7db9c1253..710c41091 100644
--- a/vl.c
+++ b/vl.c
@@ -165,11 +165,7 @@
# define LOG_IOPORT(...) do { } while (0)
#endif
-#ifdef TARGET_PPC
-#define DEFAULT_RAM_SIZE 144
-#else
#define DEFAULT_RAM_SIZE 128
-#endif
/* Max number of USB devices that can be specified on the commandline. */
#define MAX_USB_CMDLINE 8
@@ -2519,8 +2515,8 @@ int drive_init(struct drive_opt *arg, int snapshot,
onerror = BLOCK_ERR_REPORT;
if (get_param_value(buf, sizeof(serial), "werror", str)) {
- if (type != IF_IDE) {
- fprintf(stderr, "werror is supported only by IDE\n");
+ if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO) {
+ fprintf(stderr, "werror is no supported by this format\n");
return -1;
}
if (!strcmp(buf, "ignore"))
@@ -3536,37 +3532,21 @@ void qemu_del_vm_change_state_handler(VMChangeStateEntry *e)
qemu_free (e);
}
-static void vm_state_notify(int running)
+static void vm_state_notify(int running, int reason)
{
VMChangeStateEntry *e;
for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
- e->cb(e->opaque, running);
+ e->cb(e->opaque, running, reason);
}
}
-/* XXX: support several handlers */
-static VMStopHandler *vm_stop_cb;
-static void *vm_stop_opaque;
-
-int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque)
-{
- vm_stop_cb = cb;
- vm_stop_opaque = opaque;
- return 0;
-}
-
-void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque)
-{
- vm_stop_cb = NULL;
-}
-
void vm_start(void)
{
if (!vm_running) {
cpu_enable_ticks();
vm_running = 1;
- vm_state_notify(1);
+ vm_state_notify(1, 0);
qemu_rearm_alarm_timer(alarm_timer);
}
}
@@ -3576,12 +3556,7 @@ void vm_stop(int reason)
if (vm_running) {
cpu_disable_ticks();
vm_running = 0;
- if (reason != 0) {
- if (vm_stop_cb) {
- vm_stop_cb(vm_stop_opaque, reason);
- }
- }
- vm_state_notify(0);
+ vm_state_notify(0, reason);
}
}
@@ -3996,6 +3971,8 @@ static int main_loop(void)
static void help(int exitcode)
{
+ /* Please keep in synch with QEMU_OPTION_ enums, qemu_options[]
+ and qemu-doc.texi */
printf("QEMU PC emulator version " QEMU_VERSION " (" KVM_VERSION ")"
", Copyright (c) 2003-2008 Fabrice Bellard\n"
"usage: %s [options] [disk_image]\n"
@@ -4003,8 +3980,10 @@ static void help(int exitcode)
"'disk_image' is a raw hard image image for IDE hard disk 0\n"
"\n"
"Standard options:\n"
+ "-h or -help display this help and exit\n"
"-M machine select emulated machine (-M ? for list)\n"
"-cpu cpu select CPU (-cpu ? for list)\n"
+ "-smp n set the number of CPUs to 'n' [default=1]\n"
"-fda/-fdb file use 'file' as floppy disk 0/1 image\n"
"-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n"
"-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n"
@@ -4019,19 +3998,7 @@ static void help(int exitcode)
"-pflash file use 'file' as a parallel flash image\n"
"-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n"
"-snapshot write to temporary files instead of disk image files\n"
-#ifdef CONFIG_SDL
- "-no-frame open SDL window without a frame and window decorations\n"
- "-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n"
- "-no-quit disable SDL window close capability\n"
- "-sdl enable SDL\n"
-#endif
-#ifdef TARGET_I386
- "-no-fd-bootchk disable boot signature checking for floppy disks\n"
-#endif
"-m megs set virtual RAM size to megs MB [default=%d]\n"
- "-smp n set the number of CPUs to 'n' [default=1]\n"
- "-nographic disable graphical output and redirect serial I/Os to console\n"
- "-portrait rotate graphical output 90 deg left (only PXA LCD)\n"
#ifndef _WIN32
"-k language use keyboard layout (for example \"fr\" for French)\n"
#endif
@@ -4042,19 +4009,31 @@ static void help(int exitcode)
" use -soundhw ? to get the list of supported cards\n"
" use -soundhw all to enable all of them\n"
#endif
+ "-usb enable the USB driver (will be the default soon)\n"
+ "-usbdevice name add the host or guest USB device 'name'\n"
+ "-name string set the name of the guest\n"
+ "-uuid %%08x-%%04x-%%04x-%%04x-%%012x\n"
+ " specify machine UUID\n"
+ "\n"
+ "Display options:\n"
+ "-nographic disable graphical output and redirect serial I/Os to console\n"
+#ifdef CONFIG_CURSES
+ "-curses use a curses/ncurses interface instead of SDL\n"
+#endif
+#ifdef CONFIG_SDL
+ "-no-frame open SDL window without a frame and window decorations\n"
+ "-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n"
+ "-no-quit disable SDL window close capability\n"
+ "-sdl enable SDL\n"
+#endif
+ "-portrait rotate graphical output 90 deg left (only PXA LCD)\n"
"-vga [std|cirrus|vmware|none]\n"
" select video card type\n"
- "-localtime set the real time clock to local time [default=utc]\n"
"-full-screen start in full screen\n"
-#ifdef TARGET_I386
- "-win2k-hack use it when installing Windows 2000 to avoid a disk full bug\n"
- "-rtc-td-hack use it to fix time drift in Windows ACPI HAL\n"
-#endif
- "-usb enable the USB driver (will be the default soon)\n"
- "-usbdevice name add the host or guest USB device 'name'\n"
#if defined(TARGET_PPC) || defined(TARGET_SPARC)
"-g WxH[xDEPTH] Set the initial graphical resolution and depth\n"
#endif
+ "-vnc display start a VNC server on display\n"
#ifdef TARGET_IA64
"-nvram file use 'file' to save or load nvram image\n"
#endif
@@ -4093,17 +4072,6 @@ static void help(int exitcode)
#endif
"-net none use it alone to have zero network devices; if no -net option\n"
" is provided, the default is '-net nic -net user'\n"
- "\n"
- "-bt hci,null Dumb bluetooth HCI - doesn't respond to commands\n"
- "-bt hci,host[:id]\n"
- " Use host's HCI with the given name\n"
- "-bt hci[,vlan=n]\n"
- " Emulate a standard HCI in virtual scatternet 'n'\n"
- "-bt vhci[,vlan=n]\n"
- " Add host computer to virtual scatternet 'n' using VHCI\n"
- "-bt device:dev[,vlan=n]\n"
- " Emulate a bluetooth device 'dev' in scatternet 'n'\n"
- "\n"
#ifdef CONFIG_SLIRP
"-tftp dir allow tftp access to files in dir [-net user]\n"
"-bootp file advertise file in BOOTP replies\n"
@@ -4114,23 +4082,44 @@ static void help(int exitcode)
" redirect TCP or UDP connections from host to guest [-net user]\n"
#endif
"\n"
+ "-bt hci,null dumb bluetooth HCI - doesn't respond to commands\n"
+ "-bt hci,host[:id]\n"
+ " use host's HCI with the given name\n"
+ "-bt hci[,vlan=n]\n"
+ " emulate a standard HCI in virtual scatternet 'n'\n"
+ "-bt vhci[,vlan=n]\n"
+ " add host computer to virtual scatternet 'n' using VHCI\n"
+ "-bt device:dev[,vlan=n]\n"
+ " emulate a bluetooth device 'dev' in scatternet 'n'\n"
+ "\n"
+#ifdef TARGET_I386
+ "\n"
+ "i386 target only:\n"
+ "-win2k-hack use it when installing Windows 2000 to avoid a disk full bug\n"
+ "-rtc-td-hack use it to fix time drift in Windows ACPI HAL\n"
+ "-no-fd-bootchk disable boot signature checking for floppy disks\n"
+ "-no-acpi disable ACPI\n"
+ "-no-hpet disable HPET\n"
+#endif
"Linux boot specific:\n"
"-kernel bzImage use 'bzImage' as kernel image\n"
"-append cmdline use 'cmdline' as kernel command line\n"
"-initrd file use 'file' as initial ram disk\n"
"\n"
"Debug/Expert options:\n"
- "-monitor dev redirect the monitor to char device 'dev'\n"
"-serial dev redirect the serial port to char device 'dev'\n"
"-parallel dev redirect the parallel port to char device 'dev'\n"
- "-pidfile file Write PID to 'file'\n"
+ "-monitor dev redirect the monitor to char device 'dev'\n"
+ "-pidfile file write PID to 'file'\n"
"-S freeze CPU at startup (use 'c' to start execution)\n"
"-s wait gdb connection to port\n"
"-p port set gdb connection port [default=%s]\n"
"-d item1,... output log to %s (use -d ? for a list of log items)\n"
- "-hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS\n"
+ "-hdachs c,h,s[,t]\n"
+ " force hard disk 0 physical geometry and the optional BIOS\n"
" translation (t=none or lba) (usually qemu can guess them)\n"
"-L path set the directory for the BIOS, VGA BIOS and keymaps\n"
+ "-bios file set the filename for the BIOS\n"
#ifdef USE_KQEMU
"-kernel-kqemu enable KQEMU full virtualization (default is user mode only)\n"
"-no-kqemu disable KQEMU kernel module usage\n"
@@ -4153,17 +4142,10 @@ static void help(int exitcode)
" 'string' is used in log output.\n"
#endif
#endif
-#ifdef TARGET_I386
- "-no-acpi disable ACPI\n"
- "-no-hpet disable HPET\n"
-#endif
-#ifdef CONFIG_CURSES
- "-curses use a curses/ncurses interface instead of SDL\n"
-#endif
"-no-reboot exit instead of rebooting\n"
"-no-shutdown stop before shutdown\n"
- "-loadvm [tag|id] start right away with a saved state (loadvm in monitor)\n"
- "-vnc display start a VNC server on display\n"
+ "-loadvm [tag|id]\n"
+ " start right away with a saved state (loadvm in monitor)\n"
#ifndef _WIN32
"-daemonize daemonize QEMU after initializing\n"
#endif
@@ -4171,14 +4153,28 @@ static void help(int exitcode)
"-kvm-shadow-memory megs set the amount of shadow pages to be allocated\n"
"-mem-path set the path to hugetlbfs/tmpfs mounted directory, also enables allocation of guest memory with huge pages\n"
"-option-rom rom load a file, rom, into the option ROM space\n"
-#ifdef TARGET_SPARC
- "-prom-env variable=value set OpenBIOS nvram variables\n"
+#if defined(TARGET_SPARC) || defined(TARGET_PPC)
+ "-prom-env variable=value\n"
+ " set OpenBIOS nvram variables\n"
#endif
"-clock force the use of the given methods for timer alarm.\n"
" To see what timers are available use -clock ?\n"
+ "-localtime set the real time clock to local time [default=utc]\n"
"-startdate select initial date of the clock\n"
"-icount [N|auto]\n"
- " Enable virtual instruction counter with 2^N clock ticks per instruction\n"
+ " enable virtual instruction counter with 2^N clock ticks per instruction\n"
+ "-echr chr set terminal escape character instead of ctrl-a\n"
+ "-virtioconsole c\n"
+ " set virtio console\n"
+ "-show-cursor show cursor\n"
+#if defined(TARGET_ARM) || defined(TARGET_M68K)
+ "-semihosting semihosting mode\n"
+#endif
+#if defined(TARGET_ARM)
+ "-old-param old param mode\n"
+#endif
+ "-tb-size n set TB size\n"
+ "-incoming p prepare for incoming migration, listen on port p\n"
"\n"
"During emulation, the following keys are useful:\n"
"ctrl-alt-f toggle full screen\n"
@@ -4201,34 +4197,49 @@ static void help(int exitcode)
#define HAS_ARG 0x0001
enum {
+ /* Please keep in synch with help, qemu_options[] and
+ qemu-doc.texi */
+ /* Standard options: */
QEMU_OPTION_h,
-
QEMU_OPTION_M,
QEMU_OPTION_cpu,
+ QEMU_OPTION_smp,
QEMU_OPTION_fda,
QEMU_OPTION_fdb,
QEMU_OPTION_hda,
QEMU_OPTION_hdb,
QEMU_OPTION_hdc,
QEMU_OPTION_hdd,
- QEMU_OPTION_drive,
QEMU_OPTION_cdrom,
+ QEMU_OPTION_drive,
QEMU_OPTION_mtdblock,
QEMU_OPTION_sd,
QEMU_OPTION_pflash,
QEMU_OPTION_boot,
QEMU_OPTION_snapshot,
-#ifdef TARGET_I386
- QEMU_OPTION_no_fd_bootchk,
-#endif
QEMU_OPTION_m,
- QEMU_OPTION_nographic,
- QEMU_OPTION_portrait,
-#ifdef HAS_AUDIO
+ QEMU_OPTION_k,
QEMU_OPTION_audio_help,
QEMU_OPTION_soundhw,
-#endif
+ QEMU_OPTION_usb,
+ QEMU_OPTION_usbdevice,
+ QEMU_OPTION_name,
+ QEMU_OPTION_uuid,
+
+ /* Display options: */
+ QEMU_OPTION_nographic,
+ QEMU_OPTION_curses,
+ QEMU_OPTION_no_frame,
+ QEMU_OPTION_alt_grab,
+ QEMU_OPTION_no_quit,
+ QEMU_OPTION_sdl,
+ QEMU_OPTION_portrait,
+ QEMU_OPTION_vga,
+ QEMU_OPTION_full_screen,
+ QEMU_OPTION_g,
+ QEMU_OPTION_vnc,
+ /* Network options: */
QEMU_OPTION_net,
QEMU_OPTION_tftp,
QEMU_OPTION_bootp,
@@ -4236,10 +4247,23 @@ enum {
QEMU_OPTION_redir,
QEMU_OPTION_bt,
+ /* i386 target only: */
+ QEMU_OPTION_win2k_hack,
+ QEMU_OPTION_rtc_td_hack,
+ QEMU_OPTION_no_fd_bootchk,
+ QEMU_OPTION_no_acpi,
+ QEMU_OPTION_no_hpet,
+
+ /* Linux boot specific: */
QEMU_OPTION_kernel,
QEMU_OPTION_append,
QEMU_OPTION_initrd,
+ /* Debug/Expert options: */
+ QEMU_OPTION_serial,
+ QEMU_OPTION_parallel,
+ QEMU_OPTION_monitor,
+ QEMU_OPTION_pidfile,
QEMU_OPTION_S,
QEMU_OPTION_s,
QEMU_OPTION_p,
@@ -4247,35 +4271,10 @@ enum {
QEMU_OPTION_hdachs,
QEMU_OPTION_L,
QEMU_OPTION_bios,
- QEMU_OPTION_k,
- QEMU_OPTION_localtime,
- QEMU_OPTION_g,
- QEMU_OPTION_vga,
- QEMU_OPTION_echr,
- QEMU_OPTION_monitor,
- QEMU_OPTION_serial,
- QEMU_OPTION_virtiocon,
- QEMU_OPTION_parallel,
- QEMU_OPTION_loadvm,
- QEMU_OPTION_full_screen,
- QEMU_OPTION_no_frame,
- QEMU_OPTION_alt_grab,
- QEMU_OPTION_no_quit,
- QEMU_OPTION_sdl,
- QEMU_OPTION_pidfile,
- QEMU_OPTION_no_kqemu,
QEMU_OPTION_kernel_kqemu,
+ QEMU_OPTION_no_kqemu,
QEMU_OPTION_enable_kvm,
QEMU_OPTION_enable_nesting,
- QEMU_OPTION_win2k_hack,
- QEMU_OPTION_rtc_td_hack,
- QEMU_OPTION_usb,
- QEMU_OPTION_usbdevice,
- QEMU_OPTION_smp,
- QEMU_OPTION_vnc,
- QEMU_OPTION_no_acpi,
- QEMU_OPTION_no_hpet,
- QEMU_OPTION_curses,
QEMU_OPTION_no_kvm,
QEMU_OPTION_no_kvm_irqchip,
QEMU_OPTION_no_kvm_pit,
@@ -4285,20 +4284,22 @@ enum {
#endif
QEMU_OPTION_no_reboot,
QEMU_OPTION_no_shutdown,
- QEMU_OPTION_show_cursor,
+ QEMU_OPTION_loadvm,
QEMU_OPTION_daemonize,
QEMU_OPTION_option_rom,
- QEMU_OPTION_semihosting,
QEMU_OPTION_cpu_vendor,
- QEMU_OPTION_name,
QEMU_OPTION_nvram,
QEMU_OPTION_prom_env,
- QEMU_OPTION_old_param,
QEMU_OPTION_clock,
+ QEMU_OPTION_localtime,
QEMU_OPTION_startdate,
- QEMU_OPTION_tb_size,
QEMU_OPTION_icount,
- QEMU_OPTION_uuid,
+ QEMU_OPTION_echr,
+ QEMU_OPTION_virtiocon,
+ QEMU_OPTION_show_cursor,
+ QEMU_OPTION_semihosting,
+ QEMU_OPTION_old_param,
+ QEMU_OPTION_tb_size,
QEMU_OPTION_incoming,
QEMU_OPTION_tdf,
QEMU_OPTION_kvm_shadow_memory,
@@ -4312,36 +4313,60 @@ typedef struct QEMUOption {
} QEMUOption;
static const QEMUOption qemu_options[] = {
+ /* Please keep in synch with help, QEMU_OPTION_ enums, and
+ qemu-doc.texi */
+ /* Standard options: */
{ "h", 0, QEMU_OPTION_h },
{ "help", 0, QEMU_OPTION_h },
-
{ "M", HAS_ARG, QEMU_OPTION_M },
{ "cpu", HAS_ARG, QEMU_OPTION_cpu },
+ { "smp", HAS_ARG, QEMU_OPTION_smp },
{ "fda", HAS_ARG, QEMU_OPTION_fda },
{ "fdb", HAS_ARG, QEMU_OPTION_fdb },
{ "hda", HAS_ARG, QEMU_OPTION_hda },
{ "hdb", HAS_ARG, QEMU_OPTION_hdb },
{ "hdc", HAS_ARG, QEMU_OPTION_hdc },
{ "hdd", HAS_ARG, QEMU_OPTION_hdd },
- { "drive", HAS_ARG, QEMU_OPTION_drive },
{ "cdrom", HAS_ARG, QEMU_OPTION_cdrom },
+ { "drive", HAS_ARG, QEMU_OPTION_drive },
{ "mtdblock", HAS_ARG, QEMU_OPTION_mtdblock },
{ "sd", HAS_ARG, QEMU_OPTION_sd },
{ "pflash", HAS_ARG, QEMU_OPTION_pflash },
{ "boot", HAS_ARG, QEMU_OPTION_boot },
{ "snapshot", 0, QEMU_OPTION_snapshot },
-#ifdef TARGET_I386
- { "no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk },
-#endif
{ "m", HAS_ARG, QEMU_OPTION_m },
- { "nographic", 0, QEMU_OPTION_nographic },
- { "portrait", 0, QEMU_OPTION_portrait },
+#ifndef _WIN32
{ "k", HAS_ARG, QEMU_OPTION_k },
+#endif
#ifdef HAS_AUDIO
{ "audio-help", 0, QEMU_OPTION_audio_help },
{ "soundhw", HAS_ARG, QEMU_OPTION_soundhw },
#endif
+ { "usb", 0, QEMU_OPTION_usb },
+ { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice },
+ { "name", HAS_ARG, QEMU_OPTION_name },
+ { "uuid", HAS_ARG, QEMU_OPTION_uuid },
+
+ /* Display options: */
+ { "nographic", 0, QEMU_OPTION_nographic },
+#ifdef CONFIG_CURSES
+ { "curses", 0, QEMU_OPTION_curses },
+#endif
+#ifdef CONFIG_SDL
+ { "no-frame", 0, QEMU_OPTION_no_frame },
+ { "alt-grab", 0, QEMU_OPTION_alt_grab },
+ { "no-quit", 0, QEMU_OPTION_no_quit },
+ { "sdl", 0, QEMU_OPTION_sdl },
+#endif
+ { "portrait", 0, QEMU_OPTION_portrait },
+ { "vga", HAS_ARG, QEMU_OPTION_vga },
+ { "full-screen", 0, QEMU_OPTION_full_screen },
+#if defined(TARGET_PPC) || defined(TARGET_SPARC)
+ { "g", 1, QEMU_OPTION_g },
+#endif
+ { "vnc", HAS_ARG, QEMU_OPTION_vnc },
+ /* Network options: */
{ "net", HAS_ARG, QEMU_OPTION_net},
#ifdef CONFIG_SLIRP
{ "tftp", HAS_ARG, QEMU_OPTION_tftp },
@@ -4352,11 +4377,25 @@ static const QEMUOption qemu_options[] = {
{ "redir", HAS_ARG, QEMU_OPTION_redir },
#endif
{ "bt", HAS_ARG, QEMU_OPTION_bt },
+#ifdef TARGET_I386
+ /* i386 target only: */
+ { "win2k-hack", 0, QEMU_OPTION_win2k_hack },
+ { "rtc-td-hack", 0, QEMU_OPTION_rtc_td_hack },
+ { "no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk },
+ { "no-acpi", 0, QEMU_OPTION_no_acpi },
+ { "no-hpet", 0, QEMU_OPTION_no_hpet },
+#endif
+ /* Linux boot specific: */
{ "kernel", HAS_ARG, QEMU_OPTION_kernel },
{ "append", HAS_ARG, QEMU_OPTION_append },
{ "initrd", HAS_ARG, QEMU_OPTION_initrd },
+ /* Debug/Expert options: */
+ { "serial", HAS_ARG, QEMU_OPTION_serial },
+ { "parallel", HAS_ARG, QEMU_OPTION_parallel },
+ { "monitor", HAS_ARG, QEMU_OPTION_monitor },
+ { "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
{ "S", 0, QEMU_OPTION_S },
{ "s", 0, QEMU_OPTION_s },
{ "p", HAS_ARG, QEMU_OPTION_p },
@@ -4365,8 +4404,8 @@ static const QEMUOption qemu_options[] = {
{ "L", HAS_ARG, QEMU_OPTION_L },
{ "bios", HAS_ARG, QEMU_OPTION_bios },
#ifdef USE_KQEMU
- { "no-kqemu", 0, QEMU_OPTION_no_kqemu },
{ "kernel-kqemu", 0, QEMU_OPTION_kernel_kqemu },
+ { "no-kqemu", 0, QEMU_OPTION_no_kqemu },
#endif
#ifdef CONFIG_KVM
{ "enable-kvm", 0, QEMU_OPTION_enable_kvm },
@@ -4383,63 +4422,32 @@ static const QEMUOption qemu_options[] = {
{ "pcidevice", HAS_ARG, QEMU_OPTION_pcidevice },
#endif
#endif
-#if defined(TARGET_PPC) || defined(TARGET_SPARC)
- { "g", 1, QEMU_OPTION_g },
+ { "no-reboot", 0, QEMU_OPTION_no_reboot },
+ { "no-shutdown", 0, QEMU_OPTION_no_shutdown },
+ { "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
+ { "daemonize", 0, QEMU_OPTION_daemonize },
+ { "option-rom", HAS_ARG, QEMU_OPTION_option_rom },
+#if defined(TARGET_SPARC) || defined(TARGET_PPC)
+ { "prom-env", HAS_ARG, QEMU_OPTION_prom_env },
#endif
+ { "clock", HAS_ARG, QEMU_OPTION_clock },
{ "localtime", 0, QEMU_OPTION_localtime },
- { "vga", HAS_ARG, QEMU_OPTION_vga },
+ { "startdate", HAS_ARG, QEMU_OPTION_startdate },
+ { "icount", HAS_ARG, QEMU_OPTION_icount },
{ "echr", HAS_ARG, QEMU_OPTION_echr },
- { "monitor", HAS_ARG, QEMU_OPTION_monitor },
- { "serial", HAS_ARG, QEMU_OPTION_serial },
{ "virtioconsole", HAS_ARG, QEMU_OPTION_virtiocon },
- { "parallel", HAS_ARG, QEMU_OPTION_parallel },
- { "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
- { "incoming", 1, QEMU_OPTION_incoming },
- { "full-screen", 0, QEMU_OPTION_full_screen },
-#ifdef CONFIG_SDL
- { "no-frame", 0, QEMU_OPTION_no_frame },
- { "alt-grab", 0, QEMU_OPTION_alt_grab },
- { "no-quit", 0, QEMU_OPTION_no_quit },
- { "sdl", 0, QEMU_OPTION_sdl },
-#endif
- { "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
- { "win2k-hack", 0, QEMU_OPTION_win2k_hack },
- { "rtc-td-hack", 0, QEMU_OPTION_rtc_td_hack },
- { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice },
- { "smp", HAS_ARG, QEMU_OPTION_smp },
- { "vnc", HAS_ARG, QEMU_OPTION_vnc },
-#ifdef CONFIG_CURSES
- { "curses", 0, QEMU_OPTION_curses },
-#endif
- { "uuid", HAS_ARG, QEMU_OPTION_uuid },
-
- /* temporary options */
- { "usb", 0, QEMU_OPTION_usb },
- { "no-acpi", 0, QEMU_OPTION_no_acpi },
- { "no-hpet", 0, QEMU_OPTION_no_hpet },
- { "no-reboot", 0, QEMU_OPTION_no_reboot },
- { "no-shutdown", 0, QEMU_OPTION_no_shutdown },
{ "show-cursor", 0, QEMU_OPTION_show_cursor },
- { "daemonize", 0, QEMU_OPTION_daemonize },
- { "option-rom", HAS_ARG, QEMU_OPTION_option_rom },
#if defined(TARGET_ARM) || defined(TARGET_M68K)
{ "semihosting", 0, QEMU_OPTION_semihosting },
#endif
{ "tdf", 0, QEMU_OPTION_tdf }, /* enable time drift fix */
{ "kvm-shadow-memory", HAS_ARG, QEMU_OPTION_kvm_shadow_memory },
- { "name", HAS_ARG, QEMU_OPTION_name },
{ "nvram", HAS_ARG, QEMU_OPTION_nvram },
-#if defined(TARGET_SPARC) || defined(TARGET_PPC)
- { "prom-env", HAS_ARG, QEMU_OPTION_prom_env },
-#endif
{ "cpu-vendor", HAS_ARG, QEMU_OPTION_cpu_vendor },
#if defined(TARGET_ARM)
{ "old-param", 0, QEMU_OPTION_old_param },
#endif
- { "clock", HAS_ARG, QEMU_OPTION_clock },
- { "startdate", HAS_ARG, QEMU_OPTION_startdate },
{ "tb-size", HAS_ARG, QEMU_OPTION_tb_size },
- { "icount", HAS_ARG, QEMU_OPTION_icount },
{ "incoming", HAS_ARG, QEMU_OPTION_incoming },
{ "mem-path", HAS_ARG, QEMU_OPTION_mempath },
{ NULL },
@@ -5953,10 +5961,11 @@ int main(int argc, char **argv, char **envp)
if (vnc_display_open(ds, vnc_display) < 0)
exit(1);
}
- if (sdl || !vnc_display)
#if defined(CONFIG_SDL)
+ if (sdl || !vnc_display)
sdl_display_init(ds, full_screen, no_frame);
#elif defined(CONFIG_COCOA)
+ if (sdl || !vnc_display)
cocoa_display_init(ds, full_screen);
#endif
}
diff --git a/vnc.c b/vnc.c
index 17ea9a20e..2b3a6eb7d 100644
--- a/vnc.c
+++ b/vnc.c
@@ -56,6 +56,12 @@ static void vnc_debug_gnutls_log(int level, const char* str) {
#define VNC_DEBUG(fmt, ...) do { } while (0)
#endif
+#define count_bits(c, v) { \
+ for (c = 0; v; v >>= 1) \
+ { \
+ c += v & 1; \
+ } \
+}
typedef struct Buffer
{
@@ -329,12 +335,12 @@ static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
{
uint8_t r, g, b;
- r = ((v >> vs->serverds.pf.rshift) & vs->serverds.pf.rmax) * (vs->clientds.pf.rmax + 1) /
- (vs->serverds.pf.rmax + 1);
- g = ((v >> vs->serverds.pf.gshift) & vs->serverds.pf.gmax) * (vs->clientds.pf.gmax + 1) /
- (vs->serverds.pf.gmax + 1);
- b = ((v >> vs->serverds.pf.bshift) & vs->serverds.pf.bmax) * (vs->clientds.pf.bmax + 1) /
- (vs->serverds.pf.bmax + 1);
+ r = ((((v & vs->serverds.pf.rmask) >> vs->serverds.pf.rshift) << vs->clientds.pf.rbits) >>
+ vs->serverds.pf.rbits);
+ g = ((((v & vs->serverds.pf.gmask) >> vs->serverds.pf.gshift) << vs->clientds.pf.gbits) >>
+ vs->serverds.pf.gbits);
+ b = ((((v & vs->serverds.pf.bmask) >> vs->serverds.pf.bshift) << vs->clientds.pf.bbits) >>
+ vs->serverds.pf.bbits);
v = (r << vs->clientds.pf.rshift) |
(g << vs->clientds.pf.gshift) |
(b << vs->clientds.pf.bshift);
@@ -1272,12 +1278,15 @@ static void set_pixel_format(VncState *vs,
vs->clientds = vs->serverds;
vs->clientds.pf.rmax = red_max;
+ count_bits(vs->clientds.pf.rbits, red_max);
vs->clientds.pf.rshift = red_shift;
vs->clientds.pf.rmask = red_max << red_shift;
vs->clientds.pf.gmax = green_max;
+ count_bits(vs->clientds.pf.gbits, green_max);
vs->clientds.pf.gshift = green_shift;
vs->clientds.pf.gmask = green_max << green_shift;
vs->clientds.pf.bmax = blue_max;
+ count_bits(vs->clientds.pf.bbits, blue_max);
vs->clientds.pf.bshift = blue_shift;
vs->clientds.pf.bmask = blue_max << blue_shift;
vs->clientds.pf.bits_per_pixel = bits_per_pixel;
@@ -2106,6 +2115,7 @@ static void vnc_connect(VncState *vs)
memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
vs->has_resize = 0;
vs->has_hextile = 0;
+ vs->has_WMVi = 0;
dcl->dpy_copy = NULL;
vnc_update_client(vs);
reset_keys(vs);