x86 and SCSI fixes. I left out the APIC device model

patches, pending confirmation from the submitter that they really
 fix QNX.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQEcBAABAgAGBQJUZMqiAAoJEL/70l94x66DQEEH/3kWZSwiC6yh5icRmLd1PX9Q
 P8a5qIGQUldN54orlr4bDs4Slb6w4CVwwupT6AIFvNbZDFQVlJTMd+3ssZ03H++D
 eJ9WvY3yVmrC1ofFk1WNIposk01gvM0U74Kns4ttEuJ7UyB75mhPEegQd3B8WbPa
 /eJILlXu9ayxj60yEqmoR8IfqrkuuTHx7P4QmpJigGeLkBhQOq0TXjb1xi+4JPnv
 BHjVjA6YNtzuMO2wP0y6KE/9HZpow0luAb+vB0NkY0NoEezVucoDWLMMUkpSiZI/
 yYFEqp4lzRo2ygnJXlGvLFND6F2qacGIIU5lj5t8a2BmswqD83JEt/idQGYeIzM=
 =ExeA
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging

x86 and SCSI fixes.  I left out the APIC device model
patches, pending confirmation from the submitter that they really
fix QNX.

# gpg: Signature made Thu 13 Nov 2014 15:13:38 GMT using RSA key ID 78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>"
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* remotes/bonzini/tags/for-upstream:
  acpi: accurate overflow check
  smbios: change 'ram_addr_t' variables to 'uint64_t'
  kvmclock: Add comment explaining why we need cpu_clean_all_dirty()
  target-i386: fix Coverity complaints about overflows
  apic_common: migrate missing fields
  target-i386: eliminate dead code and hoist common code out of "if"
  virtio-scsi: Fix comment for VirtIOSCSIReq
  virtio-scsi: dataplane: suppress guest notification
  esp: Do not overwrite ESP_TCHI after reset
  virtio-scsi: dataplane: fix allocation for 'cmd_vrings'
  esp: fix coding standards
  virtio-scsi: work around bug in old BIOSes
  esp-pci: fixup deadlock with linux

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2014-11-13 15:44:16 +00:00
commit c52e67924f
13 changed files with 109 additions and 26 deletions

View File

@ -376,8 +376,11 @@ static void acpi_notify_wakeup(Notifier *notifier, void *data)
/* ACPI PM1a EVT */ /* ACPI PM1a EVT */
uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar) uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar)
{ {
int64_t d = acpi_pm_tmr_get_clock(); /* Compare ns-clock, not PM timer ticks, because
if (d >= ar->tmr.overflow_time) { acpi_pm_tmr_update function uses ns for setting the timer. */
int64_t d = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
if (d >= muldiv64(ar->tmr.overflow_time,
get_ticks_per_sec(), PM_TIMER_FREQUENCY)) {
ar->pm1.evt.sts |= ACPI_BITMASK_TIMER_STATUS; ar->pm1.evt.sts |= ACPI_BITMASK_TIMER_STATUS;
} }
return ar->pm1.evt.sts; return ar->pm1.evt.sts;

View File

@ -175,6 +175,9 @@ static void kvm_apic_realize(DeviceState *dev, Error **errp)
{ {
APICCommonState *s = APIC_COMMON(dev); APICCommonState *s = APIC_COMMON(dev);
/* Not used by KVM, which uses the CPU mp_state instead. */
s->wait_for_sipi = 0;
memory_region_init_io(&s->io_memory, NULL, &kvm_apic_io_ops, s, "kvm-apic-msi", memory_region_init_io(&s->io_memory, NULL, &kvm_apic_io_ops, s, "kvm-apic-msi",
APIC_SPACE_SIZE); APIC_SPACE_SIZE);

View File

@ -127,7 +127,21 @@ static void kvmclock_vm_state_change(void *opaque, int running,
} }
cpu_synchronize_all_states(); cpu_synchronize_all_states();
/* In theory, the cpu_synchronize_all_states() call above wouldn't
* affect the rest of the code, as the VCPU state inside CPUState
* is supposed to always match the VCPU state on the kernel side.
*
* In practice, calling cpu_synchronize_state() too soon will load the
* kernel-side APIC state into X86CPU.apic_state too early, APIC state
* won't be reloaded later because CPUState.vcpu_dirty==true, and
* outdated APIC state may be migrated to another host.
*
* The real fix would be to make sure outdated APIC state is read
* from the kernel again when necessary. While this is not fixed, we
* need the cpu_clean_all_dirty() call below.
*/
cpu_clean_all_dirty(); cpu_clean_all_dirty();
ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data); ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret)); fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));

