2009-03-12 20:25:12 +00:00
|
|
|
/*
|
|
|
|
* ioapic.c IOAPIC emulation logic
|
|
|
|
*
|
|
|
|
* Copyright (c) 2004-2005 Fabrice Bellard
|
|
|
|
*
|
|
|
|
* Split the ioapic logic from apic.c
|
|
|
|
* Xiantao Zhang <xiantao.zhang@intel.com>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
2020-10-23 12:44:24 +00:00
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2009-03-12 20:25:12 +00:00
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2009-07-16 20:47:01 +00:00
|
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
2009-03-12 20:25:12 +00:00
|
|
|
*/
|
|
|
|
|
2016-01-26 18:17:03 +00:00
|
|
|
#include "qemu/osdep.h"
|
2018-10-17 08:26:34 +00:00
|
|
|
#include "qapi/error.h"
|
2015-09-22 13:18:21 +00:00
|
|
|
#include "monitor/monitor.h"
|
2015-12-04 10:04:13 +00:00
|
|
|
#include "hw/i386/apic.h"
|
2013-02-05 16:06:20 +00:00
|
|
|
#include "hw/i386/ioapic.h"
|
|
|
|
#include "hw/i386/ioapic_internal.h"
|
2019-12-12 16:15:43 +00:00
|
|
|
#include "hw/i386/x86.h"
|
|
|
|
#include "hw/intc/i8259.h"
|
2018-05-03 19:50:32 +00:00
|
|
|
#include "hw/pci/msi.h"
|
2019-08-12 05:23:51 +00:00
|
|
|
#include "hw/qdev-properties.h"
|
2015-12-17 16:16:08 +00:00
|
|
|
#include "sysemu/kvm.h"
|
2019-08-12 05:23:57 +00:00
|
|
|
#include "sysemu/sysemu.h"
|
2016-07-14 05:56:23 +00:00
|
|
|
#include "hw/i386/apic-msidef.h"
|
2016-07-14 05:56:27 +00:00
|
|
|
#include "hw/i386/x86-iommu.h"
|
2017-01-09 08:55:51 +00:00
|
|
|
#include "trace.h"
|
2009-03-12 20:25:12 +00:00
|
|
|
|
2015-12-17 16:16:08 +00:00
|
|
|
#define APIC_DELIVERY_MODE_SHIFT 8
|
|
|
|
#define APIC_POLARITY_SHIFT 14
|
|
|
|
#define APIC_TRIG_MODE_SHIFT 15
|
|
|
|
|
2011-10-16 17:38:22 +00:00
|
|
|
static IOAPICCommonState *ioapics[MAX_IOAPICS];
|
2011-02-03 21:54:11 +00:00
|
|
|
|
2013-11-05 10:16:05 +00:00
|
|
|
/* global variable from ioapic_common.c */
|
|
|
|
extern int ioapic_no;
|
|
|
|
|
2016-07-14 05:56:24 +00:00
|
|
|
struct ioapic_entry_info {
|
|
|
|
/* fields parsed from IOAPIC entries */
|
|
|
|
uint8_t masked;
|
|
|
|
uint8_t trig_mode;
|
|
|
|
uint16_t dest_idx;
|
|
|
|
uint8_t dest_mode;
|
|
|
|
uint8_t delivery_mode;
|
|
|
|
uint8_t vector;
|
|
|
|
|
|
|
|
/* MSI message generated from above parsed fields */
|
|
|
|
uint32_t addr;
|
|
|
|
uint32_t data;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void ioapic_entry_parse(uint64_t entry, struct ioapic_entry_info *info)
|
|
|
|
{
|
|
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
info->masked = (entry >> IOAPIC_LVT_MASKED_SHIFT) & 1;
|
|
|
|
info->trig_mode = (entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1;
|
|
|
|
/*
|
|
|
|
* By default, this would be dest_id[8] + reserved[8]. When IR
|
|
|
|
* is enabled, this would be interrupt_index[15] +
|
|
|
|
* interrupt_format[1]. This field never means anything, but
|
|
|
|
* only used to generate corresponding MSI.
|
|
|
|
*/
|
|
|
|
info->dest_idx = (entry >> IOAPIC_LVT_DEST_IDX_SHIFT) & 0xffff;
|
|
|
|
info->dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
|
|
|
|
info->delivery_mode = (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) \
|
|
|
|
& IOAPIC_DM_MASK;
|
|
|
|
if (info->delivery_mode == IOAPIC_DM_EXTINT) {
|
|
|
|
info->vector = pic_read_irq(isa_pic);
|
|
|
|
} else {
|
|
|
|
info->vector = entry & IOAPIC_VECTOR_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
info->addr = APIC_DEFAULT_ADDRESS | \
|
|
|
|
(info->dest_idx << MSI_ADDR_DEST_IDX_SHIFT) | \
|
|
|
|
(info->dest_mode << MSI_ADDR_DEST_MODE_SHIFT);
|
|
|
|
info->data = (info->vector << MSI_DATA_VECTOR_SHIFT) | \
|
|
|
|
(info->trig_mode << MSI_DATA_TRIGGER_SHIFT) | \
|
|
|
|
(info->delivery_mode << MSI_DATA_DELIVERY_MODE_SHIFT);
|
|
|
|
}
|
|
|
|
|
2011-10-16 17:38:22 +00:00
|
|
|
static void ioapic_service(IOAPICCommonState *s)
|
2009-03-12 20:25:12 +00:00
|
|
|
{
|
2019-10-22 07:39:50 +00:00
|
|
|
AddressSpace *ioapic_as = X86_MACHINE(qdev_get_machine())->ioapic_as;
|
2016-07-14 05:56:24 +00:00
|
|
|
struct ioapic_entry_info info;
|
2009-03-12 20:25:12 +00:00
|
|
|
uint8_t i;
|
|
|
|
uint32_t mask;
|
|
|
|
uint64_t entry;
|
|
|
|
|
|
|
|
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
|
|
|
|
mask = 1 << i;
|
|
|
|
if (s->irr & mask) {
|
2015-12-17 16:16:08 +00:00
|
|
|
int coalesce = 0;
|
|
|
|
|
2009-03-12 20:25:12 +00:00
|
|
|
entry = s->ioredtbl[i];
|
2016-07-14 05:56:24 +00:00
|
|
|
ioapic_entry_parse(entry, &info);
|
|
|
|
if (!info.masked) {
|
|
|
|
if (info.trig_mode == IOAPIC_TRIGGER_EDGE) {
|
2009-03-12 20:25:12 +00:00
|
|
|
s->irr &= ~mask;
|
2011-02-03 21:54:11 +00:00
|
|
|
} else {
|
2015-12-17 16:16:08 +00:00
|
|
|
coalesce = s->ioredtbl[i] & IOAPIC_LVT_REMOTE_IRR;
|
2017-01-09 08:55:51 +00:00
|
|
|
trace_ioapic_set_remote_irr(i);
|
2011-02-03 21:54:11 +00:00
|
|
|
s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
|
|
|
|
}
|
2016-07-14 05:56:24 +00:00
|
|
|
|
2016-07-31 14:18:05 +00:00
|
|
|
if (coalesce) {
|
|
|
|
/* We are level triggered interrupts, and the
|
|
|
|
* guest should be still working on previous one,
|
|
|
|
* so skip it. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-12-17 16:16:08 +00:00
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
if (kvm_irqchip_is_split()) {
|
2016-07-14 05:56:24 +00:00
|
|
|
if (info.trig_mode == IOAPIC_TRIGGER_EDGE) {
|
2015-12-17 16:16:08 +00:00
|
|
|
kvm_set_irq(kvm_state, i, 1);
|
|
|
|
kvm_set_irq(kvm_state, i, 0);
|
|
|
|
} else {
|
2016-07-31 14:18:05 +00:00
|
|
|
kvm_set_irq(kvm_state, i, 1);
|
2015-12-17 16:16:08 +00:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
2016-07-31 14:18:05 +00:00
|
|
|
|
2016-07-14 05:56:23 +00:00
|
|
|
/* No matter whether IR is enabled, we translate
|
|
|
|
* the IOAPIC message into a MSI one, and its
|
|
|
|
* address space will decide whether we need a
|
|
|
|
* translation. */
|
2016-07-14 05:56:24 +00:00
|
|
|
stl_le_phys(ioapic_as, info.addr, info.data);
|
2009-03-12 20:25:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-02 08:02:15 +00:00
|
|
|
#define SUCCESSIVE_IRQ_MAX_COUNT 10000
|
|
|
|
|
|
|
|
static void delayed_ioapic_service_cb(void *opaque)
|
|
|
|
{
|
|
|
|
IOAPICCommonState *s = opaque;
|
|
|
|
|
|
|
|
ioapic_service(s);
|
|
|
|
}
|
|
|
|
|
2010-06-17 16:32:47 +00:00
|
|
|
static void ioapic_set_irq(void *opaque, int vector, int level)
|
2009-03-12 20:25:12 +00:00
|
|
|
{
|
2011-10-16 17:38:22 +00:00
|
|
|
IOAPICCommonState *s = opaque;
|
2009-03-12 20:25:12 +00:00
|
|
|
|
|
|
|
/* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
|
|
|
|
* to GSI 2. GSI maps to ioapic 1-1. This is not
|
|
|
|
* the cleanest way of doing it but it should work. */
|
|
|
|
|
2017-11-02 18:03:10 +00:00
|
|
|
trace_ioapic_set_irq(vector, level);
|
2017-12-29 07:31:03 +00:00
|
|
|
ioapic_stat_update_irq(s, vector, level);
|
2011-02-03 21:54:14 +00:00
|
|
|
if (vector == 0) {
|
2009-03-12 20:25:12 +00:00
|
|
|
vector = 2;
|
2011-02-03 21:54:14 +00:00
|
|
|
}
|
2018-07-04 12:03:10 +00:00
|
|
|
if (vector < IOAPIC_NUM_PINS) {
|
2009-03-12 20:25:12 +00:00
|
|
|
uint32_t mask = 1 << vector;
|
|
|
|
uint64_t entry = s->ioredtbl[vector];
|
|
|
|
|
2011-02-03 21:54:14 +00:00
|
|
|
if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
|
|
|
|
IOAPIC_TRIGGER_LEVEL) {
|
2009-03-12 20:25:12 +00:00
|
|
|
/* level triggered */
|
|
|
|
if (level) {
|
|
|
|
s->irr |= mask;
|
2015-07-30 08:19:24 +00:00
|
|
|
if (!(entry & IOAPIC_LVT_REMOTE_IRR)) {
|
|
|
|
ioapic_service(s);
|
|
|
|
}
|
2009-03-12 20:25:12 +00:00
|
|
|
} else {
|
|
|
|
s->irr &= ~mask;
|
|
|
|
}
|
|
|
|
} else {
|
2011-04-09 11:18:59 +00:00
|
|
|
/* According to the 82093AA manual, we must ignore edge requests
|
|
|
|
* if the input pin is masked. */
|
|
|
|
if (level && !(entry & IOAPIC_LVT_MASKED)) {
|
2009-03-12 20:25:12 +00:00
|
|
|
s->irr |= mask;
|
|
|
|
ioapic_service(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-17 16:16:08 +00:00
|
|
|
static void ioapic_update_kvm_routes(IOAPICCommonState *s)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (kvm_irqchip_is_split()) {
|
|
|
|
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
|
|
|
|
MSIMessage msg;
|
2016-07-14 05:56:24 +00:00
|
|
|
struct ioapic_entry_info info;
|
|
|
|
ioapic_entry_parse(s->ioredtbl[i], &info);
|
2019-06-02 11:42:13 +00:00
|
|
|
if (!info.masked) {
|
|
|
|
msg.address = info.addr;
|
|
|
|
msg.data = info.data;
|
|
|
|
kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL);
|
|
|
|
}
|
2015-12-17 16:16:08 +00:00
|
|
|
}
|
|
|
|
kvm_irqchip_commit_routes(kvm_state);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-07-14 05:56:27 +00:00
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
static void ioapic_iec_notifier(void *private, bool global,
|
|
|
|
uint32_t index, uint32_t mask)
|
|
|
|
{
|
|
|
|
IOAPICCommonState *s = (IOAPICCommonState *)private;
|
|
|
|
/* For simplicity, we just update all the routes */
|
|
|
|
ioapic_update_kvm_routes(s);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-02-03 21:54:11 +00:00
|
|
|
void ioapic_eoi_broadcast(int vector)
|
|
|
|
{
|
2011-10-16 17:38:22 +00:00
|
|
|
IOAPICCommonState *s;
|
2011-02-03 21:54:11 +00:00
|
|
|
uint64_t entry;
|
|
|
|
int i, n;
|
|
|
|
|
2017-01-09 08:55:51 +00:00
|
|
|
trace_ioapic_eoi_broadcast(vector);
|
|
|
|
|
2011-02-03 21:54:11 +00:00
|
|
|
for (i = 0; i < MAX_IOAPICS; i++) {
|
|
|
|
s = ioapics[i];
|
|
|
|
if (!s) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (n = 0; n < IOAPIC_NUM_PINS; n++) {
|
|
|
|
entry = s->ioredtbl[n];
|
2019-04-02 08:02:15 +00:00
|
|
|
|
|
|
|
if ((entry & IOAPIC_VECTOR_MASK) != vector ||
|
|
|
|
((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) != IOAPIC_TRIGGER_LEVEL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-03-18 14:52:03 +00:00
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
/*
|
|
|
|
* When IOAPIC is in the userspace while APIC is still in
|
|
|
|
* the kernel (i.e., split irqchip), we have a trick to
|
|
|
|
* kick the resamplefd logic for registered irqfds from
|
|
|
|
* userspace to deactivate the IRQ. When that happens, it
|
|
|
|
* means the irq bypassed userspace IOAPIC (so the irr and
|
|
|
|
* remote-irr of the table entry should be bypassed too
|
|
|
|
* even if interrupt come). Still kick the resamplefds if
|
|
|
|
* they're bound to the IRQ, to make sure to EOI the
|
|
|
|
* interrupt for the hardware correctly.
|
|
|
|
*
|
|
|
|
* Note: We still need to go through the irr & remote-irr
|
|
|
|
* operations below because we don't know whether there're
|
|
|
|
* emulated devices that are using/sharing the same IRQ.
|
|
|
|
*/
|
|
|
|
kvm_resample_fd_notify(n);
|
|
|
|
#endif
|
|
|
|
|
2019-04-02 08:02:15 +00:00
|
|
|
if (!(entry & IOAPIC_LVT_REMOTE_IRR)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
trace_ioapic_clear_remote_irr(n, vector);
|
|
|
|
s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
|
|
|
|
|
|
|
|
if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
|
2019-06-22 00:21:19 +00:00
|
|
|
++s->irq_eoi[n];
|
|
|
|
if (s->irq_eoi[n] >= SUCCESSIVE_IRQ_MAX_COUNT) {
|
2019-04-02 08:02:15 +00:00
|
|
|
/*
|
|
|
|
* Real hardware does not deliver the interrupt immediately
|
|
|
|
* during eoi broadcast, and this lets a buggy guest make
|
|
|
|
* slow progress even if it does not correctly handle a
|
|
|
|
* level-triggered interrupt. Emulate this behavior if we
|
|
|
|
* detect an interrupt storm.
|
|
|
|
*/
|
2019-06-22 00:21:19 +00:00
|
|
|
s->irq_eoi[n] = 0;
|
2019-04-02 08:02:15 +00:00
|
|
|
timer_mod_anticipate(s->delayed_ioapic_service_timer,
|
|
|
|
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
|
|
|
NANOSECONDS_PER_SECOND / 100);
|
2019-06-22 00:21:19 +00:00
|
|
|
trace_ioapic_eoi_delayed_reassert(n);
|
2019-04-02 08:02:15 +00:00
|
|
|
} else {
|
2011-02-03 21:54:11 +00:00
|
|
|
ioapic_service(s);
|
|
|
|
}
|
2019-04-02 08:02:15 +00:00
|
|
|
} else {
|
2019-06-22 00:21:19 +00:00
|
|
|
s->irq_eoi[n] = 0;
|
2011-02-03 21:54:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 11:11:27 +00:00
|
|
|
static uint64_t
|
2012-10-23 10:30:10 +00:00
|
|
|
ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
|
2009-03-12 20:25:12 +00:00
|
|
|
{
|
2011-10-16 17:38:22 +00:00
|
|
|
IOAPICCommonState *s = opaque;
|
2009-03-12 20:25:12 +00:00
|
|
|
int index;
|
|
|
|
uint32_t val = 0;
|
|
|
|
|
2017-01-09 08:55:51 +00:00
|
|
|
addr &= 0xff;
|
|
|
|
|
|
|
|
switch (addr) {
|
2011-02-03 21:54:14 +00:00
|
|
|
case IOAPIC_IOREGSEL:
|
2009-03-12 20:25:12 +00:00
|
|
|
val = s->ioregsel;
|
2011-02-03 21:54:14 +00:00
|
|
|
break;
|
|
|
|
case IOAPIC_IOWIN:
|
2011-10-17 11:11:29 +00:00
|
|
|
if (size != 4) {
|
|
|
|
break;
|
|
|
|
}
|
2009-03-12 20:25:12 +00:00
|
|
|
switch (s->ioregsel) {
|
2011-02-03 21:54:14 +00:00
|
|
|
case IOAPIC_REG_ID:
|
2015-07-30 08:21:00 +00:00
|
|
|
case IOAPIC_REG_ARB:
|
2011-02-03 21:54:14 +00:00
|
|
|
val = s->id << IOAPIC_ID_SHIFT;
|
|
|
|
break;
|
|
|
|
case IOAPIC_REG_VER:
|
2016-08-01 13:59:19 +00:00
|
|
|
val = s->version |
|
2011-02-03 21:54:14 +00:00
|
|
|
((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
|
|
|
|
if (index >= 0 && index < IOAPIC_NUM_PINS) {
|
|
|
|
if (s->ioregsel & 1) {
|
|
|
|
val = s->ioredtbl[index] >> 32;
|
|
|
|
} else {
|
|
|
|
val = s->ioredtbl[index] & 0xffffffff;
|
2009-03-12 20:25:12 +00:00
|
|
|
}
|
2011-02-03 21:54:14 +00:00
|
|
|
}
|
2009-03-12 20:25:12 +00:00
|
|
|
}
|
2011-02-03 21:54:14 +00:00
|
|
|
break;
|
2009-03-12 20:25:12 +00:00
|
|
|
}
|
2017-01-09 08:55:51 +00:00
|
|
|
|
2017-11-02 18:03:10 +00:00
|
|
|
trace_ioapic_mem_read(addr, s->ioregsel, size, val);
|
2017-01-09 08:55:51 +00:00
|
|
|
|
2009-03-12 20:25:12 +00:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2016-05-10 10:21:22 +00:00
|
|
|
/*
|
|
|
|
* This is to satisfy the hack in Linux kernel. One hack of it is to
|
|
|
|
* simulate clearing the Remote IRR bit of IOAPIC entry using the
|
|
|
|
* following:
|
|
|
|
*
|
|
|
|
* "For IO-APIC's with EOI register, we use that to do an explicit EOI.
|
|
|
|
* Otherwise, we simulate the EOI message manually by changing the trigger
|
|
|
|
* mode to edge and then back to level, with RTE being masked during
|
|
|
|
* this."
|
|
|
|
*
|
|
|
|
* (See linux kernel __eoi_ioapic_pin() comment in commit c0205701)
|
|
|
|
*
|
|
|
|
* This is based on the assumption that, Remote IRR bit will be
|
|
|
|
* cleared by IOAPIC hardware when configured as edge-triggered
|
|
|
|
* interrupts.
|
|
|
|
*
|
|
|
|
* Without this, level-triggered interrupts in IR mode might fail to
|
|
|
|
* work correctly.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
ioapic_fix_edge_remote_irr(uint64_t *entry)
|
|
|
|
{
|
|
|
|
if (!(*entry & IOAPIC_LVT_TRIGGER_MODE)) {
|
|
|
|
/* Edge-triggered interrupts, make sure remote IRR is zero */
|
|
|
|
*entry &= ~((uint64_t)IOAPIC_LVT_REMOTE_IRR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-03 21:54:14 +00:00
|
|
|
static void
|
2012-10-23 10:30:10 +00:00
|
|
|
ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
|
2011-10-17 11:11:27 +00:00
|
|
|
unsigned int size)
|
2009-03-12 20:25:12 +00:00
|
|
|
{
|
2011-10-16 17:38:22 +00:00
|
|
|
IOAPICCommonState *s = opaque;
|
2009-03-12 20:25:12 +00:00
|
|
|
int index;
|
|
|
|
|
2017-01-09 08:55:51 +00:00
|
|
|
addr &= 0xff;
|
2017-11-02 18:03:10 +00:00
|
|
|
trace_ioapic_mem_write(addr, s->ioregsel, size, val);
|
2017-01-09 08:55:51 +00:00
|
|
|
|
|
|
|
switch (addr) {
|
2011-02-03 21:54:14 +00:00
|
|
|
case IOAPIC_IOREGSEL:
|
2009-03-12 20:25:12 +00:00
|
|
|
s->ioregsel = val;
|
2011-02-03 21:54:14 +00:00
|
|
|
break;
|
|
|
|
case IOAPIC_IOWIN:
|
2011-10-17 11:11:29 +00:00
|
|
|
if (size != 4) {
|
|
|
|
break;
|
|
|
|
}
|
2009-03-12 20:25:12 +00:00
|
|
|
switch (s->ioregsel) {
|
2011-02-03 21:54:14 +00:00
|
|
|
case IOAPIC_REG_ID:
|
|
|
|
s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK;
|
|
|
|
break;
|
|
|
|
case IOAPIC_REG_VER:
|
|
|
|
case IOAPIC_REG_ARB:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
|
|
|
|
if (index >= 0 && index < IOAPIC_NUM_PINS) {
|
2016-05-10 10:21:21 +00:00
|
|
|
uint64_t ro_bits = s->ioredtbl[index] & IOAPIC_RO_BITS;
|
2011-02-03 21:54:14 +00:00
|
|
|
if (s->ioregsel & 1) {
|
|
|
|
s->ioredtbl[index] &= 0xffffffff;
|
|
|
|
s->ioredtbl[index] |= (uint64_t)val << 32;
|
|
|
|
} else {
|
|
|
|
s->ioredtbl[index] &= ~0xffffffffULL;
|
|
|
|
s->ioredtbl[index] |= val;
|
2009-03-12 20:25:12 +00:00
|
|
|
}
|
2016-05-10 10:21:21 +00:00
|
|
|
/* restore RO bits */
|
|
|
|
s->ioredtbl[index] &= IOAPIC_RW_BITS;
|
|
|
|
s->ioredtbl[index] |= ro_bits;
|
2019-06-24 15:16:35 +00:00
|
|
|
s->irq_eoi[index] = 0;
|
2016-05-10 10:21:22 +00:00
|
|
|
ioapic_fix_edge_remote_irr(&s->ioredtbl[index]);
|
2011-02-03 21:54:14 +00:00
|
|
|
ioapic_service(s);
|
|
|
|
}
|
2009-03-12 20:25:12 +00:00
|
|
|
}
|
2011-02-03 21:54:14 +00:00
|
|
|
break;
|
2016-08-01 13:59:19 +00:00
|
|
|
case IOAPIC_EOI:
|
|
|
|
/* Explicit EOI is only supported for IOAPIC version 0x20 */
|
|
|
|
if (size != 4 || s->version != 0x20) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ioapic_eoi_broadcast(val);
|
|
|
|
break;
|
2009-03-12 20:25:12 +00:00
|
|
|
}
|
2015-12-17 16:16:08 +00:00
|
|
|
|
|
|
|
ioapic_update_kvm_routes(s);
|
2009-03-12 20:25:12 +00:00
|
|
|
}
|
|
|
|
|
2011-10-17 11:11:27 +00:00
|
|
|
static const MemoryRegionOps ioapic_io_ops = {
|
|
|
|
.read = ioapic_mem_read,
|
|
|
|
.write = ioapic_mem_write,
|
|
|
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
2009-03-12 20:25:12 +00:00
|
|
|
};
|
|
|
|
|
2016-07-14 05:56:27 +00:00
|
|
|
static void ioapic_machine_done_notify(Notifier *notifier, void *data)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_KVM
|
|
|
|
IOAPICCommonState *s = container_of(notifier, IOAPICCommonState,
|
|
|
|
machine_done);
|
|
|
|
|
|
|
|
if (kvm_irqchip_is_split()) {
|
|
|
|
X86IOMMUState *iommu = x86_iommu_get_default();
|
|
|
|
if (iommu) {
|
|
|
|
/* Register this IOAPIC with IOMMU IEC notifier, so that
|
|
|
|
* when there are IR invalidates, we can be notified to
|
|
|
|
* update kernel IR cache. */
|
|
|
|
x86_iommu_iec_register_notifier(iommu, ioapic_iec_notifier, s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-02-03 07:18:17 +00:00
|
|
|
#define IOAPIC_VER_DEF 0x20
|
|
|
|
|
2013-11-05 10:16:05 +00:00
|
|
|
static void ioapic_realize(DeviceState *dev, Error **errp)
|
2009-03-12 20:25:12 +00:00
|
|
|
{
|
2013-11-05 10:16:05 +00:00
|
|
|
IOAPICCommonState *s = IOAPIC_COMMON(dev);
|
2013-11-05 10:16:04 +00:00
|
|
|
|
2016-08-01 13:59:19 +00:00
|
|
|
if (s->version != 0x11 && s->version != 0x20) {
|
2018-10-17 08:26:34 +00:00
|
|
|
error_setg(errp, "IOAPIC only supports version 0x11 or 0x20 "
|
|
|
|
"(default: 0x%x).", IOAPIC_VER_DEF);
|
|
|
|
return;
|
2016-08-01 13:59:19 +00:00
|
|
|
}
|
|
|
|
|
2013-06-07 01:25:08 +00:00
|
|
|
memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s,
|
|
|
|
"ioapic", 0x1000);
|
2009-03-12 20:25:12 +00:00
|
|
|
|
2019-04-02 08:02:15 +00:00
|
|
|
s->delayed_ioapic_service_timer =
|
|
|
|
timer_new_ns(QEMU_CLOCK_VIRTUAL, delayed_ioapic_service_cb, s);
|
|
|
|
|
2013-11-05 10:16:04 +00:00
|
|
|
qdev_init_gpio_in(dev, ioapic_set_irq, IOAPIC_NUM_PINS);
|
2011-02-03 21:54:11 +00:00
|
|
|
|
2013-11-05 10:16:05 +00:00
|
|
|
ioapics[ioapic_no] = s;
|
2016-07-14 05:56:27 +00:00
|
|
|
s->machine_done.notify = ioapic_machine_done_notify;
|
|
|
|
qemu_add_machine_init_done_notifier(&s->machine_done);
|
2009-03-12 20:25:12 +00:00
|
|
|
}
|
2010-06-19 07:41:43 +00:00
|
|
|
|
qdev: Unrealize must not fail
Devices may have component devices and buses.
Device realization may fail. Realization is recursive: a device's
realize() method realizes its components, and device_set_realized()
realizes its buses (which should in turn realize the devices on that
bus, except bus_set_realized() doesn't implement that, yet).
When realization of a component or bus fails, we need to roll back:
unrealize everything we realized so far. If any of these unrealizes
failed, the device would be left in an inconsistent state. Must not
happen.
device_set_realized() lets it happen: it ignores errors in the roll
back code starting at label child_realize_fail.
Since realization is recursive, unrealization must be recursive, too.
But how could a partly failed unrealize be rolled back? We'd have to
re-realize, which can fail. This design is fundamentally broken.
device_set_realized() does not roll back at all. Instead, it keeps
unrealizing, ignoring further errors.
It can screw up even for a device with no buses: if the lone
dc->unrealize() fails, it still unregisters vmstate, and calls
listeners' unrealize() callback.
bus_set_realized() does not roll back either. Instead, it stops
unrealizing.
Fortunately, no unrealize method can fail, as we'll see below.
To fix the design error, drop parameter @errp from all the unrealize
methods.
Any unrealize method that uses @errp now needs an update. This leads
us to unrealize() methods that can fail. Merely passing it to another
unrealize method cannot cause failure, though. Here are the ones that
do other things with @errp:
* virtio_serial_device_unrealize()
Fails when qbus_set_hotplug_handler() fails, but still does all the
other work. On failure, the device would stay realized with its
resources completely gone. Oops. Can't happen, because
qbus_set_hotplug_handler() can't actually fail here. Pass
&error_abort to qbus_set_hotplug_handler() instead.
* hw/ppc/spapr_drc.c's unrealize()
Fails when object_property_del() fails, but all the other work is
already done. On failure, the device would stay realized with its
vmstate registration gone. Oops. Can't happen, because
object_property_del() can't actually fail here. Pass &error_abort
to object_property_del() instead.
* spapr_phb_unrealize()
Fails and bails out when remove_drcs() fails, but other work is
already done. On failure, the device would stay realized with some
of its resources gone. Oops. remove_drcs() fails only when
chassis_from_bus()'s object_property_get_uint() fails, and it can't
here. Pass &error_abort to remove_drcs() instead.
Therefore, no unrealize method can fail before this patch.
device_set_realized()'s recursive unrealization via bus uses
object_property_set_bool(). Can't drop @errp there, so pass
&error_abort.
We similarly unrealize with object_property_set_bool() elsewhere,
always ignoring errors. Pass &error_abort instead.
Several unrealize methods no longer handle errors from other unrealize
methods: virtio_9p_device_unrealize(),
virtio_input_device_unrealize(), scsi_qdev_unrealize(), ...
Much of the deleted error handling looks wrong anyway.
One unrealize methods no longer ignore such errors:
usb_ehci_pci_exit().
Several realize methods no longer ignore errors when rolling back:
v9fs_device_realize_common(), pci_qdev_unrealize(),
spapr_phb_realize(), usb_qdev_realize(), vfio_ccw_realize(),
virtio_device_realize().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-17-armbru@redhat.com>
2020-05-05 15:29:24 +00:00
|
|
|
static void ioapic_unrealize(DeviceState *dev)
|
2019-04-02 08:02:15 +00:00
|
|
|
{
|
|
|
|
IOAPICCommonState *s = IOAPIC_COMMON(dev);
|
|
|
|
|
|
|
|
timer_free(s->delayed_ioapic_service_timer);
|
|
|
|
}
|
|
|
|
|
2016-08-01 13:59:19 +00:00
|
|
|
static Property ioapic_properties[] = {
|
2017-02-03 07:18:17 +00:00
|
|
|
DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF),
|
2016-08-01 13:59:19 +00:00
|
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
|
|
};
|
|
|
|
|
2012-01-24 19:12:29 +00:00
|
|
|
static void ioapic_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
|
2011-12-08 03:34:16 +00:00
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
2012-01-24 19:12:29 +00:00
|
|
|
|
2013-11-05 10:16:05 +00:00
|
|
|
k->realize = ioapic_realize;
|
2019-04-02 08:02:15 +00:00
|
|
|
k->unrealize = ioapic_unrealize;
|
2017-01-09 08:55:53 +00:00
|
|
|
/*
|
|
|
|
* If APIC is in kernel, we need to update the kernel cache after
|
|
|
|
* migration, otherwise first 24 gsi routes will be invalid.
|
|
|
|
*/
|
|
|
|
k->post_load = ioapic_update_kvm_routes;
|
2011-12-08 03:34:16 +00:00
|
|
|
dc->reset = ioapic_reset_common;
|
2020-01-10 15:30:32 +00:00
|
|
|
device_class_set_props(dc, ioapic_properties);
|
2012-01-24 19:12:29 +00:00
|
|
|
}
|
|
|
|
|
2013-01-10 15:19:07 +00:00
|
|
|
static const TypeInfo ioapic_info = {
|
2019-01-05 02:38:31 +00:00
|
|
|
.name = TYPE_IOAPIC,
|
2011-12-08 03:34:16 +00:00
|
|
|
.parent = TYPE_IOAPIC_COMMON,
|
|
|
|
.instance_size = sizeof(IOAPICCommonState),
|
|
|
|
.class_init = ioapic_class_init,
|
2010-06-19 07:41:43 +00:00
|
|
|
};
|
|
|
|
|
2012-02-09 14:20:55 +00:00
|
|
|
static void ioapic_register_types(void)
|
2010-06-19 07:41:43 +00:00
|
|
|
{
|
2011-12-08 03:34:16 +00:00
|
|
|
type_register_static(&ioapic_info);
|
2010-06-19 07:41:43 +00:00
|
|
|
}
|
|
|
|
|
2012-02-09 14:20:55 +00:00
|
|
|
type_init(ioapic_register_types)
|