root/arch/powerpc/kernel/vdso64/gettimeofday.S

/* [<][>][^][v][top][bottom][index][help] */
   1 /* SPDX-License-Identifier: GPL-2.0-or-later */
   2 /*
   3  * Userland implementation of gettimeofday() for 64 bits processes in a
   4  * ppc64 kernel for use in the vDSO
   5  *
   6  * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org),
   7  *                    IBM Corp.
   8  */
   9 #include <asm/processor.h>
  10 #include <asm/ppc_asm.h>
  11 #include <asm/vdso.h>
  12 #include <asm/asm-offsets.h>
  13 #include <asm/unistd.h>
  14 
  15         .text
  16 /*
  17  * Exact prototype of gettimeofday
  18  *
  19  * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
  20  *
  21  */
  22 V_FUNCTION_BEGIN(__kernel_gettimeofday)
  23   .cfi_startproc
  24         mflr    r12
  25   .cfi_register lr,r12
  26 
  27         mr      r11,r3                  /* r11 holds tv */
  28         mr      r10,r4                  /* r10 holds tz */
  29         bl      V_LOCAL_FUNC(__get_datapage)    /* get data page */
  30         cmpldi  r11,0                   /* check if tv is NULL */
  31         beq     2f
  32         lis     r7,1000000@ha           /* load up USEC_PER_SEC */
  33         addi    r7,r7,1000000@l
  34         bl      V_LOCAL_FUNC(__do_get_tspec) /* get sec/us from tb & kernel */
  35         std     r4,TVAL64_TV_SEC(r11)   /* store sec in tv */
  36         std     r5,TVAL64_TV_USEC(r11)  /* store usec in tv */
  37 2:      cmpldi  r10,0                   /* check if tz is NULL */
  38         beq     1f
  39         lwz     r4,CFG_TZ_MINUTEWEST(r3)/* fill tz */
  40         lwz     r5,CFG_TZ_DSTTIME(r3)
  41         stw     r4,TZONE_TZ_MINWEST(r10)
  42         stw     r5,TZONE_TZ_DSTTIME(r10)
  43 1:      mtlr    r12
  44         crclr   cr0*4+so
  45         li      r3,0                    /* always success */
  46         blr
  47   .cfi_endproc
  48 V_FUNCTION_END(__kernel_gettimeofday)
  49 
  50 
  51 /*
  52  * Exact prototype of clock_gettime()
  53  *
  54  * int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp);
  55  *
  56  */
  57 V_FUNCTION_BEGIN(__kernel_clock_gettime)
  58   .cfi_startproc
  59         /* Check for supported clock IDs */
  60         cmpwi   cr0,r3,CLOCK_REALTIME
  61         cmpwi   cr1,r3,CLOCK_MONOTONIC
  62         cror    cr0*4+eq,cr0*4+eq,cr1*4+eq
  63 
  64         cmpwi   cr5,r3,CLOCK_REALTIME_COARSE
  65         cmpwi   cr6,r3,CLOCK_MONOTONIC_COARSE
  66         cror    cr5*4+eq,cr5*4+eq,cr6*4+eq
  67 
  68         cror    cr0*4+eq,cr0*4+eq,cr5*4+eq
  69         bne     cr0,99f
  70 
  71         mflr    r12                     /* r12 saves lr */
  72   .cfi_register lr,r12
  73         mr      r11,r4                  /* r11 saves tp */
  74         bl      V_LOCAL_FUNC(__get_datapage)    /* get data page */
  75         lis     r7,NSEC_PER_SEC@h       /* want nanoseconds */
  76         ori     r7,r7,NSEC_PER_SEC@l
  77         beq     cr5,70f
  78 50:     bl      V_LOCAL_FUNC(__do_get_tspec)    /* get time from tb & kernel */
  79         bne     cr1,80f                 /* if not monotonic, all done */
  80 
  81         /*
  82          * CLOCK_MONOTONIC
  83          */
  84 
  85         /* now we must fixup using wall to monotonic. We need to snapshot
  86          * that value and do the counter trick again. Fortunately, we still
  87          * have the counter value in r8 that was returned by __do_get_tspec.
  88          * At this point, r4,r5 contain our sec/nsec values.
  89          */
  90 
  91         ld      r6,WTOM_CLOCK_SEC(r3)
  92         lwa     r9,WTOM_CLOCK_NSEC(r3)
  93 
  94         /* We now have our result in r6,r9. We create a fake dependency
  95          * on that result and re-check the counter
  96          */
  97         or      r0,r6,r9
  98         xor     r0,r0,r0
  99         add     r3,r3,r0
 100         ld      r0,CFG_TB_UPDATE_COUNT(r3)
 101         cmpld   cr0,r0,r8               /* check if updated */
 102         bne-    50b
 103         b       78f
 104 
 105         /*
 106          * For coarse clocks we get data directly from the vdso data page, so
 107          * we don't need to call __do_get_tspec, but we still need to do the
 108          * counter trick.
 109          */
 110 70:     ld      r8,CFG_TB_UPDATE_COUNT(r3)
 111         andi.   r0,r8,1                 /* pending update ? loop */
 112         bne-    70b
 113         add     r3,r3,r0                /* r0 is already 0 */
 114 
 115         /*
 116          * CLOCK_REALTIME_COARSE, below values are needed for MONOTONIC_COARSE
 117          * too
 118          */
 119         ld      r4,STAMP_XTIME+TSPC64_TV_SEC(r3)
 120         ld      r5,STAMP_XTIME+TSPC64_TV_NSEC(r3)
 121         bne     cr6,75f
 122 
 123         /* CLOCK_MONOTONIC_COARSE */
 124         ld      r6,WTOM_CLOCK_SEC(r3)
 125         lwa     r9,WTOM_CLOCK_NSEC(r3)
 126 
 127         /* check if counter has updated */
 128         or      r0,r6,r9
 129 75:     or      r0,r0,r4
 130         or      r0,r0,r5
 131         xor     r0,r0,r0
 132         add     r3,r3,r0
 133         ld      r0,CFG_TB_UPDATE_COUNT(r3)
 134         cmpld   cr0,r0,r8               /* check if updated */
 135         bne-    70b
 136 
 137         /* Counter has not updated, so continue calculating proper values for
 138          * sec and nsec if monotonic coarse, or just return with the proper
 139          * values for realtime.
 140          */
 141         bne     cr6,80f
 142 
 143         /* Add wall->monotonic offset and check for overflow or underflow */
 144 78:     add     r4,r4,r6
 145         add     r5,r5,r9
 146         cmpd    cr0,r5,r7
 147         cmpdi   cr1,r5,0
 148         blt     79f
 149         subf    r5,r7,r5
 150         addi    r4,r4,1
 151 79:     bge     cr1,80f
 152         addi    r4,r4,-1
 153         add     r5,r5,r7
 154 
 155 80:     std     r4,TSPC64_TV_SEC(r11)
 156         std     r5,TSPC64_TV_NSEC(r11)
 157 
 158         mtlr    r12
 159         crclr   cr0*4+so
 160         li      r3,0
 161         blr
 162 
 163         /*
 164          * syscall fallback
 165          */
 166 99:
 167         li      r0,__NR_clock_gettime
 168   .cfi_restore lr
 169         sc
 170         blr
 171   .cfi_endproc
 172 V_FUNCTION_END(__kernel_clock_gettime)
 173 
 174 
 175 /*
 176  * Exact prototype of clock_getres()
 177  *
 178  * int __kernel_clock_getres(clockid_t clock_id, struct timespec *res);
 179  *
 180  */
 181 V_FUNCTION_BEGIN(__kernel_clock_getres)
 182   .cfi_startproc
 183         /* Check for supported clock IDs */
 184         cmpwi   cr0,r3,CLOCK_REALTIME
 185         cmpwi   cr1,r3,CLOCK_MONOTONIC
 186         cror    cr0*4+eq,cr0*4+eq,cr1*4+eq
 187         bne     cr0,99f
 188 
 189         mflr    r12
 190   .cfi_register lr,r12
 191         bl      V_LOCAL_FUNC(__get_datapage)
 192         lwz     r5, CLOCK_HRTIMER_RES(r3)
 193         mtlr    r12
 194         li      r3,0
 195         cmpldi  cr0,r4,0
 196         crclr   cr0*4+so
 197         beqlr
 198         std     r3,TSPC64_TV_SEC(r4)
 199         std     r5,TSPC64_TV_NSEC(r4)
 200         blr
 201 
 202         /*
 203          * syscall fallback
 204          */
 205 99:
 206         li      r0,__NR_clock_getres
 207         sc
 208         blr
 209   .cfi_endproc
 210 V_FUNCTION_END(__kernel_clock_getres)
 211 
 212 /*
 213  * Exact prototype of time()
 214  *
 215  * time_t time(time *t);
 216  *
 217  */
 218 V_FUNCTION_BEGIN(__kernel_time)
 219   .cfi_startproc
 220         mflr    r12
 221   .cfi_register lr,r12
 222 
 223         mr      r11,r3                  /* r11 holds t */
 224         bl      V_LOCAL_FUNC(__get_datapage)
 225 
 226         ld      r4,STAMP_XTIME+TSPC64_TV_SEC(r3)
 227 
 228         cmpldi  r11,0                   /* check if t is NULL */
 229         beq     2f
 230         std     r4,0(r11)               /* store result at *t */
 231 2:      mtlr    r12
 232         crclr   cr0*4+so
 233         mr      r3,r4
 234         blr
 235   .cfi_endproc
 236 V_FUNCTION_END(__kernel_time)
 237 
 238 
 239 /*
 240  * This is the core of clock_gettime() and gettimeofday(),
 241  * it returns the current time in r4 (seconds) and r5.
 242  * On entry, r7 gives the resolution of r5, either USEC_PER_SEC
 243  * or NSEC_PER_SEC, giving r5 in microseconds or nanoseconds.
 244  * It expects the datapage ptr in r3 and doesn't clobber it.
 245  * It clobbers r0, r6 and r9.
 246  * On return, r8 contains the counter value that can be reused.
 247  * This clobbers cr0 but not any other cr field.
 248  */
 249 V_FUNCTION_BEGIN(__do_get_tspec)
 250   .cfi_startproc
 251         /* check for update count & load values */
 252 1:      ld      r8,CFG_TB_UPDATE_COUNT(r3)
 253         andi.   r0,r8,1                 /* pending update ? loop */
 254         bne-    1b
 255         xor     r0,r8,r8                /* create dependency */
 256         add     r3,r3,r0
 257 
 258         /* Get TB & offset it. We use the MFTB macro which will generate
 259          * workaround code for Cell.
 260          */
 261         MFTB(r6)
 262         ld      r9,CFG_TB_ORIG_STAMP(r3)
 263         subf    r6,r9,r6
 264 
 265         /* Scale result */
 266         ld      r5,CFG_TB_TO_XS(r3)
 267         sldi    r6,r6,12                /* compute time since stamp_xtime */
 268         mulhdu  r6,r6,r5                /* in units of 2^-32 seconds */
 269 
 270         /* Add stamp since epoch */
 271         ld      r4,STAMP_XTIME+TSPC64_TV_SEC(r3)
 272         lwz     r5,STAMP_SEC_FRAC(r3)
 273         or      r0,r4,r5
 274         or      r0,r0,r6
 275         xor     r0,r0,r0
 276         add     r3,r3,r0
 277         ld      r0,CFG_TB_UPDATE_COUNT(r3)
 278         cmpld   r0,r8                   /* check if updated */
 279         bne-    1b                      /* reload if so */
 280 
 281         /* convert to seconds & nanoseconds and add to stamp */
 282         add     r6,r6,r5                /* add on fractional seconds of xtime */
 283         mulhwu  r5,r6,r7                /* compute micro or nanoseconds and */
 284         srdi    r6,r6,32                /* seconds since stamp_xtime */
 285         clrldi  r5,r5,32
 286         add     r4,r4,r6
 287         blr
 288   .cfi_endproc
 289 V_FUNCTION_END(__do_get_tspec)

/* [<][>][^][v][top][bottom][index][help] */