qemu/include/hw/i386/apic_internal.h
Bui Quang Minh 774204cf98 apic, i386/tcg: add x2apic transitions
This commit adds support for x2APIC transitions when writing to
MSR_IA32_APICBASE register and finally adds CPUID_EXT_X2APIC to
TCG_EXT_FEATURES.

The set_base in APICCommonClass now returns an integer to indicate error in
execution. apic_set_base return -1 on invalid APIC state transition,
accelerator can use this to raise appropriate exception.

Signed-off-by: Bui Quang Minh <minhquangbui99@gmail.com>
Message-Id: <20240111154404.5333-4-minhquangbui99@gmail.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2024-02-14 06:09:32 -05:00

234 lines
7.9 KiB
C

/*
* APIC support - internal interfaces
*
* Copyright (c) 2004-2005 Fabrice Bellard
* Copyright (c) 2011 Jan Kiszka, Siemens AG
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
#ifndef QEMU_APIC_INTERNAL_H
#define QEMU_APIC_INTERNAL_H
#include "cpu.h"
#include "exec/memory.h"
#include "qemu/timer.h"
#include "target/i386/cpu-qom.h"
#include "qom/object.h"
/* APIC Local Vector Table */
#define APIC_LVT_TIMER 0
#define APIC_LVT_THERMAL 1
#define APIC_LVT_PERFORM 2
#define APIC_LVT_LINT0 3
#define APIC_LVT_LINT1 4
#define APIC_LVT_ERROR 5
#define APIC_LVT_NB 6
/* APIC delivery modes */
#define APIC_DM_FIXED 0
#define APIC_DM_LOWPRI 1
#define APIC_DM_SMI 2
#define APIC_DM_NMI 4
#define APIC_DM_INIT 5
#define APIC_DM_SIPI 6
#define APIC_DM_EXTINT 7
/* APIC destination mode */
#define APIC_DESTMODE_PHYSICAL 0
#define APIC_DESTMODE_LOGICAL 1
#define APIC_DESTMODE_LOGICAL_FLAT 0xf
#define APIC_DESTMODE_LOGICAL_CLUSTER 0
#define APIC_TRIGGER_EDGE 0
#define APIC_TRIGGER_LEVEL 1
#define APIC_VECTOR_MASK 0xff
#define APIC_DCR_MASK 0xf
#define APIC_LVT_TIMER_SHIFT 17
#define APIC_LVT_MASKED_SHIFT 16
#define APIC_LVT_LEVEL_TRIGGER_SHIFT 15
#define APIC_LVT_REMOTE_IRR_SHIFT 14
#define APIC_LVT_INT_POLARITY_SHIFT 13
#define APIC_LVT_DELIV_STS_SHIFT 12
#define APIC_LVT_DELIV_MOD_SHIFT 8
#define APIC_LVT_TIMER_TSCDEADLINE (2 << APIC_LVT_TIMER_SHIFT)
#define APIC_LVT_TIMER_PERIODIC (1 << APIC_LVT_TIMER_SHIFT)
#define APIC_LVT_MASKED (1 << APIC_LVT_MASKED_SHIFT)
#define APIC_LVT_LEVEL_TRIGGER (1 << APIC_LVT_LEVEL_TRIGGER_SHIFT)
#define APIC_LVT_REMOTE_IRR (1 << APIC_LVT_REMOTE_IRR_SHIFT)
#define APIC_LVT_INT_POLARITY (1 << APIC_LVT_INT_POLARITY_SHIFT)
#define APIC_LVT_DELIV_STS (1 << APIC_LVT_DELIV_STS_SHIFT)
#define APIC_LVT_DELIV_MOD (7 << APIC_LVT_DELIV_MOD_SHIFT)
#define APIC_ESR_ILL_ADDRESS_SHIFT 7
#define APIC_ESR_RECV_ILL_VECT_SHIFT 6
#define APIC_ESR_SEND_ILL_VECT_SHIFT 5
#define APIC_ESR_RECV_ACCEPT_SHIFT 3
#define APIC_ESR_SEND_ACCEPT_SHIFT 2
#define APIC_ESR_RECV_CHECK_SUM_SHIFT 1
#define APIC_ESR_ILLEGAL_ADDRESS (1 << APIC_ESR_ILL_ADDRESS_SHIFT)
#define APIC_ESR_RECV_ILLEGAL_VECT (1 << APIC_ESR_RECV_ILL_VECT_SHIFT)
#define APIC_ESR_SEND_ILLEGAL_VECT (1 << APIC_ESR_SEND_ILL_VECT_SHIFT)
#define APIC_ESR_RECV_ACCEPT (1 << APIC_ESR_RECV_ACCEPT_SHIFT)
#define APIC_ESR_SEND_ACCEPT (1 << APIC_ESR_SEND_ACCEPT_SHIFT)
#define APIC_ESR_RECV_CHECK_SUM (1 << APIC_ESR_RECV_CHECK_SUM_SHIFT)
#define APIC_ESR_SEND_CHECK_SUM 1
#define APIC_ICR_DEST_SHIFT 24
#define APIC_ICR_DEST_SHORT_SHIFT 18
#define APIC_ICR_TRIGGER_MOD_SHIFT 15
#define APIC_ICR_LEVEL_SHIFT 14
#define APIC_ICR_DELIV_STS_SHIFT 12
#define APIC_ICR_DEST_MOD_SHIFT 11
#define APIC_ICR_DELIV_MOD_SHIFT 8
#define APIC_ICR_DEST_SHORT (3 << APIC_ICR_DEST_SHORT_SHIFT)
#define APIC_ICR_TRIGGER_MOD (1 << APIC_ICR_TRIGGER_MOD_SHIFT)
#define APIC_ICR_LEVEL (1 << APIC_ICR_LEVEL_SHIFT)
#define APIC_ICR_DELIV_STS (1 << APIC_ICR_DELIV_STS_SHIFT)
#define APIC_ICR_DEST_MOD (1 << APIC_ICR_DEST_MOD_SHIFT)
#define APIC_ICR_DELIV_MOD (7 << APIC_ICR_DELIV_MOD_SHIFT)
#define APIC_PR_CLASS_SHIFT 4
#define APIC_PR_SUB_CLASS 0xf
#define APIC_LOGDEST_XAPIC_SHIFT 4
#define APIC_LOGDEST_XAPIC_ID 0xf
#define APIC_LOGDEST_X2APIC_SHIFT 16
#define APIC_LOGDEST_X2APIC_ID 0xffff
#define APIC_SPURIO_FOCUS_SHIFT 9
#define APIC_SPURIO_ENABLED_SHIFT 8
#define APIC_SPURIO_FOCUS (1 << APIC_SPURIO_FOCUS_SHIFT)
#define APIC_SPURIO_ENABLED (1 << APIC_SPURIO_ENABLED_SHIFT)
#define APIC_SV_DIRECTED_IO (1 << 12)
#define APIC_SV_ENABLE (1 << 8)
#define VAPIC_ENABLE_BIT 0
#define VAPIC_ENABLE_MASK (1 << VAPIC_ENABLE_BIT)
typedef struct APICCommonState APICCommonState;
#define TYPE_APIC_COMMON "apic-common"
typedef struct APICCommonClass APICCommonClass;
DECLARE_OBJ_CHECKERS(APICCommonState, APICCommonClass,
APIC_COMMON, TYPE_APIC_COMMON)
struct APICCommonClass {
DeviceClass parent_class;
DeviceRealize realize;
DeviceUnrealize unrealize;
int (*set_base)(APICCommonState *s, uint64_t val);
void (*set_tpr)(APICCommonState *s, uint8_t val);
uint8_t (*get_tpr)(APICCommonState *s);
void (*enable_tpr_reporting)(APICCommonState *s, bool enable);
void (*vapic_base_update)(APICCommonState *s);
void (*external_nmi)(APICCommonState *s);
void (*pre_save)(APICCommonState *s);
void (*post_load)(APICCommonState *s);
void (*reset)(APICCommonState *s);
/* send_msi emulates an APIC bus and its proper place would be in a new
* device, but it's convenient to have it here for now.
*/
void (*send_msi)(MSIMessage *msi);
};
struct APICCommonState {
/*< private >*/
DeviceState parent_obj;
/*< public >*/
MemoryRegion io_memory;
X86CPU *cpu;
uint32_t apicbase;
uint8_t id; /* legacy APIC ID */
uint32_t initial_apic_id;
uint8_t version;
uint8_t arb_id;
uint8_t tpr;
uint32_t spurious_vec;
uint8_t log_dest;
uint8_t dest_mode;
uint32_t isr[8]; /* in service register */
uint32_t tmr[8]; /* trigger mode register */
uint32_t irr[8]; /* interrupt request register */
uint32_t lvt[APIC_LVT_NB];
uint32_t esr; /* error register */
uint32_t icr[2];
uint32_t divide_conf;
int count_shift;
uint32_t initial_count;
int64_t initial_count_load_time;
int64_t next_time;
QEMUTimer *timer;
int64_t timer_expiry;
int sipi_vector;
int wait_for_sipi;
uint32_t vapic_control;
DeviceState *vapic;
hwaddr vapic_paddr; /* note: persistence via kvmvapic */
bool legacy_instance_id;
uint32_t extended_log_dest;
};
typedef struct VAPICState {
uint8_t tpr;
uint8_t isr;
uint8_t zero;
uint8_t irr;
uint8_t enabled;
} QEMU_PACKED VAPICState;
extern bool apic_report_tpr_access;
bool apic_next_timer(APICCommonState *s, int64_t current_time);
void apic_enable_tpr_access_reporting(DeviceState *d, bool enable);
void apic_enable_vapic(DeviceState *d, hwaddr paddr);
void vapic_report_tpr_access(DeviceState *dev, CPUState *cpu, target_ulong ip,
TPRAccess access);
int apic_get_ppr(APICCommonState *s);
uint32_t apic_get_current_count(APICCommonState *s);
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 int apic_get_bit(uint32_t *tab, int index)
{
int i, mask;
i = index >> 5;
mask = 1 << (index & 0x1f);
return !!(tab[i] & mask);
}
APICCommonClass *apic_get_class(Error **errp);
#endif /* QEMU_APIC_INTERNAL_H */