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