Revision 8546b099 hw/apic.c
b/hw/apic.c | ||
---|---|---|
17 | 17 |
* License along with this library; if not, see <http://www.gnu.org/licenses/> |
18 | 18 |
*/ |
19 | 19 |
#include "hw.h" |
20 |
#include "pc.h" |
|
21 | 20 |
#include "apic.h" |
22 |
#include "pci.h" |
|
23 | 21 |
#include "msix.h" |
24 | 22 |
#include "qemu-timer.h" |
25 | 23 |
#include "host-utils.h" |
26 |
#include "kvm.h"
|
|
24 |
#include "sysbus.h"
|
|
27 | 25 |
|
28 | 26 |
//#define DEBUG_APIC |
29 | 27 |
//#define DEBUG_COALESCING |
... | ... | |
95 | 93 |
#define MSI_ADDR_SIZE 0x100000 |
96 | 94 |
|
97 | 95 |
struct APICState { |
98 |
CPUState *cpu_env; |
|
96 |
SysBusDevice busdev; |
|
97 |
void *cpu_env; |
|
99 | 98 |
uint32_t apicbase; |
100 | 99 |
uint8_t id; |
101 | 100 |
uint8_t arb_id; |
... | ... | |
120 | 119 |
int wait_for_sipi; |
121 | 120 |
}; |
122 | 121 |
|
123 |
static int apic_io_memory; |
|
124 | 122 |
static APICState *local_apics[MAX_APICS + 1]; |
125 |
static int last_apic_idx = 0; |
|
126 | 123 |
static int apic_irq_delivered; |
127 | 124 |
|
128 |
|
|
129 | 125 |
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode); |
130 | 126 |
static void apic_update_irq(APICState *s); |
131 | 127 |
static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, |
... | ... | |
930 | 926 |
} |
931 | 927 |
}; |
932 | 928 |
|
933 |
static void apic_reset(void *opaque)
|
|
929 |
static void apic_reset(DeviceState *d)
|
|
934 | 930 |
{ |
935 |
APICState *s = opaque;
|
|
931 |
APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
|
|
936 | 932 |
int bsp; |
937 | 933 |
|
938 | 934 |
bsp = cpu_is_bsp(s->cpu_env); |
... | ... | |
963 | 959 |
apic_mem_writel, |
964 | 960 |
}; |
965 | 961 |
|
966 |
APICState *apic_init(CPUState *env, uint32_t apic_id)
|
|
962 |
APICState *apic_init(void *env, uint8_t apic_id)
|
|
967 | 963 |
{ |
964 |
DeviceState *dev; |
|
965 |
SysBusDevice *d; |
|
968 | 966 |
APICState *s; |
967 |
static int apic_mapped; |
|
969 | 968 |
|
970 |
if (last_apic_idx >= MAX_APICS) { |
|
971 |
return NULL; |
|
972 |
} |
|
973 |
s = qemu_mallocz(sizeof(APICState)); |
|
974 |
s->idx = last_apic_idx++; |
|
975 |
s->id = apic_id; |
|
976 |
s->cpu_env = env; |
|
977 |
|
|
978 |
msix_supported = 1; |
|
969 |
dev = qdev_create(NULL, "apic"); |
|
970 |
qdev_prop_set_uint8(dev, "id", apic_id); |
|
971 |
qdev_prop_set_ptr(dev, "cpu_env", env); |
|
972 |
qdev_init_nofail(dev); |
|
973 |
d = sysbus_from_qdev(dev); |
|
979 | 974 |
|
980 | 975 |
/* XXX: mapping more APICs at the same memory location */ |
981 |
if (apic_io_memory == 0) {
|
|
976 |
if (apic_mapped == 0) {
|
|
982 | 977 |
/* NOTE: the APIC is directly connected to the CPU - it is not |
983 | 978 |
on the global memory bus. */ |
984 |
apic_io_memory = cpu_register_io_memory(apic_mem_read, |
|
985 |
apic_mem_write, NULL); |
|
986 | 979 |
/* XXX: what if the base changes? */ |
987 |
cpu_register_physical_memory(MSI_ADDR_BASE, MSI_ADDR_SIZE,
|
|
988 |
apic_io_memory);
|
|
980 |
sysbus_mmio_map(d, 0, MSI_ADDR_BASE);
|
|
981 |
apic_mapped = 1;
|
|
989 | 982 |
} |
990 |
s->timer = qemu_new_timer(vm_clock, apic_timer, s); |
|
991 | 983 |
|
992 |
vmstate_register(s->idx, &vmstate_apic, s); |
|
993 |
qemu_register_reset(apic_reset, s); |
|
984 |
msix_supported = 1; |
|
985 |
|
|
986 |
s = DO_UPCAST(APICState, busdev.qdev, dev); |
|
994 | 987 |
|
995 |
local_apics[s->idx] = s; |
|
996 | 988 |
return s; |
997 | 989 |
} |
990 |
|
|
991 |
static int apic_init1(SysBusDevice *dev) |
|
992 |
{ |
|
993 |
APICState *s = FROM_SYSBUS(APICState, dev); |
|
994 |
int apic_io_memory; |
|
995 |
static int last_apic_idx; |
|
996 |
|
|
997 |
if (last_apic_idx >= MAX_APICS) { |
|
998 |
return -1; |
|
999 |
} |
|
1000 |
apic_io_memory = cpu_register_io_memory(apic_mem_read, |
|
1001 |
apic_mem_write, NULL); |
|
1002 |
sysbus_init_mmio(dev, MSI_ADDR_SIZE, apic_io_memory); |
|
1003 |
|
|
1004 |
s->timer = qemu_new_timer(vm_clock, apic_timer, s); |
|
1005 |
s->idx = last_apic_idx++; |
|
1006 |
local_apics[s->idx] = s; |
|
1007 |
return 0; |
|
1008 |
} |
|
1009 |
|
|
1010 |
static SysBusDeviceInfo apic_info = { |
|
1011 |
.init = apic_init1, |
|
1012 |
.qdev.name = "apic", |
|
1013 |
.qdev.size = sizeof(APICState), |
|
1014 |
.qdev.vmsd = &vmstate_apic, |
|
1015 |
.qdev.reset = apic_reset, |
|
1016 |
.qdev.no_user = 1, |
|
1017 |
.qdev.props = (Property[]) { |
|
1018 |
DEFINE_PROP_UINT8("id", APICState, id, -1), |
|
1019 |
DEFINE_PROP_PTR("cpu_env", APICState, cpu_env), |
|
1020 |
DEFINE_PROP_END_OF_LIST(), |
|
1021 |
} |
|
1022 |
}; |
|
1023 |
|
|
1024 |
static void apic_register_devices(void) |
|
1025 |
{ |
|
1026 |
sysbus_register_withprop(&apic_info); |
|
1027 |
} |
|
1028 |
|
|
1029 |
device_init(apic_register_devices) |
Also available in: Unified diff