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_GUEST_OS_PRIMITIVES_GUEST_CONTEXT_ARCH_H_
18 #define BERBERIS_GUEST_OS_PRIMITIVES_GUEST_CONTEXT_ARCH_H_
19 
20 #include <cstdint>
21 #include <cstring>  // memcpy
22 
23 #include "berberis/base/checks.h"
24 #include "berberis/base/struct_check.h"
25 #include "berberis/guest_state/guest_state.h"
26 
27 namespace berberis {
28 
29 class GuestContext {
30  public:
31   GuestContext() = default;
32   GuestContext(const GuestContext&) = delete;
33   GuestContext& operator=(const GuestContext&) = delete;
34 
Save(const CPUState * cpu)35   void Save(const CPUState* cpu) {
36     // Save everything.
37     cpu_ = *cpu;
38 
39     // Save context.
40     memset(&ctx_, 0, sizeof(ctx_));
41     static_assert(sizeof(cpu->x) == sizeof(ctx_.uc_mcontext.sc_regs));
42     memcpy(&ctx_.uc_mcontext.sc_regs, cpu->x, sizeof(ctx_.uc_mcontext.sc_regs));
43     // Use double FP state since GuestState supports both F and D extensions using 64-bit registers.
44     static_assert(sizeof(cpu->f) == sizeof(ctx_.uc_mcontext.sc_fpregs.d.f));
45     memcpy(ctx_.uc_mcontext.sc_fpregs.d.f, cpu->f, sizeof(ctx_.uc_mcontext.sc_fpregs.d.f));
46     ctx_.uc_mcontext.sc_regs.pc = cpu->insn_addr;
47   }
48 
Restore(CPUState * cpu)49   void Restore(CPUState* cpu) const {
50     // Restore everything.
51     *cpu = cpu_;
52 
53     // Overwrite from context.
54     memcpy(cpu->x, &ctx_.uc_mcontext.sc_regs, sizeof(ctx_.uc_mcontext.sc_regs));
55     memcpy(cpu->f, ctx_.uc_mcontext.sc_fpregs.d.f, sizeof(ctx_.uc_mcontext.sc_fpregs.d.f));
56     cpu->insn_addr = ctx_.uc_mcontext.sc_regs.pc;
57   }
58 
ptr()59   void* ptr() { return &ctx_; }
60 
61  private:
62   // See bionic/libc/kernel/uapi/asm-riscv/asm/ptrace.h
63   struct Guest_user_regs_struct {
64     uint64_t pc;
65     uint64_t ra;
66     uint64_t sp;
67     uint64_t gp;
68     uint64_t tp;
69     uint64_t t0;
70     uint64_t t1;
71     uint64_t t2;
72     uint64_t s0;
73     uint64_t s1;
74     uint64_t a0;
75     uint64_t a1;
76     uint64_t a2;
77     uint64_t a3;
78     uint64_t a4;
79     uint64_t a5;
80     uint64_t a6;
81     uint64_t a7;
82     uint64_t s2;
83     uint64_t s3;
84     uint64_t s4;
85     uint64_t s5;
86     uint64_t s6;
87     uint64_t s7;
88     uint64_t s8;
89     uint64_t s9;
90     uint64_t s10;
91     uint64_t s11;
92     uint64_t t3;
93     uint64_t t4;
94     uint64_t t5;
95     uint64_t t6;
96   };
97   struct Guest__riscv_f_ext_state {
98     uint32_t f[32];
99     uint32_t fcsr;
100   };
101   struct Guest__riscv_d_ext_state {
102     uint64_t f[32];
103     uint32_t fcsr;
104   };
105   struct Guest__riscv_q_ext_state {
106     uint64_t f[64] __attribute__((aligned(16)));
107     uint32_t fcsr;
108     uint32_t reserved[3];
109   };
110   union Guest__riscv_fp_state {
111     struct Guest__riscv_f_ext_state f;
112     struct Guest__riscv_d_ext_state d;
113     struct Guest__riscv_q_ext_state q;
114   };
115 
116   // See bionic/libc/kernel/uapi/asm-riscv/asm/sigcontext.h
117   struct Guest_sigcontext {
118     struct Guest_user_regs_struct sc_regs;
119     union Guest__riscv_fp_state sc_fpregs;
120   };
121 
122   // See bionic/libc/kernel/uapi/asm-riscv/asm/ucontext.h
123   struct Guest_ucontext {
124     uint64_t uc_flags;
125     Guest_ucontext* uc_link;
126     // We assume guest stack_t is compatible with host (see RunGuestSyscall___NR_sigaltstack).
127     stack_t uc_stack;
128     Guest_sigset_t uc_sigmask;
129     uint8_t __linux_unused[1024 / 8 - sizeof(Guest_sigset_t)];
130     Guest_sigcontext uc_mcontext;
131   };
132 
133   CHECK_STRUCT_LAYOUT(Guest_ucontext, 7680, 128);
134   CHECK_FIELD_LAYOUT(Guest_ucontext, uc_flags, 0, 64);
135   CHECK_FIELD_LAYOUT(Guest_ucontext, uc_link, 64, 64);
136   CHECK_FIELD_LAYOUT(Guest_ucontext, uc_stack, 128, 192);
137   // Bionic RISC-V sigset_t is 64 bits (generic implementation).
138   CHECK_FIELD_LAYOUT(Guest_ucontext, uc_sigmask, 320, 64);
139   CHECK_FIELD_LAYOUT(Guest_ucontext, uc_mcontext, 1408, 6272);
140 
141   Guest_ucontext ctx_;
142   CPUState cpu_;
143 };
144 
145 }  // namespace berberis
146 
147 #endif  // BERBERIS_GUEST_OS_PRIMITIVES_GUEST_CONTEXT_ARCH_H_