Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
4 : // Use of this source code is governed by a BSD-style license that can be
5 : // found in the LICENSE file.
6 :
7 : // This module gets enough CPU information to optimize the
8 : // atomicops module on x86.
9 :
10 : #include <string.h>
11 :
12 : #include "base/atomicops.h"
13 : #include "base/basictypes.h"
14 :
15 : // This file only makes sense with atomicops_internals_x86_gcc.h -- it
16 : // depends on structs that are defined in that file. If atomicops.h
17 : // doesn't sub-include that file, then we aren't needed, and shouldn't
18 : // try to do anything.
19 : #ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
20 :
21 : // Inline cpuid instruction. In PIC compilations, %ebx contains the address
22 : // of the global offset table. To avoid breaking such executables, this code
23 : // must preserve that register's value across cpuid instructions.
24 : #if defined(__i386__)
25 : #define cpuid(a, b, c, d, inp) \
26 : asm ("mov %%ebx, %%edi\n" \
27 : "cpuid\n" \
28 : "xchg %%edi, %%ebx\n" \
29 : : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
30 : #elif defined (__x86_64__)
31 : #define cpuid(a, b, c, d, inp) \
32 : asm ("mov %%rbx, %%rdi\n" \
33 : "cpuid\n" \
34 : "xchg %%rdi, %%rbx\n" \
35 : : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
36 : #endif
37 :
38 : #if defined(cpuid) // initialize the struct only on x86
39 :
40 : // Set the flags so that code will run correctly and conservatively, so even
41 : // if we haven't been initialized yet, we're probably single threaded, and our
42 : // default values should hopefully be pretty safe.
43 : struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = {
44 : false, // bug can't exist before process spawns multiple threads
45 : false, // no SSE2
46 : };
47 :
48 : // Initialize the AtomicOps_Internalx86CPUFeatures struct.
49 3 : static void AtomicOps_Internalx86CPUFeaturesInit() {
50 : uint32_t eax;
51 : uint32_t ebx;
52 : uint32_t ecx;
53 : uint32_t edx;
54 :
55 : // Get vendor string (issue CPUID with eax = 0)
56 3 : cpuid(eax, ebx, ecx, edx, 0);
57 : char vendor[13];
58 3 : memcpy(vendor, &ebx, 4);
59 3 : memcpy(vendor + 4, &edx, 4);
60 3 : memcpy(vendor + 8, &ecx, 4);
61 3 : vendor[12] = 0;
62 :
63 : // get feature flags in ecx/edx, and family/model in eax
64 3 : cpuid(eax, ebx, ecx, edx, 1);
65 :
66 3 : int family = (eax >> 8) & 0xf; // family and model fields
67 3 : int model = (eax >> 4) & 0xf;
68 3 : if (family == 0xf) { // use extended family and model fields
69 0 : family += (eax >> 20) & 0xff;
70 0 : model += ((eax >> 16) & 0xf) << 4;
71 : }
72 :
73 : // Opteron Rev E has a bug in which on very rare occasions a locked
74 : // instruction doesn't act as a read-acquire barrier if followed by a
75 : // non-locked read-modify-write instruction. Rev F has this bug in
76 : // pre-release versions, but not in versions released to customers,
77 : // so we test only for Rev E, which is family 15, model 32..63 inclusive.
78 3 : if (strcmp(vendor, "AuthenticAMD") == 0 && // AMD
79 0 : family == 15 &&
80 0 : 32 <= model && model <= 63) {
81 0 : AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true;
82 : } else {
83 3 : AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false;
84 : }
85 :
86 : // edx bit 26 is SSE2 which we use to tell use whether we can use mfence
87 3 : AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1);
88 3 : }
89 :
90 : namespace {
91 :
92 : class AtomicOpsx86Initializer {
93 : public:
94 3 : AtomicOpsx86Initializer() {
95 3 : AtomicOps_Internalx86CPUFeaturesInit();
96 3 : }
97 : };
98 :
99 : // A global to get use initialized on startup via static initialization :/
100 3 : AtomicOpsx86Initializer g_initer;
101 :
102 9 : } // namespace
103 :
104 : #endif // if x86
105 :
106 : #endif // ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
|