Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 14 Mar 2010 19:44:15 GMT
From:      John Baldwin <jhb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 175686 for review
Message-ID:  <201003141944.o2EJiFAl089581@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/chv.cgi?CH=175686

Change 175686 by jhb@jhb_jhbbsd on 2010/03/14 19:43:30

	Handle new, extended records and ascii output modes that provide
	more detail similar to the Linux mce records while still preserving
	backwards compat for the older records and ascii output.

Affected files ...

.. //depot/projects/mcelog/mcelog.c#3 edit

Differences ...

==== //depot/projects/mcelog/mcelog.c#3 (text) ====

@@ -28,6 +28,7 @@
 #include <sys/types.h>
 #include <sys/sysctl.h>
 #include <machine/cpufunc.h>
+#include <machine/cputypes.h>
 #include <machine/specialreg.h>
 #include <machine/mca.h>
 #include <err.h>
@@ -703,53 +704,91 @@
 #endif
 
 #ifdef __FreeBSD__
-/* Used to map cpuid vendor strings to Linux cpuvendor values. */
+/*
+ * Table used to map cpuid vendor strings and FreeBSD CPU vendor IDs
+ * to Linux cpuvendor values.
+ */
 static struct {
 	char *name;
+	int vendor_id;
 	u_char cpuvendor;
 } vendor_ids[] = {
-	{ "GenuineIntel", 0 },
-	{ "CyrixInstead", 1 },
-	{ "AuthenticAMD", 2 },
-	{ "UMC UMC UMC ", 3 },
-	{ "CentaurHauls", 5 },
-	{ "GenuineTMx86", 7 },
-	{ "Geode by NSC", 8 },
+	{ "GenuineIntel", CPU_VENDOR_INTEL, 0 },
+	{ "AuthenticAMD", CPU_VENDOR_AMD, 2 },
+	{ "CentaurHauls", CPU_VENDOR_CENTAUR, 5 },
+#ifdef __i386__
+	{ "CyrixInstead", CPU_VENDOR_CYRIX, 1 },
+	{ "UMC UMC UMC ", CPU_VENDOR_UMC, 3 },
+	{ "GenuineTMx86", CPU_VENDOR_TRANSMETA, 7 },
+	{ "Geode by NSC", CPU_VENDOR_NSC, 8 },
+#endif
 };
-	  
+
+static int find_cpu_vendor(const char *vendor)
+{
+	u_int i;
+
+	for (i = 0; i < sizeof(vendor_ids) / sizeof(vendor_ids[0]); i++)
+		if (strcmp(vendor, vendor_ids[i].name) == 0)
+			return (vendor_ids[i].cpuvendor);
+	return (0xff);
+}
+
+static int find_cpu_vendor_id(const char *vendor)
+{
+	u_int i;
+
+	for (i = 0; i < sizeof(vendor_ids) / sizeof(vendor_ids[0]); i++)
+		if (strcmp(vendor, vendor_ids[i].name) == 0)
+			return (vendor_ids[i].vendor_id);
+	return (0);
+}
+
+static int map_cpu_vendor(int vendor_id)
+{
+	u_int i;
+
+	for (i = 0; i < sizeof(vendor_ids) / sizeof(vendor_ids[0]); i++)
+		if (vendor_ids[i].vendor_id == vendor_id)
+			return (vendor_ids[i].cpuvendor);
+	return (0xff);
+}
+
 /* Convert FreeBSD's struct mca_record into a struct mce. */
