1 /*
2 * Copyright (C) 2018 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 <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
18 #include <linux/sched.h>
19 #include <linux/unistd.h>
20 #include <sys/stat.h>
21 #include <sys/sysinfo.h>
22 #include <sys/types.h>
23
24 #include <cerrno>
25
26 #include "berberis/base/macros.h"
27 #include "berberis/base/scoped_errno.h"
28 #include "berberis/base/tracing.h"
29 #include "berberis/guest_state/guest_addr.h"
30 #include "berberis/guest_state/guest_state.h"
31 #include "berberis/instrument/syscall.h"
32 #include "berberis/kernel_api/main_executable_real_path_emulation.h"
33 #include "berberis/kernel_api/runtime_bridge.h"
34 #include "berberis/kernel_api/syscall_emulation_common.h"
35
36 // TODO(b/346604197): Enable on arm64 once these modules are ported.
37 #ifdef __x86_64__
38 #include "berberis/guest_os_primitives/scoped_pending_signals.h"
39 #include "berberis/runtime_primitives/runtime_library.h"
40 #endif
41
42 #include "epoll_emulation.h"
43 #include "guest_types.h"
44
45 namespace berberis {
46
47 namespace {
48
FstatatForGuest(int dirfd,const char * path,struct stat * buf,int flags)49 int FstatatForGuest(int dirfd, const char* path, struct stat* buf, int flags) {
50 const char* real_path = nullptr;
51 if ((flags & AT_SYMLINK_NOFOLLOW) == 0) {
52 real_path = TryReadLinkToMainExecutableRealPath(path);
53 }
54 return syscall(__NR_newfstatat, dirfd, real_path ? real_path : path, buf, flags);
55 }
56
Hwprobe(Guest_riscv_hwprobe & pair)57 void Hwprobe(Guest_riscv_hwprobe& pair) {
58 switch (pair.key) {
59 case RISCV_HWPROBE_KEY_MVENDORID:
60 pair.value = 0;
61 break;
62 case RISCV_HWPROBE_KEY_MARCHID:
63 pair.value = 0;
64 break;
65 case RISCV_HWPROBE_KEY_MIMPID:
66 pair.value = 0;
67 break;
68 case RISCV_HWPROBE_KEY_BASE_BEHAVIOR:
69 pair.value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA;
70 break;
71 case RISCV_HWPROBE_KEY_IMA_EXT_0:
72 pair.value = RISCV_HWPROBE_IMA_FD | RISCV_HWPROBE_IMA_C | RISCV_HWPROBE_IMA_V |
73 RISCV_HWPROBE_EXT_ZBA | RISCV_HWPROBE_EXT_ZBB | RISCV_HWPROBE_EXT_ZBS;
74 break;
75 case RISCV_HWPROBE_KEY_CPUPERF_0:
76 pair.value = RISCV_HWPROBE_MISALIGNED_FAST;
77 break;
78 default:
79 TRACE("unsupported __riscv_hwprobe capability key: %ld", pair.key);
80 pair.key = -1;
81 pair.value = 0;
82 break;
83 }
84 }
85
RunGuestSyscall___NR_execveat(long arg_1,long arg_2,long arg_3,long arg_4,long arg_5)86 long RunGuestSyscall___NR_execveat(long arg_1, long arg_2, long arg_3, long arg_4, long arg_5) {
87 UNUSED(arg_1, arg_2, arg_3, arg_4, arg_5);
88 TRACE("unimplemented syscall __NR_execveat");
89 errno = ENOSYS;
90 return -1;
91 }
92
93 // sys_fadvise64 has a different entry-point symbol name between riscv64 and x86_64.
94 #ifdef __x86_64__
RunGuestSyscall___NR_fadvise64(long arg_1,long arg_2,long arg_3,long arg_4)95 long RunGuestSyscall___NR_fadvise64(long arg_1, long arg_2, long arg_3, long arg_4) {
96 // on 64-bit architectures, sys_fadvise64 and sys_fadvise64_64 are equal.
97 return syscall(__NR_fadvise64, arg_1, arg_2, arg_3, arg_4);
98 }
99 #endif
100
RunGuestSyscall___NR_ioctl(long arg_1,long arg_2,long arg_3)101 long RunGuestSyscall___NR_ioctl(long arg_1, long arg_2, long arg_3) {
102 // TODO(b/128614662): translate!
103 TRACE("unimplemented ioctl 0x%lx, running host syscall as is", arg_2);
104 return syscall(__NR_ioctl, arg_1, arg_2, arg_3);
105 }
106
RunGuestSyscall___NR_newfstatat(long arg_1,long arg_2,long arg_3,long arg_4)107 long RunGuestSyscall___NR_newfstatat(long arg_1, long arg_2, long arg_3, long arg_4) {
108 struct stat host_stat;
109 int result = FstatatForGuest(static_cast<int>(arg_1), // dirfd
110 bit_cast<const char*>(arg_2), // path
111 &host_stat,
112 static_cast<int>(arg_4)); // flags
113 if (result != -1) {
114 ConvertHostStatToGuestArch(host_stat, bit_cast<GuestAddr>(arg_3));
115 }
116 return result;
117 }
118
RunGuestSyscall___NR_riscv_hwprobe(long arg_1,long arg_2,long arg_3,long arg_4,long arg_5)119 long RunGuestSyscall___NR_riscv_hwprobe(long arg_1,
120 long arg_2,
121 long arg_3,
122 long arg_4,
123 long arg_5) {
124 UNUSED(arg_3, arg_4); // cpu_count, cpus_in
125
126 // There are currently no flags defined by the kernel. This may change in the future.
127 static constexpr unsigned int kFlagsAll = 0;
128
129 auto pairs = bit_cast<Guest_riscv_hwprobe*>(arg_1);
130 auto pair_count = bit_cast<size_t>(arg_2);
131 auto flags = static_cast<unsigned int>(bit_cast<unsigned long>(arg_5));
132 if ((flags & ~kFlagsAll) != 0) {
133 return -EINVAL;
134 }
135
136 for (size_t i = 0; i < pair_count; ++i) {
137 Hwprobe(pairs[i]);
138 }
139 return 0;
140 }
141
RunGuestSyscall___NR_riscv_flush_icache(long arg_1,long arg_2,long arg_3)142 long RunGuestSyscall___NR_riscv_flush_icache(long arg_1, long arg_2, long arg_3) {
143 // TODO(b/346604197): Enable on arm64 once runtime_primitives are ready.
144 #ifdef __x86_64__
145 static constexpr uint64_t kFlagsLocal = 1UL;
146 static constexpr uint64_t kFlagsAll = kFlagsLocal;
147
148 // ATTENTION: On RISC-V, arg_2 is the address range end, not the address range size.
149 auto start = bit_cast<GuestAddr>(arg_1);
150 auto end = bit_cast<GuestAddr>(arg_2);
151 auto flags = bit_cast<uint64_t>(arg_3);
152 if (end < start || (flags & ~kFlagsAll) != 0) {
153 errno = EINVAL;
154 return -1;
155 }
156
157 // Ignore kFlagsLocal because we do not have a per-thread cache to clear.
158 TRACE("icache flush: [0x%lx, 0x%lx)", start, end);
159 InvalidateGuestRange(start, end);
160 return 0;
161 #else
162 UNUSED(arg_1, arg_2, arg_3);
163 TRACE("unimplemented syscall __NR_riscv_flush_icache");
164 errno = ENOSYS;
165 return -1;
166 #endif
167 }
168
169 // RunGuestSyscallImpl.
170 #if defined(__aarch64__)
171 #include "gen_syscall_emulation_riscv64_to_arm64-inl.h"
172 #elif defined(__x86_64__)
173 #include "gen_syscall_emulation_riscv64_to_x86_64-inl.h"
174 #else
175 #error "Unsupported host arch"
176 #endif
177
178 } // namespace
179
RunGuestSyscall(ThreadState * state)180 void RunGuestSyscall(ThreadState* state) {
181 #ifdef __x86_64__
182 // ATTENTION: run guest signal handlers instantly!
183 // If signal arrives while in a syscall, syscall should immediately return with EINTR.
184 // In this case pending signals are OK, as guest handlers will run on return from syscall.
185 // BUT, if signal action has SA_RESTART, certain syscalls will restart instead of returning.
186 // In this case, pending signals will never run...
187 ScopedPendingSignalsDisabler scoped_pending_signals_disabler(state->thread);
188 #else
189 // TODO(b/346604197): Enable on arm64 once guest_os_primitives is ported.
190 TRACE("ScopedPendingSignalsDisabler is not available on this arch");
191 #endif
192 ScopedErrno scoped_errno;
193
194 long guest_nr = state->cpu.x[A7];
195 if (kInstrumentSyscalls) {
196 OnSyscall(state, guest_nr);
197 }
198
199 // RISCV Linux takes arguments in a0-a5 and syscall number in a7.
200 // TODO(b/161722184): if syscall is interrupted by signal, signal handler might overwrite the
201 // return value, so setting A0 here might be incorrect. Investigate!
202 long result = RunGuestSyscallImpl(guest_nr,
203 state->cpu.x[A0],
204 state->cpu.x[A1],
205 state->cpu.x[A2],
206 state->cpu.x[A3],
207 state->cpu.x[A4],
208 state->cpu.x[A5]);
209 if (result == -1) {
210 state->cpu.x[A0] = -errno;
211 } else {
212 state->cpu.x[A0] = result;
213 }
214
215 if (kInstrumentSyscalls) {
216 OnSyscallReturn(state, guest_nr);
217 }
218 }
219
220 } // namespace berberis
221