1 /*
2  * Copyright (C) 2023 The Android Open Source Project
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 
17 #include "berberis/runtime/translator.h"
18 #include "translator.h"
19 
20 #include <cstdint>
21 #include <cstdlib>
22 #include <tuple>
23 
24 #include "berberis/assembler/machine_code.h"
25 #include "berberis/guest_os_primitives/guest_map_shadow.h"
26 #include "berberis/interpreter/riscv64/interpreter.h"
27 #include "berberis/runtime_primitives/code_pool.h"
28 #include "berberis/runtime_primitives/host_code.h"
29 #include "berberis/runtime_primitives/profiler_interface.h"
30 #include "berberis/runtime_primitives/translation_cache.h"
31 #include "berberis/runtime_primitives/virtual_guest_call_frame.h"
32 
33 namespace berberis {
34 
35 namespace {
36 
37 // Syntax sugar.
38 GuestCodeEntry::Kind kSpecialHandler = GuestCodeEntry::Kind::kSpecialHandler;
39 
40 // Use aligned address of this variable as the default stop address for guest execution.
41 // It should never coincide with any guest address or address of a wrapped host symbol.
42 // Unwinder might examine nearby insns.
43 alignas(4) uint32_t g_native_bridge_call_guest[] = {
44     // <native_bridge_call_guest>:
45     0xd503201f,  // nop
46     0xd503201f,  // nop  <--
47     0xd503201f,  // nop
48 };
49 
GetRiscv64InsnSize(GuestAddr pc)50 uint8_t GetRiscv64InsnSize(GuestAddr pc) {
51   constexpr uint16_t kInsnLenMask = uint16_t{0b11};
52   if ((*ToHostAddr<uint16_t>(pc) & kInsnLenMask) != kInsnLenMask) {
53     return 2;
54   }
55   return 4;
56 }
57 
58 }  // namespace
59 
InstallTranslated(MachineCode * machine_code,GuestAddr pc,size_t size,const char * prefix)60 HostCodePiece InstallTranslated(MachineCode* machine_code,
61                                 GuestAddr pc,
62                                 size_t size,
63                                 const char* prefix) {
64   HostCodeAddr host_code = GetDefaultCodePoolInstance()->Add(machine_code);
65   ProfilerLogGeneratedCode(AsHostCode(host_code), machine_code->install_size(), pc, size, prefix);
66   return {host_code, machine_code->install_size()};
67 }
68 
69 // Check whether the given guest program counter is executable, accounting for compressed
70 // instructions. Returns a tuple indicating whether the memory is executable and the size of the
71 // first instruction in bytes.
IsPcExecutable(GuestAddr pc,GuestMapShadow * guest_map_shadow)72 std::tuple<bool, uint8_t> IsPcExecutable(GuestAddr pc, GuestMapShadow* guest_map_shadow) {
73   // First check if the instruction would be in executable memory if it is compressed.  This
74   // prevents dereferencing unknown memory to determine the size of the instruction.
75   constexpr uint8_t kMinimumInsnSize = 2;
76   if (!guest_map_shadow->IsExecutable(pc, kMinimumInsnSize)) {
77     return {false, kMinimumInsnSize};
78   }
79 
80   // Now check the rest of the instruction based on its size.  It is now safe to dereference the
81   // memory at pc because at least two bytes are within known executable memory.
82   uint8_t first_insn_size = GetRiscv64InsnSize(pc);
83   if (first_insn_size > kMinimumInsnSize &&
84       !guest_map_shadow->IsExecutable(pc + kMinimumInsnSize, first_insn_size - kMinimumInsnSize)) {
85     return {false, first_insn_size};
86   }
87 
88   return {true, first_insn_size};
89 }
90 
InitTranslator()91 void InitTranslator() {
92   InitTranslatorArch();
93   InitVirtualGuestCallFrameReturnAddress(ToGuestAddr(g_native_bridge_call_guest + 1));
94   InitInterpreter();
95 }
96 
97 }  // namespace berberis
98