Index: head/sysutils/mcelog/Makefile =================================================================== --- head/sysutils/mcelog/Makefile (revision 410603) +++ head/sysutils/mcelog/Makefile (revision 410604) @@ -1,38 +1,35 @@ # Created by: Jeremy Chadwick # $FreeBSD$ PORTNAME= mcelog -DISTVERSION= 1.0pre3 +DISTVERSIONPREFIX= v +DISTVERSION= 133 CATEGORIES= sysutils -MASTER_SITES= ftp://ftp.kernel.org/pub/linux/utils/cpu/mce/ \ - http://147.52.159.12/mirrors/ftp.kernel.org/pub/linux/utils/cpu/mce/ \ - http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/utils/cpu/mce/ \ - http://mirror.be.gbxs.net/pub/linux/utils/cpu/mce/ \ - http://ftp.eu.openbsd.org/pub/linux/utils/cpu/mce/ \ - http://korg.cs.utah.edu/pub/linux/utils/cpu/mce/ \ - http://ftp.oregonstate.edu/pub/linux/utils/cpu/mce/ -MAINTAINER= jdc@koitsu.org +MAINTAINER= ultima1252@gmail.com COMMENT= Collects and decodes Machine Check Exception data LICENSE= GPLv2 +USE_GITHUB= yes +GH_ACCOUNT= andikleen + ONLY_FOR_ARCHS= amd64 i386 ia64 -PATCH_STRIP= -p1 - USES= alias gmake MAKE_ENV+= FREEBSD=1 -LDFLAGS= -lkvm +LDFLAGS+= -lkvm PLIST_FILES= bin/mcelog man/man8/mcelog.8.gz post-patch: @${CP} ${FILESDIR}/memstream.c ${WRKSRC}/memstream.c + ${REINPLACE_CMD} 's/\"unknown\"/\"${PORTVERSION}\"/' \ + ${WRKSRC}/Makefile do-install: ${INSTALL_PROGRAM} ${WRKSRC}/mcelog ${STAGEDIR}${PREFIX}/bin ${INSTALL_MAN} ${WRKSRC}/mcelog.8 ${STAGEDIR}${MANPREFIX}/man/man8 .include Index: head/sysutils/mcelog/distinfo =================================================================== --- head/sysutils/mcelog/distinfo (revision 410603) +++ head/sysutils/mcelog/distinfo (revision 410604) @@ -1,2 +1,2 @@ -SHA256 (mcelog-1.0pre3.tar.gz) = 0782e0aa952fa4bd641071e6b501774a63993a813a4f494ffd7819521a13c50c -SIZE (mcelog-1.0pre3.tar.gz) = 176649 +SHA256 (andikleen-mcelog-v133_GH0.tar.gz) = 3b16bbbbd1f92501b046190b69f236e80def4b8de71f0ef86f89ec99bdc6dff5 +SIZE (andikleen-mcelog-v133_GH0.tar.gz) = 298521 Index: head/sysutils/mcelog/files/patch-Makefile =================================================================== --- head/sysutils/mcelog/files/patch-Makefile (revision 410603) +++ head/sysutils/mcelog/files/patch-Makefile (revision 410604) @@ -1,49 +1,61 @@ ---- Makefile.orig 2010-01-21 02:36:52 UTC +--- Makefile.orig 2016-02-10 18:38:43 UTC +++ Makefile @@ -1,5 +1,4 @@ -CFLAGS := -g -Os -prefix := /usr +prefix := /usr/local etcprefix := + MANDIR := ${prefix}/share/man # Define appropiately for your distribution - # DOCDIR := /usr/share/doc/packages/mcelog -@@ -28,11 +27,18 @@ all: mcelog +@@ -32,13 +31,19 @@ all: mcelog - .PHONY: install clean depend + .PHONY: install clean depend FORCE +LIBS := OBJ := p4.o k8.o mcelog.o dmi.o tsc.o core2.o bitfield.o intel.o \ nehalem.o dunnington.o tulsa.o config.o memutil.o msg.o \ - eventloop.o leaky-bucket.o memdb.o server.o trigger.o \ - client.o cache.o sysfs.o yellow.o page.o rbtree.o \ -- xeon75xx.o +- xeon75xx.o sandy-bridge.o ivy-bridge.o haswell.o \ +- broadwell_de.o broadwell_epex.o msr.o bus.o \ +- unknown.o + eventloop.o leaky-bucket.o memdb.o server.o client.o \ -+ cache.o rbtree.o xeon75xx.o ++ cache.o rbtree.o xeon75xx.o sandy-bridge.o ivy-bridge.o \ ++ haswell.o broadwell_de.o broadwell_epex.o msr.o +ifndef FREEBSD -+OBJ += page.o trigger.o sysfs.o yellow.o ++OBJ += page.o trigger.o sysfs.o yellow.o bus.o unknown.o +endif +ifdef FREEBSD +OBJ += memstream.o +LIBS += -lkvm +endif DISKDB_OBJ := diskdb.o dimm.o db.o - CLEAN := mcelog dmi tsc dbquery .depend .depend.X dbquery.o ${DISKDB_OBJ} - DOC := mce.pdf -@@ -48,7 +54,7 @@ endif + CLEAN := mcelog dmi tsc dbquery .depend .depend.X dbquery.o ${DISKDB_OBJ} \ + version.o version.c version.tmp +@@ -55,7 +60,7 @@ endif SRC := $(OBJ:.o=.c) --mcelog: ${OBJ} -+mcelog: ${OBJ} ${LIBS} +-mcelog: ${OBJ} version.o ++mcelog: ${OBJ} ${LIBS} version.o # dbquery intentionally not installed by default - install: mcelog -@@ -82,8 +88,6 @@ depend: .depend + install: mcelog mcelog.conf mcelog.conf.5 mcelog.triggers.5 +@@ -94,7 +99,7 @@ depend: .depend + + version.tmp: FORCE + ( echo -n "char version[] = \"" ; \ +- if type -p git >/dev/null; then \ ++ if command -v git >/dev/null; then \ + if [ -d .git ] ; then \ + git describe --tags HEAD | tr -d '\n'; \ + else \ +@@ -110,8 +115,6 @@ version.c: version.tmp .depend: ${SRC} ${CC} -MM -I. ${SRC} > .depend.X && mv .depend.X .depend -include .depend - Makefile: .depend .PHONY: iccverify src test Index: head/sysutils/mcelog/files/patch-cache.c =================================================================== --- head/sysutils/mcelog/files/patch-cache.c (revision 410603) +++ head/sysutils/mcelog/files/patch-cache.c (revision 410604) @@ -1,26 +1,26 @@ ---- ./cache.c.orig 2009-12-15 07:18:40.000000000 -0500 -+++ ./cache.c 2011-10-14 22:36:47.000000000 -0400 +--- cache.c.orig 2016-02-10 18:38:43 UTC ++++ cache.c @@ -27,6 +27,7 @@ #include "sysfs.h" #include "cache.h" +#ifdef __Linux__ struct cache { unsigned level; /* Numerical values must match MCACOD */ -@@ -164,6 +165,15 @@ +@@ -173,6 +174,15 @@ int cache_to_cpus(int cpu, unsigned leve Wprintf("Cannot find sysfs cache for CPU %d", cpu); return -1; } +#endif + +#ifdef __FreeBSD__ +int cache_to_cpus(int cpu, unsigned level, unsigned type, + int *cpulen, unsigned **cpumap) +{ + return -1; +} +#endif #ifdef TEST main() Index: head/sysutils/mcelog/files/patch-client.c =================================================================== --- head/sysutils/mcelog/files/patch-client.c (revision 410603) +++ head/sysutils/mcelog/files/patch-client.c (revision 410604) @@ -1,20 +1,20 @@ ---- ./client.c.orig 2009-12-15 07:18:40.000000000 -0500 -+++ ./client.c 2011-10-14 22:36:47.000000000 -0400 +--- client.c.orig 2016-02-10 18:38:43 UTC ++++ client.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "mcelog.h" #include "client.h" -@@ -48,6 +49,9 @@ +@@ -48,6 +49,9 @@ void ask_server(char *command) sizeof(struct sockaddr_un)) < 0) SYSERRprintf("client connect"); +#ifdef __FreeBSD__ + /* XXX: Need to use sendmsg() to send a SCM_CREDS control message. */ +#endif n = strlen(command); if (write(fd, command, n) != n) SYSERRprintf("client command write"); Index: head/sysutils/mcelog/files/patch-eventloop.c =================================================================== --- head/sysutils/mcelog/files/patch-eventloop.c (revision 410603) +++ head/sysutils/mcelog/files/patch-eventloop.c (revision 410604) @@ -1,46 +1,46 @@ ---- eventloop.c.orig 2010-01-20 18:36:52.000000000 -0800 -+++ eventloop.c 2012-09-22 02:25:13.281116126 -0700 -@@ -38,7 +38,9 @@ +--- eventloop.c.orig 2016-02-10 18:38:43 UTC ++++ eventloop.c +@@ -38,7 +38,9 @@ struct pollcb { static struct pollfd pollfds[MAX_POLLFD]; static struct pollcb pollcbs[MAX_POLLFD]; +#ifdef __Linux__ static sigset_t event_sigs; +#endif static int closeonexec(int fd) { -@@ -97,6 +99,7 @@ +@@ -97,6 +99,7 @@ static void poll_callbacks(int n) } /* Run signal handler only directly after event loop */ +#ifdef __Linux__ int event_signal(int sig) { static int first = 1; -@@ -126,17 +129,25 @@ +@@ -126,17 +129,25 @@ static int ppoll_fallback(struct pollfd static int (*ppoll_vec)(struct pollfd *, nfds_t, const struct timespec *, const sigset_t *); +#endif void eventloop(void) { +#ifdef __Linux__ #if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 5 || __GLIBC__ > 2 ppoll_vec = ppoll; #endif if (!ppoll_vec) ppoll_vec = ppoll_fallback; +#endif for (;;) { +#ifdef __Linux__ int n = ppoll_vec(pollfds, max_pollfd, NULL, &event_sigs); +#endif +#ifdef __FreeBSD__ + int n = poll(pollfds, max_pollfd, -1); +#endif if (n <= 0) { if (n < 0 && errno != EINTR) SYSERRprintf("poll error"); Index: head/sysutils/mcelog/files/patch-intel.c =================================================================== --- head/sysutils/mcelog/files/patch-intel.c (revision 410603) +++ head/sysutils/mcelog/files/patch-intel.c (revision 410604) @@ -1,30 +1,21 @@ ---- intel.c.orig 2010-01-20 18:36:52.000000000 -0800 -+++ intel.c 2012-09-22 01:58:40.204115724 -0700 -@@ -43,7 +43,7 @@ - return CPU_CORE2; - else if (model == 0x1d) - return CPU_DUNNINGTON; -- else if (model == 0x1a) -+ else if (model == 0x1a || model == 0x2c) /* Nehalem/Westmere */ - return CPU_NEHALEM; - else if (model == 0x2e) - return CPU_XEON75XX; -@@ -94,14 +94,18 @@ +--- intel.c.orig 2016-02-10 18:38:43 UTC ++++ intel.c +@@ -141,14 +141,18 @@ static int intel_memory_error(struct mce if (recordlen > offsetof(struct mce, mcgcap) && m->mcgcap & MCG_CMCI_P) corr_err_cnt = EXTRACT(m->status, 38, 52); memory_error(m, channel[0], dimm[0], corr_err_cnt, recordlen); +#ifdef __Linux__ account_page_error(m, channel[0], dimm[0]); +#endif /* * When both DIMMs have a error account the error twice to the page. */ if (channel[1] != -1) { memory_error(m, channel[1], dimm[1], corr_err_cnt, recordlen); +#ifdef __Linux__ account_page_error(m, channel[1], dimm[1]); +#endif } return 1; Index: head/sysutils/mcelog/files/patch-mcelog.c =================================================================== --- head/sysutils/mcelog/files/patch-mcelog.c (revision 410603) +++ head/sysutils/mcelog/files/patch-mcelog.c (revision 410604) @@ -1,681 +1,713 @@ ---- mcelog.c.orig 2010-01-20 18:36:52.000000000 -0800 -+++ mcelog.c 2012-09-22 02:34:19.182116917 -0700 +--- mcelog.c.orig 2016-02-10 18:38:43 UTC ++++ mcelog.c @@ -20,9 +20,22 @@ #define _GNU_SOURCE 1 #include #include +#ifdef __Linux__ #include #include #include +#endif +#ifdef __FreeBSD__ +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#undef CPU_P4 #include #include #include -@@ -58,9 +71,25 @@ - #include "yellow.h" - #include "page.h" +@@ -61,9 +74,25 @@ + #include "bus.h" + #include "unknown.h" +struct mca_record { + uint64_t mr_status; + uint64_t mr_addr; + uint64_t mr_misc; + uint64_t mr_tsc; + int mr_apic_id; + int mr_bank; + uint64_t mr_mcg_cap; + uint64_t mr_mcg_status; + int mr_cpu_id; + int mr_cpu_vendor_id; + int mr_cpu; +}; + enum cputype cputype = CPU_GENERIC; +#ifdef __Linux__ char *logfn = LOG_DEV_FILENAME; +#endif int ignore_nodev; int filter_bogus = 1; -@@ -71,12 +100,18 @@ +@@ -74,7 +103,9 @@ int ascii_mode; int dump_raw_ascii; int daemon_mode; static char *inputfile; +#ifdef __Linux__ char *processor_flags; +#endif static int foreground; int filter_memory_errors; static struct config_cred runcred = { .uid = -1U, .gid = -1U }; - static int numerrors; - static char *pidfile; +@@ -83,6 +114,10 @@ static char pidfile_default[] = PID_FILE + static char logfile_default[] = LOG_FILE; + static char *pidfile = pidfile_default; + static char *logfile; +#ifdef __FreeBSD__ +static char *execfile; +static char *corefile; +#endif - - static void check_cpu(void); - -@@ -393,6 +428,7 @@ + static int debug_numerrors; + int imc_log = -1; + static int check_only = 0; +@@ -482,6 +517,7 @@ static void dump_mce_raw_ascii(struct mc Wprintf("\n"); } +#ifdef __Linux__ - void check_cpu(void) + int is_cpu_supported(void) { enum { -@@ -460,7 +496,45 @@ - } else - Eprintf("warning: Cannot open /proc/cpuinfo\n"); +@@ -552,13 +588,58 @@ int is_cpu_supported(void) + + return 1; } +#endif -+ + +#ifdef __FreeBSD__ -+void check_cpu(void) ++int is_cpu_supported(void) +{ + char vendor[20]; + u_int regs[4]; + u_int cpu_id; + int family, model; + static int checked; + + if (checked) -+ return; ++ return 1; + + checked = 1; + + 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; + + do_cpuid(1, regs); + cpu_id = regs[0]; + family = CPUID_TO_FAMILY(cpu_id); + model = CPUID_TO_MODEL(cpu_id); + + if (cpu_forced) + ; -+ else if (!strcmp(vendor,"AuthenticAMD") && -+ (family == 15 || family == 16 || family == 17)) -+ cputype = CPU_K8; -+ else if (!strcmp(vendor,"GenuineIntel")) -+ cputype = select_intel_cputype(family, model); ++ else if (!strcmp(vendor,"AuthenticAMD")) { ++ if (family == 15) { ++ cputype = CPU_K8; ++ } else if (family >= 16) { ++ SYSERRprintf("ERROR: AMD Processor family %d: mcelog does not support this processor. Please use the edac_mce_amd module instead.\n", family); ++ return 0; ++ } ++ } else if (!strcmp(vendor,"GenuineIntel")) ++ cputype = select_intel_cputype(family, model); + /* Add checks for other CPUs here */ ++ else ++ return 1; +} +#endif - ++ +#ifdef __Linux__ static char *skipspace(char *s) { while (isspace(*s)) -@@ -484,6 +558,7 @@ - } - return skipspace(s); + ++s; + return s; } +#endif - static void dump_mce_final(struct mce *m, char *symbol, int missing, int recordlen, - int dseen) -@@ -507,6 +582,7 @@ + static char *skip_syslog(char *s) + { +@@ -667,6 +748,7 @@ static int match_patterns(char *s, char recordlen = endof_field(struct mce, f) /* Decode ASCII input for fatal messages */ +#ifdef __Linux__ static void decodefatal(FILE *inf) { struct mce m; -@@ -651,6 +727,227 @@ +@@ -877,6 +959,227 @@ restart: if (data) dump_mce_final(&m, symbol, missing, recordlen, disclaimer_seen); } +#endif + +#ifdef __FreeBSD__ +/* + * 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", 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, + 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 older live records (from sysctl), fill in some fields + * using registers from the current CPU. + */ + if (len < offsetof(struct mca_record, mr_cpu_id) && live) { + char vendor[20]; + 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 = find_cpu_vendor(vendor); + + do_cpuid(1, regs); + mce->cpuid = regs[0]; + } +} + +/* Decode ASCII input for fatal messages */ +static void decodefatal(FILE *inf) +{ + struct mca_record mr; + struct mce m; + long long val, val2; + char *cp, line[100], *s, symbol[1]; + const char *fmt; + int cpu, data, old, missing; + enum rows { + 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: "); + if (s == NULL) + continue; + s += strlen("MCA: "); + + 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. */ + if (data & BANK) { + if (mr.mr_status & MC_STATUS_ADDRV && + !(data & ADDR)) + missing = 1; + if (mr.mr_status & MC_STATUS_MISCV && + !(data & MISC)) + missing = 1; + convert_mca(&mr, &m, 0, sizeof(mr)); + mce_cpuid(&m); + dump_mce_final(&m, symbol, missing, + sizeof(struct mce), 0); + } + data = 0; + missing = 0; + memset(&mr, 0, sizeof(mr)); + } + + 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 ", &cpu) != 1) + missing = 1; + 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) + missing = 1; + else { + data |= ADDR; + mr.mr_addr = val; + } + } + if (strncmp(s, "Misc", 4) == 0) { + if (sscanf(s, "Misc 0x%llx", &val) != 1) + missing = 1; + else { + data |= MISC; + mr.mr_misc = val; + } + } + } + + /* Dump the last record. */ + if (data & BANK) { + if (mr.mr_status & MC_STATUS_ADDRV && !(data & ADDR)) + missing = 1; + if (mr.mr_status & MC_STATUS_MISCV && !(data & MISC)) + missing = 1; + convert_mca(&mr, &m, 0, sizeof(mr)); + mce_cpuid(&m); + dump_mce_final(&m, symbol, missing, sizeof(struct mce), 0); + } +} +#endif static void remove_pidfile(void) { -@@ -709,6 +1006,10 @@ +@@ -941,6 +1244,10 @@ void usage(void) " mcelog [options] --ascii < log\n" " mcelog [options] --ascii --file log\n" "Decode machine check ASCII output from kernel logs\n" +#ifdef __FreeBSD_ +" mcelog [options] -M vmcore -N kernel\n" +"Decode machine check error records from kernel crashdump.\n" +#endif + "\n" "Options:\n" - "--cpu CPU Set CPU type CPU to decode (see below for valid types)\n" - "--cpumhz MHZ Set CPU Mhz to decode time (output unreliable, not needed on new kernels)\n" -@@ -889,6 +1190,14 @@ - case O_CONFIG_FILE: - /* parsed in config.c */ + "--version Show the version of mcelog and exit\n" +@@ -1147,6 +1454,14 @@ static int modifier(int opt) + case O_IS_CPU_SUPPORTED: + check_only = 1; break; +#ifdef __FreeBSD__ + case 'M': + corefile = strdup(optarg); + break; + case 'N': + execfile = strdup(optarg); + break; +#endif case 0: break; default: -@@ -923,8 +1232,10 @@ +@@ -1197,10 +1512,12 @@ static int combined_modifier(int opt) static void general_setup(void) { +#ifdef __Linux__ trigger_setup(); yellow_setup(); + bus_setup(); + unknown_setup(); +#endif config_cred("global", "run-credentials", &runcred); if (config_bool("global", "filter-memory-errors") == 1) filter_memory_errors = 1; -@@ -947,6 +1258,7 @@ +@@ -1223,6 +1540,7 @@ static void drop_cred(void) } } +#ifdef __Linux__ static void process(int fd, unsigned recordlen, unsigned loglen, char *buf) { int i; -@@ -987,6 +1299,173 @@ +@@ -1275,6 +1593,173 @@ static void process(int fd, unsigned rec if (finish) exit(0); } +#endif + +#ifdef __FreeBSD__ +#ifdef LOCAL_HACK +struct mca_record_old { + uint64_t mr_status; + uint64_t mr_addr; + uint64_t mr_misc; + uint64_t mr_tsc; + int mr_apic_id; + int mr_bank; +}; +#endif + +struct mca_record_internal { + struct mca_record rec; + int logged; + STAILQ_ENTRY(mca_internal) link; +}; + +#ifdef LOCAL_HACK +struct mca_record_internal_old { + struct mca_record_old rec; + int logged; + STAILQ_ENTRY(mca_internal) link; +}; +#endif + +static struct nlist nl[] = { +#define X_MCA_RECORDS 0 + { .n_name = "_mca_records" }, +#ifdef LOCAL_HACK +#define X_SNAPDATE 1 + { .n_name = "_snapdate" }, +#endif + { .n_name = NULL }, +}; + +static int +kread(kvm_t *kvm, void *kvm_pointer, void *buf, size_t size, size_t offset) +{ + ssize_t ret; + + ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, buf, size); + if (ret < 0 || (size_t)ret != size) + return (-1); + return (0); +} + +static int +kread_symbol(kvm_t *kvm, int index, void *buf, size_t size) +{ + ssize_t ret; + + ret = kvm_read(kvm, nl[index].n_value, buf, size); + if (ret < 0 || (size_t)ret != size) + return (-1); + return (0); +} + +static void process_kvm(const char *execfile, const char *corefile) +{ + struct mca_record mr, *mrp; + struct mce mce; + char errbuf[_POSIX2_LINE_MAX]; + kvm_t *kvm; + size_t record_size, link_offset; + int i; +#ifdef LOCAL_HACK + int snapdate; +#endif + + kvm = kvm_openfiles(execfile, corefile, NULL, O_RDONLY, errbuf); + if (kvm == NULL) + errx(1, "kvm_openfiles: %s", errbuf); + if (kvm_nlist(kvm, nl) != 0) + errx(1, "kvm_nlist: %s", kvm_geterr(kvm)); + +#ifdef LOCAL_HACK + if (kread_symbol(kvm, X_SNAPDATE, &snapdate, sizeof(snapdate)) < 0) + errx(1, "kvm_read(snapdate) failed"); +#endif + /* stqh_first is the first pointer at this address. */ + if (kread_symbol(kvm, X_MCA_RECORDS, &mrp, sizeof(mrp)) < 0) + errx(1, "kvm_read(mca_records) failed"); +#ifdef LOCAL_HACK + if (snapdate >= 20100329) { +#endif + record_size = sizeof(struct mca_record); + link_offset = __offsetof(struct mca_record_internal, + link.stqe_next); +#ifdef LOCAL_HACK + } else { + record_size = sizeof(struct mca_record_old); + link_offset = __offsetof(struct mca_record_internal_old, + link.stqe_next); + } +#endif + + for (i = 0; mrp != NULL; i++) { + memset(&mr, 0, sizeof(mr)); + if (kread(kvm, mrp, &mr, record_size, 0) < 0) + break; + if (kread(kvm, mrp, &mrp, sizeof(mrp), link_offset) < 0) + mrp = NULL; + + convert_mca(&mr, &mce, 1, record_size); + mce_prepare(&mce); + if (!mce_filter(&mce, sizeof(struct mce))) + continue; + if (!dump_raw_ascii) { + disclaimer(); + Wprintf("MCE %d\n", i); + dump_mce(&mce, sizeof(struct mce)); + } else + dump_mce_raw_ascii(&mce, sizeof(struct mce)); + flushlog(); + } + + exit(0); +} + +static void process_live(void) +{ + struct mca_record mr; + struct mce mce; + int mib[4]; + size_t len; + int count, finish, i; + + len = sizeof(count); + if (sysctlbyname("hw.mca.count", &count, &len, NULL, 0) < 0) + return; + + len = 4; + if (sysctlnametomib("hw.mca.records", mib, &len) < 0) + return; + + finish = 0; + for (i = 0; i < count; 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, len); + mce_prepare(&mce); + if (numerrors > 0 && --numerrors == 0) + finish = 1; + if (!mce_filter(&mce, sizeof(struct mce))) + continue; + if (!dump_raw_ascii) { + disclaimer(); + Wprintf("MCE %d\n", i); + dump_mce(&mce, sizeof(struct mce)); + } else + dump_mce_raw_ascii(&mce, sizeof(struct mce)); + flushlog(); + } + + if (finish) + exit(0); +} +#endif static void noargs(int ac, char **av) { -@@ -1045,22 +1524,30 @@ +@@ -1333,12 +1818,14 @@ struct mcefd_data { char *buf; }; +#ifdef __Linux__ static void process_mcefd(struct pollfd *pfd, void *data) { struct mcefd_data *d = (struct mcefd_data *)data; assert((pfd->revents & POLLIN) != 0); process(pfd->fd, d->recordlen, d->loglen, d->buf); } +#endif + static void handle_sigusr1(int sig) + { +@@ -1347,13 +1834,18 @@ static void handle_sigusr1(int sig) + int main(int ac, char **av) { +#ifdef __Linux__ struct mcefd_data d = {}; - int opt; int fd; +- +#endif + int opt; - parse_config(av); -+#ifdef __FreeBSD__ -+ while ((opt = getopt_long(ac, av, "M:N:", options, NULL)) != -1) { ++#ifdef __FreeBSD ++ while ((opt = getopt_long(ac, av, "M:N:", options, NULL)) != -1) { +#else while ((opt = getopt_long(ac, av, "", options, NULL)) != -1) { +#endif if (opt == '?') { usage(); } else if (combined_modifier(opt) > 0) { -@@ -1080,13 +1567,21 @@ - } else if (opt == 0) - break; +@@ -1375,11 +1867,13 @@ int main(int ac, char **av) } + + /* before doing anything else let's see if the CPUs are supported */ +#ifdef __Linux__ + if (!cpu_forced && !is_cpu_supported()) { + if (!check_only) + fprintf(stderr, "CPU is unsupported\n"); + exit(1); + } ++#endif + if (check_only) + exit(0); + +@@ -1398,13 +1892,21 @@ int main(int ac, char **av) + } + + modifier_finish(); ++#ifdef __Linux__ if (av[optind]) logfn = av[optind++]; +#endif if (av[optind]) usage(); +#ifdef __FreeBSD__ + if ((corefile != NULL) ^ (execfile != NULL) || + (corefile != NULL && daemon_mode)) + usage(); +#endif checkdmi(); general_setup(); +#ifdef __Linux__ fd = open(logfn, O_RDONLY); if (fd < 0) { if (ignore_nodev) -@@ -1101,24 +1596,39 @@ +@@ -1419,27 +1921,44 @@ int main(int ac, char **av) err("MCE_GET_LOG_LEN"); d.buf = xalloc(d.recordlen * d.loglen); +#endif if (daemon_mode) { - check_cpu(); - prefill_memdb(); + prefill_memdb(do_dmi); if (!do_dmi) closedmi(); server_setup(); +#ifdef __Linux__ page_setup(); +#endif + if (imc_log) + set_imc_log(cputype); drop_cred(); +#ifdef __Linux__ register_pollcb(fd, POLLIN, process_mcefd, &d); +#endif if (!foreground && daemon(0, need_stdout()) < 0) err("daemon"); if (pidfile) write_pidfile(); + signal(SIGUSR1, handle_sigusr1); ++#ifdef __Linux__ + event_signal(SIGUSR1); ++#endif eventloop(); } else { +#ifdef __Linux__ process(fd, d.recordlen, d.loglen, d.buf); +#endif +#ifdef __FreeBSD__ + if (corefile != NULL) + process_kvm(execfile, corefile); + else + process_live(); +#endif } +#ifdef __Linux__ trigger_wait(); +#endif exit(0); } Index: head/sysutils/mcelog/files/patch-mcelog.h =================================================================== --- head/sysutils/mcelog/files/patch-mcelog.h (revision 410603) +++ head/sysutils/mcelog/files/patch-mcelog.h (revision 410604) @@ -1,25 +1,26 @@ ---- ./mcelog.h.orig 2009-12-15 07:18:40.000000000 -0500 -+++ ./mcelog.h 2011-10-14 22:37:06.000000000 -0400 -@@ -64,9 +64,11 @@ - #define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */ - #define MCI_STATUS_PCC (1ULL<<57) /* processor context corrupt */ +--- mcelog.h.orig 2016-02-10 18:38:43 UTC ++++ mcelog.h +@@ -67,10 +67,12 @@ struct mce { + #define MCI_STATUS_AR (1ULL<<55) /* action-required */ + #define MCI_STATUS_FWST (1ULL<<37) /* Firmware updated status indicator */ +#ifndef MCG_STATUS_RIPV #define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */ #define MCG_STATUS_EIPV (1ULL<<1) /* eip points to correct instruction */ #define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */ + #define MCG_STATUS_LMCES (1ULL<<3) /* local machine check signaled */ +#endif #define MCG_CMCI_P (1ULL<<10) /* CMCI supported */ #define MCG_TES_P (1ULL<<11) /* Yellow bit cache threshold supported */ -@@ -89,6 +91,10 @@ - #define PRINTFLIKE +@@ -97,6 +99,10 @@ struct mce { + #define noreturn #endif +#if defined(__FreeBSD__) && defined(_STDIO_H_) +FILE *open_memstream(char **cp, size_t *lenp); +#endif + int Wprintf(char *fmt, ...) PRINTFLIKE; void Eprintf(char *fmt, ...) PRINTFLIKE; void SYSERRprintf(char *fmt, ...) PRINTFLIKE; Index: head/sysutils/mcelog/files/patch-memdb.c =================================================================== --- head/sysutils/mcelog/files/patch-memdb.c (revision 410603) +++ head/sysutils/mcelog/files/patch-memdb.c (revision 410604) @@ -1,12 +1,12 @@ ---- ./memdb.c.orig 2009-12-15 07:18:40.000000000 -0500 -+++ ./memdb.c 2011-10-14 22:36:47.000000000 -0400 -@@ -170,7 +170,9 @@ - asprintf(&env[ei++], "THRESHOLD_COUNT=%d", bucket->count + bucket->excess); +--- memdb.c.orig 2016-02-10 18:38:43 UTC ++++ memdb.c +@@ -172,7 +172,9 @@ void memdb_trigger(char *msg, struct mem + asprintf(&env[ei++], "THRESHOLD_COUNT=%d", bucket->count); env[ei] = NULL; assert(ei < MAX_ENV); +#ifdef __Linux__ run_trigger(bc->trigger, NULL, env); +#endif for (i = 0; i < ei; i++) free(env[i]); out: Index: head/sysutils/mcelog/files/patch-p4.c =================================================================== --- head/sysutils/mcelog/files/patch-p4.c (revision 410603) +++ head/sysutils/mcelog/files/patch-p4.c (revision 410604) @@ -1,13 +1,74 @@ ---- ./p4.c.orig 2009-12-15 07:18:40.000000000 -0500 -+++ ./p4.c 2011-10-14 22:36:47.000000000 -0400 -@@ -175,8 +175,10 @@ +--- p4.c.orig 2016-02-10 18:38:43 UTC ++++ p4.c +@@ -175,8 +175,10 @@ static int decode_mca(u64 status, u64 mi + levelnum = mca & 3; + level = get_LL_str(levelnum); + Wprintf("%s Generic cache hierarchy error\n", level); ++#ifdef __Linux__ + if (track == 2) + run_yellow_trigger(cpu, -1, levelnum, "unknown", level, socket); ++#endif + } else if (test_prefix(4, mca)) { + unsigned levelnum, typenum; + char *level, *type; +@@ -185,8 +187,10 @@ static int decode_mca(u64 status, u64 mi + levelnum = (mca & TLB_LL_MASK) >> TLB_LL_SHIFT; + level = get_LL_str(levelnum); + Wprintf("%s TLB %s Error\n", type, level); ++#ifdef __Linux__ + if (track == 2) + run_yellow_trigger(cpu, typenum, levelnum, type, level, socket); ++#endif + } else if (test_prefix(8, mca)) { + unsigned typenum = (mca & CACHE_TT_MASK) >> CACHE_TT_SHIFT; + unsigned levelnum = (mca & CACHE_LL_MASK) >> CACHE_LL_SHIFT; +@@ -195,8 +199,10 @@ static int decode_mca(u64 status, u64 mi Wprintf("%s CACHE %s %s Error\n", type, level, get_RRRR_str((mca & CACHE_RRRR_MASK) >> CACHE_RRRR_SHIFT)); +#ifdef __Linux__ if (track == 2) - run_yellow_trigger(cpu, typenum, levelnum, type, level, socket); + run_yellow_trigger(cpu, typenum, levelnum, type, level,socket); +#endif } else if (test_prefix(10, mca)) { if (mca == 0x400) Wprintf("Internal Timer error\n"); +@@ -215,7 +221,9 @@ static int decode_mca(u64 status, u64 mi + + Wprintf("BUS error: %d %d %s %s %s %s %s\n", socket, cpu, + level, pp, rrrr, ii, timeout); ++#ifdef __Linux__ + run_bus_trigger(socket, cpu, level, pp, rrrr, ii, timeout); ++#endif + /* IO MCA - reported as bus/interconnect with specific PP,T,RRRR,II,LL values + * and MISCV set. MISC register points to root port that reported the error + * need to cross check with AER logs for more details. +@@ -231,7 +239,9 @@ static int decode_mca(u64 status, u64 mi + fn = EXTRACT(misc, 16, 18); + Wprintf("IO MCA reported by root port %x:%02x:%02x.%x\n", + seg, bus, dev, fn); ++#ifdef __Linux__ + run_iomca_trigger(socket, cpu, seg, bus, dev, fn); ++#endif + } + } else if (test_prefix(7, mca)) { + decode_memory_controller(mca, bank); +@@ -365,14 +375,18 @@ void decode_intel_mc(struct mce *log, in + + if (log->bank == MCE_THERMAL_BANK) { + decode_thermal(log, cpu); ++#ifdef __Linux__ + run_unknown_trigger(socket, cpu, log); ++#endif + return; + } + + decode_mcg(log->mcgstatus); ++#ifdef __Linux__ + if (decode_mci(log->status, log->misc, cpu, log->mcgcap, ismemerr, + socket, log->bank)) + run_unknown_trigger(socket, cpu, log); ++#endif + + if (test_prefix(11, (log->status & 0xffffL))) { + switch (cputype) { Index: head/sysutils/mcelog/files/patch-server.c =================================================================== --- head/sysutils/mcelog/files/patch-server.c (revision 410603) +++ head/sysutils/mcelog/files/patch-server.c (revision 410604) @@ -1,92 +1,101 @@ ---- server.c.orig 2010-01-20 18:36:52.000000000 -0800 -+++ server.c 2012-09-22 02:39:04.991117023 -0700 -@@ -101,7 +101,9 @@ +--- server.c.orig 2016-02-10 18:38:43 UTC ++++ server.c +@@ -101,7 +101,9 @@ static void dispatch_dump(FILE *fh, char static void dispatch_pages(FILE *fh) { +#ifdef __Linux__ dump_page_errors(fh); +#endif fprintf(fh, "done\n"); } -@@ -137,6 +139,7 @@ +@@ -137,6 +139,7 @@ static void process_cmd(struct clientcon Enomem(); } +#ifdef __Linux__ /* check if client is allowed to access */ static int access_check(int fd, struct msghdr *msg) { -@@ -162,6 +165,35 @@ +@@ -162,11 +165,44 @@ static int access_check(int fd, struct m sendstring(fd, "permission denied\n"); return -1; } +#endif + +#ifdef __FreeBSD__ +/* check if client is allowed to access */ +static int access_check(int fd, struct msghdr *msg) +{ + struct cmsghdr *cmsg; + struct cmsgcred *cr; + + /* check credentials */ + cmsg = CMSG_FIRSTHDR(msg); + if (cmsg == NULL || + cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_CREDS) { + Eprintf("Did not receive credentials over client unix socket %p\n", + cmsg); + return -1; + } + cr = (struct cmsgcred *)CMSG_DATA(cmsg); + if (cr->cmcred_uid == 0 || + (acc.uid != -1U && cr->cmcred_uid == acc.uid) || + (acc.gid != -1U && cr->cmcred_gid == acc.gid)) + return 0; + Eprintf("rejected client access from pid:%u uid:%u gid:%u\n", + cr->cmcred_pid, cr->cmcred_uid, cr->cmcred_gid); + sendstring(fd, "permission denied\n"); + return -1; +} +#endif /* retrieve commands from client */ static int client_input(int fd, struct clientcon *cc) -@@ -242,18 +274,22 @@ { ++#ifdef __Linux__ + char ctlbuf[CMSG_SPACE(sizeof(struct ucred))]; ++#else ++ char ctlbuf[CMSG_SPACE(sizeof(struct cmsgcred))]; ++#endif + struct iovec miov; + struct msghdr msg = { + .msg_iov = &miov, +@@ -242,18 +278,22 @@ static void client_accept(struct pollfd + { struct clientcon *cc = NULL; int nfd = accept(pfd->fd, NULL, 0); +#ifdef __Linux__ int on; +#endif if (nfd < 0) { SYSERRprintf("accept failed on client socket"); return; } +#ifdef __Linux__ on = 1; if (setsockopt(nfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) { SYSERRprintf("Cannot enable credentials passing on client socket"); goto cleanup; } +#endif cc = xalloc(sizeof(struct clientcon)); if (register_pollcb(nfd, POLLIN, client_event, cc) < 0) { -@@ -300,7 +336,12 @@ - sigaction(SIGALRM, &sa, &oldsa); +@@ -301,7 +341,12 @@ static int server_ping(struct sockaddr_u if (sigsetjmp(ping_timeout_ctx, 1) == 0) { + ret = -1; alarm(initial_ping_timeout); +#ifdef __Linux__ if (connect(fd, un, sizeof(struct sockaddr_un)) < 0) +#endif +#ifdef __FreeBSD__ + if (connect(fd, (struct sockaddr *) un, sizeof(struct sockaddr_un)) < 0) +#endif goto cleanup; if (write(fd, PAIR("ping\n")) < 0) goto cleanup; Index: head/sysutils/mcelog/files/patch-tsc.c =================================================================== --- head/sysutils/mcelog/files/patch-tsc.c (revision 410603) +++ head/sysutils/mcelog/files/patch-tsc.c (revision 410604) @@ -1,95 +1,95 @@ ---- ./tsc.c.orig 2009-12-15 07:18:40.000000000 -0500 -+++ ./tsc.c 2011-10-14 22:36:47.000000000 -0400 +--- tsc.c.orig 2016-02-10 18:38:43 UTC ++++ tsc.c @@ -15,6 +15,12 @@ on your Linux system; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define _GNU_SOURCE 1 +#ifdef __FreeBSD__ +#include +#include +#include +#include +#endif #include #include #include -@@ -46,6 +52,7 @@ +@@ -46,6 +52,7 @@ static int fmt_tsc(char **buf, u64 tsc, return 0; } +#ifdef __Linux__ static double cpufreq_mhz(int cpu, double infomhz) { double mhz; -@@ -68,12 +75,29 @@ +@@ -68,12 +75,29 @@ static double cpufreq_mhz(int cpu, doubl fclose(f); return mhz; } +#endif + +#ifdef __FreeBSD__ +static double cpufreq_mhz(int cpu, double infomhz) +{ + double mhz; + uint64_t freq; + size_t len; + + len = sizeof(freq); + if (sysctlbyname("machdep.tsc_freq", &freq, &len, NULL, 0) < 0) + return infomhz; + mhz = freq / 1000000.0; + return mhz; +} +#endif int decode_tsc_forced(char **buf, double mhz, u64 tsc) { return fmt_tsc(buf, tsc, mhz); } +#ifdef __Linux__ static int deep_sleep_states(int cpu) { int ret; -@@ -132,6 +156,41 @@ +@@ -132,6 +156,41 @@ static int tsc_reliable(int cputype, int return 0; return 1; } +#endif + +#ifdef __FreeBSD__ +/* Try to figure out if this CPU has a somewhat reliable TSC clock */ +static int tsc_reliable(int cputype, int cpunum) +{ + u_int regs[4]; + u_int cpu_id, amd_pminfo; + + if (cputype != CPU_K8 && !is_intel_cpu(cputype)) + return 0; + + do_cpuid(0, regs); + cpu_id = regs[1]; + do_cpuid(0x80000000, regs); + if (regs[0] >= 0x80000007) { + do_cpuid(0x80000007, regs); + amd_pminfo = regs[3]; + } else + amd_pminfo = 0; + + if (amd_pminfo & AMDPM_TSC_INVARIANT) + return 1; + if (is_intel_cpu(cputype)) { + if (CPUID_TO_FAMILY(cpu_id) >= 0x10 || + cpu_id == 0x60fb2) + return 1; + } else if ((CPUID_TO_FAMILY(cpu_id) == 0x6 && + CPUID_TO_MODEL(cpu_id) >= 0xe) || + (CPUID_TO_FAMILY(cpu_id) == 0xf && CPUID_TO_MODEL(cpu_id) >= 0x3)) + return 1; + + return 0; +} +#endif int decode_tsc_current(char **buf, int cpunum, enum cputype cputype, double mhz, unsigned long long tsc)