Serenity Operating System
1/*
2 * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2022, Rummskartoffel <Rummskartoffel@protonmail.com>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include "Emulator.h"
9#include "MmapRegion.h"
10#include "SimpleRegion.h"
11#include "SoftCPU.h"
12#include <AK/Debug.h>
13#include <AK/Format.h>
14#include <Kernel/API/SyscallString.h>
15#include <alloca.h>
16#include <fcntl.h>
17#include <sched.h>
18#include <serenity.h>
19#include <strings.h>
20#include <sys/ioctl.h>
21#include <sys/mman.h>
22#include <sys/poll.h>
23#include <sys/socket.h>
24#include <sys/stat.h>
25#include <sys/time.h>
26#include <sys/uio.h>
27#include <sys/utsname.h>
28#include <syscall.h>
29#include <termios.h>
30
31#if defined(AK_COMPILER_GCC)
32# pragma GCC optimize("O3")
33#endif
34
35namespace UserspaceEmulator {
36
37u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3)
38{
39 if constexpr (SPAM_DEBUG)
40 reportln("Syscall: {} ({:x})"sv, Syscall::to_string((Syscall::Function)function), function);
41 switch (function) {
42 case SC_accept4:
43 return virt$accept4(arg1);
44 case SC_allocate_tls:
45 return virt$allocate_tls(arg1, arg2);
46 case SC_anon_create:
47 return virt$anon_create(arg1, arg2);
48 case SC_annotate_mapping:
49 return virt$annotate_mapping(arg1);
50 case SC_beep:
51 return virt$beep();
52 case SC_bind:
53 return virt$bind(arg1, arg2, arg3);
54 case SC_chdir:
55 return virt$chdir(arg1, arg2);
56 case SC_chmod:
57 return virt$chmod(arg1);
58 case SC_chown:
59 return virt$chown(arg1);
60 case SC_clock_gettime:
61 return virt$clock_gettime(arg1, arg2);
62 case SC_clock_nanosleep:
63 return virt$clock_nanosleep(arg1);
64 case SC_clock_settime:
65 return virt$clock_settime(arg1, arg2);
66 case SC_close:
67 return virt$close(arg1);
68 case SC_connect:
69 return virt$connect(arg1, arg2, arg3);
70 case SC_create_inode_watcher:
71 return virt$create_inode_watcher(arg1);
72 case SC_dbgputstr:
73 return virt$dbgputstr(arg1, arg2);
74 case SC_disown:
75 return virt$disown(arg1);
76 case SC_dup2:
77 return virt$dup2(arg1, arg2);
78 case SC_emuctl:
79 return virt$emuctl(arg1, arg2, arg3);
80 case SC_execve:
81 return virt$execve(arg1);
82 case SC_exit:
83 virt$exit((int)arg1);
84 return 0;
85 case SC_faccessat:
86 return virt$faccessat(arg1);
87 case SC_fchmod:
88 return virt$fchmod(arg1, arg2);
89 case SC_fchown:
90 return virt$fchown(arg1, arg2, arg3);
91 case SC_fcntl:
92 return virt$fcntl(arg1, arg2, arg3);
93 case SC_fork:
94 return virt$fork();
95 case SC_fstat:
96 return virt$fstat(arg1, arg2);
97 case SC_ftruncate:
98 return virt$ftruncate(arg1, arg2);
99 case SC_futex:
100 return virt$futex(arg1);
101 case SC_get_dir_entries:
102 return virt$get_dir_entries(arg1, arg2, arg3);
103 case SC_get_process_name:
104 return virt$get_process_name(arg1, arg2);
105 case SC_get_stack_bounds:
106 return virt$get_stack_bounds(arg1, arg2);
107 case SC_getcwd:
108 return virt$getcwd(arg1, arg2);
109 case SC_getegid:
110 return virt$getegid();
111 case SC_geteuid:
112 return virt$geteuid();
113 case SC_getgid:
114 return virt$getgid();
115 case SC_getgroups:
116 return virt$getgroups(arg1, arg2);
117 case SC_gethostname:
118 return virt$gethostname(arg1, arg2);
119 case SC_getpeername:
120 return virt$getpeername(arg1);
121 case SC_getpgid:
122 return virt$getpgid(arg1);
123 case SC_getpgrp:
124 return virt$getpgrp();
125 case SC_getpid:
126 return virt$getpid();
127 case SC_getppid:
128 return virt$getppid();
129 case SC_getrandom:
130 return virt$getrandom(arg1, arg2, arg3);
131 case SC_getsid:
132 return virt$getsid(arg1);
133 case SC_getsockname:
134 return virt$getsockname(arg1);
135 case SC_getsockopt:
136 return virt$getsockopt(arg1);
137 case SC_gettid:
138 return virt$gettid();
139 case SC_getuid:
140 return virt$getuid();
141 case SC_inode_watcher_add_watch:
142 return virt$inode_watcher_add_watch(arg1);
143 case SC_inode_watcher_remove_watch:
144 return virt$inode_watcher_remove_watch(arg1, arg2);
145 case SC_ioctl:
146 return virt$ioctl(arg1, arg2, arg3);
147 case SC_kill:
148 return virt$kill(arg1, arg2);
149 case SC_killpg:
150 return virt$killpg(arg1, arg2);
151 case SC_listen:
152 return virt$listen(arg1, arg2);
153 case SC_lseek:
154 return virt$lseek(arg1, arg2, arg3);
155 case SC_madvise:
156 return virt$madvise(arg1, arg2, arg3);
157 case SC_map_time_page:
158 return -ENOSYS;
159 case SC_mkdir:
160 return virt$mkdir(arg1, arg2, arg3);
161 case SC_mmap:
162 return virt$mmap(arg1);
163 case SC_mount:
164 return virt$mount(arg1);
165 case SC_mprotect:
166 return virt$mprotect(arg1, arg2, arg3);
167 case SC_mremap:
168 return virt$mremap(arg1);
169 case SC_munmap:
170 return virt$munmap(arg1, arg2);
171 case SC_open:
172 return virt$open(arg1);
173 case SC_perf_event:
174 return virt$perf_event((int)arg1, arg2, arg3);
175 case SC_perf_register_string:
176 return virt$perf_register_string(arg1, arg2);
177 case SC_pipe:
178 return virt$pipe(arg1, arg2);
179 case SC_pledge:
180 return virt$pledge(arg1);
181 case SC_poll:
182 return virt$poll(arg1);
183 case SC_profiling_disable:
184 return virt$profiling_disable(arg1);
185 case SC_profiling_enable:
186 return virt$profiling_enable(arg1);
187 case SC_purge:
188 return virt$purge(arg1);
189 case SC_read:
190 return virt$read(arg1, arg2, arg3);
191 case SC_readlink:
192 return virt$readlink(arg1);
193 case SC_realpath:
194 return virt$realpath(arg1);
195 case SC_recvfd:
196 return virt$recvfd(arg1, arg2);
197 case SC_recvmsg:
198 return virt$recvmsg(arg1, arg2, arg3);
199 case SC_rename:
200 return virt$rename(arg1);
201 case SC_rmdir:
202 return virt$rmdir(arg1, arg2);
203 case SC_scheduler_get_parameters:
204 return virt$scheduler_get_parameters(arg1);
205 case SC_scheduler_set_parameters:
206 return virt$scheduler_set_parameters(arg1);
207 case SC_sendfd:
208 return virt$sendfd(arg1, arg2);
209 case SC_sendmsg:
210 return virt$sendmsg(arg1, arg2, arg3);
211 case SC_set_mmap_name:
212 return virt$set_mmap_name(arg1);
213 case SC_set_process_name:
214 return virt$set_process_name(arg1, arg2);
215 case SC_set_thread_name:
216 return virt$set_thread_name(arg1, arg2, arg3);
217 case SC_setgid:
218 return virt$setgid(arg2);
219 case SC_setgroups:
220 return virt$setgroups(arg1, arg2);
221 case SC_setpgid:
222 return virt$setpgid(arg1, arg2);
223 case SC_setsid:
224 return virt$setsid();
225 case SC_setsockopt:
226 return virt$setsockopt(arg1);
227 case SC_setuid:
228 return virt$setuid(arg1);
229 case SC_shutdown:
230 return virt$shutdown(arg1, arg2);
231 case SC_sigaction:
232 return virt$sigaction(arg1, arg2, arg3);
233 case SC_sigprocmask:
234 return virt$sigprocmask(arg1, arg2, arg3);
235 case SC_sigreturn:
236 return virt$sigreturn();
237 case SC_socket:
238 return virt$socket(arg1, arg2, arg3);
239 case SC_stat:
240 return virt$stat(arg1);
241 case SC_symlink:
242 return virt$symlink(arg1);
243 case SC_sync:
244 virt$sync();
245 return 0;
246 case SC_sysconf:
247 return virt$sysconf(arg1);
248 case SC_umask:
249 return virt$umask(arg1);
250 case SC_uname:
251 return virt$uname(arg1);
252 case SC_unlink:
253 return virt$unlink(arg1, arg2);
254 case SC_unveil:
255 return virt$unveil(arg1);
256 case SC_waitid:
257 return virt$waitid(arg1);
258 case SC_write:
259 return virt$write(arg1, arg2, arg3);
260 default:
261 reportln("\n=={}== \033[31;1mUnimplemented syscall: {}\033[0m, {:p}"sv, getpid(), Syscall::to_string((Syscall::Function)function), function);
262 dump_backtrace();
263 TODO();
264 }
265}
266
267int Emulator::virt$anon_create(size_t size, int options)
268{
269 return syscall(SC_anon_create, size, options);
270}
271
272int Emulator::virt$sendfd(int socket, int fd)
273{
274 return syscall(SC_sendfd, socket, fd);
275}
276
277int Emulator::virt$recvfd(int socket, int options)
278{
279 return syscall(SC_recvfd, socket, options);
280}
281
282int Emulator::virt$profiling_enable(pid_t pid)
283{
284 return syscall(SC_profiling_enable, pid);
285}
286
287int Emulator::virt$profiling_disable(pid_t pid)
288{
289 return syscall(SC_profiling_disable, pid);
290}
291
292FlatPtr Emulator::virt$perf_event(int event, FlatPtr arg1, FlatPtr arg2)
293{
294 if (event == PERF_EVENT_SIGNPOST) {
295 if (is_profiling()) {
296 if (profiler_string_id_map().size() > arg1)
297 emit_profile_event(profile_stream(), "signpost"sv, DeprecatedString::formatted("\"arg1\": {}, \"arg2\": {}", arg1, arg2));
298 syscall(SC_perf_event, PERF_EVENT_SIGNPOST, profiler_string_id_map().at(arg1), arg2);
299 } else {
300 syscall(SC_perf_event, PERF_EVENT_SIGNPOST, arg1, arg2);
301 }
302 return 0;
303 }
304 return -ENOSYS;
305}
306
307FlatPtr Emulator::virt$perf_register_string(FlatPtr string, size_t size)
308{
309 char* buffer = (char*)alloca(size + 4);
310 // FIXME: not nice, but works
311 __builtin_memcpy(buffer, "UE: ", 4);
312 mmu().copy_from_vm((buffer + 4), string, size);
313 auto ret = (int)syscall(SC_perf_register_string, buffer, size + 4);
314
315 if (ret >= 0 && is_profiling()) {
316 profiler_strings().append(make<DeprecatedString>(StringView { buffer + 4, size }));
317 profiler_string_id_map().append(ret);
318 ret = profiler_string_id_map().size() - 1;
319 }
320 return ret;
321}
322
323int Emulator::virt$disown(pid_t pid)
324{
325 return syscall(SC_disown, pid);
326}
327
328int Emulator::virt$purge(int mode)
329{
330 return syscall(SC_purge, mode);
331}
332
333int Emulator::virt$fstat(int fd, FlatPtr statbuf)
334{
335 struct stat local_statbuf;
336 int rc = syscall(SC_fstat, fd, &local_statbuf);
337 if (rc < 0)
338 return rc;
339 mmu().copy_to_vm(statbuf, &local_statbuf, sizeof(local_statbuf));
340 return rc;
341}
342
343int Emulator::virt$close(int fd)
344{
345 return syscall(SC_close, fd);
346}
347
348int Emulator::virt$mkdir(FlatPtr path, size_t path_length, mode_t mode)
349{
350 auto buffer = mmu().copy_buffer_from_vm(path, path_length);
351 return syscall(SC_mkdir, buffer.data(), buffer.size(), mode);
352}
353
354int Emulator::virt$rmdir(FlatPtr path, size_t path_length)
355{
356 auto buffer = mmu().copy_buffer_from_vm(path, path_length);
357 return syscall(SC_rmdir, buffer.data(), buffer.size());
358}
359
360int Emulator::virt$unlink(FlatPtr path, size_t path_length)
361{
362 auto buffer = mmu().copy_buffer_from_vm(path, path_length);
363 return syscall(SC_unlink, AT_FDCWD, buffer.data(), buffer.size(), 0);
364}
365
366int Emulator::virt$symlink(FlatPtr params_addr)
367{
368 Syscall::SC_symlink_params params;
369 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
370
371 auto target = mmu().copy_buffer_from_vm((FlatPtr)params.target.characters, params.target.length);
372 params.target.characters = (char const*)target.data();
373 params.target.length = target.size();
374
375 auto link = mmu().copy_buffer_from_vm((FlatPtr)params.linkpath.characters, params.linkpath.length);
376 params.linkpath.characters = (char const*)link.data();
377 params.linkpath.length = link.size();
378
379 return syscall(SC_symlink, ¶ms);
380}
381
382int Emulator::virt$rename(FlatPtr params_addr)
383{
384 Syscall::SC_rename_params params;
385 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
386
387 auto new_path = mmu().copy_buffer_from_vm((FlatPtr)params.new_path.characters, params.new_path.length);
388 params.new_path.characters = (char const*)new_path.data();
389 params.new_path.length = new_path.size();
390
391 auto old_path = mmu().copy_buffer_from_vm((FlatPtr)params.old_path.characters, params.old_path.length);
392 params.old_path.characters = (char const*)old_path.data();
393 params.old_path.length = old_path.size();
394
395 return syscall(SC_rename, ¶ms);
396}
397
398int Emulator::virt$dbgputstr(FlatPtr characters, int length)
399{
400 auto buffer = mmu().copy_buffer_from_vm(characters, length);
401 dbgputstr((char const*)buffer.data(), buffer.size());
402 return 0;
403}
404
405int Emulator::virt$chmod(FlatPtr params_addr)
406{
407 Syscall::SC_chmod_params params;
408 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
409
410 auto path = mmu().copy_buffer_from_vm((FlatPtr)params.path.characters, params.path.length);
411 params.path.characters = (char const*)path.data();
412 params.path.length = path.size();
413 return syscall(SC_chmod, ¶ms);
414}
415
416int Emulator::virt$chown(FlatPtr params_addr)
417{
418 Syscall::SC_chown_params params;
419 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
420
421 auto path = mmu().copy_buffer_from_vm((FlatPtr)params.path.characters, params.path.length);
422 params.path.characters = (char const*)path.data();
423 params.path.length = path.size();
424
425 return syscall(SC_chown, ¶ms);
426}
427
428int Emulator::virt$fchmod(int fd, mode_t mode)
429{
430 return syscall(SC_fchmod, fd, mode);
431}
432
433int Emulator::virt$fchown(int fd, uid_t uid, gid_t gid)
434{
435 return syscall(SC_fchown, fd, uid, gid);
436}
437
438int Emulator::virt$setsockopt(FlatPtr params_addr)
439{
440 Syscall::SC_setsockopt_params params;
441 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
442
443 if (params.option == SO_RCVTIMEO || params.option == SO_TIMESTAMP) {
444 auto host_value_buffer_result = ByteBuffer::create_zeroed(params.value_size);
445 if (host_value_buffer_result.is_error())
446 return -ENOMEM;
447 auto& host_value_buffer = host_value_buffer_result.value();
448 mmu().copy_from_vm(host_value_buffer.data(), (FlatPtr)params.value, params.value_size);
449 int rc = setsockopt(params.sockfd, params.level, params.option, host_value_buffer.data(), host_value_buffer.size());
450 if (rc < 0)
451 return -errno;
452 return rc;
453 }
454
455 if (params.option == SO_BINDTODEVICE) {
456 auto ifname = mmu().copy_buffer_from_vm((FlatPtr)params.value, params.value_size);
457 params.value = ifname.data();
458 params.value_size = ifname.size();
459 return syscall(SC_setsockopt, ¶ms);
460 }
461
462 TODO();
463}
464
465int Emulator::virt$get_stack_bounds(FlatPtr base, FlatPtr size)
466{
467 auto* region = mmu().find_region({ m_cpu->ss(), m_cpu->esp().value() });
468 FlatPtr b = region->base();
469 size_t s = region->size();
470 mmu().copy_to_vm(base, &b, sizeof(b));
471 mmu().copy_to_vm(size, &s, sizeof(s));
472 return 0;
473}
474
475int Emulator::virt$ftruncate(int fd, FlatPtr length_addr)
476{
477 off_t length;
478 mmu().copy_from_vm(&length, length_addr, sizeof(off_t));
479 return syscall(SC_ftruncate, fd, &length);
480}
481
482int Emulator::virt$uname(FlatPtr params_addr)
483{
484 struct utsname local_uname;
485 auto rc = syscall(SC_uname, &local_uname);
486 mmu().copy_to_vm(params_addr, &local_uname, sizeof(local_uname));
487 return rc;
488}
489
490mode_t Emulator::virt$umask(mode_t mask)
491{
492 return syscall(SC_umask, mask);
493}
494
495int Emulator::virt$accept4(FlatPtr params_addr)
496{
497 Syscall::SC_accept4_params params;
498 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
499 sockaddr_storage addr = {};
500 socklen_t addrlen;
501 mmu().copy_from_vm(&addrlen, (FlatPtr)params.addrlen, sizeof(socklen_t));
502 VERIFY(addrlen <= sizeof(addr));
503 int rc = accept4(params.sockfd, (sockaddr*)&addr, &addrlen, params.flags);
504 if (rc == 0) {
505 mmu().copy_to_vm((FlatPtr)params.addr, &addr, addrlen);
506 mmu().copy_to_vm((FlatPtr)params.addrlen, &addrlen, sizeof(socklen_t));
507 }
508 return rc < 0 ? -errno : rc;
509}
510
511int Emulator::virt$bind(int sockfd, FlatPtr address, socklen_t address_length)
512{
513 auto buffer = mmu().copy_buffer_from_vm(address, address_length);
514 return syscall(SC_bind, sockfd, buffer.data(), buffer.size());
515}
516
517int Emulator::virt$connect(int sockfd, FlatPtr address, socklen_t address_size)
518{
519 auto buffer = mmu().copy_buffer_from_vm(address, address_size);
520 return syscall(SC_connect, sockfd, buffer.data(), buffer.size());
521}
522
523int Emulator::virt$shutdown(int sockfd, int how)
524{
525 return syscall(SC_shutdown, sockfd, how);
526}
527
528int Emulator::virt$listen(int fd, int backlog)
529{
530 return syscall(SC_listen, fd, backlog);
531}
532
533int Emulator::virt$kill(pid_t pid, int signal)
534{
535 return syscall(SC_kill, pid, signal);
536}
537
538int Emulator::virt$killpg(int pgrp, int sig)
539{
540 return syscall(SC_killpg, pgrp, sig);
541}
542
543int Emulator::virt$clock_gettime(int clockid, FlatPtr timespec)
544{
545 struct timespec host_timespec;
546 int rc = syscall(SC_clock_gettime, clockid, &host_timespec);
547 if (rc < 0)
548 return rc;
549 mmu().copy_to_vm(timespec, &host_timespec, sizeof(host_timespec));
550 return rc;
551}
552
553int Emulator::virt$clock_settime(uint32_t clock_id, FlatPtr user_ts)
554{
555 struct timespec user_timespec;
556 mmu().copy_from_vm(&user_timespec, user_ts, sizeof(user_timespec));
557 int rc = syscall(SC_clock_settime, clock_id, &user_timespec);
558 return rc;
559}
560
561int Emulator::virt$set_mmap_name(FlatPtr params_addr)
562{
563 Syscall::SC_set_mmap_name_params params {};
564 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
565 auto name = mmu().copy_buffer_from_vm((FlatPtr)params.name.characters, params.name.length);
566
567 auto* region = mmu().find_region({ 0x23, (FlatPtr)params.addr });
568 if (!region || !is<MmapRegion>(*region))
569 return -EINVAL;
570 static_cast<MmapRegion&>(*region).set_name(DeprecatedString::copy(name));
571 return 0;
572}
573
574int Emulator::virt$get_process_name(FlatPtr buffer, int size)
575{
576 if (size < 0)
577 return -EINVAL;
578 auto host_buffer_result = ByteBuffer::create_zeroed((size_t)size);
579 if (host_buffer_result.is_error())
580 return -ENOMEM;
581 auto& host_buffer = host_buffer_result.value();
582 int rc = syscall(SC_get_process_name, host_buffer.data(), host_buffer.size());
583 mmu().copy_to_vm(buffer, host_buffer.data(), host_buffer.size());
584 return rc;
585}
586
587int Emulator::virt$set_process_name(FlatPtr user_buffer, int size)
588{
589 if (size < 0)
590 return -EINVAL;
591 auto host_buffer = mmu().copy_buffer_from_vm(user_buffer, size);
592 auto name = DeprecatedString::formatted("(UE) {}", StringView { host_buffer.data(), host_buffer.size() });
593 return syscall(SC_set_process_name, name.characters(), name.length());
594}
595
596int Emulator::virt$lseek(int fd, FlatPtr offset_addr, int whence)
597{
598 off_t offset;
599 mmu().copy_from_vm(&offset, offset_addr, sizeof(off_t));
600 auto rc = syscall(SC_lseek, fd, &offset, whence);
601 mmu().copy_to_vm(offset_addr, &offset, sizeof(off_t));
602 return rc;
603}
604
605int Emulator::virt$socket(int domain, int type, int protocol)
606{
607 return syscall(SC_socket, domain, type, protocol);
608}
609
610int Emulator::virt$recvmsg(int sockfd, FlatPtr msg_addr, int flags)
611{
612 msghdr mmu_msg;
613 mmu().copy_from_vm(&mmu_msg, msg_addr, sizeof(mmu_msg));
614
615 Vector<iovec, 1> mmu_iovs;
616 mmu_iovs.resize(mmu_msg.msg_iovlen);
617 mmu().copy_from_vm(mmu_iovs.data(), (FlatPtr)mmu_msg.msg_iov, mmu_msg.msg_iovlen * sizeof(iovec));
618 Vector<ByteBuffer, 1> buffers;
619 Vector<iovec, 1> iovs;
620 for (auto const& iov : mmu_iovs) {
621 auto buffer_result = ByteBuffer::create_uninitialized(iov.iov_len);
622 if (buffer_result.is_error())
623 return -ENOMEM;
624 buffers.append(buffer_result.release_value());
625 iovs.append({ buffers.last().data(), buffers.last().size() });
626 }
627
628 ByteBuffer control_buffer;
629 if (mmu_msg.msg_control) {
630 auto buffer_result = ByteBuffer::create_uninitialized(mmu_msg.msg_controllen);
631 if (buffer_result.is_error())
632 return -ENOMEM;
633 control_buffer = buffer_result.release_value();
634 }
635
636 sockaddr_storage addr;
637 msghdr msg = { &addr, sizeof(addr), iovs.data(), (int)iovs.size(), mmu_msg.msg_control ? control_buffer.data() : nullptr, mmu_msg.msg_controllen, mmu_msg.msg_flags };
638 int rc = recvmsg(sockfd, &msg, flags);
639 if (rc < 0)
640 return -errno;
641
642 for (size_t i = 0; i < buffers.size(); ++i)
643 mmu().copy_to_vm((FlatPtr)mmu_iovs[i].iov_base, buffers[i].data(), mmu_iovs[i].iov_len);
644
645 if (mmu_msg.msg_name)
646 mmu().copy_to_vm((FlatPtr)mmu_msg.msg_name, &addr, min(sizeof(addr), (size_t)mmu_msg.msg_namelen));
647 if (mmu_msg.msg_control)
648 mmu().copy_to_vm((FlatPtr)mmu_msg.msg_control, control_buffer.data(), min(mmu_msg.msg_controllen, msg.msg_controllen));
649 mmu_msg.msg_namelen = msg.msg_namelen;
650 mmu_msg.msg_controllen = msg.msg_controllen;
651 mmu_msg.msg_flags = msg.msg_flags;
652 mmu().copy_to_vm(msg_addr, &mmu_msg, sizeof(mmu_msg));
653 return rc;
654}
655
656int Emulator::virt$sendmsg(int sockfd, FlatPtr msg_addr, int flags)
657{
658 msghdr mmu_msg;
659 mmu().copy_from_vm(&mmu_msg, msg_addr, sizeof(mmu_msg));
660
661 Vector<iovec, 1> iovs;
662 iovs.resize(mmu_msg.msg_iovlen);
663 mmu().copy_from_vm(iovs.data(), (FlatPtr)mmu_msg.msg_iov, mmu_msg.msg_iovlen * sizeof(iovec));
664 Vector<ByteBuffer, 1> buffers;
665 for (auto& iov : iovs) {
666 buffers.append(mmu().copy_buffer_from_vm((FlatPtr)iov.iov_base, iov.iov_len));
667 iov = { buffers.last().data(), buffers.last().size() };
668 }
669
670 ByteBuffer control_buffer;
671 if (mmu_msg.msg_control) {
672 auto buffer_result = ByteBuffer::create_uninitialized(mmu_msg.msg_controllen);
673 if (buffer_result.is_error())
674 return -ENOMEM;
675 control_buffer = buffer_result.release_value();
676 }
677
678 sockaddr_storage address;
679 socklen_t address_length = 0;
680 if (mmu_msg.msg_name) {
681 address_length = min(sizeof(address), (size_t)mmu_msg.msg_namelen);
682 mmu().copy_from_vm(&address, (FlatPtr)mmu_msg.msg_name, address_length);
683 }
684
685 msghdr msg = { mmu_msg.msg_name ? &address : nullptr, address_length, iovs.data(), (int)iovs.size(), mmu_msg.msg_control ? control_buffer.data() : nullptr, mmu_msg.msg_controllen, mmu_msg.msg_flags };
686 return sendmsg(sockfd, &msg, flags);
687}
688
689int Emulator::virt$getsockopt(FlatPtr params_addr)
690{
691 Syscall::SC_getsockopt_params params;
692 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
693
694 if (params.option == SO_PEERCRED) {
695 struct ucred creds = {};
696 socklen_t creds_size = sizeof(creds);
697 int rc = getsockopt(params.sockfd, params.level, SO_PEERCRED, &creds, &creds_size);
698 if (rc < 0)
699 return -errno;
700 // FIXME: Check params.value_size
701 mmu().copy_to_vm((FlatPtr)params.value, &creds, sizeof(creds));
702 return rc;
703 }
704 if (params.option == SO_ERROR) {
705 int so_error;
706 socklen_t so_error_len = sizeof(so_error);
707 int rc = getsockopt(params.sockfd, params.level, SO_ERROR, &so_error, &so_error_len);
708 if (rc < 0)
709 return -errno;
710 // FIXME: Check params.value_size
711 mmu().copy_to_vm((FlatPtr)params.value, &so_error, sizeof(so_error));
712 return rc;
713 }
714
715 dbgln("Not implemented socket param: {}", params.option);
716 TODO();
717}
718
719int Emulator::virt$getsockname(FlatPtr params_addr)
720{
721 Syscall::SC_getsockname_params params;
722 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
723 sockaddr_storage addr = {};
724 socklen_t addrlen;
725 mmu().copy_from_vm(&addrlen, (FlatPtr)params.addrlen, sizeof(socklen_t));
726 VERIFY(addrlen <= sizeof(addr));
727 auto rc = getsockname(params.sockfd, (sockaddr*)&addr, &addrlen);
728 if (rc == 0) {
729 mmu().copy_to_vm((FlatPtr)params.addr, &addr, sizeof(addr));
730 mmu().copy_to_vm((FlatPtr)params.addrlen, &addrlen, sizeof(addrlen));
731 }
732 return rc < 0 ? -errno : rc;
733}
734
735int Emulator::virt$getpeername(FlatPtr params_addr)
736{
737 Syscall::SC_getpeername_params params;
738 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
739 sockaddr_storage addr = {};
740 socklen_t addrlen;
741 mmu().copy_from_vm(&addrlen, (FlatPtr)params.addrlen, sizeof(socklen_t));
742 VERIFY(addrlen <= sizeof(addr));
743 auto rc = getpeername(params.sockfd, (sockaddr*)&addr, &addrlen);
744 if (rc == 0) {
745 mmu().copy_to_vm((FlatPtr)params.addr, &addr, sizeof(addr));
746 mmu().copy_to_vm((FlatPtr)params.addrlen, &addrlen, sizeof(addrlen));
747 }
748 return rc < 0 ? -errno : rc;
749}
750
751int Emulator::virt$getgroups(ssize_t count, FlatPtr groups)
752{
753 if (!count)
754 return syscall(SC_getgroups, 0, nullptr);
755
756 auto buffer_result = ByteBuffer::create_uninitialized(count * sizeof(gid_t));
757 if (buffer_result.is_error())
758 return -ENOMEM;
759 auto& buffer = buffer_result.value();
760 int rc = syscall(SC_getgroups, count, buffer.data());
761 if (rc < 0)
762 return rc;
763 mmu().copy_to_vm(groups, buffer.data(), buffer.size());
764 return 0;
765}
766
767int Emulator::virt$setgroups(ssize_t count, FlatPtr groups)
768{
769 if (!count)
770 return syscall(SC_setgroups, 0, nullptr);
771
772 auto buffer = mmu().copy_buffer_from_vm(groups, count * sizeof(gid_t));
773 return syscall(SC_setgroups, count, buffer.data());
774}
775
776u32 Emulator::virt$fcntl(int fd, int cmd, u32 arg)
777{
778 switch (cmd) {
779 case F_DUPFD:
780 case F_GETFD:
781 case F_SETFD:
782 case F_GETFL:
783 case F_SETFL:
784 case F_ISTTY:
785 break;
786 default:
787 dbgln("Invalid fcntl cmd: {}", cmd);
788 }
789
790 return syscall(SC_fcntl, fd, cmd, arg);
791}
792
793u32 Emulator::virt$open(u32 params_addr)
794{
795 Syscall::SC_open_params params;
796 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
797
798 auto path = mmu().copy_buffer_from_vm((FlatPtr)params.path.characters, params.path.length);
799
800 Syscall::SC_open_params host_params {};
801 host_params.dirfd = params.dirfd;
802 host_params.mode = params.mode;
803 host_params.options = params.options;
804 host_params.path.characters = (char const*)path.data();
805 host_params.path.length = path.size();
806
807 return syscall(SC_open, &host_params);
808}
809
810int Emulator::virt$pipe(FlatPtr vm_pipefd, int flags)
811{
812 int pipefd[2];
813 int rc = syscall(SC_pipe, pipefd, flags);
814 if (rc < 0)
815 return rc;
816 mmu().copy_to_vm(vm_pipefd, pipefd, sizeof(pipefd));
817 return rc;
818}
819
820static void round_to_page_size(FlatPtr& address, size_t& size)
821{
822 auto new_end = round_up_to_power_of_two(address + size, PAGE_SIZE);
823 address &= ~(PAGE_SIZE - 1);
824 size = new_end - address;
825}
826
827u32 Emulator::virt$munmap(FlatPtr address, size_t size)
828{
829 if (is_profiling())
830 emit_profile_event(profile_stream(), "munmap"sv, DeprecatedString::formatted("\"ptr\": {}, \"size\": {}", address, size));
831 round_to_page_size(address, size);
832 Vector<Region*, 4> marked_for_deletion;
833 bool has_non_mmap_region = false;
834 mmu().for_regions_in({ 0x23, address }, size, [&](Region* region) {
835 if (region) {
836 if (!is<MmapRegion>(*region)) {
837 has_non_mmap_region = true;
838 return IterationDecision::Break;
839 }
840 marked_for_deletion.append(region);
841 }
842 return IterationDecision::Continue;
843 });
844 if (has_non_mmap_region)
845 return -EINVAL;
846
847 for (Region* region : marked_for_deletion) {
848 m_range_allocator.deallocate(region->range());
849 mmu().remove_region(*region);
850 }
851 return 0;
852}
853
854u32 Emulator::virt$mmap(u32 params_addr)
855{
856 Syscall::SC_mmap_params params;
857 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
858 params.alignment = params.alignment ? params.alignment : PAGE_SIZE;
859
860 if (params.size == 0)
861 return -EINVAL;
862
863 u32 requested_size = round_up_to_power_of_two(params.size, PAGE_SIZE);
864 FlatPtr final_address;
865
866 Optional<Range> result;
867 if (params.flags & MAP_RANDOMIZED) {
868 result = m_range_allocator.allocate_randomized(requested_size, params.alignment);
869 } else if (params.flags & MAP_FIXED || params.flags & MAP_FIXED_NOREPLACE) {
870 if (params.addr) {
871 // If MAP_FIXED is specified, existing mappings that intersect the requested range are removed.
872 if (params.flags & MAP_FIXED)
873 virt$munmap((FlatPtr)params.addr, requested_size);
874 result = m_range_allocator.allocate_specific(VirtualAddress { params.addr }, requested_size);
875 } else {
876 // mmap(nullptr, …, MAP_FIXED) is technically okay, but tends to be a bug.
877 // Therefore, refuse to be helpful.
878 reportln("\n=={}== \033[31;1mTried to mmap at nullptr with MAP_FIXED.\033[0m, {:#x} bytes."sv, getpid(), params.size);
879 dump_backtrace();
880 }
881 } else {
882 result = m_range_allocator.allocate_anywhere(requested_size, params.alignment);
883 }
884 if (!result.has_value())
885 return -ENOMEM;
886 final_address = result.value().base().get();
887 auto final_size = result.value().size();
888
889 DeprecatedString name_str;
890 if (params.name.characters) {
891 auto buffer_result = ByteBuffer::create_uninitialized(params.name.length);
892 if (buffer_result.is_error())
893 return -ENOMEM;
894 auto& name = buffer_result.value();
895 mmu().copy_from_vm(name.data(), (FlatPtr)params.name.characters, params.name.length);
896 name_str = { name.data(), name.size() };
897 }
898
899 if (is_profiling())
900 emit_profile_event(profile_stream(), "mmap"sv, DeprecatedString::formatted(R"("ptr": {}, "size": {}, "name": "{}")", final_address, final_size, name_str));
901
902 if (params.flags & MAP_ANONYMOUS) {
903 mmu().add_region(MmapRegion::create_anonymous(final_address, final_size, params.prot, move(name_str)));
904 } else {
905 auto region = MmapRegion::create_file_backed(final_address, final_size, params.prot, params.flags, params.fd, params.offset, move(name_str));
906 if (region->name() == "libsystem.so: .text" && !m_libsystem_start) {
907 m_libsystem_start = final_address;
908 m_libsystem_end = final_address + final_size;
909 }
910 mmu().add_region(move(region));
911 }
912
913 return final_address;
914}
915
916FlatPtr Emulator::virt$mremap(FlatPtr params_addr)
917{
918 Syscall::SC_mremap_params params;
919 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
920
921 // FIXME: Support regions that have been split in the past (e.g. due to mprotect or munmap).
922 if (auto* region = mmu().find_region({ m_cpu->ds(), (FlatPtr)params.old_address })) {
923 if (!is<MmapRegion>(*region))
924 return -EINVAL;
925 VERIFY(region->size() == params.old_size);
926 auto& mmap_region = *(MmapRegion*)region;
927 auto* ptr = mremap(mmap_region.data(), mmap_region.size(), mmap_region.size(), params.flags);
928 if (ptr == MAP_FAILED)
929 return -errno;
930 return (FlatPtr)ptr;
931 }
932 return -EINVAL;
933}
934
935u32 Emulator::virt$mount(u32 params_addr)
936{
937 Syscall::SC_mount_params params;
938 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
939 auto target = mmu().copy_buffer_from_vm((FlatPtr)params.target.characters, params.target.length);
940 auto fs_path = mmu().copy_buffer_from_vm((FlatPtr)params.fs_type.characters, params.fs_type.length);
941 params.fs_type.characters = (char*)fs_path.data();
942 params.fs_type.length = fs_path.size();
943 params.target.characters = (char*)target.data();
944 params.target.length = target.size();
945
946 return syscall(SC_mount, ¶ms);
947}
948
949u32 Emulator::virt$gettid()
950{
951 return gettid();
952}
953
954u32 Emulator::virt$getpid()
955{
956 return getpid();
957}
958
959pid_t Emulator::virt$getppid()
960{
961 return getppid();
962}
963
964u32 Emulator::virt$pledge(u32)
965{
966 return 0;
967}
968
969u32 Emulator::virt$unveil(u32)
970{
971 return 0;
972}
973
974u32 Emulator::virt$mprotect(FlatPtr base, size_t size, int prot)
975{
976 round_to_page_size(base, size);
977 bool has_non_mmapped_region = false;
978
979 mmu().for_regions_in({ 0x23, base }, size, [&](Region* region) {
980 if (region) {
981 if (!is<MmapRegion>(*region)) {
982 has_non_mmapped_region = true;
983 return IterationDecision::Break;
984 }
985 auto& mmap_region = *(MmapRegion*)region;
986 mmap_region.set_prot(prot);
987 }
988 return IterationDecision::Continue;
989 });
990 if (has_non_mmapped_region)
991 return -EINVAL;
992
993 return 0;
994}
995
996u32 Emulator::virt$madvise(FlatPtr, size_t, int)
997{
998 return 0;
999}
1000
1001uid_t Emulator::virt$getuid()
1002{
1003 return getuid();
1004}
1005
1006uid_t Emulator::virt$geteuid()
1007{
1008 return geteuid();
1009}
1010
1011gid_t Emulator::virt$getgid()
1012{
1013 return getgid();
1014}
1015
1016gid_t Emulator::virt$getegid()
1017{
1018 return getegid();
1019}
1020
1021int Emulator::virt$setuid(uid_t uid)
1022{
1023 return syscall(SC_setuid, uid);
1024}
1025
1026int Emulator::virt$setgid(gid_t gid)
1027{
1028 return syscall(SC_setgid, gid);
1029}
1030
1031u32 Emulator::virt$write(int fd, FlatPtr data, ssize_t size)
1032{
1033 if (size < 0)
1034 return -EINVAL;
1035 auto buffer = mmu().copy_buffer_from_vm(data, size);
1036 return syscall(SC_write, fd, buffer.data(), buffer.size());
1037}
1038
1039u32 Emulator::virt$read(int fd, FlatPtr buffer, ssize_t size)
1040{
1041 if (size < 0)
1042 return -EINVAL;
1043 auto buffer_result = ByteBuffer::create_uninitialized(size);
1044 if (buffer_result.is_error())
1045 return -ENOMEM;
1046 auto& local_buffer = buffer_result.value();
1047 int nread = syscall(SC_read, fd, local_buffer.data(), local_buffer.size());
1048 if (nread < 0) {
1049 if (nread == -EPERM) {
1050 dump_backtrace();
1051 TODO();
1052 }
1053 return nread;
1054 }
1055 mmu().copy_to_vm(buffer, local_buffer.data(), local_buffer.size());
1056 return nread;
1057}
1058
1059void Emulator::virt$sync()
1060{
1061 syscall(SC_sync);
1062}
1063
1064void Emulator::virt$exit(int status)
1065{
1066 reportln("\n=={}== \033[33;1mSyscall: exit({})\033[0m, shutting down!"sv, getpid(), status);
1067 m_exit_status = status;
1068 m_shutdown = true;
1069}
1070
1071ssize_t Emulator::virt$getrandom(FlatPtr buffer, size_t buffer_size, unsigned int flags)
1072{
1073 auto buffer_result = ByteBuffer::create_uninitialized(buffer_size);
1074 if (buffer_result.is_error())
1075 return -ENOMEM;
1076 auto& host_buffer = buffer_result.value();
1077 int rc = syscall(SC_getrandom, host_buffer.data(), host_buffer.size(), flags);
1078 if (rc < 0)
1079 return rc;
1080 mmu().copy_to_vm(buffer, host_buffer.data(), host_buffer.size());
1081 return rc;
1082}
1083
1084int Emulator::virt$get_dir_entries(int fd, FlatPtr buffer, ssize_t size)
1085{
1086 auto buffer_result = ByteBuffer::create_uninitialized(size);
1087 if (buffer_result.is_error())
1088 return -ENOMEM;
1089 auto& host_buffer = buffer_result.value();
1090 int rc = syscall(SC_get_dir_entries, fd, host_buffer.data(), host_buffer.size());
1091 if (rc < 0)
1092 return rc;
1093 mmu().copy_to_vm(buffer, host_buffer.data(), host_buffer.size());
1094 return rc;
1095}
1096
1097int Emulator::virt$ioctl([[maybe_unused]] int fd, unsigned request, [[maybe_unused]] FlatPtr arg)
1098{
1099 switch (request) {
1100 case TIOCGWINSZ: {
1101 struct winsize ws;
1102 int rc = syscall(SC_ioctl, fd, TIOCGWINSZ, &ws);
1103 if (rc < 0)
1104 return rc;
1105 mmu().copy_to_vm(arg, &ws, sizeof(winsize));
1106 return 0;
1107 }
1108 case TIOCSWINSZ: {
1109 struct winsize ws;
1110 mmu().copy_from_vm(&ws, arg, sizeof(winsize));
1111 return syscall(SC_ioctl, fd, request, &ws);
1112 }
1113 case TIOCGPGRP: {
1114 pid_t pgid;
1115 auto rc = syscall(SC_ioctl, fd, request, &pgid);
1116 mmu().copy_to_vm(arg, &pgid, sizeof(pgid));
1117 return rc;
1118 }
1119 case TIOCSPGRP:
1120 return syscall(SC_ioctl, fd, request, arg);
1121 case TCGETS: {
1122 struct termios termios;
1123 int rc = syscall(SC_ioctl, fd, request, &termios);
1124 if (rc < 0)
1125 return rc;
1126 mmu().copy_to_vm(arg, &termios, sizeof(termios));
1127 return rc;
1128 }
1129 case TCSETS:
1130 case TCSETSF:
1131 case TCSETSW: {
1132 struct termios termios;
1133 mmu().copy_from_vm(&termios, arg, sizeof(termios));
1134 return syscall(SC_ioctl, fd, request, &termios);
1135 }
1136 case TCFLSH:
1137 return syscall(SC_ioctl, fd, request, arg);
1138 case TIOCNOTTY:
1139 case TIOCSCTTY:
1140 return syscall(SC_ioctl, fd, request, 0);
1141 case TIOCSTI:
1142 return -EIO;
1143 case GRAPHICS_IOCTL_GET_PROPERTIES: {
1144 size_t size = 0;
1145 auto rc = syscall(SC_ioctl, fd, request, &size);
1146 mmu().copy_to_vm(arg, &size, sizeof(size));
1147 return rc;
1148 }
1149 case GRAPHICS_IOCTL_SET_HEAD_VERTICAL_OFFSET_BUFFER:
1150 return syscall(SC_ioctl, fd, request, arg);
1151 case FIONBIO: {
1152 int enabled;
1153 mmu().copy_from_vm(&enabled, arg, sizeof(int));
1154 return syscall(SC_ioctl, fd, request, &enabled);
1155 }
1156 default:
1157 reportln("Unsupported ioctl: {}"sv, request);
1158 dump_backtrace();
1159 TODO();
1160 }
1161 VERIFY_NOT_REACHED();
1162}
1163
1164int Emulator::virt$emuctl(FlatPtr arg1, FlatPtr arg2, FlatPtr arg3)
1165{
1166 auto* tracer = malloc_tracer();
1167 if (arg1 <= 4 && !tracer)
1168 return 0;
1169 switch (arg1) {
1170 case 1:
1171 tracer->target_did_malloc({}, arg3, arg2);
1172 return 0;
1173 case 2:
1174 tracer->target_did_free({}, arg2);
1175 return 0;
1176 case 3:
1177 tracer->target_did_realloc({}, arg3, arg2);
1178 return 0;
1179 case 4:
1180 tracer->target_did_change_chunk_size({}, arg3, arg2);
1181 return 0;
1182 case 5: // mark ROI start
1183 if (is_in_region_of_interest())
1184 return -EINVAL;
1185 m_is_in_region_of_interest = true;
1186 return 0;
1187 case 6: // mark ROI end
1188 m_is_in_region_of_interest = false;
1189 return 0;
1190 case 7:
1191 m_is_memory_auditing_suppressed = true;
1192 return 0;
1193 case 8:
1194 m_is_memory_auditing_suppressed = false;
1195 return 0;
1196 default:
1197 return -EINVAL;
1198 }
1199}
1200
1201int Emulator::virt$fork()
1202{
1203 int rc = fork();
1204 if (rc < 0)
1205 return -errno;
1206 return rc;
1207}
1208
1209int Emulator::virt$execve(FlatPtr params_addr)
1210{
1211 Syscall::SC_execve_params params;
1212 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
1213
1214 auto path = DeprecatedString::copy(mmu().copy_buffer_from_vm((FlatPtr)params.path.characters, params.path.length));
1215 Vector<DeprecatedString> arguments;
1216 Vector<DeprecatedString> environment;
1217
1218 auto copy_string_list = [this](auto& output_vector, auto& string_list) {
1219 for (size_t i = 0; i < string_list.length; ++i) {
1220 Syscall::StringArgument string;
1221 mmu().copy_from_vm(&string, (FlatPtr)&string_list.strings[i], sizeof(string));
1222 output_vector.append(DeprecatedString::copy(mmu().copy_buffer_from_vm((FlatPtr)string.characters, string.length)));
1223 }
1224 };
1225
1226 copy_string_list(arguments, params.arguments);
1227 copy_string_list(environment, params.environment);
1228
1229 reportln("\n=={}== \033[33;1mSyscall:\033[0m execve"sv, getpid());
1230 reportln("=={}== @ {}"sv, getpid(), path);
1231 for (auto& argument : arguments)
1232 reportln("=={}== - {}"sv, getpid(), argument);
1233
1234 if (access(path.characters(), X_OK) < 0) {
1235 if (errno == ENOENT || errno == EACCES)
1236 return -errno;
1237 }
1238
1239 Vector<char*> argv;
1240 Vector<char*> envp;
1241
1242 argv.append(const_cast<char*>("/bin/UserspaceEmulator"));
1243 if (g_report_to_debug)
1244 argv.append(const_cast<char*>("--report-to-debug"));
1245 argv.append(const_cast<char*>("--"));
1246 argv.append(const_cast<char*>(path.characters()));
1247
1248 auto create_string_vector = [](auto& output_vector, auto& input_vector) {
1249 for (auto& string : input_vector)
1250 output_vector.append(const_cast<char*>(string.characters()));
1251 output_vector.append(nullptr);
1252 };
1253
1254 create_string_vector(argv, arguments);
1255 create_string_vector(envp, environment);
1256
1257 // Yoink duplicated program name.
1258 argv.remove(3 + (g_report_to_debug ? 1 : 0));
1259
1260 return execve(argv[0], (char* const*)argv.data(), (char* const*)envp.data());
1261}
1262
1263int Emulator::virt$stat(FlatPtr params_addr)
1264{
1265 Syscall::SC_stat_params params;
1266 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
1267
1268 auto path = DeprecatedString::copy(mmu().copy_buffer_from_vm((FlatPtr)params.path.characters, params.path.length));
1269 struct stat host_statbuf;
1270 int rc;
1271 if (params.follow_symlinks)
1272 rc = stat(path.characters(), &host_statbuf);
1273 else
1274 rc = lstat(path.characters(), &host_statbuf);
1275 if (rc < 0)
1276 return -errno;
1277 mmu().copy_to_vm((FlatPtr)params.statbuf, &host_statbuf, sizeof(host_statbuf));
1278 return rc;
1279}
1280
1281int Emulator::virt$realpath(FlatPtr params_addr)
1282{
1283 Syscall::SC_realpath_params params;
1284 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
1285
1286 auto path = mmu().copy_buffer_from_vm((FlatPtr)params.path.characters, params.path.length);
1287 auto buffer_result = ByteBuffer::create_zeroed(params.buffer.size);
1288 if (buffer_result.is_error())
1289 return -ENOMEM;
1290 auto& host_buffer = buffer_result.value();
1291
1292 Syscall::SC_realpath_params host_params;
1293 host_params.path = { (char const*)path.data(), path.size() };
1294 host_params.buffer = { (char*)host_buffer.data(), host_buffer.size() };
1295 int rc = syscall(SC_realpath, &host_params);
1296 if (rc < 0)
1297 return rc;
1298 mmu().copy_to_vm((FlatPtr)params.buffer.data, host_buffer.data(), host_buffer.size());
1299 return rc;
1300}
1301
1302int Emulator::virt$gethostname(FlatPtr buffer, ssize_t buffer_size)
1303{
1304 if (buffer_size < 0)
1305 return -EINVAL;
1306 auto buffer_result = ByteBuffer::create_zeroed(buffer_size);
1307 if (buffer_result.is_error())
1308 return -ENOMEM;
1309 auto& host_buffer = buffer_result.value();
1310 int rc = syscall(SC_gethostname, host_buffer.data(), host_buffer.size());
1311 if (rc < 0)
1312 return rc;
1313 mmu().copy_to_vm(buffer, host_buffer.data(), host_buffer.size());
1314 return rc;
1315}
1316
1317int Emulator::virt$sigaction(int signum, FlatPtr act, FlatPtr oldact)
1318{
1319 if (signum == SIGKILL) {
1320 reportln("Attempted to sigaction() with SIGKILL"sv);
1321 return -EINVAL;
1322 }
1323
1324 if (signum <= 0 || signum >= NSIG)
1325 return -EINVAL;
1326
1327 struct sigaction host_act;
1328 mmu().copy_from_vm(&host_act, act, sizeof(host_act));
1329
1330 auto& handler = m_signal_handler[signum];
1331 handler.handler = (FlatPtr)host_act.sa_handler;
1332 handler.mask = host_act.sa_mask;
1333 handler.flags = host_act.sa_flags;
1334
1335 if (oldact) {
1336 struct sigaction host_oldact;
1337 auto& old_handler = m_signal_handler[signum];
1338 host_oldact.sa_handler = (void (*)(int))(old_handler.handler);
1339 host_oldact.sa_mask = old_handler.mask;
1340 host_oldact.sa_flags = old_handler.flags;
1341 mmu().copy_to_vm(oldact, &host_oldact, sizeof(host_oldact));
1342 }
1343 return 0;
1344}
1345
1346int Emulator::virt$sigprocmask(int how, FlatPtr set, FlatPtr old_set)
1347{
1348 if (old_set) {
1349 mmu().copy_to_vm(old_set, &m_signal_mask, sizeof(sigset_t));
1350 }
1351 if (set) {
1352 sigset_t set_value;
1353 mmu().copy_from_vm(&set_value, set, sizeof(sigset_t));
1354 switch (how) {
1355 case SIG_BLOCK:
1356 m_signal_mask |= set_value;
1357 break;
1358 case SIG_SETMASK:
1359 m_signal_mask = set_value;
1360 break;
1361 case SIG_UNBLOCK:
1362 m_signal_mask &= ~set_value;
1363 break;
1364 default:
1365 return -EINVAL;
1366 }
1367 }
1368 return 0;
1369}
1370
1371int Emulator::virt$sigreturn()
1372{
1373 u32 stack_ptr = m_cpu->esp().value();
1374 auto local_pop = [&]<typename T>() {
1375 auto value = m_cpu->read_memory<T>({ m_cpu->ss(), stack_ptr });
1376 stack_ptr += sizeof(T);
1377 return value;
1378 };
1379
1380 // State from signal trampoline (note that we're assuming i386 here):
1381 // saved_ax, ucontext, signal_info, fpu_state.
1382
1383 // Drop the FPU state
1384 // FIXME: Read and restore from this.
1385 stack_ptr += 512;
1386
1387 // Drop the signal info
1388 stack_ptr += sizeof(siginfo_t);
1389
1390 auto ucontext = local_pop.operator()<ucontext_t>();
1391
1392 auto eax = local_pop.operator()<u32>();
1393
1394 m_signal_mask = ucontext.value().uc_sigmask;
1395
1396 auto mcontext_slice = ucontext.slice<&ucontext_t::uc_mcontext>();
1397
1398 m_cpu->set_edi(mcontext_slice.slice<&__mcontext::edi>());
1399 m_cpu->set_esi(mcontext_slice.slice<&__mcontext::esi>());
1400 m_cpu->set_ebp(mcontext_slice.slice<&__mcontext::ebp>());
1401 m_cpu->set_esp(mcontext_slice.slice<&__mcontext::esp>());
1402 m_cpu->set_ebx(mcontext_slice.slice<&__mcontext::ebx>());
1403 m_cpu->set_edx(mcontext_slice.slice<&__mcontext::edx>());
1404 m_cpu->set_ecx(mcontext_slice.slice<&__mcontext::ecx>());
1405 m_cpu->set_eax(mcontext_slice.slice<&__mcontext::eax>());
1406 m_cpu->set_eip(mcontext_slice.value().eip);
1407 m_cpu->set_eflags(mcontext_slice.slice<&__mcontext::eflags>());
1408
1409 // FIXME: We're dropping the shadow bits here.
1410 return eax.value();
1411}
1412
1413int Emulator::virt$getpgrp()
1414{
1415 return syscall(SC_getpgrp);
1416}
1417
1418int Emulator::virt$getpgid(pid_t pid)
1419{
1420 return syscall(SC_getpgid, pid);
1421}
1422
1423int Emulator::virt$setpgid(pid_t pid, pid_t pgid)
1424{
1425 return syscall(SC_setpgid, pid, pgid);
1426}
1427
1428int Emulator::virt$getcwd(FlatPtr buffer, size_t buffer_size)
1429{
1430 auto buffer_result = ByteBuffer::create_zeroed(buffer_size);
1431 if (buffer_result.is_error())
1432 return -ENOMEM;
1433 auto& host_buffer = buffer_result.value();
1434 int rc = syscall(SC_getcwd, host_buffer.data(), host_buffer.size());
1435 if (rc < 0)
1436 return rc;
1437 mmu().copy_to_vm(buffer, host_buffer.data(), host_buffer.size());
1438 return rc;
1439}
1440
1441int Emulator::virt$getsid(pid_t pid)
1442{
1443 return syscall(SC_getsid, pid);
1444}
1445
1446int Emulator::virt$faccessat(FlatPtr params_addr)
1447{
1448 Syscall::SC_faccessat_params params;
1449 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
1450
1451 auto host_path = mmu().copy_buffer_from_vm(reinterpret_cast<FlatPtr>(params.pathname.characters), params.pathname.length);
1452 Syscall::SC_faccessat_params host_params = params;
1453 host_params.pathname = { reinterpret_cast<char const*>(host_path.data()), host_path.size() };
1454
1455 return syscall(SC_faccessat, &host_params);
1456}
1457
1458int Emulator::virt$waitid(FlatPtr params_addr)
1459{
1460 Syscall::SC_waitid_params params;
1461 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
1462
1463 Syscall::SC_waitid_params host_params = params;
1464 siginfo info {};
1465 host_params.infop = &info;
1466
1467 int rc = syscall(SC_waitid, &host_params);
1468 if (rc < 0)
1469 return rc;
1470
1471 if (info.si_addr) {
1472 // FIXME: Translate this somehow once we actually start setting it in the kernel.
1473 dbgln("si_addr is set to {:p}, I did not expect this!", info.si_addr);
1474 TODO();
1475 }
1476
1477 if (params.infop)
1478 mmu().copy_to_vm((FlatPtr)params.infop, &info, sizeof(info));
1479
1480 return rc;
1481}
1482
1483int Emulator::virt$chdir(FlatPtr path, size_t path_length)
1484{
1485 auto host_path = mmu().copy_buffer_from_vm(path, path_length);
1486 return syscall(SC_chdir, host_path.data(), host_path.size());
1487}
1488
1489int Emulator::virt$dup2(int old_fd, int new_fd)
1490{
1491 return syscall(SC_dup2, old_fd, new_fd);
1492}
1493
1494int Emulator::virt$scheduler_get_parameters(FlatPtr user_addr)
1495{
1496 Syscall::SC_scheduler_parameters_params user_param;
1497 mmu().copy_from_vm(&user_param, user_addr, sizeof(user_param));
1498 auto rc = syscall(SC_scheduler_get_parameters, &user_param);
1499 mmu().copy_to_vm(user_addr, &user_param, sizeof(user_param));
1500 return rc;
1501}
1502
1503int Emulator::virt$scheduler_set_parameters(FlatPtr user_addr)
1504{
1505 Syscall::SC_scheduler_parameters_params user_param;
1506 mmu().copy_from_vm(&user_param, user_addr, sizeof(user_param));
1507 return syscall(SC_scheduler_set_parameters, &user_param);
1508}
1509
1510int Emulator::virt$set_thread_name(pid_t pid, FlatPtr name_addr, size_t name_length)
1511{
1512 auto user_name = mmu().copy_buffer_from_vm(name_addr, name_length);
1513 auto name = DeprecatedString::formatted("(UE) {}", StringView { user_name.data(), user_name.size() });
1514 return syscall(SC_set_thread_name, pid, name.characters(), name.length());
1515}
1516
1517pid_t Emulator::virt$setsid()
1518{
1519 return syscall(SC_setsid);
1520}
1521
1522int Emulator::virt$create_inode_watcher(unsigned flags)
1523{
1524 return syscall(SC_create_inode_watcher, flags);
1525}
1526
1527int Emulator::virt$inode_watcher_add_watch(FlatPtr params_addr)
1528{
1529 Syscall::SC_inode_watcher_add_watch_params params;
1530 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
1531 return syscall(SC_inode_watcher_add_watch, ¶ms);
1532}
1533
1534int Emulator::virt$inode_watcher_remove_watch(int fd, int wd)
1535{
1536 return syscall(SC_inode_watcher_add_watch, fd, wd);
1537}
1538
1539int Emulator::virt$clock_nanosleep(FlatPtr params_addr)
1540{
1541 Syscall::SC_clock_nanosleep_params params;
1542 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
1543
1544 timespec requested_sleep;
1545 mmu().copy_from_vm(&requested_sleep, (FlatPtr)params.requested_sleep, sizeof(timespec));
1546 params.requested_sleep = &requested_sleep;
1547
1548 auto* remaining_vm_addr = params.remaining_sleep;
1549 timespec remaining { 0, 0 };
1550 params.remaining_sleep = &remaining;
1551
1552 int rc = syscall(SC_clock_nanosleep, ¶ms);
1553 if (remaining_vm_addr)
1554 mmu().copy_to_vm((FlatPtr)remaining_vm_addr, &remaining, sizeof(timespec));
1555
1556 return rc;
1557}
1558
1559int Emulator::virt$readlink(FlatPtr params_addr)
1560{
1561 Syscall::SC_readlink_params params;
1562 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
1563
1564 auto path = mmu().copy_buffer_from_vm((FlatPtr)params.path.characters, params.path.length);
1565 auto buffer_result = ByteBuffer::create_zeroed(params.buffer.size);
1566 if (buffer_result.is_error())
1567 return -ENOMEM;
1568 auto& host_buffer = buffer_result.value();
1569
1570 Syscall::SC_readlink_params host_params;
1571 host_params.path = { (char const*)path.data(), path.size() };
1572 host_params.buffer = { (char*)host_buffer.data(), host_buffer.size() };
1573 int rc = syscall(SC_readlink, &host_params);
1574 if (rc < 0)
1575 return rc;
1576 mmu().copy_to_vm((FlatPtr)params.buffer.data, host_buffer.data(), host_buffer.size());
1577 return rc;
1578}
1579
1580u32 Emulator::virt$allocate_tls(FlatPtr initial_data, size_t size)
1581{
1582 // TODO: This matches what Thread::make_thread_specific_region does. The kernel
1583 // ends up allocating one more page. Figure out if this is intentional.
1584 auto region_size = align_up_to(size, PAGE_SIZE) + PAGE_SIZE;
1585 constexpr auto tls_location = VirtualAddress(0x20000000);
1586 m_range_allocator.reserve_user_range(tls_location, region_size);
1587 auto tcb_region = make<SimpleRegion>(tls_location.get(), region_size);
1588
1589 size_t offset = 0;
1590 while (size - offset > 0) {
1591 u8 buffer[512];
1592 size_t read_bytes = min(sizeof(buffer), size - offset);
1593 mmu().copy_from_vm(buffer, initial_data + offset, read_bytes);
1594 memcpy(tcb_region->data() + offset, buffer, read_bytes);
1595 offset += read_bytes;
1596 }
1597 memset(tcb_region->shadow_data(), 0x01, size);
1598
1599 auto tls_region = make<SimpleRegion>(0, 4);
1600 tls_region->write32(0, shadow_wrap_as_initialized(tcb_region->base() + (u32)size));
1601 memset(tls_region->shadow_data(), 0x01, 4);
1602
1603 u32 tls_base = tcb_region->base();
1604 mmu().add_region(move(tcb_region));
1605 mmu().set_tls_region(move(tls_region));
1606 return tls_base;
1607}
1608
1609int Emulator::virt$beep()
1610{
1611 return syscall(SC_beep);
1612}
1613
1614u32 Emulator::virt$sysconf(u32 name)
1615{
1616 return syscall(SC_sysconf, name);
1617}
1618
1619int Emulator::virt$annotate_mapping(FlatPtr)
1620{
1621 // FIXME: Implement this.
1622 return 0;
1623}
1624
1625int Emulator::virt$futex(FlatPtr params_addr)
1626{
1627 Syscall::SC_futex_params params;
1628 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
1629
1630 // FIXME: Implement this.
1631 return 0;
1632}
1633
1634int Emulator::virt$poll(FlatPtr params_addr)
1635{
1636 Syscall::SC_poll_params params;
1637 mmu().copy_from_vm(¶ms, params_addr, sizeof(params));
1638
1639 if (params.nfds >= FD_SETSIZE)
1640 return EINVAL;
1641
1642 Vector<pollfd, FD_SETSIZE> fds;
1643 struct timespec timeout;
1644 u32 sigmask;
1645
1646 if (params.fds)
1647 mmu().copy_from_vm(fds.data(), (FlatPtr)params.fds, sizeof(pollfd) * params.nfds);
1648 if (params.timeout)
1649 mmu().copy_from_vm(&timeout, (FlatPtr)params.timeout, sizeof(timeout));
1650 if (params.sigmask)
1651 mmu().copy_from_vm(&sigmask, (FlatPtr)params.sigmask, sizeof(sigmask));
1652
1653 int rc = ppoll(params.fds ? fds.data() : nullptr, params.nfds, params.timeout ? &timeout : nullptr, params.sigmask ? &sigmask : nullptr);
1654 if (rc < 0)
1655 return -errno;
1656
1657 if (params.fds)
1658 mmu().copy_to_vm((FlatPtr)params.fds, fds.data(), sizeof(pollfd) * params.nfds);
1659 if (params.timeout)
1660 mmu().copy_to_vm((FlatPtr)params.timeout, &timeout, sizeof(timeout));
1661
1662 return rc;
1663}
1664}