10c7c14a7SCyrill Gorcunov #include "kvm/kvm.h" 20c7c14a7SCyrill Gorcunov #include "kvm/bios.h" 30c7c14a7SCyrill Gorcunov #include "kvm/apic.h" 40c7c14a7SCyrill Gorcunov #include "kvm/mptable.h" 50c7c14a7SCyrill Gorcunov #include "kvm/util.h" 68ec7e042SSasha Levin #include "kvm/irq.h" 70c7c14a7SCyrill Gorcunov 8ab9e4f1cSSasha Levin #include <linux/kernel.h> 90c7c14a7SCyrill Gorcunov #include <string.h> 100c7c14a7SCyrill Gorcunov 11ca99b3d3SCyrill Gorcunov /* 12ca99b3d3SCyrill Gorcunov * If kernel is not configured yet this macro 13ca99b3d3SCyrill Gorcunov * might not be defined, fix it by own definition 14ca99b3d3SCyrill Gorcunov */ 15ca99b3d3SCyrill Gorcunov #ifndef NR_CPUS 16ca99b3d3SCyrill Gorcunov #define NR_CPUS KVM_NR_CPUS 17ca99b3d3SCyrill Gorcunov #endif 18ca99b3d3SCyrill Gorcunov 190c7c14a7SCyrill Gorcunov #include <asm/mpspec_def.h> 204749e795SSasha Levin #include <linux/types.h> 210c7c14a7SCyrill Gorcunov 220c7c14a7SCyrill Gorcunov /* 230c7c14a7SCyrill Gorcunov * FIXME: please make sure the addresses borrowed 240c7c14a7SCyrill Gorcunov * for apic/ioapic never overlaped! We need a global 250c7c14a7SCyrill Gorcunov * tracker of system resources (including io, mmio, 260c7c14a7SCyrill Gorcunov * and friends). 270c7c14a7SCyrill Gorcunov */ 280c7c14a7SCyrill Gorcunov 290c7c14a7SCyrill Gorcunov static unsigned int mpf_checksum(unsigned char *mp, int len) 300c7c14a7SCyrill Gorcunov { 310c7c14a7SCyrill Gorcunov unsigned int sum = 0; 320c7c14a7SCyrill Gorcunov 330c7c14a7SCyrill Gorcunov while (len--) 340c7c14a7SCyrill Gorcunov sum += *mp++; 350c7c14a7SCyrill Gorcunov 360c7c14a7SCyrill Gorcunov return sum & 0xFF; 370c7c14a7SCyrill Gorcunov } 380c7c14a7SCyrill Gorcunov 390c7c14a7SCyrill Gorcunov static unsigned int gen_cpu_flag(unsigned int cpu, unsigned int ncpu) 400c7c14a7SCyrill Gorcunov { 410c7c14a7SCyrill Gorcunov /* sets enabled/disabled | BSP/AP processor */ 420c7c14a7SCyrill Gorcunov return ( (cpu < ncpu) ? CPU_ENABLED : 0) | 430c7c14a7SCyrill Gorcunov ((cpu == 0) ? CPU_BOOTPROCESSOR : 0x00); 440c7c14a7SCyrill Gorcunov } 450c7c14a7SCyrill Gorcunov 460c7c14a7SCyrill Gorcunov #define MPTABLE_SIG_FLOATING "_MP_" 470c7c14a7SCyrill Gorcunov #define MPTABLE_OEM "KVMCPU00" 480c7c14a7SCyrill Gorcunov #define MPTABLE_PRODUCTID "0.1 " 490c7c14a7SCyrill Gorcunov #define MPTABLE_PCIBUSTYPE "PCI " 500c7c14a7SCyrill Gorcunov #define MPTABLE_ISABUSTYPE "ISA " 510c7c14a7SCyrill Gorcunov 520c7c14a7SCyrill Gorcunov #define MPTABLE_STRNCPY(d, s) memcpy(d, s, sizeof(d)) 530c7c14a7SCyrill Gorcunov 540c7c14a7SCyrill Gorcunov /* It should be more than enough */ 550c7c14a7SCyrill Gorcunov #define MPTABLE_MAX_SIZE (32 << 20) 560c7c14a7SCyrill Gorcunov 570c7c14a7SCyrill Gorcunov /* 580c7c14a7SCyrill Gorcunov * Too many cpus will require x2apic mode 590c7c14a7SCyrill Gorcunov * and rather ACPI support so we limit it 600c7c14a7SCyrill Gorcunov * here for a while. 610c7c14a7SCyrill Gorcunov */ 620c7c14a7SCyrill Gorcunov #define MPTABLE_MAX_CPUS 255 630c7c14a7SCyrill Gorcunov 644749e795SSasha Levin static void mptable_add_irq_src(struct mpc_intsrc *mpc_intsrc, 654749e795SSasha Levin u16 srcbusid, u16 srcbusirq, 664749e795SSasha Levin u16 dstapic, u16 dstirq) 674749e795SSasha Levin { 684749e795SSasha Levin *mpc_intsrc = (struct mpc_intsrc) { 694749e795SSasha Levin .type = MP_INTSRC, 704749e795SSasha Levin .irqtype = mp_INT, 714749e795SSasha Levin .irqflag = MP_IRQDIR_DEFAULT, 724749e795SSasha Levin .srcbus = srcbusid, 734749e795SSasha Levin .srcbusirq = srcbusirq, 744749e795SSasha Levin .dstapic = dstapic, 754749e795SSasha Levin .dstirq = dstirq 764749e795SSasha Levin }; 774749e795SSasha Levin } 784749e795SSasha Levin 790c7c14a7SCyrill Gorcunov /** 800c7c14a7SCyrill Gorcunov * mptable_setup - create mptable and fill guest memory with it 810c7c14a7SCyrill Gorcunov */ 820c7c14a7SCyrill Gorcunov void mptable_setup(struct kvm *kvm, unsigned int ncpus) 830c7c14a7SCyrill Gorcunov { 84*c13efdd6SCyrill Gorcunov unsigned long real_mpc_table, real_mpf_intel, size; 850c7c14a7SCyrill Gorcunov struct mpf_intel *mpf_intel; 860c7c14a7SCyrill Gorcunov struct mpc_table *mpc_table; 870c7c14a7SCyrill Gorcunov struct mpc_cpu *mpc_cpu; 880c7c14a7SCyrill Gorcunov struct mpc_bus *mpc_bus; 890c7c14a7SCyrill Gorcunov struct mpc_ioapic *mpc_ioapic; 900c7c14a7SCyrill Gorcunov struct mpc_intsrc *mpc_intsrc; 918ec7e042SSasha Levin struct rb_node *pci_tree; 920c7c14a7SCyrill Gorcunov 930c7c14a7SCyrill Gorcunov const int pcibusid = 0; 940c7c14a7SCyrill Gorcunov const int isabusid = 1; 950c7c14a7SCyrill Gorcunov 960c7c14a7SCyrill Gorcunov unsigned int i, nentries = 0; 970c7c14a7SCyrill Gorcunov unsigned int ioapicid; 980c7c14a7SCyrill Gorcunov void *last_addr; 990c7c14a7SCyrill Gorcunov 1000c7c14a7SCyrill Gorcunov /* That is where MP table will be in guest memory */ 1010c7c14a7SCyrill Gorcunov real_mpc_table = ALIGN(MB_BIOS_BEGIN + bios_rom_size, 16); 1020c7c14a7SCyrill Gorcunov 1030c7c14a7SCyrill Gorcunov if (ncpus > MPTABLE_MAX_CPUS) { 1044542f276SCyrill Gorcunov pr_warning("Too many cpus: %d limited to %d", 1050c7c14a7SCyrill Gorcunov ncpus, MPTABLE_MAX_CPUS); 1060c7c14a7SCyrill Gorcunov ncpus = MPTABLE_MAX_CPUS; 1070c7c14a7SCyrill Gorcunov } 1080c7c14a7SCyrill Gorcunov 1090c7c14a7SCyrill Gorcunov mpc_table = calloc(1, MPTABLE_MAX_SIZE); 1100c7c14a7SCyrill Gorcunov if (!mpc_table) 1110c7c14a7SCyrill Gorcunov die("Out of memory"); 1120c7c14a7SCyrill Gorcunov 1130c7c14a7SCyrill Gorcunov MPTABLE_STRNCPY(mpc_table->signature, MPC_SIGNATURE); 1140c7c14a7SCyrill Gorcunov MPTABLE_STRNCPY(mpc_table->oem, MPTABLE_OEM); 1150c7c14a7SCyrill Gorcunov MPTABLE_STRNCPY(mpc_table->productid, MPTABLE_PRODUCTID); 1160c7c14a7SCyrill Gorcunov 1170c7c14a7SCyrill Gorcunov mpc_table->spec = 4; 1180c7c14a7SCyrill Gorcunov mpc_table->lapic = APIC_ADDR(0); 1190c7c14a7SCyrill Gorcunov mpc_table->oemcount = ncpus; /* will be updated again at end */ 1200c7c14a7SCyrill Gorcunov 1210c7c14a7SCyrill Gorcunov /* 1220c7c14a7SCyrill Gorcunov * CPUs enumeration. Technically speaking we should 1230c7c14a7SCyrill Gorcunov * ask either host or HV for apic version supported 1240c7c14a7SCyrill Gorcunov * but for a while we simply put some random value 1250c7c14a7SCyrill Gorcunov * here. 1260c7c14a7SCyrill Gorcunov */ 1270c7c14a7SCyrill Gorcunov mpc_cpu = (void *)&mpc_table[1]; 1280c7c14a7SCyrill Gorcunov for (i = 0; i < ncpus; i++) { 1290c7c14a7SCyrill Gorcunov mpc_cpu->type = MP_PROCESSOR; 1300c7c14a7SCyrill Gorcunov mpc_cpu->apicid = i; 1310c7c14a7SCyrill Gorcunov mpc_cpu->apicver = KVM_APIC_VERSION; 1320c7c14a7SCyrill Gorcunov mpc_cpu->cpuflag = gen_cpu_flag(i, ncpus); 1330c7c14a7SCyrill Gorcunov mpc_cpu->cpufeature = 0x600; /* some default value */ 1340c7c14a7SCyrill Gorcunov mpc_cpu->featureflag = 0x201; /* some default value */ 1350c7c14a7SCyrill Gorcunov mpc_cpu++; 1360c7c14a7SCyrill Gorcunov } 1370c7c14a7SCyrill Gorcunov 1380c7c14a7SCyrill Gorcunov last_addr = (void *)mpc_cpu; 1390c7c14a7SCyrill Gorcunov nentries += ncpus; 1400c7c14a7SCyrill Gorcunov 1410c7c14a7SCyrill Gorcunov /* 1420c7c14a7SCyrill Gorcunov * PCI buses. 1430c7c14a7SCyrill Gorcunov * FIXME: Some callback here to obtain real number 1440c7c14a7SCyrill Gorcunov * of PCI buses present in system. 1450c7c14a7SCyrill Gorcunov */ 1460c7c14a7SCyrill Gorcunov mpc_bus = last_addr; 1470c7c14a7SCyrill Gorcunov mpc_bus->type = MP_BUS; 1480c7c14a7SCyrill Gorcunov mpc_bus->busid = pcibusid; 1490c7c14a7SCyrill Gorcunov MPTABLE_STRNCPY(mpc_bus->bustype, MPTABLE_PCIBUSTYPE); 1500c7c14a7SCyrill Gorcunov 1510c7c14a7SCyrill Gorcunov last_addr = (void *)&mpc_bus[1]; 1520c7c14a7SCyrill Gorcunov nentries++; 1530c7c14a7SCyrill Gorcunov 1540c7c14a7SCyrill Gorcunov /* 1550c7c14a7SCyrill Gorcunov * ISA bus. 1560c7c14a7SCyrill Gorcunov * FIXME: Same issue as for PCI bus. 1570c7c14a7SCyrill Gorcunov */ 1580c7c14a7SCyrill Gorcunov mpc_bus = last_addr; 1590c7c14a7SCyrill Gorcunov mpc_bus->type = MP_BUS; 1600c7c14a7SCyrill Gorcunov mpc_bus->busid = isabusid; 1610c7c14a7SCyrill Gorcunov MPTABLE_STRNCPY(mpc_bus->bustype, MPTABLE_ISABUSTYPE); 1620c7c14a7SCyrill Gorcunov 1630c7c14a7SCyrill Gorcunov last_addr = (void *)&mpc_bus[1]; 1640c7c14a7SCyrill Gorcunov nentries++; 1650c7c14a7SCyrill Gorcunov 1660c7c14a7SCyrill Gorcunov /* 1670c7c14a7SCyrill Gorcunov * IO-APIC chip. 1680c7c14a7SCyrill Gorcunov */ 1690c7c14a7SCyrill Gorcunov ioapicid = ncpus + 1; 1700c7c14a7SCyrill Gorcunov mpc_ioapic = last_addr; 1710c7c14a7SCyrill Gorcunov mpc_ioapic->type = MP_IOAPIC; 1720c7c14a7SCyrill Gorcunov mpc_ioapic->apicid = ioapicid; 1730c7c14a7SCyrill Gorcunov mpc_ioapic->apicver = KVM_APIC_VERSION; 1740c7c14a7SCyrill Gorcunov mpc_ioapic->flags = MPC_APIC_USABLE; 1750c7c14a7SCyrill Gorcunov mpc_ioapic->apicaddr = IOAPIC_ADDR(0); 1760c7c14a7SCyrill Gorcunov 1770c7c14a7SCyrill Gorcunov last_addr = (void *)&mpc_ioapic[1]; 1780c7c14a7SCyrill Gorcunov nentries++; 1790c7c14a7SCyrill Gorcunov 1800c7c14a7SCyrill Gorcunov /* 1810c7c14a7SCyrill Gorcunov * IRQ sources. 1820c7c14a7SCyrill Gorcunov * 1830c7c14a7SCyrill Gorcunov * FIXME: Same issue as with buses. We definitely 1840c7c14a7SCyrill Gorcunov * need kind of collector routine which enumerate 1850c7c14a7SCyrill Gorcunov * resources used first and pass them here. 1860c7c14a7SCyrill Gorcunov * At moment we know we have only virtio block device 1870c7c14a7SCyrill Gorcunov * and virtio console but this is g00berfish. 1880c7c14a7SCyrill Gorcunov * 1890c7c14a7SCyrill Gorcunov * Also note we use PCI irqs here, no for ISA bus yet. 1900c7c14a7SCyrill Gorcunov */ 1918ec7e042SSasha Levin 1928ec7e042SSasha Levin for (pci_tree = irq__get_pci_tree(); pci_tree; pci_tree = rb_next(pci_tree)) { 1938ec7e042SSasha Levin struct pci_dev *dev = rb_entry(pci_tree, struct pci_dev, node); 19468791d77SCyrill Gorcunov struct irq_line *irq_line; 1958ec7e042SSasha Levin 19668791d77SCyrill Gorcunov list_for_each_entry(irq_line, &dev->lines, node) { 19768791d77SCyrill Gorcunov unsigned char srcbusirq; 19868791d77SCyrill Gorcunov 19968791d77SCyrill Gorcunov srcbusirq = (dev->id << 2) | (dev->pin - 1); 20068791d77SCyrill Gorcunov 2010c7c14a7SCyrill Gorcunov mpc_intsrc = last_addr; 2020c7c14a7SCyrill Gorcunov 20368791d77SCyrill Gorcunov mptable_add_irq_src(mpc_intsrc, pcibusid, srcbusirq, ioapicid, irq_line->line); 2040c7c14a7SCyrill Gorcunov last_addr = (void *)&mpc_intsrc[1]; 2050c7c14a7SCyrill Gorcunov nentries++; 2064749e795SSasha Levin } 2078ec7e042SSasha Levin } 2080c7c14a7SCyrill Gorcunov 2090c7c14a7SCyrill Gorcunov /* 2100c7c14a7SCyrill Gorcunov * Local IRQs assignment (LINT0, LINT1) 2110c7c14a7SCyrill Gorcunov */ 2120c7c14a7SCyrill Gorcunov mpc_intsrc = last_addr; 2130c7c14a7SCyrill Gorcunov mpc_intsrc->type = MP_LINTSRC; 2140c7c14a7SCyrill Gorcunov mpc_intsrc->irqtype = mp_ExtINT; 2150c7c14a7SCyrill Gorcunov mpc_intsrc->irqtype = mp_INT; 2160c7c14a7SCyrill Gorcunov mpc_intsrc->irqflag = MP_IRQDIR_DEFAULT; 2170c7c14a7SCyrill Gorcunov mpc_intsrc->srcbus = isabusid; 2180c7c14a7SCyrill Gorcunov mpc_intsrc->srcbusirq = 0; 2190c7c14a7SCyrill Gorcunov mpc_intsrc->dstapic = 0; /* FIXME: BSP apic */ 2200c7c14a7SCyrill Gorcunov mpc_intsrc->dstirq = 0; /* LINT0 */ 2210c7c14a7SCyrill Gorcunov 2220c7c14a7SCyrill Gorcunov last_addr = (void *)&mpc_intsrc[1]; 2230c7c14a7SCyrill Gorcunov nentries++; 2240c7c14a7SCyrill Gorcunov 2250c7c14a7SCyrill Gorcunov mpc_intsrc = last_addr; 2260c7c14a7SCyrill Gorcunov mpc_intsrc->type = MP_LINTSRC; 2270c7c14a7SCyrill Gorcunov mpc_intsrc->irqtype = mp_NMI; 2280c7c14a7SCyrill Gorcunov mpc_intsrc->irqflag = MP_IRQDIR_DEFAULT; 2290c7c14a7SCyrill Gorcunov mpc_intsrc->srcbus = isabusid; 2300c7c14a7SCyrill Gorcunov mpc_intsrc->srcbusirq = 0; 2310c7c14a7SCyrill Gorcunov mpc_intsrc->dstapic = 0; /* FIXME: BSP apic */ 2320c7c14a7SCyrill Gorcunov mpc_intsrc->dstirq = 1; /* LINT1 */ 2330c7c14a7SCyrill Gorcunov 2340c7c14a7SCyrill Gorcunov last_addr = (void *)&mpc_intsrc[1]; 2350c7c14a7SCyrill Gorcunov nentries++; 2360c7c14a7SCyrill Gorcunov 2370c7c14a7SCyrill Gorcunov /* 2380c7c14a7SCyrill Gorcunov * Floating MP table finally. 2390c7c14a7SCyrill Gorcunov */ 240*c13efdd6SCyrill Gorcunov real_mpf_intel = ALIGN((unsigned long)last_addr - (unsigned long)mpc_table, 16); 241*c13efdd6SCyrill Gorcunov mpf_intel = (void *)((unsigned long)mpc_table + real_mpf_intel); 2420c7c14a7SCyrill Gorcunov 2430c7c14a7SCyrill Gorcunov MPTABLE_STRNCPY(mpf_intel->signature, MPTABLE_SIG_FLOATING); 2440c7c14a7SCyrill Gorcunov mpf_intel->length = 1; 2450c7c14a7SCyrill Gorcunov mpf_intel->specification= 4; 2460c7c14a7SCyrill Gorcunov mpf_intel->physptr = (unsigned int)real_mpc_table; 2470c7c14a7SCyrill Gorcunov mpf_intel->checksum = -mpf_checksum((unsigned char *)mpf_intel, sizeof(*mpf_intel)); 2480c7c14a7SCyrill Gorcunov 2490c7c14a7SCyrill Gorcunov /* 2500c7c14a7SCyrill Gorcunov * No last_addr inclrement here please, we need last 2510c7c14a7SCyrill Gorcunov * active position here to compute table size. 2520c7c14a7SCyrill Gorcunov */ 2530c7c14a7SCyrill Gorcunov 2540c7c14a7SCyrill Gorcunov /* 2550c7c14a7SCyrill Gorcunov * Don't forget to update header in fixed table. 2560c7c14a7SCyrill Gorcunov */ 2570c7c14a7SCyrill Gorcunov mpc_table->oemcount = nentries; 2580c7c14a7SCyrill Gorcunov mpc_table->length = last_addr - (void *)mpc_table; 2590c7c14a7SCyrill Gorcunov mpc_table->checksum = -mpf_checksum((unsigned char *)mpc_table, mpc_table->length); 2600c7c14a7SCyrill Gorcunov 2610c7c14a7SCyrill Gorcunov 2620c7c14a7SCyrill Gorcunov /* 2630c7c14a7SCyrill Gorcunov * We will copy the whole table, no need to separate 26443835ac9SSasha Levin * floating structure and table itkvm. 2650c7c14a7SCyrill Gorcunov */ 2660c7c14a7SCyrill Gorcunov size = (unsigned long)mpf_intel + sizeof(*mpf_intel) - (unsigned long)mpc_table; 2670c7c14a7SCyrill Gorcunov 2680c7c14a7SCyrill Gorcunov /* 2690c7c14a7SCyrill Gorcunov * The finial check -- never get out of system bios 2700c7c14a7SCyrill Gorcunov * area. Lets also check for allocated memory overrun, 2710c7c14a7SCyrill Gorcunov * in real it's late but still usefull. 2720c7c14a7SCyrill Gorcunov */ 2730c7c14a7SCyrill Gorcunov 2740c7c14a7SCyrill Gorcunov if (size > (unsigned long)(MB_BIOS_END - bios_rom_size) || 2750c7c14a7SCyrill Gorcunov size > MPTABLE_MAX_SIZE) 2760c7c14a7SCyrill Gorcunov die("MP table is too big"); 2770c7c14a7SCyrill Gorcunov 2780c7c14a7SCyrill Gorcunov /* 2790c7c14a7SCyrill Gorcunov * OK, it is time to move it to guest memory. 2800c7c14a7SCyrill Gorcunov */ 2810c7c14a7SCyrill Gorcunov memcpy(guest_flat_to_host(kvm, real_mpc_table), mpc_table, size); 2820c7c14a7SCyrill Gorcunov 2830c7c14a7SCyrill Gorcunov free(mpc_table); 2840c7c14a7SCyrill Gorcunov } 285