linux.c (27592B)
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_find_map_region || 364 process->os->emu_find_map_region(process, nbytes, page_size, 365 EMU_OS_MAP_TLS, &base) != KIT_OK) 366 return KIT_ERR; 367 if (emu_addr_space_map(&process->image.addr_space, base, nbytes, 368 EMU_MEM_READ | EMU_MEM_WRITE, 369 EMU_MAP_ANON) != KIT_OK) 370 return KIT_ERR; 371 if (process->os->emu_note_map_region) 372 process->os->emu_note_map_region(process, base, nbytes, EMU_OS_MAP_TLS); 373 if (emu_tls_copy_module_image(process, m, base) != KIT_OK) return KIT_ERR; 374 if (emu_tls_blocks_add(c, &ts->tls_blocks, m->module_id, base, m->memsz) != 375 KIT_OK) 376 return KIT_NOMEM; 377 if (m->module_id == 1u) process->arch->emu->set_tp(thread, base); 378 } 379 return KIT_OK; 380 } 381 382 static KitStatus linux_deliver_signal(EmuProcess* process, EmuThread* thread, 383 int signo, u64 fault_addr, u64 fault_pc, 384 u64 next_pc, u64* next_pc_out) { 385 EmuCPUState* cpu = emu_thread_cpu(thread); 386 LinuxProcessState* ps; 387 LinuxThreadState* ts; 388 LinuxSignalAction* act; 389 u64 sp; 390 u64 frame_sp; 391 u64 frame_size; 392 u64 ctx_size; 393 u64 stack_align; 394 u8* frame; 395 if (!process || !thread || !cpu || !next_pc_out) return KIT_INVALID; 396 ps = linux_process_state(process); 397 ts = linux_thread_state(thread); 398 if (!ps || !ts) return KIT_INVALID; 399 if (signo <= 0 || signo >= 64) { 400 emu_cpu_trap_fault(cpu); 401 *next_pc_out = fault_pc ? fault_pc : next_pc; 402 return KIT_OK; 403 } 404 act = &ps->signal_actions[signo]; 405 if (ts->signal_mask & (1ull << (u32)signo)) { 406 emu_cpu_trap_fault(cpu); 407 *next_pc_out = fault_pc ? fault_pc : next_pc; 408 return KIT_OK; 409 } 410 if (!act->installed || !act->handler) { 411 emu_cpu_trap_fault(cpu); 412 *next_pc_out = fault_pc ? fault_pc : next_pc; 413 return KIT_OK; 414 } 415 if (!process->arch || !process->arch->emu || !process->arch->emu->get_sp || 416 !process->arch->emu->set_sp || !process->arch->emu->signal_context_size || 417 !process->arch->emu->save_signal_context || 418 !process->arch->emu->set_signal_handler_args || 419 !process->arch->emu->signal_stack_align) 420 return KIT_UNSUPPORTED; 421 sp = process->arch->emu->get_sp(thread); 422 ctx_size = process->arch->emu->signal_context_size(process, thread); 423 stack_align = process->arch->emu->signal_stack_align(process, thread); 424 if (!ctx_size || !stack_align || (stack_align & (stack_align - 1u)) != 0) 425 return KIT_UNSUPPORTED; 426 frame_size = EMU_LINUX_SIGFRAME_XREGS + ctx_size; 427 if (frame_size < EMU_LINUX_SIGFRAME_SIZE) 428 frame_size = EMU_LINUX_SIGFRAME_SIZE; 429 frame_size = linux_round_up(frame_size, stack_align); 430 frame_sp = (sp - frame_size) & ~(stack_align - 1u); 431 frame = emu_cpu_va_to_host_perm(cpu, frame_sp, frame_size, EMU_MEM_WRITE); 432 if (!frame) { 433 emu_cpu_trap_fault(cpu); 434 *next_pc_out = fault_pc ? fault_pc : next_pc; 435 return KIT_OK; 436 } 437 memset(frame, 0, (size_t)frame_size); 438 linux_wr64(frame, EMU_LINUX_SIGFRAME_MAGIC); 439 linux_wr64(frame + EMU_LINUX_SIGFRAME_SAVED_PC, fault_pc); 440 linux_wr64(frame + EMU_LINUX_SIGFRAME_SIGINFO, (u64)signo); 441 linux_wr64(frame + EMU_LINUX_SIGFRAME_SIGINFO + 16u, fault_addr); 442 if (process->arch->emu->save_signal_context(process, thread, 443 frame + EMU_LINUX_SIGFRAME_XREGS, 444 ctx_size) != KIT_OK) 445 return KIT_ERR; 446 ts->signal_frame_sp = frame_sp; 447 process->arch->emu->set_sp(thread, frame_sp); 448 if (process->arch->emu->set_signal_handler_args( 449 process, thread, signo, frame_sp + EMU_LINUX_SIGFRAME_SIGINFO, 450 frame_sp + EMU_LINUX_SIGFRAME_UCONTEXT) != KIT_OK) 451 return KIT_ERR; 452 emu_cpu_clear_trap(cpu); 453 emu_cpu_set_pc(cpu, act->handler); 454 *next_pc_out = act->handler; 455 return KIT_OK; 456 } 457 458 static KitStatus linux_deliver_fault(EmuProcess* process, EmuThread* thread, 459 const EmuFaultEvent* ev, 460 u64* next_pc_out) { 461 if (!ev) return KIT_INVALID; 462 return linux_deliver_signal(process, thread, 11, ev->addr, ev->pc, 463 ev->next_pc, next_pc_out); 464 } 465 466 static KitStatus linux_decode_syscall(EmuProcess* process, EmuThread* thread, 467 EmuSyscallRequest* out) { 468 u32 i; 469 if (!process || !thread || !thread->cpu || !out) return KIT_INVALID; 470 if (!process->arch || !process->arch->emu || 471 !process->arch->emu->get_syscall_no || 472 !process->arch->emu->get_syscall_arg) 473 return KIT_UNSUPPORTED; 474 memset(out, 0, sizeof(*out)); 475 out->number = process->arch->emu->get_syscall_no(thread); 476 for (i = 0; i < 6u; ++i) 477 out->args[i] = process->arch->emu->get_syscall_arg(thread, i); 478 return KIT_OK; 479 } 480 481 static KitStatus linux_encode_syscall_result(EmuProcess* process, 482 EmuThread* thread, 483 const EmuSyscallResult* r) { 484 (void)process; 485 if (!process || !thread || !thread->cpu || !r) return KIT_INVALID; 486 if (!process->arch || !process->arch->emu || 487 !process->arch->emu->set_syscall_result) 488 return KIT_UNSUPPORTED; 489 process->arch->emu->set_syscall_result(thread, (u64)r->result); 490 return KIT_OK; 491 } 492 493 static KitStatus linux_default_syscall(void* user, EmuProcess* process, 494 EmuThread* thread, 495 const EmuSyscallRequest* req, 496 EmuSyscallResult* out) { 497 EmuCPUState* s; 498 u64 nr; 499 u64 a0, a1, a2; 500 u64 a3, a4, a5; 501 i64 ret = -LINUX_ENOSYS; 502 (void)user; 503 if (!process || !thread || !thread->cpu || !req || !out) return KIT_INVALID; 504 s = thread->cpu; 505 nr = req->number; 506 a0 = req->args[0]; 507 a1 = req->args[1]; 508 a2 = req->args[2]; 509 a3 = req->args[3]; 510 a4 = req->args[4]; 511 a5 = req->args[5]; 512 memset(out, 0, sizeof(*out)); 513 514 switch (nr) { 515 case LINUX_SYS_exit: 516 case LINUX_SYS_exit_group: 517 emu_cpu_trap_exit(s, (int)(i32)a0); 518 return KIT_OK; 519 case LINUX_SYS_write: { 520 u8* p = emu_cpu_va_to_host_perm(s, a1, a2, EMU_MEM_READ); 521 ret = p ? (i64)a2 : -LINUX_EFAULT; 522 break; 523 } 524 case LINUX_SYS_read: 525 ret = a0 == 0u ? 0 : -LINUX_EBADF; 526 break; 527 case LINUX_SYS_close: 528 ret = 0; 529 break; 530 case LINUX_SYS_brk: { 531 u64 actual = 0; 532 (void)emu_addr_space_set_brk(&process->image.addr_space, a0, &actual); 533 ret = (i64)actual; 534 break; 535 } 536 case LINUX_SYS_mmap: { 537 EmuAddrSpace* as = &process->image.addr_space; 538 LinuxProcessState* ps = linux_process_state(process); 539 u64 addr = a0; 540 u64 length = linux_round_up(a1, as->page_size); 541 u64 flags = a3; 542 u64 fd = a4; 543 u64 off = a5; 544 u64 map_at = 0; 545 KitStatus st; 546 if (!ps) { 547 ret = -LINUX_EINVAL; 548 break; 549 } 550 if (!length || (off & (as->page_size - 1u)) != 0) { 551 ret = -LINUX_EINVAL; 552 break; 553 } 554 if (!(flags & LINUX_MAP_ANONYMOUS)) { 555 ret = -LINUX_ENOSYS; 556 break; 557 } 558 if (!(flags & LINUX_MAP_PRIVATE)) { 559 ret = -LINUX_EINVAL; 560 break; 561 } 562 if ((flags & LINUX_MAP_ANONYMOUS) && (i64)fd != -1 && fd != 0) { 563 ret = -LINUX_EBADF; 564 break; 565 } 566 if (flags & (LINUX_MAP_FIXED | LINUX_MAP_FIXED_NOREPLACE)) { 567 if ((addr & (as->page_size - 1u)) != 0) { 568 ret = -LINUX_EINVAL; 569 break; 570 } 571 map_at = addr; 572 if (flags & LINUX_MAP_FIXED_NOREPLACE) { 573 st = emu_addr_space_map( 574 as, map_at, length, linux_emu_perms(a2), 575 linux_emu_perms(a2) ? EMU_MAP_ANON : EMU_MAP_GUARD); 576 if (st == KIT_OK) { 577 if (process->os && process->os->emu_note_map_region) 578 process->os->emu_note_map_region(process, map_at, length, 579 EMU_OS_MAP_MMAP); 580 ret = (i64)map_at; 581 } else { 582 ret = -LINUX_EEXIST; 583 } 584 break; 585 } 586 (void)emu_addr_space_unmap(as, map_at, length); 587 } else { 588 u64 min_va = addr ? linux_round_up(addr, as->page_size) : ps->mmap_hint; 589 if (addr) { 590 st = emu_addr_space_find_gap(as, length, as->page_size, min_va, 591 0x0000800000000000ull, &map_at); 592 } else if (process->os && process->os->emu_find_map_region) { 593 st = process->os->emu_find_map_region(process, length, as->page_size, 594 EMU_OS_MAP_MMAP, &map_at); 595 } else { 596 st = KIT_UNSUPPORTED; 597 } 598 if (st != KIT_OK) { 599 ret = -LINUX_ENOMEM; 600 break; 601 } 602 } 603 st = emu_addr_space_map( 604 as, map_at, length, linux_emu_perms(a2), 605 linux_emu_perms(a2) ? EMU_MAP_ANON : EMU_MAP_GUARD); 606 if (st != KIT_OK) { 607 ret = -LINUX_ENOMEM; 608 } else { 609 if (process->os && process->os->emu_note_map_region) 610 process->os->emu_note_map_region(process, map_at, length, 611 EMU_OS_MAP_MMAP); 612 ret = (i64)map_at; 613 } 614 break; 615 } 616 case LINUX_SYS_munmap: { 617 EmuAddrSpace* as = &process->image.addr_space; 618 u64 addr = a0; 619 u64 length = linux_round_up(a1, as->page_size); 620 if (!length || (addr & (as->page_size - 1u)) != 0) { 621 ret = -LINUX_EINVAL; 622 } else { 623 (void)emu_addr_space_unmap(as, addr, length); 624 ret = 0; 625 } 626 break; 627 } 628 case LINUX_SYS_mprotect: { 629 EmuAddrSpace* as = &process->image.addr_space; 630 u64 addr = a0; 631 u64 length = linux_round_up(a1, as->page_size); 632 if (!length || (addr & (as->page_size - 1u)) != 0) { 633 ret = -LINUX_EINVAL; 634 } else if (emu_addr_space_protect(as, addr, length, 635 linux_emu_perms(a2)) == KIT_OK) { 636 ret = 0; 637 } else { 638 ret = -LINUX_ENOMEM; 639 } 640 break; 641 } 642 case LINUX_SYS_fstat: { 643 u8* p = emu_cpu_va_to_host_perm(s, a1, 128u, EMU_MEM_WRITE); 644 if (!p) { 645 ret = -LINUX_EFAULT; 646 } else { 647 memset(p, 0, 128u); 648 ret = 0; 649 } 650 break; 651 } 652 case LINUX_SYS_openat: 653 ret = -2; 654 break; 655 case LINUX_SYS_lseek: 656 ret = (i64)a1; 657 break; 658 case LINUX_SYS_readv: { 659 u8* p = emu_cpu_va_to_host_perm(s, a1, a2 * 16u, EMU_MEM_READ); 660 ret = p ? 0 : -LINUX_EFAULT; 661 break; 662 } 663 case LINUX_SYS_writev: { 664 u8* p = emu_cpu_va_to_host_perm(s, a1, a2 * 16u, EMU_MEM_READ); 665 u64 total = 0; 666 u64 i; 667 if (!p) { 668 ret = -LINUX_EFAULT; 669 break; 670 } 671 for (i = 0; i < a2; ++i) { 672 u64 l = 0; 673 u32 j; 674 for (j = 0; j < 8u; ++j) l |= ((u64)p[i * 16u + 8u + j]) << (8u * j); 675 total += l; 676 } 677 ret = (i64)total; 678 break; 679 } 680 case LINUX_SYS_set_tid_address: 681 ret = 1; 682 break; 683 case LINUX_SYS_clock_gettime: { 684 u8* p = emu_cpu_va_to_host_perm(s, a1, 16u, EMU_MEM_WRITE); 685 if (!p) { 686 ret = -LINUX_EFAULT; 687 } else { 688 memset(p, 0, 16u); 689 ret = 0; 690 } 691 break; 692 } 693 case LINUX_SYS_sched_yield: 694 ret = 0; 695 break; 696 case LINUX_SYS_rt_sigaction: 697 if (a0 < 64u && a1) { 698 LinuxProcessState* ps = linux_process_state(process); 699 u8* p = emu_cpu_va_to_host_perm(s, a1, 24u, EMU_MEM_READ); 700 if (!ps) { 701 ret = -LINUX_EINVAL; 702 } else if (!p) { 703 ret = -LINUX_EFAULT; 704 } else { 705 u64 handler = 0, flags = 0, restorer = 0; 706 u32 j; 707 for (j = 0; j < 8u; ++j) handler |= ((u64)p[j]) << (8u * j); 708 for (j = 0; j < 8u; ++j) flags |= ((u64)p[8u + j]) << (8u * j); 709 for (j = 0; j < 8u; ++j) restorer |= ((u64)p[16u + j]) << (8u * j); 710 ps->signal_actions[a0].handler = handler; 711 ps->signal_actions[a0].flags = flags; 712 ps->signal_actions[a0].restorer = restorer; 713 ps->signal_actions[a0].installed = 1; 714 ret = 0; 715 } 716 } else { 717 ret = 0; 718 } 719 break; 720 case LINUX_SYS_rt_sigprocmask: 721 if (a0 == 0u && a1) { 722 LinuxThreadState* ts = linux_thread_state(thread); 723 u8* p = emu_cpu_va_to_host_perm(s, a1, 8u, EMU_MEM_READ); 724 if (!ts) { 725 ret = -LINUX_EINVAL; 726 } else if (!p) { 727 ret = -LINUX_EFAULT; 728 } else { 729 ts->signal_mask |= linux_rd64(p); 730 ret = 0; 731 } 732 } else if (a0 == 1u && a1) { 733 LinuxThreadState* ts = linux_thread_state(thread); 734 u8* p = emu_cpu_va_to_host_perm(s, a1, 8u, EMU_MEM_READ); 735 if (!ts) { 736 ret = -LINUX_EINVAL; 737 } else if (!p) { 738 ret = -LINUX_EFAULT; 739 } else { 740 ts->signal_mask &= ~linux_rd64(p); 741 ret = 0; 742 } 743 } else if (a0 == 2u && a1) { 744 LinuxThreadState* ts = linux_thread_state(thread); 745 u8* p = emu_cpu_va_to_host_perm(s, a1, 8u, EMU_MEM_READ); 746 if (!ts) { 747 ret = -LINUX_EINVAL; 748 } else if (!p) { 749 ret = -LINUX_EFAULT; 750 } else { 751 ts->signal_mask = linux_rd64(p); 752 ret = 0; 753 } 754 } else { 755 ret = 0; 756 } 757 break; 758 case LINUX_SYS_rt_sigreturn: { 759 LinuxThreadState* ts = linux_thread_state(thread); 760 u64 frame_sp; 761 u8* frame; 762 u64 ctx_size; 763 u64 frame_size; 764 if (!process->arch || !process->arch->emu || 765 !process->arch->emu->get_sp || 766 !process->arch->emu->signal_context_size || 767 !process->arch->emu->restore_signal_context) { 768 ret = -LINUX_ENOSYS; 769 break; 770 } 771 if (!ts) { 772 ret = -LINUX_EINVAL; 773 break; 774 } 775 ctx_size = process->arch->emu->signal_context_size(process, thread); 776 frame_size = EMU_LINUX_SIGFRAME_XREGS + ctx_size; 777 frame_sp = ts->signal_frame_sp ? ts->signal_frame_sp 778 : process->arch->emu->get_sp(thread); 779 frame = emu_cpu_va_to_host_perm(s, frame_sp, frame_size, EMU_MEM_READ); 780 if (!frame || linux_rd64(frame) != EMU_LINUX_SIGFRAME_MAGIC) { 781 ret = -LINUX_EFAULT; 782 break; 783 } 784 if (process->arch->emu->restore_signal_context( 785 process, thread, frame + EMU_LINUX_SIGFRAME_XREGS, ctx_size) != 786 KIT_OK) { 787 ret = -LINUX_EFAULT; 788 break; 789 } 790 emu_cpu_set_pc(s, linux_rd64(frame + EMU_LINUX_SIGFRAME_SAVED_PC)); 791 ts->signal_frame_sp = 0; 792 out->flags |= EMU_SYSCALL_RESULT_SKIP_ENCODE; 793 ret = 0; 794 break; 795 } 796 case LINUX_SYS_getpid: 797 case LINUX_SYS_getuid: 798 case LINUX_SYS_geteuid: 799 case LINUX_SYS_getgid: 800 case LINUX_SYS_getegid: 801 ret = 1; 802 break; 803 default: 804 ret = -LINUX_ENOSYS; 805 break; 806 } 807 808 out->result = ret; 809 return KIT_OK; 810 } 811 812 static u64 linux_syscall_next_pc(EmuProcess* process, EmuThread* thread, 813 const EmuSyscallRequest* req, u64 next_pc) { 814 EmuCPUState* s = emu_thread_cpu(thread); 815 (void)process; 816 if (req && req->number == LINUX_SYS_rt_sigreturn && s) return emu_cpu_pc(s); 817 return next_pc; 818 } 819 820 const KitOsImpl linux_os_impl = { 821 .kind = KIT_OS_LINUX, 822 .name = "linux", 823 .emu_init_process_private = linux_init_process_private, 824 .emu_destroy_process_private = linux_destroy_process_private, 825 .emu_init_thread_private = linux_init_thread_private, 826 .emu_destroy_thread_private = linux_destroy_thread_private, 827 .emu_init_process = linux_init_process, 828 .emu_init_thread = linux_init_thread, 829 .emu_decode_syscall = linux_decode_syscall, 830 .emu_encode_syscall_result = linux_encode_syscall_result, 831 .emu_syscall_next_pc = linux_syscall_next_pc, 832 .emu_find_map_region = linux_find_map_region, 833 .emu_note_map_region = linux_note_map_region, 834 .emu_default_syscall = linux_default_syscall, 835 .emu_deliver_fault = linux_deliver_fault, 836 };