virtio,pc,pci: features, cleanups, fixes

vhost-user-snd support
 x2APIC mode with TCG support
 CXL update to r3.1
 
 fixes, cleanups all over the place.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmXMoXUPHG1zdEByZWRo
 YXQuY29tAAoJECgfDbjSjVRpFtMIAKUKD0hzJrwOyPo4xsRUMbsB3ehIsJsMKfOK
 w+JWzTaojAG8ENPelWBdL2sEIs5U73VOchjLqHbH2m5sz6GJ13214amvdU/fYc8+
 /dU2ZKoAmaR5L1ovKO/fq07y/J6DrITZ5tosy2i84Xa8EnsL4j3wEPNVWsDi7dna
 mvXUICSOOoJQ4O2YhSruKCQ8qIgF1/0Oi3u/rcrW3alSs8VQlrtQXxl6k+LbYqek
 +Fytco3jMRHPvQ+GYUIwGuHjN15ghArcvbsV0GIa+24BPY5h7YbDYGbfasePT5OK
 zDz51jitkoyDrQr+OzwOEe/X5+dVGhayRXfMtU5Qm53IE3y61qc=
 =K4b1
 -----END PGP SIGNATURE-----

Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging

virtio,pc,pci: features, cleanups, fixes

vhost-user-snd support
x2APIC mode with TCG support
CXL update to r3.1

fixes, cleanups all over the place.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# -----BEGIN PGP SIGNATURE-----
#
# iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmXMoXUPHG1zdEByZWRo
# YXQuY29tAAoJECgfDbjSjVRpFtMIAKUKD0hzJrwOyPo4xsRUMbsB3ehIsJsMKfOK
# w+JWzTaojAG8ENPelWBdL2sEIs5U73VOchjLqHbH2m5sz6GJ13214amvdU/fYc8+
# /dU2ZKoAmaR5L1ovKO/fq07y/J6DrITZ5tosy2i84Xa8EnsL4j3wEPNVWsDi7dna
# mvXUICSOOoJQ4O2YhSruKCQ8qIgF1/0Oi3u/rcrW3alSs8VQlrtQXxl6k+LbYqek
# +Fytco3jMRHPvQ+GYUIwGuHjN15ghArcvbsV0GIa+24BPY5h7YbDYGbfasePT5OK
# zDz51jitkoyDrQr+OzwOEe/X5+dVGhayRXfMtU5Qm53IE3y61qc=
# =K4b1
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 14 Feb 2024 11:18:13 GMT
# gpg:                using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469
# gpg:                issuer "mst@redhat.com"
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full]
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>" [full]
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu: (60 commits)
  MAINTAINERS: Switch to my Enfabrica email
  virtio-gpu-rutabaga.c: override resource_destroy method
  virtio-gpu.c: add resource_destroy class method
  hw/display/virtio-gpu.c: use reset_bh class method
  hw/smbios: Fix port connector option validation
  hw/smbios: Fix OEM strings table option validation
  virtio-gpu: Correct virgl_renderer_resource_get_info() error check
  hw/cxl: Standardize all references on CXL r3.1 and minor updates
  hw/cxl: Update mailbox status registers.
  hw/cxl: Update RAS Capability Definitions for version 3.
  hw/cxl: Update link register definitions.
  hw/cxl: Update HDM Decoder capability to version 3
  tests/acpi: Update DSDT.cxl to reflect change _STA return value.
  hw/i386: Fix _STA return value for ACPI0017
  tests/acpi: Allow update of DSDT.cxl
  hw/mem/cxl_type3: Fix potential divide by zero reported by coverity
  hw/cxl: Pass NULL for a NULL MemoryRegionOps
  hw/cxl: Pass CXLComponentState to cache_mem_ops
  hw/cxl/device: read from register values in mdev_reg_read()
  hw/cxl/mbox: Remove dead code
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-02-14 15:45:52 +00:00
commit 5767815218
84 changed files with 2004 additions and 1910 deletions

View file

