• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Declares a Simulator for PPC instructions if we are not generating a native
6 // PPC binary. This Simulator allows us to run and debug PPC code generation on
7 // regular desktop machines.
8 // V8 calls into generated code via the GeneratedCode wrapper,
9 // which will start execution in the Simulator or forwards to the real entry
10 // on a PPC HW platform.
11 
12 #ifndef V8_EXECUTION_PPC_SIMULATOR_PPC_H_
13 #define V8_EXECUTION_PPC_SIMULATOR_PPC_H_
14 
15 // globals.h defines USE_SIMULATOR.
16 #include "src/common/globals.h"
17 
18 #if defined(USE_SIMULATOR)
19 // Running with a simulator.
20 
21 #include "src/base/lazy-instance.h"
22 #include "src/base/platform/mutex.h"
23 #include "src/utils/allocation.h"
24 
25 #include "src/base/hashmap.h"
26 #include "src/codegen/assembler.h"
27 #include "src/codegen/ppc/constants-ppc.h"
28 #include "src/execution/simulator-base.h"
29 
30 namespace v8 {
31 namespace internal {
32 
33 class CachePage {
34  public:
35   static const int LINE_VALID = 0;
36   static const int LINE_INVALID = 1;
37 
38   static const int kPageShift = 12;
39   static const int kPageSize = 1 << kPageShift;
40   static const int kPageMask = kPageSize - 1;
41   static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
42   static const int kLineLength = 1 << kLineShift;
43   static const int kLineMask = kLineLength - 1;
44 
CachePage()45   CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
46 
ValidityByte(int offset)47   char* ValidityByte(int offset) {
48     return &validity_map_[offset >> kLineShift];
49   }
50 
CachedData(int offset)51   char* CachedData(int offset) { return &data_[offset]; }
52 
53  private:
54   char data_[kPageSize];  // The cached data.
55   static const int kValidityMapSize = kPageSize >> kLineShift;
56   char validity_map_[kValidityMapSize];  // One byte per line.
57 };
58 
59 class Simulator : public SimulatorBase {
60  public:
61   friend class PPCDebugger;
62   enum Register {
63     no_reg = -1,
64     r0 = 0,
65     sp,
66     r2,
67     r3,
68     r4,
69     r5,
70     r6,
71     r7,
72     r8,
73     r9,
74     r10,
75     r11,
76     r12,
77     r13,
78     r14,
79     r15,
80     r16,
81     r17,
82     r18,
83     r19,
84     r20,
85     r21,
86     r22,
87     r23,
88     r24,
89     r25,
90     r26,
91     r27,
92     r28,
93     r29,
94     r30,
95     fp,
96     kNumGPRs = 32,
97     d0 = 0,
98     d1,
99     d2,
100     d3,
101     d4,
102     d5,
103     d6,
104     d7,
105     d8,
106     d9,
107     d10,
108     d11,
109     d12,
110     d13,
111     d14,
112     d15,
113     d16,
114     d17,
115     d18,
116     d19,
117     d20,
118     d21,
119     d22,
120     d23,
121     d24,
122     d25,
123     d26,
124     d27,
125     d28,
126     d29,
127     d30,
128     d31,
129     kNumFPRs = 32
130   };
131 
132   explicit Simulator(Isolate* isolate);
133   ~Simulator();
134 
135   // The currently executing Simulator instance. Potentially there can be one
136   // for each native thread.
137   static Simulator* current(v8::internal::Isolate* isolate);
138 
139   // Accessors for register state.
140   void set_register(int reg, intptr_t value);
141   intptr_t get_register(int reg) const;
142   double get_double_from_register_pair(int reg);
set_d_register_from_double(int dreg,const double dbl)143   void set_d_register_from_double(int dreg, const double dbl) {
144     DCHECK(dreg >= 0 && dreg < kNumFPRs);
145     *bit_cast<double*>(&fp_registers_[dreg]) = dbl;
146   }
get_double_from_d_register(int dreg)147   double get_double_from_d_register(int dreg) {
148     DCHECK(dreg >= 0 && dreg < kNumFPRs);
149     return *bit_cast<double*>(&fp_registers_[dreg]);
150   }
set_d_register(int dreg,int64_t value)151   void set_d_register(int dreg, int64_t value) {
152     DCHECK(dreg >= 0 && dreg < kNumFPRs);
153     fp_registers_[dreg] = value;
154   }
get_d_register(int dreg)155   int64_t get_d_register(int dreg) {
156     DCHECK(dreg >= 0 && dreg < kNumFPRs);
157     return fp_registers_[dreg];
158   }
159 
160   // Special case of set_register and get_register to access the raw PC value.
161   void set_pc(intptr_t value);
162   intptr_t get_pc() const;
163 
get_sp()164   Address get_sp() const { return static_cast<Address>(get_register(sp)); }
165 
166   // Accessor to the internal Link Register
167   intptr_t get_lr() const;
168 
169   // Accessor to the internal simulator stack area.
170   uintptr_t StackLimit(uintptr_t c_limit) const;
171 
172   // Executes PPC instructions until the PC reaches end_sim_pc.
173   void Execute();
174 
175   template <typename Return, typename... Args>
Call(Address entry,Args...args)176   Return Call(Address entry, Args... args) {
177     return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...);
178   }
179 
180   // Alternative: call a 2-argument double function.
181   void CallFP(Address entry, double d0, double d1);
182   int32_t CallFPReturnsInt(Address entry, double d0, double d1);
183   double CallFPReturnsDouble(Address entry, double d0, double d1);
184 
185   // Push an address onto the JS stack.
186   uintptr_t PushAddress(uintptr_t address);
187 
188   // Pop an address from the JS stack.
189   uintptr_t PopAddress();
190 
191   // Debugger input.
192   void set_last_debugger_input(char* input);
last_debugger_input()193   char* last_debugger_input() { return last_debugger_input_; }
194 
195   // Redirection support.
196   static void SetRedirectInstruction(Instruction* instruction);
197 
198   // ICache checking.
199   static bool ICacheMatch(void* one, void* two);
200   static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start,
201                           size_t size);
202 
203   // Returns true if pc register contains one of the 'special_values' defined
204   // below (bad_lr, end_sim_pc).
205   bool has_bad_pc() const;
206 
207  private:
208   enum special_values {
209     // Known bad pc value to ensure that the simulator does not execute
210     // without being properly setup.
211     bad_lr = -1,
212     // A pc value used to signal the simulator to stop execution.  Generally
213     // the lr is set to this value on transition from native C code to
214     // simulated execution, so that the simulator can "return" to the native
215     // C code.
216     end_sim_pc = -2
217   };
218 
219   intptr_t CallImpl(Address entry, int argument_count,
220                     const intptr_t* arguments);
221 
222   enum BCType { BC_OFFSET, BC_LINK_REG, BC_CTR_REG };
223 
224   // Unsupported instructions use Format to print an error and stop execution.
225   void Format(Instruction* instr, const char* format);
226 
227   // Helper functions to set the conditional flags in the architecture state.
228   bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0);
229   bool BorrowFrom(int32_t left, int32_t right);
230   bool OverflowFrom(int32_t alu_out, int32_t left, int32_t right,
231                     bool addition);
232 
233   // Helper functions to decode common "addressing" modes
234   int32_t GetShiftRm(Instruction* instr, bool* carry_out);
235   int32_t GetImm(Instruction* instr, bool* carry_out);
236   void ProcessPUW(Instruction* instr, int num_regs, int operand_size,
237                   intptr_t* start_address, intptr_t* end_address);
238   void HandleRList(Instruction* instr, bool load);
239   void HandleVList(Instruction* inst);
240   void SoftwareInterrupt(Instruction* instr);
241   void DebugAtNextPC();
242 
243   // Stop helper functions.
244   inline bool isStopInstruction(Instruction* instr);
245   inline bool isWatchedStop(uint32_t bkpt_code);
246   inline bool isEnabledStop(uint32_t bkpt_code);
247   inline void EnableStop(uint32_t bkpt_code);
248   inline void DisableStop(uint32_t bkpt_code);
249   inline void IncreaseStopCounter(uint32_t bkpt_code);
250   void PrintStopInfo(uint32_t code);
251 
252   // Read and write memory.
253   template <typename T>
Read(uintptr_t address,T * value)254   inline void Read(uintptr_t address, T* value) {
255     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
256     memcpy(value, reinterpret_cast<const char*>(address), sizeof(T));
257   }
258 
259   template <typename T>
ReadEx(uintptr_t address,T * value)260   inline void ReadEx(uintptr_t address, T* value) {
261     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
262     GlobalMonitor::Get()->NotifyLoadExcl(
263         address, static_cast<TransactionSize>(sizeof(T)),
264         isolate_->thread_id());
265     memcpy(value, reinterpret_cast<const char*>(address), sizeof(T));
266   }
267 
268   template <typename T>
Write(uintptr_t address,T value)269   inline void Write(uintptr_t address, T value) {
270     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
271     GlobalMonitor::Get()->NotifyStore(address,
272                                       static_cast<TransactionSize>(sizeof(T)),
273                                       isolate_->thread_id());
274     memcpy(reinterpret_cast<char*>(address), &value, sizeof(T));
275   }
276 
277   template <typename T>
WriteEx(uintptr_t address,T value)278   inline int32_t WriteEx(uintptr_t address, T value) {
279     base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
280     if (GlobalMonitor::Get()->NotifyStoreExcl(
281             address, static_cast<TransactionSize>(sizeof(T)),
282             isolate_->thread_id())) {
283       memcpy(reinterpret_cast<char*>(address), &value, sizeof(T));
284       return 0;
285     } else {
286       return 1;
287     }
288   }
289 
290 #define RW_VAR_LIST(V) \
291   V(DWU, uint64_t)     \
292   V(DW, int64_t)       \
293   V(WU, uint32_t)      \
294   V(W, int32_t) V(HU, uint16_t) V(H, int16_t) V(BU, uint8_t) V(B, int8_t)
295 
296 #define GENERATE_RW_FUNC(size, type)                   \
297   inline type Read##size(uintptr_t addr);              \
298   inline type ReadEx##size(uintptr_t addr);            \
299   inline void Write##size(uintptr_t addr, type value); \
300   inline int32_t WriteEx##size(uintptr_t addr, type value);
301 
302   RW_VAR_LIST(GENERATE_RW_FUNC)
303 #undef GENERATE_RW_FUNC
304 
305   void Trace(Instruction* instr);
306   void SetCR0(intptr_t result, bool setSO = false);
307   void ExecuteBranchConditional(Instruction* instr, BCType type);
308   void ExecuteGeneric(Instruction* instr);
309 
SetFPSCR(int bit)310   void SetFPSCR(int bit) { fp_condition_reg_ |= (1 << (31 - bit)); }
ClearFPSCR(int bit)311   void ClearFPSCR(int bit) { fp_condition_reg_ &= ~(1 << (31 - bit)); }
312 
313   // Executes one instruction.
314   void ExecuteInstruction(Instruction* instr);
315 
316   // ICache.
317   static void CheckICache(base::CustomMatcherHashMap* i_cache,
318                           Instruction* instr);
319   static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start,
320                            int size);
321   static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache,
322                                  void* page);
323 
324   // Handle arguments and return value for runtime FP functions.
325   void GetFpArgs(double* x, double* y, intptr_t* z);
326   void SetFpResult(const double& result);
327   void TrashCallerSaveRegisters();
328 
329   void CallInternal(Address entry);
330 
331   // Architecture state.
332   // Saturating instructions require a Q flag to indicate saturation.
333   // There is currently no way to read the CPSR directly, and thus read the Q
334   // flag, so this is left unimplemented.
335   intptr_t registers_[kNumGPRs];
336   int32_t condition_reg_;
337   int32_t fp_condition_reg_;
338   intptr_t special_reg_lr_;
339   intptr_t special_reg_pc_;
340   intptr_t special_reg_ctr_;
341   int32_t special_reg_xer_;
342 
343   int64_t fp_registers_[kNumFPRs];
344 
345   // Simulator support.
346   char* stack_;
347   static const size_t stack_protection_size_ = 256 * kSystemPointerSize;
348   bool pc_modified_;
349   int icount_;
350 
351   // Debugger input.
352   char* last_debugger_input_;
353 
354   // Registered breakpoints.
355   Instruction* break_pc_;
356   Instr break_instr_;
357 
358   v8::internal::Isolate* isolate_;
359 
360   // A stop is watched if its code is less than kNumOfWatchedStops.
361   // Only watched stops support enabling/disabling and the counter feature.
362   static const uint32_t kNumOfWatchedStops = 256;
363 
364   // Breakpoint is disabled if bit 31 is set.
365   static const uint32_t kStopDisabledBit = 1 << 31;
366 
367   // A stop is enabled, meaning the simulator will stop when meeting the
368   // instruction, if bit 31 of watched_stops_[code].count is unset.
369   // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
370   // the breakpoint was hit or gone through.
371   struct StopCountAndDesc {
372     uint32_t count;
373     char* desc;
374   };
375   StopCountAndDesc watched_stops_[kNumOfWatchedStops];
376 
377   // Synchronization primitives. See ARM DDI 0406C.b, A2.9.
378   enum class MonitorAccess {
379     Open,
380     Exclusive,
381   };
382 
383   enum class TransactionSize {
384     None = 0,
385     Byte = 1,
386     HalfWord = 2,
387     Word = 4,
388     DWord = 8,
389   };
390 
391   class GlobalMonitor {
392    public:
393     // Exposed so it can be accessed by Simulator::{Read,Write}Ex*.
394     base::Mutex mutex;
395 
396     void NotifyLoadExcl(uintptr_t addr, TransactionSize size,
397                         ThreadId thread_id);
398     void NotifyStore(uintptr_t addr, TransactionSize size, ThreadId thread_id);
399     bool NotifyStoreExcl(uintptr_t addr, TransactionSize size,
400                          ThreadId thread_id);
401 
402     static GlobalMonitor* Get();
403 
404    private:
405     // Private constructor. Call {GlobalMonitor::Get()} to get the singleton.
406     GlobalMonitor() = default;
407     friend class base::LeakyObject<GlobalMonitor>;
408 
409     void Clear();
410 
411     MonitorAccess access_state_ = MonitorAccess::Open;
412     uintptr_t tagged_addr_ = 0;
413     TransactionSize size_ = TransactionSize::None;
414     ThreadId thread_id_ = ThreadId::Invalid();
415   };
416 };
417 
418 }  // namespace internal
419 }  // namespace v8
420 
421 #endif  // defined(USE_SIMULATOR)
422 #endif  // V8_EXECUTION_PPC_SIMULATOR_PPC_H_
423