github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/vdso/vdso.cc (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // This is the VDSO for sandboxed binaries. This file just contains the entry
    16  // points to the VDSO. All of the real work is done in vdso_time.cc
    17  
    18  #define _DEFAULT_SOURCE  // ensure glibc provides struct timezone.
    19  #include <sys/time.h>
    20  #include <time.h>
    21  
    22  #include "vdso/syscalls.h"
    23  #include "vdso/vdso_time.h"
    24  
    25  namespace vdso {
    26  namespace {
    27  
    28  int __common_clock_gettime(clockid_t clock, struct timespec* ts) {
    29    int ret;
    30  
    31    switch (clock) {
    32      case CLOCK_REALTIME:
    33        ret = ClockRealtime(ts);
    34        break;
    35  
    36      case CLOCK_BOOTTIME:
    37        // Fallthrough, CLOCK_BOOTTIME is an alias for CLOCK_MONOTONIC
    38      case CLOCK_MONOTONIC:
    39        ret = ClockMonotonic(ts);
    40        break;
    41  
    42      default:
    43        ret = sys_clock_gettime(clock, ts);
    44        break;
    45    }
    46  
    47    return ret;
    48  }
    49  
    50  int __common_gettimeofday(struct timeval* tv, struct timezone* tz) {
    51    if (tv) {
    52      struct timespec ts;
    53      int ret = ClockRealtime(&ts);
    54      if (ret) {
    55        return ret;
    56      }
    57      tv->tv_sec = ts.tv_sec;
    58      tv->tv_usec = ts.tv_nsec / 1000;
    59    }
    60  
    61    // Nobody should be calling gettimeofday() with a non-NULL
    62    // timezone pointer. If they do then they will get zeros.
    63    if (tz) {
    64      tz->tz_minuteswest = 0;
    65      tz->tz_dsttime = 0;
    66    }
    67  
    68    return 0;
    69  }
    70  }  // namespace
    71  
    72  // __kernel_rt_sigreturn() implements rt_sigreturn()
    73  extern "C" void __kernel_rt_sigreturn(unsigned long unused) {
    74    // No optimizations yet, just make the real system call.
    75    sys_rt_sigreturn();
    76  }
    77  
    78  #if __x86_64__
    79  
    80  // __vdso_clock_gettime() implements clock_gettime()
    81  extern "C" int __vdso_clock_gettime(clockid_t clock, struct timespec* ts) {
    82    return __common_clock_gettime(clock, ts);
    83  }
    84  extern "C" int clock_gettime(clockid_t clock, struct timespec* ts)
    85      __attribute__((weak, alias("__vdso_clock_gettime")));
    86  
    87  // __vdso_gettimeofday() implements gettimeofday()
    88  extern "C" int __vdso_gettimeofday(struct timeval* tv, struct timezone* tz) {
    89    return __common_gettimeofday(tv, tz);
    90  }
    91  extern "C" int gettimeofday(struct timeval* tv, struct timezone* tz)
    92      __attribute__((weak, alias("__vdso_gettimeofday")));
    93  
    94  // __vdso_time() implements time()
    95  extern "C" time_t __vdso_time(time_t* t) {
    96    struct timespec ts;
    97    ClockRealtime(&ts);
    98    if (t) {
    99      *t = ts.tv_sec;
   100    }
   101    return ts.tv_sec;
   102  }
   103  extern "C" time_t time(time_t* t) __attribute__((weak, alias("__vdso_time")));
   104  
   105  // __vdso_getcpu() implements getcpu()
   106  extern "C" long __vdso_getcpu(unsigned* cpu, unsigned* node,
   107                                struct getcpu_cache* cache) {
   108    // No optimizations yet, just make the real system call.
   109    return sys_getcpu(cpu, node, cache);
   110  }
   111  extern "C" long getcpu(unsigned* cpu, unsigned* node,
   112                         struct getcpu_cache* cache)
   113      __attribute__((weak, alias("__vdso_getcpu")));
   114  
   115  #elif __aarch64__
   116  
   117  // __kernel_clock_gettime() implements clock_gettime()
   118  extern "C" int __kernel_clock_gettime(clockid_t clock, struct timespec* ts) {
   119    return __common_clock_gettime(clock, ts);
   120  }
   121  
   122  // __kernel_gettimeofday() implements gettimeofday()
   123  extern "C" int __kernel_gettimeofday(struct timeval* tv, struct timezone* tz) {
   124    return __common_gettimeofday(tv, tz);
   125  }
   126  
   127  // __kernel_clock_getres() implements clock_getres()
   128  extern "C" int __kernel_clock_getres(clockid_t clock, struct timespec* res) {
   129    int ret = 0;
   130  
   131    switch (clock) {
   132      case CLOCK_REALTIME:
   133      case CLOCK_MONOTONIC:
   134      case CLOCK_BOOTTIME: {
   135        if (res == nullptr) {
   136          return 0;
   137        }
   138  
   139        res->tv_sec = 0;
   140        res->tv_nsec = 1;
   141        break;
   142      }
   143  
   144      default:
   145        ret = sys_clock_getres(clock, res);
   146        break;
   147    }
   148  
   149    return ret;
   150  }
   151  
   152  #else
   153  #error "unsupported architecture"
   154  #endif
   155  }  // namespace vdso