-static void convert_mca(struct mca_record *mr, struct mce *mce, int live)
+static void convert_mca(struct mca_record *mr, struct mce *mce, int live,
+    size_t len)
 {
 	memset(mce, 0, sizeof(*mce));
 	mce->status = mr->mr_status;
 	mce->misc = mr->mr_misc;
 	mce->addr = mr->mr_addr;
+	mce->mcgstatus = mr->mr_mcg_status;
 	mce->tsc = mr->mr_tsc;
+	mce->cpuvendor = map_cpu_vendor(mr->mr_cpu_vendor_id);
+	mce->cpuid = mr->mr_cpu_id;
 	mce->bank = mr->mr_bank;
 	mce->finished = 1;
+	mce->extcpu = mr->mr_cpu;
 	mce->apicid = mr->mr_apic_id;
+	mce->mcgcap = mr->mr_mcg_cap;
 
 	/*
-	 * For live records (from sysctl), fill in some fields using
-	 * registers from the current CPU.
+	 * For older live records (from sysctl), fill in some fields
+	 * using registers from the current CPU.
 	 */
-	if (live) {
+	if (len < offsetof(struct mca_record, mr_cpu_id) && live) {
 		char vendor[20];
-		u_int i, regs[4];
+		u_int regs[4];
 
 		do_cpuid(0, regs);
 		((u_int *)vendor)[0] = regs[1];
 		((u_int *)vendor)[1] = regs[3];
 		((u_int *)vendor)[2] = regs[2];
 		vendor[12] = 0;
-		mce->cpuvendor = 0xff;
-		for (i = 0; i < sizeof(vendor_ids) / sizeof(vendor_ids[0]); i++)
-			if (strcmp(vendor, vendor_ids[i].name) == 0)
-				mce->cpuvendor = vendor_ids[i].cpuvendor;
+		mce->cpuvendor = find_cpu_vendor(vendor);
 
 		do_cpuid(1, regs);
 		mce->cpuid = regs[0];
-		//mce->mcgcap = rdmsr(MSR_MCG_CAP);
 	}
 }
 
@@ -758,19 +797,23 @@
 {
 	struct mca_record mr;
 	struct mce m;
-	long long val;
-	char line[100], *s, symbol[1];
-	int data, missing;
+	long long val, val2;
+	char *cp, line[100], *s, symbol[1];
+	const char *fmt;
+	int cpu, data, old, missing;
 	enum rows {
-		BANK = 1,
-		CPU = 2,
-		ADDR = 4,
-		MISC = 8,
+		BANK = 0x1,
+		MCG = 0x2,
+		VENDOR = 0x4,
+		CPU = 0x8,
+		ADDR = 0x10,
+		MISC = 0x20,
 	};
 
 	symbol[0] = '\0';
 	data = 0;
 	missing = 0;
+	old = 0;
 	memset(&mr, 0, sizeof(mr));
 	while ((s = fgets(line, sizeof(line), inf)) != NULL) {
 		s = strstr(s, "MCA: ");
@@ -778,7 +821,7 @@
 			continue;
 		s += strlen("MCA: ");
 
-		if (strncmp(s, "bank", 4) == 0) {
+		if (strncmp(s, "bank", 4) == 0 || strncmp(s, "Bank", 4) == 0) {
 			/* Start of a new record, dump the previous one. */
 			if (data != 0) {
 				/* Require some minimum data. */
@@ -789,7 +832,8 @@
 					if (mr.mr_status & MC_STATUS_MISCV &&
 					    !(data & MISC))
 						missing = 1;
-					convert_mca(&mr, &m, 0);
+					convert_mca(&mr, &m, 0, sizeof(mr));
+					mce_cpuid(&m);
 					dump_mce_final(&m, symbol, missing,
 					    sizeof(struct mce), 0);
 				}
@@ -798,19 +842,55 @@
 				memset(&mr, 0, sizeof(mr));
 			}
 
-			if (sscanf(s, "bank %d, status 0x%llx", &mr.mr_bank,
-				&val) != 2)
+			if (s[0] == 'b') {
+				old = 1;
+				fmt = "bank %d, status 0x%llx";
+			} else {
+				old = 0;
+				fmt = "Bank %d, Status 0x%llx";
+			}
+			if (sscanf(s, fmt, &mr.mr_bank, &val) != 2)
 				missing = 1;
 			else {
 				data |= BANK;
 				mr.mr_status = val;
 			}
 		}
+		if (strncmp(s, "Global", 6) == 0) {
+			if (sscanf(s, "Global Cap 0x%llx, Status 0x%llx", &val,
+			    &val2) != 2)
+				missing = 1;
+			else {
+				data |= MCG;
+				mr.mr_mcg_cap = val;
+				mr.mr_mcg_status = val2;
+			}
+		}
+		if (strncmp(s, "Vendor \"", 8) == 0) {
+			s += 8;
+			cp = index(s, '"');
+			if (cp != NULL) {
+				*cp = '\0';
+				mr.mr_cpu_vendor_id = find_cpu_vendor_id(s);
+				s = cp + 1;
+				if (sscanf(s, ", ID 0x%x, APIC ID %d",
+				    &mr.mr_cpu_id, &mr.mr_apic_id) != 2)
+					missing = 1;
+				else
+					data |= VENDOR;
+			} else
+				missing = 1;
+		}
 		if (strncmp(s, "CPU", 3) == 0) {
-			if (sscanf(s, "CPU %d ", &mr.mr_apic_id) != 1)
+			if (sscanf(s, "CPU %d ", &cpu) != 1)
 				missing = 1;
-			else
+			else {
 				data |= CPU;
+				if (old)
+					mr.mr_apic_id = cpu;
+				else
+					mr.mr_cpu = cpu;
+			}
 		}
 		if (strncmp(s, "Address", 7) == 0) {
 			if (sscanf(s, "Address 0x%llx", &val) != 1)
@@ -836,7 +916,8 @@
 			missing = 1;
 		if (mr.mr_status & MC_STATUS_MISCV && !(data & MISC))
 			missing = 1;
-		convert_mca(&mr, &m, 0);
+		convert_mca(&mr, &m, 0, sizeof(mr));
+		mce_cpuid(&m);
 		dump_mce_final(&m, symbol, missing, sizeof(struct mce), 0);
 	}
 }
@@ -1183,12 +1264,13 @@
 	for (i = 0; i < (int)loglen; i++) {
 		mib[3] = i;
 		len = sizeof(mr);
+		memset(&mr, 0, sizeof(mr));
 		if (sysctl(mib, 4, &mr, &len, NULL, 0) < 0) {
 			warn("sysctl(hw.mca.records.%d)", i);
 			continue;
 		}
 
-		convert_mca(&mr, &mce, 1);
+		convert_mca(&mr, &mce, 1, len);
 		mce_prepare(&mce);
 		if (numerrors > 0 && --numerrors == 0)
 			finish = 1;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201003141944.o2EJiFAl089581>