From mboxrd@z Thu Jan 1 00:00:00 1970 From: Masami Hiramatsu Subject: [PATCH -tip v9 2/7] x86: x86 instruction decoder build-time selftest Date: Mon, 01 Jun 2009 20:37:25 -0400 Message-ID: <20090602003725.29255.84686.stgit@localhost.localdomain> References: <20090602003709.29255.48248.stgit@localhost.localdomain> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: systemtap , kvm , DLE , Masami Hiramatsu , Jim Keniston , "H. Peter Anvin" , Steven Rostedt , Ananth N Mavinakayanahalli , Ingo Molnar , Frederic Weisbecker , Andi Kleen , Vegard Nossum , Avi Kivity , =?utf-8?q?Przemys=C5=82aw?= =?utf-8?q?Pawe=C5=82czyk?= , Sam Ravnborg To: Ingo Molnar , Steven Rostedt , lkml Return-path: Received: from mx2.redhat.com ([66.187.237.31]:36908 "EHLO mx2.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757496AbZFBAer (ORCPT ); Mon, 1 Jun 2009 20:34:47 -0400 In-Reply-To: <20090602003709.29255.48248.stgit@localhost.localdomain> Sender: kvm-owner@vger.kernel.org List-ID: Add a user-space selftest of x86 instruction decoder at kernel build ti= me. When CONFIG_X86_DECODER_SELFTEST=3Dy, Kbuild builds a test harness of x= 86 instruction decoder and performs it after building vmlinux. The test compares the results of objdump and x86 instruction decoder code and check there are no differences. Changes from v7: - Add data, addr, rep, lock prefixes to skip instructions list. - Add license comments. Signed-off-by: Masami Hiramatsu Signed-off-by: Jim Keniston Cc: H. Peter Anvin Cc: Steven Rostedt Cc: Ananth N Mavinakayanahalli Cc: Ingo Molnar Cc: Frederic Weisbecker Cc: Andi Kleen Cc: Vegard Nossum Cc: Avi Kivity Cc: Przemys=C5=82aw Pawe=C5=82czyk Cc: Sam Ravnborg --- arch/x86/Kconfig.debug | 9 ++++ arch/x86/Makefile | 3 + arch/x86/include/asm/inat.h | 2 + arch/x86/include/asm/insn.h | 2 + arch/x86/lib/inat.c | 2 + arch/x86/lib/insn.c | 2 + arch/x86/scripts/Makefile | 19 +++++++ arch/x86/scripts/distill.awk | 42 +++++++++++++++++ arch/x86/scripts/test_get_len.c | 99 +++++++++++++++++++++++++++++++= ++++++++ arch/x86/scripts/user_include.h | 49 +++++++++++++++++++ 10 files changed, 229 insertions(+), 0 deletions(-) create mode 100644 arch/x86/scripts/Makefile create mode 100644 arch/x86/scripts/distill.awk create mode 100644 arch/x86/scripts/test_get_len.c create mode 100644 arch/x86/scripts/user_include.h diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 9a88937..430aab4 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -179,6 +179,15 @@ config X86_DS_SELFTEST config HAVE_MMIOTRACE_SUPPORT def_bool y =20 +config X86_DECODER_SELFTEST + bool "x86 instruction decoder selftest" + depends on DEBUG_KERNEL + ---help--- + Perform x86 instruction decoder selftests at build time. + This option is useful for checking the sanity of x86 instruction + decoder code. + If unsure, say "N". + # # IO delay types: # diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 1b68659..7046556 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -154,6 +154,9 @@ all: bzImage KBUILD_IMAGE :=3D $(boot)/bzImage =20 bzImage: vmlinux +ifeq ($(CONFIG_X86_DECODER_SELFTEST),y) + $(Q)$(MAKE) $(build)=3Darch/x86/scripts posttest +endif $(Q)$(MAKE) $(build)=3D$(boot) $(KBUILD_IMAGE) $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boo= t/$@ diff --git a/arch/x86/include/asm/inat.h b/arch/x86/include/asm/inat.h index 01e079a..9090665 100644 --- a/arch/x86/include/asm/inat.h +++ b/arch/x86/include/asm/inat.h @@ -20,7 +20,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-130= 7, USA. * */ +#ifdef __KERNEL__ #include +#endif =20 /* Instruction attributes */ typedef u32 insn_attr_t; diff --git a/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h index 5b50fa3..5736404 100644 --- a/arch/x86/include/asm/insn.h +++ b/arch/x86/include/asm/insn.h @@ -20,7 +20,9 @@ * Copyright (C) IBM Corporation, 2009 */ =20 +#ifdef __KERNEL__ #include +#endif /* insn_attr_t is defined in inat.h */ #include =20 diff --git a/arch/x86/lib/inat.c b/arch/x86/lib/inat.c index d6a34be..564ecbd 100644 --- a/arch/x86/lib/inat.c +++ b/arch/x86/lib/inat.c @@ -18,7 +18,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-130= 7, USA. * */ +#ifdef __KERNEL__ #include +#endif #include =20 /* Attribute tables are generated from opcode map */ diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c index 254c848..3b9451a 100644 --- a/arch/x86/lib/insn.c +++ b/arch/x86/lib/insn.c @@ -18,8 +18,10 @@ * Copyright (C) IBM Corporation, 2002, 2004, 2009 */ =20 +#ifdef __KERNEL__ #include #include +#endif #include #include =20 diff --git a/arch/x86/scripts/Makefile b/arch/x86/scripts/Makefile new file mode 100644 index 0000000..f08859e --- /dev/null +++ b/arch/x86/scripts/Makefile @@ -0,0 +1,19 @@ +PHONY +=3D posttest +quiet_cmd_posttest =3D TEST $@ + cmd_posttest =3D objdump -d $(objtree)/vmlinux | awk -f $(srctre= e)/arch/x86/scripts/distill.awk | $(obj)/test_get_len + +posttest: $(obj)/test_get_len vmlinux + $(call cmd,posttest) + +test_get_len_SRC =3D $(srctree)/arch/x86/scripts/test_get_len.c $(srct= ree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c +test_get_len_INC =3D $(srctree)/arch/x86/include/asm/inat.h $(srctree)= /arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c + +quiet_cmd_test_get_len =3D CC $@ + cmd_test_get_len =3D $(CC) -Wall $(test_get_len_SRC) -I$(objtree= )/arch/x86/lib/ -I$(srctree)/arch/x86/include -include $(srctree)/arch/= x86/scripts/user_include.h -o $@ + + +$(obj)/test_get_len: $(test_get_len_SRC) $(test_get_len_INC) + $(call cmd,test_get_len) + +clean-files :=3D test_get_len + diff --git a/arch/x86/scripts/distill.awk b/arch/x86/scripts/distill.aw= k new file mode 100644 index 0000000..d433619 --- /dev/null +++ b/arch/x86/scripts/distill.awk @@ -0,0 +1,42 @@ +#!/bin/awk -f +# Usage: objdump -d a.out | awk -f distill.awk | ./test_get_len +# Distills the disassembly as follows: +# - Removes all lines except the disassembled instructions. +# - For instructions that exceed 1 line (7 bytes), crams all the hex b= ytes +# into a single line. +# - Remove bad(or prefix only) instructions + +BEGIN { + prev_addr =3D "" + prev_hex =3D "" + prev_mnemonic =3D "" + bad_expr =3D "(\\(bad\\)|^rex|^.byte|^rep(z|nz)$|^lock$|^es$|^cs$|^ss= $|^ds$|^fs$|^gs$|^data(16|32)$|^addr(16|32|64))" + fwait_expr =3D "^9b " + fwait_str=3D"9b\tfwait" +} + +/^ *[0-9a-f]+:/ { + if (split($0, field, "\t") < 3) { + # This is a continuation of the same insn. + prev_hex =3D prev_hex field[2] + } else { + # Skip bad instructions + if (match(prev_mnemonic, bad_expr)) + prev_addr =3D "" + # Split fwait from other f* instructions + if (match(prev_hex, fwait_expr) && prev_mnemonic !=3D "fwait") { + printf "%s\t%s\n", prev_addr, fwait_str + sub(fwait_expr, "", prev_hex) + } + if (prev_addr !=3D "") + printf "%s\t%s\t%s\n", prev_addr, prev_hex, prev_mnemonic + prev_addr =3D field[1] + prev_hex =3D field[2] + prev_mnemonic =3D field[3] + } +} + +END { + if (prev_addr !=3D "") + printf "%s\t%s\t%s\n", prev_addr, prev_hex, prev_mnemonic +} diff --git a/arch/x86/scripts/test_get_len.c b/arch/x86/scripts/test_ge= t_len.c new file mode 100644 index 0000000..0f702e8 --- /dev/null +++ b/arch/x86/scripts/test_get_len.c @@ -0,0 +1,99 @@ +/* + * This program is free software; you can redistribute it and/or modif= y + * it under the terms of the GNU General Public License as published b= y + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-130= 7, USA. + * + * Copyright (C) IBM Corporation, 2009 + */ + +#include +#include +#include +#include + +#include + +/* + * Test of instruction analysis in general and insn_get_length() in + * particular. See if insn_get_length() and the disassembler agree + * on the length of each instruction in an elf disassembly. + * + * usage: test_get_len < distilled_disassembly + */ + +const char *prog; + +static void usage() +{ + fprintf(stderr, "usage: %s < distilled_disassembly\n", prog); + exit(1); +} + +static void malformed_line(const char *line, int line_nr) +{ + fprintf(stderr, "%s: malformed line %d:\n%s", prog, line_nr, line); + exit(3); +} + +#define BUFSIZE 256 + +int main(int argc, char **argv) +{ + char line[BUFSIZE]; + unsigned char insn_buf[16]; + struct insn insn; + int insns =3D 0; + + prog =3D argv[0]; + if (argc > 1) + usage(); + + while (fgets(line, BUFSIZE, stdin)) { + char copy[BUFSIZE], *s, *tab1, *tab2; + int nb =3D 0; + unsigned b; + + insns++; + memset(insn_buf, 0, 16); + strcpy(copy, line); + tab1 =3D strchr(copy, '\t'); + if (!tab1) + malformed_line(line, insns); + s =3D tab1 + 1; + s +=3D strspn(s, " "); + tab2 =3D strchr(s, '\t'); + if (!tab2) + malformed_line(line, insns); + *tab2 =3D '\0'; /* Characters beyond tab2 aren't examined */ + while (s < tab2) { + if (sscanf(s, "%x", &b) =3D=3D 1) { + insn_buf[nb++] =3D (unsigned char) b; + s +=3D 3; + } else + break; + } + /* Decode an instruction */ + kernel_insn_init(&insn, insn_buf); + insn_get_length(&insn); + if (insn.length !=3D nb) { + fprintf(stderr, "Error: %s", line); + fprintf(stderr, "Error: objdump says %d bytes, but " + "insn_get_length() says %d (attr:%x)\n", nb, + insn.length, insn.attr); + exit(2); + } + } + fprintf(stderr, "Succeed: decoded and checked %d instructions\n", + insns); + return 0; +} diff --git a/arch/x86/scripts/user_include.h b/arch/x86/scripts/user_in= clude.h new file mode 100644 index 0000000..3bdcc55 --- /dev/null +++ b/arch/x86/scripts/user_include.h @@ -0,0 +1,49 @@ +#ifndef __USER_TYPES_H +#define __USER_TYPES_H + +/* + * This program is free software; you can redistribute it and/or modif= y + * it under the terms of the GNU General Public License as published b= y + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-130= 7, USA. + * + * Copyright (C) IBM Corporation, 2009 + */ + +#include + +#ifdef __x86_64__ +#define CONFIG_X86_64 +#else +#define CONFIG_X86_32 +#endif +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +typedef signed char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef enum bool { false =3D 0, true } bool; + +/* any harmless file-scope decl */ +#define NOP_DECL struct __nop +#define EXPORT_SYMBOL_GPL(symbol) NOP_DECL +#define MODULE_LICENSE(gpl) NOP_DECL + +#define WARN_ON(cond) do { } while (0) +#define unlikely(cond) (cond) + +#endif /* __USER_TYPES_H */ --=20 Masami Hiramatsu Software Engineer Hitachi Computer Products (America), Inc. Software Solutions Division e-mail: mhiramat@redhat.com