├── .editorconfig ├── .gitignore ├── .gitlab-ci.yml ├── .travis.yml ├── COPYRIGHT ├── MAINTAINERS ├── Makefile ├── README.kvm.macOS.md ├── README.kvm.md ├── README.rst ├── arm ├── Makefile ├── Makefile.arm ├── Makefile.arm64 ├── Makefile.common ├── cache.c ├── cstart.S ├── cstart64.S ├── debug.c ├── flat.lds ├── gic.c ├── micro-bench.c ├── pci-test.c ├── pl031.c ├── pmu.c ├── psci.c ├── run ├── selftest.c ├── sieve.c ├── spinlock-test.c ├── timer.c └── unittests.cfg ├── ci ├── cirrus-ci-fedora.yml ├── cirrus-ci-macos-i386.yml └── cirrus-ci-macos-x86-64.yml ├── configure ├── errata.txt ├── lib ├── abort.c ├── alloc.c ├── alloc.h ├── alloc_page.c ├── alloc_page.h ├── alloc_phys.c ├── alloc_phys.h ├── argv.c ├── argv.h ├── arm │ ├── .gitignore │ ├── asm-offsets.c │ ├── asm │ │ ├── arch_gicv3.h │ │ ├── asm-offsets.h │ │ ├── assembler.h │ │ ├── barrier.h │ │ ├── bitops.h │ │ ├── cpumask.h │ │ ├── delay.h │ │ ├── gic-v2.h │ │ ├── gic-v3-its.h │ │ ├── gic-v3.h │ │ ├── gic.h │ │ ├── io.h │ │ ├── memory_areas.h │ │ ├── mmu-api.h │ │ ├── mmu.h │ │ ├── page.h │ │ ├── pci.h │ │ ├── pgtable-hwdef.h │ │ ├── pgtable.h │ │ ├── processor.h │ │ ├── psci.h │ │ ├── ptrace.h │ │ ├── setup.h │ │ ├── smp.h │ │ ├── spinlock.h │ │ ├── stack.h │ │ ├── sysreg.h │ │ ├── thread_info.h │ │ └── timer.h │ ├── bitops.c │ ├── delay.c │ ├── eabi_compat.c │ ├── gic-v2.c │ ├── gic-v3.c │ ├── gic.c │ ├── io.c │ ├── io.h │ ├── ldivmod.S │ ├── mmu.c │ ├── processor.c │ ├── psci.c │ ├── setup.c │ ├── smp.c │ ├── spinlock.c │ └── stack.c ├── arm64 │ ├── .gitignore │ ├── asm-offsets.c │ ├── asm │ │ ├── arch_gicv3.h │ │ ├── asm-offsets.h │ │ ├── assembler.h │ │ ├── barrier.h │ │ ├── bitops.h │ │ ├── cpumask.h │ │ ├── delay.h │ │ ├── esr.h │ │ ├── gic-v2.h │ │ ├── gic-v3-its.h │ │ ├── gic-v3.h │ │ ├── gic.h │ │ ├── io.h │ │ ├── memory_areas.h │ │ ├── mmu-api.h │ │ ├── mmu.h │ │ ├── page.h │ │ ├── pci.h │ │ ├── pgtable-hwdef.h │ │ ├── pgtable.h │ │ ├── processor.h │ │ ├── psci.h │ │ ├── ptrace.h │ │ ├── setup.h │ │ ├── smp.h │ │ ├── spinlock.h │ │ ├── stack.h │ │ ├── sysreg.h │ │ ├── thread_info.h │ │ └── timer.h │ ├── gic-v3-its-cmd.c │ ├── gic-v3-its.c │ ├── processor.c │ └── spinlock.c ├── asm-generic │ ├── atomic.h │ ├── barrier.h │ ├── io.h │ ├── memory_areas.h │ ├── page.h │ ├── pci-host-bridge.h │ ├── pci.h │ └── spinlock.h ├── auxinfo.c ├── auxinfo.h ├── bitops.h ├── chr-testdev.c ├── chr-testdev.h ├── ctype.h ├── devicetree.c ├── devicetree.h ├── efi.c ├── efi.h ├── errata.h ├── generated │ └── .gitignore ├── getchar.c ├── kbuild.h ├── ldiv32.c ├── libcflat.h ├── libfdt │ ├── Makefile.libfdt │ ├── README │ ├── fdt.c │ ├── fdt.h │ ├── fdt_addresses.c │ ├── fdt_check.c │ ├── fdt_empty_tree.c │ ├── fdt_overlay.c │ ├── fdt_ro.c │ ├── fdt_rw.c │ ├── fdt_strerror.c │ ├── fdt_sw.c │ ├── fdt_wip.c │ ├── libfdt.h │ ├── libfdt_env.h │ ├── libfdt_internal.h │ └── version.lds ├── linux │ ├── compiler.h │ ├── const.h │ ├── efi.h │ ├── pci_regs.h │ └── psci.h ├── list.h ├── pci-edu.c ├── pci-edu.h ├── pci-host-generic.c ├── pci-host-generic.h ├── pci-testdev.c ├── pci.c ├── pci.h ├── powerpc │ ├── .gitignore │ ├── asm │ │ ├── handlers.h │ │ ├── hcall.h │ │ ├── memory_areas.h │ │ ├── ppc_asm.h │ │ ├── processor.h │ │ ├── rtas.h │ │ ├── setup.h │ │ ├── smp.h │ │ └── stack.h │ ├── handlers.c │ ├── hcall.c │ ├── io.c │ ├── io.h │ ├── processor.c │ ├── rtas.c │ ├── setup.c │ └── smp.c ├── ppc64 │ ├── .gitignore │ ├── asm-offsets.c │ └── asm │ │ ├── asm-offsets.h │ │ ├── barrier.h │ │ ├── bitops.h │ │ ├── handlers.h │ │ ├── hcall.h │ │ ├── io.h │ │ ├── memory_areas.h │ │ ├── page.h │ │ ├── ppc_asm.h │ │ ├── processor.h │ │ ├── ptrace.h │ │ ├── rtas.h │ │ ├── setup.h │ │ ├── smp.h │ │ ├── spinlock.h │ │ └── stack.h ├── printf.c ├── report.c ├── s390x │ ├── .gitignore │ ├── asm-offsets.c │ ├── asm │ │ ├── arch_def.h │ │ ├── asm-offsets.h │ │ ├── barrier.h │ │ ├── bitops.h │ │ ├── cmm.h │ │ ├── cpacf.h │ │ ├── facility.h │ │ ├── float.h │ │ ├── interrupt.h │ │ ├── io.h │ │ ├── mem.h │ │ ├── memory_areas.h │ │ ├── page.h │ │ ├── pgtable.h │ │ ├── sigp.h │ │ ├── spinlock.h │ │ ├── stack.h │ │ ├── time.h │ │ ├── uv.h │ │ └── vector.h │ ├── css.h │ ├── css_dump.c │ ├── css_lib.c │ ├── fault.c │ ├── fault.h │ ├── gs.h │ ├── hardware.c │ ├── hardware.h │ ├── interrupt.c │ ├── interrupt.h │ ├── io.c │ ├── malloc_io.c │ ├── malloc_io.h │ ├── mmu.c │ ├── mmu.h │ ├── sclp-console.c │ ├── sclp.c │ ├── sclp.h │ ├── sie.c │ ├── sie.h │ ├── smp.c │ ├── smp.h │ ├── snippet.h │ ├── stack.c │ ├── stsi.h │ ├── uv.c │ └── uv.h ├── setjmp.h ├── stack.c ├── stack.h ├── stdlib.h ├── string.c ├── string.h ├── util.c ├── util.h ├── virtio-mmio.c ├── virtio-mmio.h ├── virtio.c ├── virtio.h ├── vmalloc.c ├── vmalloc.h └── x86 │ ├── acpi.c │ ├── acpi.h │ ├── amd_sev.c │ ├── amd_sev.h │ ├── apic-defs.h │ ├── apic.c │ ├── apic.h │ ├── asm │ ├── barrier.h │ ├── bitops.h │ ├── debugreg.h │ ├── io.h │ ├── memory_areas.h │ ├── page.h │ ├── pci.h │ ├── setup.h │ ├── spinlock.h │ └── stack.h │ ├── atomic.c │ ├── atomic.h │ ├── delay.c │ ├── delay.h │ ├── desc.c │ ├── desc.h │ ├── fault_test.c │ ├── fault_test.h │ ├── fwcfg.c │ ├── fwcfg.h │ ├── intel-iommu.c │ ├── intel-iommu.h │ ├── io.c │ ├── isr.c │ ├── isr.h │ ├── msr.h │ ├── processor.h │ ├── setjmp32.S │ ├── setjmp64.S │ ├── setup.c │ ├── smp.c │ ├── smp.h │ ├── stack.c │ ├── usermode.c │ ├── usermode.h │ ├── vm.c │ └── vm.h ├── powerpc ├── .gitignore ├── Makefile ├── Makefile.common ├── Makefile.ppc64 ├── boot_rom.S ├── cstart64.S ├── emulator.c ├── flat.lds ├── reloc64.c ├── rtas.c ├── run ├── selftest.c ├── spapr.h ├── spapr_hcall.c ├── sprs.c ├── tm.c └── unittests.cfg ├── run_tests.sh ├── s390x ├── Makefile ├── adtl-status.c ├── cmm.c ├── cpu.S ├── cpumodel.c ├── css.c ├── cstart64.S ├── diag10.c ├── diag288.c ├── diag308.c ├── edat.c ├── emulator.c ├── epsw.c ├── firq.c ├── flat.lds ├── gs.c ├── iep.c ├── intercept.c ├── macros.S ├── migration-cmm.c ├── migration-skey.c ├── migration.c ├── mvpg-sie.c ├── mvpg.c ├── pfmf.c ├── pv-attest.c ├── pv-diags.c ├── run ├── sck.c ├── sclp.c ├── selftest.c ├── selftest.parmfile ├── sie.c ├── sieve.c ├── skey.c ├── skrf.c ├── smp.c ├── snippets │ ├── asm │ │ ├── snippet-pv-diag-288.S │ │ ├── snippet-pv-diag-500.S │ │ └── snippet-pv-diag-yield.S │ └── c │ │ ├── cstart.S │ │ ├── flat.lds │ │ ├── mvpg-snippet.c │ │ └── spec_ex.c ├── spec_ex-sie.c ├── sthyi.c ├── sthyi.h ├── stsi.c ├── tprot.c ├── unittests.cfg ├── uv-guest.c ├── uv-host.c └── vector.c ├── scripts ├── arch-run.bash ├── asm-offsets.mak ├── common.bash ├── get_maintainer.pl ├── git.difforder ├── mkstandalone.sh ├── pretty_print_stacks.py ├── runtime.bash └── s390x │ └── func.bash └── x86 ├── Makefile ├── Makefile.common ├── Makefile.i386 ├── Makefile.x86_64 ├── README ├── access.c ├── access.h ├── access_test.c ├── amd_sev.c ├── apic.c ├── asyncpf.c ├── cet.c ├── cmpxchg8b.c ├── cstart.S ├── cstart64.S ├── debug.c ├── dummy.c ├── efi ├── README.md ├── crt0-efi-x86_64.S ├── efistart64.S ├── elf_x86_64_efi.lds ├── reloc_x86_64.c └── run ├── emulator.c ├── eventinj.c ├── flat.lds ├── hello_acrn.c ├── hypercall.c ├── hyperv.c ├── hyperv.h ├── hyperv_clock.c ├── hyperv_connections.c ├── hyperv_stimer.c ├── hyperv_synic.c ├── idt_test.c ├── init.c ├── intel-iommu.c ├── ioapic.c ├── ioram.h ├── kvmclock.c ├── kvmclock.h ├── kvmclock_test.c ├── la57.c ├── memory.c ├── msr.c ├── pcid.c ├── pks.c ├── pku.c ├── pmu.c ├── pmu_lbr.c ├── rdpru.c ├── realmode.c ├── realmode.lds ├── rmap_chain.c ├── run ├── s3.c ├── setjmp.c ├── sieve.c ├── smap.c ├── smptest.c ├── svm.c ├── svm.h ├── svm_npt.c ├── svm_tests.c ├── syscall.c ├── taskswitch.c ├── taskswitch2.c ├── trampolines.S ├── tsc.c ├── tsc_adjust.c ├── tscdeadline_latency.c ├── tsx-ctrl.c ├── types.h ├── umip.c ├── unittests.cfg ├── vmexit.c ├── vmware_backdoors.c ├── vmx.c ├── vmx.h ├── vmx_tests.c └── xsave.c /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is a file format and collection of text editor plugins 2 | # for maintaining consistent coding styles between different editors 3 | # and IDEs. Most popular editors support this either natively or via 4 | # plugin. 5 | # 6 | # Check https://editorconfig.org for details. 7 | 8 | root = true 9 | 10 | [*] 11 | end_of_line = lf 12 | insert_final_newline = true 13 | charset = utf-8 14 | indent_style = tab 15 | indent_size = 8 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tags 2 | .gdbinit 3 | *.a 4 | *.d 5 | *.o 6 | *.so 7 | *.flat 8 | *.efi 9 | *.elf 10 | *.patch 11 | .pc 12 | patches 13 | .stgit-* 14 | cscope.* 15 | *.swp 16 | /lib/asm 17 | /lib/config.h 18 | /config.mak 19 | /*-run 20 | /msr.out 21 | /tests 22 | /build-head 23 | /logs/ 24 | /logs.old/ 25 | /api/api-sample 26 | /api/dirty-log 27 | /api/dirty-log-perf 28 | /s390x/*.bin 29 | /s390x/snippets/*/*.gbin 30 | /efi-tests/* 31 | /s390x/snippets/*/*.hdr 32 | /s390x/snippets/*/*.*obj 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: focal 2 | language: c 3 | cache: ccache 4 | compiler: clang 5 | git: 6 | submodules: false 7 | 8 | jobs: 9 | include: 10 | 11 | - arch: arm64 12 | addons: 13 | apt_packages: qemu-system-aarch64 14 | env: 15 | - CONFIG="--arch=arm64 --cc=clang" 16 | - TESTS="cache gicv2-active gicv2-ipi gicv3-active gicv3-ipi 17 | pci-test pmu-cycle-counter pmu-event-counter-config pmu-sw-incr 18 | selftest-setup selftest-smp selftest-vectors-kernel 19 | selftest-vectors-user timer" 20 | 21 | - arch: ppc64le 22 | addons: 23 | apt_packages: clang-11 qemu-system-ppc 24 | env: 25 | - CONFIG="--arch=ppc64 --endian=little --cc=clang-11 --cflags=-no-integrated-as" 26 | - TESTS="emulator rtas-get-time-of-day rtas-get-time-of-day-base 27 | rtas-set-time-of-day selftest-setup spapr_hcall" 28 | 29 | - arch: s390x 30 | addons: 31 | apt_packages: clang-11 qemu-system-s390x 32 | env: 33 | - CONFIG="--arch=s390x --cc=clang-11 --cflags=-no-integrated-as" 34 | - TESTS="" 35 | 36 | before_script: 37 | - mkdir -p build && cd build 38 | - $TRAVIS_BUILD_DIR/configure $CONFIG 39 | script: 40 | - make -j3 41 | - if [ -n "$TESTS" ]; then 42 | ACCEL="${ACCEL:-tcg}" ./run_tests.sh -v $TESTS | tee results.txt && 43 | grep -q PASS results.txt && ! grep -q FAIL results.txt ; 44 | fi 45 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | acrn-unit-test inherits from kvm-unit-tests and will keep kvm-unit-tests license. 2 | 3 | Copyright (C) 2006 Qumranet. 4 | Copyright (C) 2007-2017 by various contributors (see source files for details) 5 | Copyright (C) 2022 Intel Corporation 6 | 7 | The kvm-unit-tests are free software; the whole package can be redistributed 8 | and/or modified under the terms of the GNU General Public License version 2 9 | as published by the Free Software Foundation. 10 | 11 | Many files in this directory and its subdirectories are also licensed under 12 | the less restrictive GNU LGPL, version 2, or other compatible licenses. See 13 | the individual files for details. 14 | -------------------------------------------------------------------------------- /arm/Makefile: -------------------------------------------------------------------------------- 1 | include $(SRCDIR)/$(TEST_DIR)/Makefile.$(ARCH) 2 | -------------------------------------------------------------------------------- /arm/Makefile.arm: -------------------------------------------------------------------------------- 1 | # 2 | # arm makefile 3 | # 4 | # Authors: Andrew Jones 5 | # 6 | bits = 32 7 | ldarch = elf32-littlearm 8 | machine = -marm -mfpu=vfp 9 | 10 | # stack.o relies on frame pointers. 11 | KEEP_FRAME_POINTER := y 12 | 13 | CFLAGS += $(machine) 14 | CFLAGS += -mcpu=$(PROCESSOR) 15 | CFLAGS += -mno-unaligned-access 16 | 17 | ifeq ($(TARGET),qemu) 18 | arch_LDFLAGS = -Ttext=40010000 19 | else ifeq ($(TARGET),kvmtool) 20 | arch_LDFLAGS = -Ttext=80008000 21 | else 22 | $(error Unknown target $(TARGET)) 23 | endif 24 | 25 | define arch_elf_check = 26 | endef 27 | 28 | cstart.o = $(TEST_DIR)/cstart.o 29 | cflatobjs += lib/arm/spinlock.o 30 | cflatobjs += lib/arm/processor.o 31 | cflatobjs += lib/arm/stack.o 32 | cflatobjs += lib/ldiv32.o 33 | cflatobjs += lib/arm/ldivmod.o 34 | 35 | # arm specific tests 36 | tests = 37 | 38 | include $(SRCDIR)/$(TEST_DIR)/Makefile.common 39 | 40 | arch_clean: arm_clean 41 | -------------------------------------------------------------------------------- /arm/Makefile.arm64: -------------------------------------------------------------------------------- 1 | # 2 | # arm64 makefile 3 | # 4 | # Authors: Andrew Jones 5 | # 6 | bits = 64 7 | ldarch = elf64-littleaarch64 8 | 9 | arch_LDFLAGS = -pie -n 10 | arch_LDFLAGS += -z notext 11 | CFLAGS += -mstrict-align 12 | 13 | mno_outline_atomics := $(call cc-option, -mno-outline-atomics, "") 14 | CFLAGS += $(mno_outline_atomics) 15 | 16 | define arch_elf_check = 17 | $(if $(shell ! $(READELF) -rW $(1) >&/dev/null && echo "nok"), 18 | $(error $(shell $(READELF) -rW $(1) 2>&1))) 19 | $(if $(shell $(READELF) -rW $(1) | grep R_ | grep -v R_AARCH64_RELATIVE), 20 | $(error $(1) has unsupported reloc types)) 21 | endef 22 | 23 | cstart.o = $(TEST_DIR)/cstart64.o 24 | cflatobjs += lib/arm64/processor.o 25 | cflatobjs += lib/arm64/spinlock.o 26 | cflatobjs += lib/arm64/gic-v3-its.o lib/arm64/gic-v3-its-cmd.o 27 | 28 | OBJDIRS += lib/arm64 29 | 30 | # arm64 specific tests 31 | tests = $(TEST_DIR)/timer.flat 32 | tests += $(TEST_DIR)/micro-bench.flat 33 | tests += $(TEST_DIR)/cache.flat 34 | tests += $(TEST_DIR)/debug.flat 35 | 36 | include $(SRCDIR)/$(TEST_DIR)/Makefile.common 37 | 38 | arch_clean: arm_clean 39 | $(RM) lib/arm64/.*.d 40 | -------------------------------------------------------------------------------- /arm/pci-test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PCI bus operation test 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | 11 | #define NR_TESTS (PCI_TESTDEV_NUM_BARS * PCI_TESTDEV_NUM_TESTS) 12 | 13 | int main(void) 14 | { 15 | int ret; 16 | 17 | if (!pci_probe()) { 18 | printf("PCI bus probing failed, skipping tests...\n"); 19 | return report_summary(); 20 | } 21 | 22 | report_prefix_push("pci"); 23 | 24 | pci_print(); 25 | 26 | ret = pci_testdev(); 27 | if (ret == -1) 28 | report_skip("No PCI test device"); 29 | else 30 | report(ret >= NR_TESTS, "PCI test device passed %d/%d tests", 31 | ret > 0 ? ret : 0, NR_TESTS); 32 | 33 | return report_summary(); 34 | } 35 | -------------------------------------------------------------------------------- /arm/sieve.c: -------------------------------------------------------------------------------- 1 | ../x86/sieve.c -------------------------------------------------------------------------------- /arm/spinlock-test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Spinlock test 3 | * 4 | * This code is based on code from the tcg_baremetal_tests. 5 | * 6 | * Copyright (C) 2015 Virtual Open Systems SAS 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #define LOOP_SIZE 10000000 18 | 19 | struct lock_ops { 20 | void (*lock)(int *v); 21 | void (*unlock)(int *v); 22 | }; 23 | static struct lock_ops lock_ops; 24 | 25 | static void gcc_builtin_lock(int *lock_var) 26 | { 27 | while (__sync_lock_test_and_set(lock_var, 1)); 28 | } 29 | static void gcc_builtin_unlock(int *lock_var) 30 | { 31 | __sync_lock_release(lock_var); 32 | } 33 | static void none_lock(int *lock_var) 34 | { 35 | while (*(volatile int *)lock_var != 0); 36 | *(volatile int *)lock_var = 1; 37 | } 38 | static void none_unlock(int *lock_var) 39 | { 40 | *(volatile int *)lock_var = 0; 41 | } 42 | 43 | static int global_a, global_b; 44 | static int global_lock; 45 | 46 | static void test_spinlock(void *data __unused) 47 | { 48 | int i, errors = 0; 49 | int cpu = smp_processor_id(); 50 | 51 | printf("CPU%d online\n", cpu); 52 | 53 | for (i = 0; i < LOOP_SIZE; i++) { 54 | 55 | lock_ops.lock(&global_lock); 56 | 57 | if (global_a == (cpu + 1) % 2) { 58 | global_a = 1; 59 | global_b = 0; 60 | } else { 61 | global_a = 0; 62 | global_b = 1; 63 | } 64 | 65 | if (global_a == global_b) 66 | errors++; 67 | 68 | lock_ops.unlock(&global_lock); 69 | } 70 | report(errors == 0, "CPU%d: Done - Errors: %d", cpu, errors); 71 | } 72 | 73 | int main(int argc, char **argv) 74 | { 75 | report_prefix_push("spinlock"); 76 | if (argc > 1 && strcmp(argv[1], "bad") != 0) { 77 | lock_ops.lock = gcc_builtin_lock; 78 | lock_ops.unlock = gcc_builtin_unlock; 79 | } else { 80 | lock_ops.lock = none_lock; 81 | lock_ops.unlock = none_unlock; 82 | } 83 | 84 | on_cpus(test_spinlock, NULL); 85 | 86 | return report_summary(); 87 | } 88 | -------------------------------------------------------------------------------- /ci/cirrus-ci-fedora.yml: -------------------------------------------------------------------------------- 1 | 2 | fedora_task: 3 | container: 4 | image: fedora:latest 5 | cpu: 4 6 | memory: 4Gb 7 | kvm: true 8 | install_script: 9 | - dnf update -y 10 | - dnf install -y diffutils gcc git make qemu-system-x86 11 | clone_script: 12 | - git clone --depth 100 "@CI_REPOSITORY_URL@" . 13 | - git fetch origin "@CI_COMMIT_REF_NAME@" 14 | - git reset --hard "@CI_COMMIT_SHA@" 15 | script: 16 | - mkdir build 17 | - cd build 18 | - ../configure 19 | - make -j$(nproc) 20 | - ./run_tests.sh 21 | access 22 | asyncpf 23 | emulator 24 | ept 25 | hypercall 26 | hyperv_clock 27 | hyperv_connections 28 | hyperv_stimer 29 | hyperv_synic 30 | idt_test 31 | intel_iommu 32 | ioapic 33 | ioapic-split 34 | kvmclock_test 35 | msr 36 | pcid-asymmetric 37 | pcid-disabled 38 | pcid-enabled 39 | rdpru 40 | realmode 41 | rmap_chain 42 | s3 43 | setjmp 44 | sieve 45 | smptest 46 | smptest3 47 | syscall 48 | tsc 49 | tsc_adjust 50 | tsx-ctrl 51 | umip 52 | vmexit_cpuid 53 | vmexit_inl_pmtimer 54 | vmexit_ipi 55 | vmexit_ipi_halt 56 | vmexit_mov_from_cr8 57 | vmexit_mov_to_cr8 58 | vmexit_ple_round_robin 59 | vmexit_tscdeadline 60 | vmexit_tscdeadline_immed 61 | vmexit_vmcall 62 | vmx_apic_passthrough_thread 63 | vmx_apic_passthrough_tpr_threshold_test 64 | vmx_init_signal_test 65 | vmx_pf_exception_test 66 | vmx_sipi_signal_test 67 | xsave 68 | | tee results.txt 69 | - grep -q PASS results.txt && ! grep -q FAIL results.txt 70 | -------------------------------------------------------------------------------- /ci/cirrus-ci-macos-i386.yml: -------------------------------------------------------------------------------- 1 | 2 | macos_i386_task: 3 | osx_instance: 4 | image: big-sur-base 5 | install_script: 6 | - brew update 7 | - brew install coreutils bash git gnu-getopt make qemu i686-elf-gcc 8 | clone_script: 9 | - git clone --depth 100 "@CI_REPOSITORY_URL@" . 10 | - git fetch origin "@CI_COMMIT_REF_NAME@" 11 | - git reset --hard "@CI_COMMIT_SHA@" 12 | script: 13 | - export PATH="/usr/local/opt/gnu-getopt/bin:$PATH" 14 | - mkdir build 15 | - cd build 16 | - ../configure --arch=i386 --cross-prefix=i686-elf- 17 | - gmake -j$(sysctl -n hw.ncpu) 18 | - ACCEL=tcg ./run_tests.sh 19 | cmpxchg8b 20 | eventinj 21 | realmode 22 | setjmp 23 | sieve 24 | taskswitch 25 | tsc 26 | umip 27 | vmexit_cpuid 28 | vmexit_inl_pmtimer 29 | vmexit_ipi 30 | vmexit_ipi_halt 31 | vmexit_mov_from_cr8 32 | vmexit_mov_to_cr8 33 | vmexit_ple_round_robin 34 | vmexit_tscdeadline 35 | vmexit_tscdeadline_immed 36 | | tee results.txt 37 | - grep -q PASS results.txt && ! grep -q FAIL results.txt 38 | -------------------------------------------------------------------------------- /ci/cirrus-ci-macos-x86-64.yml: -------------------------------------------------------------------------------- 1 | 2 | macos_task: 3 | osx_instance: 4 | image: big-sur-base 5 | install_script: 6 | - brew update 7 | - brew install coreutils bash git gnu-getopt make qemu x86_64-elf-gcc 8 | clone_script: 9 | - git clone --depth 100 "@CI_REPOSITORY_URL@" . 10 | - git fetch origin "@CI_COMMIT_REF_NAME@" 11 | - git reset --hard "@CI_COMMIT_SHA@" 12 | script: 13 | - export PATH="/usr/local/opt/gnu-getopt/bin:$PATH" 14 | - mkdir build 15 | - cd build 16 | - ../configure --cross-prefix=x86_64-elf- 17 | - gmake -j$(sysctl -n hw.ncpu) 18 | - ACCEL=tcg ./run_tests.sh 19 | eventinj 20 | intel_iommu 21 | ioapic-split 22 | realmode 23 | rmap_chain 24 | setjmp 25 | sieve 26 | smptest 27 | smptest3 28 | syscall 29 | tsc 30 | umip 31 | vmexit_cpuid 32 | vmexit_inl_pmtimer 33 | vmexit_ipi 34 | vmexit_ipi_halt 35 | vmexit_mov_from_cr8 36 | vmexit_mov_to_cr8 37 | vmexit_ple_round_robin 38 | vmexit_tscdeadline 39 | vmexit_tscdeadline_immed 40 | | tee results.txt 41 | - grep -q PASS results.txt && ! grep -q FAIL results.txt 42 | -------------------------------------------------------------------------------- /errata.txt: -------------------------------------------------------------------------------- 1 | #---------------:-------------------------------:--------------------------------------------------- 2 | # commit : minimum kernel : summary 3 | # 12 hex digits : version : 4 | #---------------:-------------------------------:--------------------------------------------------- 5 | 9e3f7a296940 : 4.9 : arm64: KVM: pmu: Fix AArch32 cycle counter access 6 | 7b6b46311a85 : 4.11 : KVM: arm/arm64: Emulate the EL1 phys timer registers 7 | 6c7a5dce22b3 : 4.12 : KVM: arm/arm64: fix races in kvm_psci_vcpu_on 8 | 8c58be34494b : 5.6 : KVM: arm/arm64: vgic-its: Fix restoration of unmapped collections 9 | #---------------:-------------------------------:--------------------------------------------------- 10 | -------------------------------------------------------------------------------- /lib/abort.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 3 | * 4 | * This work is licensed under the terms of the GNU LGPL, version 2. 5 | */ 6 | #include "libcflat.h" 7 | 8 | /* 9 | * When exit(code) is invoked, qemu will exit with ((code << 1) | 1), 10 | * leaving us 128 exit status codes. To avoid confusion with signal 11 | * status, we further limit exit codes to those resulting in qemu 12 | * exiting with a status < 128. We give abort() the highest (127), 13 | * leaving the lower status codes for unit tests. 14 | */ 15 | #define ABORT_EXIT_STATUS 63 /* 127 exit status from qemu */ 16 | 17 | void abort(void) 18 | { 19 | exit(ABORT_EXIT_STATUS); 20 | } 21 | -------------------------------------------------------------------------------- /lib/alloc.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void *malloc(size_t size) 8 | { 9 | return memalign(sizeof(long), size); 10 | } 11 | 12 | void *calloc(size_t nmemb, size_t size) 13 | { 14 | void *ptr; 15 | 16 | assert(!check_mul_overflow(nmemb, size)); 17 | ptr = malloc(nmemb * size); 18 | if (ptr) 19 | memset(ptr, 0, nmemb * size); 20 | return ptr; 21 | } 22 | 23 | void free(void *ptr) 24 | { 25 | if (alloc_ops->free) 26 | alloc_ops->free(ptr); 27 | } 28 | 29 | void *memalign(size_t alignment, size_t size) 30 | { 31 | void *p; 32 | 33 | if (!size) 34 | return NULL; 35 | 36 | assert(is_power_of_2(alignment)); 37 | assert(alloc_ops && alloc_ops->memalign); 38 | 39 | p = alloc_ops->memalign(alignment, size); 40 | assert(p); 41 | 42 | return (void *)p; 43 | } 44 | -------------------------------------------------------------------------------- /lib/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef _ALLOC_H_ 2 | #define _ALLOC_H_ 3 | /* 4 | * alloc supplies three ingredients to the test framework that are all 5 | * related to the support of dynamic memory allocation. 6 | * 7 | * The first is a set of alloc function wrappers for malloc and its 8 | * friends. Using wrappers allows test code and common code to use the 9 | * same interface for memory allocation at all stages, even though the 10 | * implementations may change with the stage, e.g. pre/post paging. 11 | * 12 | * The second is a set of implementations for the alloc function 13 | * interfaces. These implementations are named early_*, as they can be 14 | * used almost immediately by the test framework. 15 | * 16 | * The third is a very simple physical memory allocator, which the 17 | * early_* alloc functions build on. 18 | * 19 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 20 | * 21 | * This work is licensed under the terms of the GNU LGPL, version 2. 22 | */ 23 | #include "libcflat.h" 24 | 25 | struct alloc_ops { 26 | void *(*memalign)(size_t alignment, size_t size); 27 | void (*free)(void *ptr); 28 | }; 29 | 30 | extern struct alloc_ops *alloc_ops; 31 | 32 | void *malloc(size_t size); 33 | void *calloc(size_t nmemb, size_t size); 34 | void free(void *ptr); 35 | void *memalign(size_t alignment, size_t size); 36 | 37 | #endif /* _ALLOC_H_ */ 38 | -------------------------------------------------------------------------------- /lib/alloc_phys.h: -------------------------------------------------------------------------------- 1 | #ifndef _ALLOC_PHYS_H_ 2 | #define _ALLOC_PHYS_H_ 3 | /* 4 | * phys_alloc is a very simple allocator which allows physical memory 5 | * to be partitioned into regions until all memory is allocated. 6 | * 7 | * Note: This is such a simple allocator that there is no way to free 8 | * a region. For more complicated memory management a single region 9 | * can be allocated, but then have its memory managed by a more 10 | * sophisticated allocator, e.g. a page allocator. 11 | * 12 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 13 | * 14 | * This work is licensed under the terms of the GNU LGPL, version 2. 15 | */ 16 | #include "libcflat.h" 17 | 18 | #define DEFAULT_MINIMUM_ALIGNMENT 32 19 | 20 | /* 21 | * phys_alloc_init creates the initial free memory region of size @size 22 | * at @base. The minimum alignment is set to DEFAULT_MINIMUM_ALIGNMENT. 23 | */ 24 | extern void phys_alloc_init(phys_addr_t base, phys_addr_t size); 25 | 26 | /* 27 | * phys_alloc_set_minimum_alignment sets the minimum alignment to 28 | * @align. 29 | */ 30 | extern void phys_alloc_set_minimum_alignment(phys_addr_t align); 31 | 32 | /* 33 | * phys_alloc_show outputs all currently allocated regions with the 34 | * following format 35 | * - [] 36 | */ 37 | extern void phys_alloc_show(void); 38 | 39 | /* 40 | * phys_alloc_get_unused allocates all remaining memory from the region 41 | * passed to phys_alloc_init, returning the newly allocated memory's base 42 | * and top addresses. phys_alloc_get_unused will still return base and top 43 | * when no free memory is remaining, but base will equal top. 44 | */ 45 | extern void phys_alloc_get_unused(phys_addr_t *p_base, phys_addr_t *p_top); 46 | 47 | /* 48 | * Search for memory that can only be used when the MMU is on, and reinitialize 49 | * the physical memory allocator using it. 50 | */ 51 | extern void find_highmem(void); 52 | 53 | #endif /* _ALLOC_PHYS_H_ */ 54 | -------------------------------------------------------------------------------- /lib/argv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Set up arguments for main() and prepare environment variables 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | 8 | #ifndef _ARGV_H_ 9 | #define _ARGV_H_ 10 | 11 | extern void __setup_args(void); 12 | extern void setup_args_progname(const char *args); 13 | extern void setup_env(char *env, int size); 14 | extern void add_setup_arg(const char *arg); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /lib/arm/.gitignore: -------------------------------------------------------------------------------- 1 | asm-offsets.[hs] 2 | -------------------------------------------------------------------------------- /lib/arm/asm-offsets.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from arch/arm/kernel/asm-offsets.c 3 | * 4 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU GPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | 12 | int main(void) 13 | { 14 | OFFSET(S_R0, pt_regs, ARM_r0); 15 | OFFSET(S_R1, pt_regs, ARM_r1); 16 | OFFSET(S_R2, pt_regs, ARM_r2); 17 | OFFSET(S_R3, pt_regs, ARM_r3); 18 | OFFSET(S_R4, pt_regs, ARM_r4); 19 | OFFSET(S_R5, pt_regs, ARM_r5); 20 | OFFSET(S_R6, pt_regs, ARM_r6); 21 | OFFSET(S_R7, pt_regs, ARM_r7); 22 | OFFSET(S_R8, pt_regs, ARM_r8); 23 | OFFSET(S_R9, pt_regs, ARM_r9); 24 | OFFSET(S_R10, pt_regs, ARM_r10); 25 | OFFSET(S_FP, pt_regs, ARM_fp); 26 | OFFSET(S_IP, pt_regs, ARM_ip); 27 | OFFSET(S_SP, pt_regs, ARM_sp); 28 | OFFSET(S_LR, pt_regs, ARM_lr); 29 | OFFSET(S_PC, pt_regs, ARM_pc); 30 | OFFSET(S_PSR, pt_regs, ARM_cpsr); 31 | OFFSET(S_OLD_R0, pt_regs, ARM_ORIG_r0); 32 | DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /lib/arm/asm/arch_gicv3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * All ripped off from arch/arm/include/asm/arch_gicv3.h 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #ifndef _ASMARM_ARCH_GICV3_H_ 9 | #define _ASMARM_ARCH_GICV3_H_ 10 | 11 | #ifndef __ASSEMBLY__ 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0) 18 | #define ICC_SGI1R __ACCESS_CP15_64(0, c12) 19 | #define ICC_IAR1 __ACCESS_CP15(c12, 0, c12, 0) 20 | #define ICC_EOIR1 __ACCESS_CP15(c12, 0, c12, 1) 21 | #define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) 22 | 23 | static inline void gicv3_write_pmr(u32 val) 24 | { 25 | write_sysreg(val, ICC_PMR); 26 | } 27 | 28 | static inline void gicv3_write_sgi1r(u64 val) 29 | { 30 | write_sysreg(val, ICC_SGI1R); 31 | } 32 | 33 | static inline u32 gicv3_read_iar(void) 34 | { 35 | u32 irqstat = read_sysreg(ICC_IAR1); 36 | dsb(sy); 37 | return irqstat; 38 | } 39 | 40 | static inline void gicv3_write_eoir(u32 irq) 41 | { 42 | write_sysreg(irq, ICC_EOIR1); 43 | isb(); 44 | } 45 | 46 | static inline void gicv3_write_grpen1(u32 val) 47 | { 48 | write_sysreg(val, ICC_IGRPEN1); 49 | isb(); 50 | } 51 | 52 | /* 53 | * We may access GICR_TYPER and GITS_TYPER by reading both the TYPER 54 | * offset and the following offset (+ 4) and then combining them to 55 | * form a 64-bit address. 56 | */ 57 | static inline u64 gicv3_read_typer(const volatile void __iomem *addr) 58 | { 59 | u64 val = readl(addr); 60 | val |= (u64)readl(addr + 4) << 32; 61 | return val; 62 | } 63 | 64 | #endif /* !__ASSEMBLY__ */ 65 | #endif /* _ASMARM_ARCH_GICV3_H_ */ 66 | -------------------------------------------------------------------------------- /lib/arm/asm/asm-offsets.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /lib/arm/asm/assembler.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Based on several files from Linux version v5.10: arch/arm/mm/proc-macros.S, 4 | * arch/arm/mm/proc-v7.S. 5 | */ 6 | 7 | #ifndef __ASSEMBLY__ 8 | #error "Only include this from assembly code" 9 | #endif 10 | 11 | #ifndef _ASMARM_ASSEMBLER_H_ 12 | #define _ASMARM_ASSEMBLER_H_ 13 | 14 | /* 15 | * dcache_line_size - get the minimum D-cache line size from the CTR register 16 | * on ARMv7. 17 | */ 18 | .macro dcache_line_size, reg, tmp 19 | mrc p15, 0, \tmp, c0, c0, 1 // read ctr 20 | lsr \tmp, \tmp, #16 21 | and \tmp, \tmp, #0xf // cache line size encoding 22 | mov \reg, #4 // bytes per word 23 | mov \reg, \reg, lsl \tmp // actual cache line size 24 | .endm 25 | 26 | /* 27 | * Macro to perform a data cache maintenance for the interval 28 | * [addr, addr + size). 29 | * 30 | * op: operation to execute 31 | * domain domain used in the dsb instruction 32 | * addr: starting virtual address of the region 33 | * size: size of the region 34 | * Corrupts: addr, size, tmp1, tmp2 35 | */ 36 | .macro dcache_by_line_op op, domain, addr, size, tmp1, tmp2 37 | dcache_line_size \tmp1, \tmp2 38 | add \size, \addr, \size 39 | sub \tmp2, \tmp1, #1 40 | bic \addr, \addr, \tmp2 41 | 9998: 42 | .ifc \op, dccimvac 43 | mcr p15, 0, \addr, c7, c14, 1 44 | .else 45 | .err 46 | .endif 47 | add \addr, \addr, \tmp1 48 | cmp \addr, \size 49 | blo 9998b 50 | dsb \domain 51 | .endm 52 | 53 | #endif /* _ASMARM_ASSEMBLER_H_ */ 54 | -------------------------------------------------------------------------------- /lib/arm/asm/barrier.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_BARRIER_H_ 2 | #define _ASMARM_BARRIER_H_ 3 | /* 4 | * Adapted from arch/arm/include/asm/barrier.h 5 | * 6 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 7 | * 8 | * This work is licensed under the terms of the GNU GPL, version 2. 9 | */ 10 | 11 | #define sev() asm volatile("sev" : : : "memory") 12 | #define wfe() asm volatile("wfe" : : : "memory") 13 | #define wfi() asm volatile("wfi" : : : "memory") 14 | #define yield() asm volatile("yield" : : : "memory") 15 | #define cpu_relax() yield() 16 | 17 | #define isb(option) __asm__ __volatile__ ("isb " #option : : : "memory") 18 | #define dsb(option) __asm__ __volatile__ ("dsb " #option : : : "memory") 19 | #define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory") 20 | 21 | #define mb() dsb() 22 | #define rmb() dsb() 23 | #define wmb() dsb(st) 24 | #define smp_mb() dmb(ish) 25 | #define smp_rmb() smp_mb() 26 | #define smp_wmb() dmb(ishst) 27 | 28 | #endif /* _ASMARM_BARRIER_H_ */ 29 | -------------------------------------------------------------------------------- /lib/arm/asm/bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_BITOPS_H_ 2 | #define _ASMARM_BITOPS_H_ 3 | /* 4 | * Adapted from 5 | * arch/arm/lib/bitops.h 6 | * 7 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 8 | * 9 | * This work is licensed under the terms of the GNU GPL, version 2. 10 | */ 11 | 12 | #ifndef _BITOPS_H_ 13 | #error only can be included directly 14 | #endif 15 | 16 | #define BITS_PER_LONG 32 17 | 18 | #define HAVE_BUILTIN_FLS 1 19 | 20 | #define ATOMIC_BITOP(insn, mask, word) \ 21 | ({ \ 22 | unsigned long tmp1, tmp2; \ 23 | asm volatile( \ 24 | "1: ldrex %0, [%2]\n" \ 25 | insn" %0, %0, %3\n" \ 26 | " strex %1, %0, [%2]\n" \ 27 | " cmp %1, #0\n" \ 28 | " bne 1b\n" \ 29 | : "=&r" (tmp1), "=&r" (tmp2) \ 30 | : "r" (word), "r" (mask) \ 31 | : "cc"); \ 32 | }) 33 | 34 | #define ATOMIC_TESTOP(insn, mask, word, old) \ 35 | ({ \ 36 | unsigned long tmp1, tmp2; \ 37 | asm volatile( \ 38 | "1: ldrex %0, [%3]\n" \ 39 | " and %1, %0, %4\n" \ 40 | insn" %0, %0, %4\n" \ 41 | " strex %2, %0, [%3]\n" \ 42 | " cmp %2, #0\n" \ 43 | " bne 1b\n" \ 44 | : "=&r" (tmp1), "=&r" (old), "=&r" (tmp2) \ 45 | : "r" (word), "r" (mask) \ 46 | : "cc"); \ 47 | }) 48 | 49 | extern void set_bit(int nr, volatile unsigned long *addr); 50 | extern void clear_bit(int nr, volatile unsigned long *addr); 51 | extern int test_bit(int nr, const volatile unsigned long *addr); 52 | extern int test_and_set_bit(int nr, volatile unsigned long *addr); 53 | extern int test_and_clear_bit(int nr, volatile unsigned long *addr); 54 | 55 | #endif /* _ASMARM_BITOPS_H_ */ 56 | -------------------------------------------------------------------------------- /lib/arm/asm/delay.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_DELAY_H_ 2 | #define _ASMARM_DELAY_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | 10 | extern void delay(u64 cycles); 11 | extern void udelay(unsigned long usecs); 12 | extern void mdelay(unsigned long msecs); 13 | 14 | #endif /* _ASMARM_DELAY_H_ */ 15 | -------------------------------------------------------------------------------- /lib/arm/asm/gic-v2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * All GIC* defines are lifted from include/linux/irqchip/arm-gic.h 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #ifndef _ASMARM_GIC_V2_H_ 9 | #define _ASMARM_GIC_V2_H_ 10 | 11 | #ifndef _ASMARM_GIC_H_ 12 | #error Do not directly include . Include 13 | #endif 14 | 15 | #define GICD_ENABLE 0x1 16 | 17 | #define GICC_ENABLE 0x1 18 | #define GICC_IAR_INT_ID_MASK 0x3ff 19 | 20 | #ifndef __ASSEMBLY__ 21 | #include 22 | 23 | struct gicv2_data { 24 | void *dist_base; 25 | void *cpu_base; 26 | unsigned int irq_nr; 27 | }; 28 | extern struct gicv2_data gicv2_data; 29 | 30 | #define gicv2_dist_base() (gicv2_data.dist_base) 31 | #define gicv2_cpu_base() (gicv2_data.cpu_base) 32 | 33 | extern int gicv2_init(void); 34 | extern void gicv2_enable_defaults(void); 35 | extern u32 gicv2_read_iar(void); 36 | extern u32 gicv2_iar_irqnr(u32 iar); 37 | extern void gicv2_write_eoir(u32 irqstat); 38 | extern void gicv2_ipi_send_single(int irq, int cpu); 39 | extern void gicv2_ipi_send_mask(int irq, const cpumask_t *dest); 40 | 41 | #endif /* !__ASSEMBLY__ */ 42 | #endif /* _ASMARM_GIC_V2_H_ */ 43 | -------------------------------------------------------------------------------- /lib/arm/asm/gic-v3-its.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ITS 32-bit stubs 3 | * 4 | * Copyright (C) 2020, Red Hat Inc, Eric Auger 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #ifndef _ASMARM_GIC_V3_ITS_H_ 9 | #define _ASMARM_GIC_V3_ITS_H_ 10 | 11 | #ifndef _ASMARM_GIC_H_ 12 | #error Do not directly include . Include 13 | #endif 14 | 15 | #include 16 | 17 | /* dummy its_data struct to allow gic_get_dt_bases() call */ 18 | struct its_data { 19 | void *base; 20 | }; 21 | 22 | static inline void its_init(void) 23 | { 24 | assert_msg(false, "not supported on 32-bit"); 25 | } 26 | 27 | #endif /* _ASMARM_GIC_V3_ITS_H_ */ 28 | -------------------------------------------------------------------------------- /lib/arm/asm/memory_areas.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_MEMORY_AREAS_H_ 2 | #define _ASMARM_MEMORY_AREAS_H_ 3 | 4 | #include 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /lib/arm/asm/mmu-api.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_MMU_API_H_ 2 | #define _ASMARM_MMU_API_H_ 3 | 4 | #include 5 | #include 6 | 7 | extern pgd_t *mmu_idmap; 8 | extern bool mmu_enabled(void); 9 | extern void mmu_mark_enabled(int cpu); 10 | extern void mmu_mark_disabled(int cpu); 11 | extern void mmu_enable(pgd_t *pgtable); 12 | extern void mmu_disable(void); 13 | 14 | extern void mmu_set_range_sect(pgd_t *pgtable, uintptr_t virt_offset, 15 | phys_addr_t phys_start, phys_addr_t phys_end, 16 | pgprot_t prot); 17 | extern void mmu_set_range_ptes(pgd_t *pgtable, uintptr_t virt_offset, 18 | phys_addr_t phys_start, phys_addr_t phys_end, 19 | pgprot_t prot); 20 | extern pteval_t *mmu_get_pte(pgd_t *pgtable, uintptr_t vaddr); 21 | extern void mmu_clear_user(pgd_t *pgtable, unsigned long vaddr); 22 | #endif 23 | -------------------------------------------------------------------------------- /lib/arm/asm/mmu.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_MMU_H_ 2 | #define _ASMARM_MMU_H_ 3 | /* 4 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | 10 | #define PTE_USER L_PTE_USER 11 | #define PTE_UXN L_PTE_XN 12 | #define PTE_PXN L_PTE_PXN 13 | #define PTE_RDONLY PTE_AP2 14 | #define PTE_SHARED L_PTE_SHARED 15 | #define PTE_AF PTE_EXT_AF 16 | #define PTE_WBWA L_PTE_MT_WRITEALLOC 17 | #define PTE_UNCACHED L_PTE_MT_UNCACHED 18 | 19 | /* See B3.18.7 TLB maintenance operations */ 20 | 21 | static inline void local_flush_tlb_all(void) 22 | { 23 | dsb(nshst); 24 | /* TLBIALL */ 25 | asm volatile("mcr p15, 0, %0, c8, c7, 0" :: "r" (0)); 26 | dsb(nsh); 27 | isb(); 28 | } 29 | 30 | static inline void flush_tlb_all(void) 31 | { 32 | dsb(ishst); 33 | /* TLBIALLIS */ 34 | asm volatile("mcr p15, 0, %0, c8, c3, 0" :: "r" (0)); 35 | dsb(ish); 36 | isb(); 37 | } 38 | 39 | static inline void flush_tlb_page(unsigned long vaddr) 40 | { 41 | dsb(ishst); 42 | /* TLBIMVAAIS */ 43 | asm volatile("mcr p15, 0, %0, c8, c3, 3" :: "r" (vaddr)); 44 | dsb(ish); 45 | isb(); 46 | } 47 | 48 | static inline void flush_dcache_addr(unsigned long vaddr) 49 | { 50 | /* DCCIMVAC */ 51 | asm volatile("mcr p15, 0, %0, c7, c14, 1" :: "r" (vaddr)); 52 | } 53 | 54 | #include 55 | 56 | #endif /* _ASMARM_MMU_H_ */ 57 | -------------------------------------------------------------------------------- /lib/arm/asm/page.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_PAGE_H_ 2 | #define _ASMARM_PAGE_H_ 3 | /* 4 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | #include 10 | 11 | #define PAGE_SHIFT 12 12 | #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) 13 | #define PAGE_MASK (~(PAGE_SIZE-1)) 14 | 15 | #ifndef __ASSEMBLY__ 16 | 17 | #define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) 18 | 19 | typedef u64 pteval_t; 20 | typedef u64 pmdval_t; 21 | typedef u64 pgdval_t; 22 | typedef struct { pteval_t pte; } pte_t; 23 | typedef struct { pmdval_t pmd; } pmd_t; 24 | typedef struct { pgdval_t pgd; } pgd_t; 25 | typedef struct { pteval_t pgprot; } pgprot_t; 26 | 27 | #define pte_val(x) ((x).pte) 28 | #define pmd_val(x) ((x).pmd) 29 | #define pgd_val(x) ((x).pgd) 30 | #define pgprot_val(x) ((x).pgprot) 31 | 32 | /* For compatibility with arm64 page tables */ 33 | #define pud_t pgd_t 34 | #define pud_val(x) pgd_val(x) 35 | 36 | #define __pte(x) ((pte_t) { (x) } ) 37 | #define __pmd(x) ((pmd_t) { (x) } ) 38 | #define __pgd(x) ((pgd_t) { (x) } ) 39 | #define __pgprot(x) ((pgprot_t) { (x) } ) 40 | 41 | #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) 42 | #define __pa(x) __virt_to_phys((unsigned long)(x)) 43 | 44 | #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) 45 | #define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) 46 | 47 | extern phys_addr_t __virt_to_phys(unsigned long addr); 48 | extern unsigned long __phys_to_virt(phys_addr_t addr); 49 | 50 | extern void *__ioremap(phys_addr_t phys_addr, size_t size); 51 | 52 | #endif /* !__ASSEMBLY__ */ 53 | #endif /* _ASMARM_PAGE_H_ */ 54 | -------------------------------------------------------------------------------- /lib/arm/asm/pci.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /lib/arm/asm/psci.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_PSCI_H_ 2 | #define _ASMARM_PSCI_H_ 3 | #include 4 | #include 5 | 6 | typedef int (*psci_invoke_fn)(unsigned int function_id, unsigned long arg0, 7 | unsigned long arg1, unsigned long arg2); 8 | extern psci_invoke_fn psci_invoke; 9 | extern int psci_invoke_hvc(unsigned int function_id, unsigned long arg0, 10 | unsigned long arg1, unsigned long arg2); 11 | extern int psci_invoke_smc(unsigned int function_id, unsigned long arg0, 12 | unsigned long arg1, unsigned long arg2); 13 | extern void psci_set_conduit(void); 14 | extern int psci_cpu_on(unsigned long cpuid, unsigned long entry_point); 15 | extern void psci_system_reset(void); 16 | extern int cpu_psci_cpu_boot(unsigned int cpu); 17 | extern void cpu_psci_cpu_die(void); 18 | extern void psci_system_off(void); 19 | 20 | #endif /* _ASMARM_PSCI_H_ */ 21 | -------------------------------------------------------------------------------- /lib/arm/asm/setup.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_SETUP_H_ 2 | #define _ASMARM_SETUP_H_ 3 | /* 4 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | 12 | #define NR_CPUS 511 13 | extern u64 cpus[NR_CPUS]; /* per-cpu IDs (MPIDRs) */ 14 | extern int nr_cpus; 15 | 16 | #define MR_F_IO (1U << 0) 17 | #define MR_F_CODE (1U << 1) 18 | #define MR_F_UNKNOWN (1U << 31) 19 | 20 | struct mem_region { 21 | phys_addr_t start; 22 | phys_addr_t end; 23 | unsigned int flags; 24 | }; 25 | extern struct mem_region *mem_regions; 26 | extern phys_addr_t __phys_offset, __phys_end; 27 | 28 | extern struct mem_region *mem_region_find(phys_addr_t paddr); 29 | extern unsigned int mem_region_get_flags(phys_addr_t paddr); 30 | 31 | #define PHYS_OFFSET (__phys_offset) 32 | #define PHYS_END (__phys_end) 33 | 34 | #define L1_CACHE_SHIFT 6 35 | #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) 36 | #define SMP_CACHE_BYTES L1_CACHE_BYTES 37 | 38 | void setup(const void *fdt, phys_addr_t freemem_start); 39 | 40 | #endif /* _ASMARM_SETUP_H_ */ 41 | -------------------------------------------------------------------------------- /lib/arm/asm/smp.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_SMP_H_ 2 | #define _ASMARM_SMP_H_ 3 | /* 4 | * Copyright (C) 2015, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | 11 | #define smp_processor_id() (current_thread_info()->cpu) 12 | 13 | extern bool cpu0_calls_idle; 14 | 15 | extern void halt(void); 16 | extern void do_idle(void); 17 | 18 | extern cpumask_t cpu_present_mask; 19 | extern cpumask_t cpu_online_mask; 20 | extern cpumask_t cpu_idle_mask; 21 | #define cpu_present(cpu) cpumask_test_cpu(cpu, &cpu_present_mask) 22 | #define cpu_online(cpu) cpumask_test_cpu(cpu, &cpu_online_mask) 23 | #define cpu_idle(cpu) cpumask_test_cpu(cpu, &cpu_idle_mask) 24 | #define for_each_present_cpu(cpu) for_each_cpu(cpu, &cpu_present_mask) 25 | #define for_each_online_cpu(cpu) for_each_cpu(cpu, &cpu_online_mask) 26 | 27 | static inline void set_cpu_present(int cpu, bool present) 28 | { 29 | if (present) 30 | cpumask_set_cpu(cpu, &cpu_present_mask); 31 | else 32 | cpumask_clear_cpu(cpu, &cpu_present_mask); 33 | } 34 | 35 | static inline void set_cpu_online(int cpu, bool online) 36 | { 37 | if (online) 38 | cpumask_set_cpu(cpu, &cpu_online_mask); 39 | else 40 | cpumask_clear_cpu(cpu, &cpu_online_mask); 41 | } 42 | 43 | static inline void set_cpu_idle(int cpu, bool idle) 44 | { 45 | if (idle) 46 | cpumask_set_cpu(cpu, &cpu_idle_mask); 47 | else 48 | cpumask_clear_cpu(cpu, &cpu_idle_mask); 49 | } 50 | 51 | typedef void (*secondary_entry_fn)(void); 52 | extern void smp_boot_secondary(int cpu, secondary_entry_fn entry); 53 | extern void on_cpu_async(int cpu, void (*func)(void *data), void *data); 54 | extern void on_cpu(int cpu, void (*func)(void *data), void *data); 55 | extern void on_cpus(void (*func)(void *data), void *data); 56 | 57 | #endif /* _ASMARM_SMP_H_ */ 58 | -------------------------------------------------------------------------------- /lib/arm/asm/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_SPINLOCK_H_ 2 | #define _ASMARM_SPINLOCK_H_ 3 | 4 | struct spinlock { 5 | int v; 6 | }; 7 | 8 | extern void spin_lock(struct spinlock *lock); 9 | extern void spin_unlock(struct spinlock *lock); 10 | 11 | #endif /* _ASMARM_SPINLOCK_H_ */ 12 | -------------------------------------------------------------------------------- /lib/arm/asm/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM_STACK_H_ 2 | #define _ASMARM_STACK_H_ 3 | 4 | #ifndef _STACK_H_ 5 | #error Do not directly include . Just use . 6 | #endif 7 | 8 | #define HAVE_ARCH_BACKTRACE_FRAME 9 | #define HAVE_ARCH_BACKTRACE 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /lib/arm/asm/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Red Hat Inc, Andrew Jones 3 | * 4 | * This work is licensed under the terms of the GNU LGPL, version 2. 5 | */ 6 | #ifndef _ASMARM_TIMER_H_ 7 | #define _ASMARM_TIMER_H_ 8 | 9 | #define ARCH_TIMER_CTL_ENABLE (1 << 0) 10 | #define ARCH_TIMER_CTL_IMASK (1 << 1) 11 | #define ARCH_TIMER_CTL_ISTATUS (1 << 2) 12 | 13 | #ifndef __ASSEMBLY__ 14 | 15 | struct timer_state { 16 | struct { 17 | u32 irq; 18 | u32 irq_flags; 19 | } ptimer; 20 | struct { 21 | u32 irq; 22 | u32 irq_flags; 23 | } vtimer; 24 | }; 25 | extern struct timer_state __timer_state; 26 | 27 | #define TIMER_PTIMER_IRQ (__timer_state.ptimer.irq) 28 | #define TIMER_VTIMER_IRQ (__timer_state.vtimer.irq) 29 | 30 | #endif /* !__ASSEMBLY__ */ 31 | #endif /* _ASMARM_TIMER_H_ */ 32 | -------------------------------------------------------------------------------- /lib/arm/bitops.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from 3 | * include/asm-generic/bitops/atomic.h 4 | * 5 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 6 | * 7 | * This work is licensed under the terms of the GNU GPL, version 2. 8 | */ 9 | #include "libcflat.h" 10 | #include 11 | #include 12 | #include 13 | 14 | void set_bit(int nr, volatile unsigned long *addr) 15 | { 16 | volatile unsigned long *word = addr + BIT_WORD(nr); 17 | unsigned long mask = BIT_MASK(nr); 18 | 19 | if (mmu_enabled()) 20 | ATOMIC_BITOP("orr", mask, word); 21 | else 22 | *word |= mask; 23 | smp_mb(); 24 | } 25 | 26 | void clear_bit(int nr, volatile unsigned long *addr) 27 | { 28 | volatile unsigned long *word = addr + BIT_WORD(nr); 29 | unsigned long mask = BIT_MASK(nr); 30 | 31 | if (mmu_enabled()) 32 | ATOMIC_BITOP("bic", mask, word); 33 | else 34 | *word &= ~mask; 35 | smp_mb(); 36 | } 37 | 38 | int test_bit(int nr, const volatile unsigned long *addr) 39 | { 40 | const volatile unsigned long *word = addr + BIT_WORD(nr); 41 | unsigned long mask = BIT_MASK(nr); 42 | 43 | return (*word & mask) != 0; 44 | } 45 | 46 | int test_and_set_bit(int nr, volatile unsigned long *addr) 47 | { 48 | volatile unsigned long *word = addr + BIT_WORD(nr); 49 | unsigned long mask = BIT_MASK(nr); 50 | unsigned long old; 51 | 52 | smp_mb(); 53 | 54 | if (mmu_enabled()) { 55 | ATOMIC_TESTOP("orr", mask, word, old); 56 | } else { 57 | old = *word; 58 | *word = old | mask; 59 | } 60 | smp_mb(); 61 | 62 | return (old & mask) != 0; 63 | } 64 | 65 | int test_and_clear_bit(int nr, volatile unsigned long *addr) 66 | { 67 | volatile unsigned long *word = addr + BIT_WORD(nr); 68 | unsigned long mask = BIT_MASK(nr); 69 | unsigned long old; 70 | 71 | smp_mb(); 72 | 73 | if (mmu_enabled()) { 74 | ATOMIC_TESTOP("bic", mask, word, old); 75 | } else { 76 | old = *word; 77 | *word = old & ~mask; 78 | } 79 | smp_mb(); 80 | 81 | return (old & mask) != 0; 82 | } 83 | -------------------------------------------------------------------------------- /lib/arm/delay.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Delay loops 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void delay(u64 cycles) 14 | { 15 | u64 start = get_cntvct(); 16 | 17 | while ((get_cntvct() - start) < cycles) 18 | cpu_relax(); 19 | } 20 | 21 | void udelay(unsigned long usec) 22 | { 23 | delay((u64)usec * get_cntfrq() / 1000000); 24 | } 25 | 26 | void mdelay(unsigned long msecs) 27 | { 28 | while (msecs--) 29 | udelay(1000); 30 | } 31 | -------------------------------------------------------------------------------- /lib/arm/eabi_compat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from u-boot's arch/arm/lib/eabi_compat.c 3 | * 4 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU GPL, version 2. 7 | */ 8 | #include 9 | 10 | /* Needed to compile with -Wmissing-prototypes */ 11 | int raise(int signum); 12 | void __aeabi_unwind_cpp_pr0(void); 13 | void __aeabi_unwind_cpp_pr1(void); 14 | 15 | int raise(int signum __unused) 16 | { 17 | printf("Divide by zero!\n"); 18 | abort(); 19 | return 0; 20 | } 21 | 22 | /* Dummy functions to avoid linker complaints */ 23 | void __aeabi_unwind_cpp_pr0(void) 24 | { 25 | } 26 | 27 | void __aeabi_unwind_cpp_pr1(void) 28 | { 29 | } 30 | -------------------------------------------------------------------------------- /lib/arm/gic-v2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 3 | * 4 | * This work is licensed under the terms of the GNU LGPL, version 2. 5 | */ 6 | #include 7 | #include 8 | 9 | void gicv2_enable_defaults(void) 10 | { 11 | void *dist = gicv2_dist_base(); 12 | void *cpu_base = gicv2_cpu_base(); 13 | unsigned int i; 14 | 15 | gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER)); 16 | if (gicv2_data.irq_nr > 1020) 17 | gicv2_data.irq_nr = 1020; 18 | 19 | for (i = 0; i < gicv2_data.irq_nr; i += 4) 20 | writel(GICD_INT_DEF_PRI_X4, dist + GICD_IPRIORITYR + i); 21 | 22 | writel(GICD_INT_EN_SET_SGI, dist + GICD_ISENABLER + 0); 23 | writel(GICD_ENABLE, dist + GICD_CTLR); 24 | 25 | writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR); 26 | writel(GICC_ENABLE, cpu_base + GICC_CTLR); 27 | } 28 | 29 | u32 gicv2_read_iar(void) 30 | { 31 | return readl(gicv2_cpu_base() + GICC_IAR); 32 | } 33 | 34 | u32 gicv2_iar_irqnr(u32 iar) 35 | { 36 | return iar & GICC_IAR_INT_ID_MASK; 37 | } 38 | 39 | void gicv2_write_eoir(u32 irqstat) 40 | { 41 | writel(irqstat, gicv2_cpu_base() + GICC_EOIR); 42 | } 43 | 44 | void gicv2_ipi_send_single(int irq, int cpu) 45 | { 46 | assert(cpu < 8); 47 | assert(irq < 16); 48 | /* 49 | * The wmb() in writel and rmb() in readl() from gicv2_read_iar() are 50 | * sufficient for ensuring that stores that happen in program order 51 | * before the IPI will be visible after the interrupt is acknowledged. 52 | */ 53 | writel(1 << (cpu + 16) | irq, gicv2_dist_base() + GICD_SGIR); 54 | } 55 | 56 | void gicv2_ipi_send_mask(int irq, const cpumask_t *dest) 57 | { 58 | u8 tlist = (u8)cpumask_bits(dest)[0]; 59 | 60 | assert(irq < 16); 61 | /* No barriers needed, same situation as gicv2_ipi_send_single() */ 62 | writel(tlist << 16 | irq, gicv2_dist_base() + GICD_SGIR); 63 | } 64 | -------------------------------------------------------------------------------- /lib/arm/io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Prototypes for io.c 3 | * 4 | * This work is licensed under the terms of the GNU GPL, version 2. 5 | */ 6 | 7 | #ifndef _ARM_IO_H_ 8 | #define _ARM_IO_H_ 9 | 10 | extern void io_init(void); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /lib/arm/ldivmod.S: -------------------------------------------------------------------------------- 1 | // EABI ldivmod and uldivmod implementation based on libcompiler-rt 2 | // 3 | // This file is dual licensed under the MIT and the University of Illinois Open 4 | // Source Licenses. 5 | 6 | .syntax unified 7 | .align 2 8 | .globl __aeabi_uldivmod 9 | .type __aeabi_uldivmod, %function 10 | __aeabi_uldivmod: 11 | push {r11, lr} 12 | sub sp, sp, #16 13 | add r12, sp, #8 14 | str r12, [sp] // third argument to __udivmoddi4 15 | bl __udivmoddi4 16 | ldr r2, [sp, #8] // remainder returned in r2-r3 17 | ldr r3, [sp, #12] 18 | add sp, sp, #16 19 | pop {r11, pc} 20 | 21 | .globl __aeabi_ldivmod 22 | .type __aeabi_ldivmod, %function 23 | __aeabi_ldivmod: 24 | push {r11, lr} 25 | sub sp, sp, #16 26 | add r12, sp, #8 27 | str r12, [sp] // third argument to __divmoddi4 28 | bl __divmoddi4 29 | ldr r2, [sp, #8] // remainder returned in r2-r3 30 | ldr r3, [sp, #12] 31 | add sp, sp, #16 32 | pop {r11, pc} 33 | -------------------------------------------------------------------------------- /lib/arm/spinlock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ARM spinlock implementation 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void spin_lock(struct spinlock *lock) 13 | { 14 | u32 val, fail; 15 | 16 | if (!mmu_enabled()) { 17 | lock->v = 1; 18 | smp_mb(); 19 | return; 20 | } 21 | 22 | do { 23 | asm volatile( 24 | "1: ldrex %0, [%2]\n" 25 | " teq %0, #0\n" 26 | " bne 1b\n" 27 | " mov %0, #1\n" 28 | " strex %1, %0, [%2]\n" 29 | : "=&r" (val), "=&r" (fail) 30 | : "r" (&lock->v) 31 | : "cc" ); 32 | } while (fail); 33 | 34 | smp_mb(); 35 | } 36 | 37 | void spin_unlock(struct spinlock *lock) 38 | { 39 | smp_mb(); 40 | lock->v = 0; 41 | } 42 | -------------------------------------------------------------------------------- /lib/arm/stack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * backtrace support (this is a modified lib/x86/stack.c) 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | 11 | int backtrace_frame(const void *frame, const void **return_addrs, 12 | int max_depth) 13 | { 14 | static int walking; 15 | int depth; 16 | const unsigned long *fp = (unsigned long *)frame; 17 | 18 | if (walking) { 19 | printf("RECURSIVE STACK WALK!!!\n"); 20 | return 0; 21 | } 22 | walking = 1; 23 | 24 | for (depth = 0; depth < max_depth; depth++) { 25 | if (!fp) 26 | break; 27 | return_addrs[depth] = (void *)fp[0]; 28 | if (return_addrs[depth] == 0) 29 | break; 30 | fp = (unsigned long *)fp[-1]; 31 | } 32 | 33 | walking = 0; 34 | return depth; 35 | } 36 | 37 | int backtrace(const void **return_addrs, int max_depth) 38 | { 39 | return backtrace_frame(__builtin_frame_address(0), 40 | return_addrs, max_depth); 41 | } 42 | -------------------------------------------------------------------------------- /lib/arm64/.gitignore: -------------------------------------------------------------------------------- 1 | asm-offsets.[hs] 2 | -------------------------------------------------------------------------------- /lib/arm64/asm-offsets.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Adapted from arch/arm64/kernel/asm-offsets.c 3 | * 4 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU GPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | 12 | int main(void) 13 | { 14 | OFFSET(S_X0, pt_regs, regs[0]); 15 | OFFSET(S_X1, pt_regs, regs[1]); 16 | OFFSET(S_X2, pt_regs, regs[2]); 17 | OFFSET(S_X3, pt_regs, regs[3]); 18 | OFFSET(S_X4, pt_regs, regs[4]); 19 | OFFSET(S_X5, pt_regs, regs[5]); 20 | OFFSET(S_X6, pt_regs, regs[6]); 21 | OFFSET(S_X7, pt_regs, regs[7]); 22 | OFFSET(S_LR, pt_regs, regs[30]); 23 | OFFSET(S_SP, pt_regs, sp); 24 | OFFSET(S_PC, pt_regs, pc); 25 | OFFSET(S_PSTATE, pt_regs, pstate); 26 | OFFSET(S_ORIG_X0, pt_regs, orig_x0); 27 | OFFSET(S_SYSCALLNO, pt_regs, syscallno); 28 | DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /lib/arm64/asm/arch_gicv3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * All ripped off from arch/arm64/include/asm/arch_gicv3.h 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #ifndef _ASMARM64_ARCH_GICV3_H_ 9 | #define _ASMARM64_ARCH_GICV3_H_ 10 | 11 | #include 12 | 13 | #ifndef __ASSEMBLY__ 14 | 15 | #include 16 | #include 17 | 18 | /* 19 | * Low-level accessors 20 | * 21 | * These system registers are 32 bits, but we make sure that the compiler 22 | * sets the GP register's most significant bits to 0 with an explicit cast. 23 | */ 24 | 25 | static inline void gicv3_write_pmr(u32 val) 26 | { 27 | asm volatile("msr_s " xstr(ICC_PMR_EL1) ", %0" : : "r" ((u64)val)); 28 | } 29 | 30 | static inline void gicv3_write_sgi1r(u64 val) 31 | { 32 | asm volatile("msr_s " xstr(ICC_SGI1R_EL1) ", %0" : : "r" (val)); 33 | } 34 | 35 | static inline u32 gicv3_read_iar(void) 36 | { 37 | u64 irqstat; 38 | asm volatile("mrs_s %0, " xstr(ICC_IAR1_EL1) : "=r" (irqstat)); 39 | dsb(sy); 40 | return (u64)irqstat; 41 | } 42 | 43 | static inline void gicv3_write_eoir(u32 irq) 44 | { 45 | asm volatile("msr_s " xstr(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq)); 46 | isb(); 47 | } 48 | 49 | static inline void gicv3_write_grpen1(u32 val) 50 | { 51 | asm volatile("msr_s " xstr(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val)); 52 | isb(); 53 | } 54 | 55 | #define gicv3_read_typer(c) readq(c) 56 | 57 | #endif /* !__ASSEMBLY__ */ 58 | #endif /* _ASMARM64_ARCH_GICV3_H_ */ 59 | -------------------------------------------------------------------------------- /lib/arm64/asm/asm-offsets.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/assembler.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Based on the file arch/arm64/include/asm/assembled.h from Linux v5.10, which 4 | * in turn is based on arch/arm/include/asm/assembler.h and 5 | * arch/arm/mm/proc-macros.S 6 | * 7 | * Copyright (C) 1996-2000 Russell King 8 | * Copyright (C) 2012 ARM Ltd. 9 | */ 10 | 11 | #ifndef __ASSEMBLY__ 12 | #error "Only include this from assembly code" 13 | #endif 14 | 15 | #ifndef _ASMARM64_ASSEMBLER_H_ 16 | #define _ASMARM64_ASSEMBLER_H_ 17 | 18 | /* 19 | * raw_dcache_line_size - get the minimum D-cache line size on this CPU 20 | * from the CTR register. 21 | */ 22 | .macro raw_dcache_line_size, reg, tmp 23 | mrs \tmp, ctr_el0 // read CTR 24 | ubfx \tmp, \tmp, #16, #4 // cache line size encoding 25 | mov \reg, #4 // bytes per word 26 | lsl \reg, \reg, \tmp // actual cache line size 27 | .endm 28 | 29 | /* 30 | * Macro to perform a data cache maintenance for the interval 31 | * [addr, addr + size). Use the raw value for the dcache line size because 32 | * kvm-unit-tests has no concept of scheduling. 33 | * 34 | * op: operation passed to dc instruction 35 | * domain: domain used in dsb instruction 36 | * addr: starting virtual address of the region 37 | * size: size of the region 38 | * Corrupts: addr, size, tmp1, tmp2 39 | */ 40 | 41 | .macro dcache_by_line_op op, domain, addr, size, tmp1, tmp2 42 | raw_dcache_line_size \tmp1, \tmp2 43 | add \size, \addr, \size 44 | sub \tmp2, \tmp1, #1 45 | bic \addr, \addr, \tmp2 46 | 9998: 47 | dc \op, \addr 48 | add \addr, \addr, \tmp1 49 | cmp \addr, \size 50 | b.lo 9998b 51 | dsb \domain 52 | .endm 53 | 54 | #endif /* _ASMARM64_ASSEMBLER_H_ */ 55 | -------------------------------------------------------------------------------- /lib/arm64/asm/barrier.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_BARRIER_H_ 2 | #define _ASMARM64_BARRIER_H_ 3 | /* 4 | * From Linux arch/arm64/include/asm/barrier.h 5 | * 6 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 7 | * 8 | * This work is licensed under the terms of the GNU GPL, version 2. 9 | */ 10 | 11 | #define sev() asm volatile("sev" : : : "memory") 12 | #define wfe() asm volatile("wfe" : : : "memory") 13 | #define wfi() asm volatile("wfi" : : : "memory") 14 | #define yield() asm volatile("yield" : : : "memory") 15 | #define cpu_relax() yield() 16 | 17 | #define isb() asm volatile("isb" : : : "memory") 18 | #define dmb(opt) asm volatile("dmb " #opt : : : "memory") 19 | #define dsb(opt) asm volatile("dsb " #opt : : : "memory") 20 | #define mb() dsb(sy) 21 | #define rmb() dsb(ld) 22 | #define wmb() dsb(st) 23 | #define smp_mb() dmb(ish) 24 | #define smp_rmb() dmb(ishld) 25 | #define smp_wmb() dmb(ishst) 26 | 27 | #endif /* _ASMARM64_BARRIER_H_ */ 28 | -------------------------------------------------------------------------------- /lib/arm64/asm/bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_BITOPS_H_ 2 | #define _ASMARM64_BITOPS_H_ 3 | /* 4 | * Adapted from 5 | * arch/arm64/lib/bitops.S 6 | * 7 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 8 | * 9 | * This work is licensed under the terms of the GNU GPL, version 2. 10 | */ 11 | 12 | #ifndef _BITOPS_H_ 13 | #error only can be included directly 14 | #endif 15 | 16 | #define BITS_PER_LONG 64 17 | 18 | #define HAVE_BUILTIN_FLS 1 19 | 20 | #define ATOMIC_BITOP(insn, mask, word) \ 21 | ({ \ 22 | unsigned long tmp1, tmp2; \ 23 | asm volatile( \ 24 | "1: ldxr %0, [%2]\n" \ 25 | insn" %0, %0, %3\n" \ 26 | " stxr %w1, %0, [%2]\n" \ 27 | " cbnz %w1, 1b\n" \ 28 | : "=&r" (tmp1), "=&r" (tmp2) \ 29 | : "r" (word), "r" (mask) \ 30 | : "cc"); \ 31 | }) 32 | 33 | #define ATOMIC_TESTOP(insn, mask, word, old) \ 34 | ({ \ 35 | unsigned long tmp1, tmp2; \ 36 | asm volatile( \ 37 | "1: ldxr %0, [%3]\n" \ 38 | " and %1, %0, %4\n" \ 39 | insn" %0, %0, %4\n" \ 40 | " stlxr %w2, %0, [%3]\n" \ 41 | " cbnz %w2, 1b\n" \ 42 | : "=&r" (tmp1), "=&r" (old), "=&r" (tmp2) \ 43 | : "r" (word), "r" (mask) \ 44 | : "cc"); \ 45 | }) 46 | 47 | extern void set_bit(int nr, volatile unsigned long *addr); 48 | extern void clear_bit(int nr, volatile unsigned long *addr); 49 | extern int test_bit(int nr, const volatile unsigned long *addr); 50 | extern int test_and_set_bit(int nr, volatile unsigned long *addr); 51 | extern int test_and_clear_bit(int nr, volatile unsigned long *addr); 52 | 53 | #endif /* _ASMARM64_BITOPS_H_ */ 54 | -------------------------------------------------------------------------------- /lib/arm64/asm/cpumask.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/cpumask.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/delay.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/delay.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/esr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * From Linux kernel arch/arm64/include/asm/esr.h 3 | * 4 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU GPL, version 2. 7 | */ 8 | #ifndef _ASMARM64_ESR_H_ 9 | #define _ASMARM64_ESR_H_ 10 | 11 | #define ESR_EL1_WRITE (1 << 6) 12 | #define ESR_EL1_CM (1 << 8) 13 | #define ESR_EL1_IL (1 << 25) 14 | 15 | #define ESR_EL1_EC_SHIFT (26) 16 | #define ESR_EL1_EC_UNKNOWN (0x00) 17 | #define ESR_EL1_EC_WFI (0x01) 18 | #define ESR_EL1_EC_CP15_32 (0x03) 19 | #define ESR_EL1_EC_CP15_64 (0x04) 20 | #define ESR_EL1_EC_CP14_MR (0x05) 21 | #define ESR_EL1_EC_CP14_LS (0x06) 22 | #define ESR_EL1_EC_FP_ASIMD (0x07) 23 | #define ESR_EL1_EC_CP10_ID (0x08) 24 | #define ESR_EL1_EC_CP14_64 (0x0C) 25 | #define ESR_EL1_EC_ILL_ISS (0x0E) 26 | #define ESR_EL1_EC_SVC32 (0x11) 27 | #define ESR_EL1_EC_SVC64 (0x15) 28 | #define ESR_EL1_EC_SYS64 (0x18) 29 | #define ESR_EL1_EC_IABT_EL0 (0x20) 30 | #define ESR_EL1_EC_IABT_EL1 (0x21) 31 | #define ESR_EL1_EC_PC_ALIGN (0x22) 32 | #define ESR_EL1_EC_DABT_EL0 (0x24) 33 | #define ESR_EL1_EC_DABT_EL1 (0x25) 34 | #define ESR_EL1_EC_SP_ALIGN (0x26) 35 | #define ESR_EL1_EC_FP_EXC32 (0x28) 36 | #define ESR_EL1_EC_FP_EXC64 (0x2C) 37 | #define ESR_EL1_EC_SERROR (0x2F) 38 | #define ESR_EL1_EC_BREAKPT_EL0 (0x30) 39 | #define ESR_EL1_EC_BREAKPT_EL1 (0x31) 40 | #define ESR_EL1_EC_SOFTSTP_EL0 (0x32) 41 | #define ESR_EL1_EC_SOFTSTP_EL1 (0x33) 42 | #define ESR_EL1_EC_WATCHPT_EL0 (0x34) 43 | #define ESR_EL1_EC_WATCHPT_EL1 (0x35) 44 | #define ESR_EL1_EC_BKPT32 (0x38) 45 | #define ESR_EL1_EC_BRK64 (0x3C) 46 | 47 | #define ESR_EL1_FSC_MASK (0x3F) 48 | #define ESR_EL1_FSC_EXTABT (0x10) 49 | 50 | #endif /* _ASMARM64_ESR_H_ */ 51 | -------------------------------------------------------------------------------- /lib/arm64/asm/gic-v2.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/gic-v2.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/gic-v3.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/gic-v3.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/gic.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/gic.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/memory_areas.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_MEMORY_AREAS_H_ 2 | #define _ASMARM64_MEMORY_AREAS_H_ 3 | 4 | #include 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /lib/arm64/asm/mmu-api.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/mmu-api.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/mmu.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_MMU_H_ 2 | #define _ASMARM64_MMU_H_ 3 | /* 4 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | 10 | #define PMD_SECT_UNCACHED PMD_ATTRINDX(MT_DEVICE_nGnRE) 11 | #define PTE_UNCACHED PTE_ATTRINDX(MT_DEVICE_nGnRE) 12 | #define PTE_WBWA PTE_ATTRINDX(MT_NORMAL) 13 | 14 | static inline void flush_tlb_all(void) 15 | { 16 | dsb(ishst); 17 | asm("tlbi vmalle1is"); 18 | dsb(ish); 19 | isb(); 20 | } 21 | 22 | static inline void flush_tlb_page(unsigned long vaddr) 23 | { 24 | unsigned long page = vaddr >> 12; 25 | dsb(ishst); 26 | asm("tlbi vaae1is, %0" :: "r" (page)); 27 | dsb(ish); 28 | isb(); 29 | } 30 | 31 | static inline void flush_dcache_addr(unsigned long vaddr) 32 | { 33 | asm volatile("dc civac, %0" :: "r" (vaddr)); 34 | } 35 | 36 | #include 37 | 38 | #endif /* _ASMARM64_MMU_H_ */ 39 | -------------------------------------------------------------------------------- /lib/arm64/asm/pci.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/pci.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/psci.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/psci.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/setup.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/setup.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/smp.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/smp.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_SPINLOCK_H_ 2 | #define _ASMARM64_SPINLOCK_H_ 3 | 4 | struct spinlock { 5 | int v; 6 | }; 7 | 8 | extern void spin_lock(struct spinlock *lock); 9 | extern void spin_unlock(struct spinlock *lock); 10 | 11 | #endif /* _ASMARM64_SPINLOCK_H_ */ 12 | -------------------------------------------------------------------------------- /lib/arm64/asm/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMARM64_STACK_H_ 2 | #define _ASMARM64_STACK_H_ 3 | 4 | #ifndef _STACK_H_ 5 | #error Do not directly include . Just use . 6 | #endif 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /lib/arm64/asm/thread_info.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/thread_info.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/asm/timer.h: -------------------------------------------------------------------------------- 1 | #include "../../arm/asm/timer.h" 2 | -------------------------------------------------------------------------------- /lib/arm64/spinlock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * spinlocks 3 | * 4 | * Copyright (C) 2015, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void spin_lock(struct spinlock *lock) 14 | { 15 | u32 val, fail; 16 | 17 | if (!mmu_enabled()) { 18 | lock->v = 1; 19 | smp_mb(); 20 | return; 21 | } 22 | 23 | do { 24 | asm volatile( 25 | "1: ldaxr %w0, [%2]\n" 26 | " cbnz %w0, 1b\n" 27 | " mov %w0, #1\n" 28 | " stxr %w1, %w0, [%2]\n" 29 | : "=&r" (val), "=&r" (fail) 30 | : "r" (&lock->v) 31 | : "cc" ); 32 | } while (fail); 33 | smp_mb(); 34 | } 35 | 36 | void spin_unlock(struct spinlock *lock) 37 | { 38 | smp_mb(); 39 | if (mmu_enabled()) 40 | asm volatile("stlrh wzr, [%0]" :: "r" (&lock->v)); 41 | else 42 | lock->v = 0; 43 | } 44 | -------------------------------------------------------------------------------- /lib/asm-generic/atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_ATOMIC_H_ 2 | #define _ASM_GENERIC_ATOMIC_H_ 3 | 4 | /* From QEMU include/qemu/atomic.h */ 5 | #define atomic_fetch_inc(ptr) __sync_fetch_and_add(ptr, 1) 6 | #define atomic_fetch_dec(ptr) __sync_fetch_and_add(ptr, -1) 7 | #define atomic_fetch_add(ptr, n) __sync_fetch_and_add(ptr, n) 8 | #define atomic_fetch_sub(ptr, n) __sync_fetch_and_sub(ptr, n) 9 | #define atomic_fetch_and(ptr, n) __sync_fetch_and_and(ptr, n) 10 | #define atomic_fetch_or(ptr, n) __sync_fetch_and_or(ptr, n) 11 | #define atomic_fetch_xor(ptr, n) __sync_fetch_and_xor(ptr, n) 12 | 13 | #define atomic_inc_fetch(ptr) __sync_add_and_fetch(ptr, 1) 14 | #define atomic_dec_fetch(ptr) __sync_add_and_fetch(ptr, -1) 15 | #define atomic_add_fetch(ptr, n) __sync_add_and_fetch(ptr, n) 16 | #define atomic_sub_fetch(ptr, n) __sync_sub_and_fetch(ptr, n) 17 | #define atomic_and_fetch(ptr, n) __sync_and_and_fetch(ptr, n) 18 | #define atomic_or_fetch(ptr, n) __sync_or_and_fetch(ptr, n) 19 | #define atomic_xor_fetch(ptr, n) __sync_xor_and_fetch(ptr, n) 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /lib/asm-generic/barrier.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_BARRIER_H_ 2 | #define _ASM_GENERIC_BARRIER_H_ 3 | /* 4 | * asm-generic/barrier.h 5 | * 6 | * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev 7 | * 8 | * This work is licensed under the terms of the GNU LGPL, version 2. 9 | */ 10 | 11 | #ifndef mb 12 | #define mb() asm volatile("":::"memory") 13 | #endif 14 | #ifndef rmb 15 | #define rmb() asm volatile("":::"memory") 16 | #endif 17 | #ifndef wmb 18 | #define wmb() asm volatile("":::"memory") 19 | #endif 20 | 21 | #ifndef smp_mb 22 | #define smp_mb() mb() 23 | #endif 24 | #ifndef smp_rmb 25 | #define smp_rmb() rmb() 26 | #endif 27 | #ifndef smp_wmb 28 | #define smp_wmb() wmb() 29 | #endif 30 | 31 | #ifndef cpu_relax 32 | #define cpu_relax() asm volatile ("":::"memory") 33 | #endif 34 | 35 | #endif /* _ASM_GENERIC_BARRIER_H_ */ 36 | -------------------------------------------------------------------------------- /lib/asm-generic/memory_areas.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_MEMORY_AREAS_H_ 2 | #define _ASM_GENERIC_MEMORY_AREAS_H_ 3 | 4 | #define AREA_NORMAL_PFN 0 5 | #define AREA_NORMAL_NUMBER 0 6 | #define AREA_NORMAL (1 << AREA_NORMAL_NUMBER) 7 | 8 | #define MAX_AREAS 1 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /lib/asm-generic/page.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_PAGE_H_ 2 | #define _ASM_GENERIC_PAGE_H_ 3 | /* 4 | * asm-generic/page.h 5 | * adapted from the Linux kernel's include/asm-generic/page.h 6 | * 7 | * Copyright (C) 2017, Red Hat Inc, Andrew Jones 8 | * 9 | * This work is licensed under the terms of the GNU GPL, version 2. 10 | */ 11 | 12 | #include 13 | 14 | #define PAGE_SHIFT 12 15 | #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) 16 | #define PAGE_MASK (~(PAGE_SIZE-1)) 17 | 18 | #ifndef __ASSEMBLY__ 19 | 20 | #define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) 21 | 22 | #define __va(x) ((void *)((unsigned long) (x))) 23 | #define __pa(x) ((unsigned long) (x)) 24 | #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) 25 | #define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) 26 | 27 | #endif /* !__ASSEMBLY__ */ 28 | 29 | #endif /* _ASM_GENERIC_PAGE_H_ */ 30 | -------------------------------------------------------------------------------- /lib/asm-generic/pci-host-bridge.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_PCI_HOST_BRIDGE_H_ 2 | #define _ASM_GENERIC_PCI_HOST_BRIDGE_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include "libcflat.h" 9 | 10 | phys_addr_t pci_host_bridge_get_paddr(uint64_t addr); 11 | 12 | static inline 13 | phys_addr_t pci_translate_addr(pcidevaddr_t dev __unused, uint64_t addr) 14 | { 15 | /* 16 | * Assume we only have single PCI host bridge in a system. 17 | */ 18 | return pci_host_bridge_get_paddr(addr); 19 | } 20 | 21 | uint8_t pci_config_readb(pcidevaddr_t dev, uint8_t reg); 22 | uint16_t pci_config_readw(pcidevaddr_t dev, uint8_t reg); 23 | uint32_t pci_config_readl(pcidevaddr_t dev, uint8_t reg); 24 | void pci_config_writeb(pcidevaddr_t dev, uint8_t reg, uint8_t val); 25 | void pci_config_writew(pcidevaddr_t dev, uint8_t reg, uint16_t val); 26 | void pci_config_writel(pcidevaddr_t dev, uint8_t reg, uint32_t val); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /lib/asm-generic/pci.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_PCI_H_ 2 | #define _ASM_GENERIC_PCI_H_ 3 | #error need architecture specific asm/pci.h 4 | #endif 5 | -------------------------------------------------------------------------------- /lib/asm-generic/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_SPINLOCK_H_ 2 | #define _ASM_GENERIC_SPINLOCK_H_ 3 | 4 | struct spinlock { 5 | unsigned int v; 6 | }; 7 | 8 | static inline void spin_lock(struct spinlock *lock) 9 | { 10 | while (__sync_lock_test_and_set(&lock->v, 1)); 11 | } 12 | 13 | static inline void spin_unlock(struct spinlock *lock) 14 | { 15 | __sync_lock_release(&lock->v); 16 | } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /lib/auxinfo.c: -------------------------------------------------------------------------------- 1 | #include "auxinfo.h" 2 | 3 | #ifndef PROGNAME 4 | #define PROGNAME ((void *)0) 5 | #endif 6 | #ifndef AUXFLAGS 7 | #define AUXFLAGS 0 8 | #endif 9 | 10 | struct auxinfo auxinfo = { 11 | .progname = PROGNAME, 12 | .flags = AUXFLAGS, 13 | }; 14 | -------------------------------------------------------------------------------- /lib/auxinfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This code is free software; you can redistribute it and/or modify it 3 | * under the terms of the GNU Library General Public License version 2. 4 | */ 5 | #ifndef _AUXINFO_H_ 6 | #define _AUXINFO_H_ 7 | 8 | #define AUXINFO_MMU_OFF (1 << 0) 9 | 10 | #ifndef __ASSEMBLY__ 11 | struct auxinfo { 12 | const char *progname; 13 | unsigned long flags; 14 | }; 15 | 16 | extern struct auxinfo auxinfo; 17 | #endif 18 | #endif 19 | -------------------------------------------------------------------------------- /lib/chr-testdev.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 3 | * 4 | * This work is licensed under the terms of the GNU LGPL, version 2. 5 | */ 6 | #include "libcflat.h" 7 | #include "virtio.h" 8 | #include "asm/spinlock.h" 9 | 10 | #include "chr-testdev.h" 11 | 12 | #define TESTDEV_NAME "chr-testdev" 13 | 14 | static struct virtio_device *vcon; 15 | static struct virtqueue *in_vq, *out_vq; 16 | static struct spinlock lock; 17 | 18 | static void __testdev_send(char *buf, unsigned int len) 19 | { 20 | int ret; 21 | 22 | ret = virtqueue_add_outbuf(out_vq, buf, len); 23 | virtqueue_kick(out_vq); 24 | 25 | if (ret < 0) 26 | return; 27 | 28 | while (!virtqueue_get_buf(out_vq, &len)) 29 | ; 30 | } 31 | 32 | void chr_testdev_exit(int code) 33 | { 34 | unsigned int len; 35 | static char buf[8]; 36 | 37 | spin_lock(&lock); 38 | if (!vcon) 39 | goto out; 40 | 41 | snprintf(buf, sizeof(buf), "%dq", code); 42 | len = strlen(buf); 43 | 44 | __testdev_send(buf, len); 45 | 46 | out: 47 | spin_unlock(&lock); 48 | } 49 | 50 | void chr_testdev_init(void) 51 | { 52 | const char *io_names[] = { "input", "output" }; 53 | struct virtqueue *vqs[2]; 54 | int ret; 55 | 56 | vcon = virtio_bind(VIRTIO_ID_CONSOLE); 57 | if (vcon == NULL) 58 | return; 59 | 60 | ret = vcon->config->find_vqs(vcon, 2, vqs, NULL, io_names); 61 | if (ret < 0) { 62 | printf("%s: %s: can't init virtqueues\n", 63 | __func__, TESTDEV_NAME); 64 | vcon = NULL; 65 | return; 66 | } 67 | 68 | in_vq = vqs[0]; 69 | out_vq = vqs[1]; 70 | } 71 | -------------------------------------------------------------------------------- /lib/chr-testdev.h: -------------------------------------------------------------------------------- 1 | #ifndef _CHR_TESTDEV_H_ 2 | #define _CHR_TESTDEV_H_ 3 | /* 4 | * chr-testdev is a driver for the chr-testdev qemu backend. 5 | * The chr-testdev backend exposes a simple control interface to 6 | * qemu for kvm-unit-tests accessible through virtio-console. 7 | * 8 | * Copyright (C) 2014, Red Hat Inc, Andrew Jones 9 | * 10 | * This work is licensed under the terms of the GNU LGPL, version 2. 11 | */ 12 | extern void chr_testdev_init(void); 13 | extern void chr_testdev_exit(int code); 14 | #endif 15 | -------------------------------------------------------------------------------- /lib/ctype.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: LGPL-2.0-or-later */ 2 | #ifndef _CTYPE_H_ 3 | #define _CTYPE_H_ 4 | 5 | static inline int isblank(int c) 6 | { 7 | return c == ' ' || c == '\t'; 8 | } 9 | 10 | static inline int islower(int c) 11 | { 12 | return c >= 'a' && c <= 'z'; 13 | } 14 | 15 | static inline int isupper(int c) 16 | { 17 | return c >= 'A' && c <= 'Z'; 18 | } 19 | 20 | static inline int isalpha(int c) 21 | { 22 | return isupper(c) || islower(c); 23 | } 24 | 25 | static inline int isdigit(int c) 26 | { 27 | return c >= '0' && c <= '9'; 28 | } 29 | 30 | static inline int isalnum(int c) 31 | { 32 | return isalpha(c) || isdigit(c); 33 | } 34 | 35 | static inline int isspace(int c) 36 | { 37 | return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\v' || c == '\f'; 38 | } 39 | 40 | #endif /* _CTYPE_H_ */ 41 | -------------------------------------------------------------------------------- /lib/efi.h: -------------------------------------------------------------------------------- 1 | #ifndef _EFI_H_ 2 | #define _EFI_H_ 3 | 4 | /* 5 | * EFI-related functions. 6 | * 7 | * Copyright (c) 2021, Google Inc, Zixuan Wang 8 | * 9 | * SPDX-License-Identifier: LGPL-2.0-or-later 10 | */ 11 | #include "linux/efi.h" 12 | #include 13 | 14 | /* 15 | * efi_bootinfo_t: stores EFI-related machine info retrieved before exiting EFI 16 | * boot services, and is then used by setup_efi(). setup_efi() cannot retrieve 17 | * this info as it is called after ExitBootServices and thus some EFI resources 18 | * and functions are not available. 19 | */ 20 | typedef struct { 21 | struct efi_boot_memmap mem_map; 22 | } efi_bootinfo_t; 23 | 24 | efi_status_t _relocate(long ldbase, Elf64_Dyn *dyn, efi_handle_t handle, 25 | efi_system_table_t *sys_tab); 26 | efi_status_t efi_get_memory_map(struct efi_boot_memmap *map); 27 | efi_status_t efi_exit_boot_services(void *handle, struct efi_boot_memmap *map); 28 | efi_status_t efi_get_system_config_table(efi_guid_t table_guid, void **table); 29 | efi_status_t efi_main(efi_handle_t handle, efi_system_table_t *sys_tab); 30 | 31 | #endif /* _EFI_H_ */ 32 | -------------------------------------------------------------------------------- /lib/errata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * errata functions 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | #ifndef _ERRATA_H_ 8 | #define _ERRATA_H_ 9 | #include "config.h" 10 | 11 | #ifndef CONFIG_ERRATA_FORCE 12 | #define CONFIG_ERRATA_FORCE 0 13 | #endif 14 | 15 | #define _ERRATA(erratum) errata("ERRATA_" # erratum) 16 | #define ERRATA(erratum) _ERRATA(erratum) 17 | 18 | #define _ERRATA_RELAXED(erratum) errata_relaxed("ERRATA_" # erratum) 19 | #define ERRATA_RELAXED(erratum) _ERRATA_RELAXED(erratum) 20 | 21 | static inline bool errata_force(void) 22 | { 23 | char *s; 24 | 25 | if (CONFIG_ERRATA_FORCE == 1) 26 | return true; 27 | 28 | s = getenv("ERRATA_FORCE"); 29 | return s && (*s == '1' || *s == 'y' || *s == 'Y'); 30 | } 31 | 32 | static inline bool errata(const char *erratum) 33 | { 34 | char *s; 35 | 36 | if (errata_force()) 37 | return true; 38 | 39 | s = getenv(erratum); 40 | 41 | return s && (*s == '1' || *s == 'y' || *s == 'Y'); 42 | } 43 | 44 | static inline bool errata_relaxed(const char *erratum) 45 | { 46 | char *s; 47 | 48 | if (errata_force()) 49 | return true; 50 | 51 | s = getenv(erratum); 52 | 53 | return !(s && (*s == '0' || *s == 'n' || *s == 'N')); 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /lib/generated/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /lib/getchar.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | #include "asm/barrier.h" 3 | 4 | int getchar(void) 5 | { 6 | int c; 7 | 8 | while ((c = __getchar()) == -1) 9 | cpu_relax(); 10 | return c; 11 | } 12 | -------------------------------------------------------------------------------- /lib/kbuild.h: -------------------------------------------------------------------------------- 1 | #ifndef _KBUILD_H_ 2 | #define _KBUILD_H_ 3 | #define DEFINE(sym, val) \ 4 | asm volatile("\n.ascii \"->" #sym " %0 " #val "\"" : : "i" (val)) 5 | #define OFFSET(sym, str, mem) DEFINE(sym, offsetof(struct str, mem)) 6 | #define COMMENT(x) asm volatile("\n.ascii \"->#" x "\"") 7 | #define BLANK() asm volatile("\n.ascii \"->\"" : : ) 8 | #endif 9 | -------------------------------------------------------------------------------- /lib/libfdt/Makefile.libfdt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | # Makefile.libfdt 3 | # 4 | # This is not a complete Makefile of itself. Instead, it is designed to 5 | # be easily embeddable into other systems of Makefiles. 6 | # 7 | LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 8 | LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h 9 | LIBFDT_VERSION = version.lds 10 | LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \ 11 | fdt_addresses.c fdt_overlay.c fdt_check.c 12 | LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) 13 | LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT) 14 | 15 | libfdt_clean: 16 | @$(VECHO) CLEAN "(libfdt)" 17 | rm -f $(STD_CLEANFILES:%=$(LIBFDT_dir)/%) 18 | rm -f $(LIBFDT_dir)/$(LIBFDT_soname) 19 | -------------------------------------------------------------------------------- /lib/libfdt/README: -------------------------------------------------------------------------------- 1 | 2 | The code in this directory has been imported from the libfdt 3 | directory of git://git.kernel.org/pub/scm/utils/dtc/dtc.git - 4 | version v1.6.1. 5 | 6 | -------------------------------------------------------------------------------- /lib/libfdt/fdt.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ 2 | #ifndef FDT_H 3 | #define FDT_H 4 | /* 5 | * libfdt - Flat Device Tree manipulation 6 | * Copyright (C) 2006 David Gibson, IBM Corporation. 7 | * Copyright 2012 Kim Phillips, Freescale Semiconductor. 8 | */ 9 | 10 | #ifndef __ASSEMBLY__ 11 | 12 | struct fdt_header { 13 | fdt32_t magic; /* magic word FDT_MAGIC */ 14 | fdt32_t totalsize; /* total size of DT block */ 15 | fdt32_t off_dt_struct; /* offset to structure */ 16 | fdt32_t off_dt_strings; /* offset to strings */ 17 | fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ 18 | fdt32_t version; /* format version */ 19 | fdt32_t last_comp_version; /* last compatible version */ 20 | 21 | /* version 2 fields below */ 22 | fdt32_t boot_cpuid_phys; /* Which physical CPU id we're 23 | booting on */ 24 | /* version 3 fields below */ 25 | fdt32_t size_dt_strings; /* size of the strings block */ 26 | 27 | /* version 17 fields below */ 28 | fdt32_t size_dt_struct; /* size of the structure block */ 29 | }; 30 | 31 | struct fdt_reserve_entry { 32 | fdt64_t address; 33 | fdt64_t size; 34 | }; 35 | 36 | struct fdt_node_header { 37 | fdt32_t tag; 38 | char name[0]; 39 | }; 40 | 41 | struct fdt_property { 42 | fdt32_t tag; 43 | fdt32_t len; 44 | fdt32_t nameoff; 45 | char data[0]; 46 | }; 47 | 48 | #endif /* !__ASSEMBLY */ 49 | 50 | #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ 51 | #define FDT_TAGSIZE sizeof(fdt32_t) 52 | 53 | #define FDT_BEGIN_NODE 0x1 /* Start node: full name */ 54 | #define FDT_END_NODE 0x2 /* End node */ 55 | #define FDT_PROP 0x3 /* Property: name off, 56 | size, content */ 57 | #define FDT_NOP 0x4 /* nop */ 58 | #define FDT_END 0x9 59 | 60 | #define FDT_V1_SIZE (7*sizeof(fdt32_t)) 61 | #define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) 62 | #define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) 63 | #define FDT_V16_SIZE FDT_V3_SIZE 64 | #define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) 65 | 66 | #endif /* FDT_H */ 67 | -------------------------------------------------------------------------------- /lib/libfdt/fdt_empty_tree.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2012 David Gibson, IBM Corporation. 5 | */ 6 | #include "libfdt_env.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "libfdt_internal.h" 12 | 13 | int fdt_create_empty_tree(void *buf, int bufsize) 14 | { 15 | int err; 16 | 17 | err = fdt_create(buf, bufsize); 18 | if (err) 19 | return err; 20 | 21 | err = fdt_finish_reservemap(buf); 22 | if (err) 23 | return err; 24 | 25 | err = fdt_begin_node(buf, ""); 26 | if (err) 27 | return err; 28 | 29 | err = fdt_end_node(buf); 30 | if (err) 31 | return err; 32 | 33 | err = fdt_finish(buf); 34 | if (err) 35 | return err; 36 | 37 | return fdt_open_into(buf, buf, bufsize); 38 | } 39 | -------------------------------------------------------------------------------- /lib/libfdt/fdt_strerror.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 | /* 3 | * libfdt - Flat Device Tree manipulation 4 | * Copyright (C) 2006 David Gibson, IBM Corporation. 5 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6 | */ 7 | #include "libfdt_env.h" 8 | 9 | #include 10 | #include 11 | 12 | #include "libfdt_internal.h" 13 | 14 | struct fdt_errtabent { 15 | const char *str; 16 | }; 17 | 18 | #define FDT_ERRTABENT(val) \ 19 | [(val)] = { .str = #val, } 20 | 21 | static struct fdt_errtabent fdt_errtable[] = { 22 | FDT_ERRTABENT(FDT_ERR_NOTFOUND), 23 | FDT_ERRTABENT(FDT_ERR_EXISTS), 24 | FDT_ERRTABENT(FDT_ERR_NOSPACE), 25 | 26 | FDT_ERRTABENT(FDT_ERR_BADOFFSET), 27 | FDT_ERRTABENT(FDT_ERR_BADPATH), 28 | FDT_ERRTABENT(FDT_ERR_BADPHANDLE), 29 | FDT_ERRTABENT(FDT_ERR_BADSTATE), 30 | 31 | FDT_ERRTABENT(FDT_ERR_TRUNCATED), 32 | FDT_ERRTABENT(FDT_ERR_BADMAGIC), 33 | FDT_ERRTABENT(FDT_ERR_BADVERSION), 34 | FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), 35 | FDT_ERRTABENT(FDT_ERR_BADLAYOUT), 36 | FDT_ERRTABENT(FDT_ERR_INTERNAL), 37 | FDT_ERRTABENT(FDT_ERR_BADNCELLS), 38 | FDT_ERRTABENT(FDT_ERR_BADVALUE), 39 | FDT_ERRTABENT(FDT_ERR_BADOVERLAY), 40 | FDT_ERRTABENT(FDT_ERR_NOPHANDLES), 41 | FDT_ERRTABENT(FDT_ERR_BADFLAGS), 42 | }; 43 | #define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))) 44 | 45 | const char *fdt_strerror(int errval) 46 | { 47 | if (errval > 0) 48 | return ""; 49 | else if (errval == 0) 50 | return ""; 51 | else if (-errval < FDT_ERRTABSIZE) { 52 | const char *s = fdt_errtable[-errval].str; 53 | 54 | if (s) 55 | return s; 56 | } 57 | 58 | return ""; 59 | } 60 | -------------------------------------------------------------------------------- /lib/libfdt/version.lds: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */ 2 | LIBFDT_1.2 { 3 | global: 4 | fdt_next_node; 5 | fdt_check_header; 6 | fdt_move; 7 | fdt_string; 8 | fdt_num_mem_rsv; 9 | fdt_get_mem_rsv; 10 | fdt_subnode_offset_namelen; 11 | fdt_subnode_offset; 12 | fdt_path_offset_namelen; 13 | fdt_path_offset; 14 | fdt_get_name; 15 | fdt_get_property_namelen; 16 | fdt_get_property; 17 | fdt_getprop_namelen; 18 | fdt_getprop; 19 | fdt_get_phandle; 20 | fdt_get_alias_namelen; 21 | fdt_get_alias; 22 | fdt_get_path; 23 | fdt_header_size; 24 | fdt_supernode_atdepth_offset; 25 | fdt_node_depth; 26 | fdt_parent_offset; 27 | fdt_node_offset_by_prop_value; 28 | fdt_node_offset_by_phandle; 29 | fdt_node_check_compatible; 30 | fdt_node_offset_by_compatible; 31 | fdt_setprop_inplace; 32 | fdt_nop_property; 33 | fdt_nop_node; 34 | fdt_create; 35 | fdt_add_reservemap_entry; 36 | fdt_finish_reservemap; 37 | fdt_begin_node; 38 | fdt_property; 39 | fdt_end_node; 40 | fdt_finish; 41 | fdt_open_into; 42 | fdt_pack; 43 | fdt_add_mem_rsv; 44 | fdt_del_mem_rsv; 45 | fdt_set_name; 46 | fdt_setprop; 47 | fdt_delprop; 48 | fdt_add_subnode_namelen; 49 | fdt_add_subnode; 50 | fdt_del_node; 51 | fdt_strerror; 52 | fdt_offset_ptr; 53 | fdt_next_tag; 54 | fdt_appendprop; 55 | fdt_create_empty_tree; 56 | fdt_first_property_offset; 57 | fdt_get_property_by_offset; 58 | fdt_getprop_by_offset; 59 | fdt_next_property_offset; 60 | fdt_first_subnode; 61 | fdt_next_subnode; 62 | fdt_address_cells; 63 | fdt_size_cells; 64 | fdt_stringlist_contains; 65 | fdt_stringlist_count; 66 | fdt_stringlist_search; 67 | fdt_stringlist_get; 68 | fdt_resize; 69 | fdt_overlay_apply; 70 | fdt_get_string; 71 | fdt_find_max_phandle; 72 | fdt_generate_phandle; 73 | fdt_check_full; 74 | fdt_setprop_placeholder; 75 | fdt_property_placeholder; 76 | fdt_header_size_; 77 | fdt_appendprop_addrrange; 78 | fdt_setprop_inplace_namelen_partial; 79 | fdt_create_with_flags; 80 | local: 81 | *; 82 | }; 83 | -------------------------------------------------------------------------------- /lib/linux/const.h: -------------------------------------------------------------------------------- 1 | /* const.h: Macros for dealing with constants. */ 2 | 3 | #ifndef _LINUX_CONST_H 4 | #define _LINUX_CONST_H 5 | 6 | /* Some constant macros are used in both assembler and 7 | * C code. Therefore we cannot annotate them always with 8 | * 'UL' and other type specifiers unilaterally. We 9 | * use the following macros to deal with this. 10 | * 11 | * Similarly, _AT() will cast an expression with a type in C, but 12 | * leave it unchanged in asm. 13 | */ 14 | 15 | #ifdef __ASSEMBLY__ 16 | #define _AC(X,Y) X 17 | #define _AT(T,X) X 18 | #else 19 | #define __AC(X,Y) (X##Y) 20 | #define _AC(X,Y) __AC(X,Y) 21 | #define _AT(T,X) ((T)(X)) 22 | #endif 23 | 24 | #define _BITUL(x) (_AC(1,UL) << (x)) 25 | #define _BITULL(x) (_AC(1,ULL) << (x)) 26 | 27 | #endif /* !(_LINUX_CONST_H) */ 28 | -------------------------------------------------------------------------------- /lib/list.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIST_H_ 2 | #define _LIST_H_ 3 | 4 | #include 5 | 6 | /* 7 | * Circular doubly-linked list. The pointer to the list is a list item itself, 8 | * like in the kernel implementation. 9 | */ 10 | struct linked_list { 11 | struct linked_list *prev; 12 | struct linked_list *next; 13 | }; 14 | 15 | /* 16 | * An empty list is a list item whose prev and next both point to itself. 17 | * Returns true if the list is empty. 18 | */ 19 | static inline bool is_list_empty(struct linked_list *p) 20 | { 21 | return !p->next || !p->prev || p == p->next || p == p->prev; 22 | } 23 | 24 | /* 25 | * Remove the given element from the list, if the list is not already empty. 26 | * The removed element is returned. 27 | */ 28 | static inline struct linked_list *list_remove(struct linked_list *l) 29 | { 30 | if (is_list_empty(l)) 31 | return NULL; 32 | 33 | l->prev->next = l->next; 34 | l->next->prev = l->prev; 35 | l->prev = l->next = NULL; 36 | 37 | return l; 38 | } 39 | 40 | /* 41 | * Add the given element after the given list head. 42 | */ 43 | static inline void list_add(struct linked_list *head, struct linked_list *li) 44 | { 45 | assert(li); 46 | assert(head); 47 | li->prev = head; 48 | li->next = head->next; 49 | head->next->prev = li; 50 | head->next = li; 51 | } 52 | 53 | /* 54 | * Add the given element before the given list head. 55 | */ 56 | static inline void list_add_tail(struct linked_list *head, struct linked_list *li) 57 | { 58 | assert(head); 59 | list_add(head->prev, li); 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /lib/pci-edu.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Edu PCI device. 3 | * 4 | * Copyright (C) 2016 Red Hat, Inc. 5 | * 6 | * Authors: 7 | * Peter Xu , 8 | * 9 | * This work is licensed under the terms of the GNU LGPL, version 2 or 10 | * later. 11 | */ 12 | 13 | #include "pci-edu.h" 14 | #include "asm/barrier.h" 15 | 16 | /* Return true if alive */ 17 | static inline bool edu_check_alive(struct pci_edu_dev *dev) 18 | { 19 | static uint32_t live_count = 1; 20 | uint32_t value; 21 | 22 | edu_reg_writel(dev, EDU_REG_ALIVE, live_count++); 23 | value = edu_reg_readl(dev, EDU_REG_ALIVE); 24 | return (live_count - 1 == ~value); 25 | } 26 | 27 | bool edu_init(struct pci_edu_dev *dev) 28 | { 29 | pcidevaddr_t dev_addr; 30 | 31 | dev_addr = pci_find_dev(PCI_VENDOR_ID_QEMU, PCI_DEVICE_ID_EDU); 32 | if (dev_addr == PCIDEVADDR_INVALID) 33 | return false; 34 | 35 | pci_dev_init(&dev->pci_dev, dev_addr); 36 | pci_enable_defaults(&dev->pci_dev); 37 | dev->reg_base = ioremap(dev->pci_dev.resource[EDU_BAR], PAGE_SIZE); 38 | assert(edu_check_alive(dev)); 39 | return true; 40 | } 41 | 42 | void edu_dma(struct pci_edu_dev *dev, iova_t iova, 43 | size_t size, unsigned int dev_offset, bool from_device) 44 | { 45 | uint64_t from, to; 46 | uint32_t cmd = EDU_CMD_DMA_START; 47 | 48 | assert(size <= EDU_DMA_SIZE_MAX); 49 | assert(dev_offset < EDU_DMA_SIZE_MAX); 50 | 51 | printf("edu device DMA start %s addr %#" PRIx64 " size %lu off %#x\n", 52 | from_device ? "FROM" : "TO", 53 | iova, (ulong)size, dev_offset); 54 | 55 | if (from_device) { 56 | from = dev_offset + EDU_DMA_START; 57 | to = iova; 58 | cmd |= EDU_CMD_DMA_FROM; 59 | } else { 60 | from = iova; 61 | to = EDU_DMA_START + dev_offset; 62 | cmd |= EDU_CMD_DMA_TO; 63 | } 64 | 65 | edu_reg_writeq(dev, EDU_REG_DMA_SRC, from); 66 | edu_reg_writeq(dev, EDU_REG_DMA_DST, to); 67 | edu_reg_writeq(dev, EDU_REG_DMA_COUNT, size); 68 | edu_reg_writel(dev, EDU_REG_DMA_CMD, cmd); 69 | 70 | /* Wait until DMA finished */ 71 | while (edu_reg_readl(dev, EDU_REG_DMA_CMD) & EDU_CMD_DMA_START) 72 | cpu_relax(); 73 | } 74 | -------------------------------------------------------------------------------- /lib/pci-host-generic.h: -------------------------------------------------------------------------------- 1 | #ifndef _PCI_HOST_GENERIC_H_ 2 | #define _PCI_HOST_GENERIC_H_ 3 | /* 4 | * PCI host bridge supporting structures and constants 5 | * 6 | * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev 7 | * 8 | * This work is licensed under the terms of the GNU LGPL, version 2. 9 | */ 10 | #include "libcflat.h" 11 | 12 | struct pci_addr_space { 13 | phys_addr_t pci_start; 14 | phys_addr_t start; 15 | phys_addr_t size; 16 | phys_addr_t allocated; 17 | int type; 18 | }; 19 | 20 | struct pci_host_bridge { 21 | void __iomem *start; 22 | size_t size; 23 | int bus; 24 | int bus_max; 25 | int nr_addr_spaces; 26 | struct pci_addr_space addr_space[]; 27 | }; 28 | 29 | /* 30 | * The following constants are derived from Linux, see this source: 31 | * 32 | * drivers/pci/host/pci-host-generic.c 33 | * struct gen_pci_cfg_bus_ops::bus_shift 34 | * int gen_pci_parse_map_cfg_windows(struct gen_pci *pci) 35 | * 36 | * Documentation/devicetree/bindings/pci/host-generic-pci.txt describes 37 | * ECAM Configuration Space is be memory-mapped by concatenating the various 38 | * components to form an offset: 39 | * 40 | * cfg_offset(bus, device, function, register) = 41 | * bus << 20 | device << 15 | function << 12 | register 42 | */ 43 | #define PCI_ECAM_BUS_SHIFT 20 44 | #define PCI_ECAM_DEVFN_SHIFT 12 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /lib/powerpc/.gitignore: -------------------------------------------------------------------------------- 1 | asm-offsets.[hs] 2 | -------------------------------------------------------------------------------- /lib/powerpc/asm/handlers.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_HANDLERS_H_ 2 | #define _ASMPOWERPC_HANDLERS_H_ 3 | 4 | #include 5 | 6 | void dec_except_handler(struct pt_regs *regs, void *data); 7 | 8 | #endif /* _ASMPOWERPC_HANDLERS_H_ */ 9 | -------------------------------------------------------------------------------- /lib/powerpc/asm/hcall.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_HCALL_H_ 2 | #define _ASMPOWERPC_HCALL_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | #define SC1 0x44000022 10 | #define SC1_REPLACEMENT 0x7c000268 11 | 12 | #define H_SUCCESS 0 13 | #define H_HARDWARE -1 14 | #define H_FUNCTION -2 15 | #define H_PRIVILEGE -3 16 | #define H_PARAMETER -4 17 | 18 | #define H_SET_SPRG0 0x24 19 | #define H_SET_DABR 0x28 20 | #define H_PAGE_INIT 0x2c 21 | #define H_CEDE 0xE0 22 | #define H_GET_TERM_CHAR 0x54 23 | #define H_PUT_TERM_CHAR 0x58 24 | #define H_RANDOM 0x300 25 | #define H_SET_MODE 0x31C 26 | 27 | #define KVMPPC_HCALL_BASE 0xf000 28 | #define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0) 29 | 30 | #ifndef __ASSEMBLY__ 31 | /* 32 | * hcall_have_broken_sc1 checks if we're on a host with a broken sc1. 33 | * Returns 0 if we're not. 34 | */ 35 | extern int hcall_have_broken_sc1(void); 36 | 37 | /* 38 | * hcall is the hypercall wrapper function. unittests may do what 39 | * they like, but the framework should make all hypercalls through 40 | * here to ensure they use a working sc1 instruction. @nr is the 41 | * hypercall number. 42 | */ 43 | extern unsigned long hcall(unsigned long nr, ...); 44 | 45 | #endif /* !__ASSEMBLY__ */ 46 | #endif /* _ASMPOWERPC_HCALL_H_ */ 47 | -------------------------------------------------------------------------------- /lib/powerpc/asm/memory_areas.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_MEMORY_AREAS_H_ 2 | #define _ASMPOWERPC_MEMORY_AREAS_H_ 3 | 4 | #include 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /lib/powerpc/asm/ppc_asm.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_PPC_ASM_H 2 | #define _ASMPOWERPC_PPC_ASM_H 3 | 4 | #include 5 | 6 | #define SAVE_GPR(n, base) std n,GPR0+8*(n)(base) 7 | #define REST_GPR(n, base) ld n,GPR0+8*(n)(base) 8 | 9 | #define LOAD_REG_IMMEDIATE(reg,expr) \ 10 | lis reg,(expr)@highest; \ 11 | ori reg,reg,(expr)@higher; \ 12 | rldicr reg,reg,32,31; \ 13 | oris reg,reg,(expr)@h; \ 14 | ori reg,reg,(expr)@l; 15 | 16 | #define LOAD_REG_ADDR(reg,name) \ 17 | ld reg,name@got(r2) 18 | 19 | #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 20 | 21 | #define FIXUP_ENDIAN 22 | 23 | #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 24 | 25 | #define FIXUP_ENDIAN \ 26 | .long 0x05000048; /* bl . + 4 */ \ 27 | .long 0xa602487d; /* mflr r10 */ \ 28 | .long 0x20004a39; /* addi r10,r10,32 */ \ 29 | .long 0xa600607d; /* mfmsr r11 */ \ 30 | .long 0x01006b69; /* xori r11,r11,1 */ \ 31 | .long 0xa6035a7d; /* mtsrr0 r10 */ \ 32 | .long 0xa6037b7d; /* mtsrr1 r11 */ \ 33 | .long 0x2400004c; /* rfid */ \ 34 | .long 0x00000048; /* b . */ \ 35 | 36 | #endif /* __BYTE_ORDER__ */ 37 | 38 | #endif /* _ASMPOWERPC_PPC_ASM_H */ 39 | -------------------------------------------------------------------------------- /lib/powerpc/asm/processor.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_PROCESSOR_H_ 2 | #define _ASMPOWERPC_PROCESSOR_H_ 3 | 4 | #include 5 | #include 6 | 7 | #ifndef __ASSEMBLY__ 8 | void handle_exception(int trap, void (*func)(struct pt_regs *, void *), void *); 9 | void do_handle_exception(struct pt_regs *regs); 10 | #endif /* __ASSEMBLY__ */ 11 | 12 | static inline uint64_t get_tb(void) 13 | { 14 | uint64_t tb; 15 | 16 | asm volatile ("mfspr %[tb],268" : [tb] "=r" (tb)); 17 | 18 | return tb; 19 | } 20 | 21 | extern void delay(uint64_t cycles); 22 | extern void udelay(uint64_t us); 23 | 24 | static inline void mdelay(uint64_t ms) 25 | { 26 | while (ms--) 27 | udelay(1000); 28 | } 29 | 30 | #endif /* _ASMPOWERPC_PROCESSOR_H_ */ 31 | -------------------------------------------------------------------------------- /lib/powerpc/asm/rtas.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_RTAS_H_ 2 | #define _ASMPOWERPC_RTAS_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | #ifndef __ASSEMBLY__ 10 | 11 | #include 12 | 13 | #define RTAS_UNKNOWN_SERVICE (-1) 14 | 15 | struct rtas_args { 16 | u32 token; 17 | u32 nargs; 18 | u32 nret; 19 | u32 args[16]; 20 | u32 *rets; 21 | }; 22 | 23 | extern void rtas_init(void); 24 | extern int rtas_token(const char *service, uint32_t *token); 25 | extern int rtas_call(int token, int nargs, int nret, int *outputs, ...); 26 | 27 | extern void rtas_power_off(void); 28 | #endif /* __ASSEMBLY__ */ 29 | 30 | #define RTAS_MSR_MASK 0xfffffffffffffffe 31 | 32 | #endif /* _ASMPOWERPC_RTAS_H_ */ 33 | -------------------------------------------------------------------------------- /lib/powerpc/asm/setup.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_SETUP_H_ 2 | #define _ASMPOWERPC_SETUP_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | 10 | #define NR_CPUS 8 /* arbitrarily set for now */ 11 | extern u32 cpus[NR_CPUS]; 12 | extern int nr_cpus; 13 | 14 | extern uint64_t tb_hz; 15 | 16 | #define NR_MEM_REGIONS 8 17 | #define MR_F_PRIMARY (1U << 0) 18 | struct mem_region { 19 | phys_addr_t start; 20 | phys_addr_t end; 21 | unsigned int flags; 22 | }; 23 | extern struct mem_region mem_regions[NR_MEM_REGIONS]; 24 | extern phys_addr_t __physical_start, __physical_end; 25 | extern unsigned __icache_bytes, __dcache_bytes; 26 | 27 | #define PHYSICAL_START (__physical_start) 28 | #define PHYSICAL_END (__physical_end) 29 | 30 | void setup(const void *fdt); 31 | 32 | #endif /* _ASMPOWERPC_SETUP_H_ */ 33 | -------------------------------------------------------------------------------- /lib/powerpc/asm/smp.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_SMP_H_ 2 | #define _ASMPOWERPC_SMP_H_ 3 | 4 | #include 5 | 6 | extern int nr_threads; 7 | 8 | struct start_threads { 9 | int nr_threads; 10 | int nr_started; 11 | }; 12 | 13 | typedef void (*secondary_entry_fn)(void); 14 | 15 | extern void halt(void); 16 | 17 | extern int start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3); 18 | extern struct start_threads start_cpu(int cpu_node, secondary_entry_fn entry, 19 | uint32_t r3); 20 | extern bool start_all_cpus(secondary_entry_fn entry, uint32_t r3); 21 | 22 | #endif /* _ASMPOWERPC_SMP_H_ */ 23 | -------------------------------------------------------------------------------- /lib/powerpc/asm/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPOWERPC_STACK_H_ 2 | #define _ASMPOWERPC_STACK_H_ 3 | 4 | #ifndef _STACK_H_ 5 | #error Do not directly include . Just use . 6 | #endif 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /lib/powerpc/handlers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic exception handlers for registration and use in tests 3 | * 4 | * Copyright 2016 Suraj Jitindar Singh, IBM. 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | /* 14 | * Generic handler for decrementer exceptions (0x900) 15 | * Just reset the decrementer back to the value specified when registering the 16 | * handler 17 | */ 18 | void dec_except_handler(struct pt_regs *regs __unused, void *data) 19 | { 20 | uint64_t dec = *((uint64_t *) data); 21 | 22 | asm volatile ("mtdec %0" : : "r" (dec)); 23 | } 24 | -------------------------------------------------------------------------------- /lib/powerpc/hcall.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Hypercall helpers 3 | * 4 | * broken_sc1 probing/patching inspired by SLOF, see 5 | * SLOF:lib/libhvcall/brokensc1.c 6 | * 7 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 8 | * 9 | * This work is licensed under the terms of the GNU LGPL, version 2. 10 | */ 11 | #include 12 | #include 13 | #include "io.h" 14 | 15 | int hcall_have_broken_sc1(void) 16 | { 17 | register unsigned long r3 asm("r3") = H_SET_DABR; 18 | register unsigned long r4 asm("r4") = 0; 19 | 20 | asm volatile("sc 1" 21 | : "=r" (r3) 22 | : "r" (r3), "r" (r4) 23 | : "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"); 24 | 25 | return r3 == (unsigned long)H_PRIVILEGE; 26 | } 27 | 28 | void putchar(int c) 29 | { 30 | unsigned long vty = 0; /* 0 == default */ 31 | unsigned long nr_chars = 1; 32 | unsigned long chars = (unsigned long)c << 56; 33 | 34 | hcall(H_PUT_TERM_CHAR, vty, nr_chars, chars); 35 | } 36 | 37 | int __getchar(void) 38 | { 39 | register unsigned long r3 asm("r3") = H_GET_TERM_CHAR; 40 | register unsigned long r4 asm("r4") = 0; /* 0 == default vty */ 41 | register unsigned long r5 asm("r5"); 42 | 43 | asm volatile (" sc 1 " : "+r"(r3), "+r"(r4), "=r"(r5) 44 | : "r"(r3), "r"(r4)); 45 | 46 | return r3 == H_SUCCESS && r4 > 0 ? r5 >> 48 : -1; 47 | } 48 | -------------------------------------------------------------------------------- /lib/powerpc/io.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Each architecture must implement puts() and exit(). 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "io.h" 13 | 14 | static struct spinlock print_lock; 15 | 16 | void io_init(void) 17 | { 18 | rtas_init(); 19 | } 20 | 21 | void puts(const char *s) 22 | { 23 | spin_lock(&print_lock); 24 | while (*s) 25 | putchar(*s++); 26 | spin_unlock(&print_lock); 27 | } 28 | 29 | /* 30 | * Defining halt to take 'code' as an argument guarantees that it will 31 | * be in r3 when we halt. That gives us a final chance to see the exit 32 | * status while inspecting the halted unit test state. 33 | */ 34 | extern void halt(int code); 35 | 36 | void exit(int code) 37 | { 38 | // FIXME: change this print-exit/rtas-poweroff to chr_testdev_exit(), 39 | // maybe by plugging chr-testdev into a spapr-vty. 40 | printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1); 41 | rtas_power_off(); 42 | halt(code); 43 | __builtin_unreachable(); 44 | } 45 | -------------------------------------------------------------------------------- /lib/powerpc/io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Prototypes for io.c 3 | * 4 | * This work is licensed under the terms of the GNU GPL, version 2. 5 | */ 6 | 7 | #ifndef _POWERPC_IO_H_ 8 | #define _POWERPC_IO_H_ 9 | 10 | extern void io_init(void); 11 | extern void putchar(int c); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /lib/powerpc/processor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * processor control and status function 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | static struct { 15 | void (*func)(struct pt_regs *, void *data); 16 | void *data; 17 | } handlers[16]; 18 | 19 | void handle_exception(int trap, void (*func)(struct pt_regs *, void *), 20 | void * data) 21 | { 22 | trap >>= 8; 23 | 24 | if (trap < 16) { 25 | handlers[trap].func = func; 26 | handlers[trap].data = data; 27 | } 28 | } 29 | 30 | void do_handle_exception(struct pt_regs *regs) 31 | { 32 | unsigned char v; 33 | 34 | v = regs->trap >> 8; 35 | 36 | if (v < 16 && handlers[v].func) { 37 | handlers[v].func(regs, handlers[v].data); 38 | return; 39 | } 40 | 41 | printf("unhandled cpu exception %#lx\n", regs->trap); 42 | abort(); 43 | } 44 | 45 | void delay(uint64_t cycles) 46 | { 47 | uint64_t start = get_tb(); 48 | 49 | while ((get_tb() - start) < cycles) 50 | cpu_relax(); 51 | } 52 | 53 | void udelay(uint64_t us) 54 | { 55 | delay((us * tb_hz) / 1000000); 56 | } 57 | -------------------------------------------------------------------------------- /lib/ppc64/.gitignore: -------------------------------------------------------------------------------- 1 | asm-offsets.[hs] 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/asm-offsets.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/barrier.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_BARRIER_H_ 2 | #define _ASMPPC64_BARRIER_H_ 3 | 4 | #define mb() asm volatile("sync":::"memory") 5 | #define rmb() asm volatile("sync":::"memory") 6 | #define wmb() asm volatile("sync":::"memory") 7 | 8 | #include 9 | #endif 10 | -------------------------------------------------------------------------------- /lib/ppc64/asm/bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_BITOPS_H_ 2 | #define _ASMPPC64_BITOPS_H_ 3 | 4 | #ifndef _BITOPS_H_ 5 | #error only can be included directly 6 | #endif 7 | 8 | #define BITS_PER_LONG 64 9 | 10 | #define HAVE_BUILTIN_FLS 1 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /lib/ppc64/asm/handlers.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/handlers.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/hcall.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/hcall.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_IO_H_ 2 | #define _ASMPPC64_IO_H_ 3 | 4 | #define __iomem 5 | 6 | #include 7 | #endif 8 | -------------------------------------------------------------------------------- /lib/ppc64/asm/memory_areas.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_MEMORY_AREAS_H_ 2 | #define _ASMPPC64_MEMORY_AREAS_H_ 3 | 4 | #include 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /lib/ppc64/asm/page.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/ppc_asm.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/ppc_asm.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/processor.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/processor.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/ptrace.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_PTRACE_H_ 2 | #define _ASMPPC64_PTRACE_H_ 3 | 4 | #define KERNEL_REDZONE_SIZE 288 5 | #define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */ 6 | 7 | #ifndef __ASSEMBLY__ 8 | struct pt_regs { 9 | unsigned long gpr[32]; 10 | unsigned long nip; 11 | unsigned long msr; 12 | unsigned long ctr; 13 | unsigned long link; 14 | unsigned long xer; 15 | unsigned long ccr; 16 | unsigned long trap; 17 | }; 18 | 19 | #define STACK_INT_FRAME_SIZE (sizeof(struct pt_regs) + \ 20 | STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE) 21 | 22 | #endif /* __ASSEMBLY__ */ 23 | 24 | #endif /* _ASMPPC64_PTRACE_H_ */ 25 | -------------------------------------------------------------------------------- /lib/ppc64/asm/rtas.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/rtas.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/setup.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/setup.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/smp.h: -------------------------------------------------------------------------------- 1 | #include "../../powerpc/asm/smp.h" 2 | -------------------------------------------------------------------------------- /lib/ppc64/asm/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_SPINLOCK_H_ 2 | #define _ASMPPC64_SPINLOCK_H_ 3 | 4 | #include 5 | 6 | #endif /* _ASMPPC64_SPINLOCK_H_ */ 7 | -------------------------------------------------------------------------------- /lib/ppc64/asm/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMPPC64_STACK_H_ 2 | #define _ASMPPC64_STACK_H_ 3 | 4 | #ifndef _STACK_H_ 5 | #error Do not directly include . Just use . 6 | #endif 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /lib/s390x/.gitignore: -------------------------------------------------------------------------------- 1 | asm-offsets.[hs] 2 | -------------------------------------------------------------------------------- /lib/s390x/asm/asm-offsets.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2017 Red Hat Inc 4 | * 5 | * Authors: 6 | * David Hildenbrand 7 | */ 8 | #include 9 | -------------------------------------------------------------------------------- /lib/s390x/asm/barrier.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2017 Red Hat Inc 4 | * 5 | * Authors: 6 | * Thomas Huth 7 | * David Hildenbrand 8 | */ 9 | #ifndef _ASMS390X_BARRIER_H_ 10 | #define _ASMS390X_BARRIER_H_ 11 | 12 | #include 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /lib/s390x/asm/bitops.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Bitops taken from the kernel as most developers are already used 4 | * to them. 5 | * 6 | * Copyright IBM Corp. 1999,2013 7 | * 8 | * Author(s): Martin Schwidefsky , 9 | * 10 | */ 11 | #ifndef _ASMS390X_BITOPS_H_ 12 | #define _ASMS390X_BITOPS_H_ 13 | 14 | #ifndef _BITOPS_H_ 15 | #error only can be included directly 16 | #endif 17 | 18 | #define BITS_PER_LONG 64 19 | 20 | static inline bool test_bit(unsigned long nr, 21 | const volatile unsigned long *ptr) 22 | { 23 | const volatile unsigned char *addr; 24 | 25 | addr = ((const volatile unsigned char *)ptr); 26 | addr += (nr ^ (BITS_PER_LONG - 8)) >> 3; 27 | return (*addr >> (nr & 7)) & 1; 28 | } 29 | 30 | static inline bool test_bit_inv(unsigned long nr, 31 | const volatile unsigned long *ptr) 32 | { 33 | return test_bit(nr ^ (BITS_PER_LONG - 1), ptr); 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /lib/s390x/asm/cmm.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* 3 | * Copyright IBM Corp. 2017, 2022 4 | * Author(s): Claudio Imbrenda 5 | * Nico Boehr 6 | */ 7 | #include 8 | 9 | #ifndef PAGE_STATES_H 10 | #define PAGE_STATES_H 11 | 12 | #define ESSA_GET_STATE 0 13 | #define ESSA_SET_STABLE 1 14 | #define ESSA_SET_UNUSED 2 15 | #define ESSA_SET_VOLATILE 3 16 | #define ESSA_SET_POT_VOLATILE 4 17 | #define ESSA_SET_STABLE_RESIDENT 5 18 | #define ESSA_SET_STABLE_IF_RESIDENT 6 19 | #define ESSA_SET_STABLE_NODAT 7 20 | 21 | #define ESSA_MAX ESSA_SET_STABLE_NODAT 22 | 23 | #define ESSA_USAGE_STABLE 0 24 | #define ESSA_USAGE_UNUSED 1 25 | #define ESSA_USAGE_POT_VOLATILE 2 26 | #define ESSA_USAGE_VOLATILE 3 27 | 28 | static unsigned long essa(uint8_t state, unsigned long paddr) 29 | { 30 | uint64_t extr_state; 31 | 32 | asm volatile(".insn rrf,0xb9ab0000,%[extr_state],%[addr],%[new_state],0" \ 33 | : [extr_state] "=d" (extr_state) \ 34 | : [addr] "a" (paddr), [new_state] "i" (state)); 35 | 36 | return (unsigned long)extr_state; 37 | } 38 | 39 | /* 40 | * Unfortunately the availability is not indicated by stfl bits, but 41 | * we have to try to execute it and test for an operation exception. 42 | */ 43 | static inline bool check_essa_available(void) 44 | { 45 | expect_pgm_int(); 46 | essa(ESSA_GET_STATE, 0); 47 | return clear_pgm_int() == 0; 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /lib/s390x/asm/facility.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2017 Red Hat Inc 4 | * 5 | * Authors: 6 | * David Hildenbrand 7 | */ 8 | #ifndef _ASMS390X_FACILITY_H_ 9 | #define _ASMS390X_FACILITY_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define NB_STFL_DOUBLEWORDS 32 18 | extern uint64_t stfl_doublewords[]; 19 | 20 | static inline bool test_facility(int nr) 21 | { 22 | return test_bit_inv(nr, stfl_doublewords); 23 | } 24 | 25 | static inline void stfl(void) 26 | { 27 | asm volatile(" stfl 0(0)\n" : : : "memory"); 28 | } 29 | 30 | static inline void stfle(uint64_t *fac, unsigned int nb_doublewords) 31 | { 32 | register unsigned long r0 asm("0") = nb_doublewords - 1; 33 | 34 | asm volatile(" .insn s,0xb2b00000,0(%1)\n" 35 | : "+d" (r0) : "a" (fac) : "memory", "cc"); 36 | } 37 | 38 | static inline void setup_facilities(void) 39 | { 40 | stfl(); 41 | memcpy(stfl_doublewords, &lowcore.stfl, sizeof(lowcore.stfl)); 42 | if (test_facility(7)) 43 | stfle(stfl_doublewords, NB_STFL_DOUBLEWORDS); 44 | } 45 | 46 | enum supp_on_prot_facility { 47 | SOP_NONE, 48 | SOP_BASIC, 49 | SOP_ENHANCED_1, 50 | SOP_ENHANCED_2, 51 | }; 52 | 53 | static inline enum supp_on_prot_facility get_supp_on_prot_facility(void) 54 | { 55 | if (sclp_facilities.has_esop) { 56 | if (test_facility(131)) /* side-effect-access facility */ 57 | return SOP_ENHANCED_2; 58 | else 59 | return SOP_ENHANCED_1; 60 | } 61 | if (sclp_facilities.has_sop) 62 | return SOP_BASIC; 63 | return SOP_NONE; 64 | } 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /lib/s390x/asm/float.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2018 Red Hat Inc 4 | * 5 | * Authors: 6 | * David Hildenbrand 7 | */ 8 | #ifndef _ASMS390X_FLOAT_H_ 9 | #define _ASMS390X_FLOAT_H_ 10 | 11 | static inline void set_fpc(uint32_t fpc) 12 | { 13 | asm volatile(" lfpc %0\n" : : "m"(fpc) ); 14 | } 15 | 16 | static inline uint32_t get_fpc(void) 17 | { 18 | uint32_t fpc; 19 | 20 | asm volatile(" stfpc %0\n" : "=m"(fpc)); 21 | 22 | return fpc; 23 | } 24 | 25 | static inline uint8_t get_fpc_dxc(void) 26 | { 27 | return get_fpc() >> 8; 28 | } 29 | 30 | static inline void set_fpc_dxc(uint8_t dxc) 31 | { 32 | uint32_t fpc = get_fpc(); 33 | 34 | fpc = (fpc & ~0xff00) | ((uint32_t)dxc) << 8; 35 | 36 | set_fpc(fpc); 37 | } 38 | 39 | static inline void afp_enable(void) 40 | { 41 | ctl_set_bit(0, CTL0_AFP); 42 | } 43 | 44 | static inline void afp_disable(void) 45 | { 46 | ctl_clear_bit(0, CTL0_AFP); 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /lib/s390x/asm/io.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2017 Red Hat Inc 4 | * 5 | * Authors: 6 | * Thomas Huth 7 | * David Hildenbrand 8 | */ 9 | #ifndef _ASMS390X_IO_H_ 10 | #define _ASMS390X_IO_H_ 11 | 12 | #define __iomem 13 | 14 | #include 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /lib/s390x/asm/memory_areas.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMS390X_MEMORY_AREAS_H_ 2 | #define _ASMS390X_MEMORY_AREAS_H_ 3 | 4 | #define AREA_NORMAL_PFN (1 << 19) 5 | #define AREA_NORMAL_NUMBER 0 6 | #define AREA_NORMAL (1 << AREA_NORMAL_NUMBER) 7 | 8 | #define AREA_LOW_PFN 0 9 | #define AREA_LOW_NUMBER 1 10 | #define AREA_LOW (1 << AREA_LOW_NUMBER) 11 | 12 | #define MAX_AREAS 2 13 | 14 | #define AREA_DMA31 AREA_LOW 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /lib/s390x/asm/page.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2017 Red Hat Inc 4 | * 5 | * Authors: 6 | * Thomas Huth 7 | * David Hildenbrand 8 | */ 9 | #ifndef _ASMS390X_PAGE_H_ 10 | #define _ASMS390X_PAGE_H_ 11 | 12 | #include 13 | 14 | typedef uint64_t pgdval_t; /* Region-1 table entry */ 15 | typedef uint64_t p4dval_t; /* Region-2 table entry*/ 16 | typedef uint64_t pudval_t; /* Region-3 table entry */ 17 | typedef uint64_t pmdval_t; /* Segment table entry */ 18 | typedef uint64_t pteval_t; /* Page table entry */ 19 | 20 | typedef struct { pgdval_t pgd; } pgd_t; 21 | typedef struct { p4dval_t p4d; } p4d_t; 22 | typedef struct { pudval_t pud; } pud_t; 23 | typedef struct { pmdval_t pmd; } pmd_t; 24 | typedef struct { pteval_t pte; } pte_t; 25 | 26 | #define pgd_val(x) ((x).pgd) 27 | #define p4d_val(x) ((x).p4d) 28 | #define pud_val(x) ((x).pud) 29 | #define pmd_val(x) ((x).pmd) 30 | #define pte_val(x) ((x).pte) 31 | 32 | #define __pgd(x) ((pgd_t) { (x) } ) 33 | #define __p4d(x) ((p4d_t) { (x) } ) 34 | #define __pud(x) ((pud_t) { (x) } ) 35 | #define __pmd(x) ((pmd_t) { (x) } ) 36 | #define __pte(x) ((pte_t) { (x) } ) 37 | 38 | #define HPAGE_SHIFT 20 39 | #define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT) 40 | #define HPAGE_MASK (~(HPAGE_SIZE-1)) 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /lib/s390x/asm/spinlock.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2017 Red Hat Inc 4 | * 5 | * Authors: 6 | * Thomas Huth 7 | * David Hildenbrand 8 | */ 9 | #ifndef _ASMS390X_SPINLOCK_H_ 10 | #define _ASMS390X_SPINLOCK_H_ 11 | 12 | #include 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /lib/s390x/asm/stack.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Copyright (c) 2017 Red Hat Inc 4 | * 5 | * Authors: 6 | * Thomas Huth 7 | * David Hildenbrand 8 | */ 9 | #ifndef _ASMS390X_STACK_H_ 10 | #define _ASMS390X_STACK_H_ 11 | 12 | #ifndef _STACK_H_ 13 | #error Do not directly include . Just use . 14 | #endif 15 | 16 | #define HAVE_ARCH_BACKTRACE_FRAME 17 | #define HAVE_ARCH_BACKTRACE 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /lib/s390x/asm/time.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Clock utilities for s390 4 | * 5 | * Authors: 6 | * Thomas Huth 7 | * 8 | * Copied from the s390/intercept test by: 9 | * Pierre Morel 10 | */ 11 | #ifndef _ASMS390X_TIME_H_ 12 | #define _ASMS390X_TIME_H_ 13 | 14 | #define STCK_SHIFT_US (63 - 51) 15 | #define STCK_MAX ((1UL << 52) - 1) 16 | 17 | static inline uint64_t get_clock_us(void) 18 | { 19 | uint64_t clk; 20 | 21 | asm volatile(" stck %0 " : : "Q"(clk) : "memory"); 22 | 23 | return clk >> STCK_SHIFT_US; 24 | } 25 | 26 | static inline uint64_t get_clock_ms(void) 27 | { 28 | return get_clock_us() / 1000; 29 | } 30 | 31 | static inline void udelay(unsigned long us) 32 | { 33 | unsigned long startclk = get_clock_us(); 34 | unsigned long c; 35 | 36 | do { 37 | c = get_clock_us(); 38 | if (c < startclk) 39 | c += STCK_MAX; 40 | } while (c < startclk + us); 41 | } 42 | 43 | static inline void mdelay(unsigned long ms) 44 | { 45 | udelay(ms * 1000); 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /lib/s390x/asm/vector.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Vector facility related defines and functions 4 | * 5 | * Copyright IBM Corp. 2022 6 | * 7 | * Authors: 8 | * Nico Boehr 9 | */ 10 | #ifndef _ASMS390X_VECTOR_H_ 11 | #define _ASMS390X_VECTOR_H_ 12 | 13 | #define VEC_REGISTER_NUM 32 14 | #define VEC_REGISTER_SIZE 16 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /lib/s390x/fault.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Headers for fault.c 4 | * 5 | * Copyright 2021 IBM Corp. 6 | * 7 | * Authors: 8 | * Janosch Frank 9 | */ 10 | #ifndef _S390X_FAULT_H_ 11 | #define _S390X_FAULT_H_ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | /* Instruction execution prevention, i.e. no-execute, 101 */ 18 | static inline bool prot_is_iep(union teid teid) 19 | { 20 | if (!test_facility(130)) 21 | return false; 22 | /* IEP installed -> ESOP2 installed */ 23 | return teid_esop2_prot_code(teid) == PROT_IEP; 24 | } 25 | 26 | void print_decode_teid(uint64_t teid); 27 | 28 | #endif /* _S390X_FAULT_H_ */ 29 | -------------------------------------------------------------------------------- /lib/s390x/gs.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Guarded storage related definitions 4 | * 5 | * Copyright 2018 IBM Corp. 6 | * 7 | * Authors: 8 | * Martin Schwidefsky 9 | * Janosch Frank 10 | */ 11 | #include 12 | 13 | #ifndef _S390X_GS_H_ 14 | #define _S390X_GS_H_ 15 | 16 | struct gs_cb { 17 | uint64_t reserved; 18 | uint64_t gsd; 19 | uint64_t gssm; 20 | uint64_t gs_epl_a; 21 | }; 22 | 23 | struct gs_epl { 24 | uint8_t pad1; 25 | union { 26 | uint8_t gs_eam; 27 | struct { 28 | uint8_t : 6; 29 | uint8_t e : 1; 30 | uint8_t b : 1; 31 | }; 32 | }; 33 | union { 34 | uint8_t gs_eci; 35 | struct { 36 | uint8_t tx : 1; 37 | uint8_t cx : 1; 38 | uint8_t : 5; 39 | uint8_t in : 1; 40 | }; 41 | }; 42 | union { 43 | uint8_t gs_eai; 44 | struct { 45 | uint8_t : 1; 46 | uint8_t t : 1; 47 | uint8_t as : 2; 48 | uint8_t ar : 4; 49 | }; 50 | }; 51 | uint32_t pad2; 52 | uint64_t gs_eha; 53 | uint64_t gs_eia; 54 | uint64_t gs_eoa; 55 | uint64_t gs_eir; 56 | uint64_t gs_era; 57 | }; 58 | 59 | static inline void load_gs_cb(struct gs_cb *gs_cb) 60 | { 61 | asm volatile(".insn rxy,0xe3000000004d,0,%0" : : "Q" (*gs_cb)); 62 | } 63 | 64 | static inline void store_gs_cb(struct gs_cb *gs_cb) 65 | { 66 | asm volatile(".insn rxy,0xe30000000049,0,%0" : : "Q" (*gs_cb)); 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /lib/s390x/hardware.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Functions to retrieve information about the host system. 4 | * 5 | * Copyright (c) 2020 Red Hat Inc 6 | * Copyright 2022 IBM Corp. 7 | * 8 | * Authors: 9 | * Thomas Huth 10 | * Claudio Imbrenda 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include "hardware.h" 17 | #include "stsi.h" 18 | 19 | /* The string "QEMU" in EBCDIC */ 20 | static const uint8_t qemu_ebcdic[] = { 0xd8, 0xc5, 0xd4, 0xe4 }; 21 | /* The string "KVM/" in EBCDIC */ 22 | static const uint8_t kvm_ebcdic[] = { 0xd2, 0xe5, 0xd4, 0x61 }; 23 | 24 | static enum s390_host do_detect_host(void *buf) 25 | { 26 | struct sysinfo_3_2_2 *stsi_322 = buf; 27 | 28 | if (stsi_get_fc() == 2) 29 | return HOST_IS_LPAR; 30 | 31 | if (stsi_get_fc() != 3) 32 | return HOST_IS_UNKNOWN; 33 | 34 | if (!stsi(buf, 1, 1, 1)) { 35 | /* 36 | * If the manufacturer string is "QEMU" in EBCDIC, then we 37 | * are on TCG (otherwise the string is "IBM" in EBCDIC) 38 | */ 39 | if (!memcmp((char *)buf + 32, qemu_ebcdic, sizeof(qemu_ebcdic))) 40 | return HOST_IS_TCG; 41 | } 42 | 43 | if (!stsi(buf, 3, 2, 2)) { 44 | /* 45 | * If the manufacturer string is "KVM/" in EBCDIC, then we 46 | * are on KVM. 47 | */ 48 | if (!memcmp(&stsi_322->vm[0].cpi, kvm_ebcdic, sizeof(kvm_ebcdic))) 49 | return HOST_IS_KVM; 50 | } 51 | 52 | return HOST_IS_UNKNOWN; 53 | } 54 | 55 | enum s390_host detect_host(void) 56 | { 57 | static enum s390_host host = HOST_IS_UNKNOWN; 58 | static bool initialized = false; 59 | void *buf; 60 | 61 | if (initialized) 62 | return host; 63 | 64 | buf = alloc_page(); 65 | host = do_detect_host(buf); 66 | free_page(buf); 67 | initialized = true; 68 | return host; 69 | } 70 | -------------------------------------------------------------------------------- /lib/s390x/hardware.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | /* 3 | * Functions to retrieve information about the host system. 4 | * 5 | * Copyright (c) 2020 Red Hat Inc 6 | * Copyright 2022 IBM Corp. 7 | * 8 | * Authors: 9 | * Claudio Imbrenda 10 | */ 11 | 12 | #ifndef _S390X_HARDWARE_H_ 13 | #define _S390X_HARDWARE_H_ 14 | #include 15 | 16 | #define MACHINE_Z15 0x8561 17 | #define MACHINE_Z15T02 0x8562 18 | 19 | enum s390_host { 20 | HOST_IS_UNKNOWN, 21 | HOST_IS_LPAR, 22 | HOST_IS_KVM, 23 | HOST_IS_TCG 24 | }; 25 | 26 | enum s390_host detect_host(void); 27 | 28 | static inline uint16_t get_machine_id(void) 29 | { 30 | return stidp() >> 16; 31 | } 32 | 33 | static inline bool host_is_tcg(void) 34 | { 35 | return detect_host() == HOST_IS_TCG; 36 | } 37 | 38 | static inline bool host_is_kvm(void) 39 | { 40 | return detect_host() == HOST_IS_KVM; 41 | } 42 | 43 | static inline bool host_is_lpar(void) 44 | { 45 | return detect_host() == HOST_IS_LPAR; 46 | } 47 | 48 | static inline bool host_is_qemu(void) 49 | { 50 | return host_is_tcg() || host_is_kvm(); 51 | } 52 | 53 | static inline bool machine_is_z15(void) 54 | { 55 | uint16_t machine = get_machine_id(); 56 | 57 | return machine == MACHINE_Z15 || machine == MACHINE_Z15T02; 58 | } 59 | 60 | #endif /* _S390X_HARDWARE_H_ */ 61 | -------------------------------------------------------------------------------- /lib/s390x/interrupt.h: -------------------------------------------------------------------------------- 1 | #ifndef _S390X_INTERRUPT_H_ 2 | #define _S390X_INTERRUPT_H_ 3 | #include 4 | 5 | int register_io_int_func(void (*f)(void)); 6 | int unregister_io_int_func(void (*f)(void)); 7 | 8 | #endif /* INTERRUPT_H */ 9 | -------------------------------------------------------------------------------- /lib/s390x/io.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * s390x io implementation 4 | * 5 | * Copyright (c) 2017 Red Hat Inc 6 | * 7 | * Authors: 8 | * Thomas Huth 9 | * David Hildenbrand 10 | */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "sclp.h" 17 | #include "uv.h" 18 | #include "smp.h" 19 | 20 | extern char ipl_args[]; 21 | uint64_t stfl_doublewords[NB_STFL_DOUBLEWORDS]; 22 | 23 | static struct spinlock lock; 24 | 25 | void setup(void); 26 | 27 | void puts(const char *s) 28 | { 29 | spin_lock(&lock); 30 | sclp_print(s); 31 | spin_unlock(&lock); 32 | } 33 | 34 | void setup(void) 35 | { 36 | setup_args_progname(ipl_args); 37 | setup_facilities(); 38 | sclp_read_info(); 39 | sclp_facilities_setup(); 40 | sclp_console_setup(); 41 | sclp_memory_setup(); 42 | uv_setup(); 43 | smp_setup(); 44 | } 45 | 46 | void exit(int code) 47 | { 48 | smp_teardown(); 49 | printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1); 50 | while (1) { 51 | sigp(stap(), SIGP_STOP, 0, NULL); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/s390x/malloc_io.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * I/O page allocation 4 | * 5 | * Copyright (c) 2021 IBM Corp 6 | * 7 | * Authors: 8 | * Pierre Morel 9 | * 10 | * Using this interface provide host access to the allocated pages in 11 | * case the guest is a protected guest. 12 | * This is needed for I/O buffers. 13 | * 14 | */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | static int share_pages(void *p, int count) 25 | { 26 | int i = 0; 27 | 28 | for (i = 0; i < count; i++, p += PAGE_SIZE) 29 | if (uv_set_shared((unsigned long)p)) 30 | break; 31 | return i; 32 | } 33 | 34 | static void unshare_pages(void *p, int count) 35 | { 36 | int i; 37 | 38 | for (i = count; i > 0; i--, p += PAGE_SIZE) 39 | uv_remove_shared((unsigned long)p); 40 | } 41 | 42 | void *alloc_io_mem(int size, int flags) 43 | { 44 | int order = get_order(PAGE_ALIGN(size) >> PAGE_SHIFT); 45 | void *p; 46 | int n; 47 | 48 | assert(size); 49 | 50 | p = alloc_pages_flags(order, AREA_DMA31 | flags); 51 | if (!p || !uv_os_is_guest()) 52 | return p; 53 | 54 | n = share_pages(p, 1 << order); 55 | if (n == 1 << order) 56 | return p; 57 | 58 | unshare_pages(p, n); 59 | free_pages(p); 60 | return NULL; 61 | } 62 | 63 | void free_io_mem(void *p, int size) 64 | { 65 | int order = get_order(PAGE_ALIGN(size) >> PAGE_SHIFT); 66 | 67 | assert(IS_ALIGNED((uintptr_t)p, PAGE_SIZE)); 68 | 69 | if (uv_os_is_guest()) 70 | unshare_pages(p, 1 << order); 71 | free_pages(p); 72 | } 73 | -------------------------------------------------------------------------------- /lib/s390x/malloc_io.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * I/O allocations 4 | * 5 | * Copyright (c) 2021 IBM Corp 6 | * 7 | * Authors: 8 | * Pierre Morel 9 | * 10 | */ 11 | #ifndef _S390X_MALLOC_IO_H_ 12 | #define _S390X_MALLOC_IO_H_ 13 | 14 | /* 15 | * Allocates a page aligned page bound range of contiguous real or 16 | * absolute memory in the DMA31 region large enough to contain size 17 | * bytes. 18 | * If Protected Virtualisation facility is present, shares the pages 19 | * with the host. 20 | * If all the pages for the specified size cannot be reserved, 21 | * the function rewinds the partial allocation and a NULL pointer 22 | * is returned. 23 | * 24 | * @size: the minimal size allocated in byte. 25 | * @flags: the flags used for the underlying page allocator. 26 | * 27 | * Errors: 28 | * The allocation will assert the size parameter, will fail if the 29 | * underlying page allocator fail or in the case of protected 30 | * virtualisation if the sharing of the pages fails. 31 | * 32 | * Returns a pointer to the first page in case of success, NULL otherwise. 33 | */ 34 | void *alloc_io_mem(int size, int flags); 35 | 36 | /* 37 | * Frees a previously memory space allocated by alloc_io_mem. 38 | * If Protected Virtualisation facility is present, unshares the pages 39 | * with the host. 40 | * The address must be aligned on a page boundary otherwise an assertion 41 | * breaks the program. 42 | */ 43 | void free_io_mem(void *p, int size); 44 | 45 | #endif /* _S390X_MALLOC_IO_H_ */ 46 | -------------------------------------------------------------------------------- /lib/s390x/smp.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * s390x smp 4 | * 5 | * Copyright (c) 2019 IBM Corp 6 | * 7 | * Authors: 8 | * Janosch Frank 9 | */ 10 | #ifndef _S390X_SMP_H_ 11 | #define _S390X_SMP_H_ 12 | 13 | #include 14 | 15 | struct cpu_status { 16 | uint64_t fprs[16]; /* 0x0000 */ 17 | uint64_t grs[16]; /* 0x0080 */ 18 | struct psw psw; /* 0x0100 */ 19 | uint8_t pad_0x0110[0x0118 - 0x0110]; /* 0x0110 */ 20 | uint32_t prefix; /* 0x0118 */ 21 | uint32_t fpc; /* 0x011c */ 22 | uint8_t pad_0x0120[0x0124 - 0x0120]; /* 0x0120 */ 23 | uint32_t todpr; /* 0x0124 */ 24 | uint64_t cputm; /* 0x0128 */ 25 | uint64_t ckc; /* 0x0130 */ 26 | uint8_t pad_0x0138[0x0140 - 0x0138]; /* 0x0138 */ 27 | uint32_t ars[16]; /* 0x0140 */ 28 | uint64_t crs[16]; /* 0x0384 */ 29 | }; 30 | 31 | int smp_query_num_cpus(void); 32 | struct cpu *smp_cpu_from_addr(uint16_t addr); 33 | struct cpu *smp_cpu_from_idx(uint16_t idx); 34 | uint16_t smp_cpu_addr(uint16_t idx); 35 | bool smp_cpu_stopped(uint16_t idx); 36 | bool smp_sense_running_status(uint16_t idx); 37 | int smp_cpu_restart(uint16_t idx); 38 | int smp_cpu_restart_nowait(uint16_t idx); 39 | int smp_cpu_start(uint16_t idx, struct psw psw); 40 | int smp_cpu_stop(uint16_t idx); 41 | int smp_cpu_stop_nowait(uint16_t idx); 42 | int smp_cpu_stop_store_status(uint16_t idx); 43 | int smp_cpu_destroy(uint16_t idx); 44 | int smp_cpu_setup(uint16_t idx, struct psw psw); 45 | void smp_teardown(void); 46 | void smp_setup(void); 47 | int smp_sigp(uint16_t idx, uint8_t order, unsigned long parm, uint32_t *status); 48 | struct lowcore *smp_get_lowcore(uint16_t idx); 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /lib/s390x/stack.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * s390x stack implementation 4 | * 5 | * Copyright (c) 2017 Red Hat Inc 6 | * Copyright 2021 IBM Corp 7 | * 8 | * Authors: 9 | * Thomas Huth 10 | * David Hildenbrand 11 | * Janosch Frank 12 | */ 13 | #include 14 | #include 15 | #include 16 | 17 | int backtrace_frame(const void *frame, const void **return_addrs, int max_depth) 18 | { 19 | int depth = 0; 20 | struct stack_frame *stack = (struct stack_frame *)frame; 21 | 22 | for (depth = 0; stack && depth < max_depth; depth++) { 23 | return_addrs[depth] = (void *)stack->grs[8]; 24 | stack = stack->back_chain; 25 | } 26 | 27 | return depth; 28 | } 29 | 30 | int backtrace(const void **return_addrs, int max_depth) 31 | { 32 | return backtrace_frame(__builtin_frame_address(0), 33 | return_addrs, max_depth); 34 | } 35 | -------------------------------------------------------------------------------- /lib/s390x/stsi.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Structures used to Store System Information 4 | * 5 | * Copyright IBM Corp. 2022 6 | */ 7 | 8 | #ifndef _S390X_STSI_H_ 9 | #define _S390X_STSI_H_ 10 | 11 | struct sysinfo_3_2_2 { 12 | uint8_t reserved[31]; 13 | uint8_t count; 14 | struct { 15 | uint8_t reserved2[4]; 16 | uint16_t total_cpus; 17 | uint16_t conf_cpus; 18 | uint16_t standby_cpus; 19 | uint16_t reserved_cpus; 20 | uint8_t name[8]; 21 | uint32_t caf; 22 | uint8_t cpi[16]; 23 | uint8_t reserved5[3]; 24 | uint8_t ext_name_encoding; 25 | uint32_t reserved3; 26 | uint8_t uuid[16]; 27 | } vm[8]; 28 | uint8_t reserved4[1504]; 29 | uint8_t ext_names[8][256]; 30 | }; 31 | 32 | #endif /* _S390X_STSI_H_ */ 33 | -------------------------------------------------------------------------------- /lib/s390x/uv.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 | #ifndef _S390X_UV_H_ 3 | #define _S390X_UV_H_ 4 | 5 | #include 6 | #include 7 | 8 | bool uv_os_is_guest(void); 9 | bool uv_os_is_host(void); 10 | bool uv_query_test_call(unsigned int nr); 11 | const struct uv_cb_qui *uv_get_query_data(void); 12 | void uv_init(void); 13 | int uv_setup(void); 14 | void uv_create_guest(struct vm *vm); 15 | void uv_destroy_guest(struct vm *vm); 16 | int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t tweak); 17 | void uv_verify_load(struct vm *vm); 18 | 19 | /* 20 | * To run PV guests we need to setup a few things: 21 | * - A valid primary ASCE that contains the guest memory and has the P bit set. 22 | * - A valid home space ASCE for the UV calls that use home space addresses. 23 | */ 24 | static inline void uv_setup_asces(void) 25 | { 26 | uint64_t asce; 27 | 28 | /* We need to have a valid primary ASCE to run guests. */ 29 | setup_vm(); 30 | 31 | /* Set P bit in ASCE as it is required for PV guests */ 32 | asce = stctg(1) | ASCE_P; 33 | lctlg(1, asce); 34 | 35 | /* Copy ASCE into home space CR */ 36 | lctlg(13, asce); 37 | } 38 | 39 | #endif /* UV_H */ 40 | -------------------------------------------------------------------------------- /lib/setjmp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * setjmp/longjmp prototypes 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | #ifndef _LIBCFLAT_SETJMP_H_ 8 | #define _LIBCFLAT_SETJMP_H_ 9 | 10 | typedef struct jmp_buf_tag { 11 | long int regs[8]; 12 | } jmp_buf[1]; 13 | 14 | extern int setjmp (struct jmp_buf_tag env[1]); 15 | extern void longjmp (struct jmp_buf_tag env[1], int val) 16 | __attribute__ ((__noreturn__)); 17 | 18 | #endif /* setjmp.h */ 19 | -------------------------------------------------------------------------------- /lib/stack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header for stack related functions 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | #ifndef _STACK_H_ 8 | #define _STACK_H_ 9 | 10 | #include 11 | #include 12 | 13 | #ifdef HAVE_ARCH_BACKTRACE_FRAME 14 | extern int backtrace_frame(const void *frame, const void **return_addrs, 15 | int max_depth); 16 | #else 17 | static inline int 18 | backtrace_frame(const void *frame __unused, const void **return_addrs __unused, 19 | int max_depth __unused) 20 | { 21 | return 0; 22 | } 23 | #endif 24 | 25 | extern int backtrace(const void **return_addrs, int max_depth); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /lib/stdlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header for libc stdlib functions 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | #ifndef _STDLIB_H_ 8 | #define _STDLIB_H_ 9 | 10 | long int strtol(const char *nptr, char **endptr, int base); 11 | unsigned long int strtoul(const char *nptr, char **endptr, int base); 12 | long long int strtoll(const char *nptr, char **endptr, int base); 13 | unsigned long long int strtoull(const char *nptr, char **endptr, int base); 14 | 15 | #endif /* _STDLIB_H_ */ 16 | -------------------------------------------------------------------------------- /lib/string.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header for libc string functions 3 | * 4 | * This code is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Library General Public License version 2. 6 | */ 7 | #ifndef _STRING_H_ 8 | #define _STRING_H_ 9 | 10 | extern size_t strlen(const char *buf); 11 | extern size_t strnlen(const char *buf, size_t maxlen); 12 | extern char *strcat(char *dest, const char *src); 13 | extern char *strcpy(char *dest, const char *src); 14 | extern int strcmp(const char *a, const char *b); 15 | extern int strncmp(const char *a, const char *b, size_t n); 16 | extern char *strchr(const char *s, int c); 17 | extern char *strrchr(const char *s, int c); 18 | extern char *strchrnul(const char *s, int c); 19 | extern char *strstr(const char *haystack, const char *needle); 20 | extern void *memset(void *s, int c, size_t n); 21 | extern void *memcpy(void *dest, const void *src, size_t n); 22 | extern int memcmp(const void *s1, const void *s2, size_t n); 23 | extern void *memmove(void *dest, const void *src, size_t n); 24 | extern void *memchr(const void *s, int c, size_t n); 25 | 26 | #endif /* _STRING_H_ */ 27 | -------------------------------------------------------------------------------- /lib/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 3 | * 4 | * This work is licensed under the terms of the GNU LGPL, version 2. 5 | */ 6 | #include 7 | #include 8 | #include "util.h" 9 | 10 | int parse_keyval(char *s, long *val) 11 | { 12 | char *p; 13 | 14 | p = strchr(s, '='); 15 | if (!p) 16 | return -1; 17 | 18 | *val = strtol(p+1, NULL, 0); 19 | return p - s; 20 | } 21 | -------------------------------------------------------------------------------- /lib/util.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_H_ 2 | #define _UTIL_H_ 3 | /* 4 | * Collection of utility functions to share between unit tests. 5 | * 6 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 7 | * 8 | * This work is licensed under the terms of the GNU LGPL, version 2. 9 | */ 10 | 11 | /* 12 | * parse_keyval extracts the integer from a string formatted as 13 | * string=integer. This is useful for passing expected values to 14 | * the unit test on the command line, i.e. it helps parse QEMU 15 | * command lines that include something like -append var1=1 var2=2 16 | * @s is the input string, likely a command line parameter, and 17 | * @val is a pointer to where the integer will be stored. 18 | * 19 | * Returns the offset of the '=', or -1 if no keyval pair is found. 20 | */ 21 | extern int parse_keyval(char *s, long *val); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /lib/vmalloc.h: -------------------------------------------------------------------------------- 1 | #ifndef _VMALLOC_H_ 2 | #define _VMALLOC_H_ 3 | 4 | #include 5 | 6 | /* Allocate consecutive virtual pages (without backing) */ 7 | extern void *alloc_vpages(ulong nr); 8 | /* Allocate consecutive and aligned virtual pages (without backing) */ 9 | extern void *alloc_vpages_aligned(ulong nr, unsigned int alignment_order); 10 | 11 | /* Allocate one virtual page (without backing) */ 12 | extern void *alloc_vpage(void); 13 | /* Set the top of the virtual address space */ 14 | extern void init_alloc_vpage(void *top); 15 | /* Set up the virtual allocator; also sets up the page allocator if needed */ 16 | extern void setup_vm(void); 17 | /* As above, plus passes an opaque value to setup_mmu(). */ 18 | extern void __setup_vm(void *opaque); 19 | 20 | /* Set up paging */ 21 | extern void *setup_mmu(phys_addr_t top, void *opaque); 22 | /* Walk the page table and resolve the virtual address to a physical address */ 23 | extern phys_addr_t virt_to_pte_phys(pgd_t *pgtable, void *virt); 24 | /* Map the virtual address to the physical address for the given page tables */ 25 | extern pteval_t *install_page(pgd_t *pgtable, phys_addr_t phys, void *virt); 26 | 27 | /* Map consecutive physical pages */ 28 | void *vmap(phys_addr_t phys, size_t size); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /lib/x86/acpi.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | #include "acpi.h" 3 | 4 | #ifdef CONFIG_EFI 5 | struct rsdp_descriptor *efi_rsdp = NULL; 6 | 7 | void set_efi_rsdp(struct rsdp_descriptor *rsdp) 8 | { 9 | efi_rsdp = rsdp; 10 | } 11 | 12 | static struct rsdp_descriptor *get_rsdp(void) 13 | { 14 | if (efi_rsdp == NULL) { 15 | printf("Can't find RSDP from UEFI, maybe set_efi_rsdp() was not called\n"); 16 | } 17 | return efi_rsdp; 18 | } 19 | #else 20 | static struct rsdp_descriptor *get_rsdp(void) 21 | { 22 | struct rsdp_descriptor *rsdp; 23 | unsigned long addr; 24 | 25 | for (addr = 0xe0000; addr < 0x100000; addr += 16) { 26 | rsdp = (void *)addr; 27 | if (rsdp->signature == RSDP_SIGNATURE_8BYTE) 28 | break; 29 | } 30 | 31 | if (addr == 0x100000) { 32 | return NULL; 33 | } 34 | 35 | return rsdp; 36 | } 37 | #endif /* CONFIG_EFI */ 38 | 39 | void* find_acpi_table_addr(u32 sig) 40 | { 41 | struct rsdp_descriptor *rsdp; 42 | struct rsdt_descriptor_rev1 *rsdt; 43 | void *end; 44 | int i; 45 | 46 | /* FACS is special... */ 47 | if (sig == FACS_SIGNATURE) { 48 | struct fadt_descriptor_rev1 *fadt; 49 | fadt = find_acpi_table_addr(FACP_SIGNATURE); 50 | if (!fadt) { 51 | return NULL; 52 | } 53 | return (void*)(ulong)fadt->firmware_ctrl; 54 | } 55 | 56 | rsdp = get_rsdp(); 57 | if (rsdp == NULL) { 58 | printf("Can't find RSDP\n"); 59 | return 0; 60 | } 61 | 62 | if (sig == RSDP_SIGNATURE) { 63 | return rsdp; 64 | } 65 | 66 | rsdt = (void*)(ulong)rsdp->rsdt_physical_address; 67 | if (!rsdt || rsdt->signature != RSDT_SIGNATURE) 68 | return 0; 69 | 70 | if (sig == RSDT_SIGNATURE) { 71 | return rsdt; 72 | } 73 | 74 | end = (void*)rsdt + rsdt->length; 75 | for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) { 76 | struct acpi_table *t = (void*)(ulong)rsdt->table_offset_entry[i]; 77 | if (t && t->signature == sig) { 78 | return t; 79 | } 80 | } 81 | return NULL; 82 | } 83 | -------------------------------------------------------------------------------- /lib/x86/amd_sev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * AMD SEV support in kvm-unit-tests 3 | * 4 | * Copyright (c) 2021, Google Inc 5 | * 6 | * Authors: 7 | * Zixuan Wang 8 | * 9 | * SPDX-License-Identifier: LGPL-2.0-or-later 10 | */ 11 | 12 | #ifndef _X86_AMD_SEV_H_ 13 | #define _X86_AMD_SEV_H_ 14 | 15 | #ifdef CONFIG_EFI 16 | 17 | #include "libcflat.h" 18 | #include "desc.h" 19 | #include "asm/page.h" 20 | #include "efi.h" 21 | 22 | /* 23 | * AMD Programmer's Manual Volume 3 24 | * - Section "Function 8000_0000h - Maximum Extended Function Number and Vendor String" 25 | * - Section "Function 8000_001Fh - Encrypted Memory Capabilities" 26 | */ 27 | #define CPUID_FN_LARGEST_EXT_FUNC_NUM 0x80000000 28 | #define CPUID_FN_ENCRYPT_MEM_CAPAB 0x8000001f 29 | #define SEV_SUPPORT_MASK 0b10 30 | 31 | /* 32 | * AMD Programmer's Manual Volume 2 33 | * - Section "SEV_STATUS MSR" 34 | */ 35 | #define MSR_SEV_STATUS 0xc0010131 36 | #define SEV_ENABLED_MASK 0b1 37 | #define SEV_ES_ENABLED_MASK 0b10 38 | 39 | bool amd_sev_enabled(void); 40 | efi_status_t setup_amd_sev(void); 41 | 42 | /* 43 | * AMD Programmer's Manual Volume 2 44 | * - Section "#VC Exception" 45 | */ 46 | #define SEV_ES_VC_HANDLER_VECTOR 29 47 | 48 | /* 49 | * AMD Programmer's Manual Volume 2 50 | * - Section "GHCB" 51 | */ 52 | #define SEV_ES_GHCB_MSR_INDEX 0xc0010130 53 | 54 | bool amd_sev_es_enabled(void); 55 | efi_status_t setup_amd_sev_es(void); 56 | void setup_ghcb_pte(pgd_t *page_table); 57 | 58 | unsigned long long get_amd_sev_c_bit_mask(void); 59 | unsigned long long get_amd_sev_addr_upperbound(void); 60 | 61 | #endif /* CONFIG_EFI */ 62 | 63 | #endif /* _X86_AMD_SEV_H_ */ 64 | -------------------------------------------------------------------------------- /lib/x86/asm/barrier.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMX86_BARRIER_H_ 2 | #define _ASMX86_BARRIER_H_ 3 | /* 4 | * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | 9 | #define mb() asm volatile("mfence":::"memory") 10 | #define rmb() asm volatile("lfence":::"memory") 11 | #define wmb() asm volatile("sfence":::"memory") 12 | 13 | #define smp_rmb() barrier() 14 | #define smp_wmb() barrier() 15 | 16 | /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ 17 | static inline void rep_nop(void) 18 | { 19 | asm volatile("rep; nop" ::: "memory"); 20 | } 21 | 22 | static inline void cpu_relax(void) 23 | { 24 | rep_nop(); 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /lib/x86/asm/bitops.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMX86_BITOPS_H_ 2 | #define _ASMX86_BITOPS_H_ 3 | 4 | #ifndef _BITOPS_H_ 5 | #error only can be included directly 6 | #endif 7 | 8 | #ifdef __x86_64__ 9 | #define BITS_PER_LONG 64 10 | #else 11 | #define BITS_PER_LONG 32 12 | #endif 13 | 14 | #define HAVE_BUILTIN_FLS 1 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /lib/x86/asm/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMX86_IO_H_ 2 | #define _ASMX86_IO_H_ 3 | 4 | #define __iomem 5 | 6 | #define inb inb 7 | static inline uint8_t inb(unsigned long port) 8 | { 9 | unsigned char value; 10 | asm volatile("inb %w1, %0" : "=a" (value) : "Nd" ((unsigned short)port)); 11 | return value; 12 | } 13 | 14 | #define inw inw 15 | static inline uint16_t inw(unsigned long port) 16 | { 17 | unsigned short value; 18 | asm volatile("inw %w1, %0" : "=a" (value) : "Nd" ((unsigned short)port)); 19 | return value; 20 | } 21 | 22 | #define inl inl 23 | static inline uint32_t inl(unsigned long port) 24 | { 25 | unsigned int value; 26 | asm volatile("inl %w1, %0" : "=a" (value) : "Nd" ((unsigned short)port)); 27 | return value; 28 | } 29 | 30 | #define outb outb 31 | static inline void outb(uint8_t value, unsigned long port) 32 | { 33 | asm volatile("outb %b0, %w1" : : "a"(value), "Nd"((unsigned short)port)); 34 | } 35 | 36 | #define outw outw 37 | static inline void outw(uint16_t value, unsigned long port) 38 | { 39 | asm volatile("outw %w0, %w1" : : "a"(value), "Nd"((unsigned short)port)); 40 | } 41 | 42 | #define outl outl 43 | static inline void outl(uint32_t value, unsigned long port) 44 | { 45 | asm volatile("outl %0, %w1" : : "a"(value), "Nd"((unsigned short)port)); 46 | } 47 | 48 | #define virt_to_phys virt_to_phys 49 | static inline unsigned long virt_to_phys(const void *virt) 50 | { 51 | return (unsigned long)virt; 52 | } 53 | 54 | #define phys_to_virt phys_to_virt 55 | static inline void *phys_to_virt(unsigned long phys) 56 | { 57 | return (void *)phys; 58 | } 59 | 60 | #define ioremap ioremap 61 | void __iomem *ioremap(phys_addr_t phys_addr, size_t size); 62 | 63 | #include 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /lib/x86/asm/memory_areas.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMX86_MEMORY_AREAS_H_ 2 | #define _ASMX86_MEMORY_AREAS_H_ 3 | 4 | #define AREA_NORMAL_PFN BIT(36-12) 5 | #define AREA_NORMAL_NUMBER 0 6 | #define AREA_NORMAL (1 << AREA_NORMAL_NUMBER) 7 | 8 | #define AREA_HIGH_PFN BIT(32-12) 9 | #define AREA_HIGH_NUMBER 1 10 | #define AREA_HIGH (1 << AREA_HIGH_NUMBER) 11 | 12 | #define AREA_LOW_PFN BIT(24-12) 13 | #define AREA_LOW_NUMBER 2 14 | #define AREA_LOW (1 << AREA_LOW_NUMBER) 15 | 16 | #define AREA_LOWEST_PFN 0 17 | #define AREA_LOWEST_NUMBER 3 18 | #define AREA_LOWEST (1 << AREA_LOWEST_NUMBER) 19 | 20 | #define MAX_AREAS 4 21 | 22 | #define AREA_DMA24 AREA_LOWEST 23 | #define AREA_DMA32 (AREA_LOWEST | AREA_LOW) 24 | #define AREA_PAE36 (AREA_LOWEST | AREA_LOW | AREA_HIGH) 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /lib/x86/asm/pci.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMX86_PCI_H_ 2 | #define _ASMX86_PCI_H_ 3 | /* 4 | * Copyright (C) 2013, Red Hat Inc, Michael S. Tsirkin 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include "libcflat.h" 9 | #include "pci.h" 10 | #include "x86/asm/io.h" 11 | 12 | #define PCI_CONF1_ADDRESS(dev, reg) ((0x1 << 31) | (dev << 8) | reg) 13 | 14 | static inline uint8_t pci_config_readb(pcidevaddr_t dev, uint8_t reg) 15 | { 16 | outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); 17 | return inb(0xCFC); 18 | } 19 | 20 | static inline uint16_t pci_config_readw(pcidevaddr_t dev, uint8_t reg) 21 | { 22 | outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); 23 | return inw(0xCFC); 24 | } 25 | 26 | static inline uint32_t pci_config_readl(pcidevaddr_t dev, uint8_t reg) 27 | { 28 | outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); 29 | return inl(0xCFC); 30 | } 31 | 32 | static inline void pci_config_writeb(pcidevaddr_t dev, uint8_t reg, 33 | uint8_t val) 34 | { 35 | outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); 36 | outb(val, 0xCFC); 37 | } 38 | 39 | static inline void pci_config_writew(pcidevaddr_t dev, uint8_t reg, 40 | uint16_t val) 41 | { 42 | outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); 43 | outw(val, 0xCFC); 44 | } 45 | 46 | static inline void pci_config_writel(pcidevaddr_t dev, uint8_t reg, 47 | uint32_t val) 48 | { 49 | outl(PCI_CONF1_ADDRESS(dev, reg), 0xCF8); 50 | outl(val, 0xCFC); 51 | } 52 | 53 | static inline 54 | phys_addr_t pci_translate_addr(pcidevaddr_t dev __unused, uint64_t addr) 55 | { 56 | return addr; 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /lib/x86/asm/setup.h: -------------------------------------------------------------------------------- 1 | #ifndef _X86_ASM_SETUP_H_ 2 | #define _X86_ASM_SETUP_H_ 3 | 4 | unsigned long setup_tss(u8 *stacktop); 5 | 6 | #ifdef CONFIG_EFI 7 | #include "x86/acpi.h" 8 | #include "x86/apic.h" 9 | #include "x86/processor.h" 10 | #include "x86/smp.h" 11 | #include "asm/page.h" 12 | #include "efi.h" 13 | #include "x86/amd_sev.h" 14 | 15 | efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo); 16 | void setup_5level_page_table(void); 17 | #endif /* CONFIG_EFI */ 18 | 19 | void save_id(void); 20 | void ap_start64(void); 21 | 22 | #endif /* _X86_ASM_SETUP_H_ */ 23 | -------------------------------------------------------------------------------- /lib/x86/asm/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMX86_SPINLOCK_H_ 2 | #define _ASMX86_SPINLOCK_H_ 3 | 4 | #include 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /lib/x86/asm/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASMX86_STACK_H_ 2 | #define _ASMX86_STACK_H_ 3 | 4 | #ifndef _STACK_H_ 5 | #error Do not directly include . Just use . 6 | #endif 7 | 8 | #define HAVE_ARCH_BACKTRACE_FRAME 9 | #define HAVE_ARCH_BACKTRACE 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /lib/x86/atomic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "atomic.h" 3 | 4 | #ifdef __i386__ 5 | 6 | u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new) 7 | { 8 | u32 low = new; 9 | u32 high = new >> 32; 10 | 11 | asm volatile("lock cmpxchg8b %1\n" 12 | : "+A" (old), 13 | "+m" (*(volatile long long *)&v->counter) 14 | : "b" (low), "c" (high) 15 | : "memory" 16 | ); 17 | 18 | return old; 19 | } 20 | 21 | #else 22 | 23 | u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new) 24 | { 25 | u64 ret; 26 | u64 _old = old; 27 | u64 _new = new; 28 | 29 | asm volatile("lock cmpxchgq %2,%1" 30 | : "=a" (ret), "+m" (*(volatile long *)&v->counter) 31 | : "r" (_new), "0" (_old) 32 | : "memory" 33 | ); 34 | return ret; 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /lib/x86/delay.c: -------------------------------------------------------------------------------- 1 | #include "delay.h" 2 | #include "processor.h" 3 | 4 | void delay(u64 count) 5 | { 6 | u64 start = rdtsc(); 7 | 8 | do { 9 | pause(); 10 | } while (rdtsc() - start < count); 11 | } 12 | -------------------------------------------------------------------------------- /lib/x86/delay.h: -------------------------------------------------------------------------------- 1 | #ifndef _X86_DELAY_H_ 2 | #define _X86_DELAY_H_ 3 | 4 | #include "libcflat.h" 5 | 6 | #define IPI_DELAY 1000000 7 | 8 | void delay(u64 count); 9 | 10 | static inline void io_delay(void) 11 | { 12 | delay(IPI_DELAY); 13 | } 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /lib/x86/fault_test.c: -------------------------------------------------------------------------------- 1 | #include "fault_test.h" 2 | 3 | static jmp_buf jmpbuf; 4 | 5 | static void restore_exec_to_jmpbuf(void) 6 | { 7 | longjmp(jmpbuf, 1); 8 | } 9 | 10 | static void fault_test_fault(struct ex_regs *regs) 11 | { 12 | regs->rip = (unsigned long)&restore_exec_to_jmpbuf; 13 | } 14 | 15 | static bool fault_test(struct fault_test_arg *arg) 16 | { 17 | volatile uint64_t val; 18 | bool raised_vector = false; 19 | test_fault_func func = (test_fault_func) arg->func; 20 | /* Init as success in case there isn't callback */ 21 | bool callback_success = true; 22 | 23 | if (arg->usermode) { 24 | val = run_in_user((usermode_func) func, arg->fault_vector, 25 | arg->arg[0], arg->arg[1], arg->arg[2], 26 | arg->arg[3], &raised_vector); 27 | } else { 28 | handle_exception(arg->fault_vector, fault_test_fault); 29 | if (setjmp(jmpbuf) == 0) 30 | val = func(arg->arg[0], arg->arg[1], arg->arg[2], 31 | arg->arg[3]); 32 | else 33 | raised_vector = true; 34 | } 35 | 36 | if (!raised_vector) { 37 | arg->retval = val; 38 | if (arg->callback != NULL) 39 | callback_success = arg->callback(arg); 40 | } 41 | 42 | return arg->should_fault ? 43 | raised_vector : (!raised_vector && callback_success); 44 | } 45 | 46 | void test_run(struct fault_test *test) 47 | { 48 | bool passed = fault_test(&(test->arg)); 49 | 50 | report(passed, "%s", test->name); 51 | } 52 | 53 | -------------------------------------------------------------------------------- /lib/x86/fault_test.h: -------------------------------------------------------------------------------- 1 | #ifndef _X86_FAULT_TEST_H_ 2 | #define _X86_FAULT_TEST_H_ 3 | 4 | #include "x86/msr.h" 5 | #include "x86/processor.h" 6 | #include "x86/apic-defs.h" 7 | #include "x86/apic.h" 8 | #include "x86/desc.h" 9 | #include "x86/isr.h" 10 | #include "alloc.h" 11 | #include "setjmp.h" 12 | #include "usermode.h" 13 | 14 | #include "libcflat.h" 15 | #include 16 | 17 | #define FAULT_TEST(nm, a) { .name = nm, .arg = a} 18 | 19 | struct fault_test_arg; 20 | 21 | typedef uint64_t (*test_fault_func)(uint64_t arg1, uint64_t arg2, 22 | uint64_t arg3, uint64_t arg4); 23 | typedef bool (*test_fault_callback)(struct fault_test_arg *arg); 24 | 25 | struct fault_test_arg { 26 | bool usermode; 27 | unsigned int fault_vector; 28 | bool should_fault; 29 | uint64_t arg[4]; 30 | uint64_t retval; 31 | test_fault_func func; 32 | test_fault_callback callback; 33 | }; 34 | 35 | struct fault_test { 36 | const char *name; 37 | struct fault_test_arg arg; 38 | }; 39 | 40 | void test_run(struct fault_test *test); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /lib/x86/fwcfg.c: -------------------------------------------------------------------------------- 1 | #include "fwcfg.h" 2 | #include "smp.h" 3 | #include "libcflat.h" 4 | 5 | static struct spinlock lock; 6 | 7 | static long fw_override[FW_CFG_NUM_ENTRIES]; 8 | static bool fw_override_done; 9 | 10 | bool no_test_device; 11 | 12 | static void read_cfg_override(void) 13 | { 14 | const char *str; 15 | int i; 16 | 17 | /* Initialize to negative value that would be considered as invalid */ 18 | for (i = 0; i < FW_CFG_NUM_ENTRIES; i++) 19 | fw_override[i] = -1; 20 | 21 | if ((str = getenv("NR_CPUS"))) 22 | fw_override[FW_CFG_NB_CPUS] = atol(str); 23 | 24 | /* MEMSIZE is in megabytes */ 25 | if ((str = getenv("MEMSIZE"))) 26 | fw_override[FW_CFG_RAM_SIZE] = atol(str) * 1024 * 1024; 27 | 28 | if ((str = getenv("TEST_DEVICE"))) 29 | no_test_device = !atol(str); 30 | 31 | if ((str = getenv("MEMLIMIT"))) 32 | fw_override[FW_CFG_MAX_RAM] = atol(str) * 1024 * 1024; 33 | 34 | 35 | fw_override_done = true; 36 | } 37 | 38 | static uint64_t fwcfg_get_u(uint16_t index, int bytes) 39 | { 40 | uint64_t r = 0; 41 | uint8_t b; 42 | int i; 43 | 44 | if (!fw_override_done) 45 | read_cfg_override(); 46 | 47 | if (index < FW_CFG_NUM_ENTRIES && fw_override[index] >= 0) 48 | return fw_override[index]; 49 | 50 | spin_lock(&lock); 51 | asm volatile ("out %0, %1" : : "a"(index), "d"((uint16_t)BIOS_CFG_IOPORT)); 52 | for (i = 0; i < bytes; ++i) { 53 | asm volatile ("in %1, %0" : "=a"(b) : "d"((uint16_t)(BIOS_CFG_IOPORT + 1))); 54 | r |= (uint64_t)b << (i * 8); 55 | } 56 | spin_unlock(&lock); 57 | return r; 58 | } 59 | 60 | uint8_t fwcfg_get_u8(unsigned index) 61 | { 62 | return fwcfg_get_u(index, 1); 63 | } 64 | 65 | uint16_t fwcfg_get_u16(unsigned index) 66 | { 67 | return fwcfg_get_u(index, 2); 68 | } 69 | 70 | uint32_t fwcfg_get_u32(unsigned index) 71 | { 72 | return fwcfg_get_u(index, 4); 73 | } 74 | 75 | uint64_t fwcfg_get_u64(unsigned index) 76 | { 77 | return fwcfg_get_u(index, 8); 78 | } 79 | 80 | unsigned fwcfg_get_nb_cpus(void) 81 | { 82 | return 2; 83 | } 84 | -------------------------------------------------------------------------------- /lib/x86/fwcfg.h: -------------------------------------------------------------------------------- 1 | #ifndef _X86_FWCFG_H_ 2 | #define _X86_FWCFG_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define FW_CFG_SIGNATURE 0x00 8 | #define FW_CFG_ID 0x01 9 | #define FW_CFG_UUID 0x02 10 | #define FW_CFG_RAM_SIZE 0x03 11 | #define FW_CFG_NOGRAPHIC 0x04 12 | #define FW_CFG_NB_CPUS 0x05 13 | #define FW_CFG_MACHINE_ID 0x06 14 | #define FW_CFG_KERNEL_ADDR 0x07 15 | #define FW_CFG_KERNEL_SIZE 0x08 16 | #define FW_CFG_KERNEL_CMDLINE 0x09 17 | #define FW_CFG_INITRD_ADDR 0x0a 18 | #define FW_CFG_INITRD_SIZE 0x0b 19 | #define FW_CFG_BOOT_DEVICE 0x0c 20 | #define FW_CFG_NUMA 0x0d 21 | #define FW_CFG_BOOT_MENU 0x0e 22 | #define FW_CFG_MAX_CPUS 0x0f 23 | 24 | /* Dummy entries used when running on bare metal */ 25 | #define FW_CFG_MAX_RAM 0x11 26 | 27 | #define FW_CFG_NUM_ENTRIES (FW_CFG_MAX_RAM + 1) 28 | 29 | #define FW_CFG_WRITE_CHANNEL 0x4000 30 | #define FW_CFG_ARCH_LOCAL 0x8000 31 | #define FW_CFG_ENTRY_MASK ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL) 32 | 33 | #define FW_CFG_INVALID 0xffff 34 | 35 | #define BIOS_CFG_IOPORT 0x510 36 | 37 | #define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0) 38 | #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1) 39 | #define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2) 40 | 41 | extern bool no_test_device; 42 | 43 | static inline bool test_device_enabled(void) 44 | { 45 | return !no_test_device; 46 | } 47 | 48 | uint8_t fwcfg_get_u8(unsigned index); 49 | uint16_t fwcfg_get_u16(unsigned index); 50 | uint32_t fwcfg_get_u32(unsigned index); 51 | uint64_t fwcfg_get_u64(unsigned index); 52 | 53 | unsigned fwcfg_get_nb_cpus(void); 54 | 55 | #endif 56 | 57 | -------------------------------------------------------------------------------- /lib/x86/isr.h: -------------------------------------------------------------------------------- 1 | #ifndef _X86_ISR_H_ 2 | #define _X86_ISR_H_ 3 | 4 | typedef struct { 5 | ulong regs[sizeof(ulong)*2]; 6 | ulong func; 7 | ulong rip; 8 | ulong cs; 9 | ulong rflags; 10 | } isr_regs_t; 11 | 12 | void handle_irq(unsigned vec, void (*func)(isr_regs_t *regs)); 13 | void handle_external_interrupt(int vector); 14 | #endif 15 | -------------------------------------------------------------------------------- /lib/x86/setjmp32.S: -------------------------------------------------------------------------------- 1 | .globl setjmp 2 | setjmp: 3 | mov (%esp), %ecx // get return EIP 4 | mov 4(%esp), %eax // get jmp_buf 5 | mov %ecx, (%eax) 6 | mov %esp, 4(%eax) 7 | mov %ebp, 8(%eax) 8 | mov %ebx, 12(%eax) 9 | mov %esi, 16(%eax) 10 | mov %edi, 20(%eax) 11 | xor %eax, %eax 12 | ret 13 | 14 | .globl longjmp 15 | longjmp: 16 | mov 8(%esp), %eax // get return value 17 | mov 4(%esp), %ecx // get jmp_buf 18 | mov 20(%ecx), %edi 19 | mov 16(%ecx), %esi 20 | mov 12(%ecx), %ebx 21 | mov 8(%ecx), %ebp 22 | mov 4(%ecx), %esp 23 | mov (%ecx), %ecx // get saved EIP 24 | mov %ecx, (%esp) // and store it on the stack 25 | ret 26 | -------------------------------------------------------------------------------- /lib/x86/setjmp64.S: -------------------------------------------------------------------------------- 1 | .globl setjmp 2 | setjmp: 3 | mov (%rsp), %rsi 4 | mov %rsi, (%rdi) 5 | mov %rsp, 0x8(%rdi) 6 | mov %rbp, 0x10(%rdi) 7 | mov %rbx, 0x18(%rdi) 8 | mov %r12, 0x20(%rdi) 9 | mov %r13, 0x28(%rdi) 10 | mov %r14, 0x30(%rdi) 11 | mov %r15, 0x38(%rdi) 12 | xor %eax, %eax 13 | ret 14 | 15 | .globl longjmp 16 | longjmp: 17 | mov %esi, %eax 18 | mov 0x38(%rdi), %r15 19 | mov 0x30(%rdi), %r14 20 | mov 0x28(%rdi), %r13 21 | mov 0x20(%rdi), %r12 22 | mov 0x18(%rdi), %rbx 23 | mov 0x10(%rdi), %rbp 24 | mov 0x8(%rdi), %rsp 25 | mov (%rdi), %rsi 26 | mov %rsi, (%rsp) 27 | ret 28 | -------------------------------------------------------------------------------- /lib/x86/stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int backtrace_frame(const void *frame, const void **return_addrs, int max_depth) 5 | { 6 | static int walking; 7 | int depth = 0; 8 | const unsigned long *bp = (unsigned long *) frame; 9 | 10 | if (walking) { 11 | printf("RECURSIVE STACK WALK!!!\n"); 12 | return 0; 13 | } 14 | walking = 1; 15 | 16 | for (depth = 0; bp && depth < max_depth; depth++) { 17 | return_addrs[depth] = (void *) bp[1]; 18 | if (return_addrs[depth] == 0) 19 | break; 20 | bp = (unsigned long *) bp[0]; 21 | } 22 | 23 | walking = 0; 24 | return depth; 25 | } 26 | 27 | int backtrace(const void **return_addrs, int max_depth) 28 | { 29 | return backtrace_frame(__builtin_frame_address(0), return_addrs, 30 | max_depth); 31 | } 32 | -------------------------------------------------------------------------------- /lib/x86/usermode.h: -------------------------------------------------------------------------------- 1 | #ifndef _X86_USERMODE_H_ 2 | #define _X86_USERMODE_H_ 3 | 4 | #include "x86/msr.h" 5 | #include "x86/processor.h" 6 | #include "x86/apic-defs.h" 7 | #include "x86/apic.h" 8 | #include "x86/desc.h" 9 | #include "x86/isr.h" 10 | #include "alloc.h" 11 | #include "setjmp.h" 12 | 13 | #include "libcflat.h" 14 | #include 15 | 16 | typedef uint64_t (*usermode_func)(void); 17 | 18 | /* 19 | * Run function in user mode 20 | * Supports running functions with up to 4 arguments. 21 | * fault_vector: exception vector that might get thrown during the function. 22 | * raised_vector: outputs true if exception occurred. 23 | * 24 | * returns: return value returned by function, or 0 if an exception occurred. 25 | */ 26 | uint64_t run_in_user(usermode_func func, unsigned int fault_vector, 27 | uint64_t arg1, uint64_t arg2, uint64_t arg3, 28 | uint64_t arg4, bool *raised_vector); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /lib/x86/vm.h: -------------------------------------------------------------------------------- 1 | #ifndef _X86_VM_H_ 2 | #define _X86_VM_H_ 3 | 4 | #include "processor.h" 5 | #include "asm/page.h" 6 | #include "asm/io.h" 7 | #include "asm/bitops.h" 8 | 9 | void setup_5level_page_table(void); 10 | 11 | struct pte_search { 12 | int level; 13 | pteval_t *pte; 14 | }; 15 | 16 | static inline bool found_huge_pte(struct pte_search search) 17 | { 18 | return (search.level == 2 || search.level == 3) && 19 | (*search.pte & PT_PRESENT_MASK) && 20 | (*search.pte & PT_PAGE_SIZE_MASK); 21 | } 22 | 23 | static inline bool found_leaf_pte(struct pte_search search) 24 | { 25 | return search.level == 1 || found_huge_pte(search); 26 | } 27 | 28 | struct pte_search find_pte_level(pgd_t *cr3, void *virt, 29 | int lowest_level); 30 | pteval_t *get_pte(pgd_t *cr3, void *virt); 31 | pteval_t *get_pte_level(pgd_t *cr3, void *virt, int pte_level); 32 | pteval_t *install_pte(pgd_t *cr3, 33 | int pte_level, 34 | void *virt, 35 | pteval_t pte, 36 | pteval_t *pt_page); 37 | 38 | pteval_t *install_large_page(pgd_t *cr3, phys_addr_t phys, void *virt); 39 | void install_pages(pgd_t *cr3, phys_addr_t phys, size_t len, void *virt); 40 | bool any_present_pages(pgd_t *cr3, void *virt, size_t len); 41 | void set_pte_opt_mask(void); 42 | void reset_pte_opt_mask(void); 43 | 44 | enum x86_mmu_flags { 45 | X86_MMU_MAP_USER = BIT(0), 46 | X86_MMU_MAP_HUGE = BIT(1), 47 | }; 48 | void __setup_mmu_range(pgd_t *cr3, phys_addr_t start, size_t len, 49 | enum x86_mmu_flags mmu_flags); 50 | 51 | static inline void *current_page_table(void) 52 | { 53 | return phys_to_virt(read_cr3()); 54 | } 55 | 56 | void split_large_page(unsigned long *ptep, int level); 57 | void force_4k_page(void *addr); 58 | 59 | struct vm_vcpu_info { 60 | u64 cr3; 61 | u64 cr4; 62 | u64 cr0; 63 | }; 64 | 65 | typedef void (*pte_callback_t)(struct pte_search search, void *va); 66 | void walk_pte(void *virt, size_t len, pte_callback_t callback); 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /powerpc/.gitignore: -------------------------------------------------------------------------------- 1 | boot_rom.bin 2 | -------------------------------------------------------------------------------- /powerpc/Makefile: -------------------------------------------------------------------------------- 1 | include $(SRCDIR)/$(TEST_DIR)/Makefile.$(ARCH) 2 | -------------------------------------------------------------------------------- /powerpc/Makefile.ppc64: -------------------------------------------------------------------------------- 1 | # 2 | # ppc64 makefile 3 | # 4 | # Authors: Andrew Jones 5 | # 6 | bits = 64 7 | 8 | ifeq ($(ENDIAN),little) 9 | arch_CFLAGS = -mlittle-endian 10 | arch_LDFLAGS = -EL 11 | else 12 | arch_CFLAGS = -mbig-endian 13 | arch_LDFLAGS = -EB 14 | endif 15 | 16 | cstart.o = $(TEST_DIR)/cstart64.o 17 | reloc.o = $(TEST_DIR)/reloc64.o 18 | 19 | OBJDIRS += lib/ppc64 20 | 21 | # ppc64 specific tests 22 | tests = 23 | 24 | include $(SRCDIR)/$(TEST_DIR)/Makefile.common 25 | 26 | arch_clean: powerpc_clean 27 | $(RM) lib/ppc64/.*.d 28 | -------------------------------------------------------------------------------- /powerpc/boot_rom.S: -------------------------------------------------------------------------------- 1 | #include "spapr.h" 2 | 3 | .text 4 | .globl start 5 | start: 6 | b SPAPR_KERNEL_LOAD_ADDR - 0x100 7 | -------------------------------------------------------------------------------- /powerpc/flat.lds: -------------------------------------------------------------------------------- 1 | 2 | PHDRS 3 | { 4 | text PT_LOAD FLAGS(5); 5 | data PT_LOAD FLAGS(6); 6 | } 7 | 8 | SECTIONS 9 | { 10 | .text : { 11 | *(.init) 12 | *(.text) 13 | *(.text.*) 14 | } :text 15 | . = ALIGN(64K); 16 | etext = .; 17 | .opd : { *(.opd) } 18 | . = ALIGN(16); 19 | .dynamic : { 20 | dynamic_start = .; 21 | *(.dynamic) 22 | } 23 | .dynsym : { 24 | dynsym_start = .; 25 | *(.dynsym) 26 | } 27 | .rela.dyn : { *(.rela*) } 28 | . = ALIGN(16); 29 | .data : { 30 | *(.data) 31 | *(.data.rel*) 32 | } :data 33 | . = ALIGN(16); 34 | .rodata : { 35 | *(.rodata) 36 | *(.rodata.*) 37 | } :data 38 | . = ALIGN(16); 39 | .bss : { *(.bss) } 40 | . = ALIGN(256); 41 | /* 42 | * tocptr is tocbase + 32K, allowing toc offsets to be +-32K 43 | */ 44 | tocptr = . + 32K; 45 | .got : { *(.toc) *(.got) } 46 | . = ALIGN(64K); 47 | edata = .; 48 | . += 64K; 49 | . = ALIGN(64K); 50 | /* 51 | * stackptr set with initial stack frame (64 bytes) preallocated 52 | */ 53 | stackptr = . - 64; 54 | stacktop = .; 55 | } 56 | 57 | ENTRY(start) 58 | -------------------------------------------------------------------------------- /powerpc/reloc64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * relocate R_PPC_RELATIVE RELA entries. Normally this is done in 3 | * assembly code to avoid the risk of using absolute addresses before 4 | * they're relocated. We use C, but cautiously (no global references). 5 | * 6 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 7 | * 8 | * This work is licensed under the terms of the GNU LGPL, version 2. 9 | */ 10 | #define DT_NULL 0 11 | #define DT_RELA 7 12 | #define DT_RELACOUNT 0x6ffffff9 13 | #define R_PPC_RELATIVE 22 14 | 15 | struct elf64_dyn { 16 | signed long long tag; 17 | unsigned long long val; 18 | }; 19 | 20 | #define RELA_GET_TYPE(rela_ptr) ((rela_ptr)->info & 0xffffffff) 21 | struct elf64_rela { 22 | unsigned long long offset; 23 | unsigned long long info; 24 | signed long long addend; 25 | }; 26 | 27 | void relocate(unsigned long load_addr, struct elf64_dyn *dyn_table); 28 | 29 | void relocate(unsigned long load_addr, struct elf64_dyn *dyn_table) 30 | { 31 | unsigned long long rela_addr = 0, rela_count = 0, *addr; 32 | struct elf64_dyn *d = dyn_table; 33 | struct elf64_rela *r; 34 | 35 | while (d && d->tag != DT_NULL) { 36 | if (d->tag == DT_RELA) 37 | rela_addr = d->val; 38 | else if (d->tag == DT_RELACOUNT) 39 | rela_count = d->val; 40 | if (rela_addr && rela_count) 41 | break; 42 | ++d; 43 | } 44 | 45 | if (!rela_addr || !rela_count) 46 | return; 47 | 48 | r = (void *)(rela_addr + load_addr); 49 | 50 | while (rela_count--) { 51 | if (RELA_GET_TYPE(r) == R_PPC_RELATIVE) { 52 | addr = (void *)(r->offset + load_addr); 53 | *addr = r->addend + load_addr; 54 | } 55 | ++r; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /powerpc/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ -z "$KUT_STANDALONE" ]; then 4 | if [ ! -f config.mak ]; then 5 | echo "run ./configure && make first. See ./configure -h" 6 | exit 2 7 | fi 8 | source config.mak 9 | source scripts/arch-run.bash 10 | fi 11 | 12 | ACCEL=$(get_qemu_accelerator) || 13 | exit $? 14 | 15 | qemu=$(search_qemu_binary) || 16 | exit $? 17 | 18 | if ! $qemu -machine '?' 2>&1 | grep 'pseries' > /dev/null; then 19 | echo "$qemu doesn't support pSeries ('-machine pseries'). Exiting." 20 | exit 2 21 | fi 22 | 23 | M='-machine pseries' 24 | M+=",accel=$ACCEL" 25 | command="$qemu -nodefaults $M -bios $FIRMWARE" 26 | command+=" -display none -serial stdio -kernel" 27 | command="$(migration_cmd) $(timeout_cmd) $command" 28 | 29 | # powerpc tests currently exit with rtas-poweroff, which exits with 0. 30 | # run_qemu treats that as a failure exit and returns 1, so we need 31 | # to fixup the fixup below by parsing the true exit code from the output. 32 | # The second fixup is also a FIXME, because once we add chr-testdev 33 | # support for powerpc, we won't need the second fixup. 34 | run_qemu_status $command "$@" 35 | -------------------------------------------------------------------------------- /powerpc/selftest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Test the framework itself. These tests confirm that setup works. 3 | * 4 | * Copyright (C) 2016, Red Hat Inc, Andrew Jones 5 | * 6 | * This work is licensed under the terms of the GNU LGPL, version 2. 7 | */ 8 | #include 9 | #include 10 | #include 11 | 12 | static void check_setup(int argc, char **argv) 13 | { 14 | int nr_tests = 0, len, i; 15 | long val; 16 | 17 | for (i = 0; i < argc; ++i) { 18 | 19 | len = parse_keyval(argv[i], &val); 20 | if (len == -1) 21 | continue; 22 | 23 | argv[i][len] = '\0'; 24 | report_prefix_push(argv[i]); 25 | 26 | if (strcmp(argv[i], "mem") == 0) { 27 | 28 | phys_addr_t memsize = PHYSICAL_END - PHYSICAL_START; 29 | phys_addr_t expected = ((phys_addr_t)val)*1024*1024; 30 | 31 | report(memsize == expected, "size = %" PRIu64 " MB", 32 | memsize/1024/1024); 33 | ++nr_tests; 34 | 35 | } else if (strcmp(argv[i], "smp") == 0) { 36 | 37 | report(nr_cpus == (int)val, "nr_cpus = %d", nr_cpus); 38 | ++nr_tests; 39 | } 40 | 41 | report_prefix_pop(); 42 | } 43 | 44 | if (nr_tests < 2) 45 | report_abort("missing input"); 46 | } 47 | 48 | int main(int argc, char **argv) 49 | { 50 | report_prefix_push("selftest"); 51 | 52 | if (argc < 2) 53 | report_abort("no test specified"); 54 | 55 | report_prefix_push(argv[1]); 56 | 57 | if (strcmp(argv[1], "setup") == 0) { 58 | 59 | check_setup(argc-2, &argv[2]); 60 | 61 | } 62 | 63 | return report_summary(); 64 | } 65 | -------------------------------------------------------------------------------- /powerpc/spapr.h: -------------------------------------------------------------------------------- 1 | #ifndef POWERPC_SPAPR_H 2 | #define POWERPC_SPAPR_H 3 | 4 | #define SPAPR_KERNEL_LOAD_ADDR 0x400000 5 | 6 | #endif /* POWERPC_SPAPR_H */ 7 | -------------------------------------------------------------------------------- /s390x/cmm.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * CMM tests (ESSA) 4 | * 5 | * Copyright (c) 2018 IBM Corp 6 | * 7 | * Authors: 8 | * Janosch Frank 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | static uint8_t pagebuf[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 18 | 19 | static void test_params(void) 20 | { 21 | report_prefix_push("invalid ORC 8"); 22 | expect_pgm_int(); 23 | essa(8, (unsigned long)pagebuf); 24 | check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 25 | report_prefix_pop(); 26 | } 27 | 28 | static void test_priv(void) 29 | { 30 | report_prefix_push("privileged"); 31 | expect_pgm_int(); 32 | enter_pstate(); 33 | essa(ESSA_GET_STATE, (unsigned long)pagebuf); 34 | check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 35 | report_prefix_pop(); 36 | } 37 | 38 | int main(void) 39 | { 40 | bool has_essa = check_essa_available(); 41 | 42 | report_prefix_push("cmm"); 43 | if (!has_essa) { 44 | report_skip("ESSA is not available"); 45 | goto done; 46 | } 47 | 48 | test_priv(); 49 | test_params(); 50 | done: 51 | report_prefix_pop(); 52 | return report_summary(); 53 | } 54 | -------------------------------------------------------------------------------- /s390x/flat.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | .lowcore : { 4 | /* 5 | * Initial short psw for disk boot, with 31 bit addressing for 6 | * non z/Arch environment compatibility and the instruction 7 | * address 0x10000 (cstart64.S .init). 8 | */ 9 | . = 0; 10 | lowcore = .; 11 | LONG(0x00080000) 12 | LONG(0x80010000) 13 | /* Restart new PSW for booting via PSW restart. */ 14 | . = 0x1a0; 15 | QUAD(0x0000000180000000) 16 | QUAD(0x0000000000010000) 17 | } 18 | . = 0x10000; 19 | .text : { 20 | *(.init) 21 | . = 0x480; 22 | ipl_args = .; 23 | . = 0x1000; 24 | *(.text) 25 | *(.text.*) 26 | } 27 | . = ALIGN(64K); 28 | etext = .; 29 | .opd : { *(.opd) } 30 | . = ALIGN(16); 31 | .dynamic : { 32 | dynamic_start = .; 33 | *(.dynamic) 34 | } 35 | .dynsym : { 36 | dynsym_start = .; 37 | *(.dynsym) 38 | } 39 | .rela.dyn : { *(.rela*) } 40 | . = ALIGN(16); 41 | .data : { 42 | *(.data) 43 | *(.data.rel*) 44 | } 45 | . = ALIGN(16); 46 | .rodata : { *(.rodata) *(.rodata.*) } 47 | . = ALIGN(16); 48 | __bss_start = .; 49 | .bss : { *(.bss) } 50 | __bss_end = .; 51 | . = ALIGN(64K); 52 | edata = .; 53 | . += 64K; 54 | . = ALIGN(64K); 55 | /* 56 | * stackptr set with initial stack frame preallocated 57 | */ 58 | stackptr = . - 160; 59 | stacktop = .; 60 | } 61 | -------------------------------------------------------------------------------- /s390x/iep.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Instruction Execution Prevention (IEP) DAT test. 4 | * 5 | * Copyright (c) 2018 IBM Corp 6 | * 7 | * Authors: 8 | * Janosch Frank 9 | */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | static void test_iep(void) 18 | { 19 | uint16_t *code; 20 | uint8_t *iepbuf = NULL; 21 | void (*fn)(void); 22 | 23 | /* Enable IEP */ 24 | ctl_set_bit(0, CTL0_IEP); 25 | 26 | /* Get and protect a page with the IEP bit */ 27 | iepbuf = alloc_page(); 28 | protect_page(iepbuf, PAGE_ENTRY_IEP); 29 | 30 | /* Code branches into r14 which contains the return address. */ 31 | code = (uint16_t *)iepbuf; 32 | *code = 0x07fe; 33 | fn = (void *)code; 34 | 35 | report_prefix_push("iep protection"); 36 | expect_pgm_int(); 37 | /* Jump into protected page */ 38 | fn(); 39 | check_pgm_int_code(PGM_INT_CODE_PROTECTION); 40 | report_prefix_pop(); 41 | unprotect_page(iepbuf, PAGE_ENTRY_IEP); 42 | ctl_clear_bit(0, CTL0_IEP); 43 | free_page(iepbuf); 44 | } 45 | 46 | int main(void) 47 | { 48 | bool has_iep = test_facility(130); 49 | 50 | report_prefix_push("iep"); 51 | if (!has_iep) { 52 | report_skip("DAT IEP is not available"); 53 | goto done; 54 | } 55 | 56 | /* Setup DAT 1:1 mapping and memory management */ 57 | setup_vm(); 58 | test_iep(); 59 | 60 | done: 61 | report_prefix_pop(); 62 | return report_summary(); 63 | } 64 | -------------------------------------------------------------------------------- /s390x/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ -z "$KUT_STANDALONE" ]; then 4 | if [ ! -f config.mak ]; then 5 | echo "run ./configure && make first. See ./configure -h" 6 | exit 2 7 | fi 8 | source config.mak 9 | source scripts/arch-run.bash 10 | fi 11 | 12 | ACCEL=$(get_qemu_accelerator) || 13 | exit $? 14 | 15 | qemu=$(search_qemu_binary) || 16 | exit $? 17 | 18 | if [ "${1: -7}" = ".pv.bin" ] || [ "${TESTNAME: -3}" = "_PV" ] && [ "$ACCEL" = "tcg" ]; then 19 | echo "Protected Virtualization isn't supported under TCG" 20 | exit 2 21 | fi 22 | 23 | if [ "${1: -7}" = ".pv.bin" ] || [ "${TESTNAME: -3}" = "_PV" ] && [ "$MIGRATION" = "yes" ]; then 24 | echo "Migration isn't supported under Protected Virtualization" 25 | exit 2 26 | fi 27 | 28 | M='-machine s390-ccw-virtio' 29 | M+=",accel=$ACCEL" 30 | command="$qemu -nodefaults -nographic $M" 31 | command+=" -chardev stdio,id=con0 -device sclpconsole,chardev=con0" 32 | command+=" -kernel" 33 | command="$(migration_cmd) $(timeout_cmd) $command" 34 | 35 | # We return the exit code via stdout, not via the QEMU return code 36 | run_qemu_status $command "$@" 37 | -------------------------------------------------------------------------------- /s390x/selftest.parmfile: -------------------------------------------------------------------------------- 1 | test 123 -------------------------------------------------------------------------------- /s390x/sie.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Tests SIE diagnose intercepts. 4 | * Mainly used as a template for SIE tests. 5 | * 6 | * Copyright 2021 IBM Corp. 7 | * 8 | * Authors: 9 | * Janosch Frank 10 | */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | static u8 *guest; 24 | static u8 *guest_instr; 25 | static struct vm vm; 26 | 27 | static void test_diag(u32 instr) 28 | { 29 | vm.sblk->gpsw.addr = PAGE_SIZE * 2; 30 | vm.sblk->gpsw.mask = PSW_MASK_64; 31 | 32 | memset(guest_instr, 0, PAGE_SIZE); 33 | memcpy(guest_instr, &instr, 4); 34 | sie(&vm); 35 | report(vm.sblk->icptcode == ICPT_INST && 36 | vm.sblk->ipa == instr >> 16 && vm.sblk->ipb == instr << 16, 37 | "Intercept data"); 38 | } 39 | 40 | static struct { 41 | const char *name; 42 | u32 instr; 43 | } tests[] = { 44 | { "10", 0x83020010 }, 45 | { "44", 0x83020044 }, 46 | { "9c", 0x8302009c }, 47 | { NULL, 0 } 48 | }; 49 | 50 | static void test_diags(void) 51 | { 52 | int i; 53 | 54 | for (i = 0; tests[i].name; i++) { 55 | report_prefix_push(tests[i].name); 56 | test_diag(tests[i].instr); 57 | report_prefix_pop(); 58 | } 59 | } 60 | 61 | static void setup_guest(void) 62 | { 63 | setup_vm(); 64 | 65 | /* Allocate 1MB as guest memory */ 66 | guest = alloc_pages(8); 67 | /* The first two pages are the lowcore */ 68 | guest_instr = guest + PAGE_SIZE * 2; 69 | 70 | sie_guest_create(&vm, (uint64_t)guest, HPAGE_SIZE); 71 | } 72 | 73 | int main(void) 74 | { 75 | report_prefix_push("sie"); 76 | if (!sclp_facilities.has_sief2) { 77 | report_skip("SIEF2 facility unavailable"); 78 | goto done; 79 | } 80 | 81 | setup_guest(); 82 | test_diags(); 83 | sie_guest_destroy(&vm); 84 | 85 | done: 86 | report_prefix_pop(); 87 | return report_summary(); 88 | } 89 | -------------------------------------------------------------------------------- /s390x/sieve.c: -------------------------------------------------------------------------------- 1 | ../x86/sieve.c -------------------------------------------------------------------------------- /s390x/snippets/asm/snippet-pv-diag-288.S: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Diagnose 0x288 snippet used for PV interception testing. 4 | * 5 | * Copyright (c) 2021 IBM Corp 6 | * 7 | * Authors: 8 | * Janosch Frank 9 | */ 10 | #include 11 | .section .text 12 | 13 | /* Clean and pre-load registers that are used for diag 288 */ 14 | xgr %r0, %r0 15 | xgr %r1, %r1 16 | xgr %r3, %r3 17 | lghi %r0, 1 18 | lghi %r1, 2 19 | lghi %r2, 3 20 | 21 | /* Let's jump to the pgm exit label on a PGM */ 22 | larl %r4, exit_pgm 23 | stg %r4, GEN_LC_PGM_NEW_PSW + 8 24 | 25 | /* Execute the diag288 */ 26 | diag %r0, %r2, 0x288 27 | 28 | /* Force exit if we don't get a PGM */ 29 | diag 0, 0, 0x44 30 | 31 | /* Communicate the PGM code via diag9c(easiest) */ 32 | exit_pgm: 33 | lh %r1, GEN_LC_PGM_INT_CODE 34 | diag %r1, 0, 0x9c 35 | -------------------------------------------------------------------------------- /s390x/snippets/asm/snippet-pv-diag-500.S: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Diagnose 0x500 snippet used for PV interception tests 4 | * 5 | * Copyright (c) 2021 IBM Corp 6 | * 7 | * Authors: 8 | * Janosch Frank 9 | */ 10 | #include 11 | .section .text 12 | 13 | /* Clean and pre-load registers that are used for diag 500 */ 14 | xgr %r1, %r1 15 | xgr %r2, %r2 16 | xgr %r3, %r3 17 | xgr %r4, %r4 18 | lghi %r1, 1 19 | lghi %r2, 2 20 | lghi %r3, 3 21 | lghi %r4, 4 22 | 23 | /* Let's jump to the next label on a PGM */ 24 | xgr %r5, %r5 25 | stg %r5, GEN_LC_PGM_NEW_PSW 26 | larl %r5, next 27 | stg %r5, GEN_LC_PGM_NEW_PSW + 8 28 | 29 | /* Execute the diag500 */ 30 | diag 0, 0, 0x500 31 | 32 | /* Should never be executed because of the PGM */ 33 | diag 0, 0, 0x44 34 | 35 | /* Execute again to test spec PGM injection*/ 36 | next: 37 | lh %r1, GEN_LC_PGM_INT_CODE 38 | diag %r1, 0, 0x9c 39 | larl %r5, done 40 | stg %r5, GEN_LC_PGM_NEW_PSW + 8 41 | diag 0, 0, 0x500 42 | 43 | /* Should never be executed because of the PGM */ 44 | diag 0, 0, 0x44 45 | 46 | done: 47 | lh %r1, GEN_LC_PGM_INT_CODE 48 | diag %r1, 0, 0x9c 49 | -------------------------------------------------------------------------------- /s390x/snippets/asm/snippet-pv-diag-yield.S: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Diagnose 0x44 and 0x9c snippet used for PV interception tests 4 | * 5 | * Copyright (c) 2021 IBM Corp 6 | * 7 | * Authors: 8 | * Janosch Frank 9 | */ 10 | .section .text 11 | 12 | xgr %r0, %r0 13 | xgr %r1, %r1 14 | diag 0,0,0x44 15 | lghi %r1, 42 16 | diag 1,0,0x9c 17 | -------------------------------------------------------------------------------- /s390x/snippets/c/cstart.S: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Start assembly for snippets 4 | * 5 | * Copyright (c) 2021 IBM Corp. 6 | * 7 | * Authors: 8 | * Janosch Frank 9 | */ 10 | #include 11 | 12 | .section .init 13 | .globl start 14 | start: 15 | larl %r1, initial_cr0 16 | lctlg %c0, %c0, 0(%r1) 17 | /* XOR all registers with themselves to clear them fully. */ 18 | .irp i, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 19 | xgr \i,\i 20 | .endr 21 | /* 0x3000 is the stack page for now */ 22 | lghi %r15, stackptr 23 | sam64 24 | brasl %r14, main 25 | /* 26 | * If main() returns, we stop the CPU with the code below. We also 27 | * route some functions that are required by the libc (but not usable 28 | * from snippets) to the CPU stop code below, so that snippets can 29 | * still be linked against the libc code (to use non-related functions 30 | * like memset() etc.) 31 | */ 32 | .global puts 33 | .global exit 34 | puts: 35 | exit: 36 | /* For now let's only use cpu 0 in snippets so this will always work. */ 37 | xgr %r0, %r0 38 | sigp %r2, %r0, SIGP_STOP 39 | 40 | initial_cr0: 41 | /* enable AFP-register control, so FP regs (+BFP instr) can be used */ 42 | .quad 0x0000000000040000 43 | -------------------------------------------------------------------------------- /s390x/snippets/c/flat.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | .lowcore : { 4 | /* 5 | * Initial short psw for disk boot, with 31 bit addressing for 6 | * non z/Arch environment compatibility and the instruction 7 | * address 0x4000 (cstart.S .init). 8 | */ 9 | . = 0; 10 | lowcore = .; 11 | LONG(0x00080000) 12 | LONG(0x80004000) 13 | /* Restart new PSW for booting via PSW restart. */ 14 | . = 0x1a0; 15 | QUAD(0x0000000180000000) 16 | QUAD(0x0000000000004000) 17 | } 18 | . = 0x4000; 19 | stackptr = . - 160; 20 | stacktop = .; 21 | .text : { 22 | *(.init) 23 | *(.text) 24 | *(.text.*) 25 | } 26 | . = ALIGN(64K); 27 | etext = .; 28 | .opd : { *(.opd) } 29 | . = ALIGN(16); 30 | .dynamic : { 31 | dynamic_start = .; 32 | *(.dynamic) 33 | } 34 | .dynsym : { 35 | dynsym_start = .; 36 | *(.dynsym) 37 | } 38 | .rela.dyn : { *(.rela*) } 39 | . = ALIGN(16); 40 | .data : { 41 | *(.data) 42 | *(.data.rel*) 43 | } 44 | . = ALIGN(16); 45 | .rodata : { *(.rodata) *(.rodata.*) } 46 | . = ALIGN(16); 47 | __bss_start = .; 48 | .bss : { *(.bss) } 49 | __bss_end = .; 50 | . = ALIGN(64K); 51 | edata = .; 52 | . += 64K; 53 | . = ALIGN(64K); 54 | } 55 | -------------------------------------------------------------------------------- /s390x/snippets/c/mvpg-snippet.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | /* 3 | * Snippet used by the mvpg-sie.c test to check SIE PEI intercepts. 4 | * 5 | * Copyright (c) 2021 IBM Corp 6 | * 7 | * Authors: 8 | * Janosch Frank 9 | */ 10 | 11 | static inline void force_exit(void) 12 | { 13 | asm volatile(" diag 0,0,0x44\n"); 14 | } 15 | 16 | static inline int mvpg(unsigned long r0, void *dest, void *src) 17 | { 18 | register unsigned long reg0 asm ("0") = r0; 19 | int cc; 20 | 21 | asm volatile(" mvpg %1,%2\n" 22 | " ipm %0\n" 23 | " srl %0,28" 24 | : "=d" (cc) : "a" (dest), "a" (src), "d" (reg0) 25 | : "memory", "cc"); 26 | return cc; 27 | } 28 | 29 | static void test_mvpg_real(void) 30 | { 31 | mvpg(0, (void *)0x5000, (void *)0x6000); 32 | force_exit(); 33 | } 34 | 35 | __attribute__((section(".text"))) int main(void) 36 | { 37 | test_mvpg_real(); 38 | test_mvpg_real(); 39 | test_mvpg_real(); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /s390x/snippets/c/spec_ex.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright IBM Corp. 2021 4 | * 5 | * Snippet used by specification exception interception test. 6 | */ 7 | #include 8 | #include 9 | #include 10 | 11 | __attribute__((section(".text"))) int main(void) 12 | { 13 | uint64_t bad_psw = 0; 14 | 15 | /* PSW bit 12 has no name or meaning and must be 0 */ 16 | lowcore.pgm_new_psw.mask = BIT(63 - 12); 17 | lowcore.pgm_new_psw.addr = 0xdeadbeee; 18 | asm volatile ("lpsw %0" :: "Q"(bad_psw)); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /scripts/asm-offsets.mak: -------------------------------------------------------------------------------- 1 | # 2 | # asm-offsets adapted from the kernel, see 3 | # Kbuild 4 | # scripts/Kbuild.include 5 | # scripts/Makefile.build 6 | # 7 | # Authors: Andrew Jones 8 | # 9 | 10 | define sed-y 11 | 's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:; \ 12 | /^->/{s:->#\(.*\):/* \1 */:; \ 13 | s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \ 14 | s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ 15 | s:->::; p;}' 16 | endef 17 | 18 | define make_asm_offsets 19 | (set -e; \ 20 | echo "#ifndef __ASM_OFFSETS_H__"; \ 21 | echo "#define __ASM_OFFSETS_H__"; \ 22 | echo "/*"; \ 23 | echo " * Generated file. DO NOT MODIFY."; \ 24 | echo " *"; \ 25 | echo " */"; \ 26 | echo ""; \ 27 | sed -ne $(sed-y) $<; \ 28 | echo ""; \ 29 | echo "#endif" ) > $@ 30 | endef 31 | 32 | $(asm-offsets:.h=.s): $(asm-offsets:.h=.c) 33 | $(CC) $(CFLAGS) -fverbose-asm -S -o $@ $< 34 | 35 | $(asm-offsets): $(asm-offsets:.h=.s) 36 | $(call make_asm_offsets) 37 | cp -f $(asm-offsets) lib/generated/ 38 | 39 | OBJDIRS += lib/generated 40 | 41 | asm_offsets_clean: 42 | $(RM) $(asm-offsets) $(asm-offsets:.h=.s) \ 43 | $(addprefix lib/generated/,$(notdir $(asm-offsets))) 44 | 45 | -------------------------------------------------------------------------------- /scripts/common.bash: -------------------------------------------------------------------------------- 1 | source config.mak 2 | 3 | function for_each_unittest() 4 | { 5 | local unittests="$1" 6 | local cmd="$2" 7 | local testname 8 | local smp 9 | local kernel 10 | local opts 11 | local groups 12 | local arch 13 | local check 14 | local accel 15 | local timeout 16 | local rematch 17 | 18 | exec {fd}<"$unittests" 19 | 20 | while read -r -u $fd line; do 21 | if [[ "$line" =~ ^\[(.*)\]$ ]]; then 22 | rematch=${BASH_REMATCH[1]} 23 | if [ -n "${testname}" ]; then 24 | $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout" 25 | fi 26 | testname=$rematch 27 | smp=1 28 | kernel="" 29 | opts="" 30 | groups="" 31 | arch="" 32 | check="" 33 | accel="" 34 | timeout="" 35 | elif [[ $line =~ ^file\ *=\ *(.*)$ ]]; then 36 | kernel=$TEST_DIR/${BASH_REMATCH[1]} 37 | elif [[ $line =~ ^smp\ *=\ *(.*)$ ]]; then 38 | smp=${BASH_REMATCH[1]} 39 | elif [[ $line =~ ^extra_params\ *=\ *(.*)$ ]]; then 40 | opts=${BASH_REMATCH[1]} 41 | elif [[ $line =~ ^groups\ *=\ *(.*)$ ]]; then 42 | groups=${BASH_REMATCH[1]} 43 | elif [[ $line =~ ^arch\ *=\ *(.*)$ ]]; then 44 | arch=${BASH_REMATCH[1]} 45 | elif [[ $line =~ ^check\ *=\ *(.*)$ ]]; then 46 | check=${BASH_REMATCH[1]} 47 | elif [[ $line =~ ^accel\ *=\ *(.*)$ ]]; then 48 | accel=${BASH_REMATCH[1]} 49 | elif [[ $line =~ ^timeout\ *=\ *(.*)$ ]]; then 50 | timeout=${BASH_REMATCH[1]} 51 | fi 52 | done 53 | if [ -n "${testname}" ]; then 54 | $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout" 55 | fi 56 | exec {fd}<&- 57 | } 58 | 59 | function arch_cmd() 60 | { 61 | [ "${ARCH_CMD}" ] && echo "${ARCH_CMD}" 62 | } 63 | 64 | # The current file has to be the only file sourcing the arch helper 65 | # file 66 | ARCH_FUNC=scripts/${ARCH}/func.bash 67 | if [ -f "${ARCH_FUNC}" ]; then 68 | source "${ARCH_FUNC}" 69 | fi 70 | -------------------------------------------------------------------------------- /scripts/git.difforder: -------------------------------------------------------------------------------- 1 | COPYRIGHT 2 | MAINTAINERS 3 | *README 4 | scripts/*.mak 5 | scripts/*.py 6 | scripts/*.bash 7 | scripts/*.sh 8 | scripts/* 9 | */run 10 | run_tests.sh 11 | configure 12 | *Makefile* 13 | *.mak 14 | lib/*.lds 15 | lib/linux/* 16 | lib/asm-generic/* 17 | lib/*/asm/* 18 | lib/*.h 19 | lib/*.S 20 | lib/*.c 21 | *.lds 22 | *.h 23 | *.S 24 | *.c 25 | *.cfg 26 | -------------------------------------------------------------------------------- /scripts/s390x/func.bash: -------------------------------------------------------------------------------- 1 | # The file scripts/common.bash has to be the only file sourcing this 2 | # arch helper file 3 | source config.mak 4 | 5 | ARCH_CMD=arch_cmd_s390x 6 | 7 | function arch_cmd_s390x() 8 | { 9 | local cmd=$1 10 | local testname=$2 11 | local groups=$3 12 | local smp=$4 13 | local kernel=$5 14 | local opts=$6 15 | local arch=$7 16 | local check=$8 17 | local accel=$9 18 | local timeout=${10} 19 | 20 | # run the normal test case 21 | "$cmd" "$testname" "$groups" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout" 22 | 23 | # run PV test case 24 | if [ "$ACCEL" = 'tcg' ] || find_word "migration" "$groups"; then 25 | return 26 | fi 27 | kernel=${kernel%.elf}.pv.bin 28 | testname=${testname}_PV 29 | if [ ! -f "${kernel}" ]; then 30 | if [ -z "${HOST_KEY_DOCUMENT}" ]; then 31 | return 2 32 | fi 33 | 34 | print_result 'SKIP' $testname '' 'PVM image was not created' 35 | return 2 36 | fi 37 | "$cmd" "$testname" "$groups pv" "$smp" "$kernel" "$opts" "$arch" "$check" "$accel" "$timeout" 38 | } 39 | -------------------------------------------------------------------------------- /x86/Makefile: -------------------------------------------------------------------------------- 1 | include $(SRCDIR)/$(TEST_DIR)/Makefile.$(ARCH) 2 | -------------------------------------------------------------------------------- /x86/Makefile.i386: -------------------------------------------------------------------------------- 1 | cstart.o = $(TEST_DIR)/cstart.o 2 | bits = 32 3 | ldarch = elf32-i386 4 | exe = flat 5 | bin = elf 6 | COMMON_CFLAGS += -mno-sse -mno-sse2 7 | arch_LDFLAGS = -m elf_i386 8 | 9 | cflatobjs += lib/x86/setjmp32.o lib/ldiv32.o 10 | 11 | tests = $(TEST_DIR)/taskswitch.$(exe) $(TEST_DIR)/taskswitch2.$(exe) \ 12 | $(TEST_DIR)/cmpxchg8b.$(exe) $(TEST_DIR)/la57.$(exe) 13 | 14 | include $(SRCDIR)/$(TEST_DIR)/Makefile.common 15 | -------------------------------------------------------------------------------- /x86/Makefile.x86_64: -------------------------------------------------------------------------------- 1 | cstart.o = $(TEST_DIR)/cstart64.o 2 | bits = 64 3 | ldarch = elf64-x86-64 4 | ifeq ($(CONFIG_EFI),y) 5 | exe = efi 6 | bin = so 7 | FORMAT = efi-app-x86_64 8 | cstart.o = $(TEST_DIR)/efi/efistart64.o 9 | arch_LDFLAGS = '' 10 | else 11 | exe = flat 12 | bin = elf 13 | arch_LDFLAGS = -m elf_x86_64 14 | endif 15 | 16 | fcf_protection_full := $(call cc-option, -fcf-protection=full,) 17 | COMMON_CFLAGS += -mno-red-zone -mno-sse -mno-sse2 $(fcf_protection_full) 18 | 19 | cflatobjs += lib/x86/setjmp64.o 20 | cflatobjs += lib/x86/intel-iommu.o 21 | cflatobjs += lib/x86/usermode.o 22 | 23 | tests = $(TEST_DIR)/apic.$(exe) \ 24 | $(TEST_DIR)/emulator.$(exe) $(TEST_DIR)/idt_test.$(exe) \ 25 | $(TEST_DIR)/xsave.$(exe) $(TEST_DIR)/rmap_chain.$(exe) \ 26 | $(TEST_DIR)/pcid.$(exe) $(TEST_DIR)/debug.$(exe) \ 27 | $(TEST_DIR)/ioapic.$(exe) $(TEST_DIR)/memory.$(exe) \ 28 | $(TEST_DIR)/pku.$(exe) $(TEST_DIR)/hyperv_clock.$(exe) 29 | tests += $(TEST_DIR)/syscall.$(exe) 30 | tests += $(TEST_DIR)/tscdeadline_latency.$(exe) 31 | tests += $(TEST_DIR)/intel-iommu.$(exe) 32 | tests += $(TEST_DIR)/vmware_backdoors.$(exe) 33 | tests += $(TEST_DIR)/rdpru.$(exe) 34 | tests += $(TEST_DIR)/pks.$(exe) 35 | tests += $(TEST_DIR)/pmu_lbr.$(exe) 36 | 37 | ifeq ($(CONFIG_EFI),y) 38 | tests += $(TEST_DIR)/amd_sev.$(exe) 39 | endif 40 | 41 | # The following test cases are disabled when building EFI tests because they 42 | # use absolute addresses in their inline assembly code, which cannot compile 43 | # with the '-fPIC' flag 44 | ifneq ($(CONFIG_EFI),y) 45 | tests += $(TEST_DIR)/access_test.$(exe) 46 | tests += $(TEST_DIR)/svm.$(exe) 47 | tests += $(TEST_DIR)/svm_npt.$(exe) 48 | tests += $(TEST_DIR)/vmx.$(exe) 49 | endif 50 | 51 | ifneq ($(fcf_protection_full),) 52 | tests += $(TEST_DIR)/cet.$(exe) 53 | endif 54 | 55 | include $(SRCDIR)/$(TEST_DIR)/Makefile.common 56 | 57 | $(TEST_DIR)/hyperv_clock.$(bin): $(TEST_DIR)/hyperv_clock.o 58 | 59 | $(TEST_DIR)/vmx.$(bin): $(TEST_DIR)/vmx_tests.o 60 | $(TEST_DIR)/svm.$(bin): $(TEST_DIR)/svm_tests.o 61 | $(TEST_DIR)/svm_npt.$(bin): $(TEST_DIR)/svm_npt.o 62 | -------------------------------------------------------------------------------- /x86/access.h: -------------------------------------------------------------------------------- 1 | #ifndef X86_ACCESS_H 2 | #define X86_ACCESS_H 3 | 4 | #define PT_LEVEL_PML4 4 5 | #define PT_LEVEL_PML5 5 6 | 7 | int ac_test_run(int page_table_levels); 8 | 9 | #endif // X86_ACCESS_H -------------------------------------------------------------------------------- /x86/access_test.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | #include "processor.h" 3 | #include "x86/vm.h" 4 | #include "access.h" 5 | 6 | int main(void) 7 | { 8 | int r; 9 | 10 | printf("starting test\n\n"); 11 | r = ac_test_run(PT_LEVEL_PML4); 12 | 13 | #ifndef CONFIG_EFI 14 | /* 15 | * Not supported yet for UEFI, because setting up 5 16 | * level page table requires entering real mode. 17 | */ 18 | if (this_cpu_has(X86_FEATURE_LA57)) { 19 | printf("starting 5-level paging test.\n\n"); 20 | setup_5level_page_table(); 21 | r = ac_test_run(PT_LEVEL_PML5); 22 | } 23 | #endif 24 | 25 | return r ? 0 : 1; 26 | } 27 | -------------------------------------------------------------------------------- /x86/cmpxchg8b.c: -------------------------------------------------------------------------------- 1 | #include "ioram.h" 2 | #include "vm.h" 3 | #include "libcflat.h" 4 | #include "desc.h" 5 | #include "types.h" 6 | #include "processor.h" 7 | 8 | static void test_cmpxchg8b(u32 *mem) 9 | { 10 | mem[1] = 2; 11 | mem[0] = 1; 12 | asm("push %%ebx\n" 13 | "mov %[ebx_val], %%ebx\n" 14 | "lock cmpxchg8b (%0)\n" 15 | "pop %%ebx" : : "D" (mem), 16 | "d" (2), "a" (1), "c" (4), [ebx_val] "i" (3) : "memory"); 17 | report(mem[0] == 3 && mem[1] == 4, "cmpxchg8b"); 18 | } 19 | 20 | int main(void) 21 | { 22 | setup_vm(); 23 | 24 | test_cmpxchg8b(phys_to_virt(read_cr3()) + 4088); 25 | return report_summary(); 26 | } 27 | -------------------------------------------------------------------------------- /x86/dummy.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | 3 | int main(int argc, char **argv) 4 | { 5 | /* 6 | * scripts/runtime.bash uses this test as a canary to determine if the 7 | * basic setup is functional. Print a magic string to let runtime.bash 8 | * know that all is well. 9 | */ 10 | printf("Dummy Hello World!"); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /x86/efi/efistart64.S: -------------------------------------------------------------------------------- 1 | /* Startup code and pre-defined data structures */ 2 | 3 | #include "apic-defs.h" 4 | #include "asm-generic/page.h" 5 | #include "crt0-efi-x86_64.S" 6 | 7 | 8 | /* Reserve stack in .data */ 9 | .data 10 | .align PAGE_SIZE 11 | . = . + PAGE_SIZE * MAX_TEST_CPUS 12 | .globl stacktop 13 | stacktop: 14 | 15 | .globl smp_stacktop 16 | smp_stacktop: .long 0 17 | 18 | .align PAGE_SIZE 19 | .globl ptl2 20 | ptl2: 21 | . = . + 4 * PAGE_SIZE 22 | .align PAGE_SIZE 23 | 24 | .globl ptl3 25 | ptl3: 26 | . = . + PAGE_SIZE 27 | .align PAGE_SIZE 28 | 29 | .globl ptl4 30 | ptl4: 31 | . = . + PAGE_SIZE 32 | .align PAGE_SIZE 33 | 34 | .section .init 35 | .code64 36 | .text 37 | 38 | .code16 39 | REALMODE_GDT_LOWMEM = PAGE_SIZE - 2 40 | 41 | .globl rm_trampoline 42 | rm_trampoline: 43 | 44 | .globl sipi_entry 45 | sipi_entry: 46 | mov %cr0, %eax 47 | or $1, %eax 48 | mov %eax, %cr0 49 | 50 | /* Retrieve relocated ap_rm_gdt_descr address at REALMODE_GDT_LOWMEM. */ 51 | mov (REALMODE_GDT_LOWMEM), %ebx 52 | lgdtl (%ebx) 53 | 54 | lcall $0x18, $0x0 55 | 56 | .globl ap_rm_gdt 57 | ap_rm_gdt: 58 | .quad 0 59 | .quad 0x00cf9b000000ffff // flat 32-bit code segment 60 | .quad 0x00cf93000000ffff // flat 32-bit data segment 61 | .quad 0 // call gate to 32-bit AP entrypoint 62 | .globl ap_rm_gdt_end 63 | ap_rm_gdt_end: 64 | 65 | .globl ap_rm_gdt_descr 66 | ap_rm_gdt_descr: 67 | .word 0 68 | .long 0 69 | 70 | .globl sipi_end 71 | sipi_end: 72 | 73 | .globl rm_trampoline_end 74 | rm_trampoline_end: 75 | 76 | #include "../trampolines.S" 77 | -------------------------------------------------------------------------------- /x86/efi/elf_x86_64_efi.lds: -------------------------------------------------------------------------------- 1 | /* Developed based on GNU-EFI/gnuefi/elf_x86_64_efi.lds, licensed under GNU GPL */ 2 | /* Same as elf_x86_64_fbsd_efi.lds, except for OUTPUT_FORMAT below - KEEP IN SYNC */ 3 | OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") 4 | OUTPUT_ARCH(i386:x86-64) 5 | ENTRY(_start) 6 | SECTIONS 7 | { 8 | . = 0; 9 | ImageBase = .; 10 | /* .hash and/or .gnu.hash MUST come first! */ 11 | .hash : { *(.hash) } 12 | .gnu.hash : { *(.gnu.hash) } 13 | . = ALIGN(4096); 14 | .eh_frame : 15 | { 16 | *(.eh_frame) 17 | } 18 | . = ALIGN(4096); 19 | .text : 20 | { 21 | _text = .; 22 | *(.text) 23 | *(.text.*) 24 | *(.gnu.linkonce.t.*) 25 | . = ALIGN(16); 26 | } 27 | _etext = .; 28 | _text_size = . - _text; 29 | . = ALIGN(4096); 30 | .reloc : 31 | { 32 | *(.reloc) 33 | } 34 | . = ALIGN(4096); 35 | .data : 36 | { 37 | _data = .; 38 | *(.rodata*) 39 | *(.got.plt) 40 | *(.got) 41 | /* Expected by lib/x86/desc.c to store exception_table */ 42 | exception_table_start = .; 43 | *(.data.ex) 44 | exception_table_end = .; 45 | *(.data*) 46 | *(.sdata) 47 | /* the EFI loader doesn't seem to like a .bss section, so we stick 48 | it all into .data: */ 49 | *(.sbss) 50 | *(.scommon) 51 | *(.dynbss) 52 | *(.bss) 53 | *(COMMON) 54 | *(.rel.local) 55 | } 56 | .note.gnu.build-id : { *(.note.gnu.build-id) } 57 | 58 | _edata = .; 59 | _data_size = . - _etext; 60 | . = ALIGN(4096); 61 | .dynamic : { *(.dynamic) } 62 | . = ALIGN(4096); 63 | .rela : 64 | { 65 | *(.rela.data*) 66 | *(.rela.got) 67 | *(.rela.stab) 68 | } 69 | . = ALIGN(4096); 70 | .dynsym : { *(.dynsym) } 71 | . = ALIGN(4096); 72 | .dynstr : { *(.dynstr) } 73 | . = ALIGN(4096); 74 | .ignored.reloc : 75 | { 76 | *(.rela.reloc) 77 | *(.eh_frame) 78 | *(.note.GNU-stack) 79 | } 80 | .comment 0 : { *(.comment) } 81 | } 82 | -------------------------------------------------------------------------------- /x86/flat.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 4M + SIZEOF_HEADERS; 4 | stext = .; 5 | .text : { *(.init) *(.text) *(.text.*) } 6 | etext = .; 7 | . = ALIGN(4K); 8 | .data : { 9 | *(.data) 10 | exception_table_start = .; 11 | *(.data.ex) 12 | exception_table_end = .; 13 | } 14 | . = ALIGN(16); 15 | .rodata : { *(.rodata) } 16 | . = ALIGN(16); 17 | .stack : { *(stack) } 18 | . = ALIGN(16); 19 | bss_start = .; 20 | .bss : { *(.bss) } 21 | . = ALIGN(4K); 22 | edata = .; 23 | 24 | /DISCARD/ : { 25 | *(.comment .comment.* .note .note.*) 26 | } 27 | } 28 | 29 | ENTRY(start) 30 | -------------------------------------------------------------------------------- /x86/hello_acrn.c: -------------------------------------------------------------------------------- 1 | #include "vm.h" 2 | 3 | int main(void) 4 | { 5 | setup_vm(); 6 | 7 | report(true, "***Hello ACRN***"); 8 | return report_summary(); 9 | } 10 | -------------------------------------------------------------------------------- /x86/hyperv.c: -------------------------------------------------------------------------------- 1 | #include "hyperv.h" 2 | #include "asm/io.h" 3 | #include "smp.h" 4 | 5 | enum { 6 | HV_TEST_DEV_SINT_ROUTE_CREATE = 1, 7 | HV_TEST_DEV_SINT_ROUTE_DESTROY, 8 | HV_TEST_DEV_SINT_ROUTE_SET_SINT, 9 | HV_TEST_DEV_MSG_CONN_CREATE, 10 | HV_TEST_DEV_MSG_CONN_DESTROY, 11 | HV_TEST_DEV_EVT_CONN_CREATE, 12 | HV_TEST_DEV_EVT_CONN_DESTROY, 13 | }; 14 | 15 | static void synic_ctl(u32 ctl, u32 vcpu_id, u32 sint, u32 conn_id) 16 | { 17 | outl((conn_id << 24) | (ctl << 16) | (vcpu_id << 8) | sint, 0x3000); 18 | } 19 | 20 | static void sint_enable(u8 sint, u8 vec, bool auto_eoi) 21 | { 22 | wrmsr(HV_X64_MSR_SINT0 + sint, 23 | (u64)vec | (auto_eoi ? HV_SYNIC_SINT_AUTO_EOI : 0)); 24 | } 25 | 26 | static void sint_disable(u8 sint) 27 | { 28 | wrmsr(HV_X64_MSR_SINT0 + sint, 0xff | HV_SYNIC_SINT_MASKED); 29 | } 30 | 31 | void synic_sint_create(u8 sint, u8 vec, bool auto_eoi) 32 | { 33 | synic_ctl(HV_TEST_DEV_SINT_ROUTE_CREATE, smp_id(), sint, 0); 34 | sint_enable(sint, vec, auto_eoi); 35 | } 36 | 37 | void synic_sint_set(u8 vcpu, u8 sint) 38 | { 39 | synic_ctl(HV_TEST_DEV_SINT_ROUTE_SET_SINT, vcpu, sint, 0); 40 | } 41 | 42 | void synic_sint_destroy(u8 sint) 43 | { 44 | sint_disable(sint); 45 | synic_ctl(HV_TEST_DEV_SINT_ROUTE_DESTROY, smp_id(), sint, 0); 46 | } 47 | 48 | void msg_conn_create(u8 sint, u8 vec, u8 conn_id) 49 | { 50 | synic_ctl(HV_TEST_DEV_MSG_CONN_CREATE, smp_id(), sint, conn_id); 51 | sint_enable(sint, vec, true); 52 | } 53 | 54 | void msg_conn_destroy(u8 sint, u8 conn_id) 55 | { 56 | sint_disable(sint); 57 | synic_ctl(HV_TEST_DEV_MSG_CONN_DESTROY, 0, 0, conn_id); 58 | } 59 | 60 | void evt_conn_create(u8 sint, u8 vec, u8 conn_id) 61 | { 62 | synic_ctl(HV_TEST_DEV_EVT_CONN_CREATE, smp_id(), sint, conn_id); 63 | sint_enable(sint, vec, true); 64 | } 65 | 66 | void evt_conn_destroy(u8 sint, u8 conn_id) 67 | { 68 | sint_disable(sint); 69 | synic_ctl(HV_TEST_DEV_EVT_CONN_DESTROY, 0, 0, conn_id); 70 | } 71 | -------------------------------------------------------------------------------- /x86/idt_test.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | #include "processor.h" 3 | #include "desc.h" 4 | 5 | static int test_ud2(bool *rflags_rf) 6 | { 7 | asm volatile(ASM_TRY("1f") 8 | "ud2 \n\t" 9 | "1:" :); 10 | *rflags_rf = exception_rflags_rf(); 11 | return exception_vector(); 12 | } 13 | 14 | static int test_gp(bool *rflags_rf) 15 | { 16 | unsigned long tmp; 17 | 18 | asm volatile("mov $0xffffffff, %0 \n\t" 19 | ASM_TRY("1f") 20 | "mov %0, %%cr4\n\t" 21 | "1:" 22 | : "=a"(tmp)); 23 | *rflags_rf = exception_rflags_rf(); 24 | return exception_vector(); 25 | } 26 | 27 | int main(void) 28 | { 29 | int r; 30 | bool rflags_rf; 31 | 32 | printf("Starting IDT test\n"); 33 | r = test_gp(&rflags_rf); 34 | report(r == GP_VECTOR, "Testing #GP"); 35 | report(rflags_rf, "Testing #GP rflags.rf"); 36 | r = test_ud2(&rflags_rf); 37 | report(r == UD_VECTOR, "Testing #UD"); 38 | report(rflags_rf, "Testing #UD rflags.rf"); 39 | 40 | return report_summary(); 41 | } 42 | -------------------------------------------------------------------------------- /x86/ioram.h: -------------------------------------------------------------------------------- 1 | #ifndef X86_IORAM_H 2 | #define X86_IORAM_H 3 | 4 | #define IORAM_BASE_PHYS 0xff000000UL 5 | #define IORAM_LEN 0x10000UL 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /x86/kvmclock.h: -------------------------------------------------------------------------------- 1 | #ifndef X86_KVMCLOCK_H 2 | #define X86_KVMCLOCK_H 3 | 4 | #define MSR_KVM_WALL_CLOCK_NEW 0x4b564d00 5 | #define MSR_KVM_SYSTEM_TIME_NEW 0x4b564d01 6 | 7 | #define MAX_CPU 64 8 | 9 | #define PVCLOCK_TSC_STABLE_BIT (1 << 0) 10 | #define PVCLOCK_RAW_CYCLE_BIT (1 << 7) /* Get raw cycle */ 11 | 12 | # define NSEC_PER_SEC 1000000000ULL 13 | 14 | typedef u64 cycle_t; 15 | 16 | struct pvclock_vcpu_time_info { 17 | u32 version; 18 | u32 pad0; 19 | u64 tsc_timestamp; 20 | u64 system_time; 21 | u32 tsc_to_system_mul; 22 | s8 tsc_shift; 23 | u8 flags; 24 | u8 pad[2]; 25 | } __attribute__((__packed__)); /* 32 bytes */ 26 | 27 | struct pvclock_wall_clock { 28 | u32 version; 29 | u32 sec; 30 | u32 nsec; 31 | } __attribute__((__packed__)); 32 | 33 | struct timespec { 34 | long tv_sec; 35 | long tv_nsec; 36 | }; 37 | 38 | void pvclock_set_flags(unsigned char flags); 39 | cycle_t kvm_clock_read(void); 40 | void kvm_get_wallclock(struct timespec *ts); 41 | void kvm_clock_init(void *data); 42 | void kvm_clock_clear(void *data); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /x86/la57.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | #include "processor.h" 3 | #include "desc.h" 4 | 5 | int main(int ac, char **av) 6 | { 7 | int vector = write_cr4_safe(read_cr4() | X86_CR4_LA57); 8 | int expected = this_cpu_has(X86_FEATURE_LA57) ? 0 : 13; 9 | 10 | report(vector == expected, "%s when CR4.LA57 %ssupported", 11 | expected ? "#GP" : "No fault", expected ? "un" : ""); 12 | return report_summary(); 13 | } 14 | -------------------------------------------------------------------------------- /x86/rdpru.c: -------------------------------------------------------------------------------- 1 | /* RDPRU test */ 2 | 3 | #include "libcflat.h" 4 | #include "processor.h" 5 | #include "desc.h" 6 | 7 | static int rdpru_safe(void) 8 | { 9 | asm volatile (ASM_TRY("1f") 10 | ".byte 0x0f,0x01,0xfd \n\t" /* rdpru */ 11 | "1:" : : "c" (0) : "eax", "edx"); 12 | return exception_vector(); 13 | } 14 | 15 | int main(int ac, char **av) 16 | { 17 | if (this_cpu_has(X86_FEATURE_RDPRU)) 18 | report_skip("RDPRU raises #UD"); 19 | else 20 | report(rdpru_safe() == UD_VECTOR, "RDPRU raises #UD"); 21 | 22 | return report_summary(); 23 | } 24 | -------------------------------------------------------------------------------- /x86/realmode.lds: -------------------------------------------------------------------------------- 1 | SECTIONS 2 | { 3 | . = 16K; 4 | stext = .; 5 | .text : { *(.init) *(.text) } 6 | . = ALIGN(4K); 7 | .data : { *(.data) *(.rodata*) } 8 | . = ALIGN(16); 9 | .bss : { *(.bss) } 10 | edata = .; 11 | } 12 | ENTRY(start) 13 | -------------------------------------------------------------------------------- /x86/rmap_chain.c: -------------------------------------------------------------------------------- 1 | /* test long rmap chains */ 2 | 3 | #include "libcflat.h" 4 | #include "fwcfg.h" 5 | #include "vm.h" 6 | #include "vmalloc.h" 7 | #include "smp.h" 8 | #include "alloc_page.h" 9 | 10 | int main (void) 11 | { 12 | int i; 13 | int nr_pages; 14 | void *target_page, *virt_addr; 15 | 16 | setup_vm(); 17 | 18 | nr_pages = fwcfg_get_u64(FW_CFG_RAM_SIZE) / PAGE_SIZE; 19 | nr_pages -= 1000; 20 | target_page = alloc_page(); 21 | 22 | virt_addr = (void *) 0xfffffa000; 23 | for (i = 0; i < nr_pages; i++) { 24 | install_page(phys_to_virt(read_cr3()), virt_to_phys(target_page), 25 | virt_addr); 26 | virt_addr += PAGE_SIZE; 27 | } 28 | printf("created %d mappings\n", nr_pages); 29 | 30 | virt_addr = (void *) 0xfffffa000; 31 | for (i = 0; i < nr_pages; i++) { 32 | unsigned long *touch = virt_addr; 33 | 34 | *touch = 0; 35 | virt_addr += PAGE_SIZE; 36 | } 37 | printf("instantiated mappings\n"); 38 | 39 | virt_addr += PAGE_SIZE; 40 | install_pte(phys_to_virt(read_cr3()), 1, virt_addr, 41 | 0 | PT_PRESENT_MASK | PT_WRITABLE_MASK, target_page); 42 | 43 | *(unsigned long *)virt_addr = 0; 44 | printf("PASS\n"); 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /x86/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ -z "$KUT_STANDALONE" ]; then 4 | if [ ! -f config.mak ]; then 5 | echo "run ./configure && make first. See ./configure -h" 6 | exit 2 7 | fi 8 | source config.mak 9 | source scripts/arch-run.bash 10 | fi 11 | 12 | ACCEL=$(get_qemu_accelerator) || 13 | exit $? 14 | 15 | qemu=$(search_qemu_binary) || 16 | exit $? 17 | 18 | if ! ${qemu} -device '?' 2>&1 | grep -F -e \"testdev\" -e \"pc-testdev\" > /dev/null; 19 | then 20 | echo "No Qemu test device support found" 21 | exit 2 22 | fi 23 | 24 | if 25 | ${qemu} -device '?' 2>&1 | grep -F "pci-testdev" > /dev/null; 26 | then 27 | pci_testdev="-device pci-testdev" 28 | else 29 | pci_testdev="" 30 | fi 31 | 32 | if 33 | ${qemu} -device '?' 2>&1 | grep -F "pc-testdev" > /dev/null; 34 | then 35 | pc_testdev="-device pc-testdev -device isa-debug-exit,iobase=0xf4,iosize=0x4" 36 | else 37 | pc_testdev="-device testdev,chardev=testlog -chardev file,id=testlog,path=msr.out" 38 | fi 39 | 40 | command="${qemu} --no-reboot -nodefaults $pc_testdev -vnc none -serial stdio $pci_testdev" 41 | command+=" -machine accel=$ACCEL" 42 | if [ "${CONFIG_EFI}" != y ]; then 43 | command+=" -kernel" 44 | fi 45 | command="$(timeout_cmd) $command" 46 | 47 | if [ "${CONFIG_EFI}" = y ]; then 48 | # Set ENVIRON_DEFAULT=n to remove '-initrd' flag for QEMU (see 49 | # 'scripts/arch-run.bash' for more details). This is because when using 50 | # UEFI, the test case binaries are passed to QEMU through the disk 51 | # image, not through the '-kernel' flag. And QEMU reports an error if it 52 | # gets '-initrd' without a '-kernel' 53 | ENVIRON_DEFAULT=n run_qemu ${command} "$@" 54 | else 55 | run_qemu ${command} "$@" 56 | fi 57 | -------------------------------------------------------------------------------- /x86/setjmp.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | #include "setjmp.h" 3 | 4 | static const int expected[] = { 5 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 6 | }; 7 | 8 | #define NUM_LONGJMPS ARRAY_SIZE(expected) 9 | 10 | int main(void) 11 | { 12 | volatile int index = 0; 13 | jmp_buf j; 14 | int i; 15 | 16 | i = setjmp(j); 17 | report(expected[index] == i, "actual %d == expected %d", 18 | i, expected[index]); 19 | index++; 20 | if (i + 1 < NUM_LONGJMPS) 21 | longjmp(j, i + 1); 22 | 23 | return report_summary(); 24 | } 25 | -------------------------------------------------------------------------------- /x86/sieve.c: -------------------------------------------------------------------------------- 1 | #include "alloc.h" 2 | #include "libcflat.h" 3 | 4 | static int sieve(char* data, int size) 5 | { 6 | int i, j, r = 0; 7 | 8 | for (i = 0; i < size; ++i) 9 | data[i] = 1; 10 | 11 | data[0] = data[1] = 0; 12 | 13 | for (i = 2; i < size; ++i) 14 | if (data[i]) { 15 | ++r; 16 | for (j = i*2; j < size; j += i) 17 | data[j] = 0; 18 | } 19 | return r; 20 | } 21 | 22 | static void test_sieve(const char *msg, char *data, int size) 23 | { 24 | int r; 25 | 26 | printf("%s:", msg); 27 | r = sieve(data, size); 28 | printf("%d out of %d\n", r, size); 29 | } 30 | 31 | #define STATIC_SIZE 1000000 32 | #define VSIZE 100000000 33 | char static_data[STATIC_SIZE]; 34 | 35 | int main(void) 36 | { 37 | void *v; 38 | int i; 39 | 40 | printf("starting sieve\n"); 41 | test_sieve("static", static_data, STATIC_SIZE); 42 | setup_vm(); 43 | test_sieve("mapped", static_data, STATIC_SIZE); 44 | for (i = 0; i < 3; ++i) { 45 | v = malloc(VSIZE); 46 | test_sieve("virtual", v, VSIZE); 47 | free(v); 48 | } 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /x86/smptest.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | #include "apic.h" 3 | #include "smp.h" 4 | 5 | unsigned nipis; 6 | 7 | static void ipi_test(void *data) 8 | { 9 | int n = (long)data; 10 | 11 | printf("ipi called, cpu %d\n", n); 12 | if (id_map[n] != smp_id()) 13 | printf("but wrong cpu %d\n", smp_id()); 14 | else 15 | nipis++; 16 | } 17 | 18 | int main(void) 19 | { 20 | int ncpus; 21 | int i; 22 | 23 | ncpus = cpu_count(); 24 | printf("found %d cpus\n", ncpus); 25 | for (i = 0; i < ncpus; ++i) 26 | on_cpu(i, ipi_test, (void *)(long)i); 27 | 28 | report(nipis == ncpus, "IPI to each CPU"); 29 | return report_summary(); 30 | } 31 | -------------------------------------------------------------------------------- /x86/taskswitch.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010 Siemens AG 3 | * Author: Jan Kiszka 4 | * 5 | * Released under GPLv2. 6 | */ 7 | 8 | #include "libcflat.h" 9 | #include "x86/desc.h" 10 | #include "vmalloc.h" 11 | 12 | #define TSS_RETURN (FIRST_SPARE_SEL) 13 | 14 | void fault_entry(void); 15 | 16 | static __attribute__((used, regparm(1))) void 17 | fault_handler(unsigned long error_code) 18 | { 19 | print_current_tss_info(); 20 | printf("error code %lx\n", error_code); 21 | 22 | tss[0].eip += 2; 23 | 24 | gdt[TSS_MAIN / 8].type &= ~DESC_BUSY; 25 | 26 | set_gdt_task_gate(TSS_RETURN, tss_intr.prev); 27 | } 28 | 29 | asm ( 30 | "fault_entry:\n" 31 | " mov (%esp),%eax\n" 32 | " call fault_handler\n" 33 | " jmp $" xstr(TSS_RETURN) ", $0\n" 34 | ); 35 | 36 | int main(int ac, char **av) 37 | { 38 | const long invalid_segment = 0x1234; 39 | 40 | setup_tss32(); 41 | set_intr_task_gate(13, fault_entry); 42 | 43 | asm ( 44 | "mov %0,%%es\n" 45 | : : "r" (invalid_segment) : "edi" 46 | ); 47 | 48 | printf("post fault\n"); 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /x86/tsc.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | #include "processor.h" 3 | 4 | static void test_wrtsc(u64 t1) 5 | { 6 | u64 t2; 7 | 8 | wrtsc(t1); 9 | t2 = rdtsc(); 10 | printf("rdtsc after wrtsc(%" PRId64 "): %" PRId64 "\n", t1, t2); 11 | } 12 | 13 | static void test_rdtscp(u64 aux) 14 | { 15 | u32 ecx; 16 | 17 | wrmsr(MSR_TSC_AUX, aux); 18 | rdtscp(&ecx); 19 | report(ecx == aux, "Test RDTSCP %" PRIu64, aux); 20 | } 21 | 22 | static void test_rdpid(u64 aux) 23 | { 24 | u32 eax; 25 | 26 | wrmsr(MSR_TSC_AUX, aux); 27 | asm (".byte 0xf3, 0x0f, 0xc7, 0xf8" : "=a" (eax)); 28 | report(eax == aux, "Test rdpid %%eax %" PRId64, aux); 29 | } 30 | 31 | int main(void) 32 | { 33 | u64 t1, t2; 34 | 35 | t1 = rdtsc(); 36 | t2 = rdtsc(); 37 | printf("rdtsc latency %u\n", (unsigned)(t2 - t1)); 38 | 39 | test_wrtsc(0); 40 | test_wrtsc(100000000000ull); 41 | 42 | if (this_cpu_has(X86_FEATURE_RDTSCP)) { 43 | test_rdtscp(0); 44 | test_rdtscp(10); 45 | test_rdtscp(0x100); 46 | } else 47 | printf("rdtscp not supported\n"); 48 | 49 | if (this_cpu_has(X86_FEATURE_RDPID)) { 50 | test_rdpid(0); 51 | test_rdpid(10); 52 | test_rdpid(0x100); 53 | } else 54 | printf("rdpid not supported\n"); 55 | return report_summary(); 56 | } 57 | -------------------------------------------------------------------------------- /x86/tsc_adjust.c: -------------------------------------------------------------------------------- 1 | #include "libcflat.h" 2 | #include "processor.h" 3 | 4 | int main(void) 5 | { 6 | u64 t1, t2, t3, t4, t5; 7 | 8 | if (!this_cpu_has(X86_FEATURE_TSC_ADJUST)) { 9 | report_skip("MSR_IA32_TSC_ADJUST feature not enabled"); 10 | return report_summary(); 11 | } 12 | 13 | report(rdmsr(MSR_IA32_TSC_ADJUST) == 0x0, 14 | "MSR_IA32_TSC_ADJUST msr initialization"); 15 | t3 = 100000000000ull; 16 | t1 = rdtsc(); 17 | wrmsr(MSR_IA32_TSC_ADJUST, t3); 18 | t2 = rdtsc(); 19 | report(rdmsr(MSR_IA32_TSC_ADJUST) == t3, 20 | "MSR_IA32_TSC_ADJUST msr read / write"); 21 | report((t2 - t1) >= t3, 22 | "TSC adjustment for MSR_IA32_TSC_ADJUST value"); 23 | t3 = 0x0; 24 | wrmsr(MSR_IA32_TSC_ADJUST, t3); 25 | report(rdmsr(MSR_IA32_TSC_ADJUST) == t3, 26 | "MSR_IA32_TSC_ADJUST msr read / write"); 27 | t4 = 100000000000ull; 28 | t1 = rdtsc(); 29 | wrtsc(t4); 30 | t2 = rdtsc(); 31 | t5 = rdmsr(MSR_IA32_TSC_ADJUST); 32 | report(t1 <= t4 - t5, "Internal TSC advances across write to IA32_TSC"); 33 | report(t2 >= t4, "IA32_TSC advances after write to IA32_TSC"); 34 | 35 | return report_summary(); 36 | } 37 | -------------------------------------------------------------------------------- /x86/tsx-ctrl.c: -------------------------------------------------------------------------------- 1 | /* TSX tests */ 2 | 3 | #include "libcflat.h" 4 | #include "processor.h" 5 | #include "msr.h" 6 | 7 | static bool try_transaction(void) 8 | { 9 | unsigned x; 10 | int i; 11 | 12 | for (i = 0; i < 100; i++) { 13 | x = 0; 14 | /* 15 | * The value before the transaction is important, so make the 16 | * operand input/output. 17 | */ 18 | asm volatile("xbegin 2f; movb $1, %0; xend; 2:" : "+m" (x) : : "eax"); 19 | if (x) { 20 | return true; 21 | } 22 | } 23 | return false; 24 | } 25 | 26 | int main(int ac, char **av) 27 | { 28 | if (!this_cpu_has(X86_FEATURE_RTM)) { 29 | report_skip("TSX not available"); 30 | return report_summary(); 31 | } 32 | if (!this_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) { 33 | report_skip("ARCH_CAPABILITIES not available"); 34 | return report_summary(); 35 | } 36 | if (!(rdmsr(MSR_IA32_ARCH_CAPABILITIES) & ARCH_CAP_TSX_CTRL_MSR)) { 37 | report_skip("TSX_CTRL not available"); 38 | return report_summary(); 39 | } 40 | 41 | report(rdmsr(MSR_IA32_TSX_CTRL) == 0, "TSX_CTRL should be 0"); 42 | report(try_transaction(), "Transactions do not abort"); 43 | 44 | wrmsr(MSR_IA32_TSX_CTRL, TSX_CTRL_CPUID_CLEAR); 45 | report(!this_cpu_has(X86_FEATURE_RTM), "TSX_CTRL hides RTM"); 46 | report(!this_cpu_has(X86_FEATURE_HLE), "TSX_CTRL hides HLE"); 47 | 48 | /* Microcode might hide HLE unconditionally */ 49 | wrmsr(MSR_IA32_TSX_CTRL, 0); 50 | report(this_cpu_has(X86_FEATURE_RTM), "TSX_CTRL=0 unhides RTM"); 51 | 52 | wrmsr(MSR_IA32_TSX_CTRL, TSX_CTRL_RTM_DISABLE); 53 | report(!try_transaction(), "TSX_CTRL causes transactions to abort"); 54 | 55 | wrmsr(MSR_IA32_TSX_CTRL, 0); 56 | report(try_transaction(), "TSX_CTRL=0 causes transactions to succeed"); 57 | 58 | return report_summary(); 59 | } 60 | 61 | -------------------------------------------------------------------------------- /x86/types.h: -------------------------------------------------------------------------------- 1 | #ifndef X86_TYPES_H 2 | #define X86_TYPES_H 3 | 4 | #define DE_VECTOR 0 5 | #define DB_VECTOR 1 6 | #define NMI_VECTOR 2 7 | #define BP_VECTOR 3 8 | #define OF_VECTOR 4 9 | #define BR_VECTOR 5 10 | #define UD_VECTOR 6 11 | #define NM_VECTOR 7 12 | #define DF_VECTOR 8 13 | #define TS_VECTOR 10 14 | #define NP_VECTOR 11 15 | #define SS_VECTOR 12 16 | #define GP_VECTOR 13 17 | #define PF_VECTOR 14 18 | #define MF_VECTOR 16 19 | #define MC_VECTOR 18 20 | 21 | #endif 22 | --------------------------------------------------------------------------------