1/* 2 * Copyright 2018, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13/*- 14 * Copyright (c) 2014, 2015 Antti Kantee. All Rights Reserved. 15 * Copyright (c) 2015 Martin Lucina. All Rights Reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 27 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39#include <sel4/kernel.h> 40 41#include <utils/util.h> 42#include <platsupport/arch/tsc.h> 43#include <platsupport/timer.h> 44#include <bmk-core/core.h> 45#include <bmk-core/platform.h> 46#include <bmk-core/printf.h> 47#include <sel4/helpers.h> 48#include <stdio.h> 49/* RTC wall time offset at monotonic time base. */ 50static bmk_time_t rtc_epochoffset; 51#define NSEC_PER_SEC 1000000000ULL 52 53/* 54 * Calculate prod = (a * b) where a is (64.0) fixed point and b is (0.32) fixed 55 * point. The intermediate product is (64.32) fixed point, discarding the 56 * fractional bits leaves us with a (64.0) fixed point result. 57 * 58 * XXX Document what range of (a, b) is safe from overflow in this calculation. 59 */ 60static uint64_t time_base; 61 62static inline uint64_t 63mul64_32(uint64_t a, uint32_t b) 64{ 65 uint64_t prod; 66#if defined(__x86_64__) 67 /* For x86_64 the computation can be done using 64-bit multiply and 68 * shift. */ 69 __asm__ ( 70 "mul %%rdx ; " 71 "shrd $32, %%rdx, %%rax" 72 : "=a" (prod) 73 : "0" (a), "d" ((uint64_t)b) 74 ); 75#elif defined(__i386__) 76 /* For i386 we compute the partial products and add them up, discarding 77 * the lower 32 bits of the product in the process. */ 78 uint32_t h = (uint32_t)(a >> 32); 79 uint32_t l = (uint32_t)a; 80 uint32_t t1, t2; 81 __asm__ ( 82 "mul %5 ; " /* %edx:%eax = (l * b) */ 83 "mov %4,%%eax ; " /* %eax = h */ 84 "mov %%edx,%4 ; " /* t1 = ((l * b) >> 32) */ 85 "mul %5 ; " /* %edx:%eax = (h * b) */ 86 "xor %5,%5 ; " /* t2 = 0 */ 87 "add %4,%%eax ; " /* %eax = (h * b) + t1 (LSW) */ 88 "adc %5,%%edx ; " /* %edx = (h * b) + t1 (MSW) */ 89 : "=A" (prod), "=r" (t1), "=r" (t2) 90 : "a" (l), "1" (h), "2" (b) 91 ); 92#else 93#error mul64_32 not supported for target architecture 94#endif 95 96 return prod; 97} 98uint64_t tsc_mult; 99static uint64_t tsc_base; 100 101int 102arch_init_clocks(env_t env) 103{ 104 105 uint64_t tsc_freq = env->custom_simple.timer_config.tsc_freq; 106 107 tsc_base = rdtsc_pure(); 108 109 tsc_mult = (NSEC_PER_SEC << 32) / tsc_freq; 110 time_base = mul64_32(tsc_base, tsc_mult); 111 112 return 0; 113} 114 115bmk_time_t 116arch_cpu_clock_monotonic(void) 117{ 118 uint64_t tsc_now, tsc_delta; 119 120 /* 121 * Update time_base (monotonic time) and tsc_base (TSC time). 122 */ 123 tsc_now = rdtsc_pure(); 124 125 tsc_delta = tsc_now - tsc_base; 126 time_base += mul64_32(tsc_delta, tsc_mult); 127 tsc_base = tsc_now; 128 return time_base; 129} 130 131bmk_time_t 132arch_cpu_clock_epochoffset(void) 133{ 134 135 return rtc_epochoffset; 136} 137