|
|
1.1 root 1: /* 1.1.1.9 root 2: * Cisco router simulation platform. 1.1 root 3: * Copyright (c) 2005,2006 Christophe Fillot ([email protected]) 4: * 5: * MIPS64 JIT compiler. 6: */ 7: 8: #include <stdio.h> 9: #include <stdlib.h> 10: #include <unistd.h> 11: #include <string.h> 12: #include <sys/types.h> 13: #include <sys/stat.h> 14: #include <sys/mman.h> 15: #include <signal.h> 16: #include <fcntl.h> 17: #include <assert.h> 18: 1.1.1.10 root 19: #include "sbox.h" 1.1 root 20: #include "cpu.h" 21: #include "device.h" 1.1.1.13! root 22: #include "tcb.h" 1.1.1.4 root 23: #include "mips64.h" 1.1.1.9 root 24: #include "mips64_cp0.h" 1.1 root 25: #include "mips64_exec.h" 1.1.1.9 root 26: #include "mips64_jit.h" 1.1 root 27: #include "insn_lookup.h" 1.1.1.9 root 28: #include "memory.h" 1.1 root 29: #include "ptask.h" 30: 1.1.1.9 root 31: #include MIPS64_ARCH_INC_FILE 32: 1.1.1.13! root 33: #define DEBUG_JIT_SHARED 0 ! 34: 1.1 root 35: #if DEBUG_BLOCK_TIMESTAMP 36: static volatile m_uint64_t jit_jiffies = 0; 37: #endif 38: 39: /* MIPS jump instructions for block scan */ 1.1.1.9 root 40: struct mips64_insn_jump mips64_insn_jumps[] = { 1.1 root 41: { "b" , 0xffff0000, 0x10000000, 16, 1 }, 42: { "bal" , 0xffff0000, 0x04110000, 16, 1 }, 43: { "beq" , 0xfc000000, 0x10000000, 16, 1 }, 44: { "beql" , 0xfc000000, 0x50000000, 16, 1 }, 45: { "bgez" , 0xfc1f0000, 0x04010000, 16, 1 }, 46: { "bgezl" , 0xfc1f0000, 0x04030000, 16, 1 }, 47: { "bgezal" , 0xfc1f0000, 0x04110000, 16, 1 }, 48: { "bgezall" , 0xfc1f0000, 0x04130000, 16, 1 }, 49: { "bgtz" , 0xfc1f0000, 0x1c000000, 16, 1 }, 50: { "bgtzl" , 0xfc1f0000, 0x5c000000, 16, 1 }, 51: { "blez" , 0xfc1f0000, 0x18000000, 16, 1 }, 52: { "blezl" , 0xfc1f0000, 0x58000000, 16, 1 }, 53: { "bltz" , 0xfc1f0000, 0x04000000, 16, 1 }, 54: { "bltzl" , 0xfc1f0000, 0x04020000, 16, 1 }, 55: { "bltzal" , 0xfc1f0000, 0x04100000, 16, 1 }, 56: { "bltzall" , 0xfc1f0000, 0x04120000, 16, 1 }, 57: { "bne" , 0xfc000000, 0x14000000, 16, 1 }, 58: { "bnel" , 0xfc000000, 0x54000000, 16, 1 }, 59: { "j" , 0xfc000000, 0x08000000, 26, 0 }, 60: { NULL , 0x00000000, 0x00000000, 0, 0 }, 61: }; 62: 63: /* Instruction Lookup Table */ 64: static insn_lookup_t *ilt = NULL; 65: 66: static void *mips64_jit_get_insn(int index) 67: { 68: return(&mips64_insn_tags[index]); 69: } 70: 1.1.1.9 root 71: static int mips64_jit_chk_lo(struct mips64_insn_tag *tag,int value) 1.1 root 72: { 73: return((value & tag->mask) == (tag->value & 0xFFFF)); 74: } 75: 1.1.1.9 root 76: static int mips64_jit_chk_hi(struct mips64_insn_tag *tag,int value) 1.1 root 77: { 78: return((value & (tag->mask >> 16)) == (tag->value >> 16)); 79: } 80: 81: /* Initialize instruction lookup table */ 82: void mips64_jit_create_ilt(void) 83: { 84: int i,count; 85: 86: for(i=0,count=0;mips64_insn_tags[i].emit;i++) 87: count++; 88: 1.1.1.10 root 89: ilt = ilt_create("mips64j",count, 1.1 root 90: (ilt_get_insn_cbk_t)mips64_jit_get_insn, 91: (ilt_check_cbk_t)mips64_jit_chk_lo, 92: (ilt_check_cbk_t)mips64_jit_chk_hi); 93: } 94: 1.1.1.4 root 95: /* Initialize the JIT structure */ 96: int mips64_jit_init(cpu_mips_t *cpu) 1.1.1.2 root 97: { 1.1.1.13! root 98: if (tsg_bind_cpu(cpu->gen) == -1) 1.1.1.4 root 99: return(-1); 1.1.1.2 root 100: 1.1.1.13! root 101: return(cpu_jit_init(cpu->gen, ! 102: MIPS_JIT_VIRT_HASH_SIZE, ! 103: MIPS_JIT_PHYS_HASH_SIZE)); 1.1.1.2 root 104: } 105: 1.1.1.4 root 106: /* Flush the JIT */ 107: u_int mips64_jit_flush(cpu_mips_t *cpu,u_int threshold) 1.1.1.2 root 108: { 1.1.1.13! root 109: /* TO FIX / ENHANCE */ ! 110: return(tsg_remove_single_desc(cpu->gen)); 1.1.1.4 root 111: } 112: 113: /* Shutdown the JIT */ 114: void mips64_jit_shutdown(cpu_mips_t *cpu) 1.1.1.2 root 115: { 1.1.1.13! root 116: cpu_jit_shutdown(cpu->gen); 1.1.1.2 root 117: } 118: 1.1 root 119: /* Find the JIT code emitter for the specified MIPS instruction */ 1.1.1.9 root 120: static struct mips64_insn_tag *insn_tag_find(mips_insn_t ins) 1.1 root 121: { 1.1.1.9 root 122: struct mips64_insn_tag *tag = NULL; 1.1 root 123: int index; 124: 125: index = ilt_lookup(ilt,ins); 126: tag = mips64_jit_get_insn(index); 127: return tag; 128: } 129: 130: /* Check if the specified MIPS instruction is a jump */ 1.1.1.9 root 131: static struct mips64_insn_jump *insn_jump_find(mips_insn_t ins) 1.1 root 132: { 1.1.1.9 root 133: struct mips64_insn_jump *jump = NULL; 1.1 root 134: int i; 135: 136: for(i=0;mips64_insn_jumps[i].name;i++) 137: if ((ins & mips64_insn_jumps[i].mask) == mips64_insn_jumps[i].value) { 138: jump = &mips64_insn_jumps[i]; 139: break; 140: } 141: 142: return(jump); 143: } 144: 145: /* Fetch a MIPS instruction */ 1.1.1.13! root 146: static forced_inline mips_insn_t insn_fetch(cpu_tc_t *tc) 1.1 root 147: { 1.1.1.13! root 148: return(vmtoh32(((mips_insn_t *)tc->target_code)[tc->trans_pos])); 1.1 root 149: } 150: 151: /* Emit a breakpoint if necessary */ 1.1.1.4 root 152: #if BREAKPOINT_ENABLE 1.1.1.13! root 153: static void insn_emit_breakpoint(cpu_mips_t *cpu,cpu_tc_t *tc) 1.1 root 154: { 155: m_uint64_t pc; 156: int i; 157: 1.1.1.13! root 158: pc = tc->vaddr + ((tc->trans_pos-1) << 2); 1.1 root 159: 160: for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++) 161: if (pc == cpu->breakpoints[i]) { 1.1.1.13! root 162: mips64_emit_breakpoint(tc); 1.1 root 163: break; 164: } 165: } 1.1.1.4 root 166: #endif /* BREAKPOINT_ENABLE */ 1.1 root 167: 1.1.1.10 root 168: /* Check if an instruction is in a delay slot or not */ 1.1.1.13! root 169: int mips64_jit_is_delay_slot(cpu_tc_t *tc,m_uint64_t pc) 1.1.1.10 root 170: { 171: struct mips64_insn_tag *tag; 172: m_uint32_t offset,insn; 173: 1.1.1.13! root 174: offset = (pc - tc->vaddr) >> 2; 1.1.1.10 root 175: 176: if (!offset) 177: return(FALSE); 178: 179: /* Fetch the previous instruction to determine if it is a jump */ 1.1.1.13! root 180: insn = vmtoh32(((m_uint32_t *)tc->target_code)[offset-1]); 1.1.1.10 root 181: tag = insn_tag_find(insn); 182: assert(tag != NULL); 183: return(!tag->delay_slot); 184: } 185: 1.1 root 186: /* Fetch a MIPS instruction and emit corresponding translated code */ 1.1.1.9 root 187: struct mips64_insn_tag *mips64_jit_fetch_and_emit(cpu_mips_t *cpu, 1.1.1.13! root 188: cpu_tc_t *tc, 1.1.1.9 root 189: int delay_slot) 1.1 root 190: { 1.1.1.9 root 191: struct mips64_insn_tag *tag; 1.1 root 192: mips_insn_t code; 193: 1.1.1.13! root 194: code = insn_fetch(tc); 1.1 root 195: tag = insn_tag_find(code); 196: assert(tag); 1.1.1.9 root 197: 198: /* Branch-delay slot is in another page: slow exec */ 1.1.1.13! root 199: if ((tc->trans_pos == (MIPS_INSN_PER_PAGE-1)) && !tag->delay_slot) { ! 200: tc->jit_insn_ptr[tc->trans_pos] = tc->jit_ptr; 1.1.1.9 root 201: 1.1.1.13! root 202: mips64_set_pc(tc,tc->vaddr + (tc->trans_pos << 2)); ! 203: mips64_emit_single_step(tc,code); ! 204: mips64_jit_tcb_push_epilog(tc); ! 205: tc->trans_pos++; 1.1.1.9 root 206: return tag; 207: } 208: 1.1 root 209: if (delay_slot && !tag->delay_slot) { 1.1.1.13! root 210: mips64_emit_invalid_delay_slot(tc); 1.1 root 211: return NULL; 212: } 213: 1.1.1.9 root 214: if (!delay_slot) 1.1.1.13! root 215: tc->jit_insn_ptr[tc->trans_pos] = tc->jit_ptr; 1.1 root 216: 217: if (delay_slot != 2) 1.1.1.13! root 218: tc->trans_pos++; 1.1 root 219: 1.1.1.8 root 220: #if DEBUG_INSN_PERF_CNT 1.1.1.13! root 221: mips64_inc_perf_counter(tc); 1.1.1.4 root 222: #endif 1.1 root 223: 1.1.1.4 root 224: if (!delay_slot) { 225: /* Check for IRQs + Increment count register before jumps */ 226: if (!tag->delay_slot) { 1.1.1.13! root 227: mips64_inc_cp0_count_reg(tc); ! 228: mips64_check_pending_irq(tc); 1.1.1.4 root 229: } 230: } 1.1 root 231: 1.1.1.3 root 232: #if BREAKPOINT_ENABLE 233: if (cpu->breakpoints_enabled) 1.1.1.13! root 234: insn_emit_breakpoint(cpu,tc); 1.1.1.3 root 235: #endif 236: 1.1.1.13! root 237: tag->emit(cpu,tc,code); 1.1 root 238: return tag; 239: } 240: 241: /* Add end of JIT block */ 1.1.1.13! root 242: static void mips64_jit_tcb_add_end(cpu_tc_t *tc) 1.1 root 243: { 1.1.1.13! root 244: mips64_set_pc(tc,tc->vaddr+(tc->trans_pos<<2)); ! 245: mips64_jit_tcb_push_epilog(tc); 1.1 root 246: } 247: 248: /* Record a patch to apply in a compiled block */ 1.1.1.13! root 249: int mips64_jit_tcb_record_patch(cpu_mips_t *cpu,cpu_tc_t *tc, ! 250: u_char *jit_ptr,m_uint64_t vaddr) 1.1 root 251: { 1.1.1.13! root 252: struct insn_patch *patch; ! 253: ! 254: patch = tc_record_patch(cpu->gen,tc,jit_ptr,vaddr); ! 255: return((patch != NULL) ? 0 : -1); 1.1 root 256: } 257: 258: /* Apply all patches */ 1.1.1.13! root 259: static int mips64_jit_tcb_apply_patches(cpu_mips_t *cpu,cpu_tc_t *tc) 1.1 root 260: { 1.1.1.13! root 261: tc_apply_patches(tc,mips64_jit_tcb_set_patch); 1.1 root 262: return(0); 263: } 264: 265: /* Adjust the JIT buffer if its size is not sufficient */ 1.1.1.13! root 266: static int mips64_jit_tcb_adjust_buffer(cpu_mips_t *cpu,cpu_tc_t *tc) 1.1 root 267: { 1.1.1.13! root 268: return(tc_adjust_jit_buffer(cpu->gen,tc,mips64_jit_tcb_set_jump)); 1.1 root 269: } 270: 1.1.1.13! root 271: /* Produce translated code for a page. If this fails, use non-compiled mode */ ! 272: static cpu_tc_t *mips64_jit_tcb_translate(cpu_mips_t *cpu,cpu_tb_t *tb) 1.1 root 273: { 1.1.1.13! root 274: struct mips64_insn_tag *tag; ! 275: cpu_tc_t *tc; ! 276: ! 277: /* The page is not shared, we have to compile it */ ! 278: tc = tc_alloc(cpu->gen,tb->vaddr,tb->exec_state); ! 279: ! 280: if (tc == NULL) ! 281: return NULL; ! 282: ! 283: tc->target_code = tb->target_code; ! 284: tc->trans_pos = 0; ! 285: ! 286: /* Emit native code for each instruction */ ! 287: while(tc->trans_pos < MIPS_INSN_PER_PAGE) ! 288: { ! 289: if (unlikely(!(tag = mips64_jit_fetch_and_emit(cpu,tc,0)))) { ! 290: cpu_log(cpu->gen,"JIT", ! 291: "unable to fetch instruction (VA=0x%8.8llx,exec_state=%u).\n", ! 292: tb->vaddr,tb->exec_state); 1.1.1.4 root 293: return NULL; 1.1 root 294: } 295: 1.1.1.13! root 296: #if DEBUG_BLOCK_COMPILE ! 297: cpu_log(cpu->gen,"JIT","Page 0x%8.8llx: emitted tag 0x%8.8x/0x%8.8x\n", ! 298: tb->vaddr,tag->mask,tag->value); ! 299: #endif 1.1.1.4 root 300: 1.1.1.13! root 301: if (mips64_jit_tcb_adjust_buffer(cpu,tc) == -1) ! 302: return NULL; 1.1.1.4 root 303: } 304: 1.1.1.13! root 305: mips64_jit_tcb_add_end(tc); ! 306: mips64_jit_tcb_apply_patches(cpu,tc); ! 307: tc_free_patches(tc); ! 308: tc->target_code = NULL; ! 309: return tc; 1.1 root 310: } 311: 1.1.1.4 root 312: /* Compile a MIPS instruction page */ 1.1.1.13! root 313: static cpu_tb_t * ! 314: mips64_jit_tcb_compile(cpu_mips_t *cpu,m_uint64_t vaddr,m_uint32_t exec_state) ! 315: { ! 316: cpu_tb_t *tb; ! 317: cpu_tc_t *tc; 1.1.1.4 root 318: m_uint64_t page_addr; 1.1.1.13! root 319: mips_insn_t *mips_code; ! 320: m_uint32_t phys_page; 1.1.1.4 root 321: 1.1.1.13! root 322: page_addr = vaddr & MIPS_MIN_PAGE_MASK; 1.1 root 323: 1.1.1.13! root 324: /* ! 325: * Get the mips code address from the host point of view. ! 326: * If there is an error (TLB,...), we return directly to the main loop. ! 327: */ ! 328: mips_code = cpu->mem_op_ifetch(cpu,page_addr); 1.1 root 329: 1.1.1.13! root 330: if (unlikely(cpu->translate(cpu,page_addr,&phys_page))) ! 331: return NULL; 1.1 root 332: 1.1.1.13! root 333: /* Create a new translation block */ ! 334: if (!(tb = tb_alloc(cpu->gen,page_addr,exec_state))) ! 335: return NULL; ! 336: ! 337: tb->vaddr = page_addr; ! 338: tb->exec_state = exec_state; ! 339: tb->phys_page = phys_page; ! 340: tb->phys_hash = mips64_jit_get_phys_hash(phys_page); ! 341: tb->virt_hash = mips64_jit_get_virt_hash(page_addr); ! 342: tb->target_code = mips_code; ! 343: tb->checksum = tsg_checksum_page(tb->target_code,VM_PAGE_SIZE); ! 344: ! 345: /* Check if we can share this page with another virtual CPU */ ! 346: if (tc_find_shared(cpu->gen,tb) == TSG_LOOKUP_SHARED) { ! 347: #if DEBUG_JIT_SHARED ! 348: cpu_log(cpu->gen,"JIT","Page 0x%8.8llx is shared (ref_count=%u)\n", ! 349: tb->vaddr,tb->tc->ref_count); 1.1 root 350: #endif 1.1.1.13! root 351: return tb; 1.1 root 352: } 353: 1.1.1.13! root 354: /* The page is not shared, we have to compile it */ ! 355: tc = mips64_jit_tcb_translate(cpu,tb); 1.1.1.2 root 356: 1.1.1.13! root 357: if (tc != NULL) { ! 358: tc->target_code = tb->target_code; ! 359: tc->trans_pos = 0; ! 360: ! 361: tb_enable(cpu->gen,tb); ! 362: tc_register(cpu->gen,tb,tc); ! 363: } else { ! 364: tb->flags |= TB_FLAG_NOJIT; ! 365: tb_enable(cpu->gen,tb); ! 366: } ! 367: ! 368: return tb; 1.1 root 369: } 370: 371: /* Run a compiled MIPS instruction block */ 1.1.1.9 root 372: static forced_inline 1.1.1.13! root 373: void mips64_jit_tcb_run(cpu_mips_t *cpu,cpu_tb_t *tb) 1.1 root 374: { 375: #if DEBUG_SYM_TREE 376: struct symbol *sym = NULL; 377: int mark = FALSE; 378: #endif 379: 380: if (unlikely(cpu->pc & 0x03)) { 1.1.1.9 root 381: fprintf(stderr,"mips64_jit_tcb_run: Invalid PC 0x%llx.\n",cpu->pc); 382: mips64_dump_regs(cpu->gen); 383: mips64_tlb_dump(cpu->gen); 384: cpu_stop(cpu->gen); 1.1.1.4 root 385: return; 1.1 root 386: } 387: 388: #if DEBUG_SYM_TREE 1.1.1.4 root 389: if (cpu->sym_trace && cpu->sym_tree) 1.1 root 390: { 1.1.1.4 root 391: if ((sym = mips64_sym_lookup(cpu,cpu->pc)) != NULL) { 1.1.1.9 root 392: cpu_log(cpu,"mips64_jit_tcb_run(start)", 1.1.1.4 root 393: "%s (PC=0x%llx) RA = 0x%llx\na0=0x%llx, " 1.1 root 394: "a1=0x%llx, a2=0x%llx, a3=0x%llx\n", 395: sym->name, cpu->pc, cpu->gpr[MIPS_GPR_RA], 396: cpu->gpr[MIPS_GPR_A0], cpu->gpr[MIPS_GPR_A1], 397: cpu->gpr[MIPS_GPR_A2], cpu->gpr[MIPS_GPR_A3]); 398: mark = TRUE; 399: } 400: } 401: #endif 402: 403: /* Execute JIT compiled code */ 1.1.1.13! root 404: mips64_jit_tcb_exec(cpu,tb); 1.1 root 405: 406: #if DEBUG_SYM_TREE 407: if (mark) { 1.1.1.9 root 408: cpu_log(cpu,"mips64_jit_tcb_run(end)","%s, v0 = 0x%llx\n", 1.1 root 409: sym->name,cpu->gpr[MIPS_GPR_V0]); 410: } 411: #endif 412: } 413: 1.1.1.9 root 414: /* Execute compiled MIPS code */ 415: void *mips64_jit_run_cpu(cpu_gen_t *gen) 416: { 417: cpu_mips_t *cpu = CPU_MIPS64(gen); 1.1.1.4 root 418: pthread_t timer_irq_thread; 1.1.1.13! root 419: cpu_tb_t *tb; ! 420: m_uint32_t hv,hp; ! 421: m_uint32_t phys_page; 1.1.1.4 root 422: int timer_irq_check = 0; 1.1 root 423: 1.1.1.4 root 424: if (pthread_create(&timer_irq_thread,NULL, 425: (void *)mips64_timer_irq_run,cpu)) 426: { 1.1.1.7 root 427: fprintf(stderr, 428: "VM '%s': unable to create Timer IRQ thread for CPU%u.\n", 1.1.1.9 root 429: cpu->vm->name,gen->id); 430: cpu_stop(cpu->gen); 1.1.1.4 root 431: return NULL; 432: } 433: 1.1.1.9 root 434: gen->cpu_thread_running = TRUE; 1.1.1.11 root 435: cpu_exec_loop_set(gen); 436: 1.1.1.4 root 437: start_cpu: 1.1.1.9 root 438: gen->idle_count = 0; 1.1.1.6 root 439: 1.1 root 440: for(;;) { 1.1.1.13! root 441: if (unlikely(gen->state != CPU_STATE_RUNNING)) { ! 442: /* ! 443: * We are paused/halted, so free the TCB/TCD in order to allow ! 444: * reallocation of exec pages for other vCPUs. ! 445: */ ! 446: cpu_jit_tcb_flush_all(cpu->gen); 1.1 root 447: break; 1.1.1.13! root 448: } ! 449: 1.1.1.8 root 450: #if DEBUG_BLOCK_PERF_CNT 451: cpu->perf_counter++; 452: #endif 1.1.1.4 root 453: /* Handle virtual idle loop */ 454: if (unlikely(cpu->pc == cpu->idle_pc)) { 1.1.1.9 root 455: if (++gen->idle_count == gen->idle_max) { 456: cpu_idle_loop(gen); 457: gen->idle_count = 0; 1.1.1.4 root 458: } 459: } 460: 461: /* Handle the virtual CPU clock */ 462: if (++timer_irq_check == cpu->timer_irq_check_itv) { 463: timer_irq_check = 0; 464: 465: if (cpu->timer_irq_pending && !cpu->irq_disable) { 466: mips64_trigger_timer_irq(cpu); 467: mips64_trigger_irq(cpu); 468: cpu->timer_irq_pending--; 469: } 470: } 1.1 root 471: 1.1.1.13! root 472: /* Get the JIT block corresponding to PC register */ ! 473: hv = mips64_jit_get_virt_hash(cpu->pc); ! 474: tb = gen->tb_virt_hash[hv]; 1.1.1.4 root 475: 1.1.1.13! root 476: if (unlikely(!tb) || unlikely(!mips64_jit_tcb_match(cpu,tb))) ! 477: { ! 478: /* slow lookup: try to find the page by physical address */ ! 479: cpu->translate(cpu,cpu->pc,&phys_page); ! 480: hp = mips64_jit_get_phys_hash(phys_page); ! 481: ! 482: for(tb=gen->tb_phys_hash[hp];tb;tb=tb->phys_next) ! 483: if (mips64_jit_tcb_match(cpu,tb)) ! 484: goto tb_found; ! 485: ! 486: /* the TB doesn't exist, compile the page */ ! 487: tb = mips64_jit_tcb_compile(cpu,cpu->pc,cpu->exec_state); 1.1.1.5 root 488: 1.1.1.13! root 489: if (unlikely(!tb)) { 1.1.1.4 root 490: fprintf(stderr, 491: "VM '%s': unable to compile block for CPU%u PC=0x%llx\n", 1.1.1.9 root 492: cpu->vm->name,gen->id,cpu->pc); 493: cpu_stop(gen); 1.1.1.4 root 494: break; 1.1 root 495: } 1.1.1.2 root 496: 1.1.1.13! root 497: tb_found: ! 498: /* update the virtual hash table */ ! 499: gen->tb_virt_hash[hv] = tb; 1.1 root 500: } 501: 502: #if DEBUG_BLOCK_TIMESTAMP 1.1.1.13! root 503: tb->tm_last_use = jit_jiffies++; 1.1 root 504: #endif 1.1.1.13! root 505: tb->acc_count++; ! 506: ! 507: cpu->current_tb = tb; ! 508: ! 509: if (unlikely(tb->flags & TB_FLAG_NOTRANS)) ! 510: mips64_exec_page(cpu); ! 511: else ! 512: mips64_jit_tcb_run(cpu,tb); 1.1 root 513: } 514: 1.1.1.4 root 515: /* Check regularly if the CPU has been restarted */ 1.1.1.9 root 516: while(gen->cpu_thread_running) { 517: gen->seq_state++; 1.1.1.4 root 518: 1.1.1.9 root 519: switch(gen->state) { 520: case CPU_STATE_RUNNING: 1.1.1.13! root 521: printf("VM %s: starting CPU!\n",cpu->vm->name); 1.1.1.4 root 522: goto start_cpu; 523: 1.1.1.9 root 524: case CPU_STATE_HALTED: 525: gen->cpu_thread_running = FALSE; 1.1.1.4 root 526: pthread_join(timer_irq_thread,NULL); 1.1.1.12 root 527: return NULL; 1.1.1.4 root 528: } 1.1 root 529: 1.1.1.4 root 530: /* CPU is paused */ 1.1 root 531: usleep(200000); 1.1.1.4 root 532: } 1.1 root 533: 534: return NULL; 535: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.