From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932122AbcBAL4Q (ORCPT ); Mon, 1 Feb 2016 06:56:16 -0500 Received: from mail.skyhub.de ([78.46.96.112]:43203 "EHLO mail.skyhub.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753663AbcBAL4P (ORCPT ); Mon, 1 Feb 2016 06:56:15 -0500 Date: Mon, 1 Feb 2016 12:56:02 +0100 From: Borislav Petkov To: "H. Peter Anvin" , Ingo Molnar , Thomas Gleixner Cc: Andy Lutomirski , Peter Zijlstra , Steven Rostedt , Tony Luck , Brian Gerst , lkml Subject: [RFC] Dump interesting arch/platform info Message-ID: <20160201115601.GD6438@pd.tnic> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline User-Agent: Mutt/1.5.24 (2015-08-30) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi, so I've been playing with this simple module below. The idea is to be able to dump interesting arch/platform information on the currently running system. For example, how does the GDT look like. It is supposed to be used as a debugging aid and the information it dumps is not easily accessible from userspace. So the use case is you go, modprobe this thing and do cat /sys/kernel/debug/x86/archinfo Right now, it dumps only the GDT and even that is not fully done. But more interesting stuff should be added to it as need arises. Thoughts, ideas, suggestions? Thanks. --- CPU0, GDT ffff88007b609000: 00: [ base[31:24]:00 G:0 D:0 L:0 AVL:0 lim[19:16]:0 | P:0 DPL:0 S:0 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:0000 ]: System: (0x0) Reserved (illegal) 01: [ base[31:24]:00 G:1 D:1 L:0 AVL:0 lim[19:16]:f | P:1 DPL:0 S:1 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:ffff ]: User: (0xb) Code, Execute/Readable - Accessed 02: [ base[31:24]:00 G:1 D:0 L:1 AVL:0 lim[19:16]:f | P:1 DPL:0 S:1 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:ffff ]: User: (0xb) Code, Execute/Readable - Accessed 03: [ base[31:24]:00 G:1 D:1 L:0 AVL:0 lim[19:16]:f | P:1 DPL:0 S:1 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:ffff ]: User: (0x3) Data, Read/Write - Accessed 04: [ base[31:24]:00 G:1 D:1 L:0 AVL:0 lim[19:16]:f | P:1 DPL:3 S:1 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:ffff ]: User: (0xb) Code, Execute/Readable - Accessed 05: [ base[31:24]:00 G:1 D:1 L:0 AVL:0 lim[19:16]:f | P:1 DPL:3 S:1 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:ffff ]: User: (0x3) Data, Read/Write - Accessed 06: [ base[31:24]:00 G:1 D:0 L:1 AVL:0 lim[19:16]:f | P:1 DPL:3 S:1 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:ffff ]: User: (0xb) Code, Execute/Readable - Accessed 07: [ base[31:24]:00 G:0 D:0 L:0 AVL:0 lim[19:16]:0 | P:0 DPL:0 S:0 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:0000 ]: System: (0x0) Reserved (illegal) 08: [ base[31:24]:7b G:0 D:0 L:0 AVL:0 lim[19:16]:0 | P:1 DPL:0 S:0 C:0 base[23:16]:7d ] [ base[15:00]:2e00 | lim[15:00]:2087 ]: System: (0xb) Busy 32-bit TSS 09: [ base[31:24]:00 G:0 D:0 L:0 AVL:0 lim[19:16]:0 | P:0 DPL:0 S:0 C:0 base[23:16]:00 ] [ base[15:00]:ffff | lim[15:00]:8800 ]: System: (0x0) Reserved (illegal) 10: [ base[31:24]:00 G:0 D:0 L:0 AVL:0 lim[19:16]:0 | P:0 DPL:0 S:0 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:0000 ]: System: (0x0) Reserved (illegal) 11: [ base[31:24]:00 G:0 D:0 L:0 AVL:0 lim[19:16]:0 | P:0 DPL:0 S:0 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:0000 ]: System: (0x0) Reserved (illegal) 12: [ base[31:24]:00 G:0 D:0 L:0 AVL:0 lim[19:16]:0 | P:0 DPL:0 S:0 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:0000 ]: System: (0x0) Reserved (illegal) 13: [ base[31:24]:00 G:0 D:0 L:0 AVL:0 lim[19:16]:0 | P:0 DPL:0 S:0 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:0000 ]: System: (0x0) Reserved (illegal) 14: [ base[31:24]:00 G:0 D:0 L:0 AVL:0 lim[19:16]:0 | P:0 DPL:0 S:0 C:0 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:0000 ]: System: (0x0) Reserved (illegal) 15: [ base[31:24]:00 G:0 D:1 L:0 AVL:0 lim[19:16]:0 | P:1 DPL:3 S:1 C:1 base[23:16]:00 ] [ base[15:00]:0000 | lim[15:00]:0000 ]: User: (0x5) Data, Expand-down, Read-Only - Accessed ... ---- Info: base,limit,A,G,R: ignored in 64-bit mode. G: granularity bit (23): - 0b: segment limit is not scaled. - 1b: segment limit scaled by 4K. D/B: CS default operand size bit (22): - 0b: 16-bit. - 1b: 32-bit. D=0b is the only allowed setting in long mode (L=1b). Called B in stack segments. L: long mode bit (21): - 0b: CPU in compat mode. Enables segmentation. - 1b: CPU in long mode. AVL: bit available to software (20). P: present bit (15): - 0b: seg. not present in mem => #NP. - 1b: seg is present in memory. DPL: Descriptor Privilege Level [14:13]: - 0b: highest privilege level. ... - 3b: lowest privilege level. S+Type: decriptor types [12,11:8]: Specify descriptor type and access characteristics. S: - 0b: System descriptor. - 1b: User descriptor. R: readable bit (9): - 0b: code seg is executable, reads -> #GP - 1b: code seg is both read/exec A: accessed bit (8): set by CPU when desc copied into %cs; cleared only by sw. --- From: Borislav Petkov Date: Mon, 30 Nov 2015 13:53:36 +0100 Subject: [PATCH] x86: Add an archinfo dumper module Dump interesting/valuable information related to the x86 architecture of the current CPU and platform. Signed-off-by: Borislav Petkov --- arch/x86/Kconfig.debug | 5 ++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/archinfo.c | 164 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 arch/x86/kernel/archinfo.c diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 9b18ed97a8a2..c757d1ee9a7a 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -383,4 +383,9 @@ config PUNIT_ATOM_DEBUG The current power state can be read from /sys/kernel/debug/punit_atom/dev_power_state +config ARCHINFO + tristate "x86 archinfo dumper module" + ---help--- + Dump interesting x86 arch stuff. + endmenu diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index b1b78ffe01d0..89972c1b9de6 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -109,6 +109,7 @@ obj-$(CONFIG_EFI) += sysfb_efi.o obj-$(CONFIG_PERF_EVENTS) += perf_regs.o obj-$(CONFIG_TRACING) += tracepoint.o +obj-$(CONFIG_ARCHINFO) += archinfo.o ### # 64 bit specific files diff --git a/arch/x86/kernel/archinfo.c b/arch/x86/kernel/archinfo.c new file mode 100644 index 000000000000..790ba8413895 --- /dev/null +++ b/arch/x86/kernel/archinfo.c @@ -0,0 +1,164 @@ +#include +#include +#include + +#include + +static const char * const system_desc_types[] = { + [0] = "Reserved (illegal)", + [1] = "Available 16-bit TSS", + [2] = "LDT", + [3] = "Busy 16-bit TSS", + [4] = "16-bit Call Gate", + [5] = "Task Gate", + [6] = "16-bit Interrupt Gate", + [7] = "16-bit Trap Gate", + [8] = "Reserved (illegal)", + [9] = "Available 32-bit TSS", + [10] = "Reserved (illegal)", + [11] = "Busy 32-bit TSS", + [12] = "32-bit Call Gate", + [13] = "Reserved (illegal)", + [14] = "32-bit Interrupt Gate", + [15] = "32-bit Trap Gate", +}; + +static const char * const user_desc_types[] = { + [0] = "Read-Only", + [1] = "Read-only - Accessed", + [2] = "Read/Write", + [3] = "Read/Write - Accessed", + [4] = "Expand-down, Read-Only", + [5] = "Expand-down, Read-Only - Accessed", + [6] = "Expand-down, Read-Write", + [7] = "Expand-down, Read-Write - Accessed", + [8] = "Execute-Only", + [9] = "Execute-Only - Accessed", + [10] = "Execute/Readable", + [11] = "Execute/Readable - Accessed", + [12] = "Conforming, Execute-Only", + [13] = "Conforming, Execute-Only - Accessed", + [14] = "Conforming, Execute/Readable", + [15] = "Conforming, Execute/Readable - Accessed", +}; + +static void print_seg_desc(struct seq_file *m, struct desc_struct *d, int num) +{ + seq_printf(m, "%02d:\n", num); + seq_printf(m, "[ base[31:24]:%02x G:%x D:%x L:%x AVL:%x lim[19:16]:%x |", + d->base2, d->g, d->d, d->l, d->avl, d->limit); + seq_printf(m, " P:%x DPL:%x S:%x C:%x base[23:16]:%02x ]\n", + d->p, d->dpl, d->s, !!(d->type & BIT(2)), d->base1); + seq_printf(m, "[ base[15:00]:%04x | lim[15:00]:%04x ]: ", + d->base0, d->limit0); + + if (d->s) + seq_printf(m, "User: (0x%x) %s, %s\n", + d->type, + (d->type > 7 ? "Code" : "Data"), + (user_desc_types[d->type])); + else + seq_printf(m, "System: (0x%x) %s\n", d->type, system_desc_types[d->type]); + + seq_printf(m, "\n"); +} + +static void dump_gdt(void *info) +{ + struct gdt_page *g = this_cpu_ptr(&gdt_page); + struct seq_file *m = (struct seq_file *)info; + int i; + + seq_printf(m, "CPU%d, GDT %p:\n", smp_processor_id(), &g->gdt); + + for (i = 0; i < GDT_ENTRIES; i++) + print_seg_desc(m, &g->gdt[i], i); + + seq_printf(m, "----\n"); + +} + +static int archinfo_show(struct seq_file *m, void *v) +{ + int c; + + /* + * Using on_each_cpu() here fudges the output and we want it nicely + * sorted by CPU. + */ + get_online_cpus(); + for_each_online_cpu(c) + smp_call_function_single(c, dump_gdt, m, 1); + put_online_cpus(); + + seq_printf(m, + "\nInfo:\n" + "base,limit,A,G,R: ignored in 64-bit mode.\n" + "G: granularity bit (23):\n" + "\t- 0b: segment limit is not scaled.\n" + "\t- 1b: segment limit scaled by 4K.\n" + "D/B: CS default operand size bit (22):\n" + "\t- 0b: 16-bit.\n" + "\t- 1b: 32-bit.\n" + "\tD=0b is the only allowed setting in long mode (L=1b).\n" + "\tCalled B in stack segments.\n" + "L: long mode bit (21):\n" + "\t- 0b: CPU in compat mode. Enables segmentation.\n" + "\t- 1b: CPU in long mode.\n" + "AVL: bit available to software (20).\n" + "P: present bit (15):\n" + "\t- 0b: seg. not present in mem => #NP.\n" + "\t- 1b: seg is present in memory.\n" + "DPL: Descriptor Privilege Level [14:13]:\n" + "\t- 0b: highest privilege level.\n" + " ...\n" + "\t- 3b: lowest privilege level.\n" + "S+Type: decriptor types [12,11:8]:\n" + "\t Specify descriptor type and access characteristics.\n" + " S:\n" + "\t- 0b: System descriptor.\n" + "\t- 1b: User descriptor.\n" + " R: readable bit (9):\n" + "\t- 0b: code seg is executable, reads -> #GP\n" + "\t- 1b: code seg is both read/exec\n" + " A: accessed bit (8): set by CPU when desc copied into %%cs; cleared only by sw.\n" + ); + + return 0; +} + +static int archinfo_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, archinfo_show, NULL); +} + +static const struct file_operations archinfo_fops = { + .owner = THIS_MODULE, + .open = archinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct dentry *dfs_entry; + +static int __init archinfo_init(void) +{ + dfs_entry = debugfs_create_file("archinfo", S_IRUSR, + arch_debugfs_dir, NULL, &archinfo_fops); + if (!dfs_entry) + return -ENOMEM; + + return 0; +} + +static void __exit archinfo_exit(void) +{ + debugfs_remove_recursive(dfs_entry); +} + +module_init(archinfo_init); +module_exit(archinfo_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Borislav Petkov "); +MODULE_DESCRIPTION("x86 arch info dumper"); -- 2.3.5 -- Regards/Gruss, Boris. ECO tip #101: Trim your mails when you reply.