kernel -- Add MONITOR and MWAIT routine to i386 kernel.
authorVenkatesh Srinivas <me@endeavour.zapto.org>
Sat, 18 Dec 2010 15:24:58 +0000 (07:24 -0800)
committerVenkatesh Srinivas <me@endeavour.zapto.org>
Sat, 18 Dec 2010 15:24:58 +0000 (07:24 -0800)
Provides cpu_mmw_spin() and cpu_mmw_mwait(), both of which wait for a given
memory cell to contain a value different from an expected value. _spin()
merely spins on the cell; _mwait() uses the SSE3 MONITOR/MWAIT isns.

sys/cpu/i386/misc/monitor.s [new file with mode: 0644]
sys/platform/pc32/conf/files
sys/platform/pc32/i386/identcpu.c
sys/sys/param.h
sys/sys/systm.h

diff --git a/sys/cpu/i386/misc/monitor.s b/sys/cpu/i386/misc/monitor.s
new file mode 100644 (file)
index 0000000..497e388
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010 The DragonFly Project. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Venkatesh Srinivas <me@endeavour.zapto.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asmacros.h>
+#include <machine/cputypes.h>
+#include <machine/pmap.h>
+#include <machine/specialreg.h>
+
+#include "assym.s"
+
+       .text
+
+/*
+ * int cpu_mmw_spin(int *addr, int oldval)
+ *
+ *     Spin on addr, waiting for it to no longer contain oldval; 
+ *     return newval.
+ */
+ENTRY(cpu_mmw_spin)
+       movl    4(%esp), %eax
+       movl    8(%esp), %edx
+
+       .align  4
+1:
+       movl    (%eax), %ecx
+       cmpl    %ecx, %edx
+       pause
+       je      1b
+
+       movl    %ecx, %eax
+       ret
+
+/*
+ * int cpu_mmw_mwait(int *addr, int oldval)
+ *
+ *     Spin on addr, waiting for it to no longer contain oldval;
+ *     return newval. Use the MONITOR/MWAIT instructions to wait
+ *     for a state-change on the address.
+ *     
+ *     WARN 1: We receive wakeup events for much larger windows
+ *             than a single address; CPUID EAX = 0x05 reports the
+ *             windows; on an Intel Atom they seem to cacheline-sized.
+ *             Synchronization variables should probably be 
+ *             cacheline-aligned to avoid false wakeups.
+ *
+ *     WARN 2: This routine can be racy; when we wake from MWAIT, we must
+ *             load the contents of the address; in the meantime, it
+ *             is possible that it was swapped to the prior (or some other)
+ *             value; care must be used -- CMPXCHG for wakeup, for example.
+ *
+ *     WARN 3: Use this routine only when cpu_mi_features & CPU_MI_MONITOR
+ */    
+ENTRY(cpu_mmw_mwait)
+       pushl   %ebx
+       movl    8(%esp), %eax
+       movl    12(%esp), %ebx
+       xorl    %ecx, %ecx
+       xorl    %edx, %edx
+
+       .align  4
+1:
+       monitor
+       movl    (%eax), %ecx
+       cmpl    %ebx, %ecx
+       jne     2f
+       mwait
+       jmp     1b
+
+       .align  4
+2:
+       movl    %ecx, %eax
+       popl    %ebx
+       ret
+
index 4036f38..e77ac5d 100644 (file)
@@ -154,6 +154,7 @@ cpu/i386/misc/ktr.c                 optional        ktr
 cpu/i386/misc/db_disasm.c              optional        ddb
 cpu/i386/misc/i386-gdbstub.c           optional        ddb
 cpu/i386/misc/bzeront.s                        standard
+cpu/i386/misc/monitor.s                        standard
 platform/pc32/i386/autoconf.c          standard
 platform/pc32/i386/bios.c              standard
 platform/pc32/i386/bioscall.s          standard
index 17145e4..c534563 100644 (file)
@@ -1259,6 +1259,8 @@ finish:
        if (cpu_feature & CPUID_SSE2)
                cpu_mi_feature |= CPU_MI_BZERONT;
 
+       if (cpu_feature2 & CPUID2_MON)
+               cpu_mi_feature |= CPU_MI_MONITOR;
 }
 
 static u_int
index 10c9107..b750f27 100644 (file)
  * cpu_mi_feature bits
  */
 #define CPU_MI_BZERONT 0x00000001
+#define CPU_MI_MONITOR 0x00000010
 
 /*
  * File system parameters and macros.
index ca580db..df0355f 100644 (file)
@@ -315,6 +315,8 @@ void                setsofttq (void);
 void           schedsofttty (void);
 void           splz (void);
 void           splz_check (void);
+int            cpu_mmw_spin(int *, int);
+int            cpu_mmw_mwait(int *, int);
 #endif /* __i386__ */
 
 /*