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 #ifndef BERBERIS_RUNTIME_PRIMITIVES_VIRTUAL_GUEST_CALL_FRAME_H_
18 #define BERBERIS_RUNTIME_PRIMITIVES_VIRTUAL_GUEST_CALL_FRAME_H_
19 
20 #include "berberis/guest_state/guest_addr.h"
21 #include "berberis/guest_state/guest_state_opaque.h"
22 
23 namespace berberis {
24 
25 // Set state for calling guest function at given pc (except arguments passing).
26 // Restore previous state after guest function returns.
27 //
28 // Assume we have some meaningful guest state, for example, at trampoline or at signal handler call.
29 // We want to call nested guest function, for example, callback passed into trampoline or guest
30 // signal handler. We want to restore the state after guest nested function returns.
31 //
32 // Assume guest function to be called conforms to procedure calling standard. In particular, it is
33 // expected to preserve caller-saved registers, and to return by jumping to a given return address.
34 //
35 // Assume we want to allow guest unwinder to unwind to the previous guest state. For that, we should
36 // only save state into guest accessible memory - namely, into guest stack/registers.
37 //
38 // First, we want guest execution to stop when guest function returns. For that, we provide special
39 // return address that is treated as stop by dispatcher.
40 //
41 // Next, parameters are passed afterwards, so at this point we don't know how much stack they will
42 // need. To restore stack after the call, we need to save current stack pointer in a caller-saved
43 // register.
44 //
45 // Finally, we need to save the registers that are not preserved by guest function.
46 class ScopedVirtualGuestCallFrame {
47  public:
48   ScopedVirtualGuestCallFrame(CPUState* cpu, GuestAddr pc);
49   ~ScopedVirtualGuestCallFrame();
50 
SetReturnAddress(GuestAddr ra)51   static void SetReturnAddress(GuestAddr ra) { g_return_address_ = ra; }
52 
53  private:
54   static GuestAddr g_return_address_;
55 
56   CPUState* cpu_;
57 
58   // For safety checks!
59   GuestAddr stack_pointer_;
60   GuestAddr link_register_;
61   GuestAddr program_counter_;
62 };
63 
64 // Set return address for guest calls. On this address, guest execution will stop.
65 void InitVirtualGuestCallFrameReturnAddress(GuestAddr ra);
66 
67 }  // namespace berberis
68 
69 #endif  // BERBERIS_RUNTIME_PRIMITIVES_VIRTUAL_GUEST_CALL_FRAME_H_
70