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