--- //depot/vendor/mcelog/Makefile 2010-03-05 20:24:22.000000000 0000 +++ //depot/projects/mcelog/Makefile 2010-08-04 18:07:01.000000000 0000 @@ -1,5 +1,5 @@ CFLAGS := -g -Os -prefix := /usr +prefix := /usr/local etcprefix := # Define appropiately for your distribution # DOCDIR := /usr/share/doc/packages/mcelog @@ -28,10 +28,18 @@ .PHONY: install clean depend +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 + eventloop.o leaky-bucket.o memdb.o server.o client.o \ + cache.o rbtree.o +ifndef FREEBSD +OBJ += page.o trigger.o sysfs.o yellow.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 @@ -47,7 +55,7 @@ SRC := $(OBJ:.o=.c) -mcelog: ${OBJ} +mcelog: ${OBJ} ${LIBS} # dbquery intentionally not installed by default install: mcelog --- //depot/vendor/mcelog/cache.c 2010-03-05 20:24:22.000000000 0000 +++ //depot/projects/mcelog/cache.c 2010-03-05 21:09:24.000000000 0000 @@ -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 @@ 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() --- //depot/vendor/mcelog/client.c 2010-03-05 20:24:22.000000000 0000 +++ //depot/projects/mcelog/client.c 2010-03-05 21:09:24.000000000 0000 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "mcelog.h" #include "client.h" @@ -48,6 +49,9 @@ 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"); --- //depot/vendor/mcelog/config.c 2010-03-05 20:24:22.000000000 0000 +++ //depot/projects/mcelog/config.c 2011-02-22 16:05:23.000000000 0000 @@ -18,6 +18,9 @@ Author: Andi Kleen */ #define _GNU_SOURCE 1 +#ifdef __FreeBSD__ +#include +#endif #include #include #include @@ -126,6 +129,21 @@ return s; } +#if defined(__FreeBSD__) && __FreeBSD_version < 800067 +/* Provide a stub getline() for older versions of FreeBSD. */ +static ssize_t getline(char **cp, size_t *lenp, FILE *f) +{ + + if (*cp == NULL) { + *cp = malloc(4096); + *lenp = 4096; + } + if (fgets(*cp, *lenp, f) == NULL) + return (0); + return (strlen(*cp)); +} +#endif + int parse_config_file(const char *fn) { FILE *f; --- //depot/vendor/mcelog/eventloop.c 2010-03-05 20:24:22.000000000 0000 +++ //depot/projects/mcelog/eventloop.c 2010-03-05 21:09:24.000000000 0000 @@ -38,7 +38,9 @@ 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 @@ } /* Run signal handler only directly after event loop */ +#ifdef __Linux__ int event_signal(int sig) { static int first = 1; @@ -111,11 +114,17 @@ return -1; return 0; } +#endif void eventloop(void) { for (;;) { +#ifdef __Linux__ int n = ppoll(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"); --- //depot/vendor/mcelog/intel.c 2010-03-05 20:24:22.000000000 0000 +++ //depot/projects/mcelog/intel.c 2010-09-07 13:51:01.000000000 0000 @@ -38,7 +38,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; if (model >= 0x1a) @@ -79,7 +79,9 @@ corr_err_cnt = EXTRACT(m->status, 38, 52); memory_error(m, channel, dimm, corr_err_cnt, recordlen); +#ifdef __Linux__ account_page_error(m, channel, dimm, corr_err_cnt); +#endif return 1; } --- //depot/vendor/mcelog/mcelog.c 2010-03-05 20:24:22.000000000 0000 +++ //depot/projects/mcelog/mcelog.c 2010-08-25 11:41:19.000000000 0000 @@ -20,8 +20,21 @@ #define _GNU_SOURCE 1 #include #include +#ifdef __Linux__ #include #include +#endif +#ifdef __FreeBSD__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif #include #include #include @@ -59,7 +72,9 @@ enum cputype cputype = CPU_GENERIC; +#ifdef __Linux__ char *logfn = LOG_DEV_FILENAME; +#endif int ignore_nodev; int filter_bogus = 1; @@ -70,12 +85,18 @@ 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; +#ifdef __FreeBSD__ +static char *execfile; +static char *corefile; +#endif static void check_cpu(void); @@ -388,6 +409,7 @@ Wprintf("\n"); } +#ifdef __Linux__ void check_cpu(void) { enum { @@ -455,7 +477,44 @@ } else Eprintf("warning: Cannot open /proc/cpuinfo\n"); } +#endif + +#ifdef __FreeBSD__ +void check_cpu(void) +{ + char vendor[20]; + u_int regs[4]; + u_int cpu_id; + int family, model; + static int checked; + if (checked) + return; + 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); + /* Add checks for other CPUs here */ +} +#endif + +#ifdef __Linux__ static char *skipspace(char *s) { while (isspace(*s)) @@ -479,6 +538,7 @@ } return skipspace(s); } +#endif static void dump_mce_final(struct mce *m, char *symbol, int missing, int recordlen, int dseen) @@ -501,6 +561,7 @@ if (recordlen < endof_field(struct mce, f)) \ recordlen = endof_field(struct mce, f) +#ifdef __Linux__ /* Decode ASCII input for fatal messages */ static void decodefatal(FILE *inf) { @@ -646,7 +707,228 @@ 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) { unlink(pidfile); @@ -686,6 +968,10 @@ " 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 "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" @@ -866,6 +1152,14 @@ case O_CONFIG_FILE: /* parsed in config.c */ break; +#ifdef __FreeBSD__ + case 'M': + corefile = strdup(optarg); + break; + case 'N': + execfile = strdup(optarg); + break; +#endif case 0: break; default: @@ -900,8 +1194,10 @@ static void general_setup(void) { +#ifdef __Linux__ trigger_setup(); yellow_setup(); +#endif config_cred("global", "run-credentials", &runcred); if (config_bool("global", "filter-memory-errors") == 1) filter_memory_errors = 1; @@ -924,6 +1220,7 @@ } } +#ifdef __Linux__ static void process(int fd, unsigned recordlen, unsigned loglen, char *buf) { int i; @@ -964,7 +1261,174 @@ 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) { if (getopt_long(ac, av, "", options, NULL) != -1) @@ -1022,22 +1486,30 @@ 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 int main(int ac, char **av) { +#ifdef __Linux__ struct mcefd_data d = {}; + int fd; +#endif int opt; - int fd; parse_config(av); - while ((opt = getopt_long(ac, av, "", 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) { @@ -1057,13 +1529,21 @@ } else if (opt == 0) break; } +#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) @@ -1078,24 +1558,39 @@ err("MCE_GET_LOG_LEN"); d.buf = xalloc(d.recordlen * d.loglen); +#endif if (daemon_mode) { check_cpu(); prefill_memdb(); if (!do_dmi) closedmi(); server_setup(); +#ifdef __Linux__ page_setup(); +#endif 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(); 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); } --- //depot/vendor/mcelog/mcelog.h 2010-03-05 20:24:22.000000000 0000 +++ //depot/projects/mcelog/mcelog.h 2010-03-05 21:09:24.000000000 0000 @@ -64,9 +64,11 @@ #define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */ #define MCI_STATUS_PCC (1ULL<<57) /* processor context corrupt */ +#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 */ +#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 #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; --- //depot/vendor/mcelog/memdb.c 2010-03-05 20:24:22.000000000 0000 +++ //depot/projects/mcelog/memdb.c 2010-03-05 21:09:24.000000000 0000 @@ -170,7 +170,9 @@ asprintf(&env[ei++], "THRESHOLD_COUNT=%d", bucket->count + bucket->excess); 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: --- //depot/vendor/mcelog/p4.c 2010-03-05 20:24:22.000000000 0000 +++ //depot/projects/mcelog/p4.c 2010-03-05 21:09:24.000000000 0000 @@ -175,8 +175,10 @@ 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); +#endif } else if (test_prefix(10, mca)) { if (mca == 0x400) Wprintf("Internal Timer error\n"); --- //depot/vendor/mcelog/server.c 2010-03-05 20:24:22.000000000 0000 +++ //depot/projects/mcelog/server.c 2010-03-05 21:09:24.000000000 0000 @@ -101,7 +101,9 @@ static void dispatch_pages(FILE *fh) { +#ifdef __Linux__ dump_page_errors(fh); +#endif fprintf(fh, "done\n"); } @@ -137,6 +139,7 @@ Enomem(); } +#ifdef __Linux__ /* check if client is allowed to access */ static int access_check(int fd, struct msghdr *msg) { @@ -162,6 +165,35 @@ 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 @@ { 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) { --- //depot/vendor/mcelog/tsc.c 2010-03-05 20:24:22.000000000 0000 +++ //depot/projects/mcelog/tsc.c 2010-03-05 21:09:24.000000000 0000 @@ -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 @@ return 0; } +#ifdef __Linux__ static double cpufreq_mhz(int cpu, double infomhz) { double mhz; @@ -68,12 +75,29 @@ 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 @@ 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)