summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/acpi.c28
-rw-r--r--hw/acpi_piix4.c35
-rw-r--r--hw/apic.c48
-rw-r--r--hw/bonito.c1
-rw-r--r--hw/cirrus_vga.c30
-rw-r--r--hw/cirrus_vga_rop.h38
-rw-r--r--hw/cirrus_vga_rop2.h12
-rw-r--r--hw/device-hotplug.c1
-rw-r--r--hw/e1000.c38
-rw-r--r--hw/eepro100.c36
-rw-r--r--hw/elf_ops.h5
-rw-r--r--hw/escc.c56
-rw-r--r--hw/esp.c53
-rw-r--r--hw/esp.h3
-rw-r--r--hw/etraxfs.c1
-rw-r--r--hw/etraxfs_eth.c3
-rw-r--r--hw/fdc.c1
-rw-r--r--hw/fdc.h1
-rw-r--r--hw/file-op-9p.h40
-rw-r--r--hw/fmopl.c6
-rw-r--r--hw/gumstix.c1
-rw-r--r--hw/hw.h8
-rw-r--r--hw/ide/core.c99
-rw-r--r--hw/ide/pci.c61
-rw-r--r--hw/ide/qdev.c1
-rw-r--r--hw/ide/via.c1
-rw-r--r--hw/ivshmem.c829
-rw-r--r--hw/jazz_led.c21
-rw-r--r--hw/loader.c5
-rw-r--r--hw/lsi53c895a.c5
-rw-r--r--hw/mainstone.c1
-rw-r--r--hw/mips_fulong2e.c34
-rw-r--r--hw/mips_int.c32
-rw-r--r--hw/mips_jazz.c5
-rw-r--r--hw/mips_malta.c22
-rw-r--r--hw/mips_r4k.c4
-rw-r--r--hw/mipsnet.c2
-rw-r--r--hw/msix.c1
-rw-r--r--hw/multiboot.c2
-rw-r--r--hw/musicpal.c1
-rw-r--r--hw/omap.h6
-rw-r--r--hw/omap1.c18
-rw-r--r--hw/omap2.c6
-rw-r--r--hw/omap_clk.c1
-rw-r--r--hw/omap_i2c.c5
-rw-r--r--hw/omap_mmc.c5
-rw-r--r--hw/omap_sx1.c1
-rw-r--r--hw/omap_uart.c12
-rw-r--r--hw/pc.c7
-rw-r--r--hw/pc_piix.c8
-rw-r--r--hw/pci-hotplug.c3
-rw-r--r--hw/pci.c3
-rw-r--r--hw/pci.h29
-rw-r--r--hw/pckbd.c23
-rw-r--r--hw/pcmcia.h1
-rw-r--r--hw/petalogix_s3adsp1800_mmu.c14
-rw-r--r--hw/piix_pci.c1
-rw-r--r--hw/ppc.c27
-rw-r--r--hw/ppc.h7
-rw-r--r--hw/ppc405_boards.c29
-rw-r--r--hw/ppc405_uc.c28
-rw-r--r--hw/ppc440_bamboo.c41
-rw-r--r--hw/ppc4xx_devs.c5
-rw-r--r--hw/ppc_mac.h1
-rw-r--r--hw/ppc_newworld.c55
-rw-r--r--hw/ppc_oldworld.c121
-rw-r--r--hw/ppc_prep.c7
-rw-r--r--hw/ppce500_mpc8544ds.c13
-rw-r--r--hw/pxa2xx.c16
-rw-r--r--hw/qdev-properties.c3
-rw-r--r--hw/qdev.c3
-rw-r--r--hw/qdev.h1
-rw-r--r--hw/r2d.c1
-rw-r--r--hw/rc4030.c5
-rw-r--r--hw/realview.c1
-rw-r--r--hw/s390-virtio-bus.c8
-rw-r--r--hw/s390-virtio-bus.h1
-rw-r--r--hw/scsi-bus.c16
-rw-r--r--hw/scsi-disk.c146
-rw-r--r--hw/scsi-generic.c40
-rw-r--r--hw/scsi.h1
-rw-r--r--hw/sd.c3
-rw-r--r--hw/serial.c26
-rw-r--r--hw/sh_intc.c3
-rw-r--r--hw/slavio_timer.c4
-rw-r--r--hw/sm501.c5
-rw-r--r--hw/soc_dma.c5
-rw-r--r--hw/sparc32_dma.c23
-rw-r--r--hw/spitz.c1
-rw-r--r--hw/sun4m.c80
-rw-r--r--hw/sun4u.c1
-rw-r--r--hw/syborg_virtio.c8
-rw-r--r--hw/sysbus.c3
-rw-r--r--hw/sysbus.h5
-rw-r--r--hw/tc6393xb_template.h2
-rw-r--r--hw/tosa.c1
-rw-r--r--hw/usb-msd.c3
-rw-r--r--hw/usb-net.c2
-rw-r--r--hw/usb-wacom.c13
-rw-r--r--hw/versatilepb.c1
-rw-r--r--hw/vga.c7
-rw-r--r--hw/vhost.c58
-rw-r--r--hw/vhost_net.c27
-rw-r--r--hw/virtex_ml507.c276
-rw-r--r--hw/virtio-9p-debug.c195
-rw-r--r--hw/virtio-9p-debug.h1
-rw-r--r--hw/virtio-9p-local.c142
-rw-r--r--hw/virtio-9p-posix-acl.c140
-rw-r--r--hw/virtio-9p-xattr-user.c109
-rw-r--r--hw/virtio-9p-xattr.c156
-rw-r--r--hw/virtio-9p-xattr.h103
-rw-r--r--hw/virtio-9p.c1969
-rw-r--r--hw/virtio-9p.h257
-rw-r--r--hw/virtio-balloon.c12
-rw-r--r--hw/virtio-blk.c32
-rw-r--r--hw/virtio-net.c218
-rw-r--r--hw/virtio-net.h14
-rw-r--r--hw/virtio-pci.c54
-rw-r--r--hw/virtio-serial-bus.c31
-rw-r--r--hw/virtio.c59
-rw-r--r--hw/virtio.h11
-rw-r--r--hw/vmmouse.c31
-rw-r--r--hw/vmware_vga.c80
-rw-r--r--hw/vt82c686.c5
-rw-r--r--hw/watchdog.c2
-rw-r--r--hw/wm8750.c5
-rw-r--r--hw/xen_backend.h4
-rw-r--r--hw/xen_devconfig.c2
-rw-r--r--hw/xen_disk.c1
-rw-r--r--hw/xen_machine_pv.c1
130 files changed, 5352 insertions, 1129 deletions
diff --git a/hw/acpi.c b/hw/acpi.c
index c7044b1fae..8071e7beba 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -50,6 +50,8 @@ int acpi_table_add(const char *t)
char buf[1024], *p, *f;
struct acpi_table_header acpi_hdr;
unsigned long val;
+ uint32_t length;
+ struct acpi_table_header *acpi_hdr_p;
size_t off;
memset(&acpi_hdr, 0, sizeof(acpi_hdr));
@@ -108,7 +110,7 @@ int acpi_table_add(const char *t)
buf[0] = '\0';
}
- acpi_hdr.length = sizeof(acpi_hdr);
+ length = sizeof(acpi_hdr);
f = buf;
while (buf[0]) {
@@ -120,7 +122,7 @@ int acpi_table_add(const char *t)
fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
goto out;
}
- acpi_hdr.length += s.st_size;
+ length += s.st_size;
if (!n)
break;
*n = ':';
@@ -131,12 +133,12 @@ int acpi_table_add(const char *t)
acpi_tables_len = sizeof(uint16_t);
acpi_tables = qemu_mallocz(acpi_tables_len);
}
+ acpi_tables = qemu_realloc(acpi_tables,
+ acpi_tables_len + sizeof(uint16_t) + length);
p = acpi_tables + acpi_tables_len;
- acpi_tables_len += sizeof(uint16_t) + acpi_hdr.length;
- acpi_tables = qemu_realloc(acpi_tables, acpi_tables_len);
+ acpi_tables_len += sizeof(uint16_t) + length;
- acpi_hdr.length = cpu_to_le32(acpi_hdr.length);
- *(uint16_t*)p = acpi_hdr.length;
+ *(uint16_t*)p = cpu_to_le32(length);
p += sizeof(uint16_t);
memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
off = sizeof(acpi_hdr);
@@ -157,7 +159,9 @@ int acpi_table_add(const char *t)
goto out;
}
- do {
+ /* off < length is necessary because file size can be changed
+ under our foot */
+ while(s.st_size && off < length) {
int r;
r = read(fd, p + off, s.st_size);
if (r > 0) {
@@ -167,15 +171,21 @@ int acpi_table_add(const char *t)
close(fd);
goto out;
}
- } while(s.st_size);
+ }
close(fd);
if (!n)
break;
f = n + 1;
}
+ if (off < length) {
+ /* don't pass random value in process to guest */
+ memset(p + off, 0, length - off);
+ }
- ((struct acpi_table_header*)p)->checksum = acpi_checksum((uint8_t*)p, off);
+ acpi_hdr_p = (struct acpi_table_header*)p;
+ acpi_hdr_p->length = cpu_to_le32(length);
+ acpi_hdr_p->checksum = acpi_checksum((uint8_t*)p, length);
/* increase number of tables */
(*(uint16_t*)acpi_tables) =
cpu_to_le32(le32_to_cpu(*(uint16_t*)acpi_tables) + 1);
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 24dfcf2039..66c7885d62 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -22,6 +22,7 @@
#include "pci.h"
#include "acpi.h"
#include "sysemu.h"
+#include "range.h"
//#define DEBUG
@@ -37,6 +38,8 @@
#define PCI_BASE 0xae00
#define PCI_EJ_BASE 0xae08
+#define PIIX4_PCI_HOTPLUG_STATUS 2
+
struct gpe_regs {
uint16_t sts; /* status */
uint16_t en; /* enabled */
@@ -104,7 +107,9 @@ static void pm_update_sci(PIIX4PMState *s)
(ACPI_BITMASK_RT_CLOCK_ENABLE |
ACPI_BITMASK_POWER_BUTTON_ENABLE |
ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
- ACPI_BITMASK_TIMER_ENABLE)) != 0);
+ ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
+ (((s->gpe.sts & s->gpe.en) & PIIX4_PCI_HOTPLUG_STATUS) != 0);
+
qemu_set_irq(s->irq, sci_level);
/* schedule a timer interruption if needed */
if ((s->pmen & ACPI_BITMASK_TIMER_ENABLE) &&
@@ -459,7 +464,9 @@ static uint32_t gpe_read_val(uint16_t val, uint32_t addr)
static uint32_t gpe_readb(void *opaque, uint32_t addr)
{
uint32_t val = 0;
- struct gpe_regs *g = opaque;
+ PIIX4PMState *s = opaque;
+ struct gpe_regs *g = &s->gpe;
+
switch (addr) {
case GPE_BASE:
case GPE_BASE + 1:
@@ -499,7 +506,9 @@ static void gpe_reset_val(uint16_t *cur, int addr, uint32_t val)
static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
{
- struct gpe_regs *g = opaque;
+ PIIX4PMState *s = opaque;
+ struct gpe_regs *g = &s->gpe;
+
switch (addr) {
case GPE_BASE:
case GPE_BASE + 1:
@@ -511,7 +520,9 @@ static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
break;
default:
break;
- }
+ }
+
+ pm_update_sci(s);
PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
}
@@ -578,11 +589,10 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state);
static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
{
- struct gpe_regs *gpe = &s->gpe;
struct pci_status *pci0_status = &s->pci0_status;
- register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, gpe);
- register_ioport_read(GPE_BASE, 4, 1, gpe_readb, gpe);
+ register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, s);
+ register_ioport_read(GPE_BASE, 4, 1, gpe_readb, s);
register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status);
register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status);
@@ -595,13 +605,13 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
static void enable_device(PIIX4PMState *s, int slot)
{
- s->gpe.sts |= 2;
+ s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS;
s->pci0_status.up |= (1 << slot);
}
static void disable_device(PIIX4PMState *s, int slot)
{
- s->gpe.sts |= 2;
+ s->gpe.sts |= PIIX4_PCI_HOTPLUG_STATUS;
s->pci0_status.down |= (1 << slot);
}
@@ -621,9 +631,8 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state)
} else {
disable_device(s, slot);
}
- if (s->gpe.en & 2) {
- qemu_set_irq(s->irq, 1);
- qemu_set_irq(s->irq, 0);
- }
+
+ pm_update_sci(s);
+
return 0;
}
diff --git a/hw/apic.c b/hw/apic.c
index d686b510b0..63d62c7553 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -21,23 +21,7 @@
#include "qemu-timer.h"
#include "host-utils.h"
#include "sysbus.h"
-
-//#define DEBUG_APIC
-//#define DEBUG_COALESCING
-
-#ifdef DEBUG_APIC
-#define DPRINTF(fmt, ...) \
- do { printf("apic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-#ifdef DEBUG_COALESCING
-#define DPRINTF_C(fmt, ...) \
- do { printf("apic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF_C(fmt, ...)
-#endif
+#include "trace.h"
/* APIC Local Vector Table */
#define APIC_LVT_TIMER 0
@@ -168,8 +152,8 @@ static void apic_local_deliver(APICState *s, int vector)
uint32_t lvt = s->lvt[vector];
int trigger_mode;
- DPRINTF("%s: vector %d delivery mode %d\n", __func__, vector,
- (lvt >> 8) & 7);
+ trace_apic_local_deliver(vector, (lvt >> 8) & 7);
+
if (lvt & APIC_LVT_MASKED)
return;
@@ -300,9 +284,9 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
{
uint32_t deliver_bitmask[MAX_APIC_WORDS];
- DPRINTF("%s: dest %d dest_mode %d delivery_mode %d vector %d"
- " polarity %d trigger_mode %d\n", __func__, dest, dest_mode,
- delivery_mode, vector_num, polarity, trigger_mode);
+ trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
+ polarity, trigger_mode);
+
apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
trigger_mode);
@@ -312,7 +296,8 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val)
{
APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
- DPRINTF("cpu_set_apic_base: %016" PRIx64 "\n", val);
+ trace_cpu_set_apic_base(val);
+
if (!s)
return;
s->apicbase = (val & 0xfffff000) |
@@ -329,8 +314,8 @@ uint64_t cpu_get_apic_base(DeviceState *d)
{
APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
- DPRINTF("cpu_get_apic_base: %016" PRIx64 "\n",
- s ? (uint64_t)s->apicbase: 0);
+ trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase: 0);
+
return s ? s->apicbase : 0;
}
@@ -402,20 +387,23 @@ static void apic_update_irq(APICState *s)
void apic_reset_irq_delivered(void)
{
- DPRINTF_C("%s: old coalescing %d\n", __func__, apic_irq_delivered);
+ trace_apic_reset_irq_delivered(apic_irq_delivered);
+
apic_irq_delivered = 0;
}
int apic_get_irq_delivered(void)
{
- DPRINTF_C("%s: returning coalescing %d\n", __func__, apic_irq_delivered);
+ trace_apic_get_irq_delivered(apic_irq_delivered);
+
return apic_irq_delivered;
}
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
{
apic_irq_delivered += !get_bit(s->irr, vector_num);
- DPRINTF_C("%s: coalescing %d\n", __func__, apic_irq_delivered);
+
+ trace_apic_set_irq(apic_irq_delivered);
set_bit(s->irr, vector_num);
if (trigger_mode)
@@ -769,7 +757,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
val = 0;
break;
}
- DPRINTF("read: " TARGET_FMT_plx " = %08x\n", addr, val);
+ trace_apic_mem_readl(addr, val);
return val;
}
@@ -805,7 +793,7 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
}
s = DO_UPCAST(APICState, busdev.qdev, d);
- DPRINTF("write: " TARGET_FMT_plx " = %08x\n", addr, val);
+ trace_apic_mem_writel(addr, val);
switch(index) {
case 0x02:
diff --git a/hw/bonito.c b/hw/bonito.c
index 8b810321ad..dcf031134e 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -775,7 +775,6 @@ PCIBus *bonito_init(qemu_irq *pic)
pci_bonito_map_irq, pic, 0x28, 32);
pcihost->bus = b;
qdev_init_nofail(dev);
- pci_bus_set_mem_base(pcihost->bus, 0x10000000);
d = pci_create_simple(b, PCI_DEVFN(0, 0), "Bonito");
s = DO_UPCAST(PCIBonitoState, dev, d);
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index bbd4b082d2..aadc56f692 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -280,63 +280,63 @@ static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
}
#define ROP_NAME 0
-#define ROP_OP(d, s) d = 0
+#define ROP_FN(d, s) 0
#include "cirrus_vga_rop.h"
#define ROP_NAME src_and_dst
-#define ROP_OP(d, s) d = (s) & (d)
+#define ROP_FN(d, s) (s) & (d)
#include "cirrus_vga_rop.h"
#define ROP_NAME src_and_notdst
-#define ROP_OP(d, s) d = (s) & (~(d))
+#define ROP_FN(d, s) (s) & (~(d))
#include "cirrus_vga_rop.h"
#define ROP_NAME notdst
-#define ROP_OP(d, s) d = ~(d)
+#define ROP_FN(d, s) ~(d)
#include "cirrus_vga_rop.h"
#define ROP_NAME src
-#define ROP_OP(d, s) d = s
+#define ROP_FN(d, s) s
#include "cirrus_vga_rop.h"
#define ROP_NAME 1
-#define ROP_OP(d, s) d = ~0
+#define ROP_FN(d, s) ~0
#include "cirrus_vga_rop.h"
#define ROP_NAME notsrc_and_dst
-#define ROP_OP(d, s) d = (~(s)) & (d)
+#define ROP_FN(d, s) (~(s)) & (d)
#include "cirrus_vga_rop.h"
#define ROP_NAME src_xor_dst
-#define ROP_OP(d, s) d = (s) ^ (d)
+#define ROP_FN(d, s) (s) ^ (d)
#include "cirrus_vga_rop.h"
#define ROP_NAME src_or_dst
-#define ROP_OP(d, s) d = (s) | (d)
+#define ROP_FN(d, s) (s) | (d)
#include "cirrus_vga_rop.h"
#define ROP_NAME notsrc_or_notdst
-#define ROP_OP(d, s) d = (~(s)) | (~(d))
+#define ROP_FN(d, s) (~(s)) | (~(d))
#include "cirrus_vga_rop.h"
#define ROP_NAME src_notxor_dst
-#define ROP_OP(d, s) d = ~((s) ^ (d))
+#define ROP_FN(d, s) ~((s) ^ (d))
#include "cirrus_vga_rop.h"
#define ROP_NAME src_or_notdst
-#define ROP_OP(d, s) d = (s) | (~(d))
+#define ROP_FN(d, s) (s) | (~(d))
#include "cirrus_vga_rop.h"
#define ROP_NAME notsrc
-#define ROP_OP(d, s) d = (~(s))
+#define ROP_FN(d, s) (~(s))
#include "cirrus_vga_rop.h"
#define ROP_NAME notsrc_or_dst
-#define ROP_OP(d, s) d = (~(s)) | (d)
+#define ROP_FN(d, s) (~(s)) | (d)
#include "cirrus_vga_rop.h"
#define ROP_NAME notsrc_and_notdst
-#define ROP_OP(d, s) d = (~(s)) & (~(d))
+#define ROP_FN(d, s) (~(s)) & (~(d))
#include "cirrus_vga_rop.h"
static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = {
diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h
index 39a7b7285b..9c7bb09286 100644
--- a/hw/cirrus_vga_rop.h
+++ b/hw/cirrus_vga_rop.h
@@ -22,6 +22,26 @@
* THE SOFTWARE.
*/
+static inline void glue(rop_8_,ROP_NAME)(uint8_t *dst, uint8_t src)
+{
+ *dst = ROP_FN(*dst, src);
+}
+
+static inline void glue(rop_16_,ROP_NAME)(uint16_t *dst, uint16_t src)
+{
+ *dst = ROP_FN(*dst, src);
+}
+
+static inline void glue(rop_32_,ROP_NAME)(uint32_t *dst, uint32_t src)
+{
+ *dst = ROP_FN(*dst, src);
+}
+
+#define ROP_OP(d, s) glue(rop_8_,ROP_NAME)(d, s)
+#define ROP_OP_16(d, s) glue(rop_16_,ROP_NAME)(d, s)
+#define ROP_OP_32(d, s) glue(rop_32_,ROP_NAME)(d, s)
+#undef ROP_FN
+
static void
glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
uint8_t *dst,const uint8_t *src,
@@ -39,7 +59,7 @@ glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
for (y = 0; y < bltheight; y++) {
for (x = 0; x < bltwidth; x++) {
- ROP_OP(*dst, *src);
+ ROP_OP(dst, *src);
dst++;
src++;
}
@@ -59,7 +79,7 @@ glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
srcpitch += bltwidth;
for (y = 0; y < bltheight; y++) {
for (x = 0; x < bltwidth; x++) {
- ROP_OP(*dst, *src);
+ ROP_OP(dst, *src);
dst--;
src--;
}
@@ -81,7 +101,7 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
for (y = 0; y < bltheight; y++) {
for (x = 0; x < bltwidth; x++) {
p = *dst;
- ROP_OP(p, *src);
+ ROP_OP(&p, *src);
if (p != s->vga.gr[0x34]) *dst = p;
dst++;
src++;
@@ -104,7 +124,7 @@ glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
for (y = 0; y < bltheight; y++) {
for (x = 0; x < bltwidth; x++) {
p = *dst;
- ROP_OP(p, *src);
+ ROP_OP(&p, *src);
if (p != s->vga.gr[0x34]) *dst = p;
dst--;
src--;
@@ -128,8 +148,8 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
for (x = 0; x < bltwidth; x+=2) {
p1 = *dst;
p2 = *(dst+1);
- ROP_OP(p1, *src);
- ROP_OP(p2, *(src+1));
+ ROP_OP(&p1, *src);
+ ROP_OP(&p2, *(src + 1));
if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
*dst = p1;
*(dst+1) = p2;
@@ -156,8 +176,8 @@ glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
for (x = 0; x < bltwidth; x+=2) {
p1 = *(dst-1);
p2 = *dst;
- ROP_OP(p1, *(src-1));
- ROP_OP(p2, *src);
+ ROP_OP(&p1, *(src - 1));
+ ROP_OP(&p2, *src);
if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
*(dst-1) = p1;
*dst = p2;
@@ -184,3 +204,5 @@ glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
#undef ROP_NAME
#undef ROP_OP
+#undef ROP_OP_16
+#undef ROP_OP_32
diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h
index 81a5b398e0..d28bcc6f25 100644
--- a/hw/cirrus_vga_rop2.h
+++ b/hw/cirrus_vga_rop2.h
@@ -23,15 +23,15 @@
*/
#if DEPTH == 8
-#define PUTPIXEL() ROP_OP(d[0], col)
+#define PUTPIXEL() ROP_OP(&d[0], col)
#elif DEPTH == 16
-#define PUTPIXEL() ROP_OP(((uint16_t *)d)[0], col);
+#define PUTPIXEL() ROP_OP_16((uint16_t *)&d[0], col)
#elif DEPTH == 24
-#define PUTPIXEL() ROP_OP(d[0], col); \
- ROP_OP(d[1], (col >> 8)); \
- ROP_OP(d[2], (col >> 16))
+#define PUTPIXEL() ROP_OP(&d[0], col); \
+ ROP_OP(&d[1], (col >> 8)); \
+ ROP_OP(&d[2], (col >> 16))
#elif DEPTH == 32
-#define PUTPIXEL() ROP_OP(((uint32_t *)d)[0], col)
+#define PUTPIXEL() ROP_OP_32(((uint32_t *)&d[0]), col)
#else
#error unsupported DEPTH
#endif
diff --git a/hw/device-hotplug.c b/hw/device-hotplug.c
index c1a9a561d7..9704e2feb2 100644
--- a/hw/device-hotplug.c
+++ b/hw/device-hotplug.c
@@ -25,6 +25,7 @@
#include "hw.h"
#include "boards.h"
#include "net.h"
+#include "blockdev.h"
DriveInfo *add_init_drive(const char *optstr)
{
diff --git a/hw/e1000.c b/hw/e1000.c
index 8d87492e0b..532efdc27d 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -55,6 +55,7 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
#define IOPORT_SIZE 0x40
#define PNPMMIO_SIZE 0x20000
+#define MIN_BUF_SIZE 60 /* Min. octets in an ethernet frame sans FCS */
/*
* HW models:
@@ -262,21 +263,20 @@ set_eecd(E1000State *s, int index, uint32_t val)
s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS |
E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ);
+ if (!(E1000_EECD_CS & val)) // CS inactive; nothing to do
+ return;
+ if (E1000_EECD_CS & (val ^ oldval)) { // CS rise edge; reset state
+ s->eecd_state.val_in = 0;
+ s->eecd_state.bitnum_in = 0;
+ s->eecd_state.bitnum_out = 0;
+ s->eecd_state.reading = 0;
+ }
if (!(E1000_EECD_SK & (val ^ oldval))) // no clock edge
return;
if (!(E1000_EECD_SK & val)) { // falling edge
s->eecd_state.bitnum_out++;
return;
}
- if (!(val & E1000_EECD_CS)) { // rising, no CS (EEPROM reset)
- memset(&s->eecd_state, 0, sizeof s->eecd_state);
- /*
- * restore old_eecd's E1000_EECD_SK (known to be on)
- * to avoid false detection of a clock edge
- */
- s->eecd_state.old_eecd = E1000_EECD_SK;
- return;
- }
s->eecd_state.val_in <<= 1;
if (val & E1000_EECD_DI)
s->eecd_state.val_in |= 1;
@@ -346,7 +346,7 @@ is_vlan_txd(uint32_t txd_lower)
/* FCS aka Ethernet CRC-32. We don't get it from backends and can't
* fill it in, just pad descriptor length by 4 bytes unless guest
- * told us to trip it off the packet. */
+ * told us to strip it off the packet. */
static inline int
fcs_len(E1000State *s)
{
@@ -636,10 +636,19 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
uint32_t rdh_start;
uint16_t vlan_special = 0;
uint8_t vlan_status = 0, vlan_offset = 0;
+ uint8_t min_buf[MIN_BUF_SIZE];
if (!(s->mac_reg[RCTL] & E1000_RCTL_EN))
return -1;
+ /* Pad to minimum Ethernet frame length */
+ if (size < sizeof(min_buf)) {
+ memcpy(min_buf, buf, size);
+ memset(&min_buf[size], 0, sizeof(min_buf) - size);
+ buf = min_buf;
+ size = sizeof(min_buf);
+ }
+
if (size > s->rxbuf_size) {
DBGOUT(RX, "packet too large for buffers (%lu > %d)\n",
(unsigned long)size, s->rxbuf_size);
@@ -691,9 +700,14 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
s->mac_reg[GPRC]++;
s->mac_reg[TPR]++;
- n = s->mac_reg[TORL];
- if ((s->mac_reg[TORL] += size) < n)
+ /* TOR - Total Octets Received:
+ * This register includes bytes received in a packet from the <Destination
+ * Address> field through the <CRC> field, inclusively.
+ */
+ n = s->mac_reg[TORL] + size + /* Always include FCS length. */ 4;
+ if (n < s->mac_reg[TORL])
s->mac_reg[TORH]++;
+ s->mac_reg[TORL] = n;
n = E1000_ICS_RXT0;
if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 8cbc3aa7a2..41d792ad24 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -219,7 +219,8 @@ typedef enum {
typedef struct {
PCIDevice dev;
- uint8_t mult[8]; /* multicast mask array */
+ /* Hash register (multicast mask array, multiple individual addresses). */
+ uint8_t mult[8];
int mmio_index;
NICState *nic;
NICConf conf;
@@ -599,7 +600,7 @@ static void nic_reset(void *opaque)
{
EEPRO100State *s = opaque;
TRACE(OTHER, logout("%p\n", s));
- /* TODO: Clearing of multicast table for selective reset, too? */
+ /* TODO: Clearing of hash register for selective reset, too? */
memset(&s->mult[0], 0, sizeof(s->mult));
nic_selective_reset(s);
}
@@ -851,7 +852,14 @@ static void action_command(EEPRO100State *s)
case CmdConfigure:
cpu_physical_memory_read(s->cb_address + 8, &s->configuration[0],
sizeof(s->configuration));
- TRACE(OTHER, logout("configuration: %s\n", nic_dump(&s->configuration[0], 16)));
+ TRACE(OTHER, logout("configuration: %s\n",
+ nic_dump(&s->configuration[0], 16)));
+ TRACE(OTHER, logout("configuration: %s\n",
+ nic_dump(&s->configuration[16],
+ ARRAY_SIZE(s->configuration) - 16)));
+ if (s->configuration[20] & BIT(6)) {
+ TRACE(OTHER, logout("Multiple IA bit\n"));
+ }
break;
case CmdMulticastList:
set_multicast_list(s);
@@ -1282,7 +1290,7 @@ static void eepro100_write_port(EEPRO100State * s, uint32_t val)
static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
{
- uint8_t val;
+ uint8_t val = 0;
if (addr <= sizeof(s->mem) - sizeof(val)) {
memcpy(&val, &s->mem[addr], sizeof(val));
}
@@ -1325,7 +1333,7 @@ static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
{
- uint16_t val;
+ uint16_t val = 0;
if (addr <= sizeof(s->mem) - sizeof(val)) {
memcpy(&val, &s->mem[addr], sizeof(val));
}
@@ -1348,7 +1356,7 @@ static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
{
- uint32_t val;
+ uint32_t val = 0;
if (addr <= sizeof(s->mem) - sizeof(val)) {
memcpy(&val, &s->mem[addr], sizeof(val));
}
@@ -1647,12 +1655,6 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
static const uint8_t broadcast_macaddr[6] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- /* TODO: check multiple IA bit. */
- if (s->configuration[20] & BIT(6)) {
- missing("Multiple IA bit");
- return -1;
- }
-
if (s->configuration[8] & 0x80) {
/* CSMA is disabled. */
logout("%p received while CSMA is disabled\n", s);
@@ -1702,6 +1704,16 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
/* Promiscuous: receive all. */
TRACE(RXTX, logout("%p received frame in promiscuous mode, len=%zu\n", s, size));
rfd_status |= 0x0004;
+ } else if (s->configuration[20] & BIT(6)) {
+ /* Multiple IA bit set. */
+ unsigned mcast_idx = compute_mcast_idx(buf);
+ assert(mcast_idx < 64);
+ if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
+ TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s));
+ } else {
+ TRACE(RXTX, logout("%p frame ignored, multiple IA bit set\n", s));
+ return -1;
+ }
} else {
TRACE(RXTX, logout("%p received frame, ignored, len=%zu,%s\n", s, size,
nic_dump(buf, size)));
diff --git a/hw/elf_ops.h b/hw/elf_ops.h
index 27d1ab9bc2..0bd72350b4 100644
--- a/hw/elf_ops.h
+++ b/hw/elf_ops.h
@@ -153,6 +153,11 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
syms = qemu_realloc(syms, nsyms * sizeof(*syms));
qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
+ for (i = 0; i < nsyms - 1; i++) {
+ if (syms[i].st_size == 0) {
+ syms[i].st_size = syms[i + 1].st_value - syms[i].st_value;
+ }
+ }
} else {
qemu_free(syms);
syms = NULL;
diff --git a/hw/escc.c b/hw/escc.c
index 6d2fd36b11..8714239780 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -65,6 +65,8 @@
* 2006-Aug-10 Igor Kovalenko : Renamed KBDQueue to SERIOQueue, implemented
* serial mouse queue.
* Implemented serial mouse protocol.
+ *
+ * 2010-May-23 Artyom Tarasenko: Reworked IUS logic
*/
#ifdef DEBUG_SERIAL
@@ -279,7 +281,7 @@ static uint32_t get_queue(void *opaque)
static int escc_update_irq_chn(ChannelState *s)
{
- if ((((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) ||
+ if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
// tx ints enabled, pending
((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
@@ -342,24 +344,22 @@ static void escc_reset(DeviceState *d)
static inline void set_rxint(ChannelState *s)
{
s->rxint = 1;
- if (!s->txint_under_svc) {
- s->rxint_under_svc = 1;
- if (s->chn == chn_a) {
- if (s->wregs[W_MINTR] & MINTR_STATUSHI)
- s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
- else
- s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
- } else {
- if (s->wregs[W_MINTR] & MINTR_STATUSHI)
- s->rregs[R_IVEC] = IVEC_HIRXINTB;
- else
- s->rregs[R_IVEC] = IVEC_LORXINTB;
- }
- }
- if (s->chn == chn_a)
+ /* XXX: missing daisy chainnig: chn_b rx should have a lower priority
+ than chn_a rx/tx/special_condition service*/
+ s->rxint_under_svc = 1;
+ if (s->chn == chn_a) {
s->rregs[R_INTR] |= INTR_RXINTA;
- else
+ if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+ s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
+ else
+ s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
+ } else {
s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
+ if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+ s->rregs[R_IVEC] = IVEC_HIRXINTB;
+ else
+ s->rregs[R_IVEC] = IVEC_LORXINTB;
+ }
escc_update_irq(s);
}
@@ -369,19 +369,17 @@ static inline void set_txint(ChannelState *s)
if (!s->rxint_under_svc) {
s->txint_under_svc = 1;
if (s->chn == chn_a) {
+ s->rregs[R_INTR] |= INTR_TXINTA;
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
else
s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
} else {
s->rregs[R_IVEC] = IVEC_TXINTB;
+ s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
}
- }
- if (s->chn == chn_a)
- s->rregs[R_INTR] |= INTR_TXINTA;
- else
- s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
escc_update_irq(s);
+ }
}
static inline void clr_rxint(ChannelState *s)
@@ -417,6 +415,7 @@ static inline void clr_txint(ChannelState *s)
s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
s->rregs[R_INTR] &= ~INTR_TXINTA;
} else {
+ s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->rregs[R_IVEC] = IVEC_HINOINT;
else
@@ -515,10 +514,15 @@ static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
clr_txint(s);
break;
case CMD_CLR_IUS:
- if (s->rxint_under_svc)
- clr_rxint(s);
- else if (s->txint_under_svc)
- clr_txint(s);
+ if (s->rxint_under_svc) {
+ s->rxint_under_svc = 0;
+ if (s->txint) {
+ set_txint(s);
+ }
+ } else if (s->txint_under_svc) {
+ s->txint_under_svc = 0;
+ }
+ escc_update_irq(s);
break;
default:
break;
diff --git a/hw/esp.c b/hw/esp.c
index 349052a024..910fd31665 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -80,6 +80,8 @@ struct ESPState {
ESPDMAMemoryReadWriteFunc dma_memory_read;
ESPDMAMemoryReadWriteFunc dma_memory_write;
void *dma_opaque;
+ int dma_enabled;
+ void (*dma_cb)(ESPState *s);
};
#define ESP_TCLO 0x0
@@ -167,6 +169,24 @@ static void esp_lower_irq(ESPState *s)
}
}
+static void esp_dma_enable(void *opaque, int irq, int level)
+{
+ DeviceState *d = opaque;
+ ESPState *s = container_of(d, ESPState, busdev.qdev);
+
+ if (level) {
+ s->dma_enabled = 1;
+ DPRINTF("Raise enable\n");
+ if (s->dma_cb) {
+ s->dma_cb(s);
+ s->dma_cb = NULL;
+ }
+ } else {
+ DPRINTF("Lower enable\n");
+ s->dma_enabled = 0;
+ }
+}
+
static uint32_t get_cmd(ESPState *s, uint8_t *buf)
{
uint32_t dmalen;
@@ -243,6 +263,10 @@ static void handle_satn(ESPState *s)
uint8_t buf[32];
int len;
+ if (!s->dma_enabled) {
+ s->dma_cb = handle_satn;
+ return;
+ }
len = get_cmd(s, buf);
if (len)
do_cmd(s, buf);
@@ -253,6 +277,10 @@ static void handle_s_without_atn(ESPState *s)
uint8_t buf[32];
int len;
+ if (!s->dma_enabled) {
+ s->dma_cb = handle_s_without_atn;
+ return;
+ }
len = get_cmd(s, buf);
if (len) {
do_busid_cmd(s, buf, 0);
@@ -261,6 +289,10 @@ static void handle_s_without_atn(ESPState *s)
static void handle_satn_stop(ESPState *s)
{
+ if (!s->dma_enabled) {
+ s->dma_cb = handle_satn_stop;
+ return;
+ }
s->cmdlen = get_cmd(s, s->cmdbuf);
if (s->cmdlen) {
DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
@@ -431,6 +463,7 @@ static void esp_hard_reset(DeviceState *d)
s->ti_wptr = 0;
s->dma = 0;
s->do_cmd = 0;
+ s->dma_cb = NULL;
s->rregs[ESP_CFG1] = 7;
}
@@ -450,6 +483,18 @@ static void parent_esp_reset(void *opaque, int irq, int level)
}
}
+static void esp_gpio_demux(void *opaque, int irq, int level)
+{
+ switch (irq) {
+ case 0:
+ parent_esp_reset(opaque, irq, level);
+ break;
+ case 1:
+ esp_dma_enable(opaque, irq, level);
+ break;
+ }
+}
+
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
{
ESPState *s = opaque;
@@ -646,7 +691,8 @@ static const VMStateDescription vmstate_esp = {
void esp_init(target_phys_addr_t espaddr, int it_shift,
ESPDMAMemoryReadWriteFunc dma_memory_read,
ESPDMAMemoryReadWriteFunc dma_memory_write,
- void *dma_opaque, qemu_irq irq, qemu_irq *reset)
+ void *dma_opaque, qemu_irq irq, qemu_irq *reset,
+ qemu_irq *dma_enable)
{
DeviceState *dev;
SysBusDevice *s;
@@ -658,11 +704,14 @@ void esp_init(target_phys_addr_t espaddr, int it_shift,
esp->dma_memory_write = dma_memory_write;
esp->dma_opaque = dma_opaque;
esp->it_shift = it_shift;
+ /* XXX for now until rc4030 has been changed to use DMA enable signal */
+ esp->dma_enabled = 1;
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
sysbus_connect_irq(s, 0, irq);
sysbus_mmio_map(s, 0, espaddr);
*reset = qdev_get_gpio_in(dev, 0);
+ *dma_enable = qdev_get_gpio_in(dev, 1);
}
static int esp_init1(SysBusDevice *dev)
@@ -676,7 +725,7 @@ static int esp_init1(SysBusDevice *dev)
esp_io_memory = cpu_register_io_memory(esp_mem_read, esp_mem_write, s);
sysbus_init_mmio(dev, ESP_REGS << s->it_shift, esp_io_memory);
- qdev_init_gpio_in(&dev->qdev, parent_esp_reset, 1);
+ qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2);
scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, esp_command_complete);
return scsi_bus_legacy_handle_cmdline(&s->bus);
diff --git a/hw/esp.h b/hw/esp.h
index 605f953754..62bfd4d129 100644
--- a/hw/esp.h
+++ b/hw/esp.h
@@ -7,6 +7,7 @@ typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
void esp_init(target_phys_addr_t espaddr, int it_shift,
ESPDMAMemoryReadWriteFunc dma_memory_read,
ESPDMAMemoryReadWriteFunc dma_memory_write,
- void *dma_opaque, qemu_irq irq, qemu_irq *reset);
+ void *dma_opaque, qemu_irq irq, qemu_irq *reset,
+ qemu_irq *dma_enable);
#endif
diff --git a/hw/etraxfs.c b/hw/etraxfs.c
index 46e2920c23..5ee5f979aa 100644
--- a/hw/etraxfs.c
+++ b/hw/etraxfs.c
@@ -31,6 +31,7 @@
#include "loader.h"
#include "elf.h"
#include "cris-boot.h"
+#include "blockdev.h"
#define FLASH_SIZE 0x2000000
#define INTMEM_SIZE (128 * 1024)
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 187ece19ea..ade96f14ac 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -437,6 +437,7 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
eth_validate_duplex(eth);
}
eth->mdio_bus.mdc = !!(value & 4);
+ eth->regs[addr] = value;
break;
case RW_REC_CTRL:
@@ -463,7 +464,7 @@ static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
/* First bit on the wire of a MAC address signals multicast or
physical address. */
- if (!m_individual && !sa[0] & 1)
+ if (!m_individual && !(sa[0] & 1))
return 0;
/* Calculate the hash index for the GA registers. */
diff --git a/hw/fdc.c b/hw/fdc.c
index 2d50bd6a39..c159dcb630 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -34,6 +34,7 @@
#include "isa.h"
#include "sysbus.h"
#include "qdev-addr.h"
+#include "blockdev.h"
/********************************************************/
/* debug Floppy devices */
diff --git a/hw/fdc.h b/hw/fdc.h
index b6b3772592..242730af8c 100644
--- a/hw/fdc.h
+++ b/hw/fdc.h
@@ -2,7 +2,6 @@
#define HW_FDC_H
/* fdc.c */
-#include "blockdev.h"
#define MAX_FD 2
typedef struct FDCtrl FDCtrl;
diff --git a/hw/file-op-9p.h b/hw/file-op-9p.h
index a741c93527..21d60b5855 100644
--- a/hw/file-op-9p.h
+++ b/hw/file-op-9p.h
@@ -24,8 +24,19 @@
typedef enum
{
- SM_PASSTHROUGH = 1, /* uid/gid set on fileserver files */
- SM_MAPPED, /* uid/gid part of xattr */
+ /*
+ * Server will try to set uid/gid.
+ * On failure ignore the error.
+ */
+ SM_NONE = 0,
+ /*
+ * uid/gid set on fileserver files
+ */
+ SM_PASSTHROUGH = 1,
+ /*
+ * uid/gid part of xattr
+ */
+ SM_MAPPED,
} SecModel;
typedef struct FsCred
@@ -36,11 +47,14 @@ typedef struct FsCred
dev_t fc_rdev;
} FsCred;
+struct xattr_operations;
+
typedef struct FsContext
{
char *fs_root;
SecModel fs_sm;
uid_t uid;
+ struct xattr_operations **xops;
} FsContext;
extern void cred_init(FsCred *);
@@ -52,7 +66,7 @@ typedef struct FileOperations
int (*chmod)(FsContext *, const char *, FsCred *);
int (*chown)(FsContext *, const char *, FsCred *);
int (*mknod)(FsContext *, const char *, FsCred *);
- int (*utime)(FsContext *, const char *, const struct utimbuf *);
+ int (*utimensat)(FsContext *, const char *, const struct timespec *);
int (*remove)(FsContext *, const char *);
int (*symlink)(FsContext *, const char *, const char *, FsCred *);
int (*link)(FsContext *, const char *, const char *);
@@ -66,14 +80,28 @@ typedef struct FileOperations
off_t (*telldir)(FsContext *, DIR *);
struct dirent *(*readdir)(FsContext *, DIR *);
void (*seekdir)(FsContext *, DIR *, off_t);
- ssize_t (*readv)(FsContext *, int, const struct iovec *, int);
- ssize_t (*writev)(FsContext *, int, const struct iovec *, int);
- off_t (*lseek)(FsContext *, int, off_t, int);
+ ssize_t (*preadv)(FsContext *, int, const struct iovec *, int, off_t);
+ ssize_t (*pwritev)(FsContext *, int, const struct iovec *, int, off_t);
int (*mkdir)(FsContext *, const char *, FsCred *);
int (*fstat)(FsContext *, int, struct stat *);
int (*rename)(FsContext *, const char *, const char *);
int (*truncate)(FsContext *, const char *, off_t);
int (*fsync)(FsContext *, int);
+ int (*statfs)(FsContext *s, const char *path, struct statfs *stbuf);
+ ssize_t (*lgetxattr)(FsContext *, const char *,
+ const char *, void *, size_t);
+ ssize_t (*llistxattr)(FsContext *, const char *, void *, size_t);
+ int (*lsetxattr)(FsContext *, const char *,
+ const char *, void *, size_t, int);
+ int (*lremovexattr)(FsContext *, const char *, const char *);
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/fmopl.c b/hw/fmopl.c
index d1161f848f..3df1806a91 100644
--- a/hw/fmopl.c
+++ b/hw/fmopl.c
@@ -1342,8 +1342,9 @@ unsigned char OPLRead(FM_OPL *OPL,int a)
{
if(OPL->keyboardhandler_r)
return OPL->keyboardhandler_r(OPL->keyboard_param);
- else
+ else {
LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
+ }
}
return 0;
#if 0
@@ -1355,8 +1356,9 @@ unsigned char OPLRead(FM_OPL *OPL,int a)
{
if(OPL->porthandler_r)
return OPL->porthandler_r(OPL->port_param);
- else
+ else {
LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
+ }
}
return 0;
case 0x1a: /* PCM-DATA */
diff --git a/hw/gumstix.c b/hw/gumstix.c
index c343a166e8..af8b464b88 100644
--- a/hw/gumstix.c
+++ b/hw/gumstix.c
@@ -38,6 +38,7 @@
#include "sysemu.h"
#include "devices.h"
#include "boards.h"
+#include "blockdev.h"
static const int sector_len = 128 * 1024;
diff --git a/hw/hw.h b/hw/hw.h
index c2de6fe8c4..4405092b54 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -264,6 +264,8 @@ int register_savevm_live(DeviceState *dev,
void *opaque);
void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque);
+void register_device_unmigratable(DeviceState *dev, const char *idstr,
+ void *opaque);
typedef void QEMUResetHandler(void *opaque);
@@ -313,6 +315,11 @@ typedef struct {
bool (*field_exists)(void *opaque, int version_id);
} VMStateField;
+typedef struct VMStateSubsection {
+ const VMStateDescription *vmsd;
+ bool (*needed)(void *opaque);
+} VMStateSubsection;
+
struct VMStateDescription {
const char *name;
int version_id;
@@ -323,6 +330,7 @@ struct VMStateDescription {
int (*post_load)(void *opaque, int version_id);
void (*pre_save)(void *opaque);
VMStateField *fields;
+ const VMStateSubsection *subsections;
};
extern const VMStateInfo vmstate_info_int8;
diff --git a/hw/ide/core.c b/hw/ide/core.c
index af52c2cb2d..06b6e14e56 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -30,6 +30,7 @@
#include "qemu-timer.h"
#include "sysemu.h"
#include "dma.h"
+#include "blockdev.h"
#include <hw/ide/internal.h>
@@ -138,6 +139,7 @@ static void ide_identify(IDEState *s)
put_le16(p + 61, s->nb_sectors >> 16);
put_le16(p + 62, 0x07); /* single word dma0-2 supported */
put_le16(p + 63, 0x07); /* mdma0-2 supported */
+ put_le16(p + 64, 0x03); /* pio3-4 supported */
put_le16(p + 65, 120);
put_le16(p + 66, 120);
put_le16(p + 67, 120);
@@ -198,13 +200,12 @@ static void ide_atapi_identify(IDEState *s)
put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */
put_le16(p + 62, 7); /* single word dma0-2 supported */
put_le16(p + 63, 7); /* mdma0-2 supported */
- put_le16(p + 64, 0x3f); /* PIO modes supported */
#else
put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
- put_le16(p + 64, 1); /* PIO modes */
#endif
+ put_le16(p + 64, 3); /* pio3-4 supported */
put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
@@ -1643,6 +1644,21 @@ static void ide_atapi_cmd(IDEState *s)
ide_atapi_cmd_reply(s, len, max_len);
break;
}
+ case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
+ max_len = ube16_to_cpu(packet + 7);
+
+ if (packet[1] & 0x01) { /* polling */
+ /* We don't support any event class (yet). */
+ cpu_to_ube16(buf, 0x00); /* No event descriptor returned */
+ buf[2] = 0x80; /* No Event Available (NEA) */
+ buf[3] = 0x00; /* Empty supported event classes */
+ ide_atapi_cmd_reply(s, 4, max_len);
+ } else { /* asynchronous mode */
+ /* Only polling is supported, asynchronous mode is not. */
+ ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+ ASC_INV_FIELD_IN_CMD_PACKET);
+ }
+ break;
default:
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
ASC_ILLEGAL_OPCODE);
@@ -2629,7 +2645,12 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs,
if (bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM) {
s->drive_kind = IDE_CD;
bdrv_set_change_cb(bs, cdrom_change_cb, s);
+ bs->buffer_alignment = 2048;
} else {
+ if (!bdrv_is_inserted(s->bs)) {
+ error_report("Device needs media, but drive is empty");
+ return -1;
+ }
if (bdrv_is_read_only(bs)) {
error_report("Can't use a read-only drive");
return -1;
@@ -2659,7 +2680,8 @@ static void ide_init1(IDEBus *bus, int unit)
s->bus = bus;
s->unit = unit;
s->drive_serial = drive_serial++;
- s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
+ /* we need at least 2k alignment for accessing CDROMs using O_DIRECT */
+ s->io_buffer = qemu_memalign(2048, IDE_DMA_BUF_SECTORS*512 + 4);
s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
s->smart_selftest_data = qemu_blockalign(s->bs, 512);
s->sector_write_timer = qemu_new_timer(vm_clock,
@@ -2729,6 +2751,7 @@ static EndTransferFunc* transfer_end_table[] = {
ide_transfer_stop,
ide_atapi_cmd_reply_end,
ide_atapi_cmd,
+ ide_dummy_transfer_stop,
};
static int transfer_end_table_idx(EndTransferFunc *fn)
@@ -2752,26 +2775,28 @@ static int ide_drive_post_load(void *opaque, int version_id)
s->cdrom_changed = 1;
}
}
+ return 0;
+}
+
+static int ide_drive_pio_post_load(void *opaque, int version_id)
+{
+ IDEState *s = opaque;
- if (s->cur_io_buffer_len) {
- s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
- s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
- s->data_end = s->data_ptr + s->cur_io_buffer_len;
+ if (s->end_transfer_fn_idx > ARRAY_SIZE(transfer_end_table)) {
+ return -EINVAL;
}
-
+ s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
+ s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
+ s->data_end = s->data_ptr + s->cur_io_buffer_len;
+
return 0;
}
-static void ide_drive_pre_save(void *opaque)
+static void ide_drive_pio_pre_save(void *opaque)
{
IDEState *s = opaque;
int idx;
- s->cur_io_buffer_len = 0;
-
- if (!(s->status & DRQ_STAT))
- return;
-
s->cur_io_buffer_offset = s->data_ptr - s->io_buffer;
s->cur_io_buffer_len = s->data_end - s->data_ptr;
@@ -2785,12 +2810,38 @@ static void ide_drive_pre_save(void *opaque)
}
}
+static bool ide_drive_pio_state_needed(void *opaque)
+{
+ IDEState *s = opaque;
+
+ return (s->status & DRQ_STAT) != 0;
+}
+
+const VMStateDescription vmstate_ide_drive_pio_state = {
+ .name = "ide_drive/pio_state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .pre_save = ide_drive_pio_pre_save,
+ .post_load = ide_drive_pio_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32(req_nb_sectors, IDEState),
+ VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
+ vmstate_info_uint8, uint8_t),
+ VMSTATE_INT32(cur_io_buffer_offset, IDEState),
+ VMSTATE_INT32(cur_io_buffer_len, IDEState),
+ VMSTATE_UINT8(end_transfer_fn_idx, IDEState),
+ VMSTATE_INT32(elementary_transfer_size, IDEState),
+ VMSTATE_INT32(packet_transfer_size, IDEState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
const VMStateDescription vmstate_ide_drive = {
.name = "ide_drive",
- .version_id = 4,
+ .version_id = 3,
.minimum_version_id = 0,
.minimum_version_id_old = 0,
- .pre_save = ide_drive_pre_save,
.post_load = ide_drive_post_load,
.fields = (VMStateField []) {
VMSTATE_INT32(mult_sectors, IDEState),
@@ -2813,15 +2864,15 @@ const VMStateDescription vmstate_ide_drive = {
VMSTATE_UINT8(sense_key, IDEState),
VMSTATE_UINT8(asc, IDEState),
VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
- VMSTATE_INT32_V(req_nb_sectors, IDEState, 4),
- VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 4,
- vmstate_info_uint8, uint8_t),
- VMSTATE_INT32_V(cur_io_buffer_offset, IDEState, 4),
- VMSTATE_INT32_V(cur_io_buffer_len, IDEState, 4),
- VMSTATE_UINT8_V(end_transfer_fn_idx, IDEState, 4),
- VMSTATE_INT32_V(elementary_transfer_size, IDEState, 4),
- VMSTATE_INT32_V(packet_transfer_size, IDEState, 4),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection []) {
+ {
+ .vmsd = &vmstate_ide_drive_pio_state,
+ .needed = ide_drive_pio_state_needed,
+ }, {
+ /* empty */
+ }
}
};
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 4d95cc5e22..ec90f266e9 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -40,8 +40,27 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
printf("%s: 0x%08x\n", __func__, val);
#endif
if (!(val & BM_CMD_START)) {
- /* XXX: do it better */
- ide_dma_cancel(bm);
+ /*
+ * We can't cancel Scatter Gather DMA in the middle of the
+ * operation or a partial (not full) DMA transfer would reach
+ * the storage so we wait for completion instead (we beahve
+ * like if the DMA was completed by the time the guest trying
+ * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
+ * set).
+ *
+ * In the future we'll be able to safely cancel the I/O if the
+ * whole DMA operation will be submitted to disk with a single
+ * aio operation with preadv/pwritev.
+ */
+ if (bm->aiocb) {
+ qemu_aio_flush();
+#ifdef DEBUG_IDE
+ if (bm->aiocb)
+ printf("ide_dma_cancel: aiocb still pending");
+ if (bm->status & BM_STATUS_DMAING)
+ printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
+#endif
+ }
bm->cmd = val & 0x09;
} else {
if (!(bm->status & BM_STATUS_DMAING)) {
@@ -121,9 +140,31 @@ void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val)
bm->cur_addr = bm->addr;
}
+static bool ide_bmdma_current_needed(void *opaque)
+{
+ BMDMAState *bm = opaque;
+
+ return (bm->cur_prd_len != 0);
+}
+
+static const VMStateDescription vmstate_bmdma_current = {
+ .name = "ide bmdma_current",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(cur_addr, BMDMAState),
+ VMSTATE_UINT32(cur_prd_last, BMDMAState),
+ VMSTATE_UINT32(cur_prd_addr, BMDMAState),
+ VMSTATE_UINT32(cur_prd_len, BMDMAState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+
static const VMStateDescription vmstate_bmdma = {
.name = "ide bmdma",
- .version_id = 4,
+ .version_id = 3,
.minimum_version_id = 0,
.minimum_version_id_old = 0,
.fields = (VMStateField []) {
@@ -133,11 +174,15 @@ static const VMStateDescription vmstate_bmdma = {
VMSTATE_INT64(sector_num, BMDMAState),
VMSTATE_UINT32(nsector, BMDMAState),
VMSTATE_UINT8(unit, BMDMAState),
- VMSTATE_UINT32_V(cur_addr, BMDMAState, 4),
- VMSTATE_UINT32_V(cur_prd_last, BMDMAState, 4),
- VMSTATE_UINT32_V(cur_prd_addr, BMDMAState, 4),
- VMSTATE_UINT32_V(cur_prd_len, BMDMAState, 4),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection []) {
+ {
+ .vmsd = &vmstate_bmdma_current,
+ .needed = ide_bmdma_current_needed,
+ }, {
+ /* empty */
+ }
}
};
@@ -156,7 +201,7 @@ static int ide_pci_post_load(void *opaque, int version_id)
const VMStateDescription vmstate_ide_pci = {
.name = "ide",
- .version_id = 4,
+ .version_id = 3,
.minimum_version_id = 0,
.minimum_version_id_old = 0,
.post_load = ide_pci_post_load,
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 53468edcbc..080876035f 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -20,6 +20,7 @@
#include "dma.h"
#include "qemu-error.h"
#include <hw/ide/internal.h>
+#include "blockdev.h"
/* --------------------------------- */
diff --git a/hw/ide/via.c b/hw/ide/via.c
index a403e8cd98..b2c7cad622 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -150,7 +150,6 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy ATA mode */
pci_config_set_revision(pci_conf,0x06); /* Revision 0.6 */
- pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; /* header_type */
pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
qemu_register_reset(via_reset, d);
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
new file mode 100644
index 0000000000..06dce70e78
--- /dev/null
+++ b/hw/ivshmem.c
@@ -0,0 +1,829 @@
+/*
+ * Inter-VM Shared Memory PCI device.
+ *
+ * Author:
+ * Cam Macdonell <cam@cs.ualberta.ca>
+ *
+ * Based On: cirrus_vga.c
+ * Copyright (c) 2004 Fabrice Bellard
+ * Copyright (c) 2004 Makoto Suzuki (suzu)
+ *
+ * and rtl8139.c
+ * Copyright (c) 2006 Igor Kovalenko
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#include "hw.h"
+#include "pc.h"
+#include "pci.h"
+#include "msix.h"
+#include "kvm.h"
+
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#define IVSHMEM_IOEVENTFD 0
+#define IVSHMEM_MSI 1
+
+#define IVSHMEM_PEER 0
+#define IVSHMEM_MASTER 1
+
+#define IVSHMEM_REG_BAR_SIZE 0x100
+
+//#define DEBUG_IVSHMEM
+#ifdef DEBUG_IVSHMEM
+#define IVSHMEM_DPRINTF(fmt, ...) \
+ do {printf("IVSHMEM: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define IVSHMEM_DPRINTF(fmt, ...)
+#endif
+
+typedef struct Peer {
+ int nb_eventfds;
+ int *eventfds;
+} Peer;
+
+typedef struct EventfdEntry {
+ PCIDevice *pdev;
+ int vector;
+} EventfdEntry;
+
+typedef struct IVShmemState {
+ PCIDevice dev;
+ uint32_t intrmask;
+ uint32_t intrstatus;
+ uint32_t doorbell;
+
+ CharDriverState **eventfd_chr;
+ CharDriverState *server_chr;
+ int ivshmem_mmio_io_addr;
+
+ pcibus_t mmio_addr;
+ pcibus_t shm_pci_addr;
+ uint64_t ivshmem_offset;
+ uint64_t ivshmem_size; /* size of shared memory region */
+ int shm_fd; /* shared memory file descriptor */
+
+ Peer *peers;
+ int nb_peers; /* how many guests we have space for */
+ int max_peer; /* maximum numbered peer */
+
+ int vm_id;
+ uint32_t vectors;
+ uint32_t features;
+ EventfdEntry *eventfd_table;
+
+ char * shmobj;
+ char * sizearg;
+ char * role;
+ int role_val; /* scalar to avoid multiple string comparisons */
+} IVShmemState;
+
+/* registers for the Inter-VM shared memory device */
+enum ivshmem_registers {
+ INTRMASK = 0,
+ INTRSTATUS = 4,
+ IVPOSITION = 8,
+ DOORBELL = 12,
+};
+
+static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
+ unsigned int feature) {
+ return (ivs->features & (1 << feature));
+}
+
+static inline bool is_power_of_two(uint64_t x) {
+ return (x & (x - 1)) == 0;
+}
+
+static void ivshmem_map(PCIDevice *pci_dev, int region_num,
+ pcibus_t addr, pcibus_t size, int type)
+{
+ IVShmemState *s = DO_UPCAST(IVShmemState, dev, pci_dev);
+
+ s->shm_pci_addr = addr;
+
+ if (s->ivshmem_offset > 0) {
+ cpu_register_physical_memory(s->shm_pci_addr, s->ivshmem_size,
+ s->ivshmem_offset);
+ }
+
+ IVSHMEM_DPRINTF("guest pci addr = %" FMT_PCIBUS ", guest h/w addr = %"
+ PRIu64 ", size = %" FMT_PCIBUS "\n", addr, s->ivshmem_offset, size);
+
+}
+
+/* accessing registers - based on rtl8139 */
+static void ivshmem_update_irq(IVShmemState *s, int val)
+{
+ int isr;
+ isr = (s->intrstatus & s->intrmask) & 0xffffffff;
+
+ /* don't print ISR resets */
+ if (isr) {
+ IVSHMEM_DPRINTF("Set IRQ to %d (%04x %04x)\n",
+ isr ? 1 : 0, s->intrstatus, s->intrmask);
+ }
+
+ qemu_set_irq(s->dev.irq[0], (isr != 0));
+}
+
+static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
+{
+ IVSHMEM_DPRINTF("IntrMask write(w) val = 0x%04x\n", val);
+
+ s->intrmask = val;
+
+ ivshmem_update_irq(s, val);
+}
+
+static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
+{
+ uint32_t ret = s->intrmask;
+
+ IVSHMEM_DPRINTF("intrmask read(w) val = 0x%04x\n", ret);
+
+ return ret;
+}
+
+static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
+{
+ IVSHMEM_DPRINTF("IntrStatus write(w) val = 0x%04x\n", val);
+
+ s->intrstatus = val;
+
+ ivshmem_update_irq(s, val);
+ return;
+}
+
+static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
+{
+ uint32_t ret = s->intrstatus;
+
+ /* reading ISR clears all interrupts */
+ s->intrstatus = 0;
+
+ ivshmem_update_irq(s, 0);
+
+ return ret;
+}
+
+static void ivshmem_io_writew(void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+
+ IVSHMEM_DPRINTF("We shouldn't be writing words\n");
+}
+
+static void ivshmem_io_writel(void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ IVShmemState *s = opaque;
+
+ uint64_t write_one = 1;
+ uint16_t dest = val >> 16;
+ uint16_t vector = val & 0xff;
+
+ addr &= 0xfc;
+
+ IVSHMEM_DPRINTF("writing to addr " TARGET_FMT_plx "\n", addr);
+ switch (addr)
+ {
+ case INTRMASK:
+ ivshmem_IntrMask_write(s, val);
+ break;
+
+ case INTRSTATUS:
+ ivshmem_IntrStatus_write(s, val);
+ break;
+
+ case DOORBELL:
+ /* check that dest VM ID is reasonable */
+ if (dest > s->max_peer) {
+ IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
+ break;
+ }
+
+ /* check doorbell range */
+ if (vector < s->peers[dest].nb_eventfds) {
+ IVSHMEM_DPRINTF("Writing %" PRId64 " to VM %d on vector %d\n",
+ write_one, dest, vector);
+ if (write(s->peers[dest].eventfds[vector],
+ &(write_one), 8) != 8) {
+ IVSHMEM_DPRINTF("error writing to eventfd\n");
+ }
+ }
+ break;
+ default:
+ IVSHMEM_DPRINTF("Invalid VM Doorbell VM %d\n", dest);
+ }
+}
+
+static void ivshmem_io_writeb(void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ IVSHMEM_DPRINTF("We shouldn't be writing bytes\n");
+}
+
+static uint32_t ivshmem_io_readw(void *opaque, target_phys_addr_t addr)
+{
+
+ IVSHMEM_DPRINTF("We shouldn't be reading words\n");
+ return 0;
+}
+
+static uint32_t ivshmem_io_readl(void *opaque, target_phys_addr_t addr)
+{
+
+ IVShmemState *s = opaque;
+ uint32_t ret;
+
+ switch (addr)
+ {
+ case INTRMASK:
+ ret = ivshmem_IntrMask_read(s);
+ break;
+
+ case INTRSTATUS:
+ ret = ivshmem_IntrStatus_read(s);
+ break;
+
+ case IVPOSITION:
+ /* return my VM ID if the memory is mapped */
+ if (s->shm_fd > 0) {
+ ret = s->vm_id;
+ } else {
+ ret = -1;
+ }
+ break;
+
+ default:
+ IVSHMEM_DPRINTF("why are we reading " TARGET_FMT_plx "\n", addr);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static uint32_t ivshmem_io_readb(void *opaque, target_phys_addr_t addr)
+{
+ IVSHMEM_DPRINTF("We shouldn't be reading bytes\n");
+
+ return 0;
+}
+
+static CPUReadMemoryFunc * const ivshmem_mmio_read[3] = {
+ ivshmem_io_readb,
+ ivshmem_io_readw,
+ ivshmem_io_readl,
+};
+
+static CPUWriteMemoryFunc * const ivshmem_mmio_write[3] = {
+ ivshmem_io_writeb,
+ ivshmem_io_writew,
+ ivshmem_io_writel,
+};
+
+static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
+{
+ IVShmemState *s = opaque;
+
+ ivshmem_IntrStatus_write(s, *buf);
+
+ IVSHMEM_DPRINTF("ivshmem_receive 0x%02x\n", *buf);
+}
+
+static int ivshmem_can_receive(void * opaque)
+{
+ return 8;
+}
+
+static void ivshmem_event(void *opaque, int event)
+{
+ IVSHMEM_DPRINTF("ivshmem_event %d\n", event);
+}
+
+static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
+
+ EventfdEntry *entry = opaque;
+ PCIDevice *pdev = entry->pdev;
+
+ IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, entry->vector);
+ msix_notify(pdev, entry->vector);
+}
+
+static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd,
+ int vector)
+{
+ /* create a event character device based on the passed eventfd */
+ IVShmemState *s = opaque;
+ CharDriverState * chr;
+
+ chr = qemu_chr_open_eventfd(eventfd);
+
+ if (chr == NULL) {
+ fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd);
+ exit(-1);
+ }
+
+ /* if MSI is supported we need multiple interrupts */
+ if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
+ s->eventfd_table[vector].pdev = &s->dev;
+ s->eventfd_table[vector].vector = vector;
+
+ qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
+ ivshmem_event, &s->eventfd_table[vector]);
+ } else {
+ qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
+ ivshmem_event, s);
+ }
+
+ return chr;
+
+}
+
+static int check_shm_size(IVShmemState *s, int fd) {
+ /* check that the guest isn't going to try and map more memory than the
+ * the object has allocated return -1 to indicate error */
+
+ struct stat buf;
+
+ fstat(fd, &buf);
+
+ if (s->ivshmem_size > buf.st_size) {
+ fprintf(stderr,
+ "IVSHMEM ERROR: Requested memory size greater"
+ " than shared object size (%" PRIu64 " > %" PRIu64")\n",
+ s->ivshmem_size, (uint64_t)buf.st_size);
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+/* create the shared memory BAR when we are not using the server, so we can
+ * create the BAR and map the memory immediately */
+static void create_shared_memory_BAR(IVShmemState *s, int fd) {
+
+ void * ptr;
+
+ s->shm_fd = fd;
+
+ ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+
+ s->ivshmem_offset = qemu_ram_alloc_from_ptr(&s->dev.qdev, "ivshmem.bar2",
+ s->ivshmem_size, ptr);
+
+ /* region for shared memory */
+ pci_register_bar(&s->dev, 2, s->ivshmem_size,
+ PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
+}
+
+static void close_guest_eventfds(IVShmemState *s, int posn)
+{
+ int i, guest_curr_max;
+
+ guest_curr_max = s->peers[posn].nb_eventfds;
+
+ for (i = 0; i < guest_curr_max; i++) {
+ kvm_set_ioeventfd_mmio_long(s->peers[posn].eventfds[i],
+ s->mmio_addr + DOORBELL, (posn << 16) | i, 0);
+ close(s->peers[posn].eventfds[i]);
+ }
+
+ qemu_free(s->peers[posn].eventfds);
+ s->peers[posn].nb_eventfds = 0;
+}
+
+static void setup_ioeventfds(IVShmemState *s) {
+
+ int i, j;
+
+ for (i = 0; i <= s->max_peer; i++) {
+ for (j = 0; j < s->peers[i].nb_eventfds; j++) {
+ kvm_set_ioeventfd_mmio_long(s->peers[i].eventfds[j],
+ s->mmio_addr + DOORBELL, (i << 16) | j, 1);
+ }
+ }
+}
+
+/* this function increase the dynamic storage need to store data about other
+ * guests */
+static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
+
+ int j, old_nb_alloc;
+
+ old_nb_alloc = s->nb_peers;
+
+ while (new_min_size >= s->nb_peers)
+ s->nb_peers = s->nb_peers * 2;
+
+ IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
+ s->peers = qemu_realloc(s->peers, s->nb_peers * sizeof(Peer));
+
+ /* zero out new pointers */
+ for (j = old_nb_alloc; j < s->nb_peers; j++) {
+ s->peers[j].eventfds = NULL;
+ s->peers[j].nb_eventfds = 0;
+ }
+}
+
+static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
+{
+ IVShmemState *s = opaque;
+ int incoming_fd, tmp_fd;
+ int guest_max_eventfd;
+ long incoming_posn;
+
+ memcpy(&incoming_posn, buf, sizeof(long));
+ /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
+ tmp_fd = qemu_chr_get_msgfd(s->server_chr);
+ IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
+
+ /* make sure we have enough space for this guest */
+ if (incoming_posn >= s->nb_peers) {
+ increase_dynamic_storage(s, incoming_posn);
+ }
+
+ if (tmp_fd == -1) {
+ /* if posn is positive and unseen before then this is our posn*/
+ if ((incoming_posn >= 0) &&
+ (s->peers[incoming_posn].eventfds == NULL)) {
+ /* receive our posn */
+ s->vm_id = incoming_posn;
+ return;
+ } else {
+ /* otherwise an fd == -1 means an existing guest has gone away */
+ IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
+ close_guest_eventfds(s, incoming_posn);
+ return;
+ }
+ }
+
+ /* because of the implementation of get_msgfd, we need a dup */
+ incoming_fd = dup(tmp_fd);
+
+ if (incoming_fd == -1) {
+ fprintf(stderr, "could not allocate file descriptor %s\n",
+ strerror(errno));
+ return;
+ }
+
+ /* if the position is -1, then it's shared memory region fd */
+ if (incoming_posn == -1) {
+
+ void * map_ptr;
+
+ s->max_peer = 0;
+
+ if (check_shm_size(s, incoming_fd) == -1) {
+ exit(-1);
+ }
+
+ /* mmap the region and map into the BAR2 */
+ map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
+ incoming_fd, 0);
+ s->ivshmem_offset = qemu_ram_alloc_from_ptr(&s->dev.qdev,
+ "ivshmem.bar2", s->ivshmem_size, map_ptr);
+
+ IVSHMEM_DPRINTF("guest pci addr = %" FMT_PCIBUS ", guest h/w addr = %"
+ PRIu64 ", size = %" PRIu64 "\n", s->shm_pci_addr,
+ s->ivshmem_offset, s->ivshmem_size);
+
+ if (s->shm_pci_addr > 0) {
+ /* map memory into BAR2 */
+ cpu_register_physical_memory(s->shm_pci_addr, s->ivshmem_size,
+ s->ivshmem_offset);
+ }
+
+ /* only store the fd if it is successfully mapped */
+ s->shm_fd = incoming_fd;
+
+ return;
+ }
+
+ /* each guest has an array of eventfds, and we keep track of how many
+ * guests for each VM */
+ guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
+
+ if (guest_max_eventfd == 0) {
+ /* one eventfd per MSI vector */
+ s->peers[incoming_posn].eventfds = (int *) qemu_malloc(s->vectors *
+ sizeof(int));
+ }
+
+ /* this is an eventfd for a particular guest VM */
+ IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
+ guest_max_eventfd, incoming_fd);
+ s->peers[incoming_posn].eventfds[guest_max_eventfd] = incoming_fd;
+
+ /* increment count for particular guest */
+ s->peers[incoming_posn].nb_eventfds++;
+
+ /* keep track of the maximum VM ID */
+ if (incoming_posn > s->max_peer) {
+ s->max_peer = incoming_posn;
+ }
+
+ if (incoming_posn == s->vm_id) {
+ s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
+ s->peers[s->vm_id].eventfds[guest_max_eventfd],
+ guest_max_eventfd);
+ }
+
+ if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+ if (kvm_set_ioeventfd_mmio_long(incoming_fd, s->mmio_addr + DOORBELL,
+ (incoming_posn << 16) | guest_max_eventfd, 1) < 0) {
+ fprintf(stderr, "ivshmem: ioeventfd not available\n");
+ }
+ }
+
+ return;
+}
+
+static void ivshmem_reset(DeviceState *d)
+{
+ IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
+
+ s->intrstatus = 0;
+ return;
+}
+
+static void ivshmem_mmio_map(PCIDevice *pci_dev, int region_num,
+ pcibus_t addr, pcibus_t size, int type)
+{
+ IVShmemState *s = DO_UPCAST(IVShmemState, dev, pci_dev);
+
+ s->mmio_addr = addr;
+ cpu_register_physical_memory(addr + 0, IVSHMEM_REG_BAR_SIZE,
+ s->ivshmem_mmio_io_addr);
+
+ if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+ setup_ioeventfds(s);
+ }
+}
+
+static uint64_t ivshmem_get_size(IVShmemState * s) {
+
+ uint64_t value;
+ char *ptr;
+
+ value = strtoull(s->sizearg, &ptr, 10);
+ switch (*ptr) {
+ case 0: case 'M': case 'm':
+ value <<= 20;
+ break;
+ case 'G': case 'g':
+ value <<= 30;
+ break;
+ default:
+ fprintf(stderr, "qemu: invalid ram size: %s\n", s->sizearg);
+ exit(1);
+ }
+
+ /* BARs must be a power of 2 */
+ if (!is_power_of_two(value)) {
+ fprintf(stderr, "ivshmem: size must be power of 2\n");
+ exit(1);
+ }
+
+ return value;
+}
+
+static void ivshmem_setup_msi(IVShmemState * s) {
+
+ int i;
+
+ /* allocate the MSI-X vectors */
+
+ if (!msix_init(&s->dev, s->vectors, 1, 0)) {
+ pci_register_bar(&s->dev, 1,
+ msix_bar_size(&s->dev),
+ PCI_BASE_ADDRESS_SPACE_MEMORY,
+ msix_mmio_map);
+ IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
+ } else {
+ IVSHMEM_DPRINTF("msix initialization failed\n");
+ exit(1);
+ }
+
+ /* 'activate' the vectors */
+ for (i = 0; i < s->vectors; i++) {
+ msix_vector_use(&s->dev, i);
+ }
+
+ /* allocate Qemu char devices for receiving interrupts */
+ s->eventfd_table = qemu_mallocz(s->vectors * sizeof(EventfdEntry));
+}
+
+static void ivshmem_save(QEMUFile* f, void *opaque)
+{
+ IVShmemState *proxy = opaque;
+
+ IVSHMEM_DPRINTF("ivshmem_save\n");
+ pci_device_save(&proxy->dev, f);
+
+ if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
+ msix_save(&proxy->dev, f);
+ } else {
+ qemu_put_be32(f, proxy->intrstatus);
+ qemu_put_be32(f, proxy->intrmask);
+ }
+
+}
+
+static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
+{
+ IVSHMEM_DPRINTF("ivshmem_load\n");
+
+ IVShmemState *proxy = opaque;
+ int ret, i;
+
+ if (version_id > 0) {
+ return -EINVAL;
+ }
+
+ if (proxy->role_val == IVSHMEM_PEER) {
+ fprintf(stderr, "ivshmem: 'peer' devices are not migratable\n");
+ return -EINVAL;
+ }
+
+ ret = pci_device_load(&proxy->dev, f);
+ if (ret) {
+ return ret;
+ }
+
+ if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
+ msix_load(&proxy->dev, f);
+ for (i = 0; i < proxy->vectors; i++) {
+ msix_vector_use(&proxy->dev, i);
+ }
+ } else {
+ proxy->intrstatus = qemu_get_be32(f);
+ proxy->intrmask = qemu_get_be32(f);
+ }
+
+ return 0;
+}
+
+static int pci_ivshmem_init(PCIDevice *dev)
+{
+ IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
+ uint8_t *pci_conf;
+
+ if (s->sizearg == NULL)
+ s->ivshmem_size = 4 << 20; /* 4 MB default */
+ else {
+ s->ivshmem_size = ivshmem_get_size(s);
+ }
+
+ register_savevm(&s->dev.qdev, "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
+ dev);
+
+ /* IRQFD requires MSI */
+ if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
+ !ivshmem_has_feature(s, IVSHMEM_MSI)) {
+ fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n");
+ exit(1);
+ }
+
+ /* check that role is reasonable */
+ if (s->role) {
+ if (strncmp(s->role, "peer", 5) == 0) {
+ s->role_val = IVSHMEM_PEER;
+ } else if (strncmp(s->role, "master", 7) == 0) {
+ s->role_val = IVSHMEM_MASTER;
+ } else {
+ fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n");
+ exit(1);
+ }
+ } else {
+ s->role_val = IVSHMEM_MASTER; /* default */
+ }
+
+ if (s->role_val == IVSHMEM_PEER) {
+ register_device_unmigratable(&s->dev.qdev, "ivshmem", s);
+ }
+
+ pci_conf = s->dev.config;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REDHAT_QUMRANET);
+ pci_conf[0x02] = 0x10;
+ pci_conf[0x03] = 0x11;
+ pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+ pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_RAM);
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
+
+ pci_config_set_interrupt_pin(pci_conf, 1);
+
+ s->shm_pci_addr = 0;
+ s->ivshmem_offset = 0;
+ s->shm_fd = 0;
+
+ s->ivshmem_mmio_io_addr = cpu_register_io_memory(ivshmem_mmio_read,
+ ivshmem_mmio_write, s);
+ /* region for registers*/
+ pci_register_bar(&s->dev, 0, IVSHMEM_REG_BAR_SIZE,
+ PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_mmio_map);
+
+ if ((s->server_chr != NULL) &&
+ (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
+ /* if we get a UNIX socket as the parameter we will talk
+ * to the ivshmem server to receive the memory region */
+
+ if (s->shmobj != NULL) {
+ fprintf(stderr, "WARNING: do not specify both 'chardev' "
+ "and 'shm' with ivshmem\n");
+ }
+
+ IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
+ s->server_chr->filename);
+
+ if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
+ ivshmem_setup_msi(s);
+ }
+
+ /* we allocate enough space for 16 guests and grow as needed */
+ s->nb_peers = 16;
+ s->vm_id = -1;
+
+ /* allocate/initialize space for interrupt handling */
+ s->peers = qemu_mallocz(s->nb_peers * sizeof(Peer));
+
+ pci_register_bar(&s->dev, 2, s->ivshmem_size,
+ PCI_BASE_ADDRESS_SPACE_MEMORY, ivshmem_map);
+
+ s->eventfd_chr = qemu_mallocz(s->vectors * sizeof(CharDriverState *));
+
+ qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
+ ivshmem_event, s);
+ } else {
+ /* just map the file immediately, we're not using a server */
+ int fd;
+
+ if (s->shmobj == NULL) {
+ fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n");
+ }
+
+ IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
+
+ /* try opening with O_EXCL and if it succeeds zero the memory
+ * by truncating to 0 */
+ if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL,
+ S_IRWXU|S_IRWXG|S_IRWXO)) > 0) {
+ /* truncate file to length PCI device's memory */
+ if (ftruncate(fd, s->ivshmem_size) != 0) {
+ fprintf(stderr, "ivshmem: could not truncate shared file\n");
+ }
+
+ } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
+ S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
+ fprintf(stderr, "ivshmem: could not open shared file\n");
+ exit(-1);
+
+ }
+
+ if (check_shm_size(s, fd) == -1) {
+ exit(-1);
+ }
+
+ create_shared_memory_BAR(s, fd);
+
+ }
+
+ return 0;
+}
+
+static int pci_ivshmem_uninit(PCIDevice *dev)
+{
+ IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
+
+ cpu_unregister_io_memory(s->ivshmem_mmio_io_addr);
+ unregister_savevm(&dev->qdev, "ivshmem", s);
+
+ return 0;
+}
+
+static PCIDeviceInfo ivshmem_info = {
+ .qdev.name = "ivshmem",
+ .qdev.size = sizeof(IVShmemState),
+ .qdev.reset = ivshmem_reset,
+ .init = pci_ivshmem_init,
+ .exit = pci_ivshmem_uninit,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
+ DEFINE_PROP_STRING("size", IVShmemState, sizearg),
+ DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
+ DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
+ DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
+ DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
+ DEFINE_PROP_STRING("role", IVShmemState, role),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void ivshmem_register_devices(void)
+{
+ pci_qdev_register(&ivshmem_info);
+}
+
+device_init(ivshmem_register_devices)
diff --git a/hw/jazz_led.c b/hw/jazz_led.c
index 18780e9371..4cb680c3e4 100644
--- a/hw/jazz_led.c
+++ b/hw/jazz_led.c
@@ -29,6 +29,15 @@
//#define DEBUG_LED
+#ifdef DEBUG_LED
+#define DPRINTF(fmt, ...) \
+do { printf("jazz led: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "jazz led ERROR: " fmt , ## __VA_ARGS__);} while (0)
+
typedef enum {
REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2,
} screen_state_t;
@@ -49,12 +58,12 @@ static uint32_t led_readb(void *opaque, target_phys_addr_t addr)
val = s->segments;
break;
default:
-#ifdef DEBUG_LED
- printf("jazz led: invalid read [0x%x]\n", relative_addr);
-#endif
+ BADF("invalid read at [" TARGET_FMT_plx "]\n", addr);
val = 0;
}
+ DPRINTF("read addr=" TARGET_FMT_plx " val=0x%02x\n", addr, val);
+
return val;
}
@@ -92,15 +101,15 @@ static void led_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
LedState *s = opaque;
+ DPRINTF("write addr=" TARGET_FMT_plx " val=0x%02x\n", addr, val);
+
switch (addr) {
case 0:
s->segments = val;
s->state |= REDRAW_SEGMENTS;
break;
default:
-#ifdef DEBUG_LED
- printf("jazz led: invalid write of 0x%02x at [0x%x]\n", val, relative_addr);
-#endif
+ BADF("invalid write of 0x%08x at [" TARGET_FMT_plx "]\n", val, addr);
break;
}
}
diff --git a/hw/loader.c b/hw/loader.c
index 79a6f95186..49ac1fa1cc 100644
--- a/hw/loader.c
+++ b/hw/loader.c
@@ -733,11 +733,6 @@ int rom_copy(uint8_t *dest, target_phys_addr_t addr, size_t size)
s = rom->data;
l = rom->romsize;
- if (rom->addr < addr) {
- d = dest;
- s += (addr - rom->addr);
- l -= (addr - rom->addr);
- }
if ((d + l) > (dest + size)) {
l = dest - d;
}
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index bd7b661426..f97335eaa9 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -600,7 +600,7 @@ static void lsi_queue_command(LSIState *s)
{
lsi_request *p = s->current;
- DPRINTF("Queueing tag=0x%x\n", s->current_tag);
+ DPRINTF("Queueing tag=0x%x\n", p->tag);
assert(s->current != NULL);
assert(s->current->dma_len == 0);
QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
@@ -864,6 +864,7 @@ static void lsi_do_msgout(LSIState *s)
case 0x01:
len = lsi_get_msgbyte(s);
msg = lsi_get_msgbyte(s);
+ (void)len; /* avoid a warning about unused variable*/
DPRINTF("Extended message 0x%x (len %d)\n", msg, len);
switch (msg) {
case 1:
@@ -880,7 +881,7 @@ static void lsi_do_msgout(LSIState *s)
break;
case 0x20: /* SIMPLE queue */
s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
- DPRINTF("SIMPLE queue tag=0x%x\n", s->current_tag & 0xff);
+ DPRINTF("SIMPLE queue tag=0x%x\n", s->select_tag & 0xff);
break;
case 0x21: /* HEAD of queue */
BADF("HEAD queue not implemented\n");
diff --git a/hw/mainstone.c b/hw/mainstone.c
index cba7e63b3c..efa2959c72 100644
--- a/hw/mainstone.c
+++ b/hw/mainstone.c
@@ -17,6 +17,7 @@
#include "mainstone.h"
#include "sysemu.h"
#include "flash.h"
+#include "blockdev.h"
static struct keymap map[0xE0] = {
[0 ... 0xDF] = { -1, -1 },
diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c
index a9bbff64b3..07eb9eeba1 100644
--- a/hw/mips_fulong2e.c
+++ b/hw/mips_fulong2e.c
@@ -37,6 +37,7 @@
#include "elf.h"
#include "vt82c686.h"
#include "mc146818rtc.h"
+#include "blockdev.h"
#define DEBUG_FULONG2E_INIT
@@ -75,7 +76,8 @@ static struct _loaderparams {
const char *initrd_filename;
} loaderparams;
-static void prom_set(uint32_t* prom_buf, int index, const char *string, ...)
+static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
+ const char *string, ...)
{
va_list ap;
int32_t table_addr;
@@ -140,13 +142,13 @@ static int64_t load_kernel (CPUState *env)
prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
prom_buf = qemu_malloc(prom_size);
- prom_set(prom_buf, index++, loaderparams.kernel_filename);
+ prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename);
if (initrd_size > 0) {
- prom_set(prom_buf, index++, "rd_start=0x" PRIx64 " rd_size=%li %s",
+ prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
loaderparams.kernel_cmdline);
} else {
- prom_set(prom_buf, index++, loaderparams.kernel_cmdline);
+ prom_set(prom_buf, index++, "%s", loaderparams.kernel_cmdline);
}
/* Setup minimum environment variables */
@@ -219,8 +221,8 @@ uint8_t eeprom_spd[0x80] = {
#ifdef HAS_AUDIO
static void audio_init (PCIBus *pci_bus)
{
- vt82c686b_ac97_init(pci_bus, (FULONG2E_VIA_SLOT << 3) + 5);
- vt82c686b_mc97_init(pci_bus, (FULONG2E_VIA_SLOT << 3) + 6);
+ vt82c686b_ac97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 5));
+ vt82c686b_mc97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 6));
}
#endif
@@ -257,19 +259,17 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
{
char *filename;
unsigned long ram_offset, bios_offset;
- unsigned long bios_size;
+ long bios_size;
int64_t kernel_entry;
qemu_irq *i8259;
qemu_irq *cpu_exit_irq;
int via_devfn;
PCIBus *pci_bus;
- ISADevice *isa_dev;
uint8_t *eeprom_buf;
i2c_bus *smbus;
int i;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
DeviceState *eeprom;
- ISADevice *rtc_state;
CPUState *env;
/* init CPUs */
@@ -295,7 +295,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
ram_offset = qemu_ram_alloc(NULL, "fulong2e.ram", ram_size);
bios_offset = qemu_ram_alloc(NULL, "fulong2e.bios", bios_size);
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+ cpu_register_physical_memory(0, ram_size, ram_offset);
cpu_register_physical_memory(0x1fc00000LL,
bios_size, bios_offset | IO_MEM_ROM);
@@ -349,18 +349,18 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
}
- via_devfn = vt82c686b_init(pci_bus, FULONG2E_VIA_SLOT << 3);
+ via_devfn = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0));
if (via_devfn < 0) {
fprintf(stderr, "vt82c686b_init error \n");
exit(1);
}
isa_bus_irqs(i8259);
- vt82c686b_ide_init(pci_bus, hd, (FULONG2E_VIA_SLOT << 3) + 1);
- usb_uhci_vt82c686b_init(pci_bus, (FULONG2E_VIA_SLOT << 3) + 2);
- usb_uhci_vt82c686b_init(pci_bus, (FULONG2E_VIA_SLOT << 3) + 3);
+ vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1));
+ usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2));
+ usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 3));
- smbus = vt82c686b_pm_init(pci_bus, (FULONG2E_VIA_SLOT << 3) + 4,
+ smbus = vt82c686b_pm_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 4),
0xeee1, NULL);
eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
memcpy(eeprom_buf, eeprom_spd, sizeof(eeprom_spd));
@@ -376,9 +376,9 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
DMA_init(0, cpu_exit_irq);
/* Super I/O */
- isa_dev = isa_create_simple("i8042");
+ isa_create_simple("i8042");
- rtc_state = rtc_init(2000, NULL);
+ rtc_init(2000, NULL);
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
diff --git a/hw/mips_int.c b/hw/mips_int.c
index c30954caaf..477f6abf95 100644
--- a/hw/mips_int.c
+++ b/hw/mips_int.c
@@ -24,22 +24,6 @@
#include "mips_cpudevs.h"
#include "cpu.h"
-/* Raise IRQ to CPU if necessary. It must be called every time the active
- IRQ may change */
-void cpu_mips_update_irq(CPUState *env)
-{
- if ((env->CP0_Status & (1 << CP0St_IE)) &&
- !(env->CP0_Status & (1 << CP0St_EXL)) &&
- !(env->CP0_Status & (1 << CP0St_ERL)) &&
- !(env->hflags & MIPS_HFLAG_DM)) {
- if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
- !(env->interrupt_request & CPU_INTERRUPT_HARD)) {
- cpu_interrupt(env, CPU_INTERRUPT_HARD);
- }
- } else
- cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-}
-
static void cpu_mips_irq_request(void *opaque, int irq, int level)
{
CPUState *env = (CPUState *)opaque;
@@ -52,7 +36,12 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level)
} else {
env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP));
}
- cpu_mips_update_irq(env);
+
+ if (env->CP0_Cause & CP0Ca_IP_mask) {
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ } else {
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ }
}
void cpu_mips_irq_init_cpu(CPUState *env)
@@ -65,3 +54,12 @@ void cpu_mips_irq_init_cpu(CPUState *env)
env->irq[i] = qi[i];
}
}
+
+void cpu_mips_soft_irq(CPUState *env, int irq, int level)
+{
+ if (irq < 0 || irq > 2) {
+ return;
+ }
+
+ qemu_set_irq(env->irq[irq], level);
+}
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 71b05a203c..66397c0c9a 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -36,6 +36,7 @@
#include "mips-bios.h"
#include "loader.h"
#include "mc146818rtc.h"
+#include "blockdev.h"
enum jazz_model_e
{
@@ -136,7 +137,7 @@ void mips_jazz_init (ram_addr_t ram_size,
NICInfo *nd;
PITState *pit;
DriveInfo *fds[MAX_FD];
- qemu_irq esp_reset;
+ qemu_irq esp_reset, dma_enable;
qemu_irq *cpu_exit_irq;
ram_addr_t ram_offset;
ram_addr_t bios_offset;
@@ -244,7 +245,7 @@ void mips_jazz_init (ram_addr_t ram_size,
/* SCSI adapter */
esp_init(0x80002000, 0,
rc4030_dma_read, rc4030_dma_write, dmas[0],
- rc4030[5], &esp_reset);
+ rc4030[5], &esp_reset, &dma_enable);
/* Floppy */
if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) {
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 11e220a944..80260714ec 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -45,6 +45,7 @@
#include "loader.h"
#include "elf.h"
#include "mc146818rtc.h"
+#include "blockdev.h"
//#define DEBUG_BOARD_INIT
@@ -653,7 +654,8 @@ static void write_bootloader (CPUState *env, uint8_t *base,
}
-static void prom_set(uint32_t* prom_buf, int index, const char *string, ...)
+static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index,
+ const char *string, ...)
{
va_list ap;
int32_t table_addr;
@@ -727,13 +729,13 @@ static int64_t load_kernel (void)
prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
prom_buf = qemu_malloc(prom_size);
- prom_set(prom_buf, prom_index++, loaderparams.kernel_filename);
+ prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename);
if (initrd_size > 0) {
prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s",
cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size,
loaderparams.kernel_cmdline);
} else {
- prom_set(prom_buf, prom_index++, loaderparams.kernel_cmdline);
+ prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_cmdline);
}
prom_set(prom_buf, prom_index++, "memsize");
@@ -782,11 +784,7 @@ void mips_malta_init (ram_addr_t ram_size,
target_long bios_size;
int64_t kernel_entry;
PCIBus *pci_bus;
- ISADevice *isa_dev;
CPUState *env;
- ISADevice *rtc_state;
- FDCtrl *floppy_controller;
- MaltaFPGAState *malta_fpga;
qemu_irq *i8259;
qemu_irq *cpu_exit_irq;
int piix4_devfn;
@@ -849,7 +847,7 @@ void mips_malta_init (ram_addr_t ram_size,
be = 0;
#endif
/* FPGA */
- malta_fpga = malta_fpga_init(0x1f000000LL, env->irq[2], serial_hds[2]);
+ malta_fpga_init(0x1f000000LL, env->irq[2], serial_hds[2]);
/* Load firmware in flash / BIOS unless we boot directly into a kernel. */
if (kernel_filename) {
@@ -955,9 +953,9 @@ void mips_malta_init (ram_addr_t ram_size,
DMA_init(0, cpu_exit_irq);
/* Super I/O */
- isa_dev = isa_create_simple("i8042");
-
- rtc_state = rtc_init(2000, NULL);
+ isa_create_simple("i8042");
+
+ rtc_init(2000, NULL);
serial_isa_init(0, serial_hds[0]);
serial_isa_init(1, serial_hds[1]);
if (parallel_hds[0])
@@ -965,7 +963,7 @@ void mips_malta_init (ram_addr_t ram_size,
for(i = 0; i < MAX_FD; i++) {
fd[i] = drive_get(IF_FLOPPY, 0, i);
}
- floppy_controller = fdctrl_init_isa(fd);
+ fdctrl_init_isa(fd);
/* Sound card */
audio_init(pci_bus);
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 61cd33a93c..aa348904ad 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -22,6 +22,7 @@
#include "loader.h"
#include "elf.h"
#include "mc146818rtc.h"
+#include "blockdev.h"
#define MAX_IDE_BUS 2
@@ -166,7 +167,6 @@ void mips_r4k_init (ram_addr_t ram_size,
int bios_size;
CPUState *env;
ResetData *reset_info;
- ISADevice *rtc_state;
int i;
qemu_irq *i8259;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
@@ -267,7 +267,7 @@ void mips_r4k_init (ram_addr_t ram_size,
isa_bus_new(NULL);
isa_bus_irqs(i8259);
- rtc_state = rtc_init(2000, NULL);
+ rtc_init(2000, NULL);
/* Register 64 KB of ISA IO space at 0x14000000 */
#ifdef TARGET_WORDS_BIGENDIAN
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index a95b3ce07b..c5e54ffc35 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -81,7 +81,7 @@ static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t s
MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
#ifdef DEBUG_MIPSNET_RECEIVE
- printf("mipsnet: receiving len=%d\n", size);
+ printf("mipsnet: receiving len=%zu\n", size);
#endif
if (!mipsnet_can_receive(nc))
return -1;
diff --git a/hw/msix.c b/hw/msix.c
index b202ff7d85..f66d2550a7 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -14,6 +14,7 @@
#include "hw.h"
#include "msix.h"
#include "pci.h"
+#include "range.h"
/* MSI-X capability structure */
#define MSIX_TABLE_OFFSET 4
diff --git a/hw/multiboot.c b/hw/multiboot.c
index dc980e6498..f9097a2f60 100644
--- a/hw/multiboot.c
+++ b/hw/multiboot.c
@@ -252,7 +252,7 @@ int load_multiboot(void *fw_cfg,
do {
char *next_space;
- uint32_t mb_mod_length;
+ int mb_mod_length;
uint32_t offs = mbs.mb_buf_size;
next_initrd = strchr(initrd_filename, ',');
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 33180a2656..56f27669d2 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -18,6 +18,7 @@
#include "flash.h"
#include "console.h"
#include "i2c.h"
+#include "blockdev.h"
#define MP_MISC_BASE 0x80002000
#define MP_MISC_SIZE 0x00001000
diff --git a/hw/omap.h b/hw/omap.h
index 18eb72b82f..fe32ca5c4c 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -664,10 +664,12 @@ void omap_synctimer_reset(struct omap_synctimer_s *s);
struct omap_uart_s;
struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr);
+ qemu_irq txdma, qemu_irq rxdma,
+ const char *label, CharDriverState *chr);
struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr);
+ qemu_irq txdma, qemu_irq rxdma,
+ const char *label, CharDriverState *chr);
void omap_uart_reset(struct omap_uart_s *s);
void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr);
diff --git a/hw/omap1.c b/hw/omap1.c
index cf0d428692..f4966f74b6 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -25,6 +25,8 @@
#include "soc_dma.h"
/* We use pc-style serial ports. */
#include "pc.h"
+#include "blockdev.h"
+#include "range.h"
/* Should signal the TCMI/GPMC */
uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr)
@@ -3668,37 +3670,38 @@ static const struct dma_irq_map omap1_dma_irq_map[] = {
static int omap_validate_emiff_addr(struct omap_mpu_state_s *s,
target_phys_addr_t addr)
{
- return addr >= OMAP_EMIFF_BASE && addr < OMAP_EMIFF_BASE + s->sdram_size;
+ return range_covers_byte(OMAP_EMIFF_BASE, s->sdram_size, addr);
}
static int omap_validate_emifs_addr(struct omap_mpu_state_s *s,
target_phys_addr_t addr)
{
- return addr >= OMAP_EMIFS_BASE && addr < OMAP_EMIFF_BASE;
+ return range_covers_byte(OMAP_EMIFS_BASE, OMAP_EMIFF_BASE - OMAP_EMIFS_BASE,
+ addr);
}
static int omap_validate_imif_addr(struct omap_mpu_state_s *s,
target_phys_addr_t addr)
{
- return addr >= OMAP_IMIF_BASE && addr < OMAP_IMIF_BASE + s->sram_size;
+ return range_covers_byte(OMAP_IMIF_BASE, s->sram_size, addr);
}
static int omap_validate_tipb_addr(struct omap_mpu_state_s *s,
target_phys_addr_t addr)
{
- return addr >= 0xfffb0000 && addr < 0xffff0000;
+ return range_covers_byte(0xfffb0000, 0xffff0000 - 0xfffb0000, addr);
}
static int omap_validate_local_addr(struct omap_mpu_state_s *s,
target_phys_addr_t addr)
{
- return addr >= OMAP_LOCALBUS_BASE && addr < OMAP_LOCALBUS_BASE + 0x1000000;
+ return range_covers_byte(OMAP_LOCALBUS_BASE, 0x1000000, addr);
}
static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s,
target_phys_addr_t addr)
{
- return addr >= 0xe1010000 && addr < 0xe1020004;
+ return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr);
}
struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
@@ -3808,16 +3811,19 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
omap_findclk(s, "uart1_ck"),
omap_findclk(s, "uart1_ck"),
s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX],
+ "uart1",
serial_hds[0]);
s->uart[1] = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2],
omap_findclk(s, "uart2_ck"),
omap_findclk(s, "uart2_ck"),
s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX],
+ "uart2",
serial_hds[0] ? serial_hds[1] : NULL);
s->uart[2] = omap_uart_init(0xfffb9800, s->irq[0][OMAP_INT_UART3],
omap_findclk(s, "uart3_ck"),
omap_findclk(s, "uart3_ck"),
s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX],
+ "uart3",
serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
omap_dpll_init(&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1"));
diff --git a/hw/omap2.c b/hw/omap2.c
index 179075e996..e35a56e043 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -2291,13 +2291,16 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
omap_findclk(s, "uart1_fclk"),
omap_findclk(s, "uart1_iclk"),
s->drq[OMAP24XX_DMA_UART1_TX],
- s->drq[OMAP24XX_DMA_UART1_RX], serial_hds[0]);
+ s->drq[OMAP24XX_DMA_UART1_RX],
+ "uart1",
+ serial_hds[0]);
s->uart[1] = omap2_uart_init(omap_l4ta(s->l4, 20),
s->irq[0][OMAP_INT_24XX_UART2_IRQ],
omap_findclk(s, "uart2_fclk"),
omap_findclk(s, "uart2_iclk"),
s->drq[OMAP24XX_DMA_UART2_TX],
s->drq[OMAP24XX_DMA_UART2_RX],
+ "uart2",
serial_hds[0] ? serial_hds[1] : NULL);
s->uart[2] = omap2_uart_init(omap_l4ta(s->l4, 21),
s->irq[0][OMAP_INT_24XX_UART3_IRQ],
@@ -2305,6 +2308,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
omap_findclk(s, "uart3_iclk"),
s->drq[OMAP24XX_DMA_UART3_TX],
s->drq[OMAP24XX_DMA_UART3_RX],
+ "uart3",
serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7),
diff --git a/hw/omap_clk.c b/hw/omap_clk.c
index 6bcabef8ac..10c9c4308c 100644
--- a/hw/omap_clk.c
+++ b/hw/omap_clk.c
@@ -20,6 +20,7 @@
*/
#include "hw.h"
#include "omap.h"
+#include "qemu-timer.h" /* for muldiv64() */
struct clk {
const char *name;
diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c
index d7c18882da..d133977e7f 100644
--- a/hw/omap_i2c.c
+++ b/hw/omap_i2c.c
@@ -190,8 +190,9 @@ static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr)
if (s->rxlen > 2)
s->fifo >>= 16;
s->rxlen -= 2;
- } else
- /* XXX: remote access (qualifier) error - what's that? */;
+ } else {
+ /* XXX: remote access (qualifier) error - what's that? */
+ }
if (!s->rxlen) {
s->stat &= ~(1 << 3); /* RRDY */
if (((s->control >> 10) & 1) && /* MST */
diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c
index 15cbf06c87..9d167ff535 100644
--- a/hw/omap_mmc.c
+++ b/hw/omap_mmc.c
@@ -559,8 +559,9 @@ static void omap_mmc_cover_cb(void *opaque, int line, int level)
if (!host->cdet_state && level) {
host->status |= 0x0002;
omap_mmc_interrupts_update(host);
- if (host->cdet_wakeup)
- /* TODO: Assert wake-up */;
+ if (host->cdet_wakeup) {
+ /* TODO: Assert wake-up */
+ }
}
if (host->cdet_state != level) {
diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c
index c3f197393d..44dc514f3f 100644
--- a/hw/omap_sx1.c
+++ b/hw/omap_sx1.c
@@ -32,6 +32,7 @@
#include "boards.h"
#include "arm-misc.h"
#include "flash.h"
+#include "blockdev.h"
/*****************************************************************************/
/* Siemens SX1 Cellphone V1 */
diff --git a/hw/omap_uart.c b/hw/omap_uart.c
index 395bf0ccbb..cc66cd9d94 100644
--- a/hw/omap_uart.c
+++ b/hw/omap_uart.c
@@ -51,7 +51,8 @@ void omap_uart_reset(struct omap_uart_s *s)
struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr)
+ qemu_irq txdma, qemu_irq rxdma,
+ const char *label, CharDriverState *chr)
{
struct omap_uart_s *s = (struct omap_uart_s *)
qemu_mallocz(sizeof(struct omap_uart_s));
@@ -61,11 +62,11 @@ struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
s->irq = irq;
#ifdef TARGET_WORDS_BIGENDIAN
s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
- chr ?: qemu_chr_open("null", "null", NULL), 1,
+ chr ?: qemu_chr_open(label, "null", NULL), 1,
1);
#else
s->serial = serial_mm_init(base, 2, irq, omap_clk_getrate(fclk)/16,
- chr ?: qemu_chr_open("null", "null", NULL), 1,
+ chr ?: qemu_chr_open(label, "null", NULL), 1,
0);
#endif
return s;
@@ -162,11 +163,12 @@ static CPUWriteMemoryFunc * const omap_uart_writefn[] = {
struct omap_uart_s *omap2_uart_init(struct omap_target_agent_s *ta,
qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma, CharDriverState *chr)
+ qemu_irq txdma, qemu_irq rxdma,
+ const char *label, CharDriverState *chr)
{
target_phys_addr_t base = omap_l4_attach(ta, 0, 0);
struct omap_uart_s *s = omap_uart_init(base, irq,
- fclk, iclk, txdma, rxdma, chr);
+ fclk, iclk, txdma, rxdma, label, chr);
int iomemtype = cpu_register_io_memory(omap_uart_readfn,
omap_uart_writefn, s);
diff --git a/hw/pc.c b/hw/pc.c
index a96187f5b5..69b13bf62c 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -39,6 +39,7 @@
#include "msix.h"
#include "sysbus.h"
#include "sysemu.h"
+#include "blockdev.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
@@ -916,8 +917,10 @@ void pc_memory_init(ram_addr_t ram_size,
below_4g_mem_size - 0x100000,
ram_addr + 0x100000);
#if TARGET_PHYS_ADDR_BITS > 32
- cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
- ram_addr + below_4g_mem_size);
+ if (above_4g_mem_size > 0) {
+ cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
+ ram_addr + below_4g_mem_size);
+ }
#endif
/* BIOS load */
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 519e8a5ccb..12359a75c9 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -34,6 +34,7 @@
#include "kvm.h"
#include "sysemu.h"
#include "sysbus.h"
+#include "blockdev.h"
#define MAX_IDE_BUS 2
@@ -103,6 +104,7 @@ static void pc_init1(ram_addr_t ram_size,
pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
} else {
pci_bus = NULL;
+ i440fx_state = NULL;
isa_bus_new(NULL);
}
isa_bus_irqs(isa_irq);
@@ -226,7 +228,7 @@ static QEMUMachine pc_machine_v0_12 = {
.compat_props = (GlobalProperty[]) {
{
.driver = "virtio-serial-pci",
- .property = "max_nr_ports",
+ .property = "max_ports",
.value = stringify(1),
},{
.driver = "virtio-serial-pci",
@@ -249,7 +251,7 @@ static QEMUMachine pc_machine_v0_11 = {
.value = stringify(0),
},{
.driver = "virtio-serial-pci",
- .property = "max_nr_ports",
+ .property = "max_ports",
.value = stringify(1),
},{
.driver = "virtio-serial-pci",
@@ -288,7 +290,7 @@ static QEMUMachine pc_machine_v0_10 = {
.value = stringify(PCI_CLASS_DISPLAY_OTHER),
},{
.driver = "virtio-serial-pci",
- .property = "max_nr_ports",
+ .property = "max_ports",
.value = stringify(1),
},{
.driver = "virtio-serial-pci",
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index c38f47fbf1..716133c376 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -31,6 +31,7 @@
#include "scsi.h"
#include "virtio-blk.h"
#include "qemu-config.h"
+#include "blockdev.h"
#if defined(TARGET_I386)
static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
@@ -51,7 +52,7 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
return NULL;
}
- opts = qemu_opts_parse(&qemu_net_opts, opts_str ? opts_str : "", 0);
+ opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0);
if (!opts) {
return NULL;
}
diff --git a/hw/pci.c b/hw/pci.c
index 5386f5a083..962886e767 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -32,6 +32,7 @@
#include "sysemu.h"
#include "loader.h"
#include "qemu-objects.h"
+#include "range.h"
//#define DEBUG_PCI
#ifdef DEBUG_PCI
@@ -585,7 +586,7 @@ static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)
}
/*
- * multifuction bit is interpreted in two ways as follows.
+ * multifunction bit is interpreted in two ways as follows.
* - all functions must set the bit to 1.
* Example: Intel X53
* - function 0 must set the bit, but the rest function (> 0)
diff --git a/hw/pci.h b/hw/pci.h
index d6c522b8dd..7100804e7c 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -448,33 +448,4 @@ static inline uint32_t pci_config_size(const PCIDevice *d)
return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;
}
-/* These are not pci specific. Should move into a separate header.
- * Only pci.c uses them, so keep them here for now.
- */
-
-/* Get last byte of a range from offset + length.
- * Undefined for ranges that wrap around 0. */
-static inline uint64_t range_get_last(uint64_t offset, uint64_t len)
-{
- return offset + len - 1;
-}
-
-/* Check whether a given range covers a given byte. */
-static inline int range_covers_byte(uint64_t offset, uint64_t len,
- uint64_t byte)
-{
- return offset <= byte && byte <= range_get_last(offset, len);
-}
-
-/* Check whether 2 given ranges overlap.
- * Undefined if ranges that wrap around 0. */
-static inline int ranges_overlap(uint64_t first1, uint64_t len1,
- uint64_t first2, uint64_t len2)
-{
- uint64_t last1 = range_get_last(first1, len1);
- uint64_t last2 = range_get_last(first2, len2);
-
- return !(last2 < first1 || last1 < first2);
-}
-
#endif
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 0533b1d9e3..6e4e4062ad 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -56,7 +56,9 @@
#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
-#define KBD_CCMD_RESET 0xFE
+#define KBD_CCMD_PULSE_BITS_3_0 0xF0 /* Pulse bits 3-0 of the output port P2. */
+#define KBD_CCMD_RESET 0xFE /* Pulse bit 0 of the output port P2 = CPU reset. */
+#define KBD_CCMD_NO_OP 0xFF /* Pulse no bits of the output port P2. */
/* Keyboard Commands */
#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
@@ -238,6 +240,21 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
KBDState *s = opaque;
DPRINTF("kbd: write cmd=0x%02x\n", val);
+
+ /* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
+ * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE
+ * command specify the output port bits to be pulsed.
+ * 0: Bit should be pulsed. 1: Bit should not be modified.
+ * The only useful version of this command is pulsing bit 0,
+ * which does a CPU reset.
+ */
+ if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
+ if(!(val & 1))
+ val = KBD_CCMD_RESET;
+ else
+ val = KBD_CCMD_NO_OP;
+ }
+
switch(val) {
case KBD_CCMD_READ_MODE:
kbd_queue(s, s->mode, 0);
@@ -294,8 +311,8 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
case KBD_CCMD_RESET:
qemu_system_reset_request();
break;
- case 0xff:
- /* ignore that - I don't know what is its use */
+ case KBD_CCMD_NO_OP:
+ /* ignore that */
break;
default:
fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
diff --git a/hw/pcmcia.h b/hw/pcmcia.h
index 360292395b..50648c973f 100644
--- a/hw/pcmcia.h
+++ b/hw/pcmcia.h
@@ -1,7 +1,6 @@
/* PCMCIA/Cardbus */
#include "qemu-common.h"
-#include "blockdev.h"
typedef struct {
qemu_irq irq;
diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c
index 70b6a36e1e..42de45963b 100644
--- a/hw/petalogix_s3adsp1800_mmu.c
+++ b/hw/petalogix_s3adsp1800_mmu.c
@@ -34,6 +34,7 @@
#include "xilinx.h"
#include "loader.h"
#include "elf.h"
+#include "blockdev.h"
#define LMB_BRAM_SIZE (128 * 1024)
#define FLASH_SIZE (16 * 1024 * 1024)
@@ -179,11 +180,22 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size,
}
/* Always boot into physical ram. */
boot_info.bootstrap_pc = ddr_base + (entry & 0x0fffffff);
+
+ /* If it wasn't an ELF image, try an u-boot image. */
+ if (kernel_size < 0) {
+ target_phys_addr_t uentry, loadaddr;
+
+ kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0);
+ boot_info.bootstrap_pc = uentry;
+ high = (loadaddr + kernel_size + 3) & ~3;
+ }
+
+ /* Not an ELF image nor an u-boot image, try a RAW image. */
if (kernel_size < 0) {
- /* If we failed loading ELF's try a raw image. */
kernel_size = load_image_targphys(kernel_filename, ddr_base,
ram_size);
boot_info.bootstrap_pc = ddr_base;
+ high = (ddr_base + kernel_size + 3) & ~3;
}
boot_info.cmdline = high + 4096;
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index f152a0ff06..b5589b9035 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -28,6 +28,7 @@
#include "pci_host.h"
#include "isa.h"
#include "sysbus.h"
+#include "range.h"
/*
* I440FX chipset data sheet.
diff --git a/hw/ppc.c b/hw/ppc.c
index 2a77eb9bff..968aec1b16 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -28,6 +28,8 @@
#include "nvram.h"
#include "qemu-log.h"
#include "loader.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
//#define PPC_DEBUG_IRQ
//#define PPC_DEBUG_TB
@@ -50,6 +52,8 @@ static void cpu_ppc_tb_start (CPUState *env);
static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
{
+ unsigned int old_pending = env->pending_interrupts;
+
if (level) {
env->pending_interrupts |= 1 << n_IRQ;
cpu_interrupt(env, CPU_INTERRUPT_HARD);
@@ -58,6 +62,13 @@ static void ppc_set_irq (CPUState *env, int n_IRQ, int level)
if (env->pending_interrupts == 0)
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
}
+
+ if (old_pending != env->pending_interrupts) {
+#ifdef CONFIG_KVM
+ kvmppc_set_interrupt(env, n_IRQ, level);
+#endif
+ }
+
LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32
"req %08x\n", __func__, env, n_IRQ, level,
env->pending_interrupts, env->interrupt_request);
@@ -758,6 +769,9 @@ struct ppcemb_timer_t {
struct QEMUTimer *fit_timer;
uint64_t wdt_next; /* Tick for next WDT interrupt */
struct QEMUTimer *wdt_timer;
+
+ /* 405 have the PIT, 440 have a DECR. */
+ unsigned int decr_excp;
};
/* Fixed interval timer */
@@ -840,7 +854,7 @@ static void cpu_4xx_pit_cb (void *opaque)
ppcemb_timer = tb_env->opaque;
env->spr[SPR_40x_TSR] |= 1 << 27;
if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
- ppc_set_irq(env, PPC_INTERRUPT_PIT, 1);
+ ppc_set_irq(env, ppcemb_timer->decr_excp, 1);
start_stop_pit(env, tb_env, 1);
LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " "
"%016" PRIx64 "\n", __func__,
@@ -937,10 +951,15 @@ target_ulong load_40x_pit (CPUState *env)
void store_booke_tsr (CPUState *env, target_ulong val)
{
+ ppc_tb_t *tb_env = env->tb_env;
+ ppcemb_timer_t *ppcemb_timer;
+
+ ppcemb_timer = tb_env->opaque;
+
LOG_TB("%s: val " TARGET_FMT_lx "\n", __func__, val);
env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
if (val & 0x80000000)
- ppc_set_irq(env, PPC_INTERRUPT_PIT, 0);
+ ppc_set_irq(env, ppcemb_timer->decr_excp, 0);
}
void store_booke_tcr (CPUState *env, target_ulong val)
@@ -966,7 +985,8 @@ static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
/* XXX: we should also update all timers */
}
-clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
+clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq,
+ unsigned int decr_excp)
{
ppc_tb_t *tb_env;
ppcemb_timer_t *ppcemb_timer;
@@ -985,6 +1005,7 @@ clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
ppcemb_timer->wdt_timer =
qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
+ ppcemb_timer->decr_excp = decr_excp;
}
return &ppc_emb_set_tb_clk;
diff --git a/hw/ppc.h b/hw/ppc.h
index de13092ae4..34f54cf5da 100644
--- a/hw/ppc.h
+++ b/hw/ppc.h
@@ -19,7 +19,9 @@ int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn),
int (*dcr_write_error)(int dcrn));
int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
dcr_read_cb drc_read, dcr_write_cb dcr_write);
-clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq);
+clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq,
+ unsigned int decr_excp);
+
/* Embedded PowerPC reset */
void ppc40x_core_reset (CPUState *env);
void ppc40x_chip_reset (CPUState *env);
@@ -47,5 +49,8 @@ enum {
#define FW_CFG_PPC_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
#define FW_CFG_PPC_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
#define FW_CFG_PPC_TBFREQ (FW_CFG_ARCH_LOCAL + 0x03)
+#define FW_CFG_PPC_IS_KVM (FW_CFG_ARCH_LOCAL + 0x05)
+#define FW_CFG_PPC_KVM_HC (FW_CFG_ARCH_LOCAL + 0x06)
+#define FW_CFG_PPC_KVM_PID (FW_CFG_ARCH_LOCAL + 0x07)
#define PPC_SERIAL_MM_BAUDBASE 399193
diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
index 40ff1b34ea..c5897a9d4d 100644
--- a/hw/ppc405_boards.c
+++ b/hw/ppc405_boards.c
@@ -31,6 +31,7 @@
#include "boards.h"
#include "qemu-log.h"
#include "loader.h"
+#include "blockdev.h"
#define BIOS_FILENAME "ppc405_rom.bin"
#define BIOS_SIZE (2048 * 1024)
@@ -181,10 +182,12 @@ static void ref405ep_init (ram_addr_t ram_size,
qemu_irq *pic;
ram_addr_t sram_offset, bios_offset, bdloc;
target_phys_addr_t ram_bases[2], ram_sizes[2];
- target_ulong sram_size, bios_size;
+ target_ulong sram_size;
+ long bios_size;
//int phy_addr = 0;
//static int phy_addr = 1;
- target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+ target_ulong kernel_base, initrd_base;
+ long kernel_size, initrd_size;
int linux_boot;
int fl_idx, fl_sectors, len;
DriveInfo *dinfo;
@@ -220,8 +223,8 @@ static void ref405ep_init (ram_addr_t ram_size,
bios_offset = qemu_ram_alloc(NULL, "ef405ep.bios", bios_size);
fl_sectors = (bios_size + 65535) >> 16;
#ifdef DEBUG_BOARD_INIT
- printf("Register parallel flash %d size " TARGET_FMT_lx
- " at offset %08lx addr " TARGET_FMT_lx " '%s' %d\n",
+ printf("Register parallel flash %d size %lx"
+ " at offset %08lx addr %lx '%s' %d\n",
fl_idx, bios_size, bios_offset, -bios_size,
bdrv_get_device_name(dinfo->bdrv), fl_sectors);
#endif
@@ -307,7 +310,7 @@ static void ref405ep_init (ram_addr_t ram_size,
kernel_filename);
exit(1);
}
- printf("Load kernel size " TARGET_FMT_ld " at " TARGET_FMT_lx,
+ printf("Load kernel size %ld at " TARGET_FMT_lx,
kernel_size, kernel_base);
/* load initrd */
if (initrd_filename) {
@@ -498,12 +501,12 @@ static void taihu_405ep_init(ram_addr_t ram_size,
const char *cpu_model)
{
char *filename;
- CPUPPCState *env;
qemu_irq *pic;
ram_addr_t bios_offset;
target_phys_addr_t ram_bases[2], ram_sizes[2];
- target_ulong bios_size;
- target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+ long bios_size;
+ target_ulong kernel_base, initrd_base;
+ long kernel_size, initrd_size;
int linux_boot;
int fl_idx, fl_sectors;
DriveInfo *dinfo;
@@ -517,8 +520,8 @@ static void taihu_405ep_init(ram_addr_t ram_size,
#ifdef DEBUG_BOARD_INIT
printf("%s: register cpu\n", __func__);
#endif
- env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic,
- kernel_filename == NULL ? 0 : 1);
+ ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic,
+ kernel_filename == NULL ? 0 : 1);
/* allocate and load BIOS */
#ifdef DEBUG_BOARD_INIT
printf("%s: register BIOS\n", __func__);
@@ -533,8 +536,8 @@ static void taihu_405ep_init(ram_addr_t ram_size,
fl_sectors = (bios_size + 65535) >> 16;
bios_offset = qemu_ram_alloc(NULL, "taihu_405ep.bios", bios_size);
#ifdef DEBUG_BOARD_INIT
- printf("Register parallel flash %d size " TARGET_FMT_lx
- " at offset %08lx addr " TARGET_FMT_lx " '%s' %d\n",
+ printf("Register parallel flash %d size %lx"
+ " at offset %08lx addr %lx '%s' %d\n",
fl_idx, bios_size, bios_offset, -bios_size,
bdrv_get_device_name(dinfo->bdrv), fl_sectors);
#endif
@@ -575,7 +578,7 @@ static void taihu_405ep_init(ram_addr_t ram_size,
bios_size = 32 * 1024 * 1024;
fl_sectors = (bios_size + 65535) >> 16;
#ifdef DEBUG_BOARD_INIT
- printf("Register parallel flash %d size " TARGET_FMT_lx
+ printf("Register parallel flash %d size %lx"
" at offset %08lx addr " TARGET_FMT_lx " '%s'\n",
fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000,
bdrv_get_device_name(dinfo->bdrv));
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
index b884ea5fbd..3600737412 100644
--- a/hw/ppc405_uc.c
+++ b/hw/ppc405_uc.c
@@ -630,18 +630,11 @@ struct ppc405_dma_t {
static uint32_t dcr_read_dma (void *opaque, int dcrn)
{
- ppc405_dma_t *dma;
-
- dma = opaque;
-
return 0;
}
static void dcr_write_dma (void *opaque, int dcrn, uint32_t val)
{
- ppc405_dma_t *dma;
-
- dma = opaque;
}
static void ppc405_dma_reset (void *opaque)
@@ -739,9 +732,6 @@ struct ppc405_gpio_t {
static uint32_t ppc405_gpio_readb (void *opaque, target_phys_addr_t addr)
{
- ppc405_gpio_t *gpio;
-
- gpio = opaque;
#ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
#endif
@@ -752,9 +742,6 @@ static uint32_t ppc405_gpio_readb (void *opaque, target_phys_addr_t addr)
static void ppc405_gpio_writeb (void *opaque,
target_phys_addr_t addr, uint32_t value)
{
- ppc405_gpio_t *gpio;
-
- gpio = opaque;
#ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
value);
@@ -763,9 +750,6 @@ static void ppc405_gpio_writeb (void *opaque,
static uint32_t ppc405_gpio_readw (void *opaque, target_phys_addr_t addr)
{
- ppc405_gpio_t *gpio;
-
- gpio = opaque;
#ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
#endif
@@ -776,9 +760,6 @@ static uint32_t ppc405_gpio_readw (void *opaque, target_phys_addr_t addr)
static void ppc405_gpio_writew (void *opaque,
target_phys_addr_t addr, uint32_t value)
{
- ppc405_gpio_t *gpio;
-
- gpio = opaque;
#ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
value);
@@ -787,9 +768,6 @@ static void ppc405_gpio_writew (void *opaque,
static uint32_t ppc405_gpio_readl (void *opaque, target_phys_addr_t addr)
{
- ppc405_gpio_t *gpio;
-
- gpio = opaque;
#ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
#endif
@@ -800,9 +778,6 @@ static uint32_t ppc405_gpio_readl (void *opaque, target_phys_addr_t addr)
static void ppc405_gpio_writel (void *opaque,
target_phys_addr_t addr, uint32_t value)
{
- ppc405_gpio_t *gpio;
-
- gpio = opaque;
#ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
value);
@@ -823,9 +798,6 @@ static CPUWriteMemoryFunc * const ppc405_gpio_write[] = {
static void ppc405_gpio_reset (void *opaque)
{
- ppc405_gpio_t *gpio;
-
- gpio = opaque;
}
static void ppc405_gpio_init(target_phys_addr_t base)
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 6ca873ee7e..34ddf45477 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -27,6 +27,11 @@
#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
+/* from u-boot */
+#define KERNEL_ADDR 0x1000000
+#define FDT_ADDR 0x1800000
+#define RAMDISK_ADDR 0x1900000
+
static int bamboo_load_device_tree(target_phys_addr_t addr,
uint32_t ramsize,
target_phys_addr_t initrd_base,
@@ -98,10 +103,8 @@ static void bamboo_init(ram_addr_t ram_size,
uint64_t elf_lowaddr;
target_phys_addr_t entry = 0;
target_phys_addr_t loadaddr = 0;
- target_long kernel_size = 0;
- target_ulong initrd_base = 0;
target_long initrd_size = 0;
- target_ulong dt_base = 0;
+ int success;
int i;
/* Setup CPU. */
@@ -118,15 +121,15 @@ static void bamboo_init(ram_addr_t ram_size,
/* Load kernel. */
if (kernel_filename) {
- kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
- if (kernel_size < 0) {
- kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
- &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+ success = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
+ if (success < 0) {
+ success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+ &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
entry = elf_entry;
loadaddr = elf_lowaddr;
}
/* XXX try again as binary */
- if (kernel_size < 0) {
+ if (success < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
@@ -135,26 +138,20 @@ static void bamboo_init(ram_addr_t ram_size,
/* Load initrd. */
if (initrd_filename) {
- initrd_base = kernel_size + loadaddr;
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
- ram_size - initrd_base);
+ initrd_size = load_image_targphys(initrd_filename, RAMDISK_ADDR,
+ ram_size - RAMDISK_ADDR);
if (initrd_size < 0) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- initrd_filename);
+ fprintf(stderr, "qemu: could not load ram disk '%s' at %x\n",
+ initrd_filename, RAMDISK_ADDR);
exit(1);
}
}
/* If we're loading a kernel directly, we must load the device tree too. */
if (kernel_filename) {
- if (initrd_base)
- dt_base = initrd_base + initrd_size;
- else
- dt_base = kernel_size + loadaddr;
-
- if (bamboo_load_device_tree(dt_base, ram_size,
- initrd_base, initrd_size, kernel_cmdline) < 0) {
+ if (bamboo_load_device_tree(FDT_ADDR, ram_size, RAMDISK_ADDR,
+ initrd_size, kernel_cmdline) < 0) {
fprintf(stderr, "couldn't load device tree\n");
exit(1);
}
@@ -163,7 +160,7 @@ static void bamboo_init(ram_addr_t ram_size,
/* Set initial guest state. */
env->gpr[1] = (16<<20) - 8;
- env->gpr[3] = dt_base;
+ env->gpr[3] = FDT_ADDR;
env->nip = entry;
/* XXX we currently depend on KVM to create some initial TLB entries. */
}
@@ -186,7 +183,7 @@ static QEMUMachine bamboo_machine_v0_12 = {
.compat_props = (GlobalProperty[]) {
{
.driver = "virtio-serial-pci",
- .property = "max_nr_ports",
+ .property = "max_ports",
.value = stringify(1),
},{
.driver = "virtio-serial-pci",
diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c
index b15db81b6a..5f581fe2c4 100644
--- a/hw/ppc4xx_devs.c
+++ b/hw/ppc4xx_devs.c
@@ -56,7 +56,7 @@ CPUState *ppc4xx_init (const char *cpu_model,
cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
cpu_clk->opaque = env;
/* Set time-base frequency to sysclk */
- tb_clk->cb = ppc_emb_timers_init(env, sysclk);
+ tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_PIT);
tb_clk->opaque = env;
ppc_dcr_init(env, NULL, NULL);
/* Register qemu callbacks */
@@ -619,7 +619,6 @@ static void sdram_reset (void *opaque)
/* We pre-initialize RAM banks */
sdram->status = 0x00000000;
sdram->cfg = 0x00800000;
- sdram_unmap_bcr(sdram);
}
void ppc4xx_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
@@ -684,7 +683,7 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
}
ram_size -= size_left;
- if (ram_size)
+ if (size_left)
printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n",
(int)(ram_size >> 20));
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index 89f96bbc34..ea8759324c 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -30,7 +30,6 @@
#define BIOS_SIZE (1024 * 1024)
#define BIOS_FILENAME "ppc_rom.bin"
-#define VGABIOS_FILENAME "video.x"
#define NVRAM_SIZE 0x2000
#define PROM_FILENAME "openbios-ppc"
#define PROM_ADDR 0xfff00000
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index fbba9b6fb2..4369337b21 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -66,9 +66,9 @@
#include "kvm.h"
#include "kvm_ppc.h"
#include "hw/usb.h"
+#include "blockdev.h"
#define MAX_IDE_BUS 2
-#define VGA_BIOS_SIZE 65536
#define CFG_ADDR 0xf0000510
/* debug UniNorth */
@@ -128,24 +128,24 @@ static void ppc_core99_init (ram_addr_t ram_size,
const char *initrd_filename,
const char *cpu_model)
{
- CPUState *env = NULL, *envs[MAX_CPUS];
+ CPUState *env = NULL;
char *filename;
qemu_irq *pic, **openpic_irqs;
int unin_memory;
int linux_boot, i;
- ram_addr_t ram_offset, bios_offset, vga_bios_offset;
- uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
+ ram_addr_t ram_offset, bios_offset;
+ uint32_t kernel_base, initrd_base;
+ long kernel_size, initrd_size;
PCIBus *pci_bus;
MacIONVRAMState *nvr;
int nvram_mem_index;
- int vga_bios_size, bios_size;
+ int bios_size;
int pic_mem_index, dbdma_mem_index, cuda_mem_index, escc_mem_index;
int ide_mem_index[3];
int ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg;
void *dbdma;
- uint8_t *vga_bios_ptr;
int machine_arch;
linux_boot = (kernel_filename != NULL);
@@ -165,11 +165,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
}
/* Set time-base frequency to 100 Mhz */
cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
-#if 0
- env->osi_call = vga_osi_call;
-#endif
qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
- envs[i] = env;
}
/* allocate RAM */
@@ -197,36 +193,6 @@ static void ppc_core99_init (ram_addr_t ram_size,
exit(1);
}
- /* allocate and load VGA BIOS */
- vga_bios_offset = qemu_ram_alloc(NULL, "ppc_core99.vbios", VGA_BIOS_SIZE);
- vga_bios_ptr = qemu_get_ram_ptr(vga_bios_offset);
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, VGABIOS_FILENAME);
- if (filename) {
- vga_bios_size = load_image(filename, vga_bios_ptr + 8);
- qemu_free(filename);
- } else {
- vga_bios_size = -1;
- }
- if (vga_bios_size < 0) {
- /* if no bios is present, we can still work */
- fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n",
- VGABIOS_FILENAME);
- vga_bios_size = 0;
- } else {
- /* set a specific header (XXX: find real Apple format for NDRV
- drivers) */
- vga_bios_ptr[0] = 'N';
- vga_bios_ptr[1] = 'D';
- vga_bios_ptr[2] = 'R';
- vga_bios_ptr[3] = 'V';
- cpu_to_be32w((uint32_t *)(vga_bios_ptr + 4), vga_bios_size);
- vga_bios_size += 8;
-
- /* Round to page boundary */
- vga_bios_size = (vga_bios_size + TARGET_PAGE_SIZE - 1) &
- TARGET_PAGE_MASK;
- }
-
if (linux_boot) {
uint64_t lowaddr = 0;
int bswap_needed;
@@ -350,7 +316,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
machine_arch = ARCH_MAC99;
}
/* init basic PC hardware */
- pci_vga_init(pci_bus, vga_bios_offset, vga_bios_size);
+ pci_vga_init(pci_bus, 0, 0);
escc_mem_index = escc_init(0x80013000, pic[0x25], pic[0x24],
serial_hds[0], serial_hds[1], ESCC_CLOCK, 4);
@@ -426,9 +392,16 @@ static void ppc_core99_init (ram_addr_t ram_size,
fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
if (kvm_enabled()) {
#ifdef CONFIG_KVM
+ uint8_t *hypercall;
+
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+ hypercall = qemu_malloc(16);
+ kvmppc_get_hypercall(env, hypercall, 16);
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
#endif
} else {
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 6b3ab89611..a2f9ddf738 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -1,3 +1,4 @@
+
/*
* QEMU OldWorld PowerMac (currently ~G3 Beige) hardware System Emulator
*
@@ -41,81 +42,11 @@
#include "elf.h"
#include "kvm.h"
#include "kvm_ppc.h"
+#include "blockdev.h"
#define MAX_IDE_BUS 2
-#define VGA_BIOS_SIZE 65536
#define CFG_ADDR 0xf0000510
-/* temporary frame buffer OSI calls for the video.x driver. The right
- solution is to modify the driver to use VGA PCI I/Os */
-/* XXX: to be removed. This is no way related to emulation */
-static int vga_osi_call (CPUState *env)
-{
- static int vga_vbl_enabled;
- int linesize;
-
-#if 0
- printf("osi_call R5=%016" PRIx64 "\n", ppc_dump_gpr(env, 5));
-#endif
-
- /* same handler as PearPC, coming from the original MOL video
- driver. */
- switch(env->gpr[5]) {
- case 4:
- break;
- case 28: /* set_vmode */
- if (env->gpr[6] != 1 || env->gpr[7] != 0)
- env->gpr[3] = 1;
- else
- env->gpr[3] = 0;
- break;
- case 29: /* get_vmode_info */
- if (env->gpr[6] != 0) {
- if (env->gpr[6] != 1 || env->gpr[7] != 0) {
- env->gpr[3] = 1;
- break;
- }
- }
- env->gpr[3] = 0;
- env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */
- env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */
- env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */
- env->gpr[7] = 85 << 16; /* refresh rate */
- env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */
- linesize = ((graphic_depth + 7) >> 3) * graphic_width;
- linesize = (linesize + 3) & ~3;
- env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */
- break;
- case 31: /* set_video power */
- env->gpr[3] = 0;
- break;
- case 39: /* video_ctrl */
- if (env->gpr[6] == 0 || env->gpr[6] == 1)
- vga_vbl_enabled = env->gpr[6];
- env->gpr[3] = 0;
- break;
- case 47:
- break;
- case 59: /* set_color */
- /* R6 = index, R7 = RGB */
- env->gpr[3] = 0;
- break;
- case 64: /* get color */
- /* R6 = index */
- env->gpr[3] = 0;
- break;
- case 116: /* set hwcursor */
- /* R6 = x, R7 = y, R8 = visible, R9 = data */
- break;
- default:
- fprintf(stderr, "unsupported OSI call R5=%016" PRIx64 "\n",
- ppc_dump_gpr(env, 5));
- break;
- }
-
- return 1; /* osi_call handled */
-}
-
static int fw_cfg_boot_set(void *opaque, const char *boot_device)
{
fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
@@ -135,23 +66,22 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
const char *initrd_filename,
const char *cpu_model)
{
- CPUState *env = NULL, *envs[MAX_CPUS];
+ CPUState *env = NULL;
char *filename;
qemu_irq *pic, **heathrow_irqs;
int linux_boot, i;
- ram_addr_t ram_offset, bios_offset, vga_bios_offset;
+ ram_addr_t ram_offset, bios_offset;
uint32_t kernel_base, initrd_base;
int32_t kernel_size, initrd_size;
PCIBus *pci_bus;
MacIONVRAMState *nvr;
- int vga_bios_size, bios_size;
+ int bios_size;
int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index;
int escc_mem_index, ide_mem_index[2];
uint16_t ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg;
void *dbdma;
- uint8_t *vga_bios_ptr;
linux_boot = (kernel_filename != NULL);
@@ -166,9 +96,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
}
/* Set time-base frequency to 16.6 Mhz */
cpu_ppc_tb_init(env, 16600000UL);
- env->osi_call = vga_osi_call;
qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
- envs[i] = env;
}
/* allocate RAM */
@@ -202,36 +130,6 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
exit(1);
}
- /* allocate and load VGA BIOS */
- vga_bios_offset = qemu_ram_alloc(NULL, "ppc_heathrow.vbios", VGA_BIOS_SIZE);
- vga_bios_ptr = qemu_get_ram_ptr(vga_bios_offset);
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, VGABIOS_FILENAME);
- if (filename) {
- vga_bios_size = load_image(filename, vga_bios_ptr + 8);
- qemu_free(filename);
- } else {
- vga_bios_size = -1;
- }
- if (vga_bios_size < 0) {
- /* if no bios is present, we can still work */
- fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n",
- VGABIOS_FILENAME);
- vga_bios_size = 0;
- } else {
- /* set a specific header (XXX: find real Apple format for NDRV
- drivers) */
- vga_bios_ptr[0] = 'N';
- vga_bios_ptr[1] = 'D';
- vga_bios_ptr[2] = 'R';
- vga_bios_ptr[3] = 'V';
- cpu_to_be32w((uint32_t *)(vga_bios_ptr + 4), vga_bios_size);
- vga_bios_size += 8;
-
- /* Round to page boundary */
- vga_bios_size = (vga_bios_size + TARGET_PAGE_SIZE - 1) &
- TARGET_PAGE_MASK;
- }
-
if (linux_boot) {
uint64_t lowaddr = 0;
int bswap_needed;
@@ -329,7 +227,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
}
pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
pci_bus = pci_grackle_init(0xfec00000, pic);
- pci_vga_init(pci_bus, vga_bios_offset, vga_bios_size);
+ pci_vga_init(pci_bus, 0, 0);
escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
serial_hds[1], ESCC_CLOCK, 4);
@@ -398,9 +296,16 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
if (kvm_enabled()) {
#ifdef CONFIG_KVM
+ uint8_t *hypercall;
+
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+ hypercall = qemu_malloc(16);
+ kvmppc_get_hypercall(env, hypercall, 16);
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
#endif
} else {
fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index fc3e17a0c3..a6915f7e68 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -37,6 +37,7 @@
#include "ide.h"
#include "loader.h"
#include "mc146818rtc.h"
+#include "blockdev.h"
//#define HARD_DEBUG_PPC_IO
//#define DEBUG_PPC_IO
@@ -564,14 +565,15 @@ static void ppc_prep_init (ram_addr_t ram_size,
const char *initrd_filename,
const char *cpu_model)
{
- CPUState *env = NULL, *envs[MAX_CPUS];
+ CPUState *env = NULL;
char *filename;
nvram_t nvram;
M48t59State *m48t59;
int PPC_io_memory;
int linux_boot, i, nb_nics1, bios_size;
ram_addr_t ram_offset, bios_offset;
- uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
+ uint32_t kernel_base, initrd_base;
+ long kernel_size, initrd_size;
PCIBus *pci_bus;
qemu_irq *i8259;
qemu_irq *cpu_exit_irq;
@@ -600,7 +602,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
}
qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
- envs[i] = env;
}
/* allocate RAM */
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 1422fad072..59d20d30ae 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -176,7 +176,6 @@ static void mpc8544ds_init(ram_addr_t ram_size,
int i=0;
unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
qemu_irq *irqs, *mpic, *pci_irqs;
- SerialState * serial[2];
/* Setup CPU */
env = cpu_ppc_init("e500v2_v30");
@@ -200,15 +199,15 @@ static void mpc8544ds_init(ram_addr_t ram_size,
/* Serial */
if (serial_hds[0]) {
- serial[0] = serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
- 0, mpic[12+26], 399193,
- serial_hds[0], 1, 1);
+ serial_mm_init(MPC8544_SERIAL0_REGS_BASE,
+ 0, mpic[12+26], 399193,
+ serial_hds[0], 1, 1);
}
if (serial_hds[1]) {
- serial[0] = serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
- 0, mpic[12+26], 399193,
- serial_hds[0], 1, 1);
+ serial_mm_init(MPC8544_SERIAL1_REGS_BASE,
+ 0, mpic[12+26], 399193,
+ serial_hds[0], 1, 1);
}
/* PCI */
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 953e9ee1d1..6e046450df 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -15,6 +15,7 @@
#include "ssi.h"
#include "qemu-timer.h"
#include "qemu-char.h"
+#include "blockdev.h"
static struct {
target_phys_addr_t io_base;
@@ -124,7 +125,7 @@ static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
break;
default: /* Read-write registers */
- if (addr >= PMCR && addr <= PCMD31 && !(addr & 3)) {
+ if (!(addr & 3)) {
s->pm_regs[addr >> 2] = value;
break;
}
@@ -635,6 +636,7 @@ static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s)
{
s->sssr &= ~(0xf << 12); /* Clear RFL */
s->sssr &= ~(0xf << 8); /* Clear TFL */
+ s->sssr &= ~SSSR_TFS;
s->sssr &= ~SSSR_TNF;
if (s->enable) {
s->sssr |= ((s->rx_level - 1) & 0xf) << 12;
@@ -642,14 +644,13 @@ static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s)
s->sssr |= SSSR_RFS;
else
s->sssr &= ~SSSR_RFS;
- if (0 <= SSCR1_TFT(s->sscr[1]))
- s->sssr |= SSSR_TFS;
- else
- s->sssr &= ~SSSR_TFS;
if (s->rx_level)
s->sssr |= SSSR_RNE;
else
s->sssr &= ~SSSR_RNE;
+ /* TX FIFO is never filled, so it is always in underrun
+ condition if SSP is enabled */
+ s->sssr |= SSSR_TFS;
s->sssr |= SSSR_TNF;
}
@@ -1876,8 +1877,9 @@ static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr,
s->control[0] = value;
if (!(value & (1 << 4))) /* RXE */
s->rx_len = s->rx_start = 0;
- if (!(value & (1 << 3))) /* TXE */
- /* Nop */;
+ if (!(value & (1 << 3))) { /* TXE */
+ /* Nop */
+ }
s->enable = value & 1; /* ITR */
if (!s->enable)
s->status[0] = 0;
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 9219cd7a60..a493087a52 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -1,6 +1,7 @@
#include "net.h"
#include "qdev.h"
#include "qerror.h"
+#include "blockdev.h"
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
{
@@ -772,5 +773,5 @@ static int qdev_add_one_global(QemuOpts *opts, void *opaque)
void qemu_add_globals(void)
{
- qemu_opts_foreach(&qemu_global_opts, qdev_add_one_global, NULL, 0);
+ qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0);
}
diff --git a/hw/qdev.c b/hw/qdev.c
index e99c73f0d9..35858cb81b 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -29,6 +29,7 @@
#include "qdev.h"
#include "sysemu.h"
#include "monitor.h"
+#include "blockdev.h"
static int qdev_hotplug = 0;
@@ -792,7 +793,7 @@ int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
QemuOpts *opts;
- opts = qemu_opts_from_qdict(&qemu_device_opts, qdict);
+ opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
if (!opts) {
return -1;
}
diff --git a/hw/qdev.h b/hw/qdev.h
index 678f8b7d1d..579328afc2 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -2,7 +2,6 @@
#define QDEV_H
#include "hw.h"
-#include "blockdev.h"
#include "qemu-queue.h"
#include "qemu-char.h"
#include "qemu-option.h"
diff --git a/hw/r2d.c b/hw/r2d.c
index 8c1fbad4ba..a58f653e52 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -36,6 +36,7 @@
#include "loader.h"
#include "usb.h"
#include "flash.h"
+#include "blockdev.h"
#define FLASH_BASE 0x00000000
#define FLASH_SIZE 0x02000000
diff --git a/hw/rc4030.c b/hw/rc4030.c
index 223137323b..abbc3eb4e2 100644
--- a/hw/rc4030.c
+++ b/hw/rc4030.c
@@ -749,7 +749,10 @@ static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_wri
printf("rc4030 dma: Copying %d bytes %s host %p\n",
len, is_write ? "from" : "to", buf);
for (i = 0; i < len; i += 16) {
- int n = min(16, len - i);
+ int n = 16;
+ if (n > len - i) {
+ n = len - i;
+ }
for (j = 0; j < n; j++)
printf("%02x ", buf[i + j]);
while (j++ < 16)
diff --git a/hw/realview.c b/hw/realview.c
index 70bcdb846d..e9fcbc9a6d 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -18,6 +18,7 @@
#include "boards.h"
#include "bitbang_i2c.h"
#include "sysbus.h"
+#include "blockdev.h"
#define SMP_BOOT_ADDR 0xe0000000
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index fe6884d47d..784dc01b97 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -27,6 +27,7 @@
#include "elf.h"
#include "hw/virtio.h"
#include "hw/virtio-serial.h"
+#include "hw/virtio-net.h"
#include "hw/sysbus.h"
#include "kvm.h"
@@ -110,7 +111,7 @@ static int s390_virtio_net_init(VirtIOS390Device *dev)
{
VirtIODevice *vdev;
- vdev = virtio_net_init((DeviceState *)dev, &dev->nic);
+ vdev = virtio_net_init((DeviceState *)dev, &dev->nic, &dev->net);
if (!vdev) {
return -1;
}
@@ -327,6 +328,11 @@ static VirtIOS390DeviceInfo s390_virtio_net = {
.qdev.size = sizeof(VirtIOS390Device),
.qdev.props = (Property[]) {
DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic),
+ DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device,
+ net.txtimer, TX_TIMER_INTERVAL),
+ DEFINE_PROP_INT32("x-txburst", VirtIOS390Device,
+ net.txburst, TX_BURST),
+ DEFINE_PROP_STRING("tx", VirtIOS390Device, net.tx),
DEFINE_PROP_END_OF_LIST(),
},
};
diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h
index 333fea8963..41558c9c67 100644
--- a/hw/s390-virtio-bus.h
+++ b/hw/s390-virtio-bus.h
@@ -43,6 +43,7 @@ typedef struct VirtIOS390Device {
uint32_t host_features;
/* Max. number of ports we can have for a the virtio-serial device */
uint32_t max_virtserial_ports;
+ virtio_net_conf net;
} VirtIOS390Device;
typedef struct VirtIOS390Bus {
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index d69c74c4ef..5a3fd4b7ac 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -3,6 +3,7 @@
#include "scsi.h"
#include "scsi-defs.h"
#include "qdev.h"
+#include "blockdev.h"
static struct BusInfo scsi_bus_info = {
.name = "SCSI",
@@ -142,6 +143,7 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l
req->tag = tag;
req->lun = lun;
req->status = -1;
+ req->enqueued = true;
QTAILQ_INSERT_TAIL(&d->requests, req, next);
return req;
}
@@ -158,9 +160,17 @@ SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag)
return NULL;
}
+static void scsi_req_dequeue(SCSIRequest *req)
+{
+ if (req->enqueued) {
+ QTAILQ_REMOVE(&req->dev->requests, req, next);
+ req->enqueued = false;
+ }
+}
+
void scsi_req_free(SCSIRequest *req)
{
- QTAILQ_REMOVE(&req->dev->requests, req, next);
+ scsi_req_dequeue(req);
qemu_free(req);
}
@@ -198,6 +208,8 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
case SEEK_6:
case WRITE_FILEMARKS:
case SPACE:
+ case RESERVE:
+ case RELEASE:
case ERASE:
case ALLOW_MEDIUM_REMOVAL:
case VERIFY:
@@ -309,7 +321,6 @@ static void scsi_req_xfer_mode(SCSIRequest *req)
case WRITE_BUFFER:
case FORMAT_UNIT:
case REASSIGN_BLOCKS:
- case RESERVE:
case SEARCH_EQUAL:
case SEARCH_HIGH:
case SEARCH_LOW:
@@ -512,6 +523,7 @@ void scsi_req_print(SCSIRequest *req)
void scsi_req_complete(SCSIRequest *req)
{
assert(req->status != -1);
+ scsi_req_dequeue(req);
req->bus->complete(req->bus, SCSI_REASON_DONE,
req->tag,
req->status);
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index c30709c550..9628b39a21 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -36,6 +36,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
#include "scsi.h"
#include "scsi-defs.h"
#include "sysemu.h"
+#include "blockdev.h"
#define SCSI_DMA_BUF_SIZE 131072
#define SCSI_MAX_INQUIRY_LEN 256
@@ -69,14 +70,15 @@ struct SCSIDiskState
char *serial;
};
-static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
+static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag,
+ uint32_t lun)
{
SCSIRequest *req;
SCSIDiskReq *r;
- req = scsi_req_alloc(sizeof(SCSIDiskReq), d, tag, lun);
+ req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun);
r = DO_UPCAST(SCSIDiskReq, req, req);
- r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE);
+ r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
return r;
}
@@ -134,7 +136,7 @@ static void scsi_read_complete(void * opaque, int ret)
scsi_command_complete(r, CHECK_CONDITION, NO_SENSE);
return;
}
- DPRINTF("Data ready tag=0x%x len=%" PRId64 "\n", r->req.tag, r->iov.iov_len);
+ DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->iov.iov_len);
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
}
@@ -154,7 +156,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
return;
}
if (r->sector_count == (uint32_t)-1) {
- DPRINTF("Read buf_len=%" PRId64 "\n", r->iov.iov_len);
+ DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
r->sector_count = 0;
r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, r->iov.iov_len);
return;
@@ -485,16 +487,26 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
return buflen;
}
-static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
+static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
+ int page_control)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
BlockDriverState *bdrv = s->bs;
int cylinders, heads, secs;
+ /*
+ * If Changeable Values are requested, a mask denoting those mode parameters
+ * that are changeable shall be returned. As we currently don't support
+ * parameter changes via MODE_SELECT all bits are returned set to zero.
+ * The buffer was already menset to zero by the caller of this function.
+ */
switch (page) {
case 4: /* Rigid disk device geometry page. */
p[0] = 4;
p[1] = 0x16;
+ if (page_control == 1) { /* Changeable Values */
+ return p[1] + 2;
+ }
/* if a geometry hint is available, use it */
bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
p[2] = (cylinders >> 16) & 0xff;
@@ -519,11 +531,14 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
/* Medium rotation rate [rpm], 5400 rpm */
p[20] = (5400 >> 8) & 0xff;
p[21] = 5400 & 0xff;
- return 0x16;
+ return p[1] + 2;
case 5: /* Flexible disk device geometry page. */
p[0] = 5;
p[1] = 0x1e;
+ if (page_control == 1) { /* Changeable Values */
+ return p[1] + 2;
+ }
/* Transfer rate [kbit/s], 5Mbit/s */
p[2] = 5000 >> 8;
p[3] = 5000 & 0xff;
@@ -555,21 +570,27 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
/* Medium rotation rate [rpm], 5400 rpm */
p[28] = (5400 >> 8) & 0xff;
p[29] = 5400 & 0xff;
- return 0x1e;
+ return p[1] + 2;
case 8: /* Caching page. */
p[0] = 8;
p[1] = 0x12;
+ if (page_control == 1) { /* Changeable Values */
+ return p[1] + 2;
+ }
if (bdrv_enable_write_cache(s->bs)) {
p[2] = 4; /* WCE */
}
- return 20;
+ return p[1] + 2;
case 0x2a: /* CD Capabilities and Mechanical Status page. */
if (bdrv_get_type_hint(bdrv) != BDRV_TYPE_CDROM)
return 0;
p[0] = 0x2a;
p[1] = 0x14;
+ if (page_control == 1) { /* Changeable Values */
+ return p[1] + 2;
+ }
p[2] = 3; // CD-R & CD-RW read
p[3] = 0; // Writing not supported
p[4] = 0x7f; /* Audio, composite, digital out,
@@ -593,7 +614,7 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p)
p[19] = (16 * 176) & 0xff;
p[20] = (16 * 176) >> 8; // 16x write speed current
p[21] = (16 * 176) & 0xff;
- return 22;
+ return p[1] + 2;
default:
return 0;
@@ -604,29 +625,46 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
uint64_t nb_sectors;
- int page, dbd, buflen;
+ int page, dbd, buflen, page_control;
uint8_t *p;
+ uint8_t dev_specific_param;
dbd = req->cmd.buf[1] & 0x8;
page = req->cmd.buf[2] & 0x3f;
- DPRINTF("Mode Sense (page %d, len %zd)\n", page, req->cmd.xfer);
+ page_control = (req->cmd.buf[2] & 0xc0) >> 6;
+ DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
+ (req->cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, req->cmd.xfer, page_control);
memset(outbuf, 0, req->cmd.xfer);
p = outbuf;
- p[1] = 0; /* Default media type. */
- p[3] = 0; /* Block descriptor length. */
if (bdrv_is_read_only(s->bs)) {
- p[2] = 0x80; /* Readonly. */
+ dev_specific_param = 0x80; /* Readonly. */
+ } else {
+ dev_specific_param = 0x00;
+ }
+
+ if (req->cmd.buf[0] == MODE_SENSE) {
+ p[1] = 0; /* Default media type. */
+ p[2] = dev_specific_param;
+ p[3] = 0; /* Block descriptor length. */
+ p += 4;
+ } else { /* MODE_SENSE_10 */
+ p[2] = 0; /* Default media type. */
+ p[3] = dev_specific_param;
+ p[6] = p[7] = 0; /* Block descriptor length. */
+ p += 8;
}
- p += 4;
bdrv_get_geometry(s->bs, &nb_sectors);
- if ((~dbd) & nb_sectors) {
- outbuf[3] = 8; /* Block descriptor length */
+ if (!dbd && nb_sectors) {
+ if (req->cmd.buf[0] == MODE_SENSE) {
+ outbuf[3] = 8; /* Block descriptor length */
+ } else { /* MODE_SENSE_10 */
+ outbuf[7] = 8; /* Block descriptor length */
+ }
nb_sectors /= s->cluster_size;
- nb_sectors--;
if (nb_sectors > 0xffffff)
- nb_sectors = 0xffffff;
+ nb_sectors = 0;
p[0] = 0; /* media density code */
p[1] = (nb_sectors >> 16) & 0xff;
p[2] = (nb_sectors >> 8) & 0xff;
@@ -638,21 +676,37 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
p += 8;
}
+ if (page_control == 3) { /* Saved Values */
+ return -1; /* ILLEGAL_REQUEST */
+ }
+
switch (page) {
case 0x04:
case 0x05:
case 0x08:
case 0x2a:
- p += mode_sense_page(req, page, p);
+ p += mode_sense_page(req, page, p, page_control);
break;
case 0x3f:
- p += mode_sense_page(req, 0x08, p);
- p += mode_sense_page(req, 0x2a, p);
+ p += mode_sense_page(req, 0x08, p, page_control);
+ p += mode_sense_page(req, 0x2a, p, page_control);
break;
+ default:
+ return -1; /* ILLEGAL_REQUEST */
}
buflen = p - outbuf;
- outbuf[0] = buflen - 4;
+ /*
+ * The mode data length field specifies the length in bytes of the
+ * following data that is available to be transferred. The mode data
+ * length does not include itself.
+ */
+ if (req->cmd.buf[0] == MODE_SENSE) {
+ outbuf[0] = buflen - 1;
+ } else { /* MODE_SENSE_10 */
+ outbuf[0] = ((buflen - 2) >> 8) & 0xff;
+ outbuf[1] = (buflen - 2) & 0xff;
+ }
if (buflen > req->cmd.xfer)
buflen = req->cmd.xfer;
return buflen;
@@ -839,6 +893,12 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
break;
case VERIFY:
break;
+ case REZERO_UNIT:
+ DPRINTF("Rezero Unit\n");
+ if (!bdrv_is_inserted(s->bs)) {
+ goto not_ready;
+ }
+ break;
default:
goto illegal_request;
}
@@ -880,7 +940,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
}
/* ??? Tags are not unique for different luns. We only implement a
single lun, so this should not matter. */
- r = scsi_new_request(d, tag, lun);
+ r = scsi_new_request(s, tag, lun);
outbuf = (uint8_t *)r->iov.iov_base;
is_write = 0;
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
@@ -958,6 +1018,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
case SERVICE_ACTION_IN:
case REPORT_LUNS:
case VERIFY:
+ case REZERO_UNIT:
rc = scsi_disk_emulate_command(&r->req, outbuf);
if (rc > 0) {
r->iov.iov_len = rc;
@@ -981,13 +1042,40 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
case WRITE_10:
case WRITE_12:
case WRITE_16:
- DPRINTF("Write (sector %" PRId64 ", count %d)\n", lba, len);
+ case WRITE_VERIFY:
+ case WRITE_VERIFY_12:
+ case WRITE_VERIFY_16:
+ DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
+ (command & 0xe) == 0xe ? "And Verify " : "", lba, len);
if (lba > s->max_lba)
goto illegal_lba;
r->sector = lba * s->cluster_size;
r->sector_count = len * s->cluster_size;
is_write = 1;
break;
+ case MODE_SELECT:
+ DPRINTF("Mode Select(6) (len %d)\n", len);
+ /* We don't support mode parameter changes.
+ Allow the mode parameter header + block descriptors only. */
+ if (len > 12) {
+ goto fail;
+ }
+ break;
+ case MODE_SELECT_10:
+ DPRINTF("Mode Select(10) (len %d)\n", len);
+ /* We don't support mode parameter changes.
+ Allow the mode parameter header + block descriptors only. */
+ if (len > 16) {
+ goto fail;
+ }
+ break;
+ case SEEK_6:
+ case SEEK_10:
+ DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10, lba);
+ if (lba > s->max_lba) {
+ goto illegal_lba;
+ }
+ break;
default:
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
fail:
@@ -1059,6 +1147,11 @@ static int scsi_disk_initfn(SCSIDevice *dev)
s->bs = s->qdev.conf.bs;
is_cd = bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM;
+ if (!is_cd && !bdrv_is_inserted(s->bs)) {
+ error_report("Device needs media, but drive is empty");
+ return -1;
+ }
+
if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
error_report("Device doesn't support drive option rerror");
return -1;
@@ -1085,6 +1178,7 @@ static int scsi_disk_initfn(SCSIDevice *dev)
s->qdev.blocksize = s->qdev.conf.logical_block_size;
}
s->cluster_size = s->qdev.blocksize / 512;
+ s->bs->buffer_alignment = s->qdev.blocksize;
s->qdev.type = TYPE_DISK;
qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index a8b4176d80..7212091695 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -14,6 +14,7 @@
#include "qemu-common.h"
#include "qemu-error.h"
#include "scsi.h"
+#include "blockdev.h"
#ifdef __linux__
@@ -163,7 +164,7 @@ static void scsi_read_complete(void * opaque, int ret)
int len;
if (ret) {
- DPRINTF("IO error\n");
+ DPRINTF("IO error ret %d\n", ret);
scsi_command_complete(r, ret);
return;
}
@@ -235,7 +236,7 @@ static void scsi_write_complete(void * opaque, int ret)
if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
s->qdev.type == TYPE_TAPE) {
s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
- DPRINTF("block size %d\n", s->blocksize);
+ DPRINTF("block size %d\n", s->qdev.blocksize);
}
scsi_command_complete(r, ret);
@@ -350,8 +351,18 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
}
scsi_req_fixup(&r->req);
- DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag,
- cmd[0], r->req.cmd.xfer);
+ DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
+ r->req.cmd.xfer, cmd[0]);
+
+#ifdef DEBUG_SCSI
+ {
+ int i;
+ for (i = 1; i < r->req.cmd.len; i++) {
+ printf(" 0x%02x", cmd[i]);
+ }
+ printf("\n");
+ }
+#endif
if (r->req.cmd.xfer == 0) {
if (r->buf != NULL)
@@ -444,15 +455,31 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
return (buf[9] << 16) | (buf[10] << 8) | buf[11];
}
-static void scsi_destroy(SCSIDevice *d)
+static void scsi_generic_purge_requests(SCSIGenericState *s)
{
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
SCSIGenericReq *r;
while (!QTAILQ_EMPTY(&s->qdev.requests)) {
r = DO_UPCAST(SCSIGenericReq, req, QTAILQ_FIRST(&s->qdev.requests));
+ if (r->req.aiocb) {
+ bdrv_aio_cancel(r->req.aiocb);
+ }
scsi_remove_request(r);
}
+}
+
+static void scsi_generic_reset(DeviceState *dev)
+{
+ SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
+
+ scsi_generic_purge_requests(s);
+}
+
+static void scsi_destroy(SCSIDevice *d)
+{
+ SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
+
+ scsi_generic_purge_requests(s);
blockdev_mark_auto_del(s->qdev.conf.bs);
}
@@ -526,6 +553,7 @@ static SCSIDeviceInfo scsi_generic_info = {
.qdev.name = "scsi-generic",
.qdev.desc = "pass through generic scsi device (/dev/sg*)",
.qdev.size = sizeof(SCSIGenericState),
+ .qdev.reset = scsi_generic_reset,
.init = scsi_generic_initfn,
.destroy = scsi_destroy,
.send_command = scsi_send_command,
diff --git a/hw/scsi.h b/hw/scsi.h
index 4fbf1d5dfd..cb06d6d824 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -43,6 +43,7 @@ typedef struct SCSIRequest {
enum SCSIXferMode mode;
} cmd;
BlockDriverAIOCB *aiocb;
+ bool enqueued;
QTAILQ_ENTRY(SCSIRequest) next;
} SCSIRequest;
diff --git a/hw/sd.c b/hw/sd.c
index c928120abd..601545b2d9 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -31,6 +31,7 @@
#include "hw.h"
#include "block.h"
+#include "block_int.h"
#include "sd.h"
//#define DEBUG_SD 1
@@ -440,7 +441,7 @@ SDState *sd_init(BlockDriverState *bs, int is_spi)
SDState *sd;
sd = (SDState *) qemu_mallocz(sizeof(SDState));
- sd->buf = qemu_memalign(512, 512);
+ sd->buf = qemu_blockalign(bs, 512);
sd->spi = is_spi;
sd->enable = 1;
sd_reset(sd, bs);
diff --git a/hw/serial.c b/hw/serial.c
index b66d13ad41..9ebc452aea 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -99,6 +99,14 @@
#define RECV_FIFO 1
#define MAX_XMIT_RETRY 4
+#ifdef DEBUG_SERIAL
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+
typedef struct SerialFIFO {
uint8_t data[UART_FIFO_LENGTH];
uint8_t count;
@@ -267,10 +275,9 @@ static void serial_update_parameters(SerialState *s)
ssp.stop_bits = stop_bits;
s->char_transmit_time = (get_ticks_per_sec() / speed) * frame_size;
qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-#if 0
- printf("speed=%d parity=%c data=%d stop=%d\n",
+
+ DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
speed, parity, data_bits, stop_bits);
-#endif
}
static void serial_update_msl(SerialState *s)
@@ -360,9 +367,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
SerialState *s = opaque;
addr &= 7;
-#ifdef DEBUG_SERIAL
- printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
-#endif
+ DPRINTF("write addr=0x%02x val=0x%02x\n", addr, val);
switch(addr) {
default:
case 0:
@@ -583,9 +588,7 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
ret = s->scr;
break;
}
-#ifdef DEBUG_SERIAL
- printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);
-#endif
+ DPRINTF("read addr=0x%02x val=0x%02x\n", addr, ret);
return ret;
}
@@ -651,9 +654,7 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size)
static void serial_event(void *opaque, int event)
{
SerialState *s = opaque;
-#ifdef DEBUG_SERIAL
- printf("serial: event %x\n", event);
-#endif
+ DPRINTF("event %x\n", event);
if (event == CHR_EVENT_BREAK)
serial_receive_break(s);
}
@@ -673,6 +674,7 @@ static int serial_post_load(void *opaque, int version_id)
}
/* Initialize fcr via setter to perform essential side-effects */
serial_ioport_write(s, 0x02, s->fcr_vmstate);
+ serial_update_parameters(s);
return 0;
}
diff --git a/hw/sh_intc.c b/hw/sh_intc.c
index da36d32b1d..d3f5ea57d5 100644
--- a/hw/sh_intc.c
+++ b/hw/sh_intc.c
@@ -431,9 +431,8 @@ int sh_intc_init(struct intc_desc *desc,
desc->nr_prio_regs = nr_prio_regs;
i = sizeof(struct intc_source) * nr_sources;
- desc->sources = qemu_malloc(i);
+ desc->sources = qemu_mallocz(i);
- memset(desc->sources, 0, i);
for (i = 0; i < desc->nr_sources; i++) {
struct intc_source *source = desc->sources + i;
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index d7875536b6..c125de4b62 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -377,12 +377,12 @@ static void slavio_timer_reset(DeviceState *d)
curr_timer->limit = 0;
curr_timer->count = 0;
curr_timer->reached = 0;
- if (i < s->num_cpus) {
+ if (i <= s->num_cpus) {
ptimer_set_limit(curr_timer->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
ptimer_run(curr_timer->timer, 0);
+ curr_timer->running = 1;
}
- curr_timer->running = 1;
}
s->cputimer_mode = 0;
}
diff --git a/hw/sm501.c b/hw/sm501.c
index 8e6932d747..705e0a5c76 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -29,6 +29,7 @@
#include "devices.h"
#include "sysbus.h"
#include "qdev-addr.h"
+#include "range.h"
/*
* Status: 2010/05/07
@@ -814,7 +815,7 @@ static uint32_t sm501_palette_read(void *opaque, target_phys_addr_t addr)
/* TODO : consider BYTE/WORD access */
/* TODO : consider endian */
- assert(0 <= addr && addr < 0x400 * 3);
+ assert(range_covers_byte(0, 0x400 * 3, addr));
return *(uint32_t*)&s->dc_palette[addr];
}
@@ -828,7 +829,7 @@ static void sm501_palette_write(void *opaque,
/* TODO : consider BYTE/WORD access */
/* TODO : consider endian */
- assert(0 <= addr && addr < 0x400 * 3);
+ assert(range_covers_byte(0, 0x400 * 3, addr));
*(uint32_t*)&s->dc_palette[addr] = value;
}
diff --git a/hw/soc_dma.c b/hw/soc_dma.c
index e116e6373a..23ec51695a 100644
--- a/hw/soc_dma.c
+++ b/hw/soc_dma.c
@@ -192,12 +192,13 @@ static void soc_dma_ch_freq_update(struct dma_s *s)
if (s->enabled_count)
/* We completely ignore channel priorities and stuff */
s->channel_freq = s->soc.freq / s->enabled_count;
- else
+ else {
/* TODO: Signal that we want to disable the functional clock and let
* the platform code decide what to do with it, i.e. check that
* auto-idle is enabled in the clock controller and if we are stopping
* the clock, do the same with any parent clocks that had only one
- * user keeping them on and auto-idle enabled. */;
+ * user keeping them on and auto-idle enabled. */
+ }
}
void soc_dma_set_request(struct soc_dma_ch_s *ch, int level)
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index b52170787b..984ffc3e53 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -58,6 +58,7 @@
#define DMA_INTR 1
#define DMA_INTREN 0x10
#define DMA_WRITE_MEM 0x100
+#define DMA_EN 0x200
#define DMA_LOADED 0x04000000
#define DMA_DRAIN_FIFO 0x40
#define DMA_RESET 0x80
@@ -72,7 +73,12 @@ struct DMAState {
uint32_t dmaregs[DMA_REGS];
qemu_irq irq;
void *iommu;
- qemu_irq dev_reset;
+ qemu_irq gpio[2];
+};
+
+enum {
+ GPIO_RESET = 0,
+ GPIO_DMA,
};
/* Note: on sparc, the lance 16 bit bus is swapped */
@@ -201,12 +207,21 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
}
}
if (val & DMA_RESET) {
- qemu_irq_raise(s->dev_reset);
- qemu_irq_lower(s->dev_reset);
+ qemu_irq_raise(s->gpio[GPIO_RESET]);
+ qemu_irq_lower(s->gpio[GPIO_RESET]);
} else if (val & DMA_DRAIN_FIFO) {
val &= ~DMA_DRAIN_FIFO;
} else if (val == 0)
val = DMA_DRAIN_FIFO;
+
+ if (val & DMA_EN && !(s->dmaregs[0] & DMA_EN)) {
+ DPRINTF("Raise DMA enable\n");
+ qemu_irq_raise(s->gpio[GPIO_DMA]);
+ } else if (!(val & DMA_EN) && !!(s->dmaregs[0] & DMA_EN)) {
+ DPRINTF("Lower DMA enable\n");
+ qemu_irq_lower(s->gpio[GPIO_DMA]);
+ }
+
val &= ~DMA_CSR_RO_MASK;
val |= DMA_VER;
s->dmaregs[0] = (s->dmaregs[0] & DMA_CSR_RO_MASK) | val;
@@ -262,7 +277,7 @@ static int sparc32_dma_init1(SysBusDevice *dev)
sysbus_init_mmio(dev, DMA_SIZE, dma_io_memory);
qdev_init_gpio_in(&dev->qdev, dma_set_irq, 1);
- qdev_init_gpio_out(&dev->qdev, &s->dev_reset, 1);
+ qdev_init_gpio_out(&dev->qdev, s->gpio, 2);
return 0;
}
diff --git a/hw/spitz.c b/hw/spitz.c
index ccf2a091fb..a064460936 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -22,6 +22,7 @@
#include "block.h"
#include "audio/audio.h"
#include "boards.h"
+#include "blockdev.h"
#undef REG_FMT
#define REG_FMT "0x%02lx"
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 208c8a86df..0392109230 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -40,6 +40,7 @@
#include "qdev-addr.h"
#include "loader.h"
#include "elf.h"
+#include "blockdev.h"
//#define DEBUG_IRQ
@@ -89,6 +90,7 @@
#define MAX_CPUS 16
#define MAX_PILS 16
+#define MAX_VSIMMS 4
#define ESCC_CLOCK 4915200
@@ -98,6 +100,10 @@ struct sun4m_hwdef {
target_phys_addr_t serial_base, fd_base;
target_phys_addr_t afx_base, idreg_base, dma_base, esp_base, le_base;
target_phys_addr_t tcx_base, cs_base, apc_base, aux1_base, aux2_base;
+ target_phys_addr_t bpp_base, dbri_base, sx_base;
+ struct {
+ target_phys_addr_t reg_base, vram_base;
+ } vsimm[MAX_VSIMMS];
target_phys_addr_t ecc_base;
uint32_t ecc_version;
uint8_t nvram_machine_id;
@@ -804,12 +810,13 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
void *iommu, *espdma, *ledma, *nvram;
qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS],
espdma_irq, ledma_irq;
- qemu_irq esp_reset;
+ qemu_irq esp_reset, dma_enable;
qemu_irq fdc_tc;
qemu_irq *cpu_halt;
unsigned long kernel_size;
DriveInfo *fd[MAX_FD];
void *fw_cfg;
+ unsigned int num_vsimms;
/* init CPUs */
if (!cpu_model)
@@ -872,8 +879,22 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
exit (1);
}
- tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
- graphic_depth);
+ num_vsimms = 0;
+ if (num_vsimms == 0) {
+ tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
+ graphic_depth);
+ }
+
+ for (i = num_vsimms; i < MAX_VSIMMS; i++) {
+ /* vsimm registers probed by OBP */
+ if (hwdef->vsimm[i].reg_base) {
+ empty_slot_init(hwdef->vsimm[i].reg_base, 0x2000);
+ }
+ }
+
+ if (hwdef->sx_base) {
+ empty_slot_init(hwdef->sx_base, 0x2000);
+ }
lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
@@ -909,17 +930,31 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
exit(1);
}
- esp_reset = qdev_get_gpio_in(espdma, 0);
esp_init(hwdef->esp_base, 2,
espdma_memory_read, espdma_memory_write,
- espdma, espdma_irq, &esp_reset);
+ espdma, espdma_irq, &esp_reset, &dma_enable);
+ qdev_connect_gpio_out(espdma, 0, esp_reset);
+ qdev_connect_gpio_out(espdma, 1, dma_enable);
if (hwdef->cs_base) {
sysbus_create_simple("SUNW,CS4231", hwdef->cs_base,
slavio_irq[5]);
}
+ if (hwdef->dbri_base) {
+ /* ISDN chip with attached CS4215 audio codec */
+ /* prom space */
+ empty_slot_init(hwdef->dbri_base+0x1000, 0x30);
+ /* reg space */
+ empty_slot_init(hwdef->dbri_base+0x10000, 0x100);
+ }
+
+ if (hwdef->bpp_base) {
+ /* parallel port */
+ empty_slot_init(hwdef->bpp_base, 0x20);
+ }
+
kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
RAM_size);
@@ -945,8 +980,11 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA,
(uint8_t*)strdup(kernel_cmdline),
strlen(kernel_cmdline) + 1);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+ strlen(kernel_cmdline) + 1);
} else {
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
}
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
@@ -1063,9 +1101,25 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = {
.dma_base = 0xef0400000ULL,
.esp_base = 0xef0800000ULL,
.le_base = 0xef0c00000ULL,
+ .bpp_base = 0xef4800000ULL,
.apc_base = 0xefa000000ULL, // XXX should not exist
.aux1_base = 0xff1800000ULL,
.aux2_base = 0xff1a01000ULL,
+ .dbri_base = 0xee0000000ULL,
+ .sx_base = 0xf80000000ULL,
+ .vsimm = {
+ {
+ .reg_base = 0x9c000000ULL,
+ .vram_base = 0xfc000000ULL
+ }, {
+ .reg_base = 0x90000000ULL,
+ .vram_base = 0xf0000000ULL
+ }, {
+ .reg_base = 0x94000000ULL
+ }, {
+ .reg_base = 0x98000000ULL
+ }
+ },
.ecc_base = 0xf00000000ULL,
.ecc_version = 0x20000000, // version 0, implementation 2
.nvram_machine_id = 0x72,
@@ -1441,7 +1495,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
void *iounits[MAX_IOUNITS], *espdma, *ledma, *nvram;
qemu_irq *cpu_irqs[MAX_CPUS], sbi_irq[32], sbi_cpu_irq[MAX_CPUS],
espdma_irq, ledma_irq;
- qemu_irq esp_reset;
+ qemu_irq esp_reset, dma_enable;
unsigned long kernel_size;
void *fw_cfg;
DeviceState *dev;
@@ -1508,10 +1562,12 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
exit(1);
}
- esp_reset = qdev_get_gpio_in(espdma, 0);
esp_init(hwdef->esp_base, 2,
espdma_memory_read, espdma_memory_write,
- espdma, espdma_irq, &esp_reset);
+ espdma, espdma_irq, &esp_reset, &dma_enable);
+
+ qdev_connect_gpio_out(espdma, 0, esp_reset);
+ qdev_connect_gpio_out(espdma, 1, dma_enable);
kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
RAM_size);
@@ -1630,7 +1686,7 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
{
void *iommu, *espdma, *ledma, *nvram;
qemu_irq *cpu_irqs, slavio_irq[8], espdma_irq, ledma_irq;
- qemu_irq esp_reset;
+ qemu_irq esp_reset, dma_enable;
qemu_irq fdc_tc;
unsigned long kernel_size;
DriveInfo *fd[MAX_FD];
@@ -1698,10 +1754,12 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
exit(1);
}
- esp_reset = qdev_get_gpio_in(espdma, 0);
esp_init(hwdef->esp_base, 2,
espdma_memory_read, espdma_memory_write,
- espdma, espdma_irq, &esp_reset);
+ espdma, espdma_irq, &esp_reset, &dma_enable);
+
+ qdev_connect_gpio_out(espdma, 0, esp_reset);
+ qdev_connect_gpio_out(espdma, 1, dma_enable);
kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
RAM_size);
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 31c0c4c482..45a46d673c 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -37,6 +37,7 @@
#include "ide.h"
#include "loader.h"
#include "elf.h"
+#include "blockdev.h"
//#define DEBUG_IRQ
//#define DEBUG_EBUS
diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c
index abf0370107..4dfd1a87b9 100644
--- a/hw/syborg_virtio.c
+++ b/hw/syborg_virtio.c
@@ -68,6 +68,7 @@ typedef struct {
uint32_t id;
NICConf nic;
uint32_t host_features;
+ virtio_net_conf net;
} SyborgVirtIOProxy;
static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
@@ -284,7 +285,7 @@ static int syborg_virtio_net_init(SysBusDevice *dev)
VirtIODevice *vdev;
SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
- vdev = virtio_net_init(&dev->qdev, &proxy->nic);
+ vdev = virtio_net_init(&dev->qdev, &proxy->nic, &proxy->net);
return syborg_virtio_init(proxy, vdev);
}
@@ -295,6 +296,11 @@ static SysBusDeviceInfo syborg_virtio_net_info = {
.qdev.props = (Property[]) {
DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
DEFINE_VIRTIO_NET_FEATURES(SyborgVirtIOProxy, host_features),
+ DEFINE_PROP_UINT32("x-txtimer", SyborgVirtIOProxy,
+ net.txtimer, TX_TIMER_INTERVAL),
+ DEFINE_PROP_INT32("x-txburst", SyborgVirtIOProxy,
+ net.txburst, TX_BURST),
+ DEFINE_PROP_STRING("tx", SyborgVirtIOProxy, net.tx),
DEFINE_PROP_END_OF_LIST(),
}
};
diff --git a/hw/sysbus.c b/hw/sysbus.c
index 1f7f138416..d817721420 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -82,7 +82,8 @@ void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
}
}
-void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc)
+void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size,
+ ram_addr_t iofunc)
{
int n;
diff --git a/hw/sysbus.h b/hw/sysbus.h
index 1a8f289c75..5980901845 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -21,7 +21,7 @@ struct SysBusDevice {
target_phys_addr_t addr;
target_phys_addr_t size;
mmio_mapfunc cb;
- int iofunc;
+ ram_addr_t iofunc;
} mmio[QDEV_MAX_MMIO];
};
@@ -39,7 +39,8 @@ typedef struct {
void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init);
void sysbus_register_withprop(SysBusDeviceInfo *info);
void *sysbus_new(void);
-void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc);
+void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size,
+ ram_addr_t iofunc);
void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
mmio_mapfunc cb);
void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
diff --git a/hw/tc6393xb_template.h b/hw/tc6393xb_template.h
index 37bf8336be..1ccf6e8dfe 100644
--- a/hw/tc6393xb_template.h
+++ b/hw/tc6393xb_template.h
@@ -38,12 +38,10 @@
static void glue(tc6393xb_draw_graphic, BITS)(TC6393xbState *s)
{
int i;
- int w_display;
uint16_t *data_buffer;
uint8_t *data_display;
data_buffer = s->vram_ptr;
- w_display = s->scr_width * BITS / 8;
data_display = ds_get_data(s->ds);
for(i = 0; i < s->scr_height; i++) {
#if (BITS == 16)
diff --git a/hw/tosa.c b/hw/tosa.c
index ba6d9e73bf..cc8ce6d641 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -19,6 +19,7 @@
#include "boards.h"
#include "i2c.h"
#include "ssi.h"
+#include "blockdev.h"
#define TOSA_RAM 0x04000000
#define TOSA_ROM 0x00800000
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 65e9624e54..0a95d8d506 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -15,6 +15,7 @@
#include "console.h"
#include "monitor.h"
#include "sysemu.h"
+#include "blockdev.h"
//#define DEBUG_MSD
@@ -575,7 +576,7 @@ static USBDevice *usb_msd_init(const char *filename)
/* parse -usbdevice disk: syntax into drive opts */
snprintf(id, sizeof(id), "usb%d", nr++);
- opts = qemu_opts_create(&qemu_drive_opts, id, 0);
+ opts = qemu_opts_create(qemu_find_opts("drive"), id, 0);
p1 = strchr(filename, ':');
if (p1++) {
diff --git a/hw/usb-net.c b/hw/usb-net.c
index a43bd17636..70f9263291 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1472,7 +1472,7 @@ static USBDevice *usb_net_init(const char *cmdline)
QemuOpts *opts;
int idx;
- opts = qemu_opts_parse(&qemu_net_opts, cmdline, 0);
+ opts = qemu_opts_parse(qemu_find_opts("net"), cmdline, 0);
if (!opts) {
return NULL;
}
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index fe052eb756..47f26cd0a3 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -160,6 +160,7 @@ static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
if (!s->mouse_grabbed) {
s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
"QEMU PenPartner tablet");
+ qemu_activate_mouse_event_handler(s->eh_entry);
s->mouse_grabbed = 1;
}
@@ -197,6 +198,7 @@ static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
if (!s->mouse_grabbed) {
s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
"QEMU PenPartner tablet");
+ qemu_activate_mouse_event_handler(s->eh_entry);
s->mouse_grabbed = 1;
}
@@ -334,8 +336,10 @@ static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
ret = 0;
break;
case WACOM_SET_REPORT:
- qemu_remove_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 0;
+ if (s->mouse_grabbed) {
+ qemu_remove_mouse_event_handler(s->eh_entry);
+ s->mouse_grabbed = 0;
+ }
s->mode = data[0];
ret = 0;
break;
@@ -397,7 +401,10 @@ static void usb_wacom_handle_destroy(USBDevice *dev)
{
USBWacomState *s = (USBWacomState *) dev;
- qemu_remove_mouse_event_handler(s->eh_entry);
+ if (s->mouse_grabbed) {
+ qemu_remove_mouse_event_handler(s->eh_entry);
+ s->mouse_grabbed = 0;
+ }
}
static int usb_wacom_initfn(USBDevice *dev)
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 1d049f2342..c51ee02c4d 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -16,6 +16,7 @@
#include "pci.h"
#include "usb-ohci.h"
#include "boards.h"
+#include "blockdev.h"
/* Primary interrupt controller. */
diff --git a/hw/vga.c b/hw/vga.c
index b5c7ee7fe3..966185e03b 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -2313,13 +2313,6 @@ void vga_init(VGACommonState *s)
register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
-
- /* old Bochs IO ports */
- register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
- register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
-
- register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
- register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
#else
register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
diff --git a/hw/vhost.c b/hw/vhost.c
index 65709d005d..8586f66bac 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -11,11 +11,9 @@
*/
#include <sys/ioctl.h>
-#include <sys/eventfd.h>
#include "vhost.h"
#include "hw/hw.h"
-/* For range_get_last */
-#include "pci.h"
+#include "range.h"
#include <linux/vhost.h>
static void vhost_dev_sync_region(struct vhost_dev *dev,
@@ -456,11 +454,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
};
struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
- if (!vdev->binding->set_guest_notifier) {
- fprintf(stderr, "binding does not support guest notifiers\n");
- return -ENOSYS;
- }
-
if (!vdev->binding->set_host_notifier) {
fprintf(stderr, "binding does not support host notifiers\n");
return -ENOSYS;
@@ -513,12 +506,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
r = -errno;
goto fail_alloc;
}
- r = vdev->binding->set_guest_notifier(vdev->binding_opaque, idx, true);
- if (r < 0) {
- fprintf(stderr, "Error binding guest notifier: %d\n", -r);
- goto fail_guest_notifier;
- }
-
r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, true);
if (r < 0) {
fprintf(stderr, "Error binding host notifier: %d\n", -r);
@@ -528,12 +515,14 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
if (r) {
+ r = -errno;
goto fail_kick;
}
file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
if (r) {
+ r = -errno;
goto fail_call;
}
@@ -543,8 +532,6 @@ fail_call:
fail_kick:
vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
fail_host_notifier:
- vdev->binding->set_guest_notifier(vdev->binding_opaque, idx, false);
-fail_guest_notifier:
fail_alloc:
cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
0, 0);
@@ -570,13 +557,6 @@ static void vhost_virtqueue_cleanup(struct vhost_dev *dev,
.index = idx,
};
int r;
- r = vdev->binding->set_guest_notifier(vdev->binding_opaque, idx, false);
- if (r < 0) {
- fprintf(stderr, "vhost VQ %d guest cleanup failed: %d\n", idx, r);
- fflush(stderr);
- }
- assert (r >= 0);
-
r = vdev->binding->set_host_notifier(vdev->binding_opaque, idx, false);
if (r < 0) {
fprintf(stderr, "vhost VQ %d host cleanup failed: %d\n", idx, r);
@@ -649,15 +629,26 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
{
int i, r;
+ if (!vdev->binding->set_guest_notifiers) {
+ fprintf(stderr, "binding does not support guest notifiers\n");
+ r = -ENOSYS;
+ goto fail;
+ }
+
+ r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, true);
+ if (r < 0) {
+ fprintf(stderr, "Error binding guest notifier: %d\n", -r);
+ goto fail_notifiers;
+ }
r = vhost_dev_set_features(hdev, hdev->log_enabled);
if (r < 0) {
- goto fail;
+ goto fail_features;
}
r = ioctl(hdev->control, VHOST_SET_MEM_TABLE, hdev->mem);
if (r < 0) {
r = -errno;
- goto fail;
+ goto fail_mem;
}
for (i = 0; i < hdev->nvqs; ++i) {
r = vhost_virtqueue_init(hdev,
@@ -677,13 +668,14 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
(uint64_t)(unsigned long)hdev->log);
if (r < 0) {
r = -errno;
- goto fail_vq;
+ goto fail_log;
}
}
hdev->started = true;
return 0;
+fail_log:
fail_vq:
while (--i >= 0) {
vhost_virtqueue_cleanup(hdev,
@@ -691,13 +683,18 @@ fail_vq:
hdev->vqs + i,
i);
}
+fail_mem:
+fail_features:
+ vdev->binding->set_guest_notifiers(vdev->binding_opaque, false);
+fail_notifiers:
fail:
return r;
}
void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
{
- int i;
+ int i, r;
+
for (i = 0; i < hdev->nvqs; ++i) {
vhost_virtqueue_cleanup(hdev,
vdev,
@@ -706,6 +703,13 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
}
vhost_client_sync_dirty_bitmap(&hdev->client, 0,
(target_phys_addr_t)~0x0ull);
+ r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, false);
+ if (r < 0) {
+ fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
+ fflush(stderr);
+ }
+ assert (r >= 0);
+
hdev->started = false;
qemu_free(hdev->log);
hdev->log_size = 0;
diff --git a/hw/vhost_net.c b/hw/vhost_net.c
index 606aa0c1c9..c068be1f54 100644
--- a/hw/vhost_net.c
+++ b/hw/vhost_net.c
@@ -20,7 +20,6 @@
#ifdef CONFIG_VHOST_NET
#include <linux/vhost.h>
-#include <sys/eventfd.h>
#include <sys/socket.h>
#include <linux/kvm.h>
#include <fcntl.h>
@@ -51,7 +50,9 @@ unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
}
- features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+ if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) {
+ features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+ }
return features;
}
@@ -64,6 +65,9 @@ void vhost_net_ack_features(struct vhost_net *net, unsigned features)
if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
}
+ if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+ net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
+ }
}
static int vhost_net_get_fd(VLANClientState *backend)
@@ -98,6 +102,10 @@ struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd)
if (r < 0) {
goto fail;
}
+ if (!tap_has_vnet_hdr_len(backend,
+ sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
+ net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+ }
if (~net->dev.features & net->dev.backend_features) {
fprintf(stderr, "vhost lacks feature mask %" PRIu64 " for backend\n",
(uint64_t)(~net->dev.features & net->dev.backend_features));
@@ -118,6 +126,10 @@ int vhost_net_start(struct vhost_net *net,
{
struct vhost_vring_file file = { };
int r;
+ if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+ tap_set_vnet_hdr_len(net->vc,
+ sizeof(struct virtio_net_hdr_mrg_rxbuf));
+ }
net->dev.nvqs = 2;
net->dev.vqs = net->vqs;
@@ -139,12 +151,15 @@ int vhost_net_start(struct vhost_net *net,
return 0;
fail:
file.fd = -1;
- while (--file.index >= 0) {
+ while (file.index-- > 0) {
int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
assert(r >= 0);
}
net->vc->info->poll(net->vc, true);
vhost_dev_stop(&net->dev, dev);
+ if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+ tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
+ }
return r;
}
@@ -159,11 +174,17 @@ void vhost_net_stop(struct vhost_net *net,
}
net->vc->info->poll(net->vc, true);
vhost_dev_stop(&net->dev, dev);
+ if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+ tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
+ }
}
void vhost_net_cleanup(struct vhost_net *net)
{
vhost_dev_cleanup(&net->dev);
+ if (net->dev.acked_features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+ tap_set_vnet_hdr_len(net->vc, sizeof(struct virtio_net_hdr));
+ }
qemu_free(net);
}
#else
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
new file mode 100644
index 0000000000..fa605158e7
--- /dev/null
+++ b/hw/virtex_ml507.c
@@ -0,0 +1,276 @@
+/*
+ * Model of Xilinx Virtex5 ML507 PPC-440 refdesign.
+ *
+ * Copyright (c) 2010 Edgar E. Iglesias.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "hw.h"
+#include "pc.h"
+#include "net.h"
+#include "flash.h"
+#include "sysemu.h"
+#include "devices.h"
+#include "boards.h"
+#include "device_tree.h"
+#include "loader.h"
+#include "elf.h"
+#include "qemu-log.h"
+
+#include "ppc.h"
+#include "ppc4xx.h"
+#include "ppc440.h"
+#include "ppc405.h"
+
+#include "blockdev.h"
+#include "xilinx.h"
+
+#define EPAPR_MAGIC (0x45504150)
+#define FLASH_SIZE (16 * 1024 * 1024)
+
+static struct boot_info
+{
+ uint32_t bootstrap_pc;
+ uint32_t cmdline;
+ uint32_t fdt;
+ uint32_t ima_size;
+ void *vfdt;
+} boot_info;
+
+/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
+static void mmubooke_create_initial_mapping(CPUState *env,
+ target_ulong va,
+ target_phys_addr_t pa)
+{
+ ppcemb_tlb_t *tlb = &env->tlb[0].tlbe;
+
+ tlb->attr = 0;
+ tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+ tlb->size = 1 << 31; /* up to 0x80000000 */
+ tlb->EPN = va & TARGET_PAGE_MASK;
+ tlb->RPN = pa & TARGET_PAGE_MASK;
+ tlb->PID = 0;
+
+ tlb = &env->tlb[1].tlbe;
+ tlb->attr = 0;
+ tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+ tlb->size = 1 << 31; /* up to 0xffffffff */
+ tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
+ tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
+ tlb->PID = 0;
+}
+
+static CPUState *ppc440_init_xilinx(ram_addr_t *ram_size,
+ int do_init,
+ const char *cpu_model,
+ clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
+ uint32_t sysclk)
+{
+ CPUState *env;
+ qemu_irq *irqs;
+
+ env = cpu_init(cpu_model);
+ if (!env) {
+ fprintf(stderr, "Unable to initialize CPU!\n");
+ exit(1);
+ }
+
+ cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
+ cpu_clk->opaque = env;
+ /* Set time-base frequency to sysclk */
+ tb_clk->cb = ppc_emb_timers_init(env, sysclk, PPC_INTERRUPT_DECR);
+ tb_clk->opaque = env;
+
+ ppc_dcr_init(env, NULL, NULL);
+
+ /* interrupt controller */
+ irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+ irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+ irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+ ppcuic_init(env, irqs, 0x0C0, 0, 1);
+ return env;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+ struct boot_info *bi = env->load_info;
+
+ cpu_reset(env);
+ /* Linux Kernel Parameters (passing device tree):
+ * r3: pointer to the fdt
+ * r4: 0
+ * r5: 0
+ * r6: epapr magic
+ * r7: size of IMA in bytes
+ * r8: 0
+ * r9: 0
+ */
+ env->gpr[1] = (16<<20) - 8;
+ /* Provide a device-tree. */
+ env->gpr[3] = bi->fdt;
+ env->nip = bi->bootstrap_pc;
+
+ /* Create a mapping for the kernel. */
+ mmubooke_create_initial_mapping(env, 0, 0);
+ env->gpr[6] = tswap32(EPAPR_MAGIC);
+ env->gpr[7] = bi->ima_size;
+}
+
+#define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb"
+static int xilinx_load_device_tree(target_phys_addr_t addr,
+ uint32_t ramsize,
+ target_phys_addr_t initrd_base,
+ target_phys_addr_t initrd_size,
+ const char *kernel_cmdline)
+{
+ char *path;
+ int fdt_size;
+#ifdef CONFIG_FDT
+ void *fdt;
+ int r;
+
+ /* Try the local "ppc.dtb" override. */
+ fdt = load_device_tree("ppc.dtb", &fdt_size);
+ if (!fdt) {
+ path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+ if (path) {
+ fdt = load_device_tree(path, &fdt_size);
+ qemu_free(path);
+ }
+ if (!fdt) {
+ return 0;
+ }
+ }
+
+ r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
+ if (r < 0)
+ fprintf(stderr, "couldn't set /chosen/bootargs\n");
+ cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
+#else
+ /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
+ to the kernel. */
+ fdt_size = load_image_targphys("ppc.dtb", addr, 0x10000);
+ if (fdt_size < 0) {
+ path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+ if (path) {
+ fdt_size = load_image_targphys(path, addr, 0x10000);
+ qemu_free(path);
+ }
+ }
+
+ if (kernel_cmdline) {
+ fprintf(stderr,
+ "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
+ }
+#endif
+ return fdt_size;
+}
+
+static void virtex_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ DeviceState *dev;
+ CPUState *env;
+ target_phys_addr_t ram_base = 0;
+ DriveInfo *dinfo;
+ ram_addr_t phys_ram;
+ ram_addr_t phys_flash;
+ qemu_irq irq[32], *cpu_irq;
+ clk_setup_t clk_setup[7];
+ int kernel_size;
+ int i;
+
+ /* init CPUs */
+ if (cpu_model == NULL) {
+ cpu_model = "440-Xilinx";
+ }
+
+ memset(clk_setup, 0, sizeof(clk_setup));
+ env = ppc440_init_xilinx(&ram_size, 1, cpu_model, &clk_setup[0],
+ &clk_setup[1], 400000000);
+ qemu_register_reset(main_cpu_reset, env);
+
+ phys_ram = qemu_ram_alloc(NULL, "ram", ram_size);
+ cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
+
+ phys_flash = qemu_ram_alloc(NULL, "virtex.flash", FLASH_SIZE);
+ dinfo = drive_get(IF_PFLASH, 0, 0);
+ pflash_cfi01_register(0xfc000000, phys_flash,
+ dinfo ? dinfo->bdrv : NULL, (64 * 1024),
+ FLASH_SIZE >> 16,
+ 1, 0x89, 0x18, 0x0000, 0x0, 1);
+
+ cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT];
+ dev = xilinx_intc_create(0x81800000, cpu_irq[0], 0);
+ for (i = 0; i < 32; i++) {
+ irq[i] = qdev_get_gpio_in(dev, i);
+ }
+
+ serial_mm_init(0x83e01003ULL, 2, irq[9], 115200, serial_hds[0], 1, 0);
+
+ /* 2 timers at irq 2 @ 62 Mhz. */
+ xilinx_timer_create(0x83c00000, irq[3], 2, 62 * 1000000);
+
+ if (kernel_filename) {
+ uint64_t entry, low, high;
+ target_phys_addr_t boot_offset;
+
+ /* Boots a kernel elf binary. */
+ kernel_size = load_elf(kernel_filename, NULL, NULL,
+ &entry, &low, &high, 1, ELF_MACHINE, 0);
+ boot_info.bootstrap_pc = entry & 0x00ffffff;
+
+ if (kernel_size < 0) {
+ boot_offset = 0x1200000;
+ /* If we failed loading ELF's try a raw image. */
+ kernel_size = load_image_targphys(kernel_filename,
+ boot_offset,
+ ram_size);
+ boot_info.bootstrap_pc = boot_offset;
+ high = boot_info.bootstrap_pc + kernel_size + 8192;
+ }
+
+ boot_info.ima_size = kernel_size;
+
+ /* Provide a device-tree. */
+ boot_info.fdt = high + (8192 * 2);
+ boot_info.fdt &= ~8191;
+ xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline);
+ }
+ env->load_info = &boot_info;
+}
+
+static QEMUMachine virtex_machine = {
+ .name = "virtex-ml507",
+ .desc = "Xilinx Virtex ML507 reference design",
+ .init = virtex_init,
+};
+
+static void virtex_machine_init(void)
+{
+ qemu_register_machine(&virtex_machine);
+}
+
+machine_init(virtex_machine_init);
diff --git a/hw/virtio-9p-debug.c b/hw/virtio-9p-debug.c
index e4ab4bca5f..cff5b07297 100644
--- a/hw/virtio-9p-debug.c
+++ b/hw/virtio-9p-debug.c
@@ -169,15 +169,37 @@ static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
pprint_str(pdu, rx, offsetp, ", uid");
pprint_str(pdu, rx, offsetp, ", gid");
pprint_str(pdu, rx, offsetp, ", muid");
- if (dotu) {
- pprint_str(pdu, rx, offsetp, ", extension");
- pprint_int32(pdu, rx, offsetp, ", uid");
- pprint_int32(pdu, rx, offsetp, ", gid");
- pprint_int32(pdu, rx, offsetp, ", muid");
- }
+ pprint_str(pdu, rx, offsetp, ", extension");
+ pprint_int32(pdu, rx, offsetp, ", uid");
+ pprint_int32(pdu, rx, offsetp, ", gid");
+ pprint_int32(pdu, rx, offsetp, ", muid");
+ fprintf(llogfile, "}");
+}
+
+static void pprint_stat_dotl(V9fsPDU *pdu, int rx, size_t *offsetp,
+ const char *name)
+{
+ fprintf(llogfile, "%s={", name);
+ pprint_qid(pdu, rx, offsetp, "qid");
+ pprint_int32(pdu, rx, offsetp, ", st_mode");
+ pprint_int64(pdu, rx, offsetp, ", st_nlink");
+ pprint_int32(pdu, rx, offsetp, ", st_uid");
+ pprint_int32(pdu, rx, offsetp, ", st_gid");
+ pprint_int64(pdu, rx, offsetp, ", st_rdev");
+ pprint_int64(pdu, rx, offsetp, ", st_size");
+ pprint_int64(pdu, rx, offsetp, ", st_blksize");
+ pprint_int64(pdu, rx, offsetp, ", st_blocks");
+ pprint_int64(pdu, rx, offsetp, ", atime");
+ pprint_int64(pdu, rx, offsetp, ", atime_nsec");
+ pprint_int64(pdu, rx, offsetp, ", mtime");
+ pprint_int64(pdu, rx, offsetp, ", mtime_nsec");
+ pprint_int64(pdu, rx, offsetp, ", ctime");
+ pprint_int64(pdu, rx, offsetp, ", ctime_nsec");
fprintf(llogfile, "}");
}
+
+
static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name)
{
int sg_count = get_sg_count(pdu, rx);
@@ -327,7 +349,33 @@ void pprint_pdu(V9fsPDU *pdu)
llogfile = fopen("/tmp/pdu.log", "w");
}
+ BUG_ON(!llogfile);
+
switch (pdu->id) {
+ case P9_TREADDIR:
+ fprintf(llogfile, "TREADDIR: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_int64(pdu, 0, &offset, ", initial offset");
+ pprint_int32(pdu, 0, &offset, ", max count");
+ break;
+ case P9_RREADDIR:
+ fprintf(llogfile, "RREADDIR: (");
+ pprint_int32(pdu, 1, &offset, "count");
+#ifdef DEBUG_DATA
+ pprint_data(pdu, 1, &offset, ", data");
+#endif
+ break;
+ case P9_TMKDIR:
+ fprintf(llogfile, "TMKDIR: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_str(pdu, 0, &offset, "name");
+ pprint_int32(pdu, 0, &offset, "mode");
+ pprint_int32(pdu, 0, &offset, "gid");
+ break;
+ case P9_RMKDIR:
+ fprintf(llogfile, "RMKDIR: (");
+ pprint_qid(pdu, 0, &offset, "qid");
+ break;
case P9_TVERSION:
fprintf(llogfile, "TVERSION: (");
pprint_int32(pdu, 0, &offset, "msize");
@@ -338,14 +386,20 @@ void pprint_pdu(V9fsPDU *pdu)
pprint_int32(pdu, 1, &offset, "msize");
pprint_str(pdu, 1, &offset, ", version");
break;
+ case P9_TGETATTR:
+ fprintf(llogfile, "TGETATTR: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ break;
+ case P9_RGETATTR:
+ fprintf(llogfile, "RGETATTR: (");
+ pprint_stat_dotl(pdu, 1, &offset, "getattr");
+ break;
case P9_TAUTH:
fprintf(llogfile, "TAUTH: (");
pprint_int32(pdu, 0, &offset, "afid");
pprint_str(pdu, 0, &offset, ", uname");
pprint_str(pdu, 0, &offset, ", aname");
- if (dotu) {
- pprint_int32(pdu, 0, &offset, ", n_uname");
- }
+ pprint_int32(pdu, 0, &offset, ", n_uname");
break;
case P9_RAUTH:
fprintf(llogfile, "RAUTH: (");
@@ -357,9 +411,7 @@ void pprint_pdu(V9fsPDU *pdu)
pprint_int32(pdu, 0, &offset, ", afid");
pprint_str(pdu, 0, &offset, ", uname");
pprint_str(pdu, 0, &offset, ", aname");
- if (dotu) {
- pprint_int32(pdu, 0, &offset, ", n_uname");
- }
+ pprint_int32(pdu, 0, &offset, ", n_uname");
break;
case P9_RATTACH:
fprintf(llogfile, "RATTACH: (");
@@ -371,9 +423,7 @@ void pprint_pdu(V9fsPDU *pdu)
case P9_RERROR:
fprintf(llogfile, "RERROR: (");
pprint_str(pdu, 1, &offset, "ename");
- if (dotu) {
- pprint_int32(pdu, 1, &offset, ", ecode");
- }
+ pprint_int32(pdu, 1, &offset, ", ecode");
break;
case P9_TFLUSH:
fprintf(llogfile, "TFLUSH: (");
@@ -408,15 +458,58 @@ void pprint_pdu(V9fsPDU *pdu)
pprint_str(pdu, 0, &offset, ", name");
pprint_int32(pdu, 0, &offset, ", perm");
pprint_int8(pdu, 0, &offset, ", mode");
- if (dotu) {
- pprint_str(pdu, 0, &offset, ", extension");
- }
+ pprint_str(pdu, 0, &offset, ", extension");
break;
case P9_RCREATE:
fprintf(llogfile, "RCREATE: (");
pprint_qid(pdu, 1, &offset, "qid");
pprint_int32(pdu, 1, &offset, ", iounit");
break;
+ case P9_TSYMLINK:
+ fprintf(llogfile, "TSYMLINK: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_str(pdu, 0, &offset, ", name");
+ pprint_str(pdu, 0, &offset, ", symname");
+ pprint_int32(pdu, 0, &offset, ", gid");
+ break;
+ case P9_RSYMLINK:
+ fprintf(llogfile, "RSYMLINK: (");
+ pprint_qid(pdu, 1, &offset, "qid");
+ break;
+ case P9_TLCREATE:
+ fprintf(llogfile, "TLCREATE: (");
+ pprint_int32(pdu, 0, &offset, "dfid");
+ pprint_str(pdu, 0, &offset, ", name");
+ pprint_int32(pdu, 0, &offset, ", flags");
+ pprint_int32(pdu, 0, &offset, ", mode");
+ pprint_int32(pdu, 0, &offset, ", gid");
+ break;
+ case P9_RLCREATE:
+ fprintf(llogfile, "RLCREATE: (");
+ pprint_qid(pdu, 1, &offset, "qid");
+ pprint_int32(pdu, 1, &offset, ", iounit");
+ break;
+ case P9_TMKNOD:
+ fprintf(llogfile, "TMKNOD: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_str(pdu, 0, &offset, "name");
+ pprint_int32(pdu, 0, &offset, "mode");
+ pprint_int32(pdu, 0, &offset, "major");
+ pprint_int32(pdu, 0, &offset, "minor");
+ pprint_int32(pdu, 0, &offset, "gid");
+ break;
+ case P9_RMKNOD:
+ fprintf(llogfile, "RMKNOD: )");
+ pprint_qid(pdu, 0, &offset, "qid");
+ break;
+ case P9_TREADLINK:
+ fprintf(llogfile, "TREADLINK: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ break;
+ case P9_RREADLINK:
+ fprintf(llogfile, "RREADLINK: (");
+ pprint_str(pdu, 0, &offset, "target");
+ break;
case P9_TREAD:
fprintf(llogfile, "TREAD: (");
pprint_int32(pdu, 0, &offset, "fid");
@@ -450,6 +543,22 @@ void pprint_pdu(V9fsPDU *pdu)
case P9_RCLUNK:
fprintf(llogfile, "RCLUNK: (");
break;
+ case P9_TFSYNC:
+ fprintf(llogfile, "TFSYNC: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ break;
+ case P9_RFSYNC:
+ fprintf(llogfile, "RFSYNC: (");
+ break;
+ case P9_TLINK:
+ fprintf(llogfile, "TLINK: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_str(pdu, 0, &offset, ", oldpath");
+ pprint_str(pdu, 0, &offset, ", newpath");
+ break;
+ case P9_RLINK:
+ fprintf(llogfile, "RLINK: (");
+ break;
case P9_TREMOVE:
fprintf(llogfile, "TREMOVE: (");
pprint_int32(pdu, 0, &offset, "fid");
@@ -475,6 +584,56 @@ void pprint_pdu(V9fsPDU *pdu)
case P9_RWSTAT:
fprintf(llogfile, "RWSTAT: (");
break;
+ case P9_TXATTRWALK:
+ fprintf(llogfile, "TXATTRWALK: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_int32(pdu, 0, &offset, ", newfid");
+ pprint_str(pdu, 0, &offset, ", xattr name");
+ break;
+ case P9_RXATTRWALK:
+ fprintf(llogfile, "RXATTRWALK: (");
+ pprint_int64(pdu, 1, &offset, "xattrsize");
+ case P9_TXATTRCREATE:
+ fprintf(llogfile, "TXATTRCREATE: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_str(pdu, 0, &offset, ", name");
+ pprint_int64(pdu, 0, &offset, ", xattrsize");
+ pprint_int32(pdu, 0, &offset, ", flags");
+ break;
+ case P9_RXATTRCREATE:
+ fprintf(llogfile, "RXATTRCREATE: (");
+ break;
+ case P9_TLOCK:
+ fprintf(llogfile, "TLOCK: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_int8(pdu, 0, &offset, ", type");
+ pprint_int32(pdu, 0, &offset, ", flags");
+ pprint_int64(pdu, 0, &offset, ", start");
+ pprint_int64(pdu, 0, &offset, ", length");
+ pprint_int32(pdu, 0, &offset, ", proc_id");
+ pprint_str(pdu, 0, &offset, ", client_id");
+ break;
+ case P9_RLOCK:
+ fprintf(llogfile, "RLOCK: (");
+ pprint_int8(pdu, 0, &offset, "status");
+ break;
+ case P9_TGETLOCK:
+ fprintf(llogfile, "TGETLOCK: (");
+ pprint_int32(pdu, 0, &offset, "fid");
+ pprint_int8(pdu, 0, &offset, ", type");
+ pprint_int64(pdu, 0, &offset, ", start");
+ pprint_int64(pdu, 0, &offset, ", length");
+ pprint_int32(pdu, 0, &offset, ", proc_id");
+ pprint_str(pdu, 0, &offset, ", client_id");
+ break;
+ case P9_RGETLOCK:
+ fprintf(llogfile, "RGETLOCK: (");
+ pprint_int8(pdu, 0, &offset, "type");
+ pprint_int64(pdu, 0, &offset, ", start");
+ pprint_int64(pdu, 0, &offset, ", length");
+ pprint_int32(pdu, 0, &offset, ", proc_id");
+ pprint_str(pdu, 0, &offset, ", client_id");
+ break;
default:
fprintf(llogfile, "unknown(%d): (", pdu->id);
break;
diff --git a/hw/virtio-9p-debug.h b/hw/virtio-9p-debug.h
index 0104be5eb3..d9a249118d 100644
--- a/hw/virtio-9p-debug.h
+++ b/hw/virtio-9p-debug.h
@@ -1,7 +1,6 @@
#ifndef _QEMU_VIRTIO_9P_DEBUG_H
#define _QEMU_VIRTIO_9P_DEBUG_H
-extern int dotu;
void pprint_pdu(V9fsPDU *pdu);
#endif
diff --git a/hw/virtio-9p-local.c b/hw/virtio-9p-local.c
index 04f7f6f501..0d520201b4 100644
--- a/hw/virtio-9p-local.c
+++ b/hw/virtio-9p-local.c
@@ -12,6 +12,7 @@
*/
#include "virtio.h"
#include "virtio-9p.h"
+#include "virtio-9p-xattr.h"
#include <arpa/inet.h>
#include <pwd.h>
#include <grp.h>
@@ -19,14 +20,6 @@
#include <sys/un.h>
#include <attr/xattr.h>
-static 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;
-}
-
static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
{
@@ -101,8 +94,14 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
if (chmod(rpath(fs_ctx, path), credp->fc_mode & 07777) < 0) {
return -1;
}
- if (chown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid) < 0) {
- return -1;
+ if (lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid) < 0) {
+ /*
+ * If we fail to change ownership and if we are
+ * using security model none. Ignore the error
+ */
+ if (fs_ctx->fs_sm != SM_NONE) {
+ return -1;
+ }
}
return 0;
}
@@ -122,7 +121,8 @@ static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
} while (tsize == -1 && errno == EINTR);
close(fd);
return tsize;
- } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+ } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+ (fs_ctx->fs_sm == SM_NONE)) {
tsize = readlink(rpath(fs_ctx, path), buf, bufsz);
}
return tsize;
@@ -168,28 +168,42 @@ static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
return seekdir(dir, off);
}
-static ssize_t local_readv(FsContext *ctx, int fd, const struct iovec *iov,
- int iovcnt)
+static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov,
+ int iovcnt, off_t offset)
{
- return readv(fd, iov, iovcnt);
-}
-
-static off_t local_lseek(FsContext *ctx, int fd, off_t offset, int whence)
-{
- return lseek(fd, offset, whence);
+#ifdef CONFIG_PREADV
+ return preadv(fd, iov, iovcnt, offset);
+#else
+ int err = lseek(fd, offset, SEEK_SET);
+ if (err == -1) {
+ return err;
+ } else {
+ return readv(fd, iov, iovcnt);
+ }
+#endif
}
-static ssize_t local_writev(FsContext *ctx, int fd, const struct iovec *iov,
- int iovcnt)
+static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
+ int iovcnt, off_t offset)
{
- return writev(fd, iov, iovcnt);
+#ifdef CONFIG_PREADV
+ return pwritev(fd, iov, iovcnt, offset);
+#else
+ int err = lseek(fd, offset, SEEK_SET);
+ if (err == -1) {
+ return err;
+ } else {
+ return writev(fd, iov, iovcnt);
+ }
+#endif
}
static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
{
if (fs_ctx->fs_sm == SM_MAPPED) {
return local_set_xattr(rpath(fs_ctx, path), credp);
- } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+ } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+ (fs_ctx->fs_sm == SM_NONE)) {
return chmod(rpath(fs_ctx, path), credp->fc_mode);
}
return -1;
@@ -211,7 +225,8 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
serrno = errno;
goto err_end;
}
- } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+ } 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);
if (err == -1) {
return err;
@@ -247,7 +262,8 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
serrno = errno;
goto err_end;
}
- } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+ } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+ (fs_ctx->fs_sm == SM_NONE)) {
err = mkdir(rpath(fs_ctx, path), credp->fc_mode);
if (err == -1) {
return err;
@@ -316,7 +332,8 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags,
serrno = errno;
goto err_end;
}
- } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+ } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+ (fs_ctx->fs_sm == SM_NONE)) {
fd = open(rpath(fs_ctx, path), flags, credp->fc_mode);
if (fd == -1) {
return fd;
@@ -372,15 +389,23 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
serrno = errno;
goto err_end;
}
- } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+ } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
+ (fs_ctx->fs_sm == SM_NONE)) {
err = symlink(oldpath, rpath(fs_ctx, newpath));
if (err) {
return err;
}
err = lchown(rpath(fs_ctx, newpath), credp->fc_uid, credp->fc_gid);
if (err == -1) {
- serrno = errno;
- goto err_end;
+ /*
+ * If we fail to change ownership and if we are
+ * using security model none. Ignore the error
+ */
+ if (fs_ctx->fs_sm != SM_NONE) {
+ serrno = errno;
+ goto err_end;
+ } else
+ err = 0;
}
}
return err;
@@ -426,9 +451,6 @@ static int local_rename(FsContext *ctx, const char *oldpath,
int err;
tmp = qemu_strdup(rpath(ctx, oldpath));
- if (tmp == NULL) {
- return -1;
- }
err = rename(tmp, rpath(ctx, newpath));
if (err == -1) {
@@ -445,18 +467,22 @@ static int local_rename(FsContext *ctx, const char *oldpath,
static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
{
- if (fs_ctx->fs_sm == SM_MAPPED) {
+ 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);
+ } else if (fs_ctx->fs_sm == SM_MAPPED) {
return local_set_xattr(rpath(fs_ctx, path), credp);
- } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+ } 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 -1;
}
-static int local_utime(FsContext *ctx, const char *path,
- const struct utimbuf *buf)
+static int local_utimensat(FsContext *s, const char *path,
+ const struct timespec *buf)
{
- return utime(rpath(ctx, path), buf);
+ return utimensat(AT_FDCWD, rpath(s, path), buf, AT_SYMLINK_NOFOLLOW);
}
static int local_remove(FsContext *ctx, const char *path)
@@ -469,6 +495,36 @@ static int local_fsync(FsContext *ctx, int fd)
return fsync(fd);
}
+static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
+{
+ return statfs(rpath(s, path), stbuf);
+}
+
+static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
+ const char *name, void *value, size_t size)
+{
+ return v9fs_get_xattr(ctx, path, name, value, size);
+}
+
+static ssize_t local_llistxattr(FsContext *ctx, const char *path,
+ void *value, size_t size)
+{
+ return v9fs_list_xattr(ctx, path, value, size);
+}
+
+static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
+ void *value, size_t size, int flags)
+{
+ return v9fs_set_xattr(ctx, path, name, value, size, flags);
+}
+
+static int local_lremovexattr(FsContext *ctx,
+ const char *path, const char *name)
+{
+ return v9fs_remove_xattr(ctx, path, name);
+}
+
+
FileOperations local_ops = {
.lstat = local_lstat,
.readlink = local_readlink,
@@ -480,9 +536,8 @@ FileOperations local_ops = {
.telldir = local_telldir,
.readdir = local_readdir,
.seekdir = local_seekdir,
- .readv = local_readv,
- .lseek = local_lseek,
- .writev = local_writev,
+ .preadv = local_preadv,
+ .pwritev = local_pwritev,
.chmod = local_chmod,
.mknod = local_mknod,
.mkdir = local_mkdir,
@@ -493,7 +548,12 @@ FileOperations local_ops = {
.truncate = local_truncate,
.rename = local_rename,
.chown = local_chown,
- .utime = local_utime,
+ .utimensat = local_utimensat,
.remove = local_remove,
.fsync = local_fsync,
+ .statfs = local_statfs,
+ .lgetxattr = local_lgetxattr,
+ .llistxattr = local_llistxattr,
+ .lsetxattr = local_lsetxattr,
+ .lremovexattr = local_lremovexattr,
};
diff --git a/hw/virtio-9p-posix-acl.c b/hw/virtio-9p-posix-acl.c
new file mode 100644
index 0000000000..3978d0cf71
--- /dev/null
+++ b/hw/virtio-9p-posix-acl.c
@@ -0,0 +1,140 @@
+/*
+ * Virtio 9p system.posix* xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.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 <sys/types.h>
+#include <attr/xattr.h>
+#include "virtio.h"
+#include "virtio-9p.h"
+#include "file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+#define MAP_ACL_ACCESS "user.virtfs.system.posix_acl_access"
+#define MAP_ACL_DEFAULT "user.virtfs.system.posix_acl_default"
+#define ACL_ACCESS "system.posix_acl_access"
+#define ACL_DEFAULT "system.posix_acl_default"
+
+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);
+}
+
+static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
+ char *name, void *value, size_t osize)
+{
+ ssize_t len = sizeof(ACL_ACCESS);
+
+ if (!value) {
+ return len;
+ }
+
+ if (osize < len) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ strncpy(value, ACL_ACCESS, len);
+ return 0;
+}
+
+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);
+}
+
+static int mp_pacl_removexattr(FsContext *ctx,
+ const char *path, const char *name)
+{
+ int ret;
+ ret = lremovexattr(rpath(ctx, path), MAP_ACL_ACCESS);
+ if (ret == -1 && errno == ENODATA) {
+ /*
+ * We don't get ENODATA error when trying to remote a
+ * posix acl that is not present. So don't throw the error
+ * even in case of mapped security model
+ */
+ errno = 0;
+ ret = 0;
+ }
+ return ret;
+}
+
+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);
+}
+
+static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
+ char *name, void *value, size_t osize)
+{
+ ssize_t len = sizeof(ACL_DEFAULT);
+
+ if (!value) {
+ return len;
+ }
+
+ if (osize < len) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ strncpy(value, ACL_DEFAULT, len);
+ return 0;
+}
+
+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);
+}
+
+static int mp_dacl_removexattr(FsContext *ctx,
+ const char *path, const char *name)
+{
+ return lremovexattr(rpath(ctx, path), MAP_ACL_DEFAULT);
+}
+
+
+XattrOperations mapped_pacl_xattr = {
+ .name = "system.posix_acl_access",
+ .getxattr = mp_pacl_getxattr,
+ .setxattr = mp_pacl_setxattr,
+ .listxattr = mp_pacl_listxattr,
+ .removexattr = mp_pacl_removexattr,
+};
+
+XattrOperations mapped_dacl_xattr = {
+ .name = "system.posix_acl_default",
+ .getxattr = mp_dacl_getxattr,
+ .setxattr = mp_dacl_setxattr,
+ .listxattr = mp_dacl_listxattr,
+ .removexattr = mp_dacl_removexattr,
+};
+
+XattrOperations passthrough_acl_xattr = {
+ .name = "system.posix_acl_",
+ .getxattr = pt_getxattr,
+ .setxattr = pt_setxattr,
+ .listxattr = pt_listxattr,
+ .removexattr = pt_removexattr,
+};
+
+XattrOperations none_acl_xattr = {
+ .name = "system.posix_acl_",
+ .getxattr = notsup_getxattr,
+ .setxattr = notsup_setxattr,
+ .listxattr = notsup_listxattr,
+ .removexattr = notsup_removexattr,
+};
diff --git a/hw/virtio-9p-xattr-user.c b/hw/virtio-9p-xattr-user.c
new file mode 100644
index 0000000000..faa02a1911
--- /dev/null
+++ b/hw/virtio-9p-xattr-user.c
@@ -0,0 +1,109 @@
+/*
+ * Virtio 9p user. xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.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 <sys/types.h>
+#include "virtio.h"
+#include "virtio-9p.h"
+#include "file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+
+static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
+ const char *name, void *value, size_t size)
+{
+ if (strncmp(name, "user.virtfs.", 12) == 0) {
+ /*
+ * Don't allow fetch of user.virtfs namesapce
+ * in case of mapped security
+ */
+ errno = ENOATTR;
+ return -1;
+ }
+ return lgetxattr(rpath(ctx, path), name, value, size);
+}
+
+static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
+ char *name, void *value, size_t size)
+{
+ int name_size = strlen(name) + 1;
+ if (strncmp(name, "user.virtfs.", 12) == 0) {
+
+ /* check if it is a mapped posix acl */
+ if (strncmp(name, "user.virtfs.system.posix_acl_", 29) == 0) {
+ /* adjust the name and size */
+ name += 12;
+ name_size -= 12;
+ } else {
+ /*
+ * Don't allow fetch of user.virtfs namesapce
+ * in case of mapped security
+ */
+ return 0;
+ }
+ }
+ if (!value) {
+ return name_size;
+ }
+
+ if (size < name_size) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ strncpy(value, name, name_size);
+ return name_size;
+}
+
+static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
+ void *value, size_t size, int flags)
+{
+ if (strncmp(name, "user.virtfs.", 12) == 0) {
+ /*
+ * Don't allow fetch of user.virtfs namesapce
+ * in case of mapped security
+ */
+ errno = EACCES;
+ return -1;
+ }
+ return lsetxattr(rpath(ctx, path), name, value, size, flags);
+}
+
+static int mp_user_removexattr(FsContext *ctx,
+ const char *path, const char *name)
+{
+ if (strncmp(name, "user.virtfs.", 12) == 0) {
+ /*
+ * Don't allow fetch of user.virtfs namesapce
+ * in case of mapped security
+ */
+ errno = EACCES;
+ return -1;
+ }
+ return lremovexattr(rpath(ctx, path), name);
+}
+
+XattrOperations mapped_user_xattr = {
+ .name = "user.",
+ .getxattr = mp_user_getxattr,
+ .setxattr = mp_user_setxattr,
+ .listxattr = mp_user_listxattr,
+ .removexattr = mp_user_removexattr,
+};
+
+XattrOperations passthrough_user_xattr = {
+ .name = "user.",
+ .getxattr = pt_getxattr,
+ .setxattr = pt_setxattr,
+ .listxattr = pt_listxattr,
+ .removexattr = pt_removexattr,
+};
diff --git a/hw/virtio-9p-xattr.c b/hw/virtio-9p-xattr.c
new file mode 100644
index 0000000000..175f372c39
--- /dev/null
+++ b/hw/virtio-9p-xattr.c
@@ -0,0 +1,156 @@
+/*
+ * Virtio 9p xattr callback
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.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 "virtio-9p.h"
+#include "file-op-9p.h"
+#include "virtio-9p-xattr.h"
+
+
+static XattrOperations *get_xattr_operations(XattrOperations **h,
+ const char *name)
+{
+ XattrOperations *xops;
+ for (xops = *(h)++; xops != NULL; xops = *(h)++) {
+ if (!strncmp(name, xops->name, strlen(xops->name))) {
+ return xops;
+ }
+ }
+ return NULL;
+}
+
+ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
+ const char *name, void *value, size_t size)
+{
+ XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+ if (xops) {
+ return xops->getxattr(ctx, path, name, value, size);
+ }
+ errno = -EOPNOTSUPP;
+ return -1;
+}
+
+ssize_t pt_listxattr(FsContext *ctx, const char *path,
+ char *name, void *value, size_t size)
+{
+ int name_size = strlen(name) + 1;
+ if (!value) {
+ return name_size;
+ }
+
+ if (size < name_size) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ strncpy(value, name, name_size);
+ return name_size;
+}
+
+
+/*
+ * Get the list and pass to each layer to find out whether
+ * to send the data or not
+ */
+ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
+ void *value, size_t vsize)
+{
+ ssize_t size = 0;
+ 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);
+
+ /* 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);
+
+ /* store the orig pointer */
+ orig_value_start = orig_value;
+ while (xattr_len > parsed_len) {
+ xops = get_xattr_operations(ctx->xops, orig_value);
+ if (!xops) {
+ goto next_entry;
+ }
+
+ if (!value) {
+ size += xops->listxattr(ctx, path, orig_value, value, vsize);
+ } else {
+ size = xops->listxattr(ctx, path, orig_value, value, vsize);
+ if (size < 0) {
+ goto err_out;
+ }
+ value += size;
+ vsize -= size;
+ }
+next_entry:
+ /* Got the next entry */
+ attr_len = strlen(orig_value) + 1;
+ parsed_len += attr_len;
+ orig_value += attr_len;
+ }
+ if (value) {
+ size = value - ovalue;
+ }
+
+err_out:
+ qemu_free(orig_value_start);
+ return size;
+}
+
+int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
+ void *value, size_t size, int flags)
+{
+ XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+ if (xops) {
+ return xops->setxattr(ctx, path, name, value, size, flags);
+ }
+ errno = -EOPNOTSUPP;
+ return -1;
+
+}
+
+int v9fs_remove_xattr(FsContext *ctx,
+ const char *path, const char *name)
+{
+ XattrOperations *xops = get_xattr_operations(ctx->xops, name);
+ if (xops) {
+ return xops->removexattr(ctx, path, name);
+ }
+ errno = -EOPNOTSUPP;
+ return -1;
+
+}
+
+XattrOperations *mapped_xattr_ops[] = {
+ &mapped_user_xattr,
+ &mapped_pacl_xattr,
+ &mapped_dacl_xattr,
+ NULL,
+};
+
+XattrOperations *passthrough_xattr_ops[] = {
+ &passthrough_user_xattr,
+ &passthrough_acl_xattr,
+ NULL,
+};
+
+/* for .user none model should be same as passthrough */
+XattrOperations *none_xattr_ops[] = {
+ &passthrough_user_xattr,
+ &none_acl_xattr,
+ NULL,
+};
diff --git a/hw/virtio-9p-xattr.h b/hw/virtio-9p-xattr.h
new file mode 100644
index 0000000000..a6e31a152f
--- /dev/null
+++ b/hw/virtio-9p-xattr.h
@@ -0,0 +1,103 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.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_9P_XATTR_H
+#define _QEMU_VIRTIO_9P_XATTR_H
+
+#include <attr/xattr.h>
+
+typedef struct xattr_operations
+{
+ const char *name;
+ ssize_t (*getxattr)(FsContext *ctx, const char *path,
+ const char *name, void *value, size_t size);
+ ssize_t (*listxattr)(FsContext *ctx, const char *path,
+ char *name, void *value, size_t size);
+ int (*setxattr)(FsContext *ctx, const char *path, const char *name,
+ void *value, size_t size, int flags);
+ int (*removexattr)(FsContext *ctx,
+ const char *path, const char *name);
+} XattrOperations;
+
+
+extern XattrOperations mapped_user_xattr;
+extern XattrOperations passthrough_user_xattr;
+
+extern XattrOperations mapped_pacl_xattr;
+extern XattrOperations mapped_dacl_xattr;
+extern XattrOperations passthrough_acl_xattr;
+extern XattrOperations none_acl_xattr;
+
+extern XattrOperations *mapped_xattr_ops[];
+extern XattrOperations *passthrough_xattr_ops[];
+extern XattrOperations *none_xattr_ops[];
+
+extern ssize_t v9fs_get_xattr(FsContext *ctx, const char *path,
+ const char *name, void *value, size_t size);
+extern ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
+ void *value, size_t vsize);
+extern int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
+ void *value, size_t size, int flags);
+extern int v9fs_remove_xattr(FsContext *ctx,
+ const char *path, const char *name);
+extern ssize_t pt_listxattr(FsContext *ctx, const char *path,
+ char *name, void *value, size_t size);
+
+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);
+}
+
+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);
+}
+
+static inline int pt_removexattr(FsContext *ctx,
+ const char *path, const char *name)
+{
+ return lremovexattr(rpath(ctx, path), name);
+}
+
+static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
+ const char *name, void *value,
+ size_t size)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+static inline int notsup_setxattr(FsContext *ctx, const char *path,
+ const char *name, void *value,
+ size_t size, int flags)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+static inline ssize_t notsup_listxattr(FsContext *ctx, const char *path,
+ char *name, void *value, size_t size)
+{
+ return 0;
+}
+
+static inline int notsup_removexattr(FsContext *ctx,
+ const char *path, const char *name)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+#endif
diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c
index f8c85c3d28..daade77ed9 100644
--- a/hw/virtio-9p.c
+++ b/hw/virtio-9p.c
@@ -17,8 +17,8 @@
#include "virtio-9p.h"
#include "fsdev/qemu-fsdev.h"
#include "virtio-9p-debug.h"
+#include "virtio-9p-xattr.h"
-int dotu = 1;
int debug_9p_pdu;
enum {
@@ -135,21 +135,16 @@ static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
return s->ops->seekdir(&s->ctx, dir, off);
}
-static int v9fs_do_readv(V9fsState *s, int fd, const struct iovec *iov,
- int iovcnt)
+static int v9fs_do_preadv(V9fsState *s, int fd, const struct iovec *iov,
+ int iovcnt, int64_t offset)
{
- return s->ops->readv(&s->ctx, fd, iov, iovcnt);
+ return s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
}
-static off_t v9fs_do_lseek(V9fsState *s, int fd, off_t offset, int whence)
+static int v9fs_do_pwritev(V9fsState *s, int fd, const struct iovec *iov,
+ int iovcnt, int64_t offset)
{
- return s->ops->lseek(&s->ctx, fd, offset, whence);
-}
-
-static int v9fs_do_writev(V9fsState *s, int fd, const struct iovec *iov,
- int iovcnt)
-{
- return s->ops->writev(&s->ctx, fd, iov, iovcnt);
+ return s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
}
static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
@@ -160,26 +155,29 @@ static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
return s->ops->chmod(&s->ctx, path->data, &cred);
}
-static int v9fs_do_mknod(V9fsState *s, V9fsCreateState *vs, mode_t mode,
- dev_t dev)
+static int v9fs_do_mknod(V9fsState *s, char *name,
+ mode_t mode, dev_t dev, uid_t uid, gid_t gid)
{
FsCred cred;
cred_init(&cred);
- cred.fc_uid = vs->fidp->uid;
+ cred.fc_uid = uid;
+ cred.fc_gid = gid;
cred.fc_mode = mode;
cred.fc_rdev = dev;
- return s->ops->mknod(&s->ctx, vs->fullname.data, &cred);
+ return s->ops->mknod(&s->ctx, name, &cred);
}
-static int v9fs_do_mkdir(V9fsState *s, V9fsCreateState *vs)
+static int v9fs_do_mkdir(V9fsState *s, char *name, mode_t mode,
+ uid_t uid, gid_t gid)
{
FsCred cred;
cred_init(&cred);
- cred.fc_uid = vs->fidp->uid;
- cred.fc_mode = vs->perm & 0777;
+ cred.fc_uid = uid;
+ cred.fc_gid = gid;
+ cred.fc_mode = mode;
- return s->ops->mkdir(&s->ctx, vs->fullname.data, &cred);
+ return s->ops->mkdir(&s->ctx, name, &cred);
}
static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
@@ -187,28 +185,30 @@ static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
return s->ops->fstat(&s->ctx, fd, stbuf);
}
-static int v9fs_do_open2(V9fsState *s, V9fsCreateState *vs)
+static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid,
+ int flags, int mode)
{
FsCred cred;
- int flags;
cred_init(&cred);
- cred.fc_uid = vs->fidp->uid;
- cred.fc_mode = vs->perm & 0777;
- flags = omode_to_uflags(vs->mode) | O_CREAT;
+ cred.fc_uid = uid;
+ cred.fc_gid = gid;
+ cred.fc_mode = mode & 07777;
+ flags = flags;
- return s->ops->open2(&s->ctx, vs->fullname.data, flags, &cred);
+ return s->ops->open2(&s->ctx, fullname, flags, &cred);
}
-static int v9fs_do_symlink(V9fsState *s, V9fsCreateState *vs)
+static int v9fs_do_symlink(V9fsState *s, V9fsFidState *fidp,
+ const char *oldpath, const char *newpath, gid_t gid)
{
FsCred cred;
cred_init(&cred);
- cred.fc_uid = vs->fidp->uid;
- cred.fc_mode = vs->perm | 0777;
+ cred.fc_uid = fidp->uid;
+ cred.fc_gid = gid;
+ cred.fc_mode = 0777;
- return s->ops->symlink(&s->ctx, vs->extension.data, vs->fullname.data,
- &cred);
+ return s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
}
static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
@@ -237,10 +237,10 @@ static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
return s->ops->chown(&s->ctx, path->data, &cred);
}
-static int v9fs_do_utime(V9fsState *s, V9fsString *path,
- const struct utimbuf *buf)
+static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
+ const struct timespec times[2])
{
- return s->ops->utime(&s->ctx, path->data, buf);
+ return s->ops->utimensat(&s->ctx, path->data, times);
}
static int v9fs_do_remove(V9fsState *s, V9fsString *path)
@@ -253,6 +253,42 @@ static int v9fs_do_fsync(V9fsState *s, int fd)
return s->ops->fsync(&s->ctx, fd);
}
+static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
+{
+ return s->ops->statfs(&s->ctx, path->data, stbuf);
+}
+
+static ssize_t v9fs_do_lgetxattr(V9fsState *s, V9fsString *path,
+ V9fsString *xattr_name,
+ void *value, size_t size)
+{
+ return s->ops->lgetxattr(&s->ctx, path->data,
+ xattr_name->data, value, size);
+}
+
+static ssize_t v9fs_do_llistxattr(V9fsState *s, V9fsString *path,
+ void *value, size_t size)
+{
+ return s->ops->llistxattr(&s->ctx, path->data,
+ value, size);
+}
+
+static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path,
+ V9fsString *xattr_name,
+ void *value, size_t size, int flags)
+{
+ return s->ops->lsetxattr(&s->ctx, path->data,
+ xattr_name->data, value, size, flags);
+}
+
+static int v9fs_do_lremovexattr(V9fsState *s, V9fsString *path,
+ V9fsString *xattr_name)
+{
+ return s->ops->lremovexattr(&s->ctx, path->data,
+ xattr_name->data);
+}
+
+
static void v9fs_string_init(V9fsString *str)
{
str->data = NULL;
@@ -285,6 +321,14 @@ static int number_to_string(void *arg, char type)
} while (num);
break;
}
+ case 'U': {
+ unsigned long num = *(unsigned long *)arg;
+ do {
+ ret++;
+ num = num/10;
+ } while (num);
+ break;
+ }
default:
printf("Number_to_string: Unknown number format\n");
return -1;
@@ -293,7 +337,8 @@ static int number_to_string(void *arg, char type)
return ret;
}
-static int v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
+static int GCC_FMT_ATTR(2, 0)
+v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
{
va_list ap2;
char *iter = (char *)fmt;
@@ -301,6 +346,7 @@ static int v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
int nr_args = 0;
char *arg_char_ptr;
unsigned int arg_uint;
+ unsigned long arg_ulong;
/* Find the number of %'s that denotes an argument */
for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
@@ -326,6 +372,14 @@ static int v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
arg_uint = va_arg(ap2, unsigned int);
len += number_to_string((void *)&arg_uint, 'u');
break;
+ case 'l':
+ if (*++iter == 'u') {
+ arg_ulong = va_arg(ap2, unsigned long);
+ len += number_to_string((void *)&arg_ulong, 'U');
+ } else {
+ return -1;
+ }
+ break;
case 's':
arg_char_ptr = va_arg(ap2, char *);
len += strlen(arg_char_ptr);
@@ -347,7 +401,8 @@ alloc_print:
return vsprintf(*strp, fmt, ap);
}
-static void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
+static void GCC_FMT_ATTR(2, 3)
+v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
{
va_list ap;
int err;
@@ -398,8 +453,7 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
f = qemu_mallocz(sizeof(V9fsFidState));
f->fid = fid;
- f->fd = -1;
- f->dir = NULL;
+ f->fid_type = P9_FID_NONE;
f->next = s->fid_list;
s->fid_list = f;
@@ -407,8 +461,43 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
return f;
}
+static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
+{
+ int retval = 0;
+
+ if (fidp->fs.xattr.copied_len == -1) {
+ /* getxattr/listxattr fid */
+ goto free_value;
+ }
+ /*
+ * if this is fid for setxattr. clunk should
+ * result in setxattr localcall
+ */
+ if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
+ /* clunk after partial write */
+ retval = -EINVAL;
+ goto free_out;
+ }
+ if (fidp->fs.xattr.len) {
+ retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
+ fidp->fs.xattr.value,
+ fidp->fs.xattr.len,
+ fidp->fs.xattr.flags);
+ } else {
+ retval = v9fs_do_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
+ }
+free_out:
+ v9fs_string_free(&fidp->fs.xattr.name);
+free_value:
+ if (fidp->fs.xattr.value) {
+ qemu_free(fidp->fs.xattr.value);
+ }
+ return retval;
+}
+
static int free_fid(V9fsState *s, int32_t fid)
{
+ int retval = 0;
V9fsFidState **fidpp, *fidp;
for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
@@ -424,16 +513,17 @@ static int free_fid(V9fsState *s, int32_t fid)
fidp = *fidpp;
*fidpp = fidp->next;
- if (fidp->fd != -1) {
- v9fs_do_close(s, fidp->fd);
- }
- if (fidp->dir) {
- v9fs_do_closedir(s, fidp->dir);
+ if (fidp->fid_type == P9_FID_FILE) {
+ v9fs_do_close(s, fidp->fs.fd);
+ } else if (fidp->fid_type == P9_FID_DIR) {
+ v9fs_do_closedir(s, fidp->fs.dir);
+ } else if (fidp->fid_type == P9_FID_XATTR) {
+ retval = v9fs_xattr_fid_clunk(s, fidp);
}
v9fs_string_free(&fidp->path);
qemu_free(fidp);
- return 0;
+ return retval;
}
#define P9_QID_TYPE_DIR 0x80
@@ -660,6 +750,15 @@ static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
&statp->n_muid);
break;
}
+ case 'I': {
+ V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
+ offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
+ &iattr->valid, &iattr->mode,
+ &iattr->uid, &iattr->gid, &iattr->size,
+ &iattr->atime_sec, &iattr->atime_nsec,
+ &iattr->mtime_sec, &iattr->mtime_nsec);
+ break;
+ }
default:
break;
}
@@ -731,6 +830,21 @@ static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
statp->n_gid, statp->n_muid);
break;
}
+ case 'A': {
+ V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
+ offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
+ statp->st_result_mask,
+ &statp->qid, statp->st_mode,
+ statp->st_uid, statp->st_gid,
+ statp->st_nlink, statp->st_rdev,
+ statp->st_size, statp->st_blksize, statp->st_blocks,
+ statp->st_atime_sec, statp->st_atime_nsec,
+ statp->st_mtime_sec, statp->st_mtime_nsec,
+ statp->st_ctime_sec, statp->st_ctime_nsec,
+ statp->st_btime_sec, statp->st_btime_nsec,
+ statp->st_gen, statp->st_data_version);
+ break;
+ }
default:
break;
}
@@ -745,19 +859,24 @@ static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
int8_t id = pdu->id + 1; /* Response */
if (len < 0) {
- V9fsString str;
int err = -len;
+ len = 7;
- str.data = strerror(err);
- str.size = strlen(str.data);
+ if (s->proto_version != V9FS_PROTO_2000L) {
+ V9fsString str;
- len = 7;
- len += pdu_marshal(pdu, len, "s", &str);
- if (dotu) {
- len += pdu_marshal(pdu, len, "d", err);
+ str.data = strerror(err);
+ str.size = strlen(str.data);
+
+ len += pdu_marshal(pdu, len, "s", &str);
+ id = P9_RERROR;
}
- id = P9_RERROR;
+ len += pdu_marshal(pdu, len, "d", err);
+
+ if (s->proto_version == V9FS_PROTO_2000L) {
+ id = P9_RLERROR;
+ }
}
/* fill out the header */
@@ -785,22 +904,20 @@ static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
ret |= S_IFDIR;
}
- if (dotu) {
- if (mode & P9_STAT_MODE_SYMLINK) {
- ret |= S_IFLNK;
- }
- if (mode & P9_STAT_MODE_SOCKET) {
- ret |= S_IFSOCK;
- }
- if (mode & P9_STAT_MODE_NAMED_PIPE) {
- ret |= S_IFIFO;
- }
- if (mode & P9_STAT_MODE_DEVICE) {
- if (extension && extension->data[0] == 'c') {
- ret |= S_IFCHR;
- } else {
- ret |= S_IFBLK;
- }
+ if (mode & P9_STAT_MODE_SYMLINK) {
+ ret |= S_IFLNK;
+ }
+ if (mode & P9_STAT_MODE_SOCKET) {
+ ret |= S_IFSOCK;
+ }
+ if (mode & P9_STAT_MODE_NAMED_PIPE) {
+ ret |= S_IFIFO;
+ }
+ if (mode & P9_STAT_MODE_DEVICE) {
+ if (extension && extension->data[0] == 'c') {
+ ret |= S_IFCHR;
+ } else {
+ ret |= S_IFBLK;
}
}
@@ -863,34 +980,32 @@ static uint32_t stat_to_v9mode(const struct stat *stbuf)
mode |= P9_STAT_MODE_DIR;
}
- if (dotu) {
- if (S_ISLNK(stbuf->st_mode)) {
- mode |= P9_STAT_MODE_SYMLINK;
- }
+ if (S_ISLNK(stbuf->st_mode)) {
+ mode |= P9_STAT_MODE_SYMLINK;
+ }
- if (S_ISSOCK(stbuf->st_mode)) {
- mode |= P9_STAT_MODE_SOCKET;
- }
+ if (S_ISSOCK(stbuf->st_mode)) {
+ mode |= P9_STAT_MODE_SOCKET;
+ }
- if (S_ISFIFO(stbuf->st_mode)) {
- mode |= P9_STAT_MODE_NAMED_PIPE;
- }
+ if (S_ISFIFO(stbuf->st_mode)) {
+ mode |= P9_STAT_MODE_NAMED_PIPE;
+ }
- if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
- mode |= P9_STAT_MODE_DEVICE;
- }
+ if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
+ mode |= P9_STAT_MODE_DEVICE;
+ }
- if (stbuf->st_mode & S_ISUID) {
- mode |= P9_STAT_MODE_SETUID;
- }
+ if (stbuf->st_mode & S_ISUID) {
+ mode |= P9_STAT_MODE_SETUID;
+ }
- if (stbuf->st_mode & S_ISGID) {
- mode |= P9_STAT_MODE_SETGID;
- }
+ if (stbuf->st_mode & S_ISGID) {
+ mode |= P9_STAT_MODE_SETGID;
+ }
- if (stbuf->st_mode & S_ISVTX) {
- mode |= P9_STAT_MODE_SETVTX;
- }
+ if (stbuf->st_mode & S_ISVTX) {
+ mode |= P9_STAT_MODE_SETVTX;
}
return mode;
@@ -915,29 +1030,27 @@ static int stat_to_v9stat(V9fsState *s, V9fsString *name,
v9fs_string_null(&v9stat->gid);
v9fs_string_null(&v9stat->muid);
- if (dotu) {
- v9stat->n_uid = stbuf->st_uid;
- v9stat->n_gid = stbuf->st_gid;
- v9stat->n_muid = 0;
+ v9stat->n_uid = stbuf->st_uid;
+ v9stat->n_gid = stbuf->st_gid;
+ v9stat->n_muid = 0;
- v9fs_string_null(&v9stat->extension);
+ v9fs_string_null(&v9stat->extension);
- if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
- err = v9fs_do_readlink(s, name, &v9stat->extension);
- if (err == -1) {
- err = -errno;
- return err;
- }
- v9stat->extension.data[err] = 0;
- v9stat->extension.size = err;
- } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
- v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
- S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
- major(stbuf->st_rdev), minor(stbuf->st_rdev));
- } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
- v9fs_string_sprintf(&v9stat->extension, "%s %u",
- "HARDLINKCOUNT", stbuf->st_nlink);
+ if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
+ err = v9fs_do_readlink(s, name, &v9stat->extension);
+ if (err == -1) {
+ err = -errno;
+ return err;
}
+ v9stat->extension.data[err] = 0;
+ v9stat->extension.size = err;
+ } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
+ v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
+ S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
+ major(stbuf->st_rdev), minor(stbuf->st_rdev));
+ } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
+ v9fs_string_sprintf(&v9stat->extension, "%s %lu",
+ "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
}
str = strrchr(name->data, '/');
@@ -958,6 +1071,51 @@ static int stat_to_v9stat(V9fsState *s, V9fsString *name,
return 0;
}
+#define P9_STATS_MODE 0x00000001ULL
+#define P9_STATS_NLINK 0x00000002ULL
+#define P9_STATS_UID 0x00000004ULL
+#define P9_STATS_GID 0x00000008ULL
+#define P9_STATS_RDEV 0x00000010ULL
+#define P9_STATS_ATIME 0x00000020ULL
+#define P9_STATS_MTIME 0x00000040ULL
+#define P9_STATS_CTIME 0x00000080ULL
+#define P9_STATS_INO 0x00000100ULL
+#define P9_STATS_SIZE 0x00000200ULL
+#define P9_STATS_BLOCKS 0x00000400ULL
+
+#define P9_STATS_BTIME 0x00000800ULL
+#define P9_STATS_GEN 0x00001000ULL
+#define P9_STATS_DATA_VERSION 0x00002000ULL
+
+#define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
+#define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
+
+
+static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
+ V9fsStatDotl *v9lstat)
+{
+ memset(v9lstat, 0, sizeof(*v9lstat));
+
+ v9lstat->st_mode = stbuf->st_mode;
+ v9lstat->st_nlink = stbuf->st_nlink;
+ v9lstat->st_uid = stbuf->st_uid;
+ v9lstat->st_gid = stbuf->st_gid;
+ v9lstat->st_rdev = stbuf->st_rdev;
+ v9lstat->st_size = stbuf->st_size;
+ v9lstat->st_blksize = stbuf->st_blksize;
+ v9lstat->st_blocks = stbuf->st_blocks;
+ v9lstat->st_atime_sec = stbuf->st_atime;
+ v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
+ v9lstat->st_mtime_sec = stbuf->st_mtime;
+ v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
+ v9lstat->st_ctime_sec = stbuf->st_ctime;
+ v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
+ /* Currently we only support BASIC fields in stat */
+ v9lstat->st_result_mask = P9_STATS_BASIC;
+
+ stat_to_qid(stbuf, &v9lstat->qid);
+}
+
static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
{
while (len && *iovcnt) {
@@ -1019,17 +1177,20 @@ static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
{
- int32_t msize;
V9fsString version;
size_t offset = 7;
- pdu_unmarshal(pdu, offset, "ds", &msize, &version);
+ pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
- if (strcmp(version.data, "9P2000.u")) {
+ if (!strcmp(version.data, "9P2000.u")) {
+ s->proto_version = V9FS_PROTO_2000U;
+ } else if (!strcmp(version.data, "9P2000.L")) {
+ s->proto_version = V9FS_PROTO_2000L;
+ } else {
v9fs_string_sprintf(&version, "unknown");
}
- offset += pdu_marshal(pdu, offset, "ds", msize, &version);
+ offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
complete_pdu(s, pdu, offset);
v9fs_string_free(&version);
@@ -1121,6 +1282,202 @@ out:
qemu_free(vs);
}
+static void v9fs_getattr_post_lstat(V9fsState *s, V9fsStatStateDotl *vs,
+ int err)
+{
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ stat_to_v9stat_dotl(s, &vs->stbuf, &vs->v9stat_dotl);
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "A", &vs->v9stat_dotl);
+ err = vs->offset;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
+static void v9fs_getattr(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t fid;
+ V9fsStatStateDotl *vs;
+ ssize_t err = 0;
+ V9fsFidState *fidp;
+ uint64_t request_mask;
+
+ vs = qemu_malloc(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ memset(&vs->v9stat_dotl, 0, sizeof(vs->v9stat_dotl));
+
+ pdu_unmarshal(vs->pdu, vs->offset, "dq", &fid, &request_mask);
+
+ fidp = lookup_fid(s, fid);
+ if (fidp == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ /* Currently we only support BASIC fields in stat, so there is no
+ * need to look at request_mask.
+ */
+ err = v9fs_do_lstat(s, &fidp->path, &vs->stbuf);
+ v9fs_getattr_post_lstat(s, vs, err);
+ return;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
+/* From Linux kernel code */
+#define ATTR_MODE (1 << 0)
+#define ATTR_UID (1 << 1)
+#define ATTR_GID (1 << 2)
+#define ATTR_SIZE (1 << 3)
+#define ATTR_ATIME (1 << 4)
+#define ATTR_MTIME (1 << 5)
+#define ATTR_CTIME (1 << 6)
+#define ATTR_MASK 127
+#define ATTR_ATIME_SET (1 << 7)
+#define ATTR_MTIME_SET (1 << 8)
+
+static void v9fs_setattr_post_truncate(V9fsState *s, V9fsSetattrState *vs,
+ int err)
+{
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+ err = vs->offset;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
+static void v9fs_setattr_post_chown(V9fsState *s, V9fsSetattrState *vs, int err)
+{
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ if (vs->v9iattr.valid & (ATTR_SIZE)) {
+ err = v9fs_do_truncate(s, &vs->fidp->path, vs->v9iattr.size);
+ }
+ v9fs_setattr_post_truncate(s, vs, err);
+ return;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
+static void v9fs_setattr_post_utimensat(V9fsState *s, V9fsSetattrState *vs,
+ int err)
+{
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ /* If the only valid entry in iattr is ctime we can call
+ * chown(-1,-1) to update the ctime of the file
+ */
+ if ((vs->v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
+ ((vs->v9iattr.valid & ATTR_CTIME)
+ && !((vs->v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
+ if (!(vs->v9iattr.valid & ATTR_UID)) {
+ vs->v9iattr.uid = -1;
+ }
+ if (!(vs->v9iattr.valid & ATTR_GID)) {
+ vs->v9iattr.gid = -1;
+ }
+ err = v9fs_do_chown(s, &vs->fidp->path, vs->v9iattr.uid,
+ vs->v9iattr.gid);
+ }
+ v9fs_setattr_post_chown(s, vs, err);
+ return;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
+static void v9fs_setattr_post_chmod(V9fsState *s, V9fsSetattrState *vs, int err)
+{
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ if (vs->v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
+ struct timespec times[2];
+ if (vs->v9iattr.valid & ATTR_ATIME) {
+ if (vs->v9iattr.valid & ATTR_ATIME_SET) {
+ times[0].tv_sec = vs->v9iattr.atime_sec;
+ times[0].tv_nsec = vs->v9iattr.atime_nsec;
+ } else {
+ times[0].tv_nsec = UTIME_NOW;
+ }
+ } else {
+ times[0].tv_nsec = UTIME_OMIT;
+ }
+
+ if (vs->v9iattr.valid & ATTR_MTIME) {
+ if (vs->v9iattr.valid & ATTR_MTIME_SET) {
+ times[1].tv_sec = vs->v9iattr.mtime_sec;
+ times[1].tv_nsec = vs->v9iattr.mtime_nsec;
+ } else {
+ times[1].tv_nsec = UTIME_NOW;
+ }
+ } else {
+ times[1].tv_nsec = UTIME_OMIT;
+ }
+ err = v9fs_do_utimensat(s, &vs->fidp->path, times);
+ }
+ v9fs_setattr_post_utimensat(s, vs, err);
+ return;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
+static void v9fs_setattr(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t fid;
+ V9fsSetattrState *vs;
+ int err = 0;
+
+ vs = qemu_malloc(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ pdu_unmarshal(pdu, vs->offset, "dI", &fid, &vs->v9iattr);
+
+ vs->fidp = lookup_fid(s, fid);
+ if (vs->fidp == NULL) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (vs->v9iattr.valid & ATTR_MODE) {
+ err = v9fs_do_chmod(s, &vs->fidp->path, vs->v9iattr.mode);
+ }
+
+ v9fs_setattr_post_chmod(s, vs, err);
+ return;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
{
complete_pdu(s, vs->pdu, err);
@@ -1241,8 +1598,7 @@ static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
/* FIXME: is this really valid? */
if (fid == newfid) {
- BUG_ON(vs->fidp->fd != -1);
- BUG_ON(vs->fidp->dir);
+ BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
v9fs_string_init(&vs->path);
vs->name_idx = 0;
@@ -1284,13 +1640,33 @@ out:
v9fs_walk_complete(s, vs, err);
}
+static int32_t get_iounit(V9fsState *s, V9fsString *name)
+{
+ struct statfs stbuf;
+ int32_t iounit = 0;
+
+ /*
+ * iounit should be multiples of f_bsize (host filesystem block size
+ * and as well as less than (client msize - P9_IOHDRSZ))
+ */
+ if (!v9fs_do_statfs(s, name, &stbuf)) {
+ iounit = stbuf.f_bsize;
+ iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
+ }
+
+ if (!iounit) {
+ iounit = s->msize - P9_IOHDRSZ;
+ }
+ return iounit;
+}
+
static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
{
- if (vs->fidp->dir == NULL) {
+ if (vs->fidp->fs.dir == NULL) {
err = -errno;
goto out;
}
-
+ vs->fidp->fid_type = P9_FID_DIR;
vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
err = vs->offset;
out:
@@ -1299,15 +1675,25 @@ out:
}
+static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs)
+{
+ int err;
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
+ err = vs->offset;
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
{
- if (vs->fidp->fd == -1) {
+ if (vs->fidp->fs.fd == -1) {
err = -errno;
goto out;
}
-
- vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
- err = vs->offset;
+ vs->fidp->fid_type = P9_FID_FILE;
+ vs->iounit = get_iounit(s, &vs->fidp->path);
+ v9fs_open_post_getiounit(s, vs);
+ return;
out:
complete_pdu(s, vs->pdu, err);
qemu_free(vs);
@@ -1315,6 +1701,8 @@ out:
static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
{
+ int flags;
+
if (err) {
err = -errno;
goto out;
@@ -1323,11 +1711,18 @@ static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
stat_to_qid(&vs->stbuf, &vs->qid);
if (S_ISDIR(vs->stbuf.st_mode)) {
- vs->fidp->dir = v9fs_do_opendir(s, &vs->fidp->path);
+ vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path);
v9fs_open_post_opendir(s, vs, err);
} else {
- vs->fidp->fd = v9fs_do_open(s, &vs->fidp->path,
- omode_to_uflags(vs->mode));
+ if (s->proto_version == V9FS_PROTO_2000L) {
+ flags = vs->mode;
+ flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
+ /* Ignore direct disk access hint until the server supports it. */
+ flags &= ~O_DIRECT;
+ } else {
+ flags = omode_to_uflags(vs->mode);
+ }
+ vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags);
v9fs_open_post_open(s, vs, err);
}
return;
@@ -1342,12 +1737,16 @@ static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
V9fsOpenState *vs;
ssize_t err = 0;
-
vs = qemu_malloc(sizeof(*vs));
vs->pdu = pdu;
vs->offset = 7;
+ vs->mode = 0;
- pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
+ if (s->proto_version == V9FS_PROTO_2000L) {
+ pdu_unmarshal(vs->pdu, vs->offset, "dd", &fid, &vs->mode);
+ } else {
+ pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
+ }
vs->fidp = lookup_fid(s, fid);
if (vs->fidp == NULL) {
@@ -1355,8 +1754,7 @@ static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
goto out;
}
- BUG_ON(vs->fidp->fd != -1);
- BUG_ON(vs->fidp->dir);
+ BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
@@ -1367,6 +1765,122 @@ out:
qemu_free(vs);
}
+static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
+{
+ if (err == 0) {
+ v9fs_string_copy(&vs->fidp->path, &vs->fullname);
+ stat_to_qid(&vs->stbuf, &vs->qid);
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid,
+ &vs->iounit);
+ err = vs->offset;
+ } else {
+ vs->fidp->fid_type = P9_FID_NONE;
+ err = -errno;
+ if (vs->fidp->fs.fd > 0) {
+ close(vs->fidp->fs.fd);
+ }
+ }
+
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->name);
+ v9fs_string_free(&vs->fullname);
+ qemu_free(vs);
+}
+
+static void v9fs_lcreate_post_get_iounit(V9fsState *s, V9fsLcreateState *vs,
+ int err)
+{
+ if (err) {
+ err = -errno;
+ goto out;
+ }
+ err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+
+out:
+ v9fs_post_lcreate(s, vs, err);
+}
+
+static void v9fs_lcreate_post_do_open2(V9fsState *s, V9fsLcreateState *vs,
+ int err)
+{
+ if (vs->fidp->fs.fd == -1) {
+ err = -errno;
+ goto out;
+ }
+ vs->fidp->fid_type = P9_FID_FILE;
+ vs->iounit = get_iounit(s, &vs->fullname);
+ v9fs_lcreate_post_get_iounit(s, vs, err);
+ return;
+
+out:
+ v9fs_post_lcreate(s, vs, err);
+}
+
+static void v9fs_lcreate(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t dfid, flags, mode;
+ gid_t gid;
+ V9fsLcreateState *vs;
+ ssize_t err = 0;
+
+ vs = qemu_malloc(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ v9fs_string_init(&vs->fullname);
+
+ pdu_unmarshal(vs->pdu, vs->offset, "dsddd", &dfid, &vs->name, &flags,
+ &mode, &gid);
+
+ vs->fidp = lookup_fid(s, dfid);
+ if (vs->fidp == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
+ vs->name.data);
+
+ /* Ignore direct disk access hint until the server supports it. */
+ flags &= ~O_DIRECT;
+
+ vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
+ gid, flags, mode);
+ v9fs_lcreate_post_do_open2(s, vs, err);
+ return;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+}
+
+static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err)
+{
+ if (err == -1) {
+ err = -errno;
+ }
+ complete_pdu(s, pdu, err);
+}
+
+static void v9fs_fsync(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t fid;
+ size_t offset = 7;
+ V9fsFidState *fidp;
+ int err;
+
+ pdu_unmarshal(pdu, offset, "d", &fid);
+ fidp = lookup_fid(s, fid);
+ if (fidp == NULL) {
+ err = -ENOENT;
+ v9fs_post_do_fsync(s, pdu, err);
+ return;
+ }
+ err = v9fs_do_fsync(s, fidp->fs.fd);
+ v9fs_post_do_fsync(s, pdu, err);
+}
+
static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
{
int32_t fid;
@@ -1420,7 +1934,7 @@ static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
&vs->v9stat);
if ((vs->len != (vs->v9stat.size + 2)) ||
((vs->count + vs->len) > vs->max_count)) {
- v9fs_do_seekdir(s, vs->fidp->dir, vs->dir_pos);
+ v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
v9fs_read_post_seekdir(s, vs, err);
return;
}
@@ -1428,11 +1942,11 @@ static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
v9fs_stat_free(&vs->v9stat);
v9fs_string_free(&vs->name);
vs->dir_pos = vs->dent->d_off;
- vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
+ vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
v9fs_read_post_readdir(s, vs, err);
return;
out:
- v9fs_do_seekdir(s, vs->fidp->dir, vs->dir_pos);
+ v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
v9fs_read_post_seekdir(s, vs, err);
return;
@@ -1460,7 +1974,7 @@ static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
{
- vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
+ vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
v9fs_read_post_readdir(s, vs, err);
return;
}
@@ -1468,12 +1982,12 @@ static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
ssize_t err)
{
- vs->dir_pos = v9fs_do_telldir(s, vs->fidp->dir);
+ vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
v9fs_read_post_telldir(s, vs, err);
return;
}
-static void v9fs_read_post_readv(V9fsState *s, V9fsReadState *vs, ssize_t err)
+static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err)
{
if (err < 0) {
/* IO error return the error */
@@ -1487,12 +2001,16 @@ static void v9fs_read_post_readv(V9fsState *s, V9fsReadState *vs, ssize_t err)
if (0) {
print_sg(vs->sg, vs->cnt);
}
- vs->len = v9fs_do_readv(s, vs->fidp->fd, vs->sg, vs->cnt);
+ vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
+ vs->off);
+ if (vs->len > 0) {
+ vs->off += vs->len;
+ }
} while (vs->len == -1 && errno == EINTR);
if (vs->len == -1) {
err = -errno;
}
- v9fs_read_post_readv(s, vs, err);
+ v9fs_read_post_preadv(s, vs, err);
return;
}
vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
@@ -1504,28 +2022,27 @@ out:
qemu_free(vs);
}
-static void v9fs_read_post_lseek(V9fsState *s, V9fsReadState *vs, ssize_t err)
+static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
{
- if (err == -1) {
- err = -errno;
- goto out;
- }
- vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
-
- if (vs->total < vs->count) {
- do {
- if (0) {
- print_sg(vs->sg, vs->cnt);
- }
- vs->len = v9fs_do_readv(s, vs->fidp->fd, vs->sg, vs->cnt);
- } while (vs->len == -1 && errno == EINTR);
- if (vs->len == -1) {
- err = -errno;
- }
- v9fs_read_post_readv(s, vs, err);
- return;
+ ssize_t err = 0;
+ int read_count;
+ int64_t xattr_len;
+
+ xattr_len = vs->fidp->fs.xattr.len;
+ read_count = xattr_len - vs->off;
+ if (read_count > vs->count) {
+ read_count = vs->count;
+ } else if (read_count < 0) {
+ /*
+ * read beyond XATTR value
+ */
+ read_count = 0;
}
-out:
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", read_count);
+ vs->offset += pdu_pack(vs->pdu, vs->offset,
+ ((char *)vs->fidp->fs.xattr.value) + vs->off,
+ read_count);
+ err = vs->offset;
complete_pdu(s, vs->pdu, err);
qemu_free(vs);
}
@@ -1551,19 +2068,30 @@ static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
goto out;
}
- if (vs->fidp->dir) {
+ if (vs->fidp->fid_type == P9_FID_DIR) {
vs->max_count = vs->count;
vs->count = 0;
if (vs->off == 0) {
- v9fs_do_rewinddir(s, vs->fidp->dir);
+ v9fs_do_rewinddir(s, vs->fidp->fs.dir);
}
v9fs_read_post_rewinddir(s, vs, err);
return;
- } else if (vs->fidp->fd != -1) {
+ } else if (vs->fidp->fid_type == P9_FID_FILE) {
vs->sg = vs->iov;
pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
- err = v9fs_do_lseek(s, vs->fidp->fd, vs->off, SEEK_SET);
- v9fs_read_post_lseek(s, vs, err);
+ vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
+ if (vs->total <= vs->count) {
+ vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
+ vs->off);
+ if (vs->len > 0) {
+ vs->off += vs->len;
+ }
+ err = vs->len;
+ v9fs_read_post_preadv(s, vs, err);
+ }
+ return;
+ } else if (vs->fidp->fid_type == P9_FID_XATTR) {
+ v9fs_xattr_read(s, vs);
return;
} else {
err = -EINVAL;
@@ -1573,7 +2101,128 @@ out:
qemu_free(vs);
}
-static void v9fs_write_post_writev(V9fsState *s, V9fsWriteState *vs,
+typedef struct V9fsReadDirState {
+ V9fsPDU *pdu;
+ V9fsFidState *fidp;
+ V9fsQID qid;
+ off_t saved_dir_pos;
+ struct dirent *dent;
+ int32_t count;
+ int32_t max_count;
+ size_t offset;
+ int64_t initial_offset;
+ V9fsString name;
+} V9fsReadDirState;
+
+static void v9fs_readdir_post_seekdir(V9fsState *s, V9fsReadDirState *vs)
+{
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
+ vs->offset += vs->count;
+ complete_pdu(s, vs->pdu, vs->offset);
+ qemu_free(vs);
+ return;
+}
+
+/* Size of each dirent on the wire: size of qid (13) + size of offset (8)
+ * size of type (1) + size of name.size (2) + strlen(name.data)
+ */
+#define V9_READDIR_DATA_SZ (24 + strlen(vs->name.data))
+
+static void v9fs_readdir_post_readdir(V9fsState *s, V9fsReadDirState *vs)
+{
+ int len;
+ size_t size;
+
+ if (vs->dent) {
+ v9fs_string_init(&vs->name);
+ v9fs_string_sprintf(&vs->name, "%s", vs->dent->d_name);
+
+ if ((vs->count + V9_READDIR_DATA_SZ) > vs->max_count) {
+ /* Ran out of buffer. Set dir back to old position and return */
+ v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->saved_dir_pos);
+ v9fs_readdir_post_seekdir(s, vs);
+ return;
+ }
+
+ /* Fill up just the path field of qid because the client uses
+ * only that. To fill the entire qid structure we will have
+ * to stat each dirent found, which is expensive
+ */
+ size = MIN(sizeof(vs->dent->d_ino), sizeof(vs->qid.path));
+ memcpy(&vs->qid.path, &vs->dent->d_ino, size);
+ /* Fill the other fields with dummy values */
+ vs->qid.type = 0;
+ vs->qid.version = 0;
+
+ len = pdu_marshal(vs->pdu, vs->offset+4+vs->count, "Qqbs",
+ &vs->qid, vs->dent->d_off,
+ vs->dent->d_type, &vs->name);
+ vs->count += len;
+ v9fs_string_free(&vs->name);
+ vs->saved_dir_pos = vs->dent->d_off;
+ vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
+ v9fs_readdir_post_readdir(s, vs);
+ return;
+ }
+
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
+ vs->offset += vs->count;
+ complete_pdu(s, vs->pdu, vs->offset);
+ qemu_free(vs);
+ return;
+}
+
+static void v9fs_readdir_post_telldir(V9fsState *s, V9fsReadDirState *vs)
+{
+ vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
+ v9fs_readdir_post_readdir(s, vs);
+ return;
+}
+
+static void v9fs_readdir_post_setdir(V9fsState *s, V9fsReadDirState *vs)
+{
+ vs->saved_dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
+ v9fs_readdir_post_telldir(s, vs);
+ return;
+}
+
+static void v9fs_readdir(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t fid;
+ V9fsReadDirState *vs;
+ ssize_t err = 0;
+ size_t offset = 7;
+
+ vs = qemu_malloc(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+ vs->count = 0;
+
+ pdu_unmarshal(vs->pdu, offset, "dqd", &fid, &vs->initial_offset,
+ &vs->max_count);
+
+ vs->fidp = lookup_fid(s, fid);
+ if (vs->fidp == NULL || !(vs->fidp->fs.dir)) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (vs->initial_offset == 0) {
+ v9fs_do_rewinddir(s, vs->fidp->fs.dir);
+ } else {
+ v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->initial_offset);
+ }
+
+ v9fs_readdir_post_setdir(s, vs);
+ return;
+
+out:
+ complete_pdu(s, pdu, err);
+ qemu_free(vs);
+ return;
+}
+
+static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs,
ssize_t err)
{
if (err < 0) {
@@ -1588,44 +2237,62 @@ static void v9fs_write_post_writev(V9fsState *s, V9fsWriteState *vs,
if (0) {
print_sg(vs->sg, vs->cnt);
}
- vs->len = v9fs_do_writev(s, vs->fidp->fd, vs->sg, vs->cnt);
+ vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
+ vs->off);
+ if (vs->len > 0) {
+ vs->off += vs->len;
+ }
} while (vs->len == -1 && errno == EINTR);
if (vs->len == -1) {
err = -errno;
}
- v9fs_write_post_writev(s, vs, err);
+ v9fs_write_post_pwritev(s, vs, err);
return;
}
vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
-
err = vs->offset;
out:
complete_pdu(s, vs->pdu, err);
qemu_free(vs);
}
-static void v9fs_write_post_lseek(V9fsState *s, V9fsWriteState *vs, ssize_t err)
+static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
{
- if (err == -1) {
- err = -errno;
+ int i, to_copy;
+ ssize_t err = 0;
+ int write_count;
+ int64_t xattr_len;
+
+ xattr_len = vs->fidp->fs.xattr.len;
+ write_count = xattr_len - vs->off;
+ if (write_count > vs->count) {
+ write_count = vs->count;
+ } else if (write_count < 0) {
+ /*
+ * write beyond XATTR value len specified in
+ * xattrcreate
+ */
+ err = -ENOSPC;
goto out;
}
- vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
-
- if (vs->total < vs->count) {
- do {
- if (0) {
- print_sg(vs->sg, vs->cnt);
- }
- vs->len = v9fs_do_writev(s, vs->fidp->fd, vs->sg, vs->cnt);
- } while (vs->len == -1 && errno == EINTR);
- if (vs->len == -1) {
- err = -errno;
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
+ err = vs->offset;
+ vs->fidp->fs.xattr.copied_len += write_count;
+ /*
+ * Now copy the content from sg list
+ */
+ for (i = 0; i < vs->cnt; i++) {
+ if (write_count > vs->sg[i].iov_len) {
+ to_copy = vs->sg[i].iov_len;
+ } else {
+ to_copy = write_count;
}
- v9fs_write_post_writev(s, vs, err);
- return;
+ memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
+ vs->sg[i].iov_base, to_copy);
+ /* updating vs->off since we are not using below */
+ vs->off += to_copy;
+ write_count -= to_copy;
}
-
out:
complete_pdu(s, vs->pdu, err);
qemu_free(vs);
@@ -1646,7 +2313,7 @@ static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
vs->len = 0;
pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
- vs->sg, &vs->cnt);
+ vs->sg, &vs->cnt);
vs->fidp = lookup_fid(s, fid);
if (vs->fidp == NULL) {
@@ -1654,30 +2321,58 @@ static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
goto out;
}
- if (vs->fidp->fd == -1) {
+ if (vs->fidp->fid_type == P9_FID_FILE) {
+ if (vs->fidp->fs.fd == -1) {
+ err = -EINVAL;
+ goto out;
+ }
+ } else if (vs->fidp->fid_type == P9_FID_XATTR) {
+ /*
+ * setxattr operation
+ */
+ v9fs_xattr_write(s, vs);
+ return;
+ } else {
err = -EINVAL;
goto out;
}
+ vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
+ if (vs->total <= vs->count) {
+ vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, vs->off);
+ if (vs->len > 0) {
+ vs->off += vs->len;
+ }
+ err = vs->len;
+ v9fs_write_post_pwritev(s, vs, err);
+ }
+ return;
+out:
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
- err = v9fs_do_lseek(s, vs->fidp->fd, vs->off, SEEK_SET);
+static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
+{
+ int err;
+ v9fs_string_copy(&vs->fidp->path, &vs->fullname);
+ stat_to_qid(&vs->stbuf, &vs->qid);
- v9fs_write_post_lseek(s, vs, err);
- return;
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
+ err = vs->offset;
-out:
complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->name);
+ v9fs_string_free(&vs->extension);
+ v9fs_string_free(&vs->fullname);
qemu_free(vs);
}
static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
{
if (err == 0) {
- v9fs_string_copy(&vs->fidp->path, &vs->fullname);
- stat_to_qid(&vs->stbuf, &vs->qid);
-
- vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
-
- err = vs->offset;
+ vs->iounit = get_iounit(s, &vs->fidp->path);
+ v9fs_create_post_getiounit(s, vs);
+ return;
}
complete_pdu(s, vs->pdu, err);
@@ -1698,9 +2393,10 @@ static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
int err)
{
- if (!vs->fidp->dir) {
+ if (!vs->fidp->fs.dir) {
err = -errno;
}
+ vs->fidp->fid_type = P9_FID_DIR;
v9fs_post_create(s, vs, err);
}
@@ -1712,7 +2408,7 @@ static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
goto out;
}
- vs->fidp->dir = v9fs_do_opendir(s, &vs->fullname);
+ vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname);
v9fs_create_post_opendir(s, vs, err);
return;
@@ -1738,22 +2434,22 @@ out:
static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
{
if (err) {
- vs->fidp->fd = -1;
+ vs->fidp->fid_type = P9_FID_NONE;
+ close(vs->fidp->fs.fd);
err = -errno;
}
-
v9fs_post_create(s, vs, err);
return;
}
static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
{
- if (vs->fidp->fd == -1) {
+ if (vs->fidp->fs.fd == -1) {
err = -errno;
goto out;
}
-
- err = v9fs_do_fstat(s, vs->fidp->fd, &vs->stbuf);
+ vs->fidp->fid_type = P9_FID_FILE;
+ err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
v9fs_create_post_fstat(s, vs, err);
return;
@@ -1772,10 +2468,12 @@ static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
}
if (vs->perm & P9_STAT_MODE_DIR) {
- err = v9fs_do_mkdir(s, vs);
+ err = v9fs_do_mkdir(s, vs->fullname.data, vs->perm & 0777,
+ vs->fidp->uid, -1);
v9fs_create_post_mkdir(s, vs, err);
} else if (vs->perm & P9_STAT_MODE_SYMLINK) {
- err = v9fs_do_symlink(s, vs);
+ err = v9fs_do_symlink(s, vs->fidp, vs->extension.data,
+ vs->fullname.data, -1);
v9fs_create_post_perms(s, vs, err);
} else if (vs->perm & P9_STAT_MODE_LINK) {
int32_t nfid = atoi(vs->extension.data);
@@ -1810,16 +2508,21 @@ static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
}
nmode |= vs->perm & 0777;
- err = v9fs_do_mknod(s, vs, nmode, makedev(major, minor));
+ err = v9fs_do_mknod(s, vs->fullname.data, nmode,
+ makedev(major, minor), vs->fidp->uid, -1);
v9fs_create_post_perms(s, vs, err);
} else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
- err = v9fs_do_mknod(s, vs, S_IFIFO | (vs->perm & 0777), 0);
+ err = v9fs_do_mknod(s, vs->fullname.data, S_IFIFO | (vs->perm & 0777),
+ 0, vs->fidp->uid, -1);
v9fs_post_create(s, vs, err);
} else if (vs->perm & P9_STAT_MODE_SOCKET) {
- err = v9fs_do_mknod(s, vs, S_IFSOCK | (vs->perm & 0777), 0);
+ err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777),
+ 0, vs->fidp->uid, -1);
v9fs_post_create(s, vs, err);
} else {
- vs->fidp->fd = v9fs_do_open2(s, vs);
+ vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
+ -1, omode_to_uflags(vs->mode)|O_CREAT, vs->perm);
+
v9fs_create_post_open2(s, vs, err);
}
@@ -1864,23 +2567,124 @@ out:
qemu_free(vs);
}
+static void v9fs_post_symlink(V9fsState *s, V9fsSymlinkState *vs, int err)
+{
+ if (err == 0) {
+ stat_to_qid(&vs->stbuf, &vs->qid);
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
+ err = vs->offset;
+ } else {
+ err = -errno;
+ }
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->name);
+ v9fs_string_free(&vs->symname);
+ v9fs_string_free(&vs->fullname);
+ qemu_free(vs);
+}
+
+static void v9fs_symlink_post_do_symlink(V9fsState *s, V9fsSymlinkState *vs,
+ int err)
+{
+ if (err) {
+ goto out;
+ }
+ err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+out:
+ v9fs_post_symlink(s, vs, err);
+}
+
+static void v9fs_symlink(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t dfid;
+ V9fsSymlinkState *vs;
+ int err = 0;
+ gid_t gid;
+
+ vs = qemu_malloc(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ v9fs_string_init(&vs->fullname);
+
+ pdu_unmarshal(vs->pdu, vs->offset, "dssd", &dfid, &vs->name,
+ &vs->symname, &gid);
+
+ vs->dfidp = lookup_fid(s, dfid);
+ if (vs->dfidp == NULL) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->dfidp->path.data,
+ vs->name.data);
+ err = v9fs_do_symlink(s, vs->dfidp, vs->symname.data,
+ vs->fullname.data, gid);
+ v9fs_symlink_post_do_symlink(s, vs, err);
+ return;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->name);
+ v9fs_string_free(&vs->symname);
+ qemu_free(vs);
+}
+
static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
{
/* A nop call with no return */
complete_pdu(s, pdu, 7);
}
+static void v9fs_link(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t dfid, oldfid;
+ V9fsFidState *dfidp, *oldfidp;
+ V9fsString name, fullname;
+ size_t offset = 7;
+ int err = 0;
+
+ v9fs_string_init(&fullname);
+
+ pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
+
+ dfidp = lookup_fid(s, dfid);
+ if (dfidp == NULL) {
+ err = -errno;
+ goto out;
+ }
+
+ oldfidp = lookup_fid(s, oldfid);
+ if (oldfidp == NULL) {
+ err = -errno;
+ goto out;
+ }
+
+ v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
+ err = offset;
+ err = v9fs_do_link(s, &oldfidp->path, &fullname);
+ if (err) {
+ err = -errno;
+ }
+ v9fs_string_free(&fullname);
+
+out:
+ v9fs_string_free(&name);
+ complete_pdu(s, pdu, err);
+}
+
static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
int err)
{
- /* For TREMOVE we need to clunk the fid even on failed remove */
- err = free_fid(s, vs->fidp->fid);
if (err < 0) {
- goto out;
+ err = -errno;
+ } else {
+ err = vs->offset;
}
- err = vs->offset;
-out:
+ /* For TREMOVE we need to clunk the fid even on failed remove */
+ free_fid(s, vs->fidp->fid);
+
complete_pdu(s, vs->pdu, err);
qemu_free(vs);
}
@@ -1931,11 +2735,6 @@ static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
if (err < 0) {
goto out;
}
-
- if (vs->v9stat.name.size != 0) {
- v9fs_string_free(&vs->nname);
- }
-
if (vs->v9stat.length != -1) {
if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
err = -errno;
@@ -1950,17 +2749,29 @@ out:
qemu_free(vs);
}
-static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
+static int v9fs_complete_rename(V9fsState *s, V9fsRenameState *vs)
{
- V9fsFidState *fidp;
- if (err < 0) {
- goto out;
- }
+ int err = 0;
+ char *old_name, *new_name;
+ char *end;
- if (vs->v9stat.name.size != 0) {
- char *old_name, *new_name;
- char *end;
+ if (vs->newdirfid != -1) {
+ V9fsFidState *dirfidp;
+ dirfidp = lookup_fid(s, vs->newdirfid);
+ if (dirfidp == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ BUG_ON(dirfidp->fid_type != P9_FID_NONE);
+
+ new_name = qemu_mallocz(dirfidp->path.size + vs->name.size + 2);
+
+ strcpy(new_name, dirfidp->path.data);
+ strcat(new_name, "/");
+ strcat(new_name + dirfidp->path.size, vs->name.data);
+ } else {
old_name = vs->fidp->path.data;
end = strrchr(old_name, '/');
if (end) {
@@ -1968,44 +2779,74 @@ static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
} else {
end = old_name;
}
+ new_name = qemu_mallocz(end - old_name + vs->name.size + 1);
- new_name = qemu_malloc(end - old_name + vs->v9stat.name.size + 1);
+ strncat(new_name, old_name, end - old_name);
+ strncat(new_name + (end - old_name), vs->name.data, vs->name.size);
+ }
- memset(new_name, 0, end - old_name + vs->v9stat.name.size + 1);
- memcpy(new_name, old_name, end - old_name);
- memcpy(new_name + (end - old_name), vs->v9stat.name.data,
- vs->v9stat.name.size);
- vs->nname.data = new_name;
- vs->nname.size = strlen(new_name);
+ v9fs_string_free(&vs->name);
+ vs->name.data = qemu_strdup(new_name);
+ vs->name.size = strlen(new_name);
- if (strcmp(new_name, vs->fidp->path.data) != 0) {
- if (v9fs_do_rename(s, &vs->fidp->path, &vs->nname)) {
- err = -errno;
- } else {
- /*
- * Fixup fid's pointing to the old name to
- * start pointing to the new name
- */
- 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
- */
- continue;
- }
- if (!strncmp(vs->fidp->path.data, fidp->path.data,
- strlen(vs->fidp->path.data))) {
- /* replace the name */
- v9fs_fix_path(&fidp->path, &vs->nname,
- strlen(vs->fidp->path.data));
- }
+ if (strcmp(new_name, vs->fidp->path.data) != 0) {
+ if (v9fs_do_rename(s, &vs->fidp->path, &vs->name)) {
+ err = -errno;
+ } else {
+ V9fsFidState *fidp;
+ /*
+ * Fixup fid's pointing to the old name to
+ * start pointing to the new name
+ */
+ 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
+ */
+ continue;
+ }
+ if (!strncmp(vs->fidp->path.data, fidp->path.data,
+ strlen(vs->fidp->path.data))) {
+ /* replace the name */
+ v9fs_fix_path(&fidp->path, &vs->name,
+ strlen(vs->fidp->path.data));
}
- v9fs_string_copy(&vs->fidp->path, &vs->nname);
}
+ v9fs_string_copy(&vs->fidp->path, &vs->name);
}
}
+out:
+ v9fs_string_free(&vs->name);
+ return err;
+}
+
+static void v9fs_rename_post_rename(V9fsState *s, V9fsRenameState *vs, int err)
+{
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
+static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
+{
+ if (err < 0) {
+ goto out;
+ }
+
+ if (vs->v9stat.name.size != 0) {
+ V9fsRenameState *vr;
+
+ vr = qemu_mallocz(sizeof(V9fsRenameState));
+ vr->newdirfid = -1;
+ vr->pdu = vs->pdu;
+ vr->fidp = vs->fidp;
+ vr->offset = vs->offset;
+ vr->name.size = vs->v9stat.name.size;
+ vr->name.data = qemu_strdup(vs->v9stat.name.data);
+
+ err = v9fs_complete_rename(s, vr);
+ qemu_free(vr);
+ }
v9fs_wstat_post_rename(s, vs, err);
return;
@@ -2015,6 +2856,34 @@ out:
qemu_free(vs);
}
+static void v9fs_rename(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t fid;
+ V9fsRenameState *vs;
+ ssize_t err = 0;
+
+ vs = qemu_malloc(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &vs->newdirfid, &vs->name);
+
+ vs->fidp = lookup_fid(s, fid);
+ if (vs->fidp == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
+
+ err = v9fs_complete_rename(s, vs);
+ v9fs_rename_post_rename(s, vs, err);
+ return;
+out:
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
{
if (err < 0) {
@@ -2042,11 +2911,22 @@ static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
goto out;
}
- if (vs->v9stat.mtime != -1) {
- struct utimbuf tb;
- tb.actime = 0;
- tb.modtime = vs->v9stat.mtime;
- if (v9fs_do_utime(s, &vs->fidp->path, &tb)) {
+ if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
+ struct timespec times[2];
+ if (vs->v9stat.atime != -1) {
+ times[0].tv_sec = vs->v9stat.atime;
+ times[0].tv_nsec = 0;
+ } else {
+ times[0].tv_nsec = UTIME_OMIT;
+ }
+ if (vs->v9stat.mtime != -1) {
+ times[1].tv_sec = vs->v9stat.mtime;
+ times[1].tv_nsec = 0;
+ } else {
+ times[1].tv_nsec = UTIME_OMIT;
+ }
+
+ if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
err = -errno;
}
}
@@ -2121,7 +3001,7 @@ static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
/* do we need to sync the file? */
if (donttouch_stat(&vs->v9stat)) {
- err = v9fs_do_fsync(s, vs->fidp->fd);
+ err = v9fs_do_fsync(s, vs->fidp->fs.fd);
v9fs_wstat_post_fsync(s, vs, err);
return;
}
@@ -2141,21 +3021,565 @@ out:
qemu_free(vs);
}
+static void v9fs_statfs_post_statfs(V9fsState *s, V9fsStatfsState *vs, int err)
+{
+ int32_t bsize_factor;
+
+ if (err) {
+ err = -errno;
+ goto out;
+ }
+
+ /*
+ * compute bsize factor based on host file system block size
+ * and client msize
+ */
+ bsize_factor = (s->msize - P9_IOHDRSZ)/vs->stbuf.f_bsize;
+ if (!bsize_factor) {
+ bsize_factor = 1;
+ }
+ vs->v9statfs.f_type = vs->stbuf.f_type;
+ vs->v9statfs.f_bsize = vs->stbuf.f_bsize;
+ vs->v9statfs.f_bsize *= bsize_factor;
+ /*
+ * f_bsize is adjusted(multiplied) by bsize factor, so we need to
+ * adjust(divide) the number of blocks, free blocks and available
+ * blocks by bsize factor
+ */
+ vs->v9statfs.f_blocks = vs->stbuf.f_blocks/bsize_factor;
+ vs->v9statfs.f_bfree = vs->stbuf.f_bfree/bsize_factor;
+ vs->v9statfs.f_bavail = vs->stbuf.f_bavail/bsize_factor;
+ vs->v9statfs.f_files = vs->stbuf.f_files;
+ vs->v9statfs.f_ffree = vs->stbuf.f_ffree;
+ vs->v9statfs.fsid_val = (unsigned int) vs->stbuf.f_fsid.__val[0] |
+ (unsigned long long)vs->stbuf.f_fsid.__val[1] << 32;
+ vs->v9statfs.f_namelen = vs->stbuf.f_namelen;
+
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "ddqqqqqqd",
+ vs->v9statfs.f_type, vs->v9statfs.f_bsize, vs->v9statfs.f_blocks,
+ vs->v9statfs.f_bfree, vs->v9statfs.f_bavail, vs->v9statfs.f_files,
+ vs->v9statfs.f_ffree, vs->v9statfs.fsid_val,
+ vs->v9statfs.f_namelen);
+
+out:
+ complete_pdu(s, vs->pdu, vs->offset);
+ qemu_free(vs);
+}
+
+static void v9fs_statfs(V9fsState *s, V9fsPDU *pdu)
+{
+ V9fsStatfsState *vs;
+ ssize_t err = 0;
+
+ vs = qemu_malloc(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ memset(&vs->v9statfs, 0, sizeof(vs->v9statfs));
+
+ pdu_unmarshal(vs->pdu, vs->offset, "d", &vs->fid);
+
+ vs->fidp = lookup_fid(s, vs->fid);
+ if (vs->fidp == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ err = v9fs_do_statfs(s, &vs->fidp->path, &vs->stbuf);
+ v9fs_statfs_post_statfs(s, vs, err);
+ return;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
+static void v9fs_mknod_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
+{
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ stat_to_qid(&vs->stbuf, &vs->qid);
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
+ err = vs->offset;
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->fullname);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+}
+
+static void v9fs_mknod_post_mknod(V9fsState *s, V9fsMkState *vs, int err)
+{
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+ v9fs_mknod_post_lstat(s, vs, err);
+ return;
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->fullname);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+}
+
+static void v9fs_mknod(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t fid;
+ V9fsMkState *vs;
+ int err = 0;
+ V9fsFidState *fidp;
+ gid_t gid;
+ int mode;
+ int major, minor;
+
+ vs = qemu_malloc(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ v9fs_string_init(&vs->fullname);
+ pdu_unmarshal(vs->pdu, vs->offset, "dsdddd", &fid, &vs->name, &mode,
+ &major, &minor, &gid);
+
+ fidp = lookup_fid(s, fid);
+ if (fidp == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
+ err = v9fs_do_mknod(s, vs->fullname.data, mode, makedev(major, minor),
+ fidp->uid, gid);
+ v9fs_mknod_post_mknod(s, vs, err);
+ return;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->fullname);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+}
+
+/*
+ * Implement posix byte range locking code
+ * Server side handling of locking code is very simple, because 9p server in
+ * QEMU can handle only one client. And most of the lock handling
+ * (like conflict, merging) etc is done by the VFS layer itself, so no need to
+ * do any thing in * qemu 9p server side lock code path.
+ * So when a TLOCK request comes, always return success
+ */
+
+static void v9fs_lock(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t fid, err = 0;
+ V9fsLockState *vs;
+
+ vs = qemu_mallocz(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ vs->flock = qemu_malloc(sizeof(*vs->flock));
+ pdu_unmarshal(vs->pdu, vs->offset, "dbdqqds", &fid, &vs->flock->type,
+ &vs->flock->flags, &vs->flock->start, &vs->flock->length,
+ &vs->flock->proc_id, &vs->flock->client_id);
+
+ vs->status = P9_LOCK_ERROR;
+
+ /* We support only block flag now (that too ignored currently) */
+ if (vs->flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
+ err = -EINVAL;
+ goto out;
+ }
+ vs->fidp = lookup_fid(s, fid);
+ if (vs->fidp == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+ if (err < 0) {
+ err = -errno;
+ goto out;
+ }
+ vs->status = P9_LOCK_SUCCESS;
+out:
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "b", vs->status);
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs->flock);
+ qemu_free(vs);
+}
+
+/*
+ * When a TGETLOCK request comes, always return success because all lock
+ * handling is done by client's VFS layer.
+ */
+
+static void v9fs_getlock(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t fid, err = 0;
+ V9fsGetlockState *vs;
+
+ vs = qemu_mallocz(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ vs->glock = qemu_malloc(sizeof(*vs->glock));
+ pdu_unmarshal(vs->pdu, vs->offset, "dbqqds", &fid, &vs->glock->type,
+ &vs->glock->start, &vs->glock->length, &vs->glock->proc_id,
+ &vs->glock->client_id);
+
+ vs->fidp = lookup_fid(s, fid);
+ if (vs->fidp == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
+ if (err < 0) {
+ err = -errno;
+ goto out;
+ }
+ vs->glock->type = F_UNLCK;
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "bqqds", vs->glock->type,
+ vs->glock->start, vs->glock->length, vs->glock->proc_id,
+ &vs->glock->client_id);
+out:
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs->glock);
+ qemu_free(vs);
+}
+
+static void v9fs_mkdir_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
+{
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ stat_to_qid(&vs->stbuf, &vs->qid);
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
+ err = vs->offset;
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->fullname);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+}
+
+static void v9fs_mkdir_post_mkdir(V9fsState *s, V9fsMkState *vs, int err)
+{
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
+ v9fs_mkdir_post_lstat(s, vs, err);
+ return;
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->fullname);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+}
+
+static void v9fs_mkdir(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t fid;
+ V9fsMkState *vs;
+ int err = 0;
+ V9fsFidState *fidp;
+ gid_t gid;
+ int mode;
+
+ vs = qemu_malloc(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ v9fs_string_init(&vs->fullname);
+ pdu_unmarshal(vs->pdu, vs->offset, "dsdd", &fid, &vs->name, &mode,
+ &gid);
+
+ fidp = lookup_fid(s, fid);
+ if (fidp == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
+ err = v9fs_do_mkdir(s, vs->fullname.data, mode, fidp->uid, gid);
+ v9fs_mkdir_post_mkdir(s, vs, err);
+ return;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->fullname);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+}
+
+static void v9fs_post_xattr_getvalue(V9fsState *s, V9fsXattrState *vs, int err)
+{
+
+ if (err < 0) {
+ err = -errno;
+ free_fid(s, vs->xattr_fidp->fid);
+ goto out;
+ }
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
+ err = vs->offset;
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+ return;
+}
+
+static void v9fs_post_xattr_check(V9fsState *s, V9fsXattrState *vs, ssize_t err)
+{
+ if (err < 0) {
+ err = -errno;
+ free_fid(s, vs->xattr_fidp->fid);
+ goto out;
+ }
+ /*
+ * Read the xattr value
+ */
+ vs->xattr_fidp->fs.xattr.len = vs->size;
+ vs->xattr_fidp->fid_type = P9_FID_XATTR;
+ vs->xattr_fidp->fs.xattr.copied_len = -1;
+ if (vs->size) {
+ vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+ err = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
+ &vs->name, vs->xattr_fidp->fs.xattr.value,
+ vs->xattr_fidp->fs.xattr.len);
+ }
+ v9fs_post_xattr_getvalue(s, vs, err);
+ return;
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+}
+
+static void v9fs_post_lxattr_getvalue(V9fsState *s,
+ V9fsXattrState *vs, int err)
+{
+ if (err < 0) {
+ err = -errno;
+ free_fid(s, vs->xattr_fidp->fid);
+ goto out;
+ }
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
+ err = vs->offset;
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+ return;
+}
+
+static void v9fs_post_lxattr_check(V9fsState *s,
+ V9fsXattrState *vs, ssize_t err)
+{
+ if (err < 0) {
+ err = -errno;
+ free_fid(s, vs->xattr_fidp->fid);
+ goto out;
+ }
+ /*
+ * Read the xattr value
+ */
+ vs->xattr_fidp->fs.xattr.len = vs->size;
+ vs->xattr_fidp->fid_type = P9_FID_XATTR;
+ vs->xattr_fidp->fs.xattr.copied_len = -1;
+ if (vs->size) {
+ vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+ err = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
+ vs->xattr_fidp->fs.xattr.value,
+ vs->xattr_fidp->fs.xattr.len);
+ }
+ v9fs_post_lxattr_getvalue(s, vs, err);
+ return;
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+}
+
+static void v9fs_xattrwalk(V9fsState *s, V9fsPDU *pdu)
+{
+ ssize_t err = 0;
+ V9fsXattrState *vs;
+ int32_t fid, newfid;
+
+ vs = qemu_malloc(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &newfid, &vs->name);
+ vs->file_fidp = lookup_fid(s, fid);
+ if (vs->file_fidp == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ vs->xattr_fidp = alloc_fid(s, newfid);
+ if (vs->xattr_fidp == NULL) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ v9fs_string_copy(&vs->xattr_fidp->path, &vs->file_fidp->path);
+ if (vs->name.data[0] == 0) {
+ /*
+ * listxattr request. Get the size first
+ */
+ vs->size = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
+ NULL, 0);
+ if (vs->size < 0) {
+ err = vs->size;
+ }
+ v9fs_post_lxattr_check(s, vs, err);
+ return;
+ } else {
+ /*
+ * specific xattr fid. We check for xattr
+ * presence also collect the xattr size
+ */
+ vs->size = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
+ &vs->name, NULL, 0);
+ if (vs->size < 0) {
+ err = vs->size;
+ }
+ v9fs_post_xattr_check(s, vs, err);
+ return;
+ }
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+}
+
+static void v9fs_xattrcreate(V9fsState *s, V9fsPDU *pdu)
+{
+ int flags;
+ int32_t fid;
+ ssize_t err = 0;
+ V9fsXattrState *vs;
+
+ vs = qemu_malloc(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ pdu_unmarshal(vs->pdu, vs->offset, "dsqd",
+ &fid, &vs->name, &vs->size, &flags);
+
+ vs->file_fidp = lookup_fid(s, fid);
+ if (vs->file_fidp == NULL) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ /* Make the file fid point to xattr */
+ vs->xattr_fidp = vs->file_fidp;
+ vs->xattr_fidp->fid_type = P9_FID_XATTR;
+ vs->xattr_fidp->fs.xattr.copied_len = 0;
+ vs->xattr_fidp->fs.xattr.len = vs->size;
+ vs->xattr_fidp->fs.xattr.flags = flags;
+ v9fs_string_init(&vs->xattr_fidp->fs.xattr.name);
+ v9fs_string_copy(&vs->xattr_fidp->fs.xattr.name, &vs->name);
+ if (vs->size)
+ vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
+ else
+ vs->xattr_fidp->fs.xattr.value = NULL;
+
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->name);
+ qemu_free(vs);
+}
+
+static void v9fs_readlink_post_readlink(V9fsState *s, V9fsReadLinkState *vs,
+ int err)
+{
+ if (err < 0) {
+ err = -errno;
+ goto out;
+ }
+ vs->offset += pdu_marshal(vs->pdu, vs->offset, "s", &vs->target);
+ err = vs->offset;
+out:
+ complete_pdu(s, vs->pdu, err);
+ v9fs_string_free(&vs->target);
+ qemu_free(vs);
+}
+
+static void v9fs_readlink(V9fsState *s, V9fsPDU *pdu)
+{
+ int32_t fid;
+ V9fsReadLinkState *vs;
+ int err = 0;
+ V9fsFidState *fidp;
+
+ vs = qemu_malloc(sizeof(*vs));
+ vs->pdu = pdu;
+ vs->offset = 7;
+
+ pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
+
+ fidp = lookup_fid(s, fid);
+ if (fidp == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+
+ v9fs_string_init(&vs->target);
+ err = v9fs_do_readlink(s, &fidp->path, &vs->target);
+ v9fs_readlink_post_readlink(s, vs, err);
+ return;
+out:
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
static pdu_handler_t *pdu_handlers[] = {
+ [P9_TREADDIR] = v9fs_readdir,
+ [P9_TSTATFS] = v9fs_statfs,
+ [P9_TGETATTR] = v9fs_getattr,
+ [P9_TSETATTR] = v9fs_setattr,
+ [P9_TXATTRWALK] = v9fs_xattrwalk,
+ [P9_TXATTRCREATE] = v9fs_xattrcreate,
+ [P9_TMKNOD] = v9fs_mknod,
+ [P9_TRENAME] = v9fs_rename,
+ [P9_TLOCK] = v9fs_lock,
+ [P9_TGETLOCK] = v9fs_getlock,
+ [P9_TREADLINK] = v9fs_readlink,
+ [P9_TMKDIR] = v9fs_mkdir,
[P9_TVERSION] = v9fs_version,
+ [P9_TLOPEN] = v9fs_open,
[P9_TATTACH] = v9fs_attach,
[P9_TSTAT] = v9fs_stat,
[P9_TWALK] = v9fs_walk,
[P9_TCLUNK] = v9fs_clunk,
+ [P9_TFSYNC] = v9fs_fsync,
[P9_TOPEN] = v9fs_open,
[P9_TREAD] = v9fs_read,
#if 0
[P9_TAUTH] = v9fs_auth,
#endif
[P9_TFLUSH] = v9fs_flush,
+ [P9_TLINK] = v9fs_link,
+ [P9_TSYMLINK] = v9fs_symlink,
[P9_TCREATE] = v9fs_create,
+ [P9_TLCREATE] = v9fs_lcreate,
[P9_TWRITE] = v9fs_write,
[P9_TWSTAT] = v9fs_wstat,
[P9_TREMOVE] = v9fs_remove,
@@ -2252,8 +3676,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
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);
+ fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
+ "id = %s\n", conf->fsdev_id ? conf->fsdev_id : "NULL");
exit(1);
}
@@ -2268,17 +3692,26 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
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 {
- /* user haven't specified a correct security option */
- fprintf(stderr, "one of the following must be specified as the"
+ 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");
- return NULL;
+ s->ctx.fs_sm = SM_NONE;
+ s->ctx.xops = none_xattr_ops;
}
if (lstat(fse->path, &stat)) {
diff --git a/hw/virtio-9p.h b/hw/virtio-9p.h
index 67f808761f..6c233192e3 100644
--- a/hw/virtio-9p.h
+++ b/hw/virtio-9p.h
@@ -13,6 +13,42 @@
#define VIRTIO_9P_MOUNT_TAG 0
enum {
+ P9_TLERROR = 6,
+ P9_RLERROR,
+ P9_TSTATFS = 8,
+ P9_RSTATFS,
+ P9_TLOPEN = 12,
+ P9_RLOPEN,
+ P9_TLCREATE = 14,
+ P9_RLCREATE,
+ P9_TSYMLINK = 16,
+ P9_RSYMLINK,
+ P9_TMKNOD = 18,
+ P9_RMKNOD,
+ P9_TRENAME = 20,
+ P9_RRENAME,
+ P9_TREADLINK = 22,
+ P9_RREADLINK,
+ P9_TGETATTR = 24,
+ P9_RGETATTR,
+ P9_TSETATTR = 26,
+ P9_RSETATTR,
+ P9_TXATTRWALK = 30,
+ P9_RXATTRWALK,
+ P9_TXATTRCREATE = 32,
+ P9_RXATTRCREATE,
+ P9_TREADDIR = 40,
+ P9_RREADDIR,
+ P9_TFSYNC = 50,
+ P9_RFSYNC,
+ P9_TLOCK = 52,
+ P9_RLOCK,
+ P9_TGETLOCK = 54,
+ P9_RGETLOCK,
+ P9_TLINK = 70,
+ P9_RLINK,
+ P9_TMKDIR = 72,
+ P9_RMKDIR,
P9_TVERSION = 100,
P9_RVERSION,
P9_TAUTH = 102,
@@ -57,10 +93,21 @@ enum {
P9_QTFILE = 0x00,
};
+enum p9_proto_version {
+ V9FS_PROTO_2000U = 0x01,
+ V9FS_PROTO_2000L = 0x02,
+};
+
#define P9_NOTAG (u16)(~0)
#define P9_NOFID (u32)(~0)
#define P9_MAXWELEM 16
+/*
+ * ample room for Twrite/Rread header
+ * size[4] Tread/Twrite tag[2] fid[4] offset[8] count[4]
+ */
+#define P9_IOHDRSZ 24
+
typedef struct V9fsPDU V9fsPDU;
struct V9fsPDU
@@ -122,12 +169,32 @@ typedef struct V9fsStat
int32_t n_muid;
} V9fsStat;
+enum {
+ P9_FID_NONE = 0,
+ P9_FID_FILE,
+ P9_FID_DIR,
+ P9_FID_XATTR,
+};
+
+typedef struct V9fsXattr
+{
+ int64_t copied_len;
+ int64_t len;
+ void *value;
+ V9fsString name;
+ int flags;
+} V9fsXattr;
+
struct V9fsFidState
{
+ int fid_type;
int32_t fid;
V9fsString path;
- int fd;
- DIR *dir;
+ union {
+ int fd;
+ DIR *dir;
+ V9fsXattr xattr;
+ } fs;
uid_t uid;
V9fsFidState *next;
};
@@ -144,6 +211,8 @@ typedef struct V9fsState
uint16_t tag_len;
uint8_t *tag;
size_t config_size;
+ enum p9_proto_version proto_version;
+ int32_t msize;
} V9fsState;
typedef struct V9fsCreateState {
@@ -157,8 +226,20 @@ typedef struct V9fsCreateState {
V9fsString name;
V9fsString extension;
V9fsString fullname;
+ int iounit;
} V9fsCreateState;
+typedef struct V9fsLcreateState {
+ V9fsPDU *pdu;
+ size_t offset;
+ V9fsFidState *fidp;
+ V9fsQID qid;
+ int32_t iounit;
+ struct stat stbuf;
+ V9fsString name;
+ V9fsString fullname;
+} V9fsLcreateState;
+
typedef struct V9fsStatState {
V9fsPDU *pdu;
size_t offset;
@@ -167,6 +248,37 @@ typedef struct V9fsStatState {
struct stat stbuf;
} V9fsStatState;
+typedef struct V9fsStatDotl {
+ uint64_t st_result_mask;
+ V9fsQID qid;
+ uint32_t st_mode;
+ uint32_t st_uid;
+ uint32_t st_gid;
+ uint64_t st_nlink;
+ uint64_t st_rdev;
+ uint64_t st_size;
+ uint64_t st_blksize;
+ uint64_t st_blocks;
+ uint64_t st_atime_sec;
+ uint64_t st_atime_nsec;
+ uint64_t st_mtime_sec;
+ uint64_t st_mtime_nsec;
+ uint64_t st_ctime_sec;
+ uint64_t st_ctime_nsec;
+ uint64_t st_btime_sec;
+ uint64_t st_btime_nsec;
+ uint64_t st_gen;
+ uint64_t st_data_version;
+} V9fsStatDotl;
+
+typedef struct V9fsStatStateDotl {
+ V9fsPDU *pdu;
+ size_t offset;
+ V9fsStatDotl v9stat_dotl;
+ struct stat stbuf;
+} V9fsStatStateDotl;
+
+
typedef struct V9fsWalkState {
V9fsPDU *pdu;
size_t offset;
@@ -183,10 +295,11 @@ typedef struct V9fsWalkState {
typedef struct V9fsOpenState {
V9fsPDU *pdu;
size_t offset;
- int8_t mode;
+ int32_t mode;
V9fsFidState *fidp;
V9fsQID qid;
struct stat stbuf;
+ int iounit;
} V9fsOpenState;
typedef struct V9fsReadState {
@@ -235,9 +348,41 @@ typedef struct V9fsWstatState
V9fsStat v9stat;
V9fsFidState *fidp;
struct stat stbuf;
- V9fsString nname;
} V9fsWstatState;
+typedef struct V9fsSymlinkState
+{
+ V9fsPDU *pdu;
+ size_t offset;
+ V9fsString name;
+ V9fsString symname;
+ V9fsString fullname;
+ V9fsFidState *dfidp;
+ V9fsQID qid;
+ struct stat stbuf;
+} V9fsSymlinkState;
+
+typedef struct V9fsIattr
+{
+ int32_t valid;
+ int32_t mode;
+ int32_t uid;
+ int32_t gid;
+ int64_t size;
+ int64_t atime_sec;
+ int64_t atime_nsec;
+ int64_t mtime_sec;
+ int64_t mtime_nsec;
+} V9fsIattr;
+
+typedef struct V9fsSetattrState
+{
+ V9fsPDU *pdu;
+ size_t offset;
+ V9fsIattr v9iattr;
+ V9fsFidState *fidp;
+} V9fsSetattrState;
+
struct virtio_9p_config
{
/* number of characters in tag */
@@ -246,6 +391,110 @@ struct virtio_9p_config
uint8_t tag[0];
} __attribute__((packed));
+typedef struct V9fsStatfs
+{
+ uint32_t f_type;
+ uint32_t f_bsize;
+ uint64_t f_blocks;
+ uint64_t f_bfree;
+ uint64_t f_bavail;
+ uint64_t f_files;
+ uint64_t f_ffree;
+ uint64_t fsid_val;
+ uint32_t f_namelen;
+} V9fsStatfs;
+
+typedef struct V9fsStatfsState {
+ V9fsPDU *pdu;
+ size_t offset;
+ int32_t fid;
+ V9fsStatfs v9statfs;
+ V9fsFidState *fidp;
+ struct statfs stbuf;
+} V9fsStatfsState;
+
+typedef struct V9fsMkState {
+ V9fsPDU *pdu;
+ size_t offset;
+ V9fsQID qid;
+ struct stat stbuf;
+ V9fsString name;
+ V9fsString fullname;
+} V9fsMkState;
+
+typedef struct V9fsRenameState {
+ V9fsPDU *pdu;
+ V9fsFidState *fidp;
+ size_t offset;
+ int32_t newdirfid;
+ V9fsString name;
+} V9fsRenameState;
+
+typedef struct V9fsXattrState
+{
+ V9fsPDU *pdu;
+ size_t offset;
+ V9fsFidState *file_fidp;
+ V9fsFidState *xattr_fidp;
+ V9fsString name;
+ int64_t size;
+ int flags;
+ void *value;
+} V9fsXattrState;
+
+#define P9_LOCK_SUCCESS 0
+#define P9_LOCK_BLOCKED 1
+#define P9_LOCK_ERROR 2
+#define P9_LOCK_GRACE 3
+
+#define P9_LOCK_FLAGS_BLOCK 1
+#define P9_LOCK_FLAGS_RECLAIM 2
+
+typedef struct V9fsFlock
+{
+ uint8_t type;
+ uint32_t flags;
+ uint64_t start; /* absolute offset */
+ uint64_t length;
+ uint32_t proc_id;
+ V9fsString client_id;
+} V9fsFlock;
+
+typedef struct V9fsLockState
+{
+ V9fsPDU *pdu;
+ size_t offset;
+ int8_t status;
+ struct stat stbuf;
+ V9fsFidState *fidp;
+ V9fsFlock *flock;
+} V9fsLockState;
+
+typedef struct V9fsGetlock
+{
+ uint8_t type;
+ uint64_t start; /* absolute offset */
+ uint64_t length;
+ uint32_t proc_id;
+ V9fsString client_id;
+} V9fsGetlock;
+
+typedef struct V9fsGetlockState
+{
+ V9fsPDU *pdu;
+ size_t offset;
+ struct stat stbuf;
+ V9fsFidState *fidp;
+ V9fsGetlock *glock;
+} V9fsGetlockState;
+
+typedef struct V9fsReadLinkState
+{
+ V9fsPDU *pdu;
+ size_t offset;
+ V9fsString target;
+} V9fsReadLinkState;
+
extern size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
size_t offset, size_t size, int pack);
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 9fe3886b0f..8adddeaa53 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -29,6 +29,10 @@
#include <sys/mman.h>
#endif
+/* Disable guest-provided stats by now (https://bugzilla.redhat.com/show_bug.cgi?id=623903) */
+#define ENABLE_GUEST_STATS 0
+
+
typedef struct VirtIOBalloon
{
VirtIODevice vdev;
@@ -51,8 +55,8 @@ static void balloon_page(void *addr, int deflate)
{
#if defined(__linux__)
if (!kvm_enabled() || kvm_has_sync_mmu())
- madvise(addr, TARGET_PAGE_SIZE,
- deflate ? MADV_WILLNEED : MADV_DONTNEED);
+ qemu_madvise(addr, TARGET_PAGE_SIZE,
+ deflate ? QEMU_MADV_WILLNEED : QEMU_MADV_DONTNEED);
#endif
}
@@ -83,12 +87,14 @@ static QObject *get_stats_qobject(VirtIOBalloon *dev)
VIRTIO_BALLOON_PFN_SHIFT);
stat_put(dict, "actual", actual);
+#if ENABLE_GUEST_STATS
stat_put(dict, "mem_swapped_in", dev->stats[VIRTIO_BALLOON_S_SWAP_IN]);
stat_put(dict, "mem_swapped_out", dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]);
stat_put(dict, "major_page_faults", dev->stats[VIRTIO_BALLOON_S_MAJFLT]);
stat_put(dict, "minor_page_faults", dev->stats[VIRTIO_BALLOON_S_MINFLT]);
stat_put(dict, "free_mem", dev->stats[VIRTIO_BALLOON_S_MEMFREE]);
stat_put(dict, "total_mem", dev->stats[VIRTIO_BALLOON_S_MEMTOT]);
+#endif
return QOBJECT(dict);
}
@@ -214,7 +220,7 @@ static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
}
dev->stats_callback = cb;
dev->stats_opaque_callback_data = cb_data;
- if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) {
+ if (ENABLE_GUEST_STATS && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
virtio_notify(&dev->vdev, dev->svq);
} else {
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 8747634fbe..a1df26dbcf 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -12,6 +12,9 @@
*/
#include <qemu-common.h>
+#include "qemu-error.h"
+#include "trace.h"
+#include "blockdev.h"
#include "virtio-blk.h"
#ifdef __linux__
# include <scsi/sg.h>
@@ -27,6 +30,7 @@ typedef struct VirtIOBlock
BlockConf *conf;
unsigned short sector_mask;
char sn[BLOCK_SERIAL_STRLEN];
+ DeviceState *qdev;
} VirtIOBlock;
static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
@@ -49,6 +53,8 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
{
VirtIOBlock *s = req->dev;
+ trace_virtio_blk_req_complete(req, status);
+
req->in->status = status;
virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
virtio_notify(&s->vdev, s->vq);
@@ -85,6 +91,8 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
{
VirtIOBlockReq *req = opaque;
+ trace_virtio_blk_rw_complete(req, ret);
+
if (ret) {
int is_read = !(req->out->type & VIRTIO_BLK_T_OUT);
if (virtio_blk_handle_rw_error(req, -ret, is_read))
@@ -267,6 +275,8 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
{
BlockRequest *blkreq;
+ trace_virtio_blk_handle_write(req, req->out->sector, req->qiov.size / 512);
+
if (req->out->sector & req->dev->sector_mask) {
virtio_blk_rw_complete(req, -EIO);
return;
@@ -478,6 +488,11 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
req->next = s->rq;
s->rq = req;
+
+ virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr,
+ req->elem.in_num, 1);
+ virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr,
+ req->elem.out_num, 0);
}
return 0;
@@ -490,6 +505,15 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
static int virtio_blk_id;
DriveInfo *dinfo;
+ if (!conf->bs) {
+ error_report("virtio-blk-pci: drive property not set");
+ return NULL;
+ }
+ if (!bdrv_is_inserted(conf->bs)) {
+ error_report("Device needs media, but drive is empty");
+ return NULL;
+ }
+
s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK,
sizeof(struct virtio_blk_config),
sizeof(VirtIOBlock));
@@ -512,9 +536,17 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);
qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
+ s->qdev = dev;
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
virtio_blk_save, virtio_blk_load, s);
bdrv_set_removable(s->bs, 0);
+ s->bs->buffer_alignment = conf->logical_block_size;
return &s->vdev;
}
+
+void virtio_blk_exit(VirtIODevice *vdev)
+{
+ VirtIOBlock *s = to_virtio_blk(vdev);
+ unregister_savevm(s->qdev, "virtio-blk", s);
+}
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 075f72df2d..7e1688cf69 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -36,7 +36,10 @@ typedef struct VirtIONet
VirtQueue *ctrl_vq;
NICState *nic;
QEMUTimer *tx_timer;
- int tx_timer_active;
+ QEMUBH *tx_bh;
+ uint32_t tx_timeout;
+ int32_t tx_burst;
+ int tx_waiting;
uint32_t has_vnet_hdr;
uint8_t has_ufo;
struct {
@@ -51,6 +54,7 @@ typedef struct VirtIONet
uint8_t nouni;
uint8_t nobcast;
uint8_t vhost_started;
+ bool vm_running;
VMChangeStateEntry *vmstate;
struct {
int in_use;
@@ -95,6 +99,38 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
}
}
+static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
+{
+ VirtIONet *n = to_virtio_net(vdev);
+ if (!n->nic->nc.peer) {
+ return;
+ }
+ if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
+ return;
+ }
+
+ if (!tap_get_vhost_net(n->nic->nc.peer)) {
+ return;
+ }
+ if (!!n->vhost_started == ((status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+ (n->status & VIRTIO_NET_S_LINK_UP) &&
+ n->vm_running)) {
+ return;
+ }
+ if (!n->vhost_started) {
+ int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
+ if (r < 0) {
+ fprintf(stderr, "unable to start vhost net: %d: "
+ "falling back on userspace virtio\n", -r);
+ } else {
+ n->vhost_started = 1;
+ }
+ } else {
+ vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
+ n->vhost_started = 0;
+ }
+}
+
static void virtio_net_set_link_status(VLANClientState *nc)
{
VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
@@ -107,6 +143,8 @@ static void virtio_net_set_link_status(VLANClientState *nc)
if (n->status != old_status)
virtio_notify_config(&n->vdev);
+
+ virtio_net_set_status(&n->vdev, n->vdev.status);
}
static void virtio_net_reset(VirtIODevice *vdev)
@@ -120,10 +158,6 @@ static void virtio_net_reset(VirtIODevice *vdev)
n->nomulti = 0;
n->nouni = 0;
n->nobcast = 0;
- if (n->vhost_started) {
- vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
- n->vhost_started = 0;
- }
/* Flush any MAC and VLAN filter table state */
n->mac_table.in_use = 0;
@@ -619,7 +653,7 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
return size;
}
-static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq);
+static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq);
static void virtio_net_tx_complete(VLANClientState *nc, ssize_t len)
{
@@ -635,16 +669,18 @@ static void virtio_net_tx_complete(VLANClientState *nc, ssize_t len)
}
/* TX */
-static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
+static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
{
VirtQueueElement elem;
+ int32_t num_packets = 0;
- if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
- return;
+ if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ return num_packets;
+ }
if (n->async_tx.elem.out_num) {
virtio_queue_set_notification(n->tx_vq, 0);
- return;
+ return num_packets;
}
while (virtqueue_pop(vq, &elem)) {
@@ -681,38 +717,55 @@ static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
virtio_queue_set_notification(n->tx_vq, 0);
n->async_tx.elem = elem;
n->async_tx.len = len;
- return;
+ return -EBUSY;
}
len += ret;
virtqueue_push(vq, &elem, len);
virtio_notify(&n->vdev, vq);
+
+ if (++num_packets >= n->tx_burst) {
+ break;
+ }
}
+ return num_packets;
}
-static void virtio_net_handle_tx(VirtIODevice *vdev, VirtQueue *vq)
+static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIONet *n = to_virtio_net(vdev);
- if (n->tx_timer_active) {
+ if (n->tx_waiting) {
virtio_queue_set_notification(vq, 1);
qemu_del_timer(n->tx_timer);
- n->tx_timer_active = 0;
+ n->tx_waiting = 0;
virtio_net_flush_tx(n, vq);
} else {
qemu_mod_timer(n->tx_timer,
- qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
- n->tx_timer_active = 1;
+ qemu_get_clock(vm_clock) + n->tx_timeout);
+ n->tx_waiting = 1;
virtio_queue_set_notification(vq, 0);
}
}
+static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIONet *n = to_virtio_net(vdev);
+
+ if (unlikely(n->tx_waiting)) {
+ return;
+ }
+ virtio_queue_set_notification(vq, 0);
+ qemu_bh_schedule(n->tx_bh);
+ n->tx_waiting = 1;
+}
+
static void virtio_net_tx_timer(void *opaque)
{
VirtIONet *n = opaque;
- n->tx_timer_active = 0;
+ n->tx_waiting = 0;
/* Just in case the driver is not ready on more */
if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
@@ -722,20 +775,52 @@ static void virtio_net_tx_timer(void *opaque)
virtio_net_flush_tx(n, n->tx_vq);
}
-static void virtio_net_save(QEMUFile *f, void *opaque)
+static void virtio_net_tx_bh(void *opaque)
{
VirtIONet *n = opaque;
+ int32_t ret;
- if (n->vhost_started) {
- /* TODO: should we really stop the backend?
- * If we don't, it might keep writing to memory. */
- vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev);
- n->vhost_started = 0;
+ n->tx_waiting = 0;
+
+ /* Just in case the driver is not ready on more */
+ if (unlikely(!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)))
+ return;
+
+ ret = virtio_net_flush_tx(n, n->tx_vq);
+ if (ret == -EBUSY) {
+ return; /* Notification re-enable handled by tx_complete */
}
+
+ /* If we flush a full burst of packets, assume there are
+ * more coming and immediately reschedule */
+ if (ret >= n->tx_burst) {
+ qemu_bh_schedule(n->tx_bh);
+ n->tx_waiting = 1;
+ return;
+ }
+
+ /* If less than a full burst, re-enable notification and flush
+ * anything that may have come in while we weren't looking. If
+ * we find something, assume the guest is still active and reschedule */
+ virtio_queue_set_notification(n->tx_vq, 1);
+ if (virtio_net_flush_tx(n, n->tx_vq) > 0) {
+ virtio_queue_set_notification(n->tx_vq, 0);
+ qemu_bh_schedule(n->tx_bh);
+ n->tx_waiting = 1;
+ }
+}
+
+static void virtio_net_save(QEMUFile *f, void *opaque)
+{
+ VirtIONet *n = opaque;
+
+ /* At this point, backend must be stopped, otherwise
+ * it might keep writing to memory. */
+ assert(!n->vhost_started);
virtio_save(&n->vdev, f);
qemu_put_buffer(f, n->mac, ETH_ALEN);
- qemu_put_be32(f, n->tx_timer_active);
+ qemu_put_be32(f, n->tx_waiting);
qemu_put_be32(f, n->mergeable_rx_bufs);
qemu_put_be16(f, n->status);
qemu_put_byte(f, n->promisc);
@@ -764,7 +849,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
virtio_load(&n->vdev, f);
qemu_get_buffer(f, n->mac, ETH_ALEN);
- n->tx_timer_active = qemu_get_be32(f);
+ n->tx_waiting = qemu_get_be32(f);
n->mergeable_rx_bufs = qemu_get_be32(f);
if (version_id >= 3)
@@ -840,9 +925,13 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
}
n->mac_table.first_multi = i;
- if (n->tx_timer_active) {
- qemu_mod_timer(n->tx_timer,
- qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
+ if (n->tx_waiting) {
+ if (n->tx_timer) {
+ qemu_mod_timer(n->tx_timer,
+ qemu_get_clock(vm_clock) + n->tx_timeout);
+ } else {
+ qemu_bh_schedule(n->tx_bh);
+ }
}
return 0;
}
@@ -863,47 +952,18 @@ static NetClientInfo net_virtio_info = {
.link_status_changed = virtio_net_set_link_status,
};
-static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
-{
- VirtIONet *n = to_virtio_net(vdev);
- if (!n->nic->nc.peer) {
- return;
- }
- if (n->nic->nc.peer->info->type != NET_CLIENT_TYPE_TAP) {
- return;
- }
-
- if (!tap_get_vhost_net(n->nic->nc.peer)) {
- return;
- }
- if (!!n->vhost_started == !!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
- return;
- }
- if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
- int r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), vdev);
- if (r < 0) {
- fprintf(stderr, "unable to start vhost net: %d: "
- "falling back on userspace virtio\n", -r);
- } else {
- n->vhost_started = 1;
- }
- } else {
- vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
- n->vhost_started = 0;
- }
-}
-
static void virtio_net_vmstate_change(void *opaque, int running, int reason)
{
VirtIONet *n = opaque;
- uint8_t status = running ? VIRTIO_CONFIG_S_DRIVER_OK : 0;
+ n->vm_running = running;
/* This is called when vm is started/stopped,
- * it will start/stop vhost backend if * appropriate
+ * it will start/stop vhost backend if appropriate
* e.g. after migration. */
- virtio_net_set_status(&n->vdev, n->vdev.status & status);
+ virtio_net_set_status(&n->vdev, n->vdev.status);
}
-VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
+VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
+ virtio_net_conf *net)
{
VirtIONet *n;
@@ -919,7 +979,22 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
n->vdev.reset = virtio_net_reset;
n->vdev.set_status = virtio_net_set_status;
n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
- n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx);
+
+ if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) {
+ fprintf(stderr, "virtio-net: "
+ "Unknown option tx=%s, valid options: \"timer\" \"bh\"\n",
+ net->tx);
+ fprintf(stderr, "Defaulting to \"bh\"\n");
+ }
+
+ if (net->tx && !strcmp(net->tx, "timer")) {
+ n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx_timer);
+ n->tx_timer = qemu_new_timer(vm_clock, virtio_net_tx_timer, n);
+ n->tx_timeout = net->txtimer;
+ } else {
+ n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx_bh);
+ n->tx_bh = qemu_bh_new(virtio_net_tx_bh, n);
+ }
n->ctrl_vq = virtio_add_queue(&n->vdev, 64, virtio_net_handle_ctrl);
qemu_macaddr_default_if_unset(&conf->macaddr);
memcpy(&n->mac[0], &conf->macaddr, sizeof(n->mac));
@@ -929,8 +1004,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
qemu_format_nic_info_str(&n->nic->nc, conf->macaddr.a);
- n->tx_timer = qemu_new_timer(vm_clock, virtio_net_tx_timer, n);
- n->tx_timer_active = 0;
+ n->tx_waiting = 0;
+ n->tx_burst = net->txburst;
n->mergeable_rx_bufs = 0;
n->promisc = 1; /* for compatibility */
@@ -951,9 +1026,8 @@ void virtio_net_exit(VirtIODevice *vdev)
VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev);
qemu_del_vm_change_state_handler(n->vmstate);
- if (n->vhost_started) {
- vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), vdev);
- }
+ /* This will stop vhost backend if appropriate. */
+ virtio_net_set_status(vdev, 0);
qemu_purge_queued_packets(&n->nic->nc);
@@ -962,8 +1036,12 @@ void virtio_net_exit(VirtIODevice *vdev)
qemu_free(n->mac_table.macs);
qemu_free(n->vlans);
- qemu_del_timer(n->tx_timer);
- qemu_free_timer(n->tx_timer);
+ if (n->tx_timer) {
+ qemu_del_timer(n->tx_timer);
+ qemu_free_timer(n->tx_timer);
+ } else {
+ qemu_bh_delete(n->tx_bh);
+ }
virtio_cleanup(&n->vdev);
qemu_del_vlan_client(&n->nic->nc);
diff --git a/hw/virtio-net.h b/hw/virtio-net.h
index 235f1a9fa8..8af9a1ce55 100644
--- a/hw/virtio-net.h
+++ b/hw/virtio-net.h
@@ -49,6 +49,20 @@
#define TX_TIMER_INTERVAL 150000 /* 150 us */
+/* Limit the number of packets that can be sent via a single flush
+ * of the TX queue. This gives us a guaranteed exit condition and
+ * ensures fairness in the io path. 256 conveniently matches the
+ * length of the TX queue and shows a good balance of performance
+ * and latency. */
+#define TX_BURST 256
+
+typedef struct virtio_net_conf
+{
+ uint32_t txtimer;
+ int32_t txburst;
+ char *tx;
+} virtio_net_conf;
+
/* Maximum packet size we can receive from tap device: header + 64k */
#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index c728fffd73..729917d891 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -24,6 +24,7 @@
#include "net.h"
#include "loader.h"
#include "kvm.h"
+#include "blockdev.h"
/* from Linux's linux/virtio_pci.h */
@@ -106,6 +107,7 @@ typedef struct {
#endif
/* Max. number of ports we can have for a the virtio-serial device */
uint32_t max_virtserial_ports;
+ virtio_net_conf net;
} VirtIOPCIProxy;
/* virtio device */
@@ -449,6 +451,33 @@ static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
return 0;
}
+static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
+{
+ VirtIOPCIProxy *proxy = opaque;
+ VirtIODevice *vdev = proxy->vdev;
+ int r, n;
+
+ for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+ if (!virtio_queue_get_num(vdev, n)) {
+ break;
+ }
+
+ r = virtio_pci_set_guest_notifier(opaque, n, assign);
+ if (r < 0) {
+ goto assign_error;
+ }
+ }
+
+ return 0;
+
+assign_error:
+ /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
+ while (--n >= 0) {
+ virtio_pci_set_guest_notifier(opaque, n, !assign);
+ }
+ return r;
+}
+
static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign)
{
VirtIOPCIProxy *proxy = opaque;
@@ -486,7 +515,7 @@ static const VirtIOBindings virtio_pci_bindings = {
.load_queue = virtio_pci_load_queue,
.get_features = virtio_pci_get_features,
.set_host_notifier = virtio_pci_set_host_notifier,
- .set_guest_notifier = virtio_pci_set_guest_notifier,
+ .set_guest_notifiers = virtio_pci_set_guest_notifiers,
};
static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
@@ -546,11 +575,10 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev)
proxy->class_code != PCI_CLASS_STORAGE_OTHER)
proxy->class_code = PCI_CLASS_STORAGE_SCSI;
- if (!proxy->block.bs) {
- error_report("virtio-blk-pci: drive property not set");
+ vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block);
+ if (!vdev) {
return -1;
}
- vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block);
vdev->nvectors = proxy->nvectors;
virtio_init_pci(proxy, vdev,
PCI_VENDOR_ID_REDHAT_QUMRANET,
@@ -570,6 +598,7 @@ static int virtio_blk_exit_pci(PCIDevice *pci_dev)
{
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+ virtio_blk_exit(proxy->vdev);
blockdev_mark_auto_del(proxy->block.bs);
return virtio_exit_pci(pci_dev);
}
@@ -599,12 +628,20 @@ static int virtio_serial_init_pci(PCIDevice *pci_dev)
return 0;
}
+static int virtio_serial_exit_pci(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+ virtio_serial_exit(proxy->vdev);
+ return virtio_exit_pci(pci_dev);
+}
+
static int virtio_net_init_pci(PCIDevice *pci_dev)
{
VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
VirtIODevice *vdev;
- vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic);
+ vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic, &proxy->net);
vdev->nvectors = proxy->nvectors;
virtio_init_pci(proxy, vdev,
@@ -681,6 +718,11 @@ static PCIDeviceInfo virtio_info[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
+ DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy,
+ net.txtimer, TX_TIMER_INTERVAL),
+ DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy,
+ net.txburst, TX_BURST),
+ DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
DEFINE_PROP_END_OF_LIST(),
},
.qdev.reset = virtio_pci_reset,
@@ -689,7 +731,7 @@ static PCIDeviceInfo virtio_info[] = {
.qdev.alias = "virtio-serial",
.qdev.size = sizeof(VirtIOPCIProxy),
.init = virtio_serial_init_pci,
- .exit = virtio_exit_pci,
+ .exit = virtio_serial_exit_pci,
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 26d5841154..74ba5ec3d3 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -41,6 +41,8 @@ struct VirtIOSerial {
VirtIOSerialBus *bus;
+ DeviceState *qdev;
+
QTAILQ_HEAD(, VirtIOSerialPort) ports;
/* bitmap for identifying active ports */
@@ -117,6 +119,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
VirtQueueElement elem;
assert(port || discard);
+ assert(virtio_queue_ready(vq));
while ((discard || !port->throttled) && virtqueue_pop(vq, &elem)) {
uint8_t *buf;
@@ -139,6 +142,9 @@ static void flush_queued_data(VirtIOSerialPort *port, bool discard)
{
assert(port);
+ if (!virtio_queue_ready(port->ovq)) {
+ return;
+ }
do_flush_queued_data(port, port->ovq, &port->vser->vdev, discard);
}
@@ -730,11 +736,19 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
{
VirtIOSerial *vser;
VirtIODevice *vdev;
- uint32_t i;
+ uint32_t i, max_supported_ports;
if (!max_nr_ports)
return NULL;
+ /* Each port takes 2 queues, and one pair is for the control queue */
+ max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
+
+ if (max_nr_ports > max_supported_ports) {
+ error_report("maximum ports supported: %u", max_supported_ports);
+ return NULL;
+ }
+
vdev = virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE,
sizeof(struct virtio_console_config),
sizeof(VirtIOSerial));
@@ -780,6 +794,8 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
vser->vdev.get_config = get_config;
vser->vdev.set_config = set_config;
+ vser->qdev = dev;
+
/*
* Register for the savevm section with the virtio-console name
* to preserve backward compat
@@ -789,3 +805,16 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
return vdev;
}
+
+void virtio_serial_exit(VirtIODevice *vdev)
+{
+ VirtIOSerial *vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+
+ unregister_savevm(vser->qdev, "virtio-console", vser);
+
+ qemu_free(vser->ivqs);
+ qemu_free(vser->ovqs);
+ qemu_free(vser->ports_map);
+
+ virtio_cleanup(vdev);
+}
diff --git a/hw/virtio.c b/hw/virtio.c
index 4475bb3e44..a2a657e132 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -13,6 +13,7 @@
#include <inttypes.h>
+#include "trace.h"
#include "virtio.h"
#include "sysemu.h"
@@ -205,6 +206,8 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
unsigned int offset;
int i;
+ trace_virtqueue_fill(vq, elem, len, idx);
+
offset = 0;
for (i = 0; i < elem->in_num; i++) {
size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
@@ -232,6 +235,7 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count)
{
/* Make sure buffer is written before we update index. */
wmb();
+ trace_virtqueue_flush(vq, count);
vring_used_idx_increment(vq, count);
vq->inuse -= count;
}
@@ -360,11 +364,26 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes)
return 0;
}
+void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr,
+ size_t num_sg, int is_write)
+{
+ unsigned int i;
+ target_phys_addr_t len;
+
+ for (i = 0; i < num_sg; i++) {
+ len = sg[i].iov_len;
+ sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
+ if (sg[i].iov_base == NULL || len != sg[i].iov_len) {
+ fprintf(stderr, "virtio: trying to map MMIO memory\n");
+ exit(1);
+ }
+ }
+}
+
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
{
unsigned int i, head, max;
target_phys_addr_t desc_pa = vq->vring.desc;
- target_phys_addr_t len;
if (!virtqueue_num_heads(vq, vq->last_avail_idx))
return 0;
@@ -388,28 +407,19 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
i = 0;
}
+ /* Collect all the descriptors */
do {
struct iovec *sg;
- int is_write = 0;
if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
sg = &elem->in_sg[elem->in_num++];
- is_write = 1;
- } else
+ } else {
+ elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i);
sg = &elem->out_sg[elem->out_num++];
+ }
- /* Grab the first descriptor, and check it's OK. */
sg->iov_len = vring_desc_len(desc_pa, i);
- len = sg->iov_len;
-
- sg->iov_base = cpu_physical_memory_map(vring_desc_addr(desc_pa, i),
- &len, is_write);
-
- if (sg->iov_base == NULL || len != sg->iov_len) {
- fprintf(stderr, "virtio: trying to map MMIO memory\n");
- exit(1);
- }
/* If we've got too many, that implies a descriptor loop. */
if ((elem->in_num + elem->out_num) > max) {
@@ -418,10 +428,15 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
}
} while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
+ /* Now map what we have collected */
+ virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1);
+ virtqueue_map_sg(elem->out_sg, elem->out_addr, elem->out_num, 0);
+
elem->index = head;
vq->inuse++;
+ trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num);
return elem->in_num + elem->out_num;
}
@@ -443,6 +458,8 @@ void virtio_reset(void *opaque)
VirtIODevice *vdev = opaque;
int i;
+ virtio_set_status(vdev, 0);
+
if (vdev->reset)
vdev->reset(vdev);
@@ -560,6 +577,7 @@ int virtio_queue_get_num(VirtIODevice *vdev, int n)
void virtio_queue_notify(VirtIODevice *vdev, int n)
{
if (n < VIRTIO_PCI_QUEUE_MAX && vdev->vq[n].vring.desc) {
+ trace_virtio_queue_notify(vdev, n, &vdev->vq[n]);
vdev->vq[n].handle_output(vdev, &vdev->vq[n]);
}
}
@@ -597,6 +615,7 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
void virtio_irq(VirtQueue *vq)
{
+ trace_virtio_irq(vq);
vq->vdev->isr |= 0x01;
virtio_notify_vector(vq->vdev, vq->vector);
}
@@ -609,6 +628,7 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
(vq->inuse || vring_avail_idx(vq) != vq->last_avail_idx)))
return;
+ trace_virtio_notify(vdev, vq);
vdev->isr |= 0x01;
virtio_notify_vector(vdev, vq->vector);
}
@@ -661,6 +681,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
uint32_t features;
uint32_t supported_features =
vdev->binding->get_features(vdev->binding_opaque);
+ uint16_t num_heads;
if (vdev->binding->load_config) {
ret = vdev->binding->load_config(vdev->binding_opaque, f);
@@ -693,6 +714,16 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
if (vdev->vq[i].pa) {
virtqueue_init(&vdev->vq[i]);
}
+ num_heads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
+ /* Check it isn't doing very strange things with descriptor numbers. */
+ if (num_heads > vdev->vq[i].vring.num) {
+ fprintf(stderr, "VQ %d size 0x%x Guest index 0x%x "
+ "inconsistent with Host index 0x%x: delta 0x%x\n",
+ i, vdev->vq[i].vring.num,
+ vring_avail_idx(&vdev->vq[i]),
+ vdev->vq[i].last_avail_idx, num_heads);
+ return -1;
+ }
if (vdev->binding->load_queue) {
ret = vdev->binding->load_queue(vdev->binding_opaque, i, f);
if (ret)
diff --git a/hw/virtio.h b/hw/virtio.h
index e4306cd750..02fa312d3e 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -81,6 +81,7 @@ typedef struct VirtQueueElement
unsigned int out_num;
unsigned int in_num;
target_phys_addr_t in_addr[VIRTQUEUE_MAX_SIZE];
+ target_phys_addr_t out_addr[VIRTQUEUE_MAX_SIZE];
struct iovec in_sg[VIRTQUEUE_MAX_SIZE];
struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
} VirtQueueElement;
@@ -92,7 +93,7 @@ typedef struct {
int (*load_config)(void * opaque, QEMUFile *f);
int (*load_queue)(void * opaque, int n, QEMUFile *f);
unsigned (*get_features)(void * opaque);
- int (*set_guest_notifier)(void * opaque, int n, bool assigned);
+ int (*set_guest_notifiers)(void * opaque, bool assigned);
int (*set_host_notifier)(void * opaque, int n, bool assigned);
} VirtIOBindings;
@@ -142,6 +143,8 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count);
void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
unsigned int len, unsigned int idx);
+void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr,
+ size_t num_sg, int is_write);
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem);
int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes);
@@ -185,7 +188,9 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
/* Base devices. */
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf);
-VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf);
+struct virtio_net_conf;
+VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
+ struct virtio_net_conf *net);
VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports);
VirtIODevice *virtio_balloon_init(DeviceState *dev);
#ifdef CONFIG_LINUX
@@ -194,6 +199,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
void virtio_net_exit(VirtIODevice *vdev);
+void virtio_blk_exit(VirtIODevice *vdev);
+void virtio_serial_exit(VirtIODevice *vdev);
#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
DEFINE_PROP_BIT("indirect_desc", _state, _field, \
diff --git a/hw/vmmouse.c b/hw/vmmouse.c
index f3593047e7..209711942f 100644
--- a/hw/vmmouse.c
+++ b/hw/vmmouse.c
@@ -100,16 +100,29 @@ static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_
i8042_isa_mouse_fake_event(s->ps2_mouse);
}
-static void vmmouse_update_handler(VMMouseState *s)
+static void vmmouse_remove_handler(VMMouseState *s)
{
if (s->entry) {
qemu_remove_mouse_event_handler(s->entry);
s->entry = NULL;
}
- if (s->status == 0)
+}
+
+static void vmmouse_update_handler(VMMouseState *s, int absolute)
+{
+ if (s->status != 0) {
+ return;
+ }
+ if (s->absolute != absolute) {
+ s->absolute = absolute;
+ vmmouse_remove_handler(s);
+ }
+ if (s->entry == NULL) {
s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event,
s, s->absolute,
"vmmouse");
+ qemu_activate_mouse_event_handler(s->entry);
+ }
}
static void vmmouse_read_id(VMMouseState *s)
@@ -121,28 +134,25 @@ static void vmmouse_read_id(VMMouseState *s)
s->queue[s->nb_queue++] = VMMOUSE_VERSION;
s->status = 0;
- vmmouse_update_handler(s);
}
static void vmmouse_request_relative(VMMouseState *s)
{
DPRINTF("vmmouse_request_relative()\n");
- s->absolute = 0;
- vmmouse_update_handler(s);
+ vmmouse_update_handler(s, 0);
}
static void vmmouse_request_absolute(VMMouseState *s)
{
DPRINTF("vmmouse_request_absolute()\n");
- s->absolute = 1;
- vmmouse_update_handler(s);
+ vmmouse_update_handler(s, 1);
}
static void vmmouse_disable(VMMouseState *s)
{
DPRINTF("vmmouse_disable()\n");
s->status = 0xffff;
- vmmouse_update_handler(s);
+ vmmouse_remove_handler(s);
}
static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
@@ -154,7 +164,7 @@ static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
if (size == 0 || size > 6 || size > s->nb_queue) {
printf("vmmouse: driver requested too much data %d\n", size);
s->status = 0xffff;
- vmmouse_update_handler(s);
+ vmmouse_remove_handler(s);
return;
}
@@ -239,7 +249,8 @@ static int vmmouse_post_load(void *opaque, int version_id)
{
VMMouseState *s = opaque;
- vmmouse_update_handler(s);
+ vmmouse_remove_handler(s);
+ vmmouse_update_handler(s, s->absolute);
return 0;
}
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 12bff480eb..3d25c14da9 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -519,11 +519,15 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
#define CMD(f) le32_to_cpu(s->cmd->f)
-static inline int vmsvga_fifo_empty(struct vmsvga_state_s *s)
+static inline int vmsvga_fifo_length(struct vmsvga_state_s *s)
{
+ int num;
if (!s->config || !s->enable)
- return 1;
- return (s->cmd->next_cmd == s->cmd->stop);
+ return 0;
+ num = CMD(next_cmd) - CMD(stop);
+ if (num < 0)
+ num += CMD(max) - CMD(min);
+ return num >> 2;
}
static inline uint32_t vmsvga_fifo_read_raw(struct vmsvga_state_s *s)
@@ -543,13 +547,23 @@ static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s)
static void vmsvga_fifo_run(struct vmsvga_state_s *s)
{
uint32_t cmd, colour;
- int args = 0;
+ int args, len;
int x, y, dx, dy, width, height;
struct vmsvga_cursor_definition_s cursor;
- while (!vmsvga_fifo_empty(s))
+ uint32_t cmd_start;
+
+ len = vmsvga_fifo_length(s);
+ while (len > 0) {
+ /* May need to go back to the start of the command if incomplete */
+ cmd_start = s->cmd->stop;
+
switch (cmd = vmsvga_fifo_read(s)) {
case SVGA_CMD_UPDATE:
case SVGA_CMD_UPDATE_VERBOSE:
+ len -= 5;
+ if (len < 0)
+ goto rewind;
+
x = vmsvga_fifo_read(s);
y = vmsvga_fifo_read(s);
width = vmsvga_fifo_read(s);
@@ -558,6 +572,10 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
break;
case SVGA_CMD_RECT_FILL:
+ len -= 6;
+ if (len < 0)
+ goto rewind;
+
colour = vmsvga_fifo_read(s);
x = vmsvga_fifo_read(s);
y = vmsvga_fifo_read(s);
@@ -567,10 +585,15 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
vmsvga_fill_rect(s, colour, x, y, width, height);
break;
#else
+ args = 0;
goto badcmd;
#endif
case SVGA_CMD_RECT_COPY:
+ len -= 7;
+ if (len < 0)
+ goto rewind;
+
x = vmsvga_fifo_read(s);
y = vmsvga_fifo_read(s);
dx = vmsvga_fifo_read(s);
@@ -581,10 +604,15 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
vmsvga_copy_rect(s, x, y, dx, dy, width, height);
break;
#else
+ args = 0;
goto badcmd;
#endif
case SVGA_CMD_DEFINE_CURSOR:
+ len -= 8;
+ if (len < 0)
+ goto rewind;
+
cursor.id = vmsvga_fifo_read(s);
cursor.hot_x = vmsvga_fifo_read(s);
cursor.hot_y = vmsvga_fifo_read(s);
@@ -593,11 +621,14 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
vmsvga_fifo_read(s);
cursor.bpp = vmsvga_fifo_read(s);
- if (SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask ||
- SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image) {
- args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp);
- goto badcmd;
- }
+ args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp);
+ if (SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask ||
+ SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image)
+ goto badcmd;
+
+ len -= args;
+ if (len < 0)
+ goto rewind;
for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args ++)
cursor.mask[args] = vmsvga_fifo_read_raw(s);
@@ -616,6 +647,10 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
* for so we can avoid FIFO desync if driver uses them illegally.
*/
case SVGA_CMD_DEFINE_ALPHA_CURSOR:
+ len -= 6;
+ if (len < 0)
+ goto rewind;
+
vmsvga_fifo_read(s);
vmsvga_fifo_read(s);
vmsvga_fifo_read(s);
@@ -630,6 +665,10 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
args = 7;
goto badcmd;
case SVGA_CMD_DRAW_GLYPH_CLIPPED:
+ len -= 4;
+ if (len < 0)
+ goto rewind;
+
vmsvga_fifo_read(s);
vmsvga_fifo_read(s);
args = 7 + (vmsvga_fifo_read(s) >> 2);
@@ -650,13 +689,22 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
break; /* Nop */
default:
+ args = 0;
badcmd:
+ len -= args;
+ if (len < 0)
+ goto rewind;
while (args --)
vmsvga_fifo_read(s);
printf("%s: Unknown command 0x%02x in SVGA command FIFO\n",
__FUNCTION__, cmd);
break;
+
+ rewind:
+ s->cmd->stop = cmd_start;
+ break;
}
+ }
s->syncing = 0;
}
@@ -809,11 +857,11 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
s->invalidated = 1;
s->vga.invalidate(&s->vga);
if (s->enable) {
- s->fb_size = ((s->depth + 7) >> 3) * s->new_width * s->new_height;
- vga_dirty_log_stop(&s->vga);
- } else {
- vga_dirty_log_start(&s->vga);
- }
+ s->fb_size = ((s->depth + 7) >> 3) * s->new_width * s->new_height;
+ vga_dirty_log_stop(&s->vga);
+ } else {
+ vga_dirty_log_start(&s->vga);
+ }
break;
case SVGA_REG_WIDTH:
@@ -1255,7 +1303,7 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_mem);
pci_register_bar(&s->card, 2, SVGA_FIFO_SIZE,
- PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_fifo);
+ PCI_BASE_ADDRESS_MEM_PREFETCH, pci_vmsvga_map_fifo);
vmsvga_init(&s->chip, VGA_RAM_SIZE);
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index a0c5747b59..cacc21767b 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -468,7 +468,6 @@ static int vt82c686b_pm_initfn(PCIDevice *dev)
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_ACPI);
pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
pci_config_set_revision(pci_conf, 0x40);
- pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
pci_set_word(pci_conf + PCI_COMMAND, 0);
pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
@@ -556,8 +555,6 @@ static int vt82c686b_initfn(PCIDevice *d)
pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
pci_config_set_prog_interface(pci_conf, 0x0);
pci_config_set_revision(pci_conf,0x40); /* Revision 4.0 */
- pci_conf[PCI_HEADER_TYPE] =
- PCI_HEADER_TYPE_NORMAL | PCI_HEADER_TYPE_MULTI_FUNCTION;
wmask = d->wmask;
for (i = 0x00; i < 0xff; i++) {
@@ -575,7 +572,7 @@ int vt82c686b_init(PCIBus *bus, int devfn)
{
PCIDevice *d;
- d = pci_create_simple(bus, devfn, "VT82C686B");
+ d = pci_create_simple_multifunction(bus, devfn, true, "VT82C686B");
return d->devfn;
}
diff --git a/hw/watchdog.c b/hw/watchdog.c
index aebb08a0ee..e9dd56e229 100644
--- a/hw/watchdog.c
+++ b/hw/watchdog.c
@@ -66,7 +66,7 @@ int select_watchdog(const char *p)
QLIST_FOREACH(model, &watchdog_list, entry) {
if (strcasecmp(model->wdt_name, p) == 0) {
/* add the device */
- opts = qemu_opts_create(&qemu_device_opts, NULL, 0);
+ opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
qemu_opt_set(opts, "driver", p);
return 0;
}
diff --git a/hw/wm8750.c b/hw/wm8750.c
index ce43c234ac..c9c674451b 100644
--- a/hw/wm8750.c
+++ b/hw/wm8750.c
@@ -171,7 +171,6 @@ static void wm8750_set_format(WM8750State *s)
int i;
struct audsettings in_fmt;
struct audsettings out_fmt;
- struct audsettings monoout_fmt;
wm8750_out_flush(s);
@@ -212,10 +211,6 @@ static void wm8750_set_format(WM8750State *s)
out_fmt.nchannels = 2;
out_fmt.freq = s->dac_hz;
out_fmt.fmt = AUD_FMT_S16;
- monoout_fmt.endianness = 0;
- monoout_fmt.nchannels = 1;
- monoout_fmt.freq = s->rate->dac_hz;
- monoout_fmt.fmt = AUD_FMT_S16;
s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
index cc25f9d7db..1b428e3bf4 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -4,8 +4,6 @@
#include "xen_common.h"
#include "sysemu.h"
#include "net.h"
-#include "block_int.h"
-#include "blockdev.h"
/* ------------------------------------------------------------- */
@@ -86,7 +84,7 @@ int xen_be_bind_evtchn(struct XenDevice *xendev);
void xen_be_unbind_evtchn(struct XenDevice *xendev);
int xen_be_send_notify(struct XenDevice *xendev);
void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
- __attribute__ ((format(printf, 3, 4)));
+ GCC_FMT_ATTR(3, 4);
/* actual backend drivers */
extern struct XenDevOps xen_console_ops; /* xen_console.c */
diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c
index ea8f8c4c2d..8d50216c04 100644
--- a/hw/xen_devconfig.c
+++ b/hw/xen_devconfig.c
@@ -1,4 +1,6 @@
#include "xen_backend.h"
+#include "blockdev.h"
+#include "block_int.h" /* XXX */
/* ------------------------------------------------------------- */
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 9a466f3cc1..134ac3388e 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -41,6 +41,7 @@
#include "qemu-char.h"
#include "xen_blkif.h"
#include "xen_backend.h"
+#include "blockdev.h"
/* ------------------------------------------------------------- */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 586214d8ba..77a34bf111 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -28,6 +28,7 @@
#include "boards.h"
#include "xen_backend.h"
#include "xen_domainbuild.h"
+#include "blockdev.h"
static void xen_init_pv(ram_addr_t ram_size,
const char *boot_device,