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