From owner-p4-projects@FreeBSD.ORG Sun Mar 14 19:44:16 2010 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 1B7E8106566B; Sun, 14 Mar 2010 19:44:16 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D3EFF1065670 for ; Sun, 14 Mar 2010 19:44:15 +0000 (UTC) (envelope-from jhb@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id B6E088FC22 for ; Sun, 14 Mar 2010 19:44:15 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id o2EJiF7Q089583 for ; Sun, 14 Mar 2010 19:44:15 GMT (envelope-from jhb@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id o2EJiFAl089581 for perforce@freebsd.org; Sun, 14 Mar 2010 19:44:15 GMT (envelope-from jhb@freebsd.org) Date: Sun, 14 Mar 2010 19:44:15 GMT Message-Id: <201003141944.o2EJiFAl089581@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to jhb@freebsd.org using -f From: John Baldwin To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 175686 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 14 Mar 2010 19:44:16 -0000 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 #include #include +#include #include #include #include @@ -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;