kern/163978: Loading hwpmc with an unknown cpuid causes a page fault in kernel mode.

Alan Somers alans at
Mon Jan 9 23:20:13 UTC 2012

>Number:         163978
>Category:       kern
>Synopsis:       Loading hwpmc with an unknown cpuid causes a page fault in kernel mode.
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jan 09 23:20:12 UTC 2012
>Originator:     Alan Somers
>Release:        10.0-CURRENT
FreeBSD fbtst.eng 10.0-CURRENT FreeBSD 10.0-CURRENT #11: Mon Jan  9 22:51:28 MST 2012     alans at fbdev.eng:/usr/home/alans/obj/usr/home/alans/spectra/branches/redline/projects/netback/SpectraBSD_head/sys/XENHVM.pmc  amd64

Attemping to use hwpmc from a Xen guest on a Core i7 running in 64 bit mode, I got the following crash on bootup:

xbd0: 20480MB <Virtual Block Device> at device/vbd/768 on xenbusb_front0
xbd0: attaching as ad0
Timecounter "TSC" frequency 2000036316 Hz quality 800

Fatal trap 12: page fault while in kernel mode
cpuid = 0; apic id = 00
fault virtual address	= 0x0
fault code		= supervisor read instruction, page not present
instruction pointer	= 0x20:0x0
stack pointer	        = 0x28:0xffffffff81985b90
frame pointer	        = 0x28:0xffffffff81985c10
code segment		= base 0x0, limit 0xfffff, type 0x1b
			= DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags	= interrupt enabled, resume, IOPL = 0
current process		= 0 (swapper)
[ thread pid 0 tid 100000 ]
Stopped at      0:      *** error reading from address 0 ***
db> where
Tracing pid 0 tid 100000 td 0xffffffff8154f8b0
uart_sab82532_class() at 0
load() at load+0x39
syscall_module_handler() at syscall_module_handler+0xe6
module_register_init() at module_register_init+0xb0
mi_startup() at mi_startup+0x139
btext() at btext+0x2c

The problem was that Xen changes the cpuid that guests see.  Specifically, the result of do_cpuid(CORE_CPUID_REQUEST, cpuid) is changed to indicate that performance counters are not supported.  Hence, pmc_core_initialize() returns EPROGMISMATCH.  Eventually, that causes pmc_initialize() to execute a null function pointer at line 4692.  Really, the root cause of the problem is that hwpmc isn't written very defensively.  I've attached a patch that makes the panic go away, but doesn't make PMC work for my processor.
Compile an amd64 Xen domU kernel with the below lines in your configuration file and boot it:
options    HWPMC_HOOKS
device     hwpmc

==== sys/dev/hwpmc/hwpmc_mod.c#2 (text) ====

@@ -4689,7 +4689,15 @@
                if (md->pmd_pcpu_init)
                        error = md->pmd_pcpu_init(md, cpu);
                for (n = 0; error == 0 && n < md->pmd_nclass; n++)
-                       error = md->pmd_classdep[n].pcd_pcpu_init(md, cpu);
+                       if (md->pmd_classdep[n].pcd_pcpu_init != NULL)
+                               error = md->pmd_classdep[n].pcd_pcpu_init(md,
+                                   cpu);
+                       else
+                               printf("hwpmc: md->pmd_classdep[%d]."
+                                   "pcd_pcpu_init was not initialized.  "
+                                   "This is a bug.\n"
+                                   "\tMost likely your CPUID is not "
+                                   "recognized by hwpmc.\n", n);
@@ -4882,7 +4890,15 @@
                        for (c = 0; c < md->pmd_nclass; c++)
-                               md->pmd_classdep[c].pcd_pcpu_fini(md, cpu);
+                               if (md->pmd_classdep[c].pcd_pcpu_fini != NULL)
+                                       md->pmd_classdep[c].pcd_pcpu_fini(md,
+                                           cpu);
+                               else
+                                       printf("hwpmc: md->pmd_classdep[%d]."
+                                           "pcd_pcpu_fini was not initialized."
+                                           "  This is a bug.\n"
+                                           "\tMost likely your CPUID is not "
+                                           "recognized by hwpmc.\n", c);
                        if (md->pmd_pcpu_fini)
                                md->pmd_pcpu_fini(md, cpu);


More information about the freebsd-bugs mailing list