From 03f98a25183e9833eaa1796b97ae250a7bb4009a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 30 Jul 2020 18:00:46 -0400 Subject: [PATCH] retire repo Switching to gitlab. Signed-off-by: Paolo Bonzini --- .editorconfig | 15 - .gitignore | 24 - .gitlab-ci.yml | 101 - .travis.yml | 122 - COPYRIGHT | 10 - MAINTAINERS | 94 - Makefile | 131 - README.macOS.md | 47 - arm/Makefile | 1 - arm/Makefile.arm | 32 - arm/Makefile.arm64 | 34 - arm/Makefile.common | 86 - arm/cache.c | 123 - arm/cstart.S | 369 - arm/cstart64.S | 344 - arm/flat.lds | 43 - arm/gic.c | 1003 --- arm/micro-bench.c | 215 - arm/pci-test.c | 34 - arm/pl031.c | 263 - arm/pmu.c | 1077 --- arm/psci.c | 164 - arm/run | 66 - arm/selftest.c | 482 -- arm/sieve.c | 1 - arm/spinlock-test.c | 87 - arm/timer.c | 389 -- arm/unittests.cfg | 243 - configure | 227 - errata.txt | 9 - lib/abort.c | 20 - lib/alloc.c | 105 - lib/alloc.h | 38 - lib/alloc_page.c | 177 - lib/alloc_page.h | 19 - lib/alloc_phys.c | 143 - lib/alloc_phys.h | 53 - lib/argv.c | 151 - lib/argv.h | 11 - lib/arm/.gitignore | 1 - lib/arm/asm-offsets.c | 34 - lib/arm/asm/arch_gicv3.h | 65 - lib/arm/asm/asm-offsets.h | 1 - lib/arm/asm/barrier.h | 28 - lib/arm/asm/bitops.h | 55 - lib/arm/asm/cpumask.h | 118 - lib/arm/asm/delay.h | 14 - lib/arm/asm/gic-v2.h | 42 - lib/arm/asm/gic-v3-its.h | 27 - lib/arm/asm/gic-v3.h | 154 - lib/arm/asm/gic.h | 91 - lib/arm/asm/io.h | 94 - lib/arm/asm/mmu-api.h | 26 - lib/arm/asm/mmu.h | 53 - lib/arm/asm/page.h | 47 - lib/arm/asm/pci.h | 1 - lib/arm/asm/pgtable-hwdef.h | 122 - lib/arm/asm/pgtable.h | 105 - lib/arm/asm/processor.h | 94 - lib/arm/asm/psci.h | 14 - lib/arm/asm/ptrace.h | 104 - lib/arm/asm/setup.h | 39 - lib/arm/asm/smp.h | 57 - lib/arm/asm/spinlock.h | 11 - lib/arm/asm/stack.h | 11 - lib/arm/asm/sysreg.h | 65 - lib/arm/asm/thread_info.h | 75 - lib/arm/bitops.c | 82 - lib/arm/delay.c | 30 - lib/arm/eabi_compat.c | 29 - lib/arm/gic-v2.c | 57 - lib/arm/gic-v3.c | 227 - lib/arm/gic.c | 250 - lib/arm/io.c | 132 - lib/arm/io.h | 7 - lib/arm/mmu.c | 234 - lib/arm/processor.c | 147 - lib/arm/psci.c | 58 - lib/arm/setup.c | 224 - lib/arm/smp.c | 211 - lib/arm/spinlock.c | 41 - lib/arm/stack.c | 41 - lib/arm64/.gitignore | 1 - lib/arm64/asm-offsets.c | 30 - lib/arm64/asm/arch_gicv3.h | 64 - lib/arm64/asm/asm-offsets.h | 1 - lib/arm64/asm/barrier.h | 27 - lib/arm64/asm/bitops.h | 53 - lib/arm64/asm/cpumask.h | 1 - lib/arm64/asm/delay.h | 1 - lib/arm64/asm/esr.h | 50 - lib/arm64/asm/gic-v2.h | 1 - lib/arm64/asm/gic-v3-its.h | 174 - lib/arm64/asm/gic-v3.h | 1 - lib/arm64/asm/gic.h | 1 - lib/arm64/asm/io.h | 88 - lib/arm64/asm/mmu-api.h | 1 - lib/arm64/asm/mmu.h | 37 - lib/arm64/asm/page.h | 55 - lib/arm64/asm/pci.h | 1 - lib/arm64/asm/pgtable-hwdef.h | 131 - lib/arm64/asm/pgtable.h | 86 - lib/arm64/asm/processor.h | 121 - lib/arm64/asm/psci.h | 1 - lib/arm64/asm/ptrace.h | 99 - lib/arm64/asm/setup.h | 1 - lib/arm64/asm/smp.h | 1 - lib/arm64/asm/spinlock.h | 11 - lib/arm64/asm/stack.h | 8 - lib/arm64/asm/sysreg.h | 73 - lib/arm64/asm/thread_info.h | 1 - lib/arm64/gic-v3-its-cmd.c | 459 -- lib/arm64/gic-v3-its.c | 171 - lib/arm64/processor.c | 259 - lib/arm64/spinlock.c | 43 - lib/asm-generic/atomic.h | 21 - lib/asm-generic/barrier.h | 35 - lib/asm-generic/io.h | 213 - lib/asm-generic/page.h | 29 - lib/asm-generic/pci-host-bridge.h | 28 - lib/asm-generic/pci.h | 4 - lib/asm-generic/spinlock.h | 18 - lib/auxinfo.c | 13 - lib/auxinfo.h | 18 - lib/bitops.h | 87 - lib/chr-testdev.c | 73 - lib/chr-testdev.h | 14 - lib/devicetree.c | 334 - lib/devicetree.h | 251 - lib/errata.h | 56 - lib/generated/.gitignore | 1 - lib/getchar.c | 11 - lib/kbuild.h | 8 - lib/libcflat.h | 159 - lib/libfdt/Makefile.libfdt | 10 - lib/libfdt/README | 4 - lib/libfdt/fdt.c | 250 - lib/libfdt/fdt.h | 111 - lib/libfdt/fdt_empty_tree.c | 84 - lib/libfdt/fdt_ro.c | 573 -- lib/libfdt/fdt_rw.c | 492 -- lib/libfdt/fdt_strerror.c | 96 - lib/libfdt/fdt_sw.c | 256 - lib/libfdt/fdt_wip.c | 118 - lib/libfdt/libfdt.h | 1514 ----- lib/libfdt/libfdt_env.h | 111 - lib/libfdt/libfdt_internal.h | 95 - lib/libfdt/version.lds | 60 - lib/linux/compiler.h | 83 - lib/linux/const.h | 27 - lib/linux/pci_regs.h | 949 --- lib/linux/psci.h | 108 - lib/pci-edu.c | 73 - lib/pci-edu.h | 86 - lib/pci-host-generic.c | 320 - lib/pci-host-generic.h | 46 - lib/pci-testdev.c | 194 - lib/pci.c | 386 -- lib/pci.h | 105 - lib/powerpc/.gitignore | 1 - lib/powerpc/asm/handlers.h | 8 - lib/powerpc/asm/hcall.h | 46 - lib/powerpc/asm/ppc_asm.h | 38 - lib/powerpc/asm/processor.h | 30 - lib/powerpc/asm/rtas.h | 32 - lib/powerpc/asm/setup.h | 32 - lib/powerpc/asm/smp.h | 22 - lib/powerpc/asm/stack.h | 8 - lib/powerpc/handlers.c | 23 - lib/powerpc/hcall.c | 47 - lib/powerpc/io.c | 44 - lib/powerpc/io.h | 8 - lib/powerpc/processor.c | 56 - lib/powerpc/rtas.c | 135 - lib/powerpc/setup.c | 218 - lib/powerpc/smp.c | 104 - lib/ppc64/.gitignore | 1 - lib/ppc64/asm-offsets.c | 54 - lib/ppc64/asm/asm-offsets.h | 1 - lib/ppc64/asm/barrier.h | 9 - lib/ppc64/asm/bitops.h | 12 - lib/ppc64/asm/handlers.h | 1 - lib/ppc64/asm/hcall.h | 1 - lib/ppc64/asm/io.h | 15 - lib/ppc64/asm/page.h | 1 - lib/ppc64/asm/ppc_asm.h | 1 - lib/ppc64/asm/processor.h | 1 - lib/ppc64/asm/ptrace.h | 24 - lib/ppc64/asm/rtas.h | 1 - lib/ppc64/asm/setup.h | 1 - lib/ppc64/asm/smp.h | 1 - lib/ppc64/asm/spinlock.h | 6 - lib/ppc64/asm/stack.h | 8 - lib/printf.c | 322 - lib/report.c | 185 - lib/s390x/.gitignore | 1 - lib/s390x/asm-offsets.c | 76 - lib/s390x/asm/arch_def.h | 300 - lib/s390x/asm/asm-offsets.h | 10 - lib/s390x/asm/barrier.h | 16 - lib/s390x/asm/bitops.h | 10 - lib/s390x/asm/cpacf.h | 472 -- lib/s390x/asm/facility.h | 48 - lib/s390x/asm/float.h | 51 - lib/s390x/asm/interrupt.h | 40 - lib/s390x/asm/io.h | 18 - lib/s390x/asm/mem.h | 85 - lib/s390x/asm/page.h | 40 - lib/s390x/asm/pgtable.h | 224 - lib/s390x/asm/sigp.h | 78 - lib/s390x/asm/spinlock.h | 16 - lib/s390x/asm/stack.h | 21 - lib/s390x/interrupt.c | 157 - lib/s390x/io.c | 51 - lib/s390x/mmu.c | 151 - lib/s390x/mmu.h | 20 - lib/s390x/sclp-console.c | 232 - lib/s390x/sclp.c | 174 - lib/s390x/sclp.h | 279 - lib/s390x/smp.c | 271 - lib/s390x/smp.h | 53 - lib/s390x/stack.c | 28 - lib/setjmp.h | 18 - lib/stack.c | 103 - lib/stack.h | 27 - lib/string.c | 223 - lib/string.h | 23 - lib/util.c | 19 - lib/util.h | 23 - lib/virtio-mmio.c | 179 - lib/virtio-mmio.h | 65 - lib/virtio.c | 130 - lib/virtio.h | 150 - lib/vmalloc.c | 153 - lib/vmalloc.h | 28 - lib/x86/acpi.c | 52 - lib/x86/acpi.h | 104 - lib/x86/apic-defs.h | 147 - lib/x86/apic.c | 245 - lib/x86/apic.h | 98 - lib/x86/asm/barrier.h | 27 - lib/x86/asm/bitops.h | 16 - lib/x86/asm/io.h | 65 - lib/x86/asm/page.h | 55 - lib/x86/asm/pci.h | 59 - lib/x86/asm/spinlock.h | 6 - lib/x86/asm/stack.h | 11 - lib/x86/atomic.c | 37 - lib/x86/atomic.h | 166 - lib/x86/delay.c | 11 - lib/x86/delay.h | 15 - lib/x86/desc.c | 412 -- lib/x86/desc.h | 241 - lib/x86/fault_test.c | 52 - lib/x86/fault_test.h | 42 - lib/x86/fwcfg.c | 83 - lib/x86/fwcfg.h | 53 - lib/x86/intel-iommu.c | 365 - lib/x86/intel-iommu.h | 148 - lib/x86/io.c | 121 - lib/x86/isr.c | 125 - lib/x86/isr.h | 14 - lib/x86/msr.h | 434 -- lib/x86/processor.h | 611 -- lib/x86/setjmp32.S | 25 - lib/x86/setjmp64.S | 27 - lib/x86/setup.c | 133 - lib/x86/smp.c | 148 - lib/x86/smp.h | 15 - lib/x86/stack.c | 31 - lib/x86/usermode.c | 113 - lib/x86/usermode.h | 30 - lib/x86/vm.c | 258 - lib/x86/vm.h | 48 - powerpc/.gitignore | 1 - powerpc/Makefile | 1 - powerpc/Makefile.common | 81 - powerpc/Makefile.ppc64 | 27 - powerpc/boot_rom.S | 6 - powerpc/cstart64.S | 276 - powerpc/emulator.c | 373 - powerpc/flat.lds | 57 - powerpc/reloc64.c | 57 - powerpc/rtas.c | 150 - powerpc/run | 34 - powerpc/selftest.c | 64 - powerpc/spapr.h | 6 - powerpc/spapr_hcall.c | 171 - powerpc/sprs.c | 308 - powerpc/tm.c | 169 - powerpc/unittests.cfg | 72 - run_tests.sh | 170 - s390x/Makefile | 75 - s390x/cmm.c | 74 - s390x/cpumodel.c | 60 - s390x/cstart64.S | 216 - s390x/diag10.c | 104 - s390x/diag288.c | 114 - s390x/diag308.c | 119 - s390x/emulator.c | 330 - s390x/flat.lds | 59 - s390x/gs.c | 181 - s390x/iep.c | 66 - s390x/intercept.c | 247 - s390x/pfmf.c | 140 - s390x/run | 26 - s390x/sclp.c | 479 -- s390x/selftest.c | 86 - s390x/sieve.c | 1 - s390x/skey.c | 139 - s390x/skrf.c | 128 - s390x/smp.c | 350 - s390x/sthyi.c | 187 - s390x/sthyi.h | 131 - s390x/stsi.c | 159 - s390x/unittests.cfg | 86 - s390x/vector.c | 136 - scripts/arch-run.bash | 380 -- scripts/asm-offsets.mak | 43 - scripts/common.bash | 50 - scripts/git.difforder | 25 - scripts/mkstandalone.sh | 135 - scripts/pretty_print_stacks.py | 97 - scripts/runtime.bash | 178 - x86/Makefile | 1 - x86/Makefile.common | 83 - x86/Makefile.i386 | 11 - x86/Makefile.x86_64 | 29 - x86/README | 49 - x86/access.c | 1052 --- x86/apic.c | 674 -- x86/asyncpf.c | 112 - x86/cmpxchg8b.c | 26 - x86/cstart.S | 236 - x86/cstart64.S | 332 - x86/debug.c | 233 - x86/emulator.c | 1101 --- x86/eventinj.c | 431 -- x86/flat.lds | 21 - x86/hypercall.c | 82 - x86/hyperv.c | 70 - x86/hyperv.h | 217 - x86/hyperv_clock.c | 195 - x86/hyperv_connections.c | 332 - x86/hyperv_stimer.c | 375 -- x86/hyperv_synic.c | 185 - x86/idt_test.c | 41 - x86/init.c | 130 - x86/intel-iommu.c | 168 - x86/ioapic.c | 521 -- x86/ioram.h | 7 - x86/kvmclock.c | 289 - x86/kvmclock.h | 44 - x86/kvmclock_test.c | 155 - x86/memory.c | 84 - x86/msr.c | 113 - x86/pcid.c | 151 - x86/pku.c | 145 - x86/pmu.c | 568 -- x86/port80.c | 12 - x86/rdpru.c | 23 - x86/realmode.c | 1862 ----- x86/realmode.lds | 12 - x86/rmap_chain.c | 47 - x86/run | 44 - x86/s3.c | 89 - x86/setjmp.c | 24 - x86/sieve.c | 51 - x86/smap.c | 194 - x86/smptest.c | 29 - x86/svm.c | 411 -- x86/svm.h | 397 -- x86/svm_tests.c | 2203 ------ x86/syscall.c | 107 - x86/taskswitch.c | 51 - x86/taskswitch2.c | 294 - x86/tsc.c | 56 - x86/tsc_adjust.c | 40 - x86/tscdeadline_latency.c | 131 - x86/tsx-ctrl.c | 60 - x86/types.h | 21 - x86/umip.c | 194 - x86/unittests.cfg | 349 - x86/vmexit.c | 608 -- x86/vmware_backdoors.c | 190 - x86/vmx.c | 2165 ------ x86/vmx.h | 961 --- x86/vmx_tests.c | 10111 ---------------------------- x86/xsave.c | 162 - 389 files changed, 65435 deletions(-) delete mode 100644 .editorconfig delete mode 100644 .gitignore delete mode 100644 .gitlab-ci.yml delete mode 100644 .travis.yml delete mode 100644 COPYRIGHT delete mode 100644 MAINTAINERS delete mode 100644 Makefile delete mode 100644 README.macOS.md delete mode 100644 arm/Makefile delete mode 100644 arm/Makefile.arm delete mode 100644 arm/Makefile.arm64 delete mode 100644 arm/Makefile.common delete mode 100644 arm/cache.c delete mode 100644 arm/cstart.S delete mode 100644 arm/cstart64.S delete mode 100644 arm/flat.lds delete mode 100644 arm/gic.c delete mode 100644 arm/micro-bench.c delete mode 100644 arm/pci-test.c delete mode 100644 arm/pl031.c delete mode 100644 arm/pmu.c delete mode 100644 arm/psci.c delete mode 100755 arm/run delete mode 100644 arm/selftest.c delete mode 120000 arm/sieve.c delete mode 100644 arm/spinlock-test.c delete mode 100644 arm/timer.c delete mode 100644 arm/unittests.cfg delete mode 100755 configure delete mode 100644 errata.txt delete mode 100644 lib/abort.c delete mode 100644 lib/alloc.c delete mode 100644 lib/alloc.h delete mode 100644 lib/alloc_page.c delete mode 100644 lib/alloc_page.h delete mode 100644 lib/alloc_phys.c delete mode 100644 lib/alloc_phys.h delete mode 100644 lib/argv.c delete mode 100644 lib/argv.h delete mode 100644 lib/arm/.gitignore delete mode 100644 lib/arm/asm-offsets.c delete mode 100644 lib/arm/asm/arch_gicv3.h delete mode 100644 lib/arm/asm/asm-offsets.h delete mode 100644 lib/arm/asm/barrier.h delete mode 100644 lib/arm/asm/bitops.h delete mode 100644 lib/arm/asm/cpumask.h delete mode 100644 lib/arm/asm/delay.h delete mode 100644 lib/arm/asm/gic-v2.h delete mode 100644 lib/arm/asm/gic-v3-its.h delete mode 100644 lib/arm/asm/gic-v3.h delete mode 100644 lib/arm/asm/gic.h delete mode 100644 lib/arm/asm/io.h delete mode 100644 lib/arm/asm/mmu-api.h delete mode 100644 lib/arm/asm/mmu.h delete mode 100644 lib/arm/asm/page.h delete mode 100644 lib/arm/asm/pci.h delete mode 100644 lib/arm/asm/pgtable-hwdef.h delete mode 100644 lib/arm/asm/pgtable.h delete mode 100644 lib/arm/asm/processor.h delete mode 100644 lib/arm/asm/psci.h delete mode 100644 lib/arm/asm/ptrace.h delete mode 100644 lib/arm/asm/setup.h delete mode 100644 lib/arm/asm/smp.h delete mode 100644 lib/arm/asm/spinlock.h delete mode 100644 lib/arm/asm/stack.h delete mode 100644 lib/arm/asm/sysreg.h delete mode 100644 lib/arm/asm/thread_info.h delete mode 100644 lib/arm/bitops.c delete mode 100644 lib/arm/delay.c delete mode 100644 lib/arm/eabi_compat.c delete mode 100644 lib/arm/gic-v2.c delete mode 100644 lib/arm/gic-v3.c delete mode 100644 lib/arm/gic.c delete mode 100644 lib/arm/io.c delete mode 100644 lib/arm/io.h delete mode 100644 lib/arm/mmu.c delete mode 100644 lib/arm/processor.c delete mode 100644 lib/arm/psci.c delete mode 100644 lib/arm/setup.c delete mode 100644 lib/arm/smp.c delete mode 100644 lib/arm/spinlock.c delete mode 100644 lib/arm/stack.c delete mode 100644 lib/arm64/.gitignore delete mode 100644 lib/arm64/asm-offsets.c delete mode 100644 lib/arm64/asm/arch_gicv3.h delete mode 100644 lib/arm64/asm/asm-offsets.h delete mode 100644 lib/arm64/asm/barrier.h delete mode 100644 lib/arm64/asm/bitops.h delete mode 100644 lib/arm64/asm/cpumask.h delete mode 100644 lib/arm64/asm/delay.h delete mode 100644 lib/arm64/asm/esr.h delete mode 100644 lib/arm64/asm/gic-v2.h delete mode 100644 lib/arm64/asm/gic-v3-its.h delete mode 100644 lib/arm64/asm/gic-v3.h delete mode 100644 lib/arm64/asm/gic.h delete mode 100644 lib/arm64/asm/io.h delete mode 100644 lib/arm64/asm/mmu-api.h delete mode 100644 lib/arm64/asm/mmu.h delete mode 100644 lib/arm64/asm/page.h delete mode 100644 lib/arm64/asm/pci.h delete mode 100644 lib/arm64/asm/pgtable-hwdef.h delete mode 100644 lib/arm64/asm/pgtable.h delete mode 100644 lib/arm64/asm/processor.h delete mode 100644 lib/arm64/asm/psci.h delete mode 100644 lib/arm64/asm/ptrace.h delete mode 100644 lib/arm64/asm/setup.h delete mode 100644 lib/arm64/asm/smp.h delete mode 100644 lib/arm64/asm/spinlock.h delete mode 100644 lib/arm64/asm/stack.h delete mode 100644 lib/arm64/asm/sysreg.h delete mode 100644 lib/arm64/asm/thread_info.h delete mode 100644 lib/arm64/gic-v3-its-cmd.c delete mode 100644 lib/arm64/gic-v3-its.c delete mode 100644 lib/arm64/processor.c delete mode 100644 lib/arm64/spinlock.c delete mode 100644 lib/asm-generic/atomic.h delete mode 100644 lib/asm-generic/barrier.h delete mode 100644 lib/asm-generic/io.h delete mode 100644 lib/asm-generic/page.h delete mode 100644 lib/asm-generic/pci-host-bridge.h delete mode 100644 lib/asm-generic/pci.h delete mode 100644 lib/asm-generic/spinlock.h delete mode 100644 lib/auxinfo.c delete mode 100644 lib/auxinfo.h delete mode 100644 lib/bitops.h delete mode 100644 lib/chr-testdev.c delete mode 100644 lib/chr-testdev.h delete mode 100644 lib/devicetree.c delete mode 100644 lib/devicetree.h delete mode 100644 lib/errata.h delete mode 100644 lib/generated/.gitignore delete mode 100644 lib/getchar.c delete mode 100644 lib/kbuild.h delete mode 100644 lib/libcflat.h delete mode 100644 lib/libfdt/Makefile.libfdt delete mode 100644 lib/libfdt/README delete mode 100644 lib/libfdt/fdt.c delete mode 100644 lib/libfdt/fdt.h delete mode 100644 lib/libfdt/fdt_empty_tree.c delete mode 100644 lib/libfdt/fdt_ro.c delete mode 100644 lib/libfdt/fdt_rw.c delete mode 100644 lib/libfdt/fdt_strerror.c delete mode 100644 lib/libfdt/fdt_sw.c delete mode 100644 lib/libfdt/fdt_wip.c delete mode 100644 lib/libfdt/libfdt.h delete mode 100644 lib/libfdt/libfdt_env.h delete mode 100644 lib/libfdt/libfdt_internal.h delete mode 100644 lib/libfdt/version.lds delete mode 100644 lib/linux/compiler.h delete mode 100644 lib/linux/const.h delete mode 100644 lib/linux/pci_regs.h delete mode 100644 lib/linux/psci.h delete mode 100644 lib/pci-edu.c delete mode 100644 lib/pci-edu.h delete mode 100644 lib/pci-host-generic.c delete mode 100644 lib/pci-host-generic.h delete mode 100644 lib/pci-testdev.c delete mode 100644 lib/pci.c delete mode 100644 lib/pci.h delete mode 100644 lib/powerpc/.gitignore delete mode 100644 lib/powerpc/asm/handlers.h delete mode 100644 lib/powerpc/asm/hcall.h delete mode 100644 lib/powerpc/asm/ppc_asm.h delete mode 100644 lib/powerpc/asm/processor.h delete mode 100644 lib/powerpc/asm/rtas.h delete mode 100644 lib/powerpc/asm/setup.h delete mode 100644 lib/powerpc/asm/smp.h delete mode 100644 lib/powerpc/asm/stack.h delete mode 100644 lib/powerpc/handlers.c delete mode 100644 lib/powerpc/hcall.c delete mode 100644 lib/powerpc/io.c delete mode 100644 lib/powerpc/io.h delete mode 100644 lib/powerpc/processor.c delete mode 100644 lib/powerpc/rtas.c delete mode 100644 lib/powerpc/setup.c delete mode 100644 lib/powerpc/smp.c delete mode 100644 lib/ppc64/.gitignore delete mode 100644 lib/ppc64/asm-offsets.c delete mode 100644 lib/ppc64/asm/asm-offsets.h delete mode 100644 lib/ppc64/asm/barrier.h delete mode 100644 lib/ppc64/asm/bitops.h delete mode 100644 lib/ppc64/asm/handlers.h delete mode 100644 lib/ppc64/asm/hcall.h delete mode 100644 lib/ppc64/asm/io.h delete mode 100644 lib/ppc64/asm/page.h delete mode 100644 lib/ppc64/asm/ppc_asm.h delete mode 100644 lib/ppc64/asm/processor.h delete mode 100644 lib/ppc64/asm/ptrace.h delete mode 100644 lib/ppc64/asm/rtas.h delete mode 100644 lib/ppc64/asm/setup.h delete mode 100644 lib/ppc64/asm/smp.h delete mode 100644 lib/ppc64/asm/spinlock.h delete mode 100644 lib/ppc64/asm/stack.h delete mode 100644 lib/printf.c delete mode 100644 lib/report.c delete mode 100644 lib/s390x/.gitignore delete mode 100644 lib/s390x/asm-offsets.c delete mode 100644 lib/s390x/asm/arch_def.h delete mode 100644 lib/s390x/asm/asm-offsets.h delete mode 100644 lib/s390x/asm/barrier.h delete mode 100644 lib/s390x/asm/bitops.h delete mode 100644 lib/s390x/asm/cpacf.h delete mode 100644 lib/s390x/asm/facility.h delete mode 100644 lib/s390x/asm/float.h delete mode 100644 lib/s390x/asm/interrupt.h delete mode 100644 lib/s390x/asm/io.h delete mode 100644 lib/s390x/asm/mem.h delete mode 100644 lib/s390x/asm/page.h delete mode 100644 lib/s390x/asm/pgtable.h delete mode 100644 lib/s390x/asm/sigp.h delete mode 100644 lib/s390x/asm/spinlock.h delete mode 100644 lib/s390x/asm/stack.h delete mode 100644 lib/s390x/interrupt.c delete mode 100644 lib/s390x/io.c delete mode 100644 lib/s390x/mmu.c delete mode 100644 lib/s390x/mmu.h delete mode 100644 lib/s390x/sclp-console.c delete mode 100644 lib/s390x/sclp.c delete mode 100644 lib/s390x/sclp.h delete mode 100644 lib/s390x/smp.c delete mode 100644 lib/s390x/smp.h delete mode 100644 lib/s390x/stack.c delete mode 100644 lib/setjmp.h delete mode 100644 lib/stack.c delete mode 100644 lib/stack.h delete mode 100644 lib/string.c delete mode 100644 lib/string.h delete mode 100644 lib/util.c delete mode 100644 lib/util.h delete mode 100644 lib/virtio-mmio.c delete mode 100644 lib/virtio-mmio.h delete mode 100644 lib/virtio.c delete mode 100644 lib/virtio.h delete mode 100644 lib/vmalloc.c delete mode 100644 lib/vmalloc.h delete mode 100644 lib/x86/acpi.c delete mode 100644 lib/x86/acpi.h delete mode 100644 lib/x86/apic-defs.h delete mode 100644 lib/x86/apic.c delete mode 100644 lib/x86/apic.h delete mode 100644 lib/x86/asm/barrier.h delete mode 100644 lib/x86/asm/bitops.h delete mode 100644 lib/x86/asm/io.h delete mode 100644 lib/x86/asm/page.h delete mode 100644 lib/x86/asm/pci.h delete mode 100644 lib/x86/asm/spinlock.h delete mode 100644 lib/x86/asm/stack.h delete mode 100644 lib/x86/atomic.c delete mode 100644 lib/x86/atomic.h delete mode 100644 lib/x86/delay.c delete mode 100644 lib/x86/delay.h delete mode 100644 lib/x86/desc.c delete mode 100644 lib/x86/desc.h delete mode 100644 lib/x86/fault_test.c delete mode 100644 lib/x86/fault_test.h delete mode 100644 lib/x86/fwcfg.c delete mode 100644 lib/x86/fwcfg.h delete mode 100644 lib/x86/intel-iommu.c delete mode 100644 lib/x86/intel-iommu.h delete mode 100644 lib/x86/io.c delete mode 100644 lib/x86/isr.c delete mode 100644 lib/x86/isr.h delete mode 100644 lib/x86/msr.h delete mode 100644 lib/x86/processor.h delete mode 100644 lib/x86/setjmp32.S delete mode 100644 lib/x86/setjmp64.S delete mode 100644 lib/x86/setup.c delete mode 100644 lib/x86/smp.c delete mode 100644 lib/x86/smp.h delete mode 100644 lib/x86/stack.c delete mode 100644 lib/x86/usermode.c delete mode 100644 lib/x86/usermode.h delete mode 100644 lib/x86/vm.c delete mode 100644 lib/x86/vm.h delete mode 100644 powerpc/.gitignore delete mode 100644 powerpc/Makefile delete mode 100644 powerpc/Makefile.common delete mode 100644 powerpc/Makefile.ppc64 delete mode 100644 powerpc/boot_rom.S delete mode 100644 powerpc/cstart64.S delete mode 100644 powerpc/emulator.c delete mode 100644 powerpc/flat.lds delete mode 100644 powerpc/reloc64.c delete mode 100644 powerpc/rtas.c delete mode 100755 powerpc/run delete mode 100644 powerpc/selftest.c delete mode 100644 powerpc/spapr.h delete mode 100644 powerpc/spapr_hcall.c delete mode 100644 powerpc/sprs.c delete mode 100644 powerpc/tm.c delete mode 100644 powerpc/unittests.cfg delete mode 100755 run_tests.sh delete mode 100644 s390x/Makefile delete mode 100644 s390x/cmm.c delete mode 100644 s390x/cpumodel.c delete mode 100644 s390x/cstart64.S delete mode 100644 s390x/diag10.c delete mode 100644 s390x/diag288.c delete mode 100644 s390x/diag308.c delete mode 100644 s390x/emulator.c delete mode 100644 s390x/flat.lds delete mode 100644 s390x/gs.c delete mode 100644 s390x/iep.c delete mode 100644 s390x/intercept.c delete mode 100644 s390x/pfmf.c delete mode 100755 s390x/run delete mode 100644 s390x/sclp.c delete mode 100644 s390x/selftest.c delete mode 120000 s390x/sieve.c delete mode 100644 s390x/skey.c delete mode 100644 s390x/skrf.c delete mode 100644 s390x/smp.c delete mode 100644 s390x/sthyi.c delete mode 100644 s390x/sthyi.h delete mode 100644 s390x/stsi.c delete mode 100644 s390x/unittests.cfg delete mode 100644 s390x/vector.c delete mode 100644 scripts/arch-run.bash delete mode 100644 scripts/asm-offsets.mak delete mode 100644 scripts/common.bash delete mode 100644 scripts/git.difforder delete mode 100755 scripts/mkstandalone.sh delete mode 100755 scripts/pretty_print_stacks.py delete mode 100644 scripts/runtime.bash delete mode 100644 x86/Makefile delete mode 100644 x86/Makefile.common delete mode 100644 x86/Makefile.i386 delete mode 100644 x86/Makefile.x86_64 delete mode 100644 x86/README delete mode 100644 x86/access.c delete mode 100644 x86/apic.c delete mode 100644 x86/asyncpf.c delete mode 100644 x86/cmpxchg8b.c delete mode 100644 x86/cstart.S delete mode 100644 x86/cstart64.S delete mode 100644 x86/debug.c delete mode 100644 x86/emulator.c delete mode 100644 x86/eventinj.c delete mode 100644 x86/flat.lds delete mode 100644 x86/hypercall.c delete mode 100644 x86/hyperv.c delete mode 100644 x86/hyperv.h delete mode 100644 x86/hyperv_clock.c delete mode 100644 x86/hyperv_connections.c delete mode 100644 x86/hyperv_stimer.c delete mode 100644 x86/hyperv_synic.c delete mode 100644 x86/idt_test.c delete mode 100644 x86/init.c delete mode 100644 x86/intel-iommu.c delete mode 100644 x86/ioapic.c delete mode 100644 x86/ioram.h delete mode 100644 x86/kvmclock.c delete mode 100644 x86/kvmclock.h delete mode 100644 x86/kvmclock_test.c delete mode 100644 x86/memory.c delete mode 100644 x86/msr.c delete mode 100644 x86/pcid.c delete mode 100644 x86/pku.c delete mode 100644 x86/pmu.c delete mode 100644 x86/port80.c delete mode 100644 x86/rdpru.c delete mode 100644 x86/realmode.c delete mode 100644 x86/realmode.lds delete mode 100644 x86/rmap_chain.c delete mode 100755 x86/run delete mode 100644 x86/s3.c delete mode 100644 x86/setjmp.c delete mode 100644 x86/sieve.c delete mode 100644 x86/smap.c delete mode 100644 x86/smptest.c delete mode 100644 x86/svm.c delete mode 100644 x86/svm.h delete mode 100644 x86/svm_tests.c delete mode 100644 x86/syscall.c delete mode 100644 x86/taskswitch.c delete mode 100644 x86/taskswitch2.c delete mode 100644 x86/tsc.c delete mode 100644 x86/tsc_adjust.c delete mode 100644 x86/tscdeadline_latency.c delete mode 100644 x86/tsx-ctrl.c delete mode 100644 x86/types.h delete mode 100644 x86/umip.c delete mode 100644 x86/unittests.cfg delete mode 100644 x86/vmexit.c delete mode 100644 x86/vmware_backdoors.c delete mode 100644 x86/vmx.c delete mode 100644 x86/vmx.h delete mode 100644 x86/vmx_tests.c delete mode 100644 x86/xsave.c diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 46d4ac64..00000000 --- a/.editorconfig +++ /dev/null @@ -1,15 +0,0 @@ -# EditorConfig is a file format and collection of text editor plugins -# for maintaining consistent coding styles between different editors -# and IDEs. Most popular editors support this either natively or via -# plugin. -# -# Check https://editorconfig.org for details. - -root = true - -[*] -end_of_line = lf -insert_final_newline = true -charset = utf-8 -indent_style = tab -indent_size = 8 diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 784cb2dd..00000000 --- a/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -.gdbinit -*.a -*.d -*.o -*.flat -*.elf -.pc -patches -.stgit-* -cscope.* -*.swp -/lib/asm -/lib/config.h -/config.mak -/*-run -/msr.out -/tests -/build-head -/logs/ -/logs.old/ -/api/api-sample -/api/dirty-log -/api/dirty-log-perf -/s390x/*.bin diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index d042cde8..00000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,101 +0,0 @@ -image: fedora:32 - -before_script: - - dnf update -y - - dnf install -y make python - -build-aarch64: - script: - - dnf install -y qemu-system-aarch64 gcc-aarch64-linux-gnu - - ./configure --arch=aarch64 --cross-prefix=aarch64-linux-gnu- - - make -j2 - - ACCEL=tcg MAX_SMP=8 ./run_tests.sh - selftest-setup selftest-vectors-kernel selftest-vectors-user selftest-smp - pci-test pmu-cycle-counter pmu-event-counter-config pmu-sw-incr gicv2-ipi - gicv2-mmio gicv3-ipi gicv2-active gicv3-active psci timer cache - | tee results.txt - - if grep -q FAIL results.txt ; then exit 1 ; fi - -build-arm: - script: - - dnf install -y qemu-system-arm gcc-arm-linux-gnu - - ./configure --arch=arm --cross-prefix=arm-linux-gnu- - - make -j2 - - ACCEL=tcg MAX_SMP=8 ./run_tests.sh - selftest-setup selftest-vectors-kernel selftest-vectors-user selftest-smp - pci-test pmu-cycle-counter gicv2-ipi gicv2-mmio gicv3-ipi gicv2-active - gicv3-active psci - | tee results.txt - - if grep -q FAIL results.txt ; then exit 1 ; fi - -build-ppc64be: - script: - - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu - - ./configure --arch=ppc64 --endian=big --cross-prefix=powerpc64-linux-gnu- - - make -j2 - - ACCEL=tcg ./run_tests.sh - selftest-setup spapr_hcall rtas-get-time-of-day rtas-get-time-of-day-base - rtas-set-time-of-day emulator - | tee results.txt - - if grep -q FAIL results.txt ; then exit 1 ; fi - -build-ppc64le: - script: - - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu - - ./configure --arch=ppc64 --endian=little --cross-prefix=powerpc64-linux-gnu- - - make -j2 - - ACCEL=tcg ./run_tests.sh - selftest-setup spapr_hcall rtas-get-time-of-day rtas-get-time-of-day-base - rtas-set-time-of-day emulator - | tee results.txt - - if grep -q FAIL results.txt ; then exit 1 ; fi - -build-s390x: - script: - - dnf install -y qemu-system-s390x gcc-s390x-linux-gnu - - ./configure --arch=s390x --cross-prefix=s390x-linux-gnu- - - make -j2 - - ACCEL=tcg ./run_tests.sh - selftest-setup intercept emulator sieve skey diag10 diag308 vector diag288 - stsi sclp-1g sclp-3g - | tee results.txt - - if grep -q FAIL results.txt ; then exit 1 ; fi - -build-x86_64: - script: - - dnf install -y qemu-system-x86 gcc - - ./configure --arch=x86_64 - - make -j2 - - ACCEL=tcg ./run_tests.sh - ioapic-split smptest smptest3 vmexit_cpuid vmexit_mov_from_cr8 - vmexit_mov_to_cr8 vmexit_inl_pmtimer vmexit_ipi vmexit_ipi_halt - vmexit_ple_round_robin vmexit_tscdeadline vmexit_tscdeadline_immed - eventinj msr port80 setjmp sieve syscall tsc rmap_chain umip intel_iommu - | tee results.txt - - if grep -q FAIL results.txt ; then exit 1 ; fi - -build-i386: - script: - - dnf install -y qemu-system-x86 gcc - - ./configure --arch=i386 - - make -j2 - - ACCEL=tcg ./run_tests.sh - cmpxchg8b vmexit_cpuid vmexit_mov_from_cr8 vmexit_mov_to_cr8 - vmexit_inl_pmtimer vmexit_ipi vmexit_ipi_halt vmexit_ple_round_robin - vmexit_tscdeadline vmexit_tscdeadline_immed eventinj port80 setjmp sieve - tsc taskswitch umip - | tee results.txt - - if grep -q FAIL results.txt ; then exit 1 ; fi - -build-clang: - script: - - dnf install -y qemu-system-x86 clang - - ./configure --arch=x86_64 --cc=clang - - make -j2 - - ACCEL=tcg ./run_tests.sh - ioapic-split smptest smptest3 vmexit_cpuid vmexit_mov_from_cr8 - vmexit_mov_to_cr8 vmexit_inl_pmtimer vmexit_ipi vmexit_ipi_halt - vmexit_ple_round_robin vmexit_tscdeadline vmexit_tscdeadline_immed - eventinj msr port80 setjmp syscall tsc rmap_chain umip intel_iommu - | tee results.txt - - grep -q PASS results.txt && ! grep -q FAIL results.txt diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f0cfc82c..00000000 --- a/.travis.yml +++ /dev/null @@ -1,122 +0,0 @@ -sudo: true -dist: bionic -language: c -cache: ccache -git: - submodules: false - -matrix: - include: - - - addons: - apt_packages: gcc qemu-system-x86 - env: - - CONFIG="" - - BUILD_DIR="." - - TESTS="access asyncpf debug emulator ept hypercall hyperv_stimer - hyperv_synic idt_test intel_iommu ioapic ioapic-split - kvmclock_test msr pcid rdpru realmode rmap_chain s3 setjmp umip" - - ACCEL="kvm" - - - addons: - apt_packages: gcc qemu-system-x86 - env: - - CONFIG="" - - BUILD_DIR="x86-builddir" - - TESTS="smptest smptest3 tsc tsc_adjust xsave vmexit_cpuid vmexit_vmcall - sieve vmexit_inl_pmtimer vmexit_ipi_halt vmexit_mov_from_cr8 - vmexit_mov_to_cr8 vmexit_ple_round_robin vmexit_tscdeadline - vmexit_tscdeadline_immed vmx_apic_passthrough_thread syscall" - - ACCEL="kvm" - - - addons: - apt_packages: gcc gcc-multilib qemu-system-x86 - env: - - CONFIG="--arch=i386" - - BUILD_DIR="." - - TESTS="asyncpf hyperv_stimer hyperv_synic kvmclock_test msr pmu realmode - s3 sieve smap smptest smptest3 taskswitch taskswitch2 tsc_adjust" - - ACCEL="kvm" - - - addons: - apt_packages: gcc gcc-multilib qemu-system-x86 - env: - - CONFIG="--arch=i386" - - BUILD_DIR="i386-builddir" - - TESTS="cmpxchg8b tsx-ctrl umip vmexit_cpuid vmexit_ipi vmexit_ipi_halt - vmexit_mov_from_cr8 vmexit_mov_to_cr8 vmexit_ple_round_robin - vmexit_tscdeadline vmexit_tscdeadline_immed vmexit_vmcall setjmp" - - ACCEL="kvm" - - - addons: - apt_packages: gcc-arm-linux-gnueabihf qemu-system-arm - env: - - CONFIG="--arch=arm --cross-prefix=arm-linux-gnueabihf-" - - BUILD_DIR="." - - TESTS="selftest-vectors-kernel selftest-vectors-user selftest-smp" - - - addons: - apt_packages: gcc-arm-linux-gnueabihf qemu-system-arm - env: - - CONFIG="--arch=arm --cross-prefix=arm-linux-gnueabihf-" - - BUILD_DIR="arm-buildir" - - TESTS="pci-test pmu gicv2-active gicv3-active psci selftest-setup" - - - addons: - apt_packages: gcc-aarch64-linux-gnu qemu-system-aarch64 - env: - - CONFIG="--arch=arm64 --cross-prefix=aarch64-linux-gnu-" - - BUILD_DIR="." - - TESTS="selftest-vectors-kernel selftest-vectors-user selftest-smp" - - - addons: - apt_packages: gcc-aarch64-linux-gnu qemu-system-aarch64 - env: - - CONFIG="--arch=arm64 --cross-prefix=aarch64-linux-gnu-" - - BUILD_DIR="arm64-buildir" - - TESTS="pci-test pmu gicv2-active gicv3-active psci timer selftest-setup" - - - addons: - apt_packages: gcc-powerpc64le-linux-gnu qemu-system-ppc - env: - - CONFIG="--arch=ppc64 --endian=little --cross-prefix=powerpc64le-linux-gnu-" - - BUILD_DIR="." - - TESTS="spapr_hcall emulator rtas-set-time-of-day" - - ACCEL="tcg,cap-htm=off" - - - addons: - apt_packages: gcc-powerpc64le-linux-gnu qemu-system-ppc - env: - - CONFIG="--arch=ppc64 --endian=little --cross-prefix=powerpc64le-linux-gnu-" - - BUILD_DIR="ppc64le-buildir" - - TESTS="rtas-get-time-of-day rtas-get-time-of-day-base" - - ACCEL="tcg,cap-htm=off" - - - addons: - apt_packages: gcc-s390x-linux-gnu qemu-system-s390x - env: - - CONFIG="--arch=s390x --cross-prefix=s390x-linux-gnu-" - - BUILD_DIR="." - - TESTS="diag10 diag308" - - ACCEL="tcg,firmware=s390x/run" - - - addons: - apt_packages: gcc-s390x-linux-gnu qemu-system-s390x - env: - - CONFIG="--arch=s390x --cross-prefix=s390x-linux-gnu-" - - BUILD_DIR="s390x-builddir" - - TESTS="sieve" - - ACCEL="tcg,firmware=s390x/run" - -before_script: - - if [ "$ACCEL" = "kvm" ]; then - sudo chgrp kvm /usr/bin/qemu-system-* ; - sudo chmod g+s /usr/bin/qemu-system-* ; - fi - - mkdir -p $BUILD_DIR && cd $BUILD_DIR - - if [ -e ./configure ]; then ./configure $CONFIG ; fi - - if [ -e ../configure ]; then ../configure $CONFIG ; fi -script: - - make -j3 - - ACCEL="${ACCEL:-tcg}" ./run_tests.sh -v $TESTS | tee results.txt - - grep -q PASS results.txt && ! grep -q FAIL results.txt diff --git a/COPYRIGHT b/COPYRIGHT deleted file mode 100644 index b9d975fc..00000000 --- a/COPYRIGHT +++ /dev/null @@ -1,10 +0,0 @@ -Copyright (C) 2006 Qumranet. -Copyright (C) 2007-2017 by various contributors (see source files for details) - -The kvm-unit-tests are free software; the whole package can be redistributed -and/or modified under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. - -Many files in this directory and its subdirectories are also licensed under -the less restrictive GNU LGPL, version 2, or other compatible licenses. See -the individual files for details. diff --git a/MAINTAINERS b/MAINTAINERS deleted file mode 100644 index 52a3eb6f..00000000 --- a/MAINTAINERS +++ /dev/null @@ -1,94 +0,0 @@ -KVM Unit Tests Maintainers -========================== - -The intention of this file is not to establish who owns what portions of the -code base, but to provide a set of names that developers can consult when they -have a question about a particular subset and also to provide a set of names -to be CC'd when submitting a patch to obtain appropriate review. - -In general, if you have a question about inclusion of a patch, you -should consult the KVM mailing list and not any -specific individual privately. - -Descriptions of section entries: - - M: Mail patches to: FullName - R: Designated reviewer: FullName - These reviewers should be CCed on patches. - L: Mailing list that is relevant to this area - W: Web-page with status/info - Q: Patchwork web based patch tracking system site - T: SCM tree type and location. Type is one of: git, hg, quilt, stgit. - S: Status, one of the following: - Supported: Someone is actually paid to look after this. - Maintained: Someone actually looks after it. - Odd Fixes: It has a maintainer but they don't have time to do - much other than throw the odd patch in. See below. - Orphan: No current maintainer [but maybe you could take the - role as you write your new code]. - Obsolete: Old code. Something tagged obsolete generally means - it has been replaced by a better system and you - should be using that. - F: Files and directories with wildcard patterns. - A trailing slash includes all files and subdirectory files. - F: drivers/net/ all files in and below drivers/net - F: drivers/net/* all files in drivers/net, but not below - F: */net/* all files in "any top level directory"/net - One pattern per line. Multiple F: lines acceptable. - X: Files and directories that are NOT maintained, same rules as F: - Files exclusions are tested before file matches. - Can be useful for excluding a specific subdirectory, for instance: - F: net/ - X: net/ipv6/ - matches all files in and below net excluding net/ipv6/ - K: Keyword perl extended regex pattern to match content in a - patch or file. For instance: - K: of_get_profile - matches patches or files that contain "of_get_profile" - K: \b(printk|pr_(info|err))\b - matches patches or files that contain one or more of the words - printk, pr_info or pr_err - One regex pattern per line. Multiple K: lines acceptable. - - -Maintainers ------------ -M: Paolo Bonzini -L: kvm@vger.kernel.org -T: git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git - -Architecture Specific Code: ---------------------------- - -ARM -M: Drew Jones -L: kvm@vger.kernel.org -L: kvmarm@lists.cs.columbia.edu -F: arm/* -F: lib/arm/* -F: lib/arm64/* - -POWERPC -M: Laurent Vivier -M: Thomas Huth -L: kvm@vger.kernel.org -L: kvm-ppc@vger.kernel.org -F: powerpc/* -F: lib/powerpc/* -F: lib/ppc64/* - -S390X -M: Thomas Huth -M: David Hildenbrand -M: Janosch Frank -R: Cornelia Huck -L: kvm@vger.kernel.org -L: linux-s390@vger.kernel.org -F: s390x/* -F: lib/s390x/* - -X86 -M: Paolo Bonzini -L: kvm@vger.kernel.org -F: x86/* -F: lib/x86/* diff --git a/Makefile b/Makefile deleted file mode 100644 index 3ff2f916..00000000 --- a/Makefile +++ /dev/null @@ -1,131 +0,0 @@ -SHELL := /usr/bin/env bash - -ifeq ($(wildcard config.mak),) -$(error run ./configure first. See ./configure -h) -endif - -include config.mak - -# Set search path for all sources -VPATH = $(SRCDIR) - -libdirs-get = $(shell [ -d "lib/$(1)" ] && echo "lib/$(1) lib/$(1)/asm") -ARCH_LIBDIRS := $(call libdirs-get,$(ARCH)) $(call libdirs-get,$(TEST_DIR)) -OBJDIRS := $(ARCH_LIBDIRS) - -DESTDIR := $(PREFIX)/share/kvm-unit-tests/ - -.PHONY: arch_clean clean distclean cscope - -#make sure env CFLAGS variable is not used -CFLAGS = - -libgcc := $(shell $(CC) --print-libgcc-file-name) - -libcflat := lib/libcflat.a -cflatobjs := \ - lib/argv.o \ - lib/printf.o \ - lib/string.o \ - lib/abort.o \ - lib/report.o \ - lib/stack.o - -# libfdt paths -LIBFDT_objdir = lib/libfdt -LIBFDT_srcdir = $(SRCDIR)/lib/libfdt -LIBFDT_archive = $(LIBFDT_objdir)/libfdt.a -LIBFDT_include = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_INCLUDES)) -LIBFDT_version = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_VERSION)) - -OBJDIRS += $(LIBFDT_objdir) - -#include architecture specific make rules -include $(SRCDIR)/$(TEST_DIR)/Makefile - -# cc-option -# Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0) - -cc-option = $(shell if $(CC) -Werror $(1) -S -o /dev/null -xc /dev/null \ - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) - -COMMON_CFLAGS += -g $(autodepend-flags) -fno-strict-aliasing -fno-common -COMMON_CFLAGS += -Wall -Wwrite-strings -Wempty-body -Wuninitialized -COMMON_CFLAGS += -Wignored-qualifiers -Werror - -frame-pointer-flag=-f$(if $(KEEP_FRAME_POINTER),no-,)omit-frame-pointer -fomit_frame_pointer := $(call cc-option, $(frame-pointer-flag), "") -fno_stack_protector := $(call cc-option, -fno-stack-protector, "") -fno_stack_protector_all := $(call cc-option, -fno-stack-protector-all, "") -wno_frame_address := $(call cc-option, -Wno-frame-address, "") -fno_pic := $(call cc-option, -fno-pic, "") -no_pie := $(call cc-option, -no-pie, "") -wclobbered := $(call cc-option, -Wclobbered, "") -wunused_but_set_parameter := $(call cc-option, -Wunused-but-set-parameter, "") -wmissing_parameter_type := $(call cc-option, -Wmissing-parameter-type, "") -wold_style_declaration := $(call cc-option, -Wold-style-declaration, "") - -COMMON_CFLAGS += $(fomit_frame_pointer) -COMMON_CFLAGS += $(fno_stack_protector) -COMMON_CFLAGS += $(fno_stack_protector_all) -COMMON_CFLAGS += $(wno_frame_address) -COMMON_CFLAGS += $(if $(U32_LONG_FMT),-D__U32_LONG_FMT__,) -COMMON_CFLAGS += $(fno_pic) $(no_pie) -COMMON_CFLAGS += $(wclobbered) -COMMON_CFLAGS += $(wunused_but_set_parameter) - -CFLAGS += $(COMMON_CFLAGS) -CFLAGS += $(wmissing_parameter_type) -CFLAGS += $(wold_style_declaration) -CFLAGS += -Woverride-init -Wmissing-prototypes -Wstrict-prototypes - -autodepend-flags = -MMD -MF $(dir $*).$(notdir $*).d - -LDFLAGS += $(CFLAGS) - -$(libcflat): $(cflatobjs) - $(AR) rcs $@ $^ - -include $(LIBFDT_srcdir)/Makefile.libfdt -$(LIBFDT_archive): CFLAGS += -ffreestanding -I $(SRCDIR)/lib -I $(SRCDIR)/lib/libfdt -Wno-sign-compare -$(LIBFDT_archive): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS)) - $(AR) rcs $@ $^ - - -# Build directory target -.PHONY: directories -directories: - @mkdir -p $(OBJDIRS) - -%.o: %.S - $(CC) $(CFLAGS) -c -nostdlib -o $@ $< - --include */.*.d */*/.*.d - -all: directories $(shell cd $(SRCDIR) && git rev-parse --verify --short=8 HEAD >$(PWD)/build-head 2>/dev/null) - -standalone: all - @scripts/mkstandalone.sh - -install: standalone - mkdir -p $(DESTDIR) - install tests/* $(DESTDIR) - -clean: arch_clean - $(RM) lib/.*.d $(libcflat) $(cflatobjs) - -libfdt_clean: - $(RM) $(LIBFDT_archive) \ - $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS)) \ - $(LIBFDT_objdir)/.*.d - -distclean: clean libfdt_clean - $(RM) lib/asm lib/config.h config.mak $(TEST_DIR)-run msr.out cscope.* build-head - $(RM) -r tests logs logs.old - -cscope: cscope_dirs = lib lib/libfdt lib/linux $(TEST_DIR) $(ARCH_LIBDIRS) lib/asm-generic -cscope: - $(RM) ./cscope.* - find -L $(cscope_dirs) -maxdepth 1 \ - -name '*.[chsS]' -exec realpath --relative-base=$(PWD) {} \; | sort -u > ./cscope.files - cscope -bk diff --git a/README.macOS.md b/README.macOS.md deleted file mode 100644 index de46d5fe..00000000 --- a/README.macOS.md +++ /dev/null @@ -1,47 +0,0 @@ -# kvm-unit-tests on macOS - -Cross-compiler with ELF support is required for build of kvm-unit-tests on -macOS. - -## Building cross-compiler from source - -A cross-compiler toolchain can be built from source using crosstool-ng. The -latest released version of -[crosstool-ng](https://github.com/crosstool-ng/crosstool-ng) can be installed -using [homebrew](https://brew.sh) -``` -$ brew install crosstool-ng -``` - -A case-sensitive APFS/HFS+ volume has to be created using Disk Utility as a -build and installation directory for the cross-compiler. Please [see Apple -documentation](https://support.apple.com/guide/disk-utility/dsku19ed921c/mac) -for details. - -Assuming the case-sensitive volume is named /Volumes/BuildTools, the -cross-compiler can be built and installed there: -``` -$ X_BUILD_DIR=/Volumes/BuildTools/ct-ng-build -$ X_INSTALL_DIR=/Volumes/BuildTools/x-tools -$ mkdir $X_BUILD_DIR -$ ct-ng -C $X_BUILD_DIR x86_64-unknown-linux-gnu -$ ct-ng -C $X_BUILD_DIR build CT_PREFIX=$X_INSTALL_DIR -``` - -Once compiled, the cross-compiler can be used to build the tests: -``` -$ ./configure --cross-prefix=$X_INSTALL_DIR/x86_64-unknown-linux-gnu/bin/x86_64-unknown-linux-gnu- -$ make -``` - -## Pre-built cross-compiler - -x86_64-elf-gcc package in Homebrew provides pre-built cross-compiler but it -fails to compile kvm-unit-tests. - -## Running the tests - -GNU coreutils should be installed prior to running the tests: -``` -$ brew install coreutils -``` diff --git a/arm/Makefile b/arm/Makefile deleted file mode 100644 index 8a007ab5..00000000 --- a/arm/Makefile +++ /dev/null @@ -1 +0,0 @@ -include $(SRCDIR)/$(TEST_DIR)/Makefile.$(ARCH) diff --git a/arm/Makefile.arm b/arm/Makefile.arm deleted file mode 100644 index d379a280..00000000 --- a/arm/Makefile.arm +++ /dev/null @@ -1,32 +0,0 @@ -# -# arm makefile -# -# Authors: Andrew Jones -# -bits = 32 -ldarch = elf32-littlearm -machine = -marm -mfpu=vfp - -# stack.o relies on frame pointers. -KEEP_FRAME_POINTER := y - -CFLAGS += $(machine) -CFLAGS += -mcpu=$(PROCESSOR) -CFLAGS += -mno-unaligned-access - -arch_LDFLAGS = -Ttext=40010000 - -define arch_elf_check = -endef - -cstart.o = $(TEST_DIR)/cstart.o -cflatobjs += lib/arm/spinlock.o -cflatobjs += lib/arm/processor.o -cflatobjs += lib/arm/stack.o - -# arm specific tests -tests = - -include $(SRCDIR)/$(TEST_DIR)/Makefile.common - -arch_clean: arm_clean diff --git a/arm/Makefile.arm64 b/arm/Makefile.arm64 deleted file mode 100644 index dfd0c56f..00000000 --- a/arm/Makefile.arm64 +++ /dev/null @@ -1,34 +0,0 @@ -# -# arm64 makefile -# -# Authors: Andrew Jones -# -bits = 64 -ldarch = elf64-littleaarch64 - -arch_LDFLAGS = -pie -n -CFLAGS += -mstrict-align - -define arch_elf_check = - $(if $(shell ! $(OBJDUMP) -R $(1) >&/dev/null && echo "nok"), - $(error $(shell $(OBJDUMP) -R $(1) 2>&1))) - $(if $(shell $(OBJDUMP) -R $(1) | grep R_ | grep -v R_AARCH64_RELATIVE), - $(error $(1) has unsupported reloc types)) -endef - -cstart.o = $(TEST_DIR)/cstart64.o -cflatobjs += lib/arm64/processor.o -cflatobjs += lib/arm64/spinlock.o -cflatobjs += lib/arm64/gic-v3-its.o lib/arm64/gic-v3-its-cmd.o - -OBJDIRS += lib/arm64 - -# arm64 specific tests -tests = $(TEST_DIR)/timer.flat -tests += $(TEST_DIR)/micro-bench.flat -tests += $(TEST_DIR)/cache.flat - -include $(SRCDIR)/$(TEST_DIR)/Makefile.common - -arch_clean: arm_clean - $(RM) lib/arm64/.*.d diff --git a/arm/Makefile.common b/arm/Makefile.common deleted file mode 100644 index a123e85d..00000000 --- a/arm/Makefile.common +++ /dev/null @@ -1,86 +0,0 @@ -# -# arm common makefile -# -# Authors: Andrew Jones -# - -tests-common = $(TEST_DIR)/selftest.flat -tests-common += $(TEST_DIR)/spinlock-test.flat -tests-common += $(TEST_DIR)/pci-test.flat -tests-common += $(TEST_DIR)/pmu.flat -tests-common += $(TEST_DIR)/gic.flat -tests-common += $(TEST_DIR)/psci.flat -tests-common += $(TEST_DIR)/sieve.flat -tests-common += $(TEST_DIR)/pl031.flat - -tests-all = $(tests-common) $(tests) -all: directories $(tests-all) - -$(TEST_DIR)/sieve.elf: AUXFLAGS = 0x1 - -################################################################## -AUXFLAGS ?= 0x0 - -CFLAGS += -std=gnu99 -CFLAGS += -ffreestanding -CFLAGS += -O2 -CFLAGS += -I $(SRCDIR)/lib -I $(SRCDIR)/lib/libfdt -I lib - -# We want to keep intermediate files -.PRECIOUS: %.elf %.o - -asm-offsets = lib/$(ARCH)/asm-offsets.h -include $(SRCDIR)/scripts/asm-offsets.mak - -cflatobjs += lib/util.o lib/getchar.o -cflatobjs += lib/alloc_phys.o -cflatobjs += lib/alloc_page.o -cflatobjs += lib/vmalloc.o -cflatobjs += lib/alloc.o -cflatobjs += lib/devicetree.o -cflatobjs += lib/pci.o -cflatobjs += lib/pci-host-generic.o -cflatobjs += lib/pci-testdev.o -cflatobjs += lib/virtio.o -cflatobjs += lib/virtio-mmio.o -cflatobjs += lib/chr-testdev.o -cflatobjs += lib/arm/io.o -cflatobjs += lib/arm/setup.o -cflatobjs += lib/arm/mmu.o -cflatobjs += lib/arm/bitops.o -cflatobjs += lib/arm/psci.o -cflatobjs += lib/arm/smp.o -cflatobjs += lib/arm/delay.o -cflatobjs += lib/arm/gic.o lib/arm/gic-v2.o lib/arm/gic-v3.o - -OBJDIRS += lib/arm - -libeabi = lib/arm/libeabi.a -eabiobjs = lib/arm/eabi_compat.o - -libgcc := $(shell $(CC) $(machine) --print-libgcc-file-name) - -FLATLIBS = $(libcflat) $(LIBFDT_archive) $(libgcc) $(libeabi) -%.elf: LDFLAGS = -nostdlib $(arch_LDFLAGS) -%.elf: %.o $(FLATLIBS) $(SRCDIR)/arm/flat.lds $(cstart.o) - $(CC) $(CFLAGS) -c -o $(@:.elf=.aux.o) $(SRCDIR)/lib/auxinfo.c \ - -DPROGNAME=\"$(@:.elf=.flat)\" -DAUXFLAGS=$(AUXFLAGS) - $(LD) $(LDFLAGS) -o $@ -T $(SRCDIR)/arm/flat.lds \ - $(filter %.o, $^) $(FLATLIBS) $(@:.elf=.aux.o) - $(RM) $(@:.elf=.aux.o) - @chmod a-x $@ - -%.flat: %.elf - $(call arch_elf_check, $^) - $(OBJCOPY) -O binary $^ $@ - @chmod a-x $@ - -$(libeabi): $(eabiobjs) - $(AR) rcs $@ $^ - -arm_clean: libfdt_clean asm_offsets_clean - $(RM) $(TEST_DIR)/*.{o,flat,elf} $(libeabi) $(eabiobjs) \ - $(TEST_DIR)/.*.d lib/arm/.*.d - -generated-files = $(asm-offsets) -$(tests-all:.flat=.o) $(cstart.o) $(cflatobjs): $(generated-files) diff --git a/arm/cache.c b/arm/cache.c deleted file mode 100644 index 2756066f..00000000 --- a/arm/cache.c +++ /dev/null @@ -1,123 +0,0 @@ -#include -#include -#include -#include -#include - -#define NTIMES (1 << 16) - -#define CTR_DIC (1UL << 29) -#define CTR_IDC (1UL << 28) - -#define CLIDR_LOC_SHIFT 24 -#define CLIDR_LOC_MASK (7UL << CLIDR_LOC_SHIFT) -#define CLIDR_LOUU_SHIFT 27 -#define CLIDR_LOUU_MASK (7UL << CLIDR_LOUU_SHIFT) -#define CLIDR_LOUIS_SHIFT 21 -#define CLIDR_LOUIS_MASK (7UL << CLIDR_LOUIS_SHIFT) - -#define RET 0xd65f03c0 -#define MOV_X0(x) (0xd2800000 | (((x) & 0xffff) << 5)) - -#define clean_dcache_pou(addr) \ - asm volatile("dc cvau, %0\n" :: "r" (addr) : "memory") -#define inval_icache_pou(addr) \ - asm volatile("ic ivau, %0\n" :: "r" (addr) : "memory") - -typedef int (*fn_t)(void); - -static inline void prime_icache(u32 *code, u32 insn) -{ - *code = insn; - /* This is the sequence recommended in ARM DDI 0487E.a, page B2-136. */ - clean_dcache_pou(code); - dsb(ish); - inval_icache_pou(code); - dsb(ish); - isb(); - - ((fn_t)code)(); -} - -static void check_code_generation(bool dcache_clean, bool icache_inval) -{ - u32 fn[] = {MOV_X0(0x42), RET}; - u32 *code = alloc_page(); - unsigned long sctlr; - int i, ret; - bool success; - - /* Make sure we can execute from a writable page */ - mmu_clear_user(current_thread_info()->pgtable, (unsigned long)code); - - sctlr = read_sysreg(sctlr_el1); - if (sctlr & SCTLR_EL1_WXN) { - sctlr &= ~SCTLR_EL1_WXN; - write_sysreg(sctlr, sctlr_el1); - isb(); - /* SCTLR_EL1.WXN is permitted to be cached in a TLB. */ - flush_tlb_all(); - } - - for (i = 0; i < ARRAY_SIZE(fn); i++) { - *(code + i) = fn[i]; - clean_dcache_pou(code + i); - dsb(ish); - inval_icache_pou(code + i); - } - dsb(ish); - isb(); - - /* Sanity check */ - ((fn_t)code)(); - - success = true; - for (i = 0; i < NTIMES; i++) { - prime_icache(code, MOV_X0(0x42)); - *code = MOV_X0(0x66); - if (dcache_clean) - clean_dcache_pou(code); - if (icache_inval) { - if (dcache_clean) - dsb(ish); - inval_icache_pou(code); - } - dsb(ish); - isb(); - - ret = ((fn_t)code)(); - success &= (ret == 0x66); - } - - report(success, "code generation"); -} - -int main(int argc, char **argv) -{ - u64 ctr, clidr; - bool dcache_clean, icache_inval; - - report_prefix_push("IDC-DIC"); - - ctr = read_sysreg(ctr_el0); - dcache_clean = !(ctr & CTR_IDC); - icache_inval = !(ctr & CTR_DIC); - - if (dcache_clean) { - clidr = read_sysreg(clidr_el1); - if ((clidr & CLIDR_LOC_MASK) == 0) - dcache_clean = false; - if ((clidr & CLIDR_LOUU_MASK) == 0 && - (clidr & CLIDR_LOUIS_MASK) == 0) - dcache_clean = false; - } - - if (dcache_clean) - report_info("dcache clean to PoU required"); - if (icache_inval) - report_info("icache invalidation to PoU required"); - - check_code_generation(dcache_clean, icache_inval); - - return report_summary(); -} diff --git a/arm/cstart.S b/arm/cstart.S deleted file mode 100644 index ef936ae2..00000000 --- a/arm/cstart.S +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Boot entry point and assembler functions for armv7 tests. - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#define __ASSEMBLY__ -#include -#include -#include -#include -#include -#include - -#define THREAD_START_SP ((THREAD_SIZE - S_FRAME_SIZE * 8) & ~7) - -.arm - -.section .init - -.globl start -start: - /* - * set stack, making room at top of stack for cpu0's - * exception stacks. Must start wtih stackptr, not - * stacktop, so the thread size masking (shifts) work. - */ - ldr sp, =stackptr - lsr sp, #THREAD_SHIFT - lsl sp, #THREAD_SHIFT - add sp, #THREAD_START_SP - - /* - * save sp before pushing anything on the stack - * lr makes a good temp register right now - */ - mov lr, sp - - /* - * bootloader params are in r0-r2 - * See the kernel doc Documentation/arm/Booting - * r0 = 0 - * r1 = machine type number - * r2 = physical address of the dtb - * - * As we have no need for r0's nor r1's value, then - * put the dtb in r0. This allows setup to be consistent - * with arm64. - */ - mov r0, r2 - push {r0-r1} - - /* set up vector table, mode stacks, and enable the VFP */ - mov r0, lr @ lr is stack top (see above), - @ which is the exception stacks base - bl exceptions_init - bl enable_vfp - - /* complete setup */ - pop {r0-r1} - bl setup - bl get_mmu_off - cmp r0, #0 - bne 1f - bl setup_vm - -1: - /* run the test */ - ldr r0, =__argc - ldr r0, [r0] - ldr r1, =__argv - ldr r2, =__environ - bl main - bl exit - b halt - - -.macro set_mode_stack mode, stack - add \stack, #S_FRAME_SIZE - msr cpsr_c, #(\mode | PSR_I_BIT | PSR_F_BIT) - isb - mov sp, \stack -.endm - -exceptions_init: - mrc p15, 0, r2, c1, c0, 0 @ read SCTLR - bic r2, #CR_V @ SCTLR.V := 0 - mcr p15, 0, r2, c1, c0, 0 @ write SCTLR - ldr r2, =vector_table - mcr p15, 0, r2, c12, c0, 0 @ write VBAR - - mrs r2, cpsr - - /* first frame reserved for svc mode */ - set_mode_stack UND_MODE, r0 - set_mode_stack ABT_MODE, r0 - set_mode_stack IRQ_MODE, r0 - set_mode_stack FIQ_MODE, r0 - - msr cpsr_cxsf, r2 @ back to svc mode - isb - mov pc, lr - -enable_vfp: - /* Enable full access to CP10 and CP11: */ - mov r0, #(3 << 22 | 3 << 20) - mcr p15, 0, r0, c1, c0, 2 - isb - /* Set the FPEXC.EN bit to enable Advanced SIMD and VFP: */ - mov r0, #(1 << 30) - vmsr fpexc, r0 - mov pc, lr - -.text - -.global get_mmu_off -get_mmu_off: - ldr r0, =auxinfo - ldr r0, [r0, #4] - and r0, #AUXINFO_MMU_OFF - mov pc, lr - -.global secondary_entry -secondary_entry: - /* enable the MMU unless requested off */ - bl get_mmu_off - cmp r0, #0 - bne 1f - mov r1, #0 - ldr r0, =mmu_idmap - ldr r0, [r0] - bl asm_mmu_enable - -1: - /* - * Set the stack, and set up vector table - * and exception stacks. Exception stacks - * space starts at stack top and grows up. - */ - ldr r1, =secondary_data - ldr r0, [r1] - mov sp, r0 - bl exceptions_init - bl enable_vfp - - /* finish init in C code */ - bl secondary_cinit - - /* r0 is now the entry function, run it */ - blx r0 - b do_idle - -.globl halt -halt: -1: wfi - b 1b - -/* - * asm_mmu_enable - * Inputs: - * (r0 - lo, r1 - hi) is the base address of the translation table - * Outputs: none - */ -.equ PRRR, 0xeeaa4400 @ MAIR0 (from Linux kernel) -.equ NMRR, 0xff000004 @ MAIR1 (from Linux kernel) -.globl asm_mmu_enable -asm_mmu_enable: - /* TLBIALL */ - mcr p15, 0, r2, c8, c7, 0 - dsb nsh - - /* TTBCR */ - ldr r2, =(TTBCR_EAE | \ - TTBCR_SH0_SHARED | \ - TTBCR_IRGN0_WBWA | TTBCR_ORGN0_WBWA) - mcr p15, 0, r2, c2, c0, 2 - isb - - /* MAIR */ - ldr r2, =PRRR - mcr p15, 0, r2, c10, c2, 0 - ldr r2, =NMRR - mcr p15, 0, r2, c10, c2, 1 - - /* TTBR0 */ - mcrr p15, 0, r0, r1, c2 - isb - - /* SCTLR */ - mrc p15, 0, r2, c1, c0, 0 - orr r2, #CR_C - orr r2, #CR_I - orr r2, #CR_M - mcr p15, 0, r2, c1, c0, 0 - isb - - mov pc, lr - -.macro dcache_clean_inval domain, start, end, tmp1, tmp2 - ldr \tmp1, =dcache_line_size - ldr \tmp1, [\tmp1] - sub \tmp2, \tmp1, #1 - bic \start, \start, \tmp2 -9998: - /* DCCIMVAC */ - mcr p15, 0, \start, c7, c14, 1 - add \start, \start, \tmp1 - cmp \start, \end - blo 9998b - dsb \domain -.endm - -.globl asm_mmu_disable -asm_mmu_disable: - /* SCTLR */ - mrc p15, 0, r0, c1, c0, 0 - bic r0, #CR_M - mcr p15, 0, r0, c1, c0, 0 - isb - - ldr r0, =__phys_offset - ldr r0, [r0] - ldr r1, =__phys_end - ldr r1, [r1] - dcache_clean_inval sy, r0, r1, r2, r3 - isb - - mov pc, lr - -/* - * Vector stubs - * Simplified version of the Linux kernel implementation - * arch/arm/kernel/entry-armv.S - * - * Each mode has an S_FRAME_SIZE sized memory region, - * and the mode's stack pointer has been initialized - * to the base of that region in exceptions_init. - */ -.macro vector_stub, name, vec, mode, correction=0 -.align 5 -vector_\name: -.if \correction - sub lr, lr, #\correction -.endif - /* - * Save r0, r1, lr_ (parent PC) - * and spsr_ (parent CPSR) - */ - str r0, [sp, #S_R0] - str r1, [sp, #S_R1] - str lr, [sp, #S_PC] - mrs r0, spsr - str r0, [sp, #S_PSR] - - /* Prepare for SVC32 mode. */ - mrs r0, cpsr - bic r0, #MODE_MASK - orr r0, #SVC_MODE - msr spsr_cxsf, r0 - - /* Branch to handler in SVC mode */ - mov r0, #\vec - mov r1, sp - ldr lr, =vector_common - movs pc, lr -.endm - -vector_stub rst, 0, UND_MODE -vector_stub und, 1, UND_MODE -vector_stub pabt, 3, ABT_MODE, 4 -vector_stub dabt, 4, ABT_MODE, 8 -vector_stub irq, 6, IRQ_MODE, 4 -vector_stub fiq, 7, FIQ_MODE, 4 - -.align 5 -vector_svc: - /* - * Save r0, r1, lr_ (parent PC) - * and spsr_ (parent CPSR) - */ - push { r1 } - lsr r1, sp, #THREAD_SHIFT - lsl r1, #THREAD_SHIFT - add r1, #THREAD_START_SP - str r0, [r1, #S_R0] - pop { r0 } - str r0, [r1, #S_R1] - str lr, [r1, #S_PC] - mrs r0, spsr - str r0, [r1, #S_PSR] - - /* - * Branch to handler, still in SVC mode. - * r0 := 2 is the svc vector number. - */ - mov r0, #2 - ldr lr, =vector_common - mov pc, lr - -vector_common: - /* make room for pt_regs */ - sub sp, #S_FRAME_SIZE - tst sp, #4 @ check stack alignment - subne sp, #4 - - /* store registers r0-r12 */ - stmia sp, { r0-r12 } @ stored wrong r0 and r1, fix later - - /* get registers saved in the stub */ - ldr r2, [r1, #S_R0] @ r0 - ldr r3, [r1, #S_R1] @ r1 - ldr r4, [r1, #S_PC] @ lr_ (parent PC) - ldr r5, [r1, #S_PSR] @ spsr_ (parent CPSR) - - /* fix r0 and r1 */ - str r2, [sp, #S_R0] - str r3, [sp, #S_R1] - - /* store sp_svc, if we were in usr mode we'll fix this later */ - add r6, sp, #S_FRAME_SIZE - addne r6, #4 @ stack wasn't aligned - str r6, [sp, #S_SP] - - str lr, [sp, #S_LR] @ store lr_svc, fix later for usr mode - str r4, [sp, #S_PC] @ store lr_ - str r5, [sp, #S_PSR] @ store spsr_ - - /* set ORIG_r0 */ - mov r2, #-1 - str r2, [sp, #S_OLD_R0] - - /* if we were in usr mode then we need sp_usr and lr_usr instead */ - and r1, r5, #MODE_MASK - cmp r1, #USR_MODE - bne 1f - add r1, sp, #S_SP - stmia r1, { sp,lr }^ - - /* Call the handler. r0 is the vector number, r1 := pt_regs */ -1: mov r1, sp - bl do_handle_exception - - /* - * make sure we restore sp_svc on mode change. No need to - * worry about lr_svc though, as that gets clobbered on - * exception entry anyway. - */ - str r6, [sp, #S_SP] - - /* return from exception */ - msr spsr_cxsf, r5 - ldmia sp, { r0-pc }^ - -.align 5 -vector_addrexcptn: - b vector_addrexcptn - -.section .text.ex -.align 5 -vector_table: - b vector_rst - b vector_und - b vector_svc - b vector_pabt - b vector_dabt - b vector_addrexcptn @ should never happen - b vector_irq - b vector_fiq diff --git a/arm/cstart64.S b/arm/cstart64.S deleted file mode 100644 index ffdd49f7..00000000 --- a/arm/cstart64.S +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Boot entry point and assembler functions for aarch64 tests. - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#define __ASSEMBLY__ -#include -#include -#include -#include -#include -#include - -.section .init - -/* - * Bootloader params are in x0-x3. See kernel doc - * Documentation/arm64/booting.txt - */ -.globl start -start: - /* get our base address */ - adrp x4, start - add x4, x4, :lo12:start - - /* - * Update all R_AARCH64_RELATIVE relocations using the table - * of Elf64_Rela entries between reloc_start/end. The build - * will not emit other relocation types. - * - * struct Elf64_Rela { - * uint64_t r_offset; - * uint64_t r_info; - * int64_t r_addend; - * } - */ - adrp x5, reloc_start - add x5, x5, :lo12:reloc_start - adrp x6, reloc_end - add x6, x6, :lo12:reloc_end -1: - cmp x5, x6 - b.hs 1f - ldr x7, [x5] // r_offset - ldr x8, [x5, #16] // r_addend - add x8, x8, x4 // val = base + r_addend - str x8, [x4, x7] // base[r_offset] = val - add x5, x5, #24 - b 1b - -1: - /* set up stack */ - mov x4, #1 - msr spsel, x4 - isb - adrp x4, stackptr - add sp, x4, :lo12:stackptr - - /* enable FP/ASIMD */ - mov x4, #(3 << 20) - msr cpacr_el1, x4 - - /* set up exception handling */ - bl exceptions_init - - /* complete setup */ - bl setup // x0 is the addr of the dtb - bl get_mmu_off - cbnz x0, 1f - bl setup_vm - -1: - /* run the test */ - adrp x0, __argc - ldr x0, [x0, :lo12:__argc] - adrp x1, __argv - add x1, x1, :lo12:__argv - adrp x2, __environ - add x2, x2, :lo12:__environ - bl main - bl exit - b halt - -exceptions_init: - adrp x4, vector_table - add x4, x4, :lo12:vector_table - msr vbar_el1, x4 - isb - ret - -.text - -.globl get_mmu_off -get_mmu_off: - adrp x0, auxinfo - ldr x0, [x0, :lo12:auxinfo + 8] - and x0, x0, #AUXINFO_MMU_OFF - ret - -.globl secondary_entry -secondary_entry: - /* Enable FP/ASIMD */ - mov x0, #(3 << 20) - msr cpacr_el1, x0 - - /* set up exception handling */ - bl exceptions_init - - /* enable the MMU unless requested off */ - bl get_mmu_off - cbnz x0, 1f - adrp x0, mmu_idmap - ldr x0, [x0, :lo12:mmu_idmap] - bl asm_mmu_enable - -1: - /* set the stack */ - adrp x0, secondary_data - ldr x0, [x0, :lo12:secondary_data] - mov sp, x0 - - /* finish init in C code */ - bl secondary_cinit - - /* x0 is now the entry function, run it */ - blr x0 - b do_idle - -.globl halt -halt: -1: wfi - b 1b - -/* - * asm_mmu_enable - * Inputs: - * x0 is the base address of the translation table - * Outputs: none - * - * Adapted from - * arch/arm64/kernel/head.S - * arch/arm64/mm/proc.S - */ - -/* - * Memory region attributes for LPAE: - * - * n = AttrIndx[2:0] - * n MAIR - * DEVICE_nGnRnE 000 00000000 - * DEVICE_nGnRE 001 00000100 - * DEVICE_GRE 010 00001100 - * NORMAL_NC 011 01000100 - * NORMAL 100 11111111 - */ -#define MAIR(attr, mt) ((attr) << ((mt) * 8)) - -.globl asm_mmu_enable -asm_mmu_enable: - tlbi vmalle1 // invalidate I + D TLBs - dsb nsh - - /* TCR */ - ldr x1, =TCR_TxSZ(VA_BITS) | \ - TCR_TG0_64K | TCR_TG1_64K | \ - TCR_IRGN_WBWA | TCR_ORGN_WBWA | \ - TCR_SHARED - mrs x2, id_aa64mmfr0_el1 - bfi x1, x2, #32, #3 - msr tcr_el1, x1 - - /* MAIR */ - ldr x1, =MAIR(0x00, MT_DEVICE_nGnRnE) | \ - MAIR(0x04, MT_DEVICE_nGnRE) | \ - MAIR(0x0c, MT_DEVICE_GRE) | \ - MAIR(0x44, MT_NORMAL_NC) | \ - MAIR(0xff, MT_NORMAL) - msr mair_el1, x1 - - /* TTBR0 */ - msr ttbr0_el1, x0 - isb - - /* SCTLR */ - mrs x1, sctlr_el1 - orr x1, x1, SCTLR_EL1_C - orr x1, x1, SCTLR_EL1_I - orr x1, x1, SCTLR_EL1_M - msr sctlr_el1, x1 - isb - - ret - -/* Taken with small changes from arch/arm64/incluse/asm/assembler.h */ -.macro dcache_by_line_op op, domain, start, end, tmp1, tmp2 - adrp \tmp1, dcache_line_size - ldr \tmp1, [\tmp1, :lo12:dcache_line_size] - sub \tmp2, \tmp1, #1 - bic \start, \start, \tmp2 -9998: - dc \op , \start - add \start, \start, \tmp1 - cmp \start, \end - b.lo 9998b - dsb \domain -.endm - -.globl asm_mmu_disable -asm_mmu_disable: - mrs x0, sctlr_el1 - bic x0, x0, SCTLR_EL1_M - msr sctlr_el1, x0 - isb - - /* Clean + invalidate the entire memory */ - adrp x0, __phys_offset - ldr x0, [x0, :lo12:__phys_offset] - adrp x1, __phys_end - ldr x1, [x1, :lo12:__phys_end] - dcache_by_line_op civac, sy, x0, x1, x2, x3 - isb - - ret - -/* - * Vectors - * Adapted from arch/arm64/kernel/entry.S - */ -.macro vector_stub, name, vec -\name: - stp x0, x1, [sp, #-S_FRAME_SIZE]! - stp x2, x3, [sp, #16] - stp x4, x5, [sp, #32] - stp x6, x7, [sp, #48] - stp x8, x9, [sp, #64] - stp x10, x11, [sp, #80] - stp x12, x13, [sp, #96] - stp x14, x15, [sp, #112] - stp x16, x17, [sp, #128] - stp x18, x19, [sp, #144] - stp x20, x21, [sp, #160] - stp x22, x23, [sp, #176] - stp x24, x25, [sp, #192] - stp x26, x27, [sp, #208] - stp x28, x29, [sp, #224] - - str x30, [sp, #S_LR] - - .if \vec >= 8 - mrs x1, sp_el0 - .else - add x1, sp, #S_FRAME_SIZE - .endif - str x1, [sp, #S_SP] - - mrs x1, elr_el1 - mrs x2, spsr_el1 - stp x1, x2, [sp, #S_PC] - - mov x0, \vec - mov x1, sp - mrs x2, esr_el1 - bl do_handle_exception - - ldp x1, x2, [sp, #S_PC] - msr spsr_el1, x2 - msr elr_el1, x1 - - .if \vec >= 8 - ldr x1, [sp, #S_SP] - msr sp_el0, x1 - .endif - - ldr x30, [sp, #S_LR] - - ldp x28, x29, [sp, #224] - ldp x26, x27, [sp, #208] - ldp x24, x25, [sp, #192] - ldp x22, x23, [sp, #176] - ldp x20, x21, [sp, #160] - ldp x18, x19, [sp, #144] - ldp x16, x17, [sp, #128] - ldp x14, x15, [sp, #112] - ldp x12, x13, [sp, #96] - ldp x10, x11, [sp, #80] - ldp x8, x9, [sp, #64] - ldp x6, x7, [sp, #48] - ldp x4, x5, [sp, #32] - ldp x2, x3, [sp, #16] - ldp x0, x1, [sp], #S_FRAME_SIZE - - eret -.endm - -vector_stub el1t_sync, 0 -vector_stub el1t_irq, 1 -vector_stub el1t_fiq, 2 -vector_stub el1t_error, 3 - -vector_stub el1h_sync, 4 -vector_stub el1h_irq, 5 -vector_stub el1h_fiq, 6 -vector_stub el1h_error, 7 - -vector_stub el0_sync_64, 8 -vector_stub el0_irq_64, 9 -vector_stub el0_fiq_64, 10 -vector_stub el0_error_64, 11 - -vector_stub el0_sync_32, 12 -vector_stub el0_irq_32, 13 -vector_stub el0_fiq_32, 14 -vector_stub el0_error_32, 15 - -.section .text.ex - -.macro ventry, label -.align 7 - b \label -.endm - -.align 11 -vector_table: - ventry el1t_sync // Synchronous EL1t - ventry el1t_irq // IRQ EL1t - ventry el1t_fiq // FIQ EL1t - ventry el1t_error // Error EL1t - - ventry el1h_sync // Synchronous EL1h - ventry el1h_irq // IRQ EL1h - ventry el1h_fiq // FIQ EL1h - ventry el1h_error // Error EL1h - - ventry el0_sync_64 // Synchronous 64-bit EL0 - ventry el0_irq_64 // IRQ 64-bit EL0 - ventry el0_fiq_64 // FIQ 64-bit EL0 - ventry el0_error_64 // Error 64-bit EL0 - - ventry el0_sync_32 // Synchronous 32-bit EL0 - ventry el0_irq_32 // IRQ 32-bit EL0 - ventry el0_fiq_32 // FIQ 32-bit EL0 - ventry el0_error_32 // Error 32-bit EL0 diff --git a/arm/flat.lds b/arm/flat.lds deleted file mode 100644 index 25f8d03c..00000000 --- a/arm/flat.lds +++ /dev/null @@ -1,43 +0,0 @@ - -SECTIONS -{ - .text : { *(.init) *(.text) *(.text.*) } - . = ALIGN(64K); - PROVIDE(etext = .); - - PROVIDE(reloc_start = .); - .rela.dyn : { *(.rela.dyn) } - PROVIDE(reloc_end = .); - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .hash : { *(.hash) } - .gnu.hash : { *(.gnu.hash) } - .got : { *(.got) *(.got.plt) } - .eh_frame : { *(.eh_frame) } - - .rodata : { *(.rodata*) } - .data : { *(.data) } - .bss : { *(.bss) } - . = ALIGN(64K); - PROVIDE(edata = .); - - /* - * stack depth is 16K for arm and PAGE_SIZE for arm64, see THREAD_SIZE - * sp must be 16 byte aligned for arm64, and 8 byte aligned for arm - * sp must always be strictly less than the true stacktop - */ - . += 64K; - . = ALIGN(64K); - PROVIDE(stackptr = . - 16); - PROVIDE(stacktop = .); - - /DISCARD/ : { - *(.note*) - *(.interp) - *(.debug*) - *(.comment) - *(.dynamic) - } -} - -ENTRY(start) diff --git a/arm/gic.c b/arm/gic.c deleted file mode 100644 index dc1e88c6..00000000 --- a/arm/gic.c +++ /dev/null @@ -1,1003 +0,0 @@ -/* - * GIC tests - * - * GICv2 - * + test sending/receiving IPIs - * + MMIO access tests - * GICv3 - * + test sending/receiving IPIs - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IPI_SENDER 1 -#define IPI_IRQ 1 - -struct gic { - struct { - void (*send_self)(void); - void (*send_broadcast)(void); - } ipi; -}; - -static struct gic *gic; -static int acked[NR_CPUS], spurious[NR_CPUS]; -static int bad_sender[NR_CPUS], bad_irq[NR_CPUS]; -static cpumask_t ready; - -static void nr_cpu_check(int nr) -{ - if (nr_cpus < nr) - report_abort("At least %d cpus required", nr); -} - -static void wait_on_ready(void) -{ - cpumask_set_cpu(smp_processor_id(), &ready); - while (!cpumask_full(&ready)) - cpu_relax(); -} - -static void stats_reset(void) -{ - int i; - - for (i = 0; i < nr_cpus; ++i) { - acked[i] = 0; - bad_sender[i] = -1; - bad_irq[i] = -1; - } - smp_wmb(); -} - -static void check_acked(const char *testname, cpumask_t *mask) -{ - int missing = 0, extra = 0, unexpected = 0; - int nr_pass, cpu, i; - bool bad = false; - - /* Wait up to 5s for all interrupts to be delivered */ - for (i = 0; i < 50; ++i) { - mdelay(100); - nr_pass = 0; - for_each_present_cpu(cpu) { - smp_rmb(); - nr_pass += cpumask_test_cpu(cpu, mask) ? - acked[cpu] == 1 : acked[cpu] == 0; - - if (bad_sender[cpu] != -1) { - printf("cpu%d received IPI from wrong sender %d\n", - cpu, bad_sender[cpu]); - bad = true; - } - - if (bad_irq[cpu] != -1) { - printf("cpu%d received wrong irq %d\n", - cpu, bad_irq[cpu]); - bad = true; - } - } - if (nr_pass == nr_cpus) { - report(!bad, "%s", testname); - if (i) - report_info("took more than %d ms", i * 100); - return; - } - } - - for_each_present_cpu(cpu) { - if (cpumask_test_cpu(cpu, mask)) { - if (!acked[cpu]) - ++missing; - else if (acked[cpu] > 1) - ++extra; - } else { - if (acked[cpu]) - ++unexpected; - } - } - - report(false, "%s", testname); - report_info("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d", - missing, extra, unexpected); -} - -static void check_spurious(void) -{ - int cpu; - - smp_rmb(); - for_each_present_cpu(cpu) { - if (spurious[cpu]) - report_info("WARN: cpu%d got %d spurious interrupts", - cpu, spurious[cpu]); - } -} - -static void check_ipi_sender(u32 irqstat) -{ - if (gic_version() == 2) { - int src = (irqstat >> 10) & 7; - - if (src != IPI_SENDER) - bad_sender[smp_processor_id()] = src; - } -} - -static void check_irqnr(u32 irqnr) -{ - if (irqnr != IPI_IRQ) - bad_irq[smp_processor_id()] = irqnr; -} - -static void ipi_handler(struct pt_regs *regs __unused) -{ - u32 irqstat = gic_read_iar(); - u32 irqnr = gic_iar_irqnr(irqstat); - - if (irqnr != GICC_INT_SPURIOUS) { - gic_write_eoir(irqstat); - smp_rmb(); /* pairs with wmb in stats_reset */ - ++acked[smp_processor_id()]; - check_ipi_sender(irqstat); - check_irqnr(irqnr); - smp_wmb(); /* pairs with rmb in check_acked */ - } else { - ++spurious[smp_processor_id()]; - smp_wmb(); - } -} - -static void setup_irq(irq_handler_fn handler) -{ - gic_enable_defaults(); -#ifdef __arm__ - install_exception_handler(EXCPTN_IRQ, handler); -#else - install_irq_handler(EL1H_IRQ, handler); -#endif - local_irq_enable(); -} - -#if defined(__aarch64__) -struct its_event { - int cpu_id; - int lpi_id; -}; - -struct its_stats { - struct its_event expected; - struct its_event observed; -}; - -static struct its_stats lpi_stats; - -static void lpi_handler(struct pt_regs *regs __unused) -{ - u32 irqstat = gic_read_iar(); - int irqnr = gic_iar_irqnr(irqstat); - - gic_write_eoir(irqstat); - assert(irqnr >= 8192); - smp_rmb(); /* pairs with wmb in lpi_stats_expect */ - lpi_stats.observed.cpu_id = smp_processor_id(); - lpi_stats.observed.lpi_id = irqnr; - acked[lpi_stats.observed.cpu_id]++; - smp_wmb(); /* pairs with rmb in check_lpi_stats */ -} - -static void lpi_stats_expect(int exp_cpu_id, int exp_lpi_id) -{ - lpi_stats.expected.cpu_id = exp_cpu_id; - lpi_stats.expected.lpi_id = exp_lpi_id; - lpi_stats.observed.cpu_id = -1; - lpi_stats.observed.lpi_id = -1; - smp_wmb(); /* pairs with rmb in handler */ -} - -static void check_lpi_stats(const char *msg) -{ - int i; - - for (i = 0; i < 50; i++) { - mdelay(100); - smp_rmb(); /* pairs with wmb in lpi_handler */ - if (lpi_stats.observed.cpu_id == lpi_stats.expected.cpu_id && - lpi_stats.observed.lpi_id == lpi_stats.expected.lpi_id) { - report(true, "%s", msg); - return; - } - } - - if (lpi_stats.observed.cpu_id == -1 && lpi_stats.observed.lpi_id == -1) { - report_info("No LPI received whereas (cpuid=%d, intid=%d) " - "was expected", lpi_stats.expected.cpu_id, - lpi_stats.expected.lpi_id); - } else { - report_info("Unexpected LPI (cpuid=%d, intid=%d)", - lpi_stats.observed.cpu_id, - lpi_stats.observed.lpi_id); - } - report(false, "%s", msg); -} - -static void secondary_lpi_test(void) -{ - setup_irq(lpi_handler); - cpumask_set_cpu(smp_processor_id(), &ready); - while (1) - wfi(); -} - -static void check_lpi_hits(int *expected, const char *msg) -{ - bool pass = true; - int i; - - for_each_present_cpu(i) { - if (acked[i] != expected[i]) { - report_info("expected %d LPIs on PE #%d, %d observed", - expected[i], i, acked[i]); - pass = false; - break; - } - } - report(pass, "%s", msg); -} -#endif - -static void gicv2_ipi_send_self(void) -{ - writel(2 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR); -} - -static void gicv2_ipi_send_broadcast(void) -{ - writel(1 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR); -} - -static void gicv3_ipi_send_self(void) -{ - gic_ipi_send_single(IPI_IRQ, smp_processor_id()); -} - -static void gicv3_ipi_send_broadcast(void) -{ - gicv3_write_sgi1r(1ULL << 40 | IPI_IRQ << 24); - isb(); -} - -static void ipi_test_self(void) -{ - cpumask_t mask; - - report_prefix_push("self"); - stats_reset(); - cpumask_clear(&mask); - cpumask_set_cpu(smp_processor_id(), &mask); - gic->ipi.send_self(); - check_acked("IPI: self", &mask); - report_prefix_pop(); -} - -static void ipi_test_smp(void) -{ - cpumask_t mask; - int i; - - report_prefix_push("target-list"); - stats_reset(); - cpumask_copy(&mask, &cpu_present_mask); - for (i = smp_processor_id() & 1; i < nr_cpus; i += 2) - cpumask_clear_cpu(i, &mask); - gic_ipi_send_mask(IPI_IRQ, &mask); - check_acked("IPI: directed", &mask); - report_prefix_pop(); - - report_prefix_push("broadcast"); - stats_reset(); - cpumask_copy(&mask, &cpu_present_mask); - cpumask_clear_cpu(smp_processor_id(), &mask); - gic->ipi.send_broadcast(); - check_acked("IPI: broadcast", &mask); - report_prefix_pop(); -} - -static void ipi_send(void) -{ - setup_irq(ipi_handler); - wait_on_ready(); - ipi_test_self(); - ipi_test_smp(); - check_spurious(); - exit(report_summary()); -} - -static void ipi_recv(void) -{ - setup_irq(ipi_handler); - cpumask_set_cpu(smp_processor_id(), &ready); - while (1) - wfi(); -} - -static void ipi_test(void *data __unused) -{ - if (smp_processor_id() == IPI_SENDER) - ipi_send(); - else - ipi_recv(); -} - -static struct gic gicv2 = { - .ipi = { - .send_self = gicv2_ipi_send_self, - .send_broadcast = gicv2_ipi_send_broadcast, - }, -}; - -static struct gic gicv3 = { - .ipi = { - .send_self = gicv3_ipi_send_self, - .send_broadcast = gicv3_ipi_send_broadcast, - }, -}; - -static void ipi_clear_active_handler(struct pt_regs *regs __unused) -{ - u32 irqstat = gic_read_iar(); - u32 irqnr = gic_iar_irqnr(irqstat); - - if (irqnr != GICC_INT_SPURIOUS) { - void *base; - u32 val = 1 << IPI_IRQ; - - if (gic_version() == 2) - base = gicv2_dist_base(); - else - base = gicv3_sgi_base(); - - writel(val, base + GICD_ICACTIVER); - - smp_rmb(); /* pairs with wmb in stats_reset */ - ++acked[smp_processor_id()]; - check_irqnr(irqnr); - smp_wmb(); /* pairs with rmb in check_acked */ - } else { - ++spurious[smp_processor_id()]; - smp_wmb(); - } -} - -static void run_active_clear_test(void) -{ - report_prefix_push("active"); - setup_irq(ipi_clear_active_handler); - ipi_test_self(); - report_prefix_pop(); -} - -static bool test_ro_pattern_32(void *address, u32 pattern, u32 orig) -{ - u32 reg; - - writel(pattern, address); - reg = readl(address); - - if (reg != orig) - writel(orig, address); - - return reg == orig; -} - -static bool test_readonly_32(void *address, bool razwi) -{ - u32 orig, pattern; - - orig = readl(address); - if (razwi && orig) - return false; - - pattern = 0xffffffff; - if (orig != pattern) { - if (!test_ro_pattern_32(address, pattern, orig)) - return false; - } - - pattern = 0xa5a55a5a; - if (orig != pattern) { - if (!test_ro_pattern_32(address, pattern, orig)) - return false; - } - - pattern = 0; - if (orig != pattern) { - if (!test_ro_pattern_32(address, pattern, orig)) - return false; - } - - return true; -} - -static void test_typer_v2(uint32_t reg) -{ - int nr_gic_cpus = ((reg >> 5) & 0x7) + 1; - - report_info("nr_cpus=%d", nr_cpus); - report(nr_cpus == nr_gic_cpus, "all CPUs have interrupts"); -} - -#define BYTE(reg32, byte) (((reg32) >> ((byte) * 8)) & 0xff) -#define REPLACE_BYTE(reg32, byte, new) (((reg32) & ~(0xff << ((byte) * 8))) |\ - ((new) << ((byte) * 8))) - -/* - * Some registers are byte accessible, do a byte-wide read and write of known - * content to check for this. - * Apply a @mask to cater for special register properties. - * @pattern contains the value already in the register. - */ -static void test_byte_access(void *base_addr, u32 pattern, u32 mask) -{ - u32 reg = readb(base_addr + 1); - bool res; - - res = (reg == (BYTE(pattern, 1) & (mask >> 8))); - report(res, "byte reads successful"); - if (!res) - report_info("byte 1 of 0x%08x => 0x%02x", pattern & mask, reg); - - pattern = REPLACE_BYTE(pattern, 2, 0x1f); - writeb(BYTE(pattern, 2), base_addr + 2); - reg = readl(base_addr); - res = (reg == (pattern & mask)); - report(res, "byte writes successful"); - if (!res) - report_info("writing 0x%02x into bytes 2 => 0x%08x", - BYTE(pattern, 2), reg); -} - -static void test_priorities(int nr_irqs, void *priptr) -{ - u32 orig_prio, reg, pri_bits; - u32 pri_mask, pattern; - void *first_spi = priptr + GIC_FIRST_SPI; - - orig_prio = readl(first_spi); - report_prefix_push("IPRIORITYR"); - - /* - * Determine implemented number of priority bits by writing all 1's - * and checking the number of cleared bits in the value read back. - */ - writel(0xffffffff, first_spi); - pri_mask = readl(first_spi); - - reg = ~pri_mask; - report((((reg >> 16) == (reg & 0xffff)) && - ((reg & 0xff) == ((reg >> 8) & 0xff))), - "consistent priority masking"); - report_info("priority mask is 0x%08x", pri_mask); - - reg = reg & 0xff; - for (pri_bits = 8; reg & 1; reg >>= 1, pri_bits--) - ; - report(pri_bits >= 4, "implements at least 4 priority bits"); - report_info("%d priority bits implemented", pri_bits); - - pattern = 0; - writel(pattern, first_spi); - report(readl(first_spi) == pattern, "clearing priorities"); - - /* setting all priorities to their max valus was tested above */ - - report(test_readonly_32(priptr + nr_irqs, true), - "accesses beyond limit RAZ/WI"); - - writel(pattern, priptr + nr_irqs - 4); - report(readl(priptr + nr_irqs - 4) == (pattern & pri_mask), - "accessing last SPIs"); - - pattern = 0xff7fbf3f; - writel(pattern, first_spi); - report(readl(first_spi) == (pattern & pri_mask), - "priorities are preserved"); - - /* The PRIORITY registers are byte accessible. */ - test_byte_access(first_spi, pattern, pri_mask); - - report_prefix_pop(); - writel(orig_prio, first_spi); -} - -/* GICD_ITARGETSR is only used by GICv2. */ -static void test_targets(int nr_irqs) -{ - void *targetsptr = gicv2_dist_base() + GICD_ITARGETSR; - u32 orig_targets; - u32 cpu_mask; - u32 pattern, reg; - - orig_targets = readl(targetsptr + GIC_FIRST_SPI); - report_prefix_push("ITARGETSR"); - - cpu_mask = (1 << nr_cpus) - 1; - cpu_mask |= cpu_mask << 8; - cpu_mask |= cpu_mask << 16; - - /* Check that bits for non implemented CPUs are RAZ/WI. */ - if (nr_cpus < 8) { - writel(0xffffffff, targetsptr + GIC_FIRST_SPI); - report(!(readl(targetsptr + GIC_FIRST_SPI) & ~cpu_mask), - "bits for non-existent CPUs masked"); - report_info("%d non-existent CPUs", 8 - nr_cpus); - } else { - report_skip("CPU masking (all CPUs implemented)"); - } - - report(test_readonly_32(targetsptr + nr_irqs, true), - "accesses beyond limit RAZ/WI"); - - pattern = 0x0103020f; - writel(pattern, targetsptr + GIC_FIRST_SPI); - reg = readl(targetsptr + GIC_FIRST_SPI); - report(reg == (pattern & cpu_mask), "register content preserved"); - if (reg != (pattern & cpu_mask)) - report_info("writing %08x reads back as %08x", - pattern & cpu_mask, reg); - - /* The TARGETS registers are byte accessible. */ - test_byte_access(targetsptr + GIC_FIRST_SPI, pattern, cpu_mask); - - writel(orig_targets, targetsptr + GIC_FIRST_SPI); - - report_prefix_pop(); -} - -static void gic_test_mmio(void) -{ - u32 reg; - int nr_irqs; - void *gic_dist_base, *idreg; - - switch(gic_version()) { - case 0x2: - gic_dist_base = gicv2_dist_base(); - idreg = gic_dist_base + GICD_ICPIDR2; - break; - case 0x3: - report_abort("GICv3 MMIO tests NYI"); - default: - report_abort("GIC version %d not supported", gic_version()); - } - - reg = readl(gic_dist_base + GICD_TYPER); - nr_irqs = GICD_TYPER_IRQS(reg); - report_info("number of implemented SPIs: %d", nr_irqs - GIC_FIRST_SPI); - - test_typer_v2(reg); - - report_info("IIDR: 0x%08x", readl(gic_dist_base + GICD_IIDR)); - - report(test_readonly_32(gic_dist_base + GICD_TYPER, false), - "GICD_TYPER is read-only"); - report(test_readonly_32(gic_dist_base + GICD_IIDR, false), - "GICD_IIDR is read-only"); - - reg = readl(idreg); - report(test_readonly_32(idreg, false), "ICPIDR2 is read-only"); - report_info("value of ICPIDR2: 0x%08x", reg); - - test_priorities(nr_irqs, gic_dist_base + GICD_IPRIORITYR); - - if (gic_version() == 2) - test_targets(nr_irqs); -} - -#if defined(__arm__) - -static void test_its_introspection(void) {} -static void test_its_trigger(void) {} -static void test_its_migration(void) {} -static void test_its_pending_migration(void) {} -static void test_migrate_unmapped_collection(void) {} - -#else /* __aarch64__ */ - -static void test_its_introspection(void) -{ - struct its_baser *dev_baser = &its_data.device_baser; - struct its_baser *coll_baser = &its_data.coll_baser; - struct its_typer *typer = &its_data.typer; - - if (!gicv3_its_base()) { - report_skip("No ITS, skip ..."); - return; - } - - /* IIDR */ - report(test_readonly_32(gicv3_its_base() + GITS_IIDR, false), - "GITS_IIDR is read-only"), - - /* TYPER */ - report(test_readonly_32(gicv3_its_base() + GITS_TYPER, false), - "GITS_TYPER is read-only"); - - report(typer->phys_lpi, "ITS supports physical LPIs"); - report_info("vLPI support: %s", typer->virt_lpi ? "yes" : "no"); - report_info("ITT entry size = 0x%x", typer->ite_size); - report_info("Bit Count: EventID=%d DeviceId=%d CollId=%d", - typer->eventid_bits, typer->deviceid_bits, - typer->collid_bits); - report(typer->eventid_bits && typer->deviceid_bits && - typer->collid_bits, "ID spaces"); - report_info("Target address format %s", - typer->pta ? "Redist base address" : "PE #"); - - report(dev_baser && coll_baser, "detect device and collection BASER"); - report_info("device table entry_size = 0x%x", dev_baser->esz); - report_info("collection table entry_size = 0x%x", coll_baser->esz); -} - -static int its_prerequisites(int nb_cpus) -{ - int cpu; - - if (!gicv3_its_base()) { - report_skip("No ITS, skip ..."); - return -1; - } - - if (nr_cpus < nb_cpus) { - report_skip("Test requires at least %d vcpus", nb_cpus); - return -1; - } - - stats_reset(); - - setup_irq(lpi_handler); - - for_each_present_cpu(cpu) { - if (cpu == 0) - continue; - smp_boot_secondary(cpu, secondary_lpi_test); - } - wait_on_ready(); - - its_enable_defaults(); - - return 0; -} - -/* - * Setup the configuration for those mappings: - * dev_id=2 event=20 -> vcpu 3, intid=8195 - * dev_id=7 event=255 -> vcpu 2, intid=8196 - * LPIs ready to hit - */ -static int its_setup1(void) -{ - struct its_collection *col3, *col2; - struct its_device *dev2, *dev7; - - if (its_prerequisites(4)) - return -1; - - dev2 = its_create_device(2 /* dev id */, 8 /* nb_ites */); - dev7 = its_create_device(7 /* dev id */, 8 /* nb_ites */); - - col3 = its_create_collection(3 /* col id */, 3/* target PE */); - col2 = its_create_collection(2 /* col id */, 2/* target PE */); - - gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT); - gicv3_lpi_set_config(8196, LPI_PROP_DEFAULT); - - /* - * dev=2, eventid=20 -> lpi= 8195, col=3 - * dev=7, eventid=255 -> lpi= 8196, col=2 - */ - its_send_mapd(dev2, true); - its_send_mapd(dev7, true); - - its_send_mapc(col3, true); - its_send_mapc(col2, true); - - its_send_invall(col2); - its_send_invall(col3); - - its_send_mapti(dev2, 8195 /* lpi id */, 20 /* event id */, col3); - its_send_mapti(dev7, 8196 /* lpi id */, 255 /* event id */, col2); - return 0; -} - -static void test_its_trigger(void) -{ - struct its_collection *col3; - struct its_device *dev2, *dev7; - - if (its_setup1()) - return; - - col3 = its_get_collection(3); - dev2 = its_get_device(2); - dev7 = its_get_device(7); - - report_prefix_push("int"); - - lpi_stats_expect(3, 8195); - its_send_int(dev2, 20); - check_lpi_stats("dev=2, eventid=20 -> lpi= 8195, col=3"); - - lpi_stats_expect(2, 8196); - its_send_int(dev7, 255); - check_lpi_stats("dev=7, eventid=255 -> lpi= 8196, col=2"); - - report_prefix_pop(); - - report_prefix_push("inv/invall"); - - /* - * disable 8195, check dev2/eventid=20 does not trigger the - * corresponding LPI - */ - gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT & ~LPI_PROP_ENABLED); - its_send_inv(dev2, 20); - - lpi_stats_expect(-1, -1); - its_send_int(dev2, 20); - check_lpi_stats("dev2/eventid=20 does not trigger any LPI"); - - /* - * re-enable the LPI but willingly do not call invall - * so the change in config is not taken into account. - * The LPI should not hit - */ - gicv3_lpi_set_config(8195, LPI_PROP_DEFAULT); - lpi_stats_expect(-1, -1); - its_send_int(dev2, 20); - check_lpi_stats("dev2/eventid=20 still does not trigger any LPI"); - - /* Now call the invall and check the LPI hits */ - its_send_invall(col3); - lpi_stats_expect(3, 8195); - its_send_int(dev2, 20); - check_lpi_stats("dev2/eventid=20 now triggers an LPI"); - - report_prefix_pop(); - - report_prefix_push("mapd valid=false"); - /* - * Unmap device 2 and check the eventid 20 formerly - * attached to it does not hit anymore - */ - - its_send_mapd(dev2, false); - lpi_stats_expect(-1, -1); - its_send_int(dev2, 20); - check_lpi_stats("no LPI after device unmap"); - report_prefix_pop(); -} - -static void test_its_migration(void) -{ - struct its_device *dev2, *dev7; - bool test_skipped = false; - - if (its_setup1()) { - test_skipped = true; - goto do_migrate; - } - - dev2 = its_get_device(2); - dev7 = its_get_device(7); - -do_migrate: - puts("Now migrate the VM, then press a key to continue...\n"); - (void)getchar(); - report_info("Migration complete"); - if (test_skipped) - return; - - lpi_stats_expect(3, 8195); - its_send_int(dev2, 20); - check_lpi_stats("dev2/eventid=20 triggers LPI 8195 on PE #3 after migration"); - - lpi_stats_expect(2, 8196); - its_send_int(dev7, 255); - check_lpi_stats("dev7/eventid=255 triggers LPI 8196 on PE #2 after migration"); -} - -#define ERRATA_UNMAPPED_COLLECTIONS "ERRATA_8c58be34494b" - -static void test_migrate_unmapped_collection(void) -{ - struct its_collection *col = NULL; - struct its_device *dev2 = NULL, *dev7 = NULL; - bool test_skipped = false; - int pe0 = 0; - u8 config; - - if (its_setup1()) { - test_skipped = true; - goto do_migrate; - } - - if (!errata(ERRATA_UNMAPPED_COLLECTIONS)) { - report_skip("Skipping test, as this test hangs without the fix. " - "Set %s=y to enable.", ERRATA_UNMAPPED_COLLECTIONS); - test_skipped = true; - goto do_migrate; - } - - col = its_create_collection(pe0, pe0); - dev2 = its_get_device(2); - dev7 = its_get_device(7); - - /* MAPTI with the collection unmapped */ - its_send_mapti(dev2, 8192, 0, col); - gicv3_lpi_set_config(8192, LPI_PROP_DEFAULT); - -do_migrate: - puts("Now migrate the VM, then press a key to continue...\n"); - (void)getchar(); - report_info("Migration complete"); - if (test_skipped) - return; - - /* on the destination, map the collection */ - its_send_mapc(col, true); - its_send_invall(col); - - lpi_stats_expect(2, 8196); - its_send_int(dev7, 255); - check_lpi_stats("dev7/eventid= 255 triggered LPI 8196 on PE #2"); - - config = gicv3_lpi_get_config(8192); - report(config == LPI_PROP_DEFAULT, - "Config of LPI 8192 was properly migrated"); - - lpi_stats_expect(pe0, 8192); - its_send_int(dev2, 0); - check_lpi_stats("dev2/eventid = 0 triggered LPI 8192 on PE0"); -} - -static void test_its_pending_migration(void) -{ - struct its_device *dev; - struct its_collection *collection[2]; - int *expected = calloc(nr_cpus, sizeof(int)); - int pe0 = nr_cpus - 1, pe1 = nr_cpus - 2; - bool test_skipped = false; - u64 pendbaser; - void *ptr; - int i; - - if (its_prerequisites(4)) { - test_skipped = true; - goto do_migrate; - } - - dev = its_create_device(2 /* dev id */, 8 /* nb_ites */); - its_send_mapd(dev, true); - - collection[0] = its_create_collection(pe0, pe0); - collection[1] = its_create_collection(pe1, pe1); - its_send_mapc(collection[0], true); - its_send_mapc(collection[1], true); - - /* disable lpi at redist level */ - gicv3_lpi_rdist_disable(pe0); - gicv3_lpi_rdist_disable(pe1); - - /* lpis are interleaved inbetween the 2 PEs */ - for (i = 0; i < 256; i++) { - struct its_collection *col = i % 2 ? collection[0] : - collection[1]; - int vcpu = col->target_address >> 16; - - its_send_mapti(dev, LPI(i), i, col); - gicv3_lpi_set_config(LPI(i), LPI_PROP_DEFAULT); - gicv3_lpi_set_clr_pending(vcpu, LPI(i), true); - } - its_send_invall(collection[0]); - its_send_invall(collection[1]); - - /* Clear the PTZ bit on each pendbaser */ - - expected[pe0] = 128; - expected[pe1] = 128; - - ptr = gicv3_data.redist_base[pe0] + GICR_PENDBASER; - pendbaser = readq(ptr); - writeq(pendbaser & ~GICR_PENDBASER_PTZ, ptr); - - ptr = gicv3_data.redist_base[pe1] + GICR_PENDBASER; - pendbaser = readq(ptr); - writeq(pendbaser & ~GICR_PENDBASER_PTZ, ptr); - - gicv3_lpi_rdist_enable(pe0); - gicv3_lpi_rdist_enable(pe1); - -do_migrate: - puts("Now migrate the VM, then press a key to continue...\n"); - (void)getchar(); - report_info("Migration complete"); - if (test_skipped) - return; - - /* let's wait for the 256 LPIs to be handled */ - mdelay(1000); - - check_lpi_hits(expected, "128 LPIs on both PE0 and PE1 after migration"); -} -#endif - -int main(int argc, char **argv) -{ - if (!gic_init()) { - printf("No supported gic present, skipping tests...\n"); - return report_summary(); - } - - report_prefix_pushf("gicv%d", gic_version()); - - switch (gic_version()) { - case 2: - gic = &gicv2; - break; - case 3: - gic = &gicv3; - break; - } - - if (argc < 2) - report_abort("no test specified"); - - if (strcmp(argv[1], "ipi") == 0) { - report_prefix_push(argv[1]); - nr_cpu_check(2); - on_cpus(ipi_test, NULL); - } else if (strcmp(argv[1], "active") == 0) { - run_active_clear_test(); - } else if (strcmp(argv[1], "mmio") == 0) { - report_prefix_push(argv[1]); - gic_test_mmio(); - report_prefix_pop(); - } else if (!strcmp(argv[1], "its-trigger")) { - report_prefix_push(argv[1]); - test_its_trigger(); - report_prefix_pop(); - } else if (!strcmp(argv[1], "its-migration")) { - report_prefix_push(argv[1]); - test_its_migration(); - report_prefix_pop(); - } else if (!strcmp(argv[1], "its-pending-migration")) { - report_prefix_push(argv[1]); - test_its_pending_migration(); - report_prefix_pop(); - } else if (!strcmp(argv[1], "its-migrate-unmapped-collection")) { - report_prefix_push(argv[1]); - test_migrate_unmapped_collection(); - report_prefix_pop(); - } else if (strcmp(argv[1], "its-introspection") == 0) { - report_prefix_push(argv[1]); - test_its_introspection(); - report_prefix_pop(); - } else { - report_abort("Unknown subtest '%s'", argv[1]); - } - - return report_summary(); -} diff --git a/arm/micro-bench.c b/arm/micro-bench.c deleted file mode 100644 index 4612f410..00000000 --- a/arm/micro-bench.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Measure the cost of micro level operations. - * - * This test provides support for quantifying the cost of micro level - * operations. To improve precision in the measurements, one should - * consider pinning each VCPU to a specific physical CPU (PCPU) and to - * ensure no other task could run on that PCPU to skew the results. - * This can be achieved by enabling QMP server in the QEMU command in - * unittest.cfg for micro-bench, allowing a client program to get the - * thread_id for each VCPU thread from the QMP server. Based on that - * information, the client program can then pin the corresponding VCPUs to - * dedicated PCPUs and isolate interrupts and tasks from those PCPUs. - * - * Copyright Columbia University - * Author: Shih-Wei Li - * Author: Christoffer Dall - * Author: Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include - -#define NTIMES (1U << 16) - -static u32 cntfrq; - -static volatile bool ipi_ready, ipi_received; -static void *vgic_dist_base; -static void (*write_eoir)(u32 irqstat); - -static void ipi_irq_handler(struct pt_regs *regs) -{ - ipi_ready = false; - ipi_received = true; - gic_write_eoir(gic_read_iar()); - ipi_ready = true; -} - -static void ipi_secondary_entry(void *data) -{ - install_irq_handler(EL1H_IRQ, ipi_irq_handler); - gic_enable_defaults(); - local_irq_enable(); - ipi_ready = true; - while (true) - cpu_relax(); -} - -static bool test_init(void) -{ - int v = gic_init(); - - if (!v) { - printf("No supported gic present, skipping tests...\n"); - return false; - } - - if (nr_cpus < 2) { - printf("At least two cpus required, skipping tests...\n"); - return false; - } - - switch (v) { - case 2: - vgic_dist_base = gicv2_dist_base(); - write_eoir = gicv2_write_eoir; - break; - case 3: - vgic_dist_base = gicv3_dist_base(); - write_eoir = gicv3_write_eoir; - break; - } - - ipi_ready = false; - gic_enable_defaults(); - on_cpu_async(1, ipi_secondary_entry, NULL); - - cntfrq = get_cntfrq(); - printf("Timer Frequency %d Hz (Output in microseconds)\n", cntfrq); - - return true; -} - -static void ipi_prep(void) -{ - unsigned tries = 1 << 28; - - while (!ipi_ready && tries--) - cpu_relax(); - assert(ipi_ready); -} - -static void ipi_exec(void) -{ - unsigned tries = 1 << 28; - static int received = 0; - - ipi_received = false; - - gic_ipi_send_single(1, 1); - - while (!ipi_received && tries--) - cpu_relax(); - - ++received; - assert_msg(ipi_received, "failed to receive IPI in time, but received %d successfully\n", received); -} - -static void hvc_exec(void) -{ - asm volatile("mov w0, #0x4b000000; hvc #0" ::: "w0"); -} - -static void mmio_read_user_exec(void) -{ - /* - * FIXME: Read device-id in virtio mmio here in order to - * force an exit to userspace. This address needs to be - * updated in the future if any relevant changes in QEMU - * test-dev are made. - */ - void *userspace_emulated_addr = (void*)0x0a000008; - - readl(userspace_emulated_addr); -} - -static void mmio_read_vgic_exec(void) -{ - readl(vgic_dist_base + GICD_IIDR); -} - -static void eoi_exec(void) -{ - int spurious_id = 1023; /* writes to EOI are ignored */ - - /* Avoid measuring assert(..) in gic_write_eoir */ - write_eoir(spurious_id); -} - -struct exit_test { - const char *name; - void (*prep)(void); - void (*exec)(void); - bool run; -}; - -static struct exit_test tests[] = { - {"hvc", NULL, hvc_exec, true}, - {"mmio_read_user", NULL, mmio_read_user_exec, true}, - {"mmio_read_vgic", NULL, mmio_read_vgic_exec, true}, - {"eoi", NULL, eoi_exec, true}, - {"ipi", ipi_prep, ipi_exec, true}, -}; - -struct ns_time { - uint64_t ns; - uint64_t ns_frac; -}; - -#define PS_PER_SEC (1000 * 1000 * 1000 * 1000UL) -static void ticks_to_ns_time(uint64_t ticks, struct ns_time *ns_time) -{ - uint64_t ps_per_tick = PS_PER_SEC / cntfrq + !!(PS_PER_SEC % cntfrq); - uint64_t ps; - - ps = ticks * ps_per_tick; - ns_time->ns = ps / 1000; - ns_time->ns_frac = (ps % 1000) / 100; -} - -static void loop_test(struct exit_test *test) -{ - uint64_t start, end, total_ticks, ntimes = NTIMES; - struct ns_time total_ns, avg_ns; - - if (test->prep) - test->prep(); - - isb(); - start = read_sysreg(cntpct_el0); - while (ntimes--) - test->exec(); - isb(); - end = read_sysreg(cntpct_el0); - - total_ticks = end - start; - ticks_to_ns_time(total_ticks, &total_ns); - avg_ns.ns = total_ns.ns / NTIMES; - avg_ns.ns_frac = total_ns.ns_frac / NTIMES; - - printf("%-30s%15" PRId64 ".%-15" PRId64 "%15" PRId64 ".%-15" PRId64 "\n", - test->name, total_ns.ns, total_ns.ns_frac, avg_ns.ns, avg_ns.ns_frac); -} - -int main(int argc, char **argv) -{ - int i; - - if (!test_init()) - return 1; - - printf("\n%-30s%18s%13s%18s%13s\n", "name", "total ns", "", "avg ns", ""); - for (i = 0 ; i < 92; ++i) - printf("%c", '-'); - printf("\n"); - for (i = 0; i < ARRAY_SIZE(tests); i++) { - if (!tests[i].run) - continue; - assert(tests[i].name && tests[i].exec); - loop_test(&tests[i]); - } - - return 0; -} diff --git a/arm/pci-test.c b/arm/pci-test.c deleted file mode 100644 index 560e2c8b..00000000 --- a/arm/pci-test.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * PCI bus operation test - * - * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include - -#define NR_TESTS (PCI_TESTDEV_NUM_BARS * PCI_TESTDEV_NUM_TESTS) - -int main(void) -{ - int ret; - - if (!pci_probe()) { - printf("PCI bus probing failed, skipping tests...\n"); - return report_summary(); - } - - report_prefix_push("pci"); - - pci_print(); - - ret = pci_testdev(); - if (ret == -1) - report_skip("No PCI test device"); - else - report(ret >= NR_TESTS, "PCI test device passed %d/%d tests", - ret > 0 ? ret : 0, NR_TESTS); - - return report_summary(); -} diff --git a/arm/pl031.c b/arm/pl031.c deleted file mode 100644 index 86035fa4..00000000 --- a/arm/pl031.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Verify PL031 functionality - * - * This test verifies whether the emulated PL031 behaves correctly. - * - * Copyright 2019 Amazon.com, Inc. or its affiliates. - * Author: Alexander Graf - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include -#include - -struct pl031_regs { - uint32_t dr; /* Data Register */ - uint32_t mr; /* Match Register */ - uint32_t lr; /* Load Register */ - union { - uint8_t cr; /* Control Register */ - uint32_t cr32; - }; - union { - uint8_t imsc; /* Interrupt Mask Set or Clear register */ - uint32_t imsc32; - }; - union { - uint8_t ris; /* Raw Interrupt Status */ - uint32_t ris32; - }; - union { - uint8_t mis; /* Masked Interrupt Status */ - uint32_t mis32; - }; - union { - uint8_t icr; /* Interrupt Clear Register */ - uint32_t icr32; - }; - uint32_t reserved[1008]; - uint32_t periph_id[4]; - uint32_t pcell_id[4]; -}; - -static u32 cntfrq; -static struct pl031_regs *pl031; -static int pl031_irq; -static void *gic_ispendr; -static void *gic_isenabler; -static volatile bool irq_triggered; - -static int check_id(void) -{ - uint32_t id[] = { 0x31, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; - int i; - - for (i = 0; i < ARRAY_SIZE(id); i++) - if (id[i] != readl(&pl031->periph_id[i])) - return 1; - - return 0; -} - -static int check_ro(void) -{ - uint32_t offs[] = { offsetof(struct pl031_regs, ris), - offsetof(struct pl031_regs, mis), - offsetof(struct pl031_regs, periph_id[0]), - offsetof(struct pl031_regs, periph_id[1]), - offsetof(struct pl031_regs, periph_id[2]), - offsetof(struct pl031_regs, periph_id[3]), - offsetof(struct pl031_regs, pcell_id[0]), - offsetof(struct pl031_regs, pcell_id[1]), - offsetof(struct pl031_regs, pcell_id[2]), - offsetof(struct pl031_regs, pcell_id[3]) }; - int i; - - for (i = 0; i < ARRAY_SIZE(offs); i++) { - uint32_t before32; - uint16_t before16; - uint8_t before8; - void *addr = (void*)pl031 + offs[i]; - uint32_t poison = 0xdeadbeefULL; - - before8 = readb(addr); - before16 = readw(addr); - before32 = readl(addr); - - writeb(poison, addr); - writew(poison, addr); - writel(poison, addr); - - if (before8 != readb(addr)) - return 1; - if (before16 != readw(addr)) - return 1; - if (before32 != readl(addr)) - return 1; - } - - return 0; -} - -static int check_rtc_freq(void) -{ - uint32_t seconds_to_wait = 2; - uint32_t before = readl(&pl031->dr); - uint64_t before_tick = get_cntvct(); - uint64_t target_tick = before_tick + (cntfrq * seconds_to_wait); - - /* Wait for 2 seconds */ - while (get_cntvct() < target_tick) ; - - if (readl(&pl031->dr) != before + seconds_to_wait) - return 1; - - return 0; -} - -static bool gic_irq_pending(void) -{ - uint32_t offset = (pl031_irq / 32) * 4; - - return readl(gic_ispendr + offset) & (1 << (pl031_irq & 31)); -} - -static void gic_irq_unmask(void) -{ - uint32_t offset = (pl031_irq / 32) * 4; - - writel(1 << (pl031_irq & 31), gic_isenabler + offset); -} - -static void irq_handler(struct pt_regs *regs) -{ - u32 irqstat = gic_read_iar(); - u32 irqnr = gic_iar_irqnr(irqstat); - - gic_write_eoir(irqstat); - - if (irqnr == pl031_irq) { - report(readl(&pl031->ris) == 1, " RTC RIS == 1"); - report(readl(&pl031->mis) == 1, " RTC MIS == 1"); - - /* Writing one to bit zero should clear IRQ status */ - writel(1, &pl031->icr); - - report(readl(&pl031->ris) == 0, " RTC RIS == 0"); - report(readl(&pl031->mis) == 0, " RTC MIS == 0"); - irq_triggered = true; - } else { - report_info("Unexpected interrupt: %d\n", irqnr); - return; - } -} - -static int check_rtc_irq(void) -{ - uint32_t seconds_to_wait = 1; - uint32_t before = readl(&pl031->dr); - uint64_t before_tick = get_cntvct(); - uint64_t target_tick = before_tick + (cntfrq * (seconds_to_wait + 1)); - - report_info("Checking IRQ trigger (MR)"); - - irq_triggered = false; - - /* Fire IRQ in 1 second */ - writel(before + seconds_to_wait, &pl031->mr); - -#ifdef __aarch64__ - install_irq_handler(EL1H_IRQ, irq_handler); -#else - install_exception_handler(EXCPTN_IRQ, irq_handler); -#endif - - /* Wait until 2 seconds are over */ - while (get_cntvct() < target_tick) ; - - report(!gic_irq_pending(), " RTC IRQ not delivered without mask"); - - /* Mask the IRQ so that it gets delivered */ - writel(1, &pl031->imsc); - report(gic_irq_pending(), " RTC IRQ pending now"); - - /* Enable retrieval of IRQ */ - gic_irq_unmask(); - local_irq_enable(); - - report(irq_triggered, " IRQ triggered"); - report(!gic_irq_pending(), " RTC IRQ not pending anymore"); - if (!irq_triggered) { - report_info(" RTC RIS: %x", readl(&pl031->ris)); - report_info(" RTC MIS: %x", readl(&pl031->mis)); - report_info(" RTC IMSC: %x", readl(&pl031->imsc)); - report_info(" GIC IRQs pending: %08x %08x", readl(gic_ispendr), readl(gic_ispendr + 4)); - } - - local_irq_disable(); - return 0; -} - -static void rtc_irq_init(void) -{ - gic_enable_defaults(); - - switch (gic_version()) { - case 2: - gic_ispendr = gicv2_dist_base() + GICD_ISPENDR; - gic_isenabler = gicv2_dist_base() + GICD_ISENABLER; - break; - case 3: - gic_ispendr = gicv3_dist_base() + GICD_ISPENDR; - gic_isenabler = gicv3_dist_base() + GICD_ISENABLER; - break; - } -} - -static int rtc_fdt_init(void) -{ - const struct fdt_property *prop; - const void *fdt = dt_fdt(); - struct dt_pbus_reg base; - int node, len; - u32 *data; - int ret; - - node = fdt_node_offset_by_compatible(fdt, -1, "arm,pl031"); - if (node < 0) - return -1; - - prop = fdt_get_property(fdt, node, "interrupts", &len); - assert(prop && len == (3 * sizeof(u32))); - data = (u32 *)prop->data; - assert(data[0] == 0); /* SPI */ - pl031_irq = SPI(fdt32_to_cpu(data[1])); - - ret = dt_pbus_translate_node(node, 0, &base); - assert(!ret); - pl031 = ioremap(base.addr, base.size); - - return 0; -} - -int main(int argc, char **argv) -{ - cntfrq = get_cntfrq(); - rtc_irq_init(); - if (rtc_fdt_init()) { - report_skip("Skipping PL031 tests. No device present."); - return 0; - } - - report_prefix_push("pl031"); - report(!check_id(), "Periph/PCell IDs match"); - report(!check_ro(), "R/O fields are R/O"); - report(!check_rtc_freq(), "RTC ticks at 1HZ"); - report(!gic_irq_pending(), "RTC IRQ not pending yet"); - check_rtc_irq(); - - return report_summary(); -} diff --git a/arm/pmu.c b/arm/pmu.c deleted file mode 100644 index cece53ef..00000000 --- a/arm/pmu.c +++ /dev/null @@ -1,1077 +0,0 @@ -/* - * Test the ARM Performance Monitors Unit (PMU). - * - * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. - * Copyright (C) 2016, Red Hat Inc, Wei Huang - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 2.1 and - * only version 2.1 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - */ -#include "libcflat.h" -#include "errata.h" -#include "asm/barrier.h" -#include "asm/sysreg.h" -#include "asm/processor.h" -#include -#include - -#define PMU_PMCR_E (1 << 0) -#define PMU_PMCR_P (1 << 1) -#define PMU_PMCR_C (1 << 2) -#define PMU_PMCR_D (1 << 3) -#define PMU_PMCR_X (1 << 4) -#define PMU_PMCR_DP (1 << 5) -#define PMU_PMCR_LC (1 << 6) -#define PMU_PMCR_N_SHIFT 11 -#define PMU_PMCR_N_MASK 0x1f -#define PMU_PMCR_ID_SHIFT 16 -#define PMU_PMCR_ID_MASK 0xff -#define PMU_PMCR_IMP_SHIFT 24 -#define PMU_PMCR_IMP_MASK 0xff - -#define PMU_CYCLE_IDX 31 - -#define NR_SAMPLES 10 - -/* Some PMU events */ -#define SW_INCR 0x0 -#define INST_RETIRED 0x8 -#define CPU_CYCLES 0x11 -#define MEM_ACCESS 0x13 -#define INST_PREC 0x1B -#define STALL_FRONTEND 0x23 -#define STALL_BACKEND 0x24 -#define CHAIN 0x1E - -#define COMMON_EVENTS_LOW 0x0 -#define COMMON_EVENTS_HIGH 0x3F -#define EXT_COMMON_EVENTS_LOW 0x4000 -#define EXT_COMMON_EVENTS_HIGH 0x403F - -#define ALL_SET 0xFFFFFFFF -#define ALL_CLEAR 0x0 -#define PRE_OVERFLOW 0xFFFFFFF0 -#define PRE_OVERFLOW2 0xFFFFFFDC - -#define PMU_PPI 23 - -struct pmu { - unsigned int version; - unsigned int nb_implemented_counters; - uint32_t pmcr_ro; -}; - -struct pmu_stats { - unsigned long bitmap; - uint32_t interrupts[32]; - bool unexpected; -}; - -static struct pmu pmu; - -#if defined(__arm__) -#define ID_DFR0_PERFMON_SHIFT 24 -#define ID_DFR0_PERFMON_MASK 0xf - -#define ID_DFR0_PMU_NOTIMPL 0b0000 -#define ID_DFR0_PMU_V1 0b0001 -#define ID_DFR0_PMU_V2 0b0010 -#define ID_DFR0_PMU_V3 0b0011 -#define ID_DFR0_PMU_V3_8_1 0b0100 -#define ID_DFR0_PMU_V3_8_4 0b0101 -#define ID_DFR0_PMU_V3_8_5 0b0110 -#define ID_DFR0_PMU_IMPDEF 0b1111 - -#define PMCR __ACCESS_CP15(c9, 0, c12, 0) -#define ID_DFR0 __ACCESS_CP15(c0, 0, c1, 2) -#define PMSELR __ACCESS_CP15(c9, 0, c12, 5) -#define PMXEVTYPER __ACCESS_CP15(c9, 0, c13, 1) -#define PMCNTENSET __ACCESS_CP15(c9, 0, c12, 1) -#define PMCCNTR32 __ACCESS_CP15(c9, 0, c13, 0) -#define PMCCNTR64 __ACCESS_CP15_64(0, c9) - -static inline uint32_t get_id_dfr0(void) { return read_sysreg(ID_DFR0); } -static inline uint32_t get_pmcr(void) { return read_sysreg(PMCR); } -static inline void set_pmcr(uint32_t v) { write_sysreg(v, PMCR); } -static inline void set_pmcntenset(uint32_t v) { write_sysreg(v, PMCNTENSET); } - -static inline uint8_t get_pmu_version(void) -{ - return (get_id_dfr0() >> ID_DFR0_PERFMON_SHIFT) & ID_DFR0_PERFMON_MASK; -} - -static inline uint64_t get_pmccntr(void) -{ - return read_sysreg(PMCCNTR32); -} - -static inline void set_pmccntr(uint64_t value) -{ - write_sysreg(value & 0xffffffff, PMCCNTR32); -} - -/* PMCCFILTR is an obsolete name for PMXEVTYPER31 in ARMv7 */ -static inline void set_pmccfiltr(uint32_t value) -{ - write_sysreg(PMU_CYCLE_IDX, PMSELR); - write_sysreg(value, PMXEVTYPER); - isb(); -} - -/* - * Extra instructions inserted by the compiler would be difficult to compensate - * for, so hand assemble everything between, and including, the PMCR accesses - * to start and stop counting. isb instructions were inserted to make sure - * pmccntr read after this function returns the exact instructions executed in - * the controlled block. Total instrs = isb + mcr + 2*loop = 2 + 2*loop. - */ -static inline void precise_instrs_loop(int loop, uint32_t pmcr) -{ - asm volatile( - " mcr p15, 0, %[pmcr], c9, c12, 0\n" - " isb\n" - "1: subs %[loop], %[loop], #1\n" - " bgt 1b\n" - " mcr p15, 0, %[z], c9, c12, 0\n" - " isb\n" - : [loop] "+r" (loop) - : [pmcr] "r" (pmcr), [z] "r" (0) - : "cc"); -} - -/* event counter tests only implemented for aarch64 */ -static void test_event_introspection(void) {} -static void test_event_counter_config(void) {} -static void test_basic_event_count(void) {} -static void test_mem_access(void) {} -static void test_sw_incr(void) {} -static void test_chained_counters(void) {} -static void test_chained_sw_incr(void) {} -static void test_chain_promotion(void) {} -static void test_overflow_interrupt(void) {} - -#elif defined(__aarch64__) -#define ID_AA64DFR0_PERFMON_SHIFT 8 -#define ID_AA64DFR0_PERFMON_MASK 0xf - -#define ID_DFR0_PMU_NOTIMPL 0b0000 -#define ID_DFR0_PMU_V3 0b0001 -#define ID_DFR0_PMU_V3_8_1 0b0100 -#define ID_DFR0_PMU_V3_8_4 0b0101 -#define ID_DFR0_PMU_V3_8_5 0b0110 -#define ID_DFR0_PMU_IMPDEF 0b1111 - -static inline uint32_t get_id_aa64dfr0(void) { return read_sysreg(id_aa64dfr0_el1); } -static inline uint32_t get_pmcr(void) { return read_sysreg(pmcr_el0); } -static inline void set_pmcr(uint32_t v) { write_sysreg(v, pmcr_el0); } -static inline uint64_t get_pmccntr(void) { return read_sysreg(pmccntr_el0); } -static inline void set_pmccntr(uint64_t v) { write_sysreg(v, pmccntr_el0); } -static inline void set_pmcntenset(uint32_t v) { write_sysreg(v, pmcntenset_el0); } -static inline void set_pmccfiltr(uint32_t v) { write_sysreg(v, pmccfiltr_el0); } - -static inline uint8_t get_pmu_version(void) -{ - uint8_t ver = (get_id_aa64dfr0() >> ID_AA64DFR0_PERFMON_SHIFT) & ID_AA64DFR0_PERFMON_MASK; - return ver; -} - -/* - * Extra instructions inserted by the compiler would be difficult to compensate - * for, so hand assemble everything between, and including, the PMCR accesses - * to start and stop counting. isb instructions are inserted to make sure - * pmccntr read after this function returns the exact instructions executed - * in the controlled block. Total instrs = isb + msr + 2*loop = 2 + 2*loop. - */ -static inline void precise_instrs_loop(int loop, uint32_t pmcr) -{ - asm volatile( - " msr pmcr_el0, %[pmcr]\n" - " isb\n" - "1: subs %[loop], %[loop], #1\n" - " b.gt 1b\n" - " msr pmcr_el0, xzr\n" - " isb\n" - : [loop] "+r" (loop) - : [pmcr] "r" (pmcr) - : "cc"); -} - -#define PMCEID1_EL0 sys_reg(3, 3, 9, 12, 7) -#define PMCNTENSET_EL0 sys_reg(3, 3, 9, 12, 1) -#define PMCNTENCLR_EL0 sys_reg(3, 3, 9, 12, 2) - -#define PMEVTYPER_EXCLUDE_EL1 BIT(31) -#define PMEVTYPER_EXCLUDE_EL0 BIT(30) - -static bool is_event_supported(uint32_t n, bool warn) -{ - uint64_t pmceid0 = read_sysreg(pmceid0_el0); - uint64_t pmceid1 = read_sysreg_s(PMCEID1_EL0); - bool supported; - uint64_t reg; - - /* - * The low 32-bits of PMCEID0/1 respectively describe - * event support for events 0-31/32-63. Their High - * 32-bits describe support for extended events - * starting at 0x4000, using the same split. - */ - assert((n >= COMMON_EVENTS_LOW && n <= COMMON_EVENTS_HIGH) || - (n >= EXT_COMMON_EVENTS_LOW && n <= EXT_COMMON_EVENTS_HIGH)); - - if (n <= COMMON_EVENTS_HIGH) - reg = lower_32_bits(pmceid0) | ((u64)lower_32_bits(pmceid1) << 32); - else - reg = upper_32_bits(pmceid0) | ((u64)upper_32_bits(pmceid1) << 32); - - supported = reg & (1UL << (n & 0x3F)); - - if (!supported && warn) - report_info("event 0x%x is not supported", n); - return supported; -} - -static void test_event_introspection(void) -{ - bool required_events; - - if (!pmu.nb_implemented_counters) { - report_skip("No event counter, skip ..."); - return; - } - - /* PMUv3 requires an implementation includes some common events */ - required_events = is_event_supported(SW_INCR, true) && - is_event_supported(CPU_CYCLES, true) && - (is_event_supported(INST_RETIRED, true) || - is_event_supported(INST_PREC, true)); - - if (pmu.version >= ID_DFR0_PMU_V3_8_1) { - required_events = required_events && - is_event_supported(STALL_FRONTEND, true) && - is_event_supported(STALL_BACKEND, true); - } - - report(required_events, "Check required events are implemented"); -} - -/* - * Extra instructions inserted by the compiler would be difficult to compensate - * for, so hand assemble everything between, and including, the PMCR accesses - * to start and stop counting. isb instructions are inserted to make sure - * pmccntr read after this function returns the exact instructions executed - * in the controlled block. Loads @loop times the data at @address into x9. - */ -static void mem_access_loop(void *addr, int loop, uint32_t pmcr) -{ -asm volatile( - " msr pmcr_el0, %[pmcr]\n" - " isb\n" - " mov x10, %[loop]\n" - "1: sub x10, x10, #1\n" - " ldr x9, [%[addr]]\n" - " cmp x10, #0x0\n" - " b.gt 1b\n" - " msr pmcr_el0, xzr\n" - " isb\n" - : - : [addr] "r" (addr), [pmcr] "r" (pmcr), [loop] "r" (loop) - : "x9", "x10", "cc"); -} - -static struct pmu_stats pmu_stats; - -static void irq_handler(struct pt_regs *regs) -{ - uint32_t irqstat, irqnr; - - irqstat = gic_read_iar(); - irqnr = gic_iar_irqnr(irqstat); - - if (irqnr == PMU_PPI) { - unsigned long overflows = read_sysreg(pmovsclr_el0); - int i; - - for (i = 0; i < 32; i++) { - if (test_and_clear_bit(i, &overflows)) { - pmu_stats.interrupts[i]++; - pmu_stats.bitmap |= 1 << i; - } - } - write_sysreg(ALL_SET, pmovsclr_el0); - } else { - pmu_stats.unexpected = true; - } - gic_write_eoir(irqstat); -} - -static void pmu_reset_stats(void) -{ - int i; - - for (i = 0; i < 32; i++) - pmu_stats.interrupts[i] = 0; - - pmu_stats.bitmap = 0; - pmu_stats.unexpected = false; -} - -static void pmu_reset(void) -{ - /* reset all counters, counting disabled at PMCR level*/ - set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P); - /* Disable all counters */ - write_sysreg_s(ALL_SET, PMCNTENCLR_EL0); - /* clear overflow reg */ - write_sysreg(ALL_SET, pmovsclr_el0); - /* disable overflow interrupts on all counters */ - write_sysreg(ALL_SET, pmintenclr_el1); - pmu_reset_stats(); - isb(); -} - -static void test_event_counter_config(void) -{ - int i; - - if (!pmu.nb_implemented_counters) { - report_skip("No event counter, skip ..."); - return; - } - - pmu_reset(); - - /* - * Test setting through PMESELR/PMXEVTYPER and PMEVTYPERn read, - * select counter 0 - */ - write_sysreg(1, PMSELR_EL0); - /* program this counter to count unsupported event */ - write_sysreg(0xEA, PMXEVTYPER_EL0); - write_sysreg(0xdeadbeef, PMXEVCNTR_EL0); - report((read_regn_el0(pmevtyper, 1) & 0xFFF) == 0xEA, - "PMESELR/PMXEVTYPER/PMEVTYPERn"); - report((read_regn_el0(pmevcntr, 1) == 0xdeadbeef), - "PMESELR/PMXEVCNTR/PMEVCNTRn"); - - /* try to configure an unsupported event within the range [0x0, 0x3F] */ - for (i = 0; i <= 0x3F; i++) { - if (!is_event_supported(i, false)) - break; - } - if (i > 0x3F) { - report_skip("pmevtyper: all events within [0x0, 0x3F] are supported"); - return; - } - - /* select counter 0 */ - write_sysreg(0, PMSELR_EL0); - /* program this counter to count unsupported event */ - write_sysreg(i, PMXEVCNTR_EL0); - /* read the counter value */ - read_sysreg(PMXEVCNTR_EL0); - report(read_sysreg(PMXEVCNTR_EL0) == i, - "read of a counter programmed with unsupported event"); -} - -static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events) -{ - int i; - - if (pmu.nb_implemented_counters < nb_events) { - report_skip("Skip test as number of counters is too small (%d)", - pmu.nb_implemented_counters); - return false; - } - - for (i = 0; i < nb_events; i++) { - if (!is_event_supported(events[i], false)) { - report_skip("Skip test as event 0x%x is not supported", - events[i]); - return false; - } - } - return true; -} - -static void test_basic_event_count(void) -{ - uint32_t implemented_counter_mask, non_implemented_counter_mask; - uint32_t counter_mask; - uint32_t events[] = {CPU_CYCLES, INST_RETIRED}; - - if (!satisfy_prerequisites(events, ARRAY_SIZE(events))) - return; - - implemented_counter_mask = BIT(pmu.nb_implemented_counters) - 1; - non_implemented_counter_mask = ~(BIT(31) | implemented_counter_mask); - counter_mask = implemented_counter_mask | non_implemented_counter_mask; - - write_regn_el0(pmevtyper, 0, CPU_CYCLES | PMEVTYPER_EXCLUDE_EL0); - write_regn_el0(pmevtyper, 1, INST_RETIRED | PMEVTYPER_EXCLUDE_EL0); - - /* disable all counters */ - write_sysreg_s(ALL_SET, PMCNTENCLR_EL0); - report(!read_sysreg_s(PMCNTENCLR_EL0) && !read_sysreg_s(PMCNTENSET_EL0), - "pmcntenclr: disable all counters"); - - /* - * clear cycle and all event counters and allow counter enablement - * through PMCNTENSET. LC is RES1. - */ - set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P); - isb(); - report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC), "pmcr: reset counters"); - - /* Preset counter #0 to pre overflow value to trigger an overflow */ - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW, - "counter #0 preset to pre-overflow value"); - report(!read_regn_el0(pmevcntr, 1), "counter #1 is 0"); - - /* - * Enable all implemented counters and also attempt to enable - * not supported counters. Counting still is disabled by !PMCR.E - */ - write_sysreg_s(counter_mask, PMCNTENSET_EL0); - - /* check only those implemented are enabled */ - report((read_sysreg_s(PMCNTENSET_EL0) == read_sysreg_s(PMCNTENCLR_EL0)) && - (read_sysreg_s(PMCNTENSET_EL0) == implemented_counter_mask), - "pmcntenset: enabled implemented_counters"); - - /* Disable all counters but counters #0 and #1 */ - write_sysreg_s(~0x3, PMCNTENCLR_EL0); - report((read_sysreg_s(PMCNTENSET_EL0) == read_sysreg_s(PMCNTENCLR_EL0)) && - (read_sysreg_s(PMCNTENSET_EL0) == 0x3), - "pmcntenset: just enabled #0 and #1"); - - /* clear overflow register */ - write_sysreg(ALL_SET, pmovsclr_el0); - report(!read_sysreg(pmovsclr_el0), "check overflow reg is 0"); - - /* disable overflow interrupts on all counters*/ - write_sysreg(ALL_SET, pmintenclr_el1); - report(!read_sysreg(pmintenclr_el1), - "pmintenclr_el1=0, all interrupts disabled"); - - /* enable overflow interrupts on all event counters */ - write_sysreg(implemented_counter_mask | non_implemented_counter_mask, - pmintenset_el1); - report(read_sysreg(pmintenset_el1) == implemented_counter_mask, - "overflow interrupts enabled on all implemented counters"); - - /* Set PMCR.E, execute asm code and unset PMCR.E */ - precise_instrs_loop(20, pmu.pmcr_ro | PMU_PMCR_E); - - report_info("counter #0 is 0x%lx (CPU_CYCLES)", - read_regn_el0(pmevcntr, 0)); - report_info("counter #1 is 0x%lx (INST_RETIRED)", - read_regn_el0(pmevcntr, 1)); - - report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0)); - report(read_sysreg(pmovsclr_el0) & 0x1, - "check overflow happened on #0 only"); -} - -static void test_mem_access(void) -{ - void *addr = malloc(PAGE_SIZE); - uint32_t events[] = {MEM_ACCESS, MEM_ACCESS}; - - if (!satisfy_prerequisites(events, ARRAY_SIZE(events))) - return; - - pmu_reset(); - - write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0); - write_regn_el0(pmevtyper, 1, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0); - write_sysreg_s(0x3, PMCNTENSET_EL0); - isb(); - mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E); - report_info("counter #0 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 0)); - report_info("counter #1 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 1)); - /* We may measure more than 20 mem access depending on the core */ - report((read_regn_el0(pmevcntr, 0) == read_regn_el0(pmevcntr, 1)) && - (read_regn_el0(pmevcntr, 0) >= 20) && !read_sysreg(pmovsclr_el0), - "Ran 20 mem accesses"); - - pmu_reset(); - - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - write_regn_el0(pmevcntr, 1, PRE_OVERFLOW); - write_sysreg_s(0x3, PMCNTENSET_EL0); - isb(); - mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E); - report(read_sysreg(pmovsclr_el0) == 0x3, - "Ran 20 mem accesses with expected overflows on both counters"); - report_info("cnt#0 = %ld cnt#1=%ld overflow=0x%lx", - read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1), - read_sysreg(pmovsclr_el0)); -} - -static void test_sw_incr(void) -{ - uint32_t events[] = {SW_INCR, SW_INCR}; - int i; - - if (!satisfy_prerequisites(events, ARRAY_SIZE(events))) - return; - - pmu_reset(); - - write_regn_el0(pmevtyper, 0, SW_INCR | PMEVTYPER_EXCLUDE_EL0); - write_regn_el0(pmevtyper, 1, SW_INCR | PMEVTYPER_EXCLUDE_EL0); - /* enable counters #0 and #1 */ - write_sysreg_s(0x3, PMCNTENSET_EL0); - - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - - for (i = 0; i < 100; i++) - write_sysreg(0x1, pmswinc_el0); - - report_info("SW_INCR counter #0 has value %ld", read_regn_el0(pmevcntr, 0)); - report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW, - "PWSYNC does not increment if PMCR.E is unset"); - - pmu_reset(); - - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - write_sysreg_s(0x3, PMCNTENSET_EL0); - set_pmcr(pmu.pmcr_ro | PMU_PMCR_E); - - for (i = 0; i < 100; i++) - write_sysreg(0x3, pmswinc_el0); - - report(read_regn_el0(pmevcntr, 0) == 84, "counter #1 after + 100 SW_INCR"); - report(read_regn_el0(pmevcntr, 1) == 100, - "counter #0 after + 100 SW_INCR"); - report_info("counter values after 100 SW_INCR #0=%ld #1=%ld", - read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1)); - report(read_sysreg(pmovsclr_el0) == 0x1, - "overflow on counter #0 after 100 SW_INCR"); -} - -static void test_chained_counters(void) -{ - uint32_t events[] = {CPU_CYCLES, CHAIN}; - - if (!satisfy_prerequisites(events, ARRAY_SIZE(events))) - return; - - pmu_reset(); - - write_regn_el0(pmevtyper, 0, CPU_CYCLES | PMEVTYPER_EXCLUDE_EL0); - write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0); - /* enable counters #0 and #1 */ - write_sysreg_s(0x3, PMCNTENSET_EL0); - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - - precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E); - - report(read_regn_el0(pmevcntr, 1) == 1, "CHAIN counter #1 incremented"); - report(!read_sysreg(pmovsclr_el0), "no overflow recorded for chained incr #1"); - - /* test 64b overflow */ - - pmu_reset(); - write_sysreg_s(0x3, PMCNTENSET_EL0); - - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - write_regn_el0(pmevcntr, 1, 0x1); - precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E); - report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0)); - report(read_regn_el0(pmevcntr, 1) == 2, "CHAIN counter #1 set to 2"); - report(!read_sysreg(pmovsclr_el0), "no overflow recorded for chained incr #2"); - - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - write_regn_el0(pmevcntr, 1, ALL_SET); - - precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E); - report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0)); - report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped"); - report(read_sysreg(pmovsclr_el0) == 0x2, "overflow on chain counter"); -} - -static void test_chained_sw_incr(void) -{ - uint32_t events[] = {SW_INCR, CHAIN}; - int i; - - if (!satisfy_prerequisites(events, ARRAY_SIZE(events))) - return; - - pmu_reset(); - - write_regn_el0(pmevtyper, 0, SW_INCR | PMEVTYPER_EXCLUDE_EL0); - write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0); - /* enable counters #0 and #1 */ - write_sysreg_s(0x3, PMCNTENSET_EL0); - - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - set_pmcr(pmu.pmcr_ro | PMU_PMCR_E); - for (i = 0; i < 100; i++) - write_sysreg(0x1, pmswinc_el0); - - report(!read_sysreg(pmovsclr_el0) && (read_regn_el0(pmevcntr, 1) == 1), - "no overflow and chain counter incremented after 100 SW_INCR/CHAIN"); - report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0), - read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1)); - - /* 64b SW_INCR and overflow on CHAIN counter*/ - pmu_reset(); - - write_regn_el0(pmevtyper, 1, events[1] | PMEVTYPER_EXCLUDE_EL0); - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - write_regn_el0(pmevcntr, 1, ALL_SET); - write_sysreg_s(0x3, PMCNTENSET_EL0); - set_pmcr(pmu.pmcr_ro | PMU_PMCR_E); - for (i = 0; i < 100; i++) - write_sysreg(0x1, pmswinc_el0); - - report((read_sysreg(pmovsclr_el0) == 0x2) && - (read_regn_el0(pmevcntr, 1) == 0) && - (read_regn_el0(pmevcntr, 0) == 84), - "overflow on chain counter and expected values after 100 SW_INCR/CHAIN"); - report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0), - read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1)); -} - -static void test_chain_promotion(void) -{ - uint32_t events[] = {MEM_ACCESS, CHAIN}; - void *addr = malloc(PAGE_SIZE); - - if (!satisfy_prerequisites(events, ARRAY_SIZE(events))) - return; - - /* Only enable CHAIN counter */ - pmu_reset(); - write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0); - write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0); - write_sysreg_s(0x2, PMCNTENSET_EL0); - isb(); - - mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E); - report(!read_regn_el0(pmevcntr, 0), - "chain counter not counting if even counter is disabled"); - - /* Only enable even counter */ - pmu_reset(); - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - write_sysreg_s(0x1, PMCNTENSET_EL0); - isb(); - - mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E); - report(!read_regn_el0(pmevcntr, 1) && (read_sysreg(pmovsclr_el0) == 0x1), - "odd counter did not increment on overflow if disabled"); - report_info("MEM_ACCESS counter #0 has value %ld", - read_regn_el0(pmevcntr, 0)); - report_info("CHAIN counter #1 has value %ld", - read_regn_el0(pmevcntr, 1)); - report_info("overflow counter %ld", read_sysreg(pmovsclr_el0)); - - /* start at 0xFFFFFFDC, +20 with CHAIN enabled, +20 with CHAIN disabled */ - pmu_reset(); - write_sysreg_s(0x3, PMCNTENSET_EL0); - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW2); - isb(); - - mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E); - report_info("MEM_ACCESS counter #0 has value 0x%lx", - read_regn_el0(pmevcntr, 0)); - - /* disable the CHAIN event */ - write_sysreg_s(0x2, PMCNTENCLR_EL0); - mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E); - report_info("MEM_ACCESS counter #0 has value 0x%lx", - read_regn_el0(pmevcntr, 0)); - report(read_sysreg(pmovsclr_el0) == 0x1, - "should have triggered an overflow on #0"); - report(!read_regn_el0(pmevcntr, 1), - "CHAIN counter #1 shouldn't have incremented"); - - /* start at 0xFFFFFFDC, +20 with CHAIN disabled, +20 with CHAIN enabled */ - - pmu_reset(); - write_sysreg_s(0x1, PMCNTENSET_EL0); - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW2); - isb(); - report_info("counter #0 = 0x%lx, counter #1 = 0x%lx overflow=0x%lx", - read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1), - read_sysreg(pmovsclr_el0)); - - mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E); - report_info("MEM_ACCESS counter #0 has value 0x%lx", - read_regn_el0(pmevcntr, 0)); - - /* enable the CHAIN event */ - write_sysreg_s(0x3, PMCNTENSET_EL0); - isb(); - mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E); - report_info("MEM_ACCESS counter #0 has value 0x%lx", - read_regn_el0(pmevcntr, 0)); - - report((read_regn_el0(pmevcntr, 1) == 1) && !read_sysreg(pmovsclr_el0), - "CHAIN counter enabled: CHAIN counter was incremented and no overflow"); - - report_info("CHAIN counter #1 = 0x%lx, overflow=0x%lx", - read_regn_el0(pmevcntr, 1), read_sysreg(pmovsclr_el0)); - - /* start as MEM_ACCESS/CPU_CYCLES and move to CHAIN/MEM_ACCESS */ - pmu_reset(); - write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0); - write_regn_el0(pmevtyper, 1, CPU_CYCLES | PMEVTYPER_EXCLUDE_EL0); - write_sysreg_s(0x3, PMCNTENSET_EL0); - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW2); - isb(); - - mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E); - report_info("MEM_ACCESS counter #0 has value 0x%lx", - read_regn_el0(pmevcntr, 0)); - - /* 0 becomes CHAINED */ - write_sysreg_s(0x0, PMCNTENSET_EL0); - write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0); - write_sysreg_s(0x3, PMCNTENSET_EL0); - write_regn_el0(pmevcntr, 1, 0x0); - - mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E); - report_info("MEM_ACCESS counter #0 has value 0x%lx", - read_regn_el0(pmevcntr, 0)); - - report((read_regn_el0(pmevcntr, 1) == 1) && !read_sysreg(pmovsclr_el0), - "32b->64b: CHAIN counter incremented and no overflow"); - - report_info("CHAIN counter #1 = 0x%lx, overflow=0x%lx", - read_regn_el0(pmevcntr, 1), read_sysreg(pmovsclr_el0)); - - /* start as CHAIN/MEM_ACCESS and move to MEM_ACCESS/CPU_CYCLES */ - pmu_reset(); - write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0); - write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0); - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW2); - write_sysreg_s(0x3, PMCNTENSET_EL0); - - mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E); - report_info("counter #0=0x%lx, counter #1=0x%lx", - read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1)); - - write_sysreg_s(0x0, PMCNTENSET_EL0); - write_regn_el0(pmevtyper, 1, CPU_CYCLES | PMEVTYPER_EXCLUDE_EL0); - write_sysreg_s(0x3, PMCNTENSET_EL0); - - mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E); - report(read_sysreg(pmovsclr_el0) == 1, - "overflow is expected on counter 0"); - report_info("counter #0=0x%lx, counter #1=0x%lx overflow=0x%lx", - read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1), - read_sysreg(pmovsclr_el0)); -} - -static bool expect_interrupts(uint32_t bitmap) -{ - int i; - - if (pmu_stats.bitmap ^ bitmap || pmu_stats.unexpected) - return false; - - for (i = 0; i < 32; i++) { - if (test_and_clear_bit(i, &pmu_stats.bitmap)) - if (pmu_stats.interrupts[i] != 1) - return false; - } - return true; -} - -static void test_overflow_interrupt(void) -{ - uint32_t events[] = {MEM_ACCESS, SW_INCR}; - void *addr = malloc(PAGE_SIZE); - int i; - - if (!satisfy_prerequisites(events, ARRAY_SIZE(events))) - return; - - gic_enable_defaults(); - install_irq_handler(EL1H_IRQ, irq_handler); - local_irq_enable(); - gic_enable_irq(23); - - pmu_reset(); - - write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0); - write_regn_el0(pmevtyper, 1, SW_INCR | PMEVTYPER_EXCLUDE_EL0); - write_sysreg_s(0x3, PMCNTENSET_EL0); - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - write_regn_el0(pmevcntr, 1, PRE_OVERFLOW); - isb(); - - /* interrupts are disabled */ - - mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E); - report(expect_interrupts(0), "no overflow interrupt after preset"); - - set_pmcr(pmu.pmcr_ro | PMU_PMCR_E); - for (i = 0; i < 100; i++) - write_sysreg(0x2, pmswinc_el0); - - set_pmcr(pmu.pmcr_ro); - report(expect_interrupts(0), "no overflow interrupt after counting"); - - /* enable interrupts */ - - pmu_reset_stats(); - - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - write_regn_el0(pmevcntr, 1, PRE_OVERFLOW); - write_sysreg(ALL_SET, pmintenset_el1); - isb(); - - mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E); - for (i = 0; i < 100; i++) - write_sysreg(0x3, pmswinc_el0); - - mem_access_loop(addr, 200, pmu.pmcr_ro); - report_info("overflow=0x%lx", read_sysreg(pmovsclr_el0)); - report(expect_interrupts(0x3), - "overflow interrupts expected on #0 and #1"); - - /* promote to 64-b */ - - pmu_reset_stats(); - - write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0); - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - isb(); - mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E); - report(expect_interrupts(0), - "no overflow interrupt expected on 32b boundary"); - - /* overflow on odd counter */ - pmu_reset_stats(); - write_regn_el0(pmevcntr, 0, PRE_OVERFLOW); - write_regn_el0(pmevcntr, 1, ALL_SET); - isb(); - mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E); - report(expect_interrupts(0x2), - "expect overflow interrupt on odd counter"); -} -#endif - -/* - * Ensure that the cycle counter progresses between back-to-back reads. - */ -static bool check_cycles_increase(void) -{ - bool success = true; - - /* init before event access, this test only cares about cycle count */ - set_pmcntenset(1 << PMU_CYCLE_IDX); - set_pmccfiltr(0); /* count cycles in EL0, EL1, but not EL2 */ - - set_pmcr(get_pmcr() | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_E); - - for (int i = 0; i < NR_SAMPLES; i++) { - uint64_t a, b; - - a = get_pmccntr(); - b = get_pmccntr(); - - if (a >= b) { - printf("Read %"PRId64" then %"PRId64".\n", a, b); - success = false; - break; - } - } - - set_pmcr(get_pmcr() & ~PMU_PMCR_E); - - return success; -} - -/* - * Execute a known number of guest instructions. Only even instruction counts - * greater than or equal to 4 are supported by the in-line assembly code. The - * control register (PMCR_EL0) is initialized with the provided value (allowing - * for example for the cycle counter or event counters to be reset). At the end - * of the exact instruction loop, zero is written to PMCR_EL0 to disable - * counting, allowing the cycle counter or event counters to be read at the - * leisure of the calling code. - */ -static void measure_instrs(int num, uint32_t pmcr) -{ - int loop = (num - 2) / 2; - - assert(num >= 4 && ((num - 2) % 2 == 0)); - precise_instrs_loop(loop, pmcr); -} - -/* - * Measure cycle counts for various known instruction counts. Ensure that the - * cycle counter progresses (similar to check_cycles_increase() but with more - * instructions and using reset and stop controls). If supplied a positive, - * nonzero CPI parameter, it also strictly checks that every measurement matches - * it. Strict CPI checking is used to test -icount mode. - */ -static bool check_cpi(int cpi) -{ - uint32_t pmcr = get_pmcr() | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_E; - - /* init before event access, this test only cares about cycle count */ - set_pmcntenset(1 << PMU_CYCLE_IDX); - set_pmccfiltr(0); /* count cycles in EL0, EL1, but not EL2 */ - - if (cpi > 0) - printf("Checking for CPI=%d.\n", cpi); - printf("instrs : cycles0 cycles1 ...\n"); - - for (unsigned int i = 4; i < 300; i += 32) { - uint64_t avg, sum = 0; - - printf("%4d:", i); - for (int j = 0; j < NR_SAMPLES; j++) { - uint64_t cycles; - - set_pmccntr(0); - measure_instrs(i, pmcr); - cycles = get_pmccntr(); - printf(" %4"PRId64"", cycles); - - if (!cycles) { - printf("\ncycles not incrementing!\n"); - return false; - } else if (cpi > 0 && cycles != i * cpi) { - printf("\nunexpected cycle count received!\n"); - return false; - } else if ((cycles >> 32) != 0) { - /* The cycles taken by the loop above should - * fit in 32 bits easily. We check the upper - * 32 bits of the cycle counter to make sure - * there is no supprise. */ - printf("\ncycle count bigger than 32bit!\n"); - return false; - } - - sum += cycles; - } - avg = sum / NR_SAMPLES; - printf(" avg=%-4"PRId64" %s=%-3"PRId64"\n", avg, - (avg >= i) ? "cpi" : "ipc", - (avg >= i) ? avg / i : i / avg); - } - - return true; -} - -static void pmccntr64_test(void) -{ -#ifdef __arm__ - if (pmu.version == ID_DFR0_PMU_V3) { - if (ERRATA(9e3f7a296940)) { - write_sysreg(0xdead, PMCCNTR64); - report(read_sysreg(PMCCNTR64) == 0xdead, "pmccntr64"); - } else - report_skip("Skipping unsafe pmccntr64 test. Set ERRATA_9e3f7a296940=y to enable."); - } -#endif -} - -/* Return FALSE if no PMU found, otherwise return TRUE */ -static bool pmu_probe(void) -{ - uint32_t pmcr = get_pmcr(); - - pmu.version = get_pmu_version(); - if (pmu.version == ID_DFR0_PMU_NOTIMPL || pmu.version == ID_DFR0_PMU_IMPDEF) - return false; - - report_info("PMU version: 0x%x", pmu.version); - - pmcr = get_pmcr(); - report_info("PMU implementer/ID code: %#x(\"%c\")/%#x", - (pmcr >> PMU_PMCR_IMP_SHIFT) & PMU_PMCR_IMP_MASK, - ((pmcr >> PMU_PMCR_IMP_SHIFT) & PMU_PMCR_IMP_MASK) ? : ' ', - (pmcr >> PMU_PMCR_ID_SHIFT) & PMU_PMCR_ID_MASK); - - /* store read-only and RES0 fields of the PMCR bottom-half*/ - pmu.pmcr_ro = pmcr & 0xFFFFFF00; - pmu.nb_implemented_counters = - (pmcr >> PMU_PMCR_N_SHIFT) & PMU_PMCR_N_MASK; - report_info("Implements %d event counters", - pmu.nb_implemented_counters); - - return true; -} - -int main(int argc, char *argv[]) -{ - int cpi = 0; - - if (!pmu_probe()) { - printf("No PMU found, test skipped...\n"); - return report_summary(); - } - - if (argc < 2) - report_abort("no test specified"); - - report_prefix_push("pmu"); - - if (strcmp(argv[1], "cycle-counter") == 0) { - report_prefix_push(argv[1]); - if (argc > 2) - cpi = atol(argv[2]); - report(check_cycles_increase(), - "Monotonically increasing cycle count"); - report(check_cpi(cpi), "Cycle/instruction ratio"); - pmccntr64_test(); - report_prefix_pop(); - } else if (strcmp(argv[1], "pmu-event-introspection") == 0) { - report_prefix_push(argv[1]); - test_event_introspection(); - report_prefix_pop(); - } else if (strcmp(argv[1], "pmu-event-counter-config") == 0) { - report_prefix_push(argv[1]); - test_event_counter_config(); - report_prefix_pop(); - } else if (strcmp(argv[1], "pmu-basic-event-count") == 0) { - report_prefix_push(argv[1]); - test_basic_event_count(); - report_prefix_pop(); - } else if (strcmp(argv[1], "pmu-mem-access") == 0) { - report_prefix_push(argv[1]); - test_mem_access(); - report_prefix_pop(); - } else if (strcmp(argv[1], "pmu-sw-incr") == 0) { - report_prefix_push(argv[1]); - test_sw_incr(); - report_prefix_pop(); - } else if (strcmp(argv[1], "pmu-chained-counters") == 0) { - report_prefix_push(argv[1]); - test_chained_counters(); - report_prefix_pop(); - } else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) { - report_prefix_push(argv[1]); - test_chained_sw_incr(); - report_prefix_pop(); - } else if (strcmp(argv[1], "pmu-chain-promotion") == 0) { - report_prefix_push(argv[1]); - test_chain_promotion(); - report_prefix_pop(); - } else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) { - report_prefix_push(argv[1]); - test_overflow_interrupt(); - report_prefix_pop(); - } else { - report_abort("Unknown sub-test '%s'", argv[1]); - } - - return report_summary(); -} diff --git a/arm/psci.c b/arm/psci.c deleted file mode 100644 index ffc09a2e..00000000 --- a/arm/psci.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * PSCI tests - * - * Copyright (C) 2017, Red Hat, Inc. - * Author: Levente Kurusa - * Author: Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include -#include - -static bool invalid_function_exception; - -#ifdef __arm__ -static void invalid_function_handler(struct pt_regs *regs __unused) -{ - invalid_function_exception = true; -} -#else -static void invalid_function_handler(struct pt_regs *regs, unsigned int esr __unused) -{ - invalid_function_exception = true; - regs->pc += 4; -} -#endif - -static void install_invalid_function_handler(exception_fn handler) -{ -#ifdef __arm__ - install_exception_handler(EXCPTN_UND, handler); -#else - install_exception_handler(EL1H_SYNC, ESR_EL1_EC_UNKNOWN, handler); -#endif -} - -static bool psci_invalid_function(void) -{ - bool pass; - - install_invalid_function_handler(invalid_function_handler); - - pass = psci_invoke(1337, 0, 0, 0) == PSCI_RET_NOT_SUPPORTED || invalid_function_exception; - - install_invalid_function_handler(NULL); - return pass; -} - -static int psci_affinity_info(unsigned long target_affinity, uint32_t lowest_affinity_level) -{ -#ifdef __arm__ - return psci_invoke(PSCI_0_2_FN_AFFINITY_INFO, target_affinity, lowest_affinity_level, 0); -#else - return psci_invoke(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, lowest_affinity_level, 0); -#endif -} - -static bool psci_affinity_info_on(void) -{ - return psci_affinity_info(cpus[0], 0) == PSCI_0_2_AFFINITY_LEVEL_ON; -} - -static bool psci_affinity_info_off(void) -{ - return psci_affinity_info(cpus[1], 0) == PSCI_0_2_AFFINITY_LEVEL_OFF; -} - -static int cpu_on_ret[NR_CPUS]; -static cpumask_t cpu_on_ready, cpu_on_done; -static volatile int cpu_on_start; - -static void cpu_on_secondary_entry(void) -{ - int cpu = smp_processor_id(); - - cpumask_set_cpu(cpu, &cpu_on_ready); - while (!cpu_on_start) - cpu_relax(); - cpu_on_ret[cpu] = psci_cpu_on(cpus[1], __pa(halt)); - cpumask_set_cpu(cpu, &cpu_on_done); -} - -static bool psci_cpu_on_test(void) -{ - bool failed = false; - int ret_success = 0; - int cpu; - - cpumask_set_cpu(1, &cpu_on_ready); - cpumask_set_cpu(1, &cpu_on_done); - - for_each_present_cpu(cpu) { - if (cpu < 2) - continue; - smp_boot_secondary(cpu, cpu_on_secondary_entry); - } - - cpumask_set_cpu(0, &cpu_on_ready); - while (!cpumask_full(&cpu_on_ready)) - cpu_relax(); - - cpu_on_start = 1; - smp_mb(); - - cpu_on_ret[0] = psci_cpu_on(cpus[1], __pa(halt)); - cpumask_set_cpu(0, &cpu_on_done); - - while (!cpumask_full(&cpu_on_done)) - cpu_relax(); - - for_each_present_cpu(cpu) { - if (cpu == 1) - continue; - if (cpu_on_ret[cpu] == PSCI_RET_SUCCESS) { - ret_success++; - } else if (cpu_on_ret[cpu] != PSCI_RET_ALREADY_ON) { - report_info("unexpected cpu_on return value: caller=CPU%d, ret=%d", cpu, cpu_on_ret[cpu]); - failed = true; - } - } - - if (ret_success != 1) { - report_info("got %d CPU_ON success", ret_success); - failed = true; - } - - return !failed; -} - -int main(void) -{ - int ver = psci_invoke(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); - - report_prefix_push("psci"); - - if (nr_cpus < 2) { - report_skip("At least 2 cpus required"); - goto done; - } - - report_info("PSCI version %d.%d", PSCI_VERSION_MAJOR(ver), - PSCI_VERSION_MINOR(ver)); - report(psci_invalid_function(), "invalid-function"); - report(psci_affinity_info_on(), "affinity-info-on"); - report(psci_affinity_info_off(), "affinity-info-off"); - - if (ERRATA(6c7a5dce22b3)) - report(psci_cpu_on_test(), "cpu-on"); - else - report_skip("Skipping unsafe cpu-on test. Set ERRATA_6c7a5dce22b3=y to enable."); - -done: -#if 0 - report_summary(); - psci_invoke(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); - report(false, "system-off"); - return 1; /* only reaches here if system-off fails */ -#else - return report_summary(); -#endif -} diff --git a/arm/run b/arm/run deleted file mode 100755 index a390ca5a..00000000 --- a/arm/run +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash - -if [ -z "$STANDALONE" ]; then - if [ ! -f config.mak ]; then - echo "run ./configure && make first. See ./configure -h" - exit 2 - fi - source config.mak - source scripts/arch-run.bash -fi -processor="$PROCESSOR" - -ACCEL=$(get_qemu_accelerator) || - exit $? - -qemu=$(search_qemu_binary) || - exit $? - -if ! $qemu -machine '?' 2>&1 | grep 'ARM Virtual Machine' > /dev/null; then - echo "$qemu doesn't support mach-virt ('-machine virt'). Exiting." - exit 2 -fi - -M='-machine virt' - -if [ "$ACCEL" = "kvm" ]; then - if $qemu $M,\? 2>&1 | grep gic-version > /dev/null; then - M+=',gic-version=host' - fi - if [ "$HOST" = "aarch64" ] || [ "$HOST" = "arm" ]; then - processor="host" - if [ "$ARCH" = "arm" ] && [ "$HOST" = "aarch64" ]; then - processor+=",aarch64=off" - fi - fi -fi - -if [ "$ARCH" = "arm" ]; then - M+=",highmem=off" -fi - -if ! $qemu $M -device '?' 2>&1 | grep virtconsole > /dev/null; then - echo "$qemu doesn't support virtio-console for chr-testdev. Exiting." - exit 2 -fi - -if $qemu $M -chardev testdev,id=id -initrd . 2>&1 \ - | grep backend > /dev/null; then - echo "$qemu doesn't support chr-testdev. Exiting." - exit 2 -fi - -chr_testdev='-device virtio-serial-device' -chr_testdev+=' -device virtconsole,chardev=ctd -chardev testdev,id=ctd' - -pci_testdev= -if $qemu $M -device '?' 2>&1 | grep pci-testdev > /dev/null; then - pci_testdev="-device pci-testdev" -fi - -M+=",accel=$ACCEL" -command="$qemu -nodefaults $M -cpu $processor $chr_testdev $pci_testdev" -command+=" -display none -serial stdio -kernel" -command="$(migration_cmd) $(timeout_cmd) $command" - -run_qemu $command "$@" diff --git a/arm/selftest.c b/arm/selftest.c deleted file mode 100644 index 4495b161..00000000 --- a/arm/selftest.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Test the framework itself. These tests confirm that setup works. - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static cpumask_t ready, valid; - -static void __user_psci_system_off(void) -{ - psci_system_off(); - halt(); - __builtin_unreachable(); -} - -static void check_setup(int argc, char **argv) -{ - int nr_tests = 0, len, i; - long val; - - for (i = 0; i < argc; ++i) { - - len = parse_keyval(argv[i], &val); - if (len == -1) - continue; - - argv[i][len] = '\0'; - report_prefix_push(argv[i]); - - if (strcmp(argv[i], "mem") == 0) { - - phys_addr_t memsize = PHYS_END - PHYS_OFFSET; - phys_addr_t expected = ((phys_addr_t)val)*1024*1024; - - report(memsize == expected, - "memory size matches expectation"); - report_info("found %" PRIu64 " MB", memsize/1024/1024); - ++nr_tests; - - } else if (strcmp(argv[i], "smp") == 0) { - - report(nr_cpus == (int)val, - "number of CPUs matches expectation"); - report_info("found %d CPUs", nr_cpus); - ++nr_tests; - } - - report_prefix_pop(); - } - - if (nr_tests < 2) - report_abort("missing input"); -} - -unsigned long check_pabt_invalid_paddr; -static bool check_pabt_init(void) -{ - phys_addr_t highest_end = 0; - unsigned long vaddr; - struct mem_region *r; - - /* - * We need a physical address that isn't backed by anything. Without - * fully parsing the device tree there's no way to be certain of any - * address, but an unknown address immediately following the highest - * memory region has a reasonable chance. This is because we can - * assume that that memory region could have been larger, if the user - * had configured more RAM, and therefore no MMIO region should be - * there. - */ - for (r = mem_regions; r->end; ++r) { - if (r->flags & MR_F_IO) - continue; - if (r->end > highest_end) - highest_end = PAGE_ALIGN(r->end); - } - - if (mem_region_get_flags(highest_end) != MR_F_UNKNOWN) - return false; - - vaddr = (unsigned long)vmap(highest_end, PAGE_SIZE); - mmu_clear_user(current_thread_info()->pgtable, vaddr); - check_pabt_invalid_paddr = vaddr; - - return true; -} - -static struct pt_regs expected_regs; -static bool und_works; -static bool svc_works; -static bool pabt_works; -#if defined(__arm__) -/* - * Capture the current register state and execute an instruction - * that causes an exception. The test handler will check that its - * capture of the current register state matches the capture done - * here. - */ -#define test_exception(pre_insns, excptn_insn, post_insns, clobbers...) \ - asm volatile( \ - pre_insns "\n" \ - "mov r0, %0\n" \ - "stmia r0, { r0-lr }\n" \ - "mrs r1, cpsr\n" \ - "str r1, [r0, #" xstr(S_PSR) "]\n" \ - "mov r1, #-1\n" \ - "str r1, [r0, #" xstr(S_OLD_R0) "]\n" \ - "add r1, pc, #8\n" \ - "str r1, [r0, #" xstr(S_R1) "]\n" \ - "str r1, [r0, #" xstr(S_PC) "]\n" \ - excptn_insn "\n" \ - post_insns "\n" \ - :: "r" (&expected_regs) : "r0", "r1", ##clobbers) - -static bool check_regs(struct pt_regs *regs) -{ - unsigned i; - - /* exception handlers should always run in svc mode */ - if (current_mode() != SVC_MODE) - return false; - - for (i = 0; i < ARRAY_SIZE(regs->uregs); ++i) { - if (regs->uregs[i] != expected_regs.uregs[i]) - return false; - } - - return true; -} - -static void und_handler(struct pt_regs *regs) -{ - und_works = check_regs(regs); -} - -static bool check_und(void) -{ - install_exception_handler(EXCPTN_UND, und_handler); - - /* issue an instruction to a coprocessor we don't have */ - test_exception("", "mcr p2, 0, r0, c0, c0", "", "r0"); - - install_exception_handler(EXCPTN_UND, NULL); - - return und_works; -} - -static void svc_handler(struct pt_regs *regs) -{ - u32 svc = *(u32 *)(regs->ARM_pc - 4) & 0xffffff; - - if (processor_mode(regs) == SVC_MODE) { - /* - * When issuing an svc from supervisor mode lr_svc will - * get corrupted. So before issuing the svc, callers must - * always push it on the stack. We pushed it to offset 4. - */ - regs->ARM_lr = *(unsigned long *)(regs->ARM_sp + 4); - } - - svc_works = check_regs(regs) && svc == 123; -} - -static bool check_svc(void) -{ - install_exception_handler(EXCPTN_SVC, svc_handler); - - if (current_mode() == SVC_MODE) { - /* - * An svc from supervisor mode will corrupt lr_svc and - * spsr_svc. We need to save/restore them separately. - */ - test_exception( - "mrs r0, spsr\n" - "push { r0,lr }\n", - "svc #123\n", - "pop { r0,lr }\n" - "msr spsr_cxsf, r0\n", - "r0", "lr" - ); - } else { - test_exception("", "svc #123", ""); - } - - install_exception_handler(EXCPTN_SVC, NULL); - - return svc_works; -} - -static void pabt_handler(struct pt_regs *regs) -{ - expected_regs.ARM_lr = expected_regs.ARM_pc; - expected_regs.ARM_pc = expected_regs.ARM_r9; - - pabt_works = check_regs(regs); - - regs->ARM_pc = regs->ARM_lr; -} - -static bool check_pabt(void) -{ - install_exception_handler(EXCPTN_PABT, pabt_handler); - - test_exception("ldr r9, =check_pabt_invalid_paddr\n" - "ldr r9, [r9]\n", - "blx r9\n", - "", "r9", "lr"); - - install_exception_handler(EXCPTN_PABT, NULL); - - return pabt_works; -} - -static void user_psci_system_off(struct pt_regs *regs) -{ - __user_psci_system_off(); -} -#elif defined(__aarch64__) - -/* - * Capture the current register state and execute an instruction - * that causes an exception. The test handler will check that its - * capture of the current register state matches the capture done - * here. - */ -#define test_exception(pre_insns, excptn_insn, post_insns, clobbers...) \ - asm volatile( \ - pre_insns "\n" \ - "mov x1, %0\n" \ - "ldr x0, [x1, #" xstr(S_PSTATE) "]\n" \ - "mrs x1, nzcv\n" \ - "orr w0, w0, w1\n" \ - "mov x1, %0\n" \ - "str w0, [x1, #" xstr(S_PSTATE) "]\n" \ - "mov x0, sp\n" \ - "str x0, [x1, #" xstr(S_SP) "]\n" \ - "adr x0, 1f\n" \ - "str x0, [x1, #" xstr(S_PC) "]\n" \ - "stp x2, x3, [x1, #16]\n" \ - "stp x4, x5, [x1, #32]\n" \ - "stp x6, x7, [x1, #48]\n" \ - "stp x8, x9, [x1, #64]\n" \ - "stp x10, x11, [x1, #80]\n" \ - "stp x12, x13, [x1, #96]\n" \ - "stp x14, x15, [x1, #112]\n" \ - "stp x16, x17, [x1, #128]\n" \ - "stp x18, x19, [x1, #144]\n" \ - "stp x20, x21, [x1, #160]\n" \ - "stp x22, x23, [x1, #176]\n" \ - "stp x24, x25, [x1, #192]\n" \ - "stp x26, x27, [x1, #208]\n" \ - "stp x28, x29, [x1, #224]\n" \ - "str x30, [x1, #" xstr(S_LR) "]\n" \ - "stp x0, x1, [x1]\n" \ - "1:" excptn_insn "\n" \ - post_insns "\n" \ - :: "r" (&expected_regs) : "x0", "x1", ##clobbers) - -static bool check_regs(struct pt_regs *regs) -{ - unsigned i; - - /* exception handlers should always run in EL1 */ - if (current_level() != CurrentEL_EL1) - return false; - - for (i = 0; i < ARRAY_SIZE(regs->regs); ++i) { - if (regs->regs[i] != expected_regs.regs[i]) - return false; - } - - regs->pstate &= 0xf0000000 /* NZCV */ | 0x3c0 /* DAIF */ - | PSR_MODE_MASK; - - return regs->sp == expected_regs.sp - && regs->pc == expected_regs.pc - && regs->pstate == expected_regs.pstate; -} - -static enum vector check_vector_prep(void) -{ - unsigned long daif; - - if (is_user()) - return EL0_SYNC_64; - - asm volatile("mrs %0, daif" : "=r" (daif) ::); - expected_regs.pstate = daif | PSR_MODE_EL1h; - return EL1H_SYNC; -} - -static void unknown_handler(struct pt_regs *regs, unsigned int esr __unused) -{ - und_works = check_regs(regs); - regs->pc += 4; -} - -static bool check_und(void) -{ - enum vector v = check_vector_prep(); - - install_exception_handler(v, ESR_EL1_EC_UNKNOWN, unknown_handler); - - /* try to read an el2 sysreg from el0/1 */ - test_exception("", "mrs x0, sctlr_el2", "", "x0"); - - install_exception_handler(v, ESR_EL1_EC_UNKNOWN, NULL); - - return und_works; -} - -static void svc_handler(struct pt_regs *regs, unsigned int esr) -{ - u16 svc = esr & 0xffff; - - expected_regs.pc += 4; - svc_works = check_regs(regs) && svc == 123; -} - -static bool check_svc(void) -{ - enum vector v = check_vector_prep(); - - install_exception_handler(v, ESR_EL1_EC_SVC64, svc_handler); - - test_exception("", "svc #123", ""); - - install_exception_handler(v, ESR_EL1_EC_SVC64, NULL); - - return svc_works; -} - -static void pabt_handler(struct pt_regs *regs, unsigned int esr) -{ - bool is_extabt = (esr & ESR_EL1_FSC_MASK) == ESR_EL1_FSC_EXTABT; - - expected_regs.regs[30] = expected_regs.pc + 4; - expected_regs.pc = expected_regs.regs[9]; - - pabt_works = check_regs(regs) && is_extabt; - - regs->pc = regs->regs[30]; -} - -static bool check_pabt(void) -{ - enum vector v = check_vector_prep(); - - install_exception_handler(v, ESR_EL1_EC_IABT_EL1, pabt_handler); - - test_exception("adrp x9, check_pabt_invalid_paddr\n" - "add x9, x9, :lo12:check_pabt_invalid_paddr\n" - "ldr x9, [x9]\n", - "blr x9\n", - "", "x9", "x30"); - - install_exception_handler(v, ESR_EL1_EC_IABT_EL1, NULL); - - return pabt_works; -} - -static void user_psci_system_off(struct pt_regs *regs, unsigned int esr) -{ - __user_psci_system_off(); -} -#endif - -static void check_vectors(void *arg __unused) -{ - report(check_und(), "und"); - report(check_svc(), "svc"); - if (is_user()) { -#ifdef __arm__ - install_exception_handler(EXCPTN_UND, user_psci_system_off); -#else - install_exception_handler(EL0_SYNC_64, ESR_EL1_EC_UNKNOWN, - user_psci_system_off); -#endif - } else { - if (!check_pabt_init()) - report_skip("Couldn't guess an invalid physical address"); - else - report(check_pabt(), "pabt"); - } - exit(report_summary()); -} - -static bool psci_check(void) -{ - const struct fdt_property *method; - int node, len, ver; - - node = fdt_node_offset_by_compatible(dt_fdt(), -1, "arm,psci-0.2"); - if (node < 0) { - printf("PSCI v0.2 compatibility required\n"); - return false; - } - - method = fdt_get_property(dt_fdt(), node, "method", &len); - if (method == NULL) { - printf("bad psci device tree node\n"); - return false; - } - - if (len < 4 || strcmp(method->data, "hvc") != 0) { - printf("psci method must be hvc\n"); - return false; - } - - ver = psci_invoke(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); - printf("PSCI version %d.%d\n", PSCI_VERSION_MAJOR(ver), - PSCI_VERSION_MINOR(ver)); - - return true; -} - -static void cpu_report(void *data __unused) -{ - uint64_t mpidr = get_mpidr(); - int cpu = smp_processor_id(); - - if (mpidr_to_cpu(mpidr) == cpu) - cpumask_set_cpu(smp_processor_id(), &valid); - smp_wmb(); /* Paired with rmb in main(). */ - cpumask_set_cpu(smp_processor_id(), &ready); - report_info("CPU%3d: MPIDR=%010" PRIx64, cpu, mpidr); -} - -int main(int argc, char **argv) -{ - report_prefix_push("selftest"); - - if (argc < 2) - report_abort("no test specified"); - - report_prefix_push(argv[1]); - - if (strcmp(argv[1], "setup") == 0) { - - check_setup(argc-2, &argv[2]); - - } else if (strcmp(argv[1], "vectors-kernel") == 0) { - - check_vectors(NULL); - - } else if (strcmp(argv[1], "vectors-user") == 0) { - - start_usr(check_vectors, NULL, - (unsigned long)thread_stack_alloc()); - - } else if (strcmp(argv[1], "smp") == 0) { - - report(psci_check(), "PSCI version"); - on_cpus(cpu_report, NULL); - while (!cpumask_full(&ready)) - cpu_relax(); - smp_rmb(); /* Paired with wmb in cpu_report(). */ - report(cpumask_full(&valid), "MPIDR test on all CPUs"); - report_info("%d CPUs reported back", nr_cpus); - - } else { - printf("Unknown subtest\n"); - abort(); - } - - return report_summary(); -} diff --git a/arm/sieve.c b/arm/sieve.c deleted file mode 120000 index 8f14a5c3..00000000 --- a/arm/sieve.c +++ /dev/null @@ -1 +0,0 @@ -../x86/sieve.c \ No newline at end of file diff --git a/arm/spinlock-test.c b/arm/spinlock-test.c deleted file mode 100644 index 73aea76a..00000000 --- a/arm/spinlock-test.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Spinlock test - * - * This code is based on code from the tcg_baremetal_tests. - * - * Copyright (C) 2015 Virtual Open Systems SAS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include - -#define LOOP_SIZE 10000000 - -struct lock_ops { - void (*lock)(int *v); - void (*unlock)(int *v); -}; -static struct lock_ops lock_ops; - -static void gcc_builtin_lock(int *lock_var) -{ - while (__sync_lock_test_and_set(lock_var, 1)); -} -static void gcc_builtin_unlock(int *lock_var) -{ - __sync_lock_release(lock_var); -} -static void none_lock(int *lock_var) -{ - while (*(volatile int *)lock_var != 0); - *(volatile int *)lock_var = 1; -} -static void none_unlock(int *lock_var) -{ - *(volatile int *)lock_var = 0; -} - -static int global_a, global_b; -static int global_lock; - -static void test_spinlock(void *data __unused) -{ - int i, errors = 0; - int cpu = smp_processor_id(); - - printf("CPU%d online\n", cpu); - - for (i = 0; i < LOOP_SIZE; i++) { - - lock_ops.lock(&global_lock); - - if (global_a == (cpu + 1) % 2) { - global_a = 1; - global_b = 0; - } else { - global_a = 0; - global_b = 1; - } - - if (global_a == global_b) - errors++; - - lock_ops.unlock(&global_lock); - } - report(errors == 0, "CPU%d: Done - Errors: %d", cpu, errors); -} - -int main(int argc, char **argv) -{ - report_prefix_push("spinlock"); - if (argc > 1 && strcmp(argv[1], "bad") != 0) { - lock_ops.lock = gcc_builtin_lock; - lock_ops.unlock = gcc_builtin_unlock; - } else { - lock_ops.lock = none_lock; - lock_ops.unlock = none_unlock; - } - - on_cpus(test_spinlock, NULL); - - return report_summary(); -} diff --git a/arm/timer.c b/arm/timer.c deleted file mode 100644 index 44621b4f..00000000 --- a/arm/timer.c +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Timer tests for the ARM virt machine. - * - * Copyright (C) 2017, Alexander Graf - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include -#include -#include -#include -#include -#include -#include - -#define ARCH_TIMER_CTL_ENABLE (1 << 0) -#define ARCH_TIMER_CTL_IMASK (1 << 1) -#define ARCH_TIMER_CTL_ISTATUS (1 << 2) - -static void *gic_isenabler; -static void *gic_icenabler; - -static bool ptimer_unsupported; - -static void ptimer_unsupported_handler(struct pt_regs *regs, unsigned int esr) -{ - ptimer_unsupported = true; - regs->pc += 4; -} - -static u64 read_vtimer_counter(void) -{ - isb(); - return read_sysreg(cntvct_el0); -} - -static u64 read_vtimer_cval(void) -{ - return read_sysreg(cntv_cval_el0); -} - -static void write_vtimer_cval(u64 val) -{ - write_sysreg(val, cntv_cval_el0); - isb(); -} - -static s32 read_vtimer_tval(void) -{ - return read_sysreg(cntv_tval_el0); -} - -static void write_vtimer_tval(s32 val) -{ - write_sysreg(val, cntv_tval_el0); - isb(); -} - -static u64 read_vtimer_ctl(void) -{ - return read_sysreg(cntv_ctl_el0); -} - -static void write_vtimer_ctl(u64 val) -{ - write_sysreg(val, cntv_ctl_el0); - isb(); -} - -static u64 read_ptimer_counter(void) -{ - isb(); - return read_sysreg(cntpct_el0); -} - -static u64 read_ptimer_cval(void) -{ - return read_sysreg(cntp_cval_el0); -} - -static void write_ptimer_cval(u64 val) -{ - write_sysreg(val, cntp_cval_el0); - isb(); -} - -static s32 read_ptimer_tval(void) -{ - return read_sysreg(cntp_tval_el0); -} - -static void write_ptimer_tval(s32 val) -{ - write_sysreg(val, cntp_tval_el0); - isb(); -} - -static u64 read_ptimer_ctl(void) -{ - return read_sysreg(cntp_ctl_el0); -} - -static void write_ptimer_ctl(u64 val) -{ - write_sysreg(val, cntp_ctl_el0); - isb(); -} - -struct timer_info { - u32 irq; - u32 irq_flags; - volatile bool irq_received; - u64 (*read_counter)(void); - u64 (*read_cval)(void); - void (*write_cval)(u64); - s32 (*read_tval)(void); - void (*write_tval)(s32); - u64 (*read_ctl)(void); - void (*write_ctl)(u64); -}; - -static struct timer_info vtimer_info = { - .irq_received = false, - .read_counter = read_vtimer_counter, - .read_cval = read_vtimer_cval, - .write_cval = write_vtimer_cval, - .read_tval = read_vtimer_tval, - .write_tval = write_vtimer_tval, - .read_ctl = read_vtimer_ctl, - .write_ctl = write_vtimer_ctl, -}; - -static struct timer_info ptimer_info = { - .irq_received = false, - .read_counter = read_ptimer_counter, - .read_cval = read_ptimer_cval, - .write_cval = write_ptimer_cval, - .read_tval = read_ptimer_tval, - .write_tval = write_ptimer_tval, - .read_ctl = read_ptimer_ctl, - .write_ctl = write_ptimer_ctl, -}; - -static void set_timer_irq_enabled(struct timer_info *info, bool enabled) -{ - u32 val = 1 << PPI(info->irq); - - if (enabled) - writel(val, gic_isenabler); - else - writel(val, gic_icenabler); -} - -static void irq_handler(struct pt_regs *regs) -{ - struct timer_info *info; - u32 irqstat = gic_read_iar(); - u32 irqnr = gic_iar_irqnr(irqstat); - - if (irqnr == PPI(vtimer_info.irq)) { - info = &vtimer_info; - } else if (irqnr == PPI(ptimer_info.irq)) { - info = &ptimer_info; - } else { - if (irqnr != GICC_INT_SPURIOUS) - gic_write_eoir(irqstat); - report_info("Unexpected interrupt: %d\n", irqnr); - return; - } - - info->write_ctl(ARCH_TIMER_CTL_IMASK | ARCH_TIMER_CTL_ENABLE); - gic_write_eoir(irqstat); - - info->irq_received = true; -} - -/* Check that the timer condition is met. */ -static bool timer_pending(struct timer_info *info) -{ - return (info->read_ctl() & ARCH_TIMER_CTL_ENABLE) && - (info->read_ctl() & ARCH_TIMER_CTL_ISTATUS); -} - -static bool gic_timer_check_state(struct timer_info *info, - enum gic_irq_state expected_state) -{ - int i; - - /* Wait for up to 1s for the GIC to sample the interrupt. */ - for (i = 0; i < 10; i++) { - mdelay(100); - if (gic_irq_state(PPI(info->irq)) == expected_state) { - mdelay(100); - if (gic_irq_state(PPI(info->irq)) == expected_state) - return true; - } - } - - return false; -} - -static bool test_cval_10msec(struct timer_info *info) -{ - u64 time_10ms = read_sysreg(cntfrq_el0) / 100; - u64 time_1us = time_10ms / 10000; - u64 before_timer, after_timer; - s64 difference; - - /* Program timer to fire in 10 ms */ - before_timer = info->read_counter(); - info->write_cval(before_timer + time_10ms); - info->write_ctl(ARCH_TIMER_CTL_ENABLE); - - /* Wait for the timer to fire */ - while (!timer_pending(info)) - ; - - /* It fired, check how long it took */ - after_timer = info->read_counter(); - difference = after_timer - (before_timer + time_10ms); - - report_info("After timer: 0x%016lx", after_timer); - report_info("Expected : 0x%016lx", before_timer + time_10ms); - report_info("Difference : %ld us", difference / time_1us); - - if (difference < 0) { - printf("ISTATUS set too early\n"); - return false; - } - return difference < time_10ms; -} - -static void test_timer(struct timer_info *info) -{ - u64 now = info->read_counter(); - u64 time_10s = read_sysreg(cntfrq_el0) * 10; - u64 later = now + time_10s; - s32 left; - - /* We don't want the irq handler to fire because that will change the - * timer state and we want to test the timer output signal. We can - * still read the pending state even if it's disabled. */ - set_timer_irq_enabled(info, false); - - /* Enable the timer, but schedule it for much later */ - info->write_cval(later); - info->write_ctl(ARCH_TIMER_CTL_ENABLE); - report(!timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE), - "not pending before"); - - info->write_cval(now - 1); - report(timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_PENDING), - "interrupt signal pending"); - - /* Disable the timer again and prepare to take interrupts */ - info->write_ctl(0); - info->irq_received = false; - set_timer_irq_enabled(info, true); - report(!info->irq_received, "no interrupt when timer is disabled"); - report(!timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE), - "interrupt signal no longer pending"); - - info->write_cval(now - 1); - info->write_ctl(ARCH_TIMER_CTL_ENABLE | ARCH_TIMER_CTL_IMASK); - report(timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE), - "interrupt signal not pending"); - - report(test_cval_10msec(info), "latency within 10 ms"); - report(info->irq_received, "interrupt received"); - - /* Disable the timer again */ - info->write_ctl(0); - - /* Test TVAL and IRQ trigger */ - info->irq_received = false; - info->write_tval(read_sysreg(cntfrq_el0) / 100); /* 10 ms */ - local_irq_disable(); - info->write_ctl(ARCH_TIMER_CTL_ENABLE); - report_info("waiting for interrupt..."); - wfi(); - local_irq_enable(); - left = info->read_tval(); - report(info->irq_received, "interrupt received after TVAL/WFI"); - report(left < 0, "timer has expired"); - report_info("TVAL is %d ticks", left); -} - -static void test_vtimer(void) -{ - report_prefix_push("vtimer-busy-loop"); - test_timer(&vtimer_info); - report_prefix_pop(); -} - -static void test_ptimer(void) -{ - if (ptimer_unsupported) - return; - - report_prefix_push("ptimer-busy-loop"); - test_timer(&ptimer_info); - report_prefix_pop(); -} - -static void test_init(void) -{ - const struct fdt_property *prop; - const void *fdt = dt_fdt(); - int node, len; - u32 *data; - - node = fdt_node_offset_by_compatible(fdt, -1, "arm,armv8-timer"); - assert(node >= 0); - prop = fdt_get_property(fdt, node, "interrupts", &len); - assert(prop && len == (4 * 3 * sizeof(u32))); - - data = (u32 *)prop->data; - assert(fdt32_to_cpu(data[3]) == 1); - ptimer_info.irq = fdt32_to_cpu(data[4]); - ptimer_info.irq_flags = fdt32_to_cpu(data[5]); - assert(fdt32_to_cpu(data[6]) == 1); - vtimer_info.irq = fdt32_to_cpu(data[7]); - vtimer_info.irq_flags = fdt32_to_cpu(data[8]); - - install_exception_handler(EL1H_SYNC, ESR_EL1_EC_UNKNOWN, ptimer_unsupported_handler); - ptimer_info.read_ctl(); - install_exception_handler(EL1H_SYNC, ESR_EL1_EC_UNKNOWN, NULL); - - if (ptimer_unsupported && !ERRATA(7b6b46311a85)) { - report_skip("Skipping ptimer tests. Set ERRATA_7b6b46311a85=y to enable."); - } else if (ptimer_unsupported) { - report(false, "ptimer: read CNTP_CTL_EL0"); - report_info("ptimer: skipping remaining tests"); - } - - gic_enable_defaults(); - - switch (gic_version()) { - case 2: - gic_isenabler = gicv2_dist_base() + GICD_ISENABLER; - gic_icenabler = gicv2_dist_base() + GICD_ICENABLER; - break; - case 3: - gic_isenabler = gicv3_sgi_base() + GICR_ISENABLER0; - gic_icenabler = gicv3_sgi_base() + GICR_ICENABLER0; - break; - } - - install_irq_handler(EL1H_IRQ, irq_handler); - local_irq_enable(); -} - -static void print_timer_info(void) -{ - printf("CNTFRQ_EL0 : 0x%016lx\n", read_sysreg(cntfrq_el0)); - - if (!ptimer_unsupported) { - printf("CNTPCT_EL0 : 0x%016lx\n", ptimer_info.read_counter()); - printf("CNTP_CTL_EL0 : 0x%016lx\n", ptimer_info.read_ctl()); - printf("CNTP_CVAL_EL0: 0x%016lx\n", ptimer_info.read_cval()); - } - - printf("CNTVCT_EL0 : 0x%016lx\n", vtimer_info.read_counter()); - printf("CNTV_CTL_EL0 : 0x%016lx\n", vtimer_info.read_ctl()); - printf("CNTV_CVAL_EL0: 0x%016lx\n", vtimer_info.read_cval()); -} - -int main(int argc, char **argv) -{ - int i; - - test_init(); - - print_timer_info(); - - if (argc == 1) { - test_vtimer(); - test_ptimer(); - } - - for (i = 1; i < argc; ++i) { - if (strcmp(argv[i], "vtimer") == 0) - test_vtimer(); - if (strcmp(argv[i], "ptimer") == 0) - test_ptimer(); - } - - return report_summary(); -} diff --git a/arm/unittests.cfg b/arm/unittests.cfg deleted file mode 100644 index f776b66e..00000000 --- a/arm/unittests.cfg +++ /dev/null @@ -1,243 +0,0 @@ -############################################################################## -# unittest configuration -# -# [unittest_name] -# file = .flat # Name of the flat file to be used. -# smp = # Number of processors the VM will use -# # during this test. Use $MAX_SMP to use -# # the maximum the host supports. Defaults -# # to one. -# extra_params = -append # Additional parameters used. -# arch = arm|arm64 # Select one if the test case is -# # specific to only one. -# groups = ... # Used to identify test cases -# # with run_tests -g ... -# # Specify group_name=nodefault -# # to have test not run by -# # default -# accel = kvm|tcg # Optionally specify if test must run with -# # kvm or tcg. If not specified, then kvm will -# # be used when available. -# timeout = # Optionally specify a timeout. -# check = = # check a file for a particular value before running -# # a test. The check line can contain multiple files -# # to check separated by a space but each check -# # parameter needs to be of the form = -############################################################################## - -# -# Test that the configured number of processors (smp = ), and -# that the configured amount of memory (-m ) are correctly setup -# by the framework. -# -[selftest-setup] -file = selftest.flat -smp = 2 -extra_params = -m 256 -append 'setup smp=2 mem=256' -groups = selftest - -# Test vector setup and exception handling (kernel mode). -[selftest-vectors-kernel] -file = selftest.flat -extra_params = -append 'vectors-kernel' -groups = selftest - -# Test vector setup and exception handling (user mode). -[selftest-vectors-user] -file = selftest.flat -extra_params = -append 'vectors-user' -groups = selftest - -# Test SMP support -[selftest-smp] -file = selftest.flat -smp = $MAX_SMP -extra_params = -append 'smp' -groups = selftest - -# Test PCI emulation -[pci-test] -file = pci-test.flat -groups = pci - -# Test PMU support -[pmu-cycle-counter] -file = pmu.flat -groups = pmu -extra_params = -append 'cycle-counter 0' - -[pmu-event-introspection] -file = pmu.flat -groups = pmu -arch = arm64 -extra_params = -append 'pmu-event-introspection' - -[pmu-event-counter-config] -file = pmu.flat -groups = pmu -arch = arm64 -extra_params = -append 'pmu-event-counter-config' - -[pmu-basic-event-count] -file = pmu.flat -groups = pmu -arch = arm64 -extra_params = -append 'pmu-basic-event-count' - -[pmu-mem-access] -file = pmu.flat -groups = pmu -arch = arm64 -extra_params = -append 'pmu-mem-access' - -[pmu-sw-incr] -file = pmu.flat -groups = pmu -arch = arm64 -extra_params = -append 'pmu-sw-incr' - -[pmu-chained-counters] -file = pmu.flat -groups = pmu -arch = arm64 -extra_params = -append 'pmu-chained-counters' - -[pmu-chained-sw-incr] -file = pmu.flat -groups = pmu -arch = arm64 -extra_params = -append 'pmu-chained-sw-incr' - -[pmu-chain-promotion] -file = pmu.flat -groups = pmu -arch = arm64 -extra_params = -append 'pmu-chain-promotion' - -[pmu-overflow-interrupt] -file = pmu.flat -groups = pmu -arch = arm64 -extra_params = -append 'pmu-overflow-interrupt' - -# Test PMU support (TCG) with -icount IPC=1 -#[pmu-tcg-icount-1] -#file = pmu.flat -#extra_params = -icount 0 -append 'cycle-counter 1' -#groups = pmu -#accel = tcg - -# Test PMU support (TCG) with -icount IPC=256 -#[pmu-tcg-icount-256] -#file = pmu.flat -#extra_params = -icount 8 -append 'cycle-counter 256' -#groups = pmu -#accel = tcg - -# Test GIC emulation -[gicv2-ipi] -file = gic.flat -smp = $((($MAX_SMP < 8)?$MAX_SMP:8)) -extra_params = -machine gic-version=2 -append 'ipi' -groups = gic - -[gicv2-mmio] -file = gic.flat -smp = $((($MAX_SMP < 8)?$MAX_SMP:8)) -extra_params = -machine gic-version=2 -append 'mmio' -groups = gic - -[gicv2-mmio-up] -file = gic.flat -smp = 1 -extra_params = -machine gic-version=2 -append 'mmio' -groups = gic - -[gicv2-mmio-3p] -file = gic.flat -smp = $((($MAX_SMP < 3)?$MAX_SMP:3)) -extra_params = -machine gic-version=2 -append 'mmio' -groups = gic - -[gicv3-ipi] -file = gic.flat -smp = $MAX_SMP -extra_params = -machine gic-version=3 -append 'ipi' -groups = gic - -[gicv2-active] -file = gic.flat -smp = $((($MAX_SMP < 8)?$MAX_SMP:8)) -extra_params = -machine gic-version=2 -append 'active' -groups = gic - -[gicv3-active] -file = gic.flat -smp = $MAX_SMP -extra_params = -machine gic-version=3 -append 'active' -groups = gic - -[its-introspection] -file = gic.flat -smp = $MAX_SMP -extra_params = -machine gic-version=3 -append 'its-introspection' -groups = its -arch = arm64 - -[its-trigger] -file = gic.flat -smp = $MAX_SMP -extra_params = -machine gic-version=3 -append 'its-trigger' -groups = its -arch = arm64 - -[its-migration] -file = gic.flat -smp = $MAX_SMP -accel = kvm -extra_params = -machine gic-version=3 -append 'its-migration' -groups = its migration -arch = arm64 - -[its-pending-migration] -file = gic.flat -smp = $MAX_SMP -accel = kvm -extra_params = -machine gic-version=3 -append 'its-pending-migration' -groups = its migration -arch = arm64 - -[its-migrate-unmapped-collection] -file = gic.flat -smp = $MAX_SMP -accel = kvm -extra_params = -machine gic-version=3 -append 'its-migrate-unmapped-collection' -groups = its migration -arch = arm64 - -# Test PSCI emulation -[psci] -file = psci.flat -smp = $MAX_SMP -groups = psci - -# Timer tests -[timer] -file = timer.flat -groups = timer -timeout = 10s -arch = arm64 - -# Exit tests -[micro-bench] -file = micro-bench.flat -smp = 2 -groups = nodefault,micro-bench -accel = kvm -arch = arm64 - -# Cache emulation tests -[cache] -file = cache.flat -arch = arm64 -groups = cache diff --git a/configure b/configure deleted file mode 100755 index f9d030fd..00000000 --- a/configure +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/env bash - -srcdir=$(cd "$(dirname "$0")"; pwd) -prefix=/usr/local -cc=gcc -ld=ld -objcopy=objcopy -objdump=objdump -ar=ar -addr2line=addr2line -arch=`uname -m | sed -e 's/i.86/i386/;s/arm.*/arm/;s/ppc64.*/ppc64/'` -host=$arch -cross_prefix= -endian="" -pretty_print_stacks=yes -environ_default=yes -u32_long= -vmm="qemu" -errata_force=0 -erratatxt="$srcdir/errata.txt" - -usage() { - cat <<-EOF - Usage: $0 [options] - - Options include: - --arch=ARCH architecture to compile for ($arch) - --processor=PROCESSOR processor to compile for ($arch) - --vmm=VMM virtual machine monitor to compile for (qemu - or kvmtool, default is qemu) (arm/arm64 only) - --cross-prefix=PREFIX cross compiler prefix - --cc=CC c compiler to use ($cc) - --ld=LD ld linker to use ($ld) - --prefix=PREFIX where to install things ($prefix) - --endian=ENDIAN endianness to compile for (little or big, ppc64 only) - --[enable|disable]-pretty-print-stacks - enable or disable pretty stack printing (enabled by default) - --[enable|disable]-default-environ - enable or disable the generation of a default environ when - no environ is provided by the user (enabled by default) - --erratatxt=FILE specify a file to use instead of errata.txt. Use - '--erratatxt=' to ensure no file is used. -EOF - exit 1 -} - -while [[ "$1" = -* ]]; do - opt="$1"; shift - arg= - if [[ "$opt" = *=* ]]; then - arg="${opt#*=}" - opt="${opt%%=*}" - fi - case "$opt" in - --prefix) - prefix="$arg" - ;; - --arch) - arch="$arg" - ;; - --processor) - processor="$arg" - ;; - --vmm) - vmm="$arg" - ;; - --cross-prefix) - cross_prefix="$arg" - ;; - --endian) - endian="$arg" - ;; - --cc) - cc="$arg" - ;; - --ld) - ld="$arg" - ;; - --enable-pretty-print-stacks) - pretty_print_stacks=yes - ;; - --disable-pretty-print-stacks) - pretty_print_stacks=no - ;; - --enable-default-environ) - environ_default=yes - ;; - --disable-default-environ) - environ_default=no - ;; - --erratatxt) - erratatxt= - [ "$arg" ] && erratatxt=$(eval realpath "$arg") - ;; - --help) - usage - ;; - *) - usage - ;; - esac -done - -if [ "$erratatxt" ] && [ ! -f "$erratatxt" ]; then - echo "erratatxt: $erratatxt does not exist or is not a regular file" - exit 1 -fi - -arch_name=$arch -[ "$arch" = "aarch64" ] && arch="arm64" -[ "$arch_name" = "arm64" ] && arch_name="aarch64" - -[ -z "$processor" ] && processor="$arch" - -if [ "$processor" = "arm64" ]; then - processor="cortex-a57" -elif [ "$processor" = "arm" ]; then - processor="cortex-a15" -fi - -if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then - testdir=x86 -elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then - testdir=arm - if [ "$vmm" = "qemu" ]; then - arm_uart_early_addr=0x09000000 - elif [ "$vmm" = "kvmtool" ]; then - arm_uart_early_addr=0x3f8 - errata_force=1 - else - echo '--vmm must be one of "qemu" or "kvmtool"!' - usage - fi -elif [ "$arch" = "ppc64" ]; then - testdir=powerpc - firmware="$testdir/boot_rom.bin" - if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then - echo "You must provide endianness (big or little)!" - usage - fi -else - testdir=$arch -fi -if [ ! -d "$srcdir/$testdir" ]; then - echo "$testdir does not exist!" - exit 1 -fi -if [ -f "$srcdir/$testdir/run" ]; then - ln -fs "$srcdir/$testdir/run" $testdir-run -fi - -# check if uint32_t needs a long format modifier -cat << EOF > lib-test.c -__UINT32_TYPE__ -EOF -u32_long=$("$cross_prefix$cc" -E lib-test.c | grep -v '^#' | grep -q long && echo yes) -rm -f lib-test.c - -# Are we in a separate build tree? If so, link the Makefile -# and shared stuff so that 'make' and run_tests.sh work. -if test ! -e Makefile; then - echo "linking Makefile..." - ln -s "$srcdir/Makefile" . - - echo "linking tests..." - mkdir -p $testdir - ln -sf "$srcdir/$testdir/run" $testdir/ - ln -sf "$srcdir/$testdir/unittests.cfg" $testdir/ - ln -sf "$srcdir/run_tests.sh" - - echo "linking scripts..." - ln -sf "$srcdir/scripts" -fi - -# link lib/asm for the architecture -rm -f lib/asm -asm="asm-generic" -if [ -d "$srcdir/lib/$arch/asm" ]; then - asm="$srcdir/lib/$arch/asm" -elif [ -d "$srcdir/lib/$testdir/asm" ]; then - asm="$srcdir/lib/$testdir/asm" -fi -mkdir -p lib -ln -sf "$asm" lib/asm - - -# create the config -cat < config.mak -SRCDIR=$srcdir -PREFIX=$prefix -HOST=$host -ARCH=$arch -ARCH_NAME=$arch_name -PROCESSOR=$processor -CC=$cross_prefix$cc -LD=$cross_prefix$ld -OBJCOPY=$cross_prefix$objcopy -OBJDUMP=$cross_prefix$objdump -AR=$cross_prefix$ar -ADDR2LINE=$cross_prefix$addr2line -TEST_DIR=$testdir -FIRMWARE=$firmware -ENDIAN=$endian -PRETTY_PRINT_STACKS=$pretty_print_stacks -ENVIRON_DEFAULT=$environ_default -ERRATATXT=$erratatxt -U32_LONG_FMT=$u32_long -EOF - -cat < lib/config.h -#ifndef CONFIG_H -#define CONFIG_H 1 -/* - * Generated file. DO NOT MODIFY. - * - */ - -EOF -if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then -cat <> lib/config.h - -#define CONFIG_UART_EARLY_BASE ${arm_uart_early_addr} -#define CONFIG_ERRATA_FORCE ${errata_force} - -EOF -fi -echo "#endif" >> lib/config.h diff --git a/errata.txt b/errata.txt deleted file mode 100644 index b66afaa9..00000000 --- a/errata.txt +++ /dev/null @@ -1,9 +0,0 @@ -#---------------:-------------------------------:--------------------------------------------------- -# commit : minimum kernel : summary -# 12 hex digits : version : -#---------------:-------------------------------:--------------------------------------------------- -9e3f7a296940 : 4.9 : arm64: KVM: pmu: Fix AArch32 cycle counter access -7b6b46311a85 : 4.11 : KVM: arm/arm64: Emulate the EL1 phys timer registers -6c7a5dce22b3 : 4.12 : KVM: arm/arm64: fix races in kvm_psci_vcpu_on -8c58be34494b : 5.6 : KVM: arm/arm64: vgic-its: Fix restoration of unmapped collections -#---------------:-------------------------------:--------------------------------------------------- diff --git a/lib/abort.c b/lib/abort.c deleted file mode 100644 index 61f7f924..00000000 --- a/lib/abort.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" - -/* - * When exit(code) is invoked, qemu will exit with ((code << 1) | 1), - * leaving us 128 exit status codes. To avoid confusion with signal - * status, we further limit exit codes to those resulting in qemu - * exiting with a status < 128. We give abort() the highest (127), - * leaving the lower status codes for unit tests. - */ -#define ABORT_EXIT_STATUS 63 /* 127 exit status from qemu */ - -void abort(void) -{ - exit(ABORT_EXIT_STATUS); -} diff --git a/lib/alloc.c b/lib/alloc.c deleted file mode 100644 index 9d89d24b..00000000 --- a/lib/alloc.c +++ /dev/null @@ -1,105 +0,0 @@ -#include "alloc.h" -#include "bitops.h" -#include "asm/page.h" -#include "bitops.h" - -void *malloc(size_t size) -{ - return memalign(sizeof(long), size); -} - -static bool mult_overflow(size_t a, size_t b) -{ -#if BITS_PER_LONG == 32 - /* 32 bit system, easy case: just use u64 */ - return (u64)a * (u64)b >= (1ULL << 32); -#else -#ifdef __SIZEOF_INT128__ - /* if __int128 is available use it (like the u64 case above) */ - unsigned __int128 res = a; - res *= b; - res >>= 64; - return res != 0; -#else - u64 tmp; - - if ((a >> 32) && (b >> 32)) - return true; - if (!(a >> 32) && !(b >> 32)) - return false; - tmp = (u32)a; - tmp *= (u32)b; - tmp >>= 32; - if (a < b) - tmp += a * (b >> 32); - else - tmp += b * (a >> 32); - return tmp >> 32; -#endif /* __SIZEOF_INT128__ */ -#endif /* BITS_PER_LONG == 32 */ -} - -void *calloc(size_t nmemb, size_t size) -{ - void *ptr; - - assert(!mult_overflow(nmemb, size)); - ptr = malloc(nmemb * size); - if (ptr) - memset(ptr, 0, nmemb * size); - return ptr; -} - -#define METADATA_EXTRA (2 * sizeof(uintptr_t)) -#define OFS_SLACK (-2 * sizeof(uintptr_t)) -#define OFS_SIZE (-sizeof(uintptr_t)) - -static inline void *block_begin(void *mem) -{ - uintptr_t slack = *(uintptr_t *)(mem + OFS_SLACK); - return mem - slack; -} - -static inline uintptr_t block_size(void *mem) -{ - return *(uintptr_t *)(mem + OFS_SIZE); -} - -void free(void *ptr) -{ - if (!alloc_ops->free) - return; - - void *base = block_begin(ptr); - uintptr_t sz = block_size(ptr); - - alloc_ops->free(base, sz); -} - -void *memalign(size_t alignment, size_t size) -{ - void *p; - uintptr_t blkalign; - uintptr_t mem; - - if (!size) - return NULL; - - assert(alignment >= sizeof(void *) && is_power_of_2(alignment)); - assert(alloc_ops && alloc_ops->memalign); - - size += alignment - 1; - blkalign = MAX(alignment, alloc_ops->align_min); - size = ALIGN(size + METADATA_EXTRA, alloc_ops->align_min); - p = alloc_ops->memalign(blkalign, size); - assert(p); - - /* Leave room for metadata before aligning the result. */ - mem = (uintptr_t)p + METADATA_EXTRA; - mem = ALIGN(mem, alignment); - - /* Write the metadata */ - *(uintptr_t *)(mem + OFS_SLACK) = mem - (uintptr_t)p; - *(uintptr_t *)(mem + OFS_SIZE) = size; - return (void *)mem; -} diff --git a/lib/alloc.h b/lib/alloc.h deleted file mode 100644 index c44d4596..00000000 --- a/lib/alloc.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef _ALLOC_H_ -#define _ALLOC_H_ -/* - * alloc supplies three ingredients to the test framework that are all - * related to the support of dynamic memory allocation. - * - * The first is a set of alloc function wrappers for malloc and its - * friends. Using wrappers allows test code and common code to use the - * same interface for memory allocation at all stages, even though the - * implementations may change with the stage, e.g. pre/post paging. - * - * The second is a set of implementations for the alloc function - * interfaces. These implementations are named early_*, as they can be - * used almost immediately by the test framework. - * - * The third is a very simple physical memory allocator, which the - * early_* alloc functions build on. - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" - -struct alloc_ops { - void *(*memalign)(size_t alignment, size_t size); - void (*free)(void *ptr, size_t size); - size_t align_min; -}; - -extern struct alloc_ops *alloc_ops; - -void *malloc(size_t size); -void *calloc(size_t nmemb, size_t size); -void free(void *ptr); -void *memalign(size_t alignment, size_t size); - -#endif /* _ALLOC_H_ */ diff --git a/lib/alloc_page.c b/lib/alloc_page.c deleted file mode 100644 index fa3c5270..00000000 --- a/lib/alloc_page.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * This work is licensed under the terms of the GNU LGPL, version 2. - * - * This is a simple allocator that provides contiguous physical addresses - * with page granularity. - */ -#include "libcflat.h" -#include "alloc.h" -#include "alloc_phys.h" -#include "alloc_page.h" -#include "bitops.h" -#include -#include -#include - -static struct spinlock lock; -static void *freelist = 0; - -bool page_alloc_initialized(void) -{ - return freelist != 0; -} - -void free_pages(void *mem, size_t size) -{ - void *old_freelist; - void *end; - - assert_msg((unsigned long) mem % PAGE_SIZE == 0, - "mem not page aligned: %p", mem); - - assert_msg(size % PAGE_SIZE == 0, "size not page aligned: %#lx", size); - - assert_msg(size == 0 || (uintptr_t)mem == -size || - (uintptr_t)mem + size > (uintptr_t)mem, - "mem + size overflow: %p + %#lx", mem, size); - - if (size == 0) { - freelist = NULL; - return; - } - - spin_lock(&lock); - old_freelist = freelist; - freelist = mem; - end = mem + size; - while (mem + PAGE_SIZE != end) { - *(void **)mem = (mem + PAGE_SIZE); - mem += PAGE_SIZE; - } - - *(void **)mem = old_freelist; - spin_unlock(&lock); -} - -void free_pages_by_order(void *mem, unsigned int order) -{ - free_pages(mem, 1ul << (order + PAGE_SHIFT)); -} - -void *alloc_page() -{ - void *p; - - if (!freelist) - return 0; - - spin_lock(&lock); - p = freelist; - freelist = *(void **)freelist; - spin_unlock(&lock); - - if (p) - memset(p, 0, PAGE_SIZE); - return p; -} - -/* - * Allocates (1 << order) physically contiguous and naturally aligned pages. - * Returns NULL if there's no memory left. - */ -void *alloc_pages(unsigned int order) -{ - /* Generic list traversal. */ - void *prev; - void *curr = NULL; - void *next = freelist; - - /* Looking for a run of length (1 << order). */ - unsigned long run = 0; - const unsigned long n = 1ul << order; - const unsigned long align_mask = (n << PAGE_SHIFT) - 1; - void *run_start = NULL; - void *run_prev = NULL; - unsigned long run_next_pa = 0; - unsigned long pa; - - assert(order < sizeof(unsigned long) * 8); - - spin_lock(&lock); - for (;;) { - prev = curr; - curr = next; - - if (!curr) { - run_start = NULL; - break; - } - - next = *((void **) curr); - pa = virt_to_phys(curr); - - if (run == 0) { - if (!(pa & align_mask)) { - run_start = curr; - run_prev = prev; - run_next_pa = pa + PAGE_SIZE; - run = 1; - } - } else if (pa == run_next_pa) { - run_next_pa += PAGE_SIZE; - run += 1; - } else { - run = 0; - } - - if (run == n) { - if (run_prev) - *((void **) run_prev) = next; - else - freelist = next; - break; - } - } - spin_unlock(&lock); - if (run_start) - memset(run_start, 0, n * PAGE_SIZE); - return run_start; -} - - -void free_page(void *page) -{ - spin_lock(&lock); - *(void **)page = freelist; - freelist = page; - spin_unlock(&lock); -} - -static void *page_memalign(size_t alignment, size_t size) -{ - unsigned long n = ALIGN(size, PAGE_SIZE) >> PAGE_SHIFT; - unsigned int order; - - if (!size) - return NULL; - - order = get_order(n); - - return alloc_pages(order); -} - -static void page_free(void *mem, size_t size) -{ - free_pages(mem, size); -} - -static struct alloc_ops page_alloc_ops = { - .memalign = page_memalign, - .free = page_free, - .align_min = PAGE_SIZE, -}; - -void page_alloc_ops_enable(void) -{ - alloc_ops = &page_alloc_ops; -} diff --git a/lib/alloc_page.h b/lib/alloc_page.h deleted file mode 100644 index 88540d1d..00000000 --- a/lib/alloc_page.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * This work is licensed under the terms of the GNU LGPL, version 2. - * - * This is a simple allocator that provides contiguous physical addresses - * with byte granularity. - */ - -#ifndef ALLOC_PAGE_H -#define ALLOC_PAGE_H 1 - -bool page_alloc_initialized(void); -void page_alloc_ops_enable(void); -void *alloc_page(void); -void *alloc_pages(unsigned int order); -void free_page(void *page); -void free_pages(void *mem, size_t size); -void free_pages_by_order(void *mem, unsigned int order); - -#endif diff --git a/lib/alloc_phys.c b/lib/alloc_phys.c deleted file mode 100644 index 72e20f7d..00000000 --- a/lib/alloc_phys.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - * - * This is a simple allocator that provides contiguous physical addresses - * with byte granularity. - */ -#include "alloc.h" -#include "asm/spinlock.h" -#include "asm/io.h" -#include "alloc_phys.h" - -#define PHYS_ALLOC_NR_REGIONS 256 - -#define DEFAULT_MINIMUM_ALIGNMENT 32 - -struct phys_alloc_region { - phys_addr_t base; - phys_addr_t size; -}; - -static struct phys_alloc_region regions[PHYS_ALLOC_NR_REGIONS]; -static int nr_regions; - -static struct spinlock lock; -static phys_addr_t base, top; - -static void *early_memalign(size_t alignment, size_t size); -static struct alloc_ops early_alloc_ops = { - .memalign = early_memalign, - .align_min = DEFAULT_MINIMUM_ALIGNMENT -}; - -struct alloc_ops *alloc_ops = &early_alloc_ops; - -void phys_alloc_show(void) -{ - int i; - - spin_lock(&lock); - printf("phys_alloc minimum alignment: %#" PRIx64 "\n", - (u64)early_alloc_ops.align_min); - for (i = 0; i < nr_regions; ++i) - printf("%016" PRIx64 "-%016" PRIx64 " [%s]\n", - (u64)regions[i].base, - (u64)(regions[i].base + regions[i].size - 1), - "USED"); - printf("%016" PRIx64 "-%016" PRIx64 " [%s]\n", - (u64)base, (u64)(top - 1), "FREE"); - spin_unlock(&lock); -} - -void phys_alloc_init(phys_addr_t base_addr, phys_addr_t size) -{ - spin_lock(&lock); - base = base_addr; - top = base + size; - nr_regions = 0; - spin_unlock(&lock); -} - -void phys_alloc_set_minimum_alignment(phys_addr_t align) -{ - assert(align && !(align & (align - 1))); - spin_lock(&lock); - early_alloc_ops.align_min = align; - spin_unlock(&lock); -} - -static phys_addr_t phys_alloc_aligned_safe(phys_addr_t size, - phys_addr_t align, bool safe) -{ - static bool warned = false; - phys_addr_t addr, size_orig = size; - u64 top_safe; - - spin_lock(&lock); - - top_safe = top; - - if (safe && sizeof(long) == 4) - top_safe = MIN(top_safe, 1ULL << 32); - - assert(base < top_safe); - - addr = ALIGN(base, align); - size += addr - base; - - if ((top_safe - base) < size) { - printf("phys_alloc: requested=%#" PRIx64 - " (align=%#" PRIx64 "), " - "need=%#" PRIx64 ", but free=%#" PRIx64 ". " - "top=%#" PRIx64 ", top_safe=%#" PRIx64 "\n", - (u64)size_orig, (u64)align, (u64)size, top_safe - base, - (u64)top, top_safe); - spin_unlock(&lock); - return INVALID_PHYS_ADDR; - } - - base += size; - - if (nr_regions < PHYS_ALLOC_NR_REGIONS) { - regions[nr_regions].base = addr; - regions[nr_regions].size = size_orig; - ++nr_regions; - } else if (!warned) { - printf("WARNING: phys_alloc: No free log entries, " - "can no longer log allocations...\n"); - warned = true; - } - - spin_unlock(&lock); - - return addr; -} - -void phys_alloc_get_unused(phys_addr_t *p_base, phys_addr_t *p_top) -{ - *p_base = base; - *p_top = top; - if (base == top) - return; - spin_lock(&lock); - regions[nr_regions].base = base; - regions[nr_regions].size = top - base; - ++nr_regions; - base = top; - spin_unlock(&lock); -} - -static void *early_memalign(size_t alignment, size_t size) -{ - phys_addr_t addr; - - assert(alignment && !(alignment & (alignment - 1))); - - addr = phys_alloc_aligned_safe(size, alignment, true); - if (addr == INVALID_PHYS_ADDR) - return NULL; - - return phys_to_virt(addr); -} diff --git a/lib/alloc_phys.h b/lib/alloc_phys.h deleted file mode 100644 index 611aa70d..00000000 --- a/lib/alloc_phys.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _ALLOC_PHYS_H_ -#define _ALLOC_PHYS_H_ -/* - * phys_alloc is a very simple allocator which allows physical memory - * to be partitioned into regions until all memory is allocated. - * - * Note: This is such a simple allocator that there is no way to free - * a region. For more complicated memory management a single region - * can be allocated, but then have its memory managed by a more - * sophisticated allocator, e.g. a page allocator. - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" - -#define DEFAULT_MINIMUM_ALIGNMENT 32 - -/* - * phys_alloc_init creates the initial free memory region of size @size - * at @base. The minimum alignment is set to DEFAULT_MINIMUM_ALIGNMENT. - */ -extern void phys_alloc_init(phys_addr_t base, phys_addr_t size); - -/* - * phys_alloc_set_minimum_alignment sets the minimum alignment to - * @align. - */ -extern void phys_alloc_set_minimum_alignment(phys_addr_t align); - -/* - * phys_alloc_show outputs all currently allocated regions with the - * following format - * - [] - */ -extern void phys_alloc_show(void); - -/* - * phys_alloc_get_unused allocates all remaining memory from the region - * passed to phys_alloc_init, returning the newly allocated memory's base - * and top addresses. phys_alloc_get_unused will still return base and top - * when no free memory is remaining, but base will equal top. - */ -extern void phys_alloc_get_unused(phys_addr_t *p_base, phys_addr_t *p_top); - -/* - * Search for memory that can only be used when the MMU is on, and reinitialize - * the physical memory allocator using it. - */ -extern void find_highmem(void); - -#endif /* _ALLOC_PHYS_H_ */ diff --git a/lib/argv.c b/lib/argv.c deleted file mode 100644 index 0312d740..00000000 --- a/lib/argv.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Set up arguments for main() and prepare environment variables - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -#include "libcflat.h" -#include "argv.h" -#include "auxinfo.h" - -int __argc; -const char *__args; -char *__argv[100]; -char *__environ[200]; - -char **environ = __environ; - -static char args_copy[1000]; -static char *copy_ptr = args_copy; - -#define isblank(c) ((c) == ' ' || (c) == '\t') -#define isalpha(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z') || (c) == '_') -#define isalnum(c) (isalpha(c) || ((c) >= '0' && (c) <= '9')) - -static const char *skip_blanks(const char *p) -{ - while (isblank(*p)) - ++p; - return p; -} - -void __setup_args(void) -{ - const char *args = __args; - char **argv = __argv + __argc; - - while (*(args = skip_blanks(args)) != '\0') { - *argv++ = copy_ptr; - while (*args != '\0' && !isblank(*args)) - *copy_ptr++ = *args++; - *copy_ptr++ = '\0'; - } - __argc = argv - __argv; -} - -static void setup_args(const char *args) -{ - if (!args) - return; - - __args = args; - __setup_args(); -} - -void add_setup_arg(const char *arg) -{ - __argv[__argc] = copy_ptr; - strcpy(__argv[__argc], arg); - copy_ptr += strlen(arg) + 1; - ++__argc; -} - -void setup_args_progname(const char *args) -{ - add_setup_arg(auxinfo.progname); - setup_args(args); -} - -static char *env_eol(char *env) -{ - while (*env && *env != '\n') - ++env; - return env; -} - -static char *env_invalid_eol(char *env) -{ - char *eol = env_eol(env); - char eol_old = *eol; - - *eol = '\0'; - printf("Invalid environment variable: %s\n", env); - *eol = eol_old; - return eol; -} - -static char *env_next(char *env) -{ - char *p; - - if (!*env) - return env; - - if (isalpha(*env)) { - bool invalid = false; - - p = env + 1; - while (*p && *p != '=' && *p != '\n') { - if (!isalnum(*p)) - invalid = true; - ++p; - } - - if (*p != '=') - invalid = true; - - if (invalid) { - env = env_invalid_eol(env); - return *env ? env_next(env + 1) : env; - } - return env; - } - - p = env; - while (isblank(*p)) - ++p; - - if (*p == '\n') - return env_next(p + 1); - - if (*p == '#') - env = env_eol(env); - else - env = env_invalid_eol(env); - - return *env ? env_next(env + 1) : env; -} - -void setup_env(char *env, int size) -{ - char *eof = env + size, *p = env; - bool newline = false; - int i = 0; - - while (*p) - ++p; - if (p == eof) - newline = true; - - while (env < eof) { - if (newline) - env = env_next(env); - if (!*env || env >= eof) - break; - __environ[i++] = env; - while (env < eof && *env && !(newline && *env == '\n')) - ++env; - *env++ = '\0'; - } -} diff --git a/lib/argv.h b/lib/argv.h deleted file mode 100644 index e5fcf848..00000000 --- a/lib/argv.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Set up arguments for main() and prepare environment variables - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -extern void __setup_args(void); -extern void setup_args_progname(const char *args); -extern void setup_env(char *env, int size); -extern void add_setup_arg(const char *arg); diff --git a/lib/arm/.gitignore b/lib/arm/.gitignore deleted file mode 100644 index 84872bf1..00000000 --- a/lib/arm/.gitignore +++ /dev/null @@ -1 +0,0 @@ -asm-offsets.[hs] diff --git a/lib/arm/asm-offsets.c b/lib/arm/asm-offsets.c deleted file mode 100644 index 6439e1c4..00000000 --- a/lib/arm/asm-offsets.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Adapted from arch/arm/kernel/asm-offsets.c - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include -#include -#include - -int main(void) -{ - OFFSET(S_R0, pt_regs, ARM_r0); - OFFSET(S_R1, pt_regs, ARM_r1); - OFFSET(S_R2, pt_regs, ARM_r2); - OFFSET(S_R3, pt_regs, ARM_r3); - OFFSET(S_R4, pt_regs, ARM_r4); - OFFSET(S_R5, pt_regs, ARM_r5); - OFFSET(S_R6, pt_regs, ARM_r6); - OFFSET(S_R7, pt_regs, ARM_r7); - OFFSET(S_R8, pt_regs, ARM_r8); - OFFSET(S_R9, pt_regs, ARM_r9); - OFFSET(S_R10, pt_regs, ARM_r10); - OFFSET(S_FP, pt_regs, ARM_fp); - OFFSET(S_IP, pt_regs, ARM_ip); - OFFSET(S_SP, pt_regs, ARM_sp); - OFFSET(S_LR, pt_regs, ARM_lr); - OFFSET(S_PC, pt_regs, ARM_pc); - OFFSET(S_PSR, pt_regs, ARM_cpsr); - OFFSET(S_OLD_R0, pt_regs, ARM_ORIG_r0); - DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); - return 0; -} diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h deleted file mode 100644 index 45b60968..00000000 --- a/lib/arm/asm/arch_gicv3.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * All ripped off from arch/arm/include/asm/arch_gicv3.h - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#ifndef _ASMARM_ARCH_GICV3_H_ -#define _ASMARM_ARCH_GICV3_H_ - -#ifndef __ASSEMBLY__ -#include -#include -#include -#include - -#define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0) -#define ICC_SGI1R __ACCESS_CP15_64(0, c12) -#define ICC_IAR1 __ACCESS_CP15(c12, 0, c12, 0) -#define ICC_EOIR1 __ACCESS_CP15(c12, 0, c12, 1) -#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) - -static inline void gicv3_write_pmr(u32 val) -{ - write_sysreg(val, ICC_PMR); -} - -static inline void gicv3_write_sgi1r(u64 val) -{ - write_sysreg(val, ICC_SGI1R); -} - -static inline u32 gicv3_read_iar(void) -{ - u32 irqstat = read_sysreg(ICC_IAR1); - dsb(sy); - return irqstat; -} - -static inline void gicv3_write_eoir(u32 irq) -{ - write_sysreg(irq, ICC_EOIR1); - isb(); -} - -static inline void gicv3_write_grpen1(u32 val) -{ - write_sysreg(val, ICC_IGRPEN1); - isb(); -} - -/* - * We may access GICR_TYPER and GITS_TYPER by reading both the TYPER - * offset and the following offset (+ 4) and then combining them to - * form a 64-bit address. - */ -static inline u64 gicv3_read_typer(const volatile void __iomem *addr) -{ - u64 val = readl(addr); - val |= (u64)readl(addr + 4) << 32; - return val; -} - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMARM_ARCH_GICV3_H_ */ diff --git a/lib/arm/asm/asm-offsets.h b/lib/arm/asm/asm-offsets.h deleted file mode 100644 index d370ee36..00000000 --- a/lib/arm/asm/asm-offsets.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/lib/arm/asm/barrier.h b/lib/arm/asm/barrier.h deleted file mode 100644 index 7f868314..00000000 --- a/lib/arm/asm/barrier.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _ASMARM_BARRIER_H_ -#define _ASMARM_BARRIER_H_ -/* - * Adapted from arch/arm/include/asm/barrier.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#define sev() asm volatile("sev" : : : "memory") -#define wfe() asm volatile("wfe" : : : "memory") -#define wfi() asm volatile("wfi" : : : "memory") -#define yield() asm volatile("yield" : : : "memory") -#define cpu_relax() yield() - -#define isb(option) __asm__ __volatile__ ("isb " #option : : : "memory") -#define dsb(option) __asm__ __volatile__ ("dsb " #option : : : "memory") -#define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory") - -#define mb() dsb() -#define rmb() dsb() -#define wmb() dsb(st) -#define smp_mb() dmb(ish) -#define smp_rmb() smp_mb() -#define smp_wmb() dmb(ishst) - -#endif /* _ASMARM_BARRIER_H_ */ diff --git a/lib/arm/asm/bitops.h b/lib/arm/asm/bitops.h deleted file mode 100644 index 79cf4ec6..00000000 --- a/lib/arm/asm/bitops.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _ASMARM_BITOPS_H_ -#define _ASMARM_BITOPS_H_ -/* - * Adapted from - * arch/arm/lib/bitops.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#ifndef _BITOPS_H_ -#error only can be included directly -#endif - -#define BITS_PER_LONG 32 - -#define HAVE_BUILTIN_FLS 1 - -#define ATOMIC_BITOP(insn, mask, word) \ -({ \ - unsigned long tmp1, tmp2; \ - asm volatile( \ - "1: ldrex %0, [%2]\n" \ - insn" %0, %0, %3\n" \ - " strex %1, %0, [%2]\n" \ - " cmp %1, #0\n" \ - " bne 1b\n" \ - : "=&r" (tmp1), "=&r" (tmp2) \ - : "r" (word), "r" (mask) \ - : "cc"); \ -}) - -#define ATOMIC_TESTOP(insn, mask, word, old) \ -({ \ - unsigned long tmp1, tmp2; \ - asm volatile( \ - "1: ldrex %0, [%3]\n" \ - " and %1, %0, %4\n" \ - insn" %0, %0, %4\n" \ - " strex %2, %0, [%3]\n" \ - " cmp %2, #0\n" \ - " bne 1b\n" \ - : "=&r" (tmp1), "=&r" (old), "=&r" (tmp2) \ - : "r" (word), "r" (mask) \ - : "cc"); \ -}) - -extern void set_bit(int nr, volatile unsigned long *addr); -extern void clear_bit(int nr, volatile unsigned long *addr); -extern int test_bit(int nr, const volatile unsigned long *addr); -extern int test_and_set_bit(int nr, volatile unsigned long *addr); -extern int test_and_clear_bit(int nr, volatile unsigned long *addr); - -#endif /* _ASMARM_BITOPS_H_ */ diff --git a/lib/arm/asm/cpumask.h b/lib/arm/asm/cpumask.h deleted file mode 100644 index 6683bb6e..00000000 --- a/lib/arm/asm/cpumask.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef _ASMARM_CPUMASK_H_ -#define _ASMARM_CPUMASK_H_ -/* - * Simple cpumask implementation - * - * Copyright (C) 2015, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include - -#define CPUMASK_NR_LONGS ((NR_CPUS + BITS_PER_LONG - 1) / BITS_PER_LONG) - -typedef struct cpumask { - unsigned long bits[CPUMASK_NR_LONGS]; -} cpumask_t; - -#define cpumask_bits(maskp) ((maskp)->bits) - -static inline void cpumask_set_cpu(int cpu, cpumask_t *mask) -{ - set_bit(cpu, cpumask_bits(mask)); -} - -static inline void cpumask_clear_cpu(int cpu, cpumask_t *mask) -{ - clear_bit(cpu, cpumask_bits(mask)); -} - -static inline int cpumask_test_cpu(int cpu, const cpumask_t *mask) -{ - return test_bit(cpu, cpumask_bits(mask)); -} - -static inline int cpumask_test_and_set_cpu(int cpu, cpumask_t *mask) -{ - return test_and_set_bit(cpu, cpumask_bits(mask)); -} - -static inline int cpumask_test_and_clear_cpu(int cpu, cpumask_t *mask) -{ - return test_and_clear_bit(cpu, cpumask_bits(mask)); -} - -static inline void cpumask_setall(cpumask_t *mask) -{ - int i; - for (i = 0; i < nr_cpus; i += BITS_PER_LONG) - cpumask_bits(mask)[BIT_WORD(i)] = ~0UL; - i -= BITS_PER_LONG; - if ((nr_cpus - i) < BITS_PER_LONG) - cpumask_bits(mask)[BIT_WORD(i)] = BIT_MASK(nr_cpus - i) - 1; -} - -static inline void cpumask_clear(cpumask_t *mask) -{ - int i; - for (i = 0; i < nr_cpus; i += BITS_PER_LONG) - cpumask_bits(mask)[BIT_WORD(i)] = 0UL; -} - -static inline bool cpumask_empty(const cpumask_t *mask) -{ - int i; - for (i = 0; i < nr_cpus; i += BITS_PER_LONG) { - if (i < NR_CPUS) { /* silence crazy compiler warning */ - if (cpumask_bits(mask)[BIT_WORD(i)] != 0UL) - return false; - } - } - return true; -} - -static inline bool cpumask_full(const cpumask_t *mask) -{ - int i; - for (i = 0; i < nr_cpus; i += BITS_PER_LONG) { - if (cpumask_bits(mask)[BIT_WORD(i)] != ~0UL) { - if ((nr_cpus - i) >= BITS_PER_LONG) - return false; - if (cpumask_bits(mask)[BIT_WORD(i)] - != BIT_MASK(nr_cpus - i) - 1) - return false; - } - } - return true; -} - -static inline int cpumask_weight(const cpumask_t *mask) -{ - int w = 0, i; - - for (i = 0; i < nr_cpus; ++i) - if (cpumask_test_cpu(i, mask)) - ++w; - return w; -} - -static inline void cpumask_copy(cpumask_t *dst, const cpumask_t *src) -{ - memcpy(cpumask_bits(dst), cpumask_bits(src), - CPUMASK_NR_LONGS * sizeof(long)); -} - -static inline int cpumask_next(int cpu, const cpumask_t *mask) -{ - while (cpu < nr_cpus && !cpumask_test_cpu(++cpu, mask)) - ; - return cpu; -} - -#define for_each_cpu(cpu, mask) \ - for ((cpu) = cpumask_next(-1, mask); \ - (cpu) < nr_cpus; \ - (cpu) = cpumask_next(cpu, mask)) - -#endif /* _ASMARM_CPUMASK_H_ */ diff --git a/lib/arm/asm/delay.h b/lib/arm/asm/delay.h deleted file mode 100644 index 2436b28c..00000000 --- a/lib/arm/asm/delay.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _ASMARM_DELAY_H_ -#define _ASMARM_DELAY_H_ -/* - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include - -extern void delay(u64 cycles); -extern void udelay(unsigned long usecs); -extern void mdelay(unsigned long msecs); - -#endif /* _ASMARM_DELAY_H_ */ diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h deleted file mode 100644 index 1fcfd43c..00000000 --- a/lib/arm/asm/gic-v2.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * All GIC* defines are lifted from include/linux/irqchip/arm-gic.h - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#ifndef _ASMARM_GIC_V2_H_ -#define _ASMARM_GIC_V2_H_ - -#ifndef _ASMARM_GIC_H_ -#error Do not directly include . Include -#endif - -#define GICD_ENABLE 0x1 - -#define GICC_ENABLE 0x1 -#define GICC_IAR_INT_ID_MASK 0x3ff - -#ifndef __ASSEMBLY__ -#include - -struct gicv2_data { - void *dist_base; - void *cpu_base; - unsigned int irq_nr; -}; -extern struct gicv2_data gicv2_data; - -#define gicv2_dist_base() (gicv2_data.dist_base) -#define gicv2_cpu_base() (gicv2_data.cpu_base) - -extern int gicv2_init(void); -extern void gicv2_enable_defaults(void); -extern u32 gicv2_read_iar(void); -extern u32 gicv2_iar_irqnr(u32 iar); -extern void gicv2_write_eoir(u32 irqstat); -extern void gicv2_ipi_send_single(int irq, int cpu); -extern void gicv2_ipi_send_mask(int irq, const cpumask_t *dest); - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMARM_GIC_V2_H_ */ diff --git a/lib/arm/asm/gic-v3-its.h b/lib/arm/asm/gic-v3-its.h deleted file mode 100644 index efd8f675..00000000 --- a/lib/arm/asm/gic-v3-its.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * ITS 32-bit stubs - * - * Copyright (C) 2020, Red Hat Inc, Eric Auger - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#ifndef _ASMARM_GIC_V3_ITS_H_ -#define _ASMARM_GIC_V3_ITS_H_ - -#ifndef _ASMARM_GIC_H_ -#error Do not directly include . Include -#endif - -#include - -/* dummy its_data struct to allow gic_get_dt_bases() call */ -struct its_data { - void *base; -}; - -static inline void its_init(void) -{ - assert_msg(false, "not supported on 32-bit"); -} - -#endif /* _ASMARM_GIC_V3_ITS_H_ */ diff --git a/lib/arm/asm/gic-v3.h b/lib/arm/asm/gic-v3.h deleted file mode 100644 index cb729226..00000000 --- a/lib/arm/asm/gic-v3.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * All GIC* defines are lifted from include/linux/irqchip/arm-gic-v3.h - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#ifndef _ASMARM_GIC_V3_H_ -#define _ASMARM_GIC_V3_H_ - -#ifndef _ASMARM_GIC_H_ -#error Do not directly include . Include -#endif - -/* - * Distributor registers - * - * We expect to be run in Non-secure mode, thus we define the - * group1 enable bits with respect to that view. - */ -#define GICD_CTLR 0x0000 -#define GICD_CTLR_RWP (1U << 31) -#define GICD_CTLR_ARE_NS (1U << 4) -#define GICD_CTLR_ENABLE_G1A (1U << 1) -#define GICD_CTLR_ENABLE_G1 (1U << 0) - -/* Re-Distributor registers, offsets from RD_base */ -#define GICR_TYPER 0x0008 - -#define GICR_TYPER_LAST (1U << 4) - -/* Re-Distributor registers, offsets from SGI_base */ -#define GICR_IGROUPR0 GICD_IGROUPR -#define GICR_ISENABLER0 GICD_ISENABLER -#define GICR_ICENABLER0 GICD_ICENABLER -#define GICR_ISPENDR0 GICD_ISPENDR -#define GICR_ICPENDR0 GICD_ICPENDR -#define GICR_ISACTIVER0 GICD_ISACTIVER -#define GICR_ICACTIVER0 GICD_ICACTIVER -#define GICR_IPRIORITYR0 GICD_IPRIORITYR - -#define GICR_PROPBASER 0x0070 -#define GICR_PENDBASER 0x0078 -#define GICR_CTLR GICD_CTLR -#define GICR_CTLR_ENABLE_LPIS (1UL << 0) - -#define ICC_SGI1R_AFFINITY_1_SHIFT 16 -#define ICC_SGI1R_AFFINITY_2_SHIFT 32 -#define ICC_SGI1R_AFFINITY_3_SHIFT 48 -#define MPIDR_TO_SGI_AFFINITY(cluster_id, level) \ - (MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT) - -#define GICR_PENDBASER_PTZ BIT_ULL(62) - -#define LPI_PROP_GROUP1 (1 << 1) -#define LPI_PROP_ENABLED (1 << 0) -#define LPI_PROP_DEFAULT_PRIO 0xa0 -#define LPI_PROP_DEFAULT (LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1 | LPI_PROP_ENABLED) - -#define LPI_ID_BASE 8192 -#define LPI(lpi) ((lpi) + LPI_ID_BASE) -#define LPI_OFFSET(intid) ((intid) - LPI_ID_BASE) - -#include - -#ifndef __ASSEMBLY__ -#include -#include -#include -#include -#include -#include - -#define GICV3_NR_REDISTS 8 - -struct gicv3_data { - void *dist_base; - void *redist_bases[GICV3_NR_REDISTS]; - void *redist_base[NR_CPUS]; - u8 *lpi_prop; - void *lpi_pend[NR_CPUS]; - unsigned int irq_nr; -}; -extern struct gicv3_data gicv3_data; - -#define gicv3_dist_base() (gicv3_data.dist_base) -#define gicv3_redist_base() (gicv3_data.redist_base[smp_processor_id()]) -#define gicv3_sgi_base() (gicv3_data.redist_base[smp_processor_id()] + SZ_64K) - -extern int gicv3_init(void); -extern void gicv3_enable_defaults(void); -extern u32 gicv3_read_iar(void); -extern u32 gicv3_iar_irqnr(u32 iar); -extern void gicv3_write_eoir(u32 irqstat); -extern void gicv3_ipi_send_single(int irq, int cpu); -extern void gicv3_ipi_send_mask(int irq, const cpumask_t *dest); -extern void gicv3_set_redist_base(size_t stride); -extern void gicv3_lpi_set_clr_pending(int rdist, int n, bool set); -extern void gicv3_lpi_alloc_tables(void); -extern void gicv3_lpi_rdist_enable(int redist); -extern void gicv3_lpi_rdist_disable(int redist); - -static inline void gicv3_do_wait_for_rwp(void *base) -{ - int count = 100000; /* 1s */ - - while (readl(base + GICD_CTLR) & GICD_CTLR_RWP) { - if (!--count) { - printf("GICv3: RWP timeout!\n"); - abort(); - } - cpu_relax(); - udelay(10); - }; -} - -static inline void gicv3_dist_wait_for_rwp(void) -{ - gicv3_do_wait_for_rwp(gicv3_dist_base()); -} - -static inline void gicv3_redist_wait_for_uwp(void) -{ - /* - * We can build on gic_do_wait_for_rwp, which uses GICD_ registers - * because GICD_CTLR == GICR_CTLR and GICD_CTLR_RWP == GICR_CTLR_UWP - */ - gicv3_do_wait_for_rwp(gicv3_redist_base()); -} - -static inline u32 mpidr_compress(u64 mpidr) -{ - u64 compressed = mpidr & MPIDR_HWID_BITMASK; - - compressed = (((compressed >> 32) & 0xff) << 24) | compressed; - return compressed; -} - -static inline u64 mpidr_uncompress(u32 compressed) -{ - u64 mpidr = ((u64)compressed >> 24) << 32; - - mpidr |= compressed & MPIDR_HWID_BITMASK; - return mpidr; -} - -#define gicv3_lpi_set_config(intid, value) ({ \ - gicv3_data.lpi_prop[LPI_OFFSET(intid)] = value; \ -}) - -#define gicv3_lpi_get_config(intid) (gicv3_data.lpi_prop[LPI_OFFSET(intid)]) - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMARM_GIC_V3_H_ */ diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h deleted file mode 100644 index 38e79b2a..00000000 --- a/lib/arm/asm/gic.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#ifndef _ASMARM_GIC_H_ -#define _ASMARM_GIC_H_ - -#define GIC_NR_PRIVATE_IRQS 32 -#define GIC_FIRST_SPI GIC_NR_PRIVATE_IRQS - -/* Distributor registers */ -#define GICD_CTLR 0x0000 -#define GICD_TYPER 0x0004 -#define GICD_IIDR 0x0008 -#define GICD_IGROUPR 0x0080 -#define GICD_ISENABLER 0x0100 -#define GICD_ICENABLER 0x0180 -#define GICD_ISPENDR 0x0200 -#define GICD_ICPENDR 0x0280 -#define GICD_ISACTIVER 0x0300 -#define GICD_ICACTIVER 0x0380 -#define GICD_IPRIORITYR 0x0400 -#define GICD_ITARGETSR 0x0800 -#define GICD_SGIR 0x0f00 -#define GICD_ICPIDR2 0x0fe8 - -#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32) -#define GICD_INT_EN_SET_SGI 0x0000ffff -#define GICD_INT_DEF_PRI_X4 0xa0a0a0a0 - -/* CPU interface registers */ -#define GICC_CTLR 0x0000 -#define GICC_PMR 0x0004 -#define GICC_IAR 0x000c -#define GICC_EOIR 0x0010 - -#define GICC_INT_PRI_THRESHOLD 0xf0 -#define GICC_INT_SPURIOUS 0x3ff - -#include -#include -#include - -#define PPI(irq) ((irq) + 16) -#define SPI(irq) ((irq) + GIC_FIRST_SPI) - -#ifndef __ASSEMBLY__ -#include - -enum gic_irq_state { - GIC_IRQ_STATE_INACTIVE, - GIC_IRQ_STATE_PENDING, - GIC_IRQ_STATE_ACTIVE, - GIC_IRQ_STATE_ACTIVE_PENDING, -}; - -/* - * gic_init will try to find all known gics, and then - * initialize the gic data for the one found. - * returns - * 0 : no gic was found - * > 0 : the gic version of the gic found - */ -extern int gic_init(void); - -/* - * gic_enable_defaults enables the gic with basic but useful - * settings. gic_enable_defaults will call gic_init if it has - * not yet been invoked. - */ -extern void gic_enable_defaults(void); - -/* - * After enabling the gic with gic_enable_defaults the functions - * below will work with any supported gic version. - */ -extern int gic_version(void); -extern u32 gic_read_iar(void); -extern u32 gic_iar_irqnr(u32 iar); -extern void gic_write_eoir(u32 irqstat); -extern void gic_ipi_send_single(int irq, int cpu); -extern void gic_ipi_send_mask(int irq, const cpumask_t *dest); -extern enum gic_irq_state gic_irq_state(int irq); - -void gic_irq_set_clr_enable(int irq, bool enable); -#define gic_enable_irq(irq) gic_irq_set_clr_enable(irq, true) -#define gic_disable_irq(irq) gic_irq_set_clr_enable(irq, false) - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMARM_GIC_H_ */ diff --git a/lib/arm/asm/io.h b/lib/arm/asm/io.h deleted file mode 100644 index ba3b0b24..00000000 --- a/lib/arm/asm/io.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef _ASMARM_IO_H_ -#define _ASMARM_IO_H_ -#include -#include -#include - -#define __iomem -#define __force - -#define __bswap16 bswap16 -static inline u16 bswap16(u16 val) -{ - u16 ret; - asm volatile("rev16 %0, %1" : "=r" (ret) : "r" (val)); - return ret; -} - -#define __bswap32 bswap32 -static inline u32 bswap32(u32 val) -{ - u32 ret; - asm volatile("rev %0, %1" : "=r" (ret) : "r" (val)); - return ret; -} - -#define __raw_readb __raw_readb -static inline u8 __raw_readb(const volatile void __iomem *addr) -{ - u8 val; - asm volatile("ldrb %1, %0" - : "+Qo" (*(volatile u8 __force *)addr), - "=r" (val)); - return val; -} - -#define __raw_readw __raw_readw -static inline u16 __raw_readw(const volatile void __iomem *addr) -{ - u16 val; - asm volatile("ldrh %1, %0" - : "+Q" (*(volatile u16 __force *)addr), - "=r" (val)); - return val; -} - -#define __raw_readl __raw_readl -static inline u32 __raw_readl(const volatile void __iomem *addr) -{ - u32 val; - asm volatile("ldr %1, %0" - : "+Qo" (*(volatile u32 __force *)addr), - "=r" (val)); - return val; -} - -#define __raw_writeb __raw_writeb -static inline void __raw_writeb(u8 val, volatile void __iomem *addr) -{ - asm volatile("strb %1, %0" - : "+Qo" (*(volatile u8 __force *)addr) - : "r" (val)); -} - -#define __raw_writew __raw_writew -static inline void __raw_writew(u16 val, volatile void __iomem *addr) -{ - asm volatile("strh %1, %0" - : "+Q" (*(volatile u16 __force *)addr) - : "r" (val)); -} - -#define __raw_writel __raw_writel -static inline void __raw_writel(u32 val, volatile void __iomem *addr) -{ - asm volatile("str %1, %0" - : "+Qo" (*(volatile u32 __force *)addr) - : "r" (val)); -} - -#define virt_to_phys virt_to_phys -static inline phys_addr_t virt_to_phys(const volatile void *x) -{ - return __virt_to_phys((unsigned long)(x)); -} - -#define phys_to_virt phys_to_virt -static inline void *phys_to_virt(phys_addr_t x) -{ - return (void *)__phys_to_virt(x); -} - -#include - -#endif /* _ASMARM_IO_H_ */ diff --git a/lib/arm/asm/mmu-api.h b/lib/arm/asm/mmu-api.h deleted file mode 100644 index 2bbe1fae..00000000 --- a/lib/arm/asm/mmu-api.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __ASMARM_MMU_API_H_ -#define __ASMARM_MMU_API_H_ - -#include -#include - -extern pgd_t *mmu_idmap; -extern unsigned int mmu_disabled_cpu_count; -extern bool __mmu_enabled(void); -static inline bool mmu_enabled(void) -{ - return mmu_disabled_cpu_count == 0 || __mmu_enabled(); -} -extern void mmu_mark_enabled(int cpu); -extern void mmu_mark_disabled(int cpu); -extern void mmu_enable(pgd_t *pgtable); -extern void mmu_disable(void); - -extern void mmu_set_range_sect(pgd_t *pgtable, uintptr_t virt_offset, - phys_addr_t phys_start, phys_addr_t phys_end, - pgprot_t prot); -extern void mmu_set_range_ptes(pgd_t *pgtable, uintptr_t virt_offset, - phys_addr_t phys_start, phys_addr_t phys_end, - pgprot_t prot); -extern void mmu_clear_user(pgd_t *pgtable, unsigned long vaddr); -#endif diff --git a/lib/arm/asm/mmu.h b/lib/arm/asm/mmu.h deleted file mode 100644 index 122874b8..00000000 --- a/lib/arm/asm/mmu.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef __ASMARM_MMU_H_ -#define __ASMARM_MMU_H_ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include - -#define PTE_USER L_PTE_USER -#define PTE_RDONLY PTE_AP2 -#define PTE_SHARED L_PTE_SHARED -#define PTE_AF PTE_EXT_AF -#define PTE_WBWA L_PTE_MT_WRITEALLOC - -/* See B3.18.7 TLB maintenance operations */ - -static inline void local_flush_tlb_all(void) -{ - dsb(nshst); - /* TLBIALL */ - asm volatile("mcr p15, 0, %0, c8, c7, 0" :: "r" (0)); - dsb(nsh); - isb(); -} - -static inline void flush_tlb_all(void) -{ - dsb(ishst); - /* TLBIALLIS */ - asm volatile("mcr p15, 0, %0, c8, c3, 0" :: "r" (0)); - dsb(ish); - isb(); -} - -static inline void flush_tlb_page(unsigned long vaddr) -{ - dsb(ishst); - /* TLBIMVAAIS */ - asm volatile("mcr p15, 0, %0, c8, c3, 3" :: "r" (vaddr)); - dsb(ish); - isb(); -} - -static inline void flush_dcache_addr(unsigned long vaddr) -{ - /* DCCIMVAC */ - asm volatile("mcr p15, 0, %0, c7, c14, 1" :: "r" (vaddr)); -} - -#include - -#endif /* __ASMARM_MMU_H_ */ diff --git a/lib/arm/asm/page.h b/lib/arm/asm/page.h deleted file mode 100644 index 039c9f7b..00000000 --- a/lib/arm/asm/page.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef _ASMARM_PAGE_H_ -#define _ASMARM_PAGE_H_ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ - -#include - -#define PAGE_SHIFT 12 -#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) - -#ifndef __ASSEMBLY__ - -#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) - -typedef u64 pteval_t; -typedef u64 pmdval_t; -typedef u64 pgdval_t; -typedef struct { pteval_t pte; } pte_t; -typedef struct { pmdval_t pmd; } pmd_t; -typedef struct { pgdval_t pgd; } pgd_t; -typedef struct { pteval_t pgprot; } pgprot_t; - -#define pte_val(x) ((x).pte) -#define pmd_val(x) ((x).pmd) -#define pgd_val(x) ((x).pgd) -#define pgprot_val(x) ((x).pgprot) - -#define __pte(x) ((pte_t) { (x) } ) -#define __pmd(x) ((pmd_t) { (x) } ) -#define __pgd(x) ((pgd_t) { (x) } ) -#define __pgprot(x) ((pgprot_t) { (x) } ) - -#define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) -#define __pa(x) __virt_to_phys((unsigned long)(x)) - -#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) -#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) - -extern phys_addr_t __virt_to_phys(unsigned long addr); -extern unsigned long __phys_to_virt(phys_addr_t addr); - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMARM_PAGE_H_ */ diff --git a/lib/arm/asm/pci.h b/lib/arm/asm/pci.h deleted file mode 100644 index 50d0fb64..00000000 --- a/lib/arm/asm/pci.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/lib/arm/asm/pgtable-hwdef.h b/lib/arm/asm/pgtable-hwdef.h deleted file mode 100644 index 4107e188..00000000 --- a/lib/arm/asm/pgtable-hwdef.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef _ASMARM_PGTABLE_HWDEF_H_ -#define _ASMARM_PGTABLE_HWDEF_H_ -/* - * From arch/arm/include/asm/pgtable-3level.h - * arch/arm/include/asm/pgtable-3level-hwdef.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#define PTRS_PER_PGD 4 -#define PGDIR_SHIFT 30 -#define PGDIR_SIZE (_AC(1,UL) << PGDIR_SHIFT) -#define PGDIR_MASK (~((1 << PGDIR_SHIFT) - 1)) - -#define PGD_VALID (_AT(pgdval_t, 1) << 0) - -#define PTRS_PER_PTE 512 -#define PTRS_PER_PMD 512 - -#define PMD_SHIFT 21 -#define PMD_SIZE (_AC(1,UL) << PMD_SHIFT) -#define PMD_MASK (~((1 << PMD_SHIFT) - 1)) - -#define L_PMD_SECT_VALID (_AT(pmdval_t, 1) << 0) - -#define L_PTE_VALID (_AT(pteval_t, 1) << 0) /* Valid */ -#define L_PTE_PRESENT (_AT(pteval_t, 3) << 0) /* Present */ -#define L_PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */ -#define L_PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ -#define L_PTE_YOUNG (_AT(pteval_t, 1) << 10) /* AF */ -#define L_PTE_XN (_AT(pteval_t, 1) << 54) /* XN */ - -/* - * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). - */ -#define L_PTE_MT_UNCACHED (_AT(pteval_t, 0) << 2) /* strongly ordered */ -#define L_PTE_MT_BUFFERABLE (_AT(pteval_t, 1) << 2) /* normal non-cacheable */ -#define L_PTE_MT_WRITETHROUGH (_AT(pteval_t, 2) << 2) /* normal inner write-through */ -#define L_PTE_MT_WRITEBACK (_AT(pteval_t, 3) << 2) /* normal inner write-back */ -#define L_PTE_MT_WRITEALLOC (_AT(pteval_t, 7) << 2) /* normal inner write-alloc */ -#define L_PTE_MT_DEV_SHARED (_AT(pteval_t, 4) << 2) /* device */ -#define L_PTE_MT_DEV_NONSHARED (_AT(pteval_t, 4) << 2) /* device */ -#define L_PTE_MT_DEV_WC (_AT(pteval_t, 1) << 2) /* normal non-cacheable */ -#define L_PTE_MT_DEV_CACHED (_AT(pteval_t, 3) << 2) /* normal inner write-back */ -#define L_PTE_MT_MASK (_AT(pteval_t, 7) << 2) - -/* - * Hardware page table definitions. - * - * + Level 1/2 descriptor - * - common - */ -#define PMD_TYPE_MASK (_AT(pmdval_t, 3) << 0) -#define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0) -#define PMD_TYPE_TABLE (_AT(pmdval_t, 3) << 0) -#define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0) -#define PMD_SECT_VALID (_AT(pmdval_t, 1) << 0) -#define PMD_TABLE_BIT (_AT(pmdval_t, 1) << 1) -#define PMD_BIT4 (_AT(pmdval_t, 0)) -#define PMD_DOMAIN(x) (_AT(pmdval_t, 0)) -#define PMD_APTABLE_SHIFT (61) -#define PMD_APTABLE (_AT(pgdval_t, 3) << PGD_APTABLE_SHIFT) -#define PMD_PXNTABLE (_AT(pgdval_t, 1) << 59) - -/* - * - section - */ -#define PMD_SECT_BUFFERABLE (_AT(pmdval_t, 1) << 2) -#define PMD_SECT_CACHEABLE (_AT(pmdval_t, 1) << 3) -#define PMD_SECT_USER (_AT(pmdval_t, 1) << 6) /* AP[1] */ -#define PMD_SECT_AP2 (_AT(pmdval_t, 1) << 7) /* read only */ -#define PMD_SECT_S (_AT(pmdval_t, 3) << 8) -#define PMD_SECT_AF (_AT(pmdval_t, 1) << 10) -#define PMD_SECT_nG (_AT(pmdval_t, 1) << 11) -#define PMD_SECT_PXN (_AT(pmdval_t, 1) << 53) -#define PMD_SECT_XN (_AT(pmdval_t, 1) << 54) -#define PMD_SECT_AP_WRITE (_AT(pmdval_t, 0)) -#define PMD_SECT_AP_READ (_AT(pmdval_t, 0)) -#define PMD_SECT_AP1 (_AT(pmdval_t, 1) << 6) -#define PMD_SECT_TEX(x) (_AT(pmdval_t, 0)) - -/* - * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). - */ -#define PMD_SECT_UNCACHED (_AT(pmdval_t, 0) << 2) /* strongly ordered */ -#define PMD_SECT_BUFFERED (_AT(pmdval_t, 1) << 2) /* normal non-cacheable */ -#define PMD_SECT_WT (_AT(pmdval_t, 2) << 2) /* normal inner write-through */ -#define PMD_SECT_WB (_AT(pmdval_t, 3) << 2) /* normal inner write-back */ -#define PMD_SECT_WBWA (_AT(pmdval_t, 7) << 2) /* normal inner write-alloc */ - -/* - * + Level 3 descriptor (PTE) - */ -#define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0) -#define PTE_TYPE_FAULT (_AT(pteval_t, 0) << 0) -#define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0) -#define PTE_TABLE_BIT (_AT(pteval_t, 1) << 1) -#define PTE_BUFFERABLE (_AT(pteval_t, 1) << 2) /* AttrIndx[0] */ -#define PTE_CACHEABLE (_AT(pteval_t, 1) << 3) /* AttrIndx[1] */ -#define PTE_AP2 (_AT(pteval_t, 1) << 7) /* AP[2] */ -#define PTE_EXT_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ -#define PTE_EXT_AF (_AT(pteval_t, 1) << 10) /* Access Flag */ -#define PTE_EXT_NG (_AT(pteval_t, 1) << 11) /* nG */ -#define PTE_EXT_XN (_AT(pteval_t, 1) << 54) /* XN */ - -/* - * 40-bit physical address supported. - */ -#define PHYS_MASK_SHIFT (40) -#define PHYS_MASK ((_AC(1, ULL) << PHYS_MASK_SHIFT) - 1) - -#define TTBCR_IRGN0_WBWA (_AC(1, UL) << 8) -#define TTBCR_ORGN0_WBWA (_AC(1, UL) << 10) -#define TTBCR_SH0_SHARED (_AC(3, UL) << 12) -#define TTBCR_IRGN1_WBWA (_AC(1, UL) << 24) -#define TTBCR_ORGN1_WBWA (_AC(1, UL) << 26) -#define TTBCR_SH1_SHARED (_AC(3, UL) << 28) -#define TTBCR_EAE (_AC(1, UL) << 31) - -#endif /* _ASMARM_PGTABLE_HWDEF_H_ */ diff --git a/lib/arm/asm/pgtable.h b/lib/arm/asm/pgtable.h deleted file mode 100644 index 078dd16f..00000000 --- a/lib/arm/asm/pgtable.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef _ASMARM_PGTABLE_H_ -#define _ASMARM_PGTABLE_H_ -/* - * Adapted from arch/arm/include/asm/pgtable.h - * arch/arm/include/asm/pgtable-3level.h - * arch/arm/include/asm/pgalloc.h - * - * Note: some Linux function APIs have been modified. Nothing crazy, - * but if a function took, for example, an mm_struct, then - * that was either removed or replaced. - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include - -/* - * We can convert va <=> pa page table addresses with simple casts - * because we always allocate their pages with alloc_page(), and - * alloc_page() always returns identity mapped pages. - */ -#include - -#define pgtable_va(x) ((void *)(unsigned long)(x)) -#define pgtable_pa(x) ((unsigned long)(x)) - -#define pgd_none(pgd) (!pgd_val(pgd)) -#define pmd_none(pmd) (!pmd_val(pmd)) -#define pte_none(pte) (!pte_val(pte)) - -#define pgd_valid(pgd) (pgd_val(pgd) & PGD_VALID) -#define pmd_valid(pmd) (pmd_val(pmd) & PMD_SECT_VALID) -#define pte_valid(pte) (pte_val(pte) & L_PTE_VALID) - -#define pmd_huge(pmd) \ - ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_SECT) - -#define pgd_index(addr) \ - (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) -#define pgd_offset(pgtable, addr) ((pgtable) + pgd_index(addr)) - -#define pgd_free(pgd) free(pgd) -static inline pgd_t *pgd_alloc(void) -{ - pgd_t *pgd = memalign(L1_CACHE_BYTES, PTRS_PER_PGD * sizeof(pgd_t)); - memset(pgd, 0, PTRS_PER_PGD * sizeof(pgd_t)); - return pgd; -} - -static inline pmd_t *pgd_page_vaddr(pgd_t pgd) -{ - return pgtable_va(pgd_val(pgd) & PHYS_MASK & (s32)PAGE_MASK); -} - -#define pmd_index(addr) \ - (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) -#define pmd_offset(pgd, addr) \ - (pgd_page_vaddr(*(pgd)) + pmd_index(addr)) - -#define pmd_free(pmd) free_page(pmd) -static inline pmd_t *pmd_alloc_one(void) -{ - assert(PTRS_PER_PMD * sizeof(pmd_t) == PAGE_SIZE); - pmd_t *pmd = alloc_page(); - return pmd; -} -static inline pmd_t *pmd_alloc(pgd_t *pgd, unsigned long addr) -{ - if (pgd_none(*pgd)) { - pgd_t entry; - pgd_val(entry) = pgtable_pa(pmd_alloc_one()) | PMD_TYPE_TABLE; - WRITE_ONCE(*pgd, entry); - } - return pmd_offset(pgd, addr); -} - -static inline pte_t *pmd_page_vaddr(pmd_t pmd) -{ - return pgtable_va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK); -} - -#define pte_index(addr) \ - (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) -#define pte_offset(pmd, addr) \ - (pmd_page_vaddr(*(pmd)) + pte_index(addr)) - -#define pte_free(pte) free_page(pte) -static inline pte_t *pte_alloc_one(void) -{ - assert(PTRS_PER_PTE * sizeof(pte_t) == PAGE_SIZE); - pte_t *pte = alloc_page(); - return pte; -} -static inline pte_t *pte_alloc(pmd_t *pmd, unsigned long addr) -{ - if (pmd_none(*pmd)) { - pmd_t entry; - pmd_val(entry) = pgtable_pa(pte_alloc_one()) | PMD_TYPE_TABLE; - WRITE_ONCE(*pmd, entry); - } - return pte_offset(pmd, addr); -} - -#endif /* _ASMARM_PGTABLE_H_ */ diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h deleted file mode 100644 index e26ef890..00000000 --- a/lib/arm/asm/processor.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef _ASMARM_PROCESSOR_H_ -#define _ASMARM_PROCESSOR_H_ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include - -#define CTR_DMINLINE_SHIFT 16 -#define CTR_DMINLINE_MASK (0xf << 16) -#define CTR_DMINLINE(x) \ - (((x) & CTR_DMINLINE_MASK) >> CTR_DMINLINE_SHIFT) - -enum vector { - EXCPTN_RST, - EXCPTN_UND, - EXCPTN_SVC, - EXCPTN_PABT, - EXCPTN_DABT, - EXCPTN_ADDREXCPTN, - EXCPTN_IRQ, - EXCPTN_FIQ, - EXCPTN_MAX, -}; - -typedef void (*irq_handler_fn)(struct pt_regs *regs); -typedef void (*exception_fn)(struct pt_regs *); - -extern void install_exception_handler(enum vector v, exception_fn fn); - -extern void show_regs(struct pt_regs *regs); - -static inline unsigned long current_cpsr(void) -{ - unsigned long cpsr; - asm volatile("mrs %0, cpsr" : "=r" (cpsr)); - return cpsr; -} - -#define current_mode() (current_cpsr() & MODE_MASK) - -static inline void local_irq_enable(void) -{ - asm volatile("cpsie i" : : : "memory", "cc"); -} - -static inline void local_irq_disable(void) -{ - asm volatile("cpsid i" : : : "memory", "cc"); -} - -#define MPIDR __ACCESS_CP15(c0, 0, c0, 5) -static inline uint64_t get_mpidr(void) -{ - return read_sysreg(MPIDR); -} - -#define MPIDR_HWID_BITMASK 0xffffff -extern int mpidr_to_cpu(uint64_t mpidr); - -#define MPIDR_LEVEL_SHIFT(level) \ - (((1 << level) >> 1) << 3) -#define MPIDR_AFFINITY_LEVEL(mpidr, level) \ - ((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff) - -extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr); -extern bool is_user(void); - -#define CNTVCT __ACCESS_CP15_64(1, c14) -#define CNTFRQ __ACCESS_CP15(c14, 0, c0, 0) -#define CTR __ACCESS_CP15(c0, 0, c0, 1) - -static inline u64 get_cntvct(void) -{ - isb(); - return read_sysreg(CNTVCT); -} - -static inline u32 get_cntfrq(void) -{ - return read_sysreg(CNTFRQ); -} - -static inline u32 get_ctr(void) -{ - return read_sysreg(CTR); -} - -extern u32 dcache_line_size; - -#endif /* _ASMARM_PROCESSOR_H_ */ diff --git a/lib/arm/asm/psci.h b/lib/arm/asm/psci.h deleted file mode 100644 index 7b956bf5..00000000 --- a/lib/arm/asm/psci.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _ASMARM_PSCI_H_ -#define _ASMARM_PSCI_H_ -#include -#include - -extern int psci_invoke(unsigned long function_id, unsigned long arg0, - unsigned long arg1, unsigned long arg2); -extern int psci_cpu_on(unsigned long cpuid, unsigned long entry_point); -extern void psci_system_reset(void); -extern int cpu_psci_cpu_boot(unsigned int cpu); -extern void cpu_psci_cpu_die(void); -extern void psci_system_off(void); - -#endif /* _ASMARM_PSCI_H_ */ diff --git a/lib/arm/asm/ptrace.h b/lib/arm/asm/ptrace.h deleted file mode 100644 index 02bb2ccb..00000000 --- a/lib/arm/asm/ptrace.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef _ASMARM_PTRACE_H_ -#define _ASMARM_PTRACE_H_ -/* - * Adapted from Linux kernel headers - * arch/arm/include/asm/ptrace.h - * arch/arm/include/uapi/asm/ptrace.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -/* - * PSR bits - */ -#define USR_MODE 0x00000010 -#define SVC_MODE 0x00000013 -#define FIQ_MODE 0x00000011 -#define IRQ_MODE 0x00000012 -#define ABT_MODE 0x00000017 -#define HYP_MODE 0x0000001a -#define UND_MODE 0x0000001b -#define SYSTEM_MODE 0x0000001f -#define MODE32_BIT 0x00000010 -#define MODE_MASK 0x0000001f - -#define PSR_T_BIT 0x00000020 /* >= V4T, but not V7M */ -#define PSR_F_BIT 0x00000040 /* >= V4, but not V7M */ -#define PSR_I_BIT 0x00000080 /* >= V4, but not V7M */ -#define PSR_A_BIT 0x00000100 /* >= V6, but not V7M */ -#define PSR_E_BIT 0x00000200 /* >= V6, but not V7M */ -#define PSR_J_BIT 0x01000000 /* >= V5J, but not V7M */ -#define PSR_Q_BIT 0x08000000 /* >= V5E, including V7M */ -#define PSR_V_BIT 0x10000000 -#define PSR_C_BIT 0x20000000 -#define PSR_Z_BIT 0x40000000 -#define PSR_N_BIT 0x80000000 - -/* - * Groups of PSR bits - */ -#define PSR_f 0xff000000 /* Flags */ -#define PSR_s 0x00ff0000 /* Status */ -#define PSR_x 0x0000ff00 /* Extension */ -#define PSR_c 0x000000ff /* Control */ - -/* - * ARMv7 groups of PSR bits - */ -#define APSR_MASK 0xf80f0000 /* N, Z, C, V, Q and GE flags */ -#define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */ -#define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ -#define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */ - -#ifndef __ASSEMBLY__ -#include - -struct pt_regs { - unsigned long uregs[18]; -}; - -#define ARM_cpsr uregs[16] -#define ARM_pc uregs[15] -#define ARM_lr uregs[14] -#define ARM_sp uregs[13] -#define ARM_ip uregs[12] -#define ARM_fp uregs[11] -#define ARM_r10 uregs[10] -#define ARM_r9 uregs[9] -#define ARM_r8 uregs[8] -#define ARM_r7 uregs[7] -#define ARM_r6 uregs[6] -#define ARM_r5 uregs[5] -#define ARM_r4 uregs[4] -#define ARM_r3 uregs[3] -#define ARM_r2 uregs[2] -#define ARM_r1 uregs[1] -#define ARM_r0 uregs[0] -#define ARM_ORIG_r0 uregs[17] - -#define user_mode(regs) \ - (((regs)->ARM_cpsr & 0xf) == 0) - -#define processor_mode(regs) \ - ((regs)->ARM_cpsr & MODE_MASK) - -#define interrupts_enabled(regs) \ - (!((regs)->ARM_cpsr & PSR_I_BIT)) - -#define fast_interrupts_enabled(regs) \ - (!((regs)->ARM_cpsr & PSR_F_BIT)) - -#define MAX_REG_OFFSET (offsetof(struct pt_regs, ARM_ORIG_r0)) - -static inline unsigned long regs_get_register(struct pt_regs *regs, - unsigned int offset) -{ - if (offset > MAX_REG_OFFSET) - return 0; - return *(unsigned long *)((unsigned long)regs + offset); -} - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMARM_PTRACE_H_ */ diff --git a/lib/arm/asm/setup.h b/lib/arm/asm/setup.h deleted file mode 100644 index c8afb249..00000000 --- a/lib/arm/asm/setup.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _ASMARM_SETUP_H_ -#define _ASMARM_SETUP_H_ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include - -#define NR_CPUS 511 -extern u64 cpus[NR_CPUS]; /* per-cpu IDs (MPIDRs) */ -extern int nr_cpus; - -#define MR_F_PRIMARY (1U << 0) -#define MR_F_IO (1U << 1) -#define MR_F_UNKNOWN (1U << 31) - -struct mem_region { - phys_addr_t start; - phys_addr_t end; - unsigned int flags; -}; -extern struct mem_region *mem_regions; -extern phys_addr_t __phys_offset, __phys_end; - -extern unsigned int mem_region_get_flags(phys_addr_t paddr); - -#define PHYS_OFFSET (__phys_offset) -#define PHYS_END (__phys_end) - -#define L1_CACHE_SHIFT 6 -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) -#define SMP_CACHE_BYTES L1_CACHE_BYTES - -void setup(const void *fdt); - -#endif /* _ASMARM_SETUP_H_ */ diff --git a/lib/arm/asm/smp.h b/lib/arm/asm/smp.h deleted file mode 100644 index 077afde8..00000000 --- a/lib/arm/asm/smp.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _ASMARM_SMP_H_ -#define _ASMARM_SMP_H_ -/* - * Copyright (C) 2015, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include - -#define smp_processor_id() (current_thread_info()->cpu) - -extern bool cpu0_calls_idle; - -extern void halt(void); -extern void do_idle(void); - -extern cpumask_t cpu_present_mask; -extern cpumask_t cpu_online_mask; -extern cpumask_t cpu_idle_mask; -#define cpu_present(cpu) cpumask_test_cpu(cpu, &cpu_present_mask) -#define cpu_online(cpu) cpumask_test_cpu(cpu, &cpu_online_mask) -#define cpu_idle(cpu) cpumask_test_cpu(cpu, &cpu_idle_mask) -#define for_each_present_cpu(cpu) for_each_cpu(cpu, &cpu_present_mask) -#define for_each_online_cpu(cpu) for_each_cpu(cpu, &cpu_online_mask) - -static inline void set_cpu_present(int cpu, bool present) -{ - if (present) - cpumask_set_cpu(cpu, &cpu_present_mask); - else - cpumask_clear_cpu(cpu, &cpu_present_mask); -} - -static inline void set_cpu_online(int cpu, bool online) -{ - if (online) - cpumask_set_cpu(cpu, &cpu_online_mask); - else - cpumask_clear_cpu(cpu, &cpu_online_mask); -} - -static inline void set_cpu_idle(int cpu, bool idle) -{ - if (idle) - cpumask_set_cpu(cpu, &cpu_idle_mask); - else - cpumask_clear_cpu(cpu, &cpu_idle_mask); -} - -typedef void (*secondary_entry_fn)(void); -extern void smp_boot_secondary(int cpu, secondary_entry_fn entry); -extern void on_cpu_async(int cpu, void (*func)(void *data), void *data); -extern void on_cpu(int cpu, void (*func)(void *data), void *data); -extern void on_cpus(void (*func)(void *data), void *data); - -#endif /* _ASMARM_SMP_H_ */ diff --git a/lib/arm/asm/spinlock.h b/lib/arm/asm/spinlock.h deleted file mode 100644 index 2118a4b3..00000000 --- a/lib/arm/asm/spinlock.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _ASMARM_SPINLOCK_H_ -#define _ASMARM_SPINLOCK_H_ - -struct spinlock { - int v; -}; - -extern void spin_lock(struct spinlock *lock); -extern void spin_unlock(struct spinlock *lock); - -#endif /* _ASMARM_SPINLOCK_H_ */ diff --git a/lib/arm/asm/stack.h b/lib/arm/asm/stack.h deleted file mode 100644 index ebcedc2e..00000000 --- a/lib/arm/asm/stack.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _ASMARM_STACK_H_ -#define _ASMARM_STACK_H_ - -#ifndef _STACK_H_ -#error Do not directly include . Just use . -#endif - -#define HAVE_ARCH_BACKTRACE_FRAME -#define HAVE_ARCH_BACKTRACE - -#endif diff --git a/lib/arm/asm/sysreg.h b/lib/arm/asm/sysreg.h deleted file mode 100644 index 96843386..00000000 --- a/lib/arm/asm/sysreg.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef _ASMARM_SYSREG_H_ -#define _ASMARM_SYSREG_H_ -/* - * From the Linux kernel arch/arm/include/asm/cp15.h - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -/* - * CR1 bits (CP#15 CR1) - */ -#define CR_M (1 << 0) /* MMU enable */ -#define CR_A (1 << 1) /* Alignment abort enable */ -#define CR_C (1 << 2) /* Dcache enable */ -#define CR_W (1 << 3) /* Write buffer enable */ -#define CR_P (1 << 4) /* 32-bit exception handler */ -#define CR_D (1 << 5) /* 32-bit data address range */ -#define CR_L (1 << 6) /* Implementation defined */ -#define CR_B (1 << 7) /* Big endian */ -#define CR_S (1 << 8) /* System MMU protection */ -#define CR_R (1 << 9) /* ROM MMU protection */ -#define CR_F (1 << 10) /* Implementation defined */ -#define CR_Z (1 << 11) /* Implementation defined */ -#define CR_I (1 << 12) /* Icache enable */ -#define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */ -#define CR_RR (1 << 14) /* Round Robin cache replacement */ -#define CR_L4 (1 << 15) /* LDR pc can set T bit */ -#define CR_DT (1 << 16) -#define CR_HA (1 << 17) /* Hardware management of Access Flag */ -#define CR_IT (1 << 18) -#define CR_ST (1 << 19) -#define CR_FI (1 << 21) /* Fast interrupt (lower latency mode) */ -#define CR_U (1 << 22) /* Unaligned access operation */ -#define CR_XP (1 << 23) /* Extended page tables */ -#define CR_VE (1 << 24) /* Vectored interrupts */ -#define CR_EE (1 << 25) /* Exception (Big) Endian */ -#define CR_TRE (1 << 28) /* TEX remap enable */ -#define CR_AFE (1 << 29) /* Access flag enable */ -#define CR_TE (1 << 30) /* Thumb exception enable */ - -#ifndef __ASSEMBLY__ -#include - -#define __ACCESS_CP15(CRn, Op1, CRm, Op2) \ - "mrc", "mcr", xstr(p15, Op1, %0, CRn, CRm, Op2), u32 -#define __ACCESS_CP15_64(Op1, CRm) \ - "mrrc", "mcrr", xstr(p15, Op1, %Q0, %R0, CRm), u64 - -#define __ACCESS_CP14(CRn, Op1, CRm, Op2) \ - "mrc", "mcr", xstr(p14, Op1, %0, CRn, CRm, Op2), u32 -#define __ACCESS_CP14_64(Op1, CRm) \ - "mrrc", "mcrr", xstr(p14, Op1, %Q0, %R0, CRm), u64 - -#define __read_sysreg(r, w, c, t) ({ \ - t __val; \ - asm volatile(r " " c : "=r" (__val)); \ - __val; \ - }) -#define read_sysreg(...) __read_sysreg(__VA_ARGS__) - -#define __write_sysreg(v, r, w, c, t) asm volatile(w " " c : : "r" ((t)(v))) -#define write_sysreg(v, ...) __write_sysreg(v, __VA_ARGS__) -#endif /* !__ASSEMBLY__ */ - -#endif /* _ASMARM_SYSREG_H_ */ diff --git a/lib/arm/asm/thread_info.h b/lib/arm/asm/thread_info.h deleted file mode 100644 index 80ab3954..00000000 --- a/lib/arm/asm/thread_info.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _ASMARM_THREAD_INFO_H_ -#define _ASMARM_THREAD_INFO_H_ -/* - * Adapted from arch/arm64/include/asm/thread_info.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include - -#define MIN_THREAD_SHIFT 14 /* THREAD_SIZE == 16K */ -#if PAGE_SHIFT > MIN_THREAD_SHIFT -#define THREAD_SHIFT PAGE_SHIFT -#define THREAD_SIZE PAGE_SIZE -#define THREAD_MASK PAGE_MASK -#else -#define THREAD_SHIFT MIN_THREAD_SHIFT -#define THREAD_SIZE (_AC(1,UL) << THREAD_SHIFT) -#define THREAD_MASK (~(THREAD_SIZE-1)) -#endif - -#ifndef __ASSEMBLY__ -#include -#include - -#ifdef __arm__ -#include -/* - * arm needs room left at the top for the exception stacks, - * and the stack needs to be 8-byte aligned - */ -#define THREAD_START_SP \ - ((THREAD_SIZE - (sizeof(struct pt_regs) * 8)) & ~7) -#else -#define THREAD_START_SP (THREAD_SIZE - 16) -#endif - -static inline void *thread_stack_alloc(void) -{ - void *sp = memalign(PAGE_SIZE, THREAD_SIZE); - return sp + THREAD_START_SP; -} - -#define TIF_USER_MODE (1U << 0) - -struct thread_info { - int cpu; - unsigned int flags; - void *pgtable; -#ifdef __arm__ - exception_fn exception_handlers[EXCPTN_MAX]; -#else - vector_fn vector_handlers[VECTOR_MAX]; - exception_fn exception_handlers[VECTOR_MAX][EC_MAX]; -#endif - char ext[0]; /* allow unit tests to add extended info */ -}; - -static inline struct thread_info *thread_info_sp(unsigned long sp) -{ - return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); -} - -register unsigned long current_stack_pointer asm("sp"); - -static inline struct thread_info *current_thread_info(void) -{ - return thread_info_sp(current_stack_pointer); -} - -extern void thread_info_init(struct thread_info *ti, unsigned int flags); - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMARM_THREAD_INFO_H_ */ diff --git a/lib/arm/bitops.c b/lib/arm/bitops.c deleted file mode 100644 index b17d76aa..00000000 --- a/lib/arm/bitops.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Adapted from - * include/asm-generic/bitops/atomic.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include "libcflat.h" -#include -#include -#include - -void set_bit(int nr, volatile unsigned long *addr) -{ - volatile unsigned long *word = addr + BIT_WORD(nr); - unsigned long mask = BIT_MASK(nr); - - if (mmu_enabled()) - ATOMIC_BITOP("orr", mask, word); - else - *word |= mask; - smp_mb(); -} - -void clear_bit(int nr, volatile unsigned long *addr) -{ - volatile unsigned long *word = addr + BIT_WORD(nr); - unsigned long mask = BIT_MASK(nr); - - if (mmu_enabled()) - ATOMIC_BITOP("bic", mask, word); - else - *word &= ~mask; - smp_mb(); -} - -int test_bit(int nr, const volatile unsigned long *addr) -{ - const volatile unsigned long *word = addr + BIT_WORD(nr); - unsigned long mask = BIT_MASK(nr); - - return (*word & mask) != 0; -} - -int test_and_set_bit(int nr, volatile unsigned long *addr) -{ - volatile unsigned long *word = addr + BIT_WORD(nr); - unsigned long mask = BIT_MASK(nr); - unsigned long old; - - smp_mb(); - - if (mmu_enabled()) { - ATOMIC_TESTOP("orr", mask, word, old); - } else { - old = *word; - *word = old | mask; - } - smp_mb(); - - return (old & mask) != 0; -} - -int test_and_clear_bit(int nr, volatile unsigned long *addr) -{ - volatile unsigned long *word = addr + BIT_WORD(nr); - unsigned long mask = BIT_MASK(nr); - unsigned long old; - - smp_mb(); - - if (mmu_enabled()) { - ATOMIC_TESTOP("bic", mask, word, old); - } else { - old = *word; - *word = old & ~mask; - } - smp_mb(); - - return (old & mask) != 0; -} diff --git a/lib/arm/delay.c b/lib/arm/delay.c deleted file mode 100644 index 80e63860..00000000 --- a/lib/arm/delay.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Delay loops - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include - -void delay(u64 cycles) -{ - u64 start = get_cntvct(); - - while ((get_cntvct() - start) < cycles) - cpu_relax(); -} - -void udelay(unsigned long usec) -{ - delay((u64)usec * get_cntfrq() / 1000000); -} - -void mdelay(unsigned long msecs) -{ - while (msecs--) - udelay(1000); -} diff --git a/lib/arm/eabi_compat.c b/lib/arm/eabi_compat.c deleted file mode 100644 index c4071cce..00000000 --- a/lib/arm/eabi_compat.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Adapted from u-boot's arch/arm/lib/eabi_compat.c - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include - -/* Needed to compile with -Wmissing-prototypes */ -int raise(int signum); -void __aeabi_unwind_cpp_pr0(void); -void __aeabi_unwind_cpp_pr1(void); - -int raise(int signum __unused) -{ - printf("Divide by zero!\n"); - abort(); - return 0; -} - -/* Dummy functions to avoid linker complaints */ -void __aeabi_unwind_cpp_pr0(void) -{ -} - -void __aeabi_unwind_cpp_pr1(void) -{ -} diff --git a/lib/arm/gic-v2.c b/lib/arm/gic-v2.c deleted file mode 100644 index dc6a97c6..00000000 --- a/lib/arm/gic-v2.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include - -void gicv2_enable_defaults(void) -{ - void *dist = gicv2_dist_base(); - void *cpu_base = gicv2_cpu_base(); - unsigned int i; - - gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER)); - if (gicv2_data.irq_nr > 1020) - gicv2_data.irq_nr = 1020; - - for (i = 0; i < gicv2_data.irq_nr; i += 4) - writel(GICD_INT_DEF_PRI_X4, dist + GICD_IPRIORITYR + i); - - writel(GICD_INT_EN_SET_SGI, dist + GICD_ISENABLER + 0); - writel(GICD_ENABLE, dist + GICD_CTLR); - - writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR); - writel(GICC_ENABLE, cpu_base + GICC_CTLR); -} - -u32 gicv2_read_iar(void) -{ - return readl(gicv2_cpu_base() + GICC_IAR); -} - -u32 gicv2_iar_irqnr(u32 iar) -{ - return iar & GICC_IAR_INT_ID_MASK; -} - -void gicv2_write_eoir(u32 irqstat) -{ - writel(irqstat, gicv2_cpu_base() + GICC_EOIR); -} - -void gicv2_ipi_send_single(int irq, int cpu) -{ - assert(cpu < 8); - assert(irq < 16); - writel(1 << (cpu + 16) | irq, gicv2_dist_base() + GICD_SGIR); -} - -void gicv2_ipi_send_mask(int irq, const cpumask_t *dest) -{ - u8 tlist = (u8)cpumask_bits(dest)[0]; - - assert(irq < 16); - writel(tlist << 16 | irq, gicv2_dist_base() + GICD_SGIR); -} diff --git a/lib/arm/gic-v3.c b/lib/arm/gic-v3.c deleted file mode 100644 index a7e2cb81..00000000 --- a/lib/arm/gic-v3.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include - -void gicv3_set_redist_base(size_t stride) -{ - u32 aff = mpidr_compress(get_mpidr()); - u64 typer; - int i = 0; - - while (gicv3_data.redist_bases[i]) { - void *ptr = gicv3_data.redist_bases[i]; - do { - typer = gicv3_read_typer(ptr + GICR_TYPER); - if ((typer >> 32) == aff) { - gicv3_redist_base() = ptr; - return; - } - ptr += stride; /* skip RD_base, SGI_base, etc. */ - } while (!(typer & GICR_TYPER_LAST)); - ++i; - } - - /* should never reach here */ - assert(0); -} - -void gicv3_enable_defaults(void) -{ - void *dist = gicv3_dist_base(); - void *sgi_base; - unsigned int i; - - gicv3_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER)); - if (gicv3_data.irq_nr > 1020) - gicv3_data.irq_nr = 1020; - - writel(0, dist + GICD_CTLR); - gicv3_dist_wait_for_rwp(); - - writel(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1, - dist + GICD_CTLR); - gicv3_dist_wait_for_rwp(); - - for (i = 0; i < gicv3_data.irq_nr; i += 4) - writel(~0, dist + GICD_IGROUPR + i); - - if (!gicv3_redist_base()) - gicv3_set_redist_base(SZ_64K * 2); - sgi_base = gicv3_sgi_base(); - - writel(~0, sgi_base + GICR_IGROUPR0); - - for (i = 0; i < 16; i += 4) - writel(GICD_INT_DEF_PRI_X4, sgi_base + GICR_IPRIORITYR0 + i); - - writel(GICD_INT_EN_SET_SGI, sgi_base + GICR_ISENABLER0); - - gicv3_write_pmr(GICC_INT_PRI_THRESHOLD); - gicv3_write_grpen1(1); -} - -u32 gicv3_iar_irqnr(u32 iar) -{ - return iar & ((1 << 24) - 1); -} - -void gicv3_ipi_send_mask(int irq, const cpumask_t *dest) -{ - u16 tlist; - int cpu; - - assert(irq < 16); - - /* - * For each cpu in the mask collect its peers, which are also in - * the mask, in order to form target lists. - */ - for_each_cpu(cpu, dest) { - u64 mpidr = cpus[cpu], sgi1r; - u64 cluster_id; - - /* - * GICv3 can send IPIs to up 16 peer cpus with a single - * write to ICC_SGI1R_EL1 (using the target list). Peers - * are cpus that have nearly identical MPIDRs, the only - * difference being Aff0. The matching upper affinity - * levels form the cluster ID. - */ - cluster_id = mpidr & ~0xffUL; - tlist = 0; - - /* - * Sort of open code for_each_cpu in order to have a - * nested for_each_cpu loop. - */ - while (cpu < nr_cpus) { - if ((mpidr & 0xff) >= 16) { - printf("cpu%d MPIDR:aff0 is %d (>= 16)!\n", - cpu, (int)(mpidr & 0xff)); - break; - } - - tlist |= 1 << (mpidr & 0xf); - - cpu = cpumask_next(cpu, dest); - if (cpu >= nr_cpus) - break; - - mpidr = cpus[cpu]; - - if (cluster_id != (mpidr & ~0xffUL)) { - /* - * The next cpu isn't in our cluster. Roll - * back the cpu index allowing the outer - * for_each_cpu to find it again with - * cpumask_next - */ - --cpu; - break; - } - } - - /* Send the IPIs for the target list of this cluster */ - sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3) | - MPIDR_TO_SGI_AFFINITY(cluster_id, 2) | - irq << 24 | - MPIDR_TO_SGI_AFFINITY(cluster_id, 1) | - tlist); - - gicv3_write_sgi1r(sgi1r); - } - - /* Force the above writes to ICC_SGI1R_EL1 to be executed */ - isb(); -} - -void gicv3_ipi_send_single(int irq, int cpu) -{ - cpumask_t dest; - - cpumask_clear(&dest); - cpumask_set_cpu(cpu, &dest); - gicv3_ipi_send_mask(irq, &dest); -} - -#if defined(__aarch64__) - -/* - * alloc_lpi_tables - Allocate LPI config and pending tables - * and set PROPBASER (shared by all rdistributors) and per - * redistributor PENDBASER. - * - * gicv3_set_redist_base() must be called before - */ -void gicv3_lpi_alloc_tables(void) -{ - unsigned long n = SZ_64K >> PAGE_SHIFT; - unsigned long order = fls(n); - u64 prop_val; - int cpu; - - assert(gicv3_redist_base()); - - gicv3_data.lpi_prop = alloc_pages(order); - - /* ID bits = 13, ie. up to 14b LPI INTID */ - prop_val = (u64)(virt_to_phys(gicv3_data.lpi_prop)) | 13; - - for_each_present_cpu(cpu) { - u64 pend_val; - void *ptr; - - ptr = gicv3_data.redist_base[cpu]; - - writeq(prop_val, ptr + GICR_PROPBASER); - - gicv3_data.lpi_pend[cpu] = alloc_pages(order); - pend_val = (u64)(virt_to_phys(gicv3_data.lpi_pend[cpu])); - writeq(pend_val, ptr + GICR_PENDBASER); - } -} - -void gicv3_lpi_set_clr_pending(int rdist, int n, bool set) -{ - u8 *ptr = gicv3_data.lpi_pend[rdist]; - u8 mask = 1 << (n % 8), byte; - - ptr += (n / 8); - byte = *ptr; - if (set) - byte |= mask; - else - byte &= ~mask; - *ptr = byte; -} - -static void gicv3_lpi_rdist_ctrl(u32 redist, bool set) -{ - void *ptr; - u64 val; - - assert(redist < nr_cpus); - - ptr = gicv3_data.redist_base[redist]; - val = readl(ptr + GICR_CTLR); - if (set) - val |= GICR_CTLR_ENABLE_LPIS; - else - val &= ~GICR_CTLR_ENABLE_LPIS; - writel(val, ptr + GICR_CTLR); -} - -void gicv3_lpi_rdist_enable(int redist) -{ - gicv3_lpi_rdist_ctrl(redist, true); -} -void gicv3_lpi_rdist_disable(int redist) -{ - gicv3_lpi_rdist_ctrl(redist, false); -} -#endif /* __aarch64__ */ diff --git a/lib/arm/gic.c b/lib/arm/gic.c deleted file mode 100644 index 1bfcfcfb..00000000 --- a/lib/arm/gic.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include - -struct gicv2_data gicv2_data; -struct gicv3_data gicv3_data; -struct its_data its_data; - -struct gic_common_ops { - void (*enable_defaults)(void); - u32 (*read_iar)(void); - u32 (*iar_irqnr)(u32 iar); - void (*write_eoir)(u32 irqstat); - void (*ipi_send_single)(int irq, int cpu); - void (*ipi_send_mask)(int irq, const cpumask_t *dest); -}; - -static const struct gic_common_ops *gic_common_ops; - -static const struct gic_common_ops gicv2_common_ops = { - .enable_defaults = gicv2_enable_defaults, - .read_iar = gicv2_read_iar, - .iar_irqnr = gicv2_iar_irqnr, - .write_eoir = gicv2_write_eoir, - .ipi_send_single = gicv2_ipi_send_single, - .ipi_send_mask = gicv2_ipi_send_mask, -}; - -static const struct gic_common_ops gicv3_common_ops = { - .enable_defaults = gicv3_enable_defaults, - .read_iar = gicv3_read_iar, - .iar_irqnr = gicv3_iar_irqnr, - .write_eoir = gicv3_write_eoir, - .ipi_send_single = gicv3_ipi_send_single, - .ipi_send_mask = gicv3_ipi_send_mask, -}; - -/* - * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt - * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt - */ -static bool -gic_get_dt_bases(const char *compatible, void **base1, void **base2, void **base3) -{ - struct dt_pbus_reg reg; - struct dt_device gic, its; - struct dt_bus bus; - int node, subnode, ret, i, len; - const void *fdt = dt_fdt(); - - dt_bus_init_defaults(&bus); - dt_device_init(&gic, &bus, NULL); - - node = dt_device_find_compatible(&gic, compatible); - assert(node >= 0 || node == -FDT_ERR_NOTFOUND); - - if (node == -FDT_ERR_NOTFOUND) - return false; - - dt_device_bind_node(&gic, node); - - ret = dt_pbus_translate(&gic, 0, ®); - assert(ret == 0); - *base1 = ioremap(reg.addr, reg.size); - - for (i = 0; i < GICV3_NR_REDISTS; ++i) { - ret = dt_pbus_translate(&gic, i + 1, ®); - if (ret == -FDT_ERR_NOTFOUND) - break; - assert(ret == 0); - base2[i] = ioremap(reg.addr, reg.size); - } - - if (!base3) { - assert(!strcmp(compatible, "arm,cortex-a15-gic")); - return true; - } - - assert(!strcmp(compatible, "arm,gic-v3")); - - dt_for_each_subnode(node, subnode) { - const struct fdt_property *prop; - - prop = fdt_get_property(fdt, subnode, "compatible", &len); - if (!strcmp((char *)prop->data, "arm,gic-v3-its")) { - dt_device_bind_node(&its, subnode); - ret = dt_pbus_translate(&its, 0, ®); - assert(ret == 0); - *base3 = ioremap(reg.addr, reg.size); - break; - } - } - - return true; -} - -int gicv2_init(void) -{ - return gic_get_dt_bases("arm,cortex-a15-gic", - &gicv2_data.dist_base, &gicv2_data.cpu_base, NULL); -} - -int gicv3_init(void) -{ - return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base, - &gicv3_data.redist_bases[0], &its_data.base); -} - -int gic_version(void) -{ - if (gic_common_ops == &gicv2_common_ops) - return 2; - else if (gic_common_ops == &gicv3_common_ops) - return 3; - return 0; -} - -int gic_init(void) -{ - if (gicv2_init()) { - gic_common_ops = &gicv2_common_ops; - } else if (gicv3_init()) { - gic_common_ops = &gicv3_common_ops; -#ifdef __aarch64__ - its_init(); -#endif - } - return gic_version(); -} - -void gic_enable_defaults(void) -{ - if (!gic_common_ops) { - int ret = gic_init(); - assert(ret != 0); - } else - assert(gic_common_ops->enable_defaults); - gic_common_ops->enable_defaults(); -} - -u32 gic_read_iar(void) -{ - assert(gic_common_ops && gic_common_ops->read_iar); - return gic_common_ops->read_iar(); -} - -u32 gic_iar_irqnr(u32 iar) -{ - assert(gic_common_ops && gic_common_ops->iar_irqnr); - return gic_common_ops->iar_irqnr(iar); -} - -void gic_write_eoir(u32 irqstat) -{ - assert(gic_common_ops && gic_common_ops->write_eoir); - gic_common_ops->write_eoir(irqstat); -} - -void gic_ipi_send_single(int irq, int cpu) -{ - assert(gic_common_ops && gic_common_ops->ipi_send_single); - gic_common_ops->ipi_send_single(irq, cpu); -} - -void gic_ipi_send_mask(int irq, const cpumask_t *dest) -{ - assert(gic_common_ops && gic_common_ops->ipi_send_mask); - gic_common_ops->ipi_send_mask(irq, dest); -} - -void gic_irq_set_clr_enable(int irq, bool enable) -{ - u32 offset, split = 32, shift = (irq % 32); - u32 reg, mask = BIT(shift); - void *base; - - assert(irq < 1020); - - switch (gic_version()) { - case 2: - offset = enable ? GICD_ISENABLER : GICD_ICENABLER; - base = gicv2_dist_base(); - break; - case 3: - if (irq < 32) { - offset = enable ? GICR_ISENABLER0 : GICR_ICENABLER0; - base = gicv3_sgi_base(); - } else { - offset = enable ? GICD_ISENABLER : GICD_ICENABLER; - base = gicv3_dist_base(); - } - break; - default: - assert(0); - } - base += offset + (irq / split) * 4; - reg = readl(base); - writel(reg | mask, base); -} - -enum gic_irq_state gic_irq_state(int irq) -{ - enum gic_irq_state state; - void *ispendr, *isactiver; - bool pending, active; - int offset, mask; - - assert(gic_common_ops); - assert(irq < 1020); - - switch (gic_version()) { - case 2: - ispendr = gicv2_dist_base() + GICD_ISPENDR; - isactiver = gicv2_dist_base() + GICD_ISACTIVER; - break; - case 3: - if (irq < GIC_NR_PRIVATE_IRQS) { - ispendr = gicv3_sgi_base() + GICR_ISPENDR0; - isactiver = gicv3_sgi_base() + GICR_ISACTIVER0; - } else { - ispendr = gicv3_dist_base() + GICD_ISPENDR; - isactiver = gicv3_dist_base() + GICD_ISACTIVER; - } - break; - default: - assert(0); - } - - offset = irq / 32 * 4; - mask = 1 << (irq % 32); - pending = readl(ispendr + offset) & mask; - active = readl(isactiver + offset) & mask; - - if (!active && !pending) - state = GIC_IRQ_STATE_INACTIVE; - if (pending) - state = GIC_IRQ_STATE_PENDING; - if (active) - state = GIC_IRQ_STATE_ACTIVE; - if (active && pending) - state = GIC_IRQ_STATE_ACTIVE_PENDING; - - return state; -} - diff --git a/lib/arm/io.c b/lib/arm/io.c deleted file mode 100644 index 343e1082..00000000 --- a/lib/arm/io.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Each architecture must implement puts() and exit() with the I/O - * devices exposed from QEMU, e.g. pl011 and chr-testdev. That's - * what's done here, along with initialization functions for those - * devices. - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include -#include -#include -#include - -#include "io.h" - -static struct spinlock uart_lock; -/* - * Use this guess for the uart base in order to make an attempt at - * having earlier printf support. We'll overwrite it with the real - * base address that we read from the device tree later. This is - * the address we expect the virtual machine manager to put in - * its generated device tree. - */ -#define UART_EARLY_BASE (u8 *)(unsigned long)CONFIG_UART_EARLY_BASE -static volatile u8 *uart0_base = UART_EARLY_BASE; - -static void uart0_init(void) -{ - /* - * kvm-unit-tests uses the uart only for output. Both uart models have - * the TX register at offset 0 from the base address, so there is no - * need to treat them separately. - */ - const char *compatible[] = {"arm,pl011", "ns16550a"}; - struct dt_pbus_reg base; - int i, ret; - - ret = dt_get_default_console_node(); - assert(ret >= 0 || ret == -FDT_ERR_NOTFOUND); - - if (ret == -FDT_ERR_NOTFOUND) { - - for (i = 0; i < ARRAY_SIZE(compatible); i++) { - ret = dt_pbus_get_base_compatible(compatible[i], &base); - assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); - - if (ret == 0) - break; - } - - if (ret) { - printf("%s: Compatible uart not found in the device tree, " - "aborting...\n", __func__); - abort(); - } - - } else { - ret = dt_pbus_translate_node(ret, 0, &base); - assert(ret == 0); - } - - uart0_base = ioremap(base.addr, base.size); - - if (uart0_base != UART_EARLY_BASE) { - printf("WARNING: early print support may not work. " - "Found uart at %p, but early base is %p.\n", - uart0_base, UART_EARLY_BASE); - } -} - -void io_init(void) -{ - uart0_init(); - chr_testdev_init(); -} - -void puts(const char *s) -{ - spin_lock(&uart_lock); - while (*s) - writeb(*s++, uart0_base); - spin_unlock(&uart_lock); -} - -static int do_getchar(void) -{ - int c; - - spin_lock(&uart_lock); - c = readb(uart0_base); - spin_unlock(&uart_lock); - - return c ?: -1; -} - -/* - * Minimalist implementation for migration completion detection. - * Without FIFOs enabled on the QEMU UART device we just read - * the data register: we cannot read more than 16 characters. - */ -int __getchar(void) -{ - int c = do_getchar(); - static int count; - - if (c != -1) - ++count; - - assert(count < 16); - - return c; -} - -/* - * Defining halt to take 'code' as an argument guarantees that it will - * be in x0/r0 when we halt. That gives us a final chance to see the exit - * status while inspecting the halted unit test state. - */ -extern void halt(int code); - -void exit(int code) -{ - chr_testdev_exit(code); - psci_system_off(); - halt(code); - __builtin_unreachable(); -} diff --git a/lib/arm/io.h b/lib/arm/io.h deleted file mode 100644 index 2746d72e..00000000 --- a/lib/arm/io.h +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Prototypes for io.c - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -extern void io_init(void); diff --git a/lib/arm/mmu.c b/lib/arm/mmu.c deleted file mode 100644 index 540a1e84..00000000 --- a/lib/arm/mmu.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * MMU enable and page table manipulation functions - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include -#include -#include - -#include "alloc_page.h" -#include "vmalloc.h" -#include -#include - -#include - -extern unsigned long etext; - -pgd_t *mmu_idmap; - -/* CPU 0 starts with disabled MMU */ -static cpumask_t mmu_disabled_cpumask = { {1} }; -unsigned int mmu_disabled_cpu_count = 1; - -bool __mmu_enabled(void) -{ - int cpu = current_thread_info()->cpu; - - /* - * mmu_enabled is called from places that are guarding the - * use of exclusive ops (which require the mmu to be enabled). - * That means we CANNOT call anything from here that may use a - * spinlock, atomic bitop, etc., otherwise we'll recurse. - * [cpumask_]test_bit is safe though. - */ - return !cpumask_test_cpu(cpu, &mmu_disabled_cpumask); -} - -void mmu_mark_enabled(int cpu) -{ - if (cpumask_test_and_clear_cpu(cpu, &mmu_disabled_cpumask)) - --mmu_disabled_cpu_count; -} - -void mmu_mark_disabled(int cpu) -{ - if (!cpumask_test_and_set_cpu(cpu, &mmu_disabled_cpumask)) - ++mmu_disabled_cpu_count; -} - -extern void asm_mmu_enable(phys_addr_t pgtable); -void mmu_enable(pgd_t *pgtable) -{ - struct thread_info *info = current_thread_info(); - - asm_mmu_enable(__pa(pgtable)); - - info->pgtable = pgtable; - mmu_mark_enabled(info->cpu); -} - -extern void asm_mmu_disable(void); -void mmu_disable(void) -{ - unsigned long sp = current_stack_pointer; - int cpu = current_thread_info()->cpu; - - assert_msg(__virt_to_phys(sp) == sp, - "Attempting to disable MMU with non-identity mapped stack"); - - mmu_mark_disabled(cpu); - - asm_mmu_disable(); -} - -static pteval_t *get_pte(pgd_t *pgtable, uintptr_t vaddr) -{ - pgd_t *pgd = pgd_offset(pgtable, vaddr); - pmd_t *pmd = pmd_alloc(pgd, vaddr); - pte_t *pte = pte_alloc(pmd, vaddr); - - return &pte_val(*pte); -} - -static pteval_t *install_pte(pgd_t *pgtable, uintptr_t vaddr, pteval_t pte) -{ - pteval_t *p_pte = get_pte(pgtable, vaddr); - - WRITE_ONCE(*p_pte, pte); - flush_tlb_page(vaddr); - return p_pte; -} - -static pteval_t *install_page_prot(pgd_t *pgtable, phys_addr_t phys, - uintptr_t vaddr, pgprot_t prot) -{ - pteval_t pte = phys; - pte |= PTE_TYPE_PAGE | PTE_AF | PTE_SHARED; - pte |= pgprot_val(prot); - return install_pte(pgtable, vaddr, pte); -} - -pteval_t *install_page(pgd_t *pgtable, phys_addr_t phys, void *virt) -{ - return install_page_prot(pgtable, phys, (uintptr_t)virt, - __pgprot(PTE_WBWA | PTE_USER)); -} - -phys_addr_t virt_to_pte_phys(pgd_t *pgtable, void *mem) -{ - return (*get_pte(pgtable, (uintptr_t)mem) & PHYS_MASK & -PAGE_SIZE) - + ((ulong)mem & (PAGE_SIZE - 1)); -} - -void mmu_set_range_ptes(pgd_t *pgtable, uintptr_t virt_offset, - phys_addr_t phys_start, phys_addr_t phys_end, - pgprot_t prot) -{ - phys_addr_t paddr = phys_start & PAGE_MASK; - uintptr_t vaddr = virt_offset & PAGE_MASK; - uintptr_t virt_end = phys_end - paddr + vaddr; - - for (; vaddr < virt_end; vaddr += PAGE_SIZE, paddr += PAGE_SIZE) - install_page_prot(pgtable, paddr, vaddr, prot); -} - -void mmu_set_range_sect(pgd_t *pgtable, uintptr_t virt_offset, - phys_addr_t phys_start, phys_addr_t phys_end, - pgprot_t prot) -{ - phys_addr_t paddr = phys_start & PGDIR_MASK; - uintptr_t vaddr = virt_offset & PGDIR_MASK; - uintptr_t virt_end = phys_end - paddr + vaddr; - pgd_t *pgd; - pgd_t entry; - - for (; vaddr < virt_end; vaddr += PGDIR_SIZE, paddr += PGDIR_SIZE) { - pgd_val(entry) = paddr; - pgd_val(entry) |= PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S; - pgd_val(entry) |= pgprot_val(prot); - pgd = pgd_offset(pgtable, vaddr); - WRITE_ONCE(*pgd, entry); - flush_tlb_page(vaddr); - } -} - -void *setup_mmu(phys_addr_t phys_end) -{ - uintptr_t code_end = (uintptr_t)&etext; - struct mem_region *r; - - /* 0G-1G = I/O, 1G-3G = identity, 3G-4G = vmalloc */ - if (phys_end > (3ul << 30)) - phys_end = 3ul << 30; - -#ifdef __aarch64__ - init_alloc_vpage((void*)(4ul << 30)); -#endif - - mmu_idmap = alloc_page(); - - for (r = mem_regions; r->end; ++r) { - if (!(r->flags & MR_F_IO)) - continue; - mmu_set_range_sect(mmu_idmap, r->start, r->start, r->end, - __pgprot(PMD_SECT_UNCACHED | PMD_SECT_USER)); - } - - /* armv8 requires code shared between EL1 and EL0 to be read-only */ - mmu_set_range_ptes(mmu_idmap, PHYS_OFFSET, - PHYS_OFFSET, code_end, - __pgprot(PTE_WBWA | PTE_RDONLY | PTE_USER)); - - mmu_set_range_ptes(mmu_idmap, code_end, - code_end, phys_end, - __pgprot(PTE_WBWA | PTE_USER)); - - mmu_enable(mmu_idmap); - return mmu_idmap; -} - -phys_addr_t __virt_to_phys(unsigned long addr) -{ - if (mmu_enabled()) { - pgd_t *pgtable = current_thread_info()->pgtable; - return virt_to_pte_phys(pgtable, (void *)addr); - } - return addr; -} - -unsigned long __phys_to_virt(phys_addr_t addr) -{ - /* - * We don't guarantee that phys_to_virt(virt_to_phys(vaddr)) == vaddr, but - * the default page tables do identity map all physical addresses, which - * means phys_to_virt(virt_to_phys((void *)paddr)) == paddr. - */ - assert(!mmu_enabled() || __virt_to_phys(addr) == addr); - return addr; -} - -void mmu_clear_user(pgd_t *pgtable, unsigned long vaddr) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - if (!mmu_enabled()) - return; - - pgd = pgd_offset(pgtable, vaddr); - assert(pgd_valid(*pgd)); - pmd = pmd_offset(pgd, vaddr); - assert(pmd_valid(*pmd)); - - if (pmd_huge(*pmd)) { - pmd_t entry = __pmd(pmd_val(*pmd) & ~PMD_SECT_USER); - WRITE_ONCE(*pmd, entry); - goto out_flush_tlb; - } - - pte = pte_offset(pmd, vaddr); - assert(pte_valid(*pte)); - pte_t entry = __pte(pte_val(*pte) & ~PTE_USER); - WRITE_ONCE(*pte, entry); - -out_flush_tlb: - flush_tlb_page(vaddr); -} diff --git a/lib/arm/processor.c b/lib/arm/processor.c deleted file mode 100644 index 773337e6..00000000 --- a/lib/arm/processor.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * processor control and status functions - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include - -static const char *processor_modes[] = { - "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , - "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , - "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", - "UK12_26", "UK13_26", "UK14_26", "UK15_26", - "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , - "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" , - "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , - "UK12_32", "UK13_32", "UK14_32", "SYS_32" -}; - -static const char *vector_names[] = { - "rst", "und", "svc", "pabt", "dabt", "addrexcptn", "irq", "fiq" -}; - -void show_regs(struct pt_regs *regs) -{ - unsigned long flags; - char buf[64]; - - printf("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n" - "sp : %08lx ip : %08lx fp : %08lx\n", - regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr, - regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); - printf("r10: %08lx r9 : %08lx r8 : %08lx\n", - regs->ARM_r10, regs->ARM_r9, regs->ARM_r8); - printf("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", - regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4); - printf("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", - regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0); - - flags = regs->ARM_cpsr; - buf[0] = flags & PSR_N_BIT ? 'N' : 'n'; - buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z'; - buf[2] = flags & PSR_C_BIT ? 'C' : 'c'; - buf[3] = flags & PSR_V_BIT ? 'V' : 'v'; - buf[4] = '\0'; - - printf("Flags: %s IRQs o%s FIQs o%s Mode %s\n", - buf, interrupts_enabled(regs) ? "n" : "ff", - fast_interrupts_enabled(regs) ? "n" : "ff", - processor_modes[processor_mode(regs)]); - - if (!user_mode(regs)) { - unsigned int ctrl, transbase, dac; - asm volatile( - "mrc p15, 0, %0, c1, c0\n" - "mrc p15, 0, %1, c2, c0\n" - "mrc p15, 0, %2, c3, c0\n" - : "=r" (ctrl), "=r" (transbase), "=r" (dac)); - printf("Control: %08x Table: %08x DAC: %08x\n", - ctrl, transbase, dac); - } -} - -void install_exception_handler(enum vector v, exception_fn fn) -{ - struct thread_info *ti = current_thread_info(); - - if (v < EXCPTN_MAX) - ti->exception_handlers[v] = fn; -} - -/* Needed to compile with -Wmissing-prototypes */ -void do_handle_exception(enum vector v, struct pt_regs *regs); - -void do_handle_exception(enum vector v, struct pt_regs *regs) -{ - struct thread_info *ti = thread_info_sp(regs->ARM_sp); - - if (ti->flags & TIF_USER_MODE) { - if (v < EXCPTN_MAX && ti->exception_handlers[v]) { - ti->exception_handlers[v](regs); - return; - } - ti = current_thread_info(); - } - - if (v < EXCPTN_MAX && ti->exception_handlers[v]) { - ti->exception_handlers[v](regs); - return; - } - - if (v < EXCPTN_MAX) - printf("Unhandled exception %d (%s)\n", v, vector_names[v]); - else - printf("%s called with vector=%d\n", __func__, v); - - printf("Exception frame registers:\n"); - show_regs(regs); - if (v == EXCPTN_DABT) { - unsigned long far, fsr; - asm volatile("mrc p15, 0, %0, c6, c0, 0": "=r" (far)); - asm volatile("mrc p15, 0, %0, c5, c0, 0": "=r" (fsr)); - printf("DFAR: %08lx DFSR: %08lx\n", far, fsr); - } else if (v == EXCPTN_PABT) { - unsigned long far, fsr; - asm volatile("mrc p15, 0, %0, c6, c0, 2": "=r" (far)); - asm volatile("mrc p15, 0, %0, c5, c0, 1": "=r" (fsr)); - printf("IFAR: %08lx IFSR: %08lx\n", far, fsr); - } - dump_frame_stack((void *)regs->ARM_pc, (void *)regs->ARM_fp); - abort(); -} - -void thread_info_init(struct thread_info *ti, unsigned int flags) -{ - memset(ti, 0, sizeof(struct thread_info)); - ti->cpu = mpidr_to_cpu(get_mpidr()); - ti->flags = flags; -} - -void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr) -{ - sp_usr &= (~7UL); /* stack ptr needs 8-byte alignment */ - - thread_info_init(thread_info_sp(sp_usr), TIF_USER_MODE); - thread_info_sp(sp_usr)->pgtable = current_thread_info()->pgtable; - - asm volatile( - "mrs r0, cpsr\n" - "bic r0, #" xstr(MODE_MASK) "\n" - "orr r0, #" xstr(USR_MODE) "\n" - "msr cpsr_c, r0\n" - "isb\n" - "mov r0, %0\n" - "mov sp, %1\n" - "mov pc, %2\n" - :: "r" (arg), "r" (sp_usr), "r" (func) : "r0"); -} - -bool is_user(void) -{ - return current_thread_info()->flags & TIF_USER_MODE; -} diff --git a/lib/arm/psci.c b/lib/arm/psci.c deleted file mode 100644 index 936c8394..00000000 --- a/lib/arm/psci.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * PSCI API - * From arch/arm[64]/kernel/psci.c - * - * Copyright (C) 2015, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include - -__attribute__((noinline)) -int psci_invoke(unsigned long function_id, unsigned long arg0, - unsigned long arg1, unsigned long arg2) -{ - asm volatile( - "hvc #0" - : "+r" (function_id) - : "r" (arg0), "r" (arg1), "r" (arg2)); - return function_id; -} - -int psci_cpu_on(unsigned long cpuid, unsigned long entry_point) -{ -#ifdef __arm__ - return psci_invoke(PSCI_0_2_FN_CPU_ON, cpuid, entry_point, 0); -#else - return psci_invoke(PSCI_0_2_FN64_CPU_ON, cpuid, entry_point, 0); -#endif -} - -extern void secondary_entry(void); -int cpu_psci_cpu_boot(unsigned int cpu) -{ - int err = psci_cpu_on(cpus[cpu], __pa(secondary_entry)); - if (err) - printf("failed to boot CPU%d (%d)\n", cpu, err); - return err; -} - -void cpu_psci_cpu_die(void) -{ - int err = psci_invoke(PSCI_0_2_FN_CPU_OFF, 0, 0, 0); - printf("CPU%d unable to power off (error = %d)\n", smp_processor_id(), err); -} - -void psci_system_reset(void) -{ - psci_invoke(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); -} - -void psci_system_off(void) -{ - int err = psci_invoke(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); - printf("CPU%d unable to do system off (error = %d)\n", smp_processor_id(), err); -} diff --git a/lib/arm/setup.c b/lib/arm/setup.c deleted file mode 100644 index 418b4e58..00000000 --- a/lib/arm/setup.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Initialize machine setup information and I/O. - * - * After running setup() unit tests may query how many cpus they have - * (nr_cpus), how much memory they have (PHYS_END - PHYS_OFFSET), may - * use dynamic memory allocation (malloc, etc.), printf, and exit. - * Finally, argc and argv are also ready to be passed to main(). - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "io.h" - -#define NR_INITIAL_MEM_REGIONS 16 - -extern unsigned long stacktop; - -char *initrd; -u32 initrd_size; - -u64 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (u64)~0 }; -int nr_cpus; - -static struct mem_region __initial_mem_regions[NR_INITIAL_MEM_REGIONS + 1]; -struct mem_region *mem_regions = __initial_mem_regions; -phys_addr_t __phys_offset, __phys_end; - -u32 dcache_line_size; - -int mpidr_to_cpu(uint64_t mpidr) -{ - int i; - - for (i = 0; i < nr_cpus; ++i) - if (cpus[i] == (mpidr & MPIDR_HWID_BITMASK)) - return i; - return -1; -} - -static void cpu_set(int fdtnode __unused, u64 regval, void *info __unused) -{ - int cpu = nr_cpus++; - - assert_msg(cpu < NR_CPUS, "Number cpus exceeds maximum supported (%d).", NR_CPUS); - - cpus[cpu] = regval; - set_cpu_present(cpu, true); -} - -static void cpu_init(void) -{ - int ret; - - nr_cpus = 0; - ret = dt_for_each_cpu_node(cpu_set, NULL); - assert(ret == 0); - set_cpu_online(0, true); - /* - * DminLine is log2 of the number of words in the smallest cache line; a - * word is 4 bytes. - */ - dcache_line_size = 1 << (CTR_DMINLINE(get_ctr()) + 2); -} - -unsigned int mem_region_get_flags(phys_addr_t paddr) -{ - struct mem_region *r; - - for (r = mem_regions; r->end; ++r) { - if (paddr >= r->start && paddr < r->end) - return r->flags; - } - - return MR_F_UNKNOWN; -} - -static void mem_init(phys_addr_t freemem_start) -{ - struct dt_pbus_reg regs[NR_INITIAL_MEM_REGIONS]; - struct mem_region primary, mem = { - .start = (phys_addr_t)-1, - }; - phys_addr_t base, top; - int nr_regs, nr_io = 0, i; - - /* - * mach-virt I/O regions: - * - The first 1G (arm/arm64) - * - 512M at 256G (arm64, arm uses highmem=off) - * - 512G at 512G (arm64, arm uses highmem=off) - */ - mem_regions[nr_io++] = (struct mem_region){ 0, (1ul << 30), MR_F_IO }; -#ifdef __aarch64__ - mem_regions[nr_io++] = (struct mem_region){ (1ul << 38), (1ul << 38) | (1ul << 29), MR_F_IO }; - mem_regions[nr_io++] = (struct mem_region){ (1ul << 39), (1ul << 40), MR_F_IO }; -#endif - - nr_regs = dt_get_memory_params(regs, NR_INITIAL_MEM_REGIONS - nr_io); - assert(nr_regs > 0); - - primary = (struct mem_region){ 0 }; - - for (i = 0; i < nr_regs; ++i) { - struct mem_region *r = &mem_regions[nr_io + i]; - - r->start = regs[i].addr; - r->end = regs[i].addr + regs[i].size; - - /* - * pick the region we're in for our primary region - */ - if (freemem_start >= r->start && freemem_start < r->end) { - r->flags |= MR_F_PRIMARY; - primary = *r; - } - - /* - * set the lowest and highest addresses found, - * ignoring potential gaps - */ - if (r->start < mem.start) - mem.start = r->start; - if (r->end > mem.end) - mem.end = r->end; - } - assert(primary.end != 0); - assert(!(mem.start & ~PHYS_MASK) && !((mem.end - 1) & ~PHYS_MASK)); - - __phys_offset = primary.start; /* PHYS_OFFSET */ - __phys_end = primary.end; /* PHYS_END */ - - phys_alloc_init(freemem_start, primary.end - freemem_start); - phys_alloc_set_minimum_alignment(SMP_CACHE_BYTES); - - phys_alloc_get_unused(&base, &top); - base = PAGE_ALIGN(base); - top = top & PAGE_MASK; - assert(sizeof(long) == 8 || !(base >> 32)); - if (sizeof(long) != 8 && (top >> 32) != 0) - top = ((uint64_t)1 << 32); - free_pages((void *)(unsigned long)base, top - base); - page_alloc_ops_enable(); -} - -void setup(const void *fdt) -{ - void *freemem = &stacktop; - const char *bootargs, *tmp; - u32 fdt_size; - int ret; - - /* - * Before calling mem_init we need to move the fdt and initrd - * to safe locations. We move them to construct the memory - * map illustrated below: - * - * +----------------------+ <-- top of physical memory - * | | - * ~ ~ - * | | - * +----------------------+ <-- top of initrd - * | | - * +----------------------+ <-- top of FDT - * | | - * +----------------------+ <-- top of cpu0's stack - * | | - * +----------------------+ <-- top of text/data/bss sections, - * | | see arm/flat.lds - * | | - * +----------------------+ <-- load address - * | | - * +----------------------+ - */ - fdt_size = fdt_totalsize(fdt); - ret = fdt_move(fdt, freemem, fdt_size); - assert(ret == 0); - ret = dt_init(freemem); - assert(ret == 0); - freemem += fdt_size; - - ret = dt_get_initrd(&tmp, &initrd_size); - assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); - if (ret == 0) { - initrd = freemem; - memmove(initrd, tmp, initrd_size); - freemem += initrd_size; - } - - /* call init functions */ - mem_init(PAGE_ALIGN((unsigned long)freemem)); - cpu_init(); - - /* cpu_init must be called before thread_info_init */ - thread_info_init(current_thread_info(), 0); - - /* mem_init must be called before io_init */ - io_init(); - - /* finish setup */ - ret = dt_get_bootargs(&bootargs); - assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); - setup_args_progname(bootargs); - - if (initrd) { - /* environ is currently the only file in the initrd */ - char *env = malloc(initrd_size); - memcpy(env, initrd, initrd_size); - setup_env(env, initrd_size); - } -} diff --git a/lib/arm/smp.c b/lib/arm/smp.c deleted file mode 100644 index 98a5054e..00000000 --- a/lib/arm/smp.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Secondary cpu support - * - * Copyright (C) 2015, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -bool cpu0_calls_idle; - -cpumask_t cpu_present_mask; -cpumask_t cpu_online_mask; -cpumask_t cpu_idle_mask; - -struct secondary_data { - void *stack; /* must be first member of struct */ - secondary_entry_fn entry; -}; -struct secondary_data secondary_data; -static struct spinlock lock; - -/* Needed to compile with -Wmissing-prototypes */ -secondary_entry_fn secondary_cinit(void); - -secondary_entry_fn secondary_cinit(void) -{ - struct thread_info *ti = current_thread_info(); - secondary_entry_fn entry; - - thread_info_init(ti, 0); - - if (!(auxinfo.flags & AUXINFO_MMU_OFF)) { - ti->pgtable = mmu_idmap; - mmu_mark_enabled(ti->cpu); - } - - /* - * Save secondary_data.entry locally to avoid opening a race - * window between marking ourselves online and calling it. - */ - entry = secondary_data.entry; - set_cpu_online(ti->cpu, true); - sev(); - - /* - * Return to the assembly stub, allowing entry to be called - * from there with an empty stack. - */ - return entry; -} - -static void __smp_boot_secondary(int cpu, secondary_entry_fn entry) -{ - int ret; - - secondary_data.stack = thread_stack_alloc(); - secondary_data.entry = entry; - mmu_mark_disabled(cpu); - ret = cpu_psci_cpu_boot(cpu); - assert(ret == 0); - - while (!cpu_online(cpu)) - wfe(); -} - -void smp_boot_secondary(int cpu, secondary_entry_fn entry) -{ - spin_lock(&lock); - assert_msg(!cpu_online(cpu), "CPU%d already boot once", cpu); - __smp_boot_secondary(cpu, entry); - spin_unlock(&lock); -} - -struct on_cpu_info { - void (*func)(void *data); - void *data; - cpumask_t waiters; -}; -static struct on_cpu_info on_cpu_info[NR_CPUS]; - -static void __deadlock_check(int cpu, const cpumask_t *waiters, bool *found) -{ - int i; - - for_each_cpu(i, waiters) { - if (i == cpu) { - printf("CPU%d", cpu); - *found = true; - return; - } - __deadlock_check(cpu, &on_cpu_info[i].waiters, found); - if (*found) { - printf(" <=> CPU%d", i); - return; - } - } -} - -static void deadlock_check(int me, int cpu) -{ - bool found = false; - - __deadlock_check(cpu, &on_cpu_info[me].waiters, &found); - if (found) { - printf(" <=> CPU%d deadlock detectd\n", me); - assert(0); - } -} - -static void cpu_wait(int cpu) -{ - int me = smp_processor_id(); - - if (cpu == me) - return; - - cpumask_set_cpu(me, &on_cpu_info[cpu].waiters); - deadlock_check(me, cpu); - while (!cpu_idle(cpu)) - wfe(); - cpumask_clear_cpu(me, &on_cpu_info[cpu].waiters); -} - -void do_idle(void) -{ - int cpu = smp_processor_id(); - - if (cpu == 0) - cpu0_calls_idle = true; - - set_cpu_idle(cpu, true); - sev(); - - for (;;) { - while (cpu_idle(cpu)) - wfe(); - smp_rmb(); - on_cpu_info[cpu].func(on_cpu_info[cpu].data); - on_cpu_info[cpu].func = NULL; - smp_wmb(); - set_cpu_idle(cpu, true); - sev(); - } -} - -void on_cpu_async(int cpu, void (*func)(void *data), void *data) -{ - if (cpu == smp_processor_id()) { - func(data); - return; - } - - assert_msg(cpu != 0 || cpu0_calls_idle, "Waiting on CPU0, which is unlikely to idle. " - "If this is intended set cpu0_calls_idle=1"); - - spin_lock(&lock); - if (!cpu_online(cpu)) - __smp_boot_secondary(cpu, do_idle); - spin_unlock(&lock); - - for (;;) { - cpu_wait(cpu); - spin_lock(&lock); - if ((volatile void *)on_cpu_info[cpu].func == NULL) - break; - spin_unlock(&lock); - } - on_cpu_info[cpu].func = func; - on_cpu_info[cpu].data = data; - spin_unlock(&lock); - set_cpu_idle(cpu, false); - sev(); -} - -void on_cpu(int cpu, void (*func)(void *data), void *data) -{ - on_cpu_async(cpu, func, data); - cpu_wait(cpu); -} - -void on_cpus(void (*func)(void *data), void *data) -{ - int cpu, me = smp_processor_id(); - - for_each_present_cpu(cpu) { - if (cpu == me) - continue; - on_cpu_async(cpu, func, data); - } - func(data); - - for_each_present_cpu(cpu) { - if (cpu == me) - continue; - cpumask_set_cpu(me, &on_cpu_info[cpu].waiters); - deadlock_check(me, cpu); - } - while (cpumask_weight(&cpu_idle_mask) < nr_cpus - 1) - wfe(); - for_each_present_cpu(cpu) - cpumask_clear_cpu(me, &on_cpu_info[cpu].waiters); -} diff --git a/lib/arm/spinlock.c b/lib/arm/spinlock.c deleted file mode 100644 index ea7e02bc..00000000 --- a/lib/arm/spinlock.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * ARM spinlock implementation - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include -#include - -void spin_lock(struct spinlock *lock) -{ - u32 val, fail; - - if (!mmu_enabled()) { - lock->v = 1; - smp_mb(); - return; - } - - do { - asm volatile( - "1: ldrex %0, [%2]\n" - " teq %0, #0\n" - " bne 1b\n" - " mov %0, #1\n" - " strex %1, %0, [%2]\n" - : "=&r" (val), "=&r" (fail) - : "r" (&lock->v) - : "cc" ); - } while (fail); - - smp_mb(); -} - -void spin_unlock(struct spinlock *lock) -{ - smp_mb(); - lock->v = 0; -} diff --git a/lib/arm/stack.c b/lib/arm/stack.c deleted file mode 100644 index 7d081be7..00000000 --- a/lib/arm/stack.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * backtrace support (this is a modified lib/x86/stack.c) - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include - -int backtrace_frame(const void *frame, const void **return_addrs, - int max_depth) -{ - static int walking; - int depth; - const unsigned long *fp = (unsigned long *)frame; - - if (walking) { - printf("RECURSIVE STACK WALK!!!\n"); - return 0; - } - walking = 1; - - for (depth = 0; depth < max_depth; depth++) { - if (!fp) - break; - return_addrs[depth] = (void *)fp[0]; - if (return_addrs[depth] == 0) - break; - fp = (unsigned long *)fp[-1]; - } - - walking = 0; - return depth; -} - -int backtrace(const void **return_addrs, int max_depth) -{ - return backtrace_frame(__builtin_frame_address(0), - return_addrs, max_depth); -} diff --git a/lib/arm64/.gitignore b/lib/arm64/.gitignore deleted file mode 100644 index 84872bf1..00000000 --- a/lib/arm64/.gitignore +++ /dev/null @@ -1 +0,0 @@ -asm-offsets.[hs] diff --git a/lib/arm64/asm-offsets.c b/lib/arm64/asm-offsets.c deleted file mode 100644 index 53a12771..00000000 --- a/lib/arm64/asm-offsets.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Adapted from arch/arm64/kernel/asm-offsets.c - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include -#include -#include - -int main(void) -{ - OFFSET(S_X0, pt_regs, regs[0]); - OFFSET(S_X1, pt_regs, regs[1]); - OFFSET(S_X2, pt_regs, regs[2]); - OFFSET(S_X3, pt_regs, regs[3]); - OFFSET(S_X4, pt_regs, regs[4]); - OFFSET(S_X5, pt_regs, regs[5]); - OFFSET(S_X6, pt_regs, regs[6]); - OFFSET(S_X7, pt_regs, regs[7]); - OFFSET(S_LR, pt_regs, regs[30]); - OFFSET(S_SP, pt_regs, sp); - OFFSET(S_PC, pt_regs, pc); - OFFSET(S_PSTATE, pt_regs, pstate); - OFFSET(S_ORIG_X0, pt_regs, orig_x0); - OFFSET(S_SYSCALLNO, pt_regs, syscallno); - DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); - return 0; -} diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h deleted file mode 100644 index a7994ec2..00000000 --- a/lib/arm64/asm/arch_gicv3.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * All ripped off from arch/arm64/include/asm/arch_gicv3.h - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#ifndef _ASMARM64_ARCH_GICV3_H_ -#define _ASMARM64_ARCH_GICV3_H_ - -#include - -#define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0) -#define ICC_SGI1R_EL1 sys_reg(3, 0, 12, 11, 5) -#define ICC_IAR1_EL1 sys_reg(3, 0, 12, 12, 0) -#define ICC_EOIR1_EL1 sys_reg(3, 0, 12, 12, 1) -#define ICC_GRPEN1_EL1 sys_reg(3, 0, 12, 12, 7) - -#ifndef __ASSEMBLY__ - -#include -#include - -/* - * Low-level accessors - * - * These system registers are 32 bits, but we make sure that the compiler - * sets the GP register's most significant bits to 0 with an explicit cast. - */ - -static inline void gicv3_write_pmr(u32 val) -{ - asm volatile("msr_s " xstr(ICC_PMR_EL1) ", %0" : : "r" ((u64)val)); -} - -static inline void gicv3_write_sgi1r(u64 val) -{ - asm volatile("msr_s " xstr(ICC_SGI1R_EL1) ", %0" : : "r" (val)); -} - -static inline u32 gicv3_read_iar(void) -{ - u64 irqstat; - asm volatile("mrs_s %0, " xstr(ICC_IAR1_EL1) : "=r" (irqstat)); - dsb(sy); - return (u64)irqstat; -} - -static inline void gicv3_write_eoir(u32 irq) -{ - asm volatile("msr_s " xstr(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq)); - isb(); -} - -static inline void gicv3_write_grpen1(u32 val) -{ - asm volatile("msr_s " xstr(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val)); - isb(); -} - -#define gicv3_read_typer(c) readq(c) - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMARM64_ARCH_GICV3_H_ */ diff --git a/lib/arm64/asm/asm-offsets.h b/lib/arm64/asm/asm-offsets.h deleted file mode 100644 index d370ee36..00000000 --- a/lib/arm64/asm/asm-offsets.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/lib/arm64/asm/barrier.h b/lib/arm64/asm/barrier.h deleted file mode 100644 index 0e1904cf..00000000 --- a/lib/arm64/asm/barrier.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _ASMARM64_BARRIER_H_ -#define _ASMARM64_BARRIER_H_ -/* - * From Linux arch/arm64/include/asm/barrier.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#define sev() asm volatile("sev" : : : "memory") -#define wfe() asm volatile("wfe" : : : "memory") -#define wfi() asm volatile("wfi" : : : "memory") -#define yield() asm volatile("yield" : : : "memory") -#define cpu_relax() yield() - -#define isb() asm volatile("isb" : : : "memory") -#define dmb(opt) asm volatile("dmb " #opt : : : "memory") -#define dsb(opt) asm volatile("dsb " #opt : : : "memory") -#define mb() dsb(sy) -#define rmb() dsb(ld) -#define wmb() dsb(st) -#define smp_mb() dmb(ish) -#define smp_rmb() dmb(ishld) -#define smp_wmb() dmb(ishst) - -#endif /* _ASMARM64_BARRIER_H_ */ diff --git a/lib/arm64/asm/bitops.h b/lib/arm64/asm/bitops.h deleted file mode 100644 index 91b4bd94..00000000 --- a/lib/arm64/asm/bitops.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _ASMARM64_BITOPS_H_ -#define _ASMARM64_BITOPS_H_ -/* - * Adapted from - * arch/arm64/lib/bitops.S - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#ifndef _BITOPS_H_ -#error only can be included directly -#endif - -#define BITS_PER_LONG 64 - -#define HAVE_BUILTIN_FLS 1 - -#define ATOMIC_BITOP(insn, mask, word) \ -({ \ - unsigned long tmp1, tmp2; \ - asm volatile( \ - "1: ldxr %0, [%2]\n" \ - insn" %0, %0, %3\n" \ - " stxr %w1, %0, [%2]\n" \ - " cbnz %w1, 1b\n" \ - : "=&r" (tmp1), "=&r" (tmp2) \ - : "r" (word), "r" (mask) \ - : "cc"); \ -}) - -#define ATOMIC_TESTOP(insn, mask, word, old) \ -({ \ - unsigned long tmp1, tmp2; \ - asm volatile( \ - "1: ldxr %0, [%3]\n" \ - " and %1, %0, %4\n" \ - insn" %0, %0, %4\n" \ - " stlxr %w2, %0, [%3]\n" \ - " cbnz %w2, 1b\n" \ - : "=&r" (tmp1), "=&r" (old), "=&r" (tmp2) \ - : "r" (word), "r" (mask) \ - : "cc"); \ -}) - -extern void set_bit(int nr, volatile unsigned long *addr); -extern void clear_bit(int nr, volatile unsigned long *addr); -extern int test_bit(int nr, const volatile unsigned long *addr); -extern int test_and_set_bit(int nr, volatile unsigned long *addr); -extern int test_and_clear_bit(int nr, volatile unsigned long *addr); - -#endif /* _ASMARM64_BITOPS_H_ */ diff --git a/lib/arm64/asm/cpumask.h b/lib/arm64/asm/cpumask.h deleted file mode 100644 index d1421e7a..00000000 --- a/lib/arm64/asm/cpumask.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../arm/asm/cpumask.h" diff --git a/lib/arm64/asm/delay.h b/lib/arm64/asm/delay.h deleted file mode 100644 index 288e4b3f..00000000 --- a/lib/arm64/asm/delay.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../arm/asm/delay.h" diff --git a/lib/arm64/asm/esr.h b/lib/arm64/asm/esr.h deleted file mode 100644 index 8c351631..00000000 --- a/lib/arm64/asm/esr.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * From Linux kernel arch/arm64/include/asm/esr.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#ifndef _ASMARM64_ESR_H_ -#define _ASMARM64_ESR_H_ - -#define ESR_EL1_WRITE (1 << 6) -#define ESR_EL1_CM (1 << 8) -#define ESR_EL1_IL (1 << 25) - -#define ESR_EL1_EC_SHIFT (26) -#define ESR_EL1_EC_UNKNOWN (0x00) -#define ESR_EL1_EC_WFI (0x01) -#define ESR_EL1_EC_CP15_32 (0x03) -#define ESR_EL1_EC_CP15_64 (0x04) -#define ESR_EL1_EC_CP14_MR (0x05) -#define ESR_EL1_EC_CP14_LS (0x06) -#define ESR_EL1_EC_FP_ASIMD (0x07) -#define ESR_EL1_EC_CP10_ID (0x08) -#define ESR_EL1_EC_CP14_64 (0x0C) -#define ESR_EL1_EC_ILL_ISS (0x0E) -#define ESR_EL1_EC_SVC32 (0x11) -#define ESR_EL1_EC_SVC64 (0x15) -#define ESR_EL1_EC_SYS64 (0x18) -#define ESR_EL1_EC_IABT_EL0 (0x20) -#define ESR_EL1_EC_IABT_EL1 (0x21) -#define ESR_EL1_EC_PC_ALIGN (0x22) -#define ESR_EL1_EC_DABT_EL0 (0x24) -#define ESR_EL1_EC_DABT_EL1 (0x25) -#define ESR_EL1_EC_SP_ALIGN (0x26) -#define ESR_EL1_EC_FP_EXC32 (0x28) -#define ESR_EL1_EC_FP_EXC64 (0x2C) -#define ESR_EL1_EC_SERROR (0x2F) -#define ESR_EL1_EC_BREAKPT_EL0 (0x30) -#define ESR_EL1_EC_BREAKPT_EL1 (0x31) -#define ESR_EL1_EC_SOFTSTP_EL0 (0x32) -#define ESR_EL1_EC_SOFTSTP_EL1 (0x33) -#define ESR_EL1_EC_WATCHPT_EL0 (0x34) -#define ESR_EL1_EC_WATCHPT_EL1 (0x35) -#define ESR_EL1_EC_BKPT32 (0x38) -#define ESR_EL1_EC_BRK64 (0x3C) - -#define ESR_EL1_FSC_MASK (0x3F) -#define ESR_EL1_FSC_EXTABT (0x10) - -#endif /* _ASMARM64_ESR_H_ */ diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h deleted file mode 100644 index 52226624..00000000 --- a/lib/arm64/asm/gic-v2.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../arm/asm/gic-v2.h" diff --git a/lib/arm64/asm/gic-v3-its.h b/lib/arm64/asm/gic-v3-its.h deleted file mode 100644 index 0258daa1..00000000 --- a/lib/arm64/asm/gic-v3-its.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * All ITS* defines are lifted from include/linux/irqchip/arm-gic-v3.h - * - * Copyright (C) 2020, Red Hat Inc, Eric Auger - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#ifndef _ASMARM64_GIC_V3_ITS_H_ -#define _ASMARM64_GIC_V3_ITS_H_ - -#ifndef _ASMARM_GIC_H_ -#error Do not directly include . Include -#endif - -struct its_typer { - unsigned int ite_size; - unsigned int eventid_bits; - unsigned int deviceid_bits; - unsigned int collid_bits; - bool pta; - bool phys_lpi; - bool virt_lpi; -}; - -struct its_baser { - int index; - size_t psz; - int esz; - bool indirect; - void *table_addr; -}; - -#define GITS_BASER_NR_REGS 8 -#define GITS_MAX_DEVICES 8 -#define GITS_MAX_COLLECTIONS 8 - -struct its_device { - u32 device_id; /* device ID */ - u32 nr_ites; /* Max Interrupt Translation Entries */ - void *itt; /* Interrupt Translation Table GVA */ -}; - -struct its_collection { - u64 target_address; - u16 col_id; -}; - -struct its_data { - void *base; - struct its_typer typer; - struct its_baser device_baser; - struct its_baser coll_baser; - struct its_cmd_block *cmd_base; - struct its_cmd_block *cmd_write; - struct its_device devices[GITS_MAX_DEVICES]; - u32 nr_devices; /* Allocated Devices */ - struct its_collection collections[GITS_MAX_COLLECTIONS]; - u16 nr_collections; /* Allocated Collections */ -}; - -extern struct its_data its_data; - -#define gicv3_its_base() (its_data.base) - -#define GITS_CTLR 0x0000 -#define GITS_IIDR 0x0004 -#define GITS_TYPER 0x0008 -#define GITS_CBASER 0x0080 -#define GITS_CWRITER 0x0088 -#define GITS_CREADR 0x0090 -#define GITS_BASER 0x0100 - -#define GITS_TYPER_PLPIS BIT(0) -#define GITS_TYPER_VLPIS BIT(1) -#define GITS_TYPER_ITT_ENTRY_SIZE GENMASK_ULL(7, 4) -#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT 4 -#define GITS_TYPER_IDBITS GENMASK_ULL(12, 8) -#define GITS_TYPER_IDBITS_SHIFT 8 -#define GITS_TYPER_DEVBITS GENMASK_ULL(17, 13) -#define GITS_TYPER_DEVBITS_SHIFT 13 -#define GITS_TYPER_PTA BIT(19) -#define GITS_TYPER_CIDBITS GENMASK_ULL(35, 32) -#define GITS_TYPER_CIDBITS_SHIFT 32 -#define GITS_TYPER_CIL BIT(36) - -#define GITS_CTLR_ENABLE (1U << 0) - -#define GITS_CBASER_VALID (1UL << 63) - -#define GITS_BASER_VALID BIT(63) -#define GITS_BASER_INDIRECT BIT(62) -#define GITS_BASER_TYPE_SHIFT (56) -#define GITS_BASER_TYPE(r) (((r) >> GITS_BASER_TYPE_SHIFT) & 7) -#define GITS_BASER_ENTRY_SIZE_SHIFT (48) -#define GITS_BASER_ENTRY_SIZE(r) ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1) -#define GITS_BASER_PAGE_SIZE_SHIFT (8) -#define GITS_BASER_PAGE_SIZE_4K (0UL << GITS_BASER_PAGE_SIZE_SHIFT) -#define GITS_BASER_PAGE_SIZE_16K (1UL << GITS_BASER_PAGE_SIZE_SHIFT) -#define GITS_BASER_PAGE_SIZE_64K (2UL << GITS_BASER_PAGE_SIZE_SHIFT) -#define GITS_BASER_PAGE_SIZE_MASK (3UL << GITS_BASER_PAGE_SIZE_SHIFT) -#define GITS_BASER_PAGES_MAX 256 -#define GITS_BASER_PAGES_SHIFT (0) -#define GITS_BASER_NR_PAGES(r) (((r) & 0xff) + 1) -#define GITS_BASER_PHYS_ADDR_MASK 0xFFFFFFFFF000 -#define GITS_BASER_TYPE_NONE 0 -#define GITS_BASER_TYPE_DEVICE 1 -#define GITS_BASER_TYPE_COLLECTION 4 - -/* - * ITS commands - */ -#define GITS_CMD_MAPD 0x08 -#define GITS_CMD_MAPC 0x09 -#define GITS_CMD_MAPTI 0x0a -#define GITS_CMD_MAPI 0x0b -#define GITS_CMD_MOVI 0x01 -#define GITS_CMD_DISCARD 0x0f -#define GITS_CMD_INV 0x0c -#define GITS_CMD_MOVALL 0x0e -#define GITS_CMD_INVALL 0x0d -#define GITS_CMD_INT 0x03 -#define GITS_CMD_CLEAR 0x04 -#define GITS_CMD_SYNC 0x05 - -struct its_cmd_block { - u64 raw_cmd[4]; -}; - -extern void its_parse_typer(void); -extern void its_init(void); -extern int its_baser_lookup(int i, struct its_baser *baser); -extern void its_enable_defaults(void); -extern struct its_device *its_create_device(u32 dev_id, int nr_ites); -extern struct its_collection *its_create_collection(u16 col_id, u32 target_pe); - -extern void __its_send_mapd(struct its_device *dev, int valid, bool verbose); -extern void __its_send_mapc(struct its_collection *col, int valid, bool verbose); -extern void __its_send_mapti(struct its_device *dev, u32 irq_id, u32 event_id, - struct its_collection *col, bool verbose); -extern void __its_send_int(struct its_device *dev, u32 event_id, bool verbose); -extern void __its_send_inv(struct its_device *dev, u32 event_id, bool verbose); -extern void __its_send_discard(struct its_device *dev, u32 event_id, bool verbose); -extern void __its_send_clear(struct its_device *dev, u32 event_id, bool verbose); -extern void __its_send_invall(struct its_collection *col, bool verbose); -extern void __its_send_movi(struct its_device *dev, struct its_collection *col, - u32 id, bool verbose); -extern void __its_send_sync(struct its_collection *col, bool verbose); - -#define its_send_mapd(dev, valid) __its_send_mapd(dev, valid, true) -#define its_send_mapc(col, valid) __its_send_mapc(col, valid, true) -#define its_send_mapti(dev, irqid, eventid, col) __its_send_mapti(dev, irqid, eventid, col, true) -#define its_send_int(dev, eventid) __its_send_int(dev, eventid, true) -#define its_send_inv(dev, eventid) __its_send_inv(dev, eventid, true) -#define its_send_discard(dev, eventid) __its_send_discard(dev, eventid, true) -#define its_send_clear(dev, eventid) __its_send_clear(dev, eventid, true) -#define its_send_invall(col) __its_send_invall(col, true) -#define its_send_movi(dev, col, id) __its_send_movi(dev, col, id, true) -#define its_send_sync(col) __its_send_sync(col, true) - -#define its_send_mapd_nv(dev, valid) __its_send_mapd(dev, valid, false) -#define its_send_mapc_nv(col, valid) __its_send_mapc(col, valid, false) -#define its_send_mapti_nv(dev, irqid, eventid, col) __its_send_mapti(dev, irqid, eventid, col, false) -#define its_send_int_nv(dev, eventid) __its_send_int(dev, eventid, false) -#define its_send_inv_nv(dev, eventid) __its_send_inv(dev, eventid, false) -#define its_send_discard_nv(dev, eventid) __its_send_discard(dev, eventid, false) -#define its_send_clear_nv(dev, eventid) __its_send_clear(dev, eventidn false) -#define its_send_invall_nv(col) __its_send_invall(col, false) -#define its_send_movi_nv(dev, col, id) __its_send_movi(dev, col, id, false) -#define its_send_sync_nv(col) __its_send_sync(col, false) - -extern struct its_device *its_get_device(u32 id); -extern struct its_collection *its_get_collection(u32 id); - -#endif /* _ASMARM64_GIC_V3_ITS_H_ */ diff --git a/lib/arm64/asm/gic-v3.h b/lib/arm64/asm/gic-v3.h deleted file mode 100644 index 8ee5d4d9..00000000 --- a/lib/arm64/asm/gic-v3.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../arm/asm/gic-v3.h" diff --git a/lib/arm64/asm/gic.h b/lib/arm64/asm/gic.h deleted file mode 100644 index e5eb302a..00000000 --- a/lib/arm64/asm/gic.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../arm/asm/gic.h" diff --git a/lib/arm64/asm/io.h b/lib/arm64/asm/io.h deleted file mode 100644 index e0a03b25..00000000 --- a/lib/arm64/asm/io.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef _ASMARM64_IO_H_ -#define _ASMARM64_IO_H_ -/* - * From Linux arch/arm64/include/asm/io.h - * Generic IO read/write. These perform native-endian accesses. - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include -#include -#include - -#define __iomem -#define __force - -#define __raw_writeb __raw_writeb -static inline void __raw_writeb(u8 val, volatile void __iomem *addr) -{ - asm volatile("strb %w0, [%1]" : : "r" (val), "r" (addr)); -} - -#define __raw_writew __raw_writew -static inline void __raw_writew(u16 val, volatile void __iomem *addr) -{ - asm volatile("strh %w0, [%1]" : : "r" (val), "r" (addr)); -} - -#define __raw_writel __raw_writel -static inline void __raw_writel(u32 val, volatile void __iomem *addr) -{ - asm volatile("str %w0, [%1]" : : "r" (val), "r" (addr)); -} - -#define __raw_writeq __raw_writeq -static inline void __raw_writeq(u64 val, volatile void __iomem *addr) -{ - asm volatile("str %0, [%1]" : : "r" (val), "r" (addr)); -} - -#define __raw_readb __raw_readb -static inline u8 __raw_readb(const volatile void __iomem *addr) -{ - u8 val; - asm volatile("ldrb %w0, [%1]" : "=r" (val) : "r" (addr)); - return val; -} - -#define __raw_readw __raw_readw -static inline u16 __raw_readw(const volatile void __iomem *addr) -{ - u16 val; - asm volatile("ldrh %w0, [%1]" : "=r" (val) : "r" (addr)); - return val; -} - -#define __raw_readl __raw_readl -static inline u32 __raw_readl(const volatile void __iomem *addr) -{ - u32 val; - asm volatile("ldr %w0, [%1]" : "=r" (val) : "r" (addr)); - return val; -} - -#define __raw_readq __raw_readq -static inline u64 __raw_readq(const volatile void __iomem *addr) -{ - u64 val; - asm volatile("ldr %0, [%1]" : "=r" (val) : "r" (addr)); - return val; -} - -#define virt_to_phys virt_to_phys -static inline phys_addr_t virt_to_phys(const volatile void *x) -{ - return __virt_to_phys((unsigned long)(x)); -} - -#define phys_to_virt phys_to_virt -static inline void *phys_to_virt(phys_addr_t x) -{ - return (void *)__phys_to_virt(x); -} - -#include - -#endif /* _ASMARM64_IO_H_ */ diff --git a/lib/arm64/asm/mmu-api.h b/lib/arm64/asm/mmu-api.h deleted file mode 100644 index 7cd7096a..00000000 --- a/lib/arm64/asm/mmu-api.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../arm/asm/mmu-api.h" diff --git a/lib/arm64/asm/mmu.h b/lib/arm64/asm/mmu.h deleted file mode 100644 index 72d75eaf..00000000 --- a/lib/arm64/asm/mmu.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __ASMARM64_MMU_H_ -#define __ASMARM64_MMU_H_ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include - -#define PMD_SECT_UNCACHED PMD_ATTRINDX(MT_DEVICE_nGnRE) -#define PTE_WBWA PTE_ATTRINDX(MT_NORMAL) - -static inline void flush_tlb_all(void) -{ - dsb(ishst); - asm("tlbi vmalle1is"); - dsb(ish); - isb(); -} - -static inline void flush_tlb_page(unsigned long vaddr) -{ - unsigned long page = vaddr >> 12; - dsb(ishst); - asm("tlbi vaae1is, %0" :: "r" (page)); - dsb(ish); - isb(); -} - -static inline void flush_dcache_addr(unsigned long vaddr) -{ - asm volatile("dc civac, %0" :: "r" (vaddr)); -} - -#include - -#endif /* __ASMARM64_MMU_H_ */ diff --git a/lib/arm64/asm/page.h b/lib/arm64/asm/page.h deleted file mode 100644 index 46af552b..00000000 --- a/lib/arm64/asm/page.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _ASMARM64_PAGE_H_ -#define _ASMARM64_PAGE_H_ -/* - * Adapted from - * arch/arm64/include/asm/pgtable-types.h - * include/asm-generic/pgtable-nopmd.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#include - -#define PGTABLE_LEVELS 2 -#define VA_BITS 42 - -#define PAGE_SHIFT 16 -#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) - -#ifndef __ASSEMBLY__ - -#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) - -typedef u64 pteval_t; -typedef u64 pmdval_t; -typedef u64 pgdval_t; -typedef struct { pteval_t pte; } pte_t; -typedef struct { pgdval_t pgd; } pgd_t; -typedef struct { pteval_t pgprot; } pgprot_t; - -#define pte_val(x) ((x).pte) -#define pgd_val(x) ((x).pgd) -#define pgprot_val(x) ((x).pgprot) - -#define __pte(x) ((pte_t) { (x) } ) -#define __pgd(x) ((pgd_t) { (x) } ) -#define __pgprot(x) ((pgprot_t) { (x) } ) - -typedef struct { pgd_t pgd; } pmd_t; -#define pmd_val(x) (pgd_val((x).pgd)) -#define __pmd(x) ((pmd_t) { __pgd(x) } ) - -#define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) -#define __pa(x) __virt_to_phys((unsigned long)(x)) - -#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) -#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) - -extern phys_addr_t __virt_to_phys(unsigned long addr); -extern unsigned long __phys_to_virt(phys_addr_t addr); - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMARM64_PAGE_H_ */ diff --git a/lib/arm64/asm/pci.h b/lib/arm64/asm/pci.h deleted file mode 100644 index f70ef560..00000000 --- a/lib/arm64/asm/pci.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../arm/asm/pci.h" diff --git a/lib/arm64/asm/pgtable-hwdef.h b/lib/arm64/asm/pgtable-hwdef.h deleted file mode 100644 index 33524899..00000000 --- a/lib/arm64/asm/pgtable-hwdef.h +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef _ASMARM64_PGTABLE_HWDEF_H_ -#define _ASMARM64_PGTABLE_HWDEF_H_ -/* - * From arch/arm64/include/asm/pgtable-hwdef.h - * arch/arm64/include/asm/memory.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#define UL(x) _AC(x, UL) - -#define PTRS_PER_PTE (1 << (PAGE_SHIFT - 3)) - -/* - * PGDIR_SHIFT determines the size a top-level page table entry can map - * (depending on the configuration, this level can be 0, 1 or 2). - */ -#define PGDIR_SHIFT ((PAGE_SHIFT - 3) * PGTABLE_LEVELS + 3) -#define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) -#define PGDIR_MASK (~(PGDIR_SIZE-1)) -#define PTRS_PER_PGD (1 << (VA_BITS - PGDIR_SHIFT)) - -#define PGD_VALID (_AT(pgdval_t, 1) << 0) - -/* From include/asm-generic/pgtable-nopmd.h */ -#define PMD_SHIFT PGDIR_SHIFT -#define PTRS_PER_PMD 1 -#define PMD_SIZE (UL(1) << PMD_SHIFT) -#define PMD_MASK (~(PMD_SIZE-1)) - -/* - * Section address mask and size definitions. - */ -#define SECTION_SHIFT PMD_SHIFT -#define SECTION_SIZE (_AC(1, UL) << SECTION_SHIFT) -#define SECTION_MASK (~(SECTION_SIZE-1)) - -/* - * Hardware page table definitions. - * - * Level 1 descriptor (PMD). - */ -#define PMD_TYPE_MASK (_AT(pmdval_t, 3) << 0) -#define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0) -#define PMD_TYPE_TABLE (_AT(pmdval_t, 3) << 0) -#define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0) -#define PMD_TABLE_BIT (_AT(pmdval_t, 1) << 1) - -/* - * Section - */ -#define PMD_SECT_VALID (_AT(pmdval_t, 1) << 0) -#define PMD_SECT_PROT_NONE (_AT(pmdval_t, 1) << 58) -#define PMD_SECT_USER (_AT(pmdval_t, 1) << 6) /* AP[1] */ -#define PMD_SECT_RDONLY (_AT(pmdval_t, 1) << 7) /* AP[2] */ -#define PMD_SECT_S (_AT(pmdval_t, 3) << 8) -#define PMD_SECT_AF (_AT(pmdval_t, 1) << 10) -#define PMD_SECT_NG (_AT(pmdval_t, 1) << 11) -#define PMD_SECT_PXN (_AT(pmdval_t, 1) << 53) -#define PMD_SECT_UXN (_AT(pmdval_t, 1) << 54) - -/* - * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). - */ -#define PMD_ATTRINDX(t) (_AT(pmdval_t, (t)) << 2) -#define PMD_ATTRINDX_MASK (_AT(pmdval_t, 7) << 2) - -/* - * Level 3 descriptor (PTE). - */ -#define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0) -#define PTE_TYPE_FAULT (_AT(pteval_t, 0) << 0) -#define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0) -#define PTE_VALID (_AT(pteval_t, 1) << 0) -#define PTE_TABLE_BIT (_AT(pteval_t, 1) << 1) -#define PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */ -#define PTE_RDONLY (_AT(pteval_t, 1) << 7) /* AP[2] */ -#define PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ -#define PTE_AF (_AT(pteval_t, 1) << 10) /* Access Flag */ -#define PTE_NG (_AT(pteval_t, 1) << 11) /* nG */ -#define PTE_PXN (_AT(pteval_t, 1) << 53) /* Privileged XN */ -#define PTE_UXN (_AT(pteval_t, 1) << 54) /* User XN */ - -/* - * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). - */ -#define PTE_ATTRINDX(t) (_AT(pteval_t, (t)) << 2) -#define PTE_ATTRINDX_MASK (_AT(pteval_t, 7) << 2) - -/* - * Highest possible physical address supported. - */ -#define PHYS_MASK_SHIFT (48) -#define PHYS_MASK ((UL(1) << PHYS_MASK_SHIFT) - 1) - -/* - * TCR flags. - */ -#define TCR_TxSZ(x) (((UL(64) - (x)) << 16) | ((UL(64) - (x)) << 0)) -#define TCR_IRGN_NC ((UL(0) << 8) | (UL(0) << 24)) -#define TCR_IRGN_WBWA ((UL(1) << 8) | (UL(1) << 24)) -#define TCR_IRGN_WT ((UL(2) << 8) | (UL(2) << 24)) -#define TCR_IRGN_WBnWA ((UL(3) << 8) | (UL(3) << 24)) -#define TCR_IRGN_MASK ((UL(3) << 8) | (UL(3) << 24)) -#define TCR_ORGN_NC ((UL(0) << 10) | (UL(0) << 26)) -#define TCR_ORGN_WBWA ((UL(1) << 10) | (UL(1) << 26)) -#define TCR_ORGN_WT ((UL(2) << 10) | (UL(2) << 26)) -#define TCR_ORGN_WBnWA ((UL(3) << 10) | (UL(3) << 26)) -#define TCR_ORGN_MASK ((UL(3) << 10) | (UL(3) << 26)) -#define TCR_SHARED ((UL(3) << 12) | (UL(3) << 28)) -#define TCR_TG0_4K (UL(0) << 14) -#define TCR_TG0_64K (UL(1) << 14) -#define TCR_TG0_16K (UL(2) << 14) -#define TCR_TG1_16K (UL(1) << 30) -#define TCR_TG1_4K (UL(2) << 30) -#define TCR_TG1_64K (UL(3) << 30) -#define TCR_ASID16 (UL(1) << 36) -#define TCR_TBI0 (UL(1) << 37) - -/* - * Memory types available. - */ -#define MT_DEVICE_nGnRnE 0 /* noncached */ -#define MT_DEVICE_nGnRE 1 /* device */ -#define MT_DEVICE_GRE 2 -#define MT_NORMAL_NC 3 /* writecombine */ -#define MT_NORMAL 4 - -#endif /* _ASMARM64_PGTABLE_HWDEF_H_ */ diff --git a/lib/arm64/asm/pgtable.h b/lib/arm64/asm/pgtable.h deleted file mode 100644 index e577d9cf..00000000 --- a/lib/arm64/asm/pgtable.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef _ASMARM64_PGTABLE_H_ -#define _ASMARM64_PGTABLE_H_ -/* - * Adapted from arch/arm64/include/asm/pgtable.h - * include/asm-generic/pgtable-nopmd.h - * include/linux/mm.h - * - * Note: some Linux function APIs have been modified. Nothing crazy, - * but if a function took, for example, an mm_struct, then - * that was either removed or replaced. - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include -#include -#include -#include -#include - -#include - -/* - * We can convert va <=> pa page table addresses with simple casts - * because we always allocate their pages with alloc_page(), and - * alloc_page() always returns identity mapped pages. - */ -#define pgtable_va(x) ((void *)(unsigned long)(x)) -#define pgtable_pa(x) ((unsigned long)(x)) - -#define pgd_none(pgd) (!pgd_val(pgd)) -#define pmd_none(pmd) (!pmd_val(pmd)) -#define pte_none(pte) (!pte_val(pte)) - -#define pgd_valid(pgd) (pgd_val(pgd) & PGD_VALID) -#define pmd_valid(pmd) (pmd_val(pmd) & PMD_SECT_VALID) -#define pte_valid(pte) (pte_val(pte) & PTE_VALID) - -#define pmd_huge(pmd) \ - ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_SECT) - -#define pgd_index(addr) \ - (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) -#define pgd_offset(pgtable, addr) ((pgtable) + pgd_index(addr)) - -#define pgd_free(pgd) free(pgd) -static inline pgd_t *pgd_alloc(void) -{ - pgd_t *pgd = memalign(PAGE_SIZE, PTRS_PER_PGD * sizeof(pgd_t)); - memset(pgd, 0, PTRS_PER_PGD * sizeof(pgd_t)); - return pgd; -} - -#define pmd_offset(pgd, addr) ((pmd_t *)pgd) -#define pmd_free(pmd) -#define pmd_alloc(pgd, addr) pmd_offset(pgd, addr) - -static inline pte_t *pmd_page_vaddr(pmd_t pmd) -{ - return pgtable_va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK); -} - -#define pte_index(addr) \ - (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) -#define pte_offset(pmd, addr) \ - (pmd_page_vaddr(*(pmd)) + pte_index(addr)) - -#define pte_free(pte) free_page(pte) -static inline pte_t *pte_alloc_one(void) -{ - assert(PTRS_PER_PTE * sizeof(pte_t) == PAGE_SIZE); - pte_t *pte = alloc_page(); - return pte; -} -static inline pte_t *pte_alloc(pmd_t *pmd, unsigned long addr) -{ - if (pmd_none(*pmd)) { - pmd_t entry; - pmd_val(entry) = pgtable_pa(pte_alloc_one()) | PMD_TYPE_TABLE; - WRITE_ONCE(*pmd, entry); - } - return pte_offset(pmd, addr); -} - -#endif /* _ASMARM64_PGTABLE_H_ */ diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h deleted file mode 100644 index 02665b84..00000000 --- a/lib/arm64/asm/processor.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef _ASMARM64_PROCESSOR_H_ -#define _ASMARM64_PROCESSOR_H_ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ - -/* System Control Register (SCTLR_EL1) bits */ -#define SCTLR_EL1_EE (1 << 25) -#define SCTLR_EL1_WXN (1 << 19) -#define SCTLR_EL1_I (1 << 12) -#define SCTLR_EL1_SA0 (1 << 4) -#define SCTLR_EL1_SA (1 << 3) -#define SCTLR_EL1_C (1 << 2) -#define SCTLR_EL1_A (1 << 1) -#define SCTLR_EL1_M (1 << 0) - -#define CTR_DMINLINE_SHIFT 16 -#define CTR_DMINLINE_MASK (0xf << 16) -#define CTR_DMINLINE(x) \ - (((x) & CTR_DMINLINE_MASK) >> CTR_DMINLINE_SHIFT) - -#ifndef __ASSEMBLY__ -#include -#include -#include -#include - -enum vector { - EL1T_SYNC, - EL1T_IRQ, - EL1T_FIQ, - EL1T_ERROR, - EL1H_SYNC, - EL1H_IRQ, - EL1H_FIQ, - EL1H_ERROR, - EL0_SYNC_64, - EL0_IRQ_64, - EL0_FIQ_64, - EL0_ERROR_64, - EL0_SYNC_32, - EL0_IRQ_32, - EL0_FIQ_32, - EL0_ERROR_32, - VECTOR_MAX, -}; - -#define EC_MAX 64 - -typedef void (*vector_fn)(enum vector v, struct pt_regs *regs, - unsigned int esr); -typedef void (*exception_fn)(struct pt_regs *regs, unsigned int esr); -typedef void (*irq_handler_fn)(struct pt_regs *regs); -extern void install_vector_handler(enum vector v, vector_fn fn); -extern void install_exception_handler(enum vector v, unsigned int ec, - exception_fn fn); -extern void install_irq_handler(enum vector v, irq_handler_fn fn); -extern void default_vector_sync_handler(enum vector v, struct pt_regs *regs, - unsigned int esr); -extern void default_vector_irq_handler(enum vector v, struct pt_regs *regs, - unsigned int esr); -extern void vector_handlers_default_init(vector_fn *handlers); - -extern void show_regs(struct pt_regs *regs); -extern bool get_far(unsigned int esr, unsigned long *far); - -static inline unsigned long current_level(void) -{ - unsigned long el; - asm volatile("mrs %0, CurrentEL" : "=r" (el)); - return el & 0xc; -} - -static inline void local_irq_enable(void) -{ - asm volatile("msr daifclr, #2" : : : "memory"); -} - -static inline void local_irq_disable(void) -{ - asm volatile("msr daifset, #2" : : : "memory"); -} - -static inline uint64_t get_mpidr(void) -{ - return read_sysreg(mpidr_el1); -} - -#define MPIDR_HWID_BITMASK 0xff00ffffff -extern int mpidr_to_cpu(uint64_t mpidr); - -#define MPIDR_LEVEL_SHIFT(level) \ - (((1 << level) >> 1) << 3) -#define MPIDR_AFFINITY_LEVEL(mpidr, level) \ - ((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff) - -extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr); -extern bool is_user(void); - -static inline u64 get_cntvct(void) -{ - isb(); - return read_sysreg(cntvct_el0); -} - -static inline u32 get_cntfrq(void) -{ - return read_sysreg(cntfrq_el0); -} - -static inline u64 get_ctr(void) -{ - return read_sysreg(ctr_el0); -} - -extern u32 dcache_line_size; - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMARM64_PROCESSOR_H_ */ diff --git a/lib/arm64/asm/psci.h b/lib/arm64/asm/psci.h deleted file mode 100644 index 783b36ef..00000000 --- a/lib/arm64/asm/psci.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../arm/asm/psci.h" diff --git a/lib/arm64/asm/ptrace.h b/lib/arm64/asm/ptrace.h deleted file mode 100644 index ccb38dc6..00000000 --- a/lib/arm64/asm/ptrace.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef _ASMARM64_PTRACE_H_ -#define _ASMARM64_PTRACE_H_ -/* - * Adapted from Linux kernel headers - * arch/arm64/include/asm/ptrace.h - * arch/arm64/include/uapi/asm/ptrace.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -/* Current Exception Level values, as contained in CurrentEL */ -#define CurrentEL_EL1 (1 << 2) -#define CurrentEL_EL2 (2 << 2) - -/* - * PSR bits - */ -#define PSR_MODE_EL0t 0x00000000 -#define PSR_MODE_EL1t 0x00000004 -#define PSR_MODE_EL1h 0x00000005 -#define PSR_MODE_EL2t 0x00000008 -#define PSR_MODE_EL2h 0x00000009 -#define PSR_MODE_EL3t 0x0000000c -#define PSR_MODE_EL3h 0x0000000d -#define PSR_MODE_MASK 0x0000000f - -/* AArch32 CPSR bits */ -#define PSR_MODE32_BIT 0x00000010 - -/* AArch64 SPSR bits */ -#define PSR_F_BIT 0x00000040 -#define PSR_I_BIT 0x00000080 -#define PSR_A_BIT 0x00000100 -#define PSR_D_BIT 0x00000200 -#define PSR_Q_BIT 0x08000000 -#define PSR_V_BIT 0x10000000 -#define PSR_C_BIT 0x20000000 -#define PSR_Z_BIT 0x40000000 -#define PSR_N_BIT 0x80000000 - -/* - * Groups of PSR bits - */ -#define PSR_f 0xff000000 /* Flags */ -#define PSR_s 0x00ff0000 /* Status */ -#define PSR_x 0x0000ff00 /* Extension */ -#define PSR_c 0x000000ff /* Control */ - -#ifndef __ASSEMBLY__ -#include - -struct user_pt_regs { - u64 regs[31]; - u64 sp; - u64 pc; - u64 pstate; -}; - -struct user_fpsimd_state { - __uint128_t vregs[32]; - u32 fpsr; - u32 fpcr; -}; - -/* - * This struct defines the way the registers are stored on the stack during an - * exception. Note that sizeof(struct pt_regs) has to be a multiple of 16 (for - * stack alignment). struct user_pt_regs must form a prefix of struct pt_regs. - */ -struct pt_regs { - union { - struct user_pt_regs user_regs; - struct { - u64 regs[31]; - u64 sp; - u64 pc; - u64 pstate; - }; - }; - u64 orig_x0; - u64 syscallno; -}; - -#define user_mode(regs) \ - (((regs)->pstate & PSR_MODE_MASK) == PSR_MODE_EL0t) - -#define processor_mode(regs) \ - ((regs)->pstate & PSR_MODE_MASK) - -#define interrupts_enabled(regs) \ - (!((regs)->pstate & PSR_I_BIT)) - -#define fast_interrupts_enabled(regs) \ - (!((regs)->pstate & PSR_F_BIT)) - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMARM64_PTRACE_H_ */ diff --git a/lib/arm64/asm/setup.h b/lib/arm64/asm/setup.h deleted file mode 100644 index e3b47027..00000000 --- a/lib/arm64/asm/setup.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../arm/asm/setup.h" diff --git a/lib/arm64/asm/smp.h b/lib/arm64/asm/smp.h deleted file mode 100644 index e6cdaf48..00000000 --- a/lib/arm64/asm/smp.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../arm/asm/smp.h" diff --git a/lib/arm64/asm/spinlock.h b/lib/arm64/asm/spinlock.h deleted file mode 100644 index 43b2634b..00000000 --- a/lib/arm64/asm/spinlock.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _ASMARM64_SPINLOCK_H_ -#define _ASMARM64_SPINLOCK_H_ - -struct spinlock { - int v; -}; - -extern void spin_lock(struct spinlock *lock); -extern void spin_unlock(struct spinlock *lock); - -#endif /* _ASMARM64_SPINLOCK_H_ */ diff --git a/lib/arm64/asm/stack.h b/lib/arm64/asm/stack.h deleted file mode 100644 index d0006242..00000000 --- a/lib/arm64/asm/stack.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _ASMARM64_STACK_H_ -#define _ASMARM64_STACK_H_ - -#ifndef _STACK_H_ -#error Do not directly include . Just use . -#endif - -#endif diff --git a/lib/arm64/asm/sysreg.h b/lib/arm64/asm/sysreg.h deleted file mode 100644 index 378bf7eb..00000000 --- a/lib/arm64/asm/sysreg.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Ripped off from arch/arm64/include/asm/sysreg.h - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#ifndef _ASMARM64_SYSREG_H_ -#define _ASMARM64_SYSREG_H_ - -#define sys_reg(op0, op1, crn, crm, op2) \ - ((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5)) - -#ifdef __ASSEMBLY__ - .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 - .equ .L__reg_num_x\num, \num - .endr - .equ .L__reg_num_xzr, 31 - - .macro mrs_s, rt, sreg - .inst 0xd5200000|(\sreg)|(.L__reg_num_\rt) - .endm - - .macro msr_s, sreg, rt - .inst 0xd5000000|(\sreg)|(.L__reg_num_\rt) - .endm -#else -#include - -#define read_sysreg(r) ({ \ - u64 __val; \ - asm volatile("mrs %0, " xstr(r) : "=r" (__val)); \ - __val; \ -}) - -#define write_sysreg(v, r) do { \ - u64 __val = (u64)v; \ - asm volatile("msr " xstr(r) ", %x0" : : "rZ" (__val)); \ -} while (0) - -#define read_sysreg_s(r) ({ \ - u64 __val; \ - asm volatile("mrs_s %0, " xstr(r) : "=r" (__val)); \ - __val; \ -}) - -#define write_sysreg_s(v, r) do { \ - u64 __val = (u64)v; \ - asm volatile("msr_s " xstr(r) ", %x0" : : "rZ" (__val));\ -} while (0) - -#define write_regn_el0(__reg, __n, __val) \ - write_sysreg((__val), __reg ## __n ## _el0) - -#define read_regn_el0(__reg, __n) \ - read_sysreg(__reg ## __n ## _el0) - -asm( -" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n" -" .equ .L__reg_num_x\\num, \\num\n" -" .endr\n" -" .equ .L__reg_num_xzr, 31\n" -"\n" -" .macro mrs_s, rt, sreg\n" -" .inst 0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n" -" .endm\n" -"\n" -" .macro msr_s, sreg, rt\n" -" .inst 0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n" -" .endm\n" -); -#endif /* __ASSEMBLY__ */ -#endif /* _ASMARM64_SYSREG_H_ */ diff --git a/lib/arm64/asm/thread_info.h b/lib/arm64/asm/thread_info.h deleted file mode 100644 index b01fa8f3..00000000 --- a/lib/arm64/asm/thread_info.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../arm/asm/thread_info.h" diff --git a/lib/arm64/gic-v3-its-cmd.c b/lib/arm64/gic-v3-its-cmd.c deleted file mode 100644 index 2c208d13..00000000 --- a/lib/arm64/gic-v3-its-cmd.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (C) 2020, Red Hat Inc, Eric Auger - * - * Most of the code is copy-pasted from: - * drivers/irqchip/irq-gic-v3-its.c - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include - -#define ITS_ITT_ALIGN SZ_256 - -static const char * const its_cmd_string[] = { - [GITS_CMD_MAPD] = "MAPD", - [GITS_CMD_MAPC] = "MAPC", - [GITS_CMD_MAPTI] = "MAPTI", - [GITS_CMD_MAPI] = "MAPI", - [GITS_CMD_MOVI] = "MOVI", - [GITS_CMD_DISCARD] = "DISCARD", - [GITS_CMD_INV] = "INV", - [GITS_CMD_MOVALL] = "MOVALL", - [GITS_CMD_INVALL] = "INVALL", - [GITS_CMD_INT] = "INT", - [GITS_CMD_CLEAR] = "CLEAR", - [GITS_CMD_SYNC] = "SYNC", -}; - -struct its_cmd_desc { - union { - struct { - struct its_device *dev; - u32 event_id; - } its_inv_cmd; - - struct { - struct its_device *dev; - u32 event_id; - } its_int_cmd; - - struct { - struct its_device *dev; - bool valid; - } its_mapd_cmd; - - struct { - struct its_collection *col; - bool valid; - } its_mapc_cmd; - - struct { - struct its_device *dev; - u32 phys_id; - u32 event_id; - u32 col_id; - } its_mapti_cmd; - - struct { - struct its_device *dev; - struct its_collection *col; - u32 event_id; - } its_movi_cmd; - - struct { - struct its_device *dev; - u32 event_id; - } its_discard_cmd; - - struct { - struct its_device *dev; - u32 event_id; - } its_clear_cmd; - - struct { - struct its_collection *col; - } its_invall_cmd; - - struct { - struct its_collection *col; - } its_sync_cmd; - }; - bool verbose; -}; - -typedef void (*its_cmd_builder_t)(struct its_cmd_block *, - struct its_cmd_desc *); - -/* ITS COMMANDS */ - -static void its_mask_encode(u64 *raw_cmd, u64 val, int h, int l) -{ - u64 mask = GENMASK_ULL(h, l); - *raw_cmd &= ~mask; - *raw_cmd |= (val << l) & mask; -} - -static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr) -{ - its_mask_encode(&cmd->raw_cmd[0], cmd_nr, 7, 0); -} - -static void its_encode_devid(struct its_cmd_block *cmd, u32 devid) -{ - its_mask_encode(&cmd->raw_cmd[0], devid, 63, 32); -} - -static void its_encode_event_id(struct its_cmd_block *cmd, u32 id) -{ - its_mask_encode(&cmd->raw_cmd[1], id, 31, 0); -} - -static void its_encode_phys_id(struct its_cmd_block *cmd, u32 phys_id) -{ - its_mask_encode(&cmd->raw_cmd[1], phys_id, 63, 32); -} - -static void its_encode_size(struct its_cmd_block *cmd, u8 size) -{ - its_mask_encode(&cmd->raw_cmd[1], size, 4, 0); -} - -static void its_encode_itt(struct its_cmd_block *cmd, u64 itt_addr) -{ - its_mask_encode(&cmd->raw_cmd[2], itt_addr >> 8, 50, 8); -} - -static void its_encode_valid(struct its_cmd_block *cmd, int valid) -{ - its_mask_encode(&cmd->raw_cmd[2], !!valid, 63, 63); -} - -static void its_encode_target(struct its_cmd_block *cmd, u64 target_addr) -{ - its_mask_encode(&cmd->raw_cmd[2], target_addr >> 16, 50, 16); -} - -static void its_encode_collection(struct its_cmd_block *cmd, u16 col) -{ - its_mask_encode(&cmd->raw_cmd[2], col, 15, 0); -} - -static inline void its_fixup_cmd(struct its_cmd_block *cmd) -{ - /* Let's fixup BE commands */ - cmd->raw_cmd[0] = cpu_to_le64(cmd->raw_cmd[0]); - cmd->raw_cmd[1] = cpu_to_le64(cmd->raw_cmd[1]); - cmd->raw_cmd[2] = cpu_to_le64(cmd->raw_cmd[2]); - cmd->raw_cmd[3] = cpu_to_le64(cmd->raw_cmd[3]); -} - -static u64 its_cmd_ptr_to_offset(struct its_cmd_block *ptr) -{ - return (ptr - its_data.cmd_base) * sizeof(*ptr); -} - -static struct its_cmd_block *its_post_commands(void) -{ - u64 wr = its_cmd_ptr_to_offset(its_data.cmd_write); - - writeq(wr, its_data.base + GITS_CWRITER); - return its_data.cmd_write; -} - -static struct its_cmd_block *its_allocate_entry(void) -{ - struct its_cmd_block *cmd; - - assert((u64)its_data.cmd_write < (u64)its_data.cmd_base + SZ_64K); - cmd = its_data.cmd_write++; - return cmd; -} - -static void its_wait_for_range_completion(struct its_cmd_block *from, - struct its_cmd_block *to) -{ - u64 rd_idx, from_idx, to_idx; - u32 count = 1000000; /* 1s! */ - - from_idx = its_cmd_ptr_to_offset(from); - to_idx = its_cmd_ptr_to_offset(to); - while (1) { - rd_idx = readq(its_data.base + GITS_CREADR); - if (rd_idx >= to_idx || rd_idx < from_idx) - break; - - count--; - if (!count) { - unsigned int cmd_id = from->raw_cmd[0] & 0xFF; - - assert_msg(false, "%s timeout!", - cmd_id <= 0xF ? its_cmd_string[cmd_id] : - "Unexpected"); - } - udelay(1); - } -} - -static void its_send_single_command(its_cmd_builder_t builder, - struct its_cmd_desc *desc) -{ - struct its_cmd_block *cmd, *next_cmd; - - cmd = its_allocate_entry(); - builder(cmd, desc); - next_cmd = its_post_commands(); - - its_wait_for_range_completion(cmd, next_cmd); -} - -static void its_build_mapd_cmd(struct its_cmd_block *cmd, - struct its_cmd_desc *desc) -{ - unsigned long itt_addr; - u8 size = desc->its_mapd_cmd.dev->nr_ites; - - itt_addr = (unsigned long)(virt_to_phys(desc->its_mapd_cmd.dev->itt)); - itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN); - - its_encode_cmd(cmd, GITS_CMD_MAPD); - its_encode_devid(cmd, desc->its_mapd_cmd.dev->device_id); - its_encode_size(cmd, size - 1); - its_encode_itt(cmd, itt_addr); - its_encode_valid(cmd, desc->its_mapd_cmd.valid); - its_fixup_cmd(cmd); - if (desc->verbose) - printf("ITS: MAPD devid=%d size = 0x%x itt=0x%lx valid=%d\n", - desc->its_mapd_cmd.dev->device_id, - size, itt_addr, desc->its_mapd_cmd.valid); -} - -static void its_build_mapc_cmd(struct its_cmd_block *cmd, - struct its_cmd_desc *desc) -{ - its_encode_cmd(cmd, GITS_CMD_MAPC); - its_encode_collection(cmd, desc->its_mapc_cmd.col->col_id); - its_encode_target(cmd, desc->its_mapc_cmd.col->target_address); - its_encode_valid(cmd, desc->its_mapc_cmd.valid); - its_fixup_cmd(cmd); - if (desc->verbose) - printf("MAPC col_id=%d target_addr = 0x%lx valid=%d\n", - desc->its_mapc_cmd.col->col_id, - desc->its_mapc_cmd.col->target_address, - desc->its_mapc_cmd.valid); -} - -static void its_build_mapti_cmd(struct its_cmd_block *cmd, - struct its_cmd_desc *desc) -{ - its_encode_cmd(cmd, GITS_CMD_MAPTI); - its_encode_devid(cmd, desc->its_mapti_cmd.dev->device_id); - its_encode_event_id(cmd, desc->its_mapti_cmd.event_id); - its_encode_phys_id(cmd, desc->its_mapti_cmd.phys_id); - its_encode_collection(cmd, desc->its_mapti_cmd.col_id); - its_fixup_cmd(cmd); - if (desc->verbose) - printf("MAPTI dev_id=%d event_id=%d -> phys_id=%d, col_id=%d\n", - desc->its_mapti_cmd.dev->device_id, - desc->its_mapti_cmd.event_id, - desc->its_mapti_cmd.phys_id, - desc->its_mapti_cmd.col_id); -} - -static void its_build_invall_cmd(struct its_cmd_block *cmd, - struct its_cmd_desc *desc) -{ - its_encode_cmd(cmd, GITS_CMD_INVALL); - its_encode_collection(cmd, desc->its_invall_cmd.col->col_id); - its_fixup_cmd(cmd); - if (desc->verbose) - printf("INVALL col_id=%d\n", desc->its_invall_cmd.col->col_id); -} - -static void its_build_clear_cmd(struct its_cmd_block *cmd, - struct its_cmd_desc *desc) -{ - its_encode_cmd(cmd, GITS_CMD_CLEAR); - its_encode_devid(cmd, desc->its_clear_cmd.dev->device_id); - its_encode_event_id(cmd, desc->its_clear_cmd.event_id); - its_fixup_cmd(cmd); - if (desc->verbose) - printf("CLEAR dev_id=%d event_id=%d\n", desc->its_clear_cmd.dev->device_id, desc->its_clear_cmd.event_id); -} - -static void its_build_discard_cmd(struct its_cmd_block *cmd, - struct its_cmd_desc *desc) -{ - its_encode_cmd(cmd, GITS_CMD_DISCARD); - its_encode_devid(cmd, desc->its_discard_cmd.dev->device_id); - its_encode_event_id(cmd, desc->its_discard_cmd.event_id); - its_fixup_cmd(cmd); - if (desc->verbose) - printf("DISCARD dev_id=%d event_id=%d\n", - desc->its_clear_cmd.dev->device_id, desc->its_clear_cmd.event_id); -} - -static void its_build_inv_cmd(struct its_cmd_block *cmd, - struct its_cmd_desc *desc) -{ - its_encode_cmd(cmd, GITS_CMD_INV); - its_encode_devid(cmd, desc->its_inv_cmd.dev->device_id); - its_encode_event_id(cmd, desc->its_inv_cmd.event_id); - its_fixup_cmd(cmd); - if (desc->verbose) - printf("INV dev_id=%d event_id=%d\n", - desc->its_inv_cmd.dev->device_id, - desc->its_inv_cmd.event_id); -} - -static void its_build_int_cmd(struct its_cmd_block *cmd, - struct its_cmd_desc *desc) -{ - its_encode_cmd(cmd, GITS_CMD_INT); - its_encode_devid(cmd, desc->its_int_cmd.dev->device_id); - its_encode_event_id(cmd, desc->its_int_cmd.event_id); - its_fixup_cmd(cmd); - if (desc->verbose) - printf("INT dev_id=%d event_id=%d\n", - desc->its_int_cmd.dev->device_id, - desc->its_int_cmd.event_id); -} - -static void its_build_sync_cmd(struct its_cmd_block *cmd, - struct its_cmd_desc *desc) -{ - its_encode_cmd(cmd, GITS_CMD_SYNC); - its_encode_target(cmd, desc->its_sync_cmd.col->target_address); - its_fixup_cmd(cmd); - if (desc->verbose) - printf("SYNC target_addr = 0x%lx\n", - desc->its_sync_cmd.col->target_address); -} - -static void its_build_movi_cmd(struct its_cmd_block *cmd, - struct its_cmd_desc *desc) -{ - its_encode_cmd(cmd, GITS_CMD_MOVI); - its_encode_devid(cmd, desc->its_movi_cmd.dev->device_id); - its_encode_event_id(cmd, desc->its_movi_cmd.event_id); - its_encode_collection(cmd, desc->its_movi_cmd.col->col_id); - its_fixup_cmd(cmd); - if (desc->verbose) - printf("MOVI dev_id=%d event_id = %d col_id=%d\n", - desc->its_movi_cmd.dev->device_id, - desc->its_movi_cmd.event_id, - desc->its_movi_cmd.col->col_id); -} - -void __its_send_mapd(struct its_device *dev, int valid, bool verbose) -{ - struct its_cmd_desc desc; - - desc.its_mapd_cmd.dev = dev; - desc.its_mapd_cmd.valid = !!valid; - desc.verbose = verbose; - - its_send_single_command(its_build_mapd_cmd, &desc); -} - -void __its_send_mapc(struct its_collection *col, int valid, bool verbose) -{ - struct its_cmd_desc desc; - - desc.its_mapc_cmd.col = col; - desc.its_mapc_cmd.valid = !!valid; - desc.verbose = verbose; - - its_send_single_command(its_build_mapc_cmd, &desc); -} - -void __its_send_mapti(struct its_device *dev, u32 irq_id, - u32 event_id, struct its_collection *col, bool verbose) -{ - struct its_cmd_desc desc; - - desc.its_mapti_cmd.dev = dev; - desc.its_mapti_cmd.phys_id = irq_id; - desc.its_mapti_cmd.event_id = event_id; - desc.its_mapti_cmd.col_id = col->col_id; - desc.verbose = verbose; - - its_send_single_command(its_build_mapti_cmd, &desc); -} - -void __its_send_int(struct its_device *dev, u32 event_id, bool verbose) -{ - struct its_cmd_desc desc; - - desc.its_int_cmd.dev = dev; - desc.its_int_cmd.event_id = event_id; - desc.verbose = verbose; - - its_send_single_command(its_build_int_cmd, &desc); -} - -void __its_send_movi(struct its_device *dev, struct its_collection *col, - u32 id, bool verbose) -{ - struct its_cmd_desc desc; - - desc.its_movi_cmd.dev = dev; - desc.its_movi_cmd.col = col; - desc.its_movi_cmd.event_id = id; - desc.verbose = verbose; - - its_send_single_command(its_build_movi_cmd, &desc); -} - -void __its_send_invall(struct its_collection *col, bool verbose) -{ - struct its_cmd_desc desc; - - desc.its_invall_cmd.col = col; - desc.verbose = verbose; - - its_send_single_command(its_build_invall_cmd, &desc); -} - -void __its_send_inv(struct its_device *dev, u32 event_id, bool verbose) -{ - struct its_cmd_desc desc; - - desc.its_inv_cmd.dev = dev; - desc.its_inv_cmd.event_id = event_id; - desc.verbose = verbose; - - its_send_single_command(its_build_inv_cmd, &desc); -} - -void __its_send_discard(struct its_device *dev, u32 event_id, bool verbose) -{ - struct its_cmd_desc desc; - - desc.its_discard_cmd.dev = dev; - desc.its_discard_cmd.event_id = event_id; - desc.verbose = verbose; - - its_send_single_command(its_build_discard_cmd, &desc); -} - -void __its_send_clear(struct its_device *dev, u32 event_id, bool verbose) -{ - struct its_cmd_desc desc; - - desc.its_clear_cmd.dev = dev; - desc.its_clear_cmd.event_id = event_id; - desc.verbose = verbose; - - its_send_single_command(its_build_clear_cmd, &desc); -} - -void __its_send_sync(struct its_collection *col, bool verbose) -{ - struct its_cmd_desc desc; - - desc.its_sync_cmd.col = col; - desc.verbose = verbose; - - its_send_single_command(its_build_sync_cmd, &desc); -} - diff --git a/lib/arm64/gic-v3-its.c b/lib/arm64/gic-v3-its.c deleted file mode 100644 index c22bda3a..00000000 --- a/lib/arm64/gic-v3-its.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2020, Red Hat Inc, Eric Auger - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include - -void its_parse_typer(void) -{ - u64 typer = readq(gicv3_its_base() + GITS_TYPER); - struct its_typer *t = &its_data.typer; - - t->ite_size = ((typer & GITS_TYPER_ITT_ENTRY_SIZE) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) + 1; - t->pta = typer & GITS_TYPER_PTA; - t->eventid_bits = ((typer & GITS_TYPER_IDBITS) >> GITS_TYPER_IDBITS_SHIFT) + 1; - t->deviceid_bits = ((typer & GITS_TYPER_DEVBITS) >> GITS_TYPER_DEVBITS_SHIFT) + 1; - - if (typer & GITS_TYPER_CIL) - t->collid_bits = ((typer & GITS_TYPER_CIDBITS) >> GITS_TYPER_CIDBITS_SHIFT) + 1; - else - t->collid_bits = 16; - - t->virt_lpi = typer & GITS_TYPER_VLPIS; - t->phys_lpi = typer & GITS_TYPER_PLPIS; -} - -int its_baser_lookup(int type, struct its_baser *baser) -{ - int i; - - for (i = 0; i < GITS_BASER_NR_REGS; i++) { - void *reg_addr = gicv3_its_base() + GITS_BASER + i * 8; - u64 val = readq(reg_addr); - - if (GITS_BASER_TYPE(val) == type) { - assert((val & GITS_BASER_PAGE_SIZE_MASK) == GITS_BASER_PAGE_SIZE_64K); - baser->esz = GITS_BASER_ENTRY_SIZE(val); - baser->indirect = val & GITS_BASER_INDIRECT; - baser->index = i; - return 0; - } - } - return -1; -} - -/* - * Allocate the BASER table (a single page of size @baser->psz) - * and set the BASER valid - */ -static void its_baser_alloc_table(struct its_baser *baser, size_t size) -{ - unsigned long order = get_order(size >> PAGE_SHIFT); - void *reg_addr = gicv3_its_base() + GITS_BASER + baser->index * 8; - u64 val = readq(reg_addr); - - baser->table_addr = alloc_pages(order); - - val |= virt_to_phys(baser->table_addr) | GITS_BASER_VALID; - - writeq(val, reg_addr); -} - -/* - * init_cmd_queue - Allocate the command queue and initialize - * CBASER, CWRITER - */ -static void its_cmd_queue_init(void) -{ - unsigned long order = get_order(SZ_64K >> PAGE_SHIFT); - u64 cbaser; - - its_data.cmd_base = alloc_pages(order); - - cbaser = virt_to_phys(its_data.cmd_base) | (SZ_64K / SZ_4K - 1) | GITS_CBASER_VALID; - - writeq(cbaser, its_data.base + GITS_CBASER); - - its_data.cmd_write = its_data.cmd_base; - writeq(0, its_data.base + GITS_CWRITER); -} - -void its_init(void) -{ - if (!its_data.base) - return; - - its_parse_typer(); - - assert(!its_baser_lookup(GITS_BASER_TYPE_DEVICE, &its_data.device_baser)); - assert(!its_baser_lookup(GITS_BASER_TYPE_COLLECTION, &its_data.coll_baser)); - - its_baser_alloc_table(&its_data.device_baser, SZ_64K); - its_baser_alloc_table(&its_data.coll_baser, SZ_64K); - - its_cmd_queue_init(); -} - -/* must be called after gicv3_enable_defaults */ -void its_enable_defaults(void) -{ - int cpu; - - /* Allocate LPI config and pending tables */ - gicv3_lpi_alloc_tables(); - - for_each_present_cpu(cpu) - gicv3_lpi_rdist_enable(cpu); - - writel(GITS_CTLR_ENABLE, its_data.base + GITS_CTLR); -} - -struct its_device *its_create_device(u32 device_id, int nr_ites) -{ - struct its_device *new; - unsigned long n; - - assert(its_data.nr_devices < GITS_MAX_DEVICES); - - new = &its_data.devices[its_data.nr_devices]; - - new->device_id = device_id; - new->nr_ites = nr_ites; - - n = (its_data.typer.ite_size * nr_ites) >> PAGE_SHIFT; - new->itt = alloc_pages(get_order(n)); - - its_data.nr_devices++; - return new; -} - -struct its_collection *its_create_collection(u16 col_id, u32 pe) -{ - struct its_collection *new; - - assert(its_data.nr_collections < GITS_MAX_COLLECTIONS); - - new = &its_data.collections[its_data.nr_collections]; - - new->col_id = col_id; - - if (its_data.typer.pta) - new->target_address = (u64)gicv3_data.redist_base[pe]; - else - new->target_address = pe << 16; - - its_data.nr_collections++; - return new; -} - -struct its_device *its_get_device(u32 id) -{ - int i; - - for (i = 0; i < GITS_MAX_DEVICES; i++) { - if (its_data.devices[i].device_id == id) - return &its_data.devices[i]; - } - assert(0); -} - -struct its_collection *its_get_collection(u32 id) -{ - int i; - - for (i = 0; i < GITS_MAX_COLLECTIONS; i++) { - if (its_data.collections[i].col_id == id) - return &its_data.collections[i]; - } - assert(0); -} diff --git a/lib/arm64/processor.c b/lib/arm64/processor.c deleted file mode 100644 index 2a024e3f..00000000 --- a/lib/arm64/processor.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * processor control and status functions - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include - -static const char *vector_names[] = { - "el1t_sync", - "el1t_irq", - "el1t_fiq", - "el1t_error", - "el1h_sync", - "el1h_irq", - "el1h_fiq", - "el1h_error", - "el0_sync_64", - "el0_irq_64", - "el0_fiq_64", - "el0_error_64", - "el0_sync_32", - "el0_irq_32", - "el0_fiq_32", - "el0_error_32", -}; - -static const char *ec_names[EC_MAX] = { - [ESR_EL1_EC_UNKNOWN] = "UNKNOWN", - [ESR_EL1_EC_WFI] = "WFI", - [ESR_EL1_EC_CP15_32] = "CP15_32", - [ESR_EL1_EC_CP15_64] = "CP15_64", - [ESR_EL1_EC_CP14_MR] = "CP14_MR", - [ESR_EL1_EC_CP14_LS] = "CP14_LS", - [ESR_EL1_EC_FP_ASIMD] = "FP_ASMID", - [ESR_EL1_EC_CP10_ID] = "CP10_ID", - [ESR_EL1_EC_CP14_64] = "CP14_64", - [ESR_EL1_EC_ILL_ISS] = "ILL_ISS", - [ESR_EL1_EC_SVC32] = "SVC32", - [ESR_EL1_EC_SVC64] = "SVC64", - [ESR_EL1_EC_SYS64] = "SYS64", - [ESR_EL1_EC_IABT_EL0] = "IABT_EL0", - [ESR_EL1_EC_IABT_EL1] = "IABT_EL1", - [ESR_EL1_EC_PC_ALIGN] = "PC_ALIGN", - [ESR_EL1_EC_DABT_EL0] = "DABT_EL0", - [ESR_EL1_EC_DABT_EL1] = "DABT_EL1", - [ESR_EL1_EC_SP_ALIGN] = "SP_ALIGN", - [ESR_EL1_EC_FP_EXC32] = "FP_EXC32", - [ESR_EL1_EC_FP_EXC64] = "FP_EXC64", - [ESR_EL1_EC_SERROR] = "SERROR", - [ESR_EL1_EC_BREAKPT_EL0] = "BREAKPT_EL0", - [ESR_EL1_EC_BREAKPT_EL1] = "BREAKPT_EL1", - [ESR_EL1_EC_SOFTSTP_EL0] = "SOFTSTP_EL0", - [ESR_EL1_EC_SOFTSTP_EL1] = "SOFTSTP_EL1", - [ESR_EL1_EC_WATCHPT_EL0] = "WATCHPT_EL0", - [ESR_EL1_EC_WATCHPT_EL1] = "WATCHPT_EL1", - [ESR_EL1_EC_BKPT32] = "BKPT32", - [ESR_EL1_EC_BRK64] = "BRK64", -}; - -void show_regs(struct pt_regs *regs) -{ - int i; - - printf("pc : [<%016lx>] lr : [<%016lx>] pstate: %08lx\n", - regs->pc, regs->regs[30], regs->pstate); - printf("sp : %016lx\n", regs->sp); - - for (i = 29; i >= 0; --i) { - printf("x%-2d: %016lx ", i, regs->regs[i]); - if (i % 2 == 0) - printf("\n"); - } - printf("\n"); -} - -bool get_far(unsigned int esr, unsigned long *far) -{ - unsigned int ec = esr >> ESR_EL1_EC_SHIFT; - - asm volatile("mrs %0, far_el1": "=r" (*far)); - - switch (ec) { - case ESR_EL1_EC_IABT_EL0: - case ESR_EL1_EC_IABT_EL1: - case ESR_EL1_EC_PC_ALIGN: - case ESR_EL1_EC_DABT_EL0: - case ESR_EL1_EC_DABT_EL1: - case ESR_EL1_EC_WATCHPT_EL0: - case ESR_EL1_EC_WATCHPT_EL1: - if ((esr & 0x3f /* DFSC */) != 0x10 - || !(esr & 0x400 /* FnV */)) - return true; - } - return false; -} - -static void bad_exception(enum vector v, struct pt_regs *regs, - unsigned int esr, bool esr_valid, bool bad_vector) -{ - unsigned long far; - bool far_valid = get_far(esr, &far); - unsigned int ec = esr >> ESR_EL1_EC_SHIFT; - - if (bad_vector) { - if (v < VECTOR_MAX) - printf("Unhandled vector %d (%s)\n", v, - vector_names[v]); - else - printf("Got bad vector=%d\n", v); - } else if (esr_valid) { - if (ec_names[ec]) - printf("Unhandled exception ec=%#x (%s)\n", ec, - ec_names[ec]); - else - printf("Got bad ec=%#x\n", ec); - } - - printf("Vector: %d (%s)\n", v, vector_names[v]); - printf("ESR_EL1: %8s%08x, ec=%#x (%s)\n", "", esr, ec, ec_names[ec]); - printf("FAR_EL1: %016lx (%svalid)\n", far, far_valid ? "" : "not "); - printf("Exception frame registers:\n"); - show_regs(regs); - abort(); -} - -void install_exception_handler(enum vector v, unsigned int ec, exception_fn fn) -{ - struct thread_info *ti = current_thread_info(); - - if (v < VECTOR_MAX && ec < EC_MAX) - ti->exception_handlers[v][ec] = fn; -} - -void install_irq_handler(enum vector v, irq_handler_fn fn) -{ - struct thread_info *ti = current_thread_info(); - - if (v < VECTOR_MAX) - ti->exception_handlers[v][0] = (exception_fn)fn; -} - -void default_vector_sync_handler(enum vector v, struct pt_regs *regs, - unsigned int esr) -{ - struct thread_info *ti = thread_info_sp(regs->sp); - unsigned int ec = esr >> ESR_EL1_EC_SHIFT; - - if (ti->flags & TIF_USER_MODE) { - if (ec < EC_MAX && ti->exception_handlers[v][ec]) { - ti->exception_handlers[v][ec](regs, esr); - return; - } - ti = current_thread_info(); - } - - if (ec < EC_MAX && ti->exception_handlers[v][ec]) - ti->exception_handlers[v][ec](regs, esr); - else - bad_exception(v, regs, esr, true, false); -} - -void default_vector_irq_handler(enum vector v, struct pt_regs *regs, - unsigned int esr) -{ - struct thread_info *ti = thread_info_sp(regs->sp); - irq_handler_fn irq_handler = - (irq_handler_fn)ti->exception_handlers[v][0]; - - if (ti->flags & TIF_USER_MODE) { - if (irq_handler) { - irq_handler(regs); - return; - } - ti = current_thread_info(); - irq_handler = (irq_handler_fn)ti->exception_handlers[v][0]; - } - - if (irq_handler) - irq_handler(regs); - else - bad_exception(v, regs, esr, false, false); -} - -void vector_handlers_default_init(vector_fn *handlers) -{ - handlers[EL1H_SYNC] = default_vector_sync_handler; - handlers[EL1H_IRQ] = default_vector_irq_handler; - handlers[EL0_SYNC_64] = default_vector_sync_handler; - handlers[EL0_IRQ_64] = default_vector_irq_handler; -} - -/* Needed to compile with -Wmissing-prototypes */ -void do_handle_exception(enum vector v, struct pt_regs *regs, unsigned int esr); - -void do_handle_exception(enum vector v, struct pt_regs *regs, unsigned int esr) -{ - struct thread_info *ti = thread_info_sp(regs->sp); - - if (ti->flags & TIF_USER_MODE) { - if (v < VECTOR_MAX && ti->vector_handlers[v]) { - ti->vector_handlers[v](v, regs, esr); - return; - } - ti = current_thread_info(); - } - - if (v < VECTOR_MAX && ti->vector_handlers[v]) - ti->vector_handlers[v](v, regs, esr); - else - bad_exception(v, regs, esr, true, true); -} - -void install_vector_handler(enum vector v, vector_fn fn) -{ - struct thread_info *ti = current_thread_info(); - - if (v < VECTOR_MAX) - ti->vector_handlers[v] = fn; -} - -static void __thread_info_init(struct thread_info *ti, unsigned int flags) -{ - memset(ti, 0, sizeof(struct thread_info)); - ti->cpu = mpidr_to_cpu(get_mpidr()); - ti->flags = flags; -} - -void thread_info_init(struct thread_info *ti, unsigned int flags) -{ - __thread_info_init(ti, flags); - vector_handlers_default_init(ti->vector_handlers); -} - -void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr) -{ - sp_usr &= (~15UL); /* stack ptr needs 16-byte alignment */ - - __thread_info_init(thread_info_sp(sp_usr), TIF_USER_MODE); - thread_info_sp(sp_usr)->pgtable = current_thread_info()->pgtable; - - asm volatile( - "mov x0, %0\n" - "msr sp_el0, %1\n" - "msr elr_el1, %2\n" - "mov x3, xzr\n" /* clear and "set" PSR_MODE_EL0t */ - "msr spsr_el1, x3\n" - "eret\n" - :: "r" (arg), "r" (sp_usr), "r" (func) : "x0", "x3"); -} - -bool is_user(void) -{ - return current_thread_info()->flags & TIF_USER_MODE; -} diff --git a/lib/arm64/spinlock.c b/lib/arm64/spinlock.c deleted file mode 100644 index fac4fc9a..00000000 --- a/lib/arm64/spinlock.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * spinlocks - * - * Copyright (C) 2015, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include - -void spin_lock(struct spinlock *lock) -{ - u32 val, fail; - - if (!mmu_enabled()) { - lock->v = 1; - smp_mb(); - return; - } - - do { - asm volatile( - "1: ldaxr %w0, [%2]\n" - " cbnz %w0, 1b\n" - " mov %0, #1\n" - " stxr %w1, %w0, [%2]\n" - : "=&r" (val), "=&r" (fail) - : "r" (&lock->v) - : "cc" ); - } while (fail); - smp_mb(); -} - -void spin_unlock(struct spinlock *lock) -{ - smp_mb(); - if (mmu_enabled()) - asm volatile("stlrh wzr, [%0]" :: "r" (&lock->v)); - else - lock->v = 0; -} diff --git a/lib/asm-generic/atomic.h b/lib/asm-generic/atomic.h deleted file mode 100644 index 26b645a7..00000000 --- a/lib/asm-generic/atomic.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __ASM_GENERIC_ATOMIC_H__ -#define __ASM_GENERIC_ATOMIC_H__ - -/* From QEMU include/qemu/atomic.h */ -#define atomic_fetch_inc(ptr) __sync_fetch_and_add(ptr, 1) -#define atomic_fetch_dec(ptr) __sync_fetch_and_add(ptr, -1) -#define atomic_fetch_add(ptr, n) __sync_fetch_and_add(ptr, n) -#define atomic_fetch_sub(ptr, n) __sync_fetch_and_sub(ptr, n) -#define atomic_fetch_and(ptr, n) __sync_fetch_and_and(ptr, n) -#define atomic_fetch_or(ptr, n) __sync_fetch_and_or(ptr, n) -#define atomic_fetch_xor(ptr, n) __sync_fetch_and_xor(ptr, n) - -#define atomic_inc_fetch(ptr) __sync_add_and_fetch(ptr, 1) -#define atomic_dec_fetch(ptr) __sync_add_and_fetch(ptr, -1) -#define atomic_add_fetch(ptr, n) __sync_add_and_fetch(ptr, n) -#define atomic_sub_fetch(ptr, n) __sync_sub_and_fetch(ptr, n) -#define atomic_and_fetch(ptr, n) __sync_and_and_fetch(ptr, n) -#define atomic_or_fetch(ptr, n) __sync_or_and_fetch(ptr, n) -#define atomic_xor_fetch(ptr, n) __sync_xor_and_fetch(ptr, n) - -#endif diff --git a/lib/asm-generic/barrier.h b/lib/asm-generic/barrier.h deleted file mode 100644 index 6a990ff8..00000000 --- a/lib/asm-generic/barrier.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _ASM_BARRIER_H_ -#define _ASM_BARRIER_H_ -/* - * asm-generic/barrier.h - * - * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ - -#ifndef mb -#define mb() asm volatile("":::"memory") -#endif -#ifndef rmb -#define rmb() asm volatile("":::"memory") -#endif -#ifndef wmb -#define wmb() asm volatile("":::"memory") -#endif - -#ifndef smp_mb -#define smp_mb() mb() -#endif -#ifndef smp_rmb -#define smp_rmb() rmb() -#endif -#ifndef smp_wmb -#define smp_wmb() wmb() -#endif - -#ifndef cpu_relax -#define cpu_relax() asm volatile ("":::"memory") -#endif - -#endif /* _ASM_BARRIER_H_ */ diff --git a/lib/asm-generic/io.h b/lib/asm-generic/io.h deleted file mode 100644 index 88972f3b..00000000 --- a/lib/asm-generic/io.h +++ /dev/null @@ -1,213 +0,0 @@ -#ifndef _ASM_GENERIC_IO_H_ -#define _ASM_GENERIC_IO_H_ -/* - * asm-generic/io.h - * adapted from the Linux kernel's include/asm-generic/io.h - * and arch/arm/include/asm/io.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include "libcflat.h" -#include "asm/page.h" -#include "asm/barrier.h" - -#ifndef __raw_readb -static inline u8 __raw_readb(const volatile void *addr) -{ - return *(const volatile u8 *)addr; -} -#endif - -#ifndef __raw_readw -static inline u16 __raw_readw(const volatile void *addr) -{ - return *(const volatile u16 *)addr; -} -#endif - -#ifndef __raw_readl -static inline u32 __raw_readl(const volatile void *addr) -{ - return *(const volatile u32 *)addr; -} -#endif - -#ifndef __raw_readq -static inline u64 __raw_readq(const volatile void *addr) -{ - assert(sizeof(unsigned long) == sizeof(u64)); - return *(const volatile u64 *)addr; -} -#endif - -#ifndef __raw_writeb -static inline void __raw_writeb(u8 b, volatile void *addr) -{ - *(volatile u8 *)addr = b; -} -#endif - -#ifndef __raw_writew -static inline void __raw_writew(u16 b, volatile void *addr) -{ - *(volatile u16 *)addr = b; -} -#endif - -#ifndef __raw_writel -static inline void __raw_writel(u32 b, volatile void *addr) -{ - *(volatile u32 *)addr = b; -} -#endif - -#ifndef __raw_writeq -static inline void __raw_writeq(u64 b, volatile void *addr) -{ - assert(sizeof(unsigned long) == sizeof(u64)); - *(volatile u64 *)addr = b; -} -#endif - -#ifndef __bswap16 -static inline u16 __bswap16(u16 x) -{ - return ((x >> 8) & 0xff) | ((x & 0xff) << 8); -} -#endif - -#ifndef __bswap32 -static inline u32 __bswap32(u32 x) -{ - return ((x & 0xff000000) >> 24) | ((x & 0x00ff0000) >> 8) | - ((x & 0x0000ff00) << 8) | ((x & 0x000000ff) << 24); -} -#endif - -#ifndef __bswap64 -static inline u64 __bswap64(u64 x) -{ - return ((x & 0x00000000000000ffULL) << 56) | - ((x & 0x000000000000ff00ULL) << 40) | - ((x & 0x0000000000ff0000ULL) << 24) | - ((x & 0x00000000ff000000ULL) << 8) | - ((x & 0x000000ff00000000ULL) >> 8) | - ((x & 0x0000ff0000000000ULL) >> 24) | - ((x & 0x00ff000000000000ULL) >> 40) | - ((x & 0xff00000000000000ULL) >> 56); -} -#endif - -#ifndef __cpu_is_be -#define __cpu_is_be() (0) -#endif - -#define le16_to_cpu(x) \ - ({ u16 __r = __cpu_is_be() ? __bswap16(x) : ((u16)x); __r; }) -#define cpu_to_le16 le16_to_cpu - -#define le32_to_cpu(x) \ - ({ u32 __r = __cpu_is_be() ? __bswap32(x) : ((u32)x); __r; }) -#define cpu_to_le32 le32_to_cpu - -#define le64_to_cpu(x) \ - ({ u64 __r = __cpu_is_be() ? __bswap64(x) : ((u64)x); __r; }) -#define cpu_to_le64 le64_to_cpu - -#define be16_to_cpu(x) \ - ({ u16 __r = !__cpu_is_be() ? __bswap16(x) : ((u16)x); __r; }) -#define cpu_to_be16 be16_to_cpu - -#define be32_to_cpu(x) \ - ({ u32 __r = !__cpu_is_be() ? __bswap32(x) : ((u32)x); __r; }) -#define cpu_to_be32 be32_to_cpu - -#define be64_to_cpu(x) \ - ({ u64 __r = !__cpu_is_be() ? __bswap64(x) : ((u64)x); __r; }) -#define cpu_to_be64 be64_to_cpu - -#define readb(addr) \ - ({ u8 __r = __raw_readb(addr); rmb(); __r; }) -#define readw(addr) \ - ({ u16 __r = le16_to_cpu(__raw_readw(addr)); rmb(); __r; }) -#define readl(addr) \ - ({ u32 __r = le32_to_cpu(__raw_readl(addr)); rmb(); __r; }) -#define readq(addr) \ - ({ u64 __r = le64_to_cpu(__raw_readq(addr)); rmb(); __r; }) - -#define writeb(b, addr) \ - ({ wmb(); __raw_writeb(b, addr); }) -#define writew(b, addr) \ - ({ wmb(); __raw_writew(cpu_to_le16(b), addr); }) -#define writel(b, addr) \ - ({ wmb(); __raw_writel(cpu_to_le32(b), addr); }) -#define writeq(b, addr) \ - ({ wmb(); __raw_writeq(cpu_to_le64(b), addr); }) - -#ifndef inb -static inline uint8_t inb(unsigned long port) -{ - return readb((const volatile void __iomem *)port); -} -#endif - -#ifndef inw -static inline uint16_t inw(unsigned long port) -{ - return readw((const volatile void __iomem *)port); -} -#endif - -#ifndef inl -static inline uint32_t inl(unsigned long port) -{ - return readl((const volatile void __iomem *)port); -} -#endif - -#ifndef outb -static inline void outb(uint8_t value, unsigned long port) -{ - writeb(value, (volatile void __iomem *)port); -} -#endif - -#ifndef outw -static inline void outw(uint16_t value, unsigned long port) -{ - writew(value, (volatile void __iomem *)port); -} -#endif - -#ifndef outl -static inline void outl(uint32_t value, unsigned long port) -{ - writel(value, (volatile void __iomem *)port); -} -#endif - -#ifndef ioremap -static inline void __iomem *ioremap(phys_addr_t phys_addr, size_t size __unused) -{ - assert(sizeof(long) == 8 || !(phys_addr >> 32)); - return (void __iomem *)(unsigned long)phys_addr; -} -#endif - -#ifndef virt_to_phys -static inline unsigned long virt_to_phys(volatile void *address) -{ - return __pa((unsigned long)address); -} -#endif - -#ifndef phys_to_virt -static inline void *phys_to_virt(unsigned long address) -{ - return __va(address); -} -#endif - -#endif /* _ASM_GENERIC_IO_H_ */ diff --git a/lib/asm-generic/page.h b/lib/asm-generic/page.h deleted file mode 100644 index 5ed08612..00000000 --- a/lib/asm-generic/page.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _ASM_GENERIC_PAGE_H_ -#define _ASM_GENERIC_PAGE_H_ -/* - * asm-generic/page.h - * adapted from the Linux kernel's include/asm-generic/page.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#include - -#define PAGE_SHIFT 12 -#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) - -#ifndef __ASSEMBLY__ - -#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) - -#define __va(x) ((void *)((unsigned long) (x))) -#define __pa(x) ((unsigned long) (x)) -#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) -#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) - -#endif /* !__ASSEMBLY__ */ - -#endif /* _ASM_GENERIC_PAGE_H_ */ diff --git a/lib/asm-generic/pci-host-bridge.h b/lib/asm-generic/pci-host-bridge.h deleted file mode 100644 index 9e91499b..00000000 --- a/lib/asm-generic/pci-host-bridge.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _ASM_PCI_HOST_BRIDGE_H_ -#define _ASM_PCI_HOST_BRIDGE_H_ -/* - * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" - -phys_addr_t pci_host_bridge_get_paddr(uint64_t addr); - -static inline -phys_addr_t pci_translate_addr(pcidevaddr_t dev __unused, uint64_t addr) -{ - /* - * Assume we only have single PCI host bridge in a system. - */ - return pci_host_bridge_get_paddr(addr); -} - -uint8_t pci_config_readb(pcidevaddr_t dev, uint8_t reg); -uint16_t pci_config_readw(pcidevaddr_t dev, uint8_t reg); -uint32_t pci_config_readl(pcidevaddr_t dev, uint8_t reg); -void pci_config_writeb(pcidevaddr_t dev, uint8_t reg, uint8_t val); -void pci_config_writew(pcidevaddr_t dev, uint8_t reg, uint16_t val); -void pci_config_writel(pcidevaddr_t dev, uint8_t reg, uint32_t val); - -#endif diff --git a/lib/asm-generic/pci.h b/lib/asm-generic/pci.h deleted file mode 100644 index 3fa0b2ab..00000000 --- a/lib/asm-generic/pci.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _ASM_GENERIC_PCI_H_ -#define _ASM_GENERIC_PCI_H_ -#error need architecture specific asm/pci.h -#endif diff --git a/lib/asm-generic/spinlock.h b/lib/asm-generic/spinlock.h deleted file mode 100644 index 31fa510e..00000000 --- a/lib/asm-generic/spinlock.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _ASM_GENERIC_SPINLOCK_H_ -#define _ASM_GENERIC_SPINLOCK_H_ - -struct spinlock { - unsigned int v; -}; - -static inline void spin_lock(struct spinlock *lock) -{ - while (__sync_lock_test_and_set(&lock->v, 1)); -} - -static inline void spin_unlock(struct spinlock *lock) -{ - __sync_lock_release(&lock->v); -} - -#endif diff --git a/lib/auxinfo.c b/lib/auxinfo.c deleted file mode 100644 index a6463063..00000000 --- a/lib/auxinfo.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "auxinfo.h" - -#ifndef PROGNAME -#define PROGNAME ((void *)0) -#endif -#ifndef AUXFLAGS -#define AUXFLAGS 0 -#endif - -struct auxinfo auxinfo = { - .progname = PROGNAME, - .flags = AUXFLAGS, -}; diff --git a/lib/auxinfo.h b/lib/auxinfo.h deleted file mode 100644 index a46a1e6f..00000000 --- a/lib/auxinfo.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _AUXINFO_H_ -#define _AUXINFO_H_ - -#define AUXINFO_MMU_OFF (1 << 0) - -#ifndef __ASSEMBLY__ -struct auxinfo { - const char *progname; - unsigned long flags; -}; - -extern struct auxinfo auxinfo; -#endif -#endif diff --git a/lib/bitops.h b/lib/bitops.h deleted file mode 100644 index 308aa865..00000000 --- a/lib/bitops.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef _BITOPS_H_ -#define _BITOPS_H_ - -/* - * Adapted from - * include/linux/bitops.h - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#define BITS_PER_LONG_LONG 64 -#define BIT(nr) (1UL << (nr)) -#define BIT_ULL(nr) (1ULL << (nr)) -#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) -#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) -#define BIT_ULL_MASK(nr) (1ULL << ((nr) % BITS_PER_LONG_LONG)) -#define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG) -#define BITS_PER_BYTE 8 -#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) - -#include - -/* - * Create a contiguous bitmask starting at bit position @l and ending at - * position @h. For example - * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000. - */ -#define GENMASK(h, l) \ - (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) - -#define GENMASK_ULL(h, l) \ - (((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) - -#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) -#define lower_32_bits(n) ((u32)(n)) - -#ifndef HAVE_BUILTIN_FLS -static inline unsigned long fls(unsigned long word) -{ - int num = BITS_PER_LONG - 1; - -#if BITS_PER_LONG == 64 - if (!(word & (~0ul << 32))) { - num -= 32; - word <<= 32; - } -#endif - if (!(word & (~0ul << (BITS_PER_LONG-16)))) { - num -= 16; - word <<= 16; - } - if (!(word & (~0ul << (BITS_PER_LONG-8)))) { - num -= 8; - word <<= 8; - } - if (!(word & (~0ul << (BITS_PER_LONG-4)))) { - num -= 4; - word <<= 4; - } - if (!(word & (~0ul << (BITS_PER_LONG-2)))) { - num -= 2; - word <<= 2; - } - if (!(word & (~0ul << (BITS_PER_LONG-1)))) - num -= 1; - return num; -} -#else -static inline unsigned long fls(unsigned long word) -{ - return BITS_PER_LONG - __builtin_clzl(word) - 1; -} -#endif - -static inline bool is_power_of_2(unsigned long n) -{ - return n && !(n & (n - 1)); -} - -static inline unsigned int get_order(size_t size) -{ - return size ? fls(size) + !is_power_of_2(size) : 0; -} - -#endif diff --git a/lib/chr-testdev.c b/lib/chr-testdev.c deleted file mode 100644 index 6890f63c..00000000 --- a/lib/chr-testdev.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "virtio.h" -#include "asm/spinlock.h" - -#include "chr-testdev.h" - -#define TESTDEV_NAME "chr-testdev" - -static struct virtio_device *vcon; -static struct virtqueue *in_vq, *out_vq; -static struct spinlock lock; - -static void __testdev_send(char *buf, unsigned int len) -{ - int ret; - - ret = virtqueue_add_outbuf(out_vq, buf, len); - virtqueue_kick(out_vq); - - if (ret < 0) - return; - - while (!virtqueue_get_buf(out_vq, &len)) - ; -} - -void chr_testdev_exit(int code) -{ - unsigned int len; - static char buf[8]; - - spin_lock(&lock); - if (!vcon) - goto out; - - snprintf(buf, sizeof(buf), "%dq", code); - len = strlen(buf); - - __testdev_send(buf, len); - -out: - spin_unlock(&lock); -} - -void chr_testdev_init(void) -{ - const char *io_names[] = { "input", "output" }; - struct virtqueue *vqs[2]; - int ret; - - vcon = virtio_bind(VIRTIO_ID_CONSOLE); - if (vcon == NULL) { - printf("%s: %s: can't find a virtio-console\n", - __func__, TESTDEV_NAME); - return; - } - - ret = vcon->config->find_vqs(vcon, 2, vqs, NULL, io_names); - if (ret < 0) { - printf("%s: %s: can't init virtqueues\n", - __func__, TESTDEV_NAME); - vcon = NULL; - return; - } - - in_vq = vqs[0]; - out_vq = vqs[1]; -} diff --git a/lib/chr-testdev.h b/lib/chr-testdev.h deleted file mode 100644 index ffd9a851..00000000 --- a/lib/chr-testdev.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _CHR_TESTDEV_H_ -#define _CHR_TESTDEV_H_ -/* - * chr-testdev is a driver for the chr-testdev qemu backend. - * The chr-testdev backend exposes a simple control interface to - * qemu for kvm-unit-tests accessible through virtio-console. - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -extern void chr_testdev_init(void); -extern void chr_testdev_exit(int code); -#endif diff --git a/lib/devicetree.c b/lib/devicetree.c deleted file mode 100644 index 10203249..00000000 --- a/lib/devicetree.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "libfdt/libfdt.h" -#include "devicetree.h" - -static const void *fdt; - -const void *dt_fdt(void) -{ - return fdt; -} - -bool dt_available(void) -{ - return fdt_check_header(fdt) == 0; -} - -int dt_get_nr_cells(int fdtnode, u32 *nr_address_cells, u32 *nr_size_cells) -{ - const struct fdt_property *prop; - u32 *nr_cells; - int len, nac, nsc; - - prop = fdt_get_property(fdt, fdtnode, "#address-cells", &len); - if (prop == NULL) - return len; - - nr_cells = (u32 *)prop->data; - nac = fdt32_to_cpu(*nr_cells); - - prop = fdt_get_property(fdt, fdtnode, "#size-cells", &len); - if (prop == NULL) - return len; - - nr_cells = (u32 *)prop->data; - nsc = fdt32_to_cpu(*nr_cells); - - *nr_address_cells = nac; - *nr_size_cells = nsc; - - return 0; -} - -void dt_reg_init(struct dt_reg *reg, u32 nr_address_cells, u32 nr_size_cells) -{ - memset(reg, 0, sizeof(struct dt_reg)); - reg->nr_address_cells = nr_address_cells; - reg->nr_size_cells = nr_size_cells; -} - -int dt_get_reg(int fdtnode, int regidx, struct dt_reg *reg) -{ - const struct fdt_property *prop; - u32 *cells, i; - unsigned nr_tuple_cells; - int len; - - prop = fdt_get_property(fdt, fdtnode, "reg", &len); - if (prop == NULL) - return len; - - cells = (u32 *)prop->data; - nr_tuple_cells = reg->nr_address_cells + reg->nr_size_cells; - regidx *= nr_tuple_cells; - - if (regidx + nr_tuple_cells > len/sizeof(u32)) - return -FDT_ERR_NOTFOUND; - - for (i = 0; i < reg->nr_address_cells; ++i) - reg->address_cells[i] = fdt32_to_cpu(cells[regidx + i]); - - regidx += reg->nr_address_cells; - for (i = 0; i < reg->nr_size_cells; ++i) - reg->size_cells[i] = fdt32_to_cpu(cells[regidx + i]); - - return 0; -} - -int dt_pbus_translate_node(int fdtnode, int regidx, - struct dt_pbus_reg *pbus_reg) -{ - struct dt_reg raw_reg; - u32 nac, nsc; - int parent, ret; - - parent = fdt_parent_offset(fdt, fdtnode); - if (parent < 0) - return parent; - - ret = dt_get_nr_cells(parent, &nac, &nsc); - if (ret != 0) - return ret; - - dt_reg_init(&raw_reg, nac, nsc); - - ret = dt_get_reg(fdtnode, regidx, &raw_reg); - if (ret < 0) - return ret; - - pbus_reg->addr = dt_pbus_read_cells(raw_reg.nr_address_cells, - raw_reg.address_cells); - pbus_reg->size = dt_pbus_read_cells(raw_reg.nr_size_cells, - raw_reg.size_cells); - - return 0; -} - -int dt_pbus_translate(const struct dt_device *dev, int regidx, - void *reg) -{ - return dt_pbus_translate_node(dev->fdtnode, regidx, reg); -} - -int dt_bus_match_any(const struct dt_device *dev __unused, int fdtnode) -{ - /* matches any device with a valid node */ - return fdtnode < 0 ? fdtnode : 1; -} - -static const struct dt_bus dt_default_bus = { - .match = dt_bus_match_any, - .translate = dt_pbus_translate, -}; - -void dt_bus_init_defaults(struct dt_bus *bus) -{ - memcpy(bus, &dt_default_bus, sizeof(struct dt_bus)); -} - -void dt_device_init(struct dt_device *dev, const struct dt_bus *bus, - void *info) -{ - memset(dev, 0, sizeof(struct dt_device)); - dev->bus = bus; - dev->info = info; -} - -int dt_device_find_compatible(const struct dt_device *dev, - const char *compatible) -{ - int node, ret; - - node = fdt_node_offset_by_compatible(fdt, -1, compatible); - while (node >= 0) { - ret = dev->bus->match(dev, node); - if (ret < 0) - return ret; - else if (ret) - break; - node = fdt_node_offset_by_compatible(fdt, node, compatible); - } - return node; -} - -int dt_pbus_get_base_compatible(const char *compatible, - struct dt_pbus_reg *base) -{ - struct dt_device dev; - int node; - - dt_device_init(&dev, &dt_default_bus, NULL); - - node = dt_device_find_compatible(&dev, compatible); - if (node < 0) - return node; - - dt_device_bind_node(&dev, node); - - return dt_pbus_get_base(&dev, base); -} - -int dt_get_memory_params(struct dt_pbus_reg *regs, int nr_regs) -{ - const char *pn = "device_type", *pv = "memory"; - int node, ret, reg_idx, pl = strlen(pv) + 1, nr = 0; - struct dt_pbus_reg reg; - - node = fdt_node_offset_by_prop_value(fdt, -1, pn, pv, pl); - - while (node >= 0) { - - reg_idx = 0; - - while (nr < nr_regs) { - ret = dt_pbus_translate_node(node, reg_idx, ®); - if (ret == -FDT_ERR_NOTFOUND) - break; - if (ret < 0) - return ret; - regs[nr].addr = reg.addr; - regs[nr].size = reg.size; - ++nr, ++reg_idx; - } - - node = fdt_node_offset_by_prop_value(fdt, node, pn, pv, pl); - } - - return node != -FDT_ERR_NOTFOUND ? node : nr; -} - -int dt_for_each_cpu_node(void (*func)(int fdtnode, u64 regval, void *info), - void *info) -{ - const struct fdt_property *prop; - int cpus, cpu, ret, len; - struct dt_reg raw_reg; - u32 nac, nsc; - u64 regval; - - cpus = fdt_path_offset(fdt, "/cpus"); - if (cpus < 0) - return cpus; - - ret = dt_get_nr_cells(cpus, &nac, &nsc); - if (ret < 0) - return ret; - - dt_reg_init(&raw_reg, nac, nsc); - - dt_for_each_subnode(cpus, cpu) { - - prop = fdt_get_property(fdt, cpu, "device_type", &len); - if (prop == NULL) - continue; - - if (len != 4 || strcmp((char *)prop->data, "cpu")) - continue; - - ret = dt_get_reg(cpu, 0, &raw_reg); - if (ret < 0) - return ret; - - regval = raw_reg.address_cells[0]; - if (nac == 2) - regval = (regval << 32) | raw_reg.address_cells[1]; - - func(cpu, regval, info); - } - - return 0; -} - -int dt_get_bootargs(const char **bootargs) -{ - const struct fdt_property *prop; - int node, len; - - *bootargs = NULL; - - node = fdt_path_offset(fdt, "/chosen"); - if (node < 0) - return node; - - prop = fdt_get_property(fdt, node, "bootargs", &len); - if (!prop) - return len; - - *bootargs = prop->data; - return 0; -} - -int dt_get_default_console_node(void) -{ - const struct fdt_property *prop; - int node, len; - - node = fdt_path_offset(fdt, "/chosen"); - if (node < 0) - return node; - - prop = fdt_get_property(fdt, node, "stdout-path", &len); - if (!prop) { - prop = fdt_get_property(fdt, node, "linux,stdout-path", &len); - if (!prop) - return len; - } - - return fdt_path_offset(fdt, prop->data); -} - -int dt_get_initrd(const char **initrd, u32 *size) -{ - const struct fdt_property *prop; - const char *start, *end; - int node, len; - u32 *data; - - *initrd = NULL; - *size = 0; - - node = fdt_path_offset(fdt, "/chosen"); - if (node < 0) - return node; - - prop = fdt_get_property(fdt, node, "linux,initrd-start", &len); - if (!prop) - return len; - data = (u32 *)prop->data; - start = (const char *)(unsigned long)fdt32_to_cpu(*data); - - prop = fdt_get_property(fdt, node, "linux,initrd-end", &len); - if (!prop) { - assert(len != -FDT_ERR_NOTFOUND); - return len; - } - data = (u32 *)prop->data; - end = (const char *)(unsigned long)fdt32_to_cpu(*data); - - *initrd = start; - *size = (unsigned long)end - (unsigned long)start; - - return 0; -} - -int dt_init(const void *fdt_ptr) -{ - int ret; - - ret = fdt_check_header(fdt_ptr); - if (ret < 0) - return ret; - - /* Sanity check the path. */ - ret = fdt_path_offset(fdt_ptr, "/"); - if (ret < 0) - return ret; - - fdt = fdt_ptr; - return 0; -} diff --git a/lib/devicetree.h b/lib/devicetree.h deleted file mode 100644 index 93c7ebc6..00000000 --- a/lib/devicetree.h +++ /dev/null @@ -1,251 +0,0 @@ -#ifndef _DEVICETREE_H_ -#define _DEVICETREE_H_ -/* - * devicetree builds on libfdt to implement abstractions and accessors - * for Linux required device tree content. The accessors provided are - * common across architectures. See section III of the kernel doc - * Documentation/devicetree/booting-without-of.txt - * - * Copyright (C) 2014, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "libfdt/libfdt.h" - -/********************************************************************** - * devicetree init and libfdt helpers - **********************************************************************/ - -/* dt_init initializes devicetree with a pointer to an fdt, @fdt_ptr */ -extern int dt_init(const void *fdt_ptr); - -/* get the fdt pointer that devicetree is using */ -extern const void *dt_fdt(void); - -/* check for an initialized, valid devicetree */ -extern bool dt_available(void); - -/* traverse child nodes */ -#define dt_for_each_subnode(n, s) \ - for (s = fdt_first_subnode(dt_fdt(), n); \ - s != -FDT_ERR_NOTFOUND; \ - s = fdt_next_subnode(dt_fdt(), s)) - -/********************************************************************** - * Abstractions for required node types and properties - **********************************************************************/ - -struct dt_device { - int fdtnode; - const struct dt_bus *bus; - - /* - * info is a pointer to device specific data, which may be - * used by the bus match() and translate() functions - */ - void *info; -}; - -struct dt_bus { - /* - * match a device @dev to an fdt node @fdtnode - * returns - * - a positive value on match - * - zero on no match - * - a negative FDT_ERR_* value on failure - */ - int (*match)(const struct dt_device *dev, int fdtnode); - - /* - * translate the @regidx'th "address size" tuple of - * @dev's fdt node's "reg" property, and store the result - * in @reg, a bus specific structure - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ - int (*translate)(const struct dt_device *dev, int regidx, void *reg); -}; - -/* dt_bus_match_any matches any fdt node, i.e. it always returns true */ -extern int dt_bus_match_any(const struct dt_device *dev, int fdtnode); - -/* the processor bus (pbus) address type and register tuple */ -typedef u64 dt_pbus_addr_t; -struct dt_pbus_reg { - dt_pbus_addr_t addr; - dt_pbus_addr_t size; -}; - -static inline dt_pbus_addr_t dt_pbus_read_cells(u32 nr_cells, u32 *cells) -{ - switch (nr_cells) { - case 1: return cells[0]; - case 2: return ((u64)cells[0] << 32) | cells[1]; - } - return (~0ULL); -} - -/* - * dt_pbus_translate translates device node regs for the - * processor bus using the parent node's #address-cells - * and #size-cells and dt_pbus_read_cells() - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_pbus_translate(const struct dt_device *dev, int regidx, - void *reg); - -/* - * dt_pbus_translate_node is the same as dt_pbus_translate but - * operates on an fdt node instead of a dt_device - */ -extern int dt_pbus_translate_node(int fdtnode, int regidx, - struct dt_pbus_reg *reg); - -/* - * dt_pbus_get_base is an alias for - * dt_pbus_translate(dev, 0, base) - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -static inline int dt_pbus_get_base(const struct dt_device *dev, - struct dt_pbus_reg *base) -{ - return dt_pbus_translate(dev, 0, base); -} - -/* - * dt_bus_init_defaults initializes @bus with - * match <- dt_bus_match_any - * translate <- dt_pbus_translate - */ -extern void dt_bus_init_defaults(struct dt_bus *bus); - -/* - * dt_device_init initializes a dt_device with the given parameters - */ -extern void dt_device_init(struct dt_device *dev, const struct dt_bus *bus, - void *info); - -static inline void dt_device_bind_node(struct dt_device *dev, int fdtnode) -{ - dev->fdtnode = fdtnode; -} - -/* - * dt_device_find_compatible finds a @compatible node - * returns - * - node (>= 0) on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_device_find_compatible(const struct dt_device *dev, - const char *compatible); - -/* - * dt_pbus_get_base_compatible simply bundles many functions into one. - * It finds the first @compatible fdt node, then translates the 0th reg - * tuple (the base) using the processor bus translation, and finally it - * stores that result in @base. - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_pbus_get_base_compatible(const char *compatible, - struct dt_pbus_reg *base); - -/********************************************************************** - * Low-level accessors for required node types and properties - **********************************************************************/ - -/* - * dt_get_nr_cells sets @nr_address_cells and @nr_size_cells to the - * #address-cells and #size-cells properties of @fdtnode - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_get_nr_cells(int fdtnode, u32 *nr_address_cells, - u32 *nr_size_cells); - -/* dt_reg is a structure for "raw" reg tuples */ -#define MAX_ADDRESS_CELLS 4 -#define MAX_SIZE_CELLS 4 -struct dt_reg { - u32 nr_address_cells, nr_size_cells; - u32 address_cells[MAX_ADDRESS_CELLS]; - u32 size_cells[MAX_SIZE_CELLS]; -}; - -/* - * dt_reg_init initialize a dt_reg struct to zero and sets - * nr_address_cells and nr_size_cells to @nr_address_cells and - * @nr_size_cells respectively. - */ -extern void dt_reg_init(struct dt_reg *reg, u32 nr_address_cells, - u32 nr_size_cells); - -/* - * dt_get_reg gets the @regidx'th reg tuple of @fdtnode's reg property - * and stores it in @reg. @reg must be initialized. - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_get_reg(int fdtnode, int regidx, struct dt_reg *reg); - -/********************************************************************** - * High-level accessors for required node types and properties - **********************************************************************/ - -/* - * dt_get_bootargs gets the string pointer from /chosen/bootargs - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure, and @bootargs - * will be set to NULL - */ -extern int dt_get_bootargs(const char **bootargs); - -/* - * dt_get_default_console_node gets the node of the path stored in - * /chosen/stdout-path (or the deprecated /chosen/linux,stdout-path) - * returns - * - the node (>= 0) on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_get_default_console_node(void); - -/* - * dt_get_initrd gets the physical address of the initrd and its - * size from /chosen - * returns - * - zero on success - * - a negative FDT_ERR_* value on failure, and @initrd will be - * set to NULL and @size set to zero - */ -extern int dt_get_initrd(const char **initrd, u32 *size); - -/* - * dt_get_memory_params gets the memory parameters from the /memory node(s) - * storing each memory region ("address size" tuple) in consecutive entries - * of @regs, up to @nr_regs - * returns - * - number of memory regions found on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_get_memory_params(struct dt_pbus_reg *regs, int nr_regs); - -/* - * dt_for_each_cpu_node runs @func on each cpu node in the /cpus node - * passing it its fdt node, its reg property value, and @info - * - zero on success - * - a negative FDT_ERR_* value on failure - */ -extern int dt_for_each_cpu_node(void (*func)(int fdtnode, u64 regval, - void *info), void *info); - -#endif /* _DEVICETREE_H_ */ diff --git a/lib/errata.h b/lib/errata.h deleted file mode 100644 index 5af0eb3b..00000000 --- a/lib/errata.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * errata functions - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _ERRATA_H_ -#define _ERRATA_H_ -#include "config.h" - -#ifndef CONFIG_ERRATA_FORCE -#define CONFIG_ERRATA_FORCE 0 -#endif - -#define _ERRATA(erratum) errata("ERRATA_" # erratum) -#define ERRATA(erratum) _ERRATA(erratum) - -#define _ERRATA_RELAXED(erratum) errata_relaxed("ERRATA_" # erratum) -#define ERRATA_RELAXED(erratum) _ERRATA_RELAXED(erratum) - -static inline bool errata_force(void) -{ - char *s; - - if (CONFIG_ERRATA_FORCE == 1) - return true; - - s = getenv("ERRATA_FORCE"); - return s && (*s == '1' || *s == 'y' || *s == 'Y'); -} - -static inline bool errata(const char *erratum) -{ - char *s; - - if (errata_force()) - return true; - - s = getenv(erratum); - - return s && (*s == '1' || *s == 'y' || *s == 'Y'); -} - -static inline bool errata_relaxed(const char *erratum) -{ - char *s; - - if (errata_force()) - return true; - - s = getenv(erratum); - - return !(s && (*s == '0' || *s == 'n' || *s == 'N')); -} - -#endif diff --git a/lib/generated/.gitignore b/lib/generated/.gitignore deleted file mode 100644 index 72e8ffc0..00000000 --- a/lib/generated/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/lib/getchar.c b/lib/getchar.c deleted file mode 100644 index 26f6b6ba..00000000 --- a/lib/getchar.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "libcflat.h" -#include "asm/barrier.h" - -int getchar(void) -{ - int c; - - while ((c = __getchar()) == -1) - cpu_relax(); - return c; -} diff --git a/lib/kbuild.h b/lib/kbuild.h deleted file mode 100644 index ab99db67..00000000 --- a/lib/kbuild.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _KBUILD_H_ -#define _KBUILD_H_ -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) -#define OFFSET(sym, str, mem) DEFINE(sym, offsetof(struct str, mem)) -#define COMMENT(x) asm volatile("\n->#" x) -#define BLANK() asm volatile("\n->" : : ) -#endif diff --git a/lib/libcflat.h b/lib/libcflat.h deleted file mode 100644 index ec0f58b0..00000000 --- a/lib/libcflat.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright IBM Corp. 2008 - * - * Authors: Hollis Blanchard - */ - -#ifndef __LIBCFLAT_H -#define __LIBCFLAT_H - -#include -#include -#include -#include -#include - -#define __unused __attribute__((__unused__)) - -#define xstr(s...) xxstr(s) -#define xxstr(s...) #s - -#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) -#define __ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1) -#define ALIGN(x, a) __ALIGN((x), (a)) -#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) - -#define SZ_256 (1 << 8) -#define SZ_4K (1 << 12) -#define SZ_8K (1 << 13) -#define SZ_16K (1 << 14) -#define SZ_64K (1 << 16) -#define SZ_2M (1 << 21) -#define SZ_1G (1 << 30) - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -typedef uint8_t u8; -typedef int8_t s8; -typedef uint16_t u16; -typedef int16_t s16; -typedef uint32_t u32; -typedef int32_t s32; -typedef uint64_t u64; -typedef int64_t s64; -typedef unsigned long ulong; - -#if __SIZEOF_LONG__ == 8 -# define __PRI32_PREFIX -# define __PRI64_PREFIX "l" -# define __PRIPTR_PREFIX "l" -#else -#if defined(__U32_LONG_FMT__) -# define __PRI32_PREFIX "l" -#else -# define __PRI32_PREFIX -#endif -# define __PRI64_PREFIX "ll" -# define __PRIPTR_PREFIX -#endif -#define PRId32 __PRI32_PREFIX "d" -#define PRIu32 __PRI32_PREFIX "u" -#define PRIx32 __PRI32_PREFIX "x" -#define PRId64 __PRI64_PREFIX "d" -#define PRIu64 __PRI64_PREFIX "u" -#define PRIx64 __PRI64_PREFIX "x" -#define PRIxPTR __PRIPTR_PREFIX "x" - -typedef u64 phys_addr_t; -#define INVALID_PHYS_ADDR (~(phys_addr_t)0) - -extern void puts(const char *s); -extern int __getchar(void); -extern int getchar(void); -extern void exit(int code) __attribute__((noreturn)); -extern void abort(void) __attribute__((noreturn)); -extern long atol(const char *ptr); -extern char *getenv(const char *name); - -extern int printf(const char *fmt, ...) - __attribute__((format(printf, 1, 2))); -extern int snprintf(char *buf, int size, const char *fmt, ...) - __attribute__((format(printf, 3, 4))); -extern int vsnprintf(char *buf, int size, const char *fmt, va_list va) - __attribute__((format(printf, 3, 0))); -extern int vprintf(const char *fmt, va_list va) - __attribute__((format(printf, 1, 0))); - -void report_prefix_pushf(const char *prefix_fmt, ...) - __attribute__((format(printf, 1, 2))); -extern void report_prefix_push(const char *prefix); -extern void report_prefix_pop(void); -extern void report(bool pass, const char *msg_fmt, ...) - __attribute__((format(printf, 2, 3), nonnull(2))); -extern void report_xfail(bool xfail, bool pass, const char *msg_fmt, ...) - __attribute__((format(printf, 3, 4), nonnull(3))); -extern void report_abort(const char *msg_fmt, ...) - __attribute__((format(printf, 1, 2))) - __attribute__((noreturn)); -extern void report_skip(const char *msg_fmt, ...) - __attribute__((format(printf, 1, 2))); -extern void report_info(const char *msg_fmt, ...) - __attribute__((format(printf, 1, 2))); -extern void report_pass(void); -extern int report_summary(void); - -bool simple_glob(const char *text, const char *pattern); - -extern void dump_stack(void); -extern void dump_frame_stack(const void *instruction, const void *frame); - -#define ARRAY_SIZE(_a) (sizeof(_a)/sizeof((_a)[0])) - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -#define assert(cond) \ -do { \ - if (!(cond)) { \ - printf("%s:%d: assert failed: %s\n", \ - __FILE__, __LINE__, #cond); \ - dump_stack(); \ - abort(); \ - } \ -} while (0) - -#define assert_msg(cond, fmt, args...) \ -do { \ - if (!(cond)) { \ - printf("%s:%d: assert failed: %s: " fmt "\n", \ - __FILE__, __LINE__, #cond, ## args); \ - dump_stack(); \ - abort(); \ - } \ -} while (0) - -/* - * One byte per bit, a ' between each group of 4 bits, and a null terminator. - */ -#define BINSTR_SZ (sizeof(unsigned long) * 8 + sizeof(unsigned long) * 2) -void binstr(unsigned long x, char out[BINSTR_SZ]); -void print_binstr(unsigned long x); - -extern void setup_vm(void); - -#endif diff --git a/lib/libfdt/Makefile.libfdt b/lib/libfdt/Makefile.libfdt deleted file mode 100644 index 91126c00..00000000 --- a/lib/libfdt/Makefile.libfdt +++ /dev/null @@ -1,10 +0,0 @@ -# Makefile.libfdt -# -# This is not a complete Makefile of itself. Instead, it is designed to -# be easily embeddable into other systems of Makefiles. -# -LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 -LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h -LIBFDT_VERSION = version.lds -LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c -LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/lib/libfdt/README b/lib/libfdt/README deleted file mode 100644 index 24ad4fec..00000000 --- a/lib/libfdt/README +++ /dev/null @@ -1,4 +0,0 @@ - -The code in this directory is originally imported from the libfdt -directory of git://git.jdl.com/software/dtc.git - version 1.4.0. - diff --git a/lib/libfdt/fdt.c b/lib/libfdt/fdt.c deleted file mode 100644 index 2ce6a441..00000000 --- a/lib/libfdt/fdt.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -int fdt_check_header(const void *fdt) -{ - if (fdt_magic(fdt) == FDT_MAGIC) { - /* Complete tree */ - if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) - return -FDT_ERR_BADVERSION; - if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) - return -FDT_ERR_BADVERSION; - } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { - /* Unfinished sequential-write blob */ - if (fdt_size_dt_struct(fdt) == 0) - return -FDT_ERR_BADSTATE; - } else { - return -FDT_ERR_BADMAGIC; - } - - return 0; -} - -const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) -{ - const char *p; - - if (fdt_version(fdt) >= 0x11) - if (((offset + len) < offset) - || ((offset + len) > fdt_size_dt_struct(fdt))) - return NULL; - - p = _fdt_offset_ptr(fdt, offset); - - if (p + len < p) - return NULL; - return p; -} - -uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) -{ - const fdt32_t *tagp, *lenp; - uint32_t tag; - int offset = startoffset; - const char *p; - - *nextoffset = -FDT_ERR_TRUNCATED; - tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); - if (!tagp) - return FDT_END; /* premature end */ - tag = fdt32_to_cpu(*tagp); - offset += FDT_TAGSIZE; - - *nextoffset = -FDT_ERR_BADSTRUCTURE; - switch (tag) { - case FDT_BEGIN_NODE: - /* skip name */ - do { - p = fdt_offset_ptr(fdt, offset++, 1); - } while (p && (*p != '\0')); - if (!p) - return FDT_END; /* premature end */ - break; - - case FDT_PROP: - lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); - if (!lenp) - return FDT_END; /* premature end */ - /* skip-name offset, length and value */ - offset += sizeof(struct fdt_property) - FDT_TAGSIZE - + fdt32_to_cpu(*lenp); - break; - - case FDT_END: - case FDT_END_NODE: - case FDT_NOP: - break; - - default: - return FDT_END; - } - - if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) - return FDT_END; /* premature end */ - - *nextoffset = FDT_TAGALIGN(offset); - return tag; -} - -int _fdt_check_node_offset(const void *fdt, int offset) -{ - if ((offset < 0) || (offset % FDT_TAGSIZE) - || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) - return -FDT_ERR_BADOFFSET; - - return offset; -} - -int _fdt_check_prop_offset(const void *fdt, int offset) -{ - if ((offset < 0) || (offset % FDT_TAGSIZE) - || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) - return -FDT_ERR_BADOFFSET; - - return offset; -} - -int fdt_next_node(const void *fdt, int offset, int *depth) -{ - int nextoffset = 0; - uint32_t tag; - - if (offset >= 0) - if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) - return nextoffset; - - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - - switch (tag) { - case FDT_PROP: - case FDT_NOP: - break; - - case FDT_BEGIN_NODE: - if (depth) - (*depth)++; - break; - - case FDT_END_NODE: - if (depth && ((--(*depth)) < 0)) - return nextoffset; - break; - - case FDT_END: - if ((nextoffset >= 0) - || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) - return -FDT_ERR_NOTFOUND; - else - return nextoffset; - } - } while (tag != FDT_BEGIN_NODE); - - return offset; -} - -int fdt_first_subnode(const void *fdt, int offset) -{ - int depth = 0; - - offset = fdt_next_node(fdt, offset, &depth); - if (offset < 0 || depth != 1) - return -FDT_ERR_NOTFOUND; - - return offset; -} - -int fdt_next_subnode(const void *fdt, int offset) -{ - int depth = 1; - - /* - * With respect to the parent, the depth of the next subnode will be - * the same as the last. - */ - do { - offset = fdt_next_node(fdt, offset, &depth); - if (offset < 0 || depth < 1) - return -FDT_ERR_NOTFOUND; - } while (depth > 1); - - return offset; -} - -const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) -{ - int len = strlen(s) + 1; - const char *last = strtab + tabsize - len; - const char *p; - - for (p = strtab; p <= last; p++) - if (memcmp(p, s, len) == 0) - return p; - return NULL; -} - -int fdt_move(const void *fdt, void *buf, int bufsize) -{ - FDT_CHECK_HEADER(fdt); - - if (fdt_totalsize(fdt) > bufsize) - return -FDT_ERR_NOSPACE; - - memmove(buf, fdt, fdt_totalsize(fdt)); - return 0; -} diff --git a/lib/libfdt/fdt.h b/lib/libfdt/fdt.h deleted file mode 100644 index 526aedb5..00000000 --- a/lib/libfdt/fdt.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _FDT_H -#define _FDT_H -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * Copyright 2012 Kim Phillips, Freescale Semiconductor. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ASSEMBLY__ - -struct fdt_header { - fdt32_t magic; /* magic word FDT_MAGIC */ - fdt32_t totalsize; /* total size of DT block */ - fdt32_t off_dt_struct; /* offset to structure */ - fdt32_t off_dt_strings; /* offset to strings */ - fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ - fdt32_t version; /* format version */ - fdt32_t last_comp_version; /* last compatible version */ - - /* version 2 fields below */ - fdt32_t boot_cpuid_phys; /* Which physical CPU id we're - booting on */ - /* version 3 fields below */ - fdt32_t size_dt_strings; /* size of the strings block */ - - /* version 17 fields below */ - fdt32_t size_dt_struct; /* size of the structure block */ -}; - -struct fdt_reserve_entry { - fdt64_t address; - fdt64_t size; -}; - -struct fdt_node_header { - fdt32_t tag; - char name[0]; -}; - -struct fdt_property { - fdt32_t tag; - fdt32_t len; - fdt32_t nameoff; - char data[0]; -}; - -#endif /* !__ASSEMBLY */ - -#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ -#define FDT_TAGSIZE sizeof(fdt32_t) - -#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ -#define FDT_END_NODE 0x2 /* End node */ -#define FDT_PROP 0x3 /* Property: name off, - size, content */ -#define FDT_NOP 0x4 /* nop */ -#define FDT_END 0x9 - -#define FDT_V1_SIZE (7*sizeof(fdt32_t)) -#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) -#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) -#define FDT_V16_SIZE FDT_V3_SIZE -#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) - -#endif /* _FDT_H */ diff --git a/lib/libfdt/fdt_empty_tree.c b/lib/libfdt/fdt_empty_tree.c deleted file mode 100644 index f72d13b1..00000000 --- a/lib/libfdt/fdt_empty_tree.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2012 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -int fdt_create_empty_tree(void *buf, int bufsize) -{ - int err; - - err = fdt_create(buf, bufsize); - if (err) - return err; - - err = fdt_finish_reservemap(buf); - if (err) - return err; - - err = fdt_begin_node(buf, ""); - if (err) - return err; - - err = fdt_end_node(buf); - if (err) - return err; - - err = fdt_finish(buf); - if (err) - return err; - - return fdt_open_into(buf, buf, bufsize); -} - diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c deleted file mode 100644 index 50007f61..00000000 --- a/lib/libfdt/fdt_ro.c +++ /dev/null @@ -1,573 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -static int _fdt_nodename_eq(const void *fdt, int offset, - const char *s, int len) -{ - const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); - - if (! p) - /* short match */ - return 0; - - if (memcmp(p, s, len) != 0) - return 0; - - if (p[len] == '\0') - return 1; - else if (!memchr(s, '@', len) && (p[len] == '@')) - return 1; - else - return 0; -} - -const char *fdt_string(const void *fdt, int stroffset) -{ - return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; -} - -static int _fdt_string_eq(const void *fdt, int stroffset, - const char *s, int len) -{ - const char *p = fdt_string(fdt, stroffset); - - return (strlen(p) == len) && (memcmp(p, s, len) == 0); -} - -int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) -{ - FDT_CHECK_HEADER(fdt); - *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); - *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); - return 0; -} - -int fdt_num_mem_rsv(const void *fdt) -{ - int i = 0; - - while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) - i++; - return i; -} - -static int _nextprop(const void *fdt, int offset) -{ - uint32_t tag; - int nextoffset; - - do { - tag = fdt_next_tag(fdt, offset, &nextoffset); - - switch (tag) { - case FDT_END: - if (nextoffset >= 0) - return -FDT_ERR_BADSTRUCTURE; - else - return nextoffset; - - case FDT_PROP: - return offset; - } - offset = nextoffset; - } while (tag == FDT_NOP); - - return -FDT_ERR_NOTFOUND; -} - -int fdt_subnode_offset_namelen(const void *fdt, int offset, - const char *name, int namelen) -{ - int depth; - - FDT_CHECK_HEADER(fdt); - - for (depth = 0; - (offset >= 0) && (depth >= 0); - offset = fdt_next_node(fdt, offset, &depth)) - if ((depth == 1) - && _fdt_nodename_eq(fdt, offset, name, namelen)) - return offset; - - if (depth < 0) - return -FDT_ERR_NOTFOUND; - return offset; /* error */ -} - -int fdt_subnode_offset(const void *fdt, int parentoffset, - const char *name) -{ - return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); -} - -int fdt_path_offset(const void *fdt, const char *path) -{ - const char *end = path + strlen(path); - const char *p = path; - int offset = 0; - - FDT_CHECK_HEADER(fdt); - - /* see if we have an alias */ - if (*path != '/') { - const char *q = strchr(path, '/'); - - if (!q) - q = end; - - p = fdt_get_alias_namelen(fdt, p, q - p); - if (!p) - return -FDT_ERR_BADPATH; - offset = fdt_path_offset(fdt, p); - - p = q; - } - - while (*p) { - const char *q; - - while (*p == '/') - p++; - if (! *p) - return offset; - q = strchr(p, '/'); - if (! q) - q = end; - - offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); - if (offset < 0) - return offset; - - p = q; - } - - return offset; -} - -const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) -{ - const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); - int err; - - if (((err = fdt_check_header(fdt)) != 0) - || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) - goto fail; - - if (len) - *len = strlen(nh->name); - - return nh->name; - - fail: - if (len) - *len = err; - return NULL; -} - -int fdt_first_property_offset(const void *fdt, int nodeoffset) -{ - int offset; - - if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) - return offset; - - return _nextprop(fdt, offset); -} - -int fdt_next_property_offset(const void *fdt, int offset) -{ - if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) - return offset; - - return _nextprop(fdt, offset); -} - -const struct fdt_property *fdt_get_property_by_offset(const void *fdt, - int offset, - int *lenp) -{ - int err; - const struct fdt_property *prop; - - if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { - if (lenp) - *lenp = err; - return NULL; - } - - prop = _fdt_offset_ptr(fdt, offset); - - if (lenp) - *lenp = fdt32_to_cpu(prop->len); - - return prop; -} - -const struct fdt_property *fdt_get_property_namelen(const void *fdt, - int offset, - const char *name, - int namelen, int *lenp) -{ - for (offset = fdt_first_property_offset(fdt, offset); - (offset >= 0); - (offset = fdt_next_property_offset(fdt, offset))) { - const struct fdt_property *prop; - - if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { - offset = -FDT_ERR_INTERNAL; - break; - } - if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), - name, namelen)) - return prop; - } - - if (lenp) - *lenp = offset; - return NULL; -} - -const struct fdt_property *fdt_get_property(const void *fdt, - int nodeoffset, - const char *name, int *lenp) -{ - return fdt_get_property_namelen(fdt, nodeoffset, name, - strlen(name), lenp); -} - -const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, - const char *name, int namelen, int *lenp) -{ - const struct fdt_property *prop; - - prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); - if (! prop) - return NULL; - - return prop->data; -} - -const void *fdt_getprop_by_offset(const void *fdt, int offset, - const char **namep, int *lenp) -{ - const struct fdt_property *prop; - - prop = fdt_get_property_by_offset(fdt, offset, lenp); - if (!prop) - return NULL; - if (namep) - *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); - return prop->data; -} - -const void *fdt_getprop(const void *fdt, int nodeoffset, - const char *name, int *lenp) -{ - return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); -} - -uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) -{ - const fdt32_t *php; - int len; - - /* FIXME: This is a bit sub-optimal, since we potentially scan - * over all the properties twice. */ - php = fdt_getprop(fdt, nodeoffset, "phandle", &len); - if (!php || (len != sizeof(*php))) { - php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); - if (!php || (len != sizeof(*php))) - return 0; - } - - return fdt32_to_cpu(*php); -} - -const char *fdt_get_alias_namelen(const void *fdt, - const char *name, int namelen) -{ - int aliasoffset; - - aliasoffset = fdt_path_offset(fdt, "/aliases"); - if (aliasoffset < 0) - return NULL; - - return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); -} - -const char *fdt_get_alias(const void *fdt, const char *name) -{ - return fdt_get_alias_namelen(fdt, name, strlen(name)); -} - -int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) -{ - int pdepth = 0, p = 0; - int offset, depth, namelen; - const char *name; - - FDT_CHECK_HEADER(fdt); - - if (buflen < 2) - return -FDT_ERR_NOSPACE; - - for (offset = 0, depth = 0; - (offset >= 0) && (offset <= nodeoffset); - offset = fdt_next_node(fdt, offset, &depth)) { - while (pdepth > depth) { - do { - p--; - } while (buf[p-1] != '/'); - pdepth--; - } - - if (pdepth >= depth) { - name = fdt_get_name(fdt, offset, &namelen); - if (!name) - return namelen; - if ((p + namelen + 1) <= buflen) { - memcpy(buf + p, name, namelen); - p += namelen; - buf[p++] = '/'; - pdepth++; - } - } - - if (offset == nodeoffset) { - if (pdepth < (depth + 1)) - return -FDT_ERR_NOSPACE; - - if (p > 1) /* special case so that root path is "/", not "" */ - p--; - buf[p] = '\0'; - return 0; - } - } - - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; - - return offset; /* error from fdt_next_node() */ -} - -int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, - int supernodedepth, int *nodedepth) -{ - int offset, depth; - int supernodeoffset = -FDT_ERR_INTERNAL; - - FDT_CHECK_HEADER(fdt); - - if (supernodedepth < 0) - return -FDT_ERR_NOTFOUND; - - for (offset = 0, depth = 0; - (offset >= 0) && (offset <= nodeoffset); - offset = fdt_next_node(fdt, offset, &depth)) { - if (depth == supernodedepth) - supernodeoffset = offset; - - if (offset == nodeoffset) { - if (nodedepth) - *nodedepth = depth; - - if (supernodedepth > depth) - return -FDT_ERR_NOTFOUND; - else - return supernodeoffset; - } - } - - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; - - return offset; /* error from fdt_next_node() */ -} - -int fdt_node_depth(const void *fdt, int nodeoffset) -{ - int nodedepth; - int err; - - err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); - if (err) - return (err < 0) ? err : -FDT_ERR_INTERNAL; - return nodedepth; -} - -int fdt_parent_offset(const void *fdt, int nodeoffset) -{ - int nodedepth = fdt_node_depth(fdt, nodeoffset); - - if (nodedepth < 0) - return nodedepth; - return fdt_supernode_atdepth_offset(fdt, nodeoffset, - nodedepth - 1, NULL); -} - -int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, - const char *propname, - const void *propval, int proplen) -{ - int offset; - const void *val; - int len; - - FDT_CHECK_HEADER(fdt); - - /* FIXME: The algorithm here is pretty horrible: we scan each - * property of a node in fdt_getprop(), then if that didn't - * find what we want, we scan over them again making our way - * to the next node. Still it's the easiest to implement - * approach; performance can come later. */ - for (offset = fdt_next_node(fdt, startoffset, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - val = fdt_getprop(fdt, offset, propname, &len); - if (val && (len == proplen) - && (memcmp(val, propval, len) == 0)) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} - -int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) -{ - int offset; - - if ((phandle == 0) || (phandle == -1)) - return -FDT_ERR_BADPHANDLE; - - FDT_CHECK_HEADER(fdt); - - /* FIXME: The algorithm here is pretty horrible: we - * potentially scan each property of a node in - * fdt_get_phandle(), then if that didn't find what - * we want, we scan over them again making our way to the next - * node. Still it's the easiest to implement approach; - * performance can come later. */ - for (offset = fdt_next_node(fdt, -1, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - if (fdt_get_phandle(fdt, offset) == phandle) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} - -int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) -{ - int len = strlen(str); - const char *p; - - while (listlen >= len) { - if (memcmp(str, strlist, len+1) == 0) - return 1; - p = memchr(strlist, '\0', listlen); - if (!p) - return 0; /* malformed strlist.. */ - listlen -= (p-strlist) + 1; - strlist = p + 1; - } - return 0; -} - -int fdt_node_check_compatible(const void *fdt, int nodeoffset, - const char *compatible) -{ - const void *prop; - int len; - - prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); - if (!prop) - return len; - if (fdt_stringlist_contains(prop, len, compatible)) - return 0; - else - return 1; -} - -int fdt_node_offset_by_compatible(const void *fdt, int startoffset, - const char *compatible) -{ - int offset, err; - - FDT_CHECK_HEADER(fdt); - - /* FIXME: The algorithm here is pretty horrible: we scan each - * property of a node in fdt_node_check_compatible(), then if - * that didn't find what we want, we scan over them again - * making our way to the next node. Still it's the easiest to - * implement approach; performance can come later. */ - for (offset = fdt_next_node(fdt, startoffset, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - err = fdt_node_check_compatible(fdt, offset, compatible); - if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) - return err; - else if (err == 0) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} diff --git a/lib/libfdt/fdt_rw.c b/lib/libfdt/fdt_rw.c deleted file mode 100644 index fdba618f..00000000 --- a/lib/libfdt/fdt_rw.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -static int _fdt_blocks_misordered(const void *fdt, - int mem_rsv_size, int struct_size) -{ - return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) - || (fdt_off_dt_struct(fdt) < - (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) - || (fdt_off_dt_strings(fdt) < - (fdt_off_dt_struct(fdt) + struct_size)) - || (fdt_totalsize(fdt) < - (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); -} - -static int _fdt_rw_check_header(void *fdt) -{ - FDT_CHECK_HEADER(fdt); - - if (fdt_version(fdt) < 17) - return -FDT_ERR_BADVERSION; - if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), - fdt_size_dt_struct(fdt))) - return -FDT_ERR_BADLAYOUT; - if (fdt_version(fdt) > 17) - fdt_set_version(fdt, 17); - - return 0; -} - -#define FDT_RW_CHECK_HEADER(fdt) \ - { \ - int err; \ - if ((err = _fdt_rw_check_header(fdt)) != 0) \ - return err; \ - } - -static inline int _fdt_data_size(void *fdt) -{ - return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); -} - -static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) -{ - char *p = splicepoint; - char *end = (char *)fdt + _fdt_data_size(fdt); - - if (((p + oldlen) < p) || ((p + oldlen) > end)) - return -FDT_ERR_BADOFFSET; - if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) - return -FDT_ERR_NOSPACE; - memmove(p + newlen, p + oldlen, end - p - oldlen); - return 0; -} - -static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, - int oldn, int newn) -{ - int delta = (newn - oldn) * sizeof(*p); - int err; - err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); - if (err) - return err; - fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); - fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); - return 0; -} - -static int _fdt_splice_struct(void *fdt, void *p, - int oldlen, int newlen) -{ - int delta = newlen - oldlen; - int err; - - if ((err = _fdt_splice(fdt, p, oldlen, newlen))) - return err; - - fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); - fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); - return 0; -} - -static int _fdt_splice_string(void *fdt, int newlen) -{ - void *p = (char *)fdt - + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); - int err; - - if ((err = _fdt_splice(fdt, p, 0, newlen))) - return err; - - fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); - return 0; -} - -static int _fdt_find_add_string(void *fdt, const char *s) -{ - char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); - const char *p; - char *new; - int len = strlen(s) + 1; - int err; - - p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); - if (p) - /* found it */ - return (p - strtab); - - new = strtab + fdt_size_dt_strings(fdt); - err = _fdt_splice_string(fdt, len); - if (err) - return err; - - memcpy(new, s, len); - return (new - strtab); -} - -int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) -{ - struct fdt_reserve_entry *re; - int err; - - FDT_RW_CHECK_HEADER(fdt); - - re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); - err = _fdt_splice_mem_rsv(fdt, re, 0, 1); - if (err) - return err; - - re->address = cpu_to_fdt64(address); - re->size = cpu_to_fdt64(size); - return 0; -} - -int fdt_del_mem_rsv(void *fdt, int n) -{ - struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); - int err; - - FDT_RW_CHECK_HEADER(fdt); - - if (n >= fdt_num_mem_rsv(fdt)) - return -FDT_ERR_NOTFOUND; - - err = _fdt_splice_mem_rsv(fdt, re, 1, 0); - if (err) - return err; - return 0; -} - -static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, - int len, struct fdt_property **prop) -{ - int oldlen; - int err; - - *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); - if (! (*prop)) - return oldlen; - - if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), - FDT_TAGALIGN(len)))) - return err; - - (*prop)->len = cpu_to_fdt32(len); - return 0; -} - -static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, - int len, struct fdt_property **prop) -{ - int proplen; - int nextoffset; - int namestroff; - int err; - - if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) - return nextoffset; - - namestroff = _fdt_find_add_string(fdt, name); - if (namestroff < 0) - return namestroff; - - *prop = _fdt_offset_ptr_w(fdt, nextoffset); - proplen = sizeof(**prop) + FDT_TAGALIGN(len); - - err = _fdt_splice_struct(fdt, *prop, 0, proplen); - if (err) - return err; - - (*prop)->tag = cpu_to_fdt32(FDT_PROP); - (*prop)->nameoff = cpu_to_fdt32(namestroff); - (*prop)->len = cpu_to_fdt32(len); - return 0; -} - -int fdt_set_name(void *fdt, int nodeoffset, const char *name) -{ - char *namep; - int oldlen, newlen; - int err; - - FDT_RW_CHECK_HEADER(fdt); - - namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); - if (!namep) - return oldlen; - - newlen = strlen(name); - - err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), - FDT_TAGALIGN(newlen+1)); - if (err) - return err; - - memcpy(namep, name, newlen+1); - return 0; -} - -int fdt_setprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len) -{ - struct fdt_property *prop; - int err; - - FDT_RW_CHECK_HEADER(fdt); - - err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); - if (err == -FDT_ERR_NOTFOUND) - err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); - if (err) - return err; - - memcpy(prop->data, val, len); - return 0; -} - -int fdt_appendprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len) -{ - struct fdt_property *prop; - int err, oldlen, newlen; - - FDT_RW_CHECK_HEADER(fdt); - - prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); - if (prop) { - newlen = len + oldlen; - err = _fdt_splice_struct(fdt, prop->data, - FDT_TAGALIGN(oldlen), - FDT_TAGALIGN(newlen)); - if (err) - return err; - prop->len = cpu_to_fdt32(newlen); - memcpy(prop->data + oldlen, val, len); - } else { - err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); - if (err) - return err; - memcpy(prop->data, val, len); - } - return 0; -} - -int fdt_delprop(void *fdt, int nodeoffset, const char *name) -{ - struct fdt_property *prop; - int len, proplen; - - FDT_RW_CHECK_HEADER(fdt); - - prop = fdt_get_property_w(fdt, nodeoffset, name, &len); - if (! prop) - return len; - - proplen = sizeof(*prop) + FDT_TAGALIGN(len); - return _fdt_splice_struct(fdt, prop, proplen, 0); -} - -int fdt_add_subnode_namelen(void *fdt, int parentoffset, - const char *name, int namelen) -{ - struct fdt_node_header *nh; - int offset, nextoffset; - int nodelen; - int err; - uint32_t tag; - fdt32_t *endtag; - - FDT_RW_CHECK_HEADER(fdt); - - offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); - if (offset >= 0) - return -FDT_ERR_EXISTS; - else if (offset != -FDT_ERR_NOTFOUND) - return offset; - - /* Try to place the new node after the parent's properties */ - fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - } while ((tag == FDT_PROP) || (tag == FDT_NOP)); - - nh = _fdt_offset_ptr_w(fdt, offset); - nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; - - err = _fdt_splice_struct(fdt, nh, 0, nodelen); - if (err) - return err; - - nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); - memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); - memcpy(nh->name, name, namelen); - endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); - *endtag = cpu_to_fdt32(FDT_END_NODE); - - return offset; -} - -int fdt_add_subnode(void *fdt, int parentoffset, const char *name) -{ - return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); -} - -int fdt_del_node(void *fdt, int nodeoffset) -{ - int endoffset; - - FDT_RW_CHECK_HEADER(fdt); - - endoffset = _fdt_node_end_offset(fdt, nodeoffset); - if (endoffset < 0) - return endoffset; - - return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), - endoffset - nodeoffset, 0); -} - -static void _fdt_packblocks(const char *old, char *new, - int mem_rsv_size, int struct_size) -{ - int mem_rsv_off, struct_off, strings_off; - - mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); - struct_off = mem_rsv_off + mem_rsv_size; - strings_off = struct_off + struct_size; - - memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); - fdt_set_off_mem_rsvmap(new, mem_rsv_off); - - memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); - fdt_set_off_dt_struct(new, struct_off); - fdt_set_size_dt_struct(new, struct_size); - - memmove(new + strings_off, old + fdt_off_dt_strings(old), - fdt_size_dt_strings(old)); - fdt_set_off_dt_strings(new, strings_off); - fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); -} - -int fdt_open_into(const void *fdt, void *buf, int bufsize) -{ - int err; - int mem_rsv_size, struct_size; - int newsize; - const char *fdtstart = fdt; - const char *fdtend = fdtstart + fdt_totalsize(fdt); - char *tmp; - - FDT_CHECK_HEADER(fdt); - - mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) - * sizeof(struct fdt_reserve_entry); - - if (fdt_version(fdt) >= 17) { - struct_size = fdt_size_dt_struct(fdt); - } else { - struct_size = 0; - while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) - ; - if (struct_size < 0) - return struct_size; - } - - if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { - /* no further work necessary */ - err = fdt_move(fdt, buf, bufsize); - if (err) - return err; - fdt_set_version(buf, 17); - fdt_set_size_dt_struct(buf, struct_size); - fdt_set_totalsize(buf, bufsize); - return 0; - } - - /* Need to reorder */ - newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size - + struct_size + fdt_size_dt_strings(fdt); - - if (bufsize < newsize) - return -FDT_ERR_NOSPACE; - - /* First attempt to build converted tree at beginning of buffer */ - tmp = buf; - /* But if that overlaps with the old tree... */ - if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { - /* Try right after the old tree instead */ - tmp = (char *)(uintptr_t)fdtend; - if ((tmp + newsize) > ((char *)buf + bufsize)) - return -FDT_ERR_NOSPACE; - } - - _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); - memmove(buf, tmp, newsize); - - fdt_set_magic(buf, FDT_MAGIC); - fdt_set_totalsize(buf, bufsize); - fdt_set_version(buf, 17); - fdt_set_last_comp_version(buf, 16); - fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); - - return 0; -} - -int fdt_pack(void *fdt) -{ - int mem_rsv_size; - - FDT_RW_CHECK_HEADER(fdt); - - mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) - * sizeof(struct fdt_reserve_entry); - _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); - fdt_set_totalsize(fdt, _fdt_data_size(fdt)); - - return 0; -} diff --git a/lib/libfdt/fdt_strerror.c b/lib/libfdt/fdt_strerror.c deleted file mode 100644 index e6c3ceee..00000000 --- a/lib/libfdt/fdt_strerror.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -struct fdt_errtabent { - const char *str; -}; - -#define FDT_ERRTABENT(val) \ - [(val)] = { .str = #val, } - -static struct fdt_errtabent fdt_errtable[] = { - FDT_ERRTABENT(FDT_ERR_NOTFOUND), - FDT_ERRTABENT(FDT_ERR_EXISTS), - FDT_ERRTABENT(FDT_ERR_NOSPACE), - - FDT_ERRTABENT(FDT_ERR_BADOFFSET), - FDT_ERRTABENT(FDT_ERR_BADPATH), - FDT_ERRTABENT(FDT_ERR_BADSTATE), - - FDT_ERRTABENT(FDT_ERR_TRUNCATED), - FDT_ERRTABENT(FDT_ERR_BADMAGIC), - FDT_ERRTABENT(FDT_ERR_BADVERSION), - FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), - FDT_ERRTABENT(FDT_ERR_BADLAYOUT), -}; -#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) - -const char *fdt_strerror(int errval) -{ - if (errval > 0) - return ""; - else if (errval == 0) - return ""; - else if (errval > -FDT_ERRTABSIZE) { - const char *s = fdt_errtable[-errval].str; - - if (s) - return s; - } - - return ""; -} diff --git a/lib/libfdt/fdt_sw.c b/lib/libfdt/fdt_sw.c deleted file mode 100644 index f422754d..00000000 --- a/lib/libfdt/fdt_sw.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -static int _fdt_sw_check_header(void *fdt) -{ - if (fdt_magic(fdt) != FDT_SW_MAGIC) - return -FDT_ERR_BADMAGIC; - /* FIXME: should check more details about the header state */ - return 0; -} - -#define FDT_SW_CHECK_HEADER(fdt) \ - { \ - int err; \ - if ((err = _fdt_sw_check_header(fdt)) != 0) \ - return err; \ - } - -static void *_fdt_grab_space(void *fdt, size_t len) -{ - int offset = fdt_size_dt_struct(fdt); - int spaceleft; - - spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) - - fdt_size_dt_strings(fdt); - - if ((offset + len < offset) || (offset + len > spaceleft)) - return NULL; - - fdt_set_size_dt_struct(fdt, offset + len); - return _fdt_offset_ptr_w(fdt, offset); -} - -int fdt_create(void *buf, int bufsize) -{ - void *fdt = buf; - - if (bufsize < sizeof(struct fdt_header)) - return -FDT_ERR_NOSPACE; - - memset(buf, 0, bufsize); - - fdt_set_magic(fdt, FDT_SW_MAGIC); - fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); - fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); - fdt_set_totalsize(fdt, bufsize); - - fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), - sizeof(struct fdt_reserve_entry))); - fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); - fdt_set_off_dt_strings(fdt, bufsize); - - return 0; -} - -int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) -{ - struct fdt_reserve_entry *re; - int offset; - - FDT_SW_CHECK_HEADER(fdt); - - if (fdt_size_dt_struct(fdt)) - return -FDT_ERR_BADSTATE; - - offset = fdt_off_dt_struct(fdt); - if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) - return -FDT_ERR_NOSPACE; - - re = (struct fdt_reserve_entry *)((char *)fdt + offset); - re->address = cpu_to_fdt64(addr); - re->size = cpu_to_fdt64(size); - - fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); - - return 0; -} - -int fdt_finish_reservemap(void *fdt) -{ - return fdt_add_reservemap_entry(fdt, 0, 0); -} - -int fdt_begin_node(void *fdt, const char *name) -{ - struct fdt_node_header *nh; - int namelen = strlen(name) + 1; - - FDT_SW_CHECK_HEADER(fdt); - - nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); - if (! nh) - return -FDT_ERR_NOSPACE; - - nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); - memcpy(nh->name, name, namelen); - return 0; -} - -int fdt_end_node(void *fdt) -{ - fdt32_t *en; - - FDT_SW_CHECK_HEADER(fdt); - - en = _fdt_grab_space(fdt, FDT_TAGSIZE); - if (! en) - return -FDT_ERR_NOSPACE; - - *en = cpu_to_fdt32(FDT_END_NODE); - return 0; -} - -static int _fdt_find_add_string(void *fdt, const char *s) -{ - char *strtab = (char *)fdt + fdt_totalsize(fdt); - const char *p; - int strtabsize = fdt_size_dt_strings(fdt); - int len = strlen(s) + 1; - int struct_top, offset; - - p = _fdt_find_string(strtab - strtabsize, strtabsize, s); - if (p) - return p - strtab; - - /* Add it */ - offset = -strtabsize - len; - struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); - if (fdt_totalsize(fdt) + offset < struct_top) - return 0; /* no more room :( */ - - memcpy(strtab + offset, s, len); - fdt_set_size_dt_strings(fdt, strtabsize + len); - return offset; -} - -int fdt_property(void *fdt, const char *name, const void *val, int len) -{ - struct fdt_property *prop; - int nameoff; - - FDT_SW_CHECK_HEADER(fdt); - - nameoff = _fdt_find_add_string(fdt, name); - if (nameoff == 0) - return -FDT_ERR_NOSPACE; - - prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); - if (! prop) - return -FDT_ERR_NOSPACE; - - prop->tag = cpu_to_fdt32(FDT_PROP); - prop->nameoff = cpu_to_fdt32(nameoff); - prop->len = cpu_to_fdt32(len); - memcpy(prop->data, val, len); - return 0; -} - -int fdt_finish(void *fdt) -{ - char *p = (char *)fdt; - fdt32_t *end; - int oldstroffset, newstroffset; - uint32_t tag; - int offset, nextoffset; - - FDT_SW_CHECK_HEADER(fdt); - - /* Add terminator */ - end = _fdt_grab_space(fdt, sizeof(*end)); - if (! end) - return -FDT_ERR_NOSPACE; - *end = cpu_to_fdt32(FDT_END); - - /* Relocate the string table */ - oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); - newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); - memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); - fdt_set_off_dt_strings(fdt, newstroffset); - - /* Walk the structure, correcting string offsets */ - offset = 0; - while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { - if (tag == FDT_PROP) { - struct fdt_property *prop = - _fdt_offset_ptr_w(fdt, offset); - int nameoff; - - nameoff = fdt32_to_cpu(prop->nameoff); - nameoff += fdt_size_dt_strings(fdt); - prop->nameoff = cpu_to_fdt32(nameoff); - } - offset = nextoffset; - } - if (nextoffset < 0) - return nextoffset; - - /* Finally, adjust the header */ - fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); - fdt_set_magic(fdt, FDT_MAGIC); - return 0; -} diff --git a/lib/libfdt/fdt_wip.c b/lib/libfdt/fdt_wip.c deleted file mode 100644 index c5bbb68d..00000000 --- a/lib/libfdt/fdt_wip.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "libfdt_env.h" - -#include -#include - -#include "libfdt_internal.h" - -int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, - const void *val, int len) -{ - void *propval; - int proplen; - - propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); - if (! propval) - return proplen; - - if (proplen != len) - return -FDT_ERR_NOSPACE; - - memcpy(propval, val, len); - return 0; -} - -static void _fdt_nop_region(void *start, int len) -{ - fdt32_t *p; - - for (p = start; (char *)p < ((char *)start + len); p++) - *p = cpu_to_fdt32(FDT_NOP); -} - -int fdt_nop_property(void *fdt, int nodeoffset, const char *name) -{ - struct fdt_property *prop; - int len; - - prop = fdt_get_property_w(fdt, nodeoffset, name, &len); - if (! prop) - return len; - - _fdt_nop_region(prop, len + sizeof(*prop)); - - return 0; -} - -int _fdt_node_end_offset(void *fdt, int offset) -{ - int depth = 0; - - while ((offset >= 0) && (depth >= 0)) - offset = fdt_next_node(fdt, offset, &depth); - - return offset; -} - -int fdt_nop_node(void *fdt, int nodeoffset) -{ - int endoffset; - - endoffset = _fdt_node_end_offset(fdt, nodeoffset); - if (endoffset < 0) - return endoffset; - - _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), - endoffset - nodeoffset); - return 0; -} diff --git a/lib/libfdt/libfdt.h b/lib/libfdt/libfdt.h deleted file mode 100644 index 02baa84a..00000000 --- a/lib/libfdt/libfdt.h +++ /dev/null @@ -1,1514 +0,0 @@ -#ifndef _LIBFDT_H -#define _LIBFDT_H -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -#define FDT_FIRST_SUPPORTED_VERSION 0x10 -#define FDT_LAST_SUPPORTED_VERSION 0x11 - -/* Error codes: informative error codes */ -#define FDT_ERR_NOTFOUND 1 - /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ -#define FDT_ERR_EXISTS 2 - /* FDT_ERR_EXISTS: Attemped to create a node or property which - * already exists */ -#define FDT_ERR_NOSPACE 3 - /* FDT_ERR_NOSPACE: Operation needed to expand the device - * tree, but its buffer did not have sufficient space to - * contain the expanded tree. Use fdt_open_into() to move the - * device tree to a buffer with more space. */ - -/* Error codes: codes for bad parameters */ -#define FDT_ERR_BADOFFSET 4 - /* FDT_ERR_BADOFFSET: Function was passed a structure block - * offset which is out-of-bounds, or which points to an - * unsuitable part of the structure for the operation. */ -#define FDT_ERR_BADPATH 5 - /* FDT_ERR_BADPATH: Function was passed a badly formatted path - * (e.g. missing a leading / for a function which requires an - * absolute path) */ -#define FDT_ERR_BADPHANDLE 6 - /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle - * value. phandle values of 0 and -1 are not permitted. */ -#define FDT_ERR_BADSTATE 7 - /* FDT_ERR_BADSTATE: Function was passed an incomplete device - * tree created by the sequential-write functions, which is - * not sufficiently complete for the requested operation. */ - -/* Error codes: codes for bad device tree blobs */ -#define FDT_ERR_TRUNCATED 8 - /* FDT_ERR_TRUNCATED: Structure block of the given device tree - * ends without an FDT_END tag. */ -#define FDT_ERR_BADMAGIC 9 - /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a - * device tree at all - it is missing the flattened device - * tree magic number. */ -#define FDT_ERR_BADVERSION 10 - /* FDT_ERR_BADVERSION: Given device tree has a version which - * can't be handled by the requested operation. For - * read-write functions, this may mean that fdt_open_into() is - * required to convert the tree to the expected version. */ -#define FDT_ERR_BADSTRUCTURE 11 - /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt - * structure block or other serious error (e.g. misnested - * nodes, or subnodes preceding properties). */ -#define FDT_ERR_BADLAYOUT 12 - /* FDT_ERR_BADLAYOUT: For read-write functions, the given - * device tree has it's sub-blocks in an order that the - * function can't handle (memory reserve map, then structure, - * then strings). Use fdt_open_into() to reorganize the tree - * into a form suitable for the read-write operations. */ - -/* "Can't happen" error indicating a bug in libfdt */ -#define FDT_ERR_INTERNAL 13 - /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. - * Should never be returned, if it is, it indicates a bug in - * libfdt itself. */ - -#define FDT_ERR_MAX 13 - -/**********************************************************************/ -/* Low-level functions (you probably don't need these) */ -/**********************************************************************/ - -const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); -static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) -{ - return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); -} - -uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); - -/**********************************************************************/ -/* Traversal functions */ -/**********************************************************************/ - -int fdt_next_node(const void *fdt, int offset, int *depth); - -/** - * fdt_first_subnode() - get offset of first direct subnode - * - * @fdt: FDT blob - * @offset: Offset of node to check - * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none - */ -int fdt_first_subnode(const void *fdt, int offset); - -/** - * fdt_next_subnode() - get offset of next direct subnode - * - * After first calling fdt_first_subnode(), call this function repeatedly to - * get direct subnodes of a parent node. - * - * @fdt: FDT blob - * @offset: Offset of previous subnode - * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more - * subnodes - */ -int fdt_next_subnode(const void *fdt, int offset); - -/**********************************************************************/ -/* General functions */ -/**********************************************************************/ - -#define fdt_get_header(fdt, field) \ - (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) -#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) -#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) -#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) -#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) -#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) -#define fdt_version(fdt) (fdt_get_header(fdt, version)) -#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) -#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) -#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) -#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) - -#define __fdt_set_hdr(name) \ - static inline void fdt_set_##name(void *fdt, uint32_t val) \ - { \ - struct fdt_header *fdth = (struct fdt_header*)fdt; \ - fdth->name = cpu_to_fdt32(val); \ - } -__fdt_set_hdr(magic); -__fdt_set_hdr(totalsize); -__fdt_set_hdr(off_dt_struct); -__fdt_set_hdr(off_dt_strings); -__fdt_set_hdr(off_mem_rsvmap); -__fdt_set_hdr(version); -__fdt_set_hdr(last_comp_version); -__fdt_set_hdr(boot_cpuid_phys); -__fdt_set_hdr(size_dt_strings); -__fdt_set_hdr(size_dt_struct); -#undef __fdt_set_hdr - -/** - * fdt_check_header - sanity check a device tree or possible device tree - * @fdt: pointer to data which might be a flattened device tree - * - * fdt_check_header() checks that the given buffer contains what - * appears to be a flattened device tree with sane information in its - * header. - * - * returns: - * 0, if the buffer appears to contain a valid device tree - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings, as above - */ -int fdt_check_header(const void *fdt); - -/** - * fdt_move - move a device tree around in memory - * @fdt: pointer to the device tree to move - * @buf: pointer to memory where the device is to be moved - * @bufsize: size of the memory space at buf - * - * fdt_move() relocates, if possible, the device tree blob located at - * fdt to the buffer at buf of size bufsize. The buffer may overlap - * with the existing device tree blob at fdt. Therefore, - * fdt_move(fdt, fdt, fdt_totalsize(fdt)) - * should always succeed. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -int fdt_move(const void *fdt, void *buf, int bufsize); - -/**********************************************************************/ -/* Read-only functions */ -/**********************************************************************/ - -/** - * fdt_string - retrieve a string from the strings block of a device tree - * @fdt: pointer to the device tree blob - * @stroffset: offset of the string within the strings block (native endian) - * - * fdt_string() retrieves a pointer to a single string from the - * strings block of the device tree blob at fdt. - * - * returns: - * a pointer to the string, on success - * NULL, if stroffset is out of bounds - */ -const char *fdt_string(const void *fdt, int stroffset); - -/** - * fdt_num_mem_rsv - retrieve the number of memory reserve map entries - * @fdt: pointer to the device tree blob - * - * Returns the number of entries in the device tree blob's memory - * reservation map. This does not include the terminating 0,0 entry - * or any other (0,0) entries reserved for expansion. - * - * returns: - * the number of entries - */ -int fdt_num_mem_rsv(const void *fdt); - -/** - * fdt_get_mem_rsv - retrieve one memory reserve map entry - * @fdt: pointer to the device tree blob - * @address, @size: pointers to 64-bit variables - * - * On success, *address and *size will contain the address and size of - * the n-th reserve map entry from the device tree blob, in - * native-endian format. - * - * returns: - * 0, on success - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); - -/** - * fdt_subnode_offset_namelen - find a subnode based on substring - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * @namelen: number of characters of name to consider - * - * Identical to fdt_subnode_offset(), but only examine the first - * namelen characters of name for matching the subnode name. This is - * useful for finding subnodes based on a portion of a larger string, - * such as a full path. - */ -int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, - const char *name, int namelen); -/** - * fdt_subnode_offset - find a subnode of a given node - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * - * fdt_subnode_offset() finds a subnode of the node at structure block - * offset parentoffset with the given name. name may include a unit - * address, in which case fdt_subnode_offset() will find the subnode - * with that unit address, or the unit address may be omitted, in - * which case fdt_subnode_offset() will find an arbitrary subnode - * whose name excluding unit address matches the given name. - * - * returns: - * structure block offset of the requested subnode (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); - -/** - * fdt_path_offset - find a tree node by its full path - * @fdt: pointer to the device tree blob - * @path: full path of the node to locate - * - * fdt_path_offset() finds a node of a given path in the device tree. - * Each path component may omit the unit address portion, but the - * results of this are undefined if any such path component is - * ambiguous (that is if there are multiple nodes at the relevant - * level matching the given component, differentiated only by unit - * address). - * - * returns: - * structure block offset of the node with the requested path (>=0), on success - * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid - * -FDT_ERR_NOTFOUND, if the requested node does not exist - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_path_offset(const void *fdt, const char *path); - -/** - * fdt_get_name - retrieve the name of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of the starting node - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_get_name() retrieves the name (including unit address) of the - * device tree node at structure block offset nodeoffset. If lenp is - * non-NULL, the length of this name is also returned, in the integer - * pointed to by lenp. - * - * returns: - * pointer to the node's name, on success - * If lenp is non-NULL, *lenp contains the length of that name (>=0) - * NULL, on error - * if lenp is non-NULL *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); - -/** - * fdt_first_property_offset - find the offset of a node's first property - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of a node - * - * fdt_first_property_offset() finds the first property of the node at - * the given structure block offset. - * - * returns: - * structure block offset of the property (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested node has no properties - * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_first_property_offset(const void *fdt, int nodeoffset); - -/** - * fdt_next_property_offset - step through a node's properties - * @fdt: pointer to the device tree blob - * @offset: structure block offset of a property - * - * fdt_next_property_offset() finds the property immediately after the - * one at the given structure block offset. This will be a property - * of the same node as the given property. - * - * returns: - * structure block offset of the next property (>=0), on success - * -FDT_ERR_NOTFOUND, if the given property is the last in its node - * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_next_property_offset(const void *fdt, int offset); - -/** - * fdt_get_property_by_offset - retrieve the property at a given offset - * @fdt: pointer to the device tree blob - * @offset: offset of the property to retrieve - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_get_property_by_offset() retrieves a pointer to the - * fdt_property structure within the device tree blob at the given - * offset. If lenp is non-NULL, the length of the property value is - * also returned, in the integer pointed to by lenp. - * - * returns: - * pointer to the structure representing the property - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const struct fdt_property *fdt_get_property_by_offset(const void *fdt, - int offset, - int *lenp); - -/** - * fdt_get_property_namelen - find a property based on substring - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @namelen: number of characters of name to consider - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * Identical to fdt_get_property_namelen(), but only examine the first - * namelen characters of name for matching the property name. - */ -const struct fdt_property *fdt_get_property_namelen(const void *fdt, - int nodeoffset, - const char *name, - int namelen, int *lenp); - -/** - * fdt_get_property - find a given property in a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_get_property() retrieves a pointer to the fdt_property - * structure within the device tree blob corresponding to the property - * named 'name' of the node at offset nodeoffset. If lenp is - * non-NULL, the length of the property value is also returned, in the - * integer pointed to by lenp. - * - * returns: - * pointer to the structure representing the property - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, - const char *name, int *lenp); -static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, - const char *name, - int *lenp) -{ - return (struct fdt_property *)(uintptr_t) - fdt_get_property(fdt, nodeoffset, name, lenp); -} - -/** - * fdt_getprop_by_offset - retrieve the value of a property at a given offset - * @fdt: pointer to the device tree blob - * @ffset: offset of the property to read - * @namep: pointer to a string variable (will be overwritten) or NULL - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_getprop_by_offset() retrieves a pointer to the value of the - * property at structure block offset 'offset' (this will be a pointer - * to within the device blob itself, not a copy of the value). If - * lenp is non-NULL, the length of the property value is also - * returned, in the integer pointed to by lenp. If namep is non-NULL, - * the property's namne will also be returned in the char * pointed to - * by namep (this will be a pointer to within the device tree's string - * block, not a new copy of the name). - * - * returns: - * pointer to the property's value - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * if namep is non-NULL *namep contiains a pointer to the property - * name. - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const void *fdt_getprop_by_offset(const void *fdt, int offset, - const char **namep, int *lenp); - -/** - * fdt_getprop_namelen - get property value based on substring - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @namelen: number of characters of name to consider - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * Identical to fdt_getprop(), but only examine the first namelen - * characters of name for matching the property name. - */ -const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, - const char *name, int namelen, int *lenp); - -/** - * fdt_getprop - retrieve the value of a given property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to find - * @name: name of the property to find - * @lenp: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_getprop() retrieves a pointer to the value of the property - * named 'name' of the node at offset nodeoffset (this will be a - * pointer to within the device blob itself, not a copy of the value). - * If lenp is non-NULL, the length of the property value is also - * returned, in the integer pointed to by lenp. - * - * returns: - * pointer to the property's value - * if lenp is non-NULL, *lenp contains the length of the property - * value (>=0) - * NULL, on error - * if lenp is non-NULL, *lenp contains an error code (<0): - * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -const void *fdt_getprop(const void *fdt, int nodeoffset, - const char *name, int *lenp); -static inline void *fdt_getprop_w(void *fdt, int nodeoffset, - const char *name, int *lenp) -{ - return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); -} - -/** - * fdt_get_phandle - retrieve the phandle of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of the node - * - * fdt_get_phandle() retrieves the phandle of the device tree node at - * structure block offset nodeoffset. - * - * returns: - * the phandle of the node at nodeoffset, on success (!= 0, != -1) - * 0, if the node has no phandle, or another error occurs - */ -uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); - -/** - * fdt_get_alias_namelen - get alias based on substring - * @fdt: pointer to the device tree blob - * @name: name of the alias th look up - * @namelen: number of characters of name to consider - * - * Identical to fdt_get_alias(), but only examine the first namelen - * characters of name for matching the alias name. - */ -const char *fdt_get_alias_namelen(const void *fdt, - const char *name, int namelen); - -/** - * fdt_get_alias - retreive the path referenced by a given alias - * @fdt: pointer to the device tree blob - * @name: name of the alias th look up - * - * fdt_get_alias() retrieves the value of a given alias. That is, the - * value of the property named 'name' in the node /aliases. - * - * returns: - * a pointer to the expansion of the alias named 'name', if it exists - * NULL, if the given alias or the /aliases node does not exist - */ -const char *fdt_get_alias(const void *fdt, const char *name); - -/** - * fdt_get_path - determine the full path of a node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose path to find - * @buf: character buffer to contain the returned path (will be overwritten) - * @buflen: size of the character buffer at buf - * - * fdt_get_path() computes the full path of the node at offset - * nodeoffset, and records that path in the buffer at buf. - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset. - * - * returns: - * 0, on success - * buf contains the absolute path of the node at - * nodeoffset, as a NUL-terminated string. - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) - * characters and will not fit in the given buffer. - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); - -/** - * fdt_supernode_atdepth_offset - find a specific ancestor of a node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose parent to find - * @supernodedepth: depth of the ancestor to find - * @nodedepth: pointer to an integer variable (will be overwritten) or NULL - * - * fdt_supernode_atdepth_offset() finds an ancestor of the given node - * at a specific depth from the root (where the root itself has depth - * 0, its immediate subnodes depth 1 and so forth). So - * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); - * will always return 0, the offset of the root node. If the node at - * nodeoffset has depth D, then: - * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); - * will return nodeoffset itself. - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset. - * - * returns: - - * structure block offset of the node at node offset's ancestor - * of depth supernodedepth (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag -* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, - int supernodedepth, int *nodedepth); - -/** - * fdt_node_depth - find the depth of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose parent to find - * - * fdt_node_depth() finds the depth of a given node. The root node - * has depth 0, its immediate subnodes depth 1 and so forth. - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset. - * - * returns: - * depth of the node at nodeoffset (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_depth(const void *fdt, int nodeoffset); - -/** - * fdt_parent_offset - find the parent of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose parent to find - * - * fdt_parent_offset() locates the parent node of a given node (that - * is, it finds the offset of the node which contains the node at - * nodeoffset as a subnode). - * - * NOTE: This function is expensive, as it must scan the device tree - * structure from the start to nodeoffset, *twice*. - * - * returns: - * structure block offset of the parent of the node at nodeoffset - * (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_parent_offset(const void *fdt, int nodeoffset); - -/** - * fdt_node_offset_by_prop_value - find nodes with a given property value - * @fdt: pointer to the device tree blob - * @startoffset: only find nodes after this offset - * @propname: property name to check - * @propval: property value to search for - * @proplen: length of the value in propval - * - * fdt_node_offset_by_prop_value() returns the offset of the first - * node after startoffset, which has a property named propname whose - * value is of length proplen and has value equal to propval; or if - * startoffset is -1, the very first such node in the tree. - * - * To iterate through all nodes matching the criterion, the following - * idiom can be used: - * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, - * propval, proplen); - * while (offset != -FDT_ERR_NOTFOUND) { - * // other code here - * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, - * propval, proplen); - * } - * - * Note the -1 in the first call to the function, if 0 is used here - * instead, the function will never locate the root node, even if it - * matches the criterion. - * - * returns: - * structure block offset of the located node (>= 0, >startoffset), - * on success - * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the - * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, - const char *propname, - const void *propval, int proplen); - -/** - * fdt_node_offset_by_phandle - find the node with a given phandle - * @fdt: pointer to the device tree blob - * @phandle: phandle value - * - * fdt_node_offset_by_phandle() returns the offset of the node - * which has the given phandle value. If there is more than one node - * in the tree with the given phandle (an invalid tree), results are - * undefined. - * - * returns: - * structure block offset of the located node (>= 0), on success - * -FDT_ERR_NOTFOUND, no node with that phandle exists - * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); - -/** - * fdt_node_check_compatible: check a node's compatible property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of a tree node - * @compatible: string to match against - * - * - * fdt_node_check_compatible() returns 0 if the given node contains a - * 'compatible' property with the given string as one of its elements, - * it returns non-zero otherwise, or on error. - * - * returns: - * 0, if the node has a 'compatible' property listing the given string - * 1, if the node has a 'compatible' property, but it does not list - * the given string - * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property - * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_check_compatible(const void *fdt, int nodeoffset, - const char *compatible); - -/** - * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value - * @fdt: pointer to the device tree blob - * @startoffset: only find nodes after this offset - * @compatible: 'compatible' string to match against - * - * fdt_node_offset_by_compatible() returns the offset of the first - * node after startoffset, which has a 'compatible' property which - * lists the given compatible string; or if startoffset is -1, the - * very first such node in the tree. - * - * To iterate through all nodes matching the criterion, the following - * idiom can be used: - * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); - * while (offset != -FDT_ERR_NOTFOUND) { - * // other code here - * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); - * } - * - * Note the -1 in the first call to the function, if 0 is used here - * instead, the function will never locate the root node, even if it - * matches the criterion. - * - * returns: - * structure block offset of the located node (>= 0, >startoffset), - * on success - * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the - * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, standard meanings - */ -int fdt_node_offset_by_compatible(const void *fdt, int startoffset, - const char *compatible); - -/** - * fdt_stringlist_contains - check a string list property for a string - * @strlist: Property containing a list of strings to check - * @listlen: Length of property - * @str: String to search for - * - * This is a utility function provided for convenience. The list contains - * one or more strings, each terminated by \0, as is found in a device tree - * "compatible" property. - * - * @return: 1 if the string is found in the list, 0 not found, or invalid list - */ -int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); - -/**********************************************************************/ -/* Write-in-place functions */ -/**********************************************************************/ - -/** - * fdt_setprop_inplace - change a property's value, but not its size - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: pointer to data to replace the property value with - * @len: length of the property value - * - * fdt_setprop_inplace() replaces the value of a given property with - * the data in val, of length len. This function cannot change the - * size of a property, and so will only work if len is equal to the - * current length of the property. - * - * This function will alter only the bytes in the blob which contain - * the given property value, and will not alter or move any other part - * of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if len is not equal to the property's current length - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, - const void *val, int len); - -/** - * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 32-bit integer value to replace the property with - * - * fdt_setprop_inplace_u32() replaces the value of a given property - * with the 32-bit integer value in val, converting val to big-endian - * if necessary. This function cannot change the size of a property, - * and so will only work if the property already exists and has length - * 4. - * - * This function will alter only the bytes in the blob which contain - * the given property value, and will not alter or move any other part - * of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, - const char *name, uint32_t val) -{ - fdt32_t tmp = cpu_to_fdt32(val); - return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); -} - -/** - * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 64-bit integer value to replace the property with - * - * fdt_setprop_inplace_u64() replaces the value of a given property - * with the 64-bit integer value in val, converting val to big-endian - * if necessary. This function cannot change the size of a property, - * and so will only work if the property already exists and has length - * 8. - * - * This function will alter only the bytes in the blob which contain - * the given property value, and will not alter or move any other part - * of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, if the property's length is not equal to 8 - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, - const char *name, uint64_t val) -{ - fdt64_t tmp = cpu_to_fdt64(val); - return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); -} - -/** - * fdt_setprop_inplace_cell - change the value of a single-cell property - * - * This is an alternative name for fdt_setprop_inplace_u32() - */ -static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, - const char *name, uint32_t val) -{ - return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val); -} - -/** - * fdt_nop_property - replace a property with nop tags - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to nop - * @name: name of the property to nop - * - * fdt_nop_property() will replace a given property's representation - * in the blob with FDT_NOP tags, effectively removing it from the - * tree. - * - * This function will alter only the bytes in the blob which contain - * the property, and will not alter or move any other part of the - * tree. - * - * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_nop_property(void *fdt, int nodeoffset, const char *name); - -/** - * fdt_nop_node - replace a node (subtree) with nop tags - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node to nop - * - * fdt_nop_node() will replace a given node's representation in the - * blob, including all its subnodes, if any, with FDT_NOP tags, - * effectively removing it from the tree. - * - * This function will alter only the bytes in the blob which contain - * the node and its properties and subnodes, and will not alter or - * move any other part of the tree. - * - * returns: - * 0, on success - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_nop_node(void *fdt, int nodeoffset); - -/**********************************************************************/ -/* Sequential write functions */ -/**********************************************************************/ - -int fdt_create(void *buf, int bufsize); -int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); -int fdt_finish_reservemap(void *fdt); -int fdt_begin_node(void *fdt, const char *name); -int fdt_property(void *fdt, const char *name, const void *val, int len); -static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val) -{ - fdt32_t tmp = cpu_to_fdt32(val); - return fdt_property(fdt, name, &tmp, sizeof(tmp)); -} -static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) -{ - fdt64_t tmp = cpu_to_fdt64(val); - return fdt_property(fdt, name, &tmp, sizeof(tmp)); -} -static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) -{ - return fdt_property_u32(fdt, name, val); -} -#define fdt_property_string(fdt, name, str) \ - fdt_property(fdt, name, str, strlen(str)+1) -int fdt_end_node(void *fdt); -int fdt_finish(void *fdt); - -/**********************************************************************/ -/* Read-write functions */ -/**********************************************************************/ - -int fdt_create_empty_tree(void *buf, int bufsize); -int fdt_open_into(const void *fdt, void *buf, int bufsize); -int fdt_pack(void *fdt); - -/** - * fdt_add_mem_rsv - add one memory reserve map entry - * @fdt: pointer to the device tree blob - * @address, @size: 64-bit values (native endian) - * - * Adds a reserve map entry to the given blob reserving a region at - * address address of length size. - * - * This function will insert data into the reserve map and will - * therefore change the indexes of some entries in the table. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new reservation entry - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); - -/** - * fdt_del_mem_rsv - remove a memory reserve map entry - * @fdt: pointer to the device tree blob - * @n: entry to remove - * - * fdt_del_mem_rsv() removes the n-th memory reserve map entry from - * the blob. - * - * This function will delete data from the reservation table and will - * therefore change the indexes of some entries in the table. - * - * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there - * are less than n+1 reserve map entries) - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_del_mem_rsv(void *fdt, int n); - -/** - * fdt_set_name - change the name of a given node - * @fdt: pointer to the device tree blob - * @nodeoffset: structure block offset of a node - * @name: name to give the node - * - * fdt_set_name() replaces the name (including unit address, if any) - * of the given node with the given string. NOTE: this function can't - * efficiently check if the new name is unique amongst the given - * node's siblings; results are undefined if this function is invoked - * with a name equal to one of the given node's siblings. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob - * to contain the new name - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, standard meanings - */ -int fdt_set_name(void *fdt, int nodeoffset, const char *name); - -/** - * fdt_setprop - create or change a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: pointer to data to set the property value to - * @len: length of the property value - * - * fdt_setprop() sets the value of the named property in the given - * node to the given value and length, creating the property if it - * does not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_setprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len); - -/** - * fdt_setprop_u32 - set a property to a 32-bit integer - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 32-bit integer value for the property (native endian) - * - * fdt_setprop_u32() sets the value of the named property in the given - * node to the given 32-bit integer value (converting to big-endian if - * necessary), or creates a new property with that value if it does - * not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, - uint32_t val) -{ - fdt32_t tmp = cpu_to_fdt32(val); - return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); -} - -/** - * fdt_setprop_u64 - set a property to a 64-bit integer - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 64-bit integer value for the property (native endian) - * - * fdt_setprop_u64() sets the value of the named property in the given - * node to the given 64-bit integer value (converting to big-endian if - * necessary), or creates a new property with that value if it does - * not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, - uint64_t val) -{ - fdt64_t tmp = cpu_to_fdt64(val); - return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); -} - -/** - * fdt_setprop_cell - set a property to a single cell value - * - * This is an alternative name for fdt_setprop_u32() - */ -static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, - uint32_t val) -{ - return fdt_setprop_u32(fdt, nodeoffset, name, val); -} - -/** - * fdt_setprop_string - set a property to a string value - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @str: string value for the property - * - * fdt_setprop_string() sets the value of the named property in the - * given node to the given string value (using the length of the - * string to determine the new length of the property), or creates a - * new property with that value if it does not already exist. - * - * This function may insert or delete data from the blob, and will - * therefore change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -#define fdt_setprop_string(fdt, nodeoffset, name, str) \ - fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) - -/** - * fdt_appendprop - append to or create a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to append to - * @val: pointer to data to append to the property value - * @len: length of the data to append to the property value - * - * fdt_appendprop() appends the value to the named property in the - * given node, creating the property if it does not already exist. - * - * This function may insert data into the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_appendprop(void *fdt, int nodeoffset, const char *name, - const void *val, int len); - -/** - * fdt_appendprop_u32 - append a 32-bit integer value to a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 32-bit integer value to append to the property (native endian) - * - * fdt_appendprop_u32() appends the given 32-bit integer value - * (converting to big-endian if necessary) to the value of the named - * property in the given node, or creates a new property with that - * value if it does not already exist. - * - * This function may insert data into the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, - const char *name, uint32_t val) -{ - fdt32_t tmp = cpu_to_fdt32(val); - return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); -} - -/** - * fdt_appendprop_u64 - append a 64-bit integer value to a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @val: 64-bit integer value to append to the property (native endian) - * - * fdt_appendprop_u64() appends the given 64-bit integer value - * (converting to big-endian if necessary) to the value of the named - * property in the given node, or creates a new property with that - * value if it does not already exist. - * - * This function may insert data into the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, - const char *name, uint64_t val) -{ - fdt64_t tmp = cpu_to_fdt64(val); - return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); -} - -/** - * fdt_appendprop_cell - append a single cell value to a property - * - * This is an alternative name for fdt_appendprop_u32() - */ -static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, - const char *name, uint32_t val) -{ - return fdt_appendprop_u32(fdt, nodeoffset, name, val); -} - -/** - * fdt_appendprop_string - append a string to a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to change - * @name: name of the property to change - * @str: string value to append to the property - * - * fdt_appendprop_string() appends the given string to the value of - * the named property in the given node, or creates a new property - * with that value if it does not already exist. - * - * This function may insert data into the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to - * contain the new property value - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_TRUNCATED, standard meanings - */ -#define fdt_appendprop_string(fdt, nodeoffset, name, str) \ - fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) - -/** - * fdt_delprop - delete a property - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node whose property to nop - * @name: name of the property to nop - * - * fdt_del_property() will delete the given property. - * - * This function will delete data from the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_NOTFOUND, node does not have the named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_delprop(void *fdt, int nodeoffset, const char *name); - -/** - * fdt_add_subnode_namelen - creates a new node based on substring - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * @namelen: number of characters of name to consider - * - * Identical to fdt_add_subnode(), but use only the first namelen - * characters of name as the name of the new node. This is useful for - * creating subnodes based on a portion of a larger string, such as a - * full path. - */ -int fdt_add_subnode_namelen(void *fdt, int parentoffset, - const char *name, int namelen); - -/** - * fdt_add_subnode - creates a new node - * @fdt: pointer to the device tree blob - * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate - * - * fdt_add_subnode() creates a new node as a subnode of the node at - * structure block offset parentoffset, with the given name (which - * should include the unit address, if any). - * - * This function will insert data into the blob, and will therefore - * change the offsets of some existing nodes. - - * returns: - * structure block offset of the created nodeequested subnode (>=0), on success - * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of - * the given name - * -FDT_ERR_NOSPACE, if there is insufficient free space in the - * blob to contain the new node - * -FDT_ERR_NOSPACE - * -FDT_ERR_BADLAYOUT - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings. - */ -int fdt_add_subnode(void *fdt, int parentoffset, const char *name); - -/** - * fdt_del_node - delete a node (subtree) - * @fdt: pointer to the device tree blob - * @nodeoffset: offset of the node to nop - * - * fdt_del_node() will remove the given node, including all its - * subnodes if any, from the blob. - * - * This function will delete data from the blob, and will therefore - * change the offsets of some existing nodes. - * - * returns: - * 0, on success - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag - * -FDT_ERR_BADLAYOUT, - * -FDT_ERR_BADMAGIC, - * -FDT_ERR_BADVERSION, - * -FDT_ERR_BADSTATE, - * -FDT_ERR_BADSTRUCTURE, - * -FDT_ERR_TRUNCATED, standard meanings - */ -int fdt_del_node(void *fdt, int nodeoffset); - -/**********************************************************************/ -/* Debugging / informational functions */ -/**********************************************************************/ - -const char *fdt_strerror(int errval); - -#endif /* _LIBFDT_H */ diff --git a/lib/libfdt/libfdt_env.h b/lib/libfdt/libfdt_env.h deleted file mode 100644 index 9dea97df..00000000 --- a/lib/libfdt/libfdt_env.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _LIBFDT_ENV_H -#define _LIBFDT_ENV_H -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * Copyright 2012 Kim Phillips, Freescale Semiconductor. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include - -#ifdef __CHECKER__ -#define __force __attribute__((force)) -#define __bitwise __attribute__((bitwise)) -#else -#define __force -#define __bitwise -#endif - -typedef uint16_t __bitwise fdt16_t; -typedef uint32_t __bitwise fdt32_t; -typedef uint64_t __bitwise fdt64_t; - -#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) -#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) -#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \ - (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) -#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \ - (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ - (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ - (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) - -static inline uint16_t fdt16_to_cpu(fdt16_t x) -{ - return (__force uint16_t)CPU_TO_FDT16(x); -} -static inline fdt16_t cpu_to_fdt16(uint16_t x) -{ - return (__force fdt16_t)CPU_TO_FDT16(x); -} - -static inline uint32_t fdt32_to_cpu(fdt32_t x) -{ - return (__force uint32_t)CPU_TO_FDT32(x); -} -static inline fdt32_t cpu_to_fdt32(uint32_t x) -{ - return (__force fdt32_t)CPU_TO_FDT32(x); -} - -static inline uint64_t fdt64_to_cpu(fdt64_t x) -{ - return (__force uint64_t)CPU_TO_FDT64(x); -} -static inline fdt64_t cpu_to_fdt64(uint64_t x) -{ - return (__force fdt64_t)CPU_TO_FDT64(x); -} -#undef CPU_TO_FDT64 -#undef CPU_TO_FDT32 -#undef CPU_TO_FDT16 -#undef EXTRACT_BYTE - -#endif /* _LIBFDT_ENV_H */ diff --git a/lib/libfdt/libfdt_internal.h b/lib/libfdt/libfdt_internal.h deleted file mode 100644 index 381133ba..00000000 --- a/lib/libfdt/libfdt_internal.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef _LIBFDT_INTERNAL_H -#define _LIBFDT_INTERNAL_H -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - * - * libfdt is dual licensed: you can use it either under the terms of - * the GPL, or the BSD license, at your option. - * - * a) This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * Alternatively, - * - * b) Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include - -#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) - -#define FDT_CHECK_HEADER(fdt) \ - { \ - int err; \ - if ((err = fdt_check_header(fdt)) != 0) \ - return err; \ - } - -int _fdt_check_node_offset(const void *fdt, int offset); -int _fdt_check_prop_offset(const void *fdt, int offset); -const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); -int _fdt_node_end_offset(void *fdt, int nodeoffset); - -static inline const void *_fdt_offset_ptr(const void *fdt, int offset) -{ - return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; -} - -static inline void *_fdt_offset_ptr_w(void *fdt, int offset) -{ - return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset); -} - -static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) -{ - const struct fdt_reserve_entry *rsv_table = - (const struct fdt_reserve_entry *) - ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); - - return rsv_table + n; -} -static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) -{ - return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n); -} - -#define FDT_SW_MAGIC (~FDT_MAGIC) - -#endif /* _LIBFDT_INTERNAL_H */ diff --git a/lib/libfdt/version.lds b/lib/libfdt/version.lds deleted file mode 100644 index 80b322be..00000000 --- a/lib/libfdt/version.lds +++ /dev/null @@ -1,60 +0,0 @@ -LIBFDT_1.2 { - global: - fdt_next_node; - fdt_check_header; - fdt_move; - fdt_string; - fdt_num_mem_rsv; - fdt_get_mem_rsv; - fdt_subnode_offset_namelen; - fdt_subnode_offset; - fdt_path_offset; - fdt_get_name; - fdt_get_property_namelen; - fdt_get_property; - fdt_getprop_namelen; - fdt_getprop; - fdt_get_phandle; - fdt_get_alias_namelen; - fdt_get_alias; - fdt_get_path; - fdt_supernode_atdepth_offset; - fdt_node_depth; - fdt_parent_offset; - fdt_node_offset_by_prop_value; - fdt_node_offset_by_phandle; - fdt_node_check_compatible; - fdt_node_offset_by_compatible; - fdt_setprop_inplace; - fdt_nop_property; - fdt_nop_node; - fdt_create; - fdt_add_reservemap_entry; - fdt_finish_reservemap; - fdt_begin_node; - fdt_property; - fdt_end_node; - fdt_finish; - fdt_open_into; - fdt_pack; - fdt_add_mem_rsv; - fdt_del_mem_rsv; - fdt_set_name; - fdt_setprop; - fdt_delprop; - fdt_add_subnode_namelen; - fdt_add_subnode; - fdt_del_node; - fdt_strerror; - fdt_offset_ptr; - fdt_next_tag; - fdt_appendprop; - fdt_create_empty_tree; - fdt_first_property_offset; - fdt_get_property_by_offset; - fdt_getprop_by_offset; - fdt_next_property_offset; - - local: - *; -}; diff --git a/lib/linux/compiler.h b/lib/linux/compiler.h deleted file mode 100644 index 2d72f18c..00000000 --- a/lib/linux/compiler.h +++ /dev/null @@ -1,83 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Taken from Linux commit 219d54332a09 ("Linux 5.4"), from the file - * tools/include/linux/compiler.h, with minor changes. - */ -#ifndef __LINUX_COMPILER_H -#define __LINUX_COMPILER_H - -#ifndef __ASSEMBLY__ - -#include - -#define barrier() asm volatile("" : : : "memory") - -#define __always_inline inline __attribute__((always_inline)) - -static __always_inline void __read_once_size(const volatile void *p, void *res, int size) -{ - switch (size) { - case 1: *(uint8_t *)res = *(volatile uint8_t *)p; break; - case 2: *(uint16_t *)res = *(volatile uint16_t *)p; break; - case 4: *(uint32_t *)res = *(volatile uint32_t *)p; break; - case 8: *(uint64_t *)res = *(volatile uint64_t *)p; break; - default: - barrier(); - __builtin_memcpy((void *)res, (const void *)p, size); - barrier(); - } -} - -/* - * Prevent the compiler from merging or refetching reads or writes. The - * compiler is also forbidden from reordering successive instances of - * READ_ONCE and WRITE_ONCE, but only when the compiler is aware of some - * particular ordering. One way to make the compiler aware of ordering is to - * put the two invocations of READ_ONCE or WRITE_ONCE in different C - * statements. - * - * These two macros will also work on aggregate data types like structs or - * unions. If the size of the accessed data type exceeds the word size of - * the machine (e.g., 32 bits or 64 bits) READ_ONCE() and WRITE_ONCE() will - * fall back to memcpy and print a compile-time warning. - * - * Their two major use cases are: (1) Mediating communication between - * process-level code and irq/NMI handlers, all running on the same CPU, - * and (2) Ensuring that the compiler does not fold, spindle, or otherwise - * mutilate accesses that either do not require ordering or that interact - * with an explicit memory barrier or atomic instruction that provides the - * required ordering. - */ - -#define READ_ONCE(x) \ -({ \ - union { typeof(x) __val; char __c[1]; } __u = \ - { .__c = { 0 } }; \ - __read_once_size(&(x), __u.__c, sizeof(x)); \ - __u.__val; \ -}) - -static __always_inline void __write_once_size(volatile void *p, void *res, int size) -{ - switch (size) { - case 1: *(volatile uint8_t *) p = *(uint8_t *) res; break; - case 2: *(volatile uint16_t *) p = *(uint16_t *) res; break; - case 4: *(volatile uint32_t *) p = *(uint32_t *) res; break; - case 8: *(volatile uint64_t *) p = *(uint64_t *) res; break; - default: - barrier(); - __builtin_memcpy((void *)p, (const void *)res, size); - barrier(); - } -} - -#define WRITE_ONCE(x, val) \ -({ \ - union { typeof(x) __val; char __c[1]; } __u = \ - { .__val = (val) }; \ - __write_once_size(&(x), __u.__c, sizeof(x)); \ - __u.__val; \ -}) - -#endif /* !__ASSEMBLY__ */ -#endif /* !__LINUX_COMPILER_H */ diff --git a/lib/linux/const.h b/lib/linux/const.h deleted file mode 100644 index c872bfd2..00000000 --- a/lib/linux/const.h +++ /dev/null @@ -1,27 +0,0 @@ -/* const.h: Macros for dealing with constants. */ - -#ifndef _LINUX_CONST_H -#define _LINUX_CONST_H - -/* Some constant macros are used in both assembler and - * C code. Therefore we cannot annotate them always with - * 'UL' and other type specifiers unilaterally. We - * use the following macros to deal with this. - * - * Similarly, _AT() will cast an expression with a type in C, but - * leave it unchanged in asm. - */ - -#ifdef __ASSEMBLY__ -#define _AC(X,Y) X -#define _AT(T,X) X -#else -#define __AC(X,Y) (X##Y) -#define _AC(X,Y) __AC(X,Y) -#define _AT(T,X) ((T)(X)) -#endif - -#define _BITUL(x) (_AC(1,UL) << (x)) -#define _BITULL(x) (_AC(1,ULL) << (x)) - -#endif /* !(_LINUX_CONST_H) */ diff --git a/lib/linux/pci_regs.h b/lib/linux/pci_regs.h deleted file mode 100644 index 7c566d03..00000000 --- a/lib/linux/pci_regs.h +++ /dev/null @@ -1,949 +0,0 @@ -/* - * pci_regs.h - * - * PCI standard defines - * Copyright 1994, Drew Eckhardt - * Copyright 1997--1999 Martin Mares - * - * For more information, please consult the following manuals (look at - * http://www.pcisig.com/ for how to get them): - * - * PCI BIOS Specification - * PCI Local Bus Specification - * PCI to PCI Bridge Specification - * PCI System Design Guide - * - * For HyperTransport information, please consult the following manuals - * from http://www.hypertransport.org - * - * The HyperTransport I/O Link Specification - */ - -#ifndef LINUX_PCI_REGS_H -#define LINUX_PCI_REGS_H - -/* - * Under PCI, each device has 256 bytes of configuration address space, - * of which the first 64 bytes are standardized as follows: - */ -#define PCI_STD_HEADER_SIZEOF 64 -#define PCI_VENDOR_ID 0x00 /* 16 bits */ -#define PCI_DEVICE_ID 0x02 /* 16 bits */ -#define PCI_COMMAND 0x04 /* 16 bits */ -#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ -#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ -#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ -#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ -#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ -#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ -#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ -#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ -#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ -#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ -#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ - -#define PCI_STATUS 0x06 /* 16 bits */ -#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */ -#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ -#define PCI_STATUS_66MHZ 0x20 /* Support 66 MHz PCI 2.1 bus */ -#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ -#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ -#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ -#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ -#define PCI_STATUS_DEVSEL_FAST 0x000 -#define PCI_STATUS_DEVSEL_MEDIUM 0x200 -#define PCI_STATUS_DEVSEL_SLOW 0x400 -#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ -#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ -#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ -#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ -#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ - -#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ -#define PCI_REVISION_ID 0x08 /* Revision ID */ -#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ -#define PCI_CLASS_DEVICE 0x0a /* Device class */ - -#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ -#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ -#define PCI_HEADER_TYPE 0x0e /* 8 bits */ -#define PCI_HEADER_TYPE_NORMAL 0 -#define PCI_HEADER_TYPE_BRIDGE 1 -#define PCI_HEADER_TYPE_CARDBUS 2 - -#define PCI_BIST 0x0f /* 8 bits */ -#define PCI_BIST_CODE_MASK 0x0f /* Return result */ -#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ -#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ - -/* - * Base addresses specify locations in memory or I/O space. - * Decoded size can be determined by writing a value of - * 0xffffffff to the register, and reading it back. Only - * 1 bits are decoded. - */ -#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ -#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */ -#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */ -#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ -#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ -#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ -#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ -#define PCI_BASE_ADDRESS_SPACE_IO 0x01 -#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 -#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 -#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ -#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ -#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ -#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ -#define PCI_BASE_ADDRESS_MEM_MASK (~0x0f) -#define PCI_BASE_ADDRESS_IO_MASK (~0x03) -/* bit 1 is reserved if address_space = 1 */ - -/* Header type 0 (normal devices) */ -#define PCI_CARDBUS_CIS 0x28 -#define PCI_SUBSYSTEM_VENDOR_ID 0x2c -#define PCI_SUBSYSTEM_ID 0x2e -#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ -#define PCI_ROM_ADDRESS_ENABLE 0x01 -#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) - -#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ - -/* 0x35-0x3b are reserved */ -#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ -#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ -#define PCI_MIN_GNT 0x3e /* 8 bits */ -#define PCI_MAX_LAT 0x3f /* 8 bits */ - -/* Header type 1 (PCI-to-PCI bridges) */ -#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ -#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ -#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ -#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ -#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ -#define PCI_IO_LIMIT 0x1d -#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ -#define PCI_IO_RANGE_TYPE_16 0x00 -#define PCI_IO_RANGE_TYPE_32 0x01 -#define PCI_IO_RANGE_MASK (~0x0fUL) /* Standard 4K I/O windows */ -#define PCI_IO_1K_RANGE_MASK (~0x03UL) /* Intel 1K I/O windows */ -#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ -#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ -#define PCI_MEMORY_LIMIT 0x22 -#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL -#define PCI_MEMORY_RANGE_MASK (~0x0fUL) -#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ -#define PCI_PREF_MEMORY_LIMIT 0x26 -#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL -#define PCI_PREF_RANGE_TYPE_32 0x00 -#define PCI_PREF_RANGE_TYPE_64 0x01 -#define PCI_PREF_RANGE_MASK (~0x0fUL) -#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ -#define PCI_PREF_LIMIT_UPPER32 0x2c -#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ -#define PCI_IO_LIMIT_UPPER16 0x32 -/* 0x34 same as for htype 0 */ -/* 0x35-0x3b is reserved */ -#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ -/* 0x3c-0x3d are same as for htype 0 */ -#define PCI_BRIDGE_CONTROL 0x3e -#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ -#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ -#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */ -#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ -#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ -#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ -#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ - -/* Header type 2 (CardBus bridges) */ -#define PCI_CB_CAPABILITY_LIST 0x14 -/* 0x15 reserved */ -#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */ -#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */ -#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */ -#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */ -#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */ -#define PCI_CB_MEMORY_BASE_0 0x1c -#define PCI_CB_MEMORY_LIMIT_0 0x20 -#define PCI_CB_MEMORY_BASE_1 0x24 -#define PCI_CB_MEMORY_LIMIT_1 0x28 -#define PCI_CB_IO_BASE_0 0x2c -#define PCI_CB_IO_BASE_0_HI 0x2e -#define PCI_CB_IO_LIMIT_0 0x30 -#define PCI_CB_IO_LIMIT_0_HI 0x32 -#define PCI_CB_IO_BASE_1 0x34 -#define PCI_CB_IO_BASE_1_HI 0x36 -#define PCI_CB_IO_LIMIT_1 0x38 -#define PCI_CB_IO_LIMIT_1_HI 0x3a -#define PCI_CB_IO_RANGE_MASK (~0x03UL) -/* 0x3c-0x3d are same as for htype 0 */ -#define PCI_CB_BRIDGE_CONTROL 0x3e -#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */ -#define PCI_CB_BRIDGE_CTL_SERR 0x02 -#define PCI_CB_BRIDGE_CTL_ISA 0x04 -#define PCI_CB_BRIDGE_CTL_VGA 0x08 -#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20 -#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */ -#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */ -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */ -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200 -#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400 -#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40 -#define PCI_CB_SUBSYSTEM_ID 0x42 -#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */ -/* 0x48-0x7f reserved */ - -/* Capability lists */ - -#define PCI_CAP_LIST_ID 0 /* Capability ID */ -#define PCI_CAP_ID_PM 0x01 /* Power Management */ -#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ -#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ -#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ -#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ -#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ -#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ -#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ -#define PCI_CAP_ID_VNDR 0x09 /* Vendor-Specific */ -#define PCI_CAP_ID_DBG 0x0A /* Debug port */ -#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ -#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ -#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ -#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ -#define PCI_CAP_ID_SECDEV 0x0F /* Secure Device */ -#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ -#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ -#define PCI_CAP_ID_SATA 0x12 /* SATA Data/Index Conf. */ -#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ -#define PCI_CAP_ID_EA 0x14 /* PCI Enhanced Allocation */ -#define PCI_CAP_ID_MAX PCI_CAP_ID_EA -#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ -#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ -#define PCI_CAP_SIZEOF 4 - -/* Power Management Registers */ - -#define PCI_PM_PMC 2 /* PM Capabilities Register */ -#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */ -#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ -#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ -#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ -#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support mask */ -#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */ -#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */ -#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */ -#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ -#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ -#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ -#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ -#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ -#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ -#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */ -#define PCI_PM_CTRL 4 /* PM control and status register */ -#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ -#define PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */ -#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ -#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ -#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ -#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ -#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */ -#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */ -#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */ -#define PCI_PM_DATA_REGISTER 7 /* (??) */ -#define PCI_PM_SIZEOF 8 - -/* AGP registers */ - -#define PCI_AGP_VERSION 2 /* BCD version number */ -#define PCI_AGP_RFU 3 /* Rest of capability flags */ -#define PCI_AGP_STATUS 4 /* Status register */ -#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ -#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ -#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ -#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ -#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ -#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ -#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ -#define PCI_AGP_COMMAND 8 /* Control register */ -#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ -#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ -#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ -#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ -#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ -#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ -#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ -#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ -#define PCI_AGP_SIZEOF 12 - -/* Vital Product Data */ - -#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */ -#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */ -#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */ -#define PCI_VPD_DATA 4 /* 32-bits of data returned here */ -#define PCI_CAP_VPD_SIZEOF 8 - -/* Slot Identification */ - -#define PCI_SID_ESR 2 /* Expansion Slot Register */ -#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ -#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ -#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ - -/* Message Signalled Interrupts registers */ - -#define PCI_MSI_FLAGS 2 /* Message Control */ -#define PCI_MSI_FLAGS_ENABLE 0x0001 /* MSI feature enabled */ -#define PCI_MSI_FLAGS_QMASK 0x000e /* Maximum queue size available */ -#define PCI_MSI_FLAGS_QSIZE 0x0070 /* Message queue size configured */ -#define PCI_MSI_FLAGS_64BIT 0x0080 /* 64-bit addresses allowed */ -#define PCI_MSI_FLAGS_MASKBIT 0x0100 /* Per-vector masking capable */ -#define PCI_MSI_RFU 3 /* Rest of capability flags */ -#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ -#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ -#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ -#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */ -#define PCI_MSI_PENDING_32 16 /* Pending intrs for 32-bit devices */ -#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ -#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */ -#define PCI_MSI_PENDING_64 20 /* Pending intrs for 64-bit devices */ - -/* MSI-X registers */ -#define PCI_MSIX_FLAGS 2 /* Message Control */ -#define PCI_MSIX_FLAGS_QSIZE 0x07FF /* Table size */ -#define PCI_MSIX_FLAGS_MASKALL 0x4000 /* Mask all vectors for this function */ -#define PCI_MSIX_FLAGS_ENABLE 0x8000 /* MSI-X enable */ -#define PCI_MSIX_TABLE 4 /* Table offset */ -#define PCI_MSIX_TABLE_BIR 0x00000007 /* BAR index */ -#define PCI_MSIX_TABLE_OFFSET 0xfffffff8 /* Offset into specified BAR */ -#define PCI_MSIX_PBA 8 /* Pending Bit Array offset */ -#define PCI_MSIX_PBA_BIR 0x00000007 /* BAR index */ -#define PCI_MSIX_PBA_OFFSET 0xfffffff8 /* Offset into specified BAR */ -#define PCI_MSIX_FLAGS_BIRMASK PCI_MSIX_PBA_BIR /* deprecated */ -#define PCI_CAP_MSIX_SIZEOF 12 /* size of MSIX registers */ - -/* MSI-X Table entry format */ -#define PCI_MSIX_ENTRY_SIZE 16 -#define PCI_MSIX_ENTRY_LOWER_ADDR 0 -#define PCI_MSIX_ENTRY_UPPER_ADDR 4 -#define PCI_MSIX_ENTRY_DATA 8 -#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 -#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 - -/* CompactPCI Hotswap Register */ - -#define PCI_CHSWP_CSR 2 /* Control and Status Register */ -#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */ -#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */ -#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */ -#define PCI_CHSWP_LOO 0x08 /* LED On / Off */ -#define PCI_CHSWP_PI 0x30 /* Programming Interface */ -#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */ -#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */ - -/* PCI Advanced Feature registers */ - -#define PCI_AF_LENGTH 2 -#define PCI_AF_CAP 3 -#define PCI_AF_CAP_TP 0x01 -#define PCI_AF_CAP_FLR 0x02 -#define PCI_AF_CTRL 4 -#define PCI_AF_CTRL_FLR 0x01 -#define PCI_AF_STATUS 5 -#define PCI_AF_STATUS_TP 0x01 -#define PCI_CAP_AF_SIZEOF 6 /* size of AF registers */ - -/* PCI Enhanced Allocation registers */ - -#define PCI_EA_NUM_ENT 2 /* Number of Capability Entries */ -#define PCI_EA_NUM_ENT_MASK 0x3f /* Num Entries Mask */ -#define PCI_EA_FIRST_ENT 4 /* First EA Entry in List */ -#define PCI_EA_FIRST_ENT_BRIDGE 8 /* First EA Entry for Bridges */ -#define PCI_EA_ES 0x00000007 /* Entry Size */ -#define PCI_EA_BEI 0x000000f0 /* BAR Equivalent Indicator */ -/* 0-5 map to BARs 0-5 respectively */ -#define PCI_EA_BEI_BAR0 0 -#define PCI_EA_BEI_BAR5 5 -#define PCI_EA_BEI_BRIDGE 6 /* Resource behind bridge */ -#define PCI_EA_BEI_ENI 7 /* Equivalent Not Indicated */ -#define PCI_EA_BEI_ROM 8 /* Expansion ROM */ -/* 9-14 map to VF BARs 0-5 respectively */ -#define PCI_EA_BEI_VF_BAR0 9 -#define PCI_EA_BEI_VF_BAR5 14 -#define PCI_EA_BEI_RESERVED 15 /* Reserved - Treat like ENI */ -#define PCI_EA_PP 0x0000ff00 /* Primary Properties */ -#define PCI_EA_SP 0x00ff0000 /* Secondary Properties */ -#define PCI_EA_P_MEM 0x00 /* Non-Prefetch Memory */ -#define PCI_EA_P_MEM_PREFETCH 0x01 /* Prefetchable Memory */ -#define PCI_EA_P_IO 0x02 /* I/O Space */ -#define PCI_EA_P_VF_MEM_PREFETCH 0x03 /* VF Prefetchable Memory */ -#define PCI_EA_P_VF_MEM 0x04 /* VF Non-Prefetch Memory */ -#define PCI_EA_P_BRIDGE_MEM 0x05 /* Bridge Non-Prefetch Memory */ -#define PCI_EA_P_BRIDGE_MEM_PREFETCH 0x06 /* Bridge Prefetchable Memory */ -#define PCI_EA_P_BRIDGE_IO 0x07 /* Bridge I/O Space */ -/* 0x08-0xfc reserved */ -#define PCI_EA_P_MEM_RESERVED 0xfd /* Reserved Memory */ -#define PCI_EA_P_IO_RESERVED 0xfe /* Reserved I/O Space */ -#define PCI_EA_P_UNAVAILABLE 0xff /* Entry Unavailable */ -#define PCI_EA_WRITABLE 0x40000000 /* Writable: 1 = RW, 0 = HwInit */ -#define PCI_EA_ENABLE 0x80000000 /* Enable for this entry */ -#define PCI_EA_BASE 4 /* Base Address Offset */ -#define PCI_EA_MAX_OFFSET 8 /* MaxOffset (resource length) */ -/* bit 0 is reserved */ -#define PCI_EA_IS_64 0x00000002 /* 64-bit field flag */ -#define PCI_EA_FIELD_MASK 0xfffffffc /* For Base & Max Offset */ - -/* PCI-X registers (Type 0 (non-bridge) devices) */ - -#define PCI_X_CMD 2 /* Modes & Features */ -#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ -#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ -#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ -#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ -#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ -#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ -#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ - /* Max # of outstanding split transactions */ -#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */ -#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */ -#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */ -#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */ -#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */ -#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */ -#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */ -#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */ -#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ -#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */ -#define PCI_X_STATUS 4 /* PCI-X capabilities */ -#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */ -#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */ -#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */ -#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */ -#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */ -#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */ -#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */ -#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count */ -#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */ -#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */ -#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */ -#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ -#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ -#define PCI_X_ECC_CSR 8 /* ECC control and status */ -#define PCI_CAP_PCIX_SIZEOF_V0 8 /* size of registers for Version 0 */ -#define PCI_CAP_PCIX_SIZEOF_V1 24 /* size for Version 1 */ -#define PCI_CAP_PCIX_SIZEOF_V2 PCI_CAP_PCIX_SIZEOF_V1 /* Same for v2 */ - -/* PCI-X registers (Type 1 (bridge) devices) */ - -#define PCI_X_BRIDGE_SSTATUS 2 /* Secondary Status */ -#define PCI_X_SSTATUS_64BIT 0x0001 /* Secondary AD interface is 64 bits */ -#define PCI_X_SSTATUS_133MHZ 0x0002 /* 133 MHz capable */ -#define PCI_X_SSTATUS_FREQ 0x03c0 /* Secondary Bus Mode and Frequency */ -#define PCI_X_SSTATUS_VERS 0x3000 /* PCI-X Capability Version */ -#define PCI_X_SSTATUS_V1 0x1000 /* Mode 2, not Mode 1 */ -#define PCI_X_SSTATUS_V2 0x2000 /* Mode 1 or Modes 1 and 2 */ -#define PCI_X_SSTATUS_266MHZ 0x4000 /* 266 MHz capable */ -#define PCI_X_SSTATUS_533MHZ 0x8000 /* 533 MHz capable */ -#define PCI_X_BRIDGE_STATUS 4 /* Bridge Status */ - -/* PCI Bridge Subsystem ID registers */ - -#define PCI_SSVID_VENDOR_ID 4 /* PCI Bridge subsystem vendor ID */ -#define PCI_SSVID_DEVICE_ID 6 /* PCI Bridge subsystem device ID */ - -/* PCI Express capability registers */ - -#define PCI_EXP_FLAGS 2 /* Capabilities register */ -#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ -#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ -#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ -#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ -#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ -#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ -#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ -#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCIe to PCI/PCI-X Bridge */ -#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIe Bridge */ -#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ -#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ -#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ -#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ -#define PCI_EXP_DEVCAP 4 /* Device capabilities */ -#define PCI_EXP_DEVCAP_PAYLOAD 0x00000007 /* Max_Payload_Size */ -#define PCI_EXP_DEVCAP_PHANTOM 0x00000018 /* Phantom functions */ -#define PCI_EXP_DEVCAP_EXT_TAG 0x00000020 /* Extended tags */ -#define PCI_EXP_DEVCAP_L0S 0x000001c0 /* L0s Acceptable Latency */ -#define PCI_EXP_DEVCAP_L1 0x00000e00 /* L1 Acceptable Latency */ -#define PCI_EXP_DEVCAP_ATN_BUT 0x00001000 /* Attention Button Present */ -#define PCI_EXP_DEVCAP_ATN_IND 0x00002000 /* Attention Indicator Present */ -#define PCI_EXP_DEVCAP_PWR_IND 0x00004000 /* Power Indicator Present */ -#define PCI_EXP_DEVCAP_RBER 0x00008000 /* Role-Based Error Reporting */ -#define PCI_EXP_DEVCAP_PWR_VAL 0x03fc0000 /* Slot Power Limit Value */ -#define PCI_EXP_DEVCAP_PWR_SCL 0x0c000000 /* Slot Power Limit Scale */ -#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ -#define PCI_EXP_DEVCTL 8 /* Device Control */ -#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ -#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ -#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ -#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ -#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */ -#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ -#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ -#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ -#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ -#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ -#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ -#define PCI_EXP_DEVCTL_READRQ_128B 0x0000 /* 128 Bytes */ -#define PCI_EXP_DEVCTL_READRQ_256B 0x1000 /* 256 Bytes */ -#define PCI_EXP_DEVCTL_READRQ_512B 0x2000 /* 512 Bytes */ -#define PCI_EXP_DEVCTL_READRQ_1024B 0x3000 /* 1024 Bytes */ -#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ -#define PCI_EXP_DEVSTA 10 /* Device Status */ -#define PCI_EXP_DEVSTA_CED 0x0001 /* Correctable Error Detected */ -#define PCI_EXP_DEVSTA_NFED 0x0002 /* Non-Fatal Error Detected */ -#define PCI_EXP_DEVSTA_FED 0x0004 /* Fatal Error Detected */ -#define PCI_EXP_DEVSTA_URD 0x0008 /* Unsupported Request Detected */ -#define PCI_EXP_DEVSTA_AUXPD 0x0010 /* AUX Power Detected */ -#define PCI_EXP_DEVSTA_TRPND 0x0020 /* Transactions Pending */ -#define PCI_EXP_LNKCAP 12 /* Link Capabilities */ -#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */ -#define PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */ -#define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */ -#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */ -#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */ -#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */ -#define PCI_EXP_LNKCAP_L1EL 0x00038000 /* L1 Exit Latency */ -#define PCI_EXP_LNKCAP_CLKPM 0x00040000 /* Clock Power Management */ -#define PCI_EXP_LNKCAP_SDERC 0x00080000 /* Surprise Down Error Reporting Capable */ -#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link Active Reporting Capable */ -#define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notification Capability */ -#define PCI_EXP_LNKCAP_PN 0xff000000 /* Port Number */ -#define PCI_EXP_LNKCTL 16 /* Link Control */ -#define PCI_EXP_LNKCTL_ASPMC 0x0003 /* ASPM Control */ -#define PCI_EXP_LNKCTL_ASPM_L0S 0x0001 /* L0s Enable */ -#define PCI_EXP_LNKCTL_ASPM_L1 0x0002 /* L1 Enable */ -#define PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */ -#define PCI_EXP_LNKCTL_LD 0x0010 /* Link Disable */ -#define PCI_EXP_LNKCTL_RL 0x0020 /* Retrain Link */ -#define PCI_EXP_LNKCTL_CCC 0x0040 /* Common Clock Configuration */ -#define PCI_EXP_LNKCTL_ES 0x0080 /* Extended Synch */ -#define PCI_EXP_LNKCTL_CLKREQ_EN 0x0100 /* Enable clkreq */ -#define PCI_EXP_LNKCTL_HAWD 0x0200 /* Hardware Autonomous Width Disable */ -#define PCI_EXP_LNKCTL_LBMIE 0x0400 /* Link Bandwidth Management Interrupt Enable */ -#define PCI_EXP_LNKCTL_LABIE 0x0800 /* Link Autonomous Bandwidth Interrupt Enable */ -#define PCI_EXP_LNKSTA 18 /* Link Status */ -#define PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */ -#define PCI_EXP_LNKSTA_CLS_2_5GB 0x0001 /* Current Link Speed 2.5GT/s */ -#define PCI_EXP_LNKSTA_CLS_5_0GB 0x0002 /* Current Link Speed 5.0GT/s */ -#define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003 /* Current Link Speed 8.0GT/s */ -#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Negotiated Link Width */ -#define PCI_EXP_LNKSTA_NLW_X1 0x0010 /* Current Link Width x1 */ -#define PCI_EXP_LNKSTA_NLW_X2 0x0020 /* Current Link Width x2 */ -#define PCI_EXP_LNKSTA_NLW_X4 0x0040 /* Current Link Width x4 */ -#define PCI_EXP_LNKSTA_NLW_X8 0x0080 /* Current Link Width x8 */ -#define PCI_EXP_LNKSTA_NLW_SHIFT 4 /* start of NLW mask in link status */ -#define PCI_EXP_LNKSTA_LT 0x0800 /* Link Training */ -#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ -#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ -#define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */ -#define PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */ -#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V1 20 /* v1 endpoints end here */ -#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ -#define PCI_EXP_SLTCAP_ABP 0x00000001 /* Attention Button Present */ -#define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Present */ -#define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */ -#define PCI_EXP_SLTCAP_AIP 0x00000008 /* Attention Indicator Present */ -#define PCI_EXP_SLTCAP_PIP 0x00000010 /* Power Indicator Present */ -#define PCI_EXP_SLTCAP_HPS 0x00000020 /* Hot-Plug Surprise */ -#define PCI_EXP_SLTCAP_HPC 0x00000040 /* Hot-Plug Capable */ -#define PCI_EXP_SLTCAP_SPLV 0x00007f80 /* Slot Power Limit Value */ -#define PCI_EXP_SLTCAP_SPLS 0x00018000 /* Slot Power Limit Scale */ -#define PCI_EXP_SLTCAP_EIP 0x00020000 /* Electromechanical Interlock Present */ -#define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Support */ -#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ -#define PCI_EXP_SLTCTL 24 /* Slot Control */ -#define PCI_EXP_SLTCTL_ABPE 0x0001 /* Attention Button Pressed Enable */ -#define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enable */ -#define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable */ -#define PCI_EXP_SLTCTL_PDCE 0x0008 /* Presence Detect Changed Enable */ -#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrupt Enable */ -#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */ -#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Control */ -#define PCI_EXP_SLTCTL_ATTN_IND_ON 0x0040 /* Attention Indicator on */ -#define PCI_EXP_SLTCTL_ATTN_IND_BLINK 0x0080 /* Attention Indicator blinking */ -#define PCI_EXP_SLTCTL_ATTN_IND_OFF 0x00c0 /* Attention Indicator off */ -#define PCI_EXP_SLTCTL_PIC 0x0300 /* Power Indicator Control */ -#define PCI_EXP_SLTCTL_PWR_IND_ON 0x0100 /* Power Indicator on */ -#define PCI_EXP_SLTCTL_PWR_IND_BLINK 0x0200 /* Power Indicator blinking */ -#define PCI_EXP_SLTCTL_PWR_IND_OFF 0x0300 /* Power Indicator off */ -#define PCI_EXP_SLTCTL_PCC 0x0400 /* Power Controller Control */ -#define PCI_EXP_SLTCTL_PWR_ON 0x0000 /* Power On */ -#define PCI_EXP_SLTCTL_PWR_OFF 0x0400 /* Power Off */ -#define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock Control */ -#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed Enable */ -#define PCI_EXP_SLTSTA 26 /* Slot Status */ -#define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */ -#define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */ -#define PCI_EXP_SLTSTA_MRLSC 0x0004 /* MRL Sensor Changed */ -#define PCI_EXP_SLTSTA_PDC 0x0008 /* Presence Detect Changed */ -#define PCI_EXP_SLTSTA_CC 0x0010 /* Command Completed */ -#define PCI_EXP_SLTSTA_MRLSS 0x0020 /* MRL Sensor State */ -#define PCI_EXP_SLTSTA_PDS 0x0040 /* Presence Detect State */ -#define PCI_EXP_SLTSTA_EIS 0x0080 /* Electromechanical Interlock Status */ -#define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Changed */ -#define PCI_EXP_RTCTL 28 /* Root Control */ -#define PCI_EXP_RTCTL_SECEE 0x0001 /* System Error on Correctable Error */ -#define PCI_EXP_RTCTL_SENFEE 0x0002 /* System Error on Non-Fatal Error */ -#define PCI_EXP_RTCTL_SEFEE 0x0004 /* System Error on Fatal Error */ -#define PCI_EXP_RTCTL_PMEIE 0x0008 /* PME Interrupt Enable */ -#define PCI_EXP_RTCTL_CRSSVE 0x0010 /* CRS Software Visibility Enable */ -#define PCI_EXP_RTCAP 30 /* Root Capabilities */ -#define PCI_EXP_RTCAP_CRSVIS 0x0001 /* CRS Software Visibility capability */ -#define PCI_EXP_RTSTA 32 /* Root Status */ -#define PCI_EXP_RTSTA_PME 0x00010000 /* PME status */ -#define PCI_EXP_RTSTA_PENDING 0x00020000 /* PME pending */ -/* - * The Device Capabilities 2, Device Status 2, Device Control 2, - * Link Capabilities 2, Link Status 2, Link Control 2, - * Slot Capabilities 2, Slot Status 2, and Slot Control 2 registers - * are only present on devices with PCIe Capability version 2. - * Use pcie_capability_read_word() and similar interfaces to use them - * safely. - */ -#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ -#define PCI_EXP_DEVCAP2_ARI 0x00000020 /* Alternative Routing-ID */ -#define PCI_EXP_DEVCAP2_LTR 0x00000800 /* Latency tolerance reporting */ -#define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000 /* OBFF support mechanism */ -#define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */ -#define PCI_EXP_DEVCAP2_OBFF_WAKE 0x00080000 /* Re-use WAKE# for OBFF */ -#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ -#define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f /* Completion Timeout Value */ -#define PCI_EXP_DEVCTL2_ARI 0x0020 /* Alternative Routing-ID */ -#define PCI_EXP_DEVCTL2_IDO_REQ_EN 0x0100 /* Allow IDO for requests */ -#define PCI_EXP_DEVCTL2_IDO_CMP_EN 0x0200 /* Allow IDO for completions */ -#define PCI_EXP_DEVCTL2_LTR_EN 0x0400 /* Enable LTR mechanism */ -#define PCI_EXP_DEVCTL2_OBFF_MSGA_EN 0x2000 /* Enable OBFF Message type A */ -#define PCI_EXP_DEVCTL2_OBFF_MSGB_EN 0x4000 /* Enable OBFF Message type B */ -#define PCI_EXP_DEVCTL2_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */ -#define PCI_EXP_DEVSTA2 42 /* Device Status 2 */ -#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 44 /* v2 endpoints end here */ -#define PCI_EXP_LNKCAP2 44 /* Link Capabilities 2 */ -#define PCI_EXP_LNKCAP2_SLS_2_5GB 0x00000002 /* Supported Speed 2.5GT/s */ -#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x00000004 /* Supported Speed 5.0GT/s */ -#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008 /* Supported Speed 8.0GT/s */ -#define PCI_EXP_LNKCAP2_CROSSLINK 0x00000100 /* Crosslink supported */ -#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ -#define PCI_EXP_LNKSTA2 50 /* Link Status 2 */ -#define PCI_EXP_SLTCAP2 52 /* Slot Capabilities 2 */ -#define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ -#define PCI_EXP_SLTSTA2 58 /* Slot Status 2 */ - -/* Extended Capabilities (PCI-X 2.0 and Express) */ -#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff) -#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf) -#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc) - -#define PCI_EXT_CAP_ID_ERR 0x01 /* Advanced Error Reporting */ -#define PCI_EXT_CAP_ID_VC 0x02 /* Virtual Channel Capability */ -#define PCI_EXT_CAP_ID_DSN 0x03 /* Device Serial Number */ -#define PCI_EXT_CAP_ID_PWR 0x04 /* Power Budgeting */ -#define PCI_EXT_CAP_ID_RCLD 0x05 /* Root Complex Link Declaration */ -#define PCI_EXT_CAP_ID_RCILC 0x06 /* Root Complex Internal Link Control */ -#define PCI_EXT_CAP_ID_RCEC 0x07 /* Root Complex Event Collector */ -#define PCI_EXT_CAP_ID_MFVC 0x08 /* Multi-Function VC Capability */ -#define PCI_EXT_CAP_ID_VC9 0x09 /* same as _VC */ -#define PCI_EXT_CAP_ID_RCRB 0x0A /* Root Complex RB? */ -#define PCI_EXT_CAP_ID_VNDR 0x0B /* Vendor-Specific */ -#define PCI_EXT_CAP_ID_CAC 0x0C /* Config Access - obsolete */ -#define PCI_EXT_CAP_ID_ACS 0x0D /* Access Control Services */ -#define PCI_EXT_CAP_ID_ARI 0x0E /* Alternate Routing ID */ -#define PCI_EXT_CAP_ID_ATS 0x0F /* Address Translation Services */ -#define PCI_EXT_CAP_ID_SRIOV 0x10 /* Single Root I/O Virtualization */ -#define PCI_EXT_CAP_ID_MRIOV 0x11 /* Multi Root I/O Virtualization */ -#define PCI_EXT_CAP_ID_MCAST 0x12 /* Multicast */ -#define PCI_EXT_CAP_ID_PRI 0x13 /* Page Request Interface */ -#define PCI_EXT_CAP_ID_AMD_XXX 0x14 /* Reserved for AMD */ -#define PCI_EXT_CAP_ID_REBAR 0x15 /* Resizable BAR */ -#define PCI_EXT_CAP_ID_DPA 0x16 /* Dynamic Power Allocation */ -#define PCI_EXT_CAP_ID_TPH 0x17 /* TPH Requester */ -#define PCI_EXT_CAP_ID_LTR 0x18 /* Latency Tolerance Reporting */ -#define PCI_EXT_CAP_ID_SECPCI 0x19 /* Secondary PCIe Capability */ -#define PCI_EXT_CAP_ID_PMUX 0x1A /* Protocol Multiplexing */ -#define PCI_EXT_CAP_ID_PASID 0x1B /* Process Address Space ID */ -#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PASID - -#define PCI_EXT_CAP_DSN_SIZEOF 12 -#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40 - -/* Advanced Error Reporting */ -#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ -#define PCI_ERR_UNC_UND 0x00000001 /* Undefined */ -#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */ -#define PCI_ERR_UNC_SURPDN 0x00000020 /* Surprise Down */ -#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */ -#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */ -#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */ -#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */ -#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */ -#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */ -#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */ -#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */ -#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */ -#define PCI_ERR_UNC_ACSV 0x00200000 /* ACS Violation */ -#define PCI_ERR_UNC_INTN 0x00400000 /* internal error */ -#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC blocked TLP */ -#define PCI_ERR_UNC_ATOMEG 0x01000000 /* Atomic egress blocked */ -#define PCI_ERR_UNC_TLPPRE 0x02000000 /* TLP prefix blocked */ -#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */ - /* Same bits as above */ -#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */ - /* Same bits as above */ -#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */ -#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */ -#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */ -#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */ -#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */ -#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */ -#define PCI_ERR_COR_ADV_NFAT 0x00002000 /* Advisory Non-Fatal */ -#define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected Internal */ -#define PCI_ERR_COR_LOG_OVER 0x00008000 /* Header Log Overflow */ -#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ - /* Same bits as above */ -#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */ -#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */ -#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */ -#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */ -#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */ -#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */ -#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */ -#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */ -/* Correctable Err Reporting Enable */ -#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 -/* Non-fatal Err Reporting Enable */ -#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 -/* Fatal Err Reporting Enable */ -#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 -#define PCI_ERR_ROOT_STATUS 48 -#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */ -/* Multi ERR_COR Received */ -#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 -/* ERR_FATAL/NONFATAL Received */ -#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 -/* Multi ERR_FATAL/NONFATAL Received */ -#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008 -#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */ -#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ -#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ -#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */ - -/* Virtual Channel */ -#define PCI_VC_PORT_CAP1 4 -#define PCI_VC_CAP1_EVCC 0x00000007 /* extended VC count */ -#define PCI_VC_CAP1_LPEVCC 0x00000070 /* low prio extended VC count */ -#define PCI_VC_CAP1_ARB_SIZE 0x00000c00 -#define PCI_VC_PORT_CAP2 8 -#define PCI_VC_CAP2_32_PHASE 0x00000002 -#define PCI_VC_CAP2_64_PHASE 0x00000004 -#define PCI_VC_CAP2_128_PHASE 0x00000008 -#define PCI_VC_CAP2_ARB_OFF 0xff000000 -#define PCI_VC_PORT_CTRL 12 -#define PCI_VC_PORT_CTRL_LOAD_TABLE 0x00000001 -#define PCI_VC_PORT_STATUS 14 -#define PCI_VC_PORT_STATUS_TABLE 0x00000001 -#define PCI_VC_RES_CAP 16 -#define PCI_VC_RES_CAP_32_PHASE 0x00000002 -#define PCI_VC_RES_CAP_64_PHASE 0x00000004 -#define PCI_VC_RES_CAP_128_PHASE 0x00000008 -#define PCI_VC_RES_CAP_128_PHASE_TB 0x00000010 -#define PCI_VC_RES_CAP_256_PHASE 0x00000020 -#define PCI_VC_RES_CAP_ARB_OFF 0xff000000 -#define PCI_VC_RES_CTRL 20 -#define PCI_VC_RES_CTRL_LOAD_TABLE 0x00010000 -#define PCI_VC_RES_CTRL_ARB_SELECT 0x000e0000 -#define PCI_VC_RES_CTRL_ID 0x07000000 -#define PCI_VC_RES_CTRL_ENABLE 0x80000000 -#define PCI_VC_RES_STATUS 26 -#define PCI_VC_RES_STATUS_TABLE 0x00000001 -#define PCI_VC_RES_STATUS_NEGO 0x00000002 -#define PCI_CAP_VC_BASE_SIZEOF 0x10 -#define PCI_CAP_VC_PER_VC_SIZEOF 0x0C - -/* Power Budgeting */ -#define PCI_PWR_DSR 4 /* Data Select Register */ -#define PCI_PWR_DATA 8 /* Data Register */ -#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */ -#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */ -#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */ -#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */ -#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */ -#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */ -#define PCI_PWR_CAP 12 /* Capability */ -#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ -#define PCI_EXT_CAP_PWR_SIZEOF 16 - -/* Vendor-Specific (VSEC, PCI_EXT_CAP_ID_VNDR) */ -#define PCI_VNDR_HEADER 4 /* Vendor-Specific Header */ -#define PCI_VNDR_HEADER_ID(x) ((x) & 0xffff) -#define PCI_VNDR_HEADER_REV(x) (((x) >> 16) & 0xf) -#define PCI_VNDR_HEADER_LEN(x) (((x) >> 20) & 0xfff) - -/* - * HyperTransport sub capability types - * - * Unfortunately there are both 3 bit and 5 bit capability types defined - * in the HT spec, catering for that is a little messy. You probably don't - * want to use these directly, just use pci_find_ht_capability() and it - * will do the right thing for you. - */ -#define HT_3BIT_CAP_MASK 0xE0 -#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */ -#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */ - -#define HT_5BIT_CAP_MASK 0xF8 -#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ -#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */ -#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */ -#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */ -#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */ -#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */ -#define HT_MSI_FLAGS 0x02 /* Offset to flags */ -#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */ -#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */ -#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */ -#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr bits */ -#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */ -#define HT_MSI_ADDR_HI 0x08 /* Offset to high addr bits */ -#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */ -#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */ -#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */ -#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 HyperTransport configuration */ -#define HT_CAPTYPE_PM 0xE0 /* HyperTransport power management configuration */ -#define HT_CAP_SIZEOF_LONG 28 /* slave & primary */ -#define HT_CAP_SIZEOF_SHORT 24 /* host & secondary */ - -/* Alternative Routing-ID Interpretation */ -#define PCI_ARI_CAP 0x04 /* ARI Capability Register */ -#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */ -#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */ -#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */ -#define PCI_ARI_CTRL 0x06 /* ARI Control Register */ -#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */ -#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */ -#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ -#define PCI_EXT_CAP_ARI_SIZEOF 8 - -/* Address Translation Service */ -#define PCI_ATS_CAP 0x04 /* ATS Capability Register */ -#define PCI_ATS_CAP_QDEP(x) ((x) & 0x1f) /* Invalidate Queue Depth */ -#define PCI_ATS_MAX_QDEP 32 /* Max Invalidate Queue Depth */ -#define PCI_ATS_CTRL 0x06 /* ATS Control Register */ -#define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */ -#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */ -#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */ -#define PCI_EXT_CAP_ATS_SIZEOF 8 - -/* Page Request Interface */ -#define PCI_PRI_CTRL 0x04 /* PRI control register */ -#define PCI_PRI_CTRL_ENABLE 0x01 /* Enable */ -#define PCI_PRI_CTRL_RESET 0x02 /* Reset */ -#define PCI_PRI_STATUS 0x06 /* PRI status register */ -#define PCI_PRI_STATUS_RF 0x001 /* Response Failure */ -#define PCI_PRI_STATUS_UPRGI 0x002 /* Unexpected PRG index */ -#define PCI_PRI_STATUS_STOPPED 0x100 /* PRI Stopped */ -#define PCI_PRI_MAX_REQ 0x08 /* PRI max reqs supported */ -#define PCI_PRI_ALLOC_REQ 0x0c /* PRI max reqs allowed */ -#define PCI_EXT_CAP_PRI_SIZEOF 16 - -/* Process Address Space ID */ -#define PCI_PASID_CAP 0x04 /* PASID feature register */ -#define PCI_PASID_CAP_EXEC 0x02 /* Exec permissions Supported */ -#define PCI_PASID_CAP_PRIV 0x04 /* Privilege Mode Supported */ -#define PCI_PASID_CTRL 0x06 /* PASID control register */ -#define PCI_PASID_CTRL_ENABLE 0x01 /* Enable bit */ -#define PCI_PASID_CTRL_EXEC 0x02 /* Exec permissions Enable */ -#define PCI_PASID_CTRL_PRIV 0x04 /* Privilege Mode Enable */ -#define PCI_EXT_CAP_PASID_SIZEOF 8 - -/* Single Root I/O Virtualization */ -#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ -#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ -#define PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */ -#define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */ -#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */ -#define PCI_SRIOV_CTRL_VFM 0x02 /* VF Migration Enable */ -#define PCI_SRIOV_CTRL_INTR 0x04 /* VF Migration Interrupt Enable */ -#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */ -#define PCI_SRIOV_CTRL_ARI 0x10 /* ARI Capable Hierarchy */ -#define PCI_SRIOV_STATUS 0x0a /* SR-IOV Status */ -#define PCI_SRIOV_STATUS_VFM 0x01 /* VF Migration Status */ -#define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */ -#define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */ -#define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */ -#define PCI_SRIOV_FUNC_LINK 0x12 /* Function Dependency Link */ -#define PCI_SRIOV_VF_OFFSET 0x14 /* First VF Offset */ -#define PCI_SRIOV_VF_STRIDE 0x16 /* Following VF Stride */ -#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID */ -#define PCI_SRIOV_SUP_PGSIZE 0x1c /* Supported Page Sizes */ -#define PCI_SRIOV_SYS_PGSIZE 0x20 /* System Page Size */ -#define PCI_SRIOV_BAR 0x24 /* VF BAR0 */ -#define PCI_SRIOV_NUM_BARS 6 /* Number of VF BARs */ -#define PCI_SRIOV_VFM 0x3c /* VF Migration State Array Offset*/ -#define PCI_SRIOV_VFM_BIR(x) ((x) & 7) /* State BIR */ -#define PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7) /* State Offset */ -#define PCI_SRIOV_VFM_UA 0x0 /* Inactive.Unavailable */ -#define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */ -#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ -#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ -#define PCI_EXT_CAP_SRIOV_SIZEOF 64 - -#define PCI_LTR_MAX_SNOOP_LAT 0x4 -#define PCI_LTR_MAX_NOSNOOP_LAT 0x6 -#define PCI_LTR_VALUE_MASK 0x000003ff -#define PCI_LTR_SCALE_MASK 0x00001c00 -#define PCI_LTR_SCALE_SHIFT 10 -#define PCI_EXT_CAP_LTR_SIZEOF 8 - -/* Access Control Service */ -#define PCI_ACS_CAP 0x04 /* ACS Capability Register */ -#define PCI_ACS_SV 0x01 /* Source Validation */ -#define PCI_ACS_TB 0x02 /* Translation Blocking */ -#define PCI_ACS_RR 0x04 /* P2P Request Redirect */ -#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */ -#define PCI_ACS_UF 0x10 /* Upstream Forwarding */ -#define PCI_ACS_EC 0x20 /* P2P Egress Control */ -#define PCI_ACS_DT 0x40 /* Direct Translated P2P */ -#define PCI_ACS_EGRESS_BITS 0x05 /* ACS Egress Control Vector Size */ -#define PCI_ACS_CTRL 0x06 /* ACS Control Register */ -#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */ - -#define PCI_VSEC_HDR 4 /* extended cap - vendor-specific */ -#define PCI_VSEC_HDR_LEN_SHIFT 20 /* shift for length field */ - -/* SATA capability */ -#define PCI_SATA_REGS 4 /* SATA REGs specifier */ -#define PCI_SATA_REGS_MASK 0xF /* location - BAR#/inline */ -#define PCI_SATA_REGS_INLINE 0xF /* REGS in config space */ -#define PCI_SATA_SIZEOF_SHORT 8 -#define PCI_SATA_SIZEOF_LONG 16 - -/* Resizable BARs */ -#define PCI_REBAR_CTRL 8 /* control register */ -#define PCI_REBAR_CTRL_NBAR_MASK (7 << 5) /* mask for # bars */ -#define PCI_REBAR_CTRL_NBAR_SHIFT 5 /* shift for # bars */ - -/* Dynamic Power Allocation */ -#define PCI_DPA_CAP 4 /* capability register */ -#define PCI_DPA_CAP_SUBSTATE_MASK 0x1F /* # substates - 1 */ -#define PCI_DPA_BASE_SIZEOF 16 /* size with 0 substates */ - -/* TPH Requester */ -#define PCI_TPH_CAP 4 /* capability register */ -#define PCI_TPH_CAP_LOC_MASK 0x600 /* location mask */ -#define PCI_TPH_LOC_NONE 0x000 /* no location */ -#define PCI_TPH_LOC_CAP 0x200 /* in capability */ -#define PCI_TPH_LOC_MSIX 0x400 /* in MSI-X */ -#define PCI_TPH_CAP_ST_MASK 0x07FF0000 /* st table mask */ -#define PCI_TPH_CAP_ST_SHIFT 16 /* st table shift */ -#define PCI_TPH_BASE_SIZEOF 12 /* size with no st table */ - -#endif /* LINUX_PCI_REGS_H */ diff --git a/lib/linux/psci.h b/lib/linux/psci.h deleted file mode 100644 index 3d7a0fc0..00000000 --- a/lib/linux/psci.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * ARM Power State and Coordination Interface (PSCI) header - * - * This header holds common PSCI defines and macros shared - * by: ARM kernel, ARM64 kernel, KVM ARM/ARM64 and user space. - * - * Copyright (C) 2014 Linaro Ltd. - * Author: Anup Patel - */ - -#ifndef _UAPI_LINUX_PSCI_H -#define _UAPI_LINUX_PSCI_H - -/* - * PSCI v0.1 interface - * - * The PSCI v0.1 function numbers are implementation defined. - * - * Only PSCI return values such as: SUCCESS, NOT_SUPPORTED, - * INVALID_PARAMS, and DENIED defined below are applicable - * to PSCI v0.1. - */ - -/* PSCI v0.2 interface */ -#define PSCI_0_2_FN_BASE 0x84000000 -#define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n)) -#define PSCI_0_2_64BIT 0x40000000 -#define PSCI_0_2_FN64_BASE \ - (PSCI_0_2_FN_BASE + PSCI_0_2_64BIT) -#define PSCI_0_2_FN64(n) (PSCI_0_2_FN64_BASE + (n)) - -#define PSCI_0_2_FN_PSCI_VERSION PSCI_0_2_FN(0) -#define PSCI_0_2_FN_CPU_SUSPEND PSCI_0_2_FN(1) -#define PSCI_0_2_FN_CPU_OFF PSCI_0_2_FN(2) -#define PSCI_0_2_FN_CPU_ON PSCI_0_2_FN(3) -#define PSCI_0_2_FN_AFFINITY_INFO PSCI_0_2_FN(4) -#define PSCI_0_2_FN_MIGRATE PSCI_0_2_FN(5) -#define PSCI_0_2_FN_MIGRATE_INFO_TYPE PSCI_0_2_FN(6) -#define PSCI_0_2_FN_MIGRATE_INFO_UP_CPU PSCI_0_2_FN(7) -#define PSCI_0_2_FN_SYSTEM_OFF PSCI_0_2_FN(8) -#define PSCI_0_2_FN_SYSTEM_RESET PSCI_0_2_FN(9) - -#define PSCI_0_2_FN64_CPU_SUSPEND PSCI_0_2_FN64(1) -#define PSCI_0_2_FN64_CPU_ON PSCI_0_2_FN64(3) -#define PSCI_0_2_FN64_AFFINITY_INFO PSCI_0_2_FN64(4) -#define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5) -#define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7) - -#define PSCI_1_0_FN_PSCI_FEATURES PSCI_0_2_FN(10) -#define PSCI_1_0_FN_SYSTEM_SUSPEND PSCI_0_2_FN(14) - -#define PSCI_1_0_FN64_SYSTEM_SUSPEND PSCI_0_2_FN64(14) - -/* PSCI v0.2 power state encoding for CPU_SUSPEND function */ -#define PSCI_0_2_POWER_STATE_ID_MASK 0xffff -#define PSCI_0_2_POWER_STATE_ID_SHIFT 0 -#define PSCI_0_2_POWER_STATE_TYPE_SHIFT 16 -#define PSCI_0_2_POWER_STATE_TYPE_MASK \ - (0x1 << PSCI_0_2_POWER_STATE_TYPE_SHIFT) -#define PSCI_0_2_POWER_STATE_AFFL_SHIFT 24 -#define PSCI_0_2_POWER_STATE_AFFL_MASK \ - (0x3 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) - -/* PSCI extended power state encoding for CPU_SUSPEND function */ -#define PSCI_1_0_EXT_POWER_STATE_ID_MASK 0xfffffff -#define PSCI_1_0_EXT_POWER_STATE_ID_SHIFT 0 -#define PSCI_1_0_EXT_POWER_STATE_TYPE_SHIFT 30 -#define PSCI_1_0_EXT_POWER_STATE_TYPE_MASK \ - (0x1 << PSCI_1_0_EXT_POWER_STATE_TYPE_SHIFT) - -/* PSCI v0.2 affinity level state returned by AFFINITY_INFO */ -#define PSCI_0_2_AFFINITY_LEVEL_ON 0 -#define PSCI_0_2_AFFINITY_LEVEL_OFF 1 -#define PSCI_0_2_AFFINITY_LEVEL_ON_PENDING 2 - -/* PSCI v0.2 multicore support in Trusted OS returned by MIGRATE_INFO_TYPE */ -#define PSCI_0_2_TOS_UP_MIGRATE 0 -#define PSCI_0_2_TOS_UP_NO_MIGRATE 1 -#define PSCI_0_2_TOS_MP 2 - -/* PSCI version decoding (independent of PSCI version) */ -#define PSCI_VERSION_MAJOR_SHIFT 16 -#define PSCI_VERSION_MINOR_MASK \ - ((1U << PSCI_VERSION_MAJOR_SHIFT) - 1) -#define PSCI_VERSION_MAJOR_MASK ~PSCI_VERSION_MINOR_MASK -#define PSCI_VERSION_MAJOR(ver) \ - (((ver) & PSCI_VERSION_MAJOR_MASK) >> PSCI_VERSION_MAJOR_SHIFT) -#define PSCI_VERSION_MINOR(ver) \ - ((ver) & PSCI_VERSION_MINOR_MASK) - -/* PSCI features decoding (>=1.0) */ -#define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT 1 -#define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK \ - (0x1 << PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT) - -/* PSCI return values (inclusive of all PSCI versions) */ -#define PSCI_RET_SUCCESS 0 -#define PSCI_RET_NOT_SUPPORTED -1 -#define PSCI_RET_INVALID_PARAMS -2 -#define PSCI_RET_DENIED -3 -#define PSCI_RET_ALREADY_ON -4 -#define PSCI_RET_ON_PENDING -5 -#define PSCI_RET_INTERNAL_FAILURE -6 -#define PSCI_RET_NOT_PRESENT -7 -#define PSCI_RET_DISABLED -8 -#define PSCI_RET_INVALID_ADDRESS -9 - -#endif /* _UAPI_LINUX_PSCI_H */ diff --git a/lib/pci-edu.c b/lib/pci-edu.c deleted file mode 100644 index 0e031054..00000000 --- a/lib/pci-edu.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Edu PCI device. - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Authors: - * Peter Xu , - * - * This work is licensed under the terms of the GNU LGPL, version 2 or - * later. - */ - -#include "pci-edu.h" -#include "asm/barrier.h" - -/* Return true if alive */ -static inline bool edu_check_alive(struct pci_edu_dev *dev) -{ - static uint32_t live_count = 1; - uint32_t value; - - edu_reg_writel(dev, EDU_REG_ALIVE, live_count++); - value = edu_reg_readl(dev, EDU_REG_ALIVE); - return (live_count - 1 == ~value); -} - -bool edu_init(struct pci_edu_dev *dev) -{ - pcidevaddr_t dev_addr; - - dev_addr = pci_find_dev(PCI_VENDOR_ID_QEMU, PCI_DEVICE_ID_EDU); - if (dev_addr == PCIDEVADDR_INVALID) - return false; - - pci_dev_init(&dev->pci_dev, dev_addr); - pci_enable_defaults(&dev->pci_dev); - dev->reg_base = ioremap(dev->pci_dev.resource[EDU_BAR], PAGE_SIZE); - assert(edu_check_alive(dev)); - return true; -} - -void edu_dma(struct pci_edu_dev *dev, iova_t iova, - size_t size, unsigned int dev_offset, bool from_device) -{ - uint64_t from, to; - uint32_t cmd = EDU_CMD_DMA_START; - - assert(size <= EDU_DMA_SIZE_MAX); - assert(dev_offset < EDU_DMA_SIZE_MAX); - - printf("edu device DMA start %s addr %#" PRIx64 " size %lu off %#x\n", - from_device ? "FROM" : "TO", - iova, (ulong)size, dev_offset); - - if (from_device) { - from = dev_offset + EDU_DMA_START; - to = iova; - cmd |= EDU_CMD_DMA_FROM; - } else { - from = iova; - to = EDU_DMA_START + dev_offset; - cmd |= EDU_CMD_DMA_TO; - } - - edu_reg_writeq(dev, EDU_REG_DMA_SRC, from); - edu_reg_writeq(dev, EDU_REG_DMA_DST, to); - edu_reg_writeq(dev, EDU_REG_DMA_COUNT, size); - edu_reg_writel(dev, EDU_REG_DMA_CMD, cmd); - - /* Wait until DMA finished */ - while (edu_reg_readl(dev, EDU_REG_DMA_CMD) & EDU_CMD_DMA_START) - cpu_relax(); -} diff --git a/lib/pci-edu.h b/lib/pci-edu.h deleted file mode 100644 index 44b4ba16..00000000 --- a/lib/pci-edu.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Edu PCI device header. - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Authors: - * Peter Xu , - * - * This work is licensed under the terms of the GNU LGPL, version 2 or - * later. - * - * Edu device is a virtualized device in QEMU. Please refer to - * docs/specs/edu.txt in QEMU repository for EDU device manual. - */ -#ifndef __PCI_EDU_H__ -#define __PCI_EDU_H__ - -#include "pci.h" -#include "asm/io.h" - -#define PCI_VENDOR_ID_QEMU 0x1234 -#define PCI_DEVICE_ID_EDU 0x11e8 - -/* The only bar used by EDU device */ -#define EDU_BAR 0 -#define EDU_MAGIC 0xed -#define EDU_VERSION 0x100 -#define EDU_DMA_BUF_SIZE (1 << 20) -#define EDU_INPUT_BUF_SIZE 256 - -#define EDU_REG_ID 0x0 -#define EDU_REG_ALIVE 0x4 -#define EDU_REG_FACTORIAL 0x8 -#define EDU_REG_STATUS 0x20 -#define EDU_REG_INTR_STATUS 0x24 -#define EDU_REG_INTR_RAISE 0x60 -#define EDU_REG_INTR_ACK 0x64 -#define EDU_REG_DMA_SRC 0x80 -#define EDU_REG_DMA_DST 0x88 -#define EDU_REG_DMA_COUNT 0x90 -#define EDU_REG_DMA_CMD 0x98 - -#define EDU_CMD_DMA_START 0x01 -#define EDU_CMD_DMA_FROM 0x02 -#define EDU_CMD_DMA_TO 0x00 - -#define EDU_STATUS_FACTORIAL 0x1 -#define EDU_STATUS_INT_ENABLE 0x80 - -#define EDU_DMA_START 0x40000 -#define EDU_DMA_SIZE_MAX 4096 - -struct pci_edu_dev { - struct pci_dev pci_dev; - volatile void *reg_base; -}; - -#define edu_reg(d, r) (volatile void *)((d)->reg_base + (r)) - -static inline uint64_t edu_reg_readq(struct pci_edu_dev *dev, int reg) -{ - return __raw_readq(edu_reg(dev, reg)); -} - -static inline uint32_t edu_reg_readl(struct pci_edu_dev *dev, int reg) -{ - return __raw_readl(edu_reg(dev, reg)); -} - -static inline void edu_reg_writeq(struct pci_edu_dev *dev, int reg, - uint64_t val) -{ - __raw_writeq(val, edu_reg(dev, reg)); -} - -static inline void edu_reg_writel(struct pci_edu_dev *dev, int reg, - uint32_t val) -{ - __raw_writel(val, edu_reg(dev, reg)); -} - -bool edu_init(struct pci_edu_dev *dev); -void edu_dma(struct pci_edu_dev *dev, iova_t iova, - size_t size, unsigned int dev_offset, bool from_device); - -#endif diff --git a/lib/pci-host-generic.c b/lib/pci-host-generic.c deleted file mode 100644 index 818150dc..00000000 --- a/lib/pci-host-generic.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Generic PCI host controller as described in PCI Bus Binding to Open Firmware - * - * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "devicetree.h" -#include "alloc.h" -#include "pci.h" -#include "asm/pci.h" -#include "asm/io.h" -#include "pci-host-generic.h" -#include - -static struct pci_host_bridge *pci_host_bridge; - -static int of_flags_to_pci_type(u32 of_flags) -{ - static int type_map[] = { - [1] = PCI_BASE_ADDRESS_SPACE_IO, - [2] = PCI_BASE_ADDRESS_MEM_TYPE_32, - [3] = PCI_BASE_ADDRESS_MEM_TYPE_64 - }; - int idx = (of_flags >> 24) & 0x03; - int res; - - assert(idx > 0); - res = type_map[idx]; - - if (of_flags & 0x40000000) - res |= PCI_BASE_ADDRESS_MEM_PREFETCH; - - return res; -} - -static int pci_bar_type(u32 bar) -{ - if (bar & PCI_BASE_ADDRESS_SPACE) - return PCI_BASE_ADDRESS_SPACE_IO; - else - return bar & (PCI_BASE_ADDRESS_MEM_TYPE_MASK | - PCI_BASE_ADDRESS_MEM_PREFETCH); -} - -/* - * Probe DT for a generic PCI host controller - * See kernel Documentation/devicetree/bindings/pci/host-generic-pci.txt - * and function gen_pci_probe() in drivers/pci/host/pci-host-generic.c - */ -static struct pci_host_bridge *pci_dt_probe(void) -{ - struct pci_host_bridge *host; - const void *fdt = dt_fdt(); - const struct fdt_property *prop; - struct dt_pbus_reg base; - struct dt_device dt_dev; - struct dt_bus dt_bus; - struct pci_addr_space *as; - fdt32_t *data; - u32 bus, bus_max; - u32 nac, nsc, nac_root, nsc_root; - int nr_range_cells, nr_addr_spaces; - int ret, node, len, i; - - if (!dt_available()) { - printf("No device tree found\n"); - return NULL; - } - - dt_bus_init_defaults(&dt_bus); - dt_device_init(&dt_dev, &dt_bus, NULL); - - node = fdt_path_offset(fdt, "/"); - assert(node >= 0); - - ret = dt_get_nr_cells(node, &nac_root, &nsc_root); - assert(ret == 0); - assert(nac_root == 1 || nac_root == 2); - - node = fdt_node_offset_by_compatible(fdt, node, - "pci-host-ecam-generic"); - if (node == -FDT_ERR_NOTFOUND) { - printf("No PCIe ECAM compatible controller found\n"); - return NULL; - } - assert(node >= 0); - - prop = fdt_get_property(fdt, node, "device_type", &len); - assert(prop && len == 4 && !strcmp((char *)prop->data, "pci")); - - dt_device_bind_node(&dt_dev, node); - ret = dt_pbus_get_base(&dt_dev, &base); - assert(ret == 0); - - prop = fdt_get_property(fdt, node, "bus-range", &len); - if (prop == NULL) { - assert(len == -FDT_ERR_NOTFOUND); - bus = 0x00; - bus_max = 0xff; - } else { - data = (fdt32_t *)prop->data; - bus = fdt32_to_cpu(data[0]); - bus_max = fdt32_to_cpu(data[1]); - assert(bus <= bus_max); - } - assert(bus_max < base.size / (1 << PCI_ECAM_BUS_SHIFT)); - - ret = dt_get_nr_cells(node, &nac, &nsc); - assert(ret == 0); - assert(nac == 3 && nsc == 2); - - prop = fdt_get_property(fdt, node, "ranges", &len); - assert(prop != NULL); - - nr_range_cells = nac + nsc + nac_root; - nr_addr_spaces = (len / 4) / nr_range_cells; - assert(nr_addr_spaces); - - host = malloc(sizeof(*host) + - sizeof(host->addr_space[0]) * nr_addr_spaces); - assert(host != NULL); - - host->start = base.addr; - host->size = base.size; - host->bus = bus; - host->bus_max = bus_max; - host->nr_addr_spaces = nr_addr_spaces; - - data = (fdt32_t *)prop->data; - as = &host->addr_space[0]; - - for (i = 0; i < nr_addr_spaces; i++) { - /* - * The PCI binding encodes the PCI address with three - * cells as follows: - * - * phys.hi cell: npt000ss bbbbbbbb dddddfff rrrrrrrr - * phys.mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh - * phys.lo cell: llllllll llllllll llllllll llllllll - * - * PCI device bus address and flags are encoded into phys.high - * PCI 64 bit address is encoded into phys.mid and phys.low - */ - as->type = of_flags_to_pci_type(fdt32_to_cpu(data[0])); - as->pci_start = ((u64)fdt32_to_cpu(data[1]) << 32) | - fdt32_to_cpu(data[2]); - - if (nr_range_cells == 6) { - as->start = fdt32_to_cpu(data[3]); - as->size = ((u64)fdt32_to_cpu(data[4]) << 32) | - fdt32_to_cpu(data[5]); - } else { - as->start = ((u64)fdt32_to_cpu(data[3]) << 32) | - fdt32_to_cpu(data[4]); - as->size = ((u64)fdt32_to_cpu(data[5]) << 32) | - fdt32_to_cpu(data[6]); - } - - data += nr_range_cells; - as++; - } - - return host; -} - -static bool pci_alloc_resource(struct pci_dev *dev, int bar_num, u64 *addr) -{ - struct pci_host_bridge *host = pci_host_bridge; - struct pci_addr_space *as = &host->addr_space[0]; - u32 bar; - u64 size, pci_addr; - int type, i; - - *addr = INVALID_PHYS_ADDR; - - size = pci_bar_size(dev, bar_num); - if (!size) - return false; - - bar = pci_bar_get(dev, bar_num); - type = pci_bar_type(bar); - if (type & PCI_BASE_ADDRESS_MEM_TYPE_MASK) - type &= ~PCI_BASE_ADDRESS_MEM_PREFETCH; - - for (i = 0; i < host->nr_addr_spaces; i++) { - if (as->type == type) - break; - as++; - } - - if (i >= host->nr_addr_spaces) { - printf("%s: warning: can't satisfy request for ", __func__); - pci_dev_print_id(dev); - printf(" "); - pci_bar_print(dev, bar_num); - printf("\n"); - return false; - } - - pci_addr = ALIGN(as->pci_start + as->allocated, size); - size += pci_addr - (as->pci_start + as->allocated); - assert(as->allocated + size <= as->size); - *addr = pci_addr; - as->allocated += size; - - return true; -} - -bool pci_probe(void) -{ - struct pci_dev pci_dev; - pcidevaddr_t dev; - u8 header; - u32 cmd; - int i; - - assert(!pci_host_bridge); - pci_host_bridge = pci_dt_probe(); - if (!pci_host_bridge) - return false; - - for (dev = 0; dev < PCI_DEVFN_MAX; dev++) { - if (!pci_dev_exists(dev)) - continue; - - pci_dev_init(&pci_dev, dev); - - /* We are only interested in normal PCI devices */ - header = pci_config_readb(dev, PCI_HEADER_TYPE); - if ((header & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_NORMAL) - continue; - - cmd = PCI_COMMAND_SERR | PCI_COMMAND_PARITY; - - for (i = 0; i < PCI_BAR_NUM; i++) { - u64 addr; - - if (pci_alloc_resource(&pci_dev, i, &addr)) { - pci_bar_set_addr(&pci_dev, i, addr); - - if (pci_bar_is_memory(&pci_dev, i)) - cmd |= PCI_COMMAND_MEMORY; - else - cmd |= PCI_COMMAND_IO; - } - - if (pci_bar_is64(&pci_dev, i)) - i++; - } - - pci_config_writew(dev, PCI_COMMAND, cmd); - } - - return true; -} - -/* - * This function is to be called from pci_translate_addr() to provide - * mapping between this host bridge's PCI busses address and CPU physical - * address. - */ -phys_addr_t pci_host_bridge_get_paddr(u64 pci_addr) -{ - struct pci_host_bridge *host = pci_host_bridge; - struct pci_addr_space *as = &host->addr_space[0]; - int i; - - for (i = 0; i < host->nr_addr_spaces; i++) { - if (pci_addr >= as->pci_start && - pci_addr < as->pci_start + as->size) - return as->start + (pci_addr - as->pci_start); - as++; - } - - return INVALID_PHYS_ADDR; -} - -static void __iomem *pci_get_dev_conf(struct pci_host_bridge *host, int devfn) -{ - return (void __iomem *)(unsigned long) - host->start + (devfn << PCI_ECAM_DEVFN_SHIFT); -} - -u8 pci_config_readb(pcidevaddr_t dev, u8 off) -{ - void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); - return readb(conf + off); -} - -u16 pci_config_readw(pcidevaddr_t dev, u8 off) -{ - void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); - return readw(conf + off); -} - -u32 pci_config_readl(pcidevaddr_t dev, u8 off) -{ - void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); - return readl(conf + off); -} - -void pci_config_writeb(pcidevaddr_t dev, u8 off, u8 val) -{ - void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); - writeb(val, conf + off); -} - -void pci_config_writew(pcidevaddr_t dev, u8 off, u16 val) -{ - void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); - writew(val, conf + off); -} - -void pci_config_writel(pcidevaddr_t dev, u8 off, u32 val) -{ - void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); - writel(val, conf + off); -} diff --git a/lib/pci-host-generic.h b/lib/pci-host-generic.h deleted file mode 100644 index fd30e7c7..00000000 --- a/lib/pci-host-generic.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef PCI_HOST_GENERIC_H -#define PCI_HOST_GENERIC_H -/* - * PCI host bridge supporting structures and constants - * - * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" - -struct pci_addr_space { - phys_addr_t pci_start; - phys_addr_t start; - phys_addr_t size; - phys_addr_t allocated; - int type; -}; - -struct pci_host_bridge { - phys_addr_t start; - phys_addr_t size; - int bus; - int bus_max; - int nr_addr_spaces; - struct pci_addr_space addr_space[]; -}; - -/* - * The following constants are derived from Linux, see this source: - * - * drivers/pci/host/pci-host-generic.c - * struct gen_pci_cfg_bus_ops::bus_shift - * int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) - * - * Documentation/devicetree/bindings/pci/host-generic-pci.txt describes - * ECAM Configuration Space is be memory-mapped by concatenating the various - * components to form an offset: - * - * cfg_offset(bus, device, function, register) = - * bus << 20 | device << 15 | function << 12 | register - */ -#define PCI_ECAM_BUS_SHIFT 20 -#define PCI_ECAM_DEVFN_SHIFT 12 - -#endif diff --git a/lib/pci-testdev.c b/lib/pci-testdev.c deleted file mode 100644 index 039bb447..00000000 --- a/lib/pci-testdev.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * QEMU "pci-testdev" PCI test device - * - * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "pci.h" -#include "asm/io.h" - -struct pci_testdev_ops { - u8 (*io_readb)(const volatile void *addr); - u16 (*io_readw)(const volatile void *addr); - u32 (*io_readl)(const volatile void *addr); - void (*io_writeb)(u8 value, volatile void *addr); - void (*io_writew)(u16 value, volatile void *addr); - void (*io_writel)(u32 value, volatile void *addr); -}; - -static u8 pio_readb(const volatile void *addr) -{ - return inb((unsigned long)addr); -} - -static u16 pio_readw(const volatile void *addr) -{ - return inw((unsigned long)addr); -} - -static u32 pio_readl(const volatile void *addr) -{ - return inl((unsigned long)addr); -} - -static void pio_writeb(u8 value, volatile void *addr) -{ - outb(value, (unsigned long)addr); -} - -static void pio_writew(u16 value, volatile void *addr) -{ - outw(value, (unsigned long)addr); -} - -static void pio_writel(u32 value, volatile void *addr) -{ - outl(value, (unsigned long)addr); -} - -static struct pci_testdev_ops pci_testdev_io_ops = { - .io_readb = pio_readb, - .io_readw = pio_readw, - .io_readl = pio_readl, - .io_writeb = pio_writeb, - .io_writew = pio_writew, - .io_writel = pio_writel -}; - -static u8 mmio_readb(const volatile void *addr) -{ - return *(const volatile u8 __force *)addr; -} - -static u16 mmio_readw(const volatile void *addr) -{ - return *(const volatile u16 __force *)addr; -} - -static u32 mmio_readl(const volatile void *addr) -{ - return *(const volatile u32 __force *)addr; -} - -static void mmio_writeb(u8 value, volatile void *addr) -{ - *(volatile u8 __force *)addr = value; -} - -static void mmio_writew(u16 value, volatile void *addr) -{ - *(volatile u16 __force *)addr = value; -} - -static void mmio_writel(u32 value, volatile void *addr) -{ - *(volatile u32 __force *)addr = value; -} - -static struct pci_testdev_ops pci_testdev_mem_ops = { - .io_readb = mmio_readb, - .io_readw = mmio_readw, - .io_readl = mmio_readl, - .io_writeb = mmio_writeb, - .io_writew = mmio_writew, - .io_writel = mmio_writel -}; - -static bool pci_testdev_one(struct pci_test_dev_hdr *test, - int test_nr, - struct pci_testdev_ops *ops) -{ - u8 width; - u32 count, sig, off; - const int nr_writes = 16; - int i; - - ops->io_writeb(test_nr, &test->test); - count = ops->io_readl(&test->count); - if (count != 0) - return false; - - width = ops->io_readb(&test->width); - if (width != 1 && width != 2 && width != 4) - return false; - - sig = ops->io_readl(&test->data); - off = ops->io_readl(&test->offset); - - for (i = 0; i < nr_writes; i++) { - switch (width) { - case 1: ops->io_writeb(sig, (void *)test + off); break; - case 2: ops->io_writew(sig, (void *)test + off); break; - case 4: ops->io_writel(sig, (void *)test + off); break; - } - } - - count = ops->io_readl(&test->count); - if (!count) - return true; - - return (int)count == nr_writes; -} - -static void pci_testdev_print(struct pci_test_dev_hdr *test, - struct pci_testdev_ops *ops) -{ - bool io = (ops == &pci_testdev_io_ops); - int i; - - printf("pci-testdev %3s: ", io ? "io" : "mem"); - for (i = 0;; ++i) { - char c = ops->io_readb(&test->name[i]); - if (!c) - break; - printf("%c", c); - } - printf("\n"); -} - -static int pci_testdev_all(struct pci_test_dev_hdr *test, - struct pci_testdev_ops *ops) -{ - int i; - - for (i = 0;; i++) { - if (!pci_testdev_one(test, i, ops)) - break; - pci_testdev_print(test, ops); - } - - return i; -} - -int pci_testdev(void) -{ - struct pci_dev pci_dev; - pcidevaddr_t dev; - phys_addr_t addr; - void __iomem *mem, *io; - int nr_tests = 0; - bool ret; - - dev = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST); - if (dev == PCIDEVADDR_INVALID) { - printf("'pci-testdev' device is not found, " - "check QEMU '-device pci-testdev' parameter\n"); - return -1; - } - pci_dev_init(&pci_dev, dev); - - ret = pci_bar_is_valid(&pci_dev, 0) && pci_bar_is_valid(&pci_dev, 1); - assert(ret); - - addr = pci_bar_get_addr(&pci_dev, 0); - mem = ioremap(addr, PAGE_SIZE); - - addr = pci_bar_get_addr(&pci_dev, 1); - io = (void *)(unsigned long)addr; - - nr_tests += pci_testdev_all(mem, &pci_testdev_mem_ops); - nr_tests += pci_testdev_all(io, &pci_testdev_io_ops); - - return nr_tests; -} diff --git a/lib/pci.c b/lib/pci.c deleted file mode 100644 index daa33e1f..00000000 --- a/lib/pci.c +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright (C) 2013, Red Hat Inc, Michael S. Tsirkin - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include "pci.h" -#include "asm/pci.h" - -void pci_cap_walk(struct pci_dev *dev, pci_cap_handler_t handler) -{ - uint8_t cap_offset; - uint8_t cap_id; - int count = 0; - - cap_offset = pci_config_readb(dev->bdf, PCI_CAPABILITY_LIST); - while (cap_offset) { - cap_id = pci_config_readb(dev->bdf, cap_offset); - assert(cap_id < PCI_CAP_ID_MAX + 1); - handler(dev, cap_offset, cap_id); - cap_offset = pci_config_readb(dev->bdf, cap_offset + 1); - /* Avoid dead loop during cap walk */ - assert(++count <= 255); - } -} - -void pci_msi_set_enable(struct pci_dev *dev, bool enabled) -{ - uint16_t msi_control; - uint16_t offset; - - offset = dev->msi_offset; - msi_control = pci_config_readw(dev->bdf, offset + PCI_MSI_FLAGS); - - if (enabled) - msi_control |= PCI_MSI_FLAGS_ENABLE; - else - msi_control &= ~PCI_MSI_FLAGS_ENABLE; - - pci_config_writew(dev->bdf, offset + PCI_MSI_FLAGS, msi_control); -} - -bool pci_setup_msi(struct pci_dev *dev, uint64_t msi_addr, uint32_t msi_data) -{ - uint16_t msi_control; - uint16_t offset; - pcidevaddr_t addr; - - assert(dev); - - if (!dev->msi_offset) { - printf("MSI: dev %#x does not support MSI.\n", dev->bdf); - return false; - } - - addr = dev->bdf; - offset = dev->msi_offset; - msi_control = pci_config_readw(addr, offset + PCI_MSI_FLAGS); - pci_config_writel(addr, offset + PCI_MSI_ADDRESS_LO, - msi_addr & 0xffffffff); - - if (msi_control & PCI_MSI_FLAGS_64BIT) { - pci_config_writel(addr, offset + PCI_MSI_ADDRESS_HI, - (uint32_t)(msi_addr >> 32)); - pci_config_writel(addr, offset + PCI_MSI_DATA_64, msi_data); - } else { - pci_config_writel(addr, offset + PCI_MSI_DATA_32, msi_data); - } - - pci_msi_set_enable(dev, true); - - return true; -} - -void pci_cmd_set_clr(struct pci_dev *dev, uint16_t set, uint16_t clr) -{ - uint16_t val = pci_config_readw(dev->bdf, PCI_COMMAND); - - /* No overlap is allowed */ - assert((set & clr) == 0); - val |= set; - val &= ~clr; - - pci_config_writew(dev->bdf, PCI_COMMAND, val); -} - -bool pci_dev_exists(pcidevaddr_t dev) -{ - return (pci_config_readw(dev, PCI_VENDOR_ID) != 0xffff && - pci_config_readw(dev, PCI_DEVICE_ID) != 0xffff); -} - -/* Scan bus look for a specific device. Only bus 0 scanned for now. */ -pcidevaddr_t pci_find_dev(uint16_t vendor_id, uint16_t device_id) -{ - pcidevaddr_t dev; - - for (dev = 0; dev < PCI_DEVFN_MAX; ++dev) { - if (pci_config_readw(dev, PCI_VENDOR_ID) == vendor_id && - pci_config_readw(dev, PCI_DEVICE_ID) == device_id) - return dev; - } - - return PCIDEVADDR_INVALID; -} - -uint32_t pci_bar_mask(uint32_t bar) -{ - return (bar & PCI_BASE_ADDRESS_SPACE_IO) ? - PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK; -} - -uint32_t pci_bar_get(struct pci_dev *dev, int bar_num) -{ - ASSERT_BAR_NUM(bar_num); - - return pci_config_readl(dev->bdf, PCI_BASE_ADDRESS_0 + - bar_num * 4); -} - -static phys_addr_t __pci_bar_get_addr(struct pci_dev *dev, int bar_num) -{ - uint32_t bar = pci_bar_get(dev, bar_num); - uint32_t mask = pci_bar_mask(bar); - uint64_t addr = bar & mask; - phys_addr_t phys_addr; - - if (pci_bar_is64(dev, bar_num)) - addr |= (uint64_t)pci_bar_get(dev, bar_num + 1) << 32; - - phys_addr = pci_translate_addr(dev->bdf, addr); - assert(phys_addr != INVALID_PHYS_ADDR); - - return phys_addr; -} - -phys_addr_t pci_bar_get_addr(struct pci_dev *dev, int bar_num) -{ - ASSERT_BAR_NUM(bar_num); - - return dev->resource[bar_num]; -} - -void pci_bar_set_addr(struct pci_dev *dev, int bar_num, phys_addr_t addr) -{ - int off = PCI_BASE_ADDRESS_0 + bar_num * 4; - - assert(addr != INVALID_PHYS_ADDR); - assert(dev->resource[bar_num] != INVALID_PHYS_ADDR); - - ASSERT_BAR_NUM(bar_num); - if (pci_bar_is64(dev, bar_num)) - ASSERT_BAR_NUM(bar_num + 1); - else - assert((addr >> 32) == 0); - - pci_config_writel(dev->bdf, off, (uint32_t)addr); - dev->resource[bar_num] = addr; - - if (pci_bar_is64(dev, bar_num)) { - pci_config_writel(dev->bdf, off + 4, (uint32_t)(addr >> 32)); - dev->resource[bar_num + 1] = dev->resource[bar_num]; - } -} - -/* - * To determine the amount of address space needed by a PCI device, - * one must save the original value of the BAR, write a value of - * all 1's to the register, and then read it back. The amount of - * memory can be then determined by masking the information bits, - * performing a bitwise NOT, and incrementing the value by 1. - * - * The following pci_bar_size_helper() and pci_bar_size() functions - * implement the algorithm. - */ -static uint32_t pci_bar_size_helper(struct pci_dev *dev, int bar_num) -{ - int off = PCI_BASE_ADDRESS_0 + bar_num * 4; - uint16_t bdf = dev->bdf; - uint32_t bar, val; - - bar = pci_config_readl(bdf, off); - pci_config_writel(bdf, off, ~0u); - val = pci_config_readl(bdf, off); - pci_config_writel(bdf, off, bar); - - return val; -} - -phys_addr_t pci_bar_size(struct pci_dev *dev, int bar_num) -{ - uint32_t bar, size; - - size = pci_bar_size_helper(dev, bar_num); - if (!size) - return 0; - - bar = pci_bar_get(dev, bar_num); - size &= pci_bar_mask(bar); - - if (pci_bar_is64(dev, bar_num)) { - phys_addr_t size64 = pci_bar_size_helper(dev, bar_num + 1); - size64 = (size64 << 32) | size; - - return ~size64 + 1; - } else { - return ~size + 1; - } -} - -bool pci_bar_is_memory(struct pci_dev *dev, int bar_num) -{ - uint32_t bar = pci_bar_get(dev, bar_num); - - return !(bar & PCI_BASE_ADDRESS_SPACE_IO); -} - -bool pci_bar_is_valid(struct pci_dev *dev, int bar_num) -{ - return dev->resource[bar_num] != INVALID_PHYS_ADDR; -} - -bool pci_bar_is64(struct pci_dev *dev, int bar_num) -{ - uint32_t bar = pci_bar_get(dev, bar_num); - - if (bar & PCI_BASE_ADDRESS_SPACE_IO) - return false; - - return (bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == - PCI_BASE_ADDRESS_MEM_TYPE_64; -} - -void pci_bar_print(struct pci_dev *dev, int bar_num) -{ - phys_addr_t size, start, end; - uint32_t bar; - - if (!pci_bar_is_valid(dev, bar_num)) - return; - - bar = pci_bar_get(dev, bar_num); - size = pci_bar_size(dev, bar_num); - start = pci_bar_get_addr(dev, bar_num); - end = start + size - 1; - - if (pci_bar_is64(dev, bar_num)) { - printf("BAR#%d,%d [%" PRIx64 "-%" PRIx64 " ", - bar_num, bar_num + 1, start, end); - } else { - printf("BAR#%d [%02x-%02x ", - bar_num, (uint32_t)start, (uint32_t)end); - } - - if (bar & PCI_BASE_ADDRESS_SPACE_IO) { - printf("PIO"); - } else { - printf("MEM"); - switch (bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { - case PCI_BASE_ADDRESS_MEM_TYPE_32: - printf("32"); - break; - case PCI_BASE_ADDRESS_MEM_TYPE_1M: - printf("1M"); - break; - case PCI_BASE_ADDRESS_MEM_TYPE_64: - printf("64"); - break; - default: - assert(0); - } - } - - if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) - printf("/p"); - - printf("]"); -} - -void pci_dev_print_id(struct pci_dev *dev) -{ - pcidevaddr_t bdf = dev->bdf; - - printf("00.%02x.%1x %04x:%04x", bdf / 8, bdf % 8, - pci_config_readw(bdf, PCI_VENDOR_ID), - pci_config_readw(bdf, PCI_DEVICE_ID)); -} - -static void pci_cap_print(struct pci_dev *dev, int cap_offset, int cap_id) -{ - switch (cap_id) { - case PCI_CAP_ID_MSI: { - uint16_t control = pci_config_readw(dev->bdf, cap_offset + PCI_MSI_FLAGS); - printf("\tMSI,%s-bit capability ", control & PCI_MSI_FLAGS_64BIT ? "64" : "32"); - break; - } - default: - printf("\tcapability %#04x ", cap_id); - break; - } - printf("at offset %#04x\n", cap_offset); -} - -void pci_dev_print(struct pci_dev *dev) -{ - pcidevaddr_t bdf = dev->bdf; - uint8_t header = pci_config_readb(bdf, PCI_HEADER_TYPE); - uint8_t progif = pci_config_readb(bdf, PCI_CLASS_PROG); - uint8_t subclass = pci_config_readb(bdf, PCI_CLASS_DEVICE); - uint8_t class = pci_config_readb(bdf, PCI_CLASS_DEVICE + 1); - int i; - - pci_dev_print_id(dev); - printf(" type %02x progif %02x class %02x subclass %02x\n", - header, progif, class, subclass); - - pci_cap_walk(dev, pci_cap_print); - - if ((header & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_NORMAL) - return; - - for (i = 0; i < PCI_BAR_NUM; i++) { - if (pci_bar_is_valid(dev, i)) { - printf("\t"); - pci_bar_print(dev, i); - printf("\n"); - } - if (pci_bar_is64(dev, i)) - i++; - } -} - -void pci_print(void) -{ - pcidevaddr_t devfn; - struct pci_dev pci_dev; - - for (devfn = 0; devfn < PCI_DEVFN_MAX; ++devfn) { - if (pci_dev_exists(devfn)) { - pci_dev_init(&pci_dev, devfn); - pci_dev_print(&pci_dev); - } - } -} - -void pci_dev_init(struct pci_dev *dev, pcidevaddr_t bdf) -{ - int i; - - memset(dev, 0, sizeof(*dev)); - dev->bdf = bdf; - - for (i = 0; i < PCI_BAR_NUM; i++) { - if (pci_bar_size(dev, i)) { - dev->resource[i] = __pci_bar_get_addr(dev, i); - if (pci_bar_is64(dev, i)) { - assert(i + 1 < PCI_BAR_NUM); - dev->resource[i + 1] = dev->resource[i]; - i++; - } - } else { - dev->resource[i] = INVALID_PHYS_ADDR; - } - } -} - -uint8_t pci_intx_line(struct pci_dev *dev) -{ - return pci_config_readb(dev->bdf, PCI_INTERRUPT_LINE); -} - -static void pci_cap_setup(struct pci_dev *dev, int cap_offset, int cap_id) -{ - switch (cap_id) { - case PCI_CAP_ID_MSI: - dev->msi_offset = cap_offset; - break; - } -} - -void pci_enable_defaults(struct pci_dev *dev) -{ - /* Enable device DMA operations */ - pci_cmd_set_clr(dev, PCI_COMMAND_MASTER, 0); - pci_cap_walk(dev, pci_cap_setup); -} diff --git a/lib/pci.h b/lib/pci.h deleted file mode 100644 index 689f03ca..00000000 --- a/lib/pci.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef PCI_H -#define PCI_H -/* - * API for scanning a PCI bus for a given device, as well to access - * BAR registers. - * - * Copyright (C) 2013, Red Hat Inc, Michael S. Tsirkin - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" - -typedef uint16_t pcidevaddr_t; -enum { - PCIDEVADDR_INVALID = 0xffff, -}; - -#define PCI_BAR_NUM 6 -#define PCI_DEVFN_MAX 256 - -#define ASSERT_BAR_NUM(bar_num) \ - do { assert(bar_num >= 0 && bar_num < PCI_BAR_NUM); } while (0) - -#define PCI_BDF_GET_DEVFN(x) ((x) & 0xff) -#define PCI_BDF_GET_BUS(x) (((x) >> 8) & 0xff) - -struct pci_dev { - uint16_t bdf; - uint16_t msi_offset; - phys_addr_t resource[PCI_BAR_NUM]; -}; - -extern void pci_dev_init(struct pci_dev *dev, pcidevaddr_t bdf); -extern void pci_cmd_set_clr(struct pci_dev *dev, uint16_t set, uint16_t clr); -typedef void (*pci_cap_handler_t)(struct pci_dev *dev, int cap_offset, int cap_id); -extern void pci_cap_walk(struct pci_dev *dev, pci_cap_handler_t handler); -extern void pci_enable_defaults(struct pci_dev *dev); -extern bool pci_setup_msi(struct pci_dev *dev, uint64_t msi_addr, - uint32_t msi_data); - -typedef phys_addr_t iova_t; - -extern bool pci_probe(void); -extern void pci_print(void); -extern bool pci_dev_exists(pcidevaddr_t dev); -extern pcidevaddr_t pci_find_dev(uint16_t vendor_id, uint16_t device_id); - -/* - * @bar_num in all BAR access functions below is the index of the 32-bit - * register starting from the PCI_BASE_ADDRESS_0 offset. - * - * In cases where the BAR size is 64-bit, a caller should still provide - * @bar_num in terms of 32-bit words. For example, if a device has a 64-bit - * BAR#0 and a 32-bit BAR#1, then caller should provide 2 to address BAR#1, - * not 1. - * - * It is expected the caller is aware of the device BAR layout and never - * tries to address the middle of a 64-bit register. - */ -extern phys_addr_t pci_bar_get_addr(struct pci_dev *dev, int bar_num); -extern void pci_bar_set_addr(struct pci_dev *dev, int bar_num, phys_addr_t addr); -extern phys_addr_t pci_bar_size(struct pci_dev *dev, int bar_num); -extern uint32_t pci_bar_get(struct pci_dev *dev, int bar_num); -extern uint32_t pci_bar_mask(uint32_t bar); -extern bool pci_bar_is64(struct pci_dev *dev, int bar_num); -extern bool pci_bar_is_memory(struct pci_dev *dev, int bar_num); -extern bool pci_bar_is_valid(struct pci_dev *dev, int bar_num); -extern void pci_bar_print(struct pci_dev *dev, int bar_num); -extern void pci_dev_print_id(struct pci_dev *dev); -extern void pci_dev_print(struct pci_dev *dev); -extern uint8_t pci_intx_line(struct pci_dev *dev); -void pci_msi_set_enable(struct pci_dev *dev, bool enabled); - -extern int pci_testdev(void); - -/* - * pci-testdev is a driver for the pci-testdev qemu pci device. The - * device enables testing mmio and portio exits, and measuring their - * speed. - */ -#define PCI_VENDOR_ID_REDHAT 0x1b36 -#define PCI_DEVICE_ID_REDHAT_TEST 0x0005 - -/* - * pci-testdev supports at least three types of tests (via mmio and - * portio BARs): no-eventfd, wildcard-eventfd and datamatch-eventfd - */ -#define PCI_TESTDEV_BAR_MEM 0 -#define PCI_TESTDEV_BAR_IO 1 -#define PCI_TESTDEV_NUM_BARS 2 -#define PCI_TESTDEV_NUM_TESTS 3 - -struct pci_test_dev_hdr { - uint8_t test; - uint8_t width; - uint8_t pad0[2]; - uint32_t offset; - uint32_t data; - uint32_t count; - uint8_t name[]; -}; - -#define PCI_HEADER_TYPE_MASK 0x7f - -#endif /* PCI_H */ diff --git a/lib/powerpc/.gitignore b/lib/powerpc/.gitignore deleted file mode 100644 index 84872bf1..00000000 --- a/lib/powerpc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -asm-offsets.[hs] diff --git a/lib/powerpc/asm/handlers.h b/lib/powerpc/asm/handlers.h deleted file mode 100644 index 64ba727a..00000000 --- a/lib/powerpc/asm/handlers.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _ASMPOWERPC_HANDLERS_H_ -#define _ASMPOWERPC_HANDLERS_H_ - -#include - -void dec_except_handler(struct pt_regs *regs, void *data); - -#endif /* _ASMPOWERPC_HANDLERS_H_ */ diff --git a/lib/powerpc/asm/hcall.h b/lib/powerpc/asm/hcall.h deleted file mode 100644 index 1173feaa..00000000 --- a/lib/powerpc/asm/hcall.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef _ASMPOWERPC_HCALL_H_ -#define _ASMPOWERPC_HCALL_H_ -/* - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ - -#define SC1 0x44000022 -#define SC1_REPLACEMENT 0x7c000268 - -#define H_SUCCESS 0 -#define H_HARDWARE -1 -#define H_FUNCTION -2 -#define H_PRIVILEGE -3 -#define H_PARAMETER -4 - -#define H_SET_SPRG0 0x24 -#define H_SET_DABR 0x28 -#define H_PAGE_INIT 0x2c -#define H_CEDE 0xE0 -#define H_GET_TERM_CHAR 0x54 -#define H_PUT_TERM_CHAR 0x58 -#define H_RANDOM 0x300 -#define H_SET_MODE 0x31C - -#define KVMPPC_HCALL_BASE 0xf000 -#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0) - -#ifndef __ASSEMBLY__ -/* - * hcall_have_broken_sc1 checks if we're on a host with a broken sc1. - * Returns 0 if we're not. - */ -extern int hcall_have_broken_sc1(void); - -/* - * hcall is the hypercall wrapper function. unittests may do what - * they like, but the framework should make all hypercalls through - * here to ensure they use a working sc1 instruction. @nr is the - * hypercall number. - */ -extern unsigned long hcall(unsigned long nr, ...); - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASMPOWERPC_HCALL_H_ */ diff --git a/lib/powerpc/asm/ppc_asm.h b/lib/powerpc/asm/ppc_asm.h deleted file mode 100644 index 39620a39..00000000 --- a/lib/powerpc/asm/ppc_asm.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef _ASMPOWERPC_PPC_ASM_H -#define _ASMPOWERPC_PPC_ASM_H - -#include - -#define SAVE_GPR(n, base) std n,GPR0+8*(n)(base) -#define REST_GPR(n, base) ld n,GPR0+8*(n)(base) - -#define LOAD_REG_IMMEDIATE(reg,expr) \ - lis reg,(expr)@highest; \ - ori reg,reg,(expr)@higher; \ - rldicr reg,reg,32,31; \ - oris reg,reg,(expr)@h; \ - ori reg,reg,(expr)@l; - -#define LOAD_REG_ADDR(reg,name) \ - ld reg,name@got(r2) - -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - -#define FIXUP_ENDIAN - -#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - -#define FIXUP_ENDIAN \ - .long 0x05000048; /* bl . + 4 */ \ - .long 0xa602487d; /* mflr r10 */ \ - .long 0x20004a39; /* addi r10,r10,32 */ \ - .long 0xa600607d; /* mfmsr r11 */ \ - .long 0x01006b69; /* xori r11,r11,1 */ \ - .long 0xa6035a7d; /* mtsrr0 r10 */ \ - .long 0xa6037b7d; /* mtsrr1 r11 */ \ - .long 0x2400004c; /* rfid */ \ - .long 0x00000048; /* b . */ \ - -#endif /* __BYTE_ORDER__ */ - -#endif /* _ASMPOWERPC_PPC_ASM_H */ diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h deleted file mode 100644 index ac001e18..00000000 --- a/lib/powerpc/asm/processor.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _ASMPOWERPC_PROCESSOR_H_ -#define _ASMPOWERPC_PROCESSOR_H_ - -#include -#include - -#ifndef __ASSEMBLY__ -void handle_exception(int trap, void (*func)(struct pt_regs *, void *), void *); -void do_handle_exception(struct pt_regs *regs); -#endif /* __ASSEMBLY__ */ - -static inline uint64_t get_tb(void) -{ - uint64_t tb; - - asm volatile ("mfspr %[tb],268" : [tb] "=r" (tb)); - - return tb; -} - -extern void delay(uint64_t cycles); -extern void udelay(uint64_t us); - -static inline void mdelay(uint64_t ms) -{ - while (ms--) - udelay(1000); -} - -#endif /* _ASMPOWERPC_PROCESSOR_H_ */ diff --git a/lib/powerpc/asm/rtas.h b/lib/powerpc/asm/rtas.h deleted file mode 100644 index 6fb407a1..00000000 --- a/lib/powerpc/asm/rtas.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _ASMPOWERPC_RTAS_H_ -#define _ASMPOWERPC_RTAS_H_ -/* - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ - -#ifndef __ASSEMBLY__ - -#include - -#define RTAS_UNKNOWN_SERVICE (-1) - -struct rtas_args { - u32 token; - u32 nargs; - u32 nret; - u32 args[16]; - u32 *rets; -}; - -extern void rtas_init(void); -extern int rtas_token(const char *service, uint32_t *token); -extern int rtas_call(int token, int nargs, int nret, int *outputs, ...); - -extern void rtas_power_off(void); -#endif /* __ASSEMBLY__ */ - -#define RTAS_MSR_MASK 0xfffffffffffffffe - -#endif /* _ASMPOWERPC_RTAS_H_ */ diff --git a/lib/powerpc/asm/setup.h b/lib/powerpc/asm/setup.h deleted file mode 100644 index cc7cf5e2..00000000 --- a/lib/powerpc/asm/setup.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _ASMPOWERPC_SETUP_H_ -#define _ASMPOWERPC_SETUP_H_ -/* - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include - -#define NR_CPUS 8 /* arbitrarily set for now */ -extern u32 cpus[NR_CPUS]; -extern int nr_cpus; - -extern uint64_t tb_hz; - -#define NR_MEM_REGIONS 8 -#define MR_F_PRIMARY (1U << 0) -struct mem_region { - phys_addr_t start; - phys_addr_t end; - unsigned int flags; -}; -extern struct mem_region mem_regions[NR_MEM_REGIONS]; -extern phys_addr_t __physical_start, __physical_end; -extern unsigned __icache_bytes, __dcache_bytes; - -#define PHYSICAL_START (__physical_start) -#define PHYSICAL_END (__physical_end) - -void setup(const void *fdt); - -#endif /* _ASMPOWERPC_SETUP_H_ */ diff --git a/lib/powerpc/asm/smp.h b/lib/powerpc/asm/smp.h deleted file mode 100644 index 21940b4b..00000000 --- a/lib/powerpc/asm/smp.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _ASMPOWERPC_SMP_H_ -#define _ASMPOWERPC_SMP_H_ - -#include - -extern int nr_threads; - -struct start_threads { - int nr_threads; - int nr_started; -}; - -typedef void (*secondary_entry_fn)(void); - -extern void halt(void); - -extern int start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3); -extern struct start_threads start_cpu(int cpu_node, secondary_entry_fn entry, - uint32_t r3); -extern bool start_all_cpus(secondary_entry_fn entry, uint32_t r3); - -#endif /* _ASMPOWERPC_SMP_H_ */ diff --git a/lib/powerpc/asm/stack.h b/lib/powerpc/asm/stack.h deleted file mode 100644 index e1c46ee0..00000000 --- a/lib/powerpc/asm/stack.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _ASMPOWERPC_STACK_H_ -#define _ASMPOWERPC_STACK_H_ - -#ifndef _STACK_H_ -#error Do not directly include . Just use . -#endif - -#endif diff --git a/lib/powerpc/handlers.c b/lib/powerpc/handlers.c deleted file mode 100644 index c8721e0a..00000000 --- a/lib/powerpc/handlers.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Generic exception handlers for registration and use in tests - * - * Copyright 2016 Suraj Jitindar Singh, IBM. - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ - -#include -#include -#include - -/* - * Generic handler for decrementer exceptions (0x900) - * Just reset the decrementer back to the value specified when registering the - * handler - */ -void dec_except_handler(struct pt_regs *regs __unused, void *data) -{ - uint64_t dec = *((uint64_t *) data); - - asm volatile ("mtdec %0" : : "r" (dec)); -} diff --git a/lib/powerpc/hcall.c b/lib/powerpc/hcall.c deleted file mode 100644 index 711cb1b0..00000000 --- a/lib/powerpc/hcall.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Hypercall helpers - * - * broken_sc1 probing/patching inspired by SLOF, see - * SLOF:lib/libhvcall/brokensc1.c - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include "io.h" - -int hcall_have_broken_sc1(void) -{ - register unsigned long r3 asm("r3") = H_SET_DABR; - register unsigned long r4 asm("r4") = 0; - - asm volatile("sc 1" - : "=r" (r3) - : "r" (r3), "r" (r4) - : "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"); - - return r3 == (unsigned long)H_PRIVILEGE; -} - -void putchar(int c) -{ - unsigned long vty = 0; /* 0 == default */ - unsigned long nr_chars = 1; - unsigned long chars = (unsigned long)c << 56; - - hcall(H_PUT_TERM_CHAR, vty, nr_chars, chars); -} - -int __getchar(void) -{ - register unsigned long r3 asm("r3") = H_GET_TERM_CHAR; - register unsigned long r4 asm("r4") = 0; /* 0 == default vty */ - register unsigned long r5 asm("r5"); - - asm volatile (" sc 1 " : "+r"(r3), "+r"(r4), "=r"(r5) - : "r"(r3), "r"(r4)); - - return r3 == H_SUCCESS && r4 > 0 ? r5 >> 48 : -1; -} diff --git a/lib/powerpc/io.c b/lib/powerpc/io.c deleted file mode 100644 index a381688b..00000000 --- a/lib/powerpc/io.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Each architecture must implement puts() and exit(). - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include -#include "io.h" - -static struct spinlock print_lock; - -void io_init(void) -{ - rtas_init(); -} - -void puts(const char *s) -{ - spin_lock(&print_lock); - while (*s) - putchar(*s++); - spin_unlock(&print_lock); -} - -/* - * Defining halt to take 'code' as an argument guarantees that it will - * be in r3 when we halt. That gives us a final chance to see the exit - * status while inspecting the halted unit test state. - */ -extern void halt(int code); - -void exit(int code) -{ -// FIXME: change this print-exit/rtas-poweroff to chr_testdev_exit(), -// maybe by plugging chr-testdev into a spapr-vty. - printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1); - rtas_power_off(); - halt(code); - __builtin_unreachable(); -} diff --git a/lib/powerpc/io.h b/lib/powerpc/io.h deleted file mode 100644 index 1f5a7bd6..00000000 --- a/lib/powerpc/io.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Prototypes for io.c - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -extern void io_init(void); -extern void putchar(int c); diff --git a/lib/powerpc/processor.c b/lib/powerpc/processor.c deleted file mode 100644 index ec85b9d8..00000000 --- a/lib/powerpc/processor.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * processor control and status function - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -#include -#include -#include -#include -#include - -static struct { - void (*func)(struct pt_regs *, void *data); - void *data; -} handlers[16]; - -void handle_exception(int trap, void (*func)(struct pt_regs *, void *), - void * data) -{ - trap >>= 8; - - if (trap < 16) { - handlers[trap].func = func; - handlers[trap].data = data; - } -} - -void do_handle_exception(struct pt_regs *regs) -{ - unsigned char v; - - v = regs->trap >> 8; - - if (v < 16 && handlers[v].func) { - handlers[v].func(regs, handlers[v].data); - return; - } - - printf("unhandled cpu exception %#lx\n", regs->trap); - abort(); -} - -void delay(uint64_t cycles) -{ - uint64_t start = get_tb(); - - while ((get_tb() - start) < cycles) - cpu_relax(); -} - -void udelay(uint64_t us) -{ - delay((us * tb_hz) / 1000000); -} diff --git a/lib/powerpc/rtas.c b/lib/powerpc/rtas.c deleted file mode 100644 index 41c0a243..00000000 --- a/lib/powerpc/rtas.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * powerpc RTAS - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include -#include -#include -#include - -extern void enter_rtas(unsigned long); - -unsigned long rtas_entry; -static struct rtas_args rtas_args; -static struct spinlock rtas_lock; - -static int rtas_node(void) -{ - int node = fdt_path_offset(dt_fdt(), "/rtas"); - - if (node < 0) { - printf("%s: /rtas: %s\n", __func__, fdt_strerror(node)); - abort(); - } - - return node; -} - -void rtas_init(void) -{ - bool broken_sc1 = hcall_have_broken_sc1(); - int node = rtas_node(), len, words, i; - const struct fdt_property *prop; - u32 *data, *insns; - - if (!dt_available()) { - printf("%s: No device tree!\n", __func__); - abort(); - } - - prop = fdt_get_property(dt_fdt(), node, - "linux,rtas-entry", &len); - if (!prop) { - /* We don't have a qemu provided RTAS blob, enter_rtas - * will use H_RTAS directly */ - return; - } - data = (u32 *)prop->data; - rtas_entry = (unsigned long)fdt32_to_cpu(*data); - insns = (u32 *)rtas_entry; - - prop = fdt_get_property(dt_fdt(), node, "rtas-size", &len); - if (!prop) { - printf("%s: /rtas/rtas-size: %s\n", - __func__, fdt_strerror(len)); - abort(); - } - data = (u32 *)prop->data; - words = (int)fdt32_to_cpu(*data)/4; - - for (i = 0; i < words; ++i) { - if (broken_sc1 && insns[i] == cpu_to_be32(SC1)) - insns[i] = cpu_to_be32(SC1_REPLACEMENT); - } -} - -int rtas_token(const char *service, uint32_t *token) -{ - const struct fdt_property *prop; - u32 *data; - - if (!dt_available()) - return RTAS_UNKNOWN_SERVICE; - - prop = fdt_get_property(dt_fdt(), rtas_node(), service, NULL); - if (!prop) - return RTAS_UNKNOWN_SERVICE; - - data = (u32 *)prop->data; - *token = fdt32_to_cpu(*data); - - return 0; -} - -int rtas_call(int token, int nargs, int nret, int *outputs, ...) -{ - va_list list; - int ret, i; - - spin_lock(&rtas_lock); - - rtas_args.token = cpu_to_be32(token); - rtas_args.nargs = cpu_to_be32(nargs); - rtas_args.nret = cpu_to_be32(nret); - rtas_args.rets = &rtas_args.args[nargs]; - - va_start(list, outputs); - for (i = 0; i < nargs; ++i) - rtas_args.args[i] = cpu_to_be32(va_arg(list, u32)); - va_end(list); - - for (i = 0; i < nret; ++i) - rtas_args.rets[i] = 0; - - enter_rtas(__pa(&rtas_args)); - - if (nret > 1 && outputs != NULL) - for (i = 0; i < nret - 1; ++i) - outputs[i] = be32_to_cpu(rtas_args.rets[i + 1]); - - ret = nret > 0 ? be32_to_cpu(rtas_args.rets[0]) : 0; - - spin_unlock(&rtas_lock); - return ret; -} - -void rtas_power_off(void) -{ - uint32_t token; - int ret; - - ret = rtas_token("power-off", &token); - if (ret) { - puts("RTAS power-off not available\n"); - return; - } - - ret = rtas_call(token, 2, 1, NULL, -1, -1); - printf("RTAS power-off returned %d\n", ret); -} diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c deleted file mode 100644 index 1be4c030..00000000 --- a/lib/powerpc/setup.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Initialize machine setup information and I/O. - * - * After running setup() unit tests may query how many cpus they have - * (nr_cpus), how much memory they have (PHYSICAL_END - PHYSICAL_START), - * may use dynamic memory allocation (malloc, etc.), printf, and exit. - * Finally, argc and argv are also ready to be passed to main(). - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "io.h" - -extern unsigned long stacktop; - -char *initrd; -u32 initrd_size; - -u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) }; -int nr_cpus; -uint64_t tb_hz; - -struct mem_region mem_regions[NR_MEM_REGIONS]; -phys_addr_t __physical_start, __physical_end; -unsigned __icache_bytes, __dcache_bytes; - -struct cpu_set_params { - unsigned icache_bytes; - unsigned dcache_bytes; - uint64_t tb_hz; -}; - -#define EXCEPTION_STACK_SIZE (32*1024) /* 32kB */ - -static char exception_stack[NR_CPUS][EXCEPTION_STACK_SIZE]; - -static void cpu_set(int fdtnode, u64 regval, void *info) -{ - static bool read_common_info = false; - struct cpu_set_params *params = info; - int cpu = nr_cpus++; - - assert_msg(cpu < NR_CPUS, "Number cpus exceeds maximum supported (%d).", NR_CPUS); - - cpus[cpu] = regval; - - /* set exception stack address for this CPU (in SPGR0) */ - asm volatile ("mtsprg0 %[addr]" :: - [addr] "r" (exception_stack[cpu + 1])); - - if (!read_common_info) { - const struct fdt_property *prop; - u32 *data; - - prop = fdt_get_property(dt_fdt(), fdtnode, - "i-cache-line-size", NULL); - assert(prop != NULL); - data = (u32 *)prop->data; - params->icache_bytes = fdt32_to_cpu(*data); - - prop = fdt_get_property(dt_fdt(), fdtnode, - "d-cache-line-size", NULL); - assert(prop != NULL); - data = (u32 *)prop->data; - params->dcache_bytes = fdt32_to_cpu(*data); - - prop = fdt_get_property(dt_fdt(), fdtnode, - "timebase-frequency", NULL); - assert(prop != NULL); - data = (u32 *)prop->data; - params->tb_hz = fdt32_to_cpu(*data); - - read_common_info = true; - } -} - -static void cpu_init(void) -{ - struct cpu_set_params params; - int ret; - - nr_cpus = 0; - ret = dt_for_each_cpu_node(cpu_set, ¶ms); - assert(ret == 0); - __icache_bytes = params.icache_bytes; - __dcache_bytes = params.dcache_bytes; - tb_hz = params.tb_hz; - - /* Interrupt Endianness */ - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - hcall(H_SET_MODE, 1, 4, 0, 0); -#else - hcall(H_SET_MODE, 0, 4, 0, 0); -#endif -} - -static void mem_init(phys_addr_t freemem_start) -{ - struct dt_pbus_reg regs[NR_MEM_REGIONS]; - struct mem_region primary, mem = { - .start = (phys_addr_t)-1, - }; - int nr_regs, i; - - nr_regs = dt_get_memory_params(regs, NR_MEM_REGIONS); - assert(nr_regs > 0); - - primary.end = 0; - - for (i = 0; i < nr_regs; ++i) { - mem_regions[i].start = regs[i].addr; - mem_regions[i].end = regs[i].addr + regs[i].size; - - /* - * pick the region we're in for our primary region - */ - if (freemem_start >= mem_regions[i].start - && freemem_start < mem_regions[i].end) { - mem_regions[i].flags |= MR_F_PRIMARY; - primary = mem_regions[i]; - } - - /* - * set the lowest and highest addresses found, - * ignoring potential gaps - */ - if (mem_regions[i].start < mem.start) - mem.start = mem_regions[i].start; - if (mem_regions[i].end > mem.end) - mem.end = mem_regions[i].end; - } - assert(primary.end != 0); -// assert(!(mem.start & ~PHYS_MASK) && !((mem.end - 1) & ~PHYS_MASK)); - - __physical_start = mem.start; /* PHYSICAL_START */ - __physical_end = mem.end; /* PHYSICAL_END */ - - phys_alloc_init(freemem_start, primary.end - freemem_start); - phys_alloc_set_minimum_alignment(__icache_bytes > __dcache_bytes - ? __icache_bytes : __dcache_bytes); -} - -void setup(const void *fdt) -{ - void *freemem = &stacktop; - const char *bootargs, *tmp; - u32 fdt_size; - int ret; - - /* - * Before calling mem_init we need to move the fdt and initrd - * to safe locations. We move them to construct the memory - * map illustrated below: - * - * +----------------------+ <-- top of physical memory - * | | - * ~ ~ - * | | - * +----------------------+ <-- top of initrd - * | | - * +----------------------+ <-- top of FDT - * | | - * +----------------------+ <-- top of cpu0's stack - * | | - * +----------------------+ <-- top of text/data/bss/toc sections, - * | | see powerpc/flat.lds - * | | - * +----------------------+ <-- load address - * | | - * +----------------------+ - */ - fdt_size = fdt_totalsize(fdt); - ret = fdt_move(fdt, freemem, fdt_size); - assert(ret == 0); - ret = dt_init(freemem); - assert(ret == 0); - freemem += fdt_size; - - ret = dt_get_initrd(&tmp, &initrd_size); - assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); - if (ret == 0) { - initrd = freemem; - memmove(initrd, tmp, initrd_size); - freemem += initrd_size; - } - - /* call init functions */ - cpu_init(); - - /* cpu_init must be called before mem_init */ - mem_init(PAGE_ALIGN((unsigned long)freemem)); - - /* mem_init must be called before io_init */ - io_init(); - - /* finish setup */ - ret = dt_get_bootargs(&bootargs); - assert(ret == 0 || ret == -FDT_ERR_NOTFOUND); - setup_args_progname(bootargs); - - if (initrd) { - /* environ is currently the only file in the initrd */ - char *env = malloc(initrd_size); - memcpy(env, initrd, initrd_size); - setup_env(env, initrd_size); - } -} diff --git a/lib/powerpc/smp.c b/lib/powerpc/smp.c deleted file mode 100644 index afe43617..00000000 --- a/lib/powerpc/smp.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Secondary cpu support - * - * Copyright 2016 Suraj Jitindar Singh, IBM. - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ - -#include -#include -#include -#include - -int nr_threads; - -struct secondary_entry_data { - secondary_entry_fn entry; - uint64_t r3; - int nr_started; -}; - -/* - * Start stopped thread cpu_id at entry - * Returns: <0 on failure to start stopped cpu - * 0 on success - * >0 on cpu not in stopped state - */ -int start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3) -{ - uint32_t query_token, start_token; - int outputs[1], ret; - - ret = rtas_token("query-cpu-stopped-state", &query_token); - assert(ret == 0); - ret = rtas_token("start-cpu", &start_token); - assert(ret == 0); - - ret = rtas_call(query_token, 1, 2, outputs, cpu_id); - if (ret) { - printf("query-cpu-stopped-state failed for cpu %d\n", cpu_id); - } else if (!outputs[0]) { /* cpu in stopped state */ - ret = rtas_call(start_token, 3, 1, NULL, cpu_id, entry, r3); - if (ret) - printf("failed to start cpu %d\n", cpu_id); - } else { /* cpu not in stopped state */ - ret = outputs[0]; - } - - return ret; -} - -/* - * Start all stopped threads (vcpus) on cpu_node - * Returns: Number of stopped cpus which were successfully started - */ -struct start_threads start_cpu(int cpu_node, secondary_entry_fn entry, - uint32_t r3) -{ - int len, i, nr_threads, nr_started = 0; - const struct fdt_property *prop; - u32 *threads; - - /* Get the id array of threads on this cpu_node */ - prop = fdt_get_property(dt_fdt(), cpu_node, - "ibm,ppc-interrupt-server#s", &len); - assert(prop); - - nr_threads = len >> 2; /* Divide by 4 since 4 bytes per thread */ - threads = (u32 *)prop->data; /* Array of valid ids */ - - for (i = 0; i < nr_threads; i++) { - if (!start_thread(fdt32_to_cpu(threads[i]), entry, r3)) - nr_started++; - } - - return (struct start_threads) { nr_threads, nr_started }; -} - -static void start_each_secondary(int fdtnode, u64 regval __unused, void *info) -{ - struct secondary_entry_data *datap = info; - struct start_threads ret = start_cpu(fdtnode, datap->entry, datap->r3); - - nr_threads += ret.nr_threads; - datap->nr_started += ret.nr_started; -} - -/* - * Start all stopped cpus on the guest at entry with register 3 set to r3 - * We expect that we come in with only one thread currently started - * Returns: TRUE on success - * FALSE on failure - */ -bool start_all_cpus(secondary_entry_fn entry, uint32_t r3) -{ - struct secondary_entry_data data = { entry, r3, 0 }; - int ret; - - ret = dt_for_each_cpu_node(start_each_secondary, &data); - assert(ret == 0); - - /* We expect that we come in with one thread already started */ - return data.nr_started == nr_threads - 1; -} diff --git a/lib/ppc64/.gitignore b/lib/ppc64/.gitignore deleted file mode 100644 index 84872bf1..00000000 --- a/lib/ppc64/.gitignore +++ /dev/null @@ -1 +0,0 @@ -asm-offsets.[hs] diff --git a/lib/ppc64/asm-offsets.c b/lib/ppc64/asm-offsets.c deleted file mode 100644 index 7843a20b..00000000 --- a/lib/ppc64/asm-offsets.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include - -int main(void) -{ - DEFINE(INT_FRAME_SIZE, STACK_INT_FRAME_SIZE); - - DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0])); - DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1])); - DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2])); - DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3])); - DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4])); - DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5])); - DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6])); - DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7])); - DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8])); - DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9])); - DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10])); - DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11])); - DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12])); - DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13])); - DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14])); - DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15])); - DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16])); - DEFINE(GPR17, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[17])); - DEFINE(GPR18, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[18])); - DEFINE(GPR19, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[19])); - DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20])); - DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21])); - DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22])); - DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23])); - DEFINE(GPR24, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[24])); - DEFINE(GPR25, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[25])); - DEFINE(GPR26, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[26])); - DEFINE(GPR27, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[27])); - DEFINE(GPR28, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[28])); - DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29])); - DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30])); - DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31])); - DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip)); - DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr)); - DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); - DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link)); - DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); - DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr)); - DEFINE(_TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); - return 0; -} diff --git a/lib/ppc64/asm/asm-offsets.h b/lib/ppc64/asm/asm-offsets.h deleted file mode 100644 index d370ee36..00000000 --- a/lib/ppc64/asm/asm-offsets.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/lib/ppc64/asm/barrier.h b/lib/ppc64/asm/barrier.h deleted file mode 100644 index 76f6efa7..00000000 --- a/lib/ppc64/asm/barrier.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _ASMPPC64_BARRIER_H_ -#define _ASMPPC64_BARRIER_H_ - -#define mb() asm volatile("sync":::"memory") -#define rmb() asm volatile("sync":::"memory") -#define wmb() asm volatile("sync":::"memory") - -#include -#endif diff --git a/lib/ppc64/asm/bitops.h b/lib/ppc64/asm/bitops.h deleted file mode 100644 index c93d64bb..00000000 --- a/lib/ppc64/asm/bitops.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _ASMPPC64_BITOPS_H_ -#define _ASMPPC64_BITOPS_H_ - -#ifndef _BITOPS_H_ -#error only can be included directly -#endif - -#define BITS_PER_LONG 64 - -#define HAVE_BUILTIN_FLS 1 - -#endif diff --git a/lib/ppc64/asm/handlers.h b/lib/ppc64/asm/handlers.h deleted file mode 100644 index 92e6fb24..00000000 --- a/lib/ppc64/asm/handlers.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../powerpc/asm/handlers.h" diff --git a/lib/ppc64/asm/hcall.h b/lib/ppc64/asm/hcall.h deleted file mode 100644 index daabaca5..00000000 --- a/lib/ppc64/asm/hcall.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../powerpc/asm/hcall.h" diff --git a/lib/ppc64/asm/io.h b/lib/ppc64/asm/io.h deleted file mode 100644 index 2b4dd2be..00000000 --- a/lib/ppc64/asm/io.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _ASMPPC64_IO_H_ -#define _ASMPPC64_IO_H_ - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define __cpu_is_be() (0) -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define __cpu_is_be() (1) -#else -#error Undefined byte order -#endif - -#define __iomem - -#include -#endif diff --git a/lib/ppc64/asm/page.h b/lib/ppc64/asm/page.h deleted file mode 100644 index 1a8b6271..00000000 --- a/lib/ppc64/asm/page.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/lib/ppc64/asm/ppc_asm.h b/lib/ppc64/asm/ppc_asm.h deleted file mode 100644 index e3929eee..00000000 --- a/lib/ppc64/asm/ppc_asm.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../powerpc/asm/ppc_asm.h" diff --git a/lib/ppc64/asm/processor.h b/lib/ppc64/asm/processor.h deleted file mode 100644 index 066a51a0..00000000 --- a/lib/ppc64/asm/processor.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../powerpc/asm/processor.h" diff --git a/lib/ppc64/asm/ptrace.h b/lib/ppc64/asm/ptrace.h deleted file mode 100644 index 076c9d9c..00000000 --- a/lib/ppc64/asm/ptrace.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _ASMPPC64_PTRACE_H_ -#define _ASMPPC64_PTRACE_H_ - -#define KERNEL_REDZONE_SIZE 288 -#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */ - -#ifndef __ASSEMBLY__ -struct pt_regs { - unsigned long gpr[32]; - unsigned long nip; - unsigned long msr; - unsigned long ctr; - unsigned long link; - unsigned long xer; - unsigned long ccr; - unsigned long trap; -}; - -#define STACK_INT_FRAME_SIZE (sizeof(struct pt_regs) + \ - STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE) - -#endif /* __ASSEMBLY__ */ - -#endif /* _ASMPPC64_PTRACE_H_ */ diff --git a/lib/ppc64/asm/rtas.h b/lib/ppc64/asm/rtas.h deleted file mode 100644 index fe77f635..00000000 --- a/lib/ppc64/asm/rtas.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../powerpc/asm/rtas.h" diff --git a/lib/ppc64/asm/setup.h b/lib/ppc64/asm/setup.h deleted file mode 100644 index 20192985..00000000 --- a/lib/ppc64/asm/setup.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../powerpc/asm/setup.h" diff --git a/lib/ppc64/asm/smp.h b/lib/ppc64/asm/smp.h deleted file mode 100644 index 67ced756..00000000 --- a/lib/ppc64/asm/smp.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../powerpc/asm/smp.h" diff --git a/lib/ppc64/asm/spinlock.h b/lib/ppc64/asm/spinlock.h deleted file mode 100644 index f59eed19..00000000 --- a/lib/ppc64/asm/spinlock.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASMPPC64_SPINLOCK_H_ -#define _ASMPPC64_SPINLOCK_H_ - -#include - -#endif /* _ASMPPC64_SPINLOCK_H_ */ diff --git a/lib/ppc64/asm/stack.h b/lib/ppc64/asm/stack.h deleted file mode 100644 index 9734bbb8..00000000 --- a/lib/ppc64/asm/stack.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _ASMPPC64_STACK_H_ -#define _ASMPPC64_STACK_H_ - -#ifndef _STACK_H_ -#error Do not directly include . Just use . -#endif - -#endif diff --git a/lib/printf.c b/lib/printf.c deleted file mode 100644 index 1269723e..00000000 --- a/lib/printf.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * libc printf and friends - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -#include "libcflat.h" - -#define BUFSZ 2000 - -typedef struct pstream { - char *buffer; - int remain; - int added; -} pstream_t; - -typedef struct strprops { - char pad; - int npad; - bool alternate; -} strprops_t; - -static void addchar(pstream_t *p, char c) -{ - if (p->remain) { - *p->buffer++ = c; - --p->remain; - } - ++p->added; -} - -static void print_str(pstream_t *p, const char *s, strprops_t props) -{ - const char *s_orig = s; - int npad = props.npad; - - if (npad > 0) { - npad -= strlen(s_orig); - while (npad > 0) { - addchar(p, props.pad); - --npad; - } - } - - while (*s) - addchar(p, *s++); - - if (npad < 0) { - props.pad = ' '; /* ignore '0' flag with '-' flag */ - npad += strlen(s_orig); - while (npad < 0) { - addchar(p, props.pad); - ++npad; - } - } -} - -static char digits[16] = "0123456789abcdef"; - -static void print_int(pstream_t *ps, long long n, int base, strprops_t props) -{ - char buf[sizeof(long) * 3 + 2], *p = buf; - int s = 0, i; - - if (n < 0) { - n = -n; - s = 1; - } - - while (n) { - *p++ = digits[n % base]; - n /= base; - } - - if (s) - *p++ = '-'; - - if (p == buf) - *p++ = '0'; - - for (i = 0; i < (p - buf) / 2; ++i) { - char tmp; - - tmp = buf[i]; - buf[i] = p[-1-i]; - p[-1-i] = tmp; - } - - *p = 0; - - print_str(ps, buf, props); -} - -static void print_unsigned(pstream_t *ps, unsigned long long n, int base, - strprops_t props) -{ - char buf[sizeof(long) * 3 + 3], *p = buf; - int i; - - while (n) { - *p++ = digits[n % base]; - n /= base; - } - - if (p == buf) - *p++ = '0'; - else if (props.alternate && base == 16) { - if (props.pad == '0') { - addchar(ps, '0'); - addchar(ps, 'x'); - - if (props.npad > 0) - props.npad = MAX(props.npad - 2, 0); - } else { - *p++ = 'x'; - *p++ = '0'; - } - } - - for (i = 0; i < (p - buf) / 2; ++i) { - char tmp; - - tmp = buf[i]; - buf[i] = p[-1-i]; - p[-1-i] = tmp; - } - - *p = 0; - - print_str(ps, buf, props); -} - -static int fmtnum(const char **fmt) -{ - const char *f = *fmt; - int len = 0, num; - - if (*f == '-') - ++f, ++len; - - while (*f >= '0' && *f <= '9') - ++f, ++len; - - num = atol(*fmt); - *fmt += len; - return num; -} - -int vsnprintf(char *buf, int size, const char *fmt, va_list va) -{ - pstream_t s; - - s.buffer = buf; - s.remain = size - 1; - s.added = 0; - while (*fmt) { - char f = *fmt++; - int nlong = 0; - strprops_t props; - memset(&props, 0, sizeof(props)); - props.pad = ' '; - - if (f != '%') { - addchar(&s, f); - continue; - } - morefmt: - f = *fmt++; - switch (f) { - case '%': - addchar(&s, '%'); - break; - case 'c': - addchar(&s, va_arg(va, int)); - break; - case '\0': - --fmt; - break; - case '#': - props.alternate = true; - goto morefmt; - case '0': - props.pad = '0'; - ++fmt; - /* fall through */ - case '1'...'9': - case '-': - --fmt; - props.npad = fmtnum(&fmt); - goto morefmt; - case 'l': - ++nlong; - goto morefmt; - case 't': - case 'z': - /* Here we only care that sizeof(size_t) == sizeof(long). - * On a 32-bit platform it doesn't matter that size_t is - * typedef'ed to int or long; va_arg will work either way. - * Same for ptrdiff_t (%td). - */ - nlong = 1; - goto morefmt; - case 'd': - switch (nlong) { - case 0: - print_int(&s, va_arg(va, int), 10, props); - break; - case 1: - print_int(&s, va_arg(va, long), 10, props); - break; - default: - print_int(&s, va_arg(va, long long), 10, props); - break; - } - break; - case 'u': - switch (nlong) { - case 0: - print_unsigned(&s, va_arg(va, unsigned), 10, props); - break; - case 1: - print_unsigned(&s, va_arg(va, unsigned long), 10, props); - break; - default: - print_unsigned(&s, va_arg(va, unsigned long long), 10, props); - break; - } - break; - case 'x': - switch (nlong) { - case 0: - print_unsigned(&s, va_arg(va, unsigned), 16, props); - break; - case 1: - print_unsigned(&s, va_arg(va, unsigned long), 16, props); - break; - default: - print_unsigned(&s, va_arg(va, unsigned long long), 16, props); - break; - } - break; - case 'p': - props.alternate = true; - print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props); - break; - case 's': - print_str(&s, va_arg(va, const char *), props); - break; - default: - addchar(&s, f); - break; - } - } - *s.buffer = 0; - return s.added; -} - - -int snprintf(char *buf, int size, const char *fmt, ...) -{ - va_list va; - int r; - - va_start(va, fmt); - r = vsnprintf(buf, size, fmt, va); - va_end(va); - return r; -} - -int vprintf(const char *fmt, va_list va) -{ - char buf[BUFSZ]; - int r; - - r = vsnprintf(buf, sizeof(buf), fmt, va); - puts(buf); - return r; -} - -int printf(const char *fmt, ...) -{ - va_list va; - char buf[BUFSZ]; - int r; - - va_start(va, fmt); - r = vsnprintf(buf, sizeof buf, fmt, va); - va_end(va); - puts(buf); - return r; -} - -void binstr(unsigned long x, char out[BINSTR_SZ]) -{ - int i; - char *c; - int n; - - n = sizeof(unsigned long) * 8; - i = 0; - c = &out[0]; - for (;;) { - *c++ = (x & (1ul << (n - i - 1))) ? '1' : '0'; - i++; - - if (i == n) { - *c = '\0'; - break; - } - if (i % 4 == 0) - *c++ = '\''; - } - assert(c + 1 - &out[0] == BINSTR_SZ); -} - -void print_binstr(unsigned long x) -{ - char out[BINSTR_SZ]; - binstr(x, out); - printf("%s", out); -} diff --git a/lib/report.c b/lib/report.c deleted file mode 100644 index 2255dc37..00000000 --- a/lib/report.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Test result reporting - * - * Copyright (c) Siemens AG, 2014 - * - * Authors: - * Jan Kiszka - * Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ - -#include "libcflat.h" -#include "asm/spinlock.h" - -static unsigned int tests, failures, xfailures, skipped; -static char prefixes[256]; -static struct spinlock lock; - -#define PREFIX_DELIMITER ": " - -void report_pass(void) -{ - spin_lock(&lock); - tests++; - spin_unlock(&lock); -} - -void report_prefix_pushf(const char *prefix_fmt, ...) -{ - va_list va; - unsigned int len; - int start; - - spin_lock(&lock); - - len = strlen(prefixes); - assert_msg(len < sizeof(prefixes), "%d >= %zu", len, sizeof(prefixes)); - start = len; - - va_start(va, prefix_fmt); - len += vsnprintf(&prefixes[len], sizeof(prefixes) - len, prefix_fmt, - va); - va_end(va); - assert_msg(len < sizeof(prefixes), "%d >= %zu", len, sizeof(prefixes)); - - assert_msg(!strstr(&prefixes[start], PREFIX_DELIMITER), - "Prefix \"%s\" contains delimiter \"" PREFIX_DELIMITER "\"", - &prefixes[start]); - - len += snprintf(&prefixes[len], sizeof(prefixes) - len, - PREFIX_DELIMITER); - assert_msg(len < sizeof(prefixes), "%d >= %zu", len, sizeof(prefixes)); - - spin_unlock(&lock); -} - -void report_prefix_push(const char *prefix) -{ - report_prefix_pushf("%s", prefix); -} - -void report_prefix_pop(void) -{ - char *p, *q; - - spin_lock(&lock); - - if (!*prefixes) { - spin_unlock(&lock); - return; - } - - for (p = prefixes, q = strstr(p, PREFIX_DELIMITER) + 2; - *q; - p = q, q = strstr(p, PREFIX_DELIMITER) + 2) - ; - *p = '\0'; - - spin_unlock(&lock); -} - -static void va_report(const char *msg_fmt, - bool pass, bool xfail, bool skip, va_list va) -{ - const char *prefix = skip ? "SKIP" - : xfail ? (pass ? "XPASS" : "XFAIL") - : (pass ? "PASS" : "FAIL"); - - spin_lock(&lock); - - tests++; - printf("%s: ", prefix); - puts(prefixes); - vprintf(msg_fmt, va); - puts("\n"); - if (skip) - skipped++; - else if (xfail && !pass) - xfailures++; - else if (xfail || !pass) - failures++; - - spin_unlock(&lock); -} - -void report(bool pass, const char *msg_fmt, ...) -{ - va_list va; - va_start(va, msg_fmt); - va_report(msg_fmt, pass, false, false, va); - va_end(va); -} - -void report_xfail(bool xfail, bool pass, const char *msg_fmt, ...) -{ - va_list va; - va_start(va, msg_fmt); - va_report(msg_fmt, pass, xfail, false, va); - va_end(va); -} - -void report_skip(const char *msg_fmt, ...) -{ - va_list va; - va_start(va, msg_fmt); - va_report(msg_fmt, false, false, true, va); - va_end(va); -} - -void report_info(const char *msg_fmt, ...) -{ - va_list va; - - spin_lock(&lock); - puts("INFO: "); - puts(prefixes); - va_start(va, msg_fmt); - vprintf(msg_fmt, va); - va_end(va); - puts("\n"); - spin_unlock(&lock); -} - -int report_summary(void) -{ - int ret; - spin_lock(&lock); - - printf("SUMMARY: %d tests", tests); - if (failures) - printf(", %d unexpected failures", failures); - if (xfailures) - printf(", %d expected failures", xfailures); - if (skipped) - printf(", %d skipped", skipped); - printf("\n"); - - if (tests == skipped) { - spin_unlock(&lock); - /* Blame AUTOTOOLS for using 77 for skipped test and QEMU for - * mangling error codes in a way that gets 77 if we ... */ - return 77 >> 1; - } - - ret = failures > 0 ? 1 : 0; - spin_unlock(&lock); - return ret; -} - -void report_abort(const char *msg_fmt, ...) -{ - va_list va; - - spin_lock(&lock); - puts("ABORT: "); - puts(prefixes); - va_start(va, msg_fmt); - vprintf(msg_fmt, va); - va_end(va); - puts("\n"); - spin_unlock(&lock); - report_summary(); - abort(); -} diff --git a/lib/s390x/.gitignore b/lib/s390x/.gitignore deleted file mode 100644 index 84872bf1..00000000 --- a/lib/s390x/.gitignore +++ /dev/null @@ -1 +0,0 @@ -asm-offsets.[hs] diff --git a/lib/s390x/asm-offsets.c b/lib/s390x/asm-offsets.c deleted file mode 100644 index 61d26587..00000000 --- a/lib/s390x/asm-offsets.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include - -int main(void) -{ - OFFSET(GEN_LC_EXT_INT_PARAM, lowcore, ext_int_param); - OFFSET(GEN_LC_CPU_ADDR, lowcore, cpu_addr); - OFFSET(GEN_LC_EXT_INT_CODE, lowcore, ext_int_code); - OFFSET(GEN_LC_SVC_INT_ID, lowcore, svc_int_id); - OFFSET(GEN_LC_SVC_INT_CODE, lowcore, svc_int_code); - OFFSET(GEN_LC_PGM_INT_ID, lowcore, pgm_int_id); - OFFSET(GEN_LC_PGM_INT_CODE, lowcore, pgm_int_code); - OFFSET(GEN_LC_DXC_VXC, lowcore, dxc_vxc); - OFFSET(GEN_LC_MON_CLASS_NB, lowcore, mon_class_nb); - OFFSET(GEN_LC_PER_CODE, lowcore, per_code); - OFFSET(GEN_LC_PER_ATMID, lowcore, per_atmid); - OFFSET(GEN_LC_PER_ADDR, lowcore, per_addr); - OFFSET(GEN_LC_EXC_ACC_ID, lowcore, exc_acc_id); - OFFSET(GEN_LC_PER_ACC_ID, lowcore, per_acc_id); - OFFSET(GEN_LC_OP_ACC_ID, lowcore, op_acc_id); - OFFSET(GEN_LC_ARCH_MODE_ID, lowcore, arch_mode_id); - OFFSET(GEN_LC_TRANS_EXC_ID, lowcore, trans_exc_id); - OFFSET(GEN_LC_MON_CODE, lowcore, mon_code); - OFFSET(GEN_LC_SUBSYS_ID_WORD, lowcore, subsys_id_word); - OFFSET(GEN_LC_IO_INT_PARAM, lowcore, io_int_param); - OFFSET(GEN_LC_IO_INT_WORD, lowcore, io_int_word); - OFFSET(GEN_LC_STFL, lowcore, stfl); - OFFSET(GEN_LC_MCCK_INT_CODE, lowcore, mcck_int_code); - OFFSET(GEN_LC_EXT_DAMAGE_CODE, lowcore, ext_damage_code); - OFFSET(GEN_LC_FAILING_STORAGE_ADDR, lowcore, failing_storage_addr); - OFFSET(GEN_LC_EMON_CA_ORIGIN, lowcore, emon_ca_origin); - OFFSET(GEN_LC_EMON_CA_SIZE, lowcore, emon_ca_size); - OFFSET(GEN_LC_EMON_EXC_COUNT, lowcore, emon_exc_count); - OFFSET(GEN_LC_BREAKING_EVENT_ADDR, lowcore, breaking_event_addr); - OFFSET(GEN_LC_RESTART_OLD_PSW, lowcore, restart_old_psw); - OFFSET(GEN_LC_EXT_OLD_PSW, lowcore, ext_old_psw); - OFFSET(GEN_LC_SVC_OLD_PSW, lowcore, svc_old_psw); - OFFSET(GEN_LC_PGM_OLD_PSW, lowcore, pgm_old_psw); - OFFSET(GEN_LC_MCCK_OLD_PSW, lowcore, mcck_old_psw); - OFFSET(GEN_LC_IO_OLD_PSW, lowcore, io_old_psw); - OFFSET(GEN_LC_RESTART_NEW_PSW, lowcore, restart_new_psw); - OFFSET(GEN_LC_EXT_NEW_PSW, lowcore, ext_new_psw); - OFFSET(GEN_LC_SVC_NEW_PSW, lowcore, svc_new_psw); - OFFSET(GEN_LC_PGM_NEW_PSW, lowcore, pgm_new_psw); - OFFSET(GEN_LC_MCCK_NEW_PSW, lowcore, mcck_new_psw); - OFFSET(GEN_LC_IO_NEW_PSW, lowcore, io_new_psw); - OFFSET(GEN_LC_SW_INT_GRS, lowcore, sw_int_grs); - OFFSET(GEN_LC_SW_INT_FPRS, lowcore, sw_int_fprs); - OFFSET(GEN_LC_SW_INT_FPC, lowcore, sw_int_fpc); - OFFSET(GEN_LC_SW_INT_CRS, lowcore, sw_int_crs); - OFFSET(GEN_LC_SW_INT_PSW, lowcore, sw_int_psw); - OFFSET(GEN_LC_MCCK_EXT_SA_ADDR, lowcore, mcck_ext_sa_addr); - OFFSET(GEN_LC_FPRS_SA, lowcore, fprs_sa); - OFFSET(GEN_LC_GRS_SA, lowcore, grs_sa); - OFFSET(GEN_LC_PSW_SA, lowcore, psw_sa); - OFFSET(GEN_LC_PREFIX_SA, lowcore, prefix_sa); - OFFSET(GEN_LC_FPC_SA, lowcore, fpc_sa); - OFFSET(GEN_LC_TOD_PR_SA, lowcore, tod_pr_sa); - OFFSET(GEN_LC_CPUTM_SA, lowcore, cputm_sa); - OFFSET(GEN_LC_CC_SA, lowcore, cc_sa); - OFFSET(GEN_LC_ARS_SA, lowcore, ars_sa); - OFFSET(GEN_LC_CRS_SA, lowcore, crs_sa); - OFFSET(GEN_LC_PGM_INT_TDB, lowcore, pgm_int_tdb); - - return 0; -} diff --git a/lib/s390x/asm/arch_def.h b/lib/s390x/asm/arch_def.h deleted file mode 100644 index 1b3bb0c1..00000000 --- a/lib/s390x/asm/arch_def.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _ASM_S390X_ARCH_DEF_H_ -#define _ASM_S390X_ARCH_DEF_H_ - -struct psw { - uint64_t mask; - uint64_t addr; -}; - -#define PSW_MASK_EXT 0x0100000000000000UL -#define PSW_MASK_DAT 0x0400000000000000UL -#define PSW_MASK_PSTATE 0x0001000000000000UL - -#define CR0_EXTM_SCLP 0x0000000000000200UL -#define CR0_EXTM_EXTC 0x0000000000002000UL -#define CR0_EXTM_EMGC 0x0000000000004000UL -#define CR0_EXTM_MASK 0x0000000000006200UL - -struct lowcore { - uint8_t pad_0x0000[0x0080 - 0x0000]; /* 0x0000 */ - uint32_t ext_int_param; /* 0x0080 */ - uint16_t cpu_addr; /* 0x0084 */ - uint16_t ext_int_code; /* 0x0086 */ - uint16_t svc_int_id; /* 0x0088 */ - uint16_t svc_int_code; /* 0x008a */ - uint16_t pgm_int_id; /* 0x008c */ - uint16_t pgm_int_code; /* 0x008e */ - uint32_t dxc_vxc; /* 0x0090 */ - uint16_t mon_class_nb; /* 0x0094 */ - uint8_t per_code; /* 0x0096 */ - uint8_t per_atmid; /* 0x0097 */ - uint64_t per_addr; /* 0x0098 */ - uint8_t exc_acc_id; /* 0x00a0 */ - uint8_t per_acc_id; /* 0x00a1 */ - uint8_t op_acc_id; /* 0x00a2 */ - uint8_t arch_mode_id; /* 0x00a3 */ - uint8_t pad_0x00a4[0x00a8 - 0x00a4]; /* 0x00a4 */ - uint64_t trans_exc_id; /* 0x00a8 */ - uint64_t mon_code; /* 0x00b0 */ - uint32_t subsys_id_word; /* 0x00b8 */ - uint32_t io_int_param; /* 0x00bc */ - uint32_t io_int_word; /* 0x00c0 */ - uint8_t pad_0x00c4[0x00c8 - 0x00c4]; /* 0x00c4 */ - uint32_t stfl; /* 0x00c8 */ - uint8_t pad_0x00cc[0x00e8 - 0x00cc]; /* 0x00cc */ - uint64_t mcck_int_code; /* 0x00e8 */ - uint8_t pad_0x00f0[0x00f4 - 0x00f0]; /* 0x00f0 */ - uint32_t ext_damage_code; /* 0x00f4 */ - uint64_t failing_storage_addr; /* 0x00f8 */ - uint64_t emon_ca_origin; /* 0x0100 */ - uint32_t emon_ca_size; /* 0x0108 */ - uint32_t emon_exc_count; /* 0x010c */ - uint64_t breaking_event_addr; /* 0x0110 */ - uint8_t pad_0x0118[0x0120 - 0x0118]; /* 0x0118 */ - struct psw restart_old_psw; /* 0x0120 */ - struct psw ext_old_psw; /* 0x0130 */ - struct psw svc_old_psw; /* 0x0140 */ - struct psw pgm_old_psw; /* 0x0150 */ - struct psw mcck_old_psw; /* 0x0160 */ - struct psw io_old_psw; /* 0x0170 */ - uint8_t pad_0x0180[0x01a0 - 0x0180]; /* 0x0180 */ - struct psw restart_new_psw; /* 0x01a0 */ - struct psw ext_new_psw; /* 0x01b0 */ - struct psw svc_new_psw; /* 0x01c0 */ - struct psw pgm_new_psw; /* 0x01d0 */ - struct psw mcck_new_psw; /* 0x01e0 */ - struct psw io_new_psw; /* 0x01f0 */ - /* sw definition: save area for registers in interrupt handlers */ - uint64_t sw_int_grs[16]; /* 0x0200 */ - uint64_t sw_int_fprs[16]; /* 0x0280 */ - uint32_t sw_int_fpc; /* 0x0300 */ - uint8_t pad_0x0304[0x0308 - 0x0304]; /* 0x0304 */ - uint64_t sw_int_crs[16]; /* 0x0308 */ - struct psw sw_int_psw; /* 0x0388 */ - uint8_t pad_0x0310[0x11b0 - 0x0398]; /* 0x0398 */ - uint64_t mcck_ext_sa_addr; /* 0x11b0 */ - uint8_t pad_0x11b8[0x1200 - 0x11b8]; /* 0x11b8 */ - uint64_t fprs_sa[16]; /* 0x1200 */ - uint64_t grs_sa[16]; /* 0x1280 */ - struct psw psw_sa; /* 0x1300 */ - uint8_t pad_0x1310[0x1318 - 0x1310]; /* 0x1310 */ - uint32_t prefix_sa; /* 0x1318 */ - uint32_t fpc_sa; /* 0x131c */ - uint8_t pad_0x1320[0x1324 - 0x1320]; /* 0x1320 */ - uint32_t tod_pr_sa; /* 0x1324 */ - uint64_t cputm_sa; /* 0x1328 */ - uint64_t cc_sa; /* 0x1330 */ - uint8_t pad_0x1338[0x1340 - 0x1338]; /* 0x1338 */ - uint32_t ars_sa[16]; /* 0x1340 */ - uint64_t crs_sa[16]; /* 0x1380 */ - uint8_t pad_0x1400[0x1800 - 0x1400]; /* 0x1400 */ - uint8_t pgm_int_tdb[0x1900 - 0x1800]; /* 0x1800 */ -} __attribute__ ((__packed__)); -_Static_assert(sizeof(struct lowcore) == 0x1900, "Lowcore size"); - -#define PGM_INT_CODE_OPERATION 0x01 -#define PGM_INT_CODE_PRIVILEGED_OPERATION 0x02 -#define PGM_INT_CODE_EXECUTE 0x03 -#define PGM_INT_CODE_PROTECTION 0x04 -#define PGM_INT_CODE_ADDRESSING 0x05 -#define PGM_INT_CODE_SPECIFICATION 0x06 -#define PGM_INT_CODE_DATA 0x07 -#define PGM_INT_CODE_FIXED_POINT_OVERFLOW 0x08 -#define PGM_INT_CODE_FIXED_POINT_DIVIDE 0x09 -#define PGM_INT_CODE_DECIMAL_OVERFLOW 0x0a -#define PGM_INT_CODE_DECIMAL_DIVIDE 0x0b -#define PGM_INT_CODE_HFP_EXPONENT_OVERFLOW 0x0c -#define PGM_INT_CODE_HFP_EXPONENT_UNDERFLOW 0x0d -#define PGM_INT_CODE_HFP_SIGNIFICANCE 0x0e -#define PGM_INT_CODE_HFP_DIVIDE 0x0f -#define PGM_INT_CODE_SEGMENT_TRANSLATION 0x10 -#define PGM_INT_CODE_PAGE_TRANSLATION 0x11 -#define PGM_INT_CODE_TRANSLATION_SPEC 0x12 -#define PGM_INT_CODE_SPECIAL_OPERATION 0x13 -#define PGM_INT_CODE_OPERAND 0x15 -#define PGM_INT_CODE_TRACE_TABLE 0x16 -#define PGM_INT_CODE_VECTOR_PROCESSING 0x1b -#define PGM_INT_CODE_SPACE_SWITCH_EVENT 0x1c -#define PGM_INT_CODE_HFP_SQUARE_ROOT 0x1d -#define PGM_INT_CODE_PC_TRANSLATION_SPEC 0x1f -#define PGM_INT_CODE_AFX_TRANSLATION 0x20 -#define PGM_INT_CODE_ASX_TRANSLATION 0x21 -#define PGM_INT_CODE_LX_TRANSLATION 0x22 -#define PGM_INT_CODE_EX_TRANSLATION 0x23 -#define PGM_INT_CODE_PRIMARY_AUTHORITY 0x24 -#define PGM_INT_CODE_SECONDARY_AUTHORITY 0x25 -#define PGM_INT_CODE_LFX_TRANSLATION 0x26 -#define PGM_INT_CODE_LSX_TRANSLATION 0x27 -#define PGM_INT_CODE_ALET_SPECIFICATION 0x28 -#define PGM_INT_CODE_ALEN_TRANSLATION 0x29 -#define PGM_INT_CODE_ALE_SEQUENCE 0x2a -#define PGM_INT_CODE_ASTE_VALIDITY 0x2b -#define PGM_INT_CODE_ASTE_SEQUENCE 0x2c -#define PGM_INT_CODE_EXTENDED_AUTHORITY 0x2d -#define PGM_INT_CODE_LSTE_SEQUENCE 0x2e -#define PGM_INT_CODE_ASTE_INSTANCE 0x2f -#define PGM_INT_CODE_STACK_FULL 0x30 -#define PGM_INT_CODE_STACK_EMPTY 0x31 -#define PGM_INT_CODE_STACK_SPECIFICATION 0x32 -#define PGM_INT_CODE_STACK_TYPE 0x33 -#define PGM_INT_CODE_STACK_OPERATION 0x34 -#define PGM_INT_CODE_ASCE_TYPE 0x38 -#define PGM_INT_CODE_REGION_FIRST_TRANS 0x39 -#define PGM_INT_CODE_REGION_SECOND_TRANS 0x3a -#define PGM_INT_CODE_REGION_THIRD_TRANS 0x3b -#define PGM_INT_CODE_MONITOR_EVENT 0x40 -#define PGM_INT_CODE_PER 0x80 -#define PGM_INT_CODE_CRYPTO_OPERATION 0x119 -#define PGM_INT_CODE_TX_ABORTED_EVENT 0x200 - -struct cpuid { - uint64_t version : 8; - uint64_t id : 24; - uint64_t type : 16; - uint64_t format : 1; - uint64_t reserved : 15; -}; - -static inline unsigned short stap(void) -{ - unsigned short cpu_address; - - asm volatile("stap %0" : "=Q" (cpu_address)); - return cpu_address; -} - -static inline int tprot(unsigned long addr) -{ - int cc; - - asm volatile( - " tprot 0(%1),0\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc) : "a" (addr) : "cc"); - return cc; -} - -static inline void lctlg(int cr, uint64_t value) -{ - asm volatile( - " lctlg %1,%1,%0\n" - : : "Q" (value), "i" (cr)); -} - -static inline uint64_t stctg(int cr) -{ - uint64_t value; - - asm volatile( - " stctg %1,%1,%0\n" - : "=Q" (value) : "i" (cr) : "memory"); - return value; -} - -static inline void ctl_set_bit(int cr, unsigned int bit) -{ - uint64_t reg; - - reg = stctg(cr); - reg |= 1UL << bit; - lctlg(cr, reg); -} - -static inline void ctl_clear_bit(int cr, unsigned int bit) -{ - uint64_t reg; - - reg = stctg(cr); - reg &= ~(1UL << bit); - lctlg(cr, reg); -} - -static inline uint64_t extract_psw_mask(void) -{ - uint32_t mask_upper = 0, mask_lower = 0; - - asm volatile( - " epsw %0,%1\n" - : "+r" (mask_upper), "+r" (mask_lower) : : ); - - return (uint64_t) mask_upper << 32 | mask_lower; -} - -static inline void load_psw_mask(uint64_t mask) -{ - struct psw psw = { - .mask = mask, - .addr = 0, - }; - uint64_t tmp = 0; - - asm volatile( - " larl %0,0f\n" - " stg %0,8(%1)\n" - " lpswe 0(%1)\n" - "0:\n" - : "+r" (tmp) : "a" (&psw) : "memory", "cc" ); -} - -static inline void enter_pstate(void) -{ - uint64_t mask; - - mask = extract_psw_mask(); - mask |= PSW_MASK_PSTATE; - load_psw_mask(mask); -} - -static inline int stsi(void *addr, int fc, int sel1, int sel2) -{ - register int r0 asm("0") = (fc << 28) | sel1; - register int r1 asm("1") = sel2; - int cc; - - asm volatile( - "stsi 0(%3)\n" - "ipm %[cc]\n" - "srl %[cc],28\n" - : "+d" (r0), [cc] "=d" (cc) - : "d" (r1), "a" (addr) - : "cc", "memory"); - return cc; -} - -static inline int servc(uint32_t command, unsigned long sccb) -{ - int cc; - - asm volatile( - " .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */ - " ipm %0\n" - " srl %0,28" - : "=&d" (cc) : "d" (command), "a" (sccb) - : "cc", "memory"); - return cc; -} - -static inline void set_prefix(uint32_t new_prefix) -{ - asm volatile(" spx %0" : : "Q" (new_prefix) : "memory"); -} - -static inline uint32_t get_prefix(void) -{ - uint32_t current_prefix; - - asm volatile(" stpx %0" : "=Q" (current_prefix)); - return current_prefix; -} - -#endif diff --git a/lib/s390x/asm/asm-offsets.h b/lib/s390x/asm/asm-offsets.h deleted file mode 100644 index a6d7af89..00000000 --- a/lib/s390x/asm/asm-offsets.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include diff --git a/lib/s390x/asm/barrier.h b/lib/s390x/asm/barrier.h deleted file mode 100644 index d862e78f..00000000 --- a/lib/s390x/asm/barrier.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * Thomas Huth - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _ASM_S390X_BARRIER_H_ -#define _ASM_S390X_BARRIER_H_ - -#include - -#endif diff --git a/lib/s390x/asm/bitops.h b/lib/s390x/asm/bitops.h deleted file mode 100644 index e7cdda92..00000000 --- a/lib/s390x/asm/bitops.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _ASMS390X_BITOPS_H_ -#define _ASMS390X_BITOPS_H_ - -#ifndef _BITOPS_H_ -#error only can be included directly -#endif - -#define BITS_PER_LONG 64 - -#endif diff --git a/lib/s390x/asm/cpacf.h b/lib/s390x/asm/cpacf.h deleted file mode 100644 index ae2ec53b..00000000 --- a/lib/s390x/asm/cpacf.h +++ /dev/null @@ -1,472 +0,0 @@ -/* - * CP Assist for Cryptographic Functions (CPACF) - * - * Copyright IBM Corp. 2003, 2016 - * Author(s): Thomas Spatzier - * Jan Glauber - * Harald Freudenberger (freude@de.ibm.com) - * Martin Schwidefsky - */ -#ifndef _ASM_S390_CPACF_H -#define _ASM_S390_CPACF_H - -#include - -/* - * Instruction opcodes for the CPACF instructions - */ -#define CPACF_KMAC 0xb91e /* MSA */ -#define CPACF_KM 0xb92e /* MSA */ -#define CPACF_KMC 0xb92f /* MSA */ -#define CPACF_KIMD 0xb93e /* MSA */ -#define CPACF_KLMD 0xb93f /* MSA */ -#define CPACF_PCKMO 0xb928 /* MSA3 */ -#define CPACF_KMF 0xb92a /* MSA4 */ -#define CPACF_KMO 0xb92b /* MSA4 */ -#define CPACF_PCC 0xb92c /* MSA4 */ -#define CPACF_KMCTR 0xb92d /* MSA4 */ -#define CPACF_PRNO 0xb93c /* MSA5 */ -#define CPACF_KMA 0xb929 /* MSA8 */ - -/* - * En/decryption modifier bits - */ -#define CPACF_ENCRYPT 0x00 -#define CPACF_DECRYPT 0x80 - -/* - * Function codes for the KM (CIPHER MESSAGE) instruction - */ -#define CPACF_KM_QUERY 0x00 -#define CPACF_KM_DEA 0x01 -#define CPACF_KM_TDEA_128 0x02 -#define CPACF_KM_TDEA_192 0x03 -#define CPACF_KM_AES_128 0x12 -#define CPACF_KM_AES_192 0x13 -#define CPACF_KM_AES_256 0x14 -#define CPACF_KM_PAES_128 0x1a -#define CPACF_KM_PAES_192 0x1b -#define CPACF_KM_PAES_256 0x1c -#define CPACF_KM_XTS_128 0x32 -#define CPACF_KM_XTS_256 0x34 -#define CPACF_KM_PXTS_128 0x3a -#define CPACF_KM_PXTS_256 0x3c - -/* - * Function codes for the KMC (CIPHER MESSAGE WITH CHAINING) - * instruction - */ -#define CPACF_KMC_QUERY 0x00 -#define CPACF_KMC_DEA 0x01 -#define CPACF_KMC_TDEA_128 0x02 -#define CPACF_KMC_TDEA_192 0x03 -#define CPACF_KMC_AES_128 0x12 -#define CPACF_KMC_AES_192 0x13 -#define CPACF_KMC_AES_256 0x14 -#define CPACF_KMC_PAES_128 0x1a -#define CPACF_KMC_PAES_192 0x1b -#define CPACF_KMC_PAES_256 0x1c -#define CPACF_KMC_PRNG 0x43 - -/* - * Function codes for the KMCTR (CIPHER MESSAGE WITH COUNTER) - * instruction - */ -#define CPACF_KMCTR_QUERY 0x00 -#define CPACF_KMCTR_DEA 0x01 -#define CPACF_KMCTR_TDEA_128 0x02 -#define CPACF_KMCTR_TDEA_192 0x03 -#define CPACF_KMCTR_AES_128 0x12 -#define CPACF_KMCTR_AES_192 0x13 -#define CPACF_KMCTR_AES_256 0x14 -#define CPACF_KMCTR_PAES_128 0x1a -#define CPACF_KMCTR_PAES_192 0x1b -#define CPACF_KMCTR_PAES_256 0x1c - -/* - * Function codes for the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) - * instruction - */ -#define CPACF_KIMD_QUERY 0x00 -#define CPACF_KIMD_SHA_1 0x01 -#define CPACF_KIMD_SHA_256 0x02 -#define CPACF_KIMD_SHA_512 0x03 -#define CPACF_KIMD_GHASH 0x41 - -/* - * Function codes for the KLMD (COMPUTE LAST MESSAGE DIGEST) - * instruction - */ -#define CPACF_KLMD_QUERY 0x00 -#define CPACF_KLMD_SHA_1 0x01 -#define CPACF_KLMD_SHA_256 0x02 -#define CPACF_KLMD_SHA_512 0x03 - -/* - * function codes for the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) - * instruction - */ -#define CPACF_KMAC_QUERY 0x00 -#define CPACF_KMAC_DEA 0x01 -#define CPACF_KMAC_TDEA_128 0x02 -#define CPACF_KMAC_TDEA_192 0x03 - -/* - * Function codes for the PCKMO (PERFORM CRYPTOGRAPHIC KEY MANAGEMENT) - * instruction - */ -#define CPACF_PCKMO_QUERY 0x00 -#define CPACF_PCKMO_ENC_DES_KEY 0x01 -#define CPACF_PCKMO_ENC_TDES_128_KEY 0x02 -#define CPACF_PCKMO_ENC_TDES_192_KEY 0x03 -#define CPACF_PCKMO_ENC_AES_128_KEY 0x12 -#define CPACF_PCKMO_ENC_AES_192_KEY 0x13 -#define CPACF_PCKMO_ENC_AES_256_KEY 0x14 - -/* - * Function codes for the PRNO (PERFORM RANDOM NUMBER OPERATION) - * instruction - */ -#define CPACF_PRNO_QUERY 0x00 -#define CPACF_PRNO_SHA512_DRNG_GEN 0x03 -#define CPACF_PRNO_SHA512_DRNG_SEED 0x83 -#define CPACF_PRNO_TRNG_Q_R2C_RATIO 0x70 -#define CPACF_PRNO_TRNG 0x72 - -typedef struct { unsigned char bytes[16]; } cpacf_mask_t; - -/** - * cpacf_query() - check if a specific CPACF function is available - * @opcode: the opcode of the crypto instruction - * @func: the function code to test for - * - * Executes the query function for the given crypto instruction @opcode - * and checks if @func is available - * - * Returns 1 if @func is available for @opcode, 0 otherwise - */ -static inline void __cpacf_query(unsigned int opcode, cpacf_mask_t *mask) -{ - register unsigned long r0 asm("0") = 0; /* query function */ - register unsigned long r1 asm("1") = (unsigned long) mask; - - asm volatile( - " spm 0\n" /* pckmo doesn't change the cc */ - /* Parameter regs are ignored, but must be nonzero and unique */ - "0: .insn rrf,%[opc] << 16,2,4,6,0\n" - " brc 1,0b\n" /* handle partial completion */ - : "=m" (*mask) - : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (opcode) - : "cc"); -} - -static inline int __cpacf_check_opcode(unsigned int opcode) -{ - switch (opcode) { - case CPACF_KMAC: - case CPACF_KM: - case CPACF_KMC: - case CPACF_KIMD: - case CPACF_KLMD: - return test_facility(17); /* check for MSA */ - case CPACF_PCKMO: - return test_facility(76); /* check for MSA3 */ - case CPACF_KMF: - case CPACF_KMO: - case CPACF_PCC: - case CPACF_KMCTR: - return test_facility(77); /* check for MSA4 */ - case CPACF_PRNO: - return test_facility(57); /* check for MSA5 */ - default: - return 0; - } -} - -static inline int cpacf_query(unsigned int opcode, cpacf_mask_t *mask) -{ - if (__cpacf_check_opcode(opcode)) { - __cpacf_query(opcode, mask); - return 1; - } - memset(mask, 0, sizeof(*mask)); - return 0; -} - -static inline int cpacf_test_func(cpacf_mask_t *mask, unsigned int func) -{ - return (mask->bytes[func >> 3] & (0x80 >> (func & 7))) != 0; -} - -static inline int cpacf_query_func(unsigned int opcode, unsigned int func) -{ - cpacf_mask_t mask; - - if (cpacf_query(opcode, &mask)) - return cpacf_test_func(&mask, func); - return 0; -} - -/** - * cpacf_km() - executes the KM (CIPHER MESSAGE) instruction - * @func: the function code passed to KM; see CPACF_KM_xxx defines - * @param: address of parameter block; see POP for details on each func - * @dest: address of destination memory area - * @src: address of source memory area - * @src_len: length of src operand in bytes - * - * Returns 0 for the query func, number of processed bytes for - * encryption/decryption funcs - */ -static inline int cpacf_km(unsigned long func, void *param, - u8 *dest, const u8 *src, long src_len) -{ - register unsigned long r0 asm("0") = (unsigned long) func; - register unsigned long r1 asm("1") = (unsigned long) param; - register unsigned long r2 asm("2") = (unsigned long) src; - register unsigned long r3 asm("3") = (unsigned long) src_len; - register unsigned long r4 asm("4") = (unsigned long) dest; - - asm volatile( - "0: .insn rre,%[opc] << 16,%[dst],%[src]\n" - " brc 1,0b\n" /* handle partial completion */ - : [src] "+a" (r2), [len] "+d" (r3), [dst] "+a" (r4) - : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KM) - : "cc", "memory"); - - return src_len - r3; -} - -/** - * cpacf_kmc() - executes the KMC (CIPHER MESSAGE WITH CHAINING) instruction - * @func: the function code passed to KM; see CPACF_KMC_xxx defines - * @param: address of parameter block; see POP for details on each func - * @dest: address of destination memory area - * @src: address of source memory area - * @src_len: length of src operand in bytes - * - * Returns 0 for the query func, number of processed bytes for - * encryption/decryption funcs - */ -static inline int cpacf_kmc(unsigned long func, void *param, - u8 *dest, const u8 *src, long src_len) -{ - register unsigned long r0 asm("0") = (unsigned long) func; - register unsigned long r1 asm("1") = (unsigned long) param; - register unsigned long r2 asm("2") = (unsigned long) src; - register unsigned long r3 asm("3") = (unsigned long) src_len; - register unsigned long r4 asm("4") = (unsigned long) dest; - - asm volatile( - "0: .insn rre,%[opc] << 16,%[dst],%[src]\n" - " brc 1,0b\n" /* handle partial completion */ - : [src] "+a" (r2), [len] "+d" (r3), [dst] "+a" (r4) - : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KMC) - : "cc", "memory"); - - return src_len - r3; -} - -/** - * cpacf_kimd() - executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) - * instruction - * @func: the function code passed to KM; see CPACF_KIMD_xxx defines - * @param: address of parameter block; see POP for details on each func - * @src: address of source memory area - * @src_len: length of src operand in bytes - */ -static inline void cpacf_kimd(unsigned long func, void *param, - const u8 *src, long src_len) -{ - register unsigned long r0 asm("0") = (unsigned long) func; - register unsigned long r1 asm("1") = (unsigned long) param; - register unsigned long r2 asm("2") = (unsigned long) src; - register unsigned long r3 asm("3") = (unsigned long) src_len; - - asm volatile( - "0: .insn rre,%[opc] << 16,0,%[src]\n" - " brc 1,0b\n" /* handle partial completion */ - : [src] "+a" (r2), [len] "+d" (r3) - : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KIMD) - : "cc", "memory"); -} - -/** - * cpacf_klmd() - executes the KLMD (COMPUTE LAST MESSAGE DIGEST) instruction - * @func: the function code passed to KM; see CPACF_KLMD_xxx defines - * @param: address of parameter block; see POP for details on each func - * @src: address of source memory area - * @src_len: length of src operand in bytes - */ -static inline void cpacf_klmd(unsigned long func, void *param, - const u8 *src, long src_len) -{ - register unsigned long r0 asm("0") = (unsigned long) func; - register unsigned long r1 asm("1") = (unsigned long) param; - register unsigned long r2 asm("2") = (unsigned long) src; - register unsigned long r3 asm("3") = (unsigned long) src_len; - - asm volatile( - "0: .insn rre,%[opc] << 16,0,%[src]\n" - " brc 1,0b\n" /* handle partial completion */ - : [src] "+a" (r2), [len] "+d" (r3) - : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KLMD) - : "cc", "memory"); -} - -/** - * cpacf_kmac() - executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) - * instruction - * @func: the function code passed to KM; see CPACF_KMAC_xxx defines - * @param: address of parameter block; see POP for details on each func - * @src: address of source memory area - * @src_len: length of src operand in bytes - * - * Returns 0 for the query func, number of processed bytes for digest funcs - */ -static inline int cpacf_kmac(unsigned long func, void *param, - const u8 *src, long src_len) -{ - register unsigned long r0 asm("0") = (unsigned long) func; - register unsigned long r1 asm("1") = (unsigned long) param; - register unsigned long r2 asm("2") = (unsigned long) src; - register unsigned long r3 asm("3") = (unsigned long) src_len; - - asm volatile( - "0: .insn rre,%[opc] << 16,0,%[src]\n" - " brc 1,0b\n" /* handle partial completion */ - : [src] "+a" (r2), [len] "+d" (r3) - : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KMAC) - : "cc", "memory"); - - return src_len - r3; -} - -/** - * cpacf_kmctr() - executes the KMCTR (CIPHER MESSAGE WITH COUNTER) instruction - * @func: the function code passed to KMCTR; see CPACF_KMCTR_xxx defines - * @param: address of parameter block; see POP for details on each func - * @dest: address of destination memory area - * @src: address of source memory area - * @src_len: length of src operand in bytes - * @counter: address of counter value - * - * Returns 0 for the query func, number of processed bytes for - * encryption/decryption funcs - */ -static inline int cpacf_kmctr(unsigned long func, void *param, u8 *dest, - const u8 *src, long src_len, u8 *counter) -{ - register unsigned long r0 asm("0") = (unsigned long) func; - register unsigned long r1 asm("1") = (unsigned long) param; - register unsigned long r2 asm("2") = (unsigned long) src; - register unsigned long r3 asm("3") = (unsigned long) src_len; - register unsigned long r4 asm("4") = (unsigned long) dest; - register unsigned long r6 asm("6") = (unsigned long) counter; - - asm volatile( - "0: .insn rrf,%[opc] << 16,%[dst],%[src],%[ctr],0\n" - " brc 1,0b\n" /* handle partial completion */ - : [src] "+a" (r2), [len] "+d" (r3), - [dst] "+a" (r4), [ctr] "+a" (r6) - : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_KMCTR) - : "cc", "memory"); - - return src_len - r3; -} - -/** - * cpacf_prno() - executes the PRNO (PERFORM RANDOM NUMBER OPERATION) - * instruction - * @func: the function code passed to PRNO; see CPACF_PRNO_xxx defines - * @param: address of parameter block; see POP for details on each func - * @dest: address of destination memory area - * @dest_len: size of destination memory area in bytes - * @seed: address of seed data - * @seed_len: size of seed data in bytes - */ -static inline void cpacf_prno(unsigned long func, void *param, - u8 *dest, unsigned long dest_len, - const u8 *seed, unsigned long seed_len) -{ - register unsigned long r0 asm("0") = (unsigned long) func; - register unsigned long r1 asm("1") = (unsigned long) param; - register unsigned long r2 asm("2") = (unsigned long) dest; - register unsigned long r3 asm("3") = (unsigned long) dest_len; - register unsigned long r4 asm("4") = (unsigned long) seed; - register unsigned long r5 asm("5") = (unsigned long) seed_len; - - asm volatile ( - "0: .insn rre,%[opc] << 16,%[dst],%[seed]\n" - " brc 1,0b\n" /* handle partial completion */ - : [dst] "+a" (r2), [dlen] "+d" (r3) - : [fc] "d" (r0), [pba] "a" (r1), - [seed] "a" (r4), [slen] "d" (r5), [opc] "i" (CPACF_PRNO) - : "cc", "memory"); -} - -/** - * cpacf_trng() - executes the TRNG subfunction of the PRNO instruction - * @ucbuf: buffer for unconditioned data - * @ucbuf_len: amount of unconditioned data to fetch in bytes - * @cbuf: buffer for conditioned data - * @cbuf_len: amount of conditioned data to fetch in bytes - */ -static inline void cpacf_trng(u8 *ucbuf, unsigned long ucbuf_len, - u8 *cbuf, unsigned long cbuf_len) -{ - register unsigned long r0 asm("0") = (unsigned long) CPACF_PRNO_TRNG; - register unsigned long r2 asm("2") = (unsigned long) ucbuf; - register unsigned long r3 asm("3") = (unsigned long) ucbuf_len; - register unsigned long r4 asm("4") = (unsigned long) cbuf; - register unsigned long r5 asm("5") = (unsigned long) cbuf_len; - - asm volatile ( - "0: .insn rre,%[opc] << 16,%[ucbuf],%[cbuf]\n" - " brc 1,0b\n" /* handle partial completion */ - : [ucbuf] "+a" (r2), [ucbuflen] "+d" (r3), - [cbuf] "+a" (r4), [cbuflen] "+d" (r5) - : [fc] "d" (r0), [opc] "i" (CPACF_PRNO) - : "cc", "memory"); -} - -/** - * cpacf_pcc() - executes the PCC (PERFORM CRYPTOGRAPHIC COMPUTATION) - * instruction - * @func: the function code passed to PCC; see CPACF_KM_xxx defines - * @param: address of parameter block; see POP for details on each func - */ -static inline void cpacf_pcc(unsigned long func, void *param) -{ - register unsigned long r0 asm("0") = (unsigned long) func; - register unsigned long r1 asm("1") = (unsigned long) param; - - asm volatile( - "0: .insn rre,%[opc] << 16,0,0\n" /* PCC opcode */ - " brc 1,0b\n" /* handle partial completion */ - : - : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_PCC) - : "cc", "memory"); -} - -/** - * cpacf_pckmo() - executes the PCKMO (PERFORM CRYPTOGRAPHIC KEY - * MANAGEMENT) instruction - * @func: the function code passed to PCKMO; see CPACF_PCKMO_xxx defines - * @param: address of parameter block; see POP for details on each func - * - * Returns 0. - */ -static inline void cpacf_pckmo(long func, void *param) -{ - register unsigned long r0 asm("0") = (unsigned long) func; - register unsigned long r1 asm("1") = (unsigned long) param; - - asm volatile( - " .insn rre,%[opc] << 16,0,0\n" /* PCKMO opcode */ - : - : [fc] "d" (r0), [pba] "a" (r1), [opc] "i" (CPACF_PCKMO) - : "cc", "memory"); -} - -#endif /* _ASM_S390_CPACF_H */ diff --git a/lib/s390x/asm/facility.h b/lib/s390x/asm/facility.h deleted file mode 100644 index def27057..00000000 --- a/lib/s390x/asm/facility.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _ASM_S390X_FACILITY_H_ -#define _ASM_S390X_FACILITY_H_ - -#include -#include -#include - -#define NB_STFL_DOUBLEWORDS 32 -extern uint64_t stfl_doublewords[]; - -static inline bool test_facility(int nr) -{ - return stfl_doublewords[nr / 64] & (0x8000000000000000UL >> (nr % 64)); -} - -static inline void stfl(void) -{ - asm volatile(" stfl 0(0)\n" : : : "memory"); -} - -static inline void stfle(uint64_t *fac, unsigned int nb_doublewords) -{ - register unsigned long r0 asm("0") = nb_doublewords - 1; - - asm volatile(" .insn s,0xb2b00000,0(%1)\n" - : "+d" (r0) : "a" (fac) : "memory", "cc"); -} - -static inline void setup_facilities(void) -{ - struct lowcore *lc = NULL; - - stfl(); - memcpy(stfl_doublewords, &lc->stfl, sizeof(lc->stfl)); - if (test_facility(7)) - stfle(stfl_doublewords, NB_STFL_DOUBLEWORDS); -} - -#endif diff --git a/lib/s390x/asm/float.h b/lib/s390x/asm/float.h deleted file mode 100644 index f61fa626..00000000 --- a/lib/s390x/asm/float.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2018 Red Hat Inc - * - * Authors: - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _ASM_S390X_FLOAT_H_ -#define _ASM_S390X_FLOAT_H_ - -static inline void set_fpc(uint32_t fpc) -{ - asm volatile(" lfpc %0\n" : : "m"(fpc) ); -} - -static inline uint32_t get_fpc(void) -{ - uint32_t fpc; - - asm volatile(" stfpc %0\n" : "=m"(fpc)); - - return fpc; -} - -static inline uint8_t get_fpc_dxc(void) -{ - return get_fpc() >> 8; -} - -static inline void set_fpc_dxc(uint8_t dxc) -{ - uint32_t fpc = get_fpc(); - - fpc = (fpc & ~0xff00) | ((uint32_t)dxc) << 8; - - set_fpc(fpc); -} - -static inline void afp_enable(void) -{ - ctl_set_bit(0, 63 - 45); -} - -static inline void afp_disable(void) -{ - ctl_clear_bit(0, 63 - 45); -} - -#endif diff --git a/lib/s390x/asm/interrupt.h b/lib/s390x/asm/interrupt.h deleted file mode 100644 index 4cfade9e..00000000 --- a/lib/s390x/asm/interrupt.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _ASMS390X_IRQ_H_ -#define _ASMS390X_IRQ_H_ -#include - -#define EXT_IRQ_EMERGENCY_SIG 0x1201 -#define EXT_IRQ_EXTERNAL_CALL 0x1202 -#define EXT_IRQ_SERVICE_SIG 0x2401 - -void handle_pgm_int(void); -void handle_ext_int(void); -void handle_mcck_int(void); -void handle_io_int(void); -void handle_svc_int(void); -void expect_pgm_int(void); -void expect_ext_int(void); -uint16_t clear_pgm_int(void); -void check_pgm_int_code(uint16_t code); - -/* Activate low-address protection */ -static inline void low_prot_enable(void) -{ - ctl_set_bit(0, 63 - 35); -} - -/* Disable low-address protection */ -static inline void low_prot_disable(void) -{ - ctl_clear_bit(0, 63 - 35); -} - -#endif diff --git a/lib/s390x/asm/io.h b/lib/s390x/asm/io.h deleted file mode 100644 index 094dace9..00000000 --- a/lib/s390x/asm/io.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * Thomas Huth - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _ASMS390X_IO_H_ -#define _ASMS390X_IO_H_ - -#define __iomem - -#include - -#endif diff --git a/lib/s390x/asm/mem.h b/lib/s390x/asm/mem.h deleted file mode 100644 index c78bfa2b..00000000 --- a/lib/s390x/asm/mem.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Physical memory management related functions and definitions. - * - * Copyright IBM Corp. 2018 - * Author(s): Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _ASM_S390_MEM_H -#define _ASM_S390_MEM_H - -#define SKEY_ACC 0xf0 -#define SKEY_FP 0x08 -#define SKEY_RF 0x04 -#define SKEY_CH 0x02 - -union skey { - struct { - uint8_t acc : 4; - uint8_t fp : 1; - uint8_t rf : 1; - uint8_t ch : 1; - uint8_t pad : 1; - } str; - uint8_t val; -}; - -static inline void set_storage_key(void *addr, unsigned char skey, int nq) -{ - if (nq) - asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0" - : : "d" (skey), "a" (addr)); - else - asm volatile("sske %0,%1" : : "d" (skey), "a" (addr)); -} - -static inline void *set_storage_key_mb(void *addr, unsigned char skey) -{ - assert(test_facility(8)); - - asm volatile(".insn rrf,0xb22b0000,%[skey],%[addr],1,0" - : [addr] "+a" (addr) : [skey] "d" (skey)); - return addr; -} - -static inline unsigned char get_storage_key(void *addr) -{ - unsigned char skey; - - asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr)); - return skey; -} - -#define PFMF_FSC_4K 0 -#define PFMF_FSC_1M 1 -#define PFMF_FSC_2G 2 - -union pfmf_r1 { - struct { - unsigned long pad0 : 32; - unsigned long pad1 : 12; - unsigned long pad_fmfi : 2; - unsigned long sk : 1; /* set key*/ - unsigned long cf : 1; /* clear frame */ - unsigned long ui : 1; /* usage indication */ - unsigned long fsc : 3; - unsigned long pad2 : 1; - unsigned long mr : 1; - unsigned long mc : 1; - unsigned long pad3 : 1; - unsigned long key : 8; /* storage keys */ - } reg; - unsigned long val; -}; - -static inline void *pfmf(unsigned long r1, void *paddr) -{ - register void * addr asm("1") = paddr; - - asm volatile(".insn rre,0xb9af0000,%[r1],%[addr]" - : [addr] "+a" (addr) : [r1] "d" (r1) : "memory"); - return addr; -} -#endif diff --git a/lib/s390x/asm/page.h b/lib/s390x/asm/page.h deleted file mode 100644 index bc19154c..00000000 --- a/lib/s390x/asm/page.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * Thomas Huth - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _ASMS390X_PAGE_H_ -#define _ASMS390X_PAGE_H_ - -#include - -typedef uint64_t pgdval_t; /* Region-1 table entry */ -typedef uint64_t p4dval_t; /* Region-2 table entry*/ -typedef uint64_t pudval_t; /* Region-3 table entry */ -typedef uint64_t pmdval_t; /* Segment table entry */ -typedef uint64_t pteval_t; /* Page table entry */ - -typedef struct { pgdval_t pgd; } pgd_t; -typedef struct { p4dval_t p4d; } p4d_t; -typedef struct { pudval_t pud; } pud_t; -typedef struct { pmdval_t pmd; } pmd_t; -typedef struct { pteval_t pte; } pte_t; - -#define pgd_val(x) ((x).pgd) -#define p4d_val(x) ((x).p4d) -#define pud_val(x) ((x).pud) -#define pmd_val(x) ((x).pmd) -#define pte_val(x) ((x).pte) - -#define __pgd(x) ((pgd_t) { (x) } ) -#define __p4d(x) ((p4d_t) { (x) } ) -#define __pud(x) ((pud_t) { (x) } ) -#define __pmd(x) ((pmd_t) { (x) } ) -#define __pte(x) ((pte_t) { (x) } ) - -#endif diff --git a/lib/s390x/asm/pgtable.h b/lib/s390x/asm/pgtable.h deleted file mode 100644 index e15bee9c..00000000 --- a/lib/s390x/asm/pgtable.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * s390x page table definitions and functions - * - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _ASMS390X_PGTABLE_H_ -#define _ASMS390X_PGTABLE_H_ - -#include -#include - -#define ASCE_ORIGIN 0xfffffffffffff000UL -#define ASCE_G 0x0000000000000200UL -#define ASCE_P 0x0000000000000100UL -#define ASCE_S 0x0000000000000080UL -#define ASCE_X 0x0000000000000040UL -#define ASCE_R 0x0000000000000020UL -#define ASCE_DT 0x000000000000000cUL -#define ASCE_TL 0x0000000000000003UL - -#define ASCE_DT_REGION1 0x000000000000000cUL -#define ASCE_DT_REGION2 0x0000000000000008UL -#define ASCE_DT_REGION3 0x0000000000000004UL -#define ASCE_DT_SEGMENT 0x0000000000000000UL - -#define REGION_TABLE_ORDER 2 -#define REGION_TABLE_ENTRIES 2048 -#define REGION_TABLE_LENGTH 3 - -#define REGION1_SHIFT 53 -#define REGION2_SHIFT 42 -#define REGION3_SHIFT 31 - -#define REGION_ENTRY_ORIGIN 0xfffffffffffff000UL -#define REGION_ENTRY_P 0x0000000000000200UL -#define REGION_ENTRY_TF 0x00000000000000c0UL -#define REGION_ENTRY_I 0x0000000000000020UL -#define REGION_ENTRY_TT 0x000000000000000cUL -#define REGION_ENTRY_TL 0x0000000000000003UL - -#define REGION_ENTRY_TT_REGION1 0x000000000000000cUL -#define REGION_ENTRY_TT_REGION2 0x0000000000000008UL -#define REGION_ENTRY_TT_REGION3 0x0000000000000004UL - -#define REGION3_ENTRY_RFAA 0xffffffff80000000UL -#define REGION3_ENTRY_AV 0x0000000000010000UL -#define REGION3_ENTRY_ACC 0x000000000000f000UL -#define REGION3_ENTRY_F 0x0000000000000800UL -#define REGION3_ENTRY_FC 0x0000000000000400UL -#define REGION3_ENTRY_IEP 0x0000000000000100UL -#define REGION3_ENTRY_CR 0x0000000000000010UL - -#define SEGMENT_TABLE_ORDER 2 -#define SEGMENT_TABLE_ENTRIES 2048 -#define SEGMENT_TABLE_LENGTH 3 -#define SEGMENT_SHIFT 20 - -#define SEGMENT_ENTRY_ORIGIN 0xfffffffffffff800UL -#define SEGMENT_ENTRY_SFAA 0xfffffffffff80000UL -#define SEGMENT_ENTRY_AV 0x0000000000010000UL -#define SEGMENT_ENTRY_ACC 0x000000000000f000UL -#define SEGMENT_ENTRY_F 0x0000000000000800UL -#define SEGMENT_ENTRY_FC 0x0000000000000400UL -#define SEGMENT_ENTRY_P 0x0000000000000200UL -#define SEGMENT_ENTRY_IEP 0x0000000000000100UL -#define SEGMENT_ENTRY_I 0x0000000000000020UL -#define SEGMENT_ENTRY_CS 0x0000000000000010UL -#define SEGMENT_ENTRY_TT 0x000000000000000cUL - -#define SEGMENT_ENTRY_TT_REGION1 0x000000000000000cUL -#define SEGMENT_ENTRY_TT_REGION2 0x0000000000000008UL -#define SEGMENT_ENTRY_TT_REGION3 0x0000000000000004UL -#define SEGMENT_ENTRY_TT_SEGMENT 0x0000000000000000UL - -#define PAGE_TABLE_ORDER 0 -#define PAGE_TABLE_ENTRIES 256 - -#define PAGE_ENTRY_I 0x0000000000000400UL -#define PAGE_ENTRY_P 0x0000000000000200UL -#define PAGE_ENTRY_IEP 0x0000000000000100UL - -#define PTRS_PER_PGD REGION_TABLE_ENTRIES -#define PTRS_PER_P4D REGION_TABLE_ENTRIES -#define PTRS_PER_PUD REGION_TABLE_ENTRIES -#define PTRS_PER_PMD SEGMENT_TABLE_ENTRIES -#define PTRS_PER_PTE PAGE_TABLE_ENTRIES - -#define PGDIR_SHIFT REGION1_SHIFT -#define P4D_SHIFT REGION2_SHIFT -#define PUD_SHIFT REGION3_SHIFT -#define PMD_SHIFT SEGMENT_SHIFT - -#define pgd_none(entry) (pgd_val(entry) & REGION_ENTRY_I) -#define p4d_none(entry) (p4d_val(entry) & REGION_ENTRY_I) -#define pud_none(entry) (pud_val(entry) & REGION_ENTRY_I) -#define pmd_none(entry) (pmd_val(entry) & SEGMENT_ENTRY_I) -#define pte_none(entry) (pte_val(entry) & PAGE_ENTRY_I) - -#define pgd_addr(entry) __va(pgd_val(entry) & REGION_ENTRY_ORIGIN) -#define p4d_addr(entry) __va(p4d_val(entry) & REGION_ENTRY_ORIGIN) -#define pud_addr(entry) __va(pud_val(entry) & REGION_ENTRY_ORIGIN) -#define pmd_addr(entry) __va(pmd_val(entry) & SEGMENT_ENTRY_ORIGIN) -#define pte_addr(entry) __va(pte_val(entry) & PAGE_MASK) - -#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) -#define p4d_index(addr) (((addr) >> P4D_SHIFT) & (PTRS_PER_P4D - 1)) -#define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) -#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) -#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) - -#define pgd_offset(table, addr) ((pgd_t *)(table) + pgd_index(addr)) -#define p4d_offset(pgd, addr) ((p4d_t *)pgd_addr(*(pgd)) + p4d_index(addr)) -#define pud_offset(p4d, addr) ((pud_t *)p4d_addr(*(p4d)) + pud_index(addr)) -#define pmd_offset(pud, addr) ((pmd_t *)pud_addr(*(pud)) + pmd_index(addr)) -#define pte_offset(pmd, addr) ((pte_t *)pmd_addr(*(pmd)) + pte_index(addr)) - -static inline pgd_t *pgd_alloc_one(void) -{ - pgd_t *pgd = alloc_pages(REGION_TABLE_ORDER); - int i; - - for (i = 0; i < REGION_TABLE_ENTRIES; i++) - pgd_val(pgd[i]) = REGION_ENTRY_TT_REGION1 | REGION_ENTRY_I; - return pgd; -} - -static inline p4d_t *p4d_alloc_one(void) -{ - p4d_t *p4d = alloc_pages(REGION_TABLE_ORDER); - int i; - - for (i = 0; i < REGION_TABLE_ENTRIES; i++) - p4d_val(p4d[i]) = REGION_ENTRY_TT_REGION2 | REGION_ENTRY_I; - return p4d; -} - -static inline p4d_t *p4d_alloc(pgd_t *pgd, unsigned long addr) -{ - if (pgd_none(*pgd)) { - p4d_t *p4d = p4d_alloc_one(); - pgd_val(*pgd) = __pa(p4d) | REGION_ENTRY_TT_REGION1 | - REGION_TABLE_LENGTH; - } - return p4d_offset(pgd, addr); -} - -static inline pud_t *pud_alloc_one(void) -{ - pud_t *pud = alloc_pages(REGION_TABLE_ORDER); - int i; - - for (i = 0; i < REGION_TABLE_ENTRIES; i++) - pud_val(pud[i]) = REGION_ENTRY_TT_REGION3 | REGION_ENTRY_I; - return pud; -} - -static inline pud_t *pud_alloc(p4d_t *p4d, unsigned long addr) -{ - if (p4d_none(*p4d)) { - pud_t *pud = pud_alloc_one(); - p4d_val(*p4d) = __pa(pud) | REGION_ENTRY_TT_REGION2 | - REGION_TABLE_LENGTH; - } - return pud_offset(p4d, addr); -} - -static inline pmd_t *pmd_alloc_one(void) -{ - pmd_t *pmd = alloc_pages(SEGMENT_TABLE_ORDER); - int i; - - for (i = 0; i < SEGMENT_TABLE_ENTRIES; i++) - pmd_val(pmd[i]) = SEGMENT_ENTRY_TT_SEGMENT | SEGMENT_ENTRY_I; - return pmd; -} - -static inline pmd_t *pmd_alloc(pud_t *pud, unsigned long addr) -{ - if (pud_none(*pud)) { - pmd_t *pmd = pmd_alloc_one(); - pud_val(*pud) = __pa(pmd) | REGION_ENTRY_TT_REGION3 | - REGION_TABLE_LENGTH; - } - return pmd_offset(pud, addr); -} - -static inline pte_t *pte_alloc_one(void) -{ - pte_t *pte = alloc_pages(PAGE_TABLE_ORDER); - int i; - - for (i = 0; i < PAGE_TABLE_ENTRIES; i++) - pte_val(pte[i]) = PAGE_ENTRY_I; - return pte; -} - -static inline pte_t *pte_alloc(pmd_t *pmd, unsigned long addr) -{ - if (pmd_none(*pmd)) { - pte_t *pte = pte_alloc_one(); - pmd_val(*pmd) = __pa(pte) | SEGMENT_ENTRY_TT_SEGMENT | - SEGMENT_TABLE_LENGTH; - } - return pte_offset(pmd, addr); -} - -static inline void ipte(unsigned long vaddr, pteval_t *p_pte) -{ - unsigned long table_origin = (unsigned long)p_pte & PAGE_MASK; - - asm volatile( - " ipte %0,%1\n" - : : "a" (table_origin), "a" (vaddr) : "memory"); -} - -void configure_dat(int enable); - -#endif /* _ASMS390X_PGTABLE_H_ */ diff --git a/lib/s390x/asm/sigp.h b/lib/s390x/asm/sigp.h deleted file mode 100644 index 2d523139..00000000 --- a/lib/s390x/asm/sigp.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SIGP related definitions. - * - * Copied from the Linux kernel file arch/s390/include/asm/sigp.h - * - * This work is licensed under the terms of the GNU GPL, version - * 2. - */ - -#ifndef ASM_S390X_SIGP_H -#define ASM_S390X_SIGP_H - -/* SIGP order codes */ -#define SIGP_SENSE 1 -#define SIGP_EXTERNAL_CALL 2 -#define SIGP_EMERGENCY_SIGNAL 3 -#define SIGP_START 4 -#define SIGP_STOP 5 -#define SIGP_RESTART 6 -#define SIGP_STOP_AND_STORE_STATUS 9 -#define SIGP_INITIAL_CPU_RESET 11 -#define SIGP_CPU_RESET 12 -#define SIGP_SET_PREFIX 13 -#define SIGP_STORE_STATUS_AT_ADDRESS 14 -#define SIGP_SET_ARCHITECTURE 18 -#define SIGP_COND_EMERGENCY_SIGNAL 19 -#define SIGP_SENSE_RUNNING 21 -#define SIGP_SET_MULTI_THREADING 22 -#define SIGP_STORE_ADDITIONAL_STATUS 23 - -/* SIGP condition codes */ -#define SIGP_CC_ORDER_CODE_ACCEPTED 0 -#define SIGP_CC_STATUS_STORED 1 -#define SIGP_CC_BUSY 2 -#define SIGP_CC_NOT_OPERATIONAL 3 - -/* SIGP cpu status bits */ - -#define SIGP_STATUS_INVALID_ORDER 0x00000002UL -#define SIGP_STATUS_CHECK_STOP 0x00000010UL -#define SIGP_STATUS_STOPPED 0x00000040UL -#define SIGP_STATUS_EXT_CALL_PENDING 0x00000080UL -#define SIGP_STATUS_INVALID_PARAMETER 0x00000100UL -#define SIGP_STATUS_INCORRECT_STATE 0x00000200UL -#define SIGP_STATUS_NOT_RUNNING 0x00000400UL - -#ifndef __ASSEMBLER__ - - -static inline int sigp(uint16_t addr, uint8_t order, unsigned long parm, - uint32_t *status) -{ - register unsigned long reg1 asm ("1") = parm; - int cc; - - asm volatile( - " sigp %1,%2,0(%3)\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc), "+d" (reg1) : "d" (addr), "a" (order) : "cc"); - if (status) - *status = reg1; - return cc; -} - -static inline int sigp_retry(uint16_t addr, uint8_t order, unsigned long parm, - uint32_t *status) -{ - int cc; - - do { - cc = sigp(addr, order, parm, status); - } while (cc == 2); - return cc; -} - -#endif /* __ASSEMBLER__ */ -#endif /* ASM_S390X_SIGP_H */ diff --git a/lib/s390x/asm/spinlock.h b/lib/s390x/asm/spinlock.h deleted file mode 100644 index f7d3982b..00000000 --- a/lib/s390x/asm/spinlock.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * Thomas Huth - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef __ASMS390X_SPINLOCK_H -#define __ASMS390X_SPINLOCK_H - -#include - -#endif diff --git a/lib/s390x/asm/stack.h b/lib/s390x/asm/stack.h deleted file mode 100644 index e36d975f..00000000 --- a/lib/s390x/asm/stack.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * Thomas Huth - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _ASMS390X_STACK_H_ -#define _ASMS390X_STACK_H_ - -#ifndef _STACK_H_ -#error Do not directly include . Just use . -#endif - -#define HAVE_ARCH_BACKTRACE_FRAME -#define HAVE_ARCH_BACKTRACE - -#endif diff --git a/lib/s390x/interrupt.c b/lib/s390x/interrupt.c deleted file mode 100644 index 3a40cacd..00000000 --- a/lib/s390x/interrupt.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * s390x interrupt handling - * - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include -#include - -static bool pgm_int_expected; -static bool ext_int_expected; -static struct lowcore *lc; - -void expect_pgm_int(void) -{ - pgm_int_expected = true; - lc->pgm_int_code = 0; - mb(); -} - -void expect_ext_int(void) -{ - ext_int_expected = true; - lc->ext_int_code = 0; - mb(); -} - -uint16_t clear_pgm_int(void) -{ - uint16_t code; - - mb(); - code = lc->pgm_int_code; - lc->pgm_int_code = 0; - pgm_int_expected = false; - return code; -} - -void check_pgm_int_code(uint16_t code) -{ - mb(); - report(code == lc->pgm_int_code, - "Program interrupt: expected(%d) == received(%d)", code, - lc->pgm_int_code); -} - -static void fixup_pgm_int(void) -{ - switch (lc->pgm_int_code) { - case PGM_INT_CODE_PRIVILEGED_OPERATION: - /* Normal operation is in supervisor state, so this exception - * was produced intentionally and we should return to the - * supervisor state. - */ - lc->pgm_old_psw.mask &= ~PSW_MASK_PSTATE; - break; - case PGM_INT_CODE_PROTECTION: - /* Handling for iep.c test case. */ - if (lc->trans_exc_id & 0x80UL && lc->trans_exc_id & 0x04UL && - !(lc->trans_exc_id & 0x08UL)) - lc->pgm_old_psw.addr = lc->sw_int_grs[14]; - break; - case PGM_INT_CODE_SEGMENT_TRANSLATION: - case PGM_INT_CODE_PAGE_TRANSLATION: - case PGM_INT_CODE_TRACE_TABLE: - case PGM_INT_CODE_AFX_TRANSLATION: - case PGM_INT_CODE_ASX_TRANSLATION: - case PGM_INT_CODE_LX_TRANSLATION: - case PGM_INT_CODE_EX_TRANSLATION: - case PGM_INT_CODE_PRIMARY_AUTHORITY: - case PGM_INT_CODE_SECONDARY_AUTHORITY: - case PGM_INT_CODE_LFX_TRANSLATION: - case PGM_INT_CODE_LSX_TRANSLATION: - case PGM_INT_CODE_ALEN_TRANSLATION: - case PGM_INT_CODE_ALE_SEQUENCE: - case PGM_INT_CODE_ASTE_VALIDITY: - case PGM_INT_CODE_ASTE_SEQUENCE: - case PGM_INT_CODE_EXTENDED_AUTHORITY: - case PGM_INT_CODE_LSTE_SEQUENCE: - case PGM_INT_CODE_ASTE_INSTANCE: - case PGM_INT_CODE_STACK_FULL: - case PGM_INT_CODE_STACK_EMPTY: - case PGM_INT_CODE_STACK_SPECIFICATION: - case PGM_INT_CODE_STACK_TYPE: - case PGM_INT_CODE_STACK_OPERATION: - case PGM_INT_CODE_ASCE_TYPE: - case PGM_INT_CODE_REGION_FIRST_TRANS: - case PGM_INT_CODE_REGION_SECOND_TRANS: - case PGM_INT_CODE_REGION_THIRD_TRANS: - case PGM_INT_CODE_PER: - case PGM_INT_CODE_CRYPTO_OPERATION: - /* The interrupt was nullified, the old PSW points at the - * responsible instruction. Forward the PSW so we don't loop. - */ - lc->pgm_old_psw.addr += lc->pgm_int_id; - } - /* suppressed/terminated/completed point already at the next address */ -} - -void handle_pgm_int(void) -{ - if (!pgm_int_expected) { - /* Force sclp_busy to false, otherwise we will loop forever */ - sclp_handle_ext(); - report_abort("Unexpected program interrupt: %d on cpu %d at %#lx, ilen %d\n", - lc->pgm_int_code, stap(), lc->pgm_old_psw.addr, - lc->pgm_int_id); - } - - pgm_int_expected = false; - fixup_pgm_int(); -} - -void handle_ext_int(void) -{ - if (!ext_int_expected && - lc->ext_int_code != EXT_IRQ_SERVICE_SIG) { - report_abort("Unexpected external call interrupt (code %#x): on cpu %d at %#lx", - lc->ext_int_code, stap(), lc->ext_old_psw.addr); - return; - } - - if (lc->ext_int_code == EXT_IRQ_SERVICE_SIG) { - lc->sw_int_crs[0] &= ~(1UL << 9); - sclp_handle_ext(); - } else { - ext_int_expected = false; - } - - if (!(lc->sw_int_crs[0] & CR0_EXTM_MASK)) - lc->ext_old_psw.mask &= ~PSW_MASK_EXT; -} - -void handle_mcck_int(void) -{ - report_abort("Unexpected machine check interrupt: on cpu %d at %#lx", - stap(), lc->mcck_old_psw.addr); -} - -void handle_io_int(void) -{ - report_abort("Unexpected io interrupt: on cpu %d at %#lx", - stap(), lc->io_old_psw.addr); -} - -void handle_svc_int(void) -{ - report_abort("Unexpected supervisor call interrupt: on cpu %d at %#lx", - stap(), lc->svc_old_psw.addr); -} diff --git a/lib/s390x/io.c b/lib/s390x/io.c deleted file mode 100644 index c0f0bf76..00000000 --- a/lib/s390x/io.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * s390x io implementation - * - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * Thomas Huth - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include -#include -#include -#include "sclp.h" -#include "smp.h" - -extern char ipl_args[]; -uint64_t stfl_doublewords[NB_STFL_DOUBLEWORDS]; - -static struct spinlock lock; - -void setup(void); - -void puts(const char *s) -{ - spin_lock(&lock); - sclp_print(s); - spin_unlock(&lock); -} - -void setup(void) -{ - setup_args_progname(ipl_args); - setup_facilities(); - sclp_console_setup(); - sclp_memory_setup(); - smp_setup(); -} - -void exit(int code) -{ - smp_teardown(); - printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1); - while (1) { - sigp(stap(), SIGP_STOP, 0, NULL); - } -} diff --git a/lib/s390x/mmu.c b/lib/s390x/mmu.c deleted file mode 100644 index 912236ce..00000000 --- a/lib/s390x/mmu.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * s390x MMU - * - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -#include -#include -#include -#include -#include -#include "mmu.h" - -static pgd_t *table_root; - -void configure_dat(int enable) -{ - uint64_t mask; - - if (enable) - mask = extract_psw_mask() | PSW_MASK_DAT; - else - mask = extract_psw_mask() & ~PSW_MASK_DAT; - - load_psw_mask(mask); -} - -static void mmu_enable(pgd_t *pgtable) -{ - struct lowcore *lc = NULL; - const uint64_t asce = __pa(pgtable) | ASCE_DT_REGION1 | - REGION_TABLE_LENGTH; - - /* set primary asce */ - lctlg(1, asce); - assert(stctg(1) == asce); - - /* enable dat (primary == 0 set as default) */ - configure_dat(1); - - /* we can now also use DAT unconditionally in our PGM handler */ - lc->pgm_new_psw.mask |= PSW_MASK_DAT; -} - -static pteval_t *get_pte(pgd_t *pgtable, uintptr_t vaddr) -{ - pgd_t *pgd = pgd_offset(pgtable, vaddr); - p4d_t *p4d = p4d_alloc(pgd, vaddr); - pud_t *pud = pud_alloc(p4d, vaddr); - pmd_t *pmd = pmd_alloc(pud, vaddr); - pte_t *pte = pte_alloc(pmd, vaddr); - - return &pte_val(*pte); -} - -phys_addr_t virt_to_pte_phys(pgd_t *pgtable, void *vaddr) -{ - return (*get_pte(pgtable, (uintptr_t)vaddr) & PAGE_MASK) + - ((unsigned long)vaddr & ~PAGE_MASK); -} - -static pteval_t *set_pte(pgd_t *pgtable, pteval_t val, void *vaddr) -{ - pteval_t *p_pte = get_pte(pgtable, (uintptr_t)vaddr); - - /* first flush the old entry (if we're replacing anything) */ - if (!(*p_pte & PAGE_ENTRY_I)) - ipte((uintptr_t)vaddr, p_pte); - - *p_pte = val; - return p_pte; -} - -pteval_t *install_page(pgd_t *pgtable, phys_addr_t phys, void *vaddr) -{ - return set_pte(pgtable, __pa(phys), vaddr); -} - -void protect_page(void *vaddr, unsigned long prot) -{ - pteval_t *p_pte = get_pte(table_root, (uintptr_t)vaddr); - pteval_t n_pte = *p_pte | prot; - - set_pte(table_root, n_pte, vaddr); -} - -void unprotect_page(void *vaddr, unsigned long prot) -{ - pteval_t *p_pte = get_pte(table_root, (uintptr_t)vaddr); - pteval_t n_pte = *p_pte & ~prot; - - set_pte(table_root, n_pte, vaddr); -} - -void protect_range(void *start, unsigned long len, unsigned long prot) -{ - uintptr_t curr = (uintptr_t)start & PAGE_MASK; - - len &= PAGE_MASK; - for (; len; len -= PAGE_SIZE, curr += PAGE_SIZE) - protect_page((void *)curr, prot); -} - -void unprotect_range(void *start, unsigned long len, unsigned long prot) -{ - uintptr_t curr = (uintptr_t)start & PAGE_MASK; - - len &= PAGE_MASK; - for (; len; len -= PAGE_SIZE, curr += PAGE_SIZE) - unprotect_page((void *)curr, prot); -} - -static void setup_identity(pgd_t *pgtable, phys_addr_t start_addr, - phys_addr_t end_addr) -{ - phys_addr_t cur; - - start_addr &= PAGE_MASK; - for (cur = start_addr; true; cur += PAGE_SIZE) { - if (start_addr < end_addr && cur >= end_addr) - break; - if (start_addr > end_addr && cur <= end_addr) - break; - install_page(pgtable, cur, __va(cur)); - } -} - -void *setup_mmu(phys_addr_t phys_end){ - pgd_t *page_root; - - /* allocate a region-1 table */ - page_root = pgd_alloc_one(); - - /* map all physical memory 1:1 */ - setup_identity(page_root, 0, phys_end); - - /* generate 128MB of invalid adresses at the end (for testing PGM) */ - init_alloc_vpage((void *) -(1UL << 27)); - setup_identity(page_root, -(1UL << 27), 0); - - /* finally enable DAT with the new table */ - mmu_enable(page_root); - table_root = page_root; - return page_root; -} diff --git a/lib/s390x/mmu.h b/lib/s390x/mmu.h deleted file mode 100644 index f5095faa..00000000 --- a/lib/s390x/mmu.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * s390x mmu functions - * - * Copyright (c) 2018 IBM Corp - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _ASMS390X_MMU_H_ -#define _ASMS390X_MMU_H_ - -void protect_page(void *vaddr, unsigned long prot); -void protect_range(void *start, unsigned long len, unsigned long prot); -void unprotect_page(void *vaddr, unsigned long prot); -void unprotect_range(void *start, unsigned long len, unsigned long prot); - -#endif /* _ASMS390X_MMU_H_ */ diff --git a/lib/s390x/sclp-console.c b/lib/s390x/sclp-console.c deleted file mode 100644 index 6067a1a3..00000000 --- a/lib/s390x/sclp-console.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * SCLP ASCII access driver - * - * Copyright (c) 2013 Alexander Graf - * - * This work is licensed under the terms of the GNU GPL, version 2 or (at - * your option) any later version. See the COPYING file in the top-level - * directory. - */ - -#include -#include -#include -#include -#include -#include -#include "sclp.h" - -/* - * ASCII (IBM PC 437) -> EBCDIC 037 - */ -static uint8_t _ascebc[256] = { - /*00 NUL SOH STX ETX EOT ENQ ACK BEL */ - 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, - /*08 BS HT LF VT FF CR SO SI */ - /* ->NL */ - 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ - 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, - /*18 CAN EM SUB ESC FS GS RS US */ - /* ->IGS ->IRS ->IUS */ - 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, - /*20 SP ! " # $ % & ' */ - 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, - /*28 ( ) * + , - . / */ - 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, - /*30 0 1 2 3 4 5 6 7 */ - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - /*38 8 9 : ; < = > ? */ - 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, - /*40 @ A B C D E F G */ - 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - /*48 H I J K L M N O */ - 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, - /*50 P Q R S T U V W */ - 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, - /*58 X Y Z [ \ ] ^ _ */ - 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, - /*60 ` a b c d e f g */ - 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - /*68 h i j k l m n o */ - 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, - /*70 p q r s t u v w */ - 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - /*78 x y z { | } ~ DL */ - 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, - /*80*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*88*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*90*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*98*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*A0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*A8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*B0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*B8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*C0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*C8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*D0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*D8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*E0 sz */ - 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*E8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*F0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*F8*/ - 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF -}; - -static char lm_buff[120]; -static unsigned char lm_buff_off; -static struct spinlock lm_buff_lock; - -static void sclp_print_ascii(const char *str) -{ - int len = strlen(str); - WriteEventData *sccb = (void *)_sccb; - - sclp_mark_busy(); - memset(sccb, 0, sizeof(*sccb)); - sccb->h.length = offsetof(WriteEventData, msg) + len; - sccb->h.function_code = SCLP_FC_NORMAL_WRITE; - sccb->ebh.length = sizeof(EventBufferHeader) + len; - sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; - memcpy(&sccb->msg, str, len); - - sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); -} - -static void lm_print(const char *buff, int len) -{ - unsigned char *ptr, *end, ch; - unsigned int count, offset; - struct WriteEventData *sccb; - struct mdb *mdb; - struct mto *mto; - struct go *go; - - sclp_mark_busy(); - sccb = (struct WriteEventData *) _sccb; - end = (unsigned char *) sccb + 4096 - 1; - memset(sccb, 0, sizeof(*sccb)); - ptr = (unsigned char *) &sccb->msg.mdb.mto; - offset = 0; - do { - for (count = sizeof(*mto); offset < len; count++) { - ch = buff[offset++]; - if (ch == 0x0a || ptr + count > end) - break; - ptr[count] = _ascebc[ch]; - } - mto = (struct mto *) ptr; - mto->length = count; - mto->type = 4; - mto->line_type_flags = LNTPFLGS_ENDTEXT; - ptr += count; - } while (offset < len && ptr + sizeof(*mto) <= end); - len = ptr - (unsigned char *) sccb; - sccb->h.length = len - offsetof(struct WriteEventData, h); - sccb->h.function_code = SCLP_FC_NORMAL_WRITE; - sccb->ebh.type = EVTYP_MSG; - sccb->ebh.length = len - offsetof(struct WriteEventData, ebh); - mdb = &sccb->msg.mdb; - mdb->header.type = 1; - mdb->header.tag = 0xD4C4C240; - mdb->header.revision_code = 1; - mdb->header.length = len - offsetof(struct WriteEventData, msg.mdb.header); - go = &mdb->go; - go->length = sizeof(*go); - go->type = 1; - sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); -} - - -/* - * In contrast to the ascii console, linemode produces a new - * line with every write of data. The report() function uses - * several printf() calls to generate a line of data which - * would all end up on different lines. - * - * Hence we buffer here until we encounter a \n or the buffer - * is full. That means that linemode output can look a bit - * different from ascii and that it takes a bit longer for - * lines to appear. - */ -static void sclp_print_lm(const char *str) -{ - int i; - const int len = strlen(str); - - spin_lock(&lm_buff_lock); - - for (i = 0; i < len; i++) { - lm_buff[lm_buff_off++] = str[i]; - - /* Buffer full or newline? */ - if (str[i] == '\n' || lm_buff_off == (ARRAY_SIZE(lm_buff) - 1)) { - lm_print(lm_buff, lm_buff_off); - lm_buff_off = 0; - } - } - spin_unlock(&lm_buff_lock); -} - -/* - * SCLP needs to be initialized by setting a send and receive mask, - * indicating which messages the control program (we) want(s) to - * send/receive. - */ -static void sclp_set_write_mask(void) -{ - WriteEventMask *sccb = (void *)_sccb; - - sclp_mark_busy(); - memset(_sccb, 0, sizeof(*sccb)); - sccb->h.length = sizeof(WriteEventMask); - sccb->h.function_code = SCLP_FC_NORMAL_WRITE; - sccb->mask_length = sizeof(sccb_mask_t); - - /* For now we don't process sclp input. */ - sccb->cp_receive_mask = 0; - /* We send ASCII and line mode. */ - sccb->cp_send_mask = SCLP_EVENT_MASK_MSG_ASCII | SCLP_EVENT_MASK_MSG; - - sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb); - assert(sccb->h.response_code == SCLP_RC_NORMAL_COMPLETION); -} - -void sclp_console_setup(void) -{ - sclp_set_write_mask(); -} - -void sclp_print(const char *str) -{ - /* - * z/VM advertises a vt220 console which is not functional: - * (response code 05F0, "not active because of the state of - * the machine"). Hence testing the masks would only work if - * we also use stsi data to distinguish z/VM. - * - * Let's rather print on all available consoles. - */ - if (strlen(str) > (PAGE_SIZE / 2)) { - sclp_print_ascii("Warning: Printing is limited to 2KB of data."); - sclp_print_lm("Warning: Printing is limited to 2KB of data."); - return; - } - sclp_print_ascii(str); - sclp_print_lm(str); -} diff --git a/lib/s390x/sclp.c b/lib/s390x/sclp.c deleted file mode 100644 index 4054d0ee..00000000 --- a/lib/s390x/sclp.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * s390x SCLP driver - * - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -#include -#include -#include -#include -#include -#include -#include "sclp.h" -#include -#include - -extern unsigned long stacktop; - -static uint64_t storage_increment_size; -static uint64_t max_ram_size; -static uint64_t ram_size; - -char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096))); -static volatile bool sclp_busy; -static struct spinlock sclp_lock; - -static void mem_init(phys_addr_t mem_end) -{ - phys_addr_t freemem_start = (phys_addr_t)&stacktop; - phys_addr_t base, top; - - phys_alloc_init(freemem_start, mem_end - freemem_start); - phys_alloc_get_unused(&base, &top); - base = (base + PAGE_SIZE - 1) & -PAGE_SIZE; - top = top & -PAGE_SIZE; - - /* Make the pages available to the physical allocator */ - free_pages((void *)(unsigned long)base, top - base); - page_alloc_ops_enable(); -} - -void sclp_setup_int(void) -{ - uint64_t mask; - - ctl_set_bit(0, 9); - - mask = extract_psw_mask(); - mask |= PSW_MASK_EXT; - load_psw_mask(mask); -} - -void sclp_handle_ext(void) -{ - ctl_clear_bit(0, 9); - spin_lock(&sclp_lock); - sclp_busy = false; - spin_unlock(&sclp_lock); -} - -void sclp_wait_busy(void) -{ - while (sclp_busy) - mb(); -} - -void sclp_mark_busy(void) -{ - /* - * With multiple CPUs we might need to wait for another CPU's - * request before grabbing the busy indication. - */ - while (true) { - sclp_wait_busy(); - spin_lock(&sclp_lock); - if (!sclp_busy) { - sclp_busy = true; - spin_unlock(&sclp_lock); - return; - } - spin_unlock(&sclp_lock); - } -} - -static void sclp_read_scp_info(ReadInfo *ri, int length) -{ - unsigned int commands[] = { SCLP_CMDW_READ_SCP_INFO_FORCED, - SCLP_CMDW_READ_SCP_INFO }; - int i, cc; - - for (i = 0; i < ARRAY_SIZE(commands); i++) { - sclp_mark_busy(); - memset(&ri->h, 0, sizeof(ri->h)); - ri->h.length = length; - - cc = sclp_service_call(commands[i], ri); - if (cc) - break; - if (ri->h.response_code == SCLP_RC_NORMAL_READ_COMPLETION) - return; - if (ri->h.response_code != SCLP_RC_INVALID_SCLP_COMMAND) - break; - } - report_abort("READ_SCP_INFO failed"); -} - -/* Perform service call. Return 0 on success, non-zero otherwise. */ -int sclp_service_call(unsigned int command, void *sccb) -{ - int cc; - - sclp_setup_int(); - cc = servc(command, __pa(sccb)); - sclp_wait_busy(); - if (cc == 3) - return -1; - if (cc == 2) - return -1; - return 0; -} - -void sclp_memory_setup(void) -{ - ReadInfo *ri = (void *)_sccb; - uint64_t rnmax, rnsize; - int cc; - - sclp_read_scp_info(ri, SCCB_SIZE); - - /* calculate the storage increment size */ - rnsize = ri->rnsize; - if (!rnsize) { - rnsize = ri->rnsize2; - } - storage_increment_size = rnsize << 20; - - /* calculate the maximum memory size */ - rnmax = ri->rnmax; - if (!rnmax) { - rnmax = ri->rnmax2; - } - max_ram_size = rnmax * storage_increment_size; - - /* lowcore is always accessible, so the first increment is accessible */ - ram_size = storage_increment_size; - - /* probe for r/w memory up to max memory size */ - while (ram_size < max_ram_size) { - expect_pgm_int(); - cc = tprot(ram_size + storage_increment_size - 1); - /* stop once we receive an exception or have protected memory */ - if (clear_pgm_int() || cc != 0) - break; - ram_size += storage_increment_size; - } - - mem_init(ram_size); -} - -uint64_t get_ram_size(void) -{ - return ram_size; -} - -uint64_t get_max_ram_size(void) -{ - return max_ram_size; -} diff --git a/lib/s390x/sclp.h b/lib/s390x/sclp.h deleted file mode 100644 index 675f07ed..00000000 --- a/lib/s390x/sclp.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * SCLP definitions - * - * Based on the file pc-bios/s390-ccw/sclp.h from QEMU - * Copyright (c) 2013 Alexander Graf - * - * and based on the file include/hw/s390x/sclp.h from QEMU - * Copyright IBM, Corp. 2012 - * Author: Christian Borntraeger - * - * This work is licensed under the terms of the GNU GPL, version 2 or (at - * your option) any later version. See the COPYING file in the top-level - * directory. - */ - -#ifndef SCLP_H -#define SCLP_H - -#define SCLP_CMD_CODE_MASK 0xffff00ff - -/* SCLP command codes */ -#define SCLP_READ_CPU_INFO 0x00010001 -#define SCLP_CMDW_READ_SCP_INFO 0x00020001 -#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 -#define SCLP_READ_STORAGE_ELEMENT_INFO 0x00040001 -#define SCLP_ATTACH_STORAGE_ELEMENT 0x00080001 -#define SCLP_ASSIGN_STORAGE 0x000D0001 -#define SCLP_CMD_READ_EVENT_DATA 0x00770005 -#define SCLP_CMD_WRITE_EVENT_DATA 0x00760005 -#define SCLP_CMD_WRITE_EVENT_MASK 0x00780005 - -/* SCLP Memory hotplug codes */ -#define SCLP_FC_ASSIGN_ATTACH_READ_STOR 0xE00000000000ULL -#define SCLP_STARTING_SUBINCREMENT_ID 0x10001 -#define SCLP_INCREMENT_UNIT 0x10000 -#define MAX_AVAIL_SLOTS 32 -#define MAX_STORAGE_INCREMENTS 1020 - -/* CPU hotplug SCLP codes */ -#define SCLP_HAS_CPU_INFO 0x0C00000000000000ULL -#define SCLP_CMDW_READ_CPU_INFO 0x00010001 -#define SCLP_CMDW_CONFIGURE_CPU 0x00110001 -#define SCLP_CMDW_DECONFIGURE_CPU 0x00100001 - -/* SCLP PCI codes */ -#define SCLP_HAS_IOA_RECONFIG 0x0000000040000000ULL -#define SCLP_CMDW_CONFIGURE_IOA 0x001a0001 -#define SCLP_CMDW_DECONFIGURE_IOA 0x001b0001 -#define SCLP_RECONFIG_PCI_ATYPE 2 - -/* SCLP response codes */ -#define SCLP_RC_NORMAL_READ_COMPLETION 0x0010 -#define SCLP_RC_NORMAL_COMPLETION 0x0020 -#define SCLP_RC_SCCB_BOUNDARY_VIOLATION 0x0100 -#define SCLP_RC_NO_ACTION_REQUIRED 0x0120 -#define SCLP_RC_INVALID_SCLP_COMMAND 0x01f0 -#define SCLP_RC_CONTAINED_EQUIPMENT_CHECK 0x0340 -#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH 0x0300 -#define SCLP_RC_STANDBY_READ_COMPLETION 0x0410 -#define SCLP_RC_ADAPTER_IN_RESERVED_STATE 0x05f0 -#define SCLP_RC_ADAPTER_TYPE_NOT_RECOGNIZED 0x06f0 -#define SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED 0x09f0 -#define SCLP_RC_INVALID_FUNCTION 0x40f0 -#define SCLP_RC_NO_EVENT_BUFFERS_STORED 0x60f0 -#define SCLP_RC_INVALID_SELECTION_MASK 0x70f0 -#define SCLP_RC_INCONSISTENT_LENGTHS 0x72f0 -#define SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR 0x73f0 -#define SCLP_RC_INVALID_MASK_LENGTH 0x74f0 - -/* SCLP control mask bits */ -#define SCLP_CM2_VARIABLE_LENGTH_RESPONSE 0x80 - -/* SCLP function codes */ -#define SCLP_FC_NORMAL_WRITE 0 -#define SCLP_FC_SINGLE_INCREMENT_ASSIGN 0x40 -#define SCLP_FC_DUMP_INDICATOR 0x80 - -/* SCLP event buffer flags */ -#define SCLP_EVENT_BUFFER_ACCEPTED 0x80 - -/* Service Call Control Block (SCCB) and its elements */ -#define SCCB_SIZE 4096 - -typedef struct SCCBHeader { - uint16_t length; - uint8_t function_code; - uint8_t control_mask[3]; - uint16_t response_code; -} __attribute__((packed)) SCCBHeader; - -#define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader)) -#define SCCB_CPU_FEATURE_LEN 6 - -/* CPU information */ -typedef struct CPUEntry { - uint8_t address; - uint8_t reserved0; - uint8_t features[SCCB_CPU_FEATURE_LEN]; - uint8_t reserved2[6]; - uint8_t type; - uint8_t reserved1; -} __attribute__((packed)) CPUEntry; - -typedef struct ReadInfo { - SCCBHeader h; - uint16_t rnmax; - uint8_t rnsize; - uint8_t _reserved1[16 - 11]; /* 11-15 */ - uint16_t entries_cpu; /* 16-17 */ - uint16_t offset_cpu; /* 18-19 */ - uint8_t _reserved2[24 - 20]; /* 20-23 */ - uint8_t loadparm[8]; /* 24-31 */ - uint8_t _reserved3[48 - 32]; /* 32-47 */ - uint64_t facilities; /* 48-55 */ - uint8_t _reserved0[76 - 56]; /* 56-75 */ - uint32_t ibc_val; - uint8_t conf_char[99 - 80]; /* 80-98 */ - uint8_t mha_pow; - uint32_t rnsize2; - uint64_t rnmax2; - uint8_t _reserved6[116 - 112]; /* 112-115 */ - uint8_t conf_char_ext[120 - 116]; /* 116-119 */ - uint16_t highest_cpu; - uint8_t _reserved5[124 - 122]; /* 122-123 */ - uint32_t hmfai; - struct CPUEntry entries[0]; -} __attribute__((packed)) ReadInfo; - -typedef struct ReadCpuInfo { - SCCBHeader h; - uint16_t nr_configured; /* 8-9 */ - uint16_t offset_configured; /* 10-11 */ - uint16_t nr_standby; /* 12-13 */ - uint16_t offset_standby; /* 14-15 */ - uint8_t reserved0[24-16]; /* 16-23 */ - struct CPUEntry entries[0]; -} __attribute__((packed)) ReadCpuInfo; - -typedef struct ReadStorageElementInfo { - SCCBHeader h; - uint16_t max_id; - uint16_t assigned; - uint16_t standby; - uint8_t _reserved0[16 - 14]; /* 14-15 */ - uint32_t entries[0]; -} __attribute__((packed)) ReadStorageElementInfo; - -typedef struct AttachStorageElement { - SCCBHeader h; - uint8_t _reserved0[10 - 8]; /* 8-9 */ - uint16_t assigned; - uint8_t _reserved1[16 - 12]; /* 12-15 */ - uint32_t entries[0]; -} __attribute__((packed)) AttachStorageElement; - -typedef struct AssignStorage { - SCCBHeader h; - uint16_t rn; -} __attribute__((packed)) AssignStorage; - -typedef struct IoaCfgSccb { - SCCBHeader header; - uint8_t atype; - uint8_t reserved1; - uint16_t reserved2; - uint32_t aid; -} __attribute__((packed)) IoaCfgSccb; - -typedef struct SCCB { - SCCBHeader h; - char data[SCCB_DATA_LEN]; - } __attribute__((packed)) SCCB; - -/* SCLP event types */ -#define SCLP_EVENT_ASCII_CONSOLE_DATA 0x1a -#define SCLP_EVENT_SIGNAL_QUIESCE 0x1d - -/* SCLP event masks */ -#define SCLP_EVENT_MASK_SIGNAL_QUIESCE 0x00000008 -#define SCLP_EVENT_MASK_MSG_ASCII 0x00000040 -#define SCLP_EVENT_MASK_MSG 0x40000000 - -#define SCLP_UNCONDITIONAL_READ 0x00 -#define SCLP_SELECTIVE_READ 0x01 - -typedef struct WriteEventMask { - SCCBHeader h; - uint16_t _reserved; - uint16_t mask_length; - uint32_t cp_receive_mask; - uint32_t cp_send_mask; - uint32_t send_mask; - uint32_t receive_mask; -} __attribute__((packed)) WriteEventMask; - -#define MDBTYP_GO 0x0001 -#define MDBTYP_MTO 0x0004 -#define EVTYP_MSG 0x02 -#define LNTPFLGS_CNTLTEXT 0x8000 -#define LNTPFLGS_LABELTEXT 0x4000 -#define LNTPFLGS_DATATEXT 0x2000 -#define LNTPFLGS_ENDTEXT 0x1000 -#define LNTPFLGS_PROMPTTEXT 0x0800 - -typedef uint32_t sccb_mask_t; - -/* SCLP line mode console related structures. */ - -struct mto { - u16 length; - u16 type; - u16 line_type_flags; - u8 alarm_control; - u8 _reserved[3]; -} __attribute__((packed)); - -struct go { - u16 length; - u16 type; - u32 domid; - u8 hhmmss_time[8]; - u8 th_time[3]; - u8 reserved_0; - u8 dddyyyy_date[7]; - u8 _reserved_1; - u16 general_msg_flags; - u8 _reserved_2[10]; - u8 originating_system_name[8]; - u8 job_guest_name[8]; -} __attribute__((packed)); - -struct mdb_header { - u16 length; - u16 type; - u32 tag; - u32 revision_code; -} __attribute__((packed)); - -struct mdb { - struct mdb_header header; - struct go go; - struct mto mto; -} __attribute__((packed)); - -typedef struct EventBufferHeader { - uint16_t length; - uint8_t type; - uint8_t flags; - uint16_t _reserved; -} __attribute__((packed)) EventBufferHeader; - -typedef struct WriteEventData { - SCCBHeader h; - EventBufferHeader ebh; - union { - char data[0]; - struct mdb mdb; - } msg; -} __attribute__((packed)) WriteEventData; - -typedef struct ReadEventData { - SCCBHeader h; - EventBufferHeader ebh; - uint32_t mask; -} __attribute__((packed)) ReadEventData; - -extern char _sccb[]; -void sclp_setup_int(void); -void sclp_handle_ext(void); -void sclp_wait_busy(void); -void sclp_mark_busy(void); -void sclp_console_setup(void); -void sclp_print(const char *str); -int sclp_service_call(unsigned int command, void *sccb); -void sclp_memory_setup(void); -uint64_t get_ram_size(void); -uint64_t get_max_ram_size(void); - -#endif /* SCLP_H */ diff --git a/lib/s390x/smp.c b/lib/s390x/smp.c deleted file mode 100644 index 2860e9c9..00000000 --- a/lib/s390x/smp.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * s390x smp - * Based on Linux's arch/s390/kernel/smp.c and - * arch/s390/include/asm/sigp.h - * - * Copyright (c) 2019 IBM Corp - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2. - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "smp.h" -#include "sclp.h" - -static char cpu_info_buffer[PAGE_SIZE] __attribute__((__aligned__(4096))); -static struct cpu *cpus; -static struct cpu *cpu0; -static struct spinlock lock; - -extern void smp_cpu_setup_state(void); - -int smp_query_num_cpus(void) -{ - struct ReadCpuInfo *info = (void *)cpu_info_buffer; - return info->nr_configured; -} - -struct cpu *smp_cpu_from_addr(uint16_t addr) -{ - int i, num = smp_query_num_cpus(); - - for (i = 0; i < num; i++) { - if (cpus[i].addr == addr) - return &cpus[i]; - } - return NULL; -} - -bool smp_cpu_stopped(uint16_t addr) -{ - uint32_t status; - - if (sigp(addr, SIGP_SENSE, 0, &status) != SIGP_CC_STATUS_STORED) - return false; - return !!(status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED)); -} - -bool smp_sense_running_status(uint16_t addr) -{ - if (sigp(addr, SIGP_SENSE_RUNNING, 0, NULL) != SIGP_CC_STATUS_STORED) - return true; - /* Status stored condition code is equivalent to cpu not running. */ - return false; -} - -static int smp_cpu_stop_nolock(uint16_t addr, bool store) -{ - struct cpu *cpu; - uint8_t order = store ? SIGP_STOP_AND_STORE_STATUS : SIGP_STOP; - - cpu = smp_cpu_from_addr(addr); - if (!cpu || cpu == cpu0) - return -1; - - if (sigp_retry(addr, order, 0, NULL)) - return -1; - - while (!smp_cpu_stopped(addr)) - mb(); - cpu->active = false; - return 0; -} - -int smp_cpu_stop(uint16_t addr) -{ - int rc; - - spin_lock(&lock); - rc = smp_cpu_stop_nolock(addr, false); - spin_unlock(&lock); - return rc; -} - -int smp_cpu_stop_store_status(uint16_t addr) -{ - int rc; - - spin_lock(&lock); - rc = smp_cpu_stop_nolock(addr, true); - spin_unlock(&lock); - return rc; -} - -static int smp_cpu_restart_nolock(uint16_t addr, struct psw *psw) -{ - int rc; - struct cpu *cpu = smp_cpu_from_addr(addr); - - if (!cpu) - return -1; - if (psw) { - cpu->lowcore->restart_new_psw.mask = psw->mask; - cpu->lowcore->restart_new_psw.addr = psw->addr; - } - /* - * Stop the cpu, so we don't have a race between a running cpu - * and the restart in the test that checks if the cpu is - * running after the restart. - */ - smp_cpu_stop_nolock(addr, false); - rc = sigp(addr, SIGP_RESTART, 0, NULL); - if (rc) - return rc; - /* - * The order has been accepted, but the actual restart may not - * have been performed yet, so wait until the cpu is running. - */ - while (smp_cpu_stopped(addr)) - mb(); - cpu->active = true; - return 0; -} - -int smp_cpu_restart(uint16_t addr) -{ - int rc; - - spin_lock(&lock); - rc = smp_cpu_restart_nolock(addr, NULL); - spin_unlock(&lock); - return rc; -} - -int smp_cpu_start(uint16_t addr, struct psw psw) -{ - int rc; - - spin_lock(&lock); - rc = smp_cpu_restart_nolock(addr, &psw); - spin_unlock(&lock); - return rc; -} - -int smp_cpu_destroy(uint16_t addr) -{ - struct cpu *cpu; - int rc; - - spin_lock(&lock); - rc = smp_cpu_stop_nolock(addr, false); - if (!rc) { - cpu = smp_cpu_from_addr(addr); - free_pages(cpu->lowcore, 2 * PAGE_SIZE); - free_pages(cpu->stack, 4 * PAGE_SIZE); - cpu->lowcore = (void *)-1UL; - cpu->stack = (void *)-1UL; - } - spin_unlock(&lock); - return rc; -} - -int smp_cpu_setup(uint16_t addr, struct psw psw) -{ - struct lowcore *lc; - struct cpu *cpu; - int rc = -1; - - spin_lock(&lock); - - if (!cpus) - goto out; - - cpu = smp_cpu_from_addr(addr); - - if (!cpu || cpu->active) - goto out; - - sigp_retry(cpu->addr, SIGP_INITIAL_CPU_RESET, 0, NULL); - - lc = alloc_pages(1); - cpu->lowcore = lc; - memset(lc, 0, PAGE_SIZE * 2); - sigp_retry(cpu->addr, SIGP_SET_PREFIX, (unsigned long )lc, NULL); - - /* Copy all exception psws. */ - memcpy(lc, cpu0->lowcore, 512); - - /* Setup stack */ - cpu->stack = (uint64_t *)alloc_pages(2); - - /* Start without DAT and any other mask bits. */ - cpu->lowcore->sw_int_psw.mask = psw.mask; - cpu->lowcore->sw_int_psw.addr = psw.addr; - cpu->lowcore->sw_int_grs[14] = psw.addr; - cpu->lowcore->sw_int_grs[15] = (uint64_t)cpu->stack + (PAGE_SIZE * 4); - lc->restart_new_psw.mask = 0x0000000180000000UL; - lc->restart_new_psw.addr = (uint64_t)smp_cpu_setup_state; - lc->sw_int_crs[0] = 0x0000000000040000UL; - - /* Start processing */ - smp_cpu_restart_nolock(addr, NULL); - /* Wait until the cpu has finished setup and started the provided psw */ - while (lc->restart_new_psw.addr != psw.addr) - mb(); -out: - spin_unlock(&lock); - return rc; -} - -/* - * Disregarding state, stop all cpus that once were online except for - * calling cpu. - */ -void smp_teardown(void) -{ - int i = 0; - uint16_t this_cpu = stap(); - struct ReadCpuInfo *info = (void *)cpu_info_buffer; - - spin_lock(&lock); - for (; i < info->nr_configured; i++) { - if (cpus[i].active && - cpus[i].addr != this_cpu) { - sigp_retry(cpus[i].addr, SIGP_STOP, 0, NULL); - } - } - spin_unlock(&lock); -} - -/*Expected to be called from boot cpu */ -extern uint64_t *stackptr; -void smp_setup(void) -{ - int i = 0; - unsigned short cpu0_addr = stap(); - struct ReadCpuInfo *info = (void *)cpu_info_buffer; - - spin_lock(&lock); - sclp_mark_busy(); - info->h.length = PAGE_SIZE; - sclp_service_call(SCLP_READ_CPU_INFO, cpu_info_buffer); - - if (smp_query_num_cpus() > 1) - printf("SMP: Initializing, found %d cpus\n", info->nr_configured); - - cpus = calloc(info->nr_configured, sizeof(cpus)); - for (i = 0; i < info->nr_configured; i++) { - cpus[i].addr = info->entries[i].address; - cpus[i].active = false; - if (info->entries[i].address == cpu0_addr) { - cpu0 = &cpus[i]; - cpu0->stack = stackptr; - cpu0->lowcore = (void *)0; - cpu0->active = true; - } - } - spin_unlock(&lock); -} diff --git a/lib/s390x/smp.h b/lib/s390x/smp.h deleted file mode 100644 index d66e39ab..00000000 --- a/lib/s390x/smp.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * s390x smp - * - * Copyright (c) 2019 IBM Corp - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2. - */ -#ifndef SMP_H -#define SMP_H - -#include - -struct cpu { - struct lowcore *lowcore; - uint64_t *stack; - uint16_t addr; - bool active; -}; - -struct cpu_status { - uint64_t fprs[16]; /* 0x0000 */ - uint64_t grs[16]; /* 0x0080 */ - struct psw psw; /* 0x0100 */ - uint8_t pad_0x0110[0x0118 - 0x0110]; /* 0x0110 */ - uint32_t prefix; /* 0x0118 */ - uint32_t fpc; /* 0x011c */ - uint8_t pad_0x0120[0x0124 - 0x0120]; /* 0x0120 */ - uint32_t todpr; /* 0x0124 */ - uint64_t cputm; /* 0x0128 */ - uint64_t ckc; /* 0x0130 */ - uint8_t pad_0x0138[0x0140 - 0x0138]; /* 0x0138 */ - uint32_t ars[16]; /* 0x0140 */ - uint64_t crs[16]; /* 0x0384 */ -}; - -int smp_query_num_cpus(void); -struct cpu *smp_cpu_from_addr(uint16_t addr); -bool smp_cpu_stopped(uint16_t addr); -bool smp_sense_running_status(uint16_t addr); -int smp_cpu_restart(uint16_t addr); -int smp_cpu_start(uint16_t addr, struct psw psw); -int smp_cpu_stop(uint16_t addr); -int smp_cpu_stop_store_status(uint16_t addr); -int smp_cpu_destroy(uint16_t addr); -int smp_cpu_setup(uint16_t addr, struct psw psw); -void smp_teardown(void); -void smp_setup(void); - -#endif diff --git a/lib/s390x/stack.c b/lib/s390x/stack.c deleted file mode 100644 index cd34b20e..00000000 --- a/lib/s390x/stack.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * s390x stack implementation - * - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * Thomas Huth - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include - -int backtrace_frame(const void *frame, const void **return_addrs, int max_depth) -{ - printf("TODO: Implement backtrace_frame(%p, %p, %d) function!\n", - frame, return_addrs, max_depth); - return 0; -} - -int backtrace(const void **return_addrs, int max_depth) -{ - printf("TODO: Implement backtrace(%p, %d) function!\n", - return_addrs, max_depth); - return 0; -} diff --git a/lib/setjmp.h b/lib/setjmp.h deleted file mode 100644 index 2c56b4c6..00000000 --- a/lib/setjmp.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * setjmp/longjmp prototypes - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef LIBCFLAT_SETJMP_H -#define LIBCFLAT_SETJMP_H 1 - -typedef struct jmp_buf_tag { - long int regs[8]; -} jmp_buf[1]; - -extern int setjmp (struct jmp_buf_tag env[1]); -extern void longjmp (struct jmp_buf_tag env[1], int val) - __attribute__ ((__noreturn__)); - -#endif /* setjmp.h */ diff --git a/lib/stack.c b/lib/stack.c deleted file mode 100644 index bdb23fde..00000000 --- a/lib/stack.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * stack related functions - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -#include -#include - -#define MAX_DEPTH 20 - -static void print_stack(const void **return_addrs, int depth, - bool top_is_return_address) -{ - int i = 0; - - printf("\tSTACK:"); - - /* @addr indicates a non-return address, as expected by the stack - * pretty printer script. */ - if (depth > 0 && !top_is_return_address) { - printf(" @%lx", (unsigned long) return_addrs[0]); - i++; - } - - for (; i < depth; i++) { - printf(" %lx", (unsigned long) return_addrs[i]); - } - printf("\n"); -} - -void dump_stack(void) -{ - const void *return_addrs[MAX_DEPTH]; - int depth; - - depth = backtrace(return_addrs, MAX_DEPTH); - print_stack(&return_addrs[1], depth ? depth - 1 : 0, true); -} - -void dump_frame_stack(const void *instruction, const void *frame) -{ - const void *return_addrs[MAX_DEPTH]; - int depth; - - return_addrs[0] = instruction; - depth = backtrace_frame(frame, &return_addrs[1], MAX_DEPTH - 1); - print_stack(return_addrs, depth + 1, false); -} - -#ifndef HAVE_ARCH_BACKTRACE -int backtrace(const void **return_addrs, int max_depth) -{ - static int walking; - int depth = 0; - void *addr; - - if (walking) { - printf("RECURSIVE STACK WALK!!!\n"); - return 0; - } - walking = 1; - - /* __builtin_return_address requires a compile-time constant argument */ -#define GET_RETURN_ADDRESS(i) \ - if (max_depth == i) \ - goto done; \ - addr = __builtin_return_address(i); \ - if (!addr) \ - goto done; \ - return_addrs[i] = __builtin_extract_return_addr(addr); \ - depth = i + 1; \ - - GET_RETURN_ADDRESS(0) - GET_RETURN_ADDRESS(1) - GET_RETURN_ADDRESS(2) - GET_RETURN_ADDRESS(3) - GET_RETURN_ADDRESS(4) - GET_RETURN_ADDRESS(5) - GET_RETURN_ADDRESS(6) - GET_RETURN_ADDRESS(7) - GET_RETURN_ADDRESS(8) - GET_RETURN_ADDRESS(9) - GET_RETURN_ADDRESS(10) - GET_RETURN_ADDRESS(11) - GET_RETURN_ADDRESS(12) - GET_RETURN_ADDRESS(13) - GET_RETURN_ADDRESS(14) - GET_RETURN_ADDRESS(15) - GET_RETURN_ADDRESS(16) - GET_RETURN_ADDRESS(17) - GET_RETURN_ADDRESS(18) - GET_RETURN_ADDRESS(19) - GET_RETURN_ADDRESS(20) - -#undef GET_RETURN_ADDRESS - -done: - walking = 0; - return depth; -} -#endif /* HAVE_ARCH_BACKTRACE */ diff --git a/lib/stack.h b/lib/stack.h deleted file mode 100644 index 10fc2f79..00000000 --- a/lib/stack.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Header for stack related functions - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _STACK_H_ -#define _STACK_H_ - -#include -#include - -#ifdef HAVE_ARCH_BACKTRACE_FRAME -extern int backtrace_frame(const void *frame, const void **return_addrs, - int max_depth); -#else -static inline int -backtrace_frame(const void *frame __unused, const void **return_addrs __unused, - int max_depth __unused) -{ - return 0; -} -#endif - -extern int backtrace(const void **return_addrs, int max_depth); - -#endif diff --git a/lib/string.c b/lib/string.c deleted file mode 100644 index 018dcc87..00000000 --- a/lib/string.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * libc string functions - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -#include "libcflat.h" - -unsigned long strlen(const char *buf) -{ - unsigned long len = 0; - - while (*buf++) - ++len; - return len; -} - -char *strcat(char *dest, const char *src) -{ - char *p = dest; - - while (*p) - ++p; - while ((*p++ = *src++) != 0) - ; - return dest; -} - -char *strcpy(char *dest, const char *src) -{ - *dest = 0; - return strcat(dest, src); -} - -int strncmp(const char *a, const char *b, size_t n) -{ - for (; n--; ++a, ++b) - if (*a != *b || *a == '\0') - return *a - *b; - - return 0; -} - -int strcmp(const char *a, const char *b) -{ - return strncmp(a, b, SIZE_MAX); -} - -char *strchr(const char *s, int c) -{ - while (*s != (char)c) - if (*s++ == '\0') - return NULL; - return (char *)s; -} - -char *strstr(const char *s1, const char *s2) -{ - size_t l1, l2; - - l2 = strlen(s2); - if (!l2) - return (char *)s1; - l1 = strlen(s1); - while (l1 >= l2) { - l1--; - if (!memcmp(s1, s2, l2)) - return (char *)s1; - s1++; - } - return NULL; -} - -void *memset(void *s, int c, size_t n) -{ - size_t i; - char *a = s; - - for (i = 0; i < n; ++i) - a[i] = c; - - return s; -} - -void *memcpy(void *dest, const void *src, size_t n) -{ - size_t i; - char *a = dest; - const char *b = src; - - for (i = 0; i < n; ++i) - a[i] = b[i]; - - return dest; -} - -int memcmp(const void *s1, const void *s2, size_t n) -{ - const unsigned char *a = s1, *b = s2; - int ret = 0; - - while (n--) { - ret = *a - *b; - if (ret) - break; - ++a, ++b; - } - return ret; -} - -void *memmove(void *dest, const void *src, size_t n) -{ - const unsigned char *s = src; - unsigned char *d = dest; - - if (d <= s) { - while (n--) - *d++ = *s++; - } else { - d += n, s += n; - while (n--) - *--d = *--s; - } - return dest; -} - -void *memchr(const void *s, int c, size_t n) -{ - const unsigned char *str = s, chr = (unsigned char)c; - - while (n--) - if (*str++ == chr) - return (void *)(str - 1); - return NULL; -} - -long atol(const char *ptr) -{ - long acc = 0; - const char *s = ptr; - int neg, c; - - while (*s == ' ' || *s == '\t') - s++; - if (*s == '-'){ - neg = 1; - s++; - } else { - neg = 0; - if (*s == '+') - s++; - } - - while (*s) { - if (*s < '0' || *s > '9') - break; - c = *s - '0'; - acc = acc * 10 + c; - s++; - } - - if (neg) - acc = -acc; - - return acc; -} - -extern char **environ; - -char *getenv(const char *name) -{ - char **envp = environ, *delim; - - while (*envp) { - delim = strchr(*envp, '='); - if (delim && strncmp(name, *envp, delim - *envp) == 0) - return delim + 1; - ++envp; - } - return NULL; -} - -/* Very simple glob matching. Allows '*' at beginning and end of pattern. */ -bool simple_glob(const char *text, const char *pattern) -{ - bool star_start = false; - bool star_end = false; - size_t n = strlen(pattern); - char copy[n + 1]; - - if (pattern[0] == '*') { - pattern += 1; - n -= 1; - star_start = true; - } - - strcpy(copy, pattern); - - if (n > 0 && pattern[n - 1] == '*') { - n -= 1; - copy[n] = '\0'; - star_end = true; - } - - if (star_start && star_end) - return strstr(text, copy); - - if (star_end) - return strstr(text, copy) == text; - - if (star_start) { - size_t text_len = strlen(text); - const char *suffix; - - if (n > text_len) - return false; - suffix = text + text_len - n; - return !strcmp(suffix, copy); - } - - return !strcmp(text, copy); -} diff --git a/lib/string.h b/lib/string.h deleted file mode 100644 index 493d51ba..00000000 --- a/lib/string.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Header for libc string functions - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef __STRING_H -#define __STRING_H - -extern unsigned long strlen(const char *buf); -extern char *strcat(char *dest, const char *src); -extern char *strcpy(char *dest, const char *src); -extern int strcmp(const char *a, const char *b); -extern int strncmp(const char *a, const char *b, size_t n); -extern char *strchr(const char *s, int c); -extern char *strstr(const char *haystack, const char *needle); -extern void *memset(void *s, int c, size_t n); -extern void *memcpy(void *dest, const void *src, size_t n); -extern int memcmp(const void *s1, const void *s2, size_t n); -extern void *memmove(void *dest, const void *src, size_t n); -extern void *memchr(const void *s, int c, size_t n); - -#endif /* _STRING_H */ diff --git a/lib/util.c b/lib/util.c deleted file mode 100644 index a9055413..00000000 --- a/lib/util.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include "util.h" - -int parse_keyval(char *s, long *val) -{ - char *p; - - p = strchr(s, '='); - if (!p) - return -1; - - *val = atol(p+1); - return p - s; -} diff --git a/lib/util.h b/lib/util.h deleted file mode 100644 index 4c4b4413..00000000 --- a/lib/util.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _UTIL_H_ -#define _UTIL_H_ -/* - * Collection of utility functions to share between unit tests. - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ - -/* - * parse_keyval extracts the integer from a string formatted as - * string=integer. This is useful for passing expected values to - * the unit test on the command line, i.e. it helps parse QEMU - * command lines that include something like -append var1=1 var2=2 - * @s is the input string, likely a command line parameter, and - * @val is a pointer to where the integer will be stored. - * - * Returns the offset of the '=', or -1 if no keyval pair is found. - */ -extern int parse_keyval(char *s, long *val); - -#endif diff --git a/lib/virtio-mmio.c b/lib/virtio-mmio.c deleted file mode 100644 index e5e8f660..00000000 --- a/lib/virtio-mmio.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * virtqueue support adapted from the Linux kernel. - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include "libcflat.h" -#include "devicetree.h" -#include "alloc_page.h" -#include "alloc.h" -#include "asm/page.h" -#include "asm/io.h" -#include "virtio.h" -#include "virtio-mmio.h" - -static void vm_get(struct virtio_device *vdev, unsigned offset, - void *buf, unsigned len) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - u8 *p = buf; - unsigned i; - - for (i = 0; i < len; ++i) - p[i] = readb(vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i); -} - -static void vm_set(struct virtio_device *vdev, unsigned offset, - const void *buf, unsigned len) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - const u8 *p = buf; - unsigned i; - - for (i = 0; i < len; ++i) - writeb(p[i], vm_dev->base + VIRTIO_MMIO_CONFIG + offset + i); -} - -static bool vm_notify(struct virtqueue *vq) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vq->vdev); - writel(vq->index, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY); - return true; -} - -static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, - unsigned index, - void (*callback)(struct virtqueue *vq), - const char *name) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - struct vring_virtqueue *vq; - void *queue; - unsigned num = VIRTIO_MMIO_QUEUE_NUM_MIN; - - vq = calloc(1, sizeof(*vq)); - assert(VIRTIO_MMIO_QUEUE_SIZE_MIN <= 2*PAGE_SIZE); - queue = alloc_pages(1); - assert(vq && queue); - - writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL); - - assert(readl(vm_dev->base + VIRTIO_MMIO_QUEUE_NUM_MAX) >= num); - - if (readl(vm_dev->base + VIRTIO_MMIO_QUEUE_PFN) != 0) { - printf("%s: virtqueue %d already setup! base=%p\n", - __func__, index, vm_dev->base); - return NULL; - } - - writel(num, vm_dev->base + VIRTIO_MMIO_QUEUE_NUM); - writel(VIRTIO_MMIO_VRING_ALIGN, - vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN); - writel(virt_to_pfn(queue), vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); - - vring_init_virtqueue(vq, index, num, VIRTIO_MMIO_VRING_ALIGN, - vdev, queue, vm_notify, callback, name); - - return &vq->vq; -} - -static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs, - struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char *names[]) -{ - unsigned i; - - for (i = 0; i < nvqs; ++i) { - vqs[i] = vm_setup_vq(vdev, i, - callbacks ? callbacks[i] : NULL, - names ? names[i] : ""); - if (vqs[i] == NULL) - return -1; - } - - return 0; -} - -static const struct virtio_config_ops vm_config_ops = { - .get = vm_get, - .set = vm_set, - .find_vqs = vm_find_vqs, -}; - -static void vm_device_init(struct virtio_mmio_device *vm_dev) -{ - vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID); - vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID); - vm_dev->vdev.config = &vm_config_ops; - - writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE); -} - -/****************************************************** - * virtio-mmio device tree support - ******************************************************/ - -struct vm_dt_info { - u32 devid; - void *base; -}; - -static int vm_dt_match(const struct dt_device *dev, int fdtnode) -{ - struct vm_dt_info *info = (struct vm_dt_info *)dev->info; - struct dt_pbus_reg base; - u32 magic; - int ret; - - dt_device_bind_node((struct dt_device *)dev, fdtnode); - - ret = dt_pbus_get_base(dev, &base); - assert(ret == 0); - info->base = ioremap(base.addr, base.size); - - magic = readl(info->base + VIRTIO_MMIO_MAGIC_VALUE); - if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) - return false; - - return readl(info->base + VIRTIO_MMIO_DEVICE_ID) == info->devid; -} - -static struct virtio_device *virtio_mmio_dt_bind(u32 devid) -{ - struct virtio_mmio_device *vm_dev; - struct dt_device dt_dev; - struct dt_bus dt_bus; - struct vm_dt_info info; - int node; - - if (!dt_available()) - return NULL; - - dt_bus_init_defaults(&dt_bus); - dt_bus.match = vm_dt_match; - - info.devid = devid; - - dt_device_init(&dt_dev, &dt_bus, &info); - - node = dt_device_find_compatible(&dt_dev, "virtio,mmio"); - assert(node >= 0 || node == -FDT_ERR_NOTFOUND); - - if (node == -FDT_ERR_NOTFOUND) - return NULL; - - vm_dev = calloc(1, sizeof(*vm_dev)); - assert(vm_dev != NULL); - - vm_dev->base = info.base; - vm_device_init(vm_dev); - - return &vm_dev->vdev; -} - -struct virtio_device *virtio_mmio_bind(u32 devid) -{ - return virtio_mmio_dt_bind(devid); -} diff --git a/lib/virtio-mmio.h b/lib/virtio-mmio.h deleted file mode 100644 index 250f28a0..00000000 --- a/lib/virtio-mmio.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef _VIRTIO_MMIO_H_ -#define _VIRTIO_MMIO_H_ -/* - * A minimal implementation of virtio-mmio. Adapted from the Linux Kernel. - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include "libcflat.h" -#include "asm/page.h" -#include "virtio.h" - -#define VIRTIO_MMIO_MAGIC_VALUE 0x000 -#define VIRTIO_MMIO_VERSION 0x004 -#define VIRTIO_MMIO_DEVICE_ID 0x008 -#define VIRTIO_MMIO_VENDOR_ID 0x00c -#define VIRTIO_MMIO_HOST_FEATURES 0x010 -#define VIRTIO_MMIO_HOST_FEATURES_SEL 0x014 -#define VIRTIO_MMIO_GUEST_FEATURES 0x020 -#define VIRTIO_MMIO_GUEST_FEATURES_SEL 0x024 -#define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 -#define VIRTIO_MMIO_QUEUE_SEL 0x030 -#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 -#define VIRTIO_MMIO_QUEUE_NUM 0x038 -#define VIRTIO_MMIO_QUEUE_ALIGN 0x03c -#define VIRTIO_MMIO_QUEUE_PFN 0x040 -#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 -#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 -#define VIRTIO_MMIO_INTERRUPT_ACK 0x064 -#define VIRTIO_MMIO_STATUS 0x070 -#define VIRTIO_MMIO_CONFIG 0x100 - -#define VIRTIO_MMIO_INT_VRING (1 << 0) -#define VIRTIO_MMIO_INT_CONFIG (1 << 1) - -#define VIRTIO_MMIO_VRING_ALIGN PAGE_SIZE - -/* - * The minimum queue size is 2*VIRTIO_MMIO_VRING_ALIGN, which - * means the largest queue num for the minimum queue size is 128, i.e. - * 2*VIRTIO_MMIO_VRING_ALIGN = vring_size(128, VIRTIO_MMIO_VRING_ALIGN), - * where vring_size is - * - * unsigned vring_size(unsigned num, unsigned long align) - * { - * return ((sizeof(struct vring_desc) * num + sizeof(u16) * (3 + num) - * + align - 1) & ~(align - 1)) - * + sizeof(u16) * 3 + sizeof(struct vring_used_elem) * num; - * } - */ -#define VIRTIO_MMIO_QUEUE_SIZE_MIN (2*VIRTIO_MMIO_VRING_ALIGN) -#define VIRTIO_MMIO_QUEUE_NUM_MIN 128 - -#define to_virtio_mmio_device(vdev_ptr) \ - container_of(vdev_ptr, struct virtio_mmio_device, vdev) - -struct virtio_mmio_device { - struct virtio_device vdev; - void *base; -}; - -extern struct virtio_device *virtio_mmio_bind(u32 devid); - -#endif /* _VIRTIO_MMIO_H_ */ diff --git a/lib/virtio.c b/lib/virtio.c deleted file mode 100644 index 69054757..00000000 --- a/lib/virtio.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * virtqueue support adapted from the Linux kernel. - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include "libcflat.h" -#include "asm/io.h" -#include "virtio.h" -#include "virtio-mmio.h" - -void vring_init(struct vring *vr, unsigned int num, void *p, - unsigned long align) -{ - vr->num = num; - vr->desc = p; - vr->avail = p + num*sizeof(struct vring_desc); - vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + sizeof(u16) - + align-1) & ~(align - 1)); -} - -void vring_init_virtqueue(struct vring_virtqueue *vq, unsigned index, - unsigned num, unsigned vring_align, - struct virtio_device *vdev, void *pages, - bool (*notify)(struct virtqueue *), - void (*callback)(struct virtqueue *), - const char *name) -{ - unsigned i; - - vring_init(&vq->vring, num, pages, vring_align); - vq->vq.callback = callback; - vq->vq.vdev = vdev; - vq->vq.name = name; - vq->vq.num_free = num; - vq->vq.index = index; - vq->notify = notify; - vq->last_used_idx = 0; - vq->num_added = 0; - vq->free_head = 0; - - for (i = 0; i < num-1; i++) { - vq->vring.desc[i].next = i+1; - vq->data[i] = NULL; - } - vq->data[i] = NULL; -} - -int virtqueue_add_outbuf(struct virtqueue *_vq, char *buf, unsigned int len) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - unsigned avail; - int head; - - assert(buf != NULL); - assert(len != 0); - - if (!vq->vq.num_free) - return -1; - - --vq->vq.num_free; - - head = vq->free_head; - - vq->vring.desc[head].flags = 0; - vq->vring.desc[head].addr = virt_to_phys(buf); - vq->vring.desc[head].len = len; - - vq->free_head = vq->vring.desc[head].next; - - vq->data[head] = buf; - - avail = (vq->vring.avail->idx & (vq->vring.num-1)); - vq->vring.avail->ring[avail] = head; - wmb(); - vq->vring.avail->idx++; - vq->num_added++; - - return 0; -} - -bool virtqueue_kick(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - mb(); - return vq->notify(_vq); -} - -void detach_buf(struct vring_virtqueue *vq, unsigned head) -{ - unsigned i = head; - - vq->data[head] = NULL; - - while (vq->vring.desc[i].flags & VRING_DESC_F_NEXT) { - i = vq->vring.desc[i].next; - vq->vq.num_free++; - } - - vq->vring.desc[i].next = vq->free_head; - vq->free_head = head; - vq->vq.num_free++; -} - -void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - u16 last_used; - unsigned i; - void *ret; - - rmb(); - - last_used = (vq->last_used_idx & (vq->vring.num-1)); - i = vq->vring.used->ring[last_used].id; - *len = vq->vring.used->ring[last_used].len; - - ret = vq->data[i]; - detach_buf(vq, i); - - vq->last_used_idx++; - - return ret; -} - -struct virtio_device *virtio_bind(u32 devid) -{ - return virtio_mmio_bind(devid); -} diff --git a/lib/virtio.h b/lib/virtio.h deleted file mode 100644 index 2c31fdc7..00000000 --- a/lib/virtio.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef _VIRTIO_H_ -#define _VIRTIO_H_ -/* - * A minimal implementation of virtio. - * Structures adapted from the Linux Kernel. - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ -#include "libcflat.h" - -#define VIRTIO_ID_CONSOLE 3 - -struct virtio_device_id { - u32 device; - u32 vendor; -}; - -struct virtio_device { - struct virtio_device_id id; - const struct virtio_config_ops *config; -}; - -struct virtqueue { - void (*callback)(struct virtqueue *vq); - const char *name; - struct virtio_device *vdev; - unsigned int index; - unsigned int num_free; - void *priv; -}; - -typedef void vq_callback_t(struct virtqueue *); -struct virtio_config_ops { - void (*get)(struct virtio_device *vdev, unsigned offset, - void *buf, unsigned len); - void (*set)(struct virtio_device *vdev, unsigned offset, - const void *buf, unsigned len); - int (*find_vqs)(struct virtio_device *vdev, unsigned nvqs, - struct virtqueue *vqs[], - vq_callback_t *callbacks[], - const char *names[]); -}; - -static inline u8 -virtio_config_readb(struct virtio_device *vdev, unsigned offset) -{ - u8 val; - vdev->config->get(vdev, offset, &val, 1); - return val; -} - -static inline u16 -virtio_config_readw(struct virtio_device *vdev, unsigned offset) -{ - u16 val; - vdev->config->get(vdev, offset, &val, 2); - return val; -} - -static inline u32 -virtio_config_readl(struct virtio_device *vdev, unsigned offset) -{ - u32 val; - vdev->config->get(vdev, offset, &val, 4); - return val; -} - -static inline void -virtio_config_writeb(struct virtio_device *vdev, unsigned offset, u8 val) -{ - vdev->config->set(vdev, offset, &val, 1); -} - -static inline void -virtio_config_writew(struct virtio_device *vdev, unsigned offset, u16 val) -{ - vdev->config->set(vdev, offset, &val, 2); -} - -static inline void -virtio_config_writel(struct virtio_device *vdev, unsigned offset, u32 val) -{ - vdev->config->set(vdev, offset, &val, 4); -} - -#define VRING_DESC_F_NEXT 1 -#define VRING_DESC_F_WRITE 2 - -struct vring_desc { - u64 addr; - u32 len; - u16 flags; - u16 next; -}; - -struct vring_avail { - u16 flags; - u16 idx; - u16 ring[]; -}; - -struct vring_used_elem { - u32 id; - u32 len; -}; - -struct vring_used { - u16 flags; - u16 idx; - struct vring_used_elem ring[]; -}; - -struct vring { - unsigned int num; - struct vring_desc *desc; - struct vring_avail *avail; - struct vring_used *used; -}; - -struct vring_virtqueue { - struct virtqueue vq; - struct vring vring; - unsigned int free_head; - unsigned int num_added; - u16 last_used_idx; - bool (*notify)(struct virtqueue *vq); - void *data[]; -}; - -#define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq) - -extern void vring_init(struct vring *vr, unsigned int num, void *p, - unsigned long align); -extern void vring_init_virtqueue(struct vring_virtqueue *vq, unsigned index, - unsigned num, unsigned vring_align, - struct virtio_device *vdev, void *pages, - bool (*notify)(struct virtqueue *), - void (*callback)(struct virtqueue *), - const char *name); -extern int virtqueue_add_outbuf(struct virtqueue *vq, char *buf, - unsigned int len); -extern bool virtqueue_kick(struct virtqueue *vq); -extern void detach_buf(struct vring_virtqueue *vq, unsigned head); -extern void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len); - -extern struct virtio_device *virtio_bind(u32 devid); - -#endif /* _VIRTIO_H_ */ diff --git a/lib/vmalloc.c b/lib/vmalloc.c deleted file mode 100644 index e0c7b6b4..00000000 --- a/lib/vmalloc.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2012, 2017, Red Hat Inc. - * - * This allocator provides contiguous physical addresses with page - * granularity. - */ - -#include "libcflat.h" -#include "asm/spinlock.h" -#include "asm/page.h" -#include "asm/io.h" -#include "alloc.h" -#include "alloc_phys.h" -#include "alloc_page.h" -#include -#include "vmalloc.h" - -static struct spinlock lock; -static void *vfree_top = 0; -static void *page_root; - -/* - * Allocate a certain number of pages from the virtual address space (without - * physical backing). - * - * nr is the number of pages to allocate - * alignment_pages is the alignment of the allocation *in pages* - */ -void *alloc_vpages_aligned(ulong nr, unsigned int align_order) -{ - uintptr_t ptr; - - spin_lock(&lock); - ptr = (uintptr_t)vfree_top; - ptr -= PAGE_SIZE * nr; - ptr &= GENMASK_ULL(63, PAGE_SHIFT + align_order); - vfree_top = (void *)ptr; - spin_unlock(&lock); - - /* Cannot return vfree_top here, we are outside the lock! */ - return (void *)ptr; -} - -void *alloc_vpages(ulong nr) -{ - return alloc_vpages_aligned(nr, 0); -} - -void *alloc_vpage(void) -{ - return alloc_vpages(1); -} - -void *vmap(phys_addr_t phys, size_t size) -{ - void *mem, *p; - size_t pages; - - size = PAGE_ALIGN(size); - pages = size / PAGE_SIZE; - mem = p = alloc_vpages(pages); - - phys &= ~(unsigned long long)(PAGE_SIZE - 1); - while (pages--) { - install_page(page_root, phys, p); - phys += PAGE_SIZE; - p += PAGE_SIZE; - } - return mem; -} - -/* - * Allocate virtual memory, with the specified minimum alignment. - */ -static void *vm_memalign(size_t alignment, size_t size) -{ - phys_addr_t pa; - void *mem, *p; - - assert(is_power_of_2(alignment)); - - size = PAGE_ALIGN(size) / PAGE_SIZE; - alignment = get_order(PAGE_ALIGN(alignment) / PAGE_SIZE); - mem = p = alloc_vpages_aligned(size, alignment); - while (size--) { - pa = virt_to_phys(alloc_page()); - assert(pa); - install_page(page_root, pa, p); - p += PAGE_SIZE; - } - return mem; -} - -static void vm_free(void *mem, size_t size) -{ - while (size) { - free_page(phys_to_virt(virt_to_pte_phys(page_root, mem))); - mem += PAGE_SIZE; - size -= PAGE_SIZE; - } -} - -static struct alloc_ops vmalloc_ops = { - .memalign = vm_memalign, - .free = vm_free, - .align_min = PAGE_SIZE, -}; - -void __attribute__((__weak__)) find_highmem(void) -{ -} - -void init_alloc_vpage(void *top) -{ - spin_lock(&lock); - assert(alloc_ops != &vmalloc_ops); - vfree_top = top; - spin_unlock(&lock); -} - -void setup_vm() -{ - phys_addr_t base, top; - - if (alloc_ops == &vmalloc_ops) - return; - - phys_alloc_get_unused(&base, &top); - assert(base != top || page_alloc_initialized()); - /* - * Give low memory immediately to the page allocator, - * so that it can be used to allocate page tables. - */ - if (!page_alloc_initialized()) { - base = PAGE_ALIGN(base); - top = top & -PAGE_SIZE; - free_pages(phys_to_virt(base), top - base); - } - - find_highmem(); - phys_alloc_get_unused(&base, &top); - page_root = setup_mmu(top); - if (base != top) { - base = PAGE_ALIGN(base); - top = top & -PAGE_SIZE; - free_pages(phys_to_virt(base), top - base); - } - - spin_lock(&lock); - assert(alloc_ops != &vmalloc_ops); - alloc_ops = &vmalloc_ops; - spin_unlock(&lock); -} diff --git a/lib/vmalloc.h b/lib/vmalloc.h deleted file mode 100644 index 8b158f59..00000000 --- a/lib/vmalloc.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef VMALLOC_H -#define VMALLOC_H 1 - -#include - -/* Allocate consecutive virtual pages (without backing) */ -extern void *alloc_vpages(ulong nr); -/* Allocate consecutive and aligned virtual pages (without backing) */ -extern void *alloc_vpages_aligned(ulong nr, unsigned int alignment_order); - -/* Allocate one virtual page (without backing) */ -extern void *alloc_vpage(void); -/* Set the top of the virtual address space */ -extern void init_alloc_vpage(void *top); -/* Set up the virtual allocator; also sets up the page allocator if needed */ -extern void setup_vm(void); - -/* Set up paging */ -extern void *setup_mmu(phys_addr_t top); -/* Walk the page table and resolve the virtual address to a physical address */ -extern phys_addr_t virt_to_pte_phys(pgd_t *pgtable, void *virt); -/* Map the virtual address to the physical address for the given page tables */ -extern pteval_t *install_page(pgd_t *pgtable, phys_addr_t phys, void *virt); - -/* Map consecutive physical pages */ -void *vmap(phys_addr_t phys, size_t size); - -#endif diff --git a/lib/x86/acpi.c b/lib/x86/acpi.c deleted file mode 100644 index 43731062..00000000 --- a/lib/x86/acpi.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "libcflat.h" -#include "acpi.h" - -void* find_acpi_table_addr(u32 sig) -{ - unsigned long addr; - struct rsdp_descriptor *rsdp; - struct rsdt_descriptor_rev1 *rsdt; - void *end; - int i; - - /* FACS is special... */ - if (sig == FACS_SIGNATURE) { - struct fadt_descriptor_rev1 *fadt; - fadt = find_acpi_table_addr(FACP_SIGNATURE); - if (!fadt) { - return NULL; - } - return (void*)(ulong)fadt->firmware_ctrl; - } - - for(addr = 0xf0000; addr < 0x100000; addr += 16) { - rsdp = (void*)addr; - if (rsdp->signature == 0x2052545020445352LL) - break; - } - if (addr == 0x100000) { - printf("Can't find RSDP\n"); - return 0; - } - - if (sig == RSDP_SIGNATURE) { - return rsdp; - } - - rsdt = (void*)(ulong)rsdp->rsdt_physical_address; - if (!rsdt || rsdt->signature != RSDT_SIGNATURE) - return 0; - - if (sig == RSDT_SIGNATURE) { - return rsdt; - } - - end = (void*)rsdt + rsdt->length; - for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) { - struct acpi_table *t = (void*)(ulong)rsdt->table_offset_entry[i]; - if (t && t->signature == sig) { - return t; - } - } - return NULL; -} diff --git a/lib/x86/acpi.h b/lib/x86/acpi.h deleted file mode 100644 index 08aaf57a..00000000 --- a/lib/x86/acpi.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef KVM_ACPI_H -#define KVM_ACPI_H 1 - -#include "libcflat.h" - -#define ACPI_SIGNATURE(c1, c2, c3, c4) \ - ((c1) | ((c2) << 8) | ((c3) << 16) | ((c4) << 24)) - -#define RSDP_SIGNATURE ACPI_SIGNATURE('R','S','D','P') -#define RSDT_SIGNATURE ACPI_SIGNATURE('R','S','D','T') -#define FACP_SIGNATURE ACPI_SIGNATURE('F','A','C','P') -#define FACS_SIGNATURE ACPI_SIGNATURE('F','A','C','S') - -struct rsdp_descriptor { /* Root System Descriptor Pointer */ - u64 signature; /* ACPI signature, contains "RSD PTR " */ - u8 checksum; /* To make sum of struct == 0 */ - u8 oem_id [6]; /* OEM identification */ - u8 revision; /* Must be 0 for 1.0, 2 for 2.0 */ - u32 rsdt_physical_address; /* 32-bit physical address of RSDT */ - u32 length; /* XSDT Length in bytes including hdr */ - u64 xsdt_physical_address; /* 64-bit physical address of XSDT */ - u8 extended_checksum; /* Checksum of entire table */ - u8 reserved [3]; /* Reserved field must be 0 */ -}; - -#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \ - u32 signature; /* ACPI signature (4 ASCII characters) */ \ - u32 length; /* Length of table, in bytes, including header */ \ - u8 revision; /* ACPI Specification minor version # */ \ - u8 checksum; /* To make sum of entire table == 0 */ \ - u8 oem_id [6]; /* OEM identification */ \ - u8 oem_table_id [8]; /* OEM table identification */ \ - u32 oem_revision; /* OEM revision number */ \ - u8 asl_compiler_id [4]; /* ASL compiler vendor ID */ \ - u32 asl_compiler_revision; /* ASL compiler revision number */ - -struct acpi_table { - ACPI_TABLE_HEADER_DEF - char data[0]; -}; - -struct rsdt_descriptor_rev1 { - ACPI_TABLE_HEADER_DEF - u32 table_offset_entry[0]; -}; - -struct fadt_descriptor_rev1 -{ - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - u32 firmware_ctrl; /* Physical address of FACS */ - u32 dsdt; /* Physical address of DSDT */ - u8 model; /* System Interrupt Model */ - u8 reserved1; /* Reserved */ - u16 sci_int; /* System vector of SCI interrupt */ - u32 smi_cmd; /* Port address of SMI command port */ - u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ - u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ - u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ - u8 reserved2; /* Reserved - must be zero */ - u32 pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ - u32 pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ - u32 pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ - u32 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ - u32 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ - u32 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ - u32 gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ - u32 gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ - u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ - u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ - u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ - u8 pm_tmr_len; /* Byte Length of ports at pm_tm_blk */ - u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ - u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ - u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ - u8 reserved3; /* Reserved */ - u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ - u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ - u16 flush_size; /* Size of area read to flush caches */ - u16 flush_stride; /* Stride used in flushing caches */ - u8 duty_offset; /* Bit location of duty cycle field in p_cnt reg */ - u8 duty_width; /* Bit width of duty cycle field in p_cnt reg */ - u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ - u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ - u8 century; /* Index to century in RTC CMOS RAM */ - u8 reserved4; /* Reserved */ - u8 reserved4a; /* Reserved */ - u8 reserved4b; /* Reserved */ -}; - -struct facs_descriptor_rev1 -{ - u32 signature; /* ACPI Signature */ - u32 length; /* Length of structure, in bytes */ - u32 hardware_signature; /* Hardware configuration signature */ - u32 firmware_waking_vector; /* ACPI OS waking vector */ - u32 global_lock; /* Global Lock */ - u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */ - u32 reserved1 : 31; /* Must be 0 */ - u8 reserved3 [40]; /* Reserved - must be zero */ -}; - -void* find_acpi_table_addr(u32 sig); - -#endif diff --git a/lib/x86/apic-defs.h b/lib/x86/apic-defs.h deleted file mode 100644 index b2014de8..00000000 --- a/lib/x86/apic-defs.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef _ASM_X86_APICDEF_H -#define _ASM_X86_APICDEF_H - -/* - * Abuse this header file to hold the number of max-cpus, making it available - * both in C and ASM - */ - -#define MAX_TEST_CPUS (255) - -/* - * Constants for various Intel APICs. (local APIC, IOAPIC, etc.) - * - * Alan Cox , 1995. - * Ingo Molnar , 1999, 2000 - */ - -#define APIC_DEFAULT_PHYS_BASE 0xfee00000 -#define APIC_BSP (1UL << 8) -#define APIC_EXTD (1UL << 10) -#define APIC_EN (1UL << 11) - -#define APIC_ID 0x20 - -#define APIC_LVR 0x30 -#define APIC_LVR_MASK 0xFF00FF -#define GET_APIC_VERSION(x) ((x) & 0xFFu) -#define GET_APIC_MAXLVT(x) (((x) >> 16) & 0xFFu) -#ifdef CONFIG_X86_32 -# define APIC_INTEGRATED(x) ((x) & 0xF0u) -#else -# define APIC_INTEGRATED(x) (1) -#endif -#define APIC_XAPIC(x) ((x) >= 0x14) -#define APIC_TASKPRI 0x80 -#define APIC_TPRI_MASK 0xFFu -#define APIC_ARBPRI 0x90 -#define APIC_ARBPRI_MASK 0xFFu -#define APIC_PROCPRI 0xA0 -#define APIC_EOI 0xB0 -#define APIC_EIO_ACK 0x0 -#define APIC_RRR 0xC0 -#define APIC_LDR 0xD0 -#define APIC_LDR_MASK (0xFFu << 24) -#define GET_APIC_LOGICAL_ID(x) (((x) >> 24) & 0xFFu) -#define SET_APIC_LOGICAL_ID(x) (((x) << 24)) -#define APIC_ALL_CPUS 0xFFu -#define APIC_DFR 0xE0 -#define APIC_DFR_CLUSTER 0x0FFFFFFFul -#define APIC_DFR_FLAT 0xFFFFFFFFul -#define APIC_SPIV 0xF0 -#define APIC_SPIV_FOCUS_DISABLED (1 << 9) -#define APIC_SPIV_APIC_ENABLED (1 << 8) -#define APIC_ISR 0x100 -#define APIC_ISR_NR 0x8 /* Number of 32 bit ISR registers. */ -#define APIC_TMR 0x180 -#define APIC_IRR 0x200 -#define APIC_ESR 0x280 -#define APIC_ESR_SEND_CS 0x00001 -#define APIC_ESR_RECV_CS 0x00002 -#define APIC_ESR_SEND_ACC 0x00004 -#define APIC_ESR_RECV_ACC 0x00008 -#define APIC_ESR_SENDILL 0x00020 -#define APIC_ESR_RECVILL 0x00040 -#define APIC_ESR_ILLREGA 0x00080 -#define APIC_CMCI 0x2F0 -#define APIC_ICR 0x300 -#define APIC_DEST_SELF 0x40000 -#define APIC_DEST_ALLINC 0x80000 -#define APIC_DEST_ALLBUT 0xC0000 -#define APIC_ICR_RR_MASK 0x30000 -#define APIC_ICR_RR_INVALID 0x00000 -#define APIC_ICR_RR_INPROG 0x10000 -#define APIC_ICR_RR_VALID 0x20000 -#define APIC_INT_LEVELTRIG 0x08000 -#define APIC_INT_ASSERT 0x04000 -#define APIC_ICR_BUSY 0x01000 -#define APIC_DEST_LOGICAL 0x00800 -#define APIC_DEST_PHYSICAL 0x00000 -#define APIC_DM_FIXED 0x00000 -#define APIC_DM_LOWEST 0x00100 -#define APIC_DM_SMI 0x00200 -#define APIC_DM_REMRD 0x00300 -#define APIC_DM_NMI 0x00400 -#define APIC_DM_INIT 0x00500 -#define APIC_DM_STARTUP 0x00600 -#define APIC_DM_EXTINT 0x00700 -#define APIC_VECTOR_MASK 0x000FF -#define APIC_ICR2 0x310 -#define GET_APIC_DEST_FIELD(x) (((x) >> 24) & 0xFF) -#define SET_APIC_DEST_FIELD(x) ((x) << 24) -#define APIC_LVTT 0x320 -#define APIC_LVTTHMR 0x330 -#define APIC_LVTPC 0x340 -#define APIC_LVT0 0x350 -#define APIC_LVT_TIMER_BASE_MASK (0x3 << 18) -#define GET_APIC_TIMER_BASE(x) (((x) >> 18) & 0x3) -#define SET_APIC_TIMER_BASE(x) (((x) << 18)) -#define APIC_TIMER_BASE_CLKIN 0x0 -#define APIC_TIMER_BASE_TMBASE 0x1 -#define APIC_TIMER_BASE_DIV 0x2 -#define APIC_LVT_TIMER_MASK (3 << 17) -#define APIC_LVT_TIMER_ONESHOT (0 << 17) -#define APIC_LVT_TIMER_PERIODIC (1 << 17) -#define APIC_LVT_TIMER_TSCDEADLINE (2 << 17) -#define APIC_LVT_MASKED (1 << 16) -#define APIC_LVT_LEVEL_TRIGGER (1 << 15) -#define APIC_LVT_REMOTE_IRR (1 << 14) -#define APIC_INPUT_POLARITY (1 << 13) -#define APIC_SEND_PENDING (1 << 12) -#define APIC_MODE_MASK 0x700 -#define GET_APIC_DELIVERY_MODE(x) (((x) >> 8) & 0x7) -#define SET_APIC_DELIVERY_MODE(x, y) (((x) & ~0x700) | ((y) << 8)) -#define APIC_MODE_FIXED 0x0 -#define APIC_MODE_NMI 0x4 -#define APIC_MODE_EXTINT 0x7 -#define APIC_LVT1 0x360 -#define APIC_LVTERR 0x370 -#define APIC_TMICT 0x380 -#define APIC_TMCCT 0x390 -#define APIC_TDCR 0x3E0 -#define APIC_SELF_IPI 0x3F0 -#define APIC_TDR_DIV_TMBASE (1 << 2) -#define APIC_TDR_DIV_1 0xB -#define APIC_TDR_DIV_2 0x0 -#define APIC_TDR_DIV_4 0x1 -#define APIC_TDR_DIV_8 0x2 -#define APIC_TDR_DIV_16 0x3 -#define APIC_TDR_DIV_32 0x8 -#define APIC_TDR_DIV_64 0x9 -#define APIC_TDR_DIV_128 0xA -#define APIC_EILVT0 0x500 -#define APIC_EILVT_NR_AMD_K8 1 /* # of extended interrupts */ -#define APIC_EILVT_NR_AMD_10H 4 -#define APIC_EILVT_LVTOFF(x) (((x) >> 4) & 0xF) -#define APIC_EILVT_MSG_FIX 0x0 -#define APIC_EILVT_MSG_SMI 0x2 -#define APIC_EILVT_MSG_NMI 0x4 -#define APIC_EILVT_MSG_EXT 0x7 -#define APIC_EILVT_MASKED (1 << 16) -#define APIC_EILVT1 0x510 -#define APIC_EILVT2 0x520 -#define APIC_EILVT3 0x530 - -#define APIC_BASE_MSR 0x800 - -#endif /* _ASM_X86_APICDEF_H */ diff --git a/lib/x86/apic.c b/lib/x86/apic.c deleted file mode 100644 index f43e9ef0..00000000 --- a/lib/x86/apic.c +++ /dev/null @@ -1,245 +0,0 @@ -#include "libcflat.h" -#include "apic.h" -#include "msr.h" -#include "processor.h" -#include "asm/barrier.h" - -void *g_apic = (void *)0xfee00000; -void *g_ioapic = (void *)0xfec00000; -u8 id_map[MAX_TEST_CPUS]; - -struct apic_ops { - u32 (*reg_read)(unsigned reg); - void (*reg_write)(unsigned reg, u32 val); - void (*icr_write)(u32 val, u32 dest); - u32 (*id)(void); -}; - -static void outb(unsigned char data, unsigned short port) -{ - asm volatile ("out %0, %1" : : "a"(data), "d"(port)); -} - -void eoi(void) -{ - apic_write(APIC_EOI, 0); -} - -static u32 xapic_read(unsigned reg) -{ - return *(volatile u32 *)(g_apic + reg); -} - -static void xapic_write(unsigned reg, u32 val) -{ - *(volatile u32 *)(g_apic + reg) = val; -} - -static void xapic_icr_write(u32 val, u32 dest) -{ - while (xapic_read(APIC_ICR) & APIC_ICR_BUSY) - ; - xapic_write(APIC_ICR2, dest << 24); - xapic_write(APIC_ICR, val); -} - -static uint32_t xapic_id(void) -{ - return xapic_read(APIC_ID) >> 24; -} - -static const struct apic_ops xapic_ops = { - .reg_read = xapic_read, - .reg_write = xapic_write, - .icr_write = xapic_icr_write, - .id = xapic_id, -}; - -static const struct apic_ops *apic_ops = &xapic_ops; - -static u32 x2apic_read(unsigned reg) -{ - unsigned a, d; - - asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(APIC_BASE_MSR + reg/16)); - return a | (u64)d << 32; -} - -static void x2apic_write(unsigned reg, u32 val) -{ - asm volatile ("wrmsr" : : "a"(val), "d"(0), "c"(APIC_BASE_MSR + reg/16)); -} - -static void x2apic_icr_write(u32 val, u32 dest) -{ - mb(); - asm volatile ("wrmsr" : : "a"(val), "d"(dest), - "c"(APIC_BASE_MSR + APIC_ICR/16)); -} - -static uint32_t x2apic_id(void) -{ - return x2apic_read(APIC_ID); -} - -static const struct apic_ops x2apic_ops = { - .reg_read = x2apic_read, - .reg_write = x2apic_write, - .icr_write = x2apic_icr_write, - .id = x2apic_id, -}; - -u32 apic_read(unsigned reg) -{ - return apic_ops->reg_read(reg); -} - -void apic_write(unsigned reg, u32 val) -{ - apic_ops->reg_write(reg, val); -} - -bool apic_read_bit(unsigned reg, int n) -{ - reg += (n >> 5) << 4; - n &= 31; - return (apic_read(reg) & (1 << n)) != 0; -} - -void apic_icr_write(u32 val, u32 dest) -{ - apic_ops->icr_write(val, dest); -} - -uint32_t apic_id(void) -{ - return apic_ops->id(); -} - -uint8_t apic_get_tpr(void) -{ - unsigned long tpr; - -#ifdef __x86_64__ - asm volatile ("mov %%cr8, %0" : "=r"(tpr)); -#else - tpr = apic_read(APIC_TASKPRI) >> 4; -#endif - return tpr; -} - -void apic_set_tpr(uint8_t tpr) -{ -#ifdef __x86_64__ - asm volatile ("mov %0, %%cr8" : : "r"((unsigned long) tpr)); -#else - apic_write(APIC_TASKPRI, tpr << 4); -#endif -} - -int enable_x2apic(void) -{ - unsigned a, b, c, d; - - asm ("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(1)); - - if (c & (1 << 21)) { - asm ("rdmsr" : "=a"(a), "=d"(d) : "c"(MSR_IA32_APICBASE)); - a |= 1 << 10; - asm ("wrmsr" : : "a"(a), "d"(d), "c"(MSR_IA32_APICBASE)); - apic_ops = &x2apic_ops; - return 1; - } else { - return 0; - } -} - -void disable_apic(void) -{ - wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) & ~(APIC_EN | APIC_EXTD)); - apic_ops = &xapic_ops; -} - -void reset_apic(void) -{ - disable_apic(); - wrmsr(MSR_IA32_APICBASE, rdmsr(MSR_IA32_APICBASE) | APIC_EN); - xapic_write(APIC_SPIV, 0x1ff); -} - -u32 ioapic_read_reg(unsigned reg) -{ - *(volatile u32 *)g_ioapic = reg; - return *(volatile u32 *)(g_ioapic + 0x10); -} - -void ioapic_write_reg(unsigned reg, u32 value) -{ - *(volatile u32 *)g_ioapic = reg; - *(volatile u32 *)(g_ioapic + 0x10) = value; -} - -void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e) -{ - ioapic_write_reg(0x10 + line * 2 + 0, ((u32 *)&e)[0]); - ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]); -} - -ioapic_redir_entry_t ioapic_read_redir(unsigned line) -{ - ioapic_redir_entry_t e; - - ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0); - ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1); - return e; - -} - -void ioapic_set_redir(unsigned line, unsigned vec, - trigger_mode_t trig_mode) -{ - ioapic_redir_entry_t e = { - .vector = vec, - .delivery_mode = 0, - .trig_mode = trig_mode, - }; - - ioapic_write_redir(line, e); -} - -void set_mask(unsigned line, int mask) -{ - ioapic_redir_entry_t e = ioapic_read_redir(line); - - e.mask = mask; - ioapic_write_redir(line, e); -} - -void set_irq_line(unsigned line, int val) -{ - asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line))); -} - -void enable_apic(void) -{ - printf("enabling apic\n"); - xapic_write(APIC_SPIV, 0x1ff); -} - -void mask_pic_interrupts(void) -{ - outb(0xff, 0x21); - outb(0xff, 0xa1); -} - -extern unsigned char online_cpus[MAX_TEST_CPUS / 8]; - -void init_apic_map(void) -{ - unsigned int i, j = 0; - - for (i = 0; i < MAX_TEST_CPUS; i++) { - if ((1ul << (i % 8)) & (online_cpus[i / 8])) - id_map[j++] = i; - } -} diff --git a/lib/x86/apic.h b/lib/x86/apic.h deleted file mode 100644 index a7eff635..00000000 --- a/lib/x86/apic.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef CFLAT_APIC_H -#define CFLAT_APIC_H - -#include -#include "apic-defs.h" - -extern u8 id_map[MAX_TEST_CPUS]; - -extern void *g_apic; -extern void *g_ioapic; - -typedef struct { - uint8_t vector; - uint8_t delivery_mode:3; - uint8_t dest_mode:1; - uint8_t delivery_status:1; - uint8_t polarity:1; - uint8_t remote_irr:1; - uint8_t trig_mode:1; - uint8_t mask:1; - uint8_t reserve:7; - uint8_t reserved[4]; - uint8_t dest_id; -} ioapic_redir_entry_t; - -typedef enum trigger_mode { - TRIGGER_EDGE = 0, - TRIGGER_LEVEL, - TRIGGER_MAX, -} trigger_mode_t; - -void mask_pic_interrupts(void); - -void eoi(void); -uint8_t apic_get_tpr(void); -void apic_set_tpr(uint8_t tpr); - -void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e); -void ioapic_write_reg(unsigned reg, uint32_t value); -ioapic_redir_entry_t ioapic_read_redir(unsigned line); -uint32_t ioapic_read_reg(unsigned reg); - -void ioapic_set_redir(unsigned line, unsigned vec, - trigger_mode_t trig_mode); - -void set_mask(unsigned line, int mask); - -void set_irq_line(unsigned line, int val); - -void enable_apic(void); -uint32_t apic_read(unsigned reg); -bool apic_read_bit(unsigned reg, int n); -void apic_write(unsigned reg, uint32_t val); -void apic_icr_write(uint32_t val, uint32_t dest); -uint32_t apic_id(void); - -int enable_x2apic(void); -void disable_apic(void); -void reset_apic(void); -void init_apic_map(void); - -/* Converts byte-addressable APIC register offset to 4-byte offset. */ -static inline u32 apic_reg_index(u32 reg) -{ - return reg >> 2; -} - -static inline u32 x2apic_msr(u32 reg) -{ - return APIC_BASE_MSR + (reg >> 4); -} - -static inline bool apic_lvt_entry_supported(int idx) -{ - return GET_APIC_MAXLVT(apic_read(APIC_LVR)) >= idx; -} - -static inline bool x2apic_reg_reserved(u32 reg) -{ - switch (reg) { - case 0x000 ... 0x010: - case 0x040 ... 0x070: - case 0x090: - case 0x0c0: - case 0x0e0: - case 0x290 ... 0x2e0: - case 0x310: - case 0x3a0 ... 0x3d0: - case 0x3f0: - return true; - case APIC_CMCI: - return !apic_lvt_entry_supported(6); - default: - return false; - } -} - -#endif diff --git a/lib/x86/asm/barrier.h b/lib/x86/asm/barrier.h deleted file mode 100644 index 193fb4c2..00000000 --- a/lib/x86/asm/barrier.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _ASM_X86_BARRIER_H_ -#define _ASM_X86_BARRIER_H_ -/* - * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ - -#define mb() asm volatile("mfence":::"memory") -#define rmb() asm volatile("lfence":::"memory") -#define wmb() asm volatile("sfence":::"memory") - -#define smp_rmb() barrier() -#define smp_wmb() barrier() - -/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ -static inline void rep_nop(void) -{ - asm volatile("rep; nop" ::: "memory"); -} - -static inline void cpu_relax(void) -{ - rep_nop(); -} - -#endif diff --git a/lib/x86/asm/bitops.h b/lib/x86/asm/bitops.h deleted file mode 100644 index 13a25ec9..00000000 --- a/lib/x86/asm/bitops.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _ASMX86_BITOPS_H_ -#define _ASMX86_BITOPS_H_ - -#ifndef _BITOPS_H_ -#error only can be included directly -#endif - -#ifdef __x86_64__ -#define BITS_PER_LONG 64 -#else -#define BITS_PER_LONG 32 -#endif - -#define HAVE_BUILTIN_FLS 1 - -#endif diff --git a/lib/x86/asm/io.h b/lib/x86/asm/io.h deleted file mode 100644 index 35a5c734..00000000 --- a/lib/x86/asm/io.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef _ASM_X86_IO_H_ -#define _ASM_X86_IO_H_ - -#define __iomem - -#define inb inb -static inline uint8_t inb(unsigned long port) -{ - unsigned char value; - asm volatile("inb %w1, %0" : "=a" (value) : "Nd" ((unsigned short)port)); - return value; -} - -#define inw inw -static inline uint16_t inw(unsigned long port) -{ - unsigned short value; - asm volatile("inw %w1, %0" : "=a" (value) : "Nd" ((unsigned short)port)); - return value; -} - -#define inl inl -static inline uint32_t inl(unsigned long port) -{ - unsigned int value; - asm volatile("inl %w1, %0" : "=a" (value) : "Nd" ((unsigned short)port)); - return value; -} - -#define outb outb -static inline void outb(uint8_t value, unsigned long port) -{ - asm volatile("outb %b0, %w1" : : "a"(value), "Nd"((unsigned short)port)); -} - -#define outw outw -static inline void outw(uint16_t value, unsigned long port) -{ - asm volatile("outw %w0, %w1" : : "a"(value), "Nd"((unsigned short)port)); -} - -#define outl outl -static inline void outl(uint32_t value, unsigned long port) -{ - asm volatile("outl %0, %w1" : : "a"(value), "Nd"((unsigned short)port)); -} - -#define virt_to_phys virt_to_phys -static inline unsigned long virt_to_phys(const void *virt) -{ - return (unsigned long)virt; -} - -#define phys_to_virt phys_to_virt -static inline void *phys_to_virt(unsigned long phys) -{ - return (void *)phys; -} - -#define ioremap ioremap -void __iomem *ioremap(phys_addr_t phys_addr, size_t size); - -#include - -#endif diff --git a/lib/x86/asm/page.h b/lib/x86/asm/page.h deleted file mode 100644 index 7e2a3dd4..00000000 --- a/lib/x86/asm/page.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _ASM_X86_PAGE_H_ -#define _ASM_X86_PAGE_H_ -/* - * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ - - -#include -#include - -typedef unsigned long pteval_t; -typedef unsigned long pgd_t; - -#define PAGE_SHIFT 12 -#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) - -#ifndef __ASSEMBLY__ - -#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) - -#ifdef __x86_64__ -#define LARGE_PAGE_SIZE (512 * PAGE_SIZE) -#else -#define LARGE_PAGE_SIZE (1024 * PAGE_SIZE) -#endif - -#define PT_PRESENT_MASK (1ull << 0) -#define PT_WRITABLE_MASK (1ull << 1) -#define PT_USER_MASK (1ull << 2) -#define PT_ACCESSED_MASK (1ull << 5) -#define PT_DIRTY_MASK (1ull << 6) -#define PT_PAGE_SIZE_MASK (1ull << 7) -#define PT64_NX_MASK (1ull << 63) -#define PT_ADDR_MASK GENMASK_ULL(51, 12) - -#define PT_AD_MASK (PT_ACCESSED_MASK | PT_DIRTY_MASK) - -#ifdef __x86_64__ -#define PAGE_LEVEL 4 -#define PGDIR_WIDTH 9 -#define PGDIR_MASK 511 -#else -#define PAGE_LEVEL 2 -#define PGDIR_WIDTH 10 -#define PGDIR_MASK 1023 -#endif - -#define PGDIR_BITS(lvl) (((lvl) - 1) * PGDIR_WIDTH + PAGE_SHIFT) -#define PGDIR_OFFSET(va, lvl) (((va) >> PGDIR_BITS(lvl)) & PGDIR_MASK) - -#endif /* !__ASSEMBLY__ */ -#endif diff --git a/lib/x86/asm/pci.h b/lib/x86/asm/pci.h deleted file mode 100644 index c937e5cd..00000000 --- a/lib/x86/asm/pci.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef ASM_PCI_H -#define ASM_PCI_H -/* - * Copyright (C) 2013, Red Hat Inc, Michael S. Tsirkin - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "pci.h" -#include "x86/asm/io.h" - -#define PCI_CONF1_ADDRESS(dev, reg) ((0x1 << 31) | (dev << 8) | reg) - -static inline uint8_t pci_config_readb(pcidevaddr_t dev, uint8_t reg) -{ - outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); - return inb(0xCFC); -} - -static inline uint16_t pci_config_readw(pcidevaddr_t dev, uint8_t reg) -{ - outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); - return inw(0xCFC); -} - -static inline uint32_t pci_config_readl(pcidevaddr_t dev, uint8_t reg) -{ - outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); - return inl(0xCFC); -} - -static inline void pci_config_writeb(pcidevaddr_t dev, uint8_t reg, - uint8_t val) -{ - outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); - outb(val, 0xCFC); -} - -static inline void pci_config_writew(pcidevaddr_t dev, uint8_t reg, - uint16_t val) -{ - outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); - outw(val, 0xCFC); -} - -static inline void pci_config_writel(pcidevaddr_t dev, uint8_t reg, - uint32_t val) -{ - outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); - outl(val, 0xCFC); -} - -static inline -phys_addr_t pci_translate_addr(pcidevaddr_t dev __unused, uint64_t addr) -{ - return addr; -} - -#endif diff --git a/lib/x86/asm/spinlock.h b/lib/x86/asm/spinlock.h deleted file mode 100644 index 692020c5..00000000 --- a/lib/x86/asm/spinlock.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __ASM_SPINLOCK_H -#define __ASM_SPINLOCK_H - -#include - -#endif diff --git a/lib/x86/asm/stack.h b/lib/x86/asm/stack.h deleted file mode 100644 index b14e2c0f..00000000 --- a/lib/x86/asm/stack.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _X86ASM_STACK_H_ -#define _X86ASM_STACK_H_ - -#ifndef _STACK_H_ -#error Do not directly include . Just use . -#endif - -#define HAVE_ARCH_BACKTRACE_FRAME -#define HAVE_ARCH_BACKTRACE - -#endif diff --git a/lib/x86/atomic.c b/lib/x86/atomic.c deleted file mode 100644 index da74ff21..00000000 --- a/lib/x86/atomic.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include "atomic.h" - -#ifdef __i386__ - -u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new) -{ - u32 low = new; - u32 high = new >> 32; - - asm volatile("lock cmpxchg8b %1\n" - : "+A" (old), - "+m" (*(volatile long long *)&v->counter) - : "b" (low), "c" (high) - : "memory" - ); - - return old; -} - -#else - -u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new) -{ - u64 ret; - u64 _old = old; - u64 _new = new; - - asm volatile("lock cmpxchgq %2,%1" - : "=a" (ret), "+m" (*(volatile long *)&v->counter) - : "r" (_new), "0" (_old) - : "memory" - ); - return ret; -} - -#endif diff --git a/lib/x86/atomic.h b/lib/x86/atomic.h deleted file mode 100644 index c9ce489d..00000000 --- a/lib/x86/atomic.h +++ /dev/null @@ -1,166 +0,0 @@ -#ifndef __ATOMIC_H -#define __ATOMIC_H - -#include "asm-generic/atomic.h" - -typedef struct { - volatile int counter; -} atomic_t; - -#ifdef __i386__ - -/** - * atomic_read - read atomic variable - * @v: pointer of type atomic_t - * - * Atomically reads the value of @v. - */ -static inline int atomic_read(const atomic_t *v) -{ - return v->counter; -} - -/** - * atomic_set - set atomic variable - * @v: pointer of type atomic_t - * @i: required value - * - * Atomically sets the value of @v to @i. - */ -static inline void atomic_set(atomic_t *v, int i) -{ - v->counter = i; -} - -/** - * atomic_inc - increment atomic variable - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1. - */ -static inline void atomic_inc(atomic_t *v) -{ - asm volatile("lock incl %0" - : "+m" (v->counter)); -} - -/** - * atomic_dec - decrement atomic variable - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1. - */ -static inline void atomic_dec(atomic_t *v) -{ - asm volatile("lock decl %0" - : "+m" (v->counter)); -} - -typedef struct { - u64 __attribute__((aligned(8))) counter; -} atomic64_t; - -#define ATOMIC64_INIT(val) { (val) } - -/** - * atomic64_read - read atomic64 variable - * @ptr: pointer to type atomic64_t - * - * Atomically reads the value of @ptr and returns it. - */ -static inline u64 atomic64_read(atomic64_t *ptr) -{ - u64 res; - - /* - * Note, we inline this atomic64_t primitive because - * it only clobbers EAX/EDX and leaves the others - * untouched. We also (somewhat subtly) rely on the - * fact that cmpxchg8b returns the current 64-bit value - * of the memory location we are touching: - */ - asm volatile("mov %%ebx, %%eax\n\t" - "mov %%ecx, %%edx\n\t" - "lock cmpxchg8b %1\n" - : "=&A" (res) - : "m" (*ptr) - ); - return res; -} - -u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new); - -#elif defined(__x86_64__) - -/** - * atomic_read - read atomic variable - * @v: pointer of type atomic_t - * - * Atomically reads the value of @v. - */ -static inline int atomic_read(const atomic_t *v) -{ - return v->counter; -} - -/** - * atomic_set - set atomic variable - * @v: pointer of type atomic_t - * @i: required value - * - * Atomically sets the value of @v to @i. - */ -static inline void atomic_set(atomic_t *v, int i) -{ - v->counter = i; -} - -/** - * atomic_inc - increment atomic variable - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1. - */ -static inline void atomic_inc(atomic_t *v) -{ - asm volatile("lock incl %0" - : "=m" (v->counter) - : "m" (v->counter)); -} - -/** - * atomic_dec - decrement atomic variable - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1. - */ -static inline void atomic_dec(atomic_t *v) -{ - asm volatile("lock decl %0" - : "=m" (v->counter) - : "m" (v->counter)); -} - -typedef struct { - long long counter; -} atomic64_t; - -#define ATOMIC64_INIT(i) { (i) } - -/** - * atomic64_read - read atomic64 variable - * @v: pointer of type atomic64_t - * - * Atomically reads the value of @v. - * Doesn't imply a read memory barrier. - */ -static inline long atomic64_read(const atomic64_t *v) -{ - return v->counter; -} - -u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new); - -#endif - -#endif diff --git a/lib/x86/delay.c b/lib/x86/delay.c deleted file mode 100644 index e7d27174..00000000 --- a/lib/x86/delay.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "delay.h" -#include "processor.h" - -void delay(u64 count) -{ - u64 start = rdtsc(); - - do { - pause(); - } while (rdtsc() - start < count); -} diff --git a/lib/x86/delay.h b/lib/x86/delay.h deleted file mode 100644 index a51eb344..00000000 --- a/lib/x86/delay.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __X86_DELAY__ -#define __X86_DELAY__ - -#include "libcflat.h" - -#define IPI_DELAY 1000000 - -void delay(u64 count); - -static inline void io_delay(void) -{ - delay(IPI_DELAY); -} - -#endif diff --git a/lib/x86/desc.c b/lib/x86/desc.c deleted file mode 100644 index 451f504b..00000000 --- a/lib/x86/desc.c +++ /dev/null @@ -1,412 +0,0 @@ -#include "libcflat.h" -#include "desc.h" -#include "processor.h" -#include - -#ifndef __x86_64__ -__attribute__((regparm(1))) -#endif -void do_handle_exception(struct ex_regs *regs); - -void set_idt_entry(int vec, void *addr, int dpl) -{ - idt_entry_t *e = &boot_idt[vec]; - memset(e, 0, sizeof *e); - e->offset0 = (unsigned long)addr; - e->selector = read_cs(); - e->ist = 0; - e->type = 14; - e->dpl = dpl; - e->p = 1; - e->offset1 = (unsigned long)addr >> 16; -#ifdef __x86_64__ - e->offset2 = (unsigned long)addr >> 32; -#endif -} - -void set_idt_dpl(int vec, u16 dpl) -{ - idt_entry_t *e = &boot_idt[vec]; - e->dpl = dpl; -} - -void set_idt_sel(int vec, u16 sel) -{ - idt_entry_t *e = &boot_idt[vec]; - e->selector = sel; -} - -struct ex_record { - unsigned long rip; - unsigned long handler; -}; - -extern struct ex_record exception_table_start, exception_table_end; - -static const char* exception_mnemonic(int vector) -{ - switch(vector) { - case 0: return "#DE"; - case 1: return "#DB"; - case 2: return "#NMI"; - case 3: return "#BP"; - case 4: return "#OF"; - case 5: return "#BR"; - case 6: return "#UD"; - case 7: return "#NM"; - case 8: return "#DF"; - case 10: return "#TS"; - case 11: return "#NP"; - case 12: return "#SS"; - case 13: return "#GP"; - case 14: return "#PF"; - case 16: return "#MF"; - case 17: return "#AC"; - case 18: return "#MC"; - case 19: return "#XM"; - default: return "#??"; - } -} - -void unhandled_exception(struct ex_regs *regs, bool cpu) -{ - printf("Unhandled %sexception %ld %s at ip %016lx\n", - cpu ? "cpu " : "", regs->vector, - exception_mnemonic(regs->vector), regs->rip); - if (regs->vector == 14) - printf("PF at %#lx addr %#lx\n", regs->rip, read_cr2()); - - printf("error_code=%04lx rflags=%08lx cs=%08lx\n" - "rax=%016lx rcx=%016lx rdx=%016lx rbx=%016lx\n" - "rbp=%016lx rsi=%016lx rdi=%016lx\n" -#ifdef __x86_64__ - " r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n" - "r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n" -#endif - "cr0=%016lx cr2=%016lx cr3=%016lx cr4=%016lx\n" -#ifdef __x86_64__ - "cr8=%016lx\n" -#endif - , - regs->error_code, regs->rflags, regs->cs, - regs->rax, regs->rcx, regs->rdx, regs->rbx, - regs->rbp, regs->rsi, regs->rdi, -#ifdef __x86_64__ - regs->r8, regs->r9, regs->r10, regs->r11, - regs->r12, regs->r13, regs->r14, regs->r15, -#endif - read_cr0(), read_cr2(), read_cr3(), read_cr4() -#ifdef __x86_64__ - , read_cr8() -#endif - ); - dump_frame_stack((void*) regs->rip, (void*) regs->rbp); - abort(); -} - -static void check_exception_table(struct ex_regs *regs) -{ - struct ex_record *ex; - unsigned ex_val; - - ex_val = regs->vector | (regs->error_code << 16) | - (((regs->rflags >> 16) & 1) << 8); - asm("mov %0, %%gs:4" : : "r"(ex_val)); - - for (ex = &exception_table_start; ex != &exception_table_end; ++ex) { - if (ex->rip == regs->rip) { - regs->rip = ex->handler; - return; - } - } - unhandled_exception(regs, false); -} - -static handler exception_handlers[32]; - -handler handle_exception(u8 v, handler fn) -{ - handler old; - - old = exception_handlers[v]; - if (v < 32) - exception_handlers[v] = fn; - return old; -} - -#ifndef __x86_64__ -__attribute__((regparm(1))) -#endif -void do_handle_exception(struct ex_regs *regs) -{ - if (regs->vector < 32 && exception_handlers[regs->vector]) { - exception_handlers[regs->vector](regs); - return; - } - unhandled_exception(regs, true); -} - -#define EX(NAME, N) extern char NAME##_fault; \ - asm (".pushsection .text \n\t" \ - #NAME"_fault: \n\t" \ - "push"W" $0 \n\t" \ - "push"W" $"#N" \n\t" \ - "jmp __handle_exception \n\t" \ - ".popsection") - -#define EX_E(NAME, N) extern char NAME##_fault; \ - asm (".pushsection .text \n\t" \ - #NAME"_fault: \n\t" \ - "push"W" $"#N" \n\t" \ - "jmp __handle_exception \n\t" \ - ".popsection") - -EX(de, 0); -EX(db, 1); -EX(nmi, 2); -EX(bp, 3); -EX(of, 4); -EX(br, 5); -EX(ud, 6); -EX(nm, 7); -EX_E(df, 8); -EX_E(ts, 10); -EX_E(np, 11); -EX_E(ss, 12); -EX_E(gp, 13); -EX_E(pf, 14); -EX(mf, 16); -EX_E(ac, 17); -EX(mc, 18); -EX(xm, 19); - -asm (".pushsection .text \n\t" - "__handle_exception: \n\t" -#ifdef __x86_64__ - "push %r15; push %r14; push %r13; push %r12 \n\t" - "push %r11; push %r10; push %r9; push %r8 \n\t" -#endif - "push %"R "di; push %"R "si; push %"R "bp; sub $"S", %"R "sp \n\t" - "push %"R "bx; push %"R "dx; push %"R "cx; push %"R "ax \n\t" -#ifdef __x86_64__ - "mov %"R "sp, %"R "di \n\t" -#else - "mov %"R "sp, %"R "ax \n\t" -#endif - "call do_handle_exception \n\t" - "pop %"R "ax; pop %"R "cx; pop %"R "dx; pop %"R "bx \n\t" - "add $"S", %"R "sp; pop %"R "bp; pop %"R "si; pop %"R "di \n\t" -#ifdef __x86_64__ - "pop %r8; pop %r9; pop %r10; pop %r11 \n\t" - "pop %r12; pop %r13; pop %r14; pop %r15 \n\t" -#endif - "add $"S", %"R "sp \n\t" - "add $"S", %"R "sp \n\t" - "iret"W" \n\t" - ".popsection"); - -static void *idt_handlers[32] = { - [0] = &de_fault, - [1] = &db_fault, - [2] = &nmi_fault, - [3] = &bp_fault, - [4] = &of_fault, - [5] = &br_fault, - [6] = &ud_fault, - [7] = &nm_fault, - [8] = &df_fault, - [10] = &ts_fault, - [11] = &np_fault, - [12] = &ss_fault, - [13] = &gp_fault, - [14] = &pf_fault, - [16] = &mf_fault, - [17] = &ac_fault, - [18] = &mc_fault, - [19] = &xm_fault, -}; - -void setup_idt(void) -{ - int i; - static bool idt_initialized = false; - - if (idt_initialized) { - return; - } - idt_initialized = true; - for (i = 0; i < 32; i++) - if (idt_handlers[i]) - set_idt_entry(i, idt_handlers[i], 0); - handle_exception(0, check_exception_table); - handle_exception(6, check_exception_table); - handle_exception(13, check_exception_table); -} - -unsigned exception_vector(void) -{ - unsigned char vector; - - asm("movb %%gs:4, %0" : "=q"(vector)); - return vector; -} - -int write_cr4_checking(unsigned long val) -{ - asm volatile(ASM_TRY("1f") - "mov %0,%%cr4\n\t" - "1:": : "r" (val)); - return exception_vector(); -} - -unsigned exception_error_code(void) -{ - unsigned short error_code; - - asm("mov %%gs:6, %0" : "=r"(error_code)); - return error_code; -} - -bool exception_rflags_rf(void) -{ - unsigned char rf_flag; - - asm("movb %%gs:5, %b0" : "=q"(rf_flag)); - return rf_flag & 1; -} - -static char intr_alt_stack[4096]; - -#ifndef __x86_64__ -void set_gdt_entry(int sel, u32 base, u32 limit, u8 access, u8 gran) -{ - int num = sel >> 3; - - /* Setup the descriptor base address */ - gdt32[num].base_low = (base & 0xFFFF); - gdt32[num].base_middle = (base >> 16) & 0xFF; - gdt32[num].base_high = (base >> 24) & 0xFF; - - /* Setup the descriptor limits */ - gdt32[num].limit_low = (limit & 0xFFFF); - gdt32[num].granularity = ((limit >> 16) & 0x0F); - - /* Finally, set up the granularity and access flags */ - gdt32[num].granularity |= (gran & 0xF0); - gdt32[num].access = access; -} - -void set_gdt_task_gate(u16 sel, u16 tss_sel) -{ - set_gdt_entry(sel, tss_sel, 0, 0x85, 0); // task, present -} - -void set_idt_task_gate(int vec, u16 sel) -{ - idt_entry_t *e = &boot_idt[vec]; - - memset(e, 0, sizeof *e); - - e->selector = sel; - e->ist = 0; - e->type = 5; - e->dpl = 0; - e->p = 1; -} - -/* - * 0 - main task - * 1 - interrupt task - */ - -tss32_t tss_intr; - -void setup_tss32(void) -{ - u16 desc_size = sizeof(tss32_t); - - tss.cr3 = read_cr3(); - tss_intr.cr3 = read_cr3(); - tss_intr.ss0 = tss_intr.ss1 = tss_intr.ss2 = 0x10; - tss_intr.esp = tss_intr.esp0 = tss_intr.esp1 = tss_intr.esp2 = - (u32)intr_alt_stack + 4096; - tss_intr.cs = 0x08; - tss_intr.ds = tss_intr.es = tss_intr.fs = tss_intr.gs = tss_intr.ss = 0x10; - tss_intr.iomap_base = (u16)desc_size; - set_gdt_entry(TSS_INTR, (u32)&tss_intr, desc_size - 1, 0x89, 0x0f); -} - -void set_intr_task_gate(int e, void *fn) -{ - tss_intr.eip = (u32)fn; - set_idt_task_gate(e, TSS_INTR); -} - -void setup_alt_stack(void) -{ - setup_tss32(); -} - -void set_intr_alt_stack(int e, void *fn) -{ - set_intr_task_gate(e, fn); -} - -void print_current_tss_info(void) -{ - u16 tr = str(); - - if (tr != TSS_MAIN && tr != TSS_INTR) - printf("Unknown TSS %x\n", tr); - else - printf("TR=%x (%s) Main TSS back link %x. Intr TSS back link %x\n", - tr, tr ? "interrupt" : "main", tss.prev, tss_intr.prev); -} -#else -void set_intr_alt_stack(int e, void *addr) -{ - set_idt_entry(e, addr, 0); - boot_idt[e].ist = 1; -} - -void setup_alt_stack(void) -{ - tss.ist1 = (u64)intr_alt_stack + 4096; -} -#endif - -static bool exception; -static jmp_buf *exception_jmpbuf; - -static void exception_handler_longjmp(void) -{ - longjmp(*exception_jmpbuf, 1); -} - -static void exception_handler(struct ex_regs *regs) -{ - /* longjmp must happen after iret, so do not do it now. */ - exception = true; - regs->rip = (unsigned long)&exception_handler_longjmp; - regs->cs = read_cs(); -} - -bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data), - void *data) -{ - handler old; - jmp_buf jmpbuf; - int ret; - - old = handle_exception(ex, exception_handler); - ret = set_exception_jmpbuf(jmpbuf); - if (ret == 0) - trigger_func(data); - handle_exception(ex, old); - return ret; -} - -void __set_exception_jmpbuf(jmp_buf *addr) -{ - exception_jmpbuf = addr; -} diff --git a/lib/x86/desc.h b/lib/x86/desc.h deleted file mode 100644 index 0fe5cbf3..00000000 --- a/lib/x86/desc.h +++ /dev/null @@ -1,241 +0,0 @@ -#ifndef __IDT_TEST__ -#define __IDT_TEST__ - -#include - -void setup_idt(void); -void setup_alt_stack(void); - -struct ex_regs { - unsigned long rax, rcx, rdx, rbx; - unsigned long dummy, rbp, rsi, rdi; -#ifdef __x86_64__ - unsigned long r8, r9, r10, r11; - unsigned long r12, r13, r14, r15; -#endif - unsigned long vector; - unsigned long error_code; - unsigned long rip; - unsigned long cs; - unsigned long rflags; -}; - -typedef void (*handler)(struct ex_regs *regs); - -typedef struct { - u16 prev; - u16 res1; - u32 esp0; - u16 ss0; - u16 res2; - u32 esp1; - u16 ss1; - u16 res3; - u32 esp2; - u16 ss2; - u16 res4; - u32 cr3; - u32 eip; - u32 eflags; - u32 eax, ecx, edx, ebx, esp, ebp, esi, edi; - u16 es; - u16 res5; - u16 cs; - u16 res6; - u16 ss; - u16 res7; - u16 ds; - u16 res8; - u16 fs; - u16 res9; - u16 gs; - u16 res10; - u16 ldt; - u16 res11; - u16 t:1; - u16 res12:15; - u16 iomap_base; -} tss32_t; - -typedef struct __attribute__((packed)) { - u32 res1; - u64 rsp0; - u64 rsp1; - u64 rsp2; - u64 res2; - u64 ist1; - u64 ist2; - u64 ist3; - u64 ist4; - u64 ist5; - u64 ist6; - u64 ist7; - u64 res3; - u16 res4; - u16 iomap_base; -} tss64_t; - -#ifdef __x86_64 -#define ASM_TRY(catch) \ - "movl $0, %%gs:4 \n\t" \ - ".pushsection .data.ex \n\t" \ - ".quad 1111f, " catch "\n\t" \ - ".popsection \n\t" \ - "1111:" -#else -#define ASM_TRY(catch) \ - "movl $0, %%gs:4 \n\t" \ - ".pushsection .data.ex \n\t" \ - ".long 1111f, " catch "\n\t" \ - ".popsection \n\t" \ - "1111:" -#endif - -/* - * selector 32-bit 64-bit - * 0x00 NULL descriptor NULL descriptor - * 0x08 ring-0 code segment (32-bit) ring-0 code segment (64-bit) - * 0x10 ring-0 data segment (32-bit) ring-0 data segment (32/64-bit) - * 0x18 ring-0 code segment (P=0) ring-0 code segment (64-bit, P=0) - * 0x20 intr_alt_stack TSS ring-0 code segment (32-bit) - * 0x28 ring-0 code segment (16-bit) same - * 0x30 ring-0 data segment (16-bit) same - * 0x38 (0x3b) ring-3 code segment (32-bit) same - * 0x40 (0x43) ring-3 data segment (32-bit) ring-3 data segment (32/64-bit) - * 0x48 (0x4b) **unused** ring-3 code segment (64-bit) - * 0x50--0x78 free to use for test cases same - * 0x80 primary TSS (CPU 0) same - * - * Note that the same segment can be used for 32-bit and 64-bit data segments - * (the L bit is only defined for code segments) - * - * Selectors 0x08-0x10 and 0x3b-0x4b are set up for use with the SYSCALL - * and SYSRET instructions. - */ - -#define KERNEL_CS 0x08 -#define KERNEL_DS 0x10 -#define NP_SEL 0x18 -#ifdef __x86_64__ -#define KERNEL_CS32 0x20 -#else -#define TSS_INTR 0x20 -#endif -#define KERNEL_CS16 0x28 -#define KERNEL_DS16 0x30 -#define USER_CS32 0x3b -#define USER_DS 0x43 -#ifdef __x86_64__ -#define USER_CS64 0x4b -#endif - -/* Synonyms */ -#define KERNEL_DS32 KERNEL_DS -#define USER_DS32 USER_DS - -#ifdef __x86_64__ -#define KERNEL_CS64 KERNEL_CS -#define USER_CS USER_CS64 -#define KERNEL_DS64 KERNEL_DS -#define USER_DS64 USER_DS -#else -#define KERNEL_CS32 KERNEL_CS -#define USER_CS USER_CS32 -#endif - -#define FIRST_SPARE_SEL 0x50 -#define TSS_MAIN 0x80 - -typedef struct { - unsigned short offset0; - unsigned short selector; - unsigned short ist : 3; - unsigned short : 5; - unsigned short type : 4; - unsigned short : 1; - unsigned short dpl : 2; - unsigned short p : 1; - unsigned short offset1; -#ifdef __x86_64__ - unsigned offset2; - unsigned reserved; -#endif -} idt_entry_t; - -typedef struct { - u16 limit_low; - u16 base_low; - u8 base_middle; - u8 access; - u8 granularity; - u8 base_high; -} gdt_entry_t; - -struct segment_desc64 { - uint16_t limit1; - uint16_t base1; - uint8_t base2; - union { - uint16_t type_limit_flags; /* Type and limit flags */ - struct { - uint16_t type:4; - uint16_t s:1; - uint16_t dpl:2; - uint16_t p:1; - uint16_t limit:4; - uint16_t avl:1; - uint16_t l:1; - uint16_t db:1; - uint16_t g:1; - } __attribute__((__packed__)); - } __attribute__((__packed__)); - uint8_t base3; - uint32_t base4; - uint32_t zero; -} __attribute__((__packed__)); - -#define DESC_BUSY ((uint64_t) 1 << 41) - -extern idt_entry_t boot_idt[256]; - -#ifndef __x86_64__ -extern gdt_entry_t gdt32[]; -extern tss32_t tss; -extern tss32_t tss_intr; -void set_gdt_task_gate(u16 tss_sel, u16 sel); -void set_idt_task_gate(int vec, u16 sel); -void set_intr_task_gate(int vec, void *fn); -void setup_tss32(void); -#else -extern tss64_t tss; -#endif - -unsigned exception_vector(void); -int write_cr4_checking(unsigned long val); -unsigned exception_error_code(void); -bool exception_rflags_rf(void); -void set_idt_entry(int vec, void *addr, int dpl); -void set_idt_sel(int vec, u16 sel); -void set_idt_dpl(int vec, u16 dpl); -void set_gdt_entry(int sel, u32 base, u32 limit, u8 access, u8 gran); -void set_intr_alt_stack(int e, void *fn); -void print_current_tss_info(void); -handler handle_exception(u8 v, handler fn); -void unhandled_exception(struct ex_regs *regs, bool cpu); - -bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data), - void *data); -void __set_exception_jmpbuf(jmp_buf *addr); -#define set_exception_jmpbuf(jmpbuf) \ - (setjmp(jmpbuf) ? : (__set_exception_jmpbuf(&(jmpbuf)), 0)) - -static inline void *get_idt_addr(idt_entry_t *entry) -{ - uintptr_t addr = entry->offset0 | ((u32)entry->offset1 << 16); -#ifdef __x86_64__ - addr |= (u64)entry->offset2 << 32; -#endif - return (void *)addr; -} - -#endif diff --git a/lib/x86/fault_test.c b/lib/x86/fault_test.c deleted file mode 100644 index e15a2186..00000000 --- a/lib/x86/fault_test.c +++ /dev/null @@ -1,52 +0,0 @@ -#include "fault_test.h" - -static jmp_buf jmpbuf; - -static void restore_exec_to_jmpbuf(void) -{ - longjmp(jmpbuf, 1); -} - -static void fault_test_fault(struct ex_regs *regs) -{ - regs->rip = (unsigned long)&restore_exec_to_jmpbuf; -} - -static bool fault_test(struct fault_test_arg *arg) -{ - volatile uint64_t val; - bool raised_vector = false; - test_fault_func func = (test_fault_func) arg->func; - /* Init as success in case there isn't callback */ - bool callback_success = true; - - if (arg->usermode) { - val = run_in_user((usermode_func) func, arg->fault_vector, - arg->arg[0], arg->arg[1], arg->arg[2], - arg->arg[3], &raised_vector); - } else { - handle_exception(arg->fault_vector, fault_test_fault); - if (setjmp(jmpbuf) == 0) - val = func(arg->arg[0], arg->arg[1], arg->arg[2], - arg->arg[3]); - else - raised_vector = true; - } - - if (!raised_vector) { - arg->retval = val; - if (arg->callback != NULL) - callback_success = arg->callback(arg); - } - - return arg->should_fault ? - raised_vector : (!raised_vector && callback_success); -} - -void test_run(struct fault_test *test) -{ - bool passed = fault_test(&(test->arg)); - - report(passed, "%s", test->name); -} - diff --git a/lib/x86/fault_test.h b/lib/x86/fault_test.h deleted file mode 100644 index dfa715ba..00000000 --- a/lib/x86/fault_test.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __FAULT_TEST__ -#define __FAULT_TEST__ - -#include "x86/msr.h" -#include "x86/processor.h" -#include "x86/apic-defs.h" -#include "x86/apic.h" -#include "x86/desc.h" -#include "x86/isr.h" -#include "alloc.h" -#include "setjmp.h" -#include "usermode.h" - -#include "libcflat.h" -#include - -#define FAULT_TEST(nm, a) { .name = nm, .arg = a} - -struct fault_test_arg; - -typedef uint64_t (*test_fault_func)(uint64_t arg1, uint64_t arg2, - uint64_t arg3, uint64_t arg4); -typedef bool (*test_fault_callback)(struct fault_test_arg *arg); - -struct fault_test_arg { - bool usermode; - unsigned int fault_vector; - bool should_fault; - uint64_t arg[4]; - uint64_t retval; - test_fault_func func; - test_fault_callback callback; -}; - -struct fault_test { - const char *name; - struct fault_test_arg arg; -}; - -void test_run(struct fault_test *test); - -#endif diff --git a/lib/x86/fwcfg.c b/lib/x86/fwcfg.c deleted file mode 100644 index c2aaf5a4..00000000 --- a/lib/x86/fwcfg.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "fwcfg.h" -#include "smp.h" -#include "libcflat.h" - -static struct spinlock lock; - -static long fw_override[FW_CFG_MAX_ENTRY]; -static bool fw_override_done; - -bool no_test_device; - -static void read_cfg_override(void) -{ - const char *str; - int i; - - /* Initialize to negative value that would be considered as invalid */ - for (i = 0; i < FW_CFG_MAX_ENTRY; i++) - fw_override[i] = -1; - - if ((str = getenv("NR_CPUS"))) - fw_override[FW_CFG_NB_CPUS] = atol(str); - - /* MEMSIZE is in megabytes */ - if ((str = getenv("MEMSIZE"))) - fw_override[FW_CFG_RAM_SIZE] = atol(str) * 1024 * 1024; - - if ((str = getenv("TEST_DEVICE"))) - no_test_device = !atol(str); - - if ((str = getenv("MEMLIMIT"))) - fw_override[FW_CFG_MAX_RAM] = atol(str) * 1024 * 1024; - - - fw_override_done = true; -} - -static uint64_t fwcfg_get_u(uint16_t index, int bytes) -{ - uint64_t r = 0; - uint8_t b; - int i; - - if (!fw_override_done) - read_cfg_override(); - - if (index < FW_CFG_MAX_ENTRY && fw_override[index] >= 0) - return fw_override[index]; - - spin_lock(&lock); - asm volatile ("out %0, %1" : : "a"(index), "d"((uint16_t)BIOS_CFG_IOPORT)); - for (i = 0; i < bytes; ++i) { - asm volatile ("in %1, %0" : "=a"(b) : "d"((uint16_t)(BIOS_CFG_IOPORT + 1))); - r |= (uint64_t)b << (i * 8); - } - spin_unlock(&lock); - return r; -} - -uint8_t fwcfg_get_u8(unsigned index) -{ - return fwcfg_get_u(index, 1); -} - -uint16_t fwcfg_get_u16(unsigned index) -{ - return fwcfg_get_u(index, 2); -} - -uint32_t fwcfg_get_u32(unsigned index) -{ - return fwcfg_get_u(index, 4); -} - -uint64_t fwcfg_get_u64(unsigned index) -{ - return fwcfg_get_u(index, 8); -} - -unsigned fwcfg_get_nb_cpus(void) -{ - return fwcfg_get_u16(FW_CFG_NB_CPUS); -} diff --git a/lib/x86/fwcfg.h b/lib/x86/fwcfg.h deleted file mode 100644 index 64d4c6ea..00000000 --- a/lib/x86/fwcfg.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef FWCFG_H -#define FWCFG_H - -#include -#include - -#define FW_CFG_SIGNATURE 0x00 -#define FW_CFG_ID 0x01 -#define FW_CFG_UUID 0x02 -#define FW_CFG_RAM_SIZE 0x03 -#define FW_CFG_NOGRAPHIC 0x04 -#define FW_CFG_NB_CPUS 0x05 -#define FW_CFG_MACHINE_ID 0x06 -#define FW_CFG_KERNEL_ADDR 0x07 -#define FW_CFG_KERNEL_SIZE 0x08 -#define FW_CFG_KERNEL_CMDLINE 0x09 -#define FW_CFG_INITRD_ADDR 0x0a -#define FW_CFG_INITRD_SIZE 0x0b -#define FW_CFG_BOOT_DEVICE 0x0c -#define FW_CFG_NUMA 0x0d -#define FW_CFG_BOOT_MENU 0x0e -#define FW_CFG_MAX_CPUS 0x0f -#define FW_CFG_MAX_ENTRY 0x10 -#define FW_CFG_MAX_RAM 0x11 - -#define FW_CFG_WRITE_CHANNEL 0x4000 -#define FW_CFG_ARCH_LOCAL 0x8000 -#define FW_CFG_ENTRY_MASK ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL) - -#define FW_CFG_INVALID 0xffff - -#define BIOS_CFG_IOPORT 0x510 - -#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0) -#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1) -#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2) - -extern bool no_test_device; - -static inline bool test_device_enabled(void) -{ - return !no_test_device; -} - -uint8_t fwcfg_get_u8(unsigned index); -uint16_t fwcfg_get_u16(unsigned index); -uint32_t fwcfg_get_u32(unsigned index); -uint64_t fwcfg_get_u64(unsigned index); - -unsigned fwcfg_get_nb_cpus(void); - -#endif - diff --git a/lib/x86/intel-iommu.c b/lib/x86/intel-iommu.c deleted file mode 100644 index c811ba5f..00000000 --- a/lib/x86/intel-iommu.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Intel IOMMU APIs - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Authors: - * Peter Xu , - * - * This work is licensed under the terms of the GNU LGPL, version 2 or - * later. - */ - -#include "intel-iommu.h" -#include "libcflat.h" -#include "pci.h" -#include "atomic.h" -#include "alloc_page.h" - -/* - * VT-d in QEMU currently only support 39 bits address width, which is - * 3-level translation. - */ -#define VTD_PAGE_LEVEL 3 -#define VTD_CE_AW_39BIT 0x1 - -typedef uint64_t vtd_pte_t; - -struct vtd_root_entry { - /* Quad 1 */ - uint64_t present:1; - uint64_t __reserved:11; - uint64_t context_table_p:52; - /* Quad 2 */ - uint64_t __reserved_2; -} __attribute__ ((packed)); -typedef struct vtd_root_entry vtd_re_t; - -struct vtd_context_entry { - /* Quad 1 */ - uint64_t present:1; - uint64_t disable_fault_report:1; - uint64_t trans_type:2; - uint64_t __reserved:8; - uint64_t slptptr:52; - /* Quad 2 */ - uint64_t addr_width:3; - uint64_t __ignore:4; - uint64_t __reserved_2:1; - uint64_t domain_id:16; - uint64_t __reserved_3:40; -} __attribute__ ((packed)); -typedef struct vtd_context_entry vtd_ce_t; - -struct vtd_irte { - uint32_t present:1; - uint32_t fault_disable:1; /* Fault Processing Disable */ - uint32_t dest_mode:1; /* Destination Mode */ - uint32_t redir_hint:1; /* Redirection Hint */ - uint32_t trigger_mode:1; /* Trigger Mode */ - uint32_t delivery_mode:3; /* Delivery Mode */ - uint32_t __avail:4; /* Available spaces for software */ - uint32_t __reserved_0:3; /* Reserved 0 */ - uint32_t irte_mode:1; /* IRTE Mode */ - uint32_t vector:8; /* Interrupt Vector */ - uint32_t __reserved_1:8; /* Reserved 1 */ - uint32_t dest_id; /* Destination ID */ - uint16_t source_id:16; /* Source-ID */ - uint64_t sid_q:2; /* Source-ID Qualifier */ - uint64_t sid_vtype:2; /* Source-ID Validation Type */ - uint64_t __reserved_2:44; /* Reserved 2 */ -} __attribute__ ((packed)); -typedef struct vtd_irte vtd_irte_t; - -#define VTD_RTA_MASK (PAGE_MASK) -#define VTD_IRTA_MASK (PAGE_MASK) - -void *vtd_reg_base; - -static uint64_t vtd_root_table(void) -{ - /* No extend root table support yet */ - return vtd_readq(DMAR_RTADDR_REG) & VTD_RTA_MASK; -} - -static uint64_t vtd_ir_table(void) -{ - return vtd_readq(DMAR_IRTA_REG) & VTD_IRTA_MASK; -} - -static void vtd_gcmd_or(uint32_t cmd) -{ - uint32_t status; - - /* We only allow set one bit for each time */ - assert(is_power_of_2(cmd)); - - status = vtd_readl(DMAR_GSTS_REG); - vtd_writel(DMAR_GCMD_REG, status | cmd); - - if (cmd & VTD_GCMD_ONE_SHOT_BITS) { - /* One-shot bits are taking effect immediately */ - return; - } - - /* Make sure IOMMU handled our command request */ - while (!(vtd_readl(DMAR_GSTS_REG) & cmd)) - cpu_relax(); -} - -static void vtd_dump_init_info(void) -{ - uint32_t version; - - version = vtd_readl(DMAR_VER_REG); - - /* Major version >= 1 */ - assert(((version >> 3) & 0xf) >= 1); - - printf("VT-d version: %#x\n", version); - printf(" cap: %#018lx\n", vtd_readq(DMAR_CAP_REG)); - printf(" ecap: %#018lx\n", vtd_readq(DMAR_ECAP_REG)); -} - -static void vtd_setup_root_table(void) -{ - void *root = alloc_page(); - - vtd_writeq(DMAR_RTADDR_REG, virt_to_phys(root)); - vtd_gcmd_or(VTD_GCMD_ROOT); - printf("DMAR table address: %#018lx\n", vtd_root_table()); -} - -static void vtd_setup_ir_table(void) -{ - void *root = alloc_page(); - - /* 0xf stands for table size (2^(0xf+1) == 65536) */ - vtd_writeq(DMAR_IRTA_REG, virt_to_phys(root) | 0xf); - vtd_gcmd_or(VTD_GCMD_IR_TABLE); - printf("IR table address: %#018lx\n", vtd_ir_table()); -} - -static void vtd_install_pte(vtd_pte_t *root, iova_t iova, - phys_addr_t pa, int level_target) -{ - int level; - unsigned int offset; - void *page; - - for (level = VTD_PAGE_LEVEL; level > level_target; level--) { - offset = PGDIR_OFFSET(iova, level); - if (!(root[offset] & VTD_PTE_RW)) { - page = alloc_page(); - root[offset] = virt_to_phys(page) | VTD_PTE_RW; - } - root = (uint64_t *)(phys_to_virt(root[offset] & - VTD_PTE_ADDR)); - } - - offset = PGDIR_OFFSET(iova, level); - root[offset] = pa | VTD_PTE_RW; - if (level != 1) { - /* This is huge page */ - root[offset] |= VTD_PTE_HUGE; - } -} - -/** - * vtd_map_range: setup IO address mapping for specific memory range - * - * @sid: source ID of the device to setup - * @iova: start IO virtual address - * @pa: start physical address - * @size: size of the mapping area - */ -void vtd_map_range(uint16_t sid, iova_t iova, phys_addr_t pa, size_t size) -{ - uint8_t bus_n, devfn; - void *slptptr; - vtd_ce_t *ce; - vtd_re_t *re = phys_to_virt(vtd_root_table()); - - assert(IS_ALIGNED(iova, SZ_4K)); - assert(IS_ALIGNED(pa, SZ_4K)); - assert(IS_ALIGNED(size, SZ_4K)); - - bus_n = PCI_BDF_GET_BUS(sid); - devfn = PCI_BDF_GET_DEVFN(sid); - - /* Point to the correct root entry */ - re += bus_n; - - if (!re->present) { - ce = alloc_page(); - memset(re, 0, sizeof(*re)); - re->context_table_p = virt_to_phys(ce) >> VTD_PAGE_SHIFT; - re->present = 1; - printf("allocated vt-d root entry for PCI bus %d\n", - bus_n); - } else - ce = phys_to_virt(re->context_table_p << VTD_PAGE_SHIFT); - - /* Point to the correct context entry */ - ce += devfn; - - if (!ce->present) { - slptptr = alloc_page(); - memset(ce, 0, sizeof(*ce)); - /* To make it simple, domain ID is the same as SID */ - ce->domain_id = sid; - /* We only test 39 bits width case (3-level paging) */ - ce->addr_width = VTD_CE_AW_39BIT; - ce->slptptr = virt_to_phys(slptptr) >> VTD_PAGE_SHIFT; - ce->trans_type = VTD_CONTEXT_TT_MULTI_LEVEL; - ce->present = 1; - /* No error reporting yet */ - ce->disable_fault_report = 1; - printf("allocated vt-d context entry for devfn %#x\n", - devfn); - } else - slptptr = phys_to_virt(ce->slptptr << VTD_PAGE_SHIFT); - - while (size) { - /* TODO: currently we only map 4K pages (level = 1) */ - printf("map 4K page IOVA %#lx to %#lx (sid=%#06x)\n", - iova, pa, sid); - vtd_install_pte(slptptr, iova, pa, 1); - size -= VTD_PAGE_SIZE; - iova += VTD_PAGE_SIZE; - pa += VTD_PAGE_SIZE; - } -} - -static uint16_t vtd_intr_index_alloc(void) -{ - static volatile int index_ctr = 0; - int ctr; - - assert(index_ctr < 65535); - ctr = atomic_inc_fetch(&index_ctr); - printf("INTR: alloc IRTE index %d\n", ctr); - return ctr; -} - -static void vtd_setup_irte(struct pci_dev *dev, vtd_irte_t *irte, - int vector, int dest_id, trigger_mode_t trigger) -{ - assert(sizeof(vtd_irte_t) == 16); - memset(irte, 0, sizeof(*irte)); - irte->fault_disable = 1; - irte->dest_mode = 0; /* physical */ - irte->trigger_mode = trigger; - irte->delivery_mode = 0; /* fixed */ - irte->irte_mode = 0; /* remapped */ - irte->vector = vector; - irte->dest_id = dest_id; - irte->source_id = dev->bdf; - irte->sid_q = 0; - irte->sid_vtype = 1; /* full-sid verify */ - irte->present = 1; -} - -struct vtd_msi_addr { - uint32_t __dont_care:2; - uint32_t handle_15:1; /* handle[15] */ - uint32_t shv:1; - uint32_t interrupt_format:1; - uint32_t handle_0_14:15; /* handle[0:14] */ - uint32_t head:12; /* 0xfee */ - uint32_t addr_hi; /* not used except with x2apic */ -} __attribute__ ((packed)); -typedef struct vtd_msi_addr vtd_msi_addr_t; - -struct vtd_msi_data { - uint16_t __reserved; - uint16_t subhandle; -} __attribute__ ((packed)); -typedef struct vtd_msi_data vtd_msi_data_t; - -struct vtd_ioapic_entry { - uint64_t vector:8; - uint64_t __zeros:3; - uint64_t index_15:1; - uint64_t delivery_status:1; - uint64_t polarity:1; - uint64_t remote_irr:1; - uint64_t trigger_mode:1; - uint64_t mask:1; - uint64_t __zeros_2:31; - uint64_t interrupt_format:1; - uint64_t index_0_14:15; -} __attribute__ ((packed)); -typedef struct vtd_ioapic_entry vtd_ioapic_entry_t; - -/** - * vtd_setup_msi - setup MSI message for a device - * - * @dev: PCI device to setup MSI - * @vector: interrupt vector - * @dest_id: destination processor - */ -bool vtd_setup_msi(struct pci_dev *dev, int vector, int dest_id) -{ - vtd_msi_data_t msi_data = {}; - vtd_msi_addr_t msi_addr = {}; - vtd_irte_t *irte = phys_to_virt(vtd_ir_table()); - uint16_t index = vtd_intr_index_alloc(); - - assert(sizeof(vtd_msi_addr_t) == 8); - assert(sizeof(vtd_msi_data_t) == 4); - - /* Use edge irq as default */ - vtd_setup_irte(dev, irte + index, vector, - dest_id, TRIGGER_EDGE); - - msi_addr.handle_15 = index >> 15 & 1; - msi_addr.shv = 0; - msi_addr.interrupt_format = 1; - msi_addr.handle_0_14 = index & 0x7fff; - msi_addr.head = 0xfee; - msi_data.subhandle = 0; - - printf("%s: msi_addr=%#" PRIx64 ", msi_data=%#x\n", __func__, - *(uint64_t *)&msi_addr, *(uint32_t *)&msi_data); - - return pci_setup_msi(dev, *(uint64_t *)&msi_addr, - *(uint32_t *)&msi_data); -} - -void vtd_setup_ioapic_irq(struct pci_dev *dev, int vector, - int dest_id, trigger_mode_t trigger) -{ - vtd_ioapic_entry_t entry = {}; - vtd_irte_t *irte = phys_to_virt(vtd_ir_table()); - ioapic_redir_entry_t *entry_2 = (ioapic_redir_entry_t *)&entry; - uint16_t index = vtd_intr_index_alloc(); - uint8_t line; - - assert(dev); - assert(sizeof(vtd_ioapic_entry_t) == 8); - - vtd_setup_irte(dev, irte + index, vector, - dest_id, trigger); - - entry.vector = vector; - entry.trigger_mode = trigger; - entry.index_15 = (index >> 15) & 1; - entry.interrupt_format = 1; - entry.index_0_14 = index & 0x7fff; - - line = pci_intx_line(dev); - ioapic_write_redir(line, *entry_2); -} - -void vtd_init(void) -{ - vtd_reg_base = ioremap(Q35_HOST_BRIDGE_IOMMU_ADDR, PAGE_SIZE); - - vtd_dump_init_info(); - vtd_gcmd_or(VTD_GCMD_QI); /* Enable QI */ - vtd_setup_root_table(); - vtd_setup_ir_table(); - vtd_gcmd_or(VTD_GCMD_DMAR); /* Enable DMAR */ - vtd_gcmd_or(VTD_GCMD_IR); /* Enable IR */ -} diff --git a/lib/x86/intel-iommu.h b/lib/x86/intel-iommu.h deleted file mode 100644 index 05b9744b..00000000 --- a/lib/x86/intel-iommu.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Intel IOMMU header - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Authors: - * Peter Xu , - * - * This work is licensed under the terms of the GNU LGPL, version 2 or - * later. - * - * (From include/linux/intel-iommu.h) - */ - -#ifndef __INTEL_IOMMU_H__ -#define __INTEL_IOMMU_H__ - -#include "libcflat.h" -#include "isr.h" -#include "smp.h" -#include "desc.h" -#include "pci.h" -#include "asm/io.h" -#include "apic.h" - -#define Q35_HOST_BRIDGE_IOMMU_ADDR 0xfed90000ULL -#define VTD_PAGE_SHIFT PAGE_SHIFT -#define VTD_PAGE_SIZE PAGE_SIZE - -/* - * Intel IOMMU register specification - */ -#define DMAR_VER_REG 0x0 /* Arch version supported by this IOMMU */ -#define DMAR_CAP_REG 0x8 /* Hardware supported capabilities */ -#define DMAR_CAP_REG_HI 0xc /* High 32-bit of DMAR_CAP_REG */ -#define DMAR_ECAP_REG 0x10 /* Extended capabilities supported */ -#define DMAR_ECAP_REG_HI 0X14 -#define DMAR_GCMD_REG 0x18 /* Global command */ -#define DMAR_GSTS_REG 0x1c /* Global status */ -#define DMAR_RTADDR_REG 0x20 /* Root entry table */ -#define DMAR_RTADDR_REG_HI 0X24 -#define DMAR_CCMD_REG 0x28 /* Context command */ -#define DMAR_CCMD_REG_HI 0x2c -#define DMAR_FSTS_REG 0x34 /* Fault status */ -#define DMAR_FECTL_REG 0x38 /* Fault control */ -#define DMAR_FEDATA_REG 0x3c /* Fault event interrupt data */ -#define DMAR_FEADDR_REG 0x40 /* Fault event interrupt addr */ -#define DMAR_FEUADDR_REG 0x44 /* Upper address */ -#define DMAR_AFLOG_REG 0x58 /* Advanced fault control */ -#define DMAR_AFLOG_REG_HI 0X5c -#define DMAR_PMEN_REG 0x64 /* Enable protected memory region */ -#define DMAR_PLMBASE_REG 0x68 /* PMRR low addr */ -#define DMAR_PLMLIMIT_REG 0x6c /* PMRR low limit */ -#define DMAR_PHMBASE_REG 0x70 /* PMRR high base addr */ -#define DMAR_PHMBASE_REG_HI 0X74 -#define DMAR_PHMLIMIT_REG 0x78 /* PMRR high limit */ -#define DMAR_PHMLIMIT_REG_HI 0x7c -#define DMAR_IQH_REG 0x80 /* Invalidation queue head */ -#define DMAR_IQH_REG_HI 0X84 -#define DMAR_IQT_REG 0x88 /* Invalidation queue tail */ -#define DMAR_IQT_REG_HI 0X8c -#define DMAR_IQA_REG 0x90 /* Invalidation queue addr */ -#define DMAR_IQA_REG_HI 0x94 -#define DMAR_ICS_REG 0x9c /* Invalidation complete status */ -#define DMAR_IRTA_REG 0xb8 /* Interrupt remapping table addr */ -#define DMAR_IRTA_REG_HI 0xbc -#define DMAR_IECTL_REG 0xa0 /* Invalidation event control */ -#define DMAR_IEDATA_REG 0xa4 /* Invalidation event data */ -#define DMAR_IEADDR_REG 0xa8 /* Invalidation event address */ -#define DMAR_IEUADDR_REG 0xac /* Invalidation event address */ -#define DMAR_PQH_REG 0xc0 /* Page request queue head */ -#define DMAR_PQH_REG_HI 0xc4 -#define DMAR_PQT_REG 0xc8 /* Page request queue tail*/ -#define DMAR_PQT_REG_HI 0xcc -#define DMAR_PQA_REG 0xd0 /* Page request queue address */ -#define DMAR_PQA_REG_HI 0xd4 -#define DMAR_PRS_REG 0xdc /* Page request status */ -#define DMAR_PECTL_REG 0xe0 /* Page request event control */ -#define DMAR_PEDATA_REG 0xe4 /* Page request event data */ -#define DMAR_PEADDR_REG 0xe8 /* Page request event address */ -#define DMAR_PEUADDR_REG 0xec /* Page event upper address */ -#define DMAR_MTRRCAP_REG 0x100 /* MTRR capability */ -#define DMAR_MTRRCAP_REG_HI 0x104 -#define DMAR_MTRRDEF_REG 0x108 /* MTRR default type */ -#define DMAR_MTRRDEF_REG_HI 0x10c - -#define VTD_GCMD_IR_TABLE 0x1000000 -#define VTD_GCMD_IR 0x2000000 -#define VTD_GCMD_QI 0x4000000 -#define VTD_GCMD_WBF 0x8000000 /* Write Buffer Flush */ -#define VTD_GCMD_SFL 0x20000000 /* Set Fault Log */ -#define VTD_GCMD_ROOT 0x40000000 -#define VTD_GCMD_DMAR 0x80000000 -#define VTD_GCMD_ONE_SHOT_BITS (VTD_GCMD_IR_TABLE | VTD_GCMD_WBF | \ - VTD_GCMD_SFL | VTD_GCMD_ROOT) - -/* Supported Adjusted Guest Address Widths */ -#define VTD_CAP_SAGAW_SHIFT 8 -/* 39-bit AGAW, 3-level page-table */ -#define VTD_CAP_SAGAW_39bit (0x2ULL << VTD_CAP_SAGAW_SHIFT) -/* 48-bit AGAW, 4-level page-table */ -#define VTD_CAP_SAGAW_48bit (0x4ULL << VTD_CAP_SAGAW_SHIFT) -#define VTD_CAP_SAGAW VTD_CAP_SAGAW_39bit - -/* Both 1G/2M huge pages */ -#define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35)) - -#define VTD_CONTEXT_TT_MULTI_LEVEL 0 -#define VTD_CONTEXT_TT_DEV_IOTLB 1 -#define VTD_CONTEXT_TT_PASS_THROUGH 2 - -#define VTD_PTE_R (1 << 0) -#define VTD_PTE_W (1 << 1) -#define VTD_PTE_RW (VTD_PTE_R | VTD_PTE_W) -#define VTD_PTE_ADDR GENMASK_ULL(63, 12) -#define VTD_PTE_HUGE (1 << 7) - -extern void *vtd_reg_base; -#define vtd_reg(reg) ({ assert(vtd_reg_base); \ - (volatile void *)(vtd_reg_base + reg); }) - -static inline void vtd_writel(unsigned int reg, uint32_t value) -{ - __raw_writel(value, vtd_reg(reg)); -} - -static inline void vtd_writeq(unsigned int reg, uint64_t value) -{ - __raw_writeq(value, vtd_reg(reg)); -} - -static inline uint32_t vtd_readl(unsigned int reg) -{ - return __raw_readl(vtd_reg(reg)); -} - -static inline uint64_t vtd_readq(unsigned int reg) -{ - return __raw_readq(vtd_reg(reg)); -} - -void vtd_init(void); -void vtd_map_range(uint16_t sid, phys_addr_t iova, phys_addr_t pa, size_t size); -bool vtd_setup_msi(struct pci_dev *dev, int vector, int dest_id); -void vtd_setup_ioapic_irq(struct pci_dev *dev, int vector, - int dest_id, trigger_mode_t trigger); - -#endif diff --git a/lib/x86/io.c b/lib/x86/io.c deleted file mode 100644 index f4ffb449..00000000 --- a/lib/x86/io.c +++ /dev/null @@ -1,121 +0,0 @@ -#include "libcflat.h" -#include "smp.h" -#include "asm/io.h" -#include "asm/page.h" -#include "vmalloc.h" -#ifndef USE_SERIAL -#define USE_SERIAL -#endif - -static struct spinlock lock; -static int serial_iobase = 0x3f8; -static int serial_inited = 0; - -static void serial_outb(char ch) -{ - u8 lsr; - - do { - lsr = inb(serial_iobase + 0x05); - } while (!(lsr & 0x20)); - - outb(ch, serial_iobase + 0x00); -} - -static void serial_put(char ch) -{ - /* Force carriage return to be performed on \n */ - if (ch == '\n') - serial_outb('\r'); - serial_outb(ch); -} - -static void serial_init(void) -{ - u8 lcr; - - /* set DLAB */ - lcr = inb(serial_iobase + 0x03); - lcr |= 0x80; - outb(lcr, serial_iobase + 0x03); - - /* set baud rate to 115200 */ - outb(0x01, serial_iobase + 0x00); - outb(0x00, serial_iobase + 0x01); - - /* clear DLAB */ - lcr = inb(serial_iobase + 0x03); - lcr &= ~0x80; - outb(lcr, serial_iobase + 0x03); - - /* IER: disable interrupts */ - outb(0x00, serial_iobase + 0x01); - /* LCR: 8 bits, no parity, one stop bit */ - outb(0x03, serial_iobase + 0x03); - /* FCR: disable FIFO queues */ - outb(0x00, serial_iobase + 0x02); - /* MCR: RTS, DTR on */ - outb(0x03, serial_iobase + 0x04); -} - -static void print_serial(const char *buf) -{ - unsigned long len = strlen(buf); -#ifdef USE_SERIAL - unsigned long i; - if (!serial_inited) { - serial_init(); - serial_inited = 1; - } - - for (i = 0; i < len; i++) { - serial_put(buf[i]); - } -#else - asm volatile ("rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1)); -#endif -} - -void puts(const char *s) -{ - spin_lock(&lock); - print_serial(s); - spin_unlock(&lock); -} - -void exit(int code) -{ -#ifdef USE_SERIAL - static const char shutdown_str[8] = "Shutdown"; - int i; - - /* test device exit (with status) */ - outl(code, 0xf4); - - /* if that failed, try the Bochs poweroff port */ - for (i = 0; i < 8; i++) { - outb(shutdown_str[i], 0x8900); - } -#else - asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4)); -#endif - - /* Fallback */ - while (1) { - asm volatile("hlt" ::: "memory"); - } -} - -void __iomem *ioremap(phys_addr_t phys_addr, size_t size) -{ - phys_addr_t base = phys_addr & PAGE_MASK; - phys_addr_t offset = phys_addr - base; - - /* - * The kernel sets PTEs for an ioremap() with page cache disabled, - * but we do not do that right now. It would make sense that I/O - * mappings would be uncached - and may help us find bugs when we - * properly map that way. - */ - return vmap(phys_addr, size) + offset; -} diff --git a/lib/x86/isr.c b/lib/x86/isr.c deleted file mode 100644 index 53c0c2b3..00000000 --- a/lib/x86/isr.c +++ /dev/null @@ -1,125 +0,0 @@ -#include "libcflat.h" -#include "processor.h" -#include "isr.h" -#include "alloc.h" -#include "desc.h" - -extern char isr_entry_point[]; - -asm ( - "isr_entry_point: \n" -#ifdef __x86_64__ - "push %r15 \n\t" - "push %r14 \n\t" - "push %r13 \n\t" - "push %r12 \n\t" - "push %r11 \n\t" - "push %r10 \n\t" - "push %r9 \n\t" - "push %r8 \n\t" -#endif - "push %"R "di \n\t" - "push %"R "si \n\t" - "push %"R "bp \n\t" - "push %"R "sp \n\t" - "push %"R "bx \n\t" - "push %"R "dx \n\t" - "push %"R "cx \n\t" - "push %"R "ax \n\t" -#ifdef __x86_64__ - "mov %rsp, %rdi \n\t" - "callq *8*16(%rsp) \n\t" -#else - "push %esp \n\t" - "calll *4+4*8(%esp) \n\t" - "add $4, %esp \n\t" -#endif - "pop %"R "ax \n\t" - "pop %"R "cx \n\t" - "pop %"R "dx \n\t" - "pop %"R "bx \n\t" - "pop %"R "bp \n\t" - "pop %"R "bp \n\t" - "pop %"R "si \n\t" - "pop %"R "di \n\t" -#ifdef __x86_64__ - "pop %r8 \n\t" - "pop %r9 \n\t" - "pop %r10 \n\t" - "pop %r11 \n\t" - "pop %r12 \n\t" - "pop %r13 \n\t" - "pop %r14 \n\t" - "pop %r15 \n\t" -#endif - ".globl isr_iret_ip\n\t" -#ifdef __x86_64__ - "add $8, %rsp \n\t" - "isr_iret_ip: \n\t" - "iretq \n\t" -#else - "add $4, %esp \n\t" - "isr_iret_ip: \n\t" - "iretl \n\t" -#endif - ); - -void handle_irq(unsigned vec, void (*func)(isr_regs_t *regs)) -{ - u8 *thunk = malloc(50); - - set_idt_entry(vec, thunk, 0); - -#ifdef __x86_64__ - /* sub $8, %rsp */ - *thunk++ = 0x48; *thunk++ = 0x83; *thunk++ = 0xec; *thunk++ = 0x08; - /* mov $func_low, %(rsp) */ - *thunk++ = 0xc7; *thunk++ = 0x04; *thunk++ = 0x24; - *(u32 *)thunk = (ulong)func; thunk += 4; - /* mov $func_high, %(rsp+4) */ - *thunk++ = 0xc7; *thunk++ = 0x44; *thunk++ = 0x24; *thunk++ = 0x04; - *(u32 *)thunk = (ulong)func >> 32; thunk += 4; - /* jmp isr_entry_point */ - *thunk ++ = 0xe9; - *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4); -#else - /* push $func */ - *thunk++ = 0x68; - *(u32 *)thunk = (ulong)func; thunk += 4; - /* jmp isr_entry_point */ - *thunk++ = 0xe9; - *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4); -#endif -} - -void handle_external_interrupt(int vector) -{ - idt_entry_t *idt = &boot_idt[vector]; - unsigned long entry = - idt->offset0 | ((unsigned long)idt->offset1 << 16); -#ifdef __x86_64__ - unsigned long tmp; - entry |= ((unsigned long)idt->offset2 << 32); -#endif - - asm volatile( -#ifdef __x86_64__ - "mov %%rsp, %[sp]\n\t" - "and $0xfffffffffffffff0, %%rsp\n\t" - "push $%c[ss]\n\t" - "push %[sp]\n\t" -#endif - "pushf\n\t" - "orl $0x200, (%%"R "sp)\n\t" - "push $%c[cs]\n\t" - "call *%[entry]\n\t" - : -#ifdef __x86_64__ - [sp]"=&r"(tmp) -#endif - : - [entry]"r"(entry), - [ss]"i"(KERNEL_DS), - [cs]"i"(KERNEL_CS) - ); -} diff --git a/lib/x86/isr.h b/lib/x86/isr.h deleted file mode 100644 index a5092919..00000000 --- a/lib/x86/isr.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __ISR_TEST__ -#define __ISR_TEST__ - -typedef struct { - ulong regs[sizeof(ulong)*2]; - ulong func; - ulong rip; - ulong cs; - ulong rflags; -} isr_regs_t; - -void handle_irq(unsigned vec, void (*func)(isr_regs_t *regs)); -void handle_external_interrupt(int vector); -#endif diff --git a/lib/x86/msr.h b/lib/x86/msr.h deleted file mode 100644 index 6ef55020..00000000 --- a/lib/x86/msr.h +++ /dev/null @@ -1,434 +0,0 @@ -#ifndef _ASM_X86_MSR_INDEX_H -#define _ASM_X86_MSR_INDEX_H - -/* CPU model specific register (MSR) numbers */ - -/* x86-64 specific MSRs */ -#define MSR_EFER 0xc0000080 /* extended feature register */ -#define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */ -#define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */ -#define MSR_CSTAR 0xc0000083 /* compat mode SYSCALL target */ -#define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */ -#define MSR_FS_BASE 0xc0000100 /* 64bit FS base */ -#define MSR_GS_BASE 0xc0000101 /* 64bit GS base */ -#define MSR_KERNEL_GS_BASE 0xc0000102 /* SwapGS GS shadow */ -#define MSR_TSC_AUX 0xc0000103 /* Auxiliary TSC */ - -/* EFER bits: */ -#define _EFER_SCE 0 /* SYSCALL/SYSRET */ -#define _EFER_LME 8 /* Long mode enable */ -#define _EFER_LMA 10 /* Long mode active (read-only) */ -#define _EFER_NX 11 /* No execute enable */ -#define _EFER_SVME 12 /* Enable virtualization */ -#define _EFER_LMSLE 13 /* Long Mode Segment Limit Enable */ -#define _EFER_FFXSR 14 /* Enable Fast FXSAVE/FXRSTOR */ - -#define EFER_SCE (1<<_EFER_SCE) -#define EFER_LME (1<<_EFER_LME) -#define EFER_LMA (1<<_EFER_LMA) -#define EFER_NX (1<<_EFER_NX) -#define EFER_SVME (1<<_EFER_SVME) -#define EFER_LMSLE (1<<_EFER_LMSLE) -#define EFER_FFXSR (1<<_EFER_FFXSR) - -/* Intel MSRs. Some also available on other CPUs */ -#define MSR_IA32_SPEC_CTRL 0x00000048 -#define MSR_IA32_PRED_CMD 0x00000049 - -#define MSR_IA32_PMC0 0x000004c1 -#define MSR_IA32_PERFCTR0 0x000000c1 -#define MSR_IA32_PERFCTR1 0x000000c2 -#define MSR_FSB_FREQ 0x000000cd - -#define MSR_MTRRcap 0x000000fe -#define MSR_IA32_BBL_CR_CTL 0x00000119 - -#define MSR_IA32_SYSENTER_CS 0x00000174 -#define MSR_IA32_SYSENTER_ESP 0x00000175 -#define MSR_IA32_SYSENTER_EIP 0x00000176 - -#define MSR_IA32_MCG_CAP 0x00000179 -#define MSR_IA32_MCG_STATUS 0x0000017a -#define MSR_IA32_MCG_CTL 0x0000017b - -#define MSR_IA32_PEBS_ENABLE 0x000003f1 -#define MSR_IA32_DS_AREA 0x00000600 -#define MSR_IA32_PERF_CAPABILITIES 0x00000345 - -#define MSR_MTRRfix64K_00000 0x00000250 -#define MSR_MTRRfix16K_80000 0x00000258 -#define MSR_MTRRfix16K_A0000 0x00000259 -#define MSR_MTRRfix4K_C0000 0x00000268 -#define MSR_MTRRfix4K_C8000 0x00000269 -#define MSR_MTRRfix4K_D0000 0x0000026a -#define MSR_MTRRfix4K_D8000 0x0000026b -#define MSR_MTRRfix4K_E0000 0x0000026c -#define MSR_MTRRfix4K_E8000 0x0000026d -#define MSR_MTRRfix4K_F0000 0x0000026e -#define MSR_MTRRfix4K_F8000 0x0000026f -#define MSR_MTRRdefType 0x000002ff - -#define MSR_IA32_CR_PAT 0x00000277 - -#define MSR_IA32_DEBUGCTLMSR 0x000001d9 -#define MSR_IA32_LASTBRANCHFROMIP 0x000001db -#define MSR_IA32_LASTBRANCHTOIP 0x000001dc -#define MSR_IA32_LASTINTFROMIP 0x000001dd -#define MSR_IA32_LASTINTTOIP 0x000001de - -/* DEBUGCTLMSR bits (others vary by model): */ -#define DEBUGCTLMSR_LBR (1UL << 0) /* last branch recording */ -#define DEBUGCTLMSR_BTF (1UL << 1) /* single-step on branches */ -#define DEBUGCTLMSR_TR (1UL << 6) -#define DEBUGCTLMSR_BTS (1UL << 7) -#define DEBUGCTLMSR_BTINT (1UL << 8) -#define DEBUGCTLMSR_BTS_OFF_OS (1UL << 9) -#define DEBUGCTLMSR_BTS_OFF_USR (1UL << 10) -#define DEBUGCTLMSR_FREEZE_LBRS_ON_PMI (1UL << 11) - -#define MSR_IA32_MC0_CTL 0x00000400 -#define MSR_IA32_MC0_STATUS 0x00000401 -#define MSR_IA32_MC0_ADDR 0x00000402 -#define MSR_IA32_MC0_MISC 0x00000403 - -#define MSR_IA32_MCx_CTL(x) (MSR_IA32_MC0_CTL + 4*(x)) -#define MSR_IA32_MCx_STATUS(x) (MSR_IA32_MC0_STATUS + 4*(x)) -#define MSR_IA32_MCx_ADDR(x) (MSR_IA32_MC0_ADDR + 4*(x)) -#define MSR_IA32_MCx_MISC(x) (MSR_IA32_MC0_MISC + 4*(x)) - -/* These are consecutive and not in the normal 4er MCE bank block */ -#define MSR_IA32_MC0_CTL2 0x00000280 -#define MSR_IA32_MCx_CTL2(x) (MSR_IA32_MC0_CTL2 + (x)) - -#define CMCI_EN (1ULL << 30) -#define CMCI_THRESHOLD_MASK 0xffffULL - -#define MSR_P6_PERFCTR0 0x000000c1 -#define MSR_P6_PERFCTR1 0x000000c2 -#define MSR_P6_EVNTSEL0 0x00000186 -#define MSR_P6_EVNTSEL1 0x00000187 - -/* AMD64 MSRs. Not complete. See the architecture manual for a more - complete list. */ - -#define MSR_AMD64_PATCH_LEVEL 0x0000008b -#define MSR_AMD64_NB_CFG 0xc001001f -#define MSR_AMD64_PATCH_LOADER 0xc0010020 -#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 -#define MSR_AMD64_OSVW_STATUS 0xc0010141 -#define MSR_AMD64_DC_CFG 0xc0011022 -#define MSR_AMD64_IBSFETCHCTL 0xc0011030 -#define MSR_AMD64_IBSFETCHLINAD 0xc0011031 -#define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 -#define MSR_AMD64_IBSOPCTL 0xc0011033 -#define MSR_AMD64_IBSOPRIP 0xc0011034 -#define MSR_AMD64_IBSOPDATA 0xc0011035 -#define MSR_AMD64_IBSOPDATA2 0xc0011036 -#define MSR_AMD64_IBSOPDATA3 0xc0011037 -#define MSR_AMD64_IBSDCLINAD 0xc0011038 -#define MSR_AMD64_IBSDCPHYSAD 0xc0011039 -#define MSR_AMD64_IBSCTL 0xc001103a - -/* Fam 10h MSRs */ -#define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058 -#define FAM10H_MMIO_CONF_ENABLE (1<<0) -#define FAM10H_MMIO_CONF_BUSRANGE_MASK 0xf -#define FAM10H_MMIO_CONF_BUSRANGE_SHIFT 2 -#define FAM10H_MMIO_CONF_BASE_MASK 0xfffffff -#define FAM10H_MMIO_CONF_BASE_SHIFT 20 -#define MSR_FAM10H_NODE_ID 0xc001100c - -/* K8 MSRs */ -#define MSR_K8_TOP_MEM1 0xc001001a -#define MSR_K8_TOP_MEM2 0xc001001d -#define MSR_K8_SYSCFG 0xc0010010 -#define MSR_K8_INT_PENDING_MSG 0xc0010055 -/* C1E active bits in int pending message */ -#define K8_INTP_C1E_ACTIVE_MASK 0x18000000 -#define MSR_K8_TSEG_ADDR 0xc0010112 -#define K8_MTRRFIXRANGE_DRAM_ENABLE 0x00040000 /* MtrrFixDramEn bit */ -#define K8_MTRRFIXRANGE_DRAM_MODIFY 0x00080000 /* MtrrFixDramModEn bit */ -#define K8_MTRR_RDMEM_WRMEM_MASK 0x18181818 /* Mask: RdMem|WrMem */ - -/* K7 MSRs */ -#define MSR_K7_EVNTSEL0 0xc0010000 -#define MSR_K7_PERFCTR0 0xc0010004 -#define MSR_K7_EVNTSEL1 0xc0010001 -#define MSR_K7_PERFCTR1 0xc0010005 -#define MSR_K7_EVNTSEL2 0xc0010002 -#define MSR_K7_PERFCTR2 0xc0010006 -#define MSR_K7_EVNTSEL3 0xc0010003 -#define MSR_K7_PERFCTR3 0xc0010007 -#define MSR_K7_CLK_CTL 0xc001001b -#define MSR_K7_HWCR 0xc0010015 -#define MSR_K7_FID_VID_CTL 0xc0010041 -#define MSR_K7_FID_VID_STATUS 0xc0010042 - -/* K6 MSRs */ -#define MSR_K6_EFER 0xc0000080 -#define MSR_K6_STAR 0xc0000081 -#define MSR_K6_WHCR 0xc0000082 -#define MSR_K6_UWCCR 0xc0000085 -#define MSR_K6_EPMR 0xc0000086 -#define MSR_K6_PSOR 0xc0000087 -#define MSR_K6_PFIR 0xc0000088 - -/* Centaur-Hauls/IDT defined MSRs. */ -#define MSR_IDT_FCR1 0x00000107 -#define MSR_IDT_FCR2 0x00000108 -#define MSR_IDT_FCR3 0x00000109 -#define MSR_IDT_FCR4 0x0000010a - -#define MSR_IDT_MCR0 0x00000110 -#define MSR_IDT_MCR1 0x00000111 -#define MSR_IDT_MCR2 0x00000112 -#define MSR_IDT_MCR3 0x00000113 -#define MSR_IDT_MCR4 0x00000114 -#define MSR_IDT_MCR5 0x00000115 -#define MSR_IDT_MCR6 0x00000116 -#define MSR_IDT_MCR7 0x00000117 -#define MSR_IDT_MCR_CTRL 0x00000120 - -/* VIA Cyrix defined MSRs*/ -#define MSR_VIA_FCR 0x00001107 -#define MSR_VIA_LONGHAUL 0x0000110a -#define MSR_VIA_RNG 0x0000110b -#define MSR_VIA_BCR2 0x00001147 - -/* Transmeta defined MSRs */ -#define MSR_TMTA_LONGRUN_CTRL 0x80868010 -#define MSR_TMTA_LONGRUN_FLAGS 0x80868011 -#define MSR_TMTA_LRTI_READOUT 0x80868018 -#define MSR_TMTA_LRTI_VOLT_MHZ 0x8086801a - -/* Intel defined MSRs. */ -#define MSR_IA32_P5_MC_ADDR 0x00000000 -#define MSR_IA32_P5_MC_TYPE 0x00000001 -#define MSR_IA32_TSC 0x00000010 -#define MSR_IA32_PLATFORM_ID 0x00000017 -#define MSR_IA32_EBL_CR_POWERON 0x0000002a -#define MSR_IA32_FEATURE_CONTROL 0x0000003a -#define MSR_IA32_TSC_ADJUST 0x0000003b - -#define FEATURE_CONTROL_LOCKED (1<<0) -#define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1<<1) -#define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1<<2) - -#define MSR_IA32_APICBASE 0x0000001b -#define MSR_IA32_APICBASE_BSP (1<<8) -#define MSR_IA32_APICBASE_ENABLE (1<<11) -#define MSR_IA32_APICBASE_BASE (0xfffff<<12) - -#define MSR_IA32_UCODE_WRITE 0x00000079 -#define MSR_IA32_UCODE_REV 0x0000008b - -#define MSR_IA32_ARCH_CAPABILITIES 0x0000010a -#define ARCH_CAP_RDCL_NO (1ULL << 0) -#define ARCH_CAP_IBRS_ALL (1ULL << 1) -#define ARCH_CAP_SKIP_VMENTRY_L1DFLUSH (1ULL << 3) -#define ARCH_CAP_SSB_NO (1ULL << 4) -#define ARCH_CAP_MDS_NO (1ULL << 5) -#define ARCH_CAP_PSCHANGE_MC_NO (1ULL << 6) -#define ARCH_CAP_TSX_CTRL_MSR (1ULL << 7) -#define ARCH_CAP_TAA_NO (1ULL << 8) - -#define MSR_IA32_TSX_CTRL 0x00000122 -#define TSX_CTRL_RTM_DISABLE (1ULL << 0) -#define TSX_CTRL_CPUID_CLEAR (1ULL << 1) - -#define MSR_IA32_PERF_STATUS 0x00000198 -#define MSR_IA32_PERF_CTL 0x00000199 - -#define MSR_IA32_MPERF 0x000000e7 -#define MSR_IA32_APERF 0x000000e8 - -#define MSR_IA32_THERM_CONTROL 0x0000019a -#define MSR_IA32_THERM_INTERRUPT 0x0000019b - -#define THERM_INT_LOW_ENABLE (1 << 0) -#define THERM_INT_HIGH_ENABLE (1 << 1) - -#define MSR_IA32_THERM_STATUS 0x0000019c - -#define THERM_STATUS_PROCHOT (1 << 0) - -#define MSR_THERM2_CTL 0x0000019d - -#define MSR_THERM2_CTL_TM_SELECT (1ULL << 16) - -#define MSR_IA32_MISC_ENABLE 0x000001a0 - -#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2 - -/* MISC_ENABLE bits: architectural */ -#define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << 0) -#define MSR_IA32_MISC_ENABLE_TCC (1ULL << 1) -#define MSR_IA32_MISC_ENABLE_EMON (1ULL << 7) -#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1ULL << 11) -#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1ULL << 12) -#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP (1ULL << 16) -#define MSR_IA32_MISC_ENABLE_MWAIT (1ULL << 18) -#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1ULL << 22) -#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE (1ULL << 23) -#define MSR_IA32_MISC_ENABLE_XD_DISABLE (1ULL << 34) - -/* MISC_ENABLE bits: model-specific, meaning may vary from core to core */ -#define MSR_IA32_MISC_ENABLE_X87_COMPAT (1ULL << 2) -#define MSR_IA32_MISC_ENABLE_TM1 (1ULL << 3) -#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE (1ULL << 4) -#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE (1ULL << 6) -#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK (1ULL << 8) -#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE (1ULL << 9) -#define MSR_IA32_MISC_ENABLE_FERR (1ULL << 10) -#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX (1ULL << 10) -#define MSR_IA32_MISC_ENABLE_TM2 (1ULL << 13) -#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE (1ULL << 19) -#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK (1ULL << 20) -#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT (1ULL << 24) -#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE (1ULL << 37) -#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << 38) -#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << 39) - -/* P4/Xeon+ specific */ -#define MSR_IA32_MCG_EAX 0x00000180 -#define MSR_IA32_MCG_EBX 0x00000181 -#define MSR_IA32_MCG_ECX 0x00000182 -#define MSR_IA32_MCG_EDX 0x00000183 -#define MSR_IA32_MCG_ESI 0x00000184 -#define MSR_IA32_MCG_EDI 0x00000185 -#define MSR_IA32_MCG_EBP 0x00000186 -#define MSR_IA32_MCG_ESP 0x00000187 -#define MSR_IA32_MCG_EFLAGS 0x00000188 -#define MSR_IA32_MCG_EIP 0x00000189 -#define MSR_IA32_MCG_RESERVED 0x0000018a - -/* Pentium IV performance counter MSRs */ -#define MSR_P4_BPU_PERFCTR0 0x00000300 -#define MSR_P4_BPU_PERFCTR1 0x00000301 -#define MSR_P4_BPU_PERFCTR2 0x00000302 -#define MSR_P4_BPU_PERFCTR3 0x00000303 -#define MSR_P4_MS_PERFCTR0 0x00000304 -#define MSR_P4_MS_PERFCTR1 0x00000305 -#define MSR_P4_MS_PERFCTR2 0x00000306 -#define MSR_P4_MS_PERFCTR3 0x00000307 -#define MSR_P4_FLAME_PERFCTR0 0x00000308 -#define MSR_P4_FLAME_PERFCTR1 0x00000309 -#define MSR_P4_FLAME_PERFCTR2 0x0000030a -#define MSR_P4_FLAME_PERFCTR3 0x0000030b -#define MSR_P4_IQ_PERFCTR0 0x0000030c -#define MSR_P4_IQ_PERFCTR1 0x0000030d -#define MSR_P4_IQ_PERFCTR2 0x0000030e -#define MSR_P4_IQ_PERFCTR3 0x0000030f -#define MSR_P4_IQ_PERFCTR4 0x00000310 -#define MSR_P4_IQ_PERFCTR5 0x00000311 -#define MSR_P4_BPU_CCCR0 0x00000360 -#define MSR_P4_BPU_CCCR1 0x00000361 -#define MSR_P4_BPU_CCCR2 0x00000362 -#define MSR_P4_BPU_CCCR3 0x00000363 -#define MSR_P4_MS_CCCR0 0x00000364 -#define MSR_P4_MS_CCCR1 0x00000365 -#define MSR_P4_MS_CCCR2 0x00000366 -#define MSR_P4_MS_CCCR3 0x00000367 -#define MSR_P4_FLAME_CCCR0 0x00000368 -#define MSR_P4_FLAME_CCCR1 0x00000369 -#define MSR_P4_FLAME_CCCR2 0x0000036a -#define MSR_P4_FLAME_CCCR3 0x0000036b -#define MSR_P4_IQ_CCCR0 0x0000036c -#define MSR_P4_IQ_CCCR1 0x0000036d -#define MSR_P4_IQ_CCCR2 0x0000036e -#define MSR_P4_IQ_CCCR3 0x0000036f -#define MSR_P4_IQ_CCCR4 0x00000370 -#define MSR_P4_IQ_CCCR5 0x00000371 -#define MSR_P4_ALF_ESCR0 0x000003ca -#define MSR_P4_ALF_ESCR1 0x000003cb -#define MSR_P4_BPU_ESCR0 0x000003b2 -#define MSR_P4_BPU_ESCR1 0x000003b3 -#define MSR_P4_BSU_ESCR0 0x000003a0 -#define MSR_P4_BSU_ESCR1 0x000003a1 -#define MSR_P4_CRU_ESCR0 0x000003b8 -#define MSR_P4_CRU_ESCR1 0x000003b9 -#define MSR_P4_CRU_ESCR2 0x000003cc -#define MSR_P4_CRU_ESCR3 0x000003cd -#define MSR_P4_CRU_ESCR4 0x000003e0 -#define MSR_P4_CRU_ESCR5 0x000003e1 -#define MSR_P4_DAC_ESCR0 0x000003a8 -#define MSR_P4_DAC_ESCR1 0x000003a9 -#define MSR_P4_FIRM_ESCR0 0x000003a4 -#define MSR_P4_FIRM_ESCR1 0x000003a5 -#define MSR_P4_FLAME_ESCR0 0x000003a6 -#define MSR_P4_FLAME_ESCR1 0x000003a7 -#define MSR_P4_FSB_ESCR0 0x000003a2 -#define MSR_P4_FSB_ESCR1 0x000003a3 -#define MSR_P4_IQ_ESCR0 0x000003ba -#define MSR_P4_IQ_ESCR1 0x000003bb -#define MSR_P4_IS_ESCR0 0x000003b4 -#define MSR_P4_IS_ESCR1 0x000003b5 -#define MSR_P4_ITLB_ESCR0 0x000003b6 -#define MSR_P4_ITLB_ESCR1 0x000003b7 -#define MSR_P4_IX_ESCR0 0x000003c8 -#define MSR_P4_IX_ESCR1 0x000003c9 -#define MSR_P4_MOB_ESCR0 0x000003aa -#define MSR_P4_MOB_ESCR1 0x000003ab -#define MSR_P4_MS_ESCR0 0x000003c0 -#define MSR_P4_MS_ESCR1 0x000003c1 -#define MSR_P4_PMH_ESCR0 0x000003ac -#define MSR_P4_PMH_ESCR1 0x000003ad -#define MSR_P4_RAT_ESCR0 0x000003bc -#define MSR_P4_RAT_ESCR1 0x000003bd -#define MSR_P4_SAAT_ESCR0 0x000003ae -#define MSR_P4_SAAT_ESCR1 0x000003af -#define MSR_P4_SSU_ESCR0 0x000003be -#define MSR_P4_SSU_ESCR1 0x000003bf /* guess: not in manual */ - -#define MSR_P4_TBPU_ESCR0 0x000003c2 -#define MSR_P4_TBPU_ESCR1 0x000003c3 -#define MSR_P4_TC_ESCR0 0x000003c4 -#define MSR_P4_TC_ESCR1 0x000003c5 -#define MSR_P4_U2L_ESCR0 0x000003b0 -#define MSR_P4_U2L_ESCR1 0x000003b1 - -#define MSR_P4_PEBS_MATRIX_VERT 0x000003f2 - -/* Intel Core-based CPU performance counters */ -#define MSR_CORE_PERF_FIXED_CTR0 0x00000309 -#define MSR_CORE_PERF_FIXED_CTR1 0x0000030a -#define MSR_CORE_PERF_FIXED_CTR2 0x0000030b -#define MSR_CORE_PERF_FIXED_CTR_CTRL 0x0000038d -#define MSR_CORE_PERF_GLOBAL_STATUS 0x0000038e -#define MSR_CORE_PERF_GLOBAL_CTRL 0x0000038f -#define MSR_CORE_PERF_GLOBAL_OVF_CTRL 0x00000390 - -/* Geode defined MSRs */ -#define MSR_GEODE_BUSCONT_CONF0 0x00001900 - -/* Intel VT MSRs */ -#define MSR_IA32_VMX_BASIC 0x00000480 -#define MSR_IA32_VMX_PINBASED_CTLS 0x00000481 -#define MSR_IA32_VMX_PROCBASED_CTLS 0x00000482 -#define MSR_IA32_VMX_EXIT_CTLS 0x00000483 -#define MSR_IA32_VMX_ENTRY_CTLS 0x00000484 -#define MSR_IA32_VMX_MISC 0x00000485 -#define MSR_IA32_VMX_CR0_FIXED0 0x00000486 -#define MSR_IA32_VMX_CR0_FIXED1 0x00000487 -#define MSR_IA32_VMX_CR4_FIXED0 0x00000488 -#define MSR_IA32_VMX_CR4_FIXED1 0x00000489 -#define MSR_IA32_VMX_VMCS_ENUM 0x0000048a -#define MSR_IA32_VMX_PROCBASED_CTLS2 0x0000048b -#define MSR_IA32_VMX_EPT_VPID_CAP 0x0000048c -#define MSR_IA32_VMX_TRUE_PIN 0x0000048d -#define MSR_IA32_VMX_TRUE_PROC 0x0000048e -#define MSR_IA32_VMX_TRUE_EXIT 0x0000048f -#define MSR_IA32_VMX_TRUE_ENTRY 0x00000490 - -/* MSR_IA32_VMX_MISC bits */ -#define MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS (1ULL << 29) - -#define MSR_IA32_TSCDEADLINE 0x000006e0 - -/* AMD-V MSRs */ - -#define MSR_VM_CR 0xc0010114 -#define MSR_VM_IGNNE 0xc0010115 -#define MSR_VM_HSAVE_PA 0xc0010117 - -#endif /* _ASM_X86_MSR_INDEX_H */ diff --git a/lib/x86/processor.h b/lib/x86/processor.h deleted file mode 100644 index 74a2498a..00000000 --- a/lib/x86/processor.h +++ /dev/null @@ -1,611 +0,0 @@ -#ifndef LIBCFLAT_PROCESSOR_H -#define LIBCFLAT_PROCESSOR_H - -#include "libcflat.h" -#include "msr.h" -#include - -#ifdef __x86_64__ -# define R "r" -# define W "q" -# define S "8" -#else -# define R "e" -# define W "l" -# define S "4" -#endif - -#define DB_VECTOR 1 -#define BP_VECTOR 3 -#define UD_VECTOR 6 -#define DF_VECTOR 8 -#define TS_VECTOR 10 -#define NP_VECTOR 11 -#define SS_VECTOR 12 -#define GP_VECTOR 13 -#define PF_VECTOR 14 -#define AC_VECTOR 17 - -#define X86_CR0_PE 0x00000001 -#define X86_CR0_MP 0x00000002 -#define X86_CR0_EM 0x00000004 -#define X86_CR0_TS 0x00000008 -#define X86_CR0_WP 0x00010000 -#define X86_CR0_AM 0x00040000 -#define X86_CR0_NW 0x20000000 -#define X86_CR0_CD 0x40000000 -#define X86_CR0_PG 0x80000000 -#define X86_CR3_PCID_MASK 0x00000fff -#define X86_CR4_TSD 0x00000004 -#define X86_CR4_DE 0x00000008 -#define X86_CR4_PSE 0x00000010 -#define X86_CR4_PAE 0x00000020 -#define X86_CR4_MCE 0x00000040 -#define X86_CR4_PGE 0x00000080 -#define X86_CR4_PCE 0x00000100 -#define X86_CR4_UMIP 0x00000800 -#define X86_CR4_LA57 0x00001000 -#define X86_CR4_VMXE 0x00002000 -#define X86_CR4_PCIDE 0x00020000 -#define X86_CR4_SMEP 0x00100000 -#define X86_CR4_SMAP 0x00200000 -#define X86_CR4_PKE 0x00400000 - -#define X86_EFLAGS_CF 0x00000001 -#define X86_EFLAGS_FIXED 0x00000002 -#define X86_EFLAGS_PF 0x00000004 -#define X86_EFLAGS_AF 0x00000010 -#define X86_EFLAGS_ZF 0x00000040 -#define X86_EFLAGS_SF 0x00000080 -#define X86_EFLAGS_TF 0x00000100 -#define X86_EFLAGS_IF 0x00000200 -#define X86_EFLAGS_DF 0x00000400 -#define X86_EFLAGS_OF 0x00000800 -#define X86_EFLAGS_IOPL 0x00003000 -#define X86_EFLAGS_NT 0x00004000 -#define X86_EFLAGS_AC 0x00040000 - -#define X86_EFLAGS_ALU (X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF | \ - X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_OF) - -#define X86_IA32_EFER 0xc0000080 -#define X86_EFER_LMA (1UL << 8) - -/* - * CPU features - */ - -enum cpuid_output_regs { - EAX, - EBX, - ECX, - EDX -}; - -struct cpuid { u32 a, b, c, d; }; - -static inline struct cpuid raw_cpuid(u32 function, u32 index) -{ - struct cpuid r; - asm volatile ("cpuid" - : "=a"(r.a), "=b"(r.b), "=c"(r.c), "=d"(r.d) - : "0"(function), "2"(index)); - return r; -} - -static inline struct cpuid cpuid_indexed(u32 function, u32 index) -{ - u32 level = raw_cpuid(function & 0xf0000000, 0).a; - if (level < function) - return (struct cpuid) { 0, 0, 0, 0 }; - return raw_cpuid(function, index); -} - -static inline struct cpuid cpuid(u32 function) -{ - return cpuid_indexed(function, 0); -} - -static inline u8 cpuid_maxphyaddr(void) -{ - if (raw_cpuid(0x80000000, 0).a < 0x80000008) - return 36; - return raw_cpuid(0x80000008, 0).a & 0xff; -} - -#define CPUID(a, b, c, d) ((((unsigned long long) a) << 32) | (b << 16) | \ - (c << 8) | d) - -/* - * Each X86_FEATURE_XXX definition is 64-bit and contains the following - * CPUID meta-data: - * - * [63:32] : input value for EAX - * [31:16] : input value for ECX - * [15:8] : output register - * [7:0] : bit position in output register - */ - -/* - * Intel CPUID features - */ -#define X86_FEATURE_MWAIT (CPUID(0x1, 0, ECX, 3)) -#define X86_FEATURE_VMX (CPUID(0x1, 0, ECX, 5)) -#define X86_FEATURE_PCID (CPUID(0x1, 0, ECX, 17)) -#define X86_FEATURE_MOVBE (CPUID(0x1, 0, ECX, 22)) -#define X86_FEATURE_TSC_DEADLINE_TIMER (CPUID(0x1, 0, ECX, 24)) -#define X86_FEATURE_XSAVE (CPUID(0x1, 0, ECX, 26)) -#define X86_FEATURE_OSXSAVE (CPUID(0x1, 0, ECX, 27)) -#define X86_FEATURE_RDRAND (CPUID(0x1, 0, ECX, 30)) -#define X86_FEATURE_MCE (CPUID(0x1, 0, EDX, 7)) -#define X86_FEATURE_APIC (CPUID(0x1, 0, EDX, 9)) -#define X86_FEATURE_CLFLUSH (CPUID(0x1, 0, EDX, 19)) -#define X86_FEATURE_XMM (CPUID(0x1, 0, EDX, 25)) -#define X86_FEATURE_XMM2 (CPUID(0x1, 0, EDX, 26)) -#define X86_FEATURE_TSC_ADJUST (CPUID(0x7, 0, EBX, 1)) -#define X86_FEATURE_HLE (CPUID(0x7, 0, EBX, 4)) -#define X86_FEATURE_SMEP (CPUID(0x7, 0, EBX, 7)) -#define X86_FEATURE_INVPCID (CPUID(0x7, 0, EBX, 10)) -#define X86_FEATURE_RTM (CPUID(0x7, 0, EBX, 11)) -#define X86_FEATURE_SMAP (CPUID(0x7, 0, EBX, 20)) -#define X86_FEATURE_PCOMMIT (CPUID(0x7, 0, EBX, 22)) -#define X86_FEATURE_CLFLUSHOPT (CPUID(0x7, 0, EBX, 23)) -#define X86_FEATURE_CLWB (CPUID(0x7, 0, EBX, 24)) -#define X86_FEATURE_UMIP (CPUID(0x7, 0, ECX, 2)) -#define X86_FEATURE_PKU (CPUID(0x7, 0, ECX, 3)) -#define X86_FEATURE_LA57 (CPUID(0x7, 0, ECX, 16)) -#define X86_FEATURE_RDPID (CPUID(0x7, 0, ECX, 22)) -#define X86_FEATURE_SPEC_CTRL (CPUID(0x7, 0, EDX, 26)) -#define X86_FEATURE_ARCH_CAPABILITIES (CPUID(0x7, 0, EDX, 29)) -#define X86_FEATURE_NX (CPUID(0x80000001, 0, EDX, 20)) -#define X86_FEATURE_RDPRU (CPUID(0x80000008, 0, EBX, 4)) - -/* - * AMD CPUID features - */ -#define X86_FEATURE_SVM (CPUID(0x80000001, 0, ECX, 2)) -#define X86_FEATURE_RDTSCP (CPUID(0x80000001, 0, EDX, 27)) -#define X86_FEATURE_AMD_IBPB (CPUID(0x80000008, 0, EBX, 12)) -#define X86_FEATURE_NPT (CPUID(0x8000000A, 0, EDX, 0)) -#define X86_FEATURE_NRIPS (CPUID(0x8000000A, 0, EDX, 3)) - - -static inline bool this_cpu_has(u64 feature) -{ - u32 input_eax = feature >> 32; - u32 input_ecx = (feature >> 16) & 0xffff; - u32 output_reg = (feature >> 8) & 0xff; - u8 bit = feature & 0xff; - struct cpuid c; - u32 *tmp; - - c = cpuid_indexed(input_eax, input_ecx); - tmp = (u32 *)&c; - - return ((*(tmp + (output_reg % 32))) & (1 << bit)); -} - -struct far_pointer32 { - u32 offset; - u16 selector; -} __attribute__((packed)); - -struct descriptor_table_ptr { - u16 limit; - ulong base; -} __attribute__((packed)); - -static inline void barrier(void) -{ - asm volatile ("" : : : "memory"); -} - -static inline void clac(void) -{ - asm volatile (".byte 0x0f, 0x01, 0xca" : : : "memory"); -} - -static inline void stac(void) -{ - asm volatile (".byte 0x0f, 0x01, 0xcb" : : : "memory"); -} - -static inline u16 read_cs(void) -{ - unsigned val; - - asm volatile ("mov %%cs, %0" : "=mr"(val)); - return val; -} - -static inline u16 read_ds(void) -{ - unsigned val; - - asm volatile ("mov %%ds, %0" : "=mr"(val)); - return val; -} - -static inline u16 read_es(void) -{ - unsigned val; - - asm volatile ("mov %%es, %0" : "=mr"(val)); - return val; -} - -static inline u16 read_ss(void) -{ - unsigned val; - - asm volatile ("mov %%ss, %0" : "=mr"(val)); - return val; -} - -static inline u16 read_fs(void) -{ - unsigned val; - - asm volatile ("mov %%fs, %0" : "=mr"(val)); - return val; -} - -static inline u16 read_gs(void) -{ - unsigned val; - - asm volatile ("mov %%gs, %0" : "=mr"(val)); - return val; -} - -static inline unsigned long read_rflags(void) -{ - unsigned long f; - asm volatile ("pushf; pop %0\n\t" : "=rm"(f)); - return f; -} - -static inline void write_ds(unsigned val) -{ - asm volatile ("mov %0, %%ds" : : "rm"(val) : "memory"); -} - -static inline void write_es(unsigned val) -{ - asm volatile ("mov %0, %%es" : : "rm"(val) : "memory"); -} - -static inline void write_ss(unsigned val) -{ - asm volatile ("mov %0, %%ss" : : "rm"(val) : "memory"); -} - -static inline void write_fs(unsigned val) -{ - asm volatile ("mov %0, %%fs" : : "rm"(val) : "memory"); -} - -static inline void write_gs(unsigned val) -{ - asm volatile ("mov %0, %%gs" : : "rm"(val) : "memory"); -} - -static inline void write_rflags(unsigned long f) -{ - asm volatile ("push %0; popf\n\t" : : "rm"(f)); -} - -static inline void set_iopl(int iopl) -{ - unsigned long flags = read_rflags() & ~X86_EFLAGS_IOPL; - flags |= iopl * (X86_EFLAGS_IOPL / 3); - write_rflags(flags); -} - -static inline u64 rdmsr(u32 index) -{ - u32 a, d; - asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(index) : "memory"); - return a | ((u64)d << 32); -} - -static inline void wrmsr(u32 index, u64 val) -{ - u32 a = val, d = val >> 32; - asm volatile ("wrmsr" : : "a"(a), "d"(d), "c"(index) : "memory"); -} - -static inline uint64_t rdpmc(uint32_t index) -{ - uint32_t a, d; - asm volatile ("rdpmc" : "=a"(a), "=d"(d) : "c"(index)); - return a | ((uint64_t)d << 32); -} - -static inline void write_cr0(ulong val) -{ - asm volatile ("mov %0, %%cr0" : : "r"(val) : "memory"); -} - -static inline ulong read_cr0(void) -{ - ulong val; - asm volatile ("mov %%cr0, %0" : "=r"(val) : : "memory"); - return val; -} - -static inline void write_cr2(ulong val) -{ - asm volatile ("mov %0, %%cr2" : : "r"(val) : "memory"); -} - -static inline ulong read_cr2(void) -{ - ulong val; - asm volatile ("mov %%cr2, %0" : "=r"(val) : : "memory"); - return val; -} - -static inline void write_cr3(ulong val) -{ - asm volatile ("mov %0, %%cr3" : : "r"(val) : "memory"); -} - -static inline ulong read_cr3(void) -{ - ulong val; - asm volatile ("mov %%cr3, %0" : "=r"(val) : : "memory"); - return val; -} - -static inline void write_cr4(ulong val) -{ - asm volatile ("mov %0, %%cr4" : : "r"(val) : "memory"); -} - -static inline ulong read_cr4(void) -{ - ulong val; - asm volatile ("mov %%cr4, %0" : "=r"(val) : : "memory"); - return val; -} - -static inline void write_cr8(ulong val) -{ - asm volatile ("mov %0, %%cr8" : : "r"(val) : "memory"); -} - -static inline ulong read_cr8(void) -{ - ulong val; - asm volatile ("mov %%cr8, %0" : "=r"(val) : : "memory"); - return val; -} - -static inline void lgdt(const struct descriptor_table_ptr *ptr) -{ - asm volatile ("lgdt %0" : : "m"(*ptr)); -} - -static inline void sgdt(struct descriptor_table_ptr *ptr) -{ - asm volatile ("sgdt %0" : "=m"(*ptr)); -} - -static inline void lidt(const struct descriptor_table_ptr *ptr) -{ - asm volatile ("lidt %0" : : "m"(*ptr)); -} - -static inline void sidt(struct descriptor_table_ptr *ptr) -{ - asm volatile ("sidt %0" : "=m"(*ptr)); -} - -static inline void lldt(unsigned val) -{ - asm volatile ("lldt %0" : : "rm"(val)); -} - -static inline u16 sldt(void) -{ - u16 val; - asm volatile ("sldt %0" : "=rm"(val)); - return val; -} - -static inline void ltr(u16 val) -{ - asm volatile ("ltr %0" : : "rm"(val)); -} - -static inline u16 str(void) -{ - u16 val; - asm volatile ("str %0" : "=rm"(val)); - return val; -} - -static inline void write_dr6(ulong val) -{ - asm volatile ("mov %0, %%dr6" : : "r"(val) : "memory"); -} - -static inline ulong read_dr6(void) -{ - ulong val; - asm volatile ("mov %%dr6, %0" : "=r"(val)); - return val; -} - -static inline void write_dr7(ulong val) -{ - asm volatile ("mov %0, %%dr7" : : "r"(val) : "memory"); -} - -static inline ulong read_dr7(void) -{ - ulong val; - asm volatile ("mov %%dr7, %0" : "=r"(val)); - return val; -} - -static inline void pause(void) -{ - asm volatile ("pause"); -} - -static inline void cli(void) -{ - asm volatile ("cli"); -} - -static inline void sti(void) -{ - asm volatile ("sti"); -} - -static inline unsigned long long rdtsc(void) -{ - long long r; - -#ifdef __x86_64__ - unsigned a, d; - - asm volatile ("rdtsc" : "=a"(a), "=d"(d)); - r = a | ((long long)d << 32); -#else - asm volatile ("rdtsc" : "=A"(r)); -#endif - return r; -} - -/* - * Per the advice in the SDM, volume 2, the sequence "mfence; lfence" - * executed immediately before rdtsc ensures that rdtsc will be - * executed only after all previous instructions have executed and all - * previous loads and stores are globally visible. In addition, the - * lfence immediately after rdtsc ensures that rdtsc will be executed - * prior to the execution of any subsequent instruction. - */ -static inline unsigned long long fenced_rdtsc(void) -{ - unsigned long long tsc; - -#ifdef __x86_64__ - unsigned int eax, edx; - - asm volatile ("mfence; lfence; rdtsc; lfence" : "=a"(eax), "=d"(edx)); - tsc = eax | ((unsigned long long)edx << 32); -#else - asm volatile ("mfence; lfence; rdtsc; lfence" : "=A"(tsc)); -#endif - return tsc; -} - -static inline unsigned long long rdtscp(u32 *aux) -{ - long long r; - -#ifdef __x86_64__ - unsigned a, d; - - asm volatile ("rdtscp" : "=a"(a), "=d"(d), "=c"(*aux)); - r = a | ((long long)d << 32); -#else - asm volatile ("rdtscp" : "=A"(r), "=c"(*aux)); -#endif - return r; -} - -static inline void wrtsc(u64 tsc) -{ - unsigned a = tsc, d = tsc >> 32; - - asm volatile("wrmsr" : : "a"(a), "d"(d), "c"(0x10)); -} - -static inline void irq_disable(void) -{ - asm volatile("cli"); -} - -/* Note that irq_enable() does not ensure an interrupt shadow due - * to the vagaries of compiler optimizations. If you need the - * shadow, use a single asm with "sti" and the instruction after it. - */ -static inline void irq_enable(void) -{ - asm volatile("sti"); -} - -static inline void invlpg(volatile void *va) -{ - asm volatile("invlpg (%0)" ::"r" (va) : "memory"); -} - -static inline void safe_halt(void) -{ - asm volatile("sti; hlt"); -} - -static inline u32 read_pkru(void) -{ - unsigned int eax, edx; - unsigned int ecx = 0; - unsigned int pkru; - - asm volatile(".byte 0x0f,0x01,0xee\n\t" - : "=a" (eax), "=d" (edx) - : "c" (ecx)); - pkru = eax; - return pkru; -} - -static inline void write_pkru(u32 pkru) -{ - unsigned int eax = pkru; - unsigned int ecx = 0; - unsigned int edx = 0; - - asm volatile(".byte 0x0f,0x01,0xef\n\t" - : : "a" (eax), "c" (ecx), "d" (edx)); -} - -static inline bool is_canonical(u64 addr) -{ - return (s64)(addr << 16) >> 16 == addr; -} - -static inline void clear_bit(int bit, u8 *addr) -{ - __asm__ __volatile__("btr %1, %0" - : "+m" (*addr) : "Ir" (bit) : "cc", "memory"); -} - -static inline void set_bit(int bit, u8 *addr) -{ - __asm__ __volatile__("bts %1, %0" - : "+m" (*addr) : "Ir" (bit) : "cc", "memory"); -} - -static inline void flush_tlb(void) -{ - ulong cr4; - - cr4 = read_cr4(); - write_cr4(cr4 ^ X86_CR4_PGE); - write_cr4(cr4); -} - -static inline int has_spec_ctrl(void) -{ - return !!(this_cpu_has(X86_FEATURE_SPEC_CTRL)); -} - -static inline int cpu_has_efer_nx(void) -{ - return !!(this_cpu_has(X86_FEATURE_NX)); -} - -#endif diff --git a/lib/x86/setjmp32.S b/lib/x86/setjmp32.S deleted file mode 100644 index b0be7c21..00000000 --- a/lib/x86/setjmp32.S +++ /dev/null @@ -1,25 +0,0 @@ -.globl setjmp -setjmp: - mov (%esp), %ecx // get return EIP - mov 4(%esp), %eax // get jmp_buf - mov %ecx, (%eax) - mov %esp, 4(%eax) - mov %ebp, 8(%eax) - mov %ebx, 12(%eax) - mov %esi, 16(%eax) - mov %edi, 20(%eax) - xor %eax, %eax - ret - -.globl longjmp -longjmp: - mov 8(%esp), %eax // get return value - mov 4(%esp), %ecx // get jmp_buf - mov 20(%ecx), %edi - mov 16(%ecx), %esi - mov 12(%ecx), %ebx - mov 8(%ecx), %ebp - mov 4(%ecx), %esp - mov (%ecx), %ecx // get saved EIP - mov %ecx, (%esp) // and store it on the stack - ret diff --git a/lib/x86/setjmp64.S b/lib/x86/setjmp64.S deleted file mode 100644 index c8ae7900..00000000 --- a/lib/x86/setjmp64.S +++ /dev/null @@ -1,27 +0,0 @@ -.globl setjmp -setjmp: - mov (%rsp), %rsi - mov %rsi, (%rdi) - mov %rsp, 0x8(%rdi) - mov %rbp, 0x10(%rdi) - mov %rbx, 0x18(%rdi) - mov %r12, 0x20(%rdi) - mov %r13, 0x28(%rdi) - mov %r14, 0x30(%rdi) - mov %r15, 0x38(%rdi) - xor %eax, %eax - ret - -.globl longjmp -longjmp: - mov %esi, %eax - mov 0x38(%rdi), %r15 - mov 0x30(%rdi), %r14 - mov 0x28(%rdi), %r13 - mov 0x20(%rdi), %r12 - mov 0x18(%rdi), %rbx - mov 0x10(%rdi), %rbp - mov 0x8(%rdi), %rsp - mov (%rdi), %rsi - mov %rsi, (%rsp) - ret diff --git a/lib/x86/setup.c b/lib/x86/setup.c deleted file mode 100644 index 7befe096..00000000 --- a/lib/x86/setup.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Initialize machine setup information - * - * Copyright (C) 2017, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include "libcflat.h" -#include "fwcfg.h" -#include "alloc_phys.h" -#include "argv.h" - -extern char edata; - -struct mbi_bootinfo { - u32 flags; - u32 mem_lower; - u32 mem_upper; - u32 boot_device; - u32 cmdline; - u32 mods_count; - u32 mods_addr; - u32 reserved[4]; /* 28-43 */ - u32 mmap_length; - u32 mmap_addr; - u32 reserved0[3]; /* 52-63 */ - u32 bootloader; - u32 reserved1[5]; /* 68-87 */ - u32 size; -}; - -struct mbi_module { - u32 start, end; - u32 cmdline; - u32 unused; -}; - -struct mbi_mem { - u32 size; - u64 base_addr; - u64 length; - u32 type; -} __attribute__((packed)); - -#define ENV_SIZE 16384 - -void setup_env(char *env, int size); -void setup_multiboot(struct mbi_bootinfo *bootinfo); -void setup_libcflat(void); - -char *initrd; -u32 initrd_size; - -static char env[ENV_SIZE]; -static struct mbi_bootinfo *bootinfo; - -#define HUGEPAGE_SIZE (1 << 21) - -#ifdef __x86_64__ -void find_highmem(void) -{ - /* Memory above 4 GB is only supported on 64-bit systems. */ - if (!(bootinfo->flags & 64)) - return; - - u64 upper_end = bootinfo->mem_upper * 1024ull; - u64 best_start = (uintptr_t) &edata; - u64 best_end = upper_end; - u64 max_end = fwcfg_get_u64(FW_CFG_MAX_RAM); - if (max_end == 0) - max_end = -1ull; - bool found = false; - - uintptr_t mmap = bootinfo->mmap_addr; - while (mmap < bootinfo->mmap_addr + bootinfo->mmap_length) { - struct mbi_mem *mem = (void *)mmap; - mmap += mem->size + 4; - if (mem->type != 1) - continue; - if (mem->base_addr <= (uintptr_t) &edata || - (mem->base_addr <= upper_end && mem->base_addr + mem->length <= upper_end)) - continue; - if (mem->length < best_end - best_start) - continue; - if (mem->base_addr >= max_end) - continue; - best_start = mem->base_addr; - best_end = mem->base_addr + mem->length; - if (best_end > max_end) - best_end = max_end; - found = true; - } - - if (found) { - best_start = (best_start + HUGEPAGE_SIZE - 1) & -HUGEPAGE_SIZE; - best_end = best_end & -HUGEPAGE_SIZE; - phys_alloc_init(best_start, best_end - best_start); - } -} -#endif - -void setup_multiboot(struct mbi_bootinfo *bi) -{ - struct mbi_module *mods; - - bootinfo = bi; - - u64 best_start = (uintptr_t) &edata; - u64 best_end = bootinfo->mem_upper * 1024ull; - phys_alloc_init(best_start, best_end - best_start); - - if (bootinfo->mods_count != 1) - return; - - mods = (struct mbi_module *)(uintptr_t) bootinfo->mods_addr; - - initrd = (char *)(uintptr_t) mods->start; - initrd_size = mods->end - mods->start; -} - -void setup_libcflat(void) -{ - if (initrd) { - /* environ is currently the only file in the initrd */ - u32 size = MIN(initrd_size, ENV_SIZE); - const char *str; - - memcpy(env, initrd, size); - setup_env(env, size); - if ((str = getenv("BOOTLOADER")) && atol(str) != 0) - add_setup_arg("bootloader"); - } -} diff --git a/lib/x86/smp.c b/lib/x86/smp.c deleted file mode 100644 index 2ac0ef74..00000000 --- a/lib/x86/smp.c +++ /dev/null @@ -1,148 +0,0 @@ - -#include -#include "processor.h" -#include "atomic.h" -#include "smp.h" -#include "apic.h" -#include "fwcfg.h" -#include "desc.h" - -#define IPI_VECTOR 0x20 - -typedef void (*ipi_function_type)(void *data); - -static struct spinlock ipi_lock; -static volatile ipi_function_type ipi_function; -static void *volatile ipi_data; -static volatile int ipi_done; -static volatile bool ipi_wait; -static int _cpu_count; -static atomic_t active_cpus; - -static __attribute__((used)) void ipi(void) -{ - void (*function)(void *data) = ipi_function; - void *data = ipi_data; - bool wait = ipi_wait; - - if (!wait) { - ipi_done = 1; - apic_write(APIC_EOI, 0); - } - function(data); - atomic_dec(&active_cpus); - if (wait) { - ipi_done = 1; - apic_write(APIC_EOI, 0); - } -} - -asm ( - "ipi_entry: \n" - " call ipi \n" -#ifndef __x86_64__ - " iret" -#else - " iretq" -#endif - ); - -int cpu_count(void) -{ - return _cpu_count; -} - -int smp_id(void) -{ - unsigned id; - - asm ("mov %%gs:0, %0" : "=r"(id)); - return id; -} - -static void setup_smp_id(void *data) -{ - asm ("mov %0, %%gs:0" : : "r"(apic_id()) : "memory"); -} - -static void __on_cpu(int cpu, void (*function)(void *data), void *data, - int wait) -{ - unsigned int target = id_map[cpu]; - - spin_lock(&ipi_lock); - if (target == smp_id()) - function(data); - else { - atomic_inc(&active_cpus); - ipi_done = 0; - ipi_function = function; - ipi_data = data; - ipi_wait = wait; - apic_icr_write(APIC_INT_ASSERT | APIC_DEST_PHYSICAL | APIC_DM_FIXED - | IPI_VECTOR, target); - while (!ipi_done) - ; - } - spin_unlock(&ipi_lock); -} - -void on_cpu(int cpu, void (*function)(void *data), void *data) -{ - __on_cpu(cpu, function, data, 1); -} - -void on_cpu_async(int cpu, void (*function)(void *data), void *data) -{ - __on_cpu(cpu, function, data, 0); -} - -void on_cpus(void (*function)(void *data), void *data) -{ - int cpu; - - for (cpu = cpu_count() - 1; cpu >= 0; --cpu) - on_cpu_async(cpu, function, data); - - while (cpus_active() > 1) - pause(); -} - -int cpus_active(void) -{ - return atomic_read(&active_cpus); -} - -void smp_init(void) -{ - int i; - void ipi_entry(void); - - _cpu_count = fwcfg_get_nb_cpus(); - - setup_idt(); - init_apic_map(); - set_idt_entry(IPI_VECTOR, ipi_entry, 0); - - setup_smp_id(0); - for (i = 1; i < cpu_count(); ++i) - on_cpu(i, setup_smp_id, 0); - - atomic_inc(&active_cpus); -} - -static void do_reset_apic(void *data) -{ - reset_apic(); -} - -void smp_reset_apic(void) -{ - int i; - - reset_apic(); - for (i = 1; i < cpu_count(); ++i) - on_cpu(i, do_reset_apic, 0); - - atomic_inc(&active_cpus); -} diff --git a/lib/x86/smp.h b/lib/x86/smp.h deleted file mode 100644 index 09dfa86f..00000000 --- a/lib/x86/smp.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __SMP_H -#define __SMP_H -#include - -void smp_init(void); - -int cpu_count(void); -int smp_id(void); -int cpus_active(void); -void on_cpu(int cpu, void (*function)(void *data), void *data); -void on_cpu_async(int cpu, void (*function)(void *data), void *data); -void on_cpus(void (*function)(void *data), void *data); -void smp_reset_apic(void); - -#endif diff --git a/lib/x86/stack.c b/lib/x86/stack.c deleted file mode 100644 index 5ecd97ce..00000000 --- a/lib/x86/stack.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -int backtrace_frame(const void *frame, const void **return_addrs, int max_depth) -{ - static int walking; - int depth = 0; - const unsigned long *bp = (unsigned long *) frame; - - if (walking) { - printf("RECURSIVE STACK WALK!!!\n"); - return 0; - } - walking = 1; - - for (depth = 0; bp && depth < max_depth; depth++) { - return_addrs[depth] = (void *) bp[1]; - if (return_addrs[depth] == 0) - break; - bp = (unsigned long *) bp[0]; - } - - walking = 0; - return depth; -} - -int backtrace(const void **return_addrs, int max_depth) -{ - return backtrace_frame(__builtin_frame_address(0), return_addrs, - max_depth); -} diff --git a/lib/x86/usermode.c b/lib/x86/usermode.c deleted file mode 100644 index f0325236..00000000 --- a/lib/x86/usermode.c +++ /dev/null @@ -1,113 +0,0 @@ -#include "x86/msr.h" -#include "x86/processor.h" -#include "x86/apic-defs.h" -#include "x86/apic.h" -#include "x86/desc.h" -#include "x86/isr.h" -#include "alloc.h" -#include "setjmp.h" -#include "usermode.h" - -#include "libcflat.h" -#include - -#define USERMODE_STACK_SIZE 0x2000 -#define RET_TO_KERNEL_IRQ 0x20 - -static jmp_buf jmpbuf; - -static void restore_exec_to_jmpbuf(void) -{ - longjmp(jmpbuf, 1); -} - -static void restore_exec_to_jmpbuf_exception_handler(struct ex_regs *regs) -{ - /* longjmp must happen after iret, so do not do it now. */ - regs->rip = (unsigned long)&restore_exec_to_jmpbuf; - regs->cs = KERNEL_CS; -} - -uint64_t run_in_user(usermode_func func, unsigned int fault_vector, - uint64_t arg1, uint64_t arg2, uint64_t arg3, - uint64_t arg4, bool *raised_vector) -{ - extern char ret_to_kernel; - uint64_t rax = 0; - static unsigned char user_stack[USERMODE_STACK_SIZE]; - - *raised_vector = 0; - set_idt_entry(RET_TO_KERNEL_IRQ, &ret_to_kernel, 3); - handle_exception(fault_vector, - restore_exec_to_jmpbuf_exception_handler); - - if (setjmp(jmpbuf) != 0) { - *raised_vector = 1; - return 0; - } - - asm volatile ( - /* Backing Up Stack in rdi */ - "mov %%rsp, %%rdi\n\t" - /* Load user_ds to DS and ES */ - "mov %[user_ds], %%ax\n\t" - "mov %%ax, %%ds\n\t" - "mov %%ax, %%es\n\t" - /* IRET into user mode */ - "pushq %[user_ds]\n\t" - "pushq %[user_stack_top]\n\t" - "pushfq\n\t" - "pushq %[user_cs]\n\t" - "pushq $user_mode\n\t" - "iretq\n" - - "user_mode:\n\t" - /* Back up registers before invoking func */ - "push %%rbx\n\t" - "push %%rcx\n\t" - "push %%rdx\n\t" - "push %%r8\n\t" - "push %%r9\n\t" - "push %%r10\n\t" - "push %%r11\n\t" - "push %%rdi\n\t" - "push %%rsi\n\t" - /* Call user mode function */ - "mov %[arg1], %%rdi\n\t" - "mov %[arg2], %%rsi\n\t" - "mov %[arg3], %%rdx\n\t" - "mov %[arg4], %%rcx\n\t" - "call *%[func]\n\t" - /* Restore registers */ - "pop %%rsi\n\t" - "pop %%rdi\n\t" - "pop %%r11\n\t" - "pop %%r10\n\t" - "pop %%r9\n\t" - "pop %%r8\n\t" - "pop %%rdx\n\t" - "pop %%rcx\n\t" - "pop %%rbx\n\t" - /* Return to kernel via system call */ - "int %[kernel_entry_vector]\n\t" - /* Kernel Mode */ - "ret_to_kernel:\n\t" - "mov %%rdi, %%rsp\n\t" - : - "+a"(rax) - : - [arg1]"m"(arg1), - [arg2]"m"(arg2), - [arg3]"m"(arg3), - [arg4]"m"(arg4), - [func]"m"(func), - [user_ds]"i"(USER_DS), - [user_cs]"i"(USER_CS), - [user_stack_top]"r"(user_stack + - sizeof(user_stack)), - [kernel_entry_vector]"i"(RET_TO_KERNEL_IRQ) - : - "rsi", "rdi", "rcx", "rdx"); - - return rax; -} diff --git a/lib/x86/usermode.h b/lib/x86/usermode.h deleted file mode 100644 index 4e005e65..00000000 --- a/lib/x86/usermode.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _USERMODE_H_ -#define _USERMODE_H_ - -#include "x86/msr.h" -#include "x86/processor.h" -#include "x86/apic-defs.h" -#include "x86/apic.h" -#include "x86/desc.h" -#include "x86/isr.h" -#include "alloc.h" -#include "setjmp.h" - -#include "libcflat.h" -#include - -typedef uint64_t (*usermode_func)(void); - -/* - * Run function in user mode - * Supports running functions with up to 4 arguments. - * fault_vector: exception vector that might get thrown during the function. - * raised_vector: outputs true if exception occurred. - * - * returns: return value returned by function, or 0 if an exception occurred. - */ -uint64_t run_in_user(usermode_func func, unsigned int fault_vector, - uint64_t arg1, uint64_t arg2, uint64_t arg3, - uint64_t arg4, bool *raised_vector); - -#endif diff --git a/lib/x86/vm.c b/lib/x86/vm.c deleted file mode 100644 index 41d6d96d..00000000 --- a/lib/x86/vm.c +++ /dev/null @@ -1,258 +0,0 @@ -#include "vm.h" -#include "libcflat.h" -#include "vmalloc.h" -#include "alloc_page.h" - -pteval_t *install_pte(pgd_t *cr3, - int pte_level, - void *virt, - pteval_t pte, - pteval_t *pt_page) -{ - int level; - pteval_t *pt = cr3; - unsigned offset; - - for (level = PAGE_LEVEL; level > pte_level; --level) { - offset = PGDIR_OFFSET((uintptr_t)virt, level); - if (!(pt[offset] & PT_PRESENT_MASK)) { - pteval_t *new_pt = pt_page; - if (!new_pt) - new_pt = alloc_page(); - else - pt_page = 0; - memset(new_pt, 0, PAGE_SIZE); - pt[offset] = virt_to_phys(new_pt) | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK; - } - pt = phys_to_virt(pt[offset] & PT_ADDR_MASK); - } - offset = PGDIR_OFFSET((uintptr_t)virt, level); - pt[offset] = pte; - return &pt[offset]; -} - -/* - * Finds last PTE in the mapping of @virt that's at or above @lowest_level. The - * returned PTE isn't necessarily present, but its parent is. - */ -struct pte_search find_pte_level(pgd_t *cr3, void *virt, - int lowest_level) -{ - pteval_t *pt = cr3, pte; - unsigned offset; - unsigned shift; - struct pte_search r; - - assert(lowest_level >= 1 && lowest_level <= PAGE_LEVEL); - - for (r.level = PAGE_LEVEL;; --r.level) { - shift = (r.level - 1) * PGDIR_WIDTH + 12; - offset = ((uintptr_t)virt >> shift) & PGDIR_MASK; - r.pte = &pt[offset]; - pte = *r.pte; - - if (!(pte & PT_PRESENT_MASK)) - return r; - - if ((r.level == 2 || r.level == 3) && (pte & PT_PAGE_SIZE_MASK)) - return r; - - if (r.level == lowest_level) - return r; - - pt = phys_to_virt(pte & 0xffffffffff000ull); - } -} - -/* - * Returns the leaf PTE in the mapping of @virt (i.e., 4K PTE or a present huge - * PTE). Returns NULL if no leaf PTE exists. - */ -pteval_t *get_pte(pgd_t *cr3, void *virt) -{ - struct pte_search search; - - search = find_pte_level(cr3, virt, 1); - return found_leaf_pte(search) ? search.pte : NULL; -} - -/* - * Returns the PTE in the mapping of @virt at the given level @pte_level. - * Returns NULL if the PT at @pte_level isn't present (i.e., the mapping at - * @pte_level - 1 isn't present). - */ -pteval_t *get_pte_level(pgd_t *cr3, void *virt, int pte_level) -{ - struct pte_search search; - - search = find_pte_level(cr3, virt, pte_level); - return search.level == pte_level ? search.pte : NULL; -} - -pteval_t *install_large_page(pgd_t *cr3, phys_addr_t phys, void *virt) -{ - return install_pte(cr3, 2, virt, - phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK | PT_PAGE_SIZE_MASK, 0); -} - -pteval_t *install_page(pgd_t *cr3, phys_addr_t phys, void *virt) -{ - return install_pte(cr3, 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK, 0); -} - -void install_pages(pgd_t *cr3, phys_addr_t phys, size_t len, void *virt) -{ - phys_addr_t max = (u64)len + (u64)phys; - assert(phys % PAGE_SIZE == 0); - assert((uintptr_t) virt % PAGE_SIZE == 0); - assert(len % PAGE_SIZE == 0); - - while (phys + PAGE_SIZE <= max) { - install_page(cr3, phys, virt); - phys += PAGE_SIZE; - virt = (char *) virt + PAGE_SIZE; - } -} - -bool any_present_pages(pgd_t *cr3, void *virt, size_t len) -{ - uintptr_t max = (uintptr_t) virt + len; - uintptr_t curr; - - for (curr = (uintptr_t) virt; curr < max; curr += PAGE_SIZE) { - pteval_t *ptep = get_pte(cr3, (void *) curr); - if (ptep && (*ptep & PT_PRESENT_MASK)) - return true; - } - return false; -} - -static void setup_mmu_range(pgd_t *cr3, phys_addr_t start, size_t len) -{ - u64 max = (u64)len + (u64)start; - u64 phys = start; - - while (phys + LARGE_PAGE_SIZE <= max) { - install_large_page(cr3, phys, (void *)(ulong)phys); - phys += LARGE_PAGE_SIZE; - } - install_pages(cr3, phys, max - phys, (void *)(ulong)phys); -} - -void *setup_mmu(phys_addr_t end_of_memory) -{ - pgd_t *cr3 = alloc_page(); - - memset(cr3, 0, PAGE_SIZE); - -#ifdef __x86_64__ - if (end_of_memory < (1ul << 32)) - end_of_memory = (1ul << 32); /* map mmio 1:1 */ - - setup_mmu_range(cr3, 0, end_of_memory); -#else - setup_mmu_range(cr3, 0, (2ul << 30)); - setup_mmu_range(cr3, 3ul << 30, (1ul << 30)); - init_alloc_vpage((void*)(3ul << 30)); -#endif - - write_cr3(virt_to_phys(cr3)); -#ifndef __x86_64__ - write_cr4(X86_CR4_PSE); -#endif - write_cr0(X86_CR0_PG |X86_CR0_PE | X86_CR0_WP); - - printf("paging enabled\n"); - printf("cr0 = %lx\n", read_cr0()); - printf("cr3 = %lx\n", read_cr3()); - printf("cr4 = %lx\n", read_cr4()); - return cr3; -} - -phys_addr_t virt_to_pte_phys(pgd_t *cr3, void *mem) -{ - return (*get_pte(cr3, mem) & PT_ADDR_MASK) + ((ulong)mem & (PAGE_SIZE - 1)); -} - -/* - * split_large_page: Split a 2M/1G large page into 512 smaller PTEs. - * @ptep : large page table entry to split - * @level : level of ptep (2 or 3) - */ -void split_large_page(unsigned long *ptep, int level) -{ - unsigned long *new_pt; - unsigned long pa; - unsigned long pte; - unsigned long prototype; - int i; - - pte = *ptep; - assert(pte & PT_PRESENT_MASK); - assert(pte & PT_PAGE_SIZE_MASK); - assert(level == 2 || level == 3); - - new_pt = alloc_page(); - assert(new_pt); - - prototype = pte & ~PT_ADDR_MASK; - if (level == 2) - prototype &= ~PT_PAGE_SIZE_MASK; - - pa = pte & PT_ADDR_MASK; - for (i = 0; i < (1 << PGDIR_WIDTH); i++) { - new_pt[i] = prototype | pa; - pa += 1ul << PGDIR_BITS(level - 1); - } - - pte &= ~PT_PAGE_SIZE_MASK; - pte &= ~PT_ADDR_MASK; - pte |= virt_to_phys(new_pt); - - /* Modify the relevant paging-structure entry */ - *ptep = pte; - - /* - * Flush the TLB to eradicate stale mappings. - * - * Note: Removing specific TLB mappings is tricky because - * split_large_page() can be called to split the active code page - * backing the next set of instructions to be fetched and executed. - * Furthermore, Intel SDM volume 3 recommends to clear the present bit - * for the page being split, before invalidating any mappings. - * - * But clearing the mapping from the page table and removing it from the - * TLB (where it's not actually guaranteed to reside anyway) makes it - * impossible to continue fetching instructions! - */ - flush_tlb(); -} - -/* - * force_4k_page: Ensures that addr translate to a 4k page. - * - * This function uses split_large_page(), as needed, to ensure that target - * address, addr, translates to a 4k page. - * - * @addr: target address that should be mapped to a 4k page - */ -void force_4k_page(void *addr) -{ - unsigned long *ptep; - unsigned long pte; - unsigned long *cr3 = current_page_table(); - - ptep = get_pte_level(cr3, addr, 3); - assert(ptep); - pte = *ptep; - assert(pte & PT_PRESENT_MASK); - if (pte & PT_PAGE_SIZE_MASK) - split_large_page(ptep, 3); - - ptep = get_pte_level(cr3, addr, 2); - assert(ptep); - pte = *ptep; - assert(pte & PT_PRESENT_MASK); - if (pte & PT_PAGE_SIZE_MASK) - split_large_page(ptep, 2); -} diff --git a/lib/x86/vm.h b/lib/x86/vm.h deleted file mode 100644 index 8750a1e2..00000000 --- a/lib/x86/vm.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef VM_H -#define VM_H - -#include "processor.h" -#include "asm/page.h" -#include "asm/io.h" - -void setup_5level_page_table(void); - -struct pte_search { - int level; - pteval_t *pte; -}; - -static inline bool found_huge_pte(struct pte_search search) -{ - return (search.level == 2 || search.level == 3) && - (*search.pte & PT_PRESENT_MASK) && - (*search.pte & PT_PAGE_SIZE_MASK); -} - -static inline bool found_leaf_pte(struct pte_search search) -{ - return search.level == 1 || found_huge_pte(search); -} - -struct pte_search find_pte_level(pgd_t *cr3, void *virt, - int lowest_level); -pteval_t *get_pte(pgd_t *cr3, void *virt); -pteval_t *get_pte_level(pgd_t *cr3, void *virt, int pte_level); -pteval_t *install_pte(pgd_t *cr3, - int pte_level, - void *virt, - pteval_t pte, - pteval_t *pt_page); - -pteval_t *install_large_page(pgd_t *cr3, phys_addr_t phys, void *virt); -void install_pages(pgd_t *cr3, phys_addr_t phys, size_t len, void *virt); -bool any_present_pages(pgd_t *cr3, void *virt, size_t len); - -static inline void *current_page_table(void) -{ - return phys_to_virt(read_cr3()); -} - -void split_large_page(unsigned long *ptep, int level); -void force_4k_page(void *addr); -#endif diff --git a/powerpc/.gitignore b/powerpc/.gitignore deleted file mode 100644 index 2f017a8e..00000000 --- a/powerpc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -boot_rom.bin diff --git a/powerpc/Makefile b/powerpc/Makefile deleted file mode 100644 index 8a007ab5..00000000 --- a/powerpc/Makefile +++ /dev/null @@ -1 +0,0 @@ -include $(SRCDIR)/$(TEST_DIR)/Makefile.$(ARCH) diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common deleted file mode 100644 index ac3cab6d..00000000 --- a/powerpc/Makefile.common +++ /dev/null @@ -1,81 +0,0 @@ -# -# powerpc common makefile -# -# Authors: Andrew Jones -# - -tests-common = \ - $(TEST_DIR)/selftest.elf \ - $(TEST_DIR)/spapr_hcall.elf \ - $(TEST_DIR)/rtas.elf \ - $(TEST_DIR)/emulator.elf \ - $(TEST_DIR)/tm.elf \ - $(TEST_DIR)/sprs.elf - -tests-all = $(tests-common) $(tests) -all: directories $(TEST_DIR)/boot_rom.bin $(tests-all) - -################################################################## - -CFLAGS += -std=gnu99 -CFLAGS += -ffreestanding -CFLAGS += -O2 -msoft-float -mabi=no-altivec -mno-altivec -CFLAGS += -I $(SRCDIR)/lib -I $(SRCDIR)/lib/libfdt -I lib -CFLAGS += -Wa,-mregnames - -# We want to keep intermediate files -.PRECIOUS: %.o - -asm-offsets = lib/$(ARCH)/asm-offsets.h -include $(SRCDIR)/scripts/asm-offsets.mak - -cflatobjs += lib/util.o -cflatobjs += lib/getchar.o -cflatobjs += lib/alloc_phys.o -cflatobjs += lib/alloc.o -cflatobjs += lib/devicetree.o -cflatobjs += lib/powerpc/io.o -cflatobjs += lib/powerpc/hcall.o -cflatobjs += lib/powerpc/setup.o -cflatobjs += lib/powerpc/rtas.o -cflatobjs += lib/powerpc/processor.o -cflatobjs += lib/powerpc/handlers.o -cflatobjs += lib/powerpc/smp.o - -OBJDIRS += lib/powerpc - -FLATLIBS = $(libcflat) $(LIBFDT_archive) -%.elf: CFLAGS += $(arch_CFLAGS) -%.elf: LDFLAGS = $(arch_LDFLAGS) -nostdlib -pie -n -%.elf: %.o $(FLATLIBS) $(SRCDIR)/powerpc/flat.lds $(cstart.o) $(reloc.o) - $(CC) $(CFLAGS) -c -o $(@:.elf=.aux.o) $(SRCDIR)/lib/auxinfo.c \ - -DPROGNAME=\"$@\" - $(LD) $(LDFLAGS) -o $@ \ - -T $(SRCDIR)/powerpc/flat.lds --build-id=none \ - $(filter %.o, $^) $(FLATLIBS) $(@:.elf=.aux.o) - $(RM) $(@:.elf=.aux.o) - @chmod a-x $@ - @echo -n Checking $@ for unsupported reloc types... - @if $(OBJDUMP) -R $@ | grep R_ | grep -v R_PPC64_RELATIVE; then \ - false; \ - else \ - echo " looks good."; \ - fi - -$(TEST_DIR)/boot_rom.bin: $(TEST_DIR)/boot_rom.elf - dd if=/dev/zero of=$@ bs=256 count=1 - $(OBJCOPY) -O binary $^ $@.tmp - cat $@.tmp >> $@ - $(RM) $@.tmp - -$(TEST_DIR)/boot_rom.elf: CFLAGS = -mbig-endian -$(TEST_DIR)/boot_rom.elf: $(TEST_DIR)/boot_rom.o - $(LD) -EB -nostdlib -Ttext=0x100 --entry=start --build-id=none -o $@ $< - @chmod a-x $@ - -powerpc_clean: libfdt_clean asm_offsets_clean - $(RM) $(TEST_DIR)/*.{o,elf} $(TEST_DIR)/boot_rom.bin \ - $(TEST_DIR)/.*.d lib/powerpc/.*.d - -generated-files = $(asm-offsets) -$(tests-all:.elf=.o) $(cstart.o) $(cflatobjs): $(generated-files) diff --git a/powerpc/Makefile.ppc64 b/powerpc/Makefile.ppc64 deleted file mode 100644 index ea684470..00000000 --- a/powerpc/Makefile.ppc64 +++ /dev/null @@ -1,27 +0,0 @@ -# -# ppc64 makefile -# -# Authors: Andrew Jones -# -bits = 64 - -ifeq ($(ENDIAN),little) - arch_CFLAGS = -mlittle-endian - arch_LDFLAGS = -EL -else - arch_CFLAGS = -mbig-endian - arch_LDFLAGS = -EB -endif - -cstart.o = $(TEST_DIR)/cstart64.o -reloc.o = $(TEST_DIR)/reloc64.o - -OBJDIRS += lib/ppc64 - -# ppc64 specific tests -tests = - -include $(SRCDIR)/$(TEST_DIR)/Makefile.common - -arch_clean: powerpc_clean - $(RM) lib/ppc64/.*.d diff --git a/powerpc/boot_rom.S b/powerpc/boot_rom.S deleted file mode 100644 index 266d61f3..00000000 --- a/powerpc/boot_rom.S +++ /dev/null @@ -1,6 +0,0 @@ -#include "spapr.h" - -.text -.globl start -start: - b SPAPR_KERNEL_LOAD_ADDR - 0x100 diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S deleted file mode 100644 index 972851f9..00000000 --- a/powerpc/cstart64.S +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Entry point and assembler functions for ppc64 tests. - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#define __ASSEMBLY__ -#include -#include -#include -#include - -#include "spapr.h" - -#define P_HANDLER 0x2ff8 - -.section .init - -/* - * start is the entry point. r3 points to the DTB - */ -.globl start -start: - FIXUP_ENDIAN - /* - * We were loaded at QEMU's kernel load address, but we're not - * allowed to link there due to how QEMU deals with linker VMAs, - * so we just linked at zero. This means the first thing to do is - * to find our stack and toc, and then do a relocate. - */ - LOAD_REG_IMMEDIATE(r31, SPAPR_KERNEL_LOAD_ADDR) - ld r1, (p_stack - start)(r31) - ld r2, (p_toc - start)(r31) - add r1, r1, r31 - add r2, r2, r31 - - /* save DTB pointer */ - std r3, 56(r1) - - /* - * Call relocate. relocate is C code, but careful to not use - * any global references, as they may use absolute addresses, - * which are, obviously, not yet relocated. - */ - mr r3, r31 - ld r4, (p_dyn - start)(r31) - add r4, r4, r31 - bl relocate - - /* compute address of call_handler */ - - LOAD_REG_ADDR(r4, call_handler) - std r4, P_HANDLER(0) - - /* relocate vector table to base address 0x0 (MSR_IP = 0) */ - - /* source: r4, dest end: r5, destination: r6 */ - - LOAD_REG_ADDR(r4, __start_interrupts) - LOAD_REG_ADDR(r5, __end_interrupts) - sub r5,r5,r4 - li r6,0x100 - - sub r4,r4,r6 - add r5,r5,r6 - addi r6,r6,-8 -2: li r0,8 - mtctr r0 - /* copy a cache line size */ -3: addi r6,r6,8 - ldx r0,r6,r4 - stdx r0,0,r6 - bdnz 3b - dcbst 0,r6 - /* flush icache */ - sync - icbi 0,r6 - cmpld 0,r6,r5 - blt 2b - sync - isync - - /* patch sc1 if needed */ - bl hcall_have_broken_sc1 - cmpwi r3, 0 - beq 1f - LOAD_REG_ADDR(r3, hcall) - LOAD_REG_IMMEDIATE(r4, SC1_REPLACEMENT) - stw r4, 0(r3) - - /* complete setup */ -1: ld r3, 56(r1) - bl setup - - /* run the test */ - LOAD_REG_ADDR(r3, __argc) - LOAD_REG_ADDR(r4, __argv) - LOAD_REG_ADDR(r5, __environ) - lwz r3, 0(r3) - bl main - bl exit - b halt - -.align 3 -p_stack: .llong stackptr -p_toc: .llong tocptr -p_dyn: .llong dynamic_start - -.text -.align 3 - -.globl hcall -hcall: - sc 1 - blr - -.globl halt -halt: -1: b 1b - -.globl enter_rtas -enter_rtas: - LOAD_REG_ADDR(r11, rtas_entry) - ld r10, 0(r11) - - cmpdi r10,0 - bne external_rtas - - /* Use H_RTAS directly */ - mr r4,r3 - lis r3,KVMPPC_H_RTAS@h - ori r3,r3,KVMPPC_H_RTAS@l - b hcall - -external_rtas: - /* Use external RTAS blob */ - mflr r0 - std r0, 16(r1) - - LOAD_REG_ADDR(r11, rtas_return_loc) - mtlr r11 - - mfmsr r11 - LOAD_REG_IMMEDIATE(r9, RTAS_MSR_MASK) - and r11, r11, r9 - mtsrr0 r10 - mtsrr1 r11 - rfid - b . - -rtas_return_loc: - FIXUP_ENDIAN - ld r0, 16(r1) - mtlr r0 - blr - -call_handler: - /* save context */ - - /* GPRs */ - - .irp i, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 \ - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 - SAVE_GPR(\i, r1) - .endr - mfsprg1 r0 - std r0,GPR1(r1) - - /* lr, xer, ccr */ - - mflr r0 - std r0,_LINK(r1) - - mfxer r0 - std r0,_XER(r1) - - mfcr r0 - std r0,_CCR(r1) - - /* nip and msr */ - - mfsrr0 r0 - std r0, _NIP(r1) - - mfsrr1 r0 - std r0, _MSR(r1) - - /* restore TOC pointer */ - - LOAD_REG_IMMEDIATE(r31, SPAPR_KERNEL_LOAD_ADDR) - ld r2, (p_toc - start)(r31) - - /* FIXME: build stack frame */ - - /* call generic handler */ - - addi r3,r1,STACK_FRAME_OVERHEAD - bl do_handle_exception - - /* restore context */ - - ld r0,_CTR(r1) - mtctr r0 - - ld r0,_LINK(r1) - mtlr r0 - - ld r0,_XER(r1) - mtxer r0 - - ld r0,_CCR(r1) - mtcr r0 - - ld r0, _NIP(r1) - mtsrr0 r0 - - ld r0, _MSR(r1) - mtsrr1 r0 - - .irp i, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 \ - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 - REST_GPR(\i, r1) - .endr - - /* restore r1, as we don't need it anymore */ - - REST_GPR(1,r1) - - rfid - b . - -.section .text.ex - -.macro VECTOR vec - . = \vec - - mtsprg1 r1 /* save r1 */ - mfsprg0 r1 /* get exception stack address */ - subi r1,r1, INT_FRAME_SIZE - - /* save r0 and ctr to call generic handler */ - - SAVE_GPR(0,r1) - - mfctr r0 - std r0,_CTR(r1) - - ld r0, P_HANDLER(0) - mtctr r0 - - li r0,\vec - std r0,_TRAP(r1) - - bctr -.endm - - . = 0x100 - .globl __start_interrupts -__start_interrupts: - -VECTOR(0x100) -VECTOR(0x200) -VECTOR(0x300) -VECTOR(0x400) -VECTOR(0x500) -VECTOR(0x600) -VECTOR(0x700) -VECTOR(0x800) -VECTOR(0x900) - - .align 7 - .globl __end_interrupts -__end_interrupts: - .org P_HANDLER - .llong 0 diff --git a/powerpc/emulator.c b/powerpc/emulator.c deleted file mode 100644 index 147878e2..00000000 --- a/powerpc/emulator.c +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Test some powerpc instructions - */ - -#include -#include - -static int verbose; -static int volatile is_invalid; -static int volatile alignment; - -static void program_check_handler(struct pt_regs *regs, void *opaque) -{ - int *data = opaque; - - if (verbose) { - printf("Detected invalid instruction %#018lx: %08x\n", - regs->nip, *(uint32_t*)regs->nip); - } - - /* the result is bit 16 to 19 of SRR1 - * bit 0: SRR0 contains the address of the next instruction - * bit 1: Trap - * bit 2: Privileged instruction - * bit 3: Illegal instruction - * bit 4: FP enabled exception type - */ - - *data = regs->msr >> 16; - - regs->nip += 4; -} - -static void alignment_handler(struct pt_regs *regs, void *opaque) -{ - int *data = opaque; - - if (verbose) { - printf("Detected alignment exception %#018lx: %08x\n", - regs->nip, *(uint32_t*)regs->nip); - } - - *data = 1; - - regs->nip += 4; -} - -static void test_illegal(void) -{ - report_prefix_push("invalid"); - - is_invalid = 0; - - asm volatile (".long 0"); - - report(is_invalid == 8, "exception"); /* illegal instruction */ - - report_prefix_pop(); -} - -static void test_64bit(void) -{ - uint64_t msr; - - report_prefix_push("64bit"); - - asm("mfmsr %[msr]": [msr] "=r" (msr)); - - report(msr & 0x8000000000000000UL, "detected"); - - report_prefix_pop(); -} - -/** - * Test 'Load String Word Immediate' instruction - */ -static void test_lswi(void) -{ - int i; - char addr[128]; - uint64_t regs[32]; - - report_prefix_push("lswi"); - - /* fill memory with sequence */ - for (i = 0; i < 128; i++) - addr[i] = 1 + i; - - /* check incomplete register filling */ - alignment = 0; - asm volatile ("li r12,-1;" - "mr r11, r12;" - "lswi r11, %[addr], %[len];" - "std r11, 0*8(%[regs]);" - "std r12, 1*8(%[regs]);" - :: - [len] "i" (3), - [addr] "b" (addr), - [regs] "r" (regs) - : - "r11", "r12", "memory"); - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - /* - * lswi is supposed to cause an alignment exception in little endian - * mode, but QEMU does not support it. So in case we do not get an - * exception, this is an expected failure and we run the other tests - */ - report_xfail(!alignment, alignment, "alignment"); - if (alignment) { - report_prefix_pop(); - return; - } -#endif - report(regs[0] == 0x01020300 && regs[1] == (uint64_t)-1, "partial"); - - /* check NB = 0 ==> 32 bytes. */ - asm volatile ("li r19,-1;" - "mr r11, r19; mr r12, r19; mr r13, r19;" - "mr r14, r19; mr r15, r19; mr r16, r19;" - "mr r17, r19; mr r18, r19;" - "lswi r11, %[addr], %[len];" - "std r11, 0*8(%[regs]);" - "std r12, 1*8(%[regs]);" - "std r13, 2*8(%[regs]);" - "std r14, 3*8(%[regs]);" - "std r15, 4*8(%[regs]);" - "std r16, 5*8(%[regs]);" - "std r17, 6*8(%[regs]);" - "std r18, 7*8(%[regs]);" - "std r19, 8*8(%[regs]);" - :: - [len] "i" (0), - [addr] "b" (addr), - [regs] "r" (regs) - : - /* as 32 is the number of bytes, - * we should modify 32/4 = 8 regs, from r11 to r18 - * We check r19 is unmodified by filling it with 1s - * before the instruction. - */ - "r11", "r12", "r13", "r14", "r15", "r16", "r17", - "r18", "r19", "memory"); - - report(regs[0] == 0x01020304 && regs[1] == 0x05060708 && - regs[2] == 0x090a0b0c && regs[3] == 0x0d0e0f10 && - regs[4] == 0x11121314 && regs[5] == 0x15161718 && - regs[6] == 0x191a1b1c && regs[7] == 0x1d1e1f20 && - regs[8] == (uint64_t)-1, "length"); - - /* check wrap around to r0 */ - asm volatile ("li r31,-1;" - "mr r0, r31;" - "lswi r31, %[addr], %[len];" - "std r31, 0*8(%[regs]);" - "std r0, 1*8(%[regs]);" - :: - [len] "i" (8), - [addr] "b" (addr), - [regs] "r" (regs) - : - /* modify two registers from r31, wrap around to r0 */ - "r31", "r0", "memory"); - - report(regs[0] == 0x01020304 && regs[1] == 0x05060708, - "wrap around to r0"); - - /* check wrap around doesn't break RA */ - asm volatile ("mr r29,r1\n" - "li r31,-1\n" - "mr r0,r31\n" - "mr r1, %[addr]\n" - ".long 0x7fe154aa\n" /* lswi r31, r1, 10 */ - "std r31, 0*8(%[regs])\n" - "std r0, 1*8(%[regs])\n" - "std r1, 2*8(%[regs])\n" - "mr r1,r29\n" - :: - [addr] "r" (addr), - [regs] "r" (regs) - : - /* loading three registers from r31 wraps around to r1, - * r1 is saved to r29, as adding it to the clobber - * list doesn't protect it - */ - "r0", "r29", "r31", "memory"); - - /* doc says it is invalid, real proc stops when it comes to - * overwrite the register. - * In all the cases, the register must stay untouched - */ - report(regs[2] == (uint64_t)addr, "Don't overwrite Ra"); - - report_prefix_pop(); -} - -/* - * lswx: Load String Word Indexed X-form - * - * lswx RT,RA,RB - * - * EA = (RA|0) + RB - * n = XER - * - * Load n bytes from address EA into (n / 4) consecutive registers, - * throught RT -> RT + (n / 4) - 1. - * - Data are loaded into 4 low order bytes of registers (Word). - * - The unfilled bytes are set to 0. - * - The sequence of registers wraps around to GPR0. - * - if n == 0, content of RT is undefined - * - RT <= RA or RB < RT + (n + 4) is invalid or result is undefined - * - RT == RA == 0 is invalid - * - * For lswx in little-endian mode, an alignment interrupt always occurs. - * - */ - -static void test_lswx(void) -{ - int i; - char addr[128]; - uint64_t regs[32]; - - report_prefix_push("lswx"); - - /* fill memory with sequence */ - - for (i = 0; i < 128; i++) - addr[i] = 1 + i; - - /* check incomplete register filling */ - - alignment = 0; - asm volatile ("mtxer %[len];" - "li r12,-1;" - "mr r11, r12;" - "lswx r11, 0, %[addr];" - "std r11, 0*8(%[regs]);" - "std r12, 1*8(%[regs]);" - :: - [len] "r" (3), - [addr] "r" (addr), - [regs] "r" (regs) - : - "xer", "r11", "r12", "memory"); - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - /* - * lswx is supposed to cause an alignment exception in little endian - * mode, but QEMU does not support it. So in case we do not get an - * exception, this is an expected failure and we run the other tests - */ - report_xfail(!alignment, alignment, "alignment"); - if (alignment) { - report_prefix_pop(); - return; - } -#endif - report(regs[0] == 0x01020300 && regs[1] == (uint64_t)-1, "partial"); - - /* check an old know bug: the number of bytes is used as - * the number of registers, so try 32 bytes. - */ - - asm volatile ("mtxer %[len];" - "li r19,-1;" - "mr r11, r19; mr r12, r19; mr r13, r19;" - "mr r14, r19; mr r15, r19; mr r16, r19;" - "mr r17, r19; mr r18, r19;" - "lswx r11, 0, %[addr];" - "std r11, 0*8(%[regs]);" - "std r12, 1*8(%[regs]);" - "std r13, 2*8(%[regs]);" - "std r14, 3*8(%[regs]);" - "std r15, 4*8(%[regs]);" - "std r16, 5*8(%[regs]);" - "std r17, 6*8(%[regs]);" - "std r18, 7*8(%[regs]);" - "std r19, 8*8(%[regs]);" - :: - [len] "r" (32), - [addr] "r" (addr), - [regs] "r" (regs) - : - /* as 32 is the number of bytes, - * we should modify 32/4 = 8 regs, from r11 to r18 - * We check r19 is unmodified by filling it with 1s - * before the instruction. - */ - "xer", "r11", "r12", "r13", "r14", "r15", "r16", "r17", - "r18", "r19", "memory"); - - report(regs[0] == 0x01020304 && regs[1] == 0x05060708 && - regs[2] == 0x090a0b0c && regs[3] == 0x0d0e0f10 && - regs[4] == 0x11121314 && regs[5] == 0x15161718 && - regs[6] == 0x191a1b1c && regs[7] == 0x1d1e1f20 && - regs[8] == (uint64_t)-1, "length"); - - /* check wrap around to r0 */ - - asm volatile ("mtxer %[len];" - "li r31,-1;" - "mr r0, r31;" - "lswx r31, 0, %[addr];" - "std r31, 0*8(%[regs]);" - "std r0, 1*8(%[regs]);" - :: - [len] "r" (8), - [addr] "r" (addr), - [regs] "r" (regs) - : - /* modify two registers from r31, wrap around to r0 */ - "xer", "r31", "r0", "memory"); - - report(regs[0] == 0x01020304 && regs[1] == 0x05060708, - "wrap around to r0"); - - /* check wrap around to r0 over RB doesn't break RB */ - - asm volatile ("mtxer %[len];" - "mr r29,r1;" - "li r31,-1;" - "mr r1,r31;" - "mr r0, %[addr];" - "lswx r31, 0, r0;" - "std r31, 0*8(%[regs]);" - "std r0, 1*8(%[regs]);" - "std r1, 2*8(%[regs]);" - "mr r1,r29;" - :: - [len] "r" (12), - [addr] "r" (addr), - [regs] "r" (regs) - : - /* loading three registers from r31 wraps around to r1, - * r1 is saved to r29, as adding it to the clobber - * list doesn't protect it - */ - "xer", "r31", "r0", "r29", "memory"); - - /* doc says it is invalid, real proc stops when it comes to - * overwrite the register. - * In all the cases, the register must stay untouched - */ - report(regs[1] == (uint64_t)addr, "Don't overwrite Rb"); - - report_prefix_pop(); -} - -int main(int argc, char **argv) -{ - int i; - - handle_exception(0x700, program_check_handler, (void *)&is_invalid); - handle_exception(0x600, alignment_handler, (void *)&alignment); - - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "-v") == 0) { - verbose = 1; - } - } - - report_prefix_push("emulator"); - - test_64bit(); - test_illegal(); - test_lswx(); - test_lswi(); - - report_prefix_pop(); - - return report_summary(); -} diff --git a/powerpc/flat.lds b/powerpc/flat.lds deleted file mode 100644 index 5eed368d..00000000 --- a/powerpc/flat.lds +++ /dev/null @@ -1,57 +0,0 @@ - -PHDRS -{ - text PT_LOAD FLAGS(5); - data PT_LOAD FLAGS(6); -} - -SECTIONS -{ - .text : { - *(.init) - *(.text) - *(.text.*) - } :text - . = ALIGN(64K); - etext = .; - .opd : { *(.opd) } - . = ALIGN(16); - .dynamic : { - dynamic_start = .; - *(.dynamic) - } - .dynsym : { - dynsym_start = .; - *(.dynsym) - } - .rela.dyn : { *(.rela*) } - . = ALIGN(16); - .data : { - *(.data) - *(.data.rel*) - } :data - . = ALIGN(16); - .rodata : { - *(.rodata) - *(.rodata.*) - } :data - . = ALIGN(16); - .bss : { *(.bss) } - . = ALIGN(256); - /* - * tocptr is tocbase + 32K, allowing toc offsets to be +-32K - */ - tocptr = . + 32K; - .got : { *(.toc) *(.got) } - . = ALIGN(64K); - edata = .; - . += 64K; - . = ALIGN(64K); - /* - * stackptr set with initial stack frame (64 bytes) preallocated - */ - stackptr = . - 64; - stacktop = .; -} - -ENTRY(start) diff --git a/powerpc/reloc64.c b/powerpc/reloc64.c deleted file mode 100644 index f6aaabef..00000000 --- a/powerpc/reloc64.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * relocate R_PPC_RELATIVE RELA entries. Normally this is done in - * assembly code to avoid the risk of using absolute addresses before - * they're relocated. We use C, but cautiously (no global references). - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#define DT_NULL 0 -#define DT_RELA 7 -#define DT_RELACOUNT 0x6ffffff9 -#define R_PPC_RELATIVE 22 - -struct elf64_dyn { - signed long long tag; - unsigned long long val; -}; - -#define RELA_GET_TYPE(rela_ptr) ((rela_ptr)->info & 0xffffffff) -struct elf64_rela { - unsigned long long offset; - unsigned long long info; - signed long long addend; -}; - -void relocate(unsigned long load_addr, struct elf64_dyn *dyn_table); - -void relocate(unsigned long load_addr, struct elf64_dyn *dyn_table) -{ - unsigned long long rela_addr = 0, rela_count = 0, *addr; - struct elf64_dyn *d = dyn_table; - struct elf64_rela *r; - - while (d && d->tag != DT_NULL) { - if (d->tag == DT_RELA) - rela_addr = d->val; - else if (d->tag == DT_RELACOUNT) - rela_count = d->val; - if (rela_addr && rela_count) - break; - ++d; - } - - if (!rela_addr || !rela_count) - return; - - r = (void *)(rela_addr + load_addr); - - while (rela_count--) { - if (RELA_GET_TYPE(r) == R_PPC_RELATIVE) { - addr = (void *)(r->offset + load_addr); - *addr = r->addend + load_addr; - } - ++r; - } -} diff --git a/powerpc/rtas.c b/powerpc/rtas.c deleted file mode 100644 index 9f5ec4bb..00000000 --- a/powerpc/rtas.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Test the RTAS interface - */ - -#include -#include -#include - -#define DAYS(y,m,d) (365UL * (y) + ((y) / 4) - ((y) / 100) + ((y) / 400) + \ - 367UL * (m) / 12 + \ - (d)) - -static unsigned long mktime(int year, int month, int day, - int hour, int minute, int second) -{ - unsigned long epoch; - - /* Put February at end of the year to avoid leap day this year */ - - month -= 2; - if (month <= 0) { - month += 12; - year -= 1; - } - - /* compute epoch: substract DAYS(since_March(1-1-1970)) */ - - epoch = DAYS(year, month, day) - DAYS(1969, 11, 1); - - epoch = epoch * 24 + hour; - epoch = epoch * 60 + minute; - epoch = epoch * 60 + second; - - return epoch; -} - -#define DELAY 1 -#define MAX_LOOP 10000000 - -static void check_get_time_of_day(unsigned long start) -{ - uint32_t token; - int ret; - int now[8]; - unsigned long t1, t2, count; - - ret = rtas_token("get-time-of-day", &token); - report(ret == 0, "token available"); - if (ret) - return; - - ret = rtas_call(token, 0, 8, now); - report(ret == 0, "execution"); - - report(now[5] >= 0 && now[5] <= 59, "second"); - report(now[4] >= 0 && now[4] <= 59, "minute"); - report(now[3] >= 0 && now[3] <= 23, "hour"); - report(now[2] >= 1 && now[2] <= 31, "day"); - report(now[1] >= 1 && now[1] <= 12, "month"); - report(now[0] >= 1970, "year"); - report(mktime(now[0], now[1], now[2], now[3], now[4], now[5]) - start < 3, - "accuracy (< 3s)"); - - ret = rtas_call(token, 0, 8, now); - t1 = mktime(now[0], now[1], now[2], now[3], now[4], now[5]); - count = 0; - do { - ret = rtas_call(token, 0, 8, now); - t2 = mktime(now[0], now[1], now[2], now[3], now[4], now[5]); - count++; - } while (t1 + DELAY > t2 && count < MAX_LOOP); - report(t1 + DELAY <= t2, "running"); -} - -static void check_set_time_of_day(void) -{ - uint32_t stod_token, gtod_token; - int ret; - int date[8]; - unsigned long t1, t2, count; - - ret = rtas_token("set-time-of-day", &stod_token); - report(ret == 0, "token available"); - if (ret) - return; - - /* 23:59:59 28/2/2000 */ - - ret = rtas_call(stod_token, 7, 1, NULL, 2000, 2, 28, 23, 59, 59); - report(ret == 0, "execution"); - - /* check it has worked */ - ret = rtas_token("get-time-of-day", >od_token); - assert(ret == 0); - ret = rtas_call(gtod_token, 0, 8, date); - report(ret == 0, "re-read"); - t1 = mktime(2000, 2, 28, 23, 59, 59); - t2 = mktime(date[0], date[1], date[2], - date[3], date[4], date[5]); - report(t2 - t1 < 2, "result"); - - /* check it is running */ - count = 0; - do { - ret = rtas_call(gtod_token, 0, 8, date); - t2 = mktime(date[0], date[1], date[2], - date[3], date[4], date[5]); - count++; - } while (t1 + DELAY > t2 && count < MAX_LOOP); - report(t1 + DELAY <= t2, "running"); -} - -int main(int argc, char **argv) -{ - int len; - long val; - - report_prefix_push("rtas"); - - if (argc < 2) - report_abort("no test specified"); - - report_prefix_push(argv[1]); - - if (strcmp(argv[1], "get-time-of-day") == 0) { - - len = parse_keyval(argv[2], &val); - if (len == -1) { - printf("Missing parameter \"date\"\n"); - abort(); - } - argv[2][len] = '\0'; - - check_get_time_of_day(val); - - } else if (strcmp(argv[1], "set-time-of-day") == 0) { - - check_set_time_of_day(); - - } else { - printf("Unknown subtest\n"); - abort(); - } - - report_prefix_pop(); - - report_prefix_pop(); - - return report_summary(); -} diff --git a/powerpc/run b/powerpc/run deleted file mode 100755 index 597ab96e..00000000 --- a/powerpc/run +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash - -if [ -z "$STANDALONE" ]; then - if [ ! -f config.mak ]; then - echo "run ./configure && make first. See ./configure -h" - exit 2 - fi - source config.mak - source scripts/arch-run.bash -fi - -ACCEL=$(get_qemu_accelerator) || - exit $? - -qemu=$(search_qemu_binary) || - exit $? - -if ! $qemu -machine '?' 2>&1 | grep 'pseries' > /dev/null; then - echo "$qemu doesn't support pSeries ('-machine pseries'). Exiting." - exit 2 -fi - -M='-machine pseries' -M+=",accel=$ACCEL" -command="$qemu -nodefaults $M -bios $FIRMWARE" -command+=" -display none -serial stdio -kernel" -command="$(migration_cmd) $(timeout_cmd) $command" - -# powerpc tests currently exit with rtas-poweroff, which exits with 0. -# run_qemu treats that as a failure exit and returns 1, so we need -# to fixup the fixup below by parsing the true exit code from the output. -# The second fixup is also a FIXME, because once we add chr-testdev -# support for powerpc, we won't need the second fixup. -run_qemu_status $command "$@" diff --git a/powerpc/selftest.c b/powerpc/selftest.c deleted file mode 100644 index 7acff710..00000000 --- a/powerpc/selftest.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Test the framework itself. These tests confirm that setup works. - * - * Copyright (C) 2016, Red Hat Inc, Andrew Jones - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include - -static void check_setup(int argc, char **argv) -{ - int nr_tests = 0, len, i; - long val; - - for (i = 0; i < argc; ++i) { - - len = parse_keyval(argv[i], &val); - if (len == -1) - continue; - - argv[i][len] = '\0'; - report_prefix_push(argv[i]); - - if (strcmp(argv[i], "mem") == 0) { - - phys_addr_t memsize = PHYSICAL_END - PHYSICAL_START; - phys_addr_t expected = ((phys_addr_t)val)*1024*1024; - - report(memsize == expected, "size = %" PRIu64 " MB", - memsize/1024/1024); - ++nr_tests; - - } else if (strcmp(argv[i], "smp") == 0) { - - report(nr_cpus == (int)val, "nr_cpus = %d", nr_cpus); - ++nr_tests; - } - - report_prefix_pop(); - } - - if (nr_tests < 2) - report_abort("missing input"); -} - -int main(int argc, char **argv) -{ - report_prefix_push("selftest"); - - if (argc < 2) - report_abort("no test specified"); - - report_prefix_push(argv[1]); - - if (strcmp(argv[1], "setup") == 0) { - - check_setup(argc-2, &argv[2]); - - } - - return report_summary(); -} diff --git a/powerpc/spapr.h b/powerpc/spapr.h deleted file mode 100644 index b41aece0..00000000 --- a/powerpc/spapr.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASMPOWERPC_SPAPR_H_ -#define _ASMPOWERPC_SPAPR_H_ - -#define SPAPR_KERNEL_LOAD_ADDR 0x400000 - -#endif /* _ASMPOWERPC_SPAPR_H_ */ diff --git a/powerpc/spapr_hcall.c b/powerpc/spapr_hcall.c deleted file mode 100644 index 823a574a..00000000 --- a/powerpc/spapr_hcall.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Test sPAPR hypervisor calls (aka. h-calls) - * - * Copyright 2016 Thomas Huth, Red Hat Inc. - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include - -#define PAGE_SIZE 4096 - -#define H_ZERO_PAGE (1UL << (63-48)) -#define H_COPY_PAGE (1UL << (63-49)) - -#define mfspr(nr) ({ \ - uint64_t ret; \ - asm volatile("mfspr %0,%1" : "=r"(ret) : "i"(nr)); \ - ret; \ -}) - -#define SPR_SPRG0 0x110 - -/** - * Test the H_SET_SPRG0 h-call by setting some values and checking whether - * the SPRG0 register contains the correct values afterwards - */ -static void test_h_set_sprg0(int argc, char **argv) -{ - uint64_t sprg0, sprg0_orig; - int rc; - - if (argc > 1) - report_abort("Unsupported argument: '%s'", argv[1]); - - sprg0_orig = mfspr(SPR_SPRG0); - - rc = hcall(H_SET_SPRG0, 0xcafebabedeadbeefULL); - sprg0 = mfspr(SPR_SPRG0); - report(rc == H_SUCCESS && sprg0 == 0xcafebabedeadbeefULL, - "sprg0 = 0xcafebabedeadbeef"); - - rc = hcall(H_SET_SPRG0, 0xaaaaaaaa55555555ULL); - sprg0 = mfspr(SPR_SPRG0); - report(rc == H_SUCCESS && sprg0 == 0xaaaaaaaa55555555ULL, - "sprg0 = 0xaaaaaaaa55555555"); - - rc = hcall(H_SET_SPRG0, sprg0_orig); - sprg0 = mfspr(SPR_SPRG0); - report(rc == H_SUCCESS && sprg0 == sprg0_orig, "sprg0 = %#" PRIx64, - sprg0_orig); -} - -/** - * Test the H_PAGE_INIT h-call by using it to clear and to copy a page, and - * by checking for the correct values in the destination page afterwards - */ -static void test_h_page_init(int argc, char **argv) -{ - u8 *dst, *src; - int rc; - - if (argc > 1) - report_abort("Unsupported argument: '%s'", argv[1]); - - dst = memalign(PAGE_SIZE, PAGE_SIZE); - src = memalign(PAGE_SIZE, PAGE_SIZE); - if (!dst || !src) - report_abort("Failed to alloc memory"); - - memset(dst, 0xaa, PAGE_SIZE); - rc = hcall(H_PAGE_INIT, H_ZERO_PAGE, dst, src); - report(rc == H_SUCCESS && *(uint64_t *)dst == 0, "h_zero_page"); - - *(uint64_t*)src = 0xbeefc0dedeadcafeULL; - rc = hcall(H_PAGE_INIT, H_COPY_PAGE, dst, src); - report(rc == H_SUCCESS && *(uint64_t *)dst == 0xbeefc0dedeadcafeULL, - "h_copy_page"); - - *(uint64_t*)src = 0x9abcdef012345678ULL; - rc = hcall(H_PAGE_INIT, H_COPY_PAGE|H_ZERO_PAGE, dst, src); - report(rc == H_SUCCESS && *(uint64_t *)dst == 0x9abcdef012345678ULL, - "h_copy_page+h_zero_page"); - - rc = hcall(H_PAGE_INIT, H_ZERO_PAGE, dst + 0x123, src); - report(rc == H_PARAMETER, "h_zero_page unaligned dst"); - - rc = hcall(H_PAGE_INIT, H_COPY_PAGE, dst, src + 0x123); - report(rc == H_PARAMETER, "h_copy_page unaligned src"); -} - -static int h_random(uint64_t *val) -{ - register uint64_t r3 asm("r3") = H_RANDOM; - register uint64_t r4 asm("r4"); - - asm volatile (" sc 1 " : "+r"(r3), "=r"(r4) : - : "r0", "r5", "r6", "r7", "r8", "r9", "r10", - "r11", "r12", "xer", "ctr", "cc"); - *val = r4; - - return r3; -} - -/** - * Test H_RANDOM by calling it a couple of times to check whether all bit - * positions really toggle (there should be no "stuck" bits in the output) - */ -static void test_h_random(int argc, char **argv) -{ - uint64_t rval, val0, val1; - int rc, i; - - if (argc > 1) - report_abort("Unsupported argument: '%s'", argv[1]); - - /* H_RANDOM is optional - so check for sane return values first */ - rc = h_random(&rval); - if (rc == H_FUNCTION) { - report_skip("h-call is not available"); - return; - } - report(rc == H_SUCCESS, "h-call can be used successfully"); - - val0 = 0ULL; - val1 = ~0ULL; - - i = 100; - do { - rc = h_random(&rval); - if (rc != H_SUCCESS) - break; - val0 |= rval; - val1 &= rval; - } while (i-- > 0 && (val0 != ~0ULL || val1 != 0ULL)); - - report(rc == H_SUCCESS && val0 == ~0ULL && val1 == 0, "no stuck bits"); -} - -struct { - const char *name; - void (*func)(int argc, char **argv); -} hctests[] = { - { "h_set_sprg0", test_h_set_sprg0 }, - { "h_page_init", test_h_page_init }, - { "h_random", test_h_random }, - { NULL, NULL } -}; - -int main(int argc, char **argv) -{ - int all = 0; - int i; - - report_prefix_push("hypercall"); - - if (argc < 2 || (argc == 2 && !strcmp(argv[1], "all"))) - all = 1; - - for (i = 0; hctests[i].name != NULL; i++) { - report_prefix_push(hctests[i].name); - if (all || strcmp(argv[1], hctests[i].name) == 0) { - hctests[i].func(argc-1, &argv[1]); - } - report_prefix_pop(); - } - - return report_summary(); -} diff --git a/powerpc/sprs.c b/powerpc/sprs.c deleted file mode 100644 index d3c8780e..00000000 --- a/powerpc/sprs.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Test Special Purpose Registers - * - * Copyright 2017 Thomas Huth, Red Hat Inc. - * - * This work is licensed under the terms of the GNU LGPL, version 2. - * - * The basic idea of this test is to check whether the contents of the Special - * Purpose Registers (SPRs) are preserved correctly during migration. So we - * fill in the SPRs with a well-known value, read the values back (since not - * all bits might be retained in the SPRs), then wait for migration to complete - * (if the '-w' option has been specified) so that the user has a chance to - * migrate the VM. Alternatively, the test can also simply sleep a little bit - * with the H_CEDE hypercall, in the hope that we'll get scheduled to another - * host CPU and thus register contents might have changed, too (in case of - * bugs). Finally, we read back the values from the SPRs and compare them with - * the values before the migration. Mismatches are reported as test failures. - * Note that we do not test all SPRs since some of the registers change their - * content automatically, and some are only accessible with hypervisor privi- - * leges or have bad side effects, so we have to omit those registers. - */ -#include -#include -#include -#include -#include -#include -#include - -#define mfspr(nr) ({ \ - uint64_t ret; \ - asm volatile("mfspr %0,%1" : "=r"(ret) : "i"(nr)); \ - ret; \ -}) - -#define mtspr(nr, val) \ - asm volatile("mtspr %0,%1" : : "i"(nr), "r"(val)) - -uint64_t before[1024], after[1024]; - -/* Common SPRs for all PowerPC CPUs */ -static void set_sprs_common(uint64_t val) -{ - mtspr(9, val); /* CTR */ - // mtspr(273, val); /* SPRG1 */ /* Used by our exception handler */ - mtspr(274, val); /* SPRG2 */ - mtspr(275, val); /* SPRG3 */ -} - -/* SPRs from PowerPC Operating Environment Architecture, Book III, Vers. 2.01 */ -static void set_sprs_book3s_201(uint64_t val) -{ - mtspr(18, val); /* DSISR */ - mtspr(19, val); /* DAR */ - mtspr(152, val); /* CTRL */ - mtspr(256, val); /* VRSAVE */ - mtspr(786, val); /* MMCRA */ - mtspr(795, val); /* MMCR0 */ - mtspr(798, val); /* MMCR1 */ -} - -/* SPRs from PowerISA 2.07 Book III-S */ -static void set_sprs_book3s_207(uint64_t val) -{ - mtspr(3, val); /* DSCR */ - mtspr(13, val); /* AMR */ - mtspr(17, val); /* DSCR */ - mtspr(18, val); /* DSISR */ - mtspr(19, val); /* DAR */ - mtspr(29, val); /* AMR */ - mtspr(61, val); /* IAMR */ - // mtspr(152, val); /* CTRL */ /* TODO: Needs a fix in KVM */ - mtspr(153, val); /* FSCR */ - mtspr(157, val); /* UAMOR */ - mtspr(159, val); /* PSPB */ - mtspr(256, val); /* VRSAVE */ - // mtspr(272, val); /* SPRG0 */ /* Used by our exception handler */ - mtspr(769, val); /* MMCR2 */ - mtspr(770, val); /* MMCRA */ - mtspr(771, val); /* PMC1 */ - mtspr(772, val); /* PMC2 */ - mtspr(773, val); /* PMC3 */ - mtspr(774, val); /* PMC4 */ - mtspr(775, val); /* PMC5 */ - mtspr(776, val); /* PMC6 */ - mtspr(779, (val & 0xfffffffffbab3fffULL) | 0xfa0b2070); /* MMCR0 */ - mtspr(784, val); /* SIER */ - mtspr(785, val); /* MMCR2 */ - mtspr(786, val); /* MMCRA */ - mtspr(787, val); /* PMC1 */ - mtspr(788, val); /* PMC2 */ - mtspr(789, val); /* PMC3 */ - mtspr(790, val); /* PMC4 */ - mtspr(791, val); /* PMC5 */ - mtspr(792, val); /* PMC6 */ - mtspr(795, (val & 0xfffffffffbab3fffULL) | 0xfa0b2070); /* MMCR0 */ - mtspr(796, val); /* SIAR */ - mtspr(797, val); /* SDAR */ - mtspr(798, val); /* MMCR1 */ - mtspr(800, val); /* BESCRS */ - mtspr(801, val); /* BESCCRSU */ - mtspr(802, val); /* BESCRR */ - mtspr(803, val); /* BESCRRU */ - mtspr(804, val); /* EBBHR */ - mtspr(805, val); /* EBBRR */ - mtspr(806, val); /* BESCR */ - mtspr(815, val); /* TAR */ -} - -/* SPRs from PowerISA 3.00 Book III */ -static void set_sprs_book3s_300(uint64_t val) -{ - set_sprs_book3s_207(val); - mtspr(48, val); /* PIDR */ - mtspr(144, val); /* TIDR */ - mtspr(823, val); /* PSSCR */ -} - -static void set_sprs(uint64_t val) -{ - uint32_t pvr = mfspr(287); /* Processor Version Register */ - - set_sprs_common(val); - - switch (pvr >> 16) { - case 0x39: /* PPC970 */ - case 0x3C: /* PPC970FX */ - case 0x44: /* PPC970MP */ - set_sprs_book3s_201(val); - break; - case 0x4b: /* POWER8E */ - case 0x4c: /* POWER8NVL */ - case 0x4d: /* POWER8 */ - set_sprs_book3s_207(val); - break; - case 0x4e: /* POWER9 */ - set_sprs_book3s_300(val); - break; - default: - puts("Warning: Unknown processor version!\n"); - } -} - -static void get_sprs_common(uint64_t *v) -{ - v[9] = mfspr(9); /* CTR */ - // v[273] = mfspr(273); /* SPRG1 */ /* Used by our exception handler */ - v[274] = mfspr(274); /* SPRG2 */ - v[275] = mfspr(275); /* SPRG3 */ -} - -static void get_sprs_book3s_201(uint64_t *v) -{ - v[18] = mfspr(18); /* DSISR */ - v[19] = mfspr(19); /* DAR */ - v[136] = mfspr(136); /* CTRL */ - v[256] = mfspr(256); /* VRSAVE */ - v[786] = mfspr(786); /* MMCRA */ - v[795] = mfspr(795); /* MMCR0 */ - v[798] = mfspr(798); /* MMCR1 */ -} - -static void get_sprs_book3s_207(uint64_t *v) -{ - v[3] = mfspr(3); /* DSCR */ - v[13] = mfspr(13); /* AMR */ - v[17] = mfspr(17); /* DSCR */ - v[18] = mfspr(18); /* DSISR */ - v[19] = mfspr(19); /* DAR */ - v[29] = mfspr(29); /* AMR */ - v[61] = mfspr(61); /* IAMR */ - // v[136] = mfspr(136); /* CTRL */ /* TODO: Needs a fix in KVM */ - v[153] = mfspr(153); /* FSCR */ - v[157] = mfspr(157); /* UAMOR */ - v[159] = mfspr(159); /* PSPB */ - v[256] = mfspr(256); /* VRSAVE */ - v[259] = mfspr(259); /* SPRG3 (read only) */ - // v[272] = mfspr(272); /* SPRG0 */ /* Used by our exception handler */ - v[769] = mfspr(769); /* MMCR2 */ - v[770] = mfspr(770); /* MMCRA */ - v[771] = mfspr(771); /* PMC1 */ - v[772] = mfspr(772); /* PMC2 */ - v[773] = mfspr(773); /* PMC3 */ - v[774] = mfspr(774); /* PMC4 */ - v[775] = mfspr(775); /* PMC5 */ - v[776] = mfspr(776); /* PMC6 */ - v[779] = mfspr(779); /* MMCR0 */ - v[780] = mfspr(780); /* SIAR (read only) */ - v[781] = mfspr(781); /* SDAR (read only) */ - v[782] = mfspr(782); /* MMCR1 (read only) */ - v[784] = mfspr(784); /* SIER */ - v[785] = mfspr(785); /* MMCR2 */ - v[786] = mfspr(786); /* MMCRA */ - v[787] = mfspr(787); /* PMC1 */ - v[788] = mfspr(788); /* PMC2 */ - v[789] = mfspr(789); /* PMC3 */ - v[790] = mfspr(790); /* PMC4 */ - v[791] = mfspr(791); /* PMC5 */ - v[792] = mfspr(792); /* PMC6 */ - v[795] = mfspr(795); /* MMCR0 */ - v[796] = mfspr(796); /* SIAR */ - v[797] = mfspr(797); /* SDAR */ - v[798] = mfspr(798); /* MMCR1 */ - v[800] = mfspr(800); /* BESCRS */ - v[801] = mfspr(801); /* BESCCRSU */ - v[802] = mfspr(802); /* BESCRR */ - v[803] = mfspr(803); /* BESCRRU */ - v[804] = mfspr(804); /* EBBHR */ - v[805] = mfspr(805); /* EBBRR */ - v[806] = mfspr(806); /* BESCR */ - v[815] = mfspr(815); /* TAR */ -} - -static void get_sprs_book3s_300(uint64_t *v) -{ - get_sprs_book3s_207(v); - v[48] = mfspr(48); /* PIDR */ - v[144] = mfspr(144); /* TIDR */ - v[823] = mfspr(823); /* PSSCR */ -} - -static void get_sprs(uint64_t *v) -{ - uint32_t pvr = mfspr(287); /* Processor Version Register */ - - get_sprs_common(v); - - switch (pvr >> 16) { - case 0x39: /* PPC970 */ - case 0x3C: /* PPC970FX */ - case 0x44: /* PPC970MP */ - get_sprs_book3s_201(v); - break; - case 0x4b: /* POWER8E */ - case 0x4c: /* POWER8NVL */ - case 0x4d: /* POWER8 */ - get_sprs_book3s_207(v); - break; - case 0x4e: /* POWER9 */ - get_sprs_book3s_300(v); - break; - } -} - -int main(int argc, char **argv) -{ - int i; - bool pause = false; - uint64_t pat = 0xcafefacec0debabeULL; - const uint64_t patterns[] = { - 0xcafefacec0debabeULL, ~0xcafefacec0debabeULL, - 0xAAAA5555AAAA5555ULL, 0x5555AAAA5555AAAAULL, - 0x1234567890ABCDEFULL, 0xFEDCBA0987654321ULL, - -1ULL, - }; - static uint64_t decr = 0x7FFFFFFF; /* Max value */ - - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-w")) { - pause = true; - } else if (!strcmp(argv[i], "-p")) { - i += 1; - if (i >= argc || *argv[i] < '0' - || *argv[i] >= '0' + ARRAY_SIZE(patterns)) - report_abort("Error: bad value for -p"); - pat ^= patterns[*argv[i] - '0']; - } else if (!strcmp(argv[i], "-t")) { - /* Randomize with timebase register */ - asm volatile("mftb %0" : "=r"(i)); - pat ^= i; - asm volatile("mftb %0" : "=r"(i)); - pat ^= ~(uint64_t)i << 32; - } else { - report_abort("Warning: Unsupported argument: %s", - argv[i]); - } - } - - printf("Settings SPRs to %#lx...\n", pat); - set_sprs(pat); - - memset(before, 0, sizeof(before)); - memset(after, 0, sizeof(after)); - - get_sprs(before); - - if (pause) { - puts("Now migrate the VM, then press a key to continue...\n"); - (void) getchar(); - } else { - puts("Sleeping...\n"); - handle_exception(0x900, &dec_except_handler, &decr); - asm volatile ("mtdec %0" : : "r" (0x3FFFFFFF)); - hcall(H_CEDE); - } - - get_sprs(after); - - puts("Checking SPRs...\n"); - for (i = 0; i < 1024; i++) { - if (before[i] != 0 || after[i] != 0) - report(before[i] == after[i], - "SPR %d:\t%#018lx <==> %#018lx", i, before[i], - after[i]); - } - - return report_summary(); -} diff --git a/powerpc/tm.c b/powerpc/tm.c deleted file mode 100644 index 65cacdf5..00000000 --- a/powerpc/tm.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Transactional Memory Unit Tests - * - * Copyright 2016 Suraj Jitindar Singh, IBM. - * - * This work is licensed under the terms of the GNU LGPL, version 2. - */ -#include -#include -#include -#include -#include -#include -#include - -/* Check "ibm,pa-features" property of a CPU node for the TM flag */ -static void cpu_has_tm(int fdtnode, u64 regval __unused, void *ptr) -{ - const struct fdt_property *prop; - int plen; - - prop = fdt_get_property(dt_fdt(), fdtnode, "ibm,pa-features", &plen); - if (!prop) /* No features means TM is also not available */ - return; - /* Sanity check for the property layout (first two bytes are header) */ - assert(plen >= 8 && prop->data[1] == 0 && prop->data[0] <= plen - 2); - - /* - * The "Transactional Memory Category Support" flags are at byte - * offset 22 and 23 of the attribute type 0, so when adding the - * two bytes for the header, we've got to look at offset 24 for - * the TM support bit. - */ - if (prop->data[0] >= 24 && (prop->data[24] & 0x80) != 0) - *(int *)ptr += 1; -} - -/* Check amount of CPUs nodes that have the TM flag */ -static int count_cpus_with_tm(void) -{ - int ret; - int available = 0; - - ret = dt_for_each_cpu_node(cpu_has_tm, &available); - if (ret < 0) - return ret; - - return available; -} - -static int h_cede(void) -{ - register uint64_t r3 asm("r3") = H_CEDE; - - asm volatile ("sc 1" : "+r"(r3) : - : "r0", "r4", "r5", "r6", "r7", "r8", "r9", - "r10", "r11", "r12", "xer", "ctr", "cc"); - - return r3; -} - -/* - * Enable transactional memory - * Returns: FALSE - Failure - * TRUE - Success - */ -static bool enable_tm(void) -{ - uint64_t msr = 0; - - asm volatile ("mfmsr %[msr]" : [msr] "=r" (msr)); - - msr |= (((uint64_t) 1) << 32); - - asm volatile ("mtmsrd %[msr]\n\t" - "mfmsr %[msr]" : [msr] "+r" (msr)); - - return !!(msr & (((uint64_t) 1) << 32)); -} - -/* - * Test H_CEDE call while transactional memory transaction is suspended - * - * WARNING: This tests for a known vulnerability in which the host may go down. - * Probably best not to run this if your host going down is going to cause - * problems. - * - * If the test passes then your kernel probably has the necessary patch. - * If the test fails then the H_CEDE call was unsuccessful and the - * vulnerability wasn't tested. - * If the test hits the vulnerability then it will never complete or report and - * the qemu process will block indefinitely. RCU stalls will be detected on the - * cpu and any process scheduled on the lost cpu will also block indefinitely. - */ -static void test_h_cede_tm(int argc, char **argv) -{ - int i; - static uint64_t decr = 0x3FFFFF; /* ~10ms */ - - if (argc > 2) - report_abort("Unsupported argument: '%s'", argv[2]); - - handle_exception(0x900, &dec_except_handler, &decr); - asm volatile ("mtdec %0" : : "r" (decr)); - - if (!start_all_cpus(halt, 0)) - report_abort("Failed to start secondary cpus"); - - if (!enable_tm()) - report_abort("Failed to enable tm"); - - /* - * Begin a transaction and guarantee we are in the suspend state - * before continuing - */ - asm volatile ("1: .long 0x7c00051d\n\t" /* tbegin. */ - "beq 2f\n\t" - ".long 0x7c0005dd\n\t" /* tsuspend. */ - "2: .long 0x7c00059c\n\t" /* tcheck cr0 */ - "bf 2,1b" : : : "cr0"); - - for (i = 0; i < 500; i++) { - uint64_t rval = h_cede(); - - if (rval != H_SUCCESS) - break; - mdelay(5); - } - - report(i == 500, "H_CEDE TM"); -} - -struct { - const char *name; - void (*func)(int argc, char **argv); -} hctests[] = { - { "h_cede_tm", test_h_cede_tm }, - { NULL, NULL } -}; - -int main(int argc, char **argv) -{ - bool all; - int i, cpus_with_tm; - - report_prefix_push("tm"); - - cpus_with_tm = count_cpus_with_tm(); - if (cpus_with_tm == 0) { - report_skip("TM is not available"); - goto done; - } - report(cpus_with_tm == nr_cpus, - "TM available in all 'ibm,pa-features' properties"); - - all = argc == 1 || !strcmp(argv[1], "all"); - - for (i = 0; hctests[i].name != NULL; i++) { - if (all || strcmp(argv[1], hctests[i].name) == 0) { - report_prefix_push(hctests[i].name); - hctests[i].func(argc, argv); - report_prefix_pop(); - } - } - -done: - report_prefix_pop(); - return report_summary(); -} diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg deleted file mode 100644 index 1e749480..00000000 --- a/powerpc/unittests.cfg +++ /dev/null @@ -1,72 +0,0 @@ -############################################################################## -# unittest configuration -# -# [unittest_name] -# file = .flat # Name of the flat file to be used. -# smp = # Number of processors the VM will use -# # during this test. Use $MAX_SMP to use -# # the maximum the host supports. Defaults -# # to one. -# extra_params = -append # Additional parameters used. -# arch = ppc64 # Select one if the test case is -# # specific to only one. -# groups = ... # Used to identify test cases -# # with run_tests -g ... -# # Specify group_name=nodefault -# # to have test not run by -# # default -# accel = kvm|tcg # Optionally specify if test must run with -# # kvm or tcg. If not specified, then kvm will -# # be used when available. -# timeout = # Optionally specify a timeout. -# check = = # check a file for a particular value before running -# # a test. The check line can contain multiple files -# # to check separated by a space but each check -# # parameter needs to be of the form = -############################################################################## - -# -# Test that the configured number of processors (smp = ), and -# that the configured amount of memory (-m ) are correctly setup -# by the framework. -# -[selftest-setup] -file = selftest.elf -smp = 2 -extra_params = -m 256 -append 'setup smp=2 mem=256' -groups = selftest - -[spapr_hcall] -file = spapr_hcall.elf - -[rtas-get-time-of-day] -file = rtas.elf -timeout = 5 -extra_params = -append "get-time-of-day date=$(date +%s)" -groups = rtas - -[rtas-get-time-of-day-base] -file = rtas.elf -timeout = 5 -extra_params = -rtc base="2006-06-17" -append "get-time-of-day date=$(date --date="2006-06-17 UTC" +%s)" -groups = rtas - -[rtas-set-time-of-day] -file = rtas.elf -extra_params = -append "set-time-of-day" -timeout = 5 -groups = rtas - -[emulator] -file = emulator.elf - -[h_cede_tm] -file = tm.elf -smp = 2,threads=2 -extra_params = -machine cap-htm=on -append "h_cede_tm" -groups = h_cede_tm - -[sprs] -file = sprs.elf -extra_params = -append '-w' -groups = migration diff --git a/run_tests.sh b/run_tests.sh deleted file mode 100755 index 01e36dcf..00000000 --- a/run_tests.sh +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/env bash - -verbose="no" -tap_output="no" -run_all_tests="no" # don't run nodefault tests - -if [ ! -f config.mak ]; then - echo "run ./configure && make first. See ./configure -h" - exit 1 -fi -source config.mak -source scripts/common.bash - -function usage() -{ -cat <> $RUNTIME_log_file; } - postprocess_suite_output() { cat; } -else - process_test_output() { - CR=$'\r' - while read -r line; do - line="${line%$CR}" - case "${line:0:4}" in - PASS) - echo "ok TEST_NUMBER - ${line#??????}" >&3 - ;; - FAIL) - echo "not ok TEST_NUMBER - ${line#??????}" >&3 - ;; - SKIP) - echo "ok TEST_NUMBER - ${line#??????} # skip" >&3 - ;; - *) - ;; - esac - echo "${line}" - done >> $RUNTIME_log_file - } - postprocess_suite_output() { - test_number=0 - while read -r line; do - case "${line}" in - ok*|"not ok"*) - (( test_number++ )) - echo "${line/TEST_NUMBER/${test_number}}" ;; - *) echo "${line}" ;; - esac - done - echo "1..$test_number" - } -fi - -RUNTIME_log_stderr () { process_test_output; } -RUNTIME_log_stdout () { - if [ "$PRETTY_PRINT_STACKS" = "yes" ]; then - ./scripts/pretty_print_stacks.py $1 | process_test_output - else - process_test_output - fi -} - -function run_task() -{ - local testname="$1" - if [ -z "$testname" ]; then - return - fi - - while (( $(jobs | wc -l) == $unittest_run_queues )); do - # wait for any background test to finish - wait -n 2>/dev/null - done - - RUNTIME_log_file="${unittest_log_dir}/${testname}.log" - if [ $unittest_run_queues = 1 ]; then - run "$@" - else - run "$@" & - fi -} - -: ${unittest_log_dir:=logs} -: ${unittest_run_queues:=1} -config=$TEST_DIR/unittests.cfg - -rm -rf $unittest_log_dir.old -[ -d $unittest_log_dir ] && mv $unittest_log_dir $unittest_log_dir.old -mkdir $unittest_log_dir || exit 2 - -echo "BUILD_HEAD=$(cat build-head)" > $unittest_log_dir/SUMMARY - -if [[ $tap_output == "yes" ]]; then - echo "TAP version 13" -fi - -trap "wait; exit 130" SIGINT - -( - # preserve stdout so that process_test_output output can write TAP to it - exec 3>&1 - test "$tap_output" == "yes" && exec > /dev/null - for_each_unittest $config run_task -) | postprocess_suite_output - -# wait until all tasks finish -wait diff --git a/s390x/Makefile b/s390x/Makefile deleted file mode 100644 index ddb4b48e..00000000 --- a/s390x/Makefile +++ /dev/null @@ -1,75 +0,0 @@ -tests = $(TEST_DIR)/selftest.elf -tests += $(TEST_DIR)/intercept.elf -tests += $(TEST_DIR)/emulator.elf -tests += $(TEST_DIR)/sieve.elf -tests += $(TEST_DIR)/sthyi.elf -tests += $(TEST_DIR)/skey.elf -tests += $(TEST_DIR)/diag10.elf -tests += $(TEST_DIR)/diag308.elf -tests += $(TEST_DIR)/pfmf.elf -tests += $(TEST_DIR)/cmm.elf -tests += $(TEST_DIR)/vector.elf -tests += $(TEST_DIR)/gs.elf -tests += $(TEST_DIR)/iep.elf -tests += $(TEST_DIR)/cpumodel.elf -tests += $(TEST_DIR)/diag288.elf -tests += $(TEST_DIR)/stsi.elf -tests += $(TEST_DIR)/skrf.elf -tests += $(TEST_DIR)/smp.elf -tests += $(TEST_DIR)/sclp.elf -tests_binary = $(patsubst %.elf,%.bin,$(tests)) - -all: directories test_cases test_cases_binary - -test_cases: $(tests) -test_cases_binary: $(tests_binary) - -CFLAGS += -std=gnu99 -CFLAGS += -ffreestanding -CFLAGS += -I $(SRCDIR)/lib -I $(SRCDIR)/lib/s390x -I lib -CFLAGS += -O2 -CFLAGS += -march=zEC12 -CFLAGS += -fno-delete-null-pointer-checks -LDFLAGS += -nostdlib -Wl,--build-id=none - -# We want to keep intermediate files -.PRECIOUS: %.o - -asm-offsets = lib/$(ARCH)/asm-offsets.h -include $(SRCDIR)/scripts/asm-offsets.mak - -cflatobjs += lib/util.o -cflatobjs += lib/alloc.o -cflatobjs += lib/alloc_phys.o -cflatobjs += lib/alloc_page.o -cflatobjs += lib/vmalloc.o -cflatobjs += lib/alloc_phys.o -cflatobjs += lib/s390x/io.o -cflatobjs += lib/s390x/stack.o -cflatobjs += lib/s390x/sclp.o -cflatobjs += lib/s390x/sclp-console.o -cflatobjs += lib/s390x/interrupt.o -cflatobjs += lib/s390x/mmu.o -cflatobjs += lib/s390x/smp.o - -OBJDIRS += lib/s390x - -cstart.o = $(TEST_DIR)/cstart64.o - -FLATLIBS = $(libcflat) -%.elf: %.o $(FLATLIBS) $(SRCDIR)/s390x/flat.lds $(cstart.o) - $(CC) $(CFLAGS) -c -o $(@:.elf=.aux.o) \ - $(SRCDIR)/lib/auxinfo.c -DPROGNAME=\"$@\" - $(CC) $(LDFLAGS) -o $@ -T $(SRCDIR)/s390x/flat.lds \ - $(filter %.o, $^) $(FLATLIBS) $(@:.elf=.aux.o) - $(RM) $(@:.elf=.aux.o) - @chmod a-x $@ - -%.bin: %.elf - $(OBJCOPY) -O binary $< $@ - -arch_clean: asm_offsets_clean - $(RM) $(TEST_DIR)/*.{o,elf,bin} $(TEST_DIR)/.*.d lib/s390x/.*.d - -generated-files = $(asm-offsets) -$(tests:.elf=.o) $(cstart.o) $(cflatobjs): $(generated-files) diff --git a/s390x/cmm.c b/s390x/cmm.c deleted file mode 100644 index fe4d9df0..00000000 --- a/s390x/cmm.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * CMM tests (ESSA) - * - * Copyright (c) 2018 IBM Corp - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -#include -#include -#include -#include - -static uint8_t pagebuf[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); - -static unsigned long essa(uint8_t state, unsigned long paddr) -{ - uint64_t extr_state; - - asm volatile(".insn rrf,0xb9ab0000,%[extr_state],%[addr],%[new_state],0" - : [extr_state] "=d" (extr_state) - : [addr] "a" (paddr), [new_state] "i" (state)); - return (unsigned long)extr_state; -} - -static void test_params(void) -{ - report_prefix_push("invalid ORC 8"); - expect_pgm_int(); - essa(8, (unsigned long)pagebuf); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static void test_priv(void) -{ - report_prefix_push("privileged"); - expect_pgm_int(); - enter_pstate(); - essa(0, (unsigned long)pagebuf); - check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); - report_prefix_pop(); -} - -/* Unfortunately the availability is not indicated by stfl bits, but - * we have to try to execute it and test for an operation exception. - */ -static bool test_availability(void) -{ - expect_pgm_int(); - essa(0, (unsigned long)pagebuf); - return clear_pgm_int() == 0; -} - -int main(void) -{ - bool has_essa = test_availability(); - - report_prefix_push("cmm"); - if (!has_essa) { - report_skip("ESSA is not available"); - goto done; - } - - test_priv(); - test_params(); -done: - report_prefix_pop(); - return report_summary(); -} diff --git a/s390x/cpumodel.c b/s390x/cpumodel.c deleted file mode 100644 index 5d232c64..00000000 --- a/s390x/cpumodel.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Test the known dependencies for facilities - * - * Copyright 2019 IBM Corp. - * - * Authors: - * Christian Borntraeger - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -#include - -static int dep[][2] = { - /* from SA22-7832-11 4-98 facility indications */ - { 4, 3 }, - { 5, 3 }, - { 5, 4 }, - { 19, 18 }, - { 37, 42 }, - { 43, 42 }, - { 73, 49 }, - { 134, 129 }, - { 135, 129 }, - { 139, 25 }, - { 139, 28 }, - { 146, 76 }, - /* indirectly documented in description */ - { 78, 8 }, /* EDAT */ - /* new dependencies from gen15 */ - { 61, 45 }, - { 148, 129 }, - { 148, 135 }, - { 152, 129 }, - { 152, 134 }, - { 155, 76 }, - { 155, 77 }, -}; - -int main(void) -{ - int i; - - report_prefix_push("cpumodel"); - - report_prefix_push("dependency"); - for (i = 0; i < ARRAY_SIZE(dep); i++) { - if (test_facility(dep[i][0])) { - report(test_facility(dep[i][1]), "%d implies %d", - dep[i][0], dep[i][1]); - } else { - report_skip("facility %d not present", dep[i][0]); - } - } - report_prefix_pop(); - - report_prefix_pop(); - return report_summary(); -} diff --git a/s390x/cstart64.S b/s390x/cstart64.S deleted file mode 100644 index e084f130..00000000 --- a/s390x/cstart64.S +++ /dev/null @@ -1,216 +0,0 @@ -/* - * s390x startup code - * - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * Thomas Huth - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include - -.section .init - -/* - * Short init between 0x10000 and 0x10480 and then jump to 0x11000. - * 0x10480 - 0x11000 are written to by bootloader. - * - * For KVM and TCG kernel boot we are in 64 bit z/Arch mode. - * When booting from disk the initial short psw is in 31 bit mode. - * When running under LPAR or z/VM, we might start in 31 bit and esam mode. - */ - .globl start -start: - /* Switch to z/Architecture mode and 64-bit */ - slr %r0, %r0 # Set cpuid to zero - lhi %r1, 2 # mode 2 = esame - sigp %r1, %r0, SIGP_SET_ARCHITECTURE - /* XOR all registers with themselves to clear them fully. */ - .irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 - xgr \i,\i - .endr - sam64 # Set addressing mode to 64 bit - /* setup stack */ - larl %r15, stackptr - /* setup initial PSW mask + control registers*/ - larl %r1, initial_psw - lpswe 0(%r1) -clear_bss_start: - larl %r2, __bss_start - larl %r3, __bss_end - slgr %r3, %r2 # Get sizeof bss - aghi %r3,-1 - srlg %r4,%r3,8 # Calc number of 256 byte chunks - ltgr %r4,%r4 - lgr %r1,%r2 - jz clear_bss_remainder # If none, clear remaining bytes -clear_bss_loop: - xc 0(256,%r1), 0(%r1) # Clear 256 byte chunks via xor - la %r1, 256(%r1) - brctg %r4, clear_bss_loop -clear_bss_remainder: - larl %r2, memsetxc - ex %r3, 0(%r2) - /* setup pgm interrupt handler */ - larl %r1, pgm_int_psw - mvc GEN_LC_PGM_NEW_PSW(16), 0(%r1) - /* setup ext interrupt handler */ - larl %r1, ext_int_psw - mvc GEN_LC_EXT_NEW_PSW(16), 0(%r1) - /* setup mcck interrupt handler */ - larl %r1, mcck_int_psw - mvc GEN_LC_MCCK_NEW_PSW(16), 0(%r1) - /* setup io interrupt handler */ - larl %r1, io_int_psw - mvc GEN_LC_IO_NEW_PSW(16), 0(%r1) - /* setup svc interrupt handler */ - larl %r1, svc_int_psw - mvc GEN_LC_SVC_NEW_PSW(16), 0(%r1) - /* setup cr0, enabling e.g. AFP-register control */ - larl %r1, initial_cr0 - lctlg %c0, %c0, 0(%r1) - /* call setup() */ - brasl %r14, setup - /* forward test parameter */ - larl %r2, __argc - llgf %r2, 0(%r2) - larl %r3, __argv - /* call to main() */ - brasl %r14, main - /* forward exit code */ - lgr %r3, %r2 - /* call exit() */ - j exit - -memsetxc: - xc 0(1,%r1),0(%r1) - - .macro SAVE_REGS - /* save grs 0-15 */ - stmg %r0, %r15, GEN_LC_SW_INT_GRS - /* save crs 0-15 */ - stctg %c0, %c15, GEN_LC_SW_INT_CRS - /* load a cr0 that has the AFP control bit which enables all FPRs */ - larl %r1, initial_cr0 - lctlg %c0, %c0, 0(%r1) - /* save fprs 0-15 + fpc */ - la %r1, GEN_LC_SW_INT_FPRS - .irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 - std \i, \i * 8(%r1) - .endr - stfpc GEN_LC_SW_INT_FPC - .endm - - .macro RESTORE_REGS - /* restore fprs 0-15 + fpc */ - la %r1, GEN_LC_SW_INT_FPRS - .irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 - ld \i, \i * 8(%r1) - .endr - lfpc GEN_LC_SW_INT_FPC - /* restore crs 0-15 */ - lctlg %c0, %c15, GEN_LC_SW_INT_CRS - /* restore grs 0-15 */ - lmg %r0, %r15, GEN_LC_SW_INT_GRS - .endm - -.section .text -/* - * load_reset calling convention: - * %r2 subcode (0 or 1) - */ -.globl diag308_load_reset -diag308_load_reset: - SAVE_REGS - /* Backup current PSW mask, as we have to restore it on success */ - epsw %r0, %r1 - st %r0, GEN_LC_SW_INT_PSW - st %r1, GEN_LC_SW_INT_PSW + 4 - /* Load reset psw mask (short psw, 64 bit) */ - lg %r0, reset_psw - /* Load the success label address */ - larl %r1, 0f - /* Or it to the mask */ - ogr %r0, %r1 - /* Store it at the reset PSW location (real 0x0) */ - stg %r0, 0 - /* Do the reset */ - diag %r0,%r2,0x308 - /* Failure path */ - xgr %r2, %r2 - br %r14 - /* Success path */ - /* load a cr0 that has the AFP control bit which enables all FPRs */ -0: larl %r1, initial_cr0 - lctlg %c0, %c0, 0(%r1) - RESTORE_REGS - lhi %r2, 1 - larl %r0, 1f - stg %r0, GEN_LC_SW_INT_PSW + 8 - lpswe GEN_LC_SW_INT_PSW -1: br %r14 - -.globl smp_cpu_setup_state -smp_cpu_setup_state: - xgr %r1, %r1 - lmg %r0, %r15, GEN_LC_SW_INT_GRS - lctlg %c0, %c0, GEN_LC_SW_INT_CRS - /* We should only go once through cpu setup and not for every restart */ - stg %r14, GEN_LC_RESTART_NEW_PSW + 8 - larl %r14, 0f - lpswe GEN_LC_SW_INT_PSW - /* If the function returns, just loop here */ -0: j 0 - -pgm_int: - SAVE_REGS - brasl %r14, handle_pgm_int - RESTORE_REGS - lpswe GEN_LC_PGM_OLD_PSW - -ext_int: - SAVE_REGS - brasl %r14, handle_ext_int - RESTORE_REGS - lpswe GEN_LC_EXT_OLD_PSW - -mcck_int: - SAVE_REGS - brasl %r14, handle_mcck_int - RESTORE_REGS - lpswe GEN_LC_MCCK_OLD_PSW - -io_int: - SAVE_REGS - brasl %r14, handle_io_int - RESTORE_REGS - lpswe GEN_LC_IO_OLD_PSW - -svc_int: - SAVE_REGS - brasl %r14, handle_svc_int - RESTORE_REGS - lpswe GEN_LC_SVC_OLD_PSW - - .align 8 -reset_psw: - .quad 0x0008000180000000 -initial_psw: - .quad 0x0000000180000000, clear_bss_start -pgm_int_psw: - .quad 0x0000000180000000, pgm_int -ext_int_psw: - .quad 0x0000000180000000, ext_int -mcck_int_psw: - .quad 0x0000000180000000, mcck_int -io_int_psw: - .quad 0x0000000180000000, io_int -svc_int_psw: - .quad 0x0000000180000000, svc_int -initial_cr0: - /* enable AFP-register control, so FP regs (+BFP instr) can be used */ - .quad 0x0000000000040000 diff --git a/s390x/diag10.c b/s390x/diag10.c deleted file mode 100644 index 7ee8945f..00000000 --- a/s390x/diag10.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Release pages hypercall tests (DIAG 10) - * - * Copyright (c) 2018 IBM Corp - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -#include -#include -#include -#include - -static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); -const unsigned long page0 = (unsigned long)pagebuf; -const unsigned long page1 = (unsigned long)(pagebuf + PAGE_SIZE); - -/* Tells the host to release pages from guest real addresses start to - * end. Parameters have to be page aligned, instruction is privileged. - */ -static inline void diag10(unsigned long start, unsigned long end) -{ - asm volatile ( - "diag %0,%1,0x10\n" - : : "a" (start), "a" (end)); -} - -/* Try freeing the prefix */ -static void test_prefix(void) -{ - report_prefix_push("lowcore freeing"); - - report_prefix_push("0x0000/0x0000"); - expect_pgm_int(); - diag10(0, 0); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - - report_prefix_push("0x1000/0x1000"); - expect_pgm_int(); - diag10(0x1000, 0x1000); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - report_prefix_push("0x0000/0x1000"); - expect_pgm_int(); - diag10(0, 0x1000); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - report_prefix_pop(); -} - -static void test_params(void) -{ - report_prefix_push("start/end"); - - /* end < start */ - report_prefix_push("end < start"); - expect_pgm_int(); - diag10(page1, page0); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - /* Unaligned start */ - report_prefix_push("unaligned start"); - expect_pgm_int(); - diag10((unsigned long) pagebuf + 42, page1); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - /* Unaligned end */ - report_prefix_push("unaligned end"); - expect_pgm_int(); - diag10(page0, (unsigned long) pagebuf + PAGE_SIZE + 42); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - report_prefix_pop(); -} - -static void test_priv(void) -{ - report_prefix_push("privileged"); - expect_pgm_int(); - enter_pstate(); - diag10(page0, page0); - check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); - report_prefix_pop(); -} - -int main(void) -{ - report_prefix_push("diag10"); - test_prefix(); - test_params(); - test_priv(); - return report_summary(); -} diff --git a/s390x/diag288.c b/s390x/diag288.c deleted file mode 100644 index e2ecdc86..00000000 --- a/s390x/diag288.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Timer Event DIAG288 test - * - * Copyright (c) 2019 IBM Corp - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -#include -#include -#include - -struct lowcore *lc = (struct lowcore *)0x0; - -#define CODE_INIT 0 -#define CODE_CHANGE 1 -#define CODE_CANCEL 2 - -#define ACTION_RESTART 0 - -static inline void diag288(unsigned long code, unsigned long time, - unsigned long action) -{ - register unsigned long fc asm("0") = code; - register unsigned long tm asm("1") = time; - register unsigned long ac asm("2") = action; - - asm volatile("diag %0,%2,0x288" - : : "d" (fc), "d" (tm), "d" (ac)); -} - -static void test_specs(void) -{ - report_prefix_push("specification"); - - report_prefix_push("uneven"); - expect_pgm_int(); - asm volatile("diag 1,2,0x288"); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - report_prefix_push("unsupported action"); - expect_pgm_int(); - diag288(CODE_INIT, 15, 42); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - report_prefix_push("unsupported function"); - expect_pgm_int(); - diag288(42, 15, ACTION_RESTART); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - report_prefix_push("no init"); - expect_pgm_int(); - diag288(CODE_CANCEL, 15, ACTION_RESTART); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - report_prefix_push("min timer"); - expect_pgm_int(); - diag288(CODE_INIT, 14, ACTION_RESTART); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - report_prefix_pop(); -} - -static void test_priv(void) -{ - report_prefix_push("privileged"); - expect_pgm_int(); - enter_pstate(); - diag288(CODE_INIT, 15, ACTION_RESTART); - check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); - report_prefix_pop(); -} - -static void test_bite(void) -{ - uint64_t mask, time; - - /* If watchdog doesn't bite, the cpu timer does */ - asm volatile("stck %0" : "=Q" (time) : : "cc"); - time += (uint64_t)(16000 * 1000) << 12; - asm volatile("sckc %0" : : "Q" (time)); - ctl_set_bit(0, 11); - mask = extract_psw_mask(); - mask |= PSW_MASK_EXT; - load_psw_mask(mask); - - /* Arm watchdog */ - lc->restart_new_psw.mask = extract_psw_mask() & ~PSW_MASK_EXT; - diag288(CODE_INIT, 15, ACTION_RESTART); - asm volatile(" larl %r0, 1f\n" - " stg %r0, 424\n" - "0: nop\n" - " j 0b\n" - "1:"); - report(true, "restart"); -} - -int main(void) -{ - report_prefix_push("diag288"); - test_priv(); - test_specs(); - test_bite(); - return report_summary(); -} diff --git a/s390x/diag308.c b/s390x/diag308.c deleted file mode 100644 index 7fc4abdb..00000000 --- a/s390x/diag308.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Diagnose 0x308 hypercall tests - * - * Copyright (c) 2019 Thomas Huth, Red Hat Inc. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2, or (at - * your option) any later version. - */ - -#include -#include -#include - -/* The diagnose calls should be blocked in problem state */ -static void test_priv(void) -{ - expect_pgm_int(); - enter_pstate(); - asm volatile ("diag %0,%1,0x308" :: "d"(0), "d"(3)); - check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); -} - - -/* - * Check that diag308 with subcode 0 and 1 loads the PSW at address 0, i.e. - * that we can put a pointer into address 4 which then gets executed. - */ -extern int diag308_load_reset(u64); -static void test_subcode0(void) -{ - report(diag308_load_reset(0), "load modified clear done"); -} - -static void test_subcode1(void) -{ - report(diag308_load_reset(1), "load normal reset done"); -} - -/* Expect a specification exception when using an uneven register */ -static void test_uneven_reg(unsigned int subcode) -{ - register unsigned long sc asm("6") = subcode; - register unsigned long r3 asm("9") = 0x2000; - - report_prefix_push("uneven register"); - expect_pgm_int(); - asm volatile ("diag %0,%1,0x308" :: "d"(r3), "d"(sc)); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -/* Expect a specification exception when using an unaligned address */ -static void test_unaligned_address(unsigned int subcode) -{ - register unsigned long sc asm("6") = subcode; - register unsigned long addr asm("8") = 54321; - - report_prefix_push("unaligned address"); - expect_pgm_int(); - asm volatile ("diag %0,%1,0x308" :: "d"(addr), "d"(sc)); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static void test_subcode5(void) -{ - test_uneven_reg(5); - test_unaligned_address(5); -} - -static void test_subcode6(void) -{ - test_uneven_reg(6); - test_unaligned_address(6); -} - -/* Unsupported subcodes should generate a specification exception */ -static void test_unsupported_subcode(void) -{ - int subcodes[] = { 2, 0x101, 0xffff, 0x10001, -1 }; - int idx; - - for (idx = 0; idx < ARRAY_SIZE(subcodes); idx++) { - report_prefix_pushf("0x%04x", subcodes[idx]); - expect_pgm_int(); - asm volatile ("diag %0,%1,0x308" :: "d"(0), "d"(subcodes[idx])); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - } -} - -static struct { - const char *name; - void (*func)(void); -} tests[] = { - { "privileged", test_priv }, - { "subcode 0", test_subcode0 }, - { "subcode 1", test_subcode1 }, - { "subcode 5", test_subcode5 }, - { "subcode 6", test_subcode6 }, - { "unsupported", test_unsupported_subcode }, - { NULL, NULL } -}; - -int main(int argc, char**argv) -{ - int i; - - report_prefix_push("diag308"); - for (i = 0; tests[i].name; i++) { - report_prefix_push(tests[i].name); - tests[i].func(); - report_prefix_pop(); - } - report_prefix_pop(); - - return report_summary(); -} diff --git a/s390x/emulator.c b/s390x/emulator.c deleted file mode 100644 index 1ee0df58..00000000 --- a/s390x/emulator.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Emulator tests - for s390x CPU instructions that are usually interpreted - * by the hardware - * - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include -#include - -struct lowcore *lc = NULL; - -static inline void __test_spm_ipm(uint8_t cc, uint8_t key) -{ - uint64_t in = (cc << 28) | (key << 24); - uint64_t out = ~0ULL; - - report_prefix_pushf("cc=%d,key=%x", cc, key); - - asm volatile ("spm %1\n" - "ipm %0\n" - : "+r"(out) : "r"(in) : "cc"); - - report(!(out & 0xc0000000UL), "bit 32 and 33 set to zero"); - report((out & ~0xff000000ULL) == ~0xff000000ULL, - "bit 0-31, 40-63 unchanged"); - report(!((in ^ out) & 0x3f000000UL), "cc and key applied"); - - report_prefix_pop(); -} - -/* Test the SET PROGRAM PARAMETER and INSERT PROGRAM PARAMETER instruction */ -static void test_spm_ipm(void) -{ - __test_spm_ipm(0, 0xf); - __test_spm_ipm(1, 0x9); - __test_spm_ipm(2, 0x5); - __test_spm_ipm(3, 0x3); - __test_spm_ipm(0, 0); -} - -static inline void __test_cpacf(unsigned int opcode, unsigned long func, - unsigned int r1, unsigned int r2, - unsigned int r3) -{ - register unsigned long gr0 asm("0") = func; - cpacf_mask_t mask; - register unsigned long gr1 asm("1") = (unsigned long)&mask; - - asm volatile(".insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],0\n" - : : "d" (gr0), "d" (gr1), [opc] "i" (opcode), - [r1] "i" (r1), [r2] "i" (r2), [r3] "i" (r3)); -} - -static inline void __test_cpacf_r1_odd(unsigned int opcode) -{ - report_prefix_push("r1 odd"); - expect_pgm_int(); - __test_cpacf(opcode, 0, 1, 4, 6); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static inline void __test_cpacf_r1_null(unsigned int opcode) -{ - report_prefix_push("r1 null"); - expect_pgm_int(); - __test_cpacf(opcode, 0, 0, 4, 6); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static inline void __test_cpacf_r2_odd(unsigned int opcode) -{ - report_prefix_push("r2 odd"); - expect_pgm_int(); - __test_cpacf(opcode, 0, 2, 3, 6); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static inline void __test_cpacf_r2_null(unsigned int opcode) -{ - report_prefix_push("r2 null"); - expect_pgm_int(); - __test_cpacf(opcode, 0, 2, 0, 6); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static inline void __test_cpacf_r3_odd(unsigned int opcode) -{ - report_prefix_push("r3 odd"); - expect_pgm_int(); - __test_cpacf(opcode, 0, 2, 4, 5); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static inline void __test_cpacf_r3_null(unsigned int opcode) -{ - report_prefix_push("r3 null"); - expect_pgm_int(); - __test_cpacf(opcode, 0, 2, 4, 0); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static inline void __test_cpacf_mod_bit(unsigned int opcode) -{ - report_prefix_push("mod bit"); - expect_pgm_int(); - __test_cpacf(opcode, CPACF_DECRYPT, 2, 4, 6); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static inline void __test_cpacf_invalid_func(unsigned int opcode) -{ - report_prefix_push("invalid subfunction"); - expect_pgm_int(); - /* 127 is unassigned for now. We don't simply use any, as HW - * might simply mask valid codes in query but they might still work */ - if (cpacf_query_func(opcode, 127)) { - report_skip("127 not invalid"); - } else { - __test_cpacf(opcode, 127, 2, 4, 6); - } - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static inline void __test_cpacf_invalid_parm(unsigned int opcode) -{ - report_prefix_push("invalid parm address"); - expect_pgm_int(); - __cpacf_query(opcode, (void *) -1); - check_pgm_int_code(PGM_INT_CODE_ADDRESSING); - report_prefix_pop(); -} - -static inline void __test_cpacf_protected_parm(unsigned int opcode) -{ - report_prefix_push("protected parm address"); - expect_pgm_int(); - low_prot_enable(); - __cpacf_query(opcode, (void *) 8); - low_prot_disable(); - check_pgm_int_code(PGM_INT_CODE_PROTECTION); - report_prefix_pop(); -} - -static inline void __test_basic_cpacf_opcode(unsigned int opcode) -{ - bool mod_bit_allowed = false; - - if (!__cpacf_check_opcode(opcode)) { - report_skip("not available"); - return; - } - report(cpacf_query_func(opcode, 0), "query indicated in query"); - - switch (opcode) { - case CPACF_KMCTR: - __test_cpacf_r3_odd(opcode); - __test_cpacf_r3_null(opcode); - /* FALL THROUGH */ - case CPACF_PRNO: - case CPACF_KMF: - case CPACF_KMC: - case CPACF_KMO: - case CPACF_KM: - __test_cpacf_r1_odd(opcode); - __test_cpacf_r1_null(opcode); - mod_bit_allowed = true; - /* FALL THROUGH */ - case CPACF_KMAC: - case CPACF_KIMD: - case CPACF_KLMD: - __test_cpacf_r2_odd(opcode); - __test_cpacf_r2_null(opcode); - break; - } - if (!mod_bit_allowed) - __test_cpacf_mod_bit(opcode); - __test_cpacf_invalid_func(opcode); - __test_cpacf_invalid_parm(opcode); - __test_cpacf_protected_parm(opcode); -} - -/* COMPUTE MESSAGE AUTHENTICATION CODE */ -static void test_kmac(void) -{ - __test_basic_cpacf_opcode(CPACF_KMAC); -} - -/* CIPHER MESSAGE */ -static void test_km(void) -{ - __test_basic_cpacf_opcode(CPACF_KM); -} -/* CIPHER MESSAGE WITH CHAINING */ -static void test_kmc(void) -{ - __test_basic_cpacf_opcode(CPACF_KMC); -} - -/* COMPUTE INTERMEDIATE MESSAGE DIGEST */ -static void test_kimd(void) -{ - __test_basic_cpacf_opcode(CPACF_KIMD); -} - -/* COMPUTE LAST MESSAGE DIGEST */ -static void test_klmd(void) -{ - __test_basic_cpacf_opcode(CPACF_KLMD); -} - -/* PERFORM CRYPTOGRAPHIC KEY MANAGEMENT OPERATION */ -static void test_pckmo(void) -{ - __test_basic_cpacf_opcode(CPACF_PCKMO); -} - -/* CIPHER MESSAGE WITH CIPHER FEEDBACK */ -static void test_kmf(void) -{ - __test_basic_cpacf_opcode(CPACF_KMF); -} - -/* PERFORM CRYPTOGRAPHIC KEY MANAGEMENT OPERATION */ -static void test_kmo(void) -{ - __test_basic_cpacf_opcode(CPACF_KMO); -} - -/* PERFORM CRYPTOGRAPHIC COMPUTATION */ -static void test_pcc(void) -{ - __test_basic_cpacf_opcode(CPACF_PCC); -} - -/* CIPHER MESSAGE WITH COUNTER */ -static void test_kmctr(void) -{ - __test_basic_cpacf_opcode(CPACF_KMCTR); -} - -/* PERFORM RANDOM NUMBER OPERATION (formerly PPNO) */ -static void test_prno(void) -{ - __test_basic_cpacf_opcode(CPACF_PRNO); -} - -static void test_dxc(void) -{ - /* DXC (0xff) is to be stored in LC and FPC on a trap (CRT) with AFP */ - lc->dxc_vxc = 0x12345678; - set_fpc_dxc(0); - - report_prefix_push("afp"); - expect_pgm_int(); - asm volatile(" .insn rrf,0xb9600000,%0,%0,8,0\n" - : : "r"(0) : "memory"); - check_pgm_int_code(PGM_INT_CODE_DATA); - - report(lc->dxc_vxc == 0xff, "dxc in LC"); - report(get_fpc_dxc() == 0xff, "dxc in FPC"); - report_prefix_pop(); - - /* DXC (0xff) is to be stored in LC only on a trap (CRT) without AFP */ - lc->dxc_vxc = 0x12345678; - set_fpc_dxc(0); - - report_prefix_push("no-afp"); - expect_pgm_int(); - /* temporarily disable AFP */ - afp_disable(); - asm volatile(" .insn rrf,0xb9600000,%0,%0,8,0\n" - : : "r"(0) : "memory"); - afp_enable(); - check_pgm_int_code(PGM_INT_CODE_DATA); - - report(lc->dxc_vxc == 0xff, "dxc in LC"); - report(get_fpc_dxc() == 0, "dxc not in FPC"); - report_prefix_pop(); -} - -static struct { - const char *name; - void (*func)(void); -} tests[] = { - { "spm/ipm", test_spm_ipm }, - { "kmac", test_kmac }, - { "km", test_km }, - { "kmc", test_kmc }, - { "kimd", test_kimd }, - { "klmd", test_klmd }, - { "pckmo", test_pckmo }, - { "kmf", test_kmf }, - { "kmo", test_kmo }, - { "pcc", test_pcc }, - { "kmctr", test_kmctr }, - { "prno", test_prno }, - { "dxc", test_dxc }, - { NULL, NULL } -}; - -int main(int argc, char**argv) -{ - int i; - - report_prefix_push("emulator"); - for (i = 0; tests[i].name; i++) { - report_prefix_push(tests[i].name); - tests[i].func(); - report_prefix_pop(); - } - report_prefix_pop(); - - return report_summary(); -} diff --git a/s390x/flat.lds b/s390x/flat.lds deleted file mode 100644 index 86dffacd..00000000 --- a/s390x/flat.lds +++ /dev/null @@ -1,59 +0,0 @@ -SECTIONS -{ - .lowcore : { - /* - * Initial short psw for disk boot, with 31 bit addressing for - * non z/Arch environment compatibility and the instruction - * address 0x10000 (cstart64.S .init). - */ - . = 0; - LONG(0x00080000) - LONG(0x80010000) - /* Restart new PSW for booting via PSW restart. */ - . = 0x1a0; - QUAD(0x0000000180000000) - QUAD(0x0000000000010000) - } - . = 0x10000; - .text : { - *(.init) - . = 0x480; - ipl_args = .; - . = 0x1000; - *(.text) - *(.text.*) - } - . = ALIGN(64K); - etext = .; - .opd : { *(.opd) } - . = ALIGN(16); - .dynamic : { - dynamic_start = .; - *(.dynamic) - } - .dynsym : { - dynsym_start = .; - *(.dynsym) - } - .rela.dyn : { *(.rela*) } - . = ALIGN(16); - .data : { - *(.data) - *(.data.rel*) - } - . = ALIGN(16); - .rodata : { *(.rodata) *(.rodata.*) } - . = ALIGN(16); - __bss_start = .; - .bss : { *(.bss) } - __bss_end = .; - . = ALIGN(64K); - edata = .; - . += 64K; - . = ALIGN(64K); - /* - * stackptr set with initial stack frame preallocated - */ - stackptr = . - 160; - stacktop = .; -} diff --git a/s390x/gs.c b/s390x/gs.c deleted file mode 100644 index f685aa9f..00000000 --- a/s390x/gs.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Tests guarded storage support. - * - * Copyright 2018 IBM Corp. - * - * Authors: - * Martin Schwidefsky - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include -#include -#include - -struct gs_cb { - uint64_t reserved; - uint64_t gsd; - uint64_t gssm; - uint64_t gs_epl_a; -}; - -struct gs_epl { - uint8_t pad1; - union { - uint8_t gs_eam; - struct { - uint8_t : 6; - uint8_t e : 1; - uint8_t b : 1; - }; - }; - union { - uint8_t gs_eci; - struct { - uint8_t tx : 1; - uint8_t cx : 1; - uint8_t : 5; - uint8_t in : 1; - }; - }; - union { - uint8_t gs_eai; - struct { - uint8_t : 1; - uint8_t t : 1; - uint8_t as : 2; - uint8_t ar : 4; - }; - }; - uint32_t pad2; - uint64_t gs_eha; - uint64_t gs_eia; - uint64_t gs_eoa; - uint64_t gs_eir; - uint64_t gs_era; -}; - -static volatile int guarded = 0; -static struct gs_cb gs_cb; -static struct gs_epl gs_epl; -static unsigned long gs_area = 0x2000000; - -void gs_handler(struct gs_cb *this_cb); - -static inline void load_gs_cb(struct gs_cb *gs_cb) -{ - asm volatile(".insn rxy,0xe3000000004d,0,%0" : : "Q" (*gs_cb)); -} - -static inline void store_gs_cb(struct gs_cb *gs_cb) -{ - asm volatile(".insn rxy,0xe30000000049,0,%0" : : "Q" (*gs_cb)); -} - -static inline unsigned long load_guarded(unsigned long *p) -{ - unsigned long v; - - asm(".insn rxy,0xe3000000004c, %0,%1" - : "=d" (v) - : "m" (*p) - : "r14", "memory"); - return v; -} - -/* guarded-storage event handler and finally it calls gs_handler */ -extern void gs_handler_asm(void); - asm(".globl gs_handler_asm\n" - "gs_handler_asm:\n" - " lgr %r14,%r15\n" /* Save current stack address in r14 */ - " aghi %r15,-320\n" /* Allocate stack frame */ - " stmg %r0,%r13,192(%r15)\n" /* Store regs to save area */ - " stg %r14,312(%r15)\n" - " la %r2,160(%r15)\n" /* Store gscb address in this_cb */ - " .insn rxy,0xe30000000049,0,160(%r15)\n" /* stgsc */ - " lg %r14,24(%r2)\n" /* Get GSEPLA from GSCB*/ - " lg %r14,40(%r14)\n" /* Get GSERA from GSEPL*/ - " stg %r14,304(%r15)\n" /* Store GSERA in r14 of reg save area */ - " brasl %r14,gs_handler\n" /* Jump to gs_handler */ - " lmg %r0,%r15,192(%r15)\n" /* Restore regs */ - " aghi %r14, 6\n" /* Add lgg instr len to GSERA */ - " br %r14\n" /* Jump to next instruction after lgg */ - " .size gs_handler_asm,.-gs_handler_asm\n"); - -void gs_handler(struct gs_cb *this_cb) -{ - guarded = 1; - struct gs_epl *gs_epl = (struct gs_epl *) this_cb->gs_epl_a; - printf("gs_handler called for %016lx at %016lx\n", - gs_epl->gs_eir, gs_epl->gs_eia); -} - -/* Test if load guarded gets intercepted. */ -static void test_load(void) -{ - unsigned long v; - - guarded = 0; - v = load_guarded(&gs_area); - report(guarded, "load guarded %ld", v); - guarded = 0; -} - -/* Test gs instructions without enablement resulting in an exception */ -static void test_special(void) -{ - report_prefix_push("disabled gs"); - report_prefix_push("load gs"); - expect_pgm_int(); - load_gs_cb(&gs_cb); - check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); - report_prefix_pop(); - - report_prefix_push("store gs"); - expect_pgm_int(); - store_gs_cb(&gs_cb); - check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); - report_prefix_pop(); - - report_prefix_pop(); -} - -static void init(void) -{ - /* Enable control bit for gs */ - ctl_set_bit(2, 4); - - /* Setup gs registers to guard the gs_area */ - gs_cb.gsd = gs_area | 25; - - /* Check all 512kb slots for events */ - gs_cb.gssm = 0xffffffffffffffffULL; - gs_cb.gs_epl_a = (unsigned long) &gs_epl; - - /* Register handler */ - gs_epl.gs_eha = (unsigned long) gs_handler_asm; - load_gs_cb(&gs_cb); -} - -int main(void) -{ - bool has_gs = test_facility(133); - - report_prefix_push("gs"); - if (!has_gs) { - report_skip("Guarded storage is not available"); - goto done; - } - - test_special(); - init(); - test_load(); - -done: - report_prefix_pop(); - return report_summary(); -} diff --git a/s390x/iep.c b/s390x/iep.c deleted file mode 100644 index 55c01ee1..00000000 --- a/s390x/iep.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Instruction Execution Prevention (IEP) DAT test. - * - * Copyright (c) 2018 IBM Corp - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include -#include -#include -#include -#include - -static void test_iep(void) -{ - uint16_t *code; - uint8_t *iepbuf = NULL; - void (*fn)(void); - - /* Enable IEP */ - ctl_set_bit(0, 20); - - /* Get and protect a page with the IEP bit */ - iepbuf = alloc_page(); - protect_page(iepbuf, PAGE_ENTRY_IEP); - - /* Code branches into r14 which contains the return address. */ - code = (uint16_t *)iepbuf; - *code = 0x07fe; - fn = (void *)code; - - report_prefix_push("iep protection"); - expect_pgm_int(); - /* Jump into protected page */ - fn(); - check_pgm_int_code(PGM_INT_CODE_PROTECTION); - report_prefix_pop(); - unprotect_page(iepbuf, PAGE_ENTRY_IEP); - ctl_clear_bit(0, 20); - free_page(iepbuf); -} - -int main(void) -{ - bool has_iep = test_facility(130); - - report_prefix_push("iep"); - if (!has_iep) { - report_skip("DAT IEP is not available"); - goto done; - } - - /* Setup DAT 1:1 mapping and memory management */ - setup_vm(); - test_iep(); - -done: - report_prefix_pop(); - return report_summary(); -} diff --git a/s390x/intercept.c b/s390x/intercept.c deleted file mode 100644 index 5f46b826..00000000 --- a/s390x/intercept.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Interception tests - for s390x CPU instruction that cause a VM exit - * - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * Thomas Huth - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include -#include -#include - -static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); - -static unsigned long nr_iterations; -static unsigned long time_to_run; - -/* Test the STORE PREFIX instruction */ -static void test_stpx(void) -{ - uint32_t old_prefix = -1U, tst_prefix = -1U; - uint32_t new_prefix = (uint32_t)(intptr_t)pagebuf; - - /* Can we successfully change the prefix? */ - old_prefix = get_prefix(); - set_prefix(new_prefix); - tst_prefix = get_prefix(); - set_prefix(old_prefix); - report(old_prefix == 0 && tst_prefix == new_prefix, "store prefix"); - - expect_pgm_int(); - low_prot_enable(); - asm volatile(" stpx 0(%0) " : : "r"(8)); - low_prot_disable(); - check_pgm_int_code(PGM_INT_CODE_PROTECTION); - - expect_pgm_int(); - asm volatile(" stpx 0(%0) " : : "r"(1)); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - - expect_pgm_int(); - asm volatile(" stpx 0(%0) " : : "r"(-8L)); - check_pgm_int_code(PGM_INT_CODE_ADDRESSING); -} - -/* Test the SET PREFIX instruction */ -static void test_spx(void) -{ - uint32_t new_prefix = (uint32_t)(intptr_t)pagebuf; - uint32_t old_prefix; - - memset(pagebuf, 0, PAGE_SIZE * 2); - - /* - * Temporarily change the prefix page to our buffer, and store - * some facility bits there ... at least some of them should be - * set in our buffer afterwards. - */ - old_prefix = get_prefix(); - set_prefix(new_prefix); - stfl(); - set_prefix(old_prefix); - report(pagebuf[GEN_LC_STFL] != 0, "stfl to new prefix"); - - expect_pgm_int(); - asm volatile(" spx 0(%0) " : : "r"(1)); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - - expect_pgm_int(); - asm volatile(" spx 0(%0) " : : "r"(-8L)); - check_pgm_int_code(PGM_INT_CODE_ADDRESSING); -} - -/* Test the STORE CPU ADDRESS instruction */ -static void test_stap(void) -{ - uint16_t cpuid = 0xffff; - - asm volatile ("stap %0\n" : "+Q"(cpuid)); - report(cpuid != 0xffff, "get cpu address"); - - expect_pgm_int(); - low_prot_enable(); - asm volatile ("stap 0(%0)\n" : : "r"(8)); - low_prot_disable(); - check_pgm_int_code(PGM_INT_CODE_PROTECTION); - - expect_pgm_int(); - asm volatile ("stap 0(%0)\n" : : "r"(1)); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - - expect_pgm_int(); - asm volatile ("stap 0(%0)\n" : : "r"(-8L)); - check_pgm_int_code(PGM_INT_CODE_ADDRESSING); -} - -/* Test the STORE CPU ID instruction */ -static void test_stidp(void) -{ - struct cpuid id = {}; - - asm volatile ("stidp %0\n" : "+Q"(id)); - report(id.type, "type set"); - report(!id.version || id.version == 0xff, "version valid"); - report(!id.reserved, "reserved bits not set"); - - expect_pgm_int(); - low_prot_enable(); - asm volatile ("stidp 0(%0)\n" : : "r"(8)); - low_prot_disable(); - check_pgm_int_code(PGM_INT_CODE_PROTECTION); - - expect_pgm_int(); - asm volatile ("stidp 0(%0)\n" : : "r"(1)); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - - expect_pgm_int(); - asm volatile ("stidp 0(%0)\n" : : "r"(-8L)); - check_pgm_int_code(PGM_INT_CODE_ADDRESSING); -} - -/* Test the TEST BLOCK instruction */ -static void test_testblock(void) -{ - int cc; - - memset(pagebuf, 0xaa, PAGE_SIZE); - - asm volatile ( - " lghi %%r0,0\n" - " .insn rre,0xb22c0000,0,%1\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc) - : "a"(pagebuf + 0x123) - : "memory", "0", "cc"); - report(cc == 0 && pagebuf[0] == 0 && pagebuf[PAGE_SIZE - 1] == 0, - "page cleared"); - - expect_pgm_int(); - low_prot_enable(); - asm volatile (" .insn rre,0xb22c0000,0,%0\n" : : "r"(4096)); - low_prot_disable(); - check_pgm_int_code(PGM_INT_CODE_PROTECTION); - - expect_pgm_int(); - asm volatile (" .insn rre,0xb22c0000,0,%0\n" : : "r"(-4096L)); - check_pgm_int_code(PGM_INT_CODE_ADDRESSING); -} - -static uint64_t get_clock_ms(void) -{ - uint64_t clk; - - asm volatile(" stck %0 " : : "Q"(clk) : "memory"); - - /* Bit 51 is incrememented each microsecond */ - return (clk >> (63 - 51)) / 1000; -} - -struct { - const char *name; - void (*func)(void); - bool run_it; -} tests[] = { - { "stpx", test_stpx, false }, - { "spx", test_spx, false }, - { "stap", test_stap, false }, - { "stidp", test_stidp, false }, - { "testblock", test_testblock, false }, - { NULL, NULL, false } -}; - -static void parse_intercept_test_args(int argc, char **argv) -{ - int i, ti; - bool run_all = true; - - for (i = 1; i < argc; i++) { - if (!strcmp("-i", argv[i])) { - i++; - if (i >= argc) - report_abort("-i needs a parameter"); - nr_iterations = atol(argv[i]); - } else if (!strcmp("-t", argv[i])) { - i++; - if (i >= argc) - report_abort("-t needs a parameter"); - time_to_run = atol(argv[i]); - } else for (ti = 0; tests[ti].name != NULL; ti++) { - if (!strcmp(tests[ti].name, argv[i])) { - run_all = false; - tests[ti].run_it = true; - break; - } else if (tests[ti + 1].name == NULL) { - report_abort("Unsupported parameter '%s'", - argv[i]); - } - } - } - - if (run_all) { - for (ti = 0; tests[ti].name != NULL; ti++) - tests[ti].run_it = true; - } -} - -int main(int argc, char **argv) -{ - uint64_t startclk; - int ti; - - parse_intercept_test_args(argc, argv); - - if (nr_iterations == 0 && time_to_run == 0) - nr_iterations = 1; - - report_prefix_push("intercept"); - - startclk = get_clock_ms(); - for (;;) { - for (ti = 0; tests[ti].name != NULL; ti++) { - report_prefix_push(tests[ti].name); - if (tests[ti].run_it) - tests[ti].func(); - report_prefix_pop(); - } - if (nr_iterations) { - nr_iterations -= 1; - if (nr_iterations == 0) - break; - } - if (time_to_run) { - if (get_clock_ms() - startclk > time_to_run) - break; - } - } - - report_prefix_pop(); - - return report_summary(); -} diff --git a/s390x/pfmf.c b/s390x/pfmf.c deleted file mode 100644 index ac57fe4f..00000000 --- a/s390x/pfmf.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Perform Frame Management Function (pfmf) tests - * - * Copyright (c) 2018 IBM - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include -#include -#include -#include - -static uint8_t pagebuf[PAGE_SIZE * 256] __attribute__((aligned(PAGE_SIZE * 256))); - -static void test_priv(void) -{ - report_prefix_push("privileged"); - expect_pgm_int(); - enter_pstate(); - pfmf(0, pagebuf); - check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); - report_prefix_pop(); -} - -static void test_4k_key(void) -{ - union pfmf_r1 r1; - union skey skey; - - report_prefix_push("4K"); - if (test_facility(169)) { - report_skip("storage key removal facility is active"); - goto out; - } - r1.val = 0; - r1.reg.sk = 1; - r1.reg.fsc = PFMF_FSC_4K; - r1.reg.key = 0x30; - pfmf(r1.val, pagebuf); - skey.val = get_storage_key(pagebuf); - skey.val &= SKEY_ACC | SKEY_FP; - report(skey.val == 0x30, "set storage keys"); -out: - report_prefix_pop(); -} - -static void test_1m_key(void) -{ - int i; - bool rp = true; - union pfmf_r1 r1; - union skey skey; - - report_prefix_push("1M"); - if (test_facility(169)) { - report_skip("storage key removal facility is active"); - goto out; - } - r1.val = 0; - r1.reg.sk = 1; - r1.reg.fsc = PFMF_FSC_1M; - r1.reg.key = 0x30; - pfmf(r1.val, pagebuf); - for (i = 0; i < 256; i++) { - skey.val = get_storage_key(pagebuf + i * PAGE_SIZE); - skey.val &= SKEY_ACC | SKEY_FP; - if (skey.val != 0x30) { - rp = false; - break; - } - } - report(rp, "set storage keys"); -out: - report_prefix_pop(); -} - -static void test_4k_clear(void) -{ - union pfmf_r1 r1; - - r1.val = 0; - r1.reg.cf = 1; - r1.reg.fsc = PFMF_FSC_4K; - - report_prefix_push("4K"); - memset(pagebuf, 42, PAGE_SIZE); - pfmf(r1.val, pagebuf); - report(!memcmp(pagebuf, pagebuf + PAGE_SIZE, PAGE_SIZE), - "clear memory"); - report_prefix_pop(); -} - -static void test_1m_clear(void) -{ - int i; - union pfmf_r1 r1; - unsigned long sum = 0; - - r1.val = 0; - r1.reg.cf = 1; - r1.reg.fsc = PFMF_FSC_1M; - - report_prefix_push("1M"); - memset(pagebuf, 42, PAGE_SIZE * 256); - pfmf(r1.val, pagebuf); - for (i = 0; i < PAGE_SIZE * 256; i++) - sum |= pagebuf[i]; - report(!sum, "clear memory"); - report_prefix_pop(); -} - -int main(void) -{ - bool has_edat = test_facility(8); - - report_prefix_push("pfmf"); - if (!has_edat) { - report_skip("PFMF is not available"); - goto done; - } - - test_priv(); - /* Force the buffer pages in */ - memset(pagebuf, 0, PAGE_SIZE * 256); - - test_4k_key(); - test_4k_clear(); - test_1m_key(); - test_1m_clear(); - -done: - report_prefix_pop(); - return report_summary(); -} diff --git a/s390x/run b/s390x/run deleted file mode 100755 index 09805044..00000000 --- a/s390x/run +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -if [ -z "$STANDALONE" ]; then - if [ ! -f config.mak ]; then - echo "run ./configure && make first. See ./configure -h" - exit 2 - fi - source config.mak - source scripts/arch-run.bash -fi - -ACCEL=$(get_qemu_accelerator) || - exit $? - -qemu=$(search_qemu_binary) || - exit $? - -M='-machine s390-ccw-virtio' -M+=",accel=$ACCEL" -command="$qemu -nodefaults -nographic $M" -command+=" -chardev stdio,id=con0 -device sclpconsole,chardev=con0" -command+=" -kernel" -command="$(timeout_cmd) $command" - -# We return the exit code via stdout, not via the QEMU return code -run_qemu_status $command "$@" diff --git a/s390x/sclp.c b/s390x/sclp.c deleted file mode 100644 index 7d92bf32..00000000 --- a/s390x/sclp.c +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Service Call tests - * - * Copyright (c) 2020 IBM Corp - * - * Authors: - * Claudio Imbrenda - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2. - */ - -#include -#include -#include -#include -#include - -#define PGM_NONE 1 -#define PGM_BIT_SPEC (1ULL << PGM_INT_CODE_SPECIFICATION) -#define PGM_BIT_ADDR (1ULL << PGM_INT_CODE_ADDRESSING) -#define PGM_BIT_PRIV (1ULL << PGM_INT_CODE_PRIVILEGED_OPERATION) -#define MKPTR(x) ((void *)(uint64_t)(x)) - -#define LC_SIZE (2 * PAGE_SIZE) - -static uint8_t pagebuf[LC_SIZE] __attribute__((aligned(LC_SIZE))); /* scratch pages used for some tests */ -static uint8_t prefix_buf[LC_SIZE] __attribute__((aligned(LC_SIZE))); /* temporary lowcore for test_sccb_prefix */ -/* SCCB template to be used */ -static union { - uint8_t raw[PAGE_SIZE]; - SCCBHeader header; - WriteEventData data; -} sccb_template; -static uint32_t valid_code; /* valid command code for READ SCP INFO */ -static struct lowcore *lc; - -/** - * Perform one service call, handling exceptions and interrupts. - */ -static int sclp_service_call_test(unsigned int command, void *sccb) -{ - int cc; - - sclp_mark_busy(); - sclp_setup_int(); - cc = servc(command, __pa(sccb)); - if (lc->pgm_int_code) { - sclp_handle_ext(); - return 0; - } - if (!cc) - sclp_wait_busy(); - return cc; -} - -/** - * Perform one test at the given address, optionally using the SCCB template, - * checking for the expected program interrupts and return codes. - * - * The parameter buf_len indicates the number of bytes of the template that - * should be copied to the test address, and should be 0 when the test - * address is invalid, in which case nothing is copied. - * - * The template is used to simplify tests where the same buffer content is - * used many times in a row, at different addresses. - * - * Returns true in case of success or false in case of failure - */ -static bool test_one_sccb(uint32_t cmd, uint8_t *addr, uint16_t buf_len, uint64_t exp_pgm, uint16_t exp_rc) -{ - SCCBHeader *h = (SCCBHeader *)addr; - int res, pgm; - - /* Copy the template to the test address if needed */ - if (buf_len) - memcpy(addr, sccb_template.raw, buf_len); - if (exp_pgm != PGM_NONE) - expect_pgm_int(); - /* perform the actual call */ - res = sclp_service_call_test(cmd, h); - if (res) { - report_info("SCLP not ready (command %#x, address %p, cc %d)", cmd, addr, res); - return false; - } - pgm = clear_pgm_int(); - /* Check if the program exception was one of the expected ones */ - if (!((1ULL << pgm) & exp_pgm)) { - report_info("First failure at addr %p, buf_len %d, cmd %#x, pgm code %d", - addr, buf_len, cmd, pgm); - return false; - } - /* Check if the response code is the one expected */ - if (exp_rc && exp_rc != h->response_code) { - report_info("First failure at addr %p, buf_len %d, cmd %#x, resp code %#x", - addr, buf_len, cmd, h->response_code); - return false; - } - return true; -} - -/** - * Wrapper for test_one_sccb to be used when the template should not be - * copied and the memory address should not be touched. - */ -static bool test_one_ro(uint32_t cmd, uint8_t *addr, uint64_t exp_pgm, uint16_t exp_rc) -{ - return test_one_sccb(cmd, addr, 0, exp_pgm, exp_rc); -} - -/** - * Wrapper for test_one_sccb to set up a simple SCCB template. - * - * The parameter sccb_len indicates the value that will be saved in the SCCB - * length field of the SCCB, buf_len indicates the number of bytes of - * template that need to be copied to the actual test address. In many cases - * it's enough to clear/copy the first 8 bytes of the buffer, while the SCCB - * itself can be larger. - * - * Returns true in case of success or false in case of failure - */ -static bool test_one_simple(uint32_t cmd, uint8_t *addr, uint16_t sccb_len, - uint16_t buf_len, uint64_t exp_pgm, uint16_t exp_rc) -{ - memset(sccb_template.raw, 0, sizeof(sccb_template.raw)); - sccb_template.header.length = sccb_len; - return test_one_sccb(cmd, addr, buf_len, exp_pgm, exp_rc); -} - -/** - * Test SCCB lengths < 8. - */ -static void test_sccb_too_short(void) -{ - int len; - - for (len = 0; len < 8; len++) - if (!test_one_simple(valid_code, pagebuf, len, 8, PGM_BIT_SPEC, 0)) - break; - - report(len == 8, "SCCB too short"); -} - -/** - * Test SCCBs that are not 64-bit aligned. - */ -static void test_sccb_unaligned(void) -{ - int offset; - - for (offset = 1; offset < 8; offset++) - if (!test_one_simple(valid_code, offset + pagebuf, 8, 8, PGM_BIT_SPEC, 0)) - break; - report(offset == 8, "SCCB unaligned"); -} - -/** - * Test SCCBs whose address is in the lowcore or prefix area. - */ -static void test_sccb_prefix(void) -{ - uint8_t scratch[LC_SIZE]; - uint32_t prefix, new_prefix; - int offset; - - /* - * copy the current lowcore to the future new location, otherwise we - * will not have a valid lowcore after setting the new prefix. - */ - memcpy(prefix_buf, 0, LC_SIZE); - /* save the current prefix (it's probably going to be 0) */ - prefix = get_prefix(); - /* - * save the current content of absolute pages 0 and 1, so we can - * restore them after we trash them later on - */ - memcpy(scratch, (void *)(intptr_t)prefix, LC_SIZE); - /* set the new prefix to prefix_buf */ - new_prefix = (uint32_t)(intptr_t)prefix_buf; - set_prefix(new_prefix); - - /* - * testing with SCCB addresses in the lowcore; since we can't - * actually trash the lowcore (unsurprisingly, things break if we - * do), this will be a read-only test. - */ - for (offset = 0; offset < LC_SIZE; offset += 8) - if (!test_one_ro(valid_code, MKPTR(offset), PGM_BIT_SPEC, 0)) - break; - report(offset == LC_SIZE, "SCCB low pages"); - - /* - * the SCLP should not even touch the memory, but we will write the - * SCCBs all over the two pages starting at absolute address 0, thus - * trashing them; we will need to restore them later. - */ - for (offset = 0; offset < LC_SIZE; offset += 8) - if (!test_one_simple(valid_code, MKPTR(new_prefix + offset), 8, 8, PGM_BIT_SPEC, 0)) - break; - report(offset == LC_SIZE, "SCCB prefix pages"); - - /* restore the previous contents of absolute pages 0 and 1 */ - memcpy(prefix_buf, 0, LC_SIZE); - /* restore the prefix to the original value */ - set_prefix(prefix); -} - -/** - * Test SCCBs that are above 2GB. If outside of memory, an addressing - * exception is also allowed. - */ -static void test_sccb_high(void) -{ - SCCBHeader *h = (SCCBHeader *)pagebuf; - uintptr_t a[33 * 4 * 2 + 2]; /* for the list of addresses to test */ - - uint64_t maxram; - int i, pgm, len = 0; - - h->length = 8; - /* addresses with 1 bit set in the first 33 bits */ - for (i = 0; i < 33; i++) - a[len++] = 1UL << (i + 31); - /* addresses with 2 consecutive bits set in the first 33 bits */ - for (i = 0; i < 33; i++) - a[len++] = 3UL << (i + 31); - /* addresses with all bits set in bits 0..N */ - for (i = 0; i < 33; i++) - a[len++] = 0xffffffff80000000UL << i; - /* addresses with all bits set in bits N..33 */ - a[len++] = 0x80000000; - for (i = 1; i < 33; i++, len++) - a[len] = a[len - 1] | (1UL << (i + 31)); - /* all the addresses above, but adding the offset of a valid buffer */ - for (i = 0; i < len; i++) - a[len + i] = a[i] + (intptr_t)h; - len += i; - /* two more hand-crafted addresses */ - a[len++] = 0xdeadbeef00000000; - a[len++] = 0xdeaddeadbeef0000; - - maxram = get_ram_size(); - for (i = 0; i < len; i++) { - pgm = PGM_BIT_SPEC | (a[i] >= maxram ? PGM_BIT_ADDR : 0); - if (!test_one_ro(valid_code, (void *)a[i], pgm, 0)) - break; - } - report(i == len, "SCCB high addresses"); -} - -/** - * Test invalid commands, both invalid command detail codes and valid - * ones with invalid command class code. - */ -static void test_inval(void) -{ - const uint16_t res = SCLP_RC_INVALID_SCLP_COMMAND; - uint32_t cmd; - int i; - - report_prefix_push("Invalid command"); - for (i = 0; i < 65536; i++) { - cmd = 0xdead0000 | i; - if (!test_one_simple(cmd, pagebuf, PAGE_SIZE, PAGE_SIZE, PGM_NONE, res)) - break; - } - report(i == 65536, "Command detail code"); - - for (i = 0; i < 256; i++) { - cmd = (valid_code & ~0xff) | i; - if (cmd == valid_code) - continue; - if (!test_one_simple(cmd, pagebuf, PAGE_SIZE, PAGE_SIZE, PGM_NONE, res)) - break; - } - report(i == 256, "Command class code"); - report_prefix_pop(); -} - - -/** - * Test short SCCBs (but larger than 8). - */ -static void test_short(void) -{ - const uint16_t res = SCLP_RC_INSUFFICIENT_SCCB_LENGTH; - int len; - - for (len = 8; len < 144; len++) - if (!test_one_simple(valid_code, pagebuf, len, len, PGM_NONE, res)) - break; - report(len == 144, "Insufficient SCCB length (Read SCP info)"); - - for (len = 8; len < 40; len++) - if (!test_one_simple(SCLP_READ_CPU_INFO, pagebuf, len, len, PGM_NONE, res)) - break; - report(len == 40, "Insufficient SCCB length (Read CPU info)"); -} - -/** - * Test SCCB page boundary violations. - */ -static void test_boundary(void) -{ - const uint32_t cmd = SCLP_CMD_WRITE_EVENT_DATA; - const uint16_t res = SCLP_RC_SCCB_BOUNDARY_VIOLATION; - WriteEventData *sccb = &sccb_template.data; - int len, offset; - - memset(sccb_template.raw, 0, sizeof(sccb_template.raw)); - sccb->h.function_code = SCLP_FC_NORMAL_WRITE; - for (len = 32; len <= 4096; len++) { - offset = len & 7 ? len & ~7 : len - 8; - for (offset = 4096 - offset; offset < 4096; offset += 8) { - sccb->h.length = len; - if (!test_one_sccb(cmd, offset + pagebuf, len, PGM_NONE, res)) - goto out; - } - } -out: - report(len > 4096 && offset == 4096, "SCCB page boundary violation"); -} - -/** - * Test excessively long SCCBs. - */ -static void test_toolong(void) -{ - const uint32_t cmd = SCLP_CMD_WRITE_EVENT_DATA; - const uint16_t res = SCLP_RC_SCCB_BOUNDARY_VIOLATION; - WriteEventData *sccb = &sccb_template.data; - int len; - - memset(sccb_template.raw, 0, sizeof(sccb_template.raw)); - sccb->h.function_code = SCLP_FC_NORMAL_WRITE; - for (len = 4097; len < 8192; len++) { - sccb->h.length = len; - if (!test_one_sccb(cmd, pagebuf, PAGE_SIZE, PGM_NONE, res)) - break; - } - report(len == 8192, "SCCB bigger than 4k"); -} - -/** - * Test privileged operation. - */ -static void test_priv(void) -{ - SCCBHeader *h = (SCCBHeader *)pagebuf; - - report_prefix_push("Privileged operation"); - h->length = 8; - expect_pgm_int(); - enter_pstate(); - servc(valid_code, __pa(h)); - check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); - report_prefix_pop(); -} - -/** - * Test addressing exceptions. We need to test SCCB addresses between the - * end of available memory and 2GB, because after 2GB a specification - * exception is also allowed. - * Only applicable if the VM has less than 2GB of memory - */ -static void test_addressing(void) -{ - unsigned long i, maxram = get_ram_size(); - - /* the VM has more than 2GB of memory */ - if (maxram >= 0x80000000) { - report_skip("Invalid SCCB address"); - return; - } - /* test all possible valid addresses immediately after the end of memory - * up to 64KB after the end of memory - */ - for (i = 0; i < 0x10000 && i + maxram < 0x80000000; i += 8) - if (!test_one_ro(valid_code, MKPTR(i + maxram), PGM_BIT_ADDR, 0)) - goto out; - /* test more addresses until we reach 1MB after end of memory; - * increment by a prime number (times 8) in order to test all - * possible valid offsets inside pages - */ - for (; i < 0x100000 && i + maxram < 0x80000000 ; i += 808) - if (!test_one_ro(valid_code, MKPTR(i + maxram), PGM_BIT_ADDR, 0)) - goto out; - /* test the remaining addresses until we reach address 2GB; - * increment by a prime number (times 8) in order to test all - * possible valid offsets inside pages - */ - for (; i + maxram < 0x80000000; i += 800024) - if (!test_one_ro(valid_code, MKPTR(i + maxram), PGM_BIT_ADDR, 0)) - goto out; -out: - report(i + maxram >= 0x80000000, "Invalid SCCB address"); -} - -/** - * Test some bits in the instruction format that are specified to be ignored. - */ -static void test_instbits(void) -{ - SCCBHeader *h = (SCCBHeader *)pagebuf; - int cc; - - sclp_mark_busy(); - h->length = 8; - sclp_setup_int(); - - asm volatile( - " .insn rre,0xb2204200,%1,%2\n" /* servc %1,%2 */ - " ipm %0\n" - " srl %0,28" - : "=&d" (cc) : "d" (valid_code), "a" (__pa(pagebuf)) - : "cc", "memory"); - /* No exception, but also no command accepted, so no interrupt is - * expected. We need to clear the flag manually otherwise we will - * loop forever when we try to report failure. - */ - if (cc) - sclp_handle_ext(); - else - sclp_wait_busy(); - report(cc == 0, "Instruction format ignored bits"); -} - -/** - * Find a valid READ INFO command code; not all codes are always allowed, and - * probing should be performed in the right order. - */ -static void find_valid_sclp_code(void) -{ - const unsigned int commands[] = { SCLP_CMDW_READ_SCP_INFO_FORCED, - SCLP_CMDW_READ_SCP_INFO }; - SCCBHeader *h = (SCCBHeader *)pagebuf; - int i, cc; - - for (i = 0; i < ARRAY_SIZE(commands); i++) { - sclp_mark_busy(); - memset(h, 0, sizeof(*h)); - h->length = 4096; - - valid_code = commands[i]; - cc = sclp_service_call(commands[i], h); - if (cc) - break; - if (h->response_code == SCLP_RC_NORMAL_READ_COMPLETION) - return; - if (h->response_code != SCLP_RC_INVALID_SCLP_COMMAND) - break; - } - report_abort("READ_SCP_INFO failed"); -} - -int main(void) -{ - report_prefix_push("sclp"); - find_valid_sclp_code(); - - /* Test some basic things */ - test_instbits(); - test_priv(); - test_addressing(); - - /* Test the specification exceptions */ - test_sccb_too_short(); - test_sccb_unaligned(); - test_sccb_prefix(); - test_sccb_high(); - - /* Test the expected response codes */ - test_inval(); - test_short(); - test_boundary(); - test_toolong(); - - return report_summary(); -} diff --git a/s390x/selftest.c b/s390x/selftest.c deleted file mode 100644 index 4c166461..00000000 --- a/s390x/selftest.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2017 Red Hat Inc - * - * Authors: - * Thomas Huth - * David Hildenbrand - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include -#include -#include -#include - -static void test_fp(void) -{ - double a = 3.0; - double b = 2.0; - double c; - - asm volatile( - " ddb %1, %2\n" - " std %1, %0\n" - : "=m" (c) : "f" (a), "m" (b)); - - report(c == 1.5, "3.0/2.0 == 1.5"); -} - -static void test_pgm_int(void) -{ - expect_pgm_int(); - asm volatile(" .insn e,0x0000"); /* used for SW breakpoints in QEMU */ - check_pgm_int_code(PGM_INT_CODE_OPERATION); - - expect_pgm_int(); - asm volatile(" stg %0,0(%0)\n" : : "r"(-1L)); - check_pgm_int_code(PGM_INT_CODE_ADDRESSING); -} - -static void test_malloc(void) -{ - int *tmp = malloc(sizeof(int)); - int *tmp2 = malloc(sizeof(int)); - - *tmp = 123456789; - *tmp2 = 123456789; - mb(); - - report((uintptr_t)tmp & 0xf000000000000000ul, "malloc: got vaddr"); - report(*tmp == 123456789, "malloc: access works"); - report((uintptr_t)tmp2 & 0xf000000000000000ul, - "malloc: got 2nd vaddr"); - report((*tmp2 == 123456789), "malloc: access works"); - report(tmp != tmp2, "malloc: addresses differ"); - - expect_pgm_int(); - configure_dat(0); - *tmp = 987654321; - configure_dat(1); - check_pgm_int_code(PGM_INT_CODE_ADDRESSING); - - free(tmp); - free(tmp2); -} - -int main(int argc, char**argv) -{ - report_prefix_push("selftest"); - - report(true, "true"); - report(argc == 3, "argc == 3"); - report(!strcmp(argv[0], "s390x/selftest.elf"), "argv[0] == PROGNAME"); - report(!strcmp(argv[1], "test"), "argv[1] == test"); - report(!strcmp(argv[2], "123"), "argv[2] == 123"); - - setup_vm(); - - test_fp(); - test_pgm_int(); - test_malloc(); - - return report_summary(); -} diff --git a/s390x/sieve.c b/s390x/sieve.c deleted file mode 120000 index 8f14a5c3..00000000 --- a/s390x/sieve.c +++ /dev/null @@ -1 +0,0 @@ -../x86/sieve.c \ No newline at end of file diff --git a/s390x/skey.c b/s390x/skey.c deleted file mode 100644 index 86d15e2f..00000000 --- a/s390x/skey.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Storage key tests - * - * Copyright (c) 2018 IBM Corp - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include -#include -#include -#include - - -static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); - -static void test_set_mb(void) -{ - union skey skey, ret1, ret2; - void *addr = (void *)0x10000 - 2 * PAGE_SIZE; - void *end = (void *)0x10000; - - /* Multi block support came with EDAT 1 */ - if (!test_facility(8)) - return; - - skey.val = 0x30; - while (addr < end) - addr = set_storage_key_mb(addr, skey.val); - - ret1.val = get_storage_key(end - PAGE_SIZE) & (SKEY_ACC | SKEY_FP); - ret2.val = get_storage_key(end - PAGE_SIZE * 2) & (SKEY_ACC | SKEY_FP); - report(ret1.val == ret2.val && ret1.val == skey.val, "multi block"); -} - -static void test_chg(void) -{ - union skey skey1, skey2; - - skey1.val = 0x30; - set_storage_key(pagebuf, skey1.val, 0); - skey1.val = get_storage_key(pagebuf); - pagebuf[0] = 3; - skey2.val = get_storage_key(pagebuf); - report(!skey1.str.ch && skey2.str.ch, "chg bit test"); -} - -static void test_set(void) -{ - union skey skey, ret; - - skey.val = 0x30; - ret.val = get_storage_key(pagebuf); - set_storage_key(pagebuf, skey.val, 0); - ret.val = get_storage_key(pagebuf); - /* - * For all set tests we only test the ACC and FP bits. RF and - * CH are set by the machine for memory references and changes - * and hence might change between a set and a get. - */ - report(skey.str.acc == ret.str.acc && skey.str.fp == ret.str.fp, - "set key test"); -} - -/* Returns true if we are running under z/VM 6.x */ -static bool check_for_zvm6(void) -{ - int dcbt; /* Descriptor block count */ - int nr; - static const unsigned char zvm6[] = { - /* This is "z/VM 6" in EBCDIC */ - 0xa9, 0x61, 0xe5, 0xd4, 0x40, 0x40, 0x40, 0x40, 0xf6 - }; - - if (stsi(pagebuf, 3, 2, 2)) - return false; - - dcbt = pagebuf[31] & 0xf; - - for (nr = 0; nr < dcbt; nr++) { - if (!memcmp(&pagebuf[32 + nr * 64 + 24], zvm6, sizeof(zvm6))) - return true; - } - - return false; -} - -static void test_priv(void) -{ - union skey skey; - bool is_zvm6 = check_for_zvm6(); - - memset(pagebuf, 0, PAGE_SIZE * 2); - report_prefix_push("privileged"); - report_prefix_push("sske"); - expect_pgm_int(); - enter_pstate(); - set_storage_key(pagebuf, 0x30, 0); - check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); - report_prefix_pop(); - - skey.val = get_storage_key(pagebuf); - report(skey.str.acc != 3, "skey did not change on exception"); - - report_prefix_push("iske"); - if (is_zvm6) { - /* There is a known bug with z/VM 6, so skip the test there */ - report_skip("not working on z/VM 6"); - } else { - expect_pgm_int(); - enter_pstate(); - get_storage_key(pagebuf); - check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); - } - report_prefix_pop(); - - report_prefix_pop(); -} - -int main(void) -{ - report_prefix_push("skey"); - if (test_facility(169)) { - report_skip("storage key removal facility is active"); - goto done; - } - test_priv(); - test_set(); - test_set_mb(); - test_chg(); -done: - report_prefix_pop(); - return report_summary(); -} diff --git a/s390x/skrf.c b/s390x/skrf.c deleted file mode 100644 index 9cae589f..00000000 --- a/s390x/skrf.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Storage key removal facility tests - * - * Copyright (c) 2019 IBM Corp - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2. - */ -#include -#include -#include -#include -#include -#include - -static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); - -static void test_facilities(void) -{ - report_prefix_push("facilities"); - report(!test_facility(10), "!10"); - report(!test_facility(14), "!14"); - report(!test_facility(66), "!66"); - report(!test_facility(145), "!145"); - report(!test_facility(140), "!149"); - report_prefix_pop(); -} - -static void test_skey(void) -{ - report_prefix_push("sske"); - expect_pgm_int(); - set_storage_key(pagebuf, 0x30, 0); - check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); - expect_pgm_int(); - report_prefix_pop(); - report_prefix_push("iske"); - get_storage_key(pagebuf); - check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); - report_prefix_pop(); -} - -static void test_pfmf(void) -{ - union pfmf_r1 r1; - - report_prefix_push("pfmf"); - r1.val = 0; - r1.reg.sk = 1; - r1.reg.fsc = PFMF_FSC_4K; - r1.reg.key = 0x30; - expect_pgm_int(); - pfmf(r1.val, pagebuf); - check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); - report_prefix_pop(); -} - -static void test_psw_key(void) -{ - uint64_t psw_mask = extract_psw_mask() | 0xF0000000000000UL; - - report_prefix_push("psw key"); - expect_pgm_int(); - load_psw_mask(psw_mask); - check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); - report_prefix_pop(); -} - -static void test_mvcos(void) -{ - uint64_t r3 = 64; - uint8_t *src = pagebuf; - uint8_t *dst = pagebuf + PAGE_SIZE; - /* K bit set, as well as keys */ - register unsigned long oac asm("0") = 0xf002f002; - - report_prefix_push("mvcos"); - expect_pgm_int(); - asm volatile("mvcos %[dst],%[src],%[len]" - : [dst] "+Q" (*(dst)) - : [src] "Q" (*(src)), [len] "d" (r3), "d" (oac) - : "cc", "memory"); - check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); - report_prefix_pop(); -} - -static void test_spka(void) -{ - report_prefix_push("spka"); - expect_pgm_int(); - asm volatile("spka 0xf0(0)\n"); - check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); - report_prefix_pop(); -} - -static void test_tprot(void) -{ - report_prefix_push("tprot"); - expect_pgm_int(); - asm volatile("tprot %[addr],0xf0(0)\n" - : : [addr] "a" (pagebuf) : ); - check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); - report_prefix_pop(); -} - -int main(void) -{ - report_prefix_push("skrf"); - if (!test_facility(169)) { - report_skip("storage key removal facility not available\n"); - goto done; - } - - test_facilities(); - test_skey(); - test_pfmf(); - test_psw_key(); - test_mvcos(); - test_spka(); - test_tprot(); - -done: - report_prefix_pop(); - return report_summary(); -} diff --git a/s390x/smp.c b/s390x/smp.c deleted file mode 100644 index ad30e3c4..00000000 --- a/s390x/smp.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Tests sigp emulation - * - * Copyright 2019 IBM Corp. - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2. - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static int testflag = 0; - -static void wait_for_flag(void) -{ - while (!testflag) - mb(); -} - -static void set_flag(int val) -{ - mb(); - testflag = val; - mb(); -} - -static void test_func(void) -{ - set_flag(1); -} - -static void test_start(void) -{ - struct psw psw; - psw.mask = extract_psw_mask(); - psw.addr = (unsigned long)test_func; - - set_flag(0); - smp_cpu_start(1, psw); - wait_for_flag(); - report(1, "start"); -} - -/* - * Does only test restart when the target is running. - * The other tests do restarts when stopped multiple times already. - */ -static void test_restart(void) -{ - struct cpu *cpu = smp_cpu_from_addr(1); - struct lowcore *lc = cpu->lowcore; - - lc->restart_new_psw.mask = extract_psw_mask(); - lc->restart_new_psw.addr = (unsigned long)test_func; - - /* Make sure cpu is running */ - smp_cpu_stop(0); - set_flag(0); - smp_cpu_restart(1); - wait_for_flag(); - - /* - * Wait until cpu 1 has set the flag because it executed the - * restart function. - */ - set_flag(0); - smp_cpu_restart(1); - wait_for_flag(); - report(1, "restart while running"); -} - -static void test_stop(void) -{ - smp_cpu_stop(1); - /* - * The smp library waits for the CPU to shut down, but let's - * also do it here, so we don't rely on the library - * implementation - */ - while (!smp_cpu_stopped(1)) {} - report(1, "stop"); -} - -static void test_stop_store_status(void) -{ - struct cpu *cpu = smp_cpu_from_addr(1); - struct lowcore *lc = (void *)0x0; - - report_prefix_push("stop store status"); - report_prefix_push("running"); - smp_cpu_restart(1); - lc->prefix_sa = 0; - lc->grs_sa[15] = 0; - smp_cpu_stop_store_status(1); - mb(); - report(lc->prefix_sa == (uint32_t)(uintptr_t)cpu->lowcore, "prefix"); - report(lc->grs_sa[15], "stack"); - report(smp_cpu_stopped(1), "cpu stopped"); - report_prefix_pop(); - - report_prefix_push("stopped"); - lc->prefix_sa = 0; - lc->grs_sa[15] = 0; - smp_cpu_stop_store_status(1); - mb(); - report(lc->prefix_sa == (uint32_t)(uintptr_t)cpu->lowcore, "prefix"); - report(lc->grs_sa[15], "stack"); - report_prefix_pop(); - - report_prefix_pop(); -} - -static void test_store_status(void) -{ - struct cpu_status *status = alloc_pages(1); - uint32_t r; - - report_prefix_push("store status at address"); - memset(status, 0, PAGE_SIZE * 2); - - report_prefix_push("running"); - smp_cpu_restart(1); - sigp(1, SIGP_STORE_STATUS_AT_ADDRESS, (uintptr_t)status, &r); - report(r == SIGP_STATUS_INCORRECT_STATE, "incorrect state"); - report(!memcmp(status, (void *)status + PAGE_SIZE, PAGE_SIZE), - "status not written"); - report_prefix_pop(); - - memset(status, 0, PAGE_SIZE); - report_prefix_push("stopped"); - smp_cpu_stop(1); - sigp(1, SIGP_STORE_STATUS_AT_ADDRESS, (uintptr_t)status, NULL); - while (!status->prefix) { mb(); } - report(1, "status written"); - free_pages(status, PAGE_SIZE * 2); - report_prefix_pop(); - smp_cpu_stop(1); - - report_prefix_pop(); -} - -static void ecall(void) -{ - unsigned long mask; - struct lowcore *lc = (void *)0x0; - - expect_ext_int(); - ctl_set_bit(0, 13); - mask = extract_psw_mask(); - mask |= PSW_MASK_EXT; - load_psw_mask(mask); - set_flag(1); - while (lc->ext_int_code != 0x1202) { mb(); } - report(1, "received"); - set_flag(1); -} - -static void test_ecall(void) -{ - struct psw psw; - psw.mask = extract_psw_mask(); - psw.addr = (unsigned long)ecall; - - report_prefix_push("ecall"); - set_flag(0); - - smp_cpu_start(1, psw); - wait_for_flag(); - set_flag(0); - sigp(1, SIGP_EXTERNAL_CALL, 0, NULL); - wait_for_flag(); - smp_cpu_stop(1); - report_prefix_pop(); -} - -static void emcall(void) -{ - unsigned long mask; - struct lowcore *lc = (void *)0x0; - - expect_ext_int(); - ctl_set_bit(0, 14); - mask = extract_psw_mask(); - mask |= PSW_MASK_EXT; - load_psw_mask(mask); - set_flag(1); - while (lc->ext_int_code != 0x1201) { mb(); } - report(1, "received"); - set_flag(1); -} - -static void test_emcall(void) -{ - struct psw psw; - psw.mask = extract_psw_mask(); - psw.addr = (unsigned long)emcall; - - report_prefix_push("emcall"); - set_flag(0); - - smp_cpu_start(1, psw); - wait_for_flag(); - set_flag(0); - sigp(1, SIGP_EMERGENCY_SIGNAL, 0, NULL); - wait_for_flag(); - smp_cpu_stop(1); - report_prefix_pop(); -} - -static void test_sense_running(void) -{ - report_prefix_push("sense_running"); - /* we (CPU0) are running */ - report(smp_sense_running_status(0), "CPU0 sense claims running"); - /* stop the target CPU (CPU1) to speed up the not running case */ - smp_cpu_stop(1); - /* Make sure to have at least one time with a not running indication */ - while(smp_sense_running_status(1)); - report(true, "CPU1 sense claims not running"); - report_prefix_pop(); -} - -/* Used to dirty registers of cpu #1 before it is reset */ -static void test_func_initial(void) -{ - asm volatile("sfpc %0" :: "d" (0x11)); - lctlg(1, 0x42000UL); - lctlg(7, 0x43000UL); - lctlg(13, 0x44000UL); - set_flag(1); -} - -static void test_reset_initial(void) -{ - struct cpu_status *status = alloc_pages(0); - struct psw psw; - int i; - - psw.mask = extract_psw_mask(); - psw.addr = (unsigned long)test_func_initial; - - report_prefix_push("reset initial"); - set_flag(0); - smp_cpu_start(1, psw); - wait_for_flag(); - - sigp_retry(1, SIGP_INITIAL_CPU_RESET, 0, NULL); - sigp(1, SIGP_STORE_STATUS_AT_ADDRESS, (uintptr_t)status, NULL); - - report_prefix_push("clear"); - report(!status->psw.mask && !status->psw.addr, "psw"); - report(!status->prefix, "prefix"); - report(!status->fpc, "fpc"); - report(!status->cputm, "cpu timer"); - report(!status->todpr, "todpr"); - for (i = 1; i <= 13; i++) { - report(status->crs[i] == 0, "cr%d == 0", i); - } - report(status->crs[15] == 0, "cr15 == 0"); - report_prefix_pop(); - - report_prefix_push("initialized"); - report(status->crs[0] == 0xE0UL, "cr0 == 0xE0"); - report(status->crs[14] == 0xC2000000UL, "cr14 == 0xC2000000"); - report_prefix_pop(); - - report(smp_cpu_stopped(1), "cpu stopped"); - free_pages(status, PAGE_SIZE); - report_prefix_pop(); -} - -static void test_local_ints(void) -{ - unsigned long mask; - - /* Open masks for ecall and emcall */ - ctl_set_bit(0, 13); - ctl_set_bit(0, 14); - mask = extract_psw_mask(); - mask |= PSW_MASK_EXT; - load_psw_mask(mask); - set_flag(1); -} - -static void test_reset(void) -{ - struct psw psw; - - psw.mask = extract_psw_mask(); - psw.addr = (unsigned long)test_func; - - report_prefix_push("cpu reset"); - sigp(1, SIGP_EMERGENCY_SIGNAL, 0, NULL); - sigp(1, SIGP_EXTERNAL_CALL, 0, NULL); - smp_cpu_start(1, psw); - - sigp_retry(1, SIGP_CPU_RESET, 0, NULL); - report(smp_cpu_stopped(1), "cpu stopped"); - - set_flag(0); - psw.addr = (unsigned long)test_local_ints; - smp_cpu_start(1, psw); - wait_for_flag(); - report(true, "local interrupts cleared"); - report_prefix_pop(); -} - -int main(void) -{ - struct psw psw; - report_prefix_push("smp"); - - if (smp_query_num_cpus() == 1) { - report_skip("need at least 2 cpus for this test"); - goto done; - } - - /* Setting up the cpu to give it a stack and lowcore */ - psw.mask = extract_psw_mask(); - psw.addr = (unsigned long)test_func; - smp_cpu_setup(1, psw); - smp_cpu_stop(1); - - test_start(); - test_restart(); - test_stop(); - test_stop_store_status(); - test_store_status(); - test_ecall(); - test_emcall(); - test_sense_running(); - test_reset(); - test_reset_initial(); - smp_cpu_destroy(1); - -done: - report_prefix_pop(); - return report_summary(); -} diff --git a/s390x/sthyi.c b/s390x/sthyi.c deleted file mode 100644 index 68c57cb2..00000000 --- a/s390x/sthyi.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Tests exceptions and data validity for the emulated sthyi - * instruction. - * - * Copyright 2018 IBM Corp. - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include -#include -#include - -#include "sthyi.h" - -static uint8_t pagebuf[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); -static char null_buf[32] = {}; - -static inline int sthyi(uint64_t vaddr, uint64_t fcode, uint64_t *rc, - unsigned int r1, unsigned int r2) -{ - register uint64_t code asm("0") = fcode; - register uint64_t addr asm("2") = vaddr; - register uint64_t rc3 asm("3") = 0; - int cc = 0; - - asm volatile(".insn rre,0xB2560000,%[r1],%[r2]\n" - "ipm %[cc]\n" - "srl %[cc],28\n" - : [cc] "=d" (cc) - : [code] "d" (code), [addr] "a" (addr), [r1] "i" (r1), - [r2] "i" (r2) - : "memory", "cc", "r3"); - if (rc) - *rc = rc3; - return cc; -} - -static void test_exception_addr(void) -{ - report_prefix_push("Illegal address check"); - expect_pgm_int(); - sthyi(42042, 0, NULL, 0, 2); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static void test_exception_reg_odd(void) -{ - report_prefix_push("Register check odd R1"); - expect_pgm_int(); - sthyi((uint64_t)pagebuf, 0, NULL, 1, 2); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - report_prefix_push("Register check odd R2"); - expect_pgm_int(); - sthyi((uint64_t)pagebuf, 0, NULL, 0, 3); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static void test_exception_reg_equal(void) -{ - report_prefix_push("Register check equal"); - expect_pgm_int(); - sthyi((uint64_t)pagebuf, 0, NULL, 0, 0); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); -} - -static void test_function_code(uint64_t addr) -{ - uint64_t urc = 0; - int cc = sthyi((uint64_t)pagebuf, 42, &urc, 0, 2); - - report(cc == 3 && urc == CODE_UNSUPP, "Illegal fcode"); -} - -static void test_fcode0_hdr(struct sthyi_hdr_sctn *hdr) -{ - report_prefix_push("Header"); - - report(hdr->INFHDLN >= sizeof(*hdr) && !(hdr->INFHDLN % 8), "length"); - report((hdr->INFMLEN >= sizeof(struct sthyi_mach_sctn) && !(hdr->INFMLEN % 8)), - "Machine sctn length"); - report((hdr->INFPLEN >= sizeof(struct sthyi_par_sctn) && !(hdr->INFPLEN % 8)), - "Partition section length"); - - report(hdr->INFMOFF >= hdr->INFHDLN, "Machine offset"); - report(hdr->INFPOFF >= hdr->INFHDLN, "Partition offset"); - report_prefix_pop(); -} - -static void test_fcode0_mach(struct sthyi_mach_sctn *mach) -{ - int sum = mach->INFMSCPS + mach->INFMDCPS + mach->INFMSIFL + mach->INFMDIFL; - - report_prefix_push("Machine"); - if (mach->INFMVAL1 & MACH_ID_VLD) { - report(memcmp(mach->INFMTYPE, null_buf, sizeof(mach->INFMTYPE)), - "type"); - report(memcmp(mach->INFMMANU, null_buf, sizeof(mach->INFMMANU)), - "manufacturer"); - report(memcmp(mach->INFMSEQ, null_buf, sizeof(mach->INFMSEQ)), - "sequence"); - report(memcmp(mach->INFMPMAN, null_buf, sizeof(mach->INFMPMAN)), - "plant"); - } - - if (mach->INFMVAL1 & MACH_NAME_VLD) - report(memcmp(mach->INFMNAME, null_buf, sizeof(mach->INFMNAME)), - "name"); - - if (mach->INFMVAL1 & MACH_CNT_VLD) - report(sum, "core counts"); - report_prefix_pop(); -} - -static void test_fcode0_par(struct sthyi_par_sctn *par) -{ - int sum = par->INFPSCPS + par->INFPDCPS + par->INFPSIFL + par->INFPDIFL; - - report_prefix_push("Partition"); - if (par->INFPVAL1 & PART_CNT_VLD) - report(sum, "core counts"); - - if (par->INFPVAL1 & PART_STSI_SUC) { - report(par->INFPPNUM, "number"); - report(memcmp(par->INFPPNAM, null_buf, sizeof(par->INFPPNAM)), - "name"); - } - report_prefix_pop(); -} - -static void test_fcode0(void) -{ - struct sthyi_hdr_sctn *hdr; - struct sthyi_mach_sctn *mach; - struct sthyi_par_sctn *par; - - /* Zero destination memory. */ - memset(pagebuf, 0, PAGE_SIZE); - - report_prefix_push("fcode 0"); - sthyi((uint64_t)pagebuf, 0, NULL, 0, 2); - hdr = (void *)pagebuf; - mach = (void *)pagebuf + hdr->INFMOFF; - par = (void *)pagebuf + hdr->INFPOFF; - - test_fcode0_hdr(hdr); - test_fcode0_mach(mach); - test_fcode0_par(par); - report_prefix_pop(); -} - -int main(void) -{ - bool has_sthyi = test_facility(74); - - report_prefix_push("sthyi"); - - /* Test for availability */ - if (!has_sthyi) { - report_skip("STHYI is not available"); - goto done; - } - - /* Test register/argument checking. */ - report_prefix_push("Instruction"); - test_exception_addr(); - test_exception_reg_odd(); - test_exception_reg_equal(); - test_function_code((uint64_t) pagebuf); - report_prefix_pop(); - - /* Test function code 0 - CP and IFL Capacity Information */ - test_fcode0(); - -done: - report_prefix_pop(); - return report_summary(); -} diff --git a/s390x/sthyi.h b/s390x/sthyi.h deleted file mode 100644 index 06f757f8..00000000 --- a/s390x/sthyi.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * STHYI related flags and structure definitions. - * - * Copyright 2018 IBM Corp. - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#ifndef _STHYI_H_ -#define _STHYI_H_ - -#include - -enum sthyi_rtn_code { - CODE_UNSUPP = 0x04, /* with cc = 3 */ - CODE_SUCCES = 0x00, /* with cc = 0 */ -}; - -enum sthyi_hdr_flags { - HDR_PERF_UNAV = 0x80, - HDR_STSI_UNAV = 0x40, - HDR_STACK_INCM = 0x20, - HDR_NOT_LPAR = 0x10, -}; - -enum sthyi_mach_validity { - MACH_CNT_VLD = 0x80, - MACH_ID_VLD = 0x40, - MACH_NAME_VLD = 0x20, -}; - -enum sthyi_par_flag { - PART_MT_EN = 0x80, -}; - -enum sthyi_par_validity { - PART_CNT_VLD = 0x80, - PART_WGHT_CAP = 0x40, - PART_ABS_CAP = 0x20, - PART_STSI_SUC = 0x10, - PART_GRP_VLD = 0x08, -}; - -struct sthyi_hdr_sctn { - uint8_t INFHFLG1; - uint8_t INFHFLG2; /* reserved */ - uint8_t INFHVAL1; /* reserved */ - uint8_t INFHVAL2; /* reserved */ - uint8_t reserved[3]; - uint8_t INFHYGCT; - uint16_t INFHTOTL; - uint16_t INFHDLN; - uint16_t INFMOFF; - uint16_t INFMLEN; - uint16_t INFPOFF; - uint16_t INFPLEN; - uint16_t INFHOFF1; - uint16_t INFHLEN1; - uint16_t INFGOFF1; - uint16_t INFGLEN1; - uint16_t INFHOFF2; - uint16_t INFHLEN2; - uint16_t INFGOFF2; - uint16_t INFGLEN2; - uint16_t INFHOFF3; - uint16_t INFHLEN3; - uint16_t INFGOFF3; - uint16_t INFGLEN3; - uint8_t reserved2[4]; -} __attribute__((packed)); - -struct sthyi_mach_sctn { - uint8_t INFMFLG1; /* reserved */ - uint8_t INFMFLG2; /* reserved */ - uint8_t INFMVAL1; - uint8_t INFMVAL2; /* reserved */ - uint16_t INFMSCPS; - uint16_t INFMDCPS; - uint16_t INFMSIFL; - uint16_t INFMDIFL; - char INFMNAME[8]; - char INFMTYPE[4]; - char INFMMANU[16]; - char INFMSEQ[16]; - char INFMPMAN[4]; - uint8_t reserved[4]; -} __attribute__((packed)); - -struct sthyi_par_sctn { - uint8_t INFPFLG1; - uint8_t INFPFLG2; /* reserved */ - uint8_t INFPVAL1; - uint8_t INFPVAL2; /* reserved */ - uint16_t INFPPNUM; - uint16_t INFPSCPS; - uint16_t INFPDCPS; - uint16_t INFPSIFL; - uint16_t INFPDIFL; - uint16_t reserved; - char INFPPNAM[8]; - uint32_t INFPWBCP; - uint32_t INFPABCP; - uint32_t INFPWBIF; - uint32_t INFPABIF; -} __attribute__((packed)); - -struct sthyi_par_sctn_ext { - uint8_t INFPFLG1; - uint8_t INFPFLG2; /* reserved */ - uint8_t INFPVAL1; - uint8_t INFPVAL2; /* reserved */ - uint16_t INFPPNUM; - uint16_t INFPSCPS; - uint16_t INFPDCPS; - uint16_t INFPSIFL; - uint16_t INFPDIFL; - uint16_t reserved; - char INFPPNAM[8]; - uint32_t INFPWBCP; - uint32_t INFPABCP; - uint32_t INFPWBIF; - uint32_t INFPABIF; - char INFPLGNM[8]; - uint32_t INFPLGCP; - uint32_t INFPLGIF; -} __attribute__((packed)); - -#endif diff --git a/s390x/stsi.c b/s390x/stsi.c deleted file mode 100644 index b81cea75..00000000 --- a/s390x/stsi.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Store System Information tests - * - * Copyright (c) 2019 IBM Corp - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ - -#include -#include -#include -#include -#include - -struct stsi_322 { - uint8_t reserved[31]; - uint8_t count; - struct { - uint8_t reserved2[4]; - uint16_t total_cpus; - uint16_t conf_cpus; - uint16_t standby_cpus; - uint16_t reserved_cpus; - uint8_t name[8]; - uint32_t caf; - uint8_t cpi[16]; - uint8_t reserved5[3]; - uint8_t ext_name_encoding; - uint32_t reserved3; - uint8_t uuid[16]; - } vm[8]; - uint8_t reserved4[1504]; - uint8_t ext_names[8][256]; -}; -static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); - -static void test_specs(void) -{ - report_prefix_push("specification"); - - report_prefix_push("inv r0"); - expect_pgm_int(); - stsi(pagebuf, 0, 1 << 8, 0); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - report_prefix_push("inv r1"); - expect_pgm_int(); - stsi(pagebuf, 1, 0, 1 << 16); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - report_prefix_push("unaligned"); - expect_pgm_int(); - stsi(pagebuf + 42, 1, 1, 1); - check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); - report_prefix_pop(); - - report_prefix_pop(); -} - -static void test_priv(void) -{ - report_prefix_push("privileged"); - expect_pgm_int(); - enter_pstate(); - stsi(pagebuf, 0, 0, 0); - check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); - report_prefix_pop(); -} - -static inline unsigned long stsi_get_fc(void *addr) -{ - register unsigned long r0 asm("0") = 0; - register unsigned long r1 asm("1") = 0; - int cc; - - asm volatile("stsi 0(%[addr])\n" - "ipm %[cc]\n" - "srl %[cc],28\n" - : "+d" (r0), [cc] "=d" (cc) - : "d" (r1), [addr] "a" (addr) - : "cc", "memory"); - assert(!cc); - return r0 >> 28; -} - -static void test_fc(void) -{ - report(stsi(pagebuf, 7, 0, 0) == 3, "invalid fc"); - report(stsi(pagebuf, 1, 0, 1) == 3, "invalid selector 1"); - report(stsi(pagebuf, 1, 1, 0) == 3, "invalid selector 2"); - report(stsi_get_fc(pagebuf) >= 2, "query fc >= 2"); -} - -static void test_3_2_2(void) -{ - int rc; - /* EBCDIC for "kvm-unit" */ - const uint8_t vm_name[] = { 0x92, 0xa5, 0x94, 0x60, 0xa4, 0x95, 0x89, - 0xa3 }; - const uint8_t uuid[] = { 0x0f, 0xb8, 0x4a, 0x86, 0x72, 0x7c, - 0x11, 0xea, 0xbc, 0x55, 0x02, 0x42, 0xac, 0x13, - 0x00, 0x03 }; - /* EBCDIC for "KVM/" */ - const uint8_t cpi_kvm[] = { 0xd2, 0xe5, 0xd4, 0x61 }; - const char *vm_name_ext = "kvm-unit-test"; - struct stsi_322 *data = (void *)pagebuf; - - report_prefix_push("3.2.2"); - - /* Is the function code available at all? */ - if (stsi_get_fc(pagebuf) < 3) { - report_skip("Running under lpar, no level 3 to test."); - goto out; - } - - rc = stsi(pagebuf, 3, 2, 2); - report(!rc, "call"); - - /* For now we concentrate on KVM/QEMU */ - if (memcmp(&data->vm[0].cpi, cpi_kvm, sizeof(cpi_kvm))) { - report_skip("Not running under KVM/QEMU."); - goto out; - } - - report(!memcmp(data->vm[0].uuid, uuid, sizeof(uuid)), "uuid"); - report(data->vm[0].conf_cpus == smp_query_num_cpus(), "cpu count configured"); - report(data->vm[0].total_cpus == - data->vm[0].reserved_cpus + data->vm[0].conf_cpus, - "cpu count total == conf + reserved"); - report(data->vm[0].standby_cpus == 0, "cpu count standby"); - report(!memcmp(data->vm[0].name, vm_name, sizeof(data->vm[0].name)), - "VM name == kvm-unit-test"); - - if (data->vm[0].ext_name_encoding != 2) { - report_skip("Extended VM names are not UTF-8."); - goto out; - } - report(!memcmp(data->ext_names[0], vm_name_ext, sizeof(vm_name_ext)), - "ext VM name == kvm-unit-test"); - -out: - report_prefix_pop(); -} - -int main(void) -{ - report_prefix_push("stsi"); - test_priv(); - test_specs(); - test_fc(); - test_3_2_2(); - return report_summary(); -} diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg deleted file mode 100644 index b3073293..00000000 --- a/s390x/unittests.cfg +++ /dev/null @@ -1,86 +0,0 @@ -############################################################################## -# unittest configuration -# -# [unittest_name] -# file = .elf # Name of the elf file to be used. -# extra_params = -append # Additional parameters used. -# groups = ... # Used to identify test cases -# # with run_tests -g ... -# # Specify group_name=nodefault -# # to have test not run by default -# accel = kvm|tcg # Optionally specify if test must run with -# # kvm or tcg. If not specified, then kvm will -# # be used when available. -# timeout = # Optionally specify a timeout. -# check = = # check a file for a particular value before running -# # a test. The check line can contain multiple files -# # to check separated by a space but each check -# # parameter needs to be of the form = -############################################################################## - -[selftest-setup] -file = selftest.elf -groups = selftest -extra_params = -append 'test 123' - -[intercept] -file = intercept.elf - -[emulator] -file = emulator.elf - -[sieve] -file = sieve.elf -groups = selftest -# can take fairly long when KVM is nested inside z/VM -timeout = 600 - -[sthyi] -file = sthyi.elf - -[skey] -file = skey.elf - -[diag10] -file = diag10.elf - -[diag308] -file = diag308.elf - -[pfmf] -file = pfmf.elf - -[cmm] -file = cmm.elf - -[vector] -file = vector.elf - -[gs] -file = gs.elf - -[iep] -file = iep.elf - -[cpumodel] -file = cpumodel.elf - -[diag288] -file = diag288.elf -extra_params=-device diag288,id=watchdog0 --watchdog-action inject-nmi - -[stsi] -file = stsi.elf -extra_params=-name kvm-unit-test --uuid 0fb84a86-727c-11ea-bc55-0242ac130003 -smp 1,maxcpus=8 - -[smp] -file = smp.elf -smp = 2 - -[sclp-1g] -file = sclp.elf -extra_params = -m 1G - -[sclp-3g] -file = sclp.elf -extra_params = -m 3G diff --git a/s390x/vector.c b/s390x/vector.c deleted file mode 100644 index 0159ba13..00000000 --- a/s390x/vector.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Tests vector instruction support - * - * Copyright 2018 IBM Corp. - * - * Authors: - * Janosch Frank - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License version 2. - */ -#include -#include -#include -#include -#include - -static uint8_t pagebuf[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); - -/* Fills all vector registers with data from addr */ -static inline void vlm_all(unsigned long *addr) -{ - asm volatile(" .machine z13\n" - " vlm 0, 15, %[a]\n" - : : [a] "Q" (*addr) - : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", - "v9", "v10", "v11", "v12", "v13", "v14", "v15"); - asm volatile(" .machine z13\n" - " vlm 16, 31, %[a]\n" - : : [a] "Q" (*(addr+256/8)) - : "v16", "v17", "v18", "v19", "v20", "v21", "v22", - "v23", "v24", "v25", "v26", "v27", "v28", "v29", - "v30", "v31"); -} - -static void test_add(void) -{ - static struct prm { - __uint128_t a,b,c; - } prm __attribute__((aligned(16))); - - prm.a = prm.b = prm.c = 21; - - asm volatile(" .machine z13\n" - " vl 0, %[v1]\n" - " vl 1, %[v2]\n" - " va 2, 0, 1, 4\n" - " vst 2, %[v3]\n" - : [v3] "=Q" (prm.c) - : [v1] "Q" (prm.a), [v2] "Q" (prm.b) - : "v0", "v1", "v2", "memory"); - report(prm.c == 42, "adding 21"); -} - -/* z14 vector extension test */ -static void test_ext1_nand(void) -{ - bool has_vext = test_facility(134); - static struct prm { - __uint128_t a,b,c; - } prm __attribute__((aligned(16))); - - if (!has_vext) { - report_skip("Vector extensions 1 is not available"); - return; - } - - memset(&prm, 0xff, sizeof(prm)); - - asm volatile(" .machine z13\n" - " vl 0, %[v1]\n" - " vl 1, %[v2]\n" - " .byte 0xe7, 0x20, 0x10, 0x00, 0x00, 0x6e\n" /* vnn */ - " vst 2, %[v3]\n" - : [v3] "=Q" (prm.c) - : [v1] "Q" (prm.a), [v2] "Q" (prm.b) - : "v0", "v1", "v2", "memory"); - report(!prm.c, "nand ff"); -} - -/* z14 bcd extension test */ -static void test_bcd_add(void) -{ - bool has_bcd = test_facility(135); - static struct prm { - __uint128_t a,b,c; - } prm __attribute__((aligned(16))); - - if (!has_bcd) { - report_skip("Vector BCD extensions is not available"); - return; - } - - prm.c = 0; - prm.a = prm.b = 0b001000011100; - - asm volatile(" .machine z13\n" - " vl 0, %[v1]\n" - " vl 1, %[v2]\n" - " .byte 0xe6, 0x20, 0x10, 0x01, 0x00, 0x71\n" /* vap */ - " vst 2, %[v3]\n" - : [v3] "=Q" (prm.c) - : [v1] "Q" (prm.a), [v2] "Q" (prm.b) - : "v0", "v1", "v2", "memory"); - report(prm.c == 0x42c, "bcd add 21"); -} - -static void init(void) -{ - /* Enable vector instructions */ - ctl_set_bit(0, 17); - - /* Preset vector registers to 0xff */ - memset(pagebuf, 0xff, PAGE_SIZE); - vlm_all((u64*)pagebuf); -} - -int main(void) -{ - bool has_vregs = test_facility(129); - - report_prefix_push("vector"); - if (!has_vregs) { - report_skip("Basic vector facility is not available"); - goto done; - } - - init(); - test_add(); - test_ext1_nand(); - test_bcd_add(); - -done: - report_prefix_pop(); - return report_summary(); -} diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash deleted file mode 100644 index 660f1b7a..00000000 --- a/scripts/arch-run.bash +++ /dev/null @@ -1,380 +0,0 @@ -############################################################################## -# run_qemu translates the ambiguous exit status in Table1 to that in Table2. -# Table3 simply documents the complete status table. -# -# Table1: Before fixup -# -------------------- -# 0 - Unexpected exit from QEMU (possible signal), or the unittest did -# not use debug-exit -# 1 - most likely unittest succeeded, or QEMU failed -# -# Table2: After fixup -# ------------------- -# 0 - Everything succeeded -# 1 - most likely QEMU failed -# -# Table3: Complete table -# ---------------------- -# 0 - SUCCESS -# 1 - most likely QEMU failed -# 2 - most likely a run script failed -# 3 - most likely the unittest failed -# 124 - most likely the unittest timed out -# 127 - most likely the unittest called abort() -# 1..127 - FAILURE (could be QEMU, a run script, or the unittest) -# >= 128 - Signal (signum = status - 128) -############################################################################## -run_qemu () -{ - local stdout errors ret sig - - initrd_create || return $? - echo -n "$@" - [ "$ENVIRON_DEFAULT" = "yes" ] && echo -n " #" - echo " $INITRD" - - # stdout to {stdout}, stderr to $errors and stderr - exec {stdout}>&1 - errors=$("${@}" $INITRD >(tee /dev/stderr) > /dev/fd/$stdout) - ret=$? - exec {stdout}>&- - - [ $ret -eq 134 ] && echo "QEMU Aborted" >&2 - - if [ "$errors" ]; then - sig=$(grep 'terminating on signal' <<<"$errors") - if [ "$sig" ]; then - sig=$(sed 's/.*terminating on signal \([0-9][0-9]*\).*/\1/' <<<"$sig") - fi - fi - - if [ $ret -eq 0 ]; then - # Some signals result in a zero return status, but the - # error log tells the truth. - if [ "$sig" ]; then - ((ret=sig+128)) - else - # Exiting with zero (non-debugexit) is an error - ret=1 - fi - elif [ $ret -eq 1 ]; then - # Even when ret==1 (unittest success) if we also got stderr - # logs, then we assume a QEMU failure. Otherwise we translate - # status of 1 to 0 (SUCCESS) - if [ -z "$(echo "$errors" | grep -vi warning)" ]; then - ret=0 - fi - fi - - return $ret -} - -run_qemu_status () -{ - local stdout ret - - exec {stdout}>&1 - lines=$(run_qemu "$@" > >(tee /dev/fd/$stdout)) - ret=$? - exec {stdout}>&- - - if [ $ret -eq 1 ]; then - testret=$(grep '^EXIT: ' <<<"$lines" | sed 's/.*STATUS=\([0-9][0-9]*\).*/\1/') - if [ "$testret" ]; then - if [ $testret -eq 1 ]; then - ret=0 - else - ret=$testret - fi - fi - fi - - return $ret -} - -timeout_cmd () -{ - if [ "$TIMEOUT" ] && [ "$TIMEOUT" != "0" ]; then - echo "timeout -k 1s --foreground $TIMEOUT" - fi -} - -qmp () -{ - echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | nc -U $1 -} - -run_migration () -{ - if ! command -v nc >/dev/null 2>&1; then - echo "${FUNCNAME[0]} needs nc (netcat)" >&2 - return 2 - fi - - migsock=`mktemp -u -t mig-helper-socket.XXXXXXXXXX` - migout1=`mktemp -t mig-helper-stdout1.XXXXXXXXXX` - qmp1=`mktemp -u -t mig-helper-qmp1.XXXXXXXXXX` - qmp2=`mktemp -u -t mig-helper-qmp2.XXXXXXXXXX` - fifo=`mktemp -u -t mig-helper-fifo.XXXXXXXXXX` - qmpout1=/dev/null - qmpout2=/dev/null - - trap 'kill 0; exit 2' INT TERM - trap 'rm -f ${migout1} ${migsock} ${qmp1} ${qmp2} ${fifo}' RETURN EXIT - - eval "$@" -chardev socket,id=mon1,path=${qmp1},server,nowait \ - -mon chardev=mon1,mode=control | tee ${migout1} & - - # We have to use cat to open the named FIFO, because named FIFO's, unlike - # pipes, will block on open() until the other end is also opened, and that - # totally breaks QEMU... - mkfifo ${fifo} - eval "$@" -chardev socket,id=mon2,path=${qmp2},server,nowait \ - -mon chardev=mon2,mode=control -incoming unix:${migsock} < <(cat ${fifo}) & - incoming_pid=`jobs -l %+ | awk '{print$2}'` - - # The test must prompt the user to migrate, so wait for the "migrate" keyword - while ! grep -q -i "migrate" < ${migout1} ; do - sleep 1 - done - - qmp ${qmp1} '"migrate", "arguments": { "uri": "unix:'${migsock}'" }' > ${qmpout1} - - # Wait for the migration to complete - migstatus=`qmp ${qmp1} '"query-migrate"' | grep return` - while ! grep -q '"completed"' <<<"$migstatus" ; do - sleep 1 - migstatus=`qmp ${qmp1} '"query-migrate"' | grep return` - if grep -q '"failed"' <<<"$migstatus" ; then - echo "ERROR: Migration failed." >&2 - qmp ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null - qmp ${qmp2} '"quit"'> ${qmpout2} 2>/dev/null - return 2 - fi - done - qmp ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null - echo > ${fifo} - wait $incoming_pid - ret=$? - - while (( $(jobs -r | wc -l) > 0 )); do - sleep 0.5 - done - - return $ret -} - -migration_cmd () -{ - if [ "$MIGRATION" = "yes" ]; then - echo "run_migration" - fi -} - -search_qemu_binary () -{ - local save_path=$PATH - local qemucmd qemu - - export PATH=$PATH:/usr/libexec - for qemucmd in ${QEMU:-qemu-system-$ARCH_NAME qemu-kvm}; do - if $qemucmd --help 2>/dev/null | grep -q 'QEMU'; then - qemu="$qemucmd" - break - fi - done - - if [ -z "$qemu" ]; then - echo "A QEMU binary was not found." >&2 - echo "You can set a custom location by using the QEMU= environment variable." >&2 - return 2 - fi - command -v $qemu - export PATH=$save_path -} - -initrd_create () -{ - if [ "$ENVIRON_DEFAULT" = "yes" ]; then - trap_exit_push 'rm -f $KVM_UNIT_TESTS_ENV; [ "$KVM_UNIT_TESTS_ENV_OLD" ] && export KVM_UNIT_TESTS_ENV="$KVM_UNIT_TESTS_ENV_OLD" || unset KVM_UNIT_TESTS_ENV; unset KVM_UNIT_TESTS_ENV_OLD' - [ -f "$KVM_UNIT_TESTS_ENV" ] && export KVM_UNIT_TESTS_ENV_OLD="$KVM_UNIT_TESTS_ENV" - export KVM_UNIT_TESTS_ENV=$(mktemp) - env_params - env_file - env_errata || return $? - fi - - unset INITRD - [ -f "$KVM_UNIT_TESTS_ENV" ] && INITRD="-initrd $KVM_UNIT_TESTS_ENV" - - return 0 -} - -env_add_params () -{ - local p - - for p in "$@"; do - if eval test -v $p; then - eval export "$p" - else - eval export "$p=" - fi - grep "^$p=" <(env) >>$KVM_UNIT_TESTS_ENV - done -} - -env_params () -{ - local qemu have_qemu - local _ rest - - qemu=$(search_qemu_binary) && have_qemu=1 - - if [ "$have_qemu" ]; then - if [ -n "$ACCEL" ] || [ -n "$QEMU_ACCEL" ]; then - [ -n "$ACCEL" ] && QEMU_ACCEL=$ACCEL - fi - QEMU_VERSION_STRING="$($qemu -h | head -1)" - IFS='[ .]' read -r _ _ _ QEMU_MAJOR QEMU_MINOR QEMU_MICRO rest <<<"$QEMU_VERSION_STRING" - fi - env_add_params QEMU_ACCEL QEMU_VERSION_STRING QEMU_MAJOR QEMU_MINOR QEMU_MICRO - - KERNEL_VERSION_STRING=$(uname -r) - IFS=. read -r KERNEL_VERSION KERNEL_PATCHLEVEL rest <<<"$KERNEL_VERSION_STRING" - IFS=- read -r KERNEL_SUBLEVEL KERNEL_EXTRAVERSION <<<"$rest" - KERNEL_SUBLEVEL=${KERNEL_SUBLEVEL%%[!0-9]*} - KERNEL_EXTRAVERSION=${KERNEL_EXTRAVERSION%%[!0-9]*} - ! [[ $KERNEL_SUBLEVEL =~ ^[0-9]+$ ]] && unset $KERNEL_SUBLEVEL - ! [[ $KERNEL_EXTRAVERSION =~ ^[0-9]+$ ]] && unset $KERNEL_EXTRAVERSION - env_add_params KERNEL_VERSION_STRING KERNEL_VERSION KERNEL_PATCHLEVEL KERNEL_SUBLEVEL KERNEL_EXTRAVERSION -} - -env_file () -{ - local line var - - [ ! -f "$KVM_UNIT_TESTS_ENV_OLD" ] && return - - for line in $(grep -E '^[[:blank:]]*[[:alpha:]_][[:alnum:]_]*=' "$KVM_UNIT_TESTS_ENV_OLD"); do - var=${line%%=*} - if ! grep -q "^$var=" $KVM_UNIT_TESTS_ENV; then - eval export "$line" - grep "^$var=" <(env) >>$KVM_UNIT_TESTS_ENV - fi - done -} - -env_errata () -{ - if [ "$ERRATATXT" ] && [ ! -f "$ERRATATXT" ]; then - echo "$ERRATATXT not found. (ERRATATXT=$ERRATATXT)" >&2 - return 2 - elif [ "$ERRATATXT" ]; then - env_generate_errata - fi - sort <(env | grep '^ERRATA_') <(grep '^ERRATA_' $KVM_UNIT_TESTS_ENV) | uniq -u >>$KVM_UNIT_TESTS_ENV -} - -env_generate_errata () -{ - local line commit minver errata rest v p s x have - - for line in $(grep -v '^#' "$ERRATATXT" | tr -d '[:blank:]' | cut -d: -f1,2); do - commit=${line%:*} - minver=${line#*:} - - test -z "$commit" && continue - errata="ERRATA_$commit" - [ -n "${!errata}" ] && continue - - IFS=. read -r v p rest <<<"$minver" - IFS=- read -r s x <<<"$rest" - s=${s%%[!0-9]*} - x=${x%%[!0-9]*} - - if ! [[ $v =~ ^[0-9]+$ ]] || ! [[ $p =~ ^[0-9]+$ ]]; then - echo "Bad minimum kernel version in $ERRATATXT, $minver" - return 2 - fi - ! [[ $s =~ ^[0-9]+$ ]] && unset $s - ! [[ $x =~ ^[0-9]+$ ]] && unset $x - - if (( $KERNEL_VERSION > $v || - ($KERNEL_VERSION == $v && $KERNEL_PATCHLEVEL > $p) )); then - have=y - elif (( $KERNEL_VERSION == $v && $KERNEL_PATCHLEVEL == $p )); then - if [ "$KERNEL_SUBLEVEL" ] && [ "$s" ]; then - if (( $KERNEL_SUBLEVEL > $s )); then - have=y - elif (( $KERNEL_SUBLEVEL == $s )); then - if [ "$KERNEL_EXTRAVERSION" ] && [ "$x" ]; then - if (( $KERNEL_EXTRAVERSION >= $x )); then - have=y - else - have=n - fi - elif [ "$x" ] && (( $x != 0 )); then - have=n - else - have=y - fi - else - have=n - fi - elif [ "$s" ] && (( $s != 0 )); then - have=n - else - have=y - fi - else - have=n - fi - eval export "$errata=$have" - done -} - -trap_exit_push () -{ - local old_exit=$(trap -p EXIT | sed "s/^[^']*'//;s/'[^']*$//") - trap -- "$1; $old_exit" EXIT -} - -kvm_available () -{ - [ -c /dev/kvm ] || - return 1 - - [ "$HOST" = "$ARCH_NAME" ] || - ( [ "$HOST" = aarch64 ] && [ "$ARCH" = arm ] ) || - ( [ "$HOST" = x86_64 ] && [ "$ARCH" = i386 ] ) -} - -hvf_available () -{ - [ "$(sysctl -n kern.hv_support 2>/dev/null)" = "1" ] || return 1 - [ "$HOST" = "$ARCH_NAME" ] || - ( [ "$HOST" = x86_64 ] && [ "$ARCH" = i386 ] ) -} - -get_qemu_accelerator () -{ - if [ "$ACCEL" = "kvm" ] && ! kvm_available; then - echo "KVM is needed, but not available on this host" >&2 - return 2 - fi - if [ "$ACCEL" = "hvf" ] && ! hvf_available; then - echo "HVF is needed, but not available on this host" >&2 - return 2 - fi - - if [ "$ACCEL" ]; then - echo $ACCEL - elif kvm_available; then - echo kvm - elif hvf_available; then - echo hvf - else - echo tcg - fi -} diff --git a/scripts/asm-offsets.mak b/scripts/asm-offsets.mak deleted file mode 100644 index b35da09d..00000000 --- a/scripts/asm-offsets.mak +++ /dev/null @@ -1,43 +0,0 @@ -# -# asm-offsets adapted from the kernel, see -# Kbuild -# scripts/Kbuild.include -# scripts/Makefile.build -# -# Authors: Andrew Jones -# - -define sed-y - "/^->/{s:->#\(.*\):/* \1 */:; \ - s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \ - s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ - s:->::; p;}" -endef - -define make_asm_offsets - (set -e; \ - echo "#ifndef __ASM_OFFSETS_H__"; \ - echo "#define __ASM_OFFSETS_H__"; \ - echo "/*"; \ - echo " * Generated file. DO NOT MODIFY."; \ - echo " *"; \ - echo " */"; \ - echo ""; \ - sed -ne $(sed-y) $<; \ - echo ""; \ - echo "#endif" ) > $@ -endef - -$(asm-offsets:.h=.s): $(asm-offsets:.h=.c) - $(CC) $(CFLAGS) -fverbose-asm -S -o $@ $< - -$(asm-offsets): $(asm-offsets:.h=.s) - $(call make_asm_offsets) - cp -f $(asm-offsets) lib/generated/ - -OBJDIRS += lib/generated - -asm_offsets_clean: - $(RM) $(asm-offsets) $(asm-offsets:.h=.s) \ - $(addprefix lib/generated/,$(notdir $(asm-offsets))) - diff --git a/scripts/common.bash b/scripts/common.bash deleted file mode 100644 index 9a6ebbd7..00000000 --- a/scripts/common.bash +++ /dev/null @@ -1,50 +0,0 @@ - -function for_each_unittest() -{ - local unittests="$1" - local cmd="$2" - local testname - local smp - local kernel - local opts - local groups - local arch - local check - local accel - local timeout - - exec {fd}<"$unittests" - - while read -r -u $fd line; do - if [[ "$line" =~ ^\[(.*)\]$ ]]; then - "$cmd" "$testname" "$groups" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout" - testname=${BASH_REMATCH[1]} - smp=1 - kernel="" - opts="" - groups="" - arch="" - check="" - accel="" - timeout="" - elif [[ $line =~ ^file\ *=\ *(.*)$ ]]; then - kernel=$TEST_DIR/${BASH_REMATCH[1]} - elif [[ $line =~ ^smp\ *=\ *(.*)$ ]]; then - smp=${BASH_REMATCH[1]} - elif [[ $line =~ ^extra_params\ *=\ *(.*)$ ]]; then - opts=${BASH_REMATCH[1]} - elif [[ $line =~ ^groups\ *=\ *(.*)$ ]]; then - groups=${BASH_REMATCH[1]} - elif [[ $line =~ ^arch\ *=\ *(.*)$ ]]; then - arch=${BASH_REMATCH[1]} - elif [[ $line =~ ^check\ *=\ *(.*)$ ]]; then - check=${BASH_REMATCH[1]} - elif [[ $line =~ ^accel\ *=\ *(.*)$ ]]; then - accel=${BASH_REMATCH[1]} - elif [[ $line =~ ^timeout\ *=\ *(.*)$ ]]; then - timeout=${BASH_REMATCH[1]} - fi - done - "$cmd" "$testname" "$groups" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout" - exec {fd}<&- -} diff --git a/scripts/git.difforder b/scripts/git.difforder deleted file mode 100644 index ef493220..00000000 --- a/scripts/git.difforder +++ /dev/null @@ -1,25 +0,0 @@ -COPYRIGHT -MAINTAINERS -*README -scripts/*.mak -scripts/*.py -scripts/*.bash -scripts/*.sh -scripts/* -*/run -run_tests.sh -configure -*Makefile* -*.mak -lib/*.lds -lib/linux/* -lib/asm-generic/* -lib/*/asm/* -lib/*.h -lib/*.S -lib/*.c -*.lds -*.h -*.S -*.c -*.cfg diff --git a/scripts/mkstandalone.sh b/scripts/mkstandalone.sh deleted file mode 100755 index 9d506cc9..00000000 --- a/scripts/mkstandalone.sh +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env bash - -if [ ! -f config.mak ]; then - echo "run ./configure && make first. See ./configure -h" - exit 1 -fi -source config.mak -source scripts/common.bash - -temp_file () -{ - local var="$1" - local file="${2:--}" - - echo "$var=\`mktemp\`" - echo "cleanup=\"\$$var \$cleanup\"" - echo "base64 -d << 'BIN_EOF' | zcat > \$$var || exit 2" - - gzip -c "$file" | base64 - - echo "BIN_EOF" - echo "chmod +x \$$var" -} - -config_export () -{ - echo "export $(grep ^${1}= config.mak)" -} - -generate_test () -{ - local args=() - for arg in "${@}"; do - args+=("$(printf "%q" "$arg")") - done - - echo "#!/usr/bin/env bash" - echo "export STANDALONE=yes" - echo "export ENVIRON_DEFAULT=$ENVIRON_DEFAULT" - echo "export HOST=\$(uname -m | sed -e 's/i.86/i386/;s/arm.*/arm/;s/ppc64.*/ppc64/')" - echo "export PRETTY_PRINT_STACKS=no" - - config_export ARCH - config_export ARCH_NAME - config_export PROCESSOR - - echo "echo BUILD_HEAD=$(cat build-head)" - - if [ ! -f $kernel ]; then - echo 'echo "skip '"$testname"' (test kernel not present)"' - echo 'exit 2' - return - fi - - echo "trap 'rm -f \$cleanup' EXIT" - - if [ "$FIRMWARE" ]; then - temp_file FIRMWARE "$FIRMWARE" - echo 'export FIRMWARE' - fi - - if [ "$ENVIRON_DEFAULT" = "yes" ] && [ "$ERRATATXT" ]; then - temp_file ERRATATXT "$ERRATATXT" - echo 'export ERRATATXT' - fi - - temp_file bin "$kernel" - args[3]='$bin' - - (echo "#!/usr/bin/env bash" - cat scripts/arch-run.bash "$TEST_DIR/run") | temp_file RUNTIME_arch_run - - echo "exec {stdout}>&1" - echo "RUNTIME_log_stdout () { cat >&\$stdout; }" - echo "RUNTIME_log_stderr () { cat >&2; }" - - cat scripts/runtime.bash - - echo "run ${args[@]}" -} - -function mkstandalone() -{ - local testname="$1" - - if [ -z "$testname" ]; then - return - fi - - if [ -n "$one_testname" ] && [ "$testname" != "$one_testname" ]; then - return - fi - - standalone=tests/$testname - - generate_test "$@" > $standalone - - chmod +x $standalone - echo Written $standalone. -} - -if [ "$ENVIRON_DEFAULT" = "yes" ] && [ "$ERRATATXT" ] && [ ! -f "$ERRATATXT" ]; then - echo "$ERRATATXT not found. (ERRATATXT=$ERRATATXT)" >&2 - exit 2 -fi - -trap 'rm -f $cfg' EXIT -cfg=$(mktemp) - -unittests=$TEST_DIR/unittests.cfg -one_kernel="$1" - -if [ "$one_kernel" ]; then - [ ! -f $one_kernel ] && { - echo "$one_kernel doesn't exist" - exit 1 - } - - one_kernel_base=$(basename $one_kernel) - one_testname="${2:-${one_kernel_base%.*}}" - - if grep -q "\[$one_testname\]" $unittests; then - sed -n "/\\[$one_testname\\]/,/^\\[/p" $unittests \ - | awk '!/^\[/ || NR == 1' > $cfg - else - echo "[$one_testname]" > $cfg - echo "file = $one_kernel_base" >> $cfg - fi -else - cp -f $unittests $cfg -fi - -mkdir -p tests - -for_each_unittest $cfg mkstandalone diff --git a/scripts/pretty_print_stacks.py b/scripts/pretty_print_stacks.py deleted file mode 100755 index 1e59cde6..00000000 --- a/scripts/pretty_print_stacks.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python3 - -import re -import subprocess -import sys -import traceback - -config = {} - -# Subvert output buffering. -def puts(string): - sys.stdout.write(string) - sys.stdout.flush() - -def pretty_print_stack(binary, line): - addrs = line.split()[1:] - # Addresses are return addresses unless preceded by a '@'. We want the - # caller address so line numbers are more intuitive. Thus we subtract 1 - # from the address to get the call code. - for i in range(len(addrs)): - addr = addrs[i] - if addr.startswith('@'): - addrs[i] = addr[1:] - else: - addrs[i] = '%lx' % (int(addrs[i], 16) - 1) - - # Output like this: - # 0x004002be: start64 at path/to/kvm-unit-tests/x86/cstart64.S:208 - # (inlined by) test_ept_violation at path/to/kvm-unit-tests/x86/vmx_tests.c:1719 (discriminator 1) - cmd = [config.get('ADDR2LINE', 'addr2line'), '-e', binary, '-i', '-f', '--pretty', '--address'] - cmd.extend(addrs) - - p = subprocess.Popen(cmd, stdout=subprocess.PIPE) - out, err = p.communicate() - if p.returncode != 0: - puts(line) - return - - for line in out.splitlines(): - m = re.match(b'(.*) at [^ ]*/kvm-unit-tests/([^ ]*):([0-9]+)(.*)', line) - if m is None: - puts('%s\n' % line) - return - - head, path, line, tail = m.groups() - line = int(line) - puts('%s at %s:%d%s\n' % (head.decode(), path.decode(), line, tail.decode())) - try: - lines = open(path).readlines() - except IOError: - continue - if line > 1: - puts(' %s\n' % lines[line - 2].rstrip()) - puts(' > %s\n' % lines[line - 1].rstrip()) - if line < len(lines): - puts(' %s\n' % lines[line].rstrip()) - -def main(): - if len(sys.argv) != 2: - sys.stderr.write('usage: %s \n' % sys.argv[0]) - sys.exit(1) - - binary = sys.argv[1].replace(".flat", ".elf") - - with open("config.mak") as config_file: - for line in config_file: - name, val = line.partition("=")[::2] - config[name.strip()] = val.strip() - - try: - while True: - # Subvert input buffering. - line = sys.stdin.readline() - if line == '': - break - - puts(line) - - if not line.strip().startswith('STACK:'): - continue - - try: - pretty_print_stack(binary, line) - except Exception: - puts('Error pretty printing stack:\n') - puts(traceback.format_exc()) - puts('Continuing without pretty printing...\n') - while True: - puts(line) - line = sys.stdin.readline() - if line == '': - break - except: - sys.exit(1) - -if __name__ == '__main__': - main() diff --git a/scripts/runtime.bash b/scripts/runtime.bash deleted file mode 100644 index c88e2462..00000000 --- a/scripts/runtime.bash +++ /dev/null @@ -1,178 +0,0 @@ -: "${RUNTIME_arch_run?}" -: ${MAX_SMP:=$(getconf _NPROCESSORS_ONLN)} -: ${TIMEOUT:=90s} - -PASS() { echo -ne "\e[32mPASS\e[0m"; } -SKIP() { echo -ne "\e[33mSKIP\e[0m"; } -FAIL() { echo -ne "\e[31mFAIL\e[0m"; } - -extract_summary() -{ - local cr=$'\r' - tail -3 | grep '^SUMMARY: ' | sed 's/^SUMMARY: /(/;s/'"$cr"'\{0,1\}$/)/' -} - -# We assume that QEMU is going to work if it tried to load the kernel -premature_failure() -{ - local log="$(eval $(get_cmdline _NO_FILE_4Uhere_) 2>&1)" - - echo "$log" | grep "_NO_FILE_4Uhere_" | - grep -q -e "could not \(load\|open\) kernel" -e "error loading" && - return 1 - - RUNTIME_log_stderr <<< "$log" - - echo "$log" - return 0 -} - -get_cmdline() -{ - local kernel=$1 - echo "TESTNAME=$testname TIMEOUT=$timeout ACCEL=$accel $RUNTIME_arch_run $kernel -smp $smp $opts" -} - -skip_nodefault() -{ - [ "$run_all_tests" = "yes" ] && return 1 - [ "$STANDALONE" != "yes" ] && return 0 - - while true; do - read -r -p "Test marked not to be run by default, are you sure (y/N)? " yn - case $yn in - "Y" | "y" | "Yes" | "yes") - return 1 - ;; - "" | "N" | "n" | "No" | "no" | "q" | "quit" | "exit") - return 0 - ;; - esac - done -} - -function print_result() -{ - # output test results in a TAP format - # https://testanything.org/tap-version-13-specification.html - - local status="$1" - local testname="$2" - local summary="$3" - local reason="$4" - - if [ -z "$reason" ]; then - echo "`$status` $testname $summary" - else - echo "`$status` $testname ($reason)" - fi -} - -function find_word() -{ - grep -Fq " $1 " <<< " $2 " -} - -function run() -{ - local testname="$1" - local groups="$2" - local smp="$3" - local kernel="$4" - local opts="$5" - local arch="$6" - local check="${CHECK:-$7}" - local accel="$8" - local timeout="${9:-$TIMEOUT}" # unittests.cfg overrides the default - - if [ -z "$testname" ]; then - return - fi - - if [ -n "$only_tests" ] && ! find_word "$testname" "$only_tests"; then - return - fi - - if [ -n "$only_group" ] && ! find_word "$only_group" "$groups"; then - return - fi - - if [ -z "$only_group" ] && find_word nodefault "$groups" && - skip_nodefault; then - print_result "SKIP" $testname "" "test marked as manual run only" - return; - fi - - if [ -n "$arch" ] && [ "$arch" != "$ARCH" ]; then - print_result "SKIP" $testname "" "$arch only" - return 2 - fi - - if [ -n "$accel" ] && [ -n "$ACCEL" ] && [ "$accel" != "$ACCEL" ]; then - print_result "SKIP" $testname "" "$accel only, but ACCEL=$ACCEL" - return 2 - elif [ -n "$ACCEL" ]; then - accel="$ACCEL" - fi - - # check a file for a particular value before running a test - # the check line can contain multiple files to check separated by a space - # but each check parameter needs to be of the form = - for check_param in "${check[@]}"; do - path=${check_param%%=*} - value=${check_param#*=} - if [ "$path" ] && [ "$(cat $path)" != "$value" ]; then - print_result "SKIP" $testname "" "$path not equal to $value" - return 2 - fi - done - - last_line=$(premature_failure > >(tail -1)) && { - print_result "SKIP" $testname "" "$last_line" - return 77 - } - - cmdline=$(get_cmdline $kernel) - if grep -qw "migration" <<<$groups ; then - cmdline="MIGRATION=yes $cmdline" - fi - if [ "$verbose" = "yes" ]; then - echo $cmdline - fi - - # extra_params in the config file may contain backticks that need to be - # expanded, so use eval to start qemu. Use "> >(foo)" instead of a pipe to - # preserve the exit status. - summary=$(eval $cmdline 2> >(RUNTIME_log_stderr) \ - > >(tee >(RUNTIME_log_stdout $kernel) | extract_summary)) - ret=$? - [ "$STANDALONE" != "yes" ] && echo > >(RUNTIME_log_stdout $kernel) - - if [ $ret -eq 0 ]; then - print_result "PASS" $testname "$summary" - elif [ $ret -eq 77 ]; then - print_result "SKIP" $testname "$summary" - elif [ $ret -eq 124 ]; then - print_result "FAIL" $testname "" "timeout; duration=$timeout" - elif [ $ret -gt 127 ]; then - print_result "FAIL" $testname "" "terminated on SIG$(kill -l $(($ret - 128)))" - else - print_result "FAIL" $testname "$summary" - fi - - return $ret -} - -# -# Probe for MAX_SMP, in case it's less than the number of host cpus. -# -# This probing currently only works for ARM, as x86 bails on another -# error first. Also, this probing isn't necessary for any ARM hosts -# running kernels later than v4.3, i.e. those including ef748917b52 -# "arm/arm64: KVM: Remove 'config KVM_ARM_MAX_VCPUS'". So, at some -# point when maintaining the while loop gets too tiresome, we can -# just remove it... -while $RUNTIME_arch_run _NO_FILE_4Uhere_ -smp $MAX_SMP \ - |& grep -qi 'exceeds max CPUs'; do - MAX_SMP=$((MAX_SMP >> 1)) -done diff --git a/x86/Makefile b/x86/Makefile deleted file mode 100644 index 8a007ab5..00000000 --- a/x86/Makefile +++ /dev/null @@ -1 +0,0 @@ -include $(SRCDIR)/$(TEST_DIR)/Makefile.$(ARCH) diff --git a/x86/Makefile.common b/x86/Makefile.common deleted file mode 100644 index 2ea9c9f5..00000000 --- a/x86/Makefile.common +++ /dev/null @@ -1,83 +0,0 @@ -#This is a make file with common rules for both x86 & x86-64 - -all: directories test_cases - -cflatobjs += lib/pci.o -cflatobjs += lib/pci-edu.o -cflatobjs += lib/alloc.o -cflatobjs += lib/auxinfo.o -cflatobjs += lib/vmalloc.o -cflatobjs += lib/alloc_page.o -cflatobjs += lib/alloc_phys.o -cflatobjs += lib/x86/setup.o -cflatobjs += lib/x86/io.o -cflatobjs += lib/x86/smp.o -cflatobjs += lib/x86/vm.o -cflatobjs += lib/x86/fwcfg.o -cflatobjs += lib/x86/apic.o -cflatobjs += lib/x86/atomic.o -cflatobjs += lib/x86/desc.o -cflatobjs += lib/x86/isr.o -cflatobjs += lib/x86/acpi.o -cflatobjs += lib/x86/stack.o -cflatobjs += lib/x86/fault_test.o -cflatobjs += lib/x86/delay.o - -OBJDIRS += lib/x86 - -$(libcflat): LDFLAGS += -nostdlib -$(libcflat): CFLAGS += -ffreestanding -I $(SRCDIR)/lib -I lib - -COMMON_CFLAGS += -m$(bits) -COMMON_CFLAGS += -O1 - -# stack.o relies on frame pointers. -KEEP_FRAME_POINTER := y - -libgcc := $(shell $(CC) -m$(bits) --print-libgcc-file-name) - -# We want to keep intermediate file: %.elf and %.o -.PRECIOUS: %.elf %.o - -FLATLIBS = lib/libcflat.a $(libgcc) -%.elf: %.o $(FLATLIBS) $(SRCDIR)/x86/flat.lds $(cstart.o) - $(CC) $(CFLAGS) -nostdlib -o $@ -Wl,-T,$(SRCDIR)/x86/flat.lds \ - $(filter %.o, $^) $(FLATLIBS) - @chmod a-x $@ - -%.flat: %.elf - $(OBJCOPY) -O elf32-i386 $^ $@ - @chmod a-x $@ - -tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \ - $(TEST_DIR)/smptest.flat $(TEST_DIR)/port80.flat \ - $(TEST_DIR)/realmode.flat $(TEST_DIR)/msr.flat \ - $(TEST_DIR)/hypercall.flat $(TEST_DIR)/sieve.flat \ - $(TEST_DIR)/kvmclock_test.flat $(TEST_DIR)/eventinj.flat \ - $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat $(TEST_DIR)/setjmp.flat \ - $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \ - $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \ - $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \ - $(TEST_DIR)/hyperv_connections.flat \ - $(TEST_DIR)/umip.flat $(TEST_DIR)/tsx-ctrl.flat - -test_cases: $(tests-common) $(tests) - -$(TEST_DIR)/%.o: CFLAGS += -std=gnu99 -ffreestanding -I $(SRCDIR)/lib -I $(SRCDIR)/lib/x86 -I lib - -$(TEST_DIR)/realmode.elf: $(TEST_DIR)/realmode.o - $(CC) -m32 -nostdlib -o $@ -Wl,-T,$(SRCDIR)/$(TEST_DIR)/realmode.lds $^ - -$(TEST_DIR)/realmode.o: bits = 32 - -$(TEST_DIR)/kvmclock_test.elf: $(TEST_DIR)/kvmclock.o - -$(TEST_DIR)/hyperv_synic.elf: $(TEST_DIR)/hyperv.o - -$(TEST_DIR)/hyperv_stimer.elf: $(TEST_DIR)/hyperv.o - -$(TEST_DIR)/hyperv_connections.elf: $(TEST_DIR)/hyperv.o - -arch_clean: - $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \ - $(TEST_DIR)/.*.d lib/x86/.*.d \ diff --git a/x86/Makefile.i386 b/x86/Makefile.i386 deleted file mode 100644 index be9d6bcb..00000000 --- a/x86/Makefile.i386 +++ /dev/null @@ -1,11 +0,0 @@ -cstart.o = $(TEST_DIR)/cstart.o -bits = 32 -ldarch = elf32-i386 -COMMON_CFLAGS += -mno-sse -mno-sse2 - -cflatobjs += lib/x86/setjmp32.o - -tests = $(TEST_DIR)/taskswitch.flat $(TEST_DIR)/taskswitch2.flat \ - $(TEST_DIR)/cmpxchg8b.flat - -include $(SRCDIR)/$(TEST_DIR)/Makefile.common diff --git a/x86/Makefile.x86_64 b/x86/Makefile.x86_64 deleted file mode 100644 index af61d85d..00000000 --- a/x86/Makefile.x86_64 +++ /dev/null @@ -1,29 +0,0 @@ -cstart.o = $(TEST_DIR)/cstart64.o -bits = 64 -ldarch = elf64-x86-64 -COMMON_CFLAGS += -mno-red-zone -mno-sse -mno-sse2 - -cflatobjs += lib/x86/setjmp64.o -cflatobjs += lib/x86/intel-iommu.o -cflatobjs += lib/x86/usermode.o - -tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \ - $(TEST_DIR)/emulator.flat $(TEST_DIR)/idt_test.flat \ - $(TEST_DIR)/xsave.flat $(TEST_DIR)/rmap_chain.flat \ - $(TEST_DIR)/pcid.flat $(TEST_DIR)/debug.flat \ - $(TEST_DIR)/ioapic.flat $(TEST_DIR)/memory.flat \ - $(TEST_DIR)/pku.flat $(TEST_DIR)/hyperv_clock.flat -tests += $(TEST_DIR)/syscall.flat -tests += $(TEST_DIR)/svm.flat -tests += $(TEST_DIR)/vmx.flat -tests += $(TEST_DIR)/tscdeadline_latency.flat -tests += $(TEST_DIR)/intel-iommu.flat -tests += $(TEST_DIR)/vmware_backdoors.flat -tests += $(TEST_DIR)/rdpru.flat - -include $(SRCDIR)/$(TEST_DIR)/Makefile.common - -$(TEST_DIR)/hyperv_clock.elf: $(TEST_DIR)/hyperv_clock.o - -$(TEST_DIR)/vmx.elf: $(TEST_DIR)/vmx_tests.o -$(TEST_DIR)/svm.elf: $(TEST_DIR)/svm_tests.o diff --git a/x86/README b/x86/README deleted file mode 100644 index 218fe1a1..00000000 --- a/x86/README +++ /dev/null @@ -1,49 +0,0 @@ - -Tests for the x86 architecture are run as kernel images for qemu that support -multiboot format. The tests use an infrastructure called from the bios code. -The infrastructure initialize the system/cpus, switches to long-mode, and -calls the 'main' function of the individual test. Tests use a qemu virtual -test device, named testdev, for services like printing, exiting, querying -memory size, etc. See file docs/testdev.txt for more details. - -Examples of a test invocation: - These invocations run the msr test case and outputs to stdio. - - Using qemu-kvm: - - qemu-kvm -device testdev,chardev=testlog \ - -chardev file,id=testlog,path=msr.out \ - -serial stdio -kernel ./x86/msr.flat - - Using qemu (supported since qemu 1.3): - - qemu-system-x86_64 -enable-kvm -device pc-testdev -serial stdio \ - -device isa-debug-exit,iobase=0xf4,iosize=0x4 \ - -kernel ./x86/msr.flat - -Tests in this directory and what they do: - access: lots of page table related access (pte/pde) (read/write) - apic: enable x2apic, self ipi, ioapic intr, ioapic simultaneous - emulator: move to/from regs, cmps, push, pop, to/from cr8, smsw and lmsw - hypercall: intel and amd hypercall insn - msr: write to msr (only KERNEL_GS_BASE for now) - port80: lots of out to port 80 - realmode: goes back to realmode, shld, push/pop, mov immediate, cmp - immediate, add immediate, io, eflags instructions - (clc, cli, etc.), jcc short, jcc near, call, long jmp, xchg - sieve: heavy memory access with no paging and with paging static and - with paging vmalloc'ed - smptest: run smp_id() on every cpu and compares return value to number - tsc: write to tsc(0) and write to tsc(100000000000) and read it back - vmexit: long loops for each: cpuid, vmcall, mov_from_cr8, mov_to_cr8, - inl_pmtimer, ipi, ipi+halt - kvmclock_test: test of wallclock, monotonic cycle and performance of kvmclock - pcid: basic functionality test of PCID/INVPCID feature - -Legacy notes: - The exit status of the binary is inconsistent; with qemu-system, after - the unit-test is done, the exit status of qemu is 1, different from the - 'old style' qemu-kvm, whose exit status in successful completion is 0. - The run script converts the qemu-system exit status to 0 (SUCCESS), and - treats the legacy exit status of 0 as an error, converting it to an exit - status of 1. diff --git a/x86/access.c b/x86/access.c deleted file mode 100644 index 7dc9eb64..00000000 --- a/x86/access.c +++ /dev/null @@ -1,1052 +0,0 @@ - -#include "libcflat.h" -#include "desc.h" -#include "processor.h" -#include "asm/page.h" -#include "x86/vm.h" - -#define smp_id() 0 - -#define true 1 -#define false 0 - -static _Bool verbose = false; - -typedef unsigned long pt_element_t; -static int invalid_mask; -static int page_table_levels; - -#define PT_BASE_ADDR_MASK ((pt_element_t)((((pt_element_t)1 << 36) - 1) & PAGE_MASK)) -#define PT_PSE_BASE_ADDR_MASK (PT_BASE_ADDR_MASK & ~(1ull << 21)) - -#define CR0_WP_MASK (1UL << 16) -#define CR4_SMEP_MASK (1UL << 20) - -#define PFERR_PRESENT_MASK (1U << 0) -#define PFERR_WRITE_MASK (1U << 1) -#define PFERR_USER_MASK (1U << 2) -#define PFERR_RESERVED_MASK (1U << 3) -#define PFERR_FETCH_MASK (1U << 4) -#define PFERR_PK_MASK (1U << 5) - -#define MSR_EFER 0xc0000080 -#define EFER_NX_MASK (1ull << 11) - -#define PT_INDEX(address, level) \ - ((address) >> (12 + ((level)-1) * 9)) & 511 - -/* - * page table access check tests - */ - -enum { - AC_PTE_PRESENT_BIT, - AC_PTE_WRITABLE_BIT, - AC_PTE_USER_BIT, - AC_PTE_ACCESSED_BIT, - AC_PTE_DIRTY_BIT, - AC_PTE_NX_BIT, - AC_PTE_BIT51_BIT, - AC_PTE_BIT36_BIT, - - AC_PDE_PRESENT_BIT, - AC_PDE_WRITABLE_BIT, - AC_PDE_USER_BIT, - AC_PDE_ACCESSED_BIT, - AC_PDE_DIRTY_BIT, - AC_PDE_PSE_BIT, - AC_PDE_NX_BIT, - AC_PDE_BIT51_BIT, - AC_PDE_BIT36_BIT, - AC_PDE_BIT13_BIT, - - AC_PKU_AD_BIT, - AC_PKU_WD_BIT, - AC_PKU_PKEY_BIT, - - AC_ACCESS_USER_BIT, - AC_ACCESS_WRITE_BIT, - AC_ACCESS_FETCH_BIT, - AC_ACCESS_TWICE_BIT, - - AC_CPU_EFER_NX_BIT, - AC_CPU_CR0_WP_BIT, - AC_CPU_CR4_SMEP_BIT, - AC_CPU_CR4_PKE_BIT, - - NR_AC_FLAGS -}; - -#define AC_PTE_PRESENT_MASK (1 << AC_PTE_PRESENT_BIT) -#define AC_PTE_WRITABLE_MASK (1 << AC_PTE_WRITABLE_BIT) -#define AC_PTE_USER_MASK (1 << AC_PTE_USER_BIT) -#define AC_PTE_ACCESSED_MASK (1 << AC_PTE_ACCESSED_BIT) -#define AC_PTE_DIRTY_MASK (1 << AC_PTE_DIRTY_BIT) -#define AC_PTE_NX_MASK (1 << AC_PTE_NX_BIT) -#define AC_PTE_BIT51_MASK (1 << AC_PTE_BIT51_BIT) -#define AC_PTE_BIT36_MASK (1 << AC_PTE_BIT36_BIT) - -#define AC_PDE_PRESENT_MASK (1 << AC_PDE_PRESENT_BIT) -#define AC_PDE_WRITABLE_MASK (1 << AC_PDE_WRITABLE_BIT) -#define AC_PDE_USER_MASK (1 << AC_PDE_USER_BIT) -#define AC_PDE_ACCESSED_MASK (1 << AC_PDE_ACCESSED_BIT) -#define AC_PDE_DIRTY_MASK (1 << AC_PDE_DIRTY_BIT) -#define AC_PDE_PSE_MASK (1 << AC_PDE_PSE_BIT) -#define AC_PDE_NX_MASK (1 << AC_PDE_NX_BIT) -#define AC_PDE_BIT51_MASK (1 << AC_PDE_BIT51_BIT) -#define AC_PDE_BIT36_MASK (1 << AC_PDE_BIT36_BIT) -#define AC_PDE_BIT13_MASK (1 << AC_PDE_BIT13_BIT) - -#define AC_PKU_AD_MASK (1 << AC_PKU_AD_BIT) -#define AC_PKU_WD_MASK (1 << AC_PKU_WD_BIT) -#define AC_PKU_PKEY_MASK (1 << AC_PKU_PKEY_BIT) - -#define AC_ACCESS_USER_MASK (1 << AC_ACCESS_USER_BIT) -#define AC_ACCESS_WRITE_MASK (1 << AC_ACCESS_WRITE_BIT) -#define AC_ACCESS_FETCH_MASK (1 << AC_ACCESS_FETCH_BIT) -#define AC_ACCESS_TWICE_MASK (1 << AC_ACCESS_TWICE_BIT) - -#define AC_CPU_EFER_NX_MASK (1 << AC_CPU_EFER_NX_BIT) -#define AC_CPU_CR0_WP_MASK (1 << AC_CPU_CR0_WP_BIT) -#define AC_CPU_CR4_SMEP_MASK (1 << AC_CPU_CR4_SMEP_BIT) -#define AC_CPU_CR4_PKE_MASK (1 << AC_CPU_CR4_PKE_BIT) - -const char *ac_names[] = { - [AC_PTE_PRESENT_BIT] = "pte.p", - [AC_PTE_ACCESSED_BIT] = "pte.a", - [AC_PTE_WRITABLE_BIT] = "pte.rw", - [AC_PTE_USER_BIT] = "pte.user", - [AC_PTE_DIRTY_BIT] = "pte.d", - [AC_PTE_NX_BIT] = "pte.nx", - [AC_PTE_BIT51_BIT] = "pte.51", - [AC_PTE_BIT36_BIT] = "pte.36", - [AC_PDE_PRESENT_BIT] = "pde.p", - [AC_PDE_ACCESSED_BIT] = "pde.a", - [AC_PDE_WRITABLE_BIT] = "pde.rw", - [AC_PDE_USER_BIT] = "pde.user", - [AC_PDE_DIRTY_BIT] = "pde.d", - [AC_PDE_PSE_BIT] = "pde.pse", - [AC_PDE_NX_BIT] = "pde.nx", - [AC_PDE_BIT51_BIT] = "pde.51", - [AC_PDE_BIT36_BIT] = "pde.36", - [AC_PDE_BIT13_BIT] = "pde.13", - [AC_PKU_AD_BIT] = "pkru.ad", - [AC_PKU_WD_BIT] = "pkru.wd", - [AC_PKU_PKEY_BIT] = "pkey=1", - [AC_ACCESS_WRITE_BIT] = "write", - [AC_ACCESS_USER_BIT] = "user", - [AC_ACCESS_FETCH_BIT] = "fetch", - [AC_ACCESS_TWICE_BIT] = "twice", - [AC_CPU_EFER_NX_BIT] = "efer.nx", - [AC_CPU_CR0_WP_BIT] = "cr0.wp", - [AC_CPU_CR4_SMEP_BIT] = "cr4.smep", - [AC_CPU_CR4_PKE_BIT] = "cr4.pke", -}; - -static inline void *va(pt_element_t phys) -{ - return (void *)phys; -} - -typedef struct { - pt_element_t pt_pool; - unsigned pt_pool_size; - unsigned pt_pool_current; -} ac_pool_t; - -typedef struct { - unsigned flags; - void *virt; - pt_element_t phys; - pt_element_t *ptep; - pt_element_t expected_pte; - pt_element_t *pdep; - pt_element_t expected_pde; - pt_element_t ignore_pde; - int expected_fault; - unsigned expected_error; -} ac_test_t; - -typedef struct { - unsigned short limit; - unsigned long linear_addr; -} __attribute__((packed)) descriptor_table_t; - - -static void ac_test_show(ac_test_t *at); - -static unsigned long shadow_cr0; -static unsigned long shadow_cr4; -static unsigned long long shadow_efer; - -static void set_cr0_wp(int wp) -{ - unsigned long cr0 = shadow_cr0; - - cr0 &= ~CR0_WP_MASK; - if (wp) - cr0 |= CR0_WP_MASK; - if (cr0 != shadow_cr0) { - write_cr0(cr0); - shadow_cr0 = cr0; - } -} - -static unsigned set_cr4_smep(int smep) -{ - unsigned long cr4 = shadow_cr4; - extern u64 ptl2[]; - unsigned r; - - cr4 &= ~CR4_SMEP_MASK; - if (smep) - cr4 |= CR4_SMEP_MASK; - if (cr4 == shadow_cr4) - return 0; - - if (smep) - ptl2[2] &= ~PT_USER_MASK; - r = write_cr4_checking(cr4); - if (r || !smep) - ptl2[2] |= PT_USER_MASK; - if (!r) - shadow_cr4 = cr4; - return r; -} - -static void set_cr4_pke(int pke) -{ - unsigned long cr4 = shadow_cr4; - - cr4 &= ~X86_CR4_PKE; - if (pke) - cr4 |= X86_CR4_PKE; - if (cr4 == shadow_cr4) - return; - - /* Check that protection keys do not affect accesses when CR4.PKE=0. */ - if ((shadow_cr4 & X86_CR4_PKE) && !pke) - write_pkru(0xfffffffc); - write_cr4(cr4); - shadow_cr4 = cr4; -} - -static void set_efer_nx(int nx) -{ - unsigned long long efer = shadow_efer; - - efer &= ~EFER_NX_MASK; - if (nx) - efer |= EFER_NX_MASK; - if (efer != shadow_efer) { - wrmsr(MSR_EFER, efer); - shadow_efer = efer; - } -} - -static void ac_env_int(ac_pool_t *pool) -{ - extern char page_fault, kernel_entry; - set_idt_entry(14, &page_fault, 0); - set_idt_entry(0x20, &kernel_entry, 3); - - pool->pt_pool = 33 * 1024 * 1024; - pool->pt_pool_size = 120 * 1024 * 1024 - pool->pt_pool; - pool->pt_pool_current = 0; -} - -static void ac_test_init(ac_test_t *at, void *virt) -{ - set_efer_nx(1); - set_cr0_wp(1); - at->flags = 0; - at->virt = virt; - at->phys = 32 * 1024 * 1024; -} - -static int ac_test_bump_one(ac_test_t *at) -{ - at->flags = ((at->flags | invalid_mask) + 1) & ~invalid_mask; - return at->flags < (1 << NR_AC_FLAGS); -} - -#define F(x) ((flags & x##_MASK) != 0) - -static _Bool ac_test_legal(ac_test_t *at) -{ - int flags = at->flags; - - if (F(AC_ACCESS_FETCH) && F(AC_ACCESS_WRITE)) - return false; - - /* - * Since we convert current page to kernel page when cr4.smep=1, - * we can't switch to user mode. - */ - if (F(AC_ACCESS_USER) && F(AC_CPU_CR4_SMEP)) - return false; - - /* - * Only test protection key faults if CR4.PKE=1. - */ - if (!F(AC_CPU_CR4_PKE) && - (F(AC_PKU_AD) || F(AC_PKU_WD))) { - return false; - } - - /* - * pde.bit13 checks handling of reserved bits in largepage PDEs. It is - * meaningless if there is a PTE. - */ - if (!F(AC_PDE_PSE) && F(AC_PDE_BIT13)) - return false; - - /* - * Shorten the test by avoiding testing too many reserved bit combinations - */ - if ((F(AC_PDE_BIT51) + F(AC_PDE_BIT36) + F(AC_PDE_BIT13)) > 1) - return false; - if ((F(AC_PTE_BIT51) + F(AC_PTE_BIT36)) > 1) - return false; - - return true; -} - -static int ac_test_bump(ac_test_t *at) -{ - int ret; - - ret = ac_test_bump_one(at); - while (ret && !ac_test_legal(at)) - ret = ac_test_bump_one(at); - return ret; -} - -static pt_element_t ac_test_alloc_pt(ac_pool_t *pool) -{ - pt_element_t ret = pool->pt_pool + pool->pt_pool_current; - pool->pt_pool_current += PAGE_SIZE; - return ret; -} - -static _Bool ac_test_enough_room(ac_pool_t *pool) -{ - return pool->pt_pool_current + 5 * PAGE_SIZE <= pool->pt_pool_size; -} - -static void ac_test_reset_pt_pool(ac_pool_t *pool) -{ - pool->pt_pool_current = 0; -} - -static pt_element_t ac_test_permissions(ac_test_t *at, unsigned flags, - bool writable, bool user, - bool executable) -{ - bool kwritable = !F(AC_CPU_CR0_WP) && !F(AC_ACCESS_USER); - pt_element_t expected = 0; - - if (F(AC_ACCESS_USER) && !user) - at->expected_fault = 1; - - if (F(AC_ACCESS_WRITE) && !writable && !kwritable) - at->expected_fault = 1; - - if (F(AC_ACCESS_FETCH) && !executable) - at->expected_fault = 1; - - if (F(AC_ACCESS_FETCH) && user && F(AC_CPU_CR4_SMEP)) - at->expected_fault = 1; - - if (user && !F(AC_ACCESS_FETCH) && F(AC_PKU_PKEY) && F(AC_CPU_CR4_PKE)) { - if (F(AC_PKU_AD)) { - at->expected_fault = 1; - at->expected_error |= PFERR_PK_MASK; - } else if (F(AC_ACCESS_WRITE) && F(AC_PKU_WD) && !kwritable) { - at->expected_fault = 1; - at->expected_error |= PFERR_PK_MASK; - } - } - - if (!at->expected_fault) { - expected |= PT_ACCESSED_MASK; - if (F(AC_ACCESS_WRITE)) - expected |= PT_DIRTY_MASK; - } - - return expected; -} - -static void ac_emulate_access(ac_test_t *at, unsigned flags) -{ - bool pde_valid, pte_valid; - bool user, writable, executable; - - if (F(AC_ACCESS_USER)) - at->expected_error |= PFERR_USER_MASK; - - if (F(AC_ACCESS_WRITE)) - at->expected_error |= PFERR_WRITE_MASK; - - if (F(AC_ACCESS_FETCH)) - at->expected_error |= PFERR_FETCH_MASK; - - if (!F(AC_PDE_ACCESSED)) - at->ignore_pde = PT_ACCESSED_MASK; - - pde_valid = F(AC_PDE_PRESENT) - && !F(AC_PDE_BIT51) && !F(AC_PDE_BIT36) && !F(AC_PDE_BIT13) - && !(F(AC_PDE_NX) && !F(AC_CPU_EFER_NX)); - - if (!pde_valid) { - at->expected_fault = 1; - if (F(AC_PDE_PRESENT)) { - at->expected_error |= PFERR_RESERVED_MASK; - } else { - at->expected_error &= ~PFERR_PRESENT_MASK; - } - goto fault; - } - - writable = F(AC_PDE_WRITABLE); - user = F(AC_PDE_USER); - executable = !F(AC_PDE_NX); - - if (F(AC_PDE_PSE)) { - at->expected_pde |= ac_test_permissions(at, flags, writable, user, - executable); - goto no_pte; - } - - at->expected_pde |= PT_ACCESSED_MASK; - - pte_valid = F(AC_PTE_PRESENT) - && !F(AC_PTE_BIT51) && !F(AC_PTE_BIT36) - && !(F(AC_PTE_NX) && !F(AC_CPU_EFER_NX)); - - if (!pte_valid) { - at->expected_fault = 1; - if (F(AC_PTE_PRESENT)) { - at->expected_error |= PFERR_RESERVED_MASK; - } else { - at->expected_error &= ~PFERR_PRESENT_MASK; - } - goto fault; - } - - writable &= F(AC_PTE_WRITABLE); - user &= F(AC_PTE_USER); - executable &= !F(AC_PTE_NX); - - at->expected_pte |= ac_test_permissions(at, flags, writable, user, - executable); - -no_pte: -fault: - if (!at->expected_fault) - at->ignore_pde = 0; - if (!F(AC_CPU_EFER_NX) && !F(AC_CPU_CR4_SMEP)) - at->expected_error &= ~PFERR_FETCH_MASK; -} - -static void ac_set_expected_status(ac_test_t *at) -{ - invlpg(at->virt); - - if (at->ptep) - at->expected_pte = *at->ptep; - at->expected_pde = *at->pdep; - at->ignore_pde = 0; - at->expected_fault = 0; - at->expected_error = PFERR_PRESENT_MASK; - - if (at->flags & AC_ACCESS_TWICE_MASK) { - ac_emulate_access(at, at->flags & ~AC_ACCESS_WRITE_MASK - & ~AC_ACCESS_FETCH_MASK & ~AC_ACCESS_USER_MASK); - at->expected_fault = 0; - at->expected_error = PFERR_PRESENT_MASK; - at->ignore_pde = 0; - } - - ac_emulate_access(at, at->flags); -} - -static void __ac_setup_specific_pages(ac_test_t *at, ac_pool_t *pool, - u64 pd_page, u64 pt_page) - -{ - unsigned long root = read_cr3(); - int flags = at->flags; - bool skip = true; - - if (!ac_test_enough_room(pool)) - ac_test_reset_pt_pool(pool); - - at->ptep = 0; - for (int i = page_table_levels; i >= 1 && (i >= 2 || !F(AC_PDE_PSE)); --i) { - pt_element_t *vroot = va(root & PT_BASE_ADDR_MASK); - unsigned index = PT_INDEX((unsigned long)at->virt, i); - pt_element_t pte = 0; - - /* - * Reuse existing page tables along the path to the test code and data - * (which is in the bottom 2MB). - */ - if (skip && i >= 2 && index == 0) { - goto next; - } - skip = false; - - switch (i) { - case 5: - case 4: - case 3: - pte = pd_page ? pd_page : ac_test_alloc_pt(pool); - pte |= PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK; - break; - case 2: - if (!F(AC_PDE_PSE)) { - pte = pt_page ? pt_page : ac_test_alloc_pt(pool); - /* The protection key is ignored on non-leaf entries. */ - if (F(AC_PKU_PKEY)) - pte |= 2ull << 59; - } else { - pte = at->phys & PT_PSE_BASE_ADDR_MASK; - pte |= PT_PAGE_SIZE_MASK; - if (F(AC_PKU_PKEY)) - pte |= 1ull << 59; - } - if (F(AC_PDE_PRESENT)) - pte |= PT_PRESENT_MASK; - if (F(AC_PDE_WRITABLE)) - pte |= PT_WRITABLE_MASK; - if (F(AC_PDE_USER)) - pte |= PT_USER_MASK; - if (F(AC_PDE_ACCESSED)) - pte |= PT_ACCESSED_MASK; - if (F(AC_PDE_DIRTY)) - pte |= PT_DIRTY_MASK; - if (F(AC_PDE_NX)) - pte |= PT64_NX_MASK; - if (F(AC_PDE_BIT51)) - pte |= 1ull << 51; - if (F(AC_PDE_BIT36)) - pte |= 1ull << 36; - if (F(AC_PDE_BIT13)) - pte |= 1ull << 13; - at->pdep = &vroot[index]; - break; - case 1: - pte = at->phys & PT_BASE_ADDR_MASK; - if (F(AC_PKU_PKEY)) - pte |= 1ull << 59; - if (F(AC_PTE_PRESENT)) - pte |= PT_PRESENT_MASK; - if (F(AC_PTE_WRITABLE)) - pte |= PT_WRITABLE_MASK; - if (F(AC_PTE_USER)) - pte |= PT_USER_MASK; - if (F(AC_PTE_ACCESSED)) - pte |= PT_ACCESSED_MASK; - if (F(AC_PTE_DIRTY)) - pte |= PT_DIRTY_MASK; - if (F(AC_PTE_NX)) - pte |= PT64_NX_MASK; - if (F(AC_PTE_BIT51)) - pte |= 1ull << 51; - if (F(AC_PTE_BIT36)) - pte |= 1ull << 36; - at->ptep = &vroot[index]; - break; - } - vroot[index] = pte; - next: - root = vroot[index]; - } - ac_set_expected_status(at); -} - -static void ac_test_setup_pte(ac_test_t *at, ac_pool_t *pool) -{ - __ac_setup_specific_pages(at, pool, 0, 0); -} - -static void ac_setup_specific_pages(ac_test_t *at, ac_pool_t *pool, - u64 pd_page, u64 pt_page) -{ - return __ac_setup_specific_pages(at, pool, pd_page, pt_page); -} - -static void dump_mapping(ac_test_t *at) -{ - unsigned long root = read_cr3(); - int flags = at->flags; - int i; - - printf("Dump mapping: address: %p\n", at->virt); - for (i = page_table_levels ; i >= 1 && (i >= 2 || !F(AC_PDE_PSE)); --i) { - pt_element_t *vroot = va(root & PT_BASE_ADDR_MASK); - unsigned index = PT_INDEX((unsigned long)at->virt, i); - pt_element_t pte = vroot[index]; - - printf("------L%d: %lx\n", i, pte); - root = vroot[index]; - } -} - -static void ac_test_check(ac_test_t *at, _Bool *success_ret, _Bool cond, - const char *fmt, ...) -{ - va_list ap; - char buf[500]; - - if (!*success_ret) { - return; - } - - if (!cond) { - return; - } - - *success_ret = false; - - if (!verbose) { - puts("\n"); - ac_test_show(at); - } - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - printf("FAIL: %s\n", buf); - dump_mapping(at); -} - -static int pt_match(pt_element_t pte1, pt_element_t pte2, pt_element_t ignore) -{ - pte1 &= ~ignore; - pte2 &= ~ignore; - return pte1 == pte2; -} - -static int ac_test_do_access(ac_test_t *at) -{ - static unsigned unique = 42; - int fault = 0; - unsigned e; - static unsigned char user_stack[4096]; - unsigned long rsp; - _Bool success = true; - int flags = at->flags; - - ++unique; - if (!(unique & 65535)) { - puts("."); - } - - *((unsigned char *)at->phys) = 0xc3; /* ret */ - - unsigned r = unique; - set_cr0_wp(F(AC_CPU_CR0_WP)); - set_efer_nx(F(AC_CPU_EFER_NX)); - set_cr4_pke(F(AC_CPU_CR4_PKE)); - if (F(AC_CPU_CR4_PKE)) { - /* WD2=AD2=1, WD1=F(AC_PKU_WD), AD1=F(AC_PKU_AD) */ - write_pkru(0x30 | (F(AC_PKU_WD) ? 8 : 0) | - (F(AC_PKU_AD) ? 4 : 0)); - } - - set_cr4_smep(F(AC_CPU_CR4_SMEP)); - - if (F(AC_ACCESS_TWICE)) { - asm volatile ( - "mov $fixed2, %%rsi \n\t" - "mov (%[addr]), %[reg] \n\t" - "fixed2:" - : [reg]"=r"(r), [fault]"=a"(fault), "=b"(e) - : [addr]"r"(at->virt) - : "rsi" - ); - fault = 0; - } - - asm volatile ("mov $fixed1, %%rsi \n\t" - "mov %%rsp, %%rdx \n\t" - "cmp $0, %[user] \n\t" - "jz do_access \n\t" - "push %%rax; mov %[user_ds], %%ax; mov %%ax, %%ds; pop %%rax \n\t" - "pushq %[user_ds] \n\t" - "pushq %[user_stack_top] \n\t" - "pushfq \n\t" - "pushq %[user_cs] \n\t" - "pushq $do_access \n\t" - "iretq \n" - "do_access: \n\t" - "cmp $0, %[fetch] \n\t" - "jnz 2f \n\t" - "cmp $0, %[write] \n\t" - "jnz 1f \n\t" - "mov (%[addr]), %[reg] \n\t" - "jmp done \n\t" - "1: mov %[reg], (%[addr]) \n\t" - "jmp done \n\t" - "2: call *%[addr] \n\t" - "done: \n" - "fixed1: \n" - "int %[kernel_entry_vector] \n\t" - "back_to_kernel:" - : [reg]"+r"(r), "+a"(fault), "=b"(e), "=&d"(rsp) - : [addr]"r"(at->virt), - [write]"r"(F(AC_ACCESS_WRITE)), - [user]"r"(F(AC_ACCESS_USER)), - [fetch]"r"(F(AC_ACCESS_FETCH)), - [user_ds]"i"(USER_DS), - [user_cs]"i"(USER_CS), - [user_stack_top]"r"(user_stack + sizeof user_stack), - [kernel_entry_vector]"i"(0x20) - : "rsi"); - - asm volatile (".section .text.pf \n\t" - "page_fault: \n\t" - "pop %rbx \n\t" - "mov %rsi, (%rsp) \n\t" - "movl $1, %eax \n\t" - "iretq \n\t" - ".section .text"); - - asm volatile (".section .text.entry \n\t" - "kernel_entry: \n\t" - "mov %rdx, %rsp \n\t" - "jmp back_to_kernel \n\t" - ".section .text"); - - ac_test_check(at, &success, fault && !at->expected_fault, - "unexpected fault"); - ac_test_check(at, &success, !fault && at->expected_fault, - "unexpected access"); - ac_test_check(at, &success, fault && e != at->expected_error, - "error code %x expected %x", e, at->expected_error); - if (at->ptep) - ac_test_check(at, &success, *at->ptep != at->expected_pte, - "pte %x expected %x", *at->ptep, at->expected_pte); - ac_test_check(at, &success, - !pt_match(*at->pdep, at->expected_pde, at->ignore_pde), - "pde %x expected %x", *at->pdep, at->expected_pde); - - if (success && verbose) { - if (at->expected_fault) { - printf("PASS (%x)\n", at->expected_error); - } else { - printf("PASS\n"); - } - } - return success; -} - -static void ac_test_show(ac_test_t *at) -{ - char line[5000]; - - *line = 0; - strcat(line, "test"); - for (int i = 0; i < NR_AC_FLAGS; ++i) - if (at->flags & (1 << i)) { - strcat(line, " "); - strcat(line, ac_names[i]); - } - - strcat(line, ": "); - printf("%s", line); -} - -/* - * This test case is used to triger the bug which is fixed by - * commit e09e90a5 in the kvm tree - */ -static int corrupt_hugepage_triger(ac_pool_t *pool) -{ - ac_test_t at1, at2; - - ac_test_init(&at1, (void *)(0x123400000000)); - ac_test_init(&at2, (void *)(0x666600000000)); - - at2.flags = AC_CPU_CR0_WP_MASK | AC_PDE_PSE_MASK | AC_PDE_PRESENT_MASK; - ac_test_setup_pte(&at2, pool); - if (!ac_test_do_access(&at2)) - goto err; - - at1.flags = at2.flags | AC_PDE_WRITABLE_MASK; - ac_test_setup_pte(&at1, pool); - if (!ac_test_do_access(&at1)) - goto err; - - at1.flags |= AC_ACCESS_WRITE_MASK; - ac_set_expected_status(&at1); - if (!ac_test_do_access(&at1)) - goto err; - - at2.flags |= AC_ACCESS_WRITE_MASK; - ac_set_expected_status(&at2); - if (!ac_test_do_access(&at2)) - goto err; - - return 1; - -err: - printf("corrupt_hugepage_triger test fail\n"); - return 0; -} - -/* - * This test case is used to triger the bug which is fixed by - * commit 3ddf6c06e13e in the kvm tree - */ -static int check_pfec_on_prefetch_pte(ac_pool_t *pool) -{ - ac_test_t at1, at2; - - ac_test_init(&at1, (void *)(0x123406001000)); - ac_test_init(&at2, (void *)(0x123406003000)); - - at1.flags = AC_PDE_PRESENT_MASK | AC_PTE_PRESENT_MASK; - ac_setup_specific_pages(&at1, pool, 30 * 1024 * 1024, 30 * 1024 * 1024); - - at2.flags = at1.flags | AC_PTE_NX_MASK; - ac_setup_specific_pages(&at2, pool, 30 * 1024 * 1024, 30 * 1024 * 1024); - - if (!ac_test_do_access(&at1)) { - printf("%s: prepare fail\n", __FUNCTION__); - goto err; - } - - if (!ac_test_do_access(&at2)) { - printf("%s: check PFEC on prefetch pte path fail\n", - __FUNCTION__); - goto err; - } - - return 1; - -err: - return 0; -} - -/* - * If the write-fault access is from supervisor and CR0.WP is not set on the - * vcpu, kvm will fix it by adjusting pte access - it sets the W bit on pte - * and clears U bit. This is the chance that kvm can change pte access from - * readonly to writable. - * - * Unfortunately, the pte access is the access of 'direct' shadow page table, - * means direct sp.role.access = pte_access, then we will create a writable - * spte entry on the readonly shadow page table. It will cause Dirty bit is - * not tracked when two guest ptes point to the same large page. Note, it - * does not have other impact except Dirty bit since cr0.wp is encoded into - * sp.role. - * - * Note: to trigger this bug, hugepage should be disabled on host. - */ -static int check_large_pte_dirty_for_nowp(ac_pool_t *pool) -{ - ac_test_t at1, at2; - - ac_test_init(&at1, (void *)(0x123403000000)); - ac_test_init(&at2, (void *)(0x666606000000)); - - at2.flags = AC_PDE_PRESENT_MASK | AC_PDE_PSE_MASK; - ac_test_setup_pte(&at2, pool); - if (!ac_test_do_access(&at2)) { - printf("%s: read on the first mapping fail.\n", __FUNCTION__); - goto err; - } - - at1.flags = at2.flags | AC_ACCESS_WRITE_MASK; - ac_test_setup_pte(&at1, pool); - if (!ac_test_do_access(&at1)) { - printf("%s: write on the second mapping fail.\n", __FUNCTION__); - goto err; - } - - at2.flags |= AC_ACCESS_WRITE_MASK; - ac_set_expected_status(&at2); - if (!ac_test_do_access(&at2)) { - printf("%s: write on the first mapping fail.\n", __FUNCTION__); - goto err; - } - - return 1; - -err: - return 0; -} - -static int check_smep_andnot_wp(ac_pool_t *pool) -{ - ac_test_t at1; - int err_prepare_andnot_wp, err_smep_andnot_wp; - - if (!this_cpu_has(X86_FEATURE_SMEP)) { - return 1; - } - - ac_test_init(&at1, (void *)(0x123406001000)); - - at1.flags = AC_PDE_PRESENT_MASK | AC_PTE_PRESENT_MASK | - AC_PDE_USER_MASK | AC_PTE_USER_MASK | - AC_PDE_ACCESSED_MASK | AC_PTE_ACCESSED_MASK | - AC_CPU_CR4_SMEP_MASK | - AC_CPU_CR0_WP_MASK | - AC_ACCESS_WRITE_MASK; - ac_test_setup_pte(&at1, pool); - - /* - * Here we write the ro user page when - * cr0.wp=0, then we execute it and SMEP - * fault should happen. - */ - err_prepare_andnot_wp = ac_test_do_access(&at1); - if (!err_prepare_andnot_wp) { - printf("%s: SMEP prepare fail\n", __FUNCTION__); - goto clean_up; - } - - at1.flags &= ~AC_ACCESS_WRITE_MASK; - at1.flags |= AC_ACCESS_FETCH_MASK; - ac_set_expected_status(&at1); - err_smep_andnot_wp = ac_test_do_access(&at1); - -clean_up: - set_cr4_smep(0); - - if (!err_prepare_andnot_wp) - goto err; - if (!err_smep_andnot_wp) { - printf("%s: check SMEP without wp fail\n", __FUNCTION__); - goto err; - } - return 1; - -err: - return 0; -} - -static int ac_test_exec(ac_test_t *at, ac_pool_t *pool) -{ - int r; - - if (verbose) { - ac_test_show(at); - } - ac_test_setup_pte(at, pool); - r = ac_test_do_access(at); - return r; -} - -typedef int (*ac_test_fn)(ac_pool_t *pool); -const ac_test_fn ac_test_cases[] = -{ - corrupt_hugepage_triger, - check_pfec_on_prefetch_pte, - check_large_pte_dirty_for_nowp, - check_smep_andnot_wp -}; - -static int ac_test_run(void) -{ - ac_test_t at; - ac_pool_t pool; - int i, tests, successes; - - printf("run\n"); - tests = successes = 0; - - shadow_cr0 = read_cr0(); - shadow_cr4 = read_cr4(); - shadow_efer = rdmsr(MSR_EFER); - - if (cpuid_maxphyaddr() >= 52) { - invalid_mask |= AC_PDE_BIT51_MASK; - invalid_mask |= AC_PTE_BIT51_MASK; - } - if (cpuid_maxphyaddr() >= 37) { - invalid_mask |= AC_PDE_BIT36_MASK; - invalid_mask |= AC_PTE_BIT36_MASK; - } - - if (this_cpu_has(X86_FEATURE_PKU)) { - set_cr4_pke(1); - set_cr4_pke(0); - /* Now PKRU = 0xFFFFFFFF. */ - } else { - tests++; - if (write_cr4_checking(shadow_cr4 | X86_CR4_PKE) == GP_VECTOR) { - successes++; - invalid_mask |= AC_PKU_AD_MASK; - invalid_mask |= AC_PKU_WD_MASK; - invalid_mask |= AC_PKU_PKEY_MASK; - invalid_mask |= AC_CPU_CR4_PKE_MASK; - printf("CR4.PKE not available, disabling PKE tests\n"); - } else { - printf("Set PKE in CR4 - expect #GP: FAIL!\n"); - set_cr4_pke(0); - } - } - - if (!this_cpu_has(X86_FEATURE_SMEP)) { - tests++; - if (set_cr4_smep(1) == GP_VECTOR) { - successes++; - invalid_mask |= AC_CPU_CR4_SMEP_MASK; - printf("CR4.SMEP not available, disabling SMEP tests\n"); - } else { - printf("Set SMEP in CR4 - expect #GP: FAIL!\n"); - set_cr4_smep(0); - } - } - - /* Toggling LA57 in 64-bit mode (guaranteed for this test) is illegal. */ - if (this_cpu_has(X86_FEATURE_LA57)) { - tests++; - if (write_cr4_checking(shadow_cr4 ^ X86_CR4_LA57) == GP_VECTOR) - successes++; - - /* Force a VM-Exit on KVM, which doesn't intercept LA57 itself. */ - tests++; - if (write_cr4_checking(shadow_cr4 ^ (X86_CR4_LA57 | X86_CR4_PSE)) == GP_VECTOR) - successes++; - } - - ac_env_int(&pool); - ac_test_init(&at, (void *)(0x123400000000 + 16 * smp_id())); - do { - ++tests; - successes += ac_test_exec(&at, &pool); - } while (ac_test_bump(&at)); - - for (i = 0; i < ARRAY_SIZE(ac_test_cases); i++) { - ++tests; - successes += ac_test_cases[i](&pool); - } - - printf("\n%d tests, %d failures\n", tests, tests - successes); - - return successes == tests; -} - -int main(void) -{ - int r; - - printf("starting test\n\n"); - page_table_levels = 4; - r = ac_test_run(); - - if (this_cpu_has(X86_FEATURE_LA57)) { - page_table_levels = 5; - printf("starting 5-level paging test.\n\n"); - setup_5level_page_table(); - r = ac_test_run(); - } - - return r ? 0 : 1; -} diff --git a/x86/apic.c b/x86/apic.c deleted file mode 100644 index a7681fea..00000000 --- a/x86/apic.c +++ /dev/null @@ -1,674 +0,0 @@ -#include "libcflat.h" -#include "apic.h" -#include "vm.h" -#include "smp.h" -#include "desc.h" -#include "isr.h" -#include "msr.h" -#include "atomic.h" -#include "fwcfg.h" - -#define MAX_TPR 0xf - -static void test_lapic_existence(void) -{ - u8 version; - - version = (u8)apic_read(APIC_LVR); - printf("apic version: %x\n", version); - report(version >= 0x10 && version <= 0x15, "apic existence"); -} - -#define TSC_DEADLINE_TIMER_VECTOR 0xef -#define BROADCAST_VECTOR 0xcf - -static int tdt_count; - -static void tsc_deadline_timer_isr(isr_regs_t *regs) -{ - ++tdt_count; - eoi(); -} - -static void __test_tsc_deadline_timer(void) -{ - handle_irq(TSC_DEADLINE_TIMER_VECTOR, tsc_deadline_timer_isr); - irq_enable(); - - wrmsr(MSR_IA32_TSCDEADLINE, rdmsr(MSR_IA32_TSC)); - asm volatile ("nop"); - report(tdt_count == 1, "tsc deadline timer"); - report(rdmsr(MSR_IA32_TSCDEADLINE) == 0, "tsc deadline timer clearing"); -} - -static int enable_tsc_deadline_timer(void) -{ - uint32_t lvtt; - - if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) { - lvtt = APIC_LVT_TIMER_TSCDEADLINE | TSC_DEADLINE_TIMER_VECTOR; - apic_write(APIC_LVTT, lvtt); - return 1; - } else { - return 0; - } -} - -static void test_tsc_deadline_timer(void) -{ - if(enable_tsc_deadline_timer()) { - __test_tsc_deadline_timer(); - } else { - report_skip("tsc deadline timer not detected"); - } -} - -static void do_write_apicbase(void *data) -{ - wrmsr(MSR_IA32_APICBASE, *(u64 *)data); -} - -static bool test_write_apicbase_exception(u64 data) -{ - return test_for_exception(GP_VECTOR, do_write_apicbase, &data); -} - -static void test_enable_x2apic(void) -{ - u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE); - u64 apicbase; - - if (enable_x2apic()) { - printf("x2apic enabled\n"); - - apicbase = orig_apicbase & ~(APIC_EN | APIC_EXTD); - report(test_write_apicbase_exception(apicbase | APIC_EXTD), - "x2apic enabled to invalid state"); - report(test_write_apicbase_exception(apicbase | APIC_EN), - "x2apic enabled to apic enabled"); - - report(!test_write_apicbase_exception(apicbase | 0), - "x2apic enabled to disabled state"); - report(test_write_apicbase_exception(apicbase | APIC_EXTD), - "disabled to invalid state"); - report(test_write_apicbase_exception(apicbase | APIC_EN | APIC_EXTD), - "disabled to x2apic enabled"); - - report(!test_write_apicbase_exception(apicbase | APIC_EN), - "apic disabled to apic enabled"); - report(test_write_apicbase_exception(apicbase | APIC_EXTD), - "apic enabled to invalid state"); - - if (orig_apicbase & APIC_EXTD) - enable_x2apic(); - else - reset_apic(); - - /* - * Disabling the APIC resets various APIC registers, restore them to - * their desired values. - */ - apic_write(APIC_SPIV, 0x1ff); - } else { - printf("x2apic not detected\n"); - - report(test_write_apicbase_exception(APIC_EN | APIC_EXTD), - "enable unsupported x2apic"); - } -} - -static void verify_disabled_apic_mmio(void) -{ - volatile u32 *lvr = (volatile u32 *)(APIC_DEFAULT_PHYS_BASE + APIC_LVR); - volatile u32 *tpr = (volatile u32 *)(APIC_DEFAULT_PHYS_BASE + APIC_TASKPRI); - u32 cr8 = read_cr8(); - - memset((void *)APIC_DEFAULT_PHYS_BASE, 0xff, PAGE_SIZE); - report(*lvr == ~0, "*0xfee00030: %x", *lvr); - report(read_cr8() == cr8, "CR8: %lx", read_cr8()); - write_cr8(cr8 ^ MAX_TPR); - report(read_cr8() == (cr8 ^ MAX_TPR), "CR8: %lx", read_cr8()); - report(*tpr == ~0, "*0xfee00080: %x", *tpr); - write_cr8(cr8); -} - -static void test_apic_disable(void) -{ - volatile u32 *lvr = (volatile u32 *)(APIC_DEFAULT_PHYS_BASE + APIC_LVR); - volatile u32 *tpr = (volatile u32 *)(APIC_DEFAULT_PHYS_BASE + APIC_TASKPRI); - u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE); - u32 apic_version = apic_read(APIC_LVR); - u32 cr8 = read_cr8(); - - report_prefix_push("apic_disable"); - assert_msg(orig_apicbase & APIC_EN, "APIC not enabled."); - - disable_apic(); - report(!(rdmsr(MSR_IA32_APICBASE) & APIC_EN), "Local apic disabled"); - report(!this_cpu_has(X86_FEATURE_APIC), - "CPUID.1H:EDX.APIC[bit 9] is clear"); - verify_disabled_apic_mmio(); - - reset_apic(); - report((rdmsr(MSR_IA32_APICBASE) & (APIC_EN | APIC_EXTD)) == APIC_EN, - "Local apic enabled in xAPIC mode"); - report(this_cpu_has(X86_FEATURE_APIC), "CPUID.1H:EDX.APIC[bit 9] is set"); - report(*lvr == apic_version, "*0xfee00030: %x", *lvr); - report(*tpr == cr8, "*0xfee00080: %x", *tpr); - write_cr8(cr8 ^ MAX_TPR); - report(*tpr == (cr8 ^ MAX_TPR) << 4, "*0xfee00080: %x", *tpr); - write_cr8(cr8); - - if (enable_x2apic()) { - apic_write(APIC_SPIV, 0x1ff); - report((rdmsr(MSR_IA32_APICBASE) & (APIC_EN | APIC_EXTD)) == (APIC_EN | APIC_EXTD), - "Local apic enabled in x2APIC mode"); - report(this_cpu_has(X86_FEATURE_APIC), - "CPUID.1H:EDX.APIC[bit 9] is set"); - verify_disabled_apic_mmio(); - if (!(orig_apicbase & APIC_EXTD)) - reset_apic(); - } - report_prefix_pop(); -} - -#define ALTERNATE_APIC_BASE 0xfed40000 - -static void test_apicbase(void) -{ - u64 orig_apicbase = rdmsr(MSR_IA32_APICBASE); - u32 lvr = apic_read(APIC_LVR); - u64 value; - - wrmsr(MSR_IA32_APICBASE, orig_apicbase & ~(APIC_EN | APIC_EXTD)); - wrmsr(MSR_IA32_APICBASE, ALTERNATE_APIC_BASE | APIC_BSP | APIC_EN); - - report_prefix_push("apicbase"); - - report(*(volatile u32 *)(ALTERNATE_APIC_BASE + APIC_LVR) == lvr, - "relocate apic"); - - value = orig_apicbase | (1UL << cpuid_maxphyaddr()); - report(test_for_exception(GP_VECTOR, do_write_apicbase, &value), - "reserved physaddr bits"); - - value = orig_apicbase | 1; - report(test_for_exception(GP_VECTOR, do_write_apicbase, &value), - "reserved low bits"); - - wrmsr(MSR_IA32_APICBASE, orig_apicbase); - apic_write(APIC_SPIV, 0x1ff); - - report_prefix_pop(); -} - -static void do_write_apic_id(void *id) -{ - apic_write(APIC_ID, *(u32 *)id); -} - -static void __test_apic_id(void * unused) -{ - u32 id, newid; - u8 initial_xapic_id = cpuid(1).b >> 24; - u32 initial_x2apic_id = cpuid(0xb).d; - bool x2apic_mode = rdmsr(MSR_IA32_APICBASE) & APIC_EXTD; - - if (x2apic_mode) - reset_apic(); - - id = apic_id(); - report(initial_xapic_id == id, "xapic id matches cpuid"); - - newid = (id + 1) << 24; - report(!test_for_exception(GP_VECTOR, do_write_apic_id, &newid) && - (id == apic_id() || id + 1 == apic_id()), - "writeable xapic id"); - - if (!enable_x2apic()) - goto out; - - report(test_for_exception(GP_VECTOR, do_write_apic_id, &newid), - "non-writeable x2apic id"); - report(initial_xapic_id == (apic_id() & 0xff), "sane x2apic id"); - - /* old QEMUs do not set initial x2APIC ID */ - report(initial_xapic_id == (initial_x2apic_id & 0xff) && - initial_x2apic_id == apic_id(), - "x2apic id matches cpuid"); - -out: - reset_apic(); - - report(initial_xapic_id == apic_id(), "correct xapic id after reset"); - - /* old KVMs do not reset xAPIC ID */ - if (id != apic_id()) - apic_write(APIC_ID, id << 24); - - if (x2apic_mode) - enable_x2apic(); -} - -static void test_apic_id(void) -{ - if (cpu_count() < 2) - return; - - on_cpu(1, __test_apic_id, NULL); -} - -static int ipi_count; - -static void self_ipi_isr(isr_regs_t *regs) -{ - ++ipi_count; - eoi(); -} - -static void test_self_ipi(void) -{ - u64 start = rdtsc(); - int vec = 0xf1; - - handle_irq(vec, self_ipi_isr); - irq_enable(); - apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | vec, - id_map[0]); - - do { - pause(); - } while (rdtsc() - start < 1000000000 && ipi_count == 0); - - report(ipi_count == 1, "self ipi"); -} - -volatile int nmi_counter_private, nmi_counter, nmi_hlt_counter, sti_loop_active; - -static void sti_nop(char *p) -{ - asm volatile ( - ".globl post_sti \n\t" - "sti \n" - /* - * vmx won't exit on external interrupt if blocked-by-sti, - * so give it a reason to exit by accessing an unmapped page. - */ - "post_sti: testb $0, %0 \n\t" - "nop \n\t" - "cli" - : : "m"(*p) - ); - nmi_counter = nmi_counter_private; -} - -static void sti_loop(void *ignore) -{ - unsigned k = 0; - - while (sti_loop_active) { - sti_nop((char *)(ulong)((k++ * 4096) % (128 * 1024 * 1024))); - } -} - -static void nmi_handler(isr_regs_t *regs) -{ - extern void post_sti(void); - ++nmi_counter_private; - nmi_hlt_counter += regs->rip == (ulong)post_sti; -} - -static void update_cr3(void *cr3) -{ - write_cr3((ulong)cr3); -} - -static void test_sti_nmi(void) -{ - unsigned old_counter; - - if (cpu_count() < 2) { - return; - } - - handle_irq(2, nmi_handler); - on_cpu(1, update_cr3, (void *)read_cr3()); - - sti_loop_active = 1; - on_cpu_async(1, sti_loop, 0); - while (nmi_counter < 30000) { - old_counter = nmi_counter; - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[1]); - while (nmi_counter == old_counter) { - ; - } - } - sti_loop_active = 0; - report(nmi_hlt_counter == 0, "nmi-after-sti"); -} - -static volatile bool nmi_done, nmi_flushed; -static volatile int nmi_received; -static volatile int cpu0_nmi_ctr1, cpu1_nmi_ctr1; -static volatile int cpu0_nmi_ctr2, cpu1_nmi_ctr2; - -static void multiple_nmi_handler(isr_regs_t *regs) -{ - ++nmi_received; -} - -static void kick_me_nmi(void *blah) -{ - while (!nmi_done) { - ++cpu1_nmi_ctr1; - while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1 && !nmi_done) { - pause(); - } - if (nmi_done) { - return; - } - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[0]); - /* make sure the NMI has arrived by sending an IPI after it */ - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT - | 0x44, id_map[0]); - ++cpu1_nmi_ctr2; - while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2 && !nmi_done) { - pause(); - } - } -} - -static void flush_nmi(isr_regs_t *regs) -{ - nmi_flushed = true; - apic_write(APIC_EOI, 0); -} - -static void test_multiple_nmi(void) -{ - int i; - bool ok = true; - - if (cpu_count() < 2) { - return; - } - - sti(); - handle_irq(2, multiple_nmi_handler); - handle_irq(0x44, flush_nmi); - on_cpu_async(1, kick_me_nmi, 0); - for (i = 0; i < 1000000; ++i) { - nmi_flushed = false; - nmi_received = 0; - ++cpu0_nmi_ctr1; - while (cpu1_nmi_ctr1 != cpu0_nmi_ctr1) { - pause(); - } - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[0]); - while (!nmi_flushed) { - pause(); - } - if (nmi_received != 2) { - ok = false; - break; - } - ++cpu0_nmi_ctr2; - while (cpu1_nmi_ctr2 != cpu0_nmi_ctr2) { - pause(); - } - } - nmi_done = true; - report(ok, "multiple nmi"); -} - -static void pending_nmi_handler(isr_regs_t *regs) -{ - int i; - - if (++nmi_received == 1) { - for (i = 0; i < 10; ++i) - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI, 0); - } -} - -static void test_pending_nmi(void) -{ - int i; - - handle_irq(2, pending_nmi_handler); - for (i = 0; i < 100000; ++i) { - nmi_received = 0; - - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI, 0); - while (nmi_received < 2) - pause(); - - if (nmi_received != 2) - break; - } - report(nmi_received == 2, "pending nmi"); -} - -static volatile int lvtt_counter = 0; - -static void lvtt_handler(isr_regs_t *regs) -{ - lvtt_counter++; - eoi(); -} - -static void test_apic_timer_one_shot(void) -{ - uint64_t tsc1, tsc2; - static const uint32_t interval = 0x10000; - -#define APIC_LVT_TIMER_VECTOR (0xee) - - handle_irq(APIC_LVT_TIMER_VECTOR, lvtt_handler); - irq_enable(); - - /* One shot mode */ - apic_write(APIC_LVTT, APIC_LVT_TIMER_ONESHOT | - APIC_LVT_TIMER_VECTOR); - /* Divider == 1 */ - apic_write(APIC_TDCR, 0x0000000b); - - tsc1 = rdtsc(); - /* Set "Initial Counter Register", which starts the timer */ - apic_write(APIC_TMICT, interval); - while (!lvtt_counter); - tsc2 = rdtsc(); - - /* - * For LVT Timer clock, SDM vol 3 10.5.4 says it should be - * derived from processor's bus clock (IIUC which is the same - * as TSC), however QEMU seems to be using nanosecond. In all - * cases, the following should satisfy on all modern - * processors. - */ - report((lvtt_counter == 1) && (tsc2 - tsc1 >= interval), - "APIC LVT timer one shot"); -} - -static atomic_t broadcast_counter; - -static void broadcast_handler(isr_regs_t *regs) -{ - atomic_inc(&broadcast_counter); - eoi(); -} - -static bool broadcast_received(unsigned ncpus) -{ - unsigned counter; - u64 start = rdtsc(); - - do { - counter = atomic_read(&broadcast_counter); - if (counter >= ncpus) - break; - pause(); - } while (rdtsc() - start < 1000000000); - - atomic_set(&broadcast_counter, 0); - - return counter == ncpus; -} - -static void test_physical_broadcast(void) -{ - unsigned ncpus = cpu_count(); - unsigned long cr3 = read_cr3(); - u32 broadcast_address = enable_x2apic() ? 0xffffffff : 0xff; - - handle_irq(BROADCAST_VECTOR, broadcast_handler); - for (int c = 1; c < ncpus; c++) - on_cpu(c, update_cr3, (void *)cr3); - - printf("starting broadcast (%s)\n", enable_x2apic() ? "x2apic" : "xapic"); - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT | - BROADCAST_VECTOR, broadcast_address); - report(broadcast_received(ncpus), "APIC physical broadcast address"); - - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT | - BROADCAST_VECTOR | APIC_DEST_ALLINC, 0); - report(broadcast_received(ncpus), "APIC physical broadcast shorthand"); -} - -static void wait_until_tmcct_common(uint32_t initial_count, bool stop_when_half, bool should_wrap_around) -{ - uint32_t tmcct = apic_read(APIC_TMCCT); - - if (tmcct) { - while (tmcct > (initial_count / 2)) - tmcct = apic_read(APIC_TMCCT); - - if ( stop_when_half ) - return; - - /* Wait until the counter reach 0 or wrap-around */ - while ( tmcct <= (initial_count / 2) && tmcct > 0 ) - tmcct = apic_read(APIC_TMCCT); - - /* Wait specifically for wrap around to skip 0 TMCCR if we were asked to */ - while (should_wrap_around && !tmcct) - tmcct = apic_read(APIC_TMCCT); - } -} - -static void wait_until_tmcct_is_zero(uint32_t initial_count, bool stop_when_half) -{ - return wait_until_tmcct_common(initial_count, stop_when_half, false); -} - -static void wait_until_tmcct_wrap_around(uint32_t initial_count, bool stop_when_half) -{ - return wait_until_tmcct_common(initial_count, stop_when_half, true); -} - -static inline void apic_change_mode(unsigned long new_mode) -{ - uint32_t lvtt; - - lvtt = apic_read(APIC_LVTT); - apic_write(APIC_LVTT, (lvtt & ~APIC_LVT_TIMER_MASK) | new_mode); -} - -static void test_apic_change_mode(void) -{ - uint32_t tmict = 0x999999; - - printf("starting apic change mode\n"); - - apic_write(APIC_TMICT, tmict); - - apic_change_mode(APIC_LVT_TIMER_PERIODIC); - - report(apic_read(APIC_TMICT) == tmict, "TMICT value reset"); - - /* Testing one-shot */ - apic_change_mode(APIC_LVT_TIMER_ONESHOT); - apic_write(APIC_TMICT, tmict); - report(apic_read(APIC_TMCCT), "TMCCT should have a non-zero value"); - - wait_until_tmcct_is_zero(tmict, false); - report(!apic_read(APIC_TMCCT), "TMCCT should have reached 0"); - - /* - * Write TMICT before changing mode from one-shot to periodic TMCCT should - * be reset to TMICT periodicly - */ - apic_write(APIC_TMICT, tmict); - wait_until_tmcct_is_zero(tmict, true); - apic_change_mode(APIC_LVT_TIMER_PERIODIC); - report(apic_read(APIC_TMCCT), "TMCCT should have a non-zero value"); - - /* - * After the change of mode, the counter should not be reset and continue - * counting down from where it was - */ - report(apic_read(APIC_TMCCT) < (tmict / 2), - "TMCCT should not be reset to TMICT value"); - /* - * Specifically wait for timer wrap around and skip 0. - * Under KVM lapic there is a possibility that a small amount of consecutive - * TMCCR reads return 0 while hrtimer is reset in an async callback - */ - wait_until_tmcct_wrap_around(tmict, false); - report(apic_read(APIC_TMCCT) > (tmict / 2), - "TMCCT should be reset to the initial-count"); - - wait_until_tmcct_is_zero(tmict, true); - /* - * Keep the same TMICT and change timer mode to one-shot - * TMCCT should be > 0 and count-down to 0 - */ - apic_change_mode(APIC_LVT_TIMER_ONESHOT); - report(apic_read(APIC_TMCCT) < (tmict / 2), - "TMCCT should not be reset to init"); - wait_until_tmcct_is_zero(tmict, false); - report(!apic_read(APIC_TMCCT), "TMCCT should have reach zero"); - - /* now tmcct == 0 and tmict != 0 */ - apic_change_mode(APIC_LVT_TIMER_PERIODIC); - report(!apic_read(APIC_TMCCT), "TMCCT should stay at zero"); -} - -#define KVM_HC_SEND_IPI 10 - -static void test_pv_ipi(void) -{ - int ret; - unsigned long a0 = 0xFFFFFFFF, a1 = 0, a2 = 0xFFFFFFFF, a3 = 0x0; - - asm volatile("vmcall" : "=a"(ret) :"a"(KVM_HC_SEND_IPI), "b"(a0), "c"(a1), "d"(a2), "S"(a3)); - report(!ret, "PV IPIs testing"); -} - -int main(void) -{ - setup_vm(); - - test_lapic_existence(); - - mask_pic_interrupts(); - test_apic_id(); - test_apic_disable(); - test_enable_x2apic(); - test_apicbase(); - - test_self_ipi(); - test_physical_broadcast(); - if (test_device_enabled()) - test_pv_ipi(); - - test_sti_nmi(); - test_multiple_nmi(); - test_pending_nmi(); - - test_apic_timer_one_shot(); - test_apic_change_mode(); - test_tsc_deadline_timer(); - - return report_summary(); -} diff --git a/x86/asyncpf.c b/x86/asyncpf.c deleted file mode 100644 index 305a923b..00000000 --- a/x86/asyncpf.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Async PF test. For the test to actually do anything it needs to be started - * in memory cgroup with 512M of memory and with more then 1G memory provided - * to the guest. - * - * To create cgroup do as root: - * mkdir /dev/cgroup - * mount -t cgroup none -omemory /dev/cgroup - * chmod a+rxw /dev/cgroup/ - * - * From a shell you will start qemu from: - * mkdir /dev/cgroup/1 - * echo $$ > /dev/cgroup/1/tasks - * echo 512M > /dev/cgroup/1/memory.limit_in_bytes - * - */ -#include "x86/msr.h" -#include "x86/processor.h" -#include "x86/apic-defs.h" -#include "x86/apic.h" -#include "x86/desc.h" -#include "x86/isr.h" -#include "x86/vm.h" - -#include "asm/page.h" -#include "alloc.h" -#include "libcflat.h" -#include "vmalloc.h" -#include - -#define KVM_PV_REASON_PAGE_NOT_PRESENT 1 -#define KVM_PV_REASON_PAGE_READY 2 - -#define MSR_KVM_ASYNC_PF_EN 0x4b564d02 - -#define KVM_ASYNC_PF_ENABLED (1 << 0) -#define KVM_ASYNC_PF_SEND_ALWAYS (1 << 1) - -volatile uint32_t apf_reason __attribute__((aligned(64))); -char *buf; -volatile uint64_t i; -volatile uint64_t phys; - -static inline uint32_t get_apf_reason(void) -{ - uint32_t r = apf_reason; - apf_reason = 0; - return r; -} - -static void pf_isr(struct ex_regs *r) -{ - void* virt = (void*)((ulong)(buf+i) & ~(PAGE_SIZE-1)); - uint32_t reason = get_apf_reason(); - - switch (reason) { - case 0: - report(false, "unexpected #PF at %#lx", read_cr2()); - break; - case KVM_PV_REASON_PAGE_NOT_PRESENT: - phys = virt_to_pte_phys(phys_to_virt(read_cr3()), virt); - install_pte(phys_to_virt(read_cr3()), 1, virt, phys, 0); - write_cr3(read_cr3()); - report(true, - "Got not present #PF token %lx virt addr %p phys addr %#" PRIx64, - read_cr2(), virt, phys); - while(phys) { - safe_halt(); /* enables irq */ - irq_disable(); - } - break; - case KVM_PV_REASON_PAGE_READY: - report(true, "Got present #PF token %lx", read_cr2()); - if ((uint32_t)read_cr2() == ~0) - break; - install_pte(phys_to_virt(read_cr3()), 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK, 0); - write_cr3(read_cr3()); - phys = 0; - break; - default: - report(false, "unexpected async pf reason %d", reason); - break; - } -} - -#define MEM 1ull*1024*1024*1024 - -int main(int ac, char **av) -{ - int loop = 2; - - setup_vm(); - printf("install handler\n"); - handle_exception(14, pf_isr); - apf_reason = 0; - printf("enable async pf\n"); - wrmsr(MSR_KVM_ASYNC_PF_EN, virt_to_phys((void*)&apf_reason) | - KVM_ASYNC_PF_SEND_ALWAYS | KVM_ASYNC_PF_ENABLED); - printf("alloc memory\n"); - buf = malloc(MEM); - irq_enable(); - while(loop--) { - printf("start loop\n"); - /* access a lot of memory to make host swap it out */ - for (i=0; i < MEM; i+=4096) - buf[i] = 1; - printf("end loop\n"); - } - irq_disable(); - - return report_summary(); -} diff --git a/x86/cmpxchg8b.c b/x86/cmpxchg8b.c deleted file mode 100644 index a416f44f..00000000 --- a/x86/cmpxchg8b.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "ioram.h" -#include "vm.h" -#include "libcflat.h" -#include "desc.h" -#include "types.h" -#include "processor.h" - -static void test_cmpxchg8b(u32 *mem) -{ - mem[1] = 2; - mem[0] = 1; - asm("push %%ebx\n" - "mov %[ebx_val], %%ebx\n" - "lock cmpxchg8b (%0)\n" - "pop %%ebx" : : "D" (mem), - "d" (2), "a" (1), "c" (4), [ebx_val] "i" (3) : "memory"); - report(mem[0] == 3 && mem[1] == 4, "cmpxchg8b"); -} - -int main(void) -{ - setup_vm(); - - test_cmpxchg8b(phys_to_virt(read_cr3()) + 4088); - return report_summary(); -} diff --git a/x86/cstart.S b/x86/cstart.S deleted file mode 100644 index e63e4e2b..00000000 --- a/x86/cstart.S +++ /dev/null @@ -1,236 +0,0 @@ - -#include "apic-defs.h" - -.globl boot_idt -.global online_cpus - -ipi_vector = 0x20 - -max_cpus = MAX_TEST_CPUS - -.bss - - . = . + 4096 * max_cpus - .align 16 -stacktop: - - . = . + 4096 - .align 16 -ring0stacktop: - -.data - -.align 4096 -pt: -i = 0 - .rept 1024 - .long 0x1e7 | (i << 22) - i = i + 1 - .endr - -boot_idt: - .rept 256 - .quad 0 - .endr -end_boot_idt: - -.globl gdt32 -gdt32: - .quad 0 - .quad 0x00cf9b000000ffff // flat 32-bit code segment - .quad 0x00cf93000000ffff // flat 32-bit data segment - .quad 0x00cf1b000000ffff // flat 32-bit code segment, not present - .quad 0 // TSS for task gates - .quad 0x008f9b000000FFFF // 16-bit code segment - .quad 0x008f93000000FFFF // 16-bit data segment - .quad 0x00cffb000000ffff // 32-bit code segment (user) - .quad 0x00cff3000000ffff // 32-bit data segment (user) - .quad 0 // unused - - .quad 0 // 6 spare selectors - .quad 0 - .quad 0 - .quad 0 - .quad 0 - .quad 0 - -tss_descr: - .rept max_cpus - .quad 0x000089000000ffff // 32-bit avail tss - .endr -gdt32_end: - -i = 0 -.globl tss -tss: - .rept max_cpus - .long 0 - .long ring0stacktop - i * 4096 - .long 16 - .quad 0, 0 - .quad 0, 0, 0, 0, 0, 0, 0, 0 - .long 0, 0, 0 - i = i + 1 - .endr -tss_end: - -idt_descr: - .word end_boot_idt - boot_idt - 1 - .long boot_idt - -.section .init - -.code32 - -mb_magic = 0x1BADB002 -mb_flags = 0x0 - - # multiboot header - .long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) -mb_cmdline = 16 - -MSR_GS_BASE = 0xc0000101 - -.macro setup_percpu_area - lea -4096(%esp), %eax - mov $0, %edx - mov $MSR_GS_BASE, %ecx - wrmsr -.endm - -.macro setup_segments - mov $0x10, %ax - mov %ax, %ds - mov %ax, %es - mov %ax, %fs - mov %ax, %gs - mov %ax, %ss -.endm - -.globl start -start: - lgdtl gdt32_descr - setup_segments - mov $stacktop, %esp - setup_percpu_area - - push %ebx - call setup_multiboot - addl $4, %esp - call setup_libcflat - mov mb_cmdline(%ebx), %eax - mov %eax, __args - call __setup_args - call prepare_32 - jmpl $8, $start32 - -prepare_32: - mov %(1 << 4), %eax // pse - mov %eax, %cr4 - - mov $pt, %eax - mov %eax, %cr3 - - mov %cr0, %eax - bts $0, %eax - bts $31, %eax - mov %eax, %cr0 - ret - -smp_stacktop: .long stacktop - 4096 - -save_id: - movl $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax - movl (%eax), %eax - shrl $24, %eax - lock btsl %eax, online_cpus - retl - -ap_start32: - setup_segments - mov $-4096, %esp - lock/xaddl %esp, smp_stacktop - setup_percpu_area - call prepare_32 - call reset_apic - call save_id - call load_tss - call enable_apic - call enable_x2apic - sti - nop - lock incw cpu_online_count - -1: hlt - jmp 1b - -start32: - call reset_apic - call save_id - call load_tss - call mask_pic_interrupts - call enable_apic - call ap_init - call enable_x2apic - call smp_init - push $__environ - push $__argv - push __argc - call main - push %eax - call exit - -load_tss: - lidt idt_descr - mov $16, %eax - mov %ax, %ss - mov $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax - mov (%eax), %eax - shr $24, %eax - mov %eax, %ebx - shl $3, %ebx - mov $((tss_end - tss) / max_cpus), %edx - imul %edx - add $tss, %eax - mov %ax, tss_descr+2(%ebx) - shr $16, %eax - mov %al, tss_descr+4(%ebx) - shr $8, %eax - mov %al, tss_descr+7(%ebx) - lea tss_descr-gdt32(%ebx), %eax - ltr %ax - ret - -ap_init: - cld - lea sipi_entry, %esi - xor %edi, %edi - mov $(sipi_end - sipi_entry), %ecx - rep/movsb - mov $APIC_DEFAULT_PHYS_BASE, %eax - movl $(APIC_DEST_ALLBUT | APIC_DEST_PHYSICAL | APIC_DM_INIT | APIC_INT_ASSERT), APIC_ICR(%eax) - movl $(APIC_DEST_ALLBUT | APIC_DEST_PHYSICAL | APIC_DM_STARTUP), APIC_ICR(%eax) - call fwcfg_get_nb_cpus -1: pause - cmpw %ax, cpu_online_count - jne 1b - ret - -online_cpus: - .fill (max_cpus + 7) / 8, 1, 0 - -cpu_online_count: .word 1 - -.code16 -sipi_entry: - mov %cr0, %eax - or $1, %eax - mov %eax, %cr0 - lgdtl gdt32_descr - sipi_entry - ljmpl $8, $ap_start32 - -gdt32_descr: - .word gdt32_end - gdt32 - 1 - .long gdt32 - -sipi_end: diff --git a/x86/cstart64.S b/x86/cstart64.S deleted file mode 100644 index 3ae98d3d..00000000 --- a/x86/cstart64.S +++ /dev/null @@ -1,332 +0,0 @@ - -#include "apic-defs.h" - -.globl boot_idt - -.globl idt_descr -.globl tss_descr -.globl gdt64_desc -.globl online_cpus - -ipi_vector = 0x20 - -max_cpus = MAX_TEST_CPUS - -.bss - - . = . + 4096 * max_cpus - .align 16 -stacktop: - - . = . + 4096 * max_cpus - .align 16 -ring0stacktop: - -.data - -.align 4096 -.globl ptl2 -ptl2: -i = 0 - .rept 512 * 4 - .quad 0x1e7 | (i << 21) - i = i + 1 - .endr - -.align 4096 -ptl3: - .quad ptl2 + 7 + 0 * 4096 - .quad ptl2 + 7 + 1 * 4096 - .quad ptl2 + 7 + 2 * 4096 - .quad ptl2 + 7 + 3 * 4096 - -.align 4096 -ptl4: - .quad ptl3 + 7 - -.align 4096 -ptl5: - .quad ptl4 + 7 - -.align 4096 - -boot_idt: - .rept 256 - .quad 0 - .quad 0 - .endr -end_boot_idt: - -gdt64_desc: - .word gdt64_end - gdt64 - 1 - .quad gdt64 - -gdt64: - .quad 0 - .quad 0x00af9b000000ffff // 64-bit code segment - .quad 0x00cf93000000ffff // 32/64-bit data segment - .quad 0x00af1b000000ffff // 64-bit code segment, not present - .quad 0x00cf9b000000ffff // 32-bit code segment - .quad 0x008f9b000000FFFF // 16-bit code segment - .quad 0x008f93000000FFFF // 16-bit data segment - .quad 0x00cffb000000ffff // 32-bit code segment (user) - .quad 0x00cff3000000ffff // 32/64-bit data segment (user) - .quad 0x00affb000000ffff // 64-bit code segment (user) - - .quad 0 // 6 spare selectors - .quad 0 - .quad 0 - .quad 0 - .quad 0 - .quad 0 - -tss_descr: - .rept max_cpus - .quad 0x000089000000ffff // 64-bit avail tss - .quad 0 // tss high addr - .endr -gdt64_end: - -i = 0 -.globl tss -tss: - .rept max_cpus - .long 0 - .quad ring0stacktop - i * 4096 - .quad 0, 0 - .quad 0, 0, 0, 0, 0, 0, 0, 0 - .long 0, 0, 0 -i = i + 1 - .endr -tss_end: - -mb_boot_info: .quad 0 - -pt_root: .quad ptl4 - -.section .init - -.code32 - -mb_magic = 0x1BADB002 -mb_flags = 0x0 - - # multiboot header - .long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) -mb_cmdline = 16 - -MSR_GS_BASE = 0xc0000101 - -.macro setup_percpu_area - lea -4096(%esp), %eax - mov $0, %edx - mov $MSR_GS_BASE, %ecx - wrmsr -.endm - -.macro setup_segments - mov $MSR_GS_BASE, %ecx - rdmsr - - mov $0x10, %bx - mov %bx, %ds - mov %bx, %es - mov %bx, %fs - mov %bx, %gs - mov %bx, %ss - - /* restore MSR_GS_BASE */ - wrmsr -.endm - -.globl start -start: - mov %ebx, mb_boot_info - mov $stacktop, %esp - setup_percpu_area - call prepare_64 - jmpl $8, $start64 - -switch_to_5level: - /* Disable CR4.PCIDE */ - mov %cr4, %eax - btr $17, %eax - mov %eax, %cr4 - - mov %cr0, %eax - btr $31, %eax - mov %eax, %cr0 - - mov $ptl5, %eax - mov %eax, pt_root - - /* Enable CR4.LA57 */ - mov %cr4, %eax - bts $12, %eax - mov %eax, %cr4 - - mov $0x10, %ax - mov %ax, %ss - - call enter_long_mode - jmpl $8, $lvl5 - -prepare_64: - lgdt gdt64_desc - setup_segments - -enter_long_mode: - mov $(1 << 5), %eax // pae - mov %eax, %cr4 - - mov pt_root, %eax - mov %eax, %cr3 - -efer = 0xc0000080 - mov $efer, %ecx - rdmsr - bts $8, %eax - wrmsr - - mov %cr0, %eax - bts $0, %eax - bts $31, %eax - mov %eax, %cr0 - ret - -smp_stacktop: .long stacktop - 4096 - -.align 16 - -gdt32: - .quad 0 - .quad 0x00cf9b000000ffff // flat 32-bit code segment - .quad 0x00cf93000000ffff // flat 32-bit data segment -gdt32_end: - -.code16 -sipi_entry: - mov %cr0, %eax - or $1, %eax - mov %eax, %cr0 - lgdtl gdt32_descr - sipi_entry - ljmpl $8, $ap_start32 - -gdt32_descr: - .word gdt32_end - gdt32 - 1 - .long gdt32 - -sipi_end: - -.code32 -ap_start32: - setup_segments - mov $-4096, %esp - lock/xaddl %esp, smp_stacktop - setup_percpu_area - call prepare_64 - ljmpl $8, $ap_start64 - -.code64 -save_id: - movl $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax - movl (%rax), %eax - shrl $24, %eax - lock btsl %eax, online_cpus - retq - -ap_start64: - call reset_apic - call load_tss - call enable_apic - call save_id - call enable_x2apic - sti - nop - lock incw cpu_online_count - -1: hlt - jmp 1b - -start64: - call reset_apic - call load_tss - call mask_pic_interrupts - call enable_apic - call save_id - mov mb_boot_info(%rip), %rbx - mov %rbx, %rdi - call setup_multiboot - call setup_libcflat - mov mb_cmdline(%rbx), %eax - mov %rax, __args(%rip) - call __setup_args - - call ap_init - call enable_x2apic - call smp_init - - mov __argc(%rip), %edi - lea __argv(%rip), %rsi - lea __environ(%rip), %rdx - call main - mov %eax, %edi - call exit - -.globl setup_5level_page_table -setup_5level_page_table: - /* Check if 5-level paging has already enabled */ - mov %cr4, %rax - test $0x1000, %eax - jnz lvl5 - - pushq $32 - pushq $switch_to_5level - lretq -lvl5: - retq - -idt_descr: - .word end_boot_idt - boot_idt - 1 - .quad boot_idt - -online_cpus: - .fill (max_cpus + 7) / 8, 1, 0 - -load_tss: - lidtq idt_descr - mov $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax - mov (%rax), %eax - shr $24, %eax - mov %eax, %ebx - shl $4, %ebx - mov $((tss_end - tss) / max_cpus), %edx - imul %edx - add $tss, %rax - mov %ax, tss_descr+2(%rbx) - shr $16, %rax - mov %al, tss_descr+4(%rbx) - shr $8, %rax - mov %al, tss_descr+7(%rbx) - shr $8, %rax - mov %eax, tss_descr+8(%rbx) - lea tss_descr-gdt64(%rbx), %rax - ltr %ax - ret - -ap_init: - cld - lea sipi_entry, %rsi - xor %rdi, %rdi - mov $(sipi_end - sipi_entry), %rcx - rep/movsb - mov $APIC_DEFAULT_PHYS_BASE, %eax - movl $(APIC_DEST_ALLBUT | APIC_DEST_PHYSICAL | APIC_DM_INIT | APIC_INT_ASSERT), APIC_ICR(%rax) - movl $(APIC_DEST_ALLBUT | APIC_DEST_PHYSICAL | APIC_DM_STARTUP), APIC_ICR(%rax) - call fwcfg_get_nb_cpus -1: pause - cmpw %ax, cpu_online_count - jne 1b - ret - -cpu_online_count: .word 1 diff --git a/x86/debug.c b/x86/debug.c deleted file mode 100644 index 9798e625..00000000 --- a/x86/debug.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Test for x86 debugging facilities - * - * Copyright (c) Siemens AG, 2014 - * - * Authors: - * Jan Kiszka - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#include "libcflat.h" -#include "processor.h" -#include "desc.h" - -static volatile unsigned long bp_addr; -static volatile unsigned long db_addr[10], dr6[10]; -static volatile unsigned int n; -static volatile unsigned long value; - -static unsigned long get_dr6(void) -{ - unsigned long value; - - asm volatile("mov %%dr6,%0" : "=r" (value)); - return value; -} - -static void set_dr0(void *value) -{ - asm volatile("mov %0,%%dr0" : : "r" (value)); -} - -static void set_dr1(void *value) -{ - asm volatile("mov %0,%%dr1" : : "r" (value)); -} - -static void set_dr6(unsigned long value) -{ - asm volatile("mov %0,%%dr6" : : "r" (value)); -} - -static void set_dr7(unsigned long value) -{ - asm volatile("mov %0,%%dr7" : : "r" (value)); -} - -static void handle_db(struct ex_regs *regs) -{ - db_addr[n] = regs->rip; - dr6[n] = get_dr6(); - - if (dr6[n] & 0x1) - regs->rflags |= (1 << 16); - - if (++n >= 10) { - regs->rflags &= ~(1 << 8); - set_dr7(0x00000400); - } -} - -extern unsigned char handle_db_save_rip; -asm("handle_db_save_rip:\n" - "stc\n" - "nop;nop;nop\n" - "rclq $1, n(%rip)\n" - "iretq\n"); - -static void handle_bp(struct ex_regs *regs) -{ - bp_addr = regs->rip; -} - -int main(int ac, char **av) -{ - unsigned long start; - - handle_exception(DB_VECTOR, handle_db); - handle_exception(BP_VECTOR, handle_bp); - - extern unsigned char sw_bp; - asm volatile("int3; sw_bp:"); - report(bp_addr == (unsigned long)&sw_bp, "#BP"); - - n = 0; - extern unsigned char hw_bp1; - set_dr0(&hw_bp1); - set_dr7(0x00000402); - asm volatile("hw_bp1: nop"); - report(n == 1 && - db_addr[0] == ((unsigned long)&hw_bp1) && dr6[0] == 0xffff0ff1, - "hw breakpoint (test that dr6.BS is not set)"); - - n = 0; - extern unsigned char hw_bp2; - set_dr0(&hw_bp2); - set_dr6(0x00004002); - asm volatile("hw_bp2: nop"); - report(n == 1 && - db_addr[0] == ((unsigned long)&hw_bp2) && dr6[0] == 0xffff4ff1, - "hw breakpoint (test that dr6.BS is not cleared)"); - - n = 0; - set_dr6(0); - asm volatile( - "pushf\n\t" - "pop %%rax\n\t" - "or $(1<<8),%%rax\n\t" - "push %%rax\n\t" - "lea (%%rip),%0\n\t" - "popf\n\t" - "and $~(1<<8),%%rax\n\t" - "push %%rax\n\t" - "popf\n\t" - : "=r" (start) : : "rax"); - report(n == 3 && - db_addr[0] == start + 1 + 6 && dr6[0] == 0xffff4ff0 && - db_addr[1] == start + 1 + 6 + 1 && dr6[1] == 0xffff4ff0 && - db_addr[2] == start + 1 + 6 + 1 + 1 && dr6[2] == 0xffff4ff0, - "single step"); - - /* - * cpuid and rdmsr (among others) trigger VM exits and are then - * emulated. Test that single stepping works on emulated instructions. - */ - n = 0; - set_dr6(0); - asm volatile( - "pushf\n\t" - "pop %%rax\n\t" - "or $(1<<8),%%rax\n\t" - "push %%rax\n\t" - "lea (%%rip),%0\n\t" - "popf\n\t" - "and $~(1<<8),%%rax\n\t" - "push %%rax\n\t" - "xor %%rax,%%rax\n\t" - "cpuid\n\t" - "movl $0x1a0,%%ecx\n\t" - "rdmsr\n\t" - "popf\n\t" - : "=r" (start) : : "rax", "ebx", "ecx", "edx"); - report(n == 7 && - db_addr[0] == start + 1 + 6 && dr6[0] == 0xffff4ff0 && - db_addr[1] == start + 1 + 6 + 1 && dr6[1] == 0xffff4ff0 && - db_addr[2] == start + 1 + 6 + 1 + 3 && dr6[2] == 0xffff4ff0 && - db_addr[3] == start + 1 + 6 + 1 + 3 + 2 && dr6[3] == 0xffff4ff0 && - db_addr[4] == start + 1 + 6 + 1 + 3 + 2 + 5 && dr6[4] == 0xffff4ff0 && - db_addr[5] == start + 1 + 6 + 1 + 3 + 2 + 5 + 2 && dr6[5] == 0xffff4ff0 && - db_addr[6] == start + 1 + 6 + 1 + 3 + 2 + 5 + 2 + 1 && dr6[6] == 0xffff4ff0, - "single step emulated instructions"); - - n = 0; - set_dr1((void *)&value); - set_dr7(0x00d0040a); // 4-byte write - - extern unsigned char hw_wp1; - asm volatile( - "mov $42,%%rax\n\t" - "mov %%rax,%0\n\t; hw_wp1:" - : "=m" (value) : : "rax"); - report(n == 1 && - db_addr[0] == ((unsigned long)&hw_wp1) && dr6[0] == 0xffff4ff2, - "hw watchpoint (test that dr6.BS is not cleared)"); - - n = 0; - set_dr6(0); - - extern unsigned char hw_wp2; - asm volatile( - "mov $42,%%rax\n\t" - "mov %%rax,%0\n\t; hw_wp2:" - : "=m" (value) : : "rax"); - report(n == 1 && - db_addr[0] == ((unsigned long)&hw_wp2) && dr6[0] == 0xffff0ff2, - "hw watchpoint (test that dr6.BS is not set)"); - - n = 0; - set_dr6(0); - extern unsigned char sw_icebp; - asm volatile(".byte 0xf1; sw_icebp:"); - report(n == 1 && - db_addr[0] == (unsigned long)&sw_icebp && dr6[0] == 0xffff0ff0, - "icebp"); - - set_dr7(0x400); - value = KERNEL_DS; - set_dr7(0x00f0040a); // 4-byte read or write - - /* - * Each invocation of the handler should shift n by 1 and set bit 0 to 1. - * We expect a single invocation, so n should become 3. If the entry - * RIP is wrong, or if the handler is executed more than once, the value - * will not match. - */ - set_idt_entry(1, &handle_db_save_rip, 0); - - n = 1; - asm volatile( - "clc\n\t" - "mov %0,%%ss\n\t" - ".byte 0x2e, 0x2e, 0xf1" - : "=m" (value) : : "rax"); - report(n == 3, "MOV SS + watchpoint + ICEBP"); - - /* - * Here the #DB handler is invoked twice, once as a software exception - * and once as a software interrupt. - */ - n = 1; - asm volatile( - "clc\n\t" - "mov %0,%%ss\n\t" - "int $1" - : "=m" (value) : : "rax"); - report(n == 7, "MOV SS + watchpoint + int $1"); - - /* - * Here the #DB and #BP handlers are invoked once each. - */ - n = 1; - bp_addr = 0; - asm volatile( - "mov %0,%%ss\n\t" - ".byte 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0xcc\n\t" - "sw_bp2:" - : "=m" (value) : : "rax"); - extern unsigned char sw_bp2; - report(n == 3 && bp_addr == (unsigned long)&sw_bp2, - "MOV SS + watchpoint + INT3"); - return report_summary(); -} diff --git a/x86/emulator.c b/x86/emulator.c deleted file mode 100644 index 98743d15..00000000 --- a/x86/emulator.c +++ /dev/null @@ -1,1101 +0,0 @@ -#include "ioram.h" -#include "vm.h" -#include "libcflat.h" -#include "desc.h" -#include "types.h" -#include "processor.h" -#include "vmalloc.h" -#include "alloc_page.h" - -#define memset __builtin_memset -#define TESTDEV_IO_PORT 0xe0 - -static int exceptions; - -/* Forced emulation prefix, used to invoke the emulator unconditionally. */ -#define KVM_FEP "ud2; .byte 'k', 'v', 'm';" -#define KVM_FEP_LENGTH 5 -static int fep_available = 1; - -struct regs { - u64 rax, rbx, rcx, rdx; - u64 rsi, rdi, rsp, rbp; - u64 r8, r9, r10, r11; - u64 r12, r13, r14, r15; - u64 rip, rflags; -}; -struct regs inregs, outregs, save; - -struct insn_desc { - u64 ptr; - size_t len; -}; - -static char st1[] = "abcdefghijklmnop"; - -static void test_stringio(void) -{ - unsigned char r = 0; - asm volatile("cld \n\t" - "movw %0, %%dx \n\t" - "rep outsb \n\t" - : : "i"((short)TESTDEV_IO_PORT), - "S"(st1), "c"(sizeof(st1) - 1)); - asm volatile("inb %1, %0\n\t" : "=a"(r) : "i"((short)TESTDEV_IO_PORT)); - report(r == st1[sizeof(st1) - 2], "outsb up"); /* last char */ - - asm volatile("std \n\t" - "movw %0, %%dx \n\t" - "rep outsb \n\t" - : : "i"((short)TESTDEV_IO_PORT), - "S"(st1 + sizeof(st1) - 2), "c"(sizeof(st1) - 1)); - asm volatile("cld \n\t" : : ); - asm volatile("in %1, %0\n\t" : "=a"(r) : "i"((short)TESTDEV_IO_PORT)); - report(r == st1[0], "outsb down"); -} - -static void test_cmps_one(unsigned char *m1, unsigned char *m3) -{ - void *rsi, *rdi; - long rcx, tmp; - - rsi = m1; rdi = m3; rcx = 30; - asm volatile("xor %[tmp], %[tmp] \n\t" - "repe/cmpsb" - : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) - : : "cc"); - report(rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30, "repe/cmpsb (1)"); - - rsi = m1; rdi = m3; rcx = 30; - asm volatile("or $1, %[tmp]\n\t" // clear ZF - "repe/cmpsb" - : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) - : : "cc"); - report(rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30, - "repe/cmpsb (1.zf)"); - - rsi = m1; rdi = m3; rcx = 15; - asm volatile("xor %[tmp], %[tmp] \n\t" - "repe/cmpsw" - : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) - : : "cc"); - report(rcx == 0 && rsi == m1 + 30 && rdi == m3 + 30, "repe/cmpsw (1)"); - - rsi = m1; rdi = m3; rcx = 7; - asm volatile("xor %[tmp], %[tmp] \n\t" - "repe/cmpsl" - : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) - : : "cc"); - report(rcx == 0 && rsi == m1 + 28 && rdi == m3 + 28, "repe/cmpll (1)"); - - rsi = m1; rdi = m3; rcx = 4; - asm volatile("xor %[tmp], %[tmp] \n\t" - "repe/cmpsq" - : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) - : : "cc"); - report(rcx == 0 && rsi == m1 + 32 && rdi == m3 + 32, "repe/cmpsq (1)"); - - rsi = m1; rdi = m3; rcx = 130; - asm volatile("xor %[tmp], %[tmp] \n\t" - "repe/cmpsb" - : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) - : : "cc"); - report(rcx == 29 && rsi == m1 + 101 && rdi == m3 + 101, - "repe/cmpsb (2)"); - - rsi = m1; rdi = m3; rcx = 65; - asm volatile("xor %[tmp], %[tmp] \n\t" - "repe/cmpsw" - : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) - : : "cc"); - report(rcx == 14 && rsi == m1 + 102 && rdi == m3 + 102, - "repe/cmpsw (2)"); - - rsi = m1; rdi = m3; rcx = 32; - asm volatile("xor %[tmp], %[tmp] \n\t" - "repe/cmpsl" - : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) - : : "cc"); - report(rcx == 6 && rsi == m1 + 104 && rdi == m3 + 104, - "repe/cmpll (2)"); - - rsi = m1; rdi = m3; rcx = 16; - asm volatile("xor %[tmp], %[tmp] \n\t" - "repe/cmpsq" - : "+S"(rsi), "+D"(rdi), "+c"(rcx), [tmp]"=&r"(tmp) - : : "cc"); - report(rcx == 3 && rsi == m1 + 104 && rdi == m3 + 104, - "repe/cmpsq (2)"); - -} - -static void test_cmps(void *mem) -{ - unsigned char *m1 = mem, *m2 = mem + 1024; - unsigned char m3[1024]; - - for (int i = 0; i < 100; ++i) - m1[i] = m2[i] = m3[i] = i; - for (int i = 100; i < 200; ++i) - m1[i] = (m3[i] = m2[i] = i) + 1; - test_cmps_one(m1, m3); - test_cmps_one(m1, m2); -} - -static void test_scas(void *mem) -{ - bool z; - void *di; - - *(ulong *)mem = 0x77665544332211; - - di = mem; - asm ("scasb; setz %0" : "=rm"(z), "+D"(di) : "a"(0xff11)); - report(di == mem + 1 && z, "scasb match"); - - di = mem; - asm ("scasb; setz %0" : "=rm"(z), "+D"(di) : "a"(0xff54)); - report(di == mem + 1 && !z, "scasb mismatch"); - - di = mem; - asm ("scasw; setz %0" : "=rm"(z), "+D"(di) : "a"(0xff2211)); - report(di == mem + 2 && z, "scasw match"); - - di = mem; - asm ("scasw; setz %0" : "=rm"(z), "+D"(di) : "a"(0xffdd11)); - report(di == mem + 2 && !z, "scasw mismatch"); - - di = mem; - asm ("scasl; setz %0" : "=rm"(z), "+D"(di) : "a"(0xff44332211ul)); - report(di == mem + 4 && z, "scasd match"); - - di = mem; - asm ("scasl; setz %0" : "=rm"(z), "+D"(di) : "a"(0x45332211)); - report(di == mem + 4 && !z, "scasd mismatch"); - - di = mem; - asm ("scasq; setz %0" : "=rm"(z), "+D"(di) : "a"(0x77665544332211ul)); - report(di == mem + 8 && z, "scasq match"); - - di = mem; - asm ("scasq; setz %0" : "=rm"(z), "+D"(di) : "a"(3)); - report(di == mem + 8 && !z, "scasq mismatch"); -} - -static void test_cr8(void) -{ - unsigned long src, dst; - - dst = 777; - src = 3; - asm volatile("mov %[src], %%cr8; mov %%cr8, %[dst]" - : [dst]"+r"(dst), [src]"+r"(src)); - report(dst == 3 && src == 3, "mov %%cr8"); -} - -static void test_push(void *mem) -{ - unsigned long tmp; - unsigned long *stack_top = mem + 4096; - unsigned long *new_stack_top; - unsigned long memw = 0x123456789abcdeful; - - memset(mem, 0x55, (void *)stack_top - mem); - - asm volatile("mov %%rsp, %[tmp] \n\t" - "mov %[stack_top], %%rsp \n\t" - "pushq $-7 \n\t" - "pushq %[reg] \n\t" - "pushq (%[mem]) \n\t" - "pushq $-7070707 \n\t" - "mov %%rsp, %[new_stack_top] \n\t" - "mov %[tmp], %%rsp" - : [tmp]"=&r"(tmp), [new_stack_top]"=r"(new_stack_top) - : [stack_top]"r"(stack_top), - [reg]"r"(-17l), [mem]"r"(&memw) - : "memory"); - - report(stack_top[-1] == -7ul, "push $imm8"); - report(stack_top[-2] == -17ul, "push %%reg"); - report(stack_top[-3] == 0x123456789abcdeful, "push mem"); - report(stack_top[-4] == -7070707, "push $imm"); -} - -static void test_pop(void *mem) -{ - unsigned long tmp, tmp3, rsp, rbp; - unsigned long *stack_top = mem + 4096; - unsigned long memw = 0x123456789abcdeful; - static unsigned long tmp2; - - memset(mem, 0x55, (void *)stack_top - mem); - - asm volatile("pushq %[val] \n\t" - "popq (%[mem])" - : : [val]"m"(memw), [mem]"r"(mem) : "memory"); - report(*(unsigned long *)mem == memw, "pop mem"); - - memw = 7 - memw; - asm volatile("mov %%rsp, %[tmp] \n\t" - "mov %[stack_top], %%rsp \n\t" - "pushq %[val] \n\t" - "popq %[tmp2] \n\t" - "mov %[tmp], %%rsp" - : [tmp]"=&r"(tmp), [tmp2]"=m"(tmp2) - : [val]"r"(memw), [stack_top]"r"(stack_top) - : "memory"); - report(tmp2 == memw, "pop mem (2)"); - - memw = 129443 - memw; - asm volatile("mov %%rsp, %[tmp] \n\t" - "mov %[stack_top], %%rsp \n\t" - "pushq %[val] \n\t" - "popq %[tmp2] \n\t" - "mov %[tmp], %%rsp" - : [tmp]"=&r"(tmp), [tmp2]"=r"(tmp2) - : [val]"r"(memw), [stack_top]"r"(stack_top) - : "memory"); - report(tmp2 == memw, "pop reg"); - - asm volatile("mov %%rsp, %[tmp] \n\t" - "mov %[stack_top], %%rsp \n\t" - "push $1f \n\t" - "ret \n\t" - "2: jmp 2b \n\t" - "1: mov %[tmp], %%rsp" - : [tmp]"=&r"(tmp) : [stack_top]"r"(stack_top) - : "memory"); - report(1, "ret"); - - stack_top[-1] = 0x778899; - asm volatile("mov %[stack_top], %%r8 \n\t" - "mov %%rsp, %%r9 \n\t" - "xchg %%rbp, %%r8 \n\t" - "leave \n\t" - "xchg %%rsp, %%r9 \n\t" - "xchg %%rbp, %%r8 \n\t" - "mov %%r9, %[tmp] \n\t" - "mov %%r8, %[tmp3]" - : [tmp]"=&r"(tmp), [tmp3]"=&r"(tmp3) : [stack_top]"r"(stack_top-1) - : "memory", "r8", "r9"); - report(tmp == (ulong)stack_top && tmp3 == 0x778899, "leave"); - - rbp = 0xaa55aa55bb66bb66ULL; - rsp = (unsigned long)stack_top; - asm volatile("mov %[rsp], %%r8 \n\t" - "mov %[rbp], %%r9 \n\t" - "xchg %%rsp, %%r8 \n\t" - "xchg %%rbp, %%r9 \n\t" - "enter $0x1238, $0 \n\t" - "xchg %%rsp, %%r8 \n\t" - "xchg %%rbp, %%r9 \n\t" - "xchg %%r8, %[rsp] \n\t" - "xchg %%r9, %[rbp]" - : [rsp]"+a"(rsp), [rbp]"+b"(rbp) : : "memory", "r8", "r9"); - report(rsp == (unsigned long)stack_top - 8 - 0x1238 - && rbp == (unsigned long)stack_top - 8 - && stack_top[-1] == 0xaa55aa55bb66bb66ULL, - "enter"); -} - -static void test_ljmp(void *mem) -{ - unsigned char *m = mem; - volatile int res = 1; - - *(unsigned long**)m = &&jmpf; - asm volatile ("data16/mov %%cs, %0":"=m"(*(m + sizeof(unsigned long)))); - asm volatile ("rex64/ljmp *%0"::"m"(*m)); - res = 0; -jmpf: - report(res, "ljmp"); -} - -static void test_incdecnotneg(void *mem) -{ - unsigned long *m = mem, v = 1234; - unsigned char *mb = mem, vb = 66; - - *m = 0; - - asm volatile ("incl %0":"+m"(*m)); - report(*m == 1, "incl"); - asm volatile ("decl %0":"+m"(*m)); - report(*m == 0, "decl"); - asm volatile ("incb %0":"+m"(*m)); - report(*m == 1, "incb"); - asm volatile ("decb %0":"+m"(*m)); - report(*m == 0, "decb"); - - asm volatile ("lock incl %0":"+m"(*m)); - report(*m == 1, "lock incl"); - asm volatile ("lock decl %0":"+m"(*m)); - report(*m == 0, "lock decl"); - asm volatile ("lock incb %0":"+m"(*m)); - report(*m == 1, "lock incb"); - asm volatile ("lock decb %0":"+m"(*m)); - report(*m == 0, "lock decb"); - - *m = v; - - asm ("lock negq %0" : "+m"(*m)); v = -v; - report(*m == v, "lock negl"); - asm ("lock notq %0" : "+m"(*m)); v = ~v; - report(*m == v, "lock notl"); - - *mb = vb; - - asm ("lock negb %0" : "+m"(*mb)); vb = -vb; - report(*mb == vb, "lock negb"); - asm ("lock notb %0" : "+m"(*mb)); vb = ~vb; - report(*mb == vb, "lock notb"); -} - -static void test_smsw(uint64_t *h_mem) -{ - char mem[16]; - unsigned short msw, msw_orig, *pmsw; - int i, zero; - - msw_orig = read_cr0(); - - asm("smsw %0" : "=r"(msw)); - report(msw == msw_orig, "smsw (1)"); - - memset(mem, 0, 16); - pmsw = (void *)mem; - asm("smsw %0" : "=m"(pmsw[4])); - zero = 1; - for (i = 0; i < 8; ++i) - if (i != 4 && pmsw[i]) - zero = 0; - report(msw == pmsw[4] && zero, "smsw (2)"); - - /* Trigger exit on smsw */ - *h_mem = 0x12345678abcdeful; - asm volatile("smsw %0" : "+m"(*h_mem)); - report(msw == (unsigned short)*h_mem && - (*h_mem & ~0xfffful) == 0x12345678ab0000ul, "smsw (3)"); -} - -static void test_lmsw(void) -{ - char mem[16]; - unsigned short msw, *pmsw; - unsigned long cr0; - - cr0 = read_cr0(); - - msw = cr0 ^ 8; - asm("lmsw %0" : : "r"(msw)); - printf("before %lx after %lx\n", cr0, read_cr0()); - report((cr0 ^ read_cr0()) == 8, "lmsw (1)"); - - pmsw = (void *)mem; - *pmsw = cr0; - asm("lmsw %0" : : "m"(*pmsw)); - printf("before %lx after %lx\n", cr0, read_cr0()); - report(cr0 == read_cr0(), "lmsw (2)"); - - /* lmsw can't clear cr0.pe */ - msw = (cr0 & ~1ul) ^ 4; /* change EM to force trap */ - asm("lmsw %0" : : "r"(msw)); - report((cr0 ^ read_cr0()) == 4 && (cr0 & 1), "lmsw (3)"); - - /* back to normal */ - msw = cr0; - asm("lmsw %0" : : "r"(msw)); -} - -static void test_xchg(void *mem) -{ - unsigned long *memq = mem; - unsigned long rax; - - asm volatile("mov $0x123456789abcdef, %%rax\n\t" - "mov %%rax, (%[memq])\n\t" - "mov $0xfedcba9876543210, %%rax\n\t" - "xchg %%al, (%[memq])\n\t" - "mov %%rax, %[rax]\n\t" - : [rax]"=r"(rax) - : [memq]"r"(memq) - : "memory", "rax"); - report(rax == 0xfedcba98765432ef && *memq == 0x123456789abcd10, - "xchg reg, r/m (1)"); - - asm volatile("mov $0x123456789abcdef, %%rax\n\t" - "mov %%rax, (%[memq])\n\t" - "mov $0xfedcba9876543210, %%rax\n\t" - "xchg %%ax, (%[memq])\n\t" - "mov %%rax, %[rax]\n\t" - : [rax]"=r"(rax) - : [memq]"r"(memq) - : "memory", "rax"); - report(rax == 0xfedcba987654cdef && *memq == 0x123456789ab3210, - "xchg reg, r/m (2)"); - - asm volatile("mov $0x123456789abcdef, %%rax\n\t" - "mov %%rax, (%[memq])\n\t" - "mov $0xfedcba9876543210, %%rax\n\t" - "xchg %%eax, (%[memq])\n\t" - "mov %%rax, %[rax]\n\t" - : [rax]"=r"(rax) - : [memq]"r"(memq) - : "memory", "rax"); - report(rax == 0x89abcdef && *memq == 0x123456776543210, - "xchg reg, r/m (3)"); - - asm volatile("mov $0x123456789abcdef, %%rax\n\t" - "mov %%rax, (%[memq])\n\t" - "mov $0xfedcba9876543210, %%rax\n\t" - "xchg %%rax, (%[memq])\n\t" - "mov %%rax, %[rax]\n\t" - : [rax]"=r"(rax) - : [memq]"r"(memq) - : "memory", "rax"); - report(rax == 0x123456789abcdef && *memq == 0xfedcba9876543210, - "xchg reg, r/m (4)"); -} - -static void test_xadd(void *mem) -{ - unsigned long *memq = mem; - unsigned long rax; - - asm volatile("mov $0x123456789abcdef, %%rax\n\t" - "mov %%rax, (%[memq])\n\t" - "mov $0xfedcba9876543210, %%rax\n\t" - "xadd %%al, (%[memq])\n\t" - "mov %%rax, %[rax]\n\t" - : [rax]"=r"(rax) - : [memq]"r"(memq) - : "memory", "rax"); - report(rax == 0xfedcba98765432ef && *memq == 0x123456789abcdff, - "xadd reg, r/m (1)"); - - asm volatile("mov $0x123456789abcdef, %%rax\n\t" - "mov %%rax, (%[memq])\n\t" - "mov $0xfedcba9876543210, %%rax\n\t" - "xadd %%ax, (%[memq])\n\t" - "mov %%rax, %[rax]\n\t" - : [rax]"=r"(rax) - : [memq]"r"(memq) - : "memory", "rax"); - report(rax == 0xfedcba987654cdef && *memq == 0x123456789abffff, - "xadd reg, r/m (2)"); - - asm volatile("mov $0x123456789abcdef, %%rax\n\t" - "mov %%rax, (%[memq])\n\t" - "mov $0xfedcba9876543210, %%rax\n\t" - "xadd %%eax, (%[memq])\n\t" - "mov %%rax, %[rax]\n\t" - : [rax]"=r"(rax) - : [memq]"r"(memq) - : "memory", "rax"); - report(rax == 0x89abcdef && *memq == 0x1234567ffffffff, - "xadd reg, r/m (3)"); - - asm volatile("mov $0x123456789abcdef, %%rax\n\t" - "mov %%rax, (%[memq])\n\t" - "mov $0xfedcba9876543210, %%rax\n\t" - "xadd %%rax, (%[memq])\n\t" - "mov %%rax, %[rax]\n\t" - : [rax]"=r"(rax) - : [memq]"r"(memq) - : "memory", "rax"); - report(rax == 0x123456789abcdef && *memq == 0xffffffffffffffff, - "xadd reg, r/m (4)"); -} - -static void test_btc(void *mem) -{ - unsigned int *a = mem; - - memset(mem, 0, 4 * sizeof(unsigned int)); - - asm ("btcl $32, %0" :: "m"(a[0]) : "memory"); - asm ("btcl $1, %0" :: "m"(a[1]) : "memory"); - asm ("btcl %1, %0" :: "m"(a[0]), "r"(66) : "memory"); - report(a[0] == 1 && a[1] == 2 && a[2] == 4, "btcl imm8, r/m"); - - asm ("btcl %1, %0" :: "m"(a[3]), "r"(-1) : "memory"); - report(a[0] == 1 && a[1] == 2 && a[2] == 0x80000004, "btcl reg, r/m"); - - asm ("btcq %1, %0" : : "m"(a[2]), "r"(-1l) : "memory"); - report(a[0] == 1 && a[1] == 0x80000002 && a[2] == 0x80000004 && a[3] == 0, - "btcq reg, r/m"); -} - -static void test_bsfbsr(void *mem) -{ - unsigned long rax, *memq = mem; - unsigned eax, *meml = mem; - unsigned short ax, *memw = mem; - unsigned char z; - - *memw = 0xc000; - asm("bsfw %[mem], %[a]" : [a]"=a"(ax) : [mem]"m"(*memw)); - report(ax == 14, "bsfw r/m, reg"); - - *meml = 0xc0000000; - asm("bsfl %[mem], %[a]" : [a]"=a"(eax) : [mem]"m"(*meml)); - report(eax == 30, "bsfl r/m, reg"); - - *memq = 0xc00000000000; - asm("bsfq %[mem], %[a]" : [a]"=a"(rax) : [mem]"m"(*memq)); - report(rax == 46, "bsfq r/m, reg"); - - *memq = 0; - asm("bsfq %[mem], %[a]; setz %[z]" - : [a]"=a"(rax), [z]"=rm"(z) : [mem]"m"(*memq)); - report(z == 1, "bsfq r/m, reg"); - - *memw = 0xc000; - asm("bsrw %[mem], %[a]" : [a]"=a"(ax) : [mem]"m"(*memw)); - report(ax == 15, "bsrw r/m, reg"); - - *meml = 0xc0000000; - asm("bsrl %[mem], %[a]" : [a]"=a"(eax) : [mem]"m"(*meml)); - report(eax == 31, "bsrl r/m, reg"); - - *memq = 0xc00000000000; - asm("bsrq %[mem], %[a]" : [a]"=a"(rax) : [mem]"m"(*memq)); - report(rax == 47, "bsrq r/m, reg"); - - *memq = 0; - asm("bsrq %[mem], %[a]; setz %[z]" - : [a]"=a"(rax), [z]"=rm"(z) : [mem]"m"(*memq)); - report(z == 1, "bsrq r/m, reg"); -} - -static void test_imul(ulong *mem) -{ - ulong a; - - *mem = 51; a = 0x1234567812345678UL; - asm ("imulw %1, %%ax" : "+a"(a) : "m"(*mem)); - report(a == 0x12345678123439e8, "imul ax, mem"); - - *mem = 51; a = 0x1234567812345678UL; - asm ("imull %1, %%eax" : "+a"(a) : "m"(*mem)); - report(a == 0xa06d39e8, "imul eax, mem"); - - *mem = 51; a = 0x1234567812345678UL; - asm ("imulq %1, %%rax" : "+a"(a) : "m"(*mem)); - report(a == 0xA06D39EBA06D39E8UL, "imul rax, mem"); - - *mem = 0x1234567812345678UL; a = 0x8765432187654321L; - asm ("imulw $51, %1, %%ax" : "+a"(a) : "m"(*mem)); - report(a == 0x87654321876539e8, "imul ax, mem, imm8"); - - *mem = 0x1234567812345678UL; - asm ("imull $51, %1, %%eax" : "+a"(a) : "m"(*mem)); - report(a == 0xa06d39e8, "imul eax, mem, imm8"); - - *mem = 0x1234567812345678UL; - asm ("imulq $51, %1, %%rax" : "+a"(a) : "m"(*mem)); - report(a == 0xA06D39EBA06D39E8UL, "imul rax, mem, imm8"); - - *mem = 0x1234567812345678UL; a = 0x8765432187654321L; - asm ("imulw $311, %1, %%ax" : "+a"(a) : "m"(*mem)); - report(a == 0x8765432187650bc8, "imul ax, mem, imm"); - - *mem = 0x1234567812345678UL; - asm ("imull $311, %1, %%eax" : "+a"(a) : "m"(*mem)); - report(a == 0x1d950bc8, "imul eax, mem, imm"); - - *mem = 0x1234567812345678UL; - asm ("imulq $311, %1, %%rax" : "+a"(a) : "m"(*mem)); - report(a == 0x1D950BDE1D950BC8L, "imul rax, mem, imm"); -} - -static void test_muldiv(long *mem) -{ - long a, d, aa, dd; - u8 ex = 1; - - *mem = 0; a = 1; d = 2; - asm (ASM_TRY("1f") "divq %3; movb $0, %2; 1:" - : "+a"(a), "+d"(d), "+q"(ex) : "m"(*mem)); - report(a == 1 && d == 2 && ex, "divq (fault)"); - - *mem = 987654321098765UL; a = 123456789012345UL; d = 123456789012345UL; - asm (ASM_TRY("1f") "divq %3; movb $0, %2; 1:" - : "+a"(a), "+d"(d), "+q"(ex) : "m"(*mem)); - report(a == 0x1ffffffb1b963b33ul && d == 0x273ba4384ede2ul && !ex, - "divq (1)"); - aa = 0x1111111111111111; dd = 0x2222222222222222; - *mem = 0x3333333333333333; a = aa; d = dd; - asm("mulb %2" : "+a"(a), "+d"(d) : "m"(*mem)); - report(a == 0x1111111111110363 && d == dd, "mulb mem"); - *mem = 0x3333333333333333; a = aa; d = dd; - asm("mulw %2" : "+a"(a), "+d"(d) : "m"(*mem)); - report(a == 0x111111111111c963 && d == 0x2222222222220369, "mulw mem"); - *mem = 0x3333333333333333; a = aa; d = dd; - asm("mull %2" : "+a"(a), "+d"(d) : "m"(*mem)); - report(a == 0x962fc963 && d == 0x369d036, "mull mem"); - *mem = 0x3333333333333333; a = aa; d = dd; - asm("mulq %2" : "+a"(a), "+d"(d) : "m"(*mem)); - report(a == 0x2fc962fc962fc963 && d == 0x369d0369d0369d0, "mulq mem"); -} - -typedef unsigned __attribute__((vector_size(16))) sse128; - -typedef union { - sse128 sse; - unsigned u[4]; -} sse_union; - -static bool sseeq(sse_union *v1, sse_union *v2) -{ - bool ok = true; - int i; - - for (i = 0; i < 4; ++i) { - ok &= v1->u[i] == v2->u[i]; - } - - return ok; -} - -static __attribute__((target("sse2"))) void test_sse(sse_union *mem) -{ - sse_union v; - - write_cr0(read_cr0() & ~6); /* EM, TS */ - write_cr4(read_cr4() | 0x200); /* OSFXSR */ - v.u[0] = 1; v.u[1] = 2; v.u[2] = 3; v.u[3] = 4; - asm("movdqu %1, %0" : "=m"(*mem) : "x"(v.sse)); - report(sseeq(&v, mem), "movdqu (read)"); - mem->u[0] = 5; mem->u[1] = 6; mem->u[2] = 7; mem->u[3] = 8; - asm("movdqu %1, %0" : "=x"(v.sse) : "m"(*mem)); - report(sseeq(mem, &v), "movdqu (write)"); - - v.u[0] = 1; v.u[1] = 2; v.u[2] = 3; v.u[3] = 4; - asm("movaps %1, %0" : "=m"(*mem) : "x"(v.sse)); - report(sseeq(mem, &v), "movaps (read)"); - mem->u[0] = 5; mem->u[1] = 6; mem->u[2] = 7; mem->u[3] = 8; - asm("movaps %1, %0" : "=x"(v.sse) : "m"(*mem)); - report(sseeq(&v, mem), "movaps (write)"); - - v.u[0] = 1; v.u[1] = 2; v.u[2] = 3; v.u[3] = 4; - asm("movapd %1, %0" : "=m"(*mem) : "x"(v.sse)); - report(sseeq(mem, &v), "movapd (read)"); - mem->u[0] = 5; mem->u[1] = 6; mem->u[2] = 7; mem->u[3] = 8; - asm("movapd %1, %0" : "=x"(v.sse) : "m"(*mem)); - report(sseeq(&v, mem), "movapd (write)"); -} - -static void test_mmx(uint64_t *mem) -{ - uint64_t v; - - write_cr0(read_cr0() & ~6); /* EM, TS */ - asm volatile("fninit"); - v = 0x0102030405060708ULL; - asm("movq %1, %0" : "=m"(*mem) : "y"(v)); - report(v == *mem, "movq (mmx, read)"); - *mem = 0x8070605040302010ull; - asm("movq %1, %0" : "=y"(v) : "m"(*mem)); - report(v == *mem, "movq (mmx, write)"); -} - -static void test_rip_relative(unsigned *mem, char *insn_ram) -{ - /* movb $1, mem+2(%rip) */ - insn_ram[0] = 0xc6; - insn_ram[1] = 0x05; - *(unsigned *)&insn_ram[2] = 2 + (char *)mem - (insn_ram + 7); - insn_ram[6] = 0x01; - /* ret */ - insn_ram[7] = 0xc3; - - *mem = 0; - asm("callq *%1" : "+m"(*mem) : "r"(insn_ram)); - report(*mem == 0x10000, "movb $imm, 0(%%rip)"); -} - -static void test_shld_shrd(u32 *mem) -{ - *mem = 0x12345678; - asm("shld %2, %1, %0" : "+m"(*mem) : "r"(0xaaaaaaaaU), "c"((u8)3)); - report(*mem == ((0x12345678 << 3) | 5), "shld (cl)"); - *mem = 0x12345678; - asm("shrd %2, %1, %0" : "+m"(*mem) : "r"(0x55555555U), "c"((u8)3)); - report(*mem == ((0x12345678 >> 3) | (5u << 29)), "shrd (cl)"); -} - -static void test_cmov(u32 *mem) -{ - u64 val; - *mem = 0xabcdef12u; - asm ("movq $0x1234567812345678, %%rax\n\t" - "cmpl %%eax, %%eax\n\t" - "cmovnel (%[mem]), %%eax\n\t" - "movq %%rax, %[val]\n\t" - : [val]"=r"(val) : [mem]"r"(mem) : "%rax", "cc"); - report(val == 0x12345678ul, "cmovnel"); -} - -static unsigned long rip_advance; - -static void advance_rip_and_note_exception(struct ex_regs *regs) -{ - ++exceptions; - regs->rip += rip_advance; -} - -static void test_mmx_movq_mf(uint64_t *mem) -{ - /* movq %mm0, (%rax) */ - extern char movq_start, movq_end; - - uint16_t fcw = 0; /* all exceptions unmasked */ - write_cr0(read_cr0() & ~6); /* TS, EM */ - exceptions = 0; - handle_exception(MF_VECTOR, advance_rip_and_note_exception); - asm volatile("fninit; fldcw %0" : : "m"(fcw)); - asm volatile("fldz; fldz; fdivp"); /* generate exception */ - - rip_advance = &movq_end - &movq_start; - asm(KVM_FEP "movq_start: movq %mm0, (%rax); movq_end:"); - /* exit MMX mode */ - asm volatile("fnclex; emms"); - report(exceptions == 1, "movq mmx generates #MF"); - handle_exception(MF_VECTOR, 0); -} - -static void test_jmp_noncanonical(uint64_t *mem) -{ - extern char nc_jmp_start, nc_jmp_end; - - *mem = 0x1111111111111111ul; - - exceptions = 0; - rip_advance = &nc_jmp_end - &nc_jmp_start; - handle_exception(GP_VECTOR, advance_rip_and_note_exception); - asm volatile ("nc_jmp_start: jmp *%0; nc_jmp_end:" : : "m"(*mem)); - report(exceptions == 1, "jump to non-canonical address"); - handle_exception(GP_VECTOR, 0); -} - -static void test_movabs(uint64_t *mem) -{ - /* mov $0x9090909090909090, %rcx */ - unsigned long rcx; - asm(KVM_FEP "mov $0x9090909090909090, %0" : "=c" (rcx) : "0" (0)); - report(rcx == 0x9090909090909090, "64-bit mov imm2"); -} - -static void test_smsw_reg(uint64_t *mem) -{ - unsigned long cr0 = read_cr0(); - unsigned long rax; - const unsigned long in_rax = 0x1234567890abcdeful; - - asm(KVM_FEP "smsww %w0\n\t" : "=a" (rax) : "0" (in_rax)); - report((u16)rax == (u16)cr0 && rax >> 16 == in_rax >> 16, - "16-bit smsw reg"); - - asm(KVM_FEP "smswl %k0\n\t" : "=a" (rax) : "0" (in_rax)); - report(rax == (u32)cr0, "32-bit smsw reg"); - - asm(KVM_FEP "smswq %q0\n\t" : "=a" (rax) : "0" (in_rax)); - report(rax == cr0, "64-bit smsw reg"); -} - -static void test_nop(uint64_t *mem) -{ - unsigned long rax; - const unsigned long in_rax = 0x1234567890abcdeful; - asm(KVM_FEP "nop\n\t" : "=a" (rax) : "0" (in_rax)); - report(rax == in_rax, "nop"); -} - -static void test_mov_dr(uint64_t *mem) -{ - unsigned long rax; - const unsigned long in_rax = 0; - bool rtm_support = this_cpu_has(X86_FEATURE_RTM); - unsigned long dr6_fixed_1 = rtm_support ? 0xfffe0ff0ul : 0xffff0ff0ul; - asm(KVM_FEP "movq %0, %%dr6\n\t" - KVM_FEP "movq %%dr6, %0\n\t" : "=a" (rax) : "a" (in_rax)); - report(rax == dr6_fixed_1, "mov_dr6"); -} - -static void test_push16(uint64_t *mem) -{ - uint64_t rsp1, rsp2; - uint16_t r; - - asm volatile ( "movq %%rsp, %[rsp1]\n\t" - "pushw %[v]\n\t" - "popw %[r]\n\t" - "movq %%rsp, %[rsp2]\n\t" - "movq %[rsp1], %%rsp\n\t" : - [rsp1]"=r"(rsp1), [rsp2]"=r"(rsp2), [r]"=r"(r) - : [v]"m"(*mem) : "memory"); - report(rsp1 == rsp2, "push16"); -} - -static void test_crosspage_mmio(volatile uint8_t *mem) -{ - volatile uint16_t w, *pw; - - pw = (volatile uint16_t *)&mem[4095]; - mem[4095] = 0x99; - mem[4096] = 0x77; - asm volatile("mov %1, %0" : "=r"(w) : "m"(*pw) : "memory"); - report(w == 0x7799, "cross-page mmio read"); - asm volatile("mov %1, %0" : "=m"(*pw) : "r"((uint16_t)0x88aa)); - report(mem[4095] == 0xaa && mem[4096] == 0x88, "cross-page mmio write"); -} - -static void test_string_io_mmio(volatile uint8_t *mem) -{ - /* Cross MMIO pages.*/ - volatile uint8_t *mmio = mem + 4032; - - asm volatile("outw %%ax, %%dx \n\t" : : "a"(0x9999), "d"(TESTDEV_IO_PORT)); - - asm volatile ("cld; rep insb" : : "d" (TESTDEV_IO_PORT), "D" (mmio), "c" (1024)); - - report(mmio[1023] == 0x99, "string_io_mmio"); -} - -/* kvm doesn't allow lidt/lgdt from mmio, so the test is disabled */ -#if 0 -static void test_lgdt_lidt(volatile uint8_t *mem) -{ - struct descriptor_table_ptr orig, fresh = {}; - - sgdt(&orig); - *(struct descriptor_table_ptr *)mem = (struct descriptor_table_ptr) { - .limit = 0xf234, - .base = 0x12345678abcd, - }; - cli(); - asm volatile("lgdt %0" : : "m"(*(struct descriptor_table_ptr *)mem)); - sgdt(&fresh); - lgdt(&orig); - sti(); - report(orig.limit == fresh.limit && orig.base == fresh.base, - "lgdt (long address)"); - - sidt(&orig); - *(struct descriptor_table_ptr *)mem = (struct descriptor_table_ptr) { - .limit = 0x432f, - .base = 0xdbca87654321, - }; - cli(); - asm volatile("lidt %0" : : "m"(*(struct descriptor_table_ptr *)mem)); - sidt(&fresh); - lidt(&orig); - sti(); - report(orig.limit == fresh.limit && orig.base == fresh.base, - "lidt (long address)"); -} -#endif - -static void ss_bad_rpl(struct ex_regs *regs) -{ - extern char ss_bad_rpl_cont; - - ++exceptions; - regs->rip = (ulong)&ss_bad_rpl_cont; -} - -static void test_sreg(volatile uint16_t *mem) -{ - u16 ss = read_ss(); - - // check for null segment load - *mem = 0; - asm volatile("mov %0, %%ss" : : "m"(*mem)); - report(read_ss() == 0, "mov null, %%ss"); - - // check for exception when ss.rpl != cpl on null segment load - exceptions = 0; - handle_exception(GP_VECTOR, ss_bad_rpl); - *mem = 3; - asm volatile("mov %0, %%ss; ss_bad_rpl_cont:" : : "m"(*mem)); - report(exceptions == 1 && read_ss() == 0, - "mov null, %%ss (with ss.rpl != cpl)"); - handle_exception(GP_VECTOR, 0); - write_ss(ss); -} - -/* Broken emulation causes triple fault, which skips the other tests. */ -#if 0 -static void test_lldt(volatile uint16_t *mem) -{ - u64 gdt[] = { 0, /* null descriptor */ -#ifdef __X86_64__ - 0, /* ldt descriptor is 16 bytes in long mode */ -#endif - 0x0000f82000000ffffull /* ldt descriptor */ }; - struct descriptor_table_ptr gdt_ptr = { .limit = sizeof(gdt) - 1, - .base = (ulong)&gdt }; - struct descriptor_table_ptr orig_gdt; - - cli(); - sgdt(&orig_gdt); - lgdt(&gdt_ptr); - *mem = 0x8; - asm volatile("lldt %0" : : "m"(*mem)); - lgdt(&orig_gdt); - sti(); - report(sldt() == *mem, "lldt"); -} -#endif - -static void test_ltr(volatile uint16_t *mem) -{ - struct descriptor_table_ptr gdt_ptr; - uint64_t *gdt, *trp; - uint16_t tr = str(); - uint64_t busy_mask = (uint64_t)1 << 41; - - sgdt(&gdt_ptr); - gdt = (uint64_t *)gdt_ptr.base; - trp = &gdt[tr >> 3]; - *trp &= ~busy_mask; - *mem = tr; - asm volatile("ltr %0" : : "m"(*mem) : "memory"); - report(str() == tr && (*trp & busy_mask), "ltr"); -} - -static void test_simplealu(u32 *mem) -{ - *mem = 0x1234; - asm("or %1, %0" : "+m"(*mem) : "r"(0x8001)); - report(*mem == 0x9235, "or"); - asm("add %1, %0" : "+m"(*mem) : "r"(2)); - report(*mem == 0x9237, "add"); - asm("xor %1, %0" : "+m"(*mem) : "r"(0x1111)); - report(*mem == 0x8326, "xor"); - asm("sub %1, %0" : "+m"(*mem) : "r"(0x26)); - report(*mem == 0x8300, "sub"); - asm("clc; adc %1, %0" : "+m"(*mem) : "r"(0x100)); - report(*mem == 0x8400, "adc(0)"); - asm("stc; adc %1, %0" : "+m"(*mem) : "r"(0x100)); - report(*mem == 0x8501, "adc(0)"); - asm("clc; sbb %1, %0" : "+m"(*mem) : "r"(0)); - report(*mem == 0x8501, "sbb(0)"); - asm("stc; sbb %1, %0" : "+m"(*mem) : "r"(0)); - report(*mem == 0x8500, "sbb(1)"); - asm("and %1, %0" : "+m"(*mem) : "r"(0xfe77)); - report(*mem == 0x8400, "and"); - asm("test %1, %0" : "+m"(*mem) : "r"(0xf000)); - report(*mem == 0x8400, "test"); -} - -static void illegal_movbe_handler(struct ex_regs *regs) -{ - extern char bad_movbe_cont; - - ++exceptions; - regs->rip = (ulong)&bad_movbe_cont; -} - -static void test_illegal_movbe(void) -{ - if (!this_cpu_has(X86_FEATURE_MOVBE)) { - report_skip("illegal movbe"); - return; - } - - exceptions = 0; - handle_exception(UD_VECTOR, illegal_movbe_handler); - asm volatile(".byte 0x0f; .byte 0x38; .byte 0xf0; .byte 0xc0;\n\t" - " bad_movbe_cont:" : : : "rax"); - report(exceptions == 1, "illegal movbe"); - handle_exception(UD_VECTOR, 0); -} - -static void record_no_fep(struct ex_regs *regs) -{ - fep_available = 0; - regs->rip += KVM_FEP_LENGTH; -} - -int main(void) -{ - void *mem; - void *insn_page; - void *insn_ram; - unsigned long t1, t2; - - setup_vm(); - handle_exception(UD_VECTOR, record_no_fep); - asm(KVM_FEP "nop"); - handle_exception(UD_VECTOR, 0); - - mem = alloc_vpages(2); - install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem); - // install the page twice to test cross-page mmio - install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem + 4096); - insn_page = alloc_page(); - insn_ram = vmap(virt_to_phys(insn_page), 4096); - - // test mov reg, r/m and mov r/m, reg - t1 = 0x123456789abcdef; - asm volatile("mov %[t1], (%[mem]) \n\t" - "mov (%[mem]), %[t2]" - : [t2]"=r"(t2) - : [t1]"r"(t1), [mem]"r"(mem) - : "memory"); - report(t2 == 0x123456789abcdef, "mov reg, r/m (1)"); - - test_simplealu(mem); - test_cmps(mem); - test_scas(mem); - - test_push(mem); - test_pop(mem); - - test_xchg(mem); - test_xadd(mem); - - test_cr8(); - - test_smsw(mem); - test_lmsw(); - test_ljmp(mem); - test_stringio(); - test_incdecnotneg(mem); - test_btc(mem); - test_bsfbsr(mem); - test_imul(mem); - test_muldiv(mem); - test_sse(mem); - test_mmx(mem); - test_rip_relative(mem, insn_ram); - test_shld_shrd(mem); - //test_lgdt_lidt(mem); - test_sreg(mem); - //test_lldt(mem); - test_ltr(mem); - test_cmov(mem); - - if (fep_available) { - test_mmx_movq_mf(mem); - test_movabs(mem); - test_smsw_reg(mem); - test_nop(mem); - test_mov_dr(mem); - } else { - report_skip("skipping register-only tests, " - "use kvm.forced_emulation_prefix=1 to enable"); - } - - test_push16(mem); - test_crosspage_mmio(mem); - - test_string_io_mmio(mem); - - test_jmp_noncanonical(mem); - test_illegal_movbe(); - - return report_summary(); -} diff --git a/x86/eventinj.c b/x86/eventinj.c deleted file mode 100644 index 46593c94..00000000 --- a/x86/eventinj.c +++ /dev/null @@ -1,431 +0,0 @@ -#include "libcflat.h" -#include "vm.h" -#include "processor.h" -#include "desc.h" -#include "isr.h" -#include "apic.h" -#include "apic-defs.h" -#include "vmalloc.h" -#include "alloc_page.h" -#include "delay.h" -#include "fwcfg.h" - -#ifdef __x86_64__ -# define R "r" -#else -# define R "e" -#endif - -void do_pf_tss(void); - -static void apic_self_ipi(u8 v) -{ - apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | - APIC_INT_ASSERT | v, 0); -} - -static void apic_self_nmi(void) -{ - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); -} - -#define flush_phys_addr(__s) do { \ - if (test_device_enabled()) \ - outl(__s, 0xe4); \ - } while (0) - -#define flush_stack() do { \ - int __l; \ - flush_phys_addr(virt_to_phys(&__l)); \ - } while (0) - -extern char isr_iret_ip[]; - -static void flush_idt_page(void) -{ - struct descriptor_table_ptr ptr; - sidt(&ptr); - flush_phys_addr(virt_to_phys((void*)ptr.base)); -} - -static volatile unsigned int test_divider; -static volatile int test_count; - -ulong stack_phys; -void *stack_va; - -void do_pf_tss(void) -{ - printf("PF running\n"); - install_pte(phys_to_virt(read_cr3()), 1, stack_va, - stack_phys | PT_PRESENT_MASK | PT_WRITABLE_MASK, 0); - invlpg(stack_va); -} - -extern void pf_tss(void); - -asm ("pf_tss: \n\t" -#ifdef __x86_64__ - // no task on x86_64, save/restore caller-save regs - "push %rax; push %rcx; push %rdx; push %rsi; push %rdi\n" - "push %r8; push %r9; push %r10; push %r11\n" -#endif - "call do_pf_tss \n\t" -#ifdef __x86_64__ - "pop %r11; pop %r10; pop %r9; pop %r8\n" - "pop %rdi; pop %rsi; pop %rdx; pop %rcx; pop %rax\n" -#endif - "add $"S", %"R "sp\n\t" // discard error code - "iret"W" \n\t" - "jmp pf_tss\n\t" - ); - - -#ifndef __x86_64__ -static void of_isr(struct ex_regs *r) -{ - printf("OF isr running\n"); - test_count++; -} -#endif - -static void np_isr(struct ex_regs *r) -{ - printf("NP isr running %lx err=%lx\n", r->rip, r->error_code); - set_idt_sel(33, read_cs()); - test_count++; -} - -static void de_isr(struct ex_regs *r) -{ - printf("DE isr running divider is %d\n", test_divider); - test_divider = 10; -} - -static void bp_isr(struct ex_regs *r) -{ - printf("BP isr running\n"); - test_count++; -} - -static void nested_nmi_isr(struct ex_regs *r) -{ - printf("Nested NMI isr running rip=%lx\n", r->rip); - - if (r->rip != (ulong)&isr_iret_ip) - test_count++; -} -static void nmi_isr(struct ex_regs *r) -{ - printf("NMI isr running %p\n", &isr_iret_ip); - test_count++; - handle_exception(2, nested_nmi_isr); - printf("Sending nested NMI to self\n"); - apic_self_nmi(); - io_delay(); - printf("After nested NMI to self\n"); -} - -unsigned long *iret_stack; - -static void nested_nmi_iret_isr(struct ex_regs *r) -{ - printf("Nested NMI isr running rip=%lx\n", r->rip); - - if (r->rip == iret_stack[-3]) - test_count++; -} - -extern void do_iret(ulong phys_stack, void *virt_stack); - -// Return to same privilege level won't pop SS or SP, so -// save it in RDX while we run on the nested stack - -extern bool no_test_device; - -asm("do_iret:" -#ifdef __x86_64__ - "mov %rdi, %rax \n\t" // phys_stack - "mov %rsi, %rdx \n\t" // virt_stack -#else - "mov 4(%esp), %eax \n\t" // phys_stack - "mov 8(%esp), %edx \n\t" // virt_stack -#endif - "xchg %"R "dx, %"R "sp \n\t" // point to new stack - "pushf"W" \n\t" - "mov %cs, %ecx \n\t" - "push"W" %"R "cx \n\t" - "push"W" $2f \n\t" - - "cmpb $0, no_test_device\n\t" // see if need to flush - "jnz 1f\n\t" - "outl %eax, $0xe4 \n\t" // flush page - "1: \n\t" - "iret"W" \n\t" - "2: xchg %"R "dx, %"R "sp \n\t" // point to old stack - "ret\n\t" - ); - -static void nmi_iret_isr(struct ex_regs *r) -{ - unsigned long *s = alloc_page(); - test_count++; - printf("NMI isr running stack %p\n", s); - handle_exception(2, nested_nmi_iret_isr); - printf("Sending nested NMI to self\n"); - apic_self_nmi(); - printf("After nested NMI to self\n"); - iret_stack = &s[128]; - do_iret(virt_to_phys(s), iret_stack); - printf("After iret\n"); -} - -static void tirq0(isr_regs_t *r) -{ - printf("irq0 running\n"); - if (test_count == 1) - test_count++; - eoi(); -} - -static void tirq1(isr_regs_t *r) -{ - printf("irq1 running\n"); - test_count++; - eoi(); -} - -ulong saved_stack; - -#define switch_stack(S) do { \ - asm volatile ("mov %%" R "sp, %0":"=r"(saved_stack)); \ - asm volatile ("mov %0, %%" R "sp"::"r"(S)); \ - } while(0) - -#define restore_stack() do { \ - asm volatile ("mov %0, %%" R "sp"::"r"(saved_stack)); \ - } while(0) - -int main(void) -{ - unsigned int res; - ulong *pt, *cr3, i; - - setup_vm(); - setup_alt_stack(); - - handle_irq(32, tirq0); - handle_irq(33, tirq1); - - /* generate HW exception that will fault on IDT and stack */ - handle_exception(0, de_isr); - printf("Try to divide by 0\n"); - flush_idt_page(); - flush_stack(); - asm volatile ("divl %3": "=a"(res) - : "d"(0), "a"(1500), "m"(test_divider)); - printf("Result is %d\n", res); - report(res == 150, "DE exception"); - - /* generate soft exception (BP) that will fault on IDT and stack */ - test_count = 0; - handle_exception(3, bp_isr); - printf("Try int 3\n"); - flush_idt_page(); - flush_stack(); - asm volatile ("int $3"); - printf("After int 3\n"); - report(test_count == 1, "BP exception"); - -#ifndef __x86_64__ - /* generate soft exception (OF) that will fault on IDT */ - test_count = 0; - handle_exception(4, of_isr); - flush_idt_page(); - printf("Try into\n"); - asm volatile ("addb $127, %b0\ninto"::"a"(127)); - printf("After into\n"); - report(test_count == 1, "OF exception"); - - /* generate soft exception (OF) using two bit instruction that will - fault on IDT */ - test_count = 0; - handle_exception(4, of_isr); - flush_idt_page(); - printf("Try into\n"); - asm volatile ("addb $127, %b0\naddr16 into"::"a"(127)); - printf("After into\n"); - report(test_count == 1, "2 byte OF exception"); -#endif - - /* generate HW interrupt that will fault on IDT */ - test_count = 0; - flush_idt_page(); - printf("Sending vec 33 to self\n"); - irq_enable(); - apic_self_ipi(33); - io_delay(); - irq_disable(); - printf("After vec 33 to self\n"); - report(test_count == 1, "vec 33"); - - /* generate soft interrupt that will fault on IDT and stack */ - test_count = 0; - flush_idt_page(); - printf("Try int $33\n"); - flush_stack(); - asm volatile ("int $33"); - printf("After int $33\n"); - report(test_count == 1, "int $33"); - - /* Inject two HW interrupt than open iterrupt windows. Both interrupt - will fault on IDT access */ - test_count = 0; - flush_idt_page(); - printf("Sending vec 32 and 33 to self\n"); - apic_self_ipi(32); - apic_self_ipi(33); - io_delay(); - irq_enable(); - asm volatile("nop"); - irq_disable(); - printf("After vec 32 and 33 to self\n"); - report(test_count == 2, "vec 32/33"); - - - /* Inject HW interrupt, do sti and than (while in irq shadow) inject - soft interrupt. Fault during soft interrupt. Soft interrup shoud be - handled before HW interrupt */ - test_count = 0; - flush_idt_page(); - printf("Sending vec 32 and int $33\n"); - apic_self_ipi(32); - flush_stack(); - io_delay(); - asm volatile ("sti; int $33"); - irq_disable(); - printf("After vec 32 and int $33\n"); - report(test_count == 2, "vec 32/int $33"); - - /* test that TPR is honored */ - test_count = 0; - handle_irq(62, tirq1); - flush_idt_page(); - printf("Sending vec 33 and 62 and mask one with TPR\n"); - apic_write(APIC_TASKPRI, 0xf << 4); - irq_enable(); - apic_self_ipi(32); - apic_self_ipi(62); - io_delay(); - apic_write(APIC_TASKPRI, 0x2 << 4); - printf("After 33/62 TPR test\n"); - report(test_count == 1, "TPR"); - apic_write(APIC_TASKPRI, 0x0); - while(test_count != 2); /* wait for second irq */ - irq_disable(); - - /* test fault durint NP delivery */ - printf("Before NP test\n"); - test_count = 0; - handle_exception(11, np_isr); - set_idt_sel(33, NP_SEL); - flush_idt_page(); - flush_stack(); - asm volatile ("int $33"); - printf("After int33\n"); - report(test_count == 2, "NP exception"); - - /* generate NMI that will fault on IDT */ - test_count = 0; - handle_exception(2, nmi_isr); - flush_idt_page(); - printf("Sending NMI to self\n"); - apic_self_nmi(); - printf("After NMI to self\n"); - /* this is needed on VMX without NMI window notification. - Interrupt windows is used instead, so let pending NMI - to be injected */ - irq_enable(); - asm volatile ("nop"); - irq_disable(); - report(test_count == 2, "NMI"); - - /* generate NMI that will fault on IRET */ - printf("Before NMI IRET test\n"); - test_count = 0; - handle_exception(2, nmi_iret_isr); - printf("Sending NMI to self\n"); - apic_self_nmi(); - /* this is needed on VMX without NMI window notification. - Interrupt windows is used instead, so let pending NMI - to be injected */ - irq_enable(); - asm volatile ("nop"); - irq_disable(); - printf("After NMI to self\n"); - report(test_count == 2, "NMI"); - stack_phys = (ulong)virt_to_phys(alloc_page()); - stack_va = alloc_vpage(); - - /* Generate DE and PF exceptions serially */ - test_divider = 0; - set_intr_alt_stack(14, pf_tss); - handle_exception(0, de_isr); - printf("Try to divide by 0\n"); - /* install read only pte */ - install_pte(phys_to_virt(read_cr3()), 1, stack_va, - stack_phys | PT_PRESENT_MASK, 0); - invlpg(stack_va); - flush_phys_addr(stack_phys); - switch_stack(stack_va + 4095); - flush_idt_page(); - asm volatile ("divl %3": "=a"(res) - : "d"(0), "a"(1500), "m"(test_divider)); - restore_stack(); - printf("Result is %d\n", res); - report(res == 150, "DE PF exceptions"); - - /* Generate NP and PF exceptions serially */ - printf("Before NP test\n"); - test_count = 0; - set_intr_alt_stack(14, pf_tss); - handle_exception(11, np_isr); - set_idt_sel(33, NP_SEL); - /* install read only pte */ - install_pte(phys_to_virt(read_cr3()), 1, stack_va, - stack_phys | PT_PRESENT_MASK, 0); - invlpg(stack_va); - flush_idt_page(); - flush_phys_addr(stack_phys); - switch_stack(stack_va + 4095); - asm volatile ("int $33"); - restore_stack(); - printf("After int33\n"); - report(test_count == 2, "NP PF exceptions"); - - pt = alloc_page(); - cr3 = (void*)read_cr3(); - /* use shadowed stack during interrupt delivery */ - for (i = 0; i < 4096/sizeof(ulong); i++) { - if (!cr3[i]) { - cr3[i] = virt_to_phys(pt) | PT_PRESENT_MASK | PT_WRITABLE_MASK; - pt[0] = virt_to_phys(pt) | PT_PRESENT_MASK | PT_WRITABLE_MASK; -#ifndef __x86_64__ - ((ulong*)(i<<22))[1] = 0; -#else - ((ulong*)(i<<39))[1] = 0; -#endif - write_cr3(virt_to_phys(cr3)); - break; - } - } - test_count = 0; - printf("Try int 33 with shadowed stack\n"); - switch_stack(((char*)pt) + 4095); - asm volatile("int $33"); - restore_stack(); - printf("After int 33 with shadowed stack\n"); - report(test_count == 1, "int 33 with shadowed stack"); - - return report_summary(); -} diff --git a/x86/flat.lds b/x86/flat.lds deleted file mode 100644 index a278b56c..00000000 --- a/x86/flat.lds +++ /dev/null @@ -1,21 +0,0 @@ -SECTIONS -{ - . = 4M + SIZEOF_HEADERS; - stext = .; - .text : { *(.init) *(.text) *(.text.*) } - . = ALIGN(4K); - .data : { - *(.data) - exception_table_start = .; - *(.data.ex) - exception_table_end = .; - } - . = ALIGN(16); - .rodata : { *(.rodata) } - . = ALIGN(16); - .bss : { *(.bss) } - . = ALIGN(4K); - edata = .; -} - -ENTRY(start) diff --git a/x86/hypercall.c b/x86/hypercall.c deleted file mode 100644 index 28760e32..00000000 --- a/x86/hypercall.c +++ /dev/null @@ -1,82 +0,0 @@ -#include "libcflat.h" -#include "vm.h" -#include "desc.h" -#include "alloc_page.h" - -#define KVM_HYPERCALL_INTEL ".byte 0x0f,0x01,0xc1" -#define KVM_HYPERCALL_AMD ".byte 0x0f,0x01,0xd9" - -static inline long kvm_hypercall0_intel(unsigned int nr) -{ - long ret; - asm volatile(KVM_HYPERCALL_INTEL - : "=a"(ret) - : "a"(nr)); - return ret; -} - -static inline long kvm_hypercall0_amd(unsigned int nr) -{ - long ret; - asm volatile(KVM_HYPERCALL_AMD - : "=a"(ret) - : "a"(nr)); - return ret; -} - - -volatile unsigned long test_rip; -#ifdef __x86_64__ -extern void gp_tss(void); -asm ("gp_tss: \n\t" - "add $8, %rsp\n\t" // discard error code - "popq test_rip(%rip)\n\t" // pop return address - "pushq %rsi\n\t" // new return address - "iretq\n\t" - "jmp gp_tss\n\t" - ); - -static inline int -test_edge(void) -{ - test_rip = 0; - asm volatile ("movq $-1, %%rax\n\t" // prepare for vmcall - "leaq 1f(%%rip), %%rsi\n\t" // save return address for gp_tss - "movabsq $0x7ffffffffffd, %%rbx\n\t" - "jmp *%%rbx; 1:" : : : "rax", "rbx", "rsi"); - printf("Return from int 13, test_rip = %lx\n", test_rip); - return test_rip == (1ul << 47); -} -#endif - -int main(int ac, char **av) -{ - kvm_hypercall0_intel(-1u); - printf("Hypercall via VMCALL: OK\n"); - kvm_hypercall0_amd(-1u); - printf("Hypercall via VMMCALL: OK\n"); - -#ifdef __x86_64__ - setup_vm(); - setup_alt_stack(); - set_intr_alt_stack(13, gp_tss); - - u8 *data1 = alloc_page(); - u8 *topmost = (void *) ((1ul << 47) - PAGE_SIZE); - - install_pte(phys_to_virt(read_cr3()), 1, topmost, - virt_to_phys(data1) | PT_PRESENT_MASK | PT_WRITABLE_MASK, 0); - memset(topmost, 0xcc, PAGE_SIZE); - topmost[4093] = 0x0f; - topmost[4094] = 0x01; - topmost[4095] = 0xc1; - report(test_edge(), - "VMCALL on edge of canonical address space (intel)"); - - topmost[4095] = 0xd9; - report(test_edge(), - "VMMCALL on edge of canonical address space (AMD)"); -#endif - - return report_summary(); -} diff --git a/x86/hyperv.c b/x86/hyperv.c deleted file mode 100644 index 60f76455..00000000 --- a/x86/hyperv.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "hyperv.h" -#include "asm/io.h" -#include "smp.h" - -enum { - HV_TEST_DEV_SINT_ROUTE_CREATE = 1, - HV_TEST_DEV_SINT_ROUTE_DESTROY, - HV_TEST_DEV_SINT_ROUTE_SET_SINT, - HV_TEST_DEV_MSG_CONN_CREATE, - HV_TEST_DEV_MSG_CONN_DESTROY, - HV_TEST_DEV_EVT_CONN_CREATE, - HV_TEST_DEV_EVT_CONN_DESTROY, -}; - -static void synic_ctl(u32 ctl, u32 vcpu_id, u32 sint, u32 conn_id) -{ - outl((conn_id << 24) | (ctl << 16) | (vcpu_id << 8) | sint, 0x3000); -} - -static void sint_enable(u8 sint, u8 vec, bool auto_eoi) -{ - wrmsr(HV_X64_MSR_SINT0 + sint, - (u64)vec | (auto_eoi ? HV_SYNIC_SINT_AUTO_EOI : 0)); -} - -static void sint_disable(u8 sint) -{ - wrmsr(HV_X64_MSR_SINT0 + sint, 0xff | HV_SYNIC_SINT_MASKED); -} - -void synic_sint_create(u8 sint, u8 vec, bool auto_eoi) -{ - synic_ctl(HV_TEST_DEV_SINT_ROUTE_CREATE, smp_id(), sint, 0); - sint_enable(sint, vec, auto_eoi); -} - -void synic_sint_set(u8 vcpu, u8 sint) -{ - synic_ctl(HV_TEST_DEV_SINT_ROUTE_SET_SINT, vcpu, sint, 0); -} - -void synic_sint_destroy(u8 sint) -{ - sint_disable(sint); - synic_ctl(HV_TEST_DEV_SINT_ROUTE_DESTROY, smp_id(), sint, 0); -} - -void msg_conn_create(u8 sint, u8 vec, u8 conn_id) -{ - synic_ctl(HV_TEST_DEV_MSG_CONN_CREATE, smp_id(), sint, conn_id); - sint_enable(sint, vec, true); -} - -void msg_conn_destroy(u8 sint, u8 conn_id) -{ - sint_disable(sint); - synic_ctl(HV_TEST_DEV_MSG_CONN_DESTROY, 0, 0, conn_id); -} - -void evt_conn_create(u8 sint, u8 vec, u8 conn_id) -{ - synic_ctl(HV_TEST_DEV_EVT_CONN_CREATE, smp_id(), sint, conn_id); - sint_enable(sint, vec, true); -} - -void evt_conn_destroy(u8 sint, u8 conn_id) -{ - sint_disable(sint); - synic_ctl(HV_TEST_DEV_EVT_CONN_DESTROY, 0, 0, conn_id); -} diff --git a/x86/hyperv.h b/x86/hyperv.h deleted file mode 100644 index e135221f..00000000 --- a/x86/hyperv.h +++ /dev/null @@ -1,217 +0,0 @@ -#ifndef __HYPERV_H -#define __HYPERV_H - -#include "libcflat.h" -#include "processor.h" - -#define HYPERV_CPUID_FEATURES 0x40000003 - -#define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1) -#define HV_X64_MSR_SYNIC_AVAILABLE (1 << 2) -#define HV_X64_MSR_SYNTIMER_AVAILABLE (1 << 3) - -#define HV_X64_MSR_GUEST_OS_ID 0x40000000 -#define HV_X64_MSR_HYPERCALL 0x40000001 - -#define HV_X64_MSR_TIME_REF_COUNT 0x40000020 -#define HV_X64_MSR_REFERENCE_TSC 0x40000021 - -/* Define synthetic interrupt controller model specific registers. */ -#define HV_X64_MSR_SCONTROL 0x40000080 -#define HV_X64_MSR_SVERSION 0x40000081 -#define HV_X64_MSR_SIEFP 0x40000082 -#define HV_X64_MSR_SIMP 0x40000083 -#define HV_X64_MSR_EOM 0x40000084 -#define HV_X64_MSR_SINT0 0x40000090 -#define HV_X64_MSR_SINT1 0x40000091 -#define HV_X64_MSR_SINT2 0x40000092 -#define HV_X64_MSR_SINT3 0x40000093 -#define HV_X64_MSR_SINT4 0x40000094 -#define HV_X64_MSR_SINT5 0x40000095 -#define HV_X64_MSR_SINT6 0x40000096 -#define HV_X64_MSR_SINT7 0x40000097 -#define HV_X64_MSR_SINT8 0x40000098 -#define HV_X64_MSR_SINT9 0x40000099 -#define HV_X64_MSR_SINT10 0x4000009A -#define HV_X64_MSR_SINT11 0x4000009B -#define HV_X64_MSR_SINT12 0x4000009C -#define HV_X64_MSR_SINT13 0x4000009D -#define HV_X64_MSR_SINT14 0x4000009E -#define HV_X64_MSR_SINT15 0x4000009F - -/* - * Synthetic Timer MSRs. Four timers per vcpu. - */ - -#define HV_X64_MSR_STIMER0_CONFIG 0x400000B0 -#define HV_X64_MSR_STIMER0_COUNT 0x400000B1 -#define HV_X64_MSR_STIMER1_CONFIG 0x400000B2 -#define HV_X64_MSR_STIMER1_COUNT 0x400000B3 -#define HV_X64_MSR_STIMER2_CONFIG 0x400000B4 -#define HV_X64_MSR_STIMER2_COUNT 0x400000B5 -#define HV_X64_MSR_STIMER3_CONFIG 0x400000B6 -#define HV_X64_MSR_STIMER3_COUNT 0x400000B7 - -#define HV_SYNIC_CONTROL_ENABLE (1ULL << 0) -#define HV_SYNIC_SIMP_ENABLE (1ULL << 0) -#define HV_SYNIC_SIEFP_ENABLE (1ULL << 0) -#define HV_SYNIC_SINT_MASKED (1ULL << 16) -#define HV_SYNIC_SINT_AUTO_EOI (1ULL << 17) -#define HV_SYNIC_SINT_VECTOR_MASK (0xFF) -#define HV_SYNIC_SINT_COUNT 16 - -#define HV_STIMER_ENABLE (1ULL << 0) -#define HV_STIMER_PERIODIC (1ULL << 1) -#define HV_STIMER_LAZY (1ULL << 2) -#define HV_STIMER_AUTOENABLE (1ULL << 3) -#define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & 0x0F) - -#define HV_SYNIC_STIMER_COUNT (4) - -/* Define synthetic interrupt controller message constants. */ -#define HV_MESSAGE_SIZE (256) -#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) -#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) - -/* Define hypervisor message types. */ -enum hv_message_type { - HVMSG_NONE = 0x00000000, - - /* Memory access messages. */ - HVMSG_UNMAPPED_GPA = 0x80000000, - HVMSG_GPA_INTERCEPT = 0x80000001, - - /* Timer notification messages. */ - HVMSG_TIMER_EXPIRED = 0x80000010, - - /* Error messages. */ - HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020, - HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021, - HVMSG_UNSUPPORTED_FEATURE = 0x80000022, - - /* Trace buffer complete messages. */ - HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040, - - /* Platform-specific processor intercept messages. */ - HVMSG_X64_IOPORT_INTERCEPT = 0x80010000, - HVMSG_X64_MSR_INTERCEPT = 0x80010001, - HVMSG_X64_CPUID_INTERCEPT = 0x80010002, - HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003, - HVMSG_X64_APIC_EOI = 0x80010004, - HVMSG_X64_LEGACY_FP_ERROR = 0x80010005 -}; - -/* Define synthetic interrupt controller message flags. */ -union hv_message_flags { - uint8_t asu8; - struct { - uint8_t msg_pending:1; - uint8_t reserved:7; - }; -}; - -union hv_port_id { - uint32_t asu32; - struct { - uint32_t id:24; - uint32_t reserved:8; - } u; -}; - -/* Define port type. */ -enum hv_port_type { - HVPORT_MSG = 1, - HVPORT_EVENT = 2, - HVPORT_MONITOR = 3 -}; - -/* Define synthetic interrupt controller message header. */ -struct hv_message_header { - uint32_t message_type; - uint8_t payload_size; - union hv_message_flags message_flags; - uint8_t reserved[2]; - union { - uint64_t sender; - union hv_port_id port; - }; -}; - -/* Define timer message payload structure. */ -struct hv_timer_message_payload { - uint32_t timer_index; - uint32_t reserved; - uint64_t expiration_time; /* When the timer expired */ - uint64_t delivery_time; /* When the message was delivered */ -}; - -/* Define synthetic interrupt controller message format. */ -struct hv_message { - struct hv_message_header header; - union { - uint64_t payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; - } u; -}; - -/* Define the synthetic interrupt message page layout. */ -struct hv_message_page { - struct hv_message sint_message[HV_SYNIC_SINT_COUNT]; -}; - -#define HV_EVENT_FLAGS_COUNT (256 * 8) - -struct hv_event_flags { - ulong flags[HV_EVENT_FLAGS_COUNT / (8 * sizeof(ulong))]; -}; - -struct hv_event_flags_page { - struct hv_event_flags slot[HV_SYNIC_SINT_COUNT]; -}; - -#define HV_X64_MSR_HYPERCALL_ENABLE 0x1 - -#define HV_HYPERCALL_FAST (1u << 16) - -#define HVCALL_POST_MESSAGE 0x5c -#define HVCALL_SIGNAL_EVENT 0x5d - -struct hv_input_post_message { - u32 connectionid; - u32 reserved; - u32 message_type; - u32 payload_size; - u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; -}; - -static inline bool synic_supported(void) -{ - return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_SYNIC_AVAILABLE; -} - -static inline bool stimer_supported(void) -{ - return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_SYNIC_AVAILABLE; -} - -static inline bool hv_time_ref_counter_supported(void) -{ - return cpuid(HYPERV_CPUID_FEATURES).a & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE; -} - -void synic_sint_create(u8 sint, u8 vec, bool auto_eoi); -void synic_sint_set(u8 vcpu, u8 sint); -void synic_sint_destroy(u8 sint); -void msg_conn_create(u8 sint, u8 vec, u8 conn_id); -void msg_conn_destroy(u8 sint, u8 conn_id); -void evt_conn_create(u8 sint, u8 vec, u8 conn_id); -void evt_conn_destroy(u8 sint, u8 conn_id); - -struct hv_reference_tsc_page { - uint32_t tsc_sequence; - uint32_t res1; - uint64_t tsc_scale; - int64_t tsc_offset; -}; - - -#endif diff --git a/x86/hyperv_clock.c b/x86/hyperv_clock.c deleted file mode 100644 index b4cfc9fd..00000000 --- a/x86/hyperv_clock.c +++ /dev/null @@ -1,195 +0,0 @@ -#include "libcflat.h" -#include "smp.h" -#include "atomic.h" -#include "processor.h" -#include "hyperv.h" -#include "vm.h" -#include "alloc_page.h" - -#define MAX_CPU 4 -#define TICKS_PER_SEC (1000000000 / 100) - -struct hv_reference_tsc_page *hv_clock; - -/* - * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, - * yielding a 64-bit result. - */ -static inline u64 scale_delta(u64 delta, u64 mul_frac) -{ - u64 product, unused; - - __asm__ ( - "mulq %3" - : "=d" (product), "=a" (unused) : "1" (delta), "rm" ((u64)mul_frac) ); - - return product; -} - -static u64 hvclock_tsc_to_ticks(struct hv_reference_tsc_page *shadow, uint64_t tsc) -{ - u64 delta = tsc; - return scale_delta(delta, shadow->tsc_scale) + shadow->tsc_offset; -} - -/* - * Reads a consistent set of time-base values from hypervisor, - * into a shadow data area. - */ -static void hvclock_get_time_values(struct hv_reference_tsc_page *shadow, - struct hv_reference_tsc_page *page) -{ - int seq; - do { - seq = page->tsc_sequence; - rmb(); /* fetch version before data */ - *shadow = *page; - rmb(); /* test version after fetching data */ - } while (shadow->tsc_sequence != seq); -} - -static uint64_t hv_clock_read(void) -{ - struct hv_reference_tsc_page shadow; - - hvclock_get_time_values(&shadow, hv_clock); - return hvclock_tsc_to_ticks(&shadow, rdtsc()); -} - -bool ok[MAX_CPU]; -uint64_t loops[MAX_CPU]; - -#define iabs(x) ((x) < 0 ? -(x) : (x)) - -static void hv_clock_test(void *data) -{ - int i = smp_id(); - uint64_t t = rdmsr(HV_X64_MSR_TIME_REF_COUNT); - uint64_t end = t + 3 * TICKS_PER_SEC; - uint64_t msr_sample = t + TICKS_PER_SEC; - int min_delta = 123456, max_delta = -123456; - bool got_drift = false; - bool got_warp = false; - - ok[i] = true; - do { - uint64_t now = hv_clock_read(); - int delta = rdmsr(HV_X64_MSR_TIME_REF_COUNT) - now; - - min_delta = delta < min_delta ? delta : min_delta; - if (t < msr_sample) { - max_delta = delta > max_delta ? delta: max_delta; - } else if (delta < 0 || delta > max_delta * 3 / 2) { - printf("suspecting drift on CPU %d? delta = %d, acceptable [0, %d)\n", smp_id(), - delta, max_delta); - ok[i] = false; - got_drift = true; - max_delta *= 2; - } - - if (now < t && !got_warp) { - printf("warp on CPU %d!\n", smp_id()); - ok[i] = false; - got_warp = true; - break; - } - t = now; - } while(t < end); - - if (!got_drift) - printf("delta on CPU %d was %d...%d\n", smp_id(), min_delta, max_delta); - barrier(); -} - -static void check_test(int ncpus) -{ - int i; - bool pass; - - on_cpus(hv_clock_test, NULL); - - pass = true; - for (i = ncpus - 1; i >= 0; i--) - pass &= ok[i]; - - report(pass, "TSC reference precision test"); -} - -static void hv_perf_test(void *data) -{ - uint64_t t = hv_clock_read(); - uint64_t end = t + 1000000000 / 100; - uint64_t local_loops = 0; - - do { - t = hv_clock_read(); - local_loops++; - } while(t < end); - - loops[smp_id()] = local_loops; -} - -static void perf_test(int ncpus) -{ - int i; - uint64_t total_loops; - - on_cpus(hv_perf_test, NULL); - - total_loops = 0; - for (i = ncpus - 1; i >= 0; i--) - total_loops += loops[i]; - printf("iterations/sec: %" PRId64"\n", total_loops / ncpus); -} - -int main(int ac, char **av) -{ - int nerr = 0; - int ncpus; - struct hv_reference_tsc_page shadow; - uint64_t tsc1, t1, tsc2, t2; - uint64_t ref1, ref2; - - setup_vm(); - - ncpus = cpu_count(); - if (ncpus > MAX_CPU) - report_abort("number cpus exceeds %d", MAX_CPU); - - hv_clock = alloc_page(); - wrmsr(HV_X64_MSR_REFERENCE_TSC, (u64)(uintptr_t)hv_clock | 1); - report(rdmsr(HV_X64_MSR_REFERENCE_TSC) == ((u64)(uintptr_t)hv_clock | 1), - "MSR value after enabling"); - - hvclock_get_time_values(&shadow, hv_clock); - if (shadow.tsc_sequence == 0 || shadow.tsc_sequence == 0xFFFFFFFF) { - printf("Reference TSC page not available\n"); - exit(1); - } - - printf("scale: %" PRIx64" offset: %" PRId64"\n", shadow.tsc_scale, shadow.tsc_offset); - ref1 = rdmsr(HV_X64_MSR_TIME_REF_COUNT); - tsc1 = rdtsc(); - t1 = hvclock_tsc_to_ticks(&shadow, tsc1); - printf("refcnt %" PRId64", TSC %" PRIx64", TSC reference %" PRId64"\n", - ref1, tsc1, t1); - - do - ref2 = rdmsr(HV_X64_MSR_TIME_REF_COUNT); - while (ref2 < ref1 + 2 * TICKS_PER_SEC); - - tsc2 = rdtsc(); - t2 = hvclock_tsc_to_ticks(&shadow, tsc2); - printf("refcnt %" PRId64" (delta %" PRId64"), TSC %" PRIx64", " - "TSC reference %" PRId64" (delta %" PRId64")\n", - ref2, ref2 - ref1, tsc2, t2, t2 - t1); - - check_test(ncpus); - perf_test(ncpus); - - wrmsr(HV_X64_MSR_REFERENCE_TSC, 0LL); - report(rdmsr(HV_X64_MSR_REFERENCE_TSC) == 0, - "MSR value after disabling"); - - return nerr > 0 ? 1 : 0; -} diff --git a/x86/hyperv_connections.c b/x86/hyperv_connections.c deleted file mode 100644 index 6e8ac32f..00000000 --- a/x86/hyperv_connections.c +++ /dev/null @@ -1,332 +0,0 @@ -#include "libcflat.h" -#include "vm.h" -#include "smp.h" -#include "isr.h" -#include "atomic.h" -#include "hyperv.h" -#include "bitops.h" -#include "alloc_page.h" - -#define MAX_CPUS 64 - -#define MSG_VEC 0xb0 -#define EVT_VEC 0xb1 -#define MSG_SINT 0x8 -#define EVT_SINT 0x9 -#define MSG_CONN_BASE 0x10 -#define EVT_CONN_BASE 0x20 -#define MSG_TYPE 0x12345678 - -#define WAIT_CYCLES 10000000 - -static atomic_t ncpus_done; - -struct hv_vcpu { - struct hv_message_page *msg_page; - struct hv_event_flags_page *evt_page; - struct hv_input_post_message *post_msg; - u8 msg_conn; - u8 evt_conn; - u64 hvcall_status; - atomic_t sint_received; -}; - -static struct hv_vcpu hv_vcpus[MAX_CPUS]; - -static void sint_isr(isr_regs_t *regs) -{ - atomic_inc(&hv_vcpus[smp_id()].sint_received); -} - -static void *hypercall_page; - -static void setup_hypercall(void) -{ - u64 guestid = (0x8f00ull << 48); - - hypercall_page = alloc_page(); - if (!hypercall_page) - report_abort("failed to allocate hypercall page"); - - wrmsr(HV_X64_MSR_GUEST_OS_ID, guestid); - - wrmsr(HV_X64_MSR_HYPERCALL, - (u64)virt_to_phys(hypercall_page) | HV_X64_MSR_HYPERCALL_ENABLE); -} - -static void teardown_hypercall(void) -{ - wrmsr(HV_X64_MSR_HYPERCALL, 0); - wrmsr(HV_X64_MSR_GUEST_OS_ID, 0); - free_page(hypercall_page); -} - -static u64 do_hypercall(u16 code, u64 arg, bool fast) -{ - u64 ret; - u64 ctl = code; - if (fast) - ctl |= HV_HYPERCALL_FAST; - - asm volatile ("call *%[hcall_page]" -#ifdef __x86_64__ - "\n mov $0,%%r8" - : "=a"(ret) - : "c"(ctl), "d"(arg), -#else - : "=A"(ret) - : "A"(ctl), - "b" ((u32)(arg >> 32)), "c" ((u32)arg), - "D"(0), "S"(0), -#endif - [hcall_page] "m" (hypercall_page) -#ifdef __x86_64__ - : "r8" -#endif - ); - - return ret; -} - -static void setup_cpu(void *ctx) -{ - int vcpu; - struct hv_vcpu *hv; - - write_cr3((ulong)ctx); - irq_enable(); - - vcpu = smp_id(); - hv = &hv_vcpus[vcpu]; - - hv->msg_page = alloc_page(); - hv->evt_page = alloc_page(); - hv->post_msg = alloc_page(); - if (!hv->msg_page || !hv->evt_page || !hv->post_msg) - report_abort("failed to allocate synic pages for vcpu"); - hv->msg_conn = MSG_CONN_BASE + vcpu; - hv->evt_conn = EVT_CONN_BASE + vcpu; - - wrmsr(HV_X64_MSR_SIMP, - (u64)virt_to_phys(hv->msg_page) | HV_SYNIC_SIMP_ENABLE); - wrmsr(HV_X64_MSR_SIEFP, - (u64)virt_to_phys(hv->evt_page) | HV_SYNIC_SIEFP_ENABLE); - wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE); - - msg_conn_create(MSG_SINT, MSG_VEC, hv->msg_conn); - evt_conn_create(EVT_SINT, EVT_VEC, hv->evt_conn); - - hv->post_msg->connectionid = hv->msg_conn; - hv->post_msg->message_type = MSG_TYPE; - hv->post_msg->payload_size = 8; - hv->post_msg->payload[0] = (u64)vcpu << 16; -} - -static void teardown_cpu(void *ctx) -{ - int vcpu = smp_id(); - struct hv_vcpu *hv = &hv_vcpus[vcpu]; - - evt_conn_destroy(EVT_SINT, hv->evt_conn); - msg_conn_destroy(MSG_SINT, hv->msg_conn); - - wrmsr(HV_X64_MSR_SCONTROL, 0); - wrmsr(HV_X64_MSR_SIEFP, 0); - wrmsr(HV_X64_MSR_SIMP, 0); - - free_page(hv->post_msg); - free_page(hv->evt_page); - free_page(hv->msg_page); -} - -static void do_msg(void *ctx) -{ - int vcpu = (ulong)ctx; - struct hv_vcpu *hv = &hv_vcpus[vcpu]; - struct hv_input_post_message *msg = hv->post_msg; - - msg->payload[0]++; - atomic_set(&hv->sint_received, 0); - hv->hvcall_status = do_hypercall(HVCALL_POST_MESSAGE, - virt_to_phys(msg), 0); - atomic_inc(&ncpus_done); -} - -static void clear_msg(void *ctx) -{ - /* should only be done on the current vcpu */ - int vcpu = smp_id(); - struct hv_vcpu *hv = &hv_vcpus[vcpu]; - struct hv_message *msg = &hv->msg_page->sint_message[MSG_SINT]; - - atomic_set(&hv->sint_received, 0); - msg->header.message_type = 0; - barrier(); - wrmsr(HV_X64_MSR_EOM, 0); - atomic_inc(&ncpus_done); -} - -static bool msg_ok(int vcpu) -{ - struct hv_vcpu *hv = &hv_vcpus[vcpu]; - struct hv_input_post_message *post_msg = hv->post_msg; - struct hv_message *msg = &hv->msg_page->sint_message[MSG_SINT]; - - return msg->header.message_type == post_msg->message_type && - msg->header.payload_size == post_msg->payload_size && - msg->header.message_flags.msg_pending == 0 && - msg->u.payload[0] == post_msg->payload[0] && - hv->hvcall_status == 0 && - atomic_read(&hv->sint_received) == 1; -} - -static bool msg_busy(int vcpu) -{ - struct hv_vcpu *hv = &hv_vcpus[vcpu]; - struct hv_input_post_message *post_msg = hv->post_msg; - struct hv_message *msg = &hv->msg_page->sint_message[MSG_SINT]; - - return msg->header.message_type == post_msg->message_type && - msg->header.payload_size == post_msg->payload_size && - msg->header.message_flags.msg_pending == 1 && - msg->u.payload[0] == post_msg->payload[0] - 1 && - hv->hvcall_status == 0 && - atomic_read(&hv->sint_received) == 0; -} - -static void do_evt(void *ctx) -{ - int vcpu = (ulong)ctx; - struct hv_vcpu *hv = &hv_vcpus[vcpu]; - - atomic_set(&hv->sint_received, 0); - hv->hvcall_status = do_hypercall(HVCALL_SIGNAL_EVENT, - hv->evt_conn, 1); - atomic_inc(&ncpus_done); -} - -static void clear_evt(void *ctx) -{ - /* should only be done on the current vcpu */ - int vcpu = smp_id(); - struct hv_vcpu *hv = &hv_vcpus[vcpu]; - ulong *flags = hv->evt_page->slot[EVT_SINT].flags; - - atomic_set(&hv->sint_received, 0); - flags[BIT_WORD(hv->evt_conn)] &= ~BIT_MASK(hv->evt_conn); - barrier(); - atomic_inc(&ncpus_done); -} - -static bool evt_ok(int vcpu) -{ - struct hv_vcpu *hv = &hv_vcpus[vcpu]; - ulong *flags = hv->evt_page->slot[EVT_SINT].flags; - - return flags[BIT_WORD(hv->evt_conn)] == BIT_MASK(hv->evt_conn) && - hv->hvcall_status == 0 && - atomic_read(&hv->sint_received) == 1; -} - -static bool evt_busy(int vcpu) -{ - struct hv_vcpu *hv = &hv_vcpus[vcpu]; - ulong *flags = hv->evt_page->slot[EVT_SINT].flags; - - return flags[BIT_WORD(hv->evt_conn)] == BIT_MASK(hv->evt_conn) && - hv->hvcall_status == 0 && - atomic_read(&hv->sint_received) == 0; -} - -static int run_test(int ncpus, int dst_add, ulong wait_cycles, - void (*func)(void *), bool (*is_ok)(int)) -{ - int i, ret = 0; - - atomic_set(&ncpus_done, 0); - for (i = 0; i < ncpus; i++) { - ulong dst = (i + dst_add) % ncpus; - on_cpu_async(i, func, (void *)dst); - } - while (atomic_read(&ncpus_done) != ncpus) - pause(); - - while (wait_cycles--) - pause(); - - if (is_ok) - for (i = 0; i < ncpus; i++) - ret += is_ok(i); - return ret; -} - -#define HV_STATUS_INVALID_HYPERCALL_CODE 2 - -int main(int ac, char **av) -{ - int ncpus, ncpus_ok, i; - - if (!synic_supported()) { - report_skip("Hyper-V SynIC is not supported"); - goto summary; - } - - setup_vm(); - ncpus = cpu_count(); - if (ncpus > MAX_CPUS) - report_abort("# cpus: %d > %d", ncpus, MAX_CPUS); - - handle_irq(MSG_VEC, sint_isr); - handle_irq(EVT_VEC, sint_isr); - - setup_hypercall(); - - if (do_hypercall(HVCALL_SIGNAL_EVENT, 0x1234, 1) == - HV_STATUS_INVALID_HYPERCALL_CODE) { - report_skip("Hyper-V SynIC connections are not supported"); - goto summary; - } - - for (i = 0; i < ncpus; i++) - on_cpu(i, setup_cpu, (void *)read_cr3()); - - ncpus_ok = run_test(ncpus, 0, WAIT_CYCLES, do_msg, msg_ok); - report(ncpus_ok == ncpus, "send message to self: %d/%d", ncpus_ok, - ncpus); - - run_test(ncpus, 0, 0, clear_msg, NULL); - - ncpus_ok = run_test(ncpus, 1, WAIT_CYCLES, do_msg, msg_ok); - report(ncpus_ok == ncpus, "send message to another cpu: %d/%d", - ncpus_ok, ncpus); - - ncpus_ok = run_test(ncpus, 1, WAIT_CYCLES, do_msg, msg_busy); - report(ncpus_ok == ncpus, "send message to busy slot: %d/%d", - ncpus_ok, ncpus); - - ncpus_ok = run_test(ncpus, 0, WAIT_CYCLES, clear_msg, msg_ok); - report(ncpus_ok == ncpus, "receive pending message: %d/%d", ncpus_ok, - ncpus); - - ncpus_ok = run_test(ncpus, 0, WAIT_CYCLES, do_evt, evt_ok); - report(ncpus_ok == ncpus, "signal event on self: %d/%d", ncpus_ok, - ncpus); - - run_test(ncpus, 0, 0, clear_evt, NULL); - - ncpus_ok = run_test(ncpus, 1, WAIT_CYCLES, do_evt, evt_ok); - report(ncpus_ok == ncpus, "signal event on another cpu: %d/%d", - ncpus_ok, ncpus); - - ncpus_ok = run_test(ncpus, 1, WAIT_CYCLES, do_evt, evt_busy); - report(ncpus_ok == ncpus, "signal event already set: %d/%d", ncpus_ok, - ncpus); - - for (i = 0; i < ncpus; i++) - on_cpu(i, teardown_cpu, NULL); - - teardown_hypercall(); - -summary: - return report_summary(); -} diff --git a/x86/hyperv_stimer.c b/x86/hyperv_stimer.c deleted file mode 100644 index 75a69a12..00000000 --- a/x86/hyperv_stimer.c +++ /dev/null @@ -1,375 +0,0 @@ -#include "libcflat.h" -#include "processor.h" -#include "msr.h" -#include "isr.h" -#include "vm.h" -#include "apic.h" -#include "desc.h" -#include "smp.h" -#include "atomic.h" -#include "hyperv.h" -#include "asm/barrier.h" -#include "alloc_page.h" - -#define MAX_CPUS 4 - -#define SINT1_VEC 0xF1 -#define SINT2_VEC 0xF2 - -#define SINT1_NUM 2 -#define SINT2_NUM 3 -#define ONE_MS_IN_100NS 10000 - -static struct spinlock g_synic_alloc_lock; - -struct stimer { - int sint; - int index; - atomic_t fire_count; -}; - -struct svcpu { - int vcpu; - void *msg_page; - void *evt_page; - struct stimer timer[HV_SYNIC_STIMER_COUNT]; -}; - -static struct svcpu g_synic_vcpu[MAX_CPUS]; - -static void *synic_alloc_page(void) -{ - void *page; - - spin_lock(&g_synic_alloc_lock); - page = alloc_page(); - spin_unlock(&g_synic_alloc_lock); - return page; -} - -static void synic_free_page(void *page) -{ - spin_lock(&g_synic_alloc_lock); - free_page(page); - spin_unlock(&g_synic_alloc_lock); -} - -static void stimer_init(struct stimer *timer, int index) -{ - memset(timer, 0, sizeof(*timer)); - timer->index = index; -} - -static void synic_enable(void) -{ - int vcpu = smp_id(), i; - struct svcpu *svcpu = &g_synic_vcpu[vcpu]; - - memset(svcpu, 0, sizeof(*svcpu)); - svcpu->vcpu = vcpu; - svcpu->msg_page = synic_alloc_page(); - for (i = 0; i < ARRAY_SIZE(svcpu->timer); i++) { - stimer_init(&svcpu->timer[i], i); - } - wrmsr(HV_X64_MSR_SIMP, (u64)virt_to_phys(svcpu->msg_page) | - HV_SYNIC_SIMP_ENABLE); - wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE); -} - -static void stimer_shutdown(struct stimer *timer) -{ - wrmsr(HV_X64_MSR_STIMER0_CONFIG + 2*timer->index, 0); -} - -static void process_stimer_expired(struct svcpu *svcpu, struct stimer *timer, - u64 expiration_time, u64 delivery_time) -{ - atomic_inc(&timer->fire_count); -} - -static void process_stimer_msg(struct svcpu *svcpu, - struct hv_message *msg, int sint) -{ - struct hv_timer_message_payload *payload = - (struct hv_timer_message_payload *)msg->u.payload; - struct stimer *timer; - - if (msg->header.message_type != HVMSG_TIMER_EXPIRED && - msg->header.message_type != HVMSG_NONE) { - report(false, "invalid Hyper-V SynIC msg type"); - report_summary(); - abort(); - } - - if (msg->header.message_type == HVMSG_NONE) { - return; - } - - if (msg->header.payload_size < sizeof(*payload)) { - report(false, "invalid Hyper-V SynIC msg payload size"); - report_summary(); - abort(); - } - - /* Now process timer expiration message */ - - if (payload->timer_index >= ARRAY_SIZE(svcpu->timer)) { - report(false, "invalid Hyper-V SynIC timer index"); - report_summary(); - abort(); - } - timer = &svcpu->timer[payload->timer_index]; - process_stimer_expired(svcpu, timer, payload->expiration_time, - payload->delivery_time); - - msg->header.message_type = HVMSG_NONE; - mb(); - if (msg->header.message_flags.msg_pending) { - wrmsr(HV_X64_MSR_EOM, 0); - } -} - -static void __stimer_isr(int vcpu) -{ - struct svcpu *svcpu = &g_synic_vcpu[vcpu]; - struct hv_message_page *msg_page; - struct hv_message *msg; - int i; - - - msg_page = (struct hv_message_page *)svcpu->msg_page; - for (i = 0; i < ARRAY_SIZE(msg_page->sint_message); i++) { - msg = &msg_page->sint_message[i]; - process_stimer_msg(svcpu, msg, i); - } -} - -static void stimer_isr(isr_regs_t *regs) -{ - int vcpu = smp_id(); - - __stimer_isr(vcpu); - eoi(); -} - -static void stimer_isr_auto_eoi(isr_regs_t *regs) -{ - int vcpu = smp_id(); - - __stimer_isr(vcpu); -} - -static void stimer_start(struct stimer *timer, - bool auto_enable, bool periodic, - u64 tick_100ns, int sint) -{ - u64 config, count; - - timer->sint = sint; - atomic_set(&timer->fire_count, 0); - - config = 0; - if (periodic) { - config |= HV_STIMER_PERIODIC; - } - - config |= ((u8)(sint & 0xFF)) << 16; - config |= HV_STIMER_ENABLE; - if (auto_enable) { - config |= HV_STIMER_AUTOENABLE; - } - - if (periodic) { - count = tick_100ns; - } else { - count = rdmsr(HV_X64_MSR_TIME_REF_COUNT) + tick_100ns; - } - - if (!auto_enable) { - wrmsr(HV_X64_MSR_STIMER0_COUNT + timer->index*2, count); - wrmsr(HV_X64_MSR_STIMER0_CONFIG + timer->index*2, config); - } else { - wrmsr(HV_X64_MSR_STIMER0_CONFIG + timer->index*2, config); - wrmsr(HV_X64_MSR_STIMER0_COUNT + timer->index*2, count); - } -} - -static void stimers_shutdown(void) -{ - int vcpu = smp_id(), i; - struct svcpu *svcpu = &g_synic_vcpu[vcpu]; - - for (i = 0; i < ARRAY_SIZE(svcpu->timer); i++) { - stimer_shutdown(&svcpu->timer[i]); - } -} - -static void synic_disable(void) -{ - int vcpu = smp_id(); - struct svcpu *svcpu = &g_synic_vcpu[vcpu]; - - wrmsr(HV_X64_MSR_SCONTROL, 0); - wrmsr(HV_X64_MSR_SIMP, 0); - wrmsr(HV_X64_MSR_SIEFP, 0); - synic_free_page(svcpu->msg_page); -} - - -static void stimer_test_prepare(void *ctx) -{ - write_cr3((ulong)ctx); - synic_enable(); - synic_sint_create(SINT1_NUM, SINT1_VEC, false); - synic_sint_create(SINT2_NUM, SINT2_VEC, true); -} - -static void stimer_test_periodic(int vcpu, struct stimer *timer1, - struct stimer *timer2) -{ - /* Check periodic timers */ - stimer_start(timer1, false, true, ONE_MS_IN_100NS, SINT1_NUM); - stimer_start(timer2, false, true, ONE_MS_IN_100NS, SINT2_NUM); - while ((atomic_read(&timer1->fire_count) < 1000) || - (atomic_read(&timer2->fire_count) < 1000)) { - pause(); - } - report(true, "Hyper-V SynIC periodic timers test vcpu %d", vcpu); - stimer_shutdown(timer1); - stimer_shutdown(timer2); -} - -static void stimer_test_one_shot(int vcpu, struct stimer *timer) -{ - /* Check one-shot timer */ - stimer_start(timer, false, false, ONE_MS_IN_100NS, SINT1_NUM); - while (atomic_read(&timer->fire_count) < 1) { - pause(); - } - report(true, "Hyper-V SynIC one-shot test vcpu %d", vcpu); - stimer_shutdown(timer); -} - -static void stimer_test_auto_enable_one_shot(int vcpu, struct stimer *timer) -{ - /* Check auto-enable one-shot timer */ - stimer_start(timer, true, false, ONE_MS_IN_100NS, SINT1_NUM); - while (atomic_read(&timer->fire_count) < 1) { - pause(); - } - report(true, "Hyper-V SynIC auto-enable one-shot timer test vcpu %d", - vcpu); - stimer_shutdown(timer); -} - -static void stimer_test_auto_enable_periodic(int vcpu, struct stimer *timer) -{ - /* Check auto-enable periodic timer */ - stimer_start(timer, true, true, ONE_MS_IN_100NS, SINT1_NUM); - while (atomic_read(&timer->fire_count) < 1000) { - pause(); - } - report(true, "Hyper-V SynIC auto-enable periodic timer test vcpu %d", - vcpu); - stimer_shutdown(timer); -} - -static void stimer_test_one_shot_busy(int vcpu, struct stimer *timer) -{ - struct hv_message_page *msg_page = g_synic_vcpu[vcpu].msg_page; - struct hv_message *msg = &msg_page->sint_message[timer->sint]; - - msg->header.message_type = HVMSG_TIMER_EXPIRED; - wmb(); - - stimer_start(timer, false, false, ONE_MS_IN_100NS, SINT1_NUM); - - do - rmb(); - while (!msg->header.message_flags.msg_pending); - - report(!atomic_read(&timer->fire_count), - "no timer fired while msg slot busy: vcpu %d", vcpu); - - msg->header.message_type = HVMSG_NONE; - wmb(); - wrmsr(HV_X64_MSR_EOM, 0); - - while (atomic_read(&timer->fire_count) < 1) { - pause(); - } - report(true, "timer resumed when msg slot released: vcpu %d", vcpu); - - stimer_shutdown(timer); -} - -static void stimer_test(void *ctx) -{ - int vcpu = smp_id(); - struct svcpu *svcpu = &g_synic_vcpu[vcpu]; - struct stimer *timer1, *timer2; - - irq_enable(); - - timer1 = &svcpu->timer[0]; - timer2 = &svcpu->timer[1]; - - stimer_test_periodic(vcpu, timer1, timer2); - stimer_test_one_shot(vcpu, timer1); - stimer_test_auto_enable_one_shot(vcpu, timer2); - stimer_test_auto_enable_periodic(vcpu, timer1); - stimer_test_one_shot_busy(vcpu, timer1); - - irq_disable(); -} - -static void stimer_test_cleanup(void *ctx) -{ - stimers_shutdown(); - synic_sint_destroy(SINT1_NUM); - synic_sint_destroy(SINT2_NUM); - synic_disable(); -} - -static void stimer_test_all(void) -{ - int ncpus; - - setup_vm(); - enable_apic(); - - ncpus = cpu_count(); - if (ncpus > MAX_CPUS) - report_abort("number cpus exceeds %d", MAX_CPUS); - printf("cpus = %d\n", ncpus); - - handle_irq(SINT1_VEC, stimer_isr); - handle_irq(SINT2_VEC, stimer_isr_auto_eoi); - - on_cpus(stimer_test_prepare, (void *)read_cr3()); - on_cpus(stimer_test, NULL); - on_cpus(stimer_test_cleanup, NULL); -} - -int main(int ac, char **av) -{ - - if (!synic_supported()) { - report(true, "Hyper-V SynIC is not supported"); - goto done; - } - - if (!stimer_supported()) { - report(true, "Hyper-V SynIC timers are not supported"); - goto done; - } - - if (!hv_time_ref_counter_supported()) { - report(true, "Hyper-V time reference counter is not supported"); - goto done; - } - - stimer_test_all(); -done: - return report_summary(); -} diff --git a/x86/hyperv_synic.c b/x86/hyperv_synic.c deleted file mode 100644 index 25121ca1..00000000 --- a/x86/hyperv_synic.c +++ /dev/null @@ -1,185 +0,0 @@ -#include "libcflat.h" -#include "processor.h" -#include "msr.h" -#include "isr.h" -#include "vm.h" -#include "apic.h" -#include "desc.h" -#include "smp.h" -#include "atomic.h" -#include "hyperv.h" -#include "alloc_page.h" - -#define MAX_CPUS 4 - -static atomic_t isr_enter_count[MAX_CPUS]; - -static void synic_sint_auto_eoi_isr(isr_regs_t *regs) -{ - atomic_inc(&isr_enter_count[smp_id()]); -} - -static void synic_sint_isr(isr_regs_t *regs) -{ - atomic_inc(&isr_enter_count[smp_id()]); - eoi(); -} - -struct sint_vec_entry { - int vec; - bool auto_eoi; -}; - -struct sint_vec_entry sint_vecs[HV_SYNIC_SINT_COUNT] = { - {0xB0, false}, - {0xB1, false}, - {0xB2, false}, - {0xB3, true}, - {0xB4, false}, - {0xB5, false}, - {0xB6, false}, - {0xB7, false}, - {0xB8, true}, - {0xB9, false}, - {0xBA, true}, - {0xBB, false}, - {0xBC, false}, - {0xBD, false}, - {0xBE, true}, - {0xBF, false}, -}; - -static void synic_prepare_sint_vecs(void) -{ - bool auto_eoi; - int i, vec; - - for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { - vec = sint_vecs[i].vec; - auto_eoi = sint_vecs[i].auto_eoi; - handle_irq(vec, (auto_eoi) ? synic_sint_auto_eoi_isr : synic_sint_isr); - } -} - -static void synic_sints_prepare(int vcpu) -{ - bool auto_eoi; - int i, vec; - - for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { - vec = sint_vecs[i].vec; - auto_eoi = sint_vecs[i].auto_eoi; - synic_sint_create(i, vec, auto_eoi); - } -} - -static void synic_test_prepare(void *ctx) -{ - u64 r; - int i = 0; - - write_cr3((ulong)ctx); - irq_enable(); - - rdmsr(HV_X64_MSR_SVERSION); - rdmsr(HV_X64_MSR_SIMP); - rdmsr(HV_X64_MSR_SIEFP); - rdmsr(HV_X64_MSR_SCONTROL); - for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { - rdmsr(HV_X64_MSR_SINT0 + i); - } - r = rdmsr(HV_X64_MSR_EOM); - if (r != 0) { - report(false, "Hyper-V SynIC test, EOM read %#" PRIx64, r); - return; - } - - wrmsr(HV_X64_MSR_SIMP, (u64)virt_to_phys(alloc_page()) | - HV_SYNIC_SIMP_ENABLE); - wrmsr(HV_X64_MSR_SIEFP, (u64)virt_to_phys(alloc_page())| - HV_SYNIC_SIEFP_ENABLE); - wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE); - - synic_sints_prepare(smp_id()); -} - -static void synic_sints_test(int dst_vcpu) -{ - int i; - - atomic_set(&isr_enter_count[dst_vcpu], 0); - for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { - synic_sint_set(dst_vcpu, i); - } - - while (atomic_read(&isr_enter_count[dst_vcpu]) != HV_SYNIC_SINT_COUNT) { - pause(); - } -} - -static void synic_test(void *ctx) -{ - int dst_vcpu = (ulong)ctx; - - irq_enable(); - synic_sints_test(dst_vcpu); -} - -static void synic_test_cleanup(void *ctx) -{ - int i; - - irq_enable(); - for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { - synic_sint_destroy(i); - } - - wrmsr(HV_X64_MSR_SCONTROL, 0); - wrmsr(HV_X64_MSR_SIMP, 0); - wrmsr(HV_X64_MSR_SIEFP, 0); -} - -int main(int ac, char **av) -{ - - if (synic_supported()) { - int ncpus, i; - bool ok; - - setup_vm(); - enable_apic(); - - ncpus = cpu_count(); - if (ncpus > MAX_CPUS) - report_abort("number cpus exceeds %d", MAX_CPUS); - printf("ncpus = %d\n", ncpus); - - synic_prepare_sint_vecs(); - - printf("prepare\n"); - on_cpus(synic_test_prepare, (void *)read_cr3()); - - for (i = 0; i < ncpus; i++) { - printf("test %d -> %d\n", i, ncpus - 1 - i); - on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i)); - } - while (cpus_active() > 1) - pause(); - - printf("cleanup\n"); - on_cpus(synic_test_cleanup, NULL); - - ok = true; - for (i = 0; i < ncpus; ++i) { - printf("isr_enter_count[%d] = %d\n", - i, atomic_read(&isr_enter_count[i])); - ok &= atomic_read(&isr_enter_count[i]) == 16; - } - - report(ok, "Hyper-V SynIC test"); - } else { - printf("Hyper-V SynIC is not supported"); - } - - return report_summary(); -} diff --git a/x86/idt_test.c b/x86/idt_test.c deleted file mode 100644 index 5d0fc79d..00000000 --- a/x86/idt_test.c +++ /dev/null @@ -1,41 +0,0 @@ -#include "libcflat.h" -#include "processor.h" -#include "desc.h" - -static int test_ud2(bool *rflags_rf) -{ - asm volatile(ASM_TRY("1f") - "ud2 \n\t" - "1:" :); - *rflags_rf = exception_rflags_rf(); - return exception_vector(); -} - -static int test_gp(bool *rflags_rf) -{ - unsigned long tmp; - - asm volatile("mov $0xffffffff, %0 \n\t" - ASM_TRY("1f") - "mov %0, %%cr4\n\t" - "1:" - : "=a"(tmp)); - *rflags_rf = exception_rflags_rf(); - return exception_vector(); -} - -int main(void) -{ - int r; - bool rflags_rf; - - printf("Starting IDT test\n"); - r = test_gp(&rflags_rf); - report(r == GP_VECTOR, "Testing #GP"); - report(rflags_rf, "Testing #GP rflags.rf"); - r = test_ud2(&rflags_rf); - report(r == UD_VECTOR, "Testing #UD"); - report(rflags_rf, "Testing #UD rflags.rf"); - - return report_summary(); -} diff --git a/x86/init.c b/x86/init.c deleted file mode 100644 index f47d671e..00000000 --- a/x86/init.c +++ /dev/null @@ -1,130 +0,0 @@ -#include "libcflat.h" -#include "apic.h" -#include "asm/io.h" - -#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ -#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ -#define KBD_CCMD_RESET 0xFE /* CPU reset */ - -static inline void kbd_cmd(u8 val) -{ - while (inb(0x64) & 2); - outb(val, 0x64); -} - -static inline u8 kbd_in(void) -{ - kbd_cmd(KBD_CCMD_READ_OUTPORT); - while (inb(0x64) & 2); - return inb(0x60); -} - -static inline void kbd_out(u8 val) -{ - kbd_cmd(KBD_CCMD_WRITE_OUTPORT); - while (inb(0x64) & 2); - outb(val, 0x60); -} - -static inline void rtc_out(u8 reg, u8 val) -{ - outb(reg, 0x70); - outb(val, 0x71); -} - -extern char resume_start, resume_end; - -#define state (*(volatile int *)0x2000) -#define bad (*(volatile int *)0x2004) -#define resumed (*(volatile int *)0x2008) - -int main(int argc, char **argv) -{ - volatile u16 *resume_vector_ptr = (u16 *)0x467L; - char *addr, *resume_vec = (void*)0x1000; - - /* resume execution by indirect jump via 40h:0067h */ - rtc_out(0x0f, 0x0a); - resume_vector_ptr[0] = ((u32)(ulong)resume_vec); - resume_vector_ptr[1] = 0; - - for (addr = &resume_start; addr < &resume_end; addr++) - *resume_vec++ = *addr; - - if (state != 0) { - /* - * Strictly speaking this is a firmware problem, but let's check - * for it as well... - */ - if (resumed != 1) { - printf("Uh, resume vector visited %d times?\n", resumed); - bad |= 2; - } - /* - * Port 92 bit 0 is cleared on system reset. On a soft reset it - * is left to 1. Use this to distinguish INIT from hard reset. - */ - if (resumed != 0 && (inb(0x92) & 1) == 0) { - printf("Uh, hard reset!\n"); - bad |= 1; - } - } - - resumed = 0; - - switch (state++) { - case 0: - printf("testing port 92 init... "); - outb(inb(0x92) & ~1, 0x92); - outb(inb(0x92) | 1, 0x92); - break; - - case 1: - printf("testing kbd controller reset... "); - kbd_cmd(KBD_CCMD_RESET); - break; - - case 2: - printf("testing kbd controller init... "); - kbd_out(kbd_in() & ~1); - break; - - case 3: - printf("testing 0xcf9h init... "); - outb(0, 0xcf9); - outb(4, 0xcf9); - break; - - case 4: - printf("testing init to BSP... "); - apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL - | APIC_DM_INIT, 0); - break; - - case 5: - exit(bad); - } - - /* The resume code will get us back to main. */ - asm("cli; hlt"); - __builtin_unreachable(); -} - -asm ( - ".global resume_start\n" - ".global resume_end\n" - ".code16\n" - "resume_start:\n" - "incb %cs:0x2008\n" // resumed++; - "mov $0x0f, %al\n" // rtc_out(0x0f, 0x00); - "out %al, $0x70\n" - "mov $0x00, %al\n" - "out %al, $0x71\n" - "jmp $0xffff, $0x0000\n" // BIOS reset - "resume_end:\n" -#ifdef __i386__ - ".code32\n" -#else - ".code64\n" -#endif - ); diff --git a/x86/intel-iommu.c b/x86/intel-iommu.c deleted file mode 100644 index 4442fe1f..00000000 --- a/x86/intel-iommu.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Intel IOMMU unit test. - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Authors: - * Peter Xu , - * - * This work is licensed under the terms of the GNU LGPL, version 2 or - * later. - */ - -#include "intel-iommu.h" -#include "pci-edu.h" -#include "x86/apic.h" -#include "vm.h" -#include "alloc_page.h" - -#define VTD_TEST_DMAR_4B ("DMAR 4B memcpy test") -#define VTD_TEST_IR_MSI ("IR MSI") -#define VTD_TEST_IR_IOAPIC ("IR IOAPIC") - -static struct pci_edu_dev edu_dev; - -static void vtd_test_dmar(void) -{ - struct pci_edu_dev *dev = &edu_dev; - void *page = alloc_page(); - - report_prefix_push("vtd_dmar"); - -#define DMA_TEST_WORD (0x12345678) - /* Modify the first 4 bytes of the page */ - *(uint32_t *)page = DMA_TEST_WORD; - - /* - * Map the newly allocated page into IOVA address 0 (size 4K) - * of the device address space. Root entry and context entry - * will be automatically created when needed. - */ - vtd_map_range(dev->pci_dev.bdf, 0, virt_to_phys(page), PAGE_SIZE); - - /* - * DMA the first 4 bytes of the page to EDU device buffer - * offset 0. - */ - edu_dma(dev, 0, 4, 0, false); - - /* - * DMA the first 4 bytes of EDU device buffer into the page - * with offset 4 (so it'll be using 4-7 bytes). - */ - edu_dma(dev, 4, 4, 0, true); - - /* - * Check data match between 0-3 bytes and 4-7 bytes of the - * page. - */ - report(*((uint32_t *)page + 1) == DMA_TEST_WORD, VTD_TEST_DMAR_4B); - - free_page(page); - - report_prefix_pop(); -} - -static volatile bool edu_intr_recved; - -static void edu_isr(isr_regs_t *regs) -{ - edu_intr_recved = true; - eoi(); - edu_reg_writel(&edu_dev, EDU_REG_INTR_ACK, - edu_reg_readl(&edu_dev, EDU_REG_INTR_STATUS)); -} - -static void vtd_test_ir(void) -{ -#define VTD_TEST_VECTOR_IOAPIC (0xed) -#define VTD_TEST_VECTOR_MSI (0xee) - struct pci_edu_dev *dev = &edu_dev; - struct pci_dev *pci_dev = &dev->pci_dev; - - report_prefix_push("vtd_ir"); - - irq_enable(); - - /* This will enable INTx */ - pci_msi_set_enable(pci_dev, false); - vtd_setup_ioapic_irq(pci_dev, VTD_TEST_VECTOR_IOAPIC, - 0, TRIGGER_EDGE); - handle_irq(VTD_TEST_VECTOR_IOAPIC, edu_isr); - - edu_intr_recved = false; - wmb(); - /* Manually trigger INTR */ - edu_reg_writel(dev, EDU_REG_INTR_RAISE, 1); - - while (!edu_intr_recved) - cpu_relax(); - - /* Clear INTR bits */ - edu_reg_writel(dev, EDU_REG_INTR_RAISE, 0); - - /* We are good as long as we reach here */ - report(edu_intr_recved == true, VTD_TEST_IR_IOAPIC); - - /* - * Setup EDU PCI device MSI, using interrupt remapping. By - * default, EDU device is using INTx. - */ - if (!vtd_setup_msi(pci_dev, VTD_TEST_VECTOR_MSI, 0)) { - printf("edu device does not support MSI, skip test\n"); - report_skip(VTD_TEST_IR_MSI); - return; - } - - handle_irq(VTD_TEST_VECTOR_MSI, edu_isr); - - edu_intr_recved = false; - wmb(); - /* Manually trigger INTR */ - edu_reg_writel(dev, EDU_REG_INTR_RAISE, 1); - - while (!edu_intr_recved) - cpu_relax(); - - /* We are good as long as we reach here */ - report(edu_intr_recved == true, VTD_TEST_IR_MSI); - - report_prefix_pop(); -} - -int main(int argc, char *argv[]) -{ - setup_vm(); - - vtd_init(); - - report_prefix_push("vtd_init"); - - report(vtd_readl(DMAR_FSTS_REG) == 0, "fault status check"); - report(vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_QI, "QI enablement"); - report(vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_ROOT, "DMAR table setup"); - report(vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR_TABLE, "IR table setup"); - report(vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_DMAR, "DMAR enablement"); - report(vtd_readl(DMAR_GSTS_REG) & VTD_GCMD_IR, "IR enablement"); - report(vtd_readq(DMAR_CAP_REG) & VTD_CAP_SAGAW, - "DMAR support 39 bits address width"); - report(vtd_readq(DMAR_CAP_REG) & VTD_CAP_SLLPS, - "DMAR support huge pages"); - - report_prefix_pop(); - - if (!edu_init(&edu_dev)) { - printf("Please specify \"-device edu\" to do " - "further IOMMU tests.\n"); - report_skip(VTD_TEST_DMAR_4B); - report_skip(VTD_TEST_IR_IOAPIC); - report_skip(VTD_TEST_IR_MSI); - } else { - printf("Found EDU device:\n"); - pci_dev_print(&edu_dev.pci_dev); - vtd_test_dmar(); - vtd_test_ir(); - } - - return report_summary(); -} diff --git a/x86/ioapic.c b/x86/ioapic.c deleted file mode 100644 index b9f6dd2b..00000000 --- a/x86/ioapic.c +++ /dev/null @@ -1,521 +0,0 @@ -#include "libcflat.h" -#include "apic.h" -#include "vm.h" -#include "smp.h" -#include "desc.h" -#include "isr.h" -#include "delay.h" - -static void toggle_irq_line(unsigned line) -{ - set_irq_line(line, 1); - set_irq_line(line, 0); -} - -static void ioapic_reg_version(void) -{ - u8 version_offset; - uint32_t data_read, data_write; - - version_offset = 0x01; - data_read = ioapic_read_reg(version_offset); - data_write = data_read ^ 0xffffffff; - - ioapic_write_reg(version_offset, data_write); - report(data_read == ioapic_read_reg(version_offset), - "version register read only test"); -} - -static void ioapic_reg_id(void) -{ - u8 id_offset; - uint32_t data_read, data_write, diff; - - id_offset = 0x0; - data_read = ioapic_read_reg(id_offset); - data_write = data_read ^ 0xffffffff; - - ioapic_write_reg(id_offset, data_write); - - diff = data_read ^ ioapic_read_reg(id_offset); - report(diff == 0x0f000000, "id register only bits [24:27] writable"); -} - -static void ioapic_arbitration_id(void) -{ - u8 id_offset, arb_offset; - uint32_t write; - - id_offset = 0x0; - arb_offset = 0x2; - write = 0x0f000000; - - ioapic_write_reg(id_offset, write); - report(ioapic_read_reg(arb_offset) == write, - "arbitration register set by id"); - - ioapic_write_reg(arb_offset, 0x0); - report(ioapic_read_reg(arb_offset) == write, - "arbtration register read only"); -} - -static volatile int g_isr_76; - -static void ioapic_isr_76(isr_regs_t *regs) -{ - ++g_isr_76; - eoi(); -} - -static void test_ioapic_edge_intr(void) -{ - handle_irq(0x76, ioapic_isr_76); - ioapic_set_redir(0x0e, 0x76, TRIGGER_EDGE); - toggle_irq_line(0x0e); - asm volatile ("nop"); - report(g_isr_76 == 1, "edge triggered intr"); -} - -static volatile int g_isr_77; - -static void ioapic_isr_77(isr_regs_t *regs) -{ - ++g_isr_77; - set_irq_line(0x0e, 0); - eoi(); -} - -static void test_ioapic_level_intr(void) -{ - handle_irq(0x77, ioapic_isr_77); - ioapic_set_redir(0x0e, 0x77, TRIGGER_LEVEL); - set_irq_line(0x0e, 1); - asm volatile ("nop"); - report(g_isr_77 == 1, "level triggered intr"); -} - -static int g_78, g_66, g_66_after_78; -static ulong g_66_rip, g_78_rip; - -static void ioapic_isr_78(isr_regs_t *regs) -{ - ++g_78; - g_78_rip = regs->rip; - eoi(); -} - -static void ioapic_isr_66(isr_regs_t *regs) -{ - ++g_66; - if (g_78) - ++g_66_after_78; - g_66_rip = regs->rip; - eoi(); -} - -static void test_ioapic_simultaneous(void) -{ - handle_irq(0x78, ioapic_isr_78); - handle_irq(0x66, ioapic_isr_66); - ioapic_set_redir(0x0e, 0x78, TRIGGER_EDGE); - ioapic_set_redir(0x0f, 0x66, TRIGGER_EDGE); - irq_disable(); - toggle_irq_line(0x0f); - toggle_irq_line(0x0e); - irq_enable(); - asm volatile ("nop"); - report(g_66 && g_78 && g_66_after_78 && g_66_rip == g_78_rip, - "ioapic simultaneous edge interrupts"); -} - -static volatile int g_tmr_79 = -1; - -static void ioapic_isr_79(isr_regs_t *regs) -{ - g_tmr_79 = apic_read_bit(APIC_TMR, 0x79); - set_irq_line(0x0e, 0); - eoi(); -} - -static void test_ioapic_edge_tmr(bool expected_tmr_before) -{ - int tmr_before; - - handle_irq(0x79, ioapic_isr_79); - ioapic_set_redir(0x0e, 0x79, TRIGGER_EDGE); - tmr_before = apic_read_bit(APIC_TMR, 0x79); - toggle_irq_line(0x0e); - asm volatile ("nop"); - report(tmr_before == expected_tmr_before && !g_tmr_79, - "TMR for ioapic edge interrupts (expected %s)", - expected_tmr_before ? "true" : "false"); -} - -static void test_ioapic_level_tmr(bool expected_tmr_before) -{ - int tmr_before; - - handle_irq(0x79, ioapic_isr_79); - ioapic_set_redir(0x0e, 0x79, TRIGGER_LEVEL); - tmr_before = apic_read_bit(APIC_TMR, 0x79); - set_irq_line(0x0e, 1); - asm volatile ("nop"); - report(tmr_before == expected_tmr_before && g_tmr_79, - "TMR for ioapic level interrupts (expected %s)", - expected_tmr_before ? "true" : "false"); -} - -static void toggle_irq_line_0x0e(void *data) -{ - irq_disable(); - delay(IPI_DELAY); - toggle_irq_line(0x0e); - irq_enable(); -} - -static void test_ioapic_edge_tmr_smp(bool expected_tmr_before) -{ - int tmr_before; - int i; - - g_tmr_79 = -1; - handle_irq(0x79, ioapic_isr_79); - ioapic_set_redir(0x0e, 0x79, TRIGGER_EDGE); - tmr_before = apic_read_bit(APIC_TMR, 0x79); - on_cpu_async(1, toggle_irq_line_0x0e, 0); - i = 0; - while(g_tmr_79 == -1) i++; - printf("%d iterations before interrupt received\n", i); - report(tmr_before == expected_tmr_before && !g_tmr_79, - "TMR for ioapic edge interrupts (expected %s)", - expected_tmr_before ? "true" : "false"); -} - -static void set_irq_line_0x0e(void *data) -{ - irq_disable(); - delay(IPI_DELAY); - set_irq_line(0x0e, 1); - irq_enable(); -} - -static void test_ioapic_level_tmr_smp(bool expected_tmr_before) -{ - int i, tmr_before; - - g_tmr_79 = -1; - handle_irq(0x79, ioapic_isr_79); - ioapic_set_redir(0x0e, 0x79, TRIGGER_LEVEL); - tmr_before = apic_read_bit(APIC_TMR, 0x79); - on_cpu_async(1, set_irq_line_0x0e, 0); - i = 0; - while(g_tmr_79 == -1) i++; - printf("%d iterations before interrupt received\n", i); - report(tmr_before == expected_tmr_before && g_tmr_79, - "TMR for ioapic level interrupts (expected %s)", - expected_tmr_before ? "true" : "false"); -} - -static int g_isr_98; - -static void ioapic_isr_98(isr_regs_t *regs) -{ - ++g_isr_98; - if (g_isr_98 == 1) { - set_irq_line(0x0e, 0); - set_irq_line(0x0e, 1); - } - set_irq_line(0x0e, 0); - eoi(); -} - -static void test_ioapic_level_coalesce(void) -{ - handle_irq(0x98, ioapic_isr_98); - ioapic_set_redir(0x0e, 0x98, TRIGGER_LEVEL); - set_irq_line(0x0e, 1); - asm volatile ("nop"); - report(g_isr_98 == 1, "coalesce simultaneous level interrupts"); -} - -static int g_isr_99; - -static void ioapic_isr_99(isr_regs_t *regs) -{ - ++g_isr_99; - set_irq_line(0x0e, 0); - eoi(); -} - -static void test_ioapic_level_sequential(void) -{ - handle_irq(0x99, ioapic_isr_99); - ioapic_set_redir(0x0e, 0x99, TRIGGER_LEVEL); - set_irq_line(0x0e, 1); - set_irq_line(0x0e, 1); - asm volatile ("nop"); - report(g_isr_99 == 2, "sequential level interrupts"); -} - -static volatile int g_isr_9a; - -static void ioapic_isr_9a(isr_regs_t *regs) -{ - ++g_isr_9a; - if (g_isr_9a == 2) - set_irq_line(0x0e, 0); - eoi(); -} - -static void test_ioapic_level_retrigger(void) -{ - int i; - - handle_irq(0x9a, ioapic_isr_9a); - ioapic_set_redir(0x0e, 0x9a, TRIGGER_LEVEL); - - asm volatile ("cli"); - set_irq_line(0x0e, 1); - - for (i = 0; i < 10; i++) { - if (g_isr_9a == 2) - break; - - asm volatile ("sti; hlt; cli"); - } - - asm volatile ("sti"); - - report(g_isr_9a == 2, "retriggered level interrupts without masking"); -} - -static volatile int g_isr_81; - -static void ioapic_isr_81(isr_regs_t *regs) -{ - ++g_isr_81; - set_irq_line(0x0e, 0); - eoi(); -} - -static void test_ioapic_edge_mask(void) -{ - handle_irq(0x81, ioapic_isr_81); - ioapic_set_redir(0x0e, 0x81, TRIGGER_EDGE); - - set_mask(0x0e, true); - set_irq_line(0x0e, 1); - set_irq_line(0x0e, 0); - - asm volatile ("nop"); - report(g_isr_81 == 0, "masked level interrupt"); - - set_mask(0x0e, false); - set_irq_line(0x0e, 1); - - asm volatile ("nop"); - report(g_isr_81 == 1, "unmasked level interrupt"); -} - -static volatile int g_isr_82; - -static void ioapic_isr_82(isr_regs_t *regs) -{ - ++g_isr_82; - set_irq_line(0x0e, 0); - eoi(); -} - -static void test_ioapic_level_mask(void) -{ - handle_irq(0x82, ioapic_isr_82); - ioapic_set_redir(0x0e, 0x82, TRIGGER_LEVEL); - - set_mask(0x0e, true); - set_irq_line(0x0e, 1); - - asm volatile ("nop"); - report(g_isr_82 == 0, "masked level interrupt"); - - set_mask(0x0e, false); - - asm volatile ("nop"); - report(g_isr_82 == 1, "unmasked level interrupt"); -} - -static volatile int g_isr_83; - -static void ioapic_isr_83(isr_regs_t *regs) -{ - ++g_isr_83; - set_mask(0x0e, true); - eoi(); -} - -static void test_ioapic_level_retrigger_mask(void) -{ - handle_irq(0x83, ioapic_isr_83); - ioapic_set_redir(0x0e, 0x83, TRIGGER_LEVEL); - - set_irq_line(0x0e, 1); - asm volatile ("nop"); - set_mask(0x0e, false); - asm volatile ("nop"); - report(g_isr_83 == 2, "retriggered level interrupts with mask"); - - set_irq_line(0x0e, 0); - set_mask(0x0e, false); -} - -static volatile int g_isr_84; - -static void ioapic_isr_84(isr_regs_t *regs) -{ - int line = 0xe; - ioapic_redir_entry_t e; - - ++g_isr_84; - set_irq_line(line, 0); - - e = ioapic_read_redir(line); - e.dest_id = 1; - - // Update only upper part of the register because we only change the - // destination, which resides in the upper part - ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]); - - eoi(); -} - -static void test_ioapic_self_reconfigure(void) -{ - ioapic_redir_entry_t e = { - .vector = 0x84, - .delivery_mode = 0, - .dest_mode = 0, - .dest_id = 0, - .trig_mode = TRIGGER_LEVEL, - }; - - handle_irq(0x84, ioapic_isr_84); - ioapic_write_redir(0xe, e); - set_irq_line(0x0e, 1); - e = ioapic_read_redir(0xe); - report(g_isr_84 == 1 && e.remote_irr == 0, "Reconfigure self"); -} - -static volatile int g_isr_85; - -static void ioapic_isr_85(isr_regs_t *regs) -{ - ++g_isr_85; - set_irq_line(0x0e, 0); - eoi(); -} - -static void test_ioapic_physical_destination_mode(void) -{ - ioapic_redir_entry_t e = { - .vector = 0x85, - .delivery_mode = 0, - .dest_mode = 0, - .dest_id = 0x1, - .trig_mode = TRIGGER_LEVEL, - }; - handle_irq(0x85, ioapic_isr_85); - ioapic_write_redir(0xe, e); - set_irq_line(0x0e, 1); - do { - pause(); - } while(g_isr_85 != 1); - report(g_isr_85 == 1, "ioapic physical destination mode"); -} - -static volatile int g_isr_86; -struct spinlock ioapic_lock; - -static void ioapic_isr_86(isr_regs_t *regs) -{ - spin_lock(&ioapic_lock); - ++g_isr_86; - spin_unlock(&ioapic_lock); - set_irq_line(0x0e, 0); - eoi(); -} - -static void test_ioapic_logical_destination_mode(void) -{ - /* Number of vcpus which are configured/set in dest_id */ - int nr_vcpus = 3; - ioapic_redir_entry_t e = { - .vector = 0x86, - .delivery_mode = 0, - .dest_mode = 1, - .dest_id = 0xd, - .trig_mode = TRIGGER_LEVEL, - }; - handle_irq(0x86, ioapic_isr_86); - ioapic_write_redir(0xe, e); - set_irq_line(0x0e, 1); - do { - pause(); - } while(g_isr_86 < nr_vcpus); - report(g_isr_86 == nr_vcpus, "ioapic logical destination mode"); -} - -static void update_cr3(void *cr3) -{ - write_cr3((ulong)cr3); -} - -int main(void) -{ - setup_vm(); - - on_cpus(update_cr3, (void *)read_cr3()); - mask_pic_interrupts(); - - if (enable_x2apic()) - printf("x2apic enabled\n"); - else - printf("x2apic not detected\n"); - - irq_enable(); - - ioapic_reg_version(); - ioapic_reg_id(); - ioapic_arbitration_id(); - - test_ioapic_edge_intr(); - test_ioapic_level_intr(); - test_ioapic_simultaneous(); - - test_ioapic_level_coalesce(); - test_ioapic_level_sequential(); - test_ioapic_level_retrigger(); - - test_ioapic_edge_mask(); - test_ioapic_level_mask(); - test_ioapic_level_retrigger_mask(); - - test_ioapic_edge_tmr(false); - test_ioapic_level_tmr(false); - test_ioapic_level_tmr(true); - test_ioapic_edge_tmr(true); - - if (cpu_count() > 1) - test_ioapic_physical_destination_mode(); - if (cpu_count() > 3) - test_ioapic_logical_destination_mode(); - - if (cpu_count() > 1) { - test_ioapic_edge_tmr_smp(false); - test_ioapic_level_tmr_smp(false); - test_ioapic_level_tmr_smp(true); - test_ioapic_edge_tmr_smp(true); - - test_ioapic_self_reconfigure(); - } - - return report_summary(); -} diff --git a/x86/ioram.h b/x86/ioram.h deleted file mode 100644 index 2938142b..00000000 --- a/x86/ioram.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __IO_RAM_H -#define __IO_RAM_H - -#define IORAM_BASE_PHYS 0xff000000UL -#define IORAM_LEN 0x10000UL - -#endif diff --git a/x86/kvmclock.c b/x86/kvmclock.c deleted file mode 100644 index de30a5e2..00000000 --- a/x86/kvmclock.c +++ /dev/null @@ -1,289 +0,0 @@ -#include "libcflat.h" -#include "smp.h" -#include "atomic.h" -#include "processor.h" -#include "kvmclock.h" -#include "asm/barrier.h" - -#define unlikely(x) __builtin_expect(!!(x), 0) -#define likely(x) __builtin_expect(!!(x), 1) - - -struct pvclock_vcpu_time_info __attribute__((aligned(4))) hv_clock[MAX_CPU]; -struct pvclock_wall_clock wall_clock; -static unsigned char valid_flags = 0; -static atomic64_t last_value = ATOMIC64_INIT(0); - -/* - * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, - * yielding a 64-bit result. - */ -static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift) -{ - u64 product; -#ifdef __i386__ - u32 tmp1, tmp2; -#endif - - if (shift < 0) - delta >>= -shift; - else - delta <<= shift; - -#ifdef __i386__ - __asm__ ( - "mul %5 ; " - "mov %4,%%eax ; " - "mov %%edx,%4 ; " - "mul %5 ; " - "xor %5,%5 ; " - "add %4,%%eax ; " - "adc %5,%%edx ; " - : "=A" (product), "=r" (tmp1), "=r" (tmp2) - : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) ); -#elif defined(__x86_64__) - __asm__ ( - "mul %%rdx ; shrd $32,%%rdx,%%rax" - : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) ); -#else -#error implement me! -#endif - - return product; -} - -#ifdef __i386__ -# define do_div(n,base) ({ \ - u32 __base = (base); \ - u32 __rem; \ - __rem = ((u64)(n)) % __base; \ - (n) = ((u64)(n)) / __base; \ - __rem; \ - }) -#else -u32 __attribute__((weak)) __div64_32(u64 *n, u32 base); -u32 __attribute__((weak)) __div64_32(u64 *n, u32 base) -{ - u64 rem = *n; - u64 b = base; - u64 res, d = 1; - u32 high = rem >> 32; - - /* Reduce the thing a bit first */ - res = 0; - if (high >= base) { - high /= base; - res = (u64) high << 32; - rem -= (u64) (high*base) << 32; - } - - while ((s64)b > 0 && b < rem) { - b = b+b; - d = d+d; - } - - do { - if (rem >= b) { - rem -= b; - res += d; - } - b >>= 1; - d >>= 1; - } while (d); - - *n = res; - return rem; -} - -# define do_div(n,base) ({ \ - u32 __base = (base); \ - u32 __rem; \ - (void)(((typeof((n)) *)0) == ((u64 *)0)); \ - if (likely(((n) >> 32) == 0)) { \ - __rem = (u32)(n) % __base; \ - (n) = (u32)(n) / __base; \ - } else \ - __rem = __div64_32(&(n), __base); \ - __rem; \ - }) -#endif - -/** - * set_normalized_timespec - set timespec sec and nsec parts and normalize - * - * @ts: pointer to timespec variable to be set - * @sec: seconds to set - * @nsec: nanoseconds to set - * - * Set seconds and nanoseconds field of a timespec variable and - * normalize to the timespec storage format - * - * Note: The tv_nsec part is always in the range of - * 0 <= tv_nsec < NSEC_PER_SEC - * For negative values only the tv_sec field is negative ! - */ -static void set_normalized_timespec(struct timespec *ts, long sec, s64 nsec) -{ - while (nsec >= NSEC_PER_SEC) { - /* - * The following asm() prevents the compiler from - * optimising this loop into a modulo operation. See - * also __iter_div_u64_rem() in include/linux/time.h - */ - asm("" : "+rm"(nsec)); - nsec -= NSEC_PER_SEC; - ++sec; - } - while (nsec < 0) { - asm("" : "+rm"(nsec)); - nsec += NSEC_PER_SEC; - --sec; - } - ts->tv_sec = sec; - ts->tv_nsec = nsec; -} - -static inline -unsigned pvclock_read_begin(const struct pvclock_vcpu_time_info *src) -{ - unsigned version = src->version & ~1; - /* Make sure that the version is read before the data. */ - smp_rmb(); - return version; -} - -static inline -bool pvclock_read_retry(const struct pvclock_vcpu_time_info *src, - unsigned version) -{ - /* Make sure that the version is re-read after the data. */ - smp_rmb(); - return version != src->version; -} - -static inline u64 rdtsc_ordered(void) -{ - /* - * FIXME: on Intel CPUs rmb() aka lfence is sufficient which brings up - * to 2x speedup - */ - mb(); - return rdtsc(); -} - -static inline -cycle_t __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src) -{ - u64 delta = rdtsc_ordered() - src->tsc_timestamp; - cycle_t offset = scale_delta(delta, src->tsc_to_system_mul, - src->tsc_shift); - return src->system_time + offset; -} - -static cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) -{ - unsigned version; - cycle_t ret; - u64 last; - u8 flags; - - do { - version = pvclock_read_begin(src); - ret = __pvclock_read_cycles(src); - flags = src->flags; - } while (pvclock_read_retry(src, version)); - - if ((valid_flags & PVCLOCK_RAW_CYCLE_BIT) || - ((valid_flags & PVCLOCK_TSC_STABLE_BIT) && - (flags & PVCLOCK_TSC_STABLE_BIT))) - return ret; - - /* - * Assumption here is that last_value, a global accumulator, always goes - * forward. If we are less than that, we should not be much smaller. - * We assume there is an error marging we're inside, and then the correction - * does not sacrifice accuracy. - * - * For reads: global may have changed between test and return, - * but this means someone else updated poked the clock at a later time. - * We just need to make sure we are not seeing a backwards event. - * - * For updates: last_value = ret is not enough, since two vcpus could be - * updating at the same time, and one of them could be slightly behind, - * making the assumption that last_value always go forward fail to hold. - */ - last = atomic64_read(&last_value); - do { - if (ret < last) - return last; - last = atomic64_cmpxchg(&last_value, last, ret); - } while (unlikely(last != ret)); - - return ret; -} - -cycle_t kvm_clock_read() -{ - struct pvclock_vcpu_time_info *src; - cycle_t ret; - int index = smp_id(); - - src = &hv_clock[index]; - ret = pvclock_clocksource_read(src); - return ret; -} - -void kvm_clock_init(void *data) -{ - int index = smp_id(); - struct pvclock_vcpu_time_info *hvc = &hv_clock[index]; - - printf("kvm-clock: cpu %d, msr %p\n", index, hvc); - wrmsr(MSR_KVM_SYSTEM_TIME_NEW, (unsigned long)hvc | 1); -} - -void kvm_clock_clear(void *data) -{ - wrmsr(MSR_KVM_SYSTEM_TIME_NEW, 0LL); -} - -static void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock, - struct pvclock_vcpu_time_info *vcpu_time, - struct timespec *ts) -{ - u32 version; - u64 delta; - struct timespec now; - - /* get wallclock at system boot */ - do { - version = wall_clock->version; - rmb(); /* fetch version before time */ - now.tv_sec = wall_clock->sec; - now.tv_nsec = wall_clock->nsec; - rmb(); /* fetch time before checking version */ - } while ((wall_clock->version & 1) || (version != wall_clock->version)); - - delta = pvclock_clocksource_read(vcpu_time); /* time since system boot */ - delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec; - - now.tv_nsec = do_div(delta, NSEC_PER_SEC); - now.tv_sec = delta; - - set_normalized_timespec(ts, now.tv_sec, now.tv_nsec); -} - -void kvm_get_wallclock(struct timespec *ts) -{ - struct pvclock_vcpu_time_info *vcpu_time; - int index = smp_id(); - - wrmsr(MSR_KVM_WALL_CLOCK_NEW, (unsigned long)&wall_clock); - vcpu_time = &hv_clock[index]; - pvclock_read_wallclock(&wall_clock, vcpu_time, ts); -} - -void pvclock_set_flags(unsigned char flags) -{ - valid_flags = flags; -} diff --git a/x86/kvmclock.h b/x86/kvmclock.h deleted file mode 100644 index f823c6db..00000000 --- a/x86/kvmclock.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef KVMCLOCK_H -#define KVMCLOCK_H - -#define MSR_KVM_WALL_CLOCK_NEW 0x4b564d00 -#define MSR_KVM_SYSTEM_TIME_NEW 0x4b564d01 - -#define MAX_CPU 64 - -#define PVCLOCK_TSC_STABLE_BIT (1 << 0) -#define PVCLOCK_RAW_CYCLE_BIT (1 << 7) /* Get raw cycle */ - -# define NSEC_PER_SEC 1000000000ULL - -typedef u64 cycle_t; - -struct pvclock_vcpu_time_info { - u32 version; - u32 pad0; - u64 tsc_timestamp; - u64 system_time; - u32 tsc_to_system_mul; - s8 tsc_shift; - u8 flags; - u8 pad[2]; -} __attribute__((__packed__)); /* 32 bytes */ - -struct pvclock_wall_clock { - u32 version; - u32 sec; - u32 nsec; -} __attribute__((__packed__)); - -struct timespec { - long tv_sec; - long tv_nsec; -}; - -void pvclock_set_flags(unsigned char flags); -cycle_t kvm_clock_read(void); -void kvm_get_wallclock(struct timespec *ts); -void kvm_clock_init(void *data); -void kvm_clock_clear(void *data); - -#endif diff --git a/x86/kvmclock_test.c b/x86/kvmclock_test.c deleted file mode 100644 index de4b5e13..00000000 --- a/x86/kvmclock_test.c +++ /dev/null @@ -1,155 +0,0 @@ -#include "libcflat.h" -#include "smp.h" -#include "atomic.h" -#include "processor.h" -#include "kvmclock.h" - -#define DEFAULT_TEST_LOOPS 100000000L -#define DEFAULT_THRESHOLD 5L - -long loops = DEFAULT_TEST_LOOPS; -long sec = 0; -long threshold = DEFAULT_THRESHOLD; - -struct test_info { - struct spinlock lock; - u64 warps; /* warp count */ - u64 stalls; /* stall count */ - long long worst; /* worst warp */ - volatile cycle_t last; /* last cycle seen by test */ - int check; /* check cycle ? */ -}; - -struct test_info ti[4]; - -static void wallclock_test(void *data) -{ - int *p_err = data; - long ksec, offset; - struct timespec ts; - - kvm_get_wallclock(&ts); - ksec = ts.tv_sec; - - offset = ksec - sec; - printf("Raw nanoseconds value from kvmclock: %" PRIu64 " (cpu %d)\n", kvm_clock_read(), smp_id()); - printf("Seconds get from kvmclock: %ld (cpu %d, offset: %ld)\n", ksec, smp_id(), offset); - - if (offset > threshold || offset < -threshold) { - printf("offset too large!\n"); - (*p_err)++; - } -} - -static void kvm_clock_test(void *data) -{ - struct test_info *hv_test_info = (struct test_info *)data; - long i, check = hv_test_info->check; - - for (i = 0; i < loops; i++){ - cycle_t t0, t1; - long long delta; - - if (check == 0) { - kvm_clock_read(); - continue; - } - - spin_lock(&hv_test_info->lock); - t1 = kvm_clock_read(); - t0 = hv_test_info->last; - hv_test_info->last = kvm_clock_read(); - spin_unlock(&hv_test_info->lock); - - delta = t1 - t0; - if (delta < 0) { - spin_lock(&hv_test_info->lock); - ++hv_test_info->warps; - if (delta < hv_test_info->worst){ - hv_test_info->worst = delta; - printf("Worst warp %lld\n", hv_test_info->worst); - } - spin_unlock(&hv_test_info->lock); - } - if (delta == 0) - ++hv_test_info->stalls; - - if (!((unsigned long)i & 31)) - asm volatile("rep; nop"); - } -} - -static int cycle_test(int check, struct test_info *ti) -{ - unsigned long long begin, end; - - begin = rdtsc(); - - ti->check = check; - on_cpus(kvm_clock_test, ti); - - end = rdtsc(); - - printf("Total vcpus: %d\n", cpu_count()); - printf("Test loops: %ld\n", loops); - if (check == 1) { - printf("Total warps: %" PRId64 "\n", ti->warps); - printf("Total stalls: %" PRId64 "\n", ti->stalls); - printf("Worst warp: %lld\n", ti->worst); - } else - printf("TSC cycles: %lld\n", end - begin); - - return ti->warps ? 1 : 0; -} - -int main(int ac, char **av) -{ - int nerr = 0; - int ncpus; - int i; - - if (ac > 1) - loops = atol(av[1]); - if (ac > 2) - sec = atol(av[2]); - if (ac > 3) - threshold = atol(av[3]); - - ncpus = cpu_count(); - if (ncpus > MAX_CPU) - report_abort("number cpus exceeds %d", MAX_CPU); - - on_cpus(kvm_clock_init, NULL); - - if (ac > 2) { - printf("Wallclock test, threshold %ld\n", threshold); - printf("Seconds get from host: %ld\n", sec); - for (i = 0; i < ncpus; ++i) - on_cpu(i, wallclock_test, &nerr); - } - - printf("Check the stability of raw cycle ...\n"); - pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT - | PVCLOCK_RAW_CYCLE_BIT); - if (cycle_test(1, &ti[0])) - printf("Raw cycle is not stable\n"); - else - printf("Raw cycle is stable\n"); - - pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT); - printf("Monotonic cycle test:\n"); - nerr += cycle_test(1, &ti[1]); - - printf("Measure the performance of raw cycle ...\n"); - pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT - | PVCLOCK_RAW_CYCLE_BIT); - cycle_test(0, &ti[2]); - - printf("Measure the performance of adjusted cycle ...\n"); - pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT); - cycle_test(0, &ti[3]); - - on_cpus(kvm_clock_clear, NULL); - - return nerr > 0 ? 1 : 0; -} diff --git a/x86/memory.c b/x86/memory.c deleted file mode 100644 index 8f610207..00000000 --- a/x86/memory.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Test for x86 cache and memory instructions - * - * Copyright (c) 2015 Red Hat Inc - * - * Authors: - * Eduardo Habkost - * - * This work is licensed under the terms of the GNU GPL, version 2. - */ - -#include "libcflat.h" -#include "desc.h" -#include "processor.h" - -static long target; -static volatile int ud; -static volatile int isize; - -static void handle_ud(struct ex_regs *regs) -{ - ud = 1; - regs->rip += isize; -} - -int main(int ac, char **av) -{ - int expected; - - handle_exception(UD_VECTOR, handle_ud); - - /* 3-byte instructions: */ - isize = 3; - - expected = !this_cpu_has(X86_FEATURE_CLFLUSH); /* CLFLUSH */ - ud = 0; - asm volatile("clflush (%0)" : : "b" (&target)); - report(ud == expected, "clflush (%s)", expected ? "ABSENT" : "present"); - - expected = !this_cpu_has(X86_FEATURE_XMM); /* SSE */ - ud = 0; - asm volatile("sfence"); - report(ud == expected, "sfence (%s)", expected ? "ABSENT" : "present"); - - expected = !this_cpu_has(X86_FEATURE_XMM2); /* SSE2 */ - ud = 0; - asm volatile("lfence"); - report(ud == expected, "lfence (%s)", expected ? "ABSENT" : "present"); - - ud = 0; - asm volatile("mfence"); - report(ud == expected, "mfence (%s)", expected ? "ABSENT" : "present"); - - /* 4-byte instructions: */ - isize = 4; - - expected = !this_cpu_has(X86_FEATURE_CLFLUSHOPT); /* CLFLUSHOPT */ - ud = 0; - /* clflushopt (%rbx): */ - asm volatile(".byte 0x66, 0x0f, 0xae, 0x3b" : : "b" (&target)); - report(ud == expected, "clflushopt (%s)", - expected ? "ABSENT" : "present"); - - expected = !this_cpu_has(X86_FEATURE_CLWB); /* CLWB */ - ud = 0; - /* clwb (%rbx): */ - asm volatile(".byte 0x66, 0x0f, 0xae, 0x33" : : "b" (&target)); - report(ud == expected, "clwb (%s)", expected ? "ABSENT" : "present"); - - ud = 0; - /* clwb requires a memory operand, the following is NOT a valid - * CLWB instruction (modrm == 0xF0). - */ - asm volatile(".byte 0x66, 0x0f, 0xae, 0xf0"); - report(ud, "invalid clwb"); - - expected = !this_cpu_has(X86_FEATURE_PCOMMIT); /* PCOMMIT */ - ud = 0; - /* pcommit: */ - asm volatile(".byte 0x66, 0x0f, 0xae, 0xf8"); - report(ud == expected, "pcommit (%s)", expected ? "ABSENT" : "present"); - - return report_summary(); -} diff --git a/x86/msr.c b/x86/msr.c deleted file mode 100644 index f7539c34..00000000 --- a/x86/msr.c +++ /dev/null @@ -1,113 +0,0 @@ -/* msr tests */ - -#include "libcflat.h" -#include "processor.h" -#include "msr.h" - -struct msr_info { - int index; - const char *name; - struct tc { - int valid; - unsigned long long value; - unsigned long long expected; - } val_pairs[20]; -}; - - -#define addr_64 0x0000123456789abcULL -#define addr_ul (unsigned long)addr_64 - -struct msr_info msr_info[] = -{ - { .index = 0x00000174, .name = "IA32_SYSENTER_CS", - .val_pairs = {{ .valid = 1, .value = 0x1234, .expected = 0x1234}} - }, - { .index = 0x00000175, .name = "MSR_IA32_SYSENTER_ESP", - .val_pairs = {{ .valid = 1, .value = addr_ul, .expected = addr_ul}} - }, - { .index = 0x00000176, .name = "IA32_SYSENTER_EIP", - .val_pairs = {{ .valid = 1, .value = addr_ul, .expected = addr_ul}} - }, - { .index = 0x000001a0, .name = "MSR_IA32_MISC_ENABLE", - // reserved: 1:2, 4:6, 8:10, 13:15, 17, 19:21, 24:33, 35:63 - .val_pairs = {{ .valid = 1, .value = 0x400c51889, .expected = 0x400c51889}} - }, - { .index = 0x00000277, .name = "MSR_IA32_CR_PAT", - .val_pairs = {{ .valid = 1, .value = 0x07070707, .expected = 0x07070707}} - }, - { .index = 0xc0000100, .name = "MSR_FS_BASE", - .val_pairs = {{ .valid = 1, .value = addr_64, .expected = addr_64}} - }, - { .index = 0xc0000101, .name = "MSR_GS_BASE", - .val_pairs = {{ .valid = 1, .value = addr_64, .expected = addr_64}} - }, - { .index = 0xc0000102, .name = "MSR_KERNEL_GS_BASE", - .val_pairs = {{ .valid = 1, .value = addr_64, .expected = addr_64}} - }, -#ifdef __x86_64__ - { .index = 0xc0000080, .name = "MSR_EFER", - .val_pairs = {{ .valid = 1, .value = 0xD00, .expected = 0xD00}} - }, - { .index = 0xc0000082, .name = "MSR_LSTAR", - .val_pairs = {{ .valid = 1, .value = addr_64, .expected = addr_64}} - }, - { .index = 0xc0000083, .name = "MSR_CSTAR", - .val_pairs = {{ .valid = 1, .value = addr_64, .expected = addr_64}} - }, - { .index = 0xc0000084, .name = "MSR_SYSCALL_MASK", - .val_pairs = {{ .valid = 1, .value = 0xffffffff, .expected = 0xffffffff}} - }, -#endif - -// MSR_IA32_DEBUGCTLMSR needs svm feature LBRV -// MSR_VM_HSAVE_PA only AMD host -}; - -static int find_msr_info(int msr_index) -{ - int i; - for (i = 0; i < sizeof(msr_info)/sizeof(msr_info[0]) ; i++) { - if (msr_info[i].index == msr_index) { - return i; - } - } - return -1; -} - -static void test_msr_rw(int msr_index, unsigned long long input, unsigned long long expected) -{ - unsigned long long r = 0; - int index; - const char *sptr; - if ((index = find_msr_info(msr_index)) != -1) { - sptr = msr_info[index].name; - } else { - printf("couldn't find name for msr # %#x, skipping\n", msr_index); - return; - } - wrmsr(msr_index, input); - r = rdmsr(msr_index); - if (expected != r) { - printf("testing %s: output = %#x:%#x expected = %#x:%#x\n", sptr, - (u32)(r >> 32), (u32)r, (u32)(expected >> 32), (u32)expected); - } - report(expected == r, "%s", sptr); -} - -int main(int ac, char **av) -{ - int i, j; - for (i = 0 ; i < sizeof(msr_info) / sizeof(msr_info[0]); i++) { - for (j = 0; j < sizeof(msr_info[i].val_pairs) / sizeof(msr_info[i].val_pairs[0]); j++) { - if (msr_info[i].val_pairs[j].valid) { - test_msr_rw(msr_info[i].index, msr_info[i].val_pairs[j].value, msr_info[i].val_pairs[j].expected); - } else { - break; - } - } - } - - return report_summary(); -} - diff --git a/x86/pcid.c b/x86/pcid.c deleted file mode 100644 index a8dc8cbb..00000000 --- a/x86/pcid.c +++ /dev/null @@ -1,151 +0,0 @@ -/* Basic PCID & INVPCID functionality test */ - -#include "libcflat.h" -#include "processor.h" -#include "desc.h" - -struct invpcid_desc { - unsigned long pcid : 12; - unsigned long rsv : 52; - unsigned long addr : 64; -}; - -static int write_cr0_checking(unsigned long val) -{ - asm volatile(ASM_TRY("1f") - "mov %0, %%cr0\n\t" - "1:": : "r" (val)); - return exception_vector(); -} - -static int invpcid_checking(unsigned long type, void *desc) -{ - asm volatile (ASM_TRY("1f") - ".byte 0x66,0x0f,0x38,0x82,0x18 \n\t" /* invpcid (%rax), %rbx */ - "1:" : : "a" (desc), "b" (type)); - return exception_vector(); -} - -static void test_cpuid_consistency(int pcid_enabled, int invpcid_enabled) -{ - int passed = !(!pcid_enabled && invpcid_enabled); - report(passed, "CPUID consistency"); -} - -static void test_pcid_enabled(void) -{ - int passed = 0; - ulong cr0 = read_cr0(), cr3 = read_cr3(), cr4 = read_cr4(); - - /* try setting CR4.PCIDE, no exception expected */ - if (write_cr4_checking(cr4 | X86_CR4_PCIDE) != 0) - goto report; - - /* try clearing CR0.PG when CR4.PCIDE=1, #GP expected */ - if (write_cr0_checking(cr0 & ~X86_CR0_PG) != GP_VECTOR) - goto report; - - write_cr4(cr4); - - /* try setting CR4.PCIDE when CR3[11:0] != 0 , #GP expected */ - write_cr3(cr3 | 0x001); - if (write_cr4_checking(cr4 | X86_CR4_PCIDE) != GP_VECTOR) - goto report; - write_cr3(cr3); - - passed = 1; - -report: - report(passed, "Test on PCID when enabled"); -} - -static void test_pcid_disabled(void) -{ - int passed = 0; - ulong cr4 = read_cr4(); - - /* try setting CR4.PCIDE, #GP expected */ - if (write_cr4_checking(cr4 | X86_CR4_PCIDE) != GP_VECTOR) - goto report; - - passed = 1; - -report: - report(passed, "Test on PCID when disabled"); -} - -static void test_invpcid_enabled(void) -{ - int passed = 0; - ulong cr4 = read_cr4(); - struct invpcid_desc desc; - desc.rsv = 0; - - /* try executing invpcid when CR4.PCIDE=0, desc.pcid=0 and type=1 - * no exception expected - */ - desc.pcid = 0; - if (invpcid_checking(1, &desc) != 0) - goto report; - - /* try executing invpcid when CR4.PCIDE=0, desc.pcid=1 and type=1 - * #GP expected - */ - desc.pcid = 1; - if (invpcid_checking(1, &desc) != GP_VECTOR) - goto report; - - if (write_cr4_checking(cr4 | X86_CR4_PCIDE) != 0) - goto report; - - /* try executing invpcid when CR4.PCIDE=1 - * no exception expected - */ - desc.pcid = 10; - if (invpcid_checking(2, &desc) != 0) - goto report; - - passed = 1; - -report: - report(passed, "Test on INVPCID when enabled"); -} - -static void test_invpcid_disabled(void) -{ - int passed = 0; - struct invpcid_desc desc; - - /* try executing invpcid, #UD expected */ - if (invpcid_checking(2, &desc) != UD_VECTOR) - goto report; - - passed = 1; - -report: - report(passed, "Test on INVPCID when disabled"); -} - -int main(int ac, char **av) -{ - int pcid_enabled = 0, invpcid_enabled = 0; - - if (this_cpu_has(X86_FEATURE_PCID)) - pcid_enabled = 1; - if (this_cpu_has(X86_FEATURE_INVPCID)) - invpcid_enabled = 1; - - test_cpuid_consistency(pcid_enabled, invpcid_enabled); - - if (pcid_enabled) - test_pcid_enabled(); - else - test_pcid_disabled(); - - if (invpcid_enabled) - test_invpcid_enabled(); - else - test_invpcid_disabled(); - - return report_summary(); -} diff --git a/x86/pku.c b/x86/pku.c deleted file mode 100644 index 4f6086cf..00000000 --- a/x86/pku.c +++ /dev/null @@ -1,145 +0,0 @@ -#include "libcflat.h" -#include "x86/desc.h" -#include "x86/processor.h" -#include "x86/vm.h" -#include "x86/msr.h" - -#define CR0_WP_MASK (1UL << 16) -#define PTE_PKEY_BIT 59 -#define USER_BASE (1 << 24) -#define USER_VAR(v) (*((__typeof__(&(v))) (((unsigned long)&v) + USER_BASE))) - -volatile int pf_count = 0; -volatile unsigned save; -volatile unsigned test; - -static void set_cr0_wp(int wp) -{ - unsigned long cr0 = read_cr0(); - - cr0 &= ~CR0_WP_MASK; - if (wp) - cr0 |= CR0_WP_MASK; - write_cr0(cr0); -} - -void do_pf_tss(unsigned long error_code); -void do_pf_tss(unsigned long error_code) -{ - pf_count++; - save = test; - write_pkru(0); -} - -extern void pf_tss(void); - -asm ("pf_tss: \n\t" -#ifdef __x86_64__ - // no task on x86_64, save/restore caller-save regs - "push %rax; push %rcx; push %rdx; push %rsi; push %rdi\n" - "push %r8; push %r9; push %r10; push %r11\n" - "mov 9*8(%rsp),%rdi\n" -#endif - "call do_pf_tss \n\t" -#ifdef __x86_64__ - "pop %r11; pop %r10; pop %r9; pop %r8\n" - "pop %rdi; pop %rsi; pop %rdx; pop %rcx; pop %rax\n" -#endif - "add $"S", %"R "sp\n\t" // discard error code - "iret"W" \n\t" - "jmp pf_tss\n\t" - ); - -static void init_test(void) -{ - pf_count = 0; - - invlpg(&test); - invlpg(&USER_VAR(test)); - write_pkru(0); - set_cr0_wp(0); -} - -int main(int ac, char **av) -{ - unsigned long i; - unsigned int pkey = 0x2; - unsigned int pkru_ad = 0x10; - unsigned int pkru_wd = 0x20; - - if (!this_cpu_has(X86_FEATURE_PKU)) { - printf("PKU not enabled\n"); - return report_summary(); - } - - setup_vm(); - setup_alt_stack(); - set_intr_alt_stack(14, pf_tss); - wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_LMA); - - for (i = 0; i < USER_BASE; i += PAGE_SIZE) { - *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) &= ~PT_USER_MASK; - *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) |= ((unsigned long)pkey << PTE_PKEY_BIT); - invlpg((void *)i); - } - - for (i = USER_BASE; i < 2 * USER_BASE; i += PAGE_SIZE) { - *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) &= ~USER_BASE; - *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) |= ((unsigned long)pkey << PTE_PKEY_BIT); - invlpg((void *)i); - } - - write_cr4(read_cr4() | X86_CR4_PKE); - write_cr3(read_cr3()); - - init_test(); - set_cr0_wp(1); - write_pkru(pkru_ad); - test = 21; - report(pf_count == 0 && test == 21, - "write to supervisor page when pkru is ad and wp == 1"); - - init_test(); - set_cr0_wp(0); - write_pkru(pkru_ad); - test = 22; - report(pf_count == 0 && test == 22, - "write to supervisor page when pkru is ad and wp == 0"); - - init_test(); - set_cr0_wp(1); - write_pkru(pkru_wd); - test = 23; - report(pf_count == 0 && test == 23, - "write to supervisor page when pkru is wd and wp == 1"); - - init_test(); - set_cr0_wp(0); - write_pkru(pkru_wd); - test = 24; - report(pf_count == 0 && test == 24, - "write to supervisor page when pkru is wd and wp == 0"); - - init_test(); - write_pkru(pkru_wd); - set_cr0_wp(0); - USER_VAR(test) = 25; - report(pf_count == 0 && test == 25, - "write to user page when pkru is wd and wp == 0"); - - init_test(); - write_pkru(pkru_wd); - set_cr0_wp(1); - USER_VAR(test) = 26; - report(pf_count == 1 && test == 26 && save == 25, - "write to user page when pkru is wd and wp == 1"); - - init_test(); - write_pkru(pkru_ad); - (void)USER_VAR(test); - report(pf_count == 1 && save == 26, "read from user page when pkru is ad"); - - // TODO: implicit kernel access from ring 3 (e.g. int) - - return report_summary(); -} diff --git a/x86/pmu.c b/x86/pmu.c deleted file mode 100644 index 5a3d55b0..00000000 --- a/x86/pmu.c +++ /dev/null @@ -1,568 +0,0 @@ - -#include "x86/msr.h" -#include "x86/processor.h" -#include "x86/apic-defs.h" -#include "x86/apic.h" -#include "x86/desc.h" -#include "x86/isr.h" -#include "alloc.h" - -#include "libcflat.h" -#include - -#define FIXED_CNT_INDEX 32 -#define PC_VECTOR 32 - -#define EVNSEL_EVENT_SHIFT 0 -#define EVNTSEL_UMASK_SHIFT 8 -#define EVNTSEL_USR_SHIFT 16 -#define EVNTSEL_OS_SHIFT 17 -#define EVNTSEL_EDGE_SHIFT 18 -#define EVNTSEL_PC_SHIFT 19 -#define EVNTSEL_INT_SHIFT 20 -#define EVNTSEL_EN_SHIF 22 -#define EVNTSEL_INV_SHIF 23 -#define EVNTSEL_CMASK_SHIFT 24 - -#define EVNTSEL_EN (1 << EVNTSEL_EN_SHIF) -#define EVNTSEL_USR (1 << EVNTSEL_USR_SHIFT) -#define EVNTSEL_OS (1 << EVNTSEL_OS_SHIFT) -#define EVNTSEL_PC (1 << EVNTSEL_PC_SHIFT) -#define EVNTSEL_INT (1 << EVNTSEL_INT_SHIFT) -#define EVNTSEL_INV (1 << EVNTSEL_INV_SHIF) - -#define N 1000000 - -typedef struct { - uint32_t ctr; - uint32_t config; - uint64_t count; - int idx; -} pmu_counter_t; - -union cpuid10_eax { - struct { - unsigned int version_id:8; - unsigned int num_counters:8; - unsigned int bit_width:8; - unsigned int mask_length:8; - } split; - unsigned int full; -} eax; - -union cpuid10_ebx { - struct { - unsigned int no_unhalted_core_cycles:1; - unsigned int no_instructions_retired:1; - unsigned int no_unhalted_reference_cycles:1; - unsigned int no_llc_reference:1; - unsigned int no_llc_misses:1; - unsigned int no_branch_instruction_retired:1; - unsigned int no_branch_misses_retired:1; - } split; - unsigned int full; -} ebx; - -union cpuid10_edx { - struct { - unsigned int num_counters_fixed:5; - unsigned int bit_width_fixed:8; - unsigned int reserved:19; - } split; - unsigned int full; -} edx; - -struct pmu_event { - const char *name; - uint32_t unit_sel; - int min; - int max; -} gp_events[] = { - {"core cycles", 0x003c, 1*N, 50*N}, - {"instructions", 0x00c0, 10*N, 10.2*N}, - {"ref cycles", 0x013c, 0.1*N, 30*N}, - {"llc refference", 0x4f2e, 1, 2*N}, - {"llc misses", 0x412e, 1, 1*N}, - {"branches", 0x00c4, 1*N, 1.1*N}, - {"branch misses", 0x00c5, 0, 0.1*N}, -}, fixed_events[] = { - {"fixed 1", MSR_CORE_PERF_FIXED_CTR0, 10*N, 10.2*N}, - {"fixed 2", MSR_CORE_PERF_FIXED_CTR0 + 1, 1*N, 30*N}, - {"fixed 3", MSR_CORE_PERF_FIXED_CTR0 + 2, 0.1*N, 30*N} -}; - -#define PMU_CAP_FW_WRITES (1ULL << 13) -static u64 gp_counter_base = MSR_IA32_PERFCTR0; - -static int num_counters; - -char *buf; - -static inline void loop(void) -{ - unsigned long tmp, tmp2, tmp3; - - asm volatile("1: mov (%1), %2; add $64, %1; nop; nop; nop; nop; nop; nop; nop; loop 1b" - : "=c"(tmp), "=r"(tmp2), "=r"(tmp3): "0"(N), "1"(buf)); - -} - -volatile uint64_t irq_received; - -static void cnt_overflow(isr_regs_t *regs) -{ - irq_received++; - apic_write(APIC_EOI, 0); -} - -static bool check_irq(void) -{ - int i; - irq_received = 0; - irq_enable(); - for (i = 0; i < 100000 && !irq_received; i++) - asm volatile("pause"); - irq_disable(); - return irq_received; -} - -static bool is_gp(pmu_counter_t *evt) -{ - return evt->ctr < MSR_CORE_PERF_FIXED_CTR0 || - evt->ctr >= MSR_IA32_PMC0; -} - -static int event_to_global_idx(pmu_counter_t *cnt) -{ - return cnt->ctr - (is_gp(cnt) ? gp_counter_base : - (MSR_CORE_PERF_FIXED_CTR0 - FIXED_CNT_INDEX)); -} - -static struct pmu_event* get_counter_event(pmu_counter_t *cnt) -{ - if (is_gp(cnt)) { - int i; - - for (i = 0; i < sizeof(gp_events)/sizeof(gp_events[0]); i++) - if (gp_events[i].unit_sel == (cnt->config & 0xffff)) - return &gp_events[i]; - } else - return &fixed_events[cnt->ctr - MSR_CORE_PERF_FIXED_CTR0]; - - return (void*)0; -} - -static void global_enable(pmu_counter_t *cnt) -{ - cnt->idx = event_to_global_idx(cnt); - - wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_CTRL) | - (1ull << cnt->idx)); -} - -static void global_disable(pmu_counter_t *cnt) -{ - wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_CTRL) & - ~(1ull << cnt->idx)); -} - - -static void start_event(pmu_counter_t *evt) -{ - wrmsr(evt->ctr, evt->count); - if (is_gp(evt)) - wrmsr(MSR_P6_EVNTSEL0 + event_to_global_idx(evt), - evt->config | EVNTSEL_EN); - else { - uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); - int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; - uint32_t usrospmi = 0; - - if (evt->config & EVNTSEL_OS) - usrospmi |= (1 << 0); - if (evt->config & EVNTSEL_USR) - usrospmi |= (1 << 1); - if (evt->config & EVNTSEL_INT) - usrospmi |= (1 << 3); // PMI on overflow - ctrl = (ctrl & ~(0xf << shift)) | (usrospmi << shift); - wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl); - } - global_enable(evt); - apic_write(APIC_LVTPC, PC_VECTOR); -} - -static void stop_event(pmu_counter_t *evt) -{ - global_disable(evt); - if (is_gp(evt)) - wrmsr(MSR_P6_EVNTSEL0 + event_to_global_idx(evt), - evt->config & ~EVNTSEL_EN); - else { - uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); - int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; - wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl & ~(0xf << shift)); - } - evt->count = rdmsr(evt->ctr); -} - -static void measure(pmu_counter_t *evt, int count) -{ - int i; - for (i = 0; i < count; i++) - start_event(&evt[i]); - loop(); - for (i = 0; i < count; i++) - stop_event(&evt[i]); -} - -static bool verify_event(uint64_t count, struct pmu_event *e) -{ - // printf("%lld >= %lld <= %lld\n", e->min, count, e->max); - return count >= e->min && count <= e->max; - -} - -static bool verify_counter(pmu_counter_t *cnt) -{ - return verify_event(cnt->count, get_counter_event(cnt)); -} - -static void check_gp_counter(struct pmu_event *evt) -{ - pmu_counter_t cnt = { - .ctr = gp_counter_base, - .config = EVNTSEL_OS | EVNTSEL_USR | evt->unit_sel, - }; - int i; - - for (i = 0; i < num_counters; i++, cnt.ctr++) { - cnt.count = 0; - measure(&cnt, 1); - report(verify_event(cnt.count, evt), "%s-%d", evt->name, i); - } -} - -static void check_gp_counters(void) -{ - int i; - - for (i = 0; i < sizeof(gp_events)/sizeof(gp_events[0]); i++) - if (!(ebx.full & (1 << i))) - check_gp_counter(&gp_events[i]); - else - printf("GP event '%s' is disabled\n", - gp_events[i].name); -} - -static void check_fixed_counters(void) -{ - pmu_counter_t cnt = { - .config = EVNTSEL_OS | EVNTSEL_USR, - }; - int i; - - for (i = 0; i < edx.split.num_counters_fixed; i++) { - cnt.count = 0; - cnt.ctr = fixed_events[i].unit_sel; - measure(&cnt, 1); - report(verify_event(cnt.count, &fixed_events[i]), "fixed-%d", - i); - } -} - -static void check_counters_many(void) -{ - pmu_counter_t cnt[10]; - int i, n; - - for (i = 0, n = 0; n < num_counters; i++) { - if (ebx.full & (1 << i)) - continue; - - cnt[n].count = 0; - cnt[n].ctr = gp_counter_base + n; - cnt[n].config = EVNTSEL_OS | EVNTSEL_USR | - gp_events[i % ARRAY_SIZE(gp_events)].unit_sel; - n++; - } - for (i = 0; i < edx.split.num_counters_fixed; i++) { - cnt[n].count = 0; - cnt[n].ctr = fixed_events[i].unit_sel; - cnt[n].config = EVNTSEL_OS | EVNTSEL_USR; - n++; - } - - measure(cnt, n); - - for (i = 0; i < n; i++) - if (!verify_counter(&cnt[i])) - break; - - report(i == n, "all counters"); -} - -static void check_counter_overflow(void) -{ - uint64_t count; - int i; - pmu_counter_t cnt = { - .ctr = gp_counter_base, - .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel /* instructions */, - .count = 0, - }; - measure(&cnt, 1); - count = cnt.count; - - /* clear status before test */ - wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_STATUS)); - - report_prefix_push("overflow"); - - for (i = 0; i < num_counters + 1; i++, cnt.ctr++) { - uint64_t status; - int idx; - - cnt.count = 1 - count; - if (gp_counter_base == MSR_IA32_PMC0) - cnt.count &= (1ull << eax.split.bit_width) - 1; - - if (i == num_counters) { - cnt.ctr = fixed_events[0].unit_sel; - cnt.count &= (1ull << edx.split.bit_width_fixed) - 1; - } - - if (i % 2) - cnt.config |= EVNTSEL_INT; - else - cnt.config &= ~EVNTSEL_INT; - idx = event_to_global_idx(&cnt); - measure(&cnt, 1); - report(cnt.count == 1, "cntr-%d", i); - status = rdmsr(MSR_CORE_PERF_GLOBAL_STATUS); - report(status & (1ull << idx), "status-%d", i); - wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, status); - status = rdmsr(MSR_CORE_PERF_GLOBAL_STATUS); - report(!(status & (1ull << idx)), "status clear-%d", i); - report(check_irq() == (i % 2), "irq-%d", i); - } - - report_prefix_pop(); -} - -static void check_gp_counter_cmask(void) -{ - pmu_counter_t cnt = { - .ctr = gp_counter_base, - .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel /* instructions */, - .count = 0, - }; - cnt.config |= (0x2 << EVNTSEL_CMASK_SHIFT); - measure(&cnt, 1); - report(cnt.count < gp_events[1].min, "cmask"); -} - -static void do_rdpmc_fast(void *ptr) -{ - pmu_counter_t *cnt = ptr; - uint32_t idx = (uint32_t)cnt->idx | (1u << 31); - - if (!is_gp(cnt)) - idx |= 1 << 30; - - cnt->count = rdpmc(idx); -} - - -static void check_rdpmc(void) -{ - uint64_t val = 0xff0123456789ull; - bool exc; - int i; - - report_prefix_push("rdpmc"); - - for (i = 0; i < num_counters; i++) { - uint64_t x; - pmu_counter_t cnt = { - .ctr = gp_counter_base + i, - .idx = i - }; - - /* - * Without full-width writes, only the low 32 bits are writable, - * and the value is sign-extended. - */ - if (gp_counter_base == MSR_IA32_PERFCTR0) - x = (uint64_t)(int64_t)(int32_t)val; - else - x = (uint64_t)(int64_t)val; - - /* Mask according to the number of supported bits */ - x &= (1ull << eax.split.bit_width) - 1; - - wrmsr(gp_counter_base + i, val); - report(rdpmc(i) == x, "cntr-%d", i); - - exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); - if (exc) - report_skip("fast-%d", i); - else - report(cnt.count == (u32)val, "fast-%d", i); - } - for (i = 0; i < edx.split.num_counters_fixed; i++) { - uint64_t x = val & ((1ull << edx.split.bit_width_fixed) - 1); - pmu_counter_t cnt = { - .ctr = MSR_CORE_PERF_FIXED_CTR0 + i, - .idx = i - }; - - wrmsr(MSR_CORE_PERF_FIXED_CTR0 + i, x); - report(rdpmc(i | (1 << 30)) == x, "fixed cntr-%d", i); - - exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); - if (exc) - report_skip("fixed fast-%d", i); - else - report(cnt.count == (u32)x, "fixed fast-%d", i); - } - - report_prefix_pop(); -} - -static void check_running_counter_wrmsr(void) -{ - uint64_t status; - uint64_t count; - pmu_counter_t evt = { - .ctr = gp_counter_base, - .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel, - .count = 0, - }; - - report_prefix_push("running counter wrmsr"); - - start_event(&evt); - loop(); - wrmsr(gp_counter_base, 0); - stop_event(&evt); - report(evt.count < gp_events[1].min, "cntr"); - - /* clear status before overflow test */ - wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, - rdmsr(MSR_CORE_PERF_GLOBAL_STATUS)); - - evt.count = 0; - start_event(&evt); - - count = -1; - if (gp_counter_base == MSR_IA32_PMC0) - count &= (1ull << eax.split.bit_width) - 1; - - wrmsr(gp_counter_base, count); - - loop(); - stop_event(&evt); - status = rdmsr(MSR_CORE_PERF_GLOBAL_STATUS); - report(status & 1, "status"); - - report_prefix_pop(); -} - -static void check_counters(void) -{ - check_gp_counters(); - check_fixed_counters(); - check_rdpmc(); - check_counters_many(); - check_counter_overflow(); - check_gp_counter_cmask(); - check_running_counter_wrmsr(); -} - -static void do_unsupported_width_counter_write(void *index) -{ - wrmsr(MSR_IA32_PMC0 + *((int *) index), 0xffffff0123456789ull); -} - -static void check_gp_counters_write_width(void) -{ - u64 val_64 = 0xffffff0123456789ull; - u64 val_32 = val_64 & ((1ull << 32) - 1); - u64 val_max_width = val_64 & ((1ull << eax.split.bit_width) - 1); - int i; - - /* - * MSR_IA32_PERFCTRn supports 64-bit writes, - * but only the lowest 32 bits are valid. - */ - for (i = 0; i < num_counters; i++) { - wrmsr(MSR_IA32_PERFCTR0 + i, val_32); - assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); - assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); - - wrmsr(MSR_IA32_PERFCTR0 + i, val_max_width); - assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); - assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); - - wrmsr(MSR_IA32_PERFCTR0 + i, val_64); - assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); - assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); - } - - /* - * MSR_IA32_PMCn supports writing values ​​up to GP counter width, - * and only the lowest bits of GP counter width are valid. - */ - for (i = 0; i < num_counters; i++) { - wrmsr(MSR_IA32_PMC0 + i, val_32); - assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); - assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); - - wrmsr(MSR_IA32_PMC0 + i, val_max_width); - assert(rdmsr(MSR_IA32_PMC0 + i) == val_max_width); - assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_max_width); - - report(test_for_exception(GP_VECTOR, - do_unsupported_width_counter_write, &i), - "writing unsupported width to MSR_IA32_PMC%d raises #GP", i); - } -} - -int main(int ac, char **av) -{ - struct cpuid id = cpuid(10); - - setup_vm(); - handle_irq(PC_VECTOR, cnt_overflow); - buf = malloc(N*64); - - eax.full = id.a; - ebx.full = id.b; - edx.full = id.d; - - if (!eax.split.version_id) { - printf("No pmu is detected!\n"); - return report_summary(); - } - printf("PMU version: %d\n", eax.split.version_id); - printf("GP counters: %d\n", eax.split.num_counters); - printf("GP counter width: %d\n", eax.split.bit_width); - printf("Mask length: %d\n", eax.split.mask_length); - printf("Fixed counters: %d\n", edx.split.num_counters_fixed); - printf("Fixed counter width: %d\n", edx.split.bit_width_fixed); - - num_counters = eax.split.num_counters; - - apic_write(APIC_LVTPC, PC_VECTOR); - - check_counters(); - - if (rdmsr(MSR_IA32_PERF_CAPABILITIES) & PMU_CAP_FW_WRITES) { - gp_counter_base = MSR_IA32_PMC0; - report_prefix_push("full-width writes"); - check_counters(); - check_gp_counters_write_width(); - } - - return report_summary(); -} diff --git a/x86/port80.c b/x86/port80.c deleted file mode 100644 index 791431c3..00000000 --- a/x86/port80.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "libcflat.h" - -int main(void) -{ - int i; - - printf("begining port 0x80 write test\n"); - for (i = 0; i < 10000000; ++i) - asm volatile("outb %al, $0x80"); - printf("done\n"); - return 0; -} diff --git a/x86/rdpru.c b/x86/rdpru.c deleted file mode 100644 index 5cb69cb6..00000000 --- a/x86/rdpru.c +++ /dev/null @@ -1,23 +0,0 @@ -/* RDPRU test */ - -#include "libcflat.h" -#include "processor.h" -#include "desc.h" - -static int rdpru_checking(void) -{ - asm volatile (ASM_TRY("1f") - ".byte 0x0f,0x01,0xfd \n\t" /* rdpru */ - "1:" : : "c" (0) : "eax", "edx"); - return exception_vector(); -} - -int main(int ac, char **av) -{ - if (this_cpu_has(X86_FEATURE_RDPRU)) - report_skip("RDPRU raises #UD"); - else - report(rdpru_checking() == UD_VECTOR, "RDPRU raises #UD"); - - return report_summary(); -} diff --git a/x86/realmode.c b/x86/realmode.c deleted file mode 100644 index 7c2d7766..00000000 --- a/x86/realmode.c +++ /dev/null @@ -1,1862 +0,0 @@ -#ifndef USE_SERIAL -#define USE_SERIAL -#endif - -#define ARRAY_SIZE(_a) (sizeof(_a)/sizeof((_a)[0])) - -asm(".code16gcc"); - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned u32; -typedef unsigned long long u64; - -#ifndef NULL -#define NULL ((void*)0) -#endif - -void realmode_start(void); -void test_function(void); - -asm( - "test_function: \n\t" - "mov $0x1234, %eax \n\t" - "ret" - ); - -static int strlen(const char *str) -{ - int n; - - for (n = 0; *str; ++str) - ++n; - return n; -} - -static void outb(u8 data, u16 port) -{ - asm volatile("out %0, %1" : : "a"(data), "d"(port)); -} - -#ifdef USE_SERIAL -static int serial_iobase = 0x3f8; -static int serial_inited = 0; - -static u8 inb(u16 port) -{ - u8 data; - asm volatile("in %1, %0" : "=a"(data) : "d"(port)); - return data; -} - -static void serial_outb(char ch) -{ - u8 lsr; - - do { - lsr = inb(serial_iobase + 0x05); - } while (!(lsr & 0x20)); - - outb(ch, serial_iobase + 0x00); -} - -static void serial_init(void) -{ - u8 lcr; - - /* set DLAB */ - lcr = inb(serial_iobase + 0x03); - lcr |= 0x80; - outb(lcr, serial_iobase + 0x03); - - /* set baud rate to 115200 */ - outb(0x01, serial_iobase + 0x00); - outb(0x00, serial_iobase + 0x01); - - /* clear DLAB */ - lcr = inb(serial_iobase + 0x03); - lcr &= ~0x80; - outb(lcr, serial_iobase + 0x03); - - /* IER: disable interrupts */ - outb(0x00, serial_iobase + 0x01); - /* LCR: 8 bits, no parity, one stop bit */ - outb(0x03, serial_iobase + 0x03); - /* FCR: disable FIFO queues */ - outb(0x00, serial_iobase + 0x02); - /* MCR: RTS, DTR on */ - outb(0x03, serial_iobase + 0x04); -} -#endif - -static void print_serial(const char *buf) -{ - unsigned long len = strlen(buf); -#ifdef USE_SERIAL - unsigned long i; - if (!serial_inited) { - serial_init(); - serial_inited = 1; - } - - for (i = 0; i < len; i++) { - serial_outb(buf[i]); - } -#else - asm volatile ("addr32/rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1)); -#endif -} - -static void print_serial_u32(u32 value) -{ - char n[12], *p; - p = &n[11]; - *p = 0; - do { - *--p = '0' + (value % 10); - value /= 10; - } while (value > 0); - print_serial(p); -} - -static int failed; - -static void exit(int code) -{ - outb(code, 0xf4); - - while (1) { - asm volatile("hlt" ::: "memory"); - } -} - -struct regs { - u32 eax, ebx, ecx, edx; - u32 esi, edi, esp, ebp; - u32 eip, eflags; -}; - -struct table_descr { - u16 limit; - void *base; -} __attribute__((packed)); - -static u64 gdt[] = { - 0, - 0x00cf9b000000ffffull, // flat 32-bit code segment - 0x00cf93000000ffffull, // flat 32-bit data segment -}; - -static struct table_descr gdt_descr = { - sizeof(gdt) - 1, - gdt, -}; - -struct insn_desc { - u16 ptr; - u16 len; -}; - -struct { - u32 stack[128]; - char top[]; -} tmp_stack; - -static struct regs inregs, outregs; - -static inline void init_inregs(struct regs *regs) -{ - inregs = (struct regs){ 0 }; - if (regs) - inregs = *regs; - if (!inregs.esp) - inregs.esp = (unsigned long)&tmp_stack.top; -} - -static void exec_in_big_real_mode(struct insn_desc *insn) -{ - unsigned long tmp; - static struct regs save; - int i; - extern u8 test_insn[], test_insn_end[]; - - for (i = 0; i < insn->len; ++i) - test_insn[i] = ((u8 *)(unsigned long)insn->ptr)[i]; - for (; i < test_insn_end - test_insn; ++i) - test_insn[i] = 0x90; // nop - - save = inregs; - asm volatile( - "lgdtl %[gdt_descr] \n\t" - "mov %%cr0, %[tmp] \n\t" - "or $1, %[tmp] \n\t" - "mov %[tmp], %%cr0 \n\t" - "mov %[bigseg], %%gs \n\t" - "and $-2, %[tmp] \n\t" - "mov %[tmp], %%cr0 \n\t" - - /* Save ES, because it is clobbered by some tests. */ - "pushw %%es \n\t" - - "pushw %[save]+36; popfw \n\t" - "xchg %%eax, %[save]+0 \n\t" - "xchg %%ebx, %[save]+4 \n\t" - "xchg %%ecx, %[save]+8 \n\t" - "xchg %%edx, %[save]+12 \n\t" - "xchg %%esi, %[save]+16 \n\t" - "xchg %%edi, %[save]+20 \n\t" - "xchg %%esp, %[save]+24 \n\t" - "xchg %%ebp, %[save]+28 \n\t" - - "test_insn: . = . + 32\n\t" - "test_insn_end: \n\t" - - "xchg %%eax, %[save]+0 \n\t" - "xchg %%ebx, %[save]+4 \n\t" - "xchg %%ecx, %[save]+8 \n\t" - "xchg %%edx, %[save]+12 \n\t" - "xchg %%esi, %[save]+16 \n\t" - "xchg %%edi, %[save]+20 \n\t" - "xchg %%esp, %[save]+24 \n\t" - "xchg %%ebp, %[save]+28 \n\t" - - /* Save EFLAGS in outregs*/ - "pushfl \n\t" - "popl %[save]+36 \n\t" - - /* Restore ES for future rep string operations. */ - "popw %%es \n\t" - - /* Restore DF for the harness code */ - "cld\n\t" - "xor %[tmp], %[tmp] \n\t" - "mov %[tmp], %%gs \n\t" - : [tmp]"=&r"(tmp), [save]"+m"(save) - : [gdt_descr]"m"(gdt_descr), [bigseg]"r"((short)16) - : "cc", "memory" - ); - outregs = save; -} - -#define R_AX 1 -#define R_BX 2 -#define R_CX 4 -#define R_DX 8 -#define R_SI 16 -#define R_DI 32 -#define R_SP 64 -#define R_BP 128 - -static int regs_equal(int ignore) -{ - const u32 *p1 = &inregs.eax, *p2 = &outregs.eax; // yuck - int i; - - for (i = 0; i < 8; ++i) - if (!(ignore & (1 << i)) && p1[i] != p2[i]) - return 0; - return 1; -} - -static void report(const char *name, u16 regs_ignore, _Bool ok) -{ - if (!regs_equal(regs_ignore)) { - ok = 0; - } - print_serial(ok ? "PASS: " : "FAIL: "); - print_serial(name); - print_serial("\n"); - if (!ok) - failed = 1; -} - -#define MK_INSN(name, str) \ - asm ( \ - ".pushsection .data.insn \n\t" \ - "insn_" #name ": \n\t" \ - ".word 1001f, 1002f - 1001f \n\t" \ - ".popsection \n\t" \ - ".pushsection .text.insn, \"ax\" \n\t" \ - "1001: \n\t" \ - "insn_code_" #name ": " str " \n\t" \ - "1002: \n\t" \ - ".popsection" \ - ); \ - extern struct insn_desc insn_##name; - -static void test_xchg(void) -{ - MK_INSN(xchg_test1, "xchg %eax,%eax\n\t"); - MK_INSN(xchg_test2, "xchg %eax,%ebx\n\t"); - MK_INSN(xchg_test3, "xchg %eax,%ecx\n\t"); - MK_INSN(xchg_test4, "xchg %eax,%edx\n\t"); - MK_INSN(xchg_test5, "xchg %eax,%esi\n\t"); - MK_INSN(xchg_test6, "xchg %eax,%edi\n\t"); - MK_INSN(xchg_test7, "xchg %eax,%ebp\n\t"); - MK_INSN(xchg_test8, "xchg %eax,%esp\n\t"); - - inregs = (struct regs){ .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = 7}; - - exec_in_big_real_mode(&insn_xchg_test1); - report("xchg 1", 0, 1); - - exec_in_big_real_mode(&insn_xchg_test2); - report("xchg 2", R_AX | R_BX, - outregs.eax == inregs.ebx && outregs.ebx == inregs.eax); - - exec_in_big_real_mode(&insn_xchg_test3); - report("xchg 3", R_AX | R_CX, - outregs.eax == inregs.ecx && outregs.ecx == inregs.eax); - - exec_in_big_real_mode(&insn_xchg_test4); - report("xchg 4", R_AX | R_DX, - outregs.eax == inregs.edx && outregs.edx == inregs.eax); - - exec_in_big_real_mode(&insn_xchg_test5); - report("xchg 5", R_AX | R_SI, - outregs.eax == inregs.esi && outregs.esi == inregs.eax); - - exec_in_big_real_mode(&insn_xchg_test6); - report("xchg 6", R_AX | R_DI, - outregs.eax == inregs.edi && outregs.edi == inregs.eax); - - exec_in_big_real_mode(&insn_xchg_test7); - report("xchg 7", R_AX | R_BP, - outregs.eax == inregs.ebp && outregs.ebp == inregs.eax); - - exec_in_big_real_mode(&insn_xchg_test8); - report("xchg 8", R_AX | R_SP, - outregs.eax == inregs.esp && outregs.esp == inregs.eax); -} - -static void test_shld(void) -{ - MK_INSN(shld_test, "shld $8,%edx,%eax\n\t"); - - init_inregs(&(struct regs){ .eax = 0xbe, .edx = 0xef000000 }); - - exec_in_big_real_mode(&insn_shld_test); - report("shld", ~0, outregs.eax == 0xbeef); -} - -static void test_mov_imm(void) -{ - MK_INSN(mov_r32_imm_1, "mov $1234567890, %eax"); - MK_INSN(mov_r16_imm_1, "mov $1234, %ax"); - MK_INSN(mov_r8_imm_1, "mov $0x12, %ah"); - MK_INSN(mov_r8_imm_2, "mov $0x34, %al"); - MK_INSN(mov_r8_imm_3, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_mov_r16_imm_1); - report("mov 1", R_AX, outregs.eax == 1234); - - /* test mov $imm, %eax */ - exec_in_big_real_mode(&insn_mov_r32_imm_1); - report("mov 2", R_AX, outregs.eax == 1234567890); - - /* test mov $imm, %al/%ah */ - exec_in_big_real_mode(&insn_mov_r8_imm_1); - report("mov 3", R_AX, outregs.eax == 0x1200); - - exec_in_big_real_mode(&insn_mov_r8_imm_2); - report("mov 4", R_AX, outregs.eax == 0x34); - - exec_in_big_real_mode(&insn_mov_r8_imm_3); - report("mov 5", R_AX, outregs.eax == 0x1234); -} - -static void test_sub_imm(void) -{ - MK_INSN(sub_r32_imm_1, "mov $1234567890, %eax\n\t" "sub $10, %eax\n\t"); - MK_INSN(sub_r16_imm_1, "mov $1234, %ax\n\t" "sub $10, %ax\n\t"); - MK_INSN(sub_r8_imm_1, "mov $0x12, %ah\n\t" "sub $0x10, %ah\n\t"); - MK_INSN(sub_r8_imm_2, "mov $0x34, %al\n\t" "sub $0x10, %al\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_sub_r16_imm_1); - report("sub 1", R_AX, outregs.eax == 1224); - - /* test mov $imm, %eax */ - exec_in_big_real_mode(&insn_sub_r32_imm_1); - report("sub 2", R_AX, outregs.eax == 1234567880); - - /* test mov $imm, %al/%ah */ - exec_in_big_real_mode(&insn_sub_r8_imm_1); - report("sub 3", R_AX, outregs.eax == 0x0200); - - exec_in_big_real_mode(&insn_sub_r8_imm_2); - report("sub 4", R_AX, outregs.eax == 0x24); -} - -static void test_xor_imm(void) -{ - MK_INSN(xor_r32_imm_1, "mov $1234567890, %eax\n\t" "xor $1234567890, %eax\n\t"); - MK_INSN(xor_r16_imm_1, "mov $1234, %ax\n\t" "xor $1234, %ax\n\t"); - MK_INSN(xor_r8_imm_1, "mov $0x12, %ah\n\t" "xor $0x12, %ah\n\t"); - MK_INSN(xor_r8_imm_2, "mov $0x34, %al\n\t" "xor $0x34, %al\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_xor_r16_imm_1); - report("xor 1", R_AX, outregs.eax == 0); - - /* test mov $imm, %eax */ - exec_in_big_real_mode(&insn_xor_r32_imm_1); - report("xor 2", R_AX, outregs.eax == 0); - - /* test mov $imm, %al/%ah */ - exec_in_big_real_mode(&insn_xor_r8_imm_1); - report("xor 3", R_AX, outregs.eax == 0); - - exec_in_big_real_mode(&insn_xor_r8_imm_2); - report("xor 4", R_AX, outregs.eax == 0); -} - -static void test_cmp_imm(void) -{ - MK_INSN(cmp_test1, "mov $0x34, %al\n\t" - "cmp $0x34, %al\n\t"); - MK_INSN(cmp_test2, "mov $0x34, %al\n\t" - "cmp $0x39, %al\n\t"); - MK_INSN(cmp_test3, "mov $0x34, %al\n\t" - "cmp $0x24, %al\n\t"); - - init_inregs(NULL); - - /* test cmp imm8 with AL */ - /* ZF: (bit 6) Zero Flag becomes 1 if an operation results - * in a 0 writeback, or 0 register - */ - exec_in_big_real_mode(&insn_cmp_test1); - report("cmp 1", ~0, (outregs.eflags & (1<<6)) == (1<<6)); - - exec_in_big_real_mode(&insn_cmp_test2); - report("cmp 2", ~0, (outregs.eflags & (1<<6)) == 0); - - exec_in_big_real_mode(&insn_cmp_test3); - report("cmp 3", ~0, (outregs.eflags & (1<<6)) == 0); -} - -static void test_add_imm(void) -{ - MK_INSN(add_test1, "mov $0x43211234, %eax \n\t" - "add $0x12344321, %eax \n\t"); - MK_INSN(add_test2, "mov $0x12, %eax \n\t" - "add $0x21, %al\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_add_test1); - report("add 1", ~0, outregs.eax == 0x55555555); - - exec_in_big_real_mode(&insn_add_test2); - report("add 2", ~0, outregs.eax == 0x33); -} - -static void test_eflags_insn(void) -{ - MK_INSN(clc, "clc"); - MK_INSN(stc, "stc"); - MK_INSN(cli, "cli"); - MK_INSN(sti, "sti"); - MK_INSN(cld, "cld"); - MK_INSN(std, "std"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_clc); - report("clc", ~0, (outregs.eflags & 1) == 0); - - exec_in_big_real_mode(&insn_stc); - report("stc", ~0, (outregs.eflags & 1) == 1); - - exec_in_big_real_mode(&insn_cli); - report("cli", ~0, !(outregs.eflags & (1 << 9))); - - exec_in_big_real_mode(&insn_sti); - report("sti", ~0, outregs.eflags & (1 << 9)); - - exec_in_big_real_mode(&insn_cld); - report("cld", ~0, !(outregs.eflags & (1 << 10))); - - exec_in_big_real_mode(&insn_std); - report("std", ~0, (outregs.eflags & (1 << 10))); -} - -static void test_io(void) -{ - MK_INSN(io_test1, "mov $0xff, %al \n\t" - "out %al, $0xe0 \n\t" - "mov $0x00, %al \n\t" - "in $0xe0, %al \n\t"); - MK_INSN(io_test2, "mov $0xffff, %ax \n\t" - "out %ax, $0xe0 \n\t" - "mov $0x0000, %ax \n\t" - "in $0xe0, %ax \n\t"); - MK_INSN(io_test3, "mov $0xffffffff, %eax \n\t" - "out %eax, $0xe0 \n\t" - "mov $0x000000, %eax \n\t" - "in $0xe0, %eax \n\t"); - MK_INSN(io_test4, "mov $0xe0, %dx \n\t" - "mov $0xff, %al \n\t" - "out %al, %dx \n\t" - "mov $0x00, %al \n\t" - "in %dx, %al \n\t"); - MK_INSN(io_test5, "mov $0xe0, %dx \n\t" - "mov $0xffff, %ax \n\t" - "out %ax, %dx \n\t" - "mov $0x0000, %ax \n\t" - "in %dx, %ax \n\t"); - MK_INSN(io_test6, "mov $0xe0, %dx \n\t" - "mov $0xffffffff, %eax \n\t" - "out %eax, %dx \n\t" - "mov $0x00000000, %eax \n\t" - "in %dx, %eax \n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_io_test1); - report("pio 1", R_AX, outregs.eax == 0xff); - - exec_in_big_real_mode(&insn_io_test2); - report("pio 2", R_AX, outregs.eax == 0xffff); - - exec_in_big_real_mode(&insn_io_test3); - report("pio 3", R_AX, outregs.eax == 0xffffffff); - - exec_in_big_real_mode(&insn_io_test4); - report("pio 4", R_AX|R_DX, outregs.eax == 0xff); - - exec_in_big_real_mode(&insn_io_test5); - report("pio 5", R_AX|R_DX, outregs.eax == 0xffff); - - exec_in_big_real_mode(&insn_io_test6); - report("pio 6", R_AX|R_DX, outregs.eax == 0xffffffff); -} - -asm ("retf: lretw"); -extern void retf(void); - -asm ("retf_imm: lretw $10"); -extern void retf_imm(void); - -static void test_call(void) -{ - u32 addr; - - MK_INSN(call1, "mov $test_function, %eax \n\t" - "call *%eax\n\t"); - MK_INSN(call_near1, "jmp 2f\n\t" - "1: mov $0x1234, %eax\n\t" - "ret\n\t" - "2: call 1b\t"); - MK_INSN(call_near2, "call 1f\n\t" - "jmp 2f\n\t" - "1: mov $0x1234, %eax\n\t" - "ret\n\t" - "2:\t"); - MK_INSN(call_far1, "lcallw *(%ebx)\n\t"); - MK_INSN(call_far2, "lcallw $0, $retf\n\t"); - MK_INSN(ret_imm, "sub $10, %sp; jmp 2f; 1: retw $10; 2: callw 1b"); - MK_INSN(retf_imm, "sub $10, %sp; lcallw $0, $retf_imm"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_call1); - report("call 1", R_AX, outregs.eax == 0x1234); - - exec_in_big_real_mode(&insn_call_near1); - report("call near 1", R_AX, outregs.eax == 0x1234); - - exec_in_big_real_mode(&insn_call_near2); - report("call near 2", R_AX, outregs.eax == 0x1234); - - addr = (((unsigned)retf >> 4) << 16) | ((unsigned)retf & 0x0f); - inregs.ebx = (unsigned)&addr; - exec_in_big_real_mode(&insn_call_far1); - report("call far 1", 0, 1); - - exec_in_big_real_mode(&insn_call_far2); - report("call far 2", 0, 1); - - exec_in_big_real_mode(&insn_ret_imm); - report("ret imm 1", 0, 1); - - exec_in_big_real_mode(&insn_retf_imm); - report("retf imm 1", 0, 1); -} - -static void test_jcc_short(void) -{ - MK_INSN(jnz_short1, "jnz 1f\n\t" - "mov $0x1234, %eax\n\t" - "1:\n\t"); - MK_INSN(jnz_short2, "1:\n\t" - "cmp $0x1234, %eax\n\t" - "mov $0x1234, %eax\n\t" - "jnz 1b\n\t"); - MK_INSN(jmp_short1, "jmp 1f\n\t" - "mov $0x1234, %eax\n\t" - "1:\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_jnz_short1); - report("jnz short 1", ~0, 1); - - exec_in_big_real_mode(&insn_jnz_short2); - report("jnz short 2", R_AX, (outregs.eflags & (1 << 6))); - - exec_in_big_real_mode(&insn_jmp_short1); - report("jmp short 1", ~0, 1); -} - -static void test_jcc_near(void) -{ - /* encode near jmp manually. gas will not do it if offsets < 127 byte */ - MK_INSN(jnz_near1, ".byte 0x0f, 0x85, 0x06, 0x00\n\t" - "mov $0x1234, %eax\n\t"); - MK_INSN(jnz_near2, "cmp $0x1234, %eax\n\t" - "mov $0x1234, %eax\n\t" - ".byte 0x0f, 0x85, 0xf0, 0xff\n\t"); - MK_INSN(jmp_near1, ".byte 0xE9, 0x06, 0x00\n\t" - "mov $0x1234, %eax\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_jnz_near1); - report("jnz near 1", 0, 1); - - exec_in_big_real_mode(&insn_jnz_near2); - report("jnz near 2", R_AX, outregs.eflags & (1 << 6)); - - exec_in_big_real_mode(&insn_jmp_near1); - report("jmp near 1", 0, 1); -} - -static void test_long_jmp(void) -{ - MK_INSN(long_jmp, "call 1f\n\t" - "jmp 2f\n\t" - "1: jmp $0, $test_function\n\t" - "2:\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_long_jmp); - report("jmp far 1", R_AX, outregs.eax == 0x1234); -} - -static void test_push_pop(void) -{ - MK_INSN(push32, "mov $0x12345678, %eax\n\t" - "push %eax\n\t" - "pop %ebx\n\t"); - MK_INSN(push16, "mov $0x1234, %ax\n\t" - "push %ax\n\t" - "pop %bx\n\t"); - - MK_INSN(push_es, "mov $0x231, %bx\n\t" //Just write a dummy value to see if it gets overwritten - "mov $0x123, %ax\n\t" - "mov %ax, %es\n\t" - "pushw %es\n\t" - "pop %bx \n\t" - ); - MK_INSN(pop_es, "push %ax\n\t" - "popw %es\n\t" - "mov %es, %bx\n\t" - ); - MK_INSN(push_pop_ss, "pushw %ss\n\t" - "pushw %ax\n\t" - "popw %ss\n\t" - "mov %ss, %bx\n\t" - "popw %ss\n\t" - ); - MK_INSN(push_pop_fs, "pushl %fs\n\t" - "pushl %eax\n\t" - "popl %fs\n\t" - "mov %fs, %ebx\n\t" - "popl %fs\n\t" - ); - MK_INSN(push_pop_high_esp_bits, - "xor $0x12340000, %esp \n\t" - "push %ax; \n\t" - "xor $0x12340000, %esp \n\t" - "pop %bx"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_push32); - report("push/pop 1", R_AX|R_BX, - outregs.eax == outregs.ebx && outregs.eax == 0x12345678); - - exec_in_big_real_mode(&insn_push16); - report("push/pop 2", R_AX|R_BX, - outregs.eax == outregs.ebx && outregs.eax == 0x1234); - - exec_in_big_real_mode(&insn_push_es); - report("push/pop 3", R_AX|R_BX, - outregs.ebx == outregs.eax && outregs.eax == 0x123); - - exec_in_big_real_mode(&insn_pop_es); - report("push/pop 4", R_AX|R_BX, outregs.ebx == outregs.eax); - - exec_in_big_real_mode(&insn_push_pop_ss); - report("push/pop 5", R_AX|R_BX, outregs.ebx == outregs.eax); - - exec_in_big_real_mode(&insn_push_pop_fs); - report("push/pop 6", R_AX|R_BX, outregs.ebx == outregs.eax); - - inregs.eax = 0x9977; - inregs.ebx = 0x7799; - exec_in_big_real_mode(&insn_push_pop_high_esp_bits); - report("push/pop with high bits set in %esp", R_BX, outregs.ebx == 0x9977); -} - -static void test_null(void) -{ - MK_INSN(null, ""); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_null); - report("null", 0, 1); -} - -static void test_pusha_popa(void) -{ - MK_INSN(pusha, "pusha\n\t" - "pop %edi\n\t" - "pop %esi\n\t" - "pop %ebp\n\t" - "add $4, %esp\n\t" - "pop %ebx\n\t" - "pop %edx\n\t" - "pop %ecx\n\t" - "pop %eax\n\t" - ); - - MK_INSN(popa, "push %eax\n\t" - "push %ecx\n\t" - "push %edx\n\t" - "push %ebx\n\t" - "push %esp\n\t" - "push %ebp\n\t" - "push %esi\n\t" - "push %edi\n\t" - "popa\n\t" - ); - - init_inregs(&(struct regs){ .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6 }); - - exec_in_big_real_mode(&insn_pusha); - report("pusha/popa 1", 0, 1); - - exec_in_big_real_mode(&insn_popa); - report("pusha/popa 1", 0, 1); -} - -static void test_iret(void) -{ - MK_INSN(iret32, "pushf\n\t" - "pushl %cs\n\t" - "call 1f\n\t" /* a near call will push eip onto the stack */ - "jmp 2f\n\t" - "1: iretl\n\t" - "2:\n\t" - ); - - MK_INSN(iret16, "pushfw\n\t" - "pushw %cs\n\t" - "callw 1f\n\t" - "jmp 2f\n\t" - "1: iretw\n\t" - "2:\n\t"); - - MK_INSN(iret_flags32, "pushfl\n\t" - "popl %eax\n\t" - "andl $~0x2, %eax\n\t" - "orl $0xffc18028, %eax\n\t" - "pushl %eax\n\t" - "pushl %cs\n\t" - "call 1f\n\t" - "jmp 2f\n\t" - "1: iretl\n\t" - "2:\n\t"); - - MK_INSN(iret_flags16, "pushfw\n\t" - "popw %ax\n\t" - "and $~0x2, %ax\n\t" - "or $0x8028, %ax\n\t" - "pushw %ax\n\t" - "pushw %cs\n\t" - "callw 1f\n\t" - "jmp 2f\n\t" - "1: iretw\n\t" - "2:\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_iret32); - report("iret 1", 0, 1); - - exec_in_big_real_mode(&insn_iret16); - report("iret 2", 0, 1); - - exec_in_big_real_mode(&insn_iret_flags32); - report("iret 3", R_AX, 1); - report("rflags.rf", ~0, !(outregs.eflags & (1 << 16))); - - exec_in_big_real_mode(&insn_iret_flags16); - report("iret 4", R_AX, 1); -} - -static void test_int(void) -{ - init_inregs(NULL); - - *(u32 *)(0x11 * 4) = 0x1000; /* Store a pointer to address 0x1000 in IDT entry 0x11 */ - *(u8 *)(0x1000) = 0xcf; /* 0x1000 contains an IRET instruction */ - - MK_INSN(int11, "int $0x11\n\t"); - - exec_in_big_real_mode(&insn_int11); - report("int 1", 0, 1); -} - -static void test_sti_inhibit(void) -{ - init_inregs(NULL); - - *(u32 *)(0x73 * 4) = 0x1000; /* Store IRQ 11 handler in the IDT */ - *(u8 *)(0x1000) = 0xcf; /* 0x1000 contains an IRET instruction */ - - MK_INSN(sti_inhibit, "cli\n\t" - "movw $0x200b, %dx\n\t" - "movl $1, %eax\n\t" - "outl %eax, %dx\n\t" /* Set IRQ11 */ - "movl $0, %eax\n\t" - "outl %eax, %dx\n\t" /* Clear IRQ11 */ - "sti\n\t" - "hlt\n\t"); - exec_in_big_real_mode(&insn_sti_inhibit); - - report("sti inhibit", ~0, 1); -} - -static void test_imul(void) -{ - MK_INSN(imul8_1, "mov $2, %al\n\t" - "mov $-4, %cx\n\t" - "imul %cl\n\t"); - - MK_INSN(imul16_1, "mov $2, %ax\n\t" - "mov $-4, %cx\n\t" - "imul %cx\n\t"); - - MK_INSN(imul32_1, "mov $2, %eax\n\t" - "mov $-4, %ecx\n\t" - "imul %ecx\n\t"); - - MK_INSN(imul8_2, "mov $0x12340002, %eax\n\t" - "mov $4, %cx\n\t" - "imul %cl\n\t"); - - MK_INSN(imul16_2, "mov $2, %ax\n\t" - "mov $4, %cx\n\t" - "imul %cx\n\t"); - - MK_INSN(imul32_2, "mov $2, %eax\n\t" - "mov $4, %ecx\n\t" - "imul %ecx\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_imul8_1); - report("imul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == (u8)-8); - - exec_in_big_real_mode(&insn_imul16_1); - report("imul 2", R_AX | R_CX | R_DX, outregs.eax == (u16)-8); - - exec_in_big_real_mode(&insn_imul32_1); - report("imul 3", R_AX | R_CX | R_DX, outregs.eax == (u32)-8); - - exec_in_big_real_mode(&insn_imul8_2); - report("imul 4", R_AX | R_CX | R_DX, - (outregs.eax & 0xffff) == 8 - && (outregs.eax & 0xffff0000) == 0x12340000); - - exec_in_big_real_mode(&insn_imul16_2); - report("imul 5", R_AX | R_CX | R_DX, outregs.eax == 8); - - exec_in_big_real_mode(&insn_imul32_2); - report("imul 6", R_AX | R_CX | R_DX, outregs.eax == 8); -} - -static void test_mul(void) -{ - MK_INSN(mul8, "mov $2, %al\n\t" - "mov $4, %cx\n\t" - "imul %cl\n\t"); - - MK_INSN(mul16, "mov $2, %ax\n\t" - "mov $4, %cx\n\t" - "imul %cx\n\t"); - - MK_INSN(mul32, "mov $2, %eax\n\t" - "mov $4, %ecx\n\t" - "imul %ecx\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_mul8); - report("mul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == 8); - - exec_in_big_real_mode(&insn_mul16); - report("mul 2", R_AX | R_CX | R_DX, outregs.eax == 8); - - exec_in_big_real_mode(&insn_mul32); - report("mul 3", R_AX | R_CX | R_DX, outregs.eax == 8); -} - -static void test_div(void) -{ - MK_INSN(div8, "mov $257, %ax\n\t" - "mov $2, %cl\n\t" - "div %cl\n\t"); - - MK_INSN(div16, "mov $512, %ax\n\t" - "mov $5, %cx\n\t" - "div %cx\n\t"); - - MK_INSN(div32, "mov $512, %eax\n\t" - "mov $5, %ecx\n\t" - "div %ecx\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_div8); - report("div 1", R_AX | R_CX | R_DX, outregs.eax == 384); - - exec_in_big_real_mode(&insn_div16); - report("div 2", R_AX | R_CX | R_DX, - outregs.eax == 102 && outregs.edx == 2); - - exec_in_big_real_mode(&insn_div32); - report("div 3", R_AX | R_CX | R_DX, - outregs.eax == 102 && outregs.edx == 2); -} - -static void test_idiv(void) -{ - MK_INSN(idiv8, "mov $256, %ax\n\t" - "mov $-2, %cl\n\t" - "idiv %cl\n\t"); - - MK_INSN(idiv16, "mov $512, %ax\n\t" - "mov $-2, %cx\n\t" - "idiv %cx\n\t"); - - MK_INSN(idiv32, "mov $512, %eax\n\t" - "mov $-2, %ecx\n\t" - "idiv %ecx\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_idiv8); - report("idiv 1", R_AX | R_CX | R_DX, outregs.eax == (u8)-128); - - exec_in_big_real_mode(&insn_idiv16); - report("idiv 2", R_AX | R_CX | R_DX, outregs.eax == (u16)-256); - - exec_in_big_real_mode(&insn_idiv32); - report("idiv 3", R_AX | R_CX | R_DX, outregs.eax == (u32)-256); -} - -static void test_cbw(void) -{ - MK_INSN(cbw, "mov $0xFE, %eax \n\t" - "cbw\n\t"); - MK_INSN(cwde, "mov $0xFFFE, %eax \n\t" - "cwde\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_cbw); - report("cbq 1", ~0, outregs.eax == 0xFFFE); - - exec_in_big_real_mode(&insn_cwde); - report("cwde 1", ~0, outregs.eax == 0xFFFFFFFE); -} - -static void test_loopcc(void) -{ - MK_INSN(loop, "mov $10, %ecx\n\t" - "1: inc %eax\n\t" - "loop 1b\n\t"); - - MK_INSN(loope, "mov $10, %ecx\n\t" - "mov $1, %eax\n\t" - "1: dec %eax\n\t" - "loope 1b\n\t"); - - MK_INSN(loopne, "mov $10, %ecx\n\t" - "mov $5, %eax\n\t" - "1: dec %eax\n\t" - "loopne 1b\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_loop); - report("LOOPcc short 1", R_AX, outregs.eax == 10); - - exec_in_big_real_mode(&insn_loope); - report("LOOPcc short 2", R_AX | R_CX, - outregs.eax == -1 && outregs.ecx == 8); - - exec_in_big_real_mode(&insn_loopne); - report("LOOPcc short 3", R_AX | R_CX, - outregs.eax == 0 && outregs.ecx == 5); -} - -static void test_das(void) -{ - short i; - u16 nr_fail = 0; - static unsigned test_cases[1024] = { - 0x46000000, 0x8701a000, 0x9710fa00, 0x97119a00, - 0x02000101, 0x8301a101, 0x9310fb01, 0x93119b01, - 0x02000202, 0x8301a202, 0x9710fc02, 0x97119c02, - 0x06000303, 0x8701a303, 0x9310fd03, 0x93119d03, - 0x02000404, 0x8301a404, 0x9310fe04, 0x93119e04, - 0x06000505, 0x8701a505, 0x9710ff05, 0x97119f05, - 0x06000606, 0x8701a606, 0x56100006, 0x9711a006, - 0x02000707, 0x8301a707, 0x12100107, 0x9311a107, - 0x02000808, 0x8301a808, 0x12100208, 0x9311a208, - 0x06000909, 0x8701a909, 0x16100309, 0x9711a309, - 0x1200040a, 0x9301a40a, 0x1210040a, 0x9311a40a, - 0x1600050b, 0x9701a50b, 0x1610050b, 0x9711a50b, - 0x1600060c, 0x9701a60c, 0x1610060c, 0x9711a60c, - 0x1200070d, 0x9301a70d, 0x1210070d, 0x9311a70d, - 0x1200080e, 0x9301a80e, 0x1210080e, 0x9311a80e, - 0x1600090f, 0x9701a90f, 0x1610090f, 0x9711a90f, - 0x02001010, 0x8301b010, 0x16100a10, 0x9711aa10, - 0x06001111, 0x8701b111, 0x12100b11, 0x9311ab11, - 0x06001212, 0x8701b212, 0x16100c12, 0x9711ac12, - 0x02001313, 0x8301b313, 0x12100d13, 0x9311ad13, - 0x06001414, 0x8701b414, 0x12100e14, 0x9311ae14, - 0x02001515, 0x8301b515, 0x16100f15, 0x9711af15, - 0x02001616, 0x8301b616, 0x12101016, 0x9311b016, - 0x06001717, 0x8701b717, 0x16101117, 0x9711b117, - 0x06001818, 0x8701b818, 0x16101218, 0x9711b218, - 0x02001919, 0x8301b919, 0x12101319, 0x9311b319, - 0x1600141a, 0x9701b41a, 0x1610141a, 0x9711b41a, - 0x1200151b, 0x9301b51b, 0x1210151b, 0x9311b51b, - 0x1200161c, 0x9301b61c, 0x1210161c, 0x9311b61c, - 0x1600171d, 0x9701b71d, 0x1610171d, 0x9711b71d, - 0x1600181e, 0x9701b81e, 0x1610181e, 0x9711b81e, - 0x1200191f, 0x9301b91f, 0x1210191f, 0x9311b91f, - 0x02002020, 0x8701c020, 0x12101a20, 0x9311ba20, - 0x06002121, 0x8301c121, 0x16101b21, 0x9711bb21, - 0x06002222, 0x8301c222, 0x12101c22, 0x9311bc22, - 0x02002323, 0x8701c323, 0x16101d23, 0x9711bd23, - 0x06002424, 0x8301c424, 0x16101e24, 0x9711be24, - 0x02002525, 0x8701c525, 0x12101f25, 0x9311bf25, - 0x02002626, 0x8701c626, 0x12102026, 0x9711c026, - 0x06002727, 0x8301c727, 0x16102127, 0x9311c127, - 0x06002828, 0x8301c828, 0x16102228, 0x9311c228, - 0x02002929, 0x8701c929, 0x12102329, 0x9711c329, - 0x1600242a, 0x9301c42a, 0x1610242a, 0x9311c42a, - 0x1200252b, 0x9701c52b, 0x1210252b, 0x9711c52b, - 0x1200262c, 0x9701c62c, 0x1210262c, 0x9711c62c, - 0x1600272d, 0x9301c72d, 0x1610272d, 0x9311c72d, - 0x1600282e, 0x9301c82e, 0x1610282e, 0x9311c82e, - 0x1200292f, 0x9701c92f, 0x1210292f, 0x9711c92f, - 0x06003030, 0x8301d030, 0x12102a30, 0x9711ca30, - 0x02003131, 0x8701d131, 0x16102b31, 0x9311cb31, - 0x02003232, 0x8701d232, 0x12102c32, 0x9711cc32, - 0x06003333, 0x8301d333, 0x16102d33, 0x9311cd33, - 0x02003434, 0x8701d434, 0x16102e34, 0x9311ce34, - 0x06003535, 0x8301d535, 0x12102f35, 0x9711cf35, - 0x06003636, 0x8301d636, 0x16103036, 0x9311d036, - 0x02003737, 0x8701d737, 0x12103137, 0x9711d137, - 0x02003838, 0x8701d838, 0x12103238, 0x9711d238, - 0x06003939, 0x8301d939, 0x16103339, 0x9311d339, - 0x1200343a, 0x9701d43a, 0x1210343a, 0x9711d43a, - 0x1600353b, 0x9301d53b, 0x1610353b, 0x9311d53b, - 0x1600363c, 0x9301d63c, 0x1610363c, 0x9311d63c, - 0x1200373d, 0x9701d73d, 0x1210373d, 0x9711d73d, - 0x1200383e, 0x9701d83e, 0x1210383e, 0x9711d83e, - 0x1600393f, 0x9301d93f, 0x1610393f, 0x9311d93f, - 0x02004040, 0x8301e040, 0x16103a40, 0x9311da40, - 0x06004141, 0x8701e141, 0x12103b41, 0x9711db41, - 0x06004242, 0x8701e242, 0x16103c42, 0x9311dc42, - 0x02004343, 0x8301e343, 0x12103d43, 0x9711dd43, - 0x06004444, 0x8701e444, 0x12103e44, 0x9711de44, - 0x02004545, 0x8301e545, 0x16103f45, 0x9311df45, - 0x02004646, 0x8301e646, 0x12104046, 0x9311e046, - 0x06004747, 0x8701e747, 0x16104147, 0x9711e147, - 0x06004848, 0x8701e848, 0x16104248, 0x9711e248, - 0x02004949, 0x8301e949, 0x12104349, 0x9311e349, - 0x1600444a, 0x9701e44a, 0x1610444a, 0x9711e44a, - 0x1200454b, 0x9301e54b, 0x1210454b, 0x9311e54b, - 0x1200464c, 0x9301e64c, 0x1210464c, 0x9311e64c, - 0x1600474d, 0x9701e74d, 0x1610474d, 0x9711e74d, - 0x1600484e, 0x9701e84e, 0x1610484e, 0x9711e84e, - 0x1200494f, 0x9301e94f, 0x1210494f, 0x9311e94f, - 0x06005050, 0x8701f050, 0x12104a50, 0x9311ea50, - 0x02005151, 0x8301f151, 0x16104b51, 0x9711eb51, - 0x02005252, 0x8301f252, 0x12104c52, 0x9311ec52, - 0x06005353, 0x8701f353, 0x16104d53, 0x9711ed53, - 0x02005454, 0x8301f454, 0x16104e54, 0x9711ee54, - 0x06005555, 0x8701f555, 0x12104f55, 0x9311ef55, - 0x06005656, 0x8701f656, 0x16105056, 0x9711f056, - 0x02005757, 0x8301f757, 0x12105157, 0x9311f157, - 0x02005858, 0x8301f858, 0x12105258, 0x9311f258, - 0x06005959, 0x8701f959, 0x16105359, 0x9711f359, - 0x1200545a, 0x9301f45a, 0x1210545a, 0x9311f45a, - 0x1600555b, 0x9701f55b, 0x1610555b, 0x9711f55b, - 0x1600565c, 0x9701f65c, 0x1610565c, 0x9711f65c, - 0x1200575d, 0x9301f75d, 0x1210575d, 0x9311f75d, - 0x1200585e, 0x9301f85e, 0x1210585e, 0x9311f85e, - 0x1600595f, 0x9701f95f, 0x1610595f, 0x9711f95f, - 0x06006060, 0x47010060, 0x16105a60, 0x9711fa60, - 0x02006161, 0x03010161, 0x12105b61, 0x9311fb61, - 0x02006262, 0x03010262, 0x16105c62, 0x9711fc62, - 0x06006363, 0x07010363, 0x12105d63, 0x9311fd63, - 0x02006464, 0x03010464, 0x12105e64, 0x9311fe64, - 0x06006565, 0x07010565, 0x16105f65, 0x9711ff65, - 0x06006666, 0x07010666, 0x16106066, 0x57110066, - 0x02006767, 0x03010767, 0x12106167, 0x13110167, - 0x02006868, 0x03010868, 0x12106268, 0x13110268, - 0x06006969, 0x07010969, 0x16106369, 0x17110369, - 0x1200646a, 0x1301046a, 0x1210646a, 0x1311046a, - 0x1600656b, 0x1701056b, 0x1610656b, 0x1711056b, - 0x1600666c, 0x1701066c, 0x1610666c, 0x1711066c, - 0x1200676d, 0x1301076d, 0x1210676d, 0x1311076d, - 0x1200686e, 0x1301086e, 0x1210686e, 0x1311086e, - 0x1600696f, 0x1701096f, 0x1610696f, 0x1711096f, - 0x02007070, 0x03011070, 0x16106a70, 0x17110a70, - 0x06007171, 0x07011171, 0x12106b71, 0x13110b71, - 0x06007272, 0x07011272, 0x16106c72, 0x17110c72, - 0x02007373, 0x03011373, 0x12106d73, 0x13110d73, - 0x06007474, 0x07011474, 0x12106e74, 0x13110e74, - 0x02007575, 0x03011575, 0x16106f75, 0x17110f75, - 0x02007676, 0x03011676, 0x12107076, 0x13111076, - 0x06007777, 0x07011777, 0x16107177, 0x17111177, - 0x06007878, 0x07011878, 0x16107278, 0x17111278, - 0x02007979, 0x03011979, 0x12107379, 0x13111379, - 0x1600747a, 0x1701147a, 0x1610747a, 0x1711147a, - 0x1200757b, 0x1301157b, 0x1210757b, 0x1311157b, - 0x1200767c, 0x1301167c, 0x1210767c, 0x1311167c, - 0x1600777d, 0x1701177d, 0x1610777d, 0x1711177d, - 0x1600787e, 0x1701187e, 0x1610787e, 0x1711187e, - 0x1200797f, 0x1301197f, 0x1210797f, 0x1311197f, - 0x82008080, 0x03012080, 0x12107a80, 0x13111a80, - 0x86008181, 0x07012181, 0x16107b81, 0x17111b81, - 0x86008282, 0x07012282, 0x12107c82, 0x13111c82, - 0x82008383, 0x03012383, 0x16107d83, 0x17111d83, - 0x86008484, 0x07012484, 0x16107e84, 0x17111e84, - 0x82008585, 0x03012585, 0x12107f85, 0x13111f85, - 0x82008686, 0x03012686, 0x92108086, 0x13112086, - 0x86008787, 0x07012787, 0x96108187, 0x17112187, - 0x86008888, 0x07012888, 0x96108288, 0x17112288, - 0x82008989, 0x03012989, 0x92108389, 0x13112389, - 0x9600848a, 0x1701248a, 0x9610848a, 0x1711248a, - 0x9200858b, 0x1301258b, 0x9210858b, 0x1311258b, - 0x9200868c, 0x1301268c, 0x9210868c, 0x1311268c, - 0x9600878d, 0x1701278d, 0x9610878d, 0x1711278d, - 0x9600888e, 0x1701288e, 0x9610888e, 0x1711288e, - 0x9200898f, 0x1301298f, 0x9210898f, 0x1311298f, - 0x86009090, 0x07013090, 0x92108a90, 0x13112a90, - 0x82009191, 0x03013191, 0x96108b91, 0x17112b91, - 0x82009292, 0x03013292, 0x92108c92, 0x13112c92, - 0x86009393, 0x07013393, 0x96108d93, 0x17112d93, - 0x82009494, 0x03013494, 0x96108e94, 0x17112e94, - 0x86009595, 0x07013595, 0x92108f95, 0x13112f95, - 0x86009696, 0x07013696, 0x96109096, 0x17113096, - 0x82009797, 0x03013797, 0x92109197, 0x13113197, - 0x82009898, 0x03013898, 0x92109298, 0x13113298, - 0x86009999, 0x07013999, 0x96109399, 0x17113399, - 0x1300349a, 0x1301349a, 0x1310349a, 0x1311349a, - 0x1700359b, 0x1701359b, 0x1710359b, 0x1711359b, - 0x1700369c, 0x1701369c, 0x1710369c, 0x1711369c, - 0x1300379d, 0x1301379d, 0x1310379d, 0x1311379d, - 0x1300389e, 0x1301389e, 0x1310389e, 0x1311389e, - 0x1700399f, 0x1701399f, 0x1710399f, 0x1711399f, - 0x030040a0, 0x030140a0, 0x17103aa0, 0x17113aa0, - 0x070041a1, 0x070141a1, 0x13103ba1, 0x13113ba1, - 0x070042a2, 0x070142a2, 0x17103ca2, 0x17113ca2, - 0x030043a3, 0x030143a3, 0x13103da3, 0x13113da3, - 0x070044a4, 0x070144a4, 0x13103ea4, 0x13113ea4, - 0x030045a5, 0x030145a5, 0x17103fa5, 0x17113fa5, - 0x030046a6, 0x030146a6, 0x131040a6, 0x131140a6, - 0x070047a7, 0x070147a7, 0x171041a7, 0x171141a7, - 0x070048a8, 0x070148a8, 0x171042a8, 0x171142a8, - 0x030049a9, 0x030149a9, 0x131043a9, 0x131143a9, - 0x170044aa, 0x170144aa, 0x171044aa, 0x171144aa, - 0x130045ab, 0x130145ab, 0x131045ab, 0x131145ab, - 0x130046ac, 0x130146ac, 0x131046ac, 0x131146ac, - 0x170047ad, 0x170147ad, 0x171047ad, 0x171147ad, - 0x170048ae, 0x170148ae, 0x171048ae, 0x171148ae, - 0x130049af, 0x130149af, 0x131049af, 0x131149af, - 0x070050b0, 0x070150b0, 0x13104ab0, 0x13114ab0, - 0x030051b1, 0x030151b1, 0x17104bb1, 0x17114bb1, - 0x030052b2, 0x030152b2, 0x13104cb2, 0x13114cb2, - 0x070053b3, 0x070153b3, 0x17104db3, 0x17114db3, - 0x030054b4, 0x030154b4, 0x17104eb4, 0x17114eb4, - 0x070055b5, 0x070155b5, 0x13104fb5, 0x13114fb5, - 0x070056b6, 0x070156b6, 0x171050b6, 0x171150b6, - 0x030057b7, 0x030157b7, 0x131051b7, 0x131151b7, - 0x030058b8, 0x030158b8, 0x131052b8, 0x131152b8, - 0x070059b9, 0x070159b9, 0x171053b9, 0x171153b9, - 0x130054ba, 0x130154ba, 0x131054ba, 0x131154ba, - 0x170055bb, 0x170155bb, 0x171055bb, 0x171155bb, - 0x170056bc, 0x170156bc, 0x171056bc, 0x171156bc, - 0x130057bd, 0x130157bd, 0x131057bd, 0x131157bd, - 0x130058be, 0x130158be, 0x131058be, 0x131158be, - 0x170059bf, 0x170159bf, 0x171059bf, 0x171159bf, - 0x070060c0, 0x070160c0, 0x17105ac0, 0x17115ac0, - 0x030061c1, 0x030161c1, 0x13105bc1, 0x13115bc1, - 0x030062c2, 0x030162c2, 0x17105cc2, 0x17115cc2, - 0x070063c3, 0x070163c3, 0x13105dc3, 0x13115dc3, - 0x030064c4, 0x030164c4, 0x13105ec4, 0x13115ec4, - 0x070065c5, 0x070165c5, 0x17105fc5, 0x17115fc5, - 0x070066c6, 0x070166c6, 0x171060c6, 0x171160c6, - 0x030067c7, 0x030167c7, 0x131061c7, 0x131161c7, - 0x030068c8, 0x030168c8, 0x131062c8, 0x131162c8, - 0x070069c9, 0x070169c9, 0x171063c9, 0x171163c9, - 0x130064ca, 0x130164ca, 0x131064ca, 0x131164ca, - 0x170065cb, 0x170165cb, 0x171065cb, 0x171165cb, - 0x170066cc, 0x170166cc, 0x171066cc, 0x171166cc, - 0x130067cd, 0x130167cd, 0x131067cd, 0x131167cd, - 0x130068ce, 0x130168ce, 0x131068ce, 0x131168ce, - 0x170069cf, 0x170169cf, 0x171069cf, 0x171169cf, - 0x030070d0, 0x030170d0, 0x17106ad0, 0x17116ad0, - 0x070071d1, 0x070171d1, 0x13106bd1, 0x13116bd1, - 0x070072d2, 0x070172d2, 0x17106cd2, 0x17116cd2, - 0x030073d3, 0x030173d3, 0x13106dd3, 0x13116dd3, - 0x070074d4, 0x070174d4, 0x13106ed4, 0x13116ed4, - 0x030075d5, 0x030175d5, 0x17106fd5, 0x17116fd5, - 0x030076d6, 0x030176d6, 0x131070d6, 0x131170d6, - 0x070077d7, 0x070177d7, 0x171071d7, 0x171171d7, - 0x070078d8, 0x070178d8, 0x171072d8, 0x171172d8, - 0x030079d9, 0x030179d9, 0x131073d9, 0x131173d9, - 0x170074da, 0x170174da, 0x171074da, 0x171174da, - 0x130075db, 0x130175db, 0x131075db, 0x131175db, - 0x130076dc, 0x130176dc, 0x131076dc, 0x131176dc, - 0x170077dd, 0x170177dd, 0x171077dd, 0x171177dd, - 0x170078de, 0x170178de, 0x171078de, 0x171178de, - 0x130079df, 0x130179df, 0x131079df, 0x131179df, - 0x830080e0, 0x830180e0, 0x13107ae0, 0x13117ae0, - 0x870081e1, 0x870181e1, 0x17107be1, 0x17117be1, - 0x870082e2, 0x870182e2, 0x13107ce2, 0x13117ce2, - 0x830083e3, 0x830183e3, 0x17107de3, 0x17117de3, - 0x870084e4, 0x870184e4, 0x17107ee4, 0x17117ee4, - 0x830085e5, 0x830185e5, 0x13107fe5, 0x13117fe5, - 0x830086e6, 0x830186e6, 0x931080e6, 0x931180e6, - 0x870087e7, 0x870187e7, 0x971081e7, 0x971181e7, - 0x870088e8, 0x870188e8, 0x971082e8, 0x971182e8, - 0x830089e9, 0x830189e9, 0x931083e9, 0x931183e9, - 0x970084ea, 0x970184ea, 0x971084ea, 0x971184ea, - 0x930085eb, 0x930185eb, 0x931085eb, 0x931185eb, - 0x930086ec, 0x930186ec, 0x931086ec, 0x931186ec, - 0x970087ed, 0x970187ed, 0x971087ed, 0x971187ed, - 0x970088ee, 0x970188ee, 0x971088ee, 0x971188ee, - 0x930089ef, 0x930189ef, 0x931089ef, 0x931189ef, - 0x870090f0, 0x870190f0, 0x93108af0, 0x93118af0, - 0x830091f1, 0x830191f1, 0x97108bf1, 0x97118bf1, - 0x830092f2, 0x830192f2, 0x93108cf2, 0x93118cf2, - 0x870093f3, 0x870193f3, 0x97108df3, 0x97118df3, - 0x830094f4, 0x830194f4, 0x97108ef4, 0x97118ef4, - 0x870095f5, 0x870195f5, 0x93108ff5, 0x93118ff5, - 0x870096f6, 0x870196f6, 0x971090f6, 0x971190f6, - 0x830097f7, 0x830197f7, 0x931091f7, 0x931191f7, - 0x830098f8, 0x830198f8, 0x931092f8, 0x931192f8, - 0x870099f9, 0x870199f9, 0x971093f9, 0x971193f9, - 0x930094fa, 0x930194fa, 0x931094fa, 0x931194fa, - 0x970095fb, 0x970195fb, 0x971095fb, 0x971195fb, - 0x970096fc, 0x970196fc, 0x971096fc, 0x971196fc, - 0x930097fd, 0x930197fd, 0x931097fd, 0x931197fd, - 0x930098fe, 0x930198fe, 0x931098fe, 0x931198fe, - 0x970099ff, 0x970199ff, 0x971099ff, 0x971199ff, - }; - - MK_INSN(das, "das"); - - init_inregs(NULL); - - for (i = 0; i < 1024; ++i) { - unsigned tmp = test_cases[i]; - inregs.eax = tmp & 0xff; - inregs.eflags = (tmp >> 16) & 0xff; - exec_in_big_real_mode(&insn_das); - if (!regs_equal(R_AX) - || outregs.eax != ((tmp >> 8) & 0xff) - || (outregs.eflags & 0xff) != (tmp >> 24)) { - ++nr_fail; - break; - } - } - report("DAS", ~0, nr_fail == 0); -} - -static void test_cwd_cdq(void) -{ - /* Sign-bit set */ - MK_INSN(cwd_1, "mov $0x8000, %ax\n\t" - "cwd\n\t"); - - /* Sign-bit not set */ - MK_INSN(cwd_2, "mov $0x1000, %ax\n\t" - "cwd\n\t"); - - /* Sign-bit set */ - MK_INSN(cdq_1, "mov $0x80000000, %eax\n\t" - "cdq\n\t"); - - /* Sign-bit not set */ - MK_INSN(cdq_2, "mov $0x10000000, %eax\n\t" - "cdq\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_cwd_1); - report("cwd 1", R_AX | R_DX, - outregs.eax == 0x8000 && outregs.edx == 0xffff); - - exec_in_big_real_mode(&insn_cwd_2); - report("cwd 2", R_AX | R_DX, - outregs.eax == 0x1000 && outregs.edx == 0); - - exec_in_big_real_mode(&insn_cdq_1); - report("cdq 1", R_AX | R_DX, - outregs.eax == 0x80000000 && outregs.edx == 0xffffffff); - - exec_in_big_real_mode(&insn_cdq_2); - report("cdq 2", R_AX | R_DX, - outregs.eax == 0x10000000 && outregs.edx == 0); -} - -static struct { - void *address; - unsigned short sel; -} __attribute__((packed)) desc = { - (void *)0x1234, - 0x10, -}; - -static void test_lds_lss(void) -{ - init_inregs(&(struct regs){ .ebx = (unsigned long)&desc }); - - MK_INSN(lds, "pushl %ds\n\t" - "lds (%ebx), %eax\n\t" - "mov %ds, %ebx\n\t" - "popl %ds\n\t"); - exec_in_big_real_mode(&insn_lds); - report("lds", R_AX | R_BX, - outregs.eax == (unsigned long)desc.address && - outregs.ebx == desc.sel); - - MK_INSN(les, "les (%ebx), %eax\n\t" - "mov %es, %ebx\n\t"); - exec_in_big_real_mode(&insn_les); - report("les", R_AX | R_BX, - outregs.eax == (unsigned long)desc.address && - outregs.ebx == desc.sel); - - MK_INSN(lfs, "pushl %fs\n\t" - "lfs (%ebx), %eax\n\t" - "mov %fs, %ebx\n\t" - "popl %fs\n\t"); - exec_in_big_real_mode(&insn_lfs); - report("lfs", R_AX | R_BX, - outregs.eax == (unsigned long)desc.address && - outregs.ebx == desc.sel); - - MK_INSN(lgs, "pushl %gs\n\t" - "lgs (%ebx), %eax\n\t" - "mov %gs, %ebx\n\t" - "popl %gs\n\t"); - exec_in_big_real_mode(&insn_lgs); - report("lgs", R_AX | R_BX, - outregs.eax == (unsigned long)desc.address && - outregs.ebx == desc.sel); - - MK_INSN(lss, "mov %ss, %dx\n\t" - "lss (%ebx), %eax\n\t" - "mov %ss, %ebx\n\t" - "mov %dx, %ss\n\t"); - exec_in_big_real_mode(&insn_lss); - report("lss", R_AX | R_BX, - outregs.eax == (unsigned long)desc.address && - outregs.ebx == desc.sel); -} - -static void test_jcxz(void) -{ - MK_INSN(jcxz1, "jcxz 1f\n\t" - "mov $0x1234, %eax\n\t" - "1:\n\t"); - MK_INSN(jcxz2, "mov $0x100, %ecx\n\t" - "jcxz 1f\n\t" - "mov $0x1234, %eax\n\t" - "mov $0, %ecx\n\t" - "1:\n\t"); - MK_INSN(jcxz3, "mov $0x10000, %ecx\n\t" - "jcxz 1f\n\t" - "mov $0x1234, %eax\n\t" - "1:\n\t"); - MK_INSN(jecxz1, "jecxz 1f\n\t" - "mov $0x1234, %eax\n\t" - "1:\n\t"); - MK_INSN(jecxz2, "mov $0x10000, %ecx\n\t" - "jecxz 1f\n\t" - "mov $0x1234, %eax\n\t" - "mov $0, %ecx\n\t" - "1:\n\t"); - - init_inregs(NULL); - - exec_in_big_real_mode(&insn_jcxz1); - report("jcxz short 1", 0, 1); - - exec_in_big_real_mode(&insn_jcxz2); - report("jcxz short 2", R_AX, outregs.eax == 0x1234); - - exec_in_big_real_mode(&insn_jcxz3); - report("jcxz short 3", R_CX, outregs.ecx == 0x10000); - - exec_in_big_real_mode(&insn_jecxz1); - report("jecxz short 1", 0, 1); - - exec_in_big_real_mode(&insn_jecxz2); - report("jecxz short 2", R_AX, outregs.eax == 0x1234); -} - -static void test_cpuid(void) -{ - MK_INSN(cpuid, "cpuid"); - unsigned function = 0x1234; - unsigned eax, ebx, ecx, edx; - - init_inregs(&(struct regs){ .eax = function }); - - eax = inregs.eax; - ecx = inregs.ecx; - asm("cpuid" : "+a"(eax), "=b"(ebx), "+c"(ecx), "=d"(edx)); - exec_in_big_real_mode(&insn_cpuid); - report("cpuid", R_AX|R_BX|R_CX|R_DX, - outregs.eax == eax && outregs.ebx == ebx - && outregs.ecx == ecx && outregs.edx == edx); -} - -static void test_ss_base_for_esp_ebp(void) -{ - MK_INSN(ssrel1, "mov %ss, %ax; mov %bx, %ss; movl (%ebp), %ebx; mov %ax, %ss"); - MK_INSN(ssrel2, "mov %ss, %ax; mov %bx, %ss; movl (%ebp,%edi,8), %ebx; mov %ax, %ss"); - static unsigned array[] = { 0x12345678, 0, 0, 0, 0x87654321 }; - - init_inregs(&(struct regs){ .ebx = 1, .ebp = (unsigned)array }); - - exec_in_big_real_mode(&insn_ssrel1); - report("ss relative addressing (1)", R_AX | R_BX, outregs.ebx == 0x87654321); - - inregs.ebx = 1; - inregs.ebp = (unsigned)array; - inregs.edi = 0; - exec_in_big_real_mode(&insn_ssrel2); - report("ss relative addressing (2)", R_AX | R_BX, outregs.ebx == 0x87654321); -} - -extern unsigned long long r_gdt[]; - -static void test_sgdt_sidt(void) -{ - MK_INSN(sgdt, "sgdtw (%eax)"); - MK_INSN(sidt, "sidtw (%eax)"); - struct table_descr x, y; - - init_inregs(&(struct regs){ .eax = (unsigned)&y }); - - asm volatile("sgdtw %0" : "=m"(x)); - exec_in_big_real_mode(&insn_sgdt); - report("sgdt", 0, x.limit == y.limit && x.base == y.base); - - inregs.eax = (unsigned)&y; - asm volatile("sidtw %0" : "=m"(x)); - exec_in_big_real_mode(&insn_sidt); - report("sidt", 0, x.limit == y.limit && x.base == y.base); -} - -static void test_sahf(void) -{ - MK_INSN(sahf, "sahf; pushfw; mov (%esp), %al; popfw"); - - init_inregs(&(struct regs){ .eax = 0xfd00 }); - - exec_in_big_real_mode(&insn_sahf); - report("sahf", R_AX, outregs.eax == (inregs.eax | 0xd7)); -} - -static void test_lahf(void) -{ - MK_INSN(lahf, "pushfw; mov %al, (%esp); popfw; lahf"); - - init_inregs(&(struct regs){ .eax = 0xc7 }); - - exec_in_big_real_mode(&insn_lahf); - report("lahf", R_AX, (outregs.eax >> 8) == inregs.eax); -} - -static void test_movzx_movsx(void) -{ - MK_INSN(movsx, "movsx %al, %ebx"); - MK_INSN(movzx, "movzx %al, %ebx"); - MK_INSN(movzsah, "movsx %ah, %ebx"); - MK_INSN(movzxah, "movzx %ah, %ebx"); - - init_inregs(&(struct regs){ .eax = 0x1234569c }); - - exec_in_big_real_mode(&insn_movsx); - report("movsx", R_BX, outregs.ebx == (signed char)inregs.eax); - exec_in_big_real_mode(&insn_movzx); - report("movzx", R_BX, outregs.ebx == (unsigned char)inregs.eax); - exec_in_big_real_mode(&insn_movzsah); - report("movsx ah", R_BX, outregs.ebx == (signed char)(inregs.eax>>8)); - exec_in_big_real_mode(&insn_movzxah); - report("movzx ah", R_BX, outregs.ebx == (unsigned char)(inregs.eax >> 8)); -} - -static void test_bswap(void) -{ - MK_INSN(bswap, "bswap %ecx"); - - init_inregs(&(struct regs){ .ecx = 0x12345678 }); - - exec_in_big_real_mode(&insn_bswap); - report("bswap", R_CX, outregs.ecx == 0x78563412); -} - -static void test_aad(void) -{ - MK_INSN(aad, "aad"); - - init_inregs(&(struct regs){ .eax = 0x12345678 }); - - exec_in_big_real_mode(&insn_aad); - report("aad", R_AX, outregs.eax == 0x123400d4); -} - -static void test_aam(void) -{ - MK_INSN(aam, "aam"); - - init_inregs(&(struct regs){ .eax = 0x76543210 }); - - exec_in_big_real_mode(&insn_aam); - report("aam", R_AX, outregs.eax == 0x76540106); -} - -static void test_xlat(void) -{ - MK_INSN(xlat, "xlat"); - u8 table[256]; - int i; - - for (i = 0; i < 256; i++) { - table[i] = i + 1; - } - - init_inregs(&(struct regs){ .eax = 0x89abcdef, .ebx = (u32)table }); - - exec_in_big_real_mode(&insn_xlat); - report("xlat", R_AX, outregs.eax == 0x89abcdf0); -} - -static void test_salc(void) -{ - MK_INSN(clc_salc, "clc; .byte 0xd6"); - MK_INSN(stc_salc, "stc; .byte 0xd6"); - - init_inregs(&(struct regs){ .eax = 0x12345678 }); - - exec_in_big_real_mode(&insn_clc_salc); - report("salc (1)", R_AX, outregs.eax == 0x12345600); - exec_in_big_real_mode(&insn_stc_salc); - report("salc (2)", R_AX, outregs.eax == 0x123456ff); -} - -static void test_fninit(void) -{ - u16 fcw = -1, fsw = -1; - MK_INSN(fninit, "fninit ; fnstsw (%eax) ; fnstcw (%ebx)"); - - init_inregs(&(struct regs){ .eax = (u32)&fsw, .ebx = (u32)&fcw }); - - exec_in_big_real_mode(&insn_fninit); - report("fninit", 0, fsw == 0 && (fcw & 0x103f) == 0x003f); -} - -static void test_nopl(void) -{ - MK_INSN(nopl1, ".byte 0x90\n\r"); // 1 byte nop - MK_INSN(nopl2, ".byte 0x66, 0x90\n\r"); // 2 bytes nop - MK_INSN(nopl3, ".byte 0x0f, 0x1f, 0x00\n\r"); // 3 bytes nop - MK_INSN(nopl4, ".byte 0x0f, 0x1f, 0x40, 0x00\n\r"); // 4 bytes nop - exec_in_big_real_mode(&insn_nopl1); - exec_in_big_real_mode(&insn_nopl2); - exec_in_big_real_mode(&insn_nopl3); - exec_in_big_real_mode(&insn_nopl4); - report("nopl", 0, 1); -} - -static u32 perf_baseline; - -#define PERF_COUNT 1000000 - -#define MK_INSN_PERF(name, insn) \ - MK_INSN(name, "rdtsc; mov %eax, %ebx; mov %edx, %esi\n" \ - "1:" insn "\n" \ - ".byte 0x67; loop 1b\n" \ - "rdtsc"); - -static u32 cycles_in_big_real_mode(struct insn_desc *insn) -{ - u64 start, end; - - init_inregs(&(struct regs){ .ecx = PERF_COUNT }); - - exec_in_big_real_mode(insn); - start = ((u64)outregs.esi << 32) | outregs.ebx; - end = ((u64)outregs.edx << 32) | outregs.eax; - - return end - start; -} - -static void test_perf_loop(void) -{ - /* - * This test runs simple instructions that should roughly take the - * the same time to emulate: PERF_COUNT iterations of "loop" and 3 - * setup instructions. Other performance tests can run PERF_COUNT - * iterations of the same instruction and subtract the cycle count - * of this test. - */ - MK_INSN_PERF(perf_loop, ""); - perf_baseline = cycles_in_big_real_mode(&insn_perf_loop); - print_serial_u32(perf_baseline / (PERF_COUNT + 3)); - print_serial(" cycles/emulated jump instruction\n"); -} - -static void test_perf_mov(void) -{ - u32 cyc; - - MK_INSN_PERF(perf_move, "mov %esi, %edi"); - cyc = cycles_in_big_real_mode(&insn_perf_move); - print_serial_u32((cyc - perf_baseline) / PERF_COUNT); - print_serial(" cycles/emulated move instruction\n"); -} - -static void test_perf_arith(void) -{ - u32 cyc; - - MK_INSN_PERF(perf_arith, "add $4, %edi"); - cyc = cycles_in_big_real_mode(&insn_perf_arith); - print_serial_u32((cyc - perf_baseline) / PERF_COUNT); - print_serial(" cycles/emulated arithmetic instruction\n"); -} - -static void test_perf_memory_load(void) -{ - u32 cyc, tmp; - - MK_INSN_PERF(perf_memory_load, "cmpw $0, (%edi)"); - - init_inregs(&(struct regs){ .edi = (u32)&tmp }); - - cyc = cycles_in_big_real_mode(&insn_perf_memory_load); - print_serial_u32((cyc - perf_baseline) / PERF_COUNT); - print_serial(" cycles/emulated memory load instruction\n"); -} - -static void test_perf_memory_store(void) -{ - u32 cyc, tmp; - - MK_INSN_PERF(perf_memory_store, "movw %ax, (%edi)"); - - init_inregs(&(struct regs){ .edi = (u32)&tmp }); - - cyc = cycles_in_big_real_mode(&insn_perf_memory_store); - print_serial_u32((cyc - perf_baseline) / PERF_COUNT); - print_serial(" cycles/emulated memory store instruction\n"); -} - -static void test_perf_memory_rmw(void) -{ - u32 cyc, tmp; - - MK_INSN_PERF(perf_memory_rmw, "addw $1, (%edi)"); - - init_inregs(&(struct regs){ .edi = (u32)&tmp }); - - cyc = cycles_in_big_real_mode(&insn_perf_memory_rmw); - print_serial_u32((cyc - perf_baseline) / PERF_COUNT); - print_serial(" cycles/emulated memory RMW instruction\n"); -} - -static void test_dr_mod(void) -{ - MK_INSN(drmod, "movl %ebx, %dr0\n\t" - ".byte 0x0f \n\t .byte 0x21 \n\t .byte 0x0\n\t"); - - init_inregs(&(struct regs){ .eax = 0xdead, .ebx = 0xaced }); - - exec_in_big_real_mode(&insn_drmod); - report("mov dr with mod bits", R_AX | R_BX, outregs.eax == 0xaced); -} - -static void test_smsw(void) -{ - MK_INSN(smsw, "movl %cr0, %ebx\n\t" - "movl %ebx, %ecx\n\t" - "or $0x40000000, %ebx\n\t" - "movl %ebx, %cr0\n\t" - "smswl %eax\n\t" - "movl %ecx, %cr0\n\t"); - - init_inregs(&(struct regs){ .eax = 0x12345678 }); - - exec_in_big_real_mode(&insn_smsw); - report("smsw", R_AX | R_BX | R_CX, outregs.eax == outregs.ebx); -} - -static void test_xadd(void) -{ - MK_INSN(xadd, "xaddl %eax, %eax\n\t"); - - init_inregs(&(struct regs){ .eax = 0x12345678 }); - - exec_in_big_real_mode(&insn_xadd); - report("xadd", R_AX, outregs.eax == inregs.eax * 2); -} - - -void realmode_start(void) -{ - test_null(); - - test_shld(); - test_push_pop(); - test_pusha_popa(); - test_mov_imm(); - test_cmp_imm(); - test_add_imm(); - test_sub_imm(); - test_xor_imm(); - test_io(); - test_eflags_insn(); - test_jcc_short(); - test_jcc_near(); - /* test_call() uses short jump so call it after testing jcc */ - test_call(); - /* long jmp test uses call near so test it after testing call */ - test_long_jmp(); - test_xchg(); - test_iret(); - test_int(); - test_sti_inhibit(); - test_imul(); - test_mul(); - test_div(); - test_idiv(); - test_loopcc(); - test_cbw(); - test_cwd_cdq(); - test_das(); - test_lds_lss(); - test_jcxz(); - test_cpuid(); - test_ss_base_for_esp_ebp(); - test_sgdt_sidt(); - test_lahf(); - test_sahf(); - test_movzx_movsx(); - test_bswap(); - test_aad(); - test_aam(); - test_xlat(); - test_salc(); - test_fninit(); - test_dr_mod(); - test_smsw(); - test_nopl(); - test_xadd(); - test_perf_loop(); - test_perf_mov(); - test_perf_arith(); - test_perf_memory_load(); - test_perf_memory_store(); - test_perf_memory_rmw(); - - exit(failed); -} - -unsigned long long r_gdt[] = { 0, 0x9b000000ffff, 0x93000000ffff }; - -struct table_descr r_gdt_descr = { sizeof(r_gdt) - 1, &r_gdt }; -struct table_descr r_idt_descr = { 0x3ff, 0 }; - -asm( - ".section .init \n\t" - - ".code32 \n\t" - - "mb_magic = 0x1BADB002 \n\t" - "mb_flags = 0x0 \n\t" - - "# multiboot header \n\t" - ".long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) \n\t" - - ".globl start \n\t" - ".data \n\t" - ". = . + 4096 \n\t" - "stacktop: \n\t" - - ".text \n\t" - "start: \n\t" - "lgdt r_gdt_descr \n\t" - "lidt r_idt_descr \n\t" - "ljmp $8, $1f; 1: \n\t" - ".code16gcc \n\t" - "mov $16, %eax \n\t" - "mov %ax, %ds \n\t" - "mov %ax, %es \n\t" - "mov %ax, %fs \n\t" - "mov %ax, %gs \n\t" - "mov %ax, %ss \n\t" - "mov %cr0, %eax \n\t" - "btc $0, %eax \n\t" - "mov %eax, %cr0 \n\t" - "ljmp $0, $realmode_entry \n\t" - - "realmode_entry: \n\t" - - "xor %ax, %ax \n\t" - "mov %ax, %ds \n\t" - "mov %ax, %es \n\t" - "mov %ax, %ss \n\t" - "mov %ax, %fs \n\t" - "mov %ax, %gs \n\t" - "mov $stacktop, %esp\n\t" - "ljmp $0, $realmode_start \n\t" - - ".code16gcc \n\t" - ); diff --git a/x86/realmode.lds b/x86/realmode.lds deleted file mode 100644 index 0ed3063b..00000000 --- a/x86/realmode.lds +++ /dev/null @@ -1,12 +0,0 @@ -SECTIONS -{ - . = 16K; - stext = .; - .text : { *(.init) *(.text) } - . = ALIGN(4K); - .data : { *(.data) *(.rodata*) } - . = ALIGN(16); - .bss : { *(.bss) } - edata = .; -} -ENTRY(start) diff --git a/x86/rmap_chain.c b/x86/rmap_chain.c deleted file mode 100644 index 3433dda8..00000000 --- a/x86/rmap_chain.c +++ /dev/null @@ -1,47 +0,0 @@ -/* test long rmap chains */ - -#include "libcflat.h" -#include "fwcfg.h" -#include "vm.h" -#include "vmalloc.h" -#include "smp.h" -#include "alloc_page.h" - -int main (void) -{ - int i; - int nr_pages; - void *target_page, *virt_addr; - - setup_vm(); - - nr_pages = fwcfg_get_u64(FW_CFG_RAM_SIZE) / PAGE_SIZE; - nr_pages -= 1000; - target_page = alloc_page(); - - virt_addr = (void *) 0xfffffa000; - for (i = 0; i < nr_pages; i++) { - install_page(phys_to_virt(read_cr3()), virt_to_phys(target_page), - virt_addr); - virt_addr += PAGE_SIZE; - } - printf("created %d mappings\n", nr_pages); - - virt_addr = (void *) 0xfffffa000; - for (i = 0; i < nr_pages; i++) { - unsigned long *touch = virt_addr; - - *touch = 0; - virt_addr += PAGE_SIZE; - } - printf("instantiated mappings\n"); - - virt_addr += PAGE_SIZE; - install_pte(phys_to_virt(read_cr3()), 1, virt_addr, - 0 | PT_PRESENT_MASK | PT_WRITABLE_MASK, target_page); - - *(unsigned long *)virt_addr = 0; - printf("PASS\n"); - - return 0; -} diff --git a/x86/run b/x86/run deleted file mode 100755 index 8b2425f4..00000000 --- a/x86/run +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -if [ -z "$STANDALONE" ]; then - if [ ! -f config.mak ]; then - echo "run ./configure && make first. See ./configure -h" - exit 2 - fi - source config.mak - source scripts/arch-run.bash -fi - -ACCEL=$(get_qemu_accelerator) || - exit $? - -qemu=$(search_qemu_binary) || - exit $? - -if ! ${qemu} -device '?' 2>&1 | grep -F -e \"testdev\" -e \"pc-testdev\" > /dev/null; -then - echo "No Qemu test device support found" - exit 2 -fi - -if - ${qemu} -device '?' 2>&1 | grep -F "pci-testdev" > /dev/null; -then - pci_testdev="-device pci-testdev" -else - pci_testdev="" -fi - -if - ${qemu} -device '?' 2>&1 | grep -F "pc-testdev" > /dev/null; -then - pc_testdev="-device pc-testdev -device isa-debug-exit,iobase=0xf4,iosize=0x4" -else - pc_testdev="-device testdev,chardev=testlog -chardev file,id=testlog,path=msr.out" -fi - -command="${qemu} --no-reboot -nodefaults $pc_testdev -vnc none -serial stdio $pci_testdev" -command+=" -machine accel=$ACCEL -kernel" -command="$(timeout_cmd) $command" - -run_qemu ${command} "$@" diff --git a/x86/s3.c b/x86/s3.c deleted file mode 100644 index da2d00c3..00000000 --- a/x86/s3.c +++ /dev/null @@ -1,89 +0,0 @@ -#include "libcflat.h" -#include "x86/acpi.h" -#include "asm/io.h" - -static u32* find_resume_vector_addr(void) -{ - struct facs_descriptor_rev1 *facs = find_acpi_table_addr(FACS_SIGNATURE); - if (!facs) - return 0; - printf("FACS is at %p\n", facs); - return &facs->firmware_waking_vector; -} - -#define RTC_SECONDS_ALARM 1 -#define RTC_MINUTES_ALARM 3 -#define RTC_HOURS_ALARM 5 -#define RTC_ALARM_DONT_CARE 0xC0 - -#define RTC_REG_A 10 -#define RTC_REG_B 11 -#define RTC_REG_C 12 - -#define REG_A_UIP 0x80 -#define REG_B_AIE 0x20 - -static inline int rtc_in(u8 reg) -{ - outb(reg, 0x70); - return inb(0x71); -} - -static inline void rtc_out(u8 reg, u8 val) -{ - outb(reg, 0x70); - outb(val, 0x71); -} - -extern char resume_start, resume_end; - -int main(int argc, char **argv) -{ - struct fadt_descriptor_rev1 *fadt = find_acpi_table_addr(FACP_SIGNATURE); - volatile u32 *resume_vector_ptr = find_resume_vector_addr(); - char *addr, *resume_vec = (void*)0x1000; - - *resume_vector_ptr = (u32)(ulong)resume_vec; - - printf("resume vector addr is %p\n", resume_vector_ptr); - for (addr = &resume_start; addr < &resume_end; addr++) - *resume_vec++ = *addr; - printf("copy resume code from %p\n", &resume_start); - - printf("PM1a event registers at %x\n", fadt->pm1a_evt_blk); - outw(0x400, fadt->pm1a_evt_blk + 2); - - /* Setup RTC alarm to wake up on the next second. */ - while ((rtc_in(RTC_REG_A) & REG_A_UIP) == 0); - while ((rtc_in(RTC_REG_A) & REG_A_UIP) != 0); - rtc_in(RTC_REG_C); - rtc_out(RTC_SECONDS_ALARM, RTC_ALARM_DONT_CARE); - rtc_out(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE); - rtc_out(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE); - rtc_out(RTC_REG_B, rtc_in(RTC_REG_B) | REG_B_AIE); - - *(volatile int*)0 = 0; - asm volatile("outw %0, %1" :: "a"((short)0x2400), "d"((short)fadt->pm1a_cnt_blk):"memory"); - while(1) - *(volatile int*)0 = 1; - - return 0; -} - -asm ( - ".global resume_start\n" - ".global resume_end\n" - ".code16\n" - "resume_start:\n" - "mov 0x0, %eax\n" - "mov $0xf4, %dx\n" - "out %eax, %dx\n" - "1: hlt\n" - "jmp 1b\n" - "resume_end:\n" -#ifdef __i386__ - ".code32\n" -#else - ".code64\n" -#endif - ); diff --git a/x86/setjmp.c b/x86/setjmp.c deleted file mode 100644 index cc411cd1..00000000 --- a/x86/setjmp.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "libcflat.h" -#include "setjmp.h" - -static const int expected[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 -}; - -#define NUM_LONGJMPS ARRAY_SIZE(expected) - -int main(void) -{ - volatile int index = 0; - jmp_buf j; - int i; - - i = setjmp(j); - report(expected[index] == i, "actual %d == expected %d", - i, expected[index]); - index++; - if (i + 1 < NUM_LONGJMPS) - longjmp(j, i + 1); - - return report_summary(); -} diff --git a/x86/sieve.c b/x86/sieve.c deleted file mode 100644 index 8150f2d9..00000000 --- a/x86/sieve.c +++ /dev/null @@ -1,51 +0,0 @@ -#include "alloc.h" -#include "libcflat.h" - -static int sieve(char* data, int size) -{ - int i, j, r = 0; - - for (i = 0; i < size; ++i) - data[i] = 1; - - data[0] = data[1] = 0; - - for (i = 2; i < size; ++i) - if (data[i]) { - ++r; - for (j = i*2; j < size; j += i) - data[j] = 0; - } - return r; -} - -static void test_sieve(const char *msg, char *data, int size) -{ - int r; - - printf("%s:", msg); - r = sieve(data, size); - printf("%d out of %d\n", r, size); -} - -#define STATIC_SIZE 1000000 -#define VSIZE 100000000 -char static_data[STATIC_SIZE]; - -int main(void) -{ - void *v; - int i; - - printf("starting sieve\n"); - test_sieve("static", static_data, STATIC_SIZE); - setup_vm(); - test_sieve("mapped", static_data, STATIC_SIZE); - for (i = 0; i < 3; ++i) { - v = malloc(VSIZE); - test_sieve("virtual", v, VSIZE); - free(v); - } - - return 0; -} diff --git a/x86/smap.c b/x86/smap.c deleted file mode 100644 index 5782c4a1..00000000 --- a/x86/smap.c +++ /dev/null @@ -1,194 +0,0 @@ -#include "libcflat.h" -#include "x86/desc.h" -#include "x86/processor.h" -#include "x86/vm.h" - -volatile int pf_count = 0; -volatile int save; -volatile unsigned test; - -void do_pf_tss(unsigned long error_code); - -// When doing ring 3 tests, page fault handlers will always run on a -// separate stack (the ring 0 stack). Seems easier to use the alt_stack -// mechanism for both ring 0 and ring 3. - -void do_pf_tss(unsigned long error_code) -{ - pf_count++; - save = test; - -#ifndef __x86_64__ - tss.eflags |= X86_EFLAGS_AC; -#endif -} - -extern void pf_tss(void); -asm ("pf_tss:\n" -#ifdef __x86_64__ - // no task on x86_64, save/restore caller-save regs - "push %rax; push %rcx; push %rdx; push %rsi; push %rdi\n" - "push %r8; push %r9; push %r10; push %r11\n" - "mov 9*8(%rsp),%rdi\n" -#endif - "call do_pf_tss\n" -#ifdef __x86_64__ - "pop %r11; pop %r10; pop %r9; pop %r8\n" - "pop %rdi; pop %rsi; pop %rdx; pop %rcx; pop %rax\n" -#endif - "add $"S", %"R "sp\n" -#ifdef __x86_64__ - "orl $" xstr(X86_EFLAGS_AC) ", 2*"S"(%"R "sp)\n" // set EFLAGS.AC and retry -#endif - "iret"W" \n\t" - "jmp pf_tss\n\t"); - - -#define USER_BASE (1 << 24) -#define USER_VAR(v) (*((__typeof__(&(v))) (((unsigned long)&v) + USER_BASE))) -#define USER_ADDR(v) ((void *)((unsigned long)(&v) + USER_BASE)) - -static void init_test(int i) -{ - pf_count = 0; - if (i) { - invlpg(&test); - invlpg(&USER_VAR(test)); - } -} - -static void check_smap_nowp(void) -{ - test = 0x99; - - *get_pte(phys_to_virt(read_cr3()), USER_ADDR(test)) &= ~PT_WRITABLE_MASK; - - write_cr4(read_cr4() & ~X86_CR4_SMAP); - write_cr0(read_cr0() & ~X86_CR0_WP); - clac(); - write_cr3(read_cr3()); - - init_test(0); - USER_VAR(test) = 0x99; - report(pf_count == 0, - "write from user page with SMAP=0, AC=0, WP=0, PTE.U=1 && PTE.W=0"); - - write_cr4(read_cr4() | X86_CR4_SMAP); - write_cr3(read_cr3()); - - init_test(0); - (void)USER_VAR(test); - report(pf_count == 1 && save == 0x99, - "read from user page with SMAP=1, AC=0, WP=0, PTE.U=1 && PTE.W=0"); - - /* Undo changes */ - *get_pte(phys_to_virt(read_cr3()), USER_ADDR(test)) |= PT_WRITABLE_MASK; - - write_cr0(read_cr0() | X86_CR0_WP); - write_cr3(read_cr3()); -} - -int main(int ac, char **av) -{ - unsigned long i; - - if (!this_cpu_has(X86_FEATURE_SMAP)) { - printf("SMAP not enabled\n"); - return report_summary(); - } - - setup_vm(); - setup_alt_stack(); - set_intr_alt_stack(14, pf_tss); - - // Map first 16MB as supervisor pages - for (i = 0; i < USER_BASE; i += PAGE_SIZE) { - *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) &= ~PT_USER_MASK; - invlpg((void *)i); - } - - // Present the same 16MB as user pages in the 16MB-32MB range - for (i = USER_BASE; i < 2 * USER_BASE; i += PAGE_SIZE) { - *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) &= ~USER_BASE; - invlpg((void *)i); - } - - clac(); - write_cr4(read_cr4() | X86_CR4_SMAP); - write_cr3(read_cr3()); - - for (i = 0; i < 2; i++) { - if (i) - printf("testing with INVLPG\n"); - else - printf("testing without INVLPG\n"); - - init_test(i); - clac(); - test = 42; - report(pf_count == 0 && test == 42, - "write to supervisor page"); - - init_test(i); - stac(); - (void)USER_VAR(test); - report(pf_count == 0, "read from user page with AC=1"); - - init_test(i); - clac(); - (void)USER_VAR(test); - report(pf_count == 1 && save == 42, - "read from user page with AC=0"); - - init_test(i); - stac(); - save = 0; - USER_VAR(test) = 43; - report(pf_count == 0 && test == 43, - "write to user page with AC=1"); - - init_test(i); - clac(); - USER_VAR(test) = 44; - report(pf_count == 1 && test == 44 && save == 43, - "read from user page with AC=0"); - - init_test(i); - stac(); - test = -1; - asm("or $(" xstr(USER_BASE) "), %"R "sp \n" - "push $44 \n " - "decl test\n" - "and $~(" xstr(USER_BASE) "), %"R "sp \n" - "pop %"R "ax\n" - "movl %eax, test"); - report(pf_count == 0 && test == 44, - "write to user stack with AC=1"); - - init_test(i); - clac(); - test = -1; - asm("or $(" xstr(USER_BASE) "), %"R "sp \n" - "push $45 \n " - "decl test\n" - "and $~(" xstr(USER_BASE) "), %"R "sp \n" - "pop %"R "ax\n" - "movl %eax, test"); - report(pf_count == 1 && test == 45 && save == -1, - "write to user stack with AC=0"); - - /* This would be trapped by SMEP */ - init_test(i); - clac(); - asm("jmp 1f + "xstr(USER_BASE)" \n" - "1: jmp 2f - "xstr(USER_BASE)" \n" - "2:"); - report(pf_count == 0, "executing on user page with AC=0"); - } - - check_smap_nowp(); - - // TODO: implicit kernel access from ring 3 (e.g. int) - - return report_summary(); -} diff --git a/x86/smptest.c b/x86/smptest.c deleted file mode 100644 index 2989aa0b..00000000 --- a/x86/smptest.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "libcflat.h" -#include "smp.h" - -unsigned nipis; - -static void ipi_test(void *data) -{ - int n = (long)data; - - printf("ipi called, cpu %d\n", n); - if (n != smp_id()) - printf("but wrong cpu %d\n", smp_id()); - else - nipis++; -} - -int main(void) -{ - int ncpus; - int i; - - ncpus = cpu_count(); - printf("found %d cpus\n", ncpus); - for (i = 0; i < ncpus; ++i) - on_cpu(i, ipi_test, (void *)(long)i); - - report(nipis == ncpus, "IPI to each CPU"); - return report_summary(); -} diff --git a/x86/svm.c b/x86/svm.c deleted file mode 100644 index d8c8272a..00000000 --- a/x86/svm.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Framework for testing nested virtualization - */ - -#include "svm.h" -#include "libcflat.h" -#include "processor.h" -#include "desc.h" -#include "msr.h" -#include "vm.h" -#include "smp.h" -#include "types.h" -#include "alloc_page.h" -#include "isr.h" -#include "apic.h" - -/* for the nested page table*/ -u64 *pte[2048]; -u64 *pde[4]; -u64 *pdpe; -u64 *pml4e; - -struct vmcb *vmcb; - -u64 *npt_get_pte(u64 address) -{ - int i1, i2; - - address >>= 12; - i1 = (address >> 9) & 0x7ff; - i2 = address & 0x1ff; - - return &pte[i1][i2]; -} - -u64 *npt_get_pde(u64 address) -{ - int i1, i2; - - address >>= 21; - i1 = (address >> 9) & 0x3; - i2 = address & 0x1ff; - - return &pde[i1][i2]; -} - -u64 *npt_get_pdpe(void) -{ - return pdpe; -} - -u64 *npt_get_pml4e(void) -{ - return pml4e; -} - -bool smp_supported(void) -{ - return cpu_count() > 1; -} - -bool default_supported(void) -{ - return true; -} - -void default_prepare(struct svm_test *test) -{ - vmcb_ident(vmcb); -} - -void default_prepare_gif_clear(struct svm_test *test) -{ -} - -bool default_finished(struct svm_test *test) -{ - return true; /* one vmexit */ -} - -bool npt_supported(void) -{ - return this_cpu_has(X86_FEATURE_NPT); -} - -int get_test_stage(struct svm_test *test) -{ - barrier(); - return test->scratch; -} - -void set_test_stage(struct svm_test *test, int s) -{ - barrier(); - test->scratch = s; - barrier(); -} - -void inc_test_stage(struct svm_test *test) -{ - barrier(); - test->scratch++; - barrier(); -} - -static void vmcb_set_seg(struct vmcb_seg *seg, u16 selector, - u64 base, u32 limit, u32 attr) -{ - seg->selector = selector; - seg->attrib = attr; - seg->limit = limit; - seg->base = base; -} - -inline void vmmcall(void) -{ - asm volatile ("vmmcall" : : : "memory"); -} - -static test_guest_func guest_main; - -void test_set_guest(test_guest_func func) -{ - guest_main = func; -} - -static void test_thunk(struct svm_test *test) -{ - guest_main(test); - vmmcall(); -} - -u8 *io_bitmap; -u8 io_bitmap_area[16384]; - -u8 *msr_bitmap; -u8 msr_bitmap_area[MSR_BITMAP_SIZE + PAGE_SIZE]; - -void vmcb_ident(struct vmcb *vmcb) -{ - u64 vmcb_phys = virt_to_phys(vmcb); - struct vmcb_save_area *save = &vmcb->save; - struct vmcb_control_area *ctrl = &vmcb->control; - u32 data_seg_attr = 3 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK - | SVM_SELECTOR_DB_MASK | SVM_SELECTOR_G_MASK; - u32 code_seg_attr = 9 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK - | SVM_SELECTOR_L_MASK | SVM_SELECTOR_G_MASK; - struct descriptor_table_ptr desc_table_ptr; - - memset(vmcb, 0, sizeof(*vmcb)); - asm volatile ("vmsave %0" : : "a"(vmcb_phys) : "memory"); - vmcb_set_seg(&save->es, read_es(), 0, -1U, data_seg_attr); - vmcb_set_seg(&save->cs, read_cs(), 0, -1U, code_seg_attr); - vmcb_set_seg(&save->ss, read_ss(), 0, -1U, data_seg_attr); - vmcb_set_seg(&save->ds, read_ds(), 0, -1U, data_seg_attr); - sgdt(&desc_table_ptr); - vmcb_set_seg(&save->gdtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0); - sidt(&desc_table_ptr); - vmcb_set_seg(&save->idtr, 0, desc_table_ptr.base, desc_table_ptr.limit, 0); - ctrl->asid = 1; - save->cpl = 0; - save->efer = rdmsr(MSR_EFER); - save->cr4 = read_cr4(); - save->cr3 = read_cr3(); - save->cr0 = read_cr0(); - save->dr7 = read_dr7(); - save->dr6 = read_dr6(); - save->cr2 = read_cr2(); - save->g_pat = rdmsr(MSR_IA32_CR_PAT); - save->dbgctl = rdmsr(MSR_IA32_DEBUGCTLMSR); - ctrl->intercept = (1ULL << INTERCEPT_VMRUN) | (1ULL << INTERCEPT_VMMCALL); - ctrl->iopm_base_pa = virt_to_phys(io_bitmap); - ctrl->msrpm_base_pa = virt_to_phys(msr_bitmap); - - if (npt_supported()) { - ctrl->nested_ctl = 1; - ctrl->nested_cr3 = (u64)pml4e; - ctrl->tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID; - } -} - -struct regs regs; - -struct regs get_regs(void) -{ - return regs; -} - -// rax handled specially below - -#define SAVE_GPR_C \ - "xchg %%rbx, regs+0x8\n\t" \ - "xchg %%rcx, regs+0x10\n\t" \ - "xchg %%rdx, regs+0x18\n\t" \ - "xchg %%rbp, regs+0x28\n\t" \ - "xchg %%rsi, regs+0x30\n\t" \ - "xchg %%rdi, regs+0x38\n\t" \ - "xchg %%r8, regs+0x40\n\t" \ - "xchg %%r9, regs+0x48\n\t" \ - "xchg %%r10, regs+0x50\n\t" \ - "xchg %%r11, regs+0x58\n\t" \ - "xchg %%r12, regs+0x60\n\t" \ - "xchg %%r13, regs+0x68\n\t" \ - "xchg %%r14, regs+0x70\n\t" \ - "xchg %%r15, regs+0x78\n\t" - -#define LOAD_GPR_C SAVE_GPR_C - -struct svm_test *v2_test; - -#define ASM_VMRUN_CMD \ - "vmload %%rax\n\t" \ - "mov regs+0x80, %%r15\n\t" \ - "mov %%r15, 0x170(%%rax)\n\t" \ - "mov regs, %%r15\n\t" \ - "mov %%r15, 0x1f8(%%rax)\n\t" \ - LOAD_GPR_C \ - "vmrun %%rax\n\t" \ - SAVE_GPR_C \ - "mov 0x170(%%rax), %%r15\n\t" \ - "mov %%r15, regs+0x80\n\t" \ - "mov 0x1f8(%%rax), %%r15\n\t" \ - "mov %%r15, regs\n\t" \ - "vmsave %%rax\n\t" \ - -u64 guest_stack[10000]; - -int svm_vmrun(void) -{ - vmcb->save.rip = (ulong)test_thunk; - vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack)); - regs.rdi = (ulong)v2_test; - - asm volatile ( - ASM_VMRUN_CMD - : - : "a" (virt_to_phys(vmcb)) - : "memory", "r15"); - - return (vmcb->control.exit_code); -} - -static void test_run(struct svm_test *test) -{ - u64 vmcb_phys = virt_to_phys(vmcb); - - irq_disable(); - test->prepare(test); - guest_main = test->guest_func; - vmcb->save.rip = (ulong)test_thunk; - vmcb->save.rsp = (ulong)(guest_stack + ARRAY_SIZE(guest_stack)); - regs.rdi = (ulong)test; - do { - struct svm_test *the_test = test; - u64 the_vmcb = vmcb_phys; - asm volatile ( - "clgi;\n\t" // semi-colon needed for LLVM compatibility - "sti \n\t" - "call *%c[PREPARE_GIF_CLEAR](%[test]) \n \t" - "mov %[vmcb_phys], %%rax \n\t" - ASM_VMRUN_CMD - "cli \n\t" - "stgi" - : // inputs clobbered by the guest: - "=D" (the_test), // first argument register - "=b" (the_vmcb) // callee save register! - : [test] "0" (the_test), - [vmcb_phys] "1"(the_vmcb), - [PREPARE_GIF_CLEAR] "i" (offsetof(struct svm_test, prepare_gif_clear)) - : "rax", "rcx", "rdx", "rsi", - "r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15", - "memory"); - ++test->exits; - } while (!test->finished(test)); - irq_enable(); - - report(test->succeeded(test), "%s", test->name); -} - -static void setup_svm(void) -{ - void *hsave = alloc_page(); - u64 *page, address; - int i,j; - - wrmsr(MSR_VM_HSAVE_PA, virt_to_phys(hsave)); - wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SVME); - wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX); - - io_bitmap = (void *) (((ulong)io_bitmap_area + 4095) & ~4095); - - msr_bitmap = (void *) ALIGN((ulong)msr_bitmap_area, PAGE_SIZE); - - if (!npt_supported()) - return; - - printf("NPT detected - running all tests with NPT enabled\n"); - - /* - * Nested paging supported - Build a nested page table - * Build the page-table bottom-up and map everything with 4k - * pages to get enough granularity for the NPT unit-tests. - */ - - address = 0; - - /* PTE level */ - for (i = 0; i < 2048; ++i) { - page = alloc_page(); - - for (j = 0; j < 512; ++j, address += 4096) - page[j] = address | 0x067ULL; - - pte[i] = page; - } - - /* PDE level */ - for (i = 0; i < 4; ++i) { - page = alloc_page(); - - for (j = 0; j < 512; ++j) - page[j] = (u64)pte[(i * 512) + j] | 0x027ULL; - - pde[i] = page; - } - - /* PDPe level */ - pdpe = alloc_page(); - for (i = 0; i < 4; ++i) - pdpe[i] = ((u64)(pde[i])) | 0x27; - - /* PML4e level */ - pml4e = alloc_page(); - pml4e[0] = ((u64)pdpe) | 0x27; -} - -int matched; - -static bool -test_wanted(const char *name, char *filters[], int filter_count) -{ - int i; - bool positive = false; - bool match = false; - char clean_name[strlen(name) + 1]; - char *c; - const char *n; - - /* Replace spaces with underscores. */ - n = name; - c = &clean_name[0]; - do *c++ = (*n == ' ') ? '_' : *n; - while (*n++); - - for (i = 0; i < filter_count; i++) { - const char *filter = filters[i]; - - if (filter[0] == '-') { - if (simple_glob(clean_name, filter + 1)) - return false; - } else { - positive = true; - match |= simple_glob(clean_name, filter); - } - } - - if (!positive || match) { - matched++; - return true; - } else { - return false; - } -} - -int main(int ac, char **av) -{ - int i = 0; - - ac--; - av++; - - setup_vm(); - - if (!this_cpu_has(X86_FEATURE_SVM)) { - printf("SVM not availble\n"); - return report_summary(); - } - - setup_svm(); - - vmcb = alloc_page(); - - for (; svm_tests[i].name != NULL; i++) { - if (!test_wanted(svm_tests[i].name, av, ac)) - continue; - if (svm_tests[i].supported && !svm_tests[i].supported()) - continue; - if (svm_tests[i].v2 == NULL) { - test_run(&svm_tests[i]); - } else { - vmcb_ident(vmcb); - v2_test = &(svm_tests[i]); - svm_tests[i].v2(); - } - } - - if (!matched) - report(matched, "command line didn't match any tests!"); - - return report_summary(); -} diff --git a/x86/svm.h b/x86/svm.h deleted file mode 100644 index f8e7429d..00000000 --- a/x86/svm.h +++ /dev/null @@ -1,397 +0,0 @@ -#ifndef __SVM_H -#define __SVM_H - -#include "libcflat.h" - -enum { - INTERCEPT_INTR, - INTERCEPT_NMI, - INTERCEPT_SMI, - INTERCEPT_INIT, - INTERCEPT_VINTR, - INTERCEPT_SELECTIVE_CR0, - INTERCEPT_STORE_IDTR, - INTERCEPT_STORE_GDTR, - INTERCEPT_STORE_LDTR, - INTERCEPT_STORE_TR, - INTERCEPT_LOAD_IDTR, - INTERCEPT_LOAD_GDTR, - INTERCEPT_LOAD_LDTR, - INTERCEPT_LOAD_TR, - INTERCEPT_RDTSC, - INTERCEPT_RDPMC, - INTERCEPT_PUSHF, - INTERCEPT_POPF, - INTERCEPT_CPUID, - INTERCEPT_RSM, - INTERCEPT_IRET, - INTERCEPT_INTn, - INTERCEPT_INVD, - INTERCEPT_PAUSE, - INTERCEPT_HLT, - INTERCEPT_INVLPG, - INTERCEPT_INVLPGA, - INTERCEPT_IOIO_PROT, - INTERCEPT_MSR_PROT, - INTERCEPT_TASK_SWITCH, - INTERCEPT_FERR_FREEZE, - INTERCEPT_SHUTDOWN, - INTERCEPT_VMRUN, - INTERCEPT_VMMCALL, - INTERCEPT_VMLOAD, - INTERCEPT_VMSAVE, - INTERCEPT_STGI, - INTERCEPT_CLGI, - INTERCEPT_SKINIT, - INTERCEPT_RDTSCP, - INTERCEPT_ICEBP, - INTERCEPT_WBINVD, - INTERCEPT_MONITOR, - INTERCEPT_MWAIT, - INTERCEPT_MWAIT_COND, -}; - - -struct __attribute__ ((__packed__)) vmcb_control_area { - u16 intercept_cr_read; - u16 intercept_cr_write; - u16 intercept_dr_read; - u16 intercept_dr_write; - u32 intercept_exceptions; - u64 intercept; - u8 reserved_1[42]; - u16 pause_filter_count; - u64 iopm_base_pa; - u64 msrpm_base_pa; - u64 tsc_offset; - u32 asid; - u8 tlb_ctl; - u8 reserved_2[3]; - u32 int_ctl; - u32 int_vector; - u32 int_state; - u8 reserved_3[4]; - u32 exit_code; - u32 exit_code_hi; - u64 exit_info_1; - u64 exit_info_2; - u32 exit_int_info; - u32 exit_int_info_err; - u64 nested_ctl; - u8 reserved_4[16]; - u32 event_inj; - u32 event_inj_err; - u64 nested_cr3; - u64 lbr_ctl; - u64 reserved_5; - u64 next_rip; - u8 reserved_6[816]; -}; - - -#define TLB_CONTROL_DO_NOTHING 0 -#define TLB_CONTROL_FLUSH_ALL_ASID 1 - -#define V_TPR_MASK 0x0f - -#define V_IRQ_SHIFT 8 -#define V_IRQ_MASK (1 << V_IRQ_SHIFT) - -#define V_INTR_PRIO_SHIFT 16 -#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT) - -#define V_IGN_TPR_SHIFT 20 -#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT) - -#define V_INTR_MASKING_SHIFT 24 -#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT) - -#define SVM_INTERRUPT_SHADOW_MASK 1 - -#define SVM_IOIO_STR_SHIFT 2 -#define SVM_IOIO_REP_SHIFT 3 -#define SVM_IOIO_SIZE_SHIFT 4 -#define SVM_IOIO_ASIZE_SHIFT 7 - -#define SVM_IOIO_TYPE_MASK 1 -#define SVM_IOIO_STR_MASK (1 << SVM_IOIO_STR_SHIFT) -#define SVM_IOIO_REP_MASK (1 << SVM_IOIO_REP_SHIFT) -#define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT) -#define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT) - -#define SVM_VM_CR_VALID_MASK 0x001fULL -#define SVM_VM_CR_SVM_LOCK_MASK 0x0008ULL -#define SVM_VM_CR_SVM_DIS_MASK 0x0010ULL - -struct __attribute__ ((__packed__)) vmcb_seg { - u16 selector; - u16 attrib; - u32 limit; - u64 base; -}; - -struct __attribute__ ((__packed__)) vmcb_save_area { - struct vmcb_seg es; - struct vmcb_seg cs; - struct vmcb_seg ss; - struct vmcb_seg ds; - struct vmcb_seg fs; - struct vmcb_seg gs; - struct vmcb_seg gdtr; - struct vmcb_seg ldtr; - struct vmcb_seg idtr; - struct vmcb_seg tr; - u8 reserved_1[43]; - u8 cpl; - u8 reserved_2[4]; - u64 efer; - u8 reserved_3[112]; - u64 cr4; - u64 cr3; - u64 cr0; - u64 dr7; - u64 dr6; - u64 rflags; - u64 rip; - u8 reserved_4[88]; - u64 rsp; - u8 reserved_5[24]; - u64 rax; - u64 star; - u64 lstar; - u64 cstar; - u64 sfmask; - u64 kernel_gs_base; - u64 sysenter_cs; - u64 sysenter_esp; - u64 sysenter_eip; - u64 cr2; - u8 reserved_6[32]; - u64 g_pat; - u64 dbgctl; - u64 br_from; - u64 br_to; - u64 last_excp_from; - u64 last_excp_to; -}; - -struct __attribute__ ((__packed__)) vmcb { - struct vmcb_control_area control; - struct vmcb_save_area save; -}; - -#define SVM_CPUID_FEATURE_SHIFT 2 -#define SVM_CPUID_FUNC 0x8000000a - -#define SVM_VM_CR_SVM_DISABLE 4 - -#define SVM_SELECTOR_S_SHIFT 4 -#define SVM_SELECTOR_DPL_SHIFT 5 -#define SVM_SELECTOR_P_SHIFT 7 -#define SVM_SELECTOR_AVL_SHIFT 8 -#define SVM_SELECTOR_L_SHIFT 9 -#define SVM_SELECTOR_DB_SHIFT 10 -#define SVM_SELECTOR_G_SHIFT 11 - -#define SVM_SELECTOR_TYPE_MASK (0xf) -#define SVM_SELECTOR_S_MASK (1 << SVM_SELECTOR_S_SHIFT) -#define SVM_SELECTOR_DPL_MASK (3 << SVM_SELECTOR_DPL_SHIFT) -#define SVM_SELECTOR_P_MASK (1 << SVM_SELECTOR_P_SHIFT) -#define SVM_SELECTOR_AVL_MASK (1 << SVM_SELECTOR_AVL_SHIFT) -#define SVM_SELECTOR_L_MASK (1 << SVM_SELECTOR_L_SHIFT) -#define SVM_SELECTOR_DB_MASK (1 << SVM_SELECTOR_DB_SHIFT) -#define SVM_SELECTOR_G_MASK (1 << SVM_SELECTOR_G_SHIFT) - -#define SVM_SELECTOR_WRITE_MASK (1 << 1) -#define SVM_SELECTOR_READ_MASK SVM_SELECTOR_WRITE_MASK -#define SVM_SELECTOR_CODE_MASK (1 << 3) - -#define INTERCEPT_CR0_MASK 1 -#define INTERCEPT_CR3_MASK (1 << 3) -#define INTERCEPT_CR4_MASK (1 << 4) -#define INTERCEPT_CR8_MASK (1 << 8) - -#define INTERCEPT_DR0_MASK 1 -#define INTERCEPT_DR1_MASK (1 << 1) -#define INTERCEPT_DR2_MASK (1 << 2) -#define INTERCEPT_DR3_MASK (1 << 3) -#define INTERCEPT_DR4_MASK (1 << 4) -#define INTERCEPT_DR5_MASK (1 << 5) -#define INTERCEPT_DR6_MASK (1 << 6) -#define INTERCEPT_DR7_MASK (1 << 7) - -#define SVM_EVTINJ_VEC_MASK 0xff - -#define SVM_EVTINJ_TYPE_SHIFT 8 -#define SVM_EVTINJ_TYPE_MASK (7 << SVM_EVTINJ_TYPE_SHIFT) - -#define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT) -#define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT) -#define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT) -#define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT) - -#define SVM_EVTINJ_VALID (1 << 31) -#define SVM_EVTINJ_VALID_ERR (1 << 11) - -#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK -#define SVM_EXITINTINFO_TYPE_MASK SVM_EVTINJ_TYPE_MASK - -#define SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR -#define SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI -#define SVM_EXITINTINFO_TYPE_EXEPT SVM_EVTINJ_TYPE_EXEPT -#define SVM_EXITINTINFO_TYPE_SOFT SVM_EVTINJ_TYPE_SOFT - -#define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID -#define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR - -#define SVM_EXITINFOSHIFT_TS_REASON_IRET 36 -#define SVM_EXITINFOSHIFT_TS_REASON_JMP 38 -#define SVM_EXITINFOSHIFT_TS_HAS_ERROR_CODE 44 - -#define SVM_EXIT_READ_CR0 0x000 -#define SVM_EXIT_READ_CR3 0x003 -#define SVM_EXIT_READ_CR4 0x004 -#define SVM_EXIT_READ_CR8 0x008 -#define SVM_EXIT_WRITE_CR0 0x010 -#define SVM_EXIT_WRITE_CR3 0x013 -#define SVM_EXIT_WRITE_CR4 0x014 -#define SVM_EXIT_WRITE_CR8 0x018 -#define SVM_EXIT_READ_DR0 0x020 -#define SVM_EXIT_READ_DR1 0x021 -#define SVM_EXIT_READ_DR2 0x022 -#define SVM_EXIT_READ_DR3 0x023 -#define SVM_EXIT_READ_DR4 0x024 -#define SVM_EXIT_READ_DR5 0x025 -#define SVM_EXIT_READ_DR6 0x026 -#define SVM_EXIT_READ_DR7 0x027 -#define SVM_EXIT_WRITE_DR0 0x030 -#define SVM_EXIT_WRITE_DR1 0x031 -#define SVM_EXIT_WRITE_DR2 0x032 -#define SVM_EXIT_WRITE_DR3 0x033 -#define SVM_EXIT_WRITE_DR4 0x034 -#define SVM_EXIT_WRITE_DR5 0x035 -#define SVM_EXIT_WRITE_DR6 0x036 -#define SVM_EXIT_WRITE_DR7 0x037 -#define SVM_EXIT_EXCP_BASE 0x040 -#define SVM_EXIT_INTR 0x060 -#define SVM_EXIT_NMI 0x061 -#define SVM_EXIT_SMI 0x062 -#define SVM_EXIT_INIT 0x063 -#define SVM_EXIT_VINTR 0x064 -#define SVM_EXIT_CR0_SEL_WRITE 0x065 -#define SVM_EXIT_IDTR_READ 0x066 -#define SVM_EXIT_GDTR_READ 0x067 -#define SVM_EXIT_LDTR_READ 0x068 -#define SVM_EXIT_TR_READ 0x069 -#define SVM_EXIT_IDTR_WRITE 0x06a -#define SVM_EXIT_GDTR_WRITE 0x06b -#define SVM_EXIT_LDTR_WRITE 0x06c -#define SVM_EXIT_TR_WRITE 0x06d -#define SVM_EXIT_RDTSC 0x06e -#define SVM_EXIT_RDPMC 0x06f -#define SVM_EXIT_PUSHF 0x070 -#define SVM_EXIT_POPF 0x071 -#define SVM_EXIT_CPUID 0x072 -#define SVM_EXIT_RSM 0x073 -#define SVM_EXIT_IRET 0x074 -#define SVM_EXIT_SWINT 0x075 -#define SVM_EXIT_INVD 0x076 -#define SVM_EXIT_PAUSE 0x077 -#define SVM_EXIT_HLT 0x078 -#define SVM_EXIT_INVLPG 0x079 -#define SVM_EXIT_INVLPGA 0x07a -#define SVM_EXIT_IOIO 0x07b -#define SVM_EXIT_MSR 0x07c -#define SVM_EXIT_TASK_SWITCH 0x07d -#define SVM_EXIT_FERR_FREEZE 0x07e -#define SVM_EXIT_SHUTDOWN 0x07f -#define SVM_EXIT_VMRUN 0x080 -#define SVM_EXIT_VMMCALL 0x081 -#define SVM_EXIT_VMLOAD 0x082 -#define SVM_EXIT_VMSAVE 0x083 -#define SVM_EXIT_STGI 0x084 -#define SVM_EXIT_CLGI 0x085 -#define SVM_EXIT_SKINIT 0x086 -#define SVM_EXIT_RDTSCP 0x087 -#define SVM_EXIT_ICEBP 0x088 -#define SVM_EXIT_WBINVD 0x089 -#define SVM_EXIT_MONITOR 0x08a -#define SVM_EXIT_MWAIT 0x08b -#define SVM_EXIT_MWAIT_COND 0x08c -#define SVM_EXIT_NPF 0x400 - -#define SVM_EXIT_ERR -1 - -#define SVM_CR0_SELECTIVE_MASK (X86_CR0_TS | X86_CR0_MP) - -#define SVM_CR0_RESERVED_MASK 0xffffffff00000000U -#define SVM_CR3_LEGACY_RESERVED_MASK 0xfe7U -#define SVM_CR3_LEGACY_PAE_RESERVED_MASK 0x7U -#define SVM_CR3_LONG_RESERVED_MASK 0xfff0000000000fe7U -#define SVM_CR4_LEGACY_RESERVED_MASK 0xff88f000U -#define SVM_CR4_RESERVED_MASK 0xffffffffff88f000U -#define SVM_DR6_RESERVED_MASK 0xffffffffffff1ff0U -#define SVM_DR7_RESERVED_MASK 0xffffffff0000cc00U -#define SVM_EFER_RESERVED_MASK 0xffffffffffff0200U - -#define MSR_BITMAP_SIZE 8192 - -struct svm_test { - const char *name; - bool (*supported)(void); - void (*prepare)(struct svm_test *test); - void (*prepare_gif_clear)(struct svm_test *test); - void (*guest_func)(struct svm_test *test); - bool (*finished)(struct svm_test *test); - bool (*succeeded)(struct svm_test *test); - int exits; - ulong scratch; - /* Alternative test interface. */ - void (*v2)(void); -}; - -struct regs { - u64 rax; - u64 rbx; - u64 rcx; - u64 rdx; - u64 cr2; - u64 rbp; - u64 rsi; - u64 rdi; - u64 r8; - u64 r9; - u64 r10; - u64 r11; - u64 r12; - u64 r13; - u64 r14; - u64 r15; - u64 rflags; -}; - -typedef void (*test_guest_func)(struct svm_test *); - -u64 *npt_get_pte(u64 address); -u64 *npt_get_pde(u64 address); -u64 *npt_get_pdpe(void); -u64 *npt_get_pml4e(void); -bool smp_supported(void); -bool default_supported(void); -void default_prepare(struct svm_test *test); -void default_prepare_gif_clear(struct svm_test *test); -bool default_finished(struct svm_test *test); -bool npt_supported(void); -int get_test_stage(struct svm_test *test); -void set_test_stage(struct svm_test *test, int s); -void inc_test_stage(struct svm_test *test); -void vmcb_ident(struct vmcb *vmcb); -struct regs get_regs(void); -void vmmcall(void); -int svm_vmrun(void); -void test_set_guest(test_guest_func func); - -extern struct vmcb *vmcb; -extern struct svm_test svm_tests[]; - -#endif diff --git a/x86/svm_tests.c b/x86/svm_tests.c deleted file mode 100644 index 3b0d019e..00000000 --- a/x86/svm_tests.c +++ /dev/null @@ -1,2203 +0,0 @@ -#include "svm.h" -#include "libcflat.h" -#include "processor.h" -#include "desc.h" -#include "msr.h" -#include "vm.h" -#include "smp.h" -#include "types.h" -#include "alloc_page.h" -#include "isr.h" -#include "apic.h" -#include "delay.h" - -#define SVM_EXIT_MAX_DR_INTERCEPT 0x3f - -static void *scratch_page; - -#define LATENCY_RUNS 1000000 - -u64 tsc_start; -u64 tsc_end; - -u64 vmrun_sum, vmexit_sum; -u64 vmsave_sum, vmload_sum; -u64 stgi_sum, clgi_sum; -u64 latvmrun_max; -u64 latvmrun_min; -u64 latvmexit_max; -u64 latvmexit_min; -u64 latvmload_max; -u64 latvmload_min; -u64 latvmsave_max; -u64 latvmsave_min; -u64 latstgi_max; -u64 latstgi_min; -u64 latclgi_max; -u64 latclgi_min; -u64 runs; - -static void null_test(struct svm_test *test) -{ -} - -static bool null_check(struct svm_test *test) -{ - return vmcb->control.exit_code == SVM_EXIT_VMMCALL; -} - -static void prepare_no_vmrun_int(struct svm_test *test) -{ - vmcb->control.intercept &= ~(1ULL << INTERCEPT_VMRUN); -} - -static bool check_no_vmrun_int(struct svm_test *test) -{ - return vmcb->control.exit_code == SVM_EXIT_ERR; -} - -static void test_vmrun(struct svm_test *test) -{ - asm volatile ("vmrun %0" : : "a"(virt_to_phys(vmcb))); -} - -static bool check_vmrun(struct svm_test *test) -{ - return vmcb->control.exit_code == SVM_EXIT_VMRUN; -} - -static void prepare_rsm_intercept(struct svm_test *test) -{ - default_prepare(test); - vmcb->control.intercept |= 1 << INTERCEPT_RSM; - vmcb->control.intercept_exceptions |= (1ULL << UD_VECTOR); -} - -static void test_rsm_intercept(struct svm_test *test) -{ - asm volatile ("rsm" : : : "memory"); -} - -static bool check_rsm_intercept(struct svm_test *test) -{ - return get_test_stage(test) == 2; -} - -static bool finished_rsm_intercept(struct svm_test *test) -{ - switch (get_test_stage(test)) { - case 0: - if (vmcb->control.exit_code != SVM_EXIT_RSM) { - report(false, "VMEXIT not due to rsm. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - vmcb->control.intercept &= ~(1 << INTERCEPT_RSM); - inc_test_stage(test); - break; - - case 1: - if (vmcb->control.exit_code != SVM_EXIT_EXCP_BASE + UD_VECTOR) { - report(false, "VMEXIT not due to #UD. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - vmcb->save.rip += 2; - inc_test_stage(test); - break; - - default: - return true; - } - return get_test_stage(test) == 2; -} - -static void prepare_cr3_intercept(struct svm_test *test) -{ - default_prepare(test); - vmcb->control.intercept_cr_read |= 1 << 3; -} - -static void test_cr3_intercept(struct svm_test *test) -{ - asm volatile ("mov %%cr3, %0" : "=r"(test->scratch) : : "memory"); -} - -static bool check_cr3_intercept(struct svm_test *test) -{ - return vmcb->control.exit_code == SVM_EXIT_READ_CR3; -} - -static bool check_cr3_nointercept(struct svm_test *test) -{ - return null_check(test) && test->scratch == read_cr3(); -} - -static void corrupt_cr3_intercept_bypass(void *_test) -{ - struct svm_test *test = _test; - extern volatile u32 mmio_insn; - - while (!__sync_bool_compare_and_swap(&test->scratch, 1, 2)) - pause(); - pause(); - pause(); - pause(); - mmio_insn = 0x90d8200f; // mov %cr3, %rax; nop -} - -static void prepare_cr3_intercept_bypass(struct svm_test *test) -{ - default_prepare(test); - vmcb->control.intercept_cr_read |= 1 << 3; - on_cpu_async(1, corrupt_cr3_intercept_bypass, test); -} - -static void test_cr3_intercept_bypass(struct svm_test *test) -{ - ulong a = 0xa0000; - - test->scratch = 1; - while (test->scratch != 2) - barrier(); - - asm volatile ("mmio_insn: mov %0, (%0); nop" - : "+a"(a) : : "memory"); - test->scratch = a; -} - -static void prepare_dr_intercept(struct svm_test *test) -{ - default_prepare(test); - vmcb->control.intercept_dr_read = 0xff; - vmcb->control.intercept_dr_write = 0xff; -} - -static void test_dr_intercept(struct svm_test *test) -{ - unsigned int i, failcnt = 0; - - /* Loop testing debug register reads */ - for (i = 0; i < 8; i++) { - - switch (i) { - case 0: - asm volatile ("mov %%dr0, %0" : "=r"(test->scratch) : : "memory"); - break; - case 1: - asm volatile ("mov %%dr1, %0" : "=r"(test->scratch) : : "memory"); - break; - case 2: - asm volatile ("mov %%dr2, %0" : "=r"(test->scratch) : : "memory"); - break; - case 3: - asm volatile ("mov %%dr3, %0" : "=r"(test->scratch) : : "memory"); - break; - case 4: - asm volatile ("mov %%dr4, %0" : "=r"(test->scratch) : : "memory"); - break; - case 5: - asm volatile ("mov %%dr5, %0" : "=r"(test->scratch) : : "memory"); - break; - case 6: - asm volatile ("mov %%dr6, %0" : "=r"(test->scratch) : : "memory"); - break; - case 7: - asm volatile ("mov %%dr7, %0" : "=r"(test->scratch) : : "memory"); - break; - } - - if (test->scratch != i) { - report(false, "dr%u read intercept", i); - failcnt++; - } - } - - /* Loop testing debug register writes */ - for (i = 0; i < 8; i++) { - - switch (i) { - case 0: - asm volatile ("mov %0, %%dr0" : : "r"(test->scratch) : "memory"); - break; - case 1: - asm volatile ("mov %0, %%dr1" : : "r"(test->scratch) : "memory"); - break; - case 2: - asm volatile ("mov %0, %%dr2" : : "r"(test->scratch) : "memory"); - break; - case 3: - asm volatile ("mov %0, %%dr3" : : "r"(test->scratch) : "memory"); - break; - case 4: - asm volatile ("mov %0, %%dr4" : : "r"(test->scratch) : "memory"); - break; - case 5: - asm volatile ("mov %0, %%dr5" : : "r"(test->scratch) : "memory"); - break; - case 6: - asm volatile ("mov %0, %%dr6" : : "r"(test->scratch) : "memory"); - break; - case 7: - asm volatile ("mov %0, %%dr7" : : "r"(test->scratch) : "memory"); - break; - } - - if (test->scratch != i) { - report(false, "dr%u write intercept", i); - failcnt++; - } - } - - test->scratch = failcnt; -} - -static bool dr_intercept_finished(struct svm_test *test) -{ - ulong n = (vmcb->control.exit_code - SVM_EXIT_READ_DR0); - - /* Only expect DR intercepts */ - if (n > (SVM_EXIT_MAX_DR_INTERCEPT - SVM_EXIT_READ_DR0)) - return true; - - /* - * Compute debug register number. - * Per Appendix C "SVM Intercept Exit Codes" of AMD64 Architecture - * Programmer's Manual Volume 2 - System Programming: - * http://support.amd.com/TechDocs/24593.pdf - * there are 16 VMEXIT codes each for DR read and write. - */ - test->scratch = (n % 16); - - /* Jump over MOV instruction */ - vmcb->save.rip += 3; - - return false; -} - -static bool check_dr_intercept(struct svm_test *test) -{ - return !test->scratch; -} - -static bool next_rip_supported(void) -{ - return this_cpu_has(X86_FEATURE_NRIPS); -} - -static void prepare_next_rip(struct svm_test *test) -{ - vmcb->control.intercept |= (1ULL << INTERCEPT_RDTSC); -} - - -static void test_next_rip(struct svm_test *test) -{ - asm volatile ("rdtsc\n\t" - ".globl exp_next_rip\n\t" - "exp_next_rip:\n\t" ::: "eax", "edx"); -} - -static bool check_next_rip(struct svm_test *test) -{ - extern char exp_next_rip; - unsigned long address = (unsigned long)&exp_next_rip; - - return address == vmcb->control.next_rip; -} - -extern u8 *msr_bitmap; - -static void prepare_msr_intercept(struct svm_test *test) -{ - default_prepare(test); - vmcb->control.intercept |= (1ULL << INTERCEPT_MSR_PROT); - vmcb->control.intercept_exceptions |= (1ULL << GP_VECTOR); - memset(msr_bitmap, 0xff, MSR_BITMAP_SIZE); -} - -static void test_msr_intercept(struct svm_test *test) -{ - unsigned long msr_value = 0xef8056791234abcd; /* Arbitrary value */ - unsigned long msr_index; - - for (msr_index = 0; msr_index <= 0xc0011fff; msr_index++) { - if (msr_index == 0xC0010131 /* MSR_SEV_STATUS */) { - /* - * Per section 15.34.10 "SEV_STATUS MSR" of AMD64 Architecture - * Programmer's Manual volume 2 - System Programming: - * http://support.amd.com/TechDocs/24593.pdf - * SEV_STATUS MSR (C001_0131) is a non-interceptable MSR. - */ - continue; - } - - /* Skips gaps between supported MSR ranges */ - if (msr_index == 0x2000) - msr_index = 0xc0000000; - else if (msr_index == 0xc0002000) - msr_index = 0xc0010000; - - test->scratch = -1; - - rdmsr(msr_index); - - /* Check that a read intercept occurred for MSR at msr_index */ - if (test->scratch != msr_index) - report(false, "MSR 0x%lx read intercept", msr_index); - - /* - * Poor man approach to generate a value that - * seems arbitrary each time around the loop. - */ - msr_value += (msr_value << 1); - - wrmsr(msr_index, msr_value); - - /* Check that a write intercept occurred for MSR with msr_value */ - if (test->scratch != msr_value) - report(false, "MSR 0x%lx write intercept", msr_index); - } - - test->scratch = -2; -} - -static bool msr_intercept_finished(struct svm_test *test) -{ - u32 exit_code = vmcb->control.exit_code; - u64 exit_info_1; - u8 *opcode; - - if (exit_code == SVM_EXIT_MSR) { - exit_info_1 = vmcb->control.exit_info_1; - } else { - /* - * If #GP exception occurs instead, check that it was - * for RDMSR/WRMSR and set exit_info_1 accordingly. - */ - - if (exit_code != (SVM_EXIT_EXCP_BASE + GP_VECTOR)) - return true; - - opcode = (u8 *)vmcb->save.rip; - if (opcode[0] != 0x0f) - return true; - - switch (opcode[1]) { - case 0x30: /* WRMSR */ - exit_info_1 = 1; - break; - case 0x32: /* RDMSR */ - exit_info_1 = 0; - break; - default: - return true; - } - - /* - * Warn that #GP exception occured instead. - * RCX holds the MSR index. - */ - printf("%s 0x%lx #GP exception\n", - exit_info_1 ? "WRMSR" : "RDMSR", get_regs().rcx); - } - - /* Jump over RDMSR/WRMSR instruction */ - vmcb->save.rip += 2; - - /* - * Test whether the intercept was for RDMSR/WRMSR. - * For RDMSR, test->scratch is set to the MSR index; - * RCX holds the MSR index. - * For WRMSR, test->scratch is set to the MSR value; - * RDX holds the upper 32 bits of the MSR value, - * while RAX hold its lower 32 bits. - */ - if (exit_info_1) - test->scratch = - ((get_regs().rdx << 32) | (vmcb->save.rax & 0xffffffff)); - else - test->scratch = get_regs().rcx; - - return false; -} - -static bool check_msr_intercept(struct svm_test *test) -{ - memset(msr_bitmap, 0, MSR_BITMAP_SIZE); - return (test->scratch == -2); -} - -static void prepare_mode_switch(struct svm_test *test) -{ - vmcb->control.intercept_exceptions |= (1ULL << GP_VECTOR) - | (1ULL << UD_VECTOR) - | (1ULL << DF_VECTOR) - | (1ULL << PF_VECTOR); - test->scratch = 0; -} - -static void test_mode_switch(struct svm_test *test) -{ - asm volatile(" cli\n" - " ljmp *1f\n" /* jump to 32-bit code segment */ - "1:\n" - " .long 2f\n" - " .long " xstr(KERNEL_CS32) "\n" - ".code32\n" - "2:\n" - " movl %%cr0, %%eax\n" - " btcl $31, %%eax\n" /* clear PG */ - " movl %%eax, %%cr0\n" - " movl $0xc0000080, %%ecx\n" /* EFER */ - " rdmsr\n" - " btcl $8, %%eax\n" /* clear LME */ - " wrmsr\n" - " movl %%cr4, %%eax\n" - " btcl $5, %%eax\n" /* clear PAE */ - " movl %%eax, %%cr4\n" - " movw %[ds16], %%ax\n" - " movw %%ax, %%ds\n" - " ljmpl %[cs16], $3f\n" /* jump to 16 bit protected-mode */ - ".code16\n" - "3:\n" - " movl %%cr0, %%eax\n" - " btcl $0, %%eax\n" /* clear PE */ - " movl %%eax, %%cr0\n" - " ljmpl $0, $4f\n" /* jump to real-mode */ - "4:\n" - " vmmcall\n" - " movl %%cr0, %%eax\n" - " btsl $0, %%eax\n" /* set PE */ - " movl %%eax, %%cr0\n" - " ljmpl %[cs32], $5f\n" /* back to protected mode */ - ".code32\n" - "5:\n" - " movl %%cr4, %%eax\n" - " btsl $5, %%eax\n" /* set PAE */ - " movl %%eax, %%cr4\n" - " movl $0xc0000080, %%ecx\n" /* EFER */ - " rdmsr\n" - " btsl $8, %%eax\n" /* set LME */ - " wrmsr\n" - " movl %%cr0, %%eax\n" - " btsl $31, %%eax\n" /* set PG */ - " movl %%eax, %%cr0\n" - " ljmpl %[cs64], $6f\n" /* back to long mode */ - ".code64\n\t" - "6:\n" - " vmmcall\n" - :: [cs16] "i"(KERNEL_CS16), [ds16] "i"(KERNEL_DS16), - [cs32] "i"(KERNEL_CS32), [cs64] "i"(KERNEL_CS64) - : "rax", "rbx", "rcx", "rdx", "memory"); -} - -static bool mode_switch_finished(struct svm_test *test) -{ - u64 cr0, cr4, efer; - - cr0 = vmcb->save.cr0; - cr4 = vmcb->save.cr4; - efer = vmcb->save.efer; - - /* Only expect VMMCALL intercepts */ - if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) - return true; - - /* Jump over VMMCALL instruction */ - vmcb->save.rip += 3; - - /* Do sanity checks */ - switch (test->scratch) { - case 0: - /* Test should be in real mode now - check for this */ - if ((cr0 & 0x80000001) || /* CR0.PG, CR0.PE */ - (cr4 & 0x00000020) || /* CR4.PAE */ - (efer & 0x00000500)) /* EFER.LMA, EFER.LME */ - return true; - break; - case 2: - /* Test should be back in long-mode now - check for this */ - if (((cr0 & 0x80000001) != 0x80000001) || /* CR0.PG, CR0.PE */ - ((cr4 & 0x00000020) != 0x00000020) || /* CR4.PAE */ - ((efer & 0x00000500) != 0x00000500)) /* EFER.LMA, EFER.LME */ - return true; - break; - } - - /* one step forward */ - test->scratch += 1; - - return test->scratch == 2; -} - -static bool check_mode_switch(struct svm_test *test) -{ - return test->scratch == 2; -} - -extern u8 *io_bitmap; - -static void prepare_ioio(struct svm_test *test) -{ - vmcb->control.intercept |= (1ULL << INTERCEPT_IOIO_PROT); - test->scratch = 0; - memset(io_bitmap, 0, 8192); - io_bitmap[8192] = 0xFF; -} - -static void test_ioio(struct svm_test *test) -{ - // stage 0, test IO pass - inb(0x5000); - outb(0x0, 0x5000); - if (get_test_stage(test) != 0) - goto fail; - - // test IO width, in/out - io_bitmap[0] = 0xFF; - inc_test_stage(test); - inb(0x0); - if (get_test_stage(test) != 2) - goto fail; - - outw(0x0, 0x0); - if (get_test_stage(test) != 3) - goto fail; - - inl(0x0); - if (get_test_stage(test) != 4) - goto fail; - - // test low/high IO port - io_bitmap[0x5000 / 8] = (1 << (0x5000 % 8)); - inb(0x5000); - if (get_test_stage(test) != 5) - goto fail; - - io_bitmap[0x9000 / 8] = (1 << (0x9000 % 8)); - inw(0x9000); - if (get_test_stage(test) != 6) - goto fail; - - // test partial pass - io_bitmap[0x5000 / 8] = (1 << (0x5000 % 8)); - inl(0x4FFF); - if (get_test_stage(test) != 7) - goto fail; - - // test across pages - inc_test_stage(test); - inl(0x7FFF); - if (get_test_stage(test) != 8) - goto fail; - - inc_test_stage(test); - io_bitmap[0x8000 / 8] = 1 << (0x8000 % 8); - inl(0x7FFF); - if (get_test_stage(test) != 10) - goto fail; - - io_bitmap[0] = 0; - inl(0xFFFF); - if (get_test_stage(test) != 11) - goto fail; - - io_bitmap[0] = 0xFF; - io_bitmap[8192] = 0; - inl(0xFFFF); - inc_test_stage(test); - if (get_test_stage(test) != 12) - goto fail; - - return; - -fail: - report(false, "stage %d", get_test_stage(test)); - test->scratch = -1; -} - -static bool ioio_finished(struct svm_test *test) -{ - unsigned port, size; - - /* Only expect IOIO intercepts */ - if (vmcb->control.exit_code == SVM_EXIT_VMMCALL) - return true; - - if (vmcb->control.exit_code != SVM_EXIT_IOIO) - return true; - - /* one step forward */ - test->scratch += 1; - - port = vmcb->control.exit_info_1 >> 16; - size = (vmcb->control.exit_info_1 >> SVM_IOIO_SIZE_SHIFT) & 7; - - while (size--) { - io_bitmap[port / 8] &= ~(1 << (port & 7)); - port++; - } - - return false; -} - -static bool check_ioio(struct svm_test *test) -{ - memset(io_bitmap, 0, 8193); - return test->scratch != -1; -} - -static void prepare_asid_zero(struct svm_test *test) -{ - vmcb->control.asid = 0; -} - -static void test_asid_zero(struct svm_test *test) -{ - asm volatile ("vmmcall\n\t"); -} - -static bool check_asid_zero(struct svm_test *test) -{ - return vmcb->control.exit_code == SVM_EXIT_ERR; -} - -static void sel_cr0_bug_prepare(struct svm_test *test) -{ - vmcb_ident(vmcb); - vmcb->control.intercept |= (1ULL << INTERCEPT_SELECTIVE_CR0); -} - -static bool sel_cr0_bug_finished(struct svm_test *test) -{ - return true; -} - -static void sel_cr0_bug_test(struct svm_test *test) -{ - unsigned long cr0; - - /* read cr0, clear CD, and write back */ - cr0 = read_cr0(); - cr0 |= (1UL << 30); - write_cr0(cr0); - - /* - * If we are here the test failed, not sure what to do now because we - * are not in guest-mode anymore so we can't trigger an intercept. - * Trigger a tripple-fault for now. - */ - report(false, "sel_cr0 test. Can not recover from this - exiting"); - exit(report_summary()); -} - -static bool sel_cr0_bug_check(struct svm_test *test) -{ - return vmcb->control.exit_code == SVM_EXIT_CR0_SEL_WRITE; -} - -static void npt_nx_prepare(struct svm_test *test) -{ - - u64 *pte; - - vmcb_ident(vmcb); - pte = npt_get_pte((u64)null_test); - - *pte |= (1ULL << 63); -} - -static bool npt_nx_check(struct svm_test *test) -{ - u64 *pte = npt_get_pte((u64)null_test); - - *pte &= ~(1ULL << 63); - - vmcb->save.efer |= (1 << 11); - - return (vmcb->control.exit_code == SVM_EXIT_NPF) - && (vmcb->control.exit_info_1 == 0x100000015ULL); -} - -static void npt_us_prepare(struct svm_test *test) -{ - u64 *pte; - - scratch_page = alloc_page(); - vmcb_ident(vmcb); - pte = npt_get_pte((u64)scratch_page); - - *pte &= ~(1ULL << 2); -} - -static void npt_us_test(struct svm_test *test) -{ - (void) *(volatile u64 *)scratch_page; -} - -static bool npt_us_check(struct svm_test *test) -{ - u64 *pte = npt_get_pte((u64)scratch_page); - - *pte |= (1ULL << 2); - - return (vmcb->control.exit_code == SVM_EXIT_NPF) - && (vmcb->control.exit_info_1 == 0x100000005ULL); -} - -u64 save_pde; - -static void npt_rsvd_prepare(struct svm_test *test) -{ - u64 *pde; - - vmcb_ident(vmcb); - pde = npt_get_pde((u64) null_test); - - save_pde = *pde; - *pde = (1ULL << 19) | (1ULL << 7) | 0x27; -} - -static bool npt_rsvd_check(struct svm_test *test) -{ - u64 *pde = npt_get_pde((u64) null_test); - - *pde = save_pde; - - return (vmcb->control.exit_code == SVM_EXIT_NPF) - && (vmcb->control.exit_info_1 == 0x10000001dULL); -} - -static void npt_rw_prepare(struct svm_test *test) -{ - - u64 *pte; - - vmcb_ident(vmcb); - pte = npt_get_pte(0x80000); - - *pte &= ~(1ULL << 1); -} - -static void npt_rw_test(struct svm_test *test) -{ - u64 *data = (void*)(0x80000); - - *data = 0; -} - -static bool npt_rw_check(struct svm_test *test) -{ - u64 *pte = npt_get_pte(0x80000); - - *pte |= (1ULL << 1); - - return (vmcb->control.exit_code == SVM_EXIT_NPF) - && (vmcb->control.exit_info_1 == 0x100000007ULL); -} - -static void npt_rw_pfwalk_prepare(struct svm_test *test) -{ - - u64 *pte; - - vmcb_ident(vmcb); - pte = npt_get_pte(read_cr3()); - - *pte &= ~(1ULL << 1); -} - -static bool npt_rw_pfwalk_check(struct svm_test *test) -{ - u64 *pte = npt_get_pte(read_cr3()); - - *pte |= (1ULL << 1); - - return (vmcb->control.exit_code == SVM_EXIT_NPF) - && (vmcb->control.exit_info_1 == 0x200000007ULL) - && (vmcb->control.exit_info_2 == read_cr3()); -} - -static void npt_rsvd_pfwalk_prepare(struct svm_test *test) -{ - u64 *pdpe; - vmcb_ident(vmcb); - - pdpe = npt_get_pml4e(); - pdpe[0] |= (1ULL << 8); -} - -static bool npt_rsvd_pfwalk_check(struct svm_test *test) -{ - u64 *pdpe = npt_get_pml4e(); - pdpe[0] &= ~(1ULL << 8); - - return (vmcb->control.exit_code == SVM_EXIT_NPF) - && (vmcb->control.exit_info_1 == 0x20000000fULL); -} - -static void npt_l1mmio_prepare(struct svm_test *test) -{ - vmcb_ident(vmcb); -} - -u32 nested_apic_version1; -u32 nested_apic_version2; - -static void npt_l1mmio_test(struct svm_test *test) -{ - volatile u32 *data = (volatile void*)(0xfee00030UL); - - nested_apic_version1 = *data; - nested_apic_version2 = *data; -} - -static bool npt_l1mmio_check(struct svm_test *test) -{ - volatile u32 *data = (volatile void*)(0xfee00030); - u32 lvr = *data; - - return nested_apic_version1 == lvr && nested_apic_version2 == lvr; -} - -static void npt_rw_l1mmio_prepare(struct svm_test *test) -{ - - u64 *pte; - - vmcb_ident(vmcb); - pte = npt_get_pte(0xfee00080); - - *pte &= ~(1ULL << 1); -} - -static void npt_rw_l1mmio_test(struct svm_test *test) -{ - volatile u32 *data = (volatile void*)(0xfee00080); - - *data = *data; -} - -static bool npt_rw_l1mmio_check(struct svm_test *test) -{ - u64 *pte = npt_get_pte(0xfee00080); - - *pte |= (1ULL << 1); - - return (vmcb->control.exit_code == SVM_EXIT_NPF) - && (vmcb->control.exit_info_1 == 0x100000007ULL); -} - -#define TSC_ADJUST_VALUE (1ll << 32) -#define TSC_OFFSET_VALUE (~0ull << 48) -static bool ok; - -static bool tsc_adjust_supported(void) -{ - return this_cpu_has(X86_FEATURE_TSC_ADJUST); -} - -static void tsc_adjust_prepare(struct svm_test *test) -{ - default_prepare(test); - vmcb->control.tsc_offset = TSC_OFFSET_VALUE; - - wrmsr(MSR_IA32_TSC_ADJUST, -TSC_ADJUST_VALUE); - int64_t adjust = rdmsr(MSR_IA32_TSC_ADJUST); - ok = adjust == -TSC_ADJUST_VALUE; -} - -static void tsc_adjust_test(struct svm_test *test) -{ - int64_t adjust = rdmsr(MSR_IA32_TSC_ADJUST); - ok &= adjust == -TSC_ADJUST_VALUE; - - uint64_t l1_tsc = rdtsc() - TSC_OFFSET_VALUE; - wrmsr(MSR_IA32_TSC, l1_tsc - TSC_ADJUST_VALUE); - - adjust = rdmsr(MSR_IA32_TSC_ADJUST); - ok &= adjust <= -2 * TSC_ADJUST_VALUE; - - uint64_t l1_tsc_end = rdtsc() - TSC_OFFSET_VALUE; - ok &= (l1_tsc_end + TSC_ADJUST_VALUE - l1_tsc) < TSC_ADJUST_VALUE; - - uint64_t l1_tsc_msr = rdmsr(MSR_IA32_TSC) - TSC_OFFSET_VALUE; - ok &= (l1_tsc_msr + TSC_ADJUST_VALUE - l1_tsc) < TSC_ADJUST_VALUE; -} - -static bool tsc_adjust_check(struct svm_test *test) -{ - int64_t adjust = rdmsr(MSR_IA32_TSC_ADJUST); - - wrmsr(MSR_IA32_TSC_ADJUST, 0); - return ok && adjust <= -2 * TSC_ADJUST_VALUE; -} - -static void latency_prepare(struct svm_test *test) -{ - default_prepare(test); - runs = LATENCY_RUNS; - latvmrun_min = latvmexit_min = -1ULL; - latvmrun_max = latvmexit_max = 0; - vmrun_sum = vmexit_sum = 0; - tsc_start = rdtsc(); -} - -static void latency_test(struct svm_test *test) -{ - u64 cycles; - -start: - tsc_end = rdtsc(); - - cycles = tsc_end - tsc_start; - - if (cycles > latvmrun_max) - latvmrun_max = cycles; - - if (cycles < latvmrun_min) - latvmrun_min = cycles; - - vmrun_sum += cycles; - - tsc_start = rdtsc(); - - asm volatile ("vmmcall" : : : "memory"); - goto start; -} - -static bool latency_finished(struct svm_test *test) -{ - u64 cycles; - - tsc_end = rdtsc(); - - cycles = tsc_end - tsc_start; - - if (cycles > latvmexit_max) - latvmexit_max = cycles; - - if (cycles < latvmexit_min) - latvmexit_min = cycles; - - vmexit_sum += cycles; - - vmcb->save.rip += 3; - - runs -= 1; - - tsc_end = rdtsc(); - - return runs == 0; -} - -static bool latency_check(struct svm_test *test) -{ - printf(" Latency VMRUN : max: %ld min: %ld avg: %ld\n", latvmrun_max, - latvmrun_min, vmrun_sum / LATENCY_RUNS); - printf(" Latency VMEXIT: max: %ld min: %ld avg: %ld\n", latvmexit_max, - latvmexit_min, vmexit_sum / LATENCY_RUNS); - return true; -} - -static void lat_svm_insn_prepare(struct svm_test *test) -{ - default_prepare(test); - runs = LATENCY_RUNS; - latvmload_min = latvmsave_min = latstgi_min = latclgi_min = -1ULL; - latvmload_max = latvmsave_max = latstgi_max = latclgi_max = 0; - vmload_sum = vmsave_sum = stgi_sum = clgi_sum; -} - -static bool lat_svm_insn_finished(struct svm_test *test) -{ - u64 vmcb_phys = virt_to_phys(vmcb); - u64 cycles; - - for ( ; runs != 0; runs--) { - tsc_start = rdtsc(); - asm volatile("vmload %0\n\t" : : "a"(vmcb_phys) : "memory"); - cycles = rdtsc() - tsc_start; - if (cycles > latvmload_max) - latvmload_max = cycles; - if (cycles < latvmload_min) - latvmload_min = cycles; - vmload_sum += cycles; - - tsc_start = rdtsc(); - asm volatile("vmsave %0\n\t" : : "a"(vmcb_phys) : "memory"); - cycles = rdtsc() - tsc_start; - if (cycles > latvmsave_max) - latvmsave_max = cycles; - if (cycles < latvmsave_min) - latvmsave_min = cycles; - vmsave_sum += cycles; - - tsc_start = rdtsc(); - asm volatile("stgi\n\t"); - cycles = rdtsc() - tsc_start; - if (cycles > latstgi_max) - latstgi_max = cycles; - if (cycles < latstgi_min) - latstgi_min = cycles; - stgi_sum += cycles; - - tsc_start = rdtsc(); - asm volatile("clgi\n\t"); - cycles = rdtsc() - tsc_start; - if (cycles > latclgi_max) - latclgi_max = cycles; - if (cycles < latclgi_min) - latclgi_min = cycles; - clgi_sum += cycles; - } - - tsc_end = rdtsc(); - - return true; -} - -static bool lat_svm_insn_check(struct svm_test *test) -{ - printf(" Latency VMLOAD: max: %ld min: %ld avg: %ld\n", latvmload_max, - latvmload_min, vmload_sum / LATENCY_RUNS); - printf(" Latency VMSAVE: max: %ld min: %ld avg: %ld\n", latvmsave_max, - latvmsave_min, vmsave_sum / LATENCY_RUNS); - printf(" Latency STGI: max: %ld min: %ld avg: %ld\n", latstgi_max, - latstgi_min, stgi_sum / LATENCY_RUNS); - printf(" Latency CLGI: max: %ld min: %ld avg: %ld\n", latclgi_max, - latclgi_min, clgi_sum / LATENCY_RUNS); - return true; -} - -bool pending_event_ipi_fired; -bool pending_event_guest_run; - -static void pending_event_ipi_isr(isr_regs_t *regs) -{ - pending_event_ipi_fired = true; - eoi(); -} - -static void pending_event_prepare(struct svm_test *test) -{ - int ipi_vector = 0xf1; - - default_prepare(test); - - pending_event_ipi_fired = false; - - handle_irq(ipi_vector, pending_event_ipi_isr); - - pending_event_guest_run = false; - - vmcb->control.intercept |= (1ULL << INTERCEPT_INTR); - vmcb->control.int_ctl |= V_INTR_MASKING_MASK; - - apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | - APIC_DM_FIXED | ipi_vector, 0); - - set_test_stage(test, 0); -} - -static void pending_event_test(struct svm_test *test) -{ - pending_event_guest_run = true; -} - -static bool pending_event_finished(struct svm_test *test) -{ - switch (get_test_stage(test)) { - case 0: - if (vmcb->control.exit_code != SVM_EXIT_INTR) { - report(false, "VMEXIT not due to pending interrupt. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - - vmcb->control.intercept &= ~(1ULL << INTERCEPT_INTR); - vmcb->control.int_ctl &= ~V_INTR_MASKING_MASK; - - if (pending_event_guest_run) { - report(false, "Guest ran before host received IPI\n"); - return true; - } - - irq_enable(); - asm volatile ("nop"); - irq_disable(); - - if (!pending_event_ipi_fired) { - report(false, "Pending interrupt not dispatched after IRQ enabled\n"); - return true; - } - break; - - case 1: - if (!pending_event_guest_run) { - report(false, "Guest did not resume when no interrupt\n"); - return true; - } - break; - } - - inc_test_stage(test); - - return get_test_stage(test) == 2; -} - -static bool pending_event_check(struct svm_test *test) -{ - return get_test_stage(test) == 2; -} - -static void pending_event_cli_prepare(struct svm_test *test) -{ - default_prepare(test); - - pending_event_ipi_fired = false; - - handle_irq(0xf1, pending_event_ipi_isr); - - apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | - APIC_DM_FIXED | 0xf1, 0); - - set_test_stage(test, 0); -} - -static void pending_event_cli_prepare_gif_clear(struct svm_test *test) -{ - asm("cli"); -} - -static void pending_event_cli_test(struct svm_test *test) -{ - if (pending_event_ipi_fired == true) { - set_test_stage(test, -1); - report(false, "Interrupt preceeded guest"); - vmmcall(); - } - - /* VINTR_MASKING is zero. This should cause the IPI to fire. */ - irq_enable(); - asm volatile ("nop"); - irq_disable(); - - if (pending_event_ipi_fired != true) { - set_test_stage(test, -1); - report(false, "Interrupt not triggered by guest"); - } - - vmmcall(); - - /* - * Now VINTR_MASKING=1, but no interrupt is pending so - * the VINTR interception should be clear in VMCB02. Check - * that L0 did not leave a stale VINTR in the VMCB. - */ - irq_enable(); - asm volatile ("nop"); - irq_disable(); -} - -static bool pending_event_cli_finished(struct svm_test *test) -{ - if ( vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report(false, "VM_EXIT return to host is not EXIT_VMMCALL exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - - switch (get_test_stage(test)) { - case 0: - vmcb->save.rip += 3; - - pending_event_ipi_fired = false; - - vmcb->control.int_ctl |= V_INTR_MASKING_MASK; - - /* Now entering again with VINTR_MASKING=1. */ - apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | - APIC_DM_FIXED | 0xf1, 0); - - break; - - case 1: - if (pending_event_ipi_fired == true) { - report(false, "Interrupt triggered by guest"); - return true; - } - - irq_enable(); - asm volatile ("nop"); - irq_disable(); - - if (pending_event_ipi_fired != true) { - report(false, "Interrupt not triggered by host"); - return true; - } - - break; - - default: - return true; - } - - inc_test_stage(test); - - return get_test_stage(test) == 2; -} - -static bool pending_event_cli_check(struct svm_test *test) -{ - return get_test_stage(test) == 2; -} - -#define TIMER_VECTOR 222 - -static volatile bool timer_fired; - -static void timer_isr(isr_regs_t *regs) -{ - timer_fired = true; - apic_write(APIC_EOI, 0); -} - -static void interrupt_prepare(struct svm_test *test) -{ - default_prepare(test); - handle_irq(TIMER_VECTOR, timer_isr); - timer_fired = false; - set_test_stage(test, 0); -} - -static void interrupt_test(struct svm_test *test) -{ - long long start, loops; - - apic_write(APIC_LVTT, TIMER_VECTOR); - irq_enable(); - apic_write(APIC_TMICT, 1); //Timer Initial Count Register 0x380 one-shot - for (loops = 0; loops < 10000000 && !timer_fired; loops++) - asm volatile ("nop"); - - report(timer_fired, "direct interrupt while running guest"); - - if (!timer_fired) { - set_test_stage(test, -1); - vmmcall(); - } - - apic_write(APIC_TMICT, 0); - irq_disable(); - vmmcall(); - - timer_fired = false; - apic_write(APIC_TMICT, 1); - for (loops = 0; loops < 10000000 && !timer_fired; loops++) - asm volatile ("nop"); - - report(timer_fired, "intercepted interrupt while running guest"); - - if (!timer_fired) { - set_test_stage(test, -1); - vmmcall(); - } - - irq_enable(); - apic_write(APIC_TMICT, 0); - irq_disable(); - - timer_fired = false; - start = rdtsc(); - apic_write(APIC_TMICT, 1000000); - asm volatile ("sti; hlt"); - - report(rdtsc() - start > 10000 && timer_fired, - "direct interrupt + hlt"); - - if (!timer_fired) { - set_test_stage(test, -1); - vmmcall(); - } - - apic_write(APIC_TMICT, 0); - irq_disable(); - vmmcall(); - - timer_fired = false; - start = rdtsc(); - apic_write(APIC_TMICT, 1000000); - asm volatile ("hlt"); - - report(rdtsc() - start > 10000 && timer_fired, - "intercepted interrupt + hlt"); - - if (!timer_fired) { - set_test_stage(test, -1); - vmmcall(); - } - - apic_write(APIC_TMICT, 0); - irq_disable(); -} - -static bool interrupt_finished(struct svm_test *test) -{ - switch (get_test_stage(test)) { - case 0: - case 2: - if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - vmcb->save.rip += 3; - - vmcb->control.intercept |= (1ULL << INTERCEPT_INTR); - vmcb->control.int_ctl |= V_INTR_MASKING_MASK; - break; - - case 1: - case 3: - if (vmcb->control.exit_code != SVM_EXIT_INTR) { - report(false, "VMEXIT not due to intr intercept. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - - irq_enable(); - asm volatile ("nop"); - irq_disable(); - - vmcb->control.intercept &= ~(1ULL << INTERCEPT_INTR); - vmcb->control.int_ctl &= ~V_INTR_MASKING_MASK; - break; - - case 4: - break; - - default: - return true; - } - - inc_test_stage(test); - - return get_test_stage(test) == 5; -} - -static bool interrupt_check(struct svm_test *test) -{ - return get_test_stage(test) == 5; -} - -static volatile bool nmi_fired; - -static void nmi_handler(isr_regs_t *regs) -{ - nmi_fired = true; - apic_write(APIC_EOI, 0); -} - -static void nmi_prepare(struct svm_test *test) -{ - default_prepare(test); - nmi_fired = false; - handle_irq(NMI_VECTOR, nmi_handler); - set_test_stage(test, 0); -} - -static void nmi_test(struct svm_test *test) -{ - apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); - - report(nmi_fired, "direct NMI while running guest"); - - if (!nmi_fired) - set_test_stage(test, -1); - - vmmcall(); - - nmi_fired = false; - - apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); - - if (!nmi_fired) { - report(nmi_fired, "intercepted pending NMI not dispatched"); - set_test_stage(test, -1); - } - -} - -static bool nmi_finished(struct svm_test *test) -{ - switch (get_test_stage(test)) { - case 0: - if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - vmcb->save.rip += 3; - - vmcb->control.intercept |= (1ULL << INTERCEPT_NMI); - break; - - case 1: - if (vmcb->control.exit_code != SVM_EXIT_NMI) { - report(false, "VMEXIT not due to NMI intercept. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - - report(true, "NMI intercept while running guest"); - break; - - case 2: - break; - - default: - return true; - } - - inc_test_stage(test); - - return get_test_stage(test) == 3; -} - -static bool nmi_check(struct svm_test *test) -{ - return get_test_stage(test) == 3; -} - -#define NMI_DELAY 100000000ULL - -static void nmi_message_thread(void *_test) -{ - struct svm_test *test = _test; - - while (get_test_stage(test) != 1) - pause(); - - delay(NMI_DELAY); - - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[0]); - - while (get_test_stage(test) != 2) - pause(); - - delay(NMI_DELAY); - - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[0]); -} - -static void nmi_hlt_test(struct svm_test *test) -{ - long long start; - - on_cpu_async(1, nmi_message_thread, test); - - start = rdtsc(); - - set_test_stage(test, 1); - - asm volatile ("hlt"); - - report((rdtsc() - start > NMI_DELAY) && nmi_fired, - "direct NMI + hlt"); - - if (!nmi_fired) - set_test_stage(test, -1); - - nmi_fired = false; - - vmmcall(); - - start = rdtsc(); - - set_test_stage(test, 2); - - asm volatile ("hlt"); - - report((rdtsc() - start > NMI_DELAY) && nmi_fired, - "intercepted NMI + hlt"); - - if (!nmi_fired) { - report(nmi_fired, "intercepted pending NMI not dispatched"); - set_test_stage(test, -1); - vmmcall(); - } - - set_test_stage(test, 3); -} - -static bool nmi_hlt_finished(struct svm_test *test) -{ - switch (get_test_stage(test)) { - case 1: - if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - vmcb->save.rip += 3; - - vmcb->control.intercept |= (1ULL << INTERCEPT_NMI); - break; - - case 2: - if (vmcb->control.exit_code != SVM_EXIT_NMI) { - report(false, "VMEXIT not due to NMI intercept. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - - report(true, "NMI intercept while running guest"); - break; - - case 3: - break; - - default: - return true; - } - - return get_test_stage(test) == 3; -} - -static bool nmi_hlt_check(struct svm_test *test) -{ - return get_test_stage(test) == 3; -} - -static volatile int count_exc = 0; - -static void my_isr(struct ex_regs *r) -{ - count_exc++; -} - -static void exc_inject_prepare(struct svm_test *test) -{ - default_prepare(test); - handle_exception(DE_VECTOR, my_isr); - handle_exception(NMI_VECTOR, my_isr); -} - - -static void exc_inject_test(struct svm_test *test) -{ - asm volatile ("vmmcall\n\tvmmcall\n\t"); -} - -static bool exc_inject_finished(struct svm_test *test) -{ - switch (get_test_stage(test)) { - case 0: - if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - vmcb->save.rip += 3; - vmcb->control.event_inj = NMI_VECTOR | SVM_EVTINJ_TYPE_EXEPT | SVM_EVTINJ_VALID; - break; - - case 1: - if (vmcb->control.exit_code != SVM_EXIT_ERR) { - report(false, "VMEXIT not due to error. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - report(count_exc == 0, "exception with vector 2 not injected"); - vmcb->control.event_inj = DE_VECTOR | SVM_EVTINJ_TYPE_EXEPT | SVM_EVTINJ_VALID; - break; - - case 2: - if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - vmcb->save.rip += 3; - report(count_exc == 1, "divide overflow exception injected"); - report(!(vmcb->control.event_inj & SVM_EVTINJ_VALID), "eventinj.VALID cleared"); - break; - - default: - return true; - } - - inc_test_stage(test); - - return get_test_stage(test) == 3; -} - -static bool exc_inject_check(struct svm_test *test) -{ - return count_exc == 1 && get_test_stage(test) == 3; -} - -static volatile bool virq_fired; - -static void virq_isr(isr_regs_t *regs) -{ - virq_fired = true; -} - -static void virq_inject_prepare(struct svm_test *test) -{ - handle_irq(0xf1, virq_isr); - default_prepare(test); - vmcb->control.int_ctl = V_INTR_MASKING_MASK | V_IRQ_MASK | - (0x0f << V_INTR_PRIO_SHIFT); // Set to the highest priority - vmcb->control.int_vector = 0xf1; - virq_fired = false; - set_test_stage(test, 0); -} - -static void virq_inject_test(struct svm_test *test) -{ - if (virq_fired) { - report(false, "virtual interrupt fired before L2 sti"); - set_test_stage(test, -1); - vmmcall(); - } - - irq_enable(); - asm volatile ("nop"); - irq_disable(); - - if (!virq_fired) { - report(false, "virtual interrupt not fired after L2 sti"); - set_test_stage(test, -1); - } - - vmmcall(); - - if (virq_fired) { - report(false, "virtual interrupt fired before L2 sti after VINTR intercept"); - set_test_stage(test, -1); - vmmcall(); - } - - irq_enable(); - asm volatile ("nop"); - irq_disable(); - - if (!virq_fired) { - report(false, "virtual interrupt not fired after return from VINTR intercept"); - set_test_stage(test, -1); - } - - vmmcall(); - - irq_enable(); - asm volatile ("nop"); - irq_disable(); - - if (virq_fired) { - report(false, "virtual interrupt fired when V_IRQ_PRIO less than V_TPR"); - set_test_stage(test, -1); - } - - vmmcall(); - vmmcall(); -} - -static bool virq_inject_finished(struct svm_test *test) -{ - vmcb->save.rip += 3; - - switch (get_test_stage(test)) { - case 0: - if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - if (vmcb->control.int_ctl & V_IRQ_MASK) { - report(false, "V_IRQ not cleared on VMEXIT after firing"); - return true; - } - virq_fired = false; - vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR); - vmcb->control.int_ctl = V_INTR_MASKING_MASK | V_IRQ_MASK | - (0x0f << V_INTR_PRIO_SHIFT); - break; - - case 1: - if (vmcb->control.exit_code != SVM_EXIT_VINTR) { - report(false, "VMEXIT not due to vintr. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - if (virq_fired) { - report(false, "V_IRQ fired before SVM_EXIT_VINTR"); - return true; - } - vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR); - break; - - case 2: - if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - virq_fired = false; - // Set irq to lower priority - vmcb->control.int_ctl = V_INTR_MASKING_MASK | V_IRQ_MASK | - (0x08 << V_INTR_PRIO_SHIFT); - // Raise guest TPR - vmcb->control.int_ctl |= 0x0a & V_TPR_MASK; - break; - - case 3: - if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR); - break; - - case 4: - // INTERCEPT_VINTR should be ignored because V_INTR_PRIO < V_TPR - if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) { - report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x", - vmcb->control.exit_code); - return true; - } - break; - - default: - return true; - } - - inc_test_stage(test); - - return get_test_stage(test) == 5; -} - -static bool virq_inject_check(struct svm_test *test) -{ - return get_test_stage(test) == 5; -} - -/* - * Detect nested guest RIP corruption as explained in kernel commit - * b6162e82aef19fee9c32cb3fe9ac30d9116a8c73 - * - * In the assembly loop below 'ins' is executed while IO instructions - * are not intercepted; the instruction is emulated by L0. - * - * At the same time we are getting interrupts from the local APIC timer, - * and we do intercept them in L1 - * - * If the interrupt happens on the insb instruction, L0 will VMexit, emulate - * the insb instruction and then it will inject the interrupt to L1 through - * a nested VMexit. Due to a bug, it would leave pre-emulation values of RIP, - * RAX and RSP in the VMCB. - * - * In our intercept handler we detect the bug by checking that RIP is that of - * the insb instruction, but its memory operand has already been written. - * This means that insb was already executed. - */ - -static volatile int isr_cnt = 0; -static volatile uint8_t io_port_var = 0xAA; -extern const char insb_instruction_label[]; - -static void reg_corruption_isr(isr_regs_t *regs) -{ - isr_cnt++; - apic_write(APIC_EOI, 0); -} - -static void reg_corruption_prepare(struct svm_test *test) -{ - default_prepare(test); - set_test_stage(test, 0); - - vmcb->control.int_ctl = V_INTR_MASKING_MASK; - vmcb->control.intercept |= (1ULL << INTERCEPT_INTR); - - handle_irq(TIMER_VECTOR, reg_corruption_isr); - - /* set local APIC to inject external interrupts */ - apic_write(APIC_TMICT, 0); - apic_write(APIC_TDCR, 0); - apic_write(APIC_LVTT, TIMER_VECTOR | APIC_LVT_TIMER_PERIODIC); - apic_write(APIC_TMICT, 1000); -} - -static void reg_corruption_test(struct svm_test *test) -{ - /* this is endless loop, which is interrupted by the timer interrupt */ - asm volatile ( - "1:\n\t" - "movw $0x4d0, %%dx\n\t" // IO port - "lea %[io_port_var], %%rdi\n\t" - "movb $0xAA, %[io_port_var]\n\t" - "insb_instruction_label:\n\t" - "insb\n\t" - "jmp 1b\n\t" - - : [io_port_var] "=m" (io_port_var) - : /* no inputs*/ - : "rdx", "rdi" - ); -} - -static bool reg_corruption_finished(struct svm_test *test) -{ - if (isr_cnt == 10000) { - report(true, - "No RIP corruption detected after %d timer interrupts", - isr_cnt); - set_test_stage(test, 1); - return true; - } - - if (vmcb->control.exit_code == SVM_EXIT_INTR) { - - void* guest_rip = (void*)vmcb->save.rip; - - irq_enable(); - asm volatile ("nop"); - irq_disable(); - - if (guest_rip == insb_instruction_label && io_port_var != 0xAA) { - report(false, - "RIP corruption detected after %d timer interrupts", - isr_cnt); - return true; - } - - } - return false; -} - -static bool reg_corruption_check(struct svm_test *test) -{ - return get_test_stage(test) == 1; -} - -#define TEST(name) { #name, .v2 = name } - -/* - * v2 tests - */ - -static void basic_guest_main(struct svm_test *test) -{ -} - - -#define SVM_TEST_REG_RESERVED_BITS(start, end, inc, str_name, reg, val, \ - resv_mask) \ -{ \ - u64 tmp, mask; \ - int i; \ - \ - for (i = start; i <= end; i = i + inc) { \ - mask = 1ull << i; \ - if (!(mask & resv_mask)) \ - continue; \ - tmp = val | mask; \ - reg = tmp; \ - report(svm_vmrun() == SVM_EXIT_ERR, "Test %s %d:%d: %lx",\ - str_name, end, start, tmp); \ - } \ -} - -#define SVM_TEST_CR_RESERVED_BITS(start, end, inc, cr, val, resv_mask) \ -{ \ - u64 tmp, mask; \ - int i; \ - \ - for (i = start; i <= end; i = i + inc) { \ - mask = 1ull << i; \ - if (!(mask & resv_mask)) \ - continue; \ - tmp = val | mask; \ - switch (cr) { \ - case 0: \ - vmcb->save.cr0 = tmp; \ - break; \ - case 3: \ - vmcb->save.cr3 = tmp; \ - break; \ - case 4: \ - vmcb->save.cr4 = tmp; \ - } \ - report(svm_vmrun() == SVM_EXIT_ERR, "Test CR%d %d:%d: %lx",\ - cr, end, start, tmp); \ - } \ -} - -static void test_efer(void) -{ - /* - * Un-setting EFER.SVME is illegal - */ - u64 efer_saved = vmcb->save.efer; - u64 efer = efer_saved; - - report (svm_vmrun() == SVM_EXIT_VMMCALL, "EFER.SVME: %lx", efer); - efer &= ~EFER_SVME; - vmcb->save.efer = efer; - report (svm_vmrun() == SVM_EXIT_ERR, "EFER.SVME: %lx", efer); - vmcb->save.efer = efer_saved; - - /* - * EFER MBZ bits: 63:16, 9 - */ - efer_saved = vmcb->save.efer; - - SVM_TEST_REG_RESERVED_BITS(8, 9, 1, "EFER", vmcb->save.efer, - efer_saved, SVM_EFER_RESERVED_MASK); - SVM_TEST_REG_RESERVED_BITS(16, 63, 4, "EFER", vmcb->save.efer, - efer_saved, SVM_EFER_RESERVED_MASK); - - vmcb->save.efer = efer_saved; -} - -static void test_cr0(void) -{ - /* - * Un-setting CR0.CD and setting CR0.NW is illegal combination - */ - u64 cr0_saved = vmcb->save.cr0; - u64 cr0 = cr0_saved; - - cr0 |= X86_CR0_CD; - cr0 &= ~X86_CR0_NW; - vmcb->save.cr0 = cr0; - report (svm_vmrun() == SVM_EXIT_VMMCALL, "Test CR0 CD=1,NW=0: %lx", - cr0); - cr0 |= X86_CR0_NW; - vmcb->save.cr0 = cr0; - report (svm_vmrun() == SVM_EXIT_VMMCALL, "Test CR0 CD=1,NW=1: %lx", - cr0); - cr0 &= ~X86_CR0_NW; - cr0 &= ~X86_CR0_CD; - vmcb->save.cr0 = cr0; - report (svm_vmrun() == SVM_EXIT_VMMCALL, "Test CR0 CD=0,NW=0: %lx", - cr0); - cr0 |= X86_CR0_NW; - vmcb->save.cr0 = cr0; - report (svm_vmrun() == SVM_EXIT_ERR, "Test CR0 CD=0,NW=1: %lx", - cr0); - vmcb->save.cr0 = cr0_saved; - - /* - * CR0[63:32] are not zero - */ - cr0 = cr0_saved; - - SVM_TEST_REG_RESERVED_BITS(32, 63, 4, "CR0", vmcb->save.cr0, cr0_saved, - SVM_CR0_RESERVED_MASK); - vmcb->save.cr0 = cr0_saved; -} - -static void test_cr3(void) -{ - /* - * CR3 MBZ bits based on different modes: - * [2:0] - legacy PAE - * [2:0], [11:5] - legacy non-PAE - * [2:0], [11:5], [63:52] - long mode - */ - u64 cr3_saved = vmcb->save.cr3; - u64 cr4_saved = vmcb->save.cr4; - u64 cr4 = cr4_saved; - u64 efer_saved = vmcb->save.efer; - u64 efer = efer_saved; - - efer &= ~EFER_LME; - vmcb->save.efer = efer; - cr4 |= X86_CR4_PAE; - vmcb->save.cr4 = cr4; - SVM_TEST_CR_RESERVED_BITS(0, 2, 1, 3, cr3_saved, - SVM_CR3_LEGACY_PAE_RESERVED_MASK); - - cr4 = cr4_saved & ~X86_CR4_PAE; - vmcb->save.cr4 = cr4; - SVM_TEST_CR_RESERVED_BITS(0, 11, 1, 3, cr3_saved, - SVM_CR3_LEGACY_RESERVED_MASK); - - cr4 |= X86_CR4_PAE; - vmcb->save.cr4 = cr4; - efer |= EFER_LME; - vmcb->save.efer = efer; - SVM_TEST_CR_RESERVED_BITS(0, 63, 1, 3, cr3_saved, - SVM_CR3_LONG_RESERVED_MASK); - - vmcb->save.cr4 = cr4_saved; - vmcb->save.cr3 = cr3_saved; - vmcb->save.efer = efer_saved; -} - -static void test_cr4(void) -{ - /* - * CR4 MBZ bits based on different modes: - * [15:12], 17, 19, [31:22] - legacy mode - * [15:12], 17, 19, [63:22] - long mode - */ - u64 cr4_saved = vmcb->save.cr4; - u64 efer_saved = vmcb->save.efer; - u64 efer = efer_saved; - - efer &= ~EFER_LME; - vmcb->save.efer = efer; - SVM_TEST_CR_RESERVED_BITS(12, 31, 1, 4, cr4_saved, - SVM_CR4_LEGACY_RESERVED_MASK); - - efer |= EFER_LME; - vmcb->save.efer = efer; - SVM_TEST_CR_RESERVED_BITS(12, 31, 1, 4, cr4_saved, - SVM_CR4_RESERVED_MASK); - SVM_TEST_CR_RESERVED_BITS(32, 63, 4, 4, cr4_saved, - SVM_CR4_RESERVED_MASK); - - vmcb->save.cr4 = cr4_saved; - vmcb->save.efer = efer_saved; -} - -static void test_dr(void) -{ - /* - * DR6[63:32] and DR7[63:32] are MBZ - */ - u64 dr_saved = vmcb->save.dr6; - - SVM_TEST_REG_RESERVED_BITS(32, 63, 4, "DR6", vmcb->save.dr6, dr_saved, - SVM_DR6_RESERVED_MASK); - vmcb->save.dr6 = dr_saved; - - dr_saved = vmcb->save.dr7; - SVM_TEST_REG_RESERVED_BITS(32, 63, 4, "DR7", vmcb->save.dr7, dr_saved, - SVM_DR7_RESERVED_MASK); - - vmcb->save.dr7 = dr_saved; -} - -static void svm_guest_state_test(void) -{ - test_set_guest(basic_guest_main); - - test_efer(); - test_cr0(); - test_cr3(); - test_cr4(); - test_dr(); -} - -struct svm_test svm_tests[] = { - { "null", default_supported, default_prepare, - default_prepare_gif_clear, null_test, - default_finished, null_check }, - { "vmrun", default_supported, default_prepare, - default_prepare_gif_clear, test_vmrun, - default_finished, check_vmrun }, - { "ioio", default_supported, prepare_ioio, - default_prepare_gif_clear, test_ioio, - ioio_finished, check_ioio }, - { "vmrun intercept check", default_supported, prepare_no_vmrun_int, - default_prepare_gif_clear, null_test, default_finished, - check_no_vmrun_int }, - { "rsm", default_supported, - prepare_rsm_intercept, default_prepare_gif_clear, - test_rsm_intercept, finished_rsm_intercept, check_rsm_intercept }, - { "cr3 read intercept", default_supported, - prepare_cr3_intercept, default_prepare_gif_clear, - test_cr3_intercept, default_finished, check_cr3_intercept }, - { "cr3 read nointercept", default_supported, default_prepare, - default_prepare_gif_clear, test_cr3_intercept, default_finished, - check_cr3_nointercept }, - { "cr3 read intercept emulate", smp_supported, - prepare_cr3_intercept_bypass, default_prepare_gif_clear, - test_cr3_intercept_bypass, default_finished, check_cr3_intercept }, - { "dr intercept check", default_supported, prepare_dr_intercept, - default_prepare_gif_clear, test_dr_intercept, dr_intercept_finished, - check_dr_intercept }, - { "next_rip", next_rip_supported, prepare_next_rip, - default_prepare_gif_clear, test_next_rip, - default_finished, check_next_rip }, - { "msr intercept check", default_supported, prepare_msr_intercept, - default_prepare_gif_clear, test_msr_intercept, - msr_intercept_finished, check_msr_intercept }, - { "mode_switch", default_supported, prepare_mode_switch, - default_prepare_gif_clear, test_mode_switch, - mode_switch_finished, check_mode_switch }, - { "asid_zero", default_supported, prepare_asid_zero, - default_prepare_gif_clear, test_asid_zero, - default_finished, check_asid_zero }, - { "sel_cr0_bug", default_supported, sel_cr0_bug_prepare, - default_prepare_gif_clear, sel_cr0_bug_test, - sel_cr0_bug_finished, sel_cr0_bug_check }, - { "npt_nx", npt_supported, npt_nx_prepare, - default_prepare_gif_clear, null_test, - default_finished, npt_nx_check }, - { "npt_us", npt_supported, npt_us_prepare, - default_prepare_gif_clear, npt_us_test, - default_finished, npt_us_check }, - { "npt_rsvd", npt_supported, npt_rsvd_prepare, - default_prepare_gif_clear, null_test, - default_finished, npt_rsvd_check }, - { "npt_rw", npt_supported, npt_rw_prepare, - default_prepare_gif_clear, npt_rw_test, - default_finished, npt_rw_check }, - { "npt_rsvd_pfwalk", npt_supported, npt_rsvd_pfwalk_prepare, - default_prepare_gif_clear, null_test, - default_finished, npt_rsvd_pfwalk_check }, - { "npt_rw_pfwalk", npt_supported, npt_rw_pfwalk_prepare, - default_prepare_gif_clear, null_test, - default_finished, npt_rw_pfwalk_check }, - { "npt_l1mmio", npt_supported, npt_l1mmio_prepare, - default_prepare_gif_clear, npt_l1mmio_test, - default_finished, npt_l1mmio_check }, - { "npt_rw_l1mmio", npt_supported, npt_rw_l1mmio_prepare, - default_prepare_gif_clear, npt_rw_l1mmio_test, - default_finished, npt_rw_l1mmio_check }, - { "tsc_adjust", tsc_adjust_supported, tsc_adjust_prepare, - default_prepare_gif_clear, tsc_adjust_test, - default_finished, tsc_adjust_check }, - { "latency_run_exit", default_supported, latency_prepare, - default_prepare_gif_clear, latency_test, - latency_finished, latency_check }, - { "latency_svm_insn", default_supported, lat_svm_insn_prepare, - default_prepare_gif_clear, null_test, - lat_svm_insn_finished, lat_svm_insn_check }, - { "exc_inject", default_supported, exc_inject_prepare, - default_prepare_gif_clear, exc_inject_test, - exc_inject_finished, exc_inject_check }, - { "pending_event", default_supported, pending_event_prepare, - default_prepare_gif_clear, - pending_event_test, pending_event_finished, pending_event_check }, - { "pending_event_cli", default_supported, pending_event_cli_prepare, - pending_event_cli_prepare_gif_clear, - pending_event_cli_test, pending_event_cli_finished, - pending_event_cli_check }, - { "interrupt", default_supported, interrupt_prepare, - default_prepare_gif_clear, interrupt_test, - interrupt_finished, interrupt_check }, - { "nmi", default_supported, nmi_prepare, - default_prepare_gif_clear, nmi_test, - nmi_finished, nmi_check }, - { "nmi_hlt", smp_supported, nmi_prepare, - default_prepare_gif_clear, nmi_hlt_test, - nmi_hlt_finished, nmi_hlt_check }, - { "virq_inject", default_supported, virq_inject_prepare, - default_prepare_gif_clear, virq_inject_test, - virq_inject_finished, virq_inject_check }, - { "reg_corruption", default_supported, reg_corruption_prepare, - default_prepare_gif_clear, reg_corruption_test, - reg_corruption_finished, reg_corruption_check }, - TEST(svm_guest_state_test), - { NULL, NULL, NULL, NULL, NULL, NULL, NULL } -}; diff --git a/x86/syscall.c b/x86/syscall.c deleted file mode 100644 index 8cef8600..00000000 --- a/x86/syscall.c +++ /dev/null @@ -1,107 +0,0 @@ -/* msr tests */ - -#include "libcflat.h" -#include "processor.h" -#include "msr.h" -#include "desc.h" - -static void test_syscall_lazy_load(void) -{ - extern void syscall_target(void); - u16 cs = read_cs(), ss = read_ss(); - ulong tmp; - - wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SCE); - wrmsr(MSR_LSTAR, (ulong)syscall_target); - wrmsr(MSR_STAR, (uint64_t)cs << 32); - asm volatile("pushf; syscall; syscall_target: popf" : "=c"(tmp) : : "r11"); - write_ss(ss); - // will crash horribly if broken - report(true, "MSR_*STAR eager loading"); -} - -/* - * test handling of TF in syscall/sysret: #DB is raised if TF - * is 1 at the *end* of syscall/sysret. - * - * This uses 32-bit syscall/sysret because KVM emulates it on Intel processors. - * However, the same bug happens with 64-bit syscall/sysret if two vCPUs - * "race" to force the emulation of syscall/sysret. - */ - -static uint16_t code_segment_upon_db; -static void handle_db(struct ex_regs *regs) -{ - code_segment_upon_db = regs->cs; - regs->rflags &= ~(1 << 8); -} - -/* expects desired ring 3 flags in rax */ -asm("syscall32_target:\n" - " cmpl $0, code_segment_upon_db(%rip)\n" - " jne back_to_test\n" - " mov %eax,%r11d\n" - " sysretl\n"); - -/* 32-bit, ring-3 part of test_syscall_tf */ -asm(" .code32\n" - "syscall_tf_user32:\n" - " pushf\n" - " pop %eax\n" - " or $(1<<8),%eax\n" - " push %eax\n" - " popf\n" - " syscall\n" /* singlestep trap taken after syscall */ - " syscall\n" /* jumps back to test_syscall_tf's body */ - " .code64\n"); - -static void test_syscall_tf(void) -{ - extern void syscall32_target(void); - extern void syscall_tf_user32(void); - ulong rcx; - - wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SCE); - wrmsr(MSR_CSTAR, (ulong)syscall32_target); - wrmsr(MSR_STAR, ((uint64_t)USER_CS32 << 48) | ((uint64_t)KERNEL_CS64 << 32)); - wrmsr(MSR_SYSCALL_MASK, X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_NT); - handle_exception(DB_VECTOR, handle_db); - - /* good: - * sysret to syscall_tf_user32 - * popf sets TF (singlestep starts on the next instruction) - * syscall to syscall32_target -> TF cleared and no singlestep - * sysretl sets TF - * handle_db sets code_segment_upon_db to USER_CS32 and clears TF - * syscall to syscall32_target - * syscall32_target jumps to back_to_test - * - * bad: - * sysret to syscall_tf_user32 - * popf sets TF (singlestep starts on the next instruction) - * syscall to syscall32_target, TF cleared and wrong singlestep exception - * handle_db sets code_segment_upon_db to KERNEL_CS64 - * syscall32_target jumps to back_to_test - */ - rcx = (ulong)syscall_tf_user32; - asm volatile(" push %%rbp\n" - " pushf; pop %%rax\n" // expected by syscall32_target - " sysret\n" - "back_to_test:\n" - " pop %%rbp" - : "+c"(rcx) : - : "rax", "rbx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", - "r12", "r13", "r14", "r15"); - if (code_segment_upon_db != USER_CS32) { - printf("wrong CS (%#04x)!\n", code_segment_upon_db); - } - report(code_segment_upon_db == USER_CS32, "syscall TF handling"); -} - -int main(int ac, char **av) -{ - test_syscall_lazy_load(); - test_syscall_tf(); - - return report_summary(); -} diff --git a/x86/taskswitch.c b/x86/taskswitch.c deleted file mode 100644 index 889831ec..00000000 --- a/x86/taskswitch.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2010 Siemens AG - * Author: Jan Kiszka - * - * Released under GPLv2. - */ - -#include "libcflat.h" -#include "x86/desc.h" -#include "vmalloc.h" - -#define TSS_RETURN (FIRST_SPARE_SEL) - -void fault_entry(void); - -static __attribute__((used, regparm(1))) void -fault_handler(unsigned long error_code) -{ - print_current_tss_info(); - printf("error code %lx\n", error_code); - - tss.eip += 2; - - gdt32[TSS_MAIN / 8].access &= ~2; - - set_gdt_task_gate(TSS_RETURN, tss_intr.prev); -} - -asm ( - "fault_entry:\n" - " mov (%esp),%eax\n" - " call fault_handler\n" - " jmp $" xstr(TSS_RETURN) ", $0\n" -); - -int main(int ac, char **av) -{ - const long invalid_segment = 0x1234; - - setup_tss32(); - set_intr_task_gate(13, fault_entry); - - asm ( - "mov %0,%%es\n" - : : "r" (invalid_segment) : "edi" - ); - - printf("post fault\n"); - - return 0; -} diff --git a/x86/taskswitch2.c b/x86/taskswitch2.c deleted file mode 100644 index ed3f99ae..00000000 --- a/x86/taskswitch2.c +++ /dev/null @@ -1,294 +0,0 @@ -#include "libcflat.h" -#include "desc.h" -#include "apic-defs.h" -#include "apic.h" -#include "processor.h" -#include "vm.h" -#include "vmalloc.h" -#include "alloc_page.h" -#include "delay.h" - -#define MAIN_TSS_SEL (FIRST_SPARE_SEL + 0) -#define VM86_TSS_SEL (FIRST_SPARE_SEL + 8) -#define CONFORM_CS_SEL (FIRST_SPARE_SEL + 16) - -static volatile int test_count; -static volatile unsigned int test_divider; - -static char *fault_addr; -static ulong fault_phys; - -void do_pf_tss(ulong *error_code); - -static void nmi_tss(void) -{ -start: - printf("NMI task is running\n"); - print_current_tss_info(); - test_count++; - asm volatile ("iret"); - goto start; -} - -static void de_tss(void) -{ -start: - printf("DE task is running\n"); - print_current_tss_info(); - test_divider = 10; - test_count++; - asm volatile ("iret"); - goto start; -} - -static void of_tss(void) -{ -start: - printf("OF task is running\n"); - print_current_tss_info(); - test_count++; - asm volatile ("iret"); - goto start; -} - -static void bp_tss(void) -{ -start: - printf("BP task is running\n"); - print_current_tss_info(); - test_count++; - asm volatile ("iret"); - goto start; -} - -void do_pf_tss(ulong *error_code) -{ - printf("PF task is running %p %lx\n", error_code, *error_code); - print_current_tss_info(); - if (*error_code == 0x2) /* write access, not present */ - test_count++; - install_pte(phys_to_virt(read_cr3()), 1, fault_addr, - fault_phys | PT_PRESENT_MASK | PT_WRITABLE_MASK, 0); -} - -extern void pf_tss(void); - -asm ( - "pf_tss: \n\t" - "push %esp \n\t" - "call do_pf_tss \n\t" - "add $4, %esp \n\t" - "iret\n\t" - "jmp pf_tss\n\t" - ); - -static void jmp_tss(void) -{ -start: - printf("JMP to task succeeded\n"); - print_current_tss_info(); - test_count++; - asm volatile ("ljmp $" xstr(TSS_MAIN) ", $0"); - goto start; -} - -static void irq_tss(void) -{ -start: - printf("IRQ task is running\n"); - print_current_tss_info(); - test_count++; - asm volatile ("iret"); - test_count++; - printf("IRQ task restarts after iret.\n"); - goto start; -} - -static void user_tss(void) -{ -start: - printf("Conforming task is running\n"); - print_current_tss_info(); - test_count++; - asm volatile ("iret"); - goto start; -} - -static void test_kernel_mode_int(void) -{ - unsigned int res; - - /* test that int $2 triggers task gate */ - test_count = 0; - set_intr_task_gate(2, nmi_tss); - printf("Triggering nmi 2\n"); - asm volatile ("int $2"); - printf("Return from nmi %d\n", test_count); - report(test_count == 1, "NMI int $2"); - - /* test that external NMI triggers task gate */ - test_count = 0; - set_intr_task_gate(2, nmi_tss); - printf("Triggering nmi through APIC\n"); - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); - io_delay(); - printf("Return from APIC nmi\n"); - report(test_count == 1, "NMI external"); - - /* test that external interrupt triggesr task gate */ - test_count = 0; - printf("Trigger IRQ from APIC\n"); - set_intr_task_gate(0xf0, irq_tss); - irq_enable(); - apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT | 0xf0, 0); - io_delay(); - irq_disable(); - printf("Return from APIC IRQ\n"); - report(test_count == 1, "IRQ external"); - - /* test that HW exception triggesr task gate */ - set_intr_task_gate(0, de_tss); - printf("Try to devide by 0\n"); - asm volatile ("divl %3": "=a"(res) - : "d"(0), "a"(1500), "m"(test_divider)); - printf("Result is %d\n", res); - report(res == 150, "DE exeption"); - - /* test if call HW exeption DE by int $0 triggers task gate */ - test_count = 0; - set_intr_task_gate(0, de_tss); - printf("Call int 0\n"); - asm volatile ("int $0"); - printf("Return from int 0\n"); - report(test_count == 1, "int $0"); - - /* test if HW exception OF triggers task gate */ - test_count = 0; - set_intr_task_gate(4, of_tss); - printf("Call into\n"); - asm volatile ("addb $127, %b0\ninto"::"a"(127)); - printf("Return from into\n"); - report(test_count, "OF exeption"); - - /* test if HW exception BP triggers task gate */ - test_count = 0; - set_intr_task_gate(3, bp_tss); - printf("Call int 3\n"); - asm volatile ("int $3"); - printf("Return from int 3\n"); - report(test_count == 1, "BP exeption"); - - /* - * test that PF triggers task gate and error code is placed on - * exception task's stack - */ - fault_addr = alloc_vpage(); - fault_phys = (ulong)virt_to_phys(alloc_page()); - test_count = 0; - set_intr_task_gate(14, pf_tss); - printf("Access unmapped page\n"); - *fault_addr = 0; - printf("Return from pf tss\n"); - report(test_count == 1, "PF exeption"); -} - -static void test_gdt_task_gate(void) -{ - /* test that calling a task by lcall works */ - test_count = 0; - tss_intr.eip = (u32)irq_tss; - printf("Calling task by lcall\n"); - /* hlt opcode is 0xf4 I use destination IP 0xf4f4f4f4 to catch - incorrect instruction length calculation */ - asm volatile("lcall $" xstr(TSS_INTR) ", $0xf4f4f4f4"); - printf("Return from call\n"); - report(test_count == 1, "lcall"); - - /* call the same task again and check that it restarted after iret */ - test_count = 0; - asm volatile("lcall $" xstr(TSS_INTR) ", $0xf4f4f4f4"); - report(test_count == 2, "lcall2"); - - /* test that calling a task by ljmp works */ - test_count = 0; - tss_intr.eip = (u32)jmp_tss; - printf("Jumping to a task by ljmp\n"); - asm volatile ("ljmp $" xstr(TSS_INTR) ", $0xf4f4f4f4"); - printf("Jump back succeeded\n"); - report(test_count == 1, "ljmp"); -} - -static void test_vm86_switch(void) -{ - static tss32_t main_tss; - static tss32_t vm86_tss; - - u8 *vm86_start; - - /* Write a 'ud2' instruction somewhere below 1 MB */ - vm86_start = (void*) 0x42000; - vm86_start[0] = 0x0f; - vm86_start[1] = 0x0b; - - /* Main TSS */ - set_gdt_entry(MAIN_TSS_SEL, (u32)&main_tss, sizeof(tss32_t) - 1, 0x89, 0); - ltr(MAIN_TSS_SEL); - main_tss = (tss32_t) { - .prev = VM86_TSS_SEL, - .cr3 = read_cr3(), - }; - - /* VM86 TSS (marked as busy, so we can iret to it) */ - set_gdt_entry(VM86_TSS_SEL, (u32)&vm86_tss, sizeof(tss32_t) - 1, 0x8b, 0); - vm86_tss = (tss32_t) { - .eflags = 0x20002, - .cr3 = read_cr3(), - .eip = (u32) vm86_start & 0x0f, - .cs = (u32) vm86_start >> 4, - .ds = 0x1234, - .es = 0x2345, - }; - - /* Setup task gate to main TSS for #UD */ - set_idt_task_gate(6, MAIN_TSS_SEL); - - /* Jump into VM86 task with iret, #UD lets it come back immediately */ - printf("Switch to VM86 task and back\n"); - asm volatile( - "pushf\n" - "orw $0x4000, (%esp)\n" - "popf\n" - "iret\n" - ); - report(1, "VM86"); -} - -#define IOPL_SHIFT 12 - -static void test_conforming_switch(void) -{ - /* test lcall with conforming segment, cs.dpl != cs.rpl */ - test_count = 0; - - tss_intr.cs = CONFORM_CS_SEL | 3; - tss_intr.eip = (u32)user_tss; - tss_intr.ss = USER_DS; - tss_intr.ds = tss_intr.gs = tss_intr.es = tss_intr.fs = tss_intr.ss; - tss_intr.eflags |= 3 << IOPL_SHIFT; - set_gdt_entry(CONFORM_CS_SEL, 0, 0xffffffff, 0x9f, 0xc0); - asm volatile("lcall $" xstr(TSS_INTR) ", $0xf4f4f4f4"); - report(test_count == 1, "lcall with cs.rpl != cs.dpl"); -} - -int main(void) -{ - setup_vm(); - setup_tss32(); - - test_gdt_task_gate(); - test_kernel_mode_int(); - test_vm86_switch(); - test_conforming_switch(); - - return report_summary(); -} diff --git a/x86/tsc.c b/x86/tsc.c deleted file mode 100644 index bc403fc7..00000000 --- a/x86/tsc.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "libcflat.h" -#include "processor.h" - -static void test_wrtsc(u64 t1) -{ - u64 t2; - - wrtsc(t1); - t2 = rdtsc(); - printf("rdtsc after wrtsc(%" PRId64 "): %" PRId64 "\n", t1, t2); -} - -static void test_rdtscp(u64 aux) -{ - u32 ecx; - - wrmsr(MSR_TSC_AUX, aux); - rdtscp(&ecx); - report(ecx == aux, "Test RDTSCP %" PRIu64, aux); -} - -static void test_rdpid(u64 aux) -{ - u32 eax; - - wrmsr(MSR_TSC_AUX, aux); - asm (".byte 0xf3, 0x0f, 0xc7, 0xf8" : "=a" (eax)); - report(eax == aux, "Test rdpid %%eax %" PRId64, aux); -} - -int main(void) -{ - u64 t1, t2; - - t1 = rdtsc(); - t2 = rdtsc(); - printf("rdtsc latency %u\n", (unsigned)(t2 - t1)); - - test_wrtsc(0); - test_wrtsc(100000000000ull); - - if (this_cpu_has(X86_FEATURE_RDTSCP)) { - test_rdtscp(0); - test_rdtscp(10); - test_rdtscp(0x100); - } else - printf("rdtscp not supported\n"); - - if (this_cpu_has(X86_FEATURE_RDPID)) { - test_rdpid(0); - test_rdpid(10); - test_rdpid(0x100); - } else - printf("rdpid not supported\n"); - return report_summary(); -} diff --git a/x86/tsc_adjust.c b/x86/tsc_adjust.c deleted file mode 100644 index 1f26b7a7..00000000 --- a/x86/tsc_adjust.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "libcflat.h" -#include "processor.h" - -int main(void) -{ - u64 t1, t2, t3, t4, t5; - u64 est_delta_time; - - if (this_cpu_has(X86_FEATURE_TSC_ADJUST)) { // MSR_IA32_TSC_ADJUST Feature is enabled? - report(rdmsr(MSR_IA32_TSC_ADJUST) == 0x0, - "MSR_IA32_TSC_ADJUST msr initialization"); - t3 = 100000000000ull; - t1 = rdtsc(); - wrmsr(MSR_IA32_TSC_ADJUST, t3); - t2 = rdtsc(); - report(rdmsr(MSR_IA32_TSC_ADJUST) == t3, - "MSR_IA32_TSC_ADJUST msr read / write"); - report((t2 - t1) >= t3, - "TSC adjustment for MSR_IA32_TSC_ADJUST value"); - t3 = 0x0; - wrmsr(MSR_IA32_TSC_ADJUST, t3); - report(rdmsr(MSR_IA32_TSC_ADJUST) == t3, - "MSR_IA32_TSC_ADJUST msr read / write"); - t4 = 100000000000ull; - t1 = rdtsc(); - wrtsc(t4); - t2 = rdtsc(); - t5 = rdmsr(MSR_IA32_TSC_ADJUST); - // est of time between reading tsc and writing tsc, - // (based on MSR_IA32_TSC_ADJUST msr value) should be small - est_delta_time = t4 - t5 - t1; - // arbitray 2x latency (wrtsc->rdtsc) threshold - report(est_delta_time <= (2 * (t2 - t4)), - "MSR_IA32_TSC_ADJUST msr adjustment on tsc write"); - } - else { - report(true, "MSR_IA32_TSC_ADJUST feature not enabled"); - } - return report_summary(); -} diff --git a/x86/tscdeadline_latency.c b/x86/tscdeadline_latency.c deleted file mode 100644 index a3bc4ea4..00000000 --- a/x86/tscdeadline_latency.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * qemu command line | grep latency | cut -f 2 -d ":" > latency - * - * In octave: - * load latency - * min(latency) - * max(latency) - * mean(latency) - * hist(latency, 50) - */ - -/* - * for host tracing of breakmax option: - * - * # cd /sys/kernel/debug/tracing/ - * # echo x86-tsc > trace_clock - * # echo "kvm_exit kvm_entry kvm_msr" > set_event - * # echo "sched_switch $extratracepoints" >> set_event - * # echo apic_timer_fn > set_ftrace_filter - * # echo "function" > current_tracer - */ - -#include "libcflat.h" -#include "apic.h" -#include "vm.h" -#include "smp.h" -#include "desc.h" -#include "isr.h" -#include "msr.h" - -static void test_lapic_existence(void) -{ - u32 lvr; - - lvr = apic_read(APIC_LVR); - printf("apic version: %x\n", lvr); - report((u16)lvr == 0x14, "apic existence"); -} - -#define TSC_DEADLINE_TIMER_VECTOR 0xef - -static int tdt_count; -u64 exptime; -int delta; -#define TABLE_SIZE 10000 -u64 table[TABLE_SIZE]; -volatile int table_idx; -volatile int hitmax = 0; -int breakmax = 0; - -static void tsc_deadline_timer_isr(isr_regs_t *regs) -{ - u64 now = rdtsc(); - ++tdt_count; - - if (table_idx < TABLE_SIZE && tdt_count > 1) - table[table_idx++] = now - exptime; - - if (breakmax && tdt_count > 1 && (now - exptime) > breakmax) { - hitmax = 1; - apic_write(APIC_EOI, 0); - return; - } - - exptime = now+delta; - wrmsr(MSR_IA32_TSCDEADLINE, now+delta); - apic_write(APIC_EOI, 0); -} - -static void start_tsc_deadline_timer(void) -{ - handle_irq(TSC_DEADLINE_TIMER_VECTOR, tsc_deadline_timer_isr); - irq_enable(); - - wrmsr(MSR_IA32_TSCDEADLINE, rdmsr(MSR_IA32_TSC)+delta); - asm volatile ("nop"); -} - -static int enable_tsc_deadline_timer(void) -{ - uint32_t lvtt; - - if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) { - lvtt = APIC_LVT_TIMER_TSCDEADLINE | TSC_DEADLINE_TIMER_VECTOR; - apic_write(APIC_LVTT, lvtt); - start_tsc_deadline_timer(); - return 1; - } else { - return 0; - } -} - -static void test_tsc_deadline_timer(void) -{ - if(enable_tsc_deadline_timer()) { - printf("tsc deadline timer enabled\n"); - } else { - printf("tsc deadline timer not detected, aborting\n"); - abort(); - } -} - -int main(int argc, char **argv) -{ - int i, size; - - setup_vm(); - - test_lapic_existence(); - - mask_pic_interrupts(); - - delta = argc <= 1 ? 200000 : atol(argv[1]); - size = argc <= 2 ? TABLE_SIZE : atol(argv[2]); - breakmax = argc <= 3 ? 0 : atol(argv[3]); - printf("breakmax=%d\n", breakmax); - test_tsc_deadline_timer(); - irq_enable(); - - /* The condition might have triggered already, so check before HLT. */ - while (!hitmax && table_idx < size) - asm volatile("hlt"); - - for (i = 0; i < table_idx; i++) { - if (hitmax && i == table_idx-1) - printf("hit max: %d < ", breakmax); - printf("latency: %" PRId64 "\n", table[i]); - } - - return report_summary(); -} diff --git a/x86/tsx-ctrl.c b/x86/tsx-ctrl.c deleted file mode 100644 index 079ad593..00000000 --- a/x86/tsx-ctrl.c +++ /dev/null @@ -1,60 +0,0 @@ -/* TSX tests */ - -#include "libcflat.h" -#include "processor.h" -#include "msr.h" - -static bool try_transaction(void) -{ - unsigned x; - int i; - - for (i = 0; i < 100; i++) { - x = 0; - /* - * The value before the transaction is important, so make the - * operand input/output. - */ - asm volatile("xbegin 2f; movb $1, %0; xend; 2:" : "+m" (x) : : "eax"); - if (x) { - return true; - } - } - return false; -} - -int main(int ac, char **av) -{ - if (!this_cpu_has(X86_FEATURE_RTM)) { - report_skip("TSX not available"); - return 0; - } - if (!this_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) { - report_skip("ARCH_CAPABILITIES not available"); - return 0; - } - if (!(rdmsr(MSR_IA32_ARCH_CAPABILITIES) & ARCH_CAP_TSX_CTRL_MSR)) { - report_skip("TSX_CTRL not available"); - return 0; - } - - report(rdmsr(MSR_IA32_TSX_CTRL) == 0, "TSX_CTRL should be 0"); - report(try_transaction(), "Transactions do not abort"); - - wrmsr(MSR_IA32_TSX_CTRL, TSX_CTRL_CPUID_CLEAR); - report(!this_cpu_has(X86_FEATURE_RTM), "TSX_CTRL hides RTM"); - report(!this_cpu_has(X86_FEATURE_HLE), "TSX_CTRL hides HLE"); - - /* Microcode might hide HLE unconditionally */ - wrmsr(MSR_IA32_TSX_CTRL, 0); - report(this_cpu_has(X86_FEATURE_RTM), "TSX_CTRL=0 unhides RTM"); - - wrmsr(MSR_IA32_TSX_CTRL, TSX_CTRL_RTM_DISABLE); - report(!try_transaction(), "TSX_CTRL causes transactions to abort"); - - wrmsr(MSR_IA32_TSX_CTRL, 0); - report(try_transaction(), "TSX_CTRL=0 causes transactions to succeed"); - - return report_summary(); -} - diff --git a/x86/types.h b/x86/types.h deleted file mode 100644 index 047556e8..00000000 --- a/x86/types.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __TYPES_H -#define __TYPES_H - -#define DE_VECTOR 0 -#define DB_VECTOR 1 -#define NMI_VECTOR 2 -#define BP_VECTOR 3 -#define OF_VECTOR 4 -#define BR_VECTOR 5 -#define UD_VECTOR 6 -#define NM_VECTOR 7 -#define DF_VECTOR 8 -#define TS_VECTOR 10 -#define NP_VECTOR 11 -#define SS_VECTOR 12 -#define GP_VECTOR 13 -#define PF_VECTOR 14 -#define MF_VECTOR 16 -#define MC_VECTOR 18 - -#endif diff --git a/x86/umip.c b/x86/umip.c deleted file mode 100644 index c5700b32..00000000 --- a/x86/umip.c +++ /dev/null @@ -1,194 +0,0 @@ - -#include "libcflat.h" -#include "desc.h" -#include "processor.h" - - -/* GP handler to skip over faulting instructions */ - -static unsigned long expected_rip; -static int skip_count; -static volatile int gp_count; - -static void gp_handler(struct ex_regs *regs) -{ - if (regs->rip == expected_rip) { - gp_count++; - regs->rip += skip_count; - } else { - unhandled_exception(regs, false); - } -} - - -#define GP_ASM(stmt, in, clobber) \ - asm volatile ( \ - "mov" W " $1f, %[expected_rip]\n\t" \ - "movl $2f-1f, %[skip_count]\n\t" \ - "1: " stmt "\n\t" \ - "2: " \ - : [expected_rip] "=m" (expected_rip), \ - [skip_count] "=m" (skip_count) \ - : in : clobber) - -static void do_smsw(void) -{ - gp_count = 0; - GP_ASM("smsw %%ax", , "eax"); -} - -static void do_sldt(void) -{ - gp_count = 0; - GP_ASM("sldt %%ax", , "eax"); -} - -static void do_str(void) -{ - gp_count = 0; - GP_ASM("str %%ax", , "eax"); -} - -static void do_sgdt(void) -{ - struct descriptor_table_ptr dt; - gp_count = 0; - GP_ASM("sgdt %[dt]", [dt]"m"(dt), ); -} - -static void do_sidt(void) -{ - struct descriptor_table_ptr dt; - gp_count = 0; - GP_ASM("sidt %[dt]", [dt]"m"(dt), ); -} - -static void do_movcr(void) -{ - gp_count = 0; - GP_ASM("mov %%cr0, %%" R "ax", , "eax"); -} - -static void test_umip_nogp(const char *msg) -{ - puts(msg); - - do_smsw(); - report(gp_count == 0, "no exception from smsw"); - do_sgdt(); - report(gp_count == 0, "no exception from sgdt"); - do_sidt(); - report(gp_count == 0, "no exception from sidt"); - do_sldt(); - report(gp_count == 0, "no exception from sldt"); - do_str(); - report(gp_count == 0, "no exception from str"); - if (read_cs() & 3) { - do_movcr(); - report(gp_count == 1, "exception from mov %%cr0, %%eax"); - } -} - -static void test_umip_gp(const char *msg) -{ - puts(msg); - -#if 0 - /* Skip this, because it cannot be emulated correctly. */ - do_smsw(); - report(gp_count == 1, "exception from smsw"); -#endif - do_sgdt(); - report(gp_count == 1, "exception from sgdt"); - do_sidt(); - report(gp_count == 1, "exception from sidt"); - do_sldt(); - report(gp_count == 1, "exception from sldt"); - do_str(); - report(gp_count == 1, "exception from str"); - if (read_cs() & 3) { - do_movcr(); - report(gp_count == 1, "exception from mov %%cr0, %%eax"); - } -} - -/* The ugly mode switching code */ - -static int do_ring3(void (*fn)(const char *), const char *arg) -{ - static unsigned char user_stack[4096]; - int ret; - - asm volatile ("mov %[user_ds], %%" R "dx\n\t" - "mov %%dx, %%ds\n\t" - "mov %%dx, %%es\n\t" - "mov %%dx, %%fs\n\t" - "mov %%dx, %%gs\n\t" - "mov %%" R "sp, %%" R "cx\n\t" - "push" W " %%" R "dx \n\t" - "lea %[user_stack_top], %%" R "dx \n\t" - "push" W " %%" R "dx \n\t" - "pushf" W "\n\t" - "push" W " %[user_cs] \n\t" - "push" W " $1f \n\t" - "iret" W "\n" - "1: \n\t" - "push %%" R "cx\n\t" /* save kernel SP */ - -#ifndef __x86_64__ - "push %[arg]\n\t" -#endif - "call *%[fn]\n\t" -#ifndef __x86_64__ - "pop %%ecx\n\t" -#endif - - "pop %%" R "cx\n\t" - "mov $1f, %%" R "dx\n\t" - "int %[kernel_entry_vector]\n\t" - ".section .text.entry \n\t" - "kernel_entry: \n\t" - "mov %%" R "cx, %%" R "sp \n\t" - "mov %[kernel_ds], %%cx\n\t" - "mov %%cx, %%ds\n\t" - "mov %%cx, %%es\n\t" - "mov %%cx, %%fs\n\t" - "mov %%cx, %%gs\n\t" - "jmp *%%" R "dx \n\t" - ".section .text\n\t" - "1:\n\t" - : [ret] "=&a" (ret) - : [user_ds] "i" (USER_DS), - [user_cs] "i" (USER_CS), - [user_stack_top]"m"(user_stack[sizeof(user_stack) - - sizeof(long)]), - [fn]"r"(fn), - [arg]"D"(arg), - [kernel_ds]"i"(KERNEL_DS), - [kernel_entry_vector]"i"(0x20) - : "rcx", "rdx"); - return ret; -} - -int main(void) -{ - extern unsigned char kernel_entry; - - set_idt_entry(0x20, &kernel_entry, 3); - handle_exception(13, gp_handler); - set_iopl(3); - - test_umip_nogp("UMIP=0, CPL=0\n"); - do_ring3(test_umip_nogp, "UMIP=0, CPL=3\n"); - - if (!this_cpu_has(X86_FEATURE_UMIP)) { - printf("UMIP not available\n"); - return report_summary(); - } - write_cr4(read_cr4() | X86_CR4_UMIP); - - test_umip_nogp("UMIP=1, CPL=0\n"); - do_ring3(test_umip_gp, "UMIP=1, CPL=3\n"); - - return report_summary(); -} diff --git a/x86/unittests.cfg b/x86/unittests.cfg deleted file mode 100644 index 3a791514..00000000 --- a/x86/unittests.cfg +++ /dev/null @@ -1,349 +0,0 @@ -############################################################################## -# unittest configuration -# -# [unittest_name] -# file = .flat # Name of the flat file to be used. -# smp = # Number of processors the VM will use -# # during this test. Use $MAX_SMP to use -# # the maximum the host supports. Defaults -# # to one. -# extra_params = -append # Additional parameters used. -# arch = i386|x86_64 # Select one if the test case is -# # specific to only one. -# groups = ... # Used to identify test cases -# # with run_tests -g ... -# # Specify group_name=nodefault -# # to have test not run by -# # default -# accel = kvm|tcg # Optionally specify if test must run with -# # kvm or tcg. If not specified, then kvm will -# # be used when available. -# timeout = # Optionally specify a timeout. -# check = = # check a file for a particular value before running -# # a test. The check line can contain multiple files -# # to check separated by a space but each check -# # parameter needs to be of the form = -############################################################################## - -[apic-split] -file = apic.flat -smp = 2 -extra_params = -cpu qemu64,+x2apic,+tsc-deadline -machine kernel_irqchip=split -arch = x86_64 - -[ioapic-split] -file = ioapic.flat -extra_params = -cpu qemu64 -machine kernel_irqchip=split -arch = x86_64 - -[apic] -file = apic.flat -smp = 2 -extra_params = -cpu qemu64,+x2apic,+tsc-deadline -arch = x86_64 -timeout = 30 - -[ioapic] -file = ioapic.flat -smp = 4 -extra_params = -cpu qemu64,+x2apic -arch = x86_64 - -[cmpxchg8b] -file = cmpxchg8b.flat -arch = i386 - -[smptest] -file = smptest.flat -smp = 2 - -[smptest3] -file = smptest.flat -smp = 3 - -[vmexit_cpuid] -file = vmexit.flat -extra_params = -append 'cpuid' -groups = vmexit - -[vmexit_vmcall] -file = vmexit.flat -extra_params = -append 'vmcall' -groups = vmexit - -[vmexit_mov_from_cr8] -file = vmexit.flat -extra_params = -append 'mov_from_cr8' -groups = vmexit - -[vmexit_mov_to_cr8] -file = vmexit.flat -extra_params = -append 'mov_to_cr8' -groups = vmexit - -[vmexit_inl_pmtimer] -file = vmexit.flat -extra_params = -append 'inl_from_pmtimer' -groups = vmexit - -[vmexit_ipi] -file = vmexit.flat -smp = 2 -extra_params = -append 'ipi' -groups = vmexit - -[vmexit_ipi_halt] -file = vmexit.flat -smp = 2 -extra_params = -append 'ipi_halt' -groups = vmexit - -[vmexit_ple_round_robin] -file = vmexit.flat -extra_params = -append 'ple_round_robin' -groups = vmexit - -[vmexit_tscdeadline] -file = vmexit.flat -groups = vmexit -extra_params = -cpu qemu64,+x2apic,+tsc-deadline -append tscdeadline - -[vmexit_tscdeadline_immed] -file = vmexit.flat -groups = vmexit -extra_params = -cpu qemu64,+x2apic,+tsc-deadline -append tscdeadline_immed - -[access] -file = access.flat -arch = x86_64 -extra_params = -cpu host,host-phys-bits - -[smap] -file = smap.flat -extra_params = -cpu host - -[pku] -file = pku.flat -arch = x86_64 -extra_params = -cpu host - -[asyncpf] -file = asyncpf.flat -extra_params = -m 2048 - -[emulator] -file = emulator.flat -arch = x86_64 - -[eventinj] -file = eventinj.flat - -[hypercall] -file = hypercall.flat - -[idt_test] -file = idt_test.flat -arch = x86_64 - -#[init] -#file = init.flat - -[memory] -file = memory.flat -extra_params = -cpu host -arch = x86_64 - -[msr] -file = msr.flat - -[pmu] -file = pmu.flat -extra_params = -cpu host -check = /proc/sys/kernel/nmi_watchdog=0 - -[vmware_backdoors] -file = vmware_backdoors.flat -extra_params = -machine vmport=on -cpu host -check = /sys/module/kvm/parameters/enable_vmware_backdoor=Y -arch = x86_64 - -[port80] -file = port80.flat - -[realmode] -file = realmode.flat - -[s3] -file = s3.flat - -[setjmp] -file = setjmp.flat - -[sieve] -file = sieve.flat -timeout = 180 - -[syscall] -file = syscall.flat -arch = x86_64 -extra_params = -cpu Opteron_G1,vendor=AuthenticAMD - -[tsc] -file = tsc.flat -extra_params = -cpu kvm64,+rdtscp - -[tsc_adjust] -file = tsc_adjust.flat -extra_params = -cpu host - -[xsave] -file = xsave.flat -arch = x86_64 -extra_params = -cpu host - -[rmap_chain] -file = rmap_chain.flat -arch = x86_64 - -[svm] -file = svm.flat -smp = 2 -extra_params = -cpu host,+svm -arch = x86_64 - -[taskswitch] -file = taskswitch.flat -arch = i386 -groups = tasks - -[taskswitch2] -file = taskswitch2.flat -arch = i386 -groups = tasks - -[kvmclock_test] -file = kvmclock_test.flat -smp = 2 -extra_params = --append "10000000 `date +%s`" - -[pcid] -file = pcid.flat -extra_params = -cpu qemu64,+pcid,+invpcid -arch = x86_64 - -[pcid-disabled] -file = pcid.flat -extra_params = -cpu qemu64,-pcid,-invpcid -arch = x86_64 - -[rdpru] -file = rdpru.flat -extra_params = -cpu host -arch = x86_64 - -[umip] -file = umip.flat -extra_params = -cpu qemu64,+umip - -[vmx] -file = vmx.flat -extra_params = -cpu host,+vmx -append "-exit_monitor_from_l2_test -ept_access* -vmx_smp* -vmx_vmcs_shadow_test -atomic_switch_overflow_msrs_test -vmx_init_signal_test -vmx_apic_passthrough_tpr_threshold_test" -arch = x86_64 -groups = vmx - -[ept] -file = vmx.flat -extra_params = -cpu host,host-phys-bits,+vmx -m 2560 -append "ept_access*" -arch = x86_64 -groups = vmx - -[vmx_eoi_bitmap_ioapic_scan] -file = vmx.flat -smp = 2 -extra_params = -cpu host,+vmx -m 2048 -append vmx_eoi_bitmap_ioapic_scan_test -arch = x86_64 -groups = vmx - -[vmx_hlt_with_rvi_test] -file = vmx.flat -extra_params = -cpu host,+vmx -append vmx_hlt_with_rvi_test -arch = x86_64 -groups = vmx -timeout = 10 - -[vmx_apicv_test] -file = vmx.flat -extra_params = -cpu host,+vmx -append "apic_reg_virt_test virt_x2apic_mode_test" -arch = x86_64 -groups = vmx -timeout = 10 - -[vmx_apic_passthrough_thread] -file = vmx.flat -smp = 2 -extra_params = -cpu host,+vmx -m 2048 -append vmx_apic_passthrough_thread_test -arch = x86_64 -groups = vmx - -[vmx_init_signal_test] -file = vmx.flat -smp = 2 -extra_params = -cpu host,+vmx -m 2048 -append vmx_init_signal_test -arch = x86_64 -groups = vmx -timeout = 10 - -[vmx_apic_passthrough_tpr_threshold_test] -file = vmx.flat -extra_params = -cpu host,+vmx -m 2048 -append vmx_apic_passthrough_tpr_threshold_test -arch = x86_64 -groups = vmx -timeout = 10 - -[vmx_vmcs_shadow_test] -file = vmx.flat -extra_params = -cpu host,+vmx -append vmx_vmcs_shadow_test -arch = x86_64 -groups = vmx - -[debug] -file = debug.flat -arch = x86_64 - -[hyperv_synic] -file = hyperv_synic.flat -smp = 2 -extra_params = -cpu kvm64,hv_vpindex,hv_synic -device hyperv-testdev -groups = hyperv - -[hyperv_connections] -file = hyperv_connections.flat -smp = 2 -extra_params = -cpu kvm64,hv_vpindex,hv_synic -device hyperv-testdev -groups = hyperv - -[hyperv_stimer] -file = hyperv_stimer.flat -smp = 2 -extra_params = -cpu kvm64,hv_vpindex,hv_time,hv_synic,hv_stimer -device hyperv-testdev -groups = hyperv - -[hyperv_clock] -file = hyperv_clock.flat -smp = 2 -extra_params = -cpu kvm64,hv_time -arch = x86_64 -groups = hyperv -check = /sys/devices/system/clocksource/clocksource0/current_clocksource=tsc - -[intel_iommu] -file = intel-iommu.flat -arch = x86_64 -timeout = 30 -smp = 4 -extra_params = -M q35,kernel-irqchip=split -device intel-iommu,intremap=on,eim=off -device edu - -[tsx-ctrl] -file = tsx-ctrl.flat -extra_params = -cpu host -groups = tsx-ctrl diff --git a/x86/vmexit.c b/x86/vmexit.c deleted file mode 100644 index 47efb636..00000000 --- a/x86/vmexit.c +++ /dev/null @@ -1,608 +0,0 @@ -#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_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; -volatile uint64_t tsc_eoi = 0; -volatile uint64_t tsc_ipi = 0; - -static void self_ipi_isr(isr_regs_t *regs) -{ - x++; - uint64_t start = rdtsc(); - eoi(); - tsc_eoi += rdtsc() - start; -} - -static void x2apic_self_ipi(int vec) -{ - uint64_t start = rdtsc(); - wrmsr(0x83f, vec); - tsc_ipi += rdtsc() - start; -} - -static void apic_self_ipi(int vec) -{ - uint64_t start = rdtsc(); - apic_icr_write(APIC_INT_ASSERT | APIC_DEST_SELF | APIC_DEST_PHYSICAL | - APIC_DM_FIXED | IPI_TEST_VECTOR, vec); - tsc_ipi += rdtsc() - start; -} - -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) -{ - uint64_t start = rdtsc(); - on_cpu(1, nop, 0); - tsc_ipi += rdtsc() - start; -} - -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) -{ - if (!pm_tmr_blk) { - struct fadt_descriptor_rev1 *fadt; - - fadt = find_acpi_table_addr(FACP_SIGNATURE); - pm_tmr_blk = fadt->pm_tmr_blk; - printf("PM timer port is %x\n", pm_tmr_blk); - } - 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_IA32_TSC_ADJUST); -} - -static void wr_tsc_adjust_msr(void) -{ - wrmsr(MSR_IA32_TSC_ADJUST, 0x0); -} - -static void wr_kernel_gs_base(void) -{ - wrmsr(MSR_KERNEL_GS_BASE, 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 (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) { - 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 void wr_tsx_ctrl_msr(void) -{ - wrmsr(MSR_IA32_TSX_CTRL, 0); -} - -static int has_tsx_ctrl(void) -{ - return this_cpu_has(X86_FEATURE_ARCH_CAPABILITIES) - && (rdmsr(MSR_IA32_ARCH_CAPABILITIES) & ARCH_CAP_TSX_CTRL_MSR); -} - -static void wr_ibrs_msr(void) -{ - wrmsr(MSR_IA32_SPEC_CTRL, 1); - wrmsr(MSR_IA32_SPEC_CTRL, 0); -} - -static int has_ibpb(void) -{ - return has_spec_ctrl() || !!(this_cpu_has(X86_FEATURE_AMD_IBPB)); -} - -static void wr_ibpb_msr(void) -{ - wrmsr(MSR_IA32_PRED_CMD, 1); -} - -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_kernel_gs_base, "wr_kernel_gs_base", .parallel = 1 }, - { wr_tsx_ctrl_msr, "wr_tsx_ctrl_msr", has_tsx_ctrl, .parallel = 1, }, - { wr_ibrs_msr, "wr_ibrs_msr", has_spec_ctrl, .parallel = 1 }, - { wr_ibpb_msr, "wr_ibpb_msr", has_ibpb, .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 { - tsc_eoi = tsc_ipi = 0; - 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)); - if (tsc_ipi) - printf(" ipi %s %d\n", test->name, (int)(tsc_ipi / iterations)); - if (tsc_eoi) - printf(" eoi %s %d\n", test->name, (int)(tsc_eoi / iterations)); - - return test->next; -} - -static void enable_nx(void *junk) -{ - if (this_cpu_has(X86_FEATURE_NX)) - wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK); -} - -static 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) -{ - int i; - unsigned long membar = 0; - struct pci_dev pcidev; - int ret; - - setup_vm(); - handle_irq(IPI_TEST_VECTOR, self_ipi_isr); - nr_cpus = cpu_count(); - - irq_enable(); - on_cpus(enable_nx, NULL); - - 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; -} diff --git a/x86/vmware_backdoors.c b/x86/vmware_backdoors.c deleted file mode 100644 index b4902a90..00000000 --- a/x86/vmware_backdoors.c +++ /dev/null @@ -1,190 +0,0 @@ - -#include "x86/msr.h" -#include "x86/processor.h" -#include "x86/apic-defs.h" -#include "x86/apic.h" -#include "x86/desc.h" -#include "x86/isr.h" -#include "alloc.h" -#include "setjmp.h" -#include "usermode.h" -#include "fault_test.h" - -#include "libcflat.h" -#include - -#define VMWARE_BACKDOOR_PMC_HOST_TSC 0x10000 -#define VMWARE_BACKDOOR_PMC_REAL_TIME 0x10001 -#define VMWARE_BACKDOOR_PMC_APPARENT_TIME 0x10002 - -#define VMWARE_BACKDOOR_PORT 0x5658 -#define VMWARE_MAGIC 0x564D5868 - -#define VMPORT_CMD_GETVERSION 0x0a -#define VMPORT_CMD_ILLEGAL 0xfff - -#define VMPORT_DEFAULT_RETVAL 0xdeadbeef - -#define RANDOM_IO_PORT 0x1234 - -struct backdoor_port_result { - uint64_t rax; - uint64_t rbx; - uint64_t rcx; - uint64_t rdx; -}; - -static bool vmware_backdoor_port_callback(struct fault_test_arg *arg) -{ - struct backdoor_port_result *res = - (struct backdoor_port_result *) arg->retval; - - switch (arg->arg[2]) { - case VMPORT_CMD_GETVERSION: - return (res->rbx == VMWARE_MAGIC); - case VMPORT_CMD_ILLEGAL: - return (res->rbx == VMPORT_DEFAULT_RETVAL); - } - return false; -} - -static uint64_t vmware_backdoor_port(uint64_t vmport, uint64_t vmport_magic, - uint64_t command) -{ - struct backdoor_port_result *res = - (struct backdoor_port_result *) - malloc(sizeof(struct backdoor_port_result)); - - res->rax = VMPORT_DEFAULT_RETVAL; - res->rbx = VMPORT_DEFAULT_RETVAL; - res->rcx = VMPORT_DEFAULT_RETVAL; - res->rdx = VMPORT_DEFAULT_RETVAL; - - asm volatile( - "mov %[rax], %%rax\n\t" - "mov %[rdx], %%rdx\n\t" - "mov %[rcx], %%rcx\n\t" - "inl %%dx, %%eax\n\t" - : - "+a"(res->rax), - "+b"(res->rbx), - "+c"(res->rcx), - "+d"(res->rdx) - : - [rax]"m"(vmport_magic), - [rdx]"m"(vmport), - [rcx]"m"(command) - ); - - return (uint64_t) res; -} - -#define FAULT true -#define NO_FAULT false -#define USER_MODE true -#define KERNEL_MODE false - -#define RDPMC_ARG(n, m, sf) {.usermode = m, \ - .func = (test_fault_func) rdpmc, .fault_vector = GP_VECTOR, \ - .should_fault = sf, .arg = {n, 0, 0, 0}, .callback = NULL} - -#define RDPMC_TEST(name, a, m, sf) FAULT_TEST("rdpmc_test: "name, \ - RDPMC_ARG(a, m, sf)) - -#define PORT_ARG(a, b, c, m, sf) {.usermode = m, \ - .func = (test_fault_func) vmware_backdoor_port, \ - .fault_vector = GP_VECTOR, .should_fault = sf, .arg = {a, b, c, 0}, \ - .callback = vmware_backdoor_port_callback} - -#define PORT_TEST(name, a, b, c, m, sf) FAULT_TEST("port_test: "name, \ - PORT_ARG(a, b, c, m, sf)) - - -struct fault_test vmware_backdoor_tests[] = { - RDPMC_TEST("HOST_TSC kernel", VMWARE_BACKDOOR_PMC_HOST_TSC, - KERNEL_MODE, NO_FAULT), - RDPMC_TEST("REAL_TIME kernel", VMWARE_BACKDOOR_PMC_REAL_TIME, - KERNEL_MODE, NO_FAULT), - RDPMC_TEST("APPARENT_TIME kernel", VMWARE_BACKDOOR_PMC_APPARENT_TIME, - KERNEL_MODE, NO_FAULT), - RDPMC_TEST("HOST_TSC user", VMWARE_BACKDOOR_PMC_HOST_TSC, - USER_MODE, NO_FAULT), - RDPMC_TEST("REAL_TIME user", VMWARE_BACKDOOR_PMC_REAL_TIME, - USER_MODE, NO_FAULT), - RDPMC_TEST("APPARENT_TIME user", VMWARE_BACKDOOR_PMC_APPARENT_TIME, - USER_MODE, NO_FAULT), - RDPMC_TEST("RANDOM PMC user", 0xfff, USER_MODE, FAULT), - - PORT_TEST("CMD_GETVERSION user", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC, - VMPORT_CMD_GETVERSION, USER_MODE, NO_FAULT), - PORT_TEST("CMD_GETVERSION kernel", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC, - VMPORT_CMD_GETVERSION, KERNEL_MODE, NO_FAULT), - PORT_TEST("CMD_ILLEGAL user", VMWARE_BACKDOOR_PORT, VMWARE_MAGIC, - VMPORT_CMD_ILLEGAL, USER_MODE, NO_FAULT), - PORT_TEST("RANDOM port user", RANDOM_IO_PORT, VMWARE_MAGIC, 0xfff, - USER_MODE, FAULT), - { NULL }, -}; - -/* - * Set TSS IO Perm to throw GP on RANDOM_IO_PORT and VMWARE_BACKDOOR_PORT - * from User Mode - */ -static void set_tss_ioperm(void) -{ - struct descriptor_table_ptr gdt; - struct segment_desc64 *gdt_table; - struct segment_desc64 *tss_entry; - u16 tr = 0; - tss64_t *tss; - unsigned char *ioperm_bitmap; - uint64_t tss_base; - - sgdt(&gdt); - tr = str(); - gdt_table = (struct segment_desc64 *) gdt.base; - tss_entry = &gdt_table[tr / sizeof(struct segment_desc64)]; - tss_base = ((uint64_t) tss_entry->base1 | - ((uint64_t) tss_entry->base2 << 16) | - ((uint64_t) tss_entry->base3 << 24) | - ((uint64_t) tss_entry->base4 << 32)); - tss = (tss64_t *)tss_base; - tss->iomap_base = sizeof(*tss); - ioperm_bitmap = ((unsigned char *)tss+tss->iomap_base); - - /* We want GP on RANDOM_IO_PORT and VMWARE_BACKDOOR_PORT */ - ioperm_bitmap[RANDOM_IO_PORT / 8] |= - 1 << (RANDOM_IO_PORT % 8); - ioperm_bitmap[VMWARE_BACKDOOR_PORT / 8] |= - 1 << (VMWARE_BACKDOOR_PORT % 8); - *(uint64_t *)tss_entry &= ~DESC_BUSY; - - /* Update TSS */ - ltr(tr); -} - -static void check_vmware_backdoors(void) -{ - int i; - - /* Disable Permissions for IO PORTS */ - set_tss_ioperm(); - /* Disable Permission to run rdpmc from user mode */ - write_cr4(read_cr4() & ~X86_CR4_PCE); - - report_prefix_push("vmware_backdoors"); - - for (i = 0; vmware_backdoor_tests[i].name != NULL; i++) - test_run(&vmware_backdoor_tests[i]); - - report_prefix_pop(); -} - -int main(int ac, char **av) -{ - setup_vm(); - - check_vmware_backdoors(); - - return report_summary(); -} diff --git a/x86/vmx.c b/x86/vmx.c deleted file mode 100644 index 07415b4d..00000000 --- a/x86/vmx.c +++ /dev/null @@ -1,2165 +0,0 @@ -/* - * x86/vmx.c : Framework for testing nested virtualization - * This is a framework to test nested VMX for KVM, which - * started as a project of GSoC 2013. All test cases should - * be located in x86/vmx_tests.c and framework related - * functions should be in this file. - * - * How to write test cases? - * Add callbacks of test suite in variant "vmx_tests". You can - * write: - * 1. init function used for initializing test suite - * 2. main function for codes running in L2 guest, - * 3. exit_handler to handle vmexit of L2 to L1 - * 4. syscall handler to handle L2 syscall vmexit - * 5. vmenter fail handler to handle direct failure of vmenter - * 6. guest_regs is loaded when vmenter and saved when - * vmexit, you can read and set it in exit_handler - * If no special function is needed for a test suite, use - * coressponding basic_* functions as callback. More handlers - * can be added to "vmx_tests", see details of "struct vmx_test" - * and function test_run(). - * - * Currently, vmx test framework only set up one VCPU and one - * concurrent guest test environment with same paging for L2 and - * L1. For usage of EPT, only 1:1 mapped paging is used from VFN - * to PFN. - * - * Author : Arthur Chunqi Li - */ - -#include "libcflat.h" -#include "processor.h" -#include "alloc_page.h" -#include "vm.h" -#include "vmalloc.h" -#include "desc.h" -#include "vmx.h" -#include "msr.h" -#include "smp.h" -#include "apic.h" - -u64 *bsp_vmxon_region; -struct vmcs *vmcs_root; -u32 vpid_cnt; -void *guest_stack, *guest_syscall_stack; -u32 ctrl_pin, ctrl_enter, ctrl_exit, ctrl_cpu[2]; -struct regs regs; - -struct vmx_test *current; - -#define MAX_TEST_TEARDOWN_STEPS 10 - -struct test_teardown_step { - test_teardown_func func; - void *data; -}; - -static int teardown_count; -static struct test_teardown_step teardown_steps[MAX_TEST_TEARDOWN_STEPS]; - -static test_guest_func v2_guest_main; - -u64 hypercall_field; -bool launched; -static int matched; -static int guest_finished; -static int in_guest; - -union vmx_basic basic; -union vmx_ctrl_msr ctrl_pin_rev; -union vmx_ctrl_msr ctrl_cpu_rev[2]; -union vmx_ctrl_msr ctrl_exit_rev; -union vmx_ctrl_msr ctrl_enter_rev; -union vmx_ept_vpid ept_vpid; - -extern struct descriptor_table_ptr gdt64_desc; -extern struct descriptor_table_ptr idt_descr; -extern struct descriptor_table_ptr tss_descr; -extern void *vmx_return; -extern void *entry_sysenter; -extern void *guest_entry; - -static volatile u32 stage; - -static jmp_buf abort_target; - -struct vmcs_field { - u64 mask; - u64 encoding; -}; - -#define MASK(_bits) GENMASK_ULL((_bits) - 1, 0) -#define MASK_NATURAL MASK(sizeof(unsigned long) * 8) - -static struct vmcs_field vmcs_fields[] = { - { MASK(16), VPID }, - { MASK(16), PINV }, - { MASK(16), EPTP_IDX }, - - { MASK(16), GUEST_SEL_ES }, - { MASK(16), GUEST_SEL_CS }, - { MASK(16), GUEST_SEL_SS }, - { MASK(16), GUEST_SEL_DS }, - { MASK(16), GUEST_SEL_FS }, - { MASK(16), GUEST_SEL_GS }, - { MASK(16), GUEST_SEL_LDTR }, - { MASK(16), GUEST_SEL_TR }, - { MASK(16), GUEST_INT_STATUS }, - - { MASK(16), HOST_SEL_ES }, - { MASK(16), HOST_SEL_CS }, - { MASK(16), HOST_SEL_SS }, - { MASK(16), HOST_SEL_DS }, - { MASK(16), HOST_SEL_FS }, - { MASK(16), HOST_SEL_GS }, - { MASK(16), HOST_SEL_TR }, - - { MASK(64), IO_BITMAP_A }, - { MASK(64), IO_BITMAP_B }, - { MASK(64), MSR_BITMAP }, - { MASK(64), EXIT_MSR_ST_ADDR }, - { MASK(64), EXIT_MSR_LD_ADDR }, - { MASK(64), ENTER_MSR_LD_ADDR }, - { MASK(64), VMCS_EXEC_PTR }, - { MASK(64), TSC_OFFSET }, - { MASK(64), APIC_VIRT_ADDR }, - { MASK(64), APIC_ACCS_ADDR }, - { MASK(64), EPTP }, - - { MASK(64), INFO_PHYS_ADDR }, - - { MASK(64), VMCS_LINK_PTR }, - { MASK(64), GUEST_DEBUGCTL }, - { MASK(64), GUEST_EFER }, - { MASK(64), GUEST_PAT }, - { MASK(64), GUEST_PERF_GLOBAL_CTRL }, - { MASK(64), GUEST_PDPTE }, - - { MASK(64), HOST_PAT }, - { MASK(64), HOST_EFER }, - { MASK(64), HOST_PERF_GLOBAL_CTRL }, - - { MASK(32), PIN_CONTROLS }, - { MASK(32), CPU_EXEC_CTRL0 }, - { MASK(32), EXC_BITMAP }, - { MASK(32), PF_ERROR_MASK }, - { MASK(32), PF_ERROR_MATCH }, - { MASK(32), CR3_TARGET_COUNT }, - { MASK(32), EXI_CONTROLS }, - { MASK(32), EXI_MSR_ST_CNT }, - { MASK(32), EXI_MSR_LD_CNT }, - { MASK(32), ENT_CONTROLS }, - { MASK(32), ENT_MSR_LD_CNT }, - { MASK(32), ENT_INTR_INFO }, - { MASK(32), ENT_INTR_ERROR }, - { MASK(32), ENT_INST_LEN }, - { MASK(32), TPR_THRESHOLD }, - { MASK(32), CPU_EXEC_CTRL1 }, - - { MASK(32), VMX_INST_ERROR }, - { MASK(32), EXI_REASON }, - { MASK(32), EXI_INTR_INFO }, - { MASK(32), EXI_INTR_ERROR }, - { MASK(32), IDT_VECT_INFO }, - { MASK(32), IDT_VECT_ERROR }, - { MASK(32), EXI_INST_LEN }, - { MASK(32), EXI_INST_INFO }, - - { MASK(32), GUEST_LIMIT_ES }, - { MASK(32), GUEST_LIMIT_CS }, - { MASK(32), GUEST_LIMIT_SS }, - { MASK(32), GUEST_LIMIT_DS }, - { MASK(32), GUEST_LIMIT_FS }, - { MASK(32), GUEST_LIMIT_GS }, - { MASK(32), GUEST_LIMIT_LDTR }, - { MASK(32), GUEST_LIMIT_TR }, - { MASK(32), GUEST_LIMIT_GDTR }, - { MASK(32), GUEST_LIMIT_IDTR }, - { 0x1d0ff, GUEST_AR_ES }, - { 0x1f0ff, GUEST_AR_CS }, - { 0x1d0ff, GUEST_AR_SS }, - { 0x1d0ff, GUEST_AR_DS }, - { 0x1d0ff, GUEST_AR_FS }, - { 0x1d0ff, GUEST_AR_GS }, - { 0x1d0ff, GUEST_AR_LDTR }, - { 0x1d0ff, GUEST_AR_TR }, - { MASK(32), GUEST_INTR_STATE }, - { MASK(32), GUEST_ACTV_STATE }, - { MASK(32), GUEST_SMBASE }, - { MASK(32), GUEST_SYSENTER_CS }, - { MASK(32), PREEMPT_TIMER_VALUE }, - - { MASK(32), HOST_SYSENTER_CS }, - - { MASK_NATURAL, CR0_MASK }, - { MASK_NATURAL, CR4_MASK }, - { MASK_NATURAL, CR0_READ_SHADOW }, - { MASK_NATURAL, CR4_READ_SHADOW }, - { MASK_NATURAL, CR3_TARGET_0 }, - { MASK_NATURAL, CR3_TARGET_1 }, - { MASK_NATURAL, CR3_TARGET_2 }, - { MASK_NATURAL, CR3_TARGET_3 }, - - { MASK_NATURAL, EXI_QUALIFICATION }, - { MASK_NATURAL, IO_RCX }, - { MASK_NATURAL, IO_RSI }, - { MASK_NATURAL, IO_RDI }, - { MASK_NATURAL, IO_RIP }, - { MASK_NATURAL, GUEST_LINEAR_ADDRESS }, - - { MASK_NATURAL, GUEST_CR0 }, - { MASK_NATURAL, GUEST_CR3 }, - { MASK_NATURAL, GUEST_CR4 }, - { MASK_NATURAL, GUEST_BASE_ES }, - { MASK_NATURAL, GUEST_BASE_CS }, - { MASK_NATURAL, GUEST_BASE_SS }, - { MASK_NATURAL, GUEST_BASE_DS }, - { MASK_NATURAL, GUEST_BASE_FS }, - { MASK_NATURAL, GUEST_BASE_GS }, - { MASK_NATURAL, GUEST_BASE_LDTR }, - { MASK_NATURAL, GUEST_BASE_TR }, - { MASK_NATURAL, GUEST_BASE_GDTR }, - { MASK_NATURAL, GUEST_BASE_IDTR }, - { MASK_NATURAL, GUEST_DR7 }, - { MASK_NATURAL, GUEST_RSP }, - { MASK_NATURAL, GUEST_RIP }, - { MASK_NATURAL, GUEST_RFLAGS }, - { MASK_NATURAL, GUEST_PENDING_DEBUG }, - { MASK_NATURAL, GUEST_SYSENTER_ESP }, - { MASK_NATURAL, GUEST_SYSENTER_EIP }, - - { MASK_NATURAL, HOST_CR0 }, - { MASK_NATURAL, HOST_CR3 }, - { MASK_NATURAL, HOST_CR4 }, - { MASK_NATURAL, HOST_BASE_FS }, - { MASK_NATURAL, HOST_BASE_GS }, - { MASK_NATURAL, HOST_BASE_TR }, - { MASK_NATURAL, HOST_BASE_GDTR }, - { MASK_NATURAL, HOST_BASE_IDTR }, - { MASK_NATURAL, HOST_SYSENTER_ESP }, - { MASK_NATURAL, HOST_SYSENTER_EIP }, - { MASK_NATURAL, HOST_RSP }, - { MASK_NATURAL, HOST_RIP }, -}; - -enum vmcs_field_type { - VMCS_FIELD_TYPE_CONTROL = 0, - VMCS_FIELD_TYPE_READ_ONLY_DATA = 1, - VMCS_FIELD_TYPE_GUEST = 2, - VMCS_FIELD_TYPE_HOST = 3, - VMCS_FIELD_TYPES, -}; - -static inline int vmcs_field_type(struct vmcs_field *f) -{ - return (f->encoding >> VMCS_FIELD_TYPE_SHIFT) & 0x3; -} - -static int vmcs_field_readonly(struct vmcs_field *f) -{ - u64 ia32_vmx_misc; - - ia32_vmx_misc = rdmsr(MSR_IA32_VMX_MISC); - return !(ia32_vmx_misc & MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS) && - (vmcs_field_type(f) == VMCS_FIELD_TYPE_READ_ONLY_DATA); -} - -static inline u64 vmcs_field_value(struct vmcs_field *f, u8 cookie) -{ - u64 value; - - /* Incorporate the cookie and the field encoding into the value. */ - value = cookie; - value |= (f->encoding << 8); - value |= 0xdeadbeefull << 32; - - return value & f->mask; -} - -static void set_vmcs_field(struct vmcs_field *f, u8 cookie) -{ - vmcs_write(f->encoding, vmcs_field_value(f, cookie)); -} - -static bool check_vmcs_field(struct vmcs_field *f, u8 cookie) -{ - u64 expected; - u64 actual; - int ret; - - if (f->encoding == VMX_INST_ERROR) { - printf("Skipping volatile field %lx\n", f->encoding); - return true; - } - - ret = vmcs_read_checking(f->encoding, &actual); - assert(!(ret & X86_EFLAGS_CF)); - /* Skip VMCS fields that aren't recognized by the CPU */ - if (ret & X86_EFLAGS_ZF) - return true; - - if (vmcs_field_readonly(f)) { - printf("Skipping read-only field %lx\n", f->encoding); - return true; - } - - expected = vmcs_field_value(f, cookie); - actual &= f->mask; - - if (expected == actual) - return true; - - printf("FAIL: VMWRITE/VMREAD %lx (expected: %lx, actual: %lx)\n", - f->encoding, (unsigned long) expected, (unsigned long) actual); - - return false; -} - -static void set_all_vmcs_fields(u8 cookie) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(vmcs_fields); i++) - set_vmcs_field(&vmcs_fields[i], cookie); -} - -static bool check_all_vmcs_fields(u8 cookie) -{ - bool pass = true; - int i; - - for (i = 0; i < ARRAY_SIZE(vmcs_fields); i++) { - if (!check_vmcs_field(&vmcs_fields[i], cookie)) - pass = false; - } - - return pass; -} - -static u32 find_vmcs_max_index(void) -{ - u32 idx, width, type, enc; - u64 actual; - int ret; - - /* scan backwards and stop when found */ - for (idx = (1 << 9) - 1; idx >= 0; idx--) { - - /* try all combinations of width and type */ - for (type = 0; type < (1 << 2); type++) { - for (width = 0; width < (1 << 2) ; width++) { - enc = (idx << VMCS_FIELD_INDEX_SHIFT) | - (type << VMCS_FIELD_TYPE_SHIFT) | - (width << VMCS_FIELD_WIDTH_SHIFT); - - ret = vmcs_read_checking(enc, &actual); - assert(!(ret & X86_EFLAGS_CF)); - if (!(ret & X86_EFLAGS_ZF)) - return idx; - } - } - } - /* some VMCS fields should exist */ - assert(0); - return 0; -} - -static void test_vmwrite_vmread(void) -{ - struct vmcs *vmcs = alloc_page(); - u32 vmcs_enum_max, max_index = 0; - - vmcs->hdr.revision_id = basic.revision; - assert(!vmcs_clear(vmcs)); - assert(!make_vmcs_current(vmcs)); - - set_all_vmcs_fields(0x42); - report(check_all_vmcs_fields(0x42), "VMWRITE/VMREAD"); - - vmcs_enum_max = (rdmsr(MSR_IA32_VMX_VMCS_ENUM) & VMCS_FIELD_INDEX_MASK) - >> VMCS_FIELD_INDEX_SHIFT; - max_index = find_vmcs_max_index(); - report(vmcs_enum_max == max_index, - "VMX_VMCS_ENUM.MAX_INDEX expected: %x, actual: %x", - max_index, vmcs_enum_max); - - assert(!vmcs_clear(vmcs)); - free_page(vmcs); -} - -ulong finish_fault; -u8 sentinel; -bool handler_called; - -static void pf_handler(struct ex_regs *regs) -{ - /* - * check that RIP was not improperly advanced and that the - * flags value was preserved. - */ - report(regs->rip < finish_fault, "RIP has not been advanced!"); - report(((u8)regs->rflags == ((sentinel | 2) & 0xd7)), - "The low byte of RFLAGS was preserved!"); - regs->rip = finish_fault; - handler_called = true; - -} - -static void prep_flags_test_env(void **vpage, struct vmcs **vmcs, handler *old) -{ - /* - * get an unbacked address that will cause a #PF - */ - *vpage = alloc_vpage(); - - /* - * set up VMCS so we have something to read from - */ - *vmcs = alloc_page(); - - memset(*vmcs, 0, PAGE_SIZE); - (*vmcs)->hdr.revision_id = basic.revision; - assert(!vmcs_clear(*vmcs)); - assert(!make_vmcs_current(*vmcs)); - - *old = handle_exception(PF_VECTOR, &pf_handler); -} - -static void test_read_sentinel(void) -{ - void *vpage; - struct vmcs *vmcs; - handler old; - - prep_flags_test_env(&vpage, &vmcs, &old); - - /* - * set the proper label - */ - extern char finish_read_fault; - - finish_fault = (ulong)&finish_read_fault; - - /* - * execute the vmread instruction that will cause a #PF - */ - handler_called = false; - asm volatile ("movb %[byte], %%ah\n\t" - "sahf\n\t" - "vmread %[enc], %[val]; finish_read_fault:" - : [val] "=m" (*(u64 *)vpage) - : [byte] "Krm" (sentinel), - [enc] "r" ((u64)GUEST_SEL_SS) - : "cc", "ah"); - report(handler_called, "The #PF handler was invoked"); - - /* - * restore the old #PF handler - */ - handle_exception(PF_VECTOR, old); -} - -static void test_vmread_flags_touch(void) -{ - /* - * set up the sentinel value in the flags register. we - * choose these two values because they candy-stripe - * the 5 flags that sahf sets. - */ - sentinel = 0x91; - test_read_sentinel(); - - sentinel = 0x45; - test_read_sentinel(); -} - -static void test_write_sentinel(void) -{ - void *vpage; - struct vmcs *vmcs; - handler old; - - prep_flags_test_env(&vpage, &vmcs, &old); - - /* - * set the proper label - */ - extern char finish_write_fault; - - finish_fault = (ulong)&finish_write_fault; - - /* - * execute the vmwrite instruction that will cause a #PF - */ - handler_called = false; - asm volatile ("movb %[byte], %%ah\n\t" - "sahf\n\t" - "vmwrite %[val], %[enc]; finish_write_fault:" - : [val] "=m" (*(u64 *)vpage) - : [byte] "Krm" (sentinel), - [enc] "r" ((u64)GUEST_SEL_SS) - : "cc", "ah"); - report(handler_called, "The #PF handler was invoked"); - - /* - * restore the old #PF handler - */ - handle_exception(PF_VECTOR, old); -} - -static void test_vmwrite_flags_touch(void) -{ - /* - * set up the sentinel value in the flags register. we - * choose these two values because they candy-stripe - * the 5 flags that sahf sets. - */ - sentinel = 0x91; - test_write_sentinel(); - - sentinel = 0x45; - test_write_sentinel(); -} - - -static void test_vmcs_high(void) -{ - struct vmcs *vmcs = alloc_page(); - - vmcs->hdr.revision_id = basic.revision; - assert(!vmcs_clear(vmcs)); - assert(!make_vmcs_current(vmcs)); - - vmcs_write(TSC_OFFSET, 0x0123456789ABCDEFull); - report(vmcs_read(TSC_OFFSET) == 0x0123456789ABCDEFull, - "VMREAD TSC_OFFSET after VMWRITE TSC_OFFSET"); - report(vmcs_read(TSC_OFFSET_HI) == 0x01234567ull, - "VMREAD TSC_OFFSET_HI after VMWRITE TSC_OFFSET"); - vmcs_write(TSC_OFFSET_HI, 0x76543210ul); - report(vmcs_read(TSC_OFFSET_HI) == 0x76543210ul, - "VMREAD TSC_OFFSET_HI after VMWRITE TSC_OFFSET_HI"); - report(vmcs_read(TSC_OFFSET) == 0x7654321089ABCDEFull, - "VMREAD TSC_OFFSET after VMWRITE TSC_OFFSET_HI"); - - assert(!vmcs_clear(vmcs)); - free_page(vmcs); -} - -static void test_vmcs_lifecycle(void) -{ - struct vmcs *vmcs[2] = {}; - int i; - - for (i = 0; i < ARRAY_SIZE(vmcs); i++) { - vmcs[i] = alloc_page(); - vmcs[i]->hdr.revision_id = basic.revision; - } - -#define VMPTRLD(_i) do { \ - assert(_i < ARRAY_SIZE(vmcs)); \ - assert(!make_vmcs_current(vmcs[_i])); \ - printf("VMPTRLD VMCS%d\n", (_i)); \ -} while (0) - -#define VMCLEAR(_i) do { \ - assert(_i < ARRAY_SIZE(vmcs)); \ - assert(!vmcs_clear(vmcs[_i])); \ - printf("VMCLEAR VMCS%d\n", (_i)); \ -} while (0) - - VMCLEAR(0); - VMPTRLD(0); - set_all_vmcs_fields(0); - report(check_all_vmcs_fields(0), "current:VMCS0 active:[VMCS0]"); - - VMCLEAR(0); - VMPTRLD(0); - report(check_all_vmcs_fields(0), "current:VMCS0 active:[VMCS0]"); - - VMCLEAR(1); - report(check_all_vmcs_fields(0), "current:VMCS0 active:[VMCS0]"); - - VMPTRLD(1); - set_all_vmcs_fields(1); - report(check_all_vmcs_fields(1), "current:VMCS1 active:[VMCS0,VCMS1]"); - - VMPTRLD(0); - report(check_all_vmcs_fields(0), "current:VMCS0 active:[VMCS0,VCMS1]"); - VMPTRLD(1); - report(check_all_vmcs_fields(1), "current:VMCS1 active:[VMCS0,VCMS1]"); - VMPTRLD(1); - report(check_all_vmcs_fields(1), "current:VMCS1 active:[VMCS0,VCMS1]"); - - VMCLEAR(0); - report(check_all_vmcs_fields(1), "current:VMCS1 active:[VCMS1]"); - - /* VMPTRLD should not erase VMWRITEs to the current VMCS */ - set_all_vmcs_fields(2); - VMPTRLD(1); - report(check_all_vmcs_fields(2), "current:VMCS1 active:[VCMS1]"); - - for (i = 0; i < ARRAY_SIZE(vmcs); i++) { - VMCLEAR(i); - free_page(vmcs[i]); - } - -#undef VMPTRLD -#undef VMCLEAR -} - -void vmx_set_test_stage(u32 s) -{ - barrier(); - stage = s; - barrier(); -} - -u32 vmx_get_test_stage(void) -{ - u32 s; - - barrier(); - s = stage; - barrier(); - return s; -} - -void vmx_inc_test_stage(void) -{ - barrier(); - stage++; - barrier(); -} - -/* entry_sysenter */ -asm( - ".align 4, 0x90\n\t" - ".globl entry_sysenter\n\t" - "entry_sysenter:\n\t" - SAVE_GPR - " and $0xf, %rax\n\t" - " mov %rax, %rdi\n\t" - " call syscall_handler\n\t" - LOAD_GPR - " vmresume\n\t" -); - -static void __attribute__((__used__)) syscall_handler(u64 syscall_no) -{ - if (current->syscall_handler) - current->syscall_handler(syscall_no); -} - -static const char * const exit_reason_descriptions[] = { - [VMX_EXC_NMI] = "VMX_EXC_NMI", - [VMX_EXTINT] = "VMX_EXTINT", - [VMX_TRIPLE_FAULT] = "VMX_TRIPLE_FAULT", - [VMX_INIT] = "VMX_INIT", - [VMX_SIPI] = "VMX_SIPI", - [VMX_SMI_IO] = "VMX_SMI_IO", - [VMX_SMI_OTHER] = "VMX_SMI_OTHER", - [VMX_INTR_WINDOW] = "VMX_INTR_WINDOW", - [VMX_NMI_WINDOW] = "VMX_NMI_WINDOW", - [VMX_TASK_SWITCH] = "VMX_TASK_SWITCH", - [VMX_CPUID] = "VMX_CPUID", - [VMX_GETSEC] = "VMX_GETSEC", - [VMX_HLT] = "VMX_HLT", - [VMX_INVD] = "VMX_INVD", - [VMX_INVLPG] = "VMX_INVLPG", - [VMX_RDPMC] = "VMX_RDPMC", - [VMX_RDTSC] = "VMX_RDTSC", - [VMX_RSM] = "VMX_RSM", - [VMX_VMCALL] = "VMX_VMCALL", - [VMX_VMCLEAR] = "VMX_VMCLEAR", - [VMX_VMLAUNCH] = "VMX_VMLAUNCH", - [VMX_VMPTRLD] = "VMX_VMPTRLD", - [VMX_VMPTRST] = "VMX_VMPTRST", - [VMX_VMREAD] = "VMX_VMREAD", - [VMX_VMRESUME] = "VMX_VMRESUME", - [VMX_VMWRITE] = "VMX_VMWRITE", - [VMX_VMXOFF] = "VMX_VMXOFF", - [VMX_VMXON] = "VMX_VMXON", - [VMX_CR] = "VMX_CR", - [VMX_DR] = "VMX_DR", - [VMX_IO] = "VMX_IO", - [VMX_RDMSR] = "VMX_RDMSR", - [VMX_WRMSR] = "VMX_WRMSR", - [VMX_FAIL_STATE] = "VMX_FAIL_STATE", - [VMX_FAIL_MSR] = "VMX_FAIL_MSR", - [VMX_MWAIT] = "VMX_MWAIT", - [VMX_MTF] = "VMX_MTF", - [VMX_MONITOR] = "VMX_MONITOR", - [VMX_PAUSE] = "VMX_PAUSE", - [VMX_FAIL_MCHECK] = "VMX_FAIL_MCHECK", - [VMX_TPR_THRESHOLD] = "VMX_TPR_THRESHOLD", - [VMX_APIC_ACCESS] = "VMX_APIC_ACCESS", - [VMX_EOI_INDUCED] = "VMX_EOI_INDUCED", - [VMX_GDTR_IDTR] = "VMX_GDTR_IDTR", - [VMX_LDTR_TR] = "VMX_LDTR_TR", - [VMX_EPT_VIOLATION] = "VMX_EPT_VIOLATION", - [VMX_EPT_MISCONFIG] = "VMX_EPT_MISCONFIG", - [VMX_INVEPT] = "VMX_INVEPT", - [VMX_PREEMPT] = "VMX_PREEMPT", - [VMX_INVVPID] = "VMX_INVVPID", - [VMX_WBINVD] = "VMX_WBINVD", - [VMX_XSETBV] = "VMX_XSETBV", - [VMX_APIC_WRITE] = "VMX_APIC_WRITE", - [VMX_RDRAND] = "VMX_RDRAND", - [VMX_INVPCID] = "VMX_INVPCID", - [VMX_VMFUNC] = "VMX_VMFUNC", - [VMX_RDSEED] = "VMX_RDSEED", - [VMX_PML_FULL] = "VMX_PML_FULL", - [VMX_XSAVES] = "VMX_XSAVES", - [VMX_XRSTORS] = "VMX_XRSTORS", -}; - -const char *exit_reason_description(u64 reason) -{ - if (reason >= ARRAY_SIZE(exit_reason_descriptions)) - return "(unknown)"; - return exit_reason_descriptions[reason] ? : "(unused)"; -} - -void print_vmexit_info(union exit_reason exit_reason) -{ - u64 guest_rip, guest_rsp; - ulong exit_qual = vmcs_read(EXI_QUALIFICATION); - guest_rip = vmcs_read(GUEST_RIP); - guest_rsp = vmcs_read(GUEST_RSP); - printf("VMEXIT info:\n"); - printf("\tvmexit reason = %u\n", exit_reason.basic); - printf("\tfailed vmentry = %u\n", !!exit_reason.failed_vmentry); - printf("\texit qualification = %#lx\n", exit_qual); - printf("\tguest_rip = %#lx\n", guest_rip); - printf("\tRAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx\n", - regs.rax, regs.rbx, regs.rcx, regs.rdx); - printf("\tRSP=%#lx RBP=%#lx RSI=%#lx RDI=%#lx\n", - guest_rsp, regs.rbp, regs.rsi, regs.rdi); - printf("\tR8 =%#lx R9 =%#lx R10=%#lx R11=%#lx\n", - regs.r8, regs.r9, regs.r10, regs.r11); - printf("\tR12=%#lx R13=%#lx R14=%#lx R15=%#lx\n", - regs.r12, regs.r13, regs.r14, regs.r15); -} - -void print_vmentry_failure_info(struct vmentry_result *result) -{ - if (result->entered) - return; - - if (result->vm_fail) { - printf("VM-Fail on %s: ", result->instr); - switch (result->flags & VMX_ENTRY_FLAGS) { - case X86_EFLAGS_CF: - printf("current-VMCS pointer is not valid.\n"); - break; - case X86_EFLAGS_ZF: - printf("error number is %ld. See Intel 30.4.\n", - vmcs_read(VMX_INST_ERROR)); - break; - default: - printf("unexpected flags %lx!\n", result->flags); - } - } else { - u64 qual = vmcs_read(EXI_QUALIFICATION); - - printf("VM-Exit failure on %s (reason=%#x, qual=%#lx): ", - result->instr, result->exit_reason.full, qual); - - switch (result->exit_reason.basic) { - case VMX_FAIL_STATE: - printf("invalid guest state\n"); - break; - case VMX_FAIL_MSR: - printf("MSR loading\n"); - break; - case VMX_FAIL_MCHECK: - printf("machine-check event\n"); - break; - default: - printf("unexpected basic exit reason %u\n", - result->exit_reason.basic); - } - - if (!result->exit_reason.failed_vmentry) - printf("\tVMX_ENTRY_FAILURE BIT NOT SET!\n"); - - if (result->exit_reason.full & 0x7fff0000) - printf("\tRESERVED BITS SET!\n"); - } -} - -/* - * VMCLEAR should ensures all VMCS state is flushed to the VMCS - * region in memory. - */ -static void test_vmclear_flushing(void) -{ - struct vmcs *vmcs[3] = {}; - int i; - - for (i = 0; i < ARRAY_SIZE(vmcs); i++) { - vmcs[i] = alloc_page(); - } - - vmcs[0]->hdr.revision_id = basic.revision; - assert(!vmcs_clear(vmcs[0])); - assert(!make_vmcs_current(vmcs[0])); - set_all_vmcs_fields(0x86); - - assert(!vmcs_clear(vmcs[0])); - memcpy(vmcs[1], vmcs[0], basic.size); - assert(!make_vmcs_current(vmcs[1])); - report(check_all_vmcs_fields(0x86), - "test vmclear flush (current VMCS)"); - - set_all_vmcs_fields(0x87); - assert(!make_vmcs_current(vmcs[0])); - assert(!vmcs_clear(vmcs[1])); - memcpy(vmcs[2], vmcs[1], basic.size); - assert(!make_vmcs_current(vmcs[2])); - report(check_all_vmcs_fields(0x87), - "test vmclear flush (!current VMCS)"); - - for (i = 0; i < ARRAY_SIZE(vmcs); i++) { - assert(!vmcs_clear(vmcs[i])); - free_page(vmcs[i]); - } -} - -static void test_vmclear(void) -{ - struct vmcs *tmp_root; - int width = cpuid_maxphyaddr(); - - /* - * Note- The tests below do not necessarily have a - * valid VMCS, but that's ok since the invalid vmcs - * is only used for a specific test and is discarded - * without touching its contents - */ - - /* Unaligned page access */ - tmp_root = (struct vmcs *)((intptr_t)vmcs_root + 1); - report(vmcs_clear(tmp_root) == 1, "test vmclear with unaligned vmcs"); - - /* gpa bits beyond physical address width are set*/ - tmp_root = (struct vmcs *)((intptr_t)vmcs_root | - ((u64)1 << (width+1))); - report(vmcs_clear(tmp_root) == 1, - "test vmclear with vmcs address bits set beyond physical address width"); - - /* Pass VMXON region */ - tmp_root = (struct vmcs *)bsp_vmxon_region; - report(vmcs_clear(tmp_root) == 1, "test vmclear with vmxon region"); - - /* Valid VMCS */ - report(vmcs_clear(vmcs_root) == 0, - "test vmclear with valid vmcs region"); - - test_vmclear_flushing(); -} - -static void __attribute__((__used__)) guest_main(void) -{ - if (current->v2) - v2_guest_main(); - else - current->guest_main(); -} - -/* guest_entry */ -asm( - ".align 4, 0x90\n\t" - ".globl entry_guest\n\t" - "guest_entry:\n\t" - " call guest_main\n\t" - " mov $1, %edi\n\t" - " call hypercall\n\t" -); - -/* EPT paging structure related functions */ -/* split_large_ept_entry: Split a 2M/1G large page into 512 smaller PTEs. - @ptep : large page table entry to split - @level : level of ptep (2 or 3) - */ -static void split_large_ept_entry(unsigned long *ptep, int level) -{ - unsigned long *new_pt; - unsigned long gpa; - unsigned long pte; - unsigned long prototype; - int i; - - pte = *ptep; - assert(pte & EPT_PRESENT); - assert(pte & EPT_LARGE_PAGE); - assert(level == 2 || level == 3); - - new_pt = alloc_page(); - assert(new_pt); - - prototype = pte & ~EPT_ADDR_MASK; - if (level == 2) - prototype &= ~EPT_LARGE_PAGE; - - gpa = pte & EPT_ADDR_MASK; - for (i = 0; i < EPT_PGDIR_ENTRIES; i++) { - new_pt[i] = prototype | gpa; - gpa += 1ul << EPT_LEVEL_SHIFT(level - 1); - } - - pte &= ~EPT_LARGE_PAGE; - pte &= ~EPT_ADDR_MASK; - pte |= virt_to_phys(new_pt); - - *ptep = pte; -} - -/* install_ept_entry : Install a page to a given level in EPT - @pml4 : addr of pml4 table - @pte_level : level of PTE to set - @guest_addr : physical address of guest - @pte : pte value to set - @pt_page : address of page table, NULL for a new page - */ -void install_ept_entry(unsigned long *pml4, - int pte_level, - unsigned long guest_addr, - unsigned long pte, - unsigned long *pt_page) -{ - int level; - unsigned long *pt = pml4; - unsigned offset; - - /* EPT only uses 48 bits of GPA. */ - assert(guest_addr < (1ul << 48)); - - for (level = EPT_PAGE_LEVEL; level > pte_level; --level) { - offset = (guest_addr >> EPT_LEVEL_SHIFT(level)) - & EPT_PGDIR_MASK; - if (!(pt[offset] & (EPT_PRESENT))) { - unsigned long *new_pt = pt_page; - if (!new_pt) - new_pt = alloc_page(); - else - pt_page = 0; - memset(new_pt, 0, PAGE_SIZE); - pt[offset] = virt_to_phys(new_pt) - | EPT_RA | EPT_WA | EPT_EA; - } else if (pt[offset] & EPT_LARGE_PAGE) - split_large_ept_entry(&pt[offset], level); - pt = phys_to_virt(pt[offset] & EPT_ADDR_MASK); - } - offset = (guest_addr >> EPT_LEVEL_SHIFT(level)) & EPT_PGDIR_MASK; - pt[offset] = pte; -} - -/* Map a page, @perm is the permission of the page */ -void install_ept(unsigned long *pml4, - unsigned long phys, - unsigned long guest_addr, - u64 perm) -{ - install_ept_entry(pml4, 1, guest_addr, (phys & PAGE_MASK) | perm, 0); -} - -/* Map a 1G-size page */ -void install_1g_ept(unsigned long *pml4, - unsigned long phys, - unsigned long guest_addr, - u64 perm) -{ - install_ept_entry(pml4, 3, guest_addr, - (phys & PAGE_MASK) | perm | EPT_LARGE_PAGE, 0); -} - -/* Map a 2M-size page */ -void install_2m_ept(unsigned long *pml4, - unsigned long phys, - unsigned long guest_addr, - u64 perm) -{ - install_ept_entry(pml4, 2, guest_addr, - (phys & PAGE_MASK) | perm | EPT_LARGE_PAGE, 0); -} - -/* setup_ept_range : Setup a range of 1:1 mapped page to EPT paging structure. - @start : start address of guest page - @len : length of address to be mapped - @map_1g : whether 1G page map is used - @map_2m : whether 2M page map is used - @perm : permission for every page - */ -void setup_ept_range(unsigned long *pml4, unsigned long start, - unsigned long len, int map_1g, int map_2m, u64 perm) -{ - u64 phys = start; - u64 max = (u64)len + (u64)start; - - if (map_1g) { - while (phys + PAGE_SIZE_1G <= max) { - install_1g_ept(pml4, phys, phys, perm); - phys += PAGE_SIZE_1G; - } - } - if (map_2m) { - while (phys + PAGE_SIZE_2M <= max) { - install_2m_ept(pml4, phys, phys, perm); - phys += PAGE_SIZE_2M; - } - } - while (phys + PAGE_SIZE <= max) { - install_ept(pml4, phys, phys, perm); - phys += PAGE_SIZE; - } -} - -/* get_ept_pte : Get the PTE of a given level in EPT, - @level == 1 means get the latest level*/ -bool get_ept_pte(unsigned long *pml4, unsigned long guest_addr, int level, - unsigned long *pte) -{ - int l; - unsigned long *pt = pml4, iter_pte; - unsigned offset; - - assert(level >= 1 && level <= 4); - - for (l = EPT_PAGE_LEVEL; ; --l) { - offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK; - iter_pte = pt[offset]; - if (l == level) - break; - if (l < 4 && (iter_pte & EPT_LARGE_PAGE)) - return false; - if (!(iter_pte & (EPT_PRESENT))) - return false; - pt = (unsigned long *)(iter_pte & EPT_ADDR_MASK); - } - offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK; - if (pte) - *pte = pt[offset]; - return true; -} - -static void clear_ept_ad_pte(unsigned long *pml4, unsigned long guest_addr) -{ - int l; - unsigned long *pt = pml4; - u64 pte; - unsigned offset; - - for (l = EPT_PAGE_LEVEL; ; --l) { - offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK; - pt[offset] &= ~(EPT_ACCESS_FLAG|EPT_DIRTY_FLAG); - pte = pt[offset]; - if (l == 1 || (l < 4 && (pte & EPT_LARGE_PAGE))) - break; - pt = (unsigned long *)(pte & EPT_ADDR_MASK); - } -} - -/* clear_ept_ad : Clear EPT A/D bits for the page table walk and the - final GPA of a guest address. */ -void clear_ept_ad(unsigned long *pml4, u64 guest_cr3, - unsigned long guest_addr) -{ - int l; - unsigned long *pt = (unsigned long *)guest_cr3, gpa; - u64 pte, offset_in_page; - unsigned offset; - - for (l = EPT_PAGE_LEVEL; ; --l) { - offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK; - - clear_ept_ad_pte(pml4, (u64) &pt[offset]); - pte = pt[offset]; - if (l == 1 || (l < 4 && (pte & PT_PAGE_SIZE_MASK))) - break; - if (!(pte & PT_PRESENT_MASK)) - return; - pt = (unsigned long *)(pte & PT_ADDR_MASK); - } - - offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK; - offset_in_page = guest_addr & ((1 << EPT_LEVEL_SHIFT(l)) - 1); - gpa = (pt[offset] & PT_ADDR_MASK) | (guest_addr & offset_in_page); - clear_ept_ad_pte(pml4, gpa); -} - -/* check_ept_ad : Check the content of EPT A/D bits for the page table - walk and the final GPA of a guest address. */ -void check_ept_ad(unsigned long *pml4, u64 guest_cr3, - unsigned long guest_addr, int expected_gpa_ad, - int expected_pt_ad) -{ - int l; - unsigned long *pt = (unsigned long *)guest_cr3, gpa; - u64 ept_pte, pte, offset_in_page; - unsigned offset; - bool bad_pt_ad = false; - - for (l = EPT_PAGE_LEVEL; ; --l) { - offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK; - - if (!get_ept_pte(pml4, (u64) &pt[offset], 1, &ept_pte)) { - printf("EPT - guest level %d page table is not mapped.\n", l); - return; - } - - if (!bad_pt_ad) { - bad_pt_ad |= (ept_pte & (EPT_ACCESS_FLAG|EPT_DIRTY_FLAG)) != expected_pt_ad; - if (bad_pt_ad) - report(false, - "EPT - guest level %d page table A=%d/D=%d", - l, - !!(expected_pt_ad & EPT_ACCESS_FLAG), - !!(expected_pt_ad & EPT_DIRTY_FLAG)); - } - - pte = pt[offset]; - if (l == 1 || (l < 4 && (pte & PT_PAGE_SIZE_MASK))) - break; - if (!(pte & PT_PRESENT_MASK)) - return; - pt = (unsigned long *)(pte & PT_ADDR_MASK); - } - - if (!bad_pt_ad) - report(true, "EPT - guest page table structures A=%d/D=%d", - !!(expected_pt_ad & EPT_ACCESS_FLAG), - !!(expected_pt_ad & EPT_DIRTY_FLAG)); - - offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK; - offset_in_page = guest_addr & ((1 << EPT_LEVEL_SHIFT(l)) - 1); - gpa = (pt[offset] & PT_ADDR_MASK) | (guest_addr & offset_in_page); - - if (!get_ept_pte(pml4, gpa, 1, &ept_pte)) { - report(false, "EPT - guest physical address is not mapped"); - return; - } - report((ept_pte & (EPT_ACCESS_FLAG | EPT_DIRTY_FLAG)) == expected_gpa_ad, - "EPT - guest physical address A=%d/D=%d", - !!(expected_gpa_ad & EPT_ACCESS_FLAG), - !!(expected_gpa_ad & EPT_DIRTY_FLAG)); -} - - -void ept_sync(int type, u64 eptp) -{ - switch (type) { - case INVEPT_SINGLE: - if (ept_vpid.val & EPT_CAP_INVEPT_SINGLE) { - invept(INVEPT_SINGLE, eptp); - break; - } - /* else fall through */ - case INVEPT_GLOBAL: - if (ept_vpid.val & EPT_CAP_INVEPT_ALL) { - invept(INVEPT_GLOBAL, eptp); - break; - } - /* else fall through */ - default: - printf("WARNING: invept is not supported!\n"); - } -} - -void set_ept_pte(unsigned long *pml4, unsigned long guest_addr, - int level, u64 pte_val) -{ - int l; - unsigned long *pt = pml4; - unsigned offset; - - assert(level >= 1 && level <= 4); - - for (l = EPT_PAGE_LEVEL; ; --l) { - offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK; - if (l == level) - break; - assert(pt[offset] & EPT_PRESENT); - pt = (unsigned long *)(pt[offset] & EPT_ADDR_MASK); - } - offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK; - pt[offset] = pte_val; -} - -bool ept_2m_supported(void) -{ - return ept_vpid.val & EPT_CAP_2M_PAGE; -} - -bool ept_1g_supported(void) -{ - return ept_vpid.val & EPT_CAP_1G_PAGE; -} - -bool ept_huge_pages_supported(int level) -{ - if (level == 2) - return ept_2m_supported(); - else if (level == 3) - return ept_1g_supported(); - else - return false; -} - -bool ept_execute_only_supported(void) -{ - return ept_vpid.val & EPT_CAP_WT; -} - -bool ept_ad_bits_supported(void) -{ - return ept_vpid.val & EPT_CAP_AD_FLAG; -} - -void vpid_sync(int type, u16 vpid) -{ - switch(type) { - case INVVPID_CONTEXT_GLOBAL: - if (ept_vpid.val & VPID_CAP_INVVPID_CXTGLB) { - invvpid(INVVPID_CONTEXT_GLOBAL, vpid, 0); - break; - } - case INVVPID_ALL: - if (ept_vpid.val & VPID_CAP_INVVPID_ALL) { - invvpid(INVVPID_ALL, vpid, 0); - break; - } - default: - printf("WARNING: invvpid is not supported\n"); - } -} - -static void init_vmcs_ctrl(void) -{ - /* 26.2 CHECKS ON VMX CONTROLS AND HOST-STATE AREA */ - /* 26.2.1.1 */ - vmcs_write(PIN_CONTROLS, ctrl_pin); - /* Disable VMEXIT of IO instruction */ - vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]); - if (ctrl_cpu_rev[0].set & CPU_SECONDARY) { - ctrl_cpu[1] = (ctrl_cpu[1] | ctrl_cpu_rev[1].set) & - ctrl_cpu_rev[1].clr; - vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1]); - } - vmcs_write(CR3_TARGET_COUNT, 0); - vmcs_write(VPID, ++vpid_cnt); -} - -static void init_vmcs_host(void) -{ - /* 26.2 CHECKS ON VMX CONTROLS AND HOST-STATE AREA */ - /* 26.2.1.2 */ - vmcs_write(HOST_EFER, rdmsr(MSR_EFER)); - - /* 26.2.1.3 */ - vmcs_write(ENT_CONTROLS, ctrl_enter); - vmcs_write(EXI_CONTROLS, ctrl_exit); - - /* 26.2.2 */ - vmcs_write(HOST_CR0, read_cr0()); - vmcs_write(HOST_CR3, read_cr3()); - vmcs_write(HOST_CR4, read_cr4()); - vmcs_write(HOST_SYSENTER_EIP, (u64)(&entry_sysenter)); - vmcs_write(HOST_SYSENTER_CS, KERNEL_CS); - - /* 26.2.3 */ - vmcs_write(HOST_SEL_CS, KERNEL_CS); - vmcs_write(HOST_SEL_SS, KERNEL_DS); - vmcs_write(HOST_SEL_DS, KERNEL_DS); - vmcs_write(HOST_SEL_ES, KERNEL_DS); - vmcs_write(HOST_SEL_FS, KERNEL_DS); - vmcs_write(HOST_SEL_GS, KERNEL_DS); - vmcs_write(HOST_SEL_TR, TSS_MAIN); - vmcs_write(HOST_BASE_TR, tss_descr.base); - vmcs_write(HOST_BASE_GDTR, gdt64_desc.base); - vmcs_write(HOST_BASE_IDTR, idt_descr.base); - vmcs_write(HOST_BASE_FS, 0); - vmcs_write(HOST_BASE_GS, 0); - - /* Set other vmcs area */ - vmcs_write(PF_ERROR_MASK, 0); - vmcs_write(PF_ERROR_MATCH, 0); - vmcs_write(VMCS_LINK_PTR, ~0ul); - vmcs_write(VMCS_LINK_PTR_HI, ~0ul); - vmcs_write(HOST_RIP, (u64)(&vmx_return)); -} - -static void init_vmcs_guest(void) -{ - /* 26.3 CHECKING AND LOADING GUEST STATE */ - ulong guest_cr0, guest_cr4, guest_cr3; - /* 26.3.1.1 */ - guest_cr0 = read_cr0(); - guest_cr4 = read_cr4(); - guest_cr3 = read_cr3(); - if (ctrl_enter & ENT_GUEST_64) { - guest_cr0 |= X86_CR0_PG; - guest_cr4 |= X86_CR4_PAE; - } - if ((ctrl_enter & ENT_GUEST_64) == 0) - guest_cr4 &= (~X86_CR4_PCIDE); - if (guest_cr0 & X86_CR0_PG) - guest_cr0 |= X86_CR0_PE; - vmcs_write(GUEST_CR0, guest_cr0); - vmcs_write(GUEST_CR3, guest_cr3); - vmcs_write(GUEST_CR4, guest_cr4); - vmcs_write(GUEST_SYSENTER_CS, KERNEL_CS); - vmcs_write(GUEST_SYSENTER_ESP, - (u64)(guest_syscall_stack + PAGE_SIZE - 1)); - vmcs_write(GUEST_SYSENTER_EIP, (u64)(&entry_sysenter)); - vmcs_write(GUEST_DR7, 0); - vmcs_write(GUEST_EFER, rdmsr(MSR_EFER)); - - /* 26.3.1.2 */ - vmcs_write(GUEST_SEL_CS, KERNEL_CS); - vmcs_write(GUEST_SEL_SS, KERNEL_DS); - vmcs_write(GUEST_SEL_DS, KERNEL_DS); - vmcs_write(GUEST_SEL_ES, KERNEL_DS); - vmcs_write(GUEST_SEL_FS, KERNEL_DS); - vmcs_write(GUEST_SEL_GS, KERNEL_DS); - vmcs_write(GUEST_SEL_TR, TSS_MAIN); - vmcs_write(GUEST_SEL_LDTR, 0); - - vmcs_write(GUEST_BASE_CS, 0); - vmcs_write(GUEST_BASE_ES, 0); - vmcs_write(GUEST_BASE_SS, 0); - vmcs_write(GUEST_BASE_DS, 0); - vmcs_write(GUEST_BASE_FS, 0); - vmcs_write(GUEST_BASE_GS, 0); - vmcs_write(GUEST_BASE_TR, tss_descr.base); - vmcs_write(GUEST_BASE_LDTR, 0); - - vmcs_write(GUEST_LIMIT_CS, 0xFFFFFFFF); - vmcs_write(GUEST_LIMIT_DS, 0xFFFFFFFF); - vmcs_write(GUEST_LIMIT_ES, 0xFFFFFFFF); - vmcs_write(GUEST_LIMIT_SS, 0xFFFFFFFF); - vmcs_write(GUEST_LIMIT_FS, 0xFFFFFFFF); - vmcs_write(GUEST_LIMIT_GS, 0xFFFFFFFF); - vmcs_write(GUEST_LIMIT_LDTR, 0xffff); - vmcs_write(GUEST_LIMIT_TR, tss_descr.limit); - - vmcs_write(GUEST_AR_CS, 0xa09b); - vmcs_write(GUEST_AR_DS, 0xc093); - vmcs_write(GUEST_AR_ES, 0xc093); - vmcs_write(GUEST_AR_FS, 0xc093); - vmcs_write(GUEST_AR_GS, 0xc093); - vmcs_write(GUEST_AR_SS, 0xc093); - vmcs_write(GUEST_AR_LDTR, 0x82); - vmcs_write(GUEST_AR_TR, 0x8b); - - /* 26.3.1.3 */ - vmcs_write(GUEST_BASE_GDTR, gdt64_desc.base); - vmcs_write(GUEST_BASE_IDTR, idt_descr.base); - vmcs_write(GUEST_LIMIT_GDTR, gdt64_desc.limit); - vmcs_write(GUEST_LIMIT_IDTR, idt_descr.limit); - - /* 26.3.1.4 */ - vmcs_write(GUEST_RIP, (u64)(&guest_entry)); - vmcs_write(GUEST_RSP, (u64)(guest_stack + PAGE_SIZE - 1)); - vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED); - - /* 26.3.1.5 */ - vmcs_write(GUEST_ACTV_STATE, ACTV_ACTIVE); - vmcs_write(GUEST_INTR_STATE, 0); -} - -static int init_vmcs(struct vmcs **vmcs) -{ - *vmcs = alloc_page(); - (*vmcs)->hdr.revision_id = basic.revision; - /* vmclear first to init vmcs */ - if (vmcs_clear(*vmcs)) { - printf("%s : vmcs_clear error\n", __func__); - return 1; - } - - if (make_vmcs_current(*vmcs)) { - printf("%s : make_vmcs_current error\n", __func__); - return 1; - } - - /* All settings to pin/exit/enter/cpu - control fields should be placed here */ - ctrl_pin |= PIN_EXTINT | PIN_NMI | PIN_VIRT_NMI; - ctrl_exit = EXI_LOAD_EFER | EXI_HOST_64; - ctrl_enter = (ENT_LOAD_EFER | ENT_GUEST_64); - /* DIsable IO instruction VMEXIT now */ - ctrl_cpu[0] &= (~(CPU_IO | CPU_IO_BITMAP)); - ctrl_cpu[1] = 0; - - ctrl_pin = (ctrl_pin | ctrl_pin_rev.set) & ctrl_pin_rev.clr; - ctrl_enter = (ctrl_enter | ctrl_enter_rev.set) & ctrl_enter_rev.clr; - ctrl_exit = (ctrl_exit | ctrl_exit_rev.set) & ctrl_exit_rev.clr; - ctrl_cpu[0] = (ctrl_cpu[0] | ctrl_cpu_rev[0].set) & ctrl_cpu_rev[0].clr; - - init_vmcs_ctrl(); - init_vmcs_host(); - init_vmcs_guest(); - return 0; -} - -void enable_vmx(void) -{ - bool vmx_enabled = - rdmsr(MSR_IA32_FEATURE_CONTROL) & - FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; - - if (!vmx_enabled) { - wrmsr(MSR_IA32_FEATURE_CONTROL, - FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX | - FEATURE_CONTROL_LOCKED); - } -} - -static void init_vmx_caps(void) -{ - basic.val = rdmsr(MSR_IA32_VMX_BASIC); - ctrl_pin_rev.val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_PIN - : MSR_IA32_VMX_PINBASED_CTLS); - ctrl_exit_rev.val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_EXIT - : MSR_IA32_VMX_EXIT_CTLS); - ctrl_enter_rev.val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_ENTRY - : MSR_IA32_VMX_ENTRY_CTLS); - ctrl_cpu_rev[0].val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_PROC - : MSR_IA32_VMX_PROCBASED_CTLS); - if ((ctrl_cpu_rev[0].clr & CPU_SECONDARY) != 0) - ctrl_cpu_rev[1].val = rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2); - else - ctrl_cpu_rev[1].val = 0; - if ((ctrl_cpu_rev[1].clr & (CPU_EPT | CPU_VPID)) != 0) - ept_vpid.val = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP); - else - ept_vpid.val = 0; -} - -void init_vmx(u64 *vmxon_region) -{ - ulong fix_cr0_set, fix_cr0_clr; - ulong fix_cr4_set, fix_cr4_clr; - - fix_cr0_set = rdmsr(MSR_IA32_VMX_CR0_FIXED0); - fix_cr0_clr = rdmsr(MSR_IA32_VMX_CR0_FIXED1); - fix_cr4_set = rdmsr(MSR_IA32_VMX_CR4_FIXED0); - fix_cr4_clr = rdmsr(MSR_IA32_VMX_CR4_FIXED1); - - write_cr0((read_cr0() & fix_cr0_clr) | fix_cr0_set); - write_cr4((read_cr4() & fix_cr4_clr) | fix_cr4_set | X86_CR4_VMXE); - - *vmxon_region = basic.revision; -} - -static void alloc_bsp_vmx_pages(void) -{ - bsp_vmxon_region = alloc_page(); - guest_stack = alloc_page(); - guest_syscall_stack = alloc_page(); - vmcs_root = alloc_page(); -} - -static void init_bsp_vmx(void) -{ - init_vmx_caps(); - alloc_bsp_vmx_pages(); - init_vmx(bsp_vmxon_region); -} - -static void do_vmxon_off(void *data) -{ - vmx_on(); - vmx_off(); -} - -static void do_write_feature_control(void *data) -{ - wrmsr(MSR_IA32_FEATURE_CONTROL, 0); -} - -static int test_vmx_feature_control(void) -{ - u64 ia32_feature_control; - bool vmx_enabled; - bool feature_control_locked; - - ia32_feature_control = rdmsr(MSR_IA32_FEATURE_CONTROL); - vmx_enabled = - ia32_feature_control & FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; - feature_control_locked = - ia32_feature_control & FEATURE_CONTROL_LOCKED; - - if (vmx_enabled && feature_control_locked) { - printf("VMX enabled and locked by BIOS\n"); - return 0; - } else if (feature_control_locked) { - printf("ERROR: VMX locked out by BIOS!?\n"); - return 1; - } - - wrmsr(MSR_IA32_FEATURE_CONTROL, 0); - report(test_for_exception(GP_VECTOR, &do_vmxon_off, NULL), - "test vmxon with FEATURE_CONTROL cleared"); - - wrmsr(MSR_IA32_FEATURE_CONTROL, FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX); - report(test_for_exception(GP_VECTOR, &do_vmxon_off, NULL), - "test vmxon without FEATURE_CONTROL lock"); - - wrmsr(MSR_IA32_FEATURE_CONTROL, - FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX | - FEATURE_CONTROL_LOCKED); - - ia32_feature_control = rdmsr(MSR_IA32_FEATURE_CONTROL); - vmx_enabled = - ia32_feature_control & FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; - report(vmx_enabled, "test enable VMX in FEATURE_CONTROL"); - - report(test_for_exception(GP_VECTOR, &do_write_feature_control, NULL), - "test FEATURE_CONTROL lock bit"); - - return !vmx_enabled; -} - -static int test_vmxon(void) -{ - int ret, ret1; - u64 *vmxon_region; - int width = cpuid_maxphyaddr(); - - /* Unaligned page access */ - vmxon_region = (u64 *)((intptr_t)bsp_vmxon_region + 1); - ret1 = _vmx_on(vmxon_region); - report(ret1, "test vmxon with unaligned vmxon region"); - if (!ret1) { - ret = 1; - goto out; - } - - /* gpa bits beyond physical address width are set*/ - vmxon_region = (u64 *)((intptr_t)bsp_vmxon_region | ((u64)1 << (width+1))); - ret1 = _vmx_on(vmxon_region); - report(ret1, "test vmxon with bits set beyond physical address width"); - if (!ret1) { - ret = 1; - goto out; - } - - /* invalid revision indentifier */ - *bsp_vmxon_region = 0xba9da9; - ret1 = vmx_on(); - report(ret1, "test vmxon with invalid revision identifier"); - if (!ret1) { - ret = 1; - goto out; - } - - /* and finally a valid region */ - *bsp_vmxon_region = basic.revision; - ret = vmx_on(); - report(!ret, "test vmxon with valid vmxon region"); - -out: - return ret; -} - -static void test_vmptrld(void) -{ - struct vmcs *vmcs, *tmp_root; - int width = cpuid_maxphyaddr(); - - vmcs = alloc_page(); - vmcs->hdr.revision_id = basic.revision; - - /* Unaligned page access */ - tmp_root = (struct vmcs *)((intptr_t)vmcs + 1); - report(make_vmcs_current(tmp_root) == 1, - "test vmptrld with unaligned vmcs"); - - /* gpa bits beyond physical address width are set*/ - tmp_root = (struct vmcs *)((intptr_t)vmcs | - ((u64)1 << (width+1))); - report(make_vmcs_current(tmp_root) == 1, - "test vmptrld with vmcs address bits set beyond physical address width"); - - /* Pass VMXON region */ - assert(!vmcs_clear(vmcs)); - assert(!make_vmcs_current(vmcs)); - tmp_root = (struct vmcs *)bsp_vmxon_region; - report(make_vmcs_current(tmp_root) == 1, - "test vmptrld with vmxon region"); - report(vmcs_read(VMX_INST_ERROR) == VMXERR_VMPTRLD_VMXON_POINTER, - "test vmptrld with vmxon region vm-instruction error"); - - report(make_vmcs_current(vmcs) == 0, - "test vmptrld with valid vmcs region"); -} - -static void test_vmptrst(void) -{ - int ret; - struct vmcs *vmcs1, *vmcs2; - - vmcs1 = alloc_page(); - init_vmcs(&vmcs1); - ret = vmcs_save(&vmcs2); - report((!ret) && (vmcs1 == vmcs2), "test vmptrst"); -} - -struct vmx_ctl_msr { - const char *name; - u32 index, true_index; - u32 default1; -} vmx_ctl_msr[] = { - { "MSR_IA32_VMX_PINBASED_CTLS", MSR_IA32_VMX_PINBASED_CTLS, - MSR_IA32_VMX_TRUE_PIN, 0x16 }, - { "MSR_IA32_VMX_PROCBASED_CTLS", MSR_IA32_VMX_PROCBASED_CTLS, - MSR_IA32_VMX_TRUE_PROC, 0x401e172 }, - { "MSR_IA32_VMX_PROCBASED_CTLS2", MSR_IA32_VMX_PROCBASED_CTLS2, - MSR_IA32_VMX_PROCBASED_CTLS2, 0 }, - { "MSR_IA32_VMX_EXIT_CTLS", MSR_IA32_VMX_EXIT_CTLS, - MSR_IA32_VMX_TRUE_EXIT, 0x36dff }, - { "MSR_IA32_VMX_ENTRY_CTLS", MSR_IA32_VMX_ENTRY_CTLS, - MSR_IA32_VMX_TRUE_ENTRY, 0x11ff }, -}; - -static void test_vmx_caps(void) -{ - u64 val, default1, fixed0, fixed1; - union vmx_ctrl_msr ctrl, true_ctrl; - unsigned int n; - bool ok; - - printf("\nTest suite: VMX capability reporting\n"); - - report((basic.revision & (1ul << 31)) == 0 && - basic.size > 0 && basic.size <= 4096 && - (basic.type == 0 || basic.type == 6) && - basic.reserved1 == 0 && basic.reserved2 == 0, - "MSR_IA32_VMX_BASIC"); - - val = rdmsr(MSR_IA32_VMX_MISC); - report((!(ctrl_cpu_rev[1].clr & CPU_URG) || val & (1ul << 5)) && - ((val >> 16) & 0x1ff) <= 256 && - (val & 0x80007e00) == 0, - "MSR_IA32_VMX_MISC"); - - for (n = 0; n < ARRAY_SIZE(vmx_ctl_msr); n++) { - ctrl.val = rdmsr(vmx_ctl_msr[n].index); - default1 = vmx_ctl_msr[n].default1; - ok = (ctrl.set & default1) == default1; - ok = ok && (ctrl.set & ~ctrl.clr) == 0; - if (ok && basic.ctrl) { - true_ctrl.val = rdmsr(vmx_ctl_msr[n].true_index); - ok = ctrl.clr == true_ctrl.clr; - ok = ok && ctrl.set == (true_ctrl.set | default1); - } - report(ok, "%s", vmx_ctl_msr[n].name); - } - - fixed0 = rdmsr(MSR_IA32_VMX_CR0_FIXED0); - fixed1 = rdmsr(MSR_IA32_VMX_CR0_FIXED1); - report(((fixed0 ^ fixed1) & ~fixed1) == 0, - "MSR_IA32_VMX_IA32_VMX_CR0_FIXED0/1"); - - fixed0 = rdmsr(MSR_IA32_VMX_CR4_FIXED0); - fixed1 = rdmsr(MSR_IA32_VMX_CR4_FIXED1); - report(((fixed0 ^ fixed1) & ~fixed1) == 0, - "MSR_IA32_VMX_IA32_VMX_CR4_FIXED0/1"); - - val = rdmsr(MSR_IA32_VMX_VMCS_ENUM); - report((val & VMCS_FIELD_INDEX_MASK) >= 0x2a && - (val & 0xfffffffffffffc01Ull) == 0, - "MSR_IA32_VMX_VMCS_ENUM"); - - fixed0 = -1ull; - fixed0 &= ~(EPT_CAP_WT | - EPT_CAP_PWL4 | - EPT_CAP_PWL5 | - EPT_CAP_UC | - EPT_CAP_WB | - EPT_CAP_2M_PAGE | - EPT_CAP_1G_PAGE | - EPT_CAP_INVEPT | - EPT_CAP_AD_FLAG | - EPT_CAP_ADV_EPT_INFO | - EPT_CAP_INVEPT_SINGLE | - EPT_CAP_INVEPT_ALL | - VPID_CAP_INVVPID | - VPID_CAP_INVVPID_ADDR | - VPID_CAP_INVVPID_CXTGLB | - VPID_CAP_INVVPID_ALL | - VPID_CAP_INVVPID_CXTLOC); - - val = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP); - report((val & fixed0) == 0, - "MSR_IA32_VMX_EPT_VPID_CAP"); -} - -/* This function can only be called in guest */ -static void __attribute__((__used__)) hypercall(u32 hypercall_no) -{ - u64 val = 0; - val = (hypercall_no & HYPERCALL_MASK) | HYPERCALL_BIT; - hypercall_field = val; - asm volatile("vmcall\n\t"); -} - -static bool is_hypercall(union exit_reason exit_reason) -{ - return exit_reason.basic == VMX_VMCALL && - (hypercall_field & HYPERCALL_BIT); -} - -static int handle_hypercall(void) -{ - ulong hypercall_no; - - hypercall_no = hypercall_field & HYPERCALL_MASK; - hypercall_field = 0; - switch (hypercall_no) { - case HYPERCALL_VMEXIT: - return VMX_TEST_VMEXIT; - case HYPERCALL_VMABORT: - return VMX_TEST_VMABORT; - case HYPERCALL_VMSKIP: - return VMX_TEST_VMSKIP; - default: - printf("ERROR : Invalid hypercall number : %ld\n", hypercall_no); - } - return VMX_TEST_EXIT; -} - -static void continue_abort(void) -{ - assert(!in_guest); - printf("Host was here when guest aborted:\n"); - dump_stack(); - longjmp(abort_target, 1); - abort(); -} - -void __abort_test(void) -{ - if (in_guest) - hypercall(HYPERCALL_VMABORT); - else - longjmp(abort_target, 1); - abort(); -} - -static void continue_skip(void) -{ - assert(!in_guest); - longjmp(abort_target, 1); - abort(); -} - -void test_skip(const char *msg) -{ - printf("%s skipping test: %s\n", in_guest ? "Guest" : "Host", msg); - if (in_guest) - hypercall(HYPERCALL_VMABORT); - else - longjmp(abort_target, 1); - abort(); -} - -static int exit_handler(union exit_reason exit_reason) -{ - int ret; - - current->exits++; - regs.rflags = vmcs_read(GUEST_RFLAGS); - if (is_hypercall(exit_reason)) - ret = handle_hypercall(); - else - ret = current->exit_handler(exit_reason); - vmcs_write(GUEST_RFLAGS, regs.rflags); - - return ret; -} - -/* - * Tries to enter the guest, populates @result with VM-Fail, VM-Exit, entered, - * etc... - */ -static void vmx_enter_guest(struct vmentry_result *result) -{ - memset(result, 0, sizeof(*result)); - - in_guest = 1; - asm volatile ( - "mov %[HOST_RSP], %%rdi\n\t" - "vmwrite %%rsp, %%rdi\n\t" - LOAD_GPR_C - "cmpb $0, %[launched]\n\t" - "jne 1f\n\t" - "vmlaunch\n\t" - "jmp 2f\n\t" - "1: " - "vmresume\n\t" - "2: " - SAVE_GPR_C - "pushf\n\t" - "pop %%rdi\n\t" - "mov %%rdi, %[vm_fail_flags]\n\t" - "movl $1, %[vm_fail]\n\t" - "jmp 3f\n\t" - "vmx_return:\n\t" - SAVE_GPR_C - "3: \n\t" - : [vm_fail]"+m"(result->vm_fail), - [vm_fail_flags]"=m"(result->flags) - : [launched]"m"(launched), [HOST_RSP]"i"(HOST_RSP) - : "rdi", "memory", "cc" - ); - in_guest = 0; - - result->vmlaunch = !launched; - result->instr = launched ? "vmresume" : "vmlaunch"; - result->exit_reason.full = result->vm_fail ? 0xdead : - vmcs_read(EXI_REASON); - result->entered = !result->vm_fail && - !result->exit_reason.failed_vmentry; -} - -static int vmx_run(void) -{ - struct vmentry_result result; - u32 ret; - - while (1) { - vmx_enter_guest(&result); - if (result.entered) { - /* - * VMCS isn't in "launched" state if there's been any - * entry failure (early or otherwise). - */ - launched = 1; - ret = exit_handler(result.exit_reason); - } else if (current->entry_failure_handler) { - ret = current->entry_failure_handler(&result); - } else { - ret = VMX_TEST_EXIT; - } - - switch (ret) { - case VMX_TEST_RESUME: - continue; - case VMX_TEST_VMEXIT: - guest_finished = 1; - return 0; - case VMX_TEST_EXIT: - break; - default: - printf("ERROR : Invalid %s_handler return val %d.\n", - result.entered ? "exit" : "entry_failure", - ret); - break; - } - - if (result.entered) - print_vmexit_info(result.exit_reason); - else - print_vmentry_failure_info(&result); - abort(); - } -} - -static void run_teardown_step(struct test_teardown_step *step) -{ - step->func(step->data); -} - -static int test_run(struct vmx_test *test) -{ - int r; - - /* Validate V2 interface. */ - if (test->v2) { - int ret = 0; - if (test->init || test->guest_main || test->exit_handler || - test->syscall_handler) { - report(0, "V2 test cannot specify V1 callbacks."); - ret = 1; - } - if (ret) - return ret; - } - - if (test->name == NULL) - test->name = "(no name)"; - if (vmx_on()) { - printf("%s : vmxon failed.\n", __func__); - return 1; - } - - init_vmcs(&(test->vmcs)); - /* Directly call test->init is ok here, init_vmcs has done - vmcs init, vmclear and vmptrld*/ - if (test->init && test->init(test->vmcs) != VMX_TEST_START) - goto out; - teardown_count = 0; - v2_guest_main = NULL; - test->exits = 0; - current = test; - regs = test->guest_regs; - vmcs_write(GUEST_RFLAGS, regs.rflags | X86_EFLAGS_FIXED); - launched = 0; - guest_finished = 0; - printf("\nTest suite: %s\n", test->name); - - r = setjmp(abort_target); - if (r) { - assert(!in_guest); - goto out; - } - - - if (test->v2) - test->v2(); - else - vmx_run(); - - while (teardown_count > 0) - run_teardown_step(&teardown_steps[--teardown_count]); - - if (launched && !guest_finished) - report(0, "Guest didn't run to completion."); - -out: - if (vmx_off()) { - printf("%s : vmxoff failed.\n", __func__); - return 1; - } - return 0; -} - -/* - * Add a teardown step. Executed after the test's main function returns. - * Teardown steps executed in reverse order. - */ -void test_add_teardown(test_teardown_func func, void *data) -{ - struct test_teardown_step *step; - - TEST_ASSERT_MSG(teardown_count < MAX_TEST_TEARDOWN_STEPS, - "There are already %d teardown steps.", - teardown_count); - step = &teardown_steps[teardown_count++]; - step->func = func; - step->data = data; -} - -/* - * Set the target of the first enter_guest call. Can only be called once per - * test. Must be called before first enter_guest call. - */ -void test_set_guest(test_guest_func func) -{ - assert(current->v2); - TEST_ASSERT_MSG(!v2_guest_main, "Already set guest func."); - v2_guest_main = func; -} - -static void check_for_guest_termination(union exit_reason exit_reason) -{ - if (is_hypercall(exit_reason)) { - int ret; - - ret = handle_hypercall(); - switch (ret) { - case VMX_TEST_VMEXIT: - guest_finished = 1; - break; - case VMX_TEST_VMABORT: - continue_abort(); - break; - case VMX_TEST_VMSKIP: - continue_skip(); - break; - default: - printf("ERROR : Invalid handle_hypercall return %d.\n", - ret); - abort(); - } - } -} - -/* - * Enters the guest (or launches it for the first time). Error to call once the - * guest has returned (i.e., run past the end of its guest() function). - */ -void __enter_guest(u8 abort_flag, struct vmentry_result *result) -{ - TEST_ASSERT_MSG(v2_guest_main, - "Never called test_set_guest_func!"); - - TEST_ASSERT_MSG(!guest_finished, - "Called enter_guest() after guest returned."); - - vmx_enter_guest(result); - - if (result->vm_fail) { - if (abort_flag & ABORT_ON_EARLY_VMENTRY_FAIL) - goto do_abort; - return; - } - if (result->exit_reason.failed_vmentry) { - if ((abort_flag & ABORT_ON_INVALID_GUEST_STATE) || - result->exit_reason.basic != VMX_FAIL_STATE) - goto do_abort; - return; - } - - launched = 1; - check_for_guest_termination(result->exit_reason); - return; - -do_abort: - print_vmentry_failure_info(result); - abort(); -} - -void enter_guest_with_bad_controls(void) -{ - struct vmentry_result result; - - TEST_ASSERT_MSG(v2_guest_main, - "Never called test_set_guest_func!"); - - TEST_ASSERT_MSG(!guest_finished, - "Called enter_guest() after guest returned."); - - __enter_guest(ABORT_ON_INVALID_GUEST_STATE, &result); - report(result.vm_fail, "VM-Fail occurred as expected"); - report((result.flags & VMX_ENTRY_FLAGS) == X86_EFLAGS_ZF, - "FLAGS set correctly on VM-Fail"); - report(vmcs_read(VMX_INST_ERROR) == VMXERR_ENTRY_INVALID_CONTROL_FIELD, - "VM-Inst Error # is %d (VM entry with invalid control field(s))", - VMXERR_ENTRY_INVALID_CONTROL_FIELD); -} - -void enter_guest(void) -{ - struct vmentry_result result; - - __enter_guest(ABORT_ON_EARLY_VMENTRY_FAIL | - ABORT_ON_INVALID_GUEST_STATE, &result); -} - -extern struct vmx_test vmx_tests[]; - -static bool -test_wanted(const char *name, const char *filters[], int filter_count) -{ - int i; - bool positive = false; - bool match = false; - char clean_name[strlen(name) + 1]; - char *c; - const char *n; - - printf("filter = %s, test = %s\n", filters[0], name); - - /* Replace spaces with underscores. */ - n = name; - c = &clean_name[0]; - do *c++ = (*n == ' ') ? '_' : *n; - while (*n++); - - for (i = 0; i < filter_count; i++) { - const char *filter = filters[i]; - - if (filter[0] == '-') { - if (simple_glob(clean_name, filter + 1)) - return false; - } else { - positive = true; - match |= simple_glob(clean_name, filter); - } - } - - if (!positive || match) { - matched++; - return true; - } else { - return false; - } -} - -int main(int argc, const char *argv[]) -{ - int i = 0; - - setup_vm(); - hypercall_field = 0; - - /* We want xAPIC mode to test MMIO passthrough from L1 (us) to L2. */ - smp_reset_apic(); - - argv++; - argc--; - - if (!this_cpu_has(X86_FEATURE_VMX)) { - printf("WARNING: vmx not supported, add '-cpu host'\n"); - goto exit; - } - init_bsp_vmx(); - if (test_wanted("test_vmx_feature_control", argv, argc)) { - /* Sets MSR_IA32_FEATURE_CONTROL to 0x5 */ - if (test_vmx_feature_control() != 0) - goto exit; - } else { - enable_vmx(); - } - - if (test_wanted("test_vmxon", argv, argc)) { - /* Enables VMX */ - if (test_vmxon() != 0) - goto exit; - } else { - if (vmx_on()) { - report(0, "vmxon"); - goto exit; - } - } - - if (test_wanted("test_vmptrld", argv, argc)) - test_vmptrld(); - if (test_wanted("test_vmclear", argv, argc)) - test_vmclear(); - if (test_wanted("test_vmptrst", argv, argc)) - test_vmptrst(); - if (test_wanted("test_vmwrite_vmread", argv, argc)) - test_vmwrite_vmread(); - if (test_wanted("test_vmcs_high", argv, argc)) - test_vmcs_high(); - if (test_wanted("test_vmcs_lifecycle", argv, argc)) - test_vmcs_lifecycle(); - if (test_wanted("test_vmx_caps", argv, argc)) - test_vmx_caps(); - if (test_wanted("test_vmread_flags_touch", argv, argc)) - test_vmread_flags_touch(); - if (test_wanted("test_vmwrite_flags_touch", argv, argc)) - test_vmwrite_flags_touch(); - - /* Balance vmxon from test_vmxon. */ - vmx_off(); - - for (; vmx_tests[i].name != NULL; i++) { - if (!test_wanted(vmx_tests[i].name, argv, argc)) - continue; - if (test_run(&vmx_tests[i])) - goto exit; - } - - if (!matched) - report(matched, "command line didn't match any tests!"); - -exit: - return report_summary(); -} diff --git a/x86/vmx.h b/x86/vmx.h deleted file mode 100644 index d1c2436b..00000000 --- a/x86/vmx.h +++ /dev/null @@ -1,961 +0,0 @@ -#ifndef __VMX_H -#define __VMX_H - -#include "libcflat.h" -#include "processor.h" -#include "bitops.h" -#include "asm/page.h" -#include "asm/io.h" - -struct vmcs_hdr { - u32 revision_id:31; - u32 shadow_vmcs:1; -}; - -struct vmcs { - struct vmcs_hdr hdr; - u32 abort; /* VMX-abort indicator */ - /* VMCS data */ - char data[0]; -}; - -struct invvpid_operand { - u64 vpid; - u64 gla; -}; - -struct regs { - u64 rax; - u64 rcx; - u64 rdx; - u64 rbx; - u64 cr2; - u64 rbp; - u64 rsi; - u64 rdi; - u64 r8; - u64 r9; - u64 r10; - u64 r11; - u64 r12; - u64 r13; - u64 r14; - u64 r15; - u64 rflags; -}; - -union exit_reason { - struct { - u32 basic : 16; - u32 reserved16 : 1; - u32 reserved17 : 1; - u32 reserved18 : 1; - u32 reserved19 : 1; - u32 reserved20 : 1; - u32 reserved21 : 1; - u32 reserved22 : 1; - u32 reserved23 : 1; - u32 reserved24 : 1; - u32 reserved25 : 1; - u32 reserved26 : 1; - u32 enclave_mode : 1; - u32 smi_pending_mtf : 1; - u32 smi_from_vmx_root : 1; - u32 reserved30 : 1; - u32 failed_vmentry : 1; - }; - u32 full; -}; - -struct vmentry_result { - /* Instruction mnemonic (for convenience). */ - const char *instr; - /* Did the test attempt vmlaunch or vmresume? */ - bool vmlaunch; - /* Did the instruction VM-Fail? */ - bool vm_fail; - /* Did the VM-Entry fully enter the guest? */ - bool entered; - /* VM-Exit reason, valid iff !vm_fail */ - union exit_reason exit_reason; - /* Contents of [re]flags after failed entry. */ - unsigned long flags; -}; - -struct vmx_test { - const char *name; - int (*init)(struct vmcs *vmcs); - void (*guest_main)(void); - int (*exit_handler)(union exit_reason exit_reason); - void (*syscall_handler)(u64 syscall_no); - struct regs guest_regs; - int (*entry_failure_handler)(struct vmentry_result *result); - struct vmcs *vmcs; - int exits; - /* Alternative test interface. */ - void (*v2)(void); -}; - -union vmx_basic { - u64 val; - struct { - u32 revision; - u32 size:13, - reserved1: 3, - width:1, - dual:1, - type:4, - insouts:1, - ctrl:1, - reserved2:8; - }; -}; - -union vmx_ctrl_msr { - u64 val; - struct { - u32 set, clr; - }; -}; - -union vmx_misc { - u64 val; - struct { - u32 pt_bit:5, - stores_lma:1, - act_hlt:1, - act_shutdown:1, - act_wfsipi:1, - :5, - vmx_pt:1, - smm_smbase:1, - cr3_targets:9, - msr_list_size:3, - smm_mon_ctl:1, - vmwrite_any:1, - inject_len0:1, - :1; - u32 mseg_revision; - }; -}; - -union vmx_ept_vpid { - u64 val; - struct { - u32:16, - super:2, - : 2, - invept:1, - : 11; - u32 invvpid:1; - }; -}; - -enum Encoding { - /* 16-Bit Control Fields */ - VPID = 0x0000ul, - /* Posted-interrupt notification vector */ - PINV = 0x0002ul, - /* EPTP index */ - EPTP_IDX = 0x0004ul, - - /* 16-Bit Guest State Fields */ - GUEST_SEL_ES = 0x0800ul, - GUEST_SEL_CS = 0x0802ul, - GUEST_SEL_SS = 0x0804ul, - GUEST_SEL_DS = 0x0806ul, - GUEST_SEL_FS = 0x0808ul, - GUEST_SEL_GS = 0x080aul, - GUEST_SEL_LDTR = 0x080cul, - GUEST_SEL_TR = 0x080eul, - GUEST_INT_STATUS = 0x0810ul, - GUEST_PML_INDEX = 0x0812ul, - - /* 16-Bit Host State Fields */ - HOST_SEL_ES = 0x0c00ul, - HOST_SEL_CS = 0x0c02ul, - HOST_SEL_SS = 0x0c04ul, - HOST_SEL_DS = 0x0c06ul, - HOST_SEL_FS = 0x0c08ul, - HOST_SEL_GS = 0x0c0aul, - HOST_SEL_TR = 0x0c0cul, - - /* 64-Bit Control Fields */ - IO_BITMAP_A = 0x2000ul, - IO_BITMAP_B = 0x2002ul, - MSR_BITMAP = 0x2004ul, - EXIT_MSR_ST_ADDR = 0x2006ul, - EXIT_MSR_LD_ADDR = 0x2008ul, - ENTER_MSR_LD_ADDR = 0x200aul, - VMCS_EXEC_PTR = 0x200cul, - TSC_OFFSET = 0x2010ul, - TSC_OFFSET_HI = 0x2011ul, - APIC_VIRT_ADDR = 0x2012ul, - APIC_ACCS_ADDR = 0x2014ul, - POSTED_INTR_DESC_ADDR = 0x2016ul, - EPTP = 0x201aul, - EPTP_HI = 0x201bul, - VMREAD_BITMAP = 0x2026ul, - VMREAD_BITMAP_HI = 0x2027ul, - VMWRITE_BITMAP = 0x2028ul, - VMWRITE_BITMAP_HI = 0x2029ul, - EOI_EXIT_BITMAP0 = 0x201cul, - EOI_EXIT_BITMAP1 = 0x201eul, - EOI_EXIT_BITMAP2 = 0x2020ul, - EOI_EXIT_BITMAP3 = 0x2022ul, - PMLADDR = 0x200eul, - PMLADDR_HI = 0x200ful, - - - /* 64-Bit Readonly Data Field */ - INFO_PHYS_ADDR = 0x2400ul, - - /* 64-Bit Guest State */ - VMCS_LINK_PTR = 0x2800ul, - VMCS_LINK_PTR_HI = 0x2801ul, - GUEST_DEBUGCTL = 0x2802ul, - GUEST_DEBUGCTL_HI = 0x2803ul, - GUEST_EFER = 0x2806ul, - GUEST_PAT = 0x2804ul, - GUEST_PERF_GLOBAL_CTRL = 0x2808ul, - GUEST_PDPTE = 0x280aul, - GUEST_BNDCFGS = 0x2812ul, - - /* 64-Bit Host State */ - HOST_PAT = 0x2c00ul, - HOST_EFER = 0x2c02ul, - HOST_PERF_GLOBAL_CTRL = 0x2c04ul, - - /* 32-Bit Control Fields */ - PIN_CONTROLS = 0x4000ul, - CPU_EXEC_CTRL0 = 0x4002ul, - EXC_BITMAP = 0x4004ul, - PF_ERROR_MASK = 0x4006ul, - PF_ERROR_MATCH = 0x4008ul, - CR3_TARGET_COUNT = 0x400aul, - EXI_CONTROLS = 0x400cul, - EXI_MSR_ST_CNT = 0x400eul, - EXI_MSR_LD_CNT = 0x4010ul, - ENT_CONTROLS = 0x4012ul, - ENT_MSR_LD_CNT = 0x4014ul, - ENT_INTR_INFO = 0x4016ul, - ENT_INTR_ERROR = 0x4018ul, - ENT_INST_LEN = 0x401aul, - TPR_THRESHOLD = 0x401cul, - CPU_EXEC_CTRL1 = 0x401eul, - - /* 32-Bit R/O Data Fields */ - VMX_INST_ERROR = 0x4400ul, - EXI_REASON = 0x4402ul, - EXI_INTR_INFO = 0x4404ul, - EXI_INTR_ERROR = 0x4406ul, - IDT_VECT_INFO = 0x4408ul, - IDT_VECT_ERROR = 0x440aul, - EXI_INST_LEN = 0x440cul, - EXI_INST_INFO = 0x440eul, - - /* 32-Bit Guest State Fields */ - GUEST_LIMIT_ES = 0x4800ul, - GUEST_LIMIT_CS = 0x4802ul, - GUEST_LIMIT_SS = 0x4804ul, - GUEST_LIMIT_DS = 0x4806ul, - GUEST_LIMIT_FS = 0x4808ul, - GUEST_LIMIT_GS = 0x480aul, - GUEST_LIMIT_LDTR = 0x480cul, - GUEST_LIMIT_TR = 0x480eul, - GUEST_LIMIT_GDTR = 0x4810ul, - GUEST_LIMIT_IDTR = 0x4812ul, - GUEST_AR_ES = 0x4814ul, - GUEST_AR_CS = 0x4816ul, - GUEST_AR_SS = 0x4818ul, - GUEST_AR_DS = 0x481aul, - GUEST_AR_FS = 0x481cul, - GUEST_AR_GS = 0x481eul, - GUEST_AR_LDTR = 0x4820ul, - GUEST_AR_TR = 0x4822ul, - GUEST_INTR_STATE = 0x4824ul, - GUEST_ACTV_STATE = 0x4826ul, - GUEST_SMBASE = 0x4828ul, - GUEST_SYSENTER_CS = 0x482aul, - PREEMPT_TIMER_VALUE = 0x482eul, - - /* 32-Bit Host State Fields */ - HOST_SYSENTER_CS = 0x4c00ul, - - /* Natural-Width Control Fields */ - CR0_MASK = 0x6000ul, - CR4_MASK = 0x6002ul, - CR0_READ_SHADOW = 0x6004ul, - CR4_READ_SHADOW = 0x6006ul, - CR3_TARGET_0 = 0x6008ul, - CR3_TARGET_1 = 0x600aul, - CR3_TARGET_2 = 0x600cul, - CR3_TARGET_3 = 0x600eul, - - /* Natural-Width R/O Data Fields */ - EXI_QUALIFICATION = 0x6400ul, - IO_RCX = 0x6402ul, - IO_RSI = 0x6404ul, - IO_RDI = 0x6406ul, - IO_RIP = 0x6408ul, - GUEST_LINEAR_ADDRESS = 0x640aul, - - /* Natural-Width Guest State Fields */ - GUEST_CR0 = 0x6800ul, - GUEST_CR3 = 0x6802ul, - GUEST_CR4 = 0x6804ul, - GUEST_BASE_ES = 0x6806ul, - GUEST_BASE_CS = 0x6808ul, - GUEST_BASE_SS = 0x680aul, - GUEST_BASE_DS = 0x680cul, - GUEST_BASE_FS = 0x680eul, - GUEST_BASE_GS = 0x6810ul, - GUEST_BASE_LDTR = 0x6812ul, - GUEST_BASE_TR = 0x6814ul, - GUEST_BASE_GDTR = 0x6816ul, - GUEST_BASE_IDTR = 0x6818ul, - GUEST_DR7 = 0x681aul, - GUEST_RSP = 0x681cul, - GUEST_RIP = 0x681eul, - GUEST_RFLAGS = 0x6820ul, - GUEST_PENDING_DEBUG = 0x6822ul, - GUEST_SYSENTER_ESP = 0x6824ul, - GUEST_SYSENTER_EIP = 0x6826ul, - - /* Natural-Width Host State Fields */ - HOST_CR0 = 0x6c00ul, - HOST_CR3 = 0x6c02ul, - HOST_CR4 = 0x6c04ul, - HOST_BASE_FS = 0x6c06ul, - HOST_BASE_GS = 0x6c08ul, - HOST_BASE_TR = 0x6c0aul, - HOST_BASE_GDTR = 0x6c0cul, - HOST_BASE_IDTR = 0x6c0eul, - HOST_SYSENTER_ESP = 0x6c10ul, - HOST_SYSENTER_EIP = 0x6c12ul, - HOST_RSP = 0x6c14ul, - HOST_RIP = 0x6c16ul -}; - -#define VMX_ENTRY_FAILURE (1ul << 31) -#define VMX_ENTRY_FLAGS (X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF | \ - X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_OF) - -enum Reason { - VMX_EXC_NMI = 0, - VMX_EXTINT = 1, - VMX_TRIPLE_FAULT = 2, - VMX_INIT = 3, - VMX_SIPI = 4, - VMX_SMI_IO = 5, - VMX_SMI_OTHER = 6, - VMX_INTR_WINDOW = 7, - VMX_NMI_WINDOW = 8, - VMX_TASK_SWITCH = 9, - VMX_CPUID = 10, - VMX_GETSEC = 11, - VMX_HLT = 12, - VMX_INVD = 13, - VMX_INVLPG = 14, - VMX_RDPMC = 15, - VMX_RDTSC = 16, - VMX_RSM = 17, - VMX_VMCALL = 18, - VMX_VMCLEAR = 19, - VMX_VMLAUNCH = 20, - VMX_VMPTRLD = 21, - VMX_VMPTRST = 22, - VMX_VMREAD = 23, - VMX_VMRESUME = 24, - VMX_VMWRITE = 25, - VMX_VMXOFF = 26, - VMX_VMXON = 27, - VMX_CR = 28, - VMX_DR = 29, - VMX_IO = 30, - VMX_RDMSR = 31, - VMX_WRMSR = 32, - VMX_FAIL_STATE = 33, - VMX_FAIL_MSR = 34, - VMX_MWAIT = 36, - VMX_MTF = 37, - VMX_MONITOR = 39, - VMX_PAUSE = 40, - VMX_FAIL_MCHECK = 41, - VMX_TPR_THRESHOLD = 43, - VMX_APIC_ACCESS = 44, - VMX_EOI_INDUCED = 45, - VMX_GDTR_IDTR = 46, - VMX_LDTR_TR = 47, - VMX_EPT_VIOLATION = 48, - VMX_EPT_MISCONFIG = 49, - VMX_INVEPT = 50, - VMX_PREEMPT = 52, - VMX_INVVPID = 53, - VMX_WBINVD = 54, - VMX_XSETBV = 55, - VMX_APIC_WRITE = 56, - VMX_RDRAND = 57, - VMX_INVPCID = 58, - VMX_VMFUNC = 59, - VMX_RDSEED = 61, - VMX_PML_FULL = 62, - VMX_XSAVES = 63, - VMX_XRSTORS = 64, -}; - -enum Ctrl_exi { - EXI_SAVE_DBGCTLS = 1UL << 2, - EXI_HOST_64 = 1UL << 9, - EXI_LOAD_PERF = 1UL << 12, - EXI_INTA = 1UL << 15, - EXI_SAVE_PAT = 1UL << 18, - EXI_LOAD_PAT = 1UL << 19, - EXI_SAVE_EFER = 1UL << 20, - EXI_LOAD_EFER = 1UL << 21, - EXI_SAVE_PREEMPT = 1UL << 22, -}; - -enum Ctrl_ent { - ENT_LOAD_DBGCTLS = 1UL << 2, - ENT_GUEST_64 = 1UL << 9, - ENT_LOAD_PERF = 1UL << 13, - ENT_LOAD_PAT = 1UL << 14, - ENT_LOAD_EFER = 1UL << 15, - ENT_LOAD_BNDCFGS = 1UL << 16 -}; - -enum Ctrl_pin { - PIN_EXTINT = 1ul << 0, - PIN_NMI = 1ul << 3, - PIN_VIRT_NMI = 1ul << 5, - PIN_PREEMPT = 1ul << 6, - PIN_POST_INTR = 1ul << 7, -}; - -enum Ctrl0 { - CPU_INTR_WINDOW = 1ul << 2, - CPU_USE_TSC_OFFSET = 1ul << 3, - CPU_HLT = 1ul << 7, - CPU_INVLPG = 1ul << 9, - CPU_MWAIT = 1ul << 10, - CPU_RDPMC = 1ul << 11, - CPU_RDTSC = 1ul << 12, - CPU_CR3_LOAD = 1ul << 15, - CPU_CR3_STORE = 1ul << 16, - CPU_CR8_LOAD = 1ul << 19, - CPU_CR8_STORE = 1ul << 20, - CPU_TPR_SHADOW = 1ul << 21, - CPU_NMI_WINDOW = 1ul << 22, - CPU_IO = 1ul << 24, - CPU_IO_BITMAP = 1ul << 25, - CPU_MTF = 1ul << 27, - CPU_MSR_BITMAP = 1ul << 28, - CPU_MONITOR = 1ul << 29, - CPU_PAUSE = 1ul << 30, - CPU_SECONDARY = 1ul << 31, -}; - -enum Ctrl1 { - CPU_VIRT_APIC_ACCESSES = 1ul << 0, - CPU_EPT = 1ul << 1, - CPU_DESC_TABLE = 1ul << 2, - CPU_RDTSCP = 1ul << 3, - CPU_VIRT_X2APIC = 1ul << 4, - CPU_VPID = 1ul << 5, - CPU_WBINVD = 1ul << 6, - CPU_URG = 1ul << 7, - CPU_APIC_REG_VIRT = 1ul << 8, - CPU_VINTD = 1ul << 9, - CPU_RDRAND = 1ul << 11, - CPU_SHADOW_VMCS = 1ul << 14, - CPU_RDSEED = 1ul << 16, - CPU_PML = 1ul << 17, - CPU_USE_TSC_SCALING = 1ul << 25, -}; - -enum Intr_type { - VMX_INTR_TYPE_EXT_INTR = 0, - VMX_INTR_TYPE_NMI_INTR = 2, - VMX_INTR_TYPE_HARD_EXCEPTION = 3, - VMX_INTR_TYPE_SOFT_INTR = 4, - VMX_INTR_TYPE_SOFT_EXCEPTION = 6, -}; - -/* - * Interruption-information format - */ -#define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */ -#define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */ -#define INTR_INFO_DELIVER_CODE_MASK 0x800 /* 11 */ -#define INTR_INFO_UNBLOCK_NMI_MASK 0x1000 /* 12 */ -#define INTR_INFO_VALID_MASK 0x80000000 /* 31 */ - -#define INTR_INFO_INTR_TYPE_SHIFT 8 - -#define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */ -#define INTR_TYPE_RESERVED (1 << 8) /* reserved */ -#define INTR_TYPE_NMI_INTR (2 << 8) /* NMI */ -#define INTR_TYPE_HARD_EXCEPTION (3 << 8) /* processor exception */ -#define INTR_TYPE_SOFT_INTR (4 << 8) /* software interrupt */ -#define INTR_TYPE_PRIV_SW_EXCEPTION (5 << 8) /* priv. software exception */ -#define INTR_TYPE_SOFT_EXCEPTION (6 << 8) /* software exception */ -#define INTR_TYPE_OTHER_EVENT (7 << 8) /* other event */ - -/* - * Guest interruptibility state - */ -#define GUEST_INTR_STATE_STI (1 << 0) -#define GUEST_INTR_STATE_MOVSS (1 << 1) -#define GUEST_INTR_STATE_SMI (1 << 2) -#define GUEST_INTR_STATE_NMI (1 << 3) -#define GUEST_INTR_STATE_ENCLAVE (1 << 4) - -/* - * VM-instruction error numbers - */ -enum vm_instruction_error_number { - VMXERR_VMCALL_IN_VMX_ROOT_OPERATION = 1, - VMXERR_VMCLEAR_INVALID_ADDRESS = 2, - VMXERR_VMCLEAR_VMXON_POINTER = 3, - VMXERR_VMLAUNCH_NONCLEAR_VMCS = 4, - VMXERR_VMRESUME_NONLAUNCHED_VMCS = 5, - VMXERR_VMRESUME_AFTER_VMXOFF = 6, - VMXERR_ENTRY_INVALID_CONTROL_FIELD = 7, - VMXERR_ENTRY_INVALID_HOST_STATE_FIELD = 8, - VMXERR_VMPTRLD_INVALID_ADDRESS = 9, - VMXERR_VMPTRLD_VMXON_POINTER = 10, - VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID = 11, - VMXERR_UNSUPPORTED_VMCS_COMPONENT = 12, - VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT = 13, - VMXERR_VMXON_IN_VMX_ROOT_OPERATION = 15, - VMXERR_ENTRY_INVALID_EXECUTIVE_VMCS_POINTER = 16, - VMXERR_ENTRY_NONLAUNCHED_EXECUTIVE_VMCS = 17, - VMXERR_ENTRY_EXECUTIVE_VMCS_POINTER_NOT_VMXON_POINTER = 18, - VMXERR_VMCALL_NONCLEAR_VMCS = 19, - VMXERR_VMCALL_INVALID_VM_EXIT_CONTROL_FIELDS = 20, - VMXERR_VMCALL_INCORRECT_MSEG_REVISION_ID = 22, - VMXERR_VMXOFF_UNDER_DUAL_MONITOR_TREATMENT_OF_SMIS_AND_SMM = 23, - VMXERR_VMCALL_INVALID_SMM_MONITOR_FEATURES = 24, - VMXERR_ENTRY_INVALID_VM_EXECUTION_CONTROL_FIELDS_IN_EXECUTIVE_VMCS = 25, - VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS = 26, - VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID = 28, -}; - -enum vm_entry_failure_code { - ENTRY_FAIL_DEFAULT = 0, - ENTRY_FAIL_PDPTE = 2, - ENTRY_FAIL_NMI = 3, - ENTRY_FAIL_VMCS_LINK_PTR = 4, -}; - -#define SAVE_GPR \ - "xchg %rax, regs\n\t" \ - "xchg %rcx, regs+0x8\n\t" \ - "xchg %rdx, regs+0x10\n\t" \ - "xchg %rbx, regs+0x18\n\t" \ - "xchg %rbp, regs+0x28\n\t" \ - "xchg %rsi, regs+0x30\n\t" \ - "xchg %rdi, regs+0x38\n\t" \ - "xchg %r8, regs+0x40\n\t" \ - "xchg %r9, regs+0x48\n\t" \ - "xchg %r10, regs+0x50\n\t" \ - "xchg %r11, regs+0x58\n\t" \ - "xchg %r12, regs+0x60\n\t" \ - "xchg %r13, regs+0x68\n\t" \ - "xchg %r14, regs+0x70\n\t" \ - "xchg %r15, regs+0x78\n\t" - -#define LOAD_GPR SAVE_GPR - -#define SAVE_GPR_C \ - "xchg %%rax, regs\n\t" \ - "xchg %%rcx, regs+0x8\n\t" \ - "xchg %%rdx, regs+0x10\n\t" \ - "xchg %%rbx, regs+0x18\n\t" \ - "xchg %%rbp, regs+0x28\n\t" \ - "xchg %%rsi, regs+0x30\n\t" \ - "xchg %%rdi, regs+0x38\n\t" \ - "xchg %%r8, regs+0x40\n\t" \ - "xchg %%r9, regs+0x48\n\t" \ - "xchg %%r10, regs+0x50\n\t" \ - "xchg %%r11, regs+0x58\n\t" \ - "xchg %%r12, regs+0x60\n\t" \ - "xchg %%r13, regs+0x68\n\t" \ - "xchg %%r14, regs+0x70\n\t" \ - "xchg %%r15, regs+0x78\n\t" - -#define LOAD_GPR_C SAVE_GPR_C - -#define VMX_IO_SIZE_MASK 0x7 -#define _VMX_IO_BYTE 0 -#define _VMX_IO_WORD 1 -#define _VMX_IO_LONG 3 -#define VMX_IO_DIRECTION_MASK (1ul << 3) -#define VMX_IO_IN (1ul << 3) -#define VMX_IO_OUT 0 -#define VMX_IO_STRING (1ul << 4) -#define VMX_IO_REP (1ul << 5) -#define VMX_IO_OPRAND_IMM (1ul << 6) -#define VMX_IO_PORT_MASK 0xFFFF0000 -#define VMX_IO_PORT_SHIFT 16 - -#define VMX_TEST_START 0 -#define VMX_TEST_VMEXIT 1 -#define VMX_TEST_EXIT 2 -#define VMX_TEST_RESUME 3 -#define VMX_TEST_VMABORT 4 -#define VMX_TEST_VMSKIP 5 - -#define HYPERCALL_BIT (1ul << 12) -#define HYPERCALL_MASK 0xFFF -#define HYPERCALL_VMEXIT 0x1 -#define HYPERCALL_VMABORT 0x2 -#define HYPERCALL_VMSKIP 0x3 - -#define EPTP_PG_WALK_LEN_SHIFT 3ul -#define EPTP_PG_WALK_LEN_MASK 0x38ul -#define EPTP_RESERV_BITS_MASK 0x1ful -#define EPTP_RESERV_BITS_SHIFT 0x7ul -#define EPTP_AD_FLAG (1ul << 6) - -#define EPT_MEM_TYPE_UC 0ul -#define EPT_MEM_TYPE_WC 1ul -#define EPT_MEM_TYPE_WT 4ul -#define EPT_MEM_TYPE_WP 5ul -#define EPT_MEM_TYPE_WB 6ul - -#define EPT_RA 1ul -#define EPT_WA 2ul -#define EPT_EA 4ul -#define EPT_PRESENT (EPT_RA | EPT_WA | EPT_EA) -#define EPT_ACCESS_FLAG (1ul << 8) -#define EPT_DIRTY_FLAG (1ul << 9) -#define EPT_LARGE_PAGE (1ul << 7) -#define EPT_MEM_TYPE_SHIFT 3ul -#define EPT_MEM_TYPE_MASK 0x7ul -#define EPT_IGNORE_PAT (1ul << 6) -#define EPT_SUPPRESS_VE (1ull << 63) - -#define EPT_CAP_WT 1ull -#define EPT_CAP_PWL4 (1ull << 6) -#define EPT_CAP_PWL5 (1ull << 7) -#define EPT_CAP_UC (1ull << 8) -#define EPT_CAP_WB (1ull << 14) -#define EPT_CAP_2M_PAGE (1ull << 16) -#define EPT_CAP_1G_PAGE (1ull << 17) -#define EPT_CAP_INVEPT (1ull << 20) -#define EPT_CAP_AD_FLAG (1ull << 21) -#define EPT_CAP_ADV_EPT_INFO (1ull << 22) -#define EPT_CAP_INVEPT_SINGLE (1ull << 25) -#define EPT_CAP_INVEPT_ALL (1ull << 26) -#define VPID_CAP_INVVPID (1ull << 32) -#define VPID_CAP_INVVPID_ADDR (1ull << 40) -#define VPID_CAP_INVVPID_CXTGLB (1ull << 41) -#define VPID_CAP_INVVPID_ALL (1ull << 42) -#define VPID_CAP_INVVPID_CXTLOC (1ull << 43) - -#define PAGE_SIZE_2M (512 * PAGE_SIZE) -#define PAGE_SIZE_1G (512 * PAGE_SIZE_2M) -#define EPT_PAGE_LEVEL 4 -#define EPT_PGDIR_WIDTH 9 -#define EPT_PGDIR_MASK 511 -#define EPT_PGDIR_ENTRIES (1 << EPT_PGDIR_WIDTH) -#define EPT_LEVEL_SHIFT(level) (((level)-1) * EPT_PGDIR_WIDTH + 12) -#define EPT_ADDR_MASK GENMASK_ULL(51, 12) -#define PAGE_MASK_2M (~(PAGE_SIZE_2M-1)) - -#define EPT_VLT_RD (1ull << 0) -#define EPT_VLT_WR (1ull << 1) -#define EPT_VLT_FETCH (1ull << 2) -#define EPT_VLT_PERM_RD (1ull << 3) -#define EPT_VLT_PERM_WR (1ull << 4) -#define EPT_VLT_PERM_EX (1ull << 5) -#define EPT_VLT_PERM_USER_EX (1ull << 6) -#define EPT_VLT_PERMS (EPT_VLT_PERM_RD | EPT_VLT_PERM_WR | \ - EPT_VLT_PERM_EX) -#define EPT_VLT_LADDR_VLD (1ull << 7) -#define EPT_VLT_PADDR (1ull << 8) -#define EPT_VLT_GUEST_USER (1ull << 9) -#define EPT_VLT_GUEST_RW (1ull << 10) -#define EPT_VLT_GUEST_EX (1ull << 11) -#define EPT_VLT_GUEST_MASK (EPT_VLT_GUEST_USER | EPT_VLT_GUEST_RW | \ - EPT_VLT_GUEST_EX) - -#define MAGIC_VAL_1 0x12345678ul -#define MAGIC_VAL_2 0x87654321ul -#define MAGIC_VAL_3 0xfffffffful -#define MAGIC_VAL_4 0xdeadbeeful - -#define INVEPT_SINGLE 1 -#define INVEPT_GLOBAL 2 - -#define INVVPID_ADDR 0 -#define INVVPID_CONTEXT_GLOBAL 1 -#define INVVPID_ALL 2 -#define INVVPID_CONTEXT_LOCAL 3 - -#define ACTV_ACTIVE 0 -#define ACTV_HLT 1 - -/* - * VMCS field encoding: - * Bit 0: High-access - * Bits 1-9: Index - * Bits 10-12: Type - * Bits 13-15: Width - * Bits 15-64: Reserved - */ -#define VMCS_FIELD_HIGH_SHIFT (0) -#define VMCS_FIELD_INDEX_SHIFT (1) -#define VMCS_FIELD_INDEX_MASK GENMASK(9, 1) -#define VMCS_FIELD_TYPE_SHIFT (10) -#define VMCS_FIELD_WIDTH_SHIFT (13) -#define VMCS_FIELD_RESERVED_SHIFT (15) -#define VMCS_FIELD_BIT_SIZE (BITS_PER_LONG) - -extern struct regs regs; - -extern union vmx_basic basic; -extern union vmx_ctrl_msr ctrl_pin_rev; -extern union vmx_ctrl_msr ctrl_cpu_rev[2]; -extern union vmx_ctrl_msr ctrl_exit_rev; -extern union vmx_ctrl_msr ctrl_enter_rev; -extern union vmx_ept_vpid ept_vpid; - -extern u64 *bsp_vmxon_region; -extern bool launched; - -void vmx_set_test_stage(u32 s); -u32 vmx_get_test_stage(void); -void vmx_inc_test_stage(void); - -static int _vmx_on(u64 *vmxon_region) -{ - bool ret; - u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF; - asm volatile ("push %1; popf; vmxon %2; setbe %0\n\t" - : "=q" (ret) : "q" (rflags), "m" (vmxon_region) : "cc"); - return ret; -} - -static int vmx_on(void) -{ - return _vmx_on(bsp_vmxon_region); -} - -static int vmx_off(void) -{ - bool ret; - u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF; - - asm volatile("push %1; popf; vmxoff; setbe %0\n\t" - : "=q"(ret) : "q" (rflags) : "cc"); - return ret; -} - -static inline int make_vmcs_current(struct vmcs *vmcs) -{ - bool ret; - u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF; - - asm volatile ("push %1; popf; vmptrld %2; setbe %0" - : "=q" (ret) : "q" (rflags), "m" (vmcs) : "cc"); - return ret; -} - -static inline int vmcs_clear(struct vmcs *vmcs) -{ - bool ret; - u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF; - - asm volatile ("push %1; popf; vmclear %2; setbe %0" - : "=q" (ret) : "q" (rflags), "m" (vmcs) : "cc"); - return ret; -} - -static inline u64 vmcs_read(enum Encoding enc) -{ - u64 val; - asm volatile ("vmread %1, %0" : "=rm" (val) : "r" ((u64)enc) : "cc"); - return val; -} - -static inline int vmcs_read_checking(enum Encoding enc, u64 *value) -{ - u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF; - u64 encoding = enc; - u64 val; - - asm volatile ("shl $8, %%rax;" - "sahf;" - "vmread %[encoding], %[val];" - "lahf;" - "shr $8, %%rax" - : /* output */ [val]"=rm"(val), "+a"(rflags) - : /* input */ [encoding]"r"(encoding) - : /* clobber */ "cc"); - - *value = val; - return rflags & (X86_EFLAGS_CF | X86_EFLAGS_ZF); -} - -static inline int vmcs_write(enum Encoding enc, u64 val) -{ - bool ret; - asm volatile ("vmwrite %1, %2; setbe %0" - : "=q"(ret) : "rm" (val), "r" ((u64)enc) : "cc"); - return ret; -} - -static inline int vmcs_set_bits(enum Encoding enc, u64 val) -{ - return vmcs_write(enc, vmcs_read(enc) | val); -} - -static inline int vmcs_clear_bits(enum Encoding enc, u64 val) -{ - return vmcs_write(enc, vmcs_read(enc) & ~val); -} - -static inline int vmcs_save(struct vmcs **vmcs) -{ - bool ret; - unsigned long pa; - u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF; - - asm volatile ("push %2; popf; vmptrst %1; setbe %0" - : "=q" (ret), "=m" (pa) : "r" (rflags) : "cc"); - *vmcs = (pa == -1ull) ? NULL : phys_to_virt(pa); - return ret; -} - -static inline bool invept(unsigned long type, u64 eptp) -{ - bool ret; - u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF; - - struct { - u64 eptp, gpa; - } operand = {eptp, 0}; - asm volatile("push %1; popf; invept %2, %3; setbe %0" - : "=q" (ret) : "r" (rflags), "m"(operand),"r"(type) : "cc"); - return ret; -} - -static inline bool invvpid(unsigned long type, u64 vpid, u64 gla) -{ - bool ret; - u64 rflags = read_rflags() | X86_EFLAGS_CF | X86_EFLAGS_ZF; - - struct invvpid_operand operand = {vpid, gla}; - asm volatile("push %1; popf; invvpid %2, %3; setbe %0" - : "=q" (ret) : "r" (rflags), "m"(operand),"r"(type) : "cc"); - return ret; -} - -void enable_vmx(void); -void init_vmx(u64 *vmxon_region); - -const char *exit_reason_description(u64 reason); -void print_vmexit_info(union exit_reason exit_reason); -void print_vmentry_failure_info(struct vmentry_result *result); -void ept_sync(int type, u64 eptp); -void vpid_sync(int type, u16 vpid); -void install_ept_entry(unsigned long *pml4, int pte_level, - unsigned long guest_addr, unsigned long pte, - unsigned long *pt_page); -void install_1g_ept(unsigned long *pml4, unsigned long phys, - unsigned long guest_addr, u64 perm); -void install_2m_ept(unsigned long *pml4, unsigned long phys, - unsigned long guest_addr, u64 perm); -void install_ept(unsigned long *pml4, unsigned long phys, - unsigned long guest_addr, u64 perm); -void setup_ept_range(unsigned long *pml4, unsigned long start, - unsigned long len, int map_1g, int map_2m, u64 perm); -bool get_ept_pte(unsigned long *pml4, unsigned long guest_addr, int level, - unsigned long *pte); -void set_ept_pte(unsigned long *pml4, unsigned long guest_addr, - int level, u64 pte_val); -void check_ept_ad(unsigned long *pml4, u64 guest_cr3, - unsigned long guest_addr, int expected_gpa_ad, - int expected_pt_ad); -void clear_ept_ad(unsigned long *pml4, u64 guest_cr3, - unsigned long guest_addr); - -bool ept_2m_supported(void); -bool ept_1g_supported(void); -bool ept_huge_pages_supported(int level); -bool ept_execute_only_supported(void); -bool ept_ad_bits_supported(void); - -#define ABORT_ON_EARLY_VMENTRY_FAIL 0x1 -#define ABORT_ON_INVALID_GUEST_STATE 0x2 - -void __enter_guest(u8 abort_flag, struct vmentry_result *result); -void enter_guest(void); -void enter_guest_with_bad_controls(void); - -typedef void (*test_guest_func)(void); -typedef void (*test_teardown_func)(void *data); -void test_set_guest(test_guest_func func); -void test_add_teardown(test_teardown_func func, void *data); -void test_skip(const char *msg); - -void __abort_test(void); - -#define TEST_ASSERT(cond) \ -do { \ - if (!(cond)) { \ - report(0, "%s:%d: Assertion failed: %s", \ - __FILE__, __LINE__, #cond); \ - dump_stack(); \ - __abort_test(); \ - } \ - report_pass(); \ -} while (0) - -#define TEST_ASSERT_MSG(cond, fmt, args...) \ -do { \ - if (!(cond)) { \ - report(0, "%s:%d: Assertion failed: %s\n" fmt, \ - __FILE__, __LINE__, #cond, ##args); \ - dump_stack(); \ - __abort_test(); \ - } \ - report_pass(); \ -} while (0) - -#define __TEST_EQ(a, b, a_str, b_str, assertion, fmt, args...) \ -do { \ - typeof(a) _a = a; \ - typeof(b) _b = b; \ - if (_a != _b) { \ - char _bin_a[BINSTR_SZ]; \ - char _bin_b[BINSTR_SZ]; \ - binstr(_a, _bin_a); \ - binstr(_b, _bin_b); \ - report(0, \ - "%s:%d: %s failed: (%s) == (%s)\n" \ - "\tLHS: %#018lx - %s - %lu\n" \ - "\tRHS: %#018lx - %s - %lu%s" fmt, \ - __FILE__, __LINE__, \ - assertion ? "Assertion" : "Expectation", a_str, b_str, \ - (unsigned long) _a, _bin_a, (unsigned long) _a, \ - (unsigned long) _b, _bin_b, (unsigned long) _b, \ - fmt[0] == '\0' ? "" : "\n", ## args); \ - dump_stack(); \ - if (assertion) \ - __abort_test(); \ - } \ - report_pass(); \ -} while (0) - -#define TEST_ASSERT_EQ(a, b) __TEST_EQ(a, b, #a, #b, 1, "") -#define TEST_ASSERT_EQ_MSG(a, b, fmt, args...) \ - __TEST_EQ(a, b, #a, #b, 1, fmt, ## args) -#define TEST_EXPECT_EQ(a, b) __TEST_EQ(a, b, #a, #b, 0, "") -#define TEST_EXPECT_EQ_MSG(a, b, fmt, args...) \ - __TEST_EQ(a, b, #a, #b, 0, fmt, ## args) - -#endif diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c deleted file mode 100644 index 29f3d0ee..00000000 --- a/x86/vmx_tests.c +++ /dev/null @@ -1,10111 +0,0 @@ -/* - * All test cases of nested virtualization should be in this file - * - * Author : Arthur Chunqi Li - */ - -#include - -#include "vmx.h" -#include "msr.h" -#include "processor.h" -#include "vm.h" -#include "pci.h" -#include "fwcfg.h" -#include "isr.h" -#include "desc.h" -#include "apic.h" -#include "types.h" -#include "vmalloc.h" -#include "alloc_page.h" -#include "smp.h" -#include "delay.h" - -#define NONCANONICAL 0xaaaaaaaaaaaaaaaaull - -#define VPID_CAP_INVVPID_TYPES_SHIFT 40 - -u64 ia32_pat; -u64 ia32_efer; -void *io_bitmap_a, *io_bitmap_b; -u16 ioport; - -unsigned long *pml4; -u64 eptp; -void *data_page1, *data_page2; - -phys_addr_t pci_physaddr; - -void *pml_log; -#define PML_INDEX 512 - -static inline unsigned ffs(unsigned x) -{ - int pos = -1; - - __asm__ __volatile__("bsf %1, %%eax; cmovnz %%eax, %0" - : "+r"(pos) : "rm"(x) : "eax"); - return pos + 1; -} - -static inline void vmcall(void) -{ - asm volatile("vmcall"); -} - -static void basic_guest_main(void) -{ - report(1, "Basic VMX test"); -} - -static int basic_exit_handler(union exit_reason exit_reason) -{ - report(0, "Basic VMX test"); - print_vmexit_info(exit_reason); - return VMX_TEST_EXIT; -} - -static void vmenter_main(void) -{ - u64 rax; - u64 rsp, resume_rsp; - - report(1, "test vmlaunch"); - - asm volatile( - "mov %%rsp, %0\n\t" - "mov %3, %%rax\n\t" - "vmcall\n\t" - "mov %%rax, %1\n\t" - "mov %%rsp, %2\n\t" - : "=r"(rsp), "=r"(rax), "=r"(resume_rsp) - : "g"(0xABCD)); - report((rax == 0xFFFF) && (rsp == resume_rsp), "test vmresume"); -} - -static int vmenter_exit_handler(union exit_reason exit_reason) -{ - u64 guest_rip = vmcs_read(GUEST_RIP); - - switch (exit_reason.basic) { - case VMX_VMCALL: - if (regs.rax != 0xABCD) { - report(0, "test vmresume"); - return VMX_TEST_VMEXIT; - } - regs.rax = 0xFFFF; - vmcs_write(GUEST_RIP, guest_rip + 3); - return VMX_TEST_RESUME; - default: - report(0, "test vmresume"); - print_vmexit_info(exit_reason); - } - return VMX_TEST_VMEXIT; -} - -u32 preempt_scale; -volatile unsigned long long tsc_val; -volatile u32 preempt_val; -u64 saved_rip; - -static int preemption_timer_init(struct vmcs *vmcs) -{ - if (!(ctrl_pin_rev.clr & PIN_PREEMPT)) { - printf("\tPreemption timer is not supported\n"); - return VMX_TEST_EXIT; - } - vmcs_write(PIN_CONTROLS, vmcs_read(PIN_CONTROLS) | PIN_PREEMPT); - preempt_val = 10000000; - vmcs_write(PREEMPT_TIMER_VALUE, preempt_val); - preempt_scale = rdmsr(MSR_IA32_VMX_MISC) & 0x1F; - - if (!(ctrl_exit_rev.clr & EXI_SAVE_PREEMPT)) - printf("\tSave preemption value is not supported\n"); - - return VMX_TEST_START; -} - -static void preemption_timer_main(void) -{ - tsc_val = rdtsc(); - if (ctrl_exit_rev.clr & EXI_SAVE_PREEMPT) { - vmx_set_test_stage(0); - vmcall(); - if (vmx_get_test_stage() == 1) - vmcall(); - } - vmx_set_test_stage(1); - while (vmx_get_test_stage() == 1) { - if (((rdtsc() - tsc_val) >> preempt_scale) - > 10 * preempt_val) { - vmx_set_test_stage(2); - vmcall(); - } - } - tsc_val = rdtsc(); - asm volatile ("hlt"); - vmcall(); - vmx_set_test_stage(5); - vmcall(); -} - -static int preemption_timer_exit_handler(union exit_reason exit_reason) -{ - bool guest_halted; - u64 guest_rip; - u32 insn_len; - u32 ctrl_exit; - - guest_rip = vmcs_read(GUEST_RIP); - insn_len = vmcs_read(EXI_INST_LEN); - switch (exit_reason.basic) { - case VMX_PREEMPT: - switch (vmx_get_test_stage()) { - case 1: - case 2: - report(((rdtsc() - tsc_val) >> preempt_scale) >= preempt_val, - "busy-wait for preemption timer"); - vmx_set_test_stage(3); - vmcs_write(PREEMPT_TIMER_VALUE, preempt_val); - return VMX_TEST_RESUME; - case 3: - guest_halted = - (vmcs_read(GUEST_ACTV_STATE) == ACTV_HLT); - report(((rdtsc() - tsc_val) >> preempt_scale) >= preempt_val - && guest_halted, - "preemption timer during hlt"); - vmx_set_test_stage(4); - vmcs_write(PIN_CONTROLS, - vmcs_read(PIN_CONTROLS) & ~PIN_PREEMPT); - vmcs_write(EXI_CONTROLS, - vmcs_read(EXI_CONTROLS) & ~EXI_SAVE_PREEMPT); - vmcs_write(GUEST_ACTV_STATE, ACTV_ACTIVE); - return VMX_TEST_RESUME; - case 4: - report(saved_rip == guest_rip, - "preemption timer with 0 value"); - break; - default: - report(false, "Invalid stage."); - print_vmexit_info(exit_reason); - break; - } - break; - case VMX_VMCALL: - vmcs_write(GUEST_RIP, guest_rip + insn_len); - switch (vmx_get_test_stage()) { - case 0: - report(vmcs_read(PREEMPT_TIMER_VALUE) == preempt_val, - "Keep preemption value"); - vmx_set_test_stage(1); - vmcs_write(PREEMPT_TIMER_VALUE, preempt_val); - ctrl_exit = (vmcs_read(EXI_CONTROLS) | - EXI_SAVE_PREEMPT) & ctrl_exit_rev.clr; - vmcs_write(EXI_CONTROLS, ctrl_exit); - return VMX_TEST_RESUME; - case 1: - report(vmcs_read(PREEMPT_TIMER_VALUE) < preempt_val, - "Save preemption value"); - return VMX_TEST_RESUME; - case 2: - report(0, "busy-wait for preemption timer"); - vmx_set_test_stage(3); - vmcs_write(PREEMPT_TIMER_VALUE, preempt_val); - return VMX_TEST_RESUME; - case 3: - report(0, "preemption timer during hlt"); - vmx_set_test_stage(4); - /* fall through */ - case 4: - vmcs_write(PIN_CONTROLS, - vmcs_read(PIN_CONTROLS) | PIN_PREEMPT); - vmcs_write(PREEMPT_TIMER_VALUE, 0); - saved_rip = guest_rip + insn_len; - return VMX_TEST_RESUME; - case 5: - report(0, - "preemption timer with 0 value (vmcall stage 5)"); - break; - default: - // Should not reach here - report(false, "unexpected stage, %d", - vmx_get_test_stage()); - print_vmexit_info(exit_reason); - return VMX_TEST_VMEXIT; - } - break; - default: - report(false, "Unknown exit reason, 0x%x", exit_reason.full); - print_vmexit_info(exit_reason); - } - vmcs_write(PIN_CONTROLS, vmcs_read(PIN_CONTROLS) & ~PIN_PREEMPT); - return VMX_TEST_VMEXIT; -} - -static void msr_bmp_init(void) -{ - void *msr_bitmap; - u32 ctrl_cpu0; - - msr_bitmap = alloc_page(); - ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0); - ctrl_cpu0 |= CPU_MSR_BITMAP; - vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0); - vmcs_write(MSR_BITMAP, (u64)msr_bitmap); -} - -static void *get_msr_bitmap(void) -{ - void *msr_bitmap; - - if (vmcs_read(CPU_EXEC_CTRL0) & CPU_MSR_BITMAP) { - msr_bitmap = (void *)vmcs_read(MSR_BITMAP); - } else { - msr_bitmap = alloc_page(); - memset(msr_bitmap, 0xff, PAGE_SIZE); - vmcs_write(MSR_BITMAP, (u64)msr_bitmap); - vmcs_set_bits(CPU_EXEC_CTRL0, CPU_MSR_BITMAP); - } - - return msr_bitmap; -} - -static void disable_intercept_for_x2apic_msrs(void) -{ - unsigned long *msr_bitmap = (unsigned long *)get_msr_bitmap(); - u32 msr; - - for (msr = APIC_BASE_MSR; - msr < (APIC_BASE_MSR+0xff); - msr += BITS_PER_LONG) { - unsigned int word = msr / BITS_PER_LONG; - - msr_bitmap[word] = 0; - msr_bitmap[word + (0x800 / sizeof(long))] = 0; - } -} - -static int test_ctrl_pat_init(struct vmcs *vmcs) -{ - u64 ctrl_ent; - u64 ctrl_exi; - - msr_bmp_init(); - if (!(ctrl_exit_rev.clr & EXI_SAVE_PAT) && - !(ctrl_exit_rev.clr & EXI_LOAD_PAT) && - !(ctrl_enter_rev.clr & ENT_LOAD_PAT)) { - printf("\tSave/load PAT is not supported\n"); - return 1; - } - - ctrl_ent = vmcs_read(ENT_CONTROLS); - ctrl_exi = vmcs_read(EXI_CONTROLS); - ctrl_ent |= ctrl_enter_rev.clr & ENT_LOAD_PAT; - ctrl_exi |= ctrl_exit_rev.clr & (EXI_SAVE_PAT | EXI_LOAD_PAT); - vmcs_write(ENT_CONTROLS, ctrl_ent); - vmcs_write(EXI_CONTROLS, ctrl_exi); - ia32_pat = rdmsr(MSR_IA32_CR_PAT); - vmcs_write(GUEST_PAT, 0x0); - vmcs_write(HOST_PAT, ia32_pat); - return VMX_TEST_START; -} - -static void test_ctrl_pat_main(void) -{ - u64 guest_ia32_pat; - - guest_ia32_pat = rdmsr(MSR_IA32_CR_PAT); - if (!(ctrl_enter_rev.clr & ENT_LOAD_PAT)) - printf("\tENT_LOAD_PAT is not supported.\n"); - else { - if (guest_ia32_pat != 0) { - report(0, "Entry load PAT"); - return; - } - } - wrmsr(MSR_IA32_CR_PAT, 0x6); - vmcall(); - guest_ia32_pat = rdmsr(MSR_IA32_CR_PAT); - if (ctrl_enter_rev.clr & ENT_LOAD_PAT) - report(guest_ia32_pat == ia32_pat, "Entry load PAT"); -} - -static int test_ctrl_pat_exit_handler(union exit_reason exit_reason) -{ - u64 guest_rip; - u64 guest_pat; - - guest_rip = vmcs_read(GUEST_RIP); - switch (exit_reason.basic) { - case VMX_VMCALL: - guest_pat = vmcs_read(GUEST_PAT); - if (!(ctrl_exit_rev.clr & EXI_SAVE_PAT)) { - printf("\tEXI_SAVE_PAT is not supported\n"); - vmcs_write(GUEST_PAT, 0x6); - } else { - report(guest_pat == 0x6, "Exit save PAT"); - } - if (!(ctrl_exit_rev.clr & EXI_LOAD_PAT)) - printf("\tEXI_LOAD_PAT is not supported\n"); - else - report(rdmsr(MSR_IA32_CR_PAT) == ia32_pat, - "Exit load PAT"); - vmcs_write(GUEST_PAT, ia32_pat); - vmcs_write(GUEST_RIP, guest_rip + 3); - return VMX_TEST_RESUME; - default: - printf("ERROR : Unknown exit reason, 0x%x.\n", exit_reason.full); - break; - } - return VMX_TEST_VMEXIT; -} - -static int test_ctrl_efer_init(struct vmcs *vmcs) -{ - u64 ctrl_ent; - u64 ctrl_exi; - - msr_bmp_init(); - ctrl_ent = vmcs_read(ENT_CONTROLS) | ENT_LOAD_EFER; - ctrl_exi = vmcs_read(EXI_CONTROLS) | EXI_SAVE_EFER | EXI_LOAD_EFER; - vmcs_write(ENT_CONTROLS, ctrl_ent & ctrl_enter_rev.clr); - vmcs_write(EXI_CONTROLS, ctrl_exi & ctrl_exit_rev.clr); - ia32_efer = rdmsr(MSR_EFER); - vmcs_write(GUEST_EFER, ia32_efer ^ EFER_NX); - vmcs_write(HOST_EFER, ia32_efer ^ EFER_NX); - return VMX_TEST_START; -} - -static void test_ctrl_efer_main(void) -{ - u64 guest_ia32_efer; - - guest_ia32_efer = rdmsr(MSR_EFER); - if (!(ctrl_enter_rev.clr & ENT_LOAD_EFER)) - printf("\tENT_LOAD_EFER is not supported.\n"); - else { - if (guest_ia32_efer != (ia32_efer ^ EFER_NX)) { - report(0, "Entry load EFER"); - return; - } - } - wrmsr(MSR_EFER, ia32_efer); - vmcall(); - guest_ia32_efer = rdmsr(MSR_EFER); - if (ctrl_enter_rev.clr & ENT_LOAD_EFER) - report(guest_ia32_efer == ia32_efer, "Entry load EFER"); -} - -static int test_ctrl_efer_exit_handler(union exit_reason exit_reason) -{ - u64 guest_rip; - u64 guest_efer; - - guest_rip = vmcs_read(GUEST_RIP); - switch (exit_reason.basic) { - case VMX_VMCALL: - guest_efer = vmcs_read(GUEST_EFER); - if (!(ctrl_exit_rev.clr & EXI_SAVE_EFER)) { - printf("\tEXI_SAVE_EFER is not supported\n"); - vmcs_write(GUEST_EFER, ia32_efer); - } else { - report(guest_efer == ia32_efer, "Exit save EFER"); - } - if (!(ctrl_exit_rev.clr & EXI_LOAD_EFER)) { - printf("\tEXI_LOAD_EFER is not supported\n"); - wrmsr(MSR_EFER, ia32_efer ^ EFER_NX); - } else { - report(rdmsr(MSR_EFER) == (ia32_efer ^ EFER_NX), - "Exit load EFER"); - } - vmcs_write(GUEST_PAT, ia32_efer); - vmcs_write(GUEST_RIP, guest_rip + 3); - return VMX_TEST_RESUME; - default: - printf("ERROR : Unknown exit reason, 0x%x.\n", exit_reason.full); - break; - } - return VMX_TEST_VMEXIT; -} - -u32 guest_cr0, guest_cr4; - -static void cr_shadowing_main(void) -{ - u32 cr0, cr4, tmp; - - // Test read through - vmx_set_test_stage(0); - guest_cr0 = read_cr0(); - if (vmx_get_test_stage() == 1) - report(0, "Read through CR0"); - else - vmcall(); - vmx_set_test_stage(1); - guest_cr4 = read_cr4(); - if (vmx_get_test_stage() == 2) - report(0, "Read through CR4"); - else - vmcall(); - // Test write through - guest_cr0 = guest_cr0 ^ (X86_CR0_TS | X86_CR0_MP); - guest_cr4 = guest_cr4 ^ (X86_CR4_TSD | X86_CR4_DE); - vmx_set_test_stage(2); - write_cr0(guest_cr0); - if (vmx_get_test_stage() == 3) - report(0, "Write throuth CR0"); - else - vmcall(); - vmx_set_test_stage(3); - write_cr4(guest_cr4); - if (vmx_get_test_stage() == 4) - report(0, "Write through CR4"); - else - vmcall(); - // Test read shadow - vmx_set_test_stage(4); - vmcall(); - cr0 = read_cr0(); - if (vmx_get_test_stage() != 5) - report(cr0 == guest_cr0, "Read shadowing CR0"); - vmx_set_test_stage(5); - cr4 = read_cr4(); - if (vmx_get_test_stage() != 6) - report(cr4 == guest_cr4, "Read shadowing CR4"); - // Test write shadow (same value with shadow) - vmx_set_test_stage(6); - write_cr0(guest_cr0); - if (vmx_get_test_stage() == 7) - report(0, "Write shadowing CR0 (same value with shadow)"); - else - vmcall(); - vmx_set_test_stage(7); - write_cr4(guest_cr4); - if (vmx_get_test_stage() == 8) - report(0, "Write shadowing CR4 (same value with shadow)"); - else - vmcall(); - // Test write shadow (different value) - vmx_set_test_stage(8); - tmp = guest_cr0 ^ X86_CR0_TS; - asm volatile("mov %0, %%rsi\n\t" - "mov %%rsi, %%cr0\n\t" - ::"m"(tmp) - :"rsi", "memory", "cc"); - report(vmx_get_test_stage() == 9, - "Write shadowing different X86_CR0_TS"); - vmx_set_test_stage(9); - tmp = guest_cr0 ^ X86_CR0_MP; - asm volatile("mov %0, %%rsi\n\t" - "mov %%rsi, %%cr0\n\t" - ::"m"(tmp) - :"rsi", "memory", "cc"); - report(vmx_get_test_stage() == 10, - "Write shadowing different X86_CR0_MP"); - vmx_set_test_stage(10); - tmp = guest_cr4 ^ X86_CR4_TSD; - asm volatile("mov %0, %%rsi\n\t" - "mov %%rsi, %%cr4\n\t" - ::"m"(tmp) - :"rsi", "memory", "cc"); - report(vmx_get_test_stage() == 11, - "Write shadowing different X86_CR4_TSD"); - vmx_set_test_stage(11); - tmp = guest_cr4 ^ X86_CR4_DE; - asm volatile("mov %0, %%rsi\n\t" - "mov %%rsi, %%cr4\n\t" - ::"m"(tmp) - :"rsi", "memory", "cc"); - report(vmx_get_test_stage() == 12, - "Write shadowing different X86_CR4_DE"); -} - -static int cr_shadowing_exit_handler(union exit_reason exit_reason) -{ - u64 guest_rip; - u32 insn_len; - u32 exit_qual; - - guest_rip = vmcs_read(GUEST_RIP); - insn_len = vmcs_read(EXI_INST_LEN); - exit_qual = vmcs_read(EXI_QUALIFICATION); - switch (exit_reason.basic) { - case VMX_VMCALL: - switch (vmx_get_test_stage()) { - case 0: - report(guest_cr0 == vmcs_read(GUEST_CR0), - "Read through CR0"); - break; - case 1: - report(guest_cr4 == vmcs_read(GUEST_CR4), - "Read through CR4"); - break; - case 2: - report(guest_cr0 == vmcs_read(GUEST_CR0), - "Write through CR0"); - break; - case 3: - report(guest_cr4 == vmcs_read(GUEST_CR4), - "Write through CR4"); - break; - case 4: - guest_cr0 = vmcs_read(GUEST_CR0) ^ (X86_CR0_TS | X86_CR0_MP); - guest_cr4 = vmcs_read(GUEST_CR4) ^ (X86_CR4_TSD | X86_CR4_DE); - vmcs_write(CR0_MASK, X86_CR0_TS | X86_CR0_MP); - vmcs_write(CR0_READ_SHADOW, guest_cr0 & (X86_CR0_TS | X86_CR0_MP)); - vmcs_write(CR4_MASK, X86_CR4_TSD | X86_CR4_DE); - vmcs_write(CR4_READ_SHADOW, guest_cr4 & (X86_CR4_TSD | X86_CR4_DE)); - break; - case 6: - report(guest_cr0 == (vmcs_read(GUEST_CR0) ^ (X86_CR0_TS | X86_CR0_MP)), - "Write shadowing CR0 (same value)"); - break; - case 7: - report(guest_cr4 == (vmcs_read(GUEST_CR4) ^ (X86_CR4_TSD | X86_CR4_DE)), - "Write shadowing CR4 (same value)"); - break; - default: - // Should not reach here - report(false, "unexpected stage, %d", - vmx_get_test_stage()); - print_vmexit_info(exit_reason); - return VMX_TEST_VMEXIT; - } - vmcs_write(GUEST_RIP, guest_rip + insn_len); - return VMX_TEST_RESUME; - case VMX_CR: - switch (vmx_get_test_stage()) { - case 4: - report(0, "Read shadowing CR0"); - vmx_inc_test_stage(); - break; - case 5: - report(0, "Read shadowing CR4"); - vmx_inc_test_stage(); - break; - case 6: - report(0, "Write shadowing CR0 (same value)"); - vmx_inc_test_stage(); - break; - case 7: - report(0, "Write shadowing CR4 (same value)"); - vmx_inc_test_stage(); - break; - case 8: - case 9: - // 0x600 encodes "mov %esi, %cr0" - if (exit_qual == 0x600) - vmx_inc_test_stage(); - break; - case 10: - case 11: - // 0x604 encodes "mov %esi, %cr4" - if (exit_qual == 0x604) - vmx_inc_test_stage(); - break; - default: - // Should not reach here - report(false, "unexpected stage, %d", - vmx_get_test_stage()); - print_vmexit_info(exit_reason); - return VMX_TEST_VMEXIT; - } - vmcs_write(GUEST_RIP, guest_rip + insn_len); - return VMX_TEST_RESUME; - default: - report(false, "Unknown exit reason, 0x%x", exit_reason.full); - print_vmexit_info(exit_reason); - } - return VMX_TEST_VMEXIT; -} - -static int iobmp_init(struct vmcs *vmcs) -{ - u32 ctrl_cpu0; - - io_bitmap_a = alloc_page(); - io_bitmap_b = alloc_page(); - ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0); - ctrl_cpu0 |= CPU_IO_BITMAP; - ctrl_cpu0 &= (~CPU_IO); - vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0); - vmcs_write(IO_BITMAP_A, (u64)io_bitmap_a); - vmcs_write(IO_BITMAP_B, (u64)io_bitmap_b); - return VMX_TEST_START; -} - -static void iobmp_main(void) -{ - // stage 0, test IO pass - vmx_set_test_stage(0); - inb(0x5000); - outb(0x0, 0x5000); - report(vmx_get_test_stage() == 0, "I/O bitmap - I/O pass"); - // test IO width, in/out - ((u8 *)io_bitmap_a)[0] = 0xFF; - vmx_set_test_stage(2); - inb(0x0); - report(vmx_get_test_stage() == 3, "I/O bitmap - trap in"); - vmx_set_test_stage(3); - outw(0x0, 0x0); - report(vmx_get_test_stage() == 4, "I/O bitmap - trap out"); - vmx_set_test_stage(4); - inl(0x0); - report(vmx_get_test_stage() == 5, "I/O bitmap - I/O width, long"); - // test low/high IO port - vmx_set_test_stage(5); - ((u8 *)io_bitmap_a)[0x5000 / 8] = (1 << (0x5000 % 8)); - inb(0x5000); - report(vmx_get_test_stage() == 6, "I/O bitmap - I/O port, low part"); - vmx_set_test_stage(6); - ((u8 *)io_bitmap_b)[0x1000 / 8] = (1 << (0x1000 % 8)); - inb(0x9000); - report(vmx_get_test_stage() == 7, "I/O bitmap - I/O port, high part"); - // test partial pass - vmx_set_test_stage(7); - inl(0x4FFF); - report(vmx_get_test_stage() == 8, "I/O bitmap - partial pass"); - // test overrun - vmx_set_test_stage(8); - memset(io_bitmap_a, 0x0, PAGE_SIZE); - memset(io_bitmap_b, 0x0, PAGE_SIZE); - inl(0xFFFF); - report(vmx_get_test_stage() == 9, "I/O bitmap - overrun"); - vmx_set_test_stage(9); - vmcall(); - outb(0x0, 0x0); - report(vmx_get_test_stage() == 9, - "I/O bitmap - ignore unconditional exiting"); - vmx_set_test_stage(10); - vmcall(); - outb(0x0, 0x0); - report(vmx_get_test_stage() == 11, - "I/O bitmap - unconditional exiting"); -} - -static int iobmp_exit_handler(union exit_reason exit_reason) -{ - u64 guest_rip; - ulong exit_qual; - u32 insn_len, ctrl_cpu0; - - guest_rip = vmcs_read(GUEST_RIP); - exit_qual = vmcs_read(EXI_QUALIFICATION); - insn_len = vmcs_read(EXI_INST_LEN); - switch (exit_reason.basic) { - case VMX_IO: - switch (vmx_get_test_stage()) { - case 0: - case 1: - vmx_inc_test_stage(); - break; - case 2: - report((exit_qual & VMX_IO_SIZE_MASK) == _VMX_IO_BYTE, - "I/O bitmap - I/O width, byte"); - report(exit_qual & VMX_IO_IN, - "I/O bitmap - I/O direction, in"); - vmx_inc_test_stage(); - break; - case 3: - report((exit_qual & VMX_IO_SIZE_MASK) == _VMX_IO_WORD, - "I/O bitmap - I/O width, word"); - report(!(exit_qual & VMX_IO_IN), - "I/O bitmap - I/O direction, out"); - vmx_inc_test_stage(); - break; - case 4: - report((exit_qual & VMX_IO_SIZE_MASK) == _VMX_IO_LONG, - "I/O bitmap - I/O width, long"); - vmx_inc_test_stage(); - break; - case 5: - if (((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == 0x5000) - vmx_inc_test_stage(); - break; - case 6: - if (((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == 0x9000) - vmx_inc_test_stage(); - break; - case 7: - if (((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == 0x4FFF) - vmx_inc_test_stage(); - break; - case 8: - if (((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == 0xFFFF) - vmx_inc_test_stage(); - break; - case 9: - case 10: - ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0); - vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0 & ~CPU_IO); - vmx_inc_test_stage(); - break; - default: - // Should not reach here - report(false, "unexpected stage, %d", - vmx_get_test_stage()); - print_vmexit_info(exit_reason); - return VMX_TEST_VMEXIT; - } - vmcs_write(GUEST_RIP, guest_rip + insn_len); - return VMX_TEST_RESUME; - case VMX_VMCALL: - switch (vmx_get_test_stage()) { - case 9: - ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0); - ctrl_cpu0 |= CPU_IO | CPU_IO_BITMAP; - vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0); - break; - case 10: - ctrl_cpu0 = vmcs_read(CPU_EXEC_CTRL0); - ctrl_cpu0 = (ctrl_cpu0 & ~CPU_IO_BITMAP) | CPU_IO; - vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu0); - break; - default: - // Should not reach here - report(false, "unexpected stage, %d", - vmx_get_test_stage()); - print_vmexit_info(exit_reason); - return VMX_TEST_VMEXIT; - } - vmcs_write(GUEST_RIP, guest_rip + insn_len); - return VMX_TEST_RESUME; - default: - printf("guest_rip = %#lx\n", guest_rip); - printf("\tERROR : Unknown exit reason, 0x%x\n", exit_reason.full); - break; - } - return VMX_TEST_VMEXIT; -} - -#define INSN_CPU0 0 -#define INSN_CPU1 1 -#define INSN_ALWAYS_TRAP 2 - -#define FIELD_EXIT_QUAL (1 << 0) -#define FIELD_INSN_INFO (1 << 1) - -asm( - "insn_hlt: hlt;ret\n\t" - "insn_invlpg: invlpg 0x12345678;ret\n\t" - "insn_mwait: xor %eax, %eax; xor %ecx, %ecx; mwait;ret\n\t" - "insn_rdpmc: xor %ecx, %ecx; rdpmc;ret\n\t" - "insn_rdtsc: rdtsc;ret\n\t" - "insn_cr3_load: mov cr3,%rax; mov %rax,%cr3;ret\n\t" - "insn_cr3_store: mov %cr3,%rax;ret\n\t" - "insn_cr8_load: xor %eax, %eax; mov %rax,%cr8;ret\n\t" - "insn_cr8_store: mov %cr8,%rax;ret\n\t" - "insn_monitor: xor %eax, %eax; xor %ecx, %ecx; xor %edx, %edx; monitor;ret\n\t" - "insn_pause: pause;ret\n\t" - "insn_wbinvd: wbinvd;ret\n\t" - "insn_cpuid: mov $10, %eax; cpuid;ret\n\t" - "insn_invd: invd;ret\n\t" - "insn_sgdt: sgdt gdt64_desc;ret\n\t" - "insn_lgdt: lgdt gdt64_desc;ret\n\t" - "insn_sidt: sidt idt_descr;ret\n\t" - "insn_lidt: lidt idt_descr;ret\n\t" - "insn_sldt: sldt %ax;ret\n\t" - "insn_lldt: xor %eax, %eax; lldt %ax;ret\n\t" - "insn_str: str %ax;ret\n\t" - "insn_rdrand: rdrand %rax;ret\n\t" - "insn_rdseed: rdseed %rax;ret\n\t" -); -extern void insn_hlt(void); -extern void insn_invlpg(void); -extern void insn_mwait(void); -extern void insn_rdpmc(void); -extern void insn_rdtsc(void); -extern void insn_cr3_load(void); -extern void insn_cr3_store(void); -extern void insn_cr8_load(void); -extern void insn_cr8_store(void); -extern void insn_monitor(void); -extern void insn_pause(void); -extern void insn_wbinvd(void); -extern void insn_sgdt(void); -extern void insn_lgdt(void); -extern void insn_sidt(void); -extern void insn_lidt(void); -extern void insn_sldt(void); -extern void insn_lldt(void); -extern void insn_str(void); -extern void insn_cpuid(void); -extern void insn_invd(void); -extern void insn_rdrand(void); -extern void insn_rdseed(void); - -u32 cur_insn; -u64 cr3; - -#define X86_FEATURE_MONITOR (1 << 3) - -typedef bool (*supported_fn)(void); - -static bool monitor_supported(void) -{ - return this_cpu_has(X86_FEATURE_MWAIT); -} - -struct insn_table { - const char *name; - u32 flag; - void (*insn_func)(void); - u32 type; - u32 reason; - ulong exit_qual; - u32 insn_info; - // Use FIELD_EXIT_QUAL and FIELD_INSN_INFO to define - // which field need to be tested, reason is always tested - u32 test_field; - const supported_fn supported_fn; - u8 disabled; -}; - -/* - * Add more test cases of instruction intercept here. Elements in this - * table is: - * name/control flag/insn function/type/exit reason/exit qulification/ - * instruction info/field to test - * The last field defines which fields (exit_qual and insn_info) need to be - * tested in exit handler. If set to 0, only "reason" is checked. - */ -static struct insn_table insn_table[] = { - // Flags for Primary Processor-Based VM-Execution Controls - {"HLT", CPU_HLT, insn_hlt, INSN_CPU0, 12, 0, 0, 0}, - {"INVLPG", CPU_INVLPG, insn_invlpg, INSN_CPU0, 14, - 0x12345678, 0, FIELD_EXIT_QUAL}, - {"MWAIT", CPU_MWAIT, insn_mwait, INSN_CPU0, 36, 0, 0, 0, &monitor_supported}, - {"RDPMC", CPU_RDPMC, insn_rdpmc, INSN_CPU0, 15, 0, 0, 0}, - {"RDTSC", CPU_RDTSC, insn_rdtsc, INSN_CPU0, 16, 0, 0, 0}, - {"CR3 load", CPU_CR3_LOAD, insn_cr3_load, INSN_CPU0, 28, 0x3, 0, - FIELD_EXIT_QUAL}, - {"CR3 store", CPU_CR3_STORE, insn_cr3_store, INSN_CPU0, 28, 0x13, 0, - FIELD_EXIT_QUAL}, - {"CR8 load", CPU_CR8_LOAD, insn_cr8_load, INSN_CPU0, 28, 0x8, 0, - FIELD_EXIT_QUAL}, - {"CR8 store", CPU_CR8_STORE, insn_cr8_store, INSN_CPU0, 28, 0x18, 0, - FIELD_EXIT_QUAL}, - {"MONITOR", CPU_MONITOR, insn_monitor, INSN_CPU0, 39, 0, 0, 0, &monitor_supported}, - {"PAUSE", CPU_PAUSE, insn_pause, INSN_CPU0, 40, 0, 0, 0}, - // Flags for Secondary Processor-Based VM-Execution Controls - {"WBINVD", CPU_WBINVD, insn_wbinvd, INSN_CPU1, 54, 0, 0, 0}, - {"DESC_TABLE (SGDT)", CPU_DESC_TABLE, insn_sgdt, INSN_CPU1, 46, 0, 0, 0}, - {"DESC_TABLE (LGDT)", CPU_DESC_TABLE, insn_lgdt, INSN_CPU1, 46, 0, 0, 0}, - {"DESC_TABLE (SIDT)", CPU_DESC_TABLE, insn_sidt, INSN_CPU1, 46, 0, 0, 0}, - {"DESC_TABLE (LIDT)", CPU_DESC_TABLE, insn_lidt, INSN_CPU1, 46, 0, 0, 0}, - {"DESC_TABLE (SLDT)", CPU_DESC_TABLE, insn_sldt, INSN_CPU1, 47, 0, 0, 0}, - {"DESC_TABLE (LLDT)", CPU_DESC_TABLE, insn_lldt, INSN_CPU1, 47, 0, 0, 0}, - {"DESC_TABLE (STR)", CPU_DESC_TABLE, insn_str, INSN_CPU1, 47, 0, 0, 0}, - /* LTR causes a #GP if done with a busy selector, so it is not tested. */ - {"RDRAND", CPU_RDRAND, insn_rdrand, INSN_CPU1, VMX_RDRAND, 0, 0, 0}, - {"RDSEED", CPU_RDSEED, insn_rdseed, INSN_CPU1, VMX_RDSEED, 0, 0, 0}, - // Instructions always trap - {"CPUID", 0, insn_cpuid, INSN_ALWAYS_TRAP, 10, 0, 0, 0}, - {"INVD", 0, insn_invd, INSN_ALWAYS_TRAP, 13, 0, 0, 0}, - // Instructions never trap - {NULL}, -}; - -static int insn_intercept_init(struct vmcs *vmcs) -{ - u32 ctrl_cpu, cur_insn; - - ctrl_cpu = ctrl_cpu_rev[0].set | CPU_SECONDARY; - ctrl_cpu &= ctrl_cpu_rev[0].clr; - vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu); - vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu_rev[1].set); - cr3 = read_cr3(); - - for (cur_insn = 0; insn_table[cur_insn].name != NULL; cur_insn++) { - if (insn_table[cur_insn].supported_fn == NULL) - continue; - insn_table[cur_insn].disabled = !insn_table[cur_insn].supported_fn(); - } - return VMX_TEST_START; -} - -static void insn_intercept_main(void) -{ - for (cur_insn = 0; insn_table[cur_insn].name != NULL; cur_insn++) { - vmx_set_test_stage(cur_insn * 2); - if ((insn_table[cur_insn].type == INSN_CPU0 && - !(ctrl_cpu_rev[0].clr & insn_table[cur_insn].flag)) || - (insn_table[cur_insn].type == INSN_CPU1 && - !(ctrl_cpu_rev[1].clr & insn_table[cur_insn].flag))) { - printf("\tCPU_CTRL%d.CPU_%s is not supported.\n", - insn_table[cur_insn].type - INSN_CPU0, - insn_table[cur_insn].name); - continue; - } - - if (insn_table[cur_insn].disabled) { - printf("\tFeature required for %s is not supported.\n", - insn_table[cur_insn].name); - continue; - } - - if ((insn_table[cur_insn].type == INSN_CPU0 && - !(ctrl_cpu_rev[0].set & insn_table[cur_insn].flag)) || - (insn_table[cur_insn].type == INSN_CPU1 && - !(ctrl_cpu_rev[1].set & insn_table[cur_insn].flag))) { - /* skip hlt, it stalls the guest and is tested below */ - if (insn_table[cur_insn].insn_func != insn_hlt) - insn_table[cur_insn].insn_func(); - report(vmx_get_test_stage() == cur_insn * 2, - "execute %s", - insn_table[cur_insn].name); - } else if (insn_table[cur_insn].type != INSN_ALWAYS_TRAP) - printf("\tCPU_CTRL%d.CPU_%s always traps.\n", - insn_table[cur_insn].type - INSN_CPU0, - insn_table[cur_insn].name); - - vmcall(); - - insn_table[cur_insn].insn_func(); - report(vmx_get_test_stage() == cur_insn * 2 + 1, - "intercept %s", - insn_table[cur_insn].name); - - vmx_set_test_stage(cur_insn * 2 + 1); - vmcall(); - } -} - -static int insn_intercept_exit_handler(union exit_reason exit_reason) -{ - u64 guest_rip; - ulong exit_qual; - u32 insn_len; - u32 insn_info; - bool pass; - - guest_rip = vmcs_read(GUEST_RIP); - exit_qual = vmcs_read(EXI_QUALIFICATION); - insn_len = vmcs_read(EXI_INST_LEN); - insn_info = vmcs_read(EXI_INST_INFO); - - if (exit_reason.basic == VMX_VMCALL) { - u32 val = 0; - - if (insn_table[cur_insn].type == INSN_CPU0) - val = vmcs_read(CPU_EXEC_CTRL0); - else if (insn_table[cur_insn].type == INSN_CPU1) - val = vmcs_read(CPU_EXEC_CTRL1); - - if (vmx_get_test_stage() & 1) - val &= ~insn_table[cur_insn].flag; - else - val |= insn_table[cur_insn].flag; - - if (insn_table[cur_insn].type == INSN_CPU0) - vmcs_write(CPU_EXEC_CTRL0, val | ctrl_cpu_rev[0].set); - else if (insn_table[cur_insn].type == INSN_CPU1) - vmcs_write(CPU_EXEC_CTRL1, val | ctrl_cpu_rev[1].set); - } else { - pass = (cur_insn * 2 == vmx_get_test_stage()) && - insn_table[cur_insn].reason == exit_reason.full; - if (insn_table[cur_insn].test_field & FIELD_EXIT_QUAL && - insn_table[cur_insn].exit_qual != exit_qual) - pass = false; - if (insn_table[cur_insn].test_field & FIELD_INSN_INFO && - insn_table[cur_insn].insn_info != insn_info) - pass = false; - if (pass) - vmx_inc_test_stage(); - } - vmcs_write(GUEST_RIP, guest_rip + insn_len); - return VMX_TEST_RESUME; -} - -/** - * __setup_ept - Setup the VMCS fields to enable Extended Page Tables (EPT) - * @hpa: Host physical address of the top-level, a.k.a. root, EPT table - * @enable_ad: Whether or not to enable Access/Dirty bits for EPT entries - * - * Returns 0 on success, 1 on failure. - * - * Note that @hpa doesn't need to point at actual memory if VM-Launch is - * expected to fail, e.g. setup_dummy_ept() arbitrarily passes '0' to satisfy - * the various EPTP consistency checks, but doesn't ensure backing for HPA '0'. - */ -static int __setup_ept(u64 hpa, bool enable_ad) -{ - if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) || - !(ctrl_cpu_rev[1].clr & CPU_EPT)) { - printf("\tEPT is not supported"); - return 1; - } - if (!(ept_vpid.val & EPT_CAP_WB)) { - printf("WB memtype for EPT walks not supported\n"); - return 1; - } - if (!(ept_vpid.val & EPT_CAP_PWL4)) { - printf("\tPWL4 is not supported\n"); - return 1; - } - - eptp = EPT_MEM_TYPE_WB; - eptp |= (3 << EPTP_PG_WALK_LEN_SHIFT); - eptp |= hpa; - if (enable_ad) - eptp |= EPTP_AD_FLAG; - - vmcs_write(EPTP, eptp); - vmcs_write(CPU_EXEC_CTRL0, vmcs_read(CPU_EXEC_CTRL0)| CPU_SECONDARY); - vmcs_write(CPU_EXEC_CTRL1, vmcs_read(CPU_EXEC_CTRL1)| CPU_EPT); - - return 0; -} - -/** - * setup_ept - Enable Extended Page Tables (EPT) and setup an identity map - * @enable_ad: Whether or not to enable Access/Dirty bits for EPT entries - * - * Returns 0 on success, 1 on failure. - * - * This is the "real" function for setting up EPT tables, i.e. use this for - * tests that need to run code in the guest with EPT enabled. - */ -static int setup_ept(bool enable_ad) -{ - unsigned long end_of_memory; - - pml4 = alloc_page(); - - if (__setup_ept(virt_to_phys(pml4), enable_ad)) - return 1; - - end_of_memory = fwcfg_get_u64(FW_CFG_RAM_SIZE); - if (end_of_memory < (1ul << 32)) - end_of_memory = (1ul << 32); - /* Cannot use large EPT pages if we need to track EPT - * accessed/dirty bits at 4K granularity. - */ - setup_ept_range(pml4, 0, end_of_memory, 0, - !enable_ad && ept_2m_supported(), - EPT_WA | EPT_RA | EPT_EA); - return 0; -} - -/** - * setup_dummy_ept - Enable Extended Page Tables (EPT) with a dummy root HPA - * - * Setup EPT using a semi-arbitrary dummy root HPA. This function is intended - * for use by tests that need EPT enabled to verify dependent VMCS controls - * but never expect to fully enter the guest, i.e. don't need setup the actual - * EPT tables. - */ -static void setup_dummy_ept(void) -{ - if (__setup_ept(0, false)) - report_abort("EPT setup unexpectedly failed"); -} - -static int enable_unrestricted_guest(void) -{ - if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) || - !(ctrl_cpu_rev[1].clr & CPU_URG) || - !(ctrl_cpu_rev[1].clr & CPU_EPT)) - return 1; - - setup_dummy_ept(); - - vmcs_write(CPU_EXEC_CTRL0, vmcs_read(CPU_EXEC_CTRL0) | CPU_SECONDARY); - vmcs_write(CPU_EXEC_CTRL1, vmcs_read(CPU_EXEC_CTRL1) | CPU_URG); - - return 0; -} - -static void ept_enable_ad_bits(void) -{ - eptp |= EPTP_AD_FLAG; - vmcs_write(EPTP, eptp); -} - -static void ept_disable_ad_bits(void) -{ - eptp &= ~EPTP_AD_FLAG; - vmcs_write(EPTP, eptp); -} - -static int ept_ad_enabled(void) -{ - return eptp & EPTP_AD_FLAG; -} - -static void ept_enable_ad_bits_or_skip_test(void) -{ - if (!ept_ad_bits_supported()) - test_skip("EPT AD bits not supported."); - ept_enable_ad_bits(); -} - -static int apic_version; - -static int ept_init_common(bool have_ad) -{ - int ret; - struct pci_dev pcidev; - - if (setup_ept(have_ad)) - return VMX_TEST_EXIT; - data_page1 = alloc_page(); - data_page2 = alloc_page(); - *((u32 *)data_page1) = MAGIC_VAL_1; - *((u32 *)data_page2) = MAGIC_VAL_2; - install_ept(pml4, (unsigned long)data_page1, (unsigned long)data_page2, - EPT_RA | EPT_WA | EPT_EA); - - apic_version = apic_read(APIC_LVR); - - ret = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST); - if (ret != PCIDEVADDR_INVALID) { - pci_dev_init(&pcidev, ret); - pci_physaddr = pcidev.resource[PCI_TESTDEV_BAR_MEM]; - } - - return VMX_TEST_START; -} - -static int ept_init(struct vmcs *vmcs) -{ - return ept_init_common(false); -} - -static void ept_common(void) -{ - vmx_set_test_stage(0); - if (*((u32 *)data_page2) != MAGIC_VAL_1 || - *((u32 *)data_page1) != MAGIC_VAL_1) - report(0, "EPT basic framework - read"); - else { - *((u32 *)data_page2) = MAGIC_VAL_3; - vmcall(); - if (vmx_get_test_stage() == 1) { - if (*((u32 *)data_page1) == MAGIC_VAL_3 && - *((u32 *)data_page2) == MAGIC_VAL_2) - report(1, "EPT basic framework"); - else - report(1, "EPT basic framework - remap"); - } - } - // Test EPT Misconfigurations - vmx_set_test_stage(1); - vmcall(); - *((u32 *)data_page1) = MAGIC_VAL_1; - if (vmx_get_test_stage() != 2) { - report(0, "EPT misconfigurations"); - goto t1; - } - vmx_set_test_stage(2); - vmcall(); - *((u32 *)data_page1) = MAGIC_VAL_1; - report(vmx_get_test_stage() == 3, "EPT misconfigurations"); -t1: - // Test EPT violation - vmx_set_test_stage(3); - vmcall(); - *((u32 *)data_page1) = MAGIC_VAL_1; - report(vmx_get_test_stage() == 4, "EPT violation - page permission"); - // Violation caused by EPT paging structure - vmx_set_test_stage(4); - vmcall(); - *((u32 *)data_page1) = MAGIC_VAL_2; - report(vmx_get_test_stage() == 5, "EPT violation - paging structure"); - - // MMIO Read/Write - vmx_set_test_stage(5); - vmcall(); - - *(u32 volatile *)pci_physaddr; - report(vmx_get_test_stage() == 6, "MMIO EPT violation - read"); - - *(u32 volatile *)pci_physaddr = MAGIC_VAL_1; - report(vmx_get_test_stage() == 7, "MMIO EPT violation - write"); -} - -static void ept_main(void) -{ - ept_common(); - - // Test EPT access to L1 MMIO - vmx_set_test_stage(7); - report(*((u32 *)0xfee00030UL) == apic_version, "EPT - MMIO access"); - - // Test invalid operand for INVEPT - vmcall(); - report(vmx_get_test_stage() == 8, "EPT - unsupported INVEPT"); -} - -static bool invept_test(int type, u64 eptp) -{ - bool ret, supported; - - supported = ept_vpid.val & (EPT_CAP_INVEPT_SINGLE >> INVEPT_SINGLE << type); - ret = invept(type, eptp); - - if (ret == !supported) - return false; - - if (!supported) - printf("WARNING: unsupported invept passed!\n"); - else - printf("WARNING: invept failed!\n"); - - return true; -} - -static int pml_exit_handler(union exit_reason exit_reason) -{ - u16 index, count; - u64 *pmlbuf = pml_log; - u64 guest_rip = vmcs_read(GUEST_RIP);; - u64 guest_cr3 = vmcs_read(GUEST_CR3); - u32 insn_len = vmcs_read(EXI_INST_LEN); - - switch (exit_reason.basic) { - case VMX_VMCALL: - switch (vmx_get_test_stage()) { - case 0: - index = vmcs_read(GUEST_PML_INDEX); - for (count = index + 1; count < PML_INDEX; count++) { - if (pmlbuf[count] == (u64)data_page2) { - vmx_inc_test_stage(); - clear_ept_ad(pml4, guest_cr3, (unsigned long)data_page2); - break; - } - } - break; - case 1: - index = vmcs_read(GUEST_PML_INDEX); - /* Keep clearing the dirty bit till a overflow */ - clear_ept_ad(pml4, guest_cr3, (unsigned long)data_page2); - break; - default: - report(false, "unexpected stage, %d.", - vmx_get_test_stage()); - print_vmexit_info(exit_reason); - return VMX_TEST_VMEXIT; - } - vmcs_write(GUEST_RIP, guest_rip + insn_len); - return VMX_TEST_RESUME; - case VMX_PML_FULL: - vmx_inc_test_stage(); - vmcs_write(GUEST_PML_INDEX, PML_INDEX - 1); - return VMX_TEST_RESUME; - default: - report(false, "Unknown exit reason, 0x%x", exit_reason.full); - print_vmexit_info(exit_reason); - } - return VMX_TEST_VMEXIT; -} - -static int ept_exit_handler_common(union exit_reason exit_reason, bool have_ad) -{ - u64 guest_rip; - u64 guest_cr3; - u32 insn_len; - u32 exit_qual; - static unsigned long data_page1_pte, data_page1_pte_pte, memaddr_pte, - guest_pte_addr; - - guest_rip = vmcs_read(GUEST_RIP); - guest_cr3 = vmcs_read(GUEST_CR3); - insn_len = vmcs_read(EXI_INST_LEN); - exit_qual = vmcs_read(EXI_QUALIFICATION); - pteval_t *ptep; - switch (exit_reason.basic) { - case VMX_VMCALL: - switch (vmx_get_test_stage()) { - case 0: - check_ept_ad(pml4, guest_cr3, - (unsigned long)data_page1, - have_ad ? EPT_ACCESS_FLAG : 0, - have_ad ? EPT_ACCESS_FLAG | EPT_DIRTY_FLAG : 0); - check_ept_ad(pml4, guest_cr3, - (unsigned long)data_page2, - have_ad ? EPT_ACCESS_FLAG | EPT_DIRTY_FLAG : 0, - have_ad ? EPT_ACCESS_FLAG | EPT_DIRTY_FLAG : 0); - clear_ept_ad(pml4, guest_cr3, (unsigned long)data_page1); - clear_ept_ad(pml4, guest_cr3, (unsigned long)data_page2); - if (have_ad) - ept_sync(INVEPT_SINGLE, eptp);; - if (*((u32 *)data_page1) == MAGIC_VAL_3 && - *((u32 *)data_page2) == MAGIC_VAL_2) { - vmx_inc_test_stage(); - install_ept(pml4, (unsigned long)data_page2, - (unsigned long)data_page2, - EPT_RA | EPT_WA | EPT_EA); - } else - report(0, "EPT basic framework - write"); - break; - case 1: - install_ept(pml4, (unsigned long)data_page1, - (unsigned long)data_page1, EPT_WA); - ept_sync(INVEPT_SINGLE, eptp); - break; - case 2: - install_ept(pml4, (unsigned long)data_page1, - (unsigned long)data_page1, - EPT_RA | EPT_WA | EPT_EA | - (2 << EPT_MEM_TYPE_SHIFT)); - ept_sync(INVEPT_SINGLE, eptp); - break; - case 3: - clear_ept_ad(pml4, guest_cr3, (unsigned long)data_page1); - TEST_ASSERT(get_ept_pte(pml4, (unsigned long)data_page1, - 1, &data_page1_pte)); - set_ept_pte(pml4, (unsigned long)data_page1, - 1, data_page1_pte & ~EPT_PRESENT); - ept_sync(INVEPT_SINGLE, eptp); - break; - case 4: - ptep = get_pte_level((pgd_t *)guest_cr3, data_page1, /*level=*/2); - guest_pte_addr = virt_to_phys(ptep) & PAGE_MASK; - - TEST_ASSERT(get_ept_pte(pml4, guest_pte_addr, 2, &data_page1_pte_pte)); - set_ept_pte(pml4, guest_pte_addr, 2, - data_page1_pte_pte & ~EPT_PRESENT); - ept_sync(INVEPT_SINGLE, eptp); - break; - case 5: - install_ept(pml4, (unsigned long)pci_physaddr, - (unsigned long)pci_physaddr, 0); - ept_sync(INVEPT_SINGLE, eptp); - break; - case 7: - if (!invept_test(0, eptp)) - vmx_inc_test_stage(); - break; - // Should not reach here - default: - report(false, "ERROR - unexpected stage, %d.", - vmx_get_test_stage()); - print_vmexit_info(exit_reason); - return VMX_TEST_VMEXIT; - } - vmcs_write(GUEST_RIP, guest_rip + insn_len); - return VMX_TEST_RESUME; - case VMX_EPT_MISCONFIG: - switch (vmx_get_test_stage()) { - case 1: - case 2: - vmx_inc_test_stage(); - install_ept(pml4, (unsigned long)data_page1, - (unsigned long)data_page1, - EPT_RA | EPT_WA | EPT_EA); - ept_sync(INVEPT_SINGLE, eptp); - break; - // Should not reach here - default: - report(false, "ERROR - unexpected stage, %d.", - vmx_get_test_stage()); - print_vmexit_info(exit_reason); - return VMX_TEST_VMEXIT; - } - return VMX_TEST_RESUME; - case VMX_EPT_VIOLATION: - /* - * Exit-qualifications are masked not to account for advanced - * VM-exit information. Once KVM supports this feature, this - * masking should be removed. - */ - exit_qual &= ~EPT_VLT_GUEST_MASK; - - switch(vmx_get_test_stage()) { - case 3: - check_ept_ad(pml4, guest_cr3, (unsigned long)data_page1, 0, - have_ad ? EPT_ACCESS_FLAG | EPT_DIRTY_FLAG : 0); - clear_ept_ad(pml4, guest_cr3, (unsigned long)data_page1); - if (exit_qual == (EPT_VLT_WR | EPT_VLT_LADDR_VLD | - EPT_VLT_PADDR)) - vmx_inc_test_stage(); - set_ept_pte(pml4, (unsigned long)data_page1, - 1, data_page1_pte | (EPT_PRESENT)); - ept_sync(INVEPT_SINGLE, eptp); - break; - case 4: - check_ept_ad(pml4, guest_cr3, (unsigned long)data_page1, 0, - have_ad ? EPT_ACCESS_FLAG | EPT_DIRTY_FLAG : 0); - clear_ept_ad(pml4, guest_cr3, (unsigned long)data_page1); - if (exit_qual == (EPT_VLT_RD | - (have_ad ? EPT_VLT_WR : 0) | - EPT_VLT_LADDR_VLD)) - vmx_inc_test_stage(); - set_ept_pte(pml4, guest_pte_addr, 2, - data_page1_pte_pte | (EPT_PRESENT)); - ept_sync(INVEPT_SINGLE, eptp); - break; - case 5: - if (exit_qual & EPT_VLT_RD) - vmx_inc_test_stage(); - TEST_ASSERT(get_ept_pte(pml4, (unsigned long)pci_physaddr, - 1, &memaddr_pte)); - set_ept_pte(pml4, memaddr_pte, 1, memaddr_pte | EPT_RA); - ept_sync(INVEPT_SINGLE, eptp); - break; - case 6: - if (exit_qual & EPT_VLT_WR) - vmx_inc_test_stage(); - TEST_ASSERT(get_ept_pte(pml4, (unsigned long)pci_physaddr, - 1, &memaddr_pte)); - set_ept_pte(pml4, memaddr_pte, 1, memaddr_pte | EPT_RA | EPT_WA); - ept_sync(INVEPT_SINGLE, eptp); - break; - default: - // Should not reach here - report(false, "ERROR : unexpected stage, %d", - vmx_get_test_stage()); - print_vmexit_info(exit_reason); - return VMX_TEST_VMEXIT; - } - return VMX_TEST_RESUME; - default: - report(false, "Unknown exit reason, 0x%x", exit_reason.full); - print_vmexit_info(exit_reason); - } - return VMX_TEST_VMEXIT; -} - -static int ept_exit_handler(union exit_reason exit_reason) -{ - return ept_exit_handler_common(exit_reason, false); -} - -static int eptad_init(struct vmcs *vmcs) -{ - int r = ept_init_common(true); - - if (r == VMX_TEST_EXIT) - return r; - - if ((rdmsr(MSR_IA32_VMX_EPT_VPID_CAP) & EPT_CAP_AD_FLAG) == 0) { - printf("\tEPT A/D bits are not supported"); - return VMX_TEST_EXIT; - } - - return r; -} - -static int pml_init(struct vmcs *vmcs) -{ - u32 ctrl_cpu; - int r = eptad_init(vmcs); - - if (r == VMX_TEST_EXIT) - return r; - - if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) || - !(ctrl_cpu_rev[1].clr & CPU_PML)) { - printf("\tPML is not supported"); - return VMX_TEST_EXIT; - } - - pml_log = alloc_page(); - vmcs_write(PMLADDR, (u64)pml_log); - vmcs_write(GUEST_PML_INDEX, PML_INDEX - 1); - - ctrl_cpu = vmcs_read(CPU_EXEC_CTRL1) | CPU_PML; - vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu); - - return VMX_TEST_START; -} - -static void pml_main(void) -{ - int count = 0; - - vmx_set_test_stage(0); - *((u32 *)data_page2) = 0x1; - vmcall(); - report(vmx_get_test_stage() == 1, "PML - Dirty GPA Logging"); - - while (vmx_get_test_stage() == 1) { - vmcall(); - *((u32 *)data_page2) = 0x1; - if (count++ > PML_INDEX) - break; - } - report(vmx_get_test_stage() == 2, "PML Full Event"); -} - -static void eptad_main(void) -{ - ept_common(); -} - -static int eptad_exit_handler(union exit_reason exit_reason) -{ - return ept_exit_handler_common(exit_reason, true); -} - -static bool invvpid_test(int type, u16 vpid) -{ - bool ret, supported; - - supported = ept_vpid.val & - (VPID_CAP_INVVPID_ADDR >> INVVPID_ADDR << type); - ret = invvpid(type, vpid, 0); - - if (ret == !supported) - return false; - - if (!supported) - printf("WARNING: unsupported invvpid passed!\n"); - else - printf("WARNING: invvpid failed!\n"); - - return true; -} - -static int vpid_init(struct vmcs *vmcs) -{ - u32 ctrl_cpu1; - - if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) || - !(ctrl_cpu_rev[1].clr & CPU_VPID)) { - printf("\tVPID is not supported"); - return VMX_TEST_EXIT; - } - - ctrl_cpu1 = vmcs_read(CPU_EXEC_CTRL1); - ctrl_cpu1 |= CPU_VPID; - vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu1); - return VMX_TEST_START; -} - -static void vpid_main(void) -{ - vmx_set_test_stage(0); - vmcall(); - report(vmx_get_test_stage() == 1, "INVVPID SINGLE ADDRESS"); - vmx_set_test_stage(2); - vmcall(); - report(vmx_get_test_stage() == 3, "INVVPID SINGLE"); - vmx_set_test_stage(4); - vmcall(); - report(vmx_get_test_stage() == 5, "INVVPID ALL"); -} - -static int vpid_exit_handler(union exit_reason exit_reason) -{ - u64 guest_rip; - u32 insn_len; - - guest_rip = vmcs_read(GUEST_RIP); - insn_len = vmcs_read(EXI_INST_LEN); - - switch (exit_reason.basic) { - case VMX_VMCALL: - switch(vmx_get_test_stage()) { - case 0: - if (!invvpid_test(INVVPID_ADDR, 1)) - vmx_inc_test_stage(); - break; - case 2: - if (!invvpid_test(INVVPID_CONTEXT_GLOBAL, 1)) - vmx_inc_test_stage(); - break; - case 4: - if (!invvpid_test(INVVPID_ALL, 1)) - vmx_inc_test_stage(); - break; - default: - report(false, "ERROR: unexpected stage, %d", - vmx_get_test_stage()); - print_vmexit_info(exit_reason); - return VMX_TEST_VMEXIT; - } - vmcs_write(GUEST_RIP, guest_rip + insn_len); - return VMX_TEST_RESUME; - default: - report(false, "Unknown exit reason, 0x%x", exit_reason.full); - print_vmexit_info(exit_reason); - } - return VMX_TEST_VMEXIT; -} - -#define TIMER_VECTOR 222 - -static volatile bool timer_fired; - -static void timer_isr(isr_regs_t *regs) -{ - timer_fired = true; - apic_write(APIC_EOI, 0); -} - -static int interrupt_init(struct vmcs *vmcs) -{ - msr_bmp_init(); - vmcs_write(PIN_CONTROLS, vmcs_read(PIN_CONTROLS) & ~PIN_EXTINT); - handle_irq(TIMER_VECTOR, timer_isr); - return VMX_TEST_START; -} - -static void interrupt_main(void) -{ - long long start, loops; - - vmx_set_test_stage(0); - - apic_write(APIC_LVTT, TIMER_VECTOR); - irq_enable(); - - apic_write(APIC_TMICT, 1); - for (loops = 0; loops < 10000000 && !timer_fired; loops++) - asm volatile ("nop"); - report(timer_fired, "direct interrupt while running guest"); - - apic_write(APIC_TMICT, 0); - irq_disable(); - vmcall(); - timer_fired = false; - apic_write(APIC_TMICT, 1); - for (loops = 0; loops < 10000000 && !timer_fired; loops++) - asm volatile ("nop"); - report(timer_fired, "intercepted interrupt while running guest"); - - irq_enable(); - apic_write(APIC_TMICT, 0); - irq_disable(); - vmcall(); - timer_fired = false; - start = rdtsc(); - apic_write(APIC_TMICT, 1000000); - - asm volatile ("sti; hlt"); - - report(rdtsc() - start > 1000000 && timer_fired, - "direct interrupt + hlt"); - - apic_write(APIC_TMICT, 0); - irq_disable(); - vmcall(); - timer_fired = false; - start = rdtsc(); - apic_write(APIC_TMICT, 1000000); - - asm volatile ("sti; hlt"); - - report(rdtsc() - start > 10000 && timer_fired, - "intercepted interrupt + hlt"); - - apic_write(APIC_TMICT, 0); - irq_disable(); - vmcall(); - timer_fired = false; - start = rdtsc(); - apic_write(APIC_TMICT, 1000000); - - irq_enable(); - asm volatile ("nop"); - vmcall(); - - report(rdtsc() - start > 10000 && timer_fired, - "direct interrupt + activity state hlt"); - - apic_write(APIC_TMICT, 0); - irq_disable(); - vmcall(); - timer_fired = false; - start = rdtsc(); - apic_write(APIC_TMICT, 1000000); - - irq_enable(); - asm volatile ("nop"); - vmcall(); - - report(rdtsc() - start > 10000 && timer_fired, - "intercepted interrupt + activity state hlt"); - - apic_write(APIC_TMICT, 0); - irq_disable(); - vmx_set_test_stage(7); - vmcall(); - timer_fired = false; - apic_write(APIC_TMICT, 1); - for (loops = 0; loops < 10000000 && !timer_fired; loops++) - asm volatile ("nop"); - report(timer_fired, - "running a guest with interrupt acknowledgement set"); - - apic_write(APIC_TMICT, 0); - irq_enable(); - timer_fired = false; - vmcall(); - report(timer_fired, "Inject an event to a halted guest"); -} - -static int interrupt_exit_handler(union exit_reason exit_reason) -{ - u64 guest_rip = vmcs_read(GUEST_RIP); - u32 insn_len = vmcs_read(EXI_INST_LEN); - - switch (exit_reason.basic) { - case VMX_VMCALL: - switch (vmx_get_test_stage()) { - case 0: - case 2: - case 5: - vmcs_write(PIN_CONTROLS, - vmcs_read(PIN_CONTROLS) | PIN_EXTINT); - break; - case 7: - vmcs_write(EXI_CONTROLS, vmcs_read(EXI_CONTROLS) | EXI_INTA); - vmcs_write(PIN_CONTROLS, - vmcs_read(PIN_CONTROLS) | PIN_EXTINT); - break; - case 1: - case 3: - vmcs_write(PIN_CONTROLS, - vmcs_read(PIN_CONTROLS) & ~PIN_EXTINT); - break; - case 4: - case 6: - vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); - break; - - case 8: - vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); - vmcs_write(ENT_INTR_INFO, - TIMER_VECTOR | - (VMX_INTR_TYPE_EXT_INTR << INTR_INFO_INTR_TYPE_SHIFT) | - INTR_INFO_VALID_MASK); - break; - } - vmx_inc_test_stage(); - vmcs_write(GUEST_RIP, guest_rip + insn_len); - return VMX_TEST_RESUME; - case VMX_EXTINT: - if (vmcs_read(EXI_CONTROLS) & EXI_INTA) { - int vector = vmcs_read(EXI_INTR_INFO) & 0xff; - handle_external_interrupt(vector); - } else { - irq_enable(); - asm volatile ("nop"); - irq_disable(); - } - if (vmx_get_test_stage() >= 2) - vmcs_write(GUEST_ACTV_STATE, ACTV_ACTIVE); - return VMX_TEST_RESUME; - default: - report(false, "Unknown exit reason, 0x%x", exit_reason.full); - print_vmexit_info(exit_reason); - } - - return VMX_TEST_VMEXIT; -} - - -static volatile int nmi_fired; - -#define NMI_DELAY 100000000ULL - -static void nmi_isr(isr_regs_t *regs) -{ - nmi_fired = true; -} - -static int nmi_hlt_init(struct vmcs *vmcs) -{ - msr_bmp_init(); - handle_irq(NMI_VECTOR, nmi_isr); - vmcs_write(PIN_CONTROLS, - vmcs_read(PIN_CONTROLS) & ~PIN_NMI); - vmcs_write(PIN_CONTROLS, - vmcs_read(PIN_CONTROLS) & ~PIN_VIRT_NMI); - return VMX_TEST_START; -} - -static void nmi_message_thread(void *data) -{ - while (vmx_get_test_stage() != 1) - pause(); - - delay(NMI_DELAY); - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[0]); - - while (vmx_get_test_stage() != 2) - pause(); - - delay(NMI_DELAY); - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, id_map[0]); -} - -static void nmi_hlt_main(void) -{ - long long start; - - if (cpu_count() < 2) { - report_skip(__func__); - vmx_set_test_stage(-1); - return; - } - - vmx_set_test_stage(0); - on_cpu_async(1, nmi_message_thread, NULL); - start = rdtsc(); - vmx_set_test_stage(1); - asm volatile ("hlt"); - report((rdtsc() - start > NMI_DELAY) && nmi_fired, - "direct NMI + hlt"); - if (!nmi_fired) - vmx_set_test_stage(-1); - nmi_fired = false; - - vmcall(); - - start = rdtsc(); - vmx_set_test_stage(2); - asm volatile ("hlt"); - report((rdtsc() - start > NMI_DELAY) && !nmi_fired, - "intercepted NMI + hlt"); - if (nmi_fired) { - report(!nmi_fired, "intercepted NMI was dispatched"); - vmx_set_test_stage(-1); - return; - } - vmx_set_test_stage(3); -} - -static int nmi_hlt_exit_handler(union exit_reason exit_reason) -{ - u64 guest_rip = vmcs_read(GUEST_RIP); - u32 insn_len = vmcs_read(EXI_INST_LEN); - - switch (vmx_get_test_stage()) { - case 1: - if (exit_reason.basic != VMX_VMCALL) { - report(false, "VMEXIT not due to vmcall. Exit reason 0x%x", - exit_reason.full); - print_vmexit_info(exit_reason); - return VMX_TEST_VMEXIT; - } - - vmcs_write(PIN_CONTROLS, - vmcs_read(PIN_CONTROLS) | PIN_NMI); - vmcs_write(PIN_CONTROLS, - vmcs_read(PIN_CONTROLS) | PIN_VIRT_NMI); - vmcs_write(GUEST_RIP, guest_rip + insn_len); - break; - - case 2: - if (exit_reason.basic != VMX_EXC_NMI) { - report(false, "VMEXIT not due to NMI intercept. Exit reason 0x%x", - exit_reason.full); - print_vmexit_info(exit_reason); - return VMX_TEST_VMEXIT; - } - report(true, "NMI intercept while running guest"); - vmcs_write(GUEST_ACTV_STATE, ACTV_ACTIVE); - break; - - case 3: - break; - - default: - return VMX_TEST_VMEXIT; - } - - if (vmx_get_test_stage() == 3) - return VMX_TEST_VMEXIT; - - return VMX_TEST_RESUME; -} - - -static int dbgctls_init(struct vmcs *vmcs) -{ - u64 dr7 = 0x402; - u64 zero = 0; - - msr_bmp_init(); - asm volatile( - "mov %0,%%dr0\n\t" - "mov %0,%%dr1\n\t" - "mov %0,%%dr2\n\t" - "mov %1,%%dr7\n\t" - : : "r" (zero), "r" (dr7)); - wrmsr(MSR_IA32_DEBUGCTLMSR, 0x1); - vmcs_write(GUEST_DR7, 0x404); - vmcs_write(GUEST_DEBUGCTL, 0x2); - - vmcs_write(ENT_CONTROLS, vmcs_read(ENT_CONTROLS) | ENT_LOAD_DBGCTLS); - vmcs_write(EXI_CONTROLS, vmcs_read(EXI_CONTROLS) | EXI_SAVE_DBGCTLS); - - return VMX_TEST_START; -} - -static void dbgctls_main(void) -{ - u64 dr7, debugctl; - - asm volatile("mov %%dr7,%0" : "=r" (dr7)); - debugctl = rdmsr(MSR_IA32_DEBUGCTLMSR); - /* Commented out: KVM does not support DEBUGCTL so far */ - (void)debugctl; - report(dr7 == 0x404, "Load debug controls" /* && debugctl == 0x2 */); - - dr7 = 0x408; - asm volatile("mov %0,%%dr7" : : "r" (dr7)); - wrmsr(MSR_IA32_DEBUGCTLMSR, 0x3); - - vmx_set_test_stage(0); - vmcall(); - report(vmx_get_test_stage() == 1, "Save debug controls"); - - if (ctrl_enter_rev.set & ENT_LOAD_DBGCTLS || - ctrl_exit_rev.set & EXI_SAVE_DBGCTLS) { - printf("\tDebug controls are always loaded/saved\n"); - return; - } - vmx_set_test_stage(2); - vmcall(); - - asm volatile("mov %%dr7,%0" : "=r" (dr7)); - debugctl = rdmsr(MSR_IA32_DEBUGCTLMSR); - /* Commented out: KVM does not support DEBUGCTL so far */ - (void)debugctl; - report(dr7 == 0x402, - "Guest=host debug controls" /* && debugctl == 0x1 */); - - dr7 = 0x408; - asm volatile("mov %0,%%dr7" : : "r" (dr7)); - wrmsr(MSR_IA32_DEBUGCTLMSR, 0x3); - - vmx_set_test_stage(3); - vmcall(); - report(vmx_get_test_stage() == 4, "Don't save debug controls"); -} - -static int dbgctls_exit_handler(union exit_reason exit_reason) -{ - u32 insn_len = vmcs_read(EXI_INST_LEN); - u64 guest_rip = vmcs_read(GUEST_RIP); - u64 dr7, debugctl; - - asm volatile("mov %%dr7,%0" : "=r" (dr7)); - debugctl = rdmsr(MSR_IA32_DEBUGCTLMSR); - - switch (exit_reason.basic) { - case VMX_VMCALL: - switch (vmx_get_test_stage()) { - case 0: - if (dr7 == 0x400 && debugctl == 0 && - vmcs_read(GUEST_DR7) == 0x408 /* && - Commented out: KVM does not support DEBUGCTL so far - vmcs_read(GUEST_DEBUGCTL) == 0x3 */) - vmx_inc_test_stage(); - break; - case 2: - dr7 = 0x402; - asm volatile("mov %0,%%dr7" : : "r" (dr7)); - wrmsr(MSR_IA32_DEBUGCTLMSR, 0x1); - vmcs_write(GUEST_DR7, 0x404); - vmcs_write(GUEST_DEBUGCTL, 0x2); - - vmcs_write(ENT_CONTROLS, - vmcs_read(ENT_CONTROLS) & ~ENT_LOAD_DBGCTLS); - vmcs_write(EXI_CONTROLS, - vmcs_read(EXI_CONTROLS) & ~EXI_SAVE_DBGCTLS); - break; - case 3: - if (dr7 == 0x400 && debugctl == 0 && - vmcs_read(GUEST_DR7) == 0x404 /* && - Commented out: KVM does not support DEBUGCTL so far - vmcs_read(GUEST_DEBUGCTL) == 0x2 */) - vmx_inc_test_stage(); - break; - } - vmcs_write(GUEST_RIP, guest_rip + insn_len); - return VMX_TEST_RESUME; - default: - report(false, "Unknown exit reason, %d", exit_reason.full); - print_vmexit_info(exit_reason); - } - return VMX_TEST_VMEXIT; -} - -struct vmx_msr_entry { - u32 index; - u32 reserved; - u64 value; -} __attribute__((packed)); - -#define MSR_MAGIC 0x31415926 -struct vmx_msr_entry *exit_msr_store, *entry_msr_load, *exit_msr_load; - -static int msr_switch_init(struct vmcs *vmcs) -{ - msr_bmp_init(); - exit_msr_store = alloc_page(); - exit_msr_load = alloc_page(); - entry_msr_load = alloc_page(); - entry_msr_load[0].index = MSR_KERNEL_GS_BASE; - entry_msr_load[0].value = MSR_MAGIC; - - vmx_set_test_stage(1); - vmcs_write(ENT_MSR_LD_CNT, 1); - vmcs_write(ENTER_MSR_LD_ADDR, (u64)entry_msr_load); - vmcs_write(EXI_MSR_ST_CNT, 1); - vmcs_write(EXIT_MSR_ST_ADDR, (u64)exit_msr_store); - vmcs_write(EXI_MSR_LD_CNT, 1); - vmcs_write(EXIT_MSR_LD_ADDR, (u64)exit_msr_load); - return VMX_TEST_START; -} - -static void msr_switch_main(void) -{ - if (vmx_get_test_stage() == 1) { - report(rdmsr(MSR_KERNEL_GS_BASE) == MSR_MAGIC, - "VM entry MSR load"); - vmx_set_test_stage(2); - wrmsr(MSR_KERNEL_GS_BASE, MSR_MAGIC + 1); - exit_msr_store[0].index = MSR_KERNEL_GS_BASE; - exit_msr_load[0].index = MSR_KERNEL_GS_BASE; - exit_msr_load[0].value = MSR_MAGIC + 2; - } - vmcall(); -} - -static int msr_switch_exit_handler(union exit_reason exit_reason) -{ - if (exit_reason.basic == VMX_VMCALL && vmx_get_test_stage() == 2) { - report(exit_msr_store[0].value == MSR_MAGIC + 1, - "VM exit MSR store"); - report(rdmsr(MSR_KERNEL_GS_BASE) == MSR_MAGIC + 2, - "VM exit MSR load"); - vmx_set_test_stage(3); - entry_msr_load[0].index = MSR_FS_BASE; - return VMX_TEST_RESUME; - } - printf("ERROR %s: unexpected stage=%u or reason=0x%x\n", - __func__, vmx_get_test_stage(), exit_reason.full); - return VMX_TEST_EXIT; -} - -static int msr_switch_entry_failure(struct vmentry_result *result) -{ - if (result->vm_fail) { - printf("ERROR %s: VM-Fail on %s\n", __func__, result->instr); - return VMX_TEST_EXIT; - } - - if (result->exit_reason.failed_vmentry && - result->exit_reason.basic == VMX_FAIL_MSR && - vmx_get_test_stage() == 3) { - report(vmcs_read(EXI_QUALIFICATION) == 1, - "VM entry MSR load: try to load FS_BASE"); - return VMX_TEST_VMEXIT; - } - printf("ERROR %s: unexpected stage=%u or reason=%x\n", - __func__, vmx_get_test_stage(), result->exit_reason.full); - return VMX_TEST_EXIT; -} - -static int vmmcall_init(struct vmcs *vmcs) -{ - vmcs_write(EXC_BITMAP, 1 << UD_VECTOR); - return VMX_TEST_START; -} - -static void vmmcall_main(void) -{ - asm volatile( - "mov $0xABCD, %%rax\n\t" - "vmmcall\n\t" - ::: "rax"); - - report(0, "VMMCALL"); -} - -static int vmmcall_exit_handler(union exit_reason exit_reason) -{ - switch (exit_reason.basic) { - case VMX_VMCALL: - printf("here\n"); - report(0, "VMMCALL triggers #UD"); - break; - case VMX_EXC_NMI: - report((vmcs_read(EXI_INTR_INFO) & 0xff) == UD_VECTOR, - "VMMCALL triggers #UD"); - break; - default: - report(false, "Unknown exit reason, 0x%x", exit_reason.full); - print_vmexit_info(exit_reason); - } - - return VMX_TEST_VMEXIT; -} - -static int disable_rdtscp_init(struct vmcs *vmcs) -{ - u32 ctrl_cpu1; - - if (ctrl_cpu_rev[0].clr & CPU_SECONDARY) { - ctrl_cpu1 = vmcs_read(CPU_EXEC_CTRL1); - ctrl_cpu1 &= ~CPU_RDTSCP; - vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu1); - } - - return VMX_TEST_START; -} - -static void disable_rdtscp_ud_handler(struct ex_regs *regs) -{ - switch (vmx_get_test_stage()) { - case 0: - report(true, "RDTSCP triggers #UD"); - vmx_inc_test_stage(); - regs->rip += 3; - break; - case 2: - report(true, "RDPID triggers #UD"); - vmx_inc_test_stage(); - regs->rip += 4; - break; - } - return; - -} - -static void disable_rdtscp_main(void) -{ - /* Test that #UD is properly injected in L2. */ - handle_exception(UD_VECTOR, disable_rdtscp_ud_handler); - - vmx_set_test_stage(0); - asm volatile("rdtscp" : : : "eax", "ecx", "edx"); - vmcall(); - asm volatile(".byte 0xf3, 0x0f, 0xc7, 0xf8" : : : "eax"); - - handle_exception(UD_VECTOR, 0); - vmcall(); -} - -static int disable_rdtscp_exit_handler(union exit_reason exit_reason) -{ - switch (exit_reason.basic) { - case VMX_VMCALL: - switch (vmx_get_test_stage()) { - case 0: - report(false, "RDTSCP triggers #UD"); - vmx_inc_test_stage(); - /* fallthrough */ - case 1: - vmx_inc_test_stage(); - vmcs_write(GUEST_RIP, vmcs_read(GUEST_RIP) + 3); - return VMX_TEST_RESUME; - case 2: - report(false, "RDPID triggers #UD"); - break; - } - break; - - default: - report(false, "Unknown exit reason, 0x%x", exit_reason.full); - print_vmexit_info(exit_reason); - } - return VMX_TEST_VMEXIT; -} - -static int int3_init(struct vmcs *vmcs) -{ - vmcs_write(EXC_BITMAP, ~0u); - return VMX_TEST_START; -} - -static void int3_guest_main(void) -{ - asm volatile ("int3"); -} - -static int int3_exit_handler(union exit_reason exit_reason) -{ - u32 intr_info = vmcs_read(EXI_INTR_INFO); - - report(exit_reason.basic == VMX_EXC_NMI && - (intr_info & INTR_INFO_VALID_MASK) && - (intr_info & INTR_INFO_VECTOR_MASK) == BP_VECTOR && - ((intr_info & INTR_INFO_INTR_TYPE_MASK) >> - INTR_INFO_INTR_TYPE_SHIFT) == VMX_INTR_TYPE_SOFT_EXCEPTION, - "L1 intercepts #BP"); - - return VMX_TEST_VMEXIT; -} - -static int into_init(struct vmcs *vmcs) -{ - vmcs_write(EXC_BITMAP, ~0u); - return VMX_TEST_START; -} - -static void into_guest_main(void) -{ - struct far_pointer32 fp = { - .offset = (uintptr_t)&&into, - .selector = KERNEL_CS32, - }; - uintptr_t rsp; - - asm volatile ("mov %%rsp, %0" : "=r"(rsp)); - - if (fp.offset != (uintptr_t)&&into) { - printf("Code address too high.\n"); - return; - } - if ((u32)rsp != rsp) { - printf("Stack address too high.\n"); - return; - } - - asm goto ("lcall *%0" : : "m" (fp) : "rax" : into); - return; -into: - asm volatile (".code32;" - "movl $0x7fffffff, %eax;" - "addl %eax, %eax;" - "into;" - "lret;" - ".code64"); - __builtin_unreachable(); -} - -static int into_exit_handler(union exit_reason exit_reason) -{ - u32 intr_info = vmcs_read(EXI_INTR_INFO); - - report(exit_reason.basic == VMX_EXC_NMI && - (intr_info & INTR_INFO_VALID_MASK) && - (intr_info & INTR_INFO_VECTOR_MASK) == OF_VECTOR && - ((intr_info & INTR_INFO_INTR_TYPE_MASK) >> - INTR_INFO_INTR_TYPE_SHIFT) == VMX_INTR_TYPE_SOFT_EXCEPTION, - "L1 intercepts #OF"); - - return VMX_TEST_VMEXIT; -} - -static void exit_monitor_from_l2_main(void) -{ - printf("Calling exit(0) from l2...\n"); - exit(0); -} - -static int exit_monitor_from_l2_handler(union exit_reason exit_reason) -{ - report(false, "The guest should have killed the VMM"); - return VMX_TEST_EXIT; -} - -static void assert_exit_reason(u64 expected) -{ - u64 actual = vmcs_read(EXI_REASON); - - TEST_ASSERT_EQ_MSG(expected, actual, "Expected %s, got %s.", - exit_reason_description(expected), - exit_reason_description(actual)); -} - -static void skip_exit_insn(void) -{ - u64 guest_rip = vmcs_read(GUEST_RIP); - u32 insn_len = vmcs_read(EXI_INST_LEN); - vmcs_write(GUEST_RIP, guest_rip + insn_len); -} - -static void skip_exit_vmcall(void) -{ - assert_exit_reason(VMX_VMCALL); - skip_exit_insn(); -} - -static void v2_null_test_guest(void) -{ -} - -static void v2_null_test(void) -{ - test_set_guest(v2_null_test_guest); - enter_guest(); - report(1, __func__); -} - -static void v2_multiple_entries_test_guest(void) -{ - vmx_set_test_stage(1); - vmcall(); - vmx_set_test_stage(2); -} - -static void v2_multiple_entries_test(void) -{ - test_set_guest(v2_multiple_entries_test_guest); - enter_guest(); - TEST_ASSERT_EQ(vmx_get_test_stage(), 1); - skip_exit_vmcall(); - enter_guest(); - TEST_ASSERT_EQ(vmx_get_test_stage(), 2); - report(1, __func__); -} - -static int fixture_test_data = 1; - -static void fixture_test_teardown(void *data) -{ - *((int *) data) = 1; -} - -static void fixture_test_guest(void) -{ - fixture_test_data++; -} - - -static void fixture_test_setup(void) -{ - TEST_ASSERT_EQ_MSG(1, fixture_test_data, - "fixture_test_teardown didn't run?!"); - fixture_test_data = 2; - test_add_teardown(fixture_test_teardown, &fixture_test_data); - test_set_guest(fixture_test_guest); -} - -static void fixture_test_case1(void) -{ - fixture_test_setup(); - TEST_ASSERT_EQ(2, fixture_test_data); - enter_guest(); - TEST_ASSERT_EQ(3, fixture_test_data); - report(1, __func__); -} - -static void fixture_test_case2(void) -{ - fixture_test_setup(); - TEST_ASSERT_EQ(2, fixture_test_data); - enter_guest(); - TEST_ASSERT_EQ(3, fixture_test_data); - report(1, __func__); -} - -enum ept_access_op { - OP_READ, - OP_WRITE, - OP_EXEC, - OP_FLUSH_TLB, - OP_EXIT, -}; - -static struct ept_access_test_data { - unsigned long gpa; - unsigned long *gva; - unsigned long hpa; - unsigned long *hva; - enum ept_access_op op; -} ept_access_test_data; - -extern unsigned char ret42_start; -extern unsigned char ret42_end; - -/* Returns 42. */ -asm( - ".align 64\n" - "ret42_start:\n" - "mov $42, %eax\n" - "ret\n" - "ret42_end:\n" -); - -static void -diagnose_ept_violation_qual(u64 expected, u64 actual) -{ - -#define DIAGNOSE(flag) \ -do { \ - if ((expected & flag) != (actual & flag)) \ - printf(#flag " %sexpected\n", \ - (expected & flag) ? "" : "un"); \ -} while (0) - - DIAGNOSE(EPT_VLT_RD); - DIAGNOSE(EPT_VLT_WR); - DIAGNOSE(EPT_VLT_FETCH); - DIAGNOSE(EPT_VLT_PERM_RD); - DIAGNOSE(EPT_VLT_PERM_WR); - DIAGNOSE(EPT_VLT_PERM_EX); - DIAGNOSE(EPT_VLT_LADDR_VLD); - DIAGNOSE(EPT_VLT_PADDR); - -#undef DIAGNOSE -} - -static void do_ept_access_op(enum ept_access_op op) -{ - ept_access_test_data.op = op; - enter_guest(); -} - -/* - * Force the guest to flush its TLB (i.e., flush gva -> gpa mappings). Only - * needed by tests that modify guest PTEs. - */ -static void ept_access_test_guest_flush_tlb(void) -{ - do_ept_access_op(OP_FLUSH_TLB); - skip_exit_vmcall(); -} - -/* - * Modifies the EPT entry at @level in the mapping of @gpa. First clears the - * bits in @clear then sets the bits in @set. @mkhuge transforms the entry into - * a huge page. - */ -static unsigned long ept_twiddle(unsigned long gpa, bool mkhuge, int level, - unsigned long clear, unsigned long set) -{ - struct ept_access_test_data *data = &ept_access_test_data; - unsigned long orig_pte; - unsigned long pte; - - /* Screw with the mapping at the requested level. */ - TEST_ASSERT(get_ept_pte(pml4, gpa, level, &orig_pte)); - pte = orig_pte; - if (mkhuge) - pte = (orig_pte & ~EPT_ADDR_MASK) | data->hpa | EPT_LARGE_PAGE; - else - pte = orig_pte; - pte = (pte & ~clear) | set; - set_ept_pte(pml4, gpa, level, pte); - ept_sync(INVEPT_SINGLE, eptp); - - return orig_pte; -} - -static void ept_untwiddle(unsigned long gpa, int level, unsigned long orig_pte) -{ - set_ept_pte(pml4, gpa, level, orig_pte); - ept_sync(INVEPT_SINGLE, eptp); -} - -static void do_ept_violation(bool leaf, enum ept_access_op op, - u64 expected_qual, u64 expected_paddr) -{ - u64 qual; - - /* Try the access and observe the violation. */ - do_ept_access_op(op); - - assert_exit_reason(VMX_EPT_VIOLATION); - - qual = vmcs_read(EXI_QUALIFICATION); - - /* Mask undefined bits (which may later be defined in certain cases). */ - qual &= ~(EPT_VLT_GUEST_USER | EPT_VLT_GUEST_RW | EPT_VLT_GUEST_EX | - EPT_VLT_PERM_USER_EX); - - diagnose_ept_violation_qual(expected_qual, qual); - TEST_EXPECT_EQ(expected_qual, qual); - - #if 0 - /* Disable for now otherwise every test will fail */ - TEST_EXPECT_EQ(vmcs_read(GUEST_LINEAR_ADDRESS), - (unsigned long) ( - op == OP_EXEC ? data->gva + 1 : data->gva)); - #endif - /* - * TODO: tests that probe expected_paddr in pages other than the one at - * the beginning of the 1g region. - */ - TEST_EXPECT_EQ(vmcs_read(INFO_PHYS_ADDR), expected_paddr); -} - -static void -ept_violation_at_level_mkhuge(bool mkhuge, int level, unsigned long clear, - unsigned long set, enum ept_access_op op, - u64 expected_qual) -{ - struct ept_access_test_data *data = &ept_access_test_data; - unsigned long orig_pte; - - orig_pte = ept_twiddle(data->gpa, mkhuge, level, clear, set); - - do_ept_violation(level == 1 || mkhuge, op, expected_qual, - op == OP_EXEC ? data->gpa + sizeof(unsigned long) : - data->gpa); - - /* Fix the violation and resume the op loop. */ - ept_untwiddle(data->gpa, level, orig_pte); - enter_guest(); - skip_exit_vmcall(); -} - -static void -ept_violation_at_level(int level, unsigned long clear, unsigned long set, - enum ept_access_op op, u64 expected_qual) -{ - ept_violation_at_level_mkhuge(false, level, clear, set, op, - expected_qual); - if (ept_huge_pages_supported(level)) - ept_violation_at_level_mkhuge(true, level, clear, set, op, - expected_qual); -} - -static void ept_violation(unsigned long clear, unsigned long set, - enum ept_access_op op, u64 expected_qual) -{ - ept_violation_at_level(1, clear, set, op, expected_qual); - ept_violation_at_level(2, clear, set, op, expected_qual); - ept_violation_at_level(3, clear, set, op, expected_qual); - ept_violation_at_level(4, clear, set, op, expected_qual); -} - -static void ept_access_violation(unsigned long access, enum ept_access_op op, - u64 expected_qual) -{ - ept_violation(EPT_PRESENT, access, op, - expected_qual | EPT_VLT_LADDR_VLD | EPT_VLT_PADDR); -} - -/* - * For translations that don't involve a GVA, that is physical address (paddr) - * accesses, EPT violations don't set the flag EPT_VLT_PADDR. For a typical - * guest memory access, the hardware does GVA -> GPA -> HPA. However, certain - * translations don't involve GVAs, such as when the hardware does the guest - * page table walk. For example, in translating GVA_1 -> GPA_1, the guest MMU - * might try to set an A bit on a guest PTE. If the GPA_2 that the PTE resides - * on isn't present in the EPT, then the EPT violation will be for GPA_2 and - * the EPT_VLT_PADDR bit will be clear in the exit qualification. - * - * Note that paddr violations can also be triggered by loading PAE page tables - * with wonky addresses. We don't test that yet. - * - * This function modifies the EPT entry that maps the GPA that the guest page - * table entry mapping ept_access_test_data.gva resides on. - * - * @ept_access EPT permissions to set. Other permissions are cleared. - * - * @pte_ad Set the A/D bits on the guest PTE accordingly. - * - * @op Guest operation to perform with - * ept_access_test_data.gva. - * - * @expect_violation - * Is a violation expected during the paddr access? - * - * @expected_qual Expected qualification for the EPT violation. - * EPT_VLT_PADDR should be clear. - */ -static void ept_access_paddr(unsigned long ept_access, unsigned long pte_ad, - enum ept_access_op op, bool expect_violation, - u64 expected_qual) -{ - struct ept_access_test_data *data = &ept_access_test_data; - unsigned long *ptep; - unsigned long gpa; - unsigned long orig_epte; - unsigned long epte; - int i; - - /* Modify the guest PTE mapping data->gva according to @pte_ad. */ - ptep = get_pte_level(current_page_table(), data->gva, /*level=*/1); - TEST_ASSERT(ptep); - TEST_ASSERT_EQ(*ptep & PT_ADDR_MASK, data->gpa); - *ptep = (*ptep & ~PT_AD_MASK) | pte_ad; - ept_access_test_guest_flush_tlb(); - - /* - * Now modify the access bits on the EPT entry for the GPA that the - * guest PTE resides on. Note that by modifying a single EPT entry, - * we're potentially affecting 512 guest PTEs. However, we've carefully - * constructed our test such that those other 511 PTEs aren't used by - * the guest: data->gva is at the beginning of a 1G huge page, thus the - * PTE we're modifying is at the beginning of a 4K page and the - * following 511 entires are also under our control (and not touched by - * the guest). - */ - gpa = virt_to_phys(ptep); - TEST_ASSERT_EQ(gpa & ~PAGE_MASK, 0); - /* - * Make sure the guest page table page is mapped with a 4K EPT entry, - * otherwise our level=1 twiddling below will fail. We use the - * identity map (gpa = gpa) since page tables are shared with the host. - */ - install_ept(pml4, gpa, gpa, EPT_PRESENT); - orig_epte = ept_twiddle(gpa, /*mkhuge=*/0, /*level=*/1, - /*clear=*/EPT_PRESENT, /*set=*/ept_access); - - if (expect_violation) { - do_ept_violation(/*leaf=*/true, op, - expected_qual | EPT_VLT_LADDR_VLD, gpa); - ept_untwiddle(gpa, /*level=*/1, orig_epte); - do_ept_access_op(op); - } else { - do_ept_access_op(op); - if (ept_ad_enabled()) { - for (i = EPT_PAGE_LEVEL; i > 0; i--) { - TEST_ASSERT(get_ept_pte(pml4, gpa, i, &epte)); - TEST_ASSERT(epte & EPT_ACCESS_FLAG); - if (i == 1) - TEST_ASSERT(epte & EPT_DIRTY_FLAG); - else - TEST_ASSERT_EQ(epte & EPT_DIRTY_FLAG, 0); - } - } - - ept_untwiddle(gpa, /*level=*/1, orig_epte); - } - - TEST_ASSERT(*ptep & PT_ACCESSED_MASK); - if ((pte_ad & PT_DIRTY_MASK) || op == OP_WRITE) - TEST_ASSERT(*ptep & PT_DIRTY_MASK); - - skip_exit_vmcall(); -} - -static void ept_access_allowed_paddr(unsigned long ept_access, - unsigned long pte_ad, - enum ept_access_op op) -{ - ept_access_paddr(ept_access, pte_ad, op, /*expect_violation=*/false, - /*expected_qual=*/-1); -} - -static void ept_access_violation_paddr(unsigned long ept_access, - unsigned long pte_ad, - enum ept_access_op op, - u64 expected_qual) -{ - ept_access_paddr(ept_access, pte_ad, op, /*expect_violation=*/true, - expected_qual); -} - - -static void ept_allowed_at_level_mkhuge(bool mkhuge, int level, - unsigned long clear, - unsigned long set, - enum ept_access_op op) -{ - struct ept_access_test_data *data = &ept_access_test_data; - unsigned long orig_pte; - - orig_pte = ept_twiddle(data->gpa, mkhuge, level, clear, set); - - /* No violation. Should proceed to vmcall. */ - do_ept_access_op(op); - skip_exit_vmcall(); - - ept_untwiddle(data->gpa, level, orig_pte); -} - -static void ept_allowed_at_level(int level, unsigned long clear, - unsigned long set, enum ept_access_op op) -{ - ept_allowed_at_level_mkhuge(false, level, clear, set, op); - if (ept_huge_pages_supported(level)) - ept_allowed_at_level_mkhuge(true, level, clear, set, op); -} - -static void ept_allowed(unsigned long clear, unsigned long set, - enum ept_access_op op) -{ - ept_allowed_at_level(1, clear, set, op); - ept_allowed_at_level(2, clear, set, op); - ept_allowed_at_level(3, clear, set, op); - ept_allowed_at_level(4, clear, set, op); -} - -static void ept_ignored_bit(int bit) -{ - /* Set the bit. */ - ept_allowed(0, 1ul << bit, OP_READ); - ept_allowed(0, 1ul << bit, OP_WRITE); - ept_allowed(0, 1ul << bit, OP_EXEC); - - /* Clear the bit. */ - ept_allowed(1ul << bit, 0, OP_READ); - ept_allowed(1ul << bit, 0, OP_WRITE); - ept_allowed(1ul << bit, 0, OP_EXEC); -} - -static void ept_access_allowed(unsigned long access, enum ept_access_op op) -{ - ept_allowed(EPT_PRESENT, access, op); -} - - -static void ept_misconfig_at_level_mkhuge_op(bool mkhuge, int level, - unsigned long clear, - unsigned long set, - enum ept_access_op op) -{ - struct ept_access_test_data *data = &ept_access_test_data; - unsigned long orig_pte; - - orig_pte = ept_twiddle(data->gpa, mkhuge, level, clear, set); - - do_ept_access_op(op); - assert_exit_reason(VMX_EPT_MISCONFIG); - - /* Intel 27.2.1, "For all other VM exits, this field is cleared." */ - #if 0 - /* broken: */ - TEST_EXPECT_EQ_MSG(vmcs_read(EXI_QUALIFICATION), 0); - #endif - #if 0 - /* - * broken: - * According to description of exit qual for EPT violation, - * EPT_VLT_LADDR_VLD indicates if GUEST_LINEAR_ADDRESS is valid. - * However, I can't find anything that says GUEST_LINEAR_ADDRESS ought - * to be set for msiconfig. - */ - TEST_EXPECT_EQ(vmcs_read(GUEST_LINEAR_ADDRESS), - (unsigned long) ( - op == OP_EXEC ? data->gva + 1 : data->gva)); - #endif - - /* Fix the violation and resume the op loop. */ - ept_untwiddle(data->gpa, level, orig_pte); - enter_guest(); - skip_exit_vmcall(); -} - -static void ept_misconfig_at_level_mkhuge(bool mkhuge, int level, - unsigned long clear, - unsigned long set) -{ - /* The op shouldn't matter (read, write, exec), so try them all! */ - ept_misconfig_at_level_mkhuge_op(mkhuge, level, clear, set, OP_READ); - ept_misconfig_at_level_mkhuge_op(mkhuge, level, clear, set, OP_WRITE); - ept_misconfig_at_level_mkhuge_op(mkhuge, level, clear, set, OP_EXEC); -} - -static void ept_misconfig_at_level(int level, unsigned long clear, - unsigned long set) -{ - ept_misconfig_at_level_mkhuge(false, level, clear, set); - if (ept_huge_pages_supported(level)) - ept_misconfig_at_level_mkhuge(true, level, clear, set); -} - -static void ept_misconfig(unsigned long clear, unsigned long set) -{ - ept_misconfig_at_level(1, clear, set); - ept_misconfig_at_level(2, clear, set); - ept_misconfig_at_level(3, clear, set); - ept_misconfig_at_level(4, clear, set); -} - -static void ept_access_misconfig(unsigned long access) -{ - ept_misconfig(EPT_PRESENT, access); -} - -static void ept_reserved_bit_at_level_nohuge(int level, int bit) -{ - /* Setting the bit causes a misconfig. */ - ept_misconfig_at_level_mkhuge(false, level, 0, 1ul << bit); - - /* Making the entry non-present turns reserved bits into ignored. */ - ept_violation_at_level(level, EPT_PRESENT, 1ul << bit, OP_READ, - EPT_VLT_RD | EPT_VLT_LADDR_VLD | EPT_VLT_PADDR); -} - -static void ept_reserved_bit_at_level_huge(int level, int bit) -{ - /* Setting the bit causes a misconfig. */ - ept_misconfig_at_level_mkhuge(true, level, 0, 1ul << bit); - - /* Making the entry non-present turns reserved bits into ignored. */ - ept_violation_at_level(level, EPT_PRESENT, 1ul << bit, OP_READ, - EPT_VLT_RD | EPT_VLT_LADDR_VLD | EPT_VLT_PADDR); -} - -static void ept_reserved_bit_at_level(int level, int bit) -{ - /* Setting the bit causes a misconfig. */ - ept_misconfig_at_level(level, 0, 1ul << bit); - - /* Making the entry non-present turns reserved bits into ignored. */ - ept_violation_at_level(level, EPT_PRESENT, 1ul << bit, OP_READ, - EPT_VLT_RD | EPT_VLT_LADDR_VLD | EPT_VLT_PADDR); -} - -static void ept_reserved_bit(int bit) -{ - ept_reserved_bit_at_level(1, bit); - ept_reserved_bit_at_level(2, bit); - ept_reserved_bit_at_level(3, bit); - ept_reserved_bit_at_level(4, bit); -} - -#define PAGE_2M_ORDER 9 -#define PAGE_1G_ORDER 18 - -static void *get_1g_page(void) -{ - static void *alloc; - - if (!alloc) - alloc = alloc_pages(PAGE_1G_ORDER); - return alloc; -} - -static void ept_access_test_teardown(void *unused) -{ - /* Exit the guest cleanly. */ - do_ept_access_op(OP_EXIT); -} - -static void ept_access_test_guest(void) -{ - struct ept_access_test_data *data = &ept_access_test_data; - int (*code)(void) = (int (*)(void)) &data->gva[1]; - - while (true) { - switch (data->op) { - case OP_READ: - TEST_ASSERT_EQ(*data->gva, MAGIC_VAL_1); - break; - case OP_WRITE: - *data->gva = MAGIC_VAL_2; - TEST_ASSERT_EQ(*data->gva, MAGIC_VAL_2); - *data->gva = MAGIC_VAL_1; - break; - case OP_EXEC: - TEST_ASSERT_EQ(42, code()); - break; - case OP_FLUSH_TLB: - write_cr3(read_cr3()); - break; - case OP_EXIT: - return; - default: - TEST_ASSERT_MSG(false, "Unknown op %d", data->op); - } - vmcall(); - } -} - -static void ept_access_test_setup(void) -{ - struct ept_access_test_data *data = &ept_access_test_data; - unsigned long npages = 1ul << PAGE_1G_ORDER; - unsigned long size = npages * PAGE_SIZE; - unsigned long *page_table = current_page_table(); - unsigned long pte; - - if (setup_ept(false)) - test_skip("EPT not supported"); - - /* We use data->gpa = 1 << 39 so that test data has a separate pml4 entry */ - if (cpuid_maxphyaddr() < 40) - test_skip("Test needs MAXPHYADDR >= 40"); - - test_set_guest(ept_access_test_guest); - test_add_teardown(ept_access_test_teardown, NULL); - - data->hva = get_1g_page(); - TEST_ASSERT(data->hva); - data->hpa = virt_to_phys(data->hva); - - data->gpa = 1ul << 39; - data->gva = (void *) ALIGN((unsigned long) alloc_vpages(npages * 2), - size); - TEST_ASSERT(!any_present_pages(page_table, data->gva, size)); - install_pages(page_table, data->gpa, size, data->gva); - - /* - * Make sure nothing's mapped here so the tests that screw with the - * pml4 entry don't inadvertently break something. - */ - TEST_ASSERT(get_ept_pte(pml4, data->gpa, 4, &pte) && pte == 0); - TEST_ASSERT(get_ept_pte(pml4, data->gpa + size - 1, 4, &pte) && pte == 0); - install_ept(pml4, data->hpa, data->gpa, EPT_PRESENT); - - data->hva[0] = MAGIC_VAL_1; - memcpy(&data->hva[1], &ret42_start, &ret42_end - &ret42_start); -} - -static void ept_access_test_not_present(void) -{ - ept_access_test_setup(); - /* --- */ - ept_access_violation(0, OP_READ, EPT_VLT_RD); - ept_access_violation(0, OP_WRITE, EPT_VLT_WR); - ept_access_violation(0, OP_EXEC, EPT_VLT_FETCH); -} - -static void ept_access_test_read_only(void) -{ - ept_access_test_setup(); - - /* r-- */ - ept_access_allowed(EPT_RA, OP_READ); - ept_access_violation(EPT_RA, OP_WRITE, EPT_VLT_WR | EPT_VLT_PERM_RD); - ept_access_violation(EPT_RA, OP_EXEC, EPT_VLT_FETCH | EPT_VLT_PERM_RD); -} - -static void ept_access_test_write_only(void) -{ - ept_access_test_setup(); - /* -w- */ - ept_access_misconfig(EPT_WA); -} - -static void ept_access_test_read_write(void) -{ - ept_access_test_setup(); - /* rw- */ - ept_access_allowed(EPT_RA | EPT_WA, OP_READ); - ept_access_allowed(EPT_RA | EPT_WA, OP_WRITE); - ept_access_violation(EPT_RA | EPT_WA, OP_EXEC, - EPT_VLT_FETCH | EPT_VLT_PERM_RD | EPT_VLT_PERM_WR); -} - - -static void ept_access_test_execute_only(void) -{ - ept_access_test_setup(); - /* --x */ - if (ept_execute_only_supported()) { - ept_access_violation(EPT_EA, OP_READ, - EPT_VLT_RD | EPT_VLT_PERM_EX); - ept_access_violation(EPT_EA, OP_WRITE, - EPT_VLT_WR | EPT_VLT_PERM_EX); - ept_access_allowed(EPT_EA, OP_EXEC); - } else { - ept_access_misconfig(EPT_EA); - } -} - -static void ept_access_test_read_execute(void) -{ - ept_access_test_setup(); - /* r-x */ - ept_access_allowed(EPT_RA | EPT_EA, OP_READ); - ept_access_violation(EPT_RA | EPT_EA, OP_WRITE, - EPT_VLT_WR | EPT_VLT_PERM_RD | EPT_VLT_PERM_EX); - ept_access_allowed(EPT_RA | EPT_EA, OP_EXEC); -} - -static void ept_access_test_write_execute(void) -{ - ept_access_test_setup(); - /* -wx */ - ept_access_misconfig(EPT_WA | EPT_EA); -} - -static void ept_access_test_read_write_execute(void) -{ - ept_access_test_setup(); - /* rwx */ - ept_access_allowed(EPT_RA | EPT_WA | EPT_EA, OP_READ); - ept_access_allowed(EPT_RA | EPT_WA | EPT_EA, OP_WRITE); - ept_access_allowed(EPT_RA | EPT_WA | EPT_EA, OP_EXEC); -} - -static void ept_access_test_reserved_bits(void) -{ - int i; - int maxphyaddr; - - ept_access_test_setup(); - - /* Reserved bits above maxphyaddr. */ - maxphyaddr = cpuid_maxphyaddr(); - for (i = maxphyaddr; i <= 51; i++) { - report_prefix_pushf("reserved_bit=%d", i); - ept_reserved_bit(i); - report_prefix_pop(); - } - - /* Level-specific reserved bits. */ - ept_reserved_bit_at_level_nohuge(2, 3); - ept_reserved_bit_at_level_nohuge(2, 4); - ept_reserved_bit_at_level_nohuge(2, 5); - ept_reserved_bit_at_level_nohuge(2, 6); - /* 2M alignment. */ - for (i = 12; i < 20; i++) { - report_prefix_pushf("reserved_bit=%d", i); - ept_reserved_bit_at_level_huge(2, i); - report_prefix_pop(); - } - ept_reserved_bit_at_level_nohuge(3, 3); - ept_reserved_bit_at_level_nohuge(3, 4); - ept_reserved_bit_at_level_nohuge(3, 5); - ept_reserved_bit_at_level_nohuge(3, 6); - /* 1G alignment. */ - for (i = 12; i < 29; i++) { - report_prefix_pushf("reserved_bit=%d", i); - ept_reserved_bit_at_level_huge(3, i); - report_prefix_pop(); - } - ept_reserved_bit_at_level(4, 3); - ept_reserved_bit_at_level(4, 4); - ept_reserved_bit_at_level(4, 5); - ept_reserved_bit_at_level(4, 6); - ept_reserved_bit_at_level(4, 7); -} - -static void ept_access_test_ignored_bits(void) -{ - ept_access_test_setup(); - /* - * Bits ignored at every level. Bits 8 and 9 (A and D) are ignored as - * far as translation is concerned even if AD bits are enabled in the - * EPTP. Bit 63 is ignored because "EPT-violation #VE" VM-execution - * control is 0. - */ - ept_ignored_bit(8); - ept_ignored_bit(9); - ept_ignored_bit(10); - ept_ignored_bit(11); - ept_ignored_bit(52); - ept_ignored_bit(53); - ept_ignored_bit(54); - ept_ignored_bit(55); - ept_ignored_bit(56); - ept_ignored_bit(57); - ept_ignored_bit(58); - ept_ignored_bit(59); - ept_ignored_bit(60); - ept_ignored_bit(61); - ept_ignored_bit(62); - ept_ignored_bit(63); -} - -static void ept_access_test_paddr_not_present_ad_disabled(void) -{ - ept_access_test_setup(); - ept_disable_ad_bits(); - - ept_access_violation_paddr(0, PT_AD_MASK, OP_READ, EPT_VLT_RD); - ept_access_violation_paddr(0, PT_AD_MASK, OP_WRITE, EPT_VLT_RD); - ept_access_violation_paddr(0, PT_AD_MASK, OP_EXEC, EPT_VLT_RD); -} - -static void ept_access_test_paddr_not_present_ad_enabled(void) -{ - u64 qual = EPT_VLT_RD | EPT_VLT_WR; - - ept_access_test_setup(); - ept_enable_ad_bits_or_skip_test(); - - ept_access_violation_paddr(0, PT_AD_MASK, OP_READ, qual); - ept_access_violation_paddr(0, PT_AD_MASK, OP_WRITE, qual); - ept_access_violation_paddr(0, PT_AD_MASK, OP_EXEC, qual); -} - -static void ept_access_test_paddr_read_only_ad_disabled(void) -{ - /* - * When EPT AD bits are disabled, all accesses to guest paging - * structures are reported separately as a read and (after - * translation of the GPA to host physical address) a read+write - * if the A/D bits have to be set. - */ - u64 qual = EPT_VLT_WR | EPT_VLT_RD | EPT_VLT_PERM_RD; - - ept_access_test_setup(); - ept_disable_ad_bits(); - - /* Can't update A bit, so all accesses fail. */ - ept_access_violation_paddr(EPT_RA, 0, OP_READ, qual); - ept_access_violation_paddr(EPT_RA, 0, OP_WRITE, qual); - ept_access_violation_paddr(EPT_RA, 0, OP_EXEC, qual); - /* AD bits disabled, so only writes try to update the D bit. */ - ept_access_allowed_paddr(EPT_RA, PT_ACCESSED_MASK, OP_READ); - ept_access_violation_paddr(EPT_RA, PT_ACCESSED_MASK, OP_WRITE, qual); - ept_access_allowed_paddr(EPT_RA, PT_ACCESSED_MASK, OP_EXEC); - /* Both A and D already set, so read-only is OK. */ - ept_access_allowed_paddr(EPT_RA, PT_AD_MASK, OP_READ); - ept_access_allowed_paddr(EPT_RA, PT_AD_MASK, OP_WRITE); - ept_access_allowed_paddr(EPT_RA, PT_AD_MASK, OP_EXEC); -} - -static void ept_access_test_paddr_read_only_ad_enabled(void) -{ - /* - * When EPT AD bits are enabled, all accesses to guest paging - * structures are considered writes as far as EPT translation - * is concerned. - */ - u64 qual = EPT_VLT_WR | EPT_VLT_RD | EPT_VLT_PERM_RD; - - ept_access_test_setup(); - ept_enable_ad_bits_or_skip_test(); - - ept_access_violation_paddr(EPT_RA, 0, OP_READ, qual); - ept_access_violation_paddr(EPT_RA, 0, OP_WRITE, qual); - ept_access_violation_paddr(EPT_RA, 0, OP_EXEC, qual); - ept_access_violation_paddr(EPT_RA, PT_ACCESSED_MASK, OP_READ, qual); - ept_access_violation_paddr(EPT_RA, PT_ACCESSED_MASK, OP_WRITE, qual); - ept_access_violation_paddr(EPT_RA, PT_ACCESSED_MASK, OP_EXEC, qual); - ept_access_violation_paddr(EPT_RA, PT_AD_MASK, OP_READ, qual); - ept_access_violation_paddr(EPT_RA, PT_AD_MASK, OP_WRITE, qual); - ept_access_violation_paddr(EPT_RA, PT_AD_MASK, OP_EXEC, qual); -} - -static void ept_access_test_paddr_read_write(void) -{ - ept_access_test_setup(); - /* Read-write access to paging structure. */ - ept_access_allowed_paddr(EPT_RA | EPT_WA, 0, OP_READ); - ept_access_allowed_paddr(EPT_RA | EPT_WA, 0, OP_WRITE); - ept_access_allowed_paddr(EPT_RA | EPT_WA, 0, OP_EXEC); -} - -static void ept_access_test_paddr_read_write_execute(void) -{ - ept_access_test_setup(); - /* RWX access to paging structure. */ - ept_access_allowed_paddr(EPT_PRESENT, 0, OP_READ); - ept_access_allowed_paddr(EPT_PRESENT, 0, OP_WRITE); - ept_access_allowed_paddr(EPT_PRESENT, 0, OP_EXEC); -} - -static void ept_access_test_paddr_read_execute_ad_disabled(void) -{ - /* - * When EPT AD bits are disabled, all accesses to guest paging - * structures are reported separately as a read and (after - * translation of the GPA to host physical address) a read+write - * if the A/D bits have to be set. - */ - u64 qual = EPT_VLT_WR | EPT_VLT_RD | EPT_VLT_PERM_RD | EPT_VLT_PERM_EX; - - ept_access_test_setup(); - ept_disable_ad_bits(); - - /* Can't update A bit, so all accesses fail. */ - ept_access_violation_paddr(EPT_RA | EPT_EA, 0, OP_READ, qual); - ept_access_violation_paddr(EPT_RA | EPT_EA, 0, OP_WRITE, qual); - ept_access_violation_paddr(EPT_RA | EPT_EA, 0, OP_EXEC, qual); - /* AD bits disabled, so only writes try to update the D bit. */ - ept_access_allowed_paddr(EPT_RA | EPT_EA, PT_ACCESSED_MASK, OP_READ); - ept_access_violation_paddr(EPT_RA | EPT_EA, PT_ACCESSED_MASK, OP_WRITE, qual); - ept_access_allowed_paddr(EPT_RA | EPT_EA, PT_ACCESSED_MASK, OP_EXEC); - /* Both A and D already set, so read-only is OK. */ - ept_access_allowed_paddr(EPT_RA | EPT_EA, PT_AD_MASK, OP_READ); - ept_access_allowed_paddr(EPT_RA | EPT_EA, PT_AD_MASK, OP_WRITE); - ept_access_allowed_paddr(EPT_RA | EPT_EA, PT_AD_MASK, OP_EXEC); -} - -static void ept_access_test_paddr_read_execute_ad_enabled(void) -{ - /* - * When EPT AD bits are enabled, all accesses to guest paging - * structures are considered writes as far as EPT translation - * is concerned. - */ - u64 qual = EPT_VLT_WR | EPT_VLT_RD | EPT_VLT_PERM_RD | EPT_VLT_PERM_EX; - - ept_access_test_setup(); - ept_enable_ad_bits_or_skip_test(); - - ept_access_violation_paddr(EPT_RA | EPT_EA, 0, OP_READ, qual); - ept_access_violation_paddr(EPT_RA | EPT_EA, 0, OP_WRITE, qual); - ept_access_violation_paddr(EPT_RA | EPT_EA, 0, OP_EXEC, qual); - ept_access_violation_paddr(EPT_RA | EPT_EA, PT_ACCESSED_MASK, OP_READ, qual); - ept_access_violation_paddr(EPT_RA | EPT_EA, PT_ACCESSED_MASK, OP_WRITE, qual); - ept_access_violation_paddr(EPT_RA | EPT_EA, PT_ACCESSED_MASK, OP_EXEC, qual); - ept_access_violation_paddr(EPT_RA | EPT_EA, PT_AD_MASK, OP_READ, qual); - ept_access_violation_paddr(EPT_RA | EPT_EA, PT_AD_MASK, OP_WRITE, qual); - ept_access_violation_paddr(EPT_RA | EPT_EA, PT_AD_MASK, OP_EXEC, qual); -} - -static void ept_access_test_paddr_not_present_page_fault(void) -{ - ept_access_test_setup(); - /* - * TODO: test no EPT violation as long as guest PF occurs. e.g., GPA is - * page is read-only in EPT but GVA is also mapped read only in PT. - * Thus guest page fault before host takes EPT violation for trying to - * update A bit. - */ -} - -static void ept_access_test_force_2m_page(void) -{ - ept_access_test_setup(); - - TEST_ASSERT_EQ(ept_2m_supported(), true); - ept_allowed_at_level_mkhuge(true, 2, 0, 0, OP_READ); - ept_violation_at_level_mkhuge(true, 2, EPT_PRESENT, EPT_RA, OP_WRITE, - EPT_VLT_WR | EPT_VLT_PERM_RD | - EPT_VLT_LADDR_VLD | EPT_VLT_PADDR); - ept_misconfig_at_level_mkhuge(true, 2, EPT_PRESENT, EPT_WA); -} - -static bool invvpid_valid(u64 type, u64 vpid, u64 gla) -{ - u64 msr = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP); - - TEST_ASSERT(msr & VPID_CAP_INVVPID); - - if (type < INVVPID_ADDR || type > INVVPID_CONTEXT_LOCAL) - return false; - - if (!(msr & (1ull << (type + VPID_CAP_INVVPID_TYPES_SHIFT)))) - return false; - - if (vpid >> 16) - return false; - - if (type != INVVPID_ALL && !vpid) - return false; - - if (type == INVVPID_ADDR && !is_canonical(gla)) - return false; - - return true; -} - -static void try_invvpid(u64 type, u64 vpid, u64 gla) -{ - int rc; - bool valid = invvpid_valid(type, vpid, gla); - u64 expected = valid ? VMXERR_UNSUPPORTED_VMCS_COMPONENT - : VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID; - /* - * Set VMX_INST_ERROR to VMXERR_UNVALID_VMCS_COMPONENT, so - * that we can tell if it is updated by INVVPID. - */ - vmcs_read(~0); - rc = invvpid(type, vpid, gla); - report(!rc == valid, "INVVPID type %ld VPID %lx GLA %lx %s", type, - vpid, gla, - valid ? "passes" : "fails"); - report(vmcs_read(VMX_INST_ERROR) == expected, - "After %s INVVPID, VMX_INST_ERR is %ld (actual %ld)", - rc ? "failed" : "successful", - expected, vmcs_read(VMX_INST_ERROR)); -} - -static void ds_invvpid(void *data) -{ - u64 msr = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP); - u64 type = ffs(msr >> VPID_CAP_INVVPID_TYPES_SHIFT) - 1; - - TEST_ASSERT(type >= INVVPID_ADDR && type <= INVVPID_CONTEXT_LOCAL); - asm volatile("invvpid %0, %1" - : - : "m"(*(struct invvpid_operand *)data), - "r"(type)); -} - -/* - * The SS override is ignored in 64-bit mode, so we use an addressing - * mode with %rsp as the base register to generate an implicit SS - * reference. - */ -static void ss_invvpid(void *data) -{ - u64 msr = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP); - u64 type = ffs(msr >> VPID_CAP_INVVPID_TYPES_SHIFT) - 1; - - TEST_ASSERT(type >= INVVPID_ADDR && type <= INVVPID_CONTEXT_LOCAL); - asm volatile("sub %%rsp,%0; invvpid (%%rsp,%0,1), %1" - : "+r"(data) - : "r"(type)); -} - -static void invvpid_test_gp(void) -{ - bool fault; - - fault = test_for_exception(GP_VECTOR, &ds_invvpid, - (void *)NONCANONICAL); - report(fault, "INVVPID with non-canonical DS operand raises #GP"); -} - -static void invvpid_test_ss(void) -{ - bool fault; - - fault = test_for_exception(SS_VECTOR, &ss_invvpid, - (void *)NONCANONICAL); - report(fault, "INVVPID with non-canonical SS operand raises #SS"); -} - -static void invvpid_test_pf(void) -{ - void *vpage = alloc_vpage(); - bool fault; - - fault = test_for_exception(PF_VECTOR, &ds_invvpid, vpage); - report(fault, "INVVPID with unmapped operand raises #PF"); -} - -static void try_compat_invvpid(void *unused) -{ - struct far_pointer32 fp = { - .offset = (uintptr_t)&&invvpid, - .selector = KERNEL_CS32, - }; - uintptr_t rsp; - - asm volatile ("mov %%rsp, %0" : "=r"(rsp)); - - TEST_ASSERT_MSG(fp.offset == (uintptr_t)&&invvpid, - "Code address too high."); - TEST_ASSERT_MSG(rsp == (u32)rsp, "Stack address too high."); - - asm goto ("lcall *%0" : : "m" (fp) : "rax" : invvpid); - return; -invvpid: - asm volatile (".code32;" - "invvpid (%eax), %eax;" - "lret;" - ".code64"); - __builtin_unreachable(); -} - -static void invvpid_test_compatibility_mode(void) -{ - bool fault; - - fault = test_for_exception(UD_VECTOR, &try_compat_invvpid, NULL); - report(fault, "Compatibility mode INVVPID raises #UD"); -} - -static void invvpid_test_not_in_vmx_operation(void) -{ - bool fault; - - TEST_ASSERT(!vmx_off()); - fault = test_for_exception(UD_VECTOR, &ds_invvpid, NULL); - report(fault, "INVVPID outside of VMX operation raises #UD"); - TEST_ASSERT(!vmx_on()); -} - -/* - * This does not test real-address mode, virtual-8086 mode, protected mode, - * or CPL > 0. - */ -static void invvpid_test_v2(void) -{ - u64 msr; - int i; - unsigned types = 0; - unsigned type; - - if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) || - !(ctrl_cpu_rev[1].clr & CPU_VPID)) - test_skip("VPID not supported"); - - msr = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP); - - if (!(msr & VPID_CAP_INVVPID)) - test_skip("INVVPID not supported.\n"); - - if (msr & VPID_CAP_INVVPID_ADDR) - types |= 1u << INVVPID_ADDR; - if (msr & VPID_CAP_INVVPID_CXTGLB) - types |= 1u << INVVPID_CONTEXT_GLOBAL; - if (msr & VPID_CAP_INVVPID_ALL) - types |= 1u << INVVPID_ALL; - if (msr & VPID_CAP_INVVPID_CXTLOC) - types |= 1u << INVVPID_CONTEXT_LOCAL; - - if (!types) - test_skip("No INVVPID types supported.\n"); - - for (i = -127; i < 128; i++) - try_invvpid(i, 0xffff, 0); - - /* - * VPID must not be more than 16 bits. - */ - for (i = 0; i < 64; i++) - for (type = 0; type < 4; type++) - if (types & (1u << type)) - try_invvpid(type, 1ul << i, 0); - - /* - * VPID must not be zero, except for "all contexts." - */ - for (type = 0; type < 4; type++) - if (types & (1u << type)) - try_invvpid(type, 0, 0); - - /* - * The gla operand is only validated for single-address INVVPID. - */ - if (types & (1u << INVVPID_ADDR)) - try_invvpid(INVVPID_ADDR, 0xffff, NONCANONICAL); - - invvpid_test_gp(); - invvpid_test_ss(); - invvpid_test_pf(); - invvpid_test_compatibility_mode(); - invvpid_test_not_in_vmx_operation(); -} - -/* - * Test for early VMLAUNCH failure. Returns true if VMLAUNCH makes it - * at least as far as the guest-state checks. Returns false if the - * VMLAUNCH fails early and execution falls through to the next - * instruction. - */ -static bool vmlaunch_succeeds(void) -{ - u32 exit_reason; - - /* - * Indirectly set VMX_INST_ERR to 12 ("VMREAD/VMWRITE from/to - * unsupported VMCS component"). The caller can then check - * to see if a failed VM-entry sets VMX_INST_ERR as expected. - */ - vmcs_write(~0u, 0); - - vmcs_write(HOST_RIP, (uintptr_t)&&success); - __asm__ __volatile__ goto ("vmwrite %%rsp, %0; vmlaunch" - : - : "r" ((u64)HOST_RSP) - : "cc", "memory" - : success); - return false; -success: - exit_reason = vmcs_read(EXI_REASON); - TEST_ASSERT(exit_reason == (VMX_FAIL_STATE | VMX_ENTRY_FAILURE) || - exit_reason == (VMX_FAIL_MSR | VMX_ENTRY_FAILURE)); - return true; -} - -/* - * Try to launch the current VMCS. - */ -static void test_vmx_vmlaunch(u32 xerror) -{ - bool success = vmlaunch_succeeds(); - u32 vmx_inst_err; - - report(success == !xerror, "vmlaunch %s", - !xerror ? "succeeds" : "fails"); - if (!success && xerror) { - vmx_inst_err = vmcs_read(VMX_INST_ERROR); - report(vmx_inst_err == xerror, - "VMX inst error is %d (actual %d)", xerror, - vmx_inst_err); - } -} - -/* - * Try to launch the current VMCS, and expect one of two possible - * errors (or success) codes. - */ -static void test_vmx_vmlaunch2(u32 xerror1, u32 xerror2) -{ - bool success = vmlaunch_succeeds(); - u32 vmx_inst_err; - - if (!xerror1 == !xerror2) - report(success == !xerror1, "vmlaunch %s", - !xerror1 ? "succeeds" : "fails"); - - if (!success && (xerror1 || xerror2)) { - vmx_inst_err = vmcs_read(VMX_INST_ERROR); - report(vmx_inst_err == xerror1 || vmx_inst_err == xerror2, - "VMX inst error is %d or %d (actual %d)", xerror1, - xerror2, vmx_inst_err); - } -} - -static void test_vmx_invalid_controls(void) -{ - test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_CONTROL_FIELD); -} - -static void test_vmx_valid_controls(void) -{ - test_vmx_vmlaunch(0); -} - -/* - * Test a particular value of a VM-execution control bit, if the value - * is required or if the value is zero. - */ -static void test_rsvd_ctl_bit_value(const char *name, union vmx_ctrl_msr msr, - enum Encoding encoding, unsigned bit, - unsigned val) -{ - u32 mask = 1u << bit; - bool expected; - u32 controls; - - if (msr.set & mask) - TEST_ASSERT(msr.clr & mask); - - /* - * We can't arbitrarily turn on a control bit, because it may - * introduce dependencies on other VMCS fields. So, we only - * test turning on bits that have a required setting. - */ - if (val && (msr.clr & mask) && !(msr.set & mask)) - return; - - report_prefix_pushf("%s %s bit %d", - val ? "Set" : "Clear", name, bit); - - controls = vmcs_read(encoding); - if (val) { - vmcs_write(encoding, msr.set | mask); - expected = (msr.clr & mask); - } else { - vmcs_write(encoding, msr.set & ~mask); - expected = !(msr.set & mask); - } - if (expected) - test_vmx_valid_controls(); - else - test_vmx_invalid_controls(); - vmcs_write(encoding, controls); - report_prefix_pop(); -} - -/* - * Test reserved values of a VM-execution control bit, based on the - * allowed bit settings from the corresponding VMX capability MSR. - */ -static void test_rsvd_ctl_bit(const char *name, union vmx_ctrl_msr msr, - enum Encoding encoding, unsigned bit) -{ - test_rsvd_ctl_bit_value(name, msr, encoding, bit, 0); - test_rsvd_ctl_bit_value(name, msr, encoding, bit, 1); -} - -/* - * Reserved bits in the pin-based VM-execution controls must be set - * properly. Software may consult the VMX capability MSRs to determine - * the proper settings. - * [Intel SDM] - */ -static void test_pin_based_ctls(void) -{ - unsigned bit; - - printf("%s: %lx\n", basic.ctrl ? "MSR_IA32_VMX_TRUE_PIN" : - "MSR_IA32_VMX_PINBASED_CTLS", ctrl_pin_rev.val); - for (bit = 0; bit < 32; bit++) - test_rsvd_ctl_bit("pin-based controls", - ctrl_pin_rev, PIN_CONTROLS, bit); -} - -/* - * Reserved bits in the primary processor-based VM-execution controls - * must be set properly. Software may consult the VMX capability MSRs - * to determine the proper settings. - * [Intel SDM] - */ -static void test_primary_processor_based_ctls(void) -{ - unsigned bit; - - printf("\n%s: %lx\n", basic.ctrl ? "MSR_IA32_VMX_TRUE_PROC" : - "MSR_IA32_VMX_PROCBASED_CTLS", ctrl_cpu_rev[0].val); - for (bit = 0; bit < 32; bit++) - test_rsvd_ctl_bit("primary processor-based controls", - ctrl_cpu_rev[0], CPU_EXEC_CTRL0, bit); -} - -/* - * If the "activate secondary controls" primary processor-based - * VM-execution control is 1, reserved bits in the secondary - * processor-based VM-execution controls must be cleared. Software may - * consult the VMX capability MSRs to determine which bits are - * reserved. - * If the "activate secondary controls" primary processor-based - * VM-execution control is 0 (or if the processor does not support the - * 1-setting of that control), no checks are performed on the - * secondary processor-based VM-execution controls. - * [Intel SDM] - */ -static void test_secondary_processor_based_ctls(void) -{ - u32 primary; - u32 secondary; - unsigned bit; - - if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY)) - return; - - primary = vmcs_read(CPU_EXEC_CTRL0); - secondary = vmcs_read(CPU_EXEC_CTRL1); - - vmcs_write(CPU_EXEC_CTRL0, primary | CPU_SECONDARY); - printf("\nMSR_IA32_VMX_PROCBASED_CTLS2: %lx\n", ctrl_cpu_rev[1].val); - for (bit = 0; bit < 32; bit++) - test_rsvd_ctl_bit("secondary processor-based controls", - ctrl_cpu_rev[1], CPU_EXEC_CTRL1, bit); - - /* - * When the "activate secondary controls" VM-execution control - * is clear, there are no checks on the secondary controls. - */ - vmcs_write(CPU_EXEC_CTRL0, primary & ~CPU_SECONDARY); - vmcs_write(CPU_EXEC_CTRL1, ~0); - report(vmlaunch_succeeds(), - "Secondary processor-based controls ignored"); - vmcs_write(CPU_EXEC_CTRL1, secondary); - vmcs_write(CPU_EXEC_CTRL0, primary); -} - -static void try_cr3_target_count(unsigned i, unsigned max) -{ - report_prefix_pushf("CR3 target count 0x%x", i); - vmcs_write(CR3_TARGET_COUNT, i); - if (i <= max) - test_vmx_valid_controls(); - else - test_vmx_invalid_controls(); - report_prefix_pop(); -} - -/* - * The CR3-target count must not be greater than 4. Future processors - * may support a different number of CR3-target values. Software - * should read the VMX capability MSR IA32_VMX_MISC to determine the - * number of values supported. - * [Intel SDM] - */ -static void test_cr3_targets(void) -{ - unsigned supported_targets = (rdmsr(MSR_IA32_VMX_MISC) >> 16) & 0x1ff; - u32 cr3_targets = vmcs_read(CR3_TARGET_COUNT); - unsigned i; - - printf("\nSupported CR3 targets: %d\n", supported_targets); - TEST_ASSERT(supported_targets <= 256); - - try_cr3_target_count(-1u, supported_targets); - try_cr3_target_count(0x80000000, supported_targets); - try_cr3_target_count(0x7fffffff, supported_targets); - for (i = 0; i <= supported_targets + 1; i++) - try_cr3_target_count(i, supported_targets); - vmcs_write(CR3_TARGET_COUNT, cr3_targets); - - /* VMWRITE to nonexistent target fields should fail. */ - for (i = supported_targets; i < 256; i++) - TEST_ASSERT(vmcs_write(CR3_TARGET_0 + i*2, 0)); -} - -/* - * Test a particular address setting in the VMCS - */ -static void test_vmcs_addr(const char *name, - enum Encoding encoding, - u64 align, - bool ignored, - bool skip_beyond_mapped_ram, - u64 addr) -{ - report_prefix_pushf("%s = %lx", name, addr); - vmcs_write(encoding, addr); - if (skip_beyond_mapped_ram && - addr > fwcfg_get_u64(FW_CFG_RAM_SIZE) - align && - addr < (1ul << cpuid_maxphyaddr())) - printf("Skipping physical address beyond mapped RAM\n"); - else if (ignored || (IS_ALIGNED(addr, align) && - addr < (1ul << cpuid_maxphyaddr()))) - test_vmx_valid_controls(); - else - test_vmx_invalid_controls(); - report_prefix_pop(); -} - -/* - * Test interesting values for a VMCS address - */ -static void test_vmcs_addr_values(const char *name, - enum Encoding encoding, - u64 align, - bool ignored, - bool skip_beyond_mapped_ram, - u32 bit_start, u32 bit_end) -{ - unsigned i; - u64 orig_val = vmcs_read(encoding); - - for (i = bit_start; i <= bit_end; i++) - test_vmcs_addr(name, encoding, align, ignored, - skip_beyond_mapped_ram, 1ul << i); - - test_vmcs_addr(name, encoding, align, ignored, - skip_beyond_mapped_ram, PAGE_SIZE - 1); - test_vmcs_addr(name, encoding, align, ignored, - skip_beyond_mapped_ram, PAGE_SIZE); - test_vmcs_addr(name, encoding, align, ignored, - skip_beyond_mapped_ram, - (1ul << cpuid_maxphyaddr()) - PAGE_SIZE); - test_vmcs_addr(name, encoding, align, ignored, - skip_beyond_mapped_ram, -1ul); - - vmcs_write(encoding, orig_val); -} - -/* - * Test a physical address reference in the VMCS, when the corresponding - * feature is enabled and when the corresponding feature is disabled. - */ -static void test_vmcs_addr_reference(u32 control_bit, enum Encoding field, - const char *field_name, - const char *control_name, u64 align, - bool skip_beyond_mapped_ram, - bool control_primary) -{ - u32 primary = vmcs_read(CPU_EXEC_CTRL0); - u32 secondary = vmcs_read(CPU_EXEC_CTRL1); - u64 page_addr; - - if (control_primary) { - if (!(ctrl_cpu_rev[0].clr & control_bit)) - return; - } else { - if (!(ctrl_cpu_rev[1].clr & control_bit)) - return; - } - - page_addr = vmcs_read(field); - - report_prefix_pushf("%s enabled", control_name); - if (control_primary) { - vmcs_write(CPU_EXEC_CTRL0, primary | control_bit); - } else { - vmcs_write(CPU_EXEC_CTRL0, primary | CPU_SECONDARY); - vmcs_write(CPU_EXEC_CTRL1, secondary | control_bit); - } - - test_vmcs_addr_values(field_name, field, align, false, - skip_beyond_mapped_ram, 0, 63); - report_prefix_pop(); - - report_prefix_pushf("%s disabled", control_name); - if (control_primary) { - vmcs_write(CPU_EXEC_CTRL0, primary & ~control_bit); - } else { - vmcs_write(CPU_EXEC_CTRL0, primary & ~CPU_SECONDARY); - vmcs_write(CPU_EXEC_CTRL1, secondary & ~control_bit); - } - - test_vmcs_addr_values(field_name, field, align, true, false, 0, 63); - report_prefix_pop(); - - vmcs_write(field, page_addr); - vmcs_write(CPU_EXEC_CTRL0, primary); - vmcs_write(CPU_EXEC_CTRL1, secondary); -} - -/* - * If the "use I/O bitmaps" VM-execution control is 1, bits 11:0 of - * each I/O-bitmap address must be 0. Neither address should set any - * bits beyond the processor's physical-address width. - * [Intel SDM] - */ -static void test_io_bitmaps(void) -{ - test_vmcs_addr_reference(CPU_IO_BITMAP, IO_BITMAP_A, - "I/O bitmap A", "Use I/O bitmaps", - PAGE_SIZE, false, true); - test_vmcs_addr_reference(CPU_IO_BITMAP, IO_BITMAP_B, - "I/O bitmap B", "Use I/O bitmaps", - PAGE_SIZE, false, true); -} - -/* - * If the "use MSR bitmaps" VM-execution control is 1, bits 11:0 of - * the MSR-bitmap address must be 0. The address should not set any - * bits beyond the processor's physical-address width. - * [Intel SDM] - */ -static void test_msr_bitmap(void) -{ - test_vmcs_addr_reference(CPU_MSR_BITMAP, MSR_BITMAP, - "MSR bitmap", "Use MSR bitmaps", - PAGE_SIZE, false, true); -} - -/* - * If the "use TPR shadow" VM-execution control is 1, the virtual-APIC - * address must satisfy the following checks: - * - Bits 11:0 of the address must be 0. - * - The address should not set any bits beyond the processor's - * physical-address width. - * [Intel SDM] - */ -static void test_apic_virt_addr(void) -{ - /* - * Ensure the processor will never use the virtual-APIC page, since - * we will point it to invalid RAM. Otherwise KVM is puzzled about - * what we're trying to achieve and fails vmentry. - */ - u32 cpu_ctrls0 = vmcs_read(CPU_EXEC_CTRL0); - vmcs_write(CPU_EXEC_CTRL0, cpu_ctrls0 | CPU_CR8_LOAD | CPU_CR8_STORE); - test_vmcs_addr_reference(CPU_TPR_SHADOW, APIC_VIRT_ADDR, - "virtual-APIC address", "Use TPR shadow", - PAGE_SIZE, false, true); - vmcs_write(CPU_EXEC_CTRL0, cpu_ctrls0); -} - -/* - * If the "virtualize APIC-accesses" VM-execution control is 1, the - * APIC-access address must satisfy the following checks: - * - Bits 11:0 of the address must be 0. - * - The address should not set any bits beyond the processor's - * physical-address width. - * [Intel SDM] - */ -static void test_apic_access_addr(void) -{ - void *apic_access_page = alloc_page(); - - vmcs_write(APIC_ACCS_ADDR, virt_to_phys(apic_access_page)); - - test_vmcs_addr_reference(CPU_VIRT_APIC_ACCESSES, APIC_ACCS_ADDR, - "APIC-access address", - "virtualize APIC-accesses", PAGE_SIZE, - true, false); -} - -static bool set_bit_pattern(u8 mask, u32 *secondary) -{ - u8 i; - bool flag = false; - u32 test_bits[3] = { - CPU_VIRT_X2APIC, - CPU_APIC_REG_VIRT, - CPU_VINTD - }; - - for (i = 0; i < ARRAY_SIZE(test_bits); i++) { - if ((mask & (1u << i)) && - (ctrl_cpu_rev[1].clr & test_bits[i])) { - *secondary |= test_bits[i]; - flag = true; - } - } - - return (flag); -} - -/* - * If the "use TPR shadow" VM-execution control is 0, the following - * VM-execution controls must also be 0: - * - virtualize x2APIC mode - * - APIC-register virtualization - * - virtual-interrupt delivery - * [Intel SDM] - * - * 2. If the "virtualize x2APIC mode" VM-execution control is 1, the - * "virtualize APIC accesses" VM-execution control must be 0. - * [Intel SDM] - */ -static void test_apic_virtual_ctls(void) -{ - u32 saved_primary = vmcs_read(CPU_EXEC_CTRL0); - u32 saved_secondary = vmcs_read(CPU_EXEC_CTRL1); - u32 primary = saved_primary; - u32 secondary = saved_secondary; - bool ctrl = false; - char str[10] = "disabled"; - u8 i = 0, j; - - /* - * First test - */ - if (!((ctrl_cpu_rev[0].clr & (CPU_SECONDARY | CPU_TPR_SHADOW)) == - (CPU_SECONDARY | CPU_TPR_SHADOW))) - return; - - primary |= CPU_SECONDARY; - primary &= ~CPU_TPR_SHADOW; - vmcs_write(CPU_EXEC_CTRL0, primary); - - while (1) { - for (j = 1; j < 8; j++) { - secondary &= ~(CPU_VIRT_X2APIC | CPU_APIC_REG_VIRT | CPU_VINTD); - if (primary & CPU_TPR_SHADOW) { - ctrl = true; - } else { - if (! set_bit_pattern(j, &secondary)) - ctrl = true; - else - ctrl = false; - } - - vmcs_write(CPU_EXEC_CTRL1, secondary); - report_prefix_pushf("Use TPR shadow %s, virtualize x2APIC mode %s, APIC-register virtualization %s, virtual-interrupt delivery %s", - str, (secondary & CPU_VIRT_X2APIC) ? "enabled" : "disabled", (secondary & CPU_APIC_REG_VIRT) ? "enabled" : "disabled", (secondary & CPU_VINTD) ? "enabled" : "disabled"); - if (ctrl) - test_vmx_valid_controls(); - else - test_vmx_invalid_controls(); - report_prefix_pop(); - } - - if (i == 1) - break; - i++; - - primary |= CPU_TPR_SHADOW; - vmcs_write(CPU_EXEC_CTRL0, primary); - strcpy(str, "enabled"); - } - - /* - * Second test - */ - u32 apic_virt_ctls = (CPU_VIRT_X2APIC | CPU_VIRT_APIC_ACCESSES); - - primary = saved_primary; - secondary = saved_secondary; - if (!((ctrl_cpu_rev[1].clr & apic_virt_ctls) == apic_virt_ctls)) - return; - - vmcs_write(CPU_EXEC_CTRL0, primary | CPU_SECONDARY); - secondary &= ~CPU_VIRT_APIC_ACCESSES; - vmcs_write(CPU_EXEC_CTRL1, secondary & ~CPU_VIRT_X2APIC); - report_prefix_pushf("Virtualize x2APIC mode disabled; virtualize APIC access disabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VIRT_APIC_ACCESSES); - report_prefix_pushf("Virtualize x2APIC mode disabled; virtualize APIC access enabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VIRT_X2APIC); - report_prefix_pushf("Virtualize x2APIC mode enabled; virtualize APIC access enabled"); - test_vmx_invalid_controls(); - report_prefix_pop(); - - vmcs_write(CPU_EXEC_CTRL1, secondary & ~CPU_VIRT_APIC_ACCESSES); - report_prefix_pushf("Virtualize x2APIC mode enabled; virtualize APIC access disabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - vmcs_write(CPU_EXEC_CTRL0, saved_primary); - vmcs_write(CPU_EXEC_CTRL1, saved_secondary); -} - -/* - * If the "virtual-interrupt delivery" VM-execution control is 1, the - * "external-interrupt exiting" VM-execution control must be 1. - * [Intel SDM] - */ -static void test_virtual_intr_ctls(void) -{ - u32 saved_primary = vmcs_read(CPU_EXEC_CTRL0); - u32 saved_secondary = vmcs_read(CPU_EXEC_CTRL1); - u32 saved_pin = vmcs_read(PIN_CONTROLS); - u32 primary = saved_primary; - u32 secondary = saved_secondary; - u32 pin = saved_pin; - - if (!((ctrl_cpu_rev[1].clr & CPU_VINTD) && - (ctrl_pin_rev.clr & PIN_EXTINT))) - return; - - vmcs_write(CPU_EXEC_CTRL0, primary | CPU_SECONDARY | CPU_TPR_SHADOW); - vmcs_write(CPU_EXEC_CTRL1, secondary & ~CPU_VINTD); - vmcs_write(PIN_CONTROLS, pin & ~PIN_EXTINT); - report_prefix_pushf("Virtualize interrupt-delivery disabled; external-interrupt exiting disabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - vmcs_write(CPU_EXEC_CTRL1, secondary | CPU_VINTD); - report_prefix_pushf("Virtualize interrupt-delivery enabled; external-interrupt exiting disabled"); - test_vmx_invalid_controls(); - report_prefix_pop(); - - vmcs_write(PIN_CONTROLS, pin | PIN_EXTINT); - report_prefix_pushf("Virtualize interrupt-delivery enabled; external-interrupt exiting enabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - vmcs_write(PIN_CONTROLS, pin & ~PIN_EXTINT); - report_prefix_pushf("Virtualize interrupt-delivery enabled; external-interrupt exiting disabled"); - test_vmx_invalid_controls(); - report_prefix_pop(); - - vmcs_write(CPU_EXEC_CTRL0, saved_primary); - vmcs_write(CPU_EXEC_CTRL1, saved_secondary); - vmcs_write(PIN_CONTROLS, saved_pin); -} - -static void test_pi_desc_addr(u64 addr, bool ctrl) -{ - vmcs_write(POSTED_INTR_DESC_ADDR, addr); - report_prefix_pushf("Process-posted-interrupts enabled; posted-interrupt-descriptor-address 0x%lx", addr); - if (ctrl) - test_vmx_valid_controls(); - else - test_vmx_invalid_controls(); - report_prefix_pop(); -} - -/* - * If the “process posted interrupts†VM-execution control is 1, the - * following must be true: - * - * - The “virtual-interrupt delivery†VM-execution control is 1. - * - The “acknowledge interrupt on exit†VM-exit control is 1. - * - The posted-interrupt notification vector has a value in the - * - range 0–255 (bits 15:8 are all 0). - * - Bits 5:0 of the posted-interrupt descriptor address are all 0. - * - The posted-interrupt descriptor address does not set any bits - * beyond the processor's physical-address width. - * [Intel SDM] - */ -static void test_posted_intr(void) -{ - u32 saved_primary = vmcs_read(CPU_EXEC_CTRL0); - u32 saved_secondary = vmcs_read(CPU_EXEC_CTRL1); - u32 saved_pin = vmcs_read(PIN_CONTROLS); - u32 exit_ctl_saved = vmcs_read(EXI_CONTROLS); - u32 primary = saved_primary; - u32 secondary = saved_secondary; - u32 pin = saved_pin; - u32 exit_ctl = exit_ctl_saved; - u16 vec; - int i; - - if (!((ctrl_pin_rev.clr & PIN_POST_INTR) && - (ctrl_cpu_rev[1].clr & CPU_VINTD) && - (ctrl_exit_rev.clr & EXI_INTA))) - return; - - vmcs_write(CPU_EXEC_CTRL0, primary | CPU_SECONDARY | CPU_TPR_SHADOW); - - /* - * Test virtual-interrupt-delivery and acknowledge-interrupt-on-exit - */ - pin |= PIN_POST_INTR; - vmcs_write(PIN_CONTROLS, pin); - secondary &= ~CPU_VINTD; - vmcs_write(CPU_EXEC_CTRL1, secondary); - report_prefix_pushf("Process-posted-interrupts enabled; virtual-interrupt-delivery disabled"); - test_vmx_invalid_controls(); - report_prefix_pop(); - - secondary |= CPU_VINTD; - vmcs_write(CPU_EXEC_CTRL1, secondary); - report_prefix_pushf("Process-posted-interrupts enabled; virtual-interrupt-delivery enabled"); - test_vmx_invalid_controls(); - report_prefix_pop(); - - exit_ctl &= ~EXI_INTA; - vmcs_write(EXI_CONTROLS, exit_ctl); - report_prefix_pushf("Process-posted-interrupts enabled; virtual-interrupt-delivery enabled; acknowledge-interrupt-on-exit disabled"); - test_vmx_invalid_controls(); - report_prefix_pop(); - - exit_ctl |= EXI_INTA; - vmcs_write(EXI_CONTROLS, exit_ctl); - report_prefix_pushf("Process-posted-interrupts enabled; virtual-interrupt-delivery enabled; acknowledge-interrupt-on-exit enabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - secondary &= ~CPU_VINTD; - vmcs_write(CPU_EXEC_CTRL1, secondary); - report_prefix_pushf("Process-posted-interrupts enabled; virtual-interrupt-delivery disabled; acknowledge-interrupt-on-exit enabled"); - test_vmx_invalid_controls(); - report_prefix_pop(); - - secondary |= CPU_VINTD; - vmcs_write(CPU_EXEC_CTRL1, secondary); - report_prefix_pushf("Process-posted-interrupts enabled; virtual-interrupt-delivery enabled; acknowledge-interrupt-on-exit enabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - /* - * Test posted-interrupt notification vector - */ - for (i = 0; i < 8; i++) { - vec = (1ul << i); - vmcs_write(PINV, vec); - report_prefix_pushf("Process-posted-interrupts enabled; posted-interrupt-notification-vector %u", vec); - test_vmx_valid_controls(); - report_prefix_pop(); - } - for (i = 8; i < 16; i++) { - vec = (1ul << i); - vmcs_write(PINV, vec); - report_prefix_pushf("Process-posted-interrupts enabled; posted-interrupt-notification-vector %u", vec); - test_vmx_invalid_controls(); - report_prefix_pop(); - } - - vec &= ~(0xff << 8); - vmcs_write(PINV, vec); - report_prefix_pushf("Process-posted-interrupts enabled; posted-interrupt-notification-vector %u", vec); - test_vmx_valid_controls(); - report_prefix_pop(); - - /* - * Test posted-interrupt descriptor addresss - */ - for (i = 0; i < 6; i++) { - test_pi_desc_addr(1ul << i, false); - } - - test_pi_desc_addr(0xf0, false); - test_pi_desc_addr(0xff, false); - test_pi_desc_addr(0x0f, false); - test_pi_desc_addr(0x8000, true); - test_pi_desc_addr(0x00, true); - test_pi_desc_addr(0xc000, true); - - test_vmcs_addr_values("process-posted interrupts", - POSTED_INTR_DESC_ADDR, 64, - false, false, 0, 63); - - vmcs_write(CPU_EXEC_CTRL0, saved_primary); - vmcs_write(CPU_EXEC_CTRL1, saved_secondary); - vmcs_write(PIN_CONTROLS, saved_pin); -} - -static void test_apic_ctls(void) -{ - test_apic_virt_addr(); - test_apic_access_addr(); - test_apic_virtual_ctls(); - test_virtual_intr_ctls(); - test_posted_intr(); -} - -/* - * If the “enable VPID†VM-execution control is 1, the value of the - * of the VPID VM-execution control field must not be 0000H. - * [Intel SDM] - */ -static void test_vpid(void) -{ - u32 saved_primary = vmcs_read(CPU_EXEC_CTRL0); - u32 saved_secondary = vmcs_read(CPU_EXEC_CTRL1); - u16 vpid = 0x0000; - int i; - - if (!((ctrl_cpu_rev[0].clr & CPU_SECONDARY) && - (ctrl_cpu_rev[1].clr & CPU_VPID))) { - printf("Secondary controls and/or VPID not supported\n"); - return; - } - - vmcs_write(CPU_EXEC_CTRL0, saved_primary | CPU_SECONDARY); - vmcs_write(CPU_EXEC_CTRL1, saved_secondary & ~CPU_VPID); - vmcs_write(VPID, vpid); - report_prefix_pushf("VPID disabled; VPID value %x", vpid); - test_vmx_valid_controls(); - report_prefix_pop(); - - vmcs_write(CPU_EXEC_CTRL1, saved_secondary | CPU_VPID); - report_prefix_pushf("VPID enabled; VPID value %x", vpid); - test_vmx_invalid_controls(); - report_prefix_pop(); - - for (i = 0; i < 16; i++) { - vpid = (short)1 << i;; - vmcs_write(VPID, vpid); - report_prefix_pushf("VPID enabled; VPID value %x", vpid); - test_vmx_valid_controls(); - report_prefix_pop(); - } - - vmcs_write(CPU_EXEC_CTRL0, saved_primary); - vmcs_write(CPU_EXEC_CTRL1, saved_secondary); -} - -static void set_vtpr(unsigned vtpr) -{ - *(u32 *)phys_to_virt(vmcs_read(APIC_VIRT_ADDR) + APIC_TASKPRI) = vtpr; -} - -static void try_tpr_threshold_and_vtpr(unsigned threshold, unsigned vtpr) -{ - bool valid = true; - u32 primary = vmcs_read(CPU_EXEC_CTRL0); - u32 secondary = vmcs_read(CPU_EXEC_CTRL1); - - if ((primary & CPU_TPR_SHADOW) && - (!(primary & CPU_SECONDARY) || - !(secondary & (CPU_VINTD | CPU_VIRT_APIC_ACCESSES)))) - valid = (threshold & 0xf) <= ((vtpr >> 4) & 0xf); - - set_vtpr(vtpr); - report_prefix_pushf("TPR threshold 0x%x, VTPR.class 0x%x", - threshold, (vtpr >> 4) & 0xf); - if (valid) - test_vmx_valid_controls(); - else - test_vmx_invalid_controls(); - report_prefix_pop(); -} - -static void test_invalid_event_injection(void) -{ - u32 ent_intr_info_save = vmcs_read(ENT_INTR_INFO); - u32 ent_intr_error_save = vmcs_read(ENT_INTR_ERROR); - u32 ent_inst_len_save = vmcs_read(ENT_INST_LEN); - u32 primary_save = vmcs_read(CPU_EXEC_CTRL0); - u32 secondary_save = vmcs_read(CPU_EXEC_CTRL1); - u64 guest_cr0_save = vmcs_read(GUEST_CR0); - u32 ent_intr_info_base = INTR_INFO_VALID_MASK; - u32 ent_intr_info, ent_intr_err, ent_intr_len; - u32 cnt; - - /* Setup */ - report_prefix_push("invalid event injection"); - vmcs_write(ENT_INTR_ERROR, 0x00000000); - vmcs_write(ENT_INST_LEN, 0x00000001); - - /* The field’s interruption type is not set to a reserved value. */ - ent_intr_info = ent_intr_info_base | INTR_TYPE_RESERVED | DE_VECTOR; - report_prefix_pushf("%s, VM-entry intr info=0x%x", - "RESERVED interruption type invalid [-]", - ent_intr_info); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_invalid_controls(); - report_prefix_pop(); - - ent_intr_info = ent_intr_info_base | INTR_TYPE_EXT_INTR | - DE_VECTOR; - report_prefix_pushf("%s, VM-entry intr info=0x%x", - "RESERVED interruption type invalid [+]", - ent_intr_info); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_valid_controls(); - report_prefix_pop(); - - /* If the interruption type is other event, the vector is 0. */ - ent_intr_info = ent_intr_info_base | INTR_TYPE_OTHER_EVENT | DB_VECTOR; - report_prefix_pushf("%s, VM-entry intr info=0x%x", - "(OTHER EVENT && vector != 0) invalid [-]", - ent_intr_info); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_invalid_controls(); - report_prefix_pop(); - - /* If the interruption type is NMI, the vector is 2 (negative case). */ - ent_intr_info = ent_intr_info_base | INTR_TYPE_NMI_INTR | DE_VECTOR; - report_prefix_pushf("%s, VM-entry intr info=0x%x", - "(NMI && vector != 2) invalid [-]", ent_intr_info); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_invalid_controls(); - report_prefix_pop(); - - /* If the interruption type is NMI, the vector is 2 (positive case). */ - ent_intr_info = ent_intr_info_base | INTR_TYPE_NMI_INTR | NMI_VECTOR; - report_prefix_pushf("%s, VM-entry intr info=0x%x", - "(NMI && vector == 2) valid [+]", ent_intr_info); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_valid_controls(); - report_prefix_pop(); - - /* - * If the interruption type - * is HW exception, the vector is at most 31. - */ - ent_intr_info = ent_intr_info_base | INTR_TYPE_HARD_EXCEPTION | 0x20; - report_prefix_pushf("%s, VM-entry intr info=0x%x", - "(HW exception && vector > 31) invalid [-]", - ent_intr_info); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_invalid_controls(); - report_prefix_pop(); - - /* - * deliver-error-code is 1 iff either - * (a) the "unrestricted guest" VM-execution control is 0 - * (b) CR0.PE is set. - */ - - /* Assert that unrestricted guest is disabled or unsupported */ - assert(!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) || - !(secondary_save & CPU_URG)); - - ent_intr_info = ent_intr_info_base | INTR_TYPE_HARD_EXCEPTION | - GP_VECTOR; - report_prefix_pushf("%s, VM-entry intr info=0x%x", - "error code <-> (!URG || prot_mode) [-]", - ent_intr_info); - vmcs_write(GUEST_CR0, guest_cr0_save & ~X86_CR0_PE & ~X86_CR0_PG); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_invalid_controls(); - report_prefix_pop(); - - ent_intr_info = ent_intr_info_base | INTR_INFO_DELIVER_CODE_MASK | - INTR_TYPE_HARD_EXCEPTION | GP_VECTOR; - report_prefix_pushf("%s, VM-entry intr info=0x%x", - "error code <-> (!URG || prot_mode) [+]", - ent_intr_info); - vmcs_write(GUEST_CR0, guest_cr0_save & ~X86_CR0_PE & ~X86_CR0_PG); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_valid_controls(); - report_prefix_pop(); - - if (enable_unrestricted_guest()) - goto skip_unrestricted_guest; - - ent_intr_info = ent_intr_info_base | INTR_INFO_DELIVER_CODE_MASK | - INTR_TYPE_HARD_EXCEPTION | GP_VECTOR; - report_prefix_pushf("%s, VM-entry intr info=0x%x", - "error code <-> (!URG || prot_mode) [-]", - ent_intr_info); - vmcs_write(GUEST_CR0, guest_cr0_save & ~X86_CR0_PE & ~X86_CR0_PG); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_invalid_controls(); - report_prefix_pop(); - - ent_intr_info = ent_intr_info_base | INTR_TYPE_HARD_EXCEPTION | - GP_VECTOR; - report_prefix_pushf("%s, VM-entry intr info=0x%x", - "error code <-> (!URG || prot_mode) [-]", - ent_intr_info); - vmcs_write(GUEST_CR0, guest_cr0_save | X86_CR0_PE); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_invalid_controls(); - report_prefix_pop(); - - vmcs_write(CPU_EXEC_CTRL1, secondary_save); - vmcs_write(CPU_EXEC_CTRL0, primary_save); - -skip_unrestricted_guest: - vmcs_write(GUEST_CR0, guest_cr0_save); - - /* deliver-error-code is 1 iff the interruption type is HW exception */ - report_prefix_push("error code <-> HW exception"); - for (cnt = 0; cnt < 8; cnt++) { - u32 exception_type_mask = cnt << 8; - u32 deliver_error_code_mask = - exception_type_mask != INTR_TYPE_HARD_EXCEPTION ? - INTR_INFO_DELIVER_CODE_MASK : 0; - - ent_intr_info = ent_intr_info_base | deliver_error_code_mask | - exception_type_mask | GP_VECTOR; - report_prefix_pushf("VM-entry intr info=0x%x [-]", - ent_intr_info); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_invalid_controls(); - report_prefix_pop(); - } - report_prefix_pop(); - - /* - * deliver-error-code is 1 iff the the vector - * indicates an exception that would normally deliver an error code - */ - report_prefix_push("error code <-> vector delivers error code"); - for (cnt = 0; cnt < 32; cnt++) { - bool has_error_code = false; - u32 deliver_error_code_mask; - - switch (cnt) { - case DF_VECTOR: - case TS_VECTOR: - case NP_VECTOR: - case SS_VECTOR: - case GP_VECTOR: - case PF_VECTOR: - case AC_VECTOR: - has_error_code = true; - } - - /* Negative case */ - deliver_error_code_mask = has_error_code ? - 0 : - INTR_INFO_DELIVER_CODE_MASK; - ent_intr_info = ent_intr_info_base | deliver_error_code_mask | - INTR_TYPE_HARD_EXCEPTION | cnt; - report_prefix_pushf("VM-entry intr info=0x%x [-]", - ent_intr_info); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_invalid_controls(); - report_prefix_pop(); - - /* Positive case */ - deliver_error_code_mask = has_error_code ? - INTR_INFO_DELIVER_CODE_MASK : - 0; - ent_intr_info = ent_intr_info_base | deliver_error_code_mask | - INTR_TYPE_HARD_EXCEPTION | cnt; - report_prefix_pushf("VM-entry intr info=0x%x [+]", - ent_intr_info); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_valid_controls(); - report_prefix_pop(); - } - report_prefix_pop(); - - /* Reserved bits in the field (30:12) are 0. */ - report_prefix_push("reserved bits clear"); - for (cnt = 12; cnt <= 30; cnt++) { - ent_intr_info = ent_intr_info_base | - INTR_INFO_DELIVER_CODE_MASK | - INTR_TYPE_HARD_EXCEPTION | GP_VECTOR | - (1U << cnt); - report_prefix_pushf("VM-entry intr info=0x%x [-]", - ent_intr_info); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - test_vmx_invalid_controls(); - report_prefix_pop(); - } - report_prefix_pop(); - - /* - * If deliver-error-code is 1 - * bits 31:16 of the VM-entry exception error-code field are 0. - */ - ent_intr_info = ent_intr_info_base | INTR_INFO_DELIVER_CODE_MASK | - INTR_TYPE_HARD_EXCEPTION | GP_VECTOR; - report_prefix_pushf("%s, VM-entry intr info=0x%x", - "VM-entry exception error code[31:16] clear", - ent_intr_info); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - for (cnt = 16; cnt <= 31; cnt++) { - ent_intr_err = 1U << cnt; - report_prefix_pushf("VM-entry intr error=0x%x [-]", - ent_intr_err); - vmcs_write(ENT_INTR_ERROR, ent_intr_err); - test_vmx_invalid_controls(); - report_prefix_pop(); - } - vmcs_write(ENT_INTR_ERROR, 0x00000000); - report_prefix_pop(); - - /* - * If the interruption type is software interrupt, software exception, - * or privileged software exception, the VM-entry instruction-length - * field is in the range 0–15. - */ - - for (cnt = 0; cnt < 3; cnt++) { - switch (cnt) { - case 0: - ent_intr_info = ent_intr_info_base | - INTR_TYPE_SOFT_INTR; - break; - case 1: - ent_intr_info = ent_intr_info_base | - INTR_TYPE_SOFT_EXCEPTION; - break; - case 2: - ent_intr_info = ent_intr_info_base | - INTR_TYPE_PRIV_SW_EXCEPTION; - break; - } - report_prefix_pushf("%s, VM-entry intr info=0x%x", - "VM-entry instruction-length check", - ent_intr_info); - vmcs_write(ENT_INTR_INFO, ent_intr_info); - - /* Instruction length set to -1 (0xFFFFFFFF) should fail */ - ent_intr_len = -1; - report_prefix_pushf("VM-entry intr length = 0x%x [-]", - ent_intr_len); - vmcs_write(ENT_INST_LEN, ent_intr_len); - test_vmx_invalid_controls(); - report_prefix_pop(); - - /* Instruction length set to 16 should fail */ - ent_intr_len = 0x00000010; - report_prefix_pushf("VM-entry intr length = 0x%x [-]", - ent_intr_len); - vmcs_write(ENT_INST_LEN, 0x00000010); - test_vmx_invalid_controls(); - report_prefix_pop(); - - report_prefix_pop(); - } - - /* Cleanup */ - vmcs_write(ENT_INTR_INFO, ent_intr_info_save); - vmcs_write(ENT_INTR_ERROR, ent_intr_error_save); - vmcs_write(ENT_INST_LEN, ent_inst_len_save); - vmcs_write(CPU_EXEC_CTRL0, primary_save); - vmcs_write(CPU_EXEC_CTRL1, secondary_save); - vmcs_write(GUEST_CR0, guest_cr0_save); - report_prefix_pop(); -} - -/* - * Test interesting vTPR values for a given TPR threshold. - */ -static void test_vtpr_values(unsigned threshold) -{ - try_tpr_threshold_and_vtpr(threshold, (threshold - 1) << 4); - try_tpr_threshold_and_vtpr(threshold, threshold << 4); - try_tpr_threshold_and_vtpr(threshold, (threshold + 1) << 4); -} - -static void try_tpr_threshold(unsigned threshold) -{ - bool valid = true; - - u32 primary = vmcs_read(CPU_EXEC_CTRL0); - u32 secondary = vmcs_read(CPU_EXEC_CTRL1); - - if ((primary & CPU_TPR_SHADOW) && !((primary & CPU_SECONDARY) && - (secondary & CPU_VINTD))) - valid = !(threshold >> 4); - - set_vtpr(-1); - vmcs_write(TPR_THRESHOLD, threshold); - report_prefix_pushf("TPR threshold 0x%x, VTPR.class 0xf", threshold); - if (valid) - test_vmx_valid_controls(); - else - test_vmx_invalid_controls(); - report_prefix_pop(); - - if (valid) - test_vtpr_values(threshold); -} - -/* - * Test interesting TPR threshold values. - */ -static void test_tpr_threshold_values(void) -{ - unsigned i; - - for (i = 0; i < 0x10; i++) - try_tpr_threshold(i); - for (i = 4; i < 32; i++) - try_tpr_threshold(1u << i); - try_tpr_threshold(-1u); - try_tpr_threshold(0x7fffffff); -} - -/* - * This test covers the following two VM entry checks: - * - * i) If the "use TPR shadow" VM-execution control is 1 and the - * "virtual-interrupt delivery" VM-execution control is 0, bits - * 31:4 of the TPR threshold VM-execution control field must - be 0. - * [Intel SDM] - * - * ii) If the "use TPR shadow" VM-execution control is 1, the - * "virtual-interrupt delivery" VM-execution control is 0 - * and the "virtualize APIC accesses" VM-execution control - * is 0, the value of bits 3:0 of the TPR threshold VM-execution - * control field must not be greater than the value of bits - * 7:4 of VTPR. - * [Intel SDM] - */ -static void test_tpr_threshold(void) -{ - u32 primary = vmcs_read(CPU_EXEC_CTRL0); - u64 apic_virt_addr = vmcs_read(APIC_VIRT_ADDR); - u64 threshold = vmcs_read(TPR_THRESHOLD); - void *virtual_apic_page; - - if (!(ctrl_cpu_rev[0].clr & CPU_TPR_SHADOW)) - return; - - virtual_apic_page = alloc_page(); - memset(virtual_apic_page, 0xff, PAGE_SIZE); - vmcs_write(APIC_VIRT_ADDR, virt_to_phys(virtual_apic_page)); - - vmcs_write(CPU_EXEC_CTRL0, primary & ~(CPU_TPR_SHADOW | CPU_SECONDARY)); - report_prefix_pushf("Use TPR shadow disabled, secondary controls disabled"); - test_tpr_threshold_values(); - report_prefix_pop(); - vmcs_write(CPU_EXEC_CTRL0, vmcs_read(CPU_EXEC_CTRL0) | CPU_TPR_SHADOW); - report_prefix_pushf("Use TPR shadow enabled, secondary controls disabled"); - test_tpr_threshold_values(); - report_prefix_pop(); - - if (!((ctrl_cpu_rev[0].clr & CPU_SECONDARY) && - (ctrl_cpu_rev[1].clr & (CPU_VINTD | CPU_VIRT_APIC_ACCESSES)))) - goto out; - u32 secondary = vmcs_read(CPU_EXEC_CTRL1); - - if (ctrl_cpu_rev[1].clr & CPU_VINTD) { - vmcs_write(CPU_EXEC_CTRL1, CPU_VINTD); - report_prefix_pushf("Use TPR shadow enabled; secondary controls disabled; virtual-interrupt delivery enabled; virtualize APIC accesses disabled"); - test_tpr_threshold_values(); - report_prefix_pop(); - - vmcs_write(CPU_EXEC_CTRL0, - vmcs_read(CPU_EXEC_CTRL0) | CPU_SECONDARY); - report_prefix_pushf("Use TPR shadow enabled; secondary controls enabled; virtual-interrupt delivery enabled; virtualize APIC accesses disabled"); - test_tpr_threshold_values(); - report_prefix_pop(); - } - - if (ctrl_cpu_rev[1].clr & CPU_VIRT_APIC_ACCESSES) { - vmcs_write(CPU_EXEC_CTRL0, - vmcs_read(CPU_EXEC_CTRL0) & ~CPU_SECONDARY); - vmcs_write(CPU_EXEC_CTRL1, CPU_VIRT_APIC_ACCESSES); - report_prefix_pushf("Use TPR shadow enabled; secondary controls disabled; virtual-interrupt delivery enabled; virtualize APIC accesses enabled"); - test_tpr_threshold_values(); - report_prefix_pop(); - - vmcs_write(CPU_EXEC_CTRL0, - vmcs_read(CPU_EXEC_CTRL0) | CPU_SECONDARY); - report_prefix_pushf("Use TPR shadow enabled; secondary controls enabled; virtual-interrupt delivery enabled; virtualize APIC accesses enabled"); - test_tpr_threshold_values(); - report_prefix_pop(); - } - - if ((ctrl_cpu_rev[1].clr & - (CPU_VINTD | CPU_VIRT_APIC_ACCESSES)) == - (CPU_VINTD | CPU_VIRT_APIC_ACCESSES)) { - vmcs_write(CPU_EXEC_CTRL0, - vmcs_read(CPU_EXEC_CTRL0) & ~CPU_SECONDARY); - vmcs_write(CPU_EXEC_CTRL1, - CPU_VINTD | CPU_VIRT_APIC_ACCESSES); - report_prefix_pushf("Use TPR shadow enabled; secondary controls disabled; virtual-interrupt delivery enabled; virtualize APIC accesses enabled"); - test_tpr_threshold_values(); - report_prefix_pop(); - - vmcs_write(CPU_EXEC_CTRL0, - vmcs_read(CPU_EXEC_CTRL0) | CPU_SECONDARY); - report_prefix_pushf("Use TPR shadow enabled; secondary controls enabled; virtual-interrupt delivery enabled; virtualize APIC accesses enabled"); - test_tpr_threshold_values(); - report_prefix_pop(); - } - - vmcs_write(CPU_EXEC_CTRL1, secondary); -out: - vmcs_write(TPR_THRESHOLD, threshold); - vmcs_write(APIC_VIRT_ADDR, apic_virt_addr); - vmcs_write(CPU_EXEC_CTRL0, primary); -} - -/* - * This test verifies the following two vmentry checks: - * - * If the "NMI exiting" VM-execution control is 0, "Virtual NMIs" - * VM-execution control must be 0. - * [Intel SDM] - * - * If the “virtual NMIs” VM-execution control is 0, the “NMI-window - * exiting” VM-execution control must be 0. - * [Intel SDM] - */ -static void test_nmi_ctrls(void) -{ - u32 pin_ctrls, cpu_ctrls0, test_pin_ctrls, test_cpu_ctrls0; - - if ((ctrl_pin_rev.clr & (PIN_NMI | PIN_VIRT_NMI)) != - (PIN_NMI | PIN_VIRT_NMI)) { - printf("NMI exiting and Virtual NMIs are not supported !\n"); - return; - } - - /* Save the controls so that we can restore them after our tests */ - pin_ctrls = vmcs_read(PIN_CONTROLS); - cpu_ctrls0 = vmcs_read(CPU_EXEC_CTRL0); - - test_pin_ctrls = pin_ctrls & ~(PIN_NMI | PIN_VIRT_NMI); - test_cpu_ctrls0 = cpu_ctrls0 & ~CPU_NMI_WINDOW; - - vmcs_write(PIN_CONTROLS, test_pin_ctrls); - report_prefix_pushf("NMI-exiting disabled, virtual-NMIs disabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - vmcs_write(PIN_CONTROLS, test_pin_ctrls | PIN_VIRT_NMI); - report_prefix_pushf("NMI-exiting disabled, virtual-NMIs enabled"); - test_vmx_invalid_controls(); - report_prefix_pop(); - - vmcs_write(PIN_CONTROLS, test_pin_ctrls | (PIN_NMI | PIN_VIRT_NMI)); - report_prefix_pushf("NMI-exiting enabled, virtual-NMIs enabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - vmcs_write(PIN_CONTROLS, test_pin_ctrls | PIN_NMI); - report_prefix_pushf("NMI-exiting enabled, virtual-NMIs disabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - if (!(ctrl_cpu_rev[0].clr & CPU_NMI_WINDOW)) { - report_info("NMI-window exiting is not supported, skipping..."); - goto done; - } - - vmcs_write(PIN_CONTROLS, test_pin_ctrls); - vmcs_write(CPU_EXEC_CTRL0, test_cpu_ctrls0 | CPU_NMI_WINDOW); - report_prefix_pushf("Virtual-NMIs disabled, NMI-window-exiting enabled"); - test_vmx_invalid_controls(); - report_prefix_pop(); - - vmcs_write(PIN_CONTROLS, test_pin_ctrls); - vmcs_write(CPU_EXEC_CTRL0, test_cpu_ctrls0); - report_prefix_pushf("Virtual-NMIs disabled, NMI-window-exiting disabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - vmcs_write(PIN_CONTROLS, test_pin_ctrls | (PIN_NMI | PIN_VIRT_NMI)); - vmcs_write(CPU_EXEC_CTRL0, test_cpu_ctrls0 | CPU_NMI_WINDOW); - report_prefix_pushf("Virtual-NMIs enabled, NMI-window-exiting enabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - vmcs_write(PIN_CONTROLS, test_pin_ctrls | (PIN_NMI | PIN_VIRT_NMI)); - vmcs_write(CPU_EXEC_CTRL0, test_cpu_ctrls0); - report_prefix_pushf("Virtual-NMIs enabled, NMI-window-exiting disabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - /* Restore the controls to their original values */ - vmcs_write(CPU_EXEC_CTRL0, cpu_ctrls0); -done: - vmcs_write(PIN_CONTROLS, pin_ctrls); -} - -static void test_eptp_ad_bit(u64 eptp, bool ctrl) -{ - vmcs_write(EPTP, eptp); - report_prefix_pushf("Enable-EPT enabled; EPT accessed and dirty flag %s", - (eptp & EPTP_AD_FLAG) ? "1": "0"); - if (ctrl) - test_vmx_valid_controls(); - else - test_vmx_invalid_controls(); - report_prefix_pop(); - -} - -/* - * 1. If the "enable EPT" VM-execution control is 1, the "EPTP VM-execution" - * control field must satisfy the following checks: - * - * - The EPT memory type (bits 2:0) must be a value supported by the - * processor as indicated in the IA32_VMX_EPT_VPID_CAP MSR. - * - Bits 5:3 (1 less than the EPT page-walk length) must indicate a - * supported EPT page-walk length. - * - Bit 6 (enable bit for accessed and dirty flags for EPT) must be - * 0 if bit 21 of the IA32_VMX_EPT_VPID_CAP MSR is read as 0, - * indicating that the processor does not support accessed and dirty - * dirty flags for EPT. - * - Reserved bits 11:7 and 63:N (where N is the processor's - * physical-address width) must all be 0. - * - * 2. If the "unrestricted guest" VM-execution control is 1, the - * "enable EPT" VM-execution control must also be 1. - */ -static void test_ept_eptp(void) -{ - u32 primary_saved = vmcs_read(CPU_EXEC_CTRL0); - u32 secondary_saved = vmcs_read(CPU_EXEC_CTRL1); - u64 eptp_saved = vmcs_read(EPTP); - u32 primary = primary_saved; - u32 secondary = secondary_saved; - u64 msr, eptp = eptp_saved; - bool un_cache = false; - bool wr_bk = false; - bool ctrl; - u32 i, maxphysaddr; - u64 j, resv_bits_mask = 0; - - if (!((ctrl_cpu_rev[0].clr & CPU_SECONDARY) && - (ctrl_cpu_rev[1].clr & CPU_EPT))) { - printf("\"CPU secondary\" and/or \"enable EPT\" execution controls are not supported !\n"); - return; - } - - /* - * Memory type (bits 2:0) - */ - msr = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP); - if (msr & EPT_CAP_UC) - un_cache = true; - if (msr & EPT_CAP_WB) - wr_bk = true; - - /* Support for 4-level EPT is mandatory. */ - report(msr & EPT_CAP_PWL4, "4-level EPT support check"); - - primary |= CPU_SECONDARY; - vmcs_write(CPU_EXEC_CTRL0, primary); - secondary |= CPU_EPT; - vmcs_write(CPU_EXEC_CTRL1, secondary); - eptp = (eptp & ~EPTP_PG_WALK_LEN_MASK) | - (3ul << EPTP_PG_WALK_LEN_SHIFT); - vmcs_write(EPTP, eptp); - - for (i = 0; i < 8; i++) { - if (i == 0) { - if (un_cache) { - report_info("EPT paging structure memory-type is Un-cacheable\n"); - ctrl = true; - } else { - ctrl = false; - } - } else if (i == 6) { - if (wr_bk) { - report_info("EPT paging structure memory-type is Write-back\n"); - ctrl = true; - } else { - ctrl = false; - } - } else { - ctrl = false; - } - - eptp = (eptp & ~EPT_MEM_TYPE_MASK) | i; - vmcs_write(EPTP, eptp); - report_prefix_pushf("Enable-EPT enabled; EPT memory type %lu", - eptp & EPT_MEM_TYPE_MASK); - if (ctrl) - test_vmx_valid_controls(); - else - test_vmx_invalid_controls(); - report_prefix_pop(); - } - - eptp = (eptp & ~EPT_MEM_TYPE_MASK) | 6ul; - - /* - * Page walk length (bits 5:3). Note, the value in VMCS.EPTP "is 1 - * less than the EPT page-walk length". - */ - for (i = 0; i < 8; i++) { - eptp = (eptp & ~EPTP_PG_WALK_LEN_MASK) | - (i << EPTP_PG_WALK_LEN_SHIFT); - if (i == 3 || (i == 4 && (msr & EPT_CAP_PWL5))) - ctrl = true; - else - ctrl = false; - - vmcs_write(EPTP, eptp); - report_prefix_pushf("Enable-EPT enabled; EPT page walk length %lu", - eptp & EPTP_PG_WALK_LEN_MASK); - if (ctrl) - test_vmx_valid_controls(); - else - test_vmx_invalid_controls(); - report_prefix_pop(); - } - - eptp = (eptp & ~EPTP_PG_WALK_LEN_MASK) | - 3ul << EPTP_PG_WALK_LEN_SHIFT; - - /* - * Accessed and dirty flag (bit 6) - */ - if (msr & EPT_CAP_AD_FLAG) { - report_info("Processor supports accessed and dirty flag"); - eptp &= ~EPTP_AD_FLAG; - test_eptp_ad_bit(eptp, true); - - eptp |= EPTP_AD_FLAG; - test_eptp_ad_bit(eptp, true); - } else { - report_info("Processor does not supports accessed and dirty flag"); - eptp &= ~EPTP_AD_FLAG; - test_eptp_ad_bit(eptp, true); - - eptp |= EPTP_AD_FLAG; - test_eptp_ad_bit(eptp, false); - } - - /* - * Reserved bits [11:7] and [63:N] - */ - for (i = 0; i < 32; i++) { - eptp = (eptp & - ~(EPTP_RESERV_BITS_MASK << EPTP_RESERV_BITS_SHIFT)) | - (i << EPTP_RESERV_BITS_SHIFT); - vmcs_write(EPTP, eptp); - report_prefix_pushf("Enable-EPT enabled; reserved bits [11:7] %lu", - (eptp >> EPTP_RESERV_BITS_SHIFT) & - EPTP_RESERV_BITS_MASK); - if (i == 0) - test_vmx_valid_controls(); - else - test_vmx_invalid_controls(); - report_prefix_pop(); - } - - eptp = (eptp & ~(EPTP_RESERV_BITS_MASK << EPTP_RESERV_BITS_SHIFT)); - - maxphysaddr = cpuid_maxphyaddr(); - for (i = 0; i < (63 - maxphysaddr + 1); i++) { - resv_bits_mask |= 1ul << i; - } - - for (j = maxphysaddr - 1; j <= 63; j++) { - eptp = (eptp & ~(resv_bits_mask << maxphysaddr)) | - (j < maxphysaddr ? 0 : 1ul << j); - vmcs_write(EPTP, eptp); - report_prefix_pushf("Enable-EPT enabled; reserved bits [63:N] %lu", - (eptp >> maxphysaddr) & resv_bits_mask); - if (j < maxphysaddr) - test_vmx_valid_controls(); - else - test_vmx_invalid_controls(); - report_prefix_pop(); - } - - secondary &= ~(CPU_EPT | CPU_URG); - vmcs_write(CPU_EXEC_CTRL1, secondary); - report_prefix_pushf("Enable-EPT disabled, unrestricted-guest disabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - if (!(ctrl_cpu_rev[1].clr & CPU_URG)) - goto skip_unrestricted_guest; - - secondary |= CPU_URG; - vmcs_write(CPU_EXEC_CTRL1, secondary); - report_prefix_pushf("Enable-EPT disabled, unrestricted-guest enabled"); - test_vmx_invalid_controls(); - report_prefix_pop(); - - secondary |= CPU_EPT; - setup_dummy_ept(); - report_prefix_pushf("Enable-EPT enabled, unrestricted-guest enabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - -skip_unrestricted_guest: - secondary &= ~CPU_URG; - vmcs_write(CPU_EXEC_CTRL1, secondary); - report_prefix_pushf("Enable-EPT enabled, unrestricted-guest disabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - vmcs_write(CPU_EXEC_CTRL0, primary_saved); - vmcs_write(CPU_EXEC_CTRL1, secondary_saved); - vmcs_write(EPTP, eptp_saved); -} - -/* - * If the 'enable PML' VM-execution control is 1, the 'enable EPT' - * VM-execution control must also be 1. In addition, the PML address - * must satisfy the following checks: - * - * * Bits 11:0 of the address must be 0. - * * The address should not set any bits beyond the processor's - * physical-address width. - * - * [Intel SDM] - */ -static void test_pml(void) -{ - u32 primary_saved = vmcs_read(CPU_EXEC_CTRL0); - u32 secondary_saved = vmcs_read(CPU_EXEC_CTRL1); - u32 primary = primary_saved; - u32 secondary = secondary_saved; - - if (!((ctrl_cpu_rev[0].clr & CPU_SECONDARY) && - (ctrl_cpu_rev[1].clr & CPU_EPT) && (ctrl_cpu_rev[1].clr & CPU_PML))) { - printf("\"Secondary execution\" control or \"enable EPT\" control or \"enable PML\" control is not supported !\n"); - return; - } - - primary |= CPU_SECONDARY; - vmcs_write(CPU_EXEC_CTRL0, primary); - secondary &= ~(CPU_PML | CPU_EPT); - vmcs_write(CPU_EXEC_CTRL1, secondary); - report_prefix_pushf("enable-PML disabled, enable-EPT disabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - secondary |= CPU_PML; - vmcs_write(CPU_EXEC_CTRL1, secondary); - report_prefix_pushf("enable-PML enabled, enable-EPT disabled"); - test_vmx_invalid_controls(); - report_prefix_pop(); - - secondary |= CPU_EPT; - setup_dummy_ept(); - report_prefix_pushf("enable-PML enabled, enable-EPT enabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - secondary &= ~CPU_PML; - vmcs_write(CPU_EXEC_CTRL1, secondary); - report_prefix_pushf("enable-PML disabled, enable EPT enabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - test_vmcs_addr_reference(CPU_PML, PMLADDR, "PML address", "PML", - PAGE_SIZE, false, false); - - vmcs_write(CPU_EXEC_CTRL0, primary_saved); - vmcs_write(CPU_EXEC_CTRL1, secondary_saved); -} - - /* - * If the "activate VMX-preemption timer" VM-execution control is 0, the - * the "save VMX-preemption timer value" VM-exit control must also be 0. - * - * [Intel SDM] - */ -static void test_vmx_preemption_timer(void) -{ - u32 saved_pin = vmcs_read(PIN_CONTROLS); - u32 saved_exit = vmcs_read(EXI_CONTROLS); - u32 pin = saved_pin; - u32 exit = saved_exit; - - if (!((ctrl_exit_rev.clr & EXI_SAVE_PREEMPT) || - (ctrl_pin_rev.clr & PIN_PREEMPT))) { - printf("\"Save-VMX-preemption-timer\" control and/or \"Enable-VMX-preemption-timer\" control is not supported\n"); - return; - } - - pin |= PIN_PREEMPT; - vmcs_write(PIN_CONTROLS, pin); - exit &= ~EXI_SAVE_PREEMPT; - vmcs_write(EXI_CONTROLS, exit); - report_prefix_pushf("enable-VMX-preemption-timer enabled, save-VMX-preemption-timer disabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - exit |= EXI_SAVE_PREEMPT; - vmcs_write(EXI_CONTROLS, exit); - report_prefix_pushf("enable-VMX-preemption-timer enabled, save-VMX-preemption-timer enabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - pin &= ~PIN_PREEMPT; - vmcs_write(PIN_CONTROLS, pin); - report_prefix_pushf("enable-VMX-preemption-timer disabled, save-VMX-preemption-timer enabled"); - test_vmx_invalid_controls(); - report_prefix_pop(); - - exit &= ~EXI_SAVE_PREEMPT; - vmcs_write(EXI_CONTROLS, exit); - report_prefix_pushf("enable-VMX-preemption-timer disabled, save-VMX-preemption-timer disabled"); - test_vmx_valid_controls(); - report_prefix_pop(); - - vmcs_write(PIN_CONTROLS, saved_pin); - vmcs_write(EXI_CONTROLS, saved_exit); -} - -extern unsigned char test_mtf1; -extern unsigned char test_mtf2; -extern unsigned char test_mtf3; -extern unsigned char test_mtf4; - -static void test_mtf_guest(void) -{ - asm ("vmcall;\n\t" - "out %al, $0x80;\n\t" - "test_mtf1:\n\t" - "vmcall;\n\t" - "out %al, $0x80;\n\t" - "test_mtf2:\n\t" - /* - * Prepare for the 'MOV CR3' test. Attempt to induce a - * general-protection fault by moving a non-canonical address into - * CR3. The 'MOV CR3' instruction does not take an imm64 operand, - * so we must MOV the desired value into a register first. - * - * MOV RAX is done before the VMCALL such that MTF is only enabled - * for the instruction under test. - */ - "mov $0x8000000000000000, %rax;\n\t" - "vmcall;\n\t" - "mov %rax, %cr3;\n\t" - "test_mtf3:\n\t" - "vmcall;\n\t" - /* - * ICEBP/INT1 instruction. Though the instruction is now - * documented, don't rely on assemblers enumerating the - * instruction. Resort to hand assembly. - */ - ".byte 0xf1;\n\t" - "vmcall;\n\t" - "test_mtf4:\n\t" - "mov $0, %eax;\n\t"); -} - -static void test_mtf_gp_handler(struct ex_regs *regs) -{ - regs->rip = (unsigned long) &test_mtf3; -} - -static void test_mtf_db_handler(struct ex_regs *regs) -{ -} - -static void enable_mtf(void) -{ - u32 ctrl0 = vmcs_read(CPU_EXEC_CTRL0); - - vmcs_write(CPU_EXEC_CTRL0, ctrl0 | CPU_MTF); -} - -static void disable_mtf(void) -{ - u32 ctrl0 = vmcs_read(CPU_EXEC_CTRL0); - - vmcs_write(CPU_EXEC_CTRL0, ctrl0 & ~CPU_MTF); -} - -static void enable_tf(void) -{ - unsigned long rflags = vmcs_read(GUEST_RFLAGS); - - vmcs_write(GUEST_RFLAGS, rflags | X86_EFLAGS_TF); -} - -static void disable_tf(void) -{ - unsigned long rflags = vmcs_read(GUEST_RFLAGS); - - vmcs_write(GUEST_RFLAGS, rflags & ~X86_EFLAGS_TF); -} - -static void report_mtf(const char *insn_name, unsigned long exp_rip) -{ - unsigned long rip = vmcs_read(GUEST_RIP); - - assert_exit_reason(VMX_MTF); - report(rip == exp_rip, "MTF VM-exit after %s. RIP: 0x%lx (expected 0x%lx)", - insn_name, rip, exp_rip); -} - -static void vmx_mtf_test(void) -{ - unsigned long pending_dbg; - handler old_gp, old_db; - - if (!(ctrl_cpu_rev[0].clr & CPU_MTF)) { - printf("CPU does not support the 'monitor trap flag' processor-based VM-execution control.\n"); - return; - } - - test_set_guest(test_mtf_guest); - - /* Expect an MTF VM-exit after OUT instruction */ - enter_guest(); - skip_exit_vmcall(); - - enable_mtf(); - enter_guest(); - report_mtf("OUT", (unsigned long) &test_mtf1); - disable_mtf(); - - /* - * Concurrent #DB trap and MTF on instruction boundary. Expect MTF - * VM-exit with populated 'pending debug exceptions' VMCS field. - */ - enter_guest(); - skip_exit_vmcall(); - - enable_mtf(); - enable_tf(); - - enter_guest(); - report_mtf("OUT", (unsigned long) &test_mtf2); - pending_dbg = vmcs_read(GUEST_PENDING_DEBUG); - report(pending_dbg & DR_STEP, - "'pending debug exceptions' field after MTF VM-exit: 0x%lx (expected 0x%lx)", - pending_dbg, (unsigned long) DR_STEP); - - disable_mtf(); - disable_tf(); - vmcs_write(GUEST_PENDING_DEBUG, 0); - - /* - * #GP exception takes priority over MTF. Expect MTF VM-exit with RIP - * advanced to first instruction of #GP handler. - */ - enter_guest(); - skip_exit_vmcall(); - - old_gp = handle_exception(GP_VECTOR, test_mtf_gp_handler); - - enable_mtf(); - enter_guest(); - report_mtf("MOV CR3", (unsigned long) get_idt_addr(&boot_idt[GP_VECTOR])); - disable_mtf(); - - /* - * Concurrent MTF and privileged software exception (i.e. ICEBP/INT1). - * MTF should follow the delivery of #DB trap, though the SDM doesn't - * provide clear indication of the relative priority. - */ - enter_guest(); - skip_exit_vmcall(); - - handle_exception(GP_VECTOR, old_gp); - old_db = handle_exception(DB_VECTOR, test_mtf_db_handler); - - enable_mtf(); - enter_guest(); - report_mtf("INT1", (unsigned long) get_idt_addr(&boot_idt[DB_VECTOR])); - disable_mtf(); - - enter_guest(); - skip_exit_vmcall(); - handle_exception(DB_VECTOR, old_db); - vmcs_write(ENT_INTR_INFO, INTR_INFO_VALID_MASK | INTR_TYPE_OTHER_EVENT); - enter_guest(); - report_mtf("injected MTF", (unsigned long) &test_mtf4); - enter_guest(); -} - -/* - * Tests for VM-execution control fields - */ -static void test_vm_execution_ctls(void) -{ - test_pin_based_ctls(); - test_primary_processor_based_ctls(); - test_secondary_processor_based_ctls(); - test_cr3_targets(); - test_io_bitmaps(); - test_msr_bitmap(); - test_apic_ctls(); - test_tpr_threshold(); - test_nmi_ctrls(); - test_pml(); - test_vpid(); - test_ept_eptp(); - test_vmx_preemption_timer(); -} - - /* - * The following checks are performed for the VM-entry MSR-load address if - * the VM-entry MSR-load count field is non-zero: - * - * - The lower 4 bits of the VM-entry MSR-load address must be 0. - * The address should not set any bits beyond the processor’s - * physical-address width. - * - * - The address of the last byte in the VM-entry MSR-load area - * should not set any bits beyond the processor’s physical-address - * width. The address of this last byte is VM-entry MSR-load address - * + (MSR count * 16) - 1. (The arithmetic used for the computation - * uses more bits than the processor’s physical-address width.) - * - * - * [Intel SDM] - */ -static void test_entry_msr_load(void) -{ - entry_msr_load = alloc_page(); - u64 tmp; - u32 entry_msr_ld_cnt = 1; - int i; - u32 addr_len = 64; - - vmcs_write(ENT_MSR_LD_CNT, entry_msr_ld_cnt); - - /* Check first 4 bits of VM-entry MSR-load address */ - for (i = 0; i < 4; i++) { - tmp = (u64)entry_msr_load | 1ull << i; - vmcs_write(ENTER_MSR_LD_ADDR, tmp); - report_prefix_pushf("VM-entry MSR-load addr [4:0] %lx", - tmp & 0xf); - test_vmx_invalid_controls(); - report_prefix_pop(); - } - - if (basic.val & (1ul << 48)) - addr_len = 32; - - test_vmcs_addr_values("VM-entry-MSR-load address", - ENTER_MSR_LD_ADDR, 16, false, false, - 4, addr_len - 1); - - /* - * Check last byte of VM-entry MSR-load address - */ - entry_msr_load = (struct vmx_msr_entry *)((u64)entry_msr_load & ~0xf); - - for (i = (addr_len == 64 ? cpuid_maxphyaddr(): addr_len); - i < 64; i++) { - tmp = ((u64)entry_msr_load + entry_msr_ld_cnt * 16 - 1) | - 1ul << i; - vmcs_write(ENTER_MSR_LD_ADDR, - tmp - (entry_msr_ld_cnt * 16 - 1)); - test_vmx_invalid_controls(); - } - - vmcs_write(ENT_MSR_LD_CNT, 2); - vmcs_write(ENTER_MSR_LD_ADDR, (1ULL << cpuid_maxphyaddr()) - 16); - test_vmx_invalid_controls(); - vmcs_write(ENTER_MSR_LD_ADDR, (1ULL << cpuid_maxphyaddr()) - 32); - test_vmx_valid_controls(); - vmcs_write(ENTER_MSR_LD_ADDR, (1ULL << cpuid_maxphyaddr()) - 48); - test_vmx_valid_controls(); -} - -static struct vmx_state_area_test_data { - u32 msr; - u64 exp; - bool enabled; -} vmx_state_area_test_data; - -static void guest_state_test_main(void) -{ - u64 obs; - struct vmx_state_area_test_data *data = &vmx_state_area_test_data; - - while (1) { - if (vmx_get_test_stage() == 2) - break; - - if (data->enabled) { - obs = rdmsr(data->msr); - report(data->exp == obs, - "Guest state is 0x%lx (expected 0x%lx)", - obs, data->exp); - } - - vmcall(); - } - - asm volatile("fnop"); -} - -static void test_guest_state(const char *test, bool xfail, u64 field, - const char * field_name) -{ - struct vmentry_result result; - u8 abort_flags; - - abort_flags = ABORT_ON_EARLY_VMENTRY_FAIL; - if (!xfail) - abort_flags = ABORT_ON_INVALID_GUEST_STATE; - - __enter_guest(abort_flags, &result); - - report(result.exit_reason.failed_vmentry == xfail && - ((xfail && result.exit_reason.basic == VMX_FAIL_STATE) || - (!xfail && result.exit_reason.basic == VMX_VMCALL)) && - (!xfail || vmcs_read(EXI_QUALIFICATION) == ENTRY_FAIL_DEFAULT), - "%s, %s %lx", test, field_name, field); - - if (!result.exit_reason.failed_vmentry) - skip_exit_insn(); -} - -/* - * Tests for VM-entry control fields - */ -static void test_vm_entry_ctls(void) -{ - test_invalid_event_injection(); - test_entry_msr_load(); -} - -/* - * The following checks are performed for the VM-exit MSR-store address if - * the VM-exit MSR-store count field is non-zero: - * - * - The lower 4 bits of the VM-exit MSR-store address must be 0. - * The address should not set any bits beyond the processor’s - * physical-address width. - * - * - The address of the last byte in the VM-exit MSR-store area - * should not set any bits beyond the processor’s physical-address - * width. The address of this last byte is VM-exit MSR-store address - * + (MSR count * 16) - 1. (The arithmetic used for the computation - * uses more bits than the processor’s physical-address width.) - * - * If IA32_VMX_BASIC[48] is read as 1, neither address should set any bits - * in the range 63:32. - * - * [Intel SDM] - */ -static void test_exit_msr_store(void) -{ - exit_msr_store = alloc_page(); - u64 tmp; - u32 exit_msr_st_cnt = 1; - int i; - u32 addr_len = 64; - - vmcs_write(EXI_MSR_ST_CNT, exit_msr_st_cnt); - - /* Check first 4 bits of VM-exit MSR-store address */ - for (i = 0; i < 4; i++) { - tmp = (u64)exit_msr_store | 1ull << i; - vmcs_write(EXIT_MSR_ST_ADDR, tmp); - report_prefix_pushf("VM-exit MSR-store addr [4:0] %lx", - tmp & 0xf); - test_vmx_invalid_controls(); - report_prefix_pop(); - } - - if (basic.val & (1ul << 48)) - addr_len = 32; - - test_vmcs_addr_values("VM-exit-MSR-store address", - EXIT_MSR_ST_ADDR, 16, false, false, - 4, addr_len - 1); - - /* - * Check last byte of VM-exit MSR-store address - */ - exit_msr_store = (struct vmx_msr_entry *)((u64)exit_msr_store & ~0xf); - - for (i = (addr_len == 64 ? cpuid_maxphyaddr(): addr_len); - i < 64; i++) { - tmp = ((u64)exit_msr_store + exit_msr_st_cnt * 16 - 1) | - 1ul << i; - vmcs_write(EXIT_MSR_ST_ADDR, - tmp - (exit_msr_st_cnt * 16 - 1)); - test_vmx_invalid_controls(); - } - - vmcs_write(EXI_MSR_ST_CNT, 2); - vmcs_write(EXIT_MSR_ST_ADDR, (1ULL << cpuid_maxphyaddr()) - 16); - test_vmx_invalid_controls(); - vmcs_write(EXIT_MSR_ST_ADDR, (1ULL << cpuid_maxphyaddr()) - 32); - test_vmx_valid_controls(); - vmcs_write(EXIT_MSR_ST_ADDR, (1ULL << cpuid_maxphyaddr()) - 48); - test_vmx_valid_controls(); -} - -/* - * Tests for VM-exit controls - */ -static void test_vm_exit_ctls(void) -{ - test_exit_msr_store(); -} - -/* - * Check that the virtual CPU checks all of the VMX controls as - * documented in the Intel SDM. - */ -static void vmx_controls_test(void) -{ - /* - * Bit 1 of the guest's RFLAGS must be 1, or VM-entry will - * fail due to invalid guest state, should we make it that - * far. - */ - vmcs_write(GUEST_RFLAGS, 0); - - test_vm_execution_ctls(); - test_vm_exit_ctls(); - test_vm_entry_ctls(); -} - -struct apic_reg_virt_config { - bool apic_register_virtualization; - bool use_tpr_shadow; - bool virtualize_apic_accesses; - bool virtualize_x2apic_mode; - bool activate_secondary_controls; -}; - -struct apic_reg_test { - const char *name; - struct apic_reg_virt_config apic_reg_virt_config; -}; - -struct apic_reg_virt_expectation { - enum Reason rd_exit_reason; - enum Reason wr_exit_reason; - u32 val; - u32 (*virt_fn)(u32); - - /* - * If false, accessing the APIC access address from L2 is treated as a - * normal memory operation, rather than triggering virtualization. - */ - bool virtualize_apic_accesses; -}; - -static u32 apic_virt_identity(u32 val) -{ - return val; -} - -static u32 apic_virt_nibble1(u32 val) -{ - return val & 0xf0; -} - -static u32 apic_virt_byte3(u32 val) -{ - return val & (0xff << 24); -} - -static bool apic_reg_virt_exit_expectation( - u32 reg, struct apic_reg_virt_config *config, - struct apic_reg_virt_expectation *expectation) -{ - /* Good configs, where some L2 APIC accesses are virtualized. */ - bool virtualize_apic_accesses_only = - config->virtualize_apic_accesses && - !config->use_tpr_shadow && - !config->apic_register_virtualization && - !config->virtualize_x2apic_mode && - config->activate_secondary_controls; - bool virtualize_apic_accesses_and_use_tpr_shadow = - config->virtualize_apic_accesses && - config->use_tpr_shadow && - !config->apic_register_virtualization && - !config->virtualize_x2apic_mode && - config->activate_secondary_controls; - bool apic_register_virtualization = - config->virtualize_apic_accesses && - config->use_tpr_shadow && - config->apic_register_virtualization && - !config->virtualize_x2apic_mode && - config->activate_secondary_controls; - - expectation->val = MAGIC_VAL_1; - expectation->virt_fn = apic_virt_identity; - expectation->virtualize_apic_accesses = - config->virtualize_apic_accesses && - config->activate_secondary_controls; - if (virtualize_apic_accesses_only) { - expectation->rd_exit_reason = VMX_APIC_ACCESS; - expectation->wr_exit_reason = VMX_APIC_ACCESS; - } else if (virtualize_apic_accesses_and_use_tpr_shadow) { - switch (reg) { - case APIC_TASKPRI: - expectation->rd_exit_reason = VMX_VMCALL; - expectation->wr_exit_reason = VMX_VMCALL; - expectation->virt_fn = apic_virt_nibble1; - break; - default: - expectation->rd_exit_reason = VMX_APIC_ACCESS; - expectation->wr_exit_reason = VMX_APIC_ACCESS; - } - } else if (apic_register_virtualization) { - expectation->rd_exit_reason = VMX_VMCALL; - - switch (reg) { - case APIC_ID: - case APIC_EOI: - case APIC_LDR: - case APIC_DFR: - case APIC_SPIV: - case APIC_ESR: - case APIC_ICR: - case APIC_LVTT: - case APIC_LVTTHMR: - case APIC_LVTPC: - case APIC_LVT0: - case APIC_LVT1: - case APIC_LVTERR: - case APIC_TMICT: - case APIC_TDCR: - expectation->wr_exit_reason = VMX_APIC_WRITE; - break; - case APIC_LVR: - case APIC_ISR ... APIC_ISR + 0x70: - case APIC_TMR ... APIC_TMR + 0x70: - case APIC_IRR ... APIC_IRR + 0x70: - expectation->wr_exit_reason = VMX_APIC_ACCESS; - break; - case APIC_TASKPRI: - expectation->wr_exit_reason = VMX_VMCALL; - expectation->virt_fn = apic_virt_nibble1; - break; - case APIC_ICR2: - expectation->wr_exit_reason = VMX_VMCALL; - expectation->virt_fn = apic_virt_byte3; - break; - default: - expectation->rd_exit_reason = VMX_APIC_ACCESS; - expectation->wr_exit_reason = VMX_APIC_ACCESS; - } - } else if (!expectation->virtualize_apic_accesses) { - /* - * No APIC registers are directly virtualized. This includes - * VTPR, which can be virtualized through MOV to/from CR8 via - * the use TPR shadow control, but not through directly - * accessing VTPR. - */ - expectation->rd_exit_reason = VMX_VMCALL; - expectation->wr_exit_reason = VMX_VMCALL; - } else { - printf("Cannot parse APIC register virtualization config:\n" - "\tvirtualize_apic_accesses: %d\n" - "\tuse_tpr_shadow: %d\n" - "\tapic_register_virtualization: %d\n" - "\tvirtualize_x2apic_mode: %d\n" - "\tactivate_secondary_controls: %d\n", - config->virtualize_apic_accesses, - config->use_tpr_shadow, - config->apic_register_virtualization, - config->virtualize_x2apic_mode, - config->activate_secondary_controls); - - return false; - } - - return true; -} - -struct apic_reg_test apic_reg_tests[] = { - /* Good configs, where some L2 APIC accesses are virtualized. */ - { - .name = "Virtualize APIC accesses", - .apic_reg_virt_config = { - .virtualize_apic_accesses = true, - .use_tpr_shadow = false, - .apic_register_virtualization = false, - .virtualize_x2apic_mode = false, - .activate_secondary_controls = true, - }, - }, - { - .name = "Virtualize APIC accesses + Use TPR shadow", - .apic_reg_virt_config = { - .virtualize_apic_accesses = true, - .use_tpr_shadow = true, - .apic_register_virtualization = false, - .virtualize_x2apic_mode = false, - .activate_secondary_controls = true, - }, - }, - { - .name = "APIC-register virtualization", - .apic_reg_virt_config = { - .virtualize_apic_accesses = true, - .use_tpr_shadow = true, - .apic_register_virtualization = true, - .virtualize_x2apic_mode = false, - .activate_secondary_controls = true, - }, - }, - - /* - * Test that the secondary processor-based VM-execution controls are - * correctly ignored when "activate secondary controls" is disabled. - */ - { - .name = "Activate secondary controls off", - .apic_reg_virt_config = { - .virtualize_apic_accesses = true, - .use_tpr_shadow = false, - .apic_register_virtualization = true, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = false, - }, - }, - { - .name = "Activate secondary controls off + Use TPR shadow", - .apic_reg_virt_config = { - .virtualize_apic_accesses = true, - .use_tpr_shadow = true, - .apic_register_virtualization = true, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = false, - }, - }, - - /* - * Test that the APIC access address is treated like an arbitrary memory - * address when "virtualize APIC accesses" is disabled. - */ - { - .name = "Virtualize APIC accesses off + Use TPR shadow", - .apic_reg_virt_config = { - .virtualize_apic_accesses = false, - .use_tpr_shadow = true, - .apic_register_virtualization = true, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = true, - }, - }, - - /* - * Test that VM entry fails due to invalid controls when - * "APIC-register virtualization" is enabled while "use TPR shadow" is - * disabled. - */ - { - .name = "APIC-register virtualization + Use TPR shadow off", - .apic_reg_virt_config = { - .virtualize_apic_accesses = true, - .use_tpr_shadow = false, - .apic_register_virtualization = true, - .virtualize_x2apic_mode = false, - .activate_secondary_controls = true, - }, - }, - - /* - * Test that VM entry fails due to invalid controls when - * "Virtualize x2APIC mode" is enabled while "use TPR shadow" is - * disabled. - */ - { - .name = "Virtualize x2APIC mode + Use TPR shadow off", - .apic_reg_virt_config = { - .virtualize_apic_accesses = false, - .use_tpr_shadow = false, - .apic_register_virtualization = false, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = true, - }, - }, - { - .name = "Virtualize x2APIC mode + Use TPR shadow off v2", - .apic_reg_virt_config = { - .virtualize_apic_accesses = false, - .use_tpr_shadow = false, - .apic_register_virtualization = true, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = true, - }, - }, - - /* - * Test that VM entry fails due to invalid controls when - * "virtualize x2APIC mode" is enabled while "virtualize APIC accesses" - * is enabled. - */ - { - .name = "Virtualize x2APIC mode + Virtualize APIC accesses", - .apic_reg_virt_config = { - .virtualize_apic_accesses = true, - .use_tpr_shadow = true, - .apic_register_virtualization = false, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = true, - }, - }, - { - .name = "Virtualize x2APIC mode + Virtualize APIC accesses v2", - .apic_reg_virt_config = { - .virtualize_apic_accesses = true, - .use_tpr_shadow = true, - .apic_register_virtualization = true, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = true, - }, - }, -}; - -enum Apic_op { - APIC_OP_XAPIC_RD, - APIC_OP_XAPIC_WR, - TERMINATE, -}; - -static u32 vmx_xapic_read(u32 *apic_access_address, u32 reg) -{ - return *(volatile u32 *)((uintptr_t)apic_access_address + reg); -} - -static void vmx_xapic_write(u32 *apic_access_address, u32 reg, u32 val) -{ - *(volatile u32 *)((uintptr_t)apic_access_address + reg) = val; -} - -struct apic_reg_virt_guest_args { - enum Apic_op op; - u32 *apic_access_address; - u32 reg; - u32 val; - bool check_rd; - u32 (*virt_fn)(u32); -} apic_reg_virt_guest_args; - -static void apic_reg_virt_guest(void) -{ - volatile struct apic_reg_virt_guest_args *args = - &apic_reg_virt_guest_args; - - for (;;) { - enum Apic_op op = args->op; - u32 *apic_access_address = args->apic_access_address; - u32 reg = args->reg; - u32 val = args->val; - bool check_rd = args->check_rd; - u32 (*virt_fn)(u32) = args->virt_fn; - - if (op == TERMINATE) - break; - - if (op == APIC_OP_XAPIC_RD) { - u32 ret = vmx_xapic_read(apic_access_address, reg); - - if (check_rd) { - u32 want = virt_fn(val); - u32 got = virt_fn(ret); - - report(got == want, - "read 0x%x, expected 0x%x.", got, want); - } - } else if (op == APIC_OP_XAPIC_WR) { - vmx_xapic_write(apic_access_address, reg, val); - } - - /* - * The L1 should always execute a vmcall after it's done testing - * an individual APIC operation. This helps to validate that the - * L1 and L2 are in sync with each other, as expected. - */ - vmcall(); - } -} - -static void test_xapic_rd( - u32 reg, struct apic_reg_virt_expectation *expectation, - u32 *apic_access_address, u32 *virtual_apic_page) -{ - u32 val = expectation->val; - u32 exit_reason_want = expectation->rd_exit_reason; - struct apic_reg_virt_guest_args *args = &apic_reg_virt_guest_args; - - report_prefix_pushf("xapic - reading 0x%03x", reg); - - /* Configure guest to do an xapic read */ - args->op = APIC_OP_XAPIC_RD; - args->apic_access_address = apic_access_address; - args->reg = reg; - args->val = val; - args->check_rd = exit_reason_want == VMX_VMCALL; - args->virt_fn = expectation->virt_fn; - - /* Setup virtual APIC page */ - if (!expectation->virtualize_apic_accesses) { - apic_access_address[apic_reg_index(reg)] = val; - virtual_apic_page[apic_reg_index(reg)] = 0; - } else if (exit_reason_want == VMX_VMCALL) { - apic_access_address[apic_reg_index(reg)] = 0; - virtual_apic_page[apic_reg_index(reg)] = val; - } - - /* Enter guest */ - enter_guest(); - - /* - * Validate the behavior and - * pass a magic value back to the guest. - */ - if (exit_reason_want == VMX_APIC_ACCESS) { - u32 apic_page_offset = vmcs_read(EXI_QUALIFICATION) & 0xfff; - - assert_exit_reason(exit_reason_want); - report(apic_page_offset == reg, - "got APIC access exit @ page offset 0x%03x, want 0x%03x", - apic_page_offset, reg); - skip_exit_insn(); - - /* Reenter guest so it can consume/check rcx and exit again. */ - enter_guest(); - } else if (exit_reason_want != VMX_VMCALL) { - report(false, "Oops, bad exit expectation: %u.", - exit_reason_want); - } - - skip_exit_vmcall(); - report_prefix_pop(); -} - -static void test_xapic_wr( - u32 reg, struct apic_reg_virt_expectation *expectation, - u32 *apic_access_address, u32 *virtual_apic_page) -{ - u32 val = expectation->val; - u32 exit_reason_want = expectation->wr_exit_reason; - struct apic_reg_virt_guest_args *args = &apic_reg_virt_guest_args; - bool virtualized = - expectation->virtualize_apic_accesses && - (exit_reason_want == VMX_APIC_WRITE || - exit_reason_want == VMX_VMCALL); - bool checked = false; - - report_prefix_pushf("xapic - writing 0x%x to 0x%03x", val, reg); - - /* Configure guest to do an xapic read */ - args->op = APIC_OP_XAPIC_WR; - args->apic_access_address = apic_access_address; - args->reg = reg; - args->val = val; - - /* Setup virtual APIC page */ - if (virtualized || !expectation->virtualize_apic_accesses) { - apic_access_address[apic_reg_index(reg)] = 0; - virtual_apic_page[apic_reg_index(reg)] = 0; - } - - /* Enter guest */ - enter_guest(); - - /* - * Validate the behavior and - * pass a magic value back to the guest. - */ - if (exit_reason_want == VMX_APIC_ACCESS) { - u32 apic_page_offset = vmcs_read(EXI_QUALIFICATION) & 0xfff; - - assert_exit_reason(exit_reason_want); - report(apic_page_offset == reg, - "got APIC access exit @ page offset 0x%03x, want 0x%03x", - apic_page_offset, reg); - skip_exit_insn(); - - /* Reenter guest so it can consume/check rcx and exit again. */ - enter_guest(); - } else if (exit_reason_want == VMX_APIC_WRITE) { - assert_exit_reason(exit_reason_want); - report(virtual_apic_page[apic_reg_index(reg)] == val, - "got APIC write exit @ page offset 0x%03x; val is 0x%x, want 0x%x", - apic_reg_index(reg), - virtual_apic_page[apic_reg_index(reg)], val); - checked = true; - - /* Reenter guest so it can consume/check rcx and exit again. */ - enter_guest(); - } else if (exit_reason_want != VMX_VMCALL) { - report(false, "Oops, bad exit expectation: %u.", - exit_reason_want); - } - - assert_exit_reason(VMX_VMCALL); - if (virtualized && !checked) { - u32 want = expectation->virt_fn(val); - u32 got = virtual_apic_page[apic_reg_index(reg)]; - got = expectation->virt_fn(got); - - report(got == want, "exitless write; val is 0x%x, want 0x%x", - got, want); - } else if (!expectation->virtualize_apic_accesses && !checked) { - u32 got = apic_access_address[apic_reg_index(reg)]; - - report(got == val, - "non-virtualized write; val is 0x%x, want 0x%x", got, - val); - } else if (!expectation->virtualize_apic_accesses && checked) { - report(false, - "Non-virtualized write was prematurely checked!"); - } - - skip_exit_vmcall(); - report_prefix_pop(); -} - -enum Config_type { - CONFIG_TYPE_GOOD, - CONFIG_TYPE_UNSUPPORTED, - CONFIG_TYPE_VMENTRY_FAILS_EARLY, -}; - -static enum Config_type configure_apic_reg_virt_test( - struct apic_reg_virt_config *apic_reg_virt_config) -{ - u32 cpu_exec_ctrl0 = vmcs_read(CPU_EXEC_CTRL0); - u32 cpu_exec_ctrl1 = vmcs_read(CPU_EXEC_CTRL1); - /* Configs where L2 entry fails early, due to invalid controls. */ - bool use_tpr_shadow_incorrectly_off = - !apic_reg_virt_config->use_tpr_shadow && - (apic_reg_virt_config->apic_register_virtualization || - apic_reg_virt_config->virtualize_x2apic_mode) && - apic_reg_virt_config->activate_secondary_controls; - bool virtualize_apic_accesses_incorrectly_on = - apic_reg_virt_config->virtualize_apic_accesses && - apic_reg_virt_config->virtualize_x2apic_mode && - apic_reg_virt_config->activate_secondary_controls; - bool vmentry_fails_early = - use_tpr_shadow_incorrectly_off || - virtualize_apic_accesses_incorrectly_on; - - if (apic_reg_virt_config->activate_secondary_controls) { - if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY)) { - printf("VM-execution control \"activate secondary controls\" NOT supported.\n"); - return CONFIG_TYPE_UNSUPPORTED; - } - cpu_exec_ctrl0 |= CPU_SECONDARY; - } else { - cpu_exec_ctrl0 &= ~CPU_SECONDARY; - } - - if (apic_reg_virt_config->virtualize_apic_accesses) { - if (!(ctrl_cpu_rev[1].clr & CPU_VIRT_APIC_ACCESSES)) { - printf("VM-execution control \"virtualize APIC accesses\" NOT supported.\n"); - return CONFIG_TYPE_UNSUPPORTED; - } - cpu_exec_ctrl1 |= CPU_VIRT_APIC_ACCESSES; - } else { - cpu_exec_ctrl1 &= ~CPU_VIRT_APIC_ACCESSES; - } - - if (apic_reg_virt_config->use_tpr_shadow) { - if (!(ctrl_cpu_rev[0].clr & CPU_TPR_SHADOW)) { - printf("VM-execution control \"use TPR shadow\" NOT supported.\n"); - return CONFIG_TYPE_UNSUPPORTED; - } - cpu_exec_ctrl0 |= CPU_TPR_SHADOW; - } else { - cpu_exec_ctrl0 &= ~CPU_TPR_SHADOW; - } - - if (apic_reg_virt_config->apic_register_virtualization) { - if (!(ctrl_cpu_rev[1].clr & CPU_APIC_REG_VIRT)) { - printf("VM-execution control \"APIC-register virtualization\" NOT supported.\n"); - return CONFIG_TYPE_UNSUPPORTED; - } - cpu_exec_ctrl1 |= CPU_APIC_REG_VIRT; - } else { - cpu_exec_ctrl1 &= ~CPU_APIC_REG_VIRT; - } - - if (apic_reg_virt_config->virtualize_x2apic_mode) { - if (!(ctrl_cpu_rev[1].clr & CPU_VIRT_X2APIC)) { - printf("VM-execution control \"virtualize x2APIC mode\" NOT supported.\n"); - return CONFIG_TYPE_UNSUPPORTED; - } - cpu_exec_ctrl1 |= CPU_VIRT_X2APIC; - } else { - cpu_exec_ctrl1 &= ~CPU_VIRT_X2APIC; - } - - vmcs_write(CPU_EXEC_CTRL0, cpu_exec_ctrl0); - vmcs_write(CPU_EXEC_CTRL1, cpu_exec_ctrl1); - - if (vmentry_fails_early) - return CONFIG_TYPE_VMENTRY_FAILS_EARLY; - - return CONFIG_TYPE_GOOD; -} - -static bool cpu_has_apicv(void) -{ - return ((ctrl_cpu_rev[1].clr & CPU_APIC_REG_VIRT) && - (ctrl_cpu_rev[1].clr & CPU_VINTD) && - (ctrl_pin_rev.clr & PIN_POST_INTR)); -} - -/* Validates APIC register access across valid virtualization configurations. */ -static void apic_reg_virt_test(void) -{ - u32 *apic_access_address; - u32 *virtual_apic_page; - u64 control; - u64 cpu_exec_ctrl0 = vmcs_read(CPU_EXEC_CTRL0); - u64 cpu_exec_ctrl1 = vmcs_read(CPU_EXEC_CTRL1); - int i; - struct apic_reg_virt_guest_args *args = &apic_reg_virt_guest_args; - - if (!cpu_has_apicv()) { - report_skip(__func__); - return; - } - - control = cpu_exec_ctrl1; - control &= ~CPU_VINTD; - vmcs_write(CPU_EXEC_CTRL1, control); - - test_set_guest(apic_reg_virt_guest); - - /* - * From the SDM: The 1-setting of the "virtualize APIC accesses" - * VM-execution is guaranteed to apply only if translations to the - * APIC-access address use a 4-KByte page. - */ - apic_access_address = alloc_page(); - force_4k_page(apic_access_address); - vmcs_write(APIC_ACCS_ADDR, virt_to_phys(apic_access_address)); - - virtual_apic_page = alloc_page(); - vmcs_write(APIC_VIRT_ADDR, virt_to_phys(virtual_apic_page)); - - for (i = 0; i < ARRAY_SIZE(apic_reg_tests); i++) { - struct apic_reg_test *apic_reg_test = &apic_reg_tests[i]; - struct apic_reg_virt_config *apic_reg_virt_config = - &apic_reg_test->apic_reg_virt_config; - enum Config_type config_type; - u32 reg; - - printf("--- %s test ---\n", apic_reg_test->name); - config_type = - configure_apic_reg_virt_test(apic_reg_virt_config); - if (config_type == CONFIG_TYPE_UNSUPPORTED) { - printf("Skip because of missing features.\n"); - continue; - } - - if (config_type == CONFIG_TYPE_VMENTRY_FAILS_EARLY) { - enter_guest_with_bad_controls(); - continue; - } - - for (reg = 0; reg < PAGE_SIZE / sizeof(u32); reg += 0x10) { - struct apic_reg_virt_expectation expectation = {}; - bool ok; - - ok = apic_reg_virt_exit_expectation( - reg, apic_reg_virt_config, &expectation); - if (!ok) { - report(false, "Malformed test."); - break; - } - - test_xapic_rd(reg, &expectation, apic_access_address, - virtual_apic_page); - test_xapic_wr(reg, &expectation, apic_access_address, - virtual_apic_page); - } - } - - /* Terminate the guest */ - vmcs_write(CPU_EXEC_CTRL0, cpu_exec_ctrl0); - vmcs_write(CPU_EXEC_CTRL1, cpu_exec_ctrl1); - args->op = TERMINATE; - enter_guest(); - assert_exit_reason(VMX_VMCALL); -} - -struct virt_x2apic_mode_config { - struct apic_reg_virt_config apic_reg_virt_config; - bool virtual_interrupt_delivery; - bool use_msr_bitmaps; - bool disable_x2apic_msr_intercepts; - bool disable_x2apic; -}; - -struct virt_x2apic_mode_test_case { - const char *name; - struct virt_x2apic_mode_config virt_x2apic_mode_config; -}; - -enum Virt_x2apic_mode_behavior_type { - X2APIC_ACCESS_VIRTUALIZED, - X2APIC_ACCESS_PASSED_THROUGH, - X2APIC_ACCESS_TRIGGERS_GP, -}; - -struct virt_x2apic_mode_expectation { - enum Reason rd_exit_reason; - enum Reason wr_exit_reason; - - /* - * RDMSR and WRMSR handle 64-bit values. However, except for ICR, all of - * the x2APIC registers are 32 bits. Notice: - * 1. vmx_x2apic_read() clears the upper 32 bits for 32-bit registers. - * 2. vmx_x2apic_write() expects the val arg to be well-formed. - */ - u64 rd_val; - u64 wr_val; - - /* - * Compares input to virtualized output; - * 1st arg is pointer to return expected virtualization output. - */ - u64 (*virt_fn)(u64); - - enum Virt_x2apic_mode_behavior_type rd_behavior; - enum Virt_x2apic_mode_behavior_type wr_behavior; - bool wr_only; -}; - -static u64 virt_x2apic_mode_identity(u64 val) -{ - return val; -} - -static u64 virt_x2apic_mode_nibble1(u64 val) -{ - return val & 0xf0; -} - -static void virt_x2apic_mode_rd_expectation( - u32 reg, bool virt_x2apic_mode_on, bool disable_x2apic, - bool apic_register_virtualization, bool virtual_interrupt_delivery, - struct virt_x2apic_mode_expectation *expectation) -{ - bool readable = - !x2apic_reg_reserved(reg) && - reg != APIC_EOI; - - expectation->rd_exit_reason = VMX_VMCALL; - expectation->virt_fn = virt_x2apic_mode_identity; - if (virt_x2apic_mode_on && apic_register_virtualization) { - expectation->rd_val = MAGIC_VAL_1; - if (reg == APIC_PROCPRI && virtual_interrupt_delivery) - expectation->virt_fn = virt_x2apic_mode_nibble1; - else if (reg == APIC_TASKPRI) - expectation->virt_fn = virt_x2apic_mode_nibble1; - expectation->rd_behavior = X2APIC_ACCESS_VIRTUALIZED; - } else if (virt_x2apic_mode_on && !apic_register_virtualization && - reg == APIC_TASKPRI) { - expectation->rd_val = MAGIC_VAL_1; - expectation->virt_fn = virt_x2apic_mode_nibble1; - expectation->rd_behavior = X2APIC_ACCESS_VIRTUALIZED; - } else if (!disable_x2apic && readable) { - expectation->rd_val = apic_read(reg); - expectation->rd_behavior = X2APIC_ACCESS_PASSED_THROUGH; - } else { - expectation->rd_behavior = X2APIC_ACCESS_TRIGGERS_GP; - } -} - -/* - * get_x2apic_wr_val() creates an innocuous write value for an x2APIC register. - * - * For writable registers, get_x2apic_wr_val() deposits the write value into the - * val pointer arg and returns true. For non-writable registers, val is not - * modified and get_x2apic_wr_val() returns false. - */ -static bool get_x2apic_wr_val(u32 reg, u64 *val) -{ - switch (reg) { - case APIC_TASKPRI: - /* Bits 31:8 are reserved. */ - *val &= 0xff; - break; - case APIC_EOI: - case APIC_ESR: - case APIC_TMICT: - /* - * EOI, ESR: WRMSR of a non-zero value causes #GP(0). - * TMICT: A write of 0 to the initial-count register effectively - * stops the local APIC timer, in both one-shot and - * periodic mode. - */ - *val = 0; - break; - case APIC_SPIV: - case APIC_LVTT: - case APIC_LVTTHMR: - case APIC_LVTPC: - case APIC_LVT0: - case APIC_LVT1: - case APIC_LVTERR: - case APIC_TDCR: - /* - * To avoid writing a 1 to a reserved bit or causing some other - * unintended side effect, read the current value and use it as - * the write value. - */ - *val = apic_read(reg); - break; - case APIC_CMCI: - if (!apic_lvt_entry_supported(6)) - return false; - *val = apic_read(reg); - break; - case APIC_ICR: - *val = 0x40000 | 0xf1; - break; - case APIC_SELF_IPI: - /* - * With special processing (i.e., virtualize x2APIC mode + - * virtual interrupt delivery), writing zero causes an - * APIC-write VM exit. We plan to add a test for enabling - * "virtual-interrupt delivery" in VMCS12, and that's where we - * will test a self IPI with special processing. - */ - *val = 0x0; - break; - default: - return false; - } - - return true; -} - -static bool special_processing_applies(u32 reg, u64 *val, - bool virt_int_delivery) -{ - bool special_processing = - (reg == APIC_TASKPRI) || - (virt_int_delivery && - (reg == APIC_EOI || reg == APIC_SELF_IPI)); - - if (special_processing) { - TEST_ASSERT(get_x2apic_wr_val(reg, val)); - return true; - } - - return false; -} - -static void virt_x2apic_mode_wr_expectation( - u32 reg, bool virt_x2apic_mode_on, bool disable_x2apic, - bool virt_int_delivery, - struct virt_x2apic_mode_expectation *expectation) -{ - expectation->wr_exit_reason = VMX_VMCALL; - expectation->wr_val = MAGIC_VAL_1; - expectation->wr_only = false; - - if (virt_x2apic_mode_on && - special_processing_applies(reg, &expectation->wr_val, - virt_int_delivery)) { - expectation->wr_behavior = X2APIC_ACCESS_VIRTUALIZED; - if (reg == APIC_SELF_IPI) - expectation->wr_exit_reason = VMX_APIC_WRITE; - } else if (!disable_x2apic && - get_x2apic_wr_val(reg, &expectation->wr_val)) { - expectation->wr_behavior = X2APIC_ACCESS_PASSED_THROUGH; - if (reg == APIC_EOI || reg == APIC_SELF_IPI) - expectation->wr_only = true; - if (reg == APIC_ICR) - expectation->wr_exit_reason = VMX_EXTINT; - } else { - expectation->wr_behavior = X2APIC_ACCESS_TRIGGERS_GP; - /* - * Writing 1 to a reserved bit triggers a #GP. - * Thus, set the write value to 0, which seems - * the most likely to detect a missed #GP. - */ - expectation->wr_val = 0; - } -} - -static void virt_x2apic_mode_exit_expectation( - u32 reg, struct virt_x2apic_mode_config *config, - struct virt_x2apic_mode_expectation *expectation) -{ - struct apic_reg_virt_config *base_config = - &config->apic_reg_virt_config; - bool virt_x2apic_mode_on = - base_config->virtualize_x2apic_mode && - config->use_msr_bitmaps && - config->disable_x2apic_msr_intercepts && - base_config->activate_secondary_controls; - - virt_x2apic_mode_wr_expectation( - reg, virt_x2apic_mode_on, config->disable_x2apic, - config->virtual_interrupt_delivery, expectation); - virt_x2apic_mode_rd_expectation( - reg, virt_x2apic_mode_on, config->disable_x2apic, - base_config->apic_register_virtualization, - config->virtual_interrupt_delivery, expectation); -} - -struct virt_x2apic_mode_test_case virt_x2apic_mode_tests[] = { - /* - * Baseline "virtualize x2APIC mode" configuration: - * - virtualize x2APIC mode - * - virtual-interrupt delivery - * - APIC-register virtualization - * - x2APIC MSR intercepts disabled - * - * Reads come from virtual APIC page, special processing applies to - * VTPR, EOI, and SELF IPI, and all other writes pass through to L1 - * APIC. - */ - { - .name = "Baseline", - .virt_x2apic_mode_config = { - .virtual_interrupt_delivery = true, - .use_msr_bitmaps = true, - .disable_x2apic_msr_intercepts = true, - .disable_x2apic = false, - .apic_reg_virt_config = { - .apic_register_virtualization = true, - .use_tpr_shadow = true, - .virtualize_apic_accesses = false, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = true, - }, - }, - }, - { - .name = "Baseline w/ x2apic disabled", - .virt_x2apic_mode_config = { - .virtual_interrupt_delivery = true, - .use_msr_bitmaps = true, - .disable_x2apic_msr_intercepts = true, - .disable_x2apic = true, - .apic_reg_virt_config = { - .apic_register_virtualization = true, - .use_tpr_shadow = true, - .virtualize_apic_accesses = false, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = true, - }, - }, - }, - - /* - * Baseline, minus virtual-interrupt delivery. Reads come from virtual - * APIC page, special processing applies to VTPR, and all other writes - * pass through to L1 APIC. - */ - { - .name = "Baseline - virtual interrupt delivery", - .virt_x2apic_mode_config = { - .virtual_interrupt_delivery = false, - .use_msr_bitmaps = true, - .disable_x2apic_msr_intercepts = true, - .disable_x2apic = false, - .apic_reg_virt_config = { - .apic_register_virtualization = true, - .use_tpr_shadow = true, - .virtualize_apic_accesses = false, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = true, - }, - }, - }, - - /* - * Baseline, minus APIC-register virtualization. x2APIC reads pass - * through to L1's APIC, unless reading VTPR - */ - { - .name = "Virtualize x2APIC mode, no APIC reg virt", - .virt_x2apic_mode_config = { - .virtual_interrupt_delivery = true, - .use_msr_bitmaps = true, - .disable_x2apic_msr_intercepts = true, - .disable_x2apic = false, - .apic_reg_virt_config = { - .apic_register_virtualization = false, - .use_tpr_shadow = true, - .virtualize_apic_accesses = false, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = true, - }, - }, - }, - { - .name = "Virtualize x2APIC mode, no APIC reg virt, x2APIC off", - .virt_x2apic_mode_config = { - .virtual_interrupt_delivery = true, - .use_msr_bitmaps = true, - .disable_x2apic_msr_intercepts = true, - .disable_x2apic = true, - .apic_reg_virt_config = { - .apic_register_virtualization = false, - .use_tpr_shadow = true, - .virtualize_apic_accesses = false, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = true, - }, - }, - }, - - /* - * Enable "virtualize x2APIC mode" and "APIC-register virtualization", - * and disable intercepts for the x2APIC MSRs, but fail to enable - * "activate secondary controls" (i.e. L2 gets access to L1's x2APIC - * MSRs). - */ - { - .name = "Fail to enable activate secondary controls", - .virt_x2apic_mode_config = { - .virtual_interrupt_delivery = true, - .use_msr_bitmaps = true, - .disable_x2apic_msr_intercepts = true, - .disable_x2apic = false, - .apic_reg_virt_config = { - .apic_register_virtualization = true, - .use_tpr_shadow = true, - .virtualize_apic_accesses = false, - .virtualize_x2apic_mode = true, - .activate_secondary_controls = false, - }, - }, - }, - - /* - * Enable "APIC-register virtualization" and enable "activate secondary - * controls" and disable intercepts for the x2APIC MSRs, but do not - * enable the "virtualize x2APIC mode" VM-execution control (i.e. L2 - * gets access to L1's x2APIC MSRs). - */ - { - .name = "Fail to enable virtualize x2APIC mode", - .virt_x2apic_mode_config = { - .virtual_interrupt_delivery = true, - .use_msr_bitmaps = true, - .disable_x2apic_msr_intercepts = true, - .disable_x2apic = false, - .apic_reg_virt_config = { - .apic_register_virtualization = true, - .use_tpr_shadow = true, - .virtualize_apic_accesses = false, - .virtualize_x2apic_mode = false, - .activate_secondary_controls = true, - }, - }, - }, - - /* - * Disable "Virtualize x2APIC mode", disable x2APIC MSR intercepts, and - * enable "APIC-register virtualization" --> L2 gets L1's x2APIC MSRs. - */ - { - .name = "Baseline", - .virt_x2apic_mode_config = { - .virtual_interrupt_delivery = true, - .use_msr_bitmaps = true, - .disable_x2apic_msr_intercepts = true, - .disable_x2apic = false, - .apic_reg_virt_config = { - .apic_register_virtualization = true, - .use_tpr_shadow = true, - .virtualize_apic_accesses = false, - .virtualize_x2apic_mode = false, - .activate_secondary_controls = true, - }, - }, - }, -}; - -enum X2apic_op { - X2APIC_OP_RD, - X2APIC_OP_WR, - X2APIC_TERMINATE, -}; - -static u64 vmx_x2apic_read(u32 reg) -{ - u32 msr_addr = x2apic_msr(reg); - u64 val; - - val = rdmsr(msr_addr); - - return val; -} - -static void vmx_x2apic_write(u32 reg, u64 val) -{ - u32 msr_addr = x2apic_msr(reg); - - wrmsr(msr_addr, val); -} - -struct virt_x2apic_mode_guest_args { - enum X2apic_op op; - u32 reg; - u64 val; - bool should_gp; - u64 (*virt_fn)(u64); -} virt_x2apic_mode_guest_args; - -static volatile bool handle_x2apic_gp_ran; -static volatile u32 handle_x2apic_gp_insn_len; -static void handle_x2apic_gp(struct ex_regs *regs) -{ - handle_x2apic_gp_ran = true; - regs->rip += handle_x2apic_gp_insn_len; -} - -static handler setup_x2apic_gp_handler(void) -{ - handler old_handler; - - old_handler = handle_exception(GP_VECTOR, handle_x2apic_gp); - /* RDMSR and WRMSR are both 2 bytes, assuming no prefixes. */ - handle_x2apic_gp_insn_len = 2; - - return old_handler; -} - -static void teardown_x2apic_gp_handler(handler old_handler) -{ - handle_exception(GP_VECTOR, old_handler); - - /* - * Defensively reset instruction length, so that if the handler is - * incorrectly used, it will loop infinitely, rather than run off into - * la la land. - */ - handle_x2apic_gp_insn_len = 0; - handle_x2apic_gp_ran = false; -} - -static void virt_x2apic_mode_guest(void) -{ - volatile struct virt_x2apic_mode_guest_args *args = - &virt_x2apic_mode_guest_args; - - for (;;) { - enum X2apic_op op = args->op; - u32 reg = args->reg; - u64 val = args->val; - bool should_gp = args->should_gp; - u64 (*virt_fn)(u64) = args->virt_fn; - handler old_handler; - - if (op == X2APIC_TERMINATE) - break; - - if (should_gp) { - TEST_ASSERT(!handle_x2apic_gp_ran); - old_handler = setup_x2apic_gp_handler(); - } - - if (op == X2APIC_OP_RD) { - u64 ret = vmx_x2apic_read(reg); - - if (!should_gp) { - u64 want = virt_fn(val); - u64 got = virt_fn(ret); - - report(got == want, - "APIC read; got 0x%lx, want 0x%lx.", - got, want); - } - } else if (op == X2APIC_OP_WR) { - vmx_x2apic_write(reg, val); - } - - if (should_gp) { - report(handle_x2apic_gp_ran, - "x2APIC op triggered GP."); - teardown_x2apic_gp_handler(old_handler); - } - - /* - * The L1 should always execute a vmcall after it's done testing - * an individual APIC operation. This helps to validate that the - * L1 and L2 are in sync with each other, as expected. - */ - vmcall(); - } -} - -static void test_x2apic_rd( - u32 reg, struct virt_x2apic_mode_expectation *expectation, - u32 *virtual_apic_page) -{ - u64 val = expectation->rd_val; - u32 exit_reason_want = expectation->rd_exit_reason; - struct virt_x2apic_mode_guest_args *args = &virt_x2apic_mode_guest_args; - - report_prefix_pushf("x2apic - reading 0x%03x", reg); - - /* Configure guest to do an x2apic read */ - args->op = X2APIC_OP_RD; - args->reg = reg; - args->val = val; - args->should_gp = expectation->rd_behavior == X2APIC_ACCESS_TRIGGERS_GP; - args->virt_fn = expectation->virt_fn; - - /* Setup virtual APIC page */ - if (expectation->rd_behavior == X2APIC_ACCESS_VIRTUALIZED) - virtual_apic_page[apic_reg_index(reg)] = (u32)val; - - /* Enter guest */ - enter_guest(); - - if (exit_reason_want != VMX_VMCALL) { - report(false, "Oops, bad exit expectation: %u.", - exit_reason_want); - } - - skip_exit_vmcall(); - report_prefix_pop(); -} - -static volatile bool handle_x2apic_ipi_ran; -static void handle_x2apic_ipi(isr_regs_t *regs) -{ - handle_x2apic_ipi_ran = true; - eoi(); -} - -static void test_x2apic_wr( - u32 reg, struct virt_x2apic_mode_expectation *expectation, - u32 *virtual_apic_page) -{ - u64 val = expectation->wr_val; - u32 exit_reason_want = expectation->wr_exit_reason; - struct virt_x2apic_mode_guest_args *args = &virt_x2apic_mode_guest_args; - int ipi_vector = 0xf1; - u32 restore_val = 0; - - report_prefix_pushf("x2apic - writing 0x%lx to 0x%03x", val, reg); - - /* Configure guest to do an x2apic read */ - args->op = X2APIC_OP_WR; - args->reg = reg; - args->val = val; - args->should_gp = expectation->wr_behavior == X2APIC_ACCESS_TRIGGERS_GP; - - /* Setup virtual APIC page */ - if (expectation->wr_behavior == X2APIC_ACCESS_VIRTUALIZED) - virtual_apic_page[apic_reg_index(reg)] = 0; - if (expectation->wr_behavior == X2APIC_ACCESS_PASSED_THROUGH && !expectation->wr_only) - restore_val = apic_read(reg); - - /* Setup IPI handler */ - handle_x2apic_ipi_ran = false; - handle_irq(ipi_vector, handle_x2apic_ipi); - - /* Enter guest */ - enter_guest(); - - /* - * Validate the behavior and - * pass a magic value back to the guest. - */ - if (exit_reason_want == VMX_EXTINT) { - assert_exit_reason(exit_reason_want); - - /* Clear the external interrupt. */ - irq_enable(); - asm volatile ("nop"); - irq_disable(); - report(handle_x2apic_ipi_ran, - "Got pending interrupt after IRQ enabled."); - - enter_guest(); - } else if (exit_reason_want == VMX_APIC_WRITE) { - assert_exit_reason(exit_reason_want); - report(virtual_apic_page[apic_reg_index(reg)] == val, - "got APIC write exit @ page offset 0x%03x; val is 0x%x, want 0x%lx", - apic_reg_index(reg), - virtual_apic_page[apic_reg_index(reg)], val); - - /* Reenter guest so it can consume/check rcx and exit again. */ - enter_guest(); - } else if (exit_reason_want != VMX_VMCALL) { - report(false, "Oops, bad exit expectation: %u.", - exit_reason_want); - } - - assert_exit_reason(VMX_VMCALL); - if (expectation->wr_behavior == X2APIC_ACCESS_VIRTUALIZED) { - u64 want = val; - u32 got = virtual_apic_page[apic_reg_index(reg)]; - - report(got == want, "x2APIC write; got 0x%x, want 0x%lx", got, - want); - } else if (expectation->wr_behavior == X2APIC_ACCESS_PASSED_THROUGH) { - if (!expectation->wr_only) { - u32 got = apic_read(reg); - bool ok; - - /* - * When L1's TPR is passed through to L2, the lower - * nibble can be lost. For example, if L2 executes - * WRMSR(0x808, 0x78), then, L1 might read 0x70. - * - * Here's how the lower nibble can get lost: - * 1. L2 executes WRMSR(0x808, 0x78). - * 2. L2 exits to L0 with a WRMSR exit. - * 3. L0 emulates WRMSR, by writing L1's TPR. - * 4. L0 re-enters L2. - * 5. L2 exits to L0 (reason doesn't matter). - * 6. L0 reflects L2's exit to L1. - * 7. Before entering L1, L0 exits to user-space - * (e.g., to satisfy TPR access reporting). - * 8. User-space executes KVM_SET_REGS ioctl, which - * clears the lower nibble of L1's TPR. - */ - if (reg == APIC_TASKPRI) { - got = apic_virt_nibble1(got); - val = apic_virt_nibble1(val); - } - - ok = got == val; - report(ok, - "non-virtualized write; val is 0x%x, want 0x%lx", - got, val); - apic_write(reg, restore_val); - } else { - report(true, "non-virtualized and write-only OK"); - } - } - skip_exit_insn(); - - report_prefix_pop(); -} - -static enum Config_type configure_virt_x2apic_mode_test( - struct virt_x2apic_mode_config *virt_x2apic_mode_config, - u8 *msr_bitmap_page) -{ - int msr; - u32 cpu_exec_ctrl0 = vmcs_read(CPU_EXEC_CTRL0); - u64 cpu_exec_ctrl1 = vmcs_read(CPU_EXEC_CTRL1); - - /* x2apic-specific VMCS config */ - if (virt_x2apic_mode_config->use_msr_bitmaps) { - /* virt_x2apic_mode_test() checks for MSR bitmaps support */ - cpu_exec_ctrl0 |= CPU_MSR_BITMAP; - } else { - cpu_exec_ctrl0 &= ~CPU_MSR_BITMAP; - } - - if (virt_x2apic_mode_config->virtual_interrupt_delivery) { - if (!(ctrl_cpu_rev[1].clr & CPU_VINTD)) { - report_skip("VM-execution control \"virtual-interrupt delivery\" NOT supported.\n"); - return CONFIG_TYPE_UNSUPPORTED; - } - cpu_exec_ctrl1 |= CPU_VINTD; - } else { - cpu_exec_ctrl1 &= ~CPU_VINTD; - } - - vmcs_write(CPU_EXEC_CTRL0, cpu_exec_ctrl0); - vmcs_write(CPU_EXEC_CTRL1, cpu_exec_ctrl1); - - /* x2APIC MSR intercepts are usually off for "Virtualize x2APIC mode" */ - for (msr = 0x800; msr <= 0x8ff; msr++) { - if (virt_x2apic_mode_config->disable_x2apic_msr_intercepts) { - clear_bit(msr, msr_bitmap_page + 0x000); - clear_bit(msr, msr_bitmap_page + 0x800); - } else { - set_bit(msr, msr_bitmap_page + 0x000); - set_bit(msr, msr_bitmap_page + 0x800); - } - } - - /* x2APIC mode can impact virtualization */ - reset_apic(); - if (!virt_x2apic_mode_config->disable_x2apic) - enable_x2apic(); - - return configure_apic_reg_virt_test( - &virt_x2apic_mode_config->apic_reg_virt_config); -} - -static void virt_x2apic_mode_test(void) -{ - u32 *virtual_apic_page; - u8 *msr_bitmap_page; - u64 cpu_exec_ctrl0 = vmcs_read(CPU_EXEC_CTRL0); - u64 cpu_exec_ctrl1 = vmcs_read(CPU_EXEC_CTRL1); - int i; - struct virt_x2apic_mode_guest_args *args = &virt_x2apic_mode_guest_args; - - if (!cpu_has_apicv()) { - report_skip(__func__); - return; - } - - /* - * This is to exercise an issue in KVM's logic to merge L0's and L1's - * MSR bitmaps. Previously, an L1 could get at L0's x2APIC MSRs by - * writing the IA32_SPEC_CTRL MSR or the IA32_PRED_CMD MSRs. KVM would - * then proceed to manipulate the MSR bitmaps, as if VMCS12 had the - * "Virtualize x2APIC mod" control set, even when it didn't. - */ - if (has_spec_ctrl()) - wrmsr(MSR_IA32_SPEC_CTRL, 1); - - /* - * Check that VMCS12 supports: - * - "Virtual-APIC address", indicated by "use TPR shadow" - * - "MSR-bitmap address", indicated by "use MSR bitmaps" - */ - if (!(ctrl_cpu_rev[0].clr & CPU_TPR_SHADOW)) { - report_skip("VM-execution control \"use TPR shadow\" NOT supported.\n"); - return; - } else if (!(ctrl_cpu_rev[0].clr & CPU_MSR_BITMAP)) { - report_skip("VM-execution control \"use MSR bitmaps\" NOT supported.\n"); - return; - } - - test_set_guest(virt_x2apic_mode_guest); - - virtual_apic_page = alloc_page(); - vmcs_write(APIC_VIRT_ADDR, virt_to_phys(virtual_apic_page)); - - msr_bitmap_page = alloc_page(); - memset(msr_bitmap_page, 0xff, PAGE_SIZE); - vmcs_write(MSR_BITMAP, virt_to_phys(msr_bitmap_page)); - - for (i = 0; i < ARRAY_SIZE(virt_x2apic_mode_tests); i++) { - struct virt_x2apic_mode_test_case *virt_x2apic_mode_test_case = - &virt_x2apic_mode_tests[i]; - struct virt_x2apic_mode_config *virt_x2apic_mode_config = - &virt_x2apic_mode_test_case->virt_x2apic_mode_config; - enum Config_type config_type; - u32 reg; - - printf("--- %s test ---\n", virt_x2apic_mode_test_case->name); - config_type = - configure_virt_x2apic_mode_test(virt_x2apic_mode_config, - msr_bitmap_page); - if (config_type == CONFIG_TYPE_UNSUPPORTED) { - report_skip("Skip because of missing features.\n"); - continue; - } else if (config_type == CONFIG_TYPE_VMENTRY_FAILS_EARLY) { - enter_guest_with_bad_controls(); - continue; - } - - for (reg = 0; reg < PAGE_SIZE / sizeof(u32); reg += 0x10) { - struct virt_x2apic_mode_expectation expectation; - - virt_x2apic_mode_exit_expectation( - reg, virt_x2apic_mode_config, &expectation); - - test_x2apic_rd(reg, &expectation, virtual_apic_page); - test_x2apic_wr(reg, &expectation, virtual_apic_page); - } - } - - - /* Terminate the guest */ - vmcs_write(CPU_EXEC_CTRL0, cpu_exec_ctrl0); - vmcs_write(CPU_EXEC_CTRL1, cpu_exec_ctrl1); - args->op = X2APIC_TERMINATE; - enter_guest(); - assert_exit_reason(VMX_VMCALL); -} - -static void test_ctl_reg(const char *cr_name, u64 cr, u64 fixed0, u64 fixed1) -{ - u64 val; - u64 cr_saved = vmcs_read(cr); - int i; - - val = fixed0 & fixed1; - if (cr == HOST_CR4) - vmcs_write(cr, val | X86_CR4_PAE); - else - vmcs_write(cr, val); - report_prefix_pushf("%s %lx", cr_name, val); - if (val == fixed0) - test_vmx_vmlaunch(0); - else - test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); - report_prefix_pop(); - - for (i = 0; i < 64; i++) { - - /* Set a bit when the corresponding bit in fixed1 is 0 */ - if ((fixed1 & (1ull << i)) == 0) { - if (cr == HOST_CR4 && ((1ull << i) & X86_CR4_SMEP || - (1ull << i) & X86_CR4_SMAP)) - continue; - - vmcs_write(cr, cr_saved | (1ull << i)); - report_prefix_pushf("%s %llx", cr_name, - cr_saved | (1ull << i)); - test_vmx_vmlaunch( - VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); - report_prefix_pop(); - } - - /* Unset a bit when the corresponding bit in fixed0 is 1 */ - if (fixed0 & (1ull << i)) { - vmcs_write(cr, cr_saved & ~(1ull << i)); - report_prefix_pushf("%s %llx", cr_name, - cr_saved & ~(1ull << i)); - test_vmx_vmlaunch( - VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); - report_prefix_pop(); - } - } - - vmcs_write(cr, cr_saved); -} - -/* - * 1. The CR0 field must not set any bit to a value not supported in VMX - * operation. - * 2. The CR4 field must not set any bit to a value not supported in VMX - * operation. - * 3. On processors that support Intel 64 architecture, the CR3 field must - * be such that bits 63:52 and bits in the range 51:32 beyond the - * processor’s physical-address width must be 0. - * - * [Intel SDM] - */ -static void test_host_ctl_regs(void) -{ - u64 fixed0, fixed1, cr3, cr3_saved; - int i; - - /* Test CR0 */ - fixed0 = rdmsr(MSR_IA32_VMX_CR0_FIXED0); - fixed1 = rdmsr(MSR_IA32_VMX_CR0_FIXED1); - test_ctl_reg("HOST_CR0", HOST_CR0, fixed0, fixed1); - - /* Test CR4 */ - fixed0 = rdmsr(MSR_IA32_VMX_CR4_FIXED0); - fixed1 = rdmsr(MSR_IA32_VMX_CR4_FIXED1) & - ~(X86_CR4_SMEP | X86_CR4_SMAP); - test_ctl_reg("HOST_CR4", HOST_CR4, fixed0, fixed1); - - /* Test CR3 */ - cr3_saved = vmcs_read(HOST_CR3); - for (i = cpuid_maxphyaddr(); i < 64; i++) { - cr3 = cr3_saved | (1ul << i); - vmcs_write(HOST_CR3, cr3); - report_prefix_pushf("HOST_CR3 %lx", cr3); - test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); - report_prefix_pop(); - } - - vmcs_write(HOST_CR3, cr3_saved); -} - -static void test_efer_vmlaunch(u32 fld, bool ok) -{ - if (fld == HOST_EFER) { - if (ok) - test_vmx_vmlaunch(0); - else - test_vmx_vmlaunch2(VMXERR_ENTRY_INVALID_CONTROL_FIELD, - VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); - } else { - test_guest_state("EFER test", !ok, GUEST_EFER, "GUEST_EFER"); - } -} - -static void test_efer_one(u32 fld, const char * fld_name, u64 efer, - u32 ctrl_fld, u64 ctrl, - int i, const char *efer_bit_name) -{ - bool ok; - - ok = true; - if (ctrl_fld == EXI_CONTROLS && (ctrl & EXI_LOAD_EFER)) { - if (!!(efer & EFER_LMA) != !!(ctrl & EXI_HOST_64)) - ok = false; - if (!!(efer & EFER_LME) != !!(ctrl & EXI_HOST_64)) - ok = false; - } - if (ctrl_fld == ENT_CONTROLS && (ctrl & ENT_LOAD_EFER)) { - /* Check LMA too since CR0.PG is set. */ - if (!!(efer & EFER_LMA) != !!(ctrl & ENT_GUEST_64)) - ok = false; - if (!!(efer & EFER_LME) != !!(ctrl & ENT_GUEST_64)) - ok = false; - } - - /* - * Skip the test if it would enter the guest in 32-bit mode. - * Perhaps write the test in assembly and make sure it - * can be run in either mode? - */ - if (fld == GUEST_EFER && ok && !(ctrl & ENT_GUEST_64)) - return; - - vmcs_write(ctrl_fld, ctrl); - vmcs_write(fld, efer); - report_prefix_pushf("%s %s bit turned %s, controls %s", - fld_name, efer_bit_name, - (i & 1) ? "on" : "off", - (i & 2) ? "on" : "off"); - - test_efer_vmlaunch(fld, ok); - report_prefix_pop(); -} - -static void test_efer_bit(u32 fld, const char * fld_name, - u32 ctrl_fld, u64 ctrl_bit, u64 efer_bit, - const char *efer_bit_name) -{ - u64 efer_saved = vmcs_read(fld); - u32 ctrl_saved = vmcs_read(ctrl_fld); - int i; - - for (i = 0; i < 4; i++) { - u64 efer = efer_saved & ~efer_bit; - u64 ctrl = ctrl_saved & ~ctrl_bit; - - if (i & 1) - efer |= efer_bit; - if (i & 2) - ctrl |= ctrl_bit; - - test_efer_one(fld, fld_name, efer, ctrl_fld, ctrl, - i, efer_bit_name); - } - - vmcs_write(ctrl_fld, ctrl_saved); - vmcs_write(fld, efer_saved); -} - -static void test_efer(u32 fld, const char * fld_name, u32 ctrl_fld, - u64 ctrl_bit1, u64 ctrl_bit2) -{ - u64 efer_saved = vmcs_read(fld); - u32 ctrl_saved = vmcs_read(ctrl_fld); - u64 efer_reserved_bits = ~((u64)(EFER_SCE | EFER_LME | EFER_LMA)); - u64 i; - u64 efer; - - if (cpu_has_efer_nx()) - efer_reserved_bits &= ~EFER_NX; - - if (!ctrl_bit1) { - printf("\"Load-IA32-EFER\" exit control not supported\n"); - goto test_entry_exit_mode; - } - - report_prefix_pushf("%s %lx", fld_name, efer_saved); - test_efer_vmlaunch(fld, true); - report_prefix_pop(); - - /* - * Check reserved bits - */ - vmcs_write(ctrl_fld, ctrl_saved & ~ctrl_bit1); - for (i = 0; i < 64; i++) { - if ((1ull << i) & efer_reserved_bits) { - efer = efer_saved | (1ull << i); - vmcs_write(fld, efer); - report_prefix_pushf("%s %lx", fld_name, efer); - test_efer_vmlaunch(fld, true); - report_prefix_pop(); - } - } - - vmcs_write(ctrl_fld, ctrl_saved | ctrl_bit1); - for (i = 0; i < 64; i++) { - if ((1ull << i) & efer_reserved_bits) { - efer = efer_saved | (1ull << i); - vmcs_write(fld, efer); - report_prefix_pushf("%s %lx", fld_name, efer); - test_efer_vmlaunch(fld, false); - report_prefix_pop(); - } - } - - vmcs_write(ctrl_fld, ctrl_saved); - vmcs_write(fld, efer_saved); - - /* - * Check LMA and LME bits - */ - test_efer_bit(fld, fld_name, - ctrl_fld, ctrl_bit1, - EFER_LMA, - "EFER_LMA"); - test_efer_bit(fld, fld_name, - ctrl_fld, ctrl_bit1, - EFER_LME, - "EFER_LME"); - -test_entry_exit_mode: - test_efer_bit(fld, fld_name, - ctrl_fld, ctrl_bit2, - EFER_LMA, - "EFER_LMA"); - test_efer_bit(fld, fld_name, - ctrl_fld, ctrl_bit2, - EFER_LME, - "EFER_LME"); -} - -/* - * If the 'load IA32_EFER' VM-exit control is 1, bits reserved in the - * IA32_EFER MSR must be 0 in the field for that register. In addition, - * the values of the LMA and LME bits in the field must each be that of - * the 'host address-space size' VM-exit control. - * - * [Intel SDM] - */ -static void test_host_efer(void) -{ - test_efer(HOST_EFER, "HOST_EFER", EXI_CONTROLS, - ctrl_exit_rev.clr & EXI_LOAD_EFER, - EXI_HOST_64); -} - -/* - * If the 'load IA32_EFER' VM-enter control is 1, bits reserved in the - * IA32_EFER MSR must be 0 in the field for that register. In addition, - * the values of the LMA and LME bits in the field must each be that of - * the 'IA32e-mode guest' VM-exit control. - */ -static void test_guest_efer(void) -{ - if (!(ctrl_enter_rev.clr & ENT_LOAD_EFER)) { - printf("\"Load-IA32-EFER\" entry control not supported\n"); - return; - } - - vmcs_write(GUEST_EFER, rdmsr(MSR_EFER)); - test_efer(GUEST_EFER, "GUEST_EFER", ENT_CONTROLS, - ctrl_enter_rev.clr & ENT_LOAD_EFER, - ENT_GUEST_64); -} - -/* - * PAT values higher than 8 are uninteresting since they're likely lumped - * in with "8". We only test values above 8 one bit at a time, - * in order to reduce the number of VM-Entries and keep the runtime reasonable. - */ -#define PAT_VAL_LIMIT 8 - -static void test_pat(u32 field, const char * field_name, u32 ctrl_field, - u64 ctrl_bit) -{ - u32 ctrl_saved = vmcs_read(ctrl_field); - u64 pat_saved = vmcs_read(field); - u64 i, val; - u32 j; - int error; - - vmcs_clear_bits(ctrl_field, ctrl_bit); - - for (i = 0; i < 256; i = (i < PAT_VAL_LIMIT) ? i + 1 : i * 2) { - /* Test PAT0..PAT7 fields */ - for (j = 0; j < (i ? 8 : 1); j++) { - val = i << j * 8; - vmcs_write(field, val); - if (field == HOST_PAT) { - report_prefix_pushf("%s %lx", field_name, val); - test_vmx_vmlaunch(0); - report_prefix_pop(); - - } else { // GUEST_PAT - test_guest_state("ENT_LOAD_PAT enabled", false, - val, "GUEST_PAT"); - } - } - } - - vmcs_set_bits(ctrl_field, ctrl_bit); - for (i = 0; i < 256; i = (i < PAT_VAL_LIMIT) ? i + 1 : i * 2) { - /* Test PAT0..PAT7 fields */ - for (j = 0; j < (i ? 8 : 1); j++) { - val = i << j * 8; - vmcs_write(field, val); - - if (field == HOST_PAT) { - report_prefix_pushf("%s %lx", field_name, val); - if (i == 0x2 || i == 0x3 || i >= 0x8) - error = - VMXERR_ENTRY_INVALID_HOST_STATE_FIELD; - else - error = 0; - - test_vmx_vmlaunch(error); - report_prefix_pop(); - - } else { // GUEST_PAT - error = (i == 0x2 || i == 0x3 || i >= 0x8); - test_guest_state("ENT_LOAD_PAT enabled", !!error, - val, "GUEST_PAT"); - } - - } - } - - vmcs_write(ctrl_field, ctrl_saved); - vmcs_write(field, pat_saved); -} - -/* - * If the "load IA32_PAT" VM-exit control is 1, the value of the field - * for the IA32_PAT MSR must be one that could be written by WRMSR - * without fault at CPL 0. Specifically, each of the 8 bytes in the - * field must have one of the values 0 (UC), 1 (WC), 4 (WT), 5 (WP), - * 6 (WB), or 7 (UC-). - * - * [Intel SDM] - */ -static void test_load_host_pat(void) -{ - /* - * "load IA32_PAT" VM-exit control - */ - if (!(ctrl_exit_rev.clr & EXI_LOAD_PAT)) { - printf("\"Load-IA32-PAT\" exit control not supported\n"); - return; - } - - test_pat(HOST_PAT, "HOST_PAT", EXI_CONTROLS, EXI_LOAD_PAT); -} - -union cpuidA_eax { - struct { - unsigned int version_id:8; - unsigned int num_counters_gp:8; - unsigned int bit_width:8; - unsigned int mask_length:8; - } split; - unsigned int full; -}; - -union cpuidA_edx { - struct { - unsigned int num_counters_fixed:5; - unsigned int bit_width_fixed:8; - unsigned int reserved:9; - } split; - unsigned int full; -}; - -static bool valid_pgc(u64 val) -{ - struct cpuid id; - union cpuidA_eax eax; - union cpuidA_edx edx; - u64 mask; - - id = cpuid(0xA); - eax.full = id.a; - edx.full = id.d; - mask = ~(((1ull << eax.split.num_counters_gp) - 1) | - (((1ull << edx.split.num_counters_fixed) - 1) << 32)); - - return !(val & mask); -} - -static void test_pgc_vmlaunch(u32 xerror, u32 xreason, bool xfail, bool host) -{ - u32 inst_err; - u64 obs; - bool success; - struct vmx_state_area_test_data *data = &vmx_state_area_test_data; - - if (host) { - success = vmlaunch_succeeds(); - obs = rdmsr(data->msr); - if (!success) { - inst_err = vmcs_read(VMX_INST_ERROR); - report(xerror == inst_err, "vmlaunch failed, " - "VMX Inst Error is %d (expected %d)", - inst_err, xerror); - } else { - report(!data->enabled || data->exp == obs, - "Host state is 0x%lx (expected 0x%lx)", - obs, data->exp); - report(success != xfail, "vmlaunch succeeded"); - } - } else { - test_guest_state("load GUEST_PERF_GLOBAL_CTRL", xfail, - GUEST_PERF_GLOBAL_CTRL, - "GUEST_PERF_GLOBAL_CTRL"); - } -} - -/* - * test_load_perf_global_ctrl is a generic function for testing the - * "load IA32_PERF_GLOBAL_CTRL" VM-{Entry,Exit} controls. This test function - * tests the provided ctrl_val when disabled and enabled. - * - * @nr: VMCS field number corresponding to the host/guest state field - * @name: Name of the above VMCS field for printing in test report - * @ctrl_nr: VMCS field number corresponding to the VM-{Entry,Exit} control - * @ctrl_val: Bit to set on the ctrl_field - */ -static void test_perf_global_ctrl(u32 nr, const char *name, u32 ctrl_nr, - const char *ctrl_name, u64 ctrl_val) -{ - u64 ctrl_saved = vmcs_read(ctrl_nr); - u64 pgc_saved = vmcs_read(nr); - u64 i, val; - bool host = nr == HOST_PERF_GLOBAL_CTRL; - struct vmx_state_area_test_data *data = &vmx_state_area_test_data; - - data->msr = MSR_CORE_PERF_GLOBAL_CTRL; - msr_bmp_init(); - vmcs_write(ctrl_nr, ctrl_saved & ~ctrl_val); - data->enabled = false; - report_prefix_pushf("\"load IA32_PERF_GLOBAL_CTRL\"=0 on %s", - ctrl_name); - - for (i = 0; i < 64; i++) { - val = 1ull << i; - vmcs_write(nr, val); - report_prefix_pushf("%s = 0x%lx", name, val); - test_pgc_vmlaunch(0, VMX_VMCALL, false, host); - report_prefix_pop(); - } - report_prefix_pop(); - - vmcs_write(ctrl_nr, ctrl_saved | ctrl_val); - data->enabled = true; - report_prefix_pushf("\"load IA32_PERF_GLOBAL_CTRL\"=1 on %s", - ctrl_name); - for (i = 0; i < 64; i++) { - val = 1ull << i; - data->exp = val; - vmcs_write(nr, val); - report_prefix_pushf("%s = 0x%lx", name, val); - if (valid_pgc(val)) { - test_pgc_vmlaunch(0, VMX_VMCALL, false, host); - } else { - if (host) - test_pgc_vmlaunch( - VMXERR_ENTRY_INVALID_HOST_STATE_FIELD, - 0, - true, - host); - else - test_pgc_vmlaunch( - 0, - VMX_ENTRY_FAILURE | VMX_FAIL_STATE, - true, - host); - } - report_prefix_pop(); - } - - data->enabled = false; - report_prefix_pop(); - vmcs_write(ctrl_nr, ctrl_saved); - vmcs_write(nr, pgc_saved); -} - -static void test_load_host_perf_global_ctrl(void) -{ - if (!(ctrl_exit_rev.clr & EXI_LOAD_PERF)) { - printf("\"load IA32_PERF_GLOBAL_CTRL\" exit control not supported\n"); - return; - } - - test_perf_global_ctrl(HOST_PERF_GLOBAL_CTRL, "HOST_PERF_GLOBAL_CTRL", - EXI_CONTROLS, "EXI_CONTROLS", EXI_LOAD_PERF); -} - - -static void test_load_guest_perf_global_ctrl(void) -{ - if (!(ctrl_enter_rev.clr & ENT_LOAD_PERF)) { - printf("\"load IA32_PERF_GLOBAL_CTRL\" entry control not supported\n"); - return; - } - - test_perf_global_ctrl(GUEST_PERF_GLOBAL_CTRL, "GUEST_PERF_GLOBAL_CTRL", - ENT_CONTROLS, "ENT_CONTROLS", ENT_LOAD_PERF); -} - - -/* - * test_vmcs_field - test a value for the given VMCS field - * @field: VMCS field - * @field_name: string name of VMCS field - * @bit_start: starting bit - * @bit_end: ending bit - * @val: value that the bit range must or must not contain - * @valid_val: whether value given in 'val' must be valid or not - * @error: expected VMCS error when vmentry fails for an invalid value - */ -static void test_vmcs_field(u64 field, const char *field_name, u32 bit_start, - u32 bit_end, u64 val, bool valid_val, u32 error) -{ - u64 field_saved = vmcs_read(field); - u32 i; - u64 tmp; - u32 bit_on; - u64 mask = ~0ull; - - mask = (mask >> bit_end) << bit_end; - mask = mask | ((1 << bit_start) - 1); - tmp = (field_saved & mask) | (val << bit_start); - - vmcs_write(field, tmp); - report_prefix_pushf("%s %lx", field_name, tmp); - if (valid_val) - test_vmx_vmlaunch(0); - else - test_vmx_vmlaunch(error); - report_prefix_pop(); - - for (i = bit_start; i <= bit_end; i = i + 2) { - bit_on = ((1ull < i) & (val << bit_start)) ? 0 : 1; - if (bit_on) - tmp = field_saved | (1ull << i); - else - tmp = field_saved & ~(1ull << i); - vmcs_write(field, tmp); - report_prefix_pushf("%s %lx", field_name, tmp); - if (valid_val) - test_vmx_vmlaunch(error); - else - test_vmx_vmlaunch(0); - report_prefix_pop(); - } - - vmcs_write(field, field_saved); -} - -static void test_canonical(u64 field, const char * field_name, bool host) -{ - u64 addr_saved = vmcs_read(field); - - /* - * Use the existing value if possible. Writing a random canonical - * value is not an option as doing so would corrupt the field being - * tested and likely hose the test. - */ - if (is_canonical(addr_saved)) { - if (host) { - report_prefix_pushf("%s %lx", field_name, addr_saved); - test_vmx_vmlaunch(0); - report_prefix_pop(); - } else { - test_guest_state("Test canonical address", false, - addr_saved, field_name); - } - } - - vmcs_write(field, NONCANONICAL); - - if (host) { - report_prefix_pushf("%s %llx", field_name, NONCANONICAL); - test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); - report_prefix_pop(); - } else { - test_guest_state("Test non-canonical address", true, - NONCANONICAL, field_name); - } - - vmcs_write(field, addr_saved); -} - -#define TEST_RPL_TI_FLAGS(reg, name) \ - test_vmcs_field(reg, name, 0, 2, 0x0, true, \ - VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); - -#define TEST_CS_TR_FLAGS(reg, name) \ - test_vmcs_field(reg, name, 3, 15, 0x0000, false, \ - VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); - -/* - * 1. In the selector field for each of CS, SS, DS, ES, FS, GS and TR, the - * RPL (bits 1:0) and the TI flag (bit 2) must be 0. - * 2. The selector fields for CS and TR cannot be 0000H. - * 3. The selector field for SS cannot be 0000H if the "host address-space - * size" VM-exit control is 0. - * 4. On processors that support Intel 64 architecture, the base-address - * fields for FS, GS and TR must contain canonical addresses. - */ -static void test_host_segment_regs(void) -{ - u16 selector_saved; - - /* - * Test RPL and TI flags - */ - TEST_RPL_TI_FLAGS(HOST_SEL_CS, "HOST_SEL_CS"); - TEST_RPL_TI_FLAGS(HOST_SEL_SS, "HOST_SEL_SS"); - TEST_RPL_TI_FLAGS(HOST_SEL_DS, "HOST_SEL_DS"); - TEST_RPL_TI_FLAGS(HOST_SEL_ES, "HOST_SEL_ES"); - TEST_RPL_TI_FLAGS(HOST_SEL_FS, "HOST_SEL_FS"); - TEST_RPL_TI_FLAGS(HOST_SEL_GS, "HOST_SEL_GS"); - TEST_RPL_TI_FLAGS(HOST_SEL_TR, "HOST_SEL_TR"); - - /* - * Test that CS and TR fields can not be 0x0000 - */ - TEST_CS_TR_FLAGS(HOST_SEL_CS, "HOST_SEL_CS"); - TEST_CS_TR_FLAGS(HOST_SEL_TR, "HOST_SEL_TR"); - - /* - * SS field can not be 0x0000 if "host address-space size" VM-exit - * control is 0 - */ - selector_saved = vmcs_read(HOST_SEL_SS); - vmcs_write(HOST_SEL_SS, 0); - report_prefix_pushf("HOST_SEL_SS 0"); - if (vmcs_read(EXI_CONTROLS) & EXI_HOST_64) { - test_vmx_vmlaunch(0); - } else { - test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); - } - report_prefix_pop(); - - vmcs_write(HOST_SEL_SS, selector_saved); - - /* - * Base address for FS, GS and TR must be canonical - */ - test_canonical(HOST_BASE_FS, "HOST_BASE_FS", true); - test_canonical(HOST_BASE_GS, "HOST_BASE_GS", true); - test_canonical(HOST_BASE_TR, "HOST_BASE_TR", true); -} - -/* - * On processors that support Intel 64 architecture, the base-address - * fields for GDTR and IDTR must contain canonical addresses. - */ -static void test_host_desc_tables(void) -{ - test_canonical(HOST_BASE_GDTR, "HOST_BASE_GDTR", true); - test_canonical(HOST_BASE_IDTR, "HOST_BASE_IDTR", true); -} - -/* - * If the "host address-space size" VM-exit control is 0, the following must - * hold: - * - The "IA-32e mode guest" VM-entry control is 0. - * - Bit 17 of the CR4 field (corresponding to CR4.PCIDE) is 0. - * - Bits 63:32 in the RIP field are 0. - * - * If the "host address-space size" VM-exit control is 1, the following must - * hold: - * - Bit 5 of the CR4 field (corresponding to CR4.PAE) is 1. - * - The RIP field contains a canonical address. - * - */ -static void test_host_addr_size(void) -{ - u64 cr4_saved = vmcs_read(HOST_CR4); - u64 rip_saved = vmcs_read(HOST_RIP); - u64 entry_ctrl_saved = vmcs_read(ENT_CONTROLS); - int i; - u64 tmp; - - if (vmcs_read(EXI_CONTROLS) & EXI_HOST_64) { - vmcs_write(ENT_CONTROLS, entry_ctrl_saved | ENT_GUEST_64); - report_prefix_pushf("\"IA-32e mode guest\" enabled"); - test_vmx_vmlaunch(0); - report_prefix_pop(); - - vmcs_write(HOST_CR4, cr4_saved | X86_CR4_PCIDE); - report_prefix_pushf("\"CR4.PCIDE\" set"); - test_vmx_vmlaunch(0); - report_prefix_pop(); - - for (i = 32; i <= 63; i = i + 4) { - tmp = rip_saved | 1ull << i; - vmcs_write(HOST_RIP, tmp); - report_prefix_pushf("HOST_RIP %lx", tmp); - test_vmx_vmlaunch(0); - report_prefix_pop(); - } - - if (cr4_saved & X86_CR4_PAE) { - vmcs_write(HOST_CR4, cr4_saved & ~X86_CR4_PAE); - report_prefix_pushf("\"CR4.PAE\" unset"); - test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); - } else { - report_prefix_pushf("\"CR4.PAE\" set"); - test_vmx_vmlaunch(0); - } - report_prefix_pop(); - - vmcs_write(HOST_RIP, NONCANONICAL); - report_prefix_pushf("HOST_RIP %llx", NONCANONICAL); - test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); - report_prefix_pop(); - - vmcs_write(ENT_CONTROLS, entry_ctrl_saved | ENT_GUEST_64); - vmcs_write(HOST_RIP, rip_saved); - vmcs_write(HOST_CR4, cr4_saved); - } -} - -/* - * Check that the virtual CPU checks the VMX Host State Area as - * documented in the Intel SDM. - */ -static void vmx_host_state_area_test(void) -{ - /* - * Bit 1 of the guest's RFLAGS must be 1, or VM-entry will - * fail due to invalid guest state, should we make it that - * far. - */ - vmcs_write(GUEST_RFLAGS, 0); - - test_host_ctl_regs(); - - test_canonical(HOST_SYSENTER_ESP, "HOST_SYSENTER_ESP", true); - test_canonical(HOST_SYSENTER_EIP, "HOST_SYSENTER_EIP", true); - - test_host_efer(); - test_load_host_pat(); - test_host_segment_regs(); - test_host_desc_tables(); - test_host_addr_size(); - test_load_host_perf_global_ctrl(); -} - -/* - * If the "load debug controls" VM-entry control is 1, bits 63:32 in - * the DR7 field must be 0. - * - * [Intel SDM] - */ -static void test_guest_dr7(void) -{ - u32 ent_saved = vmcs_read(ENT_CONTROLS); - u64 dr7_saved = vmcs_read(GUEST_DR7); - u64 val; - int i; - - if (ctrl_enter_rev.set & ENT_LOAD_DBGCTLS) { - vmcs_clear_bits(ENT_CONTROLS, ENT_LOAD_DBGCTLS); - for (i = 0; i < 64; i++) { - val = 1ull << i; - vmcs_write(GUEST_DR7, val); - test_guest_state("ENT_LOAD_DBGCTLS disabled", false, - val, "GUEST_DR7"); - } - } - if (ctrl_enter_rev.clr & ENT_LOAD_DBGCTLS) { - vmcs_set_bits(ENT_CONTROLS, ENT_LOAD_DBGCTLS); - for (i = 0; i < 64; i++) { - val = 1ull << i; - vmcs_write(GUEST_DR7, val); - test_guest_state("ENT_LOAD_DBGCTLS enabled", i >= 32, - val, "GUEST_DR7"); - } - } - vmcs_write(GUEST_DR7, dr7_saved); - vmcs_write(ENT_CONTROLS, ent_saved); -} - -/* - * If the "load IA32_PAT" VM-entry control is 1, the value of the field - * for the IA32_PAT MSR must be one that could be written by WRMSR - * without fault at CPL 0. Specifically, each of the 8 bytes in the - * field must have one of the values 0 (UC), 1 (WC), 4 (WT), 5 (WP), - * 6 (WB), or 7 (UC-). - * - * [Intel SDM] - */ -static void test_load_guest_pat(void) -{ - /* - * "load IA32_PAT" VM-entry control - */ - if (!(ctrl_enter_rev.clr & ENT_LOAD_PAT)) { - printf("\"Load-IA32-PAT\" entry control not supported\n"); - return; - } - - test_pat(GUEST_PAT, "GUEST_PAT", ENT_CONTROLS, ENT_LOAD_PAT); -} - -#define MSR_IA32_BNDCFGS_RSVD_MASK 0x00000ffc - -/* - * If the “load IA32_BNDCFGS†VM-entry control is 1, the following - * checks are performed on the field for the IA32_BNDCFGS MSR: - * - * — Bits reserved in the IA32_BNDCFGS MSR must be 0. - * — The linear address in bits 63:12 must be canonical. - * - * [Intel SDM] - */ -static void test_load_guest_bndcfgs(void) -{ - u64 bndcfgs_saved = vmcs_read(GUEST_BNDCFGS); - u64 bndcfgs; - - if (!(ctrl_enter_rev.clr & ENT_LOAD_BNDCFGS)) { - printf("\"Load-IA32-BNDCFGS\" entry control not supported\n"); - return; - } - - vmcs_clear_bits(ENT_CONTROLS, ENT_LOAD_BNDCFGS); - - vmcs_write(GUEST_BNDCFGS, NONCANONICAL); - test_guest_state("ENT_LOAD_BNDCFGS disabled", false, - GUEST_BNDCFGS, "GUEST_BNDCFGS"); - bndcfgs = bndcfgs_saved | MSR_IA32_BNDCFGS_RSVD_MASK; - vmcs_write(GUEST_BNDCFGS, bndcfgs); - test_guest_state("ENT_LOAD_BNDCFGS disabled", false, - GUEST_BNDCFGS, "GUEST_BNDCFGS"); - - vmcs_set_bits(ENT_CONTROLS, ENT_LOAD_BNDCFGS); - - vmcs_write(GUEST_BNDCFGS, NONCANONICAL); - test_guest_state("ENT_LOAD_BNDCFGS enabled", true, - GUEST_BNDCFGS, "GUEST_BNDCFGS"); - bndcfgs = bndcfgs_saved | MSR_IA32_BNDCFGS_RSVD_MASK; - vmcs_write(GUEST_BNDCFGS, bndcfgs); - test_guest_state("ENT_LOAD_BNDCFGS enabled", true, - GUEST_BNDCFGS, "GUEST_BNDCFGS"); - - vmcs_write(GUEST_BNDCFGS, bndcfgs_saved); -} - -/* - * Check that the virtual CPU checks the VMX Guest State Area as - * documented in the Intel SDM. - */ -static void vmx_guest_state_area_test(void) -{ - vmx_set_test_stage(1); - test_set_guest(guest_state_test_main); - - /* - * The IA32_SYSENTER_ESP field and the IA32_SYSENTER_EIP field - * must each contain a canonical address. - */ - test_canonical(GUEST_SYSENTER_ESP, "GUEST_SYSENTER_ESP", false); - test_canonical(GUEST_SYSENTER_EIP, "GUEST_SYSENTER_EIP", false); - - test_guest_dr7(); - test_load_guest_pat(); - test_guest_efer(); - test_load_guest_perf_global_ctrl(); - test_load_guest_bndcfgs(); - - test_canonical(GUEST_BASE_GDTR, "GUEST_BASE_GDTR", false); - test_canonical(GUEST_BASE_IDTR, "GUEST_BASE_IDTR", false); - - u32 guest_desc_limit_saved = vmcs_read(GUEST_LIMIT_GDTR); - int i; - for (i = 16; i <= 31; i++) { - u32 tmp = guest_desc_limit_saved | (1ull << i); - vmcs_write(GUEST_LIMIT_GDTR, tmp); - test_guest_state("GUEST_LIMIT_GDTR", true, tmp, "GUEST_LIMIT_GDTR"); - } - vmcs_write(GUEST_LIMIT_GDTR, guest_desc_limit_saved); - - guest_desc_limit_saved = vmcs_read(GUEST_LIMIT_IDTR); - for (i = 16; i <= 31; i++) { - u32 tmp = guest_desc_limit_saved | (1ull << i); - vmcs_write(GUEST_LIMIT_IDTR, tmp); - test_guest_state("GUEST_LIMIT_IDTR", true, tmp, "GUEST_LIMIT_IDTR"); - } - vmcs_write(GUEST_LIMIT_IDTR, guest_desc_limit_saved); - - /* - * Let the guest finish execution - */ - vmx_set_test_stage(2); - enter_guest(); -} - -static bool valid_vmcs_for_vmentry(void) -{ - struct vmcs *current_vmcs = NULL; - - if (vmcs_save(¤t_vmcs)) - return false; - - return current_vmcs && !current_vmcs->hdr.shadow_vmcs; -} - -static void try_vmentry_in_movss_shadow(void) -{ - u32 vm_inst_err; - u32 flags; - bool early_failure = false; - u32 expected_flags = X86_EFLAGS_FIXED; - bool valid_vmcs = valid_vmcs_for_vmentry(); - - expected_flags |= valid_vmcs ? X86_EFLAGS_ZF : X86_EFLAGS_CF; - - /* - * Indirectly set VM_INST_ERR to 12 ("VMREAD/VMWRITE from/to - * unsupported VMCS component"). - */ - vmcs_write(~0u, 0); - - __asm__ __volatile__ ("mov %[host_rsp], %%edx;" - "vmwrite %%rsp, %%rdx;" - "mov 0f, %%rax;" - "mov %[host_rip], %%edx;" - "vmwrite %%rax, %%rdx;" - "mov $-1, %%ah;" - "sahf;" - "mov %%ss, %%ax;" - "mov %%ax, %%ss;" - "vmlaunch;" - "mov $1, %[early_failure];" - "0: lahf;" - "movzbl %%ah, %[flags]" - : [early_failure] "+r" (early_failure), - [flags] "=&a" (flags) - : [host_rsp] "i" (HOST_RSP), - [host_rip] "i" (HOST_RIP) - : "rdx", "cc", "memory"); - vm_inst_err = vmcs_read(VMX_INST_ERROR); - - report(early_failure, "Early VM-entry failure"); - report(flags == expected_flags, "RFLAGS[8:0] is %x (actual %x)", - expected_flags, flags); - if (valid_vmcs) - report(vm_inst_err == VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS, - "VM-instruction error is %d (actual %d)", - VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS, vm_inst_err); -} - -static void vmentry_movss_shadow_test(void) -{ - struct vmcs *orig_vmcs; - - TEST_ASSERT(!vmcs_save(&orig_vmcs)); - - /* - * Set the launched flag on the current VMCS to verify the correct - * error priority, below. - */ - test_set_guest(v2_null_test_guest); - enter_guest(); - - /* - * With bit 1 of the guest's RFLAGS clear, VM-entry should - * fail due to invalid guest state (if we make it that far). - */ - vmcs_write(GUEST_RFLAGS, 0); - - /* - * "VM entry with events blocked by MOV SS" takes precedence over - * "VMLAUNCH with non-clear VMCS." - */ - report_prefix_push("valid current-VMCS"); - try_vmentry_in_movss_shadow(); - report_prefix_pop(); - - /* - * VMfailInvalid takes precedence over "VM entry with events - * blocked by MOV SS." - */ - TEST_ASSERT(!vmcs_clear(orig_vmcs)); - report_prefix_push("no current-VMCS"); - try_vmentry_in_movss_shadow(); - report_prefix_pop(); - - TEST_ASSERT(!make_vmcs_current(orig_vmcs)); - vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED); -} - -static void vmx_cr_load_test(void) -{ - unsigned long cr3, cr4, orig_cr3, orig_cr4; - - orig_cr4 = read_cr4(); - orig_cr3 = read_cr3(); - - if (!this_cpu_has(X86_FEATURE_PCID)) { - report_skip("PCID not detected"); - return; - } - if (!this_cpu_has(X86_FEATURE_MCE)) { - report_skip("MCE not detected"); - return; - } - - TEST_ASSERT(!(orig_cr3 & X86_CR3_PCID_MASK)); - - /* Enable PCID for L1. */ - cr4 = orig_cr4 | X86_CR4_PCIDE; - cr3 = orig_cr3 | 0x1; - TEST_ASSERT(!write_cr4_checking(cr4)); - write_cr3(cr3); - - test_set_guest(v2_null_test_guest); - vmcs_write(HOST_CR4, cr4); - vmcs_write(HOST_CR3, cr3); - enter_guest(); - - /* - * No exception is expected. - * - * NB. KVM loads the last guest write to CR4 into CR4 read - * shadow. In order to trigger an exit to KVM, we can toggle a - * bit that is owned by KVM. We use CR4.MCE, which shall - * have no side effect because normally no guest MCE (e.g., as the - * result of bad memory) would happen during this test. - */ - TEST_ASSERT(!write_cr4_checking(cr4 ^ X86_CR4_MCE)); - - /* Cleanup L1 state. */ - write_cr3(orig_cr3); - TEST_ASSERT(!write_cr4_checking(orig_cr4)); -} - -static void vmx_nm_test_guest(void) -{ - write_cr0(read_cr0() | X86_CR0_TS); - asm volatile("fnop"); -} - -static void check_nm_exit(const char *test) -{ - u32 reason = vmcs_read(EXI_REASON); - u32 intr_info = vmcs_read(EXI_INTR_INFO); - const u32 expected = INTR_INFO_VALID_MASK | INTR_TYPE_HARD_EXCEPTION | - NM_VECTOR; - - report(reason == VMX_EXC_NMI && intr_info == expected, "%s", test); -} - -/* - * This test checks that: - * - * (a) If L2 launches with CR0.TS clear, but later sets CR0.TS, then - * a subsequent #NM VM-exit is reflected to L1. - * - * (b) If L2 launches with CR0.TS clear and CR0.EM set, then a - * subsequent #NM VM-exit is reflected to L1. - */ -static void vmx_nm_test(void) -{ - unsigned long cr0 = read_cr0(); - - test_set_guest(vmx_nm_test_guest); - - /* - * L1 wants to intercept #NM exceptions encountered in L2. - */ - vmcs_write(EXC_BITMAP, 1 << NM_VECTOR); - - /* - * Launch L2 with CR0.TS clear, but don't claim host ownership of - * any CR0 bits. L2 will set CR0.TS and then try to execute fnop, - * which will raise #NM. L0 should reflect the #NM VM-exit to L1. - */ - vmcs_write(CR0_MASK, 0); - vmcs_write(GUEST_CR0, cr0 & ~X86_CR0_TS); - enter_guest(); - check_nm_exit("fnop with CR0.TS set in L2 triggers #NM VM-exit to L1"); - - /* - * Re-enter L2 at the fnop instruction, with CR0.TS clear but - * CR0.EM set. The fnop will still raise #NM, and L0 should - * reflect the #NM VM-exit to L1. - */ - vmcs_write(GUEST_CR0, (cr0 & ~X86_CR0_TS) | X86_CR0_EM); - enter_guest(); - check_nm_exit("fnop with CR0.EM set in L2 triggers #NM VM-exit to L1"); - - /* - * Re-enter L2 at the fnop instruction, with both CR0.TS and - * CR0.EM clear. There will be no #NM, and the L2 guest should - * exit normally. - */ - vmcs_write(GUEST_CR0, cr0 & ~(X86_CR0_TS | X86_CR0_EM)); - enter_guest(); -} - -bool vmx_pending_event_ipi_fired; -static void vmx_pending_event_ipi_isr(isr_regs_t *regs) -{ - vmx_pending_event_ipi_fired = true; - eoi(); -} - -bool vmx_pending_event_guest_run; -static void vmx_pending_event_guest(void) -{ - vmcall(); - vmx_pending_event_guest_run = true; -} - -static void vmx_pending_event_test_core(bool guest_hlt) -{ - int ipi_vector = 0xf1; - - vmx_pending_event_ipi_fired = false; - handle_irq(ipi_vector, vmx_pending_event_ipi_isr); - - vmx_pending_event_guest_run = false; - test_set_guest(vmx_pending_event_guest); - - vmcs_set_bits(PIN_CONTROLS, PIN_EXTINT); - - enter_guest(); - skip_exit_vmcall(); - - if (guest_hlt) - vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); - - irq_disable(); - apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | - APIC_DM_FIXED | ipi_vector, - 0); - - enter_guest(); - - assert_exit_reason(VMX_EXTINT); - report(!vmx_pending_event_guest_run, - "Guest did not run before host received IPI"); - - irq_enable(); - asm volatile ("nop"); - irq_disable(); - report(vmx_pending_event_ipi_fired, - "Got pending interrupt after IRQ enabled"); - - if (guest_hlt) - vmcs_write(GUEST_ACTV_STATE, ACTV_ACTIVE); - - enter_guest(); - report(vmx_pending_event_guest_run, - "Guest finished running when no interrupt"); -} - -static void vmx_pending_event_test(void) -{ - vmx_pending_event_test_core(false); -} - -static void vmx_pending_event_hlt_test(void) -{ - vmx_pending_event_test_core(true); -} - -static int vmx_window_test_db_count; - -static void vmx_window_test_db_handler(struct ex_regs *regs) -{ - vmx_window_test_db_count++; -} - -static void vmx_nmi_window_test_guest(void) -{ - handle_exception(DB_VECTOR, vmx_window_test_db_handler); - - asm volatile("vmcall\n\t" - "nop\n\t"); - - handle_exception(DB_VECTOR, NULL); -} - -static void verify_nmi_window_exit(u64 rip) -{ - u32 exit_reason = vmcs_read(EXI_REASON); - - report(exit_reason == VMX_NMI_WINDOW, - "Exit reason (%d) is 'NMI window'", exit_reason); - report(vmcs_read(GUEST_RIP) == rip, "RIP (%#lx) is %#lx", - vmcs_read(GUEST_RIP), rip); - vmcs_write(GUEST_ACTV_STATE, ACTV_ACTIVE); -} - -static void vmx_nmi_window_test(void) -{ - u64 nop_addr; - void *db_fault_addr = get_idt_addr(&boot_idt[DB_VECTOR]); - - if (!(ctrl_pin_rev.clr & PIN_VIRT_NMI)) { - report_skip("CPU does not support the \"Virtual NMIs\" VM-execution control."); - return; - } - - if (!(ctrl_cpu_rev[0].clr & CPU_NMI_WINDOW)) { - report_skip("CPU does not support the \"NMI-window exiting\" VM-execution control."); - return; - } - - vmx_window_test_db_count = 0; - - report_prefix_push("NMI-window"); - test_set_guest(vmx_nmi_window_test_guest); - vmcs_set_bits(PIN_CONTROLS, PIN_VIRT_NMI); - enter_guest(); - skip_exit_vmcall(); - nop_addr = vmcs_read(GUEST_RIP); - - /* - * Ask for "NMI-window exiting," and expect an immediate VM-exit. - * RIP will not advance. - */ - report_prefix_push("active, no blocking"); - vmcs_set_bits(CPU_EXEC_CTRL0, CPU_NMI_WINDOW); - enter_guest(); - verify_nmi_window_exit(nop_addr); - report_prefix_pop(); - - /* - * Ask for "NMI-window exiting" in a MOV-SS shadow, and expect - * a VM-exit on the next instruction after the nop. (The nop - * is one byte.) - */ - report_prefix_push("active, blocking by MOV-SS"); - vmcs_write(GUEST_INTR_STATE, GUEST_INTR_STATE_MOVSS); - enter_guest(); - verify_nmi_window_exit(nop_addr + 1); - report_prefix_pop(); - - /* - * Ask for "NMI-window exiting" (with event injection), and - * expect a VM-exit after the event is injected. (RIP should - * be at the address specified in the IDT entry for #DB.) - */ - report_prefix_push("active, no blocking, injecting #DB"); - vmcs_write(ENT_INTR_INFO, - INTR_INFO_VALID_MASK | INTR_TYPE_HARD_EXCEPTION | DB_VECTOR); - enter_guest(); - verify_nmi_window_exit((u64)db_fault_addr); - report_prefix_pop(); - - /* - * Ask for "NMI-window exiting" with NMI blocking, and expect - * a VM-exit after the next IRET (i.e. after the #DB handler - * returns). So, RIP should be back at one byte past the nop. - */ - report_prefix_push("active, blocking by NMI"); - vmcs_write(GUEST_INTR_STATE, GUEST_INTR_STATE_NMI); - enter_guest(); - verify_nmi_window_exit(nop_addr + 1); - report(vmx_window_test_db_count == 1, - "#DB handler executed once (actual %d times)", - vmx_window_test_db_count); - report_prefix_pop(); - - if (!(rdmsr(MSR_IA32_VMX_MISC) & (1 << 6))) { - report_skip("CPU does not support activity state HLT."); - } else { - /* - * Ask for "NMI-window exiting" when entering activity - * state HLT, and expect an immediate VM-exit. RIP is - * still one byte past the nop. - */ - report_prefix_push("halted, no blocking"); - vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); - enter_guest(); - verify_nmi_window_exit(nop_addr + 1); - report_prefix_pop(); - - /* - * Ask for "NMI-window exiting" when entering activity - * state HLT (with event injection), and expect a - * VM-exit after the event is injected. (RIP should be - * at the address specified in the IDT entry for #DB.) - */ - report_prefix_push("halted, no blocking, injecting #DB"); - vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); - vmcs_write(ENT_INTR_INFO, - INTR_INFO_VALID_MASK | INTR_TYPE_HARD_EXCEPTION | - DB_VECTOR); - enter_guest(); - verify_nmi_window_exit((u64)db_fault_addr); - report_prefix_pop(); - } - - vmcs_clear_bits(CPU_EXEC_CTRL0, CPU_NMI_WINDOW); - enter_guest(); - report_prefix_pop(); -} - -static void vmx_intr_window_test_guest(void) -{ - handle_exception(DB_VECTOR, vmx_window_test_db_handler); - - /* - * The two consecutive STIs are to ensure that only the first - * one has a shadow. Note that NOP and STI are one byte - * instructions. - */ - asm volatile("vmcall\n\t" - "nop\n\t" - "sti\n\t" - "sti\n\t"); - - handle_exception(DB_VECTOR, NULL); -} - -static void verify_intr_window_exit(u64 rip) -{ - u32 exit_reason = vmcs_read(EXI_REASON); - - report(exit_reason == VMX_INTR_WINDOW, - "Exit reason (%d) is 'interrupt window'", exit_reason); - report(vmcs_read(GUEST_RIP) == rip, "RIP (%#lx) is %#lx", - vmcs_read(GUEST_RIP), rip); - vmcs_write(GUEST_ACTV_STATE, ACTV_ACTIVE); -} - -static void vmx_intr_window_test(void) -{ - u64 vmcall_addr; - u64 nop_addr; - unsigned int orig_db_gate_type; - void *db_fault_addr = get_idt_addr(&boot_idt[DB_VECTOR]); - - if (!(ctrl_cpu_rev[0].clr & CPU_INTR_WINDOW)) { - report_skip("CPU does not support the \"interrupt-window exiting\" VM-execution control."); - return; - } - - /* - * Change the IDT entry for #DB from interrupt gate to trap gate, - * so that it won't clear RFLAGS.IF. We don't want interrupts to - * be disabled after vectoring a #DB. - */ - orig_db_gate_type = boot_idt[DB_VECTOR].type; - boot_idt[DB_VECTOR].type = 15; - - report_prefix_push("interrupt-window"); - test_set_guest(vmx_intr_window_test_guest); - enter_guest(); - assert_exit_reason(VMX_VMCALL); - vmcall_addr = vmcs_read(GUEST_RIP); - - /* - * Ask for "interrupt-window exiting" with RFLAGS.IF set and - * no blocking; expect an immediate VM-exit. Note that we have - * not advanced past the vmcall instruction yet, so RIP should - * point to the vmcall instruction. - */ - report_prefix_push("active, no blocking, RFLAGS.IF=1"); - vmcs_set_bits(CPU_EXEC_CTRL0, CPU_INTR_WINDOW); - vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED | X86_EFLAGS_IF); - enter_guest(); - verify_intr_window_exit(vmcall_addr); - report_prefix_pop(); - - /* - * Ask for "interrupt-window exiting" (with event injection) - * with RFLAGS.IF set and no blocking; expect a VM-exit after - * the event is injected. That is, RIP should should be at the - * address specified in the IDT entry for #DB. - */ - report_prefix_push("active, no blocking, RFLAGS.IF=1, injecting #DB"); - vmcs_write(ENT_INTR_INFO, - INTR_INFO_VALID_MASK | INTR_TYPE_HARD_EXCEPTION | DB_VECTOR); - vmcall_addr = vmcs_read(GUEST_RIP); - enter_guest(); - verify_intr_window_exit((u64)db_fault_addr); - report_prefix_pop(); - - /* - * Let the L2 guest run through the IRET, back to the VMCALL. - * We have to clear the "interrupt-window exiting" - * VM-execution control, or it would just keep causing - * VM-exits. Then, advance past the VMCALL and set the - * "interrupt-window exiting" VM-execution control again. - */ - vmcs_clear_bits(CPU_EXEC_CTRL0, CPU_INTR_WINDOW); - enter_guest(); - skip_exit_vmcall(); - nop_addr = vmcs_read(GUEST_RIP); - vmcs_set_bits(CPU_EXEC_CTRL0, CPU_INTR_WINDOW); - - /* - * Ask for "interrupt-window exiting" in a MOV-SS shadow with - * RFLAGS.IF set, and expect a VM-exit on the next - * instruction. (NOP is one byte.) - */ - report_prefix_push("active, blocking by MOV-SS, RFLAGS.IF=1"); - vmcs_write(GUEST_INTR_STATE, GUEST_INTR_STATE_MOVSS); - enter_guest(); - verify_intr_window_exit(nop_addr + 1); - report_prefix_pop(); - - /* - * Back up to the NOP and ask for "interrupt-window exiting" - * in an STI shadow with RFLAGS.IF set, and expect a VM-exit - * on the next instruction. (NOP is one byte.) - */ - report_prefix_push("active, blocking by STI, RFLAGS.IF=1"); - vmcs_write(GUEST_RIP, nop_addr); - vmcs_write(GUEST_INTR_STATE, GUEST_INTR_STATE_STI); - enter_guest(); - verify_intr_window_exit(nop_addr + 1); - report_prefix_pop(); - - /* - * Ask for "interrupt-window exiting" with RFLAGS.IF clear, - * and expect a VM-exit on the instruction following the STI - * shadow. Only the first STI (which is one byte past the NOP) - * should have a shadow. The second STI (which is two bytes - * past the NOP) has no shadow. Therefore, the interrupt - * window opens at three bytes past the NOP. - */ - report_prefix_push("active, RFLAGS.IF = 0"); - vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED); - enter_guest(); - verify_intr_window_exit(nop_addr + 3); - report_prefix_pop(); - - if (!(rdmsr(MSR_IA32_VMX_MISC) & (1 << 6))) { - report_skip("CPU does not support activity state HLT."); - } else { - /* - * Ask for "interrupt-window exiting" when entering - * activity state HLT, and expect an immediate - * VM-exit. RIP is still three bytes past the nop. - */ - report_prefix_push("halted, no blocking"); - vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); - enter_guest(); - verify_intr_window_exit(nop_addr + 3); - report_prefix_pop(); - - /* - * Ask for "interrupt-window exiting" when entering - * activity state HLT (with event injection), and - * expect a VM-exit after the event is injected. That - * is, RIP should should be at the address specified - * in the IDT entry for #DB. - */ - report_prefix_push("halted, no blocking, injecting #DB"); - vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); - vmcs_write(ENT_INTR_INFO, - INTR_INFO_VALID_MASK | INTR_TYPE_HARD_EXCEPTION | - DB_VECTOR); - enter_guest(); - verify_intr_window_exit((u64)db_fault_addr); - report_prefix_pop(); - } - - boot_idt[DB_VECTOR].type = orig_db_gate_type; - vmcs_clear_bits(CPU_EXEC_CTRL0, CPU_INTR_WINDOW); - enter_guest(); - report_prefix_pop(); -} - -#define GUEST_TSC_OFFSET (1u << 30) - -static u64 guest_tsc; - -static void vmx_store_tsc_test_guest(void) -{ - guest_tsc = rdtsc(); -} - -/* - * This test ensures that when IA32_TSC is in the VM-exit MSR-store - * list, the value saved is not subject to the TSC offset that is - * applied to RDTSC/RDTSCP/RDMSR(IA32_TSC) in guest execution. - */ -static void vmx_store_tsc_test(void) -{ - struct vmx_msr_entry msr_entry = { .index = MSR_IA32_TSC }; - u64 low, high; - - if (!(ctrl_cpu_rev[0].clr & CPU_USE_TSC_OFFSET)) { - report_skip("'Use TSC offsetting' not supported"); - return; - } - - test_set_guest(vmx_store_tsc_test_guest); - - vmcs_set_bits(CPU_EXEC_CTRL0, CPU_USE_TSC_OFFSET); - vmcs_write(EXI_MSR_ST_CNT, 1); - vmcs_write(EXIT_MSR_ST_ADDR, virt_to_phys(&msr_entry)); - vmcs_write(TSC_OFFSET, GUEST_TSC_OFFSET); - - low = rdtsc(); - enter_guest(); - high = rdtsc(); - - report(low + GUEST_TSC_OFFSET <= guest_tsc && - guest_tsc <= high + GUEST_TSC_OFFSET, - "RDTSC value in the guest (%lu) is in range [%lu, %lu]", - guest_tsc, low + GUEST_TSC_OFFSET, high + GUEST_TSC_OFFSET); - report(low <= msr_entry.value && msr_entry.value <= high, - "IA32_TSC value saved in the VM-exit MSR-store list (%lu) is in range [%lu, %lu]", - msr_entry.value, low, high); -} - -static void vmx_preemption_timer_zero_test_db_handler(struct ex_regs *regs) -{ -} - -static void vmx_preemption_timer_zero_test_guest(void) -{ - while (vmx_get_test_stage() < 3) - vmcall(); -} - -static void vmx_preemption_timer_zero_activate_preemption_timer(void) -{ - vmcs_set_bits(PIN_CONTROLS, PIN_PREEMPT); - vmcs_write(PREEMPT_TIMER_VALUE, 0); -} - -static void vmx_preemption_timer_zero_advance_past_vmcall(void) -{ - vmcs_clear_bits(PIN_CONTROLS, PIN_PREEMPT); - enter_guest(); - skip_exit_vmcall(); -} - -static void vmx_preemption_timer_zero_inject_db(bool intercept_db) -{ - vmx_preemption_timer_zero_activate_preemption_timer(); - vmcs_write(ENT_INTR_INFO, INTR_INFO_VALID_MASK | - INTR_TYPE_HARD_EXCEPTION | DB_VECTOR); - vmcs_write(EXC_BITMAP, intercept_db ? 1 << DB_VECTOR : 0); - enter_guest(); -} - -static void vmx_preemption_timer_zero_set_pending_dbg(u32 exception_bitmap) -{ - vmx_preemption_timer_zero_activate_preemption_timer(); - vmcs_write(GUEST_PENDING_DEBUG, BIT(12) | DR_TRAP1); - vmcs_write(EXC_BITMAP, exception_bitmap); - enter_guest(); -} - -static void vmx_preemption_timer_zero_expect_preempt_at_rip(u64 expected_rip) -{ - u32 reason = (u32)vmcs_read(EXI_REASON); - u64 guest_rip = vmcs_read(GUEST_RIP); - - report(reason == VMX_PREEMPT && guest_rip == expected_rip, - "Exit reason is 0x%x (expected 0x%x) and guest RIP is %lx (0x%lx expected).", - reason, VMX_PREEMPT, guest_rip, expected_rip); -} - -/* - * This test ensures that when the VMX preemption timer is zero at - * VM-entry, a VM-exit occurs after any event injection and after any - * pending debug exceptions are raised, but before execution of any - * guest instructions. - */ -static void vmx_preemption_timer_zero_test(void) -{ - u64 db_fault_address = (u64)get_idt_addr(&boot_idt[DB_VECTOR]); - handler old_db; - u32 reason; - - if (!(ctrl_pin_rev.clr & PIN_PREEMPT)) { - report_skip("'Activate VMX-preemption timer' not supported"); - return; - } - - /* - * Install a custom #DB handler that doesn't abort. - */ - old_db = handle_exception(DB_VECTOR, - vmx_preemption_timer_zero_test_db_handler); - - test_set_guest(vmx_preemption_timer_zero_test_guest); - - /* - * VMX-preemption timer should fire after event injection. - */ - vmx_set_test_stage(0); - vmx_preemption_timer_zero_inject_db(0); - vmx_preemption_timer_zero_expect_preempt_at_rip(db_fault_address); - vmx_preemption_timer_zero_advance_past_vmcall(); - - /* - * VMX-preemption timer should fire after event injection. - * Exception bitmap is irrelevant, since you can't intercept - * an event that you injected. - */ - vmx_set_test_stage(1); - vmx_preemption_timer_zero_inject_db(true); - vmx_preemption_timer_zero_expect_preempt_at_rip(db_fault_address); - vmx_preemption_timer_zero_advance_past_vmcall(); - - /* - * VMX-preemption timer should fire after pending debug exceptions - * have delivered a #DB trap. - */ - vmx_set_test_stage(2); - vmx_preemption_timer_zero_set_pending_dbg(0); - vmx_preemption_timer_zero_expect_preempt_at_rip(db_fault_address); - vmx_preemption_timer_zero_advance_past_vmcall(); - - /* - * VMX-preemption timer would fire after pending debug exceptions - * have delivered a #DB trap, but in this case, the #DB trap is - * intercepted. - */ - vmx_set_test_stage(3); - vmx_preemption_timer_zero_set_pending_dbg(1 << DB_VECTOR); - reason = (u32)vmcs_read(EXI_REASON); - report(reason == VMX_EXC_NMI, "Exit reason is 0x%x (expected 0x%x)", - reason, VMX_EXC_NMI); - - vmcs_clear_bits(PIN_CONTROLS, PIN_PREEMPT); - enter_guest(); - - handle_exception(DB_VECTOR, old_db); -} - -static u64 vmx_preemption_timer_tf_test_prev_rip; - -static void vmx_preemption_timer_tf_test_db_handler(struct ex_regs *regs) -{ - extern char vmx_preemption_timer_tf_test_endloop; - - if (vmx_get_test_stage() == 2) { - /* - * Stage 2 means that we're done, one way or another. - * Arrange for the iret to drop us out of the wbinvd - * loop and stop single-stepping. - */ - regs->rip = (u64)&vmx_preemption_timer_tf_test_endloop; - regs->rflags &= ~X86_EFLAGS_TF; - } else if (regs->rip == vmx_preemption_timer_tf_test_prev_rip) { - /* - * The RIP should alternate between the wbinvd and the - * jmp instruction in the code below. If we ever see - * the same instruction twice in a row, that means a - * single-step trap has been dropped. Let the - * hypervisor know about the failure by executing a - * VMCALL. - */ - vmcall(); - } - vmx_preemption_timer_tf_test_prev_rip = regs->rip; -} - -static void vmx_preemption_timer_tf_test_guest(void) -{ - /* - * The hypervisor doesn't intercept WBINVD, so the loop below - * shouldn't be a problem--it's just two instructions - * executing in VMX non-root mode. However, when the - * hypervisor is running in a virtual environment, the parent - * hypervisor might intercept WBINVD and emulate it. If the - * parent hypervisor is broken, the single-step trap after the - * WBINVD might be lost. - */ - asm volatile("vmcall\n\t" - "0: wbinvd\n\t" - "1: jmp 0b\n\t" - "vmx_preemption_timer_tf_test_endloop:"); -} - -/* - * Ensure that the delivery of a "VMX-preemption timer expired" - * VM-exit doesn't disrupt single-stepping in the guest. Note that - * passing this test doesn't ensure correctness, because the test will - * only fail if the VMX-preemtion timer fires at the right time (or - * the wrong time, as it were). - */ -static void vmx_preemption_timer_tf_test(void) -{ - handler old_db; - u32 reason; - int i; - - if (!(ctrl_pin_rev.clr & PIN_PREEMPT)) { - report_skip("'Activate VMX-preemption timer' not supported"); - return; - } - - old_db = handle_exception(DB_VECTOR, - vmx_preemption_timer_tf_test_db_handler); - - test_set_guest(vmx_preemption_timer_tf_test_guest); - - enter_guest(); - skip_exit_vmcall(); - - vmx_set_test_stage(1); - vmcs_set_bits(PIN_CONTROLS, PIN_PREEMPT); - vmcs_write(PREEMPT_TIMER_VALUE, 50000); - vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED | X86_EFLAGS_TF); - - /* - * The only exit we should see is "VMX-preemption timer - * expired." If we get a VMCALL exit, that means the #DB - * handler has detected a missing single-step trap. It doesn't - * matter where the guest RIP is when the VMX-preemption timer - * expires (whether it's in the WBINVD loop or in the #DB - * handler)--a single-step trap should never be discarded. - */ - for (i = 0; i < 10000; i++) { - enter_guest(); - reason = (u32)vmcs_read(EXI_REASON); - if (reason == VMX_PREEMPT) - continue; - TEST_ASSERT(reason == VMX_VMCALL); - skip_exit_insn(); - break; - } - - report(reason == VMX_PREEMPT, "No single-step traps skipped"); - - vmx_set_test_stage(2); - vmcs_clear_bits(PIN_CONTROLS, PIN_PREEMPT); - enter_guest(); - - handle_exception(DB_VECTOR, old_db); -} - -#define VMX_PREEMPTION_TIMER_EXPIRY_CYCLES 1000000 - -static u64 vmx_preemption_timer_expiry_start; -static u64 vmx_preemption_timer_expiry_finish; - -static void vmx_preemption_timer_expiry_test_guest(void) -{ - vmcall(); - vmx_preemption_timer_expiry_start = fenced_rdtsc(); - - while (vmx_get_test_stage() == 0) - vmx_preemption_timer_expiry_finish = fenced_rdtsc(); -} - -/* - * Test that the VMX-preemption timer is not excessively delayed. - * - * Per the SDM, volume 3, VM-entry starts the VMX-preemption timer - * with the unsigned value in the VMX-preemption timer-value field, - * and the VMX-preemption timer counts down by 1 every time bit X in - * the TSC changes due to a TSC increment (where X is - * IA32_VMX_MISC[4:0]). If the timer counts down to zero in any state - * other than the wait-for-SIPI state, the logical processor - * transitions to the C0 C-state and causes a VM-exit. - * - * The guest code above reads the starting TSC after VM-entry. At this - * point, the VMX-preemption timer has already been activated. Next, - * the guest code reads the current TSC in a loop, storing the value - * read to memory. - * - * If the RDTSC in the loop reads a value past the VMX-preemption - * timer deadline, then the VMX-preemption timer VM-exit must be - * delivered before the next instruction retires. Even if a higher - * priority SMI is delivered first, the VMX-preemption timer VM-exit - * must be delivered before the next instruction retires. Hence, a TSC - * value past the VMX-preemption timer deadline might be read, but it - * cannot be stored. If a TSC value past the deadline *is* stored, - * then the architectural specification has been violated. - */ -static void vmx_preemption_timer_expiry_test(void) -{ - u32 preemption_timer_value; - union vmx_misc misc; - u64 tsc_deadline; - u32 reason; - - if (!(ctrl_pin_rev.clr & PIN_PREEMPT)) { - report_skip("'Activate VMX-preemption timer' not supported"); - return; - } - - test_set_guest(vmx_preemption_timer_expiry_test_guest); - - enter_guest(); - skip_exit_vmcall(); - - misc.val = rdmsr(MSR_IA32_VMX_MISC); - preemption_timer_value = - VMX_PREEMPTION_TIMER_EXPIRY_CYCLES >> misc.pt_bit; - - vmcs_set_bits(PIN_CONTROLS, PIN_PREEMPT); - vmcs_write(PREEMPT_TIMER_VALUE, preemption_timer_value); - vmx_set_test_stage(0); - - enter_guest(); - reason = (u32)vmcs_read(EXI_REASON); - TEST_ASSERT(reason == VMX_PREEMPT); - - vmcs_clear_bits(PIN_CONTROLS, PIN_PREEMPT); - vmx_set_test_stage(1); - enter_guest(); - - tsc_deadline = ((vmx_preemption_timer_expiry_start >> misc.pt_bit) << - misc.pt_bit) + (preemption_timer_value << misc.pt_bit); - - report(vmx_preemption_timer_expiry_finish < tsc_deadline, - "Last stored guest TSC (%lu) < TSC deadline (%lu)", - vmx_preemption_timer_expiry_finish, tsc_deadline); -} - -static void vmx_db_test_guest(void) -{ - /* - * For a hardware generated single-step #DB. - */ - asm volatile("vmcall;" - "nop;" - ".Lpost_nop:"); - /* - * ...in a MOVSS shadow, with pending debug exceptions. - */ - asm volatile("vmcall;" - "nop;" - ".Lpost_movss_nop:"); - /* - * For an L0 synthesized single-step #DB. (L0 intercepts WBINVD and - * emulates it in software.) - */ - asm volatile("vmcall;" - "wbinvd;" - ".Lpost_wbinvd:"); - /* - * ...in a MOVSS shadow, with pending debug exceptions. - */ - asm volatile("vmcall;" - "wbinvd;" - ".Lpost_movss_wbinvd:"); - /* - * For a hardware generated single-step #DB in a transactional region. - */ - asm volatile("vmcall;" - ".Lxbegin: xbegin .Lskip_rtm;" - "xend;" - ".Lskip_rtm:"); -} - -/* - * Clear the pending debug exceptions and RFLAGS.TF and re-enter - * L2. No #DB is delivered and L2 continues to the next point of - * interest. - */ -static void dismiss_db(void) -{ - vmcs_write(GUEST_PENDING_DEBUG, 0); - vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED); - enter_guest(); -} - -/* - * Check a variety of VMCS fields relevant to an intercepted #DB exception. - * Then throw away the #DB exception and resume L2. - */ -static void check_db_exit(bool xfail_qual, bool xfail_dr6, bool xfail_pdbg, - void *expected_rip, u64 expected_exit_qual, - u64 expected_dr6) -{ - u32 reason = vmcs_read(EXI_REASON); - u32 intr_info = vmcs_read(EXI_INTR_INFO); - u64 exit_qual = vmcs_read(EXI_QUALIFICATION); - u64 guest_rip = vmcs_read(GUEST_RIP); - u64 guest_pending_dbg = vmcs_read(GUEST_PENDING_DEBUG); - u64 dr6 = read_dr6(); - const u32 expected_intr_info = INTR_INFO_VALID_MASK | - INTR_TYPE_HARD_EXCEPTION | DB_VECTOR; - - report(reason == VMX_EXC_NMI && intr_info == expected_intr_info, - "Expected #DB VM-exit"); - report((u64)expected_rip == guest_rip, "Expected RIP %p (actual %lx)", - expected_rip, guest_rip); - report_xfail(xfail_pdbg, 0 == guest_pending_dbg, - "Expected pending debug exceptions 0 (actual %lx)", - guest_pending_dbg); - report_xfail(xfail_qual, expected_exit_qual == exit_qual, - "Expected exit qualification %lx (actual %lx)", - expected_exit_qual, exit_qual); - report_xfail(xfail_dr6, expected_dr6 == dr6, - "Expected DR6 %lx (actual %lx)", expected_dr6, dr6); - dismiss_db(); -} - -/* - * Assuming the guest has just exited on a VMCALL instruction, skip - * over the vmcall, and set the guest's RFLAGS.TF in the VMCS. If - * pending debug exceptions are non-zero, set the VMCS up as if the - * previous instruction was a MOVSS that generated the indicated - * pending debug exceptions. Then enter L2. - */ -static void single_step_guest(const char *test_name, u64 starting_dr6, - u64 pending_debug_exceptions) -{ - printf("\n%s\n", test_name); - skip_exit_vmcall(); - write_dr6(starting_dr6); - vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED | X86_EFLAGS_TF); - if (pending_debug_exceptions) { - vmcs_write(GUEST_PENDING_DEBUG, pending_debug_exceptions); - vmcs_write(GUEST_INTR_STATE, GUEST_INTR_STATE_MOVSS); - } - enter_guest(); -} - -/* - * When L1 intercepts #DB, verify that a single-step trap clears - * pending debug exceptions, populates the exit qualification field - * properly, and that DR6 is not prematurely clobbered. In a - * (simulated) MOVSS shadow, make sure that the pending debug - * exception bits are properly accumulated into the exit qualification - * field. - */ -static void vmx_db_test(void) -{ - /* - * We are going to set a few arbitrary bits in DR6 to verify that - * (a) DR6 is not modified by an intercepted #DB, and - * (b) stale bits in DR6 (DR6.BD, in particular) don't leak into - * the exit qualification field for a subsequent #DB exception. - */ - const u64 starting_dr6 = DR6_RESERVED | BIT(13) | DR_TRAP3 | DR_TRAP1; - extern char post_nop asm(".Lpost_nop"); - extern char post_movss_nop asm(".Lpost_movss_nop"); - extern char post_wbinvd asm(".Lpost_wbinvd"); - extern char post_movss_wbinvd asm(".Lpost_movss_wbinvd"); - extern char xbegin asm(".Lxbegin"); - extern char skip_rtm asm(".Lskip_rtm"); - - /* - * L1 wants to intercept #DB exceptions encountered in L2. - */ - vmcs_write(EXC_BITMAP, BIT(DB_VECTOR)); - - /* - * Start L2 and run it up to the first point of interest. - */ - test_set_guest(vmx_db_test_guest); - enter_guest(); - - /* - * Hardware-delivered #DB trap for single-step sets the - * standard that L0 has to follow for emulated instructions. - */ - single_step_guest("Hardware delivered single-step", starting_dr6, 0); - check_db_exit(false, false, false, &post_nop, DR_STEP, starting_dr6); - - /* - * Hardware-delivered #DB trap for single-step in MOVSS shadow - * also sets the standard that L0 has to follow for emulated - * instructions. Here, we establish the VMCS pending debug - * exceptions to indicate that the simulated MOVSS triggered a - * data breakpoint as well as the single-step trap. - */ - single_step_guest("Hardware delivered single-step in MOVSS shadow", - starting_dr6, BIT(12) | DR_STEP | DR_TRAP0 ); - check_db_exit(false, false, false, &post_movss_nop, DR_STEP | DR_TRAP0, - starting_dr6); - - /* - * L0 synthesized #DB trap for single-step is buggy, because - * kvm (a) clobbers DR6 too early, and (b) tries its best to - * reconstitute the exit qualification from the prematurely - * modified DR6, but fails miserably. - */ - single_step_guest("Software synthesized single-step", starting_dr6, 0); - check_db_exit(false, false, false, &post_wbinvd, DR_STEP, starting_dr6); - - /* - * L0 synthesized #DB trap for single-step in MOVSS shadow is - * even worse, because L0 also leaves the pending debug - * exceptions in the VMCS instead of accumulating them into - * the exit qualification field for the #DB exception. - */ - single_step_guest("Software synthesized single-step in MOVSS shadow", - starting_dr6, BIT(12) | DR_STEP | DR_TRAP0); - check_db_exit(true, false, true, &post_movss_wbinvd, DR_STEP | DR_TRAP0, - starting_dr6); - - /* - * Optional RTM test for hardware that supports RTM, to - * demonstrate that the current volume 3 of the SDM - * (325384-067US), table 27-1 is incorrect. Bit 16 of the exit - * qualification for debug exceptions is not reserved. It is - * set to 1 if a debug exception (#DB) or a breakpoint - * exception (#BP) occurs inside an RTM region while advanced - * debugging of RTM transactional regions is enabled. - */ - if (this_cpu_has(X86_FEATURE_RTM)) { - vmcs_write(ENT_CONTROLS, - vmcs_read(ENT_CONTROLS) | ENT_LOAD_DBGCTLS); - /* - * Set DR7.RTM[bit 11] and IA32_DEBUGCTL.RTM[bit 15] - * in the guest to enable advanced debugging of RTM - * transactional regions. - */ - vmcs_write(GUEST_DR7, BIT(11)); - vmcs_write(GUEST_DEBUGCTL, BIT(15)); - single_step_guest("Hardware delivered single-step in " - "transactional region", starting_dr6, 0); - check_db_exit(false, false, false, &xbegin, BIT(16), - starting_dr6); - } else { - vmcs_write(GUEST_RIP, (u64)&skip_rtm); - enter_guest(); - } -} - -static void enable_vid(void) -{ - void *virtual_apic_page; - - assert(cpu_has_apicv()); - - disable_intercept_for_x2apic_msrs(); - - virtual_apic_page = alloc_page(); - vmcs_write(APIC_VIRT_ADDR, (u64)virtual_apic_page); - - vmcs_set_bits(PIN_CONTROLS, PIN_EXTINT); - - vmcs_write(EOI_EXIT_BITMAP0, 0x0); - vmcs_write(EOI_EXIT_BITMAP1, 0x0); - vmcs_write(EOI_EXIT_BITMAP2, 0x0); - vmcs_write(EOI_EXIT_BITMAP3, 0x0); - - vmcs_set_bits(CPU_EXEC_CTRL0, CPU_SECONDARY | CPU_TPR_SHADOW); - vmcs_set_bits(CPU_EXEC_CTRL1, CPU_VINTD | CPU_VIRT_X2APIC); -} - -static void trigger_ioapic_scan_thread(void *data) -{ - /* Wait until other CPU entered L2 */ - while (vmx_get_test_stage() != 1) - ; - - /* Trigger ioapic scan */ - ioapic_set_redir(0xf, 0x79, TRIGGER_LEVEL); - vmx_set_test_stage(2); -} - -static void irq_79_handler_guest(isr_regs_t *regs) -{ - eoi(); - - /* L1 expects vmexit on VMX_VMCALL and not VMX_EOI_INDUCED */ - vmcall(); -} - -/* - * Constant for num of busy-loop iterations after which - * a timer interrupt should have happened in host - */ -#define TIMER_INTERRUPT_DELAY 100000000 - -static void vmx_eoi_bitmap_ioapic_scan_test_guest(void) -{ - handle_irq(0x79, irq_79_handler_guest); - irq_enable(); - - /* Signal to L1 CPU to trigger ioapic scan */ - vmx_set_test_stage(1); - /* Wait until L1 CPU to trigger ioapic scan */ - while (vmx_get_test_stage() != 2) - ; - - /* - * Wait for L0 timer interrupt to be raised while we run in L2 - * such that L0 will process the IOAPIC scan request before - * resuming L2 - */ - delay(TIMER_INTERRUPT_DELAY); - - asm volatile ("int $0x79"); -} - -static void vmx_eoi_bitmap_ioapic_scan_test(void) -{ - if (!cpu_has_apicv() || (cpu_count() < 2)) { - report_skip(__func__); - return; - } - - enable_vid(); - - on_cpu_async(1, trigger_ioapic_scan_thread, NULL); - test_set_guest(vmx_eoi_bitmap_ioapic_scan_test_guest); - - /* - * Launch L2. - * We expect the exit reason to be VMX_VMCALL (and not EOI INDUCED). - * In case the reason isn't VMX_VMCALL, the asserion inside - * skip_exit_vmcall() will fail. - */ - enter_guest(); - skip_exit_vmcall(); - - /* Let L2 finish */ - enter_guest(); - report(1, __func__); -} - -#define HLT_WITH_RVI_VECTOR (0xf1) - -bool vmx_hlt_with_rvi_guest_isr_fired; -static void vmx_hlt_with_rvi_guest_isr(isr_regs_t *regs) -{ - vmx_hlt_with_rvi_guest_isr_fired = true; - eoi(); -} - -static void vmx_hlt_with_rvi_guest(void) -{ - handle_irq(HLT_WITH_RVI_VECTOR, vmx_hlt_with_rvi_guest_isr); - - irq_enable(); - asm volatile ("nop"); - - vmcall(); -} - -static void vmx_hlt_with_rvi_test(void) -{ - if (!cpu_has_apicv()) { - report_skip(__func__); - return; - } - - enable_vid(); - - vmx_hlt_with_rvi_guest_isr_fired = false; - test_set_guest(vmx_hlt_with_rvi_guest); - - enter_guest(); - skip_exit_vmcall(); - - vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); - vmcs_write(GUEST_INT_STATUS, HLT_WITH_RVI_VECTOR); - enter_guest(); - - report(vmx_hlt_with_rvi_guest_isr_fired, "Interrupt raised in guest"); -} - -static void set_irq_line_thread(void *data) -{ - /* Wait until other CPU entered L2 */ - while (vmx_get_test_stage() != 1) - ; - - /* Set irq-line 0xf to raise vector 0x78 for vCPU 0 */ - ioapic_set_redir(0xf, 0x78, TRIGGER_LEVEL); - vmx_set_test_stage(2); -} - -static bool irq_78_handler_vmcall_before_eoi; -static void irq_78_handler_guest(isr_regs_t *regs) -{ - set_irq_line(0xf, 0); - if (irq_78_handler_vmcall_before_eoi) - vmcall(); - eoi(); - vmcall(); -} - -static void vmx_apic_passthrough_guest(void) -{ - handle_irq(0x78, irq_78_handler_guest); - irq_enable(); - - /* If requested, wait for other CPU to trigger ioapic scan */ - if (vmx_get_test_stage() < 1) { - vmx_set_test_stage(1); - while (vmx_get_test_stage() != 2) - ; - } - - set_irq_line(0xf, 1); -} - -static void vmx_apic_passthrough(bool set_irq_line_from_thread) -{ - if (set_irq_line_from_thread && (cpu_count() < 2)) { - report_skip(__func__); - return; - } - - /* Test device is required for generating IRQs */ - if (!test_device_enabled()) { - report_skip(__func__); - return; - } - u64 cpu_ctrl_0 = CPU_SECONDARY; - u64 cpu_ctrl_1 = 0; - - disable_intercept_for_x2apic_msrs(); - - vmcs_write(PIN_CONTROLS, vmcs_read(PIN_CONTROLS) & ~PIN_EXTINT); - - vmcs_write(CPU_EXEC_CTRL0, vmcs_read(CPU_EXEC_CTRL0) | cpu_ctrl_0); - vmcs_write(CPU_EXEC_CTRL1, vmcs_read(CPU_EXEC_CTRL1) | cpu_ctrl_1); - - if (set_irq_line_from_thread) { - irq_78_handler_vmcall_before_eoi = false; - on_cpu_async(1, set_irq_line_thread, NULL); - } else { - irq_78_handler_vmcall_before_eoi = true; - ioapic_set_redir(0xf, 0x78, TRIGGER_LEVEL); - vmx_set_test_stage(2); - } - test_set_guest(vmx_apic_passthrough_guest); - - if (irq_78_handler_vmcall_before_eoi) { - /* Before EOI remote_irr should still be set */ - enter_guest(); - skip_exit_vmcall(); - TEST_ASSERT_EQ_MSG(1, (int)ioapic_read_redir(0xf).remote_irr, - "IOAPIC pass-through: remote_irr=1 before EOI"); - } - - /* After EOI remote_irr should be cleared */ - enter_guest(); - skip_exit_vmcall(); - TEST_ASSERT_EQ_MSG(0, (int)ioapic_read_redir(0xf).remote_irr, - "IOAPIC pass-through: remote_irr=0 after EOI"); - - /* Let L2 finish */ - enter_guest(); - report(1, __func__); -} - -static void vmx_apic_passthrough_test(void) -{ - vmx_apic_passthrough(false); -} - -static void vmx_apic_passthrough_thread_test(void) -{ - vmx_apic_passthrough(true); -} - -static void vmx_apic_passthrough_tpr_threshold_guest(void) -{ - cli(); - apic_set_tpr(0); -} - -static bool vmx_apic_passthrough_tpr_threshold_ipi_isr_fired; -static void vmx_apic_passthrough_tpr_threshold_ipi_isr(isr_regs_t *regs) -{ - vmx_apic_passthrough_tpr_threshold_ipi_isr_fired = true; - eoi(); -} - -static void vmx_apic_passthrough_tpr_threshold_test(void) -{ - int ipi_vector = 0xe1; - - disable_intercept_for_x2apic_msrs(); - vmcs_clear_bits(PIN_CONTROLS, PIN_EXTINT); - - /* Raise L0 TPR-threshold by queueing vector in LAPIC IRR */ - cli(); - apic_set_tpr((ipi_vector >> 4) + 1); - apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | - APIC_DM_FIXED | ipi_vector, - 0); - - test_set_guest(vmx_apic_passthrough_tpr_threshold_guest); - enter_guest(); - - report(apic_get_tpr() == 0, "TPR was zero by guest"); - - /* Clean pending self-IPI */ - vmx_apic_passthrough_tpr_threshold_ipi_isr_fired = false; - handle_irq(ipi_vector, vmx_apic_passthrough_tpr_threshold_ipi_isr); - sti(); - asm volatile ("nop"); - report(vmx_apic_passthrough_tpr_threshold_ipi_isr_fired, "self-IPI fired"); - - report(1, __func__); -} - -static u64 init_signal_test_exit_reason; -static bool init_signal_test_thread_continued; - -static void init_signal_test_thread(void *data) -{ - struct vmcs *test_vmcs = data; - - /* Enter VMX operation (i.e. exec VMXON) */ - u64 *ap_vmxon_region = alloc_page(); - enable_vmx(); - init_vmx(ap_vmxon_region); - _vmx_on(ap_vmxon_region); - - /* Signal CPU have entered VMX operation */ - vmx_set_test_stage(1); - - /* Wait for BSP CPU to send INIT signal */ - while (vmx_get_test_stage() != 2) - ; - - /* - * Signal that we continue as usual as INIT signal - * should be blocked while CPU is in VMX operation - */ - vmx_set_test_stage(3); - - /* Wait for signal to enter VMX non-root mode */ - while (vmx_get_test_stage() != 4) - ; - - /* Enter VMX non-root mode */ - test_set_guest(v2_null_test_guest); - make_vmcs_current(test_vmcs); - enter_guest(); - /* Save exit reason for BSP CPU to compare to expected result */ - init_signal_test_exit_reason = vmcs_read(EXI_REASON); - /* VMCLEAR test-vmcs so it could be loaded by BSP CPU */ - vmcs_clear(test_vmcs); - launched = false; - /* Signal that CPU exited to VMX root mode */ - vmx_set_test_stage(5); - - /* Wait for BSP CPU to signal to exit VMX operation */ - while (vmx_get_test_stage() != 6) - ; - - /* Exit VMX operation (i.e. exec VMXOFF) */ - vmx_off(); - - /* - * Signal to BSP CPU that we continue as usual as INIT signal - * should have been consumed by VMX_INIT exit from guest - */ - vmx_set_test_stage(7); - - /* Wait for BSP CPU to signal to enter VMX operation */ - while (vmx_get_test_stage() != 8) - ; - /* Enter VMX operation (i.e. exec VMXON) */ - _vmx_on(ap_vmxon_region); - /* Signal to BSP we are in VMX operation */ - vmx_set_test_stage(9); - - /* Wait for BSP CPU to send INIT signal */ - while (vmx_get_test_stage() != 10) - ; - - /* Exit VMX operation (i.e. exec VMXOFF) */ - vmx_off(); - - /* - * Exiting VMX operation should result in latched - * INIT signal being processed. Therefore, we should - * never reach the below code. Thus, signal to BSP - * CPU if we have reached here so it is able to - * report an issue if it happens. - */ - init_signal_test_thread_continued = true; -} - -#define INIT_SIGNAL_TEST_DELAY 100000000ULL - -static void vmx_init_signal_test(void) -{ - struct vmcs *test_vmcs; - - if (cpu_count() < 2) { - report_skip(__func__); - return; - } - - /* VMCLEAR test-vmcs so it could be loaded by other CPU */ - vmcs_save(&test_vmcs); - vmcs_clear(test_vmcs); - - vmx_set_test_stage(0); - on_cpu_async(1, init_signal_test_thread, test_vmcs); - - /* Wait for other CPU to enter VMX operation */ - while (vmx_get_test_stage() != 1) - ; - - /* Send INIT signal to other CPU */ - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_INIT | APIC_INT_ASSERT, - id_map[1]); - /* Signal other CPU we have sent INIT signal */ - vmx_set_test_stage(2); - - /* - * Wait reasonable amount of time for INIT signal to - * be received on other CPU and verify that other CPU - * have proceed as usual to next test stage as INIT - * signal should be blocked while other CPU in - * VMX operation - */ - delay(INIT_SIGNAL_TEST_DELAY); - report(vmx_get_test_stage() == 3, - "INIT signal blocked when CPU in VMX operation"); - /* No point to continue if we failed at this point */ - if (vmx_get_test_stage() != 3) - return; - - /* Signal other CPU to enter VMX non-root mode */ - init_signal_test_exit_reason = -1ull; - vmx_set_test_stage(4); - /* - * Wait reasonable amont of time for other CPU - * to exit to VMX root mode - */ - delay(INIT_SIGNAL_TEST_DELAY); - if (vmx_get_test_stage() != 5) { - report(false, "Pending INIT signal didn't result in VMX exit"); - return; - } - report(init_signal_test_exit_reason == VMX_INIT, - "INIT signal during VMX non-root mode result in exit-reason %s (%lu)", - exit_reason_description(init_signal_test_exit_reason), - init_signal_test_exit_reason); - - /* Run guest to completion */ - make_vmcs_current(test_vmcs); - enter_guest(); - - /* Signal other CPU to exit VMX operation */ - init_signal_test_thread_continued = false; - vmx_set_test_stage(6); - - /* Wait reasonable amount of time for other CPU to exit VMX operation */ - delay(INIT_SIGNAL_TEST_DELAY); - report(vmx_get_test_stage() == 7, - "INIT signal consumed on VMX_INIT exit"); - /* No point to continue if we failed at this point */ - if (vmx_get_test_stage() != 7) - return; - - /* Signal other CPU to enter VMX operation */ - vmx_set_test_stage(8); - /* Wait for other CPU to enter VMX operation */ - while (vmx_get_test_stage() != 9) - ; - - /* Send INIT signal to other CPU */ - apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_INIT | APIC_INT_ASSERT, - id_map[1]); - /* Signal other CPU we have sent INIT signal */ - vmx_set_test_stage(10); - - /* - * Wait reasonable amount of time for other CPU - * to exit VMX operation and process INIT signal - */ - delay(INIT_SIGNAL_TEST_DELAY); - report(!init_signal_test_thread_continued, - "INIT signal processed after exit VMX operation"); - - /* - * TODO: Send SIPI to other CPU to sipi_entry (See x86/cstart64.S) - * to re-init it to kvm-unit-tests standard environment. - * Somehow (?) verify that SIPI was indeed received. - */ -} - -enum vmcs_access { - ACCESS_VMREAD, - ACCESS_VMWRITE, - ACCESS_NONE, -}; - -struct vmcs_shadow_test_common { - enum vmcs_access op; - enum Reason reason; - u64 field; - u64 value; - u64 flags; - u64 time; -} l1_l2_common; - -static inline u64 vmread_flags(u64 field, u64 *val) -{ - u64 flags; - - asm volatile ("vmread %2, %1; pushf; pop %0" - : "=r" (flags), "=rm" (*val) : "r" (field) : "cc"); - return flags & X86_EFLAGS_ALU; -} - -static inline u64 vmwrite_flags(u64 field, u64 val) -{ - u64 flags; - - asm volatile ("vmwrite %1, %2; pushf; pop %0" - : "=r"(flags) : "rm" (val), "r" (field) : "cc"); - return flags & X86_EFLAGS_ALU; -} - -static void vmx_vmcs_shadow_test_guest(void) -{ - struct vmcs_shadow_test_common *c = &l1_l2_common; - u64 start; - - while (c->op != ACCESS_NONE) { - start = rdtsc(); - switch (c->op) { - default: - c->flags = -1ull; - break; - case ACCESS_VMREAD: - c->flags = vmread_flags(c->field, &c->value); - break; - case ACCESS_VMWRITE: - c->flags = vmwrite_flags(c->field, 0); - break; - } - c->time = rdtsc() - start; - vmcall(); - } -} - -static u64 vmread_from_shadow(u64 field) -{ - struct vmcs *primary; - struct vmcs *shadow; - u64 value; - - TEST_ASSERT(!vmcs_save(&primary)); - shadow = (struct vmcs *)vmcs_read(VMCS_LINK_PTR); - TEST_ASSERT(!make_vmcs_current(shadow)); - value = vmcs_read(field); - TEST_ASSERT(!make_vmcs_current(primary)); - return value; -} - -static u64 vmwrite_to_shadow(u64 field, u64 value) -{ - struct vmcs *primary; - struct vmcs *shadow; - - TEST_ASSERT(!vmcs_save(&primary)); - shadow = (struct vmcs *)vmcs_read(VMCS_LINK_PTR); - TEST_ASSERT(!make_vmcs_current(shadow)); - vmcs_write(field, value); - value = vmcs_read(field); - TEST_ASSERT(!make_vmcs_current(primary)); - return value; -} - -static void vmcs_shadow_test_access(u8 *bitmap[2], enum vmcs_access access) -{ - struct vmcs_shadow_test_common *c = &l1_l2_common; - - c->op = access; - vmcs_write(VMX_INST_ERROR, 0); - enter_guest(); - c->reason = vmcs_read(EXI_REASON) & 0xffff; - if (c->reason != VMX_VMCALL) { - skip_exit_insn(); - enter_guest(); - } - skip_exit_vmcall(); -} - -static void vmcs_shadow_test_field(u8 *bitmap[2], u64 field) -{ - struct vmcs_shadow_test_common *c = &l1_l2_common; - struct vmcs *shadow; - u64 value; - uintptr_t flags[2]; - bool good_shadow; - u32 vmx_inst_error; - - report_prefix_pushf("field %lx", field); - c->field = field; - - shadow = (struct vmcs *)vmcs_read(VMCS_LINK_PTR); - if (shadow != (struct vmcs *)-1ull) { - flags[ACCESS_VMREAD] = vmread_flags(field, &value); - flags[ACCESS_VMWRITE] = vmwrite_flags(field, value); - good_shadow = !flags[ACCESS_VMREAD] && !flags[ACCESS_VMWRITE]; - } else { - /* - * When VMCS link pointer is -1ull, VMWRITE/VMREAD on - * shadowed-fields should fail with setting RFLAGS.CF. - */ - flags[ACCESS_VMREAD] = X86_EFLAGS_CF; - flags[ACCESS_VMWRITE] = X86_EFLAGS_CF; - good_shadow = false; - } - - /* Intercept both VMREAD and VMWRITE. */ - report_prefix_push("no VMREAD/VMWRITE permission"); - /* VMWRITE/VMREAD done on reserved-bit should always intercept */ - if (!(field >> VMCS_FIELD_RESERVED_SHIFT)) { - set_bit(field, bitmap[ACCESS_VMREAD]); - set_bit(field, bitmap[ACCESS_VMWRITE]); - } - vmcs_shadow_test_access(bitmap, ACCESS_VMWRITE); - report(c->reason == VMX_VMWRITE, "not shadowed for VMWRITE"); - vmcs_shadow_test_access(bitmap, ACCESS_VMREAD); - report(c->reason == VMX_VMREAD, "not shadowed for VMREAD"); - report_prefix_pop(); - - if (field >> VMCS_FIELD_RESERVED_SHIFT) - goto out; - - /* Permit shadowed VMREAD. */ - report_prefix_push("VMREAD permission only"); - clear_bit(field, bitmap[ACCESS_VMREAD]); - set_bit(field, bitmap[ACCESS_VMWRITE]); - if (good_shadow) - value = vmwrite_to_shadow(field, MAGIC_VAL_1 + field); - vmcs_shadow_test_access(bitmap, ACCESS_VMWRITE); - report(c->reason == VMX_VMWRITE, "not shadowed for VMWRITE"); - vmcs_shadow_test_access(bitmap, ACCESS_VMREAD); - vmx_inst_error = vmcs_read(VMX_INST_ERROR); - report(c->reason == VMX_VMCALL, "shadowed for VMREAD (in %ld cycles)", - c->time); - report(c->flags == flags[ACCESS_VMREAD], - "ALU flags after VMREAD (%lx) are as expected (%lx)", - c->flags, flags[ACCESS_VMREAD]); - if (good_shadow) - report(c->value == value, - "value read from shadow (%lx) is as expected (%lx)", - c->value, value); - else if (shadow != (struct vmcs *)-1ull && flags[ACCESS_VMREAD]) - report(vmx_inst_error == VMXERR_UNSUPPORTED_VMCS_COMPONENT, - "VMX_INST_ERROR (%d) is as expected (%d)", - vmx_inst_error, VMXERR_UNSUPPORTED_VMCS_COMPONENT); - report_prefix_pop(); - - /* Permit shadowed VMWRITE. */ - report_prefix_push("VMWRITE permission only"); - set_bit(field, bitmap[ACCESS_VMREAD]); - clear_bit(field, bitmap[ACCESS_VMWRITE]); - if (good_shadow) - vmwrite_to_shadow(field, MAGIC_VAL_1 + field); - vmcs_shadow_test_access(bitmap, ACCESS_VMWRITE); - vmx_inst_error = vmcs_read(VMX_INST_ERROR); - report(c->reason == VMX_VMCALL, - "shadowed for VMWRITE (in %ld cycles)", - c->time); - report(c->flags == flags[ACCESS_VMREAD], - "ALU flags after VMWRITE (%lx) are as expected (%lx)", - c->flags, flags[ACCESS_VMREAD]); - if (good_shadow) { - value = vmread_from_shadow(field); - report(value == 0, - "shadow VMCS value (%lx) is as expected (%lx)", value, - 0ul); - } else if (shadow != (struct vmcs *)-1ull && flags[ACCESS_VMWRITE]) { - report(vmx_inst_error == VMXERR_UNSUPPORTED_VMCS_COMPONENT, - "VMX_INST_ERROR (%d) is as expected (%d)", - vmx_inst_error, VMXERR_UNSUPPORTED_VMCS_COMPONENT); - } - vmcs_shadow_test_access(bitmap, ACCESS_VMREAD); - report(c->reason == VMX_VMREAD, "not shadowed for VMREAD"); - report_prefix_pop(); - - /* Permit shadowed VMREAD and VMWRITE. */ - report_prefix_push("VMREAD and VMWRITE permission"); - clear_bit(field, bitmap[ACCESS_VMREAD]); - clear_bit(field, bitmap[ACCESS_VMWRITE]); - if (good_shadow) - vmwrite_to_shadow(field, MAGIC_VAL_1 + field); - vmcs_shadow_test_access(bitmap, ACCESS_VMWRITE); - vmx_inst_error = vmcs_read(VMX_INST_ERROR); - report(c->reason == VMX_VMCALL, - "shadowed for VMWRITE (in %ld cycles)", - c->time); - report(c->flags == flags[ACCESS_VMREAD], - "ALU flags after VMWRITE (%lx) are as expected (%lx)", - c->flags, flags[ACCESS_VMREAD]); - if (good_shadow) { - value = vmread_from_shadow(field); - report(value == 0, - "shadow VMCS value (%lx) is as expected (%lx)", value, - 0ul); - } else if (shadow != (struct vmcs *)-1ull && flags[ACCESS_VMWRITE]) { - report(vmx_inst_error == VMXERR_UNSUPPORTED_VMCS_COMPONENT, - "VMX_INST_ERROR (%d) is as expected (%d)", - vmx_inst_error, VMXERR_UNSUPPORTED_VMCS_COMPONENT); - } - vmcs_shadow_test_access(bitmap, ACCESS_VMREAD); - vmx_inst_error = vmcs_read(VMX_INST_ERROR); - report(c->reason == VMX_VMCALL, "shadowed for VMREAD (in %ld cycles)", - c->time); - report(c->flags == flags[ACCESS_VMREAD], - "ALU flags after VMREAD (%lx) are as expected (%lx)", - c->flags, flags[ACCESS_VMREAD]); - if (good_shadow) - report(c->value == 0, - "value read from shadow (%lx) is as expected (%lx)", - c->value, 0ul); - else if (shadow != (struct vmcs *)-1ull && flags[ACCESS_VMREAD]) - report(vmx_inst_error == VMXERR_UNSUPPORTED_VMCS_COMPONENT, - "VMX_INST_ERROR (%d) is as expected (%d)", - vmx_inst_error, VMXERR_UNSUPPORTED_VMCS_COMPONENT); - report_prefix_pop(); - -out: - report_prefix_pop(); -} - -static void vmx_vmcs_shadow_test_body(u8 *bitmap[2]) -{ - unsigned base; - unsigned index; - unsigned bit; - unsigned highest_index = rdmsr(MSR_IA32_VMX_VMCS_ENUM); - - /* Run test on all possible valid VMCS fields */ - for (base = 0; - base < (1 << VMCS_FIELD_RESERVED_SHIFT); - base += (1 << VMCS_FIELD_TYPE_SHIFT)) - for (index = 0; index <= highest_index; index++) - vmcs_shadow_test_field(bitmap, base + index); - - /* - * Run tests on some invalid VMCS fields - * (Have reserved bit set). - */ - for (bit = VMCS_FIELD_RESERVED_SHIFT; bit < VMCS_FIELD_BIT_SIZE; bit++) - vmcs_shadow_test_field(bitmap, (1ull << bit)); -} - -static void vmx_vmcs_shadow_test(void) -{ - u8 *bitmap[2]; - struct vmcs *shadow; - - if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY)) { - printf("\t'Activate secondary controls' not supported.\n"); - return; - } - - if (!(ctrl_cpu_rev[1].clr & CPU_SHADOW_VMCS)) { - printf("\t'VMCS shadowing' not supported.\n"); - return; - } - - if (!(rdmsr(MSR_IA32_VMX_MISC) & - MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS)) { - printf("\tVMWRITE can't modify VM-exit information fields.\n"); - return; - } - - test_set_guest(vmx_vmcs_shadow_test_guest); - - bitmap[ACCESS_VMREAD] = alloc_page(); - bitmap[ACCESS_VMWRITE] = alloc_page(); - - vmcs_write(VMREAD_BITMAP, virt_to_phys(bitmap[ACCESS_VMREAD])); - vmcs_write(VMWRITE_BITMAP, virt_to_phys(bitmap[ACCESS_VMWRITE])); - - shadow = alloc_page(); - shadow->hdr.revision_id = basic.revision; - shadow->hdr.shadow_vmcs = 1; - TEST_ASSERT(!vmcs_clear(shadow)); - - vmcs_clear_bits(CPU_EXEC_CTRL0, CPU_RDTSC); - vmcs_set_bits(CPU_EXEC_CTRL0, CPU_SECONDARY); - vmcs_set_bits(CPU_EXEC_CTRL1, CPU_SHADOW_VMCS); - - vmcs_write(VMCS_LINK_PTR, virt_to_phys(shadow)); - report_prefix_push("valid link pointer"); - vmx_vmcs_shadow_test_body(bitmap); - report_prefix_pop(); - - vmcs_write(VMCS_LINK_PTR, -1ull); - report_prefix_push("invalid link pointer"); - vmx_vmcs_shadow_test_body(bitmap); - report_prefix_pop(); - - l1_l2_common.op = ACCESS_NONE; - enter_guest(); -} - -/* - * This test monitors the difference between a guest RDTSC instruction - * and the IA32_TIME_STAMP_COUNTER MSR value stored in the VMCS12 - * VM-exit MSR-store list when taking a VM-exit on the instruction - * following RDTSC. - */ -#define RDTSC_DIFF_ITERS 100000 -#define RDTSC_DIFF_FAILS 100 -#define HOST_CAPTURED_GUEST_TSC_DIFF_THRESHOLD 750 - -/* - * Set 'use TSC offsetting' and set the guest offset to the - * inverse of the host's current TSC value, so that the guest starts running - * with an effective TSC value of 0. - */ -static void reset_guest_tsc_to_zero(void) -{ - vmcs_set_bits(CPU_EXEC_CTRL0, CPU_USE_TSC_OFFSET); - vmcs_write(TSC_OFFSET, -rdtsc()); -} - -static void rdtsc_vmexit_diff_test_guest(void) -{ - int i; - - for (i = 0; i < RDTSC_DIFF_ITERS; i++) - /* Ensure rdtsc is the last instruction before the vmcall. */ - asm volatile("rdtsc; vmcall" : : : "eax", "edx"); -} - -/* - * This function only considers the "use TSC offsetting" VM-execution - * control. It does not handle "use TSC scaling" (because the latter - * isn't available to the host today.) - */ -static unsigned long long host_time_to_guest_time(unsigned long long t) -{ - TEST_ASSERT(!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) || - !(vmcs_read(CPU_EXEC_CTRL1) & CPU_USE_TSC_SCALING)); - - if (vmcs_read(CPU_EXEC_CTRL0) & CPU_USE_TSC_OFFSET) - t += vmcs_read(TSC_OFFSET); - - return t; -} - -static unsigned long long rdtsc_vmexit_diff_test_iteration(void) -{ - unsigned long long guest_tsc, host_to_guest_tsc; - - enter_guest(); - skip_exit_vmcall(); - guest_tsc = (u32) regs.rax + (regs.rdx << 32); - host_to_guest_tsc = host_time_to_guest_time(exit_msr_store[0].value); - - return host_to_guest_tsc - guest_tsc; -} - -static void rdtsc_vmexit_diff_test(void) -{ - unsigned long long delta; - int fail = 0; - int i; - - if (!(ctrl_cpu_rev[0].clr & CPU_USE_TSC_OFFSET)) - test_skip("CPU doesn't support the 'use TSC offsetting' processor-based VM-execution control.\n"); - - test_set_guest(rdtsc_vmexit_diff_test_guest); - - reset_guest_tsc_to_zero(); - - /* - * Set up the VMCS12 VM-exit MSR-store list to store just one - * MSR: IA32_TIME_STAMP_COUNTER. Note that the value stored is - * in the host time domain (i.e., it is not adjusted according - * to the TSC multiplier and TSC offset fields in the VMCS12, - * as a guest RDTSC would be.) - */ - exit_msr_store = alloc_page(); - exit_msr_store[0].index = MSR_IA32_TSC; - vmcs_write(EXI_MSR_ST_CNT, 1); - vmcs_write(EXIT_MSR_ST_ADDR, virt_to_phys(exit_msr_store)); - - for (i = 0; i < RDTSC_DIFF_ITERS && fail < RDTSC_DIFF_FAILS; i++) { - delta = rdtsc_vmexit_diff_test_iteration(); - if (delta >= HOST_CAPTURED_GUEST_TSC_DIFF_THRESHOLD) - fail++; - } - - enter_guest(); - - report(fail < RDTSC_DIFF_FAILS, - "RDTSC to VM-exit delta too high in %d of %d iterations, last = %llu", - fail, i, delta); -} - -static int invalid_msr_init(struct vmcs *vmcs) -{ - if (!(ctrl_pin_rev.clr & PIN_PREEMPT)) { - printf("\tPreemption timer is not supported\n"); - return VMX_TEST_EXIT; - } - vmcs_write(PIN_CONTROLS, vmcs_read(PIN_CONTROLS) | PIN_PREEMPT); - preempt_val = 10000000; - vmcs_write(PREEMPT_TIMER_VALUE, preempt_val); - preempt_scale = rdmsr(MSR_IA32_VMX_MISC) & 0x1F; - - if (!(ctrl_exit_rev.clr & EXI_SAVE_PREEMPT)) - printf("\tSave preemption value is not supported\n"); - - vmcs_write(ENT_MSR_LD_CNT, 1); - vmcs_write(ENTER_MSR_LD_ADDR, (u64)0x13370000); - - return VMX_TEST_START; -} - - -static void invalid_msr_main(void) -{ - report(0, "Invalid MSR load"); -} - -static int invalid_msr_exit_handler(union exit_reason exit_reason) -{ - report(0, "Invalid MSR load"); - print_vmexit_info(exit_reason); - return VMX_TEST_EXIT; -} - -static int invalid_msr_entry_failure(struct vmentry_result *result) -{ - report(result->exit_reason.failed_vmentry && - result->exit_reason.basic == VMX_FAIL_MSR, "Invalid MSR load"); - return VMX_TEST_VMEXIT; -} - -/* - * The max number of MSRs in an atomic switch MSR list is: - * (111B + 1) * 512 = 4096 - * - * Each list entry consumes: - * 4-byte MSR index + 4 bytes reserved + 8-byte data = 16 bytes - * - * Allocate 128 kB to cover max_msr_list_size (i.e., 64 kB) and then some. - */ -static const u32 msr_list_page_order = 5; - -static void atomic_switch_msr_limit_test_guest(void) -{ - vmcall(); -} - -static void populate_msr_list(struct vmx_msr_entry *msr_list, - size_t byte_capacity, int count) -{ - int i; - - for (i = 0; i < count; i++) { - msr_list[i].index = MSR_IA32_TSC; - msr_list[i].reserved = 0; - msr_list[i].value = 0x1234567890abcdef; - } - - memset(msr_list + count, 0xff, - byte_capacity - count * sizeof(*msr_list)); -} - -static int max_msr_list_size(void) -{ - u32 vmx_misc = rdmsr(MSR_IA32_VMX_MISC); - u32 factor = ((vmx_misc & GENMASK(27, 25)) >> 25) + 1; - - return factor * 512; -} - -static void atomic_switch_msrs_test(int count) -{ - struct vmx_msr_entry *vm_enter_load; - struct vmx_msr_entry *vm_exit_load; - struct vmx_msr_entry *vm_exit_store; - int max_allowed = max_msr_list_size(); - int byte_capacity = 1ul << (msr_list_page_order + PAGE_SHIFT); - /* Exceeding the max MSR list size at exit trigers KVM to abort. */ - int exit_count = count > max_allowed ? max_allowed : count; - int cleanup_count = count > max_allowed ? 2 : 1; - int i; - - /* - * Check for the IA32_TSC MSR, - * available with the "TSC flag" and used to populate the MSR lists. - */ - if (!(cpuid(1).d & (1 << 4))) { - report_skip(__func__); - return; - } - - /* Set L2 guest. */ - test_set_guest(atomic_switch_msr_limit_test_guest); - - /* Setup atomic MSR switch lists. */ - vm_enter_load = alloc_pages(msr_list_page_order); - vm_exit_load = alloc_pages(msr_list_page_order); - vm_exit_store = alloc_pages(msr_list_page_order); - - vmcs_write(ENTER_MSR_LD_ADDR, (u64)vm_enter_load); - vmcs_write(EXIT_MSR_LD_ADDR, (u64)vm_exit_load); - vmcs_write(EXIT_MSR_ST_ADDR, (u64)vm_exit_store); - - /* - * VM-Enter should succeed up to the max number of MSRs per list, and - * should not consume junk beyond the last entry. - */ - populate_msr_list(vm_enter_load, byte_capacity, count); - populate_msr_list(vm_exit_load, byte_capacity, exit_count); - populate_msr_list(vm_exit_store, byte_capacity, exit_count); - - vmcs_write(ENT_MSR_LD_CNT, count); - vmcs_write(EXI_MSR_LD_CNT, exit_count); - vmcs_write(EXI_MSR_ST_CNT, exit_count); - - if (count <= max_allowed) { - enter_guest(); - assert_exit_reason(VMX_VMCALL); - skip_exit_vmcall(); - } else { - u32 exit_qual; - - test_guest_state("Invalid MSR Load Count", true, count, - "ENT_MSR_LD_CNT"); - - exit_qual = vmcs_read(EXI_QUALIFICATION); - report(exit_qual == max_allowed + 1, "exit_qual, %u, is %u.", - exit_qual, max_allowed + 1); - } - - /* Cleanup. */ - vmcs_write(ENT_MSR_LD_CNT, 0); - vmcs_write(EXI_MSR_LD_CNT, 0); - vmcs_write(EXI_MSR_ST_CNT, 0); - for (i = 0; i < cleanup_count; i++) { - enter_guest(); - skip_exit_vmcall(); - } - free_pages_by_order(vm_enter_load, msr_list_page_order); - free_pages_by_order(vm_exit_load, msr_list_page_order); - free_pages_by_order(vm_exit_store, msr_list_page_order); -} - -static void atomic_switch_max_msrs_test(void) -{ - atomic_switch_msrs_test(max_msr_list_size()); -} - -static void atomic_switch_overflow_msrs_test(void) -{ - if (test_device_enabled()) - atomic_switch_msrs_test(max_msr_list_size() + 1); - else - test_skip("Test is only supported on KVM"); -} - -#define TEST(name) { #name, .v2 = name } - -/* name/init/guest_main/exit_handler/syscall_handler/guest_regs */ -struct vmx_test vmx_tests[] = { - { "null", NULL, basic_guest_main, basic_exit_handler, NULL, {0} }, - { "vmenter", NULL, vmenter_main, vmenter_exit_handler, NULL, {0} }, - { "preemption timer", preemption_timer_init, preemption_timer_main, - preemption_timer_exit_handler, NULL, {0} }, - { "control field PAT", test_ctrl_pat_init, test_ctrl_pat_main, - test_ctrl_pat_exit_handler, NULL, {0} }, - { "control field EFER", test_ctrl_efer_init, test_ctrl_efer_main, - test_ctrl_efer_exit_handler, NULL, {0} }, - { "CR shadowing", NULL, cr_shadowing_main, - cr_shadowing_exit_handler, NULL, {0} }, - { "I/O bitmap", iobmp_init, iobmp_main, iobmp_exit_handler, - NULL, {0} }, - { "instruction intercept", insn_intercept_init, insn_intercept_main, - insn_intercept_exit_handler, NULL, {0} }, - { "EPT A/D disabled", ept_init, ept_main, ept_exit_handler, NULL, {0} }, - { "EPT A/D enabled", eptad_init, eptad_main, eptad_exit_handler, NULL, {0} }, - { "PML", pml_init, pml_main, pml_exit_handler, NULL, {0} }, - { "VPID", vpid_init, vpid_main, vpid_exit_handler, NULL, {0} }, - { "interrupt", interrupt_init, interrupt_main, - interrupt_exit_handler, NULL, {0} }, - { "nmi_hlt", nmi_hlt_init, nmi_hlt_main, - nmi_hlt_exit_handler, NULL, {0} }, - { "debug controls", dbgctls_init, dbgctls_main, dbgctls_exit_handler, - NULL, {0} }, - { "MSR switch", msr_switch_init, msr_switch_main, - msr_switch_exit_handler, NULL, {0}, msr_switch_entry_failure }, - { "vmmcall", vmmcall_init, vmmcall_main, vmmcall_exit_handler, NULL, {0} }, - { "disable RDTSCP", disable_rdtscp_init, disable_rdtscp_main, - disable_rdtscp_exit_handler, NULL, {0} }, - { "int3", int3_init, int3_guest_main, int3_exit_handler, NULL, {0} }, - { "into", into_init, into_guest_main, into_exit_handler, NULL, {0} }, - { "exit_monitor_from_l2_test", NULL, exit_monitor_from_l2_main, - exit_monitor_from_l2_handler, NULL, {0} }, - { "invalid_msr", invalid_msr_init, invalid_msr_main, - invalid_msr_exit_handler, NULL, {0}, invalid_msr_entry_failure}, - /* Basic V2 tests. */ - TEST(v2_null_test), - TEST(v2_multiple_entries_test), - TEST(fixture_test_case1), - TEST(fixture_test_case2), - /* Opcode tests. */ - TEST(invvpid_test_v2), - /* VM-entry tests */ - TEST(vmx_controls_test), - TEST(vmx_host_state_area_test), - TEST(vmx_guest_state_area_test), - TEST(vmentry_movss_shadow_test), - /* APICv tests */ - TEST(vmx_eoi_bitmap_ioapic_scan_test), - TEST(vmx_hlt_with_rvi_test), - TEST(apic_reg_virt_test), - TEST(virt_x2apic_mode_test), - /* APIC pass-through tests */ - TEST(vmx_apic_passthrough_test), - TEST(vmx_apic_passthrough_thread_test), - TEST(vmx_apic_passthrough_tpr_threshold_test), - TEST(vmx_init_signal_test), - /* VMCS Shadowing tests */ - TEST(vmx_vmcs_shadow_test), - /* Regression tests */ - TEST(vmx_cr_load_test), - TEST(vmx_nm_test), - TEST(vmx_db_test), - TEST(vmx_nmi_window_test), - TEST(vmx_intr_window_test), - TEST(vmx_pending_event_test), - TEST(vmx_pending_event_hlt_test), - TEST(vmx_store_tsc_test), - TEST(vmx_preemption_timer_zero_test), - TEST(vmx_preemption_timer_tf_test), - TEST(vmx_preemption_timer_expiry_test), - /* EPT access tests. */ - TEST(ept_access_test_not_present), - TEST(ept_access_test_read_only), - TEST(ept_access_test_write_only), - TEST(ept_access_test_read_write), - TEST(ept_access_test_execute_only), - TEST(ept_access_test_read_execute), - TEST(ept_access_test_write_execute), - TEST(ept_access_test_read_write_execute), - TEST(ept_access_test_reserved_bits), - TEST(ept_access_test_ignored_bits), - TEST(ept_access_test_paddr_not_present_ad_disabled), - TEST(ept_access_test_paddr_not_present_ad_enabled), - TEST(ept_access_test_paddr_read_only_ad_disabled), - TEST(ept_access_test_paddr_read_only_ad_enabled), - TEST(ept_access_test_paddr_read_write), - TEST(ept_access_test_paddr_read_write_execute), - TEST(ept_access_test_paddr_read_execute_ad_disabled), - TEST(ept_access_test_paddr_read_execute_ad_enabled), - TEST(ept_access_test_paddr_not_present_page_fault), - TEST(ept_access_test_force_2m_page), - /* Atomic MSR switch tests. */ - TEST(atomic_switch_max_msrs_test), - TEST(atomic_switch_overflow_msrs_test), - TEST(rdtsc_vmexit_diff_test), - TEST(vmx_mtf_test), - { NULL, NULL, NULL, NULL, NULL, {0} }, -}; diff --git a/x86/xsave.c b/x86/xsave.c deleted file mode 100644 index 892bf561..00000000 --- a/x86/xsave.c +++ /dev/null @@ -1,162 +0,0 @@ -#include "libcflat.h" -#include "desc.h" -#include "processor.h" - -#ifdef __x86_64__ -#define uint64_t unsigned long -#else -#define uint64_t unsigned long long -#endif - -static int xgetbv_checking(u32 index, u64 *result) -{ - u32 eax, edx; - - asm volatile(ASM_TRY("1f") - ".byte 0x0f,0x01,0xd0\n\t" /* xgetbv */ - "1:" - : "=a" (eax), "=d" (edx) - : "c" (index)); - *result = eax + ((u64)edx << 32); - return exception_vector(); -} - -static int xsetbv_checking(u32 index, u64 value) -{ - u32 eax = value; - u32 edx = value >> 32; - - asm volatile(ASM_TRY("1f") - ".byte 0x0f,0x01,0xd1\n\t" /* xsetbv */ - "1:" - : : "a" (eax), "d" (edx), "c" (index)); - return exception_vector(); -} - -static uint64_t get_supported_xcr0(void) -{ - struct cpuid r; - r = cpuid_indexed(0xd, 0); - printf("eax %x, ebx %x, ecx %x, edx %x\n", - r.a, r.b, r.c, r.d); - return r.a + ((u64)r.d << 32); -} - -#define X86_CR4_OSXSAVE 0x00040000 -#define XCR_XFEATURE_ENABLED_MASK 0x00000000 -#define XCR_XFEATURE_ILLEGAL_MASK 0x00000010 - -#define XSTATE_FP 0x1 -#define XSTATE_SSE 0x2 -#define XSTATE_YMM 0x4 - -static void test_xsave(void) -{ - unsigned long cr4; - uint64_t supported_xcr0; - uint64_t test_bits; - u64 xcr0; - - printf("Legal instruction testing:\n"); - - supported_xcr0 = get_supported_xcr0(); - printf("Supported XCR0 bits: %#lx\n", supported_xcr0); - - test_bits = XSTATE_FP | XSTATE_SSE; - report((supported_xcr0 & test_bits) == test_bits, - "Check minimal XSAVE required bits"); - - cr4 = read_cr4(); - report(write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == 0, "Set CR4 OSXSAVE"); - report(this_cpu_has(X86_FEATURE_OSXSAVE), - "Check CPUID.1.ECX.OSXSAVE - expect 1"); - - printf("\tLegal tests\n"); - test_bits = XSTATE_FP; - report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0, - "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP)"); - - test_bits = XSTATE_FP | XSTATE_SSE; - report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == 0, - "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE)"); - report(xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == 0, - " xgetbv(XCR_XFEATURE_ENABLED_MASK)"); - - printf("\tIllegal tests\n"); - test_bits = 0; - report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR, - "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, 0) - expect #GP"); - - test_bits = XSTATE_SSE; - report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR, - "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_SSE) - expect #GP"); - - if (supported_xcr0 & XSTATE_YMM) { - test_bits = XSTATE_YMM; - report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR, - "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_YMM) - expect #GP"); - - test_bits = XSTATE_FP | XSTATE_YMM; - report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == GP_VECTOR, - "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_YMM) - expect #GP"); - } - - test_bits = XSTATE_SSE; - report(xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR, - "\t\txsetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP"); - - test_bits = XSTATE_SSE; - report(xsetbv_checking(XCR_XFEATURE_ILLEGAL_MASK, test_bits) == GP_VECTOR, - "\t\txgetbv(XCR_XFEATURE_ILLEGAL_MASK, XSTATE_FP) - expect #GP"); - - cr4 &= ~X86_CR4_OSXSAVE; - report(write_cr4_checking(cr4) == 0, "Unset CR4 OSXSAVE"); - report(this_cpu_has(X86_FEATURE_OSXSAVE) == 0, - "Check CPUID.1.ECX.OSXSAVE - expect 0"); - - printf("\tIllegal tests:\n"); - test_bits = XSTATE_FP; - report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR, - "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP) - expect #UD"); - - test_bits = XSTATE_FP | XSTATE_SSE; - report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, test_bits) == UD_VECTOR, - "\t\txsetbv(XCR_XFEATURE_ENABLED_MASK, XSTATE_FP | XSTATE_SSE) - expect #UD"); - - printf("\tIllegal tests:\n"); - report(xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR, - "\txgetbv(XCR_XFEATURE_ENABLED_MASK) - expect #UD"); -} - -static void test_no_xsave(void) -{ - unsigned long cr4; - u64 xcr0; - - report(this_cpu_has(X86_FEATURE_OSXSAVE) == 0, - "Check CPUID.1.ECX.OSXSAVE - expect 0"); - - printf("Illegal instruction testing:\n"); - - cr4 = read_cr4(); - report(write_cr4_checking(cr4 | X86_CR4_OSXSAVE) == GP_VECTOR, - "Set OSXSAVE in CR4 - expect #GP"); - - report(xgetbv_checking(XCR_XFEATURE_ENABLED_MASK, &xcr0) == UD_VECTOR, - "Execute xgetbv - expect #UD"); - - report(xsetbv_checking(XCR_XFEATURE_ENABLED_MASK, 0x3) == UD_VECTOR, - "Execute xsetbv - expect #UD"); -} - -int main(void) -{ - if (this_cpu_has(X86_FEATURE_XSAVE)) { - printf("CPU has XSAVE feature\n"); - test_xsave(); - } else { - printf("CPU don't has XSAVE feature\n"); - test_no_xsave(); - } - return report_summary(); -} -- GitLab