]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/ppc/commpage/commpage_asm.s
xnu-1228.3.13.tar.gz
[apple/xnu.git] / osfmk / ppc / commpage / commpage_asm.s
index 5ec82596b104870dac94a1af9e2ae8906189bc2e..d3ea83c249c9614beef5b5a2afe32cdd42dbc570 100644 (file)
@@ -1,16 +1,19 @@
 /*
 /*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003-2005 Apple Computer, Inc. All rights reserved.
  *
  *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
  * 
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * 
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
@@ -20,7 +23,7 @@
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * 
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * 
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 
 #include <sys/appleapiopts.h>
  */
 
 #include <sys/appleapiopts.h>
 #define        kLoopCnt        5                                       // Iterations of the timing loop
 #define        kDCBA           22                                      // Bit in cr5 used as a flag in timing loop
 
 #define        kLoopCnt        5                                       // Iterations of the timing loop
 #define        kDCBA           22                                      // Bit in cr5 used as a flag in timing loop
 
+
+// commpage_set_timestamp() uses the red zone for temporary storage:
+
+#define        rzSaveF1                        -8              // caller's FPR1
+#define        rzSaveF2                        -16             // caller's FPR2
+#define        rzSaveF3                        -24             // caller's FPR3
+#define        rzSaveF4                        -32             // caller's FPR4
+#define        rzSaveF5                        -40             // caller's FPR5
+#define        rzNewTimeBase           -48             // used to load 64-bit TBR into a FPR
+
+
+// commpage_set_timestamp() uses the following data.  kkTicksPerSec remembers
+// the number used to compute _COMM_PAGE_SEC_PER_TICK.  Since this constant
+// rarely changes, we use it to avoid needless recomputation.  It is a double
+// value, pre-initialize with an exponent of 2**52.
+
+#define        kkBinary0               0                                       // offset in data to long long 0 (a constant)
+#define        kkDouble1               8                                       // offset in data to double 1.0 (a constant)
+#define        kkTicksPerSec   16                                      // offset in data to double(ticks_per_sec)
+
         .data
         .align 3                                                       // three doubleword fields
 Ldata:
         .data
         .align 3                                                       // three doubleword fields
 Ldata:
@@ -49,6 +72,115 @@ Ldata:
         .text
         .align 2
         .globl EXT(commpage_time_dcba)
         .text
         .align 2
         .globl EXT(commpage_time_dcba)
