Here's v2 with the stuff we talked about, implemented. I've added
'control_regs' file too so that you can do:

$ cat /sys/kernel/debug/x86/archinfo/control_regs
CR4: [-|-|SMEP|OSXSAVE|-|-|-|-|OSXMMEXCPT|OSFXSR|-|PGE|MCE|PAE|PSE|-|-|-|-]: 
0x1406f0

for example. Yeah, only CR4 right now.

Off the top of my head, we would need "msrs" which dumps EFER and a
bunch of other interesting MSRs along with the names of the set bits.

---
From: Borislav Petkov <b...@suse.de>
Date: Mon, 30 Nov 2015 13:53:36 +0100
Subject: [PATCH -v2] 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 <b...@suse.de>
---
 arch/x86/Kconfig.debug     |   5 ++
 arch/x86/kernel/Makefile   |   1 +
 arch/x86/kernel/archinfo.c | 215 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 221 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..c04e98625565
--- /dev/null
+++ b/arch/x86/kernel/archinfo.c
@@ -0,0 +1,215 @@
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/cpu.h>
+
+#include <asm/desc.h>
+
+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 gdt_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 gdt_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, gdt_show, NULL);
+}
+
+static int cr_show(struct seq_file *m, void *v)
+{
+       unsigned long cr4 = __read_cr4();
+
+       seq_printf(m, "CR4: 
[%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s]: 0x%lx\n",
+                     (cr4 & BIT(22) ? "PKE"            : "-"),
+                     (cr4 & BIT(21) ? "SMAP"           : "-"),
+                     (cr4 & BIT(20) ? "SMEP"           : "-"),
+                     (cr4 & BIT(18) ? "OSXSAVE"        : "-"),
+                     (cr4 & BIT(17) ? "PCIDE"          : "-"),
+                     (cr4 & BIT(16) ? "FSGSBASE"       : "-"),
+                     (cr4 & BIT(14) ? "SMXE"           : "-"),
+                     (cr4 & BIT(13) ? "VMXE"           : "-"),
+                     (cr4 & BIT(10) ? "OSXMMEXCPT"     : "-"),
+                     (cr4 & BIT(9)  ? "OSFXSR"         : "-"),
+                     (cr4 & BIT(8)  ? "PCE"            : "-"),
+                     (cr4 & BIT(7)  ? "PGE"            : "-"),
+                     (cr4 & BIT(6)  ? "MCE"            : "-"),
+                     (cr4 & BIT(5)  ? "PAE"            : "-"),
+                     (cr4 & BIT(4)  ? "PSE"            : "-"),
+                     (cr4 & BIT(3)  ? "DE"             : "-"),
+                     (cr4 & BIT(2)  ? "TSD"            : "-"),
+                     (cr4 & BIT(1)  ? "PVI"            : "-"),
+                     (cr4 & BIT(0)  ? "VME"            : "-"),
+                     cr4);
+
+       return 0;
+}
+
+static int cr_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, cr_show, NULL);
+}
+
+static const struct file_operations cr_fops = {
+       .owner   = THIS_MODULE,
+       .open    = cr_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = single_release,
+};
+
+static const struct file_operations gdt_fops = {
+       .owner   = THIS_MODULE,
+       .open    = gdt_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_dir("archinfo", arch_debugfs_dir);
+       if (IS_ERR_OR_NULL(dfs_entry))
+               return -EINVAL;
+
+       if (!debugfs_create_file("gdt", S_IRUSR, dfs_entry, NULL, &gdt_fops)) {
+               debugfs_remove_recursive(dfs_entry);
+               return -EINVAL;
+       }
+
+       if (!debugfs_create_file("control_regs", S_IRUSR, dfs_entry, NULL, 
&cr_fops)) {
+               debugfs_remove_recursive(dfs_entry);
+               return -EINVAL;
+       }
+
+       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 <b...@alien8.de>");
+MODULE_DESCRIPTION("x86 arch info dumper");
-- 
2.3.5


-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.

Reply via email to