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