1a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// Protocol Buffers - Google's data interchange format 2a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// Copyright 2012 Google Inc. All rights reserved. 3afb4b72037e3f13db208590fc782c4bc8e27f862Jeff Davidson// https://developers.google.com/protocol-buffers/ 4a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// 5a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// Redistribution and use in source and binary forms, with or without 6a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// modification, are permitted provided that the following conditions are 7a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// met: 8a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// 9a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// * Redistributions of source code must retain the above copyright 10a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// notice, this list of conditions and the following disclaimer. 11a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// * Redistributions in binary form must reproduce the above 12a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// copyright notice, this list of conditions and the following disclaimer 13a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// in the documentation and/or other materials provided with the 14a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// distribution. 15a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// * Neither the name of Google Inc. nor the names of its 16a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// contributors may be used to endorse or promote products derived from 17a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// this software without specific prior written permission. 18a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// 19a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 31a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// This module gets enough CPU information to optimize the 32a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// atomicops module on x86. 33a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 34a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#include <cstring> 35a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 36a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#include <google/protobuf/stubs/atomicops.h> 37a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 38a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// This file only makes sense with atomicops_internals_x86_gcc.h -- it 39a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// depends on structs that are defined in that file. If atomicops.h 40a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// doesn't sub-include that file, then we aren't needed, and shouldn't 41a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// try to do anything. 42a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#ifdef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_ 43a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 44a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// Inline cpuid instruction. In PIC compilations, %ebx contains the address 45a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// of the global offset table. To avoid breaking such executables, this code 46a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// must preserve that register's value across cpuid instructions. 47a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#if defined(__i386__) 48a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#define cpuid(a, b, c, d, inp) \ 49a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson asm("mov %%ebx, %%edi\n" \ 50a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson "cpuid\n" \ 51a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson "xchg %%edi, %%ebx\n" \ 52a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp)) 53a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#elif defined(__x86_64__) 54a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#define cpuid(a, b, c, d, inp) \ 55a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson asm("mov %%rbx, %%rdi\n" \ 56a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson "cpuid\n" \ 57a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson "xchg %%rdi, %%rbx\n" \ 58a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp)) 59a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#endif 60a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 61a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#if defined(cpuid) // initialize the struct only on x86 62a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 63a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonnamespace google { 64a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonnamespace protobuf { 65a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonnamespace internal { 66a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 67a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// Set the flags so that code will run correctly and conservatively, so even 68a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// if we haven't been initialized yet, we're probably single threaded, and our 69a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// default values should hopefully be pretty safe. 70a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonstruct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = { 71a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson false, // bug can't exist before process spawns multiple threads 72a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson false, // no SSE2 73a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson}; 74a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 75a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonnamespace { 76a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 77a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// Initialize the AtomicOps_Internalx86CPUFeatures struct. 78a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonvoid AtomicOps_Internalx86CPUFeaturesInit() { 79a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson uint32_t eax; 80a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson uint32_t ebx; 81a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson uint32_t ecx; 82a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson uint32_t edx; 83a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 84a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Get vendor string (issue CPUID with eax = 0) 85a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson cpuid(eax, ebx, ecx, edx, 0); 86a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson char vendor[13]; 87a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson memcpy(vendor, &ebx, 4); 88a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson memcpy(vendor + 4, &edx, 4); 89a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson memcpy(vendor + 8, &ecx, 4); 90a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson vendor[12] = 0; 91a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 92a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // get feature flags in ecx/edx, and family/model in eax 93a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson cpuid(eax, ebx, ecx, edx, 1); 94a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 95a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int family = (eax >> 8) & 0xf; // family and model fields 96a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson int model = (eax >> 4) & 0xf; 97a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (family == 0xf) { // use extended family and model fields 98a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson family += (eax >> 20) & 0xff; 99a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson model += ((eax >> 16) & 0xf) << 4; 100a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 101a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 102a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // Opteron Rev E has a bug in which on very rare occasions a locked 103a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // instruction doesn't act as a read-acquire barrier if followed by a 104a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // non-locked read-modify-write instruction. Rev F has this bug in 105a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // pre-release versions, but not in versions released to customers, 106a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // so we test only for Rev E, which is family 15, model 32..63 inclusive. 107a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson if (strcmp(vendor, "AuthenticAMD") == 0 && // AMD 108a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson family == 15 && 109a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 32 <= model && model <= 63) { 110a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true; 111a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } else { 112a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false; 113a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 114a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 115a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson // edx bit 26 is SSE2 which we use to tell use whether we can use mfence 116a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1); 117a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson} 118a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 119a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonclass AtomicOpsx86Initializer { 120a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson public: 121a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson AtomicOpsx86Initializer() { 122a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson AtomicOps_Internalx86CPUFeaturesInit(); 123a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson } 124a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson}; 125a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 126a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson// A global to get use initialized on startup via static initialization :/ 127a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff DavidsonAtomicOpsx86Initializer g_initer; 128a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 129a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson} // namespace 130a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 131a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson} // namespace internal 132a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson} // namespace protobuf 133a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson} // namespace google 134a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 135a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#endif // __i386__ 136a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson 137a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_ 138