diff options
author | Jiri Kosina <jkosina@suse.cz> | 2018-06-08 04:20:42 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2018-06-08 04:20:42 -0400 |
commit | c1144d29f405ce1f4e6ede6482beb3d0d09750c6 (patch) | |
tree | 0f9fe36a50005bae6ffe28a4f978e71273f5b1d1 /tools | |
parent | d6c70a86bc72fabe7fc9d9533afdb46a56c16896 (diff) | |
parent | a317e559574b2af62095b39792d168cb98cb2561 (diff) |
Merge branch 'for-4.18/alps' into for-linus
hid-alps driver cleanups wrt. t4_read_write_register() handling
from Christophe Jaillet
Diffstat (limited to 'tools')
101 files changed, 10999 insertions, 569 deletions
diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index f41079da38c5..d554c11e01ff 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h | |||
@@ -316,6 +316,7 @@ | |||
316 | #define X86_FEATURE_VPCLMULQDQ (16*32+10) /* Carry-Less Multiplication Double Quadword */ | 316 | #define X86_FEATURE_VPCLMULQDQ (16*32+10) /* Carry-Less Multiplication Double Quadword */ |
317 | #define X86_FEATURE_AVX512_VNNI (16*32+11) /* Vector Neural Network Instructions */ | 317 | #define X86_FEATURE_AVX512_VNNI (16*32+11) /* Vector Neural Network Instructions */ |
318 | #define X86_FEATURE_AVX512_BITALG (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */ | 318 | #define X86_FEATURE_AVX512_BITALG (16*32+12) /* Support for VPOPCNT[B,W] and VPSHUF-BITQMB instructions */ |
319 | #define X86_FEATURE_TME (16*32+13) /* Intel Total Memory Encryption */ | ||
319 | #define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ | 320 | #define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ |
320 | #define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ | 321 | #define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ |
321 | #define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ | 322 | #define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ |
@@ -328,6 +329,7 @@ | |||
328 | /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ | 329 | /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ |
329 | #define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ | 330 | #define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ |
330 | #define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ | 331 | #define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ |
332 | #define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ | ||
331 | #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ | 333 | #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ |
332 | #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ | 334 | #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ |
333 | #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ | 335 | #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ |
diff --git a/tools/build/Build.include b/tools/build/Build.include index 418871d02ebf..a4bbb984941d 100644 --- a/tools/build/Build.include +++ b/tools/build/Build.include | |||
@@ -12,6 +12,7 @@ | |||
12 | # Convenient variables | 12 | # Convenient variables |
13 | comma := , | 13 | comma := , |
14 | squote := ' | 14 | squote := ' |
15 | pound := \# | ||
15 | 16 | ||
16 | ### | 17 | ### |
17 | # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o | 18 | # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o |
@@ -43,11 +44,11 @@ echo-cmd = $(if $($(quiet)cmd_$(1)),\ | |||
43 | ### | 44 | ### |
44 | # Replace >$< with >$$< to preserve $ when reloading the .cmd file | 45 | # Replace >$< with >$$< to preserve $ when reloading the .cmd file |
45 | # (needed for make) | 46 | # (needed for make) |
46 | # Replace >#< with >\#< to avoid starting a comment in the .cmd file | 47 | # Replace >#< with >$(pound)< to avoid starting a comment in the .cmd file |
47 | # (needed for make) | 48 | # (needed for make) |
48 | # Replace >'< with >'\''< to be able to enclose the whole string in '...' | 49 | # Replace >'< with >'\''< to be able to enclose the whole string in '...' |
49 | # (needed for the shell) | 50 | # (needed for the shell) |
50 | make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1))))) | 51 | make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1))))) |
51 | 52 | ||
52 | ### | 53 | ### |
53 | # Find any prerequisites that is newer than target or that does not exist. | 54 | # Find any prerequisites that is newer than target or that does not exist. |
diff --git a/tools/include/linux/spinlock.h b/tools/include/linux/spinlock.h index 4ed569fcb139..b21b586b9854 100644 --- a/tools/include/linux/spinlock.h +++ b/tools/include/linux/spinlock.h | |||
@@ -7,6 +7,7 @@ | |||
7 | 7 | ||
8 | #define spinlock_t pthread_mutex_t | 8 | #define spinlock_t pthread_mutex_t |
9 | #define DEFINE_SPINLOCK(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER; | 9 | #define DEFINE_SPINLOCK(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER; |
10 | #define __SPIN_LOCK_UNLOCKED(x) (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER | ||
10 | 11 | ||
11 | #define spin_lock_irqsave(x, f) (void)f, pthread_mutex_lock(x) | 12 | #define spin_lock_irqsave(x, f) (void)f, pthread_mutex_lock(x) |
12 | #define spin_unlock_irqrestore(x, f) (void)f, pthread_mutex_unlock(x) | 13 | #define spin_unlock_irqrestore(x, f) (void)f, pthread_mutex_unlock(x) |
diff --git a/tools/include/tools/config.h b/tools/include/tools/config.h new file mode 100644 index 000000000000..08ade7df8132 --- /dev/null +++ b/tools/include/tools/config.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #ifndef _TOOLS_CONFIG_H | ||
3 | #define _TOOLS_CONFIG_H | ||
4 | |||
5 | /* Subset of include/linux/kconfig.h */ | ||
6 | |||
7 | #define __ARG_PLACEHOLDER_1 0, | ||
8 | #define __take_second_arg(__ignored, val, ...) val | ||
9 | |||
10 | /* | ||
11 | * Helper macros to use CONFIG_ options in C/CPP expressions. Note that | ||
12 | * these only work with boolean and tristate options. | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * Getting something that works in C and CPP for an arg that may or may | ||
17 | * not be defined is tricky. Here, if we have "#define CONFIG_BOOGER 1" | ||
18 | * we match on the placeholder define, insert the "0," for arg1 and generate | ||
19 | * the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one). | ||
20 | * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when | ||
21 | * the last step cherry picks the 2nd arg, we get a zero. | ||
22 | */ | ||
23 | #define __is_defined(x) ___is_defined(x) | ||
24 | #define ___is_defined(val) ____is_defined(__ARG_PLACEHOLDER_##val) | ||
25 | #define ____is_defined(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0) | ||
26 | |||
27 | /* | ||
28 | * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0 | ||
29 | * otherwise. For boolean options, this is equivalent to | ||
30 | * IS_ENABLED(CONFIG_FOO). | ||
31 | */ | ||
32 | #define IS_BUILTIN(option) __is_defined(option) | ||
33 | |||
34 | #endif /* _TOOLS_CONFIG_H */ | ||
diff --git a/tools/include/uapi/drm/i915_drm.h b/tools/include/uapi/drm/i915_drm.h index 536ee4febd74..7f5634ce8e88 100644 --- a/tools/include/uapi/drm/i915_drm.h +++ b/tools/include/uapi/drm/i915_drm.h | |||
@@ -318,6 +318,7 @@ typedef struct _drm_i915_sarea { | |||
318 | #define DRM_I915_PERF_OPEN 0x36 | 318 | #define DRM_I915_PERF_OPEN 0x36 |
319 | #define DRM_I915_PERF_ADD_CONFIG 0x37 | 319 | #define DRM_I915_PERF_ADD_CONFIG 0x37 |
320 | #define DRM_I915_PERF_REMOVE_CONFIG 0x38 | 320 | #define DRM_I915_PERF_REMOVE_CONFIG 0x38 |
321 | #define DRM_I915_QUERY 0x39 | ||
321 | 322 | ||
322 | #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) | 323 | #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) |
323 | #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) | 324 | #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) |
@@ -375,6 +376,7 @@ typedef struct _drm_i915_sarea { | |||
375 | #define DRM_IOCTL_I915_PERF_OPEN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param) | 376 | #define DRM_IOCTL_I915_PERF_OPEN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param) |
376 | #define DRM_IOCTL_I915_PERF_ADD_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config) | 377 | #define DRM_IOCTL_I915_PERF_ADD_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config) |
377 | #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64) | 378 | #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64) |
379 | #define DRM_IOCTL_I915_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query) | ||
378 | 380 | ||
379 | /* Allow drivers to submit batchbuffers directly to hardware, relying | 381 | /* Allow drivers to submit batchbuffers directly to hardware, relying |
380 | * on the security mechanisms provided by hardware. | 382 | * on the security mechanisms provided by hardware. |
@@ -1358,7 +1360,9 @@ struct drm_intel_overlay_attrs { | |||
1358 | * active on a given plane. | 1360 | * active on a given plane. |
1359 | */ | 1361 | */ |
1360 | 1362 | ||
1361 | #define I915_SET_COLORKEY_NONE (1<<0) /* disable color key matching */ | 1363 | #define I915_SET_COLORKEY_NONE (1<<0) /* Deprecated. Instead set |
1364 | * flags==0 to disable colorkeying. | ||
1365 | */ | ||
1362 | #define I915_SET_COLORKEY_DESTINATION (1<<1) | 1366 | #define I915_SET_COLORKEY_DESTINATION (1<<1) |
1363 | #define I915_SET_COLORKEY_SOURCE (1<<2) | 1367 | #define I915_SET_COLORKEY_SOURCE (1<<2) |
1364 | struct drm_intel_sprite_colorkey { | 1368 | struct drm_intel_sprite_colorkey { |
@@ -1604,15 +1608,115 @@ struct drm_i915_perf_oa_config { | |||
1604 | __u32 n_flex_regs; | 1608 | __u32 n_flex_regs; |
1605 | 1609 | ||
1606 | /* | 1610 | /* |
1607 | * These fields are pointers to tuples of u32 values (register | 1611 | * These fields are pointers to tuples of u32 values (register address, |
1608 | * address, value). For example the expected length of the buffer | 1612 | * value). For example the expected length of the buffer pointed by |
1609 | * pointed by mux_regs_ptr is (2 * sizeof(u32) * n_mux_regs). | 1613 | * mux_regs_ptr is (2 * sizeof(u32) * n_mux_regs). |
1610 | */ | 1614 | */ |
1611 | __u64 mux_regs_ptr; | 1615 | __u64 mux_regs_ptr; |
1612 | __u64 boolean_regs_ptr; | 1616 | __u64 boolean_regs_ptr; |
1613 | __u64 flex_regs_ptr; | 1617 | __u64 flex_regs_ptr; |
1614 | }; | 1618 | }; |
1615 | 1619 | ||
1620 | struct drm_i915_query_item { | ||
1621 | __u64 query_id; | ||
1622 | #define DRM_I915_QUERY_TOPOLOGY_INFO 1 | ||
1623 | |||
1624 | /* | ||
1625 | * When set to zero by userspace, this is filled with the size of the | ||
1626 | * data to be written at the data_ptr pointer. The kernel sets this | ||
1627 | * value to a negative value to signal an error on a particular query | ||
1628 | * item. | ||
1629 | */ | ||
1630 | __s32 length; | ||
1631 | |||
1632 | /* | ||
1633 | * Unused for now. Must be cleared to zero. | ||
1634 | */ | ||
1635 | __u32 flags; | ||
1636 | |||
1637 | /* | ||
1638 | * Data will be written at the location pointed by data_ptr when the | ||
1639 | * value of length matches the length of the data to be written by the | ||
1640 | * kernel. | ||
1641 | */ | ||
1642 | __u64 data_ptr; | ||
1643 | }; | ||
1644 | |||
1645 | struct drm_i915_query { | ||
1646 | __u32 num_items; | ||
1647 | |||
1648 | /* | ||
1649 | * Unused for now. Must be cleared to zero. | ||
1650 | */ | ||
1651 | __u32 flags; | ||
1652 | |||
1653 | /* | ||
1654 | * This points to an array of num_items drm_i915_query_item structures. | ||
1655 | */ | ||
1656 | __u64 items_ptr; | ||
1657 | }; | ||
1658 | |||
1659 | /* | ||
1660 | * Data written by the kernel with query DRM_I915_QUERY_TOPOLOGY_INFO : | ||
1661 | * | ||
1662 | * data: contains the 3 pieces of information : | ||
1663 | * | ||
1664 | * - the slice mask with one bit per slice telling whether a slice is | ||
1665 | * available. The availability of slice X can be queried with the following | ||
1666 | * formula : | ||
1667 | * | ||
1668 | * (data[X / 8] >> (X % 8)) & 1 | ||
1669 | * | ||
1670 | * - the subslice mask for each slice with one bit per subslice telling | ||
1671 | * whether a subslice is available. The availability of subslice Y in slice | ||
1672 | * X can be queried with the following formula : | ||
1673 | * | ||
1674 | * (data[subslice_offset + | ||
1675 | * X * subslice_stride + | ||
1676 | * Y / 8] >> (Y % 8)) & 1 | ||
1677 | * | ||
1678 | * - the EU mask for each subslice in each slice with one bit per EU telling | ||
1679 | * whether an EU is available. The availability of EU Z in subslice Y in | ||
1680 | * slice X can be queried with the following formula : | ||
1681 | * | ||
1682 | * (data[eu_offset + | ||
1683 | * (X * max_subslices + Y) * eu_stride + | ||
1684 | * Z / 8] >> (Z % 8)) & 1 | ||
1685 | */ | ||
1686 | struct drm_i915_query_topology_info { | ||
1687 | /* | ||
1688 | * Unused for now. Must be cleared to zero. | ||
1689 | */ | ||
1690 | __u16 flags; | ||
1691 | |||
1692 | __u16 max_slices; | ||
1693 | __u16 max_subslices; | ||
1694 | __u16 max_eus_per_subslice; | ||
1695 | |||
1696 | /* | ||
1697 | * Offset in data[] at which the subslice masks are stored. | ||
1698 | */ | ||
1699 | __u16 subslice_offset; | ||
1700 | |||
1701 | /* | ||
1702 | * Stride at which each of the subslice masks for each slice are | ||
1703 | * stored. | ||
1704 | */ | ||
1705 | __u16 subslice_stride; | ||
1706 | |||
1707 | /* | ||
1708 | * Offset in data[] at which the EU masks are stored. | ||
1709 | */ | ||
1710 | __u16 eu_offset; | ||
1711 | |||
1712 | /* | ||
1713 | * Stride at which each of the EU masks for each subslice are stored. | ||
1714 | */ | ||
1715 | __u16 eu_stride; | ||
1716 | |||
1717 | __u8 data[]; | ||
1718 | }; | ||
1719 | |||
1616 | #if defined(__cplusplus) | 1720 | #if defined(__cplusplus) |
1617 | } | 1721 | } |
1618 | #endif | 1722 | #endif |
diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 7b26d4b0b052..6b89f87db200 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h | |||
@@ -925,7 +925,7 @@ struct kvm_ppc_resize_hpt { | |||
925 | #define KVM_CAP_S390_GS 140 | 925 | #define KVM_CAP_S390_GS 140 |
926 | #define KVM_CAP_S390_AIS 141 | 926 | #define KVM_CAP_S390_AIS 141 |
927 | #define KVM_CAP_SPAPR_TCE_VFIO 142 | 927 | #define KVM_CAP_SPAPR_TCE_VFIO 142 |
928 | #define KVM_CAP_X86_GUEST_MWAIT 143 | 928 | #define KVM_CAP_X86_DISABLE_EXITS 143 |
929 | #define KVM_CAP_ARM_USER_IRQ 144 | 929 | #define KVM_CAP_ARM_USER_IRQ 144 |
930 | #define KVM_CAP_S390_CMMA_MIGRATION 145 | 930 | #define KVM_CAP_S390_CMMA_MIGRATION 145 |
931 | #define KVM_CAP_PPC_FWNMI 146 | 931 | #define KVM_CAP_PPC_FWNMI 146 |
diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 5898c22ba310..56c4b3f8a01b 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat | |||
@@ -1121,9 +1121,6 @@ class Tui(object): | |||
1121 | self.screen.refresh() | 1121 | self.screen.refresh() |
1122 | 1122 | ||
1123 | def _refresh_body(self, sleeptime): | 1123 | def _refresh_body(self, sleeptime): |
1124 | def is_child_field(field): | ||
1125 | return field.find('(') != -1 | ||
1126 | |||
1127 | def insert_child(sorted_items, child, values, parent): | 1124 | def insert_child(sorted_items, child, values, parent): |
1128 | num = len(sorted_items) | 1125 | num = len(sorted_items) |
1129 | for i in range(0, num): | 1126 | for i in range(0, num): |
@@ -1134,12 +1131,14 @@ class Tui(object): | |||
1134 | def get_sorted_events(self, stats): | 1131 | def get_sorted_events(self, stats): |
1135 | """ separate parent and child events """ | 1132 | """ separate parent and child events """ |
1136 | if self._sorting == SORT_DEFAULT: | 1133 | if self._sorting == SORT_DEFAULT: |
1137 | def sortkey((_k, v)): | 1134 | def sortkey(pair): |
1138 | # sort by (delta value, overall value) | 1135 | # sort by (delta value, overall value) |
1136 | v = pair[1] | ||
1139 | return (v.delta, v.value) | 1137 | return (v.delta, v.value) |
1140 | else: | 1138 | else: |
1141 | def sortkey((_k, v)): | 1139 | def sortkey(pair): |
1142 | # sort by overall value | 1140 | # sort by overall value |
1141 | v = pair[1] | ||
1143 | return v.value | 1142 | return v.value |
1144 | 1143 | ||
1145 | childs = [] | 1144 | childs = [] |
@@ -1613,7 +1612,7 @@ def assign_globals(): | |||
1613 | global PATH_DEBUGFS_TRACING | 1612 | global PATH_DEBUGFS_TRACING |
1614 | 1613 | ||
1615 | debugfs = '' | 1614 | debugfs = '' |
1616 | for line in file('/proc/mounts'): | 1615 | for line in open('/proc/mounts'): |
1617 | if line.split(' ')[0] == 'debugfs': | 1616 | if line.split(' ')[0] == 'debugfs': |
1618 | debugfs = line.split(' ')[1] | 1617 | debugfs = line.split(' ')[1] |
1619 | break | 1618 | break |
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index e6acc281dd37..8ae824dbfca3 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile | |||
@@ -35,7 +35,7 @@ CFLAGS += -Wall -Werror $(WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) | |||
35 | LDFLAGS += -lelf $(LIBSUBCMD) | 35 | LDFLAGS += -lelf $(LIBSUBCMD) |
36 | 36 | ||
37 | # Allow old libelf to be used: | 37 | # Allow old libelf to be used: |
38 | elfshdr := $(shell echo '\#include <libelf.h>' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr) | 38 | elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr) |
39 | CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) | 39 | CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) |
40 | 40 | ||
41 | AWK = awk | 41 | AWK = awk |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index e1a660e60849..917e36fde6d8 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -80,6 +80,7 @@ OPTIONS | |||
80 | - comm: command (name) of the task which can be read via /proc/<pid>/comm | 80 | - comm: command (name) of the task which can be read via /proc/<pid>/comm |
81 | - pid: command and tid of the task | 81 | - pid: command and tid of the task |
82 | - dso: name of library or module executed at the time of sample | 82 | - dso: name of library or module executed at the time of sample |
83 | - dso_size: size of library or module executed at the time of sample | ||
83 | - symbol: name of function executed at the time of sample | 84 | - symbol: name of function executed at the time of sample |
84 | - symbol_size: size of function executed at the time of sample | 85 | - symbol_size: size of function executed at the time of sample |
85 | - parent: name of function matched to the parent regex filter. Unmatched | 86 | - parent: name of function matched to the parent regex filter. Unmatched |
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index 5a7035c5c523..115db9e06ecd 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
@@ -117,6 +117,9 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. | |||
117 | --sched:: | 117 | --sched:: |
118 | Accrue thread runtime and provide a summary at the end of the session. | 118 | Accrue thread runtime and provide a summary at the end of the session. |
119 | 119 | ||
120 | --failure:: | ||
121 | Show only syscalls that failed, i.e. that returned < 0. | ||
122 | |||
120 | -i:: | 123 | -i:: |
121 | --input:: | 124 | --input:: |
122 | Process events from a given perf data file. | 125 | Process events from a given perf data file. |
diff --git a/tools/perf/Documentation/perf-version.txt b/tools/perf/Documentation/perf-version.txt new file mode 100644 index 000000000000..e207b7cfca26 --- /dev/null +++ b/tools/perf/Documentation/perf-version.txt | |||
@@ -0,0 +1,24 @@ | |||
1 | perf-version(1) | ||
2 | =============== | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | perf-version - display the version of perf binary | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | 'perf version' [--build-options] | ||
11 | |||
12 | DESCRIPTION | ||
13 | ----------- | ||
14 | With no options given, the 'perf version' prints the perf version | ||
15 | on the standard output. | ||
16 | |||
17 | If the option '--build-options' is given, then the status of | ||
18 | compiled-in libraries are printed on the standard output. | ||
19 | |||
20 | OPTIONS | ||
21 | ------- | ||
22 | --build-options:: | ||
23 | Prints the status of compiled-in libraries on the | ||
24 | standard output. | ||
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 98ff73648b51..c7abd83a8e19 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config | |||
@@ -346,12 +346,16 @@ else | |||
346 | ifneq ($(feature-dwarf_getlocations), 1) | 346 | ifneq ($(feature-dwarf_getlocations), 1) |
347 | msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157); | 347 | msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157); |
348 | else | 348 | else |
349 | CFLAGS += -DHAVE_DWARF_GETLOCATIONS | 349 | CFLAGS += -DHAVE_DWARF_GETLOCATIONS_SUPPORT |
350 | endif # dwarf_getlocations | 350 | endif # dwarf_getlocations |
351 | endif # Dwarf support | 351 | endif # Dwarf support |
352 | endif # libelf support | 352 | endif # libelf support |
353 | endif # NO_LIBELF | 353 | endif # NO_LIBELF |
354 | 354 | ||
355 | ifeq ($(feature-glibc), 1) | ||
356 | CFLAGS += -DHAVE_GLIBC_SUPPORT | ||
357 | endif | ||
358 | |||
355 | ifdef NO_DWARF | 359 | ifdef NO_DWARF |
356 | NO_LIBDW_DWARF_UNWIND := 1 | 360 | NO_LIBDW_DWARF_UNWIND := 1 |
357 | endif | 361 | endif |
@@ -635,6 +639,7 @@ else | |||
635 | else | 639 | else |
636 | LDFLAGS += $(PERL_EMBED_LDFLAGS) | 640 | LDFLAGS += $(PERL_EMBED_LDFLAGS) |
637 | EXTLIBS += $(PERL_EMBED_LIBADD) | 641 | EXTLIBS += $(PERL_EMBED_LIBADD) |
642 | CFLAGS += -DHAVE_LIBPERL_SUPPORT | ||
638 | $(call detected,CONFIG_LIBPERL) | 643 | $(call detected,CONFIG_LIBPERL) |
639 | endif | 644 | endif |
640 | endif | 645 | endif |
@@ -671,6 +676,7 @@ else | |||
671 | LDFLAGS += $(PYTHON_EMBED_LDFLAGS) | 676 | LDFLAGS += $(PYTHON_EMBED_LDFLAGS) |
672 | EXTLIBS += $(PYTHON_EMBED_LIBADD) | 677 | EXTLIBS += $(PYTHON_EMBED_LIBADD) |
673 | LANG_BINDINGS += $(obj-perf)python/perf.so | 678 | LANG_BINDINGS += $(obj-perf)python/perf.so |
679 | CFLAGS += -DHAVE_LIBPYTHON_SUPPORT | ||
674 | $(call detected,CONFIG_LIBPYTHON) | 680 | $(call detected,CONFIG_LIBPYTHON) |
675 | endif | 681 | endif |
676 | endif | 682 | endif |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index f7517e1b73f8..83e453de36f8 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -364,7 +364,8 @@ LIBS = -Wl,--whole-archive $(PERFLIBS) $(EXTRA_PERFLIBS) -Wl,--no-whole-archive | |||
364 | 364 | ||
365 | ifeq ($(USE_CLANG), 1) | 365 | ifeq ($(USE_CLANG), 1) |
366 | CLANGLIBS_LIST = AST Basic CodeGen Driver Frontend Lex Tooling Edit Sema Analysis Parse Serialization | 366 | CLANGLIBS_LIST = AST Basic CodeGen Driver Frontend Lex Tooling Edit Sema Analysis Parse Serialization |
367 | LIBCLANG = $(foreach l,$(CLANGLIBS_LIST),$(wildcard $(shell $(LLVM_CONFIG) --libdir)/libclang$(l).a)) | 367 | CLANGLIBS_NOEXT_LIST = $(foreach l,$(CLANGLIBS_LIST),$(shell $(LLVM_CONFIG) --libdir)/libclang$(l)) |
368 | LIBCLANG = $(foreach l,$(CLANGLIBS_NOEXT_LIST),$(wildcard $(l).a $(l).so)) | ||
368 | LIBS += -Wl,--start-group $(LIBCLANG) -Wl,--end-group | 369 | LIBS += -Wl,--start-group $(LIBCLANG) -Wl,--end-group |
369 | endif | 370 | endif |
370 | 371 | ||
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 87b95c9410b4..3ad17ee89403 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -112,6 +112,7 @@ struct trace { | |||
112 | bool multiple_threads; | 112 | bool multiple_threads; |
113 | bool summary; | 113 | bool summary; |
114 | bool summary_only; | 114 | bool summary_only; |
115 | bool failure_only; | ||
115 | bool show_comm; | 116 | bool show_comm; |
116 | bool print_sample; | 117 | bool print_sample; |
117 | bool show_tool_stats; | 118 | bool show_tool_stats; |
@@ -1565,7 +1566,7 @@ static int trace__printf_interrupted_entry(struct trace *trace) | |||
1565 | struct thread_trace *ttrace; | 1566 | struct thread_trace *ttrace; |
1566 | size_t printed; | 1567 | size_t printed; |
1567 | 1568 | ||
1568 | if (trace->current == NULL) | 1569 | if (trace->failure_only || trace->current == NULL) |
1569 | return 0; | 1570 | return 0; |
1570 | 1571 | ||
1571 | ttrace = thread__priv(trace->current); | 1572 | ttrace = thread__priv(trace->current); |
@@ -1638,7 +1639,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, | |||
1638 | args, trace, thread); | 1639 | args, trace, thread); |
1639 | 1640 | ||
1640 | if (sc->is_exit) { | 1641 | if (sc->is_exit) { |
1641 | if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) { | 1642 | if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) { |
1642 | trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output); | 1643 | trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output); |
1643 | fprintf(trace->output, "%-70s)\n", ttrace->entry_str); | 1644 | fprintf(trace->output, "%-70s)\n", ttrace->entry_str); |
1644 | } | 1645 | } |
@@ -1742,7 +1743,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | |||
1742 | } | 1743 | } |
1743 | } | 1744 | } |
1744 | 1745 | ||
1745 | if (trace->summary_only) | 1746 | if (trace->summary_only || (ret >= 0 && trace->failure_only)) |
1746 | goto out; | 1747 | goto out; |
1747 | 1748 | ||
1748 | trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output); | 1749 | trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output); |
@@ -1961,7 +1962,7 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, | |||
1961 | trace->output); | 1962 | trace->output); |
1962 | } | 1963 | } |
1963 | 1964 | ||
1964 | fprintf(trace->output, ")\n"); | 1965 | fprintf(trace->output, "\n"); |
1965 | 1966 | ||
1966 | if (callchain_ret > 0) | 1967 | if (callchain_ret > 0) |
1967 | trace__fprintf_callchain(trace, sample); | 1968 | trace__fprintf_callchain(trace, sample); |
@@ -3087,6 +3088,8 @@ int cmd_trace(int argc, const char **argv) | |||
3087 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), | 3088 | OPT_INCR('v', "verbose", &verbose, "be more verbose"), |
3088 | OPT_BOOLEAN('T', "time", &trace.full_time, | 3089 | OPT_BOOLEAN('T', "time", &trace.full_time, |
3089 | "Show full timestamp, not time relative to first start"), | 3090 | "Show full timestamp, not time relative to first start"), |
3091 | OPT_BOOLEAN(0, "failure", &trace.failure_only, | ||
3092 | "Show only syscalls that failed"), | ||
3090 | OPT_BOOLEAN('s', "summary", &trace.summary_only, | 3093 | OPT_BOOLEAN('s', "summary", &trace.summary_only, |
3091 | "Show only syscall summary with statistics"), | 3094 | "Show only syscall summary with statistics"), |
3092 | OPT_BOOLEAN('S', "with-summary", &trace.summary, | 3095 | OPT_BOOLEAN('S', "with-summary", &trace.summary, |
diff --git a/tools/perf/builtin-version.c b/tools/perf/builtin-version.c index 37019c5d675f..2abe3910d6b6 100644 --- a/tools/perf/builtin-version.c +++ b/tools/perf/builtin-version.c | |||
@@ -1,11 +1,91 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include "builtin.h" | 2 | #include "builtin.h" |
3 | #include "perf.h" | 3 | #include "perf.h" |
4 | #include "color.h" | ||
4 | #include <linux/compiler.h> | 5 | #include <linux/compiler.h> |
6 | #include <tools/config.h> | ||
5 | #include <stdio.h> | 7 | #include <stdio.h> |
8 | #include <string.h> | ||
9 | #include <subcmd/parse-options.h> | ||
6 | 10 | ||
7 | int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused) | 11 | int version_verbose; |
12 | |||
13 | struct version { | ||
14 | bool build_options; | ||
15 | }; | ||
16 | |||
17 | static struct version version; | ||
18 | |||
19 | static struct option version_options[] = { | ||
20 | OPT_BOOLEAN(0, "build-options", &version.build_options, | ||
21 | "display the build options"), | ||
22 | }; | ||
23 | |||
24 | static const char * const version_usage[] = { | ||
25 | "perf version [<options>]", | ||
26 | NULL | ||
27 | }; | ||
28 | |||
29 | static void on_off_print(const char *status) | ||
30 | { | ||
31 | printf("[ "); | ||
32 | |||
33 | if (!strcmp(status, "OFF")) | ||
34 | color_fprintf(stdout, PERF_COLOR_RED, "%-3s", status); | ||
35 | else | ||
36 | color_fprintf(stdout, PERF_COLOR_GREEN, "%-3s", status); | ||
37 | |||
38 | printf(" ]"); | ||
39 | } | ||
40 | |||
41 | static void status_print(const char *name, const char *macro, | ||
42 | const char *status) | ||
8 | { | 43 | { |
44 | printf("%22s: ", name); | ||
45 | on_off_print(status); | ||
46 | printf(" # %s\n", macro); | ||
47 | } | ||
48 | |||
49 | #define STATUS(__d, __m) \ | ||
50 | do { \ | ||
51 | if (IS_BUILTIN(__d)) \ | ||
52 | status_print(#__m, #__d, "on"); \ | ||
53 | else \ | ||
54 | status_print(#__m, #__d, "OFF"); \ | ||
55 | } while (0) | ||
56 | |||
57 | static void library_status(void) | ||
58 | { | ||
59 | STATUS(HAVE_DWARF_SUPPORT, dwarf); | ||
60 | STATUS(HAVE_DWARF_GETLOCATIONS_SUPPORT, dwarf_getlocations); | ||
61 | STATUS(HAVE_GLIBC_SUPPORT, glibc); | ||
62 | STATUS(HAVE_GTK2_SUPPORT, gtk2); | ||
63 | STATUS(HAVE_LIBAUDIT_SUPPORT, libaudit); | ||
64 | STATUS(HAVE_LIBBFD_SUPPORT, libbfd); | ||
65 | STATUS(HAVE_LIBELF_SUPPORT, libelf); | ||
66 | STATUS(HAVE_LIBNUMA_SUPPORT, libnuma); | ||
67 | STATUS(HAVE_LIBNUMA_SUPPORT, numa_num_possible_cpus); | ||
68 | STATUS(HAVE_LIBPERL_SUPPORT, libperl); | ||
69 | STATUS(HAVE_LIBPYTHON_SUPPORT, libpython); | ||
70 | STATUS(HAVE_SLANG_SUPPORT, libslang); | ||
71 | STATUS(HAVE_LIBCRYPTO_SUPPORT, libcrypto); | ||
72 | STATUS(HAVE_LIBUNWIND_SUPPORT, libunwind); | ||
73 | STATUS(HAVE_DWARF_SUPPORT, libdw-dwarf-unwind); | ||
74 | STATUS(HAVE_ZLIB_SUPPORT, zlib); | ||
75 | STATUS(HAVE_LZMA_SUPPORT, lzma); | ||
76 | STATUS(HAVE_AUXTRACE_SUPPORT, get_cpuid); | ||
77 | STATUS(HAVE_LIBBPF_SUPPORT, bpf); | ||
78 | } | ||
79 | |||
80 | int cmd_version(int argc, const char **argv) | ||
81 | { | ||
82 | argc = parse_options(argc, argv, version_options, version_usage, | ||
83 | PARSE_OPT_STOP_AT_NON_OPTION); | ||
84 | |||
9 | printf("perf version %s\n", perf_version_string); | 85 | printf("perf version %s\n", perf_version_string); |
86 | |||
87 | if (version.build_options || version_verbose == 1) | ||
88 | library_status(); | ||
89 | |||
10 | return 0; | 90 | return 0; |
11 | } | 91 | } |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 1b3fc8ec0fa2..1659029d03fc 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -190,6 +190,12 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) | |||
190 | break; | 190 | break; |
191 | } | 191 | } |
192 | 192 | ||
193 | if (!strcmp(cmd, "-vv")) { | ||
194 | (*argv)[0] = "version"; | ||
195 | version_verbose = 1; | ||
196 | break; | ||
197 | } | ||
198 | |||
193 | /* | 199 | /* |
194 | * Check remaining flags. | 200 | * Check remaining flags. |
195 | */ | 201 | */ |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 8fec1abd0f1f..a1a97956136f 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -84,6 +84,7 @@ struct record_opts { | |||
84 | struct option; | 84 | struct option; |
85 | extern const char * const *record_usage; | 85 | extern const char * const *record_usage; |
86 | extern struct option *record_options; | 86 | extern struct option *record_options; |
87 | extern int version_verbose; | ||
87 | 88 | ||
88 | int record__parse_freq(const struct option *opt, const char *str, int unset); | 89 | int record__parse_freq(const struct option *opt, const char *str, int unset); |
89 | #endif | 90 | #endif |
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index 9f6ce29b83b4..4f75561424ed 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c | |||
@@ -45,11 +45,16 @@ void ui_browser__set_percent_color(struct ui_browser *browser, | |||
45 | ui_browser__set_color(browser, color); | 45 | ui_browser__set_color(browser, color); |
46 | } | 46 | } |
47 | 47 | ||
48 | void ui_browser__gotorc(struct ui_browser *browser, int y, int x) | 48 | void ui_browser__gotorc_title(struct ui_browser *browser, int y, int x) |
49 | { | 49 | { |
50 | SLsmg_gotorc(browser->y + y, browser->x + x); | 50 | SLsmg_gotorc(browser->y + y, browser->x + x); |
51 | } | 51 | } |
52 | 52 | ||
53 | void ui_browser__gotorc(struct ui_browser *browser, int y, int x) | ||
54 | { | ||
55 | SLsmg_gotorc(browser->y + y + browser->extra_title_lines, browser->x + x); | ||
56 | } | ||
57 | |||
53 | void ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const char *msg, | 58 | void ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const char *msg, |
54 | unsigned int width) | 59 | unsigned int width) |
55 | { | 60 | { |
@@ -191,6 +196,7 @@ void ui_browser__refresh_dimensions(struct ui_browser *browser) | |||
191 | { | 196 | { |
192 | browser->width = SLtt_Screen_Cols - 1; | 197 | browser->width = SLtt_Screen_Cols - 1; |
193 | browser->height = browser->rows = SLtt_Screen_Rows - 2; | 198 | browser->height = browser->rows = SLtt_Screen_Rows - 2; |
199 | browser->rows -= browser->extra_title_lines; | ||
194 | browser->y = 1; | 200 | browser->y = 1; |
195 | browser->x = 0; | 201 | browser->x = 0; |
196 | } | 202 | } |
@@ -337,8 +343,8 @@ static int __ui_browser__refresh(struct ui_browser *browser) | |||
337 | else | 343 | else |
338 | width += 1; | 344 | width += 1; |
339 | 345 | ||
340 | SLsmg_fill_region(browser->y + row, browser->x, | 346 | SLsmg_fill_region(browser->y + row + browser->extra_title_lines, browser->x, |
341 | browser->height - row, width, ' '); | 347 | browser->rows - row, width, ' '); |
342 | 348 | ||
343 | return 0; | 349 | return 0; |
344 | } | 350 | } |
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h index 70057178ee34..aa5932e1d62e 100644 --- a/tools/perf/ui/browser.h +++ b/tools/perf/ui/browser.h | |||
@@ -17,6 +17,7 @@ struct ui_browser { | |||
17 | u64 index, top_idx; | 17 | u64 index, top_idx; |
18 | void *top, *entries; | 18 | void *top, *entries; |
19 | u16 y, x, width, height, rows, columns, horiz_scroll; | 19 | u16 y, x, width, height, rows, columns, horiz_scroll; |
20 | u8 extra_title_lines; | ||
20 | int current_color; | 21 | int current_color; |
21 | void *priv; | 22 | void *priv; |
22 | const char *title; | 23 | const char *title; |
@@ -38,6 +39,7 @@ bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row); | |||
38 | void ui_browser__refresh_dimensions(struct ui_browser *browser); | 39 | void ui_browser__refresh_dimensions(struct ui_browser *browser); |
39 | void ui_browser__reset_index(struct ui_browser *browser); | 40 | void ui_browser__reset_index(struct ui_browser *browser); |
40 | 41 | ||
42 | void ui_browser__gotorc_title(struct ui_browser *browser, int y, int x); | ||
41 | void ui_browser__gotorc(struct ui_browser *browser, int y, int x); | 43 | void ui_browser__gotorc(struct ui_browser *browser, int y, int x); |
42 | void ui_browser__write_nstring(struct ui_browser *browser, const char *msg, | 44 | void ui_browser__write_nstring(struct ui_browser *browser, const char *msg, |
43 | unsigned int width); | 45 | unsigned int width); |
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index c02fb437ac8e..12c099a87f8b 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -218,7 +218,7 @@ static unsigned int annotate_browser__refresh(struct ui_browser *browser) | |||
218 | annotate_browser__draw_current_jump(browser); | 218 | annotate_browser__draw_current_jump(browser); |
219 | 219 | ||
220 | ui_browser__set_color(browser, HE_COLORSET_NORMAL); | 220 | ui_browser__set_color(browser, HE_COLORSET_NORMAL); |
221 | __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1); | 221 | __ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1); |
222 | return ret; | 222 | return ret; |
223 | } | 223 | } |
224 | 224 | ||
@@ -592,21 +592,40 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, | |||
592 | return __annotate_browser__search_reverse(browser); | 592 | return __annotate_browser__search_reverse(browser); |
593 | } | 593 | } |
594 | 594 | ||
595 | static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help) | ||
596 | { | ||
597 | struct map_symbol *ms = browser->priv; | ||
598 | struct symbol *sym = ms->sym; | ||
599 | char symbol_dso[SYM_TITLE_MAX_SIZE]; | ||
600 | |||
601 | if (ui_browser__show(browser, title, help) < 0) | ||
602 | return -1; | ||
603 | |||
604 | sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso)); | ||
605 | |||
606 | ui_browser__gotorc_title(browser, 0, 0); | ||
607 | ui_browser__set_color(browser, HE_COLORSET_ROOT); | ||
608 | ui_browser__write_nstring(browser, symbol_dso, browser->width + 1); | ||
609 | return 0; | ||
610 | } | ||
611 | |||
595 | static int annotate_browser__run(struct annotate_browser *browser, | 612 | static int annotate_browser__run(struct annotate_browser *browser, |
596 | struct perf_evsel *evsel, | 613 | struct perf_evsel *evsel, |
597 | struct hist_browser_timer *hbt) | 614 | struct hist_browser_timer *hbt) |
598 | { | 615 | { |
599 | struct rb_node *nd = NULL; | 616 | struct rb_node *nd = NULL; |
617 | struct hists *hists = evsel__hists(evsel); | ||
600 | struct map_symbol *ms = browser->b.priv; | 618 | struct map_symbol *ms = browser->b.priv; |
601 | struct symbol *sym = ms->sym; | 619 | struct symbol *sym = ms->sym; |
602 | struct annotation *notes = symbol__annotation(ms->sym); | 620 | struct annotation *notes = symbol__annotation(ms->sym); |
603 | const char *help = "Press 'h' for help on key bindings"; | 621 | const char *help = "Press 'h' for help on key bindings"; |
604 | int delay_secs = hbt ? hbt->refresh : 0; | 622 | int delay_secs = hbt ? hbt->refresh : 0; |
623 | char title[256]; | ||
605 | int key; | 624 | int key; |
606 | char title[SYM_TITLE_MAX_SIZE]; | ||
607 | 625 | ||
608 | sym_title(sym, ms->map, title, sizeof(title)); | 626 | annotation__scnprintf_samples_period(notes, title, sizeof(title), evsel); |
609 | if (ui_browser__show(&browser->b, title, help) < 0) | 627 | |
628 | if (annotate_browser__show(&browser->b, title, help) < 0) | ||
610 | return -1; | 629 | return -1; |
611 | 630 | ||
612 | annotate_browser__calc_percent(browser, evsel); | 631 | annotate_browser__calc_percent(browser, evsel); |
@@ -637,8 +656,11 @@ static int annotate_browser__run(struct annotate_browser *browser, | |||
637 | if (hbt) | 656 | if (hbt) |
638 | hbt->timer(hbt->arg); | 657 | hbt->timer(hbt->arg); |
639 | 658 | ||
640 | if (delay_secs != 0) | 659 | if (delay_secs != 0) { |
641 | symbol__annotate_decay_histogram(sym, evsel->idx); | 660 | symbol__annotate_decay_histogram(sym, evsel->idx); |
661 | hists__scnprintf_title(hists, title, sizeof(title)); | ||
662 | annotate_browser__show(&browser->b, title, help); | ||
663 | } | ||
642 | continue; | 664 | continue; |
643 | case K_TAB: | 665 | case K_TAB: |
644 | if (nd != NULL) { | 666 | if (nd != NULL) { |
@@ -812,6 +834,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, | |||
812 | .seek = ui_browser__list_head_seek, | 834 | .seek = ui_browser__list_head_seek, |
813 | .write = annotate_browser__write, | 835 | .write = annotate_browser__write, |
814 | .filter = disasm_line__filter, | 836 | .filter = disasm_line__filter, |
837 | .extra_title_lines = 1, /* for hists__scnprintf_title() */ | ||
815 | .priv = &ms, | 838 | .priv = &ms, |
816 | .use_navkeypressed = true, | 839 | .use_navkeypressed = true, |
817 | }, | 840 | }, |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 8b4e82548f8e..0eec06c105c6 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -32,8 +32,7 @@ | |||
32 | 32 | ||
33 | extern void hist_browser__init_hpp(void); | 33 | extern void hist_browser__init_hpp(void); |
34 | 34 | ||
35 | static int perf_evsel_browser_title(struct hist_browser *browser, | 35 | static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size); |
36 | char *bf, size_t size); | ||
37 | static void hist_browser__update_nr_entries(struct hist_browser *hb); | 36 | static void hist_browser__update_nr_entries(struct hist_browser *hb); |
38 | 37 | ||
39 | static struct rb_node *hists__filter_entries(struct rb_node *nd, | 38 | static struct rb_node *hists__filter_entries(struct rb_node *nd, |
@@ -62,6 +61,15 @@ static int hist_browser__get_folding(struct hist_browser *browser) | |||
62 | return unfolded_rows; | 61 | return unfolded_rows; |
63 | } | 62 | } |
64 | 63 | ||
64 | static void hist_browser__set_title_space(struct hist_browser *hb) | ||
65 | { | ||
66 | struct ui_browser *browser = &hb->b; | ||
67 | struct hists *hists = hb->hists; | ||
68 | struct perf_hpp_list *hpp_list = hists->hpp_list; | ||
69 | |||
70 | browser->extra_title_lines = hb->show_headers ? hpp_list->nr_header_lines : 0; | ||
71 | } | ||
72 | |||
65 | static u32 hist_browser__nr_entries(struct hist_browser *hb) | 73 | static u32 hist_browser__nr_entries(struct hist_browser *hb) |
66 | { | 74 | { |
67 | u32 nr_entries; | 75 | u32 nr_entries; |
@@ -82,10 +90,16 @@ static void hist_browser__update_rows(struct hist_browser *hb) | |||
82 | struct ui_browser *browser = &hb->b; | 90 | struct ui_browser *browser = &hb->b; |
83 | struct hists *hists = hb->hists; | 91 | struct hists *hists = hb->hists; |
84 | struct perf_hpp_list *hpp_list = hists->hpp_list; | 92 | struct perf_hpp_list *hpp_list = hists->hpp_list; |
85 | u16 header_offset, index_row; | 93 | u16 index_row; |
86 | 94 | ||
87 | header_offset = hb->show_headers ? hpp_list->nr_header_lines : 0; | 95 | if (!hb->show_headers) { |
88 | browser->rows = browser->height - header_offset; | 96 | browser->rows += browser->extra_title_lines; |
97 | browser->extra_title_lines = 0; | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | browser->extra_title_lines = hpp_list->nr_header_lines; | ||
102 | browser->rows -= browser->extra_title_lines; | ||
89 | /* | 103 | /* |
90 | * Verify if we were at the last line and that line isn't | 104 | * Verify if we were at the last line and that line isn't |
91 | * visibe because we now show the header line(s). | 105 | * visibe because we now show the header line(s). |
@@ -108,17 +122,6 @@ static void hist_browser__refresh_dimensions(struct ui_browser *browser) | |||
108 | * changeset. | 122 | * changeset. |
109 | */ | 123 | */ |
110 | ui_browser__refresh_dimensions(browser); | 124 | ui_browser__refresh_dimensions(browser); |
111 | hist_browser__update_rows(hb); | ||
112 | } | ||
113 | |||
114 | static void hist_browser__gotorc(struct hist_browser *browser, int row, int column) | ||
115 | { | ||
116 | struct hists *hists = browser->hists; | ||
117 | struct perf_hpp_list *hpp_list = hists->hpp_list; | ||
118 | u16 header_offset; | ||
119 | |||
120 | header_offset = browser->show_headers ? hpp_list->nr_header_lines : 0; | ||
121 | ui_browser__gotorc(&browser->b, row + header_offset, column); | ||
122 | } | 125 | } |
123 | 126 | ||
124 | static void hist_browser__reset(struct hist_browser *browser) | 127 | static void hist_browser__reset(struct hist_browser *browser) |
@@ -656,9 +659,10 @@ int hist_browser__run(struct hist_browser *browser, const char *help, | |||
656 | struct hist_entry *h = rb_entry(browser->b.top, | 659 | struct hist_entry *h = rb_entry(browser->b.top, |
657 | struct hist_entry, rb_node); | 660 | struct hist_entry, rb_node); |
658 | ui_helpline__pop(); | 661 | ui_helpline__pop(); |
659 | ui_helpline__fpush("%d: nr_ent=(%d,%d), rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", | 662 | ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", |
660 | seq++, browser->b.nr_entries, | 663 | seq++, browser->b.nr_entries, |
661 | browser->hists->nr_entries, | 664 | browser->hists->nr_entries, |
665 | browser->b.extra_title_lines, | ||
662 | browser->b.rows, | 666 | browser->b.rows, |
663 | browser->b.index, | 667 | browser->b.index, |
664 | browser->b.top_idx, | 668 | browser->b.top_idx, |
@@ -733,7 +737,7 @@ static void hist_browser__show_callchain_entry(struct hist_browser *browser, | |||
733 | } | 737 | } |
734 | 738 | ||
735 | ui_browser__set_color(&browser->b, color); | 739 | ui_browser__set_color(&browser->b, color); |
736 | hist_browser__gotorc(browser, row, 0); | 740 | ui_browser__gotorc(&browser->b, row, 0); |
737 | ui_browser__write_nstring(&browser->b, " ", offset); | 741 | ui_browser__write_nstring(&browser->b, " ", offset); |
738 | ui_browser__printf(&browser->b, "%c", folded_sign); | 742 | ui_browser__printf(&browser->b, "%c", folded_sign); |
739 | ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); | 743 | ui_browser__write_graph(&browser->b, show_annotated ? SLSMG_RARROW_CHAR : ' '); |
@@ -1249,7 +1253,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
1249 | }; | 1253 | }; |
1250 | int column = 0; | 1254 | int column = 0; |
1251 | 1255 | ||
1252 | hist_browser__gotorc(browser, row, 0); | 1256 | ui_browser__gotorc(&browser->b, row, 0); |
1253 | 1257 | ||
1254 | hists__for_each_format(browser->hists, fmt) { | 1258 | hists__for_each_format(browser->hists, fmt) { |
1255 | char s[2048]; | 1259 | char s[2048]; |
@@ -1358,7 +1362,7 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser, | |||
1358 | goto show_callchain; | 1362 | goto show_callchain; |
1359 | } | 1363 | } |
1360 | 1364 | ||
1361 | hist_browser__gotorc(browser, row, 0); | 1365 | ui_browser__gotorc(&browser->b, row, 0); |
1362 | 1366 | ||
1363 | if (current_entry && browser->b.navkeypressed) | 1367 | if (current_entry && browser->b.navkeypressed) |
1364 | ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); | 1368 | ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); |
@@ -1507,7 +1511,7 @@ static int hist_browser__show_no_entry(struct hist_browser *browser, | |||
1507 | browser->selection = NULL; | 1511 | browser->selection = NULL; |
1508 | } | 1512 | } |
1509 | 1513 | ||
1510 | hist_browser__gotorc(browser, row, 0); | 1514 | ui_browser__gotorc(&browser->b, row, 0); |
1511 | 1515 | ||
1512 | if (current_entry && browser->b.navkeypressed) | 1516 | if (current_entry && browser->b.navkeypressed) |
1513 | ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); | 1517 | ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED); |
@@ -1713,7 +1717,7 @@ static void hists_browser__headers(struct hist_browser *browser) | |||
1713 | hists_browser__scnprintf_headers(browser, headers, | 1717 | hists_browser__scnprintf_headers(browser, headers, |
1714 | sizeof(headers), line); | 1718 | sizeof(headers), line); |
1715 | 1719 | ||
1716 | ui_browser__gotorc(&browser->b, line, 0); | 1720 | ui_browser__gotorc_title(&browser->b, line, 0); |
1717 | ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); | 1721 | ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); |
1718 | ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); | 1722 | ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); |
1719 | } | 1723 | } |
@@ -1740,17 +1744,11 @@ static void ui_browser__hists_init_top(struct ui_browser *browser) | |||
1740 | static unsigned int hist_browser__refresh(struct ui_browser *browser) | 1744 | static unsigned int hist_browser__refresh(struct ui_browser *browser) |
1741 | { | 1745 | { |
1742 | unsigned row = 0; | 1746 | unsigned row = 0; |
1743 | u16 header_offset = 0; | ||
1744 | struct rb_node *nd; | 1747 | struct rb_node *nd; |
1745 | struct hist_browser *hb = container_of(browser, struct hist_browser, b); | 1748 | struct hist_browser *hb = container_of(browser, struct hist_browser, b); |
1746 | struct hists *hists = hb->hists; | ||
1747 | |||
1748 | if (hb->show_headers) { | ||
1749 | struct perf_hpp_list *hpp_list = hists->hpp_list; | ||
1750 | 1749 | ||
1750 | if (hb->show_headers) | ||
1751 | hist_browser__show_headers(hb); | 1751 | hist_browser__show_headers(hb); |
1752 | header_offset = hpp_list->nr_header_lines; | ||
1753 | } | ||
1754 | 1752 | ||
1755 | ui_browser__hists_init_top(browser); | 1753 | ui_browser__hists_init_top(browser); |
1756 | hb->he_selection = NULL; | 1754 | hb->he_selection = NULL; |
@@ -1788,7 +1786,7 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser) | |||
1788 | break; | 1786 | break; |
1789 | } | 1787 | } |
1790 | 1788 | ||
1791 | return row + header_offset; | 1789 | return row; |
1792 | } | 1790 | } |
1793 | 1791 | ||
1794 | static struct rb_node *hists__filter_entries(struct rb_node *nd, | 1792 | static struct rb_node *hists__filter_entries(struct rb_node *nd, |
@@ -2143,6 +2141,7 @@ void hist_browser__init(struct hist_browser *browser, | |||
2143 | browser->b.seek = ui_browser__hists_seek; | 2141 | browser->b.seek = ui_browser__hists_seek; |
2144 | browser->b.use_navkeypressed = true; | 2142 | browser->b.use_navkeypressed = true; |
2145 | browser->show_headers = symbol_conf.show_hist_headers; | 2143 | browser->show_headers = symbol_conf.show_hist_headers; |
2144 | hist_browser__set_title_space(browser); | ||
2146 | 2145 | ||
2147 | if (symbol_conf.report_hierarchy) { | 2146 | if (symbol_conf.report_hierarchy) { |
2148 | struct perf_hpp_list_node *fmt_node; | 2147 | struct perf_hpp_list_node *fmt_node; |
@@ -2183,7 +2182,7 @@ perf_evsel_browser__new(struct perf_evsel *evsel, | |||
2183 | if (browser) { | 2182 | if (browser) { |
2184 | browser->hbt = hbt; | 2183 | browser->hbt = hbt; |
2185 | browser->env = env; | 2184 | browser->env = env; |
2186 | browser->title = perf_evsel_browser_title; | 2185 | browser->title = hists_browser__scnprintf_title; |
2187 | } | 2186 | } |
2188 | return browser; | 2187 | return browser; |
2189 | } | 2188 | } |
@@ -2209,84 +2208,11 @@ static inline bool is_report_browser(void *timer) | |||
2209 | return timer == NULL; | 2208 | return timer == NULL; |
2210 | } | 2209 | } |
2211 | 2210 | ||
2212 | static int perf_evsel_browser_title(struct hist_browser *browser, | 2211 | static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf, size_t size) |
2213 | char *bf, size_t size) | ||
2214 | { | 2212 | { |
2215 | struct hist_browser_timer *hbt = browser->hbt; | 2213 | struct hist_browser_timer *hbt = browser->hbt; |
2216 | struct hists *hists = browser->hists; | 2214 | int printed = __hists__scnprintf_title(browser->hists, bf, size, !is_report_browser(hbt)); |
2217 | char unit; | ||
2218 | int printed; | ||
2219 | const struct dso *dso = hists->dso_filter; | ||
2220 | const struct thread *thread = hists->thread_filter; | ||
2221 | int socket_id = hists->socket_filter; | ||
2222 | unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; | ||
2223 | u64 nr_events = hists->stats.total_period; | ||
2224 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
2225 | const char *ev_name = perf_evsel__name(evsel); | ||
2226 | char buf[512], sample_freq_str[64] = ""; | ||
2227 | size_t buflen = sizeof(buf); | ||
2228 | char ref[30] = " show reference callgraph, "; | ||
2229 | bool enable_ref = false; | ||
2230 | 2215 | ||
2231 | if (symbol_conf.filter_relative) { | ||
2232 | nr_samples = hists->stats.nr_non_filtered_samples; | ||
2233 | nr_events = hists->stats.total_non_filtered_period; | ||
2234 | } | ||
2235 | |||
2236 | if (perf_evsel__is_group_event(evsel)) { | ||
2237 | struct perf_evsel *pos; | ||
2238 | |||
2239 | perf_evsel__group_desc(evsel, buf, buflen); | ||
2240 | ev_name = buf; | ||
2241 | |||
2242 | for_each_group_member(pos, evsel) { | ||
2243 | struct hists *pos_hists = evsel__hists(pos); | ||
2244 | |||
2245 | if (symbol_conf.filter_relative) { | ||
2246 | nr_samples += pos_hists->stats.nr_non_filtered_samples; | ||
2247 | nr_events += pos_hists->stats.total_non_filtered_period; | ||
2248 | } else { | ||
2249 | nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; | ||
2250 | nr_events += pos_hists->stats.total_period; | ||
2251 | } | ||
2252 | } | ||
2253 | } | ||
2254 | |||
2255 | if (symbol_conf.show_ref_callgraph && | ||
2256 | strstr(ev_name, "call-graph=no")) | ||
2257 | enable_ref = true; | ||
2258 | |||
2259 | if (!is_report_browser(hbt)) | ||
2260 | scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); | ||
2261 | |||
2262 | nr_samples = convert_unit(nr_samples, &unit); | ||
2263 | printed = scnprintf(bf, size, | ||
2264 | "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, | ||
2265 | nr_samples, unit, evsel->nr_members > 1 ? "s" : "", | ||
2266 | ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); | ||
2267 | |||
2268 | |||
2269 | if (hists->uid_filter_str) | ||
2270 | printed += snprintf(bf + printed, size - printed, | ||
2271 | ", UID: %s", hists->uid_filter_str); | ||
2272 | if (thread) { | ||
2273 | if (hists__has(hists, thread)) { | ||
2274 | printed += scnprintf(bf + printed, size - printed, | ||
2275 | ", Thread: %s(%d)", | ||
2276 | (thread->comm_set ? thread__comm_str(thread) : ""), | ||
2277 | thread->tid); | ||
2278 | } else { | ||
2279 | printed += scnprintf(bf + printed, size - printed, | ||
2280 | ", Thread: %s", | ||
2281 | (thread->comm_set ? thread__comm_str(thread) : "")); | ||
2282 | } | ||
2283 | } | ||
2284 | if (dso) | ||
2285 | printed += scnprintf(bf + printed, size - printed, | ||
2286 | ", DSO: %s", dso->short_name); | ||
2287 | if (socket_id > -1) | ||
2288 | printed += scnprintf(bf + printed, size - printed, | ||
2289 | ", Processor Socket: %d", socket_id); | ||
2290 | if (!is_report_browser(hbt)) { | 2216 | if (!is_report_browser(hbt)) { |
2291 | struct perf_top *top = hbt->arg; | 2217 | struct perf_top *top = hbt->arg; |
2292 | 2218 | ||
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 3a428d7c59b9..fbad8dfbb186 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "config.h" | 17 | #include "config.h" |
18 | #include "cache.h" | 18 | #include "cache.h" |
19 | #include "symbol.h" | 19 | #include "symbol.h" |
20 | #include "units.h" | ||
20 | #include "debug.h" | 21 | #include "debug.h" |
21 | #include "annotate.h" | 22 | #include "annotate.h" |
22 | #include "evsel.h" | 23 | #include "evsel.h" |
@@ -2324,7 +2325,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, | |||
2324 | struct dso *dso = map->dso; | 2325 | struct dso *dso = map->dso; |
2325 | struct rb_root source_line = RB_ROOT; | 2326 | struct rb_root source_line = RB_ROOT; |
2326 | struct annotation_options opts = annotation__default_options; | 2327 | struct annotation_options opts = annotation__default_options; |
2327 | const char *ev_name = perf_evsel__name(evsel); | 2328 | struct annotation *notes = symbol__annotation(sym); |
2328 | char buf[1024]; | 2329 | char buf[1024]; |
2329 | 2330 | ||
2330 | if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) | 2331 | if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) |
@@ -2336,12 +2337,8 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, | |||
2336 | print_summary(&source_line, dso->long_name); | 2337 | print_summary(&source_line, dso->long_name); |
2337 | } | 2338 | } |
2338 | 2339 | ||
2339 | if (perf_evsel__is_group_event(evsel)) { | 2340 | annotation__scnprintf_samples_period(notes, buf, sizeof(buf), evsel); |
2340 | perf_evsel__group_desc(evsel, buf, sizeof(buf)); | 2341 | fprintf(stdout, "%s\n%s() %s\n", buf, sym->name, dso->long_name); |
2341 | ev_name = buf; | ||
2342 | } | ||
2343 | |||
2344 | fprintf(stdout, "%s() %s\nEvent: %s\n\n", sym->name, dso->long_name, ev_name); | ||
2345 | symbol__annotate_fprintf2(sym, stdout); | 2342 | symbol__annotate_fprintf2(sym, stdout); |
2346 | 2343 | ||
2347 | annotated_source__purge(symbol__annotation(sym)->src); | 2344 | annotated_source__purge(symbol__annotation(sym)->src); |
@@ -2597,6 +2594,46 @@ out_free_offsets: | |||
2597 | return -1; | 2594 | return -1; |
2598 | } | 2595 | } |
2599 | 2596 | ||
2597 | int __annotation__scnprintf_samples_period(struct annotation *notes, | ||
2598 | char *bf, size_t size, | ||
2599 | struct perf_evsel *evsel, | ||
2600 | bool show_freq) | ||
2601 | { | ||
2602 | const char *ev_name = perf_evsel__name(evsel); | ||
2603 | char buf[1024], ref[30] = " show reference callgraph, "; | ||
2604 | char sample_freq_str[64] = ""; | ||
2605 | unsigned long nr_samples = 0; | ||
2606 | int nr_members = 1; | ||
2607 | bool enable_ref = false; | ||
2608 | u64 nr_events = 0; | ||
2609 | char unit; | ||
2610 | int i; | ||
2611 | |||
2612 | if (perf_evsel__is_group_event(evsel)) { | ||
2613 | perf_evsel__group_desc(evsel, buf, sizeof(buf)); | ||
2614 | ev_name = buf; | ||
2615 | nr_members = evsel->nr_members; | ||
2616 | } | ||
2617 | |||
2618 | for (i = 0; i < nr_members; i++) { | ||
2619 | struct sym_hist *ah = annotation__histogram(notes, evsel->idx + i); | ||
2620 | |||
2621 | nr_samples += ah->nr_samples; | ||
2622 | nr_events += ah->period; | ||
2623 | } | ||
2624 | |||
2625 | if (symbol_conf.show_ref_callgraph && strstr(ev_name, "call-graph=no")) | ||
2626 | enable_ref = true; | ||
2627 | |||
2628 | if (show_freq) | ||
2629 | scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); | ||
2630 | |||
2631 | nr_samples = convert_unit(nr_samples, &unit); | ||
2632 | return scnprintf(bf, size, "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, | ||
2633 | nr_samples, unit, evsel->nr_members > 1 ? "s" : "", | ||
2634 | ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); | ||
2635 | } | ||
2636 | |||
2600 | #define ANNOTATION__CFG(n) \ | 2637 | #define ANNOTATION__CFG(n) \ |
2601 | { .name = #n, .value = &annotation__default_options.n, } | 2638 | { .name = #n, .value = &annotation__default_options.n, } |
2602 | 2639 | ||
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index ff7e3df31efa..db8d09bea07e 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -151,6 +151,18 @@ double annotation_line__max_percent(struct annotation_line *al, struct annotatio | |||
151 | void annotation_line__write(struct annotation_line *al, struct annotation *notes, | 151 | void annotation_line__write(struct annotation_line *al, struct annotation *notes, |
152 | struct annotation_write_ops *ops); | 152 | struct annotation_write_ops *ops); |
153 | 153 | ||
154 | int __annotation__scnprintf_samples_period(struct annotation *notes, | ||
155 | char *bf, size_t size, | ||
156 | struct perf_evsel *evsel, | ||
157 | bool show_freq); | ||
158 | |||
159 | static inline int annotation__scnprintf_samples_period(struct annotation *notes, | ||
160 | char *bf, size_t size, | ||
161 | struct perf_evsel *evsel) | ||
162 | { | ||
163 | return __annotation__scnprintf_samples_period(notes, bf, size, evsel, true); | ||
164 | } | ||
165 | |||
154 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); | 166 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); |
155 | size_t disasm__fprintf(struct list_head *head, FILE *fp); | 167 | size_t disasm__fprintf(struct list_head *head, FILE *fp); |
156 | void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); | 168 | void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); |
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index fb357a00dd86..857de69a5361 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
@@ -302,13 +302,27 @@ static int auxtrace_queues__split_buffer(struct auxtrace_queues *queues, | |||
302 | return 0; | 302 | return 0; |
303 | } | 303 | } |
304 | 304 | ||
305 | static bool filter_cpu(struct perf_session *session, int cpu) | ||
306 | { | ||
307 | unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap; | ||
308 | |||
309 | return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap); | ||
310 | } | ||
311 | |||
305 | static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues, | 312 | static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues, |
306 | struct perf_session *session, | 313 | struct perf_session *session, |
307 | unsigned int idx, | 314 | unsigned int idx, |
308 | struct auxtrace_buffer *buffer, | 315 | struct auxtrace_buffer *buffer, |
309 | struct auxtrace_buffer **buffer_ptr) | 316 | struct auxtrace_buffer **buffer_ptr) |
310 | { | 317 | { |
311 | int err; | 318 | int err = -ENOMEM; |
319 | |||
320 | if (filter_cpu(session, buffer->cpu)) | ||
321 | return 0; | ||
322 | |||
323 | buffer = memdup(buffer, sizeof(*buffer)); | ||
324 | if (!buffer) | ||
325 | return -ENOMEM; | ||
312 | 326 | ||
313 | if (session->one_mmap) { | 327 | if (session->one_mmap) { |
314 | buffer->data = buffer->data_offset - session->one_mmap_offset + | 328 | buffer->data = buffer->data_offset - session->one_mmap_offset + |
@@ -316,31 +330,28 @@ static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues, | |||
316 | } else if (perf_data__is_pipe(session->data)) { | 330 | } else if (perf_data__is_pipe(session->data)) { |
317 | buffer->data = auxtrace_copy_data(buffer->size, session); | 331 | buffer->data = auxtrace_copy_data(buffer->size, session); |
318 | if (!buffer->data) | 332 | if (!buffer->data) |
319 | return -ENOMEM; | 333 | goto out_free; |
320 | buffer->data_needs_freeing = true; | 334 | buffer->data_needs_freeing = true; |
321 | } else if (BITS_PER_LONG == 32 && | 335 | } else if (BITS_PER_LONG == 32 && |
322 | buffer->size > BUFFER_LIMIT_FOR_32_BIT) { | 336 | buffer->size > BUFFER_LIMIT_FOR_32_BIT) { |
323 | err = auxtrace_queues__split_buffer(queues, idx, buffer); | 337 | err = auxtrace_queues__split_buffer(queues, idx, buffer); |
324 | if (err) | 338 | if (err) |
325 | return err; | 339 | goto out_free; |
326 | } | 340 | } |
327 | 341 | ||
328 | err = auxtrace_queues__queue_buffer(queues, idx, buffer); | 342 | err = auxtrace_queues__queue_buffer(queues, idx, buffer); |
329 | if (err) | 343 | if (err) |
330 | return err; | 344 | goto out_free; |
331 | 345 | ||
332 | /* FIXME: Doesn't work for split buffer */ | 346 | /* FIXME: Doesn't work for split buffer */ |
333 | if (buffer_ptr) | 347 | if (buffer_ptr) |
334 | *buffer_ptr = buffer; | 348 | *buffer_ptr = buffer; |
335 | 349 | ||
336 | return 0; | 350 | return 0; |
337 | } | ||
338 | 351 | ||
339 | static bool filter_cpu(struct perf_session *session, int cpu) | 352 | out_free: |
340 | { | 353 | auxtrace_buffer__free(buffer); |
341 | unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap; | 354 | return err; |
342 | |||
343 | return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap); | ||
344 | } | 355 | } |
345 | 356 | ||
346 | int auxtrace_queues__add_event(struct auxtrace_queues *queues, | 357 | int auxtrace_queues__add_event(struct auxtrace_queues *queues, |
@@ -348,36 +359,19 @@ int auxtrace_queues__add_event(struct auxtrace_queues *queues, | |||
348 | union perf_event *event, off_t data_offset, | 359 | union perf_event *event, off_t data_offset, |
349 | struct auxtrace_buffer **buffer_ptr) | 360 | struct auxtrace_buffer **buffer_ptr) |
350 | { | 361 | { |
351 | struct auxtrace_buffer *buffer; | 362 | struct auxtrace_buffer buffer = { |
352 | unsigned int idx; | 363 | .pid = -1, |
353 | int err; | 364 | .tid = event->auxtrace.tid, |
354 | 365 | .cpu = event->auxtrace.cpu, | |
355 | if (filter_cpu(session, event->auxtrace.cpu)) | 366 | .data_offset = data_offset, |
356 | return 0; | 367 | .offset = event->auxtrace.offset, |
357 | 368 | .reference = event->auxtrace.reference, | |
358 | buffer = zalloc(sizeof(struct auxtrace_buffer)); | 369 | .size = event->auxtrace.size, |
359 | if (!buffer) | 370 | }; |
360 | return -ENOMEM; | 371 | unsigned int idx = event->auxtrace.idx; |
361 | |||
362 | buffer->pid = -1; | ||
363 | buffer->tid = event->auxtrace.tid; | ||
364 | buffer->cpu = event->auxtrace.cpu; | ||
365 | buffer->data_offset = data_offset; | ||
366 | buffer->offset = event->auxtrace.offset; | ||
367 | buffer->reference = event->auxtrace.reference; | ||
368 | buffer->size = event->auxtrace.size; | ||
369 | idx = event->auxtrace.idx; | ||
370 | |||
371 | err = auxtrace_queues__add_buffer(queues, session, idx, buffer, | ||
372 | buffer_ptr); | ||
373 | if (err) | ||
374 | goto out_err; | ||
375 | |||
376 | return 0; | ||
377 | 372 | ||
378 | out_err: | 373 | return auxtrace_queues__add_buffer(queues, session, idx, &buffer, |
379 | auxtrace_buffer__free(buffer); | 374 | buffer_ptr); |
380 | return err; | ||
381 | } | 375 | } |
382 | 376 | ||
383 | static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues, | 377 | static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues, |
diff --git a/tools/perf/util/c++/clang-test.cpp b/tools/perf/util/c++/clang-test.cpp index a4014d786676..7b042a5ebc68 100644 --- a/tools/perf/util/c++/clang-test.cpp +++ b/tools/perf/util/c++/clang-test.cpp | |||
@@ -41,7 +41,7 @@ int test__clang_to_IR(void) | |||
41 | if (!M) | 41 | if (!M) |
42 | return -1; | 42 | return -1; |
43 | for (llvm::Function& F : *M) | 43 | for (llvm::Function& F : *M) |
44 | if (F.getName() == "bpf_func__SyS_epoll_wait") | 44 | if (F.getName() == "bpf_func__SyS_epoll_pwait") |
45 | return 0; | 45 | return 0; |
46 | return -1; | 46 | return -1; |
47 | } | 47 | } |
diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp index 1bfc946e37dc..bf31ceab33bd 100644 --- a/tools/perf/util/c++/clang.cpp +++ b/tools/perf/util/c++/clang.cpp | |||
@@ -9,6 +9,7 @@ | |||
9 | * Copyright (C) 2016 Huawei Inc. | 9 | * Copyright (C) 2016 Huawei Inc. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "clang/Basic/Version.h" | ||
12 | #include "clang/CodeGen/CodeGenAction.h" | 13 | #include "clang/CodeGen/CodeGenAction.h" |
13 | #include "clang/Frontend/CompilerInvocation.h" | 14 | #include "clang/Frontend/CompilerInvocation.h" |
14 | #include "clang/Frontend/CompilerInstance.h" | 15 | #include "clang/Frontend/CompilerInstance.h" |
@@ -58,7 +59,8 @@ createCompilerInvocation(llvm::opt::ArgStringList CFlags, StringRef& Path, | |||
58 | 59 | ||
59 | FrontendOptions& Opts = CI->getFrontendOpts(); | 60 | FrontendOptions& Opts = CI->getFrontendOpts(); |
60 | Opts.Inputs.clear(); | 61 | Opts.Inputs.clear(); |
61 | Opts.Inputs.emplace_back(Path, IK_C); | 62 | Opts.Inputs.emplace_back(Path, |
63 | FrontendOptions::getInputKindForExtension("c")); | ||
62 | return CI; | 64 | return CI; |
63 | } | 65 | } |
64 | 66 | ||
@@ -71,10 +73,17 @@ getModuleFromSource(llvm::opt::ArgStringList CFlags, | |||
71 | 73 | ||
72 | Clang.setVirtualFileSystem(&*VFS); | 74 | Clang.setVirtualFileSystem(&*VFS); |
73 | 75 | ||
76 | #if CLANG_VERSION_MAJOR < 4 | ||
74 | IntrusiveRefCntPtr<CompilerInvocation> CI = | 77 | IntrusiveRefCntPtr<CompilerInvocation> CI = |
75 | createCompilerInvocation(std::move(CFlags), Path, | 78 | createCompilerInvocation(std::move(CFlags), Path, |
76 | Clang.getDiagnostics()); | 79 | Clang.getDiagnostics()); |
77 | Clang.setInvocation(&*CI); | 80 | Clang.setInvocation(&*CI); |
81 | #else | ||
82 | std::shared_ptr<CompilerInvocation> CI( | ||
83 | createCompilerInvocation(std::move(CFlags), Path, | ||
84 | Clang.getDiagnostics())); | ||
85 | Clang.setInvocation(CI); | ||
86 | #endif | ||
78 | 87 | ||
79 | std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx)); | 88 | std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx)); |
80 | if (!Clang.ExecuteAction(*Act)) | 89 | if (!Clang.ExecuteAction(*Act)) |
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index f5acda13dcfa..7eb7de5aee44 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
@@ -979,7 +979,7 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf) | |||
979 | return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); | 979 | return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); |
980 | } | 980 | } |
981 | 981 | ||
982 | #ifdef HAVE_DWARF_GETLOCATIONS | 982 | #ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT |
983 | /** | 983 | /** |
984 | * die_get_var_innermost_scope - Get innermost scope range of given variable DIE | 984 | * die_get_var_innermost_scope - Get innermost scope range of given variable DIE |
985 | * @sp_die: a subprogram DIE | 985 | * @sp_die: a subprogram DIE |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 7d968892ee39..4d602fba40b2 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include "session.h" | 6 | #include "session.h" |
7 | #include "namespaces.h" | 7 | #include "namespaces.h" |
8 | #include "sort.h" | 8 | #include "sort.h" |
9 | #include "units.h" | ||
9 | #include "evlist.h" | 10 | #include "evlist.h" |
10 | #include "evsel.h" | 11 | #include "evsel.h" |
11 | #include "annotate.h" | 12 | #include "annotate.h" |
@@ -14,6 +15,7 @@ | |||
14 | #include "ui/progress.h" | 15 | #include "ui/progress.h" |
15 | #include <errno.h> | 16 | #include <errno.h> |
16 | #include <math.h> | 17 | #include <math.h> |
18 | #include <inttypes.h> | ||
17 | #include <sys/param.h> | 19 | #include <sys/param.h> |
18 | 20 | ||
19 | static bool hists__filter_entry_by_dso(struct hists *hists, | 21 | static bool hists__filter_entry_by_dso(struct hists *hists, |
@@ -2454,6 +2456,85 @@ u64 hists__total_period(struct hists *hists) | |||
2454 | hists->stats.total_period; | 2456 | hists->stats.total_period; |
2455 | } | 2457 | } |
2456 | 2458 | ||
2459 | int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool show_freq) | ||
2460 | { | ||
2461 | char unit; | ||
2462 | int printed; | ||
2463 | const struct dso *dso = hists->dso_filter; | ||
2464 | const struct thread *thread = hists->thread_filter; | ||
2465 | int socket_id = hists->socket_filter; | ||
2466 | unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; | ||
2467 | u64 nr_events = hists->stats.total_period; | ||
2468 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
2469 | const char *ev_name = perf_evsel__name(evsel); | ||
2470 | char buf[512], sample_freq_str[64] = ""; | ||
2471 | size_t buflen = sizeof(buf); | ||
2472 | char ref[30] = " show reference callgraph, "; | ||
2473 | bool enable_ref = false; | ||
2474 | |||
2475 | if (symbol_conf.filter_relative) { | ||
2476 | nr_samples = hists->stats.nr_non_filtered_samples; | ||
2477 | nr_events = hists->stats.total_non_filtered_period; | ||
2478 | } | ||
2479 | |||
2480 | if (perf_evsel__is_group_event(evsel)) { | ||
2481 | struct perf_evsel *pos; | ||
2482 | |||
2483 | perf_evsel__group_desc(evsel, buf, buflen); | ||
2484 | ev_name = buf; | ||
2485 | |||
2486 | for_each_group_member(pos, evsel) { | ||
2487 | struct hists *pos_hists = evsel__hists(pos); | ||
2488 | |||
2489 | if (symbol_conf.filter_relative) { | ||
2490 | nr_samples += pos_hists->stats.nr_non_filtered_samples; | ||
2491 | nr_events += pos_hists->stats.total_non_filtered_period; | ||
2492 | } else { | ||
2493 | nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; | ||
2494 | nr_events += pos_hists->stats.total_period; | ||
2495 | } | ||
2496 | } | ||
2497 | } | ||
2498 | |||
2499 | if (symbol_conf.show_ref_callgraph && | ||
2500 | strstr(ev_name, "call-graph=no")) | ||
2501 | enable_ref = true; | ||
2502 | |||
2503 | if (show_freq) | ||
2504 | scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); | ||
2505 | |||
2506 | nr_samples = convert_unit(nr_samples, &unit); | ||
2507 | printed = scnprintf(bf, size, | ||
2508 | "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, | ||
2509 | nr_samples, unit, evsel->nr_members > 1 ? "s" : "", | ||
2510 | ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); | ||
2511 | |||
2512 | |||
2513 | if (hists->uid_filter_str) | ||
2514 | printed += snprintf(bf + printed, size - printed, | ||
2515 | ", UID: %s", hists->uid_filter_str); | ||
2516 | if (thread) { | ||
2517 | if (hists__has(hists, thread)) { | ||
2518 | printed += scnprintf(bf + printed, size - printed, | ||
2519 | ", Thread: %s(%d)", | ||
2520 | (thread->comm_set ? thread__comm_str(thread) : ""), | ||
2521 | thread->tid); | ||
2522 | } else { | ||
2523 | printed += scnprintf(bf + printed, size - printed, | ||
2524 | ", Thread: %s", | ||
2525 | (thread->comm_set ? thread__comm_str(thread) : "")); | ||
2526 | } | ||
2527 | } | ||
2528 | if (dso) | ||
2529 | printed += scnprintf(bf + printed, size - printed, | ||
2530 | ", DSO: %s", dso->short_name); | ||
2531 | if (socket_id > -1) | ||
2532 | printed += scnprintf(bf + printed, size - printed, | ||
2533 | ", Processor Socket: %d", socket_id); | ||
2534 | |||
2535 | return printed; | ||
2536 | } | ||
2537 | |||
2457 | int parse_filter_percentage(const struct option *opt __maybe_unused, | 2538 | int parse_filter_percentage(const struct option *opt __maybe_unused, |
2458 | const char *arg, int unset __maybe_unused) | 2539 | const char *arg, int unset __maybe_unused) |
2459 | { | 2540 | { |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index e869cad4d89f..fbabfd8a215d 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -61,6 +61,7 @@ enum hist_column { | |||
61 | HISTC_SRCLINE_TO, | 61 | HISTC_SRCLINE_TO, |
62 | HISTC_TRACE, | 62 | HISTC_TRACE, |
63 | HISTC_SYM_SIZE, | 63 | HISTC_SYM_SIZE, |
64 | HISTC_DSO_SIZE, | ||
64 | HISTC_NR_COLS, /* Last entry */ | 65 | HISTC_NR_COLS, /* Last entry */ |
65 | }; | 66 | }; |
66 | 67 | ||
@@ -503,5 +504,11 @@ int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...); | |||
503 | int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp, | 504 | int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp, |
504 | struct perf_hpp_list *hpp_list); | 505 | struct perf_hpp_list *hpp_list); |
505 | int hists__fprintf_headers(struct hists *hists, FILE *fp); | 506 | int hists__fprintf_headers(struct hists *hists, FILE *fp); |
507 | int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool show_freq); | ||
508 | |||
509 | static inline int hists__scnprintf_title(struct hists *hists, char *bf, size_t size) | ||
510 | { | ||
511 | return __hists__scnprintf_title(hists, bf, size, true); | ||
512 | } | ||
506 | 513 | ||
507 | #endif /* __PERF_HIST_H */ | 514 | #endif /* __PERF_HIST_H */ |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index edeb7291c8e1..0e9bbe01b0ab 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -103,6 +103,10 @@ static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip) | |||
103 | return ip; | 103 | return ip; |
104 | } | 104 | } |
105 | 105 | ||
106 | static inline size_t map__size(const struct map *map) | ||
107 | { | ||
108 | return map->end - map->start; | ||
109 | } | ||
106 | 110 | ||
107 | /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ | 111 | /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ |
108 | u64 map__rip_2objdump(struct map *map, u64 rip); | 112 | u64 map__rip_2objdump(struct map *map, u64 rip); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c71ced7db152..f4a7a437ee87 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1591,7 +1591,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session) | |||
1591 | drop_rate = (double)stats->total_lost_samples / | 1591 | drop_rate = (double)stats->total_lost_samples / |
1592 | (double) (stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples); | 1592 | (double) (stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples); |
1593 | if (drop_rate > 0.05) { | 1593 | if (drop_rate > 0.05) { |
1594 | ui__warning("Processed %" PRIu64 " samples and lost %3.2f%% samples!\n\n", | 1594 | ui__warning("Processed %" PRIu64 " samples and lost %3.2f%%!\n\n", |
1595 | stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples, | 1595 | stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples, |
1596 | drop_rate * 100.0); | 1596 | drop_rate * 100.0); |
1597 | } | 1597 | } |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index e8514f651865..26a68dfd8a4f 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -1545,6 +1545,46 @@ struct sort_entry sort_sym_size = { | |||
1545 | .se_width_idx = HISTC_SYM_SIZE, | 1545 | .se_width_idx = HISTC_SYM_SIZE, |
1546 | }; | 1546 | }; |
1547 | 1547 | ||
1548 | /* --sort dso_size */ | ||
1549 | |||
1550 | static int64_t _sort__dso_size_cmp(struct map *map_l, struct map *map_r) | ||
1551 | { | ||
1552 | int64_t size_l = map_l != NULL ? map__size(map_l) : 0; | ||
1553 | int64_t size_r = map_r != NULL ? map__size(map_r) : 0; | ||
1554 | |||
1555 | return size_l < size_r ? -1 : | ||
1556 | size_l == size_r ? 0 : 1; | ||
1557 | } | ||
1558 | |||
1559 | static int64_t | ||
1560 | sort__dso_size_cmp(struct hist_entry *left, struct hist_entry *right) | ||
1561 | { | ||
1562 | return _sort__dso_size_cmp(right->ms.map, left->ms.map); | ||
1563 | } | ||
1564 | |||
1565 | static int _hist_entry__dso_size_snprintf(struct map *map, char *bf, | ||
1566 | size_t bf_size, unsigned int width) | ||
1567 | { | ||
1568 | if (map && map->dso) | ||
1569 | return repsep_snprintf(bf, bf_size, "%*d", width, | ||
1570 | map__size(map)); | ||
1571 | |||
1572 | return repsep_snprintf(bf, bf_size, "%*s", width, "unknown"); | ||
1573 | } | ||
1574 | |||
1575 | static int hist_entry__dso_size_snprintf(struct hist_entry *he, char *bf, | ||
1576 | size_t size, unsigned int width) | ||
1577 | { | ||
1578 | return _hist_entry__dso_size_snprintf(he->ms.map, bf, size, width); | ||
1579 | } | ||
1580 | |||
1581 | struct sort_entry sort_dso_size = { | ||
1582 | .se_header = "DSO size", | ||
1583 | .se_cmp = sort__dso_size_cmp, | ||
1584 | .se_snprintf = hist_entry__dso_size_snprintf, | ||
1585 | .se_width_idx = HISTC_DSO_SIZE, | ||
1586 | }; | ||
1587 | |||
1548 | 1588 | ||
1549 | struct sort_dimension { | 1589 | struct sort_dimension { |
1550 | const char *name; | 1590 | const char *name; |
@@ -1569,6 +1609,7 @@ static struct sort_dimension common_sort_dimensions[] = { | |||
1569 | DIM(SORT_TRANSACTION, "transaction", sort_transaction), | 1609 | DIM(SORT_TRANSACTION, "transaction", sort_transaction), |
1570 | DIM(SORT_TRACE, "trace", sort_trace), | 1610 | DIM(SORT_TRACE, "trace", sort_trace), |
1571 | DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size), | 1611 | DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size), |
1612 | DIM(SORT_DSO_SIZE, "dso_size", sort_dso_size), | ||
1572 | DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id), | 1613 | DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id), |
1573 | }; | 1614 | }; |
1574 | 1615 | ||
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index f5901c10a563..035b62e2c60b 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -220,6 +220,7 @@ enum sort_type { | |||
220 | SORT_TRANSACTION, | 220 | SORT_TRANSACTION, |
221 | SORT_TRACE, | 221 | SORT_TRACE, |
222 | SORT_SYM_SIZE, | 222 | SORT_SYM_SIZE, |
223 | SORT_DSO_SIZE, | ||
223 | SORT_CGROUP_ID, | 224 | SORT_CGROUP_ID, |
224 | 225 | ||
225 | /* branch stack specific sort keys */ | 226 | /* branch stack specific sort keys */ |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 9496365da3d7..c9626c206208 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -11,8 +11,7 @@ | |||
11 | #include <stdlib.h> | 11 | #include <stdlib.h> |
12 | #include <stdarg.h> | 12 | #include <stdarg.h> |
13 | #include <linux/compiler.h> | 13 | #include <linux/compiler.h> |
14 | #include <linux/types.h> | 14 | #include <sys/types.h> |
15 | #include "namespaces.h" | ||
16 | 15 | ||
17 | /* General helper functions */ | 16 | /* General helper functions */ |
18 | void usage(const char *err) __noreturn; | 17 | void usage(const char *err) __noreturn; |
@@ -26,6 +25,7 @@ static inline void *zalloc(size_t size) | |||
26 | #define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) | 25 | #define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) |
27 | 26 | ||
28 | struct dirent; | 27 | struct dirent; |
28 | struct nsinfo; | ||
29 | struct strlist; | 29 | struct strlist; |
30 | 30 | ||
31 | int mkdir_p(char *path, mode_t mode); | 31 | int mkdir_p(char *path, mode_t mode); |
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index dd614463d4d6..495066bafbe3 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include | |||
@@ -120,3 +120,5 @@ ifneq ($(silent),1) | |||
120 | QUIET_UNINST = @printf ' UNINST %s\n' $1; | 120 | QUIET_UNINST = @printf ' UNINST %s\n' $1; |
121 | endif | 121 | endif |
122 | endif | 122 | endif |
123 | |||
124 | pound := \# | ||
diff --git a/tools/testing/ktest/config-bisect.pl b/tools/testing/ktest/config-bisect.pl new file mode 100755 index 000000000000..b28feea7c363 --- /dev/null +++ b/tools/testing/ktest/config-bisect.pl | |||
@@ -0,0 +1,770 @@ | |||
1 | #!/usr/bin/perl -w | ||
2 | # | ||
3 | # Copyright 2015 - Steven Rostedt, Red Hat Inc. | ||
4 | # Copyright 2017 - Steven Rostedt, VMware, Inc. | ||
5 | # | ||
6 | # Licensed under the terms of the GNU GPL License version 2 | ||
7 | # | ||
8 | |||
9 | # usage: | ||
10 | # config-bisect.pl [options] good-config bad-config [good|bad] | ||
11 | # | ||
12 | |||
13 | # Compares a good config to a bad config, then takes half of the diffs | ||
14 | # and produces a config that is somewhere between the good config and | ||
15 | # the bad config. That is, the resulting config will start with the | ||
16 | # good config and will try to make half of the differences of between | ||
17 | # the good and bad configs match the bad config. It tries because of | ||
18 | # dependencies between the two configs it may not be able to change | ||
19 | # exactly half of the configs that are different between the two config | ||
20 | # files. | ||
21 | |||
22 | # Here's a normal way to use it: | ||
23 | # | ||
24 | # $ cd /path/to/linux/kernel | ||
25 | # $ config-bisect.pl /path/to/good/config /path/to/bad/config | ||
26 | |||
27 | # This will now pull in good config (blowing away .config in that directory | ||
28 | # so do not make that be one of the good or bad configs), and then | ||
29 | # build the config with "make oldconfig" to make sure it matches the | ||
30 | # current kernel. It will then store the configs in that result for | ||
31 | # the good config. It does the same for the bad config as well. | ||
32 | # The algorithm will run, merging half of the differences between | ||
33 | # the two configs and building them with "make oldconfig" to make sure | ||
34 | # the result changes (dependencies may reset changes the tool had made). | ||
35 | # It then copies the result of its good config to /path/to/good/config.tmp | ||
36 | # and the bad config to /path/to/bad/config.tmp (just appends ".tmp" to the | ||
37 | # files passed in). And the ".config" that you should test will be in | ||
38 | # directory | ||
39 | |||
40 | # After the first run, determine if the result is good or bad then | ||
41 | # run the same command appending the result | ||
42 | |||
43 | # For good results: | ||
44 | # $ config-bisect.pl /path/to/good/config /path/to/bad/config good | ||
45 | |||
46 | # For bad results: | ||
47 | # $ config-bisect.pl /path/to/good/config /path/to/bad/config bad | ||
48 | |||
49 | # Do not change the good-config or bad-config, config-bisect.pl will | ||
50 | # copy the good-config to a temp file with the same name as good-config | ||
51 | # but with a ".tmp" after it. It will do the same with the bad-config. | ||
52 | |||
53 | # If "good" or "bad" is not stated at the end, it will copy the good and | ||
54 | # bad configs to the .tmp versions. If a .tmp version already exists, it will | ||
55 | # warn before writing over them (-r will not warn, and just write over them). | ||
56 | # If the last config is labeled "good", then it will copy it to the good .tmp | ||
57 | # version. If the last config is labeled "bad", it will copy it to the bad | ||
58 | # .tmp version. It will continue this until it can not merge the two any more | ||
59 | # without the result being equal to either the good or bad .tmp configs. | ||
60 | |||
61 | my $start = 0; | ||
62 | my $val = ""; | ||
63 | |||
64 | my $pwd = `pwd`; | ||
65 | chomp $pwd; | ||
66 | my $tree = $pwd; | ||
67 | my $build; | ||
68 | |||
69 | my $output_config; | ||
70 | my $reset_bisect; | ||
71 | |||
72 | sub usage { | ||
73 | print << "EOF" | ||
74 | |||
75 | usage: config-bisect.pl [-l linux-tree][-b build-dir] good-config bad-config [good|bad] | ||
76 | -l [optional] define location of linux-tree (default is current directory) | ||
77 | -b [optional] define location to build (O=build-dir) (default is linux-tree) | ||
78 | good-config the config that is considered good | ||
79 | bad-config the config that does not work | ||
80 | "good" add this if the last run produced a good config | ||
81 | "bad" add this if the last run produced a bad config | ||
82 | If "good" or "bad" is not specified, then it is the start of a new bisect | ||
83 | |||
84 | Note, each run will create copy of good and bad configs with ".tmp" appended. | ||
85 | |||
86 | EOF | ||
87 | ; | ||
88 | |||
89 | exit(-1); | ||
90 | } | ||
91 | |||
92 | sub doprint { | ||
93 | print @_; | ||
94 | } | ||
95 | |||
96 | sub dodie { | ||
97 | doprint "CRITICAL FAILURE... ", @_, "\n"; | ||
98 | |||
99 | die @_, "\n"; | ||
100 | } | ||
101 | |||
102 | sub expand_path { | ||
103 | my ($file) = @_; | ||
104 | |||
105 | if ($file =~ m,^/,) { | ||
106 | return $file; | ||
107 | } | ||
108 | return "$pwd/$file"; | ||
109 | } | ||
110 | |||
111 | sub read_prompt { | ||
112 | my ($cancel, $prompt) = @_; | ||
113 | |||
114 | my $ans; | ||
115 | |||
116 | for (;;) { | ||
117 | if ($cancel) { | ||
118 | print "$prompt [y/n/C] "; | ||
119 | } else { | ||
120 | print "$prompt [y/N] "; | ||
121 | } | ||
122 | $ans = <STDIN>; | ||
123 | chomp $ans; | ||
124 | if ($ans =~ /^\s*$/) { | ||
125 | if ($cancel) { | ||
126 | $ans = "c"; | ||
127 | } else { | ||
128 | $ans = "n"; | ||
129 | } | ||
130 | } | ||
131 | last if ($ans =~ /^y$/i || $ans =~ /^n$/i); | ||
132 | if ($cancel) { | ||
133 | last if ($ans =~ /^c$/i); | ||
134 | print "Please answer either 'y', 'n' or 'c'.\n"; | ||
135 | } else { | ||
136 | print "Please answer either 'y' or 'n'.\n"; | ||
137 | } | ||
138 | } | ||
139 | if ($ans =~ /^c/i) { | ||
140 | exit; | ||
141 | } | ||
142 | if ($ans !~ /^y$/i) { | ||
143 | return 0; | ||
144 | } | ||
145 | return 1; | ||
146 | } | ||
147 | |||
148 | sub read_yn { | ||
149 | my ($prompt) = @_; | ||
150 | |||
151 | return read_prompt 0, $prompt; | ||
152 | } | ||
153 | |||
154 | sub read_ync { | ||
155 | my ($prompt) = @_; | ||
156 | |||
157 | return read_prompt 1, $prompt; | ||
158 | } | ||
159 | |||
160 | sub run_command { | ||
161 | my ($command, $redirect) = @_; | ||
162 | my $start_time; | ||
163 | my $end_time; | ||
164 | my $dord = 0; | ||
165 | my $pid; | ||
166 | |||
167 | $start_time = time; | ||
168 | |||
169 | doprint("$command ... "); | ||
170 | |||
171 | $pid = open(CMD, "$command 2>&1 |") or | ||
172 | dodie "unable to exec $command"; | ||
173 | |||
174 | if (defined($redirect)) { | ||
175 | open (RD, ">$redirect") or | ||
176 | dodie "failed to write to redirect $redirect"; | ||
177 | $dord = 1; | ||
178 | } | ||
179 | |||
180 | while (<CMD>) { | ||
181 | print RD if ($dord); | ||
182 | } | ||
183 | |||
184 | waitpid($pid, 0); | ||
185 | my $failed = $?; | ||
186 | |||
187 | close(CMD); | ||
188 | close(RD) if ($dord); | ||
189 | |||
190 | $end_time = time; | ||
191 | my $delta = $end_time - $start_time; | ||
192 | |||
193 | if ($delta == 1) { | ||
194 | doprint "[1 second] "; | ||
195 | } else { | ||
196 | doprint "[$delta seconds] "; | ||
197 | } | ||
198 | |||
199 | if ($failed) { | ||
200 | doprint "FAILED!\n"; | ||
201 | } else { | ||
202 | doprint "SUCCESS\n"; | ||
203 | } | ||
204 | |||
205 | return !$failed; | ||
206 | } | ||
207 | |||
208 | ###### CONFIG BISECT ###### | ||
209 | |||
210 | # config_ignore holds the configs that were set (or unset) for | ||
211 | # a good config and we will ignore these configs for the rest | ||
212 | # of a config bisect. These configs stay as they were. | ||
213 | my %config_ignore; | ||
214 | |||
215 | # config_set holds what all configs were set as. | ||
216 | my %config_set; | ||
217 | |||
218 | # config_off holds the set of configs that the bad config had disabled. | ||
219 | # We need to record them and set them in the .config when running | ||
220 | # olddefconfig, because olddefconfig keeps the defaults. | ||
221 | my %config_off; | ||
222 | |||
223 | # config_off_tmp holds a set of configs to turn off for now | ||
224 | my @config_off_tmp; | ||
225 | |||
226 | # config_list is the set of configs that are being tested | ||
227 | my %config_list; | ||
228 | my %null_config; | ||
229 | |||
230 | my %dependency; | ||
231 | |||
232 | my $make; | ||
233 | |||
234 | sub make_oldconfig { | ||
235 | |||
236 | if (!run_command "$make olddefconfig") { | ||
237 | # Perhaps olddefconfig doesn't exist in this version of the kernel | ||
238 | # try oldnoconfig | ||
239 | doprint "olddefconfig failed, trying make oldnoconfig\n"; | ||
240 | if (!run_command "$make oldnoconfig") { | ||
241 | doprint "oldnoconfig failed, trying yes '' | make oldconfig\n"; | ||
242 | # try a yes '' | oldconfig | ||
243 | run_command "yes '' | $make oldconfig" or | ||
244 | dodie "failed make config oldconfig"; | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | |||
249 | sub assign_configs { | ||
250 | my ($hash, $config) = @_; | ||
251 | |||
252 | doprint "Reading configs from $config\n"; | ||
253 | |||
254 | open (IN, $config) | ||
255 | or dodie "Failed to read $config"; | ||
256 | |||
257 | while (<IN>) { | ||
258 | chomp; | ||
259 | if (/^((CONFIG\S*)=.*)/) { | ||
260 | ${$hash}{$2} = $1; | ||
261 | } elsif (/^(# (CONFIG\S*) is not set)/) { | ||
262 | ${$hash}{$2} = $1; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | close(IN); | ||
267 | } | ||
268 | |||
269 | sub process_config_ignore { | ||
270 | my ($config) = @_; | ||
271 | |||
272 | assign_configs \%config_ignore, $config; | ||
273 | } | ||
274 | |||
275 | sub get_dependencies { | ||
276 | my ($config) = @_; | ||
277 | |||
278 | my $arr = $dependency{$config}; | ||
279 | if (!defined($arr)) { | ||
280 | return (); | ||
281 | } | ||
282 | |||
283 | my @deps = @{$arr}; | ||
284 | |||
285 | foreach my $dep (@{$arr}) { | ||
286 | print "ADD DEP $dep\n"; | ||
287 | @deps = (@deps, get_dependencies $dep); | ||
288 | } | ||
289 | |||
290 | return @deps; | ||
291 | } | ||
292 | |||
293 | sub save_config { | ||
294 | my ($pc, $file) = @_; | ||
295 | |||
296 | my %configs = %{$pc}; | ||
297 | |||
298 | doprint "Saving configs into $file\n"; | ||
299 | |||
300 | open(OUT, ">$file") or dodie "Can not write to $file"; | ||
301 | |||
302 | foreach my $config (keys %configs) { | ||
303 | print OUT "$configs{$config}\n"; | ||
304 | } | ||
305 | close(OUT); | ||
306 | } | ||
307 | |||
308 | sub create_config { | ||
309 | my ($name, $pc) = @_; | ||
310 | |||
311 | doprint "Creating old config from $name configs\n"; | ||
312 | |||
313 | save_config $pc, $output_config; | ||
314 | |||
315 | make_oldconfig; | ||
316 | } | ||
317 | |||
318 | # compare two config hashes, and return configs with different vals. | ||
319 | # It returns B's config values, but you can use A to see what A was. | ||
320 | sub diff_config_vals { | ||
321 | my ($pa, $pb) = @_; | ||
322 | |||
323 | # crappy Perl way to pass in hashes. | ||
324 | my %a = %{$pa}; | ||
325 | my %b = %{$pb}; | ||
326 | |||
327 | my %ret; | ||
328 | |||
329 | foreach my $item (keys %a) { | ||
330 | if (defined($b{$item}) && $b{$item} ne $a{$item}) { | ||
331 | $ret{$item} = $b{$item}; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | return %ret; | ||
336 | } | ||
337 | |||
338 | # compare two config hashes and return the configs in B but not A | ||
339 | sub diff_configs { | ||
340 | my ($pa, $pb) = @_; | ||
341 | |||
342 | my %ret; | ||
343 | |||
344 | # crappy Perl way to pass in hashes. | ||
345 | my %a = %{$pa}; | ||
346 | my %b = %{$pb}; | ||
347 | |||
348 | foreach my $item (keys %b) { | ||
349 | if (!defined($a{$item})) { | ||
350 | $ret{$item} = $b{$item}; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | return %ret; | ||
355 | } | ||
356 | |||
357 | # return if two configs are equal or not | ||
358 | # 0 is equal +1 b has something a does not | ||
359 | # +1 if a and b have a different item. | ||
360 | # -1 if a has something b does not | ||
361 | sub compare_configs { | ||
362 | my ($pa, $pb) = @_; | ||
363 | |||
364 | my %ret; | ||
365 | |||
366 | # crappy Perl way to pass in hashes. | ||
367 | my %a = %{$pa}; | ||
368 | my %b = %{$pb}; | ||
369 | |||
370 | foreach my $item (keys %b) { | ||
371 | if (!defined($a{$item})) { | ||
372 | return 1; | ||
373 | } | ||
374 | if ($a{$item} ne $b{$item}) { | ||
375 | return 1; | ||
376 | } | ||
377 | } | ||
378 | |||
379 | foreach my $item (keys %a) { | ||
380 | if (!defined($b{$item})) { | ||
381 | return -1; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | sub process_failed { | ||
389 | my ($config) = @_; | ||
390 | |||
391 | doprint "\n\n***************************************\n"; | ||
392 | doprint "Found bad config: $config\n"; | ||
393 | doprint "***************************************\n\n"; | ||
394 | } | ||
395 | |||
396 | sub process_new_config { | ||
397 | my ($tc, $nc, $gc, $bc) = @_; | ||
398 | |||
399 | my %tmp_config = %{$tc}; | ||
400 | my %good_configs = %{$gc}; | ||
401 | my %bad_configs = %{$bc}; | ||
402 | |||
403 | my %new_configs; | ||
404 | |||
405 | my $runtest = 1; | ||
406 | my $ret; | ||
407 | |||
408 | create_config "tmp_configs", \%tmp_config; | ||
409 | assign_configs \%new_configs, $output_config; | ||
410 | |||
411 | $ret = compare_configs \%new_configs, \%bad_configs; | ||
412 | if (!$ret) { | ||
413 | doprint "New config equals bad config, try next test\n"; | ||
414 | $runtest = 0; | ||
415 | } | ||
416 | |||
417 | if ($runtest) { | ||
418 | $ret = compare_configs \%new_configs, \%good_configs; | ||
419 | if (!$ret) { | ||
420 | doprint "New config equals good config, try next test\n"; | ||
421 | $runtest = 0; | ||
422 | } | ||
423 | } | ||
424 | |||
425 | %{$nc} = %new_configs; | ||
426 | |||
427 | return $runtest; | ||
428 | } | ||
429 | |||
430 | sub convert_config { | ||
431 | my ($config) = @_; | ||
432 | |||
433 | if ($config =~ /^# (.*) is not set/) { | ||
434 | $config = "$1=n"; | ||
435 | } | ||
436 | |||
437 | $config =~ s/^CONFIG_//; | ||
438 | return $config; | ||
439 | } | ||
440 | |||
441 | sub print_config { | ||
442 | my ($sym, $config) = @_; | ||
443 | |||
444 | $config = convert_config $config; | ||
445 | doprint "$sym$config\n"; | ||
446 | } | ||
447 | |||
448 | sub print_config_compare { | ||
449 | my ($good_config, $bad_config) = @_; | ||
450 | |||
451 | $good_config = convert_config $good_config; | ||
452 | $bad_config = convert_config $bad_config; | ||
453 | |||
454 | my $good_value = $good_config; | ||
455 | my $bad_value = $bad_config; | ||
456 | $good_value =~ s/(.*)=//; | ||
457 | my $config = $1; | ||
458 | |||
459 | $bad_value =~ s/.*=//; | ||
460 | |||
461 | doprint " $config $good_value -> $bad_value\n"; | ||
462 | } | ||
463 | |||
464 | # Pass in: | ||
465 | # $phalf: half of the configs names you want to add | ||
466 | # $oconfigs: The orginial configs to start with | ||
467 | # $sconfigs: The source to update $oconfigs with (from $phalf) | ||
468 | # $which: The name of which half that is updating (top / bottom) | ||
469 | # $type: The name of the source type (good / bad) | ||
470 | sub make_half { | ||
471 | my ($phalf, $oconfigs, $sconfigs, $which, $type) = @_; | ||
472 | |||
473 | my @half = @{$phalf}; | ||
474 | my %orig_configs = %{$oconfigs}; | ||
475 | my %source_configs = %{$sconfigs}; | ||
476 | |||
477 | my %tmp_config = %orig_configs; | ||
478 | |||
479 | doprint "Settings bisect with $which half of $type configs:\n"; | ||
480 | foreach my $item (@half) { | ||
481 | doprint "Updating $item to $source_configs{$item}\n"; | ||
482 | $tmp_config{$item} = $source_configs{$item}; | ||
483 | } | ||
484 | |||
485 | return %tmp_config; | ||
486 | } | ||
487 | |||
488 | sub run_config_bisect { | ||
489 | my ($pgood, $pbad) = @_; | ||
490 | |||
491 | my %good_configs = %{$pgood}; | ||
492 | my %bad_configs = %{$pbad}; | ||
493 | |||
494 | my %diff_configs = diff_config_vals \%good_configs, \%bad_configs; | ||
495 | my %b_configs = diff_configs \%good_configs, \%bad_configs; | ||
496 | my %g_configs = diff_configs \%bad_configs, \%good_configs; | ||
497 | |||
498 | # diff_arr is what is in both good and bad but are different (y->n) | ||
499 | my @diff_arr = keys %diff_configs; | ||
500 | my $len_diff = $#diff_arr + 1; | ||
501 | |||
502 | # b_arr is what is in bad but not in good (has depends) | ||
503 | my @b_arr = keys %b_configs; | ||
504 | my $len_b = $#b_arr + 1; | ||
505 | |||
506 | # g_arr is what is in good but not in bad | ||
507 | my @g_arr = keys %g_configs; | ||
508 | my $len_g = $#g_arr + 1; | ||
509 | |||
510 | my $runtest = 0; | ||
511 | my %new_configs; | ||
512 | my $ret; | ||
513 | |||
514 | # Look at the configs that are different between good and bad. | ||
515 | # This does not include those that depend on other configs | ||
516 | # (configs depending on other configs that are not set would | ||
517 | # not show up even as a "# CONFIG_FOO is not set" | ||
518 | |||
519 | |||
520 | doprint "# of configs to check: $len_diff\n"; | ||
521 | doprint "# of configs showing only in good: $len_g\n"; | ||
522 | doprint "# of configs showing only in bad: $len_b\n"; | ||
523 | |||
524 | if ($len_diff > 0) { | ||
525 | # Now test for different values | ||
526 | |||
527 | doprint "Configs left to check:\n"; | ||
528 | doprint " Good Config\t\t\tBad Config\n"; | ||
529 | doprint " -----------\t\t\t----------\n"; | ||
530 | foreach my $item (@diff_arr) { | ||
531 | doprint " $good_configs{$item}\t$bad_configs{$item}\n"; | ||
532 | } | ||
533 | |||
534 | my $half = int($#diff_arr / 2); | ||
535 | my @tophalf = @diff_arr[0 .. $half]; | ||
536 | |||
537 | doprint "Set tmp config to be good config with some bad config values\n"; | ||
538 | |||
539 | my %tmp_config = make_half \@tophalf, \%good_configs, | ||
540 | \%bad_configs, "top", "bad"; | ||
541 | |||
542 | $runtest = process_new_config \%tmp_config, \%new_configs, | ||
543 | \%good_configs, \%bad_configs; | ||
544 | |||
545 | if (!$runtest) { | ||
546 | doprint "Set tmp config to be bad config with some good config values\n"; | ||
547 | |||
548 | my %tmp_config = make_half \@tophalf, \%bad_configs, | ||
549 | \%good_configs, "top", "good"; | ||
550 | |||
551 | $runtest = process_new_config \%tmp_config, \%new_configs, | ||
552 | \%good_configs, \%bad_configs; | ||
553 | } | ||
554 | } | ||
555 | |||
556 | if (!$runtest && $len_diff > 0) { | ||
557 | # do the same thing, but this time with bottom half | ||
558 | |||
559 | my $half = int($#diff_arr / 2); | ||
560 | my @bottomhalf = @diff_arr[$half+1 .. $#diff_arr]; | ||
561 | |||
562 | doprint "Set tmp config to be good config with some bad config values\n"; | ||
563 | |||
564 | my %tmp_config = make_half \@bottomhalf, \%good_configs, | ||
565 | \%bad_configs, "bottom", "bad"; | ||
566 | |||
567 | $runtest = process_new_config \%tmp_config, \%new_configs, | ||
568 | \%good_configs, \%bad_configs; | ||
569 | |||
570 | if (!$runtest) { | ||
571 | doprint "Set tmp config to be bad config with some good config values\n"; | ||
572 | |||
573 | my %tmp_config = make_half \@bottomhalf, \%bad_configs, | ||
574 | \%good_configs, "bottom", "good"; | ||
575 | |||
576 | $runtest = process_new_config \%tmp_config, \%new_configs, | ||
577 | \%good_configs, \%bad_configs; | ||
578 | } | ||
579 | } | ||
580 | |||
581 | if ($runtest) { | ||
582 | make_oldconfig; | ||
583 | doprint "READY TO TEST .config IN $build\n"; | ||
584 | return 0; | ||
585 | } | ||
586 | |||
587 | doprint "\n%%%%%%%% FAILED TO FIND SINGLE BAD CONFIG %%%%%%%%\n"; | ||
588 | doprint "Hmm, can't make any more changes without making good == bad?\n"; | ||
589 | doprint "Difference between good (+) and bad (-)\n"; | ||
590 | |||
591 | foreach my $item (keys %bad_configs) { | ||
592 | if (!defined($good_configs{$item})) { | ||
593 | print_config "-", $bad_configs{$item}; | ||
594 | } | ||
595 | } | ||
596 | |||
597 | foreach my $item (keys %good_configs) { | ||
598 | next if (!defined($bad_configs{$item})); | ||
599 | if ($good_configs{$item} ne $bad_configs{$item}) { | ||
600 | print_config_compare $good_configs{$item}, $bad_configs{$item}; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | foreach my $item (keys %good_configs) { | ||
605 | if (!defined($bad_configs{$item})) { | ||
606 | print_config "+", $good_configs{$item}; | ||
607 | } | ||
608 | } | ||
609 | return -1; | ||
610 | } | ||
611 | |||
612 | sub config_bisect { | ||
613 | my ($good_config, $bad_config) = @_; | ||
614 | my $ret; | ||
615 | |||
616 | my %good_configs; | ||
617 | my %bad_configs; | ||
618 | my %tmp_configs; | ||
619 | |||
620 | doprint "Run good configs through make oldconfig\n"; | ||
621 | assign_configs \%tmp_configs, $good_config; | ||
622 | create_config "$good_config", \%tmp_configs; | ||
623 | assign_configs \%good_configs, $output_config; | ||
624 | |||
625 | doprint "Run bad configs through make oldconfig\n"; | ||
626 | assign_configs \%tmp_configs, $bad_config; | ||
627 | create_config "$bad_config", \%tmp_configs; | ||
628 | assign_configs \%bad_configs, $output_config; | ||
629 | |||
630 | save_config \%good_configs, $good_config; | ||
631 | save_config \%bad_configs, $bad_config; | ||
632 | |||
633 | return run_config_bisect \%good_configs, \%bad_configs; | ||
634 | } | ||
635 | |||
636 | while ($#ARGV >= 0) { | ||
637 | if ($ARGV[0] !~ m/^-/) { | ||
638 | last; | ||
639 | } | ||
640 | my $opt = shift @ARGV; | ||
641 | |||
642 | if ($opt eq "-b") { | ||
643 | $val = shift @ARGV; | ||
644 | if (!defined($val)) { | ||
645 | die "-b requires value\n"; | ||
646 | } | ||
647 | $build = $val; | ||
648 | } | ||
649 | |||
650 | elsif ($opt eq "-l") { | ||
651 | $val = shift @ARGV; | ||
652 | if (!defined($val)) { | ||
653 | die "-l requires value\n"; | ||
654 | } | ||
655 | $tree = $val; | ||
656 | } | ||
657 | |||
658 | elsif ($opt eq "-r") { | ||
659 | $reset_bisect = 1; | ||
660 | } | ||
661 | |||
662 | elsif ($opt eq "-h") { | ||
663 | usage; | ||
664 | } | ||
665 | |||
666 | else { | ||
667 | die "Unknow option $opt\n"; | ||
668 | } | ||
669 | } | ||
670 | |||
671 | $build = $tree if (!defined($build)); | ||
672 | |||
673 | $tree = expand_path $tree; | ||
674 | $build = expand_path $build; | ||
675 | |||
676 | if ( ! -d $tree ) { | ||
677 | die "$tree not a directory\n"; | ||
678 | } | ||
679 | |||
680 | if ( ! -d $build ) { | ||
681 | die "$build not a directory\n"; | ||
682 | } | ||
683 | |||
684 | usage if $#ARGV < 1; | ||
685 | |||
686 | if ($#ARGV == 1) { | ||
687 | $start = 1; | ||
688 | } elsif ($#ARGV == 2) { | ||
689 | $val = $ARGV[2]; | ||
690 | if ($val ne "good" && $val ne "bad") { | ||
691 | die "Unknown command '$val', bust be either \"good\" or \"bad\"\n"; | ||
692 | } | ||
693 | } else { | ||
694 | usage; | ||
695 | } | ||
696 | |||
697 | my $good_start = expand_path $ARGV[0]; | ||
698 | my $bad_start = expand_path $ARGV[1]; | ||
699 | |||
700 | my $good = "$good_start.tmp"; | ||
701 | my $bad = "$bad_start.tmp"; | ||
702 | |||
703 | $make = "make"; | ||
704 | |||
705 | if ($build ne $tree) { | ||
706 | $make = "make O=$build" | ||
707 | } | ||
708 | |||
709 | $output_config = "$build/.config"; | ||
710 | |||
711 | if ($start) { | ||
712 | if ( ! -f $good_start ) { | ||
713 | die "$good_start not found\n"; | ||
714 | } | ||
715 | if ( ! -f $bad_start ) { | ||
716 | die "$bad_start not found\n"; | ||
717 | } | ||
718 | if ( -f $good || -f $bad ) { | ||
719 | my $p = ""; | ||
720 | |||
721 | if ( -f $good ) { | ||
722 | $p = "$good exists\n"; | ||
723 | } | ||
724 | |||
725 | if ( -f $bad ) { | ||
726 | $p = "$p$bad exists\n"; | ||
727 | } | ||
728 | |||
729 | if (!defined($reset_bisect)) { | ||
730 | if (!read_yn "${p}Overwrite and start new bisect anyway?") { | ||
731 | exit (-1); | ||
732 | } | ||
733 | } | ||
734 | } | ||
735 | run_command "cp $good_start $good" or die "failed to copy to $good\n"; | ||
736 | run_command "cp $bad_start $bad" or die "faield to copy to $bad\n"; | ||
737 | } else { | ||
738 | if ( ! -f $good ) { | ||
739 | die "Can not find file $good\n"; | ||
740 | } | ||
741 | if ( ! -f $bad ) { | ||
742 | die "Can not find file $bad\n"; | ||
743 | } | ||
744 | if ($val eq "good") { | ||
745 | run_command "cp $output_config $good" or die "failed to copy $config to $good\n"; | ||
746 | } elsif ($val eq "bad") { | ||
747 | run_command "cp $output_config $bad" or die "failed to copy $config to $bad\n"; | ||
748 | } | ||
749 | } | ||
750 | |||
751 | chdir $tree || die "can't change directory to $tree"; | ||
752 | |||
753 | my $ret = config_bisect $good, $bad; | ||
754 | |||
755 | if (!$ret) { | ||
756 | exit(0); | ||
757 | } | ||
758 | |||
759 | if ($ret > 0) { | ||
760 | doprint "Cleaning temp files\n"; | ||
761 | run_command "rm $good"; | ||
762 | run_command "rm $bad"; | ||
763 | exit(1); | ||
764 | } else { | ||
765 | doprint "See good and bad configs for details:\n"; | ||
766 | doprint "good: $good\n"; | ||
767 | doprint "bad: $bad\n"; | ||
768 | doprint "%%%%%%%% FAILED TO FIND SINGLE BAD CONFIG %%%%%%%%\n"; | ||
769 | } | ||
770 | exit(2); | ||
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 8809f244bb7c..87af8a68ab25 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl | |||
@@ -10,6 +10,7 @@ use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); | |||
10 | use File::Path qw(mkpath); | 10 | use File::Path qw(mkpath); |
11 | use File::Copy qw(cp); | 11 | use File::Copy qw(cp); |
12 | use FileHandle; | 12 | use FileHandle; |
13 | use FindBin; | ||
13 | 14 | ||
14 | my $VERSION = "0.2"; | 15 | my $VERSION = "0.2"; |
15 | 16 | ||
@@ -22,6 +23,11 @@ my %evals; | |||
22 | 23 | ||
23 | #default opts | 24 | #default opts |
24 | my %default = ( | 25 | my %default = ( |
26 | "MAILER" => "sendmail", # default mailer | ||
27 | "EMAIL_ON_ERROR" => 1, | ||
28 | "EMAIL_WHEN_FINISHED" => 1, | ||
29 | "EMAIL_WHEN_CANCELED" => 0, | ||
30 | "EMAIL_WHEN_STARTED" => 0, | ||
25 | "NUM_TESTS" => 1, | 31 | "NUM_TESTS" => 1, |
26 | "TEST_TYPE" => "build", | 32 | "TEST_TYPE" => "build", |
27 | "BUILD_TYPE" => "randconfig", | 33 | "BUILD_TYPE" => "randconfig", |
@@ -59,6 +65,7 @@ my %default = ( | |||
59 | "GRUB_REBOOT" => "grub2-reboot", | 65 | "GRUB_REBOOT" => "grub2-reboot", |
60 | "SYSLINUX" => "extlinux", | 66 | "SYSLINUX" => "extlinux", |
61 | "SYSLINUX_PATH" => "/boot/extlinux", | 67 | "SYSLINUX_PATH" => "/boot/extlinux", |
68 | "CONNECT_TIMEOUT" => 25, | ||
62 | 69 | ||
63 | # required, and we will ask users if they don't have them but we keep the default | 70 | # required, and we will ask users if they don't have them but we keep the default |
64 | # value something that is common. | 71 | # value something that is common. |
@@ -163,6 +170,8 @@ my $store_failures; | |||
163 | my $store_successes; | 170 | my $store_successes; |
164 | my $test_name; | 171 | my $test_name; |
165 | my $timeout; | 172 | my $timeout; |
173 | my $connect_timeout; | ||
174 | my $config_bisect_exec; | ||
166 | my $booted_timeout; | 175 | my $booted_timeout; |
167 | my $detect_triplefault; | 176 | my $detect_triplefault; |
168 | my $console; | 177 | my $console; |
@@ -204,6 +213,20 @@ my $install_time; | |||
204 | my $reboot_time; | 213 | my $reboot_time; |
205 | my $test_time; | 214 | my $test_time; |
206 | 215 | ||
216 | my $pwd; | ||
217 | my $dirname = $FindBin::Bin; | ||
218 | |||
219 | my $mailto; | ||
220 | my $mailer; | ||
221 | my $mail_path; | ||
222 | my $mail_command; | ||
223 | my $email_on_error; | ||
224 | my $email_when_finished; | ||
225 | my $email_when_started; | ||
226 | my $email_when_canceled; | ||
227 | |||
228 | my $script_start_time = localtime(); | ||
229 | |||
207 | # set when a test is something other that just building or install | 230 | # set when a test is something other that just building or install |
208 | # which would require more options. | 231 | # which would require more options. |
209 | my $buildonly = 1; | 232 | my $buildonly = 1; |
@@ -229,6 +252,14 @@ my $no_reboot = 1; | |||
229 | my $reboot_success = 0; | 252 | my $reboot_success = 0; |
230 | 253 | ||
231 | my %option_map = ( | 254 | my %option_map = ( |
255 | "MAILTO" => \$mailto, | ||
256 | "MAILER" => \$mailer, | ||
257 | "MAIL_PATH" => \$mail_path, | ||
258 | "MAIL_COMMAND" => \$mail_command, | ||
259 | "EMAIL_ON_ERROR" => \$email_on_error, | ||
260 | "EMAIL_WHEN_FINISHED" => \$email_when_finished, | ||
261 | "EMAIL_WHEN_STARTED" => \$email_when_started, | ||
262 | "EMAIL_WHEN_CANCELED" => \$email_when_canceled, | ||
232 | "MACHINE" => \$machine, | 263 | "MACHINE" => \$machine, |
233 | "SSH_USER" => \$ssh_user, | 264 | "SSH_USER" => \$ssh_user, |
234 | "TMP_DIR" => \$tmpdir, | 265 | "TMP_DIR" => \$tmpdir, |
@@ -296,6 +327,8 @@ my %option_map = ( | |||
296 | "STORE_SUCCESSES" => \$store_successes, | 327 | "STORE_SUCCESSES" => \$store_successes, |
297 | "TEST_NAME" => \$test_name, | 328 | "TEST_NAME" => \$test_name, |
298 | "TIMEOUT" => \$timeout, | 329 | "TIMEOUT" => \$timeout, |
330 | "CONNECT_TIMEOUT" => \$connect_timeout, | ||
331 | "CONFIG_BISECT_EXEC" => \$config_bisect_exec, | ||
299 | "BOOTED_TIMEOUT" => \$booted_timeout, | 332 | "BOOTED_TIMEOUT" => \$booted_timeout, |
300 | "CONSOLE" => \$console, | 333 | "CONSOLE" => \$console, |
301 | "CLOSE_CONSOLE_SIGNAL" => \$close_console_signal, | 334 | "CLOSE_CONSOLE_SIGNAL" => \$close_console_signal, |
@@ -337,6 +370,7 @@ my %used_options; | |||
337 | 370 | ||
338 | # default variables that can be used | 371 | # default variables that can be used |
339 | chomp ($variable{"PWD"} = `pwd`); | 372 | chomp ($variable{"PWD"} = `pwd`); |
373 | $pwd = $variable{"PWD"}; | ||
340 | 374 | ||
341 | $config_help{"MACHINE"} = << "EOF" | 375 | $config_help{"MACHINE"} = << "EOF" |
342 | The machine hostname that you will test. | 376 | The machine hostname that you will test. |
@@ -718,22 +752,14 @@ sub set_value { | |||
718 | 752 | ||
719 | my $prvalue = process_variables($rvalue); | 753 | my $prvalue = process_variables($rvalue); |
720 | 754 | ||
721 | if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $prvalue ne "build") { | 755 | if ($lvalue =~ /^(TEST|BISECT|CONFIG_BISECT)_TYPE(\[.*\])?$/ && |
756 | $prvalue !~ /^(config_|)bisect$/ && | ||
757 | $prvalue !~ /^build$/ && | ||
758 | $buildonly) { | ||
759 | |||
722 | # Note if a test is something other than build, then we | 760 | # Note if a test is something other than build, then we |
723 | # will need other mandatory options. | 761 | # will need other mandatory options. |
724 | if ($prvalue ne "install") { | 762 | if ($prvalue ne "install") { |
725 | # for bisect, we need to check BISECT_TYPE | ||
726 | if ($prvalue ne "bisect") { | ||
727 | $buildonly = 0; | ||
728 | } | ||
729 | } else { | ||
730 | # install still limits some mandatory options. | ||
731 | $buildonly = 2; | ||
732 | } | ||
733 | } | ||
734 | |||
735 | if ($buildonly && $lvalue =~ /^BISECT_TYPE(\[.*\])?$/ && $prvalue ne "build") { | ||
736 | if ($prvalue ne "install") { | ||
737 | $buildonly = 0; | 763 | $buildonly = 0; |
738 | } else { | 764 | } else { |
739 | # install still limits some mandatory options. | 765 | # install still limits some mandatory options. |
@@ -1140,7 +1166,8 @@ sub __read_config { | |||
1140 | sub get_test_case { | 1166 | sub get_test_case { |
1141 | print "What test case would you like to run?\n"; | 1167 | print "What test case would you like to run?\n"; |
1142 | print " (build, install or boot)\n"; | 1168 | print " (build, install or boot)\n"; |
1143 | print " Other tests are available but require editing the config file\n"; | 1169 | print " Other tests are available but require editing ktest.conf\n"; |
1170 | print " (see tools/testing/ktest/sample.conf)\n"; | ||
1144 | my $ans = <STDIN>; | 1171 | my $ans = <STDIN>; |
1145 | chomp $ans; | 1172 | chomp $ans; |
1146 | $default{"TEST_TYPE"} = $ans; | 1173 | $default{"TEST_TYPE"} = $ans; |
@@ -1328,8 +1355,8 @@ sub reboot { | |||
1328 | my ($time) = @_; | 1355 | my ($time) = @_; |
1329 | my $powercycle = 0; | 1356 | my $powercycle = 0; |
1330 | 1357 | ||
1331 | # test if the machine can be connected to within 5 seconds | 1358 | # test if the machine can be connected to within a few seconds |
1332 | my $stat = run_ssh("echo check machine status", 5); | 1359 | my $stat = run_ssh("echo check machine status", $connect_timeout); |
1333 | if (!$stat) { | 1360 | if (!$stat) { |
1334 | doprint("power cycle\n"); | 1361 | doprint("power cycle\n"); |
1335 | $powercycle = 1; | 1362 | $powercycle = 1; |
@@ -1404,10 +1431,18 @@ sub do_not_reboot { | |||
1404 | 1431 | ||
1405 | return $test_type eq "build" || $no_reboot || | 1432 | return $test_type eq "build" || $no_reboot || |
1406 | ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") || | 1433 | ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") || |
1407 | ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build"); | 1434 | ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build") || |
1435 | ($test_type eq "config_bisect" && $opt{"CONFIG_BISECT_TYPE[$i]"} eq "build"); | ||
1408 | } | 1436 | } |
1409 | 1437 | ||
1438 | my $in_die = 0; | ||
1439 | |||
1410 | sub dodie { | 1440 | sub dodie { |
1441 | |||
1442 | # avoid recusion | ||
1443 | return if ($in_die); | ||
1444 | $in_die = 1; | ||
1445 | |||
1411 | doprint "CRITICAL FAILURE... ", @_, "\n"; | 1446 | doprint "CRITICAL FAILURE... ", @_, "\n"; |
1412 | 1447 | ||
1413 | my $i = $iteration; | 1448 | my $i = $iteration; |
@@ -1426,6 +1461,11 @@ sub dodie { | |||
1426 | print " See $opt{LOG_FILE} for more info.\n"; | 1461 | print " See $opt{LOG_FILE} for more info.\n"; |
1427 | } | 1462 | } |
1428 | 1463 | ||
1464 | if ($email_on_error) { | ||
1465 | send_email("KTEST: critical failure for your [$test_type] test", | ||
1466 | "Your test started at $script_start_time has failed with:\n@_\n"); | ||
1467 | } | ||
1468 | |||
1429 | if ($monitor_cnt) { | 1469 | if ($monitor_cnt) { |
1430 | # restore terminal settings | 1470 | # restore terminal settings |
1431 | system("stty $stty_orig"); | 1471 | system("stty $stty_orig"); |
@@ -1477,7 +1517,7 @@ sub exec_console { | |||
1477 | close($pts); | 1517 | close($pts); |
1478 | 1518 | ||
1479 | exec $console or | 1519 | exec $console or |
1480 | die "Can't open console $console"; | 1520 | dodie "Can't open console $console"; |
1481 | } | 1521 | } |
1482 | 1522 | ||
1483 | sub open_console { | 1523 | sub open_console { |
@@ -1515,6 +1555,9 @@ sub close_console { | |||
1515 | doprint "kill child process $pid\n"; | 1555 | doprint "kill child process $pid\n"; |
1516 | kill $close_console_signal, $pid; | 1556 | kill $close_console_signal, $pid; |
1517 | 1557 | ||
1558 | doprint "wait for child process $pid to exit\n"; | ||
1559 | waitpid($pid, 0); | ||
1560 | |||
1518 | print "closing!\n"; | 1561 | print "closing!\n"; |
1519 | close($fp); | 1562 | close($fp); |
1520 | 1563 | ||
@@ -1625,7 +1668,7 @@ sub save_logs { | |||
1625 | 1668 | ||
1626 | if (!-d $dir) { | 1669 | if (!-d $dir) { |
1627 | mkpath($dir) or | 1670 | mkpath($dir) or |
1628 | die "can't create $dir"; | 1671 | dodie "can't create $dir"; |
1629 | } | 1672 | } |
1630 | 1673 | ||
1631 | my %files = ( | 1674 | my %files = ( |
@@ -1638,7 +1681,7 @@ sub save_logs { | |||
1638 | while (my ($name, $source) = each(%files)) { | 1681 | while (my ($name, $source) = each(%files)) { |
1639 | if (-f "$source") { | 1682 | if (-f "$source") { |
1640 | cp "$source", "$dir/$name" or | 1683 | cp "$source", "$dir/$name" or |
1641 | die "failed to copy $source"; | 1684 | dodie "failed to copy $source"; |
1642 | } | 1685 | } |
1643 | } | 1686 | } |
1644 | 1687 | ||
@@ -1692,6 +1735,7 @@ sub run_command { | |||
1692 | my $end_time; | 1735 | my $end_time; |
1693 | my $dolog = 0; | 1736 | my $dolog = 0; |
1694 | my $dord = 0; | 1737 | my $dord = 0; |
1738 | my $dostdout = 0; | ||
1695 | my $pid; | 1739 | my $pid; |
1696 | 1740 | ||
1697 | $command =~ s/\$SSH_USER/$ssh_user/g; | 1741 | $command =~ s/\$SSH_USER/$ssh_user/g; |
@@ -1710,9 +1754,15 @@ sub run_command { | |||
1710 | } | 1754 | } |
1711 | 1755 | ||
1712 | if (defined($redirect)) { | 1756 | if (defined($redirect)) { |
1713 | open (RD, ">$redirect") or | 1757 | if ($redirect eq 1) { |
1714 | dodie "failed to write to redirect $redirect"; | 1758 | $dostdout = 1; |
1715 | $dord = 1; | 1759 | # Have the output of the command on its own line |
1760 | doprint "\n"; | ||
1761 | } else { | ||
1762 | open (RD, ">$redirect") or | ||
1763 | dodie "failed to write to redirect $redirect"; | ||
1764 | $dord = 1; | ||
1765 | } | ||
1716 | } | 1766 | } |
1717 | 1767 | ||
1718 | my $hit_timeout = 0; | 1768 | my $hit_timeout = 0; |
@@ -1734,6 +1784,7 @@ sub run_command { | |||
1734 | } | 1784 | } |
1735 | print LOG $line if ($dolog); | 1785 | print LOG $line if ($dolog); |
1736 | print RD $line if ($dord); | 1786 | print RD $line if ($dord); |
1787 | print $line if ($dostdout); | ||
1737 | } | 1788 | } |
1738 | 1789 | ||
1739 | waitpid($pid, 0); | 1790 | waitpid($pid, 0); |
@@ -1812,7 +1863,7 @@ sub get_grub2_index { | |||
1812 | $ssh_grub =~ s,\$SSH_COMMAND,cat $grub_file,g; | 1863 | $ssh_grub =~ s,\$SSH_COMMAND,cat $grub_file,g; |
1813 | 1864 | ||
1814 | open(IN, "$ssh_grub |") | 1865 | open(IN, "$ssh_grub |") |
1815 | or die "unable to get $grub_file"; | 1866 | or dodie "unable to get $grub_file"; |
1816 | 1867 | ||
1817 | my $found = 0; | 1868 | my $found = 0; |
1818 | 1869 | ||
@@ -1821,13 +1872,13 @@ sub get_grub2_index { | |||
1821 | $grub_number++; | 1872 | $grub_number++; |
1822 | $found = 1; | 1873 | $found = 1; |
1823 | last; | 1874 | last; |
1824 | } elsif (/^menuentry\s/) { | 1875 | } elsif (/^menuentry\s|^submenu\s/) { |
1825 | $grub_number++; | 1876 | $grub_number++; |
1826 | } | 1877 | } |
1827 | } | 1878 | } |
1828 | close(IN); | 1879 | close(IN); |
1829 | 1880 | ||
1830 | die "Could not find '$grub_menu' in $grub_file on $machine" | 1881 | dodie "Could not find '$grub_menu' in $grub_file on $machine" |
1831 | if (!$found); | 1882 | if (!$found); |
1832 | doprint "$grub_number\n"; | 1883 | doprint "$grub_number\n"; |
1833 | $last_grub_menu = $grub_menu; | 1884 | $last_grub_menu = $grub_menu; |
@@ -1855,7 +1906,7 @@ sub get_grub_index { | |||
1855 | $ssh_grub =~ s,\$SSH_COMMAND,cat /boot/grub/menu.lst,g; | 1906 | $ssh_grub =~ s,\$SSH_COMMAND,cat /boot/grub/menu.lst,g; |
1856 | 1907 | ||
1857 | open(IN, "$ssh_grub |") | 1908 | open(IN, "$ssh_grub |") |
1858 | or die "unable to get menu.lst"; | 1909 | or dodie "unable to get menu.lst"; |
1859 | 1910 | ||
1860 | my $found = 0; | 1911 | my $found = 0; |
1861 | 1912 | ||
@@ -1870,7 +1921,7 @@ sub get_grub_index { | |||
1870 | } | 1921 | } |
1871 | close(IN); | 1922 | close(IN); |
1872 | 1923 | ||
1873 | die "Could not find '$grub_menu' in /boot/grub/menu on $machine" | 1924 | dodie "Could not find '$grub_menu' in /boot/grub/menu on $machine" |
1874 | if (!$found); | 1925 | if (!$found); |
1875 | doprint "$grub_number\n"; | 1926 | doprint "$grub_number\n"; |
1876 | $last_grub_menu = $grub_menu; | 1927 | $last_grub_menu = $grub_menu; |
@@ -1983,7 +2034,7 @@ sub monitor { | |||
1983 | my $full_line = ""; | 2034 | my $full_line = ""; |
1984 | 2035 | ||
1985 | open(DMESG, "> $dmesg") or | 2036 | open(DMESG, "> $dmesg") or |
1986 | die "unable to write to $dmesg"; | 2037 | dodie "unable to write to $dmesg"; |
1987 | 2038 | ||
1988 | reboot_to; | 2039 | reboot_to; |
1989 | 2040 | ||
@@ -2862,7 +2913,7 @@ sub run_bisect { | |||
2862 | sub update_bisect_replay { | 2913 | sub update_bisect_replay { |
2863 | my $tmp_log = "$tmpdir/ktest_bisect_log"; | 2914 | my $tmp_log = "$tmpdir/ktest_bisect_log"; |
2864 | run_command "git bisect log > $tmp_log" or | 2915 | run_command "git bisect log > $tmp_log" or |
2865 | die "can't create bisect log"; | 2916 | dodie "can't create bisect log"; |
2866 | return $tmp_log; | 2917 | return $tmp_log; |
2867 | } | 2918 | } |
2868 | 2919 | ||
@@ -2871,9 +2922,9 @@ sub bisect { | |||
2871 | 2922 | ||
2872 | my $result; | 2923 | my $result; |
2873 | 2924 | ||
2874 | die "BISECT_GOOD[$i] not defined\n" if (!defined($bisect_good)); | 2925 | dodie "BISECT_GOOD[$i] not defined\n" if (!defined($bisect_good)); |
2875 | die "BISECT_BAD[$i] not defined\n" if (!defined($bisect_bad)); | 2926 | dodie "BISECT_BAD[$i] not defined\n" if (!defined($bisect_bad)); |
2876 | die "BISECT_TYPE[$i] not defined\n" if (!defined($bisect_type)); | 2927 | dodie "BISECT_TYPE[$i] not defined\n" if (!defined($bisect_type)); |
2877 | 2928 | ||
2878 | my $good = $bisect_good; | 2929 | my $good = $bisect_good; |
2879 | my $bad = $bisect_bad; | 2930 | my $bad = $bisect_bad; |
@@ -2936,7 +2987,7 @@ sub bisect { | |||
2936 | if ($check ne "good") { | 2987 | if ($check ne "good") { |
2937 | doprint "TESTING BISECT BAD [$bad]\n"; | 2988 | doprint "TESTING BISECT BAD [$bad]\n"; |
2938 | run_command "git checkout $bad" or | 2989 | run_command "git checkout $bad" or |
2939 | die "Failed to checkout $bad"; | 2990 | dodie "Failed to checkout $bad"; |
2940 | 2991 | ||
2941 | $result = run_bisect $type; | 2992 | $result = run_bisect $type; |
2942 | 2993 | ||
@@ -2948,7 +2999,7 @@ sub bisect { | |||
2948 | if ($check ne "bad") { | 2999 | if ($check ne "bad") { |
2949 | doprint "TESTING BISECT GOOD [$good]\n"; | 3000 | doprint "TESTING BISECT GOOD [$good]\n"; |
2950 | run_command "git checkout $good" or | 3001 | run_command "git checkout $good" or |
2951 | die "Failed to checkout $good"; | 3002 | dodie "Failed to checkout $good"; |
2952 | 3003 | ||
2953 | $result = run_bisect $type; | 3004 | $result = run_bisect $type; |
2954 | 3005 | ||
@@ -2959,7 +3010,7 @@ sub bisect { | |||
2959 | 3010 | ||
2960 | # checkout where we started | 3011 | # checkout where we started |
2961 | run_command "git checkout $head" or | 3012 | run_command "git checkout $head" or |
2962 | die "Failed to checkout $head"; | 3013 | dodie "Failed to checkout $head"; |
2963 | } | 3014 | } |
2964 | 3015 | ||
2965 | run_command "git bisect start$start_files" or | 3016 | run_command "git bisect start$start_files" or |
@@ -3092,76 +3143,6 @@ sub create_config { | |||
3092 | make_oldconfig; | 3143 | make_oldconfig; |
3093 | } | 3144 | } |
3094 | 3145 | ||
3095 | # compare two config hashes, and return configs with different vals. | ||
3096 | # It returns B's config values, but you can use A to see what A was. | ||
3097 | sub diff_config_vals { | ||
3098 | my ($pa, $pb) = @_; | ||
3099 | |||
3100 | # crappy Perl way to pass in hashes. | ||
3101 | my %a = %{$pa}; | ||
3102 | my %b = %{$pb}; | ||
3103 | |||
3104 | my %ret; | ||
3105 | |||
3106 | foreach my $item (keys %a) { | ||
3107 | if (defined($b{$item}) && $b{$item} ne $a{$item}) { | ||
3108 | $ret{$item} = $b{$item}; | ||
3109 | } | ||
3110 | } | ||
3111 | |||
3112 | return %ret; | ||
3113 | } | ||
3114 | |||
3115 | # compare two config hashes and return the configs in B but not A | ||
3116 | sub diff_configs { | ||
3117 | my ($pa, $pb) = @_; | ||
3118 | |||
3119 | my %ret; | ||
3120 | |||
3121 | # crappy Perl way to pass in hashes. | ||
3122 | my %a = %{$pa}; | ||
3123 | my %b = %{$pb}; | ||
3124 | |||
3125 | foreach my $item (keys %b) { | ||
3126 | if (!defined($a{$item})) { | ||
3127 | $ret{$item} = $b{$item}; | ||
3128 | } | ||
3129 | } | ||
3130 | |||
3131 | return %ret; | ||
3132 | } | ||
3133 | |||
3134 | # return if two configs are equal or not | ||
3135 | # 0 is equal +1 b has something a does not | ||
3136 | # +1 if a and b have a different item. | ||
3137 | # -1 if a has something b does not | ||
3138 | sub compare_configs { | ||
3139 | my ($pa, $pb) = @_; | ||
3140 | |||
3141 | my %ret; | ||
3142 | |||
3143 | # crappy Perl way to pass in hashes. | ||
3144 | my %a = %{$pa}; | ||
3145 | my %b = %{$pb}; | ||
3146 | |||
3147 | foreach my $item (keys %b) { | ||
3148 | if (!defined($a{$item})) { | ||
3149 | return 1; | ||
3150 | } | ||
3151 | if ($a{$item} ne $b{$item}) { | ||
3152 | return 1; | ||
3153 | } | ||
3154 | } | ||
3155 | |||
3156 | foreach my $item (keys %a) { | ||
3157 | if (!defined($b{$item})) { | ||
3158 | return -1; | ||
3159 | } | ||
3160 | } | ||
3161 | |||
3162 | return 0; | ||
3163 | } | ||
3164 | |||
3165 | sub run_config_bisect_test { | 3146 | sub run_config_bisect_test { |
3166 | my ($type) = @_; | 3147 | my ($type) = @_; |
3167 | 3148 | ||
@@ -3174,166 +3155,57 @@ sub run_config_bisect_test { | |||
3174 | return $ret; | 3155 | return $ret; |
3175 | } | 3156 | } |
3176 | 3157 | ||
3177 | sub process_failed { | 3158 | sub config_bisect_end { |
3178 | my ($config) = @_; | 3159 | my ($good, $bad) = @_; |
3160 | my $diffexec = "diff -u"; | ||
3179 | 3161 | ||
3162 | if (-f "$builddir/scripts/diffconfig") { | ||
3163 | $diffexec = "$builddir/scripts/diffconfig"; | ||
3164 | } | ||
3180 | doprint "\n\n***************************************\n"; | 3165 | doprint "\n\n***************************************\n"; |
3181 | doprint "Found bad config: $config\n"; | 3166 | doprint "No more config bisecting possible.\n"; |
3167 | run_command "$diffexec $good $bad", 1; | ||
3182 | doprint "***************************************\n\n"; | 3168 | doprint "***************************************\n\n"; |
3183 | } | 3169 | } |
3184 | 3170 | ||
3185 | # used for config bisecting | ||
3186 | my $good_config; | ||
3187 | my $bad_config; | ||
3188 | |||
3189 | sub process_new_config { | ||
3190 | my ($tc, $nc, $gc, $bc) = @_; | ||
3191 | |||
3192 | my %tmp_config = %{$tc}; | ||
3193 | my %good_configs = %{$gc}; | ||
3194 | my %bad_configs = %{$bc}; | ||
3195 | |||
3196 | my %new_configs; | ||
3197 | |||
3198 | my $runtest = 1; | ||
3199 | my $ret; | ||
3200 | |||
3201 | create_config "tmp_configs", \%tmp_config; | ||
3202 | assign_configs \%new_configs, $output_config; | ||
3203 | |||
3204 | $ret = compare_configs \%new_configs, \%bad_configs; | ||
3205 | if (!$ret) { | ||
3206 | doprint "New config equals bad config, try next test\n"; | ||
3207 | $runtest = 0; | ||
3208 | } | ||
3209 | |||
3210 | if ($runtest) { | ||
3211 | $ret = compare_configs \%new_configs, \%good_configs; | ||
3212 | if (!$ret) { | ||
3213 | doprint "New config equals good config, try next test\n"; | ||
3214 | $runtest = 0; | ||
3215 | } | ||
3216 | } | ||
3217 | |||
3218 | %{$nc} = %new_configs; | ||
3219 | |||
3220 | return $runtest; | ||
3221 | } | ||
3222 | |||
3223 | sub run_config_bisect { | 3171 | sub run_config_bisect { |
3224 | my ($pgood, $pbad) = @_; | 3172 | my ($good, $bad, $last_result) = @_; |
3225 | 3173 | my $reset = ""; | |
3226 | my $type = $config_bisect_type; | 3174 | my $cmd; |
3227 | |||
3228 | my %good_configs = %{$pgood}; | ||
3229 | my %bad_configs = %{$pbad}; | ||
3230 | |||
3231 | my %diff_configs = diff_config_vals \%good_configs, \%bad_configs; | ||
3232 | my %b_configs = diff_configs \%good_configs, \%bad_configs; | ||
3233 | my %g_configs = diff_configs \%bad_configs, \%good_configs; | ||
3234 | |||
3235 | my @diff_arr = keys %diff_configs; | ||
3236 | my $len_diff = $#diff_arr + 1; | ||
3237 | |||
3238 | my @b_arr = keys %b_configs; | ||
3239 | my $len_b = $#b_arr + 1; | ||
3240 | |||
3241 | my @g_arr = keys %g_configs; | ||
3242 | my $len_g = $#g_arr + 1; | ||
3243 | |||
3244 | my $runtest = 1; | ||
3245 | my %new_configs; | ||
3246 | my $ret; | 3175 | my $ret; |
3247 | 3176 | ||
3248 | # First, lets get it down to a single subset. | 3177 | if (!length($last_result)) { |
3249 | # Is the problem with a difference in values? | 3178 | $reset = "-r"; |
3250 | # Is the problem with a missing config? | ||
3251 | # Is the problem with a config that breaks things? | ||
3252 | |||
3253 | # Enable all of one set and see if we get a new bad | ||
3254 | # or good config. | ||
3255 | |||
3256 | # first set the good config to the bad values. | ||
3257 | |||
3258 | doprint "d=$len_diff g=$len_g b=$len_b\n"; | ||
3259 | |||
3260 | # first lets enable things in bad config that are enabled in good config | ||
3261 | |||
3262 | if ($len_diff > 0) { | ||
3263 | if ($len_b > 0 || $len_g > 0) { | ||
3264 | my %tmp_config = %bad_configs; | ||
3265 | |||
3266 | doprint "Set tmp config to be bad config with good config values\n"; | ||
3267 | foreach my $item (@diff_arr) { | ||
3268 | $tmp_config{$item} = $good_configs{$item}; | ||
3269 | } | ||
3270 | |||
3271 | $runtest = process_new_config \%tmp_config, \%new_configs, | ||
3272 | \%good_configs, \%bad_configs; | ||
3273 | } | ||
3274 | } | 3179 | } |
3180 | run_command "$config_bisect_exec $reset -b $outputdir $good $bad $last_result", 1; | ||
3275 | 3181 | ||
3276 | if (!$runtest && $len_diff > 0) { | 3182 | # config-bisect returns: |
3277 | 3183 | # 0 if there is more to bisect | |
3278 | if ($len_diff == 1) { | 3184 | # 1 for finding a good config |
3279 | process_failed $diff_arr[0]; | 3185 | # 2 if it can not find any more configs |
3280 | return 1; | 3186 | # -1 (255) on error |
3281 | } | 3187 | if ($run_command_status) { |
3282 | my %tmp_config = %bad_configs; | 3188 | return $run_command_status; |
3283 | |||
3284 | my $half = int($#diff_arr / 2); | ||
3285 | my @tophalf = @diff_arr[0 .. $half]; | ||
3286 | |||
3287 | doprint "Settings bisect with top half:\n"; | ||
3288 | doprint "Set tmp config to be bad config with some good config values\n"; | ||
3289 | foreach my $item (@tophalf) { | ||
3290 | $tmp_config{$item} = $good_configs{$item}; | ||
3291 | } | ||
3292 | |||
3293 | $runtest = process_new_config \%tmp_config, \%new_configs, | ||
3294 | \%good_configs, \%bad_configs; | ||
3295 | |||
3296 | if (!$runtest) { | ||
3297 | my %tmp_config = %bad_configs; | ||
3298 | |||
3299 | doprint "Try bottom half\n"; | ||
3300 | |||
3301 | my @bottomhalf = @diff_arr[$half+1 .. $#diff_arr]; | ||
3302 | |||
3303 | foreach my $item (@bottomhalf) { | ||
3304 | $tmp_config{$item} = $good_configs{$item}; | ||
3305 | } | ||
3306 | |||
3307 | $runtest = process_new_config \%tmp_config, \%new_configs, | ||
3308 | \%good_configs, \%bad_configs; | ||
3309 | } | ||
3310 | } | 3189 | } |
3311 | 3190 | ||
3312 | if ($runtest) { | 3191 | $ret = run_config_bisect_test $config_bisect_type; |
3313 | $ret = run_config_bisect_test $type; | 3192 | if ($ret) { |
3314 | if ($ret) { | 3193 | doprint "NEW GOOD CONFIG\n"; |
3315 | doprint "NEW GOOD CONFIG\n"; | 3194 | # Return 3 for good config |
3316 | %good_configs = %new_configs; | 3195 | return 3; |
3317 | run_command "mv $good_config ${good_config}.last"; | 3196 | } else { |
3318 | save_config \%good_configs, $good_config; | 3197 | doprint "NEW BAD CONFIG\n"; |
3319 | %{$pgood} = %good_configs; | 3198 | # Return 4 for bad config |
3320 | } else { | 3199 | return 4; |
3321 | doprint "NEW BAD CONFIG\n"; | ||
3322 | %bad_configs = %new_configs; | ||
3323 | run_command "mv $bad_config ${bad_config}.last"; | ||
3324 | save_config \%bad_configs, $bad_config; | ||
3325 | %{$pbad} = %bad_configs; | ||
3326 | } | ||
3327 | return 0; | ||
3328 | } | 3200 | } |
3329 | |||
3330 | fail "Hmm, need to do a mix match?\n"; | ||
3331 | return -1; | ||
3332 | } | 3201 | } |
3333 | 3202 | ||
3334 | sub config_bisect { | 3203 | sub config_bisect { |
3335 | my ($i) = @_; | 3204 | my ($i) = @_; |
3336 | 3205 | ||
3206 | my $good_config; | ||
3207 | my $bad_config; | ||
3208 | |||
3337 | my $type = $config_bisect_type; | 3209 | my $type = $config_bisect_type; |
3338 | my $ret; | 3210 | my $ret; |
3339 | 3211 | ||
@@ -3353,6 +3225,24 @@ sub config_bisect { | |||
3353 | $good_config = $output_config; | 3225 | $good_config = $output_config; |
3354 | } | 3226 | } |
3355 | 3227 | ||
3228 | if (!defined($config_bisect_exec)) { | ||
3229 | # First check the location that ktest.pl ran | ||
3230 | my @locations = ( "$pwd/config-bisect.pl", | ||
3231 | "$dirname/config-bisect.pl", | ||
3232 | "$builddir/tools/testing/ktest/config-bisect.pl", | ||
3233 | undef ); | ||
3234 | foreach my $loc (@locations) { | ||
3235 | doprint "loc = $loc\n"; | ||
3236 | $config_bisect_exec = $loc; | ||
3237 | last if (defined($config_bisect_exec && -x $config_bisect_exec)); | ||
3238 | } | ||
3239 | if (!defined($config_bisect_exec)) { | ||
3240 | fail "Could not find an executable config-bisect.pl\n", | ||
3241 | " Set CONFIG_BISECT_EXEC to point to config-bisect.pl"; | ||
3242 | return 1; | ||
3243 | } | ||
3244 | } | ||
3245 | |||
3356 | # we don't want min configs to cause issues here. | 3246 | # we don't want min configs to cause issues here. |
3357 | doprint "Disabling 'MIN_CONFIG' for this test\n"; | 3247 | doprint "Disabling 'MIN_CONFIG' for this test\n"; |
3358 | undef $minconfig; | 3248 | undef $minconfig; |
@@ -3361,21 +3251,31 @@ sub config_bisect { | |||
3361 | my %bad_configs; | 3251 | my %bad_configs; |
3362 | my %tmp_configs; | 3252 | my %tmp_configs; |
3363 | 3253 | ||
3254 | if (-f "$tmpdir/good_config.tmp" || -f "$tmpdir/bad_config.tmp") { | ||
3255 | if (read_yn "Interrupted config-bisect. Continue (n - will start new)?") { | ||
3256 | if (-f "$tmpdir/good_config.tmp") { | ||
3257 | $good_config = "$tmpdir/good_config.tmp"; | ||
3258 | } else { | ||
3259 | $good_config = "$tmpdir/good_config"; | ||
3260 | } | ||
3261 | if (-f "$tmpdir/bad_config.tmp") { | ||
3262 | $bad_config = "$tmpdir/bad_config.tmp"; | ||
3263 | } else { | ||
3264 | $bad_config = "$tmpdir/bad_config"; | ||
3265 | } | ||
3266 | } | ||
3267 | } | ||
3364 | doprint "Run good configs through make oldconfig\n"; | 3268 | doprint "Run good configs through make oldconfig\n"; |
3365 | assign_configs \%tmp_configs, $good_config; | 3269 | assign_configs \%tmp_configs, $good_config; |
3366 | create_config "$good_config", \%tmp_configs; | 3270 | create_config "$good_config", \%tmp_configs; |
3367 | assign_configs \%good_configs, $output_config; | 3271 | $good_config = "$tmpdir/good_config"; |
3272 | system("cp $output_config $good_config") == 0 or dodie "cp good config"; | ||
3368 | 3273 | ||
3369 | doprint "Run bad configs through make oldconfig\n"; | 3274 | doprint "Run bad configs through make oldconfig\n"; |
3370 | assign_configs \%tmp_configs, $bad_config; | 3275 | assign_configs \%tmp_configs, $bad_config; |
3371 | create_config "$bad_config", \%tmp_configs; | 3276 | create_config "$bad_config", \%tmp_configs; |
3372 | assign_configs \%bad_configs, $output_config; | ||
3373 | |||
3374 | $good_config = "$tmpdir/good_config"; | ||
3375 | $bad_config = "$tmpdir/bad_config"; | 3277 | $bad_config = "$tmpdir/bad_config"; |
3376 | 3278 | system("cp $output_config $bad_config") == 0 or dodie "cp bad config"; | |
3377 | save_config \%good_configs, $good_config; | ||
3378 | save_config \%bad_configs, $bad_config; | ||
3379 | 3279 | ||
3380 | if (defined($config_bisect_check) && $config_bisect_check ne "0") { | 3280 | if (defined($config_bisect_check) && $config_bisect_check ne "0") { |
3381 | if ($config_bisect_check ne "good") { | 3281 | if ($config_bisect_check ne "good") { |
@@ -3398,10 +3298,21 @@ sub config_bisect { | |||
3398 | } | 3298 | } |
3399 | } | 3299 | } |
3400 | 3300 | ||
3301 | my $last_run = ""; | ||
3302 | |||
3401 | do { | 3303 | do { |
3402 | $ret = run_config_bisect \%good_configs, \%bad_configs; | 3304 | $ret = run_config_bisect $good_config, $bad_config, $last_run; |
3305 | if ($ret == 3) { | ||
3306 | $last_run = "good"; | ||
3307 | } elsif ($ret == 4) { | ||
3308 | $last_run = "bad"; | ||
3309 | } | ||
3403 | print_times; | 3310 | print_times; |
3404 | } while (!$ret); | 3311 | } while ($ret == 3 || $ret == 4); |
3312 | |||
3313 | if ($ret == 2) { | ||
3314 | config_bisect_end "$good_config.tmp", "$bad_config.tmp"; | ||
3315 | } | ||
3405 | 3316 | ||
3406 | return $ret if ($ret < 0); | 3317 | return $ret if ($ret < 0); |
3407 | 3318 | ||
@@ -3416,9 +3327,9 @@ sub patchcheck_reboot { | |||
3416 | sub patchcheck { | 3327 | sub patchcheck { |
3417 | my ($i) = @_; | 3328 | my ($i) = @_; |
3418 | 3329 | ||
3419 | die "PATCHCHECK_START[$i] not defined\n" | 3330 | dodie "PATCHCHECK_START[$i] not defined\n" |
3420 | if (!defined($patchcheck_start)); | 3331 | if (!defined($patchcheck_start)); |
3421 | die "PATCHCHECK_TYPE[$i] not defined\n" | 3332 | dodie "PATCHCHECK_TYPE[$i] not defined\n" |
3422 | if (!defined($patchcheck_type)); | 3333 | if (!defined($patchcheck_type)); |
3423 | 3334 | ||
3424 | my $start = $patchcheck_start; | 3335 | my $start = $patchcheck_start; |
@@ -3432,7 +3343,7 @@ sub patchcheck { | |||
3432 | if (defined($patchcheck_end)) { | 3343 | if (defined($patchcheck_end)) { |
3433 | $end = $patchcheck_end; | 3344 | $end = $patchcheck_end; |
3434 | } elsif ($cherry) { | 3345 | } elsif ($cherry) { |
3435 | die "PATCHCHECK_END must be defined with PATCHCHECK_CHERRY\n"; | 3346 | dodie "PATCHCHECK_END must be defined with PATCHCHECK_CHERRY\n"; |
3436 | } | 3347 | } |
3437 | 3348 | ||
3438 | # Get the true sha1's since we can use things like HEAD~3 | 3349 | # Get the true sha1's since we can use things like HEAD~3 |
@@ -3496,7 +3407,7 @@ sub patchcheck { | |||
3496 | doprint "\nProcessing commit \"$item\"\n\n"; | 3407 | doprint "\nProcessing commit \"$item\"\n\n"; |
3497 | 3408 | ||
3498 | run_command "git checkout $sha1" or | 3409 | run_command "git checkout $sha1" or |
3499 | die "Failed to checkout $sha1"; | 3410 | dodie "Failed to checkout $sha1"; |
3500 | 3411 | ||
3501 | # only clean on the first and last patch | 3412 | # only clean on the first and last patch |
3502 | if ($item eq $list[0] || | 3413 | if ($item eq $list[0] || |
@@ -3587,7 +3498,7 @@ sub read_kconfig { | |||
3587 | } | 3498 | } |
3588 | 3499 | ||
3589 | open(KIN, "$kconfig") | 3500 | open(KIN, "$kconfig") |
3590 | or die "Can't open $kconfig"; | 3501 | or dodie "Can't open $kconfig"; |
3591 | while (<KIN>) { | 3502 | while (<KIN>) { |
3592 | chomp; | 3503 | chomp; |
3593 | 3504 | ||
@@ -3746,7 +3657,7 @@ sub get_depends { | |||
3746 | 3657 | ||
3747 | $dep =~ s/^[^$valid]*[$valid]+//; | 3658 | $dep =~ s/^[^$valid]*[$valid]+//; |
3748 | } else { | 3659 | } else { |
3749 | die "this should never happen"; | 3660 | dodie "this should never happen"; |
3750 | } | 3661 | } |
3751 | } | 3662 | } |
3752 | 3663 | ||
@@ -4007,7 +3918,7 @@ sub make_min_config { | |||
4007 | # update new ignore configs | 3918 | # update new ignore configs |
4008 | if (defined($ignore_config)) { | 3919 | if (defined($ignore_config)) { |
4009 | open (OUT, ">$temp_config") | 3920 | open (OUT, ">$temp_config") |
4010 | or die "Can't write to $temp_config"; | 3921 | or dodie "Can't write to $temp_config"; |
4011 | foreach my $config (keys %save_configs) { | 3922 | foreach my $config (keys %save_configs) { |
4012 | print OUT "$save_configs{$config}\n"; | 3923 | print OUT "$save_configs{$config}\n"; |
4013 | } | 3924 | } |
@@ -4035,7 +3946,7 @@ sub make_min_config { | |||
4035 | 3946 | ||
4036 | # Save off all the current mandatory configs | 3947 | # Save off all the current mandatory configs |
4037 | open (OUT, ">$temp_config") | 3948 | open (OUT, ">$temp_config") |
4038 | or die "Can't write to $temp_config"; | 3949 | or dodie "Can't write to $temp_config"; |
4039 | foreach my $config (keys %keep_configs) { | 3950 | foreach my $config (keys %keep_configs) { |
4040 | print OUT "$keep_configs{$config}\n"; | 3951 | print OUT "$keep_configs{$config}\n"; |
4041 | } | 3952 | } |
@@ -4222,6 +4133,74 @@ sub set_test_option { | |||
4222 | return eval_option($name, $option, $i); | 4133 | return eval_option($name, $option, $i); |
4223 | } | 4134 | } |
4224 | 4135 | ||
4136 | sub find_mailer { | ||
4137 | my ($mailer) = @_; | ||
4138 | |||
4139 | my @paths = split /:/, $ENV{PATH}; | ||
4140 | |||
4141 | # sendmail is usually in /usr/sbin | ||
4142 | $paths[$#paths + 1] = "/usr/sbin"; | ||
4143 | |||
4144 | foreach my $path (@paths) { | ||
4145 | if (-x "$path/$mailer") { | ||
4146 | return $path; | ||
4147 | } | ||
4148 | } | ||
4149 | |||
4150 | return undef; | ||
4151 | } | ||
4152 | |||
4153 | sub do_send_mail { | ||
4154 | my ($subject, $message) = @_; | ||
4155 | |||
4156 | if (!defined($mail_path)) { | ||
4157 | # find the mailer | ||
4158 | $mail_path = find_mailer $mailer; | ||
4159 | if (!defined($mail_path)) { | ||
4160 | die "\nCan not find $mailer in PATH\n"; | ||
4161 | } | ||
4162 | } | ||
4163 | |||
4164 | if (!defined($mail_command)) { | ||
4165 | if ($mailer eq "mail" || $mailer eq "mailx") { | ||
4166 | $mail_command = "\$MAIL_PATH/\$MAILER -s \'\$SUBJECT\' \$MAILTO <<< \'\$MESSAGE\'"; | ||
4167 | } elsif ($mailer eq "sendmail" ) { | ||
4168 | $mail_command = "echo \'Subject: \$SUBJECT\n\n\$MESSAGE\' | \$MAIL_PATH/\$MAILER -t \$MAILTO"; | ||
4169 | } else { | ||
4170 | die "\nYour mailer: $mailer is not supported.\n"; | ||
4171 | } | ||
4172 | } | ||
4173 | |||
4174 | $mail_command =~ s/\$MAILER/$mailer/g; | ||
4175 | $mail_command =~ s/\$MAIL_PATH/$mail_path/g; | ||
4176 | $mail_command =~ s/\$MAILTO/$mailto/g; | ||
4177 | $mail_command =~ s/\$SUBJECT/$subject/g; | ||
4178 | $mail_command =~ s/\$MESSAGE/$message/g; | ||
4179 | |||
4180 | run_command $mail_command; | ||
4181 | } | ||
4182 | |||
4183 | sub send_email { | ||
4184 | |||
4185 | if (defined($mailto)) { | ||
4186 | if (!defined($mailer)) { | ||
4187 | doprint "No email sent: email or mailer not specified in config.\n"; | ||
4188 | return; | ||
4189 | } | ||
4190 | do_send_mail @_; | ||
4191 | } | ||
4192 | } | ||
4193 | |||
4194 | sub cancel_test { | ||
4195 | if ($email_when_canceled) { | ||
4196 | send_email("KTEST: Your [$test_type] test was cancelled", | ||
4197 | "Your test started at $script_start_time was cancelled: sig int"); | ||
4198 | } | ||
4199 | die "\nCaught Sig Int, test interrupted: $!\n" | ||
4200 | } | ||
4201 | |||
4202 | $SIG{INT} = qw(cancel_test); | ||
4203 | |||
4225 | # First we need to do is the builds | 4204 | # First we need to do is the builds |
4226 | for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | 4205 | for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { |
4227 | 4206 | ||
@@ -4245,11 +4224,11 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
4245 | $outputdir = set_test_option("OUTPUT_DIR", $i); | 4224 | $outputdir = set_test_option("OUTPUT_DIR", $i); |
4246 | $builddir = set_test_option("BUILD_DIR", $i); | 4225 | $builddir = set_test_option("BUILD_DIR", $i); |
4247 | 4226 | ||
4248 | chdir $builddir || die "can't change directory to $builddir"; | 4227 | chdir $builddir || dodie "can't change directory to $builddir"; |
4249 | 4228 | ||
4250 | if (!-d $outputdir) { | 4229 | if (!-d $outputdir) { |
4251 | mkpath($outputdir) or | 4230 | mkpath($outputdir) or |
4252 | die "can't create $outputdir"; | 4231 | dodie "can't create $outputdir"; |
4253 | } | 4232 | } |
4254 | 4233 | ||
4255 | $make = "$makecmd O=$outputdir"; | 4234 | $make = "$makecmd O=$outputdir"; |
@@ -4262,9 +4241,15 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
4262 | $start_minconfig_defined = 1; | 4241 | $start_minconfig_defined = 1; |
4263 | 4242 | ||
4264 | # The first test may override the PRE_KTEST option | 4243 | # The first test may override the PRE_KTEST option |
4265 | if (defined($pre_ktest) && $i == 1) { | 4244 | if ($i == 1) { |
4266 | doprint "\n"; | 4245 | if (defined($pre_ktest)) { |
4267 | run_command $pre_ktest; | 4246 | doprint "\n"; |
4247 | run_command $pre_ktest; | ||
4248 | } | ||
4249 | if ($email_when_started) { | ||
4250 | send_email("KTEST: Your [$test_type] test was started", | ||
4251 | "Your test was started on $script_start_time"); | ||
4252 | } | ||
4268 | } | 4253 | } |
4269 | 4254 | ||
4270 | # Any test can override the POST_KTEST option | 4255 | # Any test can override the POST_KTEST option |
@@ -4280,7 +4265,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
4280 | 4265 | ||
4281 | if (!-d $tmpdir) { | 4266 | if (!-d $tmpdir) { |
4282 | mkpath($tmpdir) or | 4267 | mkpath($tmpdir) or |
4283 | die "can't create $tmpdir"; | 4268 | dodie "can't create $tmpdir"; |
4284 | } | 4269 | } |
4285 | 4270 | ||
4286 | $ENV{"SSH_USER"} = $ssh_user; | 4271 | $ENV{"SSH_USER"} = $ssh_user; |
@@ -4353,7 +4338,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
4353 | 4338 | ||
4354 | if (defined($checkout)) { | 4339 | if (defined($checkout)) { |
4355 | run_command "git checkout $checkout" or | 4340 | run_command "git checkout $checkout" or |
4356 | die "failed to checkout $checkout"; | 4341 | dodie "failed to checkout $checkout"; |
4357 | } | 4342 | } |
4358 | 4343 | ||
4359 | $no_reboot = 0; | 4344 | $no_reboot = 0; |
@@ -4428,4 +4413,8 @@ if ($opt{"POWEROFF_ON_SUCCESS"}) { | |||
4428 | 4413 | ||
4429 | doprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n"; | 4414 | doprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n"; |
4430 | 4415 | ||
4416 | if ($email_when_finished) { | ||
4417 | send_email("KTEST: Your [$test_type] test has finished!", | ||
4418 | "$successes of $opt{NUM_TESTS} tests started at $script_start_time were successful!"); | ||
4419 | } | ||
4431 | exit 0; | 4420 | exit 0; |
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 6c58cd8bbbae..6ca6ca0ce695 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf | |||
@@ -1,6 +1,11 @@ | |||
1 | # | 1 | # |
2 | # Config file for ktest.pl | 2 | # Config file for ktest.pl |
3 | # | 3 | # |
4 | # Place your customized version of this, in the working directory that | ||
5 | # ktest.pl is run from. By default, ktest.pl will look for a file | ||
6 | # called "ktest.conf", but you can name it anything you like and specify | ||
7 | # the name of your config file as the first argument of ktest.pl. | ||
8 | # | ||
4 | # Note, all paths must be absolute | 9 | # Note, all paths must be absolute |
5 | # | 10 | # |
6 | 11 | ||
@@ -396,6 +401,44 @@ | |||
396 | 401 | ||
397 | #### Optional Config Options (all have defaults) #### | 402 | #### Optional Config Options (all have defaults) #### |
398 | 403 | ||
404 | # Email options for receiving notifications. Users must setup | ||
405 | # the specified mailer prior to using this feature. | ||
406 | # | ||
407 | # (default undefined) | ||
408 | #MAILTO = | ||
409 | # | ||
410 | # Supported mailers: sendmail, mail, mailx | ||
411 | # (default sendmail) | ||
412 | #MAILER = sendmail | ||
413 | # | ||
414 | # The executable to run | ||
415 | # (default: for sendmail "/usr/sbin/sendmail", otherwise equals ${MAILER}) | ||
416 | #MAIL_EXEC = /usr/sbin/sendmail | ||
417 | # | ||
418 | # The command used to send mail, which uses the above options | ||
419 | # can be modified. By default if the mailer is "sendmail" then | ||
420 | # MAIL_COMMAND = echo \'Subject: $SUBJECT\n\n$MESSAGE\' | $MAIL_PATH/$MAILER -t $MAILTO | ||
421 | # For mail or mailx: | ||
422 | # MAIL_COMMAND = "$MAIL_PATH/$MAILER -s \'$SUBJECT\' $MAILTO <<< \'$MESSAGE\' | ||
423 | # ktest.pl will do the substitution for MAIL_PATH, MAILER, MAILTO at the time | ||
424 | # it sends the mail if "$FOO" format is used. If "${FOO}" format is used, | ||
425 | # then the substitutions will occur at the time the config file is read. | ||
426 | # But note, MAIL_PATH and MAILER require being set by the config file if | ||
427 | # ${MAIL_PATH} or ${MAILER} are used, but not if $MAIL_PATH or $MAILER are. | ||
428 | #MAIL_COMMAND = echo \'Subject: $SUBJECT\n\n$MESSAGE\' | $MAIL_PATH/$MAILER -t $MAILTO | ||
429 | # | ||
430 | # Errors are defined as those would terminate the script | ||
431 | # (default 1) | ||
432 | #EMAIL_ON_ERROR = 1 | ||
433 | # (default 1) | ||
434 | #EMAIL_WHEN_FINISHED = 1 | ||
435 | # (default 0) | ||
436 | #EMAIL_WHEN_STARTED = 1 | ||
437 | # | ||
438 | # Users can cancel the test by Ctrl^C | ||
439 | # (default 0) | ||
440 | #EMAIL_WHEN_CANCELED = 1 | ||
441 | |||
399 | # Start a test setup. If you leave this off, all options | 442 | # Start a test setup. If you leave this off, all options |
400 | # will be default and the test will run once. | 443 | # will be default and the test will run once. |
401 | # This is a label and not really an option (it takes no value). | 444 | # This is a label and not really an option (it takes no value). |
@@ -725,6 +768,13 @@ | |||
725 | # (default 120) | 768 | # (default 120) |
726 | #TIMEOUT = 120 | 769 | #TIMEOUT = 120 |
727 | 770 | ||
771 | # The timeout in seconds when to test if the box can be rebooted | ||
772 | # or not. Before issuing the reboot command, a ssh connection | ||
773 | # is attempted to see if the target machine is still active. | ||
774 | # If the target does not connect within this timeout, a power cycle | ||
775 | # is issued instead of a reboot. | ||
776 | # CONNECT_TIMEOUT = 25 | ||
777 | |||
728 | # In between tests, a reboot of the box may occur, and this | 778 | # In between tests, a reboot of the box may occur, and this |
729 | # is the time to wait for the console after it stops producing | 779 | # is the time to wait for the console after it stops producing |
730 | # output. Some machines may not produce a large lag on reboot | 780 | # output. Some machines may not produce a large lag on reboot |
@@ -1167,6 +1217,16 @@ | |||
1167 | # Set it to "good" to test only the good config and set it | 1217 | # Set it to "good" to test only the good config and set it |
1168 | # to "bad" to only test the bad config. | 1218 | # to "bad" to only test the bad config. |
1169 | # | 1219 | # |
1220 | # CONFIG_BISECT_EXEC (optional) | ||
1221 | # The config bisect is a separate program that comes with ktest.pl. | ||
1222 | # By befault, it will look for: | ||
1223 | # `pwd`/config-bisect.pl # the location ktest.pl was executed from. | ||
1224 | # If it does not find it there, it will look for: | ||
1225 | # `dirname <ktest.pl>`/config-bisect.pl # The directory that holds ktest.pl | ||
1226 | # If it does not find it there, it will look for: | ||
1227 | # ${BUILD_DIR}/tools/testing/ktest/config-bisect.pl | ||
1228 | # Setting CONFIG_BISECT_EXEC will override where it looks. | ||
1229 | # | ||
1170 | # Example: | 1230 | # Example: |
1171 | # TEST_START | 1231 | # TEST_START |
1172 | # TEST_TYPE = config_bisect | 1232 | # TEST_TYPE = config_bisect |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 620fa78b3b1b..cb166be4918d 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -104,7 +104,8 @@ enum { | |||
104 | NUM_HINTS = 8, | 104 | NUM_HINTS = 8, |
105 | NUM_BDW = NUM_DCR, | 105 | NUM_BDW = NUM_DCR, |
106 | NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW, | 106 | NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW, |
107 | NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ + 4 /* spa1 iset */, | 107 | NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ |
108 | + 4 /* spa1 iset */ + 1 /* spa11 iset */, | ||
108 | DIMM_SIZE = SZ_32M, | 109 | DIMM_SIZE = SZ_32M, |
109 | LABEL_SIZE = SZ_128K, | 110 | LABEL_SIZE = SZ_128K, |
110 | SPA_VCD_SIZE = SZ_4M, | 111 | SPA_VCD_SIZE = SZ_4M, |
@@ -153,6 +154,7 @@ struct nfit_test { | |||
153 | void *nfit_buf; | 154 | void *nfit_buf; |
154 | dma_addr_t nfit_dma; | 155 | dma_addr_t nfit_dma; |
155 | size_t nfit_size; | 156 | size_t nfit_size; |
157 | size_t nfit_filled; | ||
156 | int dcr_idx; | 158 | int dcr_idx; |
157 | int num_dcr; | 159 | int num_dcr; |
158 | int num_pm; | 160 | int num_pm; |
@@ -709,7 +711,9 @@ static void smart_notify(struct device *bus_dev, | |||
709 | >= thresh->media_temperature) | 711 | >= thresh->media_temperature) |
710 | || ((thresh->alarm_control & ND_INTEL_SMART_CTEMP_TRIP) | 712 | || ((thresh->alarm_control & ND_INTEL_SMART_CTEMP_TRIP) |
711 | && smart->ctrl_temperature | 713 | && smart->ctrl_temperature |
712 | >= thresh->ctrl_temperature)) { | 714 | >= thresh->ctrl_temperature) |
715 | || (smart->health != ND_INTEL_SMART_NON_CRITICAL_HEALTH) | ||
716 | || (smart->shutdown_state != 0)) { | ||
713 | device_lock(bus_dev); | 717 | device_lock(bus_dev); |
714 | __acpi_nvdimm_notify(dimm_dev, 0x81); | 718 | __acpi_nvdimm_notify(dimm_dev, 0x81); |
715 | device_unlock(bus_dev); | 719 | device_unlock(bus_dev); |
@@ -735,6 +739,32 @@ static int nfit_test_cmd_smart_set_threshold( | |||
735 | return 0; | 739 | return 0; |
736 | } | 740 | } |
737 | 741 | ||
742 | static int nfit_test_cmd_smart_inject( | ||
743 | struct nd_intel_smart_inject *inj, | ||
744 | unsigned int buf_len, | ||
745 | struct nd_intel_smart_threshold *thresh, | ||
746 | struct nd_intel_smart *smart, | ||
747 | struct device *bus_dev, struct device *dimm_dev) | ||
748 | { | ||
749 | if (buf_len != sizeof(*inj)) | ||
750 | return -EINVAL; | ||
751 | |||
752 | if (inj->mtemp_enable) | ||
753 | smart->media_temperature = inj->media_temperature; | ||
754 | if (inj->spare_enable) | ||
755 | smart->spares = inj->spares; | ||
756 | if (inj->fatal_enable) | ||
757 | smart->health = ND_INTEL_SMART_FATAL_HEALTH; | ||
758 | if (inj->unsafe_shutdown_enable) { | ||
759 | smart->shutdown_state = 1; | ||
760 | smart->shutdown_count++; | ||
761 | } | ||
762 | inj->status = 0; | ||
763 | smart_notify(bus_dev, dimm_dev, smart, thresh); | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | |||
738 | static void uc_error_notify(struct work_struct *work) | 768 | static void uc_error_notify(struct work_struct *work) |
739 | { | 769 | { |
740 | struct nfit_test *t = container_of(work, typeof(*t), work); | 770 | struct nfit_test *t = container_of(work, typeof(*t), work); |
@@ -935,6 +965,13 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
935 | t->dcr_idx], | 965 | t->dcr_idx], |
936 | &t->smart[i - t->dcr_idx], | 966 | &t->smart[i - t->dcr_idx], |
937 | &t->pdev.dev, t->dimm_dev[i]); | 967 | &t->pdev.dev, t->dimm_dev[i]); |
968 | case ND_INTEL_SMART_INJECT: | ||
969 | return nfit_test_cmd_smart_inject(buf, | ||
970 | buf_len, | ||
971 | &t->smart_threshold[i - | ||
972 | t->dcr_idx], | ||
973 | &t->smart[i - t->dcr_idx], | ||
974 | &t->pdev.dev, t->dimm_dev[i]); | ||
938 | default: | 975 | default: |
939 | return -ENOTTY; | 976 | return -ENOTTY; |
940 | } | 977 | } |
@@ -1222,7 +1259,7 @@ static void smart_init(struct nfit_test *t) | |||
1222 | | ND_INTEL_SMART_MTEMP_VALID, | 1259 | | ND_INTEL_SMART_MTEMP_VALID, |
1223 | .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, | 1260 | .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, |
1224 | .media_temperature = 23 * 16, | 1261 | .media_temperature = 23 * 16, |
1225 | .ctrl_temperature = 30 * 16, | 1262 | .ctrl_temperature = 25 * 16, |
1226 | .pmic_temperature = 40 * 16, | 1263 | .pmic_temperature = 40 * 16, |
1227 | .spares = 75, | 1264 | .spares = 75, |
1228 | .alarm_flags = ND_INTEL_SMART_SPARE_TRIP | 1265 | .alarm_flags = ND_INTEL_SMART_SPARE_TRIP |
@@ -1366,7 +1403,7 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1366 | struct acpi_nfit_data_region *bdw; | 1403 | struct acpi_nfit_data_region *bdw; |
1367 | struct acpi_nfit_flush_address *flush; | 1404 | struct acpi_nfit_flush_address *flush; |
1368 | struct acpi_nfit_capabilities *pcap; | 1405 | struct acpi_nfit_capabilities *pcap; |
1369 | unsigned int offset, i; | 1406 | unsigned int offset = 0, i; |
1370 | 1407 | ||
1371 | /* | 1408 | /* |
1372 | * spa0 (interleave first half of dimm0 and dimm1, note storage | 1409 | * spa0 (interleave first half of dimm0 and dimm1, note storage |
@@ -1380,93 +1417,102 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1380 | spa->range_index = 0+1; | 1417 | spa->range_index = 0+1; |
1381 | spa->address = t->spa_set_dma[0]; | 1418 | spa->address = t->spa_set_dma[0]; |
1382 | spa->length = SPA0_SIZE; | 1419 | spa->length = SPA0_SIZE; |
1420 | offset += spa->header.length; | ||
1383 | 1421 | ||
1384 | /* | 1422 | /* |
1385 | * spa1 (interleave last half of the 4 DIMMS, note storage | 1423 | * spa1 (interleave last half of the 4 DIMMS, note storage |
1386 | * does not actually alias the related block-data-window | 1424 | * does not actually alias the related block-data-window |
1387 | * regions) | 1425 | * regions) |
1388 | */ | 1426 | */ |
1389 | spa = nfit_buf + sizeof(*spa); | 1427 | spa = nfit_buf + offset; |
1390 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1428 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1391 | spa->header.length = sizeof(*spa); | 1429 | spa->header.length = sizeof(*spa); |
1392 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); | 1430 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); |
1393 | spa->range_index = 1+1; | 1431 | spa->range_index = 1+1; |
1394 | spa->address = t->spa_set_dma[1]; | 1432 | spa->address = t->spa_set_dma[1]; |
1395 | spa->length = SPA1_SIZE; | 1433 | spa->length = SPA1_SIZE; |
1434 | offset += spa->header.length; | ||
1396 | 1435 | ||
1397 | /* spa2 (dcr0) dimm0 */ | 1436 | /* spa2 (dcr0) dimm0 */ |
1398 | spa = nfit_buf + sizeof(*spa) * 2; | 1437 | spa = nfit_buf + offset; |
1399 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1438 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1400 | spa->header.length = sizeof(*spa); | 1439 | spa->header.length = sizeof(*spa); |
1401 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); | 1440 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); |
1402 | spa->range_index = 2+1; | 1441 | spa->range_index = 2+1; |
1403 | spa->address = t->dcr_dma[0]; | 1442 | spa->address = t->dcr_dma[0]; |
1404 | spa->length = DCR_SIZE; | 1443 | spa->length = DCR_SIZE; |
1444 | offset += spa->header.length; | ||
1405 | 1445 | ||
1406 | /* spa3 (dcr1) dimm1 */ | 1446 | /* spa3 (dcr1) dimm1 */ |
1407 | spa = nfit_buf + sizeof(*spa) * 3; | 1447 | spa = nfit_buf + offset; |
1408 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1448 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1409 | spa->header.length = sizeof(*spa); | 1449 | spa->header.length = sizeof(*spa); |
1410 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); | 1450 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); |
1411 | spa->range_index = 3+1; | 1451 | spa->range_index = 3+1; |
1412 | spa->address = t->dcr_dma[1]; | 1452 | spa->address = t->dcr_dma[1]; |
1413 | spa->length = DCR_SIZE; | 1453 | spa->length = DCR_SIZE; |
1454 | offset += spa->header.length; | ||
1414 | 1455 | ||
1415 | /* spa4 (dcr2) dimm2 */ | 1456 | /* spa4 (dcr2) dimm2 */ |
1416 | spa = nfit_buf + sizeof(*spa) * 4; | 1457 | spa = nfit_buf + offset; |
1417 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1458 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1418 | spa->header.length = sizeof(*spa); | 1459 | spa->header.length = sizeof(*spa); |
1419 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); | 1460 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); |
1420 | spa->range_index = 4+1; | 1461 | spa->range_index = 4+1; |
1421 | spa->address = t->dcr_dma[2]; | 1462 | spa->address = t->dcr_dma[2]; |
1422 | spa->length = DCR_SIZE; | 1463 | spa->length = DCR_SIZE; |
1464 | offset += spa->header.length; | ||
1423 | 1465 | ||
1424 | /* spa5 (dcr3) dimm3 */ | 1466 | /* spa5 (dcr3) dimm3 */ |
1425 | spa = nfit_buf + sizeof(*spa) * 5; | 1467 | spa = nfit_buf + offset; |
1426 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1468 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1427 | spa->header.length = sizeof(*spa); | 1469 | spa->header.length = sizeof(*spa); |
1428 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); | 1470 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); |
1429 | spa->range_index = 5+1; | 1471 | spa->range_index = 5+1; |
1430 | spa->address = t->dcr_dma[3]; | 1472 | spa->address = t->dcr_dma[3]; |
1431 | spa->length = DCR_SIZE; | 1473 | spa->length = DCR_SIZE; |
1474 | offset += spa->header.length; | ||
1432 | 1475 | ||
1433 | /* spa6 (bdw for dcr0) dimm0 */ | 1476 | /* spa6 (bdw for dcr0) dimm0 */ |
1434 | spa = nfit_buf + sizeof(*spa) * 6; | 1477 | spa = nfit_buf + offset; |
1435 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1478 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1436 | spa->header.length = sizeof(*spa); | 1479 | spa->header.length = sizeof(*spa); |
1437 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); | 1480 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); |
1438 | spa->range_index = 6+1; | 1481 | spa->range_index = 6+1; |
1439 | spa->address = t->dimm_dma[0]; | 1482 | spa->address = t->dimm_dma[0]; |
1440 | spa->length = DIMM_SIZE; | 1483 | spa->length = DIMM_SIZE; |
1484 | offset += spa->header.length; | ||
1441 | 1485 | ||
1442 | /* spa7 (bdw for dcr1) dimm1 */ | 1486 | /* spa7 (bdw for dcr1) dimm1 */ |
1443 | spa = nfit_buf + sizeof(*spa) * 7; | 1487 | spa = nfit_buf + offset; |
1444 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1488 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1445 | spa->header.length = sizeof(*spa); | 1489 | spa->header.length = sizeof(*spa); |
1446 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); | 1490 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); |
1447 | spa->range_index = 7+1; | 1491 | spa->range_index = 7+1; |
1448 | spa->address = t->dimm_dma[1]; | 1492 | spa->address = t->dimm_dma[1]; |
1449 | spa->length = DIMM_SIZE; | 1493 | spa->length = DIMM_SIZE; |
1494 | offset += spa->header.length; | ||
1450 | 1495 | ||
1451 | /* spa8 (bdw for dcr2) dimm2 */ | 1496 | /* spa8 (bdw for dcr2) dimm2 */ |
1452 | spa = nfit_buf + sizeof(*spa) * 8; | 1497 | spa = nfit_buf + offset; |
1453 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1498 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1454 | spa->header.length = sizeof(*spa); | 1499 | spa->header.length = sizeof(*spa); |
1455 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); | 1500 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); |
1456 | spa->range_index = 8+1; | 1501 | spa->range_index = 8+1; |
1457 | spa->address = t->dimm_dma[2]; | 1502 | spa->address = t->dimm_dma[2]; |
1458 | spa->length = DIMM_SIZE; | 1503 | spa->length = DIMM_SIZE; |
1504 | offset += spa->header.length; | ||
1459 | 1505 | ||
1460 | /* spa9 (bdw for dcr3) dimm3 */ | 1506 | /* spa9 (bdw for dcr3) dimm3 */ |
1461 | spa = nfit_buf + sizeof(*spa) * 9; | 1507 | spa = nfit_buf + offset; |
1462 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1508 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1463 | spa->header.length = sizeof(*spa); | 1509 | spa->header.length = sizeof(*spa); |
1464 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); | 1510 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); |
1465 | spa->range_index = 9+1; | 1511 | spa->range_index = 9+1; |
1466 | spa->address = t->dimm_dma[3]; | 1512 | spa->address = t->dimm_dma[3]; |
1467 | spa->length = DIMM_SIZE; | 1513 | spa->length = DIMM_SIZE; |
1514 | offset += spa->header.length; | ||
1468 | 1515 | ||
1469 | offset = sizeof(*spa) * 10; | ||
1470 | /* mem-region0 (spa0, dimm0) */ | 1516 | /* mem-region0 (spa0, dimm0) */ |
1471 | memdev = nfit_buf + offset; | 1517 | memdev = nfit_buf + offset; |
1472 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1518 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
@@ -1481,9 +1527,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1481 | memdev->address = 0; | 1527 | memdev->address = 0; |
1482 | memdev->interleave_index = 0; | 1528 | memdev->interleave_index = 0; |
1483 | memdev->interleave_ways = 2; | 1529 | memdev->interleave_ways = 2; |
1530 | offset += memdev->header.length; | ||
1484 | 1531 | ||
1485 | /* mem-region1 (spa0, dimm1) */ | 1532 | /* mem-region1 (spa0, dimm1) */ |
1486 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map); | 1533 | memdev = nfit_buf + offset; |
1487 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1534 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1488 | memdev->header.length = sizeof(*memdev); | 1535 | memdev->header.length = sizeof(*memdev); |
1489 | memdev->device_handle = handle[1]; | 1536 | memdev->device_handle = handle[1]; |
@@ -1497,9 +1544,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1497 | memdev->interleave_index = 0; | 1544 | memdev->interleave_index = 0; |
1498 | memdev->interleave_ways = 2; | 1545 | memdev->interleave_ways = 2; |
1499 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; | 1546 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; |
1547 | offset += memdev->header.length; | ||
1500 | 1548 | ||
1501 | /* mem-region2 (spa1, dimm0) */ | 1549 | /* mem-region2 (spa1, dimm0) */ |
1502 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 2; | 1550 | memdev = nfit_buf + offset; |
1503 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1551 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1504 | memdev->header.length = sizeof(*memdev); | 1552 | memdev->header.length = sizeof(*memdev); |
1505 | memdev->device_handle = handle[0]; | 1553 | memdev->device_handle = handle[0]; |
@@ -1513,9 +1561,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1513 | memdev->interleave_index = 0; | 1561 | memdev->interleave_index = 0; |
1514 | memdev->interleave_ways = 4; | 1562 | memdev->interleave_ways = 4; |
1515 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; | 1563 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; |
1564 | offset += memdev->header.length; | ||
1516 | 1565 | ||
1517 | /* mem-region3 (spa1, dimm1) */ | 1566 | /* mem-region3 (spa1, dimm1) */ |
1518 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 3; | 1567 | memdev = nfit_buf + offset; |
1519 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1568 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1520 | memdev->header.length = sizeof(*memdev); | 1569 | memdev->header.length = sizeof(*memdev); |
1521 | memdev->device_handle = handle[1]; | 1570 | memdev->device_handle = handle[1]; |
@@ -1528,9 +1577,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1528 | memdev->address = SPA0_SIZE/2; | 1577 | memdev->address = SPA0_SIZE/2; |
1529 | memdev->interleave_index = 0; | 1578 | memdev->interleave_index = 0; |
1530 | memdev->interleave_ways = 4; | 1579 | memdev->interleave_ways = 4; |
1580 | offset += memdev->header.length; | ||
1531 | 1581 | ||
1532 | /* mem-region4 (spa1, dimm2) */ | 1582 | /* mem-region4 (spa1, dimm2) */ |
1533 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 4; | 1583 | memdev = nfit_buf + offset; |
1534 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1584 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1535 | memdev->header.length = sizeof(*memdev); | 1585 | memdev->header.length = sizeof(*memdev); |
1536 | memdev->device_handle = handle[2]; | 1586 | memdev->device_handle = handle[2]; |
@@ -1544,9 +1594,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1544 | memdev->interleave_index = 0; | 1594 | memdev->interleave_index = 0; |
1545 | memdev->interleave_ways = 4; | 1595 | memdev->interleave_ways = 4; |
1546 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; | 1596 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; |
1597 | offset += memdev->header.length; | ||
1547 | 1598 | ||
1548 | /* mem-region5 (spa1, dimm3) */ | 1599 | /* mem-region5 (spa1, dimm3) */ |
1549 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 5; | 1600 | memdev = nfit_buf + offset; |
1550 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1601 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1551 | memdev->header.length = sizeof(*memdev); | 1602 | memdev->header.length = sizeof(*memdev); |
1552 | memdev->device_handle = handle[3]; | 1603 | memdev->device_handle = handle[3]; |
@@ -1559,9 +1610,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1559 | memdev->address = SPA0_SIZE/2; | 1610 | memdev->address = SPA0_SIZE/2; |
1560 | memdev->interleave_index = 0; | 1611 | memdev->interleave_index = 0; |
1561 | memdev->interleave_ways = 4; | 1612 | memdev->interleave_ways = 4; |
1613 | offset += memdev->header.length; | ||
1562 | 1614 | ||
1563 | /* mem-region6 (spa/dcr0, dimm0) */ | 1615 | /* mem-region6 (spa/dcr0, dimm0) */ |
1564 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 6; | 1616 | memdev = nfit_buf + offset; |
1565 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1617 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1566 | memdev->header.length = sizeof(*memdev); | 1618 | memdev->header.length = sizeof(*memdev); |
1567 | memdev->device_handle = handle[0]; | 1619 | memdev->device_handle = handle[0]; |
@@ -1574,9 +1626,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1574 | memdev->address = 0; | 1626 | memdev->address = 0; |
1575 | memdev->interleave_index = 0; | 1627 | memdev->interleave_index = 0; |
1576 | memdev->interleave_ways = 1; | 1628 | memdev->interleave_ways = 1; |
1629 | offset += memdev->header.length; | ||
1577 | 1630 | ||
1578 | /* mem-region7 (spa/dcr1, dimm1) */ | 1631 | /* mem-region7 (spa/dcr1, dimm1) */ |
1579 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 7; | 1632 | memdev = nfit_buf + offset; |
1580 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1633 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1581 | memdev->header.length = sizeof(*memdev); | 1634 | memdev->header.length = sizeof(*memdev); |
1582 | memdev->device_handle = handle[1]; | 1635 | memdev->device_handle = handle[1]; |
@@ -1589,9 +1642,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1589 | memdev->address = 0; | 1642 | memdev->address = 0; |
1590 | memdev->interleave_index = 0; | 1643 | memdev->interleave_index = 0; |
1591 | memdev->interleave_ways = 1; | 1644 | memdev->interleave_ways = 1; |
1645 | offset += memdev->header.length; | ||
1592 | 1646 | ||
1593 | /* mem-region8 (spa/dcr2, dimm2) */ | 1647 | /* mem-region8 (spa/dcr2, dimm2) */ |
1594 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 8; | 1648 | memdev = nfit_buf + offset; |
1595 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1649 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1596 | memdev->header.length = sizeof(*memdev); | 1650 | memdev->header.length = sizeof(*memdev); |
1597 | memdev->device_handle = handle[2]; | 1651 | memdev->device_handle = handle[2]; |
@@ -1604,9 +1658,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1604 | memdev->address = 0; | 1658 | memdev->address = 0; |
1605 | memdev->interleave_index = 0; | 1659 | memdev->interleave_index = 0; |
1606 | memdev->interleave_ways = 1; | 1660 | memdev->interleave_ways = 1; |
1661 | offset += memdev->header.length; | ||
1607 | 1662 | ||
1608 | /* mem-region9 (spa/dcr3, dimm3) */ | 1663 | /* mem-region9 (spa/dcr3, dimm3) */ |
1609 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 9; | 1664 | memdev = nfit_buf + offset; |
1610 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1665 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1611 | memdev->header.length = sizeof(*memdev); | 1666 | memdev->header.length = sizeof(*memdev); |
1612 | memdev->device_handle = handle[3]; | 1667 | memdev->device_handle = handle[3]; |
@@ -1619,9 +1674,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1619 | memdev->address = 0; | 1674 | memdev->address = 0; |
1620 | memdev->interleave_index = 0; | 1675 | memdev->interleave_index = 0; |
1621 | memdev->interleave_ways = 1; | 1676 | memdev->interleave_ways = 1; |
1677 | offset += memdev->header.length; | ||
1622 | 1678 | ||
1623 | /* mem-region10 (spa/bdw0, dimm0) */ | 1679 | /* mem-region10 (spa/bdw0, dimm0) */ |
1624 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 10; | 1680 | memdev = nfit_buf + offset; |
1625 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1681 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1626 | memdev->header.length = sizeof(*memdev); | 1682 | memdev->header.length = sizeof(*memdev); |
1627 | memdev->device_handle = handle[0]; | 1683 | memdev->device_handle = handle[0]; |
@@ -1634,9 +1690,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1634 | memdev->address = 0; | 1690 | memdev->address = 0; |
1635 | memdev->interleave_index = 0; | 1691 | memdev->interleave_index = 0; |
1636 | memdev->interleave_ways = 1; | 1692 | memdev->interleave_ways = 1; |
1693 | offset += memdev->header.length; | ||
1637 | 1694 | ||
1638 | /* mem-region11 (spa/bdw1, dimm1) */ | 1695 | /* mem-region11 (spa/bdw1, dimm1) */ |
1639 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 11; | 1696 | memdev = nfit_buf + offset; |
1640 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1697 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1641 | memdev->header.length = sizeof(*memdev); | 1698 | memdev->header.length = sizeof(*memdev); |
1642 | memdev->device_handle = handle[1]; | 1699 | memdev->device_handle = handle[1]; |
@@ -1649,9 +1706,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1649 | memdev->address = 0; | 1706 | memdev->address = 0; |
1650 | memdev->interleave_index = 0; | 1707 | memdev->interleave_index = 0; |
1651 | memdev->interleave_ways = 1; | 1708 | memdev->interleave_ways = 1; |
1709 | offset += memdev->header.length; | ||
1652 | 1710 | ||
1653 | /* mem-region12 (spa/bdw2, dimm2) */ | 1711 | /* mem-region12 (spa/bdw2, dimm2) */ |
1654 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 12; | 1712 | memdev = nfit_buf + offset; |
1655 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1713 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1656 | memdev->header.length = sizeof(*memdev); | 1714 | memdev->header.length = sizeof(*memdev); |
1657 | memdev->device_handle = handle[2]; | 1715 | memdev->device_handle = handle[2]; |
@@ -1664,9 +1722,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1664 | memdev->address = 0; | 1722 | memdev->address = 0; |
1665 | memdev->interleave_index = 0; | 1723 | memdev->interleave_index = 0; |
1666 | memdev->interleave_ways = 1; | 1724 | memdev->interleave_ways = 1; |
1725 | offset += memdev->header.length; | ||
1667 | 1726 | ||
1668 | /* mem-region13 (spa/dcr3, dimm3) */ | 1727 | /* mem-region13 (spa/dcr3, dimm3) */ |
1669 | memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 13; | 1728 | memdev = nfit_buf + offset; |
1670 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 1729 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1671 | memdev->header.length = sizeof(*memdev); | 1730 | memdev->header.length = sizeof(*memdev); |
1672 | memdev->device_handle = handle[3]; | 1731 | memdev->device_handle = handle[3]; |
@@ -1680,12 +1739,12 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1680 | memdev->interleave_index = 0; | 1739 | memdev->interleave_index = 0; |
1681 | memdev->interleave_ways = 1; | 1740 | memdev->interleave_ways = 1; |
1682 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; | 1741 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; |
1742 | offset += memdev->header.length; | ||
1683 | 1743 | ||
1684 | offset = offset + sizeof(struct acpi_nfit_memory_map) * 14; | ||
1685 | /* dcr-descriptor0: blk */ | 1744 | /* dcr-descriptor0: blk */ |
1686 | dcr = nfit_buf + offset; | 1745 | dcr = nfit_buf + offset; |
1687 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1746 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1688 | dcr->header.length = sizeof(struct acpi_nfit_control_region); | 1747 | dcr->header.length = sizeof(*dcr); |
1689 | dcr->region_index = 0+1; | 1748 | dcr->region_index = 0+1; |
1690 | dcr_common_init(dcr); | 1749 | dcr_common_init(dcr); |
1691 | dcr->serial_number = ~handle[0]; | 1750 | dcr->serial_number = ~handle[0]; |
@@ -1696,11 +1755,12 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1696 | dcr->command_size = 8; | 1755 | dcr->command_size = 8; |
1697 | dcr->status_offset = 8; | 1756 | dcr->status_offset = 8; |
1698 | dcr->status_size = 4; | 1757 | dcr->status_size = 4; |
1758 | offset += dcr->header.length; | ||
1699 | 1759 | ||
1700 | /* dcr-descriptor1: blk */ | 1760 | /* dcr-descriptor1: blk */ |
1701 | dcr = nfit_buf + offset + sizeof(struct acpi_nfit_control_region); | 1761 | dcr = nfit_buf + offset; |
1702 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1762 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1703 | dcr->header.length = sizeof(struct acpi_nfit_control_region); | 1763 | dcr->header.length = sizeof(*dcr); |
1704 | dcr->region_index = 1+1; | 1764 | dcr->region_index = 1+1; |
1705 | dcr_common_init(dcr); | 1765 | dcr_common_init(dcr); |
1706 | dcr->serial_number = ~handle[1]; | 1766 | dcr->serial_number = ~handle[1]; |
@@ -1711,11 +1771,12 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1711 | dcr->command_size = 8; | 1771 | dcr->command_size = 8; |
1712 | dcr->status_offset = 8; | 1772 | dcr->status_offset = 8; |
1713 | dcr->status_size = 4; | 1773 | dcr->status_size = 4; |
1774 | offset += dcr->header.length; | ||
1714 | 1775 | ||
1715 | /* dcr-descriptor2: blk */ | 1776 | /* dcr-descriptor2: blk */ |
1716 | dcr = nfit_buf + offset + sizeof(struct acpi_nfit_control_region) * 2; | 1777 | dcr = nfit_buf + offset; |
1717 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1778 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1718 | dcr->header.length = sizeof(struct acpi_nfit_control_region); | 1779 | dcr->header.length = sizeof(*dcr); |
1719 | dcr->region_index = 2+1; | 1780 | dcr->region_index = 2+1; |
1720 | dcr_common_init(dcr); | 1781 | dcr_common_init(dcr); |
1721 | dcr->serial_number = ~handle[2]; | 1782 | dcr->serial_number = ~handle[2]; |
@@ -1726,11 +1787,12 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1726 | dcr->command_size = 8; | 1787 | dcr->command_size = 8; |
1727 | dcr->status_offset = 8; | 1788 | dcr->status_offset = 8; |
1728 | dcr->status_size = 4; | 1789 | dcr->status_size = 4; |
1790 | offset += dcr->header.length; | ||
1729 | 1791 | ||
1730 | /* dcr-descriptor3: blk */ | 1792 | /* dcr-descriptor3: blk */ |
1731 | dcr = nfit_buf + offset + sizeof(struct acpi_nfit_control_region) * 3; | 1793 | dcr = nfit_buf + offset; |
1732 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1794 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1733 | dcr->header.length = sizeof(struct acpi_nfit_control_region); | 1795 | dcr->header.length = sizeof(*dcr); |
1734 | dcr->region_index = 3+1; | 1796 | dcr->region_index = 3+1; |
1735 | dcr_common_init(dcr); | 1797 | dcr_common_init(dcr); |
1736 | dcr->serial_number = ~handle[3]; | 1798 | dcr->serial_number = ~handle[3]; |
@@ -1741,8 +1803,8 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1741 | dcr->command_size = 8; | 1803 | dcr->command_size = 8; |
1742 | dcr->status_offset = 8; | 1804 | dcr->status_offset = 8; |
1743 | dcr->status_size = 4; | 1805 | dcr->status_size = 4; |
1806 | offset += dcr->header.length; | ||
1744 | 1807 | ||
1745 | offset = offset + sizeof(struct acpi_nfit_control_region) * 4; | ||
1746 | /* dcr-descriptor0: pmem */ | 1808 | /* dcr-descriptor0: pmem */ |
1747 | dcr = nfit_buf + offset; | 1809 | dcr = nfit_buf + offset; |
1748 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1810 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
@@ -1753,10 +1815,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1753 | dcr->serial_number = ~handle[0]; | 1815 | dcr->serial_number = ~handle[0]; |
1754 | dcr->code = NFIT_FIC_BYTEN; | 1816 | dcr->code = NFIT_FIC_BYTEN; |
1755 | dcr->windows = 0; | 1817 | dcr->windows = 0; |
1818 | offset += dcr->header.length; | ||
1756 | 1819 | ||
1757 | /* dcr-descriptor1: pmem */ | 1820 | /* dcr-descriptor1: pmem */ |
1758 | dcr = nfit_buf + offset + offsetof(struct acpi_nfit_control_region, | 1821 | dcr = nfit_buf + offset; |
1759 | window_size); | ||
1760 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1822 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1761 | dcr->header.length = offsetof(struct acpi_nfit_control_region, | 1823 | dcr->header.length = offsetof(struct acpi_nfit_control_region, |
1762 | window_size); | 1824 | window_size); |
@@ -1765,10 +1827,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1765 | dcr->serial_number = ~handle[1]; | 1827 | dcr->serial_number = ~handle[1]; |
1766 | dcr->code = NFIT_FIC_BYTEN; | 1828 | dcr->code = NFIT_FIC_BYTEN; |
1767 | dcr->windows = 0; | 1829 | dcr->windows = 0; |
1830 | offset += dcr->header.length; | ||
1768 | 1831 | ||
1769 | /* dcr-descriptor2: pmem */ | 1832 | /* dcr-descriptor2: pmem */ |
1770 | dcr = nfit_buf + offset + offsetof(struct acpi_nfit_control_region, | 1833 | dcr = nfit_buf + offset; |
1771 | window_size) * 2; | ||
1772 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1834 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1773 | dcr->header.length = offsetof(struct acpi_nfit_control_region, | 1835 | dcr->header.length = offsetof(struct acpi_nfit_control_region, |
1774 | window_size); | 1836 | window_size); |
@@ -1777,10 +1839,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1777 | dcr->serial_number = ~handle[2]; | 1839 | dcr->serial_number = ~handle[2]; |
1778 | dcr->code = NFIT_FIC_BYTEN; | 1840 | dcr->code = NFIT_FIC_BYTEN; |
1779 | dcr->windows = 0; | 1841 | dcr->windows = 0; |
1842 | offset += dcr->header.length; | ||
1780 | 1843 | ||
1781 | /* dcr-descriptor3: pmem */ | 1844 | /* dcr-descriptor3: pmem */ |
1782 | dcr = nfit_buf + offset + offsetof(struct acpi_nfit_control_region, | 1845 | dcr = nfit_buf + offset; |
1783 | window_size) * 3; | ||
1784 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1846 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1785 | dcr->header.length = offsetof(struct acpi_nfit_control_region, | 1847 | dcr->header.length = offsetof(struct acpi_nfit_control_region, |
1786 | window_size); | 1848 | window_size); |
@@ -1789,54 +1851,56 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1789 | dcr->serial_number = ~handle[3]; | 1851 | dcr->serial_number = ~handle[3]; |
1790 | dcr->code = NFIT_FIC_BYTEN; | 1852 | dcr->code = NFIT_FIC_BYTEN; |
1791 | dcr->windows = 0; | 1853 | dcr->windows = 0; |
1854 | offset += dcr->header.length; | ||
1792 | 1855 | ||
1793 | offset = offset + offsetof(struct acpi_nfit_control_region, | ||
1794 | window_size) * 4; | ||
1795 | /* bdw0 (spa/dcr0, dimm0) */ | 1856 | /* bdw0 (spa/dcr0, dimm0) */ |
1796 | bdw = nfit_buf + offset; | 1857 | bdw = nfit_buf + offset; |
1797 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; | 1858 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; |
1798 | bdw->header.length = sizeof(struct acpi_nfit_data_region); | 1859 | bdw->header.length = sizeof(*bdw); |
1799 | bdw->region_index = 0+1; | 1860 | bdw->region_index = 0+1; |
1800 | bdw->windows = 1; | 1861 | bdw->windows = 1; |
1801 | bdw->offset = 0; | 1862 | bdw->offset = 0; |
1802 | bdw->size = BDW_SIZE; | 1863 | bdw->size = BDW_SIZE; |
1803 | bdw->capacity = DIMM_SIZE; | 1864 | bdw->capacity = DIMM_SIZE; |
1804 | bdw->start_address = 0; | 1865 | bdw->start_address = 0; |
1866 | offset += bdw->header.length; | ||
1805 | 1867 | ||
1806 | /* bdw1 (spa/dcr1, dimm1) */ | 1868 | /* bdw1 (spa/dcr1, dimm1) */ |
1807 | bdw = nfit_buf + offset + sizeof(struct acpi_nfit_data_region); | 1869 | bdw = nfit_buf + offset; |
1808 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; | 1870 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; |
1809 | bdw->header.length = sizeof(struct acpi_nfit_data_region); | 1871 | bdw->header.length = sizeof(*bdw); |
1810 | bdw->region_index = 1+1; | 1872 | bdw->region_index = 1+1; |
1811 | bdw->windows = 1; | 1873 | bdw->windows = 1; |
1812 | bdw->offset = 0; | 1874 | bdw->offset = 0; |
1813 | bdw->size = BDW_SIZE; | 1875 | bdw->size = BDW_SIZE; |
1814 | bdw->capacity = DIMM_SIZE; | 1876 | bdw->capacity = DIMM_SIZE; |
1815 | bdw->start_address = 0; | 1877 | bdw->start_address = 0; |
1878 | offset += bdw->header.length; | ||
1816 | 1879 | ||
1817 | /* bdw2 (spa/dcr2, dimm2) */ | 1880 | /* bdw2 (spa/dcr2, dimm2) */ |
1818 | bdw = nfit_buf + offset + sizeof(struct acpi_nfit_data_region) * 2; | 1881 | bdw = nfit_buf + offset; |
1819 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; | 1882 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; |
1820 | bdw->header.length = sizeof(struct acpi_nfit_data_region); | 1883 | bdw->header.length = sizeof(*bdw); |
1821 | bdw->region_index = 2+1; | 1884 | bdw->region_index = 2+1; |
1822 | bdw->windows = 1; | 1885 | bdw->windows = 1; |
1823 | bdw->offset = 0; | 1886 | bdw->offset = 0; |
1824 | bdw->size = BDW_SIZE; | 1887 | bdw->size = BDW_SIZE; |
1825 | bdw->capacity = DIMM_SIZE; | 1888 | bdw->capacity = DIMM_SIZE; |
1826 | bdw->start_address = 0; | 1889 | bdw->start_address = 0; |
1890 | offset += bdw->header.length; | ||
1827 | 1891 | ||
1828 | /* bdw3 (spa/dcr3, dimm3) */ | 1892 | /* bdw3 (spa/dcr3, dimm3) */ |
1829 | bdw = nfit_buf + offset + sizeof(struct acpi_nfit_data_region) * 3; | 1893 | bdw = nfit_buf + offset; |
1830 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; | 1894 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; |
1831 | bdw->header.length = sizeof(struct acpi_nfit_data_region); | 1895 | bdw->header.length = sizeof(*bdw); |
1832 | bdw->region_index = 3+1; | 1896 | bdw->region_index = 3+1; |
1833 | bdw->windows = 1; | 1897 | bdw->windows = 1; |
1834 | bdw->offset = 0; | 1898 | bdw->offset = 0; |
1835 | bdw->size = BDW_SIZE; | 1899 | bdw->size = BDW_SIZE; |
1836 | bdw->capacity = DIMM_SIZE; | 1900 | bdw->capacity = DIMM_SIZE; |
1837 | bdw->start_address = 0; | 1901 | bdw->start_address = 0; |
1902 | offset += bdw->header.length; | ||
1838 | 1903 | ||
1839 | offset = offset + sizeof(struct acpi_nfit_data_region) * 4; | ||
1840 | /* flush0 (dimm0) */ | 1904 | /* flush0 (dimm0) */ |
1841 | flush = nfit_buf + offset; | 1905 | flush = nfit_buf + offset; |
1842 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; | 1906 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; |
@@ -1845,48 +1909,52 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1845 | flush->hint_count = NUM_HINTS; | 1909 | flush->hint_count = NUM_HINTS; |
1846 | for (i = 0; i < NUM_HINTS; i++) | 1910 | for (i = 0; i < NUM_HINTS; i++) |
1847 | flush->hint_address[i] = t->flush_dma[0] + i * sizeof(u64); | 1911 | flush->hint_address[i] = t->flush_dma[0] + i * sizeof(u64); |
1912 | offset += flush->header.length; | ||
1848 | 1913 | ||
1849 | /* flush1 (dimm1) */ | 1914 | /* flush1 (dimm1) */ |
1850 | flush = nfit_buf + offset + flush_hint_size * 1; | 1915 | flush = nfit_buf + offset; |
1851 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; | 1916 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; |
1852 | flush->header.length = flush_hint_size; | 1917 | flush->header.length = flush_hint_size; |
1853 | flush->device_handle = handle[1]; | 1918 | flush->device_handle = handle[1]; |
1854 | flush->hint_count = NUM_HINTS; | 1919 | flush->hint_count = NUM_HINTS; |
1855 | for (i = 0; i < NUM_HINTS; i++) | 1920 | for (i = 0; i < NUM_HINTS; i++) |
1856 | flush->hint_address[i] = t->flush_dma[1] + i * sizeof(u64); | 1921 | flush->hint_address[i] = t->flush_dma[1] + i * sizeof(u64); |
1922 | offset += flush->header.length; | ||
1857 | 1923 | ||
1858 | /* flush2 (dimm2) */ | 1924 | /* flush2 (dimm2) */ |
1859 | flush = nfit_buf + offset + flush_hint_size * 2; | 1925 | flush = nfit_buf + offset; |
1860 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; | 1926 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; |
1861 | flush->header.length = flush_hint_size; | 1927 | flush->header.length = flush_hint_size; |
1862 | flush->device_handle = handle[2]; | 1928 | flush->device_handle = handle[2]; |
1863 | flush->hint_count = NUM_HINTS; | 1929 | flush->hint_count = NUM_HINTS; |
1864 | for (i = 0; i < NUM_HINTS; i++) | 1930 | for (i = 0; i < NUM_HINTS; i++) |
1865 | flush->hint_address[i] = t->flush_dma[2] + i * sizeof(u64); | 1931 | flush->hint_address[i] = t->flush_dma[2] + i * sizeof(u64); |
1932 | offset += flush->header.length; | ||
1866 | 1933 | ||
1867 | /* flush3 (dimm3) */ | 1934 | /* flush3 (dimm3) */ |
1868 | flush = nfit_buf + offset + flush_hint_size * 3; | 1935 | flush = nfit_buf + offset; |
1869 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; | 1936 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; |
1870 | flush->header.length = flush_hint_size; | 1937 | flush->header.length = flush_hint_size; |
1871 | flush->device_handle = handle[3]; | 1938 | flush->device_handle = handle[3]; |
1872 | flush->hint_count = NUM_HINTS; | 1939 | flush->hint_count = NUM_HINTS; |
1873 | for (i = 0; i < NUM_HINTS; i++) | 1940 | for (i = 0; i < NUM_HINTS; i++) |
1874 | flush->hint_address[i] = t->flush_dma[3] + i * sizeof(u64); | 1941 | flush->hint_address[i] = t->flush_dma[3] + i * sizeof(u64); |
1942 | offset += flush->header.length; | ||
1875 | 1943 | ||
1876 | /* platform capabilities */ | 1944 | /* platform capabilities */ |
1877 | pcap = nfit_buf + offset + flush_hint_size * 4; | 1945 | pcap = nfit_buf + offset; |
1878 | pcap->header.type = ACPI_NFIT_TYPE_CAPABILITIES; | 1946 | pcap->header.type = ACPI_NFIT_TYPE_CAPABILITIES; |
1879 | pcap->header.length = sizeof(*pcap); | 1947 | pcap->header.length = sizeof(*pcap); |
1880 | pcap->highest_capability = 1; | 1948 | pcap->highest_capability = 1; |
1881 | pcap->capabilities = ACPI_NFIT_CAPABILITY_CACHE_FLUSH | | 1949 | pcap->capabilities = ACPI_NFIT_CAPABILITY_CACHE_FLUSH | |
1882 | ACPI_NFIT_CAPABILITY_MEM_FLUSH; | 1950 | ACPI_NFIT_CAPABILITY_MEM_FLUSH; |
1951 | offset += pcap->header.length; | ||
1883 | 1952 | ||
1884 | if (t->setup_hotplug) { | 1953 | if (t->setup_hotplug) { |
1885 | offset = offset + flush_hint_size * 4 + sizeof(*pcap); | ||
1886 | /* dcr-descriptor4: blk */ | 1954 | /* dcr-descriptor4: blk */ |
1887 | dcr = nfit_buf + offset; | 1955 | dcr = nfit_buf + offset; |
1888 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1956 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
1889 | dcr->header.length = sizeof(struct acpi_nfit_control_region); | 1957 | dcr->header.length = sizeof(*dcr); |
1890 | dcr->region_index = 8+1; | 1958 | dcr->region_index = 8+1; |
1891 | dcr_common_init(dcr); | 1959 | dcr_common_init(dcr); |
1892 | dcr->serial_number = ~handle[4]; | 1960 | dcr->serial_number = ~handle[4]; |
@@ -1897,8 +1965,8 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1897 | dcr->command_size = 8; | 1965 | dcr->command_size = 8; |
1898 | dcr->status_offset = 8; | 1966 | dcr->status_offset = 8; |
1899 | dcr->status_size = 4; | 1967 | dcr->status_size = 4; |
1968 | offset += dcr->header.length; | ||
1900 | 1969 | ||
1901 | offset = offset + sizeof(struct acpi_nfit_control_region); | ||
1902 | /* dcr-descriptor4: pmem */ | 1970 | /* dcr-descriptor4: pmem */ |
1903 | dcr = nfit_buf + offset; | 1971 | dcr = nfit_buf + offset; |
1904 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 1972 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
@@ -1909,21 +1977,20 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1909 | dcr->serial_number = ~handle[4]; | 1977 | dcr->serial_number = ~handle[4]; |
1910 | dcr->code = NFIT_FIC_BYTEN; | 1978 | dcr->code = NFIT_FIC_BYTEN; |
1911 | dcr->windows = 0; | 1979 | dcr->windows = 0; |
1980 | offset += dcr->header.length; | ||
1912 | 1981 | ||
1913 | offset = offset + offsetof(struct acpi_nfit_control_region, | ||
1914 | window_size); | ||
1915 | /* bdw4 (spa/dcr4, dimm4) */ | 1982 | /* bdw4 (spa/dcr4, dimm4) */ |
1916 | bdw = nfit_buf + offset; | 1983 | bdw = nfit_buf + offset; |
1917 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; | 1984 | bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; |
1918 | bdw->header.length = sizeof(struct acpi_nfit_data_region); | 1985 | bdw->header.length = sizeof(*bdw); |
1919 | bdw->region_index = 8+1; | 1986 | bdw->region_index = 8+1; |
1920 | bdw->windows = 1; | 1987 | bdw->windows = 1; |
1921 | bdw->offset = 0; | 1988 | bdw->offset = 0; |
1922 | bdw->size = BDW_SIZE; | 1989 | bdw->size = BDW_SIZE; |
1923 | bdw->capacity = DIMM_SIZE; | 1990 | bdw->capacity = DIMM_SIZE; |
1924 | bdw->start_address = 0; | 1991 | bdw->start_address = 0; |
1992 | offset += bdw->header.length; | ||
1925 | 1993 | ||
1926 | offset = offset + sizeof(struct acpi_nfit_data_region); | ||
1927 | /* spa10 (dcr4) dimm4 */ | 1994 | /* spa10 (dcr4) dimm4 */ |
1928 | spa = nfit_buf + offset; | 1995 | spa = nfit_buf + offset; |
1929 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 1996 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
@@ -1932,30 +1999,32 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1932 | spa->range_index = 10+1; | 1999 | spa->range_index = 10+1; |
1933 | spa->address = t->dcr_dma[4]; | 2000 | spa->address = t->dcr_dma[4]; |
1934 | spa->length = DCR_SIZE; | 2001 | spa->length = DCR_SIZE; |
2002 | offset += spa->header.length; | ||
1935 | 2003 | ||
1936 | /* | 2004 | /* |
1937 | * spa11 (single-dimm interleave for hotplug, note storage | 2005 | * spa11 (single-dimm interleave for hotplug, note storage |
1938 | * does not actually alias the related block-data-window | 2006 | * does not actually alias the related block-data-window |
1939 | * regions) | 2007 | * regions) |
1940 | */ | 2008 | */ |
1941 | spa = nfit_buf + offset + sizeof(*spa); | 2009 | spa = nfit_buf + offset; |
1942 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 2010 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1943 | spa->header.length = sizeof(*spa); | 2011 | spa->header.length = sizeof(*spa); |
1944 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); | 2012 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); |
1945 | spa->range_index = 11+1; | 2013 | spa->range_index = 11+1; |
1946 | spa->address = t->spa_set_dma[2]; | 2014 | spa->address = t->spa_set_dma[2]; |
1947 | spa->length = SPA0_SIZE; | 2015 | spa->length = SPA0_SIZE; |
2016 | offset += spa->header.length; | ||
1948 | 2017 | ||
1949 | /* spa12 (bdw for dcr4) dimm4 */ | 2018 | /* spa12 (bdw for dcr4) dimm4 */ |
1950 | spa = nfit_buf + offset + sizeof(*spa) * 2; | 2019 | spa = nfit_buf + offset; |
1951 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 2020 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
1952 | spa->header.length = sizeof(*spa); | 2021 | spa->header.length = sizeof(*spa); |
1953 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); | 2022 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); |
1954 | spa->range_index = 12+1; | 2023 | spa->range_index = 12+1; |
1955 | spa->address = t->dimm_dma[4]; | 2024 | spa->address = t->dimm_dma[4]; |
1956 | spa->length = DIMM_SIZE; | 2025 | spa->length = DIMM_SIZE; |
2026 | offset += spa->header.length; | ||
1957 | 2027 | ||
1958 | offset = offset + sizeof(*spa) * 3; | ||
1959 | /* mem-region14 (spa/dcr4, dimm4) */ | 2028 | /* mem-region14 (spa/dcr4, dimm4) */ |
1960 | memdev = nfit_buf + offset; | 2029 | memdev = nfit_buf + offset; |
1961 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 2030 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
@@ -1970,10 +2039,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1970 | memdev->address = 0; | 2039 | memdev->address = 0; |
1971 | memdev->interleave_index = 0; | 2040 | memdev->interleave_index = 0; |
1972 | memdev->interleave_ways = 1; | 2041 | memdev->interleave_ways = 1; |
2042 | offset += memdev->header.length; | ||
1973 | 2043 | ||
1974 | /* mem-region15 (spa0, dimm4) */ | 2044 | /* mem-region15 (spa11, dimm4) */ |
1975 | memdev = nfit_buf + offset + | 2045 | memdev = nfit_buf + offset; |
1976 | sizeof(struct acpi_nfit_memory_map); | ||
1977 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 2046 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1978 | memdev->header.length = sizeof(*memdev); | 2047 | memdev->header.length = sizeof(*memdev); |
1979 | memdev->device_handle = handle[4]; | 2048 | memdev->device_handle = handle[4]; |
@@ -1987,10 +2056,10 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1987 | memdev->interleave_index = 0; | 2056 | memdev->interleave_index = 0; |
1988 | memdev->interleave_ways = 1; | 2057 | memdev->interleave_ways = 1; |
1989 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; | 2058 | memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; |
2059 | offset += memdev->header.length; | ||
1990 | 2060 | ||
1991 | /* mem-region16 (spa/bdw4, dimm4) */ | 2061 | /* mem-region16 (spa/bdw4, dimm4) */ |
1992 | memdev = nfit_buf + offset + | 2062 | memdev = nfit_buf + offset; |
1993 | sizeof(struct acpi_nfit_memory_map) * 2; | ||
1994 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 2063 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
1995 | memdev->header.length = sizeof(*memdev); | 2064 | memdev->header.length = sizeof(*memdev); |
1996 | memdev->device_handle = handle[4]; | 2065 | memdev->device_handle = handle[4]; |
@@ -2003,8 +2072,8 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
2003 | memdev->address = 0; | 2072 | memdev->address = 0; |
2004 | memdev->interleave_index = 0; | 2073 | memdev->interleave_index = 0; |
2005 | memdev->interleave_ways = 1; | 2074 | memdev->interleave_ways = 1; |
2075 | offset += memdev->header.length; | ||
2006 | 2076 | ||
2007 | offset = offset + sizeof(struct acpi_nfit_memory_map) * 3; | ||
2008 | /* flush3 (dimm4) */ | 2077 | /* flush3 (dimm4) */ |
2009 | flush = nfit_buf + offset; | 2078 | flush = nfit_buf + offset; |
2010 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; | 2079 | flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; |
@@ -2014,8 +2083,14 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
2014 | for (i = 0; i < NUM_HINTS; i++) | 2083 | for (i = 0; i < NUM_HINTS; i++) |
2015 | flush->hint_address[i] = t->flush_dma[4] | 2084 | flush->hint_address[i] = t->flush_dma[4] |
2016 | + i * sizeof(u64); | 2085 | + i * sizeof(u64); |
2086 | offset += flush->header.length; | ||
2087 | |||
2088 | /* sanity check to make sure we've filled the buffer */ | ||
2089 | WARN_ON(offset != t->nfit_size); | ||
2017 | } | 2090 | } |
2018 | 2091 | ||
2092 | t->nfit_filled = offset; | ||
2093 | |||
2019 | post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], | 2094 | post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], |
2020 | SPA0_SIZE); | 2095 | SPA0_SIZE); |
2021 | 2096 | ||
@@ -2026,6 +2101,7 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
2026 | set_bit(ND_INTEL_SMART, &acpi_desc->dimm_cmd_force_en); | 2101 | set_bit(ND_INTEL_SMART, &acpi_desc->dimm_cmd_force_en); |
2027 | set_bit(ND_INTEL_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); | 2102 | set_bit(ND_INTEL_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); |
2028 | set_bit(ND_INTEL_SMART_SET_THRESHOLD, &acpi_desc->dimm_cmd_force_en); | 2103 | set_bit(ND_INTEL_SMART_SET_THRESHOLD, &acpi_desc->dimm_cmd_force_en); |
2104 | set_bit(ND_INTEL_SMART_INJECT, &acpi_desc->dimm_cmd_force_en); | ||
2029 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); | 2105 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); |
2030 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); | 2106 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); |
2031 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); | 2107 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); |
@@ -2061,17 +2137,18 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
2061 | spa->range_index = 0+1; | 2137 | spa->range_index = 0+1; |
2062 | spa->address = t->spa_set_dma[0]; | 2138 | spa->address = t->spa_set_dma[0]; |
2063 | spa->length = SPA2_SIZE; | 2139 | spa->length = SPA2_SIZE; |
2140 | offset += spa->header.length; | ||
2064 | 2141 | ||
2065 | /* virtual cd region */ | 2142 | /* virtual cd region */ |
2066 | spa = nfit_buf + sizeof(*spa); | 2143 | spa = nfit_buf + offset; |
2067 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; | 2144 | spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; |
2068 | spa->header.length = sizeof(*spa); | 2145 | spa->header.length = sizeof(*spa); |
2069 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_VCD), 16); | 2146 | memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_VCD), 16); |
2070 | spa->range_index = 0; | 2147 | spa->range_index = 0; |
2071 | spa->address = t->spa_set_dma[1]; | 2148 | spa->address = t->spa_set_dma[1]; |
2072 | spa->length = SPA_VCD_SIZE; | 2149 | spa->length = SPA_VCD_SIZE; |
2150 | offset += spa->header.length; | ||
2073 | 2151 | ||
2074 | offset += sizeof(*spa) * 2; | ||
2075 | /* mem-region0 (spa0, dimm0) */ | 2152 | /* mem-region0 (spa0, dimm0) */ |
2076 | memdev = nfit_buf + offset; | 2153 | memdev = nfit_buf + offset; |
2077 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 2154 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
@@ -2089,8 +2166,8 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
2089 | memdev->flags = ACPI_NFIT_MEM_SAVE_FAILED | ACPI_NFIT_MEM_RESTORE_FAILED | 2166 | memdev->flags = ACPI_NFIT_MEM_SAVE_FAILED | ACPI_NFIT_MEM_RESTORE_FAILED |
2090 | | ACPI_NFIT_MEM_FLUSH_FAILED | ACPI_NFIT_MEM_HEALTH_OBSERVED | 2167 | | ACPI_NFIT_MEM_FLUSH_FAILED | ACPI_NFIT_MEM_HEALTH_OBSERVED |
2091 | | ACPI_NFIT_MEM_NOT_ARMED; | 2168 | | ACPI_NFIT_MEM_NOT_ARMED; |
2169 | offset += memdev->header.length; | ||
2092 | 2170 | ||
2093 | offset += sizeof(*memdev); | ||
2094 | /* dcr-descriptor0 */ | 2171 | /* dcr-descriptor0 */ |
2095 | dcr = nfit_buf + offset; | 2172 | dcr = nfit_buf + offset; |
2096 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 2173 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
@@ -2101,8 +2178,8 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
2101 | dcr->serial_number = ~handle[5]; | 2178 | dcr->serial_number = ~handle[5]; |
2102 | dcr->code = NFIT_FIC_BYTE; | 2179 | dcr->code = NFIT_FIC_BYTE; |
2103 | dcr->windows = 0; | 2180 | dcr->windows = 0; |
2104 | |||
2105 | offset += dcr->header.length; | 2181 | offset += dcr->header.length; |
2182 | |||
2106 | memdev = nfit_buf + offset; | 2183 | memdev = nfit_buf + offset; |
2107 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; | 2184 | memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; |
2108 | memdev->header.length = sizeof(*memdev); | 2185 | memdev->header.length = sizeof(*memdev); |
@@ -2117,9 +2194,9 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
2117 | memdev->interleave_index = 0; | 2194 | memdev->interleave_index = 0; |
2118 | memdev->interleave_ways = 1; | 2195 | memdev->interleave_ways = 1; |
2119 | memdev->flags = ACPI_NFIT_MEM_MAP_FAILED; | 2196 | memdev->flags = ACPI_NFIT_MEM_MAP_FAILED; |
2197 | offset += memdev->header.length; | ||
2120 | 2198 | ||
2121 | /* dcr-descriptor1 */ | 2199 | /* dcr-descriptor1 */ |
2122 | offset += sizeof(*memdev); | ||
2123 | dcr = nfit_buf + offset; | 2200 | dcr = nfit_buf + offset; |
2124 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; | 2201 | dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; |
2125 | dcr->header.length = offsetof(struct acpi_nfit_control_region, | 2202 | dcr->header.length = offsetof(struct acpi_nfit_control_region, |
@@ -2129,6 +2206,12 @@ static void nfit_test1_setup(struct nfit_test *t) | |||
2129 | dcr->serial_number = ~handle[6]; | 2206 | dcr->serial_number = ~handle[6]; |
2130 | dcr->code = NFIT_FIC_BYTE; | 2207 | dcr->code = NFIT_FIC_BYTE; |
2131 | dcr->windows = 0; | 2208 | dcr->windows = 0; |
2209 | offset += dcr->header.length; | ||
2210 | |||
2211 | /* sanity check to make sure we've filled the buffer */ | ||
2212 | WARN_ON(offset != t->nfit_size); | ||
2213 | |||
2214 | t->nfit_filled = offset; | ||
2132 | 2215 | ||
2133 | post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], | 2216 | post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], |
2134 | SPA2_SIZE); | 2217 | SPA2_SIZE); |
@@ -2487,7 +2570,7 @@ static int nfit_test_probe(struct platform_device *pdev) | |||
2487 | nd_desc->ndctl = nfit_test_ctl; | 2570 | nd_desc->ndctl = nfit_test_ctl; |
2488 | 2571 | ||
2489 | rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_buf, | 2572 | rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_buf, |
2490 | nfit_test->nfit_size); | 2573 | nfit_test->nfit_filled); |
2491 | if (rc) | 2574 | if (rc) |
2492 | return rc; | 2575 | return rc; |
2493 | 2576 | ||
diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h index 428344519cdf..33752e06ff8d 100644 --- a/tools/testing/nvdimm/test/nfit_test.h +++ b/tools/testing/nvdimm/test/nfit_test.h | |||
@@ -93,6 +93,7 @@ struct nd_cmd_ars_err_inj_stat { | |||
93 | #define ND_INTEL_FW_FINISH_UPDATE 15 | 93 | #define ND_INTEL_FW_FINISH_UPDATE 15 |
94 | #define ND_INTEL_FW_FINISH_QUERY 16 | 94 | #define ND_INTEL_FW_FINISH_QUERY 16 |
95 | #define ND_INTEL_SMART_SET_THRESHOLD 17 | 95 | #define ND_INTEL_SMART_SET_THRESHOLD 17 |
96 | #define ND_INTEL_SMART_INJECT 18 | ||
96 | 97 | ||
97 | #define ND_INTEL_SMART_HEALTH_VALID (1 << 0) | 98 | #define ND_INTEL_SMART_HEALTH_VALID (1 << 0) |
98 | #define ND_INTEL_SMART_SPARES_VALID (1 << 1) | 99 | #define ND_INTEL_SMART_SPARES_VALID (1 << 1) |
@@ -111,6 +112,10 @@ struct nd_cmd_ars_err_inj_stat { | |||
111 | #define ND_INTEL_SMART_NON_CRITICAL_HEALTH (1 << 0) | 112 | #define ND_INTEL_SMART_NON_CRITICAL_HEALTH (1 << 0) |
112 | #define ND_INTEL_SMART_CRITICAL_HEALTH (1 << 1) | 113 | #define ND_INTEL_SMART_CRITICAL_HEALTH (1 << 1) |
113 | #define ND_INTEL_SMART_FATAL_HEALTH (1 << 2) | 114 | #define ND_INTEL_SMART_FATAL_HEALTH (1 << 2) |
115 | #define ND_INTEL_SMART_INJECT_MTEMP (1 << 0) | ||
116 | #define ND_INTEL_SMART_INJECT_SPARE (1 << 1) | ||
117 | #define ND_INTEL_SMART_INJECT_FATAL (1 << 2) | ||
118 | #define ND_INTEL_SMART_INJECT_SHUTDOWN (1 << 3) | ||
114 | 119 | ||
115 | struct nd_intel_smart { | 120 | struct nd_intel_smart { |
116 | __u32 status; | 121 | __u32 status; |
@@ -158,6 +163,17 @@ struct nd_intel_smart_set_threshold { | |||
158 | __u32 status; | 163 | __u32 status; |
159 | } __packed; | 164 | } __packed; |
160 | 165 | ||
166 | struct nd_intel_smart_inject { | ||
167 | __u64 flags; | ||
168 | __u8 mtemp_enable; | ||
169 | __u16 media_temperature; | ||
170 | __u8 spare_enable; | ||
171 | __u8 spares; | ||
172 | __u8 fatal_enable; | ||
173 | __u8 unsafe_shutdown_enable; | ||
174 | __u32 status; | ||
175 | } __packed; | ||
176 | |||
161 | #define INTEL_FW_STORAGE_SIZE 0x100000 | 177 | #define INTEL_FW_STORAGE_SIZE 0x100000 |
162 | #define INTEL_FW_MAX_SEND_LEN 0xFFEC | 178 | #define INTEL_FW_MAX_SEND_LEN 0xFFEC |
163 | #define INTEL_FW_QUERY_INTERVAL 250000 | 179 | #define INTEL_FW_QUERY_INTERVAL 250000 |
diff --git a/tools/testing/radix-tree/linux/gfp.h b/tools/testing/radix-tree/linux/gfp.h index e3201ccf54c3..32159c08a52e 100644 --- a/tools/testing/radix-tree/linux/gfp.h +++ b/tools/testing/radix-tree/linux/gfp.h | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #define __GFP_RECLAIM (__GFP_DIRECT_RECLAIM|__GFP_KSWAPD_RECLAIM) | 20 | #define __GFP_RECLAIM (__GFP_DIRECT_RECLAIM|__GFP_KSWAPD_RECLAIM) |
21 | 21 | ||
22 | #define GFP_ZONEMASK 0x0fu | ||
22 | #define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM) | 23 | #define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM) |
23 | #define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS) | 24 | #define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS) |
24 | #define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM) | 25 | #define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM) |
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index dbda89c9d9b9..32aafa92074c 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -15,6 +15,7 @@ TARGETS += gpio | |||
15 | TARGETS += intel_pstate | 15 | TARGETS += intel_pstate |
16 | TARGETS += ipc | 16 | TARGETS += ipc |
17 | TARGETS += kcmp | 17 | TARGETS += kcmp |
18 | TARGETS += kvm | ||
18 | TARGETS += lib | 19 | TARGETS += lib |
19 | TARGETS += membarrier | 20 | TARGETS += membarrier |
20 | TARGETS += memfd | 21 | TARGETS += memfd |
@@ -24,6 +25,7 @@ TARGETS += mqueue | |||
24 | TARGETS += net | 25 | TARGETS += net |
25 | TARGETS += nsfs | 26 | TARGETS += nsfs |
26 | TARGETS += powerpc | 27 | TARGETS += powerpc |
28 | TARGETS += proc | ||
27 | TARGETS += pstore | 29 | TARGETS += pstore |
28 | TARGETS += ptrace | 30 | TARGETS += ptrace |
29 | TARGETS += seccomp | 31 | TARGETS += seccomp |
@@ -67,6 +69,12 @@ ifndef BUILD | |||
67 | BUILD := $(shell pwd) | 69 | BUILD := $(shell pwd) |
68 | endif | 70 | endif |
69 | 71 | ||
72 | # KSFT_TAP_LEVEL is used from KSFT framework to prevent nested TAP header | ||
73 | # printing from tests. Applicable to run_tests case where run_tests adds | ||
74 | # TAP header prior running tests and when a test program invokes another | ||
75 | # with system() call. Export it here to cover override RUN_TESTS defines. | ||
76 | export KSFT_TAP_LEVEL=`echo 1` | ||
77 | |||
70 | export BUILD | 78 | export BUILD |
71 | all: | 79 | all: |
72 | @for TARGET in $(TARGETS); do \ | 80 | @for TARGET in $(TARGETS); do \ |
@@ -126,11 +134,14 @@ ifdef INSTALL_PATH | |||
126 | echo "else" >> $(ALL_SCRIPT) | 134 | echo "else" >> $(ALL_SCRIPT) |
127 | echo " OUTPUT=/dev/stdout" >> $(ALL_SCRIPT) | 135 | echo " OUTPUT=/dev/stdout" >> $(ALL_SCRIPT) |
128 | echo "fi" >> $(ALL_SCRIPT) | 136 | echo "fi" >> $(ALL_SCRIPT) |
137 | echo "export KSFT_TAP_LEVEL=`echo 1`" >> $(ALL_SCRIPT) | ||
129 | 138 | ||
130 | for TARGET in $(TARGETS); do \ | 139 | for TARGET in $(TARGETS); do \ |
131 | BUILD_TARGET=$$BUILD/$$TARGET; \ | 140 | BUILD_TARGET=$$BUILD/$$TARGET; \ |
132 | echo "echo ; echo Running tests in $$TARGET" >> $(ALL_SCRIPT); \ | 141 | echo "echo ; echo TAP version 13" >> $(ALL_SCRIPT); \ |
142 | echo "echo Running tests in $$TARGET" >> $(ALL_SCRIPT); \ | ||
133 | echo "echo ========================================" >> $(ALL_SCRIPT); \ | 143 | echo "echo ========================================" >> $(ALL_SCRIPT); \ |
144 | echo "[ -w /dev/kmsg ] && echo \"kselftest: Running tests in $$TARGET\" >> /dev/kmsg" >> $(ALL_SCRIPT); \ | ||
134 | echo "cd $$TARGET" >> $(ALL_SCRIPT); \ | 145 | echo "cd $$TARGET" >> $(ALL_SCRIPT); \ |
135 | make -s --no-print-directory OUTPUT=$$BUILD_TARGET -C $$TARGET emit_tests >> $(ALL_SCRIPT); \ | 146 | make -s --no-print-directory OUTPUT=$$BUILD_TARGET -C $$TARGET emit_tests >> $(ALL_SCRIPT); \ |
136 | echo "cd \$$ROOT" >> $(ALL_SCRIPT); \ | 147 | echo "cd \$$ROOT" >> $(ALL_SCRIPT); \ |
diff --git a/tools/testing/selftests/android/ion/.gitignore b/tools/testing/selftests/android/ion/.gitignore index 67e6f391b2a9..95e8f4561474 100644 --- a/tools/testing/selftests/android/ion/.gitignore +++ b/tools/testing/selftests/android/ion/.gitignore | |||
@@ -1,2 +1,3 @@ | |||
1 | ionapp_export | 1 | ionapp_export |
2 | ionapp_import | 2 | ionapp_import |
3 | ionmap_test | ||
diff --git a/tools/testing/selftests/android/ion/Makefile b/tools/testing/selftests/android/ion/Makefile index 96e0c448b39d..e03695287f76 100644 --- a/tools/testing/selftests/android/ion/Makefile +++ b/tools/testing/selftests/android/ion/Makefile | |||
@@ -1,8 +1,8 @@ | |||
1 | 1 | ||
2 | INCLUDEDIR := -I. -I../../../../../drivers/staging/android/uapi/ | 2 | INCLUDEDIR := -I. -I../../../../../drivers/staging/android/uapi/ -I../../../../../usr/include/ |
3 | CFLAGS := $(CFLAGS) $(INCLUDEDIR) -Wall -O2 -g | 3 | CFLAGS := $(CFLAGS) $(INCLUDEDIR) -Wall -O2 -g |
4 | 4 | ||
5 | TEST_GEN_FILES := ionapp_export ionapp_import | 5 | TEST_GEN_FILES := ionapp_export ionapp_import ionmap_test |
6 | 6 | ||
7 | all: $(TEST_GEN_FILES) | 7 | all: $(TEST_GEN_FILES) |
8 | 8 | ||
@@ -14,3 +14,4 @@ include ../../lib.mk | |||
14 | 14 | ||
15 | $(OUTPUT)/ionapp_export: ionapp_export.c ipcsocket.c ionutils.c | 15 | $(OUTPUT)/ionapp_export: ionapp_export.c ipcsocket.c ionutils.c |
16 | $(OUTPUT)/ionapp_import: ionapp_import.c ipcsocket.c ionutils.c | 16 | $(OUTPUT)/ionapp_import: ionapp_import.c ipcsocket.c ionutils.c |
17 | $(OUTPUT)/ionmap_test: ionmap_test.c ionutils.c | ||
diff --git a/tools/testing/selftests/android/ion/config b/tools/testing/selftests/android/ion/config index 19db6ca9aa2b..b4ad748a9dd9 100644 --- a/tools/testing/selftests/android/ion/config +++ b/tools/testing/selftests/android/ion/config | |||
@@ -2,3 +2,4 @@ CONFIG_ANDROID=y | |||
2 | CONFIG_STAGING=y | 2 | CONFIG_STAGING=y |
3 | CONFIG_ION=y | 3 | CONFIG_ION=y |
4 | CONFIG_ION_SYSTEM_HEAP=y | 4 | CONFIG_ION_SYSTEM_HEAP=y |
5 | CONFIG_DRM_VGEM=y | ||
diff --git a/tools/testing/selftests/android/ion/ionmap_test.c b/tools/testing/selftests/android/ion/ionmap_test.c new file mode 100644 index 000000000000..dab36b06b37d --- /dev/null +++ b/tools/testing/selftests/android/ion/ionmap_test.c | |||
@@ -0,0 +1,136 @@ | |||
1 | #include <errno.h> | ||
2 | #include <fcntl.h> | ||
3 | #include <stdio.h> | ||
4 | #include <stdint.h> | ||
5 | #include <string.h> | ||
6 | #include <unistd.h> | ||
7 | |||
8 | #include <sys/ioctl.h> | ||
9 | #include <sys/types.h> | ||
10 | #include <sys/stat.h> | ||
11 | |||
12 | #include <linux/dma-buf.h> | ||
13 | |||
14 | #include <drm/drm.h> | ||
15 | |||
16 | #include "ion.h" | ||
17 | #include "ionutils.h" | ||
18 | |||
19 | int check_vgem(int fd) | ||
20 | { | ||
21 | drm_version_t version = { 0 }; | ||
22 | char name[5]; | ||
23 | int ret; | ||
24 | |||
25 | version.name_len = 4; | ||
26 | version.name = name; | ||
27 | |||
28 | ret = ioctl(fd, DRM_IOCTL_VERSION, &version); | ||
29 | if (ret) | ||
30 | return 1; | ||
31 | |||
32 | return strcmp(name, "vgem"); | ||
33 | } | ||
34 | |||
35 | int open_vgem(void) | ||
36 | { | ||
37 | int i, fd; | ||
38 | const char *drmstr = "/dev/dri/card"; | ||
39 | |||
40 | fd = -1; | ||
41 | for (i = 0; i < 16; i++) { | ||
42 | char name[80]; | ||
43 | |||
44 | sprintf(name, "%s%u", drmstr, i); | ||
45 | |||
46 | fd = open(name, O_RDWR); | ||
47 | if (fd < 0) | ||
48 | continue; | ||
49 | |||
50 | if (check_vgem(fd)) { | ||
51 | close(fd); | ||
52 | continue; | ||
53 | } else { | ||
54 | break; | ||
55 | } | ||
56 | |||
57 | } | ||
58 | return fd; | ||
59 | } | ||
60 | |||
61 | int import_vgem_fd(int vgem_fd, int dma_buf_fd, uint32_t *handle) | ||
62 | { | ||
63 | struct drm_prime_handle import_handle = { 0 }; | ||
64 | int ret; | ||
65 | |||
66 | import_handle.fd = dma_buf_fd; | ||
67 | import_handle.flags = 0; | ||
68 | import_handle.handle = 0; | ||
69 | |||
70 | ret = ioctl(vgem_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &import_handle); | ||
71 | if (ret == 0) | ||
72 | *handle = import_handle.handle; | ||
73 | return ret; | ||
74 | } | ||
75 | |||
76 | void close_handle(int vgem_fd, uint32_t handle) | ||
77 | { | ||
78 | struct drm_gem_close close = { 0 }; | ||
79 | |||
80 | close.handle = handle; | ||
81 | ioctl(vgem_fd, DRM_IOCTL_GEM_CLOSE, &close); | ||
82 | } | ||
83 | |||
84 | int main() | ||
85 | { | ||
86 | int ret, vgem_fd; | ||
87 | struct ion_buffer_info info; | ||
88 | uint32_t handle = 0; | ||
89 | struct dma_buf_sync sync = { 0 }; | ||
90 | |||
91 | info.heap_type = ION_HEAP_TYPE_SYSTEM; | ||
92 | info.heap_size = 4096; | ||
93 | info.flag_type = ION_FLAG_CACHED; | ||
94 | |||
95 | ret = ion_export_buffer_fd(&info); | ||
96 | if (ret < 0) { | ||
97 | printf("ion buffer alloc failed\n"); | ||
98 | return -1; | ||
99 | } | ||
100 | |||
101 | vgem_fd = open_vgem(); | ||
102 | if (vgem_fd < 0) { | ||
103 | ret = vgem_fd; | ||
104 | printf("Failed to open vgem\n"); | ||
105 | goto out_ion; | ||
106 | } | ||
107 | |||
108 | ret = import_vgem_fd(vgem_fd, info.buffd, &handle); | ||
109 | |||
110 | if (ret < 0) { | ||
111 | printf("Failed to import buffer\n"); | ||
112 | goto out_vgem; | ||
113 | } | ||
114 | |||
115 | sync.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW; | ||
116 | ret = ioctl(info.buffd, DMA_BUF_IOCTL_SYNC, &sync); | ||
117 | if (ret) | ||
118 | printf("sync start failed %d\n", errno); | ||
119 | |||
120 | memset(info.buffer, 0xff, 4096); | ||
121 | |||
122 | sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW; | ||
123 | ret = ioctl(info.buffd, DMA_BUF_IOCTL_SYNC, &sync); | ||
124 | if (ret) | ||
125 | printf("sync end failed %d\n", errno); | ||
126 | |||
127 | close_handle(vgem_fd, handle); | ||
128 | ret = 0; | ||
129 | |||
130 | out_vgem: | ||
131 | close(vgem_fd); | ||
132 | out_ion: | ||
133 | ion_close_buffer_fd(&info); | ||
134 | printf("done.\n"); | ||
135 | return ret; | ||
136 | } | ||
diff --git a/tools/testing/selftests/android/ion/ionutils.c b/tools/testing/selftests/android/ion/ionutils.c index ce69c14f51fa..7d1d37c4ef6a 100644 --- a/tools/testing/selftests/android/ion/ionutils.c +++ b/tools/testing/selftests/android/ion/ionutils.c | |||
@@ -80,11 +80,6 @@ int ion_export_buffer_fd(struct ion_buffer_info *ion_info) | |||
80 | heap_id = MAX_HEAP_COUNT + 1; | 80 | heap_id = MAX_HEAP_COUNT + 1; |
81 | for (i = 0; i < query.cnt; i++) { | 81 | for (i = 0; i < query.cnt; i++) { |
82 | if (heap_data[i].type == ion_info->heap_type) { | 82 | if (heap_data[i].type == ion_info->heap_type) { |
83 | printf("--------------------------------------\n"); | ||
84 | printf("heap type: %d\n", heap_data[i].type); | ||
85 | printf(" heap id: %d\n", heap_data[i].heap_id); | ||
86 | printf("heap name: %s\n", heap_data[i].name); | ||
87 | printf("--------------------------------------\n"); | ||
88 | heap_id = heap_data[i].heap_id; | 83 | heap_id = heap_data[i].heap_id; |
89 | break; | 84 | break; |
90 | } | 85 | } |
@@ -204,7 +199,6 @@ void ion_close_buffer_fd(struct ion_buffer_info *ion_info) | |||
204 | /* Finally, close the client fd */ | 199 | /* Finally, close the client fd */ |
205 | if (ion_info->ionfd > 0) | 200 | if (ion_info->ionfd > 0) |
206 | close(ion_info->ionfd); | 201 | close(ion_info->ionfd); |
207 | printf("<%s>: buffer release successfully....\n", __func__); | ||
208 | } | 202 | } |
209 | } | 203 | } |
210 | 204 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions index df3dd7fe5f9b..2a4f16fc9819 100644 --- a/tools/testing/selftests/ftrace/test.d/functions +++ b/tools/testing/selftests/ftrace/test.d/functions | |||
@@ -59,6 +59,13 @@ disable_events() { | |||
59 | echo 0 > events/enable | 59 | echo 0 > events/enable |
60 | } | 60 | } |
61 | 61 | ||
62 | clear_synthetic_events() { # reset all current synthetic events | ||
63 | grep -v ^# synthetic_events | | ||
64 | while read line; do | ||
65 | echo "!$line" >> synthetic_events | ||
66 | done | ||
67 | } | ||
68 | |||
62 | initialize_ftrace() { # Reset ftrace to initial-state | 69 | initialize_ftrace() { # Reset ftrace to initial-state |
63 | # As the initial state, ftrace will be set to nop tracer, | 70 | # As the initial state, ftrace will be set to nop tracer, |
64 | # no events, no triggers, no filters, no function filters, | 71 | # no events, no triggers, no filters, no function filters, |
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-extended-error-support.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-extended-error-support.tc new file mode 100644 index 000000000000..786dce7e48be --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-extended-error-support.tc | |||
@@ -0,0 +1,39 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test extended error support | ||
3 | |||
4 | |||
5 | do_reset() { | ||
6 | reset_trigger | ||
7 | echo > set_event | ||
8 | clear_trace | ||
9 | } | ||
10 | |||
11 | fail() { #msg | ||
12 | do_reset | ||
13 | echo $1 | ||
14 | exit_fail | ||
15 | } | ||
16 | |||
17 | if [ ! -f set_event ]; then | ||
18 | echo "event tracing is not supported" | ||
19 | exit_unsupported | ||
20 | fi | ||
21 | |||
22 | if [ ! -f synthetic_events ]; then | ||
23 | echo "synthetic event is not supported" | ||
24 | exit_unsupported | ||
25 | fi | ||
26 | |||
27 | reset_tracer | ||
28 | do_reset | ||
29 | |||
30 | echo "Test extended error support" | ||
31 | echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_wakeup/trigger | ||
32 | echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' >> events/sched/sched_wakeup/trigger &>/dev/null | ||
33 | if ! grep -q "ERROR:" events/sched/sched_wakeup/hist; then | ||
34 | fail "Failed to generate extended error in histogram" | ||
35 | fi | ||
36 | |||
37 | do_reset | ||
38 | |||
39 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-field-variable-support.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-field-variable-support.tc new file mode 100644 index 000000000000..7fd5b4a8f060 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-field-variable-support.tc | |||
@@ -0,0 +1,54 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test field variable support | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit_fail | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f synthetic_events ]; then | ||
22 | echo "synthetic event is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | clear_synthetic_events | ||
27 | reset_tracer | ||
28 | do_reset | ||
29 | |||
30 | echo "Test field variable support" | ||
31 | |||
32 | echo 'wakeup_latency u64 lat; pid_t pid; int prio; char comm[16]' > synthetic_events | ||
33 | echo 'hist:keys=comm:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_waking/trigger | ||
34 | echo 'hist:keys=next_comm:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,sched.sched_waking.prio,next_comm) if next_comm=="ping"' > events/sched/sched_switch/trigger | ||
35 | echo 'hist:keys=pid,prio,comm:vals=lat:sort=pid,prio' > events/synthetic/wakeup_latency/trigger | ||
36 | |||
37 | ping localhost -c 3 | ||
38 | if ! grep -q "ping" events/synthetic/wakeup_latency/hist; then | ||
39 | fail "Failed to create inter-event histogram" | ||
40 | fi | ||
41 | |||
42 | if ! grep -q "synthetic_prio=prio" events/sched/sched_waking/hist; then | ||
43 | fail "Failed to create histogram with field variable" | ||
44 | fi | ||
45 | |||
46 | echo '!hist:keys=next_comm:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,sched.sched_waking.prio,next_comm) if next_comm=="ping"' >> events/sched/sched_switch/trigger | ||
47 | |||
48 | if grep -q "synthetic_prio=prio" events/sched/sched_waking/hist; then | ||
49 | fail "Failed to remove histogram with field variable" | ||
50 | fi | ||
51 | |||
52 | do_reset | ||
53 | |||
54 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc new file mode 100644 index 000000000000..c93dbe38b5df --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc | |||
@@ -0,0 +1,58 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test inter-event combined histogram trigger | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit_fail | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f synthetic_events ]; then | ||
22 | echo "synthetic event is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | reset_tracer | ||
27 | do_reset | ||
28 | clear_synthetic_events | ||
29 | |||
30 | echo "Test create synthetic event" | ||
31 | |||
32 | echo 'waking_latency u64 lat pid_t pid' > synthetic_events | ||
33 | if [ ! -d events/synthetic/waking_latency ]; then | ||
34 | fail "Failed to create waking_latency synthetic event" | ||
35 | fi | ||
36 | |||
37 | echo "Test combined histogram" | ||
38 | |||
39 | echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_waking/trigger | ||
40 | echo 'hist:keys=pid:waking_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).waking_latency($waking_lat,pid) if comm=="ping"' > events/sched/sched_wakeup/trigger | ||
41 | echo 'hist:keys=pid,lat:sort=pid,lat' > events/synthetic/waking_latency/trigger | ||
42 | |||
43 | echo 'wakeup_latency u64 lat pid_t pid' >> synthetic_events | ||
44 | echo 'hist:keys=pid:ts1=common_timestamp.usecs if comm=="ping"' >> events/sched/sched_wakeup/trigger | ||
45 | echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts1:onmatch(sched.sched_wakeup).wakeup_latency($wakeup_lat,next_pid) if next_comm=="ping"' > events/sched/sched_switch/trigger | ||
46 | |||
47 | echo 'waking+wakeup_latency u64 lat; pid_t pid' >> synthetic_events | ||
48 | echo 'hist:keys=pid,lat:sort=pid,lat:ww_lat=$waking_lat+$wakeup_lat:onmatch(synthetic.wakeup_latency).waking+wakeup_latency($ww_lat,pid)' >> events/synthetic/wakeup_latency/trigger | ||
49 | echo 'hist:keys=pid,lat:sort=pid,lat' >> events/synthetic/waking+wakeup_latency/trigger | ||
50 | |||
51 | ping localhost -c 3 | ||
52 | if ! grep -q "pid:" events/synthetic/waking+wakeup_latency/hist; then | ||
53 | fail "Failed to create combined histogram" | ||
54 | fi | ||
55 | |||
56 | do_reset | ||
57 | |||
58 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-action-hist.tc new file mode 100644 index 000000000000..e84e7d048566 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-action-hist.tc | |||
@@ -0,0 +1,50 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test inter-event histogram trigger onmatch action | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit_fail | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f synthetic_events ]; then | ||
22 | echo "synthetic event is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | clear_synthetic_events | ||
27 | reset_tracer | ||
28 | do_reset | ||
29 | |||
30 | echo "Test create synthetic event" | ||
31 | |||
32 | echo 'wakeup_latency u64 lat pid_t pid char comm[16]' > synthetic_events | ||
33 | if [ ! -d events/synthetic/wakeup_latency ]; then | ||
34 | fail "Failed to create wakeup_latency synthetic event" | ||
35 | fi | ||
36 | |||
37 | echo "Test create histogram for synthetic event" | ||
38 | echo "Test histogram variables,simple expression support and onmatch action" | ||
39 | |||
40 | echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_wakeup/trigger | ||
41 | echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_wakeup).wakeup_latency($wakeup_lat,next_pid,next_comm) if next_comm=="ping"' > events/sched/sched_switch/trigger | ||
42 | echo 'hist:keys=comm,pid,lat:wakeup_lat=lat:sort=lat' > events/synthetic/wakeup_latency/trigger | ||
43 | ping localhost -c 5 | ||
44 | if ! grep -q "ping" events/synthetic/wakeup_latency/hist; then | ||
45 | fail "Failed to create onmatch action inter-event histogram" | ||
46 | fi | ||
47 | |||
48 | do_reset | ||
49 | |||
50 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-onmax-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-onmax-action-hist.tc new file mode 100644 index 000000000000..7907d8aacde3 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-onmax-action-hist.tc | |||
@@ -0,0 +1,50 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test inter-event histogram trigger onmatch-onmax action | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit_fail | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f synthetic_events ]; then | ||
22 | echo "synthetic event is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | clear_synthetic_events | ||
27 | reset_tracer | ||
28 | do_reset | ||
29 | |||
30 | echo "Test create synthetic event" | ||
31 | |||
32 | echo 'wakeup_latency u64 lat pid_t pid char comm[16]' > synthetic_events | ||
33 | if [ ! -d events/synthetic/wakeup_latency ]; then | ||
34 | fail "Failed to create wakeup_latency synthetic event" | ||
35 | fi | ||
36 | |||
37 | echo "Test create histogram for synthetic event" | ||
38 | echo "Test histogram variables,simple expression support and onmatch-onmax action" | ||
39 | |||
40 | echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_wakeup/trigger | ||
41 | echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_wakeup).wakeup_latency($wakeup_lat,next_pid,next_comm):onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm) if next_comm=="ping"' >> events/sched/sched_switch/trigger | ||
42 | echo 'hist:keys=comm,pid,lat:wakeup_lat=lat:sort=lat' > events/synthetic/wakeup_latency/trigger | ||
43 | ping localhost -c 5 | ||
44 | if [ ! grep -q "ping" events/synthetic/wakeup_latency/hist -o ! grep -q "max:" events/sched/sched_switch/hist]; then | ||
45 | fail "Failed to create onmatch-onmax action inter-event histogram" | ||
46 | fi | ||
47 | |||
48 | do_reset | ||
49 | |||
50 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmax-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmax-action-hist.tc new file mode 100644 index 000000000000..38b7ed6242b2 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmax-action-hist.tc | |||
@@ -0,0 +1,48 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test inter-event histogram trigger onmax action | ||
3 | |||
4 | do_reset() { | ||
5 | reset_trigger | ||
6 | echo > set_event | ||
7 | clear_trace | ||
8 | } | ||
9 | |||
10 | fail() { #msg | ||
11 | do_reset | ||
12 | echo $1 | ||
13 | exit_fail | ||
14 | } | ||
15 | |||
16 | if [ ! -f set_event ]; then | ||
17 | echo "event tracing is not supported" | ||
18 | exit_unsupported | ||
19 | fi | ||
20 | |||
21 | if [ ! -f synthetic_events ]; then | ||
22 | echo "synthetic event is not supported" | ||
23 | exit_unsupported | ||
24 | fi | ||
25 | |||
26 | clear_synthetic_events | ||
27 | reset_tracer | ||
28 | do_reset | ||
29 | |||
30 | echo "Test create synthetic event" | ||
31 | |||
32 | echo 'wakeup_latency u64 lat pid_t pid char comm[16]' > synthetic_events | ||
33 | if [ ! -d events/synthetic/wakeup_latency ]; then | ||
34 | fail "Failed to create wakeup_latency synthetic event" | ||
35 | fi | ||
36 | |||
37 | echo "Test onmax action" | ||
38 | |||
39 | echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' >> events/sched/sched_waking/trigger | ||
40 | echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm) if next_comm=="ping"' >> events/sched/sched_switch/trigger | ||
41 | ping localhost -c 3 | ||
42 | if ! grep -q "max:" events/sched/sched_switch/hist; then | ||
43 | fail "Failed to create onmax action inter-event histogram" | ||
44 | fi | ||
45 | |||
46 | do_reset | ||
47 | |||
48 | exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-createremove.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-createremove.tc new file mode 100644 index 000000000000..cef11377dcbd --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-createremove.tc | |||
@@ -0,0 +1,54 @@ | |||
1 | #!/bin/sh | ||
2 | # description: event trigger - test synthetic event create remove | ||
3 | do_reset() { | ||
4 | reset_trigger | ||
5 | echo > set_event | ||
6 | clear_trace | ||
7 | } | ||
8 | |||
9 | fail() { #msg | ||
10 | do_reset | ||
11 | echo $1 | ||
12 | exit_fail | ||
13 | } | ||
14 | |||
15 | if [ ! -f set_event ]; then | ||
16 | echo "event tracing is not supported" | ||
17 | exit_unsupported | ||
18 | fi | ||
19 | |||
20 | if [ ! -f synthetic_events ]; then | ||
21 | echo "synthetic event is not supported" | ||
22 | exit_unsupported | ||
23 | fi | ||
24 | |||
25 | clear_synthetic_events | ||
26 | reset_tracer | ||
27 | do_reset | ||
28 | |||
29 | echo "Test create synthetic event" | ||
30 | |||
31 | echo 'wakeup_latency u64 lat pid_t pid char comm[16]' > synthetic_events | ||
32 | if [ ! -d events/synthetic/wakeup_latency ]; then | ||
33 | fail "Failed to create wakeup_latency synthetic event" | ||
34 | fi | ||
35 | |||
36 | reset_trigger | ||
37 | |||
38 | echo "Test create synthetic event with an error" | ||
39 | echo 'wakeup_latency u64 lat pid_t pid char' > synthetic_events > /dev/null | ||
40 | if [ -d events/synthetic/wakeup_latency ]; then | ||
41 | fail "Created wakeup_latency synthetic event with an invalid format" | ||
42 | fi | ||
43 | |||
44 | reset_trigger | ||
45 | |||
46 | echo "Test remove synthetic event" | ||
47 | echo '!wakeup_latency u64 lat pid_t pid char comm[16]' > synthetic_events | ||
48 | if [ -d events/synthetic/wakeup_latency ]; then | ||
49 | fail "Failed to delete wakeup_latency synthetic event" | ||
50 | fi | ||
51 | |||
52 | do_reset | ||
53 | |||
54 | exit 0 | ||
diff --git a/tools/testing/selftests/futex/Makefile b/tools/testing/selftests/futex/Makefile index a63e8453984d..8497a376ef9d 100644 --- a/tools/testing/selftests/futex/Makefile +++ b/tools/testing/selftests/futex/Makefile | |||
@@ -18,6 +18,10 @@ all: | |||
18 | done | 18 | done |
19 | 19 | ||
20 | override define RUN_TESTS | 20 | override define RUN_TESTS |
21 | @export KSFT_TAP_LEVEL=`echo 1`; | ||
22 | @echo "TAP version 13"; | ||
23 | @echo "selftests: futex"; | ||
24 | @echo "========================================"; | ||
21 | @cd $(OUTPUT); ./run.sh | 25 | @cd $(OUTPUT); ./run.sh |
22 | endef | 26 | endef |
23 | 27 | ||
diff --git a/tools/testing/selftests/intel_pstate/Makefile b/tools/testing/selftests/intel_pstate/Makefile index 5a3f7d37e912..7340fd6a9a9f 100644 --- a/tools/testing/selftests/intel_pstate/Makefile +++ b/tools/testing/selftests/intel_pstate/Makefile | |||
@@ -2,7 +2,10 @@ | |||
2 | CFLAGS := $(CFLAGS) -Wall -D_GNU_SOURCE | 2 | CFLAGS := $(CFLAGS) -Wall -D_GNU_SOURCE |
3 | LDLIBS := $(LDLIBS) -lm | 3 | LDLIBS := $(LDLIBS) -lm |
4 | 4 | ||
5 | ifeq (,$(filter $(ARCH),x86)) | 5 | uname_M := $(shell uname -m 2>/dev/null || echo not) |
6 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) | ||
7 | |||
8 | ifeq (x86,$(ARCH)) | ||
6 | TEST_GEN_FILES := msr aperf | 9 | TEST_GEN_FILES := msr aperf |
7 | endif | 10 | endif |
8 | 11 | ||
diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h index 1a52b03962a3..1b9d8ecdebce 100644 --- a/tools/testing/selftests/kselftest.h +++ b/tools/testing/selftests/kselftest.h | |||
@@ -57,7 +57,8 @@ static inline int ksft_get_error_cnt(void) { return ksft_cnt.ksft_error; } | |||
57 | 57 | ||
58 | static inline void ksft_print_header(void) | 58 | static inline void ksft_print_header(void) |
59 | { | 59 | { |
60 | printf("TAP version 13\n"); | 60 | if (!(getenv("KSFT_TAP_LEVEL"))) |
61 | printf("TAP version 13\n"); | ||
61 | } | 62 | } |
62 | 63 | ||
63 | static inline void ksft_print_cnts(void) | 64 | static inline void ksft_print_cnts(void) |
diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index e81bd28bdd89..6ae3730c4ee3 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h | |||
@@ -107,6 +107,27 @@ | |||
107 | __FILE__, __LINE__, _metadata->name, ##__VA_ARGS__) | 107 | __FILE__, __LINE__, _metadata->name, ##__VA_ARGS__) |
108 | 108 | ||
109 | /** | 109 | /** |
110 | * XFAIL(statement, fmt, ...) | ||
111 | * | ||
112 | * @statement: statement to run after reporting XFAIL | ||
113 | * @fmt: format string | ||
114 | * @...: optional arguments | ||
115 | * | ||
116 | * This forces a "pass" after reporting a failure with an XFAIL prefix, | ||
117 | * and runs "statement", which is usually "return" or "goto skip". | ||
118 | */ | ||
119 | #define XFAIL(statement, fmt, ...) do { \ | ||
120 | if (TH_LOG_ENABLED) { \ | ||
121 | fprintf(TH_LOG_STREAM, "[ XFAIL! ] " fmt "\n", \ | ||
122 | ##__VA_ARGS__); \ | ||
123 | } \ | ||
124 | /* TODO: find a way to pass xfail to test runner process. */ \ | ||
125 | _metadata->passed = 1; \ | ||
126 | _metadata->trigger = 0; \ | ||
127 | statement; \ | ||
128 | } while (0) | ||
129 | |||
130 | /** | ||
110 | * TEST(test_name) - Defines the test function and creates the registration | 131 | * TEST(test_name) - Defines the test function and creates the registration |
111 | * stub | 132 | * stub |
112 | * | 133 | * |
@@ -198,7 +219,7 @@ | |||
198 | 219 | ||
199 | /** | 220 | /** |
200 | * FIXTURE_SETUP(fixture_name) - Prepares the setup function for the fixture. | 221 | * FIXTURE_SETUP(fixture_name) - Prepares the setup function for the fixture. |
201 | * *_metadata* is included so that ASSERT_* work as a convenience | 222 | * *_metadata* is included so that EXPECT_* and ASSERT_* work correctly. |
202 | * | 223 | * |
203 | * @fixture_name: fixture name | 224 | * @fixture_name: fixture name |
204 | * | 225 | * |
@@ -221,6 +242,7 @@ | |||
221 | FIXTURE_DATA(fixture_name) __attribute__((unused)) *self) | 242 | FIXTURE_DATA(fixture_name) __attribute__((unused)) *self) |
222 | /** | 243 | /** |
223 | * FIXTURE_TEARDOWN(fixture_name) | 244 | * FIXTURE_TEARDOWN(fixture_name) |
245 | * *_metadata* is included so that EXPECT_* and ASSERT_* work correctly. | ||
224 | * | 246 | * |
225 | * @fixture_name: fixture name | 247 | * @fixture_name: fixture name |
226 | * | 248 | * |
@@ -253,6 +275,8 @@ | |||
253 | * Defines a test that depends on a fixture (e.g., is part of a test case). | 275 | * Defines a test that depends on a fixture (e.g., is part of a test case). |
254 | * Very similar to TEST() except that *self* is the setup instance of fixture's | 276 | * Very similar to TEST() except that *self* is the setup instance of fixture's |
255 | * datatype exposed for use by the implementation. | 277 | * datatype exposed for use by the implementation. |
278 | * | ||
279 | * Warning: use of ASSERT_* here will skip TEARDOWN. | ||
256 | */ | 280 | */ |
257 | /* TODO(wad) register fixtures on dedicated test lists. */ | 281 | /* TODO(wad) register fixtures on dedicated test lists. */ |
258 | #define TEST_F(fixture_name, test_name) \ | 282 | #define TEST_F(fixture_name, test_name) \ |
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile new file mode 100644 index 000000000000..2ddcc96ae456 --- /dev/null +++ b/tools/testing/selftests/kvm/Makefile | |||
@@ -0,0 +1,40 @@ | |||
1 | all: | ||
2 | |||
3 | top_srcdir = ../../../../ | ||
4 | UNAME_M := $(shell uname -m) | ||
5 | |||
6 | LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c | ||
7 | LIBKVM_x86_64 = lib/x86.c lib/vmx.c | ||
8 | |||
9 | TEST_GEN_PROGS_x86_64 = set_sregs_test | ||
10 | TEST_GEN_PROGS_x86_64 += sync_regs_test | ||
11 | TEST_GEN_PROGS_x86_64 += vmx_tsc_adjust_test | ||
12 | |||
13 | TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) | ||
14 | LIBKVM += $(LIBKVM_$(UNAME_M)) | ||
15 | |||
16 | INSTALL_HDR_PATH = $(top_srcdir)/usr | ||
17 | LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/ | ||
18 | CFLAGS += -O2 -g -std=gnu99 -I$(LINUX_HDR_PATH) -Iinclude -I$(<D) | ||
19 | |||
20 | # After inclusion, $(OUTPUT) is defined and | ||
21 | # $(TEST_GEN_PROGS) starts with $(OUTPUT)/ | ||
22 | include ../lib.mk | ||
23 | |||
24 | STATIC_LIBS := $(OUTPUT)/libkvm.a | ||
25 | LIBKVM_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM)) | ||
26 | EXTRA_CLEAN += $(LIBKVM_OBJ) $(STATIC_LIBS) | ||
27 | |||
28 | x := $(shell mkdir -p $(sort $(dir $(LIBKVM_OBJ)))) | ||
29 | $(LIBKVM_OBJ): $(OUTPUT)/%.o: %.c | ||
30 | $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ | ||
31 | |||
32 | $(OUTPUT)/libkvm.a: $(LIBKVM_OBJ) | ||
33 | $(AR) crs $@ $^ | ||
34 | |||
35 | $(LINUX_HDR_PATH): | ||
36 | make -C $(top_srcdir) headers_install | ||
37 | |||
38 | all: $(STATIC_LIBS) $(LINUX_HDR_PATH) | ||
39 | $(TEST_GEN_PROGS): $(STATIC_LIBS) | ||
40 | $(TEST_GEN_PROGS) $(LIBKVM_OBJ): | $(LINUX_HDR_PATH) | ||
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h new file mode 100644 index 000000000000..637b7017b6ee --- /dev/null +++ b/tools/testing/selftests/kvm/include/kvm_util.h | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/include/kvm_util.h | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | * | ||
8 | */ | ||
9 | #ifndef SELFTEST_KVM_UTIL_H | ||
10 | #define SELFTEST_KVM_UTIL_H 1 | ||
11 | |||
12 | #include "test_util.h" | ||
13 | |||
14 | #include "asm/kvm.h" | ||
15 | #include "linux/kvm.h" | ||
16 | #include <sys/ioctl.h> | ||
17 | |||
18 | #include "sparsebit.h" | ||
19 | |||
20 | /* | ||
21 | * Memslots can't cover the gfn starting at this gpa otherwise vCPUs can't be | ||
22 | * created. Only applies to VMs using EPT. | ||
23 | */ | ||
24 | #define KVM_DEFAULT_IDENTITY_MAP_ADDRESS 0xfffbc000ul | ||
25 | |||
26 | |||
27 | /* Callers of kvm_util only have an incomplete/opaque description of the | ||
28 | * structure kvm_util is using to maintain the state of a VM. | ||
29 | */ | ||
30 | struct kvm_vm; | ||
31 | |||
32 | typedef uint64_t vm_paddr_t; /* Virtual Machine (Guest) physical address */ | ||
33 | typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */ | ||
34 | |||
35 | /* Minimum allocated guest virtual and physical addresses */ | ||
36 | #define KVM_UTIL_MIN_VADDR 0x2000 | ||
37 | |||
38 | #define DEFAULT_GUEST_PHY_PAGES 512 | ||
39 | #define DEFAULT_GUEST_STACK_VADDR_MIN 0xab6000 | ||
40 | #define DEFAULT_STACK_PGS 5 | ||
41 | |||
42 | enum vm_guest_mode { | ||
43 | VM_MODE_FLAT48PG, | ||
44 | }; | ||
45 | |||
46 | enum vm_mem_backing_src_type { | ||
47 | VM_MEM_SRC_ANONYMOUS, | ||
48 | VM_MEM_SRC_ANONYMOUS_THP, | ||
49 | VM_MEM_SRC_ANONYMOUS_HUGETLB, | ||
50 | }; | ||
51 | |||
52 | int kvm_check_cap(long cap); | ||
53 | |||
54 | struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm); | ||
55 | void kvm_vm_free(struct kvm_vm *vmp); | ||
56 | |||
57 | int kvm_memcmp_hva_gva(void *hva, | ||
58 | struct kvm_vm *vm, const vm_vaddr_t gva, size_t len); | ||
59 | |||
60 | void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename, | ||
61 | uint32_t data_memslot, uint32_t pgd_memslot); | ||
62 | |||
63 | void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); | ||
64 | void vcpu_dump(FILE *stream, struct kvm_vm *vm, | ||
65 | uint32_t vcpuid, uint8_t indent); | ||
66 | |||
67 | void vm_create_irqchip(struct kvm_vm *vm); | ||
68 | |||
69 | void vm_userspace_mem_region_add(struct kvm_vm *vm, | ||
70 | enum vm_mem_backing_src_type src_type, | ||
71 | uint64_t guest_paddr, uint32_t slot, uint64_t npages, | ||
72 | uint32_t flags); | ||
73 | |||
74 | void vcpu_ioctl(struct kvm_vm *vm, | ||
75 | uint32_t vcpuid, unsigned long ioctl, void *arg); | ||
76 | void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); | ||
77 | void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); | ||
78 | void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid); | ||
79 | vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, | ||
80 | uint32_t data_memslot, uint32_t pgd_memslot); | ||
81 | void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa); | ||
82 | void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva); | ||
83 | vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva); | ||
84 | vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva); | ||
85 | |||
86 | struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid); | ||
87 | void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); | ||
88 | int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); | ||
89 | void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, | ||
90 | struct kvm_mp_state *mp_state); | ||
91 | void vcpu_regs_get(struct kvm_vm *vm, | ||
92 | uint32_t vcpuid, struct kvm_regs *regs); | ||
93 | void vcpu_regs_set(struct kvm_vm *vm, | ||
94 | uint32_t vcpuid, struct kvm_regs *regs); | ||
95 | void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); | ||
96 | void vcpu_sregs_get(struct kvm_vm *vm, | ||
97 | uint32_t vcpuid, struct kvm_sregs *sregs); | ||
98 | void vcpu_sregs_set(struct kvm_vm *vm, | ||
99 | uint32_t vcpuid, struct kvm_sregs *sregs); | ||
100 | int _vcpu_sregs_set(struct kvm_vm *vm, | ||
101 | uint32_t vcpuid, struct kvm_sregs *sregs); | ||
102 | void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, | ||
103 | struct kvm_vcpu_events *events); | ||
104 | void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, | ||
105 | struct kvm_vcpu_events *events); | ||
106 | |||
107 | const char *exit_reason_str(unsigned int exit_reason); | ||
108 | |||
109 | void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot); | ||
110 | void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, | ||
111 | uint32_t pgd_memslot); | ||
112 | vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, | ||
113 | vm_paddr_t paddr_min, uint32_t memslot); | ||
114 | |||
115 | struct kvm_cpuid2 *kvm_get_supported_cpuid(void); | ||
116 | void vcpu_set_cpuid( | ||
117 | struct kvm_vm *vm, uint32_t vcpuid, struct kvm_cpuid2 *cpuid); | ||
118 | |||
119 | struct kvm_cpuid_entry2 * | ||
120 | kvm_get_supported_cpuid_index(uint32_t function, uint32_t index); | ||
121 | |||
122 | static inline struct kvm_cpuid_entry2 * | ||
123 | kvm_get_supported_cpuid_entry(uint32_t function) | ||
124 | { | ||
125 | return kvm_get_supported_cpuid_index(function, 0); | ||
126 | } | ||
127 | |||
128 | struct kvm_vm *vm_create_default(uint32_t vcpuid, void *guest_code); | ||
129 | void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code); | ||
130 | |||
131 | typedef void (*vmx_guest_code_t)(vm_vaddr_t vmxon_vaddr, | ||
132 | vm_paddr_t vmxon_paddr, | ||
133 | vm_vaddr_t vmcs_vaddr, | ||
134 | vm_paddr_t vmcs_paddr); | ||
135 | |||
136 | struct kvm_userspace_memory_region * | ||
137 | kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, | ||
138 | uint64_t end); | ||
139 | |||
140 | struct kvm_dirty_log * | ||
141 | allocate_kvm_dirty_log(struct kvm_userspace_memory_region *region); | ||
142 | |||
143 | int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd); | ||
144 | |||
145 | #endif /* SELFTEST_KVM_UTIL_H */ | ||
diff --git a/tools/testing/selftests/kvm/include/sparsebit.h b/tools/testing/selftests/kvm/include/sparsebit.h new file mode 100644 index 000000000000..54cfeb6568d3 --- /dev/null +++ b/tools/testing/selftests/kvm/include/sparsebit.h | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/include/sparsebit.h | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | * | ||
8 | * | ||
9 | * Header file that describes API to the sparsebit library. | ||
10 | * This library provides a memory efficient means of storing | ||
11 | * the settings of bits indexed via a uint64_t. Memory usage | ||
12 | * is reasonable, significantly less than (2^64 / 8) bytes, as | ||
13 | * long as bits that are mostly set or mostly cleared are close | ||
14 | * to each other. This library is efficient in memory usage | ||
15 | * even in the case where most bits are set. | ||
16 | */ | ||
17 | |||
18 | #ifndef _TEST_SPARSEBIT_H_ | ||
19 | #define _TEST_SPARSEBIT_H_ | ||
20 | |||
21 | #include <stdbool.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdio.h> | ||
24 | |||
25 | #ifdef __cplusplus | ||
26 | extern "C" { | ||
27 | #endif | ||
28 | |||
29 | struct sparsebit; | ||
30 | typedef uint64_t sparsebit_idx_t; | ||
31 | typedef uint64_t sparsebit_num_t; | ||
32 | |||
33 | struct sparsebit *sparsebit_alloc(void); | ||
34 | void sparsebit_free(struct sparsebit **sbitp); | ||
35 | void sparsebit_copy(struct sparsebit *dstp, struct sparsebit *src); | ||
36 | |||
37 | bool sparsebit_is_set(struct sparsebit *sbit, sparsebit_idx_t idx); | ||
38 | bool sparsebit_is_set_num(struct sparsebit *sbit, | ||
39 | sparsebit_idx_t idx, sparsebit_num_t num); | ||
40 | bool sparsebit_is_clear(struct sparsebit *sbit, sparsebit_idx_t idx); | ||
41 | bool sparsebit_is_clear_num(struct sparsebit *sbit, | ||
42 | sparsebit_idx_t idx, sparsebit_num_t num); | ||
43 | sparsebit_num_t sparsebit_num_set(struct sparsebit *sbit); | ||
44 | bool sparsebit_any_set(struct sparsebit *sbit); | ||
45 | bool sparsebit_any_clear(struct sparsebit *sbit); | ||
46 | bool sparsebit_all_set(struct sparsebit *sbit); | ||
47 | bool sparsebit_all_clear(struct sparsebit *sbit); | ||
48 | sparsebit_idx_t sparsebit_first_set(struct sparsebit *sbit); | ||
49 | sparsebit_idx_t sparsebit_first_clear(struct sparsebit *sbit); | ||
50 | sparsebit_idx_t sparsebit_next_set(struct sparsebit *sbit, sparsebit_idx_t prev); | ||
51 | sparsebit_idx_t sparsebit_next_clear(struct sparsebit *sbit, sparsebit_idx_t prev); | ||
52 | sparsebit_idx_t sparsebit_next_set_num(struct sparsebit *sbit, | ||
53 | sparsebit_idx_t start, sparsebit_num_t num); | ||
54 | sparsebit_idx_t sparsebit_next_clear_num(struct sparsebit *sbit, | ||
55 | sparsebit_idx_t start, sparsebit_num_t num); | ||
56 | |||
57 | void sparsebit_set(struct sparsebit *sbitp, sparsebit_idx_t idx); | ||
58 | void sparsebit_set_num(struct sparsebit *sbitp, sparsebit_idx_t start, | ||
59 | sparsebit_num_t num); | ||
60 | void sparsebit_set_all(struct sparsebit *sbitp); | ||
61 | |||
62 | void sparsebit_clear(struct sparsebit *sbitp, sparsebit_idx_t idx); | ||
63 | void sparsebit_clear_num(struct sparsebit *sbitp, | ||
64 | sparsebit_idx_t start, sparsebit_num_t num); | ||
65 | void sparsebit_clear_all(struct sparsebit *sbitp); | ||
66 | |||
67 | void sparsebit_dump(FILE *stream, struct sparsebit *sbit, | ||
68 | unsigned int indent); | ||
69 | void sparsebit_validate_internal(struct sparsebit *sbit); | ||
70 | |||
71 | #ifdef __cplusplus | ||
72 | } | ||
73 | #endif | ||
74 | |||
75 | #endif /* _TEST_SPARSEBIT_H_ */ | ||
diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h new file mode 100644 index 000000000000..7ab98e41324f --- /dev/null +++ b/tools/testing/selftests/kvm/include/test_util.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/include/test_util.h | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #ifndef TEST_UTIL_H | ||
11 | #define TEST_UTIL_H 1 | ||
12 | |||
13 | #include <stdlib.h> | ||
14 | #include <stdarg.h> | ||
15 | #include <stdbool.h> | ||
16 | #include <stdio.h> | ||
17 | #include <string.h> | ||
18 | #include <inttypes.h> | ||
19 | #include <errno.h> | ||
20 | #include <unistd.h> | ||
21 | #include <fcntl.h> | ||
22 | |||
23 | ssize_t test_write(int fd, const void *buf, size_t count); | ||
24 | ssize_t test_read(int fd, void *buf, size_t count); | ||
25 | int test_seq_read(const char *path, char **bufp, size_t *sizep); | ||
26 | |||
27 | void test_assert(bool exp, const char *exp_str, | ||
28 | const char *file, unsigned int line, const char *fmt, ...); | ||
29 | |||
30 | #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) | ||
31 | |||
32 | #define TEST_ASSERT(e, fmt, ...) \ | ||
33 | test_assert((e), #e, __FILE__, __LINE__, fmt, ##__VA_ARGS__) | ||
34 | |||
35 | #define ASSERT_EQ(a, b) do { \ | ||
36 | typeof(a) __a = (a); \ | ||
37 | typeof(b) __b = (b); \ | ||
38 | TEST_ASSERT(__a == __b, \ | ||
39 | "ASSERT_EQ(%s, %s) failed.\n" \ | ||
40 | "\t%s is %#lx\n" \ | ||
41 | "\t%s is %#lx", \ | ||
42 | #a, #b, #a, (unsigned long) __a, #b, (unsigned long) __b); \ | ||
43 | } while (0) | ||
44 | |||
45 | #endif /* TEST_UTIL_H */ | ||
diff --git a/tools/testing/selftests/kvm/include/vmx.h b/tools/testing/selftests/kvm/include/vmx.h new file mode 100644 index 000000000000..6ed8499807fd --- /dev/null +++ b/tools/testing/selftests/kvm/include/vmx.h | |||
@@ -0,0 +1,494 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/include/vmx.h | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #ifndef SELFTEST_KVM_VMX_H | ||
11 | #define SELFTEST_KVM_VMX_H | ||
12 | |||
13 | #include <stdint.h> | ||
14 | #include "x86.h" | ||
15 | |||
16 | #define CPUID_VMX_BIT 5 | ||
17 | |||
18 | #define CPUID_VMX (1 << 5) | ||
19 | |||
20 | /* | ||
21 | * Definitions of Primary Processor-Based VM-Execution Controls. | ||
22 | */ | ||
23 | #define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004 | ||
24 | #define CPU_BASED_USE_TSC_OFFSETING 0x00000008 | ||
25 | #define CPU_BASED_HLT_EXITING 0x00000080 | ||
26 | #define CPU_BASED_INVLPG_EXITING 0x00000200 | ||
27 | #define CPU_BASED_MWAIT_EXITING 0x00000400 | ||
28 | #define CPU_BASED_RDPMC_EXITING 0x00000800 | ||
29 | #define CPU_BASED_RDTSC_EXITING 0x00001000 | ||
30 | #define CPU_BASED_CR3_LOAD_EXITING 0x00008000 | ||
31 | #define CPU_BASED_CR3_STORE_EXITING 0x00010000 | ||
32 | #define CPU_BASED_CR8_LOAD_EXITING 0x00080000 | ||
33 | #define CPU_BASED_CR8_STORE_EXITING 0x00100000 | ||
34 | #define CPU_BASED_TPR_SHADOW 0x00200000 | ||
35 | #define CPU_BASED_VIRTUAL_NMI_PENDING 0x00400000 | ||
36 | #define CPU_BASED_MOV_DR_EXITING 0x00800000 | ||
37 | #define CPU_BASED_UNCOND_IO_EXITING 0x01000000 | ||
38 | #define CPU_BASED_USE_IO_BITMAPS 0x02000000 | ||
39 | #define CPU_BASED_MONITOR_TRAP 0x08000000 | ||
40 | #define CPU_BASED_USE_MSR_BITMAPS 0x10000000 | ||
41 | #define CPU_BASED_MONITOR_EXITING 0x20000000 | ||
42 | #define CPU_BASED_PAUSE_EXITING 0x40000000 | ||
43 | #define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 0x80000000 | ||
44 | |||
45 | #define CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR 0x0401e172 | ||
46 | |||
47 | /* | ||
48 | * Definitions of Secondary Processor-Based VM-Execution Controls. | ||
49 | */ | ||
50 | #define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 | ||
51 | #define SECONDARY_EXEC_ENABLE_EPT 0x00000002 | ||
52 | #define SECONDARY_EXEC_DESC 0x00000004 | ||
53 | #define SECONDARY_EXEC_RDTSCP 0x00000008 | ||
54 | #define SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE 0x00000010 | ||
55 | #define SECONDARY_EXEC_ENABLE_VPID 0x00000020 | ||
56 | #define SECONDARY_EXEC_WBINVD_EXITING 0x00000040 | ||
57 | #define SECONDARY_EXEC_UNRESTRICTED_GUEST 0x00000080 | ||
58 | #define SECONDARY_EXEC_APIC_REGISTER_VIRT 0x00000100 | ||
59 | #define SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY 0x00000200 | ||
60 | #define SECONDARY_EXEC_PAUSE_LOOP_EXITING 0x00000400 | ||
61 | #define SECONDARY_EXEC_RDRAND_EXITING 0x00000800 | ||
62 | #define SECONDARY_EXEC_ENABLE_INVPCID 0x00001000 | ||
63 | #define SECONDARY_EXEC_ENABLE_VMFUNC 0x00002000 | ||
64 | #define SECONDARY_EXEC_SHADOW_VMCS 0x00004000 | ||
65 | #define SECONDARY_EXEC_RDSEED_EXITING 0x00010000 | ||
66 | #define SECONDARY_EXEC_ENABLE_PML 0x00020000 | ||
67 | #define SECONDARY_EPT_VE 0x00040000 | ||
68 | #define SECONDARY_ENABLE_XSAV_RESTORE 0x00100000 | ||
69 | #define SECONDARY_EXEC_TSC_SCALING 0x02000000 | ||
70 | |||
71 | #define PIN_BASED_EXT_INTR_MASK 0x00000001 | ||
72 | #define PIN_BASED_NMI_EXITING 0x00000008 | ||
73 | #define PIN_BASED_VIRTUAL_NMIS 0x00000020 | ||
74 | #define PIN_BASED_VMX_PREEMPTION_TIMER 0x00000040 | ||
75 | #define PIN_BASED_POSTED_INTR 0x00000080 | ||
76 | |||
77 | #define PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR 0x00000016 | ||
78 | |||
79 | #define VM_EXIT_SAVE_DEBUG_CONTROLS 0x00000004 | ||
80 | #define VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200 | ||
81 | #define VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL 0x00001000 | ||
82 | #define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 | ||
83 | #define VM_EXIT_SAVE_IA32_PAT 0x00040000 | ||
84 | #define VM_EXIT_LOAD_IA32_PAT 0x00080000 | ||
85 | #define VM_EXIT_SAVE_IA32_EFER 0x00100000 | ||
86 | #define VM_EXIT_LOAD_IA32_EFER 0x00200000 | ||
87 | #define VM_EXIT_SAVE_VMX_PREEMPTION_TIMER 0x00400000 | ||
88 | |||
89 | #define VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR 0x00036dff | ||
90 | |||
91 | #define VM_ENTRY_LOAD_DEBUG_CONTROLS 0x00000004 | ||
92 | #define VM_ENTRY_IA32E_MODE 0x00000200 | ||
93 | #define VM_ENTRY_SMM 0x00000400 | ||
94 | #define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800 | ||
95 | #define VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL 0x00002000 | ||
96 | #define VM_ENTRY_LOAD_IA32_PAT 0x00004000 | ||
97 | #define VM_ENTRY_LOAD_IA32_EFER 0x00008000 | ||
98 | |||
99 | #define VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR 0x000011ff | ||
100 | |||
101 | #define VMX_MISC_PREEMPTION_TIMER_RATE_MASK 0x0000001f | ||
102 | #define VMX_MISC_SAVE_EFER_LMA 0x00000020 | ||
103 | |||
104 | #define EXIT_REASON_FAILED_VMENTRY 0x80000000 | ||
105 | #define EXIT_REASON_EXCEPTION_NMI 0 | ||
106 | #define EXIT_REASON_EXTERNAL_INTERRUPT 1 | ||
107 | #define EXIT_REASON_TRIPLE_FAULT 2 | ||
108 | #define EXIT_REASON_PENDING_INTERRUPT 7 | ||
109 | #define EXIT_REASON_NMI_WINDOW 8 | ||
110 | #define EXIT_REASON_TASK_SWITCH 9 | ||
111 | #define EXIT_REASON_CPUID 10 | ||
112 | #define EXIT_REASON_HLT 12 | ||
113 | #define EXIT_REASON_INVD 13 | ||
114 | #define EXIT_REASON_INVLPG 14 | ||
115 | #define EXIT_REASON_RDPMC 15 | ||
116 | #define EXIT_REASON_RDTSC 16 | ||
117 | #define EXIT_REASON_VMCALL 18 | ||
118 | #define EXIT_REASON_VMCLEAR 19 | ||
119 | #define EXIT_REASON_VMLAUNCH 20 | ||
120 | #define EXIT_REASON_VMPTRLD 21 | ||
121 | #define EXIT_REASON_VMPTRST 22 | ||
122 | #define EXIT_REASON_VMREAD 23 | ||
123 | #define EXIT_REASON_VMRESUME 24 | ||
124 | #define EXIT_REASON_VMWRITE 25 | ||
125 | #define EXIT_REASON_VMOFF 26 | ||
126 | #define EXIT_REASON_VMON 27 | ||
127 | #define EXIT_REASON_CR_ACCESS 28 | ||
128 | #define EXIT_REASON_DR_ACCESS 29 | ||
129 | #define EXIT_REASON_IO_INSTRUCTION 30 | ||
130 | #define EXIT_REASON_MSR_READ 31 | ||
131 | #define EXIT_REASON_MSR_WRITE 32 | ||
132 | #define EXIT_REASON_INVALID_STATE 33 | ||
133 | #define EXIT_REASON_MWAIT_INSTRUCTION 36 | ||
134 | #define EXIT_REASON_MONITOR_INSTRUCTION 39 | ||
135 | #define EXIT_REASON_PAUSE_INSTRUCTION 40 | ||
136 | #define EXIT_REASON_MCE_DURING_VMENTRY 41 | ||
137 | #define EXIT_REASON_TPR_BELOW_THRESHOLD 43 | ||
138 | #define EXIT_REASON_APIC_ACCESS 44 | ||
139 | #define EXIT_REASON_EOI_INDUCED 45 | ||
140 | #define EXIT_REASON_EPT_VIOLATION 48 | ||
141 | #define EXIT_REASON_EPT_MISCONFIG 49 | ||
142 | #define EXIT_REASON_INVEPT 50 | ||
143 | #define EXIT_REASON_RDTSCP 51 | ||
144 | #define EXIT_REASON_PREEMPTION_TIMER 52 | ||
145 | #define EXIT_REASON_INVVPID 53 | ||
146 | #define EXIT_REASON_WBINVD 54 | ||
147 | #define EXIT_REASON_XSETBV 55 | ||
148 | #define EXIT_REASON_APIC_WRITE 56 | ||
149 | #define EXIT_REASON_INVPCID 58 | ||
150 | #define EXIT_REASON_PML_FULL 62 | ||
151 | #define EXIT_REASON_XSAVES 63 | ||
152 | #define EXIT_REASON_XRSTORS 64 | ||
153 | #define LAST_EXIT_REASON 64 | ||
154 | |||
155 | enum vmcs_field { | ||
156 | VIRTUAL_PROCESSOR_ID = 0x00000000, | ||
157 | POSTED_INTR_NV = 0x00000002, | ||
158 | GUEST_ES_SELECTOR = 0x00000800, | ||
159 | GUEST_CS_SELECTOR = 0x00000802, | ||
160 | GUEST_SS_SELECTOR = 0x00000804, | ||
161 | GUEST_DS_SELECTOR = 0x00000806, | ||
162 | GUEST_FS_SELECTOR = 0x00000808, | ||
163 | GUEST_GS_SELECTOR = 0x0000080a, | ||
164 | GUEST_LDTR_SELECTOR = 0x0000080c, | ||
165 | GUEST_TR_SELECTOR = 0x0000080e, | ||
166 | GUEST_INTR_STATUS = 0x00000810, | ||
167 | GUEST_PML_INDEX = 0x00000812, | ||
168 | HOST_ES_SELECTOR = 0x00000c00, | ||
169 | HOST_CS_SELECTOR = 0x00000c02, | ||
170 | HOST_SS_SELECTOR = 0x00000c04, | ||
171 | HOST_DS_SELECTOR = 0x00000c06, | ||
172 | HOST_FS_SELECTOR = 0x00000c08, | ||
173 | HOST_GS_SELECTOR = 0x00000c0a, | ||
174 | HOST_TR_SELECTOR = 0x00000c0c, | ||
175 | IO_BITMAP_A = 0x00002000, | ||
176 | IO_BITMAP_A_HIGH = 0x00002001, | ||
177 | IO_BITMAP_B = 0x00002002, | ||
178 | IO_BITMAP_B_HIGH = 0x00002003, | ||
179 | MSR_BITMAP = 0x00002004, | ||
180 | MSR_BITMAP_HIGH = 0x00002005, | ||
181 | VM_EXIT_MSR_STORE_ADDR = 0x00002006, | ||
182 | VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007, | ||
183 | VM_EXIT_MSR_LOAD_ADDR = 0x00002008, | ||
184 | VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009, | ||
185 | VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a, | ||
186 | VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b, | ||
187 | PML_ADDRESS = 0x0000200e, | ||
188 | PML_ADDRESS_HIGH = 0x0000200f, | ||
189 | TSC_OFFSET = 0x00002010, | ||
190 | TSC_OFFSET_HIGH = 0x00002011, | ||
191 | VIRTUAL_APIC_PAGE_ADDR = 0x00002012, | ||
192 | VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013, | ||
193 | APIC_ACCESS_ADDR = 0x00002014, | ||
194 | APIC_ACCESS_ADDR_HIGH = 0x00002015, | ||
195 | POSTED_INTR_DESC_ADDR = 0x00002016, | ||
196 | POSTED_INTR_DESC_ADDR_HIGH = 0x00002017, | ||
197 | EPT_POINTER = 0x0000201a, | ||
198 | EPT_POINTER_HIGH = 0x0000201b, | ||
199 | EOI_EXIT_BITMAP0 = 0x0000201c, | ||
200 | EOI_EXIT_BITMAP0_HIGH = 0x0000201d, | ||
201 | EOI_EXIT_BITMAP1 = 0x0000201e, | ||
202 | EOI_EXIT_BITMAP1_HIGH = 0x0000201f, | ||
203 | EOI_EXIT_BITMAP2 = 0x00002020, | ||
204 | EOI_EXIT_BITMAP2_HIGH = 0x00002021, | ||
205 | EOI_EXIT_BITMAP3 = 0x00002022, | ||
206 | EOI_EXIT_BITMAP3_HIGH = 0x00002023, | ||
207 | VMREAD_BITMAP = 0x00002026, | ||
208 | VMREAD_BITMAP_HIGH = 0x00002027, | ||
209 | VMWRITE_BITMAP = 0x00002028, | ||
210 | VMWRITE_BITMAP_HIGH = 0x00002029, | ||
211 | XSS_EXIT_BITMAP = 0x0000202C, | ||
212 | XSS_EXIT_BITMAP_HIGH = 0x0000202D, | ||
213 | TSC_MULTIPLIER = 0x00002032, | ||
214 | TSC_MULTIPLIER_HIGH = 0x00002033, | ||
215 | GUEST_PHYSICAL_ADDRESS = 0x00002400, | ||
216 | GUEST_PHYSICAL_ADDRESS_HIGH = 0x00002401, | ||
217 | VMCS_LINK_POINTER = 0x00002800, | ||
218 | VMCS_LINK_POINTER_HIGH = 0x00002801, | ||
219 | GUEST_IA32_DEBUGCTL = 0x00002802, | ||
220 | GUEST_IA32_DEBUGCTL_HIGH = 0x00002803, | ||
221 | GUEST_IA32_PAT = 0x00002804, | ||
222 | GUEST_IA32_PAT_HIGH = 0x00002805, | ||
223 | GUEST_IA32_EFER = 0x00002806, | ||
224 | GUEST_IA32_EFER_HIGH = 0x00002807, | ||
225 | GUEST_IA32_PERF_GLOBAL_CTRL = 0x00002808, | ||
226 | GUEST_IA32_PERF_GLOBAL_CTRL_HIGH= 0x00002809, | ||
227 | GUEST_PDPTR0 = 0x0000280a, | ||
228 | GUEST_PDPTR0_HIGH = 0x0000280b, | ||
229 | GUEST_PDPTR1 = 0x0000280c, | ||
230 | GUEST_PDPTR1_HIGH = 0x0000280d, | ||
231 | GUEST_PDPTR2 = 0x0000280e, | ||
232 | GUEST_PDPTR2_HIGH = 0x0000280f, | ||
233 | GUEST_PDPTR3 = 0x00002810, | ||
234 | GUEST_PDPTR3_HIGH = 0x00002811, | ||
235 | GUEST_BNDCFGS = 0x00002812, | ||
236 | GUEST_BNDCFGS_HIGH = 0x00002813, | ||
237 | HOST_IA32_PAT = 0x00002c00, | ||
238 | HOST_IA32_PAT_HIGH = 0x00002c01, | ||
239 | HOST_IA32_EFER = 0x00002c02, | ||
240 | HOST_IA32_EFER_HIGH = 0x00002c03, | ||
241 | HOST_IA32_PERF_GLOBAL_CTRL = 0x00002c04, | ||
242 | HOST_IA32_PERF_GLOBAL_CTRL_HIGH = 0x00002c05, | ||
243 | PIN_BASED_VM_EXEC_CONTROL = 0x00004000, | ||
244 | CPU_BASED_VM_EXEC_CONTROL = 0x00004002, | ||
245 | EXCEPTION_BITMAP = 0x00004004, | ||
246 | PAGE_FAULT_ERROR_CODE_MASK = 0x00004006, | ||
247 | PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008, | ||
248 | CR3_TARGET_COUNT = 0x0000400a, | ||
249 | VM_EXIT_CONTROLS = 0x0000400c, | ||
250 | VM_EXIT_MSR_STORE_COUNT = 0x0000400e, | ||
251 | VM_EXIT_MSR_LOAD_COUNT = 0x00004010, | ||
252 | VM_ENTRY_CONTROLS = 0x00004012, | ||
253 | VM_ENTRY_MSR_LOAD_COUNT = 0x00004014, | ||
254 | VM_ENTRY_INTR_INFO_FIELD = 0x00004016, | ||
255 | VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018, | ||
256 | VM_ENTRY_INSTRUCTION_LEN = 0x0000401a, | ||
257 | TPR_THRESHOLD = 0x0000401c, | ||
258 | SECONDARY_VM_EXEC_CONTROL = 0x0000401e, | ||
259 | PLE_GAP = 0x00004020, | ||
260 | PLE_WINDOW = 0x00004022, | ||
261 | VM_INSTRUCTION_ERROR = 0x00004400, | ||
262 | VM_EXIT_REASON = 0x00004402, | ||
263 | VM_EXIT_INTR_INFO = 0x00004404, | ||
264 | VM_EXIT_INTR_ERROR_CODE = 0x00004406, | ||
265 | IDT_VECTORING_INFO_FIELD = 0x00004408, | ||
266 | IDT_VECTORING_ERROR_CODE = 0x0000440a, | ||
267 | VM_EXIT_INSTRUCTION_LEN = 0x0000440c, | ||
268 | VMX_INSTRUCTION_INFO = 0x0000440e, | ||
269 | GUEST_ES_LIMIT = 0x00004800, | ||
270 | GUEST_CS_LIMIT = 0x00004802, | ||
271 | GUEST_SS_LIMIT = 0x00004804, | ||
272 | GUEST_DS_LIMIT = 0x00004806, | ||
273 | GUEST_FS_LIMIT = 0x00004808, | ||
274 | GUEST_GS_LIMIT = 0x0000480a, | ||
275 | GUEST_LDTR_LIMIT = 0x0000480c, | ||
276 | GUEST_TR_LIMIT = 0x0000480e, | ||
277 | GUEST_GDTR_LIMIT = 0x00004810, | ||
278 | GUEST_IDTR_LIMIT = 0x00004812, | ||
279 | GUEST_ES_AR_BYTES = 0x00004814, | ||
280 | GUEST_CS_AR_BYTES = 0x00004816, | ||
281 | GUEST_SS_AR_BYTES = 0x00004818, | ||
282 | GUEST_DS_AR_BYTES = 0x0000481a, | ||
283 | GUEST_FS_AR_BYTES = 0x0000481c, | ||
284 | GUEST_GS_AR_BYTES = 0x0000481e, | ||
285 | GUEST_LDTR_AR_BYTES = 0x00004820, | ||
286 | GUEST_TR_AR_BYTES = 0x00004822, | ||
287 | GUEST_INTERRUPTIBILITY_INFO = 0x00004824, | ||
288 | GUEST_ACTIVITY_STATE = 0X00004826, | ||
289 | GUEST_SYSENTER_CS = 0x0000482A, | ||
290 | VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, | ||
291 | HOST_IA32_SYSENTER_CS = 0x00004c00, | ||
292 | CR0_GUEST_HOST_MASK = 0x00006000, | ||
293 | CR4_GUEST_HOST_MASK = 0x00006002, | ||
294 | CR0_READ_SHADOW = 0x00006004, | ||
295 | CR4_READ_SHADOW = 0x00006006, | ||
296 | CR3_TARGET_VALUE0 = 0x00006008, | ||
297 | CR3_TARGET_VALUE1 = 0x0000600a, | ||
298 | CR3_TARGET_VALUE2 = 0x0000600c, | ||
299 | CR3_TARGET_VALUE3 = 0x0000600e, | ||
300 | EXIT_QUALIFICATION = 0x00006400, | ||
301 | GUEST_LINEAR_ADDRESS = 0x0000640a, | ||
302 | GUEST_CR0 = 0x00006800, | ||
303 | GUEST_CR3 = 0x00006802, | ||
304 | GUEST_CR4 = 0x00006804, | ||
305 | GUEST_ES_BASE = 0x00006806, | ||
306 | GUEST_CS_BASE = 0x00006808, | ||
307 | GUEST_SS_BASE = 0x0000680a, | ||
308 | GUEST_DS_BASE = 0x0000680c, | ||
309 | GUEST_FS_BASE = 0x0000680e, | ||
310 | GUEST_GS_BASE = 0x00006810, | ||
311 | GUEST_LDTR_BASE = 0x00006812, | ||
312 | GUEST_TR_BASE = 0x00006814, | ||
313 | GUEST_GDTR_BASE = 0x00006816, | ||
314 | GUEST_IDTR_BASE = 0x00006818, | ||
315 | GUEST_DR7 = 0x0000681a, | ||
316 | GUEST_RSP = 0x0000681c, | ||
317 | GUEST_RIP = 0x0000681e, | ||
318 | GUEST_RFLAGS = 0x00006820, | ||
319 | GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822, | ||
320 | GUEST_SYSENTER_ESP = 0x00006824, | ||
321 | GUEST_SYSENTER_EIP = 0x00006826, | ||
322 | HOST_CR0 = 0x00006c00, | ||
323 | HOST_CR3 = 0x00006c02, | ||
324 | HOST_CR4 = 0x00006c04, | ||
325 | HOST_FS_BASE = 0x00006c06, | ||
326 | HOST_GS_BASE = 0x00006c08, | ||
327 | HOST_TR_BASE = 0x00006c0a, | ||
328 | HOST_GDTR_BASE = 0x00006c0c, | ||
329 | HOST_IDTR_BASE = 0x00006c0e, | ||
330 | HOST_IA32_SYSENTER_ESP = 0x00006c10, | ||
331 | HOST_IA32_SYSENTER_EIP = 0x00006c12, | ||
332 | HOST_RSP = 0x00006c14, | ||
333 | HOST_RIP = 0x00006c16, | ||
334 | }; | ||
335 | |||
336 | struct vmx_msr_entry { | ||
337 | uint32_t index; | ||
338 | uint32_t reserved; | ||
339 | uint64_t value; | ||
340 | } __attribute__ ((aligned(16))); | ||
341 | |||
342 | static inline int vmxon(uint64_t phys) | ||
343 | { | ||
344 | uint8_t ret; | ||
345 | |||
346 | __asm__ __volatile__ ("vmxon %[pa]; setna %[ret]" | ||
347 | : [ret]"=rm"(ret) | ||
348 | : [pa]"m"(phys) | ||
349 | : "cc", "memory"); | ||
350 | |||
351 | return ret; | ||
352 | } | ||
353 | |||
354 | static inline void vmxoff(void) | ||
355 | { | ||
356 | __asm__ __volatile__("vmxoff"); | ||
357 | } | ||
358 | |||
359 | static inline int vmclear(uint64_t vmcs_pa) | ||
360 | { | ||
361 | uint8_t ret; | ||
362 | |||
363 | __asm__ __volatile__ ("vmclear %[pa]; setna %[ret]" | ||
364 | : [ret]"=rm"(ret) | ||
365 | : [pa]"m"(vmcs_pa) | ||
366 | : "cc", "memory"); | ||
367 | |||
368 | return ret; | ||
369 | } | ||
370 | |||
371 | static inline int vmptrld(uint64_t vmcs_pa) | ||
372 | { | ||
373 | uint8_t ret; | ||
374 | |||
375 | __asm__ __volatile__ ("vmptrld %[pa]; setna %[ret]" | ||
376 | : [ret]"=rm"(ret) | ||
377 | : [pa]"m"(vmcs_pa) | ||
378 | : "cc", "memory"); | ||
379 | |||
380 | return ret; | ||
381 | } | ||
382 | |||
383 | /* | ||
384 | * No guest state (e.g. GPRs) is established by this vmlaunch. | ||
385 | */ | ||
386 | static inline int vmlaunch(void) | ||
387 | { | ||
388 | int ret; | ||
389 | |||
390 | __asm__ __volatile__("push %%rbp;" | ||
391 | "push %%rcx;" | ||
392 | "push %%rdx;" | ||
393 | "push %%rsi;" | ||
394 | "push %%rdi;" | ||
395 | "push $0;" | ||
396 | "vmwrite %%rsp, %[host_rsp];" | ||
397 | "lea 1f(%%rip), %%rax;" | ||
398 | "vmwrite %%rax, %[host_rip];" | ||
399 | "vmlaunch;" | ||
400 | "incq (%%rsp);" | ||
401 | "1: pop %%rax;" | ||
402 | "pop %%rdi;" | ||
403 | "pop %%rsi;" | ||
404 | "pop %%rdx;" | ||
405 | "pop %%rcx;" | ||
406 | "pop %%rbp;" | ||
407 | : [ret]"=&a"(ret) | ||
408 | : [host_rsp]"r"((uint64_t)HOST_RSP), | ||
409 | [host_rip]"r"((uint64_t)HOST_RIP) | ||
410 | : "memory", "cc", "rbx", "r8", "r9", "r10", | ||
411 | "r11", "r12", "r13", "r14", "r15"); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | /* | ||
416 | * No guest state (e.g. GPRs) is established by this vmresume. | ||
417 | */ | ||
418 | static inline int vmresume(void) | ||
419 | { | ||
420 | int ret; | ||
421 | |||
422 | __asm__ __volatile__("push %%rbp;" | ||
423 | "push %%rcx;" | ||
424 | "push %%rdx;" | ||
425 | "push %%rsi;" | ||
426 | "push %%rdi;" | ||
427 | "push $0;" | ||
428 | "vmwrite %%rsp, %[host_rsp];" | ||
429 | "lea 1f(%%rip), %%rax;" | ||
430 | "vmwrite %%rax, %[host_rip];" | ||
431 | "vmresume;" | ||
432 | "incq (%%rsp);" | ||
433 | "1: pop %%rax;" | ||
434 | "pop %%rdi;" | ||
435 | "pop %%rsi;" | ||
436 | "pop %%rdx;" | ||
437 | "pop %%rcx;" | ||
438 | "pop %%rbp;" | ||
439 | : [ret]"=&a"(ret) | ||
440 | : [host_rsp]"r"((uint64_t)HOST_RSP), | ||
441 | [host_rip]"r"((uint64_t)HOST_RIP) | ||
442 | : "memory", "cc", "rbx", "r8", "r9", "r10", | ||
443 | "r11", "r12", "r13", "r14", "r15"); | ||
444 | return ret; | ||
445 | } | ||
446 | |||
447 | static inline int vmread(uint64_t encoding, uint64_t *value) | ||
448 | { | ||
449 | uint64_t tmp; | ||
450 | uint8_t ret; | ||
451 | |||
452 | __asm__ __volatile__("vmread %[encoding], %[value]; setna %[ret]" | ||
453 | : [value]"=rm"(tmp), [ret]"=rm"(ret) | ||
454 | : [encoding]"r"(encoding) | ||
455 | : "cc", "memory"); | ||
456 | |||
457 | *value = tmp; | ||
458 | return ret; | ||
459 | } | ||
460 | |||
461 | /* | ||
462 | * A wrapper around vmread that ignores errors and returns zero if the | ||
463 | * vmread instruction fails. | ||
464 | */ | ||
465 | static inline uint64_t vmreadz(uint64_t encoding) | ||
466 | { | ||
467 | uint64_t value = 0; | ||
468 | vmread(encoding, &value); | ||
469 | return value; | ||
470 | } | ||
471 | |||
472 | static inline int vmwrite(uint64_t encoding, uint64_t value) | ||
473 | { | ||
474 | uint8_t ret; | ||
475 | |||
476 | __asm__ __volatile__ ("vmwrite %[value], %[encoding]; setna %[ret]" | ||
477 | : [ret]"=rm"(ret) | ||
478 | : [value]"rm"(value), [encoding]"r"(encoding) | ||
479 | : "cc", "memory"); | ||
480 | |||
481 | return ret; | ||
482 | } | ||
483 | |||
484 | static inline uint32_t vmcs_revision(void) | ||
485 | { | ||
486 | return rdmsr(MSR_IA32_VMX_BASIC); | ||
487 | } | ||
488 | |||
489 | void prepare_for_vmx_operation(void); | ||
490 | void prepare_vmcs(void *guest_rip, void *guest_rsp); | ||
491 | struct kvm_vm *vm_create_default_vmx(uint32_t vcpuid, | ||
492 | vmx_guest_code_t guest_code); | ||
493 | |||
494 | #endif /* !SELFTEST_KVM_VMX_H */ | ||
diff --git a/tools/testing/selftests/kvm/include/x86.h b/tools/testing/selftests/kvm/include/x86.h new file mode 100644 index 000000000000..4a5b2c4c1a0f --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86.h | |||
@@ -0,0 +1,1043 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/include/x86.h | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #ifndef SELFTEST_KVM_X86_H | ||
11 | #define SELFTEST_KVM_X86_H | ||
12 | |||
13 | #include <assert.h> | ||
14 | #include <stdint.h> | ||
15 | |||
16 | #define X86_EFLAGS_FIXED (1u << 1) | ||
17 | |||
18 | #define X86_CR4_VME (1ul << 0) | ||
19 | #define X86_CR4_PVI (1ul << 1) | ||
20 | #define X86_CR4_TSD (1ul << 2) | ||
21 | #define X86_CR4_DE (1ul << 3) | ||
22 | #define X86_CR4_PSE (1ul << 4) | ||
23 | #define X86_CR4_PAE (1ul << 5) | ||
24 | #define X86_CR4_MCE (1ul << 6) | ||
25 | #define X86_CR4_PGE (1ul << 7) | ||
26 | #define X86_CR4_PCE (1ul << 8) | ||
27 | #define X86_CR4_OSFXSR (1ul << 9) | ||
28 | #define X86_CR4_OSXMMEXCPT (1ul << 10) | ||
29 | #define X86_CR4_UMIP (1ul << 11) | ||
30 | #define X86_CR4_VMXE (1ul << 13) | ||
31 | #define X86_CR4_SMXE (1ul << 14) | ||
32 | #define X86_CR4_FSGSBASE (1ul << 16) | ||
33 | #define X86_CR4_PCIDE (1ul << 17) | ||
34 | #define X86_CR4_OSXSAVE (1ul << 18) | ||
35 | #define X86_CR4_SMEP (1ul << 20) | ||
36 | #define X86_CR4_SMAP (1ul << 21) | ||
37 | #define X86_CR4_PKE (1ul << 22) | ||
38 | |||
39 | /* The enum values match the intruction encoding of each register */ | ||
40 | enum x86_register { | ||
41 | RAX = 0, | ||
42 | RCX, | ||
43 | RDX, | ||
44 | RBX, | ||
45 | RSP, | ||
46 | RBP, | ||
47 | RSI, | ||
48 | RDI, | ||
49 | R8, | ||
50 | R9, | ||
51 | R10, | ||
52 | R11, | ||
53 | R12, | ||
54 | R13, | ||
55 | R14, | ||
56 | R15, | ||
57 | }; | ||
58 | |||
59 | struct desc64 { | ||
60 | uint16_t limit0; | ||
61 | uint16_t base0; | ||
62 | unsigned base1:8, type:5, dpl:2, p:1; | ||
63 | unsigned limit1:4, zero0:3, g:1, base2:8; | ||
64 | uint32_t base3; | ||
65 | uint32_t zero1; | ||
66 | } __attribute__((packed)); | ||
67 | |||
68 | struct desc_ptr { | ||
69 | uint16_t size; | ||
70 | uint64_t address; | ||
71 | } __attribute__((packed)); | ||
72 | |||
73 | static inline uint64_t get_desc64_base(const struct desc64 *desc) | ||
74 | { | ||
75 | return ((uint64_t)desc->base3 << 32) | | ||
76 | (desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24)); | ||
77 | } | ||
78 | |||
79 | static inline uint64_t rdtsc(void) | ||
80 | { | ||
81 | uint32_t eax, edx; | ||
82 | |||
83 | /* | ||
84 | * The lfence is to wait (on Intel CPUs) until all previous | ||
85 | * instructions have been executed. | ||
86 | */ | ||
87 | __asm__ __volatile__("lfence; rdtsc" : "=a"(eax), "=d"(edx)); | ||
88 | return ((uint64_t)edx) << 32 | eax; | ||
89 | } | ||
90 | |||
91 | static inline uint64_t rdtscp(uint32_t *aux) | ||
92 | { | ||
93 | uint32_t eax, edx; | ||
94 | |||
95 | __asm__ __volatile__("rdtscp" : "=a"(eax), "=d"(edx), "=c"(*aux)); | ||
96 | return ((uint64_t)edx) << 32 | eax; | ||
97 | } | ||
98 | |||
99 | static inline uint64_t rdmsr(uint32_t msr) | ||
100 | { | ||
101 | uint32_t a, d; | ||
102 | |||
103 | __asm__ __volatile__("rdmsr" : "=a"(a), "=d"(d) : "c"(msr) : "memory"); | ||
104 | |||
105 | return a | ((uint64_t) d << 32); | ||
106 | } | ||
107 | |||
108 | static inline void wrmsr(uint32_t msr, uint64_t value) | ||
109 | { | ||
110 | uint32_t a = value; | ||
111 | uint32_t d = value >> 32; | ||
112 | |||
113 | __asm__ __volatile__("wrmsr" :: "a"(a), "d"(d), "c"(msr) : "memory"); | ||
114 | } | ||
115 | |||
116 | |||
117 | static inline uint16_t inw(uint16_t port) | ||
118 | { | ||
119 | uint16_t tmp; | ||
120 | |||
121 | __asm__ __volatile__("in %%dx, %%ax" | ||
122 | : /* output */ "=a" (tmp) | ||
123 | : /* input */ "d" (port)); | ||
124 | |||
125 | return tmp; | ||
126 | } | ||
127 | |||
128 | static inline uint16_t get_es(void) | ||
129 | { | ||
130 | uint16_t es; | ||
131 | |||
132 | __asm__ __volatile__("mov %%es, %[es]" | ||
133 | : /* output */ [es]"=rm"(es)); | ||
134 | return es; | ||
135 | } | ||
136 | |||
137 | static inline uint16_t get_cs(void) | ||
138 | { | ||
139 | uint16_t cs; | ||
140 | |||
141 | __asm__ __volatile__("mov %%cs, %[cs]" | ||
142 | : /* output */ [cs]"=rm"(cs)); | ||
143 | return cs; | ||
144 | } | ||
145 | |||
146 | static inline uint16_t get_ss(void) | ||
147 | { | ||
148 | uint16_t ss; | ||
149 | |||
150 | __asm__ __volatile__("mov %%ss, %[ss]" | ||
151 | : /* output */ [ss]"=rm"(ss)); | ||
152 | return ss; | ||
153 | } | ||
154 | |||
155 | static inline uint16_t get_ds(void) | ||
156 | { | ||
157 | uint16_t ds; | ||
158 | |||
159 | __asm__ __volatile__("mov %%ds, %[ds]" | ||
160 | : /* output */ [ds]"=rm"(ds)); | ||
161 | return ds; | ||
162 | } | ||
163 | |||
164 | static inline uint16_t get_fs(void) | ||
165 | { | ||
166 | uint16_t fs; | ||
167 | |||
168 | __asm__ __volatile__("mov %%fs, %[fs]" | ||
169 | : /* output */ [fs]"=rm"(fs)); | ||
170 | return fs; | ||
171 | } | ||
172 | |||
173 | static inline uint16_t get_gs(void) | ||
174 | { | ||
175 | uint16_t gs; | ||
176 | |||
177 | __asm__ __volatile__("mov %%gs, %[gs]" | ||
178 | : /* output */ [gs]"=rm"(gs)); | ||
179 | return gs; | ||
180 | } | ||
181 | |||
182 | static inline uint16_t get_tr(void) | ||
183 | { | ||
184 | uint16_t tr; | ||
185 | |||
186 | __asm__ __volatile__("str %[tr]" | ||
187 | : /* output */ [tr]"=rm"(tr)); | ||
188 | return tr; | ||
189 | } | ||
190 | |||
191 | static inline uint64_t get_cr0(void) | ||
192 | { | ||
193 | uint64_t cr0; | ||
194 | |||
195 | __asm__ __volatile__("mov %%cr0, %[cr0]" | ||
196 | : /* output */ [cr0]"=r"(cr0)); | ||
197 | return cr0; | ||
198 | } | ||
199 | |||
200 | static inline uint64_t get_cr3(void) | ||
201 | { | ||
202 | uint64_t cr3; | ||
203 | |||
204 | __asm__ __volatile__("mov %%cr3, %[cr3]" | ||
205 | : /* output */ [cr3]"=r"(cr3)); | ||
206 | return cr3; | ||
207 | } | ||
208 | |||
209 | static inline uint64_t get_cr4(void) | ||
210 | { | ||
211 | uint64_t cr4; | ||
212 | |||
213 | __asm__ __volatile__("mov %%cr4, %[cr4]" | ||
214 | : /* output */ [cr4]"=r"(cr4)); | ||
215 | return cr4; | ||
216 | } | ||
217 | |||
218 | static inline void set_cr4(uint64_t val) | ||
219 | { | ||
220 | __asm__ __volatile__("mov %0, %%cr4" : : "r" (val) : "memory"); | ||
221 | } | ||
222 | |||
223 | static inline uint64_t get_gdt_base(void) | ||
224 | { | ||
225 | struct desc_ptr gdt; | ||
226 | __asm__ __volatile__("sgdt %[gdt]" | ||
227 | : /* output */ [gdt]"=m"(gdt)); | ||
228 | return gdt.address; | ||
229 | } | ||
230 | |||
231 | static inline uint64_t get_idt_base(void) | ||
232 | { | ||
233 | struct desc_ptr idt; | ||
234 | __asm__ __volatile__("sidt %[idt]" | ||
235 | : /* output */ [idt]"=m"(idt)); | ||
236 | return idt.address; | ||
237 | } | ||
238 | |||
239 | #define SET_XMM(__var, __xmm) \ | ||
240 | asm volatile("movq %0, %%"#__xmm : : "r"(__var) : #__xmm) | ||
241 | |||
242 | static inline void set_xmm(int n, unsigned long val) | ||
243 | { | ||
244 | switch (n) { | ||
245 | case 0: | ||
246 | SET_XMM(val, xmm0); | ||
247 | break; | ||
248 | case 1: | ||
249 | SET_XMM(val, xmm1); | ||
250 | break; | ||
251 | case 2: | ||
252 | SET_XMM(val, xmm2); | ||
253 | break; | ||
254 | case 3: | ||
255 | SET_XMM(val, xmm3); | ||
256 | break; | ||
257 | case 4: | ||
258 | SET_XMM(val, xmm4); | ||
259 | break; | ||
260 | case 5: | ||
261 | SET_XMM(val, xmm5); | ||
262 | break; | ||
263 | case 6: | ||
264 | SET_XMM(val, xmm6); | ||
265 | break; | ||
266 | case 7: | ||
267 | SET_XMM(val, xmm7); | ||
268 | break; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | typedef unsigned long v1di __attribute__ ((vector_size (8))); | ||
273 | static inline unsigned long get_xmm(int n) | ||
274 | { | ||
275 | assert(n >= 0 && n <= 7); | ||
276 | |||
277 | register v1di xmm0 __asm__("%xmm0"); | ||
278 | register v1di xmm1 __asm__("%xmm1"); | ||
279 | register v1di xmm2 __asm__("%xmm2"); | ||
280 | register v1di xmm3 __asm__("%xmm3"); | ||
281 | register v1di xmm4 __asm__("%xmm4"); | ||
282 | register v1di xmm5 __asm__("%xmm5"); | ||
283 | register v1di xmm6 __asm__("%xmm6"); | ||
284 | register v1di xmm7 __asm__("%xmm7"); | ||
285 | switch (n) { | ||
286 | case 0: | ||
287 | return (unsigned long)xmm0; | ||
288 | case 1: | ||
289 | return (unsigned long)xmm1; | ||
290 | case 2: | ||
291 | return (unsigned long)xmm2; | ||
292 | case 3: | ||
293 | return (unsigned long)xmm3; | ||
294 | case 4: | ||
295 | return (unsigned long)xmm4; | ||
296 | case 5: | ||
297 | return (unsigned long)xmm5; | ||
298 | case 6: | ||
299 | return (unsigned long)xmm6; | ||
300 | case 7: | ||
301 | return (unsigned long)xmm7; | ||
302 | } | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * Basic CPU control in CR0 | ||
308 | */ | ||
309 | #define X86_CR0_PE (1UL<<0) /* Protection Enable */ | ||
310 | #define X86_CR0_MP (1UL<<1) /* Monitor Coprocessor */ | ||
311 | #define X86_CR0_EM (1UL<<2) /* Emulation */ | ||
312 | #define X86_CR0_TS (1UL<<3) /* Task Switched */ | ||
313 | #define X86_CR0_ET (1UL<<4) /* Extension Type */ | ||
314 | #define X86_CR0_NE (1UL<<5) /* Numeric Error */ | ||
315 | #define X86_CR0_WP (1UL<<16) /* Write Protect */ | ||
316 | #define X86_CR0_AM (1UL<<18) /* Alignment Mask */ | ||
317 | #define X86_CR0_NW (1UL<<29) /* Not Write-through */ | ||
318 | #define X86_CR0_CD (1UL<<30) /* Cache Disable */ | ||
319 | #define X86_CR0_PG (1UL<<31) /* Paging */ | ||
320 | |||
321 | /* | ||
322 | * CPU model specific register (MSR) numbers. | ||
323 | */ | ||
324 | |||
325 | /* x86-64 specific MSRs */ | ||
326 | #define MSR_EFER 0xc0000080 /* extended feature register */ | ||
327 | #define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */ | ||
328 | #define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */ | ||
329 | #define MSR_CSTAR 0xc0000083 /* compat mode SYSCALL target */ | ||
330 | #define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */ | ||
331 | #define MSR_FS_BASE 0xc0000100 /* 64bit FS base */ | ||
332 | #define MSR_GS_BASE 0xc0000101 /* 64bit GS base */ | ||
333 | #define MSR_KERNEL_GS_BASE 0xc0000102 /* SwapGS GS shadow */ | ||
334 | #define MSR_TSC_AUX 0xc0000103 /* Auxiliary TSC */ | ||
335 | |||
336 | /* EFER bits: */ | ||
337 | #define EFER_SCE (1<<0) /* SYSCALL/SYSRET */ | ||
338 | #define EFER_LME (1<<8) /* Long mode enable */ | ||
339 | #define EFER_LMA (1<<10) /* Long mode active (read-only) */ | ||
340 | #define EFER_NX (1<<11) /* No execute enable */ | ||
341 | #define EFER_SVME (1<<12) /* Enable virtualization */ | ||
342 | #define EFER_LMSLE (1<<13) /* Long Mode Segment Limit Enable */ | ||
343 | #define EFER_FFXSR (1<<14) /* Enable Fast FXSAVE/FXRSTOR */ | ||
344 | |||
345 | /* Intel MSRs. Some also available on other CPUs */ | ||
346 | |||
347 | #define MSR_PPIN_CTL 0x0000004e | ||
348 | #define MSR_PPIN 0x0000004f | ||
349 | |||
350 | #define MSR_IA32_PERFCTR0 0x000000c1 | ||
351 | #define MSR_IA32_PERFCTR1 0x000000c2 | ||
352 | #define MSR_FSB_FREQ 0x000000cd | ||
353 | #define MSR_PLATFORM_INFO 0x000000ce | ||
354 | #define MSR_PLATFORM_INFO_CPUID_FAULT_BIT 31 | ||
355 | #define MSR_PLATFORM_INFO_CPUID_FAULT BIT_ULL(MSR_PLATFORM_INFO_CPUID_FAULT_BIT) | ||
356 | |||
357 | #define MSR_PKG_CST_CONFIG_CONTROL 0x000000e2 | ||
358 | #define NHM_C3_AUTO_DEMOTE (1UL << 25) | ||
359 | #define NHM_C1_AUTO_DEMOTE (1UL << 26) | ||
360 | #define ATM_LNC_C6_AUTO_DEMOTE (1UL << 25) | ||
361 | #define SNB_C1_AUTO_UNDEMOTE (1UL << 27) | ||
362 | #define SNB_C3_AUTO_UNDEMOTE (1UL << 28) | ||
363 | |||
364 | #define MSR_MTRRcap 0x000000fe | ||
365 | #define MSR_IA32_BBL_CR_CTL 0x00000119 | ||
366 | #define MSR_IA32_BBL_CR_CTL3 0x0000011e | ||
367 | |||
368 | #define MSR_IA32_SYSENTER_CS 0x00000174 | ||
369 | #define MSR_IA32_SYSENTER_ESP 0x00000175 | ||
370 | #define MSR_IA32_SYSENTER_EIP 0x00000176 | ||
371 | |||
372 | #define MSR_IA32_MCG_CAP 0x00000179 | ||
373 | #define MSR_IA32_MCG_STATUS 0x0000017a | ||
374 | #define MSR_IA32_MCG_CTL 0x0000017b | ||
375 | #define MSR_IA32_MCG_EXT_CTL 0x000004d0 | ||
376 | |||
377 | #define MSR_OFFCORE_RSP_0 0x000001a6 | ||
378 | #define MSR_OFFCORE_RSP_1 0x000001a7 | ||
379 | #define MSR_TURBO_RATIO_LIMIT 0x000001ad | ||
380 | #define MSR_TURBO_RATIO_LIMIT1 0x000001ae | ||
381 | #define MSR_TURBO_RATIO_LIMIT2 0x000001af | ||
382 | |||
383 | #define MSR_LBR_SELECT 0x000001c8 | ||
384 | #define MSR_LBR_TOS 0x000001c9 | ||
385 | #define MSR_LBR_NHM_FROM 0x00000680 | ||
386 | #define MSR_LBR_NHM_TO 0x000006c0 | ||
387 | #define MSR_LBR_CORE_FROM 0x00000040 | ||
388 | #define MSR_LBR_CORE_TO 0x00000060 | ||
389 | |||
390 | #define MSR_LBR_INFO_0 0x00000dc0 /* ... 0xddf for _31 */ | ||
391 | #define LBR_INFO_MISPRED BIT_ULL(63) | ||
392 | #define LBR_INFO_IN_TX BIT_ULL(62) | ||
393 | #define LBR_INFO_ABORT BIT_ULL(61) | ||
394 | #define LBR_INFO_CYCLES 0xffff | ||
395 | |||
396 | #define MSR_IA32_PEBS_ENABLE 0x000003f1 | ||
397 | #define MSR_IA32_DS_AREA 0x00000600 | ||
398 | #define MSR_IA32_PERF_CAPABILITIES 0x00000345 | ||
399 | #define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6 | ||
400 | |||
401 | #define MSR_IA32_RTIT_CTL 0x00000570 | ||
402 | #define MSR_IA32_RTIT_STATUS 0x00000571 | ||
403 | #define MSR_IA32_RTIT_ADDR0_A 0x00000580 | ||
404 | #define MSR_IA32_RTIT_ADDR0_B 0x00000581 | ||
405 | #define MSR_IA32_RTIT_ADDR1_A 0x00000582 | ||
406 | #define MSR_IA32_RTIT_ADDR1_B 0x00000583 | ||
407 | #define MSR_IA32_RTIT_ADDR2_A 0x00000584 | ||
408 | #define MSR_IA32_RTIT_ADDR2_B 0x00000585 | ||
409 | #define MSR_IA32_RTIT_ADDR3_A 0x00000586 | ||
410 | #define MSR_IA32_RTIT_ADDR3_B 0x00000587 | ||
411 | #define MSR_IA32_RTIT_CR3_MATCH 0x00000572 | ||
412 | #define MSR_IA32_RTIT_OUTPUT_BASE 0x00000560 | ||
413 | #define MSR_IA32_RTIT_OUTPUT_MASK 0x00000561 | ||
414 | |||
415 | #define MSR_MTRRfix64K_00000 0x00000250 | ||
416 | #define MSR_MTRRfix16K_80000 0x00000258 | ||
417 | #define MSR_MTRRfix16K_A0000 0x00000259 | ||
418 | #define MSR_MTRRfix4K_C0000 0x00000268 | ||
419 | #define MSR_MTRRfix4K_C8000 0x00000269 | ||
420 | #define MSR_MTRRfix4K_D0000 0x0000026a | ||
421 | #define MSR_MTRRfix4K_D8000 0x0000026b | ||
422 | #define MSR_MTRRfix4K_E0000 0x0000026c | ||
423 | #define MSR_MTRRfix4K_E8000 0x0000026d | ||
424 | #define MSR_MTRRfix4K_F0000 0x0000026e | ||
425 | #define MSR_MTRRfix4K_F8000 0x0000026f | ||
426 | #define MSR_MTRRdefType 0x000002ff | ||
427 | |||
428 | #define MSR_IA32_CR_PAT 0x00000277 | ||
429 | |||
430 | #define MSR_IA32_DEBUGCTLMSR 0x000001d9 | ||
431 | #define MSR_IA32_LASTBRANCHFROMIP 0x000001db | ||
432 | #define MSR_IA32_LASTBRANCHTOIP 0x000001dc | ||
433 | #define MSR_IA32_LASTINTFROMIP 0x000001dd | ||
434 | #define MSR_IA32_LASTINTTOIP 0x000001de | ||
435 | |||
436 | /* DEBUGCTLMSR bits (others vary by model): */ | ||
437 | #define DEBUGCTLMSR_LBR (1UL << 0) /* last branch recording */ | ||
438 | #define DEBUGCTLMSR_BTF_SHIFT 1 | ||
439 | #define DEBUGCTLMSR_BTF (1UL << 1) /* single-step on branches */ | ||
440 | #define DEBUGCTLMSR_TR (1UL << 6) | ||
441 | #define DEBUGCTLMSR_BTS (1UL << 7) | ||
442 | #define DEBUGCTLMSR_BTINT (1UL << 8) | ||
443 | #define DEBUGCTLMSR_BTS_OFF_OS (1UL << 9) | ||
444 | #define DEBUGCTLMSR_BTS_OFF_USR (1UL << 10) | ||
445 | #define DEBUGCTLMSR_FREEZE_LBRS_ON_PMI (1UL << 11) | ||
446 | #define DEBUGCTLMSR_FREEZE_IN_SMM_BIT 14 | ||
447 | #define DEBUGCTLMSR_FREEZE_IN_SMM (1UL << DEBUGCTLMSR_FREEZE_IN_SMM_BIT) | ||
448 | |||
449 | #define MSR_PEBS_FRONTEND 0x000003f7 | ||
450 | |||
451 | #define MSR_IA32_POWER_CTL 0x000001fc | ||
452 | |||
453 | #define MSR_IA32_MC0_CTL 0x00000400 | ||
454 | #define MSR_IA32_MC0_STATUS 0x00000401 | ||
455 | #define MSR_IA32_MC0_ADDR 0x00000402 | ||
456 | #define MSR_IA32_MC0_MISC 0x00000403 | ||
457 | |||
458 | /* C-state Residency Counters */ | ||
459 | #define MSR_PKG_C3_RESIDENCY 0x000003f8 | ||
460 | #define MSR_PKG_C6_RESIDENCY 0x000003f9 | ||
461 | #define MSR_ATOM_PKG_C6_RESIDENCY 0x000003fa | ||
462 | #define MSR_PKG_C7_RESIDENCY 0x000003fa | ||
463 | #define MSR_CORE_C3_RESIDENCY 0x000003fc | ||
464 | #define MSR_CORE_C6_RESIDENCY 0x000003fd | ||
465 | #define MSR_CORE_C7_RESIDENCY 0x000003fe | ||
466 | #define MSR_KNL_CORE_C6_RESIDENCY 0x000003ff | ||
467 | #define MSR_PKG_C2_RESIDENCY 0x0000060d | ||
468 | #define MSR_PKG_C8_RESIDENCY 0x00000630 | ||
469 | #define MSR_PKG_C9_RESIDENCY 0x00000631 | ||
470 | #define MSR_PKG_C10_RESIDENCY 0x00000632 | ||
471 | |||
472 | /* Interrupt Response Limit */ | ||
473 | #define MSR_PKGC3_IRTL 0x0000060a | ||
474 | #define MSR_PKGC6_IRTL 0x0000060b | ||
475 | #define MSR_PKGC7_IRTL 0x0000060c | ||
476 | #define MSR_PKGC8_IRTL 0x00000633 | ||
477 | #define MSR_PKGC9_IRTL 0x00000634 | ||
478 | #define MSR_PKGC10_IRTL 0x00000635 | ||
479 | |||
480 | /* Run Time Average Power Limiting (RAPL) Interface */ | ||
481 | |||
482 | #define MSR_RAPL_POWER_UNIT 0x00000606 | ||
483 | |||
484 | #define MSR_PKG_POWER_LIMIT 0x00000610 | ||
485 | #define MSR_PKG_ENERGY_STATUS 0x00000611 | ||
486 | #define MSR_PKG_PERF_STATUS 0x00000613 | ||
487 | #define MSR_PKG_POWER_INFO 0x00000614 | ||
488 | |||
489 | #define MSR_DRAM_POWER_LIMIT 0x00000618 | ||
490 | #define MSR_DRAM_ENERGY_STATUS 0x00000619 | ||
491 | #define MSR_DRAM_PERF_STATUS 0x0000061b | ||
492 | #define MSR_DRAM_POWER_INFO 0x0000061c | ||
493 | |||
494 | #define MSR_PP0_POWER_LIMIT 0x00000638 | ||
495 | #define MSR_PP0_ENERGY_STATUS 0x00000639 | ||
496 | #define MSR_PP0_POLICY 0x0000063a | ||
497 | #define MSR_PP0_PERF_STATUS 0x0000063b | ||
498 | |||
499 | #define MSR_PP1_POWER_LIMIT 0x00000640 | ||
500 | #define MSR_PP1_ENERGY_STATUS 0x00000641 | ||
501 | #define MSR_PP1_POLICY 0x00000642 | ||
502 | |||
503 | /* Config TDP MSRs */ | ||
504 | #define MSR_CONFIG_TDP_NOMINAL 0x00000648 | ||
505 | #define MSR_CONFIG_TDP_LEVEL_1 0x00000649 | ||
506 | #define MSR_CONFIG_TDP_LEVEL_2 0x0000064A | ||
507 | #define MSR_CONFIG_TDP_CONTROL 0x0000064B | ||
508 | #define MSR_TURBO_ACTIVATION_RATIO 0x0000064C | ||
509 | |||
510 | #define MSR_PLATFORM_ENERGY_STATUS 0x0000064D | ||
511 | |||
512 | #define MSR_PKG_WEIGHTED_CORE_C0_RES 0x00000658 | ||
513 | #define MSR_PKG_ANY_CORE_C0_RES 0x00000659 | ||
514 | #define MSR_PKG_ANY_GFXE_C0_RES 0x0000065A | ||
515 | #define MSR_PKG_BOTH_CORE_GFXE_C0_RES 0x0000065B | ||
516 | |||
517 | #define MSR_CORE_C1_RES 0x00000660 | ||
518 | #define MSR_MODULE_C6_RES_MS 0x00000664 | ||
519 | |||
520 | #define MSR_CC6_DEMOTION_POLICY_CONFIG 0x00000668 | ||
521 | #define MSR_MC6_DEMOTION_POLICY_CONFIG 0x00000669 | ||
522 | |||
523 | #define MSR_ATOM_CORE_RATIOS 0x0000066a | ||
524 | #define MSR_ATOM_CORE_VIDS 0x0000066b | ||
525 | #define MSR_ATOM_CORE_TURBO_RATIOS 0x0000066c | ||
526 | #define MSR_ATOM_CORE_TURBO_VIDS 0x0000066d | ||
527 | |||
528 | |||
529 | #define MSR_CORE_PERF_LIMIT_REASONS 0x00000690 | ||
530 | #define MSR_GFX_PERF_LIMIT_REASONS 0x000006B0 | ||
531 | #define MSR_RING_PERF_LIMIT_REASONS 0x000006B1 | ||
532 | |||
533 | /* Hardware P state interface */ | ||
534 | #define MSR_PPERF 0x0000064e | ||
535 | #define MSR_PERF_LIMIT_REASONS 0x0000064f | ||
536 | #define MSR_PM_ENABLE 0x00000770 | ||
537 | #define MSR_HWP_CAPABILITIES 0x00000771 | ||
538 | #define MSR_HWP_REQUEST_PKG 0x00000772 | ||
539 | #define MSR_HWP_INTERRUPT 0x00000773 | ||
540 | #define MSR_HWP_REQUEST 0x00000774 | ||
541 | #define MSR_HWP_STATUS 0x00000777 | ||
542 | |||
543 | /* CPUID.6.EAX */ | ||
544 | #define HWP_BASE_BIT (1<<7) | ||
545 | #define HWP_NOTIFICATIONS_BIT (1<<8) | ||
546 | #define HWP_ACTIVITY_WINDOW_BIT (1<<9) | ||
547 | #define HWP_ENERGY_PERF_PREFERENCE_BIT (1<<10) | ||
548 | #define HWP_PACKAGE_LEVEL_REQUEST_BIT (1<<11) | ||
549 | |||
550 | /* IA32_HWP_CAPABILITIES */ | ||
551 | #define HWP_HIGHEST_PERF(x) (((x) >> 0) & 0xff) | ||
552 | #define HWP_GUARANTEED_PERF(x) (((x) >> 8) & 0xff) | ||
553 | #define HWP_MOSTEFFICIENT_PERF(x) (((x) >> 16) & 0xff) | ||
554 | #define HWP_LOWEST_PERF(x) (((x) >> 24) & 0xff) | ||
555 | |||
556 | /* IA32_HWP_REQUEST */ | ||
557 | #define HWP_MIN_PERF(x) (x & 0xff) | ||
558 | #define HWP_MAX_PERF(x) ((x & 0xff) << 8) | ||
559 | #define HWP_DESIRED_PERF(x) ((x & 0xff) << 16) | ||
560 | #define HWP_ENERGY_PERF_PREFERENCE(x) (((unsigned long long) x & 0xff) << 24) | ||
561 | #define HWP_EPP_PERFORMANCE 0x00 | ||
562 | #define HWP_EPP_BALANCE_PERFORMANCE 0x80 | ||
563 | #define HWP_EPP_BALANCE_POWERSAVE 0xC0 | ||
564 | #define HWP_EPP_POWERSAVE 0xFF | ||
565 | #define HWP_ACTIVITY_WINDOW(x) ((unsigned long long)(x & 0xff3) << 32) | ||
566 | #define HWP_PACKAGE_CONTROL(x) ((unsigned long long)(x & 0x1) << 42) | ||
567 | |||
568 | /* IA32_HWP_STATUS */ | ||
569 | #define HWP_GUARANTEED_CHANGE(x) (x & 0x1) | ||
570 | #define HWP_EXCURSION_TO_MINIMUM(x) (x & 0x4) | ||
571 | |||
572 | /* IA32_HWP_INTERRUPT */ | ||
573 | #define HWP_CHANGE_TO_GUARANTEED_INT(x) (x & 0x1) | ||
574 | #define HWP_EXCURSION_TO_MINIMUM_INT(x) (x & 0x2) | ||
575 | |||
576 | #define MSR_AMD64_MC0_MASK 0xc0010044 | ||
577 | |||
578 | #define MSR_IA32_MCx_CTL(x) (MSR_IA32_MC0_CTL + 4*(x)) | ||
579 | #define MSR_IA32_MCx_STATUS(x) (MSR_IA32_MC0_STATUS + 4*(x)) | ||
580 | #define MSR_IA32_MCx_ADDR(x) (MSR_IA32_MC0_ADDR + 4*(x)) | ||
581 | #define MSR_IA32_MCx_MISC(x) (MSR_IA32_MC0_MISC + 4*(x)) | ||
582 | |||
583 | #define MSR_AMD64_MCx_MASK(x) (MSR_AMD64_MC0_MASK + (x)) | ||
584 | |||
585 | /* These are consecutive and not in the normal 4er MCE bank block */ | ||
586 | #define MSR_IA32_MC0_CTL2 0x00000280 | ||
587 | #define MSR_IA32_MCx_CTL2(x) (MSR_IA32_MC0_CTL2 + (x)) | ||
588 | |||
589 | #define MSR_P6_PERFCTR0 0x000000c1 | ||
590 | #define MSR_P6_PERFCTR1 0x000000c2 | ||
591 | #define MSR_P6_EVNTSEL0 0x00000186 | ||
592 | #define MSR_P6_EVNTSEL1 0x00000187 | ||
593 | |||
594 | #define MSR_KNC_PERFCTR0 0x00000020 | ||
595 | #define MSR_KNC_PERFCTR1 0x00000021 | ||
596 | #define MSR_KNC_EVNTSEL0 0x00000028 | ||
597 | #define MSR_KNC_EVNTSEL1 0x00000029 | ||
598 | |||
599 | /* Alternative perfctr range with full access. */ | ||
600 | #define MSR_IA32_PMC0 0x000004c1 | ||
601 | |||
602 | /* AMD64 MSRs. Not complete. See the architecture manual for a more | ||
603 | complete list. */ | ||
604 | |||
605 | #define MSR_AMD64_PATCH_LEVEL 0x0000008b | ||
606 | #define MSR_AMD64_TSC_RATIO 0xc0000104 | ||
607 | #define MSR_AMD64_NB_CFG 0xc001001f | ||
608 | #define MSR_AMD64_PATCH_LOADER 0xc0010020 | ||
609 | #define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 | ||
610 | #define MSR_AMD64_OSVW_STATUS 0xc0010141 | ||
611 | #define MSR_AMD64_LS_CFG 0xc0011020 | ||
612 | #define MSR_AMD64_DC_CFG 0xc0011022 | ||
613 | #define MSR_AMD64_BU_CFG2 0xc001102a | ||
614 | #define MSR_AMD64_IBSFETCHCTL 0xc0011030 | ||
615 | #define MSR_AMD64_IBSFETCHLINAD 0xc0011031 | ||
616 | #define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 | ||
617 | #define MSR_AMD64_IBSFETCH_REG_COUNT 3 | ||
618 | #define MSR_AMD64_IBSFETCH_REG_MASK ((1UL<<MSR_AMD64_IBSFETCH_REG_COUNT)-1) | ||
619 | #define MSR_AMD64_IBSOPCTL 0xc0011033 | ||
620 | #define MSR_AMD64_IBSOPRIP 0xc0011034 | ||
621 | #define MSR_AMD64_IBSOPDATA 0xc0011035 | ||
622 | #define MSR_AMD64_IBSOPDATA2 0xc0011036 | ||
623 | #define MSR_AMD64_IBSOPDATA3 0xc0011037 | ||
624 | #define MSR_AMD64_IBSDCLINAD 0xc0011038 | ||
625 | #define MSR_AMD64_IBSDCPHYSAD 0xc0011039 | ||
626 | #define MSR_AMD64_IBSOP_REG_COUNT 7 | ||
627 | #define MSR_AMD64_IBSOP_REG_MASK ((1UL<<MSR_AMD64_IBSOP_REG_COUNT)-1) | ||
628 | #define MSR_AMD64_IBSCTL 0xc001103a | ||
629 | #define MSR_AMD64_IBSBRTARGET 0xc001103b | ||
630 | #define MSR_AMD64_IBSOPDATA4 0xc001103d | ||
631 | #define MSR_AMD64_IBS_REG_COUNT_MAX 8 /* includes MSR_AMD64_IBSBRTARGET */ | ||
632 | #define MSR_AMD64_SEV 0xc0010131 | ||
633 | #define MSR_AMD64_SEV_ENABLED_BIT 0 | ||
634 | #define MSR_AMD64_SEV_ENABLED BIT_ULL(MSR_AMD64_SEV_ENABLED_BIT) | ||
635 | |||
636 | /* Fam 17h MSRs */ | ||
637 | #define MSR_F17H_IRPERF 0xc00000e9 | ||
638 | |||
639 | /* Fam 16h MSRs */ | ||
640 | #define MSR_F16H_L2I_PERF_CTL 0xc0010230 | ||
641 | #define MSR_F16H_L2I_PERF_CTR 0xc0010231 | ||
642 | #define MSR_F16H_DR1_ADDR_MASK 0xc0011019 | ||
643 | #define MSR_F16H_DR2_ADDR_MASK 0xc001101a | ||
644 | #define MSR_F16H_DR3_ADDR_MASK 0xc001101b | ||
645 | #define MSR_F16H_DR0_ADDR_MASK 0xc0011027 | ||
646 | |||
647 | /* Fam 15h MSRs */ | ||
648 | #define MSR_F15H_PERF_CTL 0xc0010200 | ||
649 | #define MSR_F15H_PERF_CTR 0xc0010201 | ||
650 | #define MSR_F15H_NB_PERF_CTL 0xc0010240 | ||
651 | #define MSR_F15H_NB_PERF_CTR 0xc0010241 | ||
652 | #define MSR_F15H_PTSC 0xc0010280 | ||
653 | #define MSR_F15H_IC_CFG 0xc0011021 | ||
654 | |||
655 | /* Fam 10h MSRs */ | ||
656 | #define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058 | ||
657 | #define FAM10H_MMIO_CONF_ENABLE (1<<0) | ||
658 | #define FAM10H_MMIO_CONF_BUSRANGE_MASK 0xf | ||
659 | #define FAM10H_MMIO_CONF_BUSRANGE_SHIFT 2 | ||
660 | #define FAM10H_MMIO_CONF_BASE_MASK 0xfffffffULL | ||
661 | #define FAM10H_MMIO_CONF_BASE_SHIFT 20 | ||
662 | #define MSR_FAM10H_NODE_ID 0xc001100c | ||
663 | #define MSR_F10H_DECFG 0xc0011029 | ||
664 | #define MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT 1 | ||
665 | #define MSR_F10H_DECFG_LFENCE_SERIALIZE BIT_ULL(MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT) | ||
666 | |||
667 | /* K8 MSRs */ | ||
668 | #define MSR_K8_TOP_MEM1 0xc001001a | ||
669 | #define MSR_K8_TOP_MEM2 0xc001001d | ||
670 | #define MSR_K8_SYSCFG 0xc0010010 | ||
671 | #define MSR_K8_SYSCFG_MEM_ENCRYPT_BIT 23 | ||
672 | #define MSR_K8_SYSCFG_MEM_ENCRYPT BIT_ULL(MSR_K8_SYSCFG_MEM_ENCRYPT_BIT) | ||
673 | #define MSR_K8_INT_PENDING_MSG 0xc0010055 | ||
674 | /* C1E active bits in int pending message */ | ||
675 | #define K8_INTP_C1E_ACTIVE_MASK 0x18000000 | ||
676 | #define MSR_K8_TSEG_ADDR 0xc0010112 | ||
677 | #define MSR_K8_TSEG_MASK 0xc0010113 | ||
678 | #define K8_MTRRFIXRANGE_DRAM_ENABLE 0x00040000 /* MtrrFixDramEn bit */ | ||
679 | #define K8_MTRRFIXRANGE_DRAM_MODIFY 0x00080000 /* MtrrFixDramModEn bit */ | ||
680 | #define K8_MTRR_RDMEM_WRMEM_MASK 0x18181818 /* Mask: RdMem|WrMem */ | ||
681 | |||
682 | /* K7 MSRs */ | ||
683 | #define MSR_K7_EVNTSEL0 0xc0010000 | ||
684 | #define MSR_K7_PERFCTR0 0xc0010004 | ||
685 | #define MSR_K7_EVNTSEL1 0xc0010001 | ||
686 | #define MSR_K7_PERFCTR1 0xc0010005 | ||
687 | #define MSR_K7_EVNTSEL2 0xc0010002 | ||
688 | #define MSR_K7_PERFCTR2 0xc0010006 | ||
689 | #define MSR_K7_EVNTSEL3 0xc0010003 | ||
690 | #define MSR_K7_PERFCTR3 0xc0010007 | ||
691 | #define MSR_K7_CLK_CTL 0xc001001b | ||
692 | #define MSR_K7_HWCR 0xc0010015 | ||
693 | #define MSR_K7_HWCR_SMMLOCK_BIT 0 | ||
694 | #define MSR_K7_HWCR_SMMLOCK BIT_ULL(MSR_K7_HWCR_SMMLOCK_BIT) | ||
695 | #define MSR_K7_FID_VID_CTL 0xc0010041 | ||
696 | #define MSR_K7_FID_VID_STATUS 0xc0010042 | ||
697 | |||
698 | /* K6 MSRs */ | ||
699 | #define MSR_K6_WHCR 0xc0000082 | ||
700 | #define MSR_K6_UWCCR 0xc0000085 | ||
701 | #define MSR_K6_EPMR 0xc0000086 | ||
702 | #define MSR_K6_PSOR 0xc0000087 | ||
703 | #define MSR_K6_PFIR 0xc0000088 | ||
704 | |||
705 | /* Centaur-Hauls/IDT defined MSRs. */ | ||
706 | #define MSR_IDT_FCR1 0x00000107 | ||
707 | #define MSR_IDT_FCR2 0x00000108 | ||
708 | #define MSR_IDT_FCR3 0x00000109 | ||
709 | #define MSR_IDT_FCR4 0x0000010a | ||
710 | |||
711 | #define MSR_IDT_MCR0 0x00000110 | ||
712 | #define MSR_IDT_MCR1 0x00000111 | ||
713 | #define MSR_IDT_MCR2 0x00000112 | ||
714 | #define MSR_IDT_MCR3 0x00000113 | ||
715 | #define MSR_IDT_MCR4 0x00000114 | ||
716 | #define MSR_IDT_MCR5 0x00000115 | ||
717 | #define MSR_IDT_MCR6 0x00000116 | ||
718 | #define MSR_IDT_MCR7 0x00000117 | ||
719 | #define MSR_IDT_MCR_CTRL 0x00000120 | ||
720 | |||
721 | /* VIA Cyrix defined MSRs*/ | ||
722 | #define MSR_VIA_FCR 0x00001107 | ||
723 | #define MSR_VIA_LONGHAUL 0x0000110a | ||
724 | #define MSR_VIA_RNG 0x0000110b | ||
725 | #define MSR_VIA_BCR2 0x00001147 | ||
726 | |||
727 | /* Transmeta defined MSRs */ | ||
728 | #define MSR_TMTA_LONGRUN_CTRL 0x80868010 | ||
729 | #define MSR_TMTA_LONGRUN_FLAGS 0x80868011 | ||
730 | #define MSR_TMTA_LRTI_READOUT 0x80868018 | ||
731 | #define MSR_TMTA_LRTI_VOLT_MHZ 0x8086801a | ||
732 | |||
733 | /* Intel defined MSRs. */ | ||
734 | #define MSR_IA32_P5_MC_ADDR 0x00000000 | ||
735 | #define MSR_IA32_P5_MC_TYPE 0x00000001 | ||
736 | #define MSR_IA32_TSC 0x00000010 | ||
737 | #define MSR_IA32_PLATFORM_ID 0x00000017 | ||
738 | #define MSR_IA32_EBL_CR_POWERON 0x0000002a | ||
739 | #define MSR_EBC_FREQUENCY_ID 0x0000002c | ||
740 | #define MSR_SMI_COUNT 0x00000034 | ||
741 | #define MSR_IA32_FEATURE_CONTROL 0x0000003a | ||
742 | #define MSR_IA32_TSC_ADJUST 0x0000003b | ||
743 | #define MSR_IA32_BNDCFGS 0x00000d90 | ||
744 | |||
745 | #define MSR_IA32_BNDCFGS_RSVD 0x00000ffc | ||
746 | |||
747 | #define MSR_IA32_XSS 0x00000da0 | ||
748 | |||
749 | #define FEATURE_CONTROL_LOCKED (1<<0) | ||
750 | #define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1<<1) | ||
751 | #define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1<<2) | ||
752 | #define FEATURE_CONTROL_LMCE (1<<20) | ||
753 | |||
754 | #define MSR_IA32_APICBASE 0x0000001b | ||
755 | #define MSR_IA32_APICBASE_BSP (1<<8) | ||
756 | #define MSR_IA32_APICBASE_ENABLE (1<<11) | ||
757 | #define MSR_IA32_APICBASE_BASE (0xfffff<<12) | ||
758 | |||
759 | #define MSR_IA32_TSCDEADLINE 0x000006e0 | ||
760 | |||
761 | #define MSR_IA32_UCODE_WRITE 0x00000079 | ||
762 | #define MSR_IA32_UCODE_REV 0x0000008b | ||
763 | |||
764 | #define MSR_IA32_SMM_MONITOR_CTL 0x0000009b | ||
765 | #define MSR_IA32_SMBASE 0x0000009e | ||
766 | |||
767 | #define MSR_IA32_PERF_STATUS 0x00000198 | ||
768 | #define MSR_IA32_PERF_CTL 0x00000199 | ||
769 | #define INTEL_PERF_CTL_MASK 0xffff | ||
770 | #define MSR_AMD_PSTATE_DEF_BASE 0xc0010064 | ||
771 | #define MSR_AMD_PERF_STATUS 0xc0010063 | ||
772 | #define MSR_AMD_PERF_CTL 0xc0010062 | ||
773 | |||
774 | #define MSR_IA32_MPERF 0x000000e7 | ||
775 | #define MSR_IA32_APERF 0x000000e8 | ||
776 | |||
777 | #define MSR_IA32_THERM_CONTROL 0x0000019a | ||
778 | #define MSR_IA32_THERM_INTERRUPT 0x0000019b | ||
779 | |||
780 | #define THERM_INT_HIGH_ENABLE (1 << 0) | ||
781 | #define THERM_INT_LOW_ENABLE (1 << 1) | ||
782 | #define THERM_INT_PLN_ENABLE (1 << 24) | ||
783 | |||
784 | #define MSR_IA32_THERM_STATUS 0x0000019c | ||
785 | |||
786 | #define THERM_STATUS_PROCHOT (1 << 0) | ||
787 | #define THERM_STATUS_POWER_LIMIT (1 << 10) | ||
788 | |||
789 | #define MSR_THERM2_CTL 0x0000019d | ||
790 | |||
791 | #define MSR_THERM2_CTL_TM_SELECT (1ULL << 16) | ||
792 | |||
793 | #define MSR_IA32_MISC_ENABLE 0x000001a0 | ||
794 | |||
795 | #define MSR_IA32_TEMPERATURE_TARGET 0x000001a2 | ||
796 | |||
797 | #define MSR_MISC_FEATURE_CONTROL 0x000001a4 | ||
798 | #define MSR_MISC_PWR_MGMT 0x000001aa | ||
799 | |||
800 | #define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0 | ||
801 | #define ENERGY_PERF_BIAS_PERFORMANCE 0 | ||
802 | #define ENERGY_PERF_BIAS_BALANCE_PERFORMANCE 4 | ||
803 | #define ENERGY_PERF_BIAS_NORMAL 6 | ||
804 | #define ENERGY_PERF_BIAS_BALANCE_POWERSAVE 8 | ||
805 | #define ENERGY_PERF_BIAS_POWERSAVE 15 | ||
806 | |||
807 | #define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1 | ||
808 | |||
809 | #define PACKAGE_THERM_STATUS_PROCHOT (1 << 0) | ||
810 | #define PACKAGE_THERM_STATUS_POWER_LIMIT (1 << 10) | ||
811 | |||
812 | #define MSR_IA32_PACKAGE_THERM_INTERRUPT 0x000001b2 | ||
813 | |||
814 | #define PACKAGE_THERM_INT_HIGH_ENABLE (1 << 0) | ||
815 | #define PACKAGE_THERM_INT_LOW_ENABLE (1 << 1) | ||
816 | #define PACKAGE_THERM_INT_PLN_ENABLE (1 << 24) | ||
817 | |||
818 | /* Thermal Thresholds Support */ | ||
819 | #define THERM_INT_THRESHOLD0_ENABLE (1 << 15) | ||
820 | #define THERM_SHIFT_THRESHOLD0 8 | ||
821 | #define THERM_MASK_THRESHOLD0 (0x7f << THERM_SHIFT_THRESHOLD0) | ||
822 | #define THERM_INT_THRESHOLD1_ENABLE (1 << 23) | ||
823 | #define THERM_SHIFT_THRESHOLD1 16 | ||
824 | #define THERM_MASK_THRESHOLD1 (0x7f << THERM_SHIFT_THRESHOLD1) | ||
825 | #define THERM_STATUS_THRESHOLD0 (1 << 6) | ||
826 | #define THERM_LOG_THRESHOLD0 (1 << 7) | ||
827 | #define THERM_STATUS_THRESHOLD1 (1 << 8) | ||
828 | #define THERM_LOG_THRESHOLD1 (1 << 9) | ||
829 | |||
830 | /* MISC_ENABLE bits: architectural */ | ||
831 | #define MSR_IA32_MISC_ENABLE_FAST_STRING_BIT 0 | ||
832 | #define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << MSR_IA32_MISC_ENABLE_FAST_STRING_BIT) | ||
833 | #define MSR_IA32_MISC_ENABLE_TCC_BIT 1 | ||
834 | #define MSR_IA32_MISC_ENABLE_TCC (1ULL << MSR_IA32_MISC_ENABLE_TCC_BIT) | ||
835 | #define MSR_IA32_MISC_ENABLE_EMON_BIT 7 | ||
836 | #define MSR_IA32_MISC_ENABLE_EMON (1ULL << MSR_IA32_MISC_ENABLE_EMON_BIT) | ||
837 | #define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL_BIT 11 | ||
838 | #define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1ULL << MSR_IA32_MISC_ENABLE_BTS_UNAVAIL_BIT) | ||
839 | #define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL_BIT 12 | ||
840 | #define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1ULL << MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL_BIT) | ||
841 | #define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP_BIT 16 | ||
842 | #define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP (1ULL << MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP_BIT) | ||
843 | #define MSR_IA32_MISC_ENABLE_MWAIT_BIT 18 | ||
844 | #define MSR_IA32_MISC_ENABLE_MWAIT (1ULL << MSR_IA32_MISC_ENABLE_MWAIT_BIT) | ||
845 | #define MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT 22 | ||
846 | #define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1ULL << MSR_IA32_MISC_ENABLE_LIMIT_CPUID_BIT) | ||
847 | #define MSR_IA32_MISC_ENABLE_XTPR_DISABLE_BIT 23 | ||
848 | #define MSR_IA32_MISC_ENABLE_XTPR_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_XTPR_DISABLE_BIT) | ||
849 | #define MSR_IA32_MISC_ENABLE_XD_DISABLE_BIT 34 | ||
850 | #define MSR_IA32_MISC_ENABLE_XD_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_XD_DISABLE_BIT) | ||
851 | |||
852 | /* MISC_ENABLE bits: model-specific, meaning may vary from core to core */ | ||
853 | #define MSR_IA32_MISC_ENABLE_X87_COMPAT_BIT 2 | ||
854 | #define MSR_IA32_MISC_ENABLE_X87_COMPAT (1ULL << MSR_IA32_MISC_ENABLE_X87_COMPAT_BIT) | ||
855 | #define MSR_IA32_MISC_ENABLE_TM1_BIT 3 | ||
856 | #define MSR_IA32_MISC_ENABLE_TM1 (1ULL << MSR_IA32_MISC_ENABLE_TM1_BIT) | ||
857 | #define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE_BIT 4 | ||
858 | #define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE_BIT) | ||
859 | #define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE_BIT 6 | ||
860 | #define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE_BIT) | ||
861 | #define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK_BIT 8 | ||
862 | #define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK (1ULL << MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK_BIT) | ||
863 | #define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT 9 | ||
864 | #define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE_BIT) | ||
865 | #define MSR_IA32_MISC_ENABLE_FERR_BIT 10 | ||
866 | #define MSR_IA32_MISC_ENABLE_FERR (1ULL << MSR_IA32_MISC_ENABLE_FERR_BIT) | ||
867 | #define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX_BIT 10 | ||
868 | #define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX (1ULL << MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX_BIT) | ||
869 | #define MSR_IA32_MISC_ENABLE_TM2_BIT 13 | ||
870 | #define MSR_IA32_MISC_ENABLE_TM2 (1ULL << MSR_IA32_MISC_ENABLE_TM2_BIT) | ||
871 | #define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE_BIT 19 | ||
872 | #define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE_BIT) | ||
873 | #define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK_BIT 20 | ||
874 | #define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK (1ULL << MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK_BIT) | ||
875 | #define MSR_IA32_MISC_ENABLE_L1D_CONTEXT_BIT 24 | ||
876 | #define MSR_IA32_MISC_ENABLE_L1D_CONTEXT (1ULL << MSR_IA32_MISC_ENABLE_L1D_CONTEXT_BIT) | ||
877 | #define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE_BIT 37 | ||
878 | #define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE_BIT) | ||
879 | #define MSR_IA32_MISC_ENABLE_TURBO_DISABLE_BIT 38 | ||
880 | #define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_TURBO_DISABLE_BIT) | ||
881 | #define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE_BIT 39 | ||
882 | #define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE_BIT) | ||
883 | |||
884 | /* MISC_FEATURES_ENABLES non-architectural features */ | ||
885 | #define MSR_MISC_FEATURES_ENABLES 0x00000140 | ||
886 | |||
887 | #define MSR_MISC_FEATURES_ENABLES_CPUID_FAULT_BIT 0 | ||
888 | #define MSR_MISC_FEATURES_ENABLES_CPUID_FAULT BIT_ULL(MSR_MISC_FEATURES_ENABLES_CPUID_FAULT_BIT) | ||
889 | #define MSR_MISC_FEATURES_ENABLES_RING3MWAIT_BIT 1 | ||
890 | |||
891 | #define MSR_IA32_TSC_DEADLINE 0x000006E0 | ||
892 | |||
893 | /* P4/Xeon+ specific */ | ||
894 | #define MSR_IA32_MCG_EAX 0x00000180 | ||
895 | #define MSR_IA32_MCG_EBX 0x00000181 | ||
896 | #define MSR_IA32_MCG_ECX 0x00000182 | ||
897 | #define MSR_IA32_MCG_EDX 0x00000183 | ||
898 | #define MSR_IA32_MCG_ESI 0x00000184 | ||
899 | #define MSR_IA32_MCG_EDI 0x00000185 | ||
900 | #define MSR_IA32_MCG_EBP 0x00000186 | ||
901 | #define MSR_IA32_MCG_ESP 0x00000187 | ||
902 | #define MSR_IA32_MCG_EFLAGS 0x00000188 | ||
903 | #define MSR_IA32_MCG_EIP 0x00000189 | ||
904 | #define MSR_IA32_MCG_RESERVED 0x0000018a | ||
905 | |||
906 | /* Pentium IV performance counter MSRs */ | ||
907 | #define MSR_P4_BPU_PERFCTR0 0x00000300 | ||
908 | #define MSR_P4_BPU_PERFCTR1 0x00000301 | ||
909 | #define MSR_P4_BPU_PERFCTR2 0x00000302 | ||
910 | #define MSR_P4_BPU_PERFCTR3 0x00000303 | ||
911 | #define MSR_P4_MS_PERFCTR0 0x00000304 | ||
912 | #define MSR_P4_MS_PERFCTR1 0x00000305 | ||
913 | #define MSR_P4_MS_PERFCTR2 0x00000306 | ||
914 | #define MSR_P4_MS_PERFCTR3 0x00000307 | ||
915 | #define MSR_P4_FLAME_PERFCTR0 0x00000308 | ||
916 | #define MSR_P4_FLAME_PERFCTR1 0x00000309 | ||
917 | #define MSR_P4_FLAME_PERFCTR2 0x0000030a | ||
918 | #define MSR_P4_FLAME_PERFCTR3 0x0000030b | ||
919 | #define MSR_P4_IQ_PERFCTR0 0x0000030c | ||
920 | #define MSR_P4_IQ_PERFCTR1 0x0000030d | ||
921 | #define MSR_P4_IQ_PERFCTR2 0x0000030e | ||
922 | #define MSR_P4_IQ_PERFCTR3 0x0000030f | ||
923 | #define MSR_P4_IQ_PERFCTR4 0x00000310 | ||
924 | #define MSR_P4_IQ_PERFCTR5 0x00000311 | ||
925 | #define MSR_P4_BPU_CCCR0 0x00000360 | ||
926 | #define MSR_P4_BPU_CCCR1 0x00000361 | ||
927 | #define MSR_P4_BPU_CCCR2 0x00000362 | ||
928 | #define MSR_P4_BPU_CCCR3 0x00000363 | ||
929 | #define MSR_P4_MS_CCCR0 0x00000364 | ||
930 | #define MSR_P4_MS_CCCR1 0x00000365 | ||
931 | #define MSR_P4_MS_CCCR2 0x00000366 | ||
932 | #define MSR_P4_MS_CCCR3 0x00000367 | ||
933 | #define MSR_P4_FLAME_CCCR0 0x00000368 | ||
934 | #define MSR_P4_FLAME_CCCR1 0x00000369 | ||
935 | #define MSR_P4_FLAME_CCCR2 0x0000036a | ||
936 | #define MSR_P4_FLAME_CCCR3 0x0000036b | ||
937 | #define MSR_P4_IQ_CCCR0 0x0000036c | ||
938 | #define MSR_P4_IQ_CCCR1 0x0000036d | ||
939 | #define MSR_P4_IQ_CCCR2 0x0000036e | ||
940 | #define MSR_P4_IQ_CCCR3 0x0000036f | ||
941 | #define MSR_P4_IQ_CCCR4 0x00000370 | ||
942 | #define MSR_P4_IQ_CCCR5 0x00000371 | ||
943 | #define MSR_P4_ALF_ESCR0 0x000003ca | ||
944 | #define MSR_P4_ALF_ESCR1 0x000003cb | ||
945 | #define MSR_P4_BPU_ESCR0 0x000003b2 | ||
946 | #define MSR_P4_BPU_ESCR1 0x000003b3 | ||
947 | #define MSR_P4_BSU_ESCR0 0x000003a0 | ||
948 | #define MSR_P4_BSU_ESCR1 0x000003a1 | ||
949 | #define MSR_P4_CRU_ESCR0 0x000003b8 | ||
950 | #define MSR_P4_CRU_ESCR1 0x000003b9 | ||
951 | #define MSR_P4_CRU_ESCR2 0x000003cc | ||
952 | #define MSR_P4_CRU_ESCR3 0x000003cd | ||
953 | #define MSR_P4_CRU_ESCR4 0x000003e0 | ||
954 | #define MSR_P4_CRU_ESCR5 0x000003e1 | ||
955 | #define MSR_P4_DAC_ESCR0 0x000003a8 | ||
956 | #define MSR_P4_DAC_ESCR1 0x000003a9 | ||
957 | #define MSR_P4_FIRM_ESCR0 0x000003a4 | ||
958 | #define MSR_P4_FIRM_ESCR1 0x000003a5 | ||
959 | #define MSR_P4_FLAME_ESCR0 0x000003a6 | ||
960 | #define MSR_P4_FLAME_ESCR1 0x000003a7 | ||
961 | #define MSR_P4_FSB_ESCR0 0x000003a2 | ||
962 | #define MSR_P4_FSB_ESCR1 0x000003a3 | ||
963 | #define MSR_P4_IQ_ESCR0 0x000003ba | ||
964 | #define MSR_P4_IQ_ESCR1 0x000003bb | ||
965 | #define MSR_P4_IS_ESCR0 0x000003b4 | ||
966 | #define MSR_P4_IS_ESCR1 0x000003b5 | ||
967 | #define MSR_P4_ITLB_ESCR0 0x000003b6 | ||
968 | #define MSR_P4_ITLB_ESCR1 0x000003b7 | ||
969 | #define MSR_P4_IX_ESCR0 0x000003c8 | ||
970 | #define MSR_P4_IX_ESCR1 0x000003c9 | ||
971 | #define MSR_P4_MOB_ESCR0 0x000003aa | ||
972 | #define MSR_P4_MOB_ESCR1 0x000003ab | ||
973 | #define MSR_P4_MS_ESCR0 0x000003c0 | ||
974 | #define MSR_P4_MS_ESCR1 0x000003c1 | ||
975 | #define MSR_P4_PMH_ESCR0 0x000003ac | ||
976 | #define MSR_P4_PMH_ESCR1 0x000003ad | ||
977 | #define MSR_P4_RAT_ESCR0 0x000003bc | ||
978 | #define MSR_P4_RAT_ESCR1 0x000003bd | ||
979 | #define MSR_P4_SAAT_ESCR0 0x000003ae | ||
980 | #define MSR_P4_SAAT_ESCR1 0x000003af | ||
981 | #define MSR_P4_SSU_ESCR0 0x000003be | ||
982 | #define MSR_P4_SSU_ESCR1 0x000003bf /* guess: not in manual */ | ||
983 | |||
984 | #define MSR_P4_TBPU_ESCR0 0x000003c2 | ||
985 | #define MSR_P4_TBPU_ESCR1 0x000003c3 | ||
986 | #define MSR_P4_TC_ESCR0 0x000003c4 | ||
987 | #define MSR_P4_TC_ESCR1 0x000003c5 | ||
988 | #define MSR_P4_U2L_ESCR0 0x000003b0 | ||
989 | #define MSR_P4_U2L_ESCR1 0x000003b1 | ||
990 | |||
991 | #define MSR_P4_PEBS_MATRIX_VERT 0x000003f2 | ||
992 | |||
993 | /* Intel Core-based CPU performance counters */ | ||
994 | #define MSR_CORE_PERF_FIXED_CTR0 0x00000309 | ||
995 | #define MSR_CORE_PERF_FIXED_CTR1 0x0000030a | ||
996 | #define MSR_CORE_PERF_FIXED_CTR2 0x0000030b | ||
997 | #define MSR_CORE_PERF_FIXED_CTR_CTRL 0x0000038d | ||
998 | #define MSR_CORE_PERF_GLOBAL_STATUS 0x0000038e | ||
999 | #define MSR_CORE_PERF_GLOBAL_CTRL 0x0000038f | ||
1000 | #define MSR_CORE_PERF_GLOBAL_OVF_CTRL 0x00000390 | ||
1001 | |||
1002 | /* Geode defined MSRs */ | ||
1003 | #define MSR_GEODE_BUSCONT_CONF0 0x00001900 | ||
1004 | |||
1005 | /* Intel VT MSRs */ | ||
1006 | #define MSR_IA32_VMX_BASIC 0x00000480 | ||
1007 | #define MSR_IA32_VMX_PINBASED_CTLS 0x00000481 | ||
1008 | #define MSR_IA32_VMX_PROCBASED_CTLS 0x00000482 | ||
1009 | #define MSR_IA32_VMX_EXIT_CTLS 0x00000483 | ||
1010 | #define MSR_IA32_VMX_ENTRY_CTLS 0x00000484 | ||
1011 | #define MSR_IA32_VMX_MISC 0x00000485 | ||
1012 | #define MSR_IA32_VMX_CR0_FIXED0 0x00000486 | ||
1013 | #define MSR_IA32_VMX_CR0_FIXED1 0x00000487 | ||
1014 | #define MSR_IA32_VMX_CR4_FIXED0 0x00000488 | ||
1015 | #define MSR_IA32_VMX_CR4_FIXED1 0x00000489 | ||
1016 | #define MSR_IA32_VMX_VMCS_ENUM 0x0000048a | ||
1017 | #define MSR_IA32_VMX_PROCBASED_CTLS2 0x0000048b | ||
1018 | #define MSR_IA32_VMX_EPT_VPID_CAP 0x0000048c | ||
1019 | #define MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x0000048d | ||
1020 | #define MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x0000048e | ||
1021 | #define MSR_IA32_VMX_TRUE_EXIT_CTLS 0x0000048f | ||
1022 | #define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x00000490 | ||
1023 | #define MSR_IA32_VMX_VMFUNC 0x00000491 | ||
1024 | |||
1025 | /* VMX_BASIC bits and bitmasks */ | ||
1026 | #define VMX_BASIC_VMCS_SIZE_SHIFT 32 | ||
1027 | #define VMX_BASIC_TRUE_CTLS (1ULL << 55) | ||
1028 | #define VMX_BASIC_64 0x0001000000000000LLU | ||
1029 | #define VMX_BASIC_MEM_TYPE_SHIFT 50 | ||
1030 | #define VMX_BASIC_MEM_TYPE_MASK 0x003c000000000000LLU | ||
1031 | #define VMX_BASIC_MEM_TYPE_WB 6LLU | ||
1032 | #define VMX_BASIC_INOUT 0x0040000000000000LLU | ||
1033 | |||
1034 | /* MSR_IA32_VMX_MISC bits */ | ||
1035 | #define MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS (1ULL << 29) | ||
1036 | #define MSR_IA32_VMX_MISC_PREEMPTION_TIMER_SCALE 0x1F | ||
1037 | /* AMD-V MSRs */ | ||
1038 | |||
1039 | #define MSR_VM_CR 0xc0010114 | ||
1040 | #define MSR_VM_IGNNE 0xc0010115 | ||
1041 | #define MSR_VM_HSAVE_PA 0xc0010117 | ||
1042 | |||
1043 | #endif /* !SELFTEST_KVM_X86_H */ | ||
diff --git a/tools/testing/selftests/kvm/lib/assert.c b/tools/testing/selftests/kvm/lib/assert.c new file mode 100644 index 000000000000..c9f5b7d4ce38 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/assert.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/lib/assert.c | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | */ | ||
8 | |||
9 | #define _GNU_SOURCE /* for getline(3) and strchrnul(3)*/ | ||
10 | |||
11 | #include "test_util.h" | ||
12 | |||
13 | #include <execinfo.h> | ||
14 | #include <sys/syscall.h> | ||
15 | |||
16 | /* Dumps the current stack trace to stderr. */ | ||
17 | static void __attribute__((noinline)) test_dump_stack(void); | ||
18 | static void test_dump_stack(void) | ||
19 | { | ||
20 | /* | ||
21 | * Build and run this command: | ||
22 | * | ||
23 | * addr2line -s -e /proc/$PPID/exe -fpai {backtrace addresses} | \ | ||
24 | * grep -v test_dump_stack | cat -n 1>&2 | ||
25 | * | ||
26 | * Note that the spacing is different and there's no newline. | ||
27 | */ | ||
28 | size_t i; | ||
29 | size_t n = 20; | ||
30 | void *stack[n]; | ||
31 | const char *addr2line = "addr2line -s -e /proc/$PPID/exe -fpai"; | ||
32 | const char *pipeline = "|cat -n 1>&2"; | ||
33 | char cmd[strlen(addr2line) + strlen(pipeline) + | ||
34 | /* N bytes per addr * 2 digits per byte + 1 space per addr: */ | ||
35 | n * (((sizeof(void *)) * 2) + 1) + | ||
36 | /* Null terminator: */ | ||
37 | 1]; | ||
38 | char *c; | ||
39 | |||
40 | n = backtrace(stack, n); | ||
41 | c = &cmd[0]; | ||
42 | c += sprintf(c, "%s", addr2line); | ||
43 | /* | ||
44 | * Skip the first 3 frames: backtrace, test_dump_stack, and | ||
45 | * test_assert. We hope that backtrace isn't inlined and the other two | ||
46 | * we've declared noinline. | ||
47 | */ | ||
48 | for (i = 2; i < n; i++) | ||
49 | c += sprintf(c, " %lx", ((unsigned long) stack[i]) - 1); | ||
50 | c += sprintf(c, "%s", pipeline); | ||
51 | #pragma GCC diagnostic push | ||
52 | #pragma GCC diagnostic ignored "-Wunused-result" | ||
53 | system(cmd); | ||
54 | #pragma GCC diagnostic pop | ||
55 | } | ||
56 | |||
57 | static pid_t gettid(void) | ||
58 | { | ||
59 | return syscall(SYS_gettid); | ||
60 | } | ||
61 | |||
62 | void __attribute__((noinline)) | ||
63 | test_assert(bool exp, const char *exp_str, | ||
64 | const char *file, unsigned int line, const char *fmt, ...) | ||
65 | { | ||
66 | va_list ap; | ||
67 | |||
68 | if (!(exp)) { | ||
69 | va_start(ap, fmt); | ||
70 | |||
71 | fprintf(stderr, "==== Test Assertion Failure ====\n" | ||
72 | " %s:%u: %s\n" | ||
73 | " pid=%d tid=%d\n", | ||
74 | file, line, exp_str, getpid(), gettid()); | ||
75 | test_dump_stack(); | ||
76 | if (fmt) { | ||
77 | fputs(" ", stderr); | ||
78 | vfprintf(stderr, fmt, ap); | ||
79 | fputs("\n", stderr); | ||
80 | } | ||
81 | va_end(ap); | ||
82 | |||
83 | exit(254); | ||
84 | } | ||
85 | |||
86 | return; | ||
87 | } | ||
diff --git a/tools/testing/selftests/kvm/lib/elf.c b/tools/testing/selftests/kvm/lib/elf.c new file mode 100644 index 000000000000..5eb857584aa3 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/elf.c | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/lib/elf.c | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | */ | ||
8 | |||
9 | #include "test_util.h" | ||
10 | |||
11 | #include <bits/endian.h> | ||
12 | #include <linux/elf.h> | ||
13 | |||
14 | #include "kvm_util.h" | ||
15 | #include "kvm_util_internal.h" | ||
16 | |||
17 | static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp) | ||
18 | { | ||
19 | off_t offset_rv; | ||
20 | |||
21 | /* Open the ELF file. */ | ||
22 | int fd; | ||
23 | fd = open(filename, O_RDONLY); | ||
24 | TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n" | ||
25 | " filename: %s\n" | ||
26 | " rv: %i errno: %i", filename, fd, errno); | ||
27 | |||
28 | /* Read in and validate ELF Identification Record. | ||
29 | * The ELF Identification record is the first 16 (EI_NIDENT) bytes | ||
30 | * of the ELF header, which is at the beginning of the ELF file. | ||
31 | * For now it is only safe to read the first EI_NIDENT bytes. Once | ||
32 | * read and validated, the value of e_ehsize can be used to determine | ||
33 | * the real size of the ELF header. | ||
34 | */ | ||
35 | unsigned char ident[EI_NIDENT]; | ||
36 | test_read(fd, ident, sizeof(ident)); | ||
37 | TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1) | ||
38 | && (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3), | ||
39 | "ELF MAGIC Mismatch,\n" | ||
40 | " filename: %s\n" | ||
41 | " ident[EI_MAG0 - EI_MAG3]: %02x %02x %02x %02x\n" | ||
42 | " Expected: %02x %02x %02x %02x", | ||
43 | filename, | ||
44 | ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3], | ||
45 | ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3); | ||
46 | TEST_ASSERT(ident[EI_CLASS] == ELFCLASS64, | ||
47 | "Current implementation only able to handle ELFCLASS64,\n" | ||
48 | " filename: %s\n" | ||
49 | " ident[EI_CLASS]: %02x\n" | ||
50 | " expected: %02x", | ||
51 | filename, | ||
52 | ident[EI_CLASS], ELFCLASS64); | ||
53 | TEST_ASSERT(((BYTE_ORDER == LITTLE_ENDIAN) | ||
54 | && (ident[EI_DATA] == ELFDATA2LSB)) | ||
55 | || ((BYTE_ORDER == BIG_ENDIAN) | ||
56 | && (ident[EI_DATA] == ELFDATA2MSB)), "Current " | ||
57 | "implementation only able to handle\n" | ||
58 | "cases where the host and ELF file endianness\n" | ||
59 | "is the same:\n" | ||
60 | " host BYTE_ORDER: %u\n" | ||
61 | " host LITTLE_ENDIAN: %u\n" | ||
62 | " host BIG_ENDIAN: %u\n" | ||
63 | " ident[EI_DATA]: %u\n" | ||
64 | " ELFDATA2LSB: %u\n" | ||
65 | " ELFDATA2MSB: %u", | ||
66 | BYTE_ORDER, LITTLE_ENDIAN, BIG_ENDIAN, | ||
67 | ident[EI_DATA], ELFDATA2LSB, ELFDATA2MSB); | ||
68 | TEST_ASSERT(ident[EI_VERSION] == EV_CURRENT, | ||
69 | "Current implementation only able to handle current " | ||
70 | "ELF version,\n" | ||
71 | " filename: %s\n" | ||
72 | " ident[EI_VERSION]: %02x\n" | ||
73 | " expected: %02x", | ||
74 | filename, ident[EI_VERSION], EV_CURRENT); | ||
75 | |||
76 | /* Read in the ELF header. | ||
77 | * With the ELF Identification portion of the ELF header | ||
78 | * validated, especially that the value at EI_VERSION is | ||
79 | * as expected, it is now safe to read the entire ELF header. | ||
80 | */ | ||
81 | offset_rv = lseek(fd, 0, SEEK_SET); | ||
82 | TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n" | ||
83 | " rv: %zi expected: %i", offset_rv, 0); | ||
84 | test_read(fd, hdrp, sizeof(*hdrp)); | ||
85 | TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr), | ||
86 | "Unexpected physical header size,\n" | ||
87 | " hdrp->e_phentsize: %x\n" | ||
88 | " expected: %zx", | ||
89 | hdrp->e_phentsize, sizeof(Elf64_Phdr)); | ||
90 | TEST_ASSERT(hdrp->e_shentsize == sizeof(Elf64_Shdr), | ||
91 | "Unexpected section header size,\n" | ||
92 | " hdrp->e_shentsize: %x\n" | ||
93 | " expected: %zx", | ||
94 | hdrp->e_shentsize, sizeof(Elf64_Shdr)); | ||
95 | } | ||
96 | |||
97 | /* VM ELF Load | ||
98 | * | ||
99 | * Input Args: | ||
100 | * filename - Path to ELF file | ||
101 | * | ||
102 | * Output Args: None | ||
103 | * | ||
104 | * Input/Output Args: | ||
105 | * vm - Pointer to opaque type that describes the VM. | ||
106 | * | ||
107 | * Return: None, TEST_ASSERT failures for all error conditions | ||
108 | * | ||
109 | * Loads the program image of the ELF file specified by filename, | ||
110 | * into the virtual address space of the VM pointed to by vm. On entry | ||
111 | * the VM needs to not be using any of the virtual address space used | ||
112 | * by the image and it needs to have sufficient available physical pages, to | ||
113 | * back the virtual pages used to load the image. | ||
114 | */ | ||
115 | void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename, | ||
116 | uint32_t data_memslot, uint32_t pgd_memslot) | ||
117 | { | ||
118 | off_t offset, offset_rv; | ||
119 | Elf64_Ehdr hdr; | ||
120 | |||
121 | /* Open the ELF file. */ | ||
122 | int fd; | ||
123 | fd = open(filename, O_RDONLY); | ||
124 | TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n" | ||
125 | " filename: %s\n" | ||
126 | " rv: %i errno: %i", filename, fd, errno); | ||
127 | |||
128 | /* Read in the ELF header. */ | ||
129 | elfhdr_get(filename, &hdr); | ||
130 | |||
131 | /* For each program header. | ||
132 | * The following ELF header members specify the location | ||
133 | * and size of the program headers: | ||
134 | * | ||
135 | * e_phoff - File offset to start of program headers | ||
136 | * e_phentsize - Size of each program header | ||
137 | * e_phnum - Number of program header entries | ||
138 | */ | ||
139 | for (unsigned int n1 = 0; n1 < hdr.e_phnum; n1++) { | ||
140 | /* Seek to the beginning of the program header. */ | ||
141 | offset = hdr.e_phoff + (n1 * hdr.e_phentsize); | ||
142 | offset_rv = lseek(fd, offset, SEEK_SET); | ||
143 | TEST_ASSERT(offset_rv == offset, | ||
144 | "Failed to seek to begining of program header %u,\n" | ||
145 | " filename: %s\n" | ||
146 | " rv: %jd errno: %i", | ||
147 | n1, filename, (intmax_t) offset_rv, errno); | ||
148 | |||
149 | /* Read in the program header. */ | ||
150 | Elf64_Phdr phdr; | ||
151 | test_read(fd, &phdr, sizeof(phdr)); | ||
152 | |||
153 | /* Skip if this header doesn't describe a loadable segment. */ | ||
154 | if (phdr.p_type != PT_LOAD) | ||
155 | continue; | ||
156 | |||
157 | /* Allocate memory for this segment within the VM. */ | ||
158 | TEST_ASSERT(phdr.p_memsz > 0, "Unexpected loadable segment " | ||
159 | "memsize of 0,\n" | ||
160 | " phdr index: %u p_memsz: 0x%" PRIx64, | ||
161 | n1, (uint64_t) phdr.p_memsz); | ||
162 | vm_vaddr_t seg_vstart = phdr.p_vaddr; | ||
163 | seg_vstart &= ~(vm_vaddr_t)(vm->page_size - 1); | ||
164 | vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1; | ||
165 | seg_vend |= vm->page_size - 1; | ||
166 | size_t seg_size = seg_vend - seg_vstart + 1; | ||
167 | |||
168 | vm_vaddr_t vaddr = vm_vaddr_alloc(vm, seg_size, seg_vstart, | ||
169 | data_memslot, pgd_memslot); | ||
170 | TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate " | ||
171 | "virtual memory for segment at requested min addr,\n" | ||
172 | " segment idx: %u\n" | ||
173 | " seg_vstart: 0x%lx\n" | ||
174 | " vaddr: 0x%lx", | ||
175 | n1, seg_vstart, vaddr); | ||
176 | memset(addr_gva2hva(vm, vaddr), 0, seg_size); | ||
177 | /* TODO(lhuemill): Set permissions of each memory segment | ||
178 | * based on the least-significant 3 bits of phdr.p_flags. | ||
179 | */ | ||
180 | |||
181 | /* Load portion of initial state that is contained within | ||
182 | * the ELF file. | ||
183 | */ | ||
184 | if (phdr.p_filesz) { | ||
185 | offset_rv = lseek(fd, phdr.p_offset, SEEK_SET); | ||
186 | TEST_ASSERT(offset_rv == phdr.p_offset, | ||
187 | "Seek to program segment offset failed,\n" | ||
188 | " program header idx: %u errno: %i\n" | ||
189 | " offset_rv: 0x%jx\n" | ||
190 | " expected: 0x%jx\n", | ||
191 | n1, errno, (intmax_t) offset_rv, | ||
192 | (intmax_t) phdr.p_offset); | ||
193 | test_read(fd, addr_gva2hva(vm, phdr.p_vaddr), | ||
194 | phdr.p_filesz); | ||
195 | } | ||
196 | } | ||
197 | } | ||
diff --git a/tools/testing/selftests/kvm/lib/io.c b/tools/testing/selftests/kvm/lib/io.c new file mode 100644 index 000000000000..cff869ffe6ee --- /dev/null +++ b/tools/testing/selftests/kvm/lib/io.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/lib/io.c | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | */ | ||
8 | |||
9 | #include "test_util.h" | ||
10 | |||
11 | /* Test Write | ||
12 | * | ||
13 | * A wrapper for write(2), that automatically handles the following | ||
14 | * special conditions: | ||
15 | * | ||
16 | * + Interrupted system call (EINTR) | ||
17 | * + Write of less than requested amount | ||
18 | * + Non-block return (EAGAIN) | ||
19 | * | ||
20 | * For each of the above, an additional write is performed to automatically | ||
21 | * continue writing the requested data. | ||
22 | * There are also many cases where write(2) can return an unexpected | ||
23 | * error (e.g. EIO). Such errors cause a TEST_ASSERT failure. | ||
24 | * | ||
25 | * Note, for function signature compatibility with write(2), this function | ||
26 | * returns the number of bytes written, but that value will always be equal | ||
27 | * to the number of requested bytes. All other conditions in this and | ||
28 | * future enhancements to this function either automatically issue another | ||
29 | * write(2) or cause a TEST_ASSERT failure. | ||
30 | * | ||
31 | * Args: | ||
32 | * fd - Opened file descriptor to file to be written. | ||
33 | * count - Number of bytes to write. | ||
34 | * | ||
35 | * Output: | ||
36 | * buf - Starting address of data to be written. | ||
37 | * | ||
38 | * Return: | ||
39 | * On success, number of bytes written. | ||
40 | * On failure, a TEST_ASSERT failure is caused. | ||
41 | */ | ||
42 | ssize_t test_write(int fd, const void *buf, size_t count) | ||
43 | { | ||
44 | ssize_t rc; | ||
45 | ssize_t num_written = 0; | ||
46 | size_t num_left = count; | ||
47 | const char *ptr = buf; | ||
48 | |||
49 | /* Note: Count of zero is allowed (see "RETURN VALUE" portion of | ||
50 | * write(2) manpage for details. | ||
51 | */ | ||
52 | TEST_ASSERT(count >= 0, "Unexpected count, count: %li", count); | ||
53 | |||
54 | do { | ||
55 | rc = write(fd, ptr, num_left); | ||
56 | |||
57 | switch (rc) { | ||
58 | case -1: | ||
59 | TEST_ASSERT(errno == EAGAIN || errno == EINTR, | ||
60 | "Unexpected write failure,\n" | ||
61 | " rc: %zi errno: %i", rc, errno); | ||
62 | continue; | ||
63 | |||
64 | case 0: | ||
65 | TEST_ASSERT(false, "Unexpected EOF,\n" | ||
66 | " rc: %zi num_written: %zi num_left: %zu", | ||
67 | rc, num_written, num_left); | ||
68 | break; | ||
69 | |||
70 | default: | ||
71 | TEST_ASSERT(rc >= 0, "Unexpected ret from write,\n" | ||
72 | " rc: %zi errno: %i", rc, errno); | ||
73 | num_written += rc; | ||
74 | num_left -= rc; | ||
75 | ptr += rc; | ||
76 | break; | ||
77 | } | ||
78 | } while (num_written < count); | ||
79 | |||
80 | return num_written; | ||
81 | } | ||
82 | |||
83 | /* Test Read | ||
84 | * | ||
85 | * A wrapper for read(2), that automatically handles the following | ||
86 | * special conditions: | ||
87 | * | ||
88 | * + Interrupted system call (EINTR) | ||
89 | * + Read of less than requested amount | ||
90 | * + Non-block return (EAGAIN) | ||
91 | * | ||
92 | * For each of the above, an additional read is performed to automatically | ||
93 | * continue reading the requested data. | ||
94 | * There are also many cases where read(2) can return an unexpected | ||
95 | * error (e.g. EIO). Such errors cause a TEST_ASSERT failure. Note, | ||
96 | * it is expected that the file opened by fd at the current file position | ||
97 | * contains at least the number of requested bytes to be read. A TEST_ASSERT | ||
98 | * failure is produced if an End-Of-File condition occurs, before all the | ||
99 | * data is read. It is the callers responsibility to assure that sufficient | ||
100 | * data exists. | ||
101 | * | ||
102 | * Note, for function signature compatibility with read(2), this function | ||
103 | * returns the number of bytes read, but that value will always be equal | ||
104 | * to the number of requested bytes. All other conditions in this and | ||
105 | * future enhancements to this function either automatically issue another | ||
106 | * read(2) or cause a TEST_ASSERT failure. | ||
107 | * | ||
108 | * Args: | ||
109 | * fd - Opened file descriptor to file to be read. | ||
110 | * count - Number of bytes to read. | ||
111 | * | ||
112 | * Output: | ||
113 | * buf - Starting address of where to write the bytes read. | ||
114 | * | ||
115 | * Return: | ||
116 | * On success, number of bytes read. | ||
117 | * On failure, a TEST_ASSERT failure is caused. | ||
118 | */ | ||
119 | ssize_t test_read(int fd, void *buf, size_t count) | ||
120 | { | ||
121 | ssize_t rc; | ||
122 | ssize_t num_read = 0; | ||
123 | size_t num_left = count; | ||
124 | char *ptr = buf; | ||
125 | |||
126 | /* Note: Count of zero is allowed (see "If count is zero" portion of | ||
127 | * read(2) manpage for details. | ||
128 | */ | ||
129 | TEST_ASSERT(count >= 0, "Unexpected count, count: %li", count); | ||
130 | |||
131 | do { | ||
132 | rc = read(fd, ptr, num_left); | ||
133 | |||
134 | switch (rc) { | ||
135 | case -1: | ||
136 | TEST_ASSERT(errno == EAGAIN || errno == EINTR, | ||
137 | "Unexpected read failure,\n" | ||
138 | " rc: %zi errno: %i", rc, errno); | ||
139 | break; | ||
140 | |||
141 | case 0: | ||
142 | TEST_ASSERT(false, "Unexpected EOF,\n" | ||
143 | " rc: %zi num_read: %zi num_left: %zu", | ||
144 | rc, num_read, num_left); | ||
145 | break; | ||
146 | |||
147 | default: | ||
148 | TEST_ASSERT(rc > 0, "Unexpected ret from read,\n" | ||
149 | " rc: %zi errno: %i", rc, errno); | ||
150 | num_read += rc; | ||
151 | num_left -= rc; | ||
152 | ptr += rc; | ||
153 | break; | ||
154 | } | ||
155 | } while (num_read < count); | ||
156 | |||
157 | return num_read; | ||
158 | } | ||
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c new file mode 100644 index 000000000000..2cedfda181d4 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/kvm_util.c | |||
@@ -0,0 +1,1486 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/lib/kvm_util.c | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | */ | ||
8 | |||
9 | #include "test_util.h" | ||
10 | #include "kvm_util.h" | ||
11 | #include "kvm_util_internal.h" | ||
12 | |||
13 | #include <assert.h> | ||
14 | #include <sys/mman.h> | ||
15 | #include <sys/types.h> | ||
16 | #include <sys/stat.h> | ||
17 | |||
18 | #define KVM_DEV_PATH "/dev/kvm" | ||
19 | |||
20 | #define KVM_UTIL_PGS_PER_HUGEPG 512 | ||
21 | #define KVM_UTIL_MIN_PADDR 0x2000 | ||
22 | |||
23 | /* Aligns x up to the next multiple of size. Size must be a power of 2. */ | ||
24 | static void *align(void *x, size_t size) | ||
25 | { | ||
26 | size_t mask = size - 1; | ||
27 | TEST_ASSERT(size != 0 && !(size & (size - 1)), | ||
28 | "size not a power of 2: %lu", size); | ||
29 | return (void *) (((size_t) x + mask) & ~mask); | ||
30 | } | ||
31 | |||
32 | /* Capability | ||
33 | * | ||
34 | * Input Args: | ||
35 | * cap - Capability | ||
36 | * | ||
37 | * Output Args: None | ||
38 | * | ||
39 | * Return: | ||
40 | * On success, the Value corresponding to the capability (KVM_CAP_*) | ||
41 | * specified by the value of cap. On failure a TEST_ASSERT failure | ||
42 | * is produced. | ||
43 | * | ||
44 | * Looks up and returns the value corresponding to the capability | ||
45 | * (KVM_CAP_*) given by cap. | ||
46 | */ | ||
47 | int kvm_check_cap(long cap) | ||
48 | { | ||
49 | int ret; | ||
50 | int kvm_fd; | ||
51 | |||
52 | kvm_fd = open(KVM_DEV_PATH, O_RDONLY); | ||
53 | TEST_ASSERT(kvm_fd >= 0, "open %s failed, rc: %i errno: %i", | ||
54 | KVM_DEV_PATH, kvm_fd, errno); | ||
55 | |||
56 | ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, cap); | ||
57 | TEST_ASSERT(ret != -1, "KVM_CHECK_EXTENSION IOCTL failed,\n" | ||
58 | " rc: %i errno: %i", ret, errno); | ||
59 | |||
60 | close(kvm_fd); | ||
61 | |||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | /* VM Create | ||
66 | * | ||
67 | * Input Args: | ||
68 | * mode - VM Mode (e.g. VM_MODE_FLAT48PG) | ||
69 | * phy_pages - Physical memory pages | ||
70 | * perm - permission | ||
71 | * | ||
72 | * Output Args: None | ||
73 | * | ||
74 | * Return: | ||
75 | * Pointer to opaque structure that describes the created VM. | ||
76 | * | ||
77 | * Creates a VM with the mode specified by mode (e.g. VM_MODE_FLAT48PG). | ||
78 | * When phy_pages is non-zero, a memory region of phy_pages physical pages | ||
79 | * is created and mapped starting at guest physical address 0. The file | ||
80 | * descriptor to control the created VM is created with the permissions | ||
81 | * given by perm (e.g. O_RDWR). | ||
82 | */ | ||
83 | struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) | ||
84 | { | ||
85 | struct kvm_vm *vm; | ||
86 | int kvm_fd; | ||
87 | |||
88 | /* Allocate memory. */ | ||
89 | vm = calloc(1, sizeof(*vm)); | ||
90 | TEST_ASSERT(vm != NULL, "Insufficent Memory"); | ||
91 | |||
92 | vm->mode = mode; | ||
93 | kvm_fd = open(KVM_DEV_PATH, perm); | ||
94 | TEST_ASSERT(kvm_fd >= 0, "open %s failed, rc: %i errno: %i", | ||
95 | KVM_DEV_PATH, kvm_fd, errno); | ||
96 | |||
97 | /* Create VM. */ | ||
98 | vm->fd = ioctl(kvm_fd, KVM_CREATE_VM, NULL); | ||
99 | TEST_ASSERT(vm->fd >= 0, "KVM_CREATE_VM ioctl failed, " | ||
100 | "rc: %i errno: %i", vm->fd, errno); | ||
101 | |||
102 | close(kvm_fd); | ||
103 | |||
104 | /* Setup mode specific traits. */ | ||
105 | switch (vm->mode) { | ||
106 | case VM_MODE_FLAT48PG: | ||
107 | vm->page_size = 0x1000; | ||
108 | vm->page_shift = 12; | ||
109 | |||
110 | /* Limit to 48-bit canonical virtual addresses. */ | ||
111 | vm->vpages_valid = sparsebit_alloc(); | ||
112 | sparsebit_set_num(vm->vpages_valid, | ||
113 | 0, (1ULL << (48 - 1)) >> vm->page_shift); | ||
114 | sparsebit_set_num(vm->vpages_valid, | ||
115 | (~((1ULL << (48 - 1)) - 1)) >> vm->page_shift, | ||
116 | (1ULL << (48 - 1)) >> vm->page_shift); | ||
117 | |||
118 | /* Limit physical addresses to 52-bits. */ | ||
119 | vm->max_gfn = ((1ULL << 52) >> vm->page_shift) - 1; | ||
120 | break; | ||
121 | |||
122 | default: | ||
123 | TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode); | ||
124 | } | ||
125 | |||
126 | /* Allocate and setup memory for guest. */ | ||
127 | vm->vpages_mapped = sparsebit_alloc(); | ||
128 | if (phy_pages != 0) | ||
129 | vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, | ||
130 | 0, 0, phy_pages, 0); | ||
131 | |||
132 | return vm; | ||
133 | } | ||
134 | |||
135 | /* Userspace Memory Region Find | ||
136 | * | ||
137 | * Input Args: | ||
138 | * vm - Virtual Machine | ||
139 | * start - Starting VM physical address | ||
140 | * end - Ending VM physical address, inclusive. | ||
141 | * | ||
142 | * Output Args: None | ||
143 | * | ||
144 | * Return: | ||
145 | * Pointer to overlapping region, NULL if no such region. | ||
146 | * | ||
147 | * Searches for a region with any physical memory that overlaps with | ||
148 | * any portion of the guest physical addresses from start to end | ||
149 | * inclusive. If multiple overlapping regions exist, a pointer to any | ||
150 | * of the regions is returned. Null is returned only when no overlapping | ||
151 | * region exists. | ||
152 | */ | ||
153 | static struct userspace_mem_region *userspace_mem_region_find( | ||
154 | struct kvm_vm *vm, uint64_t start, uint64_t end) | ||
155 | { | ||
156 | struct userspace_mem_region *region; | ||
157 | |||
158 | for (region = vm->userspace_mem_region_head; region; | ||
159 | region = region->next) { | ||
160 | uint64_t existing_start = region->region.guest_phys_addr; | ||
161 | uint64_t existing_end = region->region.guest_phys_addr | ||
162 | + region->region.memory_size - 1; | ||
163 | if (start <= existing_end && end >= existing_start) | ||
164 | return region; | ||
165 | } | ||
166 | |||
167 | return NULL; | ||
168 | } | ||
169 | |||
170 | /* KVM Userspace Memory Region Find | ||
171 | * | ||
172 | * Input Args: | ||
173 | * vm - Virtual Machine | ||
174 | * start - Starting VM physical address | ||
175 | * end - Ending VM physical address, inclusive. | ||
176 | * | ||
177 | * Output Args: None | ||
178 | * | ||
179 | * Return: | ||
180 | * Pointer to overlapping region, NULL if no such region. | ||
181 | * | ||
182 | * Public interface to userspace_mem_region_find. Allows tests to look up | ||
183 | * the memslot datastructure for a given range of guest physical memory. | ||
184 | */ | ||
185 | struct kvm_userspace_memory_region * | ||
186 | kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, | ||
187 | uint64_t end) | ||
188 | { | ||
189 | struct userspace_mem_region *region; | ||
190 | |||
191 | region = userspace_mem_region_find(vm, start, end); | ||
192 | if (!region) | ||
193 | return NULL; | ||
194 | |||
195 | return ®ion->region; | ||
196 | } | ||
197 | |||
198 | /* VCPU Find | ||
199 | * | ||
200 | * Input Args: | ||
201 | * vm - Virtual Machine | ||
202 | * vcpuid - VCPU ID | ||
203 | * | ||
204 | * Output Args: None | ||
205 | * | ||
206 | * Return: | ||
207 | * Pointer to VCPU structure | ||
208 | * | ||
209 | * Locates a vcpu structure that describes the VCPU specified by vcpuid and | ||
210 | * returns a pointer to it. Returns NULL if the VM doesn't contain a VCPU | ||
211 | * for the specified vcpuid. | ||
212 | */ | ||
213 | struct vcpu *vcpu_find(struct kvm_vm *vm, | ||
214 | uint32_t vcpuid) | ||
215 | { | ||
216 | struct vcpu *vcpup; | ||
217 | |||
218 | for (vcpup = vm->vcpu_head; vcpup; vcpup = vcpup->next) { | ||
219 | if (vcpup->id == vcpuid) | ||
220 | return vcpup; | ||
221 | } | ||
222 | |||
223 | return NULL; | ||
224 | } | ||
225 | |||
226 | /* VM VCPU Remove | ||
227 | * | ||
228 | * Input Args: | ||
229 | * vm - Virtual Machine | ||
230 | * vcpuid - VCPU ID | ||
231 | * | ||
232 | * Output Args: None | ||
233 | * | ||
234 | * Return: None, TEST_ASSERT failures for all error conditions | ||
235 | * | ||
236 | * Within the VM specified by vm, removes the VCPU given by vcpuid. | ||
237 | */ | ||
238 | static void vm_vcpu_rm(struct kvm_vm *vm, uint32_t vcpuid) | ||
239 | { | ||
240 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
241 | |||
242 | int ret = close(vcpu->fd); | ||
243 | TEST_ASSERT(ret == 0, "Close of VCPU fd failed, rc: %i " | ||
244 | "errno: %i", ret, errno); | ||
245 | |||
246 | if (vcpu->next) | ||
247 | vcpu->next->prev = vcpu->prev; | ||
248 | if (vcpu->prev) | ||
249 | vcpu->prev->next = vcpu->next; | ||
250 | else | ||
251 | vm->vcpu_head = vcpu->next; | ||
252 | free(vcpu); | ||
253 | } | ||
254 | |||
255 | |||
256 | /* Destroys and frees the VM pointed to by vmp. | ||
257 | */ | ||
258 | void kvm_vm_free(struct kvm_vm *vmp) | ||
259 | { | ||
260 | int ret; | ||
261 | |||
262 | if (vmp == NULL) | ||
263 | return; | ||
264 | |||
265 | /* Free userspace_mem_regions. */ | ||
266 | while (vmp->userspace_mem_region_head) { | ||
267 | struct userspace_mem_region *region | ||
268 | = vmp->userspace_mem_region_head; | ||
269 | |||
270 | region->region.memory_size = 0; | ||
271 | ret = ioctl(vmp->fd, KVM_SET_USER_MEMORY_REGION, | ||
272 | ®ion->region); | ||
273 | TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed, " | ||
274 | "rc: %i errno: %i", ret, errno); | ||
275 | |||
276 | vmp->userspace_mem_region_head = region->next; | ||
277 | sparsebit_free(®ion->unused_phy_pages); | ||
278 | ret = munmap(region->mmap_start, region->mmap_size); | ||
279 | TEST_ASSERT(ret == 0, "munmap failed, rc: %i errno: %i", | ||
280 | ret, errno); | ||
281 | |||
282 | free(region); | ||
283 | } | ||
284 | |||
285 | /* Free VCPUs. */ | ||
286 | while (vmp->vcpu_head) | ||
287 | vm_vcpu_rm(vmp, vmp->vcpu_head->id); | ||
288 | |||
289 | /* Free sparsebit arrays. */ | ||
290 | sparsebit_free(&vmp->vpages_valid); | ||
291 | sparsebit_free(&vmp->vpages_mapped); | ||
292 | |||
293 | /* Close file descriptor for the VM. */ | ||
294 | ret = close(vmp->fd); | ||
295 | TEST_ASSERT(ret == 0, "Close of vm fd failed,\n" | ||
296 | " vmp->fd: %i rc: %i errno: %i", vmp->fd, ret, errno); | ||
297 | |||
298 | /* Free the structure describing the VM. */ | ||
299 | free(vmp); | ||
300 | } | ||
301 | |||
302 | /* Memory Compare, host virtual to guest virtual | ||
303 | * | ||
304 | * Input Args: | ||
305 | * hva - Starting host virtual address | ||
306 | * vm - Virtual Machine | ||
307 | * gva - Starting guest virtual address | ||
308 | * len - number of bytes to compare | ||
309 | * | ||
310 | * Output Args: None | ||
311 | * | ||
312 | * Input/Output Args: None | ||
313 | * | ||
314 | * Return: | ||
315 | * Returns 0 if the bytes starting at hva for a length of len | ||
316 | * are equal the guest virtual bytes starting at gva. Returns | ||
317 | * a value < 0, if bytes at hva are less than those at gva. | ||
318 | * Otherwise a value > 0 is returned. | ||
319 | * | ||
320 | * Compares the bytes starting at the host virtual address hva, for | ||
321 | * a length of len, to the guest bytes starting at the guest virtual | ||
322 | * address given by gva. | ||
323 | */ | ||
324 | int kvm_memcmp_hva_gva(void *hva, | ||
325 | struct kvm_vm *vm, vm_vaddr_t gva, size_t len) | ||
326 | { | ||
327 | size_t amt; | ||
328 | |||
329 | /* Compare a batch of bytes until either a match is found | ||
330 | * or all the bytes have been compared. | ||
331 | */ | ||
332 | for (uintptr_t offset = 0; offset < len; offset += amt) { | ||
333 | uintptr_t ptr1 = (uintptr_t)hva + offset; | ||
334 | |||
335 | /* Determine host address for guest virtual address | ||
336 | * at offset. | ||
337 | */ | ||
338 | uintptr_t ptr2 = (uintptr_t)addr_gva2hva(vm, gva + offset); | ||
339 | |||
340 | /* Determine amount to compare on this pass. | ||
341 | * Don't allow the comparsion to cross a page boundary. | ||
342 | */ | ||
343 | amt = len - offset; | ||
344 | if ((ptr1 >> vm->page_shift) != ((ptr1 + amt) >> vm->page_shift)) | ||
345 | amt = vm->page_size - (ptr1 % vm->page_size); | ||
346 | if ((ptr2 >> vm->page_shift) != ((ptr2 + amt) >> vm->page_shift)) | ||
347 | amt = vm->page_size - (ptr2 % vm->page_size); | ||
348 | |||
349 | assert((ptr1 >> vm->page_shift) == ((ptr1 + amt - 1) >> vm->page_shift)); | ||
350 | assert((ptr2 >> vm->page_shift) == ((ptr2 + amt - 1) >> vm->page_shift)); | ||
351 | |||
352 | /* Perform the comparison. If there is a difference | ||
353 | * return that result to the caller, otherwise need | ||
354 | * to continue on looking for a mismatch. | ||
355 | */ | ||
356 | int ret = memcmp((void *)ptr1, (void *)ptr2, amt); | ||
357 | if (ret != 0) | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | /* No mismatch found. Let the caller know the two memory | ||
362 | * areas are equal. | ||
363 | */ | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | /* Allocate an instance of struct kvm_cpuid2 | ||
368 | * | ||
369 | * Input Args: None | ||
370 | * | ||
371 | * Output Args: None | ||
372 | * | ||
373 | * Return: A pointer to the allocated struct. The caller is responsible | ||
374 | * for freeing this struct. | ||
375 | * | ||
376 | * Since kvm_cpuid2 uses a 0-length array to allow a the size of the | ||
377 | * array to be decided at allocation time, allocation is slightly | ||
378 | * complicated. This function uses a reasonable default length for | ||
379 | * the array and performs the appropriate allocation. | ||
380 | */ | ||
381 | static struct kvm_cpuid2 *allocate_kvm_cpuid2(void) | ||
382 | { | ||
383 | struct kvm_cpuid2 *cpuid; | ||
384 | int nent = 100; | ||
385 | size_t size; | ||
386 | |||
387 | size = sizeof(*cpuid); | ||
388 | size += nent * sizeof(struct kvm_cpuid_entry2); | ||
389 | cpuid = malloc(size); | ||
390 | if (!cpuid) { | ||
391 | perror("malloc"); | ||
392 | abort(); | ||
393 | } | ||
394 | |||
395 | cpuid->nent = nent; | ||
396 | |||
397 | return cpuid; | ||
398 | } | ||
399 | |||
400 | /* KVM Supported CPUID Get | ||
401 | * | ||
402 | * Input Args: None | ||
403 | * | ||
404 | * Output Args: | ||
405 | * | ||
406 | * Return: The supported KVM CPUID | ||
407 | * | ||
408 | * Get the guest CPUID supported by KVM. | ||
409 | */ | ||
410 | struct kvm_cpuid2 *kvm_get_supported_cpuid(void) | ||
411 | { | ||
412 | static struct kvm_cpuid2 *cpuid; | ||
413 | int ret; | ||
414 | int kvm_fd; | ||
415 | |||
416 | if (cpuid) | ||
417 | return cpuid; | ||
418 | |||
419 | cpuid = allocate_kvm_cpuid2(); | ||
420 | kvm_fd = open(KVM_DEV_PATH, O_RDONLY); | ||
421 | TEST_ASSERT(kvm_fd >= 0, "open %s failed, rc: %i errno: %i", | ||
422 | KVM_DEV_PATH, kvm_fd, errno); | ||
423 | |||
424 | ret = ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, cpuid); | ||
425 | TEST_ASSERT(ret == 0, "KVM_GET_SUPPORTED_CPUID failed %d %d\n", | ||
426 | ret, errno); | ||
427 | |||
428 | close(kvm_fd); | ||
429 | return cpuid; | ||
430 | } | ||
431 | |||
432 | /* Locate a cpuid entry. | ||
433 | * | ||
434 | * Input Args: | ||
435 | * cpuid: The cpuid. | ||
436 | * function: The function of the cpuid entry to find. | ||
437 | * | ||
438 | * Output Args: None | ||
439 | * | ||
440 | * Return: A pointer to the cpuid entry. Never returns NULL. | ||
441 | */ | ||
442 | struct kvm_cpuid_entry2 * | ||
443 | kvm_get_supported_cpuid_index(uint32_t function, uint32_t index) | ||
444 | { | ||
445 | struct kvm_cpuid2 *cpuid; | ||
446 | struct kvm_cpuid_entry2 *entry = NULL; | ||
447 | int i; | ||
448 | |||
449 | cpuid = kvm_get_supported_cpuid(); | ||
450 | for (i = 0; i < cpuid->nent; i++) { | ||
451 | if (cpuid->entries[i].function == function && | ||
452 | cpuid->entries[i].index == index) { | ||
453 | entry = &cpuid->entries[i]; | ||
454 | break; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | TEST_ASSERT(entry, "Guest CPUID entry not found: (EAX=%x, ECX=%x).", | ||
459 | function, index); | ||
460 | return entry; | ||
461 | } | ||
462 | |||
463 | /* VM Userspace Memory Region Add | ||
464 | * | ||
465 | * Input Args: | ||
466 | * vm - Virtual Machine | ||
467 | * backing_src - Storage source for this region. | ||
468 | * NULL to use anonymous memory. | ||
469 | * guest_paddr - Starting guest physical address | ||
470 | * slot - KVM region slot | ||
471 | * npages - Number of physical pages | ||
472 | * flags - KVM memory region flags (e.g. KVM_MEM_LOG_DIRTY_PAGES) | ||
473 | * | ||
474 | * Output Args: None | ||
475 | * | ||
476 | * Return: None | ||
477 | * | ||
478 | * Allocates a memory area of the number of pages specified by npages | ||
479 | * and maps it to the VM specified by vm, at a starting physical address | ||
480 | * given by guest_paddr. The region is created with a KVM region slot | ||
481 | * given by slot, which must be unique and < KVM_MEM_SLOTS_NUM. The | ||
482 | * region is created with the flags given by flags. | ||
483 | */ | ||
484 | void vm_userspace_mem_region_add(struct kvm_vm *vm, | ||
485 | enum vm_mem_backing_src_type src_type, | ||
486 | uint64_t guest_paddr, uint32_t slot, uint64_t npages, | ||
487 | uint32_t flags) | ||
488 | { | ||
489 | int ret; | ||
490 | unsigned long pmem_size = 0; | ||
491 | struct userspace_mem_region *region; | ||
492 | size_t huge_page_size = KVM_UTIL_PGS_PER_HUGEPG * vm->page_size; | ||
493 | |||
494 | TEST_ASSERT((guest_paddr % vm->page_size) == 0, "Guest physical " | ||
495 | "address not on a page boundary.\n" | ||
496 | " guest_paddr: 0x%lx vm->page_size: 0x%x", | ||
497 | guest_paddr, vm->page_size); | ||
498 | TEST_ASSERT((((guest_paddr >> vm->page_shift) + npages) - 1) | ||
499 | <= vm->max_gfn, "Physical range beyond maximum " | ||
500 | "supported physical address,\n" | ||
501 | " guest_paddr: 0x%lx npages: 0x%lx\n" | ||
502 | " vm->max_gfn: 0x%lx vm->page_size: 0x%x", | ||
503 | guest_paddr, npages, vm->max_gfn, vm->page_size); | ||
504 | |||
505 | /* Confirm a mem region with an overlapping address doesn't | ||
506 | * already exist. | ||
507 | */ | ||
508 | region = (struct userspace_mem_region *) userspace_mem_region_find( | ||
509 | vm, guest_paddr, guest_paddr + npages * vm->page_size); | ||
510 | if (region != NULL) | ||
511 | TEST_ASSERT(false, "overlapping userspace_mem_region already " | ||
512 | "exists\n" | ||
513 | " requested guest_paddr: 0x%lx npages: 0x%lx " | ||
514 | "page_size: 0x%x\n" | ||
515 | " existing guest_paddr: 0x%lx size: 0x%lx", | ||
516 | guest_paddr, npages, vm->page_size, | ||
517 | (uint64_t) region->region.guest_phys_addr, | ||
518 | (uint64_t) region->region.memory_size); | ||
519 | |||
520 | /* Confirm no region with the requested slot already exists. */ | ||
521 | for (region = vm->userspace_mem_region_head; region; | ||
522 | region = region->next) { | ||
523 | if (region->region.slot == slot) | ||
524 | break; | ||
525 | if ((guest_paddr <= (region->region.guest_phys_addr | ||
526 | + region->region.memory_size)) | ||
527 | && ((guest_paddr + npages * vm->page_size) | ||
528 | >= region->region.guest_phys_addr)) | ||
529 | break; | ||
530 | } | ||
531 | if (region != NULL) | ||
532 | TEST_ASSERT(false, "A mem region with the requested slot " | ||
533 | "or overlapping physical memory range already exists.\n" | ||
534 | " requested slot: %u paddr: 0x%lx npages: 0x%lx\n" | ||
535 | " existing slot: %u paddr: 0x%lx size: 0x%lx", | ||
536 | slot, guest_paddr, npages, | ||
537 | region->region.slot, | ||
538 | (uint64_t) region->region.guest_phys_addr, | ||
539 | (uint64_t) region->region.memory_size); | ||
540 | |||
541 | /* Allocate and initialize new mem region structure. */ | ||
542 | region = calloc(1, sizeof(*region)); | ||
543 | TEST_ASSERT(region != NULL, "Insufficient Memory"); | ||
544 | region->mmap_size = npages * vm->page_size; | ||
545 | |||
546 | /* Enough memory to align up to a huge page. */ | ||
547 | if (src_type == VM_MEM_SRC_ANONYMOUS_THP) | ||
548 | region->mmap_size += huge_page_size; | ||
549 | region->mmap_start = mmap(NULL, region->mmap_size, | ||
550 | PROT_READ | PROT_WRITE, | ||
551 | MAP_PRIVATE | MAP_ANONYMOUS | ||
552 | | (src_type == VM_MEM_SRC_ANONYMOUS_HUGETLB ? MAP_HUGETLB : 0), | ||
553 | -1, 0); | ||
554 | TEST_ASSERT(region->mmap_start != MAP_FAILED, | ||
555 | "test_malloc failed, mmap_start: %p errno: %i", | ||
556 | region->mmap_start, errno); | ||
557 | |||
558 | /* Align THP allocation up to start of a huge page. */ | ||
559 | region->host_mem = align(region->mmap_start, | ||
560 | src_type == VM_MEM_SRC_ANONYMOUS_THP ? huge_page_size : 1); | ||
561 | |||
562 | /* As needed perform madvise */ | ||
563 | if (src_type == VM_MEM_SRC_ANONYMOUS || src_type == VM_MEM_SRC_ANONYMOUS_THP) { | ||
564 | ret = madvise(region->host_mem, npages * vm->page_size, | ||
565 | src_type == VM_MEM_SRC_ANONYMOUS ? MADV_NOHUGEPAGE : MADV_HUGEPAGE); | ||
566 | TEST_ASSERT(ret == 0, "madvise failed,\n" | ||
567 | " addr: %p\n" | ||
568 | " length: 0x%lx\n" | ||
569 | " src_type: %x", | ||
570 | region->host_mem, npages * vm->page_size, src_type); | ||
571 | } | ||
572 | |||
573 | region->unused_phy_pages = sparsebit_alloc(); | ||
574 | sparsebit_set_num(region->unused_phy_pages, | ||
575 | guest_paddr >> vm->page_shift, npages); | ||
576 | region->region.slot = slot; | ||
577 | region->region.flags = flags; | ||
578 | region->region.guest_phys_addr = guest_paddr; | ||
579 | region->region.memory_size = npages * vm->page_size; | ||
580 | region->region.userspace_addr = (uintptr_t) region->host_mem; | ||
581 | ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); | ||
582 | TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n" | ||
583 | " rc: %i errno: %i\n" | ||
584 | " slot: %u flags: 0x%x\n" | ||
585 | " guest_phys_addr: 0x%lx size: 0x%lx", | ||
586 | ret, errno, slot, flags, | ||
587 | guest_paddr, (uint64_t) region->region.memory_size); | ||
588 | |||
589 | /* Add to linked-list of memory regions. */ | ||
590 | if (vm->userspace_mem_region_head) | ||
591 | vm->userspace_mem_region_head->prev = region; | ||
592 | region->next = vm->userspace_mem_region_head; | ||
593 | vm->userspace_mem_region_head = region; | ||
594 | } | ||
595 | |||
596 | /* Memslot to region | ||
597 | * | ||
598 | * Input Args: | ||
599 | * vm - Virtual Machine | ||
600 | * memslot - KVM memory slot ID | ||
601 | * | ||
602 | * Output Args: None | ||
603 | * | ||
604 | * Return: | ||
605 | * Pointer to memory region structure that describe memory region | ||
606 | * using kvm memory slot ID given by memslot. TEST_ASSERT failure | ||
607 | * on error (e.g. currently no memory region using memslot as a KVM | ||
608 | * memory slot ID). | ||
609 | */ | ||
610 | static struct userspace_mem_region *memslot2region(struct kvm_vm *vm, | ||
611 | uint32_t memslot) | ||
612 | { | ||
613 | struct userspace_mem_region *region; | ||
614 | |||
615 | for (region = vm->userspace_mem_region_head; region; | ||
616 | region = region->next) { | ||
617 | if (region->region.slot == memslot) | ||
618 | break; | ||
619 | } | ||
620 | if (region == NULL) { | ||
621 | fprintf(stderr, "No mem region with the requested slot found,\n" | ||
622 | " requested slot: %u\n", memslot); | ||
623 | fputs("---- vm dump ----\n", stderr); | ||
624 | vm_dump(stderr, vm, 2); | ||
625 | TEST_ASSERT(false, "Mem region not found"); | ||
626 | } | ||
627 | |||
628 | return region; | ||
629 | } | ||
630 | |||
631 | /* VM Memory Region Flags Set | ||
632 | * | ||
633 | * Input Args: | ||
634 | * vm - Virtual Machine | ||
635 | * flags - Starting guest physical address | ||
636 | * | ||
637 | * Output Args: None | ||
638 | * | ||
639 | * Return: None | ||
640 | * | ||
641 | * Sets the flags of the memory region specified by the value of slot, | ||
642 | * to the values given by flags. | ||
643 | */ | ||
644 | void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags) | ||
645 | { | ||
646 | int ret; | ||
647 | struct userspace_mem_region *region; | ||
648 | |||
649 | /* Locate memory region. */ | ||
650 | region = memslot2region(vm, slot); | ||
651 | |||
652 | region->region.flags = flags; | ||
653 | |||
654 | ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); | ||
655 | |||
656 | TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n" | ||
657 | " rc: %i errno: %i slot: %u flags: 0x%x", | ||
658 | ret, errno, slot, flags); | ||
659 | } | ||
660 | |||
661 | /* VCPU mmap Size | ||
662 | * | ||
663 | * Input Args: None | ||
664 | * | ||
665 | * Output Args: None | ||
666 | * | ||
667 | * Return: | ||
668 | * Size of VCPU state | ||
669 | * | ||
670 | * Returns the size of the structure pointed to by the return value | ||
671 | * of vcpu_state(). | ||
672 | */ | ||
673 | static int vcpu_mmap_sz(void) | ||
674 | { | ||
675 | int dev_fd, ret; | ||
676 | |||
677 | dev_fd = open(KVM_DEV_PATH, O_RDONLY); | ||
678 | TEST_ASSERT(dev_fd >= 0, "%s open %s failed, rc: %i errno: %i", | ||
679 | __func__, KVM_DEV_PATH, dev_fd, errno); | ||
680 | |||
681 | ret = ioctl(dev_fd, KVM_GET_VCPU_MMAP_SIZE, NULL); | ||
682 | TEST_ASSERT(ret >= sizeof(struct kvm_run), | ||
683 | "%s KVM_GET_VCPU_MMAP_SIZE ioctl failed, rc: %i errno: %i", | ||
684 | __func__, ret, errno); | ||
685 | |||
686 | close(dev_fd); | ||
687 | |||
688 | return ret; | ||
689 | } | ||
690 | |||
691 | /* VM VCPU Add | ||
692 | * | ||
693 | * Input Args: | ||
694 | * vm - Virtual Machine | ||
695 | * vcpuid - VCPU ID | ||
696 | * | ||
697 | * Output Args: None | ||
698 | * | ||
699 | * Return: None | ||
700 | * | ||
701 | * Creates and adds to the VM specified by vm and virtual CPU with | ||
702 | * the ID given by vcpuid. | ||
703 | */ | ||
704 | void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) | ||
705 | { | ||
706 | struct vcpu *vcpu; | ||
707 | |||
708 | /* Confirm a vcpu with the specified id doesn't already exist. */ | ||
709 | vcpu = vcpu_find(vm, vcpuid); | ||
710 | if (vcpu != NULL) | ||
711 | TEST_ASSERT(false, "vcpu with the specified id " | ||
712 | "already exists,\n" | ||
713 | " requested vcpuid: %u\n" | ||
714 | " existing vcpuid: %u state: %p", | ||
715 | vcpuid, vcpu->id, vcpu->state); | ||
716 | |||
717 | /* Allocate and initialize new vcpu structure. */ | ||
718 | vcpu = calloc(1, sizeof(*vcpu)); | ||
719 | TEST_ASSERT(vcpu != NULL, "Insufficient Memory"); | ||
720 | vcpu->id = vcpuid; | ||
721 | vcpu->fd = ioctl(vm->fd, KVM_CREATE_VCPU, vcpuid); | ||
722 | TEST_ASSERT(vcpu->fd >= 0, "KVM_CREATE_VCPU failed, rc: %i errno: %i", | ||
723 | vcpu->fd, errno); | ||
724 | |||
725 | TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->state), "vcpu mmap size " | ||
726 | "smaller than expected, vcpu_mmap_sz: %i expected_min: %zi", | ||
727 | vcpu_mmap_sz(), sizeof(*vcpu->state)); | ||
728 | vcpu->state = (struct kvm_run *) mmap(NULL, sizeof(*vcpu->state), | ||
729 | PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, 0); | ||
730 | TEST_ASSERT(vcpu->state != MAP_FAILED, "mmap vcpu_state failed, " | ||
731 | "vcpu id: %u errno: %i", vcpuid, errno); | ||
732 | |||
733 | /* Add to linked-list of VCPUs. */ | ||
734 | if (vm->vcpu_head) | ||
735 | vm->vcpu_head->prev = vcpu; | ||
736 | vcpu->next = vm->vcpu_head; | ||
737 | vm->vcpu_head = vcpu; | ||
738 | |||
739 | vcpu_setup(vm, vcpuid); | ||
740 | } | ||
741 | |||
742 | /* VM Virtual Address Unused Gap | ||
743 | * | ||
744 | * Input Args: | ||
745 | * vm - Virtual Machine | ||
746 | * sz - Size (bytes) | ||
747 | * vaddr_min - Minimum Virtual Address | ||
748 | * | ||
749 | * Output Args: None | ||
750 | * | ||
751 | * Return: | ||
752 | * Lowest virtual address at or below vaddr_min, with at least | ||
753 | * sz unused bytes. TEST_ASSERT failure if no area of at least | ||
754 | * size sz is available. | ||
755 | * | ||
756 | * Within the VM specified by vm, locates the lowest starting virtual | ||
757 | * address >= vaddr_min, that has at least sz unallocated bytes. A | ||
758 | * TEST_ASSERT failure occurs for invalid input or no area of at least | ||
759 | * sz unallocated bytes >= vaddr_min is available. | ||
760 | */ | ||
761 | static vm_vaddr_t vm_vaddr_unused_gap(struct kvm_vm *vm, size_t sz, | ||
762 | vm_vaddr_t vaddr_min) | ||
763 | { | ||
764 | uint64_t pages = (sz + vm->page_size - 1) >> vm->page_shift; | ||
765 | |||
766 | /* Determine lowest permitted virtual page index. */ | ||
767 | uint64_t pgidx_start = (vaddr_min + vm->page_size - 1) >> vm->page_shift; | ||
768 | if ((pgidx_start * vm->page_size) < vaddr_min) | ||
769 | goto no_va_found; | ||
770 | |||
771 | /* Loop over section with enough valid virtual page indexes. */ | ||
772 | if (!sparsebit_is_set_num(vm->vpages_valid, | ||
773 | pgidx_start, pages)) | ||
774 | pgidx_start = sparsebit_next_set_num(vm->vpages_valid, | ||
775 | pgidx_start, pages); | ||
776 | do { | ||
777 | /* | ||
778 | * Are there enough unused virtual pages available at | ||
779 | * the currently proposed starting virtual page index. | ||
780 | * If not, adjust proposed starting index to next | ||
781 | * possible. | ||
782 | */ | ||
783 | if (sparsebit_is_clear_num(vm->vpages_mapped, | ||
784 | pgidx_start, pages)) | ||
785 | goto va_found; | ||
786 | pgidx_start = sparsebit_next_clear_num(vm->vpages_mapped, | ||
787 | pgidx_start, pages); | ||
788 | if (pgidx_start == 0) | ||
789 | goto no_va_found; | ||
790 | |||
791 | /* | ||
792 | * If needed, adjust proposed starting virtual address, | ||
793 | * to next range of valid virtual addresses. | ||
794 | */ | ||
795 | if (!sparsebit_is_set_num(vm->vpages_valid, | ||
796 | pgidx_start, pages)) { | ||
797 | pgidx_start = sparsebit_next_set_num( | ||
798 | vm->vpages_valid, pgidx_start, pages); | ||
799 | if (pgidx_start == 0) | ||
800 | goto no_va_found; | ||
801 | } | ||
802 | } while (pgidx_start != 0); | ||
803 | |||
804 | no_va_found: | ||
805 | TEST_ASSERT(false, "No vaddr of specified pages available, " | ||
806 | "pages: 0x%lx", pages); | ||
807 | |||
808 | /* NOT REACHED */ | ||
809 | return -1; | ||
810 | |||
811 | va_found: | ||
812 | TEST_ASSERT(sparsebit_is_set_num(vm->vpages_valid, | ||
813 | pgidx_start, pages), | ||
814 | "Unexpected, invalid virtual page index range,\n" | ||
815 | " pgidx_start: 0x%lx\n" | ||
816 | " pages: 0x%lx", | ||
817 | pgidx_start, pages); | ||
818 | TEST_ASSERT(sparsebit_is_clear_num(vm->vpages_mapped, | ||
819 | pgidx_start, pages), | ||
820 | "Unexpected, pages already mapped,\n" | ||
821 | " pgidx_start: 0x%lx\n" | ||
822 | " pages: 0x%lx", | ||
823 | pgidx_start, pages); | ||
824 | |||
825 | return pgidx_start * vm->page_size; | ||
826 | } | ||
827 | |||
828 | /* VM Virtual Address Allocate | ||
829 | * | ||
830 | * Input Args: | ||
831 | * vm - Virtual Machine | ||
832 | * sz - Size in bytes | ||
833 | * vaddr_min - Minimum starting virtual address | ||
834 | * data_memslot - Memory region slot for data pages | ||
835 | * pgd_memslot - Memory region slot for new virtual translation tables | ||
836 | * | ||
837 | * Output Args: None | ||
838 | * | ||
839 | * Return: | ||
840 | * Starting guest virtual address | ||
841 | * | ||
842 | * Allocates at least sz bytes within the virtual address space of the vm | ||
843 | * given by vm. The allocated bytes are mapped to a virtual address >= | ||
844 | * the address given by vaddr_min. Note that each allocation uses a | ||
845 | * a unique set of pages, with the minimum real allocation being at least | ||
846 | * a page. | ||
847 | */ | ||
848 | vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, | ||
849 | uint32_t data_memslot, uint32_t pgd_memslot) | ||
850 | { | ||
851 | uint64_t pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0); | ||
852 | |||
853 | virt_pgd_alloc(vm, pgd_memslot); | ||
854 | |||
855 | /* Find an unused range of virtual page addresses of at least | ||
856 | * pages in length. | ||
857 | */ | ||
858 | vm_vaddr_t vaddr_start = vm_vaddr_unused_gap(vm, sz, vaddr_min); | ||
859 | |||
860 | /* Map the virtual pages. */ | ||
861 | for (vm_vaddr_t vaddr = vaddr_start; pages > 0; | ||
862 | pages--, vaddr += vm->page_size) { | ||
863 | vm_paddr_t paddr; | ||
864 | |||
865 | paddr = vm_phy_page_alloc(vm, KVM_UTIL_MIN_PADDR, data_memslot); | ||
866 | |||
867 | virt_pg_map(vm, vaddr, paddr, pgd_memslot); | ||
868 | |||
869 | sparsebit_set(vm->vpages_mapped, | ||
870 | vaddr >> vm->page_shift); | ||
871 | } | ||
872 | |||
873 | return vaddr_start; | ||
874 | } | ||
875 | |||
876 | /* Address VM Physical to Host Virtual | ||
877 | * | ||
878 | * Input Args: | ||
879 | * vm - Virtual Machine | ||
880 | * gpa - VM physical address | ||
881 | * | ||
882 | * Output Args: None | ||
883 | * | ||
884 | * Return: | ||
885 | * Equivalent host virtual address | ||
886 | * | ||
887 | * Locates the memory region containing the VM physical address given | ||
888 | * by gpa, within the VM given by vm. When found, the host virtual | ||
889 | * address providing the memory to the vm physical address is returned. | ||
890 | * A TEST_ASSERT failure occurs if no region containing gpa exists. | ||
891 | */ | ||
892 | void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa) | ||
893 | { | ||
894 | struct userspace_mem_region *region; | ||
895 | for (region = vm->userspace_mem_region_head; region; | ||
896 | region = region->next) { | ||
897 | if ((gpa >= region->region.guest_phys_addr) | ||
898 | && (gpa <= (region->region.guest_phys_addr | ||
899 | + region->region.memory_size - 1))) | ||
900 | return (void *) ((uintptr_t) region->host_mem | ||
901 | + (gpa - region->region.guest_phys_addr)); | ||
902 | } | ||
903 | |||
904 | TEST_ASSERT(false, "No vm physical memory at 0x%lx", gpa); | ||
905 | return NULL; | ||
906 | } | ||
907 | |||
908 | /* Address Host Virtual to VM Physical | ||
909 | * | ||
910 | * Input Args: | ||
911 | * vm - Virtual Machine | ||
912 | * hva - Host virtual address | ||
913 | * | ||
914 | * Output Args: None | ||
915 | * | ||
916 | * Return: | ||
917 | * Equivalent VM physical address | ||
918 | * | ||
919 | * Locates the memory region containing the host virtual address given | ||
920 | * by hva, within the VM given by vm. When found, the equivalent | ||
921 | * VM physical address is returned. A TEST_ASSERT failure occurs if no | ||
922 | * region containing hva exists. | ||
923 | */ | ||
924 | vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva) | ||
925 | { | ||
926 | struct userspace_mem_region *region; | ||
927 | for (region = vm->userspace_mem_region_head; region; | ||
928 | region = region->next) { | ||
929 | if ((hva >= region->host_mem) | ||
930 | && (hva <= (region->host_mem | ||
931 | + region->region.memory_size - 1))) | ||
932 | return (vm_paddr_t) ((uintptr_t) | ||
933 | region->region.guest_phys_addr | ||
934 | + (hva - (uintptr_t) region->host_mem)); | ||
935 | } | ||
936 | |||
937 | TEST_ASSERT(false, "No mapping to a guest physical address, " | ||
938 | "hva: %p", hva); | ||
939 | return -1; | ||
940 | } | ||
941 | |||
942 | /* VM Create IRQ Chip | ||
943 | * | ||
944 | * Input Args: | ||
945 | * vm - Virtual Machine | ||
946 | * | ||
947 | * Output Args: None | ||
948 | * | ||
949 | * Return: None | ||
950 | * | ||
951 | * Creates an interrupt controller chip for the VM specified by vm. | ||
952 | */ | ||
953 | void vm_create_irqchip(struct kvm_vm *vm) | ||
954 | { | ||
955 | int ret; | ||
956 | |||
957 | ret = ioctl(vm->fd, KVM_CREATE_IRQCHIP, 0); | ||
958 | TEST_ASSERT(ret == 0, "KVM_CREATE_IRQCHIP IOCTL failed, " | ||
959 | "rc: %i errno: %i", ret, errno); | ||
960 | } | ||
961 | |||
962 | /* VM VCPU State | ||
963 | * | ||
964 | * Input Args: | ||
965 | * vm - Virtual Machine | ||
966 | * vcpuid - VCPU ID | ||
967 | * | ||
968 | * Output Args: None | ||
969 | * | ||
970 | * Return: | ||
971 | * Pointer to structure that describes the state of the VCPU. | ||
972 | * | ||
973 | * Locates and returns a pointer to a structure that describes the | ||
974 | * state of the VCPU with the given vcpuid. | ||
975 | */ | ||
976 | struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid) | ||
977 | { | ||
978 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
979 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
980 | |||
981 | return vcpu->state; | ||
982 | } | ||
983 | |||
984 | /* VM VCPU Run | ||
985 | * | ||
986 | * Input Args: | ||
987 | * vm - Virtual Machine | ||
988 | * vcpuid - VCPU ID | ||
989 | * | ||
990 | * Output Args: None | ||
991 | * | ||
992 | * Return: None | ||
993 | * | ||
994 | * Switch to executing the code for the VCPU given by vcpuid, within the VM | ||
995 | * given by vm. | ||
996 | */ | ||
997 | void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) | ||
998 | { | ||
999 | int ret = _vcpu_run(vm, vcpuid); | ||
1000 | TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, " | ||
1001 | "rc: %i errno: %i", ret, errno); | ||
1002 | } | ||
1003 | |||
1004 | int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) | ||
1005 | { | ||
1006 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1007 | int rc; | ||
1008 | |||
1009 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1010 | do { | ||
1011 | rc = ioctl(vcpu->fd, KVM_RUN, NULL); | ||
1012 | } while (rc == -1 && errno == EINTR); | ||
1013 | return rc; | ||
1014 | } | ||
1015 | |||
1016 | /* VM VCPU Set MP State | ||
1017 | * | ||
1018 | * Input Args: | ||
1019 | * vm - Virtual Machine | ||
1020 | * vcpuid - VCPU ID | ||
1021 | * mp_state - mp_state to be set | ||
1022 | * | ||
1023 | * Output Args: None | ||
1024 | * | ||
1025 | * Return: None | ||
1026 | * | ||
1027 | * Sets the MP state of the VCPU given by vcpuid, to the state given | ||
1028 | * by mp_state. | ||
1029 | */ | ||
1030 | void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, | ||
1031 | struct kvm_mp_state *mp_state) | ||
1032 | { | ||
1033 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1034 | int ret; | ||
1035 | |||
1036 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1037 | |||
1038 | ret = ioctl(vcpu->fd, KVM_SET_MP_STATE, mp_state); | ||
1039 | TEST_ASSERT(ret == 0, "KVM_SET_MP_STATE IOCTL failed, " | ||
1040 | "rc: %i errno: %i", ret, errno); | ||
1041 | } | ||
1042 | |||
1043 | /* VM VCPU Regs Get | ||
1044 | * | ||
1045 | * Input Args: | ||
1046 | * vm - Virtual Machine | ||
1047 | * vcpuid - VCPU ID | ||
1048 | * | ||
1049 | * Output Args: | ||
1050 | * regs - current state of VCPU regs | ||
1051 | * | ||
1052 | * Return: None | ||
1053 | * | ||
1054 | * Obtains the current register state for the VCPU specified by vcpuid | ||
1055 | * and stores it at the location given by regs. | ||
1056 | */ | ||
1057 | void vcpu_regs_get(struct kvm_vm *vm, | ||
1058 | uint32_t vcpuid, struct kvm_regs *regs) | ||
1059 | { | ||
1060 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1061 | int ret; | ||
1062 | |||
1063 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1064 | |||
1065 | /* Get the regs. */ | ||
1066 | ret = ioctl(vcpu->fd, KVM_GET_REGS, regs); | ||
1067 | TEST_ASSERT(ret == 0, "KVM_GET_REGS failed, rc: %i errno: %i", | ||
1068 | ret, errno); | ||
1069 | } | ||
1070 | |||
1071 | /* VM VCPU Regs Set | ||
1072 | * | ||
1073 | * Input Args: | ||
1074 | * vm - Virtual Machine | ||
1075 | * vcpuid - VCPU ID | ||
1076 | * regs - Values to set VCPU regs to | ||
1077 | * | ||
1078 | * Output Args: None | ||
1079 | * | ||
1080 | * Return: None | ||
1081 | * | ||
1082 | * Sets the regs of the VCPU specified by vcpuid to the values | ||
1083 | * given by regs. | ||
1084 | */ | ||
1085 | void vcpu_regs_set(struct kvm_vm *vm, | ||
1086 | uint32_t vcpuid, struct kvm_regs *regs) | ||
1087 | { | ||
1088 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1089 | int ret; | ||
1090 | |||
1091 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1092 | |||
1093 | /* Set the regs. */ | ||
1094 | ret = ioctl(vcpu->fd, KVM_SET_REGS, regs); | ||
1095 | TEST_ASSERT(ret == 0, "KVM_SET_REGS failed, rc: %i errno: %i", | ||
1096 | ret, errno); | ||
1097 | } | ||
1098 | |||
1099 | void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, | ||
1100 | struct kvm_vcpu_events *events) | ||
1101 | { | ||
1102 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1103 | int ret; | ||
1104 | |||
1105 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1106 | |||
1107 | /* Get the regs. */ | ||
1108 | ret = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, events); | ||
1109 | TEST_ASSERT(ret == 0, "KVM_GET_VCPU_EVENTS, failed, rc: %i errno: %i", | ||
1110 | ret, errno); | ||
1111 | } | ||
1112 | |||
1113 | void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, | ||
1114 | struct kvm_vcpu_events *events) | ||
1115 | { | ||
1116 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1117 | int ret; | ||
1118 | |||
1119 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1120 | |||
1121 | /* Set the regs. */ | ||
1122 | ret = ioctl(vcpu->fd, KVM_SET_VCPU_EVENTS, events); | ||
1123 | TEST_ASSERT(ret == 0, "KVM_SET_VCPU_EVENTS, failed, rc: %i errno: %i", | ||
1124 | ret, errno); | ||
1125 | } | ||
1126 | |||
1127 | /* VM VCPU Args Set | ||
1128 | * | ||
1129 | * Input Args: | ||
1130 | * vm - Virtual Machine | ||
1131 | * vcpuid - VCPU ID | ||
1132 | * num - number of arguments | ||
1133 | * ... - arguments, each of type uint64_t | ||
1134 | * | ||
1135 | * Output Args: None | ||
1136 | * | ||
1137 | * Return: None | ||
1138 | * | ||
1139 | * Sets the first num function input arguments to the values | ||
1140 | * given as variable args. Each of the variable args is expected to | ||
1141 | * be of type uint64_t. | ||
1142 | */ | ||
1143 | void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) | ||
1144 | { | ||
1145 | va_list ap; | ||
1146 | struct kvm_regs regs; | ||
1147 | |||
1148 | TEST_ASSERT(num >= 1 && num <= 6, "Unsupported number of args,\n" | ||
1149 | " num: %u\n", | ||
1150 | num); | ||
1151 | |||
1152 | va_start(ap, num); | ||
1153 | vcpu_regs_get(vm, vcpuid, ®s); | ||
1154 | |||
1155 | if (num >= 1) | ||
1156 | regs.rdi = va_arg(ap, uint64_t); | ||
1157 | |||
1158 | if (num >= 2) | ||
1159 | regs.rsi = va_arg(ap, uint64_t); | ||
1160 | |||
1161 | if (num >= 3) | ||
1162 | regs.rdx = va_arg(ap, uint64_t); | ||
1163 | |||
1164 | if (num >= 4) | ||
1165 | regs.rcx = va_arg(ap, uint64_t); | ||
1166 | |||
1167 | if (num >= 5) | ||
1168 | regs.r8 = va_arg(ap, uint64_t); | ||
1169 | |||
1170 | if (num >= 6) | ||
1171 | regs.r9 = va_arg(ap, uint64_t); | ||
1172 | |||
1173 | vcpu_regs_set(vm, vcpuid, ®s); | ||
1174 | va_end(ap); | ||
1175 | } | ||
1176 | |||
1177 | /* VM VCPU System Regs Get | ||
1178 | * | ||
1179 | * Input Args: | ||
1180 | * vm - Virtual Machine | ||
1181 | * vcpuid - VCPU ID | ||
1182 | * | ||
1183 | * Output Args: | ||
1184 | * sregs - current state of VCPU system regs | ||
1185 | * | ||
1186 | * Return: None | ||
1187 | * | ||
1188 | * Obtains the current system register state for the VCPU specified by | ||
1189 | * vcpuid and stores it at the location given by sregs. | ||
1190 | */ | ||
1191 | void vcpu_sregs_get(struct kvm_vm *vm, | ||
1192 | uint32_t vcpuid, struct kvm_sregs *sregs) | ||
1193 | { | ||
1194 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1195 | int ret; | ||
1196 | |||
1197 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1198 | |||
1199 | /* Get the regs. */ | ||
1200 | /* Get the regs. */ | ||
1201 | ret = ioctl(vcpu->fd, KVM_GET_SREGS, sregs); | ||
1202 | TEST_ASSERT(ret == 0, "KVM_GET_SREGS failed, rc: %i errno: %i", | ||
1203 | ret, errno); | ||
1204 | } | ||
1205 | |||
1206 | /* VM VCPU System Regs Set | ||
1207 | * | ||
1208 | * Input Args: | ||
1209 | * vm - Virtual Machine | ||
1210 | * vcpuid - VCPU ID | ||
1211 | * sregs - Values to set VCPU system regs to | ||
1212 | * | ||
1213 | * Output Args: None | ||
1214 | * | ||
1215 | * Return: None | ||
1216 | * | ||
1217 | * Sets the system regs of the VCPU specified by vcpuid to the values | ||
1218 | * given by sregs. | ||
1219 | */ | ||
1220 | void vcpu_sregs_set(struct kvm_vm *vm, | ||
1221 | uint32_t vcpuid, struct kvm_sregs *sregs) | ||
1222 | { | ||
1223 | int ret = _vcpu_sregs_set(vm, vcpuid, sregs); | ||
1224 | TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, " | ||
1225 | "rc: %i errno: %i", ret, errno); | ||
1226 | } | ||
1227 | |||
1228 | int _vcpu_sregs_set(struct kvm_vm *vm, | ||
1229 | uint32_t vcpuid, struct kvm_sregs *sregs) | ||
1230 | { | ||
1231 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1232 | int ret; | ||
1233 | |||
1234 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1235 | |||
1236 | /* Get the regs. */ | ||
1237 | return ioctl(vcpu->fd, KVM_SET_SREGS, sregs); | ||
1238 | } | ||
1239 | |||
1240 | /* VCPU Ioctl | ||
1241 | * | ||
1242 | * Input Args: | ||
1243 | * vm - Virtual Machine | ||
1244 | * vcpuid - VCPU ID | ||
1245 | * cmd - Ioctl number | ||
1246 | * arg - Argument to pass to the ioctl | ||
1247 | * | ||
1248 | * Return: None | ||
1249 | * | ||
1250 | * Issues an arbitrary ioctl on a VCPU fd. | ||
1251 | */ | ||
1252 | void vcpu_ioctl(struct kvm_vm *vm, | ||
1253 | uint32_t vcpuid, unsigned long cmd, void *arg) | ||
1254 | { | ||
1255 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1256 | int ret; | ||
1257 | |||
1258 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1259 | |||
1260 | ret = ioctl(vcpu->fd, cmd, arg); | ||
1261 | TEST_ASSERT(ret == 0, "vcpu ioctl %lu failed, rc: %i errno: %i (%s)", | ||
1262 | cmd, ret, errno, strerror(errno)); | ||
1263 | } | ||
1264 | |||
1265 | /* VM Ioctl | ||
1266 | * | ||
1267 | * Input Args: | ||
1268 | * vm - Virtual Machine | ||
1269 | * cmd - Ioctl number | ||
1270 | * arg - Argument to pass to the ioctl | ||
1271 | * | ||
1272 | * Return: None | ||
1273 | * | ||
1274 | * Issues an arbitrary ioctl on a VM fd. | ||
1275 | */ | ||
1276 | void vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) | ||
1277 | { | ||
1278 | int ret; | ||
1279 | |||
1280 | ret = ioctl(vm->fd, cmd, arg); | ||
1281 | TEST_ASSERT(ret == 0, "vm ioctl %lu failed, rc: %i errno: %i (%s)", | ||
1282 | cmd, ret, errno, strerror(errno)); | ||
1283 | } | ||
1284 | |||
1285 | /* VM Dump | ||
1286 | * | ||
1287 | * Input Args: | ||
1288 | * vm - Virtual Machine | ||
1289 | * indent - Left margin indent amount | ||
1290 | * | ||
1291 | * Output Args: | ||
1292 | * stream - Output FILE stream | ||
1293 | * | ||
1294 | * Return: None | ||
1295 | * | ||
1296 | * Dumps the current state of the VM given by vm, to the FILE stream | ||
1297 | * given by stream. | ||
1298 | */ | ||
1299 | void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) | ||
1300 | { | ||
1301 | struct userspace_mem_region *region; | ||
1302 | struct vcpu *vcpu; | ||
1303 | |||
1304 | fprintf(stream, "%*smode: 0x%x\n", indent, "", vm->mode); | ||
1305 | fprintf(stream, "%*sfd: %i\n", indent, "", vm->fd); | ||
1306 | fprintf(stream, "%*spage_size: 0x%x\n", indent, "", vm->page_size); | ||
1307 | fprintf(stream, "%*sMem Regions:\n", indent, ""); | ||
1308 | for (region = vm->userspace_mem_region_head; region; | ||
1309 | region = region->next) { | ||
1310 | fprintf(stream, "%*sguest_phys: 0x%lx size: 0x%lx " | ||
1311 | "host_virt: %p\n", indent + 2, "", | ||
1312 | (uint64_t) region->region.guest_phys_addr, | ||
1313 | (uint64_t) region->region.memory_size, | ||
1314 | region->host_mem); | ||
1315 | fprintf(stream, "%*sunused_phy_pages: ", indent + 2, ""); | ||
1316 | sparsebit_dump(stream, region->unused_phy_pages, 0); | ||
1317 | } | ||
1318 | fprintf(stream, "%*sMapped Virtual Pages:\n", indent, ""); | ||
1319 | sparsebit_dump(stream, vm->vpages_mapped, indent + 2); | ||
1320 | fprintf(stream, "%*spgd_created: %u\n", indent, "", | ||
1321 | vm->pgd_created); | ||
1322 | if (vm->pgd_created) { | ||
1323 | fprintf(stream, "%*sVirtual Translation Tables:\n", | ||
1324 | indent + 2, ""); | ||
1325 | virt_dump(stream, vm, indent + 4); | ||
1326 | } | ||
1327 | fprintf(stream, "%*sVCPUs:\n", indent, ""); | ||
1328 | for (vcpu = vm->vcpu_head; vcpu; vcpu = vcpu->next) | ||
1329 | vcpu_dump(stream, vm, vcpu->id, indent + 2); | ||
1330 | } | ||
1331 | |||
1332 | /* VM VCPU Dump | ||
1333 | * | ||
1334 | * Input Args: | ||
1335 | * vm - Virtual Machine | ||
1336 | * vcpuid - VCPU ID | ||
1337 | * indent - Left margin indent amount | ||
1338 | * | ||
1339 | * Output Args: | ||
1340 | * stream - Output FILE stream | ||
1341 | * | ||
1342 | * Return: None | ||
1343 | * | ||
1344 | * Dumps the current state of the VCPU specified by vcpuid, within the VM | ||
1345 | * given by vm, to the FILE stream given by stream. | ||
1346 | */ | ||
1347 | void vcpu_dump(FILE *stream, struct kvm_vm *vm, | ||
1348 | uint32_t vcpuid, uint8_t indent) | ||
1349 | { | ||
1350 | struct kvm_regs regs; | ||
1351 | struct kvm_sregs sregs; | ||
1352 | |||
1353 | fprintf(stream, "%*scpuid: %u\n", indent, "", vcpuid); | ||
1354 | |||
1355 | fprintf(stream, "%*sregs:\n", indent + 2, ""); | ||
1356 | vcpu_regs_get(vm, vcpuid, ®s); | ||
1357 | regs_dump(stream, ®s, indent + 4); | ||
1358 | |||
1359 | fprintf(stream, "%*ssregs:\n", indent + 2, ""); | ||
1360 | vcpu_sregs_get(vm, vcpuid, &sregs); | ||
1361 | sregs_dump(stream, &sregs, indent + 4); | ||
1362 | } | ||
1363 | |||
1364 | /* Known KVM exit reasons */ | ||
1365 | static struct exit_reason { | ||
1366 | unsigned int reason; | ||
1367 | const char *name; | ||
1368 | } exit_reasons_known[] = { | ||
1369 | {KVM_EXIT_UNKNOWN, "UNKNOWN"}, | ||
1370 | {KVM_EXIT_EXCEPTION, "EXCEPTION"}, | ||
1371 | {KVM_EXIT_IO, "IO"}, | ||
1372 | {KVM_EXIT_HYPERCALL, "HYPERCALL"}, | ||
1373 | {KVM_EXIT_DEBUG, "DEBUG"}, | ||
1374 | {KVM_EXIT_HLT, "HLT"}, | ||
1375 | {KVM_EXIT_MMIO, "MMIO"}, | ||
1376 | {KVM_EXIT_IRQ_WINDOW_OPEN, "IRQ_WINDOW_OPEN"}, | ||
1377 | {KVM_EXIT_SHUTDOWN, "SHUTDOWN"}, | ||
1378 | {KVM_EXIT_FAIL_ENTRY, "FAIL_ENTRY"}, | ||
1379 | {KVM_EXIT_INTR, "INTR"}, | ||
1380 | {KVM_EXIT_SET_TPR, "SET_TPR"}, | ||
1381 | {KVM_EXIT_TPR_ACCESS, "TPR_ACCESS"}, | ||
1382 | {KVM_EXIT_S390_SIEIC, "S390_SIEIC"}, | ||
1383 | {KVM_EXIT_S390_RESET, "S390_RESET"}, | ||
1384 | {KVM_EXIT_DCR, "DCR"}, | ||
1385 | {KVM_EXIT_NMI, "NMI"}, | ||
1386 | {KVM_EXIT_INTERNAL_ERROR, "INTERNAL_ERROR"}, | ||
1387 | {KVM_EXIT_OSI, "OSI"}, | ||
1388 | {KVM_EXIT_PAPR_HCALL, "PAPR_HCALL"}, | ||
1389 | #ifdef KVM_EXIT_MEMORY_NOT_PRESENT | ||
1390 | {KVM_EXIT_MEMORY_NOT_PRESENT, "MEMORY_NOT_PRESENT"}, | ||
1391 | #endif | ||
1392 | }; | ||
1393 | |||
1394 | /* Exit Reason String | ||
1395 | * | ||
1396 | * Input Args: | ||
1397 | * exit_reason - Exit reason | ||
1398 | * | ||
1399 | * Output Args: None | ||
1400 | * | ||
1401 | * Return: | ||
1402 | * Constant string pointer describing the exit reason. | ||
1403 | * | ||
1404 | * Locates and returns a constant string that describes the KVM exit | ||
1405 | * reason given by exit_reason. If no such string is found, a constant | ||
1406 | * string of "Unknown" is returned. | ||
1407 | */ | ||
1408 | const char *exit_reason_str(unsigned int exit_reason) | ||
1409 | { | ||
1410 | unsigned int n1; | ||
1411 | |||
1412 | for (n1 = 0; n1 < ARRAY_SIZE(exit_reasons_known); n1++) { | ||
1413 | if (exit_reason == exit_reasons_known[n1].reason) | ||
1414 | return exit_reasons_known[n1].name; | ||
1415 | } | ||
1416 | |||
1417 | return "Unknown"; | ||
1418 | } | ||
1419 | |||
1420 | /* Physical Page Allocate | ||
1421 | * | ||
1422 | * Input Args: | ||
1423 | * vm - Virtual Machine | ||
1424 | * paddr_min - Physical address minimum | ||
1425 | * memslot - Memory region to allocate page from | ||
1426 | * | ||
1427 | * Output Args: None | ||
1428 | * | ||
1429 | * Return: | ||
1430 | * Starting physical address | ||
1431 | * | ||
1432 | * Within the VM specified by vm, locates an available physical page | ||
1433 | * at or above paddr_min. If found, the page is marked as in use | ||
1434 | * and its address is returned. A TEST_ASSERT failure occurs if no | ||
1435 | * page is available at or above paddr_min. | ||
1436 | */ | ||
1437 | vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, | ||
1438 | vm_paddr_t paddr_min, uint32_t memslot) | ||
1439 | { | ||
1440 | struct userspace_mem_region *region; | ||
1441 | sparsebit_idx_t pg; | ||
1442 | |||
1443 | TEST_ASSERT((paddr_min % vm->page_size) == 0, "Min physical address " | ||
1444 | "not divisible by page size.\n" | ||
1445 | " paddr_min: 0x%lx page_size: 0x%x", | ||
1446 | paddr_min, vm->page_size); | ||
1447 | |||
1448 | /* Locate memory region. */ | ||
1449 | region = memslot2region(vm, memslot); | ||
1450 | |||
1451 | /* Locate next available physical page at or above paddr_min. */ | ||
1452 | pg = paddr_min >> vm->page_shift; | ||
1453 | |||
1454 | if (!sparsebit_is_set(region->unused_phy_pages, pg)) { | ||
1455 | pg = sparsebit_next_set(region->unused_phy_pages, pg); | ||
1456 | if (pg == 0) { | ||
1457 | fprintf(stderr, "No guest physical page available, " | ||
1458 | "paddr_min: 0x%lx page_size: 0x%x memslot: %u", | ||
1459 | paddr_min, vm->page_size, memslot); | ||
1460 | fputs("---- vm dump ----\n", stderr); | ||
1461 | vm_dump(stderr, vm, 2); | ||
1462 | abort(); | ||
1463 | } | ||
1464 | } | ||
1465 | |||
1466 | /* Specify page as in use and return its address. */ | ||
1467 | sparsebit_clear(region->unused_phy_pages, pg); | ||
1468 | |||
1469 | return pg * vm->page_size; | ||
1470 | } | ||
1471 | |||
1472 | /* Address Guest Virtual to Host Virtual | ||
1473 | * | ||
1474 | * Input Args: | ||
1475 | * vm - Virtual Machine | ||
1476 | * gva - VM virtual address | ||
1477 | * | ||
1478 | * Output Args: None | ||
1479 | * | ||
1480 | * Return: | ||
1481 | * Equivalent host virtual address | ||
1482 | */ | ||
1483 | void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva) | ||
1484 | { | ||
1485 | return addr_gpa2hva(vm, addr_gva2gpa(vm, gva)); | ||
1486 | } | ||
diff --git a/tools/testing/selftests/kvm/lib/kvm_util_internal.h b/tools/testing/selftests/kvm/lib/kvm_util_internal.h new file mode 100644 index 000000000000..a0bd1980c81c --- /dev/null +++ b/tools/testing/selftests/kvm/lib/kvm_util_internal.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/lib/kvm_util.c | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | */ | ||
8 | |||
9 | #ifndef KVM_UTIL_INTERNAL_H | ||
10 | #define KVM_UTIL_INTERNAL_H 1 | ||
11 | |||
12 | #include "sparsebit.h" | ||
13 | |||
14 | #ifndef BITS_PER_BYTE | ||
15 | #define BITS_PER_BYTE 8 | ||
16 | #endif | ||
17 | |||
18 | #ifndef BITS_PER_LONG | ||
19 | #define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) | ||
20 | #endif | ||
21 | |||
22 | #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) | ||
23 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG) | ||
24 | |||
25 | /* Concrete definition of struct kvm_vm. */ | ||
26 | struct userspace_mem_region { | ||
27 | struct userspace_mem_region *next, *prev; | ||
28 | struct kvm_userspace_memory_region region; | ||
29 | struct sparsebit *unused_phy_pages; | ||
30 | int fd; | ||
31 | off_t offset; | ||
32 | void *host_mem; | ||
33 | void *mmap_start; | ||
34 | size_t mmap_size; | ||
35 | }; | ||
36 | |||
37 | struct vcpu { | ||
38 | struct vcpu *next, *prev; | ||
39 | uint32_t id; | ||
40 | int fd; | ||
41 | struct kvm_run *state; | ||
42 | }; | ||
43 | |||
44 | struct kvm_vm { | ||
45 | int mode; | ||
46 | int fd; | ||
47 | unsigned int page_size; | ||
48 | unsigned int page_shift; | ||
49 | uint64_t max_gfn; | ||
50 | struct vcpu *vcpu_head; | ||
51 | struct userspace_mem_region *userspace_mem_region_head; | ||
52 | struct sparsebit *vpages_valid; | ||
53 | struct sparsebit *vpages_mapped; | ||
54 | bool pgd_created; | ||
55 | vm_paddr_t pgd; | ||
56 | }; | ||
57 | |||
58 | struct vcpu *vcpu_find(struct kvm_vm *vm, | ||
59 | uint32_t vcpuid); | ||
60 | void vcpu_setup(struct kvm_vm *vm, int vcpuid); | ||
61 | void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); | ||
62 | void regs_dump(FILE *stream, struct kvm_regs *regs, | ||
63 | uint8_t indent); | ||
64 | void sregs_dump(FILE *stream, struct kvm_sregs *sregs, | ||
65 | uint8_t indent); | ||
66 | |||
67 | #endif | ||
diff --git a/tools/testing/selftests/kvm/lib/sparsebit.c b/tools/testing/selftests/kvm/lib/sparsebit.c new file mode 100644 index 000000000000..b132bc95d183 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/sparsebit.c | |||
@@ -0,0 +1,2087 @@ | |||
1 | /* | ||
2 | * Sparse bit array | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * Copyright (C) 2018, Red Hat, Inc. (code style cleanup and fuzzing driver) | ||
6 | * | ||
7 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
8 | * | ||
9 | * This library provides functions to support a memory efficient bit array, | ||
10 | * with an index size of 2^64. A sparsebit array is allocated through | ||
11 | * the use sparsebit_alloc() and free'd via sparsebit_free(), | ||
12 | * such as in the following: | ||
13 | * | ||
14 | * struct sparsebit *s; | ||
15 | * s = sparsebit_alloc(); | ||
16 | * sparsebit_free(&s); | ||
17 | * | ||
18 | * The struct sparsebit type resolves down to a struct sparsebit. | ||
19 | * Note that, sparsebit_free() takes a pointer to the sparsebit | ||
20 | * structure. This is so that sparsebit_free() is able to poison | ||
21 | * the pointer (e.g. set it to NULL) to the struct sparsebit before | ||
22 | * returning to the caller. | ||
23 | * | ||
24 | * Between the return of sparsebit_alloc() and the call of | ||
25 | * sparsebit_free(), there are multiple query and modifying operations | ||
26 | * that can be performed on the allocated sparsebit array. All of | ||
27 | * these operations take as a parameter the value returned from | ||
28 | * sparsebit_alloc() and most also take a bit index. Frequently | ||
29 | * used routines include: | ||
30 | * | ||
31 | * ---- Query Operations | ||
32 | * sparsebit_is_set(s, idx) | ||
33 | * sparsebit_is_clear(s, idx) | ||
34 | * sparsebit_any_set(s) | ||
35 | * sparsebit_first_set(s) | ||
36 | * sparsebit_next_set(s, prev_idx) | ||
37 | * | ||
38 | * ---- Modifying Operations | ||
39 | * sparsebit_set(s, idx) | ||
40 | * sparsebit_clear(s, idx) | ||
41 | * sparsebit_set_num(s, idx, num); | ||
42 | * sparsebit_clear_num(s, idx, num); | ||
43 | * | ||
44 | * A common operation, is to itterate over all the bits set in a test | ||
45 | * sparsebit array. This can be done via code with the following structure: | ||
46 | * | ||
47 | * sparsebit_idx_t idx; | ||
48 | * if (sparsebit_any_set(s)) { | ||
49 | * idx = sparsebit_first_set(s); | ||
50 | * do { | ||
51 | * ... | ||
52 | * idx = sparsebit_next_set(s, idx); | ||
53 | * } while (idx != 0); | ||
54 | * } | ||
55 | * | ||
56 | * The index of the first bit set needs to be obtained via | ||
57 | * sparsebit_first_set(), because sparsebit_next_set(), needs | ||
58 | * the index of the previously set. The sparsebit_idx_t type is | ||
59 | * unsigned, so there is no previous index before 0 that is available. | ||
60 | * Also, the call to sparsebit_first_set() is not made unless there | ||
61 | * is at least 1 bit in the array set. This is because sparsebit_first_set() | ||
62 | * aborts if sparsebit_first_set() is called with no bits set. | ||
63 | * It is the callers responsibility to assure that the | ||
64 | * sparsebit array has at least a single bit set before calling | ||
65 | * sparsebit_first_set(). | ||
66 | * | ||
67 | * ==== Implementation Overview ==== | ||
68 | * For the most part the internal implementation of sparsebit is | ||
69 | * opaque to the caller. One important implementation detail that the | ||
70 | * caller may need to be aware of is the spatial complexity of the | ||
71 | * implementation. This implementation of a sparsebit array is not | ||
72 | * only sparse, in that it uses memory proportional to the number of bits | ||
73 | * set. It is also efficient in memory usage when most of the bits are | ||
74 | * set. | ||
75 | * | ||
76 | * At a high-level the state of the bit settings are maintained through | ||
77 | * the use of a binary-search tree, where each node contains at least | ||
78 | * the following members: | ||
79 | * | ||
80 | * typedef uint64_t sparsebit_idx_t; | ||
81 | * typedef uint64_t sparsebit_num_t; | ||
82 | * | ||
83 | * sparsebit_idx_t idx; | ||
84 | * uint32_t mask; | ||
85 | * sparsebit_num_t num_after; | ||
86 | * | ||
87 | * The idx member contains the bit index of the first bit described by this | ||
88 | * node, while the mask member stores the setting of the first 32-bits. | ||
89 | * The setting of the bit at idx + n, where 0 <= n < 32, is located in the | ||
90 | * mask member at 1 << n. | ||
91 | * | ||
92 | * Nodes are sorted by idx and the bits described by two nodes will never | ||
93 | * overlap. The idx member is always aligned to the mask size, i.e. a | ||
94 | * multiple of 32. | ||
95 | * | ||
96 | * Beyond a typical implementation, the nodes in this implementation also | ||
97 | * contains a member named num_after. The num_after member holds the | ||
98 | * number of bits immediately after the mask bits that are contiguously set. | ||
99 | * The use of the num_after member allows this implementation to efficiently | ||
100 | * represent cases where most bits are set. For example, the case of all | ||
101 | * but the last two bits set, is represented by the following two nodes: | ||
102 | * | ||
103 | * node 0 - idx: 0x0 mask: 0xffffffff num_after: 0xffffffffffffffc0 | ||
104 | * node 1 - idx: 0xffffffffffffffe0 mask: 0x3fffffff num_after: 0 | ||
105 | * | ||
106 | * ==== Invariants ==== | ||
107 | * This implementation usses the following invariants: | ||
108 | * | ||
109 | * + Node are only used to represent bits that are set. | ||
110 | * Nodes with a mask of 0 and num_after of 0 are not allowed. | ||
111 | * | ||
112 | * + Sum of bits set in all the nodes is equal to the value of | ||
113 | * the struct sparsebit_pvt num_set member. | ||
114 | * | ||
115 | * + The setting of at least one bit is always described in a nodes | ||
116 | * mask (mask >= 1). | ||
117 | * | ||
118 | * + A node with all mask bits set only occurs when the last bit | ||
119 | * described by the previous node is not equal to this nodes | ||
120 | * starting index - 1. All such occurences of this condition are | ||
121 | * avoided by moving the setting of the nodes mask bits into | ||
122 | * the previous nodes num_after setting. | ||
123 | * | ||
124 | * + Node starting index is evenly divisible by the number of bits | ||
125 | * within a nodes mask member. | ||
126 | * | ||
127 | * + Nodes never represent a range of bits that wrap around the | ||
128 | * highest supported index. | ||
129 | * | ||
130 | * (idx + MASK_BITS + num_after - 1) <= ((sparsebit_idx_t) 0) - 1) | ||
131 | * | ||
132 | * As a consequence of the above, the num_after member of a node | ||
133 | * will always be <=: | ||
134 | * | ||
135 | * maximum_index - nodes_starting_index - number_of_mask_bits | ||
136 | * | ||
137 | * + Nodes within the binary search tree are sorted based on each | ||
138 | * nodes starting index. | ||
139 | * | ||
140 | * + The range of bits described by any two nodes do not overlap. The | ||
141 | * range of bits described by a single node is: | ||
142 | * | ||
143 | * start: node->idx | ||
144 | * end (inclusive): node->idx + MASK_BITS + node->num_after - 1; | ||
145 | * | ||
146 | * Note, at times these invariants are temporarily violated for a | ||
147 | * specific portion of the code. For example, when setting a mask | ||
148 | * bit, there is a small delay between when the mask bit is set and the | ||
149 | * value in the struct sparsebit_pvt num_set member is updated. Other | ||
150 | * temporary violations occur when node_split() is called with a specified | ||
151 | * index and assures that a node where its mask represents the bit | ||
152 | * at the specified index exists. At times to do this node_split() | ||
153 | * must split an existing node into two nodes or create a node that | ||
154 | * has no bits set. Such temporary violations must be corrected before | ||
155 | * returning to the caller. These corrections are typically performed | ||
156 | * by the local function node_reduce(). | ||
157 | */ | ||
158 | |||
159 | #include "test_util.h" | ||
160 | #include "sparsebit.h" | ||
161 | #include <limits.h> | ||
162 | #include <assert.h> | ||
163 | |||
164 | #define DUMP_LINE_MAX 100 /* Does not include indent amount */ | ||
165 | |||
166 | typedef uint32_t mask_t; | ||
167 | #define MASK_BITS (sizeof(mask_t) * CHAR_BIT) | ||
168 | |||
169 | struct node { | ||
170 | struct node *parent; | ||
171 | struct node *left; | ||
172 | struct node *right; | ||
173 | sparsebit_idx_t idx; /* index of least-significant bit in mask */ | ||
174 | sparsebit_num_t num_after; /* num contiguously set after mask */ | ||
175 | mask_t mask; | ||
176 | }; | ||
177 | |||
178 | struct sparsebit { | ||
179 | /* | ||
180 | * Points to root node of the binary search | ||
181 | * tree. Equal to NULL when no bits are set in | ||
182 | * the entire sparsebit array. | ||
183 | */ | ||
184 | struct node *root; | ||
185 | |||
186 | /* | ||
187 | * A redundant count of the total number of bits set. Used for | ||
188 | * diagnostic purposes and to change the time complexity of | ||
189 | * sparsebit_num_set() from O(n) to O(1). | ||
190 | * Note: Due to overflow, a value of 0 means none or all set. | ||
191 | */ | ||
192 | sparsebit_num_t num_set; | ||
193 | }; | ||
194 | |||
195 | /* Returns the number of set bits described by the settings | ||
196 | * of the node pointed to by nodep. | ||
197 | */ | ||
198 | static sparsebit_num_t node_num_set(struct node *nodep) | ||
199 | { | ||
200 | return nodep->num_after + __builtin_popcount(nodep->mask); | ||
201 | } | ||
202 | |||
203 | /* Returns a pointer to the node that describes the | ||
204 | * lowest bit index. | ||
205 | */ | ||
206 | static struct node *node_first(struct sparsebit *s) | ||
207 | { | ||
208 | struct node *nodep; | ||
209 | |||
210 | for (nodep = s->root; nodep && nodep->left; nodep = nodep->left) | ||
211 | ; | ||
212 | |||
213 | return nodep; | ||
214 | } | ||
215 | |||
216 | /* Returns a pointer to the node that describes the | ||
217 | * lowest bit index > the index of the node pointed to by np. | ||
218 | * Returns NULL if no node with a higher index exists. | ||
219 | */ | ||
220 | static struct node *node_next(struct sparsebit *s, struct node *np) | ||
221 | { | ||
222 | struct node *nodep = np; | ||
223 | |||
224 | /* | ||
225 | * If current node has a right child, next node is the left-most | ||
226 | * of the right child. | ||
227 | */ | ||
228 | if (nodep->right) { | ||
229 | for (nodep = nodep->right; nodep->left; nodep = nodep->left) | ||
230 | ; | ||
231 | return nodep; | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * No right child. Go up until node is left child of a parent. | ||
236 | * That parent is then the next node. | ||
237 | */ | ||
238 | while (nodep->parent && nodep == nodep->parent->right) | ||
239 | nodep = nodep->parent; | ||
240 | |||
241 | return nodep->parent; | ||
242 | } | ||
243 | |||
244 | /* Searches for and returns a pointer to the node that describes the | ||
245 | * highest index < the index of the node pointed to by np. | ||
246 | * Returns NULL if no node with a lower index exists. | ||
247 | */ | ||
248 | static struct node *node_prev(struct sparsebit *s, struct node *np) | ||
249 | { | ||
250 | struct node *nodep = np; | ||
251 | |||
252 | /* | ||
253 | * If current node has a left child, next node is the right-most | ||
254 | * of the left child. | ||
255 | */ | ||
256 | if (nodep->left) { | ||
257 | for (nodep = nodep->left; nodep->right; nodep = nodep->right) | ||
258 | ; | ||
259 | return (struct node *) nodep; | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * No left child. Go up until node is right child of a parent. | ||
264 | * That parent is then the next node. | ||
265 | */ | ||
266 | while (nodep->parent && nodep == nodep->parent->left) | ||
267 | nodep = nodep->parent; | ||
268 | |||
269 | return (struct node *) nodep->parent; | ||
270 | } | ||
271 | |||
272 | |||
273 | /* Allocates space to hold a copy of the node sub-tree pointed to by | ||
274 | * subtree and duplicates the bit settings to the newly allocated nodes. | ||
275 | * Returns the newly allocated copy of subtree. | ||
276 | */ | ||
277 | static struct node *node_copy_subtree(struct node *subtree) | ||
278 | { | ||
279 | struct node *root; | ||
280 | |||
281 | /* Duplicate the node at the root of the subtree */ | ||
282 | root = calloc(1, sizeof(*root)); | ||
283 | if (!root) { | ||
284 | perror("calloc"); | ||
285 | abort(); | ||
286 | } | ||
287 | |||
288 | root->idx = subtree->idx; | ||
289 | root->mask = subtree->mask; | ||
290 | root->num_after = subtree->num_after; | ||
291 | |||
292 | /* As needed, recursively duplicate the left and right subtrees */ | ||
293 | if (subtree->left) { | ||
294 | root->left = node_copy_subtree(subtree->left); | ||
295 | root->left->parent = root; | ||
296 | } | ||
297 | |||
298 | if (subtree->right) { | ||
299 | root->right = node_copy_subtree(subtree->right); | ||
300 | root->right->parent = root; | ||
301 | } | ||
302 | |||
303 | return root; | ||
304 | } | ||
305 | |||
306 | /* Searches for and returns a pointer to the node that describes the setting | ||
307 | * of the bit given by idx. A node describes the setting of a bit if its | ||
308 | * index is within the bits described by the mask bits or the number of | ||
309 | * contiguous bits set after the mask. Returns NULL if there is no such node. | ||
310 | */ | ||
311 | static struct node *node_find(struct sparsebit *s, sparsebit_idx_t idx) | ||
312 | { | ||
313 | struct node *nodep; | ||
314 | |||
315 | /* Find the node that describes the setting of the bit at idx */ | ||
316 | for (nodep = s->root; nodep; | ||
317 | nodep = nodep->idx > idx ? nodep->left : nodep->right) { | ||
318 | if (idx >= nodep->idx && | ||
319 | idx <= nodep->idx + MASK_BITS + nodep->num_after - 1) | ||
320 | break; | ||
321 | } | ||
322 | |||
323 | return nodep; | ||
324 | } | ||
325 | |||
326 | /* Entry Requirements: | ||
327 | * + A node that describes the setting of idx is not already present. | ||
328 | * | ||
329 | * Adds a new node to describe the setting of the bit at the index given | ||
330 | * by idx. Returns a pointer to the newly added node. | ||
331 | * | ||
332 | * TODO(lhuemill): Degenerate cases causes the tree to get unbalanced. | ||
333 | */ | ||
334 | static struct node *node_add(struct sparsebit *s, sparsebit_idx_t idx) | ||
335 | { | ||
336 | struct node *nodep, *parentp, *prev; | ||
337 | |||
338 | /* Allocate and initialize the new node. */ | ||
339 | nodep = calloc(1, sizeof(*nodep)); | ||
340 | if (!nodep) { | ||
341 | perror("calloc"); | ||
342 | abort(); | ||
343 | } | ||
344 | |||
345 | nodep->idx = idx & -MASK_BITS; | ||
346 | |||
347 | /* If no nodes, set it up as the root node. */ | ||
348 | if (!s->root) { | ||
349 | s->root = nodep; | ||
350 | return nodep; | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | * Find the parent where the new node should be attached | ||
355 | * and add the node there. | ||
356 | */ | ||
357 | parentp = s->root; | ||
358 | while (true) { | ||
359 | if (idx < parentp->idx) { | ||
360 | if (!parentp->left) { | ||
361 | parentp->left = nodep; | ||
362 | nodep->parent = parentp; | ||
363 | break; | ||
364 | } | ||
365 | parentp = parentp->left; | ||
366 | } else { | ||
367 | assert(idx > parentp->idx + MASK_BITS + parentp->num_after - 1); | ||
368 | if (!parentp->right) { | ||
369 | parentp->right = nodep; | ||
370 | nodep->parent = parentp; | ||
371 | break; | ||
372 | } | ||
373 | parentp = parentp->right; | ||
374 | } | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | * Does num_after bits of previous node overlap with the mask | ||
379 | * of the new node? If so set the bits in the new nodes mask | ||
380 | * and reduce the previous nodes num_after. | ||
381 | */ | ||
382 | prev = node_prev(s, nodep); | ||
383 | while (prev && prev->idx + MASK_BITS + prev->num_after - 1 >= nodep->idx) { | ||
384 | unsigned int n1 = (prev->idx + MASK_BITS + prev->num_after - 1) | ||
385 | - nodep->idx; | ||
386 | assert(prev->num_after > 0); | ||
387 | assert(n1 < MASK_BITS); | ||
388 | assert(!(nodep->mask & (1 << n1))); | ||
389 | nodep->mask |= (1 << n1); | ||
390 | prev->num_after--; | ||
391 | } | ||
392 | |||
393 | return nodep; | ||
394 | } | ||
395 | |||
396 | /* Returns whether all the bits in the sparsebit array are set. */ | ||
397 | bool sparsebit_all_set(struct sparsebit *s) | ||
398 | { | ||
399 | /* | ||
400 | * If any nodes there must be at least one bit set. Only case | ||
401 | * where a bit is set and total num set is 0, is when all bits | ||
402 | * are set. | ||
403 | */ | ||
404 | return s->root && s->num_set == 0; | ||
405 | } | ||
406 | |||
407 | /* Clears all bits described by the node pointed to by nodep, then | ||
408 | * removes the node. | ||
409 | */ | ||
410 | static void node_rm(struct sparsebit *s, struct node *nodep) | ||
411 | { | ||
412 | struct node *tmp; | ||
413 | sparsebit_num_t num_set; | ||
414 | |||
415 | num_set = node_num_set(nodep); | ||
416 | assert(s->num_set >= num_set || sparsebit_all_set(s)); | ||
417 | s->num_set -= node_num_set(nodep); | ||
418 | |||
419 | /* Have both left and right child */ | ||
420 | if (nodep->left && nodep->right) { | ||
421 | /* | ||
422 | * Move left children to the leftmost leaf node | ||
423 | * of the right child. | ||
424 | */ | ||
425 | for (tmp = nodep->right; tmp->left; tmp = tmp->left) | ||
426 | ; | ||
427 | tmp->left = nodep->left; | ||
428 | nodep->left = NULL; | ||
429 | tmp->left->parent = tmp; | ||
430 | } | ||
431 | |||
432 | /* Left only child */ | ||
433 | if (nodep->left) { | ||
434 | if (!nodep->parent) { | ||
435 | s->root = nodep->left; | ||
436 | nodep->left->parent = NULL; | ||
437 | } else { | ||
438 | nodep->left->parent = nodep->parent; | ||
439 | if (nodep == nodep->parent->left) | ||
440 | nodep->parent->left = nodep->left; | ||
441 | else { | ||
442 | assert(nodep == nodep->parent->right); | ||
443 | nodep->parent->right = nodep->left; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | nodep->parent = nodep->left = nodep->right = NULL; | ||
448 | free(nodep); | ||
449 | |||
450 | return; | ||
451 | } | ||
452 | |||
453 | |||
454 | /* Right only child */ | ||
455 | if (nodep->right) { | ||
456 | if (!nodep->parent) { | ||
457 | s->root = nodep->right; | ||
458 | nodep->right->parent = NULL; | ||
459 | } else { | ||
460 | nodep->right->parent = nodep->parent; | ||
461 | if (nodep == nodep->parent->left) | ||
462 | nodep->parent->left = nodep->right; | ||
463 | else { | ||
464 | assert(nodep == nodep->parent->right); | ||
465 | nodep->parent->right = nodep->right; | ||
466 | } | ||
467 | } | ||
468 | |||
469 | nodep->parent = nodep->left = nodep->right = NULL; | ||
470 | free(nodep); | ||
471 | |||
472 | return; | ||
473 | } | ||
474 | |||
475 | /* Leaf Node */ | ||
476 | if (!nodep->parent) { | ||
477 | s->root = NULL; | ||
478 | } else { | ||
479 | if (nodep->parent->left == nodep) | ||
480 | nodep->parent->left = NULL; | ||
481 | else { | ||
482 | assert(nodep == nodep->parent->right); | ||
483 | nodep->parent->right = NULL; | ||
484 | } | ||
485 | } | ||
486 | |||
487 | nodep->parent = nodep->left = nodep->right = NULL; | ||
488 | free(nodep); | ||
489 | |||
490 | return; | ||
491 | } | ||
492 | |||
493 | /* Splits the node containing the bit at idx so that there is a node | ||
494 | * that starts at the specified index. If no such node exists, a new | ||
495 | * node at the specified index is created. Returns the new node. | ||
496 | * | ||
497 | * idx must start of a mask boundary. | ||
498 | */ | ||
499 | static struct node *node_split(struct sparsebit *s, sparsebit_idx_t idx) | ||
500 | { | ||
501 | struct node *nodep1, *nodep2; | ||
502 | sparsebit_idx_t offset; | ||
503 | sparsebit_num_t orig_num_after; | ||
504 | |||
505 | assert(!(idx % MASK_BITS)); | ||
506 | |||
507 | /* | ||
508 | * Is there a node that describes the setting of idx? | ||
509 | * If not, add it. | ||
510 | */ | ||
511 | nodep1 = node_find(s, idx); | ||
512 | if (!nodep1) | ||
513 | return node_add(s, idx); | ||
514 | |||
515 | /* | ||
516 | * All done if the starting index of the node is where the | ||
517 | * split should occur. | ||
518 | */ | ||
519 | if (nodep1->idx == idx) | ||
520 | return nodep1; | ||
521 | |||
522 | /* | ||
523 | * Split point not at start of mask, so it must be part of | ||
524 | * bits described by num_after. | ||
525 | */ | ||
526 | |||
527 | /* | ||
528 | * Calculate offset within num_after for where the split is | ||
529 | * to occur. | ||
530 | */ | ||
531 | offset = idx - (nodep1->idx + MASK_BITS); | ||
532 | orig_num_after = nodep1->num_after; | ||
533 | |||
534 | /* | ||
535 | * Add a new node to describe the bits starting at | ||
536 | * the split point. | ||
537 | */ | ||
538 | nodep1->num_after = offset; | ||
539 | nodep2 = node_add(s, idx); | ||
540 | |||
541 | /* Move bits after the split point into the new node */ | ||
542 | nodep2->num_after = orig_num_after - offset; | ||
543 | if (nodep2->num_after >= MASK_BITS) { | ||
544 | nodep2->mask = ~(mask_t) 0; | ||
545 | nodep2->num_after -= MASK_BITS; | ||
546 | } else { | ||
547 | nodep2->mask = (1 << nodep2->num_after) - 1; | ||
548 | nodep2->num_after = 0; | ||
549 | } | ||
550 | |||
551 | return nodep2; | ||
552 | } | ||
553 | |||
554 | /* Iteratively reduces the node pointed to by nodep and its adjacent | ||
555 | * nodes into a more compact form. For example, a node with a mask with | ||
556 | * all bits set adjacent to a previous node, will get combined into a | ||
557 | * single node with an increased num_after setting. | ||
558 | * | ||
559 | * After each reduction, a further check is made to see if additional | ||
560 | * reductions are possible with the new previous and next nodes. Note, | ||
561 | * a search for a reduction is only done across the nodes nearest nodep | ||
562 | * and those that became part of a reduction. Reductions beyond nodep | ||
563 | * and the adjacent nodes that are reduced are not discovered. It is the | ||
564 | * responsibility of the caller to pass a nodep that is within one node | ||
565 | * of each possible reduction. | ||
566 | * | ||
567 | * This function does not fix the temporary violation of all invariants. | ||
568 | * For example it does not fix the case where the bit settings described | ||
569 | * by two or more nodes overlap. Such a violation introduces the potential | ||
570 | * complication of a bit setting for a specific index having different settings | ||
571 | * in different nodes. This would then introduce the further complication | ||
572 | * of which node has the correct setting of the bit and thus such conditions | ||
573 | * are not allowed. | ||
574 | * | ||
575 | * This function is designed to fix invariant violations that are introduced | ||
576 | * by node_split() and by changes to the nodes mask or num_after members. | ||
577 | * For example, when setting a bit within a nodes mask, the function that | ||
578 | * sets the bit doesn't have to worry about whether the setting of that | ||
579 | * bit caused the mask to have leading only or trailing only bits set. | ||
580 | * Instead, the function can call node_reduce(), with nodep equal to the | ||
581 | * node address that it set a mask bit in, and node_reduce() will notice | ||
582 | * the cases of leading or trailing only bits and that there is an | ||
583 | * adjacent node that the bit settings could be merged into. | ||
584 | * | ||
585 | * This implementation specifically detects and corrects violation of the | ||
586 | * following invariants: | ||
587 | * | ||
588 | * + Node are only used to represent bits that are set. | ||
589 | * Nodes with a mask of 0 and num_after of 0 are not allowed. | ||
590 | * | ||
591 | * + The setting of at least one bit is always described in a nodes | ||
592 | * mask (mask >= 1). | ||
593 | * | ||
594 | * + A node with all mask bits set only occurs when the last bit | ||
595 | * described by the previous node is not equal to this nodes | ||
596 | * starting index - 1. All such occurences of this condition are | ||
597 | * avoided by moving the setting of the nodes mask bits into | ||
598 | * the previous nodes num_after setting. | ||
599 | */ | ||
600 | static void node_reduce(struct sparsebit *s, struct node *nodep) | ||
601 | { | ||
602 | bool reduction_performed; | ||
603 | |||
604 | do { | ||
605 | reduction_performed = false; | ||
606 | struct node *prev, *next, *tmp; | ||
607 | |||
608 | /* 1) Potential reductions within the current node. */ | ||
609 | |||
610 | /* Nodes with all bits cleared may be removed. */ | ||
611 | if (nodep->mask == 0 && nodep->num_after == 0) { | ||
612 | /* | ||
613 | * About to remove the node pointed to by | ||
614 | * nodep, which normally would cause a problem | ||
615 | * for the next pass through the reduction loop, | ||
616 | * because the node at the starting point no longer | ||
617 | * exists. This potential problem is handled | ||
618 | * by first remembering the location of the next | ||
619 | * or previous nodes. Doesn't matter which, because | ||
620 | * once the node at nodep is removed, there will be | ||
621 | * no other nodes between prev and next. | ||
622 | * | ||
623 | * Note, the checks performed on nodep against both | ||
624 | * both prev and next both check for an adjacent | ||
625 | * node that can be reduced into a single node. As | ||
626 | * such, after removing the node at nodep, doesn't | ||
627 | * matter whether the nodep for the next pass | ||
628 | * through the loop is equal to the previous pass | ||
629 | * prev or next node. Either way, on the next pass | ||
630 | * the one not selected will become either the | ||
631 | * prev or next node. | ||
632 | */ | ||
633 | tmp = node_next(s, nodep); | ||
634 | if (!tmp) | ||
635 | tmp = node_prev(s, nodep); | ||
636 | |||
637 | node_rm(s, nodep); | ||
638 | nodep = NULL; | ||
639 | |||
640 | nodep = tmp; | ||
641 | reduction_performed = true; | ||
642 | continue; | ||
643 | } | ||
644 | |||
645 | /* | ||
646 | * When the mask is 0, can reduce the amount of num_after | ||
647 | * bits by moving the initial num_after bits into the mask. | ||
648 | */ | ||
649 | if (nodep->mask == 0) { | ||
650 | assert(nodep->num_after != 0); | ||
651 | assert(nodep->idx + MASK_BITS > nodep->idx); | ||
652 | |||
653 | nodep->idx += MASK_BITS; | ||
654 | |||
655 | if (nodep->num_after >= MASK_BITS) { | ||
656 | nodep->mask = ~0; | ||
657 | nodep->num_after -= MASK_BITS; | ||
658 | } else { | ||
659 | nodep->mask = (1u << nodep->num_after) - 1; | ||
660 | nodep->num_after = 0; | ||
661 | } | ||
662 | |||
663 | reduction_performed = true; | ||
664 | continue; | ||
665 | } | ||
666 | |||
667 | /* | ||
668 | * 2) Potential reductions between the current and | ||
669 | * previous nodes. | ||
670 | */ | ||
671 | prev = node_prev(s, nodep); | ||
672 | if (prev) { | ||
673 | sparsebit_idx_t prev_highest_bit; | ||
674 | |||
675 | /* Nodes with no bits set can be removed. */ | ||
676 | if (prev->mask == 0 && prev->num_after == 0) { | ||
677 | node_rm(s, prev); | ||
678 | |||
679 | reduction_performed = true; | ||
680 | continue; | ||
681 | } | ||
682 | |||
683 | /* | ||
684 | * All mask bits set and previous node has | ||
685 | * adjacent index. | ||
686 | */ | ||
687 | if (nodep->mask + 1 == 0 && | ||
688 | prev->idx + MASK_BITS == nodep->idx) { | ||
689 | prev->num_after += MASK_BITS + nodep->num_after; | ||
690 | nodep->mask = 0; | ||
691 | nodep->num_after = 0; | ||
692 | |||
693 | reduction_performed = true; | ||
694 | continue; | ||
695 | } | ||
696 | |||
697 | /* | ||
698 | * Is node adjacent to previous node and the node | ||
699 | * contains a single contiguous range of bits | ||
700 | * starting from the beginning of the mask? | ||
701 | */ | ||
702 | prev_highest_bit = prev->idx + MASK_BITS - 1 + prev->num_after; | ||
703 | if (prev_highest_bit + 1 == nodep->idx && | ||
704 | (nodep->mask | (nodep->mask >> 1)) == nodep->mask) { | ||
705 | /* | ||
706 | * How many contiguous bits are there? | ||
707 | * Is equal to the total number of set | ||
708 | * bits, due to an earlier check that | ||
709 | * there is a single contiguous range of | ||
710 | * set bits. | ||
711 | */ | ||
712 | unsigned int num_contiguous | ||
713 | = __builtin_popcount(nodep->mask); | ||
714 | assert((num_contiguous > 0) && | ||
715 | ((1ULL << num_contiguous) - 1) == nodep->mask); | ||
716 | |||
717 | prev->num_after += num_contiguous; | ||
718 | nodep->mask = 0; | ||
719 | |||
720 | /* | ||
721 | * For predictable performance, handle special | ||
722 | * case where all mask bits are set and there | ||
723 | * is a non-zero num_after setting. This code | ||
724 | * is functionally correct without the following | ||
725 | * conditionalized statements, but without them | ||
726 | * the value of num_after is only reduced by | ||
727 | * the number of mask bits per pass. There are | ||
728 | * cases where num_after can be close to 2^64. | ||
729 | * Without this code it could take nearly | ||
730 | * (2^64) / 32 passes to perform the full | ||
731 | * reduction. | ||
732 | */ | ||
733 | if (num_contiguous == MASK_BITS) { | ||
734 | prev->num_after += nodep->num_after; | ||
735 | nodep->num_after = 0; | ||
736 | } | ||
737 | |||
738 | reduction_performed = true; | ||
739 | continue; | ||
740 | } | ||
741 | } | ||
742 | |||
743 | /* | ||
744 | * 3) Potential reductions between the current and | ||
745 | * next nodes. | ||
746 | */ | ||
747 | next = node_next(s, nodep); | ||
748 | if (next) { | ||
749 | /* Nodes with no bits set can be removed. */ | ||
750 | if (next->mask == 0 && next->num_after == 0) { | ||
751 | node_rm(s, next); | ||
752 | reduction_performed = true; | ||
753 | continue; | ||
754 | } | ||
755 | |||
756 | /* | ||
757 | * Is next node index adjacent to current node | ||
758 | * and has a mask with all bits set? | ||
759 | */ | ||
760 | if (next->idx == nodep->idx + MASK_BITS + nodep->num_after && | ||
761 | next->mask == ~(mask_t) 0) { | ||
762 | nodep->num_after += MASK_BITS; | ||
763 | next->mask = 0; | ||
764 | nodep->num_after += next->num_after; | ||
765 | next->num_after = 0; | ||
766 | |||
767 | node_rm(s, next); | ||
768 | next = NULL; | ||
769 | |||
770 | reduction_performed = true; | ||
771 | continue; | ||
772 | } | ||
773 | } | ||
774 | } while (nodep && reduction_performed); | ||
775 | } | ||
776 | |||
777 | /* Returns whether the bit at the index given by idx, within the | ||
778 | * sparsebit array is set or not. | ||
779 | */ | ||
780 | bool sparsebit_is_set(struct sparsebit *s, sparsebit_idx_t idx) | ||
781 | { | ||
782 | struct node *nodep; | ||
783 | |||
784 | /* Find the node that describes the setting of the bit at idx */ | ||
785 | for (nodep = s->root; nodep; | ||
786 | nodep = nodep->idx > idx ? nodep->left : nodep->right) | ||
787 | if (idx >= nodep->idx && | ||
788 | idx <= nodep->idx + MASK_BITS + nodep->num_after - 1) | ||
789 | goto have_node; | ||
790 | |||
791 | return false; | ||
792 | |||
793 | have_node: | ||
794 | /* Bit is set if it is any of the bits described by num_after */ | ||
795 | if (nodep->num_after && idx >= nodep->idx + MASK_BITS) | ||
796 | return true; | ||
797 | |||
798 | /* Is the corresponding mask bit set */ | ||
799 | assert(idx >= nodep->idx && idx - nodep->idx < MASK_BITS); | ||
800 | return !!(nodep->mask & (1 << (idx - nodep->idx))); | ||
801 | } | ||
802 | |||
803 | /* Within the sparsebit array pointed to by s, sets the bit | ||
804 | * at the index given by idx. | ||
805 | */ | ||
806 | static void bit_set(struct sparsebit *s, sparsebit_idx_t idx) | ||
807 | { | ||
808 | struct node *nodep; | ||
809 | |||
810 | /* Skip bits that are already set */ | ||
811 | if (sparsebit_is_set(s, idx)) | ||
812 | return; | ||
813 | |||
814 | /* | ||
815 | * Get a node where the bit at idx is described by the mask. | ||
816 | * The node_split will also create a node, if there isn't | ||
817 | * already a node that describes the setting of bit. | ||
818 | */ | ||
819 | nodep = node_split(s, idx & -MASK_BITS); | ||
820 | |||
821 | /* Set the bit within the nodes mask */ | ||
822 | assert(idx >= nodep->idx && idx <= nodep->idx + MASK_BITS - 1); | ||
823 | assert(!(nodep->mask & (1 << (idx - nodep->idx)))); | ||
824 | nodep->mask |= 1 << (idx - nodep->idx); | ||
825 | s->num_set++; | ||
826 | |||
827 | node_reduce(s, nodep); | ||
828 | } | ||
829 | |||
830 | /* Within the sparsebit array pointed to by s, clears the bit | ||
831 | * at the index given by idx. | ||
832 | */ | ||
833 | static void bit_clear(struct sparsebit *s, sparsebit_idx_t idx) | ||
834 | { | ||
835 | struct node *nodep; | ||
836 | |||
837 | /* Skip bits that are already cleared */ | ||
838 | if (!sparsebit_is_set(s, idx)) | ||
839 | return; | ||
840 | |||
841 | /* Is there a node that describes the setting of this bit? */ | ||
842 | nodep = node_find(s, idx); | ||
843 | if (!nodep) | ||
844 | return; | ||
845 | |||
846 | /* | ||
847 | * If a num_after bit, split the node, so that the bit is | ||
848 | * part of a node mask. | ||
849 | */ | ||
850 | if (idx >= nodep->idx + MASK_BITS) | ||
851 | nodep = node_split(s, idx & -MASK_BITS); | ||
852 | |||
853 | /* | ||
854 | * After node_split above, bit at idx should be within the mask. | ||
855 | * Clear that bit. | ||
856 | */ | ||
857 | assert(idx >= nodep->idx && idx <= nodep->idx + MASK_BITS - 1); | ||
858 | assert(nodep->mask & (1 << (idx - nodep->idx))); | ||
859 | nodep->mask &= ~(1 << (idx - nodep->idx)); | ||
860 | assert(s->num_set > 0 || sparsebit_all_set(s)); | ||
861 | s->num_set--; | ||
862 | |||
863 | node_reduce(s, nodep); | ||
864 | } | ||
865 | |||
866 | /* Recursively dumps to the FILE stream given by stream the contents | ||
867 | * of the sub-tree of nodes pointed to by nodep. Each line of output | ||
868 | * is prefixed by the number of spaces given by indent. On each | ||
869 | * recursion, the indent amount is increased by 2. This causes nodes | ||
870 | * at each level deeper into the binary search tree to be displayed | ||
871 | * with a greater indent. | ||
872 | */ | ||
873 | static void dump_nodes(FILE *stream, struct node *nodep, | ||
874 | unsigned int indent) | ||
875 | { | ||
876 | char *node_type; | ||
877 | |||
878 | /* Dump contents of node */ | ||
879 | if (!nodep->parent) | ||
880 | node_type = "root"; | ||
881 | else if (nodep == nodep->parent->left) | ||
882 | node_type = "left"; | ||
883 | else { | ||
884 | assert(nodep == nodep->parent->right); | ||
885 | node_type = "right"; | ||
886 | } | ||
887 | fprintf(stream, "%*s---- %s nodep: %p\n", indent, "", node_type, nodep); | ||
888 | fprintf(stream, "%*s parent: %p left: %p right: %p\n", indent, "", | ||
889 | nodep->parent, nodep->left, nodep->right); | ||
890 | fprintf(stream, "%*s idx: 0x%lx mask: 0x%x num_after: 0x%lx\n", | ||
891 | indent, "", nodep->idx, nodep->mask, nodep->num_after); | ||
892 | |||
893 | /* If present, dump contents of left child nodes */ | ||
894 | if (nodep->left) | ||
895 | dump_nodes(stream, nodep->left, indent + 2); | ||
896 | |||
897 | /* If present, dump contents of right child nodes */ | ||
898 | if (nodep->right) | ||
899 | dump_nodes(stream, nodep->right, indent + 2); | ||
900 | } | ||
901 | |||
902 | static inline sparsebit_idx_t node_first_set(struct node *nodep, int start) | ||
903 | { | ||
904 | mask_t leading = (mask_t)1 << start; | ||
905 | int n1 = __builtin_ctz(nodep->mask & -leading); | ||
906 | |||
907 | return nodep->idx + n1; | ||
908 | } | ||
909 | |||
910 | static inline sparsebit_idx_t node_first_clear(struct node *nodep, int start) | ||
911 | { | ||
912 | mask_t leading = (mask_t)1 << start; | ||
913 | int n1 = __builtin_ctz(~nodep->mask & -leading); | ||
914 | |||
915 | return nodep->idx + n1; | ||
916 | } | ||
917 | |||
918 | /* Dumps to the FILE stream specified by stream, the implementation dependent | ||
919 | * internal state of s. Each line of output is prefixed with the number | ||
920 | * of spaces given by indent. The output is completely implementation | ||
921 | * dependent and subject to change. Output from this function should only | ||
922 | * be used for diagnostic purposes. For example, this function can be | ||
923 | * used by test cases after they detect an unexpected condition, as a means | ||
924 | * to capture diagnostic information. | ||
925 | */ | ||
926 | static void sparsebit_dump_internal(FILE *stream, struct sparsebit *s, | ||
927 | unsigned int indent) | ||
928 | { | ||
929 | /* Dump the contents of s */ | ||
930 | fprintf(stream, "%*sroot: %p\n", indent, "", s->root); | ||
931 | fprintf(stream, "%*snum_set: 0x%lx\n", indent, "", s->num_set); | ||
932 | |||
933 | if (s->root) | ||
934 | dump_nodes(stream, s->root, indent); | ||
935 | } | ||
936 | |||
937 | /* Allocates and returns a new sparsebit array. The initial state | ||
938 | * of the newly allocated sparsebit array has all bits cleared. | ||
939 | */ | ||
940 | struct sparsebit *sparsebit_alloc(void) | ||
941 | { | ||
942 | struct sparsebit *s; | ||
943 | |||
944 | /* Allocate top level structure. */ | ||
945 | s = calloc(1, sizeof(*s)); | ||
946 | if (!s) { | ||
947 | perror("calloc"); | ||
948 | abort(); | ||
949 | } | ||
950 | |||
951 | return s; | ||
952 | } | ||
953 | |||
954 | /* Frees the implementation dependent data for the sparsebit array | ||
955 | * pointed to by s and poisons the pointer to that data. | ||
956 | */ | ||
957 | void sparsebit_free(struct sparsebit **sbitp) | ||
958 | { | ||
959 | struct sparsebit *s = *sbitp; | ||
960 | |||
961 | if (!s) | ||
962 | return; | ||
963 | |||
964 | sparsebit_clear_all(s); | ||
965 | free(s); | ||
966 | *sbitp = NULL; | ||
967 | } | ||
968 | |||
969 | /* Makes a copy of the sparsebit array given by s, to the sparsebit | ||
970 | * array given by d. Note, d must have already been allocated via | ||
971 | * sparsebit_alloc(). It can though already have bits set, which | ||
972 | * if different from src will be cleared. | ||
973 | */ | ||
974 | void sparsebit_copy(struct sparsebit *d, struct sparsebit *s) | ||
975 | { | ||
976 | /* First clear any bits already set in the destination */ | ||
977 | sparsebit_clear_all(d); | ||
978 | |||
979 | if (s->root) { | ||
980 | d->root = node_copy_subtree(s->root); | ||
981 | d->num_set = s->num_set; | ||
982 | } | ||
983 | } | ||
984 | |||
985 | /* Returns whether num consecutive bits starting at idx are all set. */ | ||
986 | bool sparsebit_is_set_num(struct sparsebit *s, | ||
987 | sparsebit_idx_t idx, sparsebit_num_t num) | ||
988 | { | ||
989 | sparsebit_idx_t next_cleared; | ||
990 | |||
991 | assert(num > 0); | ||
992 | assert(idx + num - 1 >= idx); | ||
993 | |||
994 | /* With num > 0, the first bit must be set. */ | ||
995 | if (!sparsebit_is_set(s, idx)) | ||
996 | return false; | ||
997 | |||
998 | /* Find the next cleared bit */ | ||
999 | next_cleared = sparsebit_next_clear(s, idx); | ||
1000 | |||
1001 | /* | ||
1002 | * If no cleared bits beyond idx, then there are at least num | ||
1003 | * set bits. idx + num doesn't wrap. Otherwise check if | ||
1004 | * there are enough set bits between idx and the next cleared bit. | ||
1005 | */ | ||
1006 | return next_cleared == 0 || next_cleared - idx >= num; | ||
1007 | } | ||
1008 | |||
1009 | /* Returns whether the bit at the index given by idx. */ | ||
1010 | bool sparsebit_is_clear(struct sparsebit *s, | ||
1011 | sparsebit_idx_t idx) | ||
1012 | { | ||
1013 | return !sparsebit_is_set(s, idx); | ||
1014 | } | ||
1015 | |||
1016 | /* Returns whether num consecutive bits starting at idx are all cleared. */ | ||
1017 | bool sparsebit_is_clear_num(struct sparsebit *s, | ||
1018 | sparsebit_idx_t idx, sparsebit_num_t num) | ||
1019 | { | ||
1020 | sparsebit_idx_t next_set; | ||
1021 | |||
1022 | assert(num > 0); | ||
1023 | assert(idx + num - 1 >= idx); | ||
1024 | |||
1025 | /* With num > 0, the first bit must be cleared. */ | ||
1026 | if (!sparsebit_is_clear(s, idx)) | ||
1027 | return false; | ||
1028 | |||
1029 | /* Find the next set bit */ | ||
1030 | next_set = sparsebit_next_set(s, idx); | ||
1031 | |||
1032 | /* | ||
1033 | * If no set bits beyond idx, then there are at least num | ||
1034 | * cleared bits. idx + num doesn't wrap. Otherwise check if | ||
1035 | * there are enough cleared bits between idx and the next set bit. | ||
1036 | */ | ||
1037 | return next_set == 0 || next_set - idx >= num; | ||
1038 | } | ||
1039 | |||
1040 | /* Returns the total number of bits set. Note: 0 is also returned for | ||
1041 | * the case of all bits set. This is because with all bits set, there | ||
1042 | * is 1 additional bit set beyond what can be represented in the return | ||
1043 | * value. Use sparsebit_any_set(), instead of sparsebit_num_set() > 0, | ||
1044 | * to determine if the sparsebit array has any bits set. | ||
1045 | */ | ||
1046 | sparsebit_num_t sparsebit_num_set(struct sparsebit *s) | ||
1047 | { | ||
1048 | return s->num_set; | ||
1049 | } | ||
1050 | |||
1051 | /* Returns whether any bit is set in the sparsebit array. */ | ||
1052 | bool sparsebit_any_set(struct sparsebit *s) | ||
1053 | { | ||
1054 | /* | ||
1055 | * Nodes only describe set bits. If any nodes then there | ||
1056 | * is at least 1 bit set. | ||
1057 | */ | ||
1058 | if (!s->root) | ||
1059 | return false; | ||
1060 | |||
1061 | /* | ||
1062 | * Every node should have a non-zero mask. For now will | ||
1063 | * just assure that the root node has a non-zero mask, | ||
1064 | * which is a quick check that at least 1 bit is set. | ||
1065 | */ | ||
1066 | assert(s->root->mask != 0); | ||
1067 | assert(s->num_set > 0 || | ||
1068 | (s->root->num_after == ((sparsebit_num_t) 0) - MASK_BITS && | ||
1069 | s->root->mask == ~(mask_t) 0)); | ||
1070 | |||
1071 | return true; | ||
1072 | } | ||
1073 | |||
1074 | /* Returns whether all the bits in the sparsebit array are cleared. */ | ||
1075 | bool sparsebit_all_clear(struct sparsebit *s) | ||
1076 | { | ||
1077 | return !sparsebit_any_set(s); | ||
1078 | } | ||
1079 | |||
1080 | /* Returns whether all the bits in the sparsebit array are set. */ | ||
1081 | bool sparsebit_any_clear(struct sparsebit *s) | ||
1082 | { | ||
1083 | return !sparsebit_all_set(s); | ||
1084 | } | ||
1085 | |||
1086 | /* Returns the index of the first set bit. Abort if no bits are set. | ||
1087 | */ | ||
1088 | sparsebit_idx_t sparsebit_first_set(struct sparsebit *s) | ||
1089 | { | ||
1090 | struct node *nodep; | ||
1091 | |||
1092 | /* Validate at least 1 bit is set */ | ||
1093 | assert(sparsebit_any_set(s)); | ||
1094 | |||
1095 | nodep = node_first(s); | ||
1096 | return node_first_set(nodep, 0); | ||
1097 | } | ||
1098 | |||
1099 | /* Returns the index of the first cleared bit. Abort if | ||
1100 | * no bits are cleared. | ||
1101 | */ | ||
1102 | sparsebit_idx_t sparsebit_first_clear(struct sparsebit *s) | ||
1103 | { | ||
1104 | struct node *nodep1, *nodep2; | ||
1105 | |||
1106 | /* Validate at least 1 bit is cleared. */ | ||
1107 | assert(sparsebit_any_clear(s)); | ||
1108 | |||
1109 | /* If no nodes or first node index > 0 then lowest cleared is 0 */ | ||
1110 | nodep1 = node_first(s); | ||
1111 | if (!nodep1 || nodep1->idx > 0) | ||
1112 | return 0; | ||
1113 | |||
1114 | /* Does the mask in the first node contain any cleared bits. */ | ||
1115 | if (nodep1->mask != ~(mask_t) 0) | ||
1116 | return node_first_clear(nodep1, 0); | ||
1117 | |||
1118 | /* | ||
1119 | * All mask bits set in first node. If there isn't a second node | ||
1120 | * then the first cleared bit is the first bit after the bits | ||
1121 | * described by the first node. | ||
1122 | */ | ||
1123 | nodep2 = node_next(s, nodep1); | ||
1124 | if (!nodep2) { | ||
1125 | /* | ||
1126 | * No second node. First cleared bit is first bit beyond | ||
1127 | * bits described by first node. | ||
1128 | */ | ||
1129 | assert(nodep1->mask == ~(mask_t) 0); | ||
1130 | assert(nodep1->idx + MASK_BITS + nodep1->num_after != (sparsebit_idx_t) 0); | ||
1131 | return nodep1->idx + MASK_BITS + nodep1->num_after; | ||
1132 | } | ||
1133 | |||
1134 | /* | ||
1135 | * There is a second node. | ||
1136 | * If it is not adjacent to the first node, then there is a gap | ||
1137 | * of cleared bits between the nodes, and the first cleared bit | ||
1138 | * is the first bit within the gap. | ||
1139 | */ | ||
1140 | if (nodep1->idx + MASK_BITS + nodep1->num_after != nodep2->idx) | ||
1141 | return nodep1->idx + MASK_BITS + nodep1->num_after; | ||
1142 | |||
1143 | /* | ||
1144 | * Second node is adjacent to the first node. | ||
1145 | * Because it is adjacent, its mask should be non-zero. If all | ||
1146 | * its mask bits are set, then with it being adjacent, it should | ||
1147 | * have had the mask bits moved into the num_after setting of the | ||
1148 | * previous node. | ||
1149 | */ | ||
1150 | return node_first_clear(nodep2, 0); | ||
1151 | } | ||
1152 | |||
1153 | /* Returns index of next bit set within s after the index given by prev. | ||
1154 | * Returns 0 if there are no bits after prev that are set. | ||
1155 | */ | ||
1156 | sparsebit_idx_t sparsebit_next_set(struct sparsebit *s, | ||
1157 | sparsebit_idx_t prev) | ||
1158 | { | ||
1159 | sparsebit_idx_t lowest_possible = prev + 1; | ||
1160 | sparsebit_idx_t start; | ||
1161 | struct node *nodep; | ||
1162 | |||
1163 | /* A bit after the highest index can't be set. */ | ||
1164 | if (lowest_possible == 0) | ||
1165 | return 0; | ||
1166 | |||
1167 | /* | ||
1168 | * Find the leftmost 'candidate' overlapping or to the right | ||
1169 | * of lowest_possible. | ||
1170 | */ | ||
1171 | struct node *candidate = NULL; | ||
1172 | |||
1173 | /* True iff lowest_possible is within candidate */ | ||
1174 | bool contains = false; | ||
1175 | |||
1176 | /* | ||
1177 | * Find node that describes setting of bit at lowest_possible. | ||
1178 | * If such a node doesn't exist, find the node with the lowest | ||
1179 | * starting index that is > lowest_possible. | ||
1180 | */ | ||
1181 | for (nodep = s->root; nodep;) { | ||
1182 | if ((nodep->idx + MASK_BITS + nodep->num_after - 1) | ||
1183 | >= lowest_possible) { | ||
1184 | candidate = nodep; | ||
1185 | if (candidate->idx <= lowest_possible) { | ||
1186 | contains = true; | ||
1187 | break; | ||
1188 | } | ||
1189 | nodep = nodep->left; | ||
1190 | } else { | ||
1191 | nodep = nodep->right; | ||
1192 | } | ||
1193 | } | ||
1194 | if (!candidate) | ||
1195 | return 0; | ||
1196 | |||
1197 | assert(candidate->mask != 0); | ||
1198 | |||
1199 | /* Does the candidate node describe the setting of lowest_possible? */ | ||
1200 | if (!contains) { | ||
1201 | /* | ||
1202 | * Candidate doesn't describe setting of bit at lowest_possible. | ||
1203 | * Candidate points to the first node with a starting index | ||
1204 | * > lowest_possible. | ||
1205 | */ | ||
1206 | assert(candidate->idx > lowest_possible); | ||
1207 | |||
1208 | return node_first_set(candidate, 0); | ||
1209 | } | ||
1210 | |||
1211 | /* | ||
1212 | * Candidate describes setting of bit at lowest_possible. | ||
1213 | * Note: although the node describes the setting of the bit | ||
1214 | * at lowest_possible, its possible that its setting and the | ||
1215 | * setting of all latter bits described by this node are 0. | ||
1216 | * For now, just handle the cases where this node describes | ||
1217 | * a bit at or after an index of lowest_possible that is set. | ||
1218 | */ | ||
1219 | start = lowest_possible - candidate->idx; | ||
1220 | |||
1221 | if (start < MASK_BITS && candidate->mask >= (1 << start)) | ||
1222 | return node_first_set(candidate, start); | ||
1223 | |||
1224 | if (candidate->num_after) { | ||
1225 | sparsebit_idx_t first_num_after_idx = candidate->idx + MASK_BITS; | ||
1226 | |||
1227 | return lowest_possible < first_num_after_idx | ||
1228 | ? first_num_after_idx : lowest_possible; | ||
1229 | } | ||
1230 | |||
1231 | /* | ||
1232 | * Although candidate node describes setting of bit at | ||
1233 | * the index of lowest_possible, all bits at that index and | ||
1234 | * latter that are described by candidate are cleared. With | ||
1235 | * this, the next bit is the first bit in the next node, if | ||
1236 | * such a node exists. If a next node doesn't exist, then | ||
1237 | * there is no next set bit. | ||
1238 | */ | ||
1239 | candidate = node_next(s, candidate); | ||
1240 | if (!candidate) | ||
1241 | return 0; | ||
1242 | |||
1243 | return node_first_set(candidate, 0); | ||
1244 | } | ||
1245 | |||
1246 | /* Returns index of next bit cleared within s after the index given by prev. | ||
1247 | * Returns 0 if there are no bits after prev that are cleared. | ||
1248 | */ | ||
1249 | sparsebit_idx_t sparsebit_next_clear(struct sparsebit *s, | ||
1250 | sparsebit_idx_t prev) | ||
1251 | { | ||
1252 | sparsebit_idx_t lowest_possible = prev + 1; | ||
1253 | sparsebit_idx_t idx; | ||
1254 | struct node *nodep1, *nodep2; | ||
1255 | |||
1256 | /* A bit after the highest index can't be set. */ | ||
1257 | if (lowest_possible == 0) | ||
1258 | return 0; | ||
1259 | |||
1260 | /* | ||
1261 | * Does a node describing the setting of lowest_possible exist? | ||
1262 | * If not, the bit at lowest_possible is cleared. | ||
1263 | */ | ||
1264 | nodep1 = node_find(s, lowest_possible); | ||
1265 | if (!nodep1) | ||
1266 | return lowest_possible; | ||
1267 | |||
1268 | /* Does a mask bit in node 1 describe the next cleared bit. */ | ||
1269 | for (idx = lowest_possible - nodep1->idx; idx < MASK_BITS; idx++) | ||
1270 | if (!(nodep1->mask & (1 << idx))) | ||
1271 | return nodep1->idx + idx; | ||
1272 | |||
1273 | /* | ||
1274 | * Next cleared bit is not described by node 1. If there | ||
1275 | * isn't a next node, then next cleared bit is described | ||
1276 | * by bit after the bits described by the first node. | ||
1277 | */ | ||
1278 | nodep2 = node_next(s, nodep1); | ||
1279 | if (!nodep2) | ||
1280 | return nodep1->idx + MASK_BITS + nodep1->num_after; | ||
1281 | |||
1282 | /* | ||
1283 | * There is a second node. | ||
1284 | * If it is not adjacent to the first node, then there is a gap | ||
1285 | * of cleared bits between the nodes, and the next cleared bit | ||
1286 | * is the first bit within the gap. | ||
1287 | */ | ||
1288 | if (nodep1->idx + MASK_BITS + nodep1->num_after != nodep2->idx) | ||
1289 | return nodep1->idx + MASK_BITS + nodep1->num_after; | ||
1290 | |||
1291 | /* | ||
1292 | * Second node is adjacent to the first node. | ||
1293 | * Because it is adjacent, its mask should be non-zero. If all | ||
1294 | * its mask bits are set, then with it being adjacent, it should | ||
1295 | * have had the mask bits moved into the num_after setting of the | ||
1296 | * previous node. | ||
1297 | */ | ||
1298 | return node_first_clear(nodep2, 0); | ||
1299 | } | ||
1300 | |||
1301 | /* Starting with the index 1 greater than the index given by start, finds | ||
1302 | * and returns the index of the first sequence of num consecutively set | ||
1303 | * bits. Returns a value of 0 of no such sequence exists. | ||
1304 | */ | ||
1305 | sparsebit_idx_t sparsebit_next_set_num(struct sparsebit *s, | ||
1306 | sparsebit_idx_t start, sparsebit_num_t num) | ||
1307 | { | ||
1308 | sparsebit_idx_t idx; | ||
1309 | |||
1310 | assert(num >= 1); | ||
1311 | |||
1312 | for (idx = sparsebit_next_set(s, start); | ||
1313 | idx != 0 && idx + num - 1 >= idx; | ||
1314 | idx = sparsebit_next_set(s, idx)) { | ||
1315 | assert(sparsebit_is_set(s, idx)); | ||
1316 | |||
1317 | /* | ||
1318 | * Does the sequence of bits starting at idx consist of | ||
1319 | * num set bits? | ||
1320 | */ | ||
1321 | if (sparsebit_is_set_num(s, idx, num)) | ||
1322 | return idx; | ||
1323 | |||
1324 | /* | ||
1325 | * Sequence of set bits at idx isn't large enough. | ||
1326 | * Skip this entire sequence of set bits. | ||
1327 | */ | ||
1328 | idx = sparsebit_next_clear(s, idx); | ||
1329 | if (idx == 0) | ||
1330 | return 0; | ||
1331 | } | ||
1332 | |||
1333 | return 0; | ||
1334 | } | ||
1335 | |||
1336 | /* Starting with the index 1 greater than the index given by start, finds | ||
1337 | * and returns the index of the first sequence of num consecutively cleared | ||
1338 | * bits. Returns a value of 0 of no such sequence exists. | ||
1339 | */ | ||
1340 | sparsebit_idx_t sparsebit_next_clear_num(struct sparsebit *s, | ||
1341 | sparsebit_idx_t start, sparsebit_num_t num) | ||
1342 | { | ||
1343 | sparsebit_idx_t idx; | ||
1344 | |||
1345 | assert(num >= 1); | ||
1346 | |||
1347 | for (idx = sparsebit_next_clear(s, start); | ||
1348 | idx != 0 && idx + num - 1 >= idx; | ||
1349 | idx = sparsebit_next_clear(s, idx)) { | ||
1350 | assert(sparsebit_is_clear(s, idx)); | ||
1351 | |||
1352 | /* | ||
1353 | * Does the sequence of bits starting at idx consist of | ||
1354 | * num cleared bits? | ||
1355 | */ | ||
1356 | if (sparsebit_is_clear_num(s, idx, num)) | ||
1357 | return idx; | ||
1358 | |||
1359 | /* | ||
1360 | * Sequence of cleared bits at idx isn't large enough. | ||
1361 | * Skip this entire sequence of cleared bits. | ||
1362 | */ | ||
1363 | idx = sparsebit_next_set(s, idx); | ||
1364 | if (idx == 0) | ||
1365 | return 0; | ||
1366 | } | ||
1367 | |||
1368 | return 0; | ||
1369 | } | ||
1370 | |||
1371 | /* Sets the bits * in the inclusive range idx through idx + num - 1. */ | ||
1372 | void sparsebit_set_num(struct sparsebit *s, | ||
1373 | sparsebit_idx_t start, sparsebit_num_t num) | ||
1374 | { | ||
1375 | struct node *nodep, *next; | ||
1376 | unsigned int n1; | ||
1377 | sparsebit_idx_t idx; | ||
1378 | sparsebit_num_t n; | ||
1379 | sparsebit_idx_t middle_start, middle_end; | ||
1380 | |||
1381 | assert(num > 0); | ||
1382 | assert(start + num - 1 >= start); | ||
1383 | |||
1384 | /* | ||
1385 | * Leading - bits before first mask boundary. | ||
1386 | * | ||
1387 | * TODO(lhuemill): With some effort it may be possible to | ||
1388 | * replace the following loop with a sequential sequence | ||
1389 | * of statements. High level sequence would be: | ||
1390 | * | ||
1391 | * 1. Use node_split() to force node that describes setting | ||
1392 | * of idx to be within the mask portion of a node. | ||
1393 | * 2. Form mask of bits to be set. | ||
1394 | * 3. Determine number of mask bits already set in the node | ||
1395 | * and store in a local variable named num_already_set. | ||
1396 | * 4. Set the appropriate mask bits within the node. | ||
1397 | * 5. Increment struct sparsebit_pvt num_set member | ||
1398 | * by the number of bits that were actually set. | ||
1399 | * Exclude from the counts bits that were already set. | ||
1400 | * 6. Before returning to the caller, use node_reduce() to | ||
1401 | * handle the multiple corner cases that this method | ||
1402 | * introduces. | ||
1403 | */ | ||
1404 | for (idx = start, n = num; n > 0 && idx % MASK_BITS != 0; idx++, n--) | ||
1405 | bit_set(s, idx); | ||
1406 | |||
1407 | /* Middle - bits spanning one or more entire mask */ | ||
1408 | middle_start = idx; | ||
1409 | middle_end = middle_start + (n & -MASK_BITS) - 1; | ||
1410 | if (n >= MASK_BITS) { | ||
1411 | nodep = node_split(s, middle_start); | ||
1412 | |||
1413 | /* | ||
1414 | * As needed, split just after end of middle bits. | ||
1415 | * No split needed if end of middle bits is at highest | ||
1416 | * supported bit index. | ||
1417 | */ | ||
1418 | if (middle_end + 1 > middle_end) | ||
1419 | (void) node_split(s, middle_end + 1); | ||
1420 | |||
1421 | /* Delete nodes that only describe bits within the middle. */ | ||
1422 | for (next = node_next(s, nodep); | ||
1423 | next && (next->idx < middle_end); | ||
1424 | next = node_next(s, nodep)) { | ||
1425 | assert(next->idx + MASK_BITS + next->num_after - 1 <= middle_end); | ||
1426 | node_rm(s, next); | ||
1427 | next = NULL; | ||
1428 | } | ||
1429 | |||
1430 | /* As needed set each of the mask bits */ | ||
1431 | for (n1 = 0; n1 < MASK_BITS; n1++) { | ||
1432 | if (!(nodep->mask & (1 << n1))) { | ||
1433 | nodep->mask |= 1 << n1; | ||
1434 | s->num_set++; | ||
1435 | } | ||
1436 | } | ||
1437 | |||
1438 | s->num_set -= nodep->num_after; | ||
1439 | nodep->num_after = middle_end - middle_start + 1 - MASK_BITS; | ||
1440 | s->num_set += nodep->num_after; | ||
1441 | |||
1442 | node_reduce(s, nodep); | ||
1443 | } | ||
1444 | idx = middle_end + 1; | ||
1445 | n -= middle_end - middle_start + 1; | ||
1446 | |||
1447 | /* Trailing - bits at and beyond last mask boundary */ | ||
1448 | assert(n < MASK_BITS); | ||
1449 | for (; n > 0; idx++, n--) | ||
1450 | bit_set(s, idx); | ||
1451 | } | ||
1452 | |||
1453 | /* Clears the bits * in the inclusive range idx through idx + num - 1. */ | ||
1454 | void sparsebit_clear_num(struct sparsebit *s, | ||
1455 | sparsebit_idx_t start, sparsebit_num_t num) | ||
1456 | { | ||
1457 | struct node *nodep, *next; | ||
1458 | unsigned int n1; | ||
1459 | sparsebit_idx_t idx; | ||
1460 | sparsebit_num_t n; | ||
1461 | sparsebit_idx_t middle_start, middle_end; | ||
1462 | |||
1463 | assert(num > 0); | ||
1464 | assert(start + num - 1 >= start); | ||
1465 | |||
1466 | /* Leading - bits before first mask boundary */ | ||
1467 | for (idx = start, n = num; n > 0 && idx % MASK_BITS != 0; idx++, n--) | ||
1468 | bit_clear(s, idx); | ||
1469 | |||
1470 | /* Middle - bits spanning one or more entire mask */ | ||
1471 | middle_start = idx; | ||
1472 | middle_end = middle_start + (n & -MASK_BITS) - 1; | ||
1473 | if (n >= MASK_BITS) { | ||
1474 | nodep = node_split(s, middle_start); | ||
1475 | |||
1476 | /* | ||
1477 | * As needed, split just after end of middle bits. | ||
1478 | * No split needed if end of middle bits is at highest | ||
1479 | * supported bit index. | ||
1480 | */ | ||
1481 | if (middle_end + 1 > middle_end) | ||
1482 | (void) node_split(s, middle_end + 1); | ||
1483 | |||
1484 | /* Delete nodes that only describe bits within the middle. */ | ||
1485 | for (next = node_next(s, nodep); | ||
1486 | next && (next->idx < middle_end); | ||
1487 | next = node_next(s, nodep)) { | ||
1488 | assert(next->idx + MASK_BITS + next->num_after - 1 <= middle_end); | ||
1489 | node_rm(s, next); | ||
1490 | next = NULL; | ||
1491 | } | ||
1492 | |||
1493 | /* As needed clear each of the mask bits */ | ||
1494 | for (n1 = 0; n1 < MASK_BITS; n1++) { | ||
1495 | if (nodep->mask & (1 << n1)) { | ||
1496 | nodep->mask &= ~(1 << n1); | ||
1497 | s->num_set--; | ||
1498 | } | ||
1499 | } | ||
1500 | |||
1501 | /* Clear any bits described by num_after */ | ||
1502 | s->num_set -= nodep->num_after; | ||
1503 | nodep->num_after = 0; | ||
1504 | |||
1505 | /* | ||
1506 | * Delete the node that describes the beginning of | ||
1507 | * the middle bits and perform any allowed reductions | ||
1508 | * with the nodes prev or next of nodep. | ||
1509 | */ | ||
1510 | node_reduce(s, nodep); | ||
1511 | nodep = NULL; | ||
1512 | } | ||
1513 | idx = middle_end + 1; | ||
1514 | n -= middle_end - middle_start + 1; | ||
1515 | |||
1516 | /* Trailing - bits at and beyond last mask boundary */ | ||
1517 | assert(n < MASK_BITS); | ||
1518 | for (; n > 0; idx++, n--) | ||
1519 | bit_clear(s, idx); | ||
1520 | } | ||
1521 | |||
1522 | /* Sets the bit at the index given by idx. */ | ||
1523 | void sparsebit_set(struct sparsebit *s, sparsebit_idx_t idx) | ||
1524 | { | ||
1525 | sparsebit_set_num(s, idx, 1); | ||
1526 | } | ||
1527 | |||
1528 | /* Clears the bit at the index given by idx. */ | ||
1529 | void sparsebit_clear(struct sparsebit *s, sparsebit_idx_t idx) | ||
1530 | { | ||
1531 | sparsebit_clear_num(s, idx, 1); | ||
1532 | } | ||
1533 | |||
1534 | /* Sets the bits in the entire addressable range of the sparsebit array. */ | ||
1535 | void sparsebit_set_all(struct sparsebit *s) | ||
1536 | { | ||
1537 | sparsebit_set(s, 0); | ||
1538 | sparsebit_set_num(s, 1, ~(sparsebit_idx_t) 0); | ||
1539 | assert(sparsebit_all_set(s)); | ||
1540 | } | ||
1541 | |||
1542 | /* Clears the bits in the entire addressable range of the sparsebit array. */ | ||
1543 | void sparsebit_clear_all(struct sparsebit *s) | ||
1544 | { | ||
1545 | sparsebit_clear(s, 0); | ||
1546 | sparsebit_clear_num(s, 1, ~(sparsebit_idx_t) 0); | ||
1547 | assert(!sparsebit_any_set(s)); | ||
1548 | } | ||
1549 | |||
1550 | static size_t display_range(FILE *stream, sparsebit_idx_t low, | ||
1551 | sparsebit_idx_t high, bool prepend_comma_space) | ||
1552 | { | ||
1553 | char *fmt_str; | ||
1554 | size_t sz; | ||
1555 | |||
1556 | /* Determine the printf format string */ | ||
1557 | if (low == high) | ||
1558 | fmt_str = prepend_comma_space ? ", 0x%lx" : "0x%lx"; | ||
1559 | else | ||
1560 | fmt_str = prepend_comma_space ? ", 0x%lx:0x%lx" : "0x%lx:0x%lx"; | ||
1561 | |||
1562 | /* | ||
1563 | * When stream is NULL, just determine the size of what would | ||
1564 | * have been printed, else print the range. | ||
1565 | */ | ||
1566 | if (!stream) | ||
1567 | sz = snprintf(NULL, 0, fmt_str, low, high); | ||
1568 | else | ||
1569 | sz = fprintf(stream, fmt_str, low, high); | ||
1570 | |||
1571 | return sz; | ||
1572 | } | ||
1573 | |||
1574 | |||
1575 | /* Dumps to the FILE stream given by stream, the bit settings | ||
1576 | * of s. Each line of output is prefixed with the number of | ||
1577 | * spaces given by indent. The length of each line is implementation | ||
1578 | * dependent and does not depend on the indent amount. The following | ||
1579 | * is an example output of a sparsebit array that has bits: | ||
1580 | * | ||
1581 | * 0x5, 0x8, 0xa:0xe, 0x12 | ||
1582 | * | ||
1583 | * This corresponds to a sparsebit whose bits 5, 8, 10, 11, 12, 13, 14, 18 | ||
1584 | * are set. Note that a ':', instead of a '-' is used to specify a range of | ||
1585 | * contiguous bits. This is done because '-' is used to specify command-line | ||
1586 | * options, and sometimes ranges are specified as command-line arguments. | ||
1587 | */ | ||
1588 | void sparsebit_dump(FILE *stream, struct sparsebit *s, | ||
1589 | unsigned int indent) | ||
1590 | { | ||
1591 | size_t current_line_len = 0; | ||
1592 | size_t sz; | ||
1593 | struct node *nodep; | ||
1594 | |||
1595 | if (!sparsebit_any_set(s)) | ||
1596 | return; | ||
1597 | |||
1598 | /* Display initial indent */ | ||
1599 | fprintf(stream, "%*s", indent, ""); | ||
1600 | |||
1601 | /* For each node */ | ||
1602 | for (nodep = node_first(s); nodep; nodep = node_next(s, nodep)) { | ||
1603 | unsigned int n1; | ||
1604 | sparsebit_idx_t low, high; | ||
1605 | |||
1606 | /* For each group of bits in the mask */ | ||
1607 | for (n1 = 0; n1 < MASK_BITS; n1++) { | ||
1608 | if (nodep->mask & (1 << n1)) { | ||
1609 | low = high = nodep->idx + n1; | ||
1610 | |||
1611 | for (; n1 < MASK_BITS; n1++) { | ||
1612 | if (nodep->mask & (1 << n1)) | ||
1613 | high = nodep->idx + n1; | ||
1614 | else | ||
1615 | break; | ||
1616 | } | ||
1617 | |||
1618 | if ((n1 == MASK_BITS) && nodep->num_after) | ||
1619 | high += nodep->num_after; | ||
1620 | |||
1621 | /* | ||
1622 | * How much room will it take to display | ||
1623 | * this range. | ||
1624 | */ | ||
1625 | sz = display_range(NULL, low, high, | ||
1626 | current_line_len != 0); | ||
1627 | |||
1628 | /* | ||
1629 | * If there is not enough room, display | ||
1630 | * a newline plus the indent of the next | ||
1631 | * line. | ||
1632 | */ | ||
1633 | if (current_line_len + sz > DUMP_LINE_MAX) { | ||
1634 | fputs("\n", stream); | ||
1635 | fprintf(stream, "%*s", indent, ""); | ||
1636 | current_line_len = 0; | ||
1637 | } | ||
1638 | |||
1639 | /* Display the range */ | ||
1640 | sz = display_range(stream, low, high, | ||
1641 | current_line_len != 0); | ||
1642 | current_line_len += sz; | ||
1643 | } | ||
1644 | } | ||
1645 | |||
1646 | /* | ||
1647 | * If num_after and most significant-bit of mask is not | ||
1648 | * set, then still need to display a range for the bits | ||
1649 | * described by num_after. | ||
1650 | */ | ||
1651 | if (!(nodep->mask & (1 << (MASK_BITS - 1))) && nodep->num_after) { | ||
1652 | low = nodep->idx + MASK_BITS; | ||
1653 | high = nodep->idx + MASK_BITS + nodep->num_after - 1; | ||
1654 | |||
1655 | /* | ||
1656 | * How much room will it take to display | ||
1657 | * this range. | ||
1658 | */ | ||
1659 | sz = display_range(NULL, low, high, | ||
1660 | current_line_len != 0); | ||
1661 | |||
1662 | /* | ||
1663 | * If there is not enough room, display | ||
1664 | * a newline plus the indent of the next | ||
1665 | * line. | ||
1666 | */ | ||
1667 | if (current_line_len + sz > DUMP_LINE_MAX) { | ||
1668 | fputs("\n", stream); | ||
1669 | fprintf(stream, "%*s", indent, ""); | ||
1670 | current_line_len = 0; | ||
1671 | } | ||
1672 | |||
1673 | /* Display the range */ | ||
1674 | sz = display_range(stream, low, high, | ||
1675 | current_line_len != 0); | ||
1676 | current_line_len += sz; | ||
1677 | } | ||
1678 | } | ||
1679 | fputs("\n", stream); | ||
1680 | } | ||
1681 | |||
1682 | /* Validates the internal state of the sparsebit array given by | ||
1683 | * s. On error, diagnostic information is printed to stderr and | ||
1684 | * abort is called. | ||
1685 | */ | ||
1686 | void sparsebit_validate_internal(struct sparsebit *s) | ||
1687 | { | ||
1688 | bool error_detected = false; | ||
1689 | struct node *nodep, *prev = NULL; | ||
1690 | sparsebit_num_t total_bits_set = 0; | ||
1691 | unsigned int n1; | ||
1692 | |||
1693 | /* For each node */ | ||
1694 | for (nodep = node_first(s); nodep; | ||
1695 | prev = nodep, nodep = node_next(s, nodep)) { | ||
1696 | |||
1697 | /* | ||
1698 | * Increase total bits set by the number of bits set | ||
1699 | * in this node. | ||
1700 | */ | ||
1701 | for (n1 = 0; n1 < MASK_BITS; n1++) | ||
1702 | if (nodep->mask & (1 << n1)) | ||
1703 | total_bits_set++; | ||
1704 | |||
1705 | total_bits_set += nodep->num_after; | ||
1706 | |||
1707 | /* | ||
1708 | * Arbitrary choice as to whether a mask of 0 is allowed | ||
1709 | * or not. For diagnostic purposes it is beneficial to | ||
1710 | * have only one valid means to represent a set of bits. | ||
1711 | * To support this an arbitrary choice has been made | ||
1712 | * to not allow a mask of zero. | ||
1713 | */ | ||
1714 | if (nodep->mask == 0) { | ||
1715 | fprintf(stderr, "Node mask of zero, " | ||
1716 | "nodep: %p nodep->mask: 0x%x", | ||
1717 | nodep, nodep->mask); | ||
1718 | error_detected = true; | ||
1719 | break; | ||
1720 | } | ||
1721 | |||
1722 | /* | ||
1723 | * Validate num_after is not greater than the max index | ||
1724 | * - the number of mask bits. The num_after member | ||
1725 | * uses 0-based indexing and thus has no value that | ||
1726 | * represents all bits set. This limitation is handled | ||
1727 | * by requiring a non-zero mask. With a non-zero mask, | ||
1728 | * MASK_BITS worth of bits are described by the mask, | ||
1729 | * which makes the largest needed num_after equal to: | ||
1730 | * | ||
1731 | * (~(sparsebit_num_t) 0) - MASK_BITS + 1 | ||
1732 | */ | ||
1733 | if (nodep->num_after | ||
1734 | > (~(sparsebit_num_t) 0) - MASK_BITS + 1) { | ||
1735 | fprintf(stderr, "num_after too large, " | ||
1736 | "nodep: %p nodep->num_after: 0x%lx", | ||
1737 | nodep, nodep->num_after); | ||
1738 | error_detected = true; | ||
1739 | break; | ||
1740 | } | ||
1741 | |||
1742 | /* Validate node index is divisible by the mask size */ | ||
1743 | if (nodep->idx % MASK_BITS) { | ||
1744 | fprintf(stderr, "Node index not divisible by " | ||
1745 | "mask size,\n" | ||
1746 | " nodep: %p nodep->idx: 0x%lx " | ||
1747 | "MASK_BITS: %lu\n", | ||
1748 | nodep, nodep->idx, MASK_BITS); | ||
1749 | error_detected = true; | ||
1750 | break; | ||
1751 | } | ||
1752 | |||
1753 | /* | ||
1754 | * Validate bits described by node don't wrap beyond the | ||
1755 | * highest supported index. | ||
1756 | */ | ||
1757 | if ((nodep->idx + MASK_BITS + nodep->num_after - 1) < nodep->idx) { | ||
1758 | fprintf(stderr, "Bits described by node wrap " | ||
1759 | "beyond highest supported index,\n" | ||
1760 | " nodep: %p nodep->idx: 0x%lx\n" | ||
1761 | " MASK_BITS: %lu nodep->num_after: 0x%lx", | ||
1762 | nodep, nodep->idx, MASK_BITS, nodep->num_after); | ||
1763 | error_detected = true; | ||
1764 | break; | ||
1765 | } | ||
1766 | |||
1767 | /* Check parent pointers. */ | ||
1768 | if (nodep->left) { | ||
1769 | if (nodep->left->parent != nodep) { | ||
1770 | fprintf(stderr, "Left child parent pointer " | ||
1771 | "doesn't point to this node,\n" | ||
1772 | " nodep: %p nodep->left: %p " | ||
1773 | "nodep->left->parent: %p", | ||
1774 | nodep, nodep->left, | ||
1775 | nodep->left->parent); | ||
1776 | error_detected = true; | ||
1777 | break; | ||
1778 | } | ||
1779 | } | ||
1780 | |||
1781 | if (nodep->right) { | ||
1782 | if (nodep->right->parent != nodep) { | ||
1783 | fprintf(stderr, "Right child parent pointer " | ||
1784 | "doesn't point to this node,\n" | ||
1785 | " nodep: %p nodep->right: %p " | ||
1786 | "nodep->right->parent: %p", | ||
1787 | nodep, nodep->right, | ||
1788 | nodep->right->parent); | ||
1789 | error_detected = true; | ||
1790 | break; | ||
1791 | } | ||
1792 | } | ||
1793 | |||
1794 | if (!nodep->parent) { | ||
1795 | if (s->root != nodep) { | ||
1796 | fprintf(stderr, "Unexpected root node, " | ||
1797 | "s->root: %p nodep: %p", | ||
1798 | s->root, nodep); | ||
1799 | error_detected = true; | ||
1800 | break; | ||
1801 | } | ||
1802 | } | ||
1803 | |||
1804 | if (prev) { | ||
1805 | /* | ||
1806 | * Is index of previous node before index of | ||
1807 | * current node? | ||
1808 | */ | ||
1809 | if (prev->idx >= nodep->idx) { | ||
1810 | fprintf(stderr, "Previous node index " | ||
1811 | ">= current node index,\n" | ||
1812 | " prev: %p prev->idx: 0x%lx\n" | ||
1813 | " nodep: %p nodep->idx: 0x%lx", | ||
1814 | prev, prev->idx, nodep, nodep->idx); | ||
1815 | error_detected = true; | ||
1816 | break; | ||
1817 | } | ||
1818 | |||
1819 | /* | ||
1820 | * Nodes occur in asscending order, based on each | ||
1821 | * nodes starting index. | ||
1822 | */ | ||
1823 | if ((prev->idx + MASK_BITS + prev->num_after - 1) | ||
1824 | >= nodep->idx) { | ||
1825 | fprintf(stderr, "Previous node bit range " | ||
1826 | "overlap with current node bit range,\n" | ||
1827 | " prev: %p prev->idx: 0x%lx " | ||
1828 | "prev->num_after: 0x%lx\n" | ||
1829 | " nodep: %p nodep->idx: 0x%lx " | ||
1830 | "nodep->num_after: 0x%lx\n" | ||
1831 | " MASK_BITS: %lu", | ||
1832 | prev, prev->idx, prev->num_after, | ||
1833 | nodep, nodep->idx, nodep->num_after, | ||
1834 | MASK_BITS); | ||
1835 | error_detected = true; | ||
1836 | break; | ||
1837 | } | ||
1838 | |||
1839 | /* | ||
1840 | * When the node has all mask bits set, it shouldn't | ||
1841 | * be adjacent to the last bit described by the | ||
1842 | * previous node. | ||
1843 | */ | ||
1844 | if (nodep->mask == ~(mask_t) 0 && | ||
1845 | prev->idx + MASK_BITS + prev->num_after == nodep->idx) { | ||
1846 | fprintf(stderr, "Current node has mask with " | ||
1847 | "all bits set and is adjacent to the " | ||
1848 | "previous node,\n" | ||
1849 | " prev: %p prev->idx: 0x%lx " | ||
1850 | "prev->num_after: 0x%lx\n" | ||
1851 | " nodep: %p nodep->idx: 0x%lx " | ||
1852 | "nodep->num_after: 0x%lx\n" | ||
1853 | " MASK_BITS: %lu", | ||
1854 | prev, prev->idx, prev->num_after, | ||
1855 | nodep, nodep->idx, nodep->num_after, | ||
1856 | MASK_BITS); | ||
1857 | |||
1858 | error_detected = true; | ||
1859 | break; | ||
1860 | } | ||
1861 | } | ||
1862 | } | ||
1863 | |||
1864 | if (!error_detected) { | ||
1865 | /* | ||
1866 | * Is sum of bits set in each node equal to the count | ||
1867 | * of total bits set. | ||
1868 | */ | ||
1869 | if (s->num_set != total_bits_set) { | ||
1870 | fprintf(stderr, "Number of bits set missmatch,\n" | ||
1871 | " s->num_set: 0x%lx total_bits_set: 0x%lx", | ||
1872 | s->num_set, total_bits_set); | ||
1873 | |||
1874 | error_detected = true; | ||
1875 | } | ||
1876 | } | ||
1877 | |||
1878 | if (error_detected) { | ||
1879 | fputs(" dump_internal:\n", stderr); | ||
1880 | sparsebit_dump_internal(stderr, s, 4); | ||
1881 | abort(); | ||
1882 | } | ||
1883 | } | ||
1884 | |||
1885 | |||
1886 | #ifdef FUZZ | ||
1887 | /* A simple but effective fuzzing driver. Look for bugs with the help | ||
1888 | * of some invariants and of a trivial representation of sparsebit. | ||
1889 | * Just use 512 bytes of /dev/zero and /dev/urandom as inputs, and let | ||
1890 | * afl-fuzz do the magic. :) | ||
1891 | */ | ||
1892 | |||
1893 | #include <stdlib.h> | ||
1894 | #include <assert.h> | ||
1895 | |||
1896 | struct range { | ||
1897 | sparsebit_idx_t first, last; | ||
1898 | bool set; | ||
1899 | }; | ||
1900 | |||
1901 | struct sparsebit *s; | ||
1902 | struct range ranges[1000]; | ||
1903 | int num_ranges; | ||
1904 | |||
1905 | static bool get_value(sparsebit_idx_t idx) | ||
1906 | { | ||
1907 | int i; | ||
1908 | |||
1909 | for (i = num_ranges; --i >= 0; ) | ||
1910 | if (ranges[i].first <= idx && idx <= ranges[i].last) | ||
1911 | return ranges[i].set; | ||
1912 | |||
1913 | return false; | ||
1914 | } | ||
1915 | |||
1916 | static void operate(int code, sparsebit_idx_t first, sparsebit_idx_t last) | ||
1917 | { | ||
1918 | sparsebit_num_t num; | ||
1919 | sparsebit_idx_t next; | ||
1920 | |||
1921 | if (first < last) { | ||
1922 | num = last - first + 1; | ||
1923 | } else { | ||
1924 | num = first - last + 1; | ||
1925 | first = last; | ||
1926 | last = first + num - 1; | ||
1927 | } | ||
1928 | |||
1929 | switch (code) { | ||
1930 | case 0: | ||
1931 | sparsebit_set(s, first); | ||
1932 | assert(sparsebit_is_set(s, first)); | ||
1933 | assert(!sparsebit_is_clear(s, first)); | ||
1934 | assert(sparsebit_any_set(s)); | ||
1935 | assert(!sparsebit_all_clear(s)); | ||
1936 | if (get_value(first)) | ||
1937 | return; | ||
1938 | if (num_ranges == 1000) | ||
1939 | exit(0); | ||
1940 | ranges[num_ranges++] = (struct range) | ||
1941 | { .first = first, .last = first, .set = true }; | ||
1942 | break; | ||
1943 | case 1: | ||
1944 | sparsebit_clear(s, first); | ||
1945 | assert(!sparsebit_is_set(s, first)); | ||
1946 | assert(sparsebit_is_clear(s, first)); | ||
1947 | assert(sparsebit_any_clear(s)); | ||
1948 | assert(!sparsebit_all_set(s)); | ||
1949 | if (!get_value(first)) | ||
1950 | return; | ||
1951 | if (num_ranges == 1000) | ||
1952 | exit(0); | ||
1953 | ranges[num_ranges++] = (struct range) | ||
1954 | { .first = first, .last = first, .set = false }; | ||
1955 | break; | ||
1956 | case 2: | ||
1957 | assert(sparsebit_is_set(s, first) == get_value(first)); | ||
1958 | assert(sparsebit_is_clear(s, first) == !get_value(first)); | ||
1959 | break; | ||
1960 | case 3: | ||
1961 | if (sparsebit_any_set(s)) | ||
1962 | assert(get_value(sparsebit_first_set(s))); | ||
1963 | if (sparsebit_any_clear(s)) | ||
1964 | assert(!get_value(sparsebit_first_clear(s))); | ||
1965 | sparsebit_set_all(s); | ||
1966 | assert(!sparsebit_any_clear(s)); | ||
1967 | assert(sparsebit_all_set(s)); | ||
1968 | num_ranges = 0; | ||
1969 | ranges[num_ranges++] = (struct range) | ||
1970 | { .first = 0, .last = ~(sparsebit_idx_t)0, .set = true }; | ||
1971 | break; | ||
1972 | case 4: | ||
1973 | if (sparsebit_any_set(s)) | ||
1974 | assert(get_value(sparsebit_first_set(s))); | ||
1975 | if (sparsebit_any_clear(s)) | ||
1976 | assert(!get_value(sparsebit_first_clear(s))); | ||
1977 | sparsebit_clear_all(s); | ||
1978 | assert(!sparsebit_any_set(s)); | ||
1979 | assert(sparsebit_all_clear(s)); | ||
1980 | num_ranges = 0; | ||
1981 | break; | ||
1982 | case 5: | ||
1983 | next = sparsebit_next_set(s, first); | ||
1984 | assert(next == 0 || next > first); | ||
1985 | assert(next == 0 || get_value(next)); | ||
1986 | break; | ||
1987 | case 6: | ||
1988 | next = sparsebit_next_clear(s, first); | ||
1989 | assert(next == 0 || next > first); | ||
1990 | assert(next == 0 || !get_value(next)); | ||
1991 | break; | ||
1992 | case 7: | ||
1993 | next = sparsebit_next_clear(s, first); | ||
1994 | if (sparsebit_is_set_num(s, first, num)) { | ||
1995 | assert(next == 0 || next > last); | ||
1996 | if (first) | ||
1997 | next = sparsebit_next_set(s, first - 1); | ||
1998 | else if (sparsebit_any_set(s)) | ||
1999 | next = sparsebit_first_set(s); | ||
2000 | else | ||
2001 | return; | ||
2002 | assert(next == first); | ||
2003 | } else { | ||
2004 | assert(sparsebit_is_clear(s, first) || next <= last); | ||
2005 | } | ||
2006 | break; | ||
2007 | case 8: | ||
2008 | next = sparsebit_next_set(s, first); | ||
2009 | if (sparsebit_is_clear_num(s, first, num)) { | ||
2010 | assert(next == 0 || next > last); | ||
2011 | if (first) | ||
2012 | next = sparsebit_next_clear(s, first - 1); | ||
2013 | else if (sparsebit_any_clear(s)) | ||
2014 | next = sparsebit_first_clear(s); | ||
2015 | else | ||
2016 | return; | ||
2017 | assert(next == first); | ||
2018 | } else { | ||
2019 | assert(sparsebit_is_set(s, first) || next <= last); | ||
2020 | } | ||
2021 | break; | ||
2022 | case 9: | ||
2023 | sparsebit_set_num(s, first, num); | ||
2024 | assert(sparsebit_is_set_num(s, first, num)); | ||
2025 | assert(!sparsebit_is_clear_num(s, first, num)); | ||
2026 | assert(sparsebit_any_set(s)); | ||
2027 | assert(!sparsebit_all_clear(s)); | ||
2028 | if (num_ranges == 1000) | ||
2029 | exit(0); | ||
2030 | ranges[num_ranges++] = (struct range) | ||
2031 | { .first = first, .last = last, .set = true }; | ||
2032 | break; | ||
2033 | case 10: | ||
2034 | sparsebit_clear_num(s, first, num); | ||
2035 | assert(!sparsebit_is_set_num(s, first, num)); | ||
2036 | assert(sparsebit_is_clear_num(s, first, num)); | ||
2037 | assert(sparsebit_any_clear(s)); | ||
2038 | assert(!sparsebit_all_set(s)); | ||
2039 | if (num_ranges == 1000) | ||
2040 | exit(0); | ||
2041 | ranges[num_ranges++] = (struct range) | ||
2042 | { .first = first, .last = last, .set = false }; | ||
2043 | break; | ||
2044 | case 11: | ||
2045 | sparsebit_validate_internal(s); | ||
2046 | break; | ||
2047 | default: | ||
2048 | break; | ||
2049 | } | ||
2050 | } | ||
2051 | |||
2052 | unsigned char get8(void) | ||
2053 | { | ||
2054 | int ch; | ||
2055 | |||
2056 | ch = getchar(); | ||
2057 | if (ch == EOF) | ||
2058 | exit(0); | ||
2059 | return ch; | ||
2060 | } | ||
2061 | |||
2062 | uint64_t get64(void) | ||
2063 | { | ||
2064 | uint64_t x; | ||
2065 | |||
2066 | x = get8(); | ||
2067 | x = (x << 8) | get8(); | ||
2068 | x = (x << 8) | get8(); | ||
2069 | x = (x << 8) | get8(); | ||
2070 | x = (x << 8) | get8(); | ||
2071 | x = (x << 8) | get8(); | ||
2072 | x = (x << 8) | get8(); | ||
2073 | return (x << 8) | get8(); | ||
2074 | } | ||
2075 | |||
2076 | int main(void) | ||
2077 | { | ||
2078 | s = sparsebit_alloc(); | ||
2079 | for (;;) { | ||
2080 | uint8_t op = get8() & 0xf; | ||
2081 | uint64_t first = get64(); | ||
2082 | uint64_t last = get64(); | ||
2083 | |||
2084 | operate(op, first, last); | ||
2085 | } | ||
2086 | } | ||
2087 | #endif | ||
diff --git a/tools/testing/selftests/kvm/lib/vmx.c b/tools/testing/selftests/kvm/lib/vmx.c new file mode 100644 index 000000000000..0231bc0aae7b --- /dev/null +++ b/tools/testing/selftests/kvm/lib/vmx.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/lib/x86.c | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | */ | ||
8 | |||
9 | #define _GNU_SOURCE /* for program_invocation_name */ | ||
10 | |||
11 | #include "test_util.h" | ||
12 | #include "kvm_util.h" | ||
13 | #include "x86.h" | ||
14 | #include "vmx.h" | ||
15 | |||
16 | /* Create a default VM for VMX tests. | ||
17 | * | ||
18 | * Input Args: | ||
19 | * vcpuid - The id of the single VCPU to add to the VM. | ||
20 | * guest_code - The vCPU's entry point | ||
21 | * | ||
22 | * Output Args: None | ||
23 | * | ||
24 | * Return: | ||
25 | * Pointer to opaque structure that describes the created VM. | ||
26 | */ | ||
27 | struct kvm_vm * | ||
28 | vm_create_default_vmx(uint32_t vcpuid, vmx_guest_code_t guest_code) | ||
29 | { | ||
30 | struct kvm_cpuid2 *cpuid; | ||
31 | struct kvm_vm *vm; | ||
32 | vm_vaddr_t vmxon_vaddr; | ||
33 | vm_paddr_t vmxon_paddr; | ||
34 | vm_vaddr_t vmcs_vaddr; | ||
35 | vm_paddr_t vmcs_paddr; | ||
36 | |||
37 | vm = vm_create_default(vcpuid, (void *) guest_code); | ||
38 | |||
39 | /* Enable nesting in CPUID */ | ||
40 | vcpu_set_cpuid(vm, vcpuid, kvm_get_supported_cpuid()); | ||
41 | |||
42 | /* Setup of a region of guest memory for the vmxon region. */ | ||
43 | vmxon_vaddr = vm_vaddr_alloc(vm, getpagesize(), 0, 0, 0); | ||
44 | vmxon_paddr = addr_gva2gpa(vm, vmxon_vaddr); | ||
45 | |||
46 | /* Setup of a region of guest memory for a vmcs. */ | ||
47 | vmcs_vaddr = vm_vaddr_alloc(vm, getpagesize(), 0, 0, 0); | ||
48 | vmcs_paddr = addr_gva2gpa(vm, vmcs_vaddr); | ||
49 | |||
50 | vcpu_args_set(vm, vcpuid, 4, vmxon_vaddr, vmxon_paddr, vmcs_vaddr, | ||
51 | vmcs_paddr); | ||
52 | |||
53 | return vm; | ||
54 | } | ||
55 | |||
56 | void prepare_for_vmx_operation(void) | ||
57 | { | ||
58 | uint64_t feature_control; | ||
59 | uint64_t required; | ||
60 | unsigned long cr0; | ||
61 | unsigned long cr4; | ||
62 | |||
63 | /* | ||
64 | * Ensure bits in CR0 and CR4 are valid in VMX operation: | ||
65 | * - Bit X is 1 in _FIXED0: bit X is fixed to 1 in CRx. | ||
66 | * - Bit X is 0 in _FIXED1: bit X is fixed to 0 in CRx. | ||
67 | */ | ||
68 | __asm__ __volatile__("mov %%cr0, %0" : "=r"(cr0) : : "memory"); | ||
69 | cr0 &= rdmsr(MSR_IA32_VMX_CR0_FIXED1); | ||
70 | cr0 |= rdmsr(MSR_IA32_VMX_CR0_FIXED0); | ||
71 | __asm__ __volatile__("mov %0, %%cr0" : : "r"(cr0) : "memory"); | ||
72 | |||
73 | __asm__ __volatile__("mov %%cr4, %0" : "=r"(cr4) : : "memory"); | ||
74 | cr4 &= rdmsr(MSR_IA32_VMX_CR4_FIXED1); | ||
75 | cr4 |= rdmsr(MSR_IA32_VMX_CR4_FIXED0); | ||
76 | /* Enable VMX operation */ | ||
77 | cr4 |= X86_CR4_VMXE; | ||
78 | __asm__ __volatile__("mov %0, %%cr4" : : "r"(cr4) : "memory"); | ||
79 | |||
80 | /* | ||
81 | * Configure IA32_FEATURE_CONTROL MSR to allow VMXON: | ||
82 | * Bit 0: Lock bit. If clear, VMXON causes a #GP. | ||
83 | * Bit 2: Enables VMXON outside of SMX operation. If clear, VMXON | ||
84 | * outside of SMX causes a #GP. | ||
85 | */ | ||
86 | required = FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; | ||
87 | required |= FEATURE_CONTROL_LOCKED; | ||
88 | feature_control = rdmsr(MSR_IA32_FEATURE_CONTROL); | ||
89 | if ((feature_control & required) != required) | ||
90 | wrmsr(MSR_IA32_FEATURE_CONTROL, feature_control | required); | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * Initialize the control fields to the most basic settings possible. | ||
95 | */ | ||
96 | static inline void init_vmcs_control_fields(void) | ||
97 | { | ||
98 | vmwrite(VIRTUAL_PROCESSOR_ID, 0); | ||
99 | vmwrite(POSTED_INTR_NV, 0); | ||
100 | |||
101 | vmwrite(PIN_BASED_VM_EXEC_CONTROL, rdmsr(MSR_IA32_VMX_PINBASED_CTLS)); | ||
102 | vmwrite(CPU_BASED_VM_EXEC_CONTROL, rdmsr(MSR_IA32_VMX_PROCBASED_CTLS)); | ||
103 | vmwrite(EXCEPTION_BITMAP, 0); | ||
104 | vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0); | ||
105 | vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, -1); /* Never match */ | ||
106 | vmwrite(CR3_TARGET_COUNT, 0); | ||
107 | vmwrite(VM_EXIT_CONTROLS, rdmsr(MSR_IA32_VMX_EXIT_CTLS) | | ||
108 | VM_EXIT_HOST_ADDR_SPACE_SIZE); /* 64-bit host */ | ||
109 | vmwrite(VM_EXIT_MSR_STORE_COUNT, 0); | ||
110 | vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0); | ||
111 | vmwrite(VM_ENTRY_CONTROLS, rdmsr(MSR_IA32_VMX_ENTRY_CTLS) | | ||
112 | VM_ENTRY_IA32E_MODE); /* 64-bit guest */ | ||
113 | vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0); | ||
114 | vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0); | ||
115 | vmwrite(TPR_THRESHOLD, 0); | ||
116 | vmwrite(SECONDARY_VM_EXEC_CONTROL, 0); | ||
117 | |||
118 | vmwrite(CR0_GUEST_HOST_MASK, 0); | ||
119 | vmwrite(CR4_GUEST_HOST_MASK, 0); | ||
120 | vmwrite(CR0_READ_SHADOW, get_cr0()); | ||
121 | vmwrite(CR4_READ_SHADOW, get_cr4()); | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * Initialize the host state fields based on the current host state, with | ||
126 | * the exception of HOST_RSP and HOST_RIP, which should be set by vmlaunch | ||
127 | * or vmresume. | ||
128 | */ | ||
129 | static inline void init_vmcs_host_state(void) | ||
130 | { | ||
131 | uint32_t exit_controls = vmreadz(VM_EXIT_CONTROLS); | ||
132 | |||
133 | vmwrite(HOST_ES_SELECTOR, get_es()); | ||
134 | vmwrite(HOST_CS_SELECTOR, get_cs()); | ||
135 | vmwrite(HOST_SS_SELECTOR, get_ss()); | ||
136 | vmwrite(HOST_DS_SELECTOR, get_ds()); | ||
137 | vmwrite(HOST_FS_SELECTOR, get_fs()); | ||
138 | vmwrite(HOST_GS_SELECTOR, get_gs()); | ||
139 | vmwrite(HOST_TR_SELECTOR, get_tr()); | ||
140 | |||
141 | if (exit_controls & VM_EXIT_LOAD_IA32_PAT) | ||
142 | vmwrite(HOST_IA32_PAT, rdmsr(MSR_IA32_CR_PAT)); | ||
143 | if (exit_controls & VM_EXIT_LOAD_IA32_EFER) | ||
144 | vmwrite(HOST_IA32_EFER, rdmsr(MSR_EFER)); | ||
145 | if (exit_controls & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL) | ||
146 | vmwrite(HOST_IA32_PERF_GLOBAL_CTRL, | ||
147 | rdmsr(MSR_CORE_PERF_GLOBAL_CTRL)); | ||
148 | |||
149 | vmwrite(HOST_IA32_SYSENTER_CS, rdmsr(MSR_IA32_SYSENTER_CS)); | ||
150 | |||
151 | vmwrite(HOST_CR0, get_cr0()); | ||
152 | vmwrite(HOST_CR3, get_cr3()); | ||
153 | vmwrite(HOST_CR4, get_cr4()); | ||
154 | vmwrite(HOST_FS_BASE, rdmsr(MSR_FS_BASE)); | ||
155 | vmwrite(HOST_GS_BASE, rdmsr(MSR_GS_BASE)); | ||
156 | vmwrite(HOST_TR_BASE, | ||
157 | get_desc64_base((struct desc64 *)(get_gdt_base() + get_tr()))); | ||
158 | vmwrite(HOST_GDTR_BASE, get_gdt_base()); | ||
159 | vmwrite(HOST_IDTR_BASE, get_idt_base()); | ||
160 | vmwrite(HOST_IA32_SYSENTER_ESP, rdmsr(MSR_IA32_SYSENTER_ESP)); | ||
161 | vmwrite(HOST_IA32_SYSENTER_EIP, rdmsr(MSR_IA32_SYSENTER_EIP)); | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * Initialize the guest state fields essentially as a clone of | ||
166 | * the host state fields. Some host state fields have fixed | ||
167 | * values, and we set the corresponding guest state fields accordingly. | ||
168 | */ | ||
169 | static inline void init_vmcs_guest_state(void *rip, void *rsp) | ||
170 | { | ||
171 | vmwrite(GUEST_ES_SELECTOR, vmreadz(HOST_ES_SELECTOR)); | ||
172 | vmwrite(GUEST_CS_SELECTOR, vmreadz(HOST_CS_SELECTOR)); | ||
173 | vmwrite(GUEST_SS_SELECTOR, vmreadz(HOST_SS_SELECTOR)); | ||
174 | vmwrite(GUEST_DS_SELECTOR, vmreadz(HOST_DS_SELECTOR)); | ||
175 | vmwrite(GUEST_FS_SELECTOR, vmreadz(HOST_FS_SELECTOR)); | ||
176 | vmwrite(GUEST_GS_SELECTOR, vmreadz(HOST_GS_SELECTOR)); | ||
177 | vmwrite(GUEST_LDTR_SELECTOR, 0); | ||
178 | vmwrite(GUEST_TR_SELECTOR, vmreadz(HOST_TR_SELECTOR)); | ||
179 | vmwrite(GUEST_INTR_STATUS, 0); | ||
180 | vmwrite(GUEST_PML_INDEX, 0); | ||
181 | |||
182 | vmwrite(VMCS_LINK_POINTER, -1ll); | ||
183 | vmwrite(GUEST_IA32_DEBUGCTL, 0); | ||
184 | vmwrite(GUEST_IA32_PAT, vmreadz(HOST_IA32_PAT)); | ||
185 | vmwrite(GUEST_IA32_EFER, vmreadz(HOST_IA32_EFER)); | ||
186 | vmwrite(GUEST_IA32_PERF_GLOBAL_CTRL, | ||
187 | vmreadz(HOST_IA32_PERF_GLOBAL_CTRL)); | ||
188 | |||
189 | vmwrite(GUEST_ES_LIMIT, -1); | ||
190 | vmwrite(GUEST_CS_LIMIT, -1); | ||
191 | vmwrite(GUEST_SS_LIMIT, -1); | ||
192 | vmwrite(GUEST_DS_LIMIT, -1); | ||
193 | vmwrite(GUEST_FS_LIMIT, -1); | ||
194 | vmwrite(GUEST_GS_LIMIT, -1); | ||
195 | vmwrite(GUEST_LDTR_LIMIT, -1); | ||
196 | vmwrite(GUEST_TR_LIMIT, 0x67); | ||
197 | vmwrite(GUEST_GDTR_LIMIT, 0xffff); | ||
198 | vmwrite(GUEST_IDTR_LIMIT, 0xffff); | ||
199 | vmwrite(GUEST_ES_AR_BYTES, | ||
200 | vmreadz(GUEST_ES_SELECTOR) == 0 ? 0x10000 : 0xc093); | ||
201 | vmwrite(GUEST_CS_AR_BYTES, 0xa09b); | ||
202 | vmwrite(GUEST_SS_AR_BYTES, 0xc093); | ||
203 | vmwrite(GUEST_DS_AR_BYTES, | ||
204 | vmreadz(GUEST_DS_SELECTOR) == 0 ? 0x10000 : 0xc093); | ||
205 | vmwrite(GUEST_FS_AR_BYTES, | ||
206 | vmreadz(GUEST_FS_SELECTOR) == 0 ? 0x10000 : 0xc093); | ||
207 | vmwrite(GUEST_GS_AR_BYTES, | ||
208 | vmreadz(GUEST_GS_SELECTOR) == 0 ? 0x10000 : 0xc093); | ||
209 | vmwrite(GUEST_LDTR_AR_BYTES, 0x10000); | ||
210 | vmwrite(GUEST_TR_AR_BYTES, 0x8b); | ||
211 | vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0); | ||
212 | vmwrite(GUEST_ACTIVITY_STATE, 0); | ||
213 | vmwrite(GUEST_SYSENTER_CS, vmreadz(HOST_IA32_SYSENTER_CS)); | ||
214 | vmwrite(VMX_PREEMPTION_TIMER_VALUE, 0); | ||
215 | |||
216 | vmwrite(GUEST_CR0, vmreadz(HOST_CR0)); | ||
217 | vmwrite(GUEST_CR3, vmreadz(HOST_CR3)); | ||
218 | vmwrite(GUEST_CR4, vmreadz(HOST_CR4)); | ||
219 | vmwrite(GUEST_ES_BASE, 0); | ||
220 | vmwrite(GUEST_CS_BASE, 0); | ||
221 | vmwrite(GUEST_SS_BASE, 0); | ||
222 | vmwrite(GUEST_DS_BASE, 0); | ||
223 | vmwrite(GUEST_FS_BASE, vmreadz(HOST_FS_BASE)); | ||
224 | vmwrite(GUEST_GS_BASE, vmreadz(HOST_GS_BASE)); | ||
225 | vmwrite(GUEST_LDTR_BASE, 0); | ||
226 | vmwrite(GUEST_TR_BASE, vmreadz(HOST_TR_BASE)); | ||
227 | vmwrite(GUEST_GDTR_BASE, vmreadz(HOST_GDTR_BASE)); | ||
228 | vmwrite(GUEST_IDTR_BASE, vmreadz(HOST_IDTR_BASE)); | ||
229 | vmwrite(GUEST_DR7, 0x400); | ||
230 | vmwrite(GUEST_RSP, (uint64_t)rsp); | ||
231 | vmwrite(GUEST_RIP, (uint64_t)rip); | ||
232 | vmwrite(GUEST_RFLAGS, 2); | ||
233 | vmwrite(GUEST_PENDING_DBG_EXCEPTIONS, 0); | ||
234 | vmwrite(GUEST_SYSENTER_ESP, vmreadz(HOST_IA32_SYSENTER_ESP)); | ||
235 | vmwrite(GUEST_SYSENTER_EIP, vmreadz(HOST_IA32_SYSENTER_EIP)); | ||
236 | } | ||
237 | |||
238 | void prepare_vmcs(void *guest_rip, void *guest_rsp) | ||
239 | { | ||
240 | init_vmcs_control_fields(); | ||
241 | init_vmcs_host_state(); | ||
242 | init_vmcs_guest_state(guest_rip, guest_rsp); | ||
243 | } | ||
diff --git a/tools/testing/selftests/kvm/lib/x86.c b/tools/testing/selftests/kvm/lib/x86.c new file mode 100644 index 000000000000..2f17675f4275 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/x86.c | |||
@@ -0,0 +1,700 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/lib/x86.c | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | */ | ||
8 | |||
9 | #define _GNU_SOURCE /* for program_invocation_name */ | ||
10 | |||
11 | #include "test_util.h" | ||
12 | #include "kvm_util.h" | ||
13 | #include "kvm_util_internal.h" | ||
14 | #include "x86.h" | ||
15 | |||
16 | /* Minimum physical address used for virtual translation tables. */ | ||
17 | #define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 | ||
18 | |||
19 | /* Virtual translation table structure declarations */ | ||
20 | struct pageMapL4Entry { | ||
21 | uint64_t present:1; | ||
22 | uint64_t writable:1; | ||
23 | uint64_t user:1; | ||
24 | uint64_t write_through:1; | ||
25 | uint64_t cache_disable:1; | ||
26 | uint64_t accessed:1; | ||
27 | uint64_t ignored_06:1; | ||
28 | uint64_t page_size:1; | ||
29 | uint64_t ignored_11_08:4; | ||
30 | uint64_t address:40; | ||
31 | uint64_t ignored_62_52:11; | ||
32 | uint64_t execute_disable:1; | ||
33 | }; | ||
34 | |||
35 | struct pageDirectoryPointerEntry { | ||
36 | uint64_t present:1; | ||
37 | uint64_t writable:1; | ||
38 | uint64_t user:1; | ||
39 | uint64_t write_through:1; | ||
40 | uint64_t cache_disable:1; | ||
41 | uint64_t accessed:1; | ||
42 | uint64_t ignored_06:1; | ||
43 | uint64_t page_size:1; | ||
44 | uint64_t ignored_11_08:4; | ||
45 | uint64_t address:40; | ||
46 | uint64_t ignored_62_52:11; | ||
47 | uint64_t execute_disable:1; | ||
48 | }; | ||
49 | |||
50 | struct pageDirectoryEntry { | ||
51 | uint64_t present:1; | ||
52 | uint64_t writable:1; | ||
53 | uint64_t user:1; | ||
54 | uint64_t write_through:1; | ||
55 | uint64_t cache_disable:1; | ||
56 | uint64_t accessed:1; | ||
57 | uint64_t ignored_06:1; | ||
58 | uint64_t page_size:1; | ||
59 | uint64_t ignored_11_08:4; | ||
60 | uint64_t address:40; | ||
61 | uint64_t ignored_62_52:11; | ||
62 | uint64_t execute_disable:1; | ||
63 | }; | ||
64 | |||
65 | struct pageTableEntry { | ||
66 | uint64_t present:1; | ||
67 | uint64_t writable:1; | ||
68 | uint64_t user:1; | ||
69 | uint64_t write_through:1; | ||
70 | uint64_t cache_disable:1; | ||
71 | uint64_t accessed:1; | ||
72 | uint64_t dirty:1; | ||
73 | uint64_t reserved_07:1; | ||
74 | uint64_t global:1; | ||
75 | uint64_t ignored_11_09:3; | ||
76 | uint64_t address:40; | ||
77 | uint64_t ignored_62_52:11; | ||
78 | uint64_t execute_disable:1; | ||
79 | }; | ||
80 | |||
81 | /* Register Dump | ||
82 | * | ||
83 | * Input Args: | ||
84 | * indent - Left margin indent amount | ||
85 | * regs - register | ||
86 | * | ||
87 | * Output Args: | ||
88 | * stream - Output FILE stream | ||
89 | * | ||
90 | * Return: None | ||
91 | * | ||
92 | * Dumps the state of the registers given by regs, to the FILE stream | ||
93 | * given by steam. | ||
94 | */ | ||
95 | void regs_dump(FILE *stream, struct kvm_regs *regs, | ||
96 | uint8_t indent) | ||
97 | { | ||
98 | fprintf(stream, "%*srax: 0x%.16llx rbx: 0x%.16llx " | ||
99 | "rcx: 0x%.16llx rdx: 0x%.16llx\n", | ||
100 | indent, "", | ||
101 | regs->rax, regs->rbx, regs->rcx, regs->rdx); | ||
102 | fprintf(stream, "%*srsi: 0x%.16llx rdi: 0x%.16llx " | ||
103 | "rsp: 0x%.16llx rbp: 0x%.16llx\n", | ||
104 | indent, "", | ||
105 | regs->rsi, regs->rdi, regs->rsp, regs->rbp); | ||
106 | fprintf(stream, "%*sr8: 0x%.16llx r9: 0x%.16llx " | ||
107 | "r10: 0x%.16llx r11: 0x%.16llx\n", | ||
108 | indent, "", | ||
109 | regs->r8, regs->r9, regs->r10, regs->r11); | ||
110 | fprintf(stream, "%*sr12: 0x%.16llx r13: 0x%.16llx " | ||
111 | "r14: 0x%.16llx r15: 0x%.16llx\n", | ||
112 | indent, "", | ||
113 | regs->r12, regs->r13, regs->r14, regs->r15); | ||
114 | fprintf(stream, "%*srip: 0x%.16llx rfl: 0x%.16llx\n", | ||
115 | indent, "", | ||
116 | regs->rip, regs->rflags); | ||
117 | } | ||
118 | |||
119 | /* Segment Dump | ||
120 | * | ||
121 | * Input Args: | ||
122 | * indent - Left margin indent amount | ||
123 | * segment - KVM segment | ||
124 | * | ||
125 | * Output Args: | ||
126 | * stream - Output FILE stream | ||
127 | * | ||
128 | * Return: None | ||
129 | * | ||
130 | * Dumps the state of the KVM segment given by segment, to the FILE stream | ||
131 | * given by steam. | ||
132 | */ | ||
133 | static void segment_dump(FILE *stream, struct kvm_segment *segment, | ||
134 | uint8_t indent) | ||
135 | { | ||
136 | fprintf(stream, "%*sbase: 0x%.16llx limit: 0x%.8x " | ||
137 | "selector: 0x%.4x type: 0x%.2x\n", | ||
138 | indent, "", segment->base, segment->limit, | ||
139 | segment->selector, segment->type); | ||
140 | fprintf(stream, "%*spresent: 0x%.2x dpl: 0x%.2x " | ||
141 | "db: 0x%.2x s: 0x%.2x l: 0x%.2x\n", | ||
142 | indent, "", segment->present, segment->dpl, | ||
143 | segment->db, segment->s, segment->l); | ||
144 | fprintf(stream, "%*sg: 0x%.2x avl: 0x%.2x " | ||
145 | "unusable: 0x%.2x padding: 0x%.2x\n", | ||
146 | indent, "", segment->g, segment->avl, | ||
147 | segment->unusable, segment->padding); | ||
148 | } | ||
149 | |||
150 | /* dtable Dump | ||
151 | * | ||
152 | * Input Args: | ||
153 | * indent - Left margin indent amount | ||
154 | * dtable - KVM dtable | ||
155 | * | ||
156 | * Output Args: | ||
157 | * stream - Output FILE stream | ||
158 | * | ||
159 | * Return: None | ||
160 | * | ||
161 | * Dumps the state of the KVM dtable given by dtable, to the FILE stream | ||
162 | * given by steam. | ||
163 | */ | ||
164 | static void dtable_dump(FILE *stream, struct kvm_dtable *dtable, | ||
165 | uint8_t indent) | ||
166 | { | ||
167 | fprintf(stream, "%*sbase: 0x%.16llx limit: 0x%.4x " | ||
168 | "padding: 0x%.4x 0x%.4x 0x%.4x\n", | ||
169 | indent, "", dtable->base, dtable->limit, | ||
170 | dtable->padding[0], dtable->padding[1], dtable->padding[2]); | ||
171 | } | ||
172 | |||
173 | /* System Register Dump | ||
174 | * | ||
175 | * Input Args: | ||
176 | * indent - Left margin indent amount | ||
177 | * sregs - System registers | ||
178 | * | ||
179 | * Output Args: | ||
180 | * stream - Output FILE stream | ||
181 | * | ||
182 | * Return: None | ||
183 | * | ||
184 | * Dumps the state of the system registers given by sregs, to the FILE stream | ||
185 | * given by steam. | ||
186 | */ | ||
187 | void sregs_dump(FILE *stream, struct kvm_sregs *sregs, | ||
188 | uint8_t indent) | ||
189 | { | ||
190 | unsigned int i; | ||
191 | |||
192 | fprintf(stream, "%*scs:\n", indent, ""); | ||
193 | segment_dump(stream, &sregs->cs, indent + 2); | ||
194 | fprintf(stream, "%*sds:\n", indent, ""); | ||
195 | segment_dump(stream, &sregs->ds, indent + 2); | ||
196 | fprintf(stream, "%*ses:\n", indent, ""); | ||
197 | segment_dump(stream, &sregs->es, indent + 2); | ||
198 | fprintf(stream, "%*sfs:\n", indent, ""); | ||
199 | segment_dump(stream, &sregs->fs, indent + 2); | ||
200 | fprintf(stream, "%*sgs:\n", indent, ""); | ||
201 | segment_dump(stream, &sregs->gs, indent + 2); | ||
202 | fprintf(stream, "%*sss:\n", indent, ""); | ||
203 | segment_dump(stream, &sregs->ss, indent + 2); | ||
204 | fprintf(stream, "%*str:\n", indent, ""); | ||
205 | segment_dump(stream, &sregs->tr, indent + 2); | ||
206 | fprintf(stream, "%*sldt:\n", indent, ""); | ||
207 | segment_dump(stream, &sregs->ldt, indent + 2); | ||
208 | |||
209 | fprintf(stream, "%*sgdt:\n", indent, ""); | ||
210 | dtable_dump(stream, &sregs->gdt, indent + 2); | ||
211 | fprintf(stream, "%*sidt:\n", indent, ""); | ||
212 | dtable_dump(stream, &sregs->idt, indent + 2); | ||
213 | |||
214 | fprintf(stream, "%*scr0: 0x%.16llx cr2: 0x%.16llx " | ||
215 | "cr3: 0x%.16llx cr4: 0x%.16llx\n", | ||
216 | indent, "", | ||
217 | sregs->cr0, sregs->cr2, sregs->cr3, sregs->cr4); | ||
218 | fprintf(stream, "%*scr8: 0x%.16llx efer: 0x%.16llx " | ||
219 | "apic_base: 0x%.16llx\n", | ||
220 | indent, "", | ||
221 | sregs->cr8, sregs->efer, sregs->apic_base); | ||
222 | |||
223 | fprintf(stream, "%*sinterrupt_bitmap:\n", indent, ""); | ||
224 | for (i = 0; i < (KVM_NR_INTERRUPTS + 63) / 64; i++) { | ||
225 | fprintf(stream, "%*s%.16llx\n", indent + 2, "", | ||
226 | sregs->interrupt_bitmap[i]); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot) | ||
231 | { | ||
232 | int rc; | ||
233 | |||
234 | TEST_ASSERT(vm->mode == VM_MODE_FLAT48PG, "Attempt to use " | ||
235 | "unknown or unsupported guest mode, mode: 0x%x", vm->mode); | ||
236 | |||
237 | /* If needed, create page map l4 table. */ | ||
238 | if (!vm->pgd_created) { | ||
239 | vm_paddr_t paddr = vm_phy_page_alloc(vm, | ||
240 | KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot); | ||
241 | vm->pgd = paddr; | ||
242 | |||
243 | /* Set pointer to pgd tables in all the VCPUs that | ||
244 | * have already been created. Future VCPUs will have | ||
245 | * the value set as each one is created. | ||
246 | */ | ||
247 | for (struct vcpu *vcpu = vm->vcpu_head; vcpu; | ||
248 | vcpu = vcpu->next) { | ||
249 | struct kvm_sregs sregs; | ||
250 | |||
251 | /* Obtain the current system register settings */ | ||
252 | vcpu_sregs_get(vm, vcpu->id, &sregs); | ||
253 | |||
254 | /* Set and store the pointer to the start of the | ||
255 | * pgd tables. | ||
256 | */ | ||
257 | sregs.cr3 = vm->pgd; | ||
258 | vcpu_sregs_set(vm, vcpu->id, &sregs); | ||
259 | } | ||
260 | |||
261 | vm->pgd_created = true; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | /* VM Virtual Page Map | ||
266 | * | ||
267 | * Input Args: | ||
268 | * vm - Virtual Machine | ||
269 | * vaddr - VM Virtual Address | ||
270 | * paddr - VM Physical Address | ||
271 | * pgd_memslot - Memory region slot for new virtual translation tables | ||
272 | * | ||
273 | * Output Args: None | ||
274 | * | ||
275 | * Return: None | ||
276 | * | ||
277 | * Within the VM given by vm, creates a virtual translation for the page | ||
278 | * starting at vaddr to the page starting at paddr. | ||
279 | */ | ||
280 | void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, | ||
281 | uint32_t pgd_memslot) | ||
282 | { | ||
283 | uint16_t index[4]; | ||
284 | struct pageMapL4Entry *pml4e; | ||
285 | |||
286 | TEST_ASSERT(vm->mode == VM_MODE_FLAT48PG, "Attempt to use " | ||
287 | "unknown or unsupported guest mode, mode: 0x%x", vm->mode); | ||
288 | |||
289 | TEST_ASSERT((vaddr % vm->page_size) == 0, | ||
290 | "Virtual address not on page boundary,\n" | ||
291 | " vaddr: 0x%lx vm->page_size: 0x%x", | ||
292 | vaddr, vm->page_size); | ||
293 | TEST_ASSERT(sparsebit_is_set(vm->vpages_valid, | ||
294 | (vaddr >> vm->page_shift)), | ||
295 | "Invalid virtual address, vaddr: 0x%lx", | ||
296 | vaddr); | ||
297 | TEST_ASSERT((paddr % vm->page_size) == 0, | ||
298 | "Physical address not on page boundary,\n" | ||
299 | " paddr: 0x%lx vm->page_size: 0x%x", | ||
300 | paddr, vm->page_size); | ||
301 | TEST_ASSERT((paddr >> vm->page_shift) <= vm->max_gfn, | ||
302 | "Physical address beyond beyond maximum supported,\n" | ||
303 | " paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x", | ||
304 | paddr, vm->max_gfn, vm->page_size); | ||
305 | |||
306 | index[0] = (vaddr >> 12) & 0x1ffu; | ||
307 | index[1] = (vaddr >> 21) & 0x1ffu; | ||
308 | index[2] = (vaddr >> 30) & 0x1ffu; | ||
309 | index[3] = (vaddr >> 39) & 0x1ffu; | ||
310 | |||
311 | /* Allocate page directory pointer table if not present. */ | ||
312 | pml4e = addr_gpa2hva(vm, vm->pgd); | ||
313 | if (!pml4e[index[3]].present) { | ||
314 | pml4e[index[3]].address = vm_phy_page_alloc(vm, | ||
315 | KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot) | ||
316 | >> vm->page_shift; | ||
317 | pml4e[index[3]].writable = true; | ||
318 | pml4e[index[3]].present = true; | ||
319 | } | ||
320 | |||
321 | /* Allocate page directory table if not present. */ | ||
322 | struct pageDirectoryPointerEntry *pdpe; | ||
323 | pdpe = addr_gpa2hva(vm, pml4e[index[3]].address * vm->page_size); | ||
324 | if (!pdpe[index[2]].present) { | ||
325 | pdpe[index[2]].address = vm_phy_page_alloc(vm, | ||
326 | KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot) | ||
327 | >> vm->page_shift; | ||
328 | pdpe[index[2]].writable = true; | ||
329 | pdpe[index[2]].present = true; | ||
330 | } | ||
331 | |||
332 | /* Allocate page table if not present. */ | ||
333 | struct pageDirectoryEntry *pde; | ||
334 | pde = addr_gpa2hva(vm, pdpe[index[2]].address * vm->page_size); | ||
335 | if (!pde[index[1]].present) { | ||
336 | pde[index[1]].address = vm_phy_page_alloc(vm, | ||
337 | KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot) | ||
338 | >> vm->page_shift; | ||
339 | pde[index[1]].writable = true; | ||
340 | pde[index[1]].present = true; | ||
341 | } | ||
342 | |||
343 | /* Fill in page table entry. */ | ||
344 | struct pageTableEntry *pte; | ||
345 | pte = addr_gpa2hva(vm, pde[index[1]].address * vm->page_size); | ||
346 | pte[index[0]].address = paddr >> vm->page_shift; | ||
347 | pte[index[0]].writable = true; | ||
348 | pte[index[0]].present = 1; | ||
349 | } | ||
350 | |||
351 | /* Virtual Translation Tables Dump | ||
352 | * | ||
353 | * Input Args: | ||
354 | * vm - Virtual Machine | ||
355 | * indent - Left margin indent amount | ||
356 | * | ||
357 | * Output Args: | ||
358 | * stream - Output FILE stream | ||
359 | * | ||
360 | * Return: None | ||
361 | * | ||
362 | * Dumps to the FILE stream given by stream, the contents of all the | ||
363 | * virtual translation tables for the VM given by vm. | ||
364 | */ | ||
365 | void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) | ||
366 | { | ||
367 | struct pageMapL4Entry *pml4e, *pml4e_start; | ||
368 | struct pageDirectoryPointerEntry *pdpe, *pdpe_start; | ||
369 | struct pageDirectoryEntry *pde, *pde_start; | ||
370 | struct pageTableEntry *pte, *pte_start; | ||
371 | |||
372 | if (!vm->pgd_created) | ||
373 | return; | ||
374 | |||
375 | fprintf(stream, "%*s " | ||
376 | " no\n", indent, ""); | ||
377 | fprintf(stream, "%*s index hvaddr gpaddr " | ||
378 | "addr w exec dirty\n", | ||
379 | indent, ""); | ||
380 | pml4e_start = (struct pageMapL4Entry *) addr_gpa2hva(vm, | ||
381 | vm->pgd); | ||
382 | for (uint16_t n1 = 0; n1 <= 0x1ffu; n1++) { | ||
383 | pml4e = &pml4e_start[n1]; | ||
384 | if (!pml4e->present) | ||
385 | continue; | ||
386 | fprintf(stream, "%*spml4e 0x%-3zx %p 0x%-12lx 0x%-10lx %u " | ||
387 | " %u\n", | ||
388 | indent, "", | ||
389 | pml4e - pml4e_start, pml4e, | ||
390 | addr_hva2gpa(vm, pml4e), (uint64_t) pml4e->address, | ||
391 | pml4e->writable, pml4e->execute_disable); | ||
392 | |||
393 | pdpe_start = addr_gpa2hva(vm, pml4e->address | ||
394 | * vm->page_size); | ||
395 | for (uint16_t n2 = 0; n2 <= 0x1ffu; n2++) { | ||
396 | pdpe = &pdpe_start[n2]; | ||
397 | if (!pdpe->present) | ||
398 | continue; | ||
399 | fprintf(stream, "%*spdpe 0x%-3zx %p 0x%-12lx 0x%-10lx " | ||
400 | "%u %u\n", | ||
401 | indent, "", | ||
402 | pdpe - pdpe_start, pdpe, | ||
403 | addr_hva2gpa(vm, pdpe), | ||
404 | (uint64_t) pdpe->address, pdpe->writable, | ||
405 | pdpe->execute_disable); | ||
406 | |||
407 | pde_start = addr_gpa2hva(vm, | ||
408 | pdpe->address * vm->page_size); | ||
409 | for (uint16_t n3 = 0; n3 <= 0x1ffu; n3++) { | ||
410 | pde = &pde_start[n3]; | ||
411 | if (!pde->present) | ||
412 | continue; | ||
413 | fprintf(stream, "%*spde 0x%-3zx %p " | ||
414 | "0x%-12lx 0x%-10lx %u %u\n", | ||
415 | indent, "", pde - pde_start, pde, | ||
416 | addr_hva2gpa(vm, pde), | ||
417 | (uint64_t) pde->address, pde->writable, | ||
418 | pde->execute_disable); | ||
419 | |||
420 | pte_start = addr_gpa2hva(vm, | ||
421 | pde->address * vm->page_size); | ||
422 | for (uint16_t n4 = 0; n4 <= 0x1ffu; n4++) { | ||
423 | pte = &pte_start[n4]; | ||
424 | if (!pte->present) | ||
425 | continue; | ||
426 | fprintf(stream, "%*spte 0x%-3zx %p " | ||
427 | "0x%-12lx 0x%-10lx %u %u " | ||
428 | " %u 0x%-10lx\n", | ||
429 | indent, "", | ||
430 | pte - pte_start, pte, | ||
431 | addr_hva2gpa(vm, pte), | ||
432 | (uint64_t) pte->address, | ||
433 | pte->writable, | ||
434 | pte->execute_disable, | ||
435 | pte->dirty, | ||
436 | ((uint64_t) n1 << 27) | ||
437 | | ((uint64_t) n2 << 18) | ||
438 | | ((uint64_t) n3 << 9) | ||
439 | | ((uint64_t) n4)); | ||
440 | } | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | |||
446 | /* Set Unusable Segment | ||
447 | * | ||
448 | * Input Args: None | ||
449 | * | ||
450 | * Output Args: | ||
451 | * segp - Pointer to segment register | ||
452 | * | ||
453 | * Return: None | ||
454 | * | ||
455 | * Sets the segment register pointed to by segp to an unusable state. | ||
456 | */ | ||
457 | static void kvm_seg_set_unusable(struct kvm_segment *segp) | ||
458 | { | ||
459 | memset(segp, 0, sizeof(*segp)); | ||
460 | segp->unusable = true; | ||
461 | } | ||
462 | |||
463 | /* Set Long Mode Flat Kernel Code Segment | ||
464 | * | ||
465 | * Input Args: | ||
466 | * selector - selector value | ||
467 | * | ||
468 | * Output Args: | ||
469 | * segp - Pointer to KVM segment | ||
470 | * | ||
471 | * Return: None | ||
472 | * | ||
473 | * Sets up the KVM segment pointed to by segp, to be a code segment | ||
474 | * with the selector value given by selector. | ||
475 | */ | ||
476 | static void kvm_seg_set_kernel_code_64bit(uint16_t selector, | ||
477 | struct kvm_segment *segp) | ||
478 | { | ||
479 | memset(segp, 0, sizeof(*segp)); | ||
480 | segp->selector = selector; | ||
481 | segp->limit = 0xFFFFFFFFu; | ||
482 | segp->s = 0x1; /* kTypeCodeData */ | ||
483 | segp->type = 0x08 | 0x01 | 0x02; /* kFlagCode | kFlagCodeAccessed | ||
484 | * | kFlagCodeReadable | ||
485 | */ | ||
486 | segp->g = true; | ||
487 | segp->l = true; | ||
488 | segp->present = 1; | ||
489 | } | ||
490 | |||
491 | /* Set Long Mode Flat Kernel Data Segment | ||
492 | * | ||
493 | * Input Args: | ||
494 | * selector - selector value | ||
495 | * | ||
496 | * Output Args: | ||
497 | * segp - Pointer to KVM segment | ||
498 | * | ||
499 | * Return: None | ||
500 | * | ||
501 | * Sets up the KVM segment pointed to by segp, to be a data segment | ||
502 | * with the selector value given by selector. | ||
503 | */ | ||
504 | static void kvm_seg_set_kernel_data_64bit(uint16_t selector, | ||
505 | struct kvm_segment *segp) | ||
506 | { | ||
507 | memset(segp, 0, sizeof(*segp)); | ||
508 | segp->selector = selector; | ||
509 | segp->limit = 0xFFFFFFFFu; | ||
510 | segp->s = 0x1; /* kTypeCodeData */ | ||
511 | segp->type = 0x00 | 0x01 | 0x02; /* kFlagData | kFlagDataAccessed | ||
512 | * | kFlagDataWritable | ||
513 | */ | ||
514 | segp->g = true; | ||
515 | segp->present = true; | ||
516 | } | ||
517 | |||
518 | /* Address Guest Virtual to Guest Physical | ||
519 | * | ||
520 | * Input Args: | ||
521 | * vm - Virtual Machine | ||
522 | * gpa - VM virtual address | ||
523 | * | ||
524 | * Output Args: None | ||
525 | * | ||
526 | * Return: | ||
527 | * Equivalent VM physical address | ||
528 | * | ||
529 | * Translates the VM virtual address given by gva to a VM physical | ||
530 | * address and then locates the memory region containing the VM | ||
531 | * physical address, within the VM given by vm. When found, the host | ||
532 | * virtual address providing the memory to the vm physical address is returned. | ||
533 | * A TEST_ASSERT failure occurs if no region containing translated | ||
534 | * VM virtual address exists. | ||
535 | */ | ||
536 | vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) | ||
537 | { | ||
538 | uint16_t index[4]; | ||
539 | struct pageMapL4Entry *pml4e; | ||
540 | struct pageDirectoryPointerEntry *pdpe; | ||
541 | struct pageDirectoryEntry *pde; | ||
542 | struct pageTableEntry *pte; | ||
543 | void *hva; | ||
544 | |||
545 | TEST_ASSERT(vm->mode == VM_MODE_FLAT48PG, "Attempt to use " | ||
546 | "unknown or unsupported guest mode, mode: 0x%x", vm->mode); | ||
547 | |||
548 | index[0] = (gva >> 12) & 0x1ffu; | ||
549 | index[1] = (gva >> 21) & 0x1ffu; | ||
550 | index[2] = (gva >> 30) & 0x1ffu; | ||
551 | index[3] = (gva >> 39) & 0x1ffu; | ||
552 | |||
553 | if (!vm->pgd_created) | ||
554 | goto unmapped_gva; | ||
555 | pml4e = addr_gpa2hva(vm, vm->pgd); | ||
556 | if (!pml4e[index[3]].present) | ||
557 | goto unmapped_gva; | ||
558 | |||
559 | pdpe = addr_gpa2hva(vm, pml4e[index[3]].address * vm->page_size); | ||
560 | if (!pdpe[index[2]].present) | ||
561 | goto unmapped_gva; | ||
562 | |||
563 | pde = addr_gpa2hva(vm, pdpe[index[2]].address * vm->page_size); | ||
564 | if (!pde[index[1]].present) | ||
565 | goto unmapped_gva; | ||
566 | |||
567 | pte = addr_gpa2hva(vm, pde[index[1]].address * vm->page_size); | ||
568 | if (!pte[index[0]].present) | ||
569 | goto unmapped_gva; | ||
570 | |||
571 | return (pte[index[0]].address * vm->page_size) + (gva & 0xfffu); | ||
572 | |||
573 | unmapped_gva: | ||
574 | TEST_ASSERT(false, "No mapping for vm virtual address, " | ||
575 | "gva: 0x%lx", gva); | ||
576 | } | ||
577 | |||
578 | void vcpu_setup(struct kvm_vm *vm, int vcpuid) | ||
579 | { | ||
580 | struct kvm_sregs sregs; | ||
581 | |||
582 | /* Set mode specific system register values. */ | ||
583 | vcpu_sregs_get(vm, vcpuid, &sregs); | ||
584 | |||
585 | switch (vm->mode) { | ||
586 | case VM_MODE_FLAT48PG: | ||
587 | sregs.cr0 = X86_CR0_PE | X86_CR0_NE | X86_CR0_PG; | ||
588 | sregs.cr4 |= X86_CR4_PAE; | ||
589 | sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX); | ||
590 | |||
591 | kvm_seg_set_unusable(&sregs.ldt); | ||
592 | kvm_seg_set_kernel_code_64bit(0x8, &sregs.cs); | ||
593 | kvm_seg_set_kernel_data_64bit(0x10, &sregs.ds); | ||
594 | kvm_seg_set_kernel_data_64bit(0x10, &sregs.es); | ||
595 | break; | ||
596 | |||
597 | default: | ||
598 | TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", vm->mode); | ||
599 | } | ||
600 | vcpu_sregs_set(vm, vcpuid, &sregs); | ||
601 | |||
602 | /* If virtual translation table have been setup, set system register | ||
603 | * to point to the tables. It's okay if they haven't been setup yet, | ||
604 | * in that the code that sets up the virtual translation tables, will | ||
605 | * go back through any VCPUs that have already been created and set | ||
606 | * their values. | ||
607 | */ | ||
608 | if (vm->pgd_created) { | ||
609 | struct kvm_sregs sregs; | ||
610 | |||
611 | vcpu_sregs_get(vm, vcpuid, &sregs); | ||
612 | |||
613 | sregs.cr3 = vm->pgd; | ||
614 | vcpu_sregs_set(vm, vcpuid, &sregs); | ||
615 | } | ||
616 | } | ||
617 | /* Adds a vCPU with reasonable defaults (i.e., a stack) | ||
618 | * | ||
619 | * Input Args: | ||
620 | * vcpuid - The id of the VCPU to add to the VM. | ||
621 | * guest_code - The vCPU's entry point | ||
622 | */ | ||
623 | void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) | ||
624 | { | ||
625 | struct kvm_mp_state mp_state; | ||
626 | struct kvm_regs regs; | ||
627 | vm_vaddr_t stack_vaddr; | ||
628 | stack_vaddr = vm_vaddr_alloc(vm, DEFAULT_STACK_PGS * getpagesize(), | ||
629 | DEFAULT_GUEST_STACK_VADDR_MIN, 0, 0); | ||
630 | |||
631 | /* Create VCPU */ | ||
632 | vm_vcpu_add(vm, vcpuid); | ||
633 | |||
634 | /* Setup guest general purpose registers */ | ||
635 | vcpu_regs_get(vm, vcpuid, ®s); | ||
636 | regs.rflags = regs.rflags | 0x2; | ||
637 | regs.rsp = stack_vaddr + (DEFAULT_STACK_PGS * getpagesize()); | ||
638 | regs.rip = (unsigned long) guest_code; | ||
639 | vcpu_regs_set(vm, vcpuid, ®s); | ||
640 | |||
641 | /* Setup the MP state */ | ||
642 | mp_state.mp_state = 0; | ||
643 | vcpu_set_mp_state(vm, vcpuid, &mp_state); | ||
644 | } | ||
645 | |||
646 | /* VM VCPU CPUID Set | ||
647 | * | ||
648 | * Input Args: | ||
649 | * vm - Virtual Machine | ||
650 | * vcpuid - VCPU id | ||
651 | * cpuid - The CPUID values to set. | ||
652 | * | ||
653 | * Output Args: None | ||
654 | * | ||
655 | * Return: void | ||
656 | * | ||
657 | * Set the VCPU's CPUID. | ||
658 | */ | ||
659 | void vcpu_set_cpuid(struct kvm_vm *vm, | ||
660 | uint32_t vcpuid, struct kvm_cpuid2 *cpuid) | ||
661 | { | ||
662 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
663 | int rc; | ||
664 | |||
665 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
666 | |||
667 | rc = ioctl(vcpu->fd, KVM_SET_CPUID2, cpuid); | ||
668 | TEST_ASSERT(rc == 0, "KVM_SET_CPUID2 failed, rc: %i errno: %i", | ||
669 | rc, errno); | ||
670 | |||
671 | } | ||
672 | /* Create a VM with reasonable defaults | ||
673 | * | ||
674 | * Input Args: | ||
675 | * vcpuid - The id of the single VCPU to add to the VM. | ||
676 | * guest_code - The vCPU's entry point | ||
677 | * | ||
678 | * Output Args: None | ||
679 | * | ||
680 | * Return: | ||
681 | * Pointer to opaque structure that describes the created VM. | ||
682 | */ | ||
683 | struct kvm_vm *vm_create_default(uint32_t vcpuid, void *guest_code) | ||
684 | { | ||
685 | struct kvm_vm *vm; | ||
686 | |||
687 | /* Create VM */ | ||
688 | vm = vm_create(VM_MODE_FLAT48PG, DEFAULT_GUEST_PHY_PAGES, O_RDWR); | ||
689 | |||
690 | /* Setup guest code */ | ||
691 | kvm_vm_elf_load(vm, program_invocation_name, 0, 0); | ||
692 | |||
693 | /* Setup IRQ Chip */ | ||
694 | vm_create_irqchip(vm); | ||
695 | |||
696 | /* Add the first vCPU. */ | ||
697 | vm_vcpu_add_default(vm, vcpuid, guest_code); | ||
698 | |||
699 | return vm; | ||
700 | } | ||
diff --git a/tools/testing/selftests/kvm/set_sregs_test.c b/tools/testing/selftests/kvm/set_sregs_test.c new file mode 100644 index 000000000000..090fd3f19352 --- /dev/null +++ b/tools/testing/selftests/kvm/set_sregs_test.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * KVM_SET_SREGS tests | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | * | ||
8 | * This is a regression test for the bug fixed by the following commit: | ||
9 | * d3802286fa0f ("kvm: x86: Disallow illegal IA32_APIC_BASE MSR values") | ||
10 | * | ||
11 | * That bug allowed a user-mode program that called the KVM_SET_SREGS | ||
12 | * ioctl to put a VCPU's local APIC into an invalid state. | ||
13 | * | ||
14 | */ | ||
15 | #define _GNU_SOURCE /* for program_invocation_short_name */ | ||
16 | #include <fcntl.h> | ||
17 | #include <stdio.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | #include <sys/ioctl.h> | ||
21 | |||
22 | #include "test_util.h" | ||
23 | |||
24 | #include "kvm_util.h" | ||
25 | #include "x86.h" | ||
26 | |||
27 | #define VCPU_ID 5 | ||
28 | |||
29 | int main(int argc, char *argv[]) | ||
30 | { | ||
31 | struct kvm_sregs sregs; | ||
32 | struct kvm_vm *vm; | ||
33 | int rc; | ||
34 | |||
35 | /* Tell stdout not to buffer its content */ | ||
36 | setbuf(stdout, NULL); | ||
37 | |||
38 | /* Create VM */ | ||
39 | vm = vm_create_default(VCPU_ID, NULL); | ||
40 | |||
41 | vcpu_sregs_get(vm, VCPU_ID, &sregs); | ||
42 | sregs.apic_base = 1 << 10; | ||
43 | rc = _vcpu_sregs_set(vm, VCPU_ID, &sregs); | ||
44 | TEST_ASSERT(rc, "Set IA32_APIC_BASE to %llx (invalid)", | ||
45 | sregs.apic_base); | ||
46 | sregs.apic_base = 1 << 11; | ||
47 | rc = _vcpu_sregs_set(vm, VCPU_ID, &sregs); | ||
48 | TEST_ASSERT(!rc, "Couldn't set IA32_APIC_BASE to %llx (valid)", | ||
49 | sregs.apic_base); | ||
50 | |||
51 | kvm_vm_free(vm); | ||
52 | |||
53 | return 0; | ||
54 | } | ||
diff --git a/tools/testing/selftests/kvm/sync_regs_test.c b/tools/testing/selftests/kvm/sync_regs_test.c new file mode 100644 index 000000000000..428e9473f5e2 --- /dev/null +++ b/tools/testing/selftests/kvm/sync_regs_test.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * Test for x86 KVM_CAP_SYNC_REGS | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | * | ||
8 | * Verifies expected behavior of x86 KVM_CAP_SYNC_REGS functionality, | ||
9 | * including requesting an invalid register set, updates to/from values | ||
10 | * in kvm_run.s.regs when kvm_valid_regs and kvm_dirty_regs are toggled. | ||
11 | */ | ||
12 | |||
13 | #define _GNU_SOURCE /* for program_invocation_short_name */ | ||
14 | #include <fcntl.h> | ||
15 | #include <stdio.h> | ||
16 | #include <stdlib.h> | ||
17 | #include <string.h> | ||
18 | #include <sys/ioctl.h> | ||
19 | |||
20 | #include "test_util.h" | ||
21 | #include "kvm_util.h" | ||
22 | #include "x86.h" | ||
23 | |||
24 | #define VCPU_ID 5 | ||
25 | #define PORT_HOST_SYNC 0x1000 | ||
26 | |||
27 | static void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1) | ||
28 | { | ||
29 | __asm__ __volatile__("in %[port], %%al" | ||
30 | : | ||
31 | : [port]"d"(port), "D"(arg0), "S"(arg1) | ||
32 | : "rax"); | ||
33 | } | ||
34 | |||
35 | #define exit_to_l0(_port, _arg0, _arg1) \ | ||
36 | __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1)) | ||
37 | |||
38 | #define GUEST_ASSERT(_condition) do { \ | ||
39 | if (!(_condition)) \ | ||
40 | exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition, 0);\ | ||
41 | } while (0) | ||
42 | |||
43 | void guest_code(void) | ||
44 | { | ||
45 | for (;;) { | ||
46 | exit_to_l0(PORT_HOST_SYNC, "hello", 0); | ||
47 | asm volatile ("inc %r11"); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | static void compare_regs(struct kvm_regs *left, struct kvm_regs *right) | ||
52 | { | ||
53 | #define REG_COMPARE(reg) \ | ||
54 | TEST_ASSERT(left->reg == right->reg, \ | ||
55 | "Register " #reg \ | ||
56 | " values did not match: 0x%llx, 0x%llx\n", \ | ||
57 | left->reg, right->reg) | ||
58 | REG_COMPARE(rax); | ||
59 | REG_COMPARE(rbx); | ||
60 | REG_COMPARE(rcx); | ||
61 | REG_COMPARE(rdx); | ||
62 | REG_COMPARE(rsi); | ||
63 | REG_COMPARE(rdi); | ||
64 | REG_COMPARE(rsp); | ||
65 | REG_COMPARE(rbp); | ||
66 | REG_COMPARE(r8); | ||
67 | REG_COMPARE(r9); | ||
68 | REG_COMPARE(r10); | ||
69 | REG_COMPARE(r11); | ||
70 | REG_COMPARE(r12); | ||
71 | REG_COMPARE(r13); | ||
72 | REG_COMPARE(r14); | ||
73 | REG_COMPARE(r15); | ||
74 | REG_COMPARE(rip); | ||
75 | REG_COMPARE(rflags); | ||
76 | #undef REG_COMPARE | ||
77 | } | ||
78 | |||
79 | static void compare_sregs(struct kvm_sregs *left, struct kvm_sregs *right) | ||
80 | { | ||
81 | } | ||
82 | |||
83 | static void compare_vcpu_events(struct kvm_vcpu_events *left, | ||
84 | struct kvm_vcpu_events *right) | ||
85 | { | ||
86 | } | ||
87 | |||
88 | int main(int argc, char *argv[]) | ||
89 | { | ||
90 | struct kvm_vm *vm; | ||
91 | struct kvm_run *run; | ||
92 | struct kvm_regs regs; | ||
93 | struct kvm_sregs sregs; | ||
94 | struct kvm_vcpu_events events; | ||
95 | int rv, cap; | ||
96 | |||
97 | /* Tell stdout not to buffer its content */ | ||
98 | setbuf(stdout, NULL); | ||
99 | |||
100 | cap = kvm_check_cap(KVM_CAP_SYNC_REGS); | ||
101 | TEST_ASSERT((unsigned long)cap == KVM_SYNC_X86_VALID_FIELDS, | ||
102 | "KVM_CAP_SYNC_REGS (0x%x) != KVM_SYNC_X86_VALID_FIELDS (0x%lx)\n", | ||
103 | cap, KVM_SYNC_X86_VALID_FIELDS); | ||
104 | |||
105 | /* Create VM */ | ||
106 | vm = vm_create_default(VCPU_ID, guest_code); | ||
107 | |||
108 | run = vcpu_state(vm, VCPU_ID); | ||
109 | |||
110 | /* Request reading invalid register set from VCPU. */ | ||
111 | run->kvm_valid_regs = KVM_SYNC_X86_VALID_FIELDS << 1; | ||
112 | rv = _vcpu_run(vm, VCPU_ID); | ||
113 | TEST_ASSERT(rv < 0 && errno == EINVAL, | ||
114 | "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", | ||
115 | rv); | ||
116 | vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0; | ||
117 | |||
118 | /* Request setting invalid register set into VCPU. */ | ||
119 | run->kvm_dirty_regs = KVM_SYNC_X86_VALID_FIELDS << 1; | ||
120 | rv = _vcpu_run(vm, VCPU_ID); | ||
121 | TEST_ASSERT(rv < 0 && errno == EINVAL, | ||
122 | "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", | ||
123 | rv); | ||
124 | vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0; | ||
125 | |||
126 | /* Request and verify all valid register sets. */ | ||
127 | /* TODO: BUILD TIME CHECK: TEST_ASSERT(KVM_SYNC_X86_NUM_FIELDS != 3); */ | ||
128 | run->kvm_valid_regs = KVM_SYNC_X86_VALID_FIELDS; | ||
129 | rv = _vcpu_run(vm, VCPU_ID); | ||
130 | TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, | ||
131 | "Unexpected exit reason: %u (%s),\n", | ||
132 | run->exit_reason, | ||
133 | exit_reason_str(run->exit_reason)); | ||
134 | |||
135 | vcpu_regs_get(vm, VCPU_ID, ®s); | ||
136 | compare_regs(®s, &run->s.regs.regs); | ||
137 | |||
138 | vcpu_sregs_get(vm, VCPU_ID, &sregs); | ||
139 | compare_sregs(&sregs, &run->s.regs.sregs); | ||
140 | |||
141 | vcpu_events_get(vm, VCPU_ID, &events); | ||
142 | compare_vcpu_events(&events, &run->s.regs.events); | ||
143 | |||
144 | /* Set and verify various register values. */ | ||
145 | run->s.regs.regs.r11 = 0xBAD1DEA; | ||
146 | run->s.regs.sregs.apic_base = 1 << 11; | ||
147 | /* TODO run->s.regs.events.XYZ = ABC; */ | ||
148 | |||
149 | run->kvm_valid_regs = KVM_SYNC_X86_VALID_FIELDS; | ||
150 | run->kvm_dirty_regs = KVM_SYNC_X86_REGS | KVM_SYNC_X86_SREGS; | ||
151 | rv = _vcpu_run(vm, VCPU_ID); | ||
152 | TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, | ||
153 | "Unexpected exit reason: %u (%s),\n", | ||
154 | run->exit_reason, | ||
155 | exit_reason_str(run->exit_reason)); | ||
156 | TEST_ASSERT(run->s.regs.regs.r11 == 0xBAD1DEA + 1, | ||
157 | "r11 sync regs value incorrect 0x%llx.", | ||
158 | run->s.regs.regs.r11); | ||
159 | TEST_ASSERT(run->s.regs.sregs.apic_base == 1 << 11, | ||
160 | "apic_base sync regs value incorrect 0x%llx.", | ||
161 | run->s.regs.sregs.apic_base); | ||
162 | |||
163 | vcpu_regs_get(vm, VCPU_ID, ®s); | ||
164 | compare_regs(®s, &run->s.regs.regs); | ||
165 | |||
166 | vcpu_sregs_get(vm, VCPU_ID, &sregs); | ||
167 | compare_sregs(&sregs, &run->s.regs.sregs); | ||
168 | |||
169 | vcpu_events_get(vm, VCPU_ID, &events); | ||
170 | compare_vcpu_events(&events, &run->s.regs.events); | ||
171 | |||
172 | /* Clear kvm_dirty_regs bits, verify new s.regs values are | ||
173 | * overwritten with existing guest values. | ||
174 | */ | ||
175 | run->kvm_valid_regs = KVM_SYNC_X86_VALID_FIELDS; | ||
176 | run->kvm_dirty_regs = 0; | ||
177 | run->s.regs.regs.r11 = 0xDEADBEEF; | ||
178 | rv = _vcpu_run(vm, VCPU_ID); | ||
179 | TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, | ||
180 | "Unexpected exit reason: %u (%s),\n", | ||
181 | run->exit_reason, | ||
182 | exit_reason_str(run->exit_reason)); | ||
183 | TEST_ASSERT(run->s.regs.regs.r11 != 0xDEADBEEF, | ||
184 | "r11 sync regs value incorrect 0x%llx.", | ||
185 | run->s.regs.regs.r11); | ||
186 | |||
187 | /* Clear kvm_valid_regs bits and kvm_dirty_bits. | ||
188 | * Verify s.regs values are not overwritten with existing guest values | ||
189 | * and that guest values are not overwritten with kvm_sync_regs values. | ||
190 | */ | ||
191 | run->kvm_valid_regs = 0; | ||
192 | run->kvm_dirty_regs = 0; | ||
193 | run->s.regs.regs.r11 = 0xAAAA; | ||
194 | regs.r11 = 0xBAC0; | ||
195 | vcpu_regs_set(vm, VCPU_ID, ®s); | ||
196 | rv = _vcpu_run(vm, VCPU_ID); | ||
197 | TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, | ||
198 | "Unexpected exit reason: %u (%s),\n", | ||
199 | run->exit_reason, | ||
200 | exit_reason_str(run->exit_reason)); | ||
201 | TEST_ASSERT(run->s.regs.regs.r11 == 0xAAAA, | ||
202 | "r11 sync regs value incorrect 0x%llx.", | ||
203 | run->s.regs.regs.r11); | ||
204 | vcpu_regs_get(vm, VCPU_ID, ®s); | ||
205 | TEST_ASSERT(regs.r11 == 0xBAC0 + 1, | ||
206 | "r11 guest value incorrect 0x%llx.", | ||
207 | regs.r11); | ||
208 | |||
209 | /* Clear kvm_valid_regs bits. Verify s.regs values are not overwritten | ||
210 | * with existing guest values but that guest values are overwritten | ||
211 | * with kvm_sync_regs values. | ||
212 | */ | ||
213 | run->kvm_valid_regs = 0; | ||
214 | run->kvm_dirty_regs = KVM_SYNC_X86_VALID_FIELDS; | ||
215 | run->s.regs.regs.r11 = 0xBBBB; | ||
216 | rv = _vcpu_run(vm, VCPU_ID); | ||
217 | TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, | ||
218 | "Unexpected exit reason: %u (%s),\n", | ||
219 | run->exit_reason, | ||
220 | exit_reason_str(run->exit_reason)); | ||
221 | TEST_ASSERT(run->s.regs.regs.r11 == 0xBBBB, | ||
222 | "r11 sync regs value incorrect 0x%llx.", | ||
223 | run->s.regs.regs.r11); | ||
224 | vcpu_regs_get(vm, VCPU_ID, ®s); | ||
225 | TEST_ASSERT(regs.r11 == 0xBBBB + 1, | ||
226 | "r11 guest value incorrect 0x%llx.", | ||
227 | regs.r11); | ||
228 | |||
229 | kvm_vm_free(vm); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
diff --git a/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c b/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c new file mode 100644 index 000000000000..8f7f62093add --- /dev/null +++ b/tools/testing/selftests/kvm/vmx_tsc_adjust_test.c | |||
@@ -0,0 +1,231 @@ | |||
1 | /* | ||
2 | * gtests/tests/vmx_tsc_adjust_test.c | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | * | ||
8 | * | ||
9 | * IA32_TSC_ADJUST test | ||
10 | * | ||
11 | * According to the SDM, "if an execution of WRMSR to the | ||
12 | * IA32_TIME_STAMP_COUNTER MSR adds (or subtracts) value X from the TSC, | ||
13 | * the logical processor also adds (or subtracts) value X from the | ||
14 | * IA32_TSC_ADJUST MSR. | ||
15 | * | ||
16 | * Note that when L1 doesn't intercept writes to IA32_TSC, a | ||
17 | * WRMSR(IA32_TSC) from L2 sets L1's TSC value, not L2's perceived TSC | ||
18 | * value. | ||
19 | * | ||
20 | * This test verifies that this unusual case is handled correctly. | ||
21 | */ | ||
22 | |||
23 | #include "test_util.h" | ||
24 | #include "kvm_util.h" | ||
25 | #include "x86.h" | ||
26 | #include "vmx.h" | ||
27 | |||
28 | #include <string.h> | ||
29 | #include <sys/ioctl.h> | ||
30 | |||
31 | #ifndef MSR_IA32_TSC_ADJUST | ||
32 | #define MSR_IA32_TSC_ADJUST 0x3b | ||
33 | #endif | ||
34 | |||
35 | #define PAGE_SIZE 4096 | ||
36 | #define VCPU_ID 5 | ||
37 | |||
38 | #define TSC_ADJUST_VALUE (1ll << 32) | ||
39 | #define TSC_OFFSET_VALUE -(1ll << 48) | ||
40 | |||
41 | enum { | ||
42 | PORT_ABORT = 0x1000, | ||
43 | PORT_REPORT, | ||
44 | PORT_DONE, | ||
45 | }; | ||
46 | |||
47 | struct vmx_page { | ||
48 | vm_vaddr_t virt; | ||
49 | vm_paddr_t phys; | ||
50 | }; | ||
51 | |||
52 | enum { | ||
53 | VMXON_PAGE = 0, | ||
54 | VMCS_PAGE, | ||
55 | MSR_BITMAP_PAGE, | ||
56 | |||
57 | NUM_VMX_PAGES, | ||
58 | }; | ||
59 | |||
60 | struct kvm_single_msr { | ||
61 | struct kvm_msrs header; | ||
62 | struct kvm_msr_entry entry; | ||
63 | } __attribute__((packed)); | ||
64 | |||
65 | /* The virtual machine object. */ | ||
66 | static struct kvm_vm *vm; | ||
67 | |||
68 | /* Array of vmx_page descriptors that is shared with the guest. */ | ||
69 | struct vmx_page *vmx_pages; | ||
70 | |||
71 | #define exit_to_l0(_port, _arg) do_exit_to_l0(_port, (unsigned long) (_arg)) | ||
72 | static void do_exit_to_l0(uint16_t port, unsigned long arg) | ||
73 | { | ||
74 | __asm__ __volatile__("in %[port], %%al" | ||
75 | : | ||
76 | : [port]"d"(port), "D"(arg) | ||
77 | : "rax"); | ||
78 | } | ||
79 | |||
80 | |||
81 | #define GUEST_ASSERT(_condition) do { \ | ||
82 | if (!(_condition)) \ | ||
83 | exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition); \ | ||
84 | } while (0) | ||
85 | |||
86 | static void check_ia32_tsc_adjust(int64_t max) | ||
87 | { | ||
88 | int64_t adjust; | ||
89 | |||
90 | adjust = rdmsr(MSR_IA32_TSC_ADJUST); | ||
91 | exit_to_l0(PORT_REPORT, adjust); | ||
92 | GUEST_ASSERT(adjust <= max); | ||
93 | } | ||
94 | |||
95 | static void l2_guest_code(void) | ||
96 | { | ||
97 | uint64_t l1_tsc = rdtsc() - TSC_OFFSET_VALUE; | ||
98 | |||
99 | wrmsr(MSR_IA32_TSC, l1_tsc - TSC_ADJUST_VALUE); | ||
100 | check_ia32_tsc_adjust(-2 * TSC_ADJUST_VALUE); | ||
101 | |||
102 | /* Exit to L1 */ | ||
103 | __asm__ __volatile__("vmcall"); | ||
104 | } | ||
105 | |||
106 | static void l1_guest_code(struct vmx_page *vmx_pages) | ||
107 | { | ||
108 | #define L2_GUEST_STACK_SIZE 64 | ||
109 | unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; | ||
110 | uint32_t control; | ||
111 | uintptr_t save_cr3; | ||
112 | |||
113 | GUEST_ASSERT(rdtsc() < TSC_ADJUST_VALUE); | ||
114 | wrmsr(MSR_IA32_TSC, rdtsc() - TSC_ADJUST_VALUE); | ||
115 | check_ia32_tsc_adjust(-1 * TSC_ADJUST_VALUE); | ||
116 | |||
117 | prepare_for_vmx_operation(); | ||
118 | |||
119 | /* Enter VMX root operation. */ | ||
120 | *(uint32_t *)vmx_pages[VMXON_PAGE].virt = vmcs_revision(); | ||
121 | GUEST_ASSERT(!vmxon(vmx_pages[VMXON_PAGE].phys)); | ||
122 | |||
123 | /* Load a VMCS. */ | ||
124 | *(uint32_t *)vmx_pages[VMCS_PAGE].virt = vmcs_revision(); | ||
125 | GUEST_ASSERT(!vmclear(vmx_pages[VMCS_PAGE].phys)); | ||
126 | GUEST_ASSERT(!vmptrld(vmx_pages[VMCS_PAGE].phys)); | ||
127 | |||
128 | /* Prepare the VMCS for L2 execution. */ | ||
129 | prepare_vmcs(l2_guest_code, &l2_guest_stack[L2_GUEST_STACK_SIZE]); | ||
130 | control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); | ||
131 | control |= CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_USE_TSC_OFFSETING; | ||
132 | vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); | ||
133 | vmwrite(MSR_BITMAP, vmx_pages[MSR_BITMAP_PAGE].phys); | ||
134 | vmwrite(TSC_OFFSET, TSC_OFFSET_VALUE); | ||
135 | |||
136 | /* Jump into L2. First, test failure to load guest CR3. */ | ||
137 | save_cr3 = vmreadz(GUEST_CR3); | ||
138 | vmwrite(GUEST_CR3, -1ull); | ||
139 | GUEST_ASSERT(!vmlaunch()); | ||
140 | GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == | ||
141 | (EXIT_REASON_FAILED_VMENTRY | EXIT_REASON_INVALID_STATE)); | ||
142 | check_ia32_tsc_adjust(-1 * TSC_ADJUST_VALUE); | ||
143 | vmwrite(GUEST_CR3, save_cr3); | ||
144 | |||
145 | GUEST_ASSERT(!vmlaunch()); | ||
146 | GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); | ||
147 | |||
148 | check_ia32_tsc_adjust(-2 * TSC_ADJUST_VALUE); | ||
149 | |||
150 | exit_to_l0(PORT_DONE, 0); | ||
151 | } | ||
152 | |||
153 | static void allocate_vmx_page(struct vmx_page *page) | ||
154 | { | ||
155 | vm_vaddr_t virt; | ||
156 | |||
157 | virt = vm_vaddr_alloc(vm, PAGE_SIZE, 0, 0, 0); | ||
158 | memset(addr_gva2hva(vm, virt), 0, PAGE_SIZE); | ||
159 | |||
160 | page->virt = virt; | ||
161 | page->phys = addr_gva2gpa(vm, virt); | ||
162 | } | ||
163 | |||
164 | static vm_vaddr_t allocate_vmx_pages(void) | ||
165 | { | ||
166 | vm_vaddr_t vmx_pages_vaddr; | ||
167 | int i; | ||
168 | |||
169 | vmx_pages_vaddr = vm_vaddr_alloc( | ||
170 | vm, sizeof(struct vmx_page) * NUM_VMX_PAGES, 0, 0, 0); | ||
171 | |||
172 | vmx_pages = (void *) addr_gva2hva(vm, vmx_pages_vaddr); | ||
173 | |||
174 | for (i = 0; i < NUM_VMX_PAGES; i++) | ||
175 | allocate_vmx_page(&vmx_pages[i]); | ||
176 | |||
177 | return vmx_pages_vaddr; | ||
178 | } | ||
179 | |||
180 | void report(int64_t val) | ||
181 | { | ||
182 | printf("IA32_TSC_ADJUST is %ld (%lld * TSC_ADJUST_VALUE + %lld).\n", | ||
183 | val, val / TSC_ADJUST_VALUE, val % TSC_ADJUST_VALUE); | ||
184 | } | ||
185 | |||
186 | int main(int argc, char *argv[]) | ||
187 | { | ||
188 | vm_vaddr_t vmx_pages_vaddr; | ||
189 | struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1); | ||
190 | |||
191 | if (!(entry->ecx & CPUID_VMX)) { | ||
192 | printf("nested VMX not enabled, skipping test"); | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | vm = vm_create_default_vmx(VCPU_ID, (void *) l1_guest_code); | ||
197 | |||
198 | /* Allocate VMX pages and shared descriptors (vmx_pages). */ | ||
199 | vmx_pages_vaddr = allocate_vmx_pages(); | ||
200 | vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_vaddr); | ||
201 | |||
202 | for (;;) { | ||
203 | volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); | ||
204 | struct kvm_regs regs; | ||
205 | |||
206 | vcpu_run(vm, VCPU_ID); | ||
207 | TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, | ||
208 | "Got exit_reason other than KVM_EXIT_IO: %u (%s),\n", | ||
209 | run->exit_reason, | ||
210 | exit_reason_str(run->exit_reason)); | ||
211 | |||
212 | vcpu_regs_get(vm, VCPU_ID, ®s); | ||
213 | |||
214 | switch (run->io.port) { | ||
215 | case PORT_ABORT: | ||
216 | TEST_ASSERT(false, "%s", (const char *) regs.rdi); | ||
217 | /* NOT REACHED */ | ||
218 | case PORT_REPORT: | ||
219 | report(regs.rdi); | ||
220 | break; | ||
221 | case PORT_DONE: | ||
222 | goto done; | ||
223 | default: | ||
224 | TEST_ASSERT(false, "Unknown port 0x%x.", run->io.port); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | kvm_vm_free(vm); | ||
229 | done: | ||
230 | return 0; | ||
231 | } | ||
diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk index 7de482a0519d..195e9d4739a9 100644 --- a/tools/testing/selftests/lib.mk +++ b/tools/testing/selftests/lib.mk | |||
@@ -20,6 +20,7 @@ all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) | |||
20 | 20 | ||
21 | .ONESHELL: | 21 | .ONESHELL: |
22 | define RUN_TESTS | 22 | define RUN_TESTS |
23 | @export KSFT_TAP_LEVEL=`echo 1`; | ||
23 | @test_num=`echo 0`; | 24 | @test_num=`echo 0`; |
24 | @echo "TAP version 13"; | 25 | @echo "TAP version 13"; |
25 | @for TEST in $(1); do \ | 26 | @for TEST in $(1); do \ |
diff --git a/tools/testing/selftests/powerpc/benchmarks/.gitignore b/tools/testing/selftests/powerpc/benchmarks/.gitignore index 04dc1e6ef2ce..9161679b1e1a 100644 --- a/tools/testing/selftests/powerpc/benchmarks/.gitignore +++ b/tools/testing/selftests/powerpc/benchmarks/.gitignore | |||
@@ -1,5 +1,7 @@ | |||
1 | gettimeofday | 1 | gettimeofday |
2 | context_switch | 2 | context_switch |
3 | fork | ||
4 | exec_target | ||
3 | mmap_bench | 5 | mmap_bench |
4 | futex_bench | 6 | futex_bench |
5 | null_syscall | 7 | null_syscall |
diff --git a/tools/testing/selftests/powerpc/benchmarks/Makefile b/tools/testing/selftests/powerpc/benchmarks/Makefile index a35058e3766c..b4d7432a0ecd 100644 --- a/tools/testing/selftests/powerpc/benchmarks/Makefile +++ b/tools/testing/selftests/powerpc/benchmarks/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
2 | TEST_GEN_PROGS := gettimeofday context_switch mmap_bench futex_bench null_syscall | 2 | TEST_GEN_PROGS := gettimeofday context_switch fork mmap_bench futex_bench null_syscall |
3 | TEST_GEN_FILES := exec_target | ||
3 | 4 | ||
4 | CFLAGS += -O2 | 5 | CFLAGS += -O2 |
5 | 6 | ||
@@ -10,3 +11,7 @@ $(TEST_GEN_PROGS): ../harness.c | |||
10 | $(OUTPUT)/context_switch: ../utils.c | 11 | $(OUTPUT)/context_switch: ../utils.c |
11 | $(OUTPUT)/context_switch: CFLAGS += -maltivec -mvsx -mabi=altivec | 12 | $(OUTPUT)/context_switch: CFLAGS += -maltivec -mvsx -mabi=altivec |
12 | $(OUTPUT)/context_switch: LDLIBS += -lpthread | 13 | $(OUTPUT)/context_switch: LDLIBS += -lpthread |
14 | |||
15 | $(OUTPUT)/fork: LDLIBS += -lpthread | ||
16 | |||
17 | $(OUTPUT)/exec_target: CFLAGS += -static -nostartfiles | ||
diff --git a/tools/testing/selftests/powerpc/benchmarks/exec_target.c b/tools/testing/selftests/powerpc/benchmarks/exec_target.c new file mode 100644 index 000000000000..3c9c144192be --- /dev/null +++ b/tools/testing/selftests/powerpc/benchmarks/exec_target.c | |||
@@ -0,0 +1,13 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | |||
3 | /* | ||
4 | * Part of fork context switch microbenchmark. | ||
5 | * | ||
6 | * Copyright 2018, Anton Blanchard, IBM Corp. | ||
7 | */ | ||
8 | |||
9 | void _exit(int); | ||
10 | void _start(void) | ||
11 | { | ||
12 | _exit(0); | ||
13 | } | ||
diff --git a/tools/testing/selftests/powerpc/benchmarks/fork.c b/tools/testing/selftests/powerpc/benchmarks/fork.c new file mode 100644 index 000000000000..d312e638cb37 --- /dev/null +++ b/tools/testing/selftests/powerpc/benchmarks/fork.c | |||
@@ -0,0 +1,325 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | |||
3 | /* | ||
4 | * Context switch microbenchmark. | ||
5 | * | ||
6 | * Copyright 2018, Anton Blanchard, IBM Corp. | ||
7 | */ | ||
8 | |||
9 | #define _GNU_SOURCE | ||
10 | #include <assert.h> | ||
11 | #include <errno.h> | ||
12 | #include <getopt.h> | ||
13 | #include <limits.h> | ||
14 | #include <linux/futex.h> | ||
15 | #include <pthread.h> | ||
16 | #include <sched.h> | ||
17 | #include <signal.h> | ||
18 | #include <stdio.h> | ||
19 | #include <stdlib.h> | ||
20 | #include <string.h> | ||
21 | #include <sys/shm.h> | ||
22 | #include <sys/syscall.h> | ||
23 | #include <sys/time.h> | ||
24 | #include <sys/types.h> | ||
25 | #include <sys/wait.h> | ||
26 | #include <unistd.h> | ||
27 | |||
28 | static unsigned int timeout = 30; | ||
29 | |||
30 | static void set_cpu(int cpu) | ||
31 | { | ||
32 | cpu_set_t cpuset; | ||
33 | |||
34 | if (cpu == -1) | ||
35 | return; | ||
36 | |||
37 | CPU_ZERO(&cpuset); | ||
38 | CPU_SET(cpu, &cpuset); | ||
39 | |||
40 | if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) { | ||
41 | perror("sched_setaffinity"); | ||
42 | exit(1); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | static void start_process_on(void *(*fn)(void *), void *arg, int cpu) | ||
47 | { | ||
48 | int pid; | ||
49 | |||
50 | pid = fork(); | ||
51 | if (pid == -1) { | ||
52 | perror("fork"); | ||
53 | exit(1); | ||
54 | } | ||
55 | |||
56 | if (pid) | ||
57 | return; | ||
58 | |||
59 | set_cpu(cpu); | ||
60 | |||
61 | fn(arg); | ||
62 | |||
63 | exit(0); | ||
64 | } | ||
65 | |||
66 | static int cpu; | ||
67 | static int do_fork = 0; | ||
68 | static int do_vfork = 0; | ||
69 | static int do_exec = 0; | ||
70 | static char *exec_file; | ||
71 | static int exec_target = 0; | ||
72 | static unsigned long iterations; | ||
73 | static unsigned long iterations_prev; | ||
74 | |||
75 | static void run_exec(void) | ||
76 | { | ||
77 | char *const argv[] = { "./exec_target", NULL }; | ||
78 | |||
79 | if (execve("./exec_target", argv, NULL) == -1) { | ||
80 | perror("execve"); | ||
81 | exit(1); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | static void bench_fork(void) | ||
86 | { | ||
87 | while (1) { | ||
88 | pid_t pid = fork(); | ||
89 | if (pid == -1) { | ||
90 | perror("fork"); | ||
91 | exit(1); | ||
92 | } | ||
93 | if (pid == 0) { | ||
94 | if (do_exec) | ||
95 | run_exec(); | ||
96 | _exit(0); | ||
97 | } | ||
98 | pid = waitpid(pid, NULL, 0); | ||
99 | if (pid == -1) { | ||
100 | perror("waitpid"); | ||
101 | exit(1); | ||
102 | } | ||
103 | iterations++; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | static void bench_vfork(void) | ||
108 | { | ||
109 | while (1) { | ||
110 | pid_t pid = vfork(); | ||
111 | if (pid == -1) { | ||
112 | perror("fork"); | ||
113 | exit(1); | ||
114 | } | ||
115 | if (pid == 0) { | ||
116 | if (do_exec) | ||
117 | run_exec(); | ||
118 | _exit(0); | ||
119 | } | ||
120 | pid = waitpid(pid, NULL, 0); | ||
121 | if (pid == -1) { | ||
122 | perror("waitpid"); | ||
123 | exit(1); | ||
124 | } | ||
125 | iterations++; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | static void *null_fn(void *arg) | ||
130 | { | ||
131 | pthread_exit(NULL); | ||
132 | } | ||
133 | |||
134 | static void bench_thread(void) | ||
135 | { | ||
136 | pthread_t tid; | ||
137 | cpu_set_t cpuset; | ||
138 | pthread_attr_t attr; | ||
139 | int rc; | ||
140 | |||
141 | rc = pthread_attr_init(&attr); | ||
142 | if (rc) { | ||
143 | errno = rc; | ||
144 | perror("pthread_attr_init"); | ||
145 | exit(1); | ||
146 | } | ||
147 | |||
148 | if (cpu != -1) { | ||
149 | CPU_ZERO(&cpuset); | ||
150 | CPU_SET(cpu, &cpuset); | ||
151 | |||
152 | rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset); | ||
153 | if (rc) { | ||
154 | errno = rc; | ||
155 | perror("pthread_attr_setaffinity_np"); | ||
156 | exit(1); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | while (1) { | ||
161 | rc = pthread_create(&tid, &attr, null_fn, NULL); | ||
162 | if (rc) { | ||
163 | errno = rc; | ||
164 | perror("pthread_create"); | ||
165 | exit(1); | ||
166 | } | ||
167 | rc = pthread_join(tid, NULL); | ||
168 | if (rc) { | ||
169 | errno = rc; | ||
170 | perror("pthread_join"); | ||
171 | exit(1); | ||
172 | } | ||
173 | iterations++; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | static void sigalrm_handler(int junk) | ||
178 | { | ||
179 | unsigned long i = iterations; | ||
180 | |||
181 | printf("%ld\n", i - iterations_prev); | ||
182 | iterations_prev = i; | ||
183 | |||
184 | if (--timeout == 0) | ||
185 | kill(0, SIGUSR1); | ||
186 | |||
187 | alarm(1); | ||
188 | } | ||
189 | |||
190 | static void sigusr1_handler(int junk) | ||
191 | { | ||
192 | exit(0); | ||
193 | } | ||
194 | |||
195 | static void *bench_proc(void *arg) | ||
196 | { | ||
197 | signal(SIGALRM, sigalrm_handler); | ||
198 | alarm(1); | ||
199 | |||
200 | if (do_fork) | ||
201 | bench_fork(); | ||
202 | else if (do_vfork) | ||
203 | bench_vfork(); | ||
204 | else | ||
205 | bench_thread(); | ||
206 | |||
207 | return NULL; | ||
208 | } | ||
209 | |||
210 | static struct option options[] = { | ||
211 | { "fork", no_argument, &do_fork, 1 }, | ||
212 | { "vfork", no_argument, &do_vfork, 1 }, | ||
213 | { "exec", no_argument, &do_exec, 1 }, | ||
214 | { "timeout", required_argument, 0, 's' }, | ||
215 | { "exec-target", no_argument, &exec_target, 1 }, | ||
216 | { NULL }, | ||
217 | }; | ||
218 | |||
219 | static void usage(void) | ||
220 | { | ||
221 | fprintf(stderr, "Usage: fork <options> CPU\n\n"); | ||
222 | fprintf(stderr, "\t\t--fork\tUse fork() (default threads)\n"); | ||
223 | fprintf(stderr, "\t\t--vfork\tUse vfork() (default threads)\n"); | ||
224 | fprintf(stderr, "\t\t--exec\tAlso exec() (default no exec)\n"); | ||
225 | fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n"); | ||
226 | fprintf(stderr, "\t\t--exec-target\tInternal option for exec workload\n"); | ||
227 | } | ||
228 | |||
229 | int main(int argc, char *argv[]) | ||
230 | { | ||
231 | signed char c; | ||
232 | |||
233 | while (1) { | ||
234 | int option_index = 0; | ||
235 | |||
236 | c = getopt_long(argc, argv, "", options, &option_index); | ||
237 | |||
238 | if (c == -1) | ||
239 | break; | ||
240 | |||
241 | switch (c) { | ||
242 | case 0: | ||
243 | if (options[option_index].flag != 0) | ||
244 | break; | ||
245 | |||
246 | usage(); | ||
247 | exit(1); | ||
248 | break; | ||
249 | |||
250 | case 's': | ||
251 | timeout = atoi(optarg); | ||
252 | break; | ||
253 | |||
254 | default: | ||
255 | usage(); | ||
256 | exit(1); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | if (do_fork && do_vfork) { | ||
261 | usage(); | ||
262 | exit(1); | ||
263 | } | ||
264 | if (do_exec && !do_fork && !do_vfork) { | ||
265 | usage(); | ||
266 | exit(1); | ||
267 | } | ||
268 | |||
269 | if (do_exec) { | ||
270 | char *dirname = strdup(argv[0]); | ||
271 | int i; | ||
272 | i = strlen(dirname) - 1; | ||
273 | while (i) { | ||
274 | if (dirname[i] == '/') { | ||
275 | dirname[i] = '\0'; | ||
276 | if (chdir(dirname) == -1) { | ||
277 | perror("chdir"); | ||
278 | exit(1); | ||
279 | } | ||
280 | break; | ||
281 | } | ||
282 | i--; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | if (exec_target) { | ||
287 | exit(0); | ||
288 | } | ||
289 | |||
290 | if (((argc - optind) != 1)) { | ||
291 | cpu = -1; | ||
292 | } else { | ||
293 | cpu = atoi(argv[optind++]); | ||
294 | } | ||
295 | |||
296 | if (do_exec) | ||
297 | exec_file = argv[0]; | ||
298 | |||
299 | set_cpu(cpu); | ||
300 | |||
301 | printf("Using "); | ||
302 | if (do_fork) | ||
303 | printf("fork"); | ||
304 | else if (do_vfork) | ||
305 | printf("vfork"); | ||
306 | else | ||
307 | printf("clone"); | ||
308 | |||
309 | if (do_exec) | ||
310 | printf(" + exec"); | ||
311 | |||
312 | printf(" on cpu %d\n", cpu); | ||
313 | |||
314 | /* Create a new process group so we can signal everyone for exit */ | ||
315 | setpgid(getpid(), getpid()); | ||
316 | |||
317 | signal(SIGUSR1, sigusr1_handler); | ||
318 | |||
319 | start_process_on(bench_proc, NULL, cpu); | ||
320 | |||
321 | while (1) | ||
322 | sleep(3600); | ||
323 | |||
324 | return 0; | ||
325 | } | ||
diff --git a/tools/testing/selftests/powerpc/copyloops/Makefile b/tools/testing/selftests/powerpc/copyloops/Makefile index ac4a52e19e59..eedce3366f64 100644 --- a/tools/testing/selftests/powerpc/copyloops/Makefile +++ b/tools/testing/selftests/powerpc/copyloops/Makefile | |||
@@ -5,8 +5,8 @@ CFLAGS += -I$(CURDIR) | |||
5 | CFLAGS += -D SELFTEST | 5 | CFLAGS += -D SELFTEST |
6 | CFLAGS += -maltivec | 6 | CFLAGS += -maltivec |
7 | 7 | ||
8 | # Use our CFLAGS for the implicit .S rule | 8 | # Use our CFLAGS for the implicit .S rule & set the asm machine type |
9 | ASFLAGS = $(CFLAGS) | 9 | ASFLAGS = $(CFLAGS) -Wa,-mpower4 |
10 | 10 | ||
11 | TEST_GEN_PROGS := copyuser_64 copyuser_power7 memcpy_64 memcpy_power7 | 11 | TEST_GEN_PROGS := copyuser_64 copyuser_power7 memcpy_64 memcpy_power7 |
12 | EXTRA_SOURCES := validate.c ../harness.c | 12 | EXTRA_SOURCES := validate.c ../harness.c |
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index 5c72ff978f27..c0e45d2dde25 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile | |||
@@ -4,7 +4,7 @@ SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu | |||
4 | 4 | ||
5 | TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ | 5 | TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ |
6 | tm-vmxcopy tm-fork tm-tar tm-tmspr tm-vmx-unavail tm-unavailable tm-trap \ | 6 | tm-vmxcopy tm-fork tm-tar tm-tmspr tm-vmx-unavail tm-unavailable tm-trap \ |
7 | $(SIGNAL_CONTEXT_CHK_TESTS) | 7 | $(SIGNAL_CONTEXT_CHK_TESTS) tm-sigreturn |
8 | 8 | ||
9 | include ../../lib.mk | 9 | include ../../lib.mk |
10 | 10 | ||
diff --git a/tools/testing/selftests/powerpc/tm/tm-sigreturn.c b/tools/testing/selftests/powerpc/tm/tm-sigreturn.c new file mode 100644 index 000000000000..85d63449243b --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-sigreturn.c | |||
@@ -0,0 +1,92 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | /* | ||
4 | * Copyright 2015, Laurent Dufour, IBM Corp. | ||
5 | * | ||
6 | * Test the kernel's signal returning code to check reclaim is done if the | ||
7 | * sigreturn() is called while in a transaction (suspended since active is | ||
8 | * already dropped trough the system call path). | ||
9 | * | ||
10 | * The kernel must discard the transaction when entering sigreturn, since | ||
11 | * restoring the potential TM SPRS from the signal frame is requiring to not be | ||
12 | * in a transaction. | ||
13 | */ | ||
14 | |||
15 | #include <signal.h> | ||
16 | #include <stdio.h> | ||
17 | #include <stdlib.h> | ||
18 | #include <string.h> | ||
19 | #include <sys/types.h> | ||
20 | #include <sys/wait.h> | ||
21 | #include <unistd.h> | ||
22 | |||
23 | #include "tm.h" | ||
24 | #include "utils.h" | ||
25 | |||
26 | |||
27 | void handler(int sig) | ||
28 | { | ||
29 | uint64_t ret; | ||
30 | |||
31 | asm __volatile__( | ||
32 | "li 3,1 ;" | ||
33 | "tbegin. ;" | ||
34 | "beq 1f ;" | ||
35 | "li 3,0 ;" | ||
36 | "tsuspend. ;" | ||
37 | "1: ;" | ||
38 | "std%X[ret] 3, %[ret] ;" | ||
39 | : [ret] "=m"(ret) | ||
40 | : | ||
41 | : "memory", "3", "cr0"); | ||
42 | |||
43 | if (ret) | ||
44 | exit(1); | ||
45 | |||
46 | /* | ||
47 | * We return from the signal handle while in a suspended transaction | ||
48 | */ | ||
49 | } | ||
50 | |||
51 | |||
52 | int tm_sigreturn(void) | ||
53 | { | ||
54 | struct sigaction sa; | ||
55 | uint64_t ret = 0; | ||
56 | |||
57 | SKIP_IF(!have_htm()); | ||
58 | |||
59 | memset(&sa, 0, sizeof(sa)); | ||
60 | sa.sa_handler = handler; | ||
61 | sigemptyset(&sa.sa_mask); | ||
62 | |||
63 | if (sigaction(SIGSEGV, &sa, NULL)) | ||
64 | exit(1); | ||
65 | |||
66 | asm __volatile__( | ||
67 | "tbegin. ;" | ||
68 | "beq 1f ;" | ||
69 | "li 3,0 ;" | ||
70 | "std 3,0(3) ;" /* trigger SEGV */ | ||
71 | "li 3,1 ;" | ||
72 | "std%X[ret] 3,%[ret] ;" | ||
73 | "tend. ;" | ||
74 | "b 2f ;" | ||
75 | "1: ;" | ||
76 | "li 3,2 ;" | ||
77 | "std%X[ret] 3,%[ret] ;" | ||
78 | "2: ;" | ||
79 | : [ret] "=m"(ret) | ||
80 | : | ||
81 | : "memory", "3", "cr0"); | ||
82 | |||
83 | if (ret != 2) | ||
84 | exit(1); | ||
85 | |||
86 | exit(0); | ||
87 | } | ||
88 | |||
89 | int main(void) | ||
90 | { | ||
91 | return test_harness(tm_sigreturn, "tm_sigreturn"); | ||
92 | } | ||
diff --git a/tools/testing/selftests/powerpc/tm/tm-unavailable.c b/tools/testing/selftests/powerpc/tm/tm-unavailable.c index e6a0fad2bfd0..156c8e750259 100644 --- a/tools/testing/selftests/powerpc/tm/tm-unavailable.c +++ b/tools/testing/selftests/powerpc/tm/tm-unavailable.c | |||
@@ -80,7 +80,7 @@ bool is_failure(uint64_t condition_reg) | |||
80 | return ((condition_reg >> 28) & 0xa) == 0xa; | 80 | return ((condition_reg >> 28) & 0xa) == 0xa; |
81 | } | 81 | } |
82 | 82 | ||
83 | void *ping(void *input) | 83 | void *tm_una_ping(void *input) |
84 | { | 84 | { |
85 | 85 | ||
86 | /* | 86 | /* |
@@ -280,7 +280,7 @@ void *ping(void *input) | |||
280 | } | 280 | } |
281 | 281 | ||
282 | /* Thread to force context switch */ | 282 | /* Thread to force context switch */ |
283 | void *pong(void *not_used) | 283 | void *tm_una_pong(void *not_used) |
284 | { | 284 | { |
285 | /* Wait thread get its name "pong". */ | 285 | /* Wait thread get its name "pong". */ |
286 | if (DEBUG) | 286 | if (DEBUG) |
@@ -311,11 +311,11 @@ void test_fp_vec(int fp, int vec, pthread_attr_t *attr) | |||
311 | do { | 311 | do { |
312 | int rc; | 312 | int rc; |
313 | 313 | ||
314 | /* Bind 'ping' to CPU 0, as specified in 'attr'. */ | 314 | /* Bind to CPU 0, as specified in 'attr'. */ |
315 | rc = pthread_create(&t0, attr, ping, (void *) &flags); | 315 | rc = pthread_create(&t0, attr, tm_una_ping, (void *) &flags); |
316 | if (rc) | 316 | if (rc) |
317 | pr_err(rc, "pthread_create()"); | 317 | pr_err(rc, "pthread_create()"); |
318 | rc = pthread_setname_np(t0, "ping"); | 318 | rc = pthread_setname_np(t0, "tm_una_ping"); |
319 | if (rc) | 319 | if (rc) |
320 | pr_warn(rc, "pthread_setname_np"); | 320 | pr_warn(rc, "pthread_setname_np"); |
321 | rc = pthread_join(t0, &ret_value); | 321 | rc = pthread_join(t0, &ret_value); |
@@ -333,13 +333,15 @@ void test_fp_vec(int fp, int vec, pthread_attr_t *attr) | |||
333 | } | 333 | } |
334 | } | 334 | } |
335 | 335 | ||
336 | int main(int argc, char **argv) | 336 | int tm_unavailable_test(void) |
337 | { | 337 | { |
338 | int rc, exception; /* FP = 0, VEC = 1, VSX = 2 */ | 338 | int rc, exception; /* FP = 0, VEC = 1, VSX = 2 */ |
339 | pthread_t t1; | 339 | pthread_t t1; |
340 | pthread_attr_t attr; | 340 | pthread_attr_t attr; |
341 | cpu_set_t cpuset; | 341 | cpu_set_t cpuset; |
342 | 342 | ||
343 | SKIP_IF(!have_htm()); | ||
344 | |||
343 | /* Set only CPU 0 in the mask. Both threads will be bound to CPU 0. */ | 345 | /* Set only CPU 0 in the mask. Both threads will be bound to CPU 0. */ |
344 | CPU_ZERO(&cpuset); | 346 | CPU_ZERO(&cpuset); |
345 | CPU_SET(0, &cpuset); | 347 | CPU_SET(0, &cpuset); |
@@ -354,12 +356,12 @@ int main(int argc, char **argv) | |||
354 | if (rc) | 356 | if (rc) |
355 | pr_err(rc, "pthread_attr_setaffinity_np()"); | 357 | pr_err(rc, "pthread_attr_setaffinity_np()"); |
356 | 358 | ||
357 | rc = pthread_create(&t1, &attr /* Bind 'pong' to CPU 0 */, pong, NULL); | 359 | rc = pthread_create(&t1, &attr /* Bind to CPU 0 */, tm_una_pong, NULL); |
358 | if (rc) | 360 | if (rc) |
359 | pr_err(rc, "pthread_create()"); | 361 | pr_err(rc, "pthread_create()"); |
360 | 362 | ||
361 | /* Name it for systemtap convenience */ | 363 | /* Name it for systemtap convenience */ |
362 | rc = pthread_setname_np(t1, "pong"); | 364 | rc = pthread_setname_np(t1, "tm_una_pong"); |
363 | if (rc) | 365 | if (rc) |
364 | pr_warn(rc, "pthread_create()"); | 366 | pr_warn(rc, "pthread_create()"); |
365 | 367 | ||
@@ -394,3 +396,9 @@ int main(int argc, char **argv) | |||
394 | exit(0); | 396 | exit(0); |
395 | } | 397 | } |
396 | } | 398 | } |
399 | |||
400 | int main(int argc, char **argv) | ||
401 | { | ||
402 | test_harness_set_timeout(220); | ||
403 | return test_harness(tm_unavailable_test, "tm_unavailable_test"); | ||
404 | } | ||
diff --git a/tools/testing/selftests/proc/.gitignore b/tools/testing/selftests/proc/.gitignore new file mode 100644 index 000000000000..6c16f77c722c --- /dev/null +++ b/tools/testing/selftests/proc/.gitignore | |||
@@ -0,0 +1,8 @@ | |||
1 | /proc-loadavg-001 | ||
2 | /proc-self-map-files-001 | ||
3 | /proc-self-map-files-002 | ||
4 | /proc-self-syscall | ||
5 | /proc-self-wchan | ||
6 | /proc-uptime-001 | ||
7 | /proc-uptime-002 | ||
8 | /read | ||
diff --git a/tools/testing/selftests/proc/Makefile b/tools/testing/selftests/proc/Makefile new file mode 100644 index 000000000000..dbb87e56264c --- /dev/null +++ b/tools/testing/selftests/proc/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | CFLAGS += -Wall -O2 | ||
2 | |||
3 | TEST_GEN_PROGS := | ||
4 | TEST_GEN_PROGS += proc-loadavg-001 | ||
5 | TEST_GEN_PROGS += proc-self-map-files-001 | ||
6 | TEST_GEN_PROGS += proc-self-map-files-002 | ||
7 | TEST_GEN_PROGS += proc-self-syscall | ||
8 | TEST_GEN_PROGS += proc-self-wchan | ||
9 | TEST_GEN_PROGS += proc-uptime-001 | ||
10 | TEST_GEN_PROGS += proc-uptime-002 | ||
11 | TEST_GEN_PROGS += read | ||
12 | |||
13 | include ../lib.mk | ||
diff --git a/tools/testing/selftests/proc/config b/tools/testing/selftests/proc/config new file mode 100644 index 000000000000..68fbd2b35884 --- /dev/null +++ b/tools/testing/selftests/proc/config | |||
@@ -0,0 +1 @@ | |||
CONFIG_PROC_FS=y | |||
diff --git a/tools/testing/selftests/proc/proc-loadavg-001.c b/tools/testing/selftests/proc/proc-loadavg-001.c new file mode 100644 index 000000000000..fcff7047000d --- /dev/null +++ b/tools/testing/selftests/proc/proc-loadavg-001.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> | ||
3 | * | ||
4 | * Permission to use, copy, modify, and distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | /* Test that /proc/loadavg correctly reports last pid in pid namespace. */ | ||
17 | #define _GNU_SOURCE | ||
18 | #include <errno.h> | ||
19 | #include <sched.h> | ||
20 | #include <sys/types.h> | ||
21 | #include <sys/stat.h> | ||
22 | #include <fcntl.h> | ||
23 | #include <unistd.h> | ||
24 | #include <sys/wait.h> | ||
25 | |||
26 | int main(void) | ||
27 | { | ||
28 | pid_t pid; | ||
29 | int wstatus; | ||
30 | |||
31 | if (unshare(CLONE_NEWPID) == -1) { | ||
32 | if (errno == ENOSYS || errno == EPERM) | ||
33 | return 2; | ||
34 | return 1; | ||
35 | } | ||
36 | |||
37 | pid = fork(); | ||
38 | if (pid == -1) | ||
39 | return 1; | ||
40 | if (pid == 0) { | ||
41 | char buf[128], *p; | ||
42 | int fd; | ||
43 | ssize_t rv; | ||
44 | |||
45 | fd = open("/proc/loadavg" , O_RDONLY); | ||
46 | if (fd == -1) | ||
47 | return 1; | ||
48 | rv = read(fd, buf, sizeof(buf)); | ||
49 | if (rv < 3) | ||
50 | return 1; | ||
51 | p = buf + rv; | ||
52 | |||
53 | /* pid 1 */ | ||
54 | if (!(p[-3] == ' ' && p[-2] == '1' && p[-1] == '\n')) | ||
55 | return 1; | ||
56 | |||
57 | pid = fork(); | ||
58 | if (pid == -1) | ||
59 | return 1; | ||
60 | if (pid == 0) | ||
61 | return 0; | ||
62 | if (waitpid(pid, NULL, 0) == -1) | ||
63 | return 1; | ||
64 | |||
65 | lseek(fd, 0, SEEK_SET); | ||
66 | rv = read(fd, buf, sizeof(buf)); | ||
67 | if (rv < 3) | ||
68 | return 1; | ||
69 | p = buf + rv; | ||
70 | |||
71 | /* pid 2 */ | ||
72 | if (!(p[-3] == ' ' && p[-2] == '2' && p[-1] == '\n')) | ||
73 | return 1; | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | if (waitpid(pid, &wstatus, 0) == -1) | ||
79 | return 1; | ||
80 | if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) | ||
81 | return 0; | ||
82 | return 1; | ||
83 | } | ||
diff --git a/tools/testing/selftests/proc/proc-self-map-files-001.c b/tools/testing/selftests/proc/proc-self-map-files-001.c new file mode 100644 index 000000000000..4209c64283d6 --- /dev/null +++ b/tools/testing/selftests/proc/proc-self-map-files-001.c | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> | ||
3 | * | ||
4 | * Permission to use, copy, modify, and distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | /* Test readlink /proc/self/map_files/... */ | ||
17 | #include <errno.h> | ||
18 | #include <sys/types.h> | ||
19 | #include <sys/stat.h> | ||
20 | #include <fcntl.h> | ||
21 | #include <stdio.h> | ||
22 | #include <unistd.h> | ||
23 | #include <sys/mman.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | static void pass(const char *fmt, unsigned long a, unsigned long b) | ||
27 | { | ||
28 | char name[64]; | ||
29 | char buf[64]; | ||
30 | |||
31 | snprintf(name, sizeof(name), fmt, a, b); | ||
32 | if (readlink(name, buf, sizeof(buf)) == -1) | ||
33 | exit(1); | ||
34 | } | ||
35 | |||
36 | static void fail(const char *fmt, unsigned long a, unsigned long b) | ||
37 | { | ||
38 | char name[64]; | ||
39 | char buf[64]; | ||
40 | |||
41 | snprintf(name, sizeof(name), fmt, a, b); | ||
42 | if (readlink(name, buf, sizeof(buf)) == -1 && errno == ENOENT) | ||
43 | return; | ||
44 | exit(1); | ||
45 | } | ||
46 | |||
47 | int main(void) | ||
48 | { | ||
49 | const unsigned int PAGE_SIZE = sysconf(_SC_PAGESIZE); | ||
50 | void *p; | ||
51 | int fd; | ||
52 | unsigned long a, b; | ||
53 | |||
54 | fd = open("/dev/zero", O_RDONLY); | ||
55 | if (fd == -1) | ||
56 | return 1; | ||
57 | |||
58 | p = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE|MAP_FILE, fd, 0); | ||
59 | if (p == MAP_FAILED) | ||
60 | return 1; | ||
61 | |||
62 | a = (unsigned long)p; | ||
63 | b = (unsigned long)p + PAGE_SIZE; | ||
64 | |||
65 | pass("/proc/self/map_files/%lx-%lx", a, b); | ||
66 | fail("/proc/self/map_files/ %lx-%lx", a, b); | ||
67 | fail("/proc/self/map_files/%lx -%lx", a, b); | ||
68 | fail("/proc/self/map_files/%lx- %lx", a, b); | ||
69 | fail("/proc/self/map_files/%lx-%lx ", a, b); | ||
70 | fail("/proc/self/map_files/0%lx-%lx", a, b); | ||
71 | fail("/proc/self/map_files/%lx-0%lx", a, b); | ||
72 | if (sizeof(long) == 4) { | ||
73 | fail("/proc/self/map_files/100000000%lx-%lx", a, b); | ||
74 | fail("/proc/self/map_files/%lx-100000000%lx", a, b); | ||
75 | } else if (sizeof(long) == 8) { | ||
76 | fail("/proc/self/map_files/10000000000000000%lx-%lx", a, b); | ||
77 | fail("/proc/self/map_files/%lx-10000000000000000%lx", a, b); | ||
78 | } else | ||
79 | return 1; | ||
80 | |||
81 | return 0; | ||
82 | } | ||
diff --git a/tools/testing/selftests/proc/proc-self-map-files-002.c b/tools/testing/selftests/proc/proc-self-map-files-002.c new file mode 100644 index 000000000000..6f1f4a6e1ecb --- /dev/null +++ b/tools/testing/selftests/proc/proc-self-map-files-002.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> | ||
3 | * | ||
4 | * Permission to use, copy, modify, and distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | /* Test readlink /proc/self/map_files/... with address 0. */ | ||
17 | #include <errno.h> | ||
18 | #include <sys/types.h> | ||
19 | #include <sys/stat.h> | ||
20 | #include <fcntl.h> | ||
21 | #include <stdio.h> | ||
22 | #include <unistd.h> | ||
23 | #include <sys/mman.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | static void pass(const char *fmt, unsigned long a, unsigned long b) | ||
27 | { | ||
28 | char name[64]; | ||
29 | char buf[64]; | ||
30 | |||
31 | snprintf(name, sizeof(name), fmt, a, b); | ||
32 | if (readlink(name, buf, sizeof(buf)) == -1) | ||
33 | exit(1); | ||
34 | } | ||
35 | |||
36 | static void fail(const char *fmt, unsigned long a, unsigned long b) | ||
37 | { | ||
38 | char name[64]; | ||
39 | char buf[64]; | ||
40 | |||
41 | snprintf(name, sizeof(name), fmt, a, b); | ||
42 | if (readlink(name, buf, sizeof(buf)) == -1 && errno == ENOENT) | ||
43 | return; | ||
44 | exit(1); | ||
45 | } | ||
46 | |||
47 | int main(void) | ||
48 | { | ||
49 | const unsigned int PAGE_SIZE = sysconf(_SC_PAGESIZE); | ||
50 | void *p; | ||
51 | int fd; | ||
52 | unsigned long a, b; | ||
53 | |||
54 | fd = open("/dev/zero", O_RDONLY); | ||
55 | if (fd == -1) | ||
56 | return 1; | ||
57 | |||
58 | p = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE|MAP_FILE|MAP_FIXED, fd, 0); | ||
59 | if (p == MAP_FAILED) { | ||
60 | if (errno == EPERM) | ||
61 | return 2; | ||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | a = (unsigned long)p; | ||
66 | b = (unsigned long)p + PAGE_SIZE; | ||
67 | |||
68 | pass("/proc/self/map_files/%lx-%lx", a, b); | ||
69 | fail("/proc/self/map_files/ %lx-%lx", a, b); | ||
70 | fail("/proc/self/map_files/%lx -%lx", a, b); | ||
71 | fail("/proc/self/map_files/%lx- %lx", a, b); | ||
72 | fail("/proc/self/map_files/%lx-%lx ", a, b); | ||
73 | fail("/proc/self/map_files/0%lx-%lx", a, b); | ||
74 | fail("/proc/self/map_files/%lx-0%lx", a, b); | ||
75 | if (sizeof(long) == 4) { | ||
76 | fail("/proc/self/map_files/100000000%lx-%lx", a, b); | ||
77 | fail("/proc/self/map_files/%lx-100000000%lx", a, b); | ||
78 | } else if (sizeof(long) == 8) { | ||
79 | fail("/proc/self/map_files/10000000000000000%lx-%lx", a, b); | ||
80 | fail("/proc/self/map_files/%lx-10000000000000000%lx", a, b); | ||
81 | } else | ||
82 | return 1; | ||
83 | |||
84 | return 0; | ||
85 | } | ||
diff --git a/tools/testing/selftests/proc/proc-self-syscall.c b/tools/testing/selftests/proc/proc-self-syscall.c new file mode 100644 index 000000000000..5ab5f4810e43 --- /dev/null +++ b/tools/testing/selftests/proc/proc-self-syscall.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> | ||
3 | * | ||
4 | * Permission to use, copy, modify, and distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | #define _GNU_SOURCE | ||
17 | #include <unistd.h> | ||
18 | #include <sys/syscall.h> | ||
19 | #include <sys/types.h> | ||
20 | #include <sys/stat.h> | ||
21 | #include <fcntl.h> | ||
22 | #include <errno.h> | ||
23 | #include <unistd.h> | ||
24 | #include <string.h> | ||
25 | #include <stdio.h> | ||
26 | |||
27 | static inline ssize_t sys_read(int fd, void *buf, size_t len) | ||
28 | { | ||
29 | return syscall(SYS_read, fd, buf, len); | ||
30 | } | ||
31 | |||
32 | int main(void) | ||
33 | { | ||
34 | char buf1[64]; | ||
35 | char buf2[64]; | ||
36 | int fd; | ||
37 | ssize_t rv; | ||
38 | |||
39 | fd = open("/proc/self/syscall", O_RDONLY); | ||
40 | if (fd == -1) { | ||
41 | if (errno == ENOENT) | ||
42 | return 2; | ||
43 | return 1; | ||
44 | } | ||
45 | |||
46 | /* Do direct system call as libc can wrap anything. */ | ||
47 | snprintf(buf1, sizeof(buf1), "%ld 0x%lx 0x%lx 0x%lx", | ||
48 | (long)SYS_read, (long)fd, (long)buf2, (long)sizeof(buf2)); | ||
49 | |||
50 | memset(buf2, 0, sizeof(buf2)); | ||
51 | rv = sys_read(fd, buf2, sizeof(buf2)); | ||
52 | if (rv < 0) | ||
53 | return 1; | ||
54 | if (rv < strlen(buf1)) | ||
55 | return 1; | ||
56 | if (strncmp(buf1, buf2, strlen(buf1)) != 0) | ||
57 | return 1; | ||
58 | |||
59 | return 0; | ||
60 | } | ||
diff --git a/tools/testing/selftests/proc/proc-self-wchan.c b/tools/testing/selftests/proc/proc-self-wchan.c new file mode 100644 index 000000000000..a38b2fbaa7ad --- /dev/null +++ b/tools/testing/selftests/proc/proc-self-wchan.c | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> | ||
3 | * | ||
4 | * Permission to use, copy, modify, and distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | #include <sys/types.h> | ||
17 | #include <sys/stat.h> | ||
18 | #include <fcntl.h> | ||
19 | #include <errno.h> | ||
20 | #include <unistd.h> | ||
21 | |||
22 | int main(void) | ||
23 | { | ||
24 | char buf[64]; | ||
25 | int fd; | ||
26 | |||
27 | fd = open("/proc/self/wchan", O_RDONLY); | ||
28 | if (fd == -1) { | ||
29 | if (errno == ENOENT) | ||
30 | return 2; | ||
31 | return 1; | ||
32 | } | ||
33 | |||
34 | buf[0] = '\0'; | ||
35 | if (read(fd, buf, sizeof(buf)) != 1) | ||
36 | return 1; | ||
37 | if (buf[0] != '0') | ||
38 | return 1; | ||
39 | return 0; | ||
40 | } | ||
diff --git a/tools/testing/selftests/proc/proc-uptime-001.c b/tools/testing/selftests/proc/proc-uptime-001.c new file mode 100644 index 000000000000..781f7a50fc3f --- /dev/null +++ b/tools/testing/selftests/proc/proc-uptime-001.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> | ||
3 | * | ||
4 | * Permission to use, copy, modify, and distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | // Test that values in /proc/uptime increment monotonically. | ||
17 | #undef NDEBUG | ||
18 | #include <assert.h> | ||
19 | #include <stdint.h> | ||
20 | #include <sys/types.h> | ||
21 | #include <sys/stat.h> | ||
22 | #include <fcntl.h> | ||
23 | |||
24 | #include "proc-uptime.h" | ||
25 | |||
26 | int main(void) | ||
27 | { | ||
28 | uint64_t start, u0, u1, i0, i1; | ||
29 | int fd; | ||
30 | |||
31 | fd = open("/proc/uptime", O_RDONLY); | ||
32 | assert(fd >= 0); | ||
33 | |||
34 | proc_uptime(fd, &u0, &i0); | ||
35 | start = u0; | ||
36 | do { | ||
37 | proc_uptime(fd, &u1, &i1); | ||
38 | assert(u1 >= u0); | ||
39 | assert(i1 >= i0); | ||
40 | u0 = u1; | ||
41 | i0 = i1; | ||
42 | } while (u1 - start < 100); | ||
43 | |||
44 | return 0; | ||
45 | } | ||
diff --git a/tools/testing/selftests/proc/proc-uptime-002.c b/tools/testing/selftests/proc/proc-uptime-002.c new file mode 100644 index 000000000000..30e2b7849089 --- /dev/null +++ b/tools/testing/selftests/proc/proc-uptime-002.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> | ||
3 | * | ||
4 | * Permission to use, copy, modify, and distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | // Test that values in /proc/uptime increment monotonically | ||
17 | // while shifting across CPUs. | ||
18 | #define _GNU_SOURCE | ||
19 | #undef NDEBUG | ||
20 | #include <assert.h> | ||
21 | #include <unistd.h> | ||
22 | #include <sys/syscall.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | |||
26 | #include <stdint.h> | ||
27 | #include <sys/types.h> | ||
28 | #include <sys/stat.h> | ||
29 | #include <fcntl.h> | ||
30 | |||
31 | #include "proc-uptime.h" | ||
32 | |||
33 | static inline int sys_sched_getaffinity(pid_t pid, unsigned int len, unsigned long *m) | ||
34 | { | ||
35 | return syscall(SYS_sched_getaffinity, pid, len, m); | ||
36 | } | ||
37 | |||
38 | static inline int sys_sched_setaffinity(pid_t pid, unsigned int len, unsigned long *m) | ||
39 | { | ||
40 | return syscall(SYS_sched_setaffinity, pid, len, m); | ||
41 | } | ||
42 | |||
43 | int main(void) | ||
44 | { | ||
45 | unsigned int len; | ||
46 | unsigned long *m; | ||
47 | unsigned int cpu; | ||
48 | uint64_t u0, u1, i0, i1; | ||
49 | int fd; | ||
50 | |||
51 | /* find out "nr_cpu_ids" */ | ||
52 | m = NULL; | ||
53 | len = 0; | ||
54 | do { | ||
55 | len += sizeof(unsigned long); | ||
56 | free(m); | ||
57 | m = malloc(len); | ||
58 | } while (sys_sched_getaffinity(0, len, m) == -EINVAL); | ||
59 | |||
60 | fd = open("/proc/uptime", O_RDONLY); | ||
61 | assert(fd >= 0); | ||
62 | |||
63 | proc_uptime(fd, &u0, &i0); | ||
64 | for (cpu = 0; cpu < len * 8; cpu++) { | ||
65 | memset(m, 0, len); | ||
66 | m[cpu / (8 * sizeof(unsigned long))] |= 1UL << (cpu % (8 * sizeof(unsigned long))); | ||
67 | |||
68 | /* CPU might not exist, ignore error */ | ||
69 | sys_sched_setaffinity(0, len, m); | ||
70 | |||
71 | proc_uptime(fd, &u1, &i1); | ||
72 | assert(u1 >= u0); | ||
73 | assert(i1 >= i0); | ||
74 | u0 = u1; | ||
75 | i0 = i1; | ||
76 | } | ||
77 | |||
78 | return 0; | ||
79 | } | ||
diff --git a/tools/testing/selftests/proc/proc-uptime.h b/tools/testing/selftests/proc/proc-uptime.h new file mode 100644 index 000000000000..0e464b50e9d9 --- /dev/null +++ b/tools/testing/selftests/proc/proc-uptime.h | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> | ||
3 | * | ||
4 | * Permission to use, copy, modify, and distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | #undef NDEBUG | ||
17 | #include <assert.h> | ||
18 | #include <errno.h> | ||
19 | #include <string.h> | ||
20 | #include <stdlib.h> | ||
21 | #include <unistd.h> | ||
22 | |||
23 | static unsigned long long xstrtoull(const char *p, char **end) | ||
24 | { | ||
25 | if (*p == '0') { | ||
26 | *end = (char *)p + 1; | ||
27 | return 0; | ||
28 | } else if ('1' <= *p && *p <= '9') { | ||
29 | unsigned long long val; | ||
30 | |||
31 | errno = 0; | ||
32 | val = strtoull(p, end, 10); | ||
33 | assert(errno == 0); | ||
34 | return val; | ||
35 | } else | ||
36 | assert(0); | ||
37 | } | ||
38 | |||
39 | static void proc_uptime(int fd, uint64_t *uptime, uint64_t *idle) | ||
40 | { | ||
41 | uint64_t val1, val2; | ||
42 | char buf[64], *p; | ||
43 | ssize_t rv; | ||
44 | |||
45 | /* save "p < end" checks */ | ||
46 | memset(buf, 0, sizeof(buf)); | ||
47 | rv = pread(fd, buf, sizeof(buf), 0); | ||
48 | assert(0 <= rv && rv <= sizeof(buf)); | ||
49 | buf[sizeof(buf) - 1] = '\0'; | ||
50 | |||
51 | p = buf; | ||
52 | |||
53 | val1 = xstrtoull(p, &p); | ||
54 | assert(p[0] == '.'); | ||
55 | assert('0' <= p[1] && p[1] <= '9'); | ||
56 | assert('0' <= p[2] && p[2] <= '9'); | ||
57 | assert(p[3] == ' '); | ||
58 | |||
59 | val2 = (p[1] - '0') * 10 + p[2] - '0'; | ||
60 | *uptime = val1 * 100 + val2; | ||
61 | |||
62 | p += 4; | ||
63 | |||
64 | val1 = xstrtoull(p, &p); | ||
65 | assert(p[0] == '.'); | ||
66 | assert('0' <= p[1] && p[1] <= '9'); | ||
67 | assert('0' <= p[2] && p[2] <= '9'); | ||
68 | assert(p[3] == '\n'); | ||
69 | |||
70 | val2 = (p[1] - '0') * 10 + p[2] - '0'; | ||
71 | *idle = val1 * 100 + val2; | ||
72 | |||
73 | assert(p + 4 == buf + rv); | ||
74 | } | ||
diff --git a/tools/testing/selftests/proc/read.c b/tools/testing/selftests/proc/read.c new file mode 100644 index 000000000000..1e73c2232097 --- /dev/null +++ b/tools/testing/selftests/proc/read.c | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> | ||
3 | * | ||
4 | * Permission to use, copy, modify, and distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | // Test | ||
17 | // 1) read of every file in /proc | ||
18 | // 2) readlink of every symlink in /proc | ||
19 | // 3) recursively (1) + (2) for every directory in /proc | ||
20 | // 4) write to /proc/*/clear_refs and /proc/*/task/*/clear_refs | ||
21 | // 5) write to /proc/sysrq-trigger | ||
22 | #undef NDEBUG | ||
23 | #include <assert.h> | ||
24 | #include <errno.h> | ||
25 | #include <sys/types.h> | ||
26 | #include <dirent.h> | ||
27 | #include <stdbool.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <string.h> | ||
30 | #include <sys/stat.h> | ||
31 | #include <fcntl.h> | ||
32 | #include <unistd.h> | ||
33 | |||
34 | static inline bool streq(const char *s1, const char *s2) | ||
35 | { | ||
36 | return strcmp(s1, s2) == 0; | ||
37 | } | ||
38 | |||
39 | static struct dirent *xreaddir(DIR *d) | ||
40 | { | ||
41 | struct dirent *de; | ||
42 | |||
43 | errno = 0; | ||
44 | de = readdir(d); | ||
45 | if (!de && errno != 0) { | ||
46 | exit(1); | ||
47 | } | ||
48 | return de; | ||
49 | } | ||
50 | |||
51 | static void f_reg(DIR *d, const char *filename) | ||
52 | { | ||
53 | char buf[4096]; | ||
54 | int fd; | ||
55 | ssize_t rv; | ||
56 | |||
57 | /* read from /proc/kmsg can block */ | ||
58 | fd = openat(dirfd(d), filename, O_RDONLY|O_NONBLOCK); | ||
59 | if (fd == -1) | ||
60 | return; | ||
61 | rv = read(fd, buf, sizeof(buf)); | ||
62 | assert((0 <= rv && rv <= sizeof(buf)) || rv == -1); | ||
63 | close(fd); | ||
64 | } | ||
65 | |||
66 | static void f_reg_write(DIR *d, const char *filename, const char *buf, size_t len) | ||
67 | { | ||
68 | int fd; | ||
69 | ssize_t rv; | ||
70 | |||
71 | fd = openat(dirfd(d), filename, O_WRONLY); | ||
72 | if (fd == -1) | ||
73 | return; | ||
74 | rv = write(fd, buf, len); | ||
75 | assert((0 <= rv && rv <= len) || rv == -1); | ||
76 | close(fd); | ||
77 | } | ||
78 | |||
79 | static void f_lnk(DIR *d, const char *filename) | ||
80 | { | ||
81 | char buf[4096]; | ||
82 | ssize_t rv; | ||
83 | |||
84 | rv = readlinkat(dirfd(d), filename, buf, sizeof(buf)); | ||
85 | assert((0 <= rv && rv <= sizeof(buf)) || rv == -1); | ||
86 | } | ||
87 | |||
88 | static void f(DIR *d, unsigned int level) | ||
89 | { | ||
90 | struct dirent *de; | ||
91 | |||
92 | de = xreaddir(d); | ||
93 | assert(de->d_type == DT_DIR); | ||
94 | assert(streq(de->d_name, ".")); | ||
95 | |||
96 | de = xreaddir(d); | ||
97 | assert(de->d_type == DT_DIR); | ||
98 | assert(streq(de->d_name, "..")); | ||
99 | |||
100 | while ((de = xreaddir(d))) { | ||
101 | assert(!streq(de->d_name, ".")); | ||
102 | assert(!streq(de->d_name, "..")); | ||
103 | |||
104 | switch (de->d_type) { | ||
105 | DIR *dd; | ||
106 | int fd; | ||
107 | |||
108 | case DT_REG: | ||
109 | if (level == 0 && streq(de->d_name, "sysrq-trigger")) { | ||
110 | f_reg_write(d, de->d_name, "h", 1); | ||
111 | } else if (level == 1 && streq(de->d_name, "clear_refs")) { | ||
112 | f_reg_write(d, de->d_name, "1", 1); | ||
113 | } else if (level == 3 && streq(de->d_name, "clear_refs")) { | ||
114 | f_reg_write(d, de->d_name, "1", 1); | ||
115 | } else { | ||
116 | f_reg(d, de->d_name); | ||
117 | } | ||
118 | break; | ||
119 | case DT_DIR: | ||
120 | fd = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY); | ||
121 | if (fd == -1) | ||
122 | continue; | ||
123 | dd = fdopendir(fd); | ||
124 | if (!dd) | ||
125 | continue; | ||
126 | f(dd, level + 1); | ||
127 | closedir(dd); | ||
128 | break; | ||
129 | case DT_LNK: | ||
130 | f_lnk(d, de->d_name); | ||
131 | break; | ||
132 | default: | ||
133 | assert(0); | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | int main(void) | ||
139 | { | ||
140 | DIR *d; | ||
141 | |||
142 | d = opendir("/proc"); | ||
143 | if (!d) | ||
144 | return 2; | ||
145 | f(d, 0); | ||
146 | return 0; | ||
147 | } | ||
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 5df609950a66..168c66d74fc5 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c | |||
@@ -2860,6 +2860,7 @@ TEST(get_metadata) | |||
2860 | int pipefd[2]; | 2860 | int pipefd[2]; |
2861 | char buf; | 2861 | char buf; |
2862 | struct seccomp_metadata md; | 2862 | struct seccomp_metadata md; |
2863 | long ret; | ||
2863 | 2864 | ||
2864 | ASSERT_EQ(0, pipe(pipefd)); | 2865 | ASSERT_EQ(0, pipe(pipefd)); |
2865 | 2866 | ||
@@ -2893,16 +2894,26 @@ TEST(get_metadata) | |||
2893 | ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid)); | 2894 | ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid)); |
2894 | ASSERT_EQ(pid, waitpid(pid, NULL, 0)); | 2895 | ASSERT_EQ(pid, waitpid(pid, NULL, 0)); |
2895 | 2896 | ||
2897 | /* Past here must not use ASSERT or child process is never killed. */ | ||
2898 | |||
2896 | md.filter_off = 0; | 2899 | md.filter_off = 0; |
2897 | ASSERT_EQ(sizeof(md), ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md)); | 2900 | errno = 0; |
2901 | ret = ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md); | ||
2902 | EXPECT_EQ(sizeof(md), ret) { | ||
2903 | if (errno == EINVAL) | ||
2904 | XFAIL(goto skip, "Kernel does not support PTRACE_SECCOMP_GET_METADATA (missing CONFIG_CHECKPOINT_RESTORE?)"); | ||
2905 | } | ||
2906 | |||
2898 | EXPECT_EQ(md.flags, SECCOMP_FILTER_FLAG_LOG); | 2907 | EXPECT_EQ(md.flags, SECCOMP_FILTER_FLAG_LOG); |
2899 | EXPECT_EQ(md.filter_off, 0); | 2908 | EXPECT_EQ(md.filter_off, 0); |
2900 | 2909 | ||
2901 | md.filter_off = 1; | 2910 | md.filter_off = 1; |
2902 | ASSERT_EQ(sizeof(md), ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md)); | 2911 | ret = ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md); |
2912 | EXPECT_EQ(sizeof(md), ret); | ||
2903 | EXPECT_EQ(md.flags, 0); | 2913 | EXPECT_EQ(md.flags, 0); |
2904 | EXPECT_EQ(md.filter_off, 1); | 2914 | EXPECT_EQ(md.filter_off, 1); |
2905 | 2915 | ||
2916 | skip: | ||
2906 | ASSERT_EQ(0, kill(pid, SIGKILL)); | 2917 | ASSERT_EQ(0, kill(pid, SIGKILL)); |
2907 | } | 2918 | } |
2908 | 2919 | ||
diff --git a/tools/thermal/tmon/sysfs.c b/tools/thermal/tmon/sysfs.c index 1c12536f2081..18f523557983 100644 --- a/tools/thermal/tmon/sysfs.c +++ b/tools/thermal/tmon/sysfs.c | |||
@@ -486,6 +486,7 @@ int zone_instance_to_index(int zone_inst) | |||
486 | int update_thermal_data() | 486 | int update_thermal_data() |
487 | { | 487 | { |
488 | int i; | 488 | int i; |
489 | int next_thermal_record = cur_thermal_record + 1; | ||
489 | char tz_name[256]; | 490 | char tz_name[256]; |
490 | static unsigned long samples; | 491 | static unsigned long samples; |
491 | 492 | ||
@@ -495,9 +496,9 @@ int update_thermal_data() | |||
495 | } | 496 | } |
496 | 497 | ||
497 | /* circular buffer for keeping historic data */ | 498 | /* circular buffer for keeping historic data */ |
498 | if (cur_thermal_record >= NR_THERMAL_RECORDS) | 499 | if (next_thermal_record >= NR_THERMAL_RECORDS) |
499 | cur_thermal_record = 0; | 500 | next_thermal_record = 0; |
500 | gettimeofday(&trec[cur_thermal_record].tv, NULL); | 501 | gettimeofday(&trec[next_thermal_record].tv, NULL); |
501 | if (tmon_log) { | 502 | if (tmon_log) { |
502 | fprintf(tmon_log, "%lu ", ++samples); | 503 | fprintf(tmon_log, "%lu ", ++samples); |
503 | fprintf(tmon_log, "%3.1f ", p_param.t_target); | 504 | fprintf(tmon_log, "%3.1f ", p_param.t_target); |
@@ -507,11 +508,12 @@ int update_thermal_data() | |||
507 | snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, | 508 | snprintf(tz_name, 256, "%s/%s%d", THERMAL_SYSFS, TZONE, |
508 | ptdata.tzi[i].instance); | 509 | ptdata.tzi[i].instance); |
509 | sysfs_get_ulong(tz_name, "temp", | 510 | sysfs_get_ulong(tz_name, "temp", |
510 | &trec[cur_thermal_record].temp[i]); | 511 | &trec[next_thermal_record].temp[i]); |
511 | if (tmon_log) | 512 | if (tmon_log) |
512 | fprintf(tmon_log, "%lu ", | 513 | fprintf(tmon_log, "%lu ", |
513 | trec[cur_thermal_record].temp[i]/1000); | 514 | trec[next_thermal_record].temp[i] / 1000); |
514 | } | 515 | } |
516 | cur_thermal_record = next_thermal_record; | ||
515 | for (i = 0; i < ptdata.nr_cooling_dev; i++) { | 517 | for (i = 0; i < ptdata.nr_cooling_dev; i++) { |
516 | char cdev_name[256]; | 518 | char cdev_name[256]; |
517 | unsigned long val; | 519 | unsigned long val; |
diff --git a/tools/thermal/tmon/tmon.c b/tools/thermal/tmon/tmon.c index 9aa19652e8e8..b43138f8b862 100644 --- a/tools/thermal/tmon/tmon.c +++ b/tools/thermal/tmon/tmon.c | |||
@@ -336,7 +336,6 @@ int main(int argc, char **argv) | |||
336 | show_data_w(); | 336 | show_data_w(); |
337 | show_cooling_device(); | 337 | show_cooling_device(); |
338 | } | 338 | } |
339 | cur_thermal_record++; | ||
340 | time_elapsed += ticktime; | 339 | time_elapsed += ticktime; |
341 | controller_handler(trec[0].temp[target_tz_index] / 1000, | 340 | controller_handler(trec[0].temp[target_tz_index] / 1000, |
342 | &yk); | 341 | &yk); |
diff --git a/tools/virtio/ringtest/ptr_ring.c b/tools/virtio/ringtest/ptr_ring.c index 477899c12c51..2d566fbd236b 100644 --- a/tools/virtio/ringtest/ptr_ring.c +++ b/tools/virtio/ringtest/ptr_ring.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #define likely(x) (__builtin_expect(!!(x), 1)) | 17 | #define likely(x) (__builtin_expect(!!(x), 1)) |
18 | #define ALIGN(x, a) (((x) + (a) - 1) / (a) * (a)) | 18 | #define ALIGN(x, a) (((x) + (a) - 1) / (a) * (a)) |
19 | #define SIZE_MAX (~(size_t)0) | 19 | #define SIZE_MAX (~(size_t)0) |
20 | #define KMALLOC_MAX_SIZE SIZE_MAX | ||
21 | #define BUG_ON(x) assert(x) | ||
20 | 22 | ||
21 | typedef pthread_spinlock_t spinlock_t; | 23 | typedef pthread_spinlock_t spinlock_t; |
22 | 24 | ||
@@ -57,6 +59,9 @@ static void kfree(void *p) | |||
57 | free(p); | 59 | free(p); |
58 | } | 60 | } |
59 | 61 | ||
62 | #define kvmalloc_array kmalloc_array | ||
63 | #define kvfree kfree | ||
64 | |||
60 | static void spin_lock_init(spinlock_t *lock) | 65 | static void spin_lock_init(spinlock_t *lock) |
61 | { | 66 | { |
62 | int r = pthread_spin_init(lock, 0); | 67 | int r = pthread_spin_init(lock, 0); |