View File

@ -645,7 +645,7 @@ static void smbios_build_type_4_table(unsigned instance)
static void smbios_build_type_16_table(unsigned dimm_cnt) static void smbios_build_type_16_table(unsigned dimm_cnt)
{ {
ram_addr_t size_kb; uint64_t size_kb;
SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */ SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */
@ -669,10 +669,10 @@ static void smbios_build_type_16_table(unsigned dimm_cnt)
#define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */ #define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */
#define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */ #define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */
static void smbios_build_type_17_table(unsigned instance, ram_addr_t size) static void smbios_build_type_17_table(unsigned instance, uint64_t size)
{ {
char loc_str[128]; char loc_str[128];
ram_addr_t size_mb; uint64_t size_mb;
SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */ SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */
@ -711,9 +711,9 @@ static void smbios_build_type_17_table(unsigned instance, ram_addr_t size)
} }
static void smbios_build_type_19_table(unsigned instance, static void smbios_build_type_19_table(unsigned instance,
ram_addr_t start, ram_addr_t size) uint64_t start, uint64_t size)
{ {
ram_addr_t end, start_kb, end_kb; uint64_t end, start_kb, end_kb;
SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */ SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */

View File

@ -324,6 +324,19 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
} }
static int apic_pre_load(void *opaque)
{
APICCommonState *s = APIC_COMMON(opaque);
/* The default is !cpu_is_bsp(s->cpu), but the common value is 0
* so that's what apic_common_sipi_needed checks for. Reset to
* the value that is assumed when the apic_sipi subsection is
* absent.
*/
s->wait_for_sipi = 0;
return 0;
}
static void apic_dispatch_pre_save(void *opaque) static void apic_dispatch_pre_save(void *opaque)
{ {
APICCommonState *s = APIC_COMMON(opaque); APICCommonState *s = APIC_COMMON(opaque);
@ -345,12 +358,30 @@ static int apic_dispatch_post_load(void *opaque, int version_id)
return 0; return 0;
} }
static bool apic_common_sipi_needed(void *opaque)
{
APICCommonState *s = APIC_COMMON(opaque);
return s->wait_for_sipi != 0;
}
static const VMStateDescription vmstate_apic_common_sipi = {
.name = "apic_sipi",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_INT32(sipi_vector, APICCommonState),
VMSTATE_INT32(wait_for_sipi, APICCommonState),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_apic_common = { static const VMStateDescription vmstate_apic_common = {
.name = "apic", .name = "apic",
.version_id = 3, .version_id = 3,
.minimum_version_id = 3, .minimum_version_id = 3,
.minimum_version_id_old = 1, .minimum_version_id_old = 1,
.load_state_old = apic_load_old, .load_state_old = apic_load_old,
.pre_load = apic_pre_load,
.pre_save = apic_dispatch_pre_save, .pre_save = apic_dispatch_pre_save,
.post_load = apic_dispatch_post_load, .post_load = apic_dispatch_post_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
@ -375,6 +406,13 @@ static const VMStateDescription vmstate_apic_common = {
VMSTATE_INT64(timer_expiry, VMSTATE_INT64(timer_expiry,
APICCommonState), /* open-coded timer state */ APICCommonState), /* open-coded timer state */
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_apic_common_sipi,
.needed = apic_common_sipi_needed,
},
VMSTATE_END_OF_LIST()
} }
}; };

View File

@ -268,6 +268,9 @@ static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
/* update status registers */ /* update status registers */
pci->dma_regs[DMA_WBC] -= len; pci->dma_regs[DMA_WBC] -= len;
pci->dma_regs[DMA_WAC] += len; pci->dma_regs[DMA_WAC] += len;
if (pci->dma_regs[DMA_WBC] == 0) {
pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
}
} }
static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len) static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len)

