123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556 |
- #include "libcflat.h"
- #include "smp.h"
- #include "processor.h"
- #include "atomic.h"
- #include "pci.h"
- #include "x86/vm.h"
- #include "x86/desc.h"
- #include "x86/acpi.h"
- #include "x86/apic.h"
- #include "x86/isr.h"
- #define IPI_TEST_VECTOR 0xb0
- struct test {
- void (*func)(void);
- const char *name;
- int (*valid)(void);
- int parallel;
- bool (*next)(struct test *);
- };
- #define GOAL (1ull << 30)
- static int nr_cpus;
- static void cpuid_test(void)
- {
- asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx"
- : : : "eax", "ecx", "edx");
- }
- static void vmcall(void)
- {
- unsigned long a = 0, b, c, d;
- asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d));
- }
- #define MSR_TSC_ADJUST 0x3b
- #define MSR_EFER 0xc0000080
- #define EFER_NX_MASK (1ull << 11)
- #ifdef __x86_64__
- static void mov_from_cr8(void)
- {
- unsigned long cr8;
- asm volatile ("mov %%cr8, %0" : "=r"(cr8));
- }
- static void mov_to_cr8(void)
- {
- unsigned long cr8 = 0;
- asm volatile ("mov %0, %%cr8" : : "r"(cr8));
- }
- #endif
- static int is_smp(void)
- {
- return cpu_count() > 1;
- }
- static void nop(void *junk)
- {
- }
- volatile int x = 0;
- static void self_ipi_isr(isr_regs_t *regs)
- {
- x++;
- eoi();
- }
- static void x2apic_self_ipi(int vec)
- {
- wrmsr(0x83f, vec);
- }
- static void apic_self_ipi(int vec)
- {
- apic_icr_write(APIC_INT_ASSERT | APIC_DEST_SELF | APIC_DEST_PHYSICAL |
- APIC_DM_FIXED | IPI_TEST_VECTOR, vec);
- }
- static void self_ipi_sti_nop(void)
- {
- x = 0;
- irq_disable();
- apic_self_ipi(IPI_TEST_VECTOR);
- asm volatile("sti; nop");
- if (x != 1) printf("%d", x);
- }
- static void self_ipi_sti_hlt(void)
- {
- x = 0;
- irq_disable();
- apic_self_ipi(IPI_TEST_VECTOR);
- asm volatile("sti; hlt");
- if (x != 1) printf("%d", x);
- }
- static void self_ipi_tpr(void)
- {
- x = 0;
- apic_set_tpr(0x0f);
- apic_self_ipi(IPI_TEST_VECTOR);
- apic_set_tpr(0x00);
- asm volatile("nop");
- if (x != 1) printf("%d", x);
- }
- static void self_ipi_tpr_sti_nop(void)
- {
- x = 0;
- irq_disable();
- apic_set_tpr(0x0f);
- apic_self_ipi(IPI_TEST_VECTOR);
- apic_set_tpr(0x00);
- asm volatile("sti; nop");
- if (x != 1) printf("%d", x);
- }
- static void self_ipi_tpr_sti_hlt(void)
- {
- x = 0;
- irq_disable();
- apic_set_tpr(0x0f);
- apic_self_ipi(IPI_TEST_VECTOR);
- apic_set_tpr(0x00);
- asm volatile("sti; hlt");
- if (x != 1) printf("%d", x);
- }
- static int is_x2apic(void)
- {
- return rdmsr(MSR_IA32_APICBASE) & APIC_EXTD;
- }
- static void x2apic_self_ipi_sti_nop(void)
- {
- irq_disable();
- x2apic_self_ipi(IPI_TEST_VECTOR);
- asm volatile("sti; nop");
- }
- static void x2apic_self_ipi_sti_hlt(void)
- {
- irq_disable();
- x2apic_self_ipi(IPI_TEST_VECTOR);
- asm volatile("sti; hlt");
- }
- static void x2apic_self_ipi_tpr(void)
- {
- apic_set_tpr(0x0f);
- x2apic_self_ipi(IPI_TEST_VECTOR);
- apic_set_tpr(0x00);
- asm volatile("nop");
- }
- static void x2apic_self_ipi_tpr_sti_nop(void)
- {
- irq_disable();
- apic_set_tpr(0x0f);
- x2apic_self_ipi(IPI_TEST_VECTOR);
- apic_set_tpr(0x00);
- asm volatile("sti; nop");
- }
- static void x2apic_self_ipi_tpr_sti_hlt(void)
- {
- irq_disable();
- apic_set_tpr(0x0f);
- x2apic_self_ipi(IPI_TEST_VECTOR);
- apic_set_tpr(0x00);
- asm volatile("sti; hlt");
- }
- static void ipi(void)
- {
- on_cpu(1, nop, 0);
- }
- static void ipi_halt(void)
- {
- unsigned long long t;
- on_cpu(1, nop, 0);
- t = rdtsc() + 2000;
- while (rdtsc() < t)
- ;
- }
- int pm_tmr_blk;
- static void inl_pmtimer(void)
- {
- inl(pm_tmr_blk);
- }
- static void inl_nop_qemu(void)
- {
- inl(0x1234);
- }
- static void inl_nop_kernel(void)
- {
- inb(0x4d0);
- }
- static void outl_elcr_kernel(void)
- {
- outb(0, 0x4d0);
- }
- static void mov_dr(void)
- {
- asm volatile("mov %0, %%dr7" : : "r" (0x400L));
- }
- static void ple_round_robin(void)
- {
- struct counter {
- volatile int n1;
- int n2;
- } __attribute__((aligned(64)));
- static struct counter counters[64] = { { -1, 0 } };
- int me = smp_id();
- int you;
- volatile struct counter *p = &counters[me];
- while (p->n1 == p->n2)
- asm volatile ("pause");
- p->n2 = p->n1;
- you = me + 1;
- if (you == nr_cpus)
- you = 0;
- ++counters[you].n1;
- }
- static void rd_tsc_adjust_msr(void)
- {
- rdmsr(MSR_TSC_ADJUST);
- }
- static void wr_tsc_adjust_msr(void)
- {
- wrmsr(MSR_TSC_ADJUST, 0x0);
- }
- static struct pci_test {
- unsigned iobar;
- unsigned ioport;
- volatile void *memaddr;
- volatile void *mem;
- int test_idx;
- uint32_t data;
- uint32_t offset;
- } pci_test = {
- .test_idx = -1
- };
- static void pci_mem_testb(void)
- {
- *(volatile uint8_t *)pci_test.mem = pci_test.data;
- }
- static void pci_mem_testw(void)
- {
- *(volatile uint16_t *)pci_test.mem = pci_test.data;
- }
- static void pci_mem_testl(void)
- {
- *(volatile uint32_t *)pci_test.mem = pci_test.data;
- }
- static void pci_io_testb(void)
- {
- outb(pci_test.data, pci_test.ioport);
- }
- static void pci_io_testw(void)
- {
- outw(pci_test.data, pci_test.ioport);
- }
- static void pci_io_testl(void)
- {
- outl(pci_test.data, pci_test.ioport);
- }
- static uint8_t ioreadb(unsigned long addr, bool io)
- {
- if (io) {
- return inb(addr);
- } else {
- return *(volatile uint8_t *)addr;
- }
- }
- static uint32_t ioreadl(unsigned long addr, bool io)
- {
- /* Note: assumes little endian */
- if (io) {
- return inl(addr);
- } else {
- return *(volatile uint32_t *)addr;
- }
- }
- static void iowriteb(unsigned long addr, uint8_t data, bool io)
- {
- if (io) {
- outb(data, addr);
- } else {
- *(volatile uint8_t *)addr = data;
- }
- }
- static bool pci_next(struct test *test, unsigned long addr, bool io)
- {
- int i;
- uint8_t width;
- if (!pci_test.memaddr) {
- test->func = NULL;
- return true;
- }
- pci_test.test_idx++;
- iowriteb(addr + offsetof(struct pci_test_dev_hdr, test),
- pci_test.test_idx, io);
- width = ioreadb(addr + offsetof(struct pci_test_dev_hdr, width),
- io);
- switch (width) {
- case 1:
- test->func = io ? pci_io_testb : pci_mem_testb;
- break;
- case 2:
- test->func = io ? pci_io_testw : pci_mem_testw;
- break;
- case 4:
- test->func = io ? pci_io_testl : pci_mem_testl;
- break;
- default:
- /* Reset index for purposes of the next test */
- pci_test.test_idx = -1;
- test->func = NULL;
- return false;
- }
- pci_test.data = ioreadl(addr + offsetof(struct pci_test_dev_hdr, data),
- io);
- pci_test.offset = ioreadl(addr + offsetof(struct pci_test_dev_hdr,
- offset), io);
- for (i = 0; i < pci_test.offset; ++i) {
- char c = ioreadb(addr + offsetof(struct pci_test_dev_hdr,
- name) + i, io);
- if (!c) {
- break;
- }
- printf("%c",c);
- }
- printf(":");
- return true;
- }
- static bool pci_mem_next(struct test *test)
- {
- bool ret;
- ret = pci_next(test, ((unsigned long)pci_test.memaddr), false);
- if (ret) {
- pci_test.mem = pci_test.memaddr + pci_test.offset;
- }
- return ret;
- }
- static bool pci_io_next(struct test *test)
- {
- bool ret;
- ret = pci_next(test, ((unsigned long)pci_test.iobar), true);
- if (ret) {
- pci_test.ioport = pci_test.iobar + pci_test.offset;
- }
- return ret;
- }
- static int has_tscdeadline(void)
- {
- uint32_t lvtt;
- if (cpuid(1).c & (1 << 24)) {
- lvtt = APIC_LVT_TIMER_TSCDEADLINE | IPI_TEST_VECTOR;
- apic_write(APIC_LVTT, lvtt);
- return 1;
- } else {
- return 0;
- }
- }
- static void tscdeadline_immed(void)
- {
- wrmsr(MSR_IA32_TSCDEADLINE, rdtsc());
- asm volatile("nop");
- }
- static void tscdeadline(void)
- {
- x = 0;
- wrmsr(MSR_IA32_TSCDEADLINE, rdtsc()+3000);
- while (x == 0) barrier();
- }
- static struct test tests[] = {
- { cpuid_test, "cpuid", .parallel = 1, },
- { vmcall, "vmcall", .parallel = 1, },
- #ifdef __x86_64__
- { mov_from_cr8, "mov_from_cr8", .parallel = 1, },
- { mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
- #endif
- { inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
- { inl_nop_qemu, "inl_from_qemu", .parallel = 1 },
- { inl_nop_kernel, "inl_from_kernel", .parallel = 1 },
- { outl_elcr_kernel, "outl_to_kernel", .parallel = 1 },
- { mov_dr, "mov_dr", .parallel = 1 },
- { tscdeadline_immed, "tscdeadline_immed", has_tscdeadline, .parallel = 1, },
- { tscdeadline, "tscdeadline", has_tscdeadline, .parallel = 1, },
- { self_ipi_sti_nop, "self_ipi_sti_nop", .parallel = 0, },
- { self_ipi_sti_hlt, "self_ipi_sti_hlt", .parallel = 0, },
- { self_ipi_tpr, "self_ipi_tpr", .parallel = 0, },
- { self_ipi_tpr_sti_nop, "self_ipi_tpr_sti_nop", .parallel = 0, },
- { self_ipi_tpr_sti_hlt, "self_ipi_tpr_sti_hlt", .parallel = 0, },
- { x2apic_self_ipi_sti_nop, "x2apic_self_ipi_sti_nop", is_x2apic, .parallel = 0, },
- { x2apic_self_ipi_sti_hlt, "x2apic_self_ipi_sti_hlt", is_x2apic, .parallel = 0, },
- { x2apic_self_ipi_tpr, "x2apic_self_ipi_tpr", is_x2apic, .parallel = 0, },
- { x2apic_self_ipi_tpr_sti_nop, "x2apic_self_ipi_tpr_sti_nop", is_x2apic, .parallel = 0, },
- { x2apic_self_ipi_tpr_sti_hlt, "x2apic_self_ipi_tpr_sti_hlt", is_x2apic, .parallel = 0, },
- { ipi, "ipi", is_smp, .parallel = 0, },
- { ipi_halt, "ipi+halt", is_smp, .parallel = 0, },
- { ple_round_robin, "ple-round-robin", .parallel = 1 },
- { wr_tsc_adjust_msr, "wr_tsc_adjust_msr", .parallel = 1 },
- { rd_tsc_adjust_msr, "rd_tsc_adjust_msr", .parallel = 1 },
- { NULL, "pci-mem", .parallel = 0, .next = pci_mem_next },
- { NULL, "pci-io", .parallel = 0, .next = pci_io_next },
- };
- unsigned iterations;
- static void run_test(void *_func)
- {
- int i;
- void (*func)(void) = _func;
- for (i = 0; i < iterations; ++i)
- func();
- }
- static bool do_test(struct test *test)
- {
- int i;
- unsigned long long t1, t2;
- void (*func)(void);
- iterations = 32;
- if (test->valid && !test->valid()) {
- printf("%s (skipped)\n", test->name);
- return false;
- }
- if (test->next && !test->next(test)) {
- return false;
- }
- func = test->func;
- if (!func) {
- printf("%s (skipped)\n", test->name);
- return false;
- }
- do {
- iterations *= 2;
- t1 = rdtsc();
- if (!test->parallel) {
- for (i = 0; i < iterations; ++i)
- func();
- } else {
- on_cpus(run_test, func);
- }
- t2 = rdtsc();
- } while ((t2 - t1) < GOAL);
- printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
- return test->next;
- }
- static void enable_nx(void *junk)
- {
- if (cpuid(0x80000001).d & (1 << 20))
- wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
- }
- bool test_wanted(struct test *test, char *wanted[], int nwanted)
- {
- int i;
- if (!nwanted)
- return true;
- for (i = 0; i < nwanted; ++i)
- if (strcmp(wanted[i], test->name) == 0)
- return true;
- return false;
- }
- int main(int ac, char **av)
- {
- struct fadt_descriptor_rev1 *fadt;
- int i;
- unsigned long membar = 0;
- struct pci_dev pcidev;
- int ret;
- smp_init();
- setup_vm();
- handle_irq(IPI_TEST_VECTOR, self_ipi_isr);
- nr_cpus = cpu_count();
- irq_enable();
- on_cpus(enable_nx, NULL);
- fadt = find_acpi_table_addr(FACP_SIGNATURE);
- pm_tmr_blk = fadt->pm_tmr_blk;
- printf("PM timer port is %x\n", pm_tmr_blk);
- ret = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
- if (ret != PCIDEVADDR_INVALID) {
- pci_dev_init(&pcidev, ret);
- assert(pci_bar_is_memory(&pcidev, PCI_TESTDEV_BAR_MEM));
- assert(!pci_bar_is_memory(&pcidev, PCI_TESTDEV_BAR_IO));
- membar = pcidev.resource[PCI_TESTDEV_BAR_MEM];
- pci_test.memaddr = ioremap(membar, PAGE_SIZE);
- pci_test.iobar = pcidev.resource[PCI_TESTDEV_BAR_IO];
- printf("pci-testdev at %#x membar %lx iobar %x\n",
- pcidev.bdf, membar, pci_test.iobar);
- }
- for (i = 0; i < ARRAY_SIZE(tests); ++i)
- if (test_wanted(&tests[i], av + 1, ac - 1))
- while (do_test(&tests[i])) {}
- return 0;
- }
|