@ -32,14 +32,13 @@
#include "qapi/error.h"
#include "qom/object.h"
#define MAX_APICS 255
#define MAX_APIC_WORDS 8
#define SYNC_FROM_VAPIC 0x1
#define SYNC_TO_VAPIC 0x2
#define SYNC_ISR_IRR_TO_VAPIC 0x4
static APICCommonState *local_apics[MAX_APICS + 1];
static APICCommonState **local_apics;
static uint32_t max_apics;
static uint32_t max_apic_words;
#define TYPE_APIC "apic"
/*This is reusing the APICCommonState typedef from APIC_COMMON */
@ -49,7 +48,19 @@ DECLARE_INSTANCE_CHECKER(APICCommonState, 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,
uint8_t dest, uint8_t dest_mode);
uint32_t dest, uint8_t dest_mode);
void apic_set_max_apic_id(uint32_t max_apic_id)
{
int word_size = 32;
/* round up the max apic id to next multiple of words */
max_apics = (max_apic_id + word_size - 1) & ~(word_size - 1);
local_apics = g_malloc0(sizeof(*local_apics) * max_apics);
max_apic_words = max_apics >> 5;
}
/* Find first bit starting from msb */
static int apic_fls_bit(uint32_t value)
@ -199,10 +210,10 @@ static void apic_external_nmi(APICCommonState *s)
#define foreach_apic(apic, deliver_bitmask, code) \
{\
int __i, __j;\
for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
for (__i = 0; __i < max_apic_words; __i++) {\
uint32_t __mask = deliver_bitmask[__i];\
if (__mask) {\
for(__j = 0; __j < 32; __j++) {\
for (__j = 0; __j < 32; __j++) {\
if (__mask & (1U << __j)) {\
apic = local_apics[__i * 32 + __j];\
if (apic) {\
@ -226,7 +237,7 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask,
{
int i, d;
d = -1;
for(i = 0; i < MAX_APIC_WORDS; i++) {
for (i = 0; i < max_apic_words; i++) {
if (deliver_bitmask[i]) {
d = i * 32 + apic_ffs_bit(deliver_bitmask[i]);
break;
@ -276,20 +287,70 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask,
apic_set_irq(apic_iter, vector_num, trigger_mode) );
}
void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
uint8_t vector_num, uint8_t trigger_mode)
static void apic_deliver_irq(uint32_t dest, uint8_t dest_mode,
uint8_t delivery_mode, uint8_t vector_num,
uint8_t trigger_mode)
{
uint32_t deliver_bitmask[MAX_APIC_WORDS];
uint32_t *deliver_bitmask = g_malloc(max_apic_words * sizeof(uint32_t));
trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
trigger_mode);
apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
g_free(deliver_bitmask);
}
static void apic_set_base(APICCommonState *s, uint64_t val)
bool is_x2apic_mode(DeviceState *dev)
{
APICCommonState *s = APIC(dev);
return s->apicbase & MSR_IA32_APICBASE_EXTD;
}
static int apic_set_base_check(APICCommonState *s, uint64_t val)
{
/* Enable x2apic when x2apic is not supported by CPU */
if (!cpu_has_x2apic_feature(&s->cpu->env) &&
val & MSR_IA32_APICBASE_EXTD) {
return -1;
}
/*
* Transition into invalid state
* (s->apicbase & MSR_IA32_APICBASE_ENABLE == 0) &&
* (s->apicbase & MSR_IA32_APICBASE_EXTD) == 1
*/
if (!(val & MSR_IA32_APICBASE_ENABLE) &&
(val & MSR_IA32_APICBASE_EXTD)) {
return -1;
}
/* Invalid transition from disabled mode to x2APIC */
if (!(s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
!(s->apicbase & MSR_IA32_APICBASE_EXTD) &&
(val & MSR_IA32_APICBASE_ENABLE) &&
(val & MSR_IA32_APICBASE_EXTD)) {
return -1;
}
/* Invalid transition from x2APIC to xAPIC */
if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
(s->apicbase & MSR_IA32_APICBASE_EXTD) &&
(val & MSR_IA32_APICBASE_ENABLE) &&
!(val & MSR_IA32_APICBASE_EXTD)) {
return -1;
}
return 0;
}
static int apic_set_base(APICCommonState *s, uint64_t val)
{
if (apic_set_base_check(s, val) < 0) {
return -1;
}
s->apicbase = (val & 0xfffff000) |
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
/* if disabled, cannot be enabled again */
@ -298,6 +359,25 @@ static void apic_set_base(APICCommonState *s, uint64_t val)
cpu_clear_apic_feature(&s->cpu->env);
s->spurious_vec &= ~APIC_SV_ENABLE;
}
/* Transition from disabled mode to xAPIC */
if (!(s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
(val & MSR_IA32_APICBASE_ENABLE)) {
s->apicbase |= MSR_IA32_APICBASE_ENABLE;
cpu_set_apic_feature(&s->cpu->env);
}
/* Transition from xAPIC to x2APIC */
if (cpu_has_x2apic_feature(&s->cpu->env) &&
!(s->apicbase & MSR_IA32_APICBASE_EXTD) &&
(val & MSR_IA32_APICBASE_EXTD)) {
s->apicbase |= MSR_IA32_APICBASE_EXTD;
s->log_dest = ((s->initial_apic_id & 0xffff0) << 16) |
(1 << (s->initial_apic_id & 0xf));
}
return 0;
}
static void apic_set_tpr(APICCommonState *s, uint8_t val)
@ -435,57 +515,123 @@ static void apic_eoi(APICCommonState *s)
apic_update_irq(s);
}
static int apic_find_dest(uint8_t dest)
static bool apic_match_dest(APICCommonState *apic, uint32_t dest)
{
APICCommonState *apic = local_apics[dest];
if (is_x2apic_mode(&apic->parent_obj)) {
return apic->initial_apic_id == dest;
} else {
return apic->id == (uint8_t)dest;
}
}
static void apic_find_dest(uint32_t *deliver_bitmask, uint32_t dest)
{
APICCommonState *apic = NULL;
int i;
if (apic && apic->id == dest)
return dest; /* shortcut in case apic->id == local_apics[dest]->id */
for (i = 0; i < MAX_APICS; i++) {
for (i = 0; i < max_apics; i++) {
apic = local_apics[i];
if (apic && apic->id == dest)
return i;
if (!apic)
break;
if (apic && apic_match_dest(apic, dest)) {
apic_set_bit(deliver_bitmask, i);
}
}
}
return -1;
/*
* Deliver interrupt to x2APIC CPUs if it is x2APIC broadcast.
* Otherwise, deliver interrupt to xAPIC CPUs if it is xAPIC
* broadcast.
*/
static void apic_get_broadcast_bitmask(uint32_t *deliver_bitmask,
bool is_x2apic_broadcast)
{
int i;
APICCommonState *apic_iter;
for (i = 0; i < max_apics; i++) {
apic_iter = local_apics[i];
if (apic_iter) {
bool apic_in_x2apic = is_x2apic_mode(&apic_iter->parent_obj);
if (is_x2apic_broadcast && apic_in_x2apic) {
apic_set_bit(deliver_bitmask, i);
} else if (!is_x2apic_broadcast && !apic_in_x2apic) {
apic_set_bit(deliver_bitmask, i);
}
}
}
}
static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
uint8_t dest, uint8_t dest_mode)
uint32_t dest, uint8_t dest_mode)
{
APICCommonState *apic_iter;
APICCommonState *apic;
int i;
if (dest_mode == 0) {
if (dest == 0xff) {
memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
memset(deliver_bitmask, 0x00, max_apic_words * sizeof(uint32_t));
/*
* x2APIC broadcast is delivered to all x2APIC CPUs regardless of
* destination mode. In case the destination mode is physical, it is
* broadcasted to all xAPIC CPUs too. Otherwise, if the destination
* mode is logical, we need to continue checking if xAPIC CPUs accepts
* the interrupt.
*/
if (dest == 0xffffffff) {
if (dest_mode == APIC_DESTMODE_PHYSICAL) {
memset(deliver_bitmask, 0xff, max_apic_words * sizeof(uint32_t));
return;
} else {
int idx = apic_find_dest(dest);
memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
if (idx >= 0)
apic_set_bit(deliver_bitmask, idx);
apic_get_broadcast_bitmask(deliver_bitmask, true);
}
}
if (dest_mode == APIC_DESTMODE_PHYSICAL) {
apic_find_dest(deliver_bitmask, dest);
/* Any APIC in xAPIC mode will interpret 0xFF as broadcast */
if (dest == 0xff) {
apic_get_broadcast_bitmask(deliver_bitmask, false);
}
} else {
/* XXX: cluster mode */
memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
for(i = 0; i < MAX_APICS; i++) {
apic_iter = local_apics[i];
if (apic_iter) {
if (apic_iter->dest_mode == 0xf) {
if (dest & apic_iter->log_dest)
apic_set_bit(deliver_bitmask, i);
} else if (apic_iter->dest_mode == 0x0) {
if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
(dest & apic_iter->log_dest & 0x0f)) {
/* XXX: logical mode */
for (i = 0; i < max_apics; i++) {
apic = local_apics[i];
if (apic) {
/* x2APIC logical mode */
if (apic->apicbase & MSR_IA32_APICBASE_EXTD) {
if ((dest >> 16) == (apic->extended_log_dest >> 16) &&
(dest & apic->extended_log_dest & 0xffff)) {
apic_set_bit(deliver_bitmask, i);
}
continue;
}
} else {
break;
/* xAPIC logical mode */
dest = (uint8_t)dest;
if (apic->dest_mode == APIC_DESTMODE_LOGICAL_FLAT) {
if (dest & apic->log_dest) {
apic_set_bit(deliver_bitmask, i);
}
} else if (apic->dest_mode == APIC_DESTMODE_LOGICAL_CLUSTER) {
/*
* In cluster model of xAPIC logical mode IPI, 4 higher
* bits are used as cluster address, 4 lower bits are
* the bitmask for local APICs in the cluster. The IPI
* is delivered to an APIC if the cluster address
* matches and the APIC's address bit in the cluster is
* set in bitmask of destination ID in IPI.
*
* The cluster address ranges from 0 - 14, the cluster
* address 15 (0xf) is the broadcast address to all
* clusters.
*/
if ((dest & 0xf0) == 0xf0 ||
(dest & 0xf0) == (apic->log_dest & 0xf0)) {
if (dest & apic->log_dest & 0x0f) {
apic_set_bit(deliver_bitmask, i);
}
}
}
}
}
}
@ -509,29 +655,36 @@ void apic_sipi(DeviceState *dev)
s->wait_for_sipi = 0;
}
static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode,
static void apic_deliver(DeviceState *dev, uint32_t dest, uint8_t dest_mode,
uint8_t delivery_mode, uint8_t vector_num,
uint8_t trigger_mode)
uint8_t trigger_mode, uint8_t dest_shorthand)
{
APICCommonState *s = APIC(dev);
uint32_t deliver_bitmask[MAX_APIC_WORDS];
int dest_shorthand = (s->icr[0] >> 18) & 3;
APICCommonState *apic_iter;
uint32_t deliver_bitmask_size = max_apic_words * sizeof(uint32_t);
uint32_t *deliver_bitmask = g_malloc(deliver_bitmask_size);
uint32_t current_apic_id;
if (is_x2apic_mode(dev)) {
current_apic_id = s->initial_apic_id;
} else {
current_apic_id = s->id;
}
switch (dest_shorthand) {
case 0:
apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
break;
case 1:
memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
apic_set_bit(deliver_bitmask, s->id);
memset(deliver_bitmask, 0x00, deliver_bitmask_size);
apic_set_bit(deliver_bitmask, current_apic_id);
break;
case 2:
memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
memset(deliver_bitmask, 0xff, deliver_bitmask_size);
break;
case 3:
memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
apic_reset_bit(deliver_bitmask, s->id);
memset(deliver_bitmask, 0xff, deliver_bitmask_size);
apic_reset_bit(deliver_bitmask, current_apic_id);
break;
}
@ -555,6 +708,7 @@ static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode,
}
apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
g_free(deliver_bitmask);
}
static bool apic_check_pic(APICCommonState *s)
@ -636,27 +790,26 @@ static void apic_timer(void *opaque)
apic_timer_update(s, s->next_time);
}
static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size)
static int apic_register_read(int index, uint64_t *value)
{
DeviceState *dev;
APICCommonState *s;
uint32_t val;
int index;
if (size < 4) {
return 0;
}
int ret = 0;
dev = cpu_get_current_apic();
if (!dev) {
return 0;
return -1;
}
s = APIC(dev);
index = (addr >> 4) & 0xff;
switch(index) {
case 0x02: /* id */
val = s->id << 24;
if (is_x2apic_mode(dev)) {
val = s->initial_apic_id;
} else {
val = s->id << 24;
}
break;
case 0x03: /* version */
val = s->version | ((APIC_LVT_NB - 1) << 16);
@ -679,10 +832,19 @@ static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size)
val = 0;
break;
case 0x0d:
val = s->log_dest << 24;
if (is_x2apic_mode(dev)) {
val = s->extended_log_dest;
} else {
val = s->log_dest << 24;
}
break;
case 0x0e:
val = (s->dest_mode << 28) | 0xfffffff;
if (is_x2apic_mode(dev)) {
val = 0;
ret = -1;
} else {
val = (s->dest_mode << 28) | 0xfffffff;
}
break;
case 0x0f:
val = s->spurious_vec;
@ -718,17 +880,56 @@ static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size)
default:
s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
val = 0;
ret = -1;
break;
}
trace_apic_mem_readl(addr, val);
trace_apic_register_read(index, val);
*value = val;
return ret;
}
static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size)
{
uint64_t val;
int index;
if (size < 4) {
return 0;
}
index = (addr >> 4) & 0xff;
apic_register_read(index, &val);
return val;
}
int apic_msr_read(int index, uint64_t *val)
{
DeviceState *dev;
dev = cpu_get_current_apic();
if (!dev) {
return -1;
}
if (!is_x2apic_mode(dev)) {
return -1;
}
return apic_register_read(index, val);
}
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;
uint32_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
/*
* The higher 3 bytes of destination id is stored in higher word of
* msi address. See x86_iommu_irq_to_msi_message()
*/
dest = dest | (addr >> 32);
uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
@ -737,38 +938,25 @@ static void apic_send_msi(MSIMessage *msi)
apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
}
static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
static int apic_register_write(int index, uint64_t val)
{
DeviceState *dev;
APICCommonState *s;
int index = (addr >> 4) & 0xff;
if (size < 4) {
return;
}
if (addr > 0xfff || !index) {
/* MSI and MMIO APIC are at the same memory location,
* but actually not on the global bus: MSI is on PCI bus
* 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. */
MSIMessage msi = { .address = addr, .data = val };
apic_send_msi(&msi);
return;
}
dev = cpu_get_current_apic();
if (!dev) {
return;
return -1;
}
s = APIC(dev);
trace_apic_mem_writel(addr, val);
trace_apic_register_write(index, val);
switch(index) {
case 0x02:
if (is_x2apic_mode(dev)) {
return -1;
}
s->id = (val >> 24);
break;
case 0x03:
@ -788,9 +976,17 @@ static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val,
apic_eoi(s);
break;
case 0x0d:
if (is_x2apic_mode(dev)) {
return -1;
}
s->log_dest = val >> 24;
break;
case 0x0e:
if (is_x2apic_mode(dev)) {
return -1;
}
s->dest_mode = val >> 28;
break;
case 0x0f:
@ -802,13 +998,27 @@ static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val,
case 0x20 ... 0x27:
case 0x28:
break;
case 0x30:
case 0x30: {
uint32_t dest;
s->icr[0] = val;
apic_deliver(dev, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
if (is_x2apic_mode(dev)) {
s->icr[1] = val >> 32;
dest = s->icr[1];
} else {
dest = (s->icr[1] >> 24) & 0xff;
}
apic_deliver(dev, dest, (s->icr[0] >> 11) & 1,
(s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
(s->icr[0] >> 15) & 1);
(s->icr[0] >> 15) & 1, (s->icr[0] >> 18) & 3);
break;
}
case 0x31:
if (is_x2apic_mode(dev)) {
return -1;
}
s->icr[1] = val;
break;
case 0x32 ... 0x37:
@ -837,10 +1047,70 @@ static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val,
s->count_shift = (v + 1) & 7;
}
break;
default:
s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
case 0x3f: {
int vector = val & 0xff;
if (!is_x2apic_mode(dev)) {
return -1;
}
/*
* Self IPI is identical to IPI with
* - Destination shorthand: 1 (Self)
* - Trigger mode: 0 (Edge)
* - Delivery mode: 0 (Fixed)
*/
apic_deliver(dev, 0, 0, APIC_DM_FIXED, vector, 0, 1);
break;
}
default:
s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
return -1;
}
return 0;
}
static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
int index = (addr >> 4) & 0xff;
if (size < 4) {
return;
}
if (addr > 0xfff || !index) {
/*
* MSI and MMIO APIC are at the same memory location,
* but actually not on the global bus: MSI is on PCI bus
* 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.
*/
MSIMessage msi = { .address = addr, .data = val };
apic_send_msi(&msi);
return;
}
apic_register_write(index, val);
}
int apic_msr_write(int index, uint64_t val)
{
DeviceState *dev;
dev = cpu_get_current_apic();
if (!dev) {
return -1;
}
if (!is_x2apic_mode(dev)) {
return -1;
}
return apic_register_write(index, val);
}
static void apic_pre_save(APICCommonState *s)
@ -871,12 +1141,6 @@ static void apic_realize(DeviceState *dev, Error **errp)
{
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;
}
if (kvm_enabled()) {
warn_report("Userspace local APIC is deprecated for KVM.");
warn_report("Do not use kernel-irqchip except for the -M isapc machine type.");
@ -893,7 +1157,16 @@ static void apic_realize(DeviceState *dev, Error **errp)
s->io_memory.disable_reentrancy_guard = true;
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s);
local_apics[s->id] = s;
/*
* The --machine none does not call apic_set_max_apic_id before creating
* apic, so we need to call it here and set it to 1 which is the max cpus
* in machine none.
*/
if (!local_apics) {
apic_set_max_apic_id(1);
}
local_apics[s->initial_apic_id] = s;
msi_nonbroken = true;
}
@ -903,7 +1176,7 @@ static void apic_unrealize(DeviceState *dev)
APICCommonState *s = APIC(dev);
timer_free(s->timer);
local_apics[s->id] = NULL;
local_apics[s->initial_apic_id] = NULL;
}
static void apic_class_init(ObjectClass *klass, void *data)

