1 /*
  2  * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2014, 2018, Red Hat Inc. All rights reserved.
  4  * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
  5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  6  *
  7  * This code is free software; you can redistribute it and/or modify it
  8  * under the terms of the GNU General Public License version 2 only, as
  9  * published by the Free Software Foundation.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  *
 25  */
 26 
 27 #ifndef CPU_RISCV_NATIVEINST_RISCV_HPP
 28 #define CPU_RISCV_NATIVEINST_RISCV_HPP
 29 
 30 #include "asm/assembler.hpp"
 31 #include "runtime/icache.hpp"
 32 #include "runtime/os.hpp"
 33 
 34 // We have interfaces for the following instructions:
 35 // - NativeInstruction
 36 // - - NativeCall
 37 // - - NativeMovConstReg
 38 // - - NativeMovRegMem
 39 // - - NativeJump
 40 // - - NativeGeneralJump
 41 // - - NativeIllegalInstruction
 42 // - - NativeCallTrampolineStub
 43 // - - NativeMembar
 44 
 45 // The base class for different kinds of native instruction abstractions.
 46 // Provides the primitive operations to manipulate code relative to this.
 47 
 48 class NativeCall;
 49 
 50 class NativeInstruction {
 51   friend class Relocation;
 52   friend bool is_NativeCallTrampolineStub_at(address);
 53  public:
 54   enum {
 55     instruction_size = 4,
 56     compressed_instruction_size = 2,
 57   };
 58 
 59   juint encoding() const {
 60     return uint_at(0);
 61   }
 62 
 63   bool is_jal()                             const { return is_jal_at(addr_at(0));         }
 64   bool is_movptr()                          const { return is_movptr_at(addr_at(0));      }
 65   bool is_call()                            const { return is_call_at(addr_at(0));        }
 66   bool is_jump()                            const { return is_jump_at(addr_at(0));        }
 67 
 68   static bool is_jal_at(address instr)        { assert_cond(instr != NULL); return extract_opcode(instr) == 0b1101111; }
 69   static bool is_jalr_at(address instr)       { assert_cond(instr != NULL); return extract_opcode(instr) == 0b1100111 && extract_funct3(instr) == 0b000; }
 70   static bool is_branch_at(address instr)     { assert_cond(instr != NULL); return extract_opcode(instr) == 0b1100011; }
 71   static bool is_ld_at(address instr)         { assert_cond(instr != NULL); return is_load_at(instr) && extract_funct3(instr) == 0b011; }
 72   static bool is_load_at(address instr)       { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0000011; }
 73   static bool is_float_load_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0000111; }
 74   static bool is_auipc_at(address instr)      { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0010111; }
 75   static bool is_jump_at(address instr)       { assert_cond(instr != NULL); return is_branch_at(instr) || is_jal_at(instr) || is_jalr_at(instr); }
 76   static bool is_addi_at(address instr)       { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0010011 && extract_funct3(instr) == 0b000; }
 77   static bool is_addiw_at(address instr)      { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0011011 && extract_funct3(instr) == 0b000; }
 78   static bool is_lui_at(address instr)        { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0110111; }
 79   static bool is_slli_shift_at(address instr, uint32_t shift) {
 80     assert_cond(instr != NULL);
 81     return (extract_opcode(instr) == 0b0010011 && // opcode field
 82             extract_funct3(instr) == 0b001 &&     // funct3 field, select the type of operation
 83             Assembler::extract(((unsigned*)instr)[0], 25, 20) == shift);    // shamt field
 84   }
 85 
 86   static Register extract_rs1(address instr);
 87   static Register extract_rs2(address instr);
 88   static Register extract_rd(address instr);
 89   static uint32_t extract_opcode(address instr);
 90   static uint32_t extract_funct3(address instr);
 91 
 92   // the instruction sequence of movptr is as below:
 93   //     lui
 94   //     addi
 95   //     slli
 96   //     addi
 97   //     slli
 98   //     addi/jalr/load
 99   static bool check_movptr_data_dependency(address instr) {
100     address lui = instr;
101     address addi1 = lui + instruction_size;
102     address slli1 = addi1 + instruction_size;
103     address addi2 = slli1 + instruction_size;
104     address slli2 = addi2 + instruction_size;
105     address last_instr = slli2 + instruction_size;
106     return extract_rs1(addi1) == extract_rd(lui) &&
107            extract_rs1(addi1) == extract_rd(addi1) &&
108            extract_rs1(slli1) == extract_rd(addi1) &&
109            extract_rs1(slli1) == extract_rd(slli1) &&
110            extract_rs1(addi2) == extract_rd(slli1) &&
111            extract_rs1(addi2) == extract_rd(addi2) &&
112            extract_rs1(slli2) == extract_rd(addi2) &&
113            extract_rs1(slli2) == extract_rd(slli2) &&
114            extract_rs1(last_instr) == extract_rd(slli2);
115   }
116 
117   // the instruction sequence of li64 is as below:
118   //     lui
119   //     addi
120   //     slli
121   //     addi
122   //     slli
123   //     addi
124   //     slli
125   //     addi
126   static bool check_li64_data_dependency(address instr) {
127     address lui = instr;
128     address addi1 = lui + instruction_size;
129     address slli1 = addi1 + instruction_size;
130     address addi2 = slli1 + instruction_size;
131     address slli2 = addi2 + instruction_size;
132     address addi3 = slli2 + instruction_size;
133     address slli3 = addi3 + instruction_size;
134     address addi4 = slli3 + instruction_size;
135     return extract_rs1(addi1) == extract_rd(lui) &&
136            extract_rs1(addi1) == extract_rd(addi1) &&
137            extract_rs1(slli1) == extract_rd(addi1) &&
138            extract_rs1(slli1) == extract_rd(slli1) &&
139            extract_rs1(addi2) == extract_rd(slli1) &&
140            extract_rs1(addi2) == extract_rd(addi2) &&
141            extract_rs1(slli2) == extract_rd(addi2) &&
142            extract_rs1(slli2) == extract_rd(slli2) &&
143            extract_rs1(addi3) == extract_rd(slli2) &&
144            extract_rs1(addi3) == extract_rd(addi3) &&
145            extract_rs1(slli3) == extract_rd(addi3) &&
146            extract_rs1(slli3) == extract_rd(slli3) &&
147            extract_rs1(addi4) == extract_rd(slli3) &&
148            extract_rs1(addi4) == extract_rd(addi4);
149   }
150 
151   // the instruction sequence of li32 is as below:
152   //     lui
153   //     addiw
154   static bool check_li32_data_dependency(address instr) {
155     address lui = instr;
156     address addiw = lui + instruction_size;
157 
158     return extract_rs1(addiw) == extract_rd(lui) &&
159            extract_rs1(addiw) == extract_rd(addiw);
160   }
161 
162   // the instruction sequence of pc-relative is as below:
163   //     auipc
164   //     jalr/addi/load/float_load
165   static bool check_pc_relative_data_dependency(address instr) {
166     address auipc = instr;
167     address last_instr = auipc + instruction_size;
168 
169     return extract_rs1(last_instr) == extract_rd(auipc);
170   }
171 
172   // the instruction sequence of load_label is as below:
173   //     auipc
174   //     load
175   static bool check_load_pc_relative_data_dependency(address instr) {
176     address auipc = instr;
177     address load = auipc + instruction_size;
178 
179     return extract_rd(load) == extract_rd(auipc) &&
180            extract_rs1(load) == extract_rd(load);
181   }
182 
183   static bool is_movptr_at(address instr);
184   static bool is_li32_at(address instr);
185   static bool is_li64_at(address instr);
186   static bool is_pc_relative_at(address branch);
187   static bool is_load_pc_relative_at(address branch);
188 
189   static bool is_call_at(address instr) {
190     if (is_jal_at(instr) || is_jalr_at(instr)) {
191       return true;
192     }
193     return false;
194   }
195   static bool is_lwu_to_zr(address instr);
196 
197   inline bool is_nop();
198   inline bool is_jump_or_nop();
199   bool is_safepoint_poll();
200   bool is_sigill_zombie_not_entrant();
201   bool is_stop();
202 
203  protected:
204   address addr_at(int offset) const    { return address(this) + offset; }
205 
206   jint int_at(int offset) const        { return *(jint*) addr_at(offset); }
207   juint uint_at(int offset) const      { return *(juint*) addr_at(offset); }
208 
209   address ptr_at(int offset) const     { return *(address*) addr_at(offset); }
210 
211   oop  oop_at (int offset) const       { return *(oop*) addr_at(offset); }
212 
213 
214   void set_int_at(int offset, jint  i)        { *(jint*)addr_at(offset) = i; }
215   void set_uint_at(int offset, jint  i)       { *(juint*)addr_at(offset) = i; }
216   void set_ptr_at (int offset, address  ptr)  { *(address*) addr_at(offset) = ptr; }
217   void set_oop_at (int offset, oop  o)        { *(oop*) addr_at(offset) = o; }
218 
219  public:
220 
221   inline friend NativeInstruction* nativeInstruction_at(address addr);
222 
223   static bool maybe_cpool_ref(address instr) {
224     return is_auipc_at(instr);
225   }
226 
227   bool is_membar() {
228     return (uint_at(0) & 0x7f) == 0b1111 && extract_funct3(addr_at(0)) == 0;
229   }
230 };
231 
232 inline NativeInstruction* nativeInstruction_at(address addr) {
233   return (NativeInstruction*)addr;
234 }
235 
236 // The natural type of an RISCV instruction is uint32_t
237 inline NativeInstruction* nativeInstruction_at(uint32_t *addr) {
238   return (NativeInstruction*)addr;
239 }
240 
241 inline NativeCall* nativeCall_at(address addr);
242 // The NativeCall is an abstraction for accessing/manipulating native
243 // call instructions (used to manipulate inline caches, primitive &
244 // DSO calls, etc.).
245 
246 class NativeCall: public NativeInstruction {
247  public:
248   enum RISCV_specific_constants {
249     instruction_size            =    4,
250     instruction_offset          =    0,
251     displacement_offset         =    0,
252     return_address_offset       =    4
253   };
254 
255   address instruction_address() const       { return addr_at(instruction_offset); }
256   address next_instruction_address() const  { return addr_at(return_address_offset); }
257   address return_address() const            { return addr_at(return_address_offset); }
258   address destination() const;
259 
260   void set_destination(address dest) {
261     assert(is_jal(), "Should be jal instruction!");
262     intptr_t offset = (intptr_t)(dest - instruction_address());
263     assert((offset & 0x1) == 0, "bad alignment");
264     assert(is_imm_in_range(offset, 20, 1), "encoding constraint");
265     unsigned int insn = 0b1101111; // jal
266     address pInsn = (address)(&insn);
267     Assembler::patch(pInsn, 31, 31, (offset >> 20) & 0x1);
268     Assembler::patch(pInsn, 30, 21, (offset >> 1) & 0x3ff);
269     Assembler::patch(pInsn, 20, 20, (offset >> 11) & 0x1);
270     Assembler::patch(pInsn, 19, 12, (offset >> 12) & 0xff);
271     Assembler::patch(pInsn, 11, 7, ra->encoding()); // Rd must be x1, need ra
272     set_int_at(displacement_offset, insn);
273   }
274 
275   void verify_alignment() {} // do nothing on riscv
276   void verify();
277   void print();
278 
279   // Creation
280   inline friend NativeCall* nativeCall_at(address addr);
281   inline friend NativeCall* nativeCall_before(address return_address);
282 
283   static bool is_call_before(address return_address) {
284     return is_call_at(return_address - NativeCall::return_address_offset);
285   }
286 
287   // MT-safe patching of a call instruction.
288   static void insert(address code_pos, address entry);
289 
290   static void replace_mt_safe(address instr_addr, address code_buffer);
291 
292   // Similar to replace_mt_safe, but just changes the destination.  The
293   // important thing is that free-running threads are able to execute
294   // this call instruction at all times.  If the call is an immediate BL
295   // instruction we can simply rely on atomicity of 32-bit writes to
296   // make sure other threads will see no intermediate states.
297 
298   // We cannot rely on locks here, since the free-running threads must run at
299   // full speed.
300   //
301   // Used in the runtime linkage of calls; see class CompiledIC.
302   // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.)
303 
304   // The parameter assert_lock disables the assertion during code generation.
305   void set_destination_mt_safe(address dest, bool assert_lock = true);
306 
307   address get_trampoline();
308 };
309 
310 inline NativeCall* nativeCall_at(address addr) {
311   assert_cond(addr != NULL);
312   NativeCall* call = (NativeCall*)(addr - NativeCall::instruction_offset);
313   DEBUG_ONLY(call->verify());
314   return call;
315 }
316 
317 inline NativeCall* nativeCall_before(address return_address) {
318   assert_cond(return_address != NULL);
319   NativeCall* call = (NativeCall*)(return_address - NativeCall::return_address_offset);
320   DEBUG_ONLY(call->verify());
321   return call;
322 }
323 
324 // An interface for accessing/manipulating native mov reg, imm instructions.
325 // (used to manipulate inlined 64-bit data calls, etc.)
326 class NativeMovConstReg: public NativeInstruction {
327  public:
328   enum RISCV_specific_constants {
329     movptr_instruction_size             =    6 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli, addi.  See movptr().
330     movptr_with_offset_instruction_size =    5 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli. See movptr_with_offset().
331     load_pc_relative_instruction_size   =    2 * NativeInstruction::instruction_size, // auipc, ld
332     instruction_offset                  =    0,
333     displacement_offset                 =    0
334   };
335 
336   address instruction_address() const       { return addr_at(instruction_offset); }
337   address next_instruction_address() const  {
338     // if the instruction at 5 * instruction_size is addi,
339     // it means a lui + addi + slli + addi + slli + addi instruction sequence,
340     // and the next instruction address should be addr_at(6 * instruction_size).
341     // However, when the instruction at 5 * instruction_size isn't addi,
342     // the next instruction address should be addr_at(5 * instruction_size)
343     if (nativeInstruction_at(instruction_address())->is_movptr()) {
344       if (is_addi_at(addr_at(movptr_with_offset_instruction_size))) {
345         // Assume: lui, addi, slli, addi, slli, addi
346         return addr_at(movptr_instruction_size);
347       } else {
348         // Assume: lui, addi, slli, addi, slli
349         return addr_at(movptr_with_offset_instruction_size);
350       }
351     } else if (is_load_pc_relative_at(instruction_address())) {
352       // Assume: auipc, ld
353       return addr_at(load_pc_relative_instruction_size);
354     }
355     guarantee(false, "Unknown instruction in NativeMovConstReg");
356     return NULL;
357   }
358 
359   intptr_t data() const;
360   void set_data(intptr_t x);
361 
362   void flush() {
363     if (!maybe_cpool_ref(instruction_address())) {
364       ICache::invalidate_range(instruction_address(), movptr_instruction_size);
365     }
366   }
367 
368   void verify();
369   void print();
370 
371   // Creation
372   inline friend NativeMovConstReg* nativeMovConstReg_at(address addr);
373   inline friend NativeMovConstReg* nativeMovConstReg_before(address addr);
374 };
375 
376 inline NativeMovConstReg* nativeMovConstReg_at(address addr) {
377   assert_cond(addr != NULL);
378   NativeMovConstReg* test = (NativeMovConstReg*)(addr - NativeMovConstReg::instruction_offset);
379   DEBUG_ONLY(test->verify());
380   return test;
381 }
382 
383 inline NativeMovConstReg* nativeMovConstReg_before(address addr) {
384   assert_cond(addr != NULL);
385   NativeMovConstReg* test = (NativeMovConstReg*)(addr - NativeMovConstReg::instruction_size - NativeMovConstReg::instruction_offset);
386   DEBUG_ONLY(test->verify());
387   return test;
388 }
389 
390 // RISCV should not use C1 runtime patching, but still implement
391 // NativeMovRegMem to keep some compilers happy.
392 class NativeMovRegMem: public NativeInstruction {
393  public:
394   enum RISCV_specific_constants {
395     instruction_size            =    NativeInstruction::instruction_size,
396     instruction_offset          =    0,
397     data_offset                 =    0,
398     next_instruction_offset     =    NativeInstruction::instruction_size
399   };
400 
401   int instruction_start() const { return instruction_offset; }
402 
403   address instruction_address() const { return addr_at(instruction_offset); }
404 
405   int num_bytes_to_end_of_patch() const { return instruction_offset + instruction_size; }
406 
407   int offset() const;
408 
409   void set_offset(int x);
410 
411   void add_offset_in_bytes(int add_offset) {
412     set_offset(offset() + add_offset);
413   }
414 
415   void verify();
416   void print();
417 
418  private:
419   inline friend NativeMovRegMem* nativeMovRegMem_at(address addr);
420 };
421 
422 inline NativeMovRegMem* nativeMovRegMem_at(address addr) {
423   NativeMovRegMem* test = (NativeMovRegMem*)(addr - NativeMovRegMem::instruction_offset);
424   DEBUG_ONLY(test->verify());
425   return test;
426 }
427 
428 class NativeJump: public NativeInstruction {
429  public:
430   enum RISCV_specific_constants {
431     instruction_size            =    NativeInstruction::instruction_size,
432     instruction_offset          =    0,
433     data_offset                 =    0,
434     next_instruction_offset     =    NativeInstruction::instruction_size
435   };
436 
437   address instruction_address() const       { return addr_at(instruction_offset); }
438   address next_instruction_address() const  { return addr_at(instruction_size); }
439   address jump_destination() const;
440   void set_jump_destination(address dest);
441 
442   // Creation
443   inline friend NativeJump* nativeJump_at(address address);
444 
445   void verify();
446 
447   // Insertion of native jump instruction
448   static void insert(address code_pos, address entry);
449   // MT-safe insertion of native jump at verified method entry
450   static void check_verified_entry_alignment(address entry, address verified_entry);
451   static void patch_verified_entry(address entry, address verified_entry, address dest);
452 };
453 
454 inline NativeJump* nativeJump_at(address addr) {
455   NativeJump* jump = (NativeJump*)(addr - NativeJump::instruction_offset);
456   DEBUG_ONLY(jump->verify());
457   return jump;
458 }
459 
460 class NativeGeneralJump: public NativeJump {
461 public:
462   enum RISCV_specific_constants {
463     instruction_size            =    6 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli, jalr
464     instruction_offset          =    0,
465     data_offset                 =    0,
466     next_instruction_offset     =    6 * NativeInstruction::instruction_size  // lui, addi, slli, addi, slli, jalr
467   };
468 
469   address jump_destination() const;
470 
471   static void insert_unconditional(address code_pos, address entry);
472   static void replace_mt_safe(address instr_addr, address code_buffer);
473 };
474 
475 inline NativeGeneralJump* nativeGeneralJump_at(address addr) {
476   assert_cond(addr != NULL);
477   NativeGeneralJump* jump = (NativeGeneralJump*)(addr);
478   debug_only(jump->verify();)
479   return jump;
480 }
481 
482 class NativeIllegalInstruction: public NativeInstruction {
483  public:
484   // Insert illegal opcode as specific address
485   static void insert(address code_pos);
486 };
487 
488 inline bool NativeInstruction::is_nop()         {
489   uint32_t insn = *(uint32_t*)addr_at(0);
490   return insn == 0x13;
491 }
492 
493 inline bool NativeInstruction::is_jump_or_nop() {
494   return is_nop() || is_jump();
495 }
496 
497 // Call trampoline stubs.
498 class NativeCallTrampolineStub : public NativeInstruction {
499  public:
500 
501   enum RISCV_specific_constants {
502     // Refer to function emit_trampoline_stub.
503     instruction_size = 3 * NativeInstruction::instruction_size + wordSize, // auipc + ld + jr + target address
504     data_offset      = 3 * NativeInstruction::instruction_size,            // auipc + ld + jr
505   };
506 
507   address destination(nmethod *nm = NULL) const;
508   void set_destination(address new_destination);
509   ptrdiff_t destination_offset() const;
510 };
511 
512 inline bool is_NativeCallTrampolineStub_at(address addr) {
513   // Ensure that the stub is exactly
514   //      ld   t0, L--->auipc + ld
515   //      jr   t0
516   // L:
517 
518   // judge inst + register + imm
519   // 1). check the instructions: auipc + ld + jalr
520   // 2). check if auipc[11:7] == t0 and ld[11:7] == t0 and ld[19:15] == t0 && jr[19:15] == t0
521   // 3). check if the offset in ld[31:20] equals the data_offset
522   assert_cond(addr != NULL);
523   const int instr_size = NativeInstruction::instruction_size;
524   if (NativeInstruction::is_auipc_at(addr) &&
525       NativeInstruction::is_ld_at(addr + instr_size) &&
526       NativeInstruction::is_jalr_at(addr + 2 * instr_size) &&
527       (NativeInstruction::extract_rd(addr)                    == x5) &&
528       (NativeInstruction::extract_rd(addr + instr_size)       == x5) &&
529       (NativeInstruction::extract_rs1(addr + instr_size)      == x5) &&
530       (NativeInstruction::extract_rs1(addr + 2 * instr_size)  == x5) &&
531       (Assembler::extract(((unsigned*)addr)[1], 31, 20) == NativeCallTrampolineStub::data_offset)) {
532     return true;
533   }
534   return false;
535 }
536 
537 inline NativeCallTrampolineStub* nativeCallTrampolineStub_at(address addr) {
538   assert_cond(addr != NULL);
539   assert(is_NativeCallTrampolineStub_at(addr), "no call trampoline found");
540   return (NativeCallTrampolineStub*)addr;
541 }
542 
543 class NativeMembar : public NativeInstruction {
544 public:
545   uint32_t get_kind();
546   void set_kind(uint32_t order_kind);
547 };
548 
549 inline NativeMembar *NativeMembar_at(address addr) {
550   assert_cond(addr != NULL);
551   assert(nativeInstruction_at(addr)->is_membar(), "no membar found");
552   return (NativeMembar*)addr;
553 }
554 
555 #endif // CPU_RISCV_NATIVEINST_RISCV_HPP