From 71048bf46e2beea4cbfa41a7b0987f1817fc2218 Mon Sep 17 00:00:00 2001
From: Alexey Makhalov <amakhalov@vmware.com>
Date: Tue, 9 May 2017 12:31:15 -0700
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 | 143 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 140 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
index 6745c0b7414e..1ef88701b2d9 100644
--- a/arch/x86/kernel/cpu/vmware.c
+++ b/arch/x86/kernel/cpu/vmware.c
@@ -30,19 +30,23 @@
#include <asm/hypervisor.h>
#include <asm/timer.h>
#include <asm/apic.h>
+#include <linux/kmsg_dump.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 +70,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;
@@ -152,6 +163,8 @@ static void __init vmware_platform_setup(void)
#endif
vmware_paravirt_ops_setup();
+
+ kmsg_dump_register(&kmsg_dumper);
}
/*
@@ -211,3 +224,127 @@ const __refconst struct hypervisor_x86 x86_hyper_vmware = {
.x2apic_available = vmware_legacy_x2apic_available,
};
EXPORT_SYMBOL(x86_hyper_vmware);
+
+#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;
+}
+
+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;
+ }
+}
--
2.11.0