View file

@ -35,20 +35,19 @@
bool apic_report_tpr_access;
void cpu_set_apic_base(DeviceState *dev, uint64_t val)
int cpu_set_apic_base(DeviceState *dev, uint64_t val)
{
trace_cpu_set_apic_base(val);
if (dev) {
APICCommonState *s = APIC_COMMON(dev);
APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
/* switching to x2APIC, reset possibly modified xAPIC ID */
if (!(s->apicbase & MSR_IA32_APICBASE_EXTD) &&
(val & MSR_IA32_APICBASE_EXTD)) {
s->id = s->initial_apic_id;
}
info->set_base(s, val);
/* Reset possibly modified xAPIC ID */
s->id = s->initial_apic_id;
return info->set_base(s, val);
}
return 0;
}
uint64_t cpu_get_apic_base(DeviceState *dev)
@ -63,6 +62,19 @@ uint64_t cpu_get_apic_base(DeviceState *dev)
}
}
bool cpu_is_apic_enabled(DeviceState *dev)
{
APICCommonState *s;
if (!dev) {
return false;
}
s = APIC_COMMON(dev);
return s->apicbase & MSR_IA32_APICBASE_ENABLE;
}
void cpu_set_apic_tpr(DeviceState *dev, uint8_t val)
{
APICCommonState *s;
@ -287,6 +299,10 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
}
vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common,
s, -1, 0, NULL);
/* APIC LDR in x2APIC mode */
s->extended_log_dest = ((s->initial_apic_id >> 4) << 16) |
(1 << (s->initial_apic_id & 0xf));
}
static void apic_common_unrealize(DeviceState *dev)
@ -427,6 +443,11 @@ static void apic_common_set_id(Object *obj, Visitor *v, const char *name,
return;
}
if (value >= 255 && !cpu_has_x2apic_feature(&s->cpu->env)) {
error_setg(errp, "APIC ID %d requires x2APIC feature in CPU", value);
return;
}
s->initial_apic_id = value;
s->id = (uint8_t)value;
}

View file

@ -14,8 +14,8 @@ cpu_get_apic_base(uint64_t val) "0x%016"PRIx64
# apic.c
apic_local_deliver(int vector, uint32_t lvt) "vector %d delivery mode %d"
apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode) "dest %d dest_mode %d delivery_mode %d vector %d trigger_mode %d"
apic_mem_readl(uint64_t addr, uint32_t val) "0x%"PRIx64" = 0x%08x"
apic_mem_writel(uint64_t addr, uint32_t val) "0x%"PRIx64" = 0x%08x"
apic_register_read(uint8_t reg, uint64_t val) "register 0x%02x = 0x%"PRIx64
apic_register_write(uint8_t reg, uint64_t val) "register 0x%02x = 0x%"PRIx64
# ioapic.c
ioapic_set_remote_irr(int n) "set remote irr for pin %d"