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