Revision 54c96da7
b/hw/apic.c | ||
---|---|---|
19 | 19 |
*/ |
20 | 20 |
#include "hw.h" |
21 | 21 |
#include "pc.h" |
22 |
#include "pci.h" |
|
23 |
#include "msix.h" |
|
22 | 24 |
#include "qemu-timer.h" |
23 | 25 |
#include "host-utils.h" |
24 | 26 |
|
... | ... | |
63 | 65 |
#define MAX_APICS 255 |
64 | 66 |
#define MAX_APIC_WORDS 8 |
65 | 67 |
|
68 |
/* Intel APIC constants: from include/asm/msidef.h */ |
|
69 |
#define MSI_DATA_VECTOR_SHIFT 0 |
|
70 |
#define MSI_DATA_VECTOR_MASK 0x000000ff |
|
71 |
#define MSI_DATA_DELIVERY_MODE_SHIFT 8 |
|
72 |
#define MSI_DATA_TRIGGER_SHIFT 15 |
|
73 |
#define MSI_DATA_LEVEL_SHIFT 14 |
|
74 |
#define MSI_ADDR_DEST_MODE_SHIFT 2 |
|
75 |
#define MSI_ADDR_DEST_ID_SHIFT 12 |
|
76 |
#define MSI_ADDR_DEST_ID_MASK 0x00ffff0 |
|
77 |
|
|
78 |
#define MSI_ADDR_BASE 0xfee00000 |
|
79 |
#define MSI_ADDR_SIZE 0x100000 |
|
80 |
|
|
66 | 81 |
typedef struct APICState { |
67 | 82 |
CPUState *cpu_env; |
68 | 83 |
uint32_t apicbase; |
... | ... | |
745 | 760 |
return val; |
746 | 761 |
} |
747 | 762 |
|
763 |
static void apic_send_msi(target_phys_addr_t addr, uint32 data) |
|
764 |
{ |
|
765 |
uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; |
|
766 |
uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; |
|
767 |
uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1; |
|
768 |
uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1; |
|
769 |
uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7; |
|
770 |
/* XXX: Ignore redirection hint. */ |
|
771 |
apic_deliver_irq(dest, dest_mode, delivery, vector, 0, trigger_mode); |
|
772 |
} |
|
773 |
|
|
748 | 774 |
static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
749 | 775 |
{ |
750 | 776 |
CPUState *env; |
751 | 777 |
APICState *s; |
752 |
int index; |
|
778 |
int index = (addr >> 4) & 0xff; |
|
779 |
if (addr > 0xfff || !index) { |
|
780 |
/* MSI and MMIO APIC are at the same memory location, |
|
781 |
* but actually not on the global bus: MSI is on PCI bus |
|
782 |
* APIC is connected directly to the CPU. |
|
783 |
* Mapping them on the global bus happens to work because |
|
784 |
* MSI registers are reserved in APIC MMIO and vice versa. */ |
|
785 |
apic_send_msi(addr, val); |
|
786 |
return; |
|
787 |
} |
|
753 | 788 |
|
754 | 789 |
env = cpu_single_env; |
755 | 790 |
if (!env) |
... | ... | |
760 | 795 |
printf("APIC write: %08x = %08x\n", (uint32_t)addr, val); |
761 | 796 |
#endif |
762 | 797 |
|
763 |
index = (addr >> 4) & 0xff; |
|
764 | 798 |
switch(index) { |
765 | 799 |
case 0x02: |
766 | 800 |
s->id = (val >> 24); |
... | ... | |
946 | 980 |
s->cpu_env = env; |
947 | 981 |
|
948 | 982 |
apic_reset(s); |
983 |
msix_supported = 1; |
|
949 | 984 |
|
950 | 985 |
/* XXX: mapping more APICs at the same memory location */ |
951 | 986 |
if (apic_io_memory == 0) { |
... | ... | |
953 | 988 |
on the global memory bus. */ |
954 | 989 |
apic_io_memory = cpu_register_io_memory(apic_mem_read, |
955 | 990 |
apic_mem_write, NULL); |
956 |
cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, |
|
991 |
/* XXX: what if the base changes? */ |
|
992 |
cpu_register_physical_memory(MSI_ADDR_BASE, MSI_ADDR_SIZE, |
|
957 | 993 |
apic_io_memory); |
958 | 994 |
} |
959 | 995 |
s->timer = qemu_new_timer(vm_clock, apic_timer, s); |
... | ... | |
964 | 1000 |
local_apics[s->idx] = s; |
965 | 1001 |
return 0; |
966 | 1002 |
} |
967 |
|
Also available in: Unified diff