The Pedigree Project 0.1
glue-infoblock.c
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20// Contains implementations of syscalls that use global info blocks instead of
21// native syscalls proper.
22
23#include "pedigree/kernel/process/InfoBlock.h"
24
25#include <config.h>
26#include <errno.h>
27#include <stdint.h>
28#include <time.h>
29
30#include <sys/select.h>
31#include <sys/syscall.h>
32
34#if X86_COMMON
35static struct InfoBlock* infoBlock = (struct InfoBlock*)0xFFFFFFFF8FFF0000;
36#elif HOSTED
37static struct InfoBlock* infoBlock = (struct InfoBlock*)0x0000710000000000;
38#else
39#error no infoblock address configured for this platform
40#endif
41
42struct getcpu_cache;
43
44int __vdso_clock_gettime(clockid_t clock_id, struct timespec* tp);
45int __vdso_gettimeofday(struct timeval* tv, void* tz);
46int __vdso_getcpu(unsigned* cpu, unsigned* node, struct getcpu_cache* cache);
47time_t __vdso_time(time_t* tloc);
48
49int __vdso_clock_gettime(clockid_t clock_id, struct timespec* tp) {
50#if X64 && !HOSTED
51 // A shared snapshot can be arbitrarily old without periodic interrupts.
52 long result = SYS_clock_gettime;
53 __asm__ volatile("syscall"
54 : "+a"(result)
55 : "D"(clock_id), "S"(tp)
56 : "rcx", "r11", "memory", "cc");
57 return (int)result;
58#else
59 if (!tp) {
60 return -EFAULT;
61 }
62
63 uint64_t now;
64 if (clock_id == CLOCK_REALTIME) {
65 now = infoBlock->now;
66 } else if (clock_id == CLOCK_MONOTONIC || clock_id == CLOCK_MONOTONIC_RAW) {
67 // InfoBlock publishes getTicks(), which is not frequency-adjusted.
68 now = infoBlock->monotonic;
69 } else {
70 return -EINVAL;
71 }
72
73 const uint64_t seconds = now / 1000000000U;
74 tp->tv_sec = seconds;
75 tp->tv_nsec = now - seconds * 1000000000U;
76
77 return 0;
78#endif
79}
80
81int __vdso_gettimeofday(struct timeval* tv, void* tz) {
82#if X64 && !HOSTED
83 long result = SYS_gettimeofday;
84 __asm__ volatile("syscall" : "+a"(result) : "D"(tv), "S"(tz) : "rcx", "r11", "memory", "cc");
85 return (int)result;
86#else
87 if (tv) {
88 // 'now' is in nanoseconds.
89 uint64_t now = infoBlock->now;
90 const uint64_t seconds = now / 1000000000U;
91 tv->tv_sec = seconds;
92 tv->tv_usec = (now - seconds * 1000000000U) / 1000U;
93 }
94
96
97 return 0;
98#endif
99}
100
101int __vdso_getcpu(unsigned* cpu, unsigned* node, struct getcpu_cache* cache) {
102#if X64
103 if (infoBlock->vdso_features & INFO_BLOCK_VDSO_GETCPU_RDTSCP) {
104 unsigned ignored_low, ignored_high, aux;
105 __asm__ volatile("rdtscp" : "=a"(ignored_low), "=d"(ignored_high), "=c"(aux) : : "memory");
106 if (cpu) {
107 *cpu = aux;
108 }
109 if (node) {
110 *node = 0;
111 }
112 return 0;
113 }
114
115 // The shared info block cannot identify the calling task's current CPU.
116 long result = 309;
117 __asm__ volatile("syscall"
118 : "+a"(result)
119 : "D"(cpu), "S"(node), "d"(cache)
120 : "rcx", "r11", "memory", "cc");
121 return (int)result;
122#else
123 (void)cpu;
124 (void)node;
125 (void)cache;
126 return -ENOSYS;
127#endif
128}
129
130time_t __vdso_time(time_t* tloc) {
131#if X64 && !HOSTED
132 long result = SYS_time;
133 __asm__ volatile("syscall" : "+a"(result) : "D"(tloc) : "rcx", "r11", "memory", "cc");
134 return (time_t)result;
135#else
136 const time_t now = infoBlock->now_s;
137 if (tloc) {
138 *tloc = now;
139 }
140
141 return now;
142#endif
143}
144
145__asm__(".symver __vdso_clock_gettime,__vdso_clock_gettime@LINUX_2.6");
146__asm__(".symver __vdso_gettimeofday,__vdso_gettimeofday@LINUX_2.6");
147__asm__(".symver __vdso_getcpu,__vdso_getcpu@LINUX_2.6");
148__asm__(".symver __vdso_time,__vdso_time@LINUX_2.6");
149
150int clock_gettime(clockid_t, struct timespec*) __attribute__((weak, alias("__vdso_clock_gettime")));
151int gettimeofday(struct timeval* __restrict, void* __restrict)
152 __attribute__((weak, alias("__vdso_gettimeofday")));
153int getcpu(unsigned*, unsigned*, struct getcpu_cache*)
154 __attribute__((weak, alias("__vdso_getcpu")));
155time_t time(time_t*) __attribute__((weak, alias("__vdso_time")));
uint64_t monotonic
Monotonic tick count in nanoseconds.
Definition InfoBlock.h:53
uint64_t now
Current timestamp in nanoseconds since the UNIX epoch.
Definition InfoBlock.h:38
uint32_t vdso_features
CPU-local vDSO capabilities published by the kernel.
Definition InfoBlock.h:56
uint64_t now_s
Current timestamp in seconds since the UNIX epoch.
Definition InfoBlock.h:41