1
2/*
3 * Copyright (c) 2015, ETH Zurich.
4 * All rights reserved.
5 *
6 * This file is distributed under the terms in the attached LICENSE file.
7 * If you do not find this file, copies can be found by writing to:
8 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
9 */
10
11#ifndef ARCH_K1OM_BARRELFISH_KPI_ASM_INLINES_H
12#define ARCH_K1OM_BARRELFISH_KPI_ASM_INLINES_H 1
13
14#include <machine/param.h>
15
16#ifndef __ASSEMBLER__
17
18#include <target/x86_64/barrelfish_kpi/registers_target.h>
19
20#define CLOCK_PER_MS 1046008
21
22static inline void
23delay_ms(uint32_t ms)
24{
25    if (ms == 0) {
26        return;
27    }
28    uint64_t num_cpu_clks = ms * CLOCK_PER_MS;
29
30    if (num_cpu_clks <= 1023) {
31        /* since delay can only go upto 1023 clocks */
32        __asm __volatile("delay %0"::"r"(num_cpu_clks));
33    } else {
34        /* break it up into 1000 clock chunks */
35        for (uint32_t tick = 1000; num_cpu_clks >= 1000; num_cpu_clks -= 1000) {
36            __asm __volatile("delay %0"::"r"(tick));
37        }
38
39        /* the remaining */
40        __asm __volatile("delay %0"::"r"(num_cpu_clks));
41    }
42    return;
43}
44
45
46
47/*
48 * some functions require to have the register ECX set to a specific value
49 * and will produce wrong results if the value in register ECX is out of range.
50 */
51static inline void
52cpuid_ext(uint32_t function,
53          uint32_t ecx_in,
54          uint32_t *eax,
55          uint32_t *ebx,
56          uint32_t *ecx,
57          uint32_t *edx)
58{
59    // make it possible to omit certain return registers
60    uint32_t a, b, c, d;
61    if (eax == NULL) {
62        eax = &a;
63    }
64    if (ebx == NULL) {
65        ebx = &b;
66    }
67    if (ecx == NULL) {
68        ecx = &c;
69    }
70    if (edx == NULL) {
71        edx = &d;
72    }
73    __asm volatile("cpuid"
74            : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
75            : "a" (function), "c" (ecx_in)
76    );
77}
78
79static inline void
80cpuid(uint32_t function,
81      uint32_t *eax,
82      uint32_t *ebx,
83      uint32_t *ecx,
84      uint32_t *edx)
85{
86    cpuid_ext(function, 0, eax, ebx, ecx, edx);
87}
88
89/** \brief Atomic compare-and-swap on 128 bits
90 *
91 * If *dst == old then *dst = new, returns 0 on failure
92 *
93 * Note, dest should point to a 128bit structure that is to be overwritten
94 */
95static inline int cmpxchg128(volatile uint64_t dest[2], uint64_t old_top, uint64_t old_bot, uint64_t new_top, uint64_t new_bot)
96{
97    uint8_t ret;
98
99    __asm volatile (
100        "lock cmpxchg16b %1\n\t"
101        "setz %0\n\t"
102        : "=a"(ret), "=m"(*dest)//, "=d"(old_top), "=a"(old_bot)
103        : "a"(old_top), "d"(old_bot), "b"(new_top), "c"(new_bot), "m"(*dest)
104        : "memory");
105
106    return ret;
107}
108
109static inline void fpu_init(void)
110{
111    __asm volatile ("fninit");
112}
113
114
115#if 0
116
117/** \brief This code reads the cycle counter */
118static inline uint64_t
119rdtsc(void)
120{
121
122    uint32_t eax, edx;
123    __asm volatile ("rdtsc" : "=a" (eax), "=d" (edx));
124    return ((uint64_t) edx << 32) | eax;
125
126    return 0;
127}
128
129/** \brief This code reads the cycle counter -- flushing the
130 instruction pipeline first. Throws away the processor ID information. */
131static inline uint64_t
132rdtscp(void)
133{
134    /*
135     uint32_t eax, edx;
136     __asm volatile ("rdtscp" : "=a" (eax), "=d" (edx) :: "ecx");
137     return ((uint64_t)edx << 32) | eax;
138     */
139    return 0;
140}
141
142static inline uint64_t
143rdpmc(uint32_t counter)
144{
145    /*
146    uint32_t eax, edx;
147
148     __asm volatile("rdpmc"
149     : "=a" (eax), "=d" (edx)
150     : "c" (counter)
151     );
152
153    return ((uint64_t) edx << 32) | eax;
154     */
155    return 0;
156}
157
158static inline void
159mfence(void)
160{
161    // __asm volatile("mfence");
162}
163
164static inline void
165sfence(void)
166{
167    //  __asm volatile("sfence");
168}
169
170static inline void
171lfence(void)
172{
173    // __asm volatile("lfence");
174}
175
176static inline void
177clflush(void *line)
178{
179    //__asm volatile("clflush %0" :: "m" (line));
180}
181
182#ifndef __cplusplus
183/* flush a range of memory from the cache */
184static inline void cache_flush_range(void *base, size_t len)
185{
186    //mfence();
187
188    uint8_t *line = (uint8_t *)((uintptr_t)base & ~(CACHE_LINE_SIZE-1UL));
189    do {
190        clflush(line);
191        line += CACHE_LINE_SIZE;
192    }while (line < (uint8_t *)base + len);
193}
194#endif
195#endif
196#endif // __ASSEMBLER__
197
198#endif // ARCH_K1OM_BARRELFISH_KPI_ASM_INLINES_H
199