+        .globl EXT(commpage_set_timestamp)
+
+
+/*     ***********************************************
+ *     * C O M M P A G E _ S E T _ T I M E S T A M P *
+ *     ***********************************************
+ *
+ *     Update the gettimeofday() shared data on the commpages, as follows:
+ *             _COMM_PAGE_TIMESTAMP = the clock offset at timebase (seconds)
+ *             _COMM_PAGE_TIMEBASE = the timebase at which the timestamp was valid
+ *             _COMM_PAGE_SEC_PER_TICK = multiply timebase ticks by this to get seconds (double)
+ *     The convention is that if the timebase is 0, the data is invalid.  Because other
+ *     CPUs are reading the three values asynchronously and must get a consistent set, 
+ *     it is critical that we update them with the following protocol:
+ *             1. set timebase to 0 (atomically), to invalidate all three values
+ *             2. eieio (to create a barrier in stores to cacheable memory)
+ *             3. change timestamp and "secs per tick"
+ *             4. eieio
+ *             5. set timebase nonzero (atomically)
+ *     This works because readers read the timebase, then the timestamp and divisor, sync
+ *     if MP, then read the timebase a second time and check to be sure it is equal to the first.
+ *
+ *     We could save a few cycles on 64-bit machines by special casing them, but it probably
+ *     isn't necessary because this routine shouldn't be called very often.
+ *
+ *     When called:
+ *             r3 = upper half of timebase (timebase is disabled if 0)
+ *             r4 = lower half of timebase
+ *             r5 = upper half of timestamp
+ *             r6 = lower half of timestamp
+ *             r7 = divisor (ie, timebase ticks per sec)
+ *     We set up:
+ *             r8 = ptr to our static data (kkBinary0, kkDouble1, kkTicksPerSec)
+ *             r9 = ptr to 32-bit commpage in kernel map
+ *     r10 = ptr to 64-bit commpage in kernel map
+ *
+ *     --> Interrupts must be disabled and rtclock locked when called.  <--
+ */
+        .align 5
+LEXT(commpage_set_timestamp)                           // void commpage_set_timestamp(tbr,secs,divisor)
+        mfmsr  r11                                                     // get MSR
+        ori            r2,r11,MASK(MSR_FP)                     // turn FP on
+        mtmsr  r2
+        isync                                                          // wait until MSR changes take effect
+        
+        or.            r0,r3,r4                                        // is timebase 0? (thus disabled)
+        lis            r8,hi16(Ldata)                          // point to our data
+        lis            r9,ha16(EXT(commPagePtr32))     // get ptrs to address of commpages in kernel map
+               lis             r10,ha16(EXT(commPagePtr64))
+        stfd   f1,rzSaveF1(r1)                         // save a FPR in the red zone
+        ori            r8,r8,lo16(Ldata)
+        lwz            r9,lo16(EXT(commPagePtr32))(r9) // r9 <- 32-bit commpage ptr
+               lwz             r10,lo16(EXT(commPagePtr64))(r10) // r10 <- 64-bit commpage ptr
+        lfd            f1,kkBinary0(r8)                        // get fixed 0s
+        li             r0,_COMM_PAGE_BASE_ADDRESS      // get va in user space of commpage
+        cmpwi  cr1,r9,0                                        // is 32-bit commpage allocated yet?
+               cmpwi   cr6,r10,0                                       // is 64-bit commpage allocated yet?
+        sub            r9,r9,r0                                        // r9 <- 32-bit commpage address, biased by user va
+               sub             r10,r10,r0                                      // r10<- 64-bit commpage address
+        beq--  cr1,3f                                          // skip if 32-bit commpage not allocated (64-bit won't be either)
+               bne++   cr6,1f                                          // skip if 64-bit commpage is allocated
+               mr              r10,r9                                          // if no 64-bit commpage, point to 32-bit version with r10 too
+1:
+        stfd   f1,_COMM_PAGE_TIMEBASE(r9)      // turn off the 32-bit-commpage timestamp (atomically)
+               stfd    f1,_COMM_PAGE_TIMEBASE(r10) // and the 64-bit one too
+        eieio                                                          // make sure all CPUs see it is off
+        beq            3f                                                      // all we had to do is turn off timestamp
+        
+        lwz            r0,kkTicksPerSec+4(r8)          // get last ticks_per_sec (or 0 if first)
+        stw            r3,rzNewTimeBase(r1)            // store new timebase so we can lfd
+        stw            r4,rzNewTimeBase+4(r1)
+        cmpw   r0,r7                                           // do we need to recompute _COMM_PAGE_SEC_PER_TICK?
+        stw            r5,_COMM_PAGE_TIMESTAMP(r9)     // store the new timestamp in the 32-bit page
+        stw            r6,_COMM_PAGE_TIMESTAMP+4(r9)
+        stw            r5,_COMM_PAGE_TIMESTAMP(r10)// and the 64-bit commpage
+        stw            r6,_COMM_PAGE_TIMESTAMP+4(r10)
+        lfd            f1,rzNewTimeBase(r1)            // get timebase in a FPR so we can store atomically
+        beq++  2f                                                      // same ticks_per_sec, no need to recompute
+        
+        stw            r7,kkTicksPerSec+4(r8)          // must recompute SEC_PER_TICK
+        stfd   f2,rzSaveF2(r1)                         // we'll need a few more temp FPRs
+        stfd   f3,rzSaveF3(r1)
+        stfd   f4,rzSaveF4(r1)
+        stfd   f5,rzSaveF5(r1)
+        lfd            f2,_COMM_PAGE_2_TO_52(r9)       // f2 <- double(2**52)
+        lfd            f3,kkTicksPerSec(r8)            // float new ticks_per_sec + 2**52
+        lfd            f4,kkDouble1(r8)                        // f4 <- double(1.0)
+        mffs   f5                                                      // save caller's FPSCR
+        mtfsfi 7,1                                                     // clear Inexeact Exception bit, set round-to-zero
+        fsub   f3,f3,f2                                        // get ticks_per_sec
+        fdiv   f3,f4,f3                                        // divide 1 by ticks_per_sec to get SEC_PER_TICK
+        stfd   f3,_COMM_PAGE_SEC_PER_TICK(r9)
+        stfd   f3,_COMM_PAGE_SEC_PER_TICK(r10)
+        mtfsf  0xFF,f5                                         // restore FPSCR
+        lfd            f2,rzSaveF2(r1)                         // restore FPRs
+        lfd            f3,rzSaveF3(r1)
+        lfd            f4,rzSaveF4(r1)
+        lfd            f5,rzSaveF5(r1)
+2:                                                                                     // f1 == new timestamp
+        eieio                                                          // wait until the stores take
+        stfd   f1,_COMM_PAGE_TIMEBASE(r9)      // then turn the timestamp back on (atomically)
+        stfd   f1,_COMM_PAGE_TIMEBASE(r10)     // both
+3:                                                                                     // here once all fields updated
+        lfd            f1,rzSaveF1(r1)                         // restore last FPR
+        mtmsr  r11                                                     // turn FP back off
+        isync
+        blr
+
 
 /*     ***************************************
  *     * C O M M P A G E _ T I M E _ D C B A *
 
 /*     ***************************************
  *     * C O M M P A G E _ T I M E _ D C B A *