linux.c (27648B)
1 #include <string.h> 2 3 #include "core/slice.h" 4 #include "emu/emu.h" 5 #include "obj/format.h" 6 7 #define LINUX_SYS_openat 56u 8 #define LINUX_SYS_close 57u 9 #define LINUX_SYS_lseek 62u 10 #define LINUX_SYS_read 63u 11 #define LINUX_SYS_write 64u 12 #define LINUX_SYS_readv 65u 13 #define LINUX_SYS_writev 66u 14 #define LINUX_SYS_fstat 80u 15 #define LINUX_SYS_exit 93u 16 #define LINUX_SYS_exit_group 94u 17 #define LINUX_SYS_set_tid_address 96u 18 #define LINUX_SYS_clock_gettime 113u 19 #define LINUX_SYS_sched_yield 124u 20 #define LINUX_SYS_rt_sigaction 134u 21 #define LINUX_SYS_rt_sigprocmask 135u 22 #define LINUX_SYS_rt_sigreturn 139u 23 #define LINUX_SYS_getpid 172u 24 #define LINUX_SYS_getuid 174u 25 #define LINUX_SYS_geteuid 175u 26 #define LINUX_SYS_getgid 176u 27 #define LINUX_SYS_getegid 177u 28 #define LINUX_SYS_brk 214u 29 #define LINUX_SYS_mmap 222u 30 #define LINUX_SYS_mprotect 226u 31 #define LINUX_SYS_munmap 215u 32 33 #define LINUX_PROT_READ 1u 34 #define LINUX_PROT_WRITE 2u 35 #define LINUX_PROT_EXEC 4u 36 37 #define LINUX_MAP_PRIVATE 0x02u 38 #define LINUX_MAP_FIXED 0x10u 39 #define LINUX_MAP_ANONYMOUS 0x20u 40 #define LINUX_MAP_FIXED_NOREPLACE 0x100000u 41 42 #define LINUX_EBADF 9 43 #define LINUX_EFAULT 14 44 #define LINUX_EINVAL 22 45 #define LINUX_ENOSYS 38 46 #define LINUX_ENOMEM 12 47 #define LINUX_EEXIST 17 48 49 #define EMU_LINUX_SIGFRAME_MAGIC 0x53494746524d3031ull 50 #define EMU_LINUX_SIGFRAME_SIZE 512u 51 #define EMU_LINUX_SIGFRAME_SAVED_PC 8u 52 #define EMU_LINUX_SIGFRAME_SIGINFO 32u 53 #define EMU_LINUX_SIGFRAME_UCONTEXT 64u 54 #define EMU_LINUX_SIGFRAME_XREGS 128u 55 #define EMU_LINUX_STACK_SIZE (1u * 1024u * 1024u) 56 #define EMU_LINUX_BRK_RESERVE (2u * 1024u * 1024u) 57 #define EMU_LINUX_INITIAL_MMAP_HINT 0x4000000000ull 58 59 typedef struct LinuxSignalAction { 60 u64 handler; 61 u64 flags; 62 u64 restorer; 63 int installed; 64 } LinuxSignalAction; 65 66 typedef struct LinuxProcessState { 67 u64 mmap_hint; 68 LinuxSignalAction signal_actions[64]; 69 } LinuxProcessState; 70 71 typedef struct LinuxThreadState { 72 u64 signal_mask; 73 u64 signal_frame_sp; 74 EmuTlsBlocks tls_blocks; 75 } LinuxThreadState; 76 77 static u64 linux_round_up(u64 v, u64 a) { return (v + a - 1u) & ~(a - 1u); } 78 79 static LinuxProcessState* linux_process_state(EmuProcess* process) { 80 return process ? (LinuxProcessState*)process->os_private : NULL; 81 } 82 83 static LinuxThreadState* linux_thread_state(EmuThread* thread) { 84 return thread ? (LinuxThreadState*)thread->os_private : NULL; 85 } 86 87 static u64 linux_rd64(const u8* p) { 88 return (u64)p[0] | ((u64)p[1] << 8) | ((u64)p[2] << 16) | ((u64)p[3] << 24) | 89 ((u64)p[4] << 32) | ((u64)p[5] << 40) | ((u64)p[6] << 48) | 90 ((u64)p[7] << 56); 91 } 92 93 static void linux_wr64(u8* p, u64 v) { 94 u32 i; 95 for (i = 0; i < 8u; ++i) p[i] = (u8)(v >> (8u * i)); 96 } 97 98 static void linux_free_stack_lists(Heap* heap, u64* argv_addrs, int argc, 99 u64* envp_addrs, int envc) { 100 if (argv_addrs) heap->free(heap, argv_addrs, sizeof(u64) * (size_t)argc); 101 if (envp_addrs) heap->free(heap, envp_addrs, sizeof(u64) * (size_t)envc); 102 } 103 104 static u8 linux_emu_perms(u64 prot) { 105 u8 perms = 0; 106 if (prot & LINUX_PROT_READ) perms |= EMU_MEM_READ; 107 if (prot & LINUX_PROT_WRITE) perms |= EMU_MEM_WRITE; 108 if (prot & LINUX_PROT_EXEC) perms |= EMU_MEM_EXEC; 109 return perms; 110 } 111 112 static KitStatus linux_find_map_region(EmuProcess* process, u64 nbytes, 113 u64 align, u32 purpose, u64* out) { 114 EmuAddrSpace* as; 115 LinuxProcessState* ps; 116 u64 max_va = 0x0000800000000000ull; 117 u64 min_va; 118 if (!process || !out) return KIT_INVALID; 119 ps = linux_process_state(process); 120 if (!ps) return KIT_INVALID; 121 as = &process->image.addr_space; 122 min_va = ps->mmap_hint; 123 if (purpose == EMU_OS_MAP_TLS && min_va < 0x7000000000ull) 124 min_va = 0x7000000000ull; 125 return emu_addr_space_find_gap(as, nbytes, align ? align : as->page_size, 126 min_va, max_va, out); 127 } 128 129 static void linux_note_map_region(EmuProcess* process, u64 base, u64 nbytes, 130 u32 purpose) { 131 LinuxProcessState* ps; 132 u64 page_size; 133 (void)purpose; 134 if (!process || !nbytes) return; 135 ps = linux_process_state(process); 136 if (!ps) return; 137 page_size = process->image.addr_space.page_size 138 ? process->image.addr_space.page_size 139 : 0x1000u; 140 ps->mmap_hint = linux_round_up(base + nbytes, page_size); 141 } 142 143 static KitStatus linux_init_process_private(Compiler* c, EmuProcess* process) { 144 LinuxProcessState* ps; 145 KitStatus st; 146 if (!c || !process) return KIT_INVALID; 147 st = emu_process_os_alloc(c, process, sizeof(LinuxProcessState), 148 _Alignof(LinuxProcessState)); 149 if (st != KIT_OK) return st; 150 ps = linux_process_state(process); 151 ps->mmap_hint = EMU_LINUX_INITIAL_MMAP_HINT; 152 return KIT_OK; 153 } 154 155 static void linux_destroy_process_private(Compiler* c, EmuProcess* process) { 156 if (!c || !process) return; 157 emu_process_os_free(c, process, sizeof(LinuxProcessState)); 158 } 159 160 static KitStatus linux_init_thread_private(Compiler* c, EmuProcess* process, 161 EmuThread* thread) { 162 (void)process; 163 if (!c || !thread) return KIT_INVALID; 164 return emu_thread_os_alloc(c, thread, sizeof(LinuxThreadState), 165 _Alignof(LinuxThreadState)); 166 } 167 168 static void linux_destroy_thread_private(Compiler* c, EmuThread* thread) { 169 LinuxThreadState* ts; 170 if (!c || !thread) return; 171 ts = linux_thread_state(thread); 172 if (ts) emu_tls_destroy_blocks(c, &ts->tls_blocks); 173 emu_thread_os_free(c, thread, sizeof(LinuxThreadState)); 174 } 175 176 static KitStatus linux_init_process(Compiler* c, EmuProcess* process, 177 const EmuLoadOptions* opts, 178 const EmuLoadedImage* image) { 179 EmuLoadedImage* img; 180 EmuLoadedObject* main_obj; 181 Heap* heap; 182 u64 image_end; 183 u64 brk_start; 184 u64 stack_guard_base; 185 u64 stack_base; 186 u64 stack_top; 187 u64 cursor; 188 u64 at_random_va; 189 u64 table_bytes; 190 u64 sp; 191 u64* argv_addrs = NULL; 192 u64* envp_addrs = NULL; 193 int argc = 0; 194 int envc = 0; 195 const char* const* p; 196 u32 i; 197 u8* tp; 198 enum { 199 AT_NULL_ = 0, 200 AT_PHDR = 3, 201 AT_PHENT = 4, 202 AT_PHNUM = 5, 203 AT_PAGESZ = 6, 204 AT_ENTRY = 9, 205 AT_RANDOM = 25 206 }; 207 struct { 208 u64 type; 209 u64 val; 210 } aux[7]; 211 u32 aux_count = sizeof(aux) / sizeof(aux[0]); 212 213 (void)image; 214 if (!c || !process || !opts) return KIT_INVALID; 215 if (!linux_process_state(process)) return KIT_INVALID; 216 img = &process->image; 217 if (!img->link_map.nobjects || 218 img->link_map.main_object >= img->link_map.nobjects) 219 return KIT_INVALID; 220 main_obj = &img->link_map.objects[img->link_map.main_object]; 221 heap = c->ctx->heap; 222 223 image_end = linux_round_up(main_obj->map_end, img->addr_space.page_size); 224 brk_start = image_end; 225 stack_guard_base = brk_start + EMU_LINUX_BRK_RESERVE; 226 stack_base = stack_guard_base + img->addr_space.page_size; 227 stack_top = stack_base + EMU_LINUX_STACK_SIZE; 228 if (emu_addr_space_map(&img->addr_space, stack_guard_base, 229 img->addr_space.page_size, 0, 230 EMU_MAP_GUARD) != KIT_OK || 231 emu_addr_space_map(&img->addr_space, stack_base, EMU_LINUX_STACK_SIZE, 232 EMU_MEM_READ | EMU_MEM_WRITE, EMU_MAP_ANON) != KIT_OK) 233 return KIT_ERR; 234 235 if (opts->argv) { 236 for (p = opts->argv; *p; ++p) ++argc; 237 } 238 if (opts->envp) { 239 for (p = opts->envp; *p; ++p) ++envc; 240 } 241 if (argc > 0) { 242 argv_addrs = (u64*)heap->alloc(heap, sizeof(u64) * (size_t)argc, 8u); 243 if (!argv_addrs) return KIT_ERR; 244 } 245 if (envc > 0) { 246 envp_addrs = (u64*)heap->alloc(heap, sizeof(u64) * (size_t)envc, 8u); 247 if (!envp_addrs) { 248 linux_free_stack_lists(heap, argv_addrs, argc, envp_addrs, envc); 249 return KIT_ERR; 250 } 251 } 252 253 cursor = stack_top; 254 for (i = 0; i < (u32)argc; ++i) { 255 size_t slen = slice_from_cstr(opts->argv[i]).len + 1u; 256 cursor -= slen; 257 if (emu_addr_space_copy_in(&img->addr_space, cursor, opts->argv[i], slen) != 258 KIT_OK) { 259 linux_free_stack_lists(heap, argv_addrs, argc, envp_addrs, envc); 260 return KIT_INVALID; 261 } 262 argv_addrs[i] = cursor; 263 } 264 for (i = 0; i < (u32)envc; ++i) { 265 size_t slen = slice_from_cstr(opts->envp[i]).len + 1u; 266 cursor -= slen; 267 if (emu_addr_space_copy_in(&img->addr_space, cursor, opts->envp[i], slen) != 268 KIT_OK) { 269 linux_free_stack_lists(heap, argv_addrs, argc, envp_addrs, envc); 270 return KIT_INVALID; 271 } 272 envp_addrs[i] = cursor; 273 } 274 cursor -= 16u; 275 { 276 u8 random[16]; 277 for (i = 0; i < 16u; ++i) random[i] = (u8)(0xa5u ^ i); 278 if (emu_addr_space_copy_in(&img->addr_space, cursor, random, 16u) != 279 KIT_OK) { 280 linux_free_stack_lists(heap, argv_addrs, argc, envp_addrs, envc); 281 return KIT_INVALID; 282 } 283 } 284 at_random_va = cursor; 285 cursor &= ~(u64)0xfu; 286 287 aux[0].type = AT_PHDR; 288 aux[0].val = img->process_info.headers_vaddr; 289 aux[1].type = AT_PHENT; 290 aux[1].val = img->process_info.header_entry_size; 291 aux[2].type = AT_PHNUM; 292 aux[2].val = img->process_info.header_count; 293 aux[3].type = AT_PAGESZ; 294 aux[3].val = img->addr_space.page_size; 295 aux[4].type = AT_ENTRY; 296 aux[4].val = img->entry_pc; 297 aux[5].type = AT_RANDOM; 298 aux[5].val = at_random_va; 299 aux[6].type = AT_NULL_; 300 aux[6].val = 0; 301 302 table_bytes = 303 8u + (u64)(argc + 1) * 8u + (u64)(envc + 1) * 8u + (u64)aux_count * 16u; 304 sp = (cursor - table_bytes) & ~(u64)0xfu; 305 tp = emu_addr_space_ptr(&img->addr_space, sp, table_bytes, EMU_MEM_WRITE); 306 if (!tp) { 307 linux_free_stack_lists(heap, argv_addrs, argc, envp_addrs, envc); 308 return KIT_INVALID; 309 } 310 linux_wr64(tp, (u64)argc); 311 tp += 8u; 312 for (i = 0; i < (u32)argc; ++i) { 313 linux_wr64(tp, argv_addrs[i]); 314 tp += 8u; 315 } 316 linux_wr64(tp, 0); 317 tp += 8u; 318 for (i = 0; i < (u32)envc; ++i) { 319 linux_wr64(tp, envp_addrs[i]); 320 tp += 8u; 321 } 322 linux_wr64(tp, 0); 323 tp += 8u; 324 for (i = 0; i < aux_count; ++i) { 325 linux_wr64(tp, aux[i].type); 326 tp += 8u; 327 linux_wr64(tp, aux[i].val); 328 tp += 8u; 329 } 330 linux_free_stack_lists(heap, argv_addrs, argc, envp_addrs, envc); 331 332 img->addr_space.brk_base = brk_start; 333 img->addr_space.brk_cur = brk_start; 334 img->addr_space.brk_max = brk_start + EMU_LINUX_BRK_RESERVE; 335 linux_note_map_region(process, stack_base, EMU_LINUX_STACK_SIZE, 336 EMU_OS_MAP_MMAP); 337 img->initial_sp = sp; 338 if (emu_dl_init_process(c, process) != KIT_OK) return KIT_ERR; 339 if (!process->obj_format || !process->obj_format->emu || 340 emu_dl_load_dependencies_and_relocate(c, process, opts, 341 process->obj_format->emu) != KIT_OK) 342 return KIT_ERR; 343 return KIT_OK; 344 } 345 346 static KitStatus linux_init_thread(Compiler* c, EmuProcess* process, 347 EmuThread* thread) { 348 LinuxThreadState* ts; 349 u32 i; 350 if (!c || !process || !thread || !thread->cpu) return KIT_INVALID; 351 ts = linux_thread_state(thread); 352 if (!ts) return KIT_INVALID; 353 if (!process->arch || !process->arch->emu || !process->arch->emu->set_tp) 354 return KIT_UNSUPPORTED; 355 for (i = 0; i < process->tls_state.nmodules; ++i) { 356 EmuTlsModule* m = &process->tls_state.modules[i]; 357 u64 page_size = process->image.addr_space.page_size 358 ? process->image.addr_space.page_size 359 : 0x1000u; 360 u64 nbytes = linux_round_up(m->memsz ? m->memsz : m->filesz, page_size); 361 u64 base = 0; 362 if (!nbytes) continue; 363 if (!process->os || !process->os->emu || 364 !process->os->emu->find_map_region || 365 process->os->emu->find_map_region(process, nbytes, page_size, 366 EMU_OS_MAP_TLS, &base) != KIT_OK) 367 return KIT_ERR; 368 if (emu_addr_space_map(&process->image.addr_space, base, nbytes, 369 EMU_MEM_READ | EMU_MEM_WRITE, 370 EMU_MAP_ANON) != KIT_OK) 371 return KIT_ERR; 372 if (process->os->emu->note_map_region) 373 process->os->emu->note_map_region(process, base, nbytes, EMU_OS_MAP_TLS); 374 if (emu_tls_copy_module_image(process, m, base) != KIT_OK) return KIT_ERR; 375 if (emu_tls_blocks_add(c, &ts->tls_blocks, m->module_id, base, m->memsz) != 376 KIT_OK) 377 return KIT_NOMEM; 378 if (m->module_id == 1u) process->arch->emu->set_tp(thread, base); 379 } 380 return KIT_OK; 381 } 382 383 static KitStatus linux_deliver_signal(EmuProcess* process, EmuThread* thread, 384 int signo, u64 fault_addr, u64 fault_pc, 385 u64 next_pc, u64* next_pc_out) { 386 EmuCPUState* cpu = emu_thread_cpu(thread); 387 LinuxProcessState* ps; 388 LinuxThreadState* ts; 389 LinuxSignalAction* act; 390 u64 sp; 391 u64 frame_sp; 392 u64 frame_size; 393 u64 ctx_size; 394 u64 stack_align; 395 u8* frame; 396 if (!process || !thread || !cpu || !next_pc_out) return KIT_INVALID; 397 ps = linux_process_state(process); 398 ts = linux_thread_state(thread); 399 if (!ps || !ts) return KIT_INVALID; 400 if (signo <= 0 || signo >= 64) { 401 emu_cpu_trap_fault(cpu); 402 *next_pc_out = fault_pc ? fault_pc : next_pc; 403 return KIT_OK; 404 } 405 act = &ps->signal_actions[signo]; 406 if (ts->signal_mask & (1ull << (u32)signo)) { 407 emu_cpu_trap_fault(cpu); 408 *next_pc_out = fault_pc ? fault_pc : next_pc; 409 return KIT_OK; 410 } 411 if (!act->installed || !act->handler) { 412 emu_cpu_trap_fault(cpu); 413 *next_pc_out = fault_pc ? fault_pc : next_pc; 414 return KIT_OK; 415 } 416 if (!process->arch || !process->arch->emu || !process->arch->emu->get_sp || 417 !process->arch->emu->set_sp || !process->arch->emu->signal_context_size || 418 !process->arch->emu->save_signal_context || 419 !process->arch->emu->set_signal_handler_args || 420 !process->arch->emu->signal_stack_align) 421 return KIT_UNSUPPORTED; 422 sp = process->arch->emu->get_sp(thread); 423 ctx_size = process->arch->emu->signal_context_size(process, thread); 424 stack_align = process->arch->emu->signal_stack_align(process, thread); 425 if (!ctx_size || !stack_align || (stack_align & (stack_align - 1u)) != 0) 426 return KIT_UNSUPPORTED; 427 frame_size = EMU_LINUX_SIGFRAME_XREGS + ctx_size; 428 if (frame_size < EMU_LINUX_SIGFRAME_SIZE) 429 frame_size = EMU_LINUX_SIGFRAME_SIZE; 430 frame_size = linux_round_up(frame_size, stack_align); 431 frame_sp = (sp - frame_size) & ~(stack_align - 1u); 432 frame = emu_cpu_va_to_host_perm(cpu, frame_sp, frame_size, EMU_MEM_WRITE); 433 if (!frame) { 434 emu_cpu_trap_fault(cpu); 435 *next_pc_out = fault_pc ? fault_pc : next_pc; 436 return KIT_OK; 437 } 438 memset(frame, 0, (size_t)frame_size); 439 linux_wr64(frame, EMU_LINUX_SIGFRAME_MAGIC); 440 linux_wr64(frame + EMU_LINUX_SIGFRAME_SAVED_PC, fault_pc); 441 linux_wr64(frame + EMU_LINUX_SIGFRAME_SIGINFO, (u64)signo); 442 linux_wr64(frame + EMU_LINUX_SIGFRAME_SIGINFO + 16u, fault_addr); 443 if (process->arch->emu->save_signal_context(process, thread, 444 frame + EMU_LINUX_SIGFRAME_XREGS, 445 ctx_size) != KIT_OK) 446 return KIT_ERR; 447 ts->signal_frame_sp = frame_sp; 448 process->arch->emu->set_sp(thread, frame_sp); 449 if (process->arch->emu->set_signal_handler_args( 450 process, thread, signo, frame_sp + EMU_LINUX_SIGFRAME_SIGINFO, 451 frame_sp + EMU_LINUX_SIGFRAME_UCONTEXT) != KIT_OK) 452 return KIT_ERR; 453 emu_cpu_clear_trap(cpu); 454 emu_cpu_set_pc(cpu, act->handler); 455 *next_pc_out = act->handler; 456 return KIT_OK; 457 } 458 459 static KitStatus linux_deliver_fault(EmuProcess* process, EmuThread* thread, 460 const EmuFaultEvent* ev, 461 u64* next_pc_out) { 462 if (!ev) return KIT_INVALID; 463 return linux_deliver_signal(process, thread, 11, ev->addr, ev->pc, 464 ev->next_pc, next_pc_out); 465 } 466 467 static KitStatus linux_decode_syscall(EmuProcess* process, EmuThread* thread, 468 EmuSyscallRequest* out) { 469 u32 i; 470 if (!process || !thread || !thread->cpu || !out) return KIT_INVALID; 471 if (!process->arch || !process->arch->emu || 472 !process->arch->emu->get_syscall_no || 473 !process->arch->emu->get_syscall_arg) 474 return KIT_UNSUPPORTED; 475 memset(out, 0, sizeof(*out)); 476 out->number = process->arch->emu->get_syscall_no(thread); 477 for (i = 0; i < 6u; ++i) 478 out->args[i] = process->arch->emu->get_syscall_arg(thread, i); 479 return KIT_OK; 480 } 481 482 static KitStatus linux_encode_syscall_result(EmuProcess* process, 483 EmuThread* thread, 484 const EmuSyscallResult* r) { 485 (void)process; 486 if (!process || !thread || !thread->cpu || !r) return KIT_INVALID; 487 if (!process->arch || !process->arch->emu || 488 !process->arch->emu->set_syscall_result) 489 return KIT_UNSUPPORTED; 490 process->arch->emu->set_syscall_result(thread, (u64)r->result); 491 return KIT_OK; 492 } 493 494 static KitStatus linux_default_syscall(void* user, EmuProcess* process, 495 EmuThread* thread, 496 const EmuSyscallRequest* req, 497 EmuSyscallResult* out) { 498 EmuCPUState* s; 499 u64 nr; 500 u64 a0, a1, a2; 501 u64 a3, a4, a5; 502 i64 ret = -LINUX_ENOSYS; 503 (void)user; 504 if (!process || !thread || !thread->cpu || !req || !out) return KIT_INVALID; 505 s = thread->cpu; 506 nr = req->number; 507 a0 = req->args[0]; 508 a1 = req->args[1]; 509 a2 = req->args[2]; 510 a3 = req->args[3]; 511 a4 = req->args[4]; 512 a5 = req->args[5]; 513 memset(out, 0, sizeof(*out)); 514 515 switch (nr) { 516 case LINUX_SYS_exit: 517 case LINUX_SYS_exit_group: 518 emu_cpu_trap_exit(s, (int)(i32)a0); 519 return KIT_OK; 520 case LINUX_SYS_write: { 521 u8* p = emu_cpu_va_to_host_perm(s, a1, a2, EMU_MEM_READ); 522 ret = p ? (i64)a2 : -LINUX_EFAULT; 523 break; 524 } 525 case LINUX_SYS_read: 526 ret = a0 == 0u ? 0 : -LINUX_EBADF; 527 break; 528 case LINUX_SYS_close: 529 ret = 0; 530 break; 531 case LINUX_SYS_brk: { 532 u64 actual = 0; 533 (void)emu_addr_space_set_brk(&process->image.addr_space, a0, &actual); 534 ret = (i64)actual; 535 break; 536 } 537 case LINUX_SYS_mmap: { 538 EmuAddrSpace* as = &process->image.addr_space; 539 LinuxProcessState* ps = linux_process_state(process); 540 u64 addr = a0; 541 u64 length = linux_round_up(a1, as->page_size); 542 u64 flags = a3; 543 u64 fd = a4; 544 u64 off = a5; 545 u64 map_at = 0; 546 KitStatus st; 547 if (!ps) { 548 ret = -LINUX_EINVAL; 549 break; 550 } 551 if (!length || (off & (as->page_size - 1u)) != 0) { 552 ret = -LINUX_EINVAL; 553 break; 554 } 555 if (!(flags & LINUX_MAP_ANONYMOUS)) { 556 ret = -LINUX_ENOSYS; 557 break; 558 } 559 if (!(flags & LINUX_MAP_PRIVATE)) { 560 ret = -LINUX_EINVAL; 561 break; 562 } 563 if ((flags & LINUX_MAP_ANONYMOUS) && (i64)fd != -1 && fd != 0) { 564 ret = -LINUX_EBADF; 565 break; 566 } 567 if (flags & (LINUX_MAP_FIXED | LINUX_MAP_FIXED_NOREPLACE)) { 568 if ((addr & (as->page_size - 1u)) != 0) { 569 ret = -LINUX_EINVAL; 570 break; 571 } 572 map_at = addr; 573 if (flags & LINUX_MAP_FIXED_NOREPLACE) { 574 st = emu_addr_space_map( 575 as, map_at, length, linux_emu_perms(a2), 576 linux_emu_perms(a2) ? EMU_MAP_ANON : EMU_MAP_GUARD); 577 if (st == KIT_OK) { 578 if (process->os && process->os->emu && 579 process->os->emu->note_map_region) 580 process->os->emu->note_map_region(process, map_at, length, 581 EMU_OS_MAP_MMAP); 582 ret = (i64)map_at; 583 } else { 584 ret = -LINUX_EEXIST; 585 } 586 break; 587 } 588 (void)emu_addr_space_unmap(as, map_at, length); 589 } else { 590 u64 min_va = addr ? linux_round_up(addr, as->page_size) : ps->mmap_hint; 591 if (addr) { 592 st = emu_addr_space_find_gap(as, length, as->page_size, min_va, 593 0x0000800000000000ull, &map_at); 594 } else if (process->os && process->os->emu && 595 process->os->emu->find_map_region) { 596 st = process->os->emu->find_map_region(process, length, as->page_size, 597 EMU_OS_MAP_MMAP, &map_at); 598 } else { 599 st = KIT_UNSUPPORTED; 600 } 601 if (st != KIT_OK) { 602 ret = -LINUX_ENOMEM; 603 break; 604 } 605 } 606 st = emu_addr_space_map( 607 as, map_at, length, linux_emu_perms(a2), 608 linux_emu_perms(a2) ? EMU_MAP_ANON : EMU_MAP_GUARD); 609 if (st != KIT_OK) { 610 ret = -LINUX_ENOMEM; 611 } else { 612 if (process->os && process->os->emu && 613 process->os->emu->note_map_region) 614 process->os->emu->note_map_region(process, map_at, length, 615 EMU_OS_MAP_MMAP); 616 ret = (i64)map_at; 617 } 618 break; 619 } 620 case LINUX_SYS_munmap: { 621 EmuAddrSpace* as = &process->image.addr_space; 622 u64 addr = a0; 623 u64 length = linux_round_up(a1, as->page_size); 624 if (!length || (addr & (as->page_size - 1u)) != 0) { 625 ret = -LINUX_EINVAL; 626 } else { 627 (void)emu_addr_space_unmap(as, addr, length); 628 ret = 0; 629 } 630 break; 631 } 632 case LINUX_SYS_mprotect: { 633 EmuAddrSpace* as = &process->image.addr_space; 634 u64 addr = a0; 635 u64 length = linux_round_up(a1, as->page_size); 636 if (!length || (addr & (as->page_size - 1u)) != 0) { 637 ret = -LINUX_EINVAL; 638 } else if (emu_addr_space_protect(as, addr, length, 639 linux_emu_perms(a2)) == KIT_OK) { 640 ret = 0; 641 } else { 642 ret = -LINUX_ENOMEM; 643 } 644 break; 645 } 646 case LINUX_SYS_fstat: { 647 u8* p = emu_cpu_va_to_host_perm(s, a1, 128u, EMU_MEM_WRITE); 648 if (!p) { 649 ret = -LINUX_EFAULT; 650 } else { 651 memset(p, 0, 128u); 652 ret = 0; 653 } 654 break; 655 } 656 case LINUX_SYS_openat: 657 ret = -2; 658 break; 659 case LINUX_SYS_lseek: 660 ret = (i64)a1; 661 break; 662 case LINUX_SYS_readv: { 663 u8* p = emu_cpu_va_to_host_perm(s, a1, a2 * 16u, EMU_MEM_READ); 664 ret = p ? 0 : -LINUX_EFAULT; 665 break; 666 } 667 case LINUX_SYS_writev: { 668 u8* p = emu_cpu_va_to_host_perm(s, a1, a2 * 16u, EMU_MEM_READ); 669 u64 total = 0; 670 u64 i; 671 if (!p) { 672 ret = -LINUX_EFAULT; 673 break; 674 } 675 for (i = 0; i < a2; ++i) { 676 u64 l = 0; 677 u32 j; 678 for (j = 0; j < 8u; ++j) l |= ((u64)p[i * 16u + 8u + j]) << (8u * j); 679 total += l; 680 } 681 ret = (i64)total; 682 break; 683 } 684 case LINUX_SYS_set_tid_address: 685 ret = 1; 686 break; 687 case LINUX_SYS_clock_gettime: { 688 u8* p = emu_cpu_va_to_host_perm(s, a1, 16u, EMU_MEM_WRITE); 689 if (!p) { 690 ret = -LINUX_EFAULT; 691 } else { 692 memset(p, 0, 16u); 693 ret = 0; 694 } 695 break; 696 } 697 case LINUX_SYS_sched_yield: 698 ret = 0; 699 break; 700 case LINUX_SYS_rt_sigaction: 701 if (a0 < 64u && a1) { 702 LinuxProcessState* ps = linux_process_state(process); 703 u8* p = emu_cpu_va_to_host_perm(s, a1, 24u, EMU_MEM_READ); 704 if (!ps) { 705 ret = -LINUX_EINVAL; 706 } else if (!p) { 707 ret = -LINUX_EFAULT; 708 } else { 709 u64 handler = 0, flags = 0, restorer = 0; 710 u32 j; 711 for (j = 0; j < 8u; ++j) handler |= ((u64)p[j]) << (8u * j); 712 for (j = 0; j < 8u; ++j) flags |= ((u64)p[8u + j]) << (8u * j); 713 for (j = 0; j < 8u; ++j) restorer |= ((u64)p[16u + j]) << (8u * j); 714 ps->signal_actions[a0].handler = handler; 715 ps->signal_actions[a0].flags = flags; 716 ps->signal_actions[a0].restorer = restorer; 717 ps->signal_actions[a0].installed = 1; 718 ret = 0; 719 } 720 } else { 721 ret = 0; 722 } 723 break; 724 case LINUX_SYS_rt_sigprocmask: 725 if (a0 == 0u && a1) { 726 LinuxThreadState* ts = linux_thread_state(thread); 727 u8* p = emu_cpu_va_to_host_perm(s, a1, 8u, EMU_MEM_READ); 728 if (!ts) { 729 ret = -LINUX_EINVAL; 730 } else if (!p) { 731 ret = -LINUX_EFAULT; 732 } else { 733 ts->signal_mask |= linux_rd64(p); 734 ret = 0; 735 } 736 } else if (a0 == 1u && a1) { 737 LinuxThreadState* ts = linux_thread_state(thread); 738 u8* p = emu_cpu_va_to_host_perm(s, a1, 8u, EMU_MEM_READ); 739 if (!ts) { 740 ret = -LINUX_EINVAL; 741 } else if (!p) { 742 ret = -LINUX_EFAULT; 743 } else { 744 ts->signal_mask &= ~linux_rd64(p); 745 ret = 0; 746 } 747 } else if (a0 == 2u && a1) { 748 LinuxThreadState* ts = linux_thread_state(thread); 749 u8* p = emu_cpu_va_to_host_perm(s, a1, 8u, EMU_MEM_READ); 750 if (!ts) { 751 ret = -LINUX_EINVAL; 752 } else if (!p) { 753 ret = -LINUX_EFAULT; 754 } else { 755 ts->signal_mask = linux_rd64(p); 756 ret = 0; 757 } 758 } else { 759 ret = 0; 760 } 761 break; 762 case LINUX_SYS_rt_sigreturn: { 763 LinuxThreadState* ts = linux_thread_state(thread); 764 u64 frame_sp; 765 u8* frame; 766 u64 ctx_size; 767 u64 frame_size; 768 if (!process->arch || !process->arch->emu || 769 !process->arch->emu->get_sp || 770 !process->arch->emu->signal_context_size || 771 !process->arch->emu->restore_signal_context) { 772 ret = -LINUX_ENOSYS; 773 break; 774 } 775 if (!ts) { 776 ret = -LINUX_EINVAL; 777 break; 778 } 779 ctx_size = process->arch->emu->signal_context_size(process, thread); 780 frame_size = EMU_LINUX_SIGFRAME_XREGS + ctx_size; 781 frame_sp = ts->signal_frame_sp ? ts->signal_frame_sp 782 : process->arch->emu->get_sp(thread); 783 frame = emu_cpu_va_to_host_perm(s, frame_sp, frame_size, EMU_MEM_READ); 784 if (!frame || linux_rd64(frame) != EMU_LINUX_SIGFRAME_MAGIC) { 785 ret = -LINUX_EFAULT; 786 break; 787 } 788 if (process->arch->emu->restore_signal_context( 789 process, thread, frame + EMU_LINUX_SIGFRAME_XREGS, ctx_size) != 790 KIT_OK) { 791 ret = -LINUX_EFAULT; 792 break; 793 } 794 emu_cpu_set_pc(s, linux_rd64(frame + EMU_LINUX_SIGFRAME_SAVED_PC)); 795 ts->signal_frame_sp = 0; 796 out->flags |= EMU_SYSCALL_RESULT_SKIP_ENCODE; 797 ret = 0; 798 break; 799 } 800 case LINUX_SYS_getpid: 801 case LINUX_SYS_getuid: 802 case LINUX_SYS_geteuid: 803 case LINUX_SYS_getgid: 804 case LINUX_SYS_getegid: 805 ret = 1; 806 break; 807 default: 808 ret = -LINUX_ENOSYS; 809 break; 810 } 811 812 out->result = ret; 813 return KIT_OK; 814 } 815 816 static u64 linux_syscall_next_pc(EmuProcess* process, EmuThread* thread, 817 const EmuSyscallRequest* req, u64 next_pc) { 818 EmuCPUState* s = emu_thread_cpu(thread); 819 (void)process; 820 if (req && req->number == LINUX_SYS_rt_sigreturn && s) return emu_cpu_pc(s); 821 return next_pc; 822 } 823 824 const KitOsEmuOps kit_os_linux_emu_ops = { 825 .init_process_private = linux_init_process_private, 826 .destroy_process_private = linux_destroy_process_private, 827 .init_thread_private = linux_init_thread_private, 828 .destroy_thread_private = linux_destroy_thread_private, 829 .init_process = linux_init_process, 830 .init_thread = linux_init_thread, 831 .decode_syscall = linux_decode_syscall, 832 .encode_syscall_result = linux_encode_syscall_result, 833 .syscall_next_pc = linux_syscall_next_pc, 834 .find_map_region = linux_find_map_region, 835 .note_map_region = linux_note_map_region, 836 .default_syscall = linux_default_syscall, 837 .deliver_fault = linux_deliver_fault, 838 };