mirror of https://github.com/xemu-project/xemu.git
Merge branch 'master' of git://git.qemu.org/qemu
This commit is contained in:
commit
670acc9bf2
45
Makefile
45
Makefile
|
@ -106,6 +106,8 @@ audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
|
|||
|
||||
QEMU_CFLAGS+=$(CURL_CFLAGS)
|
||||
|
||||
QEMU_CFLAGS+=$(GLIB_CFLAGS)
|
||||
|
||||
ui/cocoa.o: ui/cocoa.m
|
||||
|
||||
ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
|
||||
|
@ -138,7 +140,7 @@ endif
|
|||
######################################################################
|
||||
|
||||
qemu-img.o: qemu-img-cmds.h
|
||||
qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o: $(GENERATED_HEADERS)
|
||||
qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o qemu-ga.o: $(GENERATED_HEADERS)
|
||||
|
||||
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
|
||||
|
||||
|
@ -160,19 +162,54 @@ check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
|
|||
check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
|
||||
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 error.o qerror.o qemu-error.o $(CHECK_PROG_DEPS)
|
||||
|
||||
$(qapi-obj-y): $(GENERATED_HEADERS)
|
||||
qapi-dir := qapi-generated
|
||||
test-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
|
||||
|
||||
$(qapi-dir)/test-qapi-types.c: $(qapi-dir)/test-qapi-types.h
|
||||
$(qapi-dir)/test-qapi-types.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
|
||||
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
|
||||
$(qapi-dir)/test-qapi-visit.c: $(qapi-dir)/test-qapi-visit.h
|
||||
$(qapi-dir)/test-qapi-visit.h: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
|
||||
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
|
||||
$(qapi-dir)/test-qmp-commands.h: $(qapi-dir)/test-qmp-marshal.c
|
||||
$(qapi-dir)/test-qmp-marshal.c: $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
|
||||
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@")
|
||||
|
||||
$(qapi-dir)/qga-qapi-types.c: $(qapi-dir)/qga-qapi-types.h
|
||||
$(qapi-dir)/qga-qapi-types.h: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
|
||||
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@")
|
||||
$(qapi-dir)/qga-qapi-visit.c: $(qapi-dir)/qga-qapi-visit.h
|
||||
$(qapi-dir)/qga-qapi-visit.h: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
|
||||
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@")
|
||||
$(qapi-dir)/qga-qmp-marshal.c: $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
|
||||
$(call quiet-command,python $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@")
|
||||
|
||||
test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
|
||||
test-visitor: test-visitor.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
|
||||
|
||||
test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h) $(qapi-obj-y)
|
||||
test-qmp-commands: test-qmp-commands.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
|
||||
|
||||
QGALIB=qga/guest-agent-command-state.o qga/guest-agent-commands.o
|
||||
|
||||
qemu-ga.o: $(addprefix $(qapi-dir)/, qga-qapi-types.c qga-qapi-types.h qga-qapi-visit.c qga-qmp-marshal.c) $(qapi-obj-y)
|
||||
qemu-ga$(EXESUF): qemu-ga.o $(QGALIB) qemu-tool.o qemu-error.o error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) $(qapi-obj-y) qemu-timer-common.o qemu-sockets.o module.o qapi/qmp-dispatch.o qapi/qmp-registry.o $(qapi-dir)/qga-qapi-visit.o $(qapi-dir)/qga-qapi-types.o $(qapi-dir)/qga-qmp-marshal.o
|
||||
|
||||
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
|
||||
|
||||
clean:
|
||||
# avoid old build problems by removing potentially incorrect old files
|
||||
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
rm -f qemu-options.def
|
||||
rm -f *.o *.d *.a *.lo $(TOOLS) TAGS cscope.* *.pod *~ */*~
|
||||
rm -f *.o *.d *.a *.lo $(TOOLS) qemu-ga TAGS cscope.* *.pod *~ */*~
|
||||
rm -Rf .libs
|
||||
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d
|
||||
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d qga/*.o qga/*.d
|
||||
rm -f qemu-img-cmds.h
|
||||
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
|
||||
rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
|
||||
rm -f trace-dtrace.h trace-dtrace.h-timestamp
|
||||
rm -rf $(qapi-dir)
|
||||
$(MAKE) -C tests clean
|
||||
for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
|
||||
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
|
||||
|
@ -361,4 +398,4 @@ tarbin:
|
|||
$(mandir)/man8/qemu-nbd.8
|
||||
|
||||
# Include automatically generated dependency files
|
||||
-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d)
|
||||
-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d ui/*.d qapi/*.d qga/*.d)
|
||||
|
|
|
@ -155,8 +155,8 @@ slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o
|
|||
common-obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y))
|
||||
|
||||
# xen backend driver support
|
||||
common-obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o
|
||||
common-obj-$(CONFIG_XEN) += xen_console.o xenfb.o xen_disk.o xen_nic.o
|
||||
common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
|
||||
common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o xenfb.o xen_disk.o xen_nic.o
|
||||
|
||||
######################################################################
|
||||
# libuser
|
||||
|
@ -171,7 +171,7 @@ user-obj-y += cutils.o cache-utils.o
|
|||
|
||||
hw-obj-y =
|
||||
hw-obj-y += vl.o loader.o
|
||||
hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o
|
||||
hw-obj-$(CONFIG_VIRTIO) += virtio-console.o
|
||||
hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
|
||||
hw-obj-y += fw_cfg.o
|
||||
hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
|
||||
|
@ -205,6 +205,7 @@ hw-obj-$(CONFIG_HPET) += hpet.o
|
|||
hw-obj-$(CONFIG_APPLESMC) += applesmc.o
|
||||
hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o
|
||||
hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
|
||||
hw-obj-$(CONFIG_USB_REDIR) += usb-redir.o
|
||||
|
||||
# PPC devices
|
||||
hw-obj-$(CONFIG_OPENPIC) += openpic.o
|
||||
|
@ -372,7 +373,15 @@ endif
|
|||
|
||||
libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
|
||||
|
||||
######################################################################
|
||||
# qapi
|
||||
|
||||
qapi-nested-y = qapi-visit-core.o qmp-input-visitor.o qmp-output-visitor.o qapi-dealloc-visitor.o
|
||||
qapi-nested-y += qmp-registry.o qmp-dispatch.o
|
||||
qapi-obj-y = $(addprefix qapi/, $(qapi-nested-y))
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
|
||||
|
||||
vl.o: QEMU_CFLAGS+=$(GLIB_CFLAGS)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
GENERATED_HEADERS = config-target.h
|
||||
CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)
|
||||
CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
|
||||
CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
|
||||
|
||||
include ../config-host.mak
|
||||
include config-devices.mak
|
||||
|
@ -94,7 +95,7 @@ tcg/tcg.o: cpu.h
|
|||
|
||||
# HELPER_CFLAGS is used for all the code compiled with static register
|
||||
# variables
|
||||
%_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
|
||||
op_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
|
||||
|
||||
# Note: this is a workaround. The real fix is to avoid compiling
|
||||
# cpu_signal_handler() in user-exec.c.
|
||||
|
@ -190,7 +191,7 @@ obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
|
|||
# virtio has to be here due to weird dependency between PCI and virtio-net.
|
||||
# need to fix this properly
|
||||
obj-$(CONFIG_NO_PCI) += pci-stub.o
|
||||
obj-$(CONFIG_VIRTIO) += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
|
||||
obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
|
||||
obj-y += vhost_net.o
|
||||
obj-$(CONFIG_VHOST_NET) += vhost.o
|
||||
obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
|
||||
|
@ -203,21 +204,11 @@ QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
|
|||
QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
|
||||
QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
|
||||
QEMU_CFLAGS += $(VNC_PNG_CFLAGS)
|
||||
QEMU_CFLAGS += $(GLIB_CFLAGS)
|
||||
|
||||
# xen backend driver support
|
||||
obj-i386-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
|
||||
|
||||
ifeq ($(TARGET_BASE_ARCH), i386)
|
||||
CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
|
||||
else
|
||||
CONFIG_NO_XEN = y
|
||||
endif
|
||||
# xen support
|
||||
CONFIG_NO_XEN_MAPCACHE = $(if $(subst n,,$(CONFIG_XEN_MAPCACHE)),n,y)
|
||||
obj-i386-$(CONFIG_XEN) += xen-all.o
|
||||
obj-$(CONFIG_XEN) += xen-all.o xen_machine_pv.o xen_domainbuild.o xen-mapcache.o
|
||||
obj-$(CONFIG_NO_XEN) += xen-stub.o
|
||||
obj-i386-$(CONFIG_XEN_MAPCACHE) += xen-mapcache.o
|
||||
obj-$(CONFIG_NO_XEN_MAPCACHE) += xen-mapcache-stub.o
|
||||
|
||||
obj-i386-$(CONFIG_XEN) += xen_platform.o
|
||||
|
||||
|
@ -260,7 +251,7 @@ endif
|
|||
obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
|
||||
obj-ppc-y += ppc440.o ppc440_bamboo.o
|
||||
# PowerPC E500 boards
|
||||
obj-ppc-y += ppce500_mpc8544ds.o
|
||||
obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o
|
||||
# PowerPC 440 Xilinx ML507 reference board.
|
||||
obj-ppc-y += virtex_ml507.o
|
||||
obj-ppc-$(CONFIG_KVM) += kvm_ppc.o
|
||||
|
|
129
arm-semi.c
129
arm-semi.c
|
@ -34,6 +34,7 @@
|
|||
#else
|
||||
#include "qemu-common.h"
|
||||
#include "gdbstub.h"
|
||||
#include "hw/arm-misc.h"
|
||||
#endif
|
||||
|
||||
#define SYS_OPEN 0x01
|
||||
|
@ -369,68 +370,88 @@ uint32_t do_arm_semihosting(CPUState *env)
|
|||
return syscall_err;
|
||||
#endif
|
||||
case SYS_GET_CMDLINE:
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* Build a commandline from the original argv. */
|
||||
{
|
||||
char *arm_cmdline_buffer;
|
||||
const char *host_cmdline_buffer;
|
||||
/* Build a command-line from the original argv.
|
||||
*
|
||||
* The inputs are:
|
||||
* * ARG(0), pointer to a buffer of at least the size
|
||||
* specified in ARG(1).
|
||||
* * ARG(1), size of the buffer pointed to by ARG(0) in
|
||||
* bytes.
|
||||
*
|
||||
* The outputs are:
|
||||
* * ARG(0), pointer to null-terminated string of the
|
||||
* command line.
|
||||
* * ARG(1), length of the string pointed to by ARG(0).
|
||||
*/
|
||||
|
||||
char *output_buffer;
|
||||
size_t input_size = ARG(1);
|
||||
size_t output_size;
|
||||
int status = 0;
|
||||
|
||||
/* Compute the size of the output string. */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
output_size = strlen(ts->boot_info->kernel_filename)
|
||||
+ 1 /* Separating space. */
|
||||
+ strlen(ts->boot_info->kernel_cmdline)
|
||||
+ 1; /* Terminating null byte. */
|
||||
#else
|
||||
unsigned int i;
|
||||
unsigned int arm_cmdline_len = ARG(1);
|
||||
unsigned int host_cmdline_len =
|
||||
ts->info->arg_end-ts->info->arg_start;
|
||||
|
||||
if (!arm_cmdline_len || host_cmdline_len > arm_cmdline_len) {
|
||||
return -1; /* not enough space to store command line */
|
||||
}
|
||||
|
||||
if (!host_cmdline_len) {
|
||||
output_size = ts->info->arg_end - ts->info->arg_start;
|
||||
if (!output_size) {
|
||||
/* We special-case the "empty command line" case (argc==0).
|
||||
Just provide the terminating 0. */
|
||||
arm_cmdline_buffer = lock_user(VERIFY_WRITE, ARG(0), 1, 0);
|
||||
arm_cmdline_buffer[0] = 0;
|
||||
unlock_user(arm_cmdline_buffer, ARG(0), 1);
|
||||
|
||||
/* Adjust the commandline length argument. */
|
||||
SET_ARG(1, 0);
|
||||
return 0;
|
||||
output_size = 1;
|
||||
}
|
||||
|
||||
/* lock the buffers on the ARM side */
|
||||
arm_cmdline_buffer =
|
||||
lock_user(VERIFY_WRITE, ARG(0), host_cmdline_len, 0);
|
||||
host_cmdline_buffer =
|
||||
lock_user(VERIFY_READ, ts->info->arg_start,
|
||||
host_cmdline_len, 1);
|
||||
|
||||
if (arm_cmdline_buffer && host_cmdline_buffer)
|
||||
{
|
||||
/* the last argument is zero-terminated;
|
||||
no need for additional termination */
|
||||
memcpy(arm_cmdline_buffer, host_cmdline_buffer,
|
||||
host_cmdline_len);
|
||||
|
||||
/* separate arguments by white spaces */
|
||||
for (i = 0; i < host_cmdline_len-1; i++) {
|
||||
if (arm_cmdline_buffer[i] == 0) {
|
||||
arm_cmdline_buffer[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust the commandline length argument. */
|
||||
SET_ARG(1, host_cmdline_len-1);
|
||||
}
|
||||
|
||||
/* Unlock the buffers on the ARM side. */
|
||||
unlock_user(arm_cmdline_buffer, ARG(0), host_cmdline_len);
|
||||
unlock_user((void*)host_cmdline_buffer, ts->info->arg_start, 0);
|
||||
|
||||
/* Return success if we could return a commandline. */
|
||||
return (arm_cmdline_buffer && host_cmdline_buffer) ? 0 : -1;
|
||||
}
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
if (output_size > input_size) {
|
||||
/* Not enough space to store command-line arguments. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Adjust the command-line length. */
|
||||
SET_ARG(1, output_size - 1);
|
||||
|
||||
/* Lock the buffer on the ARM side. */
|
||||
output_buffer = lock_user(VERIFY_WRITE, ARG(0), output_size, 0);
|
||||
if (!output_buffer) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy the command-line arguments. */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
pstrcpy(output_buffer, output_size, ts->boot_info->kernel_filename);
|
||||
pstrcat(output_buffer, output_size, " ");
|
||||
pstrcat(output_buffer, output_size, ts->boot_info->kernel_cmdline);
|
||||
#else
|
||||
if (output_size == 1) {
|
||||
/* Empty command-line. */
|
||||
output_buffer[0] = '\0';
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (copy_from_user(output_buffer, ts->info->arg_start,
|
||||
output_size)) {
|
||||
status = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Separate arguments by white spaces. */
|
||||
for (i = 0; i < output_size - 1; i++) {
|
||||
if (output_buffer[i] == 0) {
|
||||
output_buffer[i] = ' ';
|
||||
}
|
||||
}
|
||||
out:
|
||||
#endif
|
||||
/* Unlock the buffer on the ARM side. */
|
||||
unlock_user(output_buffer, ARG(0), output_size);
|
||||
|
||||
return status;
|
||||
}
|
||||
case SYS_HEAPINFO:
|
||||
{
|
||||
uint32_t *ptr;
|
||||
|
|
19
block.c
19
block.c
|
@ -1146,6 +1146,25 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Length of a allocated file in bytes. Sparse files are counted by actual
|
||||
* allocated space. Return < 0 if error or unknown.
|
||||
*/
|
||||
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
if (!drv) {
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
if (drv->bdrv_get_allocated_file_size) {
|
||||
return drv->bdrv_get_allocated_file_size(bs);
|
||||
}
|
||||
if (bs->file) {
|
||||
return bdrv_get_allocated_file_size(bs->file);
|
||||
}
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Length of a file in bytes. Return < 0 if error or unknown.
|
||||
*/
|
||||
|
|
1
block.h
1
block.h
|
@ -89,6 +89,7 @@ int bdrv_write_sync(BlockDriverState *bs, int64_t sector_num,
|
|||
const uint8_t *buf, int nb_sectors);
|
||||
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
|
||||
int64_t bdrv_getlength(BlockDriverState *bs);
|
||||
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
|
||||
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
|
||||
void bdrv_guess_geometry(BlockDriverState *bs, int *pcyls, int *pheads, int *psecs);
|
||||
int bdrv_commit(BlockDriverState *bs);
|
||||
|
|
|
@ -312,3 +312,15 @@ found:
|
|||
c->entries[i].dirty = true;
|
||||
}
|
||||
|
||||
bool qcow2_cache_set_writethrough(BlockDriverState *bs, Qcow2Cache *c,
|
||||
bool enable)
|
||||
{
|
||||
bool old = c->writethrough;
|
||||
|
||||
if (!old && enable) {
|
||||
qcow2_cache_flush(bs, c);
|
||||
}
|
||||
|
||||
c->writethrough = enable;
|
||||
return old;
|
||||
}
|
||||
|
|
|
@ -705,8 +705,15 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
|
||||
int64_t old_offset, old_l2_offset;
|
||||
int i, j, l1_modified, nb_csectors, refcount;
|
||||
int i, j, l1_modified = 0, nb_csectors, refcount;
|
||||
int ret;
|
||||
bool old_l2_writethrough, old_refcount_writethrough;
|
||||
|
||||
/* Switch caches to writeback mode during update */
|
||||
old_l2_writethrough =
|
||||
qcow2_cache_set_writethrough(bs, s->l2_table_cache, false);
|
||||
old_refcount_writethrough =
|
||||
qcow2_cache_set_writethrough(bs, s->refcount_block_cache, false);
|
||||
|
||||
l2_table = NULL;
|
||||
l1_table = NULL;
|
||||
|
@ -720,7 +727,11 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||
l1_allocated = 1;
|
||||
if (bdrv_pread(bs->file, l1_table_offset,
|
||||
l1_table, l1_size2) != l1_size2)
|
||||
{
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for(i = 0;i < l1_size; i++)
|
||||
be64_to_cpus(&l1_table[i]);
|
||||
} else {
|
||||
|
@ -729,7 +740,6 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||
l1_allocated = 0;
|
||||
}
|
||||
|
||||
l1_modified = 0;
|
||||
for(i = 0; i < l1_size; i++) {
|
||||
l2_offset = l1_table[i];
|
||||
if (l2_offset) {
|
||||
|
@ -773,6 +783,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||
}
|
||||
|
||||
if (refcount < 0) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
@ -803,6 +814,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||
refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
|
||||
}
|
||||
if (refcount < 0) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
} else if (refcount == 1) {
|
||||
l2_offset |= QCOW_OFLAG_COPIED;
|
||||
|
@ -813,6 +825,18 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
if (l2_table) {
|
||||
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||
}
|
||||
|
||||
/* Enable writethrough cache mode again */
|
||||
qcow2_cache_set_writethrough(bs, s->l2_table_cache, old_l2_writethrough);
|
||||
qcow2_cache_set_writethrough(bs, s->refcount_block_cache,
|
||||
old_refcount_writethrough);
|
||||
|
||||
if (l1_modified) {
|
||||
for(i = 0; i < l1_size; i++)
|
||||
cpu_to_be64s(&l1_table[i]);
|
||||
|
@ -824,15 +848,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||
}
|
||||
if (l1_allocated)
|
||||
qemu_free(l1_table);
|
||||
return 0;
|
||||
fail:
|
||||
if (l2_table) {
|
||||
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||
}
|
||||
|
||||
if (l1_allocated)
|
||||
qemu_free(l1_table);
|
||||
return -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -228,6 +228,8 @@ int qcow2_read_snapshots(BlockDriverState *bs);
|
|||
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
|
||||
bool writethrough);
|
||||
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
|
||||
bool qcow2_cache_set_writethrough(BlockDriverState *bs, Qcow2Cache *c,
|
||||
bool enable);
|
||||
|
||||
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
|
||||
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include <sys/dkio.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <linux/cdrom.h>
|
||||
|
@ -791,6 +793,17 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
|
||||
{
|
||||
struct stat st;
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
if (fstat(s->fd, &st) < 0) {
|
||||
return -errno;
|
||||
}
|
||||
return (int64_t)st.st_blocks * 512;
|
||||
}
|
||||
|
||||
static int raw_create(const char *filename, QEMUOptionParameter *options)
|
||||
{
|
||||
int fd;
|
||||
|
@ -886,6 +899,8 @@ static BlockDriver bdrv_file = {
|
|||
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
.create_options = raw_create_options,
|
||||
};
|
||||
|
@ -1154,6 +1169,8 @@ static BlockDriver bdrv_host_device = {
|
|||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
/* generic scsi device */
|
||||
#ifdef __linux__
|
||||
|
@ -1188,6 +1205,7 @@ static int floppy_probe_device(const char *filename)
|
|||
int fd, ret;
|
||||
int prio = 0;
|
||||
struct floppy_struct fdparam;
|
||||
struct stat st;
|
||||
|
||||
if (strstart(filename, "/dev/fd", NULL))
|
||||
prio = 50;
|
||||
|
@ -1196,12 +1214,17 @@ static int floppy_probe_device(const char *filename)
|
|||
if (fd < 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = fstat(fd, &st);
|
||||
if (ret == -1 || !S_ISBLK(st.st_mode)) {
|
||||
goto outc;
|
||||
}
|
||||
|
||||
/* Attempt to detect via a floppy specific ioctl */
|
||||
ret = ioctl(fd, FDGETPRM, &fdparam);
|
||||
if (ret >= 0)
|
||||
prio = 100;
|
||||
|
||||
outc:
|
||||
close(fd);
|
||||
out:
|
||||
return prio;
|
||||
|
@ -1269,6 +1292,8 @@ static BlockDriver bdrv_host_floppy = {
|
|||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
/* removable device support */
|
||||
.bdrv_is_inserted = floppy_is_inserted,
|
||||
|
@ -1290,17 +1315,23 @@ static int cdrom_probe_device(const char *filename)
|
|||
{
|
||||
int fd, ret;
|
||||
int prio = 0;
|
||||
struct stat st;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = fstat(fd, &st);
|
||||
if (ret == -1 || !S_ISBLK(st.st_mode)) {
|
||||
goto outc;
|
||||
}
|
||||
|
||||
/* Attempt to detect via a CDROM specific ioctl */
|
||||
ret = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
|
||||
if (ret >= 0)
|
||||
prio = 100;
|
||||
|
||||
outc:
|
||||
close(fd);
|
||||
out:
|
||||
return prio;
|
||||
|
@ -1366,6 +1397,8 @@ static BlockDriver bdrv_host_cdrom = {
|
|||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
/* removable device support */
|
||||
.bdrv_is_inserted = cdrom_is_inserted,
|
||||
|
@ -1489,6 +1522,8 @@ static BlockDriver bdrv_host_cdrom = {
|
|||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
/* removable device support */
|
||||
.bdrv_is_inserted = cdrom_is_inserted,
|
||||
|
|
|
@ -213,6 +213,31 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
|||
return l.QuadPart;
|
||||
}
|
||||
|
||||
static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
|
||||
{
|
||||
typedef DWORD (WINAPI * get_compressed_t)(const char *filename,
|
||||
DWORD * high);
|
||||
get_compressed_t get_compressed;
|
||||
struct _stati64 st;
|
||||
const char *filename = bs->filename;
|
||||
/* WinNT support GetCompressedFileSize to determine allocate size */
|
||||
get_compressed =
|
||||
(get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"),
|
||||
"GetCompressedFileSizeA");
|
||||
if (get_compressed) {
|
||||
DWORD high, low;
|
||||
low = get_compressed(filename, &high);
|
||||
if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) {
|
||||
return (((int64_t) high) << 32) + low;
|
||||
}
|
||||
}
|
||||
|
||||
if (_stati64(filename, &st) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
static int raw_create(const char *filename, QEMUOptionParameter *options)
|
||||
{
|
||||
int fd;
|
||||
|
@ -257,6 +282,8 @@ static BlockDriver bdrv_file = {
|
|||
.bdrv_write = raw_write,
|
||||
.bdrv_truncate = raw_truncate,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
|
||||
.create_options = raw_create_options,
|
||||
};
|
||||
|
@ -419,6 +446,8 @@ static BlockDriver bdrv_host_device = {
|
|||
.bdrv_read = raw_read,
|
||||
.bdrv_write = raw_write,
|
||||
.bdrv_getlength = raw_getlength,
|
||||
.bdrv_get_allocated_file_size
|
||||
= raw_get_allocated_file_size,
|
||||
};
|
||||
|
||||
static void bdrv_file_init(void)
|
||||
|
|
|
@ -1286,6 +1286,49 @@ static int do_sd_create(char *filename, int64_t vdi_size,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sd_prealloc(const char *filename)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
uint32_t idx, max_idx;
|
||||
int64_t vdi_size;
|
||||
void *buf = qemu_mallocz(SD_DATA_OBJ_SIZE);
|
||||
int ret;
|
||||
|
||||
ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
vdi_size = bdrv_getlength(bs);
|
||||
if (vdi_size < 0) {
|
||||
ret = vdi_size;
|
||||
goto out;
|
||||
}
|
||||
max_idx = DIV_ROUND_UP(vdi_size, SD_DATA_OBJ_SIZE);
|
||||
|
||||
for (idx = 0; idx < max_idx; idx++) {
|
||||
/*
|
||||
* The created image can be a cloned image, so we need to read
|
||||
* a data from the source image.
|
||||
*/
|
||||
ret = bdrv_pread(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = bdrv_pwrite(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (bs) {
|
||||
bdrv_delete(bs);
|
||||
}
|
||||
qemu_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sd_create(const char *filename, QEMUOptionParameter *options)
|
||||
{
|
||||
int ret;
|
||||
|
@ -1295,13 +1338,15 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
|
|||
BDRVSheepdogState s;
|
||||
char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
|
||||
uint32_t snapid;
|
||||
int prealloc = 0;
|
||||
const char *vdiname;
|
||||
|
||||
strstart(filename, "sheepdog:", (const char **)&filename);
|
||||
strstart(filename, "sheepdog:", &vdiname);
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
memset(vdi, 0, sizeof(vdi));
|
||||
memset(tag, 0, sizeof(tag));
|
||||
if (parse_vdiname(&s, filename, vdi, &snapid, tag) < 0) {
|
||||
if (parse_vdiname(&s, vdiname, vdi, &snapid, tag) < 0) {
|
||||
error_report("invalid filename");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1311,6 +1356,16 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
|
|||
vdi_size = options->value.n;
|
||||
} else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
|
||||
backing_file = options->value.s;
|
||||
} else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
|
||||
if (!options->value.s || !strcmp(options->value.s, "off")) {
|
||||
prealloc = 0;
|
||||
} else if (!strcmp(options->value.s, "full")) {
|
||||
prealloc = 1;
|
||||
} else {
|
||||
error_report("Invalid preallocation mode: '%s'",
|
||||
options->value.s);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
options++;
|
||||
}
|
||||
|
@ -1348,7 +1403,12 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
|
|||
bdrv_delete(bs);
|
||||
}
|
||||
|
||||
return do_sd_create((char *)vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port);
|
||||
ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port);
|
||||
if (!prealloc || ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return sd_prealloc(filename);
|
||||
}
|
||||
|
||||
static void sd_close(BlockDriverState *bs)
|
||||
|
@ -1984,6 +2044,11 @@ static QEMUOptionParameter sd_create_options[] = {
|
|||
.type = OPT_STRING,
|
||||
.help = "File name of a base image"
|
||||
},
|
||||
{
|
||||
.name = BLOCK_OPT_PREALLOC,
|
||||
.type = OPT_STRING,
|
||||
.help = "Preallocation mode (allowed values: off, full)"
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
|
1345
block/vmdk.c
1345
block/vmdk.c
File diff suppressed because it is too large
Load Diff
|
@ -39,6 +39,7 @@
|
|||
#define BLOCK_OPT_CLUSTER_SIZE "cluster_size"
|
||||
#define BLOCK_OPT_TABLE_SIZE "table_size"
|
||||
#define BLOCK_OPT_PREALLOC "preallocation"
|
||||
#define BLOCK_OPT_SUBFMT "subformat"
|
||||
|
||||
typedef struct AIOPool {
|
||||
void (*cancel)(BlockDriverAIOCB *acb);
|
||||
|
@ -85,6 +86,7 @@ struct BlockDriver {
|
|||
const char *protocol_name;
|
||||
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
|
||||
int64_t (*bdrv_getlength)(BlockDriverState *bs);
|
||||
int64_t (*bdrv_get_allocated_file_size)(BlockDriverState *bs);
|
||||
int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
|
||||
|
|
18
blockdev.c
18
blockdev.c
|
@ -240,14 +240,6 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
|
|||
int ret;
|
||||
|
||||
translation = BIOS_ATA_TRANSLATION_AUTO;
|
||||
|
||||
if (default_to_scsi) {
|
||||
type = IF_SCSI;
|
||||
pstrcpy(devname, sizeof(devname), "scsi");
|
||||
} else {
|
||||
type = IF_IDE;
|
||||
pstrcpy(devname, sizeof(devname), "ide");
|
||||
}
|
||||
media = MEDIA_DISK;
|
||||
|
||||
/* extract parameters */
|
||||
|
@ -273,7 +265,11 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
|
|||
error_report("unsupported bus type '%s'", buf);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
type = default_to_scsi ? IF_SCSI : IF_IDE;
|
||||
pstrcpy(devname, sizeof(devname), if_name[type]);
|
||||
}
|
||||
|
||||
max_devs = if_max_devs[type];
|
||||
|
||||
if (cyls || heads || secs) {
|
||||
|
@ -314,7 +310,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
|
|||
media = MEDIA_DISK;
|
||||
} else if (!strcmp(buf, "cdrom")) {
|
||||
if (cyls || secs || heads) {
|
||||
error_report("'%s' invalid physical CHS format", buf);
|
||||
error_report("CHS can't be set with media=%s", buf);
|
||||
return NULL;
|
||||
}
|
||||
media = MEDIA_CDROM;
|
||||
|
@ -572,7 +568,7 @@ void do_commit(Monitor *mon, const QDict *qdict)
|
|||
int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
const char *filename = qdict_get_try_str(qdict, "snapshot_file");
|
||||
const char *filename = qdict_get_try_str(qdict, "snapshot-file");
|
||||
const char *format = qdict_get_try_str(qdict, "format");
|
||||
BlockDriverState *bs;
|
||||
BlockDriver *drv, *old_drv, *proto_drv;
|
||||
|
@ -581,7 +577,7 @@ int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||
char old_filename[1024];
|
||||
|
||||
if (!filename) {
|
||||
qerror_report(QERR_MISSING_PARAMETER, "snapshot_file");
|
||||
qerror_report(QERR_MISSING_PARAMETER, "snapshot-file");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -866,7 +866,7 @@ int main(int argc, char **argv)
|
|||
int mask;
|
||||
const CPULogItem *item;
|
||||
|
||||
mask = cpu_str_to_log_mask(r);
|
||||
mask = cpu_str_to_log_mask(log_mask);
|
||||
if (!mask) {
|
||||
printf("Log items (comma separated):\n");
|
||||
for (item = cpu_log_items; item->mask != 0; item++) {
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/* public domain */
|
||||
|
||||
#ifndef COMPILER_H
|
||||
#define COMPILER_H
|
||||
|
||||
#include "config-host.h"
|
||||
|
||||
#define QEMU_NORETURN __attribute__ ((__noreturn__))
|
||||
#ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT
|
||||
#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
#define QEMU_WARN_UNUSED_RESULT
|
||||
#endif
|
||||
|
||||
#define QEMU_BUILD_BUG_ON(x) \
|
||||
typedef char qemu_build_bug_on__##__LINE__[(x)?-1:1];
|
||||
|
||||
#if defined __GNUC__
|
||||
# if (__GNUC__ < 4) || \
|
||||
defined(__GNUC_MINOR__) && (__GNUC__ == 4) && (__GNUC_MINOR__ < 4)
|
||||
/* gcc versions before 4.4.x don't support gnu_printf, so use printf. */
|
||||
# define GCC_ATTR __attribute__((__unused__, format(printf, 1, 2)))
|
||||
# define GCC_FMT_ATTR(n, m) __attribute__((format(printf, n, m)))
|
||||
# else
|
||||
/* Use gnu_printf when supported (qemu uses standard format strings). */
|
||||
# define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2)))
|
||||
# define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m)))
|
||||
# endif
|
||||
#else
|
||||
#define GCC_ATTR /**/
|
||||
#define GCC_FMT_ATTR(n, m)
|
||||
#endif
|
||||
|
||||
#endif /* COMPILER_H */
|
|
@ -177,6 +177,7 @@ spice=""
|
|||
rbd=""
|
||||
smartcard=""
|
||||
smartcard_nss=""
|
||||
usb_redir=""
|
||||
opengl=""
|
||||
|
||||
# parse CC options first
|
||||
|
@ -743,6 +744,10 @@ for opt do
|
|||
;;
|
||||
--enable-smartcard-nss) smartcard_nss="yes"
|
||||
;;
|
||||
--disable-usb-redir) usb_redir="no"
|
||||
;;
|
||||
--enable-usb-redir) usb_redir="yes"
|
||||
;;
|
||||
*) echo "ERROR: unknown option $opt"; show_help="yes"
|
||||
;;
|
||||
esac
|
||||
|
@ -1018,6 +1023,8 @@ echo " --disable-smartcard disable smartcard support"
|
|||
echo " --enable-smartcard enable smartcard support"
|
||||
echo " --disable-smartcard-nss disable smartcard nss support"
|
||||
echo " --enable-smartcard-nss enable smartcard nss support"
|
||||
echo " --disable-usb-redir disable usb network redirection support"
|
||||
echo " --enable-usb-redir enable usb network redirection support"
|
||||
echo ""
|
||||
echo "NOTE: The object files are built at the place where configure is launched"
|
||||
exit 1
|
||||
|
@ -1802,6 +1809,18 @@ EOF
|
|||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# glib support probe
|
||||
if $pkg_config --modversion gthread-2.0 gio-2.0 > /dev/null 2>&1 ; then
|
||||
glib_cflags=`$pkg_config --cflags gthread-2.0 gio-2.0 2>/dev/null`
|
||||
glib_libs=`$pkg_config --libs gthread-2.0 gio-2.0 2>/dev/null`
|
||||
libs_softmmu="$glib_libs $libs_softmmu"
|
||||
libs_tools="$glib_libs $libs_tools"
|
||||
else
|
||||
echo "glib-2.0 required to compile QEMU"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# pthread probe
|
||||
PTHREADLIBS_LIST="-lpthread -lpthreadGC2"
|
||||
|
@ -2371,6 +2390,22 @@ if test "$smartcard" = "no" ; then
|
|||
smartcard_nss="no"
|
||||
fi
|
||||
|
||||
# check for usbredirparser for usb network redirection support
|
||||
if test "$usb_redir" != "no" ; then
|
||||
if $pkg_config libusbredirparser >/dev/null 2>&1 ; then
|
||||
usb_redir="yes"
|
||||
usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null)
|
||||
usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null)
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags"
|
||||
LIBS="$LIBS $usb_redir_libs"
|
||||
else
|
||||
if test "$usb_redir" = "yes"; then
|
||||
feature_not_found "usb-redir"
|
||||
fi
|
||||
usb_redir="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
|
||||
##########################################
|
||||
|
@ -2520,6 +2555,7 @@ if test "$softmmu" = yes ; then
|
|||
tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
|
||||
if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
|
||||
tools="qemu-nbd\$(EXESUF) $tools"
|
||||
tools="qemu-ga\$(EXESUF) $tools"
|
||||
if [ "$check_utests" = "yes" ]; then
|
||||
tools="check-qint check-qstring check-qdict check-qlist $tools"
|
||||
tools="check-qfloat check-qjson $tools"
|
||||
|
@ -2617,6 +2653,7 @@ echo "spice support $spice"
|
|||
echo "rbd support $rbd"
|
||||
echo "xfsctl support $xfs"
|
||||
echo "nss used $smartcard_nss"
|
||||
echo "usb net redir $usb_redir"
|
||||
echo "OpenGL support $opengl"
|
||||
|
||||
if test $sdl_too_old = "yes"; then
|
||||
|
@ -2849,8 +2886,9 @@ if test "$bluez" = "yes" ; then
|
|||
echo "CONFIG_BLUEZ=y" >> $config_host_mak
|
||||
echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak
|
||||
fi
|
||||
echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
|
||||
if test "$xen" = "yes" ; then
|
||||
echo "CONFIG_XEN=y" >> $config_host_mak
|
||||
echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
|
||||
echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
|
||||
fi
|
||||
if test "$io_thread" = "yes" ; then
|
||||
|
@ -2910,6 +2948,10 @@ if test "$smartcard_nss" = "yes" ; then
|
|||
echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$usb_redir" = "yes" ; then
|
||||
echo "CONFIG_USB_REDIR=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$opengl" = "yes" ; then
|
||||
echo "CONFIG_OPENGL=y" >> $config_host_mak
|
||||
fi
|
||||
|
@ -3473,6 +3515,8 @@ DIRS="tests tests/cris slirp audio block net pc-bios/optionrom"
|
|||
DIRS="$DIRS pc-bios/spapr-rtas"
|
||||
DIRS="$DIRS roms/seabios roms/vgabios"
|
||||
DIRS="$DIRS fsdev ui"
|
||||
DIRS="$DIRS qapi"
|
||||
DIRS="$DIRS qga"
|
||||
FILES="Makefile tests/Makefile"
|
||||
FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
|
||||
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
|
||||
|
|
19
cpu-common.h
19
cpu-common.h
|
@ -65,7 +65,7 @@ void qemu_ram_free_from_ptr(ram_addr_t addr);
|
|||
void qemu_ram_remap(ram_addr_t addr, ram_addr_t length);
|
||||
/* This should only be used for ram local to a device. */
|
||||
void *qemu_get_ram_ptr(ram_addr_t addr);
|
||||
void *qemu_ram_ptr_length(target_phys_addr_t addr, target_phys_addr_t *size);
|
||||
void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size);
|
||||
/* Same but slower, to use for migration, where the order of
|
||||
* RAMBlocks must not change. */
|
||||
void *qemu_safe_ram_ptr(ram_addr_t addr);
|
||||
|
@ -134,15 +134,30 @@ void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
|
|||
void qemu_flush_coalesced_mmio_buffer(void);
|
||||
|
||||
uint32_t ldub_phys(target_phys_addr_t addr);
|
||||
uint32_t lduw_le_phys(target_phys_addr_t addr);
|
||||
uint32_t lduw_be_phys(target_phys_addr_t addr);
|
||||
uint32_t ldl_le_phys(target_phys_addr_t addr);
|
||||
uint32_t ldl_be_phys(target_phys_addr_t addr);
|
||||
uint64_t ldq_le_phys(target_phys_addr_t addr);
|
||||
uint64_t ldq_be_phys(target_phys_addr_t addr);
|
||||
void stb_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stw_le_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stw_be_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stl_le_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stl_be_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stq_le_phys(target_phys_addr_t addr, uint64_t val);
|
||||
void stq_be_phys(target_phys_addr_t addr, uint64_t val);
|
||||
|
||||
#ifdef NEED_CPU_H
|
||||
uint32_t lduw_phys(target_phys_addr_t addr);
|
||||
uint32_t ldl_phys(target_phys_addr_t addr);
|
||||
uint64_t ldq_phys(target_phys_addr_t addr);
|
||||
void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
|
||||
void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val);
|
||||
void stb_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stw_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stl_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stq_phys(target_phys_addr_t addr, uint64_t val);
|
||||
#endif
|
||||
|
||||
void cpu_physical_memory_write_rom(target_phys_addr_t addr,
|
||||
const uint8_t *buf, int len);
|
||||
|
|
|
@ -587,6 +587,10 @@ int cpu_exec(CPUState *env)
|
|||
/* reset soft MMU for next block (it can currently
|
||||
only be set by a memory fault) */
|
||||
} /* for(;;) */
|
||||
} else {
|
||||
/* Reload env after longjmp - the compiler may have smashed all
|
||||
* local variables as longjmp is marked 'noreturn'. */
|
||||
env = cpu_single_env;
|
||||
}
|
||||
} /* for(;;) */
|
||||
|
||||
|
|
12
cpus.c
12
cpus.c
|
@ -396,12 +396,19 @@ static int qemu_signal_init(void)
|
|||
sigaddset(&set, SIGUSR2);
|
||||
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
|
||||
|
||||
/*
|
||||
* SIG_IPI must be blocked in the main thread and must not be caught
|
||||
* by sigwait() in the signal thread. Otherwise, the cpu thread will
|
||||
* not catch it reliably.
|
||||
*/
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIG_IPI);
|
||||
pthread_sigmask(SIG_BLOCK, &set, NULL);
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGIO);
|
||||
sigaddset(&set, SIGALRM);
|
||||
sigaddset(&set, SIG_IPI);
|
||||
sigaddset(&set, SIGBUS);
|
||||
pthread_sigmask(SIG_BLOCK, &set, NULL);
|
||||
#else
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGBUS);
|
||||
|
@ -414,6 +421,7 @@ static int qemu_signal_init(void)
|
|||
sigaddset(&set, SIGALRM);
|
||||
}
|
||||
#endif
|
||||
pthread_sigmask(SIG_BLOCK, &set, NULL);
|
||||
|
||||
sigfd = qemu_signalfd(&set);
|
||||
if (sigfd == -1) {
|
||||
|
|
|
@ -819,7 +819,7 @@ int main(int argc, char **argv)
|
|||
int mask;
|
||||
CPULogItem *item;
|
||||
|
||||
mask = cpu_str_to_log_mask(r);
|
||||
mask = cpu_str_to_log_mask(log_mask);
|
||||
if (!mask) {
|
||||
printf("Log items (comma separated):\n");
|
||||
for (item = cpu_log_items; item->mask != 0; item++) {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
###########################################################################
|
||||
#
|
||||
# You can pass this file directly to qemu using the -readconfig
|
||||
# command line switch.
|
||||
#
|
||||
# This config file creates a EHCI adapter with companion UHCI
|
||||
# controllers as multifunction device in PCI slot "1d".
|
||||
#
|
||||
# Specify "bus=ehci.0" when creating usb devices to hook them up
|
||||
# there.
|
||||
#
|
||||
|
||||
[device "ehci"]
|
||||
driver = "ich9-usb-ehci1"
|
||||
addr = "1d.7"
|
||||
multifunction = "on"
|
||||
|
||||
[device "uhci-1"]
|
||||
driver = "ich9-usb-uhci1"
|
||||
addr = "1d.0"
|
||||
multifunction = "on"
|
||||
masterbus = "ehci.0"
|
||||
firstport = "0"
|
||||
|
||||
[device "uhci-2"]
|
||||
driver = "ich9-usb-uhci2"
|
||||
addr = "1d.1"
|
||||
multifunction = "on"
|
||||
masterbus = "ehci.0"
|
||||
firstport = "2"
|
||||
|
||||
[device "uhci-3"]
|
||||
driver = "ich9-usb-uhci3"
|
||||
addr = "1d.2"
|
||||
multifunction = "on"
|
||||
masterbus = "ehci.0"
|
||||
firstport = "4"
|
|
@ -0,0 +1,316 @@
|
|||
= How to use the QAPI code generator =
|
||||
|
||||
* Note: as of this writing, QMP does not use QAPI. Eventually QMP
|
||||
commands will be converted to use QAPI internally. The following
|
||||
information describes QMP/QAPI as it will exist after the
|
||||
conversion.
|
||||
|
||||
QAPI is a native C API within QEMU which provides management-level
|
||||
functionality to internal/external users. For external
|
||||
users/processes, this interface is made available by a JSON-based
|
||||
QEMU Monitor protocol that is provided by the QMP server.
|
||||
|
||||
To map QMP-defined interfaces to the native C QAPI implementations,
|
||||
a JSON-based schema is used to define types and function
|
||||
signatures, and a set of scripts is used to generate types/signatures,
|
||||
and marshaling/dispatch code. The QEMU Guest Agent also uses these
|
||||
scripts, paired with a seperate schema, to generate
|
||||
marshaling/dispatch code for the guest agent server running in the
|
||||
guest.
|
||||
|
||||
This document will describe how the schemas, scripts, and resulting
|
||||
code is used.
|
||||
|
||||
|
||||
== QMP/Guest agent schema ==
|
||||
|
||||
This file defines the types, commands, and events used by QMP. It should
|
||||
fully describe the interface used by QMP.
|
||||
|
||||
This file is designed to be loosely based on JSON although it's technically
|
||||
executable Python. While dictionaries are used, they are parsed as
|
||||
OrderedDicts so that ordering is preserved.
|
||||
|
||||
There are two basic syntaxes used, type definitions and command definitions.
|
||||
|
||||
The first syntax defines a type and is represented by a dictionary. There are
|
||||
two kinds of types that are supported: complex user-defined types, and enums.
|
||||
|
||||
A complex type is a dictionary containing a single key who's value is a
|
||||
dictionary. This corresponds to a struct in C or an Object in JSON. An
|
||||
example of a complex type is:
|
||||
|
||||
{ 'type': 'MyType',
|
||||
'data' { 'member1': 'str', 'member2': 'int', '*member3': 'str } }
|
||||
|
||||
The use of '*' as a prefix to the name means the member is optional. Optional
|
||||
members should always be added to the end of the dictionary to preserve
|
||||
backwards compatibility.
|
||||
|
||||
An enumeration type is a dictionary containing a single key who's value is a
|
||||
list of strings. An example enumeration is:
|
||||
|
||||
{ 'enum': 'MyEnum', 'data': [ 'value1', 'value2', 'value3' ] }
|
||||
|
||||
Generally speaking, complex types and enums should always use CamelCase for
|
||||
the type names.
|
||||
|
||||
Commands are defined by using a list containing three members. The first
|
||||
member is the command name, the second member is a dictionary containing
|
||||
arguments, and the third member is the return type.
|
||||
|
||||
An example command is:
|
||||
|
||||
{ 'command': 'my-command',
|
||||
'data': { 'arg1': 'str', '*arg2': 'str' },
|
||||
'returns': 'str' ]
|
||||
|
||||
Command names should be all lower case with words separated by a hyphen.
|
||||
|
||||
|
||||
== Code generation ==
|
||||
|
||||
Schemas are fed into 3 scripts to generate all the code/files that, paired
|
||||
with the core QAPI libraries, comprise everything required to take JSON
|
||||
commands read in by a QMP/guest agent server, unmarshal the arguments into
|
||||
the underlying C types, call into the corresponding C function, and map the
|
||||
response back to a QMP/guest agent response to be returned to the user.
|
||||
|
||||
As an example, we'll use the following schema, which describes a single
|
||||
complex user-defined type (which will produce a C struct, along with a list
|
||||
node structure that can be used to chain together a list of such types in
|
||||
case we want to accept/return a list of this type with a command), and a
|
||||
command which takes that type as a parameter and returns the same type:
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ cat example-schema.json
|
||||
{ 'type': 'UserDefOne',
|
||||
'data': { 'integer': 'int', 'string': 'str' } }
|
||||
|
||||
{ 'command': 'my-command',
|
||||
'data': {'arg1': 'UserDefOne'},
|
||||
'returns': 'UserDefOne' }
|
||||
mdroth@illuin:~/w/qemu2.git$
|
||||
|
||||
=== scripts/qapi-types.py ===
|
||||
|
||||
Used to generate the C types defined by a schema. The following files are
|
||||
created:
|
||||
|
||||
$(prefix)qapi-types.h - C types corresponding to types defined in
|
||||
the schema you pass in
|
||||
$(prefix)qapi-types.c - Cleanup functions for the above C types
|
||||
|
||||
The $(prefix) is an optional parameter used as a namespace to keep the
|
||||
generated code from one schema/code-generation separated from others so code
|
||||
can be generated/used from multiple schemas without clobbering previously
|
||||
created code.
|
||||
|
||||
Example:
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \
|
||||
--output-dir="qapi-generated" --prefix="example-" < example-schema.json
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c
|
||||
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
#include "qapi/qapi-dealloc-visitor.h"
|
||||
#include "example-qapi-types.h"
|
||||
#include "example-qapi-visit.h"
|
||||
|
||||
void qapi_free_UserDefOne(UserDefOne * obj)
|
||||
{
|
||||
QapiDeallocVisitor *md;
|
||||
Visitor *v;
|
||||
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
md = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOne(v, &obj, NULL, NULL);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
}
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h
|
||||
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
|
||||
#define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
|
||||
|
||||
#include "qapi/qapi-types-core.h"
|
||||
|
||||
typedef struct UserDefOne UserDefOne;
|
||||
|
||||
typedef struct UserDefOneList
|
||||
{
|
||||
UserDefOne *value;
|
||||
struct UserDefOneList *next;
|
||||
} UserDefOneList;
|
||||
|
||||
struct UserDefOne
|
||||
{
|
||||
int64_t integer;
|
||||
char * string;
|
||||
};
|
||||
|
||||
void qapi_free_UserDefOne(UserDefOne * obj);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
=== scripts/qapi-visit.py ===
|
||||
|
||||
Used to generate the visitor functions used to walk through and convert
|
||||
a QObject (as provided by QMP) to a native C data structure and
|
||||
vice-versa, as well as the visitor function used to dealloc a complex
|
||||
schema-defined C type.
|
||||
|
||||
The following files are generated:
|
||||
|
||||
$(prefix)qapi-visit.c: visitor function for a particular C type, used
|
||||
to automagically convert QObjects into the
|
||||
corresponding C type and vice-versa, as well
|
||||
as for deallocating memory for an existing C
|
||||
type
|
||||
|
||||
$(prefix)qapi-visit.h: declarations for previously mentioned visitor
|
||||
functions
|
||||
|
||||
Example:
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \
|
||||
--output-dir="qapi-generated" --prefix="example-" < example-schema.json
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
#include "example-qapi-visit.h"
|
||||
|
||||
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
|
||||
{
|
||||
visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp);
|
||||
visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp);
|
||||
visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp);
|
||||
visit_end_struct(m, errp);
|
||||
}
|
||||
|
||||
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
|
||||
{
|
||||
GenericList *i;
|
||||
|
||||
visit_start_list(m, name, errp);
|
||||
|
||||
for (i = visit_next_list(m, (GenericList **)obj, errp); i; i = visit_next_list(m, &i, errp)) {
|
||||
UserDefOneList *native_i = (UserDefOneList *)i;
|
||||
visit_type_UserDefOne(m, &native_i->value, NULL, errp);
|
||||
}
|
||||
|
||||
visit_end_list(m, errp);
|
||||
}
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT
|
||||
#define QAPI_GENERATED_EXAMPLE_QAPI_VISIT
|
||||
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "example-qapi-types.h"
|
||||
|
||||
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
|
||||
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
|
||||
|
||||
#endif
|
||||
mdroth@illuin:~/w/qemu2.git$
|
||||
|
||||
|
||||
=== scripts/qapi-commands.py ===
|
||||
|
||||
Used to generate the marshaling/dispatch functions for the commands defined
|
||||
in the schema. The following files are generated:
|
||||
|
||||
$(prefix)qmp-marshal.c: command marshal/dispatch functions for each
|
||||
QMP command defined in the schema. Functions
|
||||
generated by qapi-visit.py are used to
|
||||
convert QObjects recieved from the wire into
|
||||
function parameters, and uses the same
|
||||
visitor functions to convert native C return
|
||||
values to QObjects from transmission back
|
||||
over the wire.
|
||||
|
||||
$(prefix)qmp-commands.h: Function prototypes for the QMP commands
|
||||
specified in the schema.
|
||||
|
||||
Example:
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
#include "qemu-objects.h"
|
||||
#include "qapi/qmp-core.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "qapi/qmp-input-visitor.h"
|
||||
#include "qapi/qapi-dealloc-visitor.h"
|
||||
#include "example-qapi-types.h"
|
||||
#include "example-qapi-visit.h"
|
||||
|
||||
#include "example-qmp-commands.h"
|
||||
static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
|
||||
{
|
||||
QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
|
||||
QmpOutputVisitor *mo = qmp_output_visitor_new();
|
||||
Visitor *v;
|
||||
|
||||
v = qmp_output_get_visitor(mo);
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", errp);
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", errp);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
|
||||
|
||||
*ret_out = qmp_output_get_qobject(mo);
|
||||
}
|
||||
|
||||
static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp)
|
||||
{
|
||||
UserDefOne * retval = NULL;
|
||||
QmpInputVisitor *mi;
|
||||
QapiDeallocVisitor *md;
|
||||
Visitor *v;
|
||||
UserDefOne * arg1 = NULL;
|
||||
|
||||
mi = qmp_input_visitor_new(QOBJECT(args));
|
||||
v = qmp_input_get_visitor(mi);
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", errp);
|
||||
|
||||
if (error_is_set(errp)) {
|
||||
goto out;
|
||||
}
|
||||
retval = qmp_my_command(arg1, errp);
|
||||
qmp_marshal_output_my_command(retval, ret, errp);
|
||||
|
||||
out:
|
||||
md = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", errp);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
return;
|
||||
}
|
||||
|
||||
static void qmp_init_marshal(void)
|
||||
{
|
||||
qmp_register_command("my-command", qmp_marshal_input_my_command);
|
||||
}
|
||||
|
||||
qapi_init(qmp_init_marshal);
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
#ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
|
||||
#define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
|
||||
|
||||
#include "example-qapi-types.h"
|
||||
#include "error.h"
|
||||
|
||||
UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
|
||||
|
||||
#endif
|
||||
mdroth@illuin:~/w/qemu2.git$
|
|
@ -2,11 +2,13 @@
|
|||
USB 2.0 Quick Start
|
||||
===================
|
||||
|
||||
The QEMU EHCI Adapter does *not* support companion controllers. That
|
||||
implies there are two completely separate USB busses: One USB 1.1 bus
|
||||
driven by the UHCI controller and one USB 2.0 bus driven by the EHCI
|
||||
controller. Devices must be attached to the correct controller
|
||||
manually.
|
||||
The QEMU EHCI Adapter can be used with and without companion
|
||||
controllers. See below for the companion controller mode.
|
||||
|
||||
When not running in companion controller mode there are two completely
|
||||
separate USB busses: One USB 1.1 bus driven by the UHCI controller and
|
||||
one USB 2.0 bus driven by the EHCI controller. Devices must be
|
||||
attached to the correct controller manually.
|
||||
|
||||
The '-usb' switch will make qemu create the UHCI controller as part of
|
||||
the PIIX3 chipset. The USB 1.1 bus will carry the name "usb.0".
|
||||
|
@ -32,6 +34,27 @@ This attaches a usb tablet to the UHCI adapter and a usb mass storage
|
|||
device to the EHCI adapter.
|
||||
|
||||
|
||||
Companion controller support
|
||||
----------------------------
|
||||
|
||||
Companion controller support has been added recently. The operational
|
||||
model described above with two completely separate busses still works
|
||||
fine. Additionally the UHCI and OHCI controllers got the ability to
|
||||
attach to a usb bus created by EHCI as companion controllers. This is
|
||||
done by specifying the masterbus and firstport properties. masterbus
|
||||
specifies the bus name the controller should attach to. firstport
|
||||
specifies the first port the controller should attach to, which is
|
||||
needed as usually one ehci controller with six ports has three uhci
|
||||
companion controllers with two ports each.
|
||||
|
||||
There is a config file in docs which will do all this for you, just
|
||||
try ...
|
||||
|
||||
qemu -readconfig docs/ich9-ehci-uhci.cfg
|
||||
|
||||
... then use "bus=ehci.0" to assign your usb devices to that bus.
|
||||
|
||||
|
||||
More USB tips & tricks
|
||||
======================
|
||||
|
||||
|
|
1
error.h
1
error.h
|
@ -12,6 +12,7 @@
|
|||
#ifndef ERROR_H
|
||||
#define ERROR_H
|
||||
|
||||
#include "compiler.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,11 +44,7 @@ struct TranslationBlock;
|
|||
typedef struct TranslationBlock TranslationBlock;
|
||||
|
||||
/* XXX: make safe guess about sizes */
|
||||
#if (HOST_LONG_BITS == 32) && (TARGET_LONG_BITS == 64)
|
||||
#define MAX_OP_PER_INSTR 128
|
||||
#else
|
||||
#define MAX_OP_PER_INSTR 96
|
||||
#endif
|
||||
#define MAX_OP_PER_INSTR 208
|
||||
|
||||
#if HOST_LONG_BITS == 32
|
||||
#define MAX_OPC_PARAM_PER_ARG 2
|
||||
|
@ -327,7 +323,7 @@ static inline tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong add
|
|||
pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK;
|
||||
if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
|
||||
#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SPARC)
|
||||
do_unassigned_access(addr, 0, 1, 0, 4);
|
||||
cpu_unassigned_access(env1, addr, 0, 1, 0, 4);
|
||||
#else
|
||||
cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
|
||||
#endif
|
||||
|
|
272
exec.c
272
exec.c
|
@ -555,8 +555,8 @@ static void code_gen_alloc(unsigned long tb_size)
|
|||
#endif
|
||||
#endif /* !USE_STATIC_CODE_GEN_BUFFER */
|
||||
map_exec(code_gen_prologue, sizeof(code_gen_prologue));
|
||||
code_gen_buffer_max_size = code_gen_buffer_size -
|
||||
(TCG_MAX_OP_SIZE * OPC_MAX_SIZE);
|
||||
code_gen_buffer_max_size = code_gen_buffer_size -
|
||||
(TCG_MAX_OP_SIZE * OPC_BUF_SIZE);
|
||||
code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
|
||||
tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
|
||||
}
|
||||
|
@ -2953,7 +2953,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
|
|||
abort();
|
||||
}
|
||||
#else
|
||||
if (xen_mapcache_enabled()) {
|
||||
if (xen_enabled()) {
|
||||
xen_ram_alloc(new_block->offset, size);
|
||||
} else {
|
||||
new_block->host = qemu_vmalloc(size);
|
||||
|
@ -3019,8 +3019,8 @@ void qemu_ram_free(ram_addr_t addr)
|
|||
#if defined(TARGET_S390X) && defined(CONFIG_KVM)
|
||||
munmap(block->host, block->length);
|
||||
#else
|
||||
if (xen_mapcache_enabled()) {
|
||||
qemu_invalidate_entry(block->host);
|
||||
if (xen_enabled()) {
|
||||
xen_invalidate_map_cache_entry(block->host);
|
||||
} else {
|
||||
qemu_vfree(block->host);
|
||||
}
|
||||
|
@ -3112,15 +3112,16 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
|
|||
QLIST_REMOVE(block, next);
|
||||
QLIST_INSERT_HEAD(&ram_list.blocks, block, next);
|
||||
}
|
||||
if (xen_mapcache_enabled()) {
|
||||
if (xen_enabled()) {
|
||||
/* We need to check if the requested address is in the RAM
|
||||
* because we don't want to map the entire memory in QEMU.
|
||||
* In that case just map until the end of the page.
|
||||
*/
|
||||
if (block->offset == 0) {
|
||||
return qemu_map_cache(addr, 0, 0);
|
||||
return xen_map_cache(addr, 0, 0);
|
||||
} else if (block->host == NULL) {
|
||||
block->host = qemu_map_cache(block->offset, block->length, 1);
|
||||
block->host =
|
||||
xen_map_cache(block->offset, block->length, 1);
|
||||
}
|
||||
}
|
||||
return block->host + (addr - block->offset);
|
||||
|
@ -3142,15 +3143,16 @@ void *qemu_safe_ram_ptr(ram_addr_t addr)
|
|||
|
||||
QLIST_FOREACH(block, &ram_list.blocks, next) {
|
||||
if (addr - block->offset < block->length) {
|
||||
if (xen_mapcache_enabled()) {
|
||||
if (xen_enabled()) {
|
||||
/* We need to check if the requested address is in the RAM
|
||||
* because we don't want to map the entire memory in QEMU.
|
||||
* In that case just map until the end of the page.
|
||||
*/
|
||||
if (block->offset == 0) {
|
||||
return qemu_map_cache(addr, 0, 0);
|
||||
return xen_map_cache(addr, 0, 0);
|
||||
} else if (block->host == NULL) {
|
||||
block->host = qemu_map_cache(block->offset, block->length, 1);
|
||||
block->host =
|
||||
xen_map_cache(block->offset, block->length, 1);
|
||||
}
|
||||
}
|
||||
return block->host + (addr - block->offset);
|
||||
|
@ -3165,11 +3167,14 @@ void *qemu_safe_ram_ptr(ram_addr_t addr)
|
|||
|
||||
/* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr
|
||||
* but takes a size argument */
|
||||
void *qemu_ram_ptr_length(target_phys_addr_t addr, target_phys_addr_t *size)
|
||||
void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size)
|
||||
{
|
||||
if (xen_mapcache_enabled())
|
||||
return qemu_map_cache(addr, *size, 1);
|
||||
else {
|
||||
if (*size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (xen_enabled()) {
|
||||
return xen_map_cache(addr, *size, 1);
|
||||
} else {
|
||||
RAMBlock *block;
|
||||
|
||||
QLIST_FOREACH(block, &ram_list.blocks, next) {
|
||||
|
@ -3182,9 +3187,6 @@ void *qemu_ram_ptr_length(target_phys_addr_t addr, target_phys_addr_t *size)
|
|||
|
||||
fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
|
||||
abort();
|
||||
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3198,8 +3200,8 @@ int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
|
|||
RAMBlock *block;
|
||||
uint8_t *host = ptr;
|
||||
|
||||
if (xen_mapcache_enabled()) {
|
||||
*ram_addr = qemu_ram_addr_from_mapcache(ptr);
|
||||
if (xen_enabled()) {
|
||||
*ram_addr = xen_ram_addr_from_mapcache(ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3236,7 +3238,7 @@ static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
|
|||
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
|
||||
#endif
|
||||
#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
|
||||
do_unassigned_access(addr, 0, 0, 0, 1);
|
||||
cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -3247,7 +3249,7 @@ static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
|
|||
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
|
||||
#endif
|
||||
#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
|
||||
do_unassigned_access(addr, 0, 0, 0, 2);
|
||||
cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 2);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -3258,7 +3260,7 @@ static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
|
|||
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
|
||||
#endif
|
||||
#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
|
||||
do_unassigned_access(addr, 0, 0, 0, 4);
|
||||
cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 4);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -3269,7 +3271,7 @@ static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_
|
|||
printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
|
||||
#endif
|
||||
#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
|
||||
do_unassigned_access(addr, 1, 0, 0, 1);
|
||||
cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -3279,7 +3281,7 @@ static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_
|
|||
printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
|
||||
#endif
|
||||
#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
|
||||
do_unassigned_access(addr, 1, 0, 0, 2);
|
||||
cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -3289,7 +3291,7 @@ static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_
|
|||
printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
|
||||
#endif
|
||||
#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
|
||||
do_unassigned_access(addr, 1, 0, 0, 4);
|
||||
cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -4050,7 +4052,9 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
|
|||
target_phys_addr_t page;
|
||||
unsigned long pd;
|
||||
PhysPageDesc *p;
|
||||
target_phys_addr_t addr1 = addr;
|
||||
ram_addr_t raddr = ULONG_MAX;
|
||||
ram_addr_t rlen;
|
||||
void *ret;
|
||||
|
||||
while (len > 0) {
|
||||
page = addr & TARGET_PAGE_MASK;
|
||||
|
@ -4078,13 +4082,18 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
|
|||
*plen = l;
|
||||
return bounce.buffer;
|
||||
}
|
||||
if (!todo) {
|
||||
raddr = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
|
||||
}
|
||||
|
||||
len -= l;
|
||||
addr += l;
|
||||
todo += l;
|
||||
}
|
||||
*plen = todo;
|
||||
return qemu_ram_ptr_length(addr1, plen);
|
||||
rlen = todo;
|
||||
ret = qemu_ram_ptr_length(raddr, &rlen);
|
||||
*plen = rlen;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Unmaps a memory region previously mapped by cpu_physical_memory_map().
|
||||
|
@ -4113,8 +4122,8 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
|
|||
access_len -= l;
|
||||
}
|
||||
}
|
||||
if (xen_mapcache_enabled()) {
|
||||
qemu_invalidate_entry(buffer);
|
||||
if (xen_enabled()) {
|
||||
xen_invalidate_map_cache_entry(buffer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -4127,7 +4136,8 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
|
|||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
uint32_t ldl_phys(target_phys_addr_t addr)
|
||||
static inline uint32_t ldl_phys_internal(target_phys_addr_t addr,
|
||||
enum device_endian endian)
|
||||
{
|
||||
int io_index;
|
||||
uint8_t *ptr;
|
||||
|
@ -4149,17 +4159,52 @@ uint32_t ldl_phys(target_phys_addr_t addr)
|
|||
if (p)
|
||||
addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
|
||||
val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
|
||||
(addr & ~TARGET_PAGE_MASK);
|
||||
val = ldl_p(ptr);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
val = ldl_le_p(ptr);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
val = ldl_be_p(ptr);
|
||||
break;
|
||||
default:
|
||||
val = ldl_p(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t ldl_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return ldl_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t ldl_le_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return ldl_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t ldl_be_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return ldl_phys_internal(addr, DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
uint64_t ldq_phys(target_phys_addr_t addr)
|
||||
static inline uint64_t ldq_phys_internal(target_phys_addr_t addr,
|
||||
enum device_endian endian)
|
||||
{
|
||||
int io_index;
|
||||
uint8_t *ptr;
|
||||
|
@ -4180,6 +4225,9 @@ uint64_t ldq_phys(target_phys_addr_t addr)
|
|||
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
||||
if (p)
|
||||
addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
|
||||
|
||||
/* XXX This is broken when device endian != cpu endian.
|
||||
Fix and add "endian" variable check */
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
|
||||
val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
|
||||
|
@ -4191,11 +4239,36 @@ uint64_t ldq_phys(target_phys_addr_t addr)
|
|||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
|
||||
(addr & ~TARGET_PAGE_MASK);
|
||||
val = ldq_p(ptr);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
val = ldq_le_p(ptr);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
val = ldq_be_p(ptr);
|
||||
break;
|
||||
default:
|
||||
val = ldq_p(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint64_t ldq_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return ldq_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
uint64_t ldq_le_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return ldq_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
uint64_t ldq_be_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return ldq_phys_internal(addr, DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* XXX: optimize */
|
||||
uint32_t ldub_phys(target_phys_addr_t addr)
|
||||
{
|
||||
|
@ -4205,7 +4278,8 @@ uint32_t ldub_phys(target_phys_addr_t addr)
|
|||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
uint32_t lduw_phys(target_phys_addr_t addr)
|
||||
static inline uint32_t lduw_phys_internal(target_phys_addr_t addr,
|
||||
enum device_endian endian)
|
||||
{
|
||||
int io_index;
|
||||
uint8_t *ptr;
|
||||
|
@ -4227,15 +4301,49 @@ uint32_t lduw_phys(target_phys_addr_t addr)
|
|||
if (p)
|
||||
addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
|
||||
val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
|
||||
(addr & ~TARGET_PAGE_MASK);
|
||||
val = lduw_p(ptr);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
val = lduw_le_p(ptr);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
val = lduw_be_p(ptr);
|
||||
break;
|
||||
default:
|
||||
val = lduw_p(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t lduw_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return lduw_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t lduw_le_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return lduw_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t lduw_be_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return lduw_phys_internal(addr, DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned. The ram page is not masked as dirty
|
||||
and the code inside is not invalidated. It is useful if the dirty
|
||||
bits are used to track modified PTEs */
|
||||
|
@ -4308,7 +4416,8 @@ void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
|
|||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
void stl_phys(target_phys_addr_t addr, uint32_t val)
|
||||
static inline void stl_phys_internal(target_phys_addr_t addr, uint32_t val,
|
||||
enum device_endian endian)
|
||||
{
|
||||
int io_index;
|
||||
uint8_t *ptr;
|
||||
|
@ -4326,13 +4435,32 @@ void stl_phys(target_phys_addr_t addr, uint32_t val)
|
|||
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
||||
if (p)
|
||||
addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
#endif
|
||||
io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
|
||||
} else {
|
||||
unsigned long addr1;
|
||||
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
stl_p(ptr, val);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
stl_le_p(ptr, val);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
stl_be_p(ptr, val);
|
||||
break;
|
||||
default:
|
||||
stl_p(ptr, val);
|
||||
break;
|
||||
}
|
||||
if (!cpu_physical_memory_is_dirty(addr1)) {
|
||||
/* invalidate code */
|
||||
tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
|
||||
|
@ -4343,6 +4471,21 @@ void stl_phys(target_phys_addr_t addr, uint32_t val)
|
|||
}
|
||||
}
|
||||
|
||||
void stl_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
stl_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
void stl_le_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
stl_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void stl_be_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
stl_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* XXX: optimize */
|
||||
void stb_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
|
@ -4351,7 +4494,8 @@ void stb_phys(target_phys_addr_t addr, uint32_t val)
|
|||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
void stw_phys(target_phys_addr_t addr, uint32_t val)
|
||||
static inline void stw_phys_internal(target_phys_addr_t addr, uint32_t val,
|
||||
enum device_endian endian)
|
||||
{
|
||||
int io_index;
|
||||
uint8_t *ptr;
|
||||
|
@ -4369,13 +4513,32 @@ void stw_phys(target_phys_addr_t addr, uint32_t val)
|
|||
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
||||
if (p)
|
||||
addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
#endif
|
||||
io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
|
||||
} else {
|
||||
unsigned long addr1;
|
||||
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
stw_p(ptr, val);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
stw_le_p(ptr, val);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
stw_be_p(ptr, val);
|
||||
break;
|
||||
default:
|
||||
stw_p(ptr, val);
|
||||
break;
|
||||
}
|
||||
if (!cpu_physical_memory_is_dirty(addr1)) {
|
||||
/* invalidate code */
|
||||
tb_invalidate_phys_page_range(addr1, addr1 + 2, 0);
|
||||
|
@ -4386,6 +4549,21 @@ void stw_phys(target_phys_addr_t addr, uint32_t val)
|
|||
}
|
||||
}
|
||||
|
||||
void stw_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
stw_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
void stw_le_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
stw_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void stw_be_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
stw_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* XXX: optimize */
|
||||
void stq_phys(target_phys_addr_t addr, uint64_t val)
|
||||
{
|
||||
|
@ -4393,6 +4571,18 @@ void stq_phys(target_phys_addr_t addr, uint64_t val)
|
|||
cpu_physical_memory_write(addr, &val, 8);
|
||||
}
|
||||
|
||||
void stq_le_phys(target_phys_addr_t addr, uint64_t val)
|
||||
{
|
||||
val = cpu_to_le64(val);
|
||||
cpu_physical_memory_write(addr, &val, 8);
|
||||
}
|
||||
|
||||
void stq_be_phys(target_phys_addr_t addr, uint64_t val)
|
||||
{
|
||||
val = cpu_to_be64(val);
|
||||
cpu_physical_memory_write(addr, &val, 8);
|
||||
}
|
||||
|
||||
/* virtual memory access for debug (includes writing to ROM) */
|
||||
int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
|
||||
uint8_t *buf, int len, int is_write)
|
||||
|
|
|
@ -840,7 +840,7 @@ ETEXI
|
|||
|
||||
{
|
||||
.name = "snapshot_blkdev",
|
||||
.args_type = "device:B,snapshot_file:s?,format:s?",
|
||||
.args_type = "device:B,snapshot-file:s?,format:s?",
|
||||
.params = "device [new-image-file] [format]",
|
||||
.help = "initiates a live snapshot\n\t\t\t"
|
||||
"of device. If a new image file is specified, the\n\t\t\t"
|
||||
|
|
|
@ -1771,13 +1771,13 @@ static const char *const add_compl_names[] = { 0, "", ",l", ",tsv" };
|
|||
static void
|
||||
fput_reg (unsigned reg, disassemble_info *info)
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, reg ? reg_names[reg] : "r0");
|
||||
(*info->fprintf_func) (info->stream, "%s", reg ? reg_names[reg] : "r0");
|
||||
}
|
||||
|
||||
static void
|
||||
fput_fp_reg (unsigned reg, disassemble_info *info)
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, reg ? fp_reg_names[reg] : "fr0");
|
||||
(*info->fprintf_func) (info->stream, "%s", reg ? fp_reg_names[reg] : "fr0");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1794,7 +1794,7 @@ fput_fp_reg_r (unsigned reg, disassemble_info *info)
|
|||
static void
|
||||
fput_creg (unsigned reg, disassemble_info *info)
|
||||
{
|
||||
(*info->fprintf_func) (info->stream, control_reg[reg]);
|
||||
(*info->fprintf_func) (info->stream, "%s", control_reg[reg]);
|
||||
}
|
||||
|
||||
/* Print constants with sign. */
|
||||
|
|
|
@ -31,7 +31,7 @@ struct arm_boot_info {
|
|||
target_phys_addr_t smp_priv_base;
|
||||
int nb_cpus;
|
||||
int board_id;
|
||||
int (*atag_board)(struct arm_boot_info *info, void *p);
|
||||
int (*atag_board)(const struct arm_boot_info *info, void *p);
|
||||
/* Used internally by arm_boot.c */
|
||||
int is_linux;
|
||||
target_phys_addr_t initrd_size;
|
||||
|
|
|
@ -49,7 +49,7 @@ static uint32_t smpboot[] = {
|
|||
p += 4; \
|
||||
} while (0)
|
||||
|
||||
static void set_kernel_args(struct arm_boot_info *info,
|
||||
static void set_kernel_args(const struct arm_boot_info *info,
|
||||
int initrd_size, target_phys_addr_t base)
|
||||
{
|
||||
target_phys_addr_t p;
|
||||
|
@ -102,7 +102,7 @@ static void set_kernel_args(struct arm_boot_info *info,
|
|||
WRITE_WORD(p, 0);
|
||||
}
|
||||
|
||||
static void set_kernel_args_old(struct arm_boot_info *info,
|
||||
static void set_kernel_args_old(const struct arm_boot_info *info,
|
||||
int initrd_size, target_phys_addr_t base)
|
||||
{
|
||||
target_phys_addr_t p;
|
||||
|
@ -178,7 +178,7 @@ static void set_kernel_args_old(struct arm_boot_info *info,
|
|||
static void do_cpu_reset(void *opaque)
|
||||
{
|
||||
CPUState *env = opaque;
|
||||
struct arm_boot_info *info = env->boot_info;
|
||||
const struct arm_boot_info *info = env->boot_info;
|
||||
|
||||
cpu_reset(env);
|
||||
if (info) {
|
||||
|
|
162
hw/ds1225y.c
162
hw/ds1225y.c
|
@ -22,31 +22,24 @@
|
|||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "hw.h"
|
||||
#include "mips.h"
|
||||
#include "nvram.h"
|
||||
#include "sysbus.h"
|
||||
#include "trace.h"
|
||||
|
||||
//#define DEBUG_NVRAM
|
||||
|
||||
typedef struct ds1225y_t
|
||||
{
|
||||
typedef struct {
|
||||
DeviceState qdev;
|
||||
uint32_t chip_size;
|
||||
char *filename;
|
||||
QEMUFile *file;
|
||||
uint8_t *contents;
|
||||
uint8_t protection;
|
||||
} ds1225y_t;
|
||||
|
||||
} NvRamState;
|
||||
|
||||
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
ds1225y_t *s = opaque;
|
||||
NvRamState *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
val = s->contents[addr];
|
||||
|
||||
#ifdef DEBUG_NVRAM
|
||||
printf("nvram: read 0x%x at " TARGET_FMT_lx "\n", val, addr);
|
||||
#endif
|
||||
trace_nvram_read(addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
|
@ -70,13 +63,12 @@ static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
|
|||
|
||||
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
ds1225y_t *s = opaque;
|
||||
NvRamState *s = opaque;
|
||||
|
||||
#ifdef DEBUG_NVRAM
|
||||
printf("nvram: write 0x%x at " TARGET_FMT_lx "\n", val, addr);
|
||||
#endif
|
||||
val &= 0xff;
|
||||
trace_nvram_write(addr, s->contents[addr], val);
|
||||
|
||||
s->contents[addr] = val & 0xff;
|
||||
s->contents[addr] = val;
|
||||
if (s->file) {
|
||||
qemu_fseek(s->file, addr, SEEK_SET);
|
||||
qemu_put_byte(s->file, (int)val);
|
||||
|
@ -98,34 +90,6 @@ static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
|
|||
nvram_writeb(opaque, addr + 3, (val >> 24) & 0xff);
|
||||
}
|
||||
|
||||
static void nvram_writeb_protected (void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
ds1225y_t *s = opaque;
|
||||
|
||||
if (s->protection != 7) {
|
||||
#ifdef DEBUG_NVRAM
|
||||
printf("nvram: prevent write of 0x%x at " TARGET_FMT_lx "\n", val, addr);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
nvram_writeb(opaque, addr, val);
|
||||
}
|
||||
|
||||
static void nvram_writew_protected (void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
nvram_writeb_protected(opaque, addr, val & 0xff);
|
||||
nvram_writeb_protected(opaque, addr + 1, (val >> 8) & 0xff);
|
||||
}
|
||||
|
||||
static void nvram_writel_protected (void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
nvram_writeb_protected(opaque, addr, val & 0xff);
|
||||
nvram_writeb_protected(opaque, addr + 1, (val >> 8) & 0xff);
|
||||
nvram_writeb_protected(opaque, addr + 2, (val >> 16) & 0xff);
|
||||
nvram_writeb_protected(opaque, addr + 3, (val >> 24) & 0xff);
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc * const nvram_read[] = {
|
||||
&nvram_readb,
|
||||
&nvram_readw,
|
||||
|
@ -138,45 +102,83 @@ static CPUWriteMemoryFunc * const nvram_write[] = {
|
|||
&nvram_writel,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc * const nvram_write_protected[] = {
|
||||
&nvram_writeb_protected,
|
||||
&nvram_writew_protected,
|
||||
&nvram_writel_protected,
|
||||
};
|
||||
|
||||
/* Initialisation routine */
|
||||
void *ds1225y_init(target_phys_addr_t mem_base, const char *filename)
|
||||
static int nvram_post_load(void *opaque, int version_id)
|
||||
{
|
||||
ds1225y_t *s;
|
||||
int mem_indexRW, mem_indexRP;
|
||||
QEMUFile *file;
|
||||
NvRamState *s = opaque;
|
||||
|
||||
s = qemu_mallocz(sizeof(ds1225y_t));
|
||||
s->chip_size = 0x2000; /* Fixed for ds1225y chip: 8 KiB */
|
||||
s->contents = qemu_mallocz(s->chip_size);
|
||||
s->protection = 7;
|
||||
|
||||
/* Read current file */
|
||||
file = qemu_fopen(filename, "rb");
|
||||
if (file) {
|
||||
/* Read nvram contents */
|
||||
qemu_get_buffer(file, s->contents, s->chip_size);
|
||||
qemu_fclose(file);
|
||||
/* Close file, as filename may has changed in load/store process */
|
||||
if (s->file) {
|
||||
qemu_fclose(s->file);
|
||||
}
|
||||
s->file = qemu_fopen(filename, "wb");
|
||||
|
||||
/* Write back nvram contents */
|
||||
s->file = qemu_fopen(s->filename, "wb");
|
||||
if (s->file) {
|
||||
/* Write back contents, as 'wb' mode cleaned the file */
|
||||
qemu_put_buffer(s->file, s->contents, s->chip_size);
|
||||
qemu_fflush(s->file);
|
||||
}
|
||||
|
||||
/* Read/write memory */
|
||||
mem_indexRW = cpu_register_io_memory(nvram_read, nvram_write, s,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
cpu_register_physical_memory(mem_base, s->chip_size, mem_indexRW);
|
||||
/* Read/write protected memory */
|
||||
mem_indexRP = cpu_register_io_memory(nvram_read, nvram_write_protected, s,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
cpu_register_physical_memory(mem_base + s->chip_size, s->chip_size, mem_indexRP);
|
||||
return s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_nvram = {
|
||||
.name = "nvram",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.post_load = nvram_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VARRAY_UINT32(contents, NvRamState, chip_size, 0,
|
||||
vmstate_info_uint8, uint8_t),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
SysBusDevice busdev;
|
||||
NvRamState nvram;
|
||||
} SysBusNvRamState;
|
||||
|
||||
static int nvram_sysbus_initfn(SysBusDevice *dev)
|
||||
{
|
||||
NvRamState *s = &FROM_SYSBUS(SysBusNvRamState, dev)->nvram;
|
||||
QEMUFile *file;
|
||||
int s_io;
|
||||
|
||||
s->contents = qemu_mallocz(s->chip_size);
|
||||
|
||||
s_io = cpu_register_io_memory(nvram_read, nvram_write, s,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
sysbus_init_mmio(dev, s->chip_size, s_io);
|
||||
|
||||
/* Read current file */
|
||||
file = qemu_fopen(s->filename, "rb");
|
||||
if (file) {
|
||||
/* Read nvram contents */
|
||||
qemu_get_buffer(file, s->contents, s->chip_size);
|
||||
qemu_fclose(file);
|
||||
}
|
||||
nvram_post_load(s, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SysBusDeviceInfo nvram_sysbus_info = {
|
||||
.qdev.name = "ds1225y",
|
||||
.qdev.size = sizeof(SysBusNvRamState),
|
||||
.qdev.vmsd = &vmstate_nvram,
|
||||
.init = nvram_sysbus_initfn,
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
|
||||
DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static void nvram_register(void)
|
||||
{
|
||||
sysbus_register_withprop(&nvram_sysbus_info);
|
||||
}
|
||||
|
||||
device_init(nvram_register)
|
||||
|
|
6
hw/esp.c
6
hw/esp.c
|
@ -211,7 +211,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
|
|||
} else {
|
||||
dmalen = s->ti_size;
|
||||
memcpy(buf, s->ti_buf, dmalen);
|
||||
buf[0] = 0;
|
||||
buf[0] = buf[2] >> 5;
|
||||
}
|
||||
DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
|
||||
|
||||
|
@ -219,7 +219,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
|
|||
s->ti_rptr = 0;
|
||||
s->ti_wptr = 0;
|
||||
|
||||
if (s->current_dev) {
|
||||
if (s->current_req) {
|
||||
/* Started a new command before the old one finished. Cancel it. */
|
||||
scsi_req_cancel(s->current_req);
|
||||
s->async_len = 0;
|
||||
|
@ -244,7 +244,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
|
|||
|
||||
DPRINTF("do_busid_cmd: busid 0x%x\n", busid);
|
||||
lun = busid & 7;
|
||||
s->current_req = scsi_req_new(s->current_dev, 0, lun);
|
||||
s->current_req = scsi_req_new(s->current_dev, 0, lun, NULL);
|
||||
datalen = scsi_req_enqueue(s->current_req, buf);
|
||||
s->ti_size = datalen;
|
||||
if (datalen != 0) {
|
||||
|
|
|
@ -190,15 +190,23 @@ static void serial_event(void *opaque, int event)
|
|||
|
||||
}
|
||||
|
||||
static int etraxfs_ser_init(SysBusDevice *dev)
|
||||
static void etraxfs_ser_reset(DeviceState *d)
|
||||
{
|
||||
struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
|
||||
int ser_regs;
|
||||
struct etrax_serial *s = container_of(d, typeof(*s), busdev.qdev);
|
||||
|
||||
/* transmitter begins ready and idle. */
|
||||
s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
|
||||
s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
|
||||
|
||||
s->regs[RW_REC_CTRL] = 0x10000;
|
||||
|
||||
}
|
||||
|
||||
static int etraxfs_ser_init(SysBusDevice *dev)
|
||||
{
|
||||
struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
|
||||
int ser_regs;
|
||||
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
ser_regs = cpu_register_io_memory(ser_read, ser_write, s,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
|
@ -211,10 +219,16 @@ static int etraxfs_ser_init(SysBusDevice *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static SysBusDeviceInfo etraxfs_ser_info = {
|
||||
.init = etraxfs_ser_init,
|
||||
.qdev.name = "etraxfs,serial",
|
||||
.qdev.size = sizeof(struct etrax_serial),
|
||||
.qdev.reset = etraxfs_ser_reset,
|
||||
};
|
||||
|
||||
static void etraxfs_serial_register(void)
|
||||
{
|
||||
sysbus_register_dev("etraxfs,serial", sizeof (struct etrax_serial),
|
||||
etraxfs_ser_init);
|
||||
sysbus_register_withprop(&etraxfs_ser_info);
|
||||
}
|
||||
|
||||
device_init(etraxfs_serial_register)
|
||||
|
|
|
@ -78,6 +78,9 @@ void framebuffer_update_display(
|
|||
dest = ds_get_data(ds);
|
||||
if (dest_col_pitch < 0)
|
||||
dest -= dest_col_pitch * (cols - 1);
|
||||
if (dest_row_pitch < 0) {
|
||||
dest -= dest_row_pitch * (rows - 1);
|
||||
}
|
||||
first = -1;
|
||||
addr = pd;
|
||||
|
||||
|
|
|
@ -192,7 +192,7 @@ static void update_irq(struct HPETTimer *timer, int set)
|
|||
qemu_irq_lower(s->irqs[route]);
|
||||
}
|
||||
} else if (timer_fsb_route(timer)) {
|
||||
stl_phys(timer->fsb >> 32, timer->fsb & 0xffffffff);
|
||||
stl_le_phys(timer->fsb >> 32, timer->fsb & 0xffffffff);
|
||||
} else if (timer->config & HPET_TN_TYPE_LEVEL) {
|
||||
s->isr |= mask;
|
||||
qemu_irq_raise(s->irqs[route]);
|
||||
|
|
|
@ -56,6 +56,7 @@ static const int smart_attributes[][12] = {
|
|||
};
|
||||
|
||||
static int ide_handle_rw_error(IDEState *s, int error, int op);
|
||||
static void ide_dummy_transfer_stop(IDEState *s);
|
||||
|
||||
static void padstr(char *str, const char *src, int len)
|
||||
{
|
||||
|
@ -1532,15 +1533,36 @@ void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val)
|
|||
bus->cmd = val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the running PIO transfer is a PIO out (i.e. data is
|
||||
* transferred from the device to the guest), false if it's a PIO in
|
||||
*/
|
||||
static bool ide_is_pio_out(IDEState *s)
|
||||
{
|
||||
if (s->end_transfer_func == ide_sector_write ||
|
||||
s->end_transfer_func == ide_atapi_cmd) {
|
||||
return false;
|
||||
} else if (s->end_transfer_func == ide_sector_read ||
|
||||
s->end_transfer_func == ide_transfer_stop ||
|
||||
s->end_transfer_func == ide_atapi_cmd_reply_end ||
|
||||
s->end_transfer_func == ide_dummy_transfer_stop) {
|
||||
return true;
|
||||
}
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
IDEBus *bus = opaque;
|
||||
IDEState *s = idebus_active_if(bus);
|
||||
uint8_t *p;
|
||||
|
||||
/* PIO data access allowed only when DRQ bit is set */
|
||||
if (!(s->status & DRQ_STAT))
|
||||
/* PIO data access allowed only when DRQ bit is set. The result of a write
|
||||
* during PIO out is indeterminate, just ignore it. */
|
||||
if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
*(uint16_t *)p = le16_to_cpu(val);
|
||||
|
@ -1557,9 +1579,11 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr)
|
|||
uint8_t *p;
|
||||
int ret;
|
||||
|
||||
/* PIO data access allowed only when DRQ bit is set */
|
||||
if (!(s->status & DRQ_STAT))
|
||||
/* PIO data access allowed only when DRQ bit is set. The result of a read
|
||||
* during PIO in is indeterminate, return 0 and don't move forward. */
|
||||
if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
ret = cpu_to_le16(*(uint16_t *)p);
|
||||
|
@ -1576,9 +1600,11 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
|
|||
IDEState *s = idebus_active_if(bus);
|
||||
uint8_t *p;
|
||||
|
||||
/* PIO data access allowed only when DRQ bit is set */
|
||||
if (!(s->status & DRQ_STAT))
|
||||
/* PIO data access allowed only when DRQ bit is set. The result of a write
|
||||
* during PIO out is indeterminate, just ignore it. */
|
||||
if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
*(uint32_t *)p = le32_to_cpu(val);
|
||||
|
@ -1595,9 +1621,11 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr)
|
|||
uint8_t *p;
|
||||
int ret;
|
||||
|
||||
/* PIO data access allowed only when DRQ bit is set */
|
||||
if (!(s->status & DRQ_STAT))
|
||||
/* PIO data access allowed only when DRQ bit is set. The result of a read
|
||||
* during PIO in is indeterminate, return 0 and don't move forward. */
|
||||
if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
ret = cpu_to_le32(*(uint32_t *)p);
|
||||
|
@ -1761,9 +1789,13 @@ static void ide_init1(IDEBus *bus, int unit)
|
|||
s->unit = unit;
|
||||
s->drive_serial = drive_serial++;
|
||||
/* we need at least 2k alignment for accessing CDROMs using O_DIRECT */
|
||||
s->io_buffer = qemu_memalign(2048, IDE_DMA_BUF_SECTORS*512 + 4);
|
||||
s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
|
||||
s->io_buffer = qemu_memalign(2048, s->io_buffer_total_len);
|
||||
memset(s->io_buffer, 0, s->io_buffer_total_len);
|
||||
|
||||
s->smart_selftest_data = qemu_blockalign(s->bs, 512);
|
||||
memset(s->smart_selftest_data, 0, 512);
|
||||
|
||||
s->sector_write_timer = qemu_new_timer_ns(vm_clock,
|
||||
ide_sector_write_timer_cb, s);
|
||||
}
|
||||
|
|
|
@ -224,19 +224,6 @@ static target_phys_addr_t intel_hda_addr(uint32_t lbase, uint32_t ubase)
|
|||
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;
|
||||
|
@ -341,7 +328,7 @@ static void intel_hda_corb_run(IntelHDAState *d)
|
|||
|
||||
rp = (d->corb_rp + 1) & 0xff;
|
||||
addr = intel_hda_addr(d->corb_lbase, d->corb_ubase);
|
||||
verb = ldl_phys_le(addr + 4*rp);
|
||||
verb = ldl_le_phys(addr + 4*rp);
|
||||
d->corb_rp = rp;
|
||||
|
||||
dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb);
|
||||
|
@ -373,8 +360,8 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res
|
|||
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);
|
||||
stl_le_phys(addr + 8*wp, response);
|
||||
stl_le_phys(addr + 8*wp + 4, ex);
|
||||
d->rirb_wp = wp;
|
||||
|
||||
dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n",
|
||||
|
@ -461,7 +448,7 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
|
|||
}
|
||||
if (d->dp_lbase & 0x01) {
|
||||
addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase);
|
||||
stl_phys_le(addr + 8*s, st->lpib);
|
||||
stl_le_phys(addr + 8*s, st->lpib);
|
||||
}
|
||||
dprint(d, 3, "dma: --\n");
|
||||
|
||||
|
|
|
@ -661,7 +661,7 @@ static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
|
|||
static void lsi_request_cancelled(SCSIRequest *req)
|
||||
{
|
||||
LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
|
||||
lsi_request *p;
|
||||
lsi_request *p = req->hba_private;
|
||||
|
||||
if (s->current && req == s->current->req) {
|
||||
scsi_req_unref(req);
|
||||
|
@ -670,7 +670,6 @@ static void lsi_request_cancelled(SCSIRequest *req)
|
|||
return;
|
||||
}
|
||||
|
||||
p = lsi_find_by_tag(s, req->tag);
|
||||
if (p) {
|
||||
QTAILQ_REMOVE(&s->queue, p, next);
|
||||
scsi_req_unref(req);
|
||||
|
@ -680,18 +679,12 @@ static void lsi_request_cancelled(SCSIRequest *req)
|
|||
|
||||
/* Record that data is available for a queued command. Returns zero if
|
||||
the device was reselected, nonzero if the IO is deferred. */
|
||||
static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t len)
|
||||
static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
|
||||
{
|
||||
lsi_request *p;
|
||||
|
||||
p = lsi_find_by_tag(s, tag);
|
||||
if (!p) {
|
||||
BADF("IO with unknown tag %d\n", tag);
|
||||
return 1;
|
||||
}
|
||||
lsi_request *p = req->hba_private;
|
||||
|
||||
if (p->pending) {
|
||||
BADF("Multiple IO pending for tag %d\n", tag);
|
||||
BADF("Multiple IO pending for request %p\n", p);
|
||||
}
|
||||
p->pending = len;
|
||||
/* Reselect if waiting for it, or if reselection triggers an IRQ
|
||||
|
@ -743,9 +736,9 @@ static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
|
|||
LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
|
||||
int out;
|
||||
|
||||
if (s->waiting == 1 || !s->current || req->tag != s->current->tag ||
|
||||
if (s->waiting == 1 || !s->current || req->hba_private != s->current ||
|
||||
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
|
||||
if (lsi_queue_tag(s, req->tag, len)) {
|
||||
if (lsi_queue_req(s, req, len)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -789,7 +782,8 @@ static void lsi_do_command(LSIState *s)
|
|||
assert(s->current == NULL);
|
||||
s->current = qemu_mallocz(sizeof(lsi_request));
|
||||
s->current->tag = s->select_tag;
|
||||
s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun);
|
||||
s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun,
|
||||
s->current);
|
||||
|
||||
n = scsi_req_enqueue(s->current->req, buf);
|
||||
if (n) {
|
||||
|
|
|
@ -247,16 +247,21 @@ static void softusb_attach(USBPort *port)
|
|||
{
|
||||
}
|
||||
|
||||
static void softusb_device_destroy(USBBus *bus, USBDevice *dev)
|
||||
static void softusb_detach(USBPort *port)
|
||||
{
|
||||
}
|
||||
|
||||
static void softusb_child_detach(USBPort *port, USBDevice *child)
|
||||
{
|
||||
}
|
||||
|
||||
static USBPortOps softusb_ops = {
|
||||
.attach = softusb_attach,
|
||||
.detach = softusb_detach,
|
||||
.child_detach = softusb_child_detach,
|
||||
};
|
||||
|
||||
static USBBusOps softusb_bus_ops = {
|
||||
.device_destroy = softusb_device_destroy,
|
||||
};
|
||||
|
||||
static void milkymist_softusb_reset(DeviceState *d)
|
||||
|
|
|
@ -8,10 +8,6 @@ PCIBus *gt64120_register(qemu_irq *pic);
|
|||
/* bonito.c */
|
||||
PCIBus *bonito_init(qemu_irq *pic);
|
||||
|
||||
/* ds1225y.c */
|
||||
void *ds1225y_init(target_phys_addr_t mem_base, const char *filename);
|
||||
void ds1225y_set_protection(void *opaque, int protection);
|
||||
|
||||
/* g364fb.c */
|
||||
int g364fb_mm_init(target_phys_addr_t vram_base,
|
||||
target_phys_addr_t ctrl_base, int it_shift,
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "loader.h"
|
||||
#include "mc146818rtc.h"
|
||||
#include "blockdev.h"
|
||||
#include "sysbus.h"
|
||||
|
||||
enum jazz_model_e
|
||||
{
|
||||
|
@ -115,6 +116,8 @@ void mips_jazz_init (ram_addr_t ram_size,
|
|||
void* rc4030_opaque;
|
||||
int s_rtc, s_dma_dummy;
|
||||
NICInfo *nd;
|
||||
DeviceState *dev;
|
||||
SysBusDevice *sysbus;
|
||||
ISADevice *pit;
|
||||
DriveInfo *fds[MAX_FD];
|
||||
qemu_irq esp_reset, dma_enable;
|
||||
|
@ -266,8 +269,11 @@ void mips_jazz_init (ram_addr_t ram_size,
|
|||
/* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */
|
||||
audio_init(i8259, NULL);
|
||||
|
||||
/* NVRAM: Unprotected at 0x9000, Protected at 0xa000, Read only at 0xb000 */
|
||||
ds1225y_init(0x80009000, "nvram");
|
||||
/* NVRAM */
|
||||
dev = qdev_create(NULL, "ds1225y");
|
||||
qdev_init_nofail(dev);
|
||||
sysbus = sysbus_from_qdev(dev);
|
||||
sysbus_mmio_map(sysbus, 0, 0x80009000);
|
||||
|
||||
/* LED indicator */
|
||||
jazz_led_init(0x8000f000);
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* QEMU PowerPC MPC8544 global util pseudo-device
|
||||
*
|
||||
* Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Author: Alexander Graf, <alex@csgraf.de>
|
||||
*
|
||||
* This 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 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* *****************************************************************
|
||||
*
|
||||
* The documentation for this device is noted in the MPC8544 documentation,
|
||||
* file name "MPC8544ERM.pdf". You can easily find it on the web.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hw.h"
|
||||
#include "sysemu.h"
|
||||
#include "sysbus.h"
|
||||
|
||||
#define MPC8544_GUTS_MMIO_SIZE 0x1000
|
||||
#define MPC8544_GUTS_RSTCR_RESET 0x02
|
||||
|
||||
#define MPC8544_GUTS_ADDR_PORPLLSR 0x00
|
||||
#define MPC8544_GUTS_ADDR_PORBMSR 0x04
|
||||
#define MPC8544_GUTS_ADDR_PORIMPSCR 0x08
|
||||
#define MPC8544_GUTS_ADDR_PORDEVSR 0x0C
|
||||
#define MPC8544_GUTS_ADDR_PORDBGMSR 0x10
|
||||
#define MPC8544_GUTS_ADDR_PORDEVSR2 0x14
|
||||
#define MPC8544_GUTS_ADDR_GPPORCR 0x20
|
||||
#define MPC8544_GUTS_ADDR_GPIOCR 0x30
|
||||
#define MPC8544_GUTS_ADDR_GPOUTDR 0x40
|
||||
#define MPC8544_GUTS_ADDR_GPINDR 0x50
|
||||
#define MPC8544_GUTS_ADDR_PMUXCR 0x60
|
||||
#define MPC8544_GUTS_ADDR_DEVDISR 0x70
|
||||
#define MPC8544_GUTS_ADDR_POWMGTCSR 0x80
|
||||
#define MPC8544_GUTS_ADDR_MCPSUMR 0x90
|
||||
#define MPC8544_GUTS_ADDR_RSTRSCR 0x94
|
||||
#define MPC8544_GUTS_ADDR_PVR 0xA0
|
||||
#define MPC8544_GUTS_ADDR_SVR 0xA4
|
||||
#define MPC8544_GUTS_ADDR_RSTCR 0xB0
|
||||
#define MPC8544_GUTS_ADDR_IOVSELSR 0xC0
|
||||
#define MPC8544_GUTS_ADDR_DDRCSR 0xB20
|
||||
#define MPC8544_GUTS_ADDR_DDRCDR 0xB24
|
||||
#define MPC8544_GUTS_ADDR_DDRCLKDR 0xB28
|
||||
#define MPC8544_GUTS_ADDR_CLKOCR 0xE00
|
||||
#define MPC8544_GUTS_ADDR_SRDS1CR1 0xF04
|
||||
#define MPC8544_GUTS_ADDR_SRDS2CR1 0xF10
|
||||
#define MPC8544_GUTS_ADDR_SRDS2CR3 0xF18
|
||||
|
||||
struct GutsState {
|
||||
SysBusDevice busdev;
|
||||
};
|
||||
|
||||
typedef struct GutsState GutsState;
|
||||
|
||||
static uint32_t mpc8544_guts_read32(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
CPUState *env = cpu_single_env;
|
||||
|
||||
addr &= MPC8544_GUTS_MMIO_SIZE - 1;
|
||||
switch (addr) {
|
||||
case MPC8544_GUTS_ADDR_PVR:
|
||||
value = env->spr[SPR_PVR];
|
||||
break;
|
||||
case MPC8544_GUTS_ADDR_SVR:
|
||||
value = env->spr[SPR_E500_SVR];
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr);
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc * const mpc8544_guts_read[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
&mpc8544_guts_read32,
|
||||
};
|
||||
|
||||
static void mpc8544_guts_write32(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t value)
|
||||
{
|
||||
addr &= MPC8544_GUTS_MMIO_SIZE - 1;
|
||||
|
||||
switch (addr) {
|
||||
case MPC8544_GUTS_ADDR_RSTCR:
|
||||
if (value & MPC8544_GUTS_RSTCR_RESET) {
|
||||
qemu_system_reset_request();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "guts: Unknown register write: %x = %x\n",
|
||||
(int)addr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc * const mpc8544_guts_write[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
&mpc8544_guts_write32,
|
||||
};
|
||||
|
||||
static int mpc8544_guts_initfn(SysBusDevice *dev)
|
||||
{
|
||||
GutsState *s;
|
||||
int iomem;
|
||||
|
||||
s = FROM_SYSBUS(GutsState, sysbus_from_qdev(dev));
|
||||
|
||||
iomem = cpu_register_io_memory(mpc8544_guts_read, mpc8544_guts_write, s,
|
||||
DEVICE_BIG_ENDIAN);
|
||||
sysbus_init_mmio(dev, MPC8544_GUTS_MMIO_SIZE, iomem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SysBusDeviceInfo mpc8544_guts_info = {
|
||||
.init = mpc8544_guts_initfn,
|
||||
.qdev.name = "mpc8544-guts",
|
||||
.qdev.size = sizeof(GutsState),
|
||||
};
|
||||
|
||||
static void mpc8544_guts_register(void)
|
||||
{
|
||||
sysbus_register_withprop(&mpc8544_guts_info);
|
||||
}
|
||||
device_init(mpc8544_guts_register);
|
2
hw/msi.c
2
hw/msi.c
|
@ -249,7 +249,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
|
|||
"notify vector 0x%x"
|
||||
" address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
|
||||
vector, address, data);
|
||||
stl_phys(address, data);
|
||||
stl_le_phys(address, data);
|
||||
}
|
||||
|
||||
/* call this function after updating configs by pci_default_write_config(). */
|
||||
|
|
|
@ -359,7 +359,7 @@ void msix_notify(PCIDevice *dev, unsigned vector)
|
|||
|
||||
address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
|
||||
data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
|
||||
stl_phys(address, data);
|
||||
stl_le_phys(address, data);
|
||||
}
|
||||
|
||||
void msix_reset(PCIDevice *dev)
|
||||
|
|
|
@ -1254,12 +1254,12 @@ static int n8x0_atag_setup(void *p, int model)
|
|||
return (void *) w - p;
|
||||
}
|
||||
|
||||
static int n800_atag_setup(struct arm_boot_info *info, void *p)
|
||||
static int n800_atag_setup(const struct arm_boot_info *info, void *p)
|
||||
{
|
||||
return n8x0_atag_setup(p, 800);
|
||||
}
|
||||
|
||||
static int n810_atag_setup(struct arm_boot_info *info, void *p)
|
||||
static int n810_atag_setup(const struct arm_boot_info *info, void *p)
|
||||
{
|
||||
return n8x0_atag_setup(p, 810);
|
||||
}
|
||||
|
|
11
hw/pci_ids.h
11
hw/pci_ids.h
|
@ -109,5 +109,14 @@
|
|||
#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
|
||||
#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
|
||||
#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
|
||||
#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934
|
||||
#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935
|
||||
#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936
|
||||
#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937
|
||||
#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938
|
||||
#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939
|
||||
#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a
|
||||
#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c
|
||||
|
||||
#define PCI_VENDOR_ID_XENSOURCE 0x5853
|
||||
#define PCI_VENDOR_ID_XEN 0x5853
|
||||
#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001
|
||||
|
|
|
@ -478,6 +478,9 @@ static PCIDeviceInfo i440fx_info[] = {
|
|||
.no_hotplug = 1,
|
||||
.init = piix3_initfn,
|
||||
.config_write = piix3_write_config_xen,
|
||||
.vendor_id = PCI_VENDOR_ID_INTEL,
|
||||
.device_id = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
|
||||
.class_id = PCI_CLASS_BRIDGE_ISA,
|
||||
},{
|
||||
/* end of list */
|
||||
}
|
||||
|
|
|
@ -199,10 +199,10 @@ again:
|
|||
if (size == 0) {
|
||||
/* Transfer complete. */
|
||||
if (ch->lli) {
|
||||
ch->src = ldl_phys(ch->lli);
|
||||
ch->dest = ldl_phys(ch->lli + 4);
|
||||
ch->ctrl = ldl_phys(ch->lli + 12);
|
||||
ch->lli = ldl_phys(ch->lli + 8);
|
||||
ch->src = ldl_le_phys(ch->lli);
|
||||
ch->dest = ldl_le_phys(ch->lli + 4);
|
||||
ch->ctrl = ldl_le_phys(ch->lli + 12);
|
||||
ch->lli = ldl_le_phys(ch->lli + 8);
|
||||
} else {
|
||||
ch->conf &= ~PL080_CCONF_E;
|
||||
}
|
||||
|
|
|
@ -51,39 +51,42 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd,
|
|||
bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t);
|
||||
else
|
||||
bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t);
|
||||
stl_phys(bdloc + 0x00, bd->bi_memstart);
|
||||
stl_phys(bdloc + 0x04, bd->bi_memsize);
|
||||
stl_phys(bdloc + 0x08, bd->bi_flashstart);
|
||||
stl_phys(bdloc + 0x0C, bd->bi_flashsize);
|
||||
stl_phys(bdloc + 0x10, bd->bi_flashoffset);
|
||||
stl_phys(bdloc + 0x14, bd->bi_sramstart);
|
||||
stl_phys(bdloc + 0x18, bd->bi_sramsize);
|
||||
stl_phys(bdloc + 0x1C, bd->bi_bootflags);
|
||||
stl_phys(bdloc + 0x20, bd->bi_ipaddr);
|
||||
for (i = 0; i < 6; i++)
|
||||
stl_be_phys(bdloc + 0x00, bd->bi_memstart);
|
||||
stl_be_phys(bdloc + 0x04, bd->bi_memsize);
|
||||
stl_be_phys(bdloc + 0x08, bd->bi_flashstart);
|
||||
stl_be_phys(bdloc + 0x0C, bd->bi_flashsize);
|
||||
stl_be_phys(bdloc + 0x10, bd->bi_flashoffset);
|
||||
stl_be_phys(bdloc + 0x14, bd->bi_sramstart);
|
||||
stl_be_phys(bdloc + 0x18, bd->bi_sramsize);
|
||||
stl_be_phys(bdloc + 0x1C, bd->bi_bootflags);
|
||||
stl_be_phys(bdloc + 0x20, bd->bi_ipaddr);
|
||||
for (i = 0; i < 6; i++) {
|
||||
stb_phys(bdloc + 0x24 + i, bd->bi_enetaddr[i]);
|
||||
stw_phys(bdloc + 0x2A, bd->bi_ethspeed);
|
||||
stl_phys(bdloc + 0x2C, bd->bi_intfreq);
|
||||
stl_phys(bdloc + 0x30, bd->bi_busfreq);
|
||||
stl_phys(bdloc + 0x34, bd->bi_baudrate);
|
||||
for (i = 0; i < 4; i++)
|
||||
}
|
||||
stw_be_phys(bdloc + 0x2A, bd->bi_ethspeed);
|
||||
stl_be_phys(bdloc + 0x2C, bd->bi_intfreq);
|
||||
stl_be_phys(bdloc + 0x30, bd->bi_busfreq);
|
||||
stl_be_phys(bdloc + 0x34, bd->bi_baudrate);
|
||||
for (i = 0; i < 4; i++) {
|
||||
stb_phys(bdloc + 0x38 + i, bd->bi_s_version[i]);
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
stb_phys(bdloc + 0x3C + i, bd->bi_r_version[i]);
|
||||
}
|
||||
stl_phys(bdloc + 0x5C, bd->bi_plb_busfreq);
|
||||
stl_phys(bdloc + 0x60, bd->bi_pci_busfreq);
|
||||
for (i = 0; i < 6; i++)
|
||||
stl_be_phys(bdloc + 0x5C, bd->bi_plb_busfreq);
|
||||
stl_be_phys(bdloc + 0x60, bd->bi_pci_busfreq);
|
||||
for (i = 0; i < 6; i++) {
|
||||
stb_phys(bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]);
|
||||
}
|
||||
n = 0x6A;
|
||||
if (flags & 0x00000001) {
|
||||
for (i = 0; i < 6; i++)
|
||||
stb_phys(bdloc + n++, bd->bi_pci_enetaddr2[i]);
|
||||
}
|
||||
stl_phys(bdloc + n, bd->bi_opbfreq);
|
||||
stl_be_phys(bdloc + n, bd->bi_opbfreq);
|
||||
n += 4;
|
||||
for (i = 0; i < 2; i++) {
|
||||
stl_phys(bdloc + n, bd->bi_iic_fast[i]);
|
||||
stl_be_phys(bdloc + n, bd->bi_iic_fast[i]);
|
||||
n += 4;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,9 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
|
|||
qemu_irq *irqs;
|
||||
qemu_irq *pci_irqs;
|
||||
|
||||
if (cpu_model == NULL)
|
||||
cpu_model = "405"; // XXX: should be 440EP
|
||||
if (cpu_model == NULL) {
|
||||
cpu_model = "440-Xilinx"; // XXX: should be 440EP
|
||||
}
|
||||
env = cpu_init(cpu_model);
|
||||
if (!env) {
|
||||
fprintf(stderr, "Unable to initialize CPU!\n");
|
||||
|
|
|
@ -35,8 +35,7 @@
|
|||
#define PROM_ADDR 0xfff00000
|
||||
|
||||
#define KERNEL_LOAD_ADDR 0x01000000
|
||||
#define CMDLINE_ADDR 0x027ff000
|
||||
#define INITRD_LOAD_ADDR 0x02800000
|
||||
#define KERNEL_GAP 0x00100000
|
||||
|
||||
#define ESCC_CLOCK 3686400
|
||||
|
||||
|
|
|
@ -120,6 +120,11 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
|
|||
return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
|
||||
}
|
||||
|
||||
static target_phys_addr_t round_page(target_phys_addr_t addr)
|
||||
{
|
||||
return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
|
||||
}
|
||||
|
||||
/* PowerPC Mac99 hardware initialisation */
|
||||
static void ppc_core99_init (ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
|
@ -134,7 +139,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
|
|||
int unin_memory;
|
||||
int linux_boot, i;
|
||||
ram_addr_t ram_offset, bios_offset;
|
||||
uint32_t kernel_base, initrd_base;
|
||||
target_phys_addr_t kernel_base, initrd_base, cmdline_base = 0;
|
||||
long kernel_size, initrd_size;
|
||||
PCIBus *pci_bus;
|
||||
MacIONVRAMState *nvr;
|
||||
|
@ -220,7 +225,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
|
|||
}
|
||||
/* load initrd */
|
||||
if (initrd_filename) {
|
||||
initrd_base = INITRD_LOAD_ADDR;
|
||||
initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
|
||||
initrd_size = load_image_targphys(initrd_filename, initrd_base,
|
||||
ram_size - initrd_base);
|
||||
if (initrd_size < 0) {
|
||||
|
@ -228,9 +233,11 @@ static void ppc_core99_init (ram_addr_t ram_size,
|
|||
initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
cmdline_base = round_page(initrd_base + initrd_size);
|
||||
} else {
|
||||
initrd_base = 0;
|
||||
initrd_size = 0;
|
||||
cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
|
||||
}
|
||||
ppc_boot_device = 'm';
|
||||
} else {
|
||||
|
@ -373,8 +380,8 @@ static void ppc_core99_init (ram_addr_t ram_size,
|
|||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
|
||||
if (kernel_cmdline) {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
|
||||
pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base);
|
||||
pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline);
|
||||
} else {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
|
||||
}
|
||||
|
|
|
@ -59,6 +59,11 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
|
|||
return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
|
||||
}
|
||||
|
||||
static target_phys_addr_t round_page(target_phys_addr_t addr)
|
||||
{
|
||||
return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
|
||||
}
|
||||
|
||||
static void ppc_heathrow_init (ram_addr_t ram_size,
|
||||
const char *boot_device,
|
||||
const char *kernel_filename,
|
||||
|
@ -71,7 +76,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
|
|||
qemu_irq *pic, **heathrow_irqs;
|
||||
int linux_boot, i;
|
||||
ram_addr_t ram_offset, bios_offset;
|
||||
uint32_t kernel_base, initrd_base;
|
||||
uint32_t kernel_base, initrd_base, cmdline_base = 0;
|
||||
int32_t kernel_size, initrd_size;
|
||||
PCIBus *pci_bus;
|
||||
MacIONVRAMState *nvr;
|
||||
|
@ -157,7 +162,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
|
|||
}
|
||||
/* load initrd */
|
||||
if (initrd_filename) {
|
||||
initrd_base = INITRD_LOAD_ADDR;
|
||||
initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
|
||||
initrd_size = load_image_targphys(initrd_filename, initrd_base,
|
||||
ram_size - initrd_base);
|
||||
if (initrd_size < 0) {
|
||||
|
@ -165,9 +170,11 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
|
|||
initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
cmdline_base = round_page(initrd_base + initrd_size);
|
||||
} else {
|
||||
initrd_base = 0;
|
||||
initrd_size = 0;
|
||||
cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
|
||||
}
|
||||
ppc_boot_device = 'm';
|
||||
} else {
|
||||
|
@ -278,8 +285,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
|
|||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
|
||||
if (kernel_cmdline) {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
|
||||
pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base);
|
||||
pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline);
|
||||
} else {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#define MPC8544_PCI_REGS_SIZE 0x1000
|
||||
#define MPC8544_PCI_IO 0xE1000000
|
||||
#define MPC8544_PCI_IOLEN 0x10000
|
||||
#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000)
|
||||
|
||||
struct boot_info
|
||||
{
|
||||
|
@ -81,11 +82,12 @@ out:
|
|||
}
|
||||
#endif
|
||||
|
||||
static int mpc8544_load_device_tree(target_phys_addr_t addr,
|
||||
uint32_t ramsize,
|
||||
target_phys_addr_t initrd_base,
|
||||
target_phys_addr_t initrd_size,
|
||||
const char *kernel_cmdline)
|
||||
static int mpc8544_load_device_tree(CPUState *env,
|
||||
target_phys_addr_t addr,
|
||||
uint32_t ramsize,
|
||||
target_phys_addr_t initrd_base,
|
||||
target_phys_addr_t initrd_size,
|
||||
const char *kernel_cmdline)
|
||||
{
|
||||
int ret = -1;
|
||||
#ifdef CONFIG_FDT
|
||||
|
@ -93,6 +95,7 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr,
|
|||
char *filename;
|
||||
int fdt_size;
|
||||
void *fdt;
|
||||
uint8_t hypercall[16];
|
||||
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
|
||||
if (!filename) {
|
||||
|
@ -156,6 +159,13 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr,
|
|||
|
||||
mpc8544_copy_soc_cell(fdt, buf, "clock-frequency");
|
||||
mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency");
|
||||
|
||||
/* indicate KVM hypercall interface */
|
||||
qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
|
||||
"linux,kvm");
|
||||
kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
|
||||
qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
|
||||
hypercall, sizeof(hypercall));
|
||||
} else {
|
||||
const uint32_t freq = 400000000;
|
||||
|
||||
|
@ -175,18 +185,23 @@ out:
|
|||
}
|
||||
|
||||
/* Create -kernel TLB entries for BookE, linearly spanning 256MB. */
|
||||
static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
|
||||
{
|
||||
return (ffs(size >> 10) - 1) >> 1;
|
||||
}
|
||||
|
||||
static void mmubooke_create_initial_mapping(CPUState *env,
|
||||
target_ulong va,
|
||||
target_phys_addr_t pa)
|
||||
{
|
||||
ppcemb_tlb_t *tlb = booke206_get_tlbe(env, 1, 0, 0);
|
||||
ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
|
||||
target_phys_addr_t size;
|
||||
|
||||
tlb->attr = 0;
|
||||
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
||||
tlb->size = 256 * 1024 * 1024;
|
||||
tlb->EPN = va & TARGET_PAGE_MASK;
|
||||
tlb->RPN = pa & TARGET_PAGE_MASK;
|
||||
tlb->PID = 0;
|
||||
size = (booke206_page_size_to_tlb(256 * 1024 * 1024) << MAS1_TSIZE_SHIFT);
|
||||
tlb->mas1 = MAS1_VALID | size;
|
||||
tlb->mas2 = va & TARGET_PAGE_MASK;
|
||||
tlb->mas7_3 = pa & TARGET_PAGE_MASK;
|
||||
tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
|
||||
}
|
||||
|
||||
static void mpc8544ds_cpu_reset(void *opaque)
|
||||
|
@ -270,6 +285,9 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
|||
serial_hds[0], 1, 1);
|
||||
}
|
||||
|
||||
/* General Utility device */
|
||||
sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
|
||||
|
||||
/* PCI */
|
||||
dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
|
||||
mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
|
||||
|
@ -326,7 +344,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
|
|||
cpu_abort(env, "Compiled without FDT support - can't load kernel\n");
|
||||
#endif
|
||||
dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
|
||||
if (mpc8544_load_device_tree(dt_base, ram_size,
|
||||
if (mpc8544_load_device_tree(env, dt_base, ram_size,
|
||||
initrd_base, initrd_size, kernel_cmdline) < 0) {
|
||||
fprintf(stderr, "couldn't load device tree\n");
|
||||
exit(1);
|
||||
|
|
109
hw/pxa2xx_lcd.c
109
hw/pxa2xx_lcd.c
|
@ -665,7 +665,7 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
|
|||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_lcdc_dma0_redraw_horiz(PXA2xxLCDState *s,
|
||||
static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
|
||||
target_phys_addr_t addr, int *miny, int *maxy)
|
||||
{
|
||||
int src_width, dest_width;
|
||||
|
@ -692,7 +692,7 @@ static void pxa2xx_lcdc_dma0_redraw_horiz(PXA2xxLCDState *s,
|
|||
fn, s->dma_ch[0].palette, miny, maxy);
|
||||
}
|
||||
|
||||
static void pxa2xx_lcdc_dma0_redraw_vert(PXA2xxLCDState *s,
|
||||
static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
|
||||
target_phys_addr_t addr, int *miny, int *maxy)
|
||||
{
|
||||
int src_width, dest_width;
|
||||
|
@ -720,6 +720,67 @@ static void pxa2xx_lcdc_dma0_redraw_vert(PXA2xxLCDState *s,
|
|||
miny, maxy);
|
||||
}
|
||||
|
||||
static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
|
||||
target_phys_addr_t addr, int *miny, int *maxy)
|
||||
{
|
||||
int src_width, dest_width;
|
||||
drawfn fn = NULL;
|
||||
if (s->dest_width) {
|
||||
fn = s->line_fn[s->transp][s->bpp];
|
||||
}
|
||||
if (!fn) {
|
||||
return;
|
||||
}
|
||||
|
||||
src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
|
||||
if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
|
||||
src_width *= 3;
|
||||
} else if (s->bpp > pxa_lcdc_16bpp) {
|
||||
src_width *= 4;
|
||||
} else if (s->bpp > pxa_lcdc_8bpp) {
|
||||
src_width *= 2;
|
||||
}
|
||||
|
||||
dest_width = s->xres * s->dest_width;
|
||||
*miny = 0;
|
||||
framebuffer_update_display(s->ds,
|
||||
addr, s->xres, s->yres,
|
||||
src_width, -dest_width, -s->dest_width,
|
||||
s->invalidated,
|
||||
fn, s->dma_ch[0].palette, miny, maxy);
|
||||
}
|
||||
|
||||
static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
|
||||
target_phys_addr_t addr, int *miny, int *maxy)
|
||||
{
|
||||
int src_width, dest_width;
|
||||
drawfn fn = NULL;
|
||||
if (s->dest_width) {
|
||||
fn = s->line_fn[s->transp][s->bpp];
|
||||
}
|
||||
if (!fn) {
|
||||
return;
|
||||
}
|
||||
|
||||
src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
|
||||
if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
|
||||
src_width *= 3;
|
||||
} else if (s->bpp > pxa_lcdc_16bpp) {
|
||||
src_width *= 4;
|
||||
} else if (s->bpp > pxa_lcdc_8bpp) {
|
||||
src_width *= 2;
|
||||
}
|
||||
|
||||
dest_width = s->yres * s->dest_width;
|
||||
*miny = 0;
|
||||
framebuffer_update_display(s->ds,
|
||||
addr, s->xres, s->yres,
|
||||
src_width, -s->dest_width, dest_width,
|
||||
s->invalidated,
|
||||
fn, s->dma_ch[0].palette,
|
||||
miny, maxy);
|
||||
}
|
||||
|
||||
static void pxa2xx_lcdc_resize(PXA2xxLCDState *s)
|
||||
{
|
||||
int width, height;
|
||||
|
@ -730,10 +791,11 @@ static void pxa2xx_lcdc_resize(PXA2xxLCDState *s)
|
|||
height = LCCR2_LPP(s->control[2]) + 1;
|
||||
|
||||
if (width != s->xres || height != s->yres) {
|
||||
if (s->orientation)
|
||||
if (s->orientation == 90 || s->orientation == 270) {
|
||||
qemu_console_resize(s->ds, height, width);
|
||||
else
|
||||
} else {
|
||||
qemu_console_resize(s->ds, width, height);
|
||||
}
|
||||
s->invalidated = 1;
|
||||
s->xres = width;
|
||||
s->yres = height;
|
||||
|
@ -797,10 +859,24 @@ static void pxa2xx_update_display(void *opaque)
|
|||
}
|
||||
|
||||
if (miny >= 0) {
|
||||
if (s->orientation)
|
||||
dpy_update(s->ds, miny, 0, maxy - miny, s->xres);
|
||||
else
|
||||
dpy_update(s->ds, 0, miny, s->xres, maxy - miny);
|
||||
switch (s->orientation) {
|
||||
case 0:
|
||||
dpy_update(s->ds, 0, miny, s->xres, maxy - miny + 1);
|
||||
break;
|
||||
case 90:
|
||||
dpy_update(s->ds, miny, 0, maxy - miny + 1, s->xres);
|
||||
break;
|
||||
case 180:
|
||||
maxy = s->yres - maxy - 1;
|
||||
miny = s->yres - miny - 1;
|
||||
dpy_update(s->ds, 0, maxy, s->xres, miny - maxy + 1);
|
||||
break;
|
||||
case 270:
|
||||
maxy = s->yres - maxy - 1;
|
||||
miny = s->yres - miny - 1;
|
||||
dpy_update(s->ds, maxy, 0, miny - maxy + 1, s->xres);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pxa2xx_lcdc_int_update(s);
|
||||
|
||||
|
@ -822,10 +898,19 @@ static void pxa2xx_lcdc_orientation(void *opaque, int angle)
|
|||
{
|
||||
PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
|
||||
|
||||
if (angle) {
|
||||
s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_vert;
|
||||
} else {
|
||||
s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_horiz;
|
||||
switch (angle) {
|
||||
case 0:
|
||||
s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot0;
|
||||
break;
|
||||
case 90:
|
||||
s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot90;
|
||||
break;
|
||||
case 180:
|
||||
s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot180;
|
||||
break;
|
||||
case 270:
|
||||
s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot270;
|
||||
break;
|
||||
}
|
||||
|
||||
s->orientation = angle;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu-timer.h"
|
||||
#include "qxl.h"
|
||||
|
||||
static const char *qxl_type[] = {
|
||||
|
@ -223,7 +224,8 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
|
|||
if (!qxl->cmdlog) {
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "qxl-%d/%s:", qxl->id, ring);
|
||||
fprintf(stderr, "%ld qxl-%d/%s:", qemu_get_clock_ns(vm_clock),
|
||||
qxl->id, ring);
|
||||
fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
|
||||
qxl_name(qxl_type, ext->cmd.type),
|
||||
compat ? "(compat)" : "");
|
||||
|
|
54
hw/qxl.c
54
hw/qxl.c
|
@ -336,6 +336,21 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
|
|||
info->n_surfaces = NUM_SURFACES;
|
||||
}
|
||||
|
||||
static const char *qxl_mode_to_string(int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case QXL_MODE_COMPAT:
|
||||
return "compat";
|
||||
case QXL_MODE_NATIVE:
|
||||
return "native";
|
||||
case QXL_MODE_UNDEFINED:
|
||||
return "undefined";
|
||||
case QXL_MODE_VGA:
|
||||
return "vga";
|
||||
}
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
/* called from spice server thread context only */
|
||||
static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
|
||||
{
|
||||
|
@ -358,18 +373,19 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
|
|||
}
|
||||
qemu_mutex_unlock(&qxl->ssd.lock);
|
||||
if (ret) {
|
||||
dprint(qxl, 2, "%s %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode));
|
||||
qxl_log_command(qxl, "vga", ext);
|
||||
}
|
||||
return ret;
|
||||
case QXL_MODE_COMPAT:
|
||||
case QXL_MODE_NATIVE:
|
||||
case QXL_MODE_UNDEFINED:
|
||||
dprint(qxl, 2, "%s: %s\n", __FUNCTION__,
|
||||
qxl->cmdflags ? "compat" : "native");
|
||||
dprint(qxl, 4, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode));
|
||||
ring = &qxl->ram->cmd_ring;
|
||||
if (SPICE_RING_IS_EMPTY(ring)) {
|
||||
return false;
|
||||
}
|
||||
dprint(qxl, 2, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode));
|
||||
SPICE_RING_CONS_ITEM(ring, cmd);
|
||||
ext->cmd = *cmd;
|
||||
ext->group_id = MEMSLOT_GROUP_GUEST;
|
||||
|
@ -640,8 +656,8 @@ static void qxl_reset_state(PCIQXLDevice *d)
|
|||
QXLRam *ram = d->ram;
|
||||
QXLRom *rom = d->rom;
|
||||
|
||||
assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring));
|
||||
assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring));
|
||||
assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
|
||||
assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
|
||||
d->shadow_rom.update_id = cpu_to_le32(0);
|
||||
*rom = d->shadow_rom;
|
||||
qxl_rom_set_dirty(d);
|
||||
|
@ -926,6 +942,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||
case QXL_IO_MEMSLOT_ADD:
|
||||
case QXL_IO_MEMSLOT_DEL:
|
||||
case QXL_IO_CREATE_PRIMARY:
|
||||
case QXL_IO_UPDATE_IRQ:
|
||||
case QXL_IO_LOG:
|
||||
break;
|
||||
default:
|
||||
if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
|
||||
|
@ -969,7 +987,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||
break;
|
||||
case QXL_IO_LOG:
|
||||
if (d->guestdebug) {
|
||||
fprintf(stderr, "qxl/guest: %s", d->ram->log_buf);
|
||||
fprintf(stderr, "qxl/guest-%d: %ld: %s", d->id,
|
||||
qemu_get_clock_ns(vm_clock), d->ram->log_buf);
|
||||
}
|
||||
break;
|
||||
case QXL_IO_RESET:
|
||||
|
@ -993,7 +1012,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||
break;
|
||||
case QXL_IO_DESTROY_PRIMARY:
|
||||
PANIC_ON(val != 0);
|
||||
dprint(d, 1, "QXL_IO_DESTROY_PRIMARY\n");
|
||||
dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode));
|
||||
qxl_destroy_primary(d);
|
||||
break;
|
||||
case QXL_IO_DESTROY_SURFACE_WAIT:
|
||||
|
@ -1167,11 +1186,14 @@ static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
|
|||
qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason);
|
||||
|
||||
if (!running && qxl->mode == QXL_MODE_NATIVE) {
|
||||
/* dirty all vram (which holds surfaces) to make sure it is saved */
|
||||
/* dirty all vram (which holds surfaces) and devram (primary surface)
|
||||
* to make sure they are saved */
|
||||
/* FIXME #1: should go out during "live" stage */
|
||||
/* FIXME #2: we only need to save the areas which are actually used */
|
||||
ram_addr_t addr = qxl->vram_offset;
|
||||
qxl_set_dirty(addr, addr + qxl->vram_size);
|
||||
ram_addr_t vram_addr = qxl->vram_offset;
|
||||
ram_addr_t surface0_addr = qxl->vga.vram_offset + qxl->shadow_rom.draw_area_offset;
|
||||
qxl_set_dirty(vram_addr, vram_addr + qxl->vram_size);
|
||||
qxl_set_dirty(surface0_addr, surface0_addr + qxl->shadow_rom.surface0_area_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1207,7 +1229,6 @@ static DisplayChangeListener display_listener = {
|
|||
static int qxl_init_common(PCIQXLDevice *qxl)
|
||||
{
|
||||
uint8_t* config = qxl->pci.config;
|
||||
uint32_t pci_device_id;
|
||||
uint32_t pci_device_rev;
|
||||
uint32_t io_size;
|
||||
|
||||
|
@ -1218,20 +1239,14 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
|||
|
||||
switch (qxl->revision) {
|
||||
case 1: /* spice 0.4 -- qxl-1 */
|
||||
pci_device_id = QXL_DEVICE_ID_STABLE;
|
||||
pci_device_rev = QXL_REVISION_STABLE_V04;
|
||||
break;
|
||||
case 2: /* spice 0.6 -- qxl-2 */
|
||||
pci_device_id = QXL_DEVICE_ID_STABLE;
|
||||
default:
|
||||
pci_device_rev = QXL_REVISION_STABLE_V06;
|
||||
break;
|
||||
default: /* experimental */
|
||||
pci_device_id = QXL_DEVICE_ID_DEVEL;
|
||||
pci_device_rev = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
pci_config_set_device_id(config, pci_device_id);
|
||||
pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
|
||||
pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
|
||||
|
||||
|
@ -1375,7 +1390,8 @@ static int qxl_post_load(void *opaque, int version)
|
|||
|
||||
d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset);
|
||||
|
||||
dprint(d, 1, "%s: restore mode\n", __FUNCTION__);
|
||||
dprint(d, 1, "%s: restore mode (%s)\n", __FUNCTION__,
|
||||
qxl_mode_to_string(d->mode));
|
||||
newmode = d->mode;
|
||||
d->mode = QXL_MODE_UNDEFINED;
|
||||
switch (newmode) {
|
||||
|
@ -1492,6 +1508,7 @@ static PCIDeviceInfo qxl_info_primary = {
|
|||
.config_write = qxl_write_config,
|
||||
.romfile = "vgabios-qxl.bin",
|
||||
.vendor_id = REDHAT_PCI_VENDOR_ID,
|
||||
.device_id = QXL_DEVICE_ID_STABLE,
|
||||
.class_id = PCI_CLASS_DISPLAY_VGA,
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
|
||||
|
@ -1512,6 +1529,7 @@ static PCIDeviceInfo qxl_info_secondary = {
|
|||
.qdev.vmsd = &qxl_vmstate,
|
||||
.init = qxl_init_secondary,
|
||||
.vendor_id = REDHAT_PCI_VENDOR_ID,
|
||||
.device_id = QXL_DEVICE_ID_STABLE,
|
||||
.class_id = PCI_CLASS_DISPLAY_OTHER,
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
|
||||
|
|
|
@ -128,7 +128,8 @@ static int s390_virtio_blk_init(VirtIOS390Device *dev)
|
|||
{
|
||||
VirtIODevice *vdev;
|
||||
|
||||
vdev = virtio_blk_init((DeviceState *)dev, &dev->block);
|
||||
vdev = virtio_blk_init((DeviceState *)dev, &dev->block,
|
||||
&dev->block_serial);
|
||||
if (!vdev) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -165,7 +166,7 @@ static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
|
|||
(vq * VIRTIO_VQCONFIG_LEN) +
|
||||
VIRTIO_VQCONFIG_OFFS_TOKEN;
|
||||
|
||||
return ldq_phys(token_off);
|
||||
return ldq_be_phys(token_off);
|
||||
}
|
||||
|
||||
static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev)
|
||||
|
@ -219,8 +220,8 @@ void s390_virtio_device_sync(VirtIOS390Device *dev)
|
|||
vring = s390_virtio_next_ring(bus);
|
||||
virtio_queue_set_addr(dev->vdev, i, vring);
|
||||
virtio_queue_set_vector(dev->vdev, i, i);
|
||||
stq_phys(vq + VIRTIO_VQCONFIG_OFFS_ADDRESS, vring);
|
||||
stw_phys(vq + VIRTIO_VQCONFIG_OFFS_NUM, virtio_queue_get_num(dev->vdev, i));
|
||||
stq_be_phys(vq + VIRTIO_VQCONFIG_OFFS_ADDRESS, vring);
|
||||
stw_be_phys(vq + VIRTIO_VQCONFIG_OFFS_NUM, virtio_queue_get_num(dev->vdev, i));
|
||||
}
|
||||
|
||||
cur_offs = dev->dev_offs;
|
||||
|
@ -228,7 +229,7 @@ void s390_virtio_device_sync(VirtIOS390Device *dev)
|
|||
cur_offs += num_vq * VIRTIO_VQCONFIG_LEN;
|
||||
|
||||
/* Sync feature bitmap */
|
||||
stl_phys(cur_offs, bswap32(dev->host_features));
|
||||
stl_le_phys(cur_offs, dev->host_features);
|
||||
|
||||
dev->feat_offs = cur_offs + dev->feat_len;
|
||||
cur_offs += dev->feat_len * 2;
|
||||
|
@ -252,7 +253,7 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev)
|
|||
|
||||
/* Update guest supported feature bitmap */
|
||||
|
||||
features = bswap32(ldl_phys(dev->feat_offs));
|
||||
features = bswap32(ldl_be_phys(dev->feat_offs));
|
||||
if (vdev->set_features) {
|
||||
vdev->set_features(vdev, features);
|
||||
}
|
||||
|
@ -355,6 +356,7 @@ static VirtIOS390DeviceInfo s390_virtio_blk = {
|
|||
.qdev.size = sizeof(VirtIOS390Device),
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
|
||||
DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -42,6 +42,7 @@ typedef struct VirtIOS390Device {
|
|||
uint8_t feat_len;
|
||||
VirtIODevice *vdev;
|
||||
BlockConf block;
|
||||
char *block_serial;
|
||||
NICConf nic;
|
||||
uint32_t host_features;
|
||||
virtio_serial_conf serial;
|
||||
|
|
|
@ -193,7 +193,7 @@ static void s390_init(ram_addr_t my_ram_size,
|
|||
if (kernel_filename) {
|
||||
kernel_size = load_image(kernel_filename, qemu_get_ram_ptr(0));
|
||||
|
||||
if (lduw_phys(KERN_IMAGE_START) != 0x0dd0) {
|
||||
if (lduw_be_phys(KERN_IMAGE_START) != 0x0dd0) {
|
||||
fprintf(stderr, "Specified image is not an s390 boot image\n");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -232,8 +232,8 @@ static void s390_init(ram_addr_t my_ram_size,
|
|||
}
|
||||
initrd_size = load_image(initrd_filename, qemu_get_ram_ptr(initrd_offset));
|
||||
|
||||
stq_phys(INITRD_PARM_START, initrd_offset);
|
||||
stq_phys(INITRD_PARM_SIZE, initrd_size);
|
||||
stq_be_phys(INITRD_PARM_START, initrd_offset);
|
||||
stq_be_phys(INITRD_PARM_SIZE, initrd_size);
|
||||
}
|
||||
|
||||
if (kernel_cmdline) {
|
||||
|
|
|
@ -131,7 +131,8 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
|
|||
return res;
|
||||
}
|
||||
|
||||
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun)
|
||||
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag,
|
||||
uint32_t lun, void *hba_private)
|
||||
{
|
||||
SCSIRequest *req;
|
||||
|
||||
|
@ -141,14 +142,16 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l
|
|||
req->dev = d;
|
||||
req->tag = tag;
|
||||
req->lun = lun;
|
||||
req->hba_private = hba_private;
|
||||
req->status = -1;
|
||||
trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
|
||||
return req;
|
||||
}
|
||||
|
||||
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun)
|
||||
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
||||
void *hba_private)
|
||||
{
|
||||
return d->info->alloc_req(d, tag, lun);
|
||||
return d->info->alloc_req(d, tag, lun, hba_private);
|
||||
}
|
||||
|
||||
uint8_t *scsi_req_get_buf(SCSIRequest *req)
|
||||
|
|
|
@ -81,13 +81,13 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
|
|||
static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
|
||||
|
||||
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
|
||||
uint32_t lun)
|
||||
uint32_t lun, void *hba_private)
|
||||
{
|
||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
|
||||
SCSIRequest *req;
|
||||
SCSIDiskReq *r;
|
||||
|
||||
req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun);
|
||||
req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun, hba_private);
|
||||
r = DO_UPCAST(SCSIDiskReq, req, req);
|
||||
r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
|
||||
return req;
|
||||
|
@ -398,7 +398,8 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||
"buffer size %zd\n", req->cmd.xfer);
|
||||
pages = buflen++;
|
||||
outbuf[buflen++] = 0x00; // list of supported pages (this page)
|
||||
outbuf[buflen++] = 0x80; // unit serial number
|
||||
if (s->serial)
|
||||
outbuf[buflen++] = 0x80; // unit serial number
|
||||
outbuf[buflen++] = 0x83; // device identification
|
||||
if (s->drive_kind == SCSI_HD) {
|
||||
outbuf[buflen++] = 0xb0; // block limits
|
||||
|
@ -409,8 +410,14 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
|||
}
|
||||
case 0x80: /* Device serial number, optional */
|
||||
{
|
||||
int l = strlen(s->serial);
|
||||
int l;
|
||||
|
||||
if (!s->serial) {
|
||||
DPRINTF("Inquiry (EVPD[Serial number] not supported\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
l = strlen(s->serial);
|
||||
if (l > req->cmd.xfer)
|
||||
l = req->cmd.xfer;
|
||||
if (l > 20)
|
||||
|
@ -1007,7 +1014,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
|||
|
||||
command = buf[0];
|
||||
outbuf = (uint8_t *)r->iov.iov_base;
|
||||
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
|
||||
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);
|
||||
|
||||
if (scsi_req_parse(&r->req, buf) != 0) {
|
||||
BADF("Unsupported command length, command %x\n", command);
|
||||
|
@ -1203,7 +1210,9 @@ static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
|
|||
if (!s->serial) {
|
||||
/* try to fall back to value set with legacy -drive serial=... */
|
||||
dinfo = drive_get_by_blockdev(s->bs);
|
||||
s->serial = qemu_strdup(*dinfo->serial ? dinfo->serial : "0");
|
||||
if (*dinfo->serial) {
|
||||
s->serial = qemu_strdup(dinfo->serial);
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->version) {
|
||||
|
|
|
@ -96,11 +96,12 @@ static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len)
|
|||
return size;
|
||||
}
|
||||
|
||||
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
|
||||
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
||||
void *hba_private)
|
||||
{
|
||||
SCSIRequest *req;
|
||||
|
||||
req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun);
|
||||
req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun, hba_private);
|
||||
return req;
|
||||
}
|
||||
|
||||
|
|
10
hw/scsi.h
10
hw/scsi.h
|
@ -43,6 +43,7 @@ struct SCSIRequest {
|
|||
} cmd;
|
||||
BlockDriverAIOCB *aiocb;
|
||||
bool enqueued;
|
||||
void *hba_private;
|
||||
QTAILQ_ENTRY(SCSIRequest) next;
|
||||
};
|
||||
|
||||
|
@ -67,7 +68,8 @@ struct SCSIDeviceInfo {
|
|||
DeviceInfo qdev;
|
||||
scsi_qdev_initfn init;
|
||||
void (*destroy)(SCSIDevice *s);
|
||||
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun);
|
||||
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
|
||||
void *hba_private);
|
||||
void (*free_req)(SCSIRequest *req);
|
||||
int32_t (*send_command)(SCSIRequest *req, uint8_t *buf);
|
||||
void (*read_data)(SCSIRequest *req);
|
||||
|
@ -138,8 +140,10 @@ extern const struct SCSISense sense_code_LUN_FAILURE;
|
|||
int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed);
|
||||
int scsi_sense_valid(SCSISense sense);
|
||||
|
||||
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun);
|
||||
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun);
|
||||
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag,
|
||||
uint32_t lun, void *hba_private);
|
||||
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
|
||||
void *hba_private);
|
||||
int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf);
|
||||
void scsi_req_free(SCSIRequest *req);
|
||||
SCSIRequest *scsi_req_ref(SCSIRequest *req);
|
||||
|
|
|
@ -280,12 +280,12 @@ target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
|
|||
|
||||
static inline uint32_t rtas_ld(target_ulong phys, int n)
|
||||
{
|
||||
return ldl_phys(phys + 4*n);
|
||||
return ldl_be_phys(phys + 4*n);
|
||||
}
|
||||
|
||||
static inline void rtas_st(target_ulong phys, int n, uint32_t val)
|
||||
{
|
||||
stl_phys(phys + 4*n, val);
|
||||
stl_be_phys(phys + 4*n, val);
|
||||
}
|
||||
|
||||
typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token,
|
||||
|
|
|
@ -278,7 +278,7 @@ static target_ulong register_vpa(CPUState *env, target_ulong vpa)
|
|||
}
|
||||
/* FIXME: bounds check the address */
|
||||
|
||||
size = lduw_phys(vpa + 0x4);
|
||||
size = lduw_be_phys(vpa + 0x4);
|
||||
|
||||
if (size < VPA_MIN_SIZE) {
|
||||
return H_PARAMETER;
|
||||
|
@ -321,7 +321,7 @@ static target_ulong register_slb_shadow(CPUState *env, target_ulong addr)
|
|||
return H_HARDWARE;
|
||||
}
|
||||
|
||||
size = ldl_phys(addr + 0x4);
|
||||
size = ldl_be_phys(addr + 0x4);
|
||||
if (size < 0x8) {
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
@ -354,7 +354,7 @@ static target_ulong register_dtl(CPUState *env, target_ulong addr)
|
|||
return H_HARDWARE;
|
||||
}
|
||||
|
||||
size = ldl_phys(addr + 0x4);
|
||||
size = ldl_be_phys(addr + 0x4);
|
||||
|
||||
if (size < 48) {
|
||||
return H_PARAMETER;
|
||||
|
@ -441,9 +441,9 @@ static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr,
|
|||
target_ulong opcode, target_ulong *args)
|
||||
{
|
||||
target_ulong rtas_r3 = args[0];
|
||||
uint32_t token = ldl_phys(rtas_r3);
|
||||
uint32_t nargs = ldl_phys(rtas_r3 + 4);
|
||||
uint32_t nret = ldl_phys(rtas_r3 + 8);
|
||||
uint32_t token = ldl_be_phys(rtas_r3);
|
||||
uint32_t nargs = ldl_be_phys(rtas_r3 + 4);
|
||||
uint32_t nret = ldl_be_phys(rtas_r3 + 8);
|
||||
|
||||
return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12,
|
||||
nret, rtas_r3 + 12 + 4*nargs);
|
||||
|
|
|
@ -121,7 +121,7 @@ static struct vscsi_req *vscsi_get_req(VSCSIState *s)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void vscsi_put_req(VSCSIState *s, vscsi_req *req)
|
||||
static void vscsi_put_req(vscsi_req *req)
|
||||
{
|
||||
if (req->sreq != NULL) {
|
||||
scsi_req_unref(req->sreq);
|
||||
|
@ -130,15 +130,6 @@ static void vscsi_put_req(VSCSIState *s, vscsi_req *req)
|
|||
req->active = 0;
|
||||
}
|
||||
|
||||
static vscsi_req *vscsi_find_req(VSCSIState *s, SCSIRequest *req)
|
||||
{
|
||||
uint32_t tag = req->tag;
|
||||
if (tag >= VSCSI_REQ_LIMIT || !s->reqs[tag].active) {
|
||||
return NULL;
|
||||
}
|
||||
return &s->reqs[tag];
|
||||
}
|
||||
|
||||
static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun)
|
||||
{
|
||||
/* XXX Figure that one out properly ! This is crackpot */
|
||||
|
@ -454,7 +445,7 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
|
|||
if (n) {
|
||||
req->senselen = n;
|
||||
vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
|
||||
vscsi_put_req(s, req);
|
||||
vscsi_put_req(req);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -483,7 +474,7 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
|
|||
static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
|
||||
{
|
||||
VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
|
||||
vscsi_req *req = vscsi_find_req(s, sreq);
|
||||
vscsi_req *req = sreq->hba_private;
|
||||
uint8_t *buf;
|
||||
int rc = 0;
|
||||
|
||||
|
@ -531,7 +522,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
|
|||
static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status)
|
||||
{
|
||||
VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
|
||||
vscsi_req *req = vscsi_find_req(s, sreq);
|
||||
vscsi_req *req = sreq->hba_private;
|
||||
int32_t res_in = 0, res_out = 0;
|
||||
|
||||
dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n",
|
||||
|
@ -563,15 +554,14 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status)
|
|||
}
|
||||
}
|
||||
vscsi_send_rsp(s, req, 0, res_in, res_out);
|
||||
vscsi_put_req(s, req);
|
||||
vscsi_put_req(req);
|
||||
}
|
||||
|
||||
static void vscsi_request_cancelled(SCSIRequest *sreq)
|
||||
{
|
||||
VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
|
||||
vscsi_req *req = vscsi_find_req(s, sreq);
|
||||
vscsi_req *req = sreq->hba_private;
|
||||
|
||||
vscsi_put_req(s, req);
|
||||
vscsi_put_req(req);
|
||||
}
|
||||
|
||||
static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
|
||||
|
@ -659,7 +649,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
|
|||
}
|
||||
|
||||
req->lun = lun;
|
||||
req->sreq = scsi_req_new(sdev, req->qtag, lun);
|
||||
req->sreq = scsi_req_new(sdev, req->qtag, lun, req);
|
||||
n = scsi_req_enqueue(req->sreq, srp->cmd.cdb);
|
||||
|
||||
dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n",
|
||||
|
@ -858,7 +848,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
|
|||
}
|
||||
|
||||
if (done) {
|
||||
vscsi_put_req(s, req);
|
||||
vscsi_put_req(req);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
24
hw/usb-bt.c
24
hw/usb-bt.c
|
@ -99,13 +99,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
|
|||
.eps = (USBDescEndpoint[]) {
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = 0,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = 0,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
|
@ -120,13 +120,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
|
|||
.eps = (USBDescEndpoint[]) {
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = 0x09,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = 0x09,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
|
@ -141,13 +141,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
|
|||
.eps = (USBDescEndpoint[]) {
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = 0x11,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = 0x11,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
|
@ -162,13 +162,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
|
|||
.eps = (USBDescEndpoint[]) {
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = 0x19,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = 0x19,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
|
@ -183,13 +183,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
|
|||
.eps = (USBDescEndpoint[]) {
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = 0x21,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = 0x21,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
|
@ -204,13 +204,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
|
|||
.eps = (USBDescEndpoint[]) {
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = 0x31,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
{
|
||||
.bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
|
||||
.wMaxPacketSize = 0x31,
|
||||
.bInterval = 0x01,
|
||||
},
|
||||
|
|
46
hw/usb-bus.c
46
hw/usb-bus.c
|
@ -82,12 +82,10 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
|
|||
static int usb_qdev_exit(DeviceState *qdev)
|
||||
{
|
||||
USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
|
||||
USBBus *bus = usb_bus_from_device(dev);
|
||||
|
||||
if (dev->attached) {
|
||||
usb_device_detach(dev);
|
||||
}
|
||||
bus->ops->device_destroy(bus, dev);
|
||||
if (dev->info->handle_destroy) {
|
||||
dev->info->handle_destroy(dev);
|
||||
}
|
||||
|
@ -140,19 +138,55 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name)
|
|||
return dev;
|
||||
}
|
||||
|
||||
void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
|
||||
USBPortOps *ops, int speedmask)
|
||||
static void usb_fill_port(USBPort *port, void *opaque, int index,
|
||||
USBPortOps *ops, int speedmask)
|
||||
{
|
||||
port->opaque = opaque;
|
||||
port->index = index;
|
||||
port->opaque = opaque;
|
||||
port->index = index;
|
||||
port->ops = ops;
|
||||
port->speedmask = speedmask;
|
||||
usb_port_location(port, NULL, index + 1);
|
||||
}
|
||||
|
||||
void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
|
||||
USBPortOps *ops, int speedmask)
|
||||
{
|
||||
usb_fill_port(port, opaque, index, ops, speedmask);
|
||||
QTAILQ_INSERT_TAIL(&bus->free, port, next);
|
||||
bus->nfree++;
|
||||
}
|
||||
|
||||
int usb_register_companion(const char *masterbus, USBPort *ports[],
|
||||
uint32_t portcount, uint32_t firstport,
|
||||
void *opaque, USBPortOps *ops, int speedmask)
|
||||
{
|
||||
USBBus *bus;
|
||||
int i;
|
||||
|
||||
QTAILQ_FOREACH(bus, &busses, next) {
|
||||
if (strcmp(bus->qbus.name, masterbus) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bus || !bus->ops->register_companion) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
|
||||
"an USB masterbus");
|
||||
if (bus) {
|
||||
error_printf_unless_qmp(
|
||||
"USB bus '%s' does not allow companion controllers\n",
|
||||
masterbus);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < portcount; i++) {
|
||||
usb_fill_port(ports[i], opaque, i, ops, speedmask);
|
||||
}
|
||||
|
||||
return bus->ops->register_companion(bus, ports, portcount, firstport);
|
||||
}
|
||||
|
||||
void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
|
||||
{
|
||||
if (upstream) {
|
||||
|
|
270
hw/usb-ehci.c
270
hw/usb-ehci.c
|
@ -20,9 +20,6 @@
|
|||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* TODO:
|
||||
* o Downstream port handoff
|
||||
*/
|
||||
|
||||
#include "hw.h"
|
||||
|
@ -103,10 +100,10 @@
|
|||
#define PORTSC_BEGIN PORTSC
|
||||
#define PORTSC_END (PORTSC + 4 * NB_PORTS)
|
||||
/*
|
||||
* Bits that are reserverd or are read-only are masked out of values
|
||||
* Bits that are reserved or are read-only are masked out of values
|
||||
* written to us by software
|
||||
*/
|
||||
#define PORTSC_RO_MASK 0x007021c5
|
||||
#define PORTSC_RO_MASK 0x007001c0
|
||||
#define PORTSC_RWC_MASK 0x0000002a
|
||||
#define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable
|
||||
#define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable
|
||||
|
@ -133,7 +130,7 @@
|
|||
#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
|
||||
|
||||
#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
|
||||
#define NB_PORTS 4 // Number of downstream ports
|
||||
#define NB_PORTS 6 // Number of downstream ports
|
||||
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
|
||||
#define MAX_ITERATIONS 20 // Max number of QH before we break the loop
|
||||
#define MAX_QH 100 // Max allowable queue heads in a chain
|
||||
|
@ -373,7 +370,7 @@ struct EHCIState {
|
|||
qemu_irq irq;
|
||||
target_phys_addr_t mem_base;
|
||||
int mem;
|
||||
int num_ports;
|
||||
int companion_count;
|
||||
|
||||
/* properties */
|
||||
uint32_t freq;
|
||||
|
@ -409,6 +406,7 @@ struct EHCIState {
|
|||
int astate; // Current state in asynchronous schedule
|
||||
int pstate; // Current state in periodic schedule
|
||||
USBPort ports[NB_PORTS];
|
||||
USBPort *companion_ports[NB_PORTS];
|
||||
uint32_t usbsts_pending;
|
||||
QTAILQ_HEAD(, EHCIQueue) queues;
|
||||
|
||||
|
@ -731,17 +729,17 @@ static void ehci_attach(USBPort *port)
|
|||
|
||||
trace_usb_ehci_port_attach(port->index, port->dev->product_desc);
|
||||
|
||||
if (*portsc & PORTSC_POWNER) {
|
||||
USBPort *companion = s->companion_ports[port->index];
|
||||
companion->dev = port->dev;
|
||||
companion->ops->attach(companion);
|
||||
return;
|
||||
}
|
||||
|
||||
*portsc |= PORTSC_CONNECT;
|
||||
*portsc |= PORTSC_CSC;
|
||||
|
||||
/*
|
||||
* If a high speed device is attached then we own this port(indicated
|
||||
* by zero in the PORTSC_POWNER bit field) so set the status bit
|
||||
* and set an interrupt if enabled.
|
||||
*/
|
||||
if ( !(*portsc & PORTSC_POWNER)) {
|
||||
ehci_set_interrupt(s, USBSTS_PCD);
|
||||
}
|
||||
ehci_set_interrupt(s, USBSTS_PCD);
|
||||
}
|
||||
|
||||
static void ehci_detach(USBPort *port)
|
||||
|
@ -751,17 +749,88 @@ static void ehci_detach(USBPort *port)
|
|||
|
||||
trace_usb_ehci_port_detach(port->index);
|
||||
|
||||
*portsc &= ~PORTSC_CONNECT;
|
||||
if (*portsc & PORTSC_POWNER) {
|
||||
USBPort *companion = s->companion_ports[port->index];
|
||||
companion->ops->detach(companion);
|
||||
companion->dev = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
ehci_queues_rip_device(s, port->dev);
|
||||
|
||||
*portsc &= ~(PORTSC_CONNECT|PORTSC_PED);
|
||||
*portsc |= PORTSC_CSC;
|
||||
|
||||
/*
|
||||
* If a high speed device is attached then we own this port(indicated
|
||||
* by zero in the PORTSC_POWNER bit field) so set the status bit
|
||||
* and set an interrupt if enabled.
|
||||
*/
|
||||
if ( !(*portsc & PORTSC_POWNER)) {
|
||||
ehci_set_interrupt(s, USBSTS_PCD);
|
||||
ehci_set_interrupt(s, USBSTS_PCD);
|
||||
}
|
||||
|
||||
static void ehci_child_detach(USBPort *port, USBDevice *child)
|
||||
{
|
||||
EHCIState *s = port->opaque;
|
||||
uint32_t portsc = s->portsc[port->index];
|
||||
|
||||
if (portsc & PORTSC_POWNER) {
|
||||
USBPort *companion = s->companion_ports[port->index];
|
||||
companion->ops->child_detach(companion, child);
|
||||
companion->dev = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
ehci_queues_rip_device(s, child);
|
||||
}
|
||||
|
||||
static void ehci_wakeup(USBPort *port)
|
||||
{
|
||||
EHCIState *s = port->opaque;
|
||||
uint32_t portsc = s->portsc[port->index];
|
||||
|
||||
if (portsc & PORTSC_POWNER) {
|
||||
USBPort *companion = s->companion_ports[port->index];
|
||||
if (companion->ops->wakeup) {
|
||||
companion->ops->wakeup(companion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ehci_register_companion(USBBus *bus, USBPort *ports[],
|
||||
uint32_t portcount, uint32_t firstport)
|
||||
{
|
||||
EHCIState *s = container_of(bus, EHCIState, bus);
|
||||
uint32_t i;
|
||||
|
||||
if (firstport + portcount > NB_PORTS) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_VALUE, "firstport",
|
||||
"firstport on masterbus");
|
||||
error_printf_unless_qmp(
|
||||
"firstport value of %u makes companion take ports %u - %u, which "
|
||||
"is outside of the valid range of 0 - %u\n", firstport, firstport,
|
||||
firstport + portcount - 1, NB_PORTS - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < portcount; i++) {
|
||||
if (s->companion_ports[firstport + i]) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
|
||||
"an USB masterbus");
|
||||
error_printf_unless_qmp(
|
||||
"port %u on masterbus %s already has a companion assigned\n",
|
||||
firstport + i, bus->qbus.name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < portcount; i++) {
|
||||
s->companion_ports[firstport + i] = ports[i];
|
||||
s->ports[firstport + i].speedmask |=
|
||||
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL;
|
||||
/* Ensure devs attached before the initial reset go to the companion */
|
||||
s->portsc[firstport + i] = PORTSC_POWNER;
|
||||
}
|
||||
|
||||
s->companion_count++;
|
||||
s->mmio[0x05] = (s->companion_count << 4) | portcount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 4.1 host controller initialization */
|
||||
|
@ -769,9 +838,21 @@ static void ehci_reset(void *opaque)
|
|||
{
|
||||
EHCIState *s = opaque;
|
||||
int i;
|
||||
USBDevice *devs[NB_PORTS];
|
||||
|
||||
trace_usb_ehci_reset();
|
||||
|
||||
/*
|
||||
* Do the detach before touching portsc, so that it correctly gets send to
|
||||
* us or to our companion based on PORTSC_POWNER before the reset.
|
||||
*/
|
||||
for(i = 0; i < NB_PORTS; i++) {
|
||||
devs[i] = s->ports[i].dev;
|
||||
if (devs[i]) {
|
||||
usb_attach(&s->ports[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
|
||||
|
||||
s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
|
||||
|
@ -783,10 +864,13 @@ static void ehci_reset(void *opaque)
|
|||
s->attach_poll_counter = 0;
|
||||
|
||||
for(i = 0; i < NB_PORTS; i++) {
|
||||
s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
|
||||
|
||||
if (s->ports[i].dev) {
|
||||
usb_attach(&s->ports[i], s->ports[i].dev);
|
||||
if (s->companion_ports[i]) {
|
||||
s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
|
||||
} else {
|
||||
s->portsc[i] = PORTSC_PPOWER;
|
||||
}
|
||||
if (devs[i]) {
|
||||
usb_attach(&s->ports[i], devs[i]);
|
||||
}
|
||||
}
|
||||
ehci_queues_rip_all(s);
|
||||
|
@ -836,43 +920,67 @@ static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
|
||||
{
|
||||
USBDevice *dev = s->ports[port].dev;
|
||||
uint32_t *portsc = &s->portsc[port];
|
||||
uint32_t orig;
|
||||
|
||||
if (s->companion_ports[port] == NULL)
|
||||
return;
|
||||
|
||||
owner = owner & PORTSC_POWNER;
|
||||
orig = *portsc & PORTSC_POWNER;
|
||||
|
||||
if (!(owner ^ orig)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev) {
|
||||
usb_attach(&s->ports[port], NULL);
|
||||
}
|
||||
|
||||
*portsc &= ~PORTSC_POWNER;
|
||||
*portsc |= owner;
|
||||
|
||||
if (dev) {
|
||||
usb_attach(&s->ports[port], dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
|
||||
{
|
||||
uint32_t *portsc = &s->portsc[port];
|
||||
int rwc;
|
||||
USBDevice *dev = s->ports[port].dev;
|
||||
|
||||
rwc = val & PORTSC_RWC_MASK;
|
||||
/* Clear rwc bits */
|
||||
*portsc &= ~(val & PORTSC_RWC_MASK);
|
||||
/* The guest may clear, but not set the PED bit */
|
||||
*portsc &= val | ~PORTSC_PED;
|
||||
/* POWNER is masked out by RO_MASK as it is RO when we've no companion */
|
||||
handle_port_owner_write(s, port, val);
|
||||
/* And finally apply RO_MASK */
|
||||
val &= PORTSC_RO_MASK;
|
||||
|
||||
// handle_read_write_clear(&val, portsc, PORTSC_PEDC | PORTSC_CSC);
|
||||
|
||||
*portsc &= ~rwc;
|
||||
|
||||
if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) {
|
||||
trace_usb_ehci_port_reset(port, 1);
|
||||
}
|
||||
|
||||
if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
|
||||
trace_usb_ehci_port_reset(port, 0);
|
||||
usb_attach(&s->ports[port], dev);
|
||||
|
||||
// TODO how to handle reset of ports with no device
|
||||
if (dev) {
|
||||
usb_attach(&s->ports[port], dev);
|
||||
usb_send_msg(dev, USB_MSG_RESET);
|
||||
}
|
||||
|
||||
if (s->ports[port].dev) {
|
||||
*portsc &= ~PORTSC_CSC;
|
||||
}
|
||||
|
||||
/* Table 2.16 Set the enable bit(and enable bit change) to indicate
|
||||
/*
|
||||
* Table 2.16 Set the enable bit(and enable bit change) to indicate
|
||||
* to SW that this port has a high speed device attached
|
||||
*
|
||||
* TODO - when to disable?
|
||||
*/
|
||||
val |= PORTSC_PED;
|
||||
val |= PORTSC_PEDC;
|
||||
if (dev && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
|
||||
val |= PORTSC_PED;
|
||||
}
|
||||
}
|
||||
|
||||
*portsc &= ~PORTSC_RO_MASK;
|
||||
|
@ -955,7 +1063,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
|
|||
val &= 0x1;
|
||||
if (val) {
|
||||
for(i = 0; i < NB_PORTS; i++)
|
||||
s->portsc[i] &= ~PORTSC_POWNER;
|
||||
handle_port_owner_write(s, i, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1111,10 +1219,19 @@ static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ehci_async_complete_packet(USBDevice *dev, USBPacket *packet)
|
||||
static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
|
||||
{
|
||||
EHCIQueue *q = container_of(packet, EHCIQueue, packet);
|
||||
EHCIQueue *q;
|
||||
EHCIState *s = port->opaque;
|
||||
uint32_t portsc = s->portsc[port->index];
|
||||
|
||||
if (portsc & PORTSC_POWNER) {
|
||||
USBPort *companion = s->companion_ports[port->index];
|
||||
companion->ops->complete(companion, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
q = container_of(packet, EHCIQueue, packet);
|
||||
trace_usb_ehci_queue_action(q, "wakeup");
|
||||
assert(q->async == EHCI_ASYNC_INFLIGHT);
|
||||
q->async = EHCI_ASYNC_FINISHED;
|
||||
|
@ -1244,8 +1361,6 @@ static int ehci_execute(EHCIQueue *q)
|
|||
port = &q->ehci->ports[i];
|
||||
dev = port->dev;
|
||||
|
||||
// TODO sometime we will also need to check if we are the port owner
|
||||
|
||||
if (!(q->ehci->portsc[i] &(PORTSC_CONNECT))) {
|
||||
DPRINTF("Port %d, no exec, not connected(%08X)\n",
|
||||
i, q->ehci->portsc[i]);
|
||||
|
@ -1338,8 +1453,6 @@ static int ehci_process_itd(EHCIState *ehci,
|
|||
port = &ehci->ports[j];
|
||||
dev = port->dev;
|
||||
|
||||
// TODO sometime we will also need to check if we are the port owner
|
||||
|
||||
if (!(ehci->portsc[j] &(PORTSC_CONNECT))) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2117,38 +2230,48 @@ static void ehci_map(PCIDevice *pci_dev, int region_num,
|
|||
cpu_register_physical_memory(addr, size, s->mem);
|
||||
}
|
||||
|
||||
static void ehci_device_destroy(USBBus *bus, USBDevice *dev)
|
||||
{
|
||||
EHCIState *s = container_of(bus, EHCIState, bus);
|
||||
|
||||
ehci_queues_rip_device(s, dev);
|
||||
}
|
||||
|
||||
static int usb_ehci_initfn(PCIDevice *dev);
|
||||
|
||||
static USBPortOps ehci_port_ops = {
|
||||
.attach = ehci_attach,
|
||||
.detach = ehci_detach,
|
||||
.child_detach = ehci_child_detach,
|
||||
.wakeup = ehci_wakeup,
|
||||
.complete = ehci_async_complete_packet,
|
||||
};
|
||||
|
||||
static USBBusOps ehci_bus_ops = {
|
||||
.device_destroy = ehci_device_destroy,
|
||||
.register_companion = ehci_register_companion,
|
||||
};
|
||||
|
||||
static PCIDeviceInfo ehci_info = {
|
||||
.qdev.name = "usb-ehci",
|
||||
.qdev.size = sizeof(EHCIState),
|
||||
.init = usb_ehci_initfn,
|
||||
.vendor_id = PCI_VENDOR_ID_INTEL,
|
||||
.device_id = PCI_DEVICE_ID_INTEL_82801D,
|
||||
.revision = 0x10,
|
||||
.class_id = PCI_CLASS_SERIAL_USB,
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_UINT32("freq", EHCIState, freq, FRAME_TIMER_FREQ),
|
||||
DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
},
|
||||
static Property ehci_properties[] = {
|
||||
DEFINE_PROP_UINT32("freq", EHCIState, freq, FRAME_TIMER_FREQ),
|
||||
DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static PCIDeviceInfo ehci_info[] = {
|
||||
{
|
||||
.qdev.name = "usb-ehci",
|
||||
.qdev.size = sizeof(EHCIState),
|
||||
.init = usb_ehci_initfn,
|
||||
.vendor_id = PCI_VENDOR_ID_INTEL,
|
||||
.device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */
|
||||
.revision = 0x10,
|
||||
.class_id = PCI_CLASS_SERIAL_USB,
|
||||
.qdev.props = ehci_properties,
|
||||
},{
|
||||
.qdev.name = "ich9-usb-ehci1",
|
||||
.qdev.size = sizeof(EHCIState),
|
||||
.init = usb_ehci_initfn,
|
||||
.vendor_id = PCI_VENDOR_ID_INTEL,
|
||||
.device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1,
|
||||
.revision = 0x03,
|
||||
.class_id = PCI_CLASS_SERIAL_USB,
|
||||
.qdev.props = ehci_properties,
|
||||
},{
|
||||
/* end of list */
|
||||
}
|
||||
};
|
||||
|
||||
static int usb_ehci_initfn(PCIDevice *dev)
|
||||
|
@ -2206,7 +2329,6 @@ static int usb_ehci_initfn(PCIDevice *dev)
|
|||
for(i = 0; i < NB_PORTS; i++) {
|
||||
usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
|
||||
USB_SPEED_MASK_HIGH);
|
||||
usb_port_location(&s->ports[i], NULL, i+1);
|
||||
s->ports[i].dev = 0;
|
||||
}
|
||||
|
||||
|
@ -2228,7 +2350,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
|
|||
|
||||
static void ehci_register(void)
|
||||
{
|
||||
pci_qdev_register(&ehci_info);
|
||||
pci_qdev_register_many(ehci_info);
|
||||
}
|
||||
device_init(ehci_register);
|
||||
|
||||
|
|
|
@ -531,18 +531,15 @@ static void usb_keyboard_process_keycode(USBHIDState *hs)
|
|||
case 0xe0:
|
||||
if (s->modifiers & (1 << 9)) {
|
||||
s->modifiers ^= 3 << 8;
|
||||
usb_hid_changed(hs);
|
||||
return;
|
||||
}
|
||||
case 0xe1 ... 0xe7:
|
||||
if (keycode & (1 << 7)) {
|
||||
s->modifiers &= ~(1 << (hid_code & 0x0f));
|
||||
usb_hid_changed(hs);
|
||||
return;
|
||||
}
|
||||
case 0xe8 ... 0xef:
|
||||
s->modifiers |= 1 << (hid_code & 0x0f);
|
||||
usb_hid_changed(hs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -769,10 +766,12 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
|
|||
}
|
||||
break;
|
||||
case GET_REPORT:
|
||||
if (s->kind == USB_MOUSE || s->kind == USB_TABLET)
|
||||
if (s->kind == USB_MOUSE || s->kind == USB_TABLET) {
|
||||
ret = usb_pointer_poll(s, data, length);
|
||||
else if (s->kind == USB_KEYBOARD)
|
||||
} else if (s->kind == USB_KEYBOARD) {
|
||||
ret = usb_keyboard_poll(s, data, length);
|
||||
}
|
||||
s->changed = s->n > 0;
|
||||
break;
|
||||
case SET_REPORT:
|
||||
if (s->kind == USB_KEYBOARD)
|
||||
|
|
90
hw/usb-hub.c
90
hw/usb-hub.c
|
@ -138,74 +138,6 @@ static const USBDesc desc_hub = {
|
|||
.str = desc_strings,
|
||||
};
|
||||
|
||||
static const uint8_t qemu_hub_dev_descriptor[] = {
|
||||
0x12, /* u8 bLength; */
|
||||
0x01, /* u8 bDescriptorType; Device */
|
||||
0x10, 0x01, /* u16 bcdUSB; v1.1 */
|
||||
|
||||
0x09, /* u8 bDeviceClass; HUB_CLASSCODE */
|
||||
0x00, /* u8 bDeviceSubClass; */
|
||||
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
|
||||
0x08, /* u8 bMaxPacketSize0; 8 Bytes */
|
||||
|
||||
0x00, 0x00, /* u16 idVendor; */
|
||||
0x00, 0x00, /* u16 idProduct; */
|
||||
0x01, 0x01, /* u16 bcdDevice */
|
||||
|
||||
0x03, /* u8 iManufacturer; */
|
||||
0x02, /* u8 iProduct; */
|
||||
0x01, /* u8 iSerialNumber; */
|
||||
0x01 /* u8 bNumConfigurations; */
|
||||
};
|
||||
|
||||
/* XXX: patch interrupt size */
|
||||
static const uint8_t qemu_hub_config_descriptor[] = {
|
||||
|
||||
/* one configuration */
|
||||
0x09, /* u8 bLength; */
|
||||
0x02, /* u8 bDescriptorType; Configuration */
|
||||
0x19, 0x00, /* u16 wTotalLength; */
|
||||
0x01, /* u8 bNumInterfaces; (1) */
|
||||
0x01, /* u8 bConfigurationValue; */
|
||||
0x00, /* u8 iConfiguration; */
|
||||
0xe0, /* u8 bmAttributes;
|
||||
Bit 7: must be set,
|
||||
6: Self-powered,
|
||||
5: Remote wakeup,
|
||||
4..0: resvd */
|
||||
0x00, /* u8 MaxPower; */
|
||||
|
||||
/* USB 1.1:
|
||||
* USB 2.0, single TT organization (mandatory):
|
||||
* one interface, protocol 0
|
||||
*
|
||||
* USB 2.0, multiple TT organization (optional):
|
||||
* two interfaces, protocols 1 (like single TT)
|
||||
* and 2 (multiple TT mode) ... config is
|
||||
* sometimes settable
|
||||
* NOT IMPLEMENTED
|
||||
*/
|
||||
|
||||
/* one interface */
|
||||
0x09, /* u8 if_bLength; */
|
||||
0x04, /* u8 if_bDescriptorType; Interface */
|
||||
0x00, /* u8 if_bInterfaceNumber; */
|
||||
0x00, /* u8 if_bAlternateSetting; */
|
||||
0x01, /* u8 if_bNumEndpoints; */
|
||||
0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */
|
||||
0x00, /* u8 if_bInterfaceSubClass; */
|
||||
0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
|
||||
0x00, /* u8 if_iInterface; */
|
||||
|
||||
/* one endpoint (status change endpoint) */
|
||||
0x07, /* u8 ep_bLength; */
|
||||
0x05, /* u8 ep_bDescriptorType; Endpoint */
|
||||
0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
|
||||
0x03, /* u8 ep_bmAttributes; Interrupt */
|
||||
0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
|
||||
0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
|
||||
};
|
||||
|
||||
static const uint8_t qemu_hub_hub_descriptor[] =
|
||||
{
|
||||
0x00, /* u8 bLength; patched in later */
|
||||
|
@ -238,6 +170,9 @@ static void usb_hub_detach(USBPort *port1)
|
|||
USBHubState *s = port1->opaque;
|
||||
USBHubPort *port = &s->ports[port1->index];
|
||||
|
||||
/* Let upstream know the device on this port is gone */
|
||||
s->dev.port->ops->child_detach(s->dev.port, port1->dev);
|
||||
|
||||
port->wPortStatus &= ~PORT_STAT_CONNECTION;
|
||||
port->wPortChange |= PORT_STAT_C_CONNECTION;
|
||||
if (port->wPortStatus & PORT_STAT_ENABLE) {
|
||||
|
@ -246,10 +181,18 @@ static void usb_hub_detach(USBPort *port1)
|
|||
}
|
||||
}
|
||||
|
||||
static void usb_hub_wakeup(USBDevice *dev)
|
||||
static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
|
||||
{
|
||||
USBHubState *s = dev->port->opaque;
|
||||
USBHubPort *port = &s->ports[dev->port->index];
|
||||
USBHubState *s = port1->opaque;
|
||||
|
||||
/* Pass along upstream */
|
||||
s->dev.port->ops->child_detach(s->dev.port, child);
|
||||
}
|
||||
|
||||
static void usb_hub_wakeup(USBPort *port1)
|
||||
{
|
||||
USBHubState *s = port1->opaque;
|
||||
USBHubPort *port = &s->ports[port1->index];
|
||||
|
||||
if (port->wPortStatus & PORT_STAT_SUSPEND) {
|
||||
port->wPortChange |= PORT_STAT_C_SUSPEND;
|
||||
|
@ -257,9 +200,9 @@ static void usb_hub_wakeup(USBDevice *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static void usb_hub_complete(USBDevice *dev, USBPacket *packet)
|
||||
static void usb_hub_complete(USBPort *port, USBPacket *packet)
|
||||
{
|
||||
USBHubState *s = dev->port->opaque;
|
||||
USBHubState *s = port->opaque;
|
||||
|
||||
/*
|
||||
* Just pass it along upstream for now.
|
||||
|
@ -537,6 +480,7 @@ static void usb_hub_handle_destroy(USBDevice *dev)
|
|||
static USBPortOps usb_hub_port_ops = {
|
||||
.attach = usb_hub_attach,
|
||||
.detach = usb_hub_detach,
|
||||
.child_detach = usb_hub_child_detach,
|
||||
.wakeup = usb_hub_wakeup,
|
||||
.complete = usb_hub_complete,
|
||||
};
|
||||
|
|
|
@ -216,10 +216,6 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
|
|||
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
|
||||
USBPacket *p = s->packet;
|
||||
|
||||
if (req->tag != s->tag) {
|
||||
fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag);
|
||||
}
|
||||
|
||||
assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
|
||||
s->scsi_len = len;
|
||||
s->scsi_buf = scsi_req_get_buf(req);
|
||||
|
@ -241,9 +237,6 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
|
|||
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
|
||||
USBPacket *p = s->packet;
|
||||
|
||||
if (req->tag != s->tag) {
|
||||
fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag);
|
||||
}
|
||||
DPRINTF("Command complete %d\n", status);
|
||||
s->residue = s->data_len;
|
||||
s->result = status != 0;
|
||||
|
@ -387,7 +380,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
|
|||
s->tag, cbw.flags, cbw.cmd_len, s->data_len);
|
||||
s->residue = 0;
|
||||
s->scsi_len = 0;
|
||||
s->req = scsi_req_new(s->scsi_dev, s->tag, 0);
|
||||
s->req = scsi_req_new(s->scsi_dev, s->tag, 0, NULL);
|
||||
scsi_req_enqueue(s->req, cbw.cmd);
|
||||
/* ??? Should check that USB and SCSI data transfer
|
||||
directions match. */
|
||||
|
|
|
@ -261,17 +261,18 @@
|
|||
|
||||
static void musb_attach(USBPort *port);
|
||||
static void musb_detach(USBPort *port);
|
||||
static void musb_schedule_cb(USBDevice *dev, USBPacket *p);
|
||||
static void musb_device_destroy(USBBus *bus, USBDevice *dev);
|
||||
static void musb_child_detach(USBPort *port, USBDevice *child);
|
||||
static void musb_schedule_cb(USBPort *port, USBPacket *p);
|
||||
static void musb_async_cancel_device(MUSBState *s, USBDevice *dev);
|
||||
|
||||
static USBPortOps musb_port_ops = {
|
||||
.attach = musb_attach,
|
||||
.detach = musb_detach,
|
||||
.child_detach = musb_child_detach,
|
||||
.complete = musb_schedule_cb,
|
||||
};
|
||||
|
||||
static USBBusOps musb_bus_ops = {
|
||||
.device_destroy = musb_device_destroy,
|
||||
};
|
||||
|
||||
typedef struct MUSBPacket MUSBPacket;
|
||||
|
@ -369,7 +370,6 @@ struct MUSBState *musb_init(qemu_irq *irqs)
|
|||
usb_bus_new(&s->bus, &musb_bus_ops, NULL /* FIXME */);
|
||||
usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
|
||||
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
|
||||
usb_port_location(&s->port, NULL, 1);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -498,10 +498,19 @@ static void musb_detach(USBPort *port)
|
|||
{
|
||||
MUSBState *s = (MUSBState *) port->opaque;
|
||||
|
||||
musb_async_cancel_device(s, port->dev);
|
||||
|
||||
musb_intr_set(s, musb_irq_disconnect, 1);
|
||||
musb_session_update(s, 1, s->session);
|
||||
}
|
||||
|
||||
static void musb_child_detach(USBPort *port, USBDevice *child)
|
||||
{
|
||||
MUSBState *s = (MUSBState *) port->opaque;
|
||||
|
||||
musb_async_cancel_device(s, child);
|
||||
}
|
||||
|
||||
static void musb_cb_tick0(void *opaque)
|
||||
{
|
||||
MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
|
||||
|
@ -518,7 +527,7 @@ static void musb_cb_tick1(void *opaque)
|
|||
|
||||
#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0)
|
||||
|
||||
static void musb_schedule_cb(USBDevice *dev, USBPacket *packey)
|
||||
static void musb_schedule_cb(USBPort *port, USBPacket *packey)
|
||||
{
|
||||
MUSBPacket *p = container_of(packey, MUSBPacket, p);
|
||||
MUSBEndPoint *ep = p->ep;
|
||||
|
@ -616,7 +625,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
|
|||
}
|
||||
|
||||
ep->status[dir] = ret;
|
||||
usb_packet_complete(s->port.dev, &ep->packey[dir].p);
|
||||
musb_schedule_cb(&s->port, &ep->packey[dir].p);
|
||||
}
|
||||
|
||||
static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
|
||||
|
@ -783,9 +792,8 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
|
|||
musb_rx_intr_set(s, epnum, 1);
|
||||
}
|
||||
|
||||
static void musb_device_destroy(USBBus *bus, USBDevice *dev)
|
||||
static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
|
||||
{
|
||||
MUSBState *s = container_of(bus, MUSBState, bus);
|
||||
int ep, dir;
|
||||
|
||||
for (ep = 0; ep < 16; ep++) {
|
||||
|
|
|
@ -124,6 +124,7 @@ struct ohci_hcca {
|
|||
};
|
||||
|
||||
static void ohci_bus_stop(OHCIState *ohci);
|
||||
static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
|
||||
|
||||
/* Bitfields for the first word of an Endpoint Desciptor. */
|
||||
#define OHCI_ED_FA_SHIFT 0
|
||||
|
@ -326,6 +327,7 @@ static void ohci_attach(USBPort *port1)
|
|||
{
|
||||
OHCIState *s = port1->opaque;
|
||||
OHCIPort *port = &s->rhport[port1->index];
|
||||
uint32_t old_state = port->ctrl;
|
||||
|
||||
/* set connect status */
|
||||
port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
|
||||
|
@ -343,6 +345,10 @@ static void ohci_attach(USBPort *port1)
|
|||
}
|
||||
|
||||
DPRINTF("usb-ohci: Attached port %d\n", port1->index);
|
||||
|
||||
if (old_state != port->ctrl) {
|
||||
ohci_set_interrupt(s, OHCI_INTR_RHSC);
|
||||
}
|
||||
}
|
||||
|
||||
static void ohci_detach(USBPort *port1)
|
||||
|
@ -351,6 +357,8 @@ static void ohci_detach(USBPort *port1)
|
|||
OHCIPort *port = &s->rhport[port1->index];
|
||||
uint32_t old_state = port->ctrl;
|
||||
|
||||
ohci_async_cancel_device(s, port1->dev);
|
||||
|
||||
/* set connect status */
|
||||
if (port->ctrl & OHCI_PORT_CCS) {
|
||||
port->ctrl &= ~OHCI_PORT_CCS;
|
||||
|
@ -363,19 +371,18 @@ static void ohci_detach(USBPort *port1)
|
|||
}
|
||||
DPRINTF("usb-ohci: Detached port %d\n", port1->index);
|
||||
|
||||
if (old_state != port->ctrl)
|
||||
if (old_state != port->ctrl) {
|
||||
ohci_set_interrupt(s, OHCI_INTR_RHSC);
|
||||
}
|
||||
}
|
||||
|
||||
static void ohci_wakeup(USBDevice *dev)
|
||||
static void ohci_wakeup(USBPort *port1)
|
||||
{
|
||||
USBBus *bus = usb_bus_from_device(dev);
|
||||
OHCIState *s = container_of(bus, OHCIState, bus);
|
||||
int portnum = dev->port->index;
|
||||
OHCIPort *port = &s->rhport[portnum];
|
||||
OHCIState *s = port1->opaque;
|
||||
OHCIPort *port = &s->rhport[port1->index];
|
||||
uint32_t intr = 0;
|
||||
if (port->ctrl & OHCI_PORT_PSS) {
|
||||
DPRINTF("usb-ohci: port %d: wakeup\n", portnum);
|
||||
DPRINTF("usb-ohci: port %d: wakeup\n", port1->index);
|
||||
port->ctrl |= OHCI_PORT_PSSC;
|
||||
port->ctrl &= ~OHCI_PORT_PSS;
|
||||
intr = OHCI_INTR_RHSC;
|
||||
|
@ -394,6 +401,13 @@ static void ohci_wakeup(USBDevice *dev)
|
|||
ohci_set_interrupt(s, intr);
|
||||
}
|
||||
|
||||
static void ohci_child_detach(USBPort *port1, USBDevice *child)
|
||||
{
|
||||
OHCIState *s = port1->opaque;
|
||||
|
||||
ohci_async_cancel_device(s, child);
|
||||
}
|
||||
|
||||
/* Reset the controller */
|
||||
static void ohci_reset(void *opaque)
|
||||
{
|
||||
|
@ -602,7 +616,7 @@ static void ohci_copy_iso_td(OHCIState *ohci,
|
|||
|
||||
static void ohci_process_lists(OHCIState *ohci, int completion);
|
||||
|
||||
static void ohci_async_complete_packet(USBDevice *dev, USBPacket *packet)
|
||||
static void ohci_async_complete_packet(USBPort *port, USBPacket *packet)
|
||||
{
|
||||
OHCIState *ohci = container_of(packet, OHCIState, usb_packet);
|
||||
#ifdef DEBUG_PACKET
|
||||
|
@ -1675,10 +1689,8 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
|
|||
}
|
||||
}
|
||||
|
||||
static void ohci_device_destroy(USBBus *bus, USBDevice *dev)
|
||||
static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
|
||||
{
|
||||
OHCIState *ohci = container_of(bus, OHCIState, bus);
|
||||
|
||||
if (ohci->async_td && ohci->usb_packet.owner == dev) {
|
||||
usb_cancel_packet(&ohci->usb_packet);
|
||||
ohci->async_td = 0;
|
||||
|
@ -1702,16 +1714,17 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={
|
|||
static USBPortOps ohci_port_ops = {
|
||||
.attach = ohci_attach,
|
||||
.detach = ohci_detach,
|
||||
.child_detach = ohci_child_detach,
|
||||
.wakeup = ohci_wakeup,
|
||||
.complete = ohci_async_complete_packet,
|
||||
};
|
||||
|
||||
static USBBusOps ohci_bus_ops = {
|
||||
.device_destroy = ohci_device_destroy,
|
||||
};
|
||||
|
||||
static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
|
||||
int num_ports, uint32_t localmem_base)
|
||||
static int usb_ohci_init(OHCIState *ohci, DeviceState *dev,
|
||||
int num_ports, uint32_t localmem_base,
|
||||
char *masterbus, uint32_t firstport)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -1731,39 +1744,58 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
|
|||
usb_frame_time, usb_bit_time);
|
||||
}
|
||||
|
||||
ohci->num_ports = num_ports;
|
||||
if (masterbus) {
|
||||
USBPort *ports[OHCI_MAX_PORTS];
|
||||
for(i = 0; i < num_ports; i++) {
|
||||
ports[i] = &ohci->rhport[i].port;
|
||||
}
|
||||
if (usb_register_companion(masterbus, ports, num_ports,
|
||||
firstport, ohci, &ohci_port_ops,
|
||||
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
usb_bus_new(&ohci->bus, &ohci_bus_ops, dev);
|
||||
for (i = 0; i < num_ports; i++) {
|
||||
usb_register_port(&ohci->bus, &ohci->rhport[i].port,
|
||||
ohci, i, &ohci_port_ops,
|
||||
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
|
||||
}
|
||||
}
|
||||
|
||||
ohci->mem = cpu_register_io_memory(ohci_readfn, ohci_writefn, ohci,
|
||||
DEVICE_LITTLE_ENDIAN);
|
||||
ohci->localmem_base = localmem_base;
|
||||
|
||||
ohci->name = dev->info->name;
|
||||
|
||||
usb_bus_new(&ohci->bus, &ohci_bus_ops, dev);
|
||||
ohci->num_ports = num_ports;
|
||||
for (i = 0; i < num_ports; i++) {
|
||||
usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, &ohci_port_ops,
|
||||
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
|
||||
usb_port_location(&ohci->rhport[i].port, NULL, i+1);
|
||||
}
|
||||
|
||||
ohci->async_td = 0;
|
||||
qemu_register_reset(ohci_reset, ohci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
PCIDevice pci_dev;
|
||||
OHCIState state;
|
||||
char *masterbus;
|
||||
uint32_t num_ports;
|
||||
uint32_t firstport;
|
||||
} OHCIPCIState;
|
||||
|
||||
static int usb_ohci_initfn_pci(struct PCIDevice *dev)
|
||||
{
|
||||
OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
|
||||
int num_ports = 3;
|
||||
|
||||
ohci->pci_dev.config[PCI_CLASS_PROG] = 0x10; /* OHCI */
|
||||
/* TODO: RST# value should be 0. */
|
||||
ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
|
||||
|
||||
usb_ohci_init(&ohci->state, &dev->qdev, num_ports, 0);
|
||||
if (usb_ohci_init(&ohci->state, &dev->qdev, ohci->num_ports, 0,
|
||||
ohci->masterbus, ohci->firstport) != 0) {
|
||||
return -1;
|
||||
}
|
||||
ohci->state.irq = ohci->pci_dev.irq[0];
|
||||
|
||||
/* TODO: avoid cast below by using dev */
|
||||
|
@ -1787,7 +1819,8 @@ static int ohci_init_pxa(SysBusDevice *dev)
|
|||
{
|
||||
OHCISysBusState *s = FROM_SYSBUS(OHCISysBusState, dev);
|
||||
|
||||
usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset);
|
||||
/* Cannot fail as we pass NULL for masterbus */
|
||||
usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset, NULL, 0);
|
||||
sysbus_init_irq(dev, &s->ohci.irq);
|
||||
sysbus_init_mmio(dev, 0x1000, s->ohci.mem);
|
||||
|
||||
|
@ -1802,6 +1835,12 @@ static PCIDeviceInfo ohci_pci_info = {
|
|||
.vendor_id = PCI_VENDOR_ID_APPLE,
|
||||
.device_id = PCI_DEVICE_ID_APPLE_IPID_USB,
|
||||
.class_id = PCI_CLASS_SERIAL_USB,
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
|
||||
DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
|
||||
DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static SysBusDeviceInfo ohci_sysbus_info = {
|
||||
|
|
101
hw/usb-uhci.c
101
hw/usb-uhci.c
|
@ -132,7 +132,7 @@ typedef struct UHCIPort {
|
|||
|
||||
struct UHCIState {
|
||||
PCIDevice dev;
|
||||
USBBus bus;
|
||||
USBBus bus; /* Note unused when we're a companion controller */
|
||||
uint16_t cmd; /* cmd register */
|
||||
uint16_t status;
|
||||
uint16_t intr; /* interrupt enable register */
|
||||
|
@ -150,6 +150,10 @@ struct UHCIState {
|
|||
/* Active packets */
|
||||
QTAILQ_HEAD(,UHCIAsync) async_pending;
|
||||
uint8_t num_ports_vmstate;
|
||||
|
||||
/* Properties */
|
||||
char *masterbus;
|
||||
uint32_t firstport;
|
||||
};
|
||||
|
||||
typedef struct UHCI_TD {
|
||||
|
@ -606,6 +610,8 @@ static void uhci_detach(USBPort *port1)
|
|||
UHCIState *s = port1->opaque;
|
||||
UHCIPort *port = &s->ports[port1->index];
|
||||
|
||||
uhci_async_cancel_device(s, port1->dev);
|
||||
|
||||
/* set connect status */
|
||||
if (port->ctrl & UHCI_PORT_CCS) {
|
||||
port->ctrl &= ~UHCI_PORT_CCS;
|
||||
|
@ -620,11 +626,17 @@ static void uhci_detach(USBPort *port1)
|
|||
uhci_resume(s);
|
||||
}
|
||||
|
||||
static void uhci_wakeup(USBDevice *dev)
|
||||
static void uhci_child_detach(USBPort *port1, USBDevice *child)
|
||||
{
|
||||
USBBus *bus = usb_bus_from_device(dev);
|
||||
UHCIState *s = container_of(bus, UHCIState, bus);
|
||||
UHCIPort *port = s->ports + dev->port->index;
|
||||
UHCIState *s = port1->opaque;
|
||||
|
||||
uhci_async_cancel_device(s, child);
|
||||
}
|
||||
|
||||
static void uhci_wakeup(USBPort *port1)
|
||||
{
|
||||
UHCIState *s = port1->opaque;
|
||||
UHCIPort *port = &s->ports[port1->index];
|
||||
|
||||
if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) {
|
||||
port->ctrl |= UHCI_PORT_RD;
|
||||
|
@ -657,7 +669,7 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void uhci_async_complete(USBDevice *dev, USBPacket *packet);
|
||||
static void uhci_async_complete(USBPort *port, USBPacket *packet);
|
||||
static void uhci_process_frame(UHCIState *s);
|
||||
|
||||
/* return -1 if fatal error (frame must be stopped)
|
||||
|
@ -718,6 +730,9 @@ out:
|
|||
td->ctrl |= TD_CTRL_STALL;
|
||||
td->ctrl &= ~TD_CTRL_ACTIVE;
|
||||
s->status |= UHCI_STS_USBERR;
|
||||
if (td->ctrl & TD_CTRL_IOC) {
|
||||
*int_mask |= 0x01;
|
||||
}
|
||||
uhci_update_irq(s);
|
||||
return 1;
|
||||
|
||||
|
@ -725,6 +740,9 @@ out:
|
|||
td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
|
||||
td->ctrl &= ~TD_CTRL_ACTIVE;
|
||||
s->status |= UHCI_STS_USBERR;
|
||||
if (td->ctrl & TD_CTRL_IOC) {
|
||||
*int_mask |= 0x01;
|
||||
}
|
||||
uhci_update_irq(s);
|
||||
/* frame interrupted */
|
||||
return -1;
|
||||
|
@ -849,7 +867,7 @@ done:
|
|||
return len;
|
||||
}
|
||||
|
||||
static void uhci_async_complete(USBDevice *dev, USBPacket *packet)
|
||||
static void uhci_async_complete(USBPort *port, USBPacket *packet)
|
||||
{
|
||||
UHCIAsync *async = container_of(packet, UHCIAsync, packet);
|
||||
UHCIState *s = async->uhci;
|
||||
|
@ -1096,22 +1114,15 @@ static void uhci_map(PCIDevice *pci_dev, int region_num,
|
|||
register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
|
||||
}
|
||||
|
||||
static void uhci_device_destroy(USBBus *bus, USBDevice *dev)
|
||||
{
|
||||
UHCIState *s = container_of(bus, UHCIState, bus);
|
||||
|
||||
uhci_async_cancel_device(s, dev);
|
||||
}
|
||||
|
||||
static USBPortOps uhci_port_ops = {
|
||||
.attach = uhci_attach,
|
||||
.detach = uhci_detach,
|
||||
.child_detach = uhci_child_detach,
|
||||
.wakeup = uhci_wakeup,
|
||||
.complete = uhci_async_complete,
|
||||
};
|
||||
|
||||
static USBBusOps uhci_bus_ops = {
|
||||
.device_destroy = uhci_device_destroy,
|
||||
};
|
||||
|
||||
static int usb_uhci_common_initfn(PCIDevice *dev)
|
||||
|
@ -1125,11 +1136,22 @@ static int usb_uhci_common_initfn(PCIDevice *dev)
|
|||
pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
|
||||
pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
|
||||
|
||||
usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev);
|
||||
for(i = 0; i < NB_PORTS; i++) {
|
||||
usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
|
||||
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
|
||||
usb_port_location(&s->ports[i].port, NULL, i+1);
|
||||
if (s->masterbus) {
|
||||
USBPort *ports[NB_PORTS];
|
||||
for(i = 0; i < NB_PORTS; i++) {
|
||||
ports[i] = &s->ports[i].port;
|
||||
}
|
||||
if (usb_register_companion(s->masterbus, ports, NB_PORTS,
|
||||
s->firstport, s, &uhci_port_ops,
|
||||
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev);
|
||||
for (i = 0; i < NB_PORTS; i++) {
|
||||
usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
|
||||
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
|
||||
}
|
||||
}
|
||||
s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s);
|
||||
s->num_ports_vmstate = NB_PORTS;
|
||||
|
@ -1160,6 +1182,12 @@ static int usb_uhci_vt82c686b_initfn(PCIDevice *dev)
|
|||
return usb_uhci_common_initfn(dev);
|
||||
}
|
||||
|
||||
static Property uhci_properties[] = {
|
||||
DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
|
||||
DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static PCIDeviceInfo uhci_info[] = {
|
||||
{
|
||||
.qdev.name = "piix3-usb-uhci",
|
||||
|
@ -1170,6 +1198,7 @@ static PCIDeviceInfo uhci_info[] = {
|
|||
.device_id = PCI_DEVICE_ID_INTEL_82371SB_2,
|
||||
.revision = 0x01,
|
||||
.class_id = PCI_CLASS_SERIAL_USB,
|
||||
.qdev.props = uhci_properties,
|
||||
},{
|
||||
.qdev.name = "piix4-usb-uhci",
|
||||
.qdev.size = sizeof(UHCIState),
|
||||
|
@ -1179,6 +1208,7 @@ static PCIDeviceInfo uhci_info[] = {
|
|||
.device_id = PCI_DEVICE_ID_INTEL_82371AB_2,
|
||||
.revision = 0x01,
|
||||
.class_id = PCI_CLASS_SERIAL_USB,
|
||||
.qdev.props = uhci_properties,
|
||||
},{
|
||||
.qdev.name = "vt82c686b-usb-uhci",
|
||||
.qdev.size = sizeof(UHCIState),
|
||||
|
@ -1188,6 +1218,37 @@ static PCIDeviceInfo uhci_info[] = {
|
|||
.device_id = PCI_DEVICE_ID_VIA_UHCI,
|
||||
.revision = 0x01,
|
||||
.class_id = PCI_CLASS_SERIAL_USB,
|
||||
.qdev.props = uhci_properties,
|
||||
},{
|
||||
.qdev.name = "ich9-usb-uhci1",
|
||||
.qdev.size = sizeof(UHCIState),
|
||||
.qdev.vmsd = &vmstate_uhci,
|
||||
.init = usb_uhci_common_initfn,
|
||||
.vendor_id = PCI_VENDOR_ID_INTEL,
|
||||
.device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
|
||||
.revision = 0x03,
|
||||
.class_id = PCI_CLASS_SERIAL_USB,
|
||||
.qdev.props = uhci_properties,
|
||||
},{
|
||||
.qdev.name = "ich9-usb-uhci2",
|
||||
.qdev.size = sizeof(UHCIState),
|
||||
.qdev.vmsd = &vmstate_uhci,
|
||||
.init = usb_uhci_common_initfn,
|
||||
.vendor_id = PCI_VENDOR_ID_INTEL,
|
||||
.device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
|
||||
.revision = 0x03,
|
||||
.class_id = PCI_CLASS_SERIAL_USB,
|
||||
.qdev.props = uhci_properties,
|
||||
},{
|
||||
.qdev.name = "ich9-usb-uhci3",
|
||||
.qdev.size = sizeof(UHCIState),
|
||||
.qdev.vmsd = &vmstate_uhci,
|
||||
.init = usb_uhci_common_initfn,
|
||||
.vendor_id = PCI_VENDOR_ID_INTEL,
|
||||
.device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
|
||||
.revision = 0x03,
|
||||
.class_id = PCI_CLASS_SERIAL_USB,
|
||||
.qdev.props = uhci_properties,
|
||||
},{
|
||||
/* end of list */
|
||||
}
|
||||
|
|
13
hw/usb.c
13
hw/usb.c
|
@ -40,19 +40,18 @@ void usb_attach(USBPort *port, USBDevice *dev)
|
|||
} else {
|
||||
/* detach */
|
||||
dev = port->dev;
|
||||
assert(dev);
|
||||
port->ops->detach(port);
|
||||
if (dev) {
|
||||
usb_send_msg(dev, USB_MSG_DETACH);
|
||||
dev->port = NULL;
|
||||
port->dev = NULL;
|
||||
}
|
||||
usb_send_msg(dev, USB_MSG_DETACH);
|
||||
dev->port = NULL;
|
||||
port->dev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void usb_wakeup(USBDevice *dev)
|
||||
{
|
||||
if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
|
||||
dev->port->ops->wakeup(dev);
|
||||
dev->port->ops->wakeup(dev->port);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,7 +334,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
|
|||
{
|
||||
/* Note: p->owner != dev is possible in case dev is a hub */
|
||||
assert(p->owner != NULL);
|
||||
dev->port->ops->complete(dev, p);
|
||||
dev->port->ops->complete(dev->port, p);
|
||||
p->owner = NULL;
|
||||
}
|
||||
|
||||
|
|
20
hw/usb.h
20
hw/usb.h
|
@ -252,8 +252,18 @@ struct USBDeviceInfo {
|
|||
typedef struct USBPortOps {
|
||||
void (*attach)(USBPort *port);
|
||||
void (*detach)(USBPort *port);
|
||||
void (*wakeup)(USBDevice *dev);
|
||||
void (*complete)(USBDevice *dev, USBPacket *p);
|
||||
/*
|
||||
* This gets called when a device downstream from the device attached to
|
||||
* the port (iow attached through a hub) gets detached.
|
||||
*/
|
||||
void (*child_detach)(USBPort *port, USBDevice *child);
|
||||
void (*wakeup)(USBPort *port);
|
||||
/*
|
||||
* Note that port->dev will be different then the device from which
|
||||
* the packet originated when a hub is involved, if you want the orginating
|
||||
* device use p->owner
|
||||
*/
|
||||
void (*complete)(USBPort *port, USBPacket *p);
|
||||
} USBPortOps;
|
||||
|
||||
/* USB port on which a device can be connected */
|
||||
|
@ -344,7 +354,8 @@ struct USBBus {
|
|||
};
|
||||
|
||||
struct USBBusOps {
|
||||
void (*device_destroy)(USBBus *bus, USBDevice *dev);
|
||||
int (*register_companion)(USBBus *bus, USBPort *ports[],
|
||||
uint32_t portcount, uint32_t firstport);
|
||||
};
|
||||
|
||||
void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
|
||||
|
@ -356,6 +367,9 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name);
|
|||
USBDevice *usbdevice_create(const char *cmdline);
|
||||
void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
|
||||
USBPortOps *ops, int speedmask);
|
||||
int usb_register_companion(const char *masterbus, USBPort *ports[],
|
||||
uint32_t portcount, uint32_t firstport,
|
||||
void *opaque, USBPortOps *ops, int speedmask);
|
||||
void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr);
|
||||
void usb_unregister_port(USBBus *bus, USBPort *port);
|
||||
int usb_device_attach(USBDevice *dev);
|
||||
|
|
|
@ -784,5 +784,6 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
|
|||
|
||||
hdev->started = false;
|
||||
qemu_free(hdev->log);
|
||||
hdev->log = NULL;
|
||||
hdev->log_size = 0;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ static void mmubooke_create_initial_mapping(CPUState *env,
|
|||
target_ulong va,
|
||||
target_phys_addr_t pa)
|
||||
{
|
||||
ppcemb_tlb_t *tlb = &env->tlb[0].tlbe;
|
||||
ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
|
||||
|
||||
tlb->attr = 0;
|
||||
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
||||
|
@ -69,7 +69,7 @@ static void mmubooke_create_initial_mapping(CPUState *env,
|
|||
tlb->RPN = pa & TARGET_PAGE_MASK;
|
||||
tlb->PID = 0;
|
||||
|
||||
tlb = &env->tlb[1].tlbe;
|
||||
tlb = &env->tlb.tlbe[1];
|
||||
tlb->attr = 0;
|
||||
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
|
||||
tlb->size = 1 << 31; /* up to 0xffffffff */
|
||||
|
|
|
@ -28,8 +28,8 @@ typedef struct VirtIOBlock
|
|||
void *rq;
|
||||
QEMUBH *bh;
|
||||
BlockConf *conf;
|
||||
char *serial;
|
||||
unsigned short sector_mask;
|
||||
char sn[BLOCK_SERIAL_STRLEN];
|
||||
DeviceState *qdev;
|
||||
} VirtIOBlock;
|
||||
|
||||
|
@ -362,8 +362,13 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req,
|
|||
} else if (type & VIRTIO_BLK_T_GET_ID) {
|
||||
VirtIOBlock *s = req->dev;
|
||||
|
||||
memcpy(req->elem.in_sg[0].iov_base, s->sn,
|
||||
MIN(req->elem.in_sg[0].iov_len, sizeof(s->sn)));
|
||||
/*
|
||||
* NB: per existing s/n string convention the string is
|
||||
* terminated by '\0' only when shorter than buffer.
|
||||
*/
|
||||
strncpy(req->elem.in_sg[0].iov_base,
|
||||
s->serial ? s->serial : "",
|
||||
MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
|
||||
} else if (type & VIRTIO_BLK_T_OUT) {
|
||||
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
|
||||
|
@ -531,7 +536,8 @@ static void virtio_blk_change_cb(void *opaque, int reason)
|
|||
}
|
||||
}
|
||||
|
||||
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
|
||||
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
||||
char **serial)
|
||||
{
|
||||
VirtIOBlock *s;
|
||||
int cylinders, heads, secs;
|
||||
|
@ -547,6 +553,14 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!*serial) {
|
||||
/* try to fall back to value set with legacy -drive serial=... */
|
||||
dinfo = drive_get_by_blockdev(conf->bs);
|
||||
if (*dinfo->serial) {
|
||||
*serial = strdup(dinfo->serial);
|
||||
}
|
||||
}
|
||||
|
||||
s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK,
|
||||
sizeof(struct virtio_blk_config),
|
||||
sizeof(VirtIOBlock));
|
||||
|
@ -556,16 +570,11 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
|
|||
s->vdev.reset = virtio_blk_reset;
|
||||
s->bs = conf->bs;
|
||||
s->conf = conf;
|
||||
s->serial = *serial;
|
||||
s->rq = NULL;
|
||||
s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
|
||||
bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
|
||||
|
||||
/* NB: per existing s/n string convention the string is terminated
|
||||
* by '\0' only when less than sizeof (s->sn)
|
||||
*/
|
||||
dinfo = drive_get_by_blockdev(s->bs);
|
||||
strncpy(s->sn, dinfo->serial, sizeof (s->sn));
|
||||
|
||||
s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);
|
||||
|
||||
qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#define VIRTIO_BLK_F_WCACHE 9 /* write cache enabled */
|
||||
#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */
|
||||
|
||||
#define VIRTIO_BLK_ID_BYTES 20 /* ID string length */
|
||||
|
||||
struct virtio_blk_config
|
||||
{
|
||||
uint64_t capacity;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "qemu-char.h"
|
||||
#include "qemu-error.h"
|
||||
#include "trace.h"
|
||||
#include "virtio-serial.h"
|
||||
|
||||
typedef struct VirtConsole {
|
||||
|
@ -24,8 +25,26 @@ typedef struct VirtConsole {
|
|||
static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
|
||||
{
|
||||
VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
|
||||
ssize_t ret;
|
||||
|
||||
return qemu_chr_write(vcon->chr, buf, len);
|
||||
ret = qemu_chr_write(vcon->chr, buf, len);
|
||||
trace_virtio_console_flush_buf(port->id, len, ret);
|
||||
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* Ideally we'd get a better error code than just -1, but
|
||||
* that's what the chardev interface gives us right now. If
|
||||
* we had a finer-grained message, like -EPIPE, we could close
|
||||
* this connection. Absent such error messages, the most we
|
||||
* can do is to return 0 here.
|
||||
*
|
||||
* This will prevent stray -1 values to go to
|
||||
* virtio-serial-bus.c and cause abort()s in
|
||||
* do_flush_queued_data().
|
||||
*/
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Callback function that's called when the guest opens the port */
|
||||
|
@ -57,6 +76,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
|
|||
{
|
||||
VirtConsole *vcon = opaque;
|
||||
|
||||
trace_virtio_console_chr_read(vcon->port.id, size);
|
||||
virtio_serial_write(&vcon->port, buf, size);
|
||||
}
|
||||
|
||||
|
@ -64,6 +84,7 @@ static void chr_event(void *opaque, int event)
|
|||
{
|
||||
VirtConsole *vcon = opaque;
|
||||
|
||||
trace_virtio_console_chr_event(vcon->port.id, event);
|
||||
switch (event) {
|
||||
case CHR_EVENT_OPENED:
|
||||
virtio_serial_open(&vcon->port);
|
||||
|
|
|
@ -657,7 +657,7 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
|
|||
|
||||
/* copy in packet. ugh */
|
||||
len = iov_from_buf(sg, elem.in_num,
|
||||
buf + offset, size - offset);
|
||||
buf + offset, 0, size - offset);
|
||||
total += len;
|
||||
offset += len;
|
||||
/* If buffers can't be merged, at this point we
|
||||
|
|
|
@ -700,7 +700,8 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev)
|
|||
proxy->class_code != PCI_CLASS_STORAGE_OTHER)
|
||||
proxy->class_code = PCI_CLASS_STORAGE_SCSI;
|
||||
|
||||
vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block);
|
||||
vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block,
|
||||
&proxy->block_serial);
|
||||
if (!vdev) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -805,6 +806,7 @@ static PCIDeviceInfo virtio_info[] = {
|
|||
.qdev.props = (Property[]) {
|
||||
DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
|
||||
DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial),
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
||||
|
|
|
@ -26,6 +26,7 @@ typedef struct {
|
|||
uint32_t class_code;
|
||||
uint32_t nvectors;
|
||||
BlockConf block;
|
||||
char *block_serial;
|
||||
NICConf nic;
|
||||
uint32_t host_features;
|
||||
#ifdef CONFIG_LINUX
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "monitor.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "sysbus.h"
|
||||
#include "trace.h"
|
||||
#include "virtio-serial.h"
|
||||
|
||||
/* The virtio-serial bus on top of which the ports will ride as devices */
|
||||
|
@ -103,7 +104,7 @@ static size_t write_to_port(VirtIOSerialPort *port,
|
|||
}
|
||||
|
||||
len = iov_from_buf(elem.in_sg, elem.in_num,
|
||||
buf + offset, size - offset);
|
||||
buf + offset, 0, size - offset);
|
||||
offset += len;
|
||||
|
||||
virtqueue_push(vq, &elem, len);
|
||||
|
@ -221,6 +222,7 @@ static size_t send_control_event(VirtIOSerialPort *port, uint16_t event,
|
|||
stw_p(&cpkt.event, event);
|
||||
stw_p(&cpkt.value, value);
|
||||
|
||||
trace_virtio_serial_send_control_event(port->id, event, value);
|
||||
return send_control_msg(port, &cpkt, sizeof(cpkt));
|
||||
}
|
||||
|
||||
|
@ -302,6 +304,7 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
|
|||
return;
|
||||
}
|
||||
|
||||
trace_virtio_serial_throttle_port(port->id, throttle);
|
||||
port->throttled = throttle;
|
||||
if (throttle) {
|
||||
return;
|
||||
|
@ -328,6 +331,8 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
|
|||
cpkt.event = lduw_p(&gcpkt->event);
|
||||
cpkt.value = lduw_p(&gcpkt->value);
|
||||
|
||||
trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value);
|
||||
|
||||
if (cpkt.event == VIRTIO_CONSOLE_DEVICE_READY) {
|
||||
if (!cpkt.value) {
|
||||
error_report("virtio-serial-bus: Guest failure in adding device %s",
|
||||
|
@ -346,11 +351,13 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
|
|||
|
||||
port = find_port_by_id(vser, ldl_p(&gcpkt->id));
|
||||
if (!port) {
|
||||
error_report("virtio-serial-bus: Unexpected port id %u for device %s\n",
|
||||
error_report("virtio-serial-bus: Unexpected port id %u for device %s",
|
||||
ldl_p(&gcpkt->id), vser->bus.qbus.name);
|
||||
return;
|
||||
}
|
||||
|
||||
trace_virtio_serial_handle_control_message_port(port->id);
|
||||
|
||||
info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
|
||||
|
||||
switch(cpkt.event) {
|
||||
|
|
|
@ -449,9 +449,17 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
|
|||
struct iovec *sg;
|
||||
|
||||
if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
|
||||
if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) {
|
||||
error_report("Too many write descriptors in indirect table");
|
||||
exit(1);
|
||||
}
|
||||
elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
|
||||
sg = &elem->in_sg[elem->in_num++];
|
||||
} else {
|
||||
if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) {
|
||||
error_report("Too many read descriptors in indirect table");
|
||||
exit(1);
|
||||
}
|
||||
elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i);
|
||||
sg = &elem->out_sg[elem->out_num++];
|
||||
}
|
||||
|
|
|
@ -197,7 +197,8 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
|
|||
void *opaque);
|
||||
|
||||
/* Base devices. */
|
||||
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf);
|
||||
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
||||
char **serial);
|
||||
struct virtio_net_conf;
|
||||
VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
|
||||
struct virtio_net_conf *net);
|
||||
|
|
10
hw/xen.h
10
hw/xen.h
|
@ -31,15 +31,6 @@ static inline int xen_enabled(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline int xen_mapcache_enabled(void)
|
||||
{
|
||||
#ifdef CONFIG_XEN_MAPCACHE
|
||||
return xen_enabled();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
|
||||
void xen_piix3_set_irq(void *opaque, int irq_num, int level);
|
||||
void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
|
||||
|
@ -50,6 +41,7 @@ qemu_irq *xen_interrupt_controller_init(void);
|
|||
int xen_init(void);
|
||||
int xen_hvm_init(void);
|
||||
void xen_vcpu_init(void);
|
||||
void xenstore_store_pv_console_info(int i, struct CharDriverState *chr);
|
||||
|
||||
#if defined(NEED_CPU_H) && !defined(CONFIG_USER_ONLY)
|
||||
void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size);
|
||||
|
|
|
@ -85,6 +85,18 @@ static inline int xc_domain_add_to_physmap(int xc_handle, uint32_t domid,
|
|||
return xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
|
||||
}
|
||||
|
||||
static inline struct xs_handle *xs_open(unsigned long flags)
|
||||
{
|
||||
return xs_daemon_open();
|
||||
}
|
||||
|
||||
static inline void xs_close(struct xs_handle *xsh)
|
||||
{
|
||||
if (xsh != NULL) {
|
||||
xs_daemon_close(xsh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Xen 4.1 */
|
||||
#else
|
||||
|
|
|
@ -179,7 +179,9 @@ static void xencons_send(struct XenConsole *con)
|
|||
static int con_init(struct XenDevice *xendev)
|
||||
{
|
||||
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
|
||||
char *type, *dom;
|
||||
char *type, *dom, label[32];
|
||||
int ret = 0;
|
||||
const char *output;
|
||||
|
||||
/* setup */
|
||||
dom = xs_get_domain_path(xenstore, con->xendev.dom);
|
||||
|
@ -189,16 +191,25 @@ static int con_init(struct XenDevice *xendev)
|
|||
type = xenstore_read_str(con->console, "type");
|
||||
if (!type || strcmp(type, "ioemu") != 0) {
|
||||
xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
|
||||
return -1;
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!serial_hds[con->xendev.dev])
|
||||
xen_be_printf(xendev, 1, "WARNING: serial line %d not configured\n",
|
||||
con->xendev.dev);
|
||||
else
|
||||
con->chr = serial_hds[con->xendev.dev];
|
||||
output = xenstore_read_str(con->console, "output");
|
||||
|
||||
return 0;
|
||||
/* no Xen override, use qemu output device */
|
||||
if (output == NULL) {
|
||||
con->chr = serial_hds[con->xendev.dev];
|
||||
} else {
|
||||
snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
|
||||
con->chr = qemu_chr_open(label, output, NULL);
|
||||
}
|
||||
|
||||
xenstore_store_pv_console_info(con->xendev.dev, con->chr);
|
||||
|
||||
out:
|
||||
qemu_free(type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int con_connect(struct XenDevice *xendev)
|
||||
|
|
|
@ -616,12 +616,14 @@ static int blk_init(struct XenDevice *xendev)
|
|||
{
|
||||
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
|
||||
int index, qflags, have_barriers, info = 0;
|
||||
char *h;
|
||||
|
||||
/* read xenstore entries */
|
||||
if (blkdev->params == NULL) {
|
||||
char *h = NULL;
|
||||
blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
|
||||
h = strchr(blkdev->params, ':');
|
||||
if (blkdev->params != NULL) {
|
||||
h = strchr(blkdev->params, ':');
|
||||
}
|
||||
if (h != NULL) {
|
||||
blkdev->fileproto = blkdev->params;
|
||||
blkdev->filename = h+1;
|
||||
|
@ -631,6 +633,9 @@ static int blk_init(struct XenDevice *xendev)
|
|||
blkdev->filename = blkdev->params;
|
||||
}
|
||||
}
|
||||
if (!strcmp("aio", blkdev->fileproto)) {
|
||||
blkdev->fileproto = "raw";
|
||||
}
|
||||
if (blkdev->mode == NULL) {
|
||||
blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
|
||||
}
|
||||
|
@ -649,7 +654,7 @@ static int blk_init(struct XenDevice *xendev)
|
|||
blkdev->mode == NULL ||
|
||||
blkdev->type == NULL ||
|
||||
blkdev->dev == NULL) {
|
||||
return -1;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
/* read-only ? */
|
||||
|
@ -672,10 +677,15 @@ static int blk_init(struct XenDevice *xendev)
|
|||
/* setup via xenbus -> create new block driver instance */
|
||||
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
|
||||
blkdev->bs = bdrv_new(blkdev->dev);
|
||||
if (bdrv_open(blkdev->bs, blkdev->filename, qflags,
|
||||
bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
|
||||
bdrv_delete(blkdev->bs);
|
||||
return -1;
|
||||
if (blkdev->bs) {
|
||||
if (bdrv_open(blkdev->bs, blkdev->filename, qflags,
|
||||
bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
|
||||
bdrv_delete(blkdev->bs);
|
||||
blkdev->bs = NULL;
|
||||
}
|
||||
}
|
||||
if (!blkdev->bs) {
|
||||
goto out_error;
|
||||
}
|
||||
} else {
|
||||
/* setup via qemu cmdline -> already setup for us */
|
||||
|
@ -704,6 +714,19 @@ static int blk_init(struct XenDevice *xendev)
|
|||
xenstore_write_be_int(&blkdev->xendev, "sectors",
|
||||
blkdev->file_size / blkdev->file_blk);
|
||||
return 0;
|
||||
|
||||
out_error:
|
||||
qemu_free(blkdev->params);
|
||||
blkdev->params = NULL;
|
||||
qemu_free(blkdev->mode);
|
||||
blkdev->mode = NULL;
|
||||
qemu_free(blkdev->type);
|
||||
blkdev->type = NULL;
|
||||
qemu_free(blkdev->dev);
|
||||
blkdev->dev = NULL;
|
||||
qemu_free(blkdev->devtype);
|
||||
blkdev->devtype = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int blk_connect(struct XenDevice *xendev)
|
||||
|
|
|
@ -290,18 +290,10 @@ static int xen_platform_initfn(PCIDevice *dev)
|
|||
|
||||
pci_conf = d->pci_dev.config;
|
||||
|
||||
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_XENSOURCE);
|
||||
pci_config_set_device_id(pci_conf, 0x0001);
|
||||
pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, PCI_VENDOR_ID_XENSOURCE);
|
||||
pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0001);
|
||||
|
||||
pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
|
||||
|
||||
pci_config_set_revision(pci_conf, 1);
|
||||
pci_config_set_prog_interface(pci_conf, 0);
|
||||
|
||||
pci_config_set_class(pci_conf, PCI_CLASS_OTHERS << 8 | 0x80);
|
||||
|
||||
pci_conf[PCI_INTERRUPT_PIN] = 1;
|
||||
|
||||
pci_register_bar(&d->pci_dev, 0, 0x100,
|
||||
|
@ -330,6 +322,13 @@ static PCIDeviceInfo xen_platform_info = {
|
|||
.qdev.size = sizeof(PCIXenPlatformState),
|
||||
.qdev.vmsd = &vmstate_xen_platform,
|
||||
.qdev.reset = platform_reset,
|
||||
|
||||
.vendor_id = PCI_VENDOR_ID_XEN,
|
||||
.device_id = PCI_DEVICE_ID_XEN_PLATFORM,
|
||||
.class_id = PCI_CLASS_OTHERS << 8 | 0x80,
|
||||
.subsystem_vendor_id = PCI_VENDOR_ID_XEN,
|
||||
.subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM,
|
||||
.revision = 1,
|
||||
};
|
||||
|
||||
static void xen_platform_register(void)
|
||||
|
|
19
hw/xenfb.c
19
hw/xenfb.c
|
@ -347,13 +347,6 @@ static void xenfb_mouse_event(void *opaque,
|
|||
|
||||
static int input_init(struct XenDevice *xendev)
|
||||
{
|
||||
struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
|
||||
|
||||
if (!in->c.ds) {
|
||||
xen_be_printf(xendev, 1, "ds not set (yet)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
|
||||
return 0;
|
||||
}
|
||||
|
@ -367,6 +360,18 @@ static int input_connect(struct XenDevice *xendev)
|
|||
&in->abs_pointer_wanted) == -1)
|
||||
in->abs_pointer_wanted = 0;
|
||||
|
||||
if (!in->c.ds) {
|
||||
char *vfb = xenstore_read_str(NULL, "device/vfb");
|
||||
if (vfb == NULL) {
|
||||
/* there is no vfb, run vkbd on its own */
|
||||
in->c.ds = get_displaystate();
|
||||
} else {
|
||||
qemu_free(vfb);
|
||||
xen_be_printf(xendev, 1, "ds not set (yet)\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rc = common_bind(&in->c);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
|
34
input.c
34
input.c
|
@ -148,7 +148,7 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
|
|||
QEMUPutMouseEntry *entry;
|
||||
QEMUPutMouseEvent *mouse_event;
|
||||
void *mouse_event_opaque;
|
||||
int width;
|
||||
int width, height;
|
||||
|
||||
if (QTAILQ_EMPTY(&mouse_handlers)) {
|
||||
return;
|
||||
|
@ -160,15 +160,31 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
|
|||
mouse_event_opaque = entry->qemu_put_mouse_event_opaque;
|
||||
|
||||
if (mouse_event) {
|
||||
if (graphic_rotate) {
|
||||
if (entry->qemu_put_mouse_event_absolute) {
|
||||
width = 0x7fff;
|
||||
} else {
|
||||
width = graphic_width - 1;
|
||||
}
|
||||
mouse_event(mouse_event_opaque, width - dy, dx, dz, buttons_state);
|
||||
if (entry->qemu_put_mouse_event_absolute) {
|
||||
width = 0x7fff;
|
||||
height = 0x7fff;
|
||||
} else {
|
||||
mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state);
|
||||
width = graphic_width - 1;
|
||||
height = graphic_height - 1;
|
||||
}
|
||||
|
||||
switch (graphic_rotate) {
|
||||
case 0:
|
||||
mouse_event(mouse_event_opaque,
|
||||
dx, dy, dz, buttons_state);
|
||||
break;
|
||||
case 90:
|
||||
mouse_event(mouse_event_opaque,
|
||||
width - dy, dx, dz, buttons_state);
|
||||
break;
|
||||
case 180:
|
||||
mouse_event(mouse_event_opaque,
|
||||
width - dx, height - dy, dz, buttons_state);
|
||||
break;
|
||||
case 270:
|
||||
mouse_event(mouse_event_opaque,
|
||||
dy, height - dx, dz, buttons_state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
69
iov.c
69
iov.c
|
@ -14,56 +14,61 @@
|
|||
|
||||
#include "iov.h"
|
||||
|
||||
size_t iov_from_buf(struct iovec *iov, unsigned int iovcnt,
|
||||
const void *buf, size_t size)
|
||||
size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
|
||||
const void *buf, size_t iov_off, size_t size)
|
||||
{
|
||||
size_t offset;
|
||||
size_t iovec_off, buf_off;
|
||||
unsigned int i;
|
||||
|
||||
offset = 0;
|
||||
for (i = 0; offset < size && i < iovcnt; i++) {
|
||||
size_t len;
|
||||
|
||||
len = MIN(iov[i].iov_len, size - offset);
|
||||
|
||||
memcpy(iov[i].iov_base, buf + offset, len);
|
||||
offset += len;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
size_t iov_to_buf(const struct iovec *iov, const unsigned int iovcnt,
|
||||
void *buf, size_t offset, size_t size)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
size_t iov_off, buf_off;
|
||||
unsigned int i;
|
||||
|
||||
ptr = buf;
|
||||
iov_off = 0;
|
||||
iovec_off = 0;
|
||||
buf_off = 0;
|
||||
for (i = 0; i < iovcnt && size; i++) {
|
||||
if (offset < (iov_off + iov[i].iov_len)) {
|
||||
size_t len = MIN((iov_off + iov[i].iov_len) - offset , size);
|
||||
for (i = 0; i < iov_cnt && size; i++) {
|
||||
if (iov_off < (iovec_off + iov[i].iov_len)) {
|
||||
size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off, size);
|
||||
|
||||
memcpy(ptr + buf_off, iov[i].iov_base + (offset - iov_off), len);
|
||||
memcpy(iov[i].iov_base + (iov_off - iovec_off), buf + buf_off, len);
|
||||
|
||||
buf_off += len;
|
||||
offset += len;
|
||||
iov_off += len;
|
||||
size -= len;
|
||||
}
|
||||
iov_off += iov[i].iov_len;
|
||||
iovec_off += iov[i].iov_len;
|
||||
}
|
||||
return buf_off;
|
||||
}
|
||||
|
||||
size_t iov_size(const struct iovec *iov, const unsigned int iovcnt)
|
||||
size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
|
||||
void *buf, size_t iov_off, size_t size)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
size_t iovec_off, buf_off;
|
||||
unsigned int i;
|
||||
|
||||
ptr = buf;
|
||||
iovec_off = 0;
|
||||
buf_off = 0;
|
||||
for (i = 0; i < iov_cnt && size; i++) {
|
||||
if (iov_off < (iovec_off + iov[i].iov_len)) {
|
||||
size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size);
|
||||
|
||||
memcpy(ptr + buf_off, iov[i].iov_base + (iov_off - iovec_off), len);
|
||||
|
||||
buf_off += len;
|
||||
iov_off += len;
|
||||
size -= len;
|
||||
}
|
||||
iovec_off += iov[i].iov_len;
|
||||
}
|
||||
return buf_off;
|
||||
}
|
||||
|
||||
size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
|
||||
{
|
||||
size_t len;
|
||||
unsigned int i;
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i < iovcnt; i++) {
|
||||
for (i = 0; i < iov_cnt; i++) {
|
||||
len += iov[i].iov_len;
|
||||
}
|
||||
return len;
|
||||
|
|
10
iov.h
10
iov.h
|
@ -12,8 +12,8 @@
|
|||
|
||||
#include "qemu-common.h"
|
||||
|
||||
size_t iov_from_buf(struct iovec *iov, unsigned int iovcnt,
|
||||
const void *buf, size_t size);
|
||||
size_t iov_to_buf(const struct iovec *iov, const unsigned int iovcnt,
|
||||
void *buf, size_t offset, size_t size);
|
||||
size_t iov_size(const struct iovec *iov, const unsigned int iovcnt);
|
||||
size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt,
|
||||
const void *buf, size_t iov_off, size_t size);
|
||||
size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
|
||||
void *buf, size_t iov_off, size_t size);
|
||||
size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue