emu.c (17200B)
1 #include "emu/emu.h" 2 3 #include <string.h> 4 5 #include "arch/arch.h" 6 #include "arch/riscv/isa.h" 7 #include "core/slice.h" 8 9 #define RV64_EMU_SYM_XREG "__emu_rv64_xreg" 10 #define RV64_EMU_SYM_SET_XREG "__emu_rv64_set_xreg" 11 #define RV64_EMU_SYM_JALR "__emu_rv64_jalr" 12 13 typedef struct Rv64EmuCPUState { 14 u64 x[32]; 15 u64 f[32]; 16 u32 fcsr; 17 u64 reserved_addr; 18 int has_reservation; 19 } Rv64EmuCPUState; 20 21 typedef struct Rv64EmuLiftSyms { 22 KitCgSym xreg; 23 KitCgSym set_xreg; 24 KitCgSym load64; 25 KitCgSym load64_checked; 26 KitCgSym store64; 27 KitCgSym jalr; 28 KitCgSym syscall; 29 KitCgTypeId xreg_fn; 30 KitCgTypeId set_xreg_fn; 31 KitCgTypeId load64_fn; 32 KitCgTypeId load64_checked_fn; 33 KitCgTypeId store64_fn; 34 KitCgTypeId jalr_fn; 35 KitCgTypeId syscall_fn; 36 KitCgTypeId thread_ptr; 37 KitCgTypeId i32; 38 KitCgTypeId i64; 39 KitCgTypeId i64_ptr; 40 KitCgTypeId void_ty; 41 } Rv64EmuLiftSyms; 42 43 static KitCgSym rv64_emu_decl_helper(KitCompiler* c, KitCg* cg, 44 const char* name, KitCgTypeId type) { 45 KitCgDecl d; 46 memset(&d, 0, sizeof(d)); 47 d.kind = KIT_CG_DECL_FUNC; 48 d.linkage_name = kit_sym_intern(c, kit_slice_cstr(name)); 49 d.display_name = d.linkage_name; 50 d.linkage_name = kit_cg_c_linkage_name(c, d.linkage_name); 51 d.type = type; 52 d.sym.bind = KIT_SB_GLOBAL; 53 d.sym.visibility = KIT_CG_VIS_DEFAULT; 54 return kit_cg_decl(cg, d); 55 } 56 57 static KitCgTypeId rv64_emu_func_type(KitCompiler* c, KitCgTypeId ret, 58 const KitCgTypeId* params, u32 nparams) { 59 KitCgFuncParam p[5]; 60 KitCgFuncResult result; 61 KitCgFuncSig sig; 62 u32 i; 63 memset(p, 0, sizeof(p)); 64 for (i = 0; i < nparams; ++i) p[i].type = params[i]; 65 memset(&sig, 0, sizeof(sig)); 66 memset(&result, 0, sizeof(result)); 67 result.type = ret; 68 sig.result = result; 69 sig.params = p; 70 sig.nparams = nparams; 71 sig.call_conv = KIT_CG_CC_TARGET_C; 72 return kit_cg_type_func(c, sig); 73 } 74 75 static void rv64_emu_lift_syms_init(KitCompiler* c, KitCg* cg, 76 Rv64EmuLiftSyms* out) { 77 KitCgBuiltinTypes bi = kit_cg_builtin_types(c); 78 KitCgTypeId params[5]; 79 memset(out, 0, sizeof(*out)); 80 out->void_ty = bi.id[KIT_CG_BUILTIN_VOID]; 81 out->i32 = bi.id[KIT_CG_BUILTIN_I32]; 82 out->i64 = bi.id[KIT_CG_BUILTIN_I64]; 83 out->i64_ptr = kit_cg_type_ptr(c, out->i64, 0); 84 out->thread_ptr = emu_thread_type((Compiler*)c); 85 86 params[0] = out->thread_ptr; 87 params[1] = out->i32; 88 out->xreg_fn = rv64_emu_func_type(c, out->i64, params, 2); 89 90 params[0] = out->thread_ptr; 91 params[1] = out->i32; 92 params[2] = out->i64; 93 out->set_xreg_fn = rv64_emu_func_type(c, out->void_ty, params, 3); 94 95 params[0] = out->thread_ptr; 96 params[1] = out->i64; 97 out->load64_fn = rv64_emu_func_type(c, out->i64, params, 2); 98 99 { 100 KitCgTypeId load_params[5]; 101 load_params[0] = out->thread_ptr; 102 load_params[1] = out->i64; 103 load_params[2] = out->i64; 104 load_params[3] = out->i64; 105 load_params[4] = out->i64_ptr; 106 out->load64_checked_fn = rv64_emu_func_type(c, out->i64, load_params, 5); 107 } 108 109 { 110 KitCgTypeId store_params[5]; 111 store_params[0] = out->thread_ptr; 112 store_params[1] = out->i64; 113 store_params[2] = out->i64; 114 store_params[3] = out->i64; 115 store_params[4] = out->i64; 116 out->store64_fn = rv64_emu_func_type(c, out->i64, store_params, 5); 117 } 118 119 { 120 KitCgTypeId jalr_params[5]; 121 jalr_params[0] = out->thread_ptr; 122 jalr_params[1] = out->i64; 123 jalr_params[2] = out->i64; 124 jalr_params[3] = out->i64; 125 jalr_params[4] = out->i64; 126 out->jalr_fn = rv64_emu_func_type(c, out->i64, jalr_params, 5); 127 } 128 129 params[0] = out->thread_ptr; 130 params[1] = out->i64; 131 out->syscall_fn = rv64_emu_func_type(c, out->i64, params, 2); 132 133 out->xreg = rv64_emu_decl_helper(c, cg, RV64_EMU_SYM_XREG, out->xreg_fn); 134 out->set_xreg = 135 rv64_emu_decl_helper(c, cg, RV64_EMU_SYM_SET_XREG, out->set_xreg_fn); 136 out->load64 = rv64_emu_decl_helper(c, cg, EMU_SYM_LOAD64, out->load64_fn); 137 out->load64_checked = rv64_emu_decl_helper(c, cg, EMU_SYM_LOAD64_CHECKED, 138 out->load64_checked_fn); 139 out->store64 = rv64_emu_decl_helper(c, cg, EMU_SYM_STORE64, out->store64_fn); 140 out->jalr = rv64_emu_decl_helper(c, cg, RV64_EMU_SYM_JALR, out->jalr_fn); 141 out->syscall = rv64_emu_decl_helper(c, cg, EMU_SYM_SYSCALL, out->syscall_fn); 142 } 143 144 static KitCgMemAccess rv64_emu_mem(KitCgTypeId type) { 145 KitCgMemAccess m; 146 memset(&m, 0, sizeof(m)); 147 m.type = type; 148 return m; 149 } 150 151 static void rv64_emu_push_thread(KitCg* cg, KitCgLocal thread, 152 KitCgTypeId thread_ptr) { 153 kit_cg_push_local(cg, thread); 154 kit_cg_load(cg, rv64_emu_mem(thread_ptr)); 155 } 156 157 static void rv64_emu_push_xreg(KitCg* cg, const Rv64EmuLiftSyms* s, 158 KitCgLocal thread, u32 reg) { 159 if (reg == 0u) { 160 kit_cg_push_int(cg, 0, s->i64); 161 return; 162 } 163 rv64_emu_push_thread(cg, thread, s->thread_ptr); 164 kit_cg_push_int(cg, reg, s->i32); 165 kit_cg_call_symbol(cg, s->xreg, 2, (KitCgCallAttrs){0}); 166 } 167 168 static void rv64_emu_store_xreg_from_tmp(KitCg* cg, const Rv64EmuLiftSyms* s, 169 KitCgLocal thread, KitCgLocal tmp, 170 u32 reg) { 171 if (reg == 0u) return; 172 rv64_emu_push_thread(cg, thread, s->thread_ptr); 173 kit_cg_push_int(cg, reg, s->i32); 174 kit_cg_push_local(cg, tmp); 175 kit_cg_load(cg, rv64_emu_mem(s->i64)); 176 kit_cg_call_symbol(cg, s->set_xreg, 3, (KitCgCallAttrs){0}); 177 } 178 179 static void rv64_emu_store_xreg_from_stack(KitCg* cg, const Rv64EmuLiftSyms* s, 180 KitCgLocal thread, u32 reg, 181 KitCgLocal tmp) { 182 kit_cg_push_local(cg, tmp); 183 kit_cg_swap(cg); 184 kit_cg_store(cg, rv64_emu_mem(s->i64)); 185 if (reg == 0u) return; 186 rv64_emu_store_xreg_from_tmp(cg, s, thread, tmp, reg); 187 } 188 189 static void rv64_emu_store_local_from_stack(KitCg* cg, const Rv64EmuLiftSyms* s, 190 KitCgLocal local) { 191 kit_cg_push_local(cg, local); 192 kit_cg_swap(cg); 193 kit_cg_store(cg, rv64_emu_mem(s->i64)); 194 } 195 196 static void rv64_emu_push_local_value(KitCg* cg, const Rv64EmuLiftSyms* s, 197 KitCgLocal local) { 198 kit_cg_push_local(cg, local); 199 kit_cg_load(cg, rv64_emu_mem(s->i64)); 200 } 201 202 static void rv64_emu_push_addr(KitCg* cg, const Rv64EmuLiftSyms* s, 203 KitCgLocal thread, 204 const KitDecodedOperand* mem) { 205 rv64_emu_push_xreg(cg, s, thread, mem->reg); 206 if (mem->imm) { 207 kit_cg_push_int(cg, (u64)mem->imm, s->i64); 208 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); 209 } 210 } 211 212 static KitStatus rv64_emu_lift_block(Compiler* compiler, KitCg* cg, 213 const KitDecodedInsn* insts, u32 n, 214 const EmuLiftCtx* ctx) { 215 Rv64EmuLiftSyms syms; 216 KitCgLocal thread; 217 KitCgLocal tmp; 218 KitCgLocal fault_next; 219 KitCgLocalAttrs attrs; 220 u64 next_pc; 221 u32 i; 222 KitCompiler* c; 223 224 if (!compiler || !cg || !insts || !ctx) return KIT_INVALID; 225 c = (KitCompiler*)compiler; 226 rv64_emu_lift_syms_init(c, cg, &syms); 227 228 kit_cg_func_begin(cg, ctx->block_sym); 229 memset(&attrs, 0, sizeof(attrs)); 230 attrs.name = kit_sym_intern(c, KIT_SLICE_LIT("thread")); 231 thread = kit_cg_param(cg, 0, syms.thread_ptr, attrs); 232 attrs.name = kit_sym_intern(c, KIT_SLICE_LIT("tmp")); 233 tmp = kit_cg_local(cg, syms.i64, attrs); 234 attrs.name = kit_sym_intern(c, KIT_SLICE_LIT("fault_next")); 235 fault_next = kit_cg_local(cg, syms.i64, attrs); 236 237 next_pc = ctx->guest_pc; 238 for (i = 0; i < n; ++i) { 239 const KitDecodedInsn* in = &insts[i]; 240 next_pc = in->pc + in->nbytes; 241 switch (in->opcode) { 242 case RV64_DEC_ADDI: { 243 u32 rd = in->operands[0].reg; 244 u32 rs1 = in->operands[1].reg; 245 i64 imm = in->operands[2].imm; 246 rv64_emu_push_xreg(cg, &syms, thread, rs1); 247 kit_cg_push_int(cg, (u64)imm, syms.i64); 248 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); 249 rv64_emu_store_xreg_from_stack(cg, &syms, thread, rd, tmp); 250 break; 251 } 252 case RV64_DEC_ADD: { 253 u32 rd = in->operands[0].reg; 254 u32 rs1 = in->operands[1].reg; 255 u32 rs2 = in->operands[2].reg; 256 rv64_emu_push_xreg(cg, &syms, thread, rs1); 257 rv64_emu_push_xreg(cg, &syms, thread, rs2); 258 kit_cg_int_binop(cg, KIT_CG_INT_ADD, 0); 259 rv64_emu_store_xreg_from_stack(cg, &syms, thread, rd, tmp); 260 break; 261 } 262 case RV64_DEC_AUIPC: { 263 u32 rd = in->operands[0].reg; 264 i64 imm = in->operands[1].imm; 265 kit_cg_push_int(cg, (u64)(in->pc + (u64)imm), syms.i64); 266 rv64_emu_store_xreg_from_stack(cg, &syms, thread, rd, tmp); 267 break; 268 } 269 case RV64_DEC_LD: { 270 u32 rd = in->operands[0].reg; 271 KitCgLabel ok = kit_cg_label_new(cg); 272 rv64_emu_push_thread(cg, thread, syms.thread_ptr); 273 rv64_emu_push_addr(cg, &syms, thread, &in->operands[1]); 274 kit_cg_push_int(cg, in->pc, syms.i64); 275 kit_cg_push_int(cg, next_pc, syms.i64); 276 kit_cg_push_local_addr(cg, tmp); 277 kit_cg_call_symbol(cg, syms.load64_checked, 5, (KitCgCallAttrs){0}); 278 rv64_emu_store_local_from_stack(cg, &syms, fault_next); 279 rv64_emu_push_local_value(cg, &syms, fault_next); 280 kit_cg_push_int(cg, 0, syms.i64); 281 kit_cg_int_cmp(cg, KIT_CG_INT_NE); 282 kit_cg_branch_false(cg, ok); 283 rv64_emu_push_local_value(cg, &syms, fault_next); 284 kit_cg_ret(cg); 285 kit_cg_label_place(cg, ok); 286 rv64_emu_store_xreg_from_tmp(cg, &syms, thread, tmp, rd); 287 break; 288 } 289 case RV64_DEC_SD: { 290 rv64_emu_push_thread(cg, thread, syms.thread_ptr); 291 rv64_emu_push_addr(cg, &syms, thread, &in->operands[1]); 292 rv64_emu_push_xreg(cg, &syms, thread, in->operands[0].reg); 293 kit_cg_push_int(cg, in->pc, syms.i64); 294 kit_cg_push_int(cg, next_pc, syms.i64); 295 kit_cg_call_symbol(cg, syms.store64, 5, (KitCgCallAttrs){0}); 296 kit_cg_ret(cg); 297 kit_cg_func_end(cg); 298 return KIT_OK; 299 } 300 case RV64_DEC_JALR: { 301 Rv64I ji = rv64_i_unpack(in->arch[0]); 302 u32 rd = ji.rd; 303 u32 rs1 = ji.rs1; 304 i64 imm = rv64_sext(ji.imm12, 12); 305 rv64_emu_push_thread(cg, thread, syms.thread_ptr); 306 kit_cg_push_int(cg, rd, syms.i64); 307 kit_cg_push_int(cg, rs1, syms.i64); 308 kit_cg_push_int(cg, (u64)imm, syms.i64); 309 kit_cg_push_int(cg, next_pc, syms.i64); 310 kit_cg_call_symbol(cg, syms.jalr, 5, (KitCgCallAttrs){0}); 311 kit_cg_ret(cg); 312 kit_cg_func_end(cg); 313 return KIT_OK; 314 break; 315 } 316 case RV64_DEC_ECALL: 317 rv64_emu_push_thread(cg, thread, syms.thread_ptr); 318 kit_cg_push_int(cg, next_pc, syms.i64); 319 kit_cg_call_symbol(cg, syms.syscall, 2, (KitCgCallAttrs){0}); 320 kit_cg_ret(cg); 321 kit_cg_func_end(cg); 322 return KIT_OK; 323 default: 324 kit_cg_push_int(cg, in->pc, syms.i64); 325 kit_cg_ret(cg); 326 kit_cg_func_end(cg); 327 return KIT_OK; 328 } 329 } 330 331 kit_cg_push_int(cg, next_pc, syms.i64); 332 kit_cg_ret(cg); 333 kit_cg_func_end(cg); 334 return KIT_OK; 335 } 336 337 static EmuCPUState* rv64_emu_cpu_new(Compiler* c, u64 initial_pc, 338 u64 initial_sp) { 339 EmuCPUState* cpu = emu_cpu_new_with_arch_state(c, KIT_ARCH_RV64, initial_pc, 340 sizeof(Rv64EmuCPUState), 341 _Alignof(Rv64EmuCPUState)); 342 Rv64EmuCPUState* rv = (Rv64EmuCPUState*)emu_cpu_arch_state(cpu); 343 if (rv) rv->x[2] = initial_sp; 344 return cpu; 345 } 346 347 static Rv64EmuCPUState* rv64_thread_state(EmuThread* thread) { 348 return thread ? (Rv64EmuCPUState*)emu_cpu_arch_state(emu_thread_cpu(thread)) 349 : NULL; 350 } 351 352 u64 emu_rv64_xreg(EmuThread* thread, u32 i) { 353 Rv64EmuCPUState* rv = rv64_thread_state(thread); 354 if (!rv || i >= 32u) return 0; 355 return i == 0u ? 0u : rv->x[i]; 356 } 357 358 void emu_rv64_set_xreg(EmuThread* thread, u32 i, u64 v) { 359 Rv64EmuCPUState* rv = rv64_thread_state(thread); 360 if (!rv || i >= 32u || i == 0u) return; 361 rv->x[i] = v; 362 } 363 364 static u64 rv64_get_syscall_no(EmuThread* thread) { 365 return emu_rv64_xreg(thread, 17u); 366 } 367 368 static u64 rv64_get_syscall_arg(EmuThread* thread, u32 index) { 369 static const u32 regs[6] = {10u, 11u, 12u, 13u, 14u, 15u}; 370 return index < 6u ? emu_rv64_xreg(thread, regs[index]) : 0; 371 } 372 373 static void rv64_set_syscall_result(EmuThread* thread, u64 value) { 374 emu_rv64_set_xreg(thread, 10u, value); 375 } 376 377 static u64 rv64_get_sp(EmuThread* thread) { return emu_rv64_xreg(thread, 2u); } 378 379 static void rv64_set_sp(EmuThread* thread, u64 value) { 380 emu_rv64_set_xreg(thread, 2u, value); 381 } 382 383 static u64 rv64_get_tp(EmuThread* thread) { return emu_rv64_xreg(thread, 4u); } 384 385 static void rv64_set_tp(EmuThread* thread, u64 value) { 386 emu_rv64_set_xreg(thread, 4u, value); 387 } 388 389 static void rv64_signal_wr64(u8* p, u64 v) { 390 u32 i; 391 for (i = 0; i < 8u; ++i) p[i] = (u8)(v >> (8u * i)); 392 } 393 394 static u64 rv64_signal_rd64(const u8* p) { 395 return (u64)p[0] | ((u64)p[1] << 8) | ((u64)p[2] << 16) | ((u64)p[3] << 24) | 396 ((u64)p[4] << 32) | ((u64)p[5] << 40) | ((u64)p[6] << 48) | 397 ((u64)p[7] << 56); 398 } 399 400 static u64 rv64_signal_context_size(EmuProcess* process, EmuThread* thread) { 401 (void)process; 402 (void)thread; 403 return 32u * 8u; 404 } 405 406 static KitStatus rv64_save_signal_context(EmuProcess* process, 407 EmuThread* thread, u8* dst, 408 u64 size) { 409 u32 i; 410 (void)process; 411 if (!thread || !dst || size < 32u * 8u) return KIT_INVALID; 412 for (i = 0; i < 32u; ++i) 413 rv64_signal_wr64(dst + (u64)i * 8u, emu_rv64_xreg(thread, i)); 414 return KIT_OK; 415 } 416 417 static KitStatus rv64_restore_signal_context(EmuProcess* process, 418 EmuThread* thread, const u8* src, 419 u64 size) { 420 u32 i; 421 (void)process; 422 if (!thread || !src || size < 32u * 8u) return KIT_INVALID; 423 for (i = 0; i < 32u; ++i) 424 emu_rv64_set_xreg(thread, i, rv64_signal_rd64(src + (u64)i * 8u)); 425 return KIT_OK; 426 } 427 428 static KitStatus rv64_set_signal_handler_args(EmuProcess* process, 429 EmuThread* thread, int signo, 430 u64 siginfo, u64 ucontext) { 431 (void)process; 432 if (!thread) return KIT_INVALID; 433 emu_rv64_set_xreg(thread, 10u, (u64)signo); 434 emu_rv64_set_xreg(thread, 11u, siginfo); 435 emu_rv64_set_xreg(thread, 12u, ucontext); 436 return KIT_OK; 437 } 438 439 static u64 rv64_signal_stack_align(EmuProcess* process, EmuThread* thread) { 440 (void)process; 441 (void)thread; 442 return 16u; 443 } 444 445 static KitStatus rv64_emit_import_thunk(EmuProcess* process, u64 thunk_vaddr) { 446 u8 code[4]; 447 u32 word = 0x00008067u; 448 u32 i; 449 if (!process) return KIT_INVALID; 450 for (i = 0; i < 4u; ++i) code[i] = (u8)(word >> (8u * i)); 451 return emu_addr_space_copy_in(&process->image.addr_space, thunk_vaddr, code, 452 sizeof(code)); 453 } 454 455 u64 emu_rv64_jalr(EmuThread* thread, u64 rd, u64 rs1, u64 imm, u64 next_pc) { 456 EmuImportBinding* b = NULL; 457 u64 target; 458 if (rd != 0u) emu_rv64_set_xreg(thread, (u32)rd, next_pc); 459 target = emu_rv64_xreg(thread, (u32)rs1) + imm; 460 target &= ~1ull; 461 if (emu_dl_resolve_import_thunk(thread ? thread->process : NULL, target, 462 &b) == KIT_OK && 463 b) { 464 u64 args[3]; 465 u64 result = 0; 466 args[0] = emu_rv64_xreg(thread, 10u); 467 args[1] = emu_rv64_xreg(thread, 11u); 468 args[2] = emu_rv64_xreg(thread, 12u); 469 if (emu_call_host_import(thread, b, args, 3u, &result) != KIT_OK) { 470 emu_cpu_trap_fault(emu_thread_cpu(thread)); 471 return next_pc; 472 } 473 if (b->signature.result != KIT_EMU_VALUE_VOID) 474 emu_rv64_set_xreg(thread, 10u, result); 475 return next_pc; 476 } 477 return target; 478 } 479 480 static void* rv64_resolve_runtime_helper(void* emu, KitSlice name) { 481 (void)emu; 482 if (kit_slice_eq_cstr(name, RV64_EMU_SYM_XREG)) return (void*)emu_rv64_xreg; 483 if (kit_slice_eq_cstr(name, RV64_EMU_SYM_SET_XREG)) 484 return (void*)emu_rv64_set_xreg; 485 if (kit_slice_eq_cstr(name, RV64_EMU_SYM_JALR)) return (void*)emu_rv64_jalr; 486 return NULL; 487 } 488 489 const ArchEmuOps rv64_emu_ops = { 490 .cpu_new = rv64_emu_cpu_new, 491 .block_fn_type = emu_block_fn_type, 492 .lift_block = rv64_emu_lift_block, 493 .get_gpr = emu_rv64_xreg, 494 .set_gpr = emu_rv64_set_xreg, 495 .get_syscall_no = rv64_get_syscall_no, 496 .get_syscall_arg = rv64_get_syscall_arg, 497 .set_syscall_result = rv64_set_syscall_result, 498 .get_sp = rv64_get_sp, 499 .set_sp = rv64_set_sp, 500 .get_tp = rv64_get_tp, 501 .set_tp = rv64_set_tp, 502 .signal_context_size = rv64_signal_context_size, 503 .save_signal_context = rv64_save_signal_context, 504 .restore_signal_context = rv64_restore_signal_context, 505 .set_signal_handler_args = rv64_set_signal_handler_args, 506 .signal_stack_align = rv64_signal_stack_align, 507 .import_thunk_size = 4u, 508 .emit_import_thunk = rv64_emit_import_thunk, 509 .resolve_runtime_helper = rv64_resolve_runtime_helper, 510 };