From fede934a9115f80961336a92a736f1f0407ef7c1 Mon Sep 17 00:00:00 2001 From: Pengfei Xu Date: Fri, 15 Sep 2023 16:29:57 +0800 Subject: [PATCH] tools: add cpuid check tool Add cpuid_check as a common tool to check cpuid. It does not depend on any other package such as cpuid package and checks cpuid specific bit settings as expected. Signed-off-by: Pengfei Xu --- tools/Makefile | 18 ++++ tools/cpuid_check/Makefile | 12 +++ tools/cpuid_check/cpuid_check.c | 152 ++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 tools/Makefile create mode 100644 tools/cpuid_check/Makefile create mode 100644 tools/cpuid_check/cpuid_check.c diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 00000000..362c2992 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2022 Intel Corporation. + +SUBDIRS = $(shell ls -d */) +all: + @for dir in $(SUBDIRS) ; do \ + if [ -f "$$dir/Makefile" ]; then \ + cd $$dir && \ + make && \ + cd .. || exit 2; \ + fi \ + done +clean: + for dir in $(SUBDIRS) ; do \ + if [ -f "$$dir/Makefile" ]; then \ + make -C $$dir clean || exit 2; \ + fi \ + done diff --git a/tools/cpuid_check/Makefile b/tools/cpuid_check/Makefile new file mode 100644 index 00000000..343968d1 --- /dev/null +++ b/tools/cpuid_check/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2023 Intel Corporation. + +BIN := cpuid_check + +all: $(BIN) + +cpuid_check: cpuid_check.c + gcc $^ -o $@ + +clean: + rm -rf $(BIN) diff --git a/tools/cpuid_check/cpuid_check.c b/tools/cpuid_check/cpuid_check.c new file mode 100644 index 00000000..2af06a2b --- /dev/null +++ b/tools/cpuid_check/cpuid_check.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2022 Intel Corporation. + +#include +#include +#include +#define N 32 +#define M 40 + +int usage(char *progname) +{ + printf("%s NUM1 NUM2 NUM3 NUM4 CHAR5 NUM6\n", progname); + printf(" NUM1: input EAX value in hex\n"); + printf(" NUM2: input EBX value in hex\n"); + printf(" NUM3: input ECX value in hex\n"); + printf(" NUM4: input EDX value in hex\n"); + printf(" CHAR5: a|b|c|d, which match with EAX|EBX|ECX|EDX output\n"); + printf(" NUM6: bit number in decimal for output CHAR5 register which matched with SPEC\n"); + exit(2); +} + +/* cpuid checking function with assembly. */ +static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + asm volatile("cpuid" + : "=a" (*eax), + "=b" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx) + : "memory"); +} + +/* Convert hex to binary mode to display cpuid information. */ +int h_to_b(long n) +{ + int i = 0; + static int a[N]; + + for (i = 0; i != N; ++i) { + a[N - 1 - i] = n % 2; + n /= 2; + } + for (i = 0; i != N; ++i) { + printf("%d", a[i]); + if ((i + 1) % 4 == 0) + printf(" "); + } + printf("\n"); + return 0; +} + +/* Check that the cpuid target output bits are correct. */ +int check_id(long n, int ex_number) +{ + int i = 0; + static int b[N]; + int bit_n = N - 1 - ex_number; + + for (i = 0; i != N; ++i) { + b[N - 1 - i] = n % 2; + n /= 2; + } + printf("Start with 0, pass: bit set 1, fail: bit set 0\n"); + if (b[bit_n] == 1) { + printf("Order bit:%d, invert order:%d, bit:%d, pass!\n", + bit_n, ex_number, b[bit_n]); + } else { + printf("Order bit:%d, invert order:%d, bit:%d, fail!\n", + bit_n, ex_number, b[bit_n]); + return 1; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0; + int ex_n, test_result = 1; + char ex = 'e'; + + if (argc == 1) { + usage(argv[0]); + exit(2); + } else if (argc == 5) { + if (sscanf(argv[1], "%x", &eax) != 1) + usage(argv[0]); + printf("4 parameters, eax=%d\n", eax); + if (sscanf(argv[2], "%x", &ebx) != 1) + usage(argv[0]); + if (sscanf(argv[3], "%x", &ecx) != 1) + usage(argv[0]); + if (sscanf(argv[4], "%x", &edx) != 1) + usage(argv[0]); + } else if (argc == 7) { + if (sscanf(argv[1], "%x", &eax) != 1) + usage(argv[0]); + printf("6 parameters, eax=%d\n", eax); + if (sscanf(argv[2], "%x", &ebx) != 1) + usage(argv[0]); + if (sscanf(argv[3], "%x", &ecx) != 1) + usage(argv[0]); + if (sscanf(argv[4], "%x", &edx) != 1) + usage(argv[0]); + if (sscanf(argv[5], "%c", &ex) != 1) + usage(argv[0]); + if (sscanf(argv[6], "%d", &ex_n) != 1) + usage(argv[0]); + } else { + if (sscanf(argv[1], "%x", &eax) != 1) + usage(argv[0]); + printf("Just get eax=%d\n", eax); + } + + printf("cpuid(eax=%08x, ebx=%08x, ecx=%08x, edx=%08x)\n", + eax, ebx, ecx, edx); + printf("cpuid(&eax=%p, &ebx=%p, &ecx=%p, &edx=%p)\n", + &eax, &ebx, &ecx, &edx); + native_cpuid(&eax, &ebx, &ecx, &edx); + printf("After native_cpuid:\n"); + printf("out: eax=%08x, ebx=%08x, ecx=%08x, edx=%08x\n", + eax, ebx, ecx, edx); + printf("cpuid(&eax=%p, &ebx=%p, &ecx=%p, &edx=%p)\n", + &eax, &ebx, &ecx, &edx); + printf("output:\n"); + printf(" eax=%08x || Binary: ", eax); + h_to_b(eax); + printf(" ebx=%08x || Binary: ", ebx); + h_to_b(ebx); + printf(" ecx=%08x || Binary: ", ecx); + h_to_b(ecx); + printf(" edx=%08x || Binary: ", edx); + h_to_b(edx); + + printf("Now check cpuid e%cx, bit %d\n", ex, ex_n); + if (ex == 'a') { + test_result = check_id(eax, ex_n); + } else if (ex == 'b') { + test_result = check_id(ebx, ex_n); + } else if (ex == 'c') { + test_result = check_id(ecx, ex_n); + } else if (ex == 'd') { + test_result = check_id(edx, ex_n); + } else { + printf("No check point, not in a-d, skip.\n"); + test_result = 0; + } + + printf("Done! Return:%d.\n\n", test_result); + return test_result; +}