[Spice-commits] 169 commits - Changelog MAINTAINERS Makefile Makefile.objs Makefile.target QMP/qmp.py alpha-dis.c async.c audio/audio_pt_int.c audio/coreaudio.c audio/sdlaudio.c block.c block.h block/qcow.c block/qcow2-cluster.c block/qcow2-refcount.c block/qcow2.c block/qcow2.h block/qed.c block/raw-posix.c block/raw-win32.c block/rbd.c block/rbd_types.h block/vdi.c block/vmdk.c block_int.h blockdev.c bsd-user/main.c bsd-user/syscall.c compatfd.c configure cpu-exec.c cpus.c cpus.h darwin-user/main.c darwin-user/signal.c default-configs/alpha-softmmu.mak dis-asm.h disas.c dma-helpers.c dma.h docs/qdev-device-use.txt docs/usb2.txt error.c error.h error_int.h exec-all.h exec.c fsdev/file-op-9p.h fsdev/qemu-fsdev-dummy.c hmp-commands.hx hw/9pfs hw/alpha_palcode.c hw/ide hw/lan9118.c hw/milkymist-softusb.c hw/pc.c hw/qxl.c hw/sga.c hw/smc91c111.c hw/usb-bus.c hw/usb-ccid.c hw/usb-ehci.c hw/usb-hid.c hw/usb-musb.c hw/usb-ohci.c hw/usb-uhci.c hw/usb.h hw/vga-isa.c hw/virtio-pci.c hw/virti o-pci.h json-lexer.c json-lexer.h json-parser.c json-parser.h json-streamer.c json-streamer.h libcacard/Makefile libfdt_env.h linux-user/main.c linux-user/signal.c monitor.c net/slirp.c net/tap.c os-posix.c os-win32.c osdep.h oslib-posix.c posix-aio-compat.c qemu-char.c qemu-common.h qemu-config.c qemu-io.c qemu-nbd.c qemu-options.hx qemu-progress.c qemu-timer.c qerror.c qerror.h qmp-commands.hx rules.mak savevm.c spice-qemu-char.c target-alpha/cpu.h target-alpha/exec.h target-alpha/helper.c target-alpha/helper.h target-alpha/machine.c target-alpha/op_helper.c target-alpha/translate.c target-i386/cpu.h target-i386/cpuid.c target-i386/helper.c target-i386/kvm.c target-i386/translate.c target-lm32/translate.c target-m68k/translate.c target-ppc/helper.c target-sparc/helper.c trace-events ui/cocoa.m ui/curses.c ui/sdl.c ui/spice-core.c usb-bsd.c usb-linux.c vl.c
Gerd Hoffmann
kraxel at kemper.freedesktop.org
Fri Jun 17 08:47:06 PDT 2011
Changelog | 6
MAINTAINERS | 4
Makefile | 24
Makefile.objs | 24
Makefile.target | 10
QMP/qmp.py | 54 +
alpha-dis.c | 4
async.c | 5
audio/audio_pt_int.c | 2
audio/coreaudio.c | 2
audio/sdlaudio.c | 1
block.c | 13
block.h | 6
block/qcow.c | 58 +
block/qcow2-cluster.c | 14
block/qcow2-refcount.c | 9
block/qcow2.c | 46 +
block/qcow2.h | 2
block/qed.c | 3
block/raw-posix.c | 79 ++
block/raw-win32.c | 12
block/rbd.c | 900 ++++++++++------------------
block/rbd_types.h | 71 --
block/vdi.c | 47 +
block/vmdk.c | 22
block_int.h | 4
blockdev.c | 2
bsd-user/main.c | 46 -
bsd-user/syscall.c | 1
compatfd.c | 2
configure | 65 +-
cpu-exec.c | 33 -
cpus.c | 5
cpus.h | 1
darwin-user/main.c | 45 -
darwin-user/signal.c | 3
default-configs/alpha-softmmu.mak | 9
dis-asm.h | 3
disas.c | 2
dma-helpers.c | 23
dma.h | 8
docs/qdev-device-use.txt | 180 +++--
docs/usb2.txt | 85 ++
error.c | 140 ++++
error.h | 70 ++
error_int.h | 29
exec-all.h | 2
exec.c | 13
fsdev/file-op-9p.h | 7
fsdev/qemu-fsdev-dummy.c | 28
hmp-commands.hx | 9
hw/9pfs/virtio-9p-debug.c | 5
hw/9pfs/virtio-9p-device.c | 173 +++++
hw/9pfs/virtio-9p-local.c | 138 ++--
hw/9pfs/virtio-9p-posix-acl.c | 22
hw/9pfs/virtio-9p-xattr-user.c | 11
hw/9pfs/virtio-9p-xattr.c | 7
hw/9pfs/virtio-9p-xattr.h | 9
hw/9pfs/virtio-9p.c | 164 +----
hw/9pfs/virtio-9p.h | 7
hw/alpha_palcode.c | 1048 ---------------------------------
hw/ide/core.c | 159 ++++-
hw/ide/internal.h | 32 -
hw/ide/macio.c | 13
hw/ide/pci.c | 88 ++
hw/ide/pci.h | 4
hw/ide/qdev.c | 5
hw/lan9118.c | 12
hw/milkymist-softusb.c | 10
hw/pc.c | 9
hw/qxl.c | 4
hw/sga.c | 56 +
hw/smc91c111.c | 9
hw/usb-bus.c | 10
hw/usb-ccid.c | 28
hw/usb-ehci.c | 1198 ++++++++++++++++++++++----------------
hw/usb-hid.c | 5
hw/usb-musb.c | 23
hw/usb-ohci.c | 37 +
hw/usb-uhci.c | 32 -
hw/usb.h | 14
hw/vga-isa.c | 1
hw/virtio-pci.c | 57 -
hw/virtio-pci.h | 43 +
json-lexer.c | 47 +
json-lexer.h | 1
json-parser.c | 83 ++
json-parser.h | 2
json-streamer.c | 42 +
json-streamer.h | 1
libcacard/Makefile | 32 -
libfdt_env.h | 8
linux-user/main.c | 93 +-
linux-user/signal.c | 1
monitor.c | 19
net/slirp.c | 2
net/tap.c | 1
os-posix.c | 2
os-win32.c | 2
osdep.h | 7
oslib-posix.c | 16
posix-aio-compat.c | 1
qemu-char.c | 1
qemu-common.h | 6
qemu-config.c | 12
qemu-io.c | 4
qemu-nbd.c | 4
qemu-options.hx | 29
qemu-progress.c | 1
qemu-timer.c | 120 ---
qerror.c | 63 +
qerror.h | 7
qmp-commands.hx | 27
rules.mak | 8
savevm.c | 1
spice-qemu-char.c | 11
target-alpha/cpu.h | 375 +++++------
target-alpha/exec.h | 12
target-alpha/helper.c | 589 ++++++++----------
target-alpha/helper.h | 32 -
target-alpha/machine.c | 87 ++
target-alpha/op_helper.c | 278 +++-----
target-alpha/translate.c | 804 ++++++++++++++-----------
target-i386/cpu.h | 9
target-i386/cpuid.c | 66 ++
target-i386/helper.c | 1
target-i386/kvm.c | 15
target-i386/translate.c | 2
target-lm32/translate.c | 2
target-m68k/translate.c | 43 -
target-ppc/helper.c | 1
target-sparc/helper.c | 1
trace-events | 20
ui/cocoa.m | 25
ui/curses.c | 1
ui/sdl.c | 4
ui/spice-core.c | 26
usb-bsd.c | 1
usb-linux.c | 97 ++-
vl.c | 32 -
140 files changed, 4619 insertions(+), 4224 deletions(-)
New commits:
commit eb47d7c5d96060040931c42773ee07e61e547af9
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Thu May 26 17:34:11 2011 +0100
hw/9118.c: Implement active-low interrupt support
The 9118 ethernet controller interrupt line is active low unless
the IRQ config register is programmed to set both the IRQ_POL
(polarity: active-high) and IRQ_TYPE (type: push-pull) bits:
implement support for inverting the irq output in other configurations.
This also requires that we support setting the bits in the first
place, and that we correctly preserve them across software reset.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Andrzej Zaborowski <andrew.zaborowski at intel.com>
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 4c42fe9..3f3c05d 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -228,6 +228,12 @@ static void lan9118_update(lan9118_state *s)
if ((s->irq_cfg & IRQ_EN) == 0) {
level = 0;
}
+ if ((s->irq_cfg & (IRQ_TYPE | IRQ_POL)) != (IRQ_TYPE | IRQ_POL)) {
+ /* Interrupt is active low unless we're configured as
+ * active-high polarity, push-pull type.
+ */
+ level = !level;
+ }
qemu_set_irq(s->irq, level);
}
@@ -294,8 +300,7 @@ static void phy_reset(lan9118_state *s)
static void lan9118_reset(DeviceState *d)
{
lan9118_state *s = FROM_SYSBUS(lan9118_state, sysbus_from_qdev(d));
-
- s->irq_cfg &= ~(IRQ_TYPE | IRQ_POL);
+ s->irq_cfg &= (IRQ_TYPE | IRQ_POL);
s->int_sts = 0;
s->int_en = 0;
s->fifo_int = 0x48000000;
@@ -904,7 +909,8 @@ static void lan9118_writel(void *opaque, target_phys_addr_t offset,
switch (offset) {
case CSR_IRQ_CFG:
/* TODO: Implement interrupt deassertion intervals. */
- s->irq_cfg = (s->irq_cfg & IRQ_INT) | (val & IRQ_EN);
+ val &= (IRQ_EN | IRQ_POL | IRQ_TYPE);
+ s->irq_cfg = (s->irq_cfg & IRQ_INT) | val;
break;
case CSR_INT_STS:
s->int_sts &= ~val;
commit 953ffe0f935f40c0d6061d69e76e0339393b54f8
Author: Andreas Färber <andreas.faerber at web.de>
Date: Thu Jun 2 19:58:06 2011 +0200
Introduce format string for pid_t
BeOS and Haiku on i386 use long for 32-bit types, including pid_t.
Using %d with pid_t therefore results in a warning.
Unfortunately POSIX:2008 does not define a PRId* string for pid_t.
In some places pid_t was previously casted to long and %ld hardcoded.
The predecessor of this patch added another upcast for the simpletrace
filename but was not applied to date.
Since new uses of pid_t with %d keep creeping in, let's instead define
an OS-dependent format string and use that consistently.
Cc: Stefan Hajnoczi <stefanha at gmail.com>
Cc: Blue Swirl <blauwirbel at gmail.com>
Cc: Ingo Weinhold <ingo_weinhold at gmx.de>
Cc: Gleb Natapov <gleb at redhat.com>
Signed-off-by: Andreas Färber <andreas.faerber at web.de>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/configure b/configure
index 4c4aa92..44c092a 100755
--- a/configure
+++ b/configure
@@ -3041,7 +3041,7 @@ if test "$trace_backend" = "simple"; then
fi
# Set the appropriate trace file.
if test "$trace_backend" = "simple"; then
- trace_file="\"$trace_file-%u\""
+ trace_file="\"$trace_file-\" FMT_pid"
fi
if test "$trace_backend" = "dtrace" -a "$trace_backend_stap" = "yes" ; then
echo "CONFIG_SYSTEMTAP_TRACE=y" >> $config_host_mak
diff --git a/os-posix.c b/os-posix.c
index 3204197..7dfb278 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -368,7 +368,7 @@ int qemu_create_pidfile(const char *filename)
if (lockf(fd, F_TLOCK, 0) == -1) {
return -1;
}
- len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
+ len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", getpid());
if (write(fd, buffer, len) != len) {
return -1;
}
diff --git a/os-win32.c b/os-win32.c
index d6d54c6..b6652af 100644
--- a/os-win32.c
+++ b/os-win32.c
@@ -258,7 +258,7 @@ int qemu_create_pidfile(const char *filename)
if (file == INVALID_HANDLE_VALUE) {
return -1;
}
- len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
+ len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", getpid());
ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len,
&overlap, NULL);
if (ret == 0) {
diff --git a/osdep.h b/osdep.h
index 6eb9a49..a817017 100644
--- a/osdep.h
+++ b/osdep.h
@@ -128,6 +128,12 @@ void qemu_vfree(void *ptr);
int qemu_madvise(void *addr, size_t len, int advice);
+#if defined(__HAIKU__) && defined(__i386__)
+#define FMT_pid "%ld"
+#else
+#define FMT_pid "%d"
+#endif
+
int qemu_create_pidfile(const char *filename);
int qemu_get_thread_id(void);
diff --git a/vl.c b/vl.c
index 7b83c43..dbdec71 100644
--- a/vl.c
+++ b/vl.c
@@ -1197,7 +1197,7 @@ void qemu_kill_report(void)
*/
fputc('\n', stderr);
} else {
- fprintf(stderr, " from pid %d\n", shutdown_pid);
+ fprintf(stderr, " from pid " FMT_pid "\n", shutdown_pid);
}
shutdown_signal = -1;
}
commit 1e36f6a5b573009267160edc33cb216c9621abc0
Author: Juha Riihimäki <juha.riihimaki at nokia.com>
Date: Tue May 31 17:48:23 2011 +0100
smc91c111: qdevify reset
Register the smc91c111 reset function as a qdev reset function.
Signed-off-by: Juha Riihimäki <juha.riihimaki at nokia.com>
Reviewed-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index dafea5c..701baaf 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -252,8 +252,9 @@ static void smc91c111_queue_tx(smc91c111_state *s, int packet)
smc91c111_do_tx(s);
}
-static void smc91c111_reset(smc91c111_state *s)
+static void smc91c111_reset(DeviceState *dev)
{
+ smc91c111_state *s = FROM_SYSBUS(smc91c111_state, sysbus_from_qdev(dev));
s->bank = 0;
s->tx_fifo_len = 0;
s->tx_fifo_done_len = 0;
@@ -302,7 +303,7 @@ static void smc91c111_writeb(void *opaque, target_phys_addr_t offset,
case 5:
SET_HIGH(rcr, value);
if (s->rcr & RCR_SOFT_RST)
- smc91c111_reset(s);
+ smc91c111_reset(&s->busdev.qdev);
return;
case 10: case 11: /* RPCR */
/* Ignored */
@@ -753,9 +754,6 @@ static int smc91c111_init1(SysBusDevice *dev)
sysbus_init_mmio(dev, 16, s->mmio_index);
sysbus_init_irq(dev, &s->irq);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
- smc91c111_reset(s);
-
s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
dev->qdev.info->name, dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
@@ -768,6 +766,7 @@ static SysBusDeviceInfo smc91c111_info = {
.qdev.name = "smc91c111",
.qdev.size = sizeof(smc91c111_state),
.qdev.vmsd = &vmstate_smc91c111,
+ .qdev.reset = smc91c111_reset,
.qdev.props = (Property[]) {
DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
DEFINE_PROP_END_OF_LIST(),
commit 22e1e729600dad1639329185614d094243409359
Merge: c235d73... f97742d...
Author: Blue Swirl <blauwirbel at gmail.com>
Date: Wed Jun 15 18:31:56 2011 +0000
Merge branch 'cocoa-for-upstream' of git://repo.or.cz/qemu/afaerber
* 'cocoa-for-upstream' of git://repo.or.cz/qemu/afaerber:
Darwin: Fix compilation warning regarding the deprecated daemon() function
cocoa: Avoid warning related to multiple handleEvent: definitions
cocoa: Revert dependency on VNC
cocoa: Provide central qemu_main() prototype
Fix libfdt warnings on Darwin
configure: Fix check for fdatasync()
Remove warning in printf due to type mismatch
Cocoa: avoid displaying window when command-line contains '-h' or '-help'
Fix compilation warning due to incorrectly specified type
cocoa: do not create a spurious window for -version
commit c235d7387c850857ec6b0ba8ee28c7e1548f68c0
Author: Matthew Fernandez <matthew.fernandez at gmail.com>
Date: Tue Jun 7 16:32:40 2011 +0000
Command line support for altering the log file location
Add command line support for logging to a location other than /tmp/qemu.log.
With logging enabled (command line option -d), the log is written to
the hard-coded path /tmp/qemu.log. This patch adds support for writing
the log to a different location by passing the -D option.
Signed-off-by: Matthew Fernandez <matthew.fernandez at gmail.com>
Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 0c3fca1..0af8a7e 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -690,7 +690,8 @@ static void usage(void)
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
"\n"
"Debug options:\n"
- "-d options activate log (logfile=%s)\n"
+ "-d options activate log (default logfile=%s)\n"
+ "-D logfile override default logfile location\n"
"-p pagesize set the host page size to 'pagesize'\n"
"-singlestep always run in singlestep mode\n"
"-strace log system calls\n"
@@ -731,6 +732,8 @@ int main(int argc, char **argv)
{
const char *filename;
const char *cpu_model;
+ const char *log_file = DEBUG_LOGFILE;
+ const char *log_mask = NULL;
struct target_pt_regs regs1, *regs = ®s1;
struct image_info info1, *info = &info1;
TaskState ts1, *ts = &ts1;
@@ -745,9 +748,6 @@ int main(int argc, char **argv)
if (argc <= 1)
usage();
- /* init debug */
- cpu_set_log_filename(DEBUG_LOGFILE);
-
if ((envlist = envlist_create()) == NULL) {
(void) fprintf(stderr, "Unable to allocate envlist\n");
exit(1);
@@ -775,22 +775,15 @@ int main(int argc, char **argv)
if (!strcmp(r, "-")) {
break;
} else if (!strcmp(r, "d")) {
- int mask;
- const CPULogItem *item;
-
- if (optind >= argc)
+ if (optind >= argc) {
break;
-
- r = argv[optind++];
- mask = cpu_str_to_log_mask(r);
- if (!mask) {
- printf("Log items (comma separated):\n");
- for(item = cpu_log_items; item->mask != 0; item++) {
- printf("%-10s %s\n", item->name, item->help);
- }
- exit(1);
}
- cpu_set_log(mask);
+ log_mask = argv[optind++];
+ } else if (!strcmp(r, "D")) {
+ if (optind >= argc) {
+ break;
+ }
+ log_file = argv[optind++];
} else if (!strcmp(r, "E")) {
r = argv[optind++];
if (envlist_setenv(envlist, r) != 0)
@@ -867,6 +860,23 @@ int main(int argc, char **argv)
usage();
filename = argv[optind];
+ /* init debug */
+ cpu_set_log_filename(log_file);
+ if (log_mask) {
+ int mask;
+ const CPULogItem *item;
+
+ mask = cpu_str_to_log_mask(r);
+ if (!mask) {
+ printf("Log items (comma separated):\n");
+ for (item = cpu_log_items; item->mask != 0; item++) {
+ printf("%-10s %s\n", item->name, item->help);
+ }
+ exit(1);
+ }
+ cpu_set_log(mask);
+ }
+
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
diff --git a/cpus.c b/cpus.c
index 1fc34b7..17e96b5 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1142,6 +1142,11 @@ void set_cpu_log(const char *optarg)
cpu_set_log(mask);
}
+void set_cpu_log_filename(const char *optarg)
+{
+ cpu_set_log_filename(optarg);
+}
+
/* Return the virtual CPU time, based on the instruction counter. */
int64_t cpu_get_icount(void)
{
diff --git a/cpus.h b/cpus.h
index 6fdeb0d..f42b54e 100644
--- a/cpus.h
+++ b/cpus.h
@@ -19,6 +19,7 @@ void vm_state_notify(int running, int reason);
bool cpu_exec_all(void);
void set_numa_modes(void);
void set_cpu_log(const char *optarg);
+void set_cpu_log_filename(const char *optarg);
void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg);
#endif
diff --git a/darwin-user/main.c b/darwin-user/main.c
index 175e12f..a6dc859 100644
--- a/darwin-user/main.c
+++ b/darwin-user/main.c
@@ -738,6 +738,8 @@ TaskState *first_task_state;
int main(int argc, char **argv)
{
const char *filename;
+ const char *log_file = DEBUG_LOGFILE;
+ const char *log_mask = NULL;
struct target_pt_regs regs1, *regs = ®s1;
TaskState ts1, *ts = &ts1;
CPUState *env;
@@ -749,9 +751,6 @@ int main(int argc, char **argv)
if (argc <= 1)
usage();
- /* init debug */
- cpu_set_log_filename(DEBUG_LOGFILE);
-
optind = 1;
for(;;) {
if (optind >= argc)
@@ -764,22 +763,15 @@ int main(int argc, char **argv)
if (!strcmp(r, "-")) {
break;
} else if (!strcmp(r, "d")) {
- int mask;
- CPULogItem *item;
-
- if (optind >= argc)
- break;
-
- r = argv[optind++];
- mask = cpu_str_to_log_mask(r);
- if (!mask) {
- printf("Log items (comma separated):\n");
- for(item = cpu_log_items; item->mask != 0; item++) {
- printf("%-10s %s\n", item->name, item->help);
- }
- exit(1);
+ if (optind >= argc) {
+ break;
}
- cpu_set_log(mask);
+ log_mask = argv[optind++];
+ } else if (!strcmp(r, "D")) {
+ if (optind >= argc) {
+ break;
+ }
+ log_file = argv[optind++];
} else if (!strcmp(r, "s")) {
r = argv[optind++];
stack_size = strtol(r, (char **)&r, 0);
@@ -821,6 +813,23 @@ int main(int argc, char **argv)
usage();
filename = argv[optind];
+ /* init debug */
+ cpu_set_log_filename(log_file);
+ if (log_mask) {
+ int mask;
+ CPULogItem *item;
+
+ mask = cpu_str_to_log_mask(r);
+ if (!mask) {
+ printf("Log items (comma separated):\n");
+ for (item = cpu_log_items; item->mask != 0; item++) {
+ printf("%-10s %s\n", item->name, item->help);
+ }
+ exit(1);
+ }
+ cpu_set_log(mask);
+ }
+
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
diff --git a/linux-user/main.c b/linux-user/main.c
index 04da0a4..71dd253 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2832,6 +2832,8 @@ int main(int argc, char **argv, char **envp)
{
const char *filename;
const char *cpu_model;
+ const char *log_file = DEBUG_LOGFILE;
+ const char *log_mask = NULL;
struct target_pt_regs regs1, *regs = ®s1;
struct image_info info1, *info = &info1;
struct linux_binprm bprm;
@@ -2853,9 +2855,6 @@ int main(int argc, char **argv, char **envp)
qemu_cache_utils_init(envp);
- /* init debug */
- cpu_set_log_filename(DEBUG_LOGFILE);
-
if ((envlist = envlist_create()) == NULL) {
(void) fprintf(stderr, "Unable to allocate envlist\n");
exit(1);
@@ -2894,22 +2893,15 @@ int main(int argc, char **argv, char **envp)
if (!strcmp(r, "-")) {
break;
} else if (!strcmp(r, "d")) {
- int mask;
- const CPULogItem *item;
-
- if (optind >= argc)
+ if (optind >= argc) {
break;
-
- r = argv[optind++];
- mask = cpu_str_to_log_mask(r);
- if (!mask) {
- printf("Log items (comma separated):\n");
- for(item = cpu_log_items; item->mask != 0; item++) {
- printf("%-10s %s\n", item->name, item->help);
- }
- exit(1);
}
- cpu_set_log(mask);
+ log_mask = argv[optind++];
+ } else if (!strcmp(r, "D")) {
+ if (optind >= argc) {
+ break;
+ }
+ log_file = argv[optind++];
} else if (!strcmp(r, "E")) {
r = argv[optind++];
if (envlist_setenv(envlist, r) != 0)
@@ -3022,6 +3014,23 @@ int main(int argc, char **argv, char **envp)
filename = argv[optind];
exec_path = argv[optind];
+ /* init debug */
+ cpu_set_log_filename(log_file);
+ if (log_mask) {
+ int mask;
+ const CPULogItem *item;
+
+ mask = cpu_str_to_log_mask(r);
+ if (!mask) {
+ printf("Log items (comma separated):\n");
+ for (item = cpu_log_items; item->mask != 0; item++) {
+ printf("%-10s %s\n", item->name, item->help);
+ }
+ exit(1);
+ }
+ cpu_set_log(mask);
+ }
+
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
diff --git a/qemu-options.hx b/qemu-options.hx
index f2ef9a1..37e54ee 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2007,6 +2007,15 @@ STEXI
Output log in /tmp/qemu.log
ETEXI
+DEF("D", HAS_ARG, QEMU_OPTION_D, \
+ "-D logfile output log to logfile (instead of the default /tmp/qemu.log)\n",
+ QEMU_ARCH_ALL)
+STEXI
+ at item -D
+ at findex -D
+Output log in logfile instead of /tmp/qemu.log
+ETEXI
+
DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \
"-hdachs c,h,s[,t]\n" \
" force hard disk 0 physical geometry and the optional BIOS\n" \
diff --git a/vl.c b/vl.c
index c1cc614..7b83c43 100644
--- a/vl.c
+++ b/vl.c
@@ -2067,6 +2067,8 @@ int main(int argc, char **argv, char **envp)
#endif
int defconfig = 1;
const char *trace_file = NULL;
+ const char *log_mask = NULL;
+ const char *log_file = NULL;
atexit(qemu_run_exit_notifiers);
error_set_progname(argv[0]);
@@ -2441,7 +2443,10 @@ int main(int argc, char **argv, char **envp)
break;
#endif
case QEMU_OPTION_d:
- set_cpu_log(optarg);
+ log_mask = optarg;
+ break;
+ case QEMU_OPTION_D:
+ log_file = optarg;
break;
case QEMU_OPTION_s:
gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT;
@@ -2907,6 +2912,18 @@ int main(int argc, char **argv, char **envp)
}
loc_set_none();
+ /* Open the logfile at this point, if necessary. We can't open the logfile
+ * when encountering either of the logging options (-d or -D) because the
+ * other one may be encountered later on the command line, changing the
+ * location or level of logging.
+ */
+ if (log_mask) {
+ if (log_file) {
+ set_cpu_log_filename(log_file);
+ }
+ set_cpu_log(log_mask);
+ }
+
if (!st_init(trace_file)) {
fprintf(stderr, "warning: unable to initialize simple trace backend\n");
}
commit 71f34ad05359d7fa97996562d904979281ddc7f5
Merge: b45a9b1... e13e973...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 15 09:03:49 2011 -0500
Merge remote-tracking branch 'alon/pull-libcacard-1' into staging
commit b45a9b185120a10455859341d8035cce9b441fc8
Merge: f897235... 3dc769a...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 15 09:03:33 2011 -0500
Merge remote-tracking branch 'qemu-kvm/uq/master' into staging
commit f897235e0a0840c44645b609dc52a4c47ddfc3d5
Merge: 1f8bedb... 94cc916...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 15 09:03:22 2011 -0500
Merge remote-tracking branch 'kraxel/usb.16' into staging
commit 1f8bedba79f453596b06e9ebbfa2be8db1eccb68
Merge: f791168... 7887f62...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 15 09:02:18 2011 -0500
Merge remote-tracking branch 'kwolf/for-anthony' into staging
commit 7887f6201ff3fdc9a142eba14d61c563adb57596
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue Jun 7 17:51:21 2011 +0200
Allow nested qemu_bh_poll() after BH deletion
Without this, qemu segfaults when a BH handler first deletes its BH and
then calls another function which involves a nested qemu_bh_poll() call.
This can be reproduced by generating an I/O error (e.g. with blkdebug) on
an IDE device and using rerror/werror=stop to stop the VM. When continuing
the VM, qemu segfaults.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/async.c b/async.c
index 57ac3a8..fd313df 100644
--- a/async.c
+++ b/async.c
@@ -137,11 +137,12 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
int qemu_bh_poll(void)
{
- QEMUBH *bh, **bhp;
+ QEMUBH *bh, **bhp, *next;
int ret;
ret = 0;
- for (bh = async_context->first_bh; bh; bh = bh->next) {
+ for (bh = async_context->first_bh; bh; bh = next) {
+ next = bh->next;
if (!bh->deleted && bh->scheduled) {
bh->scheduled = 0;
if (!bh->idle)
commit ee752da74f5d07cf441f8d42455c4241d6051ae5
Author: Kevin Wolf <kwolf at redhat.com>
Date: Fri Jun 10 16:32:13 2011 +0200
ide: Clear error_status after restarting flush
Clearing the error status flag was missing for restarting flushes. Now that the
error status is separate from the BM status register, we can simply set it to 0
after restarting the request. This ensures that we never forget to clear a bit.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index c940375..9f3050a 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -189,6 +189,7 @@ static void bmdma_restart_bh(void *opaque)
BMDMAState *bm = opaque;
IDEBus *bus = bm->bus;
int is_read;
+ int error_status;
qemu_bh_delete(bm->bh);
bm->bh = NULL;
@@ -199,22 +200,25 @@ static void bmdma_restart_bh(void *opaque)
is_read = !!(bus->error_status & BM_STATUS_RETRY_READ);
- if (bus->error_status & BM_STATUS_DMA_RETRY) {
- if (bus->error_status & BM_STATUS_RETRY_TRIM) {
- bus->error_status &= ~BM_STATUS_RETRY_TRIM;
+ /* The error status must be cleared before resubmitting the request: The
+ * request may fail again, and this case can only be distinguished if the
+ * called function can set a new error status. */
+ error_status = bus->error_status;
+ bus->error_status = 0;
+
+ if (error_status & BM_STATUS_DMA_RETRY) {
+ if (error_status & BM_STATUS_RETRY_TRIM) {
bmdma_restart_dma(bm, IDE_DMA_TRIM);
} else {
- bus->error_status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ);
bmdma_restart_dma(bm, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
}
- } else if (bus->error_status & BM_STATUS_PIO_RETRY) {
- bus->error_status &= ~(BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ);
+ } else if (error_status & BM_STATUS_PIO_RETRY) {
if (is_read) {
ide_sector_read(bmdma_active_if(bm));
} else {
ide_sector_write(bmdma_active_if(bm));
}
- } else if (bus->error_status & BM_STATUS_RETRY_FLUSH) {
+ } else if (error_status & BM_STATUS_RETRY_FLUSH) {
ide_flush_cache(bmdma_active_if(bm));
}
}
commit d353fb72f59cd0e1f67baf773e74719cda761a89
Author: Christoph Hellwig <hch at lst.de>
Date: Thu May 19 10:58:19 2011 +0200
ide: add TRIM support
Add support for TRIM sub function of the data set management command,
and wire it up to the qemu discard infrastructure.
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 14bda82..ca17a43 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -78,7 +78,7 @@ static void ide_identify(IDEState *s)
{
uint16_t *p;
unsigned int oldsize;
- IDEDevice *dev;
+ IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master;
if (s->identify_set) {
memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
@@ -124,6 +124,9 @@ static void ide_identify(IDEState *s)
put_le16(p + 66, 120);
put_le16(p + 67, 120);
put_le16(p + 68, 120);
+ if (dev && dev->conf.discard_granularity) {
+ put_le16(p + 69, (1 << 14)); /* determinate TRIM behavior */
+ }
if (s->ncq_queues) {
put_le16(p + 75, s->ncq_queues - 1);
@@ -154,9 +157,12 @@ static void ide_identify(IDEState *s)
put_le16(p + 101, s->nb_sectors >> 16);
put_le16(p + 102, s->nb_sectors >> 32);
put_le16(p + 103, s->nb_sectors >> 48);
- dev = s->unit ? s->bus->slave : s->bus->master;
+
if (dev && dev->conf.physical_block_size)
put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf));
+ if (dev && dev->conf.discard_granularity) {
+ put_le16(p + 169, 1); /* TRIM support */
+ }
memcpy(s->identify_data, p, sizeof(s->identify_data));
s->identify_set = 1;
@@ -299,6 +305,74 @@ static void ide_set_signature(IDEState *s)
}
}
+typedef struct TrimAIOCB {
+ BlockDriverAIOCB common;
+ QEMUBH *bh;
+ int ret;
+} TrimAIOCB;
+
+static void trim_aio_cancel(BlockDriverAIOCB *acb)
+{
+ TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common);
+
+ qemu_bh_delete(iocb->bh);
+ iocb->bh = NULL;
+ qemu_aio_release(iocb);
+}
+
+static AIOPool trim_aio_pool = {
+ .aiocb_size = sizeof(TrimAIOCB),
+ .cancel = trim_aio_cancel,
+};
+
+static void ide_trim_bh_cb(void *opaque)
+{
+ TrimAIOCB *iocb = opaque;
+
+ iocb->common.cb(iocb->common.opaque, iocb->ret);
+
+ qemu_bh_delete(iocb->bh);
+ iocb->bh = NULL;
+
+ qemu_aio_release(iocb);
+}
+
+BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ TrimAIOCB *iocb;
+ int i, j, ret;
+
+ iocb = qemu_aio_get(&trim_aio_pool, bs, cb, opaque);
+ iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb);
+ iocb->ret = 0;
+
+ for (j = 0; j < qiov->niov; j++) {
+ uint64_t *buffer = qiov->iov[j].iov_base;
+
+ for (i = 0; i < qiov->iov[j].iov_len / 8; i++) {
+ /* 6-byte LBA + 2-byte range per entry */
+ uint64_t entry = le64_to_cpu(buffer[i]);
+ uint64_t sector = entry & 0x0000ffffffffffffULL;
+ uint16_t count = entry >> 48;
+
+ if (count == 0) {
+ break;
+ }
+
+ ret = bdrv_discard(bs, sector, count);
+ if (!iocb->ret) {
+ iocb->ret = ret;
+ }
+ }
+ }
+
+ qemu_bh_schedule(iocb->bh);
+
+ return &iocb->common;
+}
+
static inline void ide_abort_command(IDEState *s)
{
s->status = READY_STAT | ERR_STAT;
@@ -474,6 +548,9 @@ handle_rw_error:
if (s->dma_cmd == IDE_DMA_READ)
op |= BM_STATUS_RETRY_READ;
+ else if (s->dma_cmd == IDE_DMA_TRIM)
+ op |= BM_STATUS_RETRY_TRIM;
+
if (ide_handle_rw_error(s, -ret, op)) {
return;
}
@@ -519,6 +596,10 @@ handle_rw_error:
s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
ide_dma_cb, s);
break;
+ case IDE_DMA_TRIM:
+ s->bus->dma->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
+ ide_issue_trim, ide_dma_cb, s, 1);
+ break;
}
if (!s->bus->dma->aiocb) {
@@ -818,6 +899,18 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
return;
switch(val) {
+ case WIN_DSM:
+ switch (s->feature) {
+ case DSM_TRIM:
+ if (!s->bs) {
+ goto abort_cmd;
+ }
+ ide_sector_start_dma(s, IDE_DMA_TRIM);
+ break;
+ default:
+ goto abort_cmd;
+ }
+ break;
case WIN_IDENTIFY:
if (s->bs && s->drive_kind != IDE_CD) {
if (s->drive_kind != IDE_CFATA)
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index ea3edf5..02e805f 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -62,7 +62,11 @@ typedef struct IDEDMAOps IDEDMAOps;
*/
#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */
/*
- * 0x04->0x07 Reserved
+ * 0x04->0x05 Reserved
+ */
+#define WIN_DSM 0x06
+/*
+ * 0x07 Reserved
*/
#define WIN_SRST 0x08 /* ATAPI soft reset command */
#define WIN_DEVICE_RESET 0x08
@@ -190,6 +194,9 @@ typedef struct IDEDMAOps IDEDMAOps;
#define IDE_DMA_BUF_SECTORS 256
+/* feature values for Data Set Management */
+#define DSM_TRIM 0x01
+
#if (IDE_DMA_BUF_SECTORS < MAX_MULT_SECTORS)
#error "IDE_DMA_BUF_SECTORS must be bigger or equal to MAX_MULT_SECTORS"
#endif
@@ -382,6 +389,7 @@ struct unreported_events {
enum ide_dma_cmd {
IDE_DMA_READ,
IDE_DMA_WRITE,
+ IDE_DMA_TRIM,
};
#define ide_cmd_is_read(s) \
@@ -521,6 +529,7 @@ struct IDEDeviceInfo {
#define BM_STATUS_PIO_RETRY 0x10
#define BM_STATUS_RETRY_READ 0x20
#define BM_STATUS_RETRY_FLUSH 0x40
+#define BM_STATUS_RETRY_TRIM 0x80
#define BM_MIGRATION_COMPAT_STATUS_BITS \
(BM_STATUS_DMA_RETRY | BM_STATUS_PIO_RETRY | \
@@ -591,6 +600,9 @@ void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func);
void ide_transfer_stop(IDEState *s);
void ide_set_inactive(IDEState *s);
+BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque);
/* hw/ide/atapi.c */
void ide_atapi_cmd(IDEState *s);
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 099b8cb..7daeb31 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -154,6 +154,10 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
pmac_ide_transfer_cb, io);
break;
+ case IDE_DMA_TRIM:
+ m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
+ ide_issue_trim, pmac_ide_transfer_cb, s, 1);
+ break;
}
if (!m->aiocb)
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 80c5794..c940375 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -200,8 +200,13 @@ static void bmdma_restart_bh(void *opaque)
is_read = !!(bus->error_status & BM_STATUS_RETRY_READ);
if (bus->error_status & BM_STATUS_DMA_RETRY) {
- bus->error_status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ);
- bmdma_restart_dma(bm, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
+ if (bus->error_status & BM_STATUS_RETRY_TRIM) {
+ bus->error_status &= ~BM_STATUS_RETRY_TRIM;
+ bmdma_restart_dma(bm, IDE_DMA_TRIM);
+ } else {
+ bus->error_status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ);
+ bmdma_restart_dma(bm, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
+ }
} else if (bus->error_status & BM_STATUS_PIO_RETRY) {
bus->error_status &= ~(BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ);
if (is_read) {
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 3f9dc89..d9b8f24 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -125,6 +125,11 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
const char *serial;
DriveInfo *dinfo;
+ if (dev->conf.discard_granularity && dev->conf.discard_granularity != 512) {
+ error_report("discard_granularity must be 512 for ide");
+ return -1;
+ }
+
serial = dev->serial;
if (!serial) {
/* try to fall back to value set with legacy -drive serial=... */
commit 4e1e00515e2522bbae98a0653ea2692ec20851ac
Author: Christoph Hellwig <hch at lst.de>
Date: Thu May 19 10:58:09 2011 +0200
ide: allow other dma comands than read and write
Replace the is_read flag with a dma_cmd flag to allow the dma and
restart logic to handler other commands like TRIM.
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 399b74c..14bda82 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -472,7 +472,7 @@ handle_rw_error:
if (ret < 0) {
int op = BM_STATUS_DMA_RETRY;
- if (s->is_read)
+ if (s->dma_cmd == IDE_DMA_READ)
op |= BM_STATUS_RETRY_READ;
if (ide_handle_rw_error(s, -ret, op)) {
return;
@@ -482,7 +482,7 @@ handle_rw_error:
n = s->io_buffer_size >> 9;
sector_num = ide_get_sector(s);
if (n > 0) {
- dma_buf_commit(s, s->is_read);
+ dma_buf_commit(s, ide_cmd_is_read(s));
sector_num += n;
ide_set_sector(s, sector_num);
s->nsector -= n;
@@ -499,23 +499,26 @@ handle_rw_error:
n = s->nsector;
s->io_buffer_index = 0;
s->io_buffer_size = n * 512;
- if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->is_read) == 0) {
+ if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) == 0) {
/* The PRDs were too short. Reset the Active bit, but don't raise an
* interrupt. */
goto eot;
}
#ifdef DEBUG_AIO
- printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, is_read=%d\n",
- sector_num, n, s->is_read);
+ printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, cmd_cmd=%d\n",
+ sector_num, n, s->dma_cmd);
#endif
- if (s->is_read) {
+ switch (s->dma_cmd) {
+ case IDE_DMA_READ:
s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
ide_dma_cb, s);
- } else {
+ break;
+ case IDE_DMA_WRITE:
s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
ide_dma_cb, s);
+ break;
}
if (!s->bus->dma->aiocb) {
@@ -528,12 +531,12 @@ eot:
ide_set_inactive(s);
}
-static void ide_sector_start_dma(IDEState *s, int is_read)
+static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
{
s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
s->io_buffer_index = 0;
s->io_buffer_size = 0;
- s->is_read = is_read;
+ s->dma_cmd = dma_cmd;
s->bus->dma->ops->start_dma(s->bus->dma, s, ide_dma_cb);
}
@@ -916,7 +919,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
if (!s->bs)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
- ide_sector_start_dma(s, 1);
+ ide_sector_start_dma(s, IDE_DMA_READ);
break;
case WIN_WRITEDMA_EXT:
lba48 = 1;
@@ -925,7 +928,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
if (!s->bs)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
- ide_sector_start_dma(s, 0);
+ ide_sector_start_dma(s, IDE_DMA_WRITE);
s->media_changed = 1;
break;
case WIN_READ_NATIVE_MAX_EXT:
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 8d18cc3..ea3edf5 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -379,6 +379,14 @@ struct unreported_events {
bool new_media;
};
+enum ide_dma_cmd {
+ IDE_DMA_READ,
+ IDE_DMA_WRITE,
+};
+
+#define ide_cmd_is_read(s) \
+ ((s)->dma_cmd == IDE_DMA_READ)
+
/* NOTE: IDEState represents in fact one drive */
struct IDEState {
IDEBus *bus;
@@ -446,7 +454,7 @@ struct IDEState {
uint32_t mdata_size;
uint8_t *mdata_storage;
int media_changed;
- int is_read;
+ enum ide_dma_cmd dma_cmd;
/* SMART */
uint8_t smart_enabled;
uint8_t smart_autosave;
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 7107f6b..099b8cb 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -145,12 +145,17 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
io->addr += io->len;
io->len = 0;
- if (s->is_read)
+ switch (s->dma_cmd) {
+ case IDE_DMA_READ:
m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
pmac_ide_transfer_cb, io);
- else
+ break;
+ case IDE_DMA_WRITE:
m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
pmac_ide_transfer_cb, io);
+ break;
+ }
+
if (!m->aiocb)
pmac_ide_transfer_cb(io, -1);
}
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 7fa32bd..80c5794 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -169,7 +169,7 @@ static int bmdma_set_inactive(IDEDMA *dma)
return 0;
}
-static void bmdma_restart_dma(BMDMAState *bm, int is_read)
+static void bmdma_restart_dma(BMDMAState *bm, enum ide_dma_cmd dma_cmd)
{
IDEState *s = bmdma_active_if(bm);
@@ -177,7 +177,7 @@ static void bmdma_restart_dma(BMDMAState *bm, int is_read)
s->io_buffer_index = 0;
s->io_buffer_size = 0;
s->nsector = bm->nsector;
- s->is_read = is_read;
+ s->dma_cmd = dma_cmd;
bm->cur_addr = bm->addr;
bm->dma_cb = ide_dma_cb;
bmdma_start_dma(&bm->dma, s, bm->dma_cb);
@@ -201,7 +201,7 @@ static void bmdma_restart_bh(void *opaque)
if (bus->error_status & BM_STATUS_DMA_RETRY) {
bus->error_status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ);
- bmdma_restart_dma(bm, is_read);
+ bmdma_restart_dma(bm, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
} else if (bus->error_status & BM_STATUS_PIO_RETRY) {
bus->error_status &= ~(BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ);
if (is_read) {
commit cb144ccb2ffdb3bca4026455074e434d8db34d73
Author: Christoph Hellwig <hch at lst.de>
Date: Thu May 19 10:57:59 2011 +0200
make dma_bdrv_io available to drivers
Make dma_bdrv_io available for drivers, and pass an explicit I/O function
instead of hardcoding bdrv_aio_readv/bdrv_aio_writev. This is required
to implement non-READ/WRITE dma commands in the ide driver, e.g. the
upcoming TRIM support.
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/dma-helpers.c b/dma-helpers.c
index 712ed89..ba7f897 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -47,6 +47,7 @@ typedef struct {
target_phys_addr_t sg_cur_byte;
QEMUIOVector iov;
QEMUBH *bh;
+ DMAIOFunc *io_func;
} DMAAIOCB;
static void dma_bdrv_cb(void *opaque, int ret);
@@ -116,13 +117,8 @@ static void dma_bdrv_cb(void *opaque, int ret)
return;
}
- if (dbs->is_write) {
- dbs->acb = bdrv_aio_writev(dbs->bs, dbs->sector_num, &dbs->iov,
- dbs->iov.size / 512, dma_bdrv_cb, dbs);
- } else {
- dbs->acb = bdrv_aio_readv(dbs->bs, dbs->sector_num, &dbs->iov,
- dbs->iov.size / 512, dma_bdrv_cb, dbs);
- }
+ dbs->acb = dbs->io_func(dbs->bs, dbs->sector_num, &dbs->iov,
+ dbs->iov.size / 512, dma_bdrv_cb, dbs);
if (!dbs->acb) {
dma_bdrv_unmap(dbs);
qemu_iovec_destroy(&dbs->iov);
@@ -144,12 +140,12 @@ static AIOPool dma_aio_pool = {
.cancel = dma_aio_cancel,
};
-static BlockDriverAIOCB *dma_bdrv_io(
+BlockDriverAIOCB *dma_bdrv_io(
BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
- BlockDriverCompletionFunc *cb, void *opaque,
- int is_write)
+ DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
+ void *opaque, int is_write)
{
- DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
+ DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
dbs->acb = NULL;
dbs->bs = bs;
@@ -158,6 +154,7 @@ static BlockDriverAIOCB *dma_bdrv_io(
dbs->sg_cur_index = 0;
dbs->sg_cur_byte = 0;
dbs->is_write = is_write;
+ dbs->io_func = io_func;
dbs->bh = NULL;
qemu_iovec_init(&dbs->iov, sg->nsg);
dma_bdrv_cb(dbs, 0);
@@ -173,12 +170,12 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector,
void (*cb)(void *opaque, int ret), void *opaque)
{
- return dma_bdrv_io(bs, sg, sector, cb, opaque, 0);
+ return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque, 0);
}
BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector,
void (*cb)(void *opaque, int ret), void *opaque)
{
- return dma_bdrv_io(bs, sg, sector, cb, opaque, 1);
+ return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, 1);
}
diff --git a/dma.h b/dma.h
index f3bb275..3d8324b 100644
--- a/dma.h
+++ b/dma.h
@@ -32,6 +32,14 @@ void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
target_phys_addr_t len);
void qemu_sglist_destroy(QEMUSGList *qsg);
+typedef BlockDriverAIOCB *DMAIOFunc(BlockDriverState *bs, int64_t sector_num,
+ QEMUIOVector *iov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque);
+
+BlockDriverAIOCB *dma_bdrv_io(BlockDriverState *bs,
+ QEMUSGList *sg, uint64_t sector_num,
+ DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
+ void *opaque, int is_write);
BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector,
BlockDriverCompletionFunc *cb, void *opaque);
commit 0754f9ecef98ad95442f16657df9721dd5682c3a
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Jun 9 14:15:18 2011 +0200
ide: Add forgotten VMSTATE_END_OF_LIST in subsection
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index e5def8b..399b74c 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1864,6 +1864,7 @@ const VMStateDescription vmstate_ide_atapi_gesn_state = {
.fields = (VMStateField []) {
VMSTATE_BOOL(events.new_media, IDEState),
VMSTATE_BOOL(events.eject_request, IDEState),
+ VMSTATE_END_OF_LIST()
}
};
commit fdc650d76d785ba56b1e87c260ce96d8e22c7cc8
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu Jun 9 14:12:57 2011 +0200
ide: Fix ide_drive_pio_state_needed()
When a failed PIO request caused the VM to stop, we still need to transfer the
PIO state even though DRQ=0 at this point.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index da250ac..e5def8b 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1837,7 +1837,8 @@ static bool ide_drive_pio_state_needed(void *opaque)
{
IDEState *s = opaque;
- return (s->status & DRQ_STAT) != 0;
+ return ((s->status & DRQ_STAT) != 0)
+ || (s->bus->error_status & BM_STATUS_PIO_RETRY);
}
static bool ide_atapi_gesn_needed(void *opaque)
commit def93791f22a3536c3508244ec7d270098484c7d
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu May 26 15:00:34 2011 +0200
ide: Split error status from status register
When adding the werror=stop mode, some flags were added to s->status
which are used to determine what kind of operation should be restarted
when the VM is continued.
Unfortunately, it turns out that s->status is in fact a device register
and as such is visible to the guest (some of the abused bits are even
writable for the guest).
For migration we keep on using the old VMState field (renamed to
migration_compat_status) if the status register doesn't use any of the
previously abused bits. If it does, we use a subsection with a clean copy of
the status register.
The error status is always sent in a subsection if there is any error. It can't
use the old field because errors happen even without PCI.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 95beb17..da250ac 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -446,7 +446,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
|| action == BLOCK_ERR_STOP_ANY) {
s->bus->dma->ops->set_unit(s->bus->dma, s->unit);
- s->bus->dma->ops->add_status(s->bus->dma, op);
+ s->bus->error_status = op;
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
vm_stop(VMSTOP_DISKFULL);
} else {
@@ -1847,6 +1847,13 @@ static bool ide_atapi_gesn_needed(void *opaque)
return s->events.new_media || s->events.eject_request;
}
+static bool ide_error_needed(void *opaque)
+{
+ IDEBus *bus = opaque;
+
+ return (bus->error_status != 0);
+}
+
/* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
const VMStateDescription vmstate_ide_atapi_gesn_state = {
.name ="ide_drive/atapi/gesn_state",
@@ -1921,6 +1928,17 @@ const VMStateDescription vmstate_ide_drive = {
}
};
+const VMStateDescription vmstate_ide_error_status = {
+ .name ="ide_bus/error",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32(error_status, IDEBus),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
const VMStateDescription vmstate_ide_bus = {
.name = "ide_bus",
.version_id = 1,
@@ -1930,6 +1948,14 @@ const VMStateDescription vmstate_ide_bus = {
VMSTATE_UINT8(cmd, IDEBus),
VMSTATE_UINT8(unit, IDEBus),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection []) {
+ {
+ .vmsd = &vmstate_ide_error_status,
+ .needed = ide_error_needed,
+ }, {
+ /* empty */
+ }
}
};
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index c2b35ec..8d18cc3 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -486,6 +486,8 @@ struct IDEBus {
uint8_t unit;
uint8_t cmd;
qemu_irq irq;
+
+ int error_status;
};
struct IDEDevice {
@@ -505,11 +507,17 @@ struct IDEDeviceInfo {
#define BM_STATUS_DMAING 0x01
#define BM_STATUS_ERROR 0x02
#define BM_STATUS_INT 0x04
+
+/* FIXME These are not status register bits */
#define BM_STATUS_DMA_RETRY 0x08
#define BM_STATUS_PIO_RETRY 0x10
#define BM_STATUS_RETRY_READ 0x20
#define BM_STATUS_RETRY_FLUSH 0x40
+#define BM_MIGRATION_COMPAT_STATUS_BITS \
+ (BM_STATUS_DMA_RETRY | BM_STATUS_PIO_RETRY | \
+ BM_STATUS_RETRY_READ | BM_STATUS_RETRY_FLUSH)
+
#define BM_CMD_START 0x01
#define BM_CMD_READ 0x08
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index a4726ad..7fa32bd 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -183,27 +183,33 @@ static void bmdma_restart_dma(BMDMAState *bm, int is_read)
bmdma_start_dma(&bm->dma, s, bm->dma_cb);
}
+/* TODO This should be common IDE code */
static void bmdma_restart_bh(void *opaque)
{
BMDMAState *bm = opaque;
+ IDEBus *bus = bm->bus;
int is_read;
qemu_bh_delete(bm->bh);
bm->bh = NULL;
- is_read = !!(bm->status & BM_STATUS_RETRY_READ);
+ if (bm->unit == (uint8_t) -1) {
+ return;
+ }
- if (bm->status & BM_STATUS_DMA_RETRY) {
- bm->status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ);
+ is_read = !!(bus->error_status & BM_STATUS_RETRY_READ);
+
+ if (bus->error_status & BM_STATUS_DMA_RETRY) {
+ bus->error_status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ);
bmdma_restart_dma(bm, is_read);
- } else if (bm->status & BM_STATUS_PIO_RETRY) {
- bm->status &= ~(BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ);
+ } else if (bus->error_status & BM_STATUS_PIO_RETRY) {
+ bus->error_status &= ~(BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ);
if (is_read) {
ide_sector_read(bmdma_active_if(bm));
} else {
ide_sector_write(bmdma_active_if(bm));
}
- } else if (bm->status & BM_STATUS_RETRY_FLUSH) {
+ } else if (bus->error_status & BM_STATUS_RETRY_FLUSH) {
ide_flush_cache(bmdma_active_if(bm));
}
}
@@ -351,6 +357,43 @@ static bool ide_bmdma_current_needed(void *opaque)
return (bm->cur_prd_len != 0);
}
+static bool ide_bmdma_status_needed(void *opaque)
+{
+ BMDMAState *bm = opaque;
+
+ /* Older versions abused some bits in the status register for internal
+ * error state. If any of these bits are set, we must add a subsection to
+ * transfer the real status register */
+ uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+
+ return ((bm->status & abused_bits) != 0);
+}
+
+static void ide_bmdma_pre_save(void *opaque)
+{
+ BMDMAState *bm = opaque;
+ uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+
+ bm->migration_compat_status =
+ (bm->status & ~abused_bits) | (bm->bus->error_status & abused_bits);
+}
+
+/* This function accesses bm->bus->error_status which is loaded only after
+ * BMDMA itself. This is why the function is called from ide_pci_post_load
+ * instead of being registered with VMState where it would run too early. */
+static int ide_bmdma_post_load(void *opaque, int version_id)
+{
+ BMDMAState *bm = opaque;
+ uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+
+ if (bm->status == 0) {
+ bm->status = bm->migration_compat_status & ~abused_bits;
+ bm->bus->error_status |= bm->migration_compat_status & abused_bits;
+ }
+
+ return 0;
+}
+
static const VMStateDescription vmstate_bmdma_current = {
.name = "ide bmdma_current",
.version_id = 1,
@@ -365,15 +408,26 @@ static const VMStateDescription vmstate_bmdma_current = {
}
};
+const VMStateDescription vmstate_bmdma_status = {
+ .name ="ide bmdma/status",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT8(status, BMDMAState),
+ VMSTATE_END_OF_LIST()
+ }
+};
static const VMStateDescription vmstate_bmdma = {
.name = "ide bmdma",
.version_id = 3,
.minimum_version_id = 0,
.minimum_version_id_old = 0,
+ .pre_save = ide_bmdma_pre_save,
.fields = (VMStateField []) {
VMSTATE_UINT8(cmd, BMDMAState),
- VMSTATE_UINT8(status, BMDMAState),
+ VMSTATE_UINT8(migration_compat_status, BMDMAState),
VMSTATE_UINT32(addr, BMDMAState),
VMSTATE_INT64(sector_num, BMDMAState),
VMSTATE_UINT32(nsector, BMDMAState),
@@ -385,6 +439,9 @@ static const VMStateDescription vmstate_bmdma = {
.vmsd = &vmstate_bmdma_current,
.needed = ide_bmdma_current_needed,
}, {
+ .vmsd = &vmstate_bmdma_status,
+ .needed = ide_bmdma_status_needed,
+ }, {
/* empty */
}
}
@@ -399,7 +456,9 @@ static int ide_pci_post_load(void *opaque, int version_id)
/* current versions always store 0/1, but older version
stored bigger values. We only need last bit */
d->bmdma[i].unit &= 1;
+ ide_bmdma_post_load(&d->bmdma[i], -1);
}
+
return 0;
}
diff --git a/hw/ide/pci.h b/hw/ide/pci.h
index cd72cba..b4f3691 100644
--- a/hw/ide/pci.h
+++ b/hw/ide/pci.h
@@ -22,6 +22,10 @@ typedef struct BMDMAState {
IORange addr_ioport;
QEMUBH *bh;
qemu_irq irq;
+
+ /* Bit 0-2 and 7: BM status register
+ * Bit 3-6: bus->error_status */
+ uint8_t migration_compat_status;
} BMDMAState;
typedef struct PCIIDEState {
commit 9e2a3701a1fcfec0316b9dc1a6cd62869de5542c
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue May 24 16:40:02 2011 +0200
qcow2: Fix in-flight list after qcow2_cache_put failure
If qcow2_cache_put returns an error during cluster allocation and the
allocation fails, it must be removed from the list of in-flight allocations.
Otherwise we'd get a loop in the list when the ACB is used for the next
allocation.
Luckily, this qcow2_cache_put shouldn't fail anyway because the L2 table is
only read, so that qcow2_cache_put doesn't even involve I/O.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
Reviewed-by: Christoph Hellwig <hch at lst.de>
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index c9e7bbd..882f50a 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -796,8 +796,8 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
m->depends_on = old_alloc;
m->nb_clusters = 0;
*num = 0;
- ret = 0;
- goto fail;
+
+ goto out_wait_dependency;
}
}
}
@@ -812,7 +812,6 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
if (cluster_offset < 0) {
- QLIST_REMOVE(m, next_in_flight);
ret = cluster_offset;
goto fail;
}
@@ -825,7 +824,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
out:
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
if (ret < 0) {
- return ret;
+ goto fail_put;
}
m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end);
@@ -835,8 +834,13 @@ out:
return 0;
+out_wait_dependency:
+ return qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+
fail:
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+fail_put:
+ QLIST_REMOVE(m, next_in_flight);
return ret;
}
commit 39aa9a12ccbfd1ca2253fd1dc584bfb13670be47
Author: Devin Nakamura <devin122 at gmail.com>
Date: Thu Jun 9 01:06:43 2011 -0400
Replaced tabs with spaces in block.h and block_int.h
Signed-off-by: Devin Nakamura <devin122 at gmail.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.h b/block.h
index da7d39c..859d1d9 100644
--- a/block.h
+++ b/block.h
@@ -110,7 +110,7 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res);
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
- int sector_num);
+ int sector_num);
BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
@@ -118,7 +118,7 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
- BlockDriverCompletionFunc *cb, void *opaque);
+ BlockDriverCompletionFunc *cb, void *opaque);
void bdrv_aio_cancel(BlockDriverAIOCB *acb);
typedef struct BlockRequest {
@@ -150,7 +150,7 @@ void bdrv_close_all(void);
int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
int bdrv_has_zero_init(BlockDriverState *bs);
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
- int *pnum);
+ int *pnum);
#define BIOS_ATA_TRANSLATION_AUTO 0
#define BIOS_ATA_TRANSLATION_NONE 1
diff --git a/block_int.h b/block_int.h
index fa91337..1e265d2 100644
--- a/block_int.h
+++ b/block_int.h
@@ -203,8 +203,8 @@ struct BlockDriverState {
void *private;
};
-#define CHANGE_MEDIA 0x01
-#define CHANGE_SIZE 0x02
+#define CHANGE_MEDIA 0x01
+#define CHANGE_SIZE 0x02
struct BlockDriverAIOCB {
AIOPool *pool;
commit e67a64a869312eccc1487409aaa03177da4d2f26
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue Jun 7 16:12:58 2011 +0200
vdi: Avoid direct AIO callback
bdrv_aio_* must not call the callback before returning to its caller. In vdi,
this could happen in some error cases. This starts the real requests processing
in a BH to avoid this situation.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/vdi.c b/block/vdi.c
index 4c9e201..261cf9b 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -152,6 +152,7 @@ typedef struct {
/* Buffer for new allocated block. */
void *block_buffer;
void *orig_buf;
+ bool is_write;
int header_modified;
BlockDriverAIOCB *hd_aiocb;
struct iovec hd_iov;
@@ -504,6 +505,8 @@ static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, int64_t sector_num,
acb->hd_aiocb = NULL;
acb->sector_num = sector_num;
acb->qiov = qiov;
+ acb->is_write = is_write;
+
if (qiov->niov > 1) {
acb->buf = qemu_blockalign(bs, qiov->size);
acb->orig_buf = acb->buf;
@@ -542,14 +545,20 @@ static int vdi_schedule_bh(QEMUBHFunc *cb, VdiAIOCB *acb)
}
static void vdi_aio_read_cb(void *opaque, int ret);
+static void vdi_aio_write_cb(void *opaque, int ret);
-static void vdi_aio_read_bh(void *opaque)
+static void vdi_aio_rw_bh(void *opaque)
{
VdiAIOCB *acb = opaque;
logout("\n");
qemu_bh_delete(acb->bh);
acb->bh = NULL;
- vdi_aio_read_cb(opaque, 0);
+
+ if (acb->is_write) {
+ vdi_aio_write_cb(opaque, 0);
+ } else {
+ vdi_aio_read_cb(opaque, 0);
+ }
}
static void vdi_aio_read_cb(void *opaque, int ret)
@@ -597,7 +606,7 @@ static void vdi_aio_read_cb(void *opaque, int ret)
if (bmap_entry == VDI_UNALLOCATED) {
/* Block not allocated, return zeros, no need to wait. */
memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
- ret = vdi_schedule_bh(vdi_aio_read_bh, acb);
+ ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
if (ret < 0) {
goto done;
}
@@ -630,12 +639,23 @@ static BlockDriverAIOCB *vdi_aio_readv(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
VdiAIOCB *acb;
+ int ret;
+
logout("\n");
acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb) {
return NULL;
}
- vdi_aio_read_cb(acb, 0);
+
+ ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
+ if (ret < 0) {
+ if (acb->qiov->niov > 1) {
+ qemu_vfree(acb->orig_buf);
+ }
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
return &acb->common;
}
@@ -789,12 +809,23 @@ static BlockDriverAIOCB *vdi_aio_writev(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
VdiAIOCB *acb;
+ int ret;
+
logout("\n");
acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
if (!acb) {
return NULL;
}
- vdi_aio_write_cb(acb, 0);
+
+ ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
+ if (ret < 0) {
+ if (acb->qiov->niov > 1) {
+ qemu_vfree(acb->orig_buf);
+ }
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
return &acb->common;
}
commit b11a24dee661dd1e1de0dcbc149052ed67b0647a
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue Jun 7 15:20:44 2011 +0200
qcow: Avoid direct AIO callback
bdrv_aio_* must not call the callback before returning to its caller. In qcow,
this could happen in some error cases. This starts the real requests processing
in a BH to avoid this situation.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow.c b/block/qcow.c
index a26c886..227b104 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -496,6 +496,8 @@ typedef struct QCowAIOCB {
uint64_t cluster_offset;
uint8_t *cluster_data;
struct iovec hd_iov;
+ bool is_write;
+ QEMUBH *bh;
QEMUIOVector hd_qiov;
BlockDriverAIOCB *hd_aiocb;
} QCowAIOCB;
@@ -525,6 +527,8 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
acb->hd_aiocb = NULL;
acb->sector_num = sector_num;
acb->qiov = qiov;
+ acb->is_write = is_write;
+
if (qiov->niov > 1) {
acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
if (is_write)
@@ -538,6 +542,38 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
return acb;
}
+static void qcow_aio_read_cb(void *opaque, int ret);
+static void qcow_aio_write_cb(void *opaque, int ret);
+
+static void qcow_aio_rw_bh(void *opaque)
+{
+ QCowAIOCB *acb = opaque;
+ qemu_bh_delete(acb->bh);
+ acb->bh = NULL;
+
+ if (acb->is_write) {
+ qcow_aio_write_cb(opaque, 0);
+ } else {
+ qcow_aio_read_cb(opaque, 0);
+ }
+}
+
+static int qcow_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
+{
+ if (acb->bh) {
+ return -EIO;
+ }
+
+ acb->bh = qemu_bh_new(cb, acb);
+ if (!acb->bh) {
+ return -EIO;
+ }
+
+ qemu_bh_schedule(acb->bh);
+
+ return 0;
+}
+
static void qcow_aio_read_cb(void *opaque, int ret)
{
QCowAIOCB *acb = opaque;
@@ -640,12 +676,21 @@ static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
QCowAIOCB *acb;
+ int ret;
acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb)
return NULL;
- qcow_aio_read_cb(acb, 0);
+ ret = qcow_schedule_bh(qcow_aio_rw_bh, acb);
+ if (ret < 0) {
+ if (acb->qiov->niov > 1) {
+ qemu_vfree(acb->orig_buf);
+ }
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
return &acb->common;
}
@@ -725,6 +770,7 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
{
BDRVQcowState *s = bs->opaque;
QCowAIOCB *acb;
+ int ret;
s->cluster_cache_offset = -1; /* disable compressed cache */
@@ -733,7 +779,15 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
return NULL;
- qcow_aio_write_cb(acb, 0);
+ ret = qcow_schedule_bh(qcow_aio_rw_bh, acb);
+ if (ret < 0) {
+ if (acb->qiov->niov > 1) {
+ qemu_vfree(acb->orig_buf);
+ }
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
return &acb->common;
}
commit 42496d6240bfedc7ac6d92f04f92cff6c2e9f226
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue Jun 7 15:04:32 2011 +0200
qcow2: Avoid direct AIO callback
bdrv_aio_* must not call the callback before returning to its caller. In qcow2,
this could happen in some error cases. This starts the real requests processing
in a BH to avoid this situation.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2.c b/block/qcow2.c
index 8451ded..2c51e7c 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -378,6 +378,7 @@ typedef struct QCowAIOCB {
uint64_t bytes_done;
uint64_t cluster_offset;
uint8_t *cluster_data;
+ bool is_write;
BlockDriverAIOCB *hd_aiocb;
QEMUIOVector hd_qiov;
QEMUBH *bh;
@@ -399,12 +400,19 @@ static AIOPool qcow2_aio_pool = {
};
static void qcow2_aio_read_cb(void *opaque, int ret);
-static void qcow2_aio_read_bh(void *opaque)
+static void qcow2_aio_write_cb(void *opaque, int ret);
+
+static void qcow2_aio_rw_bh(void *opaque)
{
QCowAIOCB *acb = opaque;
qemu_bh_delete(acb->bh);
acb->bh = NULL;
- qcow2_aio_read_cb(opaque, 0);
+
+ if (acb->is_write) {
+ qcow2_aio_write_cb(opaque, 0);
+ } else {
+ qcow2_aio_read_cb(opaque, 0);
+ }
}
static int qcow2_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
@@ -493,14 +501,14 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
goto done;
}
} else {
- ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
+ ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
if (ret < 0)
goto done;
}
} else {
/* Note: in this case, no need to wait */
qemu_iovec_memset(&acb->hd_qiov, 0, 512 * acb->cur_nr_sectors);
- ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
+ ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
if (ret < 0)
goto done;
}
@@ -515,7 +523,7 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
s->cluster_cache + index_in_cluster * 512,
512 * acb->cur_nr_sectors);
- ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
+ ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
if (ret < 0)
goto done;
} else {
@@ -572,6 +580,7 @@ static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num,
acb->hd_aiocb = NULL;
acb->sector_num = sector_num;
acb->qiov = qiov;
+ acb->is_write = is_write;
qemu_iovec_init(&acb->hd_qiov, qiov->niov);
@@ -591,17 +600,22 @@ static BlockDriverAIOCB *qcow2_aio_readv(BlockDriverState *bs,
void *opaque)
{
QCowAIOCB *acb;
+ int ret;
acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb)
return NULL;
- qcow2_aio_read_cb(acb, 0);
+ ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
+ if (ret < 0) {
+ qemu_iovec_destroy(&acb->hd_qiov);
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
return &acb->common;
}
-static void qcow2_aio_write_cb(void *opaque, int ret);
-
static void run_dependent_requests(QCowL2Meta *m)
{
QCowAIOCB *req;
@@ -724,6 +738,7 @@ static BlockDriverAIOCB *qcow2_aio_writev(BlockDriverState *bs,
{
BDRVQcowState *s = bs->opaque;
QCowAIOCB *acb;
+ int ret;
s->cluster_cache_offset = -1; /* disable compressed cache */
@@ -731,7 +746,13 @@ static BlockDriverAIOCB *qcow2_aio_writev(BlockDriverState *bs,
if (!acb)
return NULL;
- qcow2_aio_write_cb(acb, 0);
+ ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
+ if (ret < 0) {
+ qemu_iovec_destroy(&acb->hd_qiov);
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
return &acb->common;
}
commit f79116867ec80ed5d1d10043a3fd9ac8afd182c1
Author: Yang, Wei Y <wei.y.yang at intel.com>
Date: Mon May 30 23:17:42 2011 +0800
kvm: Enable CPU SMEP feature
This patchset enables a new CPU feature SMEP (Supervisor Mode Execution
Protection) in QEMU-KVM. SMEP prevents kernel from executing code in application.
Updated Intel SDM describes this CPU feature. The document will be published soon.
SMEP is identified by CPUID leaf 7 EBX[7], which is 0 before. Get the right value by query KVM kernel module, so that guest can get SMEP through CPUID.
Signed-off-by: Yang, Wei <wei.y.yang at intel.com>
Singed-off-by: Shan, Haitao <haitao.shan at intel.com>
Singed-off-by: Li, Xin <xin.li at intel.com>
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 40a73c7..79e7580 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -1142,6 +1142,19 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx = 0;
*edx = 0;
break;
+ case 7:
+ if (kvm_enabled()) {
+ *eax = kvm_arch_get_supported_cpuid(env, 0x7, count, R_EAX);
+ *ebx = kvm_arch_get_supported_cpuid(env, 0x7, count, R_EBX);
+ *ecx = kvm_arch_get_supported_cpuid(env, 0x7, count, R_ECX);
+ *edx = kvm_arch_get_supported_cpuid(env, 0x7, count, R_EDX);
+ } else {
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ }
+ break;
case 9:
/* Direct Cache Access Information Leaf */
*eax = 0; /* Bits 0-31 in DCA_CAP MSR */
commit b3baa152aaef1905876670590275c2dd0bbb088c
Author: brillywu at viatech.com.cn <brillywu at viatech.com.cn>
Date: Wed Jun 1 09:59:52 2011 +0800
kvm: Add CPUID support for VIA CPU
When KVM is running on VIA CPU with host cpu's model, the
feautures of VIA CPU will be passed into kvm guest by calling
the CPUID instruction for Centaur.
Signed-off-by: BrillyWu<brillywu at viatech.com.cn>
Signed-off-by: KaryJin<karyjin at viatech.com.cn>
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index fe65886..9c3340d 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -438,9 +438,13 @@
#define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
#define CPUID_VENDOR_AMD_1 0x68747541 /* "Auth" */
-#define CPUID_VENDOR_AMD_2 0x69746e65 /* "enti" */
+#define CPUID_VENDOR_AMD_2 0x69746e65 /* "enti" */
#define CPUID_VENDOR_AMD_3 0x444d4163 /* "cAMD" */
+#define CPUID_VENDOR_VIA_1 0x746e6543 /* "Cent" */
+#define CPUID_VENDOR_VIA_2 0x48727561 /* "aurH" */
+#define CPUID_VENDOR_VIA_3 0x736c7561 /* "auls" */
+
#define CPUID_MWAIT_IBE (1 << 1) /* Interrupts can exit capability */
#define CPUID_MWAIT_EMX (1 << 0) /* enumeration supported */
@@ -716,6 +720,9 @@ typedef struct CPUX86State {
uint32_t cpuid_ext3_features;
uint32_t cpuid_apic_id;
int cpuid_vendor_override;
+ /* Store the results of Centaur's CPUID instructions */
+ uint32_t cpuid_xlevel2;
+ uint32_t cpuid_ext4_features;
/* MTRRs */
uint64_t mtrr_fixed[11];
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index e479a4d..40a73c7 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -230,6 +230,9 @@ typedef struct x86_def_t {
char model_id[48];
int vendor_override;
uint32_t flags;
+ /* Store the results of Centaur's CPUID instructions */
+ uint32_t ext4_features;
+ uint32_t xlevel2;
} x86_def_t;
#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -522,6 +525,18 @@ static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
cpu_x86_fill_model_id(x86_cpu_def->model_id);
x86_cpu_def->vendor_override = 0;
+ /* Call Centaur's CPUID instruction. */
+ if (x86_cpu_def->vendor1 == CPUID_VENDOR_VIA_1 &&
+ x86_cpu_def->vendor2 == CPUID_VENDOR_VIA_2 &&
+ x86_cpu_def->vendor3 == CPUID_VENDOR_VIA_3) {
+ host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
+ if (eax >= 0xC0000001) {
+ /* Support VIA max extended level */
+ x86_cpu_def->xlevel2 = eax;
+ host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_def->ext4_features = edx;
+ }
+ }
/*
* Every SVM feature requires emulation support in KVM - so we can't just
@@ -855,6 +870,8 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model)
env->cpuid_xlevel = def->xlevel;
env->cpuid_kvm_features = def->kvm_features;
env->cpuid_svm_features = def->svm_features;
+ env->cpuid_ext4_features = def->ext4_features;
+ env->cpuid_xlevel2 = def->xlevel2;
if (!kvm_enabled()) {
env->cpuid_features &= TCG_FEATURES;
env->cpuid_ext_features &= TCG_EXT_FEATURES;
@@ -1035,8 +1052,18 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
{
/* test if maximum index reached */
if (index & 0x80000000) {
- if (index > env->cpuid_xlevel)
- index = env->cpuid_level;
+ if (index > env->cpuid_xlevel) {
+ if (env->cpuid_xlevel2 > 0) {
+ /* Handle the Centaur's CPUID instruction. */
+ if (index > env->cpuid_xlevel2) {
+ index = env->cpuid_xlevel2;
+ } else if (index < 0xC0000000) {
+ index = env->cpuid_xlevel;
+ }
+ } else {
+ index = env->cpuid_xlevel;
+ }
+ }
} else {
if (index > env->cpuid_level)
index = env->cpuid_level;
@@ -1231,6 +1258,28 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*edx = 0;
}
break;
+ case 0xC0000000:
+ *eax = env->cpuid_xlevel2;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
+ case 0xC0000001:
+ /* Support for VIA CPU's CPUID instruction */
+ *eax = env->cpuid_version;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = env->cpuid_ext4_features;
+ break;
+ case 0xC0000002:
+ case 0xC0000003:
+ case 0xC0000004:
+ /* Reserved for the future, and now filled with zero */
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
default:
/* reserved values: zero */
*eax = 0;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index faedc6c..1ae2d61 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -482,6 +482,21 @@ int kvm_arch_init_vcpu(CPUState *env)
cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
}
+ /* Call Centaur's CPUID instructions they are supported. */
+ if (env->cpuid_xlevel2 > 0) {
+ env->cpuid_ext4_features &=
+ kvm_arch_get_supported_cpuid(env, 0xC0000001, 0, R_EDX);
+ cpu_x86_cpuid(env, 0xC0000000, 0, &limit, &unused, &unused, &unused);
+
+ for (i = 0xC0000000; i <= limit; i++) {
+ c = &cpuid_data.entries[cpuid_i++];
+
+ c->function = i;
+ c->flags = 0;
+ cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ }
+ }
+
cpuid_data.cpuid.nent = cpuid_i;
#ifdef KVM_CAP_MCE
commit 6df658f55c41c583b3f6d6f872e3314ad7fe744c
Author: Markus Armbruster <armbru at redhat.com>
Date: Tue May 24 18:09:10 2011 +0200
usb-ccid: Plug memory leak on qdev exit()
ccid_initfn() allocates CCIDBus dynamically, but there is no exit
callback to free it.
Fix by getting rid of the allocation.
Signed-off-by: Markus Armbruster <armbru at redhat.com>
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index 5b6878b..59c6431 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -255,17 +255,18 @@ enum {
MIGRATION_MIGRATED,
};
-typedef struct CCIDBus CCIDBus;
-typedef struct USBCCIDState USBCCIDState;
+typedef struct CCIDBus {
+ BusState qbus;
+} CCIDBus;
#define MAX_PROTOCOL_SIZE 7
/*
* powered - defaults to true, changed by PowerOn/PowerOff messages
*/
-struct USBCCIDState {
+typedef struct USBCCIDState {
USBDevice dev;
- CCIDBus *bus;
+ CCIDBus bus;
CCIDCardState *card;
CCIDCardInfo *cardinfo; /* caching the info pointer */
BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
@@ -293,7 +294,7 @@ struct USBCCIDState {
uint8_t powered;
uint8_t notify_slot_change;
uint8_t debug;
-};
+} USBCCIDState;
/*
* CCID Spec chapter 4: CCID uses a standard device descriptor per Chapter 9,
@@ -1113,10 +1114,6 @@ static void ccid_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
}
}
-struct CCIDBus {
- BusState qbus;
-};
-
static struct BusInfo ccid_bus_info = {
.name = "ccid-bus",
.size = sizeof(CCIDBus),
@@ -1127,16 +1124,6 @@ static struct BusInfo ccid_bus_info = {
}
};
-static CCIDBus *ccid_bus_new(DeviceState *dev)
-{
- CCIDBus *bus;
-
- bus = FROM_QBUS(CCIDBus, qbus_create(&ccid_bus_info, dev, NULL));
- bus->qbus.allow_hotplug = 1;
-
- return bus;
-}
-
void ccid_card_send_apdu_to_guest(CCIDCardState *card,
uint8_t *apdu, uint32_t len)
{
@@ -1276,7 +1263,8 @@ static int ccid_initfn(USBDevice *dev)
{
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
- s->bus = ccid_bus_new(&dev->qdev);
+ qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
+ s->bus.qbus.allow_hotplug = 1;
s->card = NULL;
s->cardinfo = NULL;
s->migration_state = MIGRATION_NONE;
commit 44dc0ca3d22db732a6c4b7f3e59594fc323113f8
Author: Alon Levy <alevy at redhat.com>
Date: Sun May 15 11:51:28 2011 +0300
libcacard: add libcacard.la target
No flag to configure is required. Instead, added a libcacard.la target that
is not built by default, only when requested explicitly via:
mkdir build
cd build
../configure
make libcacard.la
make install-libcacard
Uses libtool to do actual linking of object files and shared library, and
installing. Tested only under linux, but supposed to work on other systems as
well.
If libtool isn't found you get a message complaining about that, only at build
time (since it is not a default target I did not add a message at configure
time).
New build artifacts:
.libs subdirectories (at <buildroot> and <buildroot>/libcacard)
*.lo files (at same locations as the respective o files)
Added %.lo : %.c rule that uses libtool.
Updated clean rule to clean up those artifacts.
Added specific rule to call dtrace with libtool wrapper (note that because of
a current upstream dtrace bug fixed by systemtap b1568fd85 commit the -fPIC flag
isn't actually passed on. still current dtrace+libtool produced object links fine).
If libtool is missing any of the following targets will complain and exit 1:
any subdir: *.lo
root and libcacard: libcacard.la, libcacard-instsall
Tested to link and load with all tracing backends.
diff --git a/Makefile b/Makefile
index 096480b..b3ffbe2 100644
--- a/Makefile
+++ b/Makefile
@@ -119,6 +119,23 @@ version.o: $(SRC_PATH)/version.rc config-host.mak
version-obj-$(CONFIG_WIN32) += version.o
######################################################################
+# Support building shared library libcacard
+
+.PHONY: libcacard.la install-libcacard
+ifeq ($(LIBTOOL),)
+libcacard.la:
+ @echo "libtool is missing, please install and rerun configure"; exit 1
+
+install-libcacard:
+ @echo "libtool is missing, please install and rerun configure"; exit 1
+else
+libcacard.la: $(GENERATED_HEADERS) $(oslib-obj-y) qemu-malloc.o qemu-timer-common.o $(addsuffix .lo, $(basename $(trace-obj-y)))
+ $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" libcacard.la,)
+
+install-libcacard: libcacard.la
+ $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,)
+endif
+######################################################################
qemu-img.o: qemu-img-cmds.h
qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o: $(GENERATED_HEADERS)
@@ -149,7 +166,8 @@ 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 $(TOOLS) TAGS cscope.* *.pod *~ */*~
+ rm -f *.o *.d *.a *.lo $(TOOLS) 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 qemu-img-cmds.h
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
diff --git a/Makefile.objs b/Makefile.objs
index 52d8b23..f617ed5 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -347,6 +347,14 @@ trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
$(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o")
+ifeq ($(LIBTOOL),)
+trace-dtrace.lo: trace-dtrace.dtrace
+ @echo "missing libtool. please install and rerun configure."; exit 1
+else
+trace-dtrace.lo: trace-dtrace.dtrace
+ $(call quiet-command,libtool --mode=compile --tag=CC dtrace -o $@ -G -s $<, " lt GEN trace-dtrace.o")
+endif
+
simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
ifeq ($(TRACE_BACKEND),dtrace)
diff --git a/configure b/configure
index 767c383..a6e9d1c 100755
--- a/configure
+++ b/configure
@@ -1280,6 +1280,15 @@ if ! has $pkg_config; then
fi
##########################################
+# libtool probe
+
+if ! has libtool; then
+ libtool=
+else
+ libtool=libtool
+fi
+
+##########################################
# Sparse probe
if test "$sparse" != "no" ; then
if has cgcc; then
@@ -3047,6 +3056,7 @@ echo "AR=$ar" >> $config_host_mak
echo "OBJCOPY=$objcopy" >> $config_host_mak
echo "LD=$ld" >> $config_host_mak
echo "WINDRES=$windres" >> $config_host_mak
+echo "LIBTOOL=$libtool" >> $config_host_mak
echo "CFLAGS=$CFLAGS" >> $config_host_mak
echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak
@@ -3580,7 +3590,7 @@ if [ "$source_path" != `pwd` ]; then
# out of tree build
mkdir -p libcacard
rm -f libcacard/Makefile
- ln -s "$source_path/libcacard/Makefile" libcacard/Makefile
+ symlink "$source_path/libcacard/Makefile" libcacard/Makefile
fi
d=libuser
diff --git a/libcacard/Makefile b/libcacard/Makefile
index 1d34df0..9802c37 100644
--- a/libcacard/Makefile
+++ b/libcacard/Makefile
@@ -4,15 +4,39 @@
$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/libcacard)
-QEMU_OBJS=$(addprefix ../, $(oslib-obj-y) $(trace-obj-y) qemu-malloc.o qemu-timer-common.o)
+# objects linked against normal qemu binaries, not compiled with libtool
+QEMU_OBJS=$(addprefix ../,$(oslib-obj-y) qemu-malloc.o qemu-timer-common.o $(trace-obj-y))
+
+# objects linked into a shared library, built with libtool with -fPIC if required
+QEMU_OBJS_LIB=$(addsuffix .lo,$(basename $(QEMU_OBJS)))
QEMU_CFLAGS+=-I../
+libcacard.lib-y=$(addsuffix .lo,$(basename $(libcacard-y)))
+
vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o
- $(call quiet-command,$(CC) $(libcacard_libs) -lrt -o $@ $^," LINK $(TARGET_DIR)$@")
+ $(call quiet-command,$(CC) $(libcacard_libs) -lrt -o $@ $^," LINK $@")
+
+clean:
+ rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient *.lo .libs/* *.la
+ rm -Rf .libs
all: vscclient
-clean:
- rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient
+#########################################################################
+# Rules for building libcacard standalone library
+
+ifeq ($(LIBTOOL),)
+libcacard.la:
+ @echo "libtool is missing, please install and rerun configure"; exit 1
+
+install-libcacard:
+ @echo "libtool is missing, please install and rerun configure"; exit 1
+else
+libcacard.la: $(libcacard.lib-y) $(QEMU_OBJS_LIB)
+ $(call quiet-command,libtool --mode=link --quiet --tag=CC $(CC) $(libcacard_libs) -lrt -rpath $(libdir) -o $@ $^," lt LINK $@")
+install-libcacard: libcacard.la
+ $(INSTALL_DIR) "$(DESTDIR)$(libdir)"
+ libtool --mode=install $(INSTALL_PROG) libcacard.la "$(DESTDIR)$(libdir)"
+endif
diff --git a/rules.mak b/rules.mak
index ed59c9e..612ae37 100644
--- a/rules.mak
+++ b/rules.mak
@@ -17,6 +17,14 @@ QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(*D)/$(*F).d
%.o: %.c
$(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CC $(TARGET_DIR)$@")
+ifeq ($(LIBTOOL),)
+%.lo: %.c
+ @echo "missing libtool. please install and rerun configure"; exit 1
+else
+%.lo: %.c
+ $(call quiet-command,libtool --mode=compile --quiet --tag=CC $(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," lt CC $@")
+endif
+
%.o: %.S
$(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," AS $(TARGET_DIR)$@")
commit 3aa5d2bee8e948deabd7c25a7c6ee963daa56a27
Author: Alon Levy <alevy at redhat.com>
Date: Sun May 15 12:08:59 2011 +0300
configure: add libdir and --libdir
diff --git a/configure b/configure
index c931ae8..767c383 100755
--- a/configure
+++ b/configure
@@ -146,6 +146,7 @@ mandir="\${prefix}/share/man"
datadir="\${prefix}/share/qemu"
docdir="\${prefix}/share/doc/qemu"
bindir="\${prefix}/bin"
+libdir="\${prefix}/lib"
sysconfdir="\${prefix}/etc"
confsuffix="/qemu"
slirp="yes"
@@ -536,6 +537,8 @@ for opt do
;;
--bindir=*) bindir="$optarg"
;;
+ --libdir=*) libdir="$optarg"
+ ;;
--datadir=*) datadir="$optarg"
;;
--docdir=*) docdir="$optarg"
@@ -2617,6 +2620,7 @@ fi
echo "Install prefix $prefix"
echo "BIOS directory `eval echo $datadir`"
echo "binary directory `eval echo $bindir`"
+echo "library directory `eval echo $libdir`"
echo "config directory `eval echo $sysconfdir`"
if test "$mingw32" = "no" ; then
echo "Manual directory `eval echo $mandir`"
@@ -2709,6 +2713,7 @@ echo >> $config_host_mak
echo all: >> $config_host_mak
echo "prefix=$prefix" >> $config_host_mak
echo "bindir=$bindir" >> $config_host_mak
+echo "libdir=$libdir" >> $config_host_mak
echo "mandir=$mandir" >> $config_host_mak
echo "datadir=$datadir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
commit 94cc916a8c7e631afc650cb3c9c2832167b0dd8f
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Fri Jun 10 14:38:08 2011 +0200
usb-uhci: fix expire time initialization.
expire_time must be initialited when the guest activates the
usb scheduler, not at device creation time.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 1503373..75cd231 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -424,6 +424,8 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
case 0x00:
if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
/* start frame processing */
+ s->expire_time = qemu_get_clock_ns(vm_clock) +
+ (get_ticks_per_sec() / FRAME_TIMER_FREQ);
qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
s->status &= ~UHCI_STS_HCHALTED;
} else if (!(val & UHCI_CMD_RS)) {
@@ -1131,8 +1133,6 @@ static int usb_uhci_common_initfn(UHCIState *s)
usb_port_location(&s->ports[i].port, NULL, i+1);
}
s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s);
- s->expire_time = qemu_get_clock_ns(vm_clock) +
- (get_ticks_per_sec() / FRAME_TIMER_FREQ);
s->num_ports_vmstate = NB_PORTS;
QTAILQ_INIT(&s->async_pending);
commit 9bba1eb180cb9b08ee1a53c19c52ee57253ac8c2
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Tue Jun 7 19:50:12 2011 +0100
hw/usb-ohci.c: Implement remote wakeup
Implement the wakeup callback in the OHCI USBPortOps, so that when
a downstream device wakes up it correctly causes the OHCI controller
to come out of suspend.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index ab77434..832dcd6 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -367,6 +367,22 @@ static void ohci_detach(USBPort *port1)
ohci_set_interrupt(s, OHCI_INTR_RHSC);
}
+static void ohci_wakeup(USBDevice *dev)
+{
+ USBBus *bus = usb_bus_from_device(dev);
+ OHCIState *s = container_of(bus, OHCIState, bus);
+ int portnum = dev->port->index;
+ OHCIPort *port = &s->rhport[portnum];
+ if (port->ctrl & OHCI_PORT_PSS) {
+ DPRINTF("usb-ohci: port %d: wakeup\n", portnum);
+ port->ctrl |= OHCI_PORT_PSSC;
+ port->ctrl &= ~OHCI_PORT_PSS;
+ if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
+ ohci_set_interrupt(s, OHCI_INTR_RD);
+ }
+ }
+}
+
/* Reset the controller */
static void ohci_reset(void *opaque)
{
@@ -1675,6 +1691,7 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={
static USBPortOps ohci_port_ops = {
.attach = ohci_attach,
.detach = ohci_detach,
+ .wakeup = ohci_wakeup,
.complete = ohci_async_complete_packet,
};
commit 4b0315d7edcbcfcbb07f7935c6e879b3f49fb99e
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Tue Jun 7 20:02:29 2011 +0100
hw/usb-ohci.c: Ignore writes to HcPeriodCurrentED register
HcPeriodCurrentED is read-only, but Linux writes to it anyway; silently
ignore this rather than printing a warning message.
(Specifically, drivers/usb/host/ohci-hub.c:ohci_rh_resume() writes a
0, in at least kernels 2.6.25 through 2.6.39.)
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 401045a..ab77434 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1575,6 +1575,10 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
ohci->hcca = val & OHCI_HCCA_MASK;
break;
+ case 7: /* HcPeriodCurrentED */
+ /* Ignore writes to this read-only register, Linux does them */
+ break;
+
case 8: /* HcControlHeadED */
ohci->ctrl_head = val & OHCI_EDPTR_MASK;
break;
commit 4001f22ffdd6bc890ffc58e6e1ac75443fe67c97
Author: Brad Hards <bradh at frogmouth.net>
Date: Thu Jun 2 11:18:48 2011 +1000
usb: Use defines for serial bus release number register for EHCI
Signed-off-by: Brad Hards <bradh at frogmouth.net>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index fb01d54..c909127 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -2167,7 +2167,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
// pci_conf[0x50] = 0x01; // power management caps
- pci_set_byte(&pci_conf[0x60], 0x20); // spec release number (2.1.4)
+ pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); // release number (2.1.4)
pci_set_byte(&pci_conf[0x61], 0x20); // frame length adjustment (2.1.5)
pci_set_word(&pci_conf[0x62], 0x00); // port wake up capability (2.1.6)
commit e59d33a7346641aef52deb3e5e577ea6a73a7be9
Author: Brad Hards <bradh at frogmouth.net>
Date: Thu Jun 2 11:18:47 2011 +1000
usb: Use defines for serial bus release number register for UHCI
Signed-off-by: Brad Hards <bradh at frogmouth.net>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 8f504d1..1503373 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1122,7 +1122,7 @@ static int usb_uhci_common_initfn(UHCIState *s)
pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
/* TODO: reset value should be 0. */
pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
- pci_conf[0x60] = 0x10; // release number
+ 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++) {
commit 8e257816b0cb267b0cdfb819449d39f1689e0aa4
Author: Brad Hards <bradh at frogmouth.net>
Date: Thu Jun 2 11:18:46 2011 +1000
usb: Add defines for USB Serial Bus Release Number register
Signed-off-by: Brad Hards <bradh at frogmouth.net>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb.h b/hw/usb.h
index 6097208..06ce058 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -26,6 +26,12 @@
#include "qdev.h"
#include "qemu-queue.h"
+/* Constants related to the USB / PCI interaction */
+#define USB_SBRN 0x60 /* Serial Bus Release Number Register */
+#define USB_RELEASE_1 0x10 /* USB 1.0 */
+#define USB_RELEASE_2 0x20 /* USB 2.0 */
+#define USB_RELEASE_3 0x30 /* USB 3.0 */
+
#define USB_TOKEN_SETUP 0x2d
#define USB_TOKEN_IN 0x69 /* device -> host */
#define USB_TOKEN_OUT 0xe1 /* host -> device */
commit 290a5c60a3d203a62a09c88083456ed3ad20329f
Author: Hans de Goede <hdegoede at redhat.com>
Date: Tue May 31 11:35:29 2011 +0200
usb-bus: Don't detach non attached devices on device exit
This causes an "Error: tried to detach unattached usb device " to be printed,
this can happen when deleting ie a usb host qdev, which did not
get attached (because a device matching the filter never got plugged in).
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 91f2083..480956d 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -84,7 +84,9 @@ static int usb_qdev_exit(DeviceState *qdev)
USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
USBBus *bus = usb_bus_from_device(dev);
- usb_device_detach(dev);
+ if (dev->attached) {
+ usb_device_detach(dev);
+ }
bus->ops->device_destroy(bus, dev);
if (dev->info->handle_destroy) {
dev->info->handle_destroy(dev);
commit 290d26d2e7510fbbcb68a765695b5838af60b3f0
Author: Hans de Goede <hdegoede at redhat.com>
Date: Tue May 31 11:35:27 2011 +0200
usb-bus: Add knowledge of USB_SPEED_SUPER to usb_speed helper
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 874c253..91f2083 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -273,6 +273,7 @@ static const char *usb_speed(unsigned int speed)
[ USB_SPEED_LOW ] = "1.5",
[ USB_SPEED_FULL ] = "12",
[ USB_SPEED_HIGH ] = "480",
+ [ USB_SPEED_SUPER ] = "5000",
};
if (speed >= ARRAY_SIZE(txt))
return "?";
commit f8ddbfbcda3ed83b57df537f2457db25de2cc572
Author: Hans de Goede <hdegoede at redhat.com>
Date: Tue May 31 11:35:26 2011 +0200
usb-linux: Enlarge buffer for descriptors to 8192 bytes
1024 bytes is way to small, one hd UVC webcam I have over here has so
many resolutions its descriptors take op close to 4k. Hopefully 8k will
be enough for all devices.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/usb-linux.c b/usb-linux.c
index a4dfe5c..5d2ec5c 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -115,7 +115,7 @@ typedef struct USBHostDevice {
USBDevice dev;
int fd;
- uint8_t descr[1024];
+ uint8_t descr[8192];
int descr_len;
int configuration;
int ninterfaces;
commit e447fc63530bcd0e50201da3b06e112eab1a851d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Wed Jun 1 14:41:59 2011 +0200
usb: don't call usb_host_device_open from vl.c
Not needed any more, usb-host is qdev-ified these days.
Well, at least the linux version ...
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/vl.c b/vl.c
index d7f905d..c1cc614 100644
--- a/vl.c
+++ b/vl.c
@@ -925,9 +925,13 @@ static int usb_device_add(const char *devname)
goto done;
/* the other ones */
+#ifndef CONFIG_LINUX
+ /* only the linux version is qdev-ified, usb-bsd still needs this */
if (strstart(devname, "host:", &p)) {
dev = usb_host_device_open(p);
- } else if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
+ } else
+#endif
+ if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
dev = usb_bt_init(devname[2] ? hci_init(p) :
bt_new_hci(qemu_find_bt_vlan(0)));
} else {
commit 1f45a81bef8bc4aee98e29bd28bfb21edb623879
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon Jun 6 09:45:20 2011 +0200
usb-linux: only cleanup in host_close when host_open was successful.
diff --git a/usb-linux.c b/usb-linux.c
index a1b1444..a4dfe5c 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1158,9 +1158,9 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
return 0;
fail:
- dev->fd = -1;
- if (fd != -1) {
- close(fd);
+ if (dev->fd != -1) {
+ close(dev->fd);
+ dev->fd = -1;
}
return -1;
}
@@ -1169,7 +1169,7 @@ static int usb_host_close(USBHostDevice *dev)
{
int i;
- if (dev->fd == -1) {
+ if (dev->fd == -1 || !dev->dev.attached) {
return -1;
}
commit 97f8616648b426f35621d7f9165c304a3416cd62
Author: Hans de Goede <hdegoede at redhat.com>
Date: Tue May 31 11:35:24 2011 +0200
usb-linux: Don't try to open the same device twice
If a user wants to redirect 2 identical usb sticks, in theory this is
possible by doing:
usb_add host:1234:5678
usb_add host:1234:5678
But this will lead to us trying to open the first stick twice, since we
don't break the loop after having found a match in our filter list, so the next'
filter list entry will result in us trying to open the same device again.
Fix this by adding the missing break.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/usb-linux.c b/usb-linux.c
index 2e0495e..a1b1444 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1671,6 +1671,7 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
usb_host_open(s, bus_num, addr, port, product_name, speed);
+ break;
}
return 0;
commit 130314f83dc43fc3cc2f431d8cfa1595209673fe
Author: Hans de Goede <hdegoede at redhat.com>
Date: Tue May 31 11:35:22 2011 +0200
usb-linux: Ensure devep != 0
So that we don't index endp_table with a negative index.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/usb-linux.c b/usb-linux.c
index feb4d36..2e0495e 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1029,6 +1029,11 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
}
devep = descriptors[i + 2];
+ if ((devep & 0x0f) == 0) {
+ fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
+ return 1;
+ }
+
switch (descriptors[i + 3] & 0x3) {
case 0x00:
type = USBDEVFS_URB_TYPE_CONTROL;
commit 61c1117f08f4ed6f7e5cfa59cc9e02cf19c8f92d
Author: Hans de Goede <hdegoede at redhat.com>
Date: Tue May 31 11:35:20 2011 +0200
usb-linux: Don't do perror when errno is not set
Note that "op" also is not set, so before this change these error paths
would feed NULL to perror.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/usb-linux.c b/usb-linux.c
index ed1d56a..feb4d36 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -376,7 +376,8 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
i = 0;
dev_descr_len = dev->descr[0];
if (dev_descr_len > dev->descr_len) {
- goto fail;
+ fprintf(stderr, "husb: update iface failed. descr too short\n");
+ return 0;
}
i += dev_descr_len;
@@ -404,7 +405,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
if (i >= dev->descr_len) {
fprintf(stderr,
"husb: update iface failed. no matching configuration\n");
- goto fail;
+ return 0;
}
nb_interfaces = dev->descr[i + 4];
commit f264cfbf4a010e1be879bf2e62d323443989d72f
Author: Hans de Goede <hdegoede at redhat.com>
Date: Tue May 31 11:35:19 2011 +0200
usb-linux: Teach about super speed
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/usb-linux.c b/usb-linux.c
index e990d3a..ed1d56a 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1378,7 +1378,9 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
goto fail;
}
- if (!strcmp(buf, "480")) {
+ if (!strcmp(buf, "5000")) {
+ speed = USB_SPEED_SUPER;
+ } else if (!strcmp(buf, "480")) {
speed = USB_SPEED_HIGH;
} else if (!strcmp(buf, "1.5")) {
speed = USB_SPEED_LOW;
@@ -1522,7 +1524,9 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
goto the_end;
}
- if (!strcmp(line, "480\n")) {
+ if (!strcmp(line, "5000\n")) {
+ speed = USB_SPEED_SUPER;
+ } else if (!strcmp(line, "480\n")) {
speed = USB_SPEED_HIGH;
} else if (!strcmp(line, "1.5\n")) {
speed = USB_SPEED_LOW;
@@ -1799,6 +1803,9 @@ static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,
case USB_SPEED_HIGH:
speed_str = "480";
break;
+ case USB_SPEED_SUPER:
+ speed_str = "5000";
+ break;
default:
speed_str = "?";
break;
commit 3991c35e8586cc42501de1236d0c155e82223540
Author: Hans de Goede <hdegoede at redhat.com>
Date: Tue May 31 11:35:18 2011 +0200
usb-linux: Get speed from sysfs rather then from the connectinfo ioctl
The connectinfo ioctl only differentiates between lo speed devices, and
all other speeds, where as we would like to know the real speed. The real
speed is available in sysfs so use that when available.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/usb-linux.c b/usb-linux.c
index e089485..e990d3a 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1056,10 +1056,9 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
}
static int usb_host_open(USBHostDevice *dev, int bus_num,
- int addr, char *port, const char *prod_name)
+ int addr, char *port, const char *prod_name, int speed)
{
int fd = -1, ret;
- struct usbdevfs_connectinfo ci;
char buf[1024];
if (dev->fd != -1) {
@@ -1114,24 +1113,29 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
goto fail;
}
- ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
- if (ret < 0) {
- perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
- goto fail;
- }
-
- printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
-
ret = usb_linux_update_endp_table(dev);
if (ret) {
goto fail;
}
- if (ci.slow) {
- dev->dev.speed = USB_SPEED_LOW;
- } else {
- dev->dev.speed = USB_SPEED_HIGH;
+ if (speed == -1) {
+ struct usbdevfs_connectinfo ci;
+
+ ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
+ if (ret < 0) {
+ perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
+ goto fail;
+ }
+
+ if (ci.slow) {
+ speed = USB_SPEED_LOW;
+ } else {
+ speed = USB_SPEED_HIGH;
+ }
}
+ dev->dev.speed = speed;
+
+ printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
if (!prod_name || prod_name[0] == '\0') {
snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
@@ -1345,7 +1349,8 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
}
device_count = 0;
- bus_num = addr = speed = class_id = product_id = vendor_id = 0;
+ bus_num = addr = class_id = product_id = vendor_id = 0;
+ speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
for(;;) {
if (fgets(line, sizeof(line), f) == NULL) {
break;
@@ -1655,7 +1660,7 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
}
DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
- usb_host_open(s, bus_num, addr, port, product_name);
+ usb_host_open(s, bus_num, addr, port, product_name, speed);
}
return 0;
commit f72e502e5f0b846a4e4bffd35315e36567da68c8
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue May 31 12:21:43 2011 +0200
usb: documentation update
Add some more informations to docs/usb2.txt about using usb2 (also usb1)
devices.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/docs/usb2.txt b/docs/usb2.txt
index b283c13..5950c71 100644
--- a/docs/usb2.txt
+++ b/docs/usb2.txt
@@ -31,6 +31,91 @@ a complete example:
This attaches a usb tablet to the UHCI adapter and a usb mass storage
device to the EHCI adapter.
+
+More USB tips & tricks
+======================
+
+Recently the usb pass through driver (also known as usb-host) and the
+qemu usb subsystem gained a few capabilities which are available only
+via qdev properties, i,e. when using '-device'.
+
+
+physical port addressing
+------------------------
+
+First you can (for all usb devices) specify the physical port where
+the device will show up in the guest. This can be done using the
+"port" property. UHCI has two root ports (1,2). EHCI has four root
+ports (1-4), the emulated (1.1) USB hub has eight ports.
+
+Plugging a tablet into UHCI port 1 works like this:
+
+ -device usb-tablet,bus=usb.0,port=1
+
+Plugging a hub into UHCI port 2 works like this:
+
+ -device usb-hub,bus=usb.0,port=2
+
+Plugging a virtual usb stick into port 4 of the hub just plugged works
+this way:
+
+ -device usb-storage,bus=usb.0,port=2.4,drive=...
+
+You can do basically the same in the monitor using the device_add
+command. If you want to unplug devices too you should specify some
+unique id which you can use to refer to the device ...
+
+ (qemu) device_add usb-tablet,bus=usb.0,port=1,id=my-tablet
+ (qemu) device_del my-tablet
+
+... when unplugging it with device_del.
+
+
+USB pass through hints
+----------------------
+
+The usb-host driver has a bunch of properties to specify the device
+which should be passed to the guest:
+
+ hostbus=<nr> -- Specifies the bus number the device must be attached
+ to.
+
+ hostaddr=<nr> -- Specifies the device address the device got
+ assigned by the guest os.
+
+ hostport=<str> -- Specifies the physical port the device is attached
+ to.
+
+ vendorid=<hexnr> -- Specifies the vendor ID of the device.
+ productid=<hexnr> -- Specifies the product ID of the device.
+
+In theory you can combine all these properties as you like. In
+practice only a few combinations are useful:
+
+ (1) vendorid+productid -- match for a specific device, pass it to
+ the guest when it shows up somewhere in the host.
+
+ (2) hostbus+hostport -- match for a specific physical port in the
+ host, any device which is plugged in there gets passed to the
+ guest.
+
+ (3) hostbus+hostaddr -- most useful for ad-hoc pass through as the
+ hostaddr isn't stable, the next time you plug in the device it
+ gets a new one ...
+
+Note that USB 1.1 devices are handled by UHCI/OHCI and USB 2.0 by
+EHCI. That means a device plugged into the very same physical port
+may show up on different busses depending on the speed. The port I'm
+using for testing is bus 1 + port 1 for 2.0 devices and bus 3 + port 1
+for 1.1 devices. Passing through any device plugged into that port
+and also assign them to the correct bus can be done this way:
+
+ qemu -M pc ${otheroptions} \
+ -usb \
+ -device usb-ehci,id=ehci \
+ -device usb-host,bus=usb.0,hostbus=3,hostport=1 \
+ -device usb-host,bus=ehci.0,hostbus=1,hostport=1
+
enjoy,
Gerd
commit 025b168ca674e42896c573fdbddf3090c6dc0d8f
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon Jun 6 12:31:34 2011 +0200
usb-ehci: split trace calls to handle arg count limits
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 1778600..fb01d54 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -600,31 +600,37 @@ static int ehci_get_fetch_addr(EHCIState *s, int async)
static void ehci_trace_qh(EHCIQueue *q, target_phys_addr_t addr, EHCIqh *qh)
{
- trace_usb_ehci_qh(q, addr, qh->next,
- qh->current_qtd, qh->next_qtd, qh->altnext_qtd,
- get_field(qh->epchar, QH_EPCHAR_RL),
- get_field(qh->epchar, QH_EPCHAR_MPLEN),
- get_field(qh->epchar, QH_EPCHAR_EPS),
- get_field(qh->epchar, QH_EPCHAR_EP),
- get_field(qh->epchar, QH_EPCHAR_DEVADDR),
- (bool)(qh->epchar & QH_EPCHAR_C),
- (bool)(qh->epchar & QH_EPCHAR_H),
- (bool)(qh->epchar & QH_EPCHAR_DTC),
- (bool)(qh->epchar & QH_EPCHAR_I));
+ /* need three here due to argument count limits */
+ trace_usb_ehci_qh_ptrs(q, addr, qh->next,
+ qh->current_qtd, qh->next_qtd, qh->altnext_qtd);
+ trace_usb_ehci_qh_fields(addr,
+ get_field(qh->epchar, QH_EPCHAR_RL),
+ get_field(qh->epchar, QH_EPCHAR_MPLEN),
+ get_field(qh->epchar, QH_EPCHAR_EPS),
+ get_field(qh->epchar, QH_EPCHAR_EP),
+ get_field(qh->epchar, QH_EPCHAR_DEVADDR));
+ trace_usb_ehci_qh_bits(addr,
+ (bool)(qh->epchar & QH_EPCHAR_C),
+ (bool)(qh->epchar & QH_EPCHAR_H),
+ (bool)(qh->epchar & QH_EPCHAR_DTC),
+ (bool)(qh->epchar & QH_EPCHAR_I));
}
static void ehci_trace_qtd(EHCIQueue *q, target_phys_addr_t addr, EHCIqtd *qtd)
{
- trace_usb_ehci_qtd(q, addr, qtd->next, qtd->altnext,
- get_field(qtd->token, QTD_TOKEN_TBYTES),
- get_field(qtd->token, QTD_TOKEN_CPAGE),
- get_field(qtd->token, QTD_TOKEN_CERR),
- get_field(qtd->token, QTD_TOKEN_PID),
- (bool)(qtd->token & QTD_TOKEN_IOC),
- (bool)(qtd->token & QTD_TOKEN_ACTIVE),
- (bool)(qtd->token & QTD_TOKEN_HALT),
- (bool)(qtd->token & QTD_TOKEN_BABBLE),
- (bool)(qtd->token & QTD_TOKEN_XACTERR));
+ /* need three here due to argument count limits */
+ trace_usb_ehci_qtd_ptrs(q, addr, qtd->next, qtd->altnext);
+ trace_usb_ehci_qtd_fields(addr,
+ get_field(qtd->token, QTD_TOKEN_TBYTES),
+ get_field(qtd->token, QTD_TOKEN_CPAGE),
+ get_field(qtd->token, QTD_TOKEN_CERR),
+ get_field(qtd->token, QTD_TOKEN_PID));
+ trace_usb_ehci_qtd_bits(addr,
+ (bool)(qtd->token & QTD_TOKEN_IOC),
+ (bool)(qtd->token & QTD_TOKEN_ACTIVE),
+ (bool)(qtd->token & QTD_TOKEN_HALT),
+ (bool)(qtd->token & QTD_TOKEN_BABBLE),
+ (bool)(qtd->token & QTD_TOKEN_XACTERR));
}
static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd)
diff --git a/trace-events b/trace-events
index dd69702..f1230f1 100644
--- a/trace-events
+++ b/trace-events
@@ -201,8 +201,12 @@ disable usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val) "wr m
disable usb_ehci_mmio_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)"
disable usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
disable usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
-disable usb_ehci_qh(void *q, uint32_t addr, uint32_t next, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd, int rl, int mplen, int eps, int ep, int devaddr, int c, int h, int dtc, int i) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x - rl %d, mplen %d, eps %d, ep %d, dev %d, c %d, h %d, dtc %d, i %d"
-disable usb_ehci_qtd(void *q, uint32_t addr, uint32_t next, uint32_t altnext, int tbytes, int cpage, int cerr, int pid, int ioc, int active, int halt, int babble, int xacterr) "q %p - QTD @ %08x: next %08x altnext %08x - tbytes %d, cpage %d, cerr %d, pid %d, ioc %d, active %d, halt %d, babble %d, xacterr %d"
+disable usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t next, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x"
+disable usb_ehci_qh_fields(uint32_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ %08x - rl %d, mplen %d, eps %d, ep %d, dev %d"
+disable usb_ehci_qh_bits(uint32_t addr, int c, int h, int dtc, int i) "QH @ %08x - c %d, h %d, dtc %d, i %d"
+disable usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t next, uint32_t altnext) "q %p - QTD @ %08x: next %08x altnext %08x"
+disable usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ %08x - tbytes %d, cpage %d, cerr %d, pid %d"
+disable usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ %08x - ioc %d, active %d, halt %d, babble %d, xacterr %d"
disable usb_ehci_itd(uint32_t addr, uint32_t next, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ %08x: next %08x - mplen %d, mult %d, ep %d, dev %d"
disable usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
disable usb_ehci_port_detach(uint32_t port) "detach port #%d"
commit e654887f3880fb0f6d4d40d15d2977de245a6440
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon May 30 16:09:08 2011 +0200
usb-ehci: itd handling fixes.
This patch fixes a bunch of issues in the itd descriptor handling.
Most important fix is to handle transfers which cross page borders
correctly by looking up the address of the next page. Luckily the
linux uses physically contigous memory so the data used to hits the
correct location even with this bug instead of corrupting guest
memory. Also the transfer length updates for outgoing transfers wasn't
correct.
While being at it DPRINTFs have been replaced by tracepoints.
The isoch_pause logic has been disabled. Not clear to me which propose
this serves and I think it is incorrect too as we just skip processing
itds. Even when no xfer happens we have to clear the active bit.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 7471a2f..1778600 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -198,6 +198,7 @@ typedef struct EHCIitd {
#define ITD_BUFPTR_MAXPKT_MASK 0x000007ff
#define ITD_BUFPTR_MAXPKT_SH 0
#define ITD_BUFPTR_MULT_MASK 0x00000003
+#define ITD_BUFPTR_MULT_SH 0
} EHCIitd;
/* EHCI spec version 1.0 Section 3.4
@@ -628,7 +629,11 @@ static void ehci_trace_qtd(EHCIQueue *q, target_phys_addr_t addr, EHCIqtd *qtd)
static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd)
{
- trace_usb_ehci_itd(addr, itd->next);
+ trace_usb_ehci_itd(addr, itd->next,
+ get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT),
+ get_field(itd->bufptr[2], ITD_BUFPTR_MULT),
+ get_field(itd->bufptr[0], ITD_BUFPTR_EP),
+ get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR));
}
/* queue management */
@@ -1270,41 +1275,51 @@ static int ehci_process_itd(EHCIState *ehci,
USBPort *port;
USBDevice *dev;
int ret;
- int i, j;
- int ptr;
- int pid;
- int pg;
- int len;
- int dir;
- int devadr;
- int endp;
+ uint32_t i, j, len, len1, len2, pid, dir, devaddr, endp;
+ uint32_t pg, off, ptr1, ptr2, max, mult;
dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
- devadr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
+ devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
- /* maxpkt = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT); */
+ max = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
+ mult = get_field(itd->bufptr[2], ITD_BUFPTR_MULT);
for(i = 0; i < 8; i++) {
if (itd->transact[i] & ITD_XACT_ACTIVE) {
- DPRINTF("ISOCHRONOUS active for frame %d, interval %d\n",
- ehci->frindex >> 3, i);
-
- pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
- ptr = (itd->bufptr[pg] & ITD_BUFPTR_MASK) |
- (itd->transact[i] & ITD_XACT_OFFSET_MASK);
- len = get_field(itd->transact[i], ITD_XACT_LENGTH);
+ pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
+ off = itd->transact[i] & ITD_XACT_OFFSET_MASK;
+ ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
+ ptr2 = (itd->bufptr[pg+1] & ITD_BUFPTR_MASK);
+ len = get_field(itd->transact[i], ITD_XACT_LENGTH);
+
+ if (len > max * mult) {
+ len = max * mult;
+ }
if (len > BUFF_SIZE) {
return USB_RET_PROCERR;
}
- DPRINTF("ISOCH: buffer %08X len %d\n", ptr, len);
+ if (off + len > 4096) {
+ /* transfer crosses page border */
+ len2 = off + len - 4096;
+ len1 = len - len2;
+ } else {
+ len1 = len;
+ len2 = 0;
+ }
if (!dir) {
- cpu_physical_memory_rw(ptr, &ehci->ibuffer[0], len, 0);
pid = USB_TOKEN_OUT;
- } else
+ trace_usb_ehci_data(0, pg, off, ptr1 + off, len1, 0);
+ cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 0);
+ if (len2) {
+ trace_usb_ehci_data(0, pg+1, 0, ptr2, len2, len1);
+ cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 0);
+ }
+ } else {
pid = USB_TOKEN_IN;
+ }
ret = USB_RET_NODEV;
@@ -1315,18 +1330,15 @@ static int ehci_process_itd(EHCIState *ehci,
// TODO sometime we will also need to check if we are the port owner
if (!(ehci->portsc[j] &(PORTSC_CONNECT))) {
- DPRINTF("Port %d, no exec, not connected(%08X)\n",
- j, ehci->portsc[j]);
continue;
}
ehci->ipacket.pid = pid;
- ehci->ipacket.devaddr = devadr;
+ ehci->ipacket.devaddr = devaddr;
ehci->ipacket.devep = endp;
ehci->ipacket.data = ehci->ibuffer;
ehci->ipacket.len = len;
- DPRINTF("calling usb_handle_packet\n");
ret = usb_handle_packet(dev, &ehci->ipacket);
if (ret != USB_RET_NODEV) {
@@ -1334,6 +1346,7 @@ static int ehci_process_itd(EHCIState *ehci,
}
}
+#if 0
/* In isoch, there is no facility to indicate a NAK so let's
* instead just complete a zero-byte transaction. Setting
* DBERR seems too draconian.
@@ -1358,24 +1371,40 @@ static int ehci_process_itd(EHCIState *ehci,
DPRINTF("ISOCH: received ACK, clearing pause\n");
ehci->isoch_pause = -1;
}
+#else
+ if (ret == USB_RET_NAK) {
+ ret = 0;
+ }
+#endif
if (ret >= 0) {
- itd->transact[i] &= ~ITD_XACT_ACTIVE;
+ if (!dir) {
+ /* OUT */
+ set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH);
+ } else {
+ /* IN */
+ if (len1 > ret) {
+ len1 = ret;
+ }
+ if (len2 > ret - len1) {
+ len2 = ret - len1;
+ }
+ if (len1) {
+ trace_usb_ehci_data(1, pg, off, ptr1 + off, len1, 0);
+ cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 1);
+ }
+ if (len2) {
+ trace_usb_ehci_data(1, pg+1, 0, ptr2, len2, len1);
+ cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 1);
+ }
+ set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
+ }
if (itd->transact[i] & ITD_XACT_IOC) {
ehci_record_interrupt(ehci, USBSTS_INT);
}
}
-
- if (ret >= 0 && dir) {
- cpu_physical_memory_rw(ptr, &ehci->ibuffer[0], len, 1);
-
- if (ret != len) {
- DPRINTF("ISOCH IN expected %d, got %d\n",
- len, ret);
- set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
- }
- }
+ itd->transact[i] &= ~ITD_XACT_ACTIVE;
}
}
return 0;
diff --git a/trace-events b/trace-events
index 51e2e7c..dd69702 100644
--- a/trace-events
+++ b/trace-events
@@ -203,7 +203,7 @@ disable usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
disable usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
disable usb_ehci_qh(void *q, uint32_t addr, uint32_t next, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd, int rl, int mplen, int eps, int ep, int devaddr, int c, int h, int dtc, int i) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x - rl %d, mplen %d, eps %d, ep %d, dev %d, c %d, h %d, dtc %d, i %d"
disable usb_ehci_qtd(void *q, uint32_t addr, uint32_t next, uint32_t altnext, int tbytes, int cpage, int cerr, int pid, int ioc, int active, int halt, int babble, int xacterr) "q %p - QTD @ %08x: next %08x altnext %08x - tbytes %d, cpage %d, cerr %d, pid %d, ioc %d, active %d, halt %d, babble %d, xacterr %d"
-disable usb_ehci_itd(uint32_t addr, uint32_t next) "ITD @ %08x: next %08x"
+disable usb_ehci_itd(uint32_t addr, uint32_t next, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ %08x: next %08x - mplen %d, mult %d, ep %d, dev %d"
disable usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
disable usb_ehci_port_detach(uint32_t port) "detach port #%d"
disable usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
commit 69bf405b50ae18cdbbb7b8bf08ab1f275d4e0d75
Author: Kevin O'Connor <kevin at koconnor.net>
Date: Sat May 28 11:47:50 2011 -0400
The USB tablet should not claim boot protocol support.
The USB tablet advertises that it supports the "boot" protocol.
However, its reports aren't "boot" protocol compatible. So, it
shouldn't claim that.
Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 8197a86..d711b5c 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -142,7 +142,6 @@ static const USBDescIface desc_iface_tablet = {
.bInterfaceNumber = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
.bInterfaceProtocol = 0x02,
.ndesc = 1,
.descs = (USBDescOther[]) {
commit 46115ac4c4f211b5b9b4d22f7af6ebe91c79a05c
Author: Kevin O'Connor <kevin at koconnor.net>
Date: Sat May 28 11:47:15 2011 -0400
Fix USB mouse Set_Protocol behavior
The QEMU USB mouse claims to support the "boot" protocol
(bInterfaceSubClass is 1). However, the mouse rejects the
Set_Protocol command.
The qemu mouse does support the "boot" protocol specification, so a
simple fix is to enable the Set_Protocol request.
Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 53b261c..8197a86 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -782,13 +782,13 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
goto fail;
break;
case GET_PROTOCOL:
- if (s->kind != USB_KEYBOARD)
+ if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
goto fail;
ret = 1;
data[0] = s->protocol;
break;
case SET_PROTOCOL:
- if (s->kind != USB_KEYBOARD)
+ if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
goto fail;
ret = 0;
s->protocol = value;
commit d05393071ad4cb72ae69f77f9f61fc451251521f
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Fri May 20 22:08:44 2011 +0200
usb-ehci: drop EXECUTING checks.
The state machine doesn't stop in EXECUTING state any more when async
packets are in flight, so the checks are not needed any more and can
be dropped.
Also kick out the check for the frame timer. As we don't stop & sleep
any more on async packets this is obsolete.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 9051571..7471a2f 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -1437,17 +1437,6 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
int again = 0;
uint32_t entry = ehci_get_fetch_addr(ehci, async);
-#if EHCI_DEBUG == 0
- if (qemu_get_clock_ns(vm_clock) / 1000 >= ehci->frame_end_usec) {
- if (async) {
- DPRINTF("FETCHENTRY: FRAME timer elapsed, exit state machine\n");
- goto out;
- } else {
- DPRINTF("FETCHENTRY: WARNING "
- "- frame timer elapsed during periodic\n");
- }
- }
-#endif
if (entry < 0x1000) {
DPRINTF("fetchentry: entry invalid (0x%08x)\n", entry);
ehci_set_state(ehci, async, EST_ACTIVE);
@@ -1952,12 +1941,6 @@ static void ehci_advance_async_state(EHCIState *ehci)
}
ehci_set_state(ehci, async, EST_WAITLISTHEAD);
- /* fall through */
-
- case EST_FETCHENTRY:
- /* fall through */
-
- case EST_EXECUTING:
ehci_advance_state(ehci, async);
break;
@@ -2010,11 +1993,6 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
ehci_advance_state(ehci, async);
break;
- case EST_EXECUTING:
- DPRINTF("PERIODIC state adv for executing\n");
- ehci_advance_state(ehci, async);
- break;
-
default:
/* this should only be due to a developer mistake */
fprintf(stderr, "ehci: Bad periodic state %d. "
@@ -2063,11 +2041,7 @@ static void ehci_frame_timer(void *opaque)
if (frames - i > 10) {
skipped_frames++;
} else {
- // TODO could this cause periodic frames to get skipped if async
- // active?
- if (ehci_get_state(ehci, 1) != EST_EXECUTING) {
- ehci_advance_periodic_state(ehci);
- }
+ ehci_advance_periodic_state(ehci);
}
ehci->last_run_usec += FRAME_TIMER_USEC;
@@ -2082,9 +2056,7 @@ static void ehci_frame_timer(void *opaque)
/* Async is not inside loop since it executes everything it can once
* called
*/
- if (ehci_get_state(ehci, 0) != EST_EXECUTING) {
- ehci_advance_async_state(ehci);
- }
+ ehci_advance_async_state(ehci);
qemu_mod_timer(ehci->frame_timer, expire_time);
}
commit 07771f6fcebdb12de6dca537423f56299ed9b4b9
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon May 23 17:37:12 2011 +0200
usb: cancel async packets on unplug
This patch adds USBBusOps struct with (for now) only a single callback
which is called when a device is about to be destroyed. The USB Host
adapters are implementing this callback and use it to cancel any async
requests which might be in flight before the device actually goes away.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index 1565260..028f3b7 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -247,10 +247,18 @@ static void softusb_attach(USBPort *port)
{
}
+static void softusb_device_destroy(USBBus *bus, USBDevice *dev)
+{
+}
+
static USBPortOps softusb_ops = {
.attach = softusb_attach,
};
+static USBBusOps softusb_bus_ops = {
+ .device_destroy = softusb_device_destroy,
+};
+
static void milkymist_softusb_reset(DeviceState *d)
{
MilkymistSoftUsbState *s =
@@ -294,7 +302,7 @@ static int milkymist_softusb_init(SysBusDevice *dev)
qemu_add_mouse_event_handler(softusb_mouse_event, s, 0, "Milkymist Mouse");
/* create our usb bus */
- usb_bus_new(&s->usbbus, NULL);
+ usb_bus_new(&s->usbbus, &softusb_bus_ops, NULL);
/* our two ports */
usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops,
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index abc7e61..874c253 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -39,9 +39,10 @@ const VMStateDescription vmstate_usb_device = {
}
};
-void usb_bus_new(USBBus *bus, DeviceState *host)
+void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host)
{
qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
+ bus->ops = ops;
bus->busnr = next_usb_bus++;
bus->qbus.allow_hotplug = 1; /* Yes, we can */
QTAILQ_INIT(&bus->free);
@@ -81,8 +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);
usb_device_detach(dev);
+ bus->ops->device_destroy(bus, dev);
if (dev->info->handle_destroy) {
dev->info->handle_destroy(dev);
}
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index dd2752d..9051571 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -685,6 +685,18 @@ static void ehci_queues_rip_unused(EHCIState *ehci)
}
}
+static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev)
+{
+ EHCIQueue *q, *tmp;
+
+ QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+ if (q->packet.owner != dev) {
+ continue;
+ }
+ ehci_free_queue(q);
+ }
+}
+
static void ehci_queues_rip_all(EHCIState *ehci)
{
EHCIQueue *q, *tmp;
@@ -2100,6 +2112,13 @@ 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 = {
@@ -2108,6 +2127,10 @@ static USBPortOps ehci_port_ops = {
.complete = ehci_async_complete_packet,
};
+static USBBusOps ehci_bus_ops = {
+ .device_destroy = ehci_device_destroy,
+};
+
static PCIDeviceInfo ehci_info = {
.qdev.name = "usb-ehci",
.qdev.size = sizeof(EHCIState),
@@ -2170,7 +2193,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
s->irq = s->dev.irq[3];
- usb_bus_new(&s->bus, &s->dev.qdev);
+ usb_bus_new(&s->bus, &ehci_bus_ops, &s->dev.qdev);
for(i = 0; i < NB_PORTS; i++) {
usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
USB_SPEED_MASK_HIGH);
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 6037193..21f35af 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -262,6 +262,7 @@
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 USBPortOps musb_port_ops = {
.attach = musb_attach,
@@ -269,6 +270,10 @@ static USBPortOps musb_port_ops = {
.complete = musb_schedule_cb,
};
+static USBBusOps musb_bus_ops = {
+ .device_destroy = musb_device_destroy,
+};
+
typedef struct MUSBPacket MUSBPacket;
typedef struct MUSBEndPoint MUSBEndPoint;
@@ -361,7 +366,7 @@ struct MUSBState *musb_init(qemu_irq *irqs)
s->ep[i].epnum = i;
}
- usb_bus_new(&s->bus, NULL /* FIXME */);
+ 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);
@@ -778,6 +783,22 @@ 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)
+{
+ MUSBState *s = container_of(bus, MUSBState, bus);
+ int ep, dir;
+
+ for (ep = 0; ep < 16; ep++) {
+ for (dir = 0; dir < 2; dir++) {
+ if (s->ep[ep].packey[dir].p.owner != dev) {
+ continue;
+ }
+ usb_cancel_packet(&s->ep[ep].packey[dir].p);
+ /* status updates needed here? */
+ }
+ }
+}
+
static void musb_tx_rdy(MUSBState *s, int epnum)
{
MUSBEndPoint *ep = s->ep + epnum;
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 8b966f7..401045a 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1644,6 +1644,16 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
}
}
+static void ohci_device_destroy(USBBus *bus, 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;
+ }
+}
+
/* Only dword reads are defined on OHCI register space */
static CPUReadMemoryFunc * const ohci_readfn[3]={
ohci_mem_read,
@@ -1664,6 +1674,10 @@ static USBPortOps ohci_port_ops = {
.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)
{
@@ -1691,7 +1705,7 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
ohci->name = dev->info->name;
- usb_bus_new(&ohci->bus, dev);
+ 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,
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index c0de05b..8f504d1 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -234,6 +234,19 @@ static void uhci_async_validate_end(UHCIState *s)
}
}
+static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
+{
+ UHCIAsync *curr, *n;
+
+ QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
+ if (curr->packet.owner != dev) {
+ continue;
+ }
+ uhci_async_unlink(s, curr);
+ uhci_async_cancel(s, curr);
+ }
+}
+
static void uhci_async_cancel_all(UHCIState *s)
{
UHCIAsync *curr, *n;
@@ -1081,6 +1094,13 @@ 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,
@@ -1088,6 +1108,10 @@ static USBPortOps uhci_port_ops = {
.complete = uhci_async_complete,
};
+static USBBusOps uhci_bus_ops = {
+ .device_destroy = uhci_device_destroy,
+};
+
static int usb_uhci_common_initfn(UHCIState *s)
{
uint8_t *pci_conf = s->dev.config;
@@ -1100,7 +1124,7 @@ static int usb_uhci_common_initfn(UHCIState *s)
pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
pci_conf[0x60] = 0x10; // release number
- usb_bus_new(&s->bus, &s->dev.qdev);
+ 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);
diff --git a/hw/usb.h b/hw/usb.h
index 9882400..6097208 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -132,6 +132,7 @@
#define USB_ENDPOINT_XFER_INT 3
typedef struct USBBus USBBus;
+typedef struct USBBusOps USBBusOps;
typedef struct USBPort USBPort;
typedef struct USBDevice USBDevice;
typedef struct USBDeviceInfo USBDeviceInfo;
@@ -323,6 +324,7 @@ void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
struct USBBus {
BusState qbus;
+ USBBusOps *ops;
int busnr;
int nfree;
int nused;
@@ -331,7 +333,11 @@ struct USBBus {
QTAILQ_ENTRY(USBBus) next;
};
-void usb_bus_new(USBBus *bus, DeviceState *host);
+struct USBBusOps {
+ void (*device_destroy)(USBBus *bus, USBDevice *dev);
+};
+
+void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
USBBus *usb_bus_find(int busnr);
void usb_qdev_register(USBDeviceInfo *info);
void usb_qdev_register_many(USBDeviceInfo *info);
commit 8e4faf3de9d1a8bd3289e5cc69d4ed206e2ed0cf
Author: Hans de Goede <hdegoede at redhat.com>
Date: Mon May 23 14:49:43 2011 +0200
ehci: fix a number of unused-but-set-variable warnings (new with gcc-4.6)
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 156ccd1..dd2752d 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -740,11 +740,9 @@ static void ehci_detach(USBPort *port)
static void ehci_reset(void *opaque)
{
EHCIState *s = opaque;
- uint8_t *pci_conf;
int i;
trace_usb_ehci_reset();
- pci_conf = s->dev.config;
memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
@@ -1268,12 +1266,11 @@ static int ehci_process_itd(EHCIState *ehci,
int dir;
int devadr;
int endp;
- int maxpkt;
dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
devadr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
- maxpkt = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
+ /* maxpkt = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT); */
for(i = 0; i < 8; i++) {
if (itd->transact[i] & ITD_XACT_ACTIVE) {
commit d2bd525fbbebcb108a62963140dad076b476aa5f
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon May 23 09:50:27 2011 +0200
usb-ehci: fix error handling.
Set the correct bits for nodev, stall and babble errors.
Raise errint irq. Fix state transition from WRITEBACK
to the next state.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 5de0cda..156ccd1 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -1114,10 +1114,10 @@ err:
switch(q->usb_status) {
case USB_RET_NODEV:
- fprintf(stderr, "USB no device\n");
+ q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
+ ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
break;
case USB_RET_STALL:
- fprintf(stderr, "USB stall\n");
q->qh.token |= QTD_TOKEN_HALT;
ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
break;
@@ -1133,8 +1133,7 @@ err:
}
break;
case USB_RET_BABBLE:
- fprintf(stderr, "USB babble TODO\n");
- q->qh.token |= QTD_TOKEN_BABBLE;
+ q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
break;
default:
@@ -1792,15 +1791,21 @@ static int ehci_state_writeback(EHCIQueue *q, int async)
put_dwords(NLPTR_GET(q->qtdaddr),(uint32_t *) &q->qh.next_qtd,
sizeof(EHCIqtd) >> 2);
- /* TODO confirm next state. For now, keep going if async
- * but stop after one qtd if periodic
+ /*
+ * EHCI specs say go horizontal here.
+ *
+ * We can also advance the queue here for performance reasons. We
+ * need to take care to only take that shortcut in case we've
+ * processed the qtd just written back without errors, i.e. halt
+ * bit is clear.
*/
- //if (async) {
+ if (q->qh.token & QTD_TOKEN_HALT) {
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+ again = 1;
+ } else {
ehci_set_state(q->ehci, async, EST_ADVANCEQUEUE);
again = 1;
- //} else {
- // ehci_set_state(ehci, async, EST_ACTIVE);
- //}
+ }
return again;
}
commit ba7cb5a86ae2ad8b2b78b9367493f9a0d990bac8
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Fri May 20 17:25:07 2011 +0200
usb-ehci: fix offset writeback in ehci_buffer_rw
Two bugs at once:
First the mask is backwards, so the it used to keeps the offset and
clears the page address, which is not what we need when we update the
offset.
Second the offset calculation is wrong in case head isn't page aligned.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index da22d10..5de0cda 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -1066,6 +1066,7 @@ static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw)
cpu_physical_memory_rw(head, q->buffer + bufpos, tail - head, rw);
bufpos += (tail - head);
+ offset += (tail - head);
bytes -= (tail - head);
if (bytes > 0) {
@@ -1078,8 +1079,7 @@ static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw)
set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
/* save offset into cpage */
- offset = tail - head;
- q->qh.bufptr[0] &= ~QTD_BUFPTR_MASK;
+ q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
q->qh.bufptr[0] |= offset;
return 0;
commit 8ac6d699c453e0f46e601597e371e9ae58c0237e
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu May 19 17:56:19 2011 +0200
usb-ehci: multiqueue support
This patch adds support for keeping multiple queues going at the same
time. One slow device will not affect other devices any more.
The patch adds code to manage EHCIQueue structs. It also does a number
of changes to the state machine:
* The state machine will never ever stop in EXECUTING any more.
Instead it will continue with the next queue (aka HORIZONTALQH) when
the usb device returns USB_RET_ASYNC.
* The state machine will stop processing when it figures it walks in
circles (easy to figure now that we have a EHCIQueue struct for each
QH we've processed). The bailout logic should not be needed any
more. For now it is still in, but will assert() in case it triggers.
* The state machine will just skip queues with a async USBPacket in
flight.
* The state machine will resume processing as soon as the async
USBPacket is finished.
The patch also takes care to flush the QH struct back to guest memory
when needed, so we don't get stale data when (re-)loading it from guest
memory in FETCHQH state.
It also makes the writeback code to not touch the first three dwords of
the QH struct as the EHCI must not write them. This actually fixes a
bug where QH chaining changes (next ptr) by the linux ehci driver where
overwritten by the emulated EHCI.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 3656a35..da22d10 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -345,6 +345,9 @@ enum async_state {
struct EHCIQueue {
EHCIState *ehci;
+ QTAILQ_ENTRY(EHCIQueue) next;
+ bool async_schedule;
+ uint32_t seen, ts;
/* cached data from guest - needs to be flushed
* when guest removes an entry (doorbell, handshake sequence)
@@ -400,7 +403,7 @@ struct EHCIState {
int pstate; // Current state in periodic schedule
USBPort ports[NB_PORTS];
uint32_t usbsts_pending;
- EHCIQueue queue;
+ QTAILQ_HEAD(, EHCIQueue) queues;
uint32_t a_fetch_addr; // which address to look at next
uint32_t p_fetch_addr; // which address to look at next
@@ -594,9 +597,9 @@ static int ehci_get_fetch_addr(EHCIState *s, int async)
return async ? s->a_fetch_addr : s->p_fetch_addr;
}
-static void ehci_trace_qh(EHCIState *s, target_phys_addr_t addr, EHCIqh *qh)
+static void ehci_trace_qh(EHCIQueue *q, target_phys_addr_t addr, EHCIqh *qh)
{
- trace_usb_ehci_qh(addr, qh->next,
+ trace_usb_ehci_qh(q, addr, qh->next,
qh->current_qtd, qh->next_qtd, qh->altnext_qtd,
get_field(qh->epchar, QH_EPCHAR_RL),
get_field(qh->epchar, QH_EPCHAR_MPLEN),
@@ -609,9 +612,9 @@ static void ehci_trace_qh(EHCIState *s, target_phys_addr_t addr, EHCIqh *qh)
(bool)(qh->epchar & QH_EPCHAR_I));
}
-static void ehci_trace_qtd(EHCIState *s, target_phys_addr_t addr, EHCIqtd *qtd)
+static void ehci_trace_qtd(EHCIQueue *q, target_phys_addr_t addr, EHCIqtd *qtd)
{
- trace_usb_ehci_qtd(addr, qtd->next, qtd->altnext,
+ trace_usb_ehci_qtd(q, addr, qtd->next, qtd->altnext,
get_field(qtd->token, QTD_TOKEN_TBYTES),
get_field(qtd->token, QTD_TOKEN_CPAGE),
get_field(qtd->token, QTD_TOKEN_CERR),
@@ -628,6 +631,69 @@ static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd)
trace_usb_ehci_itd(addr, itd->next);
}
+/* queue management */
+
+static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async)
+{
+ EHCIQueue *q;
+
+ q = qemu_mallocz(sizeof(*q));
+ q->ehci = ehci;
+ q->async_schedule = async;
+ QTAILQ_INSERT_HEAD(&ehci->queues, q, next);
+ trace_usb_ehci_queue_action(q, "alloc");
+ return q;
+}
+
+static void ehci_free_queue(EHCIQueue *q)
+{
+ trace_usb_ehci_queue_action(q, "free");
+ if (q->async == EHCI_ASYNC_INFLIGHT) {
+ usb_cancel_packet(&q->packet);
+ }
+ QTAILQ_REMOVE(&q->ehci->queues, q, next);
+ qemu_free(q);
+}
+
+static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr)
+{
+ EHCIQueue *q;
+
+ QTAILQ_FOREACH(q, &ehci->queues, next) {
+ if (addr == q->qhaddr) {
+ return q;
+ }
+ }
+ return NULL;
+}
+
+static void ehci_queues_rip_unused(EHCIState *ehci)
+{
+ EHCIQueue *q, *tmp;
+
+ QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+ if (q->seen) {
+ q->seen = 0;
+ q->ts = ehci->last_run_usec;
+ continue;
+ }
+ if (ehci->last_run_usec < q->ts + 250000) {
+ /* allow 0.25 sec idle */
+ continue;
+ }
+ ehci_free_queue(q);
+ }
+}
+
+static void ehci_queues_rip_all(EHCIState *ehci)
+{
+ EHCIQueue *q, *tmp;
+
+ QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+ ehci_free_queue(q);
+ }
+}
+
/* Attach or detach a device on root hub */
static void ehci_attach(USBPort *port)
@@ -697,6 +763,7 @@ static void ehci_reset(void *opaque)
usb_attach(&s->ports[i], s->ports[i].dev);
}
}
+ ehci_queues_rip_all(s);
}
static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
@@ -1022,8 +1089,8 @@ static void ehci_async_complete_packet(USBDevice *dev, USBPacket *packet)
{
EHCIQueue *q = container_of(packet, EHCIQueue, packet);
- DPRINTF("Async packet complete\n");
- assert(q->async == EHIC_ASYNC_INFLIGHT);
+ trace_usb_ehci_queue_action(q, "wakeup");
+ assert(q->async == EHCI_ASYNC_INFLIGHT);
q->async = EHCI_ASYNC_FINISHED;
q->usb_status = packet->len;
}
@@ -1032,10 +1099,7 @@ static void ehci_execute_complete(EHCIQueue *q)
{
int c_err, reload;
- if (q->async == EHCI_ASYNC_INFLIGHT) {
- DPRINTF("not done yet\n");
- return;
- }
+ assert(q->async != EHCI_ASYNC_INFLIGHT);
q->async = EHCI_ASYNC_NONE;
DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
@@ -1185,10 +1249,6 @@ static int ehci_execute(EHCIQueue *q)
return USB_RET_PROCERR;
}
- if (ret == USB_RET_ASYNC) {
- q->async = EHCI_ASYNC_INFLIGHT;
- }
-
return ret;
}
@@ -1328,10 +1388,12 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
ehci_set_usbsts(ehci, USBSTS_REC);
}
+ ehci_queues_rip_unused(ehci);
+
/* Find the head of the list (4.9.1.1) */
for(i = 0; i < MAX_QH; i++) {
get_dwords(NLPTR_GET(entry), (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
- ehci_trace_qh(ehci, NLPTR_GET(entry), &qh);
+ ehci_trace_qh(NULL, NLPTR_GET(entry), &qh);
if (qh.epchar & QH_EPCHAR_H) {
if (async) {
@@ -1419,11 +1481,34 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
int reload;
entry = ehci_get_fetch_addr(ehci, async);
- q = &ehci->queue; /* temporary */
+ q = ehci_find_queue_by_qh(ehci, entry);
+ if (NULL == q) {
+ q = ehci_alloc_queue(ehci, async);
+ }
q->qhaddr = entry;
+ q->seen++;
+
+ if (q->seen > 1) {
+ /* we are going in circles -- stop processing */
+ ehci_set_state(ehci, async, EST_ACTIVE);
+ q = NULL;
+ goto out;
+ }
get_dwords(NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
- ehci_trace_qh(ehci, NLPTR_GET(q->qhaddr), &q->qh);
+ ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
+
+ if (q->async == EHCI_ASYNC_INFLIGHT) {
+ /* I/O still in progress -- skip queue */
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
+ goto out;
+ }
+ if (q->async == EHCI_ASYNC_FINISHED) {
+ /* I/O finished -- continue processing queue */
+ trace_usb_ehci_queue_action(q, "resume");
+ ehci_set_state(ehci, async, EST_EXECUTING);
+ goto out;
+ }
if (async && (q->qh.epchar & QH_EPCHAR_H)) {
@@ -1542,7 +1627,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q, int async)
int again = 0;
get_dwords(NLPTR_GET(q->qtdaddr),(uint32_t *) &q->qtd, sizeof(EHCIqtd) >> 2);
- ehci_trace_qtd(q->ehci, NLPTR_GET(q->qtdaddr), &q->qtd);
+ ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &q->qtd);
if (q->qtd.token & QTD_TOKEN_ACTIVE) {
ehci_set_state(q->ehci, async, EST_EXECUTE);
@@ -1570,6 +1655,23 @@ static int ehci_state_horizqh(EHCIQueue *q, int async)
return again;
}
+/*
+ * Write the qh back to guest physical memory. This step isn't
+ * in the EHCI spec but we need to do it since we don't share
+ * physical memory with our guest VM.
+ *
+ * The first three dwords are read-only for the EHCI, so skip them
+ * when writing back the qh.
+ */
+static void ehci_flush_qh(EHCIQueue *q)
+{
+ uint32_t *qh = (uint32_t *) &q->qh;
+ uint32_t dwords = sizeof(EHCIqh) >> 2;
+ uint32_t addr = NLPTR_GET(q->qhaddr);
+
+ put_dwords(addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3);
+}
+
static int ehci_state_execute(EHCIQueue *q, int async)
{
int again = 0;
@@ -1614,12 +1716,18 @@ static int ehci_state_execute(EHCIQueue *q, int async)
again = -1;
goto out;
}
- ehci_set_state(q->ehci, async, EST_EXECUTING);
-
- if (q->usb_status != USB_RET_ASYNC) {
+ if (q->usb_status == USB_RET_ASYNC) {
+ ehci_flush_qh(q);
+ trace_usb_ehci_queue_action(q, "suspend");
+ q->async = EHCI_ASYNC_INFLIGHT;
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
again = 1;
+ goto out;
}
+ ehci_set_state(q->ehci, async, EST_EXECUTING);
+ again = 1;
+
out:
return again;
}
@@ -1660,13 +1768,6 @@ static int ehci_state_executing(EHCIQueue *q, int async)
set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
}
- /*
- * Write the qh back to guest physical memory. This step isn't
- * in the EHCI spec but we need to do it since we don't share
- * physical memory with our guest VM.
- */
- put_dwords(NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
-
/* 4.10.5 */
if ((q->usb_status == USB_RET_NAK) || (q->qh.token & QTD_TOKEN_ACTIVE)) {
ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
@@ -1677,6 +1778,7 @@ static int ehci_state_executing(EHCIQueue *q, int async)
again = 1;
out:
+ ehci_flush_qh(q);
return again;
}
@@ -1686,7 +1788,7 @@ static int ehci_state_writeback(EHCIQueue *q, int async)
int again = 0;
/* Write back the QTD from the QH area */
- ehci_trace_qtd(q->ehci, NLPTR_GET(q->qtdaddr), (EHCIqtd*) &q->qh.next_qtd);
+ ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), (EHCIqtd*) &q->qh.next_qtd);
put_dwords(NLPTR_GET(q->qtdaddr),(uint32_t *) &q->qh.next_qtd,
sizeof(EHCIqtd) >> 2);
@@ -1720,11 +1822,14 @@ static void ehci_advance_state(EHCIState *ehci,
* something is wrong with the linked list. TO-DO: why is
* this hack needed?
*/
+ assert(iter < MAX_ITERATIONS);
+#if 0
if (iter > MAX_ITERATIONS) {
DPRINTF("\n*** advance_state: bailing on MAX ITERATIONS***\n");
ehci_set_state(ehci, async, EST_ACTIVE);
break;
}
+#endif
}
switch(ehci_get_state(ehci, async)) {
case EST_WAITLISTHEAD:
@@ -1762,7 +1867,7 @@ static void ehci_advance_state(EHCIState *ehci,
break;
case EST_EXECUTING:
- q = &ehci->queue; /* temporary */
+ assert(q != NULL);
again = ehci_state_executing(q, async);
break;
@@ -1773,6 +1878,7 @@ static void ehci_advance_state(EHCIState *ehci,
default:
fprintf(stderr, "Bad state!\n");
again = -1;
+ assert(0);
break;
}
@@ -1780,6 +1886,7 @@ static void ehci_advance_state(EHCIState *ehci,
fprintf(stderr, "processing error - resetting ehci HC\n");
ehci_reset(ehci);
again = 0;
+ assert(0);
}
}
while (again);
@@ -2070,7 +2177,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
}
s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s);
- s->queue.ehci = s;
+ QTAILQ_INIT(&s->queues);
qemu_register_reset(ehci_reset, s);
diff --git a/trace-events b/trace-events
index 3426e14..51e2e7c 100644
--- a/trace-events
+++ b/trace-events
@@ -201,13 +201,14 @@ disable usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val) "wr m
disable usb_ehci_mmio_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)"
disable usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
disable usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
-disable usb_ehci_qh(uint32_t addr, uint32_t next, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd, int rl, int mplen, int eps, int ep, int devaddr, int c, int h, int dtc, int i) "QH @ %08x: next %08x qtds %08x,%08x,%08x - rl %d, mplen %d, eps %d, ep %d, dev %d, c %d, h %d, dtc %d, i %d"
-disable usb_ehci_qtd(uint32_t addr, uint32_t next, uint32_t altnext, int tbytes, int cpage, int cerr, int pid, int ioc, int active, int halt, int babble, int xacterr) "QH @ %08x: next %08x altnext %08x - tbytes %d, cpage %d, cerr %d, pid %d, ioc %d, active %d, halt %d, babble %d, xacterr %d"
+disable usb_ehci_qh(void *q, uint32_t addr, uint32_t next, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd, int rl, int mplen, int eps, int ep, int devaddr, int c, int h, int dtc, int i) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x - rl %d, mplen %d, eps %d, ep %d, dev %d, c %d, h %d, dtc %d, i %d"
+disable usb_ehci_qtd(void *q, uint32_t addr, uint32_t next, uint32_t altnext, int tbytes, int cpage, int cerr, int pid, int ioc, int active, int halt, int babble, int xacterr) "q %p - QTD @ %08x: next %08x altnext %08x - tbytes %d, cpage %d, cerr %d, pid %d, ioc %d, active %d, halt %d, babble %d, xacterr %d"
disable usb_ehci_itd(uint32_t addr, uint32_t next) "ITD @ %08x: next %08x"
disable usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
disable usb_ehci_port_detach(uint32_t port) "detach port #%d"
disable usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
disable usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t len, uint32_t bufpos) "write %d, cpage %d, offset 0x%03x, addr 0x%08x, len %d, bufpos %d"
+disable usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
# hw/usb-desc.c
disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
commit 0122f47279d18eb79fa63ddc550aa43a98d85faf
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu May 19 10:49:03 2011 +0200
usb-ehci: add queue data struct
Add EHCIQueue struct, move the fields needed to track the queue state
into that struct. Pass the new struct instead of ehci state down to
functions which handle the queue state. Lot of variable references have
changed due to that without an actual functional change.
Replace fetch_addr with two variables, one for async and one for
periodic schedule. Add functions to get and set the fetch address.
Use EHCIQueue->usb_status (old name: EHCIState->exec_status) directly in
ehci_execute_complete instead of passing around the status using a
parameters and the return value.
ehci_state_fetchqh returns a EHCIQueue struct now.
No change in behavior.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index d89cb28..3656a35 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -334,8 +334,37 @@ typedef struct EHCIfstn {
uint32_t backptr; // Standard next link pointer
} EHCIfstn;
-typedef struct {
+typedef struct EHCIQueue EHCIQueue;
+typedef struct EHCIState EHCIState;
+
+enum async_state {
+ EHCI_ASYNC_NONE = 0,
+ EHCI_ASYNC_INFLIGHT,
+ EHCI_ASYNC_FINISHED,
+};
+
+struct EHCIQueue {
+ EHCIState *ehci;
+
+ /* cached data from guest - needs to be flushed
+ * when guest removes an entry (doorbell, handshake sequence)
+ */
+ EHCIqh qh; // copy of current QH (being worked on)
+ uint32_t qhaddr; // address QH read from
+ EHCIqtd qtd; // copy of current QTD (being worked on)
+ uint32_t qtdaddr; // address QTD read from
+
+ USBPacket packet;
+ uint8_t buffer[BUFF_SIZE];
+ int pid;
+ uint32_t tbytes;
+ enum async_state async;
+ int usb_status;
+};
+
+struct EHCIState {
PCIDevice dev;
+ USBBus bus;
qemu_irq irq;
target_phys_addr_t mem_base;
int mem;
@@ -360,6 +389,7 @@ typedef struct {
uint32_t portsc[NB_PORTS];
};
};
+
/*
* Internal states, shadow registers, etc
*/
@@ -369,32 +399,19 @@ typedef struct {
int astate; // Current state in asynchronous schedule
int pstate; // Current state in periodic schedule
USBPort ports[NB_PORTS];
- uint8_t buffer[BUFF_SIZE];
uint32_t usbsts_pending;
+ EHCIQueue queue;
- /* cached data from guest - needs to be flushed
- * when guest removes an entry (doorbell, handshake sequence)
- */
- EHCIqh qh; // copy of current QH (being worked on)
- uint32_t qhaddr; // address QH read from
-
- EHCIqtd qtd; // copy of current QTD (being worked on)
- uint32_t qtdaddr; // address QTD read from
-
- uint32_t itdaddr; // current ITD
-
- uint32_t fetch_addr; // which address to look at next
+ uint32_t a_fetch_addr; // which address to look at next
+ uint32_t p_fetch_addr; // which address to look at next
- USBBus bus;
- USBPacket usb_packet;
- int async_complete;
- uint32_t tbytes;
- int pid;
- int exec_status;
+ USBPacket ipacket;
+ uint8_t ibuffer[BUFF_SIZE];
int isoch_pause;
+
uint32_t last_run_usec;
uint32_t frame_end_usec;
-} EHCIState;
+};
#define SET_LAST_RUN_CLOCK(s) \
(s)->last_run_usec = qemu_get_clock_ns(vm_clock) / 1000;
@@ -563,6 +580,20 @@ static int ehci_get_state(EHCIState *s, int async)
return async ? s->astate : s->pstate;
}
+static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr)
+{
+ if (async) {
+ s->a_fetch_addr = addr;
+ } else {
+ s->p_fetch_addr = addr;
+ }
+}
+
+static int ehci_get_fetch_addr(EHCIState *s, int async)
+{
+ return async ? s->a_fetch_addr : s->p_fetch_addr;
+}
+
static void ehci_trace_qh(EHCIState *s, target_phys_addr_t addr, EHCIqh *qh)
{
trace_usb_ehci_qh(addr, qh->next,
@@ -656,7 +687,6 @@ static void ehci_reset(void *opaque)
s->astate = EST_INACTIVE;
s->pstate = EST_INACTIVE;
- s->async_complete = 0;
s->isoch_pause = -1;
s->attach_poll_counter = 0;
@@ -888,7 +918,7 @@ static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
// 4.10.2
-static int ehci_qh_do_overlay(EHCIState *ehci, EHCIqh *qh, EHCIqtd *qtd)
+static int ehci_qh_do_overlay(EHCIQueue *q)
{
int i;
int dtoggle;
@@ -898,43 +928,43 @@ static int ehci_qh_do_overlay(EHCIState *ehci, EHCIqh *qh, EHCIqtd *qtd)
// remember values in fields to preserve in qh after overlay
- dtoggle = qh->token & QTD_TOKEN_DTOGGLE;
- ping = qh->token & QTD_TOKEN_PING;
+ dtoggle = q->qh.token & QTD_TOKEN_DTOGGLE;
+ ping = q->qh.token & QTD_TOKEN_PING;
- qh->current_qtd = ehci->qtdaddr;
- qh->next_qtd = qtd->next;
- qh->altnext_qtd = qtd->altnext;
- qh->token = qtd->token;
+ q->qh.current_qtd = q->qtdaddr;
+ q->qh.next_qtd = q->qtd.next;
+ q->qh.altnext_qtd = q->qtd.altnext;
+ q->qh.token = q->qtd.token;
- eps = get_field(qh->epchar, QH_EPCHAR_EPS);
+ eps = get_field(q->qh.epchar, QH_EPCHAR_EPS);
if (eps == EHCI_QH_EPS_HIGH) {
- qh->token &= ~QTD_TOKEN_PING;
- qh->token |= ping;
+ q->qh.token &= ~QTD_TOKEN_PING;
+ q->qh.token |= ping;
}
- reload = get_field(qh->epchar, QH_EPCHAR_RL);
- set_field(&qh->altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+ reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+ set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
for (i = 0; i < 5; i++) {
- qh->bufptr[i] = qtd->bufptr[i];
+ q->qh.bufptr[i] = q->qtd.bufptr[i];
}
- if (!(qh->epchar & QH_EPCHAR_DTC)) {
+ if (!(q->qh.epchar & QH_EPCHAR_DTC)) {
// preserve QH DT bit
- qh->token &= ~QTD_TOKEN_DTOGGLE;
- qh->token |= dtoggle;
+ q->qh.token &= ~QTD_TOKEN_DTOGGLE;
+ q->qh.token |= dtoggle;
}
- qh->bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
- qh->bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
+ q->qh.bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
+ q->qh.bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
- put_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+ put_dwords(NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
return 0;
}
-static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
+static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw)
{
int bufpos = 0;
int cpage, offset;
@@ -946,17 +976,17 @@ static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
return 0;
}
- cpage = get_field(qh->token, QTD_TOKEN_CPAGE);
+ cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
if (cpage > 4) {
fprintf(stderr, "cpage out of range (%d)\n", cpage);
return USB_RET_PROCERR;
}
- offset = qh->bufptr[0] & ~QTD_BUFPTR_MASK;
+ offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
do {
/* start and end of this page */
- head = qh->bufptr[cpage] & QTD_BUFPTR_MASK;
+ head = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK;
tail = head + ~QTD_BUFPTR_MASK + 1;
/* add offset into page */
head |= offset;
@@ -966,7 +996,7 @@ static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
}
trace_usb_ehci_data(rw, cpage, offset, head, tail-head, bufpos);
- cpu_physical_memory_rw(head, &buffer[bufpos], tail - head, rw);
+ cpu_physical_memory_rw(head, q->buffer + bufpos, tail - head, rw);
bufpos += (tail - head);
bytes -= (tail - head);
@@ -978,112 +1008,111 @@ static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
} while (bytes > 0);
/* save cpage */
- set_field(&qh->token, cpage, QTD_TOKEN_CPAGE);
+ set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
/* save offset into cpage */
offset = tail - head;
- qh->bufptr[0] &= ~QTD_BUFPTR_MASK;
- qh->bufptr[0] |= offset;
+ q->qh.bufptr[0] &= ~QTD_BUFPTR_MASK;
+ q->qh.bufptr[0] |= offset;
return 0;
}
static void ehci_async_complete_packet(USBDevice *dev, USBPacket *packet)
{
- EHCIState *ehci = container_of(packet, EHCIState, usb_packet);
+ EHCIQueue *q = container_of(packet, EHCIQueue, packet);
DPRINTF("Async packet complete\n");
- ehci->async_complete = 1;
- ehci->exec_status = packet->len;
+ assert(q->async == EHIC_ASYNC_INFLIGHT);
+ q->async = EHCI_ASYNC_FINISHED;
+ q->usb_status = packet->len;
}
-static int ehci_execute_complete(EHCIState *ehci, EHCIqh *qh, int ret)
+static void ehci_execute_complete(EHCIQueue *q)
{
int c_err, reload;
- if (ret == USB_RET_ASYNC && !ehci->async_complete) {
+ if (q->async == EHCI_ASYNC_INFLIGHT) {
DPRINTF("not done yet\n");
- return ret;
+ return;
}
-
- ehci->async_complete = 0;
+ q->async = EHCI_ASYNC_NONE;
DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
- ehci->qhaddr, qh->next, ehci->qtdaddr, ret);
+ q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
- if (ret < 0) {
+ if (q->usb_status < 0) {
err:
/* TO-DO: put this is in a function that can be invoked below as well */
- c_err = get_field(qh->token, QTD_TOKEN_CERR);
+ c_err = get_field(q->qh.token, QTD_TOKEN_CERR);
c_err--;
- set_field(&qh->token, c_err, QTD_TOKEN_CERR);
+ set_field(&q->qh.token, c_err, QTD_TOKEN_CERR);
- switch(ret) {
+ switch(q->usb_status) {
case USB_RET_NODEV:
fprintf(stderr, "USB no device\n");
break;
case USB_RET_STALL:
fprintf(stderr, "USB stall\n");
- qh->token |= QTD_TOKEN_HALT;
- ehci_record_interrupt(ehci, USBSTS_ERRINT);
+ q->qh.token |= QTD_TOKEN_HALT;
+ ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
break;
case USB_RET_NAK:
/* 4.10.3 */
- reload = get_field(qh->epchar, QH_EPCHAR_RL);
- if ((ehci->pid == USB_TOKEN_IN) && reload) {
- int nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
+ reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+ if ((q->pid == USB_TOKEN_IN) && reload) {
+ int nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
nakcnt--;
- set_field(&qh->altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+ set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
} else if (!reload) {
- return USB_RET_NAK;
+ return;
}
break;
case USB_RET_BABBLE:
fprintf(stderr, "USB babble TODO\n");
- qh->token |= QTD_TOKEN_BABBLE;
- ehci_record_interrupt(ehci, USBSTS_ERRINT);
+ q->qh.token |= QTD_TOKEN_BABBLE;
+ ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
break;
default:
- fprintf(stderr, "USB invalid response %d to handle\n", ret);
- /* TO-DO: transaction error */
- ret = USB_RET_PROCERR;
+ /* should not be triggerable */
+ fprintf(stderr, "USB invalid response %d to handle\n", q->usb_status);
+ assert(0);
break;
}
} else {
// DPRINTF("Short packet condition\n");
// TODO check 4.12 for splits
- if ((ret > ehci->tbytes) && (ehci->pid == USB_TOKEN_IN)) {
- ret = USB_RET_BABBLE;
+ if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) {
+ q->usb_status = USB_RET_BABBLE;
goto err;
}
- if (ehci->tbytes && ehci->pid == USB_TOKEN_IN) {
- if (ehci_buffer_rw(ehci->buffer, qh, ret, 1) != 0) {
- return USB_RET_PROCERR;
+ if (q->tbytes && q->pid == USB_TOKEN_IN) {
+ if (ehci_buffer_rw(q, q->usb_status, 1) != 0) {
+ q->usb_status = USB_RET_PROCERR;
+ return;
}
- ehci->tbytes -= ret;
+ q->tbytes -= q->usb_status;
} else {
- ehci->tbytes = 0;
+ q->tbytes = 0;
}
- DPRINTF("updating tbytes to %d\n", ehci->tbytes);
- set_field(&qh->token, ehci->tbytes, QTD_TOKEN_TBYTES);
+ DPRINTF("updating tbytes to %d\n", q->tbytes);
+ set_field(&q->qh.token, q->tbytes, QTD_TOKEN_TBYTES);
}
- qh->token ^= QTD_TOKEN_DTOGGLE;
- qh->token &= ~QTD_TOKEN_ACTIVE;
+ q->qh.token ^= QTD_TOKEN_DTOGGLE;
+ q->qh.token &= ~QTD_TOKEN_ACTIVE;
- if ((ret >= 0) && (qh->token & QTD_TOKEN_IOC)) {
- ehci_record_interrupt(ehci, USBSTS_INT);
+ if ((q->usb_status >= 0) && (q->qh.token & QTD_TOKEN_IOC)) {
+ ehci_record_interrupt(q->ehci, USBSTS_INT);
}
-
- return ret;
}
// 4.10.3
-static int ehci_execute(EHCIState *ehci, EHCIqh *qh)
+static int ehci_execute(EHCIQueue *q)
{
USBPort *port;
USBDevice *dev;
@@ -1092,59 +1121,59 @@ static int ehci_execute(EHCIState *ehci, EHCIqh *qh)
int endp;
int devadr;
- if ( !(qh->token & QTD_TOKEN_ACTIVE)) {
+ if ( !(q->qh.token & QTD_TOKEN_ACTIVE)) {
fprintf(stderr, "Attempting to execute inactive QH\n");
return USB_RET_PROCERR;
}
- ehci->tbytes = (qh->token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
- if (ehci->tbytes > BUFF_SIZE) {
+ q->tbytes = (q->qh.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
+ if (q->tbytes > BUFF_SIZE) {
fprintf(stderr, "Request for more bytes than allowed\n");
return USB_RET_PROCERR;
}
- ehci->pid = (qh->token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
- switch(ehci->pid) {
- case 0: ehci->pid = USB_TOKEN_OUT; break;
- case 1: ehci->pid = USB_TOKEN_IN; break;
- case 2: ehci->pid = USB_TOKEN_SETUP; break;
+ q->pid = (q->qh.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
+ switch(q->pid) {
+ case 0: q->pid = USB_TOKEN_OUT; break;
+ case 1: q->pid = USB_TOKEN_IN; break;
+ case 2: q->pid = USB_TOKEN_SETUP; break;
default: fprintf(stderr, "bad token\n"); break;
}
- if ((ehci->tbytes && ehci->pid != USB_TOKEN_IN) &&
- (ehci_buffer_rw(ehci->buffer, qh, ehci->tbytes, 0) != 0)) {
+ if ((q->tbytes && q->pid != USB_TOKEN_IN) &&
+ (ehci_buffer_rw(q, q->tbytes, 0) != 0)) {
return USB_RET_PROCERR;
}
- endp = get_field(qh->epchar, QH_EPCHAR_EP);
- devadr = get_field(qh->epchar, QH_EPCHAR_DEVADDR);
+ endp = get_field(q->qh.epchar, QH_EPCHAR_EP);
+ devadr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
ret = USB_RET_NODEV;
// TO-DO: associating device with ehci port
for(i = 0; i < NB_PORTS; i++) {
- port = &ehci->ports[i];
+ port = &q->ehci->ports[i];
dev = port->dev;
// TODO sometime we will also need to check if we are the port owner
- if (!(ehci->portsc[i] &(PORTSC_CONNECT))) {
+ if (!(q->ehci->portsc[i] &(PORTSC_CONNECT))) {
DPRINTF("Port %d, no exec, not connected(%08X)\n",
- i, ehci->portsc[i]);
+ i, q->ehci->portsc[i]);
continue;
}
- ehci->usb_packet.pid = ehci->pid;
- ehci->usb_packet.devaddr = devadr;
- ehci->usb_packet.devep = endp;
- ehci->usb_packet.data = ehci->buffer;
- ehci->usb_packet.len = ehci->tbytes;
+ q->packet.pid = q->pid;
+ q->packet.devaddr = devadr;
+ q->packet.devep = endp;
+ q->packet.data = q->buffer;
+ q->packet.len = q->tbytes;
- ret = usb_handle_packet(dev, &ehci->usb_packet);
+ ret = usb_handle_packet(dev, &q->packet);
DPRINTF("submit: qh %x next %x qtd %x pid %x len %d (total %d) endp %x ret %d\n",
- ehci->qhaddr, qh->next, ehci->qtdaddr, ehci->pid,
- ehci->usb_packet.len, ehci->tbytes, endp, ret);
+ q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
+ q->packet.len, q->tbytes, endp, ret);
if (ret != USB_RET_NODEV) {
break;
@@ -1157,7 +1186,7 @@ static int ehci_execute(EHCIState *ehci, EHCIqh *qh)
}
if (ret == USB_RET_ASYNC) {
- ehci->async_complete = 0;
+ q->async = EHCI_ASYNC_INFLIGHT;
}
return ret;
@@ -1204,7 +1233,7 @@ static int ehci_process_itd(EHCIState *ehci,
DPRINTF("ISOCH: buffer %08X len %d\n", ptr, len);
if (!dir) {
- cpu_physical_memory_rw(ptr, &ehci->buffer[0], len, 0);
+ cpu_physical_memory_rw(ptr, &ehci->ibuffer[0], len, 0);
pid = USB_TOKEN_OUT;
} else
pid = USB_TOKEN_IN;
@@ -1223,14 +1252,14 @@ static int ehci_process_itd(EHCIState *ehci,
continue;
}
- ehci->usb_packet.pid = ehci->pid;
- ehci->usb_packet.devaddr = devadr;
- ehci->usb_packet.devep = endp;
- ehci->usb_packet.data = ehci->buffer;
- ehci->usb_packet.len = len;
+ ehci->ipacket.pid = pid;
+ ehci->ipacket.devaddr = devadr;
+ ehci->ipacket.devep = endp;
+ ehci->ipacket.data = ehci->ibuffer;
+ ehci->ipacket.len = len;
DPRINTF("calling usb_handle_packet\n");
- ret = usb_handle_packet(dev, &ehci->usb_packet);
+ ret = usb_handle_packet(dev, &ehci->ipacket);
if (ret != USB_RET_NODEV) {
break;
@@ -1271,7 +1300,7 @@ static int ehci_process_itd(EHCIState *ehci,
}
if (ret >= 0 && dir) {
- cpu_physical_memory_rw(ptr, &ehci->buffer[0], len, 1);
+ cpu_physical_memory_rw(ptr, &ehci->ibuffer[0], len, 1);
if (ret != len) {
DPRINTF("ISOCH IN expected %d, got %d\n",
@@ -1289,7 +1318,7 @@ static int ehci_process_itd(EHCIState *ehci,
*/
static int ehci_state_waitlisthead(EHCIState *ehci, int async)
{
- EHCIqh *qh = &ehci->qh;
+ EHCIqh qh;
int i = 0;
int again = 0;
uint32_t entry = ehci->asynclistaddr;
@@ -1301,21 +1330,21 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
/* Find the head of the list (4.9.1.1) */
for(i = 0; i < MAX_QH; i++) {
- get_dwords(NLPTR_GET(entry), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
- ehci_trace_qh(ehci, NLPTR_GET(entry), qh);
+ get_dwords(NLPTR_GET(entry), (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
+ ehci_trace_qh(ehci, NLPTR_GET(entry), &qh);
- if (qh->epchar & QH_EPCHAR_H) {
+ if (qh.epchar & QH_EPCHAR_H) {
if (async) {
entry |= (NLPTR_TYPE_QH << 1);
}
- ehci->fetch_addr = entry;
+ ehci_set_fetch_addr(ehci, async, entry);
ehci_set_state(ehci, async, EST_FETCHENTRY);
again = 1;
goto out;
}
- entry = qh->next;
+ entry = qh.next;
if (entry == ehci->asynclistaddr) {
break;
}
@@ -1336,7 +1365,7 @@ out:
static int ehci_state_fetchentry(EHCIState *ehci, int async)
{
int again = 0;
- uint32_t entry = ehci->fetch_addr;
+ uint32_t entry = ehci_get_fetch_addr(ehci, async);
#if EHCI_DEBUG == 0
if (qemu_get_clock_ns(vm_clock) / 1000 >= ehci->frame_end_usec) {
@@ -1364,13 +1393,11 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
switch (NLPTR_TYPE_GET(entry)) {
case NLPTR_TYPE_QH:
ehci_set_state(ehci, async, EST_FETCHQH);
- ehci->qhaddr = entry;
again = 1;
break;
case NLPTR_TYPE_ITD:
ehci_set_state(ehci, async, EST_FETCHITD);
- ehci->itdaddr = entry;
again = 1;
break;
@@ -1385,85 +1412,91 @@ out:
return again;
}
-static int ehci_state_fetchqh(EHCIState *ehci, int async)
+static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
{
- EHCIqh *qh = &ehci->qh;
+ uint32_t entry;
+ EHCIQueue *q;
int reload;
- int again = 0;
- get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
- ehci_trace_qh(ehci, NLPTR_GET(ehci->qhaddr), qh);
+ entry = ehci_get_fetch_addr(ehci, async);
+ q = &ehci->queue; /* temporary */
+ q->qhaddr = entry;
- if (async && (qh->epchar & QH_EPCHAR_H)) {
+ get_dwords(NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
+ ehci_trace_qh(ehci, NLPTR_GET(q->qhaddr), &q->qh);
+
+ if (async && (q->qh.epchar & QH_EPCHAR_H)) {
/* EHCI spec version 1.0 Section 4.8.3 & 4.10.1 */
if (ehci->usbsts & USBSTS_REC) {
ehci_clear_usbsts(ehci, USBSTS_REC);
} else {
DPRINTF("FETCHQH: QH 0x%08x. H-bit set, reclamation status reset"
- " - done processing\n", ehci->qhaddr);
+ " - done processing\n", q->qhaddr);
ehci_set_state(ehci, async, EST_ACTIVE);
+ q = NULL;
goto out;
}
}
#if EHCI_DEBUG
- if (ehci->qhaddr != qh->next) {
+ if (q->qhaddr != q->qh.next) {
DPRINTF("FETCHQH: QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
- ehci->qhaddr,
- qh->epchar & QH_EPCHAR_H,
- qh->token & QTD_TOKEN_HALT,
- qh->token & QTD_TOKEN_ACTIVE,
- qh->next);
+ q->qhaddr,
+ q->qh.epchar & QH_EPCHAR_H,
+ q->qh.token & QTD_TOKEN_HALT,
+ q->qh.token & QTD_TOKEN_ACTIVE,
+ q->qh.next);
}
#endif
- reload = get_field(qh->epchar, QH_EPCHAR_RL);
+ reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
if (reload) {
- set_field(&qh->altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+ set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
}
- if (qh->token & QTD_TOKEN_HALT) {
+ if (q->qh.token & QTD_TOKEN_HALT) {
ehci_set_state(ehci, async, EST_HORIZONTALQH);
- again = 1;
- } else if ((qh->token & QTD_TOKEN_ACTIVE) && (qh->current_qtd > 0x1000)) {
- ehci->qtdaddr = qh->current_qtd;
+ } else if ((q->qh.token & QTD_TOKEN_ACTIVE) && (q->qh.current_qtd > 0x1000)) {
+ q->qtdaddr = q->qh.current_qtd;
ehci_set_state(ehci, async, EST_FETCHQTD);
- again = 1;
} else {
/* EHCI spec version 1.0 Section 4.10.2 */
ehci_set_state(ehci, async, EST_ADVANCEQUEUE);
- again = 1;
}
out:
- return again;
+ return q;
}
static int ehci_state_fetchitd(EHCIState *ehci, int async)
{
+ uint32_t entry;
EHCIitd itd;
- get_dwords(NLPTR_GET(ehci->itdaddr),(uint32_t *) &itd,
+ assert(!async);
+ entry = ehci_get_fetch_addr(ehci, async);
+
+ get_dwords(NLPTR_GET(entry),(uint32_t *) &itd,
sizeof(EHCIitd) >> 2);
- ehci_trace_itd(ehci, ehci->itdaddr, &itd);
+ ehci_trace_itd(ehci, entry, &itd);
if (ehci_process_itd(ehci, &itd) != 0) {
return -1;
}
- put_dwords(NLPTR_GET(ehci->itdaddr), (uint32_t *) &itd,
+ put_dwords(NLPTR_GET(entry), (uint32_t *) &itd,
sizeof(EHCIitd) >> 2);
- ehci->fetch_addr = itd.next;
+ ehci_set_fetch_addr(ehci, async, itd.next);
ehci_set_state(ehci, async, EST_FETCHENTRY);
return 1;
}
/* Section 4.10.2 - paragraph 3 */
-static int ehci_state_advqueue(EHCIState *ehci, int async)
+static int ehci_state_advqueue(EHCIQueue *q, int async)
{
#if 0
/* TO-DO: 4.10.2 - paragraph 2
@@ -1479,84 +1512,81 @@ static int ehci_state_advqueue(EHCIState *ehci, int async)
/*
* want data and alt-next qTD is valid
*/
- if (((ehci->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
- (ehci->qh.altnext_qtd > 0x1000) &&
- (NLPTR_TBIT(ehci->qh.altnext_qtd) == 0)) {
- ehci->qtdaddr = ehci->qh.altnext_qtd;
- ehci_set_state(ehci, async, EST_FETCHQTD);
+ if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
+ (q->qh.altnext_qtd > 0x1000) &&
+ (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) {
+ q->qtdaddr = q->qh.altnext_qtd;
+ ehci_set_state(q->ehci, async, EST_FETCHQTD);
/*
* next qTD is valid
*/
- } else if ((ehci->qh.next_qtd > 0x1000) &&
- (NLPTR_TBIT(ehci->qh.next_qtd) == 0)) {
- ehci->qtdaddr = ehci->qh.next_qtd;
- ehci_set_state(ehci, async, EST_FETCHQTD);
+ } else if ((q->qh.next_qtd > 0x1000) &&
+ (NLPTR_TBIT(q->qh.next_qtd) == 0)) {
+ q->qtdaddr = q->qh.next_qtd;
+ ehci_set_state(q->ehci, async, EST_FETCHQTD);
/*
* no valid qTD, try next QH
*/
} else {
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
}
return 1;
}
/* Section 4.10.2 - paragraph 4 */
-static int ehci_state_fetchqtd(EHCIState *ehci, int async)
+static int ehci_state_fetchqtd(EHCIQueue *q, int async)
{
- EHCIqtd *qtd = &ehci->qtd;
int again = 0;
- get_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) qtd, sizeof(EHCIqtd) >> 2);
- ehci_trace_qtd(ehci, NLPTR_GET(ehci->qtdaddr), qtd);
+ get_dwords(NLPTR_GET(q->qtdaddr),(uint32_t *) &q->qtd, sizeof(EHCIqtd) >> 2);
+ ehci_trace_qtd(q->ehci, NLPTR_GET(q->qtdaddr), &q->qtd);
- if (qtd->token & QTD_TOKEN_ACTIVE) {
- ehci_set_state(ehci, async, EST_EXECUTE);
+ if (q->qtd.token & QTD_TOKEN_ACTIVE) {
+ ehci_set_state(q->ehci, async, EST_EXECUTE);
again = 1;
} else {
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
again = 1;
}
return again;
}
-static int ehci_state_horizqh(EHCIState *ehci, int async)
+static int ehci_state_horizqh(EHCIQueue *q, int async)
{
int again = 0;
- if (ehci->fetch_addr != ehci->qh.next) {
- ehci->fetch_addr = ehci->qh.next;
- ehci_set_state(ehci, async, EST_FETCHENTRY);
+ if (ehci_get_fetch_addr(q->ehci, async) != q->qh.next) {
+ ehci_set_fetch_addr(q->ehci, async, q->qh.next);
+ ehci_set_state(q->ehci, async, EST_FETCHENTRY);
again = 1;
} else {
- ehci_set_state(ehci, async, EST_ACTIVE);
+ ehci_set_state(q->ehci, async, EST_ACTIVE);
}
return again;
}
-static int ehci_state_execute(EHCIState *ehci, int async)
+static int ehci_state_execute(EHCIQueue *q, int async)
{
- EHCIqh *qh = &ehci->qh;
- EHCIqtd *qtd = &ehci->qtd;
int again = 0;
int reload, nakcnt;
int smask;
- if (ehci_qh_do_overlay(ehci, qh, qtd) != 0) {
+ if (ehci_qh_do_overlay(q) != 0) {
return -1;
}
- smask = get_field(qh->epcap, QH_EPCAP_SMASK);
+ smask = get_field(q->qh.epcap, QH_EPCAP_SMASK);
if (!smask) {
- reload = get_field(qh->epchar, QH_EPCHAR_RL);
- nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
+ reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+ nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
if (reload && !nakcnt) {
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
again = 1;
goto out;
}
@@ -1567,26 +1597,26 @@ static int ehci_state_execute(EHCIState *ehci, int async)
// TODO Windows does not seem to ever set the MULT field
if (!async) {
- int transactCtr = get_field(qh->epcap, QH_EPCAP_MULT);
+ int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
if (!transactCtr) {
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
again = 1;
goto out;
}
}
if (async) {
- ehci_set_usbsts(ehci, USBSTS_REC);
+ ehci_set_usbsts(q->ehci, USBSTS_REC);
}
- ehci->exec_status = ehci_execute(ehci, qh);
- if (ehci->exec_status == USB_RET_PROCERR) {
+ q->usb_status = ehci_execute(q);
+ if (q->usb_status == USB_RET_PROCERR) {
again = -1;
goto out;
}
- ehci_set_state(ehci, async, EST_EXECUTING);
+ ehci_set_state(q->ehci, async, EST_EXECUTING);
- if (ehci->exec_status != USB_RET_ASYNC) {
+ if (q->usb_status != USB_RET_ASYNC) {
again = 1;
}
@@ -1594,42 +1624,40 @@ out:
return again;
}
-static int ehci_state_executing(EHCIState *ehci, int async)
+static int ehci_state_executing(EHCIQueue *q, int async)
{
- EHCIqh *qh = &ehci->qh;
int again = 0;
int reload, nakcnt;
- ehci->exec_status = ehci_execute_complete(ehci, qh, ehci->exec_status);
- if (ehci->exec_status == USB_RET_ASYNC) {
+ ehci_execute_complete(q);
+ if (q->usb_status == USB_RET_ASYNC) {
goto out;
}
- if (ehci->exec_status == USB_RET_PROCERR) {
+ if (q->usb_status == USB_RET_PROCERR) {
again = -1;
goto out;
}
// 4.10.3
if (!async) {
- int transactCtr = get_field(qh->epcap, QH_EPCAP_MULT);
+ int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
transactCtr--;
- set_field(&qh->epcap, transactCtr, QH_EPCAP_MULT);
+ set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT);
// 4.10.3, bottom of page 82, should exit this state when transaction
// counter decrements to 0
}
-
- reload = get_field(qh->epchar, QH_EPCHAR_RL);
+ reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
if (reload) {
- nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
- if (ehci->exec_status == USB_RET_NAK) {
+ nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
+ if (q->usb_status == USB_RET_NAK) {
if (nakcnt) {
nakcnt--;
}
} else {
nakcnt = reload;
}
- set_field(&qh->altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+ set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
}
/*
@@ -1637,13 +1665,13 @@ static int ehci_state_executing(EHCIState *ehci, int async)
* in the EHCI spec but we need to do it since we don't share
* physical memory with our guest VM.
*/
- put_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+ put_dwords(NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
/* 4.10.5 */
- if ((ehci->exec_status == USB_RET_NAK) || (qh->token & QTD_TOKEN_ACTIVE)) {
- ehci_set_state(ehci, async, EST_HORIZONTALQH);
+ if ((q->usb_status == USB_RET_NAK) || (q->qh.token & QTD_TOKEN_ACTIVE)) {
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
} else {
- ehci_set_state(ehci, async, EST_WRITEBACK);
+ ehci_set_state(q->ehci, async, EST_WRITEBACK);
}
again = 1;
@@ -1653,21 +1681,20 @@ out:
}
-static int ehci_state_writeback(EHCIState *ehci, int async)
+static int ehci_state_writeback(EHCIQueue *q, int async)
{
- EHCIqh *qh = &ehci->qh;
int again = 0;
/* Write back the QTD from the QH area */
- ehci_trace_qtd(ehci, NLPTR_GET(ehci->qtdaddr), (EHCIqtd*) &qh->next_qtd);
- put_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) &qh->next_qtd,
+ ehci_trace_qtd(q->ehci, NLPTR_GET(q->qtdaddr), (EHCIqtd*) &q->qh.next_qtd);
+ put_dwords(NLPTR_GET(q->qtdaddr),(uint32_t *) &q->qh.next_qtd,
sizeof(EHCIqtd) >> 2);
/* TODO confirm next state. For now, keep going if async
* but stop after one qtd if periodic
*/
//if (async) {
- ehci_set_state(ehci, async, EST_ADVANCEQUEUE);
+ ehci_set_state(q->ehci, async, EST_ADVANCEQUEUE);
again = 1;
//} else {
// ehci_set_state(ehci, async, EST_ACTIVE);
@@ -1682,6 +1709,7 @@ static int ehci_state_writeback(EHCIState *ehci, int async)
static void ehci_advance_state(EHCIState *ehci,
int async)
{
+ EHCIQueue *q = NULL;
int again;
int iter = 0;
@@ -1708,7 +1736,8 @@ static void ehci_advance_state(EHCIState *ehci,
break;
case EST_FETCHQH:
- again = ehci_state_fetchqh(ehci, async);
+ q = ehci_state_fetchqh(ehci, async);
+ again = q ? 1 : 0;
break;
case EST_FETCHITD:
@@ -1716,28 +1745,29 @@ static void ehci_advance_state(EHCIState *ehci,
break;
case EST_ADVANCEQUEUE:
- again = ehci_state_advqueue(ehci, async);
+ again = ehci_state_advqueue(q, async);
break;
case EST_FETCHQTD:
- again = ehci_state_fetchqtd(ehci, async);
+ again = ehci_state_fetchqtd(q, async);
break;
case EST_HORIZONTALQH:
- again = ehci_state_horizqh(ehci, async);
+ again = ehci_state_horizqh(q, async);
break;
case EST_EXECUTE:
iter = 0;
- again = ehci_state_execute(ehci, async);
+ again = ehci_state_execute(q, async);
break;
case EST_EXECUTING:
- again = ehci_state_executing(ehci, async);
+ q = &ehci->queue; /* temporary */
+ again = ehci_state_executing(q, async);
break;
case EST_WRITEBACK:
- again = ehci_state_writeback(ehci, async);
+ again = ehci_state_writeback(q, async);
break;
default:
@@ -1759,7 +1789,6 @@ static void ehci_advance_state(EHCIState *ehci,
static void ehci_advance_async_state(EHCIState *ehci)
{
- EHCIqh qh;
int async = 1;
switch(ehci_get_state(ehci, async)) {
@@ -1808,8 +1837,6 @@ static void ehci_advance_async_state(EHCIState *ehci)
/* fall through */
case EST_EXECUTING:
- get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) &qh,
- sizeof(EHCIqh) >> 2);
ehci_advance_state(ehci, async);
break;
@@ -1817,7 +1844,7 @@ static void ehci_advance_async_state(EHCIState *ehci)
/* this should only be due to a developer mistake */
fprintf(stderr, "ehci: Bad asynchronous state %d. "
"Resetting to active\n", ehci->astate);
- ehci_set_state(ehci, async, EST_ACTIVE);
+ assert(0);
}
}
@@ -1857,7 +1884,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
ehci->frindex / 8, list, entry);
- ehci->fetch_addr = entry;
+ ehci_set_fetch_addr(ehci, async,entry);
ehci_set_state(ehci, async, EST_FETCHENTRY);
ehci_advance_state(ehci, async);
break;
@@ -1871,7 +1898,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
/* this should only be due to a developer mistake */
fprintf(stderr, "ehci: Bad periodic state %d. "
"Resetting to active\n", ehci->pstate);
- ehci_set_state(ehci, async, EST_ACTIVE);
+ assert(0);
}
}
@@ -2043,6 +2070,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
}
s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s);
+ s->queue.ehci = s;
qemu_register_reset(ehci_reset, s);
commit f2c88dc10e9258ba57f5edaeb3670259fb6ac2b9
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu May 19 09:24:00 2011 +0200
usb-ehci: trace buffer copy
Add a trace point for buffer copies and drop the DPRINTF's.
No change in behavior.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index b9204ab..d89cb28 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -901,8 +901,6 @@ static int ehci_qh_do_overlay(EHCIState *ehci, EHCIqh *qh, EHCIqtd *qtd)
dtoggle = qh->token & QTD_TOKEN_DTOGGLE;
ping = qh->token & QTD_TOKEN_PING;
- DPRINTF("setting qh.current from %08X to 0x%08X\n", qh->current_qtd,
- ehci->qtdaddr);
qh->current_qtd = ehci->qtdaddr;
qh->next_qtd = qtd->next;
qh->altnext_qtd = qtd->altnext;
@@ -955,8 +953,6 @@ static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
}
offset = qh->bufptr[0] & ~QTD_BUFPTR_MASK;
- DPRINTF("ehci_buffer_rw: %sing %d bytes %08x cpage %d offset %d\n",
- rw ? "writ" : "read", bytes, qh->bufptr[0], cpage, offset);
do {
/* start and end of this page */
@@ -969,9 +965,7 @@ static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
tail = head + bytes;
}
- DPRINTF("DATA %s cpage:%d head:%08X tail:%08X target:%08X\n",
- rw ? "WRITE" : "READ ", cpage, head, tail, bufpos);
-
+ trace_usb_ehci_data(rw, cpage, offset, head, tail-head, bufpos);
cpu_physical_memory_rw(head, &buffer[bufpos], tail - head, rw);
bufpos += (tail - head);
diff --git a/trace-events b/trace-events
index 1ee711e..3426e14 100644
--- a/trace-events
+++ b/trace-events
@@ -207,6 +207,7 @@ disable usb_ehci_itd(uint32_t addr, uint32_t next) "ITD @ %08x: next %08x"
disable usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
disable usb_ehci_port_detach(uint32_t port) "detach port #%d"
disable usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
+disable usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t len, uint32_t bufpos) "write %d, cpage %d, offset 0x%03x, addr 0x%08x, len %d, bufpos %d"
# hw/usb-desc.c
disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
commit c4f8e21165036a2f5422cd5faa507ccdf91aa945
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu May 19 08:55:09 2011 +0200
usb-ehci: improve mmio tracing
Add a separate tracepoint to log how register values change in response
to a mmio write. Especially useful for registers which have read-only
or clear-on-write bits in them.
No change in behavior.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 85e5ed9..b9204ab 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -719,10 +719,6 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
int rwc;
USBDevice *dev = s->ports[port].dev;
- DPRINTF("port_status_write: "
- "PORTSC (port %d) curr %08X new %08X rw-clear %08X rw %08X\n",
- port, *portsc, val, (val & PORTSC_RWC_MASK), val & PORTSC_RO_MASK);
-
rwc = val & PORTSC_RWC_MASK;
val &= PORTSC_RO_MASK;
@@ -744,8 +740,6 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
}
if (s->ports[port].dev) {
- DPRINTF("port_status_write: "
- "Device was connected before reset, clearing CSC bit\n");
*portsc &= ~PORTSC_CSC;
}
@@ -760,16 +754,16 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
*portsc &= ~PORTSC_RO_MASK;
*portsc |= val;
- DPRINTF("port_status_write: Port %d status set to 0x%08x\n", port, *portsc);
}
static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
{
EHCIState *s = ptr;
+ uint32_t *mmio = (uint32_t *)(&s->mmio[addr]);
+ uint32_t old = *mmio;
int i;
- trace_usb_ehci_mmio_writel(addr, addr2str(addr), val,
- *(uint32_t *)(&s->mmio[addr]));
+ trace_usb_ehci_mmio_writel(addr, addr2str(addr), val);
/* Only aligned reads are allowed on OHCI */
if (addr & 3) {
@@ -780,6 +774,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) {
handle_port_status_write(s, (addr-PORTSC)/4, val);
+ trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
return;
}
@@ -858,7 +853,8 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
break;
}
- *(uint32_t *)(&s->mmio[addr]) = val;
+ *mmio = val;
+ trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
}
diff --git a/trace-events b/trace-events
index 38c8939..1ee711e 100644
--- a/trace-events
+++ b/trace-events
@@ -197,7 +197,8 @@ disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
# hw/usb-ehci.c
disable usb_ehci_reset(void) "=== RESET ==="
disable usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
-disable usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val, uint32_t oldval) "wr mmio %04x [%s] = %x (old: %x)"
+disable usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x"
+disable usb_ehci_mmio_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)"
disable usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
disable usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
disable usb_ehci_qh(uint32_t addr, uint32_t next, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd, int rl, int mplen, int eps, int ep, int devaddr, int c, int h, int dtc, int i) "QH @ %08x: next %08x qtds %08x,%08x,%08x - rl %d, mplen %d, eps %d, ep %d, dev %d, c %d, h %d, dtc %d, i %d"
commit dcbd0b5c0ef825c02b443e11f501599d801f396a
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Thu May 19 08:46:53 2011 +0200
usb-ehci: trace port state
Trace usb port operations (attach, detach, reset),
drop a few obsolete DPRINTF's.
No change in behavior.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 40a447b..85e5ed9 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -604,8 +604,7 @@ static void ehci_attach(USBPort *port)
EHCIState *s = port->opaque;
uint32_t *portsc = &s->portsc[port->index];
- DPRINTF("ehci_attach invoked for index %d, portsc 0x%x, desc %s\n",
- port->index, *portsc, port->dev->product_desc);
+ trace_usb_ehci_port_attach(port->index, port->dev->product_desc);
*portsc |= PORTSC_CONNECT;
*portsc |= PORTSC_CSC;
@@ -625,8 +624,7 @@ static void ehci_detach(USBPort *port)
EHCIState *s = port->opaque;
uint32_t *portsc = &s->portsc[port->index];
- DPRINTF("ehci_attach invoked for index %d, portsc 0x%x\n",
- port->index, *portsc);
+ trace_usb_ehci_port_detach(port->index);
*portsc &= ~PORTSC_CONNECT;
*portsc |= PORTSC_CSC;
@@ -733,11 +731,11 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
*portsc &= ~rwc;
if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) {
- DPRINTF("port_status_write: USBTRAN Port %d reset begin\n", port);
+ trace_usb_ehci_port_reset(port, 1);
}
if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
- DPRINTF("port_status_write: USBTRAN Port %d reset done\n", port);
+ trace_usb_ehci_port_reset(port, 0);
usb_attach(&s->ports[port], dev);
// TODO how to handle reset of ports with no device
diff --git a/trace-events b/trace-events
index 2b89d0f..38c8939 100644
--- a/trace-events
+++ b/trace-events
@@ -203,6 +203,9 @@ disable usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
disable usb_ehci_qh(uint32_t addr, uint32_t next, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd, int rl, int mplen, int eps, int ep, int devaddr, int c, int h, int dtc, int i) "QH @ %08x: next %08x qtds %08x,%08x,%08x - rl %d, mplen %d, eps %d, ep %d, dev %d, c %d, h %d, dtc %d, i %d"
disable usb_ehci_qtd(uint32_t addr, uint32_t next, uint32_t altnext, int tbytes, int cpage, int cerr, int pid, int ioc, int active, int halt, int babble, int xacterr) "QH @ %08x: next %08x altnext %08x - tbytes %d, cpage %d, cerr %d, pid %d, ioc %d, active %d, halt %d, babble %d, xacterr %d"
disable usb_ehci_itd(uint32_t addr, uint32_t next) "ITD @ %08x: next %08x"
+disable usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
+disable usb_ehci_port_detach(uint32_t port) "detach port #%d"
+disable usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
# hw/usb-desc.c
disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
commit 26d53979db57939969efc7c698c2240a89f50648
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Wed May 18 14:23:35 2011 +0200
usb-ehci: trace state machine changes
Add functions to get and set the current state of the state machine,
add tracepoints there to trace state transitions. Add support for
traceing the queue heads and transfer descriptors as we look at them.
Drop a few DPRINTFs and all DPRINTF_ST lines, they are obsolete now.
No change in behavior.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 16fbca6..40a447b 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -33,20 +33,13 @@
#include "trace.h"
#define EHCI_DEBUG 0
-#define STATE_DEBUG 0 /* state transitions */
-#if EHCI_DEBUG || STATE_DEBUG
+#if EHCI_DEBUG
#define DPRINTF printf
#else
#define DPRINTF(...)
#endif
-#if STATE_DEBUG
-#define DPRINTF_ST DPRINTF
-#else
-#define DPRINTF_ST(...)
-#endif
-
/* internal processing - reset HC to try and recover */
#define USB_RET_PROCERR (-99)
@@ -417,33 +410,59 @@ typedef struct {
*data = val; \
} while(0)
+static const char *ehci_state_names[] = {
+ [ EST_INACTIVE ] = "INACTIVE",
+ [ EST_ACTIVE ] = "ACTIVE",
+ [ EST_EXECUTING ] = "EXECUTING",
+ [ EST_SLEEPING ] = "SLEEPING",
+ [ EST_WAITLISTHEAD ] = "WAITLISTHEAD",
+ [ EST_FETCHENTRY ] = "FETCH ENTRY",
+ [ EST_FETCHQH ] = "FETCH QH",
+ [ EST_FETCHITD ] = "FETCH ITD",
+ [ EST_ADVANCEQUEUE ] = "ADVANCEQUEUE",
+ [ EST_FETCHQTD ] = "FETCH QTD",
+ [ EST_EXECUTE ] = "EXECUTE",
+ [ EST_WRITEBACK ] = "WRITEBACK",
+ [ EST_HORIZONTALQH ] = "HORIZONTALQH",
+};
+
+static const char *ehci_mmio_names[] = {
+ [ CAPLENGTH ] = "CAPLENGTH",
+ [ HCIVERSION ] = "HCIVERSION",
+ [ HCSPARAMS ] = "HCSPARAMS",
+ [ HCCPARAMS ] = "HCCPARAMS",
+ [ USBCMD ] = "USBCMD",
+ [ USBSTS ] = "USBSTS",
+ [ USBINTR ] = "USBINTR",
+ [ FRINDEX ] = "FRINDEX",
+ [ PERIODICLISTBASE ] = "P-LIST BASE",
+ [ ASYNCLISTADDR ] = "A-LIST ADDR",
+ [ PORTSC_BEGIN ] = "PORTSC #0",
+ [ PORTSC_BEGIN + 4] = "PORTSC #1",
+ [ PORTSC_BEGIN + 8] = "PORTSC #2",
+ [ PORTSC_BEGIN + 12] = "PORTSC #3",
+ [ CONFIGFLAG ] = "CONFIGFLAG",
+};
-static const char *addr2str(target_phys_addr_t addr)
+static const char *nr2str(const char **n, size_t len, uint32_t nr)
{
- const char *r = "unknown";
- const char *n[] = {
- [ CAPLENGTH ] = "CAPLENGTH",
- [ HCIVERSION ] = "HCIVERSION",
- [ HCSPARAMS ] = "HCSPARAMS",
- [ HCCPARAMS ] = "HCCPARAMS",
- [ USBCMD ] = "USBCMD",
- [ USBSTS ] = "USBSTS",
- [ USBINTR ] = "USBINTR",
- [ FRINDEX ] = "FRINDEX",
- [ PERIODICLISTBASE ] = "P-LIST BASE",
- [ ASYNCLISTADDR ] = "A-LIST ADDR",
- [ PORTSC_BEGIN ...
- PORTSC_END ] = "PORTSC",
- [ CONFIGFLAG ] = "CONFIGFLAG",
- };
-
- if (addr < ARRAY_SIZE(n) && n[addr] != NULL) {
- return n[addr];
+ if (nr < len && n[nr] != NULL) {
+ return n[nr];
} else {
- return r;
+ return "unknown";
}
}
+static const char *state2str(uint32_t state)
+{
+ return nr2str(ehci_state_names, ARRAY_SIZE(ehci_state_names), state);
+}
+
+static const char *addr2str(target_phys_addr_t addr)
+{
+ return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
+}
+
static void ehci_trace_usbsts(uint32_t mask, int state)
{
/* interrupts */
@@ -528,6 +547,56 @@ static inline void ehci_commit_interrupt(EHCIState *s)
s->usbsts_pending = 0;
}
+static void ehci_set_state(EHCIState *s, int async, int state)
+{
+ if (async) {
+ trace_usb_ehci_state("async", state2str(state));
+ s->astate = state;
+ } else {
+ trace_usb_ehci_state("periodic", state2str(state));
+ s->pstate = state;
+ }
+}
+
+static int ehci_get_state(EHCIState *s, int async)
+{
+ return async ? s->astate : s->pstate;
+}
+
+static void ehci_trace_qh(EHCIState *s, target_phys_addr_t addr, EHCIqh *qh)
+{
+ trace_usb_ehci_qh(addr, qh->next,
+ qh->current_qtd, qh->next_qtd, qh->altnext_qtd,
+ get_field(qh->epchar, QH_EPCHAR_RL),
+ get_field(qh->epchar, QH_EPCHAR_MPLEN),
+ get_field(qh->epchar, QH_EPCHAR_EPS),
+ get_field(qh->epchar, QH_EPCHAR_EP),
+ get_field(qh->epchar, QH_EPCHAR_DEVADDR),
+ (bool)(qh->epchar & QH_EPCHAR_C),
+ (bool)(qh->epchar & QH_EPCHAR_H),
+ (bool)(qh->epchar & QH_EPCHAR_DTC),
+ (bool)(qh->epchar & QH_EPCHAR_I));
+}
+
+static void ehci_trace_qtd(EHCIState *s, target_phys_addr_t addr, EHCIqtd *qtd)
+{
+ trace_usb_ehci_qtd(addr, qtd->next, qtd->altnext,
+ get_field(qtd->token, QTD_TOKEN_TBYTES),
+ get_field(qtd->token, QTD_TOKEN_CPAGE),
+ get_field(qtd->token, QTD_TOKEN_CERR),
+ get_field(qtd->token, QTD_TOKEN_PID),
+ (bool)(qtd->token & QTD_TOKEN_IOC),
+ (bool)(qtd->token & QTD_TOKEN_ACTIVE),
+ (bool)(qtd->token & QTD_TOKEN_HALT),
+ (bool)(qtd->token & QTD_TOKEN_BABBLE),
+ (bool)(qtd->token & QTD_TOKEN_XACTERR));
+}
+
+static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd)
+{
+ trace_usb_ehci_itd(addr, itd->next);
+}
+
/* Attach or detach a device on root hub */
static void ehci_attach(USBPort *port)
@@ -1230,7 +1299,7 @@ static int ehci_process_itd(EHCIState *ehci,
/* This state is the entry point for asynchronous schedule
* processing. Entry here consitutes a EHCI start event state (4.8.5)
*/
-static int ehci_state_waitlisthead(EHCIState *ehci, int async, int *state)
+static int ehci_state_waitlisthead(EHCIState *ehci, int async)
{
EHCIqh *qh = &ehci->qh;
int i = 0;
@@ -1245,32 +1314,28 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async, int *state)
/* Find the head of the list (4.9.1.1) */
for(i = 0; i < MAX_QH; i++) {
get_dwords(NLPTR_GET(entry), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+ ehci_trace_qh(ehci, NLPTR_GET(entry), qh);
if (qh->epchar & QH_EPCHAR_H) {
- DPRINTF_ST("WAITLISTHEAD: QH %08X is the HEAD of the list\n",
- entry);
if (async) {
entry |= (NLPTR_TYPE_QH << 1);
}
ehci->fetch_addr = entry;
- *state = EST_FETCHENTRY;
+ ehci_set_state(ehci, async, EST_FETCHENTRY);
again = 1;
goto out;
}
- DPRINTF_ST("WAITLISTHEAD: QH %08X is NOT the HEAD of the list\n",
- entry);
entry = qh->next;
if (entry == ehci->asynclistaddr) {
- DPRINTF("WAITLISTHEAD: reached beginning of QH list\n");
break;
}
}
/* no head found for list. */
- *state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
out:
return again;
@@ -1280,7 +1345,7 @@ out:
/* This state is the entry point for periodic schedule processing as
* well as being a continuation state for async processing.
*/
-static int ehci_state_fetchentry(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchentry(EHCIState *ehci, int async)
{
int again = 0;
uint32_t entry = ehci->fetch_addr;
@@ -1298,7 +1363,7 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async, int *state)
#endif
if (entry < 0x1000) {
DPRINTF("fetchentry: entry invalid (0x%08x)\n", entry);
- *state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
goto out;
}
@@ -1310,15 +1375,13 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async, int *state)
switch (NLPTR_TYPE_GET(entry)) {
case NLPTR_TYPE_QH:
- DPRINTF_ST("FETCHENTRY: entry %X is a Queue Head\n", entry);
- *state = EST_FETCHQH;
+ ehci_set_state(ehci, async, EST_FETCHQH);
ehci->qhaddr = entry;
again = 1;
break;
case NLPTR_TYPE_ITD:
- DPRINTF_ST("FETCHENTRY: entry %X is an ITD\n", entry);
- *state = EST_FETCHITD;
+ ehci_set_state(ehci, async, EST_FETCHITD);
ehci->itdaddr = entry;
again = 1;
break;
@@ -1334,13 +1397,14 @@ out:
return again;
}
-static int ehci_state_fetchqh(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchqh(EHCIState *ehci, int async)
{
EHCIqh *qh = &ehci->qh;
int reload;
int again = 0;
get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+ ehci_trace_qh(ehci, NLPTR_GET(ehci->qhaddr), qh);
if (async && (qh->epchar & QH_EPCHAR_H)) {
@@ -1350,7 +1414,7 @@ static int ehci_state_fetchqh(EHCIState *ehci, int async, int *state)
} else {
DPRINTF("FETCHQH: QH 0x%08x. H-bit set, reclamation status reset"
" - done processing\n", ehci->qhaddr);
- *state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
goto out;
}
}
@@ -1368,25 +1432,21 @@ static int ehci_state_fetchqh(EHCIState *ehci, int async, int *state)
reload = get_field(qh->epchar, QH_EPCHAR_RL);
if (reload) {
- DPRINTF_ST("FETCHQH: reloading nakcnt to %d\n", reload);
set_field(&qh->altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
}
if (qh->token & QTD_TOKEN_HALT) {
- DPRINTF_ST("FETCHQH: QH Halted, go horizontal\n");
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
again = 1;
} else if ((qh->token & QTD_TOKEN_ACTIVE) && (qh->current_qtd > 0x1000)) {
- DPRINTF_ST("FETCHQH: Active, !Halt, execute - fetch qTD\n");
ehci->qtdaddr = qh->current_qtd;
- *state = EST_FETCHQTD;
+ ehci_set_state(ehci, async, EST_FETCHQTD);
again = 1;
} else {
/* EHCI spec version 1.0 Section 4.10.2 */
- DPRINTF_ST("FETCHQH: !Active, !Halt, advance queue\n");
- *state = EST_ADVANCEQUEUE;
+ ehci_set_state(ehci, async, EST_ADVANCEQUEUE);
again = 1;
}
@@ -1394,14 +1454,13 @@ out:
return again;
}
-static int ehci_state_fetchitd(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchitd(EHCIState *ehci, int async)
{
EHCIitd itd;
get_dwords(NLPTR_GET(ehci->itdaddr),(uint32_t *) &itd,
sizeof(EHCIitd) >> 2);
- DPRINTF_ST("FETCHITD: Fetched ITD at address %08X " "(next is %08X)\n",
- ehci->itdaddr, itd.next);
+ ehci_trace_itd(ehci, ehci->itdaddr, &itd);
if (ehci_process_itd(ehci, &itd) != 0) {
return -1;
@@ -1410,13 +1469,13 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async, int *state)
put_dwords(NLPTR_GET(ehci->itdaddr), (uint32_t *) &itd,
sizeof(EHCIitd) >> 2);
ehci->fetch_addr = itd.next;
- *state = EST_FETCHENTRY;
+ ehci_set_state(ehci, async, EST_FETCHENTRY);
return 1;
}
/* Section 4.10.2 - paragraph 3 */
-static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
+static int ehci_state_advqueue(EHCIState *ehci, int async)
{
#if 0
/* TO-DO: 4.10.2 - paragraph 2
@@ -1424,7 +1483,7 @@ static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
* go to horizontal QH
*/
if (I-bit set) {
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
goto out;
}
#endif
@@ -1435,71 +1494,63 @@ static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
if (((ehci->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
(ehci->qh.altnext_qtd > 0x1000) &&
(NLPTR_TBIT(ehci->qh.altnext_qtd) == 0)) {
- DPRINTF_ST("ADVQUEUE: goto alt next qTD. "
- "curr 0x%08x next 0x%08x alt 0x%08x (next qh %x)\n",
- ehci->qh.current_qtd, ehci->qh.altnext_qtd,
- ehci->qh.next_qtd, ehci->qh.next);
ehci->qtdaddr = ehci->qh.altnext_qtd;
- *state = EST_FETCHQTD;
+ ehci_set_state(ehci, async, EST_FETCHQTD);
/*
* next qTD is valid
*/
} else if ((ehci->qh.next_qtd > 0x1000) &&
(NLPTR_TBIT(ehci->qh.next_qtd) == 0)) {
- DPRINTF_ST("ADVQUEUE: next qTD. "
- "curr 0x%08x next 0x%08x alt 0x%08x (next qh %x)\n",
- ehci->qh.current_qtd, ehci->qh.altnext_qtd,
- ehci->qh.next_qtd, ehci->qh.next);
ehci->qtdaddr = ehci->qh.next_qtd;
- *state = EST_FETCHQTD;
+ ehci_set_state(ehci, async, EST_FETCHQTD);
/*
* no valid qTD, try next QH
*/
} else {
- DPRINTF_ST("ADVQUEUE: go to horizontal QH\n");
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
}
return 1;
}
/* Section 4.10.2 - paragraph 4 */
-static int ehci_state_fetchqtd(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchqtd(EHCIState *ehci, int async)
{
EHCIqtd *qtd = &ehci->qtd;
int again = 0;
get_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) qtd, sizeof(EHCIqtd) >> 2);
+ ehci_trace_qtd(ehci, NLPTR_GET(ehci->qtdaddr), qtd);
if (qtd->token & QTD_TOKEN_ACTIVE) {
- *state = EST_EXECUTE;
+ ehci_set_state(ehci, async, EST_EXECUTE);
again = 1;
} else {
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
again = 1;
}
return again;
}
-static int ehci_state_horizqh(EHCIState *ehci, int async, int *state)
+static int ehci_state_horizqh(EHCIState *ehci, int async)
{
int again = 0;
if (ehci->fetch_addr != ehci->qh.next) {
ehci->fetch_addr = ehci->qh.next;
- *state = EST_FETCHENTRY;
+ ehci_set_state(ehci, async, EST_FETCHENTRY);
again = 1;
} else {
- *state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
}
return again;
}
-static int ehci_state_execute(EHCIState *ehci, int async, int *state)
+static int ehci_state_execute(EHCIState *ehci, int async)
{
EHCIqh *qh = &ehci->qh;
EHCIqtd *qtd = &ehci->qtd;
@@ -1507,13 +1558,6 @@ static int ehci_state_execute(EHCIState *ehci, int async, int *state)
int reload, nakcnt;
int smask;
- if (async) {
- DPRINTF_ST(">>>>> ASYNC STATE MACHINE execute QH 0x%08x, QTD 0x%08x\n",
- ehci->qhaddr, ehci->qtdaddr);
- } else {
- DPRINTF_ST(">>>>> PERIODIC STATE MACHINE execute\n");
- }
-
if (ehci_qh_do_overlay(ehci, qh, qtd) != 0) {
return -1;
}
@@ -1524,8 +1568,7 @@ static int ehci_state_execute(EHCIState *ehci, int async, int *state)
reload = get_field(qh->epchar, QH_EPCHAR_RL);
nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
if (reload && !nakcnt) {
- DPRINTF_ST("EXECUTE: RL != 0 but NakCnt == 0 -- no execute\n");
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
again = 1;
goto out;
}
@@ -1538,8 +1581,7 @@ static int ehci_state_execute(EHCIState *ehci, int async, int *state)
if (!async) {
int transactCtr = get_field(qh->epcap, QH_EPCAP_MULT);
if (!transactCtr) {
- DPRINTF("ZERO transactctr for int qh, go HORIZ\n");
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
again = 1;
goto out;
}
@@ -1554,7 +1596,7 @@ static int ehci_state_execute(EHCIState *ehci, int async, int *state)
again = -1;
goto out;
}
- *state = EST_EXECUTING;
+ ehci_set_state(ehci, async, EST_EXECUTING);
if (ehci->exec_status != USB_RET_ASYNC) {
again = 1;
@@ -1564,7 +1606,7 @@ out:
return again;
}
-static int ehci_state_executing(EHCIState *ehci, int async, int *state)
+static int ehci_state_executing(EHCIState *ehci, int async)
{
EHCIqh *qh = &ehci->qh;
int again = 0;
@@ -1596,12 +1638,8 @@ static int ehci_state_executing(EHCIState *ehci, int async, int *state)
if (nakcnt) {
nakcnt--;
}
- DPRINTF_ST("EXECUTING: Nak occured and RL != 0, dec NakCnt to %d\n",
- nakcnt);
} else {
nakcnt = reload;
- DPRINTF_ST("EXECUTING: Nak didn't occur, reloading to %d\n",
- nakcnt);
}
set_field(&qh->altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
}
@@ -1611,16 +1649,13 @@ static int ehci_state_executing(EHCIState *ehci, int async, int *state)
* in the EHCI spec but we need to do it since we don't share
* physical memory with our guest VM.
*/
-
- DPRINTF("EXECUTING: write QH to VM memory: qhaddr 0x%x, next 0x%x\n",
- ehci->qhaddr, qh->next);
put_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
/* 4.10.5 */
if ((ehci->exec_status == USB_RET_NAK) || (qh->token & QTD_TOKEN_ACTIVE)) {
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
} else {
- *state = EST_WRITEBACK;
+ ehci_set_state(ehci, async, EST_WRITEBACK);
}
again = 1;
@@ -1630,13 +1665,13 @@ out:
}
-static int ehci_state_writeback(EHCIState *ehci, int async, int *state)
+static int ehci_state_writeback(EHCIState *ehci, int async)
{
EHCIqh *qh = &ehci->qh;
int again = 0;
/* Write back the QTD from the QH area */
- DPRINTF_ST("WRITEBACK: write QTD to VM memory\n");
+ ehci_trace_qtd(ehci, NLPTR_GET(ehci->qtdaddr), (EHCIqtd*) &qh->next_qtd);
put_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) &qh->next_qtd,
sizeof(EHCIqtd) >> 2);
@@ -1644,10 +1679,10 @@ static int ehci_state_writeback(EHCIState *ehci, int async, int *state)
* but stop after one qtd if periodic
*/
//if (async) {
- *state = EST_ADVANCEQUEUE;
+ ehci_set_state(ehci, async, EST_ADVANCEQUEUE);
again = 1;
//} else {
- // *state = EST_ACTIVE;
+ // ehci_set_state(ehci, async, EST_ACTIVE);
//}
return again;
}
@@ -1656,15 +1691,14 @@ static int ehci_state_writeback(EHCIState *ehci, int async, int *state)
* This is the state machine that is common to both async and periodic
*/
-static int ehci_advance_state(EHCIState *ehci,
- int async,
- int state)
+static void ehci_advance_state(EHCIState *ehci,
+ int async)
{
int again;
int iter = 0;
do {
- if (state == EST_FETCHQH) {
+ if (ehci_get_state(ehci, async) == EST_FETCHQH) {
iter++;
/* if we are roaming a lot of QH without executing a qTD
* something is wrong with the linked list. TO-DO: why is
@@ -1672,50 +1706,50 @@ static int ehci_advance_state(EHCIState *ehci,
*/
if (iter > MAX_ITERATIONS) {
DPRINTF("\n*** advance_state: bailing on MAX ITERATIONS***\n");
- state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
break;
}
}
- switch(state) {
+ switch(ehci_get_state(ehci, async)) {
case EST_WAITLISTHEAD:
- again = ehci_state_waitlisthead(ehci, async, &state);
+ again = ehci_state_waitlisthead(ehci, async);
break;
case EST_FETCHENTRY:
- again = ehci_state_fetchentry(ehci, async, &state);
+ again = ehci_state_fetchentry(ehci, async);
break;
case EST_FETCHQH:
- again = ehci_state_fetchqh(ehci, async, &state);
+ again = ehci_state_fetchqh(ehci, async);
break;
case EST_FETCHITD:
- again = ehci_state_fetchitd(ehci, async, &state);
+ again = ehci_state_fetchitd(ehci, async);
break;
case EST_ADVANCEQUEUE:
- again = ehci_state_advqueue(ehci, async, &state);
+ again = ehci_state_advqueue(ehci, async);
break;
case EST_FETCHQTD:
- again = ehci_state_fetchqtd(ehci, async, &state);
+ again = ehci_state_fetchqtd(ehci, async);
break;
case EST_HORIZONTALQH:
- again = ehci_state_horizqh(ehci, async, &state);
+ again = ehci_state_horizqh(ehci, async);
break;
case EST_EXECUTE:
iter = 0;
- again = ehci_state_execute(ehci, async, &state);
+ again = ehci_state_execute(ehci, async);
break;
case EST_EXECUTING:
- again = ehci_state_executing(ehci, async, &state);
+ again = ehci_state_executing(ehci, async);
break;
case EST_WRITEBACK:
- again = ehci_state_writeback(ehci, async, &state);
+ again = ehci_state_writeback(ehci, async);
break;
default:
@@ -1733,27 +1767,26 @@ static int ehci_advance_state(EHCIState *ehci,
while (again);
ehci_commit_interrupt(ehci);
- return state;
}
static void ehci_advance_async_state(EHCIState *ehci)
{
EHCIqh qh;
- int state = ehci->astate;
+ int async = 1;
- switch(state) {
+ switch(ehci_get_state(ehci, async)) {
case EST_INACTIVE:
if (!(ehci->usbcmd & USBCMD_ASE)) {
break;
}
ehci_set_usbsts(ehci, USBSTS_ASS);
- ehci->astate = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
// No break, fall through to ACTIVE
case EST_ACTIVE:
if ( !(ehci->usbcmd & USBCMD_ASE)) {
ehci_clear_usbsts(ehci, USBSTS_ASS);
- ehci->astate = EST_INACTIVE;
+ ehci_set_state(ehci, async, EST_INACTIVE);
break;
}
@@ -1775,14 +1808,12 @@ static void ehci_advance_async_state(EHCIState *ehci)
break;
}
- DPRINTF_ST("ASYNC: waiting for listhead, starting at %08x\n",
- ehci->asynclistaddr);
/* check that address register has been set */
if (ehci->asynclistaddr == 0) {
break;
}
- state = EST_WAITLISTHEAD;
+ ehci_set_state(ehci, async, EST_WAITLISTHEAD);
/* fall through */
case EST_FETCHENTRY:
@@ -1791,14 +1822,14 @@ static void ehci_advance_async_state(EHCIState *ehci)
case EST_EXECUTING:
get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) &qh,
sizeof(EHCIqh) >> 2);
- ehci->astate = ehci_advance_state(ehci, 1, state);
+ ehci_advance_state(ehci, async);
break;
default:
/* this should only be due to a developer mistake */
fprintf(stderr, "ehci: Bad asynchronous state %d. "
"Resetting to active\n", ehci->astate);
- ehci->astate = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
}
}
@@ -1806,14 +1837,15 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
{
uint32_t entry;
uint32_t list;
+ int async = 0;
// 4.6
- switch(ehci->pstate) {
+ switch(ehci_get_state(ehci, async)) {
case EST_INACTIVE:
if ( !(ehci->frindex & 7) && (ehci->usbcmd & USBCMD_PSE)) {
ehci_set_usbsts(ehci, USBSTS_PSS);
- ehci->pstate = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
// No break, fall through to ACTIVE
} else
break;
@@ -1821,7 +1853,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
case EST_ACTIVE:
if ( !(ehci->frindex & 7) && !(ehci->usbcmd & USBCMD_PSE)) {
ehci_clear_usbsts(ehci, USBSTS_PSS);
- ehci->pstate = EST_INACTIVE;
+ ehci_set_state(ehci, async, EST_INACTIVE);
break;
}
@@ -1838,19 +1870,20 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
ehci->frindex / 8, list, entry);
ehci->fetch_addr = entry;
- ehci->pstate = ehci_advance_state(ehci, 0, EST_FETCHENTRY);
+ ehci_set_state(ehci, async, EST_FETCHENTRY);
+ ehci_advance_state(ehci, async);
break;
case EST_EXECUTING:
DPRINTF("PERIODIC state adv for executing\n");
- ehci->pstate = ehci_advance_state(ehci, 0, EST_EXECUTING);
+ ehci_advance_state(ehci, async);
break;
default:
/* this should only be due to a developer mistake */
fprintf(stderr, "ehci: Bad periodic state %d. "
"Resetting to active\n", ehci->pstate);
- ehci->pstate = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
}
}
@@ -1896,7 +1929,7 @@ static void ehci_frame_timer(void *opaque)
} else {
// TODO could this cause periodic frames to get skipped if async
// active?
- if (ehci->astate != EST_EXECUTING) {
+ if (ehci_get_state(ehci, 1) != EST_EXECUTING) {
ehci_advance_periodic_state(ehci);
}
}
@@ -1913,7 +1946,7 @@ static void ehci_frame_timer(void *opaque)
/* Async is not inside loop since it executes everything it can once
* called
*/
- if (ehci->pstate != EST_EXECUTING) {
+ if (ehci_get_state(ehci, 0) != EST_EXECUTING) {
ehci_advance_async_state(ehci);
}
diff --git a/trace-events b/trace-events
index c87a86e..2b89d0f 100644
--- a/trace-events
+++ b/trace-events
@@ -199,6 +199,10 @@ disable usb_ehci_reset(void) "=== RESET ==="
disable usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
disable usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val, uint32_t oldval) "wr mmio %04x [%s] = %x (old: %x)"
disable usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
+disable usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
+disable usb_ehci_qh(uint32_t addr, uint32_t next, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd, int rl, int mplen, int eps, int ep, int devaddr, int c, int h, int dtc, int i) "QH @ %08x: next %08x qtds %08x,%08x,%08x - rl %d, mplen %d, eps %d, ep %d, dev %d, c %d, h %d, dtc %d, i %d"
+disable usb_ehci_qtd(uint32_t addr, uint32_t next, uint32_t altnext, int tbytes, int cpage, int cerr, int pid, int ioc, int active, int halt, int babble, int xacterr) "QH @ %08x: next %08x altnext %08x - tbytes %d, cpage %d, cerr %d, pid %d, ioc %d, active %d, halt %d, babble %d, xacterr %d"
+disable usb_ehci_itd(uint32_t addr, uint32_t next) "ITD @ %08x: next %08x"
# hw/usb-desc.c
disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
commit 439a97ccab2dba51e4dad94ba2d347143a0709cc
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Wed May 18 10:12:58 2011 +0200
usb-ehci: trace mmio and usbsts
This patch starts adding trace support to ehci. It traces
updates of the status register (USBSTS), mmio access and
controller reset.
It also adds functions to set and clear status register bits
and puts them in use everywhere.
Some DPRINTF's are dropped in favor of the new tracepoints.
No change in behavior.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index f63519e..16fbca6 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -30,6 +30,7 @@
#include "usb.h"
#include "pci.h"
#include "monitor.h"
+#include "trace.h"
#define EHCI_DEBUG 0
#define STATE_DEBUG 0 /* state transitions */
@@ -417,24 +418,23 @@ typedef struct {
} while(0)
-#if EHCI_DEBUG
-static const char *addr2str(unsigned addr)
+static const char *addr2str(target_phys_addr_t addr)
{
- const char *r = " unknown";
+ const char *r = "unknown";
const char *n[] = {
- [ CAPLENGTH ] = " CAPLENGTH",
+ [ CAPLENGTH ] = "CAPLENGTH",
[ HCIVERSION ] = "HCIVERSION",
- [ HCSPARAMS ] = " HCSPARAMS",
- [ HCCPARAMS ] = " HCCPARAMS",
- [ USBCMD ] = " COMMAND",
- [ USBSTS ] = " STATUS",
- [ USBINTR ] = " INTERRUPT",
- [ FRINDEX ] = " FRAME IDX",
+ [ HCSPARAMS ] = "HCSPARAMS",
+ [ HCCPARAMS ] = "HCCPARAMS",
+ [ USBCMD ] = "USBCMD",
+ [ USBSTS ] = "USBSTS",
+ [ USBINTR ] = "USBINTR",
+ [ FRINDEX ] = "FRINDEX",
[ PERIODICLISTBASE ] = "P-LIST BASE",
[ ASYNCLISTADDR ] = "A-LIST ADDR",
[ PORTSC_BEGIN ...
- PORTSC_END ] = "PORT STATUS",
- [ CONFIGFLAG ] = "CONFIG FLAG",
+ PORTSC_END ] = "PORTSC",
+ [ CONFIGFLAG ] = "CONFIGFLAG",
};
if (addr < ARRAY_SIZE(n) && n[addr] != NULL) {
@@ -443,8 +443,61 @@ static const char *addr2str(unsigned addr)
return r;
}
}
-#endif
+static void ehci_trace_usbsts(uint32_t mask, int state)
+{
+ /* interrupts */
+ if (mask & USBSTS_INT) {
+ trace_usb_ehci_usbsts("INT", state);
+ }
+ if (mask & USBSTS_ERRINT) {
+ trace_usb_ehci_usbsts("ERRINT", state);
+ }
+ if (mask & USBSTS_PCD) {
+ trace_usb_ehci_usbsts("PCD", state);
+ }
+ if (mask & USBSTS_FLR) {
+ trace_usb_ehci_usbsts("FLR", state);
+ }
+ if (mask & USBSTS_HSE) {
+ trace_usb_ehci_usbsts("HSE", state);
+ }
+ if (mask & USBSTS_IAA) {
+ trace_usb_ehci_usbsts("IAA", state);
+ }
+
+ /* status */
+ if (mask & USBSTS_HALT) {
+ trace_usb_ehci_usbsts("HALT", state);
+ }
+ if (mask & USBSTS_REC) {
+ trace_usb_ehci_usbsts("REC", state);
+ }
+ if (mask & USBSTS_PSS) {
+ trace_usb_ehci_usbsts("PSS", state);
+ }
+ if (mask & USBSTS_ASS) {
+ trace_usb_ehci_usbsts("ASS", state);
+ }
+}
+
+static inline void ehci_set_usbsts(EHCIState *s, int mask)
+{
+ if ((s->usbsts & mask) == mask) {
+ return;
+ }
+ ehci_trace_usbsts(mask, 1);
+ s->usbsts |= mask;
+}
+
+static inline void ehci_clear_usbsts(EHCIState *s, int mask)
+{
+ if ((s->usbsts & mask) == 0) {
+ return;
+ }
+ ehci_trace_usbsts(mask, 0);
+ s->usbsts &= ~mask;
+}
static inline void ehci_set_interrupt(EHCIState *s, int intr)
{
@@ -452,7 +505,7 @@ static inline void ehci_set_interrupt(EHCIState *s, int intr)
// TODO honour interrupt threshold requests
- s->usbsts |= intr;
+ ehci_set_usbsts(s, intr);
if ((s->usbsts & USBINTR_MASK) & s->usbintr) {
level = 1;
@@ -526,6 +579,7 @@ static void ehci_reset(void *opaque)
uint8_t *pci_conf;
int i;
+ trace_usb_ehci_reset();
pci_conf = s->dev.config;
memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
@@ -576,6 +630,7 @@ static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr)
val = s->mmio[addr] | (s->mmio[addr+1] << 8) |
(s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24);
+ trace_usb_ehci_mmio_readl(addr, addr2str(addr), val);
return val;
}
@@ -645,9 +700,9 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
{
EHCIState *s = ptr;
int i;
-#if EHCI_DEBUG
- const char *str;
-#endif
+
+ trace_usb_ehci_mmio_writel(addr, addr2str(addr), val,
+ *(uint32_t *)(&s->mmio[addr]));
/* Only aligned reads are allowed on OHCI */
if (addr & 3) {
@@ -669,30 +724,21 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
/* Do any register specific pre-write processing here. */
-#if EHCI_DEBUG
- str = addr2str((unsigned) addr);
-#endif
switch(addr) {
case USBCMD:
- DPRINTF("ehci_mem_writel: USBCMD val=0x%08X, current cmd=0x%08X\n",
- val, s->usbcmd);
-
if ((val & USBCMD_RUNSTOP) && !(s->usbcmd & USBCMD_RUNSTOP)) {
- DPRINTF("ehci_mem_writel: %s run, clear halt\n", str);
qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
SET_LAST_RUN_CLOCK(s);
- s->usbsts &= ~USBSTS_HALT;
+ ehci_clear_usbsts(s, USBSTS_HALT);
}
if (!(val & USBCMD_RUNSTOP) && (s->usbcmd & USBCMD_RUNSTOP)) {
- DPRINTF(" ** STOP **\n");
qemu_del_timer(s->frame_timer);
// TODO - should finish out some stuff before setting halt
- s->usbsts |= USBSTS_HALT;
+ ehci_set_usbsts(s, USBSTS_HALT);
}
if (val & USBCMD_HCRESET) {
- DPRINTF("ehci_mem_writel: %s run, resetting\n", str);
ehci_reset(s);
val &= ~USBCMD_HCRESET;
}
@@ -703,56 +749,24 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
val & USBCMD_FLS);
val &= ~USBCMD_FLS;
}
-#if EHCI_DEBUG
- if ((val & USBCMD_PSE) && !(s->usbcmd & USBCMD_PSE)) {
- DPRINTF("periodic scheduling enabled\n");
- }
- if (!(val & USBCMD_PSE) && (s->usbcmd & USBCMD_PSE)) {
- DPRINTF("periodic scheduling disabled\n");
- }
- if ((val & USBCMD_ASE) && !(s->usbcmd & USBCMD_ASE)) {
- DPRINTF("asynchronous scheduling enabled\n");
- }
- if (!(val & USBCMD_ASE) && (s->usbcmd & USBCMD_ASE)) {
- DPRINTF("asynchronous scheduling disabled\n");
- }
- if ((val & USBCMD_IAAD) && !(s->usbcmd & USBCMD_IAAD)) {
- DPRINTF("doorbell request received\n");
- }
- if ((val & USBCMD_LHCR) && !(s->usbcmd & USBCMD_LHCR)) {
- DPRINTF("light host controller reset received\n");
- }
- if ((val & USBCMD_ITC) != (s->usbcmd & USBCMD_ITC)) {
- DPRINTF("interrupt threshold control set to %x\n",
- (val & USBCMD_ITC)>>USBCMD_ITC_SH);
- }
-#endif
break;
-
case USBSTS:
val &= USBSTS_RO_MASK; // bits 6 thru 31 are RO
- DPRINTF("ehci_mem_writel: %s RWC set to 0x%08X\n", str, val);
-
- val = (s->usbsts &= ~val); // bits 0 thru 5 are R/WC
-
- DPRINTF("ehci_mem_writel: %s updating interrupt condition\n", str);
+ ehci_clear_usbsts(s, val); // bits 0 thru 5 are R/WC
+ val = s->usbsts;
ehci_set_interrupt(s, 0);
break;
-
case USBINTR:
val &= USBINTR_MASK;
- DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
break;
case FRINDEX:
s->sofv = val >> 3;
- DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
break;
case CONFIGFLAG:
- DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
val &= 0x1;
if (val) {
for(i = 0; i < NB_PORTS; i++)
@@ -766,7 +780,6 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
"ehci: PERIODIC list base register set while periodic schedule\n"
" is enabled and HC is enabled\n");
}
- DPRINTF("ehci_mem_writel: P-LIST BASE set to 0x%08X\n", val);
break;
case ASYNCLISTADDR:
@@ -775,7 +788,6 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
"ehci: ASYNC list address register set while async schedule\n"
" is enabled and HC is enabled\n");
}
- DPRINTF("ehci_mem_writel: A-LIST ADDR set to 0x%08X\n", val);
break;
}
@@ -1227,7 +1239,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async, int *state)
/* set reclamation flag at start event (4.8.6) */
if (async) {
- ehci->usbsts |= USBSTS_REC;
+ ehci_set_usbsts(ehci, USBSTS_REC);
}
/* Find the head of the list (4.9.1.1) */
@@ -1334,7 +1346,7 @@ static int ehci_state_fetchqh(EHCIState *ehci, int async, int *state)
/* EHCI spec version 1.0 Section 4.8.3 & 4.10.1 */
if (ehci->usbsts & USBSTS_REC) {
- ehci->usbsts &= ~USBSTS_REC;
+ ehci_clear_usbsts(ehci, USBSTS_REC);
} else {
DPRINTF("FETCHQH: QH 0x%08x. H-bit set, reclamation status reset"
" - done processing\n", ehci->qhaddr);
@@ -1534,7 +1546,7 @@ static int ehci_state_execute(EHCIState *ehci, int async, int *state)
}
if (async) {
- ehci->usbsts |= USBSTS_REC;
+ ehci_set_usbsts(ehci, USBSTS_REC);
}
ehci->exec_status = ehci_execute(ehci, qh);
@@ -1734,13 +1746,13 @@ static void ehci_advance_async_state(EHCIState *ehci)
if (!(ehci->usbcmd & USBCMD_ASE)) {
break;
}
- ehci->usbsts |= USBSTS_ASS;
+ ehci_set_usbsts(ehci, USBSTS_ASS);
ehci->astate = EST_ACTIVE;
// No break, fall through to ACTIVE
case EST_ACTIVE:
if ( !(ehci->usbcmd & USBCMD_ASE)) {
- ehci->usbsts &= ~USBSTS_ASS;
+ ehci_clear_usbsts(ehci, USBSTS_ASS);
ehci->astate = EST_INACTIVE;
break;
}
@@ -1800,8 +1812,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
switch(ehci->pstate) {
case EST_INACTIVE:
if ( !(ehci->frindex & 7) && (ehci->usbcmd & USBCMD_PSE)) {
- DPRINTF("PERIODIC going active\n");
- ehci->usbsts |= USBSTS_PSS;
+ ehci_set_usbsts(ehci, USBSTS_PSS);
ehci->pstate = EST_ACTIVE;
// No break, fall through to ACTIVE
} else
@@ -1809,8 +1820,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
case EST_ACTIVE:
if ( !(ehci->frindex & 7) && !(ehci->usbcmd & USBCMD_PSE)) {
- DPRINTF("PERIODIC going inactive\n");
- ehci->usbsts &= ~USBSTS_PSS;
+ ehci_clear_usbsts(ehci, USBSTS_PSS);
ehci->pstate = EST_INACTIVE;
break;
}
diff --git a/trace-events b/trace-events
index e0e9574..c87a86e 100644
--- a/trace-events
+++ b/trace-events
@@ -194,6 +194,12 @@ disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "g
disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
+# hw/usb-ehci.c
+disable usb_ehci_reset(void) "=== RESET ==="
+disable usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
+disable usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val, uint32_t oldval) "wr mmio %04x [%s] = %x (old: %x)"
+disable usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
+
# hw/usb-desc.c
disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
disable usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d"
commit 41c01ee7157c04abea1b97ab409cd5065ecd30bd
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue May 24 16:12:31 2011 +0200
usb-linux: catch ENODEV in more places.
Factor out disconnect code (called when a device disappears) to a
separate function. Add a check for ENODEV errno to a few more places
to make sure we notice disconnects.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/usb-linux.c b/usb-linux.c
index fcfa09e..e089485 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -267,6 +267,14 @@ static void async_free(AsyncURB *aurb)
qemu_free(aurb);
}
+static void do_disconnect(USBHostDevice *s)
+{
+ printf("husb: device %d.%d disconnected\n",
+ s->bus_num, s->addr);
+ usb_host_close(s);
+ usb_host_auto_check(NULL);
+}
+
static void async_complete(void *opaque)
{
USBHostDevice *s = opaque;
@@ -281,10 +289,7 @@ static void async_complete(void *opaque)
return;
}
if (errno == ENODEV && !s->closing) {
- printf("husb: device %d.%d disconnected\n",
- s->bus_num, s->addr);
- usb_host_close(s);
- usb_host_auto_check(NULL);
+ do_disconnect(s);
return;
}
@@ -358,6 +363,7 @@ static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
{
+ const char *op = NULL;
int dev_descr_len, config_descr_len;
int interface, nb_interfaces;
int ret, i;
@@ -410,9 +416,9 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
ctrl.ioctl_code = USBDEVFS_DISCONNECT;
ctrl.ifno = interface;
ctrl.data = 0;
+ op = "USBDEVFS_DISCONNECT";
ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
if (ret < 0 && errno != ENODATA) {
- perror("USBDEVFS_DISCONNECT");
goto fail;
}
}
@@ -421,6 +427,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
/* XXX: only grab if all interfaces are free */
for (interface = 0; interface < nb_interfaces; interface++) {
+ op = "USBDEVFS_CLAIMINTERFACE";
ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
if (ret < 0) {
if (errno == EBUSY) {
@@ -428,8 +435,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
} else {
perror("husb: failed to claim interface");
}
- fail:
- return 0;
+ goto fail;
}
}
@@ -439,6 +445,13 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
dev->ninterfaces = nb_interfaces;
dev->configuration = configuration;
return 1;
+
+fail:
+ if (errno == ENODEV) {
+ do_disconnect(dev);
+ }
+ perror(op);
+ return 0;
}
static int usb_host_release_interfaces(USBHostDevice *s)
commit 7bf4162a801761792834e9e7da4b80b089434ce7
Author: Stefan Weil <weil at mail.berlios.de>
Date: Fri Jun 10 22:05:30 2011 +0200
block/rbd: Remove unused local variable
Variable 'snap' is assigned a value that is never used.
Remove snap and the related code.
Cc: Christian Brunner <chb at muc.de>
Cc: Josh Durgin <josh.durgin at dreamhost.com>
Cc: Kevin Wolf <kwolf at redhat.com>
Signed-off-by: Stefan Weil <weil at mail.berlios.de>
Reviewed-by: Josh Durgin <josh.durgin at dreamhost.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/rbd.c b/block/rbd.c
index bdc448a..d5659cd 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -227,7 +227,6 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
char name[RBD_MAX_IMAGE_NAME_SIZE];
char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
char conf[RBD_MAX_CONF_SIZE];
- char *snap = NULL;
rados_t cluster;
rados_ioctx_t io_ctx;
int ret;
@@ -238,9 +237,6 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
conf, sizeof(conf)) < 0) {
return -EINVAL;
}
- if (snap_buf[0] != '\0') {
- snap = snap_buf;
- }
/* Read out options */
while (options && options->name) {
commit f97742d0d36810ea72a2bd40b3abb890589ea3b8
Author: Alexandre Raymond <cerbere at gmail.com>
Date: Mon Jun 6 23:34:10 2011 -0400
Darwin: Fix compilation warning regarding the deprecated daemon() function
Changes since v1: create a wrapper function named qemu_daemon() in oslib-posix.c
instead of putting the OS specific workaround in qemu-nbd.c directly.
On OSX >= 10.5, daemon() is deprecated, resulting in the following warning:
----8<----
qemu-nbd.c: In function âmainâ:
qemu-nbd.c:371: warning: âdaemonâ is deprecated (declared at /usr/include/stdlib.h:289)
----8<----
The following trick, used in mDNSResponder, takes care of this warning:
http://www.opensource.apple.com/source/mDNSResponder/mDNSResponder-258.18/mDNSPosix/PosixDaemon.c
On OSX, it temporarily renames the daemon() function before including stdlib.h
and declares it manually as an extern function. This way, the compiler does not
see the declaration from stdlib.h and thus does not display the warning.
Signed-off-by: Alexandre Raymond <cerbere at gmail.com>
Cc: Blue Swirl <blauwirbel at gmail.com>
Signed-off-by: Andreas Färber <andreas.faerber at web.de>
diff --git a/osdep.h b/osdep.h
index 970d767..6eb9a49 100644
--- a/osdep.h
+++ b/osdep.h
@@ -88,6 +88,7 @@
# define QEMU_GNUC_PREREQ(maj, min) 0
#endif
+int qemu_daemon(int nochdir, int noclose);
void *qemu_memalign(size_t alignment, size_t size);
void *qemu_vmalloc(size_t size);
void qemu_vfree(void *ptr);
diff --git a/oslib-posix.c b/oslib-posix.c
index 7bc5f7c..3a18e86 100644
--- a/oslib-posix.c
+++ b/oslib-posix.c
@@ -26,11 +26,27 @@
* THE SOFTWARE.
*/
+/* The following block of code temporarily renames the daemon() function so the
+ compiler does not see the warning associated with it in stdlib.h on OSX */
+#ifdef __APPLE__
+#define daemon qemu_fake_daemon_function
+#include <stdlib.h>
+#undef daemon
+extern int daemon(int, int);
+#endif
+
#include "config-host.h"
#include "sysemu.h"
#include "trace.h"
#include "qemu_socket.h"
+
+
+int qemu_daemon(int nochdir, int noclose)
+{
+ return daemon(nochdir, noclose);
+}
+
void *qemu_oom_check(void *ptr)
{
if (ptr == NULL) {
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 110d78e..d91c02c 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -359,7 +359,7 @@ int main(int argc, char **argv)
if (!verbose) {
/* detach client and server */
- if (daemon(0, 0) == -1) {
+ if (qemu_daemon(0, 0) == -1) {
err(EXIT_FAILURE, "Failed to daemonize");
}
}
commit 7fee199cf9704587d4ed9eb23044970f2206debc
Author: Andreas Färber <andreas.faerber at web.de>
Date: Thu Jun 9 20:53:32 2011 +0200
cocoa: Avoid warning related to multiple handleEvent: definitions
Avoid compiler confusion as to which method signature to use for the
handleEvent: selector on OSX >= 10.6 by making the variable type-safe
as opposed to generic 'id' type.
Requires moving the variable definition to after the class definition.
----8<----
ui/cocoa.m: In function âcocoa_refreshâ:
ui/cocoa.m:997: warning: multiple methods named â-handleEvent:â found
/System/Library/Frameworks/AppKit.framework/Headers/NSTextInputContext.h:84: warning: using â-(BOOL)handleEvent:(NSEvent *)theEventâ
ui/cocoa.m:272: warning: also found â-(void)handleEvent:(NSEvent *)eventâ
----8<---
Reported-by: Alexandre Raymond <cerbere at gmail.com>
Signed-off-by: Andreas Färber <andreas.faerber at web.de>
Tested-by: Alexandre Raymond <cerbere at gmail.com>
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 1c54759..515e684 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -63,7 +63,6 @@ typedef struct {
} QEMUScreen;
NSWindow *normalWindow;
-id cocoaView;
static DisplayChangeListener *dcl;
int gArgc;
@@ -278,6 +277,8 @@ static int cocoa_keycode_to_qemu(int keycode)
- (QEMUScreen) gscreen;
@end
+QemuCocoaView *cocoaView;
+
@implementation QemuCocoaView
- (id)initWithFrame:(NSRect)frameRect
{
commit e949467ba6e9829be0a2fc7ec27ec544d7bd3a29
Author: Andreas Färber <andreas.faerber at web.de>
Date: Thu Jun 2 20:51:22 2011 +0200
cocoa: Revert dependency on VNC
In 821601ea5b02a68ada479731a4d3d07a9876632a (Make VNC support optional)
cocoa.o was moved from ui-obj-$(CONFIG_COCOA) to vnc-obj-$(CONFIG_COCOA),
adding a dependency on $(CONFIG_VNC). That must've been unintentional.
Cc: Jes Sorensen <Jes.Sorensen at redhat.com>
Cc: Anthony Liguori <aliguori at us.ibm.com>
Signed-off-by: Andreas Färber <andreas.faerber at web.de>
diff --git a/Makefile.objs b/Makefile.objs
index 52d8b23..509ab39 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -128,6 +128,7 @@ common-obj-y += $(addprefix audio/, $(audio-obj-y))
ui-obj-y += keymaps.o
ui-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
+ui-obj-$(CONFIG_COCOA) += cocoa.o
ui-obj-$(CONFIG_CURSES) += curses.o
vnc-obj-y += vnc.o d3des.o
vnc-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
@@ -135,7 +136,6 @@ vnc-obj-y += vnc-enc-tight.o vnc-palette.o
vnc-obj-y += vnc-enc-zrle.o
vnc-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
-vnc-obj-$(CONFIG_COCOA) += cocoa.o
ifdef CONFIG_VNC_THREAD
vnc-obj-y += vnc-jobs-async.o
else
commit 3bbbee18a4e72f92a5830d6937ec50c441ec7826
Author: Andreas Färber <andreas.faerber at web.de>
Date: Sun May 29 19:42:51 2011 +0200
cocoa: Provide central qemu_main() prototype
This fixes a missing prototype warning in vl.c and obsoletes
the prototype in cocoa.m. Adjust callers in cocoa.m to supply
third argument, which is currently only used on Linux/ppc.
The prototype is designed so that it could be shared with SDL
and other frontends, if desired.
Cc: Alexandre Raymond <cerbere at gmail.com>
Signed-off-by: Andreas Färber <andreas.faerber at web.de>
diff --git a/qemu-common.h b/qemu-common.h
index 39fabc9..109498d 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -132,6 +132,11 @@ static inline char *realpath(const char *path, char *resolved_path)
#endif /* !defined(NEED_CPU_H) */
+/* main function, renamed */
+#if defined(CONFIG_COCOA)
+int qemu_main(int argc, char **argv, char **envp);
+#endif
+
/* bottom halves */
typedef void QEMUBHFunc(void *opaque);
diff --git a/ui/cocoa.m b/ui/cocoa.m
index e1312d3..1c54759 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -23,6 +23,7 @@
*/
#import <Cocoa/Cocoa.h>
+#include <crt_externs.h>
#include "qemu-common.h"
#include "console.h"
@@ -61,7 +62,6 @@ typedef struct {
int bitsPerPixel;
} QEMUScreen;
-int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
NSWindow *normalWindow;
id cocoaView;
static DisplayChangeListener *dcl;
@@ -794,7 +794,7 @@ static int cocoa_keycode_to_qemu(int keycode)
COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n");
int status;
- status = qemu_main(argc, argv);
+ status = qemu_main(argc, argv, *_NSGetEnviron());
exit(status);
}
@@ -877,7 +877,7 @@ int main (int argc, const char * argv[]) {
!strcmp(opt, "-nographic") ||
!strcmp(opt, "-version") ||
!strcmp(opt, "-curses")) {
- return qemu_main(gArgc, gArgv);
+ return qemu_main(gArgc, gArgv, *_NSGetEnviron());
}
}
}
commit d3922ab5fa791ac1546140f2a8df86d632d8fd6a
Author: Andreas Färber <andreas.faerber at web.de>
Date: Sat May 28 15:45:18 2011 +0200
Fix libfdt warnings on Darwin
Building with libfdt results in the following warnings on Mac OS X:
CC ppc-softmmu/device_tree.o
In file included from /Users/andreas/QEMU/latest64/include/libfdt.h:54,
from /Users/andreas/QEMU/qemu/device_tree.c:26:
/Users/andreas/QEMU/qemu/libfdt_env.h:25:20: warning: endian.h: No such file or directory
/Users/andreas/QEMU/qemu/libfdt_env.h:26:22: warning: byteswap.h: No such file or directory
/Users/andreas/QEMU/qemu/libfdt_env.h:28:5: warning: "__BYTE_ORDER" is not defined
/Users/andreas/QEMU/qemu/libfdt_env.h:28:21: warning: "__BIG_ENDIAN" is not defined
Since QEMU's copy of libfdt_env.h only uses bswap_32() and bswap_64(),
let QEMU's bswap.h take care of the headers and use its endianness define.
Cc: Hollis Blanchard <hollis at penguinppc.org>
Signed-off-by: Andreas Färber <andreas.faerber at web.de>
Acked-by: Alexander Graf <agraf at suse.de>
diff --git a/libfdt_env.h b/libfdt_env.h
index ee0419f..90d7f3b 100644
--- a/libfdt_env.h
+++ b/libfdt_env.h
@@ -19,13 +19,9 @@
#ifndef _LIBFDT_ENV_H
#define _LIBFDT_ENV_H
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-#include <endian.h>
-#include <byteswap.h>
+#include "bswap.h"
-#if __BYTE_ORDER == __BIG_ENDIAN
+#ifdef HOST_WORDS_BIGENDIAN
#define fdt32_to_cpu(x) (x)
#define cpu_to_fdt32(x) (x)
#define fdt64_to_cpu(x) (x)
commit d1722a27f552a22561104210e0afad4577878e53
Author: Alexandre Raymond <cerbere at gmail.com>
Date: Sun May 29 18:22:48 2011 -0400
configure: Fix check for fdatasync()
Under Darwin, a symbol exists for the fdatasync() function, so that our
link test succeeds. However _POSIX_SYNCHRONIZED_IO is set to '-1'.
According to POSIX:2008, a value of -1 means the feature is not supported.
A value of 0 means supported at compilation time, and a value greater 0
means supported at both compilation and run time.
Enable fdatasync() only if _POSIX_SYNCHRONIZED_IO is '>0'.
Signed-off-by: Alexandre Raymond <cerbere at gmail.com>
Signed-off-by: Andreas Färber <andreas.faerber at web.de>
diff --git a/configure b/configure
index c931ae8..6101f4e 100755
--- a/configure
+++ b/configure
@@ -2461,7 +2461,13 @@ fi
fdatasync=no
cat > $TMPC << EOF
#include <unistd.h>
-int main(void) { return fdatasync(0); }
+int main(void) {
+#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
+return fdatasync(0);
+#else
+#abort Not supported
+#endif
+}
EOF
if compile_prog "" "" ; then
fdatasync=yes
commit dfa5294fce3e035192b283fe0b6fd08be48d78da
Author: Alexandre Raymond <cerbere at gmail.com>
Date: Sun May 29 18:22:50 2011 -0400
Remove warning in printf due to type mismatch
----8<----
qemu/target-lm32/translate.c: In function âgen_intermediate_code_internalâ:
qemu/target-lm32/translate.c:1135: warning: format â%zdâ expects type âsigned size_tâ, but argument 4 has type âintâ
----8<----
Both gen_opc_ptr and gen_opc_buf are "uint16_t *". The difference between
pointers is a ptrdiff_t so printf needs '%td'.
Signed-off-by: Alexandre Raymond <cerbere at gmail.com>
Acked-by: Stefan Weil <weil at mail.berlios.de>
Signed-off-by: Andreas Färber <andreas.faerber at web.de>
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
index eb21158..5e19725 100644
--- a/target-lm32/translate.c
+++ b/target-lm32/translate.c
@@ -1132,7 +1132,7 @@ static void gen_intermediate_code_internal(CPUState *env,
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
qemu_log("\n");
log_target_disas(pc_start, dc->pc - pc_start, 0);
- qemu_log("\nisize=%d osize=%zd\n",
+ qemu_log("\nisize=%d osize=%td\n",
dc->pc - pc_start, gen_opc_ptr - gen_opc_buf);
}
#endif
commit 9851484f3d4afea83b46cc0974758ab756edfacd
Author: Alexandre Raymond <cerbere at gmail.com>
Date: Sun May 29 18:22:49 2011 -0400
Cocoa: avoid displaying window when command-line contains '-h' or '-help'
There was already a check in place to avoid displaying a window
in certain modes such as vnc, nographic or curses.
Add a check for '-h' and '-help' to avoid displaying a window for a split-
second before showing the usage information.
Signed-off-by: Alexandre Raymond <cerbere at gmail.com>
Signed-off-by: Andreas Färber <andreas.faerber at web.de>
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 1ff1ac6..e1312d3 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -872,7 +872,8 @@ int main (int argc, const char * argv[]) {
if (opt[1] == '-') {
opt++;
}
- if (!strcmp(opt, "-vnc") ||
+ if (!strcmp(opt, "-h") || !strcmp(opt, "-help") ||
+ !strcmp(opt, "-vnc") ||
!strcmp(opt, "-nographic") ||
!strcmp(opt, "-version") ||
!strcmp(opt, "-curses")) {
commit d9cbb0f3ed0e3a185a61a18de856d51cf7789bf5
Author: Alexandre Raymond <cerbere at gmail.com>
Date: Fri May 27 13:22:28 2011 -0400
Fix compilation warning due to incorrectly specified type
In audio/coreaudio.c, a variable named "str" was assigned "const char" values,
which resulted in the following warnings:
-----8<-----
audio/coreaudio.c: In function âcoreaudio_logstatusâ:
audio/coreaudio.c:59: warning: initialization discards qualifiers from pointer target type
audio/coreaudio.c:63: warning: assignment discards qualifiers from pointer target type
(...)
-----8<-----
Signed-off-by: Alexandre Raymond <cerbere at gmail.com>
Acked-by: Stefan Weil <weil at mail.berlios.de>
Signed-off-by: Andreas Färber <andreas.faerber at web.de>
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 0a26413..3bd75cd 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -56,7 +56,7 @@ typedef struct coreaudioVoiceOut {
static void coreaudio_logstatus (OSStatus status)
{
- char *str = "BUG";
+ const char *str = "BUG";
switch(status) {
case kAudioHardwareNoError:
commit e4ebcc1a37a7e66205f477a7d2805fb5d0ce3d3b
Author: Tristan Gingold <gingold at adacore.com>
Date: Tue Mar 15 14:18:22 2011 +0100
cocoa: do not create a spurious window for -version
When invoked with -version, qemu will exit just after displaying the version,
so there is no need to create a window.
Also handles --XXX options.
Signed-off-by: Tristan Gingold <gingold at adacore.com>
Signed-off-by: Andreas Färber <andreas.faerber at web.de>
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 20f91bc..1ff1ac6 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -865,10 +865,19 @@ int main (int argc, const char * argv[]) {
/* In case we don't need to display a window, let's not do that */
for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-vnc") ||
- !strcmp(argv[i], "-nographic") ||
- !strcmp(argv[i], "-curses")) {
+ const char *opt = argv[i];
+
+ if (opt[0] == '-') {
+ /* Treat --foo the same as -foo. */
+ if (opt[1] == '-') {
+ opt++;
+ }
+ if (!strcmp(opt, "-vnc") ||
+ !strcmp(opt, "-nographic") ||
+ !strcmp(opt, "-version") ||
+ !strcmp(opt, "-curses")) {
return qemu_main(gArgc, gArgv);
+ }
}
}
commit 0b862cedf36d927818c50584ddd611b0370673df
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Thu Jun 9 22:54:29 2011 +0100
configure: Detect and don't try to use older libcurl
Older versions of libcurl don't have some of the features we try to
use, in particular curl_multi_setopt(). Check for this in the 'is
libcurl available?' configure test so we disable curl support if the
library is too old.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
diff --git a/configure b/configure
index 663b557..c931ae8 100755
--- a/configure
+++ b/configure
@@ -1710,7 +1710,7 @@ fi
if test "$curl" != "no" ; then
cat > $TMPC << EOF
#include <curl/curl.h>
-int main(void) { return curl_easy_init(); }
+int main(void) { curl_easy_init(); curl_multi_setopt(0, 0, 0); return 0; }
EOF
curl_cflags=`$curlconfig --cflags 2>/dev/null`
curl_libs=`$curlconfig --libs 2>/dev/null`
commit 5f04e36882ab958b5a2e5f5153609921d03dd7d5
Author: Peter Maydell <peter.maydell at linaro.org>
Date: Thu Jun 9 11:43:12 2011 +0100
Changelog: Add explanatory note that this file is no longer updated
Add an explanatory note to the top of Changelog pointing at the
wiki and git history for changelogs for more recent releases.
Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
diff --git a/Changelog b/Changelog
index 1c41e14..28a69af 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,9 @@
+This file documents changes for QEMU releases 0.12 and earlier.
+For changelog information for later releases, see
+http://wiki.qemu.org/ChangeLog or look at the git history for
+more detailed information.
+
+
version 0.12.0:
- Update to SeaBIOS 0.5.0
commit caef55ed14db20b5764453b02390f1f4179698ff
Author: Brad Hards <bradh at frogmouth.net>
Date: Thu Jun 9 07:50:43 2011 +1000
doc: Minor typo fix.
Thanks to agraf_, stefanha and Snader_LB for their IRC assistance.
Thanks to Markus Armbruster and Alexander Graf (again) for their
assistance with the second version of this patch. No patch is too
simple to test...
Signed-off-by: Brad Hards <bradh at frogmouth.net>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
diff --git a/qemu-options.hx b/qemu-options.hx
index d9edff7..f2ef9a1 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1177,9 +1177,9 @@ Specify the guest-visible address of the host. Default is the 2nd IP in the
guest network, i.e. x.x.x.2.
@item restrict=y|yes|n|no
-If this options is enabled, the guest will be isolated, i.e. it will not be
+If this option is enabled, the guest will be isolated, i.e. it will not be
able to contact the host and no guest IP packets will be routed over the host
-to the outside. This option does not affect explicitly set forwarding rule.
+to the outside. This option does not affect any explicitly set forwarding rules.
@item hostname=@var{name}
Specifies the client hostname reported by the builtin DHCP server.
commit 09716e45a05cc0c93bcf55bd0c0888dd678e490f
Author: Alexander Graf <agraf at suse.de>
Date: Thu Jun 9 00:55:37 2011 +0200
sigfd: use pthread_sigmask
Qemu uses signalfd to figure out, if a signal occured without the need
to actually receive the signal. Instead, it can read from the fd to receive
its news.
Now, we obviously don't always have signalfd around. Especially not on
non-Linux systems. So what we do there is that we create a new thread,
block that thread on all signals and simply call sigwait to wait for a
signal we're interested in to occur.
This all sounds great, but what we're really doing is:
sigset_t all;
sigfillset(&all);
sigprocmask(SIG_BLOCK, &all, NULL);
which - on Darwin - blocks all signals on the current _process_, not only
on the current thread. To block signals on the thread, we can use
pthread_sigmask().
This patch does that, assuming that my above analysis is correct, and thus
renders Qemu useable on Darwin again.
Reported-by: Andreas Färber <andreas.faerber at web.de>
Acked-by: Paolo Bonizni <pbonzini at redhat.com>
CC: Jan Kiszka <jan.kiszka at siemens.com>
CC: Anthony Liguori <anthony at codemonkey.ws>
Signed-off-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
diff --git a/compatfd.c b/compatfd.c
index bd377c4..41586ce 100644
--- a/compatfd.c
+++ b/compatfd.c
@@ -29,7 +29,7 @@ static void *sigwait_compat(void *opaque)
sigset_t all;
sigfillset(&all);
- sigprocmask(SIG_BLOCK, &all, NULL);
+ pthread_sigmask(SIG_BLOCK, &all, NULL);
while (1) {
int sig;
commit 448293961f889d635295ad5b1ecc57ce267801ba
Merge: 1c532d9... 3b4fefd...
Author: Edgar E. Iglesias <edgar.iglesias at gmail.com>
Date: Fri Jun 10 22:21:14 2011 +0200
Merge remote branch 'rth/axp-next' into alpha-merge
* rth/axp-next: (26 commits)
target-alpha: Implement TLB flush primitives.
target-alpha: Use a fixed frequency for the RPCC in system mode.
target-alpha: Trap for unassigned and unaligned addresses.
target-alpha: Remap PIO space for 43-bit KSEG for EV6.
target-alpha: Implement cpu_alpha_handle_mmu_fault for system mode.
target-alpha: Implement more CALL_PAL values inline.
target-alpha: Disable interrupts properly.
target-alpha: All ISA checks to use TB->FLAGS.
target-alpha: Swap shadow registers moving to/from PALmode.
target-alpha: Implement do_interrupt for system mode.
target-alpha: Add IPRs to be used by the emulation PALcode.
target-alpha: Use kernel mmu_idx for pal_mode.
target-alpha: Add various symbolic constants.
target-alpha: Use do_restore_state for arithmetic exceptions.
target-alpha: Tidy up arithmetic exceptions.
target-alpha: Tidy exception constants.
target-alpha: Enable the alpha-softmmu target.
target-alpha: Rationalize internal processor registers.
target-alpha: Merge HW_REI and HW_RET implementations.
target-alpha: Cleanup MMU modes.
...
commit 1c532d92ab9bc2a8180296d7abe14f29d762f612
Author: Edgar E. Iglesias <edgar.iglesias at gmail.com>
Date: Fri Jun 10 15:29:11 2011 +0200
fsdev: Fix archs that dont use fsdev
Fix provided by: "Aneesh Kumar K.V" <aneesh.kumar at linux.vnet.ibm.com>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias at gmail.com>
diff --git a/fsdev/qemu-fsdev-dummy.c b/fsdev/qemu-fsdev-dummy.c
index 619e163..4e700dd 100644
--- a/fsdev/qemu-fsdev-dummy.c
+++ b/fsdev/qemu-fsdev-dummy.c
@@ -13,8 +13,16 @@
#include <stdio.h>
#include <string.h>
#include "qemu-fsdev.h"
+#include "qemu-config.h"
int qemu_fsdev_add(QemuOpts *opts)
{
return 0;
}
+
+static void fsdev_register_config(void)
+{
+ qemu_add_opts(&qemu_fsdev_opts);
+ qemu_add_opts(&qemu_virtfs_opts);
+}
+machine_init(fsdev_register_config);
commit 924f766af9be3ff036a419fc85ed740aa01f8eac
Merge: 93e0597... 37628f1...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 8 12:16:24 2011 -0500
Merge remote-tracking branch 'qmp/for-anthony' into staging
commit 93e0597ef9fa266756c30e61fafe4b70fc7ce6a6
Merge: ac779fe... 5c3234c...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 8 12:15:43 2011 -0500
Merge remote-tracking branch 'jvrao/for-anthony' into staging
diff --cc Makefile.target
index 85480d8,99ff3ba..f7cb17d
--- a/Makefile.target
+++ b/Makefile.target
@@@ -190,9 -191,10 +190,9 @@@ obj-y = arch_init.o cpus.o monitor.o ma
# 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_PCI) += virtio-pci.o
obj-y += vhost_net.o
obj-$(CONFIG_VHOST_NET) += vhost.o
- obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p.o
+ obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
obj-y += rwhandler.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
commit ac779fe2334ebea5d4a365b053d786f7748a1db5
Merge: 13748cf... 212496c...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 8 12:15:11 2011 -0500
Merge remote-tracking branch 'spice/spice.v37' into staging
Conflicts:
vl.c
diff --cc vl.c
index 04b4a20,2021bbb..d7f905d
--- a/vl.c
+++ b/vl.c
@@@ -289,7 -289,7 +289,8 @@@ static struct
{ .driver = "VGA", .flag = &default_vga },
{ .driver = "cirrus-vga", .flag = &default_vga },
{ .driver = "vmware-svga", .flag = &default_vga },
+ { .driver = "isa-vga", .flag = &default_vga },
+ { .driver = "qxl-vga", .flag = &default_vga },
};
static int default_driver_check(QemuOpts *opts, void *opaque)
commit 13748cf499fbd93468e7103c0866e073a666f270
Merge: 99cce9f... 7665385...
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 8 12:13:58 2011 -0500
Merge remote-tracking branch 'stefanha/trivial-patches' into staging
commit 99cce9fa4e091fd7ead1926e1c0db016ef293f36
Author: Kevin Wolf <kwolf at redhat.com>
Date: Tue May 31 15:01:46 2011 +0200
qemu-img create: Fix displayed default cluster size
When not specifying a cluster size on the command line, qemu-img printed
a cluster size of 0:
Formatting '/tmp/test.qcow2', fmt=qcow2 size=67108864
encryption=off cluster_size=0
This patch adds the default cluster size to the QEMUOptionParameter list, so
that it displays the default value that is used.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2.c b/block/qcow2.c
index db1931b..8451ded 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1036,7 +1036,7 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
const char *backing_fmt = NULL;
uint64_t sectors = 0;
int flags = 0;
- size_t cluster_size = 65536;
+ size_t cluster_size = DEFAULT_CLUSTER_SIZE;
int prealloc = 0;
/* Read out options */
@@ -1343,7 +1343,8 @@ static QEMUOptionParameter qcow2_create_options[] = {
{
.name = BLOCK_OPT_CLUSTER_SIZE,
.type = OPT_SIZE,
- .help = "qcow2 cluster size"
+ .help = "qcow2 cluster size",
+ .value = { .n = DEFAULT_CLUSTER_SIZE },
},
{
.name = BLOCK_OPT_PREALLOC,
diff --git a/block/qcow2.h b/block/qcow2.h
index a019831..e1ae3e8 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -54,6 +54,8 @@
/* Must be at least 4 to cover all cases of refcount table growth */
#define REFCOUNT_CACHE_SIZE 4
+#define DEFAULT_CLUSTER_SIZE 65536
+
typedef struct QCowHeader {
uint32_t magic;
uint32_t version;
diff --git a/block/qed.c b/block/qed.c
index da0bf31..3970379 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -1464,7 +1464,8 @@ static QEMUOptionParameter qed_create_options[] = {
}, {
.name = BLOCK_OPT_CLUSTER_SIZE,
.type = OPT_SIZE,
- .help = "Cluster size (in bytes)"
+ .help = "Cluster size (in bytes)",
+ .value = { .n = QED_DEFAULT_CLUSTER_SIZE },
}, {
.name = BLOCK_OPT_TABLE_SIZE,
.type = OPT_SIZE,
diff --git a/block/vdi.c b/block/vdi.c
index 701745b..4c9e201 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -87,6 +87,7 @@ void uuid_unparse(const uuid_t uu, char *out);
#define MiB (KiB * KiB)
#define SECTOR_SIZE 512
+#define DEFAULT_CLUSTER_SIZE (1 * MiB)
#if defined(CONFIG_VDI_DEBUG)
#define logout(fmt, ...) \
@@ -803,7 +804,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
int result = 0;
uint64_t bytes = 0;
uint32_t blocks;
- size_t block_size = 1 * MiB;
+ size_t block_size = DEFAULT_CLUSTER_SIZE;
uint32_t image_type = VDI_TYPE_DYNAMIC;
VdiHeader header;
size_t i;
@@ -921,7 +922,8 @@ static QEMUOptionParameter vdi_create_options[] = {
{
.name = BLOCK_OPT_CLUSTER_SIZE,
.type = OPT_SIZE,
- .help = "VDI cluster (block) size"
+ .help = "VDI cluster (block) size",
+ .value = { .n = DEFAULT_CLUSTER_SIZE },
},
#endif
#if defined(CONFIG_VDI_STATIC_IMAGE)
commit d220894e025ea85d604a2cdc1eef541ed516728e
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Jun 1 14:03:31 2011 +0200
bdrv_img_create: Fix segfault
Block drivers that don't support creating images don't have a size option. Fail
gracefully instead of segfaulting when trying to access the option's value.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.c b/block.c
index 3036a2d..24a25d5 100644
--- a/block.c
+++ b/block.c
@@ -2881,7 +2881,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
char *options, uint64_t img_size, int flags)
{
QEMUOptionParameter *param = NULL, *create_options = NULL;
- QEMUOptionParameter *backing_fmt, *backing_file;
+ QEMUOptionParameter *backing_fmt, *backing_file, *size;
BlockDriverState *bs = NULL;
BlockDriver *drv, *proto_drv;
BlockDriver *backing_drv = NULL;
@@ -2964,7 +2964,8 @@ int bdrv_img_create(const char *filename, const char *fmt,
// The size for the image must always be specified, with one exception:
// If we are using a backing file, we can obtain the size from there
- if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
+ size = get_option_parameter(param, BLOCK_OPT_SIZE);
+ if (size && size->value.n == -1) {
if (backing_file && backing_file->value.s) {
uint64_t size;
char buf[32];
commit 80fa3341a70151d250be92ae900e3c1580817540
Author: Kevin Wolf <kwolf at redhat.com>
Date: Wed Jun 1 10:50:00 2011 +0200
qcow2: Fix memory leaks in error cases
This fixes memory leaks that may be caused by I/O errors during L1 table growth
(can happen during save_vm) and in qemu-img check.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 750abe3..c9e7bbd 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -70,7 +70,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size)
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
- return ret;
+ goto fail;
}
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index d62dc1c..ac95b88 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1086,7 +1086,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
s->l1_table_offset, s->l1_size, 1);
if (ret < 0) {
- return ret;
+ goto fail;
}
/* snapshots */
@@ -1095,7 +1095,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
sn->l1_table_offset, sn->l1_size, 0);
if (ret < 0) {
- return ret;
+ goto fail;
}
}
inc_refcounts(bs, res, refcount_table, nb_clusters,
@@ -1159,8 +1159,11 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
}
}
+ ret = 0;
+
+fail:
qemu_free(refcount_table);
- return 0;
+ return ret;
}
commit 30cdc48cc8c9ad28e1b95460021d0c121b3ed4f4
Author: Josh Durgin <josh.durgin at dreamhost.com>
Date: Thu May 26 16:07:34 2011 -0700
rbd: Add bdrv_truncate implementation
Reviewed-by: Christian Brunner <chb at muc.de>
Signed-off-by: Josh Durgin <josh.durgin at dreamhost.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/rbd.c b/block/rbd.c
index f4da6ab..bdc448a 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -688,6 +688,19 @@ static int64_t qemu_rbd_getlength(BlockDriverState *bs)
return info.size;
}
+static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset)
+{
+ BDRVRBDState *s = bs->opaque;
+ int r;
+
+ r = rbd_resize(s->image, offset);
+ if (r < 0) {
+ return r;
+ }
+
+ return 0;
+}
+
static int qemu_rbd_snap_create(BlockDriverState *bs,
QEMUSnapshotInfo *sn_info)
{
@@ -784,6 +797,7 @@ static BlockDriver bdrv_rbd = {
.bdrv_get_info = qemu_rbd_getinfo,
.create_options = qemu_rbd_create_options,
.bdrv_getlength = qemu_rbd_getlength,
+ .bdrv_truncate = qemu_rbd_truncate,
.protocol_name = "rbd",
.bdrv_aio_readv = qemu_rbd_aio_readv,
commit 51a135287ae6be62d54d7ac2a99e647cbab1a828
Author: Josh Durgin <josh.durgin at dreamhost.com>
Date: Thu May 26 16:07:33 2011 -0700
rbd: check return values when scheduling aio
If scheduling fails, the number of outstanding I/Os must be correct,
or there will be a hang when waiting for everything to be flushed.
Reviewed-by: Christian Brunner <chb at muc.de>
Reported-by: Stefan Hajnoczi <stefanha at gmail.com>
Signed-off-by: Josh Durgin <josh.durgin at dreamhost.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/rbd.c b/block/rbd.c
index edf1086..f4da6ab 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -581,10 +581,14 @@ static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
rbd_completion_t c;
int64_t off, size;
char *buf;
+ int r;
BDRVRBDState *s = bs->opaque;
acb = qemu_aio_get(&rbd_aio_pool, bs, cb, opaque);
+ if (!acb) {
+ return NULL;
+ }
acb->write = write;
acb->qiov = qiov;
acb->bounce = qemu_blockalign(bs, qiov->size);
@@ -611,16 +615,28 @@ static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
rcb->buf = buf;
rcb->s = acb->s;
rcb->size = size;
+ r = rbd_aio_create_completion(rcb, (rbd_callback_t) rbd_finish_aiocb, &c);
+ if (r < 0) {
+ goto failed;
+ }
if (write) {
- rbd_aio_create_completion(rcb, (rbd_callback_t) rbd_finish_aiocb, &c);
- rbd_aio_write(s->image, off, size, buf, c);
+ r = rbd_aio_write(s->image, off, size, buf, c);
} else {
- rbd_aio_create_completion(rcb, (rbd_callback_t) rbd_finish_aiocb, &c);
- rbd_aio_read(s->image, off, size, buf, c);
+ r = rbd_aio_read(s->image, off, size, buf, c);
+ }
+
+ if (r < 0) {
+ goto failed;
}
return &acb->common;
+
+failed:
+ qemu_free(rcb);
+ s->qemu_aio_count--;
+ qemu_aio_release(acb);
+ return NULL;
}
static BlockDriverAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
commit fab5cf592c36a00124018604abc24f4000e07690
Author: Josh Durgin <josh.durgin at dreamhost.com>
Date: Thu May 26 16:07:32 2011 -0700
rbd: allow configuration of rados from the rbd filename
The new format is rbd:pool/image[@snapshot][:option1=value1[:option2=value2...]]
Each option is used to configure rados, and may be any Ceph option, or "conf".
The "conf" option specifies a Ceph configuration file to read.
This allows rbd volumes from more than one Ceph cluster to be used by
specifying different monitor addresses, as well as having different
logging levels or locations for different volumes.
Reviewed-by: Christian Brunner <chb at muc.de>
Signed-off-by: Josh Durgin <josh.durgin at dreamhost.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/rbd.c b/block/rbd.c
index 2cee70d..edf1086 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -23,13 +23,17 @@
/*
* When specifying the image filename use:
*
- * rbd:poolname/devicename
+ * rbd:poolname/devicename[@snapshotname][:option1=value1[:option2=value2...]]
*
* poolname must be the name of an existing rados pool
*
* devicename is the basename for all objects used to
* emulate the raw device.
*
+ * Each option given is used to configure rados, and may be
+ * any Ceph option, or "conf". The "conf" option specifies
+ * a Ceph configuration file to read.
+ *
* Metadata information (image size, ...) is stored in an
* object with the name "devicename.rbd".
*
@@ -123,7 +127,8 @@ static int qemu_rbd_next_tok(char *dst, int dst_len,
static int qemu_rbd_parsename(const char *filename,
char *pool, int pool_len,
char *snap, int snap_len,
- char *name, int name_len)
+ char *name, int name_len,
+ char *conf, int conf_len)
{
const char *start;
char *p, *buf;
@@ -135,28 +140,84 @@ static int qemu_rbd_parsename(const char *filename,
buf = qemu_strdup(start);
p = buf;
+ *snap = '\0';
+ *conf = '\0';
ret = qemu_rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
if (ret < 0 || !p) {
ret = -EINVAL;
goto done;
}
- ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
- if (ret < 0) {
- goto done;
+
+ if (strchr(p, '@')) {
+ ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
+ if (ret < 0) {
+ goto done;
+ }
+ ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p);
+ } else {
+ ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p);
}
- if (!p) {
- *snap = '\0';
+ if (ret < 0 || !p) {
goto done;
}
- ret = qemu_rbd_next_tok(snap, snap_len, p, '\0', "snap name", &p);
+ ret = qemu_rbd_next_tok(conf, conf_len, p, '\0', "configuration", &p);
done:
qemu_free(buf);
return ret;
}
+static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
+{
+ char *p, *buf;
+ char name[RBD_MAX_CONF_NAME_SIZE];
+ char value[RBD_MAX_CONF_VAL_SIZE];
+ int ret = 0;
+
+ buf = qemu_strdup(conf);
+ p = buf;
+
+ while (p) {
+ ret = qemu_rbd_next_tok(name, sizeof(name), p,
+ '=', "conf option name", &p);
+ if (ret < 0) {
+ break;
+ }
+
+ if (!p) {
+ error_report("conf option %s has no value", name);
+ ret = -EINVAL;
+ break;
+ }
+
+ ret = qemu_rbd_next_tok(value, sizeof(value), p,
+ ':', "conf option value", &p);
+ if (ret < 0) {
+ break;
+ }
+
+ if (strcmp(name, "conf")) {
+ ret = rados_conf_set(cluster, name, value);
+ if (ret < 0) {
+ error_report("invalid conf option %s", name);
+ ret = -EINVAL;
+ break;
+ }
+ } else {
+ ret = rados_conf_read_file(cluster, value);
+ if (ret < 0) {
+ error_report("error reading conf file %s", value);
+ break;
+ }
+ }
+ }
+
+ qemu_free(buf);
+ return ret;
+}
+
static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
{
int64_t bytes = 0;
@@ -165,6 +226,7 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
char pool[RBD_MAX_POOL_NAME_SIZE];
char name[RBD_MAX_IMAGE_NAME_SIZE];
char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
+ char conf[RBD_MAX_CONF_SIZE];
char *snap = NULL;
rados_t cluster;
rados_ioctx_t io_ctx;
@@ -172,7 +234,8 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
if (qemu_rbd_parsename(filename, pool, sizeof(pool),
snap_buf, sizeof(snap_buf),
- name, sizeof(name)) < 0) {
+ name, sizeof(name),
+ conf, sizeof(conf)) < 0) {
return -EINVAL;
}
if (snap_buf[0] != '\0') {
@@ -205,8 +268,17 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
return -EIO;
}
- if (rados_conf_read_file(cluster, NULL) < 0) {
- error_report("error reading config file");
+ if (strstr(conf, "conf=") == NULL) {
+ if (rados_conf_read_file(cluster, NULL) < 0) {
+ error_report("error reading config file");
+ rados_shutdown(cluster);
+ return -EIO;
+ }
+ }
+
+ if (conf[0] != '\0' &&
+ qemu_rbd_set_conf(cluster, conf) < 0) {
+ error_report("error setting config options");
rados_shutdown(cluster);
return -EIO;
}
@@ -316,11 +388,13 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
BDRVRBDState *s = bs->opaque;
char pool[RBD_MAX_POOL_NAME_SIZE];
char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
+ char conf[RBD_MAX_CONF_SIZE];
int r;
if (qemu_rbd_parsename(filename, pool, sizeof(pool),
snap_buf, sizeof(snap_buf),
- s->name, sizeof(s->name)) < 0) {
+ s->name, sizeof(s->name),
+ conf, sizeof(conf)) < 0) {
return -EINVAL;
}
s->snap = NULL;
@@ -334,11 +408,22 @@ static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
return r;
}
- r = rados_conf_read_file(s->cluster, NULL);
- if (r < 0) {
- error_report("error reading config file");
- rados_shutdown(s->cluster);
- return r;
+ if (strstr(conf, "conf=") == NULL) {
+ r = rados_conf_read_file(s->cluster, NULL);
+ if (r < 0) {
+ error_report("error reading config file");
+ rados_shutdown(s->cluster);
+ return r;
+ }
+ }
+
+ if (conf[0] != '\0') {
+ r = qemu_rbd_set_conf(s->cluster, conf);
+ if (r < 0) {
+ error_report("error setting config options");
+ rados_shutdown(s->cluster);
+ return r;
+ }
}
r = rados_connect(s->cluster);
commit ad32e9c003647142d08dfce450eafa0ab7887d10
Author: Josh Durgin <josh.durgin at dreamhost.com>
Date: Thu May 26 16:07:31 2011 -0700
rbd: use the higher level librbd instead of just librados
librbd stacks on top of librados to provide access
to rbd images.
Using librbd simplifies the qemu code, and allows
qemu to use new versions of the rbd format
with few (if any) changes.
Reviewed-by: Christian Brunner <chb at muc.de>
Signed-off-by: Josh Durgin <josh.durgin at dreamhost.com>
Signed-off-by: Yehuda Sadeh <yehuda at hq.newdream.net>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/rbd.c b/block/rbd.c
index 249a590..2cee70d 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -1,20 +1,22 @@
/*
* QEMU Block driver for RADOS (Ceph)
*
- * Copyright (C) 2010 Christian Brunner <chb at muc.de>
+ * Copyright (C) 2010-2011 Christian Brunner <chb at muc.de>,
+ * Josh Durgin <josh.durgin at dreamhost.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
+#include <inttypes.h>
+
#include "qemu-common.h"
#include "qemu-error.h"
-#include "rbd_types.h"
#include "block_int.h"
-#include <rados/librados.h>
+#include <rbd/librbd.h>
@@ -40,6 +42,13 @@
#define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER)
+#define RBD_MAX_CONF_NAME_SIZE 128
+#define RBD_MAX_CONF_VAL_SIZE 512
+#define RBD_MAX_CONF_SIZE 1024
+#define RBD_MAX_POOL_NAME_SIZE 128
+#define RBD_MAX_SNAP_NAME_SIZE 128
+#define RBD_MAX_SNAPS 100
+
typedef struct RBDAIOCB {
BlockDriverAIOCB common;
QEMUBH *bh;
@@ -48,7 +57,6 @@ typedef struct RBDAIOCB {
char *bounce;
int write;
int64_t sector_num;
- int aiocnt;
int error;
struct BDRVRBDState *s;
int cancelled;
@@ -59,7 +67,7 @@ typedef struct RADOSCB {
RBDAIOCB *acb;
struct BDRVRBDState *s;
int done;
- int64_t segsize;
+ int64_t size;
char *buf;
int ret;
} RADOSCB;
@@ -69,25 +77,22 @@ typedef struct RADOSCB {
typedef struct BDRVRBDState {
int fds[2];
- rados_pool_t pool;
- rados_pool_t header_pool;
- char name[RBD_MAX_OBJ_NAME_SIZE];
- char block_name[RBD_MAX_BLOCK_NAME_SIZE];
- uint64_t size;
- uint64_t objsize;
+ rados_t cluster;
+ rados_ioctx_t io_ctx;
+ rbd_image_t image;
+ char name[RBD_MAX_IMAGE_NAME_SIZE];
int qemu_aio_count;
+ char *snap;
int event_reader_pos;
RADOSCB *event_rcb;
} BDRVRBDState;
-typedef struct rbd_obj_header_ondisk RbdHeader1;
-
static void rbd_aio_bh_cb(void *opaque);
-static int rbd_next_tok(char *dst, int dst_len,
- char *src, char delim,
- const char *name,
- char **p)
+static int qemu_rbd_next_tok(char *dst, int dst_len,
+ char *src, char delim,
+ const char *name,
+ char **p)
{
int l;
char *end;
@@ -115,10 +120,10 @@ static int rbd_next_tok(char *dst, int dst_len,
return 0;
}
-static int rbd_parsename(const char *filename,
- char *pool, int pool_len,
- char *snap, int snap_len,
- char *name, int name_len)
+static int qemu_rbd_parsename(const char *filename,
+ char *pool, int pool_len,
+ char *snap, int snap_len,
+ char *name, int name_len)
{
const char *start;
char *p, *buf;
@@ -131,12 +136,12 @@ static int rbd_parsename(const char *filename,
buf = qemu_strdup(start);
p = buf;
- ret = rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
+ ret = qemu_rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
if (ret < 0 || !p) {
ret = -EINVAL;
goto done;
}
- ret = rbd_next_tok(name, name_len, p, '@', "object name", &p);
+ ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
if (ret < 0) {
goto done;
}
@@ -145,123 +150,35 @@ static int rbd_parsename(const char *filename,
goto done;
}
- ret = rbd_next_tok(snap, snap_len, p, '\0', "snap name", &p);
+ ret = qemu_rbd_next_tok(snap, snap_len, p, '\0', "snap name", &p);
done:
qemu_free(buf);
return ret;
}
-static int create_tmap_op(uint8_t op, const char *name, char **tmap_desc)
-{
- uint32_t len = strlen(name);
- uint32_t len_le = cpu_to_le32(len);
- /* total_len = encoding op + name + empty buffer */
- uint32_t total_len = 1 + (sizeof(uint32_t) + len) + sizeof(uint32_t);
- uint8_t *desc = NULL;
-
- desc = qemu_malloc(total_len);
-
- *tmap_desc = (char *)desc;
-
- *desc = op;
- desc++;
- memcpy(desc, &len_le, sizeof(len_le));
- desc += sizeof(len_le);
- memcpy(desc, name, len);
- desc += len;
- len = 0; /* no need for endian conversion for 0 */
- memcpy(desc, &len, sizeof(len));
- desc += sizeof(len);
-
- return (char *)desc - *tmap_desc;
-}
-
-static void free_tmap_op(char *tmap_desc)
-{
- qemu_free(tmap_desc);
-}
-
-static int rbd_register_image(rados_pool_t pool, const char *name)
-{
- char *tmap_desc;
- const char *dir = RBD_DIRECTORY;
- int ret;
-
- ret = create_tmap_op(CEPH_OSD_TMAP_SET, name, &tmap_desc);
- if (ret < 0) {
- return ret;
- }
-
- ret = rados_tmap_update(pool, dir, tmap_desc, ret);
- free_tmap_op(tmap_desc);
-
- return ret;
-}
-
-static int touch_rbd_info(rados_pool_t pool, const char *info_oid)
-{
- int r = rados_write(pool, info_oid, 0, NULL, 0);
- if (r < 0) {
- return r;
- }
- return 0;
-}
-
-static int rbd_assign_bid(rados_pool_t pool, uint64_t *id)
-{
- uint64_t out[1];
- const char *info_oid = RBD_INFO;
-
- *id = 0;
-
- int r = touch_rbd_info(pool, info_oid);
- if (r < 0) {
- return r;
- }
-
- r = rados_exec(pool, info_oid, "rbd", "assign_bid", NULL,
- 0, (char *)out, sizeof(out));
- if (r < 0) {
- return r;
- }
-
- le64_to_cpus(out);
- *id = out[0];
-
- return 0;
-}
-
-static int rbd_create(const char *filename, QEMUOptionParameter *options)
+static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
{
int64_t bytes = 0;
int64_t objsize;
- uint64_t size;
- time_t mtime;
- uint8_t obj_order = RBD_DEFAULT_OBJ_ORDER;
- char pool[RBD_MAX_SEG_NAME_SIZE];
- char n[RBD_MAX_SEG_NAME_SIZE];
- char name[RBD_MAX_OBJ_NAME_SIZE];
- char snap_buf[RBD_MAX_SEG_NAME_SIZE];
+ int obj_order = 0;
+ char pool[RBD_MAX_POOL_NAME_SIZE];
+ char name[RBD_MAX_IMAGE_NAME_SIZE];
+ char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
char *snap = NULL;
- RbdHeader1 header;
- rados_pool_t p;
- uint64_t bid;
- uint32_t hi, lo;
+ rados_t cluster;
+ rados_ioctx_t io_ctx;
int ret;
- if (rbd_parsename(filename,
- pool, sizeof(pool),
- snap_buf, sizeof(snap_buf),
- name, sizeof(name)) < 0) {
+ if (qemu_rbd_parsename(filename, pool, sizeof(pool),
+ snap_buf, sizeof(snap_buf),
+ name, sizeof(name)) < 0) {
return -EINVAL;
}
if (snap_buf[0] != '\0') {
snap = snap_buf;
}
- snprintf(n, sizeof(n), "%s%s", name, RBD_SUFFIX);
-
/* Read out options */
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
@@ -277,82 +194,55 @@ static int rbd_create(const char *filename, QEMUOptionParameter *options)
error_report("obj size too small");
return -EINVAL;
}
- obj_order = ffs(objsize) - 1;
+ obj_order = ffs(objsize) - 1;
}
}
options++;
}
- memset(&header, 0, sizeof(header));
- pstrcpy(header.text, sizeof(header.text), RBD_HEADER_TEXT);
- pstrcpy(header.signature, sizeof(header.signature), RBD_HEADER_SIGNATURE);
- pstrcpy(header.version, sizeof(header.version), RBD_HEADER_VERSION);
- header.image_size = cpu_to_le64(bytes);
- header.options.order = obj_order;
- header.options.crypt_type = RBD_CRYPT_NONE;
- header.options.comp_type = RBD_COMP_NONE;
- header.snap_seq = 0;
- header.snap_count = 0;
-
- if (rados_initialize(0, NULL) < 0) {
+ if (rados_create(&cluster, NULL) < 0) {
error_report("error initializing");
return -EIO;
}
- if (rados_open_pool(pool, &p)) {
- error_report("error opening pool %s", pool);
- rados_deinitialize();
+ if (rados_conf_read_file(cluster, NULL) < 0) {
+ error_report("error reading config file");
+ rados_shutdown(cluster);
return -EIO;
}
- /* check for existing rbd header file */
- ret = rados_stat(p, n, &size, &mtime);
- if (ret == 0) {
- ret=-EEXIST;
- goto done;
- }
-
- ret = rbd_assign_bid(p, &bid);
- if (ret < 0) {
- error_report("failed assigning block id");
- rados_deinitialize();
+ if (rados_connect(cluster) < 0) {
+ error_report("error connecting");
+ rados_shutdown(cluster);
return -EIO;
}
- hi = bid >> 32;
- lo = bid & 0xFFFFFFFF;
- snprintf(header.block_name, sizeof(header.block_name), "rb.%x.%x", hi, lo);
- /* create header file */
- ret = rados_write(p, n, 0, (const char *)&header, sizeof(header));
- if (ret < 0) {
- goto done;
+ if (rados_ioctx_create(cluster, pool, &io_ctx) < 0) {
+ error_report("error opening pool %s", pool);
+ rados_shutdown(cluster);
+ return -EIO;
}
- ret = rbd_register_image(p, name);
-done:
- rados_close_pool(p);
- rados_deinitialize();
+ ret = rbd_create(io_ctx, name, bytes, &obj_order);
+ rados_ioctx_destroy(io_ctx);
+ rados_shutdown(cluster);
return ret;
}
/*
- * This aio completion is being called from rbd_aio_event_reader() and
- * runs in qemu context. It schedules a bh, but just in case the aio
+ * This aio completion is being called from qemu_rbd_aio_event_reader()
+ * and runs in qemu context. It schedules a bh, but just in case the aio
* was not cancelled before.
*/
-static void rbd_complete_aio(RADOSCB *rcb)
+static void qemu_rbd_complete_aio(RADOSCB *rcb)
{
RBDAIOCB *acb = rcb->acb;
int64_t r;
- acb->aiocnt--;
-
if (acb->cancelled) {
- if (!acb->aiocnt) {
- qemu_vfree(acb->bounce);
- qemu_aio_release(acb);
- }
+ qemu_vfree(acb->bounce);
+ qemu_aio_release(acb);
goto done;
}
@@ -363,32 +253,25 @@ static void rbd_complete_aio(RADOSCB *rcb)
acb->ret = r;
acb->error = 1;
} else if (!acb->error) {
- acb->ret += rcb->segsize;
+ acb->ret = rcb->size;
}
} else {
- if (r == -ENOENT) {
- memset(rcb->buf, 0, rcb->segsize);
- if (!acb->error) {
- acb->ret += rcb->segsize;
- }
- } else if (r < 0) {
- memset(rcb->buf, 0, rcb->segsize);
+ if (r < 0) {
+ memset(rcb->buf, 0, rcb->size);
acb->ret = r;
acb->error = 1;
- } else if (r < rcb->segsize) {
- memset(rcb->buf + r, 0, rcb->segsize - r);
+ } else if (r < rcb->size) {
+ memset(rcb->buf + r, 0, rcb->size - r);
if (!acb->error) {
- acb->ret += rcb->segsize;
+ acb->ret = rcb->size;
}
} else if (!acb->error) {
- acb->ret += r;
+ acb->ret = r;
}
}
/* Note that acb->bh can be NULL in case where the aio was cancelled */
- if (!acb->aiocnt) {
- acb->bh = qemu_bh_new(rbd_aio_bh_cb, acb);
- qemu_bh_schedule(acb->bh);
- }
+ acb->bh = qemu_bh_new(rbd_aio_bh_cb, acb);
+ qemu_bh_schedule(acb->bh);
done:
qemu_free(rcb);
}
@@ -397,7 +280,7 @@ done:
* aio fd read handler. It runs in the qemu context and calls the
* completion handling of completed rados aio operations.
*/
-static void rbd_aio_event_reader(void *opaque)
+static void qemu_rbd_aio_event_reader(void *opaque)
{
BDRVRBDState *s = opaque;
@@ -413,176 +296,74 @@ static void rbd_aio_event_reader(void *opaque)
s->event_reader_pos += ret;
if (s->event_reader_pos == sizeof(s->event_rcb)) {
s->event_reader_pos = 0;
- rbd_complete_aio(s->event_rcb);
- s->qemu_aio_count --;
+ qemu_rbd_complete_aio(s->event_rcb);
+ s->qemu_aio_count--;
}
}
}
} while (ret < 0 && errno == EINTR);
}
-static int rbd_aio_flush_cb(void *opaque)
+static int qemu_rbd_aio_flush_cb(void *opaque)
{
BDRVRBDState *s = opaque;
return (s->qemu_aio_count > 0);
}
-
-static int rbd_set_snapc(rados_pool_t pool, const char *snap, RbdHeader1 *header)
-{
- uint32_t snap_count = le32_to_cpu(header->snap_count);
- rados_snap_t *snaps = NULL;
- rados_snap_t seq;
- uint32_t i;
- uint64_t snap_names_len = le64_to_cpu(header->snap_names_len);
- int r;
- rados_snap_t snapid = 0;
-
- if (snap_count) {
- const char *header_snap = (const char *)&header->snaps[snap_count];
- const char *end = header_snap + snap_names_len;
- snaps = qemu_malloc(sizeof(rados_snap_t) * header->snap_count);
-
- for (i=0; i < snap_count; i++) {
- snaps[i] = le64_to_cpu(header->snaps[i].id);
-
- if (snap && strcmp(snap, header_snap) == 0) {
- snapid = snaps[i];
- }
-
- header_snap += strlen(header_snap) + 1;
- if (header_snap > end) {
- error_report("bad header, snapshot list broken");
- }
- }
- }
-
- if (snap && !snapid) {
- error_report("snapshot not found");
- qemu_free(snaps);
- return -ENOENT;
- }
- seq = le32_to_cpu(header->snap_seq);
-
- r = rados_set_snap_context(pool, seq, snaps, snap_count);
-
- rados_set_snap(pool, snapid);
-
- qemu_free(snaps);
-
- return r;
-}
-
-#define BUF_READ_START_LEN 4096
-
-static int rbd_read_header(BDRVRBDState *s, char **hbuf)
-{
- char *buf = NULL;
- char n[RBD_MAX_SEG_NAME_SIZE];
- uint64_t len = BUF_READ_START_LEN;
- int r;
-
- snprintf(n, sizeof(n), "%s%s", s->name, RBD_SUFFIX);
-
- buf = qemu_malloc(len);
-
- r = rados_read(s->header_pool, n, 0, buf, len);
- if (r < 0) {
- goto failed;
- }
-
- if (r < len) {
- goto done;
- }
-
- qemu_free(buf);
- buf = qemu_malloc(len);
-
- r = rados_stat(s->header_pool, n, &len, NULL);
- if (r < 0) {
- goto failed;
- }
-
- r = rados_read(s->header_pool, n, 0, buf, len);
- if (r < 0) {
- goto failed;
- }
-
-done:
- *hbuf = buf;
- return 0;
-
-failed:
- qemu_free(buf);
- return r;
-}
-
-static int rbd_open(BlockDriverState *bs, const char *filename, int flags)
+static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRBDState *s = bs->opaque;
- RbdHeader1 *header;
- char pool[RBD_MAX_SEG_NAME_SIZE];
- char snap_buf[RBD_MAX_SEG_NAME_SIZE];
- char *snap = NULL;
- char *hbuf = NULL;
+ char pool[RBD_MAX_POOL_NAME_SIZE];
+ char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
int r;
- if (rbd_parsename(filename, pool, sizeof(pool),
- snap_buf, sizeof(snap_buf),
- s->name, sizeof(s->name)) < 0) {
+ if (qemu_rbd_parsename(filename, pool, sizeof(pool),
+ snap_buf, sizeof(snap_buf),
+ s->name, sizeof(s->name)) < 0) {
return -EINVAL;
}
+ s->snap = NULL;
if (snap_buf[0] != '\0') {
- snap = snap_buf;
+ s->snap = qemu_strdup(snap_buf);
}
- if ((r = rados_initialize(0, NULL)) < 0) {
+ r = rados_create(&s->cluster, NULL);
+ if (r < 0) {
error_report("error initializing");
return r;
}
- if ((r = rados_open_pool(pool, &s->pool))) {
- error_report("error opening pool %s", pool);
- rados_deinitialize();
+ r = rados_conf_read_file(s->cluster, NULL);
+ if (r < 0) {
+ error_report("error reading config file");
+ rados_shutdown(s->cluster);
return r;
}
- if ((r = rados_open_pool(pool, &s->header_pool))) {
- error_report("error opening pool %s", pool);
- rados_deinitialize();
+ r = rados_connect(s->cluster);
+ if (r < 0) {
+ error_report("error connecting");
+ rados_shutdown(s->cluster);
return r;
}
- if ((r = rbd_read_header(s, &hbuf)) < 0) {
- error_report("error reading header from %s", s->name);
- goto failed;
- }
-
- if (memcmp(hbuf + 64, RBD_HEADER_SIGNATURE, 4)) {
- error_report("Invalid header signature");
- r = -EMEDIUMTYPE;
- goto failed;
- }
-
- if (memcmp(hbuf + 68, RBD_HEADER_VERSION, 8)) {
- error_report("Unknown image version");
- r = -EMEDIUMTYPE;
- goto failed;
+ r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
+ if (r < 0) {
+ error_report("error opening pool %s", pool);
+ rados_shutdown(s->cluster);
+ return r;
}
- header = (RbdHeader1 *) hbuf;
- s->size = le64_to_cpu(header->image_size);
- s->objsize = 1ULL << header->options.order;
- memcpy(s->block_name, header->block_name, sizeof(header->block_name));
-
- r = rbd_set_snapc(s->pool, snap, header);
+ r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
if (r < 0) {
- error_report("failed setting snap context: %s", strerror(-r));
- goto failed;
+ error_report("error reading header from %s", s->name);
+ rados_ioctx_destroy(s->io_ctx);
+ rados_shutdown(s->cluster);
+ return r;
}
- bs->read_only = (snap != NULL);
+ bs->read_only = (s->snap != NULL);
s->event_reader_pos = 0;
r = qemu_pipe(s->fds);
@@ -592,23 +373,20 @@ static int rbd_open(BlockDriverState *bs, const char *filename, int flags)
}
fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
- qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], rbd_aio_event_reader, NULL,
- rbd_aio_flush_cb, NULL, s);
+ qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
+ NULL, qemu_rbd_aio_flush_cb, NULL, s);
- qemu_free(hbuf);
return 0;
failed:
- qemu_free(hbuf);
-
- rados_close_pool(s->header_pool);
- rados_close_pool(s->pool);
- rados_deinitialize();
+ rbd_close(s->image);
+ rados_ioctx_destroy(s->io_ctx);
+ rados_shutdown(s->cluster);
return r;
}
-static void rbd_close(BlockDriverState *bs)
+static void qemu_rbd_close(BlockDriverState *bs)
{
BDRVRBDState *s = bs->opaque;
@@ -617,16 +395,17 @@ static void rbd_close(BlockDriverState *bs)
qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL , NULL, NULL, NULL,
NULL);
- rados_close_pool(s->header_pool);
- rados_close_pool(s->pool);
- rados_deinitialize();
+ rbd_close(s->image);
+ rados_ioctx_destroy(s->io_ctx);
+ qemu_free(s->snap);
+ rados_shutdown(s->cluster);
}
/*
* Cancel aio. Since we don't reference acb in a non qemu threads,
* it is safe to access it here.
*/
-static void rbd_aio_cancel(BlockDriverAIOCB *blockacb)
+static void qemu_rbd_aio_cancel(BlockDriverAIOCB *blockacb)
{
RBDAIOCB *acb = (RBDAIOCB *) blockacb;
acb->cancelled = 1;
@@ -634,39 +413,28 @@ static void rbd_aio_cancel(BlockDriverAIOCB *blockacb)
static AIOPool rbd_aio_pool = {
.aiocb_size = sizeof(RBDAIOCB),
- .cancel = rbd_aio_cancel,
+ .cancel = qemu_rbd_aio_cancel,
};
-/*
- * This is the callback function for rados_aio_read and _write
- *
- * Note: this function is being called from a non qemu thread so
- * we need to be careful about what we do here. Generally we only
- * write to the block notification pipe, and do the rest of the
- * io completion handling from rbd_aio_event_reader() which
- * runs in a qemu context.
- */
-static void rbd_finish_aiocb(rados_completion_t c, RADOSCB *rcb)
+static int qemu_rbd_send_pipe(BDRVRBDState *s, RADOSCB *rcb)
{
- int ret;
- rcb->ret = rados_aio_get_return_value(c);
- rados_aio_release(c);
+ int ret = 0;
while (1) {
fd_set wfd;
- int fd = rcb->s->fds[RBD_FD_WRITE];
+ int fd = s->fds[RBD_FD_WRITE];
- /* send the rcb pointer to the qemu thread that is responsible
- for the aio completion. Must do it in a qemu thread context */
+ /* send the op pointer to the qemu thread that is responsible
+ for the aio/op completion. Must do it in a qemu thread context */
ret = write(fd, (void *)&rcb, sizeof(rcb));
if (ret >= 0) {
break;
}
if (errno == EINTR) {
continue;
- }
+ }
if (errno != EAGAIN) {
break;
- }
+ }
FD_ZERO(&wfd);
FD_SET(fd, &wfd);
@@ -675,13 +443,31 @@ static void rbd_finish_aiocb(rados_completion_t c, RADOSCB *rcb)
} while (ret < 0 && errno == EINTR);
}
+ return ret;
+}
+
+/*
+ * This is the callback function for rbd_aio_read and _write
+ *
+ * Note: this function is being called from a non qemu thread so
+ * we need to be careful about what we do here. Generally we only
+ * write to the block notification pipe, and do the rest of the
+ * io completion handling from qemu_rbd_aio_event_reader() which
+ * runs in a qemu context.
+ */
+static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
+{
+ int ret;
+ rcb->ret = rbd_aio_get_return_value(c);
+ rbd_aio_release(c);
+ ret = qemu_rbd_send_pipe(rcb->s, rcb);
if (ret < 0) {
- error_report("failed writing to acb->s->fds\n");
+ error_report("failed writing to acb->s->fds");
qemu_free(rcb);
}
}
-/* Callback when all queued rados_aio requests are complete */
+/* Callback when all queued rbd_aio requests are complete */
static void rbd_aio_bh_cb(void *opaque)
{
@@ -707,9 +493,7 @@ static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
{
RBDAIOCB *acb;
RADOSCB *rcb;
- rados_completion_t c;
- char n[RBD_MAX_SEG_NAME_SIZE];
- int64_t segnr, segoffs, segsize, last_segnr;
+ rbd_completion_t c;
int64_t off, size;
char *buf;
@@ -719,7 +503,6 @@ static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
acb->write = write;
acb->qiov = qiov;
acb->bounce = qemu_blockalign(bs, qiov->size);
- acb->aiocnt = 0;
acb->ret = 0;
acb->error = 0;
acb->s = s;
@@ -734,95 +517,81 @@ static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
off = sector_num * BDRV_SECTOR_SIZE;
size = nb_sectors * BDRV_SECTOR_SIZE;
- segnr = off / s->objsize;
- segoffs = off % s->objsize;
- segsize = s->objsize - segoffs;
-
- last_segnr = ((off + size - 1) / s->objsize);
- acb->aiocnt = (last_segnr - segnr) + 1;
- s->qemu_aio_count += acb->aiocnt; /* All the RADOSCB */
+ s->qemu_aio_count++; /* All the RADOSCB */
- while (size > 0) {
- if (size < segsize) {
- segsize = size;
- }
-
- snprintf(n, sizeof(n), "%s.%012" PRIx64, s->block_name,
- segnr);
-
- rcb = qemu_malloc(sizeof(RADOSCB));
- rcb->done = 0;
- rcb->acb = acb;
- rcb->segsize = segsize;
- rcb->buf = buf;
- rcb->s = acb->s;
-
- if (write) {
- rados_aio_create_completion(rcb, NULL,
- (rados_callback_t) rbd_finish_aiocb,
- &c);
- rados_aio_write(s->pool, n, segoffs, buf, segsize, c);
- } else {
- rados_aio_create_completion(rcb,
- (rados_callback_t) rbd_finish_aiocb,
- NULL, &c);
- rados_aio_read(s->pool, n, segoffs, buf, segsize, c);
- }
+ rcb = qemu_malloc(sizeof(RADOSCB));
+ rcb->done = 0;
+ rcb->acb = acb;
+ rcb->buf = buf;
+ rcb->s = acb->s;
+ rcb->size = size;
- buf += segsize;
- size -= segsize;
- segoffs = 0;
- segsize = s->objsize;
- segnr++;
+ if (write) {
+ rbd_aio_create_completion(rcb, (rbd_callback_t) rbd_finish_aiocb, &c);
+ rbd_aio_write(s->image, off, size, buf, c);
+ } else {
+ rbd_aio_create_completion(rcb, (rbd_callback_t) rbd_finish_aiocb, &c);
+ rbd_aio_read(s->image, off, size, buf, c);
}
return &acb->common;
}
-static BlockDriverAIOCB *rbd_aio_readv(BlockDriverState * bs,
- int64_t sector_num, QEMUIOVector * qiov,
- int nb_sectors,
- BlockDriverCompletionFunc * cb,
- void *opaque)
+static BlockDriverAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
+ int64_t sector_num,
+ QEMUIOVector *qiov,
+ int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque)
{
return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
}
-static BlockDriverAIOCB *rbd_aio_writev(BlockDriverState * bs,
- int64_t sector_num, QEMUIOVector * qiov,
- int nb_sectors,
- BlockDriverCompletionFunc * cb,
- void *opaque)
+static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
+ int64_t sector_num,
+ QEMUIOVector *qiov,
+ int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque)
{
return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
}
-static int rbd_getinfo(BlockDriverState * bs, BlockDriverInfo * bdi)
+static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
{
BDRVRBDState *s = bs->opaque;
- bdi->cluster_size = s->objsize;
+ rbd_image_info_t info;
+ int r;
+
+ r = rbd_stat(s->image, &info, sizeof(info));
+ if (r < 0) {
+ return r;
+ }
+
+ bdi->cluster_size = info.obj_size;
return 0;
}
-static int64_t rbd_getlength(BlockDriverState * bs)
+static int64_t qemu_rbd_getlength(BlockDriverState *bs)
{
BDRVRBDState *s = bs->opaque;
+ rbd_image_info_t info;
+ int r;
- return s->size;
+ r = rbd_stat(s->image, &info, sizeof(info));
+ if (r < 0) {
+ return r;
+ }
+
+ return info.size;
}
-static int rbd_snap_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
+static int qemu_rbd_snap_create(BlockDriverState *bs,
+ QEMUSnapshotInfo *sn_info)
{
BDRVRBDState *s = bs->opaque;
- char inbuf[512], outbuf[128];
- uint64_t snap_id;
int r;
- char *p = inbuf;
- char *end = inbuf + sizeof(inbuf);
- char n[RBD_MAX_SEG_NAME_SIZE];
- char *hbuf = NULL;
- RbdHeader1 *header;
if (sn_info->name[0] == '\0') {
return -EINVAL; /* we need a name for rbd snapshots */
@@ -841,185 +610,57 @@ static int rbd_snap_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
return -ERANGE;
}
- r = rados_selfmanaged_snap_create(s->header_pool, &snap_id);
+ r = rbd_snap_create(s->image, sn_info->name);
if (r < 0) {
- error_report("failed to create snap id: %s", strerror(-r));
+ error_report("failed to create snap: %s", strerror(-r));
return r;
}
- *(uint32_t *)p = strlen(sn_info->name);
- cpu_to_le32s((uint32_t *)p);
- p += sizeof(uint32_t);
- strncpy(p, sn_info->name, end - p);
- p += strlen(p);
- if (p + sizeof(snap_id) > end) {
- error_report("invalid input parameter");
- return -EINVAL;
- }
-
- *(uint64_t *)p = snap_id;
- cpu_to_le64s((uint64_t *)p);
-
- snprintf(n, sizeof(n), "%s%s", s->name, RBD_SUFFIX);
-
- r = rados_exec(s->header_pool, n, "rbd", "snap_add", inbuf,
- sizeof(inbuf), outbuf, sizeof(outbuf));
- if (r < 0) {
- error_report("rbd.snap_add execution failed failed: %s", strerror(-r));
- return r;
- }
-
- sprintf(sn_info->id_str, "%s", sn_info->name);
-
- r = rbd_read_header(s, &hbuf);
- if (r < 0) {
- error_report("failed reading header: %s", strerror(-r));
- return r;
- }
-
- header = (RbdHeader1 *) hbuf;
- r = rbd_set_snapc(s->pool, sn_info->name, header);
- if (r < 0) {
- error_report("failed setting snap context: %s", strerror(-r));
- goto failed;
- }
-
- return 0;
-
-failed:
- qemu_free(header);
- return r;
-}
-
-static int decode32(char **p, const char *end, uint32_t *v)
-{
- if (*p + 4 > end) {
- return -ERANGE;
- }
-
- *v = *(uint32_t *)(*p);
- le32_to_cpus(v);
- *p += 4;
return 0;
}
-static int decode64(char **p, const char *end, uint64_t *v)
-{
- if (*p + 8 > end) {
- return -ERANGE;
- }
-
- *v = *(uint64_t *)(*p);
- le64_to_cpus(v);
- *p += 8;
- return 0;
-}
-
-static int decode_str(char **p, const char *end, char **s)
-{
- uint32_t len;
- int r;
-
- if ((r = decode32(p, end, &len)) < 0) {
- return r;
- }
-
- *s = qemu_malloc(len + 1);
- memcpy(*s, *p, len);
- *p += len;
- (*s)[len] = '\0';
-
- return len;
-}
-
-static int rbd_snap_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
+static int qemu_rbd_snap_list(BlockDriverState *bs,
+ QEMUSnapshotInfo **psn_tab)
{
BDRVRBDState *s = bs->opaque;
- char n[RBD_MAX_SEG_NAME_SIZE];
QEMUSnapshotInfo *sn_info, *sn_tab = NULL;
- RbdHeader1 *header;
- char *hbuf = NULL;
- char *outbuf = NULL, *end, *buf;
- uint64_t len;
- uint64_t snap_seq;
- uint32_t snap_count;
- int r, i;
-
- /* read header to estimate how much space we need to read the snap
- * list */
- if ((r = rbd_read_header(s, &hbuf)) < 0) {
- goto done_err;
- }
- header = (RbdHeader1 *)hbuf;
- len = le64_to_cpu(header->snap_names_len);
- len += 1024; /* should have already been enough, but new snapshots might
- already been created since we read the header. just allocate
- a bit more, so that in most cases it'll suffice anyway */
- qemu_free(hbuf);
-
- snprintf(n, sizeof(n), "%s%s", s->name, RBD_SUFFIX);
- while (1) {
- qemu_free(outbuf);
- outbuf = qemu_malloc(len);
+ int i, snap_count;
+ rbd_snap_info_t *snaps;
+ int max_snaps = RBD_MAX_SNAPS;
- r = rados_exec(s->header_pool, n, "rbd", "snap_list", NULL, 0,
- outbuf, len);
- if (r < 0) {
- error_report("rbd.snap_list execution failed failed: %s", strerror(-r));
- goto done_err;
+ do {
+ snaps = qemu_malloc(sizeof(*snaps) * max_snaps);
+ snap_count = rbd_snap_list(s->image, snaps, &max_snaps);
+ if (snap_count < 0) {
+ qemu_free(snaps);
}
- if (r != len) {
- break;
- }
+ } while (snap_count == -ERANGE);
- /* if we're here, we probably raced with some snaps creation */
- len *= 2;
- }
- buf = outbuf;
- end = buf + len;
-
- if ((r = decode64(&buf, end, &snap_seq)) < 0) {
- goto done_err;
- }
- if ((r = decode32(&buf, end, &snap_count)) < 0) {
- goto done_err;
+ if (snap_count <= 0) {
+ return snap_count;
}
sn_tab = qemu_mallocz(snap_count * sizeof(QEMUSnapshotInfo));
- for (i = 0; i < snap_count; i++) {
- uint64_t id, image_size;
- char *snap_name;
- if ((r = decode64(&buf, end, &id)) < 0) {
- goto done_err;
- }
- if ((r = decode64(&buf, end, &image_size)) < 0) {
- goto done_err;
- }
- if ((r = decode_str(&buf, end, &snap_name)) < 0) {
- goto done_err;
- }
+ for (i = 0; i < snap_count; i++) {
+ const char *snap_name = snaps[i].name;
sn_info = sn_tab + i;
pstrcpy(sn_info->id_str, sizeof(sn_info->id_str), snap_name);
pstrcpy(sn_info->name, sizeof(sn_info->name), snap_name);
- qemu_free(snap_name);
- sn_info->vm_state_size = image_size;
+ sn_info->vm_state_size = snaps[i].size;
sn_info->date_sec = 0;
sn_info->date_nsec = 0;
sn_info->vm_clock_nsec = 0;
}
+ rbd_snap_list_end(snaps);
+
*psn_tab = sn_tab;
- qemu_free(outbuf);
return snap_count;
-done_err:
- qemu_free(sn_tab);
- qemu_free(outbuf);
- return r;
}
-static QEMUOptionParameter rbd_create_options[] = {
+static QEMUOptionParameter qemu_rbd_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
.type = OPT_SIZE,
@@ -1036,19 +677,19 @@ static QEMUOptionParameter rbd_create_options[] = {
static BlockDriver bdrv_rbd = {
.format_name = "rbd",
.instance_size = sizeof(BDRVRBDState),
- .bdrv_file_open = rbd_open,
- .bdrv_close = rbd_close,
- .bdrv_create = rbd_create,
- .bdrv_get_info = rbd_getinfo,
- .create_options = rbd_create_options,
- .bdrv_getlength = rbd_getlength,
+ .bdrv_file_open = qemu_rbd_open,
+ .bdrv_close = qemu_rbd_close,
+ .bdrv_create = qemu_rbd_create,
+ .bdrv_get_info = qemu_rbd_getinfo,
+ .create_options = qemu_rbd_create_options,
+ .bdrv_getlength = qemu_rbd_getlength,
.protocol_name = "rbd",
- .bdrv_aio_readv = rbd_aio_readv,
- .bdrv_aio_writev = rbd_aio_writev,
+ .bdrv_aio_readv = qemu_rbd_aio_readv,
+ .bdrv_aio_writev = qemu_rbd_aio_writev,
- .bdrv_snapshot_create = rbd_snap_create,
- .bdrv_snapshot_list = rbd_snap_list,
+ .bdrv_snapshot_create = qemu_rbd_snap_create,
+ .bdrv_snapshot_list = qemu_rbd_snap_list,
};
static void bdrv_rbd_init(void)
diff --git a/block/rbd_types.h b/block/rbd_types.h
deleted file mode 100644
index f4cca99..0000000
--- a/block/rbd_types.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2004-2010 Sage Weil <sage at newdream.net>
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation. See file COPYING.LIB.
- *
- */
-
-#ifndef CEPH_RBD_TYPES_H
-#define CEPH_RBD_TYPES_H
-
-
-/*
- * rbd image 'foo' consists of objects
- * foo.rbd - image metadata
- * foo.00000000
- * foo.00000001
- * ... - data
- */
-
-#define RBD_SUFFIX ".rbd"
-#define RBD_DIRECTORY "rbd_directory"
-#define RBD_INFO "rbd_info"
-
-#define RBD_DEFAULT_OBJ_ORDER 22 /* 4MB */
-
-#define RBD_MAX_OBJ_NAME_SIZE 96
-#define RBD_MAX_BLOCK_NAME_SIZE 24
-#define RBD_MAX_SEG_NAME_SIZE 128
-
-#define RBD_COMP_NONE 0
-#define RBD_CRYPT_NONE 0
-
-#define RBD_HEADER_TEXT "<<< Rados Block Device Image >>>\n"
-#define RBD_HEADER_SIGNATURE "RBD"
-#define RBD_HEADER_VERSION "001.005"
-
-struct rbd_info {
- uint64_t max_id;
-} __attribute__ ((packed));
-
-struct rbd_obj_snap_ondisk {
- uint64_t id;
- uint64_t image_size;
-} __attribute__((packed));
-
-struct rbd_obj_header_ondisk {
- char text[40];
- char block_name[RBD_MAX_BLOCK_NAME_SIZE];
- char signature[4];
- char version[8];
- struct {
- uint8_t order;
- uint8_t crypt_type;
- uint8_t comp_type;
- uint8_t unused;
- } __attribute__((packed)) options;
- uint64_t image_size;
- uint64_t snap_seq;
- uint32_t snap_count;
- uint32_t reserved;
- uint64_t snap_names_len;
- struct rbd_obj_snap_ondisk snaps[0];
-} __attribute__((packed));
-
-
-#endif
diff --git a/configure b/configure
index d38b952..bdacb49 100755
--- a/configure
+++ b/configure
@@ -1917,41 +1917,24 @@ fi
if test "$rbd" != "no" ; then
cat > $TMPC <<EOF
#include <stdio.h>
-#include <rados/librados.h>
-int main(void) { rados_initialize(0, NULL); return 0; }
-EOF
- rbd_libs="-lrados"
- if compile_prog "" "$rbd_libs" ; then
- librados_too_old=no
- cat > $TMPC <<EOF
-#include <stdio.h>
-#include <rados/librados.h>
-#ifndef CEPH_OSD_TMAP_SET
-#error missing CEPH_OSD_TMAP_SET
-#endif
+#include <rbd/librbd.h>
int main(void) {
- int (*func)(const rados_pool_t pool, uint64_t *snapid) = rados_selfmanaged_snap_create;
- rados_initialize(0, NULL);
+ rados_t cluster;
+ rados_create(&cluster, NULL);
return 0;
}
EOF
- if compile_prog "" "$rbd_libs" ; then
- rbd=yes
- libs_tools="$rbd_libs $libs_tools"
- libs_softmmu="$rbd_libs $libs_softmmu"
- else
- rbd=no
- librados_too_old=yes
- fi
+ rbd_libs="-lrbd -lrados"
+ if compile_prog "" "$rbd_libs" ; then
+ rbd=yes
+ libs_tools="$rbd_libs $libs_tools"
+ libs_softmmu="$rbd_libs $libs_softmmu"
else
if test "$rbd" = "yes" ; then
feature_not_found "rados block device"
fi
rbd=no
fi
- if test "$librados_too_old" = "yes" ; then
- echo "-> Your librados version is too old - upgrade needed to have rbd support"
- fi
fi
##########################################
commit d1f6fd8d1400ab356aee776b1ecc3ed1e89dbeaa
Author: Christoph Egger <Christoph.Egger at amd.com>
Date: Mon May 23 14:31:17 2011 +0200
block/raw-posix: get right partition size
use the correct way to get the size of a disk device or partition
From: Adam Hamsik <haad at netbsd.org>
Signed-off-by: Christoph Egger <Christoph.Egger at amd.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 00ed580..fd57b5b 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -64,6 +64,13 @@
#include <sys/dkio.h>
#endif
+#ifdef __NetBSD__
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/dkio.h>
+#include <sys/disk.h>
+#endif
+
#ifdef __DragonFly__
#include <sys/ioctl.h>
#include <sys/diskslice.h>
@@ -665,6 +672,31 @@ static int64_t raw_getlength(BlockDriverState *bs)
} else
return st.st_size;
}
+#elif defined(__NetBSD__)
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ int fd = s->fd;
+ struct stat st;
+
+ if (fstat(fd, &st))
+ return -1;
+ if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
+ struct dkwedge_info dkw;
+
+ if (ioctl(fd, DIOCGWEDGEINFO, &dkw) != -1) {
+ return dkw.dkw_size * 512;
+ } else {
+ struct disklabel dl;
+
+ if (ioctl(fd, DIOCGDINFO, &dl))
+ return -1;
+ return (uint64_t)dl.d_secsize *
+ dl.d_partitions[DISKPART(st.st_rdev)].p_size;
+ }
+ } else
+ return st.st_size;
+}
#elif defined(__sun__)
static int64_t raw_getlength(BlockDriverState *bs)
{
commit 1de1ae0a7d956b3c87712bf2c09d277f99873f4c
Author: Christoph Egger <Christoph.Egger at amd.com>
Date: Tue May 24 11:30:29 2011 +0200
block/raw-posix: use a character device if a block device is given
On NetBSD a userland process is better with the character device
interface. In addition, a block device can't be opened twice; if a Xen
backend opens it, qemu can't and vice-versa.
Signed-off-by: Christoph Egger <Christoph.Egger at amd.com>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 50428fd..00ed580 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -136,12 +136,55 @@ static int64_t raw_getlength(BlockDriverState *bs);
static int cdrom_reopen(BlockDriverState *bs);
#endif
+#if defined(__NetBSD__)
+static int raw_normalize_devicepath(const char **filename)
+{
+ static char namebuf[PATH_MAX];
+ const char *dp, *fname;
+ struct stat sb;
+
+ fname = *filename;
+ dp = strrchr(fname, '/');
+ if (lstat(fname, &sb) < 0) {
+ fprintf(stderr, "%s: stat failed: %s\n",
+ fname, strerror(errno));
+ return -errno;
+ }
+
+ if (!S_ISBLK(sb.st_mode)) {
+ return 0;
+ }
+
+ if (dp == NULL) {
+ snprintf(namebuf, PATH_MAX, "r%s", fname);
+ } else {
+ snprintf(namebuf, PATH_MAX, "%.*s/r%s",
+ (int)(dp - fname), fname, dp + 1);
+ }
+ fprintf(stderr, "%s is a block device", fname);
+ *filename = namebuf;
+ fprintf(stderr, ", using %s\n", *filename);
+
+ return 0;
+}
+#else
+static int raw_normalize_devicepath(const char **filename)
+{
+ return 0;
+}
+#endif
+
static int raw_open_common(BlockDriverState *bs, const char *filename,
int bdrv_flags, int open_flags)
{
BDRVRawState *s = bs->opaque;
int fd, ret;
+ ret = raw_normalize_devicepath(&filename);
+ if (ret != 0) {
+ return ret;
+ }
+
s->open_flags = open_flags | O_BINARY;
s->open_flags &= ~O_ACCMODE;
if (bdrv_flags & BDRV_O_RDWR) {
commit 16372ff03d71c7ed3283f0e873ea0727a35810a9
Author: Alexander Graf <agraf at suse.de>
Date: Wed May 25 00:46:55 2011 +0200
vmdk: fix endianness bugs
The vmdk code is sloppy when handling the header descriptor during
creation of an image. Fix all header accesses in the create path to
either store native endianness or convert it when appropriate.
Reported-by: Yury Tsarev <ytsarev at novell.com>
Signed-off-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block/vmdk.c b/block/vmdk.c
index 8fc9d67..922b23d 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -716,11 +716,11 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
return -errno;
magic = cpu_to_be32(VMDK4_MAGIC);
memset(&header, 0, sizeof(header));
- header.version = cpu_to_le32(1);
- header.flags = cpu_to_le32(3); /* ?? */
- header.capacity = cpu_to_le64(total_size);
- header.granularity = cpu_to_le64(128);
- header.num_gtes_per_gte = cpu_to_le32(512);
+ header.version = 1;
+ header.flags = 3; /* ?? */
+ header.capacity = total_size;
+ header.granularity = 128;
+ header.num_gtes_per_gte = 512;
grains = (total_size + header.granularity - 1) / header.granularity;
gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
@@ -736,6 +736,12 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
header.granularity - 1) / header.granularity) *
header.granularity;
+ /* swap endianness for all header fields */
+ header.version = cpu_to_le32(header.version);
+ header.flags = cpu_to_le32(header.flags);
+ header.capacity = cpu_to_le64(header.capacity);
+ header.granularity = cpu_to_le64(header.granularity);
+ header.num_gtes_per_gte = cpu_to_le32(header.num_gtes_per_gte);
header.desc_offset = cpu_to_le64(header.desc_offset);
header.desc_size = cpu_to_le64(header.desc_size);
header.rgd_offset = cpu_to_le64(header.rgd_offset);
@@ -759,7 +765,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
goto exit;
}
- ret = ftruncate(fd, header.grain_offset << 9);
+ ret = ftruncate(fd, le64_to_cpu(header.grain_offset) << 9);
if (ret < 0) {
ret = -errno;
goto exit;
@@ -767,7 +773,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
/* write grain directory */
lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
- for (i = 0, tmp = header.rgd_offset + gd_size;
+ for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_size;
i < gt_count; i++, tmp += gt_size) {
ret = qemu_write_full(fd, &tmp, sizeof(tmp));
if (ret != sizeof(tmp)) {
@@ -778,7 +784,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
/* write backup grain directory */
lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
- for (i = 0, tmp = header.gd_offset + gd_size;
+ for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_size;
i < gt_count; i++, tmp += gt_size) {
ret = qemu_write_full(fd, &tmp, sizeof(tmp));
if (ret != sizeof(tmp)) {
commit a659979328fb6d4d6100d398f5bd9a2310c3e169
Author: Christoph Hellwig <hch at lst.de>
Date: Tue May 17 18:04:06 2011 +0200
block: clarify the meaning of BDRV_O_NOCACHE
Change BDRV_O_NOCACHE to only imply bypassing the host OS file cache,
but no writeback semantics. All existing callers are changed to also
specify BDRV_O_CACHE_WB to give them writeback semantics.
Signed-off-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/block.c b/block.c
index effa86f..3036a2d 100644
--- a/block.c
+++ b/block.c
@@ -439,13 +439,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
bs->drv = drv;
bs->opaque = qemu_mallocz(drv->instance_size);
- /*
- * Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a
- * write cache to the guest. We do need the fdatasync to flush
- * out transactions for block allocations, and we maybe have a
- * volatile write cache in our backing device to deal with.
- */
- if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
+ if (flags & BDRV_O_CACHE_WB)
bs->enable_write_cache = 1;
/*
diff --git a/block/qcow2.c b/block/qcow2.c
index 75b8bec..db1931b 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -229,7 +229,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
}
/* alloc L2 table/refcount block cache */
- writethrough = ((flags & BDRV_O_CACHE_MASK) == 0);
+ writethrough = ((flags & BDRV_O_CACHE_WB) == 0);
s->l2_table_cache = qcow2_cache_create(bs, L2_CACHE_SIZE, writethrough);
s->refcount_block_cache = qcow2_cache_create(bs, REFCOUNT_CACHE_SIZE,
writethrough);
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 6b72470..50428fd 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -154,7 +154,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
* and O_DIRECT for no caching. */
if ((bdrv_flags & BDRV_O_NOCACHE))
s->open_flags |= O_DIRECT;
- else if (!(bdrv_flags & BDRV_O_CACHE_WB))
+ if (!(bdrv_flags & BDRV_O_CACHE_WB))
s->open_flags |= O_DSYNC;
s->fd = -1;
diff --git a/block/raw-win32.c b/block/raw-win32.c
index c204a80..56bd719 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -88,9 +88,9 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
}
overlapped = FILE_ATTRIBUTE_NORMAL;
- if ((flags & BDRV_O_NOCACHE))
- overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
- else if (!(flags & BDRV_O_CACHE_WB))
+ if (flags & BDRV_O_NOCACHE)
+ overlapped |= FILE_FLAG_NO_BUFFERING;
+ if (!(flags & BDRV_O_CACHE_WB))
overlapped |= FILE_FLAG_WRITE_THROUGH;
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
@@ -349,9 +349,9 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
create_flags = OPEN_EXISTING;
overlapped = FILE_ATTRIBUTE_NORMAL;
- if ((flags & BDRV_O_NOCACHE))
- overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
- else if (!(flags & BDRV_O_CACHE_WB))
+ if (flags & BDRV_O_NOCACHE)
+ overlapped |= FILE_FLAG_NO_BUFFERING;
+ if (!(flags & BDRV_O_CACHE_WB))
overlapped |= FILE_FLAG_WRITE_THROUGH;
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
diff --git a/blockdev.c b/blockdev.c
index 6e0eb83..1502575 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -326,7 +326,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
if (!strcmp(buf, "off") || !strcmp(buf, "none")) {
- bdrv_flags |= BDRV_O_NOCACHE;
+ bdrv_flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
} else if (!strcmp(buf, "writeback")) {
bdrv_flags |= BDRV_O_CACHE_WB;
} else if (!strcmp(buf, "unsafe")) {
diff --git a/qemu-io.c b/qemu-io.c
index 4470e49..dd4ebf5 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1655,7 +1655,7 @@ open_f(int argc, char **argv)
flags |= BDRV_O_SNAPSHOT;
break;
case 'n':
- flags |= BDRV_O_NOCACHE;
+ flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
break;
case 'r':
readonly = 1;
@@ -1751,7 +1751,7 @@ int main(int argc, char **argv)
flags |= BDRV_O_SNAPSHOT;
break;
case 'n':
- flags |= BDRV_O_NOCACHE;
+ flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
break;
case 'c':
add_user_command(optarg);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index e858033..110d78e 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -238,7 +238,7 @@ int main(int argc, char **argv)
flags |= BDRV_O_SNAPSHOT;
break;
case 'n':
- flags |= BDRV_O_NOCACHE;
+ flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
break;
case 'b':
bindto = optarg;
commit 69c38b8fcec823da05f98f6ea98ec2b0013d64e2
Author: Kevin Wolf <kwolf at redhat.com>
Date: Thu May 19 16:42:24 2011 +0200
ide/core: Remove explicit setting of BM_STATUS_INT
BM_STATUS_INT is automatically set during ide_set_irq(), there's no reason to
set it manually in addition.
There is even one case where the interrupt status bit was set, but no IRQ was
raised. This is when the PRD table was reached but there is more data to
transfer. The correct behaviour for this case is not to set BM_STATUS_INT.
Signed-off-by: Kevin Wolf <kwolf at redhat.com>
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 45410e8..95beb17 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -430,7 +430,6 @@ void ide_dma_error(IDEState *s)
s->error = ABRT_ERR;
s->status = READY_STAT | ERR_STAT;
ide_set_inactive(s);
- s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
ide_set_irq(s->bus);
}
@@ -500,8 +499,11 @@ handle_rw_error:
n = s->nsector;
s->io_buffer_index = 0;
s->io_buffer_size = n * 512;
- if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->is_read) == 0)
+ if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->is_read) == 0) {
+ /* The PRDs were too short. Reset the Active bit, but don't raise an
+ * interrupt. */
goto eot;
+ }
#ifdef DEBUG_AIO
printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, is_read=%d\n",
@@ -523,7 +525,6 @@ handle_rw_error:
return;
eot:
- s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
ide_set_inactive(s);
}
commit 7665385a8580ee5cea2cae44e1b58d6d7518a156
Author: Jan Kiszka <jan.kiszka at siemens.com>
Date: Tue Apr 26 01:32:08 2011 +0000
virtio: Move virtio-pci to hw library
This module has no target dependencies (except for target_phys_addr_t
size) and can thus be built as part of libhw.
Signed-off-by: Jan Kiszka <jan.kiszka at siemens.com>
Reviewed-by: Aurelien Jarno <aurelien at aurel32.net>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/Makefile.objs b/Makefile.objs
index 66ffad4..50fbb20 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -170,6 +170,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_PCI) += virtio-pci.o
hw-obj-y += fw_cfg.o
hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
hw-obj-$(CONFIG_PCI) += msix.o msi.o
diff --git a/Makefile.target b/Makefile.target
index 5c22df8..85480d8 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -190,7 +190,6 @@ obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
# 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_PCI) += virtio-pci.o
obj-y += vhost_net.o
obj-$(CONFIG_VHOST_NET) += vhost.o
obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p.o
commit 8001c294f878966c0a9efe2e811d56d3f5a7da69
Author: Martin Simmons <martin at lispworks.com>
Date: Mon Jun 6 15:49:17 2011 +0100
target-i386: Make x86 mfence and lfence illegal without SSE2
While trying to use qemu -cpu pentium3 to test for incorrect uses of certain
SSE2 instructions, I found that QEMU allowed the mfence and lfence
instructions to be executed even though Pentium 3 doesn't support them.
According to the processor specs (and experience on a real Pentium 3), these
instructions are only available with SSE2, but QEMU is checking for SSE. The
check for the related sfence instruction is correct (it works with SSE).
This trival patch fixes the test.
Signed-off-by: Martin Simmons <martin at lispworks.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 199302e..10bd72a 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7538,7 +7538,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
break;
case 5: /* lfence */
case 6: /* mfence */
- if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE))
+ if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE2))
goto illegal_op;
break;
case 7: /* sfence / clflush */
commit 351326a61842f3d4e7ed34d89b7d0f952f0af039
Author: Laurent Vivier <laurent at vivier.eu>
Date: Fri Mar 25 09:36:36 2011 +0000
m68k: Replace gen_im32() by tcg_const_i32()
Signed-off-by: Laurent Vivier <laurent at vivier.eu>
Reviewed-by: Andreas Färber <andreas.faerber at web.de>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 9e5578d..26f0ee4 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -171,9 +171,6 @@ typedef void (*disas_proc)(DisasContext *, uint16_t);
static void disas_##name (DisasContext *s, uint16_t insn)
#endif
-/* FIXME: Remove this. */
-#define gen_im32(val) tcg_const_i32(val)
-
/* Generate a load from the specified address. Narrow values are
sign extended to full register width. */
static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
@@ -339,7 +336,7 @@ static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base)
if ((ext & 0x80) == 0) {
/* base not suppressed */
if (IS_NULL_QREG(base)) {
- base = gen_im32(offset + bd);
+ base = tcg_const_i32(offset + bd);
bd = 0;
}
if (!IS_NULL_QREG(add)) {
@@ -355,7 +352,7 @@ static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base)
add = tmp;
}
} else {
- add = gen_im32(bd);
+ add = tcg_const_i32(bd);
}
if ((ext & 3) != 0) {
/* memory indirect */
@@ -536,15 +533,15 @@ static TCGv gen_lea(DisasContext *s, uint16_t insn, int opsize)
case 0: /* Absolute short. */
offset = ldsw_code(s->pc);
s->pc += 2;
- return gen_im32(offset);
+ return tcg_const_i32(offset);
case 1: /* Absolute long. */
offset = read_im32(s);
- return gen_im32(offset);
+ return tcg_const_i32(offset);
case 2: /* pc displacement */
offset = s->pc;
offset += ldsw_code(s->pc);
s->pc += 2;
- return gen_im32(offset);
+ return tcg_const_i32(offset);
case 3: /* pc index+displacement. */
return gen_lea_indexed(s, opsize, NULL_QREG);
case 4: /* Immediate. */
@@ -1209,16 +1206,16 @@ DISAS_INSN(arith_im)
break;
case 2: /* subi */
tcg_gen_mov_i32(dest, src1);
- gen_helper_xflag_lt(QREG_CC_X, dest, gen_im32(im));
+ gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im));
tcg_gen_subi_i32(dest, dest, im);
- gen_update_cc_add(dest, gen_im32(im));
+ gen_update_cc_add(dest, tcg_const_i32(im));
s->cc_op = CC_OP_SUB;
break;
case 3: /* addi */
tcg_gen_mov_i32(dest, src1);
tcg_gen_addi_i32(dest, dest, im);
- gen_update_cc_add(dest, gen_im32(im));
- gen_helper_xflag_lt(QREG_CC_X, dest, gen_im32(im));
+ gen_update_cc_add(dest, tcg_const_i32(im));
+ gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im));
s->cc_op = CC_OP_ADD;
break;
case 5: /* eori */
@@ -1228,7 +1225,7 @@ DISAS_INSN(arith_im)
case 6: /* cmpi */
tcg_gen_mov_i32(dest, src1);
tcg_gen_subi_i32(dest, dest, im);
- gen_update_cc_add(dest, gen_im32(im));
+ gen_update_cc_add(dest, tcg_const_i32(im));
s->cc_op = CC_OP_SUB;
break;
default:
@@ -1324,8 +1321,8 @@ DISAS_INSN(clr)
default:
abort();
}
- DEST_EA(insn, opsize, gen_im32(0), NULL);
- gen_logic_cc(s, gen_im32(0));
+ DEST_EA(insn, opsize, tcg_const_i32(0), NULL);
+ gen_logic_cc(s, tcg_const_i32(0));
}
static TCGv gen_get_ccr(DisasContext *s)
@@ -1589,7 +1586,7 @@ DISAS_INSN(jump)
}
if ((insn & 0x40) == 0) {
/* jsr */
- gen_push(s, gen_im32(s->pc));
+ gen_push(s, tcg_const_i32(s->pc));
}
gen_jmp(s, tmp);
}
@@ -1617,7 +1614,7 @@ DISAS_INSN(addsubq)
tcg_gen_addi_i32(dest, dest, val);
}
} else {
- src2 = gen_im32(val);
+ src2 = tcg_const_i32(val);
if (insn & 0x0100) {
gen_helper_xflag_lt(QREG_CC_X, dest, src2);
tcg_gen_subi_i32(dest, dest, val);
@@ -1666,7 +1663,7 @@ DISAS_INSN(branch)
}
if (op == 1) {
/* bsr */
- gen_push(s, gen_im32(s->pc));
+ gen_push(s, tcg_const_i32(s->pc));
}
gen_flush_cc_op(s);
if (op > 1) {
@@ -1757,7 +1754,7 @@ DISAS_INSN(mov3q)
val = (insn >> 9) & 7;
if (val == 0)
val = -1;
- src = gen_im32(val);
+ src = tcg_const_i32(val);
gen_logic_cc(s, src);
DEST_EA(insn, OS_LONG, src, NULL);
}
@@ -1883,7 +1880,7 @@ DISAS_INSN(shift_im)
tmp = (insn >> 9) & 7;
if (tmp == 0)
tmp = 8;
- shift = gen_im32(tmp);
+ shift = tcg_const_i32(tmp);
/* No need to flush flags becuse we know we will set C flag. */
if (insn & 0x100) {
gen_helper_shl_cc(reg, cpu_env, reg, shift);
@@ -2191,7 +2188,7 @@ DISAS_INSN(fpu)
switch ((ext >> 10) & 7) {
case 4: /* FPCR */
/* Not implemented. Always return zero. */
- tmp32 = gen_im32(0);
+ tmp32 = tcg_const_i32(0);
break;
case 1: /* FPIAR */
case 2: /* FPSR */
@@ -2592,7 +2589,7 @@ DISAS_INSN(mac)
/* Skip the accumulate if the value is already saturated. */
l1 = gen_new_label();
tmp = tcg_temp_new();
- gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
+ gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
gen_op_jmp_nz32(tmp, l1);
}
#endif
@@ -2626,7 +2623,7 @@ DISAS_INSN(mac)
/* Skip the accumulate if the value is already saturated. */
l1 = gen_new_label();
tmp = tcg_temp_new();
- gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
+ gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
gen_op_jmp_nz32(tmp, l1);
}
#endif
commit a9899996c8bc8eb7686f64207ef2ce1137dd125b
Author: Alexander Graf <agraf at suse.de>
Date: Sat Jun 4 07:25:59 2011 +0200
slirp: fix guestfwd id
When using -net user,guestfwd=... Qemu immediately complains about the id
being in invalid format. This is because we pass in an id that contains a
colon, while the id restrictions don't allow colons.
This patch changes the colon into a dot, making guestfwd work again.
Signed-off-by: Alexander Graf <agraf at suse.de>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/net/slirp.c b/net/slirp.c
index e387a11..e057a14 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -614,7 +614,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
}
fwd = qemu_malloc(sizeof(struct GuestFwd));
- snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port);
+ snprintf(buf, sizeof(buf), "guestfwd.tcp.%d", port);
fwd->hd = qemu_chr_open(buf, p, NULL);
if (!fwd->hd) {
error_report("could not open guest forwarding device '%s'", buf);
commit 9bf0960a9adb93c38b879a2114f6c67e30427307
Author: Alexandre Raymond <cerbere at gmail.com>
Date: Thu Jun 2 23:26:49 2011 -0400
Fix compilation warning due to missing header for sigaction (followup)
This patch removes all references to signal.h when qemu-common.h is included
as they become redundant.
Signed-off-by: Alexandre Raymond <cerbere at gmail.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/audio/audio_pt_int.c b/audio/audio_pt_int.c
index 908c569..9a9c306 100644
--- a/audio/audio_pt_int.c
+++ b/audio/audio_pt_int.c
@@ -6,8 +6,6 @@
#include "audio_int.h"
#include "audio_pt_int.h"
-#include <signal.h>
-
static void GCC_FMT_ATTR(3, 4) logerr (struct audio_pt *pt, int err,
const char *fmt, ...)
{
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index a847aa9..d24daa5 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -32,7 +32,6 @@
#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
#include <pthread.h>
#endif
-#include <signal.h>
#endif
#define AUDIO_CAP "sdl"
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 6b72470..9a72a17 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -43,7 +43,6 @@
#ifdef __sun__
#define _POSIX_PTHREAD_SEMANTICS 1
-#include <signal.h>
#include <sys/dkio.h>
#endif
#ifdef __linux__
@@ -53,7 +52,6 @@
#include <linux/fd.h>
#endif
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
-#include <signal.h>
#include <sys/disk.h>
#include <sys/cdio.h>
#endif
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index eb1cdf2..d4d039a 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -31,7 +31,6 @@
#include <sys/syscall.h>
#include <sys/param.h>
#include <sys/sysctl.h>
-#include <signal.h>
#include <utime.h>
#include "qemu.h"
diff --git a/darwin-user/signal.c b/darwin-user/signal.c
index 4862018..e2adca3 100644
--- a/darwin-user/signal.c
+++ b/darwin-user/signal.c
@@ -21,7 +21,6 @@
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
-#include <signal.h>
#include <errno.h>
#include <sys/ucontext.h>
@@ -32,8 +31,6 @@
#undef uc_link
#endif
-#include <signal.h>
-
#include "qemu.h"
#include "qemu-common.h"
diff --git a/exec.c b/exec.c
index 6f339ef..bffc201 100644
--- a/exec.c
+++ b/exec.c
@@ -36,7 +36,6 @@
#include "qemu-timer.h"
#if defined(CONFIG_USER_ONLY)
#include <qemu.h>
-#include <signal.h>
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <sys/param.h>
#if __FreeBSD_version >= 700104
diff --git a/linux-user/signal.c b/linux-user/signal.c
index c7a375f..11b25be 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -21,7 +21,6 @@
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
-#include <signal.h>
#include <errno.h>
#include <assert.h>
#include <sys/ucontext.h>
diff --git a/net/tap.c b/net/tap.c
index b8cd252..1f26dc9 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -27,7 +27,6 @@
#include "config-host.h"
-#include <signal.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index f3cc868..c4116e3 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -17,7 +17,6 @@
#include <unistd.h>
#include <errno.h>
#include <time.h>
-#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
diff --git a/qemu-char.c b/qemu-char.c
index 5e04a20..fb13b28 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -35,7 +35,6 @@
#include <unistd.h>
#include <fcntl.h>
-#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/time.h>
diff --git a/qemu-progress.c b/qemu-progress.c
index 8ebe8ef..5f1b8df 100644
--- a/qemu-progress.c
+++ b/qemu-progress.c
@@ -26,7 +26,6 @@
#include "osdep.h"
#include "sysemu.h"
#include <stdio.h>
-#include <signal.h>
struct progress_state {
float current;
diff --git a/savevm.c b/savevm.c
index f4ff1a1..939845c 100644
--- a/savevm.c
+++ b/savevm.c
@@ -23,7 +23,6 @@
*/
#include <unistd.h>
#include <fcntl.h>
-#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/time.h>
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 5c4b288..509d68c 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -21,7 +21,6 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
-#include <signal.h>
#include "cpu.h"
#include "exec-all.h"
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 4700632..cf2a368 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -21,7 +21,6 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
-#include <signal.h>
#include "cpu.h"
#include "exec-all.h"
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index b2d4d70..e9b42d0 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -21,7 +21,6 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
-#include <signal.h>
#include "cpu.h"
#include "exec-all.h"
diff --git a/ui/curses.c b/ui/curses.c
index 82bc614..d29b6cf 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -24,7 +24,6 @@
#include <curses.h>
#ifndef _WIN32
-#include <signal.h>
#include <sys/ioctl.h>
#include <termios.h>
#endif
diff --git a/ui/sdl.c b/ui/sdl.c
index 14a62d9..f2bd4a0 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -28,10 +28,6 @@
#include <SDL.h>
#include <SDL_syswm.h>
-#ifndef _WIN32
-#include <signal.h>
-#endif
-
#include "qemu-common.h"
#include "console.h"
#include "sysemu.h"
diff --git a/usb-bsd.c b/usb-bsd.c
index 9bab6e3..c1bcc4a 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -39,7 +39,6 @@
#else
#include <bus/usb/usb.h>
#endif
-#include <signal.h>
/* This value has maximum potential at 16.
* You should also set hw.usb.debug to gain
diff --git a/usb-linux.c b/usb-linux.c
index baa6574..fcfa09e 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -37,7 +37,6 @@
#include <dirent.h>
#include <sys/ioctl.h>
-#include <signal.h>
#include <linux/usbdevice_fs.h>
#include <linux/version.h>
commit 86f69a92b163dac5ee230c8a109c3e8f37f13d38
Author: Alexandre Raymond <cerbere at gmail.com>
Date: Wed Jun 1 22:21:30 2011 -0400
Fix compilation warning due to missing header for sigaction
Fix the following warning by including signal.h directly in qemu-common.h
----8<----
iohandler.c: In function âqemu_init_child_watchâ:
iohandler.c:172: warning: implicit declaration of function âsigactionâ
iohandler.c:172: warning: nested extern declaration of âsigactionâ
----8<----
Signed-off-by: Alexandre Raymond <cerbere at gmail.com>
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
diff --git a/qemu-common.h b/qemu-common.h
index b851b20..39fabc9 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -39,6 +39,7 @@ typedef struct Monitor Monitor;
#include <sys/stat.h>
#include <sys/time.h>
#include <assert.h>
+#include <signal.h>
#ifdef _WIN32
#include "qemu-os-win32.h"
commit a90d4690074526f54ad0851fce19fa6783f06803
Author: Glauber Costa <glommer at redhat.com>
Date: Mon May 16 15:45:08 2011 -0300
Add an isa device for SGA
This patch adds a dummy legacy ISA device whose responsibility is to
deploy sgabios, an option rom for a serial graphics adapter.
The proposal is that this device is always-on when -nographics,
but can otherwise be enable in any setup when -device sga is used.
[v2: suggestions on qdev by Markus ]
[v3: cleanups and documentation, per list suggestions ]
Signed-off-by: Glauber Costa <glommer at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile.target b/Makefile.target
index 8b6e271..5c22df8 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -231,7 +231,7 @@ obj-$(CONFIG_IVSHMEM) += ivshmem.o
# Hardware support
obj-i386-y += vga.o
obj-i386-y += mc146818rtc.o i8259.o pc.o
-obj-i386-y += cirrus_vga.o apic.o ioapic.o piix_pci.o
+obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o
obj-i386-y += vmport.o
obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
obj-i386-y += debugcon.o multiboot.o
diff --git a/hw/pc.c b/hw/pc.c
index 8106197..a3e8539 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1070,6 +1070,15 @@ void pc_vga_init(PCIBus *pci_bus)
isa_vga_init();
}
}
+
+ /*
+ * sga does not suppress normal vga output. So a machine can have both a
+ * vga card and sga manually enabled. Output will be seen on both.
+ * For nographic case, sga is enabled at all times
+ */
+ if (display_type == DT_NOGRAPHIC) {
+ isa_create_simple("sga");
+ }
}
static void cpu_request_exit(void *opaque, int irq, int level)
diff --git a/hw/sga.c b/hw/sga.c
new file mode 100644
index 0000000..7ef750a
--- /dev/null
+++ b/hw/sga.c
@@ -0,0 +1,56 @@
+/*
+ * QEMU dummy ISA device for loading sgabios option rom.
+ *
+ * Copyright (c) 2011 Glauber Costa, Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * sgabios code originally available at code.google.com/p/sgabios
+ *
+ */
+#include "pci.h"
+#include "pc.h"
+#include "loader.h"
+#include "sysemu.h"
+
+#define SGABIOS_FILENAME "sgabios.bin"
+
+typedef struct ISAGAState {
+ ISADevice dev;
+} ISASGAState;
+
+static int isa_cirrus_vga_initfn(ISADevice *dev)
+{
+ rom_add_vga(SGABIOS_FILENAME);
+ return 0;
+}
+
+static ISADeviceInfo sga_info = {
+ .qdev.name = "sga",
+ .qdev.desc = "Serial Graphics Adapter",
+ .qdev.size = sizeof(ISASGAState),
+ .init = isa_cirrus_vga_initfn,
+};
+
+static void sga_register(void)
+{
+ isa_qdev_register(&sga_info);
+}
+
+device_init(sga_register);
commit c1990ebfa11265d3aa9b6a4d5d1a02bd3f9ac5c6
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date: Wed Jun 1 12:15:00 2011 -0500
json-parser: add handling for NULL token list
Currently a NULL token list will crash the parser, instead we have it
pass back a NULL QObject.
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/json-parser.c b/json-parser.c
index 58e973b..849e215 100644
--- a/json-parser.c
+++ b/json-parser.c
@@ -633,9 +633,13 @@ QObject *json_parser_parse(QList *tokens, va_list *ap)
QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp)
{
JSONParserContext ctxt = {};
- QList *working = qlist_copy(tokens);
+ QList *working;
QObject *result;
+ if (!tokens) {
+ return NULL;
+ }
+ working = qlist_copy(tokens);
result = parse_value(&ctxt, &working, ap);
QDECREF(working);
commit 5e2dafeb198ba095ea784a97b44011ce2ed03511
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date: Wed Jun 1 12:14:59 2011 -0500
json-streamer: add handling for JSON_ERROR token/state
This allows a JSON_ERROR state to be passed to the streamer to force a
flush of the current tokens and pass a NULL token list to the parser
rather that have it churn on bad data. (Alternatively we could just not
pass it to the parser at all, but it may be useful to push there errors
up the stack. NULL token lists are not currently handled by the parser,
the next patch will address that)
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/json-streamer.c b/json-streamer.c
index a6cb28f..c255c78 100644
--- a/json-streamer.c
+++ b/json-streamer.c
@@ -56,29 +56,40 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok
qlist_append(parser->tokens, dict);
- if (parser->brace_count < 0 ||
+ if (type == JSON_ERROR) {
+ goto out_emit_bad;
+ } else if (parser->brace_count < 0 ||
parser->bracket_count < 0 ||
(parser->brace_count == 0 &&
parser->bracket_count == 0)) {
- parser->brace_count = 0;
- parser->bracket_count = 0;
- parser->emit(parser, parser->tokens);
- QDECREF(parser->tokens);
- parser->tokens = qlist_new();
- parser->token_size = 0;
+ goto out_emit;
} else if (parser->token_size > MAX_TOKEN_SIZE ||
parser->bracket_count > MAX_NESTING ||
parser->brace_count > MAX_NESTING) {
/* Security consideration, we limit total memory allocated per object
* and the maximum recursion depth that a message can force.
*/
- parser->brace_count = 0;
- parser->bracket_count = 0;
- parser->emit(parser, parser->tokens);
+ goto out_emit;
+ }
+
+ return;
+
+out_emit_bad:
+ /* clear out token list and tell the parser to emit and error
+ * indication by passing it a NULL list
+ */
+ QDECREF(parser->tokens);
+ parser->tokens = NULL;
+out_emit:
+ /* send current list of tokens to parser and reset tokenizer */
+ parser->brace_count = 0;
+ parser->bracket_count = 0;
+ parser->emit(parser, parser->tokens);
+ if (parser->tokens) {
QDECREF(parser->tokens);
- parser->tokens = qlist_new();
- parser->token_size = 0;
}
+ parser->tokens = qlist_new();
+ parser->token_size = 0;
}
void json_message_parser_init(JSONMessageParser *parser,
commit b011f61931f0113b29b7cd7e921dd022e0b04834
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date: Wed Jun 1 12:14:58 2011 -0500
json-lexer: make lexer error-recovery more deterministic
Currently when we reach an error state we effectively flush everything
fed to the lexer, which can put us in a state where we keep feeding
tokens into the parser at arbitrary offsets in the stream. This makes it
difficult for the lexer/tokenizer/parser to get back in sync when bad
input is made by the client.
With these changes we emit an error state/token up to the tokenizer as
soon as we reach an error state, and continue processing any data passed
in rather than bailing out. The reset token will be used to reset the
tokenizer and parser, such that they'll recover state as soon as the
lexer begins generating valid token sequences again.
We also map chr(192,193,245-255) to an error state here, since they are
invalid UTF-8 characters. QMP guest proxy/agent will use chr(255) to
force a flush/reset of previous input for reliable delivery of certain
events, so also we document that thoroughly here.
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/json-lexer.c b/json-lexer.c
index 6b49047..c21338f 100644
--- a/json-lexer.c
+++ b/json-lexer.c
@@ -105,7 +105,8 @@ static const uint8_t json_lexer[][256] = {
['u'] = IN_DQ_UCODE0,
},
[IN_DQ_STRING] = {
- [1 ... 0xFF] = IN_DQ_STRING,
+ [1 ... 0xBF] = IN_DQ_STRING,
+ [0xC2 ... 0xF4] = IN_DQ_STRING,
['\\'] = IN_DQ_STRING_ESCAPE,
['"'] = JSON_STRING,
},
@@ -144,7 +145,8 @@ static const uint8_t json_lexer[][256] = {
['u'] = IN_SQ_UCODE0,
},
[IN_SQ_STRING] = {
- [1 ... 0xFF] = IN_SQ_STRING,
+ [1 ... 0xBF] = IN_SQ_STRING,
+ [0xC2 ... 0xF4] = IN_SQ_STRING,
['\\'] = IN_SQ_STRING_ESCAPE,
['\''] = JSON_STRING,
},
@@ -305,10 +307,25 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
new_state = IN_START;
break;
case IN_ERROR:
+ /* XXX: To avoid having previous bad input leaving the parser in an
+ * unresponsive state where we consume unpredictable amounts of
+ * subsequent "good" input, percolate this error state up to the
+ * tokenizer/parser by forcing a NULL object to be emitted, then
+ * reset state.
+ *
+ * Also note that this handling is required for reliable channel
+ * negotiation between QMP and the guest agent, since chr(0xFF)
+ * is placed at the beginning of certain events to ensure proper
+ * delivery when the channel is in an unknown state. chr(0xFF) is
+ * never a valid ASCII/UTF-8 sequence, so this should reliably
+ * induce an error/flush state.
+ */
+ lexer->emit(lexer, lexer->token, JSON_ERROR, lexer->x, lexer->y);
QDECREF(lexer->token);
lexer->token = qstring_new();
new_state = IN_START;
- return -EINVAL;
+ lexer->state = new_state;
+ return 0;
default:
break;
}
@@ -346,7 +363,7 @@ int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
int json_lexer_flush(JSONLexer *lexer)
{
- return lexer->state == IN_START ? 0 : json_lexer_feed_char(lexer, 0);
+ return lexer->state == IN_START ? 0 : json_lexer_feed_char(lexer, 0, true);
}
void json_lexer_destroy(JSONLexer *lexer)
diff --git a/json-lexer.h b/json-lexer.h
index 3b50c46..10bc0a7 100644
--- a/json-lexer.h
+++ b/json-lexer.h
@@ -25,6 +25,7 @@ typedef enum json_token_type {
JSON_STRING,
JSON_ESCAPE,
JSON_SKIP,
+ JSON_ERROR,
} JSONTokenType;
typedef struct JSONLexer JSONLexer;
commit bd3924a33a66c40065a8fa73b4d7a27aca3b0e04
Author: Michael Roth <mdroth at linux.vnet.ibm.com>
Date: Wed Jun 1 12:14:57 2011 -0500
json-lexer: fix flushing logic to not always go to error state
Currently we flush the lexer by passing in a NULL character. This
generally forces the lexer to go to the corresponding TERMINAL() state
for whatever token type it is currently parsing, emits the token to the
parser, then puts the lexer back into IN_START state. However, since a
NULL character causes char_consumed to be 0, we always do a second pass
after this, which puts us in the IN_ERROR state. Fix this behavior by
adding a "flush" flag that tells the lexer not to do a more than 1
iteration.
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/json-lexer.c b/json-lexer.c
index a5bbe9e..6b49047 100644
--- a/json-lexer.c
+++ b/json-lexer.c
@@ -274,7 +274,7 @@ void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func)
lexer->x = lexer->y = 0;
}
-static int json_lexer_feed_char(JSONLexer *lexer, char ch)
+static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
{
int char_consumed, new_state;
@@ -313,7 +313,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch)
break;
}
lexer->state = new_state;
- } while (!char_consumed);
+ } while (!char_consumed && !flush);
/* Do not let a single token grow to an arbitrarily large size,
* this is a security consideration.
@@ -335,7 +335,7 @@ int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
for (i = 0; i < size; i++) {
int err;
- err = json_lexer_feed_char(lexer, buffer[i]);
+ err = json_lexer_feed_char(lexer, buffer[i], false);
if (err < 0) {
return err;
}
commit 529a0ef5f30e28a801d6527a3556adcaa4959669
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 1 12:14:56 2011 -0500
json-lexer: reset the lexer state on an invalid token
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/json-lexer.c b/json-lexer.c
index fe5a060..a5bbe9e 100644
--- a/json-lexer.c
+++ b/json-lexer.c
@@ -305,6 +305,9 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch)
new_state = IN_START;
break;
case IN_ERROR:
+ QDECREF(lexer->token);
+ lexer->token = qstring_new();
+ new_state = IN_START;
return -EINVAL;
default:
break;
commit 11e8a46cc3594567c6ba9b745f8f1b7d50be5b75
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 1 12:14:55 2011 -0500
json-parser: detect premature EOI
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/json-parser.c b/json-parser.c
index ac4063a..58e973b 100644
--- a/json-parser.c
+++ b/json-parser.c
@@ -275,10 +275,15 @@ out:
*/
static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_list *ap)
{
- QObject *key, *token = NULL, *value, *peek;
+ QObject *key = NULL, *token = NULL, *value, *peek;
QList *working = qlist_copy(*tokens);
peek = qlist_peek(working);
+ if (peek == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
key = parse_value(ctxt, &working, ap);
if (!key || qobject_type(key) != QTYPE_QSTRING) {
parse_error(ctxt, peek, "key is not a string in object");
@@ -286,6 +291,11 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_l
}
token = qlist_pop(working);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
if (!token_is_operator(token, ':')) {
parse_error(ctxt, token, "missing : in object pair");
goto out;
@@ -321,6 +331,10 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
QList *working = qlist_copy(*tokens);
token = qlist_pop(working);
+ if (token == NULL) {
+ goto out;
+ }
+
if (!token_is_operator(token, '{')) {
goto out;
}
@@ -330,12 +344,22 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
dict = qdict_new();
peek = qlist_peek(working);
+ if (peek == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
if (!token_is_operator(peek, '}')) {
if (parse_pair(ctxt, dict, &working, ap) == -1) {
goto out;
}
token = qlist_pop(working);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
while (!token_is_operator(token, '}')) {
if (!token_is_operator(token, ',')) {
parse_error(ctxt, token, "expected separator in dict");
@@ -349,6 +373,10 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
}
token = qlist_pop(working);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
}
qobject_decref(token);
token = NULL;
@@ -377,6 +405,10 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
QList *working = qlist_copy(*tokens);
token = qlist_pop(working);
+ if (token == NULL) {
+ goto out;
+ }
+
if (!token_is_operator(token, '[')) {
goto out;
}
@@ -386,6 +418,11 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
list = qlist_new();
peek = qlist_peek(working);
+ if (peek == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
if (!token_is_operator(peek, ']')) {
QObject *obj;
@@ -398,6 +435,11 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
qlist_append_obj(list, obj);
token = qlist_pop(working);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
while (!token_is_operator(token, ']')) {
if (!token_is_operator(token, ',')) {
parse_error(ctxt, token, "expected separator in list");
@@ -416,6 +458,10 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
qlist_append_obj(list, obj);
token = qlist_pop(working);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
}
qobject_decref(token);
@@ -444,6 +490,9 @@ static QObject *parse_keyword(JSONParserContext *ctxt, QList **tokens)
QList *working = qlist_copy(*tokens);
token = qlist_pop(working);
+ if (token == NULL) {
+ goto out;
+ }
if (token_get_type(token) != JSON_KEYWORD) {
goto out;
@@ -481,6 +530,9 @@ static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *a
}
token = qlist_pop(working);
+ if (token == NULL) {
+ goto out;
+ }
if (token_is_escape(token, "%p")) {
obj = va_arg(*ap, QObject *);
@@ -520,6 +572,10 @@ static QObject *parse_literal(JSONParserContext *ctxt, QList **tokens)
QList *working = qlist_copy(*tokens);
token = qlist_pop(working);
+ if (token == NULL) {
+ goto out;
+ }
+
switch (token_get_type(token)) {
case JSON_STRING:
obj = QOBJECT(qstring_from_escaped_str(ctxt, token));
commit eca7db46ff8f24a70f4040af3e941dc19fd33ebe
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 1 12:14:54 2011 -0500
json-streamer: make sure to reset token_size after emitting a token list
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/json-streamer.c b/json-streamer.c
index 6b9af63..a6cb28f 100644
--- a/json-streamer.c
+++ b/json-streamer.c
@@ -65,6 +65,7 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok
parser->emit(parser, parser->tokens);
QDECREF(parser->tokens);
parser->tokens = qlist_new();
+ parser->token_size = 0;
} else if (parser->token_size > MAX_TOKEN_SIZE ||
parser->bracket_count > MAX_NESTING ||
parser->brace_count > MAX_NESTING) {
@@ -76,6 +77,7 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok
parser->emit(parser, parser->tokens);
QDECREF(parser->tokens);
parser->tokens = qlist_new();
+ parser->token_size = 0;
}
}
diff --git a/json-streamer.h b/json-streamer.h
index 09f3bd7..f09bc4d 100644
--- a/json-streamer.h
+++ b/json-streamer.h
@@ -24,6 +24,7 @@ typedef struct JSONMessageParser
int brace_count;
int bracket_count;
QList *tokens;
+ uint64_t token_size;
} JSONMessageParser;
void json_message_parser_init(JSONMessageParser *parser,
commit 29c75ddd87ff7904005da08ff1056395261d90f1
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 1 12:14:53 2011 -0500
json-streamer: limit the maximum recursion depth and maximum token count
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/json-streamer.c b/json-streamer.c
index 549e9b7..6b9af63 100644
--- a/json-streamer.c
+++ b/json-streamer.c
@@ -18,6 +18,9 @@
#include "json-lexer.h"
#include "json-streamer.h"
+#define MAX_TOKEN_SIZE (64ULL << 20)
+#define MAX_NESTING (1ULL << 10)
+
static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTokenType type, int x, int y)
{
JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
@@ -49,6 +52,8 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok
qdict_put(dict, "x", qint_from_int(x));
qdict_put(dict, "y", qint_from_int(y));
+ parser->token_size += token->length;
+
qlist_append(parser->tokens, dict);
if (parser->brace_count < 0 ||
@@ -60,6 +65,17 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok
parser->emit(parser, parser->tokens);
QDECREF(parser->tokens);
parser->tokens = qlist_new();
+ } else if (parser->token_size > MAX_TOKEN_SIZE ||
+ parser->bracket_count > MAX_NESTING ||
+ parser->brace_count > MAX_NESTING) {
+ /* Security consideration, we limit total memory allocated per object
+ * and the maximum recursion depth that a message can force.
+ */
+ parser->brace_count = 0;
+ parser->bracket_count = 0;
+ parser->emit(parser, parser->tokens);
+ QDECREF(parser->tokens);
+ parser->tokens = qlist_new();
}
}
@@ -70,6 +86,7 @@ void json_message_parser_init(JSONMessageParser *parser,
parser->brace_count = 0;
parser->bracket_count = 0;
parser->tokens = qlist_new();
+ parser->token_size = 0;
json_lexer_init(&parser->lexer, json_message_process_token);
}
commit 325601b47b64b33cbe237508df2037e195795497
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 1 12:14:52 2011 -0500
json-lexer: limit the maximum size of a given token
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/json-lexer.c b/json-lexer.c
index 65c9720..fe5a060 100644
--- a/json-lexer.c
+++ b/json-lexer.c
@@ -18,6 +18,8 @@
#include "qemu-common.h"
#include "json-lexer.h"
+#define MAX_TOKEN_SIZE (64ULL << 20)
+
/*
* \"([^\\\"]|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*\"
* '([^\\']|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*'
@@ -309,6 +311,17 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch)
}
lexer->state = new_state;
} while (!char_consumed);
+
+ /* Do not let a single token grow to an arbitrarily large size,
+ * this is a security consideration.
+ */
+ if (lexer->token->length > MAX_TOKEN_SIZE) {
+ lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y);
+ QDECREF(lexer->token);
+ lexer->token = qstring_new();
+ lexer->state = IN_START;
+ }
+
return 0;
}
commit 55f8301f7665eeef6d454cf4843c3f67b067f357
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 1 12:14:51 2011 -0500
json-streamer: allow recovery after bad input
Once we detect a malformed message, make sure to reset our state.
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/json-streamer.c b/json-streamer.c
index f7e7a68..549e9b7 100644
--- a/json-streamer.c
+++ b/json-streamer.c
@@ -51,8 +51,12 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok
qlist_append(parser->tokens, dict);
- if (parser->brace_count == 0 &&
- parser->bracket_count == 0) {
+ if (parser->brace_count < 0 ||
+ parser->bracket_count < 0 ||
+ (parser->brace_count == 0 &&
+ parser->bracket_count == 0)) {
+ parser->brace_count = 0;
+ parser->bracket_count = 0;
parser->emit(parser, parser->tokens);
QDECREF(parser->tokens);
parser->tokens = qlist_new();
commit ef749d07e717ca38b7d8b525c81d6b04db5f16ed
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Wed Jun 1 12:14:50 2011 -0500
json-parser: propagate error from parser
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile b/Makefile
index b6466e7..096480b 100644
--- a/Makefile
+++ b/Makefile
@@ -134,14 +134,14 @@ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS)
-CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y)
+CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y) qemu-tool.o
check-qint: check-qint.o qint.o $(CHECK_PROG_DEPS)
check-qstring: check-qstring.o qstring.o $(CHECK_PROG_DEPS)
check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(CHECK_PROG_DEPS)
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 $(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)
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
diff --git a/Makefile.objs b/Makefile.objs
index 0f7bb52..66ffad4 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -2,7 +2,7 @@
# QObject
qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
-qobject-obj-y += qerror.o
+qobject-obj-y += qerror.o error.o
#######################################################################
# oslib-obj-y is code depending on the OS (win32 vs posix)
@@ -59,7 +59,7 @@ fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
# system emulation, i.e. a single QEMU executable should support all
# CPUs and machines.
-common-obj-y = $(block-obj-y) blockdev.o error.o
+common-obj-y = $(block-obj-y) blockdev.o
common-obj-y += $(net-obj-y)
common-obj-y += $(qobject-obj-y)
common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
diff --git a/json-parser.c b/json-parser.c
index 6c06ef9..ac4063a 100644
--- a/json-parser.c
+++ b/json-parser.c
@@ -22,9 +22,11 @@
#include "qbool.h"
#include "json-parser.h"
#include "json-lexer.h"
+#include "qerror.h"
typedef struct JSONParserContext
{
+ Error *err;
} JSONParserContext;
#define BUG_ON(cond) assert(!(cond))
@@ -95,11 +97,15 @@ static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt,
QObject *token, const char *msg, ...)
{
va_list ap;
+ char message[1024];
va_start(ap, msg);
- fprintf(stderr, "parse error: ");
- vfprintf(stderr, msg, ap);
- fprintf(stderr, "\n");
+ vsnprintf(message, sizeof(message), msg, ap);
va_end(ap);
+ if (ctxt->err) {
+ error_free(ctxt->err);
+ ctxt->err = NULL;
+ }
+ error_set(&ctxt->err, QERR_JSON_PARSE_ERROR, message);
}
/**
@@ -565,6 +571,11 @@ static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap
QObject *json_parser_parse(QList *tokens, va_list *ap)
{
+ return json_parser_parse_err(tokens, ap, NULL);
+}
+
+QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp)
+{
JSONParserContext ctxt = {};
QList *working = qlist_copy(tokens);
QObject *result;
@@ -573,5 +584,7 @@ QObject *json_parser_parse(QList *tokens, va_list *ap)
QDECREF(working);
+ error_propagate(errp, ctxt.err);
+
return result;
}
diff --git a/json-parser.h b/json-parser.h
index 97f43f6..8f2b5ec 100644
--- a/json-parser.h
+++ b/json-parser.h
@@ -16,7 +16,9 @@
#include "qemu-common.h"
#include "qlist.h"
+#include "error.h"
QObject *json_parser_parse(QList *tokens, va_list *ap);
+QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp);
#endif
diff --git a/qerror.h b/qerror.h
index 13ad9d4..8b971fd 100644
--- a/qerror.h
+++ b/qerror.h
@@ -121,6 +121,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_JSON_PARSING \
"{ 'class': 'JSONParsing', 'data': {} }"
+#define QERR_JSON_PARSE_ERROR \
+ "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
+
#define QERR_KVM_MISSING_CAP \
"{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
commit d5ec4f27c387c3b3200abb8656343b2519ea3047
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date: Wed Jun 1 12:14:49 2011 -0500
Introduce the new error framework
New error-handling framework that allows for exception-like error
propagation.
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/Makefile.objs b/Makefile.objs
index 90838f6..0f7bb52 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -59,7 +59,7 @@ fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
# system emulation, i.e. a single QEMU executable should support all
# CPUs and machines.
-common-obj-y = $(block-obj-y) blockdev.o
+common-obj-y = $(block-obj-y) blockdev.o error.o
common-obj-y += $(net-obj-y)
common-obj-y += $(qobject-obj-y)
common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
diff --git a/error.c b/error.c
new file mode 100644
index 0000000..867eec2
--- /dev/null
+++ b/error.c
@@ -0,0 +1,140 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2. See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#include "error.h"
+#include "error_int.h"
+#include "qemu-objects.h"
+#include "qerror.h"
+#include <assert.h>
+
+struct Error
+{
+ QDict *obj;
+ const char *fmt;
+ char *msg;
+};
+
+void error_set(Error **errp, const char *fmt, ...)
+{
+ Error *err;
+ va_list ap;
+
+ if (errp == NULL) {
+ return;
+ }
+
+ err = qemu_mallocz(sizeof(*err));
+
+ va_start(ap, fmt);
+ err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap));
+ va_end(ap);
+ err->fmt = fmt;
+
+ *errp = err;
+}
+
+bool error_is_set(Error **errp)
+{
+ return (errp && *errp);
+}
+
+const char *error_get_pretty(Error *err)
+{
+ if (err->msg == NULL) {
+ QString *str;
+ str = qerror_format(err->fmt, err->obj);
+ err->msg = qemu_strdup(qstring_get_str(str));
+ QDECREF(str);
+ }
+
+ return err->msg;
+}
+
+const char *error_get_field(Error *err, const char *field)
+{
+ if (strcmp(field, "class") == 0) {
+ return qdict_get_str(err->obj, field);
+ } else {
+ QDict *dict = qdict_get_qdict(err->obj, "data");
+ return qdict_get_str(dict, field);
+ }
+}
+
+QDict *error_get_data(Error *err)
+{
+ QDict *data = qdict_get_qdict(err->obj, "data");
+ QINCREF(data);
+ return data;
+}
+
+void error_set_field(Error *err, const char *field, const char *value)
+{
+ QDict *dict = qdict_get_qdict(err->obj, "data");
+ return qdict_put(dict, field, qstring_from_str(value));
+}
+
+void error_free(Error *err)
+{
+ if (err) {
+ QDECREF(err->obj);
+ qemu_free(err->msg);
+ qemu_free(err);
+ }
+}
+
+bool error_is_type(Error *err, const char *fmt)
+{
+ const char *error_class;
+ char *ptr;
+ char *end;
+
+ ptr = strstr(fmt, "'class': '");
+ assert(ptr != NULL);
+ ptr += strlen("'class': '");
+
+ end = strchr(ptr, '\'');
+ assert(end != NULL);
+
+ error_class = error_get_field(err, "class");
+ if (strlen(error_class) != end - ptr) {
+ return false;
+ }
+
+ return strncmp(ptr, error_class, end - ptr) == 0;
+}
+
+void error_propagate(Error **dst_err, Error *local_err)
+{
+ if (dst_err) {
+ *dst_err = local_err;
+ } else if (local_err) {
+ error_free(local_err);
+ }
+}
+
+QObject *error_get_qobject(Error *err)
+{
+ QINCREF(err->obj);
+ return QOBJECT(err->obj);
+}
+
+void error_set_qobject(Error **errp, QObject *obj)
+{
+ Error *err;
+ if (errp == NULL) {
+ return;
+ }
+ err = qemu_mallocz(sizeof(*err));
+ err->obj = qobject_to_qdict(obj);
+ qobject_incref(obj);
+
+ *errp = err;
+}
diff --git a/error.h b/error.h
new file mode 100644
index 0000000..003c855
--- /dev/null
+++ b/error.h
@@ -0,0 +1,70 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2. See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#ifndef ERROR_H
+#define ERROR_H
+
+#include <stdbool.h>
+
+/**
+ * A class representing internal errors within QEMU. An error has a string
+ * typename and optionally a set of named string parameters.
+ */
+typedef struct Error Error;
+
+/**
+ * Set an indirect pointer to an error given a printf-style format parameter.
+ * Currently, qerror.h defines these error formats. This function is not
+ * meant to be used outside of QEMU.
+ */
+void error_set(Error **err, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+
+/**
+ * Returns true if an indirect pointer to an error is pointing to a valid
+ * error object.
+ */
+bool error_is_set(Error **err);
+
+/**
+ * Get a human readable representation of an error object.
+ */
+const char *error_get_pretty(Error *err);
+
+/**
+ * Get an individual named error field.
+ */
+const char *error_get_field(Error *err, const char *field);
+
+/**
+ * Get an individual named error field.
+ */
+void error_set_field(Error *err, const char *field, const char *value);
+
+/**
+ * Propagate an error to an indirect pointer to an error. This function will
+ * always transfer ownership of the error reference and handles the case where
+ * dst_err is NULL correctly.
+ */
+void error_propagate(Error **dst_err, Error *local_err);
+
+/**
+ * Free an error object.
+ */
+void error_free(Error *err);
+
+/**
+ * Determine if an error is of a speific type (based on the qerror format).
+ * Non-QEMU users should get the `class' field to identify the error type.
+ */
+bool error_is_type(Error *err, const char *fmt);
+
+#endif
diff --git a/error_int.h b/error_int.h
new file mode 100644
index 0000000..5e39424
--- /dev/null
+++ b/error_int.h
@@ -0,0 +1,29 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2. See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#ifndef QEMU_ERROR_INT_H
+#define QEMU_ERROR_INT_H
+
+#include "qemu-common.h"
+#include "qobject.h"
+#include "qdict.h"
+#include "error.h"
+
+/**
+ * Internal QEMU functions for working with Error.
+ *
+ * These are used to convert QErrors to Errors
+ */
+QDict *error_get_data(Error *err);
+QObject *error_get_qobject(Error *err);
+void error_set_qobject(Error **errp, QObject *obj);
+
+#endif
commit 87c2f59166b7ec5b3ce44b5c4a2337c07a78e533
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date: Wed Jun 1 12:14:48 2011 -0500
QError: Introduce qerror_format()
Will be used by new error propagation framework to convert Error objects
into human-readable form.
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/qerror.c b/qerror.c
index af6ed39..c18641f 100644
--- a/qerror.c
+++ b/qerror.c
@@ -400,6 +400,21 @@ static QString *qerror_format_desc(QDict *error,
return qstring;
}
+QString *qerror_format(const char *fmt, QDict *error)
+{
+ const QErrorStringTable *entry = NULL;
+ int i;
+
+ for (i = 0; qerror_table[i].error_fmt; i++) {
+ if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
+ entry = &qerror_table[i];
+ break;
+ }
+ }
+
+ return qerror_format_desc(error, entry);
+}
+
/**
* qerror_human(): Format QError data into human-readable string.
*/
diff --git a/qerror.h b/qerror.h
index df61d2c..13ad9d4 100644
--- a/qerror.h
+++ b/qerror.h
@@ -39,6 +39,7 @@ QString *qerror_human(const QError *qerror);
void qerror_print(QError *qerror);
void qerror_report_internal(const char *file, int linenr, const char *func,
const char *fmt, ...) GCC_FMT_ATTR(4, 5);
+QString *qerror_format(const char *fmt, QDict *error);
#define qerror_report(fmt, ...) \
qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
QError *qobject_to_qerror(const QObject *obj);
commit a12eeaaa4fdaed9ed4a92f337b5f3c8a5a3fb946
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date: Wed Jun 1 12:14:47 2011 -0500
QError: Introduce qerror_format_desc()
Refactor non-QError-specific bits out of qerror_human() into general
function that can be used by the error_get_pretty() analogue in the
new error-propagation framework.
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
Signed-off-by: Michael Roth <mdroth at linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/qerror.c b/qerror.c
index 4855604..af6ed39 100644
--- a/qerror.c
+++ b/qerror.c
@@ -326,12 +326,14 @@ QError *qerror_from_info(const char *file, int linenr, const char *func,
return qerr;
}
-static void parse_error(const QError *qerror, int c)
+static void parse_error(const QErrorStringTable *entry, int c)
{
- qerror_abort(qerror, "expected '%c' in '%s'", c, qerror->entry->desc);
+ fprintf(stderr, "expected '%c' in '%s'", c, entry->desc);
+ abort();
}
-static const char *append_field(QString *outstr, const QError *qerror,
+static const char *append_field(QDict *error, QString *outstr,
+ const QErrorStringTable *entry,
const char *start)
{
QObject *obj;
@@ -340,23 +342,23 @@ static const char *append_field(QString *outstr, const QError *qerror,
const char *end, *key;
if (*start != '%')
- parse_error(qerror, '%');
+ parse_error(entry, '%');
start++;
if (*start != '(')
- parse_error(qerror, '(');
+ parse_error(entry, '(');
start++;
end = strchr(start, ')');
if (!end)
- parse_error(qerror, ')');
+ parse_error(entry, ')');
key_qs = qstring_from_substr(start, 0, end - start - 1);
key = qstring_get_str(key_qs);
- qdict = qobject_to_qdict(qdict_get(qerror->error, "data"));
+ qdict = qobject_to_qdict(qdict_get(error, "data"));
obj = qdict_get(qdict, key);
if (!obj) {
- qerror_abort(qerror, "key '%s' not found in QDict", key);
+ abort();
}
switch (qobject_type(obj)) {
@@ -367,35 +369,31 @@ static const char *append_field(QString *outstr, const QError *qerror,
qstring_append_int(outstr, qdict_get_int(qdict, key));
break;
default:
- qerror_abort(qerror, "invalid type '%c'", qobject_type(obj));
+ abort();
}
QDECREF(key_qs);
return ++end;
}
-/**
- * qerror_human(): Format QError data into human-readable string.
- *
- * Formats according to member 'desc' of the specified QError object.
- */
-QString *qerror_human(const QError *qerror)
+static QString *qerror_format_desc(QDict *error,
+ const QErrorStringTable *entry)
{
- const char *p;
QString *qstring;
+ const char *p;
- assert(qerror->entry != NULL);
+ assert(entry != NULL);
qstring = qstring_new();
- for (p = qerror->entry->desc; *p != '\0';) {
+ for (p = entry->desc; *p != '\0';) {
if (*p != '%') {
qstring_append_chr(qstring, *p++);
} else if (*(p + 1) == '%') {
qstring_append_chr(qstring, '%');
p += 2;
} else {
- p = append_field(qstring, qerror, p);
+ p = append_field(error, qstring, entry, p);
}
}
@@ -403,6 +401,14 @@ QString *qerror_human(const QError *qerror)
}
/**
+ * qerror_human(): Format QError data into human-readable string.
+ */
+QString *qerror_human(const QError *qerror)
+{
+ return qerror_format_desc(qerror->error, qerror->entry);
+}
+
+/**
* qerror_print(): Print QError data
*
* This function will print the member 'desc' of the specified QError object,
commit 23bf93b215b48bab4a9739d6300ec533773588e8
Author: Markus Armbruster <armbru at redhat.com>
Date: Tue Jun 7 10:34:31 2011 +0200
docs: qdev-device-use.txt has become stale, update it
Document more bus addresses.
Update for bugs fixed.
Describe where exactly the -drive options go.
Update for recent split of qdev ide-drive into ide-{cd,hd},
scsi-disk into scsi-{cd,hd}.
Document scsi-hd's removable property only for usb-storage, because
that's where it's used.
Fix description of -global isa.fdc.
Document usb-storage lossage.
Clean up misleading description of network device's split into guest
and host part.
Document -vga's machine dependence.
New qdevs: virtconsole, qxl-vga, isa-vga, intel-hda, usb-ccid
Update for changed pci-assign property iommu.
New section "Default Devices".
Signed-off-by: Markus Armbruster <armbru at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt
index 4bb2be8..057c322 100644
--- a/docs/qdev-device-use.txt
+++ b/docs/qdev-device-use.txt
@@ -8,20 +8,23 @@ more buses for children. You can specify a device's parent bus with
A device typically has a device address on its parent bus. For buses
where this address can be configured, devices provide a bus-specific
-property. These are
-
- bus property name value format
- PCI addr %x.%x (dev.fn, .fn optional)
- I2C address %u
- SCSI scsi-id %u
+property. Examples:
+
+ bus property name value format
+ PCI addr %x.%x (dev.fn, .fn optional)
+ I2C address %u
+ SCSI scsi-id %u
+ IDE unit %u
+ HDA cad %u
+ virtio-serial-bus nr %u
+ ccid-bus slot %u
+ USB port %d(.%d)* (port.port...)
Example: device i440FX-pcihost is on the root bus, and provides a PCI
bus named pci.0. To put a FOO device into its slot 4, use -device
FOO,bus=/i440FX-pcihost/pci.0,addr=4. The abbreviated form bus=pci.0
also works as long as the bus name is unique.
-Note: the USB device address can't be controlled at this time.
-
=== Block Devices ===
A QEMU block device (drive) has a host and a guest part.
@@ -44,28 +47,43 @@ The new way keeps the parts separate: you create the host part with
The various old ways to define drives all boil down to the common form
- -drive if=TYPE,index=IDX,bus=BUS,unit=UNIT,HOST-OPTS...
+ -drive if=TYPE,bus=BUS,unit=UNIT,OPTS...
TYPE, BUS and UNIT identify the controller device, which of its buses
to use, and the drive's address on that bus. Details depend on TYPE.
-IDX is an alternative way to specify BUS and UNIT.
+
+Instead of bus=BUS,unit=UNIT, you can also say index=IDX.
In the new way, this becomes something like
-drive if=none,id=DRIVE-ID,HOST-OPTS...
-device DEVNAME,drive=DRIVE-ID,DEV-OPTS...
-The -device argument differs in detail for each kind of drive:
+The old OPTS get split into HOST-OPTS and DEV-OPTS as follows:
-* if=ide
+* file, format, snapshot, cache, aio, readonly, rerror, werror go into
+ HOST-OPTS.
+
+* cyls, head, secs and trans go into HOST-OPTS. Future work: they
+ should go into DEV-OPTS instead.
+
+* serial goes into DEV-OPTS, for devices supporting serial numbers.
+ For other devices, it goes nowhere.
- -device ide-drive,drive=DRIVE-ID,bus=IDE-BUS,unit=UNIT
+* media is special. In the old way, it selects disk vs. CD-ROM with
+ if=ide, if=scsi and if=xen. The new way uses DEVNAME for that.
+ Additionally, readonly=on goes into HOST-OPTS.
- where IDE-BUS identifies an IDE bus, normally either ide.0 or ide.1,
- and UNIT is either 0 or 1.
+* addr is special, see if=virtio below.
- Bug: new way does not work for ide.1 unit 0 (in old terms: index=2)
- unless you disable the default CD-ROM with -nodefaults.
+The -device argument differs in detail for each type of drive:
+
+* if=ide
+
+ -device DEVNAME,drive=DRIVE-ID,bus=IDE-BUS,unit=UNIT
+
+ where DEVNAME is either ide-hd or ide-cd, IDE-BUS identifies an IDE
+ bus, normally either ide.0 or ide.1, and UNIT is either 0 or 1.
* if=scsi
@@ -77,27 +95,25 @@ The -device argument differs in detail for each kind of drive:
As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to
control the PCI device address.
- This SCSI controller a single SCSI bus, named ID.0. Put a disk on
- it:
+ This SCSI controller provides a single SCSI bus, named ID.0. Put a
+ disk on it:
- -device scsi-disk,drive=DRIVE-ID,bus=ID.0,scsi-id=SCSI-ID,removable=RMB
+ -device DEVNAME,drive=DRIVE-ID,bus=ID.0,scsi-id=UNIT
- The (optional) removable parameter lets you override the SCSI INQUIRY
- removable (RMB) bit for non CD-ROM devices. It is ignored for CD-ROM devices
- which are always removable. RMB is "on" or "off".
+ where DEVNAME is either scsi-hd, scsi-cd or scsi-generic.
* if=floppy
- -global isa-fdc,driveA=DRIVE-ID,driveB=DRIVE-ID
+ -global isa-fdc.driveA=DRIVE-ID
+ -global isa-fdc.driveB=DRIVE-ID
This is -global instead of -device, because the floppy controller is
created automatically, and we want to configure that one, not create
a second one (which isn't possible anyway).
- Omitting a drive parameter makes that drive empty.
-
- Bug: driveA works only if you disable the default floppy drive with
- -nodefaults.
+ Without any -global isa-fdc,... you get an empty driveA and no
+ driveB. You can use -nodefaults to suppress the default driveA, see
+ "Default Devices".
* if=virtio
@@ -105,11 +121,12 @@ The -device argument differs in detail for each kind of drive:
This lets you control PCI device class and MSI-X vectors.
- IOEVENTFD controls whether or not ioeventfd is used for virtqueue notify. It
- can be set to on (default) or off.
+ IOEVENTFD controls whether or not ioeventfd is used for virtqueue
+ notify. It can be set to on (default) or off.
As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to
- control the PCI device address.
+ control the PCI device address. This replaces option addr available
+ with -drive if=virtio.
* if=pflash, if=mtd, if=sd, if=xen are not yet available with -device
@@ -117,15 +134,20 @@ For USB devices, the old way is actually different:
-usbdevice disk:format=FMT:FILENAME
-Provides much less control than -drive's HOST-OPTS... The new way
-fixes that:
+Provides much less control than -drive's OPTS... The new way fixes
+that:
-device usb-storage,drive=DRIVE-ID,removable=RMB
-The removable parameter gives control over the SCSI INQUIRY removable (RMB)
-bit. USB thumbdrives usually set removable=on, while USB hard disks set
-removable=off. See the if=scsi description above for details on the removable
-parameter, which applies only to scsi-disk devices and not to scsi-generic.
+The removable parameter gives control over the SCSI INQUIRY removable
+(RMB) bit. USB thumbdrives usually set removable=on, while USB hard
+disks set removable=off.
+
+Bug: usb-storage pretends to be a block device, but it's really a SCSI
+controller that can serve only a single device, which it creates
+automatically. The automatic creation guesses what kind of guest part
+to create from the host part, like -drive if=scsi. Host and guest
+part are not cleanly separated.
=== Character Devices ===
@@ -170,7 +192,9 @@ The appropriate DEVNAME depends on the machine type. For type "pc":
-device usb-braille,chardev=braille,vendorid=VID,productid=PRID
-chardev braille,id=braille
-* -virtioconsole is still being worked on
+* -virtioconsole becomes
+ -device virtio-serial-pci,class=C,vectors=V,ioeventfd=IOEVENTFD,max_ports=N
+ -device virtconsole,is_console=NUM,nr=NR,name=NAME
LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows:
@@ -219,38 +243,29 @@ LEGACY-CHARDEV to refer to a host part defined with -chardev.
=== Network Devices ===
-A QEMU network device (NIC) has a host and a guest part.
+Host and guest part of network devices have always been separate.
-The old ways to define NICs define host and guest part together. It
-looks like this:
+The old way to define the guest part looks like this:
- -net nic,vlan=VLAN,macaddr=MACADDR,model=MODEL,name=ID,addr=STR,vectors=V
+ -net nic,netdev=NET-ID,macaddr=MACADDR,model=MODEL,name=ID,addr=STR,vectors=V
Except for USB it looks like this:
- -usbdevice net:vlan=VLAN,macaddr=MACADDR,name=ID,addr=STR,vectors=V
+ -usbdevice net:netdev=NET-ID,macaddr=MACADDR,name=ID
-The new way keeps the parts separate: you create the host part with
--netdev, and the guest device with -device, like this:
+The new way is -device:
- -netdev type=TYPE,id=NET-ID
-device DEVNAME,netdev=NET-ID,mac=MACADDR,DEV-OPTS...
-Unlike the old way, this creates just a network device, not a VLAN.
-If you really want a VLAN, create it the usual way, then create the
-guest device like this:
-
- -device DEVNAME,vlan=VLAN,mac=MACADDR,DEV-OPTS...
-
DEVNAME equals MODEL, except for virtio you have to name the virtio
device appropriate for the bus (virtio-net-pci for PCI), and for USB
-NIC you have to use usb-net.
+you have to use usb-net.
The old name=ID parameter becomes the usual id=ID with -device.
For PCI devices, you can add bus=PCI-BUS,addr=DEVFN to control the PCI
device address, as usual. The old -net nic provides parameter addr
-for that, it is silently ignored when the NIC is not a PCI device.
+for that, which is silently ignored when the NIC is not a PCI device.
For virtio-net-pci, you can control whether or not ioeventfd is used for
virtqueue notify by setting ioeventfd= to on or off (default).
@@ -264,20 +279,25 @@ devices and ne2k_isa are.
Some PCI devices aren't available with -net nic, e.g. i82558a.
-Bug: usb-net does not work, yet. Patch posted.
+To connect to a VLAN instead of an ordinary host part, replace
+netdev=NET-ID by vlan=VLAN.
=== Graphics Devices ===
Host and guest part of graphics devices have always been separate.
-The old way to define the guest graphics device is -vga VGA.
+The old way to define the guest graphics device is -vga VGA. Not all
+machines support all -vga options.
-The new way is -device. Map from -vga argument to -device:
+The new way is -device. The mapping from -vga argument to -device
+depends on the machine type. For machine "pc", it's:
std -device VGA
cirrus -device cirrus-vga
vmware -device vmware-svga
- xenfb not yet available with -device
+ qxl -device qxl-vga
+ none -nodefaults
+ disables more than just VGA, see "Default Devices"
As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to control
the PCI device address.
@@ -285,13 +305,16 @@ the PCI device address.
-device VGA supports properties bios-offset and bios-size, but they
aren't used with machine type "pc".
-Bug: -device cirrus-vga and -device vmware-svga require -nodefaults.
+For machine "isapc", it's
-Bug: the new way requires PCI; ISA VGA is not yet available with
--device.
+ std -device isa-vga
+ cirrus not yet available with -device
+ none -nodefaults
+ disables more than just VGA, see "Default Devices"
-Bug: the new way doesn't work for machine type "pc", because it
-violates obscure device initialization ordering constraints.
+Bug: the new way doesn't work for machine types "pc" and "isapc",
+because it violates obscure device initialization ordering
+constraints.
=== Audio Devices ===
@@ -308,6 +331,7 @@ Map from -soundhw sound card name to -device:
cs4231a -device cs4231a,iobase=IOADDR,irq=IRQ,dma=DMA
es1370 -device ES1370
gus -device gus,iobase=IOADDR,irq=IRQ,dma=DMA,freq=F
+ hda -device intel-hda,msi=MSI -device hda-duplex
sb16 -device sb16,iobase=IOADDR,irq=IRQ,dma=DMA,dma16=DMA16,version=V
adlib not yet available with -device
pcspk not yet available with -device
@@ -321,9 +345,10 @@ The old way to define a virtual USB device is -usbdevice DRIVER:OPTS...
The new way is -device DEVNAME,DEV-OPTS... Details depend on DRIVER:
+* ccid -device usb-ccid
+* keyboard -device usb-kbd
* mouse -device usb-mouse
* tablet -device usb-tablet
-* keyboard -device usb-kdb
* wacom-tablet -device usb-wacom-tablet
* host:... See "Host Device Assignment"
* disk:... See "Block Devices"
@@ -353,7 +378,7 @@ The new way is
-device pci-assign,host=ADDR,iommu=IOMMU,id=ID
-The old dma=none becomes iommu=0 with -device.
+The old dma=none becomes iommu=off with -device.
The old way to assign a host USB device is
@@ -365,4 +390,27 @@ The new way is
-device usb-host,hostbus=BUS,hostaddr=ADDR,vendorid=VID,productid=PRID
-where left out or zero BUS, ADDR, VID, PRID serve as wildcard.
+Omitted options match anything, just like the old way's wildcard.
+
+=== Default Devices ===
+
+QEMU creates a number of devices by default, depending on the machine
+type.
+
+-device DEVNAME... and global DEVNAME... suppress default devices for
+some DEVNAMEs:
+
+ default device suppressing DEVNAMEs
+ CD-ROM ide-cd, ide-drive, scsi-cd
+ isa-fdc's driveA isa-fdc
+ parallel isa-parallel
+ serial isa-serial
+ VGA VGA, cirrus-vga, vmware-svga
+ virtioconsole virtio-serial-pci, virtio-serial-s390, virtio-serial
+
+The default NIC is connected to a default part created along with it.
+It is *not* suppressed by configuring a NIC with -device (you may call
+that a bug). -net and -netdev suppress the default NIC.
+
+-nodefaults suppresses all the default devices mentioned above, plus a
+few other things such as default SD-Card drive and default monitor.
commit 0826c7105aea1d3fd5d4448dee6e63f5d3ee2cff
Author: Markus Armbruster <armbru at redhat.com>
Date: Tue Jun 7 10:34:30 2011 +0200
isa-vga: Make available with -device, like the other VGA qdevs
Switch no_user off and make it suppress the default VGA.
Signed-off-by: Markus Armbruster <armbru at redhat.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/hw/vga-isa.c b/hw/vga-isa.c
index fde0d56..245841f 100644
--- a/hw/vga-isa.c
+++ b/hw/vga-isa.c
@@ -77,7 +77,6 @@ static ISADeviceInfo vga_info = {
.qdev.size = sizeof(ISAVGAState),
.qdev.vmsd = &vmstate_vga_common,
.qdev.reset = vga_reset_isa,
- .qdev.no_user = 1,
.init = vga_initfn,
};
diff --git a/vl.c b/vl.c
index 11f6386..04b4a20 100644
--- a/vl.c
+++ b/vl.c
@@ -289,6 +289,7 @@ static struct {
{ .driver = "VGA", .flag = &default_vga },
{ .driver = "cirrus-vga", .flag = &default_vga },
{ .driver = "vmware-svga", .flag = &default_vga },
+ { .driver = "isa-vga", .flag = &default_vga },
};
static int default_driver_check(QemuOpts *opts, void *opaque)
commit a16c53b101a9897b0b2be96a1bb3bde7c04380f2
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Mon Jun 6 08:25:06 2011 -0500
Fix regression introduced by -machine accel=
Commit 85097db6 changed the timing when kvm_allowed is set until after
kvm is initialized. During initialization, the ioeventfd initialization code
checks kvm_enabled() and after this change, ioeventfd is effectively disabled.
This causes a significant regression in performance.
Fix this by setting kvm_allowed before calling init.
Reported-by: Khoa Huynh <khoa at us.ibm.com>
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/vl.c b/vl.c
index b362871..11f6386 100644
--- a/vl.c
+++ b/vl.c
@@ -1933,6 +1933,7 @@ static int configure_accelerator(void)
p = get_opt_name(buf, sizeof (buf), p, ':');
for (i = 0; i < ARRAY_SIZE(accel_list); i++) {
if (strcmp(accel_list[i].opt_name, buf) == 0) {
+ *(accel_list[i].allowed) = 1;
ret = accel_list[i].init();
if (ret < 0) {
init_failed = 1;
@@ -1944,9 +1945,9 @@ static int configure_accelerator(void)
accel_list[i].name,
strerror(-ret));
}
+ *(accel_list[i].allowed) = 0;
} else {
accel_initalised = 1;
- *(accel_list[i].allowed) = 1;
}
break;
}
commit 25f3151ece1d5881826232bebccc21b588d4e03e
Author: Anthony Liguori <aliguori at us.ibm.com>
Date: Tue May 31 10:51:11 2011 -0500
timer: drop HPET and RTC
dynticks will provide equally good timer granularity on all modern Linux
systems. This is more or less dead code these days.
Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>
diff --git a/qemu-timer.c b/qemu-timer.c
index 4141b6e..72066c7 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -39,15 +39,6 @@
#include <sys/param.h>
#endif
-#ifdef __linux__
-#include <sys/ioctl.h>
-#include <linux/rtc.h>
-/* For the benefit of older linux systems which don't supply it,
- we use a local copy of hpet.h. */
-/* #include <linux/hpet.h> */
-#include "hpet.h"
-#endif
-
#ifdef _WIN32
#include <windows.h>
#include <mmsystem.h>
@@ -234,12 +225,6 @@ static int dynticks_start_timer(struct qemu_alarm_timer *t);
static void dynticks_stop_timer(struct qemu_alarm_timer *t);
static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
-static int hpet_start_timer(struct qemu_alarm_timer *t);
-static void hpet_stop_timer(struct qemu_alarm_timer *t);
-
-static int rtc_start_timer(struct qemu_alarm_timer *t);
-static void rtc_stop_timer(struct qemu_alarm_timer *t);
-
#endif /* __linux__ */
#endif /* _WIN32 */
@@ -304,10 +289,6 @@ static struct qemu_alarm_timer alarm_timers[] = {
#ifdef __linux__
{"dynticks", dynticks_start_timer,
dynticks_stop_timer, dynticks_rearm_timer},
- /* HPET - if available - is preferred */
- {"hpet", hpet_start_timer, hpet_stop_timer, NULL},
- /* ...otherwise try RTC */
- {"rtc", rtc_start_timer, rtc_stop_timer, NULL},
#endif
{"unix", unix_start_timer, unix_stop_timer, NULL},
#else
@@ -822,107 +803,6 @@ static int64_t qemu_next_alarm_deadline(void)
#if defined(__linux__)
-#define RTC_FREQ 1024
-
-static void enable_sigio_timer(int fd)
-{
- struct sigaction act;
-
- /* timer signal */
- sigfillset(&act.sa_mask);
- act.sa_flags = 0;
- act.sa_handler = host_alarm_handler;
-
- sigaction(SIGIO, &act, NULL);
- fcntl_setfl(fd, O_ASYNC);
- fcntl(fd, F_SETOWN, getpid());
-}
-
-static int hpet_start_timer(struct qemu_alarm_timer *t)
-{
- struct hpet_info info;
- int r, fd;
-
- fd = qemu_open("/dev/hpet", O_RDONLY);
- if (fd < 0)
- return -1;
-
- /* Set frequency */
- r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ);
- if (r < 0) {
- fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n"
- "error, but for better emulation accuracy type:\n"
- "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n");
- goto fail;
- }
-
- /* Check capabilities */
- r = ioctl(fd, HPET_INFO, &info);
- if (r < 0)
- goto fail;
-
- /* Enable periodic mode */
- r = ioctl(fd, HPET_EPI, 0);
- if (info.hi_flags && (r < 0))
- goto fail;
-
- /* Enable interrupt */
- r = ioctl(fd, HPET_IE_ON, 0);
- if (r < 0)
- goto fail;
-
- enable_sigio_timer(fd);
- t->fd = fd;
-
- return 0;
-fail:
- close(fd);
- return -1;
-}
-
-static void hpet_stop_timer(struct qemu_alarm_timer *t)
-{
- int fd = t->fd;
-
- close(fd);
-}
-
-static int rtc_start_timer(struct qemu_alarm_timer *t)
-{
- int rtc_fd;
- unsigned long current_rtc_freq = 0;
-
- TFR(rtc_fd = qemu_open("/dev/rtc", O_RDONLY));
- if (rtc_fd < 0)
- return -1;
- ioctl(rtc_fd, RTC_IRQP_READ, ¤t_rtc_freq);
- if (current_rtc_freq != RTC_FREQ &&
- ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {
- fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n"
- "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n"
- "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n");
- goto fail;
- }
- if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) {
- fail:
- close(rtc_fd);
- return -1;
- }
-
- enable_sigio_timer(rtc_fd);
-
- t->fd = rtc_fd;
-
- return 0;
-}
-
-static void rtc_stop_timer(struct qemu_alarm_timer *t)
-{
- int rtc_fd = t->fd;
-
- close(rtc_fd);
-}
-
static int dynticks_start_timer(struct qemu_alarm_timer *t)
{
struct sigevent ev;
commit 212496c98219df17913f3157a7bf85575b32384f
Author: Alon Levy <alevy at redhat.com>
Date: Wed May 18 17:34:36 2011 +0300
qxl: fix cmdlog for vga
Signed-off-by: Alon Levy <alevy at redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/hw/qxl.c b/hw/qxl.c
index 2bb36c6..1906e84 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -357,7 +357,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
ret = true;
}
qemu_mutex_unlock(&qxl->ssd.lock);
- qxl_log_command(qxl, "vga", ext);
+ if (ret) {
+ qxl_log_command(qxl, "vga", ext);
+ }
return ret;
case QXL_MODE_COMPAT:
case QXL_MODE_NATIVE:
commit 012b80d3f904c9a4d4ea85036ba8d4d1acf12e7d
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue May 17 10:48:14 2011 +0200
spice: require spice 0.6.0 or newer.
This patch raises the minimum required spice version to 0.6.0 and drops
a few ifdefs.
0.6.0 is the first stable release with the current libspice-server API,
there shouldn't be any 0.5.x development versions deployed any more.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/configure b/configure
index d38b952..11f85bf 100755
--- a/configure
+++ b/configure
@@ -2431,7 +2431,7 @@ int main(void) { spice_server_new(); return 0; }
EOF
spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
- if $pkg_config --atleast-version=0.5.3 spice-server >/dev/null 2>&1 && \
+ if $pkg_config --atleast-version=0.6.0 spice-server >/dev/null 2>&1 && \
compile_prog "$spice_cflags" "$spice_libs" ; then
spice="yes"
libs_softmmu="$libs_softmmu $spice_libs"
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 457d34d..dd9905b 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -299,8 +299,6 @@ static int parse_name(const char *string, const char *optname,
exit(1);
}
-#if SPICE_SERVER_VERSION >= 0x000600 /* 0.6.0 */
-
static const char *stream_video_names[] = {
[ SPICE_STREAM_VIDEO_OFF ] = "off",
[ SPICE_STREAM_VIDEO_ALL ] = "all",
@@ -309,8 +307,6 @@ static const char *stream_video_names[] = {
#define parse_stream_video(_name) \
name2enum(_name, stream_video_names, ARRAY_SIZE(stream_video_names))
-#endif /* >= 0.6.0 */
-
static const char *compression_names[] = {
[ SPICE_IMAGE_COMPRESS_OFF ] = "off",
[ SPICE_IMAGE_COMPRESS_AUTO_GLZ ] = "auto_glz",
@@ -593,8 +589,6 @@ void qemu_spice_init(void)
}
spice_server_set_zlib_glz_compression(spice_server, wan_compr);
-#if SPICE_SERVER_VERSION >= 0x000600 /* 0.6.0 */
-
str = qemu_opt_get(opts, "streaming-video");
if (str) {
int streaming_video = parse_stream_video(str);
@@ -606,8 +600,6 @@ void qemu_spice_init(void)
spice_server_set_playback_compression
(spice_server, qemu_opt_get_bool(opts, "playback-compression", 1));
-#endif /* >= 0.6.0 */
-
qemu_opt_foreach(opts, add_channel, NULL, 0);
spice_server_init(spice_server, &core_interface);
commit 44bd6907de2018f8abb28fcee3dda8a7cfbf9c96
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Tue May 17 10:40:43 2011 +0200
qemu-config: comment spell fix
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/qemu-config.c b/qemu-config.c
index b00aa3a..c63741c 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -306,7 +306,7 @@ static QemuOptsList qemu_trace_opts = {
.name = "file",
.type = QEMU_OPT_STRING,
},
- { /* end if list */ }
+ { /* end of list */ }
},
};
#endif
@@ -436,7 +436,7 @@ QemuOptsList qemu_spice_opts = {
.name = "playback-compression",
.type = QEMU_OPT_BOOL,
},
- { /* end if list */ }
+ { /* end of list */ }
},
};
@@ -452,7 +452,7 @@ QemuOptsList qemu_option_rom_opts = {
.name = "romfile",
.type = QEMU_OPT_STRING,
},
- { /* end if list */ }
+ { /* end of list */ }
},
};
commit 48b3ed0a68b8c1b288b4e15743ea39b7b5b318c3
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date: Tue May 17 10:40:33 2011 +0200
spice: add SASL support
Turn on SASL support by appending "sasl" to the spice arguments, which
requires that the client use SASL to authenticate with the spice. The
exact choice of authentication method used is controlled from the
system / user's SASL configuration file for the 'qemu' service. This
is typically found in /etc/sasl2/qemu.conf. If running QEMU as an
unprivileged user, an environment variable SASL_CONF_PATH can be used
to make it search alternate locations for the service config. While
some SASL auth methods can also provide data encryption (eg GSSAPI),
it is recommended that SASL always be combined with the 'tls' and
'x509' settings to enable use of SSL and server certificates. This
ensures a data encryption preventing compromise of authentication
credentials.
It requires support from spice 0.8.1.
[ kraxel: moved spell fix to separate commit ]
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/qemu-config.c b/qemu-config.c
index 04c97e5..b00aa3a 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -388,6 +388,9 @@ QemuOptsList qemu_spice_opts = {
.name = "disable-copy-paste",
.type = QEMU_OPT_BOOL,
},{
+ .name = "sasl",
+ .type = QEMU_OPT_BOOL,
+ },{
.name = "x509-dir",
.type = QEMU_OPT_STRING,
},{
diff --git a/qemu-options.hx b/qemu-options.hx
index 63e8cb0..d9edff7 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -714,6 +714,19 @@ Force using the specified IP version.
@item password=<secret>
Set the password you need to authenticate.
+ at item sasl
+Require that the client use SASL to authenticate with the spice.
+The exact choice of authentication method used is controlled from the
+system / user's SASL configuration file for the 'qemu' service. This
+is typically found in /etc/sasl2/qemu.conf. If running QEMU as an
+unprivileged user, an environment variable SASL_CONF_PATH can be used
+to make it search alternate locations for the service config.
+While some SASL auth methods can also provide data encryption (eg GSSAPI),
+it is recommended that SASL always be combined with the 'tls' and
+'x509' settings to enable use of SSL and server certificates. This
+ensures a data encryption preventing compromise of authentication
+credentials.
+
@item disable-ticketing
Allow client connects without authentication.
diff --git a/ui/spice-core.c b/ui/spice-core.c
index a3351f3..457d34d 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -549,6 +549,18 @@ void qemu_spice_init(void)
if (password) {
spice_server_set_ticket(spice_server, password, 0, 0, 0);
}
+ if (qemu_opt_get_bool(opts, "sasl", 0)) {
+#if SPICE_SERVER_VERSION >= 0x000900 /* 0.9.0 */
+ if (spice_server_set_sasl_appname(spice_server, "qemu") == -1 ||
+ spice_server_set_sasl(spice_server, 1) == -1) {
+ fprintf(stderr, "spice: failed to enable sasl\n");
+ exit(1);
+ }
+#else
+ fprintf(stderr, "spice: sasl is not available (spice >= 0.9 required)\n");
+ exit(1);
+#endif
+ }
if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) {
auth = "none";
spice_server_set_noauth(spice_server);
commit 42138043f29b350219a45895017cf677237b6a97
Author: Gerd Hoffmann <kraxel at redhat.com>
Date: Mon May 16 09:28:58 2011 +0200
qxl: add to the list of devices which disable the default vga
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
diff --git a/vl.c b/vl.c
index b362871..2021bbb 100644
--- a/vl.c
+++ b/vl.c
@@ -289,6 +289,7 @@ static struct {
{ .driver = "VGA", .flag = &default_vga },
{ .driver = "cirrus-vga", .flag = &default_vga },
{ .driver = "vmware-svga", .flag = &default_vga },
+ { .driver = "qxl-vga", .flag = &default_vga },
};
static int default_driver_check(QemuOpts *opts, void *opaque)
commit d4970b071f698a4f3984487bbb97d1ecc36f5950
Author: Hans de Goede <hdegoede at redhat.com>
Date: Sun Mar 27 16:43:54 2011 +0200
spice: add option for disabling copy paste support
Some people want to be able disable spice's guest <-> client copy paste support
because of security considerations.
[ kraxel: drop old-version error message ]
diff --git a/qemu-config.c b/qemu-config.c
index 5d7ffa2..04c97e5 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -385,6 +385,9 @@ QemuOptsList qemu_spice_opts = {
.name = "disable-ticketing",
.type = QEMU_OPT_BOOL,
},{
+ .name = "disable-copy-paste",
+ .type = QEMU_OPT_BOOL,
+ },{
.name = "x509-dir",
.type = QEMU_OPT_STRING,
},{
diff --git a/qemu-options.hx b/qemu-options.hx
index 82e085a..63e8cb0 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -717,6 +717,9 @@ Set the password you need to authenticate.
@item disable-ticketing
Allow client connects without authentication.
+ at item disable-copy-paste
+Disable copy paste between the client and the guest.
+
@item tls-port=<nr>
Set the TCP port spice is listening on for encrypted channels.
diff --git a/ui/spice-core.c b/ui/spice-core.c
index ef56ed6..a3351f3 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -554,6 +554,12 @@ void qemu_spice_init(void)
spice_server_set_noauth(spice_server);
}
+#if SPICE_SERVER_VERSION >= 0x000801
+ if (qemu_opt_get_bool(opts, "disable-copy-paste", 0)) {
+ spice_server_set_agent_copypaste(spice_server, false);
+ }
+#endif
+
compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ;
str = qemu_opt_get(opts, "image-compression");
if (str) {
commit 35106c2df2eda83e5f7fea356d80c11fed93df1f
Author: Hans de Goede <hdegoede at redhat.com>
Date: Tue Mar 22 16:28:41 2011 +0100
spice-qemu-char: Fix flow control in client -> guest direction
In the old spice-vmc device we used to have:
last_out = virtio_serial_write(&svc->port, p, MIN(len, VMC_MAX_HOST_WRITE));
if (last_out > 0)
...
Now in the chardev backend we have:
last_out = MIN(len, VMC_MAX_HOST_WRITE);
qemu_chr_read(scd->chr, p, last_out);
if (last_out > 0) {
...
Which causes us to no longer detect if the virtio port is not ready
to receive data from us. chardev actually has a mechanism to detect this,
but it requires a separate call to qemu_chr_can_read, before calling
qemu_chr_read (which return void).
This patch uses qemu_chr_can_read to fix the flow control from client to
guest.
Signed-off-by: Hans de Goede <hdegoede at redhat.com>
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index fa15a71..605c241 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -36,14 +36,13 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
while (len > 0) {
last_out = MIN(len, VMC_MAX_HOST_WRITE);
- qemu_chr_read(scd->chr, p, last_out);
- if (last_out > 0) {
- out += last_out;
- len -= last_out;
- p += last_out;
- } else {
+ if (qemu_chr_can_read(scd->chr) < last_out) {
break;
}
+ qemu_chr_read(scd->chr, p, last_out);
+ out += last_out;
+ len -= last_out;
+ p += last_out;
}
dprintf(scd, 3, "%s: %lu/%zd\n", __func__, out, len + out);
commit 5c3234c6c037943bd4c2d643a1b8cc35f563dbdb
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date: Wed Jun 1 12:35:14 2011 +0530
hw/9pfs: Don't crash when we get a request with not supported 9p operation
Return EOPNOTSUPP as error
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri (JV) <jvrao at linux.vnet.ibm.com>
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index ec97b10..ed08139 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -3606,6 +3606,11 @@ static pdu_handler_t *pdu_handlers[] = {
[P9_TREMOVE] = v9fs_remove,
};
+static void v9fs_op_not_supp(V9fsState *s, V9fsPDU *pdu)
+{
+ complete_pdu(s, pdu, -EOPNOTSUPP);
+}
+
static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
{
pdu_handler_t *handler;
@@ -3613,12 +3618,12 @@ static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
if (debug_9p_pdu) {
pprint_pdu(pdu);
}
-
- BUG_ON(pdu->id >= ARRAY_SIZE(pdu_handlers));
-
- handler = pdu_handlers[pdu->id];
- BUG_ON(handler == NULL);
-
+ if (pdu->id >= ARRAY_SIZE(pdu_handlers) ||
+ (pdu_handlers[pdu->id] == NULL)) {
+ handler = v9fs_op_not_supp;
+ } else {
+ handler = pdu_handlers[pdu->id];
+ }
handler(s, pdu);
}
commit faa44e3d3e986f29579e0d0d07b7aef771184e8c
Author: Venkateswararao Jujjuri (JV) <jvrao at linux.vnet.ibm.com>
Date: Wed Jun 1 12:35:14 2011 +0530
[virtio-9p] Make rpath thread safe
Current rpath inline function is heavily used in all system calls.
This function has a static buffer making it a non-thread safe function.
This patch introduces new thread-safe routine and makes use of it.
Signed-off-by: Venkateswararao Jujjuri "<jvrao at linux.vnet.ibm.com>
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 126e60e..af9daf7 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -97,11 +97,4 @@ typedef struct FileOperations
void *opaque;
} FileOperations;
-static inline const char *rpath(FsContext *ctx, const char *path)
-{
- /* FIXME: so wrong... */
- static char buffer[4096];
- snprintf(buffer, sizeof(buffer), "%s/%s", ctx->fs_root, path);
- return buffer;
-}
#endif
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 3effc39..77904c3 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -25,7 +25,8 @@
static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
{
int err;
- err = lstat(rpath(fs_ctx, path), stbuf);
+ char buffer[PATH_MAX];
+ err = lstat(rpath(fs_ctx, path, buffer), stbuf);
if (err) {
return err;
}
@@ -35,19 +36,19 @@ static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
gid_t tmp_gid;
mode_t tmp_mode;
dev_t tmp_dev;
- if (getxattr(rpath(fs_ctx, path), "user.virtfs.uid", &tmp_uid,
+ if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid,
sizeof(uid_t)) > 0) {
stbuf->st_uid = tmp_uid;
}
- if (getxattr(rpath(fs_ctx, path), "user.virtfs.gid", &tmp_gid,
+ if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid,
sizeof(gid_t)) > 0) {
stbuf->st_gid = tmp_gid;
}
- if (getxattr(rpath(fs_ctx, path), "user.virtfs.mode", &tmp_mode,
- sizeof(mode_t)) > 0) {
+ if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode",
+ &tmp_mode, sizeof(mode_t)) > 0) {
stbuf->st_mode = tmp_mode;
}
- if (getxattr(rpath(fs_ctx, path), "user.virtfs.rdev", &tmp_dev,
+ if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev,
sizeof(dev_t)) > 0) {
stbuf->st_rdev = tmp_dev;
}
@@ -92,10 +93,12 @@ static int local_set_xattr(const char *path, FsCred *credp)
static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
FsCred *credp)
{
- if (chmod(rpath(fs_ctx, path), credp->fc_mode & 07777) < 0) {
+ char buffer[PATH_MAX];
+ if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
return -1;
}
- if (lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid) < 0) {
+ if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
+ credp->fc_gid) < 0) {
/*
* If we fail to change ownership and if we are
* using security model none. Ignore the error
@@ -111,9 +114,10 @@ static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
char *buf, size_t bufsz)
{
ssize_t tsize = -1;
+ char buffer[PATH_MAX];
if (fs_ctx->fs_sm == SM_MAPPED) {
int fd;
- fd = open(rpath(fs_ctx, path), O_RDONLY);
+ fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
if (fd == -1) {
return -1;
}
@@ -124,7 +128,7 @@ static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
return tsize;
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- tsize = readlink(rpath(fs_ctx, path), buf, bufsz);
+ tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz);
}
return tsize;
}
@@ -141,12 +145,14 @@ static int local_closedir(FsContext *ctx, DIR *dir)
static int local_open(FsContext *ctx, const char *path, int flags)
{
- return open(rpath(ctx, path), flags);
+ char buffer[PATH_MAX];
+ return open(rpath(ctx, path, buffer), flags);
}
static DIR *local_opendir(FsContext *ctx, const char *path)
{
- return opendir(rpath(ctx, path));
+ char buffer[PATH_MAX];
+ return opendir(rpath(ctx, path, buffer));
}
static void local_rewinddir(FsContext *ctx, DIR *dir)
@@ -201,11 +207,12 @@ static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
{
+ char buffer[PATH_MAX];
if (fs_ctx->fs_sm == SM_MAPPED) {
- return local_set_xattr(rpath(fs_ctx, path), credp);
+ return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- return chmod(rpath(fs_ctx, path), credp->fc_mode);
+ return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
}
return -1;
}
@@ -214,21 +221,24 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
{
int err = -1;
int serrno = 0;
+ char buffer[PATH_MAX];
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
- err = mknod(rpath(fs_ctx, path), SM_LOCAL_MODE_BITS|S_IFREG, 0);
+ err = mknod(rpath(fs_ctx, path, buffer),
+ SM_LOCAL_MODE_BITS|S_IFREG, 0);
if (err == -1) {
return err;
}
- local_set_xattr(rpath(fs_ctx, path), credp);
+ local_set_xattr(rpath(fs_ctx, path, buffer), credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- err = mknod(rpath(fs_ctx, path), credp->fc_mode, credp->fc_rdev);
+ err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
+ credp->fc_rdev);
if (err == -1) {
return err;
}
@@ -241,7 +251,7 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
return err;
err_end:
- remove(rpath(fs_ctx, path));
+ remove(rpath(fs_ctx, path, buffer));
errno = serrno;
return err;
}
@@ -250,22 +260,23 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
{
int err = -1;
int serrno = 0;
+ char buffer[PATH_MAX];
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
- err = mkdir(rpath(fs_ctx, path), SM_LOCAL_DIR_MODE_BITS);
+ err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
if (err == -1) {
return err;
}
credp->fc_mode = credp->fc_mode|S_IFDIR;
- err = local_set_xattr(rpath(fs_ctx, path), credp);
+ err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- err = mkdir(rpath(fs_ctx, path), credp->fc_mode);
+ err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
if (err == -1) {
return err;
}
@@ -278,7 +289,7 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
return err;
err_end:
- remove(rpath(fs_ctx, path));
+ remove(rpath(fs_ctx, path, buffer));
errno = serrno;
return err;
}
@@ -319,23 +330,24 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags,
int fd = -1;
int err = -1;
int serrno = 0;
+ char buffer[PATH_MAX];
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
- fd = open(rpath(fs_ctx, path), flags, SM_LOCAL_MODE_BITS);
+ fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
if (fd == -1) {
return fd;
}
credp->fc_mode = credp->fc_mode|S_IFREG;
/* Set cleint credentials in xattr */
- err = local_set_xattr(rpath(fs_ctx, path), credp);
+ err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- fd = open(rpath(fs_ctx, path), flags, credp->fc_mode);
+ fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
if (fd == -1) {
return fd;
}
@@ -349,7 +361,7 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags,
err_end:
close(fd);
- remove(rpath(fs_ctx, path));
+ remove(rpath(fs_ctx, path, buffer));
errno = serrno;
return err;
}
@@ -360,12 +372,13 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
{
int err = -1;
int serrno = 0;
+ char buffer[PATH_MAX];
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
int fd;
ssize_t oldpath_size, write_size;
- fd = open(rpath(fs_ctx, newpath), O_CREAT|O_EXCL|O_RDWR,
+ fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
SM_LOCAL_MODE_BITS);
if (fd == -1) {
return fd;
@@ -385,18 +398,19 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
close(fd);
/* Set cleint credentials in symlink's xattr */
credp->fc_mode = credp->fc_mode|S_IFLNK;
- err = local_set_xattr(rpath(fs_ctx, newpath), credp);
+ err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- err = symlink(oldpath, rpath(fs_ctx, newpath));
+ err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
if (err) {
return err;
}
- err = lchown(rpath(fs_ctx, newpath), credp->fc_uid, credp->fc_gid);
+ err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid,
+ credp->fc_gid);
if (err == -1) {
/*
* If we fail to change ownership and if we are
@@ -412,70 +426,45 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
return err;
err_end:
- remove(rpath(fs_ctx, newpath));
+ remove(rpath(fs_ctx, newpath, buffer));
errno = serrno;
return err;
}
static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
{
- char *tmp = qemu_strdup(rpath(ctx, oldpath));
- int err, serrno = 0;
+ char buffer[PATH_MAX], buffer1[PATH_MAX];
- if (tmp == NULL) {
- return -ENOMEM;
- }
-
- err = link(tmp, rpath(ctx, newpath));
- if (err == -1) {
- serrno = errno;
- }
-
- qemu_free(tmp);
-
- if (err == -1) {
- errno = serrno;
- }
-
- return err;
+ return link(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
}
static int local_truncate(FsContext *ctx, const char *path, off_t size)
{
- return truncate(rpath(ctx, path), size);
+ char buffer[PATH_MAX];
+ return truncate(rpath(ctx, path, buffer), size);
}
static int local_rename(FsContext *ctx, const char *oldpath,
const char *newpath)
{
- char *tmp;
- int err;
-
- tmp = qemu_strdup(rpath(ctx, oldpath));
-
- err = rename(tmp, rpath(ctx, newpath));
- if (err == -1) {
- int serrno = errno;
- qemu_free(tmp);
- errno = serrno;
- } else {
- qemu_free(tmp);
- }
-
- return err;
+ char buffer[PATH_MAX], buffer1[PATH_MAX];
+ return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
}
static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
{
+ char buffer[PATH_MAX];
if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
(fs_ctx->fs_sm == SM_PASSTHROUGH)) {
- return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
+ return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
+ credp->fc_gid);
} else if (fs_ctx->fs_sm == SM_MAPPED) {
- return local_set_xattr(rpath(fs_ctx, path), credp);
+ return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
+ return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
+ credp->fc_gid);
}
return -1;
}
@@ -483,12 +472,15 @@ static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
static int local_utimensat(FsContext *s, const char *path,
const struct timespec *buf)
{
- return qemu_utimensat(AT_FDCWD, rpath(s, path), buf, AT_SYMLINK_NOFOLLOW);
+ char buffer[PATH_MAX];
+ return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf,
+ AT_SYMLINK_NOFOLLOW);
}
static int local_remove(FsContext *ctx, const char *path)
{
- return remove(rpath(ctx, path));
+ char buffer[PATH_MAX];
+ return remove(rpath(ctx, path, buffer));
}
static int local_fsync(FsContext *ctx, int fd, int datasync)
@@ -502,7 +494,8 @@ static int local_fsync(FsContext *ctx, int fd, int datasync)
static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
{
- return statfs(rpath(s, path), stbuf);
+ char buffer[PATH_MAX];
+ return statfs(rpath(s, path, buffer), stbuf);
}
static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
diff --git a/hw/9pfs/virtio-9p-posix-acl.c b/hw/9pfs/virtio-9p-posix-acl.c
index c0ae9d6..f5b392e 100644
--- a/hw/9pfs/virtio-9p-posix-acl.c
+++ b/hw/9pfs/virtio-9p-posix-acl.c
@@ -26,7 +26,8 @@
static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- return lgetxattr(rpath(ctx, path), MAP_ACL_ACCESS, value, size);
+ char buffer[PATH_MAX];
+ return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value, size);
}
static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
@@ -50,14 +51,17 @@ static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags)
{
- return lsetxattr(rpath(ctx, path), MAP_ACL_ACCESS, value, size, flags);
+ char buffer[PATH_MAX];
+ return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value,
+ size, flags);
}
static int mp_pacl_removexattr(FsContext *ctx,
const char *path, const char *name)
{
int ret;
- ret = lremovexattr(rpath(ctx, path), MAP_ACL_ACCESS);
+ char buffer[PATH_MAX];
+ ret = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS);
if (ret == -1 && errno == ENODATA) {
/*
* We don't get ENODATA error when trying to remove a
@@ -73,7 +77,8 @@ static int mp_pacl_removexattr(FsContext *ctx,
static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- return lgetxattr(rpath(ctx, path), MAP_ACL_DEFAULT, value, size);
+ char buffer[PATH_MAX];
+ return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value, size);
}
static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
@@ -97,14 +102,17 @@ static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags)
{
- return lsetxattr(rpath(ctx, path), MAP_ACL_DEFAULT, value, size, flags);
+ char buffer[PATH_MAX];
+ return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value,
+ size, flags);
}
static int mp_dacl_removexattr(FsContext *ctx,
const char *path, const char *name)
{
int ret;
- ret = lremovexattr(rpath(ctx, path), MAP_ACL_DEFAULT);
+ char buffer[PATH_MAX];
+ ret = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT);
if (ret == -1 && errno == ENODATA) {
/*
* We don't get ENODATA error when trying to remove a
diff --git a/hw/9pfs/virtio-9p-xattr-user.c b/hw/9pfs/virtio-9p-xattr-user.c
index c56039c..5044a3e 100644
--- a/hw/9pfs/virtio-9p-xattr-user.c
+++ b/hw/9pfs/virtio-9p-xattr-user.c
@@ -21,6 +21,7 @@
static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
+ char buffer[PATH_MAX];
if (strncmp(name, "user.virtfs.", 12) == 0) {
/*
* Don't allow fetch of user.virtfs namesapce
@@ -29,7 +30,7 @@ static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
errno = ENOATTR;
return -1;
}
- return lgetxattr(rpath(ctx, path), name, value, size);
+ return lgetxattr(rpath(ctx, path, buffer), name, value, size);
}
static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
@@ -67,6 +68,7 @@ static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags)
{
+ char buffer[PATH_MAX];
if (strncmp(name, "user.virtfs.", 12) == 0) {
/*
* Don't allow fetch of user.virtfs namesapce
@@ -75,12 +77,13 @@ static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
errno = EACCES;
return -1;
}
- return lsetxattr(rpath(ctx, path), name, value, size, flags);
+ return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
}
static int mp_user_removexattr(FsContext *ctx,
const char *path, const char *name)
{
+ char buffer[PATH_MAX];
if (strncmp(name, "user.virtfs.", 12) == 0) {
/*
* Don't allow fetch of user.virtfs namesapce
@@ -89,7 +92,7 @@ static int mp_user_removexattr(FsContext *ctx,
errno = EACCES;
return -1;
}
- return lremovexattr(rpath(ctx, path), name);
+ return lremovexattr(rpath(ctx, path, buffer), name);
}
XattrOperations mapped_user_xattr = {
diff --git a/hw/9pfs/virtio-9p-xattr.c b/hw/9pfs/virtio-9p-xattr.c
index f08ce6e..bde0b7f 100644
--- a/hw/9pfs/virtio-9p-xattr.c
+++ b/hw/9pfs/virtio-9p-xattr.c
@@ -66,20 +66,21 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
void *value, size_t vsize)
{
ssize_t size = 0;
+ char buffer[PATH_MAX];
void *ovalue = value;
XattrOperations *xops;
char *orig_value, *orig_value_start;
ssize_t xattr_len, parsed_len = 0, attr_len;
/* Get the actual len */
- xattr_len = llistxattr(rpath(ctx, path), value, 0);
+ xattr_len = llistxattr(rpath(ctx, path, buffer), value, 0);
if (xattr_len <= 0) {
return xattr_len;
}
/* Now fetch the xattr and find the actual size */
orig_value = qemu_malloc(xattr_len);
- xattr_len = llistxattr(rpath(ctx, path), orig_value, xattr_len);
+ xattr_len = llistxattr(rpath(ctx, path, buffer), orig_value, xattr_len);
/* store the orig pointer */
orig_value_start = orig_value;
diff --git a/hw/9pfs/virtio-9p-xattr.h b/hw/9pfs/virtio-9p-xattr.h
index 2bbae2d..247e414 100644
--- a/hw/9pfs/virtio-9p-xattr.h
+++ b/hw/9pfs/virtio-9p-xattr.h
@@ -54,20 +54,23 @@ ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- return lgetxattr(rpath(ctx, path), name, value, size);
+ char buffer[PATH_MAX];
+ return lgetxattr(rpath(ctx, path, buffer), name, value, size);
}
static inline int pt_setxattr(FsContext *ctx, const char *path,
const char *name, void *value,
size_t size, int flags)
{
- return lsetxattr(rpath(ctx, path), name, value, size, flags);
+ char buffer[PATH_MAX];
+ return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
}
static inline int pt_removexattr(FsContext *ctx,
const char *path, const char *name)
{
- return lremovexattr(rpath(ctx, path), name);
+ char buffer[PATH_MAX];
+ return lremovexattr(rpath(ctx, path, buffer), name);
}
static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 27f9970..2bfbe62 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -101,6 +101,11 @@ enum p9_proto_version {
#define P9_NOTAG (u16)(~0)
#define P9_NOFID (u32)(~0)
#define P9_MAXWELEM 16
+static inline const char *rpath(FsContext *ctx, const char *path, char *buffer)
+{
+ snprintf(buffer, PATH_MAX, "%s/%s", ctx->fs_root, path);
+ return buffer;
+}
/*
* ample room for Twrite/Rread header
commit 873c32139354caef3cc1013f00963cc740a6a727
Author: Stefan Weil <weil at mail.berlios.de>
Date: Wed Jun 1 12:35:14 2011 +0530
virtio-9p: Use relative includes for files in hw
Commit 353ac78d495ef976242abd868f68d78420861c2c moved the files
without fixing the include paths. It used a modified CFLAGS
to add hw to the include search path, but this breaks builds
where the user wants to set special CFLAGS. Long include paths
also increase compilation time.
Therefore this patch removes the special CFLAGS for virtio
and fixes the include statements by using relative include paths.
v2: Remove special CFLAGS.
v3: Update needed for latest QEMU.
Signed-off-by: Stefan Weil <weil at mail.berlios.de>
Signed-off-by: Venkateswararao Jujjuri (JV) <jvrao at linux.vnet.ibm.com>
diff --git a/Makefile.objs b/Makefile.objs
index 1dc45c4..00ffa42 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -292,7 +292,6 @@ hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
-$(addprefix 9pfs/, $(9pfs-nested-y)): CFLAGS += -I$(SRC_PATH)/hw/
######################################################################
diff --git a/Makefile.target b/Makefile.target
index 73ab016..99ff3ba 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -413,8 +413,6 @@ hmp-commands.h: $(SRC_PATH)/hmp-commands.hx
qmp-commands.h: $(SRC_PATH)/qmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
-9pfs/virtio-9p-device.o: CFLAGS += -I$(SRC_PATH)/hw/
-
clean:
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o
diff --git a/hw/9pfs/virtio-9p-debug.c b/hw/9pfs/virtio-9p-debug.c
index 6b18842..4636ad5 100644
--- a/hw/9pfs/virtio-9p-debug.c
+++ b/hw/9pfs/virtio-9p-debug.c
@@ -10,8 +10,9 @@
* the COPYING file in the top-level directory.
*
*/
-#include "virtio.h"
-#include "pc.h"
+
+#include "hw/virtio.h"
+#include "hw/pc.h"
#include "virtio-9p.h"
#include "virtio-9p-debug.h"
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index f985486..a2b6acc 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -11,10 +11,10 @@
*
*/
-#include "virtio.h"
-#include "pc.h"
+#include "hw/virtio.h"
+#include "hw/pc.h"
#include "qemu_socket.h"
-#include "virtio-pci.h"
+#include "hw/virtio-pci.h"
#include "virtio-9p.h"
#include "fsdev/qemu-fsdev.h"
#include "virtio-9p-xattr.h"
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 0a015de..3effc39 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -10,7 +10,8 @@
* the COPYING file in the top-level directory.
*
*/
-#include "virtio.h"
+
+#include "hw/virtio.h"
#include "virtio-9p.h"
#include "virtio-9p-xattr.h"
#include <arpa/inet.h>
diff --git a/hw/9pfs/virtio-9p-posix-acl.c b/hw/9pfs/virtio-9p-posix-acl.c
index 575abe8..c0ae9d6 100644
--- a/hw/9pfs/virtio-9p-posix-acl.c
+++ b/hw/9pfs/virtio-9p-posix-acl.c
@@ -13,7 +13,7 @@
#include <sys/types.h>
#include <attr/xattr.h>
-#include "virtio.h"
+#include "hw/virtio.h"
#include "virtio-9p.h"
#include "fsdev/file-op-9p.h"
#include "virtio-9p-xattr.h"
diff --git a/hw/9pfs/virtio-9p-xattr-user.c b/hw/9pfs/virtio-9p-xattr-user.c
index bba13ce..c56039c 100644
--- a/hw/9pfs/virtio-9p-xattr-user.c
+++ b/hw/9pfs/virtio-9p-xattr-user.c
@@ -12,7 +12,7 @@
*/
#include <sys/types.h>
-#include "virtio.h"
+#include "hw/virtio.h"
#include "virtio-9p.h"
#include "fsdev/file-op-9p.h"
#include "virtio-9p-xattr.h"
diff --git a/hw/9pfs/virtio-9p-xattr.c b/hw/9pfs/virtio-9p-xattr.c
index 03c3d3f..f08ce6e 100644
--- a/hw/9pfs/virtio-9p-xattr.c
+++ b/hw/9pfs/virtio-9p-xattr.c
@@ -11,7 +11,7 @@
*
*/
-#include "virtio.h"
+#include "hw/virtio.h"
#include "virtio-9p.h"
#include "fsdev/file-op-9p.h"
#include "virtio-9p-xattr.h"
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 21865b1..ec97b10 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -11,10 +11,10 @@
*
*/
-#include "virtio.h"
-#include "pc.h"
+#include "hw/virtio.h"
+#include "hw/pc.h"
#include "qemu_socket.h"
-#include "virtio-pci.h"
+#include "hw/virtio-pci.h"
#include "virtio-9p.h"
#include "fsdev/qemu-fsdev.h"
#include "virtio-9p-debug.h"
commit f4f61d272e26ca34612c05070dfbda86dc00298b
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date: Wed Jun 1 12:35:13 2011 +0530
virtio-9p: Move device specific code to virtio-9p-device
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri (JV) <jvrao at linux.vnet.ibm.com>
diff --git a/Makefile.objs b/Makefile.objs
index 1af0c44..1dc45c4 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -287,7 +287,7 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
-9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p-debug.o
+9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p.o virtio-9p-debug.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
diff --git a/Makefile.target b/Makefile.target
index 602d50d..73ab016 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -194,7 +194,7 @@ obj-$(CONFIG_VIRTIO) += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial
obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
obj-y += vhost_net.o
obj-$(CONFIG_VHOST_NET) += vhost.o
-obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p.o
+obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
obj-y += rwhandler.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
@@ -413,7 +413,7 @@ hmp-commands.h: $(SRC_PATH)/hmp-commands.hx
qmp-commands.h: $(SRC_PATH)/qmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
-9pfs/virtio-9p.o: CFLAGS += -I$(SRC_PATH)/hw/
+9pfs/virtio-9p-device.o: CFLAGS += -I$(SRC_PATH)/hw/
clean:
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
new file mode 100644
index 0000000..f985486
--- /dev/null
+++ b/hw/9pfs/virtio-9p-device.c
@@ -0,0 +1,173 @@
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio.h"
+#include "pc.h"
+#include "qemu_socket.h"
+#include "virtio-pci.h"
+#include "virtio-9p.h"
+#include "fsdev/qemu-fsdev.h"
+#include "virtio-9p-xattr.h"
+
+static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
+{
+ features |= 1 << VIRTIO_9P_MOUNT_TAG;
+ return features;
+}
+
+static V9fsState *to_virtio_9p(VirtIODevice *vdev)
+{
+ return (V9fsState *)vdev;
+}
+
+static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+ struct virtio_9p_config *cfg;
+ V9fsState *s = to_virtio_9p(vdev);
+
+ cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
+ s->tag_len);
+ stw_raw(&cfg->tag_len, s->tag_len);
+ memcpy(cfg->tag, s->tag, s->tag_len);
+ memcpy(config, cfg, s->config_size);
+ qemu_free(cfg);
+}
+
+VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
+ {
+ V9fsState *s;
+ int i, len;
+ struct stat stat;
+ FsTypeEntry *fse;
+
+
+ s = (V9fsState *)virtio_common_init("virtio-9p",
+ VIRTIO_ID_9P,
+ sizeof(struct virtio_9p_config)+
+ MAX_TAG_LEN,
+ sizeof(V9fsState));
+
+ /* initialize pdu allocator */
+ QLIST_INIT(&s->free_list);
+ for (i = 0; i < (MAX_REQ - 1); i++) {
+ QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
+ }
+
+ s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
+
+ fse = get_fsdev_fsentry(conf->fsdev_id);
+
+ if (!fse) {
+ /* We don't have a fsdev identified by fsdev_id */
+ fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
+ "id = %s\n", conf->fsdev_id ? conf->fsdev_id : "NULL");
+ exit(1);
+ }
+
+ if (!fse->path || !conf->tag) {
+ /* we haven't specified a mount_tag or the path */
+ fprintf(stderr, "fsdev with id %s needs path "
+ "and Virtio-9p device needs mount_tag arguments\n",
+ conf->fsdev_id);
+ exit(1);
+ }
+
+ if (!strcmp(fse->security_model, "passthrough")) {
+ /* Files on the Fileserver set to client user credentials */
+ s->ctx.fs_sm = SM_PASSTHROUGH;
+ s->ctx.xops = passthrough_xattr_ops;
+ } else if (!strcmp(fse->security_model, "mapped")) {
+ /* Files on the fileserver are set to QEMU credentials.
+ * Client user credentials are saved in extended attributes.
+ */
+ s->ctx.fs_sm = SM_MAPPED;
+ s->ctx.xops = mapped_xattr_ops;
+ } else if (!strcmp(fse->security_model, "none")) {
+ /*
+ * Files on the fileserver are set to QEMU credentials.
+ */
+ s->ctx.fs_sm = SM_NONE;
+ s->ctx.xops = none_xattr_ops;
+ } else {
+ fprintf(stderr, "Default to security_model=none. You may want"
+ " enable advanced security model using "
+ "security option:\n\t security_model=passthrough\n\t "
+ "security_model=mapped\n");
+ s->ctx.fs_sm = SM_NONE;
+ s->ctx.xops = none_xattr_ops;
+ }
+
+ if (lstat(fse->path, &stat)) {
+ fprintf(stderr, "share path %s does not exist\n", fse->path);
+ exit(1);
+ } else if (!S_ISDIR(stat.st_mode)) {
+ fprintf(stderr, "share path %s is not a directory\n", fse->path);
+ exit(1);
+ }
+
+ s->ctx.fs_root = qemu_strdup(fse->path);
+ len = strlen(conf->tag);
+ if (len > MAX_TAG_LEN) {
+ len = MAX_TAG_LEN;
+ }
+ /* s->tag is non-NULL terminated string */
+ s->tag = qemu_malloc(len);
+ memcpy(s->tag, conf->tag, len);
+ s->tag_len = len;
+ s->ctx.uid = -1;
+
+ s->ops = fse->ops;
+ s->vdev.get_features = virtio_9p_get_features;
+ s->config_size = sizeof(struct virtio_9p_config) +
+ s->tag_len;
+ s->vdev.get_config = virtio_9p_get_config;
+
+ return &s->vdev;
+}
+
+static int virtio_9p_init_pci(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+ VirtIODevice *vdev;
+
+ vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
+ vdev->nvectors = proxy->nvectors;
+ virtio_init_pci(proxy, vdev,
+ PCI_VENDOR_ID_REDHAT_QUMRANET,
+ 0x1009,
+ 0x2,
+ 0x00);
+ /* make the actual value visible */
+ proxy->nvectors = vdev->nvectors;
+ return 0;
+}
+
+static PCIDeviceInfo virtio_9p_info = {
+ .qdev.name = "virtio-9p-pci",
+ .qdev.size = sizeof(VirtIOPCIProxy),
+ .init = virtio_9p_init_pci,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
+ DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void virtio_9p_register_devices(void)
+{
+ pci_qdev_register(&virtio_9p_info);
+}
+
+device_init(virtio_9p_register_devices)
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 28c128e..21865b1 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -3622,7 +3622,7 @@ static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
handler(s, pdu);
}
-static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
+void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
{
V9fsState *s = (V9fsState *)vdev;
V9fsPDU *pdu;
@@ -3646,156 +3646,3 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
free_pdu(s, pdu);
}
-
-static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
-{
- features |= 1 << VIRTIO_9P_MOUNT_TAG;
- return features;
-}
-
-static V9fsState *to_virtio_9p(VirtIODevice *vdev)
-{
- return (V9fsState *)vdev;
-}
-
-static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
-{
- struct virtio_9p_config *cfg;
- V9fsState *s = to_virtio_9p(vdev);
-
- cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
- s->tag_len);
- stw_raw(&cfg->tag_len, s->tag_len);
- memcpy(cfg->tag, s->tag, s->tag_len);
- memcpy(config, cfg, s->config_size);
- qemu_free(cfg);
-}
-
-VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
- {
- V9fsState *s;
- int i, len;
- struct stat stat;
- FsTypeEntry *fse;
-
-
- s = (V9fsState *)virtio_common_init("virtio-9p",
- VIRTIO_ID_9P,
- sizeof(struct virtio_9p_config)+
- MAX_TAG_LEN,
- sizeof(V9fsState));
-
- /* initialize pdu allocator */
- QLIST_INIT(&s->free_list);
- for (i = 0; i < (MAX_REQ - 1); i++) {
- QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
- }
-
- s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
-
- fse = get_fsdev_fsentry(conf->fsdev_id);
-
- if (!fse) {
- /* We don't have a fsdev identified by fsdev_id */
- fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
- "id = %s\n", conf->fsdev_id ? conf->fsdev_id : "NULL");
- exit(1);
- }
-
- if (!fse->path || !conf->tag) {
- /* we haven't specified a mount_tag or the path */
- fprintf(stderr, "fsdev with id %s needs path "
- "and Virtio-9p device needs mount_tag arguments\n",
- conf->fsdev_id);
- exit(1);
- }
-
- if (!strcmp(fse->security_model, "passthrough")) {
- /* Files on the Fileserver set to client user credentials */
- s->ctx.fs_sm = SM_PASSTHROUGH;
- s->ctx.xops = passthrough_xattr_ops;
- } else if (!strcmp(fse->security_model, "mapped")) {
- /* Files on the fileserver are set to QEMU credentials.
- * Client user credentials are saved in extended attributes.
- */
- s->ctx.fs_sm = SM_MAPPED;
- s->ctx.xops = mapped_xattr_ops;
- } else if (!strcmp(fse->security_model, "none")) {
- /*
- * Files on the fileserver are set to QEMU credentials.
- */
- s->ctx.fs_sm = SM_NONE;
- s->ctx.xops = none_xattr_ops;
- } else {
- fprintf(stderr, "Default to security_model=none. You may want"
- " enable advanced security model using "
- "security option:\n\t security_model=passthrough \n\t "
- "security_model=mapped\n");
- s->ctx.fs_sm = SM_NONE;
- s->ctx.xops = none_xattr_ops;
- }
-
- if (lstat(fse->path, &stat)) {
- fprintf(stderr, "share path %s does not exist\n", fse->path);
- exit(1);
- } else if (!S_ISDIR(stat.st_mode)) {
- fprintf(stderr, "share path %s is not a directory \n", fse->path);
- exit(1);
- }
-
- s->ctx.fs_root = qemu_strdup(fse->path);
- len = strlen(conf->tag);
- if (len > MAX_TAG_LEN) {
- len = MAX_TAG_LEN;
- }
- /* s->tag is non-NULL terminated string */
- s->tag = qemu_malloc(len);
- memcpy(s->tag, conf->tag, len);
- s->tag_len = len;
- s->ctx.uid = -1;
-
- s->ops = fse->ops;
- s->vdev.get_features = virtio_9p_get_features;
- s->config_size = sizeof(struct virtio_9p_config) +
- s->tag_len;
- s->vdev.get_config = virtio_9p_get_config;
-
- return &s->vdev;
-}
-
-static int virtio_9p_init_pci(PCIDevice *pci_dev)
-{
- VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
- VirtIODevice *vdev;
-
- vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
- vdev->nvectors = proxy->nvectors;
- virtio_init_pci(proxy, vdev,
- PCI_VENDOR_ID_REDHAT_QUMRANET,
- 0x1009,
- 0x2,
- 0x00);
- /* make the actual value visible */
- proxy->nvectors = vdev->nvectors;
- return 0;
-}
-
-static PCIDeviceInfo virtio_9p_info = {
- .qdev.name = "virtio-9p-pci",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_9p_init_pci,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
- DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void virtio_9p_register_devices(void)
-{
- pci_qdev_register(&virtio_9p_info);
-}
-
-device_init(virtio_9p_register_devices)
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 622928f..27f9970 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -504,4 +504,6 @@ static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
return pdu_packunpack(dst, sg, sg_count, offset, size, 0);
}
+extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
+
#endif
commit 9fe1ebebd0c427fd9b3d1ffffa77a9969d873d93
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date: Wed Jun 1 12:35:13 2011 +0530
virtio-9p: Move 9p device registration into virtio-9p.c
This patch move the 9p device registration into its own file
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri (JV) <jvrao at linux.vnet.ibm.com>
diff --git a/Makefile.objs b/Makefile.objs
index bdcc845..1af0c44 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -45,7 +45,7 @@ net-nested-$(CONFIG_SLIRP) += slirp.o
net-nested-$(CONFIG_VDE) += vde.o
net-obj-y += $(addprefix net/, $(net-nested-y))
-ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS),yy)
+ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
# only pull in the actual virtio-9p device if we also enabled virtio.
CONFIG_REALLY_VIRTFS=y
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index 77d1c08..28c128e 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -14,6 +14,7 @@
#include "virtio.h"
#include "pc.h"
#include "qemu_socket.h"
+#include "virtio-pci.h"
#include "virtio-9p.h"
#include "fsdev/qemu-fsdev.h"
#include "virtio-9p-debug.h"
@@ -3761,3 +3762,40 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
return &s->vdev;
}
+
+static int virtio_9p_init_pci(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+ VirtIODevice *vdev;
+
+ vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
+ vdev->nvectors = proxy->nvectors;
+ virtio_init_pci(proxy, vdev,
+ PCI_VENDOR_ID_REDHAT_QUMRANET,
+ 0x1009,
+ 0x2,
+ 0x00);
+ /* make the actual value visible */
+ proxy->nvectors = vdev->nvectors;
+ return 0;
+}
+
+static PCIDeviceInfo virtio_9p_info = {
+ .qdev.name = "virtio-9p-pci",
+ .qdev.size = sizeof(VirtIOPCIProxy),
+ .init = virtio_9p_init_pci,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
+ DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void virtio_9p_register_devices(void)
+{
+ pci_qdev_register(&virtio_9p_info);
+}
+
+device_init(virtio_9p_register_devices)
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index c19629d..c018351 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -26,6 +26,7 @@
#include "loader.h"
#include "kvm.h"
#include "blockdev.h"
+#include "virtio-pci.h"
/* from Linux's linux/virtio_pci.h */
@@ -95,27 +96,6 @@
*/
#define wmb() do { } while (0)
-/* PCI bindings. */
-
-typedef struct {
- PCIDevice pci_dev;
- VirtIODevice *vdev;
- uint32_t flags;
- uint32_t addr;
- uint32_t class_code;
- uint32_t nvectors;
- BlockConf block;
- NICConf nic;
- uint32_t host_features;
-#ifdef CONFIG_LINUX
- V9fsConf fsconf;
-#endif
- virtio_serial_conf serial;
- virtio_net_conf net;
- bool ioeventfd_disabled;
- bool ioeventfd_started;
-} VirtIOPCIProxy;
-
/* virtio device */
static void virtio_pci_notify(void *opaque, uint16_t vector)
@@ -669,7 +649,7 @@ static const VirtIOBindings virtio_pci_bindings = {
.vmstate_change = virtio_pci_vmstate_change,
};
-static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
+void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
uint16_t vendor, uint16_t device,
uint16_t class_code, uint8_t pif)
{
@@ -835,25 +815,6 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev)
return 0;
}
-#ifdef CONFIG_VIRTFS
-static int virtio_9p_init_pci(PCIDevice *pci_dev)
-{
- VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
- VirtIODevice *vdev;
-
- vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
- vdev->nvectors = proxy->nvectors;
- virtio_init_pci(proxy, vdev,
- PCI_VENDOR_ID_REDHAT_QUMRANET,
- 0x1009,
- 0x2,
- 0x00);
- /* make the actual value visible */
- proxy->nvectors = vdev->nvectors;
- return 0;
-}
-#endif
-
static PCIDeviceInfo virtio_info[] = {
{
.qdev.name = "virtio-blk-pci",
@@ -922,20 +883,6 @@ static PCIDeviceInfo virtio_info[] = {
},
.qdev.reset = virtio_pci_reset,
},{
-#ifdef CONFIG_VIRTFS
- .qdev.name = "virtio-9p-pci",
- .qdev.alias = "virtio-9p",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_9p_init_pci,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
- DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
- DEFINE_PROP_END_OF_LIST(),
- },
- }, {
-#endif
/* end of list */
}
};
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
new file mode 100644
index 0000000..a4b5fd3
--- /dev/null
+++ b/hw/virtio-pci.h
@@ -0,0 +1,43 @@
+/*
+ * Virtio PCI Bindings
+ *
+ * Copyright IBM, Corp. 2007
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors:
+ * Anthony Liguori <aliguori at us.ibm.com>
+ * Paul Brook <paul at codesourcery.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_VIRTIO_PCI_H
+#define QEMU_VIRTIO_PCI_H
+
+#include "virtio-net.h"
+#include "virtio-serial.h"
+
+typedef struct {
+ PCIDevice pci_dev;
+ VirtIODevice *vdev;
+ uint32_t flags;
+ uint32_t addr;
+ uint32_t class_code;
+ uint32_t nvectors;
+ BlockConf block;
+ NICConf nic;
+ uint32_t host_features;
+#ifdef CONFIG_LINUX
+ V9fsConf fsconf;
+#endif
+ virtio_serial_conf serial;
+ virtio_net_conf net;
+ bool ioeventfd_disabled;
+ bool ioeventfd_started;
+} VirtIOPCIProxy;
+
+extern void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
+ uint16_t vendor, uint16_t device,
+ uint16_t class_code, uint8_t pif);
+#endif
commit 1c88c71564bb6e6554f8aad16c7be1bf2a57c89b
Author: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Date: Wed Jun 1 12:35:13 2011 +0530
virtio-9p: Don't link to 9p if virtio is not enabled
If virtio is not enabled then we should not pull in
virtfs files
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri (JV) <jvrao at linux.vnet.ibm.com>
diff --git a/Makefile.objs b/Makefile.objs
index 90838f6..bdcc845 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -49,8 +49,10 @@ ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS),yy)
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
# only pull in the actual virtio-9p device if we also enabled virtio.
CONFIG_REALLY_VIRTFS=y
+fsdev-nested-y = qemu-fsdev.o
+else
+fsdev-nested-y = qemu-fsdev-dummy.o
endif
-fsdev-nested-$(CONFIG_VIRTFS) = qemu-fsdev.o
fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
######################################################################
@@ -285,11 +287,11 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
-9pfs-nested-$(CONFIG_REALLY_VIRTFS) = virtio-9p-debug.o
+9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p-debug.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
-hw-obj-$(CONFIG_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
+hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
$(addprefix 9pfs/, $(9pfs-nested-y)): CFLAGS += -I$(SRC_PATH)/hw/
diff --git a/fsdev/qemu-fsdev-dummy.c b/fsdev/qemu-fsdev-dummy.c
new file mode 100644
index 0000000..619e163
--- /dev/null
+++ b/fsdev/qemu-fsdev-dummy.c
@@ -0,0 +1,20 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Gautham R Shenoy <ego at in.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include "qemu-fsdev.h"
+
+int qemu_fsdev_add(QemuOpts *opts)
+{
+ return 0;
+}
commit 936532a4928ce6c95de5718974f6c987aaad7b68
Author: Malahal Naineni <malahal at us.ibm.com>
Date: Wed Jun 1 12:35:11 2011 +0530
[virtio-9p] Stop renaming files with similar name!
v9fs_complete_rename() mistakenly renames files with similar name
as we don't check if the matched name is really an offspring.
Signed-off-by: Malahal Naineni <malahal at us.ibm.com>
Signed-off-by: Venkateswararao Jujjuri (JV) <jvrao at linux.vnet.ibm.com>
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index b5fc52b..77d1c08 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -423,6 +423,22 @@ static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
v9fs_string_sprintf(lhs, "%s", rhs->data);
}
+/*
+ * Return TRUE if s1 is an ancestor of s2.
+ *
+ * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
+ * As a special case, We treat s1 as ancestor of s2 if they are same!
+ */
+static int v9fs_path_is_ancestor(V9fsString *s1, V9fsString *s2)
+{
+ if (!strncmp(s1->data, s2->data, s1->size)) {
+ if (s2->data[s1->size] == '\0' || s2->data[s1->size] == '/') {
+ return 1;
+ }
+ }
+ return 0;
+}
+
static size_t v9fs_string_size(V9fsString *str)
{
return str->size;
@@ -2805,13 +2821,13 @@ static int v9fs_complete_rename(V9fsState *s, V9fsRenameState *vs)
for (fidp = s->fid_list; fidp; fidp = fidp->next) {
if (vs->fidp == fidp) {
/*
- * we replace name of this fid towards the end
- * so that our below strcmp will work
+ * we replace name of this fid towards the end so
+ * that our below v9fs_path_is_ancestor check will
+ * work
*/
continue;
}
- if (!strncmp(vs->fidp->path.data, fidp->path.data,
- strlen(vs->fidp->path.data))) {
+ if (v9fs_path_is_ancestor(&vs->fidp->path, &fidp->path)) {
/* replace the name */
v9fs_fix_path(&fidp->path, &vs->name,
strlen(vs->fidp->path.data));
commit 37628f11c6b190ebb3082938868aadb23942ee3a
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Wed May 25 19:48:01 2011 +0100
QMP: add server mode to QEMUMonitorProtocol
QEMU supports socket chardevs that establish connections like a server
or a client. The QEMUMonitorProtocol class only supports connecting as
a client. It is not possible to connect race-free when launching QEMU
since trying to connect before QEMU has bound and is listening on the
socket results in failure.
Add the QEMUMonitorProtocol(server=True) argument to bind and listen on
the socket. The QEMU process can then be launched and connects to the
already existing QMP socket without a race condition:
qmp = qmp.QEMUMonitorProtocol(monitor_path, server=True)
popen = subprocess.Popen(args)
qmp.accept()
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/QMP/qmp.py b/QMP/qmp.py
index 2565508..c7dbea0 100644
--- a/QMP/qmp.py
+++ b/QMP/qmp.py
@@ -22,19 +22,24 @@ class QMPCapabilitiesError(QMPError):
pass
class QEMUMonitorProtocol:
- def __init__(self, address):
+ def __init__(self, address, server=False):
"""
Create a QEMUMonitorProtocol class.
@param address: QEMU address, can be either a unix socket path (string)
or a tuple in the form ( address, port ) for a TCP
connection
- @note No connection is established, this is done by the connect() method
+ @param server: server mode listens on the socket (bool)
+ @raise socket.error on socket connection errors
+ @note No connection is established, this is done by the connect() or
+ accept() methods
"""
self.__events = []
self.__address = address
self.__sock = self.__get_sock()
- self.__sockfile = self.__sock.makefile()
+ if server:
+ self.__sock.bind(self.__address)
+ self.__sock.listen(1)
def __get_sock(self):
if isinstance(self.__address, tuple):
@@ -43,6 +48,17 @@ class QEMUMonitorProtocol:
family = socket.AF_UNIX
return socket.socket(family, socket.SOCK_STREAM)
+ def __negotiate_capabilities(self):
+ self.__sockfile = self.__sock.makefile()
+ greeting = self.__json_read()
+ if greeting is None or not greeting.has_key('QMP'):
+ raise QMPConnectError
+ # Greeting seems ok, negotiate capabilities
+ resp = self.cmd('qmp_capabilities')
+ if "return" in resp:
+ return greeting
+ raise QMPCapabilitiesError
+
def __json_read(self, only_event=False):
while True:
data = self.__sockfile.readline()
@@ -67,14 +83,19 @@ class QEMUMonitorProtocol:
@raise QMPCapabilitiesError if fails to negotiate capabilities
"""
self.__sock.connect(self.__address)
- greeting = self.__json_read()
- if greeting is None or not greeting.has_key('QMP'):
- raise QMPConnectError
- # Greeting seems ok, negotiate capabilities
- resp = self.cmd('qmp_capabilities')
- if "return" in resp:
- return greeting
- raise QMPCapabilitiesError
+ return self.__negotiate_capabilities()
+
+ def accept(self):
+ """
+ Await connection from QMP Monitor and perform capabilities negotiation.
+
+ @return QMP greeting dict
+ @raise socket.error on socket connection errors
+ @raise QMPConnectError if the greeting is not received
+ @raise QMPCapabilitiesError if fails to negotiate capabilities
+ """
+ self.__sock, _ = self.__sock.accept()
+ return self.__negotiate_capabilities()
def cmd_obj(self, qmp_cmd):
"""
commit 91b8eddf41fd62ecbc61cb901c40f50287126fac
Author: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Date: Wed May 25 19:48:00 2011 +0100
QMP: add get_events(wait=True) option
The get_events() function polls for new QMP events and then returns. It
can be useful to wait for the next QMP event so add the boolean 'wait'
keyword argument.
Signed-off-by: Stefan Hajnoczi <stefanha at linux.vnet.ibm.com>
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/QMP/qmp.py b/QMP/qmp.py
index 14ce8b0..2565508 100644
--- a/QMP/qmp.py
+++ b/QMP/qmp.py
@@ -43,7 +43,7 @@ class QEMUMonitorProtocol:
family = socket.AF_UNIX
return socket.socket(family, socket.SOCK_STREAM)
- def __json_read(self):
+ def __json_read(self, only_event=False):
while True:
data = self.__sockfile.readline()
if not data:
@@ -51,7 +51,8 @@ class QEMUMonitorProtocol:
resp = json.loads(data)
if 'event' in resp:
self.__events.append(resp)
- continue
+ if not only_event:
+ continue
return resp
error = socket.error
@@ -106,9 +107,11 @@ class QEMUMonitorProtocol:
qmp_cmd['id'] = id
return self.cmd_obj(qmp_cmd)
- def get_events(self):
+ def get_events(self, wait=False):
"""
Get a list of available QMP events.
+
+ @param wait: block until an event is available (bool)
"""
self.__sock.setblocking(0)
try:
@@ -118,6 +121,8 @@ class QEMUMonitorProtocol:
# No data available
pass
self.__sock.setblocking(1)
+ if not self.__events and wait:
+ self.__json_read(only_event=True)
return self.__events
def clear_events(self):
commit e9b4b432e781863869b074d46966bfa0bd672b8f
Author: Luiz Capitulino <lcapitulino at redhat.com>
Date: Fri Apr 29 12:11:50 2011 -0300
HMP: Use QMP inject nmi implementation
This **CHANGES** the human monitor "nmi" command behavior.
Currently it accepts an CPU argument which, when provided, will send
the NMI to the specified CPU. This feature is of discussable value
though and HMP shouldn't have more features than QMP, so let's use
QMP's instead (it's also simpler).
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 834e6a8..6ad8806 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -740,10 +740,11 @@ ETEXI
#if defined(TARGET_I386)
{
.name = "nmi",
- .args_type = "cpu_index:i",
- .params = "cpu",
- .help = "inject an NMI on the given CPU",
- .mhandler.cmd = do_inject_nmi,
+ .args_type = "",
+ .params = "",
+ .help = "inject an NMI on all guest's CPUs",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_inject_nmi,
},
#endif
STEXI
diff --git a/monitor.c b/monitor.c
index 81d3c9b..6af6a4d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2544,19 +2544,7 @@ static void do_wav_capture(Monitor *mon, const QDict *qdict)
#endif
#if defined(TARGET_I386)
-static void do_inject_nmi(Monitor *mon, const QDict *qdict)
-{
- CPUState *env;
- int cpu_index = qdict_get_int(qdict, "cpu_index");
-
- for (env = first_cpu; env != NULL; env = env->next_cpu)
- if (env->cpu_index == cpu_index) {
- cpu_interrupt(env, CPU_INTERRUPT_NMI);
- break;
- }
-}
-
-static int do_inject_nmi_all(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
CPUState *env;
@@ -2567,7 +2555,7 @@ static int do_inject_nmi_all(Monitor *mon, const QDict *qdict, QObject **ret_dat
return 0;
}
#else
-static int do_inject_nmi_all(Monitor *mon, const QDict *qdict, QObject **ret_data)
+static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
qerror_report(QERR_UNSUPPORTED);
return -1;
diff --git a/qmp-commands.hx b/qmp-commands.hx
index ae08b7a..92c5c3a 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -435,7 +435,7 @@ EQMP
.params = "",
.help = "",
.user_print = monitor_user_noop,
- .mhandler.cmd_new = do_inject_nmi_all,
+ .mhandler.cmd_new = do_inject_nmi,
},
SQMP
commit a404666457b54142d6cfe8302bcded9be4cda379
Author: Lai Jiangshan <laijs at cn.fujitsu.com>
Date: Mon Mar 7 17:05:15 2011 +0800
QMP: add inject-nmi qmp command
inject-nmi command injects an NMI on all CPUs of guest.
It is only supported for x86 guest currently, it will
returns "Unsupported" error for non-x86 guest.
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/monitor.c b/monitor.c
index f63cce0..81d3c9b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2555,6 +2555,23 @@ static void do_inject_nmi(Monitor *mon, const QDict *qdict)
break;
}
}
+
+static int do_inject_nmi_all(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ CPUState *env;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ cpu_interrupt(env, CPU_INTERRUPT_NMI);
+ }
+
+ return 0;
+}
+#else
+static int do_inject_nmi_all(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ qerror_report(QERR_UNSUPPORTED);
+ return -1;
+}
#endif
static void do_info_status_print(Monitor *mon, const QObject *data)
diff --git a/qmp-commands.hx b/qmp-commands.hx
index a9f109a..ae08b7a 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -430,6 +430,33 @@ Example:
EQMP
{
+ .name = "inject-nmi",
+ .args_type = "",
+ .params = "",
+ .help = "",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_inject_nmi_all,
+ },
+
+SQMP
+inject-nmi
+----------
+
+Inject an NMI on guest's CPUs.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "inject-nmi" }
+<- { "return": {} }
+
+Note: inject-nmi is only supported for x86 guest currently, it will
+ returns "Unsupported" error for non-x86 guest.
+
+EQMP
+
+ {
.name = "migrate",
.args_type = "detach:-d,blk:-b,inc:-i,uri:s",
.params = "[-d] [-b] [-i] uri",
commit 4c5a1e4db7c68b0e7edf5687dc10beeb776bad9f
Author: Lai Jiangshan <laijs at cn.fujitsu.com>
Date: Mon Mar 7 17:05:04 2011 +0800
QMP: QError: New QERR_UNSUPPORTED
New QERR_UNSUPPORTED for unsupported commands or requests.
Signed-off-by: Luiz Capitulino <lcapitulino at redhat.com>
diff --git a/qerror.c b/qerror.c
index 4855604..4f3b7ca 100644
--- a/qerror.c
+++ b/qerror.c
@@ -201,6 +201,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "An undefined error has ocurred",
},
{
+ .error_fmt = QERR_UNSUPPORTED,
+ .desc = "this feature or command is not currently supported",
+ },
+ {
.error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
.desc = "'%(device)' uses a %(format) feature which is not "
"supported by this qemu version: %(feature)",
diff --git a/qerror.h b/qerror.h
index df61d2c..582b5ef 100644
--- a/qerror.h
+++ b/qerror.h
@@ -165,6 +165,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_UNDEFINED_ERROR \
"{ 'class': 'UndefinedError', 'data': {} }"
+#define QERR_UNSUPPORTED \
+ "{ 'class': 'Unsupported', 'data': {} }"
+
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
commit 3dc769ab43fb4f0e552ecae7ed4414e2b7b77c4b
Author: Yang, Wei Y <wei.y.yang at intel.com>
Date: Mon May 30 23:17:42 2011 +0800
kvm: Enable CPU SMEP feature
This patchset enables a new CPU feature SMEP (Supervisor Mode Execution
Protection) in QEMU-KVM. SMEP prevents kernel from executing code in application.
Updated Intel SDM describes this CPU feature. The document will be published soon.
SMEP is identified by CPUID leaf 7 EBX[7], which is 0 before. Get the right value by query KVM kernel module, so that guest can get SMEP through CPUID.
Signed-off-by: Yang, Wei <wei.y.yang at intel.com>
Singed-off-by: Shan, Haitao <haitao.shan at intel.com>
Singed-off-by: Li, Xin <xin.li at intel.com>
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 40a73c7..79e7580 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -1142,6 +1142,19 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx = 0;
*edx = 0;
break;
+ case 7:
+ if (kvm_enabled()) {
+ *eax = kvm_arch_get_supported_cpuid(env, 0x7, count, R_EAX);
+ *ebx = kvm_arch_get_supported_cpuid(env, 0x7, count, R_EBX);
+ *ecx = kvm_arch_get_supported_cpuid(env, 0x7, count, R_ECX);
+ *edx = kvm_arch_get_supported_cpuid(env, 0x7, count, R_EDX);
+ } else {
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ }
+ break;
case 9:
/* Direct Cache Access Information Leaf */
*eax = 0; /* Bits 0-31 in DCA_CAP MSR */
commit 2d5f20b5f055109c4ccfd1dbf22a100be0b03491
Author: brillywu at viatech.com.cn <brillywu at viatech.com.cn>
Date: Wed Jun 1 09:59:52 2011 +0800
kvm: Add CPUID support for VIA CPU
When KVM is running on VIA CPU with host cpu's model, the
feautures of VIA CPU will be passed into kvm guest by calling
the CPUID instruction for Centaur.
Signed-off-by: BrillyWu<brillywu at viatech.com.cn>
Signed-off-by: KaryJin<karyjin at viatech.com.cn>
Signed-off-by: Marcelo Tosatti <mtosatti at redhat.com>
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 715828f..0b039d4 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -438,9 +438,13 @@
#define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
#define CPUID_VENDOR_AMD_1 0x68747541 /* "Auth" */
-#define CPUID_VENDOR_AMD_2 0x69746e65 /* "enti" */
+#define CPUID_VENDOR_AMD_2 0x69746e65 /* "enti" */
#define CPUID_VENDOR_AMD_3 0x444d4163 /* "cAMD" */
+#define CPUID_VENDOR_VIA_1 0x746e6543 /* "Cent" */
+#define CPUID_VENDOR_VIA_2 0x48727561 /* "aurH" */
+#define CPUID_VENDOR_VIA_3 0x736c7561 /* "auls" */
+
#define CPUID_MWAIT_IBE (1 << 1) /* Interrupts can exit capability */
#define CPUID_MWAIT_EMX (1 << 0) /* enumeration supported */
@@ -730,6 +734,9 @@ typedef struct CPUX86State {
uint32_t cpuid_ext3_features;
uint32_t cpuid_apic_id;
int cpuid_vendor_override;
+ /* Store the results of Centaur's CPUID instructions */
+ uint32_t cpuid_xlevel2;
+ uint32_t cpuid_ext4_features;
/* MTRRs */
uint64_t mtrr_fixed[11];
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index e479a4d..40a73c7 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -230,6 +230,9 @@ typedef struct x86_def_t {
char model_id[48];
int vendor_override;
uint32_t flags;
+ /* Store the results of Centaur's CPUID instructions */
+ uint32_t ext4_features;
+ uint32_t xlevel2;
} x86_def_t;
#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -522,6 +525,18 @@ static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
cpu_x86_fill_model_id(x86_cpu_def->model_id);
x86_cpu_def->vendor_override = 0;
+ /* Call Centaur's CPUID instruction. */
+ if (x86_cpu_def->vendor1 == CPUID_VENDOR_VIA_1 &&
+ x86_cpu_def->vendor2 == CPUID_VENDOR_VIA_2 &&
+ x86_cpu_def->vendor3 == CPUID_VENDOR_VIA_3) {
+ host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
+ if (eax >= 0xC0000001) {
+ /* Support VIA max extended level */
+ x86_cpu_def->xlevel2 = eax;
+ host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_def->ext4_features = edx;
+ }
+ }
/*
* Every SVM feature requires emulation support in KVM - so we can't just
@@ -855,6 +870,8 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model)
env->cpuid_xlevel = def->xlevel;
env->cpuid_kvm_features = def->kvm_features;
env->cpuid_svm_features = def->svm_features;
+ env->cpuid_ext4_features = def->ext4_features;
+ env->cpuid_xlevel2 = def->xlevel2;
if (!kvm_enabled()) {
env->cpuid_features &= TCG_FEATURES;
env->cpuid_ext_features &= TCG_EXT_FEATURES;
@@ -1035,8 +1052,18 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
{
/* test if maximum index reached */
if (index & 0x80000000) {
- if (index > env->cpuid_xlevel)
- index = env->cpuid_level;
+ if (index > env->cpuid_xlevel) {
+ if (env->cpuid_xlevel2 > 0) {
+ /* Handle the Centaur's CPUID instruction. */
+ if (index > env->cpuid_xlevel2) {
+ index = env->cpuid_xlevel2;
+ } else if (index < 0xC0000000) {
+ index = env->cpuid_xlevel;
+ }
+ } else {
+ index = env->cpuid_xlevel;
+ }
+ }
} else {
if (index > env->cpuid_level)
index = env->cpuid_level;
@@ -1231,6 +1258,28 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*edx = 0;
}
break;
+ case 0xC0000000:
+ *eax = env->cpuid_xlevel2;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
+ case 0xC0000001:
+ /* Support for VIA CPU's CPUID instruction */
+ *eax = env->cpuid_version;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = env->cpuid_ext4_features;
+ break;
+ case 0xC0000002:
+ case 0xC0000003:
+ case 0xC0000004:
+ /* Reserved for the future, and now filled with zero */
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
default:
/* reserved values: zero */
*eax = 0;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index faedc6c..1ae2d61 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -482,6 +482,21 @@ int kvm_arch_init_vcpu(CPUState *env)
cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
}
+ /* Call Centaur's CPUID instructions they are supported. */
+ if (env->cpuid_xlevel2 > 0) {
+ env->cpuid_ext4_features &=
+ kvm_arch_get_supported_cpuid(env, 0xC0000001, 0, R_EDX);
+ cpu_x86_cpuid(env, 0xC0000000, 0, &limit, &unused, &unused, &unused);
+
+ for (i = 0xC0000000; i <= limit; i++) {
+ c = &cpuid_data.entries[cpuid_i++];
+
+ c->function = i;
+ c->flags = 0;
+ cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ }
+ }
+
cpuid_data.cpuid.nent = cpuid_i;
#ifdef KVM_CAP_MCE
commit 3b4fefd6e65a7bdb994d10a9fa36c19b5749b502
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Apr 18 20:01:20 2011 -0700
target-alpha: Implement TLB flush primitives.
Expose these via MTPR, more or less like the real HW does.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index 9ffc372..2dec57e 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -110,6 +110,9 @@ DEF_HELPER_2(stl_phys, void, i64, i64)
DEF_HELPER_2(stq_phys, void, i64, i64)
DEF_HELPER_2(stl_c_phys, i64, i64, i64)
DEF_HELPER_2(stq_c_phys, i64, i64, i64)
+
+DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void)
+DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64)
#endif
#include "def-helper.h"
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 36b8289..d332719 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -1205,6 +1205,16 @@ void helper_hw_ret (uint64_t a)
swap_shadow_regs(env);
}
}
+
+void helper_tbia(void)
+{
+ tlb_flush(env, 1);
+}
+
+void helper_tbis(uint64_t p)
+{
+ tlb_flush_page(env, p);
+}
#endif
/*****************************************************************************/
@@ -1335,5 +1345,4 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
}
env = saved_env;
}
-
#endif
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index e664d62..ad6c2ca 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1621,7 +1621,6 @@ static void gen_mfpr(int ra, int regno)
static void gen_mtpr(int rb, int regno)
{
TCGv tmp;
- int data;
if (rb == 31) {
tmp = tcg_const_i64(0);
@@ -1629,16 +1628,27 @@ static void gen_mtpr(int rb, int regno)
tmp = cpu_ir[rb];
}
- /* The basic registers are data only, and unknown registers
- are read-zero, write-ignore. */
- data = cpu_pr_data(regno);
- if (data != 0) {
- if (data & PR_BYTE) {
- tcg_gen_st8_i64(tmp, cpu_env, data & ~PR_BYTE);
- } else if (data & PR_LONG) {
- tcg_gen_st32_i64(tmp, cpu_env, data & ~PR_LONG);
- } else {
- tcg_gen_st_i64(tmp, cpu_env, data);
+ /* These two register numbers perform a TLB cache flush. Thankfully we
+ can only do this inside PALmode, which means that the current basic
+ block cannot be affected by the change in mappings. */
+ if (regno == 255) {
+ /* TBIA */
+ gen_helper_tbia();
+ } else if (regno == 254) {
+ /* TBIS */
+ gen_helper_tbis(tmp);
+ } else {
+ /* The basic registers are data only, and unknown registers
+ are read-zero, write-ignore. */
+ int data = cpu_pr_data(regno);
+ if (data != 0) {
+ if (data & PR_BYTE) {
+ tcg_gen_st8_i64(tmp, cpu_env, data & ~PR_BYTE);
+ } else if (data & PR_LONG) {
+ tcg_gen_st32_i64(tmp, cpu_env, data & ~PR_LONG);
+ } else {
+ tcg_gen_st_i64(tmp, cpu_env, data);
+ }
}
}
commit e5214853eac8f86aca2f5493e7171d6f36ddde38
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Apr 18 19:53:31 2011 -0700
target-alpha: Use a fixed frequency for the RPCC in system mode.
Also include the PCC_OFS in the return value. For user mode we
can pretend the PCC_OFS value is always zero.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 91ef90a..36b8289 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -65,8 +65,17 @@ static void QEMU_NORETURN arith_excp(int exc, uint64_t mask)
uint64_t helper_load_pcc (void)
{
- /* ??? This isn't a timer for which we have any rate info. */
+#ifndef CONFIG_USER_ONLY
+ /* In system mode we have access to a decent high-resolution clock.
+ In order to make OS-level time accounting work with the RPCC,
+ present it with a well-timed clock fixed at 250MHz. */
+ return (((uint64_t)env->pcc_ofs << 32)
+ | (uint32_t)(qemu_get_clock_ns(vm_clock) >> 2));
+#else
+ /* In user-mode, vm_clock doesn't exist. Just pass through the host cpu
+ clock ticks. Also, don't bother taking PCC_OFS into account. */
return (uint32_t)cpu_get_real_ticks();
+#endif
}
uint64_t helper_load_fpcr (void)
commit 5b4504079a3bc37f85cce44e77c347e9ec742307
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Apr 18 16:13:12 2011 -0700
target-alpha: Trap for unassigned and unaligned addresses.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/exec-all.h b/exec-all.h
index 026864e..2a13a95 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -325,7 +325,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_SPARC) || defined(TARGET_MIPS)
+#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SPARC)
do_unassigned_access(addr, 0, 1, 0, 4);
#else
cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
diff --git a/exec.c b/exec.c
index 8529390..b8005dd 100644
--- a/exec.c
+++ b/exec.c
@@ -3181,7 +3181,7 @@ static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
#endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
do_unassigned_access(addr, 0, 0, 0, 1);
#endif
return 0;
@@ -3192,7 +3192,7 @@ static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
#endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
do_unassigned_access(addr, 0, 0, 0, 2);
#endif
return 0;
@@ -3203,7 +3203,7 @@ static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
#endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
do_unassigned_access(addr, 0, 0, 0, 4);
#endif
return 0;
@@ -3214,7 +3214,7 @@ static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
#endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
do_unassigned_access(addr, 1, 0, 0, 1);
#endif
}
@@ -3224,7 +3224,7 @@ static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
#endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
do_unassigned_access(addr, 1, 0, 0, 2);
#endif
}
@@ -3234,7 +3234,7 @@ static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
#endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
do_unassigned_access(addr, 1, 0, 0, 4);
#endif
}
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 030ed17..e98b325 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -434,7 +434,11 @@ void do_interrupt (CPUState *env);
uint64_t cpu_alpha_load_fpcr (CPUState *env);
void cpu_alpha_store_fpcr (CPUState *env, uint64_t val);
-extern void swap_shadow_regs(CPUState *env);
+#ifndef CONFIG_USER_ONLY
+void swap_shadow_regs(CPUState *env);
+extern QEMU_NORETURN void do_unassigned_access(target_phys_addr_t addr,
+ int, int, int, int);
+#endif
/* Bits in TB->FLAGS that control how translation is processed. */
enum {
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 03b5091..91ef90a 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -1265,7 +1265,33 @@ uint64_t helper_stq_c_phys(uint64_t p, uint64_t v)
return ret;
}
+static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
+ int is_user, void *retaddr)
+{
+ uint64_t pc;
+ uint32_t insn;
+
+ do_restore_state(retaddr);
+
+ pc = env->pc;
+ insn = ldl_code(pc);
+
+ env->trap_arg0 = addr;
+ env->trap_arg1 = insn >> 26; /* opcode */
+ env->trap_arg2 = (insn >> 21) & 31; /* dest regno */
+ helper_excp(EXCP_UNALIGN, 0);
+}
+
+void QEMU_NORETURN do_unassigned_access(target_phys_addr_t addr, int is_write,
+ int is_exec, int unused, int size)
+{
+ env->trap_arg0 = addr;
+ env->trap_arg1 = is_write;
+ dynamic_excp(EXCP_MCHK, 0);
+}
+
#define MMUSUFFIX _mmu
+#define ALIGNED_ONLY
#define SHIFT 0
#include "softmmu_template.h"
commit fa6e0a6354539582ae98c232982070d99ea14770
Author: Richard Henderson <rth at twiddle.net>
Date: Wed Apr 27 09:22:18 2011 -0700
target-alpha: Remap PIO space for 43-bit KSEG for EV6.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index d0e4db2..32c2cf9 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -220,14 +220,18 @@ static int get_physical_address(CPUState *env, target_ulong addr,
/* Translate the superpage. */
/* ??? When we do more than emulate Unix PALcode, we'll need to
- determine which superpage is actually active. */
- if (saddr < 0 && (saddr >> (TARGET_VIRT_ADDR_SPACE_BITS - 2) & 3) == 2) {
- /* User-space cannot access kseg addresses. */
+ determine which KSEG is actually active. */
+ if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
+ /* User-space cannot access KSEG addresses. */
if (mmu_idx != MMU_KERNEL_IDX) {
goto exit;
}
+ /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
+ We would not do this if the 48-bit KSEG is enabled. */
phys = saddr & ((1ull << 40) - 1);
+ phys |= (saddr & (1ull << 40)) << 3;
+
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
ret = -1;
goto exit;
commit a3b9af162468674cd4bb6e1c7671d7bdabd8699c
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Apr 18 15:59:21 2011 -0700
target-alpha: Implement cpu_alpha_handle_mmu_fault for system mode.
Reads the page table how PALcode would, except that the virtual
page table base register is not used.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index a1f92ab..030ed17 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -320,6 +320,19 @@ enum {
#define CPU_INTERRUPT_SMP CPU_INTERRUPT_TGT_EXT_1
#define CPU_INTERRUPT_MCHK CPU_INTERRUPT_TGT_EXT_2
+/* OSF/1 Page table bits. */
+enum {
+ PTE_VALID = 0x0001,
+ PTE_FOR = 0x0002, /* used for page protection (fault on read) */
+ PTE_FOW = 0x0004, /* used for page protection (fault on write) */
+ PTE_FOE = 0x0008, /* used for page protection (fault on exec) */
+ PTE_ASM = 0x0010,
+ PTE_KRE = 0x0100,
+ PTE_URE = 0x0200,
+ PTE_KWE = 0x1000,
+ PTE_UWE = 0x2000
+};
+
/* Hardware interrupt (entInt) constants. */
enum {
INT_K_IP,
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 4f56e2b..d0e4db2 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -200,14 +200,135 @@ void swap_shadow_regs(CPUState *env)
env->shadow[7] = i7;
}
-target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
+/* Returns the OSF/1 entMM failure indication, or -1 on success. */
+static int get_physical_address(CPUState *env, target_ulong addr,
+ int prot_need, int mmu_idx,
+ target_ulong *pphys, int *pprot)
{
- return -1;
+ target_long saddr = addr;
+ target_ulong phys = 0;
+ target_ulong L1pte, L2pte, L3pte;
+ target_ulong pt, index;
+ int prot = 0;
+ int ret = MM_K_ACV;
+
+ /* Ensure that the virtual address is properly sign-extended from
+ the last implemented virtual address bit. */
+ if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
+ goto exit;
+ }
+
+ /* Translate the superpage. */
+ /* ??? When we do more than emulate Unix PALcode, we'll need to
+ determine which superpage is actually active. */
+ if (saddr < 0 && (saddr >> (TARGET_VIRT_ADDR_SPACE_BITS - 2) & 3) == 2) {
+ /* User-space cannot access kseg addresses. */
+ if (mmu_idx != MMU_KERNEL_IDX) {
+ goto exit;
+ }
+
+ phys = saddr & ((1ull << 40) - 1);
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ ret = -1;
+ goto exit;
+ }
+
+ /* Interpret the page table exactly like PALcode does. */
+
+ pt = env->ptbr;
+
+ /* L1 page table read. */
+ index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
+ L1pte = ldq_phys(pt + index*8);
+
+ if (unlikely((L1pte & PTE_VALID) == 0)) {
+ ret = MM_K_TNV;
+ goto exit;
+ }
+ if (unlikely((L1pte & PTE_KRE) == 0)) {
+ goto exit;
+ }
+ pt = L1pte >> 32 << TARGET_PAGE_BITS;
+
+ /* L2 page table read. */
+ index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
+ L2pte = ldq_phys(pt + index*8);
+
+ if (unlikely((L2pte & PTE_VALID) == 0)) {
+ ret = MM_K_TNV;
+ goto exit;
+ }
+ if (unlikely((L2pte & PTE_KRE) == 0)) {
+ goto exit;
+ }
+ pt = L2pte >> 32 << TARGET_PAGE_BITS;
+
+ /* L3 page table read. */
+ index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
+ L3pte = ldq_phys(pt + index*8);
+
+ phys = L3pte >> 32 << TARGET_PAGE_BITS;
+ if (unlikely((L3pte & PTE_VALID) == 0)) {
+ ret = MM_K_TNV;
+ goto exit;
+ }
+
+#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
+# error page bits out of date
+#endif
+
+ /* Check access violations. */
+ if (L3pte & (PTE_KRE << mmu_idx)) {
+ prot |= PAGE_READ | PAGE_EXEC;
+ }
+ if (L3pte & (PTE_KWE << mmu_idx)) {
+ prot |= PAGE_WRITE;
+ }
+ if (unlikely((prot & prot_need) == 0 && prot_need)) {
+ goto exit;
+ }
+
+ /* Check fault-on-operation violations. */
+ prot &= ~(L3pte >> 1);
+ ret = -1;
+ if (unlikely((prot & prot_need) == 0)) {
+ ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
+ prot_need & PAGE_WRITE ? MM_K_FOW :
+ prot_need & PAGE_READ ? MM_K_FOR : -1);
+ }
+
+ exit:
+ *pphys = phys;
+ *pprot = prot;
+ return ret;
}
-int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
- int mmu_idx, int is_softmmu)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+ target_ulong phys;
+ int prot, fail;
+
+ fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
+ return (fail >= 0 ? -1 : phys);
+}
+
+int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
+ int mmu_idx, int is_softmmu)
{
+ target_ulong phys;
+ int prot, fail;
+
+ fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
+ if (unlikely(fail >= 0)) {
+ env->exception_index = EXCP_MMFAULT;
+ env->trap_arg0 = addr;
+ env->trap_arg1 = fail;
+ env->trap_arg2 = (rw == 2 ? -1 : rw);
+ return 1;
+ }
+
+ tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
+ prot, mmu_idx, TARGET_PAGE_SIZE);
return 0;
}
#endif /* USER_ONLY */
commit 2ace7e55a2b3bdf6a373e5809459a720f71851cf
Author: Richard Henderson <rth at twiddle.net>
Date: Mon May 23 13:09:00 2011 -0700
target-alpha: Implement more CALL_PAL values inline.
In particular, SWPIPL is used quite a lot by the Linux kernel.
Doing this inline makes it significantly easier to step through
without the debugger getting confused by the mode switch.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index a6c6bca..e664d62 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -85,8 +85,10 @@ static TCGv cpu_pc;
static TCGv cpu_lock_addr;
static TCGv cpu_lock_st_addr;
static TCGv cpu_lock_value;
-#ifdef CONFIG_USER_ONLY
-static TCGv cpu_uniq;
+static TCGv cpu_unique;
+#ifndef CONFIG_USER_ONLY
+static TCGv cpu_sysval;
+static TCGv cpu_usp;
#endif
/* register names */
@@ -131,9 +133,13 @@ static void alpha_translate_init(void)
offsetof(CPUState, lock_value),
"lock_value");
-#ifdef CONFIG_USER_ONLY
- cpu_uniq = tcg_global_mem_new_i64(TCG_AREG0,
- offsetof(CPUState, unique), "uniq");
+ cpu_unique = tcg_global_mem_new_i64(TCG_AREG0,
+ offsetof(CPUState, unique), "unique");
+#ifndef CONFIG_USER_ONLY
+ cpu_sysval = tcg_global_mem_new_i64(TCG_AREG0,
+ offsetof(CPUState, sysval), "sysval");
+ cpu_usp = tcg_global_mem_new_i64(TCG_AREG0,
+ offsetof(CPUState, usp), "usp");
#endif
/* register helpers */
@@ -1464,6 +1470,101 @@ static void gen_rx(int ra, int set)
tcg_temp_free_i32(tmp);
}
+static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
+{
+ /* We're emulating OSF/1 PALcode. Many of these are trivial access
+ to internal cpu registers. */
+
+ /* Unprivileged PAL call */
+ if (palcode >= 0x80 && palcode < 0xC0) {
+ switch (palcode) {
+ case 0x86:
+ /* IMB */
+ /* No-op inside QEMU. */
+ break;
+ case 0x9E:
+ /* RDUNIQUE */
+ tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_unique);
+ break;
+ case 0x9F:
+ /* WRUNIQUE */
+ tcg_gen_mov_i64(cpu_unique, cpu_ir[IR_A0]);
+ break;
+ default:
+ return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0xbf);
+ }
+ return NO_EXIT;
+ }
+
+#ifndef CONFIG_USER_ONLY
+ /* Privileged PAL code */
+ if (palcode < 0x40 && (ctx->tb->flags & TB_FLAGS_USER_MODE) == 0) {
+ switch (palcode) {
+ case 0x01:
+ /* CFLUSH */
+ /* No-op inside QEMU. */
+ break;
+ case 0x02:
+ /* DRAINA */
+ /* No-op inside QEMU. */
+ break;
+ case 0x2D:
+ /* WRVPTPTR */
+ tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env, offsetof(CPUState, vptptr));
+ break;
+ case 0x31:
+ /* WRVAL */
+ tcg_gen_mov_i64(cpu_sysval, cpu_ir[IR_A0]);
+ break;
+ case 0x32:
+ /* RDVAL */
+ tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_sysval);
+ break;
+
+ case 0x35: {
+ /* SWPIPL */
+ TCGv tmp;
+
+ /* Note that we already know we're in kernel mode, so we know
+ that PS only contains the 3 IPL bits. */
+ tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUState, ps));
+
+ /* But make sure and store only the 3 IPL bits from the user. */
+ tmp = tcg_temp_new();
+ tcg_gen_andi_i64(tmp, cpu_ir[IR_A0], PS_INT_MASK);
+ tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUState, ps));
+ tcg_temp_free(tmp);
+ break;
+ }
+
+ case 0x36:
+ /* RDPS */
+ tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUState, ps));
+ break;
+ case 0x38:
+ /* WRUSP */
+ tcg_gen_mov_i64(cpu_usp, cpu_ir[IR_A0]);
+ break;
+ case 0x3A:
+ /* RDUSP */
+ tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_usp);
+ break;
+ case 0x3C:
+ /* WHAMI */
+ tcg_gen_ld32s_i64(cpu_ir[IR_V0], cpu_env,
+ offsetof(CPUState, cpu_index));
+ break;
+
+ default:
+ return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0x3f);
+ }
+ return NO_EXIT;
+ }
+#endif
+
+ return gen_invalid(ctx);
+}
+
#ifndef CONFIG_USER_ONLY
#define PR_BYTE 0x100000
@@ -1582,33 +1683,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
switch (opc) {
case 0x00:
/* CALL_PAL */
-#ifdef CONFIG_USER_ONLY
- if (palcode == 0x9E) {
- /* RDUNIQUE */
- tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_uniq);
- break;
- } else if (palcode == 0x9F) {
- /* WRUNIQUE */
- tcg_gen_mov_i64(cpu_uniq, cpu_ir[IR_A0]);
- break;
- }
-#endif
- if (palcode >= 0x80 && palcode < 0xC0) {
- /* Unprivileged PAL call */
- ret = gen_excp(ctx, EXCP_CALL_PAL, palcode & 0xBF);
- break;
- }
-#ifndef CONFIG_USER_ONLY
- if (palcode < 0x40) {
- /* Privileged PAL code */
- if (ctx->mem_idx != MMU_KERNEL_IDX) {
- goto invalid_opc;
- }
- ret = gen_excp(ctx, EXCP_CALL_PAL, palcode & 0x3F);
- }
-#endif
- /* Invalid PAL call */
- goto invalid_opc;
+ ret = gen_call_pal(ctx, palcode);
+ break;
case 0x01:
/* OPC01 */
goto invalid_opc;
commit 6a80e088c70b88f844ed90b78f4ce987c43ec522
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Apr 18 15:09:09 2011 -0700
target-alpha: Disable interrupts properly.
Interrupts are disabled in PALmode, and when the PS IL is high enough.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/cpu-exec.c b/cpu-exec.c
index 6ddd8dd..e1de56b 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -488,9 +488,36 @@ int cpu_exec(CPUState *env1)
next_tb = 0;
}
#elif defined(TARGET_ALPHA)
- if (interrupt_request & CPU_INTERRUPT_HARD) {
- do_interrupt(env);
- next_tb = 0;
+ {
+ int idx = -1;
+ /* ??? This hard-codes the OSF/1 interrupt levels. */
+ switch (env->pal_mode ? 7 : env->ps & PS_INT_MASK) {
+ case 0 ... 3:
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
+ idx = EXCP_DEV_INTERRUPT;
+ }
+ /* FALLTHRU */
+ case 4:
+ if (interrupt_request & CPU_INTERRUPT_TIMER) {
+ idx = EXCP_CLK_INTERRUPT;
+ }
+ /* FALLTHRU */
+ case 5:
+ if (interrupt_request & CPU_INTERRUPT_SMP) {
+ idx = EXCP_SMP_INTERRUPT;
+ }
+ /* FALLTHRU */
+ case 6:
+ if (interrupt_request & CPU_INTERRUPT_MCHK) {
+ idx = EXCP_MCHK;
+ }
+ }
+ if (idx >= 0) {
+ env->exception_index = idx;
+ env->error_code = 0;
+ do_interrupt(env);
+ next_tb = 0;
+ }
}
#elif defined(TARGET_CRIS)
if (interrupt_request & CPU_INTERRUPT_HARD
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index f5d90c7..a1f92ab 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -315,6 +315,11 @@ enum {
EXCP_STQ_C,
};
+/* Alpha-specific interrupt pending bits. */
+#define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_EXT_0
+#define CPU_INTERRUPT_SMP CPU_INTERRUPT_TGT_EXT_1
+#define CPU_INTERRUPT_MCHK CPU_INTERRUPT_TGT_EXT_2
+
/* Hardware interrupt (entInt) constants. */
enum {
INT_K_IP,
diff --git a/target-alpha/exec.h b/target-alpha/exec.h
index 6ae96d1..7a325e7 100644
--- a/target-alpha/exec.h
+++ b/target-alpha/exec.h
@@ -39,7 +39,17 @@ register struct CPUAlphaState *env asm(AREG0);
static inline int cpu_has_work(CPUState *env)
{
- return (env->interrupt_request & CPU_INTERRUPT_HARD);
+ /* Here we are checking to see if the CPU should wake up from HALT.
+ We will have gotten into this state only for WTINT from PALmode. */
+ /* ??? I'm not sure how the IPL state works with WTINT to keep a CPU
+ asleep even if (some) interrupts have been asserted. For now,
+ assume that if a CPU really wants to stay asleep, it will mask
+ interrupts at the chipset level, which will prevent these bits
+ from being set in the first place. */
+ return env->interrupt_request & (CPU_INTERRUPT_HARD
+ | CPU_INTERRUPT_TIMER
+ | CPU_INTERRUPT_SMP
+ | CPU_INTERRUPT_MCHK);
}
static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
commit a18ad89351dd6c828b7fe33fafd1764cef61a40d
Author: Richard Henderson <rth at twiddle.net>
Date: Mon May 23 12:30:22 2011 -0700
target-alpha: All ISA checks to use TB->FLAGS.
We had two different methods in use, both of which referenced ENV,
and neither of which indicated to the generic code when different
compilation modes are not compatible.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index c1546f8..f5d90c7 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -418,12 +418,40 @@ uint64_t cpu_alpha_load_fpcr (CPUState *env);
void cpu_alpha_store_fpcr (CPUState *env, uint64_t val);
extern void swap_shadow_regs(CPUState *env);
+/* Bits in TB->FLAGS that control how translation is processed. */
+enum {
+ TB_FLAGS_PAL_MODE = 1,
+ TB_FLAGS_FEN = 2,
+ TB_FLAGS_USER_MODE = 8,
+
+ TB_FLAGS_AMASK_SHIFT = 4,
+ TB_FLAGS_AMASK_BWX = AMASK_BWX << TB_FLAGS_AMASK_SHIFT,
+ TB_FLAGS_AMASK_FIX = AMASK_FIX << TB_FLAGS_AMASK_SHIFT,
+ TB_FLAGS_AMASK_CIX = AMASK_CIX << TB_FLAGS_AMASK_SHIFT,
+ TB_FLAGS_AMASK_MVI = AMASK_MVI << TB_FLAGS_AMASK_SHIFT,
+ TB_FLAGS_AMASK_TRAP = AMASK_TRAP << TB_FLAGS_AMASK_SHIFT,
+ TB_FLAGS_AMASK_PREFETCH = AMASK_PREFETCH << TB_FLAGS_AMASK_SHIFT,
+};
+
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
- target_ulong *cs_base, int *flags)
+ target_ulong *cs_base, int *pflags)
{
+ int flags = 0;
+
*pc = env->pc;
*cs_base = 0;
- *flags = env->ps;
+
+ if (env->pal_mode) {
+ flags = TB_FLAGS_PAL_MODE;
+ } else {
+ flags = env->ps & PS_USER_MODE;
+ }
+ if (env->fen) {
+ flags |= TB_FLAGS_FEN;
+ }
+ flags |= env->amask << TB_FLAGS_AMASK_SHIFT;
+
+ *pflags = flags;
}
#if defined(CONFIG_USER_ONLY)
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 3802428..a6c6bca 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -47,10 +47,6 @@ struct DisasContext {
CPUAlphaState *env;
uint64_t pc;
int mem_idx;
-#if !defined (CONFIG_USER_ONLY)
- int pal_mode;
-#endif
- uint32_t amask;
/* Current rounding mode for this TB. */
int tb_rm;
@@ -1654,20 +1650,22 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x0A:
/* LDBU */
- if (!(ctx->amask & AMASK_BWX))
- goto invalid_opc;
- gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
+ gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0);
+ break;
+ }
+ goto invalid_opc;
case 0x0B:
/* LDQ_U */
gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 1);
break;
case 0x0C:
/* LDWU */
- if (!(ctx->amask & AMASK_BWX))
- goto invalid_opc;
- gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, disp16, 0, 0);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
+ gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, disp16, 0, 0);
+ break;
+ }
+ goto invalid_opc;
case 0x0D:
/* STW */
gen_store_mem(ctx, &tcg_gen_qemu_st16, ra, rb, disp16, 0, 0);
@@ -2071,20 +2069,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
case 0x61:
/* AMASK */
if (likely(rc != 31)) {
- if (islit)
- tcg_gen_movi_i64(cpu_ir[rc], lit);
- else
- tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
- switch (ctx->env->implver) {
- case IMPLVER_2106x:
- /* EV4, EV45, LCA, LCA45 & EV5 */
- break;
- case IMPLVER_21164:
- case IMPLVER_21264:
- case IMPLVER_21364:
- tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[rc],
- ~(uint64_t)ctx->amask);
- break;
+ uint64_t amask = ctx->tb->flags >> TB_FLAGS_AMASK_SHIFT;
+
+ if (islit) {
+ tcg_gen_movi_i64(cpu_ir[rc], lit & ~amask);
+ } else {
+ tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[rb], ~amask);
}
}
break;
@@ -2298,8 +2288,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
switch (fpfn) { /* fn11 & 0x3F */
case 0x04:
/* ITOFS */
- if (!(ctx->amask & AMASK_FIX))
+ if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
goto invalid_opc;
+ }
if (likely(rc != 31)) {
if (ra != 31) {
TCGv_i32 tmp = tcg_temp_new_i32();
@@ -2312,20 +2303,23 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x0A:
/* SQRTF */
- if (!(ctx->amask & AMASK_FIX))
- goto invalid_opc;
- gen_fsqrtf(rb, rc);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+ gen_fsqrtf(rb, rc);
+ break;
+ }
+ goto invalid_opc;
case 0x0B:
/* SQRTS */
- if (!(ctx->amask & AMASK_FIX))
- goto invalid_opc;
- gen_fsqrts(ctx, rb, rc, fn11);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+ gen_fsqrts(ctx, rb, rc, fn11);
+ break;
+ }
+ goto invalid_opc;
case 0x14:
/* ITOFF */
- if (!(ctx->amask & AMASK_FIX))
+ if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
goto invalid_opc;
+ }
if (likely(rc != 31)) {
if (ra != 31) {
TCGv_i32 tmp = tcg_temp_new_i32();
@@ -2338,8 +2332,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x24:
/* ITOFT */
- if (!(ctx->amask & AMASK_FIX))
+ if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
goto invalid_opc;
+ }
if (likely(rc != 31)) {
if (ra != 31)
tcg_gen_mov_i64(cpu_fir[rc], cpu_ir[ra]);
@@ -2349,16 +2344,18 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x2A:
/* SQRTG */
- if (!(ctx->amask & AMASK_FIX))
- goto invalid_opc;
- gen_fsqrtg(rb, rc);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+ gen_fsqrtg(rb, rc);
+ break;
+ }
+ goto invalid_opc;
case 0x02B:
/* SQRTT */
- if (!(ctx->amask & AMASK_FIX))
- goto invalid_opc;
- gen_fsqrtt(ctx, rb, rc, fn11);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+ gen_fsqrtt(ctx, rb, rc, fn11);
+ break;
+ }
+ goto invalid_opc;
default:
goto invalid_opc;
}
@@ -2660,7 +2657,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
case 0x19:
/* HW_MFPR (PALcode) */
#ifndef CONFIG_USER_ONLY
- if (ctx->pal_mode) {
+ if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
gen_mfpr(ra, insn & 0xffff);
break;
}
@@ -2681,13 +2678,15 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x1B:
/* HW_LD (PALcode) */
-#if defined (CONFIG_USER_ONLY)
- goto invalid_opc;
-#else
- if (!ctx->pal_mode)
- goto invalid_opc;
- if (ra != 31) {
- TCGv addr = tcg_temp_new();
+#ifndef CONFIG_USER_ONLY
+ if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+ TCGv addr;
+
+ if (ra == 31) {
+ break;
+ }
+
+ addr = tcg_temp_new();
if (rb != 31)
tcg_gen_addi_i64(addr, cpu_ir[rb], disp12);
else
@@ -2754,15 +2753,17 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
}
tcg_temp_free(addr);
+ break;
}
- break;
#endif
+ goto invalid_opc;
case 0x1C:
switch (fn7) {
case 0x00:
/* SEXTB */
- if (!(ctx->amask & AMASK_BWX))
+ if ((ctx->tb->flags & TB_FLAGS_AMASK_BWX) == 0) {
goto invalid_opc;
+ }
if (likely(rc != 31)) {
if (islit)
tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int8_t)lit));
@@ -2772,138 +2773,164 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x01:
/* SEXTW */
- if (!(ctx->amask & AMASK_BWX))
- goto invalid_opc;
- if (likely(rc != 31)) {
- if (islit)
- tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int16_t)lit));
- else
- tcg_gen_ext16s_i64(cpu_ir[rc], cpu_ir[rb]);
+ if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
+ if (likely(rc != 31)) {
+ if (islit) {
+ tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int16_t)lit));
+ } else {
+ tcg_gen_ext16s_i64(cpu_ir[rc], cpu_ir[rb]);
+ }
+ }
+ break;
}
- break;
+ goto invalid_opc;
case 0x30:
/* CTPOP */
- if (!(ctx->amask & AMASK_CIX))
- goto invalid_opc;
- if (likely(rc != 31)) {
- if (islit)
- tcg_gen_movi_i64(cpu_ir[rc], ctpop64(lit));
- else
- gen_helper_ctpop(cpu_ir[rc], cpu_ir[rb]);
+ if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
+ if (likely(rc != 31)) {
+ if (islit) {
+ tcg_gen_movi_i64(cpu_ir[rc], ctpop64(lit));
+ } else {
+ gen_helper_ctpop(cpu_ir[rc], cpu_ir[rb]);
+ }
+ }
+ break;
}
- break;
+ goto invalid_opc;
case 0x31:
/* PERR */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_perr(ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_perr(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x32:
/* CTLZ */
- if (!(ctx->amask & AMASK_CIX))
- goto invalid_opc;
- if (likely(rc != 31)) {
- if (islit)
- tcg_gen_movi_i64(cpu_ir[rc], clz64(lit));
- else
- gen_helper_ctlz(cpu_ir[rc], cpu_ir[rb]);
+ if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
+ if (likely(rc != 31)) {
+ if (islit) {
+ tcg_gen_movi_i64(cpu_ir[rc], clz64(lit));
+ } else {
+ gen_helper_ctlz(cpu_ir[rc], cpu_ir[rb]);
+ }
+ }
+ break;
}
- break;
+ goto invalid_opc;
case 0x33:
/* CTTZ */
- if (!(ctx->amask & AMASK_CIX))
- goto invalid_opc;
- if (likely(rc != 31)) {
- if (islit)
- tcg_gen_movi_i64(cpu_ir[rc], ctz64(lit));
- else
- gen_helper_cttz(cpu_ir[rc], cpu_ir[rb]);
+ if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
+ if (likely(rc != 31)) {
+ if (islit) {
+ tcg_gen_movi_i64(cpu_ir[rc], ctz64(lit));
+ } else {
+ gen_helper_cttz(cpu_ir[rc], cpu_ir[rb]);
+ }
+ }
+ break;
}
- break;
+ goto invalid_opc;
case 0x34:
/* UNPKBW */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- if (real_islit || ra != 31)
- goto invalid_opc;
- gen_unpkbw (rb, rc);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ if (real_islit || ra != 31) {
+ goto invalid_opc;
+ }
+ gen_unpkbw(rb, rc);
+ break;
+ }
+ goto invalid_opc;
case 0x35:
/* UNPKBL */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- if (real_islit || ra != 31)
- goto invalid_opc;
- gen_unpkbl (rb, rc);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ if (real_islit || ra != 31) {
+ goto invalid_opc;
+ }
+ gen_unpkbl(rb, rc);
+ break;
+ }
+ goto invalid_opc;
case 0x36:
/* PKWB */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- if (real_islit || ra != 31)
- goto invalid_opc;
- gen_pkwb (rb, rc);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ if (real_islit || ra != 31) {
+ goto invalid_opc;
+ }
+ gen_pkwb(rb, rc);
+ break;
+ }
+ goto invalid_opc;
case 0x37:
/* PKLB */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- if (real_islit || ra != 31)
- goto invalid_opc;
- gen_pklb (rb, rc);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ if (real_islit || ra != 31) {
+ goto invalid_opc;
+ }
+ gen_pklb(rb, rc);
+ break;
+ }
+ goto invalid_opc;
case 0x38:
/* MINSB8 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_minsb8 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_minsb8(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x39:
/* MINSW4 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_minsw4 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_minsw4(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x3A:
/* MINUB8 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_minub8 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_minub8(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x3B:
/* MINUW4 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_minuw4 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_minuw4(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x3C:
/* MAXUB8 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_maxub8 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_maxub8(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x3D:
/* MAXUW4 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_maxuw4 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_maxuw4(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x3E:
/* MAXSB8 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_maxsb8 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_maxsb8(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x3F:
/* MAXSW4 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_maxsw4 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_maxsw4(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x70:
/* FTOIT */
- if (!(ctx->amask & AMASK_FIX))
+ if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
goto invalid_opc;
+ }
if (likely(rc != 31)) {
if (ra != 31)
tcg_gen_mov_i64(cpu_ir[rc], cpu_fir[ra]);
@@ -2913,8 +2940,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x78:
/* FTOIS */
- if (!(ctx->amask & AMASK_FIX))
+ if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
goto invalid_opc;
+ }
if (rc != 31) {
TCGv_i32 tmp1 = tcg_temp_new_i32();
if (ra != 31)
@@ -2935,41 +2963,36 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
case 0x1D:
/* HW_MTPR (PALcode) */
#ifndef CONFIG_USER_ONLY
- if (ctx->pal_mode) {
- gen_mtpr(ra, insn & 0xffff);
+ if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+ gen_mtpr(rb, insn & 0xffff);
break;
}
#endif
goto invalid_opc;
case 0x1E:
/* HW_RET (PALcode) */
-#if defined (CONFIG_USER_ONLY)
- goto invalid_opc;
-#else
- if (!ctx->pal_mode)
- goto invalid_opc;
- if (rb == 31) {
- /* Pre-EV6 CPUs interpreted this as HW_REI, loading the return
- address from EXC_ADDR. This turns out to be useful for our
- emulation PALcode, so continue to accept it. */
- TCGv tmp = tcg_temp_new();
- /* FIXME: Get exc_addr. */
- gen_helper_hw_ret(tmp);
- tcg_temp_free(tmp);
- } else {
- gen_helper_hw_ret(cpu_ir[rb]);
+#ifndef CONFIG_USER_ONLY
+ if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+ if (rb == 31) {
+ /* Pre-EV6 CPUs interpreted this as HW_REI, loading the return
+ address from EXC_ADDR. This turns out to be useful for our
+ emulation PALcode, so continue to accept it. */
+ TCGv tmp = tcg_temp_new();
+ tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUState, exc_addr));
+ gen_helper_hw_ret(tmp);
+ tcg_temp_free(tmp);
+ } else {
+ gen_helper_hw_ret(cpu_ir[rb]);
+ }
+ ret = EXIT_PC_UPDATED;
+ break;
}
- ret = EXIT_PC_UPDATED;
- break;
#endif
+ goto invalid_opc;
case 0x1F:
/* HW_ST (PALcode) */
-#if defined (CONFIG_USER_ONLY)
- goto invalid_opc;
-#else
- if (!ctx->pal_mode)
- goto invalid_opc;
- else {
+#ifndef CONFIG_USER_ONLY
+ if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
TCGv addr, val;
addr = tcg_temp_new();
if (rb != 31)
@@ -3039,9 +3062,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
if (ra == 31)
tcg_temp_free(val);
tcg_temp_free(addr);
+ break;
}
- break;
#endif
+ goto invalid_opc;
case 0x20:
/* LDF */
gen_load_mem(ctx, &gen_qemu_ldf, ra, rb, disp16, 1, 0);
@@ -3192,11 +3216,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
ctx.tb = tb;
ctx.env = env;
ctx.pc = pc_start;
- ctx.amask = env->amask;
ctx.mem_idx = cpu_mmu_index(env);
-#if !defined (CONFIG_USER_ONLY)
- ctx.pal_mode = env->pal_mode;
-#endif
/* ??? Every TB begins with unset rounding mode, to be initialized on
the first fp insn of the TB. Alternately we could define a proper
commit 21d2beaaef6f99f14022fad98fe2ab189fc1c657
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Apr 18 14:07:59 2011 -0700
target-alpha: Swap shadow registers moving to/from PALmode.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index d1ef04d..c1546f8 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -416,6 +416,7 @@ void do_interrupt (CPUState *env);
uint64_t cpu_alpha_load_fpcr (CPUState *env);
void cpu_alpha_store_fpcr (CPUState *env, uint64_t val);
+extern void swap_shadow_regs(CPUState *env);
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 6f890cd..4f56e2b 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -168,6 +168,38 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
return 1;
}
#else
+void swap_shadow_regs(CPUState *env)
+{
+ uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
+
+ i0 = env->ir[8];
+ i1 = env->ir[9];
+ i2 = env->ir[10];
+ i3 = env->ir[11];
+ i4 = env->ir[12];
+ i5 = env->ir[13];
+ i6 = env->ir[14];
+ i7 = env->ir[25];
+
+ env->ir[8] = env->shadow[0];
+ env->ir[9] = env->shadow[1];
+ env->ir[10] = env->shadow[2];
+ env->ir[11] = env->shadow[3];
+ env->ir[12] = env->shadow[4];
+ env->ir[13] = env->shadow[5];
+ env->ir[14] = env->shadow[6];
+ env->ir[25] = env->shadow[7];
+
+ env->shadow[0] = i0;
+ env->shadow[1] = i1;
+ env->shadow[2] = i2;
+ env->shadow[3] = i3;
+ env->shadow[4] = i4;
+ env->shadow[5] = i5;
+ env->shadow[6] = i6;
+ env->shadow[7] = i7;
+}
+
target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
{
return -1;
@@ -290,7 +322,10 @@ void do_interrupt (CPUState *env)
env->pc = env->palbr + i;
/* Switch to PALmode. */
- env->pal_mode = 1;
+ if (!env->pal_mode) {
+ env->pal_mode = 1;
+ swap_shadow_regs(env);
+ }
#endif /* !USER_ONLY */
}
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index fc5020a..03b5091 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -1189,9 +1189,12 @@ uint64_t helper_cvtqg (uint64_t a)
void helper_hw_ret (uint64_t a)
{
env->pc = a & ~3;
- env->pal_mode = a & 1;
env->intr_flag = 0;
env->lock_addr = -1;
+ if ((a & 1) == 0) {
+ env->pal_mode = 0;
+ swap_shadow_regs(env);
+ }
}
#endif
commit 3a6fa678bf67d94e7b07a42de5b2f66a2fb1c635
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Apr 18 14:05:35 2011 -0700
target-alpha: Implement do_interrupt for system mode.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index c5479fd..6f890cd 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -160,7 +160,6 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
}
#if defined(CONFIG_USER_ONLY)
-
int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int mmu_idx, int is_softmmu)
{
@@ -168,14 +167,7 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
env->trap_arg0 = address;
return 1;
}
-
-void do_interrupt (CPUState *env)
-{
- env->exception_index = -1;
-}
-
#else
-
target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
{
return -1;
@@ -186,12 +178,121 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
{
return 0;
}
+#endif /* USER_ONLY */
void do_interrupt (CPUState *env)
{
- abort();
+ int i = env->exception_index;
+
+ if (qemu_loglevel_mask(CPU_LOG_INT)) {
+ static int count;
+ const char *name = "<unknown>";
+
+ switch (i) {
+ case EXCP_RESET:
+ name = "reset";
+ break;
+ case EXCP_MCHK:
+ name = "mchk";
+ break;
+ case EXCP_SMP_INTERRUPT:
+ name = "smp_interrupt";
+ break;
+ case EXCP_CLK_INTERRUPT:
+ name = "clk_interrupt";
+ break;
+ case EXCP_DEV_INTERRUPT:
+ name = "dev_interrupt";
+ break;
+ case EXCP_MMFAULT:
+ name = "mmfault";
+ break;
+ case EXCP_UNALIGN:
+ name = "unalign";
+ break;
+ case EXCP_OPCDEC:
+ name = "opcdec";
+ break;
+ case EXCP_ARITH:
+ name = "arith";
+ break;
+ case EXCP_FEN:
+ name = "fen";
+ break;
+ case EXCP_CALL_PAL:
+ name = "call_pal";
+ break;
+ case EXCP_STL_C:
+ name = "stl_c";
+ break;
+ case EXCP_STQ_C:
+ name = "stq_c";
+ break;
+ }
+ qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
+ ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
+ }
+
+ env->exception_index = -1;
+
+#if !defined(CONFIG_USER_ONLY)
+ switch (i) {
+ case EXCP_RESET:
+ i = 0x0000;
+ break;
+ case EXCP_MCHK:
+ i = 0x0080;
+ break;
+ case EXCP_SMP_INTERRUPT:
+ i = 0x0100;
+ break;
+ case EXCP_CLK_INTERRUPT:
+ i = 0x0180;
+ break;
+ case EXCP_DEV_INTERRUPT:
+ i = 0x0200;
+ break;
+ case EXCP_MMFAULT:
+ i = 0x0280;
+ break;
+ case EXCP_UNALIGN:
+ i = 0x0300;
+ break;
+ case EXCP_OPCDEC:
+ i = 0x0380;
+ break;
+ case EXCP_ARITH:
+ i = 0x0400;
+ break;
+ case EXCP_FEN:
+ i = 0x0480;
+ break;
+ case EXCP_CALL_PAL:
+ i = env->error_code;
+ /* There are 64 entry points for both privileged and unprivileged,
+ with bit 0x80 indicating unprivileged. Each entry point gets
+ 64 bytes to do its job. */
+ if (i & 0x80) {
+ i = 0x2000 + (i - 0x80) * 64;
+ } else {
+ i = 0x1000 + i * 64;
+ }
+ break;
+ default:
+ cpu_abort(env, "Unhandled CPU exception");
+ }
+
+ /* Remember where the exception happened. Emulate real hardware in
+ that the low bit of the PC indicates PALmode. */
+ env->exc_addr = env->pc | env->pal_mode;
+
+ /* Continue execution at the PALcode entry point. */
+ env->pc = env->palbr + i;
+
+ /* Switch to PALmode. */
+ env->pal_mode = 1;
+#endif /* !USER_ONLY */
}
-#endif
void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
int flags)
commit 26b46094478a347e65d3b1cbdb60f069d259a965
Author: Richard Henderson <rth at twiddle.net>
Date: Mon May 23 12:12:29 2011 -0700
target-alpha: Add IPRs to be used by the emulation PALcode.
These aren't actually used yet, but we can at least access
them via the HW_MFPR and HW_MTPR instructions.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index a59b39a..d1ef04d 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -244,6 +244,9 @@ struct CPUAlphaState {
uint8_t ps;
uint8_t intr_flag;
uint8_t pal_mode;
+ uint8_t fen;
+
+ uint32_t pcc_ofs;
/* These pass data from the exception logic in the translator and
helpers to the OS entry point. This is used for both system
@@ -252,6 +255,18 @@ struct CPUAlphaState {
uint64_t trap_arg1;
uint64_t trap_arg2;
+#if !defined(CONFIG_USER_ONLY)
+ /* The internal data required by our emulation of the Unix PALcode. */
+ uint64_t exc_addr;
+ uint64_t palbr;
+ uint64_t ptbr;
+ uint64_t vptptr;
+ uint64_t sysval;
+ uint64_t usp;
+ uint64_t shadow[8];
+ uint64_t scratch[24];
+#endif
+
#if TARGET_LONG_BITS > HOST_LONG_BITS
/* temporary fixed-point registers
* used to emulate 64 bits target on 32 bits hosts
diff --git a/target-alpha/machine.c b/target-alpha/machine.c
index ed9bf65..76d70d9 100644
--- a/target-alpha/machine.c
+++ b/target-alpha/machine.c
@@ -47,11 +47,24 @@ static VMStateField vmstate_cpu_fields[] = {
VMSTATE_UINT8(ps, CPUState),
VMSTATE_UINT8(intr_flag, CPUState),
VMSTATE_UINT8(pal_mode, CPUState),
+ VMSTATE_UINT8(fen, CPUState),
+
+ VMSTATE_UINT32(pcc_ofs, CPUState),
VMSTATE_UINTTL(trap_arg0, CPUState),
VMSTATE_UINTTL(trap_arg1, CPUState),
VMSTATE_UINTTL(trap_arg2, CPUState),
+ VMSTATE_UINTTL(exc_addr, CPUState),
+ VMSTATE_UINTTL(palbr, CPUState),
+ VMSTATE_UINTTL(ptbr, CPUState),
+ VMSTATE_UINTTL(vptptr, CPUState),
+ VMSTATE_UINTTL(sysval, CPUState),
+ VMSTATE_UINTTL(usp, CPUState),
+
+ VMSTATE_UINTTL_ARRAY(shadow, CPUState, 8),
+ VMSTATE_UINTTL_ARRAY(scratch, CPUState, 24),
+
VMSTATE_END_OF_LIST()
};
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index a937356..3802428 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1468,6 +1468,89 @@ static void gen_rx(int ra, int set)
tcg_temp_free_i32(tmp);
}
+#ifndef CONFIG_USER_ONLY
+
+#define PR_BYTE 0x100000
+#define PR_LONG 0x200000
+
+static int cpu_pr_data(int pr)
+{
+ switch (pr) {
+ case 0: return offsetof(CPUAlphaState, ps) | PR_BYTE;
+ case 1: return offsetof(CPUAlphaState, fen) | PR_BYTE;
+ case 2: return offsetof(CPUAlphaState, pcc_ofs) | PR_LONG;
+ case 3: return offsetof(CPUAlphaState, trap_arg0);
+ case 4: return offsetof(CPUAlphaState, trap_arg1);
+ case 5: return offsetof(CPUAlphaState, trap_arg2);
+ case 6: return offsetof(CPUAlphaState, exc_addr);
+ case 7: return offsetof(CPUAlphaState, palbr);
+ case 8: return offsetof(CPUAlphaState, ptbr);
+ case 9: return offsetof(CPUAlphaState, vptptr);
+ case 10: return offsetof(CPUAlphaState, unique);
+ case 11: return offsetof(CPUAlphaState, sysval);
+ case 12: return offsetof(CPUAlphaState, usp);
+
+ case 32 ... 39:
+ return offsetof(CPUAlphaState, shadow[pr - 32]);
+ case 40 ... 63:
+ return offsetof(CPUAlphaState, scratch[pr - 40]);
+ }
+ return 0;
+}
+
+static void gen_mfpr(int ra, int regno)
+{
+ int data = cpu_pr_data(regno);
+
+ /* In our emulated PALcode, these processor registers have no
+ side effects from reading. */
+ if (ra == 31) {
+ return;
+ }
+
+ /* The basic registers are data only, and unknown registers
+ are read-zero, write-ignore. */
+ if (data == 0) {
+ tcg_gen_movi_i64(cpu_ir[ra], 0);
+ } else if (data & PR_BYTE) {
+ tcg_gen_ld8u_i64(cpu_ir[ra], cpu_env, data & ~PR_BYTE);
+ } else if (data & PR_LONG) {
+ tcg_gen_ld32s_i64(cpu_ir[ra], cpu_env, data & ~PR_LONG);
+ } else {
+ tcg_gen_ld_i64(cpu_ir[ra], cpu_env, data);
+ }
+}
+
+static void gen_mtpr(int rb, int regno)
+{
+ TCGv tmp;
+ int data;
+
+ if (rb == 31) {
+ tmp = tcg_const_i64(0);
+ } else {
+ tmp = cpu_ir[rb];
+ }
+
+ /* The basic registers are data only, and unknown registers
+ are read-zero, write-ignore. */
+ data = cpu_pr_data(regno);
+ if (data != 0) {
+ if (data & PR_BYTE) {
+ tcg_gen_st8_i64(tmp, cpu_env, data & ~PR_BYTE);
+ } else if (data & PR_LONG) {
+ tcg_gen_st32_i64(tmp, cpu_env, data & ~PR_LONG);
+ } else {
+ tcg_gen_st_i64(tmp, cpu_env, data);
+ }
+ }
+
+ if (rb == 31) {
+ tcg_temp_free(tmp);
+ }
+}
+#endif /* !USER_ONLY*/
+
static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
{
uint32_t palcode;
@@ -2576,6 +2659,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x19:
/* HW_MFPR (PALcode) */
+#ifndef CONFIG_USER_ONLY
+ if (ctx->pal_mode) {
+ gen_mfpr(ra, insn & 0xffff);
+ break;
+ }
+#endif
goto invalid_opc;
case 0x1A:
/* JMP, JSR, RET, JSR_COROUTINE. These only differ by the branch
@@ -2845,6 +2934,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x1D:
/* HW_MTPR (PALcode) */
+#ifndef CONFIG_USER_ONLY
+ if (ctx->pal_mode) {
+ gen_mtpr(ra, insn & 0xffff);
+ break;
+ }
+#endif
goto invalid_opc;
case 0x1E:
/* HW_RET (PALcode) */
@@ -3272,6 +3367,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
| FPCR_UNFD | FPCR_INED | FPCR_DNOD));
#endif
env->lock_addr = -1;
+ env->fen = 1;
qemu_init_vcpu(env);
return env;
commit bba9bdcee8d4acc4e5f243f40d015a5a30493faa
Author: Richard Henderson <rth at twiddle.net>
Date: Fri May 20 14:14:44 2011 -0700
target-alpha: Use kernel mmu_idx for pal_mode.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 4407b32..a59b39a 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -341,7 +341,13 @@ enum {
static inline int cpu_mmu_index(CPUState *env)
{
- return (env->ps & PS_USER_MODE) != 0;
+ if (env->pal_mode) {
+ return MMU_KERNEL_IDX;
+ } else if (env->ps & PS_USER_MODE) {
+ return MMU_USER_IDX;
+ } else {
+ return MMU_KERNEL_IDX;
+ }
}
enum {
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 2f3c637..a937356 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -3098,10 +3098,8 @@ static inline void gen_intermediate_code_internal(CPUState *env,
ctx.env = env;
ctx.pc = pc_start;
ctx.amask = env->amask;
-#if defined (CONFIG_USER_ONLY)
- ctx.mem_idx = 0;
-#else
- ctx.mem_idx = ((env->ps >> 3) & 3);
+ ctx.mem_idx = cpu_mmu_index(env);
+#if !defined (CONFIG_USER_ONLY)
ctx.pal_mode = env->pal_mode;
#endif
commit ea879fc719b0756f1768f765ee3a5660ce05ca7b
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Apr 18 14:19:17 2011 -0700
target-alpha: Add various symbolic constants.
The EXC_M_* constants were being set for the EV6, not as set for
the Unix kernel entry point.
Use PS_USER_MODE instead of hard-coding access to the PS register.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 01e3741..4407b32 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -274,11 +274,6 @@ struct CPUAlphaState {
#define cpu_gen_code cpu_alpha_gen_code
#define cpu_signal_handler cpu_alpha_signal_handler
-static inline int cpu_mmu_index (CPUState *env)
-{
- return (env->ps >> 3) & 1;
-}
-
#include "cpu-all.h"
enum {
@@ -305,14 +300,49 @@ enum {
EXCP_STQ_C,
};
-/* Arithmetic exception */
-#define EXC_M_IOV (1<<16) /* Integer Overflow */
-#define EXC_M_INE (1<<15) /* Inexact result */
-#define EXC_M_UNF (1<<14) /* Underflow */
-#define EXC_M_FOV (1<<13) /* Overflow */
-#define EXC_M_DZE (1<<12) /* Division by zero */
-#define EXC_M_INV (1<<11) /* Invalid operation */
-#define EXC_M_SWC (1<<10) /* Software completion */
+/* Hardware interrupt (entInt) constants. */
+enum {
+ INT_K_IP,
+ INT_K_CLK,
+ INT_K_MCHK,
+ INT_K_DEV,
+ INT_K_PERF,
+};
+
+/* Memory management (entMM) constants. */
+enum {
+ MM_K_TNV,
+ MM_K_ACV,
+ MM_K_FOR,
+ MM_K_FOE,
+ MM_K_FOW
+};
+
+/* Arithmetic exception (entArith) constants. */
+enum {
+ EXC_M_SWC = 1, /* Software completion */
+ EXC_M_INV = 2, /* Invalid operation */
+ EXC_M_DZE = 4, /* Division by zero */
+ EXC_M_FOV = 8, /* Overflow */
+ EXC_M_UNF = 16, /* Underflow */
+ EXC_M_INE = 32, /* Inexact result */
+ EXC_M_IOV = 64 /* Integer Overflow */
+};
+
+/* Processor status constants. */
+enum {
+ /* Low 3 bits are interrupt mask level. */
+ PS_INT_MASK = 7,
+
+ /* Bits 4 and 5 are the mmu mode. The VMS PALcode uses all 4 modes;
+ The Unix PALcode only uses bit 4. */
+ PS_USER_MODE = 8
+};
+
+static inline int cpu_mmu_index(CPUState *env)
+{
+ return (env->ps & PS_USER_MODE) != 0;
+}
enum {
IR_V0 = 0,
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 5f40d34..2f3c637 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -3269,7 +3269,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
env->amask = amask;
#if defined (CONFIG_USER_ONLY)
- env->ps = 1 << 3;
+ env->ps = PS_USER_MODE;
cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
| FPCR_UNFD | FPCR_INED | FPCR_DNOD));
#endif
commit 2d9671d391531a9bc3e79b8a7538dd06f3094623
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Apr 25 12:20:27 2011 -0700
target-alpha: Use do_restore_state for arithmetic exceptions.
This gets the PC right after an arithmetic exception. Also tidies
the code in the TLB fault handlers to use common code.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 672940e..fc5020a 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -25,20 +25,42 @@
/*****************************************************************************/
/* Exceptions processing helpers */
-void QEMU_NORETURN helper_excp (int excp, int error)
+
+/* This should only be called from translate, via gen_excp.
+ We expect that ENV->PC has already been updated. */
+void QEMU_NORETURN helper_excp(int excp, int error)
+{
+ env->exception_index = excp;
+ env->error_code = error;
+ cpu_loop_exit();
+}
+
+static void do_restore_state(void *retaddr)
+{
+ unsigned long pc = (unsigned long)retaddr;
+
+ if (pc) {
+ TranslationBlock *tb = tb_find_pc(pc);
+ if (tb) {
+ cpu_restore_state(tb, env, pc);
+ }
+ }
+}
+
+/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
+static void QEMU_NORETURN dynamic_excp(int excp, int error)
{
env->exception_index = excp;
env->error_code = error;
+ do_restore_state(GETPC());
cpu_loop_exit();
}
static void QEMU_NORETURN arith_excp(int exc, uint64_t mask)
{
- env->exception_index = EXCP_ARITH;
- env->error_code = 0;
env->trap_arg0 = exc;
env->trap_arg1 = mask;
- cpu_loop_exit();
+ dynamic_excp(EXCP_ARITH, 0);
}
uint64_t helper_load_pcc (void)
@@ -521,7 +543,7 @@ static inline float32 f_to_float32(uint64_t a)
if (unlikely(!exp && mant_sig)) {
/* Reserved operands / Dirty zero */
- helper_excp(EXCP_OPCDEC, 0);
+ dynamic_excp(EXCP_OPCDEC, 0);
}
if (exp < 3) {
@@ -651,7 +673,7 @@ static inline float64 g_to_float64(uint64_t a)
if (!exp && mant_sig) {
/* Reserved operands / Dirty zero */
- helper_excp(EXCP_OPCDEC, 0);
+ dynamic_excp(EXCP_OPCDEC, 0);
}
if (exp < 3) {
@@ -1260,9 +1282,7 @@ uint64_t helper_stq_c_phys(uint64_t p, uint64_t v)
/* XXX: fix it to restore all registers */
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
{
- TranslationBlock *tb;
CPUState *saved_env;
- unsigned long pc;
int ret;
/* XXX: hack to restore env in all cases, even if not called from
@@ -1270,17 +1290,8 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
saved_env = env;
env = cpu_single_env;
ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
- if (!likely(ret == 0)) {
- if (likely(retaddr)) {
- /* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
- if (likely(tb)) {
- /* the PC is inside the translated code. It means that we have
- a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
- }
- }
+ if (unlikely(ret != 0)) {
+ do_restore_state(retaddr);
/* Exception index and error code are already set */
cpu_loop_exit();
}
commit b5f1aa64442409cca7a146f34fc0fd53ac8a3527
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Apr 18 13:19:28 2011 -0700
target-alpha: Tidy up arithmetic exceptions.
Introduce and use arith_excp, filling in the trap_arg[01] IPRs.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 73e5805..672940e 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -32,6 +32,15 @@ void QEMU_NORETURN helper_excp (int excp, int error)
cpu_loop_exit();
}
+static void QEMU_NORETURN arith_excp(int exc, uint64_t mask)
+{
+ env->exception_index = EXCP_ARITH;
+ env->error_code = 0;
+ env->trap_arg0 = exc;
+ env->trap_arg1 = mask;
+ cpu_loop_exit();
+}
+
uint64_t helper_load_pcc (void)
{
/* ??? This isn't a timer for which we have any rate info. */
@@ -53,7 +62,7 @@ uint64_t helper_addqv (uint64_t op1, uint64_t op2)
uint64_t tmp = op1;
op1 += op2;
if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return op1;
}
@@ -63,7 +72,7 @@ uint64_t helper_addlv (uint64_t op1, uint64_t op2)
uint64_t tmp = op1;
op1 = (uint32_t)(op1 + op2);
if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return op1;
}
@@ -73,7 +82,7 @@ uint64_t helper_subqv (uint64_t op1, uint64_t op2)
uint64_t res;
res = op1 - op2;
if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return res;
}
@@ -83,7 +92,7 @@ uint64_t helper_sublv (uint64_t op1, uint64_t op2)
uint32_t res;
res = op1 - op2;
if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return res;
}
@@ -93,7 +102,7 @@ uint64_t helper_mullv (uint64_t op1, uint64_t op2)
int64_t res = (int64_t)op1 * (int64_t)op2;
if (unlikely((int32_t)res != res)) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return (int64_t)((int32_t)res);
}
@@ -105,7 +114,7 @@ uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
muls64(&tl, &th, op1, op2);
/* If th != 0 && th != -1, then we had an overflow */
if (unlikely((th + 1) > 1)) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return tl;
}
@@ -373,8 +382,6 @@ void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
if (exc) {
uint32_t hw_exc = 0;
- env->trap_arg1 = 1ull << regno;
-
if (exc & float_flag_invalid) {
hw_exc |= EXC_M_INV;
}
@@ -390,7 +397,8 @@ void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
if (exc & float_flag_inexact) {
hw_exc |= EXC_M_INE;
}
- helper_excp(EXCP_ARITH, hw_exc);
+
+ arith_excp(hw_exc, 1ull << regno);
}
}
@@ -420,7 +428,7 @@ uint64_t helper_ieee_input(uint64_t val)
if (env->fpcr_dnz) {
val &= 1ull << 63;
} else {
- helper_excp(EXCP_ARITH, EXC_M_UNF);
+ arith_excp(EXC_M_UNF, 0);
}
}
} else if (exp == 0x7ff) {
@@ -428,7 +436,7 @@ uint64_t helper_ieee_input(uint64_t val)
/* ??? I'm not sure these exception bit flags are correct. I do
know that the Linux kernel, at least, doesn't rely on them and
just emulates the insn to figure out what exception to use. */
- helper_excp(EXCP_ARITH, frac ? EXC_M_INV : EXC_M_FOV);
+ arith_excp(frac ? EXC_M_INV : EXC_M_FOV, 0);
}
return val;
}
@@ -445,12 +453,12 @@ uint64_t helper_ieee_input_cmp(uint64_t val)
if (env->fpcr_dnz) {
val &= 1ull << 63;
} else {
- helper_excp(EXCP_ARITH, EXC_M_UNF);
+ arith_excp(EXC_M_UNF, 0);
}
}
} else if (exp == 0x7ff && frac) {
/* NaN. */
- helper_excp(EXCP_ARITH, EXC_M_INV);
+ arith_excp(EXC_M_INV, 0);
}
return val;
}
commit 07b6c13b09d2e00a95e83fa76630d7c0d16c10b3
Author: Richard Henderson <rth at twiddle.net>
Date: Fri May 20 14:04:57 2011 -0700
target-alpha: Tidy exception constants.
There's no need to attempt to match EXCP_* values with PALcode entry
point offsets. Instead, compress all the values to make for more
efficient switch statements within QEMU.
We will be doing TLB fill within QEMU proper, not within the PALcode,
so all of the ITB/DTB miss, double fault, and access exceptions can
be compressed to EXCP_MMFAULT.
Compress all of the EXCP_CALL_PAL exceptions into one.
Use env->error_code to store the specific entry point.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/linux-user/main.c b/linux-user/main.c
index 0954591..04da0a4 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2508,19 +2508,13 @@ void cpu_loop (CPUState *env)
fprintf(stderr, "Machine check exception. Exit\n");
exit(1);
break;
- case EXCP_ARITH:
- env->lock_addr = -1;
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_FLTINV;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, &info);
- break;
- case EXCP_HW_INTERRUPT:
+ case EXCP_SMP_INTERRUPT:
+ case EXCP_CLK_INTERRUPT:
+ case EXCP_DEV_INTERRUPT:
fprintf(stderr, "External interrupt. Exit\n");
exit(1);
break;
- case EXCP_DFAULT:
+ case EXCP_MMFAULT:
env->lock_addr = -1;
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
@@ -2529,22 +2523,6 @@ void cpu_loop (CPUState *env)
info._sifields._sigfault._addr = env->trap_arg0;
queue_signal(env, info.si_signo, &info);
break;
- case EXCP_DTB_MISS_PAL:
- fprintf(stderr, "MMU data TLB miss in PALcode\n");
- exit(1);
- break;
- case EXCP_ITB_MISS:
- fprintf(stderr, "MMU instruction TLB miss\n");
- exit(1);
- break;
- case EXCP_ITB_ACV:
- fprintf(stderr, "MMU instruction access violation\n");
- exit(1);
- break;
- case EXCP_DTB_MISS_NATIVE:
- fprintf(stderr, "MMU data TLB miss\n");
- exit(1);
- break;
case EXCP_UNALIGN:
env->lock_addr = -1;
info.si_signo = TARGET_SIGBUS;
@@ -2562,12 +2540,20 @@ void cpu_loop (CPUState *env)
info._sifields._sigfault._addr = env->pc;
queue_signal(env, info.si_signo, &info);
break;
+ case EXCP_ARITH:
+ env->lock_addr = -1;
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_FLTINV;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, &info);
+ break;
case EXCP_FEN:
/* No-op. Linux simply re-enables the FPU. */
break;
- case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1):
+ case EXCP_CALL_PAL:
env->lock_addr = -1;
- switch ((trapnr >> 6) | 0x80) {
+ switch (env->error_code) {
case 0x80:
/* BPT */
info.si_signo = TARGET_SIGTRAP;
@@ -2658,8 +2644,6 @@ void cpu_loop (CPUState *env)
goto do_sigill;
}
break;
- case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1):
- goto do_sigill;
case EXCP_DEBUG:
info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP);
if (info.si_signo) {
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index be7d151..01e3741 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -289,26 +289,20 @@ enum {
};
enum {
- EXCP_RESET = 0x0000,
- EXCP_MCHK = 0x0020,
- EXCP_ARITH = 0x0060,
- EXCP_HW_INTERRUPT = 0x00E0,
- EXCP_DFAULT = 0x01E0,
- EXCP_DTB_MISS_PAL = 0x09E0,
- EXCP_ITB_MISS = 0x03E0,
- EXCP_ITB_ACV = 0x07E0,
- EXCP_DTB_MISS_NATIVE = 0x08E0,
- EXCP_UNALIGN = 0x11E0,
- EXCP_OPCDEC = 0x13E0,
- EXCP_FEN = 0x17E0,
- EXCP_CALL_PAL = 0x2000,
- EXCP_CALL_PALP = 0x3000,
- EXCP_CALL_PALE = 0x4000,
- /* Pseudo exception for console */
- EXCP_CONSOLE_DISPATCH = 0x4001,
- EXCP_CONSOLE_FIXUP = 0x4002,
- EXCP_STL_C = 0x4003,
- EXCP_STQ_C = 0x4004,
+ EXCP_RESET,
+ EXCP_MCHK,
+ EXCP_SMP_INTERRUPT,
+ EXCP_CLK_INTERRUPT,
+ EXCP_DEV_INTERRUPT,
+ EXCP_MMFAULT,
+ EXCP_UNALIGN,
+ EXCP_OPCDEC,
+ EXCP_ARITH,
+ EXCP_FEN,
+ EXCP_CALL_PAL,
+ /* For Usermode emulation. */
+ EXCP_STL_C,
+ EXCP_STQ_C,
};
/* Arithmetic exception */
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 5c3263b..c5479fd 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -164,10 +164,7 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int mmu_idx, int is_softmmu)
{
- if (rw == 2)
- env->exception_index = EXCP_ITB_MISS;
- else
- env->exception_index = EXCP_DFAULT;
+ env->exception_index = EXCP_MMFAULT;
env->trap_arg0 = address;
return 1;
}
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index fe0ae96..5f40d34 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1516,7 +1516,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
#endif
if (palcode >= 0x80 && palcode < 0xC0) {
/* Unprivileged PAL call */
- ret = gen_excp(ctx, EXCP_CALL_PAL + ((palcode & 0x3F) << 6), 0);
+ ret = gen_excp(ctx, EXCP_CALL_PAL, palcode & 0xBF);
break;
}
#ifndef CONFIG_USER_ONLY
@@ -1525,7 +1525,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
if (ctx->mem_idx != MMU_KERNEL_IDX) {
goto invalid_opc;
}
- ret = gen_excp(ctx, EXCP_CALL_PALP + ((palcode & 0x3F) << 6), 0);
+ ret = gen_excp(ctx, EXCP_CALL_PAL, palcode & 0x3F);
}
#endif
/* Invalid PAL call */
commit b758aca1f6cdb175634812b79f5560c36c902d00
Author: Richard Henderson <rth at twiddle.net>
Date: Fri May 20 14:02:28 2011 -0700
target-alpha: Enable the alpha-softmmu target.
With all of the pre-existing code that would not compile gone,
this is the earliest point at which the target can be enabled.
There is no machine defined yet, so this will crash on startup.
Enable the target anyway, to make sure that further compilation
problems do not creep back in.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/Makefile.target b/Makefile.target
index d2c988f..1d3862a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -376,7 +376,8 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
-obj-alpha-y =
+obj-alpha-y = i8259.o mc146818rtc.o
+obj-alpha-y += vga.o cirrus_vga.o
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/configure b/configure
index a318d37..53666d2 100755
--- a/configure
+++ b/configure
@@ -831,6 +831,7 @@ if [ "$softmmu" = "yes" ] ; then
default_target_list="\
i386-softmmu \
x86_64-softmmu \
+alpha-softmmu \
arm-softmmu \
cris-softmmu \
lm32-softmmu \
diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak
new file mode 100644
index 0000000..abadcff
--- /dev/null
+++ b/default-configs/alpha-softmmu.mak
@@ -0,0 +1,9 @@
+# Default configuration for alpha-softmmu
+
+include pci.mak
+CONFIG_SERIAL=y
+CONFIG_I8254=y
+CONFIG_VGA_PCI=y
+CONFIG_IDE_CORE=y
+CONFIG_IDE_QDEV=y
+CONFIG_VMWARE_VGA=y
diff --git a/target-alpha/machine.c b/target-alpha/machine.c
new file mode 100644
index 0000000..ed9bf65
--- /dev/null
+++ b/target-alpha/machine.c
@@ -0,0 +1,74 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+static int get_fpcr(QEMUFile *f, void *opaque, size_t size)
+{
+ CPUAlphaState *env = opaque;
+ cpu_alpha_store_fpcr(env, qemu_get_be64(f));
+ return 0;
+}
+
+static void put_fpcr(QEMUFile *f, void *opaque, size_t size)
+{
+ CPUAlphaState *env = opaque;
+ qemu_put_be64(f, cpu_alpha_load_fpcr(env));
+}
+
+static const VMStateInfo vmstate_fpcr = {
+ .name = "fpcr",
+ .get = get_fpcr,
+ .put = put_fpcr,
+};
+
+static VMStateField vmstate_cpu_fields[] = {
+ VMSTATE_UINTTL_ARRAY(ir, CPUState, 31),
+ VMSTATE_UINTTL_ARRAY(fir, CPUState, 31),
+ /* Save the architecture value of the fpcr, not the internally
+ expanded version. Since this architecture value does not
+ exist in memory to be stored, this requires a but of hoop
+ jumping. We want OFFSET=0 so that we effectively pass ENV
+ to the helper functions, and we need to fill in the name by
+ hand since there's no field of that name. */
+ {
+ .name = "fpcr",
+ .version_id = 0,
+ .size = sizeof(uint64_t),
+ .info = &vmstate_fpcr,
+ .flags = VMS_SINGLE,
+ .offset = 0
+ },
+ VMSTATE_UINTTL(pc, CPUState),
+ VMSTATE_UINTTL(unique, CPUState),
+ VMSTATE_UINTTL(lock_addr, CPUState),
+ VMSTATE_UINTTL(lock_value, CPUState),
+ /* Note that lock_st_addr is not saved; it is a temporary
+ used during the execution of the st[lq]_c insns. */
+
+ VMSTATE_UINT8(ps, CPUState),
+ VMSTATE_UINT8(intr_flag, CPUState),
+ VMSTATE_UINT8(pal_mode, CPUState),
+
+ VMSTATE_UINTTL(trap_arg0, CPUState),
+ VMSTATE_UINTTL(trap_arg1, CPUState),
+ VMSTATE_UINTTL(trap_arg2, CPUState),
+
+ VMSTATE_END_OF_LIST()
+};
+
+static const VMStateDescription vmstate_cpu = {
+ .name = "cpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = vmstate_cpu_fields,
+};
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+ vmstate_save_state(f, &vmstate_cpu, opaque);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+ return vmstate_load_state(f, &vmstate_cpu, opaque, version_id);
+}
commit 129d8aa575b1a0c06b471a506c5a233bd270bff4
Author: Richard Henderson <rth at twiddle.net>
Date: Fri May 20 13:30:00 2011 -0700
target-alpha: Rationalize internal processor registers.
Delete all the code that tried to emulate the real IPRs of some
unnamed CPU. Replace those with just 3 slots that we can use to
communicate trap information between the helper functions that
signal exceptions and the OS trap handler.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/linux-user/main.c b/linux-user/main.c
index 088def3..0954591 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2524,9 +2524,9 @@ void cpu_loop (CPUState *env)
env->lock_addr = -1;
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
- info.si_code = (page_get_flags(env->ipr[IPR_EXC_ADDR]) & PAGE_VALID
+ info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
- info._sifields._sigfault._addr = env->ipr[IPR_EXC_ADDR];
+ info._sifields._sigfault._addr = env->trap_arg0;
queue_signal(env, info.si_signo, &info);
break;
case EXCP_DTB_MISS_PAL:
@@ -2550,7 +2550,7 @@ void cpu_loop (CPUState *env)
info.si_signo = TARGET_SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_BUS_ADRALN;
- info._sifields._sigfault._addr = env->ipr[IPR_EXC_ADDR];
+ info._sifields._sigfault._addr = env->trap_arg0;
queue_signal(env, info.si_signo, &info);
break;
case EXCP_OPCDEC:
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 6b9deb3..be7d151 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -192,131 +192,6 @@ enum {
#define SWCR_MASK (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK)
-/* Internal processor registers */
-/* XXX: TOFIX: most of those registers are implementation dependant */
-enum {
-#if defined(CONFIG_USER_ONLY)
- IPR_EXC_ADDR,
- IPR_EXC_SUM,
- IPR_EXC_MASK,
-#else
- /* Ebox IPRs */
- IPR_CC = 0xC0, /* 21264 */
- IPR_CC_CTL = 0xC1, /* 21264 */
-#define IPR_CC_CTL_ENA_SHIFT 32
-#define IPR_CC_CTL_COUNTER_MASK 0xfffffff0UL
- IPR_VA = 0xC2, /* 21264 */
- IPR_VA_CTL = 0xC4, /* 21264 */
-#define IPR_VA_CTL_VA_48_SHIFT 1
-#define IPR_VA_CTL_VPTB_SHIFT 30
- IPR_VA_FORM = 0xC3, /* 21264 */
- /* Ibox IPRs */
- IPR_ITB_TAG = 0x00, /* 21264 */
- IPR_ITB_PTE = 0x01, /* 21264 */
- IPR_ITB_IAP = 0x02,
- IPR_ITB_IA = 0x03, /* 21264 */
- IPR_ITB_IS = 0x04, /* 21264 */
- IPR_PMPC = 0x05,
- IPR_EXC_ADDR = 0x06, /* 21264 */
- IPR_IVA_FORM = 0x07, /* 21264 */
- IPR_CM = 0x09, /* 21264 */
-#define IPR_CM_SHIFT 3
-#define IPR_CM_MASK (3ULL << IPR_CM_SHIFT) /* 21264 */
- IPR_IER = 0x0A, /* 21264 */
-#define IPR_IER_MASK 0x0000007fffffe000ULL
- IPR_IER_CM = 0x0B, /* 21264: = CM | IER */
- IPR_SIRR = 0x0C, /* 21264 */
-#define IPR_SIRR_SHIFT 14
-#define IPR_SIRR_MASK 0x7fff
- IPR_ISUM = 0x0D, /* 21264 */
- IPR_HW_INT_CLR = 0x0E, /* 21264 */
- IPR_EXC_SUM = 0x0F,
- IPR_PAL_BASE = 0x10,
- IPR_I_CTL = 0x11,
-#define IPR_I_CTL_CHIP_ID_SHIFT 24 /* 21264 */
-#define IPR_I_CTL_BIST_FAIL (1 << 23) /* 21264 */
-#define IPR_I_CTL_IC_EN_SHIFT 2 /* 21264 */
-#define IPR_I_CTL_SDE1_SHIFT 7 /* 21264 */
-#define IPR_I_CTL_HWE_SHIFT 12 /* 21264 */
-#define IPR_I_CTL_VA_48_SHIFT 15 /* 21264 */
-#define IPR_I_CTL_SPE_SHIFT 3 /* 21264 */
-#define IPR_I_CTL_CALL_PAL_R23_SHIFT 20 /* 21264 */
- IPR_I_STAT = 0x16, /* 21264 */
- IPR_IC_FLUSH = 0x13, /* 21264 */
- IPR_IC_FLUSH_ASM = 0x12, /* 21264 */
- IPR_CLR_MAP = 0x15,
- IPR_SLEEP = 0x17,
- IPR_PCTX = 0x40,
- IPR_PCTX_ASN = 0x01, /* field */
-#define IPR_PCTX_ASN_SHIFT 39
- IPR_PCTX_ASTER = 0x02, /* field */
-#define IPR_PCTX_ASTER_SHIFT 5
- IPR_PCTX_ASTRR = 0x04, /* field */
-#define IPR_PCTX_ASTRR_SHIFT 9
- IPR_PCTX_PPCE = 0x08, /* field */
-#define IPR_PCTX_PPCE_SHIFT 1
- IPR_PCTX_FPE = 0x10, /* field */
-#define IPR_PCTX_FPE_SHIFT 2
- IPR_PCTX_ALL = 0x5f, /* all fields */
- IPR_PCTR_CTL = 0x14, /* 21264 */
- /* Mbox IPRs */
- IPR_DTB_TAG0 = 0x20, /* 21264 */
- IPR_DTB_TAG1 = 0xA0, /* 21264 */
- IPR_DTB_PTE0 = 0x21, /* 21264 */
- IPR_DTB_PTE1 = 0xA1, /* 21264 */
- IPR_DTB_ALTMODE = 0xA6,
- IPR_DTB_ALTMODE0 = 0x26, /* 21264 */
-#define IPR_DTB_ALTMODE_MASK 3
- IPR_DTB_IAP = 0xA2,
- IPR_DTB_IA = 0xA3, /* 21264 */
- IPR_DTB_IS0 = 0x24,
- IPR_DTB_IS1 = 0xA4,
- IPR_DTB_ASN0 = 0x25, /* 21264 */
- IPR_DTB_ASN1 = 0xA5, /* 21264 */
-#define IPR_DTB_ASN_SHIFT 56
- IPR_MM_STAT = 0x27, /* 21264 */
- IPR_M_CTL = 0x28, /* 21264 */
-#define IPR_M_CTL_SPE_SHIFT 1
-#define IPR_M_CTL_SPE_MASK 7
- IPR_DC_CTL = 0x29, /* 21264 */
- IPR_DC_STAT = 0x2A, /* 21264 */
- /* Cbox IPRs */
- IPR_C_DATA = 0x2B,
- IPR_C_SHIFT = 0x2C,
-
- IPR_ASN,
- IPR_ASTEN,
- IPR_ASTSR,
- IPR_DATFX,
- IPR_ESP,
- IPR_FEN,
- IPR_IPIR,
- IPR_IPL,
- IPR_KSP,
- IPR_MCES,
- IPR_PERFMON,
- IPR_PCBB,
- IPR_PRBR,
- IPR_PTBR,
- IPR_SCBB,
- IPR_SISR,
- IPR_SSP,
- IPR_SYSPTBR,
- IPR_TBCHK,
- IPR_TBIA,
- IPR_TBIAP,
- IPR_TBIS,
- IPR_TBISD,
- IPR_TBISI,
- IPR_USP,
- IPR_VIRBND,
- IPR_VPTB,
- IPR_WHAMI,
- IPR_ALT_MODE,
-#endif
- IPR_LAST,
-};
-
/* MMU modes definitions */
/* Alpha has 5 MMU modes: PALcode, kernel, executive, supervisor, and user.
@@ -350,8 +225,6 @@ struct CPUAlphaState {
uint64_t ir[31];
float64 fir[31];
uint64_t pc;
- uint64_t ipr[IPR_LAST];
- uint64_t ps;
uint64_t unique;
uint64_t lock_addr;
uint64_t lock_st_addr;
@@ -366,10 +239,18 @@ struct CPUAlphaState {
uint8_t fpcr_dnod;
uint8_t fpcr_undz;
- /* Used for HW_LD / HW_ST */
- uint8_t saved_mode;
- /* For RC and RS */
+ /* The Internal Processor Registers. Some of these we assume always
+ exist for use in user-mode. */
+ uint8_t ps;
uint8_t intr_flag;
+ uint8_t pal_mode;
+
+ /* These pass data from the exception logic in the translator and
+ helpers to the OS entry point. This is used for both system
+ emulation and user-mode. */
+ uint64_t trap_arg0;
+ uint64_t trap_arg1;
+ uint64_t trap_arg2;
#if TARGET_LONG_BITS > HOST_LONG_BITS
/* temporary fixed-point registers
@@ -381,8 +262,6 @@ struct CPUAlphaState {
/* Those resources are used only in Qemu core */
CPU_COMMON
- uint32_t hflags;
-
int error_code;
uint32_t features;
@@ -492,8 +371,6 @@ void do_interrupt (CPUState *env);
uint64_t cpu_alpha_load_fpcr (CPUState *env);
void cpu_alpha_store_fpcr (CPUState *env, uint64_t val);
-int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp);
-int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp);
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index f7cf4ee..5c3263b 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -168,8 +168,7 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
env->exception_index = EXCP_ITB_MISS;
else
env->exception_index = EXCP_DFAULT;
- env->ipr[IPR_EXC_ADDR] = address;
-
+ env->trap_arg0 = address;
return 1;
}
@@ -188,352 +187,12 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int mmu_idx, int is_softmmu)
{
- uint32_t opc;
-
- if (rw == 2) {
- /* Instruction translation buffer miss */
- env->exception_index = EXCP_ITB_MISS;
- } else {
- if (env->ipr[IPR_EXC_ADDR] & 1)
- env->exception_index = EXCP_DTB_MISS_PAL;
- else
- env->exception_index = EXCP_DTB_MISS_NATIVE;
- opc = (ldl_code(env->pc) >> 21) << 4;
- if (rw) {
- opc |= 0x9;
- } else {
- opc |= 0x4;
- }
- env->ipr[IPR_MM_STAT] = opc;
- }
-
- return 1;
-}
-
-int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
-{
- uint64_t hwpcb;
- int ret = 0;
-
- hwpcb = env->ipr[IPR_PCBB];
- switch (iprn) {
- case IPR_ASN:
- if (env->features & FEATURE_ASN)
- *valp = env->ipr[IPR_ASN];
- else
- *valp = 0;
- break;
- case IPR_ASTEN:
- *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60;
- break;
- case IPR_ASTSR:
- *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60;
- break;
- case IPR_DATFX:
- /* Write only */
- ret = -1;
- break;
- case IPR_ESP:
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_ESP];
- else
- *valp = ldq_raw(hwpcb + 8);
- break;
- case IPR_FEN:
- *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63;
- break;
- case IPR_IPIR:
- /* Write-only */
- ret = -1;
- break;
- case IPR_IPL:
- *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
- break;
- case IPR_KSP:
- if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
- ret = -1;
- } else {
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_KSP];
- else
- *valp = ldq_raw(hwpcb + 0);
- }
- break;
- case IPR_MCES:
- *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59;
- break;
- case IPR_PERFMON:
- /* Implementation specific */
- *valp = 0;
- break;
- case IPR_PCBB:
- *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16;
- break;
- case IPR_PRBR:
- *valp = env->ipr[IPR_PRBR];
- break;
- case IPR_PTBR:
- *valp = env->ipr[IPR_PTBR];
- break;
- case IPR_SCBB:
- *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]);
- break;
- case IPR_SIRR:
- /* Write-only */
- ret = -1;
- break;
- case IPR_SISR:
- *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]);
- case IPR_SSP:
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_SSP];
- else
- *valp = ldq_raw(hwpcb + 16);
- break;
- case IPR_SYSPTBR:
- if (env->features & FEATURE_VIRBND)
- *valp = env->ipr[IPR_SYSPTBR];
- else
- ret = -1;
- break;
- case IPR_TBCHK:
- if ((env->features & FEATURE_TBCHK)) {
- /* XXX: TODO */
- *valp = 0;
- ret = -1;
- } else {
- ret = -1;
- }
- break;
- case IPR_TBIA:
- /* Write-only */
- ret = -1;
- break;
- case IPR_TBIAP:
- /* Write-only */
- ret = -1;
- break;
- case IPR_TBIS:
- /* Write-only */
- ret = -1;
- break;
- case IPR_TBISD:
- /* Write-only */
- ret = -1;
- break;
- case IPR_TBISI:
- /* Write-only */
- ret = -1;
- break;
- case IPR_USP:
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_USP];
- else
- *valp = ldq_raw(hwpcb + 24);
- break;
- case IPR_VIRBND:
- if (env->features & FEATURE_VIRBND)
- *valp = env->ipr[IPR_VIRBND];
- else
- ret = -1;
- break;
- case IPR_VPTB:
- *valp = env->ipr[IPR_VPTB];
- break;
- case IPR_WHAMI:
- *valp = env->ipr[IPR_WHAMI];
- break;
- default:
- /* Invalid */
- ret = -1;
- break;
- }
-
- return ret;
-}
-
-int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
-{
- uint64_t hwpcb, tmp64;
- uint8_t tmp8;
- int ret = 0;
-
- hwpcb = env->ipr[IPR_PCBB];
- switch (iprn) {
- case IPR_ASN:
- /* Read-only */
- ret = -1;
- break;
- case IPR_ASTEN:
- tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4;
- *oldvalp = tmp8;
- tmp8 &= val & 0xF;
- tmp8 |= (val >> 4) & 0xF;
- env->ipr[IPR_ASTEN] &= ~0xF;
- env->ipr[IPR_ASTEN] |= tmp8;
- ret = 1;
- break;
- case IPR_ASTSR:
- tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4;
- *oldvalp = tmp8;
- tmp8 &= val & 0xF;
- tmp8 |= (val >> 4) & 0xF;
- env->ipr[IPR_ASTSR] &= ~0xF;
- env->ipr[IPR_ASTSR] |= tmp8;
- ret = 1;
- case IPR_DATFX:
- env->ipr[IPR_DATFX] &= ~0x1;
- env->ipr[IPR_DATFX] |= val & 1;
- tmp64 = ldq_raw(hwpcb + 56);
- tmp64 &= ~0x8000000000000000ULL;
- tmp64 |= (val & 1) << 63;
- stq_raw(hwpcb + 56, tmp64);
- break;
- case IPR_ESP:
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_ESP] = val;
- else
- stq_raw(hwpcb + 8, val);
- break;
- case IPR_FEN:
- env->ipr[IPR_FEN] = val & 1;
- tmp64 = ldq_raw(hwpcb + 56);
- tmp64 &= ~1;
- tmp64 |= val & 1;
- stq_raw(hwpcb + 56, tmp64);
- break;
- case IPR_IPIR:
- /* XXX: TODO: Send IRQ to CPU #ir[16] */
- break;
- case IPR_IPL:
- *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
- env->ipr[IPR_IPL] &= ~0x1F;
- env->ipr[IPR_IPL] |= val & 0x1F;
- /* XXX: may issue an interrupt or ASR _now_ */
- ret = 1;
- break;
- case IPR_KSP:
- if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
- ret = -1;
- } else {
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_KSP] = val;
- else
- stq_raw(hwpcb + 0, val);
- }
- break;
- case IPR_MCES:
- env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18);
- env->ipr[IPR_MCES] |= val & 0x18;
- break;
- case IPR_PERFMON:
- /* Implementation specific */
- *oldvalp = 0;
- ret = 1;
- break;
- case IPR_PCBB:
- /* Read-only */
- ret = -1;
- break;
- case IPR_PRBR:
- env->ipr[IPR_PRBR] = val;
- break;
- case IPR_PTBR:
- /* Read-only */
- ret = -1;
- break;
- case IPR_SCBB:
- env->ipr[IPR_SCBB] = (uint32_t)val;
- break;
- case IPR_SIRR:
- if (val & 0xF) {
- env->ipr[IPR_SISR] |= 1 << (val & 0xF);
- /* XXX: request a software interrupt _now_ */
- }
- break;
- case IPR_SISR:
- /* Read-only */
- ret = -1;
- break;
- case IPR_SSP:
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_SSP] = val;
- else
- stq_raw(hwpcb + 16, val);
- break;
- case IPR_SYSPTBR:
- if (env->features & FEATURE_VIRBND)
- env->ipr[IPR_SYSPTBR] = val;
- else
- ret = -1;
- break;
- case IPR_TBCHK:
- /* Read-only */
- ret = -1;
- break;
- case IPR_TBIA:
- tlb_flush(env, 1);
- break;
- case IPR_TBIAP:
- tlb_flush(env, 1);
- break;
- case IPR_TBIS:
- tlb_flush_page(env, val);
- break;
- case IPR_TBISD:
- tlb_flush_page(env, val);
- break;
- case IPR_TBISI:
- tlb_flush_page(env, val);
- break;
- case IPR_USP:
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_USP] = val;
- else
- stq_raw(hwpcb + 24, val);
- break;
- case IPR_VIRBND:
- if (env->features & FEATURE_VIRBND)
- env->ipr[IPR_VIRBND] = val;
- else
- ret = -1;
- break;
- case IPR_VPTB:
- env->ipr[IPR_VPTB] = val;
- break;
- case IPR_WHAMI:
- /* Read-only */
- ret = -1;
- break;
- default:
- /* Invalid */
- ret = -1;
- break;
- }
-
- return ret;
+ return 0;
}
void do_interrupt (CPUState *env)
{
- int excp;
-
- env->ipr[IPR_EXC_ADDR] = env->pc | 1;
- excp = env->exception_index;
- env->exception_index = -1;
- env->error_code = 0;
- /* XXX: disable interrupts and memory mapping */
- if (env->ipr[IPR_PAL_BASE] != -1ULL) {
- /* We use native PALcode */
- env->pc = env->ipr[IPR_PAL_BASE] + excp;
- } else {
- /* We use emulated PALcode */
- abort();
- /* Emulate REI */
- env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
- env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
- /* XXX: re-enable interrupts and memory mapping */
- }
+ abort();
}
#endif
@@ -548,7 +207,7 @@ void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
};
int i;
- cpu_fprintf(f, " PC " TARGET_FMT_lx " PS " TARGET_FMT_lx "\n",
+ cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
env->pc, env->ps);
for (i = 0; i < 31; i++) {
cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index de86ff2..9ffc372 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -101,8 +101,6 @@ DEF_HELPER_1(ieee_input_s, i64, i64)
#if !defined (CONFIG_USER_ONLY)
DEF_HELPER_1(hw_ret, void, i64)
-DEF_HELPER_2(mfpr, i64, int, i64)
-DEF_HELPER_2(mtpr, void, int, i64)
DEF_HELPER_1(ldl_phys, i64, i64)
DEF_HELPER_1(ldq_phys, i64, i64)
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index ea11cd2..73e5805 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -373,7 +373,7 @@ void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
if (exc) {
uint32_t hw_exc = 0;
- env->ipr[IPR_EXC_MASK] |= 1ull << regno;
+ env->trap_arg1 = 1ull << regno;
if (exc & float_flag_invalid) {
hw_exc |= EXC_M_INV;
@@ -1159,25 +1159,10 @@ uint64_t helper_cvtqg (uint64_t a)
void helper_hw_ret (uint64_t a)
{
env->pc = a & ~3;
- env->ipr[IPR_EXC_ADDR] = a & 1;
+ env->pal_mode = a & 1;
env->intr_flag = 0;
env->lock_addr = -1;
}
-
-uint64_t helper_mfpr (int iprn, uint64_t val)
-{
- uint64_t tmp;
-
- if (cpu_alpha_mfpr(env, iprn, &tmp) == 0)
- val = tmp;
-
- return val;
-}
-
-void helper_mtpr (int iprn, uint64_t val)
-{
- cpu_alpha_mtpr(env, iprn, val, NULL);
-}
#endif
/*****************************************************************************/
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 2559814..fe0ae96 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -2576,18 +2576,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x19:
/* HW_MFPR (PALcode) */
-#if defined (CONFIG_USER_ONLY)
goto invalid_opc;
-#else
- if (!ctx->pal_mode)
- goto invalid_opc;
- if (ra != 31) {
- TCGv tmp = tcg_const_i32(insn & 0xFF);
- gen_helper_mfpr(cpu_ir[ra], tmp, cpu_ir[ra]);
- tcg_temp_free(tmp);
- }
- break;
-#endif
case 0x1A:
/* JMP, JSR, RET, JSR_COROUTINE. These only differ by the branch
prediction stack action, which of course we don't implement. */
@@ -2856,25 +2845,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x1D:
/* HW_MTPR (PALcode) */
-#if defined (CONFIG_USER_ONLY)
goto invalid_opc;
-#else
- if (!ctx->pal_mode)
- goto invalid_opc;
- else {
- TCGv tmp1 = tcg_const_i32(insn & 0xFF);
- if (ra != 31)
- gen_helper_mtpr(tmp1, cpu_ir[ra]);
- else {
- TCGv tmp2 = tcg_const_i64(0);
- gen_helper_mtpr(tmp1, tmp2);
- tcg_temp_free(tmp2);
- }
- tcg_temp_free(tmp1);
- ret = EXIT_PC_STALE;
- }
- break;
-#endif
case 0x1E:
/* HW_RET (PALcode) */
#if defined (CONFIG_USER_ONLY)
@@ -2887,7 +2858,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
address from EXC_ADDR. This turns out to be useful for our
emulation PALcode, so continue to accept it. */
TCGv tmp = tcg_temp_new();
- tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUState, ipr[IPR_EXC_ADDR]));
+ /* FIXME: Get exc_addr. */
gen_helper_hw_ret(tmp);
tcg_temp_free(tmp);
} else {
@@ -3131,7 +3102,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
ctx.mem_idx = 0;
#else
ctx.mem_idx = ((env->ps >> 3) & 3);
- ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1;
+ ctx.pal_mode = env->pal_mode;
#endif
/* ??? Every TB begins with unset rounding mode, to be initialized on
@@ -3297,42 +3268,13 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
env->implver = implver;
env->amask = amask;
- env->ps = 0x1F00;
#if defined (CONFIG_USER_ONLY)
- env->ps |= 1 << 3;
+ env->ps = 1 << 3;
cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
| FPCR_UNFD | FPCR_INED | FPCR_DNOD));
#endif
env->lock_addr = -1;
- /* Initialize IPR */
-#if defined (CONFIG_USER_ONLY)
- env->ipr[IPR_EXC_ADDR] = 0;
- env->ipr[IPR_EXC_SUM] = 0;
- env->ipr[IPR_EXC_MASK] = 0;
-#else
- {
- // uint64_t hwpcb;
- // hwpcb = env->ipr[IPR_PCBB];
- env->ipr[IPR_ASN] = 0;
- env->ipr[IPR_ASTEN] = 0;
- env->ipr[IPR_ASTSR] = 0;
- env->ipr[IPR_DATFX] = 0;
- /* XXX: fix this */
- // env->ipr[IPR_ESP] = ldq_raw(hwpcb + 8);
- // env->ipr[IPR_KSP] = ldq_raw(hwpcb + 0);
- // env->ipr[IPR_SSP] = ldq_raw(hwpcb + 16);
- // env->ipr[IPR_USP] = ldq_raw(hwpcb + 24);
- env->ipr[IPR_FEN] = 0;
- env->ipr[IPR_IPL] = 31;
- env->ipr[IPR_MCES] = 0;
- env->ipr[IPR_PERFMON] = 0; /* Implementation specific */
- // env->ipr[IPR_PTBR] = ldq_raw(hwpcb + 32);
- env->ipr[IPR_SISR] = 0;
- env->ipr[IPR_VIRBND] = -1ULL;
- }
-#endif
-
qemu_init_vcpu(env);
return env;
}
commit 508b43eaf3dd179363557bf68e911ddea637e58b
Author: Richard Henderson <rth at twiddle.net>
Date: Fri May 20 13:21:15 2011 -0700
target-alpha: Merge HW_REI and HW_RET implementations.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index f4f693a..de86ff2 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -100,7 +100,6 @@ DEF_HELPER_1(ieee_input_cmp, i64, i64)
DEF_HELPER_1(ieee_input_s, i64, i64)
#if !defined (CONFIG_USER_ONLY)
-DEF_HELPER_0(hw_rei, void)
DEF_HELPER_1(hw_ret, void, i64)
DEF_HELPER_2(mfpr, i64, int, i64)
DEF_HELPER_2(mtpr, void, int, i64)
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index a90c7a6..ea11cd2 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -1156,22 +1156,12 @@ uint64_t helper_cvtqg (uint64_t a)
/* PALcode support special instructions */
#if !defined (CONFIG_USER_ONLY)
-void helper_hw_rei (void)
-{
- env->pc = env->ipr[IPR_EXC_ADDR] & ~3;
- env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
- env->intr_flag = 0;
- env->lock_addr = -1;
- /* XXX: re-enable interrupts and memory mapping */
-}
-
void helper_hw_ret (uint64_t a)
{
env->pc = a & ~3;
env->ipr[IPR_EXC_ADDR] = a & 1;
env->intr_flag = 0;
env->lock_addr = -1;
- /* XXX: re-enable interrupts and memory mapping */
}
uint64_t helper_mfpr (int iprn, uint64_t val)
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 2c0b9c2..2559814 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -2876,25 +2876,22 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
#endif
case 0x1E:
- /* HW_REI (PALcode) */
+ /* HW_RET (PALcode) */
#if defined (CONFIG_USER_ONLY)
goto invalid_opc;
#else
if (!ctx->pal_mode)
goto invalid_opc;
if (rb == 31) {
- /* "Old" alpha */
- gen_helper_hw_rei();
- } else {
- TCGv tmp;
-
- if (ra != 31) {
- tmp = tcg_temp_new();
- tcg_gen_addi_i64(tmp, cpu_ir[rb], (((int64_t)insn << 51) >> 51));
- } else
- tmp = tcg_const_i64(((int64_t)insn << 51) >> 51);
+ /* Pre-EV6 CPUs interpreted this as HW_REI, loading the return
+ address from EXC_ADDR. This turns out to be useful for our
+ emulation PALcode, so continue to accept it. */
+ TCGv tmp = tcg_temp_new();
+ tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUState, ipr[IPR_EXC_ADDR]));
gen_helper_hw_ret(tmp);
tcg_temp_free(tmp);
+ } else {
+ gen_helper_hw_ret(cpu_ir[rb]);
}
ret = EXIT_PC_UPDATED;
break;
commit 8417845ee9dbb2881409bac75365099d17d1cc3d
Author: Richard Henderson <rth at twiddle.net>
Date: Fri May 20 13:11:25 2011 -0700
target-alpha: Cleanup MMU modes.
Don't bother including executive and supervisor modes.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 0daa556..6b9deb3 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -317,9 +317,34 @@ enum {
IPR_LAST,
};
-typedef struct CPUAlphaState CPUAlphaState;
+/* MMU modes definitions */
+
+/* Alpha has 5 MMU modes: PALcode, kernel, executive, supervisor, and user.
+ The Unix PALcode only exposes the kernel and user modes; presumably
+ executive and supervisor are used by VMS.
+
+ PALcode itself uses physical mode for code and kernel mode for data;
+ there are PALmode instructions that can access data via physical mode
+ or via an os-installed "alternate mode", which is one of the 4 above.
+
+ QEMU does not currently properly distinguish between code/data when
+ looking up addresses. To avoid having to address this issue, our
+ emulated PALcode will cheat and use the KSEG mapping for its code+data
+ rather than physical addresses.
+
+ Moreover, we're only emulating Unix PALcode, and not attempting VMS.
+
+ All of which allows us to drop all but kernel and user modes.
+ Elide the unused MMU modes to save space. */
-#define NB_MMU_MODES 4
+#define NB_MMU_MODES 2
+
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_KERNEL_IDX 0
+#define MMU_USER_IDX 1
+
+typedef struct CPUAlphaState CPUAlphaState;
struct CPUAlphaState {
uint64_t ir[31];
@@ -370,15 +395,9 @@ struct CPUAlphaState {
#define cpu_gen_code cpu_alpha_gen_code
#define cpu_signal_handler cpu_alpha_signal_handler
-/* MMU modes definitions */
-#define MMU_MODE0_SUFFIX _kernel
-#define MMU_MODE1_SUFFIX _executive
-#define MMU_MODE2_SUFFIX _supervisor
-#define MMU_MODE3_SUFFIX _user
-#define MMU_USER_IDX 3
static inline int cpu_mmu_index (CPUState *env)
{
- return (env->ps >> 3) & 3;
+ return (env->ps >> 3) & 1;
}
#include "cpu-all.h"
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 851a045..2c0b9c2 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1522,8 +1522,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
#ifndef CONFIG_USER_ONLY
if (palcode < 0x40) {
/* Privileged PAL code */
- if (ctx->mem_idx & 1)
+ if (ctx->mem_idx != MMU_KERNEL_IDX) {
goto invalid_opc;
+ }
ret = gen_excp(ctx, EXCP_CALL_PALP + ((palcode & 0x3F) << 6), 0);
}
#endif
@@ -2651,11 +2652,11 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
goto invalid_opc;
case 0xA:
/* Longword virtual access with protection check (hw_ldl/w) */
- tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
+ tcg_gen_qemu_ld32s(cpu_ir[ra], addr, MMU_KERNEL_IDX);
break;
case 0xB:
/* Quadword virtual access with protection check (hw_ldq/w) */
- tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0);
+ tcg_gen_qemu_ld64(cpu_ir[ra], addr, MMU_KERNEL_IDX);
break;
case 0xC:
/* Longword virtual access with alt access mode (hw_ldl/a)*/
commit e52458fe29ac6f2c0edb17c3f78164200cd047b8
Author: Richard Henderson <rth at twiddle.net>
Date: Fri May 20 13:07:25 2011 -0700
target-alpha: Fix system store_conditional
This code contained typos, as it had never been compiled.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 73c19d9..851a045 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -326,7 +326,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
#if defined(CONFIG_USER_ONLY)
addr = cpu_lock_st_addr;
#else
- addr = tcg_local_new();
+ addr = tcg_temp_local_new();
#endif
if (rb != 31) {
@@ -349,7 +349,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
lab_fail = gen_new_label();
lab_done = gen_new_label();
- tcg_gen_brcond(TCG_COND_NE, addr, cpu_lock_addr, lab_fail);
+ tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_lock_addr, lab_fail);
val = tcg_temp_new();
if (quad) {
@@ -357,7 +357,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
} else {
tcg_gen_qemu_ld32s(val, addr, ctx->mem_idx);
}
- tcg_gen_brcond(TCG_COND_NE, val, cpu_lock_value, lab_fail);
+ tcg_gen_brcond_i64(TCG_COND_NE, val, cpu_lock_value, lab_fail);
if (quad) {
tcg_gen_qemu_st64(cpu_ir[ra], addr, ctx->mem_idx);
commit 2374e73edafff0586cbfb67c333c5a7588f81fd5
Author: Richard Henderson <rth at twiddle.net>
Date: Fri May 20 13:04:35 2011 -0700
target-alpha: Fix translation of PALmode memory insns.
All of the "raw" memory accesses should be "phys" instead. Fix
some confusion about argument ordering of the store routines.
Fix the implementation of store-conditional.
Delete the "alt-mode" helpers. Because we only implement two
mmu modes, let /a imply user-mode unconditionally.
Leave some combinations of virt access without permission
checks as unimplemented. There are too many hoops through
which to jump, and these insns will not be needed in the
emulation palcode.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index ccf6a2a..f4f693a 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -104,23 +104,15 @@ DEF_HELPER_0(hw_rei, void)
DEF_HELPER_1(hw_ret, void, i64)
DEF_HELPER_2(mfpr, i64, int, i64)
DEF_HELPER_2(mtpr, void, int, i64)
-DEF_HELPER_0(set_alt_mode, void)
-DEF_HELPER_0(restore_mode, void)
-
-DEF_HELPER_1(ld_virt_to_phys, i64, i64)
-DEF_HELPER_1(st_virt_to_phys, i64, i64)
-DEF_HELPER_2(ldl_raw, void, i64, i64)
-DEF_HELPER_2(ldq_raw, void, i64, i64)
-DEF_HELPER_2(ldl_l_raw, void, i64, i64)
-DEF_HELPER_2(ldq_l_raw, void, i64, i64)
-DEF_HELPER_2(ldl_kernel, void, i64, i64)
-DEF_HELPER_2(ldq_kernel, void, i64, i64)
-DEF_HELPER_2(ldl_data, void, i64, i64)
-DEF_HELPER_2(ldq_data, void, i64, i64)
-DEF_HELPER_2(stl_raw, void, i64, i64)
-DEF_HELPER_2(stq_raw, void, i64, i64)
-DEF_HELPER_2(stl_c_raw, i64, i64, i64)
-DEF_HELPER_2(stq_c_raw, i64, i64, i64)
+
+DEF_HELPER_1(ldl_phys, i64, i64)
+DEF_HELPER_1(ldq_phys, i64, i64)
+DEF_HELPER_1(ldl_l_phys, i64, i64)
+DEF_HELPER_1(ldq_l_phys, i64, i64)
+DEF_HELPER_2(stl_phys, void, i64, i64)
+DEF_HELPER_2(stq_phys, void, i64, i64)
+DEF_HELPER_2(stl_c_phys, i64, i64, i64)
+DEF_HELPER_2(stq_c_phys, i64, i64, i64)
#endif
#include "def-helper.h"
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 4ccb10b..a90c7a6 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -1188,150 +1188,71 @@ void helper_mtpr (int iprn, uint64_t val)
{
cpu_alpha_mtpr(env, iprn, val, NULL);
}
-
-void helper_set_alt_mode (void)
-{
- env->saved_mode = env->ps & 0xC;
- env->ps = (env->ps & ~0xC) | (env->ipr[IPR_ALT_MODE] & 0xC);
-}
-
-void helper_restore_mode (void)
-{
- env->ps = (env->ps & ~0xC) | env->saved_mode;
-}
-
#endif
/*****************************************************************************/
/* Softmmu support */
#if !defined (CONFIG_USER_ONLY)
-
-/* XXX: the two following helpers are pure hacks.
- * Hopefully, we emulate the PALcode, then we should never see
- * HW_LD / HW_ST instructions.
- */
-uint64_t helper_ld_virt_to_phys (uint64_t virtaddr)
-{
- uint64_t tlb_addr, physaddr;
- int index, mmu_idx;
- void *retaddr;
-
- mmu_idx = cpu_mmu_index(env);
- index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- redo:
- tlb_addr = env->tlb_table[mmu_idx][index].addr_read;
- if ((virtaddr & TARGET_PAGE_MASK) ==
- (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
- physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend;
- } else {
- /* the page is not in the TLB : fill it */
- retaddr = GETPC();
- tlb_fill(virtaddr, 0, mmu_idx, retaddr);
- goto redo;
- }
- return physaddr;
-}
-
-uint64_t helper_st_virt_to_phys (uint64_t virtaddr)
-{
- uint64_t tlb_addr, physaddr;
- int index, mmu_idx;
- void *retaddr;
-
- mmu_idx = cpu_mmu_index(env);
- index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- redo:
- tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
- if ((virtaddr & TARGET_PAGE_MASK) ==
- (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
- physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend;
- } else {
- /* the page is not in the TLB : fill it */
- retaddr = GETPC();
- tlb_fill(virtaddr, 1, mmu_idx, retaddr);
- goto redo;
- }
- return physaddr;
-}
-
-void helper_ldl_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_ldl_phys(uint64_t p)
{
- ldl_raw(t1, t0);
+ return (int32_t)ldl_phys(p);
}
-void helper_ldq_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_ldq_phys(uint64_t p)
{
- ldq_raw(t1, t0);
+ return ldq_phys(p);
}
-void helper_ldl_l_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_ldl_l_phys(uint64_t p)
{
- env->lock = t1;
- ldl_raw(t1, t0);
+ env->lock_addr = p;
+ return env->lock_value = (int32_t)ldl_phys(p);
}
-void helper_ldq_l_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_ldq_l_phys(uint64_t p)
{
- env->lock = t1;
- ldl_raw(t1, t0);
+ env->lock_addr = p;
+ return env->lock_value = ldl_phys(p);
}
-void helper_ldl_kernel(uint64_t t0, uint64_t t1)
+void helper_stl_phys(uint64_t p, uint64_t v)
{
- ldl_kernel(t1, t0);
+ stl_phys(p, v);
}
-void helper_ldq_kernel(uint64_t t0, uint64_t t1)
+void helper_stq_phys(uint64_t p, uint64_t v)
{
- ldq_kernel(t1, t0);
+ stq_phys(p, v);
}
-void helper_ldl_data(uint64_t t0, uint64_t t1)
+uint64_t helper_stl_c_phys(uint64_t p, uint64_t v)
{
- ldl_data(t1, t0);
-}
+ uint64_t ret = 0;
-void helper_ldq_data(uint64_t t0, uint64_t t1)
-{
- ldq_data(t1, t0);
-}
-
-void helper_stl_raw(uint64_t t0, uint64_t t1)
-{
- stl_raw(t1, t0);
-}
-
-void helper_stq_raw(uint64_t t0, uint64_t t1)
-{
- stq_raw(t1, t0);
-}
-
-uint64_t helper_stl_c_raw(uint64_t t0, uint64_t t1)
-{
- uint64_t ret;
-
- if (t1 == env->lock) {
- stl_raw(t1, t0);
- ret = 0;
- } else
- ret = 1;
-
- env->lock = 1;
+ if (p == env->lock_addr) {
+ int32_t old = ldl_phys(p);
+ if (old == (int32_t)env->lock_value) {
+ stl_phys(p, v);
+ ret = 1;
+ }
+ }
+ env->lock_addr = -1;
return ret;
}
-uint64_t helper_stq_c_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_stq_c_phys(uint64_t p, uint64_t v)
{
- uint64_t ret;
+ uint64_t ret = 0;
- if (t1 == env->lock) {
- stq_raw(t1, t0);
- ret = 0;
- } else
- ret = 1;
-
- env->lock = 1;
+ if (p == env->lock_addr) {
+ uint64_t old = ldq_phys(p);
+ if (old == env->lock_value) {
+ stq_phys(p, v);
+ ret = 1;
+ }
+ }
+ env->lock_addr = -1;
return ret;
}
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index c9fd16f..73c19d9 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -2616,27 +2616,26 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
switch ((insn >> 12) & 0xF) {
case 0x0:
/* Longword physical access (hw_ldl/p) */
- gen_helper_ldl_raw(cpu_ir[ra], addr);
+ gen_helper_ldl_phys(cpu_ir[ra], addr);
break;
case 0x1:
/* Quadword physical access (hw_ldq/p) */
- gen_helper_ldq_raw(cpu_ir[ra], addr);
+ gen_helper_ldq_phys(cpu_ir[ra], addr);
break;
case 0x2:
/* Longword physical access with lock (hw_ldl_l/p) */
- gen_helper_ldl_l_raw(cpu_ir[ra], addr);
+ gen_helper_ldl_l_phys(cpu_ir[ra], addr);
break;
case 0x3:
/* Quadword physical access with lock (hw_ldq_l/p) */
- gen_helper_ldq_l_raw(cpu_ir[ra], addr);
+ gen_helper_ldq_l_phys(cpu_ir[ra], addr);
break;
case 0x4:
/* Longword virtual PTE fetch (hw_ldl/v) */
- tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
- break;
+ goto invalid_opc;
case 0x5:
/* Quadword virtual PTE fetch (hw_ldq/v) */
- tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0);
+ goto invalid_opc;
break;
case 0x6:
/* Incpu_ir[ra]id */
@@ -2646,14 +2645,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
goto invalid_opc;
case 0x8:
/* Longword virtual access (hw_ldl) */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldl_raw(cpu_ir[ra], addr);
- break;
+ goto invalid_opc;
case 0x9:
/* Quadword virtual access (hw_ldq) */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldq_raw(cpu_ir[ra], addr);
- break;
+ goto invalid_opc;
case 0xA:
/* Longword virtual access with protection check (hw_ldl/w) */
tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
@@ -2664,33 +2659,19 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0xC:
/* Longword virtual access with alt access mode (hw_ldl/a)*/
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldl_raw(cpu_ir[ra], addr);
- gen_helper_restore_mode();
- break;
+ goto invalid_opc;
case 0xD:
/* Quadword virtual access with alt access mode (hw_ldq/a) */
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldq_raw(cpu_ir[ra], addr);
- gen_helper_restore_mode();
- break;
+ goto invalid_opc;
case 0xE:
/* Longword virtual access with alternate access mode and
- * protection checks (hw_ldl/wa)
- */
- gen_helper_set_alt_mode();
- gen_helper_ldl_data(cpu_ir[ra], addr);
- gen_helper_restore_mode();
+ protection checks (hw_ldl/wa) */
+ tcg_gen_qemu_ld32s(cpu_ir[ra], addr, MMU_USER_IDX);
break;
case 0xF:
/* Quadword virtual access with alternate access mode and
- * protection checks (hw_ldq/wa)
- */
- gen_helper_set_alt_mode();
- gen_helper_ldq_data(cpu_ir[ra], addr);
- gen_helper_restore_mode();
+ protection checks (hw_ldq/wa) */
+ tcg_gen_qemu_ld64(cpu_ir[ra], addr, MMU_USER_IDX);
break;
}
tcg_temp_free(addr);
@@ -2940,30 +2921,26 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
switch ((insn >> 12) & 0xF) {
case 0x0:
/* Longword physical access */
- gen_helper_stl_raw(val, addr);
+ gen_helper_stl_phys(addr, val);
break;
case 0x1:
/* Quadword physical access */
- gen_helper_stq_raw(val, addr);
+ gen_helper_stq_phys(addr, val);
break;
case 0x2:
/* Longword physical access with lock */
- gen_helper_stl_c_raw(val, val, addr);
+ gen_helper_stl_c_phys(val, addr, val);
break;
case 0x3:
/* Quadword physical access with lock */
- gen_helper_stq_c_raw(val, val, addr);
+ gen_helper_stq_c_phys(val, addr, val);
break;
case 0x4:
/* Longword virtual access */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stl_raw(val, addr);
- break;
+ goto invalid_opc;
case 0x5:
/* Quadword virtual access */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stq_raw(val, addr);
- break;
+ goto invalid_opc;
case 0x6:
/* Invalid */
goto invalid_opc;
@@ -2984,18 +2961,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
goto invalid_opc;
case 0xC:
/* Longword virtual access with alternate access mode */
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stl_raw(val, addr);
- gen_helper_restore_mode();
- break;
+ goto invalid_opc;
case 0xD:
/* Quadword virtual access with alternate access mode */
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stl_raw(val, addr);
- gen_helper_restore_mode();
- break;
+ goto invalid_opc;
case 0xE:
/* Invalid */
goto invalid_opc;
commit 352e48b0f492359559cb46f8b3222bac9c461ac4
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Apr 18 12:17:02 2011 -0700
target-alpha: Remove partial support for palcode emulation.
This code does not work, and will be replaced by a bios image.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/Makefile.target b/Makefile.target
index 602d50d..d2c988f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -376,7 +376,7 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
-obj-alpha-y = alpha_palcode.o
+obj-alpha-y =
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c
deleted file mode 100644
index 033b542..0000000
--- a/hw/alpha_palcode.c
+++ /dev/null
@@ -1,1048 +0,0 @@
-/*
- * Alpha emulation - PALcode emulation for qemu.
- *
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-
-/* Shared handlers */
-static void pal_reset (CPUState *env);
-/* Console handlers */
-static void pal_console_call (CPUState *env, uint32_t palcode);
-/* OpenVMS handlers */
-static void pal_openvms_call (CPUState *env, uint32_t palcode);
-/* UNIX / Linux handlers */
-static void pal_unix_call (CPUState *env, uint32_t palcode);
-
-pal_handler_t pal_handlers[] = {
- /* Console handler */
- {
- .reset = &pal_reset,
- .call_pal = &pal_console_call,
- },
- /* OpenVMS handler */
- {
- .reset = &pal_reset,
- .call_pal = &pal_openvms_call,
- },
- /* UNIX / Linux handler */
- {
- .reset = &pal_reset,
- .call_pal = &pal_unix_call,
- },
-};
-
-#if 0
-/* One must explicitly check that the TB is valid and the FOE bit is reset */
-static void update_itb (void)
-{
- /* This writes into a temp register, not the actual one */
- mtpr(TB_TAG);
- mtpr(TB_CTL);
- /* This commits the TB update */
- mtpr(ITB_PTE);
-}
-
-static void update_dtb (void);
-{
- mtpr(TB_CTL);
- /* This write into a temp register, not the actual one */
- mtpr(TB_TAG);
- /* This commits the TB update */
- mtpr(DTB_PTE);
-}
-#endif
-
-static void pal_reset (CPUState *env)
-{
-}
-
-static void do_swappal (CPUState *env, uint64_t palid)
-{
- pal_handler_t *pal_handler;
-
- switch (palid) {
- case 0 ... 2:
- pal_handler = &pal_handlers[palid];
- env->pal_handler = pal_handler;
- env->ipr[IPR_PAL_BASE] = -1ULL;
- (*pal_handler->reset)(env);
- break;
- case 3 ... 255:
- /* Unknown identifier */
- env->ir[0] = 1;
- return;
- default:
- /* We were given the entry point address */
- env->pal_handler = NULL;
- env->ipr[IPR_PAL_BASE] = palid;
- env->pc = env->ipr[IPR_PAL_BASE];
- cpu_loop_exit();
- }
-}
-
-static void pal_console_call (CPUState *env, uint32_t palcode)
-{
- uint64_t palid;
-
- if (palcode < 0x00000080) {
- /* Privileged palcodes */
- if (!(env->ps >> 3)) {
- /* TODO: generate privilege exception */
- }
- }
- switch (palcode) {
- case 0x00000000:
- /* HALT */
- /* REQUIRED */
- break;
- case 0x00000001:
- /* CFLUSH */
- break;
- case 0x00000002:
- /* DRAINA */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000009:
- /* CSERVE */
- /* REQUIRED */
- break;
- case 0x0000000A:
- /* SWPPAL */
- /* REQUIRED */
- palid = env->ir[16];
- do_swappal(env, palid);
- break;
- case 0x00000080:
- /* BPT */
- /* REQUIRED */
- break;
- case 0x00000081:
- /* BUGCHK */
- /* REQUIRED */
- break;
- case 0x00000086:
- /* IMB */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x0000009E:
- /* RDUNIQUE */
- /* REQUIRED */
- break;
- case 0x0000009F:
- /* WRUNIQUE */
- /* REQUIRED */
- break;
- case 0x000000AA:
- /* GENTRAP */
- /* REQUIRED */
- break;
- default:
- break;
- }
-}
-
-static void pal_openvms_call (CPUState *env, uint32_t palcode)
-{
- uint64_t palid, val, oldval;
-
- if (palcode < 0x00000080) {
- /* Privileged palcodes */
- if (!(env->ps >> 3)) {
- /* TODO: generate privilege exception */
- }
- }
- switch (palcode) {
- case 0x00000000:
- /* HALT */
- /* REQUIRED */
- break;
- case 0x00000001:
- /* CFLUSH */
- break;
- case 0x00000002:
- /* DRAINA */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000003:
- /* LDQP */
- break;
- case 0x00000004:
- /* STQP */
- break;
- case 0x00000005:
- /* SWPCTX */
- break;
- case 0x00000006:
- /* MFPR_ASN */
- if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000007:
- /* MTPR_ASTEN */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000008:
- /* MTPR_ASTSR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000009:
- /* CSERVE */
- /* REQUIRED */
- break;
- case 0x0000000A:
- /* SWPPAL */
- /* REQUIRED */
- palid = env->ir[16];
- do_swappal(env, palid);
- break;
- case 0x0000000B:
- /* MFPR_FEN */
- if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000000C:
- /* MTPR_FEN */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000000D:
- /* MTPR_IPIR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000000E:
- /* MFPR_IPL */
- if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000000F:
- /* MTPR_IPL */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000010:
- /* MFPR_MCES */
- if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000011:
- /* MTPR_MCES */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000012:
- /* MFPR_PCBB */
- if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000013:
- /* MFPR_PRBR */
- if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000014:
- /* MTPR_PRBR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000015:
- /* MFPR_PTBR */
- if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000016:
- /* MFPR_SCBB */
- if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000017:
- /* MTPR_SCBB */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000018:
- /* MTPR_SIRR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000019:
- /* MFPR_SISR */
- if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000001A:
- /* MFPR_TBCHK */
- if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000001B:
- /* MTPR_TBIA */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000001C:
- /* MTPR_TBIAP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000001D:
- /* MTPR_TBIS */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000001E:
- /* MFPR_ESP */
- if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000001F:
- /* MTPR_ESP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000020:
- /* MFPR_SSP */
- if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000021:
- /* MTPR_SSP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000022:
- /* MFPR_USP */
- if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000023:
- /* MTPR_USP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000024:
- /* MTPR_TBISD */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000025:
- /* MTPR_TBISI */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000026:
- /* MFPR_ASTEN */
- if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000027:
- /* MFPR_ASTSR */
- if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000029:
- /* MFPR_VPTB */
- if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000002A:
- /* MTPR_VPTB */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000002B:
- /* MTPR_PERFMON */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000002E:
- /* MTPR_DATFX */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000003E:
- /* WTINT */
- break;
- case 0x0000003F:
- /* MFPR_WHAMI */
- if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000080:
- /* BPT */
- /* REQUIRED */
- break;
- case 0x00000081:
- /* BUGCHK */
- /* REQUIRED */
- break;
- case 0x00000082:
- /* CHME */
- break;
- case 0x00000083:
- /* CHMK */
- break;
- case 0x00000084:
- /* CHMS */
- break;
- case 0x00000085:
- /* CHMU */
- break;
- case 0x00000086:
- /* IMB */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000087:
- /* INSQHIL */
- break;
- case 0x00000088:
- /* INSQTIL */
- break;
- case 0x00000089:
- /* INSQHIQ */
- break;
- case 0x0000008A:
- /* INSQTIQ */
- break;
- case 0x0000008B:
- /* INSQUEL */
- break;
- case 0x0000008C:
- /* INSQUEQ */
- break;
- case 0x0000008D:
- /* INSQUEL/D */
- break;
- case 0x0000008E:
- /* INSQUEQ/D */
- break;
- case 0x0000008F:
- /* PROBER */
- break;
- case 0x00000090:
- /* PROBEW */
- break;
- case 0x00000091:
- /* RD_PS */
- break;
- case 0x00000092:
- /* REI */
- break;
- case 0x00000093:
- /* REMQHIL */
- break;
- case 0x00000094:
- /* REMQTIL */
- break;
- case 0x00000095:
- /* REMQHIQ */
- break;
- case 0x00000096:
- /* REMQTIQ */
- break;
- case 0x00000097:
- /* REMQUEL */
- break;
- case 0x00000098:
- /* REMQUEQ */
- break;
- case 0x00000099:
- /* REMQUEL/D */
- break;
- case 0x0000009A:
- /* REMQUEQ/D */
- break;
- case 0x0000009B:
- /* SWASTEN */
- break;
- case 0x0000009C:
- /* WR_PS_SW */
- break;
- case 0x0000009D:
- /* RSCC */
- break;
- case 0x0000009E:
- /* READ_UNQ */
- /* REQUIRED */
- break;
- case 0x0000009F:
- /* WRITE_UNQ */
- /* REQUIRED */
- break;
- case 0x000000A0:
- /* AMOVRR */
- break;
- case 0x000000A1:
- /* AMOVRM */
- break;
- case 0x000000A2:
- /* INSQHILR */
- break;
- case 0x000000A3:
- /* INSQTILR */
- break;
- case 0x000000A4:
- /* INSQHIQR */
- break;
- case 0x000000A5:
- /* INSQTIQR */
- break;
- case 0x000000A6:
- /* REMQHILR */
- break;
- case 0x000000A7:
- /* REMQTILR */
- break;
- case 0x000000A8:
- /* REMQHIQR */
- break;
- case 0x000000A9:
- /* REMQTIQR */
- break;
- case 0x000000AA:
- /* GENTRAP */
- /* REQUIRED */
- break;
- case 0x000000AE:
- /* CLRFEN */
- break;
- default:
- break;
- }
-}
-
-static void pal_unix_call (CPUState *env, uint32_t palcode)
-{
- uint64_t palid, val, oldval;
-
- if (palcode < 0x00000080) {
- /* Privileged palcodes */
- if (!(env->ps >> 3)) {
- /* TODO: generate privilege exception */
- }
- }
- switch (palcode) {
- case 0x00000000:
- /* HALT */
- /* REQUIRED */
- break;
- case 0x00000001:
- /* CFLUSH */
- break;
- case 0x00000002:
- /* DRAINA */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000009:
- /* CSERVE */
- /* REQUIRED */
- break;
- case 0x0000000A:
- /* SWPPAL */
- /* REQUIRED */
- palid = env->ir[16];
- do_swappal(env, palid);
- break;
- case 0x0000000D:
- /* WRIPIR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000010:
- /* RDMCES */
- if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000011:
- /* WRMCES */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000002B:
- /* WRFEN */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000002D:
- /* WRVPTPTR */
- break;
- case 0x00000030:
- /* SWPCTX */
- break;
- case 0x00000031:
- /* WRVAL */
- break;
- case 0x00000032:
- /* RDVAL */
- break;
- case 0x00000033:
- /* TBI */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000034:
- /* WRENT */
- break;
- case 0x00000035:
- /* SWPIPL */
- break;
- case 0x00000036:
- /* RDPS */
- break;
- case 0x00000037:
- /* WRKGP */
- break;
- case 0x00000038:
- /* WRUSP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000039:
- /* WRPERFMON */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000003A:
- /* RDUSP */
- if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000003C:
- /* WHAMI */
- if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000003D:
- /* RETSYS */
- break;
- case 0x0000003E:
- /* WTINT */
- break;
- case 0x0000003F:
- /* RTI */
- if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000080:
- /* BPT */
- /* REQUIRED */
- break;
- case 0x00000081:
- /* BUGCHK */
- /* REQUIRED */
- break;
- case 0x00000083:
- /* CALLSYS */
- break;
- case 0x00000086:
- /* IMB */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000092:
- /* URTI */
- break;
- case 0x0000009E:
- /* RDUNIQUE */
- /* REQUIRED */
- break;
- case 0x0000009F:
- /* WRUNIQUE */
- /* REQUIRED */
- break;
- case 0x000000AA:
- /* GENTRAP */
- /* REQUIRED */
- break;
- case 0x000000AE:
- /* CLRFEN */
- break;
- default:
- break;
- }
-}
-
-void call_pal (CPUState *env)
-{
- pal_handler_t *pal_handler = env->pal_handler;
-
- switch (env->exception_index) {
- case EXCP_RESET:
- (*pal_handler->reset)(env);
- break;
- case EXCP_MCHK:
- (*pal_handler->machine_check)(env);
- break;
- case EXCP_ARITH:
- (*pal_handler->arithmetic)(env);
- break;
- case EXCP_INTERRUPT:
- (*pal_handler->interrupt)(env);
- break;
- case EXCP_DFAULT:
- (*pal_handler->dfault)(env);
- break;
- case EXCP_DTB_MISS_PAL:
- (*pal_handler->dtb_miss_pal)(env);
- break;
- case EXCP_DTB_MISS_NATIVE:
- (*pal_handler->dtb_miss_native)(env);
- break;
- case EXCP_UNALIGN:
- (*pal_handler->unalign)(env);
- break;
- case EXCP_ITB_MISS:
- (*pal_handler->itb_miss)(env);
- break;
- case EXCP_ITB_ACV:
- (*pal_handler->itb_acv)(env);
- break;
- case EXCP_OPCDEC:
- (*pal_handler->opcdec)(env);
- break;
- case EXCP_FEN:
- (*pal_handler->fen)(env);
- break;
- default:
- if (env->exception_index >= EXCP_CALL_PAL &&
- env->exception_index < EXCP_CALL_PALP) {
- /* Unprivileged PAL call */
- (*pal_handler->call_pal)
- (env, (env->exception_index - EXCP_CALL_PAL) >> 6);
- } else if (env->exception_index >= EXCP_CALL_PALP &&
- env->exception_index < EXCP_CALL_PALE) {
- /* Privileged PAL call */
- (*pal_handler->call_pal)
- (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80);
- } else {
- /* Should never happen */
- }
- break;
- }
- env->ipr[IPR_EXC_ADDR] &= ~1;
-}
-
-void pal_init (CPUState *env)
-{
- do_swappal(env, 0);
-}
-
-#if 0
-static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
-{
- uint64_t virbnd, ptbr;
-
- if ((env->features & FEATURE_VIRBND)) {
- cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd);
- if (vaddr >= virbnd)
- cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr);
- else
- cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
- } else {
- cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
- }
-
- return ptbr;
-}
-
-static int get_page_bits (CPUState *env)
-{
- /* XXX */
- return 13;
-}
-
-static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp,
- uint64_t ptebase, int page_bits, uint64_t level,
- int mmu_idx, int rw)
-{
- uint64_t pteaddr, pte, pfn;
- uint8_t gh;
- int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user;
-
- /* XXX: TOFIX */
- is_user = mmu_idx == MMU_USER_IDX;
- pteaddr = (ptebase << page_bits) + (8 * level);
- pte = ldq_raw(pteaddr);
- /* Decode all interresting PTE fields */
- pfn = pte >> 32;
- uwe = (pte >> 13) & 1;
- kwe = (pte >> 12) & 1;
- ure = (pte >> 9) & 1;
- kre = (pte >> 8) & 1;
- gh = (pte >> 5) & 3;
- foE = (pte >> 3) & 1;
- foW = (pte >> 2) & 1;
- foR = (pte >> 1) & 1;
- v = pte & 1;
- ret = 0;
- if (!v)
- ret = 0x1;
- /* Check access rights */
- ar = 0;
- if (is_user) {
- if (ure)
- ar |= PAGE_READ;
- if (uwe)
- ar |= PAGE_WRITE;
- if (rw == 1 && !uwe)
- ret |= 0x2;
- if (rw != 1 && !ure)
- ret |= 0x2;
- } else {
- if (kre)
- ar |= PAGE_READ;
- if (kwe)
- ar |= PAGE_WRITE;
- if (rw == 1 && !kwe)
- ret |= 0x2;
- if (rw != 1 && !kre)
- ret |= 0x2;
- }
- if (rw == 0 && foR)
- ret |= 0x4;
- if (rw == 2 && foE)
- ret |= 0x8;
- if (rw == 1 && foW)
- ret |= 0xC;
- *pfnp = pfn;
- if (zbitsp != NULL)
- *zbitsp = page_bits + (3 * gh);
- if (protp != NULL)
- *protp = ar;
-
- return ret;
-}
-
-static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
- uint64_t ptebase, int page_bits,
- uint64_t vaddr, int mmu_idx, int rw)
-{
- uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
- int lvl_bits, ret;
-
- page_mask = (1ULL << page_bits) - 1ULL;
- lvl_bits = page_bits - 3;
- lvl_mask = (1ULL << lvl_bits) - 1ULL;
- level3 = (vaddr >> page_bits) & lvl_mask;
- level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
- level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
- /* Level 1 PTE */
- ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
- switch (ret) {
- case 3:
- /* Access violation */
- return 2;
- case 2:
- /* translation not valid */
- return 1;
- default:
- /* OK */
- break;
- }
- /* Level 2 PTE */
- ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
- switch (ret) {
- case 3:
- /* Access violation */
- return 2;
- case 2:
- /* translation not valid */
- return 1;
- default:
- /* OK */
- break;
- }
- /* Level 3 PTE */
- ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw);
- if (ret & 0x1) {
- /* Translation not valid */
- ret = 1;
- } else if (ret & 2) {
- /* Access violation */
- ret = 2;
- } else {
- switch (ret & 0xC) {
- case 0:
- /* OK */
- ret = 0;
- break;
- case 0x4:
- /* Fault on read */
- ret = 3;
- break;
- case 0x8:
- /* Fault on execute */
- ret = 4;
- break;
- case 0xC:
- /* Fault on write */
- ret = 5;
- break;
- }
- }
- *paddr = (pfn << page_bits) | (vaddr & page_mask);
-
- return 0;
-}
-
-static int virtual_to_physical (CPUState *env, uint64_t *physp,
- int *zbitsp, int *protp,
- uint64_t virtual, int mmu_idx, int rw)
-{
- uint64_t sva, ptebase;
- int seg, page_bits, ret;
-
- sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
- if (sva != virtual)
- seg = -1;
- else
- seg = sva >> (VA_BITS - 2);
- virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
- ptebase = get_ptebase(env, virtual);
- page_bits = get_page_bits(env);
- ret = 0;
- switch (seg) {
- case 0:
- /* seg1: 3 levels of PTE */
- ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
- virtual, mmu_idx, rw);
- break;
- case 1:
- /* seg1: 2 levels of PTE */
- ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
- virtual, mmu_idx, rw);
- break;
- case 2:
- /* kernel segment */
- if (mmu_idx != 0) {
- ret = 2;
- } else {
- *physp = virtual;
- }
- break;
- case 3:
- /* seg1: TB mapped */
- ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
- virtual, mmu_idx, rw);
- break;
- default:
- ret = 1;
- break;
- }
-
- return ret;
-}
-
-/* XXX: code provision */
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
- int mmu_idx, int is_softmmu)
-{
- uint64_t physical, page_size, end;
- int prot, zbits, ret;
-
- ret = virtual_to_physical(env, &physical, &zbits, &prot,
- address, mmu_idx, rw);
-
- switch (ret) {
- case 0:
- /* No fault */
- page_size = 1ULL << zbits;
- address &= ~(page_size - 1);
- /* FIXME: page_size should probably be passed to tlb_set_page,
- and this loop removed. */
- for (end = physical + page_size; physical < end; physical += 0x1000) {
- tlb_set_page(env, address, physical, prot, mmu_idx,
- TARGET_PAGE_SIZE);
- address += 0x1000;
- }
- ret = 0;
- break;
-#if 0
- case 1:
- env->exception_index = EXCP_DFAULT;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- break;
- case 2:
- env->exception_index = EXCP_ACCESS_VIOLATION;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- break;
- case 3:
- env->exception_index = EXCP_FAULT_ON_READ;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- break;
- case 4:
- env->exception_index = EXCP_FAULT_ON_EXECUTE;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- case 5:
- env->exception_index = EXCP_FAULT_ON_WRITE;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
-#endif
- default:
- /* Should never happen */
- env->exception_index = EXCP_MCHK;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- break;
- }
-
- return ret;
-}
-#endif
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 686fb4a..0daa556 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -319,36 +319,6 @@ enum {
typedef struct CPUAlphaState CPUAlphaState;
-typedef struct pal_handler_t pal_handler_t;
-struct pal_handler_t {
- /* Reset */
- void (*reset)(CPUAlphaState *env);
- /* Uncorrectable hardware error */
- void (*machine_check)(CPUAlphaState *env);
- /* Arithmetic exception */
- void (*arithmetic)(CPUAlphaState *env);
- /* Interrupt / correctable hardware error */
- void (*interrupt)(CPUAlphaState *env);
- /* Data fault */
- void (*dfault)(CPUAlphaState *env);
- /* DTB miss pal */
- void (*dtb_miss_pal)(CPUAlphaState *env);
- /* DTB miss native */
- void (*dtb_miss_native)(CPUAlphaState *env);
- /* Unaligned access */
- void (*unalign)(CPUAlphaState *env);
- /* ITB miss */
- void (*itb_miss)(CPUAlphaState *env);
- /* Instruction stream access violation */
- void (*itb_acv)(CPUAlphaState *env);
- /* Reserved or privileged opcode */
- void (*opcdec)(CPUAlphaState *env);
- /* Floating point exception */
- void (*fen)(CPUAlphaState *env);
- /* Call pal instruction */
- void (*call_pal)(CPUAlphaState *env, uint32_t palcode);
-};
-
#define NB_MMU_MODES 4
struct CPUAlphaState {
@@ -393,7 +363,6 @@ struct CPUAlphaState {
uint32_t features;
uint32_t amask;
int implver;
- pal_handler_t *pal_handler;
};
#define cpu_init cpu_alpha_init
@@ -506,10 +475,6 @@ uint64_t cpu_alpha_load_fpcr (CPUState *env);
void cpu_alpha_store_fpcr (CPUState *env, uint64_t val);
int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp);
int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp);
-#if !defined (CONFIG_USER_ONLY)
-void pal_init (CPUState *env);
-void call_pal (CPUState *env);
-#endif
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 3ba4478..f7cf4ee 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -528,7 +528,7 @@ void do_interrupt (CPUState *env)
env->pc = env->ipr[IPR_PAL_BASE] + excp;
} else {
/* We use emulated PALcode */
- call_pal(env);
+ abort();
/* Emulate REI */
env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 194a286..c9fd16f 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -3335,8 +3335,6 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
env->ps |= 1 << 3;
cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
| FPCR_UNFD | FPCR_INED | FPCR_DNOD));
-#else
- pal_init(env);
#endif
env->lock_addr = -1;
commit bf1b03fe182eb5a0df9ec6fc4121d8a36e1fdb97
Author: Richard Henderson <rth at twiddle.net>
Date: Mon Apr 25 12:52:57 2011 -0700
target-alpha: Single-step properly across branches.
We were failing to generate EXC_DEBUG in the EXIT_PC_UPDATED path.
This caused us not to stop at the instruction after a branch, but
on the instruction afterward.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 456ba51..194a286 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -147,17 +147,21 @@ static void alpha_translate_init(void)
done_init = 1;
}
-static ExitStatus gen_excp(DisasContext *ctx, int exception, int error_code)
+static void gen_excp_1(int exception, int error_code)
{
TCGv_i32 tmp1, tmp2;
- tcg_gen_movi_i64(cpu_pc, ctx->pc);
tmp1 = tcg_const_i32(exception);
tmp2 = tcg_const_i32(error_code);
gen_helper_excp(tmp1, tmp2);
tcg_temp_free_i32(tmp2);
tcg_temp_free_i32(tmp1);
+}
+static ExitStatus gen_excp(DisasContext *ctx, int exception, int error_code)
+{
+ tcg_gen_movi_i64(cpu_pc, ctx->pc);
+ gen_excp_1(exception, error_code);
return EXIT_NORETURN;
}
@@ -3211,18 +3215,15 @@ static inline void gen_intermediate_code_internal(CPUState *env,
ctx.pc += 4;
ret = translate_one(ctxp, insn);
- if (ret == NO_EXIT) {
- /* If we reach a page boundary, are single stepping,
- or exhaust instruction count, stop generation. */
- if (env->singlestep_enabled) {
- gen_excp(&ctx, EXCP_DEBUG, 0);
- ret = EXIT_PC_UPDATED;
- } else if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0
- || gen_opc_ptr >= gen_opc_end
- || num_insns >= max_insns
- || singlestep) {
- ret = EXIT_PC_STALE;
- }
+ /* If we reach a page boundary, are single stepping,
+ or exhaust instruction count, stop generation. */
+ if (ret == NO_EXIT
+ && ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0
+ || gen_opc_ptr >= gen_opc_end
+ || num_insns >= max_insns
+ || singlestep
+ || env->singlestep_enabled)) {
+ ret = EXIT_PC_STALE;
}
} while (ret == NO_EXIT);
@@ -3238,7 +3239,11 @@ static inline void gen_intermediate_code_internal(CPUState *env,
tcg_gen_movi_i64(cpu_pc, ctx.pc);
/* FALLTHRU */
case EXIT_PC_UPDATED:
- tcg_gen_exit_tb(0);
+ if (env->singlestep_enabled) {
+ gen_excp_1(EXCP_DEBUG, 0);
+ } else {
+ tcg_gen_exit_tb(0);
+ }
break;
default:
abort();
commit b9bec751c8c8b08d8055da32306eb105db03031b
Author: Richard Henderson <rth at twiddle.net>
Date: Sun Apr 10 10:31:20 2011 -0700
target-alpha: Disassemble EV6 PALcode instructions.
The QEMU emulation PALcode will use EV6 PALcode insns regardless
of the "real" cpu instruction set being emulated.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/alpha-dis.c b/alpha-dis.c
index 8a2411e..ae331b3 100644
--- a/alpha-dis.c
+++ b/alpha-dis.c
@@ -238,10 +238,6 @@ extern const unsigned alpha_num_operands;
#define AXP_REG_SP 30
#define AXP_REG_ZERO 31
-#define bfd_mach_alpha_ev4 0x10
-#define bfd_mach_alpha_ev5 0x20
-#define bfd_mach_alpha_ev6 0x30
-
enum bfd_reloc_code_real {
BFD_RELOC_23_PCREL_S2,
BFD_RELOC_ALPHA_HINT
diff --git a/dis-asm.h b/dis-asm.h
index 296537a..5b07d7f 100644
--- a/dis-asm.h
+++ b/dis-asm.h
@@ -184,6 +184,9 @@ enum bfd_architecture
#define bfd_mach_sh5 0x50
bfd_arch_alpha, /* Dec Alpha */
#define bfd_mach_alpha 1
+#define bfd_mach_alpha_ev4 0x10
+#define bfd_mach_alpha_ev5 0x20
+#define bfd_mach_alpha_ev6 0x30
bfd_arch_arm, /* Advanced Risc Machines ARM */
#define bfd_mach_arm_unknown 0
#define bfd_mach_arm_2 1
diff --git a/disas.c b/disas.c
index 223606c..d208c52 100644
--- a/disas.c
+++ b/disas.c
@@ -205,7 +205,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
disasm_info.mach = bfd_mach_sh4;
print_insn = print_insn_sh;
#elif defined(TARGET_ALPHA)
- disasm_info.mach = bfd_mach_alpha;
+ disasm_info.mach = bfd_mach_alpha_ev6;
print_insn = print_insn_alpha;
#elif defined(TARGET_CRIS)
if (flags != 32) {
commit 8d6df264f130a21d08cde320a9f3bccbdd7b532c
Author: Richard Henderson <rth at twiddle.net>
Date: Fri May 20 12:23:18 2011 -0700
target-alpha: Claim ownership.
I've been maintaining this port for a while now.
Signed-off-by: Richard Henderson <rth at twiddle.net>
diff --git a/MAINTAINERS b/MAINTAINERS
index e6f853d..35d4496 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -56,8 +56,8 @@ M: Paul Brook <paul at codesourcery.com>
Guest CPU cores (TCG):
----------------------
Alpha
-M: qemu-devel at nongnu.org
-S: Orphan
+M: Richard Henderson <rth at twiddle.net>
+S: Maintained
F: target-alpha/
ARM
commit e13e973eedba0a52b4b8b079c4b85cdc68b7b4f0
Author: Markus Armbruster <armbru at redhat.com>
Date: Tue May 24 18:09:10 2011 +0200
usb-ccid: Plug memory leak on qdev exit()
ccid_initfn() allocates CCIDBus dynamically, but there is no exit
callback to free it.
Fix by getting rid of the allocation.
Signed-off-by: Markus Armbruster <armbru at redhat.com>
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index 5b6878b..59c6431 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -255,17 +255,18 @@ enum {
MIGRATION_MIGRATED,
};
-typedef struct CCIDBus CCIDBus;
-typedef struct USBCCIDState USBCCIDState;
+typedef struct CCIDBus {
+ BusState qbus;
+} CCIDBus;
#define MAX_PROTOCOL_SIZE 7
/*
* powered - defaults to true, changed by PowerOn/PowerOff messages
*/
-struct USBCCIDState {
+typedef struct USBCCIDState {
USBDevice dev;
- CCIDBus *bus;
+ CCIDBus bus;
CCIDCardState *card;
CCIDCardInfo *cardinfo; /* caching the info pointer */
BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
@@ -293,7 +294,7 @@ struct USBCCIDState {
uint8_t powered;
uint8_t notify_slot_change;
uint8_t debug;
-};
+} USBCCIDState;
/*
* CCID Spec chapter 4: CCID uses a standard device descriptor per Chapter 9,
@@ -1113,10 +1114,6 @@ static void ccid_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
}
}
-struct CCIDBus {
- BusState qbus;
-};
-
static struct BusInfo ccid_bus_info = {
.name = "ccid-bus",
.size = sizeof(CCIDBus),
@@ -1127,16 +1124,6 @@ static struct BusInfo ccid_bus_info = {
}
};
-static CCIDBus *ccid_bus_new(DeviceState *dev)
-{
- CCIDBus *bus;
-
- bus = FROM_QBUS(CCIDBus, qbus_create(&ccid_bus_info, dev, NULL));
- bus->qbus.allow_hotplug = 1;
-
- return bus;
-}
-
void ccid_card_send_apdu_to_guest(CCIDCardState *card,
uint8_t *apdu, uint32_t len)
{
@@ -1276,7 +1263,8 @@ static int ccid_initfn(USBDevice *dev)
{
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
- s->bus = ccid_bus_new(&dev->qdev);
+ qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
+ s->bus.qbus.allow_hotplug = 1;
s->card = NULL;
s->cardinfo = NULL;
s->migration_state = MIGRATION_NONE;
commit b7b8c61893f64416cf8b07a3192f25976d4a29eb
Author: Alon Levy <alevy at redhat.com>
Date: Sun May 15 11:51:28 2011 +0300
libcacard: add libcacard.la target
No flag to configure is required. Instead, added a libcacard.la target that
is not built by default, only when requested explicitly via:
mkdir build
cd build
../configure
make libcacard.la
make install-libcacard
Uses libtool to do actual linking of object files and shared library, and
installing. Tested only under linux, but supposed to work on other systems as
well.
If libtool isn't found you get a message complaining about that, only at build
time (since it is not a default target I did not add a message at configure
time).
New build artifacts:
.libs subdirectories (at <buildroot> and <buildroot>/libcacard)
*.lo files (at same locations as the respective o files)
Added %.lo : %.c rule that uses libtool.
Updated clean rule to clean up those artifacts.
Added specific rule to call dtrace with libtool wrapper (note that because of
a current upstream dtrace bug fixed by systemtap b1568fd85 commit the -fPIC flag
isn't actually passed on. still current dtrace+libtool produced object links fine).
If libtool is missing any of the following targets will complain and exit 1:
any subdir: *.lo
root and libcacard: libcacard.la, libcacard-instsall
Tested to link and load with all tracing backends.
diff --git a/Makefile b/Makefile
index 2b0438c..6d58710 100644
--- a/Makefile
+++ b/Makefile
@@ -119,6 +119,23 @@ version.o: $(SRC_PATH)/version.rc config-host.mak
version-obj-$(CONFIG_WIN32) += version.o
######################################################################
+# Support building shared library libcacard
+
+.PHONY: libcacard.la install-libcacard
+ifeq ($(LIBTOOL),)
+libcacard.la:
+ @echo "libtool is missing, please install and rerun configure"; exit 1
+
+install-libcacard:
+ @echo "libtool is missing, please install and rerun configure"; exit 1
+else
+libcacard.la: $(GENERATED_HEADERS) $(oslib-obj-y) qemu-malloc.o qemu-timer-common.o $(addsuffix .lo, $(basename $(trace-obj-y)))
+ $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" libcacard.la,)
+
+install-libcacard: libcacard.la
+ $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,)
+endif
+######################################################################
qemu-img.o: qemu-img-cmds.h
qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o: $(GENERATED_HEADERS)
@@ -149,7 +166,8 @@ 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 $(TOOLS) TAGS cscope.* *.pod *~ */*~
+ rm -f *.o *.d *.a *.lo $(TOOLS) 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 qemu-img-cmds.h
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
diff --git a/Makefile.objs b/Makefile.objs
index 90838f6..0b235db 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -345,6 +345,14 @@ trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events config-host.mak
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
$(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o")
+ifeq ($(LIBTOOL),)
+trace-dtrace.lo: trace-dtrace.dtrace
+ @echo "missing libtool. please install and rerun configure."; exit 1
+else
+trace-dtrace.lo: trace-dtrace.dtrace
+ $(call quiet-command,libtool --mode=compile --tag=CC dtrace -o $@ -G -s $<, " lt GEN trace-dtrace.o")
+endif
+
simpletrace.o: simpletrace.c $(GENERATED_HEADERS)
ifeq ($(TRACE_BACKEND),dtrace)
diff --git a/configure b/configure
index 17c6bfc..79e2ac9 100755
--- a/configure
+++ b/configure
@@ -1279,6 +1279,15 @@ if ! has $pkg_config; then
fi
##########################################
+# libtool probe
+
+if ! has libtool; then
+ libtool=
+else
+ libtool=libtool
+fi
+
+##########################################
# Sparse probe
if test "$sparse" != "no" ; then
if has cgcc; then
@@ -3063,6 +3072,7 @@ echo "AR=$ar" >> $config_host_mak
echo "OBJCOPY=$objcopy" >> $config_host_mak
echo "LD=$ld" >> $config_host_mak
echo "WINDRES=$windres" >> $config_host_mak
+echo "LIBTOOL=$libtool" >> $config_host_mak
echo "CFLAGS=$CFLAGS" >> $config_host_mak
echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
echo "QEMU_INCLUDES=$QEMU_INCLUDES" >> $config_host_mak
@@ -3598,7 +3608,7 @@ if [ "$source_path" != `pwd` ]; then
# out of tree build
mkdir -p libcacard
rm -f libcacard/Makefile
- ln -s "$source_path/libcacard/Makefile" libcacard/Makefile
+ symlink "$source_path/libcacard/Makefile" libcacard/Makefile
fi
d=libuser
diff --git a/libcacard/Makefile b/libcacard/Makefile
index 1d34df0..9802c37 100644
--- a/libcacard/Makefile
+++ b/libcacard/Makefile
@@ -4,15 +4,39 @@
$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/libcacard)
-QEMU_OBJS=$(addprefix ../, $(oslib-obj-y) $(trace-obj-y) qemu-malloc.o qemu-timer-common.o)
+# objects linked against normal qemu binaries, not compiled with libtool
+QEMU_OBJS=$(addprefix ../,$(oslib-obj-y) qemu-malloc.o qemu-timer-common.o $(trace-obj-y))
+
+# objects linked into a shared library, built with libtool with -fPIC if required
+QEMU_OBJS_LIB=$(addsuffix .lo,$(basename $(QEMU_OBJS)))
QEMU_CFLAGS+=-I../
+libcacard.lib-y=$(addsuffix .lo,$(basename $(libcacard-y)))
+
vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o
- $(call quiet-command,$(CC) $(libcacard_libs) -lrt -o $@ $^," LINK $(TARGET_DIR)$@")
+ $(call quiet-command,$(CC) $(libcacard_libs) -lrt -o $@ $^," LINK $@")
+
+clean:
+ rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient *.lo .libs/* *.la
+ rm -Rf .libs
all: vscclient
-clean:
- rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient
+#########################################################################
+# Rules for building libcacard standalone library
+
+ifeq ($(LIBTOOL),)
+libcacard.la:
+ @echo "libtool is missing, please install and rerun configure"; exit 1
+
+install-libcacard:
+ @echo "libtool is missing, please install and rerun configure"; exit 1
+else
+libcacard.la: $(libcacard.lib-y) $(QEMU_OBJS_LIB)
+ $(call quiet-command,libtool --mode=link --quiet --tag=CC $(CC) $(libcacard_libs) -lrt -rpath $(libdir) -o $@ $^," lt LINK $@")
+install-libcacard: libcacard.la
+ $(INSTALL_DIR) "$(DESTDIR)$(libdir)"
+ libtool --mode=install $(INSTALL_PROG) libcacard.la "$(DESTDIR)$(libdir)"
+endif
diff --git a/rules.mak b/rules.mak
index ed59c9e..612ae37 100644
--- a/rules.mak
+++ b/rules.mak
@@ -17,6 +17,14 @@ QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(*D)/$(*F).d
%.o: %.c
$(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CC $(TARGET_DIR)$@")
+ifeq ($(LIBTOOL),)
+%.lo: %.c
+ @echo "missing libtool. please install and rerun configure"; exit 1
+else
+%.lo: %.c
+ $(call quiet-command,libtool --mode=compile --quiet --tag=CC $(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," lt CC $@")
+endif
+
%.o: %.S
$(call quiet-command,$(CC) $(QEMU_CFLAGS) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," AS $(TARGET_DIR)$@")
commit aedce09e87cc0d4672fa6d318d577413342473a2
Author: Alon Levy <alevy at redhat.com>
Date: Sun May 15 12:08:59 2011 +0300
configure: add libdir and --libdir
diff --git a/configure b/configure
index a318d37..17c6bfc 100755
--- a/configure
+++ b/configure
@@ -146,6 +146,7 @@ mandir="\${prefix}/share/man"
datadir="\${prefix}/share/qemu"
docdir="\${prefix}/share/doc/qemu"
bindir="\${prefix}/bin"
+libdir="\${prefix}/lib"
sysconfdir="\${prefix}/etc"
confsuffix="/qemu"
slirp="yes"
@@ -536,6 +537,8 @@ for opt do
;;
--bindir=*) bindir="$optarg"
;;
+ --libdir=*) libdir="$optarg"
+ ;;
--datadir=*) datadir="$optarg"
;;
--docdir=*) docdir="$optarg"
@@ -2633,6 +2636,7 @@ fi
echo "Install prefix $prefix"
echo "BIOS directory `eval echo $datadir`"
echo "binary directory `eval echo $bindir`"
+echo "library directory `eval echo $libdir`"
echo "config directory `eval echo $sysconfdir`"
if test "$mingw32" = "no" ; then
echo "Manual directory `eval echo $mandir`"
@@ -2725,6 +2729,7 @@ echo >> $config_host_mak
echo all: >> $config_host_mak
echo "prefix=$prefix" >> $config_host_mak
echo "bindir=$bindir" >> $config_host_mak
+echo "libdir=$libdir" >> $config_host_mak
echo "mandir=$mandir" >> $config_host_mak
echo "datadir=$datadir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
More information about the Spice-commits
mailing list