diff options
88 files changed, 3916 insertions, 839 deletions
@@ -131,23 +131,23 @@ version-obj-$(CONFIG_WIN32) += version.o qemu-img.o: qemu-img-cmds.h qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o: $(GENERATED_HEADERS) -qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o +qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o -qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o +qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o -qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o +qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $@") check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS) -check-qint: check-qint.o qint.o qemu-malloc.o -check-qstring: check-qstring.o qstring.o qemu-malloc.o -check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o -check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o -check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o -check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o +check-qint: check-qint.o qint.o qemu-malloc.o $(trace-obj-y) +check-qstring: check-qstring.o qstring.o qemu-malloc.o $(trace-obj-y) +check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o $(trace-obj-y) +check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o $(trace-obj-y) +check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o $(trace-obj-y) +check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o $(trace-obj-y) clean: # avoid old build problems by removing potentially incorrect old files diff --git a/Makefile.objs b/Makefile.objs index 702569f673..faf485ed1b 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -5,10 +5,16 @@ qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o qobject-obj-y += qerror.o ####################################################################### +# oslib-obj-y is code depending on the OS (win32 vs posix) +oslib-obj-y = osdep.o +oslib-obj-$(CONFIG_WIN32) += oslib-win32.o +oslib-obj-$(CONFIG_POSIX) += oslib-posix.o + +####################################################################### # block-obj-y is code used by both qemu system emulation and qemu-img block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o -block-obj-y += nbd.o block.o aio.o aes.o osdep.o qemu-config.o +block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o block-obj-$(CONFIG_POSIX) += posix-aio-compat.o block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o @@ -50,6 +56,7 @@ common-obj-y += $(net-obj-y) common-obj-y += $(qobject-obj-y) common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX)) common-obj-y += readline.o console.o cursor.o async.o qemu-error.o +common-obj-y += $(oslib-obj-y) common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o @@ -248,6 +255,7 @@ sound-obj-$(CONFIG_AC97) += ac97.o sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o sound-obj-$(CONFIG_CS4231A) += cs4231a.o +sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0 hw-obj-$(CONFIG_SOUND) += $(sound-obj-y) diff --git a/Makefile.target b/Makefile.target index c48cbcc7f3..91e6e74399 100644 --- a/Makefile.target +++ b/Makefile.target @@ -88,7 +88,7 @@ $(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \ elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o \ - qemu-malloc.o + qemu-malloc.o $(oslib-obj-y) obj-$(TARGET_HAS_BFLT) += flatload.o diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt index 01ec85fbb9..aa2021082f 100644 --- a/QMP/qmp-events.txt +++ b/QMP/qmp-events.txt @@ -89,7 +89,7 @@ Data: None. Example: -{ "event": "SHUTDOWN", +{ "event": "STOP", "timestamp": { "seconds": 1267041730, "microseconds": 281295 } } VNC_CONNECTED diff --git a/arch_init.c b/arch_init.c index 4caadd0c0a..44869255ef 100644 --- a/arch_init.c +++ b/arch_init.c @@ -502,6 +502,16 @@ struct soundhw soundhw[] = { }, #endif +#ifdef CONFIG_HDA + { + "hda", + "Intel HD Audio", + 0, + 0, + { .init_pci = intel_hda_and_codec_init } + }, +#endif + #endif /* HAS_AUDIO_CHOICE */ { NULL, NULL, 0, 0, { NULL } } @@ -1899,6 +1899,22 @@ int bdrv_snapshot_list(BlockDriverState *bs, return -ENOTSUP; } +int bdrv_snapshot_load_tmp(BlockDriverState *bs, + const char *snapshot_name) +{ + BlockDriver *drv = bs->drv; + if (!drv) { + return -ENOMEDIUM; + } + if (!bs->read_only) { + return -EINVAL; + } + if (drv->bdrv_snapshot_load_tmp) { + return drv->bdrv_snapshot_load_tmp(bs, snapshot_name); + } + return -ENOTSUP; +} + #define NB_SUFFIXES 4 char *get_human_readable_size(char *buf, int buf_size, int64_t size) @@ -211,6 +211,8 @@ int bdrv_snapshot_goto(BlockDriverState *bs, int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id); int bdrv_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_info); +int bdrv_snapshot_load_tmp(BlockDriverState *bs, + const char *snapshot_name); char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); char *get_human_readable_size(char *buf, int buf_size, int64_t size); diff --git a/block/blkverify.c b/block/blkverify.c index 8083464751..b2a12fe7f5 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -53,7 +53,8 @@ static AIOPool blkverify_aio_pool = { .cancel = blkverify_aio_cancel, }; -static void blkverify_err(BlkverifyAIOCB *acb, const char *fmt, ...) +static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb, + const char *fmt, ...) { va_list ap; @@ -299,7 +300,7 @@ static void blkverify_verify_readv(BlkverifyAIOCB *acb) { ssize_t offset = blkverify_iovec_compare(acb->qiov, &acb->raw_qiov); if (offset != -1) { - blkverify_err(acb, "contents mismatch in sector %ld", + blkverify_err(acb, "contents mismatch in sector %lld", acb->sector_num + (offset / BDRV_SECTOR_SIZE)); } } diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index fb4224a669..4f7dc59b76 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -28,7 +28,7 @@ #include "block_int.h" #include "block/qcow2.h" -int qcow2_grow_l1_table(BlockDriverState *bs, int min_size) +int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size) { BDRVQcowState *s = bs->opaque; int new_l1_size, new_l1_size2, ret, i; @@ -36,15 +36,22 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size) int64_t new_l1_table_offset; uint8_t data[12]; - new_l1_size = s->l1_size; - if (min_size <= new_l1_size) + if (min_size <= s->l1_size) return 0; - if (new_l1_size == 0) { - new_l1_size = 1; - } - while (min_size > new_l1_size) { - new_l1_size = (new_l1_size * 3 + 1) / 2; + + if (exact_size) { + new_l1_size = min_size; + } else { + /* Bump size up to reduce the number of times we have to grow */ + new_l1_size = s->l1_size; + if (new_l1_size == 0) { + new_l1_size = 1; + } + while (min_size > new_l1_size) { + new_l1_size = (new_l1_size * 3 + 1) / 2; + } } + #ifdef DEBUG_ALLOC2 printf("grow l1_table from %d to %d\n", s->l1_size, new_l1_size); #endif @@ -550,7 +557,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset, l1_index = offset >> (s->l2_bits + s->cluster_bits); if (l1_index >= s->l1_size) { - ret = qcow2_grow_l1_table(bs, l1_index + 1); + ret = qcow2_grow_l1_table(bs, l1_index + 1, false); if (ret < 0) { return ret; } diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index bbfcaaae22..aacf357821 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -327,7 +327,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0) goto fail; - if (qcow2_grow_l1_table(bs, sn->l1_size) < 0) + if (qcow2_grow_l1_table(bs, sn->l1_size, true) < 0) goto fail; s->l1_size = sn->l1_size; @@ -418,3 +418,34 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) return s->nb_snapshots; } +int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name) +{ + int i, snapshot_index, l1_size2; + BDRVQcowState *s = bs->opaque; + QCowSnapshot *sn; + + snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_name); + if (snapshot_index < 0) { + return -ENOENT; + } + + sn = &s->snapshots[snapshot_index]; + s->l1_size = sn->l1_size; + l1_size2 = s->l1_size * sizeof(uint64_t); + if (s->l1_table != NULL) { + qemu_free(s->l1_table); + } + + s->l1_table_offset = sn->l1_table_offset; + s->l1_table = qemu_mallocz(align_offset(l1_size2, 512)); + + if (bdrv_pread(bs->file, sn->l1_table_offset, + s->l1_table, l1_size2) != l1_size2) { + return -1; + } + + for(i = 0;i < s->l1_size; i++) { + be64_to_cpus(&s->l1_table[i]); + } + return 0; +} diff --git a/block/qcow2.c b/block/qcow2.c index ee3481b786..b816d8733f 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -27,6 +27,7 @@ #include <zlib.h> #include "aes.h" #include "block/qcow2.h" +#include "qemu-error.h" /* Differences with QCOW: @@ -794,28 +795,6 @@ static int qcow2_change_backing_file(BlockDriverState *bs, return qcow2_update_ext_header(bs, backing_file, backing_fmt); } -static int get_bits_from_size(size_t size) -{ - int res = 0; - - if (size == 0) { - return -1; - } - - while (size != 1) { - /* Not a power of two */ - if (size & 1) { - return -1; - } - - size >>= 1; - res++; - } - - return res; -} - - static int preallocate(BlockDriverState *bs) { uint64_t nb_sectors; @@ -871,199 +850,127 @@ static int preallocate(BlockDriverState *bs) static int qcow_create2(const char *filename, int64_t total_size, const char *backing_file, const char *backing_format, - int flags, size_t cluster_size, int prealloc) + int flags, size_t cluster_size, int prealloc, + QEMUOptionParameter *options) { + /* Calulate cluster_bits */ + int cluster_bits; + cluster_bits = ffs(cluster_size) - 1; + if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS || + (1 << cluster_bits) != cluster_size) + { + error_report( + "Cluster size must be a power of two between %d and %dk\n", + 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10)); + return -EINVAL; + } - int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits; - int ref_clusters, reftable_clusters, backing_format_len = 0; - int rounded_ext_bf_len = 0; + /* + * Open the image file and write a minimal qcow2 header. + * + * We keep things simple and start with a zero-sized image. We also + * do without refcount blocks or a L1 table for now. We'll fix the + * inconsistency later. + * + * We do need a refcount table because growing the refcount table means + * allocating two new refcount blocks - the seconds of which would be at + * 2 GB for 64k clusters, and we don't want to have a 2 GB initial file + * size for any qcow2 image. + */ + BlockDriverState* bs; QCowHeader header; - uint64_t tmp, offset; - uint64_t old_ref_clusters; - QCowCreateState s1, *s = &s1; - QCowExtension ext_bf = {0, 0}; + uint8_t* refcount_table; int ret; - memset(s, 0, sizeof(*s)); + ret = bdrv_create_file(filename, options); + if (ret < 0) { + return ret; + } - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); - if (fd < 0) - return -errno; + ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR); + if (ret < 0) { + return ret; + } + + /* Write the header */ memset(&header, 0, sizeof(header)); header.magic = cpu_to_be32(QCOW_MAGIC); header.version = cpu_to_be32(QCOW_VERSION); - header.size = cpu_to_be64(total_size * 512); - header_size = sizeof(header); - backing_filename_len = 0; - if (backing_file) { - if (backing_format) { - ext_bf.magic = QCOW_EXT_MAGIC_BACKING_FORMAT; - backing_format_len = strlen(backing_format); - ext_bf.len = backing_format_len; - rounded_ext_bf_len = (sizeof(ext_bf) + ext_bf.len + 7) & ~7; - header_size += rounded_ext_bf_len; - } - header.backing_file_offset = cpu_to_be64(header_size); - backing_filename_len = strlen(backing_file); - header.backing_file_size = cpu_to_be32(backing_filename_len); - header_size += backing_filename_len; - } - - /* Cluster size */ - s->cluster_bits = get_bits_from_size(cluster_size); - if (s->cluster_bits < MIN_CLUSTER_BITS || - s->cluster_bits > MAX_CLUSTER_BITS) - { - fprintf(stderr, "Cluster size must be a power of two between " - "%d and %dk\n", - 1 << MIN_CLUSTER_BITS, - 1 << (MAX_CLUSTER_BITS - 10)); - return -EINVAL; - } - s->cluster_size = 1 << s->cluster_bits; + header.cluster_bits = cpu_to_be32(cluster_bits); + header.size = cpu_to_be64(0); + header.l1_table_offset = cpu_to_be64(0); + header.l1_size = cpu_to_be32(0); + header.refcount_table_offset = cpu_to_be64(cluster_size); + header.refcount_table_clusters = cpu_to_be32(1); - header.cluster_bits = cpu_to_be32(s->cluster_bits); - header_size = (header_size + 7) & ~7; if (flags & BLOCK_FLAG_ENCRYPT) { header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES); } else { header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); } - l2_bits = s->cluster_bits - 3; - shift = s->cluster_bits + l2_bits; - l1_size = (((total_size * 512) + (1LL << shift) - 1) >> shift); - offset = align_offset(header_size, s->cluster_size); - s->l1_table_offset = offset; - header.l1_table_offset = cpu_to_be64(s->l1_table_offset); - header.l1_size = cpu_to_be32(l1_size); - offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size); - - /* count how many refcount blocks needed */ - -#define NUM_CLUSTERS(bytes) \ - (((bytes) + (s->cluster_size) - 1) / (s->cluster_size)) - ref_clusters = NUM_CLUSTERS(NUM_CLUSTERS(offset) * sizeof(uint16_t)); - - do { - uint64_t image_clusters; - old_ref_clusters = ref_clusters; - - /* Number of clusters used for the refcount table */ - reftable_clusters = NUM_CLUSTERS(ref_clusters * sizeof(uint64_t)); + ret = bdrv_pwrite(bs, 0, &header, sizeof(header)); + if (ret < 0) { + goto out; + } - /* Number of clusters that the whole image will have */ - image_clusters = NUM_CLUSTERS(offset) + ref_clusters - + reftable_clusters; + /* Write an empty refcount table */ + refcount_table = qemu_mallocz(cluster_size); + ret = bdrv_pwrite(bs, cluster_size, refcount_table, cluster_size); + qemu_free(refcount_table); - /* Number of refcount blocks needed for the image */ - ref_clusters = NUM_CLUSTERS(image_clusters * sizeof(uint16_t)); + if (ret < 0) { + goto out; + } - } while (ref_clusters != old_ref_clusters); + bdrv_close(bs); - s->refcount_table = qemu_mallocz(reftable_clusters * s->cluster_size); + /* + * And now open the image and make it consistent first (i.e. increase the + * refcount of the cluster that is occupied by the header and the refcount + * table) + */ + BlockDriver* drv = bdrv_find_format("qcow2"); + assert(drv != NULL); + ret = bdrv_open(bs, filename, BDRV_O_RDWR | BDRV_O_NO_FLUSH, drv); + if (ret < 0) { + goto out; + } - s->refcount_table_offset = offset; - header.refcount_table_offset = cpu_to_be64(offset); - header.refcount_table_clusters = cpu_to_be32(reftable_clusters); - offset += (reftable_clusters * s->cluster_size); - s->refcount_block_offset = offset; + ret = qcow2_alloc_clusters(bs, 2 * cluster_size); + if (ret < 0) { + goto out; - for (i=0; i < ref_clusters; i++) { - s->refcount_table[i] = cpu_to_be64(offset); - offset += s->cluster_size; + } else if (ret != 0) { + error_report("Huh, first cluster in empty image is already in use?"); + abort(); } - s->refcount_block = qemu_mallocz(ref_clusters * s->cluster_size); - - /* update refcounts */ - qcow2_create_refcount_update(s, 0, header_size); - qcow2_create_refcount_update(s, s->l1_table_offset, - l1_size * sizeof(uint64_t)); - qcow2_create_refcount_update(s, s->refcount_table_offset, - reftable_clusters * s->cluster_size); - qcow2_create_refcount_update(s, s->refcount_block_offset, - ref_clusters * s->cluster_size); - - /* write all the data */ - ret = qemu_write_full(fd, &header, sizeof(header)); - if (ret != sizeof(header)) { - ret = -errno; - goto exit; + /* Okay, now that we have a valid image, let's give it the right size */ + ret = bdrv_truncate(bs, total_size * BDRV_SECTOR_SIZE); + if (ret < 0) { + goto out; } + + /* Want a backing file? There you go.*/ if (backing_file) { - if (backing_format_len) { - char zero[16]; - int padding = rounded_ext_bf_len - (ext_bf.len + sizeof(ext_bf)); - - memset(zero, 0, sizeof(zero)); - cpu_to_be32s(&ext_bf.magic); - cpu_to_be32s(&ext_bf.len); - ret = qemu_write_full(fd, &ext_bf, sizeof(ext_bf)); - if (ret != sizeof(ext_bf)) { - ret = -errno; - goto exit; - } - ret = qemu_write_full(fd, backing_format, backing_format_len); - if (ret != backing_format_len) { - ret = -errno; - goto exit; - } - if (padding > 0) { - ret = qemu_write_full(fd, zero, padding); - if (ret != padding) { - ret = -errno; - goto exit; - } - } - } - ret = qemu_write_full(fd, backing_file, backing_filename_len); - if (ret != backing_filename_len) { - ret = -errno; - goto exit; - } - } - lseek(fd, s->l1_table_offset, SEEK_SET); - tmp = 0; - for(i = 0;i < l1_size; i++) { - ret = qemu_write_full(fd, &tmp, sizeof(tmp)); - if (ret != sizeof(tmp)) { - ret = -errno; - goto exit; + ret = bdrv_change_backing_file(bs, backing_file, backing_format); + if (ret < 0) { + goto out; } } - lseek(fd, s->refcount_table_offset, SEEK_SET); - ret = qemu_write_full(fd, s->refcount_table, - reftable_clusters * s->cluster_size); - if (ret != reftable_clusters * s->cluster_size) { - ret = -errno; - goto exit; - } - - lseek(fd, s->refcount_block_offset, SEEK_SET); - ret = qemu_write_full(fd, s->refcount_block, - ref_clusters * s->cluster_size); - if (ret != ref_clusters * s->cluster_size) { - ret = -errno; - goto exit; - } - ret = 0; -exit: - qemu_free(s->refcount_table); - qemu_free(s->refcount_block); - close(fd); - - /* Preallocate metadata */ - if (ret == 0 && prealloc) { - BlockDriverState *bs; - BlockDriver *drv = bdrv_find_format("qcow2"); - bs = bdrv_new(""); - bdrv_open(bs, filename, BDRV_O_CACHE_WB | BDRV_O_RDWR, drv); + /* And if we're supposed to preallocate metadata, do that now */ + if (prealloc) { ret = preallocate(bs); - bdrv_close(bs); + if (ret < 0) { + goto out; + } } + ret = 0; +out: + bdrv_delete(bs); return ret; } @@ -1111,7 +1018,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options) } return qcow_create2(filename, sectors, backing_file, backing_fmt, flags, - cluster_size, prealloc); + cluster_size, prealloc, options); } static int qcow_make_empty(BlockDriverState *bs) @@ -1154,7 +1061,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset) } new_l1_size = size_to_l1(s, offset); - ret = qcow2_grow_l1_table(bs, new_l1_size); + ret = qcow2_grow_l1_table(bs, new_l1_size, true); if (ret < 0) { return ret; } @@ -1379,6 +1286,7 @@ static BlockDriver bdrv_qcow2 = { .bdrv_snapshot_goto = qcow2_snapshot_goto, .bdrv_snapshot_delete = qcow2_snapshot_delete, .bdrv_snapshot_list = qcow2_snapshot_list, + .bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp, .bdrv_get_info = qcow_get_info, .bdrv_save_vmstate = qcow_save_vmstate, diff --git a/block/qcow2.h b/block/qcow2.h index 356a34af43..2d22e5ec47 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -188,7 +188,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res); /* qcow2-cluster.c functions */ -int qcow2_grow_l1_table(BlockDriverState *bs, int min_size); +int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size); void qcow2_l2_cache_reset(BlockDriverState *bs); int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num, @@ -211,6 +211,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id); int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id); int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab); +int qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_name); void qcow2_free_snapshots(BlockDriverState *bs); int qcow2_read_snapshots(BlockDriverState *bs); diff --git a/block_int.h b/block_int.h index e8e7156c92..87e60b8597 100644 --- a/block_int.h +++ b/block_int.h @@ -93,6 +93,8 @@ struct BlockDriver { int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id); int (*bdrv_snapshot_list)(BlockDriverState *bs, QEMUSnapshotInfo **psn_info); + int (*bdrv_snapshot_load_tmp)(BlockDriverState *bs, + const char *snapshot_name); int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); int (*bdrv_save_vmstate)(BlockDriverState *bs, const uint8_t *buf, diff --git a/cache-utils.c b/cache-utils.c index b1f20978ca..2db5af2db1 100644 --- a/cache-utils.c +++ b/cache-utils.c @@ -79,7 +79,7 @@ static void ppc_init_cacheline_sizes(void) qemu_cache_conf.dcache_bsize = cacheline; qemu_cache_conf.icache_bsize = cacheline; } -#endif +#endif #ifdef __linux__ void qemu_cache_utils_init(char **envp) diff --git a/check-qjson.c b/check-qjson.c index 0b60e45fa6..64fcdcb4ad 100644 --- a/check-qjson.c +++ b/check-qjson.c @@ -639,7 +639,9 @@ END_TEST START_TEST(empty_input) { - QObject *obj = qobject_from_json(""); + const char *empty = ""; + + QObject *obj = qobject_from_json(empty); fail_unless(obj == NULL); } END_TEST @@ -76,8 +76,8 @@ sparc_cpu="" cross_prefix="" cc="gcc" audio_drv_list="" -audio_card_list="ac97 es1370 sb16" -audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus" +audio_card_list="ac97 es1370 sb16 hda" +audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus hda" block_drv_whitelist="" host_cc="gcc" ar="ar" @@ -765,12 +765,10 @@ int page_check_range(target_ulong start, target_ulong len, int flags); CPUState *cpu_copy(CPUState *env); CPUState *qemu_get_cpu(int cpu); -void cpu_dump_state(CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags); -void cpu_dump_statistics (CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), - int flags); +void cpu_dump_statistics(CPUState *env, FILE *f, fprintf_function cpu_fprintf, + int flags); void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...) GCC_FMT_ATTR(2, 3); @@ -959,8 +957,7 @@ int cpu_physical_memory_get_dirty_tracking(void); int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr); -void dump_exec_info(FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +void dump_exec_info(FILE *f, fprintf_function cpu_fprintf); #endif /* !CONFIG_USER_ONLY */ int cpu_memory_rw_debug(CPUState *env, target_ulong addr, @@ -978,8 +978,7 @@ int64_t cpu_get_icount(void) return qemu_icount_bias + (icount << icount_time_shift); } -void list_cpus(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), - const char *optarg) +void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg) { /* XXX: implement xxx_cpu_list for targets that still miss it */ #if defined(cpu_list_id) @@ -16,7 +16,6 @@ void vm_state_notify(int running, int reason); bool cpu_exec_all(void); void set_numa_modes(void); void set_cpu_log(const char *optarg); -void list_cpus(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), - const char *optarg); +void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg); #endif @@ -23,17 +23,10 @@ #include <sys/types.h> #include <sys/mman.h> #endif -#include <stdlib.h> -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <inttypes.h> +#include "qemu-common.h" #include "cpu.h" #include "exec-all.h" -#include "qemu-common.h" #include "tcg.h" #include "hw/hw.h" #include "hw/qdev.h" @@ -4096,8 +4089,7 @@ void cpu_io_recompile(CPUState *env, void *retaddr) #if !defined(CONFIG_USER_ONLY) -void dump_exec_info(FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +void dump_exec_info(FILE *f, fprintf_function cpu_fprintf) { int i, target_code_size, max_target_code_size; int direct_jmp_count, direct_jmp2_count, cross_page; @@ -4124,14 +4116,14 @@ void dump_exec_info(FILE *f, } /* XXX: avoid using doubles ? */ cpu_fprintf(f, "Translation buffer state:\n"); - cpu_fprintf(f, "gen code size %ld/%ld\n", + cpu_fprintf(f, "gen code size %td/%ld\n", code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size); cpu_fprintf(f, "TB count %d/%d\n", nb_tbs, code_gen_max_blocks); cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", nb_tbs ? target_code_size / nb_tbs : 0, max_target_code_size); - cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n", + cpu_fprintf(f, "TB avg host size %td bytes (expansion ratio: %0.1f)\n", nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0, target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0); cpu_fprintf(f, "cross page TB count %d (%d%%)\n", diff --git a/hw/audiodev.h b/hw/audiodev.h index 39a729b8a4..8e930b21ae 100644 --- a/hw/audiodev.h +++ b/hw/audiodev.h @@ -15,3 +15,6 @@ int ac97_init(PCIBus *buf); /* cs4231a.c */ int cs4231a_init(qemu_irq *pic); + +/* intel-hda.c + hda-audio.c */ +int intel_hda_and_codec_init(PCIBus *bus); diff --git a/hw/bt-sdp.c b/hw/bt-sdp.c index cc0bf2f9b3..cdf2d95d52 100644 --- a/hw/bt-sdp.c +++ b/hw/bt-sdp.c @@ -786,11 +786,11 @@ static void sdp_service_db_build(struct bt_l2cap_sdp_state_s *sdp, .type = SDP_DTYPE_UUID | SDP_DSIZE_16, \ .value.uint = val, \ }, -#define TRUE { \ +#define SDP_TRUE { \ .type = SDP_DTYPE_BOOL | SDP_DSIZE_1, \ .value.uint = 1, \ }, -#define FALSE { \ +#define SDP_FALSE { \ .type = SDP_DTYPE_BOOL | SDP_DSIZE_1, \ .value.uint = 0, \ }, @@ -842,8 +842,8 @@ SERVICE(hid, /* TODO: extract from l2cap_device->device.class[0] */ ATTRIBUTE(DEVICE_SUBCLASS, UINT8(0x40)) ATTRIBUTE(COUNTRY_CODE, UINT8(0x15)) - ATTRIBUTE(VIRTUAL_CABLE, TRUE) - ATTRIBUTE(RECONNECT_INITIATE, FALSE) + ATTRIBUTE(VIRTUAL_CABLE, SDP_TRUE) + ATTRIBUTE(RECONNECT_INITIATE, SDP_FALSE) /* TODO: extract from hid->usbdev->report_desc */ ATTRIBUTE(DESCRIPTOR_LIST, LIST( LIST(UINT8(0x22) ARRAY( @@ -883,12 +883,12 @@ SERVICE(hid, ATTRIBUTE(LANG_ID_BASE_LIST, LIST( LIST(UINT16(0x0409) UINT16(0x0100)) )) - ATTRIBUTE(SDP_DISABLE, FALSE) - ATTRIBUTE(BATTERY_POWER, TRUE) - ATTRIBUTE(REMOTE_WAKEUP, TRUE) - ATTRIBUTE(BOOT_DEVICE, TRUE) /* XXX: untested */ + ATTRIBUTE(SDP_DISABLE, SDP_FALSE) + ATTRIBUTE(BATTERY_POWER, SDP_TRUE) + ATTRIBUTE(REMOTE_WAKEUP, SDP_TRUE) + ATTRIBUTE(BOOT_DEVICE, SDP_TRUE) /* XXX: untested */ ATTRIBUTE(SUPERVISION_TIMEOUT, UINT16(0x0c80)) - ATTRIBUTE(NORMALLY_CONNECTABLE, TRUE) + ATTRIBUTE(NORMALLY_CONNECTABLE, SDP_TRUE) ATTRIBUTE(PROFILE_VERSION, UINT16(0x0100)) ) @@ -936,7 +936,7 @@ SERVICE(pnp, /* Profile specific */ ATTRIBUTE(SPECIFICATION_ID, UINT16(0x0100)) ATTRIBUTE(VERSION, UINT16(0x0100)) - ATTRIBUTE(PRIMARY_RECORD, TRUE) + ATTRIBUTE(PRIMARY_RECORD, SDP_TRUE) ) static int bt_l2cap_sdp_new_ch(struct bt_l2cap_device_s *dev, diff --git a/hw/cs4231.c b/hw/cs4231.c index f7ce0af3f9..2977101e39 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -23,9 +23,7 @@ */ #include "sysbus.h" - -/* debug CS4231 */ -//#define DEBUG_CS +#include "trace.h" /* * In addition to Crystal CS4231 there is a DMA controller on Sparc. @@ -46,13 +44,6 @@ typedef struct CSState { #define CS_VER 0xa0 #define CS_CDC_VER 0x8a -#ifdef DEBUG_CS -#define DPRINTF(fmt, ...) \ - do { printf("CS: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) -#endif - static void cs_reset(DeviceState *d) { CSState *s = container_of(d, CSState, busdev.qdev); @@ -79,11 +70,11 @@ static uint32_t cs_mem_readl(void *opaque, target_phys_addr_t addr) ret = s->dregs[CS_RAP(s)]; break; } - DPRINTF("read dreg[%d]: 0x%8.8x\n", CS_RAP(s), ret); + trace_cs4231_mem_readl_dreg(CS_RAP(s), ret); break; default: ret = s->regs[saddr]; - DPRINTF("read reg[%d]: 0x%8.8x\n", saddr, ret); + trace_cs4231_mem_readl_reg(saddr, ret); break; } return ret; @@ -95,11 +86,10 @@ static void cs_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) uint32_t saddr; saddr = addr >> 2; - DPRINTF("write reg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->regs[saddr], val); + trace_cs4231_mem_writel_reg(saddr, s->regs[saddr], val); switch (saddr) { case 1: - DPRINTF("write dreg[%d]: 0x%2.2x -> 0x%2.2x\n", CS_RAP(s), - s->dregs[CS_RAP(s)], val); + trace_cs4231_mem_writel_dreg(CS_RAP(s), s->dregs[CS_RAP(s)], val); switch(CS_RAP(s)) { case 11: case 25: // Read only diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c index 498c61a89c..a8042e94bc 100644 --- a/hw/eccmemctl.c +++ b/hw/eccmemctl.c @@ -23,15 +23,7 @@ */ #include "sysbus.h" - -//#define DEBUG_ECC - -#ifdef DEBUG_ECC -#define DPRINTF(fmt, ...) \ - do { printf("ECC: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) -#endif +#include "trace.h" /* There are 3 versions of this chip used in SMP sun4m systems: * MCC (version 0, implementation 0) SS-600MP @@ -148,32 +140,32 @@ static void ecc_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_1); else if (s->version == ECC_SMC) s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_2); - DPRINTF("Write memory enable %08x\n", val); + trace_ecc_mem_writel_mer(val); break; case ECC_MDR: s->regs[ECC_MDR] = val & ECC_MDR_MASK; - DPRINTF("Write memory delay %08x\n", val); + trace_ecc_mem_writel_mdr(val); break; case ECC_MFSR: s->regs[ECC_MFSR] = val; qemu_irq_lower(s->irq); - DPRINTF("Write memory fault status %08x\n", val); + trace_ecc_mem_writel_mfsr(val); break; case ECC_VCR: s->regs[ECC_VCR] = val; - DPRINTF("Write slot configuration %08x\n", val); + trace_ecc_mem_writel_vcr(val); break; case ECC_DR: s->regs[ECC_DR] = val; - DPRINTF("Write diagnostic %08x\n", val); + trace_ecc_mem_writel_dr(val); break; case ECC_ECR0: s->regs[ECC_ECR0] = val; - DPRINTF("Write event count 1 %08x\n", val); + trace_ecc_mem_writel_ecr0(val); break; case ECC_ECR1: s->regs[ECC_ECR0] = val; - DPRINTF("Write event count 2 %08x\n", val); + trace_ecc_mem_writel_ecr1(val); break; } } @@ -186,39 +178,39 @@ static uint32_t ecc_mem_readl(void *opaque, target_phys_addr_t addr) switch (addr >> 2) { case ECC_MER: ret = s->regs[ECC_MER]; - DPRINTF("Read memory enable %08x\n", ret); + trace_ecc_mem_readl_mer(ret); break; case ECC_MDR: ret = s->regs[ECC_MDR]; - DPRINTF("Read memory delay %08x\n", ret); + trace_ecc_mem_readl_mdr(ret); break; case ECC_MFSR: ret = s->regs[ECC_MFSR]; - DPRINTF("Read memory fault status %08x\n", ret); + trace_ecc_mem_readl_mfsr(ret); break; case ECC_VCR: ret = s->regs[ECC_VCR]; - DPRINTF("Read slot configuration %08x\n", ret); + trace_ecc_mem_readl_vcr(ret); break; case ECC_MFAR0: ret = s->regs[ECC_MFAR0]; - DPRINTF("Read memory fault address 0 %08x\n", ret); + trace_ecc_mem_readl_mfar0(ret); break; case ECC_MFAR1: ret = s->regs[ECC_MFAR1]; - DPRINTF("Read memory fault address 1 %08x\n", ret); + trace_ecc_mem_readl_mfar1(ret); break; case ECC_DR: ret = s->regs[ECC_DR]; - DPRINTF("Read diagnostic %08x\n", ret); + trace_ecc_mem_readl_dr(ret); break; case ECC_ECR0: ret = s->regs[ECC_ECR0]; - DPRINTF("Read event count 1 %08x\n", ret); + trace_ecc_mem_readl_ecr0(ret); break; case ECC_ECR1: ret = s->regs[ECC_ECR0]; - DPRINTF("Read event count 2 %08x\n", ret); + trace_ecc_mem_readl_ecr1(ret); break; } return ret; @@ -241,7 +233,7 @@ static void ecc_diag_mem_writeb(void *opaque, target_phys_addr_t addr, { ECCState *s = opaque; - DPRINTF("Write diagnostic[%d] = %02x\n", (int)addr, val); + trace_ecc_diag_mem_writeb(addr, val); s->diag[addr & ECC_DIAG_MASK] = val; } @@ -250,7 +242,7 @@ static uint32_t ecc_diag_mem_readb(void *opaque, target_phys_addr_t addr) ECCState *s = opaque; uint32_t ret = s->diag[(int)addr]; - DPRINTF("Read diagnostic[%d] = %02x\n", (int)addr, ret); + trace_ecc_diag_mem_readb(addr, ret); return ret; } diff --git a/hw/hda-audio.c b/hw/hda-audio.c new file mode 100644 index 0000000000..103577470a --- /dev/null +++ b/hw/hda-audio.c @@ -0,0 +1,902 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * written by Gerd Hoffmann <kraxel@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw.h" +#include "pci.h" +#include "intel-hda.h" +#include "intel-hda-defs.h" +#include "audio/audio.h" + +/* -------------------------------------------------------------------------- */ + +typedef struct desc_param { + uint32_t id; + uint32_t val; +} desc_param; + +typedef struct desc_node { + uint32_t nid; + const char *name; + const desc_param *params; + uint32_t nparams; + uint32_t config; + uint32_t pinctl; + uint32_t *conn; + uint32_t stindex; +} desc_node; + +typedef struct desc_codec { + const char *name; + uint32_t iid; + const desc_node *nodes; + uint32_t nnodes; +} desc_codec; + +static const desc_param* hda_codec_find_param(const desc_node *node, uint32_t id) +{ + int i; + + for (i = 0; i < node->nparams; i++) { + if (node->params[i].id == id) { + return &node->params[i]; + } + } + return NULL; +} + +static const desc_node* hda_codec_find_node(const desc_codec *codec, uint32_t nid) +{ + int i; + + for (i = 0; i < codec->nnodes; i++) { + if (codec->nodes[i].nid == nid) { + return &codec->nodes[i]; + } + } + return NULL; +} + +static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) +{ + if (format & AC_FMT_TYPE_NON_PCM) { + return; + } + + as->freq = (format & AC_FMT_BASE_44K) ? 44100 : 48000; + + switch ((format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT) { + case 1: as->freq *= 2; break; + case 2: as->freq *= 3; break; + case 3: as->freq *= 4; break; + } + + switch ((format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT) { + case 1: as->freq /= 2; break; + case 2: as->freq /= 3; break; + case 3: as->freq /= 4; break; + case 4: as->freq /= 5; break; + case 5: as->freq /= 6; break; + case 6: as->freq /= 7; break; + case 7: as->freq /= 8; break; + } + + switch (format & AC_FMT_BITS_MASK) { + case AC_FMT_BITS_8: as->fmt = AUD_FMT_S8; break; + case AC_FMT_BITS_16: as->fmt = AUD_FMT_S16; break; + case AC_FMT_BITS_32: as->fmt = AUD_FMT_S32; break; + } + + as->nchannels = ((format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT) + 1; +} + +/* -------------------------------------------------------------------------- */ +/* + * HDA codec descriptions + */ + +/* some defines */ + +#define QEMU_HDA_ID_VENDOR 0x1af4 +#define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x10) +#define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x20) + +#define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 | \ + 0x1fc /* 16 -> 96 kHz */) +#define QEMU_HDA_AMP_NONE (0) +#define QEMU_HDA_AMP_STEPS 0x4a + +#ifdef CONFIG_MIXEMU +#define QEMU_HDA_AMP_CAPS \ + (AC_AMPCAP_MUTE | \ + (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT) | \ + (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) | \ + (3 << AC_AMPCAP_STEP_SIZE_SHIFT)) +#else +#define QEMU_HDA_AMP_CAPS QEMU_HDA_AMP_NONE +#endif + +/* common: audio output widget */ +static const desc_param common_params_audio_dac[] = { + { + .id = AC_PAR_AUDIO_WIDGET_CAP, + .val = ((AC_WID_AUD_OUT << AC_WCAP_TYPE_SHIFT) | + AC_WCAP_FORMAT_OVRD | + AC_WCAP_AMP_OVRD | + AC_WCAP_OUT_AMP | + AC_WCAP_STEREO), + },{ + .id = AC_PAR_PCM, + .val = QEMU_HDA_PCM_FORMATS, + },{ + .id = AC_PAR_STREAM, + .val = AC_SUPFMT_PCM, + },{ + .id = AC_PAR_AMP_IN_CAP, + .val = QEMU_HDA_AMP_NONE, + },{ + .id = AC_PAR_AMP_OUT_CAP, + .val = QEMU_HDA_AMP_CAPS, + }, +}; + +/* common: pin widget (line-out) */ +static const desc_param common_params_audio_lineout[] = { + { + .id = AC_PAR_AUDIO_WIDGET_CAP, + .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) | + AC_WCAP_CONN_LIST | + AC_WCAP_STEREO), + },{ + .id = AC_PAR_PIN_CAP, + .val = AC_PINCAP_OUT, + },{ + .id = AC_PAR_CONNLIST_LEN, + .val = 1, + },{ + .id = AC_PAR_AMP_IN_CAP, + .val = QEMU_HDA_AMP_NONE, + },{ + .id = AC_PAR_AMP_OUT_CAP, + .val = QEMU_HDA_AMP_NONE, + }, +}; + +/* output: root node */ +static const desc_param output_params_root[] = { + { + .id = AC_PAR_VENDOR_ID, + .val = QEMU_HDA_ID_OUTPUT, + },{ + .id = AC_PAR_SUBSYSTEM_ID, + .val = QEMU_HDA_ID_OUTPUT, + },{ + .id = AC_PAR_REV_ID, + .val = 0x00100101, + },{ + .id = AC_PAR_NODE_COUNT, + .val = 0x00010001, + }, +}; + +/* output: audio function */ +static const desc_param output_params_audio_func[] = { + { + .id = AC_PAR_FUNCTION_TYPE, + .val = AC_GRP_AUDIO_FUNCTION, + },{ + .id = AC_PAR_SUBSYSTEM_ID, + .val = QEMU_HDA_ID_OUTPUT, + },{ + .id = AC_PAR_NODE_COUNT, + .val = 0x00020002, + },{ + .id = AC_PAR_PCM, + .val = QEMU_HDA_PCM_FORMATS, + },{ + .id = AC_PAR_STREAM, + .val = AC_SUPFMT_PCM, + },{ + .id = AC_PAR_AMP_IN_CAP, + .val = QEMU_HDA_AMP_NONE, + },{ + .id = AC_PAR_AMP_OUT_CAP, + .val = QEMU_HDA_AMP_NONE, + },{ + .id = AC_PAR_GPIO_CAP, + .val = 0, + },{ + .id = AC_PAR_AUDIO_FG_CAP, + .val = 0x00000808, + },{ + .id = AC_PAR_POWER_STATE, + .val = 0, + }, +}; + +/* output: nodes */ +static const desc_node output_nodes[] = { + { + .nid = AC_NODE_ROOT, + .name = "root", + .params = output_params_root, + .nparams = ARRAY_SIZE(output_params_root), + },{ + .nid = 1, + .name = "func", + .params = output_params_audio_func, + .nparams = ARRAY_SIZE(output_params_audio_func), + },{ + .nid = 2, + .name = "dac", + .params = common_params_audio_dac, + .nparams = ARRAY_SIZE(common_params_audio_dac), + .stindex = 0, + },{ + .nid = 3, + .name = "out", + .params = common_params_audio_lineout, + .nparams = ARRAY_SIZE(common_params_audio_lineout), + .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | + (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) | + (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | + (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) | + 0x10), + .pinctl = AC_PINCTL_OUT_EN, + .conn = (uint32_t[]) { 2 }, + } +}; + +/* output: codec */ +static const desc_codec output = { + .name = "output", + .iid = QEMU_HDA_ID_OUTPUT, + .nodes = output_nodes, + .nnodes = ARRAY_SIZE(output_nodes), +}; + +/* duplex: root node */ +static const desc_param duplex_params_root[] = { + { + .id = AC_PAR_VENDOR_ID, + .val = QEMU_HDA_ID_DUPLEX, + },{ + .id = AC_PAR_SUBSYSTEM_ID, + .val = QEMU_HDA_ID_DUPLEX, + },{ + .id = AC_PAR_REV_ID, + .val = 0x00100101, + },{ + .id = AC_PAR_NODE_COUNT, + .val = 0x00010001, + }, +}; + +/* duplex: audio input widget */ +static const desc_param duplex_params_audio_adc[] = { + { + .id = AC_PAR_AUDIO_WIDGET_CAP, + .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) | + AC_WCAP_CONN_LIST | + AC_WCAP_FORMAT_OVRD | + AC_WCAP_AMP_OVRD | + AC_WCAP_IN_AMP | + AC_WCAP_STEREO), + },{ + .id = AC_PAR_CONNLIST_LEN, + .val = 1, + },{ + .id = AC_PAR_PCM, + .val = QEMU_HDA_PCM_FORMATS, + },{ + .id = AC_PAR_STREAM, + .val = AC_SUPFMT_PCM, + },{ + .id = AC_PAR_AMP_IN_CAP, + .val = QEMU_HDA_AMP_CAPS, + },{ + .id = AC_PAR_AMP_OUT_CAP, + .val = QEMU_HDA_AMP_NONE, + }, +}; + +/* duplex: pin widget (line-in) */ +static const desc_param duplex_params_audio_linein[] = { + { + .id = AC_PAR_AUDIO_WIDGET_CAP, + .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) | + AC_WCAP_STEREO), + },{ + .id = AC_PAR_PIN_CAP, + .val = AC_PINCAP_IN, + },{ + .id = AC_PAR_AMP_IN_CAP, + .val = QEMU_HDA_AMP_NONE, + },{ + .id = AC_PAR_AMP_OUT_CAP, + .val = QEMU_HDA_AMP_NONE, + }, +}; + +/* duplex: audio function */ +static const desc_param duplex_params_audio_func[] = { + { + .id = AC_PAR_FUNCTION_TYPE, + .val = AC_GRP_AUDIO_FUNCTION, + },{ + .id = AC_PAR_SUBSYSTEM_ID, + .val = QEMU_HDA_ID_DUPLEX, + },{ + .id = AC_PAR_NODE_COUNT, + .val = 0x00020004, + },{ + .id = AC_PAR_PCM, + .val = QEMU_HDA_PCM_FORMATS, + },{ + .id = AC_PAR_STREAM, + .val = AC_SUPFMT_PCM, + },{ + .id = AC_PAR_AMP_IN_CAP, + .val = QEMU_HDA_AMP_NONE, + },{ + .id = AC_PAR_AMP_OUT_CAP, + .val = QEMU_HDA_AMP_NONE, + },{ + .id = AC_PAR_GPIO_CAP, + .val = 0, + },{ + .id = AC_PAR_AUDIO_FG_CAP, + .val = 0x00000808, + },{ + .id = AC_PAR_POWER_STATE, + .val = 0, + }, +}; + +/* duplex: nodes */ +static const desc_node duplex_nodes[] = { + { + .nid = AC_NODE_ROOT, + .name = "root", + .params = duplex_params_root, + .nparams = ARRAY_SIZE(duplex_params_root), + },{ + .nid = 1, + .name = "func", + .params = duplex_params_audio_func, + .nparams = ARRAY_SIZE(duplex_params_audio_func), + },{ + .nid = 2, + .name = "dac", + .params = common_params_audio_dac, + .nparams = ARRAY_SIZE(common_params_audio_dac), + .stindex = 0, + },{ + .nid = 3, + .name = "out", + .params = common_params_audio_lineout, + .nparams = ARRAY_SIZE(common_params_audio_lineout), + .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | + (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) | + (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | + (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) | + 0x10), + .pinctl = AC_PINCTL_OUT_EN, + .conn = (uint32_t[]) { 2 }, + },{ + .nid = 4, + .name = "adc", + .params = duplex_params_audio_adc, + .nparams = ARRAY_SIZE(duplex_params_audio_adc), + .stindex = 1, + .conn = (uint32_t[]) { 5 }, + },{ + .nid = 5, + .name = "in", + .params = duplex_params_audio_linein, + .nparams = ARRAY_SIZE(duplex_params_audio_linein), + .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | + (AC_JACK_LINE_IN << AC_DEFCFG_DEVICE_SHIFT) | + (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | + (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) | + 0x20), + .pinctl = AC_PINCTL_IN_EN, + } +}; + +/* duplex: codec */ +static const desc_codec duplex = { + .name = "duplex", + .iid = QEMU_HDA_ID_DUPLEX, + .nodes = duplex_nodes, + .nnodes = ARRAY_SIZE(duplex_nodes), +}; + +/* -------------------------------------------------------------------------- */ + +static const char *fmt2name[] = { + [ AUD_FMT_U8 ] = "PCM-U8", + [ AUD_FMT_S8 ] = "PCM-S8", + [ AUD_FMT_U16 ] = "PCM-U16", + [ AUD_FMT_S16 ] = "PCM-S16", + [ AUD_FMT_U32 ] = "PCM-U32", + [ AUD_FMT_S32 ] = "PCM-S32", +}; + +typedef struct HDAAudioState HDAAudioState; +typedef struct HDAAudioStream HDAAudioStream; + +struct HDAAudioStream { + HDAAudioState *state; + const desc_node *node; + bool output, running; + uint32_t stream; + uint32_t channel; + uint32_t format; + uint32_t gain_left, gain_right; + bool mute_left, mute_right; + struct audsettings as; + union { + SWVoiceIn *in; + SWVoiceOut *out; + } voice; + uint8_t buf[HDA_BUFFER_SIZE]; + uint32_t bpos; +}; + +struct HDAAudioState { + HDACodecDevice hda; + const char *name; + + QEMUSoundCard card; + const desc_codec *desc; + HDAAudioStream st[4]; + bool running[16]; + + /* properties */ + uint32_t debug; +}; + +static void hda_audio_input_cb(void *opaque, int avail) +{ + HDAAudioStream *st = opaque; + int recv = 0; + int len; + bool rc; + + while (avail - recv >= sizeof(st->buf)) { + if (st->bpos != sizeof(st->buf)) { + len = AUD_read(st->voice.in, st->buf + st->bpos, + sizeof(st->buf) - st->bpos); + st->bpos += len; + recv += len; + if (st->bpos != sizeof(st->buf)) { + break; + } + } + rc = hda_codec_xfer(&st->state->hda, st->stream, false, + st->buf, sizeof(st->buf)); + if (!rc) { + break; + } + st->bpos = 0; + } +} + +static void hda_audio_output_cb(void *opaque, int avail) +{ + HDAAudioStream *st = opaque; + int sent = 0; + int len; + bool rc; + + while (avail - sent >= sizeof(st->buf)) { + if (st->bpos == sizeof(st->buf)) { + rc = hda_codec_xfer(&st->state->hda, st->stream, true, + st->buf, sizeof(st->buf)); + if (!rc) { + break; + } + st->bpos = 0; + } + len = AUD_write(st->voice.out, st->buf + st->bpos, + sizeof(st->buf) - st->bpos); + st->bpos += len; + sent += len; + if (st->bpos != sizeof(st->buf)) { + break; + } + } +} + +static void hda_audio_set_running(HDAAudioStream *st, bool running) +{ + if (st->node == NULL) { + return; + } + if (st->running == running) { + return; + } + st->running = running; + dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name, + st->running ? "on" : "off", st->stream); + if (st->output) { + AUD_set_active_out(st->voice.out, st->running); + } else { + AUD_set_active_in(st->voice.in, st->running); + } +} + +static void hda_audio_set_amp(HDAAudioStream *st) +{ + bool muted; + uint32_t left, right; + + if (st->node == NULL) { + return; + } + + muted = st->mute_left && st->mute_right; + left = st->mute_left ? 0 : st->gain_left; + right = st->mute_right ? 0 : st->gain_right; + + left = left * 255 / QEMU_HDA_AMP_STEPS; + right = right * 255 / QEMU_HDA_AMP_STEPS; + + if (st->output) { + AUD_set_volume_out(st->voice.out, muted, left, right); + } else { + AUD_set_volume_in(st->voice.in, muted, left, right); + } +} + +static void hda_audio_setup(HDAAudioStream *st) +{ + if (st->node == NULL) { + return; + } + + dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n", + st->node->name, st->as.nchannels, + fmt2name[st->as.fmt], st->as.freq); + + if (st->output) { + st->voice.out = AUD_open_out(&st->state->card, st->voice.out, + st->node->name, st, + hda_audio_output_cb, &st->as); + } else { + st->voice.in = AUD_open_in(&st->state->card, st->voice.in, + st->node->name, st, + hda_audio_input_cb, &st->as); + } +} + +static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data) +{ + HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); + HDAAudioStream *st; + const desc_node *node = NULL; + const desc_param *param; + uint32_t verb, payload, response, count, shift; + + if ((data & 0x70000) == 0x70000) { + /* 12/8 id/payload */ + verb = (data >> 8) & 0xfff; + payload = data & 0x00ff; + } else { + /* 4/16 id/payload */ + verb = (data >> 8) & 0xf00; + payload = data & 0xffff; + } + + node = hda_codec_find_node(a->desc, nid); + if (node == NULL) { + goto fail; + } + dprint(a, 2, "%s: nid %d (%s), verb 0x%x, payload 0x%x\n", + __FUNCTION__, nid, node->name, verb, payload); + + switch (verb) { + /* all nodes */ + case AC_VERB_PARAMETERS: + param = hda_codec_find_param(node, payload); + if (param == NULL) { + goto fail; + } + hda_codec_response(hda, true, param->val); + break; + case AC_VERB_GET_SUBSYSTEM_ID: + hda_codec_response(hda, true, a->desc->iid); + break; + + /* all functions */ + case AC_VERB_GET_CONNECT_LIST: + param = hda_codec_find_param(node, AC_PAR_CONNLIST_LEN); + count = param ? param->val : 0; + response = 0; + shift = 0; + while (payload < count && shift < 32) { + response |= node->conn[payload] << shift; + payload++; + shift += 8; + } + hda_codec_response(hda, true, response); + break; + + /* pin widget */ + case AC_VERB_GET_CONFIG_DEFAULT: + hda_codec_response(hda, true, node->config); + break; + case AC_VERB_GET_PIN_WIDGET_CONTROL: + hda_codec_response(hda, true, node->pinctl); + break; + case AC_VERB_SET_PIN_WIDGET_CONTROL: + if (node->pinctl != payload) { + dprint(a, 1, "unhandled pin control bit\n"); + } + hda_codec_response(hda, true, 0); + break; + + /* audio in/out widget */ + case AC_VERB_SET_CHANNEL_STREAMID: + st = a->st + node->stindex; + if (st->node == NULL) { + goto fail; + } + hda_audio_set_running(st, false); + st->stream = (payload >> 4) & 0x0f; + st->channel = payload & 0x0f; + dprint(a, 2, "%s: stream %d, channel %d\n", + st->node->name, st->stream, st->channel); + hda_audio_set_running(st, a->running[st->stream]); + hda_codec_response(hda, true, 0); + break; + case AC_VERB_GET_CONV: + st = a->st + node->stindex; + if (st->node == NULL) { + goto fail; + } + response = st->stream << 4 | st->channel; + hda_codec_response(hda, true, response); + break; + case AC_VERB_SET_STREAM_FORMAT: + st = a->st + node->stindex; + if (st->node == NULL) { + goto fail; + } + st->format = payload; + hda_codec_parse_fmt(st->format, &st->as); + hda_audio_setup(st); + hda_codec_response(hda, true, 0); + break; + case AC_VERB_GET_STREAM_FORMAT: + st = a->st + node->stindex; + if (st->node == NULL) { + goto fail; + } + hda_codec_response(hda, true, st->format); + break; + case AC_VERB_GET_AMP_GAIN_MUTE: + st = a->st + node->stindex; + if (st->node == NULL) { + goto fail; + } + if (payload & AC_AMP_GET_LEFT) { + response = st->gain_left | (st->mute_left ? AC_AMP_MUTE : 0); + } else { + response = st->gain_right | (st->mute_right ? AC_AMP_MUTE : 0); + } + hda_codec_response(hda, true, response); + break; + case AC_VERB_SET_AMP_GAIN_MUTE: + st = a->st + node->stindex; + if (st->node == NULL) { + goto fail; + } + dprint(a, 1, "amp (%s): %s%s%s%s index %d gain %3d %s\n", + st->node->name, + (payload & AC_AMP_SET_OUTPUT) ? "o" : "-", + (payload & AC_AMP_SET_INPUT) ? "i" : "-", + (payload & AC_AMP_SET_LEFT) ? "l" : "-", + (payload & AC_AMP_SET_RIGHT) ? "r" : "-", + (payload & AC_AMP_SET_INDEX) >> AC_AMP_SET_INDEX_SHIFT, + (payload & AC_AMP_GAIN), + (payload & AC_AMP_MUTE) ? "muted" : ""); + if (payload & AC_AMP_SET_LEFT) { + st->gain_left = payload & AC_AMP_GAIN; + st->mute_left = payload & AC_AMP_MUTE; + } + if (payload & AC_AMP_SET_RIGHT) { + st->gain_right = payload & AC_AMP_GAIN; + st->mute_right = payload & AC_AMP_MUTE; + } + hda_audio_set_amp(st); + hda_codec_response(hda, true, 0); + break; + + /* not supported */ + case AC_VERB_SET_POWER_STATE: + case AC_VERB_GET_POWER_STATE: + case AC_VERB_GET_SDI_SELECT: + hda_codec_response(hda, true, 0); + break; + default: + goto fail; + } + return; + +fail: + dprint(a, 1, "%s: not handled: nid %d (%s), verb 0x%x, payload 0x%x\n", + __FUNCTION__, nid, node ? node->name : "?", verb, payload); + hda_codec_response(hda, true, 0); +} + +static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running) +{ + HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); + int s; + + a->running[stnr] = running; + for (s = 0; s < ARRAY_SIZE(a->st); s++) { + if (a->st[s].node == NULL) { + continue; + } + if (a->st[s].stream != stnr) { + continue; + } + hda_audio_set_running(&a->st[s], running); + } +} + +static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) +{ + HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); + HDAAudioStream *st; + const desc_node *node; + const desc_param *param; + uint32_t i, type; + + a->desc = desc; + a->name = a->hda.qdev.info->name; + dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad); + + AUD_register_card("hda", &a->card); + for (i = 0; i < a->desc->nnodes; i++) { + node = a->desc->nodes + i; + param = hda_codec_find_param(node, AC_PAR_AUDIO_WIDGET_CAP); + if (NULL == param) + continue; + type = (param->val & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + switch (type) { + case AC_WID_AUD_OUT: + case AC_WID_AUD_IN: + assert(node->stindex < ARRAY_SIZE(a->st)); + st = a->st + node->stindex; + st->state = a; + st->node = node; + if (type == AC_WID_AUD_OUT) { + /* unmute output by default */ + st->gain_left = QEMU_HDA_AMP_STEPS; + st->gain_right = QEMU_HDA_AMP_STEPS; + st->bpos = sizeof(st->buf); + st->output = true; + } else { + st->output = false; + } + st->format = AC_FMT_TYPE_PCM | AC_FMT_BITS_16 | + (1 << AC_FMT_CHAN_SHIFT); + hda_codec_parse_fmt(st->format, &st->as); + hda_audio_setup(st); + break; + } + } + return 0; +} + +static int hda_audio_post_load(void *opaque, int version) +{ + HDAAudioState *a = opaque; + HDAAudioStream *st; + int i; + + dprint(a, 1, "%s\n", __FUNCTION__); + for (i = 0; i < ARRAY_SIZE(a->st); i++) { + st = a->st + i; + if (st->node == NULL) + continue; + hda_codec_parse_fmt(st->format, &st->as); + hda_audio_setup(st); + hda_audio_set_amp(st); + hda_audio_set_running(st, a->running[st->stream]); + } + return 0; +} + +static const VMStateDescription vmstate_hda_audio_stream = { + .name = "hda-audio-stream", + .version_id = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(stream, HDAAudioStream), + VMSTATE_UINT32(channel, HDAAudioStream), + VMSTATE_UINT32(format, HDAAudioStream), + VMSTATE_UINT32(gain_left, HDAAudioStream), + VMSTATE_UINT32(gain_right, HDAAudioStream), + VMSTATE_BOOL(mute_left, HDAAudioStream), + VMSTATE_BOOL(mute_right, HDAAudioStream), + VMSTATE_UINT32(bpos, HDAAudioStream), + VMSTATE_BUFFER(buf, HDAAudioStream), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_hda_audio = { + .name = "hda-audio", + .version_id = 1, + .post_load = hda_audio_post_load, + .fields = (VMStateField []) { + VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0, + vmstate_hda_audio_stream, + HDAAudioStream), + VMSTATE_BOOL_ARRAY(running, HDAAudioState, 16), + VMSTATE_END_OF_LIST() + } +}; + +static Property hda_audio_properties[] = { + DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static int hda_audio_init_output(HDACodecDevice *hda) +{ + return hda_audio_init(hda, &output); +} + +static int hda_audio_init_duplex(HDACodecDevice *hda) +{ + return hda_audio_init(hda, &duplex); +} + +static HDACodecDeviceInfo hda_audio_info_output = { + .qdev.name = "hda-output", + .qdev.desc = "HDA Audio Codec, output-only", + .qdev.size = sizeof(HDAAudioState), + .qdev.vmsd = &vmstate_hda_audio, + .qdev.props = hda_audio_properties, + .init = hda_audio_init_output, + .command = hda_audio_command, + .stream = hda_audio_stream, +}; + +static HDACodecDeviceInfo hda_audio_info_duplex = { + .qdev.name = "hda-duplex", + .qdev.desc = "HDA Audio Codec, duplex", + .qdev.size = sizeof(HDAAudioState), + .qdev.vmsd = &vmstate_hda_audio, + .qdev.props = hda_audio_properties, + .init = hda_audio_init_duplex, + .command = hda_audio_command, + .stream = hda_audio_stream, +}; + +static void hda_audio_register(void) +{ + hda_codec_register(&hda_audio_info_output); + hda_codec_register(&hda_audio_info_duplex); +} +device_init(hda_audio_register); @@ -333,6 +333,8 @@ struct VMStateDescription { const VMStateSubsection *subsections; }; +extern const VMStateInfo vmstate_info_bool; + extern const VMStateInfo vmstate_info_int8; extern const VMStateInfo vmstate_info_int16; extern const VMStateInfo vmstate_info_int32; @@ -602,6 +604,9 @@ extern const VMStateDescription vmstate_i2c_slave; #define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) \ VMSTATE_STRUCT_POINTER_TEST(_field, _state, NULL, _vmsd, _type) +#define VMSTATE_BOOL_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, vmstate_info_bool, bool) + #define VMSTATE_INT8_V(_f, _s, _v) \ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int8, int8_t) #define VMSTATE_INT16_V(_f, _s, _v) \ @@ -620,6 +625,9 @@ extern const VMStateDescription vmstate_i2c_slave; #define VMSTATE_UINT64_V(_f, _s, _v) \ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64, uint64_t) +#define VMSTATE_BOOL(_f, _s) \ + VMSTATE_BOOL_V(_f, _s, 0) + #define VMSTATE_INT8(_f, _s) \ VMSTATE_INT8_V(_f, _s, 0) #define VMSTATE_INT16(_f, _s) \ @@ -674,6 +682,12 @@ extern const VMStateDescription vmstate_i2c_slave; #define VMSTATE_PTIMER(_f, _s) \ VMSTATE_PTIMER_V(_f, _s, 0) +#define VMSTATE_BOOL_ARRAY_V(_f, _s, _n, _v) \ + VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_bool, bool) + +#define VMSTATE_BOOL_ARRAY(_f, _s, _n) \ + VMSTATE_BOOL_ARRAY_V(_f, _s, _n, 0) + #define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v) \ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t) diff --git a/hw/ide/core.c b/hw/ide/core.c index 06b6e14e56..bc3e91658a 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -65,6 +65,7 @@ static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb); static void ide_dma_restart(IDEState *s, int is_read); static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret); static int ide_handle_rw_error(IDEState *s, int error, int op); +static void ide_flush_cache(IDEState *s); static void padstr(char *str, const char *src, int len) { @@ -146,8 +147,8 @@ static void ide_identify(IDEState *s) put_le16(p + 68, 120); put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */ put_le16(p + 81, 0x16); /* conforms to ata5 */ - /* 14=NOP supported, 0=SMART supported */ - put_le16(p + 82, (1 << 14) | 1); + /* 14=NOP supported, 5=WCACHE supported, 0=SMART supported */ + put_le16(p + 82, (1 << 14) | (1 << 5) | 1); /* 13=flush_cache_ext,12=flush_cache,10=lba48 */ put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); /* 14=set to 1, 1=SMART self test, 0=SMART error logging */ @@ -688,6 +689,8 @@ static void ide_dma_restart_bh(void *opaque) } else { ide_sector_write(bmdma_active_if(bm)); } + } else if (bm->status & BM_STATUS_RETRY_FLUSH) { + ide_flush_cache(bmdma_active_if(bm)); } } @@ -795,12 +798,26 @@ static void ide_flush_cb(void *opaque, int ret) { IDEState *s = opaque; - /* XXX: how do we signal I/O errors here? */ + if (ret < 0) { + /* XXX: What sector number to set here? */ + if (ide_handle_rw_error(s, -ret, BM_STATUS_RETRY_FLUSH)) { + return; + } + } s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); } +static void ide_flush_cache(IDEState *s) +{ + if (s->bs) { + bdrv_aio_flush(s->bs, ide_flush_cb, s); + } else { + ide_flush_cb(s, 0); + } +} + static inline void cpu_to_ube16(uint8_t *buf, int val) { buf[0] = val >> 8; @@ -2031,10 +2048,7 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case WIN_FLUSH_CACHE: case WIN_FLUSH_CACHE_EXT: - if (s->bs) - bdrv_aio_flush(s->bs, ide_flush_cb, s); - else - ide_flush_cb(s, 0); + ide_flush_cache(s); break; case WIN_STANDBY: case WIN_STANDBY2: diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 416554324c..d652e06c45 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -472,7 +472,8 @@ struct IDEDeviceInfo { #define BM_STATUS_INT 0x04 #define BM_STATUS_DMA_RETRY 0x08 #define BM_STATUS_PIO_RETRY 0x10 -#define BM_STATUS_RETRY_READ 0x20 +#define BM_STATUS_RETRY_READ 0x20 +#define BM_STATUS_RETRY_FLUSH 0x40 #define BM_CMD_START 0x01 #define BM_CMD_READ 0x08 diff --git a/hw/intel-hda-defs.h b/hw/intel-hda-defs.h new file mode 100644 index 0000000000..2e37e5b874 --- /dev/null +++ b/hw/intel-hda-defs.h @@ -0,0 +1,717 @@ +#ifndef HW_INTEL_HDA_DEFS_H +#define HW_INTEL_HDA_DEFS_H + +/* qemu */ +#define HDA_BUFFER_SIZE 256 + +/* --------------------------------------------------------------------- */ +/* from linux/sound/pci/hda/hda_intel.c */ + +/* + * registers + */ +#define ICH6_REG_GCAP 0x00 +#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */ +#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */ +#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */ +#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */ +#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */ +#define ICH6_REG_VMIN 0x02 +#define ICH6_REG_VMAJ 0x03 +#define ICH6_REG_OUTPAY 0x04 +#define ICH6_REG_INPAY 0x06 +#define ICH6_REG_GCTL 0x08 +#define ICH6_GCTL_RESET (1 << 0) /* controller reset */ +#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */ +#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ +#define ICH6_REG_WAKEEN 0x0c +#define ICH6_REG_STATESTS 0x0e +#define ICH6_REG_GSTS 0x10 +#define ICH6_GSTS_FSTS (1 << 1) /* flush status */ +#define ICH6_REG_INTCTL 0x20 +#define ICH6_REG_INTSTS 0x24 +#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */ +#define ICH6_REG_SYNC 0x34 +#define ICH6_REG_CORBLBASE 0x40 +#define ICH6_REG_CORBUBASE 0x44 +#define ICH6_REG_CORBWP 0x48 +#define ICH6_REG_CORBRP 0x4a +#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */ +#define ICH6_REG_CORBCTL 0x4c +#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */ +#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ +#define ICH6_REG_CORBSTS 0x4d +#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */ +#define ICH6_REG_CORBSIZE 0x4e + +#define ICH6_REG_RIRBLBASE 0x50 +#define ICH6_REG_RIRBUBASE 0x54 +#define ICH6_REG_RIRBWP 0x58 +#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */ +#define ICH6_REG_RINTCNT 0x5a +#define ICH6_REG_RIRBCTL 0x5c +#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ +#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */ +#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ +#define ICH6_REG_RIRBSTS 0x5d +#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */ +#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */ +#define ICH6_REG_RIRBSIZE 0x5e + +#define ICH6_REG_IC 0x60 +#define ICH6_REG_IR 0x64 +#define ICH6_REG_IRS 0x68 +#define ICH6_IRS_VALID (1<<1) +#define ICH6_IRS_BUSY (1<<0) + +#define ICH6_REG_DPLBASE 0x70 +#define ICH6_REG_DPUBASE 0x74 +#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */ + +/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ +enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; + +/* stream register offsets from stream base */ +#define ICH6_REG_SD_CTL 0x00 +#define ICH6_REG_SD_STS 0x03 +#define ICH6_REG_SD_LPIB 0x04 +#define ICH6_REG_SD_CBL 0x08 +#define ICH6_REG_SD_LVI 0x0c +#define ICH6_REG_SD_FIFOW 0x0e +#define ICH6_REG_SD_FIFOSIZE 0x10 +#define ICH6_REG_SD_FORMAT 0x12 +#define ICH6_REG_SD_BDLPL 0x18 +#define ICH6_REG_SD_BDLPU 0x1c + +/* PCI space */ +#define ICH6_PCIREG_TCSEL 0x44 + +/* + * other constants + */ + +/* max number of SDs */ +/* ICH, ATI and VIA have 4 playback and 4 capture */ +#define ICH6_NUM_CAPTURE 4 +#define ICH6_NUM_PLAYBACK 4 + +/* ULI has 6 playback and 5 capture */ +#define ULI_NUM_CAPTURE 5 +#define ULI_NUM_PLAYBACK 6 + +/* ATI HDMI has 1 playback and 0 capture */ +#define ATIHDMI_NUM_CAPTURE 0 +#define ATIHDMI_NUM_PLAYBACK 1 + +/* TERA has 4 playback and 3 capture */ +#define TERA_NUM_CAPTURE 3 +#define TERA_NUM_PLAYBACK 4 + +/* this number is statically defined for simplicity */ +#define MAX_AZX_DEV 16 + +/* max number of fragments - we may use more if allocating more pages for BDL */ +#define BDL_SIZE 4096 +#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) +#define AZX_MAX_FRAG 32 +/* max buffer size - no h/w limit, you can increase as you like */ +#define AZX_MAX_BUF_SIZE (1024*1024*1024) + +/* RIRB int mask: overrun[2], response[0] */ +#define RIRB_INT_RESPONSE 0x01 +#define RIRB_INT_OVERRUN 0x04 +#define RIRB_INT_MASK 0x05 + +/* STATESTS int mask: S3,SD2,SD1,SD0 */ +#define AZX_MAX_CODECS 8 +#define AZX_DEFAULT_CODECS 4 +#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1) + +/* SD_CTL bits */ +#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ +#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */ +#define SD_CTL_STRIPE (3 << 16) /* stripe control */ +#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */ +#define SD_CTL_DIR (1 << 19) /* bi-directional stream */ +#define SD_CTL_STREAM_TAG_MASK (0xf << 20) +#define SD_CTL_STREAM_TAG_SHIFT 20 + +/* SD_CTL and SD_STS */ +#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ +#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ +#define SD_INT_COMPLETE 0x04 /* completion interrupt */ +#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ + SD_INT_COMPLETE) + +/* SD_STS */ +#define SD_STS_FIFO_READY 0x20 /* FIFO ready */ + +/* INTCTL and INTSTS */ +#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ +#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ +#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ + +/* below are so far hardcoded - should read registers in future */ +#define ICH6_MAX_CORB_ENTRIES 256 +#define ICH6_MAX_RIRB_ENTRIES 256 + +/* position fix mode */ +enum { + POS_FIX_AUTO, + POS_FIX_LPIB, + POS_FIX_POSBUF, +}; + +/* Defines for ATI HD Audio support in SB450 south bridge */ +#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 +#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 + +/* Defines for Nvidia HDA support */ +#define NVIDIA_HDA_TRANSREG_ADDR 0x4e +#define NVIDIA_HDA_ENABLE_COHBITS 0x0f +#define NVIDIA_HDA_ISTRM_COH 0x4d +#define NVIDIA_HDA_OSTRM_COH 0x4c +#define NVIDIA_HDA_ENABLE_COHBIT 0x01 + +/* Defines for Intel SCH HDA snoop control */ +#define INTEL_SCH_HDA_DEVC 0x78 +#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) + +/* Define IN stream 0 FIFO size offset in VIA controller */ +#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 +/* Define VIA HD Audio Device ID*/ +#define VIA_HDAC_DEVICE_ID 0x3288 + +/* HD Audio class code */ +#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 + +/* --------------------------------------------------------------------- */ +/* from linux/sound/pci/hda/hda_codec.h */ + +/* + * nodes + */ +#define AC_NODE_ROOT 0x00 + +/* + * function group types + */ +enum { + AC_GRP_AUDIO_FUNCTION = 0x01, + AC_GRP_MODEM_FUNCTION = 0x02, +}; + +/* + * widget types + */ +enum { + AC_WID_AUD_OUT, /* Audio Out */ + AC_WID_AUD_IN, /* Audio In */ + AC_WID_AUD_MIX, /* Audio Mixer */ + AC_WID_AUD_SEL, /* Audio Selector */ + AC_WID_PIN, /* Pin Complex */ + AC_WID_POWER, /* Power */ + AC_WID_VOL_KNB, /* Volume Knob */ + AC_WID_BEEP, /* Beep Generator */ + AC_WID_VENDOR = 0x0f /* Vendor specific */ +}; + +/* + * GET verbs + */ +#define AC_VERB_GET_STREAM_FORMAT 0x0a00 +#define AC_VERB_GET_AMP_GAIN_MUTE 0x0b00 +#define AC_VERB_GET_PROC_COEF 0x0c00 +#define AC_VERB_GET_COEF_INDEX 0x0d00 +#define AC_VERB_PARAMETERS 0x0f00 +#define AC_VERB_GET_CONNECT_SEL 0x0f01 +#define AC_VERB_GET_CONNECT_LIST 0x0f02 +#define AC_VERB_GET_PROC_STATE 0x0f03 +#define AC_VERB_GET_SDI_SELECT 0x0f04 +#define AC_VERB_GET_POWER_STATE 0x0f05 +#define AC_VERB_GET_CONV 0x0f06 +#define AC_VERB_GET_PIN_WIDGET_CONTROL 0x0f07 +#define AC_VERB_GET_UNSOLICITED_RESPONSE 0x0f08 +#define AC_VERB_GET_PIN_SENSE 0x0f09 +#define AC_VERB_GET_BEEP_CONTROL 0x0f0a +#define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c +#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d +#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */ +#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f +/* f10-f1a: GPIO */ +#define AC_VERB_GET_GPIO_DATA 0x0f15 +#define AC_VERB_GET_GPIO_MASK 0x0f16 +#define AC_VERB_GET_GPIO_DIRECTION 0x0f17 +#define AC_VERB_GET_GPIO_WAKE_MASK 0x0f18 +#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK 0x0f19 +#define AC_VERB_GET_GPIO_STICKY_MASK 0x0f1a +#define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c +/* f20: AFG/MFG */ +#define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 +#define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d +#define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e +#define AC_VERB_GET_HDMI_ELDD 0x0f2f +#define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30 +#define AC_VERB_GET_HDMI_DIP_DATA 0x0f31 +#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 +#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 +#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 + +/* + * SET verbs + */ +#define AC_VERB_SET_STREAM_FORMAT 0x200 +#define AC_VERB_SET_AMP_GAIN_MUTE 0x300 +#define AC_VERB_SET_PROC_COEF 0x400 +#define AC_VERB_SET_COEF_INDEX 0x500 +#define AC_VERB_SET_CONNECT_SEL 0x701 +#define AC_VERB_SET_PROC_STATE 0x703 +#define AC_VERB_SET_SDI_SELECT 0x704 +#define AC_VERB_SET_POWER_STATE 0x705 +#define AC_VERB_SET_CHANNEL_STREAMID 0x706 +#define AC_VERB_SET_PIN_WIDGET_CONTROL 0x707 +#define AC_VERB_SET_UNSOLICITED_ENABLE 0x708 +#define AC_VERB_SET_PIN_SENSE 0x709 +#define AC_VERB_SET_BEEP_CONTROL 0x70a +#define AC_VERB_SET_EAPD_BTLENABLE 0x70c +#define AC_VERB_SET_DIGI_CONVERT_1 0x70d +#define AC_VERB_SET_DIGI_CONVERT_2 0x70e +#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f +#define AC_VERB_SET_GPIO_DATA 0x715 +#define AC_VERB_SET_GPIO_MASK 0x716 +#define AC_VERB_SET_GPIO_DIRECTION 0x717 +#define AC_VERB_SET_GPIO_WAKE_MASK 0x718 +#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK 0x719 +#define AC_VERB_SET_GPIO_STICKY_MASK 0x71a +#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c +#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d +#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e +#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f +#define AC_VERB_SET_EAPD 0x788 +#define AC_VERB_SET_CODEC_RESET 0x7ff +#define AC_VERB_SET_CVT_CHAN_COUNT 0x72d +#define AC_VERB_SET_HDMI_DIP_INDEX 0x730 +#define AC_VERB_SET_HDMI_DIP_DATA 0x731 +#define AC_VERB_SET_HDMI_DIP_XMIT 0x732 +#define AC_VERB_SET_HDMI_CP_CTRL 0x733 +#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 + +/* + * Parameter IDs + */ +#define AC_PAR_VENDOR_ID 0x00 +#define AC_PAR_SUBSYSTEM_ID 0x01 +#define AC_PAR_REV_ID 0x02 +#define AC_PAR_NODE_COUNT 0x04 +#define AC_PAR_FUNCTION_TYPE 0x05 +#define AC_PAR_AUDIO_FG_CAP 0x08 +#define AC_PAR_AUDIO_WIDGET_CAP 0x09 +#define AC_PAR_PCM 0x0a +#define AC_PAR_STREAM 0x0b +#define AC_PAR_PIN_CAP 0x0c +#define AC_PAR_AMP_IN_CAP 0x0d +#define AC_PAR_CONNLIST_LEN 0x0e +#define AC_PAR_POWER_STATE 0x0f +#define AC_PAR_PROC_CAP 0x10 +#define AC_PAR_GPIO_CAP 0x11 +#define AC_PAR_AMP_OUT_CAP 0x12 +#define AC_PAR_VOL_KNB_CAP 0x13 +#define AC_PAR_HDMI_LPCM_CAP 0x20 + +/* + * AC_VERB_PARAMETERS results (32bit) + */ + +/* Function Group Type */ +#define AC_FGT_TYPE (0xff<<0) +#define AC_FGT_TYPE_SHIFT 0 +#define AC_FGT_UNSOL_CAP (1<<8) + +/* Audio Function Group Capabilities */ +#define AC_AFG_OUT_DELAY (0xf<<0) +#define AC_AFG_IN_DELAY (0xf<<8) +#define AC_AFG_BEEP_GEN (1<<16) + +/* Audio Widget Capabilities */ +#define AC_WCAP_STEREO (1<<0) /* stereo I/O */ +#define AC_WCAP_IN_AMP (1<<1) /* AMP-in present */ +#define AC_WCAP_OUT_AMP (1<<2) /* AMP-out present */ +#define AC_WCAP_AMP_OVRD (1<<3) /* AMP-parameter override */ +#define AC_WCAP_FORMAT_OVRD (1<<4) /* format override */ +#define AC_WCAP_STRIPE (1<<5) /* stripe */ +#define AC_WCAP_PROC_WID (1<<6) /* Proc Widget */ +#define AC_WCAP_UNSOL_CAP (1<<7) /* Unsol capable */ +#define AC_WCAP_CONN_LIST (1<<8) /* connection list */ +#define AC_WCAP_DIGITAL (1<<9) /* digital I/O */ +#define AC_WCAP_POWER (1<<10) /* power control */ +#define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */ +#define AC_WCAP_CP_CAPS (1<<12) /* content protection */ +#define AC_WCAP_CHAN_CNT_EXT (7<<13) /* channel count ext */ +#define AC_WCAP_DELAY (0xf<<16) +#define AC_WCAP_DELAY_SHIFT 16 +#define AC_WCAP_TYPE (0xf<<20) +#define AC_WCAP_TYPE_SHIFT 20 + +/* supported PCM rates and bits */ +#define AC_SUPPCM_RATES (0xfff << 0) +#define AC_SUPPCM_BITS_8 (1<<16) +#define AC_SUPPCM_BITS_16 (1<<17) +#define AC_SUPPCM_BITS_20 (1<<18) +#define AC_SUPPCM_BITS_24 (1<<19) +#define AC_SUPPCM_BITS_32 (1<<20) + +/* supported PCM stream format */ +#define AC_SUPFMT_PCM (1<<0) +#define AC_SUPFMT_FLOAT32 (1<<1) +#define AC_SUPFMT_AC3 (1<<2) + +/* GP I/O count */ +#define AC_GPIO_IO_COUNT (0xff<<0) +#define AC_GPIO_O_COUNT (0xff<<8) +#define AC_GPIO_O_COUNT_SHIFT 8 +#define AC_GPIO_I_COUNT (0xff<<16) +#define AC_GPIO_I_COUNT_SHIFT 16 +#define AC_GPIO_UNSOLICITED (1<<30) +#define AC_GPIO_WAKE (1<<31) + +/* Converter stream, channel */ +#define AC_CONV_CHANNEL (0xf<<0) +#define AC_CONV_STREAM (0xf<<4) +#define AC_CONV_STREAM_SHIFT 4 + +/* Input converter SDI select */ +#define AC_SDI_SELECT (0xf<<0) + +/* stream format id */ +#define AC_FMT_CHAN_SHIFT 0 +#define AC_FMT_CHAN_MASK (0x0f << 0) +#define AC_FMT_BITS_SHIFT 4 +#define AC_FMT_BITS_MASK (7 << 4) +#define AC_FMT_BITS_8 (0 << 4) +#define AC_FMT_BITS_16 (1 << 4) +#define AC_FMT_BITS_20 (2 << 4) +#define AC_FMT_BITS_24 (3 << 4) +#define AC_FMT_BITS_32 (4 << 4) +#define AC_FMT_DIV_SHIFT 8 +#define AC_FMT_DIV_MASK (7 << 8) +#define AC_FMT_MULT_SHIFT 11 +#define AC_FMT_MULT_MASK (7 << 11) +#define AC_FMT_BASE_SHIFT 14 +#define AC_FMT_BASE_48K (0 << 14) +#define AC_FMT_BASE_44K (1 << 14) +#define AC_FMT_TYPE_SHIFT 15 +#define AC_FMT_TYPE_PCM (0 << 15) +#define AC_FMT_TYPE_NON_PCM (1 << 15) + +/* Unsolicited response control */ +#define AC_UNSOL_TAG (0x3f<<0) +#define AC_UNSOL_ENABLED (1<<7) +#define AC_USRSP_EN AC_UNSOL_ENABLED + +/* Unsolicited responses */ +#define AC_UNSOL_RES_TAG (0x3f<<26) +#define AC_UNSOL_RES_TAG_SHIFT 26 +#define AC_UNSOL_RES_SUBTAG (0x1f<<21) +#define AC_UNSOL_RES_SUBTAG_SHIFT 21 +#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */ +#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */ +#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */ +#define AC_UNSOL_RES_CP_READY (1<<0) /* content protection */ + +/* Pin widget capabilies */ +#define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ +#define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */ +#define AC_PINCAP_PRES_DETECT (1<<2) /* presence detect capable */ +#define AC_PINCAP_HP_DRV (1<<3) /* headphone drive capable */ +#define AC_PINCAP_OUT (1<<4) /* output capable */ +#define AC_PINCAP_IN (1<<5) /* input capable */ +#define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ +/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification, + * but is marked reserved in the Intel HDA specification. + */ +#define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */ +/* Note: The same bit as LR_SWAP is newly defined as HDMI capability + * in HD-audio specification + */ +#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */ +#define AC_PINCAP_DP (1<<24) /* DisplayPort pin, can + * coexist with AC_PINCAP_HDMI + */ +#define AC_PINCAP_VREF (0x37<<8) +#define AC_PINCAP_VREF_SHIFT 8 +#define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ +#define AC_PINCAP_HBR (1<<27) /* High Bit Rate */ +/* Vref status (used in pin cap) */ +#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */ +#define AC_PINCAP_VREF_50 (1<<1) /* 50% */ +#define AC_PINCAP_VREF_GRD (1<<2) /* ground */ +#define AC_PINCAP_VREF_80 (1<<4) /* 80% */ +#define AC_PINCAP_VREF_100 (1<<5) /* 100% */ + +/* Amplifier capabilities */ +#define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */ +#define AC_AMPCAP_OFFSET_SHIFT 0 +#define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ +#define AC_AMPCAP_NUM_STEPS_SHIFT 8 +#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB + * in 0.25dB + */ +#define AC_AMPCAP_STEP_SIZE_SHIFT 16 +#define AC_AMPCAP_MUTE (1<<31) /* mute capable */ +#define AC_AMPCAP_MUTE_SHIFT 31 + +/* Connection list */ +#define AC_CLIST_LENGTH (0x7f<<0) +#define AC_CLIST_LONG (1<<7) + +/* Supported power status */ +#define AC_PWRST_D0SUP (1<<0) +#define AC_PWRST_D1SUP (1<<1) +#define AC_PWRST_D2SUP (1<<2) +#define AC_PWRST_D3SUP (1<<3) +#define AC_PWRST_D3COLDSUP (1<<4) +#define AC_PWRST_S3D3COLDSUP (1<<29) +#define AC_PWRST_CLKSTOP (1<<30) +#define AC_PWRST_EPSS (1U<<31) + +/* Power state values */ +#define AC_PWRST_SETTING (0xf<<0) +#define AC_PWRST_ACTUAL (0xf<<4) +#define AC_PWRST_ACTUAL_SHIFT 4 +#define AC_PWRST_D0 0x00 +#define AC_PWRST_D1 0x01 +#define AC_PWRST_D2 0x02 +#define AC_PWRST_D3 0x03 + +/* Processing capabilies */ +#define AC_PCAP_BENIGN (1<<0) +#define AC_PCAP_NUM_COEF (0xff<<8) +#define AC_PCAP_NUM_COEF_SHIFT 8 + +/* Volume knobs capabilities */ +#define AC_KNBCAP_NUM_STEPS (0x7f<<0) +#define AC_KNBCAP_DELTA (1<<7) + +/* HDMI LPCM capabilities */ +#define AC_LPCMCAP_48K_CP_CHNS (0x0f<<0) /* max channels w/ CP-on */ +#define AC_LPCMCAP_48K_NO_CHNS (0x0f<<4) /* max channels w/o CP-on */ +#define AC_LPCMCAP_48K_20BIT (1<<8) /* 20b bitrate supported */ +#define AC_LPCMCAP_48K_24BIT (1<<9) /* 24b bitrate supported */ +#define AC_LPCMCAP_96K_CP_CHNS (0x0f<<10) /* max channels w/ CP-on */ +#define AC_LPCMCAP_96K_NO_CHNS (0x0f<<14) /* max channels w/o CP-on */ +#define AC_LPCMCAP_96K_20BIT (1<<18) /* 20b bitrate supported */ +#define AC_LPCMCAP_96K_24BIT (1<<19) /* 24b bitrate supported */ +#define AC_LPCMCAP_192K_CP_CHNS (0x0f<<20) /* max channels w/ CP-on */ +#define AC_LPCMCAP_192K_NO_CHNS (0x0f<<24) /* max channels w/o CP-on */ +#define AC_LPCMCAP_192K_20BIT (1<<28) /* 20b bitrate supported */ +#define AC_LPCMCAP_192K_24BIT (1<<29) /* 24b bitrate supported */ +#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */ +#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */ + +/* + * Control Parameters + */ + +/* Amp gain/mute */ +#define AC_AMP_MUTE (1<<7) +#define AC_AMP_GAIN (0x7f) +#define AC_AMP_GET_INDEX (0xf<<0) + +#define AC_AMP_GET_LEFT (1<<13) +#define AC_AMP_GET_RIGHT (0<<13) +#define AC_AMP_GET_OUTPUT (1<<15) +#define AC_AMP_GET_INPUT (0<<15) + +#define AC_AMP_SET_INDEX (0xf<<8) +#define AC_AMP_SET_INDEX_SHIFT 8 +#define AC_AMP_SET_RIGHT (1<<12) +#define AC_AMP_SET_LEFT (1<<13) +#define AC_AMP_SET_INPUT (1<<14) +#define AC_AMP_SET_OUTPUT (1<<15) + +/* DIGITAL1 bits */ +#define AC_DIG1_ENABLE (1<<0) +#define AC_DIG1_V (1<<1) +#define AC_DIG1_VCFG (1<<2) +#define AC_DIG1_EMPHASIS (1<<3) +#define AC_DIG1_COPYRIGHT (1<<4) +#define AC_DIG1_NONAUDIO (1<<5) +#define AC_DIG1_PROFESSIONAL (1<<6) +#define AC_DIG1_LEVEL (1<<7) + +/* DIGITAL2 bits */ +#define AC_DIG2_CC (0x7f<<0) + +/* Pin widget control - 8bit */ +#define AC_PINCTL_EPT (0x3<<0) +#define AC_PINCTL_EPT_NATIVE 0 +#define AC_PINCTL_EPT_HBR 3 +#define AC_PINCTL_VREFEN (0x7<<0) +#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ +#define AC_PINCTL_VREF_50 1 /* 50% */ +#define AC_PINCTL_VREF_GRD 2 /* ground */ +#define AC_PINCTL_VREF_80 4 /* 80% */ +#define AC_PINCTL_VREF_100 5 /* 100% */ +#define AC_PINCTL_IN_EN (1<<5) +#define AC_PINCTL_OUT_EN (1<<6) +#define AC_PINCTL_HP_EN (1<<7) + +/* Pin sense - 32bit */ +#define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff) +#define AC_PINSENSE_PRESENCE (1<<31) +#define AC_PINSENSE_ELDV (1<<30) /* ELD valid (HDMI) */ + +/* EAPD/BTL enable - 32bit */ +#define AC_EAPDBTL_BALANCED (1<<0) +#define AC_EAPDBTL_EAPD (1<<1) +#define AC_EAPDBTL_LR_SWAP (1<<2) + +/* HDMI ELD data */ +#define AC_ELDD_ELD_VALID (1<<31) +#define AC_ELDD_ELD_DATA 0xff + +/* HDMI DIP size */ +#define AC_DIPSIZE_ELD_BUF (1<<3) /* ELD buf size of packet size */ +#define AC_DIPSIZE_PACK_IDX (0x07<<0) /* packet index */ + +/* HDMI DIP index */ +#define AC_DIPIDX_PACK_IDX (0x07<<5) /* packet idnex */ +#define AC_DIPIDX_BYTE_IDX (0x1f<<0) /* byte index */ + +/* HDMI DIP xmit (transmit) control */ +#define AC_DIPXMIT_MASK (0x3<<6) +#define AC_DIPXMIT_DISABLE (0x0<<6) /* disable xmit */ +#define AC_DIPXMIT_ONCE (0x2<<6) /* xmit once then disable */ +#define AC_DIPXMIT_BEST (0x3<<6) /* best effort */ + +/* HDMI content protection (CP) control */ +#define AC_CPCTRL_CES (1<<9) /* current encryption state */ +#define AC_CPCTRL_READY (1<<8) /* ready bit */ +#define AC_CPCTRL_SUBTAG (0x1f<<3) /* subtag for unsol-resp */ +#define AC_CPCTRL_STATE (3<<0) /* current CP request state */ + +/* Converter channel <-> HDMI slot mapping */ +#define AC_CVTMAP_HDMI_SLOT (0xf<<0) /* HDMI slot number */ +#define AC_CVTMAP_CHAN (0xf<<4) /* converter channel number */ + +/* configuration default - 32bit */ +#define AC_DEFCFG_SEQUENCE (0xf<<0) +#define AC_DEFCFG_DEF_ASSOC (0xf<<4) +#define AC_DEFCFG_ASSOC_SHIFT 4 +#define AC_DEFCFG_MISC (0xf<<8) +#define AC_DEFCFG_MISC_SHIFT 8 +#define AC_DEFCFG_MISC_NO_PRESENCE (1<<0) +#define AC_DEFCFG_COLOR (0xf<<12) +#define AC_DEFCFG_COLOR_SHIFT 12 +#define AC_DEFCFG_CONN_TYPE (0xf<<16) +#define AC_DEFCFG_CONN_TYPE_SHIFT 16 +#define AC_DEFCFG_DEVICE (0xf<<20) +#define AC_DEFCFG_DEVICE_SHIFT 20 +#define AC_DEFCFG_LOCATION (0x3f<<24) +#define AC_DEFCFG_LOCATION_SHIFT 24 +#define AC_DEFCFG_PORT_CONN (0x3<<30) +#define AC_DEFCFG_PORT_CONN_SHIFT 30 + +/* device device types (0x0-0xf) */ +enum { + AC_JACK_LINE_OUT, + AC_JACK_SPEAKER, + AC_JACK_HP_OUT, + AC_JACK_CD, + AC_JACK_SPDIF_OUT, + AC_JACK_DIG_OTHER_OUT, + AC_JACK_MODEM_LINE_SIDE, + AC_JACK_MODEM_HAND_SIDE, + AC_JACK_LINE_IN, + AC_JACK_AUX, + AC_JACK_MIC_IN, + AC_JACK_TELEPHONY, + AC_JACK_SPDIF_IN, + AC_JACK_DIG_OTHER_IN, + AC_JACK_OTHER = 0xf, +}; + +/* jack connection types (0x0-0xf) */ +enum { + AC_JACK_CONN_UNKNOWN, + AC_JACK_CONN_1_8, + AC_JACK_CONN_1_4, + AC_JACK_CONN_ATAPI, + AC_JACK_CONN_RCA, + AC_JACK_CONN_OPTICAL, + AC_JACK_CONN_OTHER_DIGITAL, + AC_JACK_CONN_OTHER_ANALOG, + AC_JACK_CONN_DIN, + AC_JACK_CONN_XLR, + AC_JACK_CONN_RJ11, + AC_JACK_CONN_COMB, + AC_JACK_CONN_OTHER = 0xf, +}; + +/* jack colors (0x0-0xf) */ +enum { + AC_JACK_COLOR_UNKNOWN, + AC_JACK_COLOR_BLACK, + AC_JACK_COLOR_GREY, + AC_JACK_COLOR_BLUE, + AC_JACK_COLOR_GREEN, + AC_JACK_COLOR_RED, + AC_JACK_COLOR_ORANGE, + AC_JACK_COLOR_YELLOW, + AC_JACK_COLOR_PURPLE, + AC_JACK_COLOR_PINK, + AC_JACK_COLOR_WHITE = 0xe, + AC_JACK_COLOR_OTHER, +}; + +/* Jack location (0x0-0x3f) */ +/* common case */ +enum { + AC_JACK_LOC_NONE, + AC_JACK_LOC_REAR, + AC_JACK_LOC_FRONT, + AC_JACK_LOC_LEFT, + AC_JACK_LOC_RIGHT, + AC_JACK_LOC_TOP, + AC_JACK_LOC_BOTTOM, +}; +/* bits 4-5 */ +enum { + AC_JACK_LOC_EXTERNAL = 0x00, + AC_JACK_LOC_INTERNAL = 0x10, + AC_JACK_LOC_SEPARATE = 0x20, + AC_JACK_LOC_OTHER = 0x30, +}; +enum { + /* external on primary chasis */ + AC_JACK_LOC_REAR_PANEL = 0x07, + AC_JACK_LOC_DRIVE_BAY, + /* internal */ + AC_JACK_LOC_RISER = 0x17, + AC_JACK_LOC_HDMI, + AC_JACK_LOC_ATAPI, + /* others */ + AC_JACK_LOC_MOBILE_IN = 0x37, + AC_JACK_LOC_MOBILE_OUT, +}; + +/* Port connectivity (0-3) */ +enum { + AC_JACK_PORT_COMPLEX, + AC_JACK_PORT_NONE, + AC_JACK_PORT_FIXED, + AC_JACK_PORT_BOTH, +}; + +/* max. connections to a widget */ +#define HDA_MAX_CONNECTIONS 32 + +/* max. codec address */ +#define HDA_MAX_CODEC_ADDRESS 0x0f + +/* max number of PCM devics per card */ +#define HDA_MAX_PCMS 10 + +/* --------------------------------------------------------------------- */ + +#endif diff --git a/hw/intel-hda.c b/hw/intel-hda.c new file mode 100644 index 0000000000..ccb059dc92 --- /dev/null +++ b/hw/intel-hda.c @@ -0,0 +1,1250 @@ +/* + * Copyright (C) 2010 Red Hat, Inc. + * + * written by Gerd Hoffmann <kraxel@redhat.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw.h" +#include "pci.h" +#include "qemu-timer.h" +#include "audiodev.h" +#include "intel-hda.h" +#include "intel-hda-defs.h" + +/* --------------------------------------------------------------------- */ +/* hda bus */ + +static struct BusInfo hda_codec_bus_info = { + .name = "HDA", + .size = sizeof(HDACodecBus), + .props = (Property[]) { + DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1), + DEFINE_PROP_END_OF_LIST() + } +}; + +void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, + hda_codec_response_func response, + hda_codec_xfer_func xfer) +{ + qbus_create_inplace(&bus->qbus, &hda_codec_bus_info, dev, NULL); + bus->response = response; + bus->xfer = xfer; +} + +static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base) +{ + HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus); + HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev); + HDACodecDeviceInfo *info = DO_UPCAST(HDACodecDeviceInfo, qdev, base); + + dev->info = info; + if (dev->cad == -1) { + dev->cad = bus->next_cad; + } + if (dev->cad > 15) + return -1; + bus->next_cad = dev->cad + 1; + return info->init(dev); +} + +void hda_codec_register(HDACodecDeviceInfo *info) +{ + info->qdev.init = hda_codec_dev_init; + info->qdev.bus_info = &hda_codec_bus_info; + qdev_register(&info->qdev); +} + +HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad) +{ + DeviceState *qdev; + HDACodecDevice *cdev; + + QLIST_FOREACH(qdev, &bus->qbus.children, sibling) { + cdev = DO_UPCAST(HDACodecDevice, qdev, qdev); + if (cdev->cad == cad) { + return cdev; + } + } + return NULL; +} + +void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response) +{ + HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); + bus->response(dev, solicited, response); +} + +bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, + uint8_t *buf, uint32_t len) +{ + HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); + return bus->xfer(dev, stnr, output, buf, len); +} + +/* --------------------------------------------------------------------- */ +/* intel hda emulation */ + +typedef struct IntelHDAStream IntelHDAStream; +typedef struct IntelHDAState IntelHDAState; +typedef struct IntelHDAReg IntelHDAReg; + +typedef struct bpl { + uint64_t addr; + uint32_t len; + uint32_t flags; +} bpl; + +struct IntelHDAStream { + /* registers */ + uint32_t ctl; + uint32_t lpib; + uint32_t cbl; + uint32_t lvi; + uint32_t fmt; + uint32_t bdlp_lbase; + uint32_t bdlp_ubase; + + /* state */ + bpl *bpl; + uint32_t bentries; + uint32_t bsize, be, bp; +}; + +struct IntelHDAState { + PCIDevice pci; + const char *name; + HDACodecBus codecs; + + /* registers */ + uint32_t g_ctl; + uint32_t wake_en; + uint32_t state_sts; + uint32_t int_ctl; + uint32_t int_sts; + uint32_t wall_clk; + + uint32_t corb_lbase; + uint32_t corb_ubase; + uint32_t corb_rp; + uint32_t corb_wp; + uint32_t corb_ctl; + uint32_t corb_sts; + uint32_t corb_size; + + uint32_t rirb_lbase; + uint32_t rirb_ubase; + uint32_t rirb_wp; + uint32_t rirb_cnt; + uint32_t rirb_ctl; + uint32_t rirb_sts; + uint32_t rirb_size; + + uint32_t dp_lbase; + uint32_t dp_ubase; + + uint32_t icw; + uint32_t irr; + uint32_t ics; + + /* streams */ + IntelHDAStream st[8]; + + /* state */ + int mmio_addr; + uint32_t rirb_count; + int64_t wall_base_ns; + + /* debug logging */ + const IntelHDAReg *last_reg; + uint32_t last_val; + uint32_t last_write; + uint32_t last_sec; + uint32_t repeat_count; + + /* properties */ + uint32_t debug; +}; + +struct IntelHDAReg { + const char *name; /* register name */ + uint32_t size; /* size in bytes */ + uint32_t reset; /* reset value */ + uint32_t wmask; /* write mask */ + uint32_t wclear; /* write 1 to clear bits */ + uint32_t offset; /* location in IntelHDAState */ + uint32_t shift; /* byte access entries for dwords */ + uint32_t stream; + void (*whandler)(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old); + void (*rhandler)(IntelHDAState *d, const IntelHDAReg *reg); +}; + +static void intel_hda_reset(DeviceState *dev); + +/* --------------------------------------------------------------------- */ + +static target_phys_addr_t intel_hda_addr(uint32_t lbase, uint32_t ubase) +{ + target_phys_addr_t addr; + +#if TARGET_PHYS_ADDR_BITS == 32 + addr = lbase; +#else + addr = ubase; + addr <<= 32; + addr |= lbase; +#endif + return addr; +} + +static void stl_phys_le(target_phys_addr_t addr, uint32_t value) +{ + uint32_t value_le = cpu_to_le32(value); + cpu_physical_memory_write(addr, (uint8_t*)(&value_le), sizeof(value_le)); +} + +static uint32_t ldl_phys_le(target_phys_addr_t addr) +{ + uint32_t value_le; + cpu_physical_memory_read(addr, (uint8_t*)(&value_le), sizeof(value_le)); + return le32_to_cpu(value_le); +} + +static void intel_hda_update_int_sts(IntelHDAState *d) +{ + uint32_t sts = 0; + uint32_t i; + + /* update controller status */ + if (d->rirb_sts & ICH6_RBSTS_IRQ) { + sts |= (1 << 30); + } + if (d->rirb_sts & ICH6_RBSTS_OVERRUN) { + sts |= (1 << 30); + } + if (d->state_sts) { + sts |= (1 << 30); + } + + /* update stream status */ + for (i = 0; i < 8; i++) { + /* buffer completion interrupt */ + if (d->st[i].ctl & (1 << 26)) { + sts |= (1 << i); + } + } + + /* update global status */ + if (sts & d->int_ctl) { + sts |= (1 << 31); + } + + d->int_sts = sts; +} + +static void intel_hda_update_irq(IntelHDAState *d) +{ + int level; + + intel_hda_update_int_sts(d); + if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) { + level = 1; + } else { + level = 0; + } + dprint(d, 2, "%s: level %d\n", __FUNCTION__, level); + qemu_set_irq(d->pci.irq[0], level); +} + +static int intel_hda_send_command(IntelHDAState *d, uint32_t verb) +{ + uint32_t cad, nid, data; + HDACodecDevice *codec; + + cad = (verb >> 28) & 0x0f; + if (verb & (1 << 27)) { + /* indirect node addressing, not specified in HDA 1.0 */ + dprint(d, 1, "%s: indirect node addressing (guest bug?)\n", __FUNCTION__); + return -1; + } + nid = (verb >> 20) & 0x7f; + data = verb & 0xfffff; + + codec = hda_codec_find(&d->codecs, cad); + if (codec == NULL) { + dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__); + return -1; + } + codec->info->command(codec, nid, data); + return 0; +} + +static void intel_hda_corb_run(IntelHDAState *d) +{ + target_phys_addr_t addr; + uint32_t rp, verb; + + if (d->ics & ICH6_IRS_BUSY) { + dprint(d, 2, "%s: [icw] verb 0x%08x\n", __FUNCTION__, d->icw); + intel_hda_send_command(d, d->icw); + return; + } + + for (;;) { + if (!(d->corb_ctl & ICH6_CORBCTL_RUN)) { + dprint(d, 2, "%s: !run\n", __FUNCTION__); + return; + } + if ((d->corb_rp & 0xff) == d->corb_wp) { + dprint(d, 2, "%s: corb ring empty\n", __FUNCTION__); + return; + } + if (d->rirb_count == d->rirb_cnt) { + dprint(d, 2, "%s: rirb count reached\n", __FUNCTION__); + return; + } + + rp = (d->corb_rp + 1) & 0xff; + addr = intel_hda_addr(d->corb_lbase, d->corb_ubase); + verb = ldl_phys_le(addr + 4*rp); + d->corb_rp = rp; + + dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb); + intel_hda_send_command(d, verb); + } +} + +static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response) +{ + HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); + IntelHDAState *d = container_of(bus, IntelHDAState, codecs); + target_phys_addr_t addr; + uint32_t wp, ex; + + if (d->ics & ICH6_IRS_BUSY) { + dprint(d, 2, "%s: [irr] response 0x%x, cad 0x%x\n", + __FUNCTION__, response, dev->cad); + d->irr = response; + d->ics &= ~(ICH6_IRS_BUSY | 0xf0); + d->ics |= (ICH6_IRS_VALID | (dev->cad << 4)); + return; + } + + if (!(d->rirb_ctl & ICH6_RBCTL_DMA_EN)) { + dprint(d, 1, "%s: rirb dma disabled, drop codec response\n", __FUNCTION__); + return; + } + + ex = (solicited ? 0 : (1 << 4)) | dev->cad; + wp = (d->rirb_wp + 1) & 0xff; + addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase); + stl_phys_le(addr + 8*wp, response); + stl_phys_le(addr + 8*wp + 4, ex); + d->rirb_wp = wp; + + dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n", + __FUNCTION__, wp, response, ex); + + d->rirb_count++; + if (d->rirb_count == d->rirb_cnt) { + dprint(d, 2, "%s: rirb count reached (%d)\n", __FUNCTION__, d->rirb_count); + if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) { + d->rirb_sts |= ICH6_RBSTS_IRQ; + intel_hda_update_irq(d); + } + } else if ((d->corb_rp & 0xff) == d->corb_wp) { + dprint(d, 2, "%s: corb ring empty (%d/%d)\n", __FUNCTION__, + d->rirb_count, d->rirb_cnt); + if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) { + d->rirb_sts |= ICH6_RBSTS_IRQ; + intel_hda_update_irq(d); + } + } +} + +static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, + uint8_t *buf, uint32_t len) +{ + HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); + IntelHDAState *d = container_of(bus, IntelHDAState, codecs); + IntelHDAStream *st = NULL; + target_phys_addr_t addr; + uint32_t s, copy, left; + bool irq = false; + + for (s = 0; s < ARRAY_SIZE(d->st); s++) { + if (stnr == ((d->st[s].ctl >> 20) & 0x0f)) { + st = d->st + s; + break; + } + } + if (st == NULL) { + return false; + } + if (st->bpl == NULL) { + return false; + } + if (st->ctl & (1 << 26)) { + /* + * Wait with the next DMA xfer until the guest + * has acked the buffer completion interrupt + */ + return false; + } + + left = len; + while (left > 0) { + copy = left; + if (copy > st->bsize - st->lpib) + copy = st->bsize - st->lpib; + if (copy > st->bpl[st->be].len - st->bp) + copy = st->bpl[st->be].len - st->bp; + + dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n", + st->be, st->bp, st->bpl[st->be].len, copy); + + cpu_physical_memory_rw(st->bpl[st->be].addr + st->bp, + buf, copy, !output); + st->lpib += copy; + st->bp += copy; + buf += copy; + left -= copy; + + if (st->bpl[st->be].len == st->bp) { + /* bpl entry filled */ + if (st->bpl[st->be].flags & 0x01) { + irq = true; + } + st->bp = 0; + st->be++; + if (st->be == st->bentries) { + /* bpl wrap around */ + st->be = 0; + st->lpib = 0; + } + } + } + if (d->dp_lbase & 0x01) { + addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase); + stl_phys_le(addr + 8*s, st->lpib); + } + dprint(d, 3, "dma: --\n"); + + if (irq) { + st->ctl |= (1 << 26); /* buffer completion interrupt */ + intel_hda_update_irq(d); + } + return true; +} + +static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st) +{ + target_phys_addr_t addr; + uint8_t buf[16]; + uint32_t i; + + addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase); + st->bentries = st->lvi +1; + qemu_free(st->bpl); + st->bpl = qemu_malloc(sizeof(bpl) * st->bentries); + for (i = 0; i < st->bentries; i++, addr += 16) { + cpu_physical_memory_read(addr, buf, 16); + st->bpl[i].addr = le64_to_cpu(*(uint64_t *)buf); + st->bpl[i].len = le32_to_cpu(*(uint32_t *)(buf + 8)); + st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12)); + dprint(d, 1, "bdl/%d: 0x%" PRIx64 " +0x%x, 0x%x\n", + i, st->bpl[i].addr, st->bpl[i].len, st->bpl[i].flags); + } + + st->bsize = st->cbl; + st->lpib = 0; + st->be = 0; + st->bp = 0; +} + +static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running) +{ + DeviceState *qdev; + HDACodecDevice *cdev; + + QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) { + cdev = DO_UPCAST(HDACodecDevice, qdev, qdev); + if (cdev->info->stream) { + cdev->info->stream(cdev, stream, running); + } + } +} + +/* --------------------------------------------------------------------- */ + +static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) +{ + if ((d->g_ctl & ICH6_GCTL_RESET) == 0) { + intel_hda_reset(&d->pci.qdev); + } +} + +static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) +{ + intel_hda_update_irq(d); +} + +static void intel_hda_set_int_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) +{ + intel_hda_update_irq(d); +} + +static void intel_hda_get_wall_clk(IntelHDAState *d, const IntelHDAReg *reg) +{ + int64_t ns; + + ns = qemu_get_clock_ns(vm_clock) - d->wall_base_ns; + d->wall_clk = (uint32_t)(ns * 24 / 1000); /* 24 MHz */ +} + +static void intel_hda_set_corb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) +{ + intel_hda_corb_run(d); +} + +static void intel_hda_set_corb_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) +{ + intel_hda_corb_run(d); +} + +static void intel_hda_set_rirb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) +{ + if (d->rirb_wp & ICH6_RIRBWP_RST) { + d->rirb_wp = 0; + } +} + +static void intel_hda_set_rirb_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) +{ + intel_hda_update_irq(d); + + if ((old & ICH6_RBSTS_IRQ) && !(d->rirb_sts & ICH6_RBSTS_IRQ)) { + /* cleared ICH6_RBSTS_IRQ */ + d->rirb_count = 0; + intel_hda_corb_run(d); + } +} + +static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) +{ + if (d->ics & ICH6_IRS_BUSY) { + intel_hda_corb_run(d); + } +} + +static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) +{ + IntelHDAStream *st = d->st + reg->stream; + + if (st->ctl & 0x01) { + /* reset */ + dprint(d, 1, "st #%d: reset\n", reg->stream); + st->ctl = 0; + } + if ((st->ctl & 0x02) != (old & 0x02)) { + uint32_t stnr = (st->ctl >> 20) & 0x0f; + /* run bit flipped */ + if (st->ctl & 0x02) { + /* start */ + dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n", + reg->stream, stnr, st->cbl); + intel_hda_parse_bdl(d, st); + intel_hda_notify_codecs(d, stnr, true); + } else { + /* stop */ + dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr); + intel_hda_notify_codecs(d, stnr, false); + } + } + intel_hda_update_irq(d); +} + +/* --------------------------------------------------------------------- */ + +#define ST_REG(_n, _o) (0x80 + (_n) * 0x20 + (_o)) + +static const struct IntelHDAReg regtab[] = { + /* global */ + [ ICH6_REG_GCAP ] = { + .name = "GCAP", + .size = 2, + .reset = 0x4401, + }, + [ ICH6_REG_VMIN ] = { + .name = "VMIN", + .size = 1, + }, + [ ICH6_REG_VMAJ ] = { + .name = "VMAJ", + .size = 1, + .reset = 1, + }, + [ ICH6_REG_OUTPAY ] = { + .name = "OUTPAY", + .size = 2, + .reset = 0x3c, + }, + [ ICH6_REG_INPAY ] = { + .name = "INPAY", + .size = 2, + .reset = 0x1d, + }, + [ ICH6_REG_GCTL ] = { + .name = "GCTL", + .size = 4, + .wmask = 0x0103, + .offset = offsetof(IntelHDAState, g_ctl), + .whandler = intel_hda_set_g_ctl, + }, + [ ICH6_REG_WAKEEN ] = { + .name = "WAKEEN", + .size = 2, + .offset = offsetof(IntelHDAState, wake_en), + }, + [ ICH6_REG_STATESTS ] = { + .name = "STATESTS", + .size = 2, + .wmask = 0x3fff, + .wclear = 0x3fff, + .offset = offsetof(IntelHDAState, state_sts), + .whandler = intel_hda_set_state_sts, + }, + + /* interrupts */ + [ ICH6_REG_INTCTL ] = { + .name = "INTCTL", + .size = 4, + .wmask = 0xc00000ff, + .offset = offsetof(IntelHDAState, int_ctl), + .whandler = intel_hda_set_int_ctl, + }, + [ ICH6_REG_INTSTS ] = { + .name = "INTSTS", + .size = 4, + .wmask = 0xc00000ff, + .wclear = 0xc00000ff, + .offset = offsetof(IntelHDAState, int_sts), + }, + + /* misc */ + [ ICH6_REG_WALLCLK ] = { + .name = "WALLCLK", + .size = 4, + .offset = offsetof(IntelHDAState, wall_clk), + .rhandler = intel_hda_get_wall_clk, + }, + [ ICH6_REG_WALLCLK + 0x2000 ] = { + .name = "WALLCLK(alias)", + .size = 4, + .offset = offsetof(IntelHDAState, wall_clk), + .rhandler = intel_hda_get_wall_clk, + }, + + /* dma engine */ + [ ICH6_REG_CORBLBASE ] = { + .name = "CORBLBASE", + .size = 4, + .wmask = 0xffffff80, + .offset = offsetof(IntelHDAState, corb_lbase), + }, + [ ICH6_REG_CORBUBASE ] = { + .name = "CORBUBASE", + .size = 4, + .wmask = 0xffffffff, + .offset = offsetof(IntelHDAState, corb_ubase), + }, + [ ICH6_REG_CORBWP ] = { + .name = "CORBWP", + .size = 2, + .wmask = 0xff, + .offset = offsetof(IntelHDAState, corb_wp), + .whandler = intel_hda_set_corb_wp, + }, + [ ICH6_REG_CORBRP ] = { + .name = "CORBRP", + .size = 2, + .wmask = 0x80ff, + .offset = offsetof(IntelHDAState, corb_rp), + }, + [ ICH6_REG_CORBCTL ] = { + .name = "CORBCTL", + .size = 1, + .wmask = 0x03, + .offset = offsetof(IntelHDAState, corb_ctl), + .whandler = intel_hda_set_corb_ctl, + }, + [ ICH6_REG_CORBSTS ] = { + .name = "CORBSTS", + .size = 1, + .wmask = 0x01, + .wclear = 0x01, + .offset = offsetof(IntelHDAState, corb_sts), + }, + [ ICH6_REG_CORBSIZE ] = { + .name = "CORBSIZE", + .size = 1, + .reset = 0x42, + .offset = offsetof(IntelHDAState, corb_size), + }, + [ ICH6_REG_RIRBLBASE ] = { + .name = "RIRBLBASE", + .size = 4, + .wmask = 0xffffff80, + .offset = offsetof(IntelHDAState, rirb_lbase), + }, + [ ICH6_REG_RIRBUBASE ] = { + .name = "RIRBUBASE", + .size = 4, + .wmask = 0xffffffff, + .offset = offsetof(IntelHDAState, rirb_ubase), + }, + [ ICH6_REG_RIRBWP ] = { + .name = "RIRBWP", + .size = 2, + .wmask = 0x8000, + .offset = offsetof(IntelHDAState, rirb_wp), + .whandler = intel_hda_set_rirb_wp, + }, + [ ICH6_REG_RINTCNT ] = { + .name = "RINTCNT", + .size = 2, + .wmask = 0xff, + .offset = offsetof(IntelHDAState, rirb_cnt), + }, + [ ICH6_REG_RIRBCTL ] = { + .name = "RIRBCTL", + .size = 1, + .wmask = 0x07, + .offset = offsetof(IntelHDAState, rirb_ctl), + }, + [ ICH6_REG_RIRBSTS ] = { + .name = "RIRBSTS", + .size = 1, + .wmask = 0x05, + .wclear = 0x05, + .offset = offsetof(IntelHDAState, rirb_sts), + .whandler = intel_hda_set_rirb_sts, + }, + [ ICH6_REG_RIRBSIZE ] = { + .name = "RIRBSIZE", + .size = 1, + .reset = 0x42, + .offset = offsetof(IntelHDAState, rirb_size), + }, + + [ ICH6_REG_DPLBASE ] = { + .name = "DPLBASE", + .size = 4, + .wmask = 0xffffff81, + .offset = offsetof(IntelHDAState, dp_lbase), + }, + [ ICH6_REG_DPUBASE ] = { + .name = "DPUBASE", + .size = 4, + .wmask = 0xffffffff, + .offset = offsetof(IntelHDAState, dp_ubase), + }, + + [ ICH6_REG_IC ] = { + .name = "ICW", + .size = 4, + .wmask = 0xffffffff, + .offset = offsetof(IntelHDAState, icw), + }, + [ ICH6_REG_IR ] = { + .name = "IRR", + .size = 4, + .offset = offsetof(IntelHDAState, irr), + }, + [ ICH6_REG_IRS ] = { + .name = "ICS", + .size = 2, + .wmask = 0x0003, + .wclear = 0x0002, + .offset = offsetof(IntelHDAState, ics), + .whandler = intel_hda_set_ics, + }, + +#define HDA_STREAM(_t, _i) \ + [ ST_REG(_i, ICH6_REG_SD_CTL) ] = { \ + .stream = _i, \ + .name = _t stringify(_i) " CTL", \ + .size = 4, \ + .wmask = 0x1cff001f, \ + .offset = offsetof(IntelHDAState, st[_i].ctl), \ + .whandler = intel_hda_set_st_ctl, \ + }, \ + [ ST_REG(_i, ICH6_REG_SD_CTL) + 2] = { \ + .stream = _i, \ + .name = _t stringify(_i) " CTL(stnr)", \ + .size = 1, \ + .shift = 16, \ + .wmask = 0x00ff0000, \ + .offset = offsetof(IntelHDAState, st[_i].ctl), \ + .whandler = intel_hda_set_st_ctl, \ + }, \ + [ ST_REG(_i, ICH6_REG_SD_STS)] = { \ + .stream = _i, \ + .name = _t stringify(_i) " CTL(sts)", \ + .size = 1, \ + .shift = 24, \ + .wmask = 0x1c000000, \ + .wclear = 0x1c000000, \ + .offset = offsetof(IntelHDAState, st[_i].ctl), \ + .whandler = intel_hda_set_st_ctl, \ + }, \ + [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \ + .stream = _i, \ + .name = _t stringify(_i) " LPIB", \ + .size = 4, \ + .offset = offsetof(IntelHDAState, st[_i].lpib), \ + }, \ + [ ST_REG(_i, ICH6_REG_SD_LPIB) + 0x2000 ] = { \ + .stream = _i, \ + .name = _t stringify(_i) " LPIB(alias)", \ + .size = 4, \ + .offset = offsetof(IntelHDAState, st[_i].lpib), \ + }, \ + [ ST_REG(_i, ICH6_REG_SD_CBL) ] = { \ + .stream = _i, \ + .name = _t stringify(_i) " CBL", \ + .size = 4, \ + .wmask = 0xffffffff, \ + .offset = offsetof(IntelHDAState, st[_i].cbl), \ + }, \ + [ ST_REG(_i, ICH6_REG_SD_LVI) ] = { \ + .stream = _i, \ + .name = _t stringify(_i) " LVI", \ + .size = 2, \ + .wmask = 0x00ff, \ + .offset = offsetof(IntelHDAState, st[_i].lvi), \ + }, \ + [ ST_REG(_i, ICH6_REG_SD_FIFOSIZE) ] = { \ + .stream = _i, \ + .name = _t stringify(_i) " FIFOS", \ + .size = 2, \ + .reset = HDA_BUFFER_SIZE, \ + }, \ + [ ST_REG(_i, ICH6_REG_SD_FORMAT) ] = { \ + .stream = _i, \ + .name = _t stringify(_i) " FMT", \ + .size = 2, \ + .wmask = 0x7f7f, \ + .offset = offsetof(IntelHDAState, st[_i].fmt), \ + }, \ + [ ST_REG(_i, ICH6_REG_SD_BDLPL) ] = { \ + .stream = _i, \ + .name = _t stringify(_i) " BDLPL", \ + .size = 4, \ + .wmask = 0xffffff80, \ + .offset = offsetof(IntelHDAState, st[_i].bdlp_lbase), \ + }, \ + [ ST_REG(_i, ICH6_REG_SD_BDLPU) ] = { \ + .stream = _i, \ + .name = _t stringify(_i) " BDLPU", \ + .size = 4, \ + .wmask = 0xffffffff, \ + .offset = offsetof(IntelHDAState, st[_i].bdlp_ubase), \ + }, \ + + HDA_STREAM("IN", 0) + HDA_STREAM("IN", 1) + HDA_STREAM("IN", 2) + HDA_STREAM("IN", 3) + + HDA_STREAM("OUT", 4) + HDA_STREAM("OUT", 5) + HDA_STREAM("OUT", 6) + HDA_STREAM("OUT", 7) + +}; + +static const IntelHDAReg *intel_hda_reg_find(IntelHDAState *d, target_phys_addr_t addr) +{ + const IntelHDAReg *reg; + + if (addr >= sizeof(regtab)/sizeof(regtab[0])) { + goto noreg; + } + reg = regtab+addr; + if (reg->name == NULL) { + goto noreg; + } + return reg; + +noreg: + dprint(d, 1, "unknown register, addr 0x%x\n", (int) addr); + return NULL; +} + +static uint32_t *intel_hda_reg_addr(IntelHDAState *d, const IntelHDAReg *reg) +{ + uint8_t *addr = (void*)d; + + addr += reg->offset; + return (uint32_t*)addr; +} + +static void intel_hda_reg_write(IntelHDAState *d, const IntelHDAReg *reg, uint32_t val, + uint32_t wmask) +{ + uint32_t *addr; + uint32_t old; + + if (!reg) { + return; + } + + if (d->debug) { + time_t now = time(NULL); + if (d->last_write && d->last_reg == reg && d->last_val == val) { + d->repeat_count++; + if (d->last_sec != now) { + dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count); + d->last_sec = now; + d->repeat_count = 0; + } + } else { + if (d->repeat_count) { + dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count); + } + dprint(d, 2, "write %-16s: 0x%x (%x)\n", reg->name, val, wmask); + d->last_write = 1; + d->last_reg = reg; + d->last_val = val; + d->last_sec = now; + d->repeat_count = 0; + } + } + assert(reg->offset != 0); + + addr = intel_hda_reg_addr(d, reg); + old = *addr; + + if (reg->shift) { + val <<= reg->shift; + wmask <<= reg->shift; + } + wmask &= reg->wmask; + *addr &= ~wmask; + *addr |= wmask & val; + *addr &= ~(val & reg->wclear); + + if (reg->whandler) { + reg->whandler(d, reg, old); + } +} + +static uint32_t intel_hda_reg_read(IntelHDAState *d, const IntelHDAReg *reg, + uint32_t rmask) +{ + uint32_t *addr, ret; + + if (!reg) { + return 0; + } + + if (reg->rhandler) { + reg->rhandler(d, reg); + } + + if (reg->offset == 0) { + /* constant read-only register */ + ret = reg->reset; + } else { + addr = intel_hda_reg_addr(d, reg); + ret = *addr; + if (reg->shift) { + ret >>= reg->shift; + } + ret &= rmask; + } + if (d->debug) { + time_t now = time(NULL); + if (!d->last_write && d->last_reg == reg && d->last_val == ret) { + d->repeat_count++; + if (d->last_sec != now) { + dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count); + d->last_sec = now; + d->repeat_count = 0; + } + } else { + if (d->repeat_count) { + dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count); + } + dprint(d, 2, "read %-16s: 0x%x (%x)\n", reg->name, ret, rmask); + d->last_write = 0; + d->last_reg = reg; + d->last_val = ret; + d->last_sec = now; + d->repeat_count = 0; + } + } + return ret; +} + +static void intel_hda_regs_reset(IntelHDAState *d) +{ + uint32_t *addr; + int i; + + for (i = 0; i < sizeof(regtab)/sizeof(regtab[0]); i++) { + if (regtab[i].name == NULL) { + continue; + } + if (regtab[i].offset == 0) { + continue; + } + addr = intel_hda_reg_addr(d, regtab + i); + *addr = regtab[i].reset; + } +} + +/* --------------------------------------------------------------------- */ + +static void intel_hda_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + IntelHDAState *d = opaque; + const IntelHDAReg *reg = intel_hda_reg_find(d, addr); + + intel_hda_reg_write(d, reg, val, 0xff); +} + +static void intel_hda_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + IntelHDAState *d = opaque; + const IntelHDAReg *reg = intel_hda_reg_find(d, addr); + + intel_hda_reg_write(d, reg, val, 0xffff); +} + +static void intel_hda_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + IntelHDAState *d = opaque; + const IntelHDAReg *reg = intel_hda_reg_find(d, addr); + + intel_hda_reg_write(d, reg, val, 0xffffffff); +} + +static uint32_t intel_hda_mmio_readb(void *opaque, target_phys_addr_t addr) +{ + IntelHDAState *d = opaque; + const IntelHDAReg *reg = intel_hda_reg_find(d, addr); + + return intel_hda_reg_read(d, reg, 0xff); +} + +static uint32_t intel_hda_mmio_readw(void *opaque, target_phys_addr_t addr) +{ + IntelHDAState *d = opaque; + const IntelHDAReg *reg = intel_hda_reg_find(d, addr); + + return intel_hda_reg_read(d, reg, 0xffff); +} + +static uint32_t intel_hda_mmio_readl(void *opaque, target_phys_addr_t addr) +{ + IntelHDAState *d = opaque; + const IntelHDAReg *reg = intel_hda_reg_find(d, addr); + + return intel_hda_reg_read(d, reg, 0xffffffff); +} + +static CPUReadMemoryFunc * const intel_hda_mmio_read[3] = { + intel_hda_mmio_readb, + intel_hda_mmio_readw, + intel_hda_mmio_readl, +}; + +static CPUWriteMemoryFunc * const intel_hda_mmio_write[3] = { + intel_hda_mmio_writeb, + intel_hda_mmio_writew, + intel_hda_mmio_writel, +}; + +static void intel_hda_map(PCIDevice *pci, int region_num, + pcibus_t addr, pcibus_t size, int type) +{ + IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci); + + cpu_register_physical_memory(addr, 0x4000, d->mmio_addr); +} + +/* --------------------------------------------------------------------- */ + +static void intel_hda_reset(DeviceState *dev) +{ + IntelHDAState *d = DO_UPCAST(IntelHDAState, pci.qdev, dev); + DeviceState *qdev; + HDACodecDevice *cdev; + + intel_hda_regs_reset(d); + d->wall_base_ns = qemu_get_clock(vm_clock); + + /* reset codecs */ + QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) { + cdev = DO_UPCAST(HDACodecDevice, qdev, qdev); + if (qdev->info->reset) { + qdev->info->reset(qdev); + } + d->state_sts |= (1 << cdev->cad); + } + intel_hda_update_irq(d); +} + +static int intel_hda_init(PCIDevice *pci) +{ + IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci); + uint8_t *conf = d->pci.config; + + d->name = d->pci.qdev.info->name; + + pci_config_set_vendor_id(conf, PCI_VENDOR_ID_INTEL); + pci_config_set_device_id(conf, 0x2668); + pci_config_set_revision(conf, 1); + pci_config_set_class(conf, PCI_CLASS_MULTIMEDIA_HD_AUDIO); + pci_config_set_interrupt_pin(conf, 1); + + /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */ + conf[0x40] = 0x01; + + d->mmio_addr = cpu_register_io_memory(intel_hda_mmio_read, + intel_hda_mmio_write, d); + pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY, + intel_hda_map); + + hda_codec_bus_init(&d->pci.qdev, &d->codecs, + intel_hda_response, intel_hda_xfer); + + return 0; +} + +static int intel_hda_post_load(void *opaque, int version) +{ + IntelHDAState* d = opaque; + int i; + + dprint(d, 1, "%s\n", __FUNCTION__); + for (i = 0; i < ARRAY_SIZE(d->st); i++) { + if (d->st[i].ctl & 0x02) { + intel_hda_parse_bdl(d, &d->st[i]); + } + } + intel_hda_update_irq(d); + return 0; +} + +static const VMStateDescription vmstate_intel_hda_stream = { + .name = "intel-hda-stream", + .version_id = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(ctl, IntelHDAStream), + VMSTATE_UINT32(lpib, IntelHDAStream), + VMSTATE_UINT32(cbl, IntelHDAStream), + VMSTATE_UINT32(lvi, IntelHDAStream), + VMSTATE_UINT32(fmt, IntelHDAStream), + VMSTATE_UINT32(bdlp_lbase, IntelHDAStream), + VMSTATE_UINT32(bdlp_ubase, IntelHDAStream), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_intel_hda = { + .name = "intel-hda", + .version_id = 1, + .post_load = intel_hda_post_load, + .fields = (VMStateField []) { + VMSTATE_PCI_DEVICE(pci, IntelHDAState), + + /* registers */ + VMSTATE_UINT32(g_ctl, IntelHDAState), + VMSTATE_UINT32(wake_en, IntelHDAState), + VMSTATE_UINT32(state_sts, IntelHDAState), + VMSTATE_UINT32(int_ctl, IntelHDAState), + VMSTATE_UINT32(int_sts, IntelHDAState), + VMSTATE_UINT32(wall_clk, IntelHDAState), + VMSTATE_UINT32(corb_lbase, IntelHDAState), + VMSTATE_UINT32(corb_ubase, IntelHDAState), + VMSTATE_UINT32(corb_rp, IntelHDAState), + VMSTATE_UINT32(corb_wp, IntelHDAState), + VMSTATE_UINT32(corb_ctl, IntelHDAState), + VMSTATE_UINT32(corb_sts, IntelHDAState), + VMSTATE_UINT32(corb_size, IntelHDAState), + VMSTATE_UINT32(rirb_lbase, IntelHDAState), + VMSTATE_UINT32(rirb_ubase, IntelHDAState), + VMSTATE_UINT32(rirb_wp, IntelHDAState), + VMSTATE_UINT32(rirb_cnt, IntelHDAState), + VMSTATE_UINT32(rirb_ctl, IntelHDAState), + VMSTATE_UINT32(rirb_sts, IntelHDAState), + VMSTATE_UINT32(rirb_size, IntelHDAState), + VMSTATE_UINT32(dp_lbase, IntelHDAState), + VMSTATE_UINT32(dp_ubase, IntelHDAState), + VMSTATE_UINT32(icw, IntelHDAState), + VMSTATE_UINT32(irr, IntelHDAState), + VMSTATE_UINT32(ics, IntelHDAState), + VMSTATE_STRUCT_ARRAY(st, IntelHDAState, 8, 0, + vmstate_intel_hda_stream, + IntelHDAStream), + + /* additional state info */ + VMSTATE_UINT32(rirb_count, IntelHDAState), + VMSTATE_INT64(wall_base_ns, IntelHDAState), + + VMSTATE_END_OF_LIST() + } +}; + +static PCIDeviceInfo intel_hda_info = { + .qdev.name = "intel-hda", + .qdev.desc = "Intel HD Audio Controller", + .qdev.size = sizeof(IntelHDAState), + .qdev.vmsd = &vmstate_intel_hda, + .qdev.reset = intel_hda_reset, + .init = intel_hda_init, + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void intel_hda_register(void) +{ + pci_qdev_register(&intel_hda_info); +} +device_init(intel_hda_register); + +/* + * create intel hda controller with codec attached to it, + * so '-soundhw hda' works. + */ +int intel_hda_and_codec_init(PCIBus *bus) +{ + PCIDevice *controller; + BusState *hdabus; + DeviceState *codec; + + controller = pci_create_simple(bus, -1, "intel-hda"); + hdabus = QLIST_FIRST(&controller->qdev.child_bus); + codec = qdev_create(hdabus, "hda-duplex"); + qdev_init_nofail(codec); + return 0; +} + diff --git a/hw/intel-hda.h b/hw/intel-hda.h new file mode 100644 index 0000000000..ba290ec850 --- /dev/null +++ b/hw/intel-hda.h @@ -0,0 +1,61 @@ +#ifndef HW_INTEL_HDA_H +#define HW_INTEL_HDA_H + +#include "qdev.h" + +/* --------------------------------------------------------------------- */ +/* hda bus */ + +typedef struct HDACodecBus HDACodecBus; +typedef struct HDACodecDevice HDACodecDevice; +typedef struct HDACodecDeviceInfo HDACodecDeviceInfo; + +typedef void (*hda_codec_response_func)(HDACodecDevice *dev, + bool solicited, uint32_t response); +typedef bool (*hda_codec_xfer_func)(HDACodecDevice *dev, + uint32_t stnr, bool output, + uint8_t *buf, uint32_t len); + +struct HDACodecBus { + BusState qbus; + uint32_t next_cad; + hda_codec_response_func response; + hda_codec_xfer_func xfer; +}; + +struct HDACodecDevice { + DeviceState qdev; + HDACodecDeviceInfo *info; + uint32_t cad; /* codec address */ +}; + +struct HDACodecDeviceInfo { + DeviceInfo qdev; + int (*init)(HDACodecDevice *dev); + void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data); + void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running); +}; + +void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, + hda_codec_response_func response, + hda_codec_xfer_func xfer); +void hda_codec_register(HDACodecDeviceInfo *info); +HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad); + +void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response); +bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, + uint8_t *buf, uint32_t len); + +/* --------------------------------------------------------------------- */ + +#define dprint(_dev, _level, _fmt, ...) \ + do { \ + if (_dev->debug >= _level) { \ + fprintf(stderr, "%s: ", _dev->name); \ + fprintf(stderr, _fmt, ## __VA_ARGS__); \ + } \ + } while (0) + +/* --------------------------------------------------------------------- */ + +#endif diff --git a/hw/lance.c b/hw/lance.c index b6b04ddb9c..dc12144ded 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -40,8 +40,8 @@ #include "qemu-timer.h" #include "qemu_socket.h" #include "sun4m.h" - #include "pcnet.h" +#include "trace.h" typedef struct { SysBusDevice busdev; @@ -59,10 +59,8 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { SysBusPCNetState *d = opaque; -#ifdef PCNET_DEBUG_IO - printf("lance_mem_writew addr=" TARGET_FMT_plx " val=0x%04x\n", addr, - val & 0xffff); -#endif + + trace_lance_mem_writew(addr, val & 0xffff); pcnet_ioport_writew(&d->state, addr, val & 0xffff); } @@ -72,11 +70,7 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) uint32_t val; val = pcnet_ioport_readw(&d->state, addr); -#ifdef PCNET_DEBUG_IO - printf("lance_mem_readw addr=" TARGET_FMT_plx " val = 0x%04x\n", addr, - val & 0xffff); -#endif - + trace_lance_mem_readw(addr, val & 0xffff); return val & 0xffff; } diff --git a/hw/omap_clk.c b/hw/omap_clk.c index 10c9c4308c..6bcabef8ac 100644 --- a/hw/omap_clk.c +++ b/hw/omap_clk.c @@ -20,7 +20,6 @@ */ #include "hw.h" #include "omap.h" -#include "qemu-timer.h" /* for muldiv64() */ struct clk { const char *name; diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 10362a3655..9d5ad86d98 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -25,16 +25,9 @@ #include "sun4m.h" #include "monitor.h" #include "sysbus.h" +#include "trace.h" //#define DEBUG_IRQ_COUNT -//#define DEBUG_IRQ - -#ifdef DEBUG_IRQ -#define DPRINTF(fmt, ...) \ - do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) -#endif /* * Registers of interrupt controller in sun4m. @@ -97,7 +90,7 @@ static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr) ret = 0; break; } - DPRINTF("read cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, ret); + trace_slavio_intctl_mem_readl(s->cpu, addr, ret); return ret; } @@ -109,21 +102,19 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t saddr; saddr = addr >> 2; - DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, val); + trace_slavio_intctl_mem_writel(s->cpu, addr, val); switch (saddr) { case 1: // clear pending softints val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN; s->intreg_pending &= ~val; slavio_check_interrupts(s->master, 1); - DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", s->cpu, val, - s->intreg_pending); + trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending); break; case 2: // set softint val &= CPU_SOFTIRQ_MASK; s->intreg_pending |= val; slavio_check_interrupts(s->master, 1); - DPRINTF("Set cpu %d irq mask %x, curmask %x\n", s->cpu, val, - s->intreg_pending); + trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending); break; default: break; @@ -163,7 +154,7 @@ static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr) ret = 0; break; } - DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret); + trace_slavio_intctlm_mem_readl(addr, ret); return ret; } @@ -175,14 +166,13 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t saddr; saddr = addr >> 2; - DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val); + trace_slavio_intctlm_mem_writel(addr, val); switch (saddr) { case 2: // clear (enable) // Force clear unused bits val &= MASTER_IRQ_MASK; s->intregm_disabled &= ~val; - DPRINTF("Enabled master irq mask %x, curmask %x\n", val, - s->intregm_disabled); + trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled); slavio_check_interrupts(s, 1); break; case 3: // set (disable; doesn't affect pending) @@ -190,13 +180,12 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, val &= MASTER_IRQ_MASK; s->intregm_disabled |= val; slavio_check_interrupts(s, 1); - DPRINTF("Disabled master irq mask %x, curmask %x\n", val, - s->intregm_disabled); + trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled); break; case 4: s->target_cpu = val & (MAX_CPUS - 1); slavio_check_interrupts(s, 1); - DPRINTF("Set master irq cpu %d\n", s->target_cpu); + trace_slavio_intctlm_mem_writel_target(s->target_cpu); break; default: break; @@ -264,7 +253,7 @@ static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs) pending &= ~s->intregm_disabled; - DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); + trace_slavio_check_interrupts(pending, s->intregm_disabled); for (i = 0; i < MAX_CPUS; i++) { pil_pending = 0; @@ -327,8 +316,7 @@ static void slavio_set_irq(void *opaque, int irq, int level) uint32_t pil = intbit_to_level[irq]; unsigned int i; - DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil, - level); + trace_slavio_set_irq(s->target_cpu, irq, pil, level); if (pil > 0) { if (level) { #ifdef DEBUG_IRQ_COUNT @@ -356,7 +344,7 @@ static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level) { SLAVIO_INTCTLState *s = opaque; - DPRINTF("Set cpu %d local timer level %d\n", cpu, level); + trace_slavio_set_timer_irq_cpu(cpu, level); if (level) { s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN; diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 5ae628df8e..1d81a633c7 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -24,9 +24,7 @@ #include "sysemu.h" #include "sysbus.h" - -/* debug misc */ -//#define DEBUG_MISC +#include "trace.h" /* * This is the auxio port, chip control and system control part of @@ -36,13 +34,6 @@ * This also includes the PMC CPU idle controller. */ -#ifdef DEBUG_MISC -#define MISC_DPRINTF(fmt, ...) \ - do { printf("MISC: " fmt , ## __VA_ARGS__); } while (0) -#else -#define MISC_DPRINTF(fmt, ...) -#endif - typedef struct MiscState { SysBusDevice busdev; qemu_irq irq; @@ -79,10 +70,10 @@ static void slavio_misc_update_irq(void *opaque) MiscState *s = opaque; if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) { - MISC_DPRINTF("Raise IRQ\n"); + trace_slavio_misc_update_irq_raise(); qemu_irq_raise(s->irq); } else { - MISC_DPRINTF("Lower IRQ\n"); + trace_slavio_misc_update_irq_lower(); qemu_irq_lower(s->irq); } } @@ -99,7 +90,7 @@ static void slavio_set_power_fail(void *opaque, int irq, int power_failing) { MiscState *s = opaque; - MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config); + trace_slavio_set_power_fail(power_failing, s->config); if (power_failing && (s->config & CFG_PWRINTEN)) { s->aux2 |= AUX2_PWRFAIL; } else { @@ -113,7 +104,7 @@ static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr, { MiscState *s = opaque; - MISC_DPRINTF("Write config %2.2x\n", val & 0xff); + trace_slavio_cfg_mem_writeb(val & 0xff); s->config = val & 0xff; slavio_misc_update_irq(s); } @@ -124,7 +115,7 @@ static uint32_t slavio_cfg_mem_readb(void *opaque, target_phys_addr_t addr) uint32_t ret = 0; ret = s->config; - MISC_DPRINTF("Read config %2.2x\n", ret); + trace_slavio_cfg_mem_readb(ret); return ret; } @@ -145,7 +136,7 @@ static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr, { MiscState *s = opaque; - MISC_DPRINTF("Write diag %2.2x\n", val & 0xff); + trace_slavio_diag_mem_writeb(val & 0xff); s->diag = val & 0xff; } @@ -155,7 +146,7 @@ static uint32_t slavio_diag_mem_readb(void *opaque, target_phys_addr_t addr) uint32_t ret = 0; ret = s->diag; - MISC_DPRINTF("Read diag %2.2x\n", ret); + trace_slavio_diag_mem_readb(ret); return ret; } @@ -176,7 +167,7 @@ static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr, { MiscState *s = opaque; - MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff); + trace_slavio_mdm_mem_writeb(val & 0xff); s->mctrl = val & 0xff; } @@ -186,7 +177,7 @@ static uint32_t slavio_mdm_mem_readb(void *opaque, target_phys_addr_t addr) uint32_t ret = 0; ret = s->mctrl; - MISC_DPRINTF("Read modem control %2.2x\n", ret); + trace_slavio_mdm_mem_readb(ret); return ret; } @@ -207,7 +198,7 @@ static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr, { MiscState *s = opaque; - MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff); + trace_slavio_aux1_mem_writeb(val & 0xff); if (val & AUX1_TC) { // Send a pulse to floppy terminal count line if (s->fdc_tc) { @@ -225,8 +216,7 @@ static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr) uint32_t ret = 0; ret = s->aux1; - MISC_DPRINTF("Read aux1 %2.2x\n", ret); - + trace_slavio_aux1_mem_readb(ret); return ret; } @@ -248,7 +238,7 @@ static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr, MiscState *s = opaque; val &= AUX2_PWRINTCLR | AUX2_PWROFF; - MISC_DPRINTF("Write aux2 %2.2x\n", val); + trace_slavio_aux2_mem_writeb(val & 0xff); val |= s->aux2 & AUX2_PWRFAIL; if (val & AUX2_PWRINTCLR) // Clear Power Fail int val &= AUX2_PWROFF; @@ -264,8 +254,7 @@ static uint32_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr) uint32_t ret = 0; ret = s->aux2; - MISC_DPRINTF("Read aux2 %2.2x\n", ret); - + trace_slavio_aux2_mem_readb(ret); return ret; } @@ -285,7 +274,7 @@ static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { APCState *s = opaque; - MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); + trace_apc_mem_writeb(val & 0xff); qemu_irq_raise(s->cpu_halt); } @@ -293,7 +282,7 @@ static uint32_t apc_mem_readb(void *opaque, target_phys_addr_t addr) { uint32_t ret = 0; - MISC_DPRINTF("Read power management %2.2x\n", ret); + trace_apc_mem_readb(ret); return ret; } @@ -321,7 +310,7 @@ static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr) default: break; } - MISC_DPRINTF("Read system control %08x\n", ret); + trace_slavio_sysctrl_mem_readl(ret); return ret; } @@ -330,7 +319,7 @@ static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr, { MiscState *s = opaque; - MISC_DPRINTF("Write system control %08x\n", val); + trace_slavio_sysctrl_mem_writel(val); switch (addr) { case 0: if (val & SYS_RESET) { @@ -367,7 +356,7 @@ static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr) default: break; } - MISC_DPRINTF("Read diagnostic LED %04x\n", ret); + trace_slavio_led_mem_readw(ret); return ret; } @@ -376,7 +365,7 @@ static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr, { MiscState *s = opaque; - MISC_DPRINTF("Write diagnostic LED %04x\n", val & 0xffff); + trace_slavio_led_mem_readw(val & 0xffff); switch (addr) { case 0: s->leds = val; diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index c125de4b62..13f1e62ad8 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -25,15 +25,7 @@ #include "sun4m.h" #include "qemu-timer.h" #include "sysbus.h" - -//#define DEBUG_TIMER - -#ifdef DEBUG_TIMER -#define DPRINTF(fmt, ...) \ - do { printf("TIMER: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif +#include "trace.h" /* * Registers of hardware timer in sun4m. @@ -112,8 +104,7 @@ static void slavio_timer_get_out(CPUTimerState *t) } count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer)); - DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", t->limit, t->counthigh, - t->count); + trace_slavio_timer_get_out(t->limit, t->counthigh, t->count); t->count = count & TIMER_COUNT_MASK32; t->counthigh = count >> 32; } @@ -126,7 +117,7 @@ static void slavio_timer_irq(void *opaque) CPUTimerState *t = &s->cputimer[tc->timer_index]; slavio_timer_get_out(t); - DPRINTF("callback: count %x%08x\n", t->counthigh, t->count); + trace_slavio_timer_irq(t->counthigh, t->count); /* if limit is 0 (free-run), there will be no match */ if (t->limit != 0) { t->reached = TIMER_REACHED; @@ -188,12 +179,11 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) ret = s->cputimer_mode; break; default: - DPRINTF("invalid read address " TARGET_FMT_plx "\n", addr); + trace_slavio_timer_mem_readl_invalid(addr); ret = 0; break; } - DPRINTF("read " TARGET_FMT_plx " = %08x\n", addr, ret); - + trace_slavio_timer_mem_readl(addr, ret); return ret; } @@ -206,7 +196,7 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, unsigned int timer_index = tc->timer_index; CPUTimerState *t = &s->cputimer[timer_index]; - DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val); + trace_slavio_timer_mem_writel(addr, val); saddr = addr >> 2; switch (saddr) { case TIMER_LIMIT: @@ -218,8 +208,7 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, t->counthigh = val & (TIMER_MAX_COUNT64 >> 32); t->reached = 0; count = ((uint64_t)t->counthigh << 32) | t->count; - DPRINTF("processor %d user timer set to %016" PRIx64 "\n", - timer_index, count); + trace_slavio_timer_mem_writel_limit(timer_index, count); ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); } else { // set limit, reset counter @@ -244,11 +233,11 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, t->count = val & TIMER_MAX_COUNT64; t->reached = 0; count = ((uint64_t)t->counthigh) << 32 | t->count; - DPRINTF("processor %d user timer set to %016" PRIx64 "\n", - timer_index, count); + trace_slavio_timer_mem_writel_limit(timer_index, count); ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count)); - } else - DPRINTF("not user timer\n"); + } else { + trace_slavio_timer_mem_writel_counter_invalid(); + } break; case TIMER_COUNTER_NORST: // set limit without resetting counter @@ -263,13 +252,11 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, if (slavio_timer_is_user(tc)) { // start/stop user counter if ((val & 1) && !t->running) { - DPRINTF("processor %d user timer started\n", - timer_index); + trace_slavio_timer_mem_writel_status_start(timer_index); ptimer_run(t->timer, 0); t->running = 1; } else if (!(val & 1) && t->running) { - DPRINTF("processor %d user timer stopped\n", - timer_index); + trace_slavio_timer_mem_writel_status_stop(timer_index); ptimer_stop(t->timer); t->running = 0; } @@ -298,8 +285,7 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, // set this processors user timer bit in config // register s->cputimer_mode |= processor; - DPRINTF("processor %d changed from counter to user " - "timer\n", timer_index); + trace_slavio_timer_mem_writel_mode_user(timer_index); } else { // user timer -> counter // stop the user timer if it is running if (curr_timer->running) { @@ -311,17 +297,16 @@ static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, // clear this processors user timer bit in config // register s->cputimer_mode &= ~processor; - DPRINTF("processor %d changed from user timer to " - "counter\n", timer_index); + trace_slavio_timer_mem_writel_mode_counter(timer_index); } } } } else { - DPRINTF("not system timer\n"); + trace_slavio_timer_mem_writel_mode_invalid(); } break; default: - DPRINTF("invalid write address " TARGET_FMT_plx "\n", addr); + trace_slavio_timer_mem_writel_invalid(addr); break; } } diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index 984ffc3e53..0904188c95 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -29,9 +29,7 @@ #include "sparc32_dma.h" #include "sun4m.h" #include "sysbus.h" - -/* debug DMA */ -//#define DEBUG_DMA +#include "trace.h" /* * This is the DMA controller part of chip STP2000 (Master I/O), also @@ -41,13 +39,6 @@ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/DMA2.txt */ -#ifdef DEBUG_DMA -#define DPRINTF(fmt, ...) \ - do { printf("DMA: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) -#endif - #define DMA_REGS 4 #define DMA_SIZE (4 * sizeof(uint32_t)) /* We need the mask, because one instance of the device is not page @@ -88,9 +79,8 @@ void ledma_memory_read(void *opaque, target_phys_addr_t addr, DMAState *s = opaque; int i; - DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n", - s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); addr |= s->dmaregs[3]; + trace_ledma_memory_read(addr); if (do_bswap) { sparc_iommu_memory_read(s->iommu, addr, buf, len); } else { @@ -110,9 +100,8 @@ void ledma_memory_write(void *opaque, target_phys_addr_t addr, int l, i; uint16_t tmp_buf[32]; - DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n", - s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); addr |= s->dmaregs[3]; + trace_ledma_memory_write(addr); if (do_bswap) { sparc_iommu_memory_write(s->iommu, addr, buf, len); } else { @@ -139,14 +128,14 @@ static void dma_set_irq(void *opaque, int irq, int level) if (level) { s->dmaregs[0] |= DMA_INTR; if (s->dmaregs[0] & DMA_INTREN) { - DPRINTF("Raise IRQ\n"); + trace_sparc32_dma_set_irq_raise(); qemu_irq_raise(s->irq); } } else { if (s->dmaregs[0] & DMA_INTR) { s->dmaregs[0] &= ~DMA_INTR; if (s->dmaregs[0] & DMA_INTREN) { - DPRINTF("Lower IRQ\n"); + trace_sparc32_dma_set_irq_lower(); qemu_irq_lower(s->irq); } } @@ -157,8 +146,7 @@ void espdma_memory_read(void *opaque, uint8_t *buf, int len) { DMAState *s = opaque; - DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n", - s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); + trace_espdma_memory_read(s->dmaregs[1]); sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len); s->dmaregs[1] += len; } @@ -167,8 +155,7 @@ void espdma_memory_write(void *opaque, uint8_t *buf, int len) { DMAState *s = opaque; - DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n", - s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); + trace_espdma_memory_write(s->dmaregs[1]); sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len); s->dmaregs[1] += len; } @@ -179,9 +166,7 @@ static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr) uint32_t saddr; saddr = (addr & DMA_MASK) >> 2; - DPRINTF("read dmareg " TARGET_FMT_plx ": 0x%8.8x\n", addr, - s->dmaregs[saddr]); - + trace_sparc32_dma_mem_readl(addr, s->dmaregs[saddr]); return s->dmaregs[saddr]; } @@ -191,18 +176,17 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) uint32_t saddr; saddr = (addr & DMA_MASK) >> 2; - DPRINTF("write dmareg " TARGET_FMT_plx ": 0x%8.8x -> 0x%8.8x\n", addr, - s->dmaregs[saddr], val); + trace_sparc32_dma_mem_writel(addr, s->dmaregs[saddr], val); switch (saddr) { case 0: if (val & DMA_INTREN) { if (s->dmaregs[0] & DMA_INTR) { - DPRINTF("Raise IRQ\n"); + trace_sparc32_dma_set_irq_raise(); qemu_irq_raise(s->irq); } } else { if (s->dmaregs[0] & (DMA_INTR | DMA_INTREN)) { - DPRINTF("Lower IRQ\n"); + trace_sparc32_dma_set_irq_lower(); qemu_irq_lower(s->irq); } } @@ -215,10 +199,10 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) val = DMA_DRAIN_FIFO; if (val & DMA_EN && !(s->dmaregs[0] & DMA_EN)) { - DPRINTF("Raise DMA enable\n"); + trace_sparc32_dma_enable_raise(); qemu_irq_raise(s->gpio[GPIO_DMA]); } else if (!(val & DMA_EN) && !!(s->dmaregs[0] & DMA_EN)) { - DPRINTF("Lower DMA enable\n"); + trace_sparc32_dma_enable_lower(); qemu_irq_lower(s->gpio[GPIO_DMA]); } diff --git a/hw/sun4m.c b/hw/sun4m.c index 0392109230..4795b3f45e 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -41,8 +41,7 @@ #include "loader.h" #include "elf.h" #include "blockdev.h" - -//#define DEBUG_IRQ +#include "trace.h" /* * Sun4m architecture was used in the following machines: @@ -72,13 +71,6 @@ * See for example: http://www.sunhelp.org/faq/sunref1.html */ -#ifdef DEBUG_IRQ -#define DPRINTF(fmt, ...) \ - do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) -#endif - #define KERNEL_LOAD_ADDR 0x00004000 #define CMDLINE_ADDR 0x007ff000 #define INITRD_LOAD_ADDR 0x00800000 @@ -248,14 +240,14 @@ void cpu_check_irqs(CPUState *env) env->interrupt_index = TT_EXTINT | i; if (old_interrupt != env->interrupt_index) { - DPRINTF("Set CPU IRQ %d\n", i); + trace_sun4m_cpu_interrupt(i); cpu_interrupt(env, CPU_INTERRUPT_HARD); } break; } } } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { - DPRINTF("Reset CPU IRQ %d\n", env->interrupt_index & 15); + trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15); env->interrupt_index = 0; cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); } @@ -266,12 +258,12 @@ static void cpu_set_irq(void *opaque, int irq, int level) CPUState *env = opaque; if (level) { - DPRINTF("Raise CPU IRQ %d\n", irq); + trace_sun4m_cpu_set_irq_raise(irq); env->halted = 0; env->pil_in |= 1 << irq; cpu_check_irqs(env); } else { - DPRINTF("Lower CPU IRQ %d\n", irq); + trace_sun4m_cpu_set_irq_lower(irq); env->pil_in &= ~(1 << irq); cpu_check_irqs(env); } diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c index 1dbe077466..720ee3f0bd 100644 --- a/hw/sun4m_iommu.c +++ b/hw/sun4m_iommu.c @@ -24,16 +24,7 @@ #include "sun4m.h" #include "sysbus.h" - -/* debug iommu */ -//#define DEBUG_IOMMU - -#ifdef DEBUG_IOMMU -#define DPRINTF(fmt, ...) \ - do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) -#endif +#include "trace.h" /* * I/O MMU used by Sun4m systems @@ -160,7 +151,7 @@ static uint32_t iommu_mem_readl(void *opaque, target_phys_addr_t addr) qemu_irq_lower(s->irq); break; } - DPRINTF("read reg[%d] = %x\n", (int)saddr, ret); + trace_sun4m_iommu_mem_readl(saddr, ret); return ret; } @@ -171,7 +162,7 @@ static void iommu_mem_writel(void *opaque, target_phys_addr_t addr, target_phys_addr_t saddr; saddr = addr >> 2; - DPRINTF("write reg[%d] = %x\n", (int)saddr, val); + trace_sun4m_iommu_mem_writel(saddr, val); switch (saddr) { case IOMMU_CTRL: switch (val & IOMMU_CTRL_RNGE) { @@ -201,18 +192,18 @@ static void iommu_mem_writel(void *opaque, target_phys_addr_t addr, s->iostart = 0xffffffff80000000ULL; break; } - DPRINTF("iostart = " TARGET_FMT_plx "\n", s->iostart); + trace_sun4m_iommu_mem_writel_ctrl(s->iostart); s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | s->version); break; case IOMMU_BASE: s->regs[saddr] = val & IOMMU_BASE_MASK; break; case IOMMU_TLBFLUSH: - DPRINTF("tlb flush %x\n", val); + trace_sun4m_iommu_mem_writel_tlbflush(val); s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK; break; case IOMMU_PGFLUSH: - DPRINTF("page flush %x\n", val); + trace_sun4m_iommu_mem_writel_pgflush(val); s->regs[saddr] = val & IOMMU_PGFLUSH_MASK; break; case IOMMU_AFAR: @@ -262,18 +253,14 @@ static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr) { uint32_t ret; target_phys_addr_t iopte; -#ifdef DEBUG_IOMMU target_phys_addr_t pa = addr; -#endif iopte = s->regs[IOMMU_BASE] << 4; addr &= ~s->iostart; iopte += (addr >> (IOMMU_PAGE_SHIFT - 2)) & ~3; cpu_physical_memory_read(iopte, (uint8_t *)&ret, 4); tswap32s(&ret); - DPRINTF("get flags addr " TARGET_FMT_plx " => pte " TARGET_FMT_plx - ", *pte = %x\n", pa, iopte, ret); - + trace_sun4m_iommu_page_get_flags(pa, iopte, ret); return ret; } @@ -283,16 +270,14 @@ static target_phys_addr_t iommu_translate_pa(target_phys_addr_t addr, target_phys_addr_t pa; pa = ((pte & IOPTE_PAGE) << 4) + (addr & ~IOMMU_PAGE_MASK); - DPRINTF("xlate dva " TARGET_FMT_plx " => pa " TARGET_FMT_plx - " (iopte = %x)\n", addr, pa, pte); - + trace_sun4m_iommu_translate_pa(addr, pa, pte); return pa; } static void iommu_bad_addr(IOMMUState *s, target_phys_addr_t addr, int is_write) { - DPRINTF("bad addr " TARGET_FMT_plx "\n", addr); + trace_sun4m_iommu_bad_addr(addr); s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | IOMMU_AFSR_RESV | IOMMU_AFSR_FAV; if (!is_write) diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index a1df26dbcf..dbe207070e 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -106,7 +106,13 @@ static void virtio_blk_flush_complete(void *opaque, int ret) { VirtIOBlockReq *req = opaque; - virtio_blk_req_complete(req, ret ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK); + if (ret) { + if (virtio_blk_handle_rw_error(req, -ret, 0)) { + return; + } + } + + virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); } static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s) diff --git a/m68k-semi.c b/m68k-semi.c index d16bc671c6..0371089b98 100644 --- a/m68k-semi.c +++ b/m68k-semi.c @@ -33,10 +33,10 @@ #define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024) #else #include "qemu-common.h" -#include "sysemu.h" #include "gdbstub.h" #include "softmmu-semi.h" #endif +#include "sysemu.h" #define HOSTED_EXIT 0 #define HOSTED_INIT_SIM 1 @@ -3976,6 +3976,11 @@ static void file_completion(const char *input) d = readdir(ffs); if (!d) break; + + if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) { + continue; + } + if (strstart(d->d_name, file_prefix, NULL)) { memcpy(file, input, input_path_len); if (input_path_len < sizeof(file)) diff --git a/os-posix.c b/os-posix.c index 6321e990c5..38c29d1afe 100644 --- a/os-posix.c +++ b/os-posix.c @@ -43,6 +43,10 @@ #include <sys/prctl.h> #endif +#ifdef CONFIG_EVENTFD +#include <sys/eventfd.h> +#endif + static struct passwd *user_pwd; static const char *chroot_dir; static int daemonize; @@ -329,3 +333,52 @@ void os_set_line_buffering(void) { setvbuf(stdout, NULL, _IOLBF, 0); } + +/* + * Creates an eventfd that looks like a pipe and has EFD_CLOEXEC set. + */ +int qemu_eventfd(int fds[2]) +{ +#ifdef CONFIG_EVENTFD + int ret; + + ret = eventfd(0, 0); + if (ret >= 0) { + fds[0] = ret; + qemu_set_cloexec(ret); + if ((fds[1] = dup(ret)) == -1) { + close(ret); + return -1; + } + qemu_set_cloexec(fds[1]); + return 0; + } + + if (errno != ENOSYS) { + return -1; + } +#endif + + return qemu_pipe(fds); +} + +int qemu_create_pidfile(const char *filename) +{ + char buffer[128]; + int len; + int fd; + + fd = qemu_open(filename, O_RDWR | O_CREAT, 0600); + if (fd == -1) { + return -1; + } + if (lockf(fd, F_TLOCK, 0) == -1) { + return -1; + } + len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); + if (write(fd, buffer, len) != len) { + return -1; + } + + return 0; +} diff --git a/os-win32.c b/os-win32.c index 3c6f50fa94..566d5e9853 100644 --- a/os-win32.c +++ b/os-win32.c @@ -240,3 +240,27 @@ void os_pidfile_error(void) { fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno)); } + +int qemu_create_pidfile(const char *filename) +{ + char buffer[128]; + int len; + HANDLE file; + OVERLAPPED overlap; + BOOL ret; + memset(&overlap, 0, sizeof(overlap)); + + file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (file == INVALID_HANDLE_VALUE) { + return -1; + } + len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); + ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len, + &overlap, NULL); + if (ret == 0) { + return -1; + } + return 0; +} @@ -44,108 +44,11 @@ extern int madvise(caddr_t, size_t, int); #endif -#ifdef CONFIG_EVENTFD -#include <sys/eventfd.h> -#endif - -#ifdef _WIN32 -#include <windows.h> -#elif defined(CONFIG_BSD) -#include <stdlib.h> -#else -#include <malloc.h> -#endif - #include "qemu-common.h" #include "trace.h" #include "sysemu.h" #include "qemu_socket.h" -#if !defined(_POSIX_C_SOURCE) || defined(_WIN32) || defined(__sun__) -static void *oom_check(void *ptr) -{ - if (ptr == NULL) { -#if defined(_WIN32) - fprintf(stderr, "Failed to allocate memory: %lu\n", GetLastError()); -#else - fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno)); -#endif - abort(); - } - return ptr; -} -#endif - -#if defined(_WIN32) -void *qemu_memalign(size_t alignment, size_t size) -{ - void *ptr; - - if (!size) { - abort(); - } - ptr = oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE)); - trace_qemu_memalign(alignment, size, ptr); - return ptr; -} - -void *qemu_vmalloc(size_t size) -{ - void *ptr; - - /* FIXME: this is not exactly optimal solution since VirtualAlloc - has 64Kb granularity, but at least it guarantees us that the - memory is page aligned. */ - if (!size) { - abort(); - } - ptr = oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE)); - trace_qemu_vmalloc(size, ptr); - return ptr; -} - -void qemu_vfree(void *ptr) -{ - trace_qemu_vfree(ptr); - VirtualFree(ptr, 0, MEM_RELEASE); -} - -#else - -void *qemu_memalign(size_t alignment, size_t size) -{ - void *ptr; -#if defined(_POSIX_C_SOURCE) && !defined(__sun__) - int ret; - ret = posix_memalign(&ptr, alignment, size); - if (ret != 0) { - fprintf(stderr, "Failed to allocate %zu B: %s\n", - size, strerror(ret)); - abort(); - } -#elif defined(CONFIG_BSD) - ptr = oom_check(valloc(size)); -#else - ptr = oom_check(memalign(alignment, size)); -#endif - trace_qemu_memalign(alignment, size, ptr); - return ptr; -} - -/* alloc shared memory pages */ -void *qemu_vmalloc(size_t size) -{ - return qemu_memalign(getpagesize(), size); -} - -void qemu_vfree(void *ptr) -{ - trace_qemu_vfree(ptr); - free(ptr); -} - -#endif - int qemu_madvise(void *addr, size_t len, int advice) { if (advice == QEMU_MADV_INVALID) { @@ -162,113 +65,6 @@ int qemu_madvise(void *addr, size_t len, int advice) #endif } -int qemu_create_pidfile(const char *filename) -{ - char buffer[128]; - int len; -#ifndef _WIN32 - int fd; - - fd = qemu_open(filename, O_RDWR | O_CREAT, 0600); - if (fd == -1) - return -1; - - if (lockf(fd, F_TLOCK, 0) == -1) - return -1; - - len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); - if (write(fd, buffer, len) != len) - return -1; -#else - HANDLE file; - OVERLAPPED overlap; - BOOL ret; - memset(&overlap, 0, sizeof(overlap)); - - file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - if (file == INVALID_HANDLE_VALUE) - return -1; - - len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); - ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len, - &overlap, NULL); - if (ret == 0) - return -1; -#endif - return 0; -} - -#ifdef _WIN32 - -/* mingw32 needs ffs for compilations without optimization. */ -int ffs(int i) -{ - /* Use gcc's builtin ffs. */ - return __builtin_ffs(i); -} - -/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ -#define _W32_FT_OFFSET (116444736000000000ULL) - -int qemu_gettimeofday(qemu_timeval *tp) -{ - union { - unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */ - FILETIME ft; - } _now; - - if(tp) - { - GetSystemTimeAsFileTime (&_now.ft); - tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL ); - tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL); - } - /* Always return 0 as per Open Group Base Specifications Issue 6. - Do not set errno on error. */ - return 0; -} -#endif /* _WIN32 */ - - -#ifdef _WIN32 -void socket_set_nonblock(int fd) -{ - unsigned long opt = 1; - ioctlsocket(fd, FIONBIO, &opt); -} - -int inet_aton(const char *cp, struct in_addr *ia) -{ - uint32_t addr = inet_addr(cp); - if (addr == 0xffffffff) - return 0; - ia->s_addr = addr; - return 1; -} - -void qemu_set_cloexec(int fd) -{ -} - -#else - -void socket_set_nonblock(int fd) -{ - int f; - f = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, f | O_NONBLOCK); -} - -void qemu_set_cloexec(int fd) -{ - int f; - f = fcntl(fd, F_GETFD); - fcntl(fd, F_SETFD, f | FD_CLOEXEC); -} - -#endif /* * Opens a file with FD_CLOEXEC set @@ -330,58 +126,6 @@ ssize_t qemu_write_full(int fd, const void *buf, size_t count) return total; } -#ifndef _WIN32 -/* - * Creates an eventfd that looks like a pipe and has EFD_CLOEXEC set. - */ -int qemu_eventfd(int fds[2]) -{ -#ifdef CONFIG_EVENTFD - int ret; - - ret = eventfd(0, 0); - if (ret >= 0) { - fds[0] = ret; - qemu_set_cloexec(ret); - if ((fds[1] = dup(ret)) == -1) { - close(ret); - return -1; - } - qemu_set_cloexec(fds[1]); - return 0; - } - - if (errno != ENOSYS) { - return -1; - } -#endif - - return qemu_pipe(fds); -} - -/* - * Creates a pipe with FD_CLOEXEC set on both file descriptors - */ -int qemu_pipe(int pipefd[2]) -{ - int ret; - -#ifdef CONFIG_PIPE2 - ret = pipe2(pipefd, O_CLOEXEC); - if (ret != -1 || errno != ENOSYS) { - return ret; - } -#endif - ret = pipe(pipefd); - if (ret == 0) { - qemu_set_cloexec(pipefd[0]); - qemu_set_cloexec(pipefd[1]); - } - - return ret; -} -#endif - /* * Opens a socket with FD_CLOEXEC set */ @@ -127,19 +127,4 @@ int qemu_madvise(void *addr, size_t len, int advice); int qemu_create_pidfile(const char *filename); -#ifdef _WIN32 -int ffs(int i); - -int setenv(const char *name, const char *value, int overwrite); - -typedef struct { - long tv_sec; - long tv_usec; -} qemu_timeval; -int qemu_gettimeofday(qemu_timeval *tp); -#else -typedef struct timeval qemu_timeval; -#define qemu_gettimeofday(tp) gettimeofday(tp, NULL); -#endif /* !_WIN32 */ - #endif diff --git a/oslib-posix.c b/oslib-posix.c new file mode 100644 index 0000000000..6e9b0c3c13 --- /dev/null +++ b/oslib-posix.c @@ -0,0 +1,109 @@ +/* + * os-posix-lib.c + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2010 Red Hat, Inc. + * + * QEMU library functions on POSIX which are shared between QEMU and + * the QEMU tools. + * + * 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. + */ + +#include "config-host.h" +#include "sysemu.h" +#include "trace.h" +#include "qemu_socket.h" + +void *qemu_oom_check(void *ptr) +{ + if (ptr == NULL) { + fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno)); + abort(); + } + return ptr; +} + +void *qemu_memalign(size_t alignment, size_t size) +{ + void *ptr; +#if defined(_POSIX_C_SOURCE) && !defined(__sun__) + int ret; + ret = posix_memalign(&ptr, alignment, size); + if (ret != 0) { + fprintf(stderr, "Failed to allocate %zu B: %s\n", + size, strerror(ret)); + abort(); + } +#elif defined(CONFIG_BSD) + ptr = qemu_oom_check(valloc(size)); +#else + ptr = qemu_oom_check(memalign(alignment, size)); +#endif + trace_qemu_memalign(alignment, size, ptr); + return ptr; +} + +/* alloc shared memory pages */ +void *qemu_vmalloc(size_t size) +{ + return qemu_memalign(getpagesize(), size); +} + +void qemu_vfree(void *ptr) +{ + trace_qemu_vfree(ptr); + free(ptr); +} + +void socket_set_nonblock(int fd) +{ + int f; + f = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, f | O_NONBLOCK); +} + +void qemu_set_cloexec(int fd) +{ + int f; + f = fcntl(fd, F_GETFD); + fcntl(fd, F_SETFD, f | FD_CLOEXEC); +} + +/* + * Creates a pipe with FD_CLOEXEC set on both file descriptors + */ +int qemu_pipe(int pipefd[2]) +{ + int ret; + +#ifdef CONFIG_PIPE2 + ret = pipe2(pipefd, O_CLOEXEC); + if (ret != -1 || errno != ENOSYS) { + return ret; + } +#endif + ret = pipe(pipefd); + if (ret == 0) { + qemu_set_cloexec(pipefd[0]); + qemu_set_cloexec(pipefd[1]); + } + + return ret; +} diff --git a/oslib-win32.c b/oslib-win32.c new file mode 100644 index 0000000000..ab29eae45c --- /dev/null +++ b/oslib-win32.c @@ -0,0 +1,121 @@ +/* + * os-win32.c + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2010 Red Hat, Inc. + * + * QEMU library functions for win32 which are shared between QEMU and + * the QEMU tools. + * + * 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. + */ +#include <windows.h> +#include "config-host.h" +#include "sysemu.h" +#include "trace.h" +#include "qemu_socket.h" + +void *qemu_oom_check(void *ptr) +{ + if (ptr == NULL) { + fprintf(stderr, "Failed to allocate memory: %lu\n", GetLastError()); + abort(); + } + return ptr; +} + +void *qemu_memalign(size_t alignment, size_t size) +{ + void *ptr; + + if (!size) { + abort(); + } + ptr = qemu_oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE)); + trace_qemu_memalign(alignment, size, ptr); + return ptr; +} + +void *qemu_vmalloc(size_t size) +{ + void *ptr; + + /* FIXME: this is not exactly optimal solution since VirtualAlloc + has 64Kb granularity, but at least it guarantees us that the + memory is page aligned. */ + if (!size) { + abort(); + } + ptr = qemu_oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE)); + trace_qemu_vmalloc(size, ptr); + return ptr; +} + +void qemu_vfree(void *ptr) +{ + trace_qemu_vfree(ptr); + VirtualFree(ptr, 0, MEM_RELEASE); +} + +void socket_set_nonblock(int fd) +{ + unsigned long opt = 1; + ioctlsocket(fd, FIONBIO, &opt); +} + +int inet_aton(const char *cp, struct in_addr *ia) +{ + uint32_t addr = inet_addr(cp); + if (addr == 0xffffffff) { + return 0; + } + ia->s_addr = addr; + return 1; +} + +void qemu_set_cloexec(int fd) +{ +} + +/* mingw32 needs ffs for compilations without optimization. */ +int ffs(int i) +{ + /* Use gcc's builtin ffs. */ + return __builtin_ffs(i); +} + +/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ +#define _W32_FT_OFFSET (116444736000000000ULL) + +int qemu_gettimeofday(qemu_timeval *tp) +{ + union { + unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */ + FILETIME ft; + } _now; + + if(tp) { + GetSystemTimeAsFileTime (&_now.ft); + tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL ); + tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL); + } + /* Always return 0 as per Open Group Base Specifications Issue 6. + Do not set errno on error. */ + return 0; +} diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin Binary files differindex d0d4b6aa43..f79c342264 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin diff --git a/posix-aio-compat.c b/posix-aio-compat.c index 7b862b5400..fa5494db8c 100644 --- a/posix-aio-compat.c +++ b/posix-aio-compat.c @@ -24,6 +24,7 @@ #include "qemu-queue.h" #include "osdep.h" +#include "sysemu.h" #include "qemu-common.h" #include "trace.h" #include "block_int.h" diff --git a/qemu-common.h b/qemu-common.h index 2498769efa..21fc3a5308 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -81,6 +81,9 @@ struct iovec { #define GCC_FMT_ATTR(n, m) #endif +typedef int (*fprintf_function)(FILE *f, const char *fmt, ...) + GCC_FMT_ATTR(2, 3); + #ifdef _WIN32 #define fsync _commit #define lseek _lseeki64 @@ -167,6 +170,12 @@ const char *path(const char *pathname); #define qemu_isascii(c) isascii((unsigned char)(c)) #define qemu_toascii(c) toascii((unsigned char)(c)) +#ifdef _WIN32 +/* ffs() in oslib-win32.c for WIN32, strings.h for the rest of the world */ +int ffs(int i); +#endif + +void *qemu_oom_check(void *ptr); void *qemu_malloc(size_t size); void *qemu_realloc(void *ptr, size_t size); void *qemu_mallocz(size_t size); @@ -313,6 +322,30 @@ static inline uint8_t from_bcd(uint8_t val) return ((val >> 4) * 10) + (val & 0x0f); } +/* compute with 96 bit intermediate result: (a*b)/c */ +static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) +{ + union { + uint64_t ll; + struct { +#ifdef HOST_WORDS_BIGENDIAN + uint32_t high, low; +#else + uint32_t low, high; +#endif + } l; + } u, res; + uint64_t rl, rh; + + u.ll = a; + rl = (uint64_t)u.l.low * (uint64_t)b; + rh = (uint64_t)u.l.high * (uint64_t)b; + rh += (rl >> 32); + res.l.high = rh / c; + res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; + return res.ll; +} + #include "module.h" #endif diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 6d3e5f8e69..6c7176f8b4 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -28,9 +28,9 @@ STEXI ETEXI DEF("convert", img_convert, - "convert [-c] [-f fmt] [-O output_fmt] [-o options] filename [filename2 [...]] output_filename") + "convert [-c] [-f fmt] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename") STEXI -@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] @var{filename} [@var{filename2} [...]] @var{output_filename} +@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename} ETEXI DEF("info", img_info, diff --git a/qemu-img.c b/qemu-img.c index 578b8ebe8c..fa77ac0dbe 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -24,6 +24,7 @@ #include "qemu-common.h" #include "qemu-option.h" #include "osdep.h" +#include "sysemu.h" #include "block_int.h" #include <stdio.h> @@ -645,14 +646,16 @@ static int img_convert(int argc, char **argv) const uint8_t *buf1; BlockDriverInfo bdi; QEMUOptionParameter *param = NULL, *create_options = NULL; + QEMUOptionParameter *out_baseimg_param; char *options = NULL; + const char *snapshot_name = NULL; fmt = NULL; out_fmt = "raw"; out_baseimg = NULL; flags = 0; for(;;) { - c = getopt(argc, argv, "f:O:B:hce6o:"); + c = getopt(argc, argv, "f:O:B:s:hce6o:"); if (c == -1) break; switch(c) { @@ -680,6 +683,9 @@ static int img_convert(int argc, char **argv) case 'o': options = optarg; break; + case 's': + snapshot_name = optarg; + break; } } @@ -711,6 +717,19 @@ static int img_convert(int argc, char **argv) total_sectors += bs_sectors; } + if (snapshot_name != NULL) { + if (bs_n > 1) { + error("No support for concatenating multiple snapshot\n"); + ret = -1; + goto out; + } + if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) { + error("Failed to load snapshot\n"); + ret = -1; + goto out; + } + } + /* Find driver and parse its options */ drv = bdrv_find_format(out_fmt); if (!drv) { @@ -752,6 +771,12 @@ static int img_convert(int argc, char **argv) goto out; } + /* Get backing file name if -o backing_file was used */ + out_baseimg_param = get_option_parameter(param, BLOCK_OPT_BACKING_FILE); + if (out_baseimg_param) { + out_baseimg = out_baseimg_param->value.s; + } + /* Check if compression is supported */ if (flags & BLOCK_FLAG_COMPRESS) { QEMUOptionParameter *encryption = diff --git a/qemu-img.texi b/qemu-img.texi index c1b1f2717e..1b90ddbcfc 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -77,9 +77,9 @@ it doesn't need to be specified separately in this case. Commit the changes recorded in @var{filename} in its base image. -@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] @var{filename} [@var{filename2} [...]] @var{output_filename} +@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename} -Convert the disk image @var{filename} to disk image @var{output_filename} +Convert the disk image @var{filename} or a snapshot @var{snapshot_name} to disk image @var{output_filename} using format @var{output_fmt}. It can be optionally compressed (@code{-c} option) or use any format specific options like encryption (@code{-o} option). @@ -1443,6 +1443,44 @@ static const cmdinfo_t alloc_cmd = { }; static int +map_f(int argc, char **argv) +{ + int64_t offset; + int64_t nb_sectors; + char s1[64]; + int num, num_checked; + int ret; + const char *retstr; + + offset = 0; + nb_sectors = bs->total_sectors; + + do { + num_checked = MIN(nb_sectors, INT_MAX); + ret = bdrv_is_allocated(bs, offset, num_checked, &num); + retstr = ret ? " allocated" : "not allocated"; + cvtstr(offset << 9ULL, s1, sizeof(s1)); + printf("[% 24" PRId64 "] % 8d/% 8d sectors %s at offset %s (%d)\n", + offset << 9ULL, num, num_checked, retstr, s1, ret); + + offset += num; + nb_sectors -= num; + } while(offset < bs->total_sectors); + + return 0; +} + +static const cmdinfo_t map_cmd = { + .name = "map", + .argmin = 0, + .argmax = 0, + .cfunc = map_f, + .args = "", + .oneline = "prints the allocated areas of a file", +}; + + +static int close_f(int argc, char **argv) { bdrv_close(bs); @@ -1680,6 +1718,7 @@ int main(int argc, char **argv) add_command(&length_cmd); add_command(&info_cmd); add_command(&alloc_cmd); + add_command(&map_cmd); add_args_command(init_args_command); add_check_command(init_check_command); diff --git a/qemu-malloc.c b/qemu-malloc.c index ecffb676e2..28fb05a481 100644 --- a/qemu-malloc.c +++ b/qemu-malloc.c @@ -25,14 +25,6 @@ #include "trace.h" #include <stdlib.h> -static void *oom_check(void *ptr) -{ - if (ptr == NULL) { - abort(); - } - return ptr; -} - void qemu_free(void *ptr) { trace_qemu_free(ptr); @@ -54,7 +46,7 @@ void *qemu_malloc(size_t size) if (!size && !allow_zero_malloc()) { abort(); } - ptr = oom_check(malloc(size ? size : 1)); + ptr = qemu_oom_check(malloc(size ? size : 1)); trace_qemu_malloc(size, ptr); return ptr; } @@ -65,7 +57,7 @@ void *qemu_realloc(void *ptr, size_t size) if (!size && !allow_zero_malloc()) { abort(); } - newptr = oom_check(realloc(ptr, size ? size : 1)); + newptr = qemu_oom_check(realloc(ptr, size ? size : 1)); trace_qemu_realloc(ptr, size, newptr); return newptr; } @@ -75,7 +67,7 @@ void *qemu_mallocz(size_t size) if (!size && !allow_zero_malloc()) { abort(); } - return oom_check(calloc(1, size ? size : 1)); + return qemu_oom_check(calloc(1, size ? size : 1)); } char *qemu_strdup(const char *str) diff --git a/qemu-os-posix.h b/qemu-os-posix.h index ed5c058bc3..353f87813f 100644 --- a/qemu-os-posix.h +++ b/qemu-os-posix.h @@ -36,4 +36,7 @@ void os_setup_signal_handling(void); void os_daemonize(void); void os_setup_post(void); +typedef struct timeval qemu_timeval; +#define qemu_gettimeofday(tp) gettimeofday(tp, NULL) + #endif diff --git a/qemu-os-win32.h b/qemu-os-win32.h index c63778d2fc..1a07e5e264 100644 --- a/qemu-os-win32.h +++ b/qemu-os-win32.h @@ -52,4 +52,12 @@ static inline void os_set_proc_name(const char *dummy) {} # define EPROTONOSUPPORT EINVAL #endif +int setenv(const char *name, const char *value, int overwrite); + +typedef struct { + long tv_sec; + long tv_usec; +} qemu_timeval; +int qemu_gettimeofday(qemu_timeval *tp); + #endif diff --git a/qemu-timer.h b/qemu-timer.h index 299e387768..8cd8f8368a 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -59,30 +59,6 @@ static inline int64_t get_ticks_per_sec(void) return 1000000000LL; } -/* compute with 96 bit intermediate result: (a*b)/c */ -static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) -{ - union { - uint64_t ll; - struct { -#ifdef HOST_WORDS_BIGENDIAN - uint32_t high, low; -#else - uint32_t low, high; -#endif - } l; - } u, res; - uint64_t rl, rh; - - u.ll = a; - rl = (uint64_t)u.l.low * (uint64_t)b; - rh = (uint64_t)u.l.high * (uint64_t)b; - rh += (rl >> 32); - res.l.high = rh / c; - res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; - return res.ll; -} - /* real time host monotonic timer */ static inline int64_t get_clock_realtime(void) { diff --git a/qemu-tool.c b/qemu-tool.c index 9ccca655ef..392e1c9505 100644 --- a/qemu-tool.c +++ b/qemu-tool.c @@ -15,6 +15,7 @@ #include "monitor.h" #include "qemu-timer.h" #include "qemu-log.h" +#include "sysemu.h" #include <sys/time.h> diff --git a/roms/seabios b/roms/seabios -Subproject 17d3e46511aeedc9f09a8216d194d749187b80a +Subproject 0ff9051f756ba739bc2edca77925191c3c6cbc2 @@ -675,6 +675,27 @@ uint64_t qemu_get_be64(QEMUFile *f) return v; } +/* bool */ + +static int get_bool(QEMUFile *f, void *pv, size_t size) +{ + bool *v = pv; + *v = qemu_get_byte(f); + return 0; +} + +static void put_bool(QEMUFile *f, void *pv, size_t size) +{ + bool *v = pv; + qemu_put_byte(f, *v); +} + +const VMStateInfo vmstate_info_bool = { + .name = "bool", + .get = get_bool, + .put = put_bool, +}; + /* 8 bit int */ static int get_int8(QEMUFile *f, void *pv, size_t size) diff --git a/target-alpha/helper.c b/target-alpha/helper.c index b6d21601d5..3ba4478c8e 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -537,8 +537,7 @@ void do_interrupt (CPUState *env) } #endif -void cpu_dump_state (CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { static const char *linux_reg_names[] = { diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 39c4a0e987..b87c605f7f 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -25,6 +25,8 @@ #define CPUState struct CPUARMState +#include "config.h" +#include "qemu-common.h" #include "cpu-defs.h" #include "softfloat.h" @@ -353,7 +355,7 @@ static inline int arm_feature(CPUARMState *env, int feature) return (env->features & (1u << feature)) != 0; } -void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf); /* Interface between CPU and Interrupt controller. */ void armv7m_nvic_set_pending(void *opaque, int irq); diff --git a/target-arm/helper.c b/target-arm/helper.c index 2dd64d94d8..996d40d185 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -348,7 +348,7 @@ static const struct arm_cpu_t arm_cpu_names[] = { { 0, NULL} }; -void arm_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf) { int i; diff --git a/target-arm/translate.c b/target-arm/translate.c index 6fcdd7e544..99464ab730 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -9262,8 +9262,7 @@ static const char *cpu_mode_names[16] = { "???", "???", "???", "und", "???", "???", "???", "sys" }; -void cpu_dump_state(CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { int i; diff --git a/target-cris/cpu.h b/target-cris/cpu.h index e1d48ed77e..d9087759d3 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -263,6 +263,6 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, } #define cpu_list cris_cpu_list -void cris_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf); #endif diff --git a/target-cris/translate.c b/target-cris/translate.c index 8361369214..4e4606cb25 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3426,8 +3426,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -void cpu_dump_state (CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { int i; @@ -3480,7 +3479,7 @@ struct {32, "crisv32"}, }; -void cris_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf) { unsigned int i; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 85ed30f7d3..2440d6536c 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -20,6 +20,7 @@ #define CPU_I386_H #include "config.h" +#include "qemu-common.h" #ifdef TARGET_X86_64 #define TARGET_LONG_BITS 64 @@ -756,8 +757,7 @@ typedef struct CPUX86State { CPUX86State *cpu_x86_init(const char *cpu_model); int cpu_x86_exec(CPUX86State *s); void cpu_x86_close(CPUX86State *s); -void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), - const char *optarg); +void x86_cpu_list (FILE *f, fprintf_function cpu_fprintf, const char *optarg); void x86_cpudef_setup(void); int cpu_get_pic_interrupt(CPUX86State *s); diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index 0e0bf60f4c..650a7192de 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -762,8 +762,7 @@ static void listflags(char *buf, int bufsize, uint32_t fbits, * -?dump output all model (x86_def_t) data * -?cpuid list all recognized cpuid flag names */ -void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), - const char *optarg) +void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf, const char *optarg) { unsigned char model = !strcmp("?model", optarg); unsigned char dump = !strcmp("?dump", optarg); diff --git a/target-i386/helper.c b/target-i386/helper.c index 4fff4a871f..26ea1e58e0 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -169,8 +169,7 @@ static const char *cc_op_str[] = { }; static void -cpu_x86_dump_seg_cache(CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +cpu_x86_dump_seg_cache(CPUState *env, FILE *f, fprintf_function cpu_fprintf, const char *name, struct SegmentCache *sc) { #ifdef TARGET_X86_64 @@ -224,8 +223,7 @@ done: cpu_fprintf(f, "\n"); } -void cpu_dump_state(CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { int eflags, i, nb; @@ -335,9 +333,11 @@ void cpu_dump_state(CPUState *env, FILE *f, (uint32_t)env->cr[2], (uint32_t)env->cr[3], (uint32_t)env->cr[4]); - for(i = 0; i < 4; i++) - cpu_fprintf(f, "DR%d=%08x ", i, env->dr[i]); - cpu_fprintf(f, "\nDR6=%08x DR7=%08x\n", env->dr[6], env->dr[7]); + for(i = 0; i < 4; i++) { + cpu_fprintf(f, "DR%d=" TARGET_FMT_lx " ", i, env->dr[i]); + } + cpu_fprintf(f, "\nDR6=" TARGET_FMT_lx " DR7=" TARGET_FMT_lx "\n", + env->dr[6], env->dr[7]); } if (flags & X86_DUMP_CCOP) { if ((unsigned)env->cc_op < CC_OP_NB) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 33c41b2ebc..b025b6689d 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -24,6 +24,7 @@ #define CPUState struct CPUM68KState +#include "qemu-common.h" #include "cpu-defs.h" #include "softfloat.h" @@ -198,7 +199,7 @@ static inline int m68k_feature(CPUM68KState *env, int feature) return (env->features & (1u << feature)) != 0; } -void m68k_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf); void register_m68k_insns (CPUM68KState *env); diff --git a/target-m68k/helper.c b/target-m68k/helper.c index b4ebb14e83..56de897c1d 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -53,7 +53,7 @@ static m68k_def_t m68k_cpu_defs[] = { {NULL, 0}, }; -void m68k_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf) { unsigned int i; diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 5351880c68..6f72a2bdd2 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3092,8 +3092,7 @@ void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -void cpu_dump_state(CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { int i; diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 38149bb357..1ada15e19d 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -1534,8 +1534,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -void cpu_dump_state (CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { int i; diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 19511d7f02..c1f211fc17 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -8,6 +8,7 @@ #define CPUState struct CPUMIPSState #include "config.h" +#include "qemu-common.h" #include "mips-defs.h" #include "cpu-defs.h" #include "softfloat.h" @@ -496,7 +497,7 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, int unused, int size); #endif -void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf); #define cpu_init cpu_mips_init #define cpu_exec cpu_mips_exec diff --git a/target-mips/translate.c b/target-mips/translate.c index d62c6158fc..ba45eb0e52 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -12450,8 +12450,7 @@ void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -static void fpu_dump_state(CPUState *env, FILE *f, - int (*fpu_fprintf)(FILE *f, const char *fmt, ...), +static void fpu_dump_state(CPUState *env, FILE *f, fprintf_function fpu_fprintf, int flags) { int i; @@ -12480,8 +12479,8 @@ static void fpu_dump_state(CPUState *env, FILE *f, } while(0) - fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%08x(0x%02x)\n", - env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64, env->active_fpu.fp_status, + fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%02x\n", + env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64, get_float_exception_flags(&env->active_fpu.fp_status)); for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { fpu_fprintf(f, "%3s: ", fregnames[i]); @@ -12499,7 +12498,7 @@ static void fpu_dump_state(CPUState *env, FILE *f, static void cpu_mips_check_sign_extensions (CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + fprintf_function cpu_fprintf, int flags) { int i; @@ -12525,8 +12524,7 @@ cpu_mips_check_sign_extensions (CPUState *env, FILE *f, } #endif -void cpu_dump_state (CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { int i; diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 8d1ece704d..590e092a1d 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -500,7 +500,7 @@ static const mips_def_t *cpu_mips_find_by_name (const char *name) return NULL; } -void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf) { int i; diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 1334dd1b46..deb8d7c9c5 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -20,7 +20,7 @@ #define __CPU_PPC_H__ #include "config.h" -#include <inttypes.h> +#include "qemu-common.h" //#define PPC_EMULATE_32BITS_HYPV @@ -761,7 +761,7 @@ void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value); #endif /* !defined(CONFIG_USER_ONLY) */ void ppc_store_msr (CPUPPCState *env, target_ulong value); -void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf); const ppc_def_t *cpu_ppc_find_by_name (const char *name); int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index fd0686182e..c82a4835d4 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -8830,8 +8830,7 @@ GEN_SPEOP_LDST(evstwwo, 0x1E, 2), /*****************************************************************************/ /* Misc PowerPC helpers */ -void cpu_dump_state (CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { #define RGPL 4 @@ -8840,15 +8839,15 @@ void cpu_dump_state (CPUState *env, FILE *f, int i; cpu_fprintf(f, "NIP " TARGET_FMT_lx " LR " TARGET_FMT_lx " CTR " - TARGET_FMT_lx " XER %08x\n", env->nip, env->lr, env->ctr, - env->xer); + TARGET_FMT_lx " XER " TARGET_FMT_lx "\n", + env->nip, env->lr, env->ctr, env->xer); cpu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF " TARGET_FMT_lx " idx %d\n", env->msr, env->spr[SPR_HID0], env->hflags, env->mmu_idx); #if !defined(NO_TIMER_DUMP) - cpu_fprintf(f, "TB %08x %08x " + cpu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 #if !defined(CONFIG_USER_ONLY) - "DECR %08x" + " DECR %08" PRIu32 #endif "\n", cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env) @@ -8898,8 +8897,7 @@ void cpu_dump_state (CPUState *env, FILE *f, #undef RFPL } -void cpu_dump_statistics (CPUState *env, FILE*f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_statistics (CPUState *env, FILE*f, fprintf_function cpu_fprintf, int flags) { #if defined(DO_PPC_STATISTICS) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 05ffe95762..dfcd94980f 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9756,7 +9756,7 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name) return ret; } -void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf) { int i, max; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 44dfa65085..881d8c4acf 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -23,8 +23,7 @@ #include "tcg-op.h" #include "qemu-log.h" -void cpu_dump_state(CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { int i; diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 64a609b8ad..e19776643b 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -20,6 +20,7 @@ #define _CPU_SH4_H #include "config.h" +#include "qemu-common.h" #define TARGET_LONG_BITS 32 #define TARGET_HAS_ICE 1 @@ -168,7 +169,7 @@ int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw, #define cpu_handle_mmu_fault cpu_sh4_handle_mmu_fault void do_interrupt(CPUSH4State * env); -void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf); #if !defined(CONFIG_USER_ONLY) void cpu_sh4_invalidate_tlb(CPUSH4State *s); void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, diff --git a/target-sh4/translate.c b/target-sh4/translate.c index deee939e12..f418139931 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -257,7 +257,7 @@ static const sh4_def_t *cpu_sh4_find_by_name(const char *name) return NULL; } -void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf) { int i; diff --git a/target-sparc/helper.c b/target-sparc/helper.c index aa1fd632cc..e84c31256f 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -1323,8 +1323,7 @@ static const char * const feature_name[] = { "gl", }; -static void print_features(FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +static void print_features(FILE *f, fprintf_function cpu_fprintf, uint32_t features, const char *prefix) { unsigned int i; @@ -1452,7 +1451,7 @@ static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model) return -1; } -void sparc_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf) { unsigned int i; @@ -1479,8 +1478,7 @@ void sparc_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) "fpu_version mmu_version nwindows\n"); } -static void cpu_print_cc(FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf, uint32_t cc) { cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-', @@ -1494,8 +1492,7 @@ static void cpu_print_cc(FILE *f, #define REGS_PER_LINE 8 #endif -void cpu_dump_state(CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags) { int i, x; @@ -2124,8 +2124,7 @@ int tcg_gen_code_search_pc(TCGContext *s, uint8_t *gen_code_buf, long offset) } #ifdef CONFIG_PROFILER -void tcg_dump_info(FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf) { TCGContext *s = &tcg_ctx; int64_t tot; @@ -2169,8 +2168,7 @@ void tcg_dump_info(FILE *f, dump_op_count(); } #else -void tcg_dump_info(FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) +void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf) { cpu_fprintf(f, "[TCG profiler not compiled]\n"); } @@ -392,8 +392,7 @@ static inline TCGv_i64 tcg_temp_local_new_i64(void) void tcg_temp_free_i64(TCGv_i64 arg); char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg); -void tcg_dump_info(FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +void tcg_dump_info(FILE *f, fprintf_function cpu_fprintf); #define TCG_CT_ALIAS 0x80 #define TCG_CT_IALIAS 0x40 diff --git a/trace-events b/trace-events index ed2055e425..947f8b08cb 100644 --- a/trace-events +++ b/trace-events @@ -81,3 +81,111 @@ disable apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x" disable apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d" disable apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d" disable apic_set_irq(int apic_irq_delivered) "coalescing %d" + +# hw/cs4231.c +disable cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x" +disable cs4231_mem_readl_reg(uint32_t reg, uint32_t ret) "read reg %d: 0x%08x" +disable cs4231_mem_writel_reg(uint32_t reg, uint32_t old, uint32_t val) "write reg %d: 0x%08x -> 0x%08x" +disable cs4231_mem_writel_dreg(uint32_t reg, uint32_t old, uint32_t val) "write dreg %d: 0x%02x -> 0x%02x" + +# hw/eccmemctl.c +disable ecc_mem_writel_mer(uint32_t val) "Write memory enable %08x" +disable ecc_mem_writel_mdr(uint32_t val) "Write memory delay %08x" +disable ecc_mem_writel_mfsr(uint32_t val) "Write memory fault status %08x" +disable ecc_mem_writel_vcr(uint32_t val) "Write slot configuration %08x" +disable ecc_mem_writel_dr(uint32_t val) "Write diagnostic %08x" +disable ecc_mem_writel_ecr0(uint32_t val) "Write event count 1 %08x" +disable ecc_mem_writel_ecr1(uint32_t val) "Write event count 2 %08x" +disable ecc_mem_readl_mer(uint32_t ret) "Read memory enable %08x" +disable ecc_mem_readl_mdr(uint32_t ret) "Read memory delay %08x" +disable ecc_mem_readl_mfsr(uint32_t ret) "Read memory fault status %08x" +disable ecc_mem_readl_vcr(uint32_t ret) "Read slot configuration %08x" +disable ecc_mem_readl_mfar0(uint32_t ret) "Read memory fault address 0 %08x" +disable ecc_mem_readl_mfar1(uint32_t ret) "Read memory fault address 1 %08x" +disable ecc_mem_readl_dr(uint32_t ret) "Read diagnostic %08x" +disable ecc_mem_readl_ecr0(uint32_t ret) "Read event count 1 %08x" +disable ecc_mem_readl_ecr1(uint32_t ret) "Read event count 2 %08x" +disable ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = %02x" +disable ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x" + +# hw/lance.c +disable lance_mem_readw(uint64_t addr, uint32_t ret) "addr=%"PRIx64"val=0x%04x" +disable lance_mem_writew(uint64_t addr, uint32_t val) "addr=%"PRIx64"val=0x%04x" + +# hw/slavio_intctl.c +disable slavio_intctl_mem_readl(uint32_t cpu, uint64_t addr, uint32_t ret) "read cpu %d reg 0x%"PRIx64" = %x" +disable slavio_intctl_mem_writel(uint32_t cpu, uint64_t addr, uint32_t val) "write cpu %d reg 0x%"PRIx64" = %x" +disable slavio_intctl_mem_writel_clear(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Cleared cpu %d irq mask %x, curmask %x" +disable slavio_intctl_mem_writel_set(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Set cpu %d irq mask %x, curmask %x" +disable slavio_intctlm_mem_readl(uint64_t addr, uint32_t ret) "read system reg 0x%"PRIx64" = %x" +disable slavio_intctlm_mem_writel(uint64_t addr, uint32_t val) "write system reg 0x%"PRIx64" = %x" +disable slavio_intctlm_mem_writel_enable(uint32_t val, uint32_t intregm_disabled) "Enabled master irq mask %x, curmask %x" +disable slavio_intctlm_mem_writel_disable(uint32_t val, uint32_t intregm_disabled) "Disabled master irq mask %x, curmask %x" +disable slavio_intctlm_mem_writel_target(uint32_t cpu) "Set master irq cpu %d" +disable slavio_check_interrupts(uint32_t pending, uint32_t intregm_disabled) "pending %x disabled %x" +disable slavio_set_irq(uint32_t target_cpu, int irq, uint32_t pil, int level) "Set cpu %d irq %d -> pil %d level %d" +disable slavio_set_timer_irq_cpu(int cpu, int level) "Set cpu %d local timer level %d" + +# hw/slavio_misc.c +disable slavio_misc_update_irq_raise(void) "Raise IRQ" +disable slavio_misc_update_irq_lower(void) "Lower IRQ" +disable slavio_set_power_fail(int power_failing, uint8_t config) "Power fail: %d, config: %d" +disable slavio_cfg_mem_writeb(uint32_t val) "Write config %02x" +disable slavio_cfg_mem_readb(uint32_t ret) "Read config %02x" +disable slavio_diag_mem_writeb(uint32_t val) "Write diag %02x" +disable slavio_diag_mem_readb(uint32_t ret) "Read diag %02x" +disable slavio_mdm_mem_writeb(uint32_t val) "Write modem control %02x" +disable slavio_mdm_mem_readb(uint32_t ret) "Read modem control %02x" +disable slavio_aux1_mem_writeb(uint32_t val) "Write aux1 %02x" +disable slavio_aux1_mem_readb(uint32_t ret) "Read aux1 %02x" +disable slavio_aux2_mem_writeb(uint32_t val) "Write aux2 %02x" +disable slavio_aux2_mem_readb(uint32_t ret) "Read aux2 %02x" +disable apc_mem_writeb(uint32_t val) "Write power management %02x" +disable apc_mem_readb(uint32_t ret) "Read power management %02x" +disable slavio_sysctrl_mem_writel(uint32_t val) "Write system control %08x" +disable slavio_sysctrl_mem_readl(uint32_t ret) "Read system control %08x" +disable slavio_led_mem_writew(uint32_t val) "Write diagnostic LED %04x" +disable slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED %04x" + +# hw/slavio_timer.c +disable slavio_timer_get_out(uint64_t limit, uint32_t counthigh, uint32_t count) "limit %"PRIx64" count %x%08x" +disable slavio_timer_irq(uint32_t counthigh, uint32_t count) "callback: count %x%08x" +disable slavio_timer_mem_readl_invalid(uint64_t addr) "invalid read address %"PRIx64"" +disable slavio_timer_mem_readl(uint64_t addr, uint32_t ret) "read %"PRIx64" = %08x" +disable slavio_timer_mem_writel(uint64_t addr, uint32_t val) "write %"PRIx64" = %08x" +disable slavio_timer_mem_writel_limit(unsigned int timer_index, uint64_t count) "processor %d user timer set to %016"PRIx64"" +disable slavio_timer_mem_writel_counter_invalid(void) "not user timer" +disable slavio_timer_mem_writel_status_start(unsigned int timer_index) "processor %d user timer started" +disable slavio_timer_mem_writel_status_stop(unsigned int timer_index) "processor %d user timer stopped" +disable slavio_timer_mem_writel_mode_user(unsigned int timer_index) "processor %d changed from counter to user timer" +disable slavio_timer_mem_writel_mode_counter(unsigned int timer_index) "processor %d changed from user timer to counter" +disable slavio_timer_mem_writel_mode_invalid(void) "not system timer" +disable slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64"" + +# hw/sparc32_dma.c +disable ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64"" +disable ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64"" +disable sparc32_dma_set_irq_raise(void) "Raise IRQ" +disable sparc32_dma_set_irq_lower(void) "Lower IRQ" +disable espdma_memory_read(uint32_t addr) "DMA read addr 0x%08x" +disable espdma_memory_write(uint32_t addr) "DMA write addr 0x%08x" +disable sparc32_dma_mem_readl(uint64_t addr, uint32_t ret) "read dmareg %"PRIx64": 0x%08x" +disable sparc32_dma_mem_writel(uint64_t addr, uint32_t old, uint32_t val) "write dmareg %"PRIx64": 0x%08x -> 0x%08x" +disable sparc32_dma_enable_raise(void) "Raise DMA enable" +disable sparc32_dma_enable_lower(void) "Lower DMA enable" + +# hw/sun4m.c +disable sun4m_cpu_interrupt(unsigned int level) "Set CPU IRQ %d" +disable sun4m_cpu_reset_interrupt(unsigned int level) "Reset CPU IRQ %d" +disable sun4m_cpu_set_irq_raise(int level) "Raise CPU IRQ %d" +disable sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d" + +# hw/sun4m_iommu.c +disable sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[%"PRIx64"] = %x" +disable sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[%"PRIx64"] = %x" +disable sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = %"PRIx64"" +disable sun4m_iommu_mem_writel_tlbflush(uint32_t val) "tlb flush %x" +disable sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush %x" +disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr %"PRIx64" => pte %"PRIx64", *pte = %x" +disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x" +disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64"" |