From 5da729255406ae4da5bc539569b8d7a10407dcbf Mon Sep 17 00:00:00 2001 From: Alexey Makhalov <amakhalov@vmware.com> Date: Fri, 22 Dec 2017 14:59:28 -0800 Subject: [PATCH] Log kmsg dump on panic In case of panic kmsg will be dumped to vmware.log file --- arch/x86/kernel/cpu/vmware.c | 145 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index 8e005329648b..eb8515b5cad7 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c @@ -30,19 +30,24 @@ #include <asm/hypervisor.h> #include <asm/timer.h> #include <asm/apic.h> +#include <linux/kmsg_dump.h> +#include <linux/frame.h> #undef pr_fmt #define pr_fmt(fmt) "vmware: " fmt -#define CPUID_VMWARE_INFO_LEAF 0x40000000 -#define VMWARE_HYPERVISOR_MAGIC 0x564D5868 -#define VMWARE_HYPERVISOR_PORT 0x5658 +#define CPUID_VMWARE_INFO_LEAF 0x40000000 +#define VMWARE_HYPERVISOR_MAGIC 0x564D5868 +#define VMWARE_HYPERVISOR_PORT 0x5658 +#define VMWARE_HYPERVISOR_HB_PORT 0x5659 #define VMWARE_PORT_CMD_GETVERSION 10 #define VMWARE_PORT_CMD_GETHZ 45 #define VMWARE_PORT_CMD_GETVCPU_INFO 68 #define VMWARE_PORT_CMD_LEGACY_X2APIC 3 #define VMWARE_PORT_CMD_VCPU_RESERVED 31 +#define VMWARE_PORT_CMD_MESSAGE 30 +#define VMWARE_HB_PORT_CMD_MESSAGE 0 #define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \ __asm__("inl (%%dx)" : \ @@ -66,6 +71,13 @@ static unsigned long vmware_get_tsc_khz(void) return vmware_tsc_khz; } +static void kmsg_dumper_vmware_log(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason); + +static struct kmsg_dumper kmsg_dumper = { + .dump = kmsg_dumper_vmware_log +}; + #ifdef CONFIG_PARAVIRT static struct cyc2ns_data vmware_cyc2ns __ro_after_init; static int vmw_sched_clock __initdata = 1; @@ -172,6 +184,8 @@ static void __init vmware_platform_setup(void) #endif vmware_set_capabilities(); + + kmsg_dump_register(&kmsg_dumper); } /* @@ -212,3 +226,128 @@ const __initconst struct hypervisor_x86 x86_hyper_vmware = { .init.init_platform = vmware_platform_setup, .init.x2apic_available = vmware_legacy_x2apic_available, }; + +#define MESSAGE_STATUS_SUCCESS (0x01 << 16) +#define MESSAGE_STATUS_CPT (0x10 << 16) +#define MESSAGE_STATUS_HB (0x80 << 16) + +#define RPCI_PROTOCOL_NUM 0x49435052 /* 'RPCI' */ +#define GUESTMSG_FLAG_COOKIE 0x80000000 + +#define MESSAGE_TYPE_OPEN (0 << 16) +#define MESSAGE_TYPE_SENDSIZE (1 << 16) +#define MESSAGE_TYPE_CLOSE (6 << 16) + +typedef struct { + uint32_t id; + uint32_t cookieHigh; + uint32_t cookieLow; +} vmw_msg; + +static int +vmware_log_open(vmw_msg *msg) { + uint32_t result, info, dx, si, di; + __asm__ __volatile__ ("inl (%%dx)" + : "=a" (result), + "=c" (info), + "=d" (dx), + "=S" (si), + "=D" (di) + : "a" (VMWARE_HYPERVISOR_MAGIC), + "c" (VMWARE_PORT_CMD_MESSAGE | MESSAGE_TYPE_OPEN), + "d" (VMWARE_HYPERVISOR_PORT), + "b" (RPCI_PROTOCOL_NUM | GUESTMSG_FLAG_COOKIE)); + + if ((info & MESSAGE_STATUS_SUCCESS) == 0) + return 1; + + msg->id = dx & 0xffff0000; + msg->cookieHigh = si; + msg->cookieLow = di; + return 0; +} + +static int +vmware_log_close(vmw_msg *msg) { + uint32_t result, info; + __asm__ __volatile__ ("inl (%%dx)" + : "=a" (result), + "=c" (info) + : "a" (VMWARE_HYPERVISOR_MAGIC), + "c" (VMWARE_PORT_CMD_MESSAGE | MESSAGE_TYPE_CLOSE), + "d" (VMWARE_HYPERVISOR_PORT | msg->id), + "b" (0), + "S" (msg->cookieHigh), + "D" (msg->cookieLow)); + + if ((info & MESSAGE_STATUS_SUCCESS) == 0) + return 1; + return 0; +} + +static int +vmware_log_send(vmw_msg *msg, const char *string) { + uint32_t result, info; + uint32_t len = strlen(string); + +retry: + __asm__ __volatile__ ("inl (%%dx)" + : "=a" (result), + "=c" (info) + : "a" (VMWARE_HYPERVISOR_MAGIC), + "c" (VMWARE_PORT_CMD_MESSAGE | MESSAGE_TYPE_SENDSIZE), + "d" (VMWARE_HYPERVISOR_PORT | msg->id), + "b" (len), + "S" (msg->cookieHigh), + "D" (msg->cookieLow)); + + if ((info & MESSAGE_STATUS_SUCCESS) == 0 || + (info & MESSAGE_STATUS_HB) == 0) + /* Expected success + high-bandwidth. Give up. */ + return 1; + + __asm__ __volatile__ ("pushq %%rbp\n\t" + "movl %[rbp], %%ebp\n\t" + "cld\n\t" + "rep; outsb\n\t" + "popq %%rbp\n\t" + : "=a" (result), + "=b" (info) + : "a" (VMWARE_HYPERVISOR_MAGIC), + "c" (len), + "d" (VMWARE_HYPERVISOR_HB_PORT | msg->id), + "b" (VMWARE_HB_PORT_CMD_MESSAGE | MESSAGE_STATUS_SUCCESS), + "S" (string), + [rbp] "r" (msg->cookieHigh), + "D" (msg->cookieLow)); + + if ((info & MESSAGE_STATUS_SUCCESS) == 0) { + if (info & MESSAGE_STATUS_CPT) + /* A checkpoint occurred. Retry. */ + goto retry; + return 1; + } + return 0; +} +STACK_FRAME_NON_STANDARD(vmware_log_send); + +static void kmsg_dumper_vmware_log(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason) +{ + vmw_msg msg; + static char line[1024]; + size_t len = 0; + + line[0] = 'l'; + line[1] = 'o'; + line[2] = 'g'; + line[3] = ' '; + + while (kmsg_dump_get_line(dumper, true, line + 4, sizeof(line) - 4, &len)) { + line[len + 4] = '\0'; + if (vmware_log_open(&msg) || + vmware_log_send(&msg, line) || + vmware_log_close(&msg)) + break; + } +}