* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
#include "qemu/thread.h"
#include "hw/i386/apic_internal.h"
#include "hw/i386/apic.h"
#include "trace.h"
#include "hw/i386/pc.h"
#include "hw/i386/apic-msidef.h"
+#include "qapi/error.h"
+#define MAX_APICS 255
#define MAX_APIC_WORDS 8
#define SYNC_FROM_VAPIC 0x1
static APICCommonState *local_apics[MAX_APICS + 1];
+#define TYPE_APIC "apic"
+#define APIC(obj) \
+ OBJECT_CHECK(APICCommonState, (obj), TYPE_APIC)
+
static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
static void apic_update_irq(APICCommonState *s);
static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
return ctz32(value);
}
-static inline void apic_set_bit(uint32_t *tab, int index)
-{
- int i, mask;
- i = index >> 5;
- mask = 1 << (index & 0x1f);
- tab[i] |= mask;
-}
-
static inline void apic_reset_bit(uint32_t *tab, int index)
{
int i, mask;
tab[i] &= ~mask;
}
-static inline int apic_get_bit(uint32_t *tab, int index)
-{
- int i, mask;
- i = index >> 5;
- mask = 1 << (index & 0x1f);
- return !!(tab[i] & mask);
-}
-
/* return -1 if no bit is set */
static int get_highest_priority_int(uint32_t *tab)
{
void apic_deliver_pic_intr(DeviceState *dev, int level)
{
- APICCommonState *s = APIC_COMMON(dev);
+ APICCommonState *s = APIC(dev);
if (level) {
apic_local_deliver(s, APIC_LVT_LINT0);
}
}
+int apic_get_highest_priority_irr(DeviceState *dev)
+{
+ APICCommonState *s;
+
+ if (!dev) {
+ /* no interrupts */
+ return -1;
+ }
+ s = APIC_COMMON(dev);
+ return get_highest_priority_int(s->irr);
+}
+
static uint8_t apic_get_tpr(APICCommonState *s)
{
apic_sync_vapic(s, SYNC_FROM_VAPIC);
return s->tpr >> 4;
}
-static int apic_get_ppr(APICCommonState *s)
+int apic_get_ppr(APICCommonState *s)
{
int tpr, isrv, ppr;
void apic_poll_irq(DeviceState *dev)
{
- APICCommonState *s = APIC_COMMON(dev);
+ APICCommonState *s = APIC(dev);
apic_sync_vapic(s, SYNC_FROM_VAPIC);
apic_update_irq(s);
int i;
if (apic && apic->id == dest)
- return dest; /* shortcut in case apic->id == apic->idx */
+ return dest; /* shortcut in case apic->id == local_apics[dest]->id */
for (i = 0; i < MAX_APICS; i++) {
apic = local_apics[i];
void apic_sipi(DeviceState *dev)
{
- APICCommonState *s = APIC_COMMON(dev);
+ APICCommonState *s = APIC(dev);
cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
uint8_t delivery_mode, uint8_t vector_num,
uint8_t trigger_mode)
{
- APICCommonState *s = APIC_COMMON(dev);
+ APICCommonState *s = APIC(dev);
uint32_t deliver_bitmask[MAX_APIC_WORDS];
int dest_shorthand = (s->icr[0] >> 18) & 3;
APICCommonState *apic_iter;
break;
case 1:
memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
- apic_set_bit(deliver_bitmask, s->idx);
+ apic_set_bit(deliver_bitmask, s->id);
break;
case 2:
memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
break;
case 3:
memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
- apic_reset_bit(deliver_bitmask, s->idx);
+ apic_reset_bit(deliver_bitmask, s->id);
break;
}
int apic_get_interrupt(DeviceState *dev)
{
- APICCommonState *s = APIC_COMMON(dev);
+ APICCommonState *s = APIC(dev);
int intno;
/* if the APIC is installed or enabled, we let the 8259 handle the
int apic_accept_pic_intr(DeviceState *dev)
{
- APICCommonState *s = APIC_COMMON(dev);
+ APICCommonState *s = APIC(dev);
uint32_t lvt0;
if (!s)
if (!dev) {
return 0;
}
- s = APIC_COMMON(dev);
+ s = APIC(dev);
index = (addr >> 4) & 0xff;
switch(index) {
val = s->divide_conf;
break;
default:
- s->esr |= ESR_ILLEGAL_ADDRESS;
+ s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
val = 0;
break;
}
return val;
}
-static void apic_send_msi(hwaddr addr, uint32_t data)
+static void apic_send_msi(MSIMessage *msi)
{
+ uint64_t addr = msi->address;
+ uint32_t data = msi->data;
uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
* APIC is connected directly to the CPU.
* Mapping them on the global bus happens to work because
* MSI registers are reserved in APIC MMIO and vice versa. */
- apic_send_msi(addr, val);
+ MSIMessage msi = { .address = addr, .data = val };
+ apic_send_msi(&msi);
return;
}
if (!dev) {
return;
}
- s = APIC_COMMON(dev);
+ s = APIC(dev);
trace_apic_mem_writel(addr, val);
}
break;
default:
- s->esr |= ESR_ILLEGAL_ADDRESS;
+ s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
break;
}
}
static void apic_realize(DeviceState *dev, Error **errp)
{
- APICCommonState *s = APIC_COMMON(dev);
+ APICCommonState *s = APIC(dev);
+
+ if (s->id >= MAX_APICS) {
+ error_setg(errp, "%s initialization failed. APIC ID %d is invalid",
+ object_get_typename(OBJECT(dev)), s->id);
+ return;
+ }
memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi",
APIC_SPACE_SIZE);
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s);
- local_apics[s->idx] = s;
+ local_apics[s->id] = s;
+
+ msi_nonbroken = true;
+}
+
+static void apic_unrealize(DeviceState *dev, Error **errp)
+{
+ APICCommonState *s = APIC(dev);
- msi_supported = true;
+ timer_del(s->timer);
+ timer_free(s->timer);
+ local_apics[s->id] = NULL;
}
static void apic_class_init(ObjectClass *klass, void *data)
APICCommonClass *k = APIC_COMMON_CLASS(klass);
k->realize = apic_realize;
+ k->unrealize = apic_unrealize;
k->set_base = apic_set_base;
k->set_tpr = apic_set_tpr;
k->get_tpr = apic_get_tpr;
k->external_nmi = apic_external_nmi;
k->pre_save = apic_pre_save;
k->post_load = apic_post_load;
+ k->send_msi = apic_send_msi;
}
static const TypeInfo apic_info = {
- .name = "apic",
+ .name = TYPE_APIC,
.instance_size = sizeof(APICCommonState),
.parent = TYPE_APIC_COMMON,
.class_init = apic_class_init,