1// Copyright 2006 Google Inc. All Rights Reserved.
2// Author: nsanders, menderico
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7
8//      http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#ifndef STRESSAPPTEST_OS_H_  // NOLINT
17#define STRESSAPPTEST_OS_H_
18
19#include <dirent.h>
20#include <string>
21#include <list>
22#include <map>
23#include <vector>
24
25// This file must work with autoconf on its public version,
26// so these includes are correct.
27#include "adler32memcpy.h"  // NOLINT
28#include "sattypes.h"       // NOLINT
29
30const char kSysfsPath[] = "/sys/bus/pci/devices";
31
32struct PCIDevice {
33  int32 domain;
34  uint16 bus;
35  uint8 dev;
36  uint8 func;
37  uint16 vendor_id;
38  uint16 device_id;
39  uint64 base_addr[6];
40  uint64 size[6];
41};
42
43typedef vector<PCIDevice*> PCIDevices;
44
45class ErrorDiag;
46
47// This class implements OS/Platform specific funtions.
48class OsLayer {
49 public:
50  OsLayer();
51  virtual ~OsLayer();
52
53  // Set the minimum amount of hugepages that should be available for testing.
54  // Must be set before Initialize().
55  void SetMinimumHugepagesSize(int64 min_bytes) {
56    min_hugepages_bytes_ = min_bytes;
57  }
58
59  // Initializes data strctures and open files.
60  // Returns false on error.
61  virtual bool Initialize();
62
63  // Virtual to physical. This implementation is optional for
64  // subclasses to implement.
65  // Takes a pointer, and returns the corresponding bus address.
66  virtual uint64 VirtualToPhysical(void *vaddr);
67
68  // Prints failed dimm. This implementation is optional for
69  // subclasses to implement.
70  // Takes a bus address and string, and prints the DIMM name
71  // into the string. Returns error status.
72  virtual int FindDimm(uint64 addr, char *buf, int len);
73  // Print dimm info, plus more available info.
74  virtual int FindDimmExtended(uint64 addr, char *buf, int len) {
75    return FindDimm(addr, buf, len);
76  }
77
78
79  // Classifies addresses according to "regions"
80  // This may mean different things on different platforms.
81  virtual int32 FindRegion(uint64 paddr);
82  // Find cpu cores associated with a region. Either NUMA or arbitrary.
83  virtual cpu_set_t *FindCoreMask(int32 region);
84  // Return cpu cores associated with a region in a hex string.
85  virtual string FindCoreMaskFormat(int32 region);
86
87  // Returns the HD device that contains this file.
88  virtual string FindFileDevice(string filename);
89
90  // Returns a list of paths coresponding to HD devices found on this machine.
91  virtual list<string> FindFileDevices();
92
93  // Polls for errors. This implementation is optional.
94  // This will poll once for errors and return zero iff no errors were found.
95  virtual int ErrorPoll();
96
97  // Delay an appropriate amount of time between polling.
98  virtual void ErrorWait();
99
100  // Report errors. This implementation is mandatory.
101  // This will output a machine readable line regarding the error.
102  virtual bool ErrorReport(const char *part, const char *symptom, int count);
103
104  // Flushes page cache. Used to circumvent the page cache when doing disk
105  // I/O.  This will be a NOP until ActivateFlushPageCache() is called, which
106  // is typically done when opening a file with O_DIRECT fails.
107  // Returns false on error, true on success or NOP.
108  // Subclasses may implement this in machine specific ways..
109  virtual bool FlushPageCache(void);
110  // Enable FlushPageCache() to actually do the flush instead of being a NOP.
111  virtual void ActivateFlushPageCache(void);
112
113  // Flushes cacheline. Used to distinguish read or write errors.
114  // Subclasses may implement this in machine specific ways..
115  // Takes a pointer, and flushed the cacheline containing that pointer.
116  virtual void Flush(void *vaddr);
117
118  // Fast flush, for use in performance critical code.
119  // This is bound at compile time, and will not pick up
120  // any runtime machine configuration info.
121  inline static void FastFlush(void *vaddr) {
122#ifdef STRESSAPPTEST_CPU_PPC
123    asm volatile("dcbf 0,%0; sync" : : "r" (vaddr));
124#elif defined(STRESSAPPTEST_CPU_X86_64) || defined(STRESSAPPTEST_CPU_I686)
125    // Put mfence before and after clflush to make sure:
126    // 1. The write before the clflush is committed to memory bus;
127    // 2. The read after the clflush is hitting the memory bus.
128    //
129    // From Intel manual:
130    // CLFLUSH is only ordered by the MFENCE instruction. It is not guaranteed
131    // to be ordered by any other fencing, serializing or other CLFLUSH
132    // instruction. For example, software can use an MFENCE instruction to
133    // insure that previous stores are included in the write-back.
134    asm volatile("mfence");
135    asm volatile("clflush (%0)" :: "r" (vaddr));
136    asm volatile("mfence");
137#elif defined(STRESSAPPTEST_CPU_ARMV7A)
138  #warning "Unsupported CPU type ARMV7A: Unable to force cache flushes."
139#else
140  #warning "Unsupported CPU type: Unable to force cache flushes."
141#endif
142  }
143
144  // Get time in cpu timer ticks. Useful for matching MCEs with software
145  // actions.
146  inline static uint64 GetTimestamp(void) {
147    uint64 tsc;
148#ifdef STRESSAPPTEST_CPU_PPC
149    uint32 tbl, tbu, temp;
150    __asm __volatile(
151      "1:\n"
152      "mftbu  %2\n"
153      "mftb   %0\n"
154      "mftbu  %1\n"
155      "cmpw   %2,%1\n"
156      "bne    1b\n"
157      : "=r"(tbl), "=r"(tbu), "=r"(temp)
158      :
159      : "cc");
160
161    tsc = (static_cast<uint64>(tbu) << 32) | static_cast<uint64>(tbl);
162#elif defined(STRESSAPPTEST_CPU_X86_64) || defined(STRESSAPPTEST_CPU_I686)
163    datacast_t data;
164    __asm __volatile("rdtsc" : "=a" (data.l32.l), "=d"(data.l32.h));
165    tsc = data.l64;
166#elif defined(STRESSAPPTEST_CPU_ARMV7A)
167  #warning "Unsupported CPU type ARMV7A: your build may not function correctly"
168    tsc = 0;
169#else
170  #warning "Unsupported CPU type: your build may not function correctly"
171    tsc = 0;
172#endif
173    return (tsc);
174  }
175
176  // Find the free memory on the machine.
177  virtual int64 FindFreeMemSize();
178
179  // Allocates test memory of length bytes.
180  // Subclasses must implement this.
181  // Call PepareTestMem to get a pointer.
182  virtual int64 AllocateAllMem();  // Returns length.
183  // Returns success.
184  virtual bool AllocateTestMem(int64 length, uint64 paddr_base);
185  virtual void FreeTestMem();
186
187  // Prepares the memory for use. You must call this
188  // before using test memory, and after you are done.
189  virtual void *PrepareTestMem(uint64 offset, uint64 length);
190  virtual void ReleaseTestMem(void *addr, uint64 offset, uint64 length);
191
192  // Machine type detected. Can we implement all these functions correctly?
193  // Returns true if machine type is detected and implemented.
194  virtual bool IsSupported();
195
196  // Returns 32 for 32-bit, 64 for 64-bit.
197  virtual int AddressMode();
198  // Update OsLayer state regarding cpu support for various features.
199  virtual void GetFeatures();
200
201  // Open, read, write pci cfg through /proc/bus/pci. fd is /proc/pci file.
202  virtual int PciOpen(int bus, int device, int function);
203  virtual void PciWrite(int fd, uint32 offset, uint32 value, int width);
204  virtual uint32 PciRead(int fd, uint32 offset, int width);
205
206  // Read MSRs
207  virtual bool ReadMSR(uint32 core, uint32 address, uint64 *data);
208  virtual bool WriteMSR(uint32 core, uint32 address, uint64 *data);
209
210  // Extract bits [n+len-1, n] from a 32 bit word.
211  // so GetBitField(0x0f00, 8, 4) == 0xf.
212  virtual uint32 GetBitField(uint32 val, uint32 n, uint32 len);
213
214  // Platform and CPU specific CPU-stressing function.
215  // Returns true on success, false otherwise.
216  virtual bool CpuStressWorkload();
217
218  // Causes false errors for unittesting.
219  // Setting to "true" causes errors to be injected.
220  void set_error_injection(bool errors) { error_injection_ = errors; }
221  bool error_injection() const { return error_injection_; }
222
223  // Is SAT using normal malloc'd memory, or exotic mmap'd memory.
224  bool normal_mem() const { return normal_mem_; }
225
226  // Get numa config, if available..
227  int num_nodes() const { return num_nodes_; }
228  int num_cpus() const { return num_cpus_; }
229
230  // Handle to platform-specific error diagnoser.
231  ErrorDiag *error_diagnoser_;
232
233  // Detect all PCI Devices.
234  virtual PCIDevices GetPCIDevices();
235
236  // Disambiguate between different "warm" memcopies.
237  virtual bool AdlerMemcpyWarm(uint64 *dstmem, uint64 *srcmem,
238                               unsigned int size_in_bytes,
239                               AdlerChecksum *checksum);
240
241  // Store a callback to use to print
242  // app-specific info about the last error location.
243  // This call back is called with a physical address, and the app can fill in
244  // the most recent transaction that occurred at that address.
245  typedef bool (*ErrCallback)(uint64 paddr, string *buf);
246  void set_err_log_callback(
247    ErrCallback err_log_callback) {
248    err_log_callback_ = err_log_callback;
249  }
250  ErrCallback get_err_log_callback() { return err_log_callback_; }
251
252 protected:
253  void *testmem_;                // Location of test memory.
254  uint64 testmemsize_;           // Size of test memory.
255  int64 totalmemsize_;           // Size of available memory.
256  int64 min_hugepages_bytes_;    // Minimum hugepages size.
257  bool  error_injection_;        // Do error injection?
258  bool  normal_mem_;             // Memory DMA capable?
259  bool  use_hugepages_;          // Use hugepage shmem?
260  bool  use_posix_shm_;          // Use 4k page shmem?
261  bool  dynamic_mapped_shmem_;   // Conserve virtual address space.
262  int   shmid_;                  // Handle to shmem
263
264  int64 regionsize_;             // Size of memory "regions"
265  int   regioncount_;            // Number of memory "regions"
266  int   num_cpus_;               // Number of cpus in the system.
267  int   num_nodes_;              // Number of nodes in the system.
268  int   num_cpus_per_node_;      // Number of cpus per node in the system.
269  int   address_mode_;           // Are we running 32 or 64 bit?
270  bool  has_sse2_;               // Do we have sse2 instructions?
271  bool  has_clflush_;            // Do we have clflush instructions?
272  bool  use_flush_page_cache_;   // Do we need to flush the page cache?
273
274
275  time_t time_initialized_;      // Start time of test.
276
277  vector<cpu_set_t> cpu_sets_;   // Cache for cpu masks.
278  vector<bool> cpu_sets_valid_;  // If the cpu mask cache is valid.
279
280  // Get file descriptor for dev msr.
281  virtual int OpenMSR(uint32 core, uint32 address);
282  // Auxiliary methods for PCI device configuration
283  int PCIGetValue(string name, string object);
284  int PCIGetResources(string name, PCIDevice *device);
285
286  // Look up how many hugepages there are.
287  virtual int64 FindHugePages();
288
289  // Link to find last transaction at an error location.
290  ErrCallback err_log_callback_;
291
292 private:
293  DISALLOW_COPY_AND_ASSIGN(OsLayer);
294};
295
296// Selects and returns the proper OS and hardware interface.  Does not call
297// OsLayer::Initialize() on the new object.
298OsLayer *OsLayerFactory(const std::map<std::string, std::string> &options);
299
300#endif  // STRESSAPPTEST_OS_H_ NOLINT
301