[RFC] Dump interesting arch/platform info

From: Borislav Petkov
Date: Mon Feb 01 2016 - 06:56:19 EST


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 <bp@xxxxxxx>
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 <bp@xxxxxxx>
---
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 <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 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 <bp@xxxxxxxxx>");
+MODULE_DESCRIPTION("x86 arch info dumper");
--
2.3.5


--
Regards/Gruss,
Boris.

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