View File

@ -364,7 +364,7 @@ void esp_hard_reset(ESPState *s)
{ {
memset(s->rregs, 0, ESP_REGS); memset(s->rregs, 0, ESP_REGS);
memset(s->wregs, 0, ESP_REGS); memset(s->wregs, 0, ESP_REGS);
s->rregs[ESP_TCHI] = s->chip_id; s->tchi_written = 0;
s->ti_size = 0; s->ti_size = 0;
s->ti_rptr = 0; s->ti_rptr = 0;
s->ti_wptr = 0; s->ti_wptr = 0;
@ -422,6 +422,11 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
esp_lower_irq(s); esp_lower_irq(s);
return old_val; return old_val;
case ESP_TCHI:
/* Return the unique id if the value has never been written */
if (!s->tchi_written) {
return s->chip_id;
}
default: default:
break; break;
} }
@ -432,9 +437,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
{ {
trace_esp_mem_writeb(saddr, s->wregs[saddr], val); trace_esp_mem_writeb(saddr, s->wregs[saddr], val);
switch (saddr) { switch (saddr) {
case ESP_TCHI:
s->tchi_written = true;
/* fall through */
case ESP_TCLO: case ESP_TCLO:
case ESP_TCMID: case ESP_TCMID:
case ESP_TCHI:
s->rregs[ESP_RSTAT] &= ~STAT_TC; s->rregs[ESP_RSTAT] &= ~STAT_TC;
break; break;
case ESP_FIFO: case ESP_FIFO:

View File

@ -92,9 +92,14 @@ VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s,
void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req) void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(req->vring->parent);
vring_push(&req->vring->vring, &req->elem, vring_push(&req->vring->vring, &req->elem,
req->qsgl.size + req->resp_iov.size); req->qsgl.size + req->resp_iov.size);
event_notifier_set(&req->vring->guest_notifier);
if (vring_should_notify(vdev, &req->vring->vring)) {
event_notifier_set(&req->vring->guest_notifier);
}
} }
static void virtio_scsi_iothread_handle_ctrl(EventNotifier *notifier) static void virtio_scsi_iothread_handle_ctrl(EventNotifier *notifier)
@ -230,7 +235,7 @@ void virtio_scsi_dataplane_start(VirtIOSCSI *s)
if (!s->event_vring) { if (!s->event_vring) {
goto fail_vrings; goto fail_vrings;
} }
s->cmd_vrings = g_malloc0(sizeof(VirtIOSCSIVring) * vs->conf.num_queues); s->cmd_vrings = g_new(VirtIOSCSIVring *, vs->conf.num_queues);
for (i = 0; i < vs->conf.num_queues; i++) { for (i = 0; i < vs->conf.num_queues; i++) {
s->cmd_vrings[i] = s->cmd_vrings[i] =
virtio_scsi_vring_init(s, vs->cmd_vqs[i], virtio_scsi_vring_init(s, vs->cmd_vqs[i],

View File

@ -118,6 +118,7 @@ static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov,
static int virtio_scsi_parse_req(VirtIOSCSIReq *req, static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
unsigned req_size, unsigned resp_size) unsigned req_size, unsigned resp_size)
{ {
VirtIODevice *vdev = (VirtIODevice *) req->dev;
size_t in_size, out_size; size_t in_size, out_size;
if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
@ -130,8 +131,24 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
resp_size) < resp_size) { resp_size) < resp_size) {
return -EINVAL; return -EINVAL;
} }
req->resp_size = resp_size; req->resp_size = resp_size;
/* Old BIOSes left some padding by mistake after the req_size/resp_size.
* As a workaround, always consider the first buffer as the virtio-scsi
* request/response, making the payload start at the second element
* of the iovec.
*
* The actual length of the response header, stored in req->resp_size,
* does not change.
*
* TODO: always disable this workaround for virtio 1.0 devices.
*/
if ((vdev->guest_features & VIRTIO_F_ANY_LAYOUT) == 0) {
req_size = req->elem.out_sg[0].iov_len;
resp_size = req->elem.in_sg[0].iov_len;
}
out_size = qemu_sgl_concat(req, req->elem.out_sg, out_size = qemu_sgl_concat(req, req->elem.out_sg,
&req->elem.out_addr[0], req->elem.out_num, &req->elem.out_addr[0], req->elem.out_num,
req_size); req_size);

View File

@ -22,6 +22,7 @@ struct ESPState {
uint8_t wregs[ESP_REGS]; uint8_t wregs[ESP_REGS];
qemu_irq irq; qemu_irq irq;
uint8_t chip_id; uint8_t chip_id;
bool tchi_written;
int32_t ti_size; int32_t ti_size;
uint32_t ti_rptr, ti_wptr; uint32_t ti_rptr, ti_wptr;
uint32_t status; uint32_t status;

View File

@ -209,7 +209,8 @@ typedef struct VirtIOSCSIReq {
/* Note: /* Note:
* - fields before elem are initialized by virtio_scsi_init_req; * - fields before elem are initialized by virtio_scsi_init_req;
* - elem is uninitialized at the time of allocation. * - elem is uninitialized at the time of allocation.
* - fields after elem are zeroed by virtio_scsi_init_req. * - fields after elem (except the ending cdb[]) are zeroed by
* virtio_scsi_init_req.
* */ * */
VirtQueueElement elem; VirtQueueElement elem;

View File

@ -1104,7 +1104,7 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env,
} }
static inline void cpu_x86_load_seg_cache_sipi(X86CPU *cpu, static inline void cpu_x86_load_seg_cache_sipi(X86CPU *cpu,
int sipi_vector) uint8_t sipi_vector)
{ {
CPUState *cs = CPU(cpu); CPUState *cs = CPU(cpu);
CPUX86State *env = &cpu->env; CPUX86State *env = &cpu->env;

View File

@ -883,32 +883,23 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int,
} }
if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) { if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
/* to inner privilege */ /* to inner privilege */
if (ist != 0) {
esp = get_rsp_from_tss(env, ist + 3);
} else {
esp = get_rsp_from_tss(env, dpl);
}
esp &= ~0xfLL; /* align stack */
ss = 0;
new_stack = 1; new_stack = 1;
esp = get_rsp_from_tss(env, ist != 0 ? ist + 3 : dpl);
ss = 0;
} else if ((e2 & DESC_C_MASK) || dpl == cpl) { } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
/* to same privilege */ /* to same privilege */
if (env->eflags & VM_MASK) { if (env->eflags & VM_MASK) {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc);
} }
new_stack = 0; new_stack = 0;
if (ist != 0) { esp = env->regs[R_ESP];
esp = get_rsp_from_tss(env, ist + 3);
} else {
esp = env->regs[R_ESP];
}
esp &= ~0xfLL; /* align stack */
dpl = cpl; dpl = cpl;
} else { } else {
raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc); raise_exception_err(env, EXCP0D_GPF, selector & 0xfffc);
new_stack = 0; /* avoid warning */ new_stack = 0; /* avoid warning */
esp = 0; /* avoid warning */ esp = 0; /* avoid warning */
} }
esp &= ~0xfLL; /* align stack */
PUSHQ(esp, env->segs[R_SS].selector); PUSHQ(esp, env->segs[R_SS].selector);
PUSHQ(esp, env->regs[R_ESP]); PUSHQ(esp, env->regs[R_ESP]);