• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gtest/gtest.h"
18 
19 #include "berberis/assembler/x86_64.h"
20 
21 #include "berberis/assembler/machine_code.h"
22 #include "berberis/base/bit_util.h"
23 #include "berberis/code_gen_lib/gen_adaptor.h"
24 #include "berberis/code_gen_lib/gen_wrapper.h"
25 #include "berberis/guest_abi/guest_arguments.h"
26 #include "berberis/guest_state/guest_addr.h"
27 #include "berberis/guest_state/guest_state.h"
28 #include "berberis/runtime_primitives/host_code.h"
29 #include "berberis/runtime_primitives/translation_cache.h"
30 #include "berberis/test_utils/scoped_exec_region.h"
31 #include "berberis/test_utils/testing_run_generated_code.h"
32 
33 namespace berberis {
34 
35 namespace {
36 
37 // Constant for NaN boxing and unboxing of 32-bit floats.
38 constexpr uint64_t kNanBoxFloat32 = 0xffff'ffff'0000'0000ULL;
39 
40 bool g_called;
41 uint32_t g_arg;
42 ThreadState g_state{};
43 uint32_t g_insn;
44 uint32_t g_ret_insn;
45 
DummyTrampoline(void * arg,ThreadState * state)46 void DummyTrampoline(void* arg, ThreadState* state) {
47   g_called = true;
48   ASSERT_EQ(&g_arg, arg);
49   ASSERT_EQ(&g_state, state);
50   ASSERT_EQ(g_state.cpu.insn_addr, ToGuestAddr(&g_insn));
51   ASSERT_EQ(GetLinkRegister(g_state.cpu), ToGuestAddr(&g_ret_insn));
52 }
53 
TEST(CodeGenLib,GenTrampolineAdaptor)54 TEST(CodeGenLib, GenTrampolineAdaptor) {
55   MachineCode machine_code;
56 
57   GenTrampolineAdaptor(
58       &machine_code, ToGuestAddr(&g_insn), AsHostCode(DummyTrampoline), &g_arg, "DummyTrampoline");
59 
60   ScopedExecRegion exec(&machine_code);
61 
62   g_called = false;
63   g_state.cpu.insn_addr = 0;
64   SetLinkRegister(g_state.cpu, ToGuestAddr(&g_ret_insn));
65 
66   TestingRunGeneratedCode(&g_state, exec.get(), ToGuestAddr(&g_ret_insn));
67 
68   ASSERT_TRUE(g_called);
69   ASSERT_EQ(g_state.cpu.insn_addr, ToGuestAddr(&g_ret_insn));
70 }
71 
GenMoveResidenceToReg(MachineCode * machine_code)72 void GenMoveResidenceToReg(MachineCode* machine_code) {
73   x86_64::Assembler as(machine_code);
74   // Perform x0 = ThreadState::residence.
75   as.Movq(as.rdx, {.base = as.rbp, .disp = offsetof(ThreadState, residence)});
76   as.Movq({.base = as.rbp, .disp = offsetof(ThreadState, cpu.x[0])}, as.rdx);
77   as.Jmp(kEntryExitGeneratedCode);
78 }
79 
GetResidenceReg(const ThreadState & state)80 uint64_t GetResidenceReg(const ThreadState& state) {
81   return state.cpu.x[0];
82 }
83 
CheckResidenceTrampoline(void *,ThreadState * state)84 void CheckResidenceTrampoline(void*, ThreadState* state) {
85   EXPECT_EQ(state->residence, kOutsideGeneratedCode);
86 }
87 
AddToTranslationCache(GuestAddr guest_addr,HostCodePiece host_code_piece)88 void AddToTranslationCache(GuestAddr guest_addr, HostCodePiece host_code_piece) {
89   auto* tc = TranslationCache::GetInstance();
90   GuestCodeEntry* entry = tc->AddAndLockForTranslation(guest_addr, 0);
91   ASSERT_NE(entry, nullptr);
92   tc->SetTranslatedAndUnlock(
93       guest_addr, entry, 1, GuestCodeEntry::Kind::kSpecialHandler, host_code_piece);
94 }
95 
TEST(CodeGenLib,GenTrampolineAdaptorResidence)96 TEST(CodeGenLib, GenTrampolineAdaptorResidence) {
97   MachineCode trampoline_adaptor;
98   GenTrampolineAdaptor(&trampoline_adaptor,
99                        ToGuestAddr(&g_insn),
100                        AsHostCode(CheckResidenceTrampoline),
101                        nullptr,
102                        nullptr);
103   ScopedExecRegion trampoline_exec(&trampoline_adaptor);
104 
105   // Trampoline returns to generated code, so we generate some.
106   MachineCode generated_code;
107   GenMoveResidenceToReg(&generated_code);
108   ScopedExecRegion generated_code_exec(&generated_code);
109 
110   AddToTranslationCache(ToGuestAddr(&g_ret_insn),
111                         {generated_code_exec.get(), generated_code.install_size()});
112 
113   g_state.cpu.insn_addr = 0;
114   SetLinkRegister(g_state.cpu, ToGuestAddr(&g_ret_insn));
115   EXPECT_EQ(g_state.residence, kOutsideGeneratedCode);
116 
117   berberis_RunGeneratedCode(&g_state, trampoline_exec.get());
118 
119   EXPECT_EQ(g_state.residence, kOutsideGeneratedCode);
120   EXPECT_EQ(g_state.cpu.insn_addr, ToGuestAddr(&g_ret_insn));
121   EXPECT_EQ(GetResidenceReg(g_state), kInsideGeneratedCode);
122 
123   TranslationCache::GetInstance()->InvalidateGuestRange(ToGuestAddr(&g_ret_insn),
124                                                         ToGuestAddr(&g_ret_insn) + 1);
125 }
126 
DummyRunner2(GuestAddr pc,GuestArgumentBuffer * buf)127 void DummyRunner2(GuestAddr pc, GuestArgumentBuffer* buf) {
128   g_called = true;
129   ASSERT_EQ(pc, ToGuestAddr(&g_insn));
130   ASSERT_NE(nullptr, buf);
131   ASSERT_EQ(1, buf->argc);
132   ASSERT_EQ(0, buf->resc);
133   ASSERT_EQ(1234u, buf->argv[0]);
134 }
135 
TEST(CodeGenLib,GenWrapGuestFunction)136 TEST(CodeGenLib, GenWrapGuestFunction) {
137   MachineCode machine_code;
138 
139   GenWrapGuestFunction(
140       &machine_code, ToGuestAddr(&g_insn), "vi", AsHostCode(DummyRunner2), "DummyRunner2");
141 
142   ScopedExecRegion exec(&machine_code);
143 
144   g_called = false;
145   exec.get<void(int)>()(1234);
146 
147   ASSERT_TRUE(g_called);
148 }
149 
Run10UInt8(GuestAddr pc,GuestArgumentBuffer * buf)150 void Run10UInt8(GuestAddr pc, GuestArgumentBuffer* buf) {
151   ASSERT_EQ(ToGuestAddr(&g_insn), pc);
152   ASSERT_NE(buf, nullptr);
153   ASSERT_EQ(buf->argc, 8);
154   ASSERT_EQ(buf->stack_argc, 16);
155   ASSERT_EQ(buf->resc, 1);
156   ASSERT_EQ(buf->argv[0], 0U);
157   ASSERT_EQ(buf->argv[1], 0xffU);
158   ASSERT_EQ(buf->argv[2], 2U);
159   ASSERT_EQ(buf->argv[3], 3U);
160   ASSERT_EQ(buf->argv[4], 4U);
161   ASSERT_EQ(buf->argv[5], 5U);
162   ASSERT_EQ(buf->argv[6], 6U);
163   ASSERT_EQ(buf->argv[7], 0xf9U);
164   ASSERT_EQ(buf->stack_argv[0], 0xf8U);
165   ASSERT_EQ(buf->stack_argv[1], 9U);
166   buf->argv[0] = 0xf6;
167 }
168 
TEST(CodeGenLib,GenWrapGuestFunction_Run10UInt8)169 TEST(CodeGenLib, GenWrapGuestFunction_Run10UInt8) {
170   MachineCode machine_code;
171 
172   GenWrapGuestFunction(
173       &machine_code, ToGuestAddr(&g_insn), "zzzzzzzzzzz", AsHostCode(Run10UInt8), "Run10UInt8");
174 
175   ScopedExecRegion exec(&machine_code);
176 
177   using Func = uint8_t(
178       uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t);
179   uint8_t res = exec.get<Func>()(0, 0xff, 2, 3, 4, 5, 6, 0xf9, 0xf8, 9);
180   ASSERT_EQ(res, 0xF6u);
181 }
182 
Run10Int8(GuestAddr pc,GuestArgumentBuffer * buf)183 void Run10Int8(GuestAddr pc, GuestArgumentBuffer* buf) {
184   ASSERT_EQ(ToGuestAddr(&g_insn), pc);
185   ASSERT_NE(buf, nullptr);
186   ASSERT_EQ(buf->argc, 8);
187   ASSERT_EQ(buf->stack_argc, 16);
188   ASSERT_EQ(buf->resc, 1);
189   ASSERT_EQ(buf->argv[0], 0U);
190   ASSERT_EQ(buf->argv[1], 0xffff'ffff'ffff'ffffULL);
191   ASSERT_EQ(buf->argv[2], 2U);
192   ASSERT_EQ(buf->argv[3], 3U);
193   ASSERT_EQ(buf->argv[4], 4U);
194   ASSERT_EQ(buf->argv[5], 5U);
195   ASSERT_EQ(buf->argv[6], 6U);
196   ASSERT_EQ(buf->argv[7], 0xffff'ffff'ffff'fff9ULL);
197   ASSERT_EQ(buf->stack_argv[0], 0xffff'ffff'ffff'fff8ULL);
198   ASSERT_EQ(buf->stack_argv[1], 9U);
199   buf->argv[0] = 0xffff'ffff'ffff'fff6;
200 }
201 
TEST(CodeGenLib,GenWrapGuestFunction_Run10Int8)202 TEST(CodeGenLib, GenWrapGuestFunction_Run10Int8) {
203   MachineCode machine_code;
204 
205   GenWrapGuestFunction(
206       &machine_code, ToGuestAddr(&g_insn), "bbbbbbbbbbb", AsHostCode(Run10Int8), "Run10Int8");
207 
208   ScopedExecRegion exec(&machine_code);
209 
210   using Func =
211       int8_t(int8_t, int8_t, int8_t, int8_t, int8_t, int8_t, int8_t, int8_t, int8_t, int8_t);
212   int8_t res = exec.get<Func>()(0, -1, 2, 3, 4, 5, 6, -7, -8, 9);
213   ASSERT_EQ(res, -10);
214 }
215 
Run10UInt16(GuestAddr pc,GuestArgumentBuffer * buf)216 void Run10UInt16(GuestAddr pc, GuestArgumentBuffer* buf) {
217   ASSERT_EQ(ToGuestAddr(&g_insn), pc);
218   ASSERT_NE(buf, nullptr);
219   ASSERT_EQ(buf->argc, 8);
220   ASSERT_EQ(buf->stack_argc, 16);
221   ASSERT_EQ(buf->resc, 1);
222   ASSERT_EQ(buf->argv[0], 0U);
223   ASSERT_EQ(buf->argv[1], 0xffffU);
224   ASSERT_EQ(buf->argv[2], 2U);
225   ASSERT_EQ(buf->argv[3], 3U);
226   ASSERT_EQ(buf->argv[4], 4U);
227   ASSERT_EQ(buf->argv[5], 5U);
228   ASSERT_EQ(buf->argv[6], 6U);
229   ASSERT_EQ(buf->argv[7], 0xfff9U);
230   ASSERT_EQ(buf->stack_argv[0], 0xfff8U);
231   ASSERT_EQ(buf->stack_argv[1], 9U);
232   buf->argv[0] = 0xfff6;
233 }
234 
TEST(CodeGenLib,GenWrapGuestFunction_Run10UInt16)235 TEST(CodeGenLib, GenWrapGuestFunction_Run10UInt16) {
236   MachineCode machine_code;
237 
238   GenWrapGuestFunction(
239       &machine_code, ToGuestAddr(&g_insn), "ccccccccccc", AsHostCode(Run10UInt16), "Run10UInt16");
240 
241   ScopedExecRegion exec(&machine_code);
242 
243   using Func = uint16_t(uint16_t,
244                         uint16_t,
245                         uint16_t,
246                         uint16_t,
247                         uint16_t,
248                         uint16_t,
249                         uint16_t,
250                         uint16_t,
251                         uint16_t,
252                         uint16_t);
253   uint16_t res = exec.get<Func>()(0, 0xffff, 2, 3, 4, 5, 6, 0xfff9, 0xfff8, 9);
254   ASSERT_EQ(res, 0xfff6U);
255 }
256 
Run10Int16(GuestAddr pc,GuestArgumentBuffer * buf)257 void Run10Int16(GuestAddr pc, GuestArgumentBuffer* buf) {
258   ASSERT_EQ(ToGuestAddr(&g_insn), pc);
259   ASSERT_NE(buf, nullptr);
260   ASSERT_EQ(buf->argc, 8);
261   ASSERT_EQ(buf->stack_argc, 16);
262   ASSERT_EQ(buf->resc, 1);
263   ASSERT_EQ(buf->argv[0], 0U);
264   ASSERT_EQ(buf->argv[1], 0xffff'ffff'ffff'ffffULL);
265   ASSERT_EQ(buf->argv[2], 2U);
266   ASSERT_EQ(buf->argv[3], 3U);
267   ASSERT_EQ(buf->argv[4], 4U);
268   ASSERT_EQ(buf->argv[5], 5U);
269   ASSERT_EQ(buf->argv[6], 6U);
270   ASSERT_EQ(buf->argv[7], 0xffff'ffff'ffff'fff9ULL);
271   ASSERT_EQ(buf->stack_argv[0], 0xffff'ffff'ffff'fff8ULL);
272   ASSERT_EQ(buf->stack_argv[1], 9U);
273   buf->argv[0] = 0xffff'ffff'ffff'fff6;
274 }
275 
TEST(CodeGenLib,GenWrapGuestFunction_Run10Int16)276 TEST(CodeGenLib, GenWrapGuestFunction_Run10Int16) {
277   MachineCode machine_code;
278 
279   GenWrapGuestFunction(
280       &machine_code, ToGuestAddr(&g_insn), "sssssssssss", AsHostCode(Run10Int16), "Run10Int16");
281 
282   ScopedExecRegion exec(&machine_code);
283 
284   using Func = int16_t(
285       int16_t, int16_t, int16_t, int16_t, int16_t, int16_t, int16_t, int16_t, int16_t, int16_t);
286   int16_t res = exec.get<Func>()(0, -1, 2, 3, 4, 5, 6, -7, -8, 9);
287   ASSERT_EQ(res, -10);
288 }
289 
Run10Int(GuestAddr pc,GuestArgumentBuffer * buf)290 void Run10Int(GuestAddr pc, GuestArgumentBuffer* buf) {
291   ASSERT_EQ(ToGuestAddr(&g_insn), pc);
292   ASSERT_NE(buf, nullptr);
293   ASSERT_EQ(buf->argc, 8);
294   ASSERT_EQ(buf->stack_argc, 16);
295   ASSERT_EQ(buf->resc, 1);
296   ASSERT_EQ(buf->argv[0], 0U);
297   ASSERT_EQ(buf->argv[1], 0xffff'ffff'ffff'ffffULL);
298   ASSERT_EQ(buf->argv[2], 2U);
299   ASSERT_EQ(buf->argv[3], 3U);
300   ASSERT_EQ(buf->argv[4], 4U);
301   ASSERT_EQ(buf->argv[5], 5U);
302   ASSERT_EQ(buf->argv[6], 6U);
303   ASSERT_EQ(buf->argv[7], 0xffff'ffff'ffff'fff9ULL);
304   ASSERT_EQ(buf->stack_argv[0], 0xffff'ffff'ffff'fff8ULL);
305   ASSERT_EQ(buf->stack_argv[1], 9U);
306   buf->argv[0] = 0xffff'ffff'ffff'fff6;
307 }
308 
TEST(CodeGenLib,GenWrapGuestFunction_Run10Int)309 TEST(CodeGenLib, GenWrapGuestFunction_Run10Int) {
310   MachineCode machine_code;
311 
312   GenWrapGuestFunction(
313       &machine_code, ToGuestAddr(&g_insn), "iiiiiiiiiii", AsHostCode(Run10Int), "Run10Int");
314 
315   ScopedExecRegion exec(&machine_code);
316 
317   using Func = int(int, int, int, int, int, int, int, int, int, int);
318   int res = exec.get<Func>()(0, -1, 2, 3, 4, 5, 6, -7, -8, 9);
319   ASSERT_EQ(res, -10);
320 }
321 
Run18Fp(GuestAddr pc,GuestArgumentBuffer * buf)322 void Run18Fp(GuestAddr pc, GuestArgumentBuffer* buf) {
323   static_assert(sizeof(float) == sizeof(uint32_t));
324   ASSERT_EQ(pc, ToGuestAddr(&g_insn));
325   ASSERT_NE(nullptr, buf);
326   // riscv verification
327   ASSERT_EQ(8, buf->argc);
328   ASSERT_EQ(8, buf->fp_argc);
329   ASSERT_EQ(16, buf->stack_argc);
330   ASSERT_EQ(0, buf->resc);
331   ASSERT_EQ(1, buf->fp_resc);
332   // 32-bit parameters passed in floating-point registers are 1-extended.
333   // 32-bit parameters passed in general-purpose registers and on the stack are 0-extended.
334   ASSERT_EQ(kNanBoxFloat32, buf->fp_argv[0] & kNanBoxFloat32);
335   ASSERT_FLOAT_EQ(0.0f, bit_cast<float>(static_cast<uint32_t>(buf->fp_argv[0])));
336   ASSERT_EQ(kNanBoxFloat32, buf->fp_argv[1] & kNanBoxFloat32);
337   ASSERT_FLOAT_EQ(1.1f, bit_cast<float>(static_cast<uint32_t>(buf->fp_argv[1])));
338   ASSERT_EQ(kNanBoxFloat32, buf->fp_argv[2] & kNanBoxFloat32);
339   ASSERT_FLOAT_EQ(2.2f, bit_cast<float>(static_cast<uint32_t>(buf->fp_argv[2])));
340   ASSERT_EQ(kNanBoxFloat32, buf->fp_argv[3] & kNanBoxFloat32);
341   ASSERT_FLOAT_EQ(3.3f, bit_cast<float>(static_cast<uint32_t>(buf->fp_argv[3])));
342   ASSERT_EQ(kNanBoxFloat32, buf->fp_argv[4] & kNanBoxFloat32);
343   ASSERT_FLOAT_EQ(4.4f, bit_cast<float>(static_cast<uint32_t>(buf->fp_argv[4])));
344   ASSERT_EQ(kNanBoxFloat32, buf->fp_argv[5] & kNanBoxFloat32);
345   ASSERT_FLOAT_EQ(5.5f, bit_cast<float>(static_cast<uint32_t>(buf->fp_argv[5])));
346   ASSERT_EQ(kNanBoxFloat32, buf->fp_argv[6] & kNanBoxFloat32);
347   ASSERT_FLOAT_EQ(6.6f, bit_cast<float>(static_cast<uint32_t>(buf->fp_argv[6])));
348   ASSERT_EQ(kNanBoxFloat32, buf->fp_argv[7] & kNanBoxFloat32);
349   ASSERT_FLOAT_EQ(7.7f, bit_cast<float>(static_cast<uint32_t>(buf->fp_argv[7])));
350   ASSERT_FLOAT_EQ(8.8f, bit_cast<float>(static_cast<uint32_t>(buf->argv[0])));
351   ASSERT_FLOAT_EQ(9.9f, bit_cast<float>(static_cast<uint32_t>(buf->argv[1])));
352   ASSERT_FLOAT_EQ(10.01f, bit_cast<float>(static_cast<uint32_t>(buf->argv[2])));
353   ASSERT_FLOAT_EQ(20.02f, bit_cast<float>(static_cast<uint32_t>(buf->argv[3])));
354   ASSERT_FLOAT_EQ(30.03f, bit_cast<float>(static_cast<uint32_t>(buf->argv[4])));
355   ASSERT_FLOAT_EQ(40.04f, bit_cast<float>(static_cast<uint32_t>(buf->argv[5])));
356   ASSERT_FLOAT_EQ(50.05f, bit_cast<float>(static_cast<uint32_t>(buf->argv[6])));
357   ASSERT_FLOAT_EQ(60.06f, bit_cast<float>(static_cast<uint32_t>(buf->argv[7])));
358   ASSERT_FLOAT_EQ(70.07f, bit_cast<float>(static_cast<uint32_t>(buf->stack_argv[0])));
359   ASSERT_FLOAT_EQ(80.08f, bit_cast<float>(static_cast<uint32_t>(buf->stack_argv[1])));
360   buf->fp_argv[0] = static_cast<uint64_t>(bit_cast<uint32_t>(45.45f)) | kNanBoxFloat32;
361 }
362 
TEST(CodeGenLib,GenWrapGuestFunction_Run10Fp)363 TEST(CodeGenLib, GenWrapGuestFunction_Run10Fp) {
364   MachineCode machine_code;
365 
366   GenWrapGuestFunction(
367       &machine_code, ToGuestAddr(&g_insn), "fffffffffffffffffff", AsHostCode(Run18Fp), "Run18Fp");
368 
369   ScopedExecRegion exec(&machine_code);
370 
371   using Func = float(float,
372                      float,
373                      float,
374                      float,
375                      float,
376                      float,
377                      float,
378                      float,
379                      float,
380                      float,
381                      float,
382                      float,
383                      float,
384                      float,
385                      float,
386                      float,
387                      float,
388                      float);
389   float res = exec.get<Func>()(0.0f,
390                                1.1f,
391                                2.2f,
392                                3.3f,
393                                4.4f,
394                                5.5f,
395                                6.6f,
396                                7.7f,
397                                8.8f,
398                                9.9f,
399                                10.01f,
400                                20.02f,
401                                30.03f,
402                                40.04f,
403                                50.05f,
404                                60.06f,
405                                70.07f,
406                                80.08f);
407   ASSERT_FLOAT_EQ(45.45f, res);
408 }
409 
410 }  // namespace
411 
412 }  // namespace berberis
413