Commit 6a00d60127dc0e1d4efadafe1feb88f05030fe52
1 parent
f0aca822
SMP support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1640 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
9 changed files
with
296 additions
and
138 deletions
cpu-defs.h
| ... | ... | @@ -96,6 +96,7 @@ typedef struct CPUTLBEntry { |
| 96 | 96 | |
| 97 | 97 | #define CPU_COMMON \ |
| 98 | 98 | struct TranslationBlock *current_tb; /* currently executing TB */ \ |
| 99 | + int cpu_halted; /* TRUE if cpu is halted (sleep mode) */ \ | |
| 99 | 100 | /* soft mmu support */ \ |
| 100 | 101 | /* in order to avoid passing too many arguments to the memory \ |
| 101 | 102 | write helpers, we store some rarely used information in the CPU \ |
| ... | ... | @@ -115,9 +116,9 @@ typedef struct CPUTLBEntry { |
| 115 | 116 | int nb_breakpoints; \ |
| 116 | 117 | int singlestep_enabled; \ |
| 117 | 118 | \ |
| 119 | + void *next_cpu; /* next CPU sharing TB cache */ \ | |
| 120 | + int cpu_index; /* CPU index (informative) */ \ | |
| 118 | 121 | /* user data */ \ |
| 119 | 122 | void *opaque; |
| 120 | 123 | |
| 121 | - | |
| 122 | - | |
| 123 | 124 | #endif | ... | ... |
cpu-exec.c
| ... | ... | @@ -251,6 +251,8 @@ int cpu_exec(CPUState *env1) |
| 251 | 251 | TranslationBlock *tb; |
| 252 | 252 | uint8_t *tc_ptr; |
| 253 | 253 | |
| 254 | + cpu_single_env = env1; | |
| 255 | + | |
| 254 | 256 | /* first we save global registers */ |
| 255 | 257 | saved_env = env; |
| 256 | 258 | env = env1; |
| ... | ... | @@ -755,6 +757,8 @@ int cpu_exec(CPUState *env1) |
| 755 | 757 | T2 = saved_T2; |
| 756 | 758 | #endif |
| 757 | 759 | env = saved_env; |
| 760 | + /* fail safe : never use cpu_single_env outside cpu_exec() */ | |
| 761 | + cpu_single_env = NULL; | |
| 758 | 762 | return ret; |
| 759 | 763 | } |
| 760 | 764 | ... | ... |
disas.c
| ... | ... | @@ -138,6 +138,7 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info) |
| 138 | 138 | values: |
| 139 | 139 | i386 - nonzero means 16 bit code |
| 140 | 140 | arm - nonzero means thumb code |
| 141 | + ppc - nonzero means little endian | |
| 141 | 142 | other targets - unused |
| 142 | 143 | */ |
| 143 | 144 | void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) |
| ... | ... | @@ -177,7 +178,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) |
| 177 | 178 | disasm_info.mach = bfd_mach_sparc_v9b; |
| 178 | 179 | #endif |
| 179 | 180 | #elif defined(TARGET_PPC) |
| 180 | - if (cpu_single_env->msr[MSR_LE]) | |
| 181 | + if (flags) | |
| 181 | 182 | disasm_info.endian = BFD_ENDIAN_LITTLE; |
| 182 | 183 | #ifdef TARGET_PPC64 |
| 183 | 184 | disasm_info.mach = bfd_mach_ppc64; |
| ... | ... | @@ -314,6 +315,7 @@ void term_vprintf(const char *fmt, va_list ap); |
| 314 | 315 | void term_printf(const char *fmt, ...); |
| 315 | 316 | |
| 316 | 317 | static int monitor_disas_is_physical; |
| 318 | +static CPUState *monitor_disas_env; | |
| 317 | 319 | |
| 318 | 320 | static int |
| 319 | 321 | monitor_read_memory (memaddr, myaddr, length, info) |
| ... | ... | @@ -325,7 +327,7 @@ monitor_read_memory (memaddr, myaddr, length, info) |
| 325 | 327 | if (monitor_disas_is_physical) { |
| 326 | 328 | cpu_physical_memory_rw(memaddr, myaddr, length, 0); |
| 327 | 329 | } else { |
| 328 | - cpu_memory_rw_debug(cpu_single_env, memaddr,myaddr, length, 0); | |
| 330 | + cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0); | |
| 329 | 331 | } |
| 330 | 332 | return 0; |
| 331 | 333 | } |
| ... | ... | @@ -339,7 +341,8 @@ static int monitor_fprintf(FILE *stream, const char *fmt, ...) |
| 339 | 341 | return 0; |
| 340 | 342 | } |
| 341 | 343 | |
| 342 | -void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) | |
| 344 | +void monitor_disas(CPUState *env, | |
| 345 | + target_ulong pc, int nb_insn, int is_physical, int flags) | |
| 343 | 346 | { |
| 344 | 347 | int count, i; |
| 345 | 348 | struct disassemble_info disasm_info; |
| ... | ... | @@ -347,6 +350,7 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) |
| 347 | 350 | |
| 348 | 351 | INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf); |
| 349 | 352 | |
| 353 | + monitor_disas_env = env; | |
| 350 | 354 | monitor_disas_is_physical = is_physical; |
| 351 | 355 | disasm_info.read_memory_func = monitor_read_memory; |
| 352 | 356 | ... | ... |
exec-all.h
| ... | ... | @@ -91,7 +91,7 @@ int cpu_restore_state_copy(struct TranslationBlock *tb, |
| 91 | 91 | CPUState *env, unsigned long searched_pc, |
| 92 | 92 | void *puc); |
| 93 | 93 | void cpu_resume_from_signal(CPUState *env1, void *puc); |
| 94 | -void cpu_exec_init(void); | |
| 94 | +void cpu_exec_init(CPUState *env); | |
| 95 | 95 | int page_unprotect(unsigned long address, unsigned long pc, void *puc); |
| 96 | 96 | void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, |
| 97 | 97 | int is_cpu_write_access); | ... | ... |
exec.c
| ... | ... | @@ -74,6 +74,11 @@ int phys_ram_fd; |
| 74 | 74 | uint8_t *phys_ram_base; |
| 75 | 75 | uint8_t *phys_ram_dirty; |
| 76 | 76 | |
| 77 | +CPUState *first_cpu; | |
| 78 | +/* current CPU in the current thread. It is only valid inside | |
| 79 | + cpu_exec() */ | |
| 80 | +CPUState *cpu_single_env; | |
| 81 | + | |
| 77 | 82 | typedef struct PageDesc { |
| 78 | 83 | /* list of TBs intersecting this ram page */ |
| 79 | 84 | TranslationBlock *first_tb; |
| ... | ... | @@ -233,19 +238,30 @@ static inline PhysPageDesc *phys_page_find(target_phys_addr_t index) |
| 233 | 238 | } |
| 234 | 239 | |
| 235 | 240 | #if !defined(CONFIG_USER_ONLY) |
| 236 | -static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr, | |
| 237 | - target_ulong vaddr); | |
| 241 | +static void tlb_protect_code(ram_addr_t ram_addr); | |
| 238 | 242 | static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, |
| 239 | 243 | target_ulong vaddr); |
| 240 | 244 | #endif |
| 241 | 245 | |
| 242 | -void cpu_exec_init(void) | |
| 246 | +void cpu_exec_init(CPUState *env) | |
| 243 | 247 | { |
| 248 | + CPUState **penv; | |
| 249 | + int cpu_index; | |
| 250 | + | |
| 244 | 251 | if (!code_gen_ptr) { |
| 245 | 252 | code_gen_ptr = code_gen_buffer; |
| 246 | 253 | page_init(); |
| 247 | 254 | io_mem_init(); |
| 248 | 255 | } |
| 256 | + env->next_cpu = NULL; | |
| 257 | + penv = &first_cpu; | |
| 258 | + cpu_index = 0; | |
| 259 | + while (*penv != NULL) { | |
| 260 | + penv = (CPUState **)&(*penv)->next_cpu; | |
| 261 | + cpu_index++; | |
| 262 | + } | |
| 263 | + env->cpu_index = cpu_index; | |
| 264 | + *penv = env; | |
| 249 | 265 | } |
| 250 | 266 | |
| 251 | 267 | static inline void invalidate_page_bitmap(PageDesc *p) |
| ... | ... | @@ -277,8 +293,9 @@ static void page_flush_tb(void) |
| 277 | 293 | |
| 278 | 294 | /* flush all the translation blocks */ |
| 279 | 295 | /* XXX: tb_flush is currently not thread safe */ |
| 280 | -void tb_flush(CPUState *env) | |
| 296 | +void tb_flush(CPUState *env1) | |
| 281 | 297 | { |
| 298 | + CPUState *env; | |
| 282 | 299 | #if defined(DEBUG_FLUSH) |
| 283 | 300 | printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", |
| 284 | 301 | code_gen_ptr - code_gen_buffer, |
| ... | ... | @@ -286,7 +303,10 @@ void tb_flush(CPUState *env) |
| 286 | 303 | nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); |
| 287 | 304 | #endif |
| 288 | 305 | nb_tbs = 0; |
| 289 | - memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); | |
| 306 | + | |
| 307 | + for(env = first_cpu; env != NULL; env = env->next_cpu) { | |
| 308 | + memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); | |
| 309 | + } | |
| 290 | 310 | |
| 291 | 311 | memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *)); |
| 292 | 312 | page_flush_tb(); |
| ... | ... | @@ -424,6 +444,7 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n) |
| 424 | 444 | |
| 425 | 445 | static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr) |
| 426 | 446 | { |
| 447 | + CPUState *env; | |
| 427 | 448 | PageDesc *p; |
| 428 | 449 | unsigned int h, n1; |
| 429 | 450 | target_ulong phys_pc; |
| ... | ... | @@ -451,7 +472,10 @@ static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_ad |
| 451 | 472 | |
| 452 | 473 | /* remove the TB from the hash list */ |
| 453 | 474 | h = tb_jmp_cache_hash_func(tb->pc); |
| 454 | - cpu_single_env->tb_jmp_cache[h] = NULL; | |
| 475 | + for(env = first_cpu; env != NULL; env = env->next_cpu) { | |
| 476 | + if (env->tb_jmp_cache[h] == tb) | |
| 477 | + env->tb_jmp_cache[h] = NULL; | |
| 478 | + } | |
| 455 | 479 | |
| 456 | 480 | /* suppress this TB from the two jump lists */ |
| 457 | 481 | tb_jmp_remove(tb, 0); |
| ... | ... | @@ -818,10 +842,7 @@ static inline void tb_alloc_page(TranslationBlock *tb, |
| 818 | 842 | protected. So we handle the case where only the first TB is |
| 819 | 843 | allocated in a physical page */ |
| 820 | 844 | if (!last_first_tb) { |
| 821 | - target_ulong virt_addr; | |
| 822 | - | |
| 823 | - virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS); | |
| 824 | - tlb_protect_code(cpu_single_env, page_addr, virt_addr); | |
| 845 | + tlb_protect_code(page_addr); | |
| 825 | 846 | } |
| 826 | 847 | #endif |
| 827 | 848 | |
| ... | ... | @@ -1246,40 +1267,13 @@ void tlb_flush_page(CPUState *env, target_ulong addr) |
| 1246 | 1267 | #endif |
| 1247 | 1268 | } |
| 1248 | 1269 | |
| 1249 | -static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr) | |
| 1250 | -{ | |
| 1251 | - if (addr == (tlb_entry->address & | |
| 1252 | - (TARGET_PAGE_MASK | TLB_INVALID_MASK)) && | |
| 1253 | - (tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { | |
| 1254 | - tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; | |
| 1255 | - } | |
| 1256 | -} | |
| 1257 | - | |
| 1258 | 1270 | /* update the TLBs so that writes to code in the virtual page 'addr' |
| 1259 | 1271 | can be detected */ |
| 1260 | -static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr, | |
| 1261 | - target_ulong vaddr) | |
| 1272 | +static void tlb_protect_code(ram_addr_t ram_addr) | |
| 1262 | 1273 | { |
| 1263 | - int i; | |
| 1264 | - | |
| 1265 | - vaddr &= TARGET_PAGE_MASK; | |
| 1266 | - i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); | |
| 1267 | - tlb_protect_code1(&env->tlb_write[0][i], vaddr); | |
| 1268 | - tlb_protect_code1(&env->tlb_write[1][i], vaddr); | |
| 1269 | - | |
| 1270 | -#ifdef USE_KQEMU | |
| 1271 | - if (env->kqemu_enabled) { | |
| 1272 | - kqemu_set_notdirty(env, ram_addr); | |
| 1273 | - } | |
| 1274 | -#endif | |
| 1275 | - phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] &= ~CODE_DIRTY_FLAG; | |
| 1276 | - | |
| 1277 | -#if !defined(CONFIG_SOFTMMU) | |
| 1278 | - /* NOTE: as we generated the code for this page, it is already at | |
| 1279 | - least readable */ | |
| 1280 | - if (vaddr < MMAP_AREA_END) | |
| 1281 | - mprotect((void *)vaddr, TARGET_PAGE_SIZE, PROT_READ); | |
| 1282 | -#endif | |
| 1274 | + cpu_physical_memory_reset_dirty(ram_addr, | |
| 1275 | + ram_addr + TARGET_PAGE_SIZE, | |
| 1276 | + CODE_DIRTY_FLAG); | |
| 1283 | 1277 | } |
| 1284 | 1278 | |
| 1285 | 1279 | /* update the TLB so that writes in physical page 'phys_addr' are no longer |
| ... | ... | @@ -1317,8 +1311,9 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, |
| 1317 | 1311 | if (length == 0) |
| 1318 | 1312 | return; |
| 1319 | 1313 | len = length >> TARGET_PAGE_BITS; |
| 1320 | - env = cpu_single_env; | |
| 1321 | 1314 | #ifdef USE_KQEMU |
| 1315 | + /* XXX: should not depend on cpu context */ | |
| 1316 | + env = first_cpu; | |
| 1322 | 1317 | if (env->kqemu_enabled) { |
| 1323 | 1318 | ram_addr_t addr; |
| 1324 | 1319 | addr = start; |
| ... | ... | @@ -1336,10 +1331,12 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, |
| 1336 | 1331 | /* we modify the TLB cache so that the dirty bit will be set again |
| 1337 | 1332 | when accessing the range */ |
| 1338 | 1333 | start1 = start + (unsigned long)phys_ram_base; |
| 1339 | - for(i = 0; i < CPU_TLB_SIZE; i++) | |
| 1340 | - tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length); | |
| 1341 | - for(i = 0; i < CPU_TLB_SIZE; i++) | |
| 1342 | - tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length); | |
| 1334 | + for(env = first_cpu; env != NULL; env = env->next_cpu) { | |
| 1335 | + for(i = 0; i < CPU_TLB_SIZE; i++) | |
| 1336 | + tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length); | |
| 1337 | + for(i = 0; i < CPU_TLB_SIZE; i++) | |
| 1338 | + tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length); | |
| 1339 | + } | |
| 1343 | 1340 | |
| 1344 | 1341 | #if !defined(CONFIG_SOFTMMU) |
| 1345 | 1342 | /* XXX: this is expensive */ |
| ... | ... | @@ -1407,9 +1404,9 @@ static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, |
| 1407 | 1404 | |
| 1408 | 1405 | /* update the TLB corresponding to virtual page vaddr and phys addr |
| 1409 | 1406 | addr so that it is no longer dirty */ |
| 1410 | -static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) | |
| 1407 | +static inline void tlb_set_dirty(CPUState *env, | |
| 1408 | + unsigned long addr, target_ulong vaddr) | |
| 1411 | 1409 | { |
| 1412 | - CPUState *env = cpu_single_env; | |
| 1413 | 1410 | int i; |
| 1414 | 1411 | |
| 1415 | 1412 | addr &= TARGET_PAGE_MASK; |
| ... | ... | @@ -1723,7 +1720,8 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size) |
| 1723 | 1720 | } |
| 1724 | 1721 | } |
| 1725 | 1722 | |
| 1726 | -static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) | |
| 1723 | +static inline void tlb_set_dirty(CPUState *env, | |
| 1724 | + unsigned long addr, target_ulong vaddr) | |
| 1727 | 1725 | { |
| 1728 | 1726 | } |
| 1729 | 1727 | #endif /* defined(CONFIG_USER_ONLY) */ |
| ... | ... | @@ -1787,7 +1785,7 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t |
| 1787 | 1785 | /* we remove the notdirty callback only if the code has been |
| 1788 | 1786 | flushed */ |
| 1789 | 1787 | if (dirty_flags == 0xff) |
| 1790 | - tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); | |
| 1788 | + tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr); | |
| 1791 | 1789 | } |
| 1792 | 1790 | |
| 1793 | 1791 | static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) |
| ... | ... | @@ -1808,7 +1806,7 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t |
| 1808 | 1806 | /* we remove the notdirty callback only if the code has been |
| 1809 | 1807 | flushed */ |
| 1810 | 1808 | if (dirty_flags == 0xff) |
| 1811 | - tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); | |
| 1809 | + tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr); | |
| 1812 | 1810 | } |
| 1813 | 1811 | |
| 1814 | 1812 | static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
| ... | ... | @@ -1829,7 +1827,7 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t |
| 1829 | 1827 | /* we remove the notdirty callback only if the code has been |
| 1830 | 1828 | flushed */ |
| 1831 | 1829 | if (dirty_flags == 0xff) |
| 1832 | - tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); | |
| 1830 | + tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr); | |
| 1833 | 1831 | } |
| 1834 | 1832 | |
| 1835 | 1833 | static CPUReadMemoryFunc *error_mem_read[3] = { |
| ... | ... | @@ -1953,6 +1951,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, |
| 1953 | 1951 | if (is_write) { |
| 1954 | 1952 | if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { |
| 1955 | 1953 | io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); |
| 1954 | + /* XXX: could force cpu_single_env to NULL to avoid | |
| 1955 | + potential bugs */ | |
| 1956 | 1956 | if (l >= 4 && ((addr & 3) == 0)) { |
| 1957 | 1957 | /* 32 bit write access */ |
| 1958 | 1958 | val = ldl_p(buf); | ... | ... |
gdbstub.c
| ... | ... | @@ -47,6 +47,7 @@ enum RSState { |
| 47 | 47 | static int gdbserver_fd = -1; |
| 48 | 48 | |
| 49 | 49 | typedef struct GDBState { |
| 50 | + CPUState *env; /* current CPU */ | |
| 50 | 51 | enum RSState state; /* parsing state */ |
| 51 | 52 | int fd; |
| 52 | 53 | char line_buf[4096]; |
| ... | ... | @@ -576,10 +577,10 @@ static void gdb_vm_stopped(void *opaque, int reason) |
| 576 | 577 | int ret; |
| 577 | 578 | |
| 578 | 579 | /* disable single step if it was enable */ |
| 579 | - cpu_single_step(cpu_single_env, 0); | |
| 580 | + cpu_single_step(s->env, 0); | |
| 580 | 581 | |
| 581 | 582 | if (reason == EXCP_DEBUG) { |
| 582 | - tb_flush(cpu_single_env); | |
| 583 | + tb_flush(s->env); | |
| 583 | 584 | ret = SIGTRAP; |
| 584 | 585 | } |
| 585 | 586 | else |
| ... | ... | @@ -589,8 +590,9 @@ static void gdb_vm_stopped(void *opaque, int reason) |
| 589 | 590 | } |
| 590 | 591 | #endif |
| 591 | 592 | |
| 592 | -static void gdb_read_byte(GDBState *s, CPUState *env, int ch) | |
| 593 | +static void gdb_read_byte(GDBState *s, int ch) | |
| 593 | 594 | { |
| 595 | + CPUState *env = s->env; | |
| 594 | 596 | int i, csum; |
| 595 | 597 | char reply[1]; |
| 596 | 598 | |
| ... | ... | @@ -676,7 +678,7 @@ gdb_handlesig (CPUState *env, int sig) |
| 676 | 678 | int i; |
| 677 | 679 | |
| 678 | 680 | for (i = 0; i < n; i++) |
| 679 | - gdb_read_byte (s, env, buf[i]); | |
| 681 | + gdb_read_byte (s, buf[i]); | |
| 680 | 682 | } |
| 681 | 683 | else if (n == 0 || errno != EAGAIN) |
| 682 | 684 | { |
| ... | ... | @@ -721,7 +723,7 @@ static void gdb_read(void *opaque) |
| 721 | 723 | vm_start(); |
| 722 | 724 | } else { |
| 723 | 725 | for(i = 0; i < size; i++) |
| 724 | - gdb_read_byte(s, cpu_single_env, buf[i]); | |
| 726 | + gdb_read_byte(s, buf[i]); | |
| 725 | 727 | } |
| 726 | 728 | } |
| 727 | 729 | |
| ... | ... | @@ -759,6 +761,7 @@ static void gdb_accept(void *opaque) |
| 759 | 761 | return; |
| 760 | 762 | } |
| 761 | 763 | #endif |
| 764 | + s->env = first_cpu; /* XXX: allow to change CPU */ | |
| 762 | 765 | s->fd = fd; |
| 763 | 766 | |
| 764 | 767 | fcntl(fd, F_SETFL, O_NONBLOCK); | ... | ... |
monitor.c
| ... | ... | @@ -64,6 +64,8 @@ static int term_outbuf_index; |
| 64 | 64 | |
| 65 | 65 | static void monitor_start_input(void); |
| 66 | 66 | |
| 67 | +CPUState *mon_cpu = NULL; | |
| 68 | + | |
| 67 | 69 | void term_flush(void) |
| 68 | 70 | { |
| 69 | 71 | if (term_outbuf_index > 0) { |
| ... | ... | @@ -201,17 +203,69 @@ static void do_info_block(void) |
| 201 | 203 | bdrv_info(); |
| 202 | 204 | } |
| 203 | 205 | |
| 206 | +/* get the current CPU defined by the user */ | |
| 207 | +int mon_set_cpu(int cpu_index) | |
| 208 | +{ | |
| 209 | + CPUState *env; | |
| 210 | + | |
| 211 | + for(env = first_cpu; env != NULL; env = env->next_cpu) { | |
| 212 | + if (env->cpu_index == cpu_index) { | |
| 213 | + mon_cpu = env; | |
| 214 | + return 0; | |
| 215 | + } | |
| 216 | + } | |
| 217 | + return -1; | |
| 218 | +} | |
| 219 | + | |
| 220 | +CPUState *mon_get_cpu(void) | |
| 221 | +{ | |
| 222 | + if (!mon_cpu) { | |
| 223 | + mon_set_cpu(0); | |
| 224 | + } | |
| 225 | + return mon_cpu; | |
| 226 | +} | |
| 227 | + | |
| 204 | 228 | static void do_info_registers(void) |
| 205 | 229 | { |
| 230 | + CPUState *env; | |
| 231 | + env = mon_get_cpu(); | |
| 232 | + if (!env) | |
| 233 | + return; | |
| 206 | 234 | #ifdef TARGET_I386 |
| 207 | - cpu_dump_state(cpu_single_env, NULL, monitor_fprintf, | |
| 235 | + cpu_dump_state(env, NULL, monitor_fprintf, | |
| 208 | 236 | X86_DUMP_FPU); |
| 209 | 237 | #else |
| 210 | - cpu_dump_state(cpu_single_env, NULL, monitor_fprintf, | |
| 238 | + cpu_dump_state(env, NULL, monitor_fprintf, | |
| 211 | 239 | 0); |
| 212 | 240 | #endif |
| 213 | 241 | } |
| 214 | 242 | |
| 243 | +static void do_info_cpus(void) | |
| 244 | +{ | |
| 245 | + CPUState *env; | |
| 246 | + | |
| 247 | + /* just to set the default cpu if not already done */ | |
| 248 | + mon_get_cpu(); | |
| 249 | + | |
| 250 | + for(env = first_cpu; env != NULL; env = env->next_cpu) { | |
| 251 | + term_printf("%c CPU #%d:", | |
| 252 | + (env == mon_cpu) ? '*' : ' ', | |
| 253 | + env->cpu_index); | |
| 254 | +#if defined(TARGET_I386) | |
| 255 | + term_printf(" pc=0x" TARGET_FMT_lx, env->eip + env->segs[R_CS].base); | |
| 256 | + if (env->cpu_halted) | |
| 257 | + term_printf(" (halted)"); | |
| 258 | +#endif | |
| 259 | + term_printf("\n"); | |
| 260 | + } | |
| 261 | +} | |
| 262 | + | |
| 263 | +static void do_cpu_set(int index) | |
| 264 | +{ | |
| 265 | + if (mon_set_cpu(index) < 0) | |
| 266 | + term_printf("Invalid CPU index\n"); | |
| 267 | +} | |
| 268 | + | |
| 215 | 269 | static void do_info_jit(void) |
| 216 | 270 | { |
| 217 | 271 | dump_exec_info(NULL, monitor_fprintf); |
| ... | ... | @@ -381,6 +435,7 @@ static void term_printc(int c) |
| 381 | 435 | static void memory_dump(int count, int format, int wsize, |
| 382 | 436 | target_ulong addr, int is_physical) |
| 383 | 437 | { |
| 438 | + CPUState *env; | |
| 384 | 439 | int nb_per_line, l, line_size, i, max_digits, len; |
| 385 | 440 | uint8_t buf[16]; |
| 386 | 441 | uint64_t v; |
| ... | ... | @@ -388,19 +443,22 @@ static void memory_dump(int count, int format, int wsize, |
| 388 | 443 | if (format == 'i') { |
| 389 | 444 | int flags; |
| 390 | 445 | flags = 0; |
| 446 | + env = mon_get_cpu(); | |
| 447 | + if (!env && !is_physical) | |
| 448 | + return; | |
| 391 | 449 | #ifdef TARGET_I386 |
| 392 | 450 | if (wsize == 2) { |
| 393 | 451 | flags = 1; |
| 394 | 452 | } else if (wsize == 4) { |
| 395 | 453 | flags = 0; |
| 396 | 454 | } else { |
| 397 | - /* as default we use the current CS size */ | |
| 455 | + /* as default we use the current CS size */ | |
| 398 | 456 | flags = 0; |
| 399 | - if (!(cpu_single_env->segs[R_CS].flags & DESC_B_MASK)) | |
| 457 | + if (env && !(env->segs[R_CS].flags & DESC_B_MASK)) | |
| 400 | 458 | flags = 1; |
| 401 | 459 | } |
| 402 | 460 | #endif |
| 403 | - monitor_disas(addr, count, is_physical, flags); | |
| 461 | + monitor_disas(env, addr, count, is_physical, flags); | |
| 404 | 462 | return; |
| 405 | 463 | } |
| 406 | 464 | |
| ... | ... | @@ -437,7 +495,10 @@ static void memory_dump(int count, int format, int wsize, |
| 437 | 495 | if (is_physical) { |
| 438 | 496 | cpu_physical_memory_rw(addr, buf, l, 0); |
| 439 | 497 | } else { |
| 440 | - cpu_memory_rw_debug(cpu_single_env, addr, buf, l, 0); | |
| 498 | + env = mon_get_cpu(); | |
| 499 | + if (!env) | |
| 500 | + break; | |
| 501 | + cpu_memory_rw_debug(env, addr, buf, l, 0); | |
| 441 | 502 | } |
| 442 | 503 | i = 0; |
| 443 | 504 | while (i < l) { |
| ... | ... | @@ -776,10 +837,14 @@ static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask) |
| 776 | 837 | |
| 777 | 838 | static void tlb_info(void) |
| 778 | 839 | { |
| 779 | - CPUState *env = cpu_single_env; | |
| 840 | + CPUState *env; | |
| 780 | 841 | int l1, l2; |
| 781 | 842 | uint32_t pgd, pde, pte; |
| 782 | 843 | |
| 844 | + env = mon_get_cpu(); | |
| 845 | + if (!env) | |
| 846 | + return; | |
| 847 | + | |
| 783 | 848 | if (!(env->cr[0] & CR0_PG_MASK)) { |
| 784 | 849 | term_printf("PG disabled\n"); |
| 785 | 850 | return; |
| ... | ... | @@ -830,10 +895,14 @@ static void mem_print(uint32_t *pstart, int *plast_prot, |
| 830 | 895 | |
| 831 | 896 | static void mem_info(void) |
| 832 | 897 | { |
| 833 | - CPUState *env = cpu_single_env; | |
| 898 | + CPUState *env; | |
| 834 | 899 | int l1, l2, prot, last_prot; |
| 835 | 900 | uint32_t pgd, pde, pte, start, end; |
| 836 | 901 | |
| 902 | + env = mon_get_cpu(); | |
| 903 | + if (!env) | |
| 904 | + return; | |
| 905 | + | |
| 837 | 906 | if (!(env->cr[0] & CR0_PG_MASK)) { |
| 838 | 907 | term_printf("PG disabled\n"); |
| 839 | 908 | return; |
| ... | ... | @@ -874,10 +943,15 @@ static void mem_info(void) |
| 874 | 943 | static void do_info_kqemu(void) |
| 875 | 944 | { |
| 876 | 945 | #ifdef USE_KQEMU |
| 946 | + CPUState *env; | |
| 877 | 947 | int val; |
| 878 | 948 | val = 0; |
| 879 | - if (cpu_single_env) | |
| 880 | - val = cpu_single_env->kqemu_enabled; | |
| 949 | + env = mon_get_cpu(); | |
| 950 | + if (!env) { | |
| 951 | + term_printf("No cpu initialized yet"); | |
| 952 | + return; | |
| 953 | + } | |
| 954 | + val = env->kqemu_enabled; | |
| 881 | 955 | term_printf("kqemu is %s\n", val ? "enabled" : "disabled"); |
| 882 | 956 | #else |
| 883 | 957 | term_printf("kqemu support is not compiled\n"); |
| ... | ... | @@ -934,6 +1008,8 @@ static term_cmd_t term_cmds[] = { |
| 934 | 1008 | "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" }, |
| 935 | 1009 | { "usb_del", "s", do_usb_del, |
| 936 | 1010 | "device", "remove USB device 'bus.addr'" }, |
| 1011 | + { "cpu", "i", do_cpu_set, | |
| 1012 | + "index", "set the default CPU" }, | |
| 937 | 1013 | { NULL, NULL, }, |
| 938 | 1014 | }; |
| 939 | 1015 | |
| ... | ... | @@ -946,6 +1022,8 @@ static term_cmd_t info_cmds[] = { |
| 946 | 1022 | "", "show the block devices" }, |
| 947 | 1023 | { "registers", "", do_info_registers, |
| 948 | 1024 | "", "show the cpu registers" }, |
| 1025 | + { "cpus", "", do_info_cpus, | |
| 1026 | + "", "show infos for each CPU" }, | |
| 949 | 1027 | { "history", "", do_info_history, |
| 950 | 1028 | "", "show the command line history", }, |
| 951 | 1029 | { "irq", "", irq_info, |
| ... | ... | @@ -989,63 +1067,85 @@ typedef struct MonitorDef { |
| 989 | 1067 | #if defined(TARGET_I386) |
| 990 | 1068 | static target_long monitor_get_pc (struct MonitorDef *md, int val) |
| 991 | 1069 | { |
| 992 | - return cpu_single_env->eip + cpu_single_env->segs[R_CS].base; | |
| 1070 | + CPUState *env = mon_get_cpu(); | |
| 1071 | + if (!env) | |
| 1072 | + return 0; | |
| 1073 | + return env->eip + env->segs[R_CS].base; | |
| 993 | 1074 | } |
| 994 | 1075 | #endif |
| 995 | 1076 | |
| 996 | 1077 | #if defined(TARGET_PPC) |
| 997 | 1078 | static target_long monitor_get_ccr (struct MonitorDef *md, int val) |
| 998 | 1079 | { |
| 1080 | + CPUState *env = mon_get_cpu(); | |
| 999 | 1081 | unsigned int u; |
| 1000 | 1082 | int i; |
| 1001 | 1083 | |
| 1084 | + if (!env) | |
| 1085 | + return 0; | |
| 1086 | + | |
| 1002 | 1087 | u = 0; |
| 1003 | 1088 | for (i = 0; i < 8; i++) |
| 1004 | - u |= cpu_single_env->crf[i] << (32 - (4 * i)); | |
| 1089 | + u |= env->crf[i] << (32 - (4 * i)); | |
| 1005 | 1090 | |
| 1006 | 1091 | return u; |
| 1007 | 1092 | } |
| 1008 | 1093 | |
| 1009 | 1094 | static target_long monitor_get_msr (struct MonitorDef *md, int val) |
| 1010 | 1095 | { |
| 1011 | - return (cpu_single_env->msr[MSR_POW] << MSR_POW) | | |
| 1012 | - (cpu_single_env->msr[MSR_ILE] << MSR_ILE) | | |
| 1013 | - (cpu_single_env->msr[MSR_EE] << MSR_EE) | | |
| 1014 | - (cpu_single_env->msr[MSR_PR] << MSR_PR) | | |
| 1015 | - (cpu_single_env->msr[MSR_FP] << MSR_FP) | | |
| 1016 | - (cpu_single_env->msr[MSR_ME] << MSR_ME) | | |
| 1017 | - (cpu_single_env->msr[MSR_FE0] << MSR_FE0) | | |
| 1018 | - (cpu_single_env->msr[MSR_SE] << MSR_SE) | | |
| 1019 | - (cpu_single_env->msr[MSR_BE] << MSR_BE) | | |
| 1020 | - (cpu_single_env->msr[MSR_FE1] << MSR_FE1) | | |
| 1021 | - (cpu_single_env->msr[MSR_IP] << MSR_IP) | | |
| 1022 | - (cpu_single_env->msr[MSR_IR] << MSR_IR) | | |
| 1023 | - (cpu_single_env->msr[MSR_DR] << MSR_DR) | | |
| 1024 | - (cpu_single_env->msr[MSR_RI] << MSR_RI) | | |
| 1025 | - (cpu_single_env->msr[MSR_LE] << MSR_LE); | |
| 1096 | + CPUState *env = mon_get_cpu(); | |
| 1097 | + if (!env) | |
| 1098 | + return 0; | |
| 1099 | + return (env->msr[MSR_POW] << MSR_POW) | | |
| 1100 | + (env->msr[MSR_ILE] << MSR_ILE) | | |
| 1101 | + (env->msr[MSR_EE] << MSR_EE) | | |
| 1102 | + (env->msr[MSR_PR] << MSR_PR) | | |
| 1103 | + (env->msr[MSR_FP] << MSR_FP) | | |
| 1104 | + (env->msr[MSR_ME] << MSR_ME) | | |
| 1105 | + (env->msr[MSR_FE0] << MSR_FE0) | | |
| 1106 | + (env->msr[MSR_SE] << MSR_SE) | | |
| 1107 | + (env->msr[MSR_BE] << MSR_BE) | | |
| 1108 | + (env->msr[MSR_FE1] << MSR_FE1) | | |
| 1109 | + (env->msr[MSR_IP] << MSR_IP) | | |
| 1110 | + (env->msr[MSR_IR] << MSR_IR) | | |
| 1111 | + (env->msr[MSR_DR] << MSR_DR) | | |
| 1112 | + (env->msr[MSR_RI] << MSR_RI) | | |
| 1113 | + (env->msr[MSR_LE] << MSR_LE); | |
| 1026 | 1114 | } |
| 1027 | 1115 | |
| 1028 | 1116 | static target_long monitor_get_xer (struct MonitorDef *md, int val) |
| 1029 | 1117 | { |
| 1030 | - return (cpu_single_env->xer[XER_SO] << XER_SO) | | |
| 1031 | - (cpu_single_env->xer[XER_OV] << XER_OV) | | |
| 1032 | - (cpu_single_env->xer[XER_CA] << XER_CA) | | |
| 1033 | - (cpu_single_env->xer[XER_BC] << XER_BC); | |
| 1118 | + CPUState *env = mon_get_cpu(); | |
| 1119 | + if (!env) | |
| 1120 | + return 0; | |
| 1121 | + return (env->xer[XER_SO] << XER_SO) | | |
| 1122 | + (env->xer[XER_OV] << XER_OV) | | |
| 1123 | + (env->xer[XER_CA] << XER_CA) | | |
| 1124 | + (env->xer[XER_BC] << XER_BC); | |
| 1034 | 1125 | } |
| 1035 | 1126 | |
| 1036 | 1127 | static target_long monitor_get_decr (struct MonitorDef *md, int val) |
| 1037 | 1128 | { |
| 1038 | - return cpu_ppc_load_decr(cpu_single_env); | |
| 1129 | + CPUState *env = mon_get_cpu(); | |
| 1130 | + if (!env) | |
| 1131 | + return 0; | |
| 1132 | + return cpu_ppc_load_decr(env); | |
| 1039 | 1133 | } |
| 1040 | 1134 | |
| 1041 | 1135 | static target_long monitor_get_tbu (struct MonitorDef *md, int val) |
| 1042 | 1136 | { |
| 1043 | - return cpu_ppc_load_tbu(cpu_single_env); | |
| 1137 | + CPUState *env = mon_get_cpu(); | |
| 1138 | + if (!env) | |
| 1139 | + return 0; | |
| 1140 | + return cpu_ppc_load_tbu(env); | |
| 1044 | 1141 | } |
| 1045 | 1142 | |
| 1046 | 1143 | static target_long monitor_get_tbl (struct MonitorDef *md, int val) |
| 1047 | 1144 | { |
| 1048 | - return cpu_ppc_load_tbl(cpu_single_env); | |
| 1145 | + CPUState *env = mon_get_cpu(); | |
| 1146 | + if (!env) | |
| 1147 | + return 0; | |
| 1148 | + return cpu_ppc_load_tbl(env); | |
| 1049 | 1149 | } |
| 1050 | 1150 | #endif |
| 1051 | 1151 | |
| ... | ... | @@ -1053,13 +1153,19 @@ static target_long monitor_get_tbl (struct MonitorDef *md, int val) |
| 1053 | 1153 | #ifndef TARGET_SPARC64 |
| 1054 | 1154 | static target_long monitor_get_psr (struct MonitorDef *md, int val) |
| 1055 | 1155 | { |
| 1056 | - return GET_PSR(cpu_single_env); | |
| 1156 | + CPUState *env = mon_get_cpu(); | |
| 1157 | + if (!env) | |
| 1158 | + return 0; | |
| 1159 | + return GET_PSR(env); | |
| 1057 | 1160 | } |
| 1058 | 1161 | #endif |
| 1059 | 1162 | |
| 1060 | 1163 | static target_long monitor_get_reg(struct MonitorDef *md, int val) |
| 1061 | 1164 | { |
| 1062 | - return cpu_single_env->regwptr[val]; | |
| 1165 | + CPUState *env = mon_get_cpu(); | |
| 1166 | + if (!env) | |
| 1167 | + return 0; | |
| 1168 | + return env->regwptr[val]; | |
| 1063 | 1169 | } |
| 1064 | 1170 | #endif |
| 1065 | 1171 | |
| ... | ... | @@ -1269,6 +1375,7 @@ static void expr_error(const char *fmt) |
| 1269 | 1375 | longjmp(expr_env, 1); |
| 1270 | 1376 | } |
| 1271 | 1377 | |
| 1378 | +/* return 0 if OK, -1 if not found, -2 if no CPU defined */ | |
| 1272 | 1379 | static int get_monitor_def(target_long *pval, const char *name) |
| 1273 | 1380 | { |
| 1274 | 1381 | MonitorDef *md; |
| ... | ... | @@ -1279,7 +1386,10 @@ static int get_monitor_def(target_long *pval, const char *name) |
| 1279 | 1386 | if (md->get_value) { |
| 1280 | 1387 | *pval = md->get_value(md, md->offset); |
| 1281 | 1388 | } else { |
| 1282 | - ptr = (uint8_t *)cpu_single_env + md->offset; | |
| 1389 | + CPUState *env = mon_get_cpu(); | |
| 1390 | + if (!env) | |
| 1391 | + return -2; | |
| 1392 | + ptr = (uint8_t *)env + md->offset; | |
| 1283 | 1393 | switch(md->type) { |
| 1284 | 1394 | case MD_I32: |
| 1285 | 1395 | *pval = *(int32_t *)ptr; |
| ... | ... | @@ -1313,6 +1423,7 @@ static target_long expr_unary(void) |
| 1313 | 1423 | { |
| 1314 | 1424 | target_long n; |
| 1315 | 1425 | char *p; |
| 1426 | + int ret; | |
| 1316 | 1427 | |
| 1317 | 1428 | switch(*pch) { |
| 1318 | 1429 | case '+': |
| ... | ... | @@ -1362,8 +1473,11 @@ static target_long expr_unary(void) |
| 1362 | 1473 | while (isspace(*pch)) |
| 1363 | 1474 | pch++; |
| 1364 | 1475 | *q = 0; |
| 1365 | - if (get_monitor_def(&n, buf)) | |
| 1476 | + ret = get_monitor_def(&n, buf); | |
| 1477 | + if (ret == -1) | |
| 1366 | 1478 | expr_error("unknown register"); |
| 1479 | + else if (ret == -2) | |
| 1480 | + expr_error("no cpu defined"); | |
| 1367 | 1481 | } |
| 1368 | 1482 | break; |
| 1369 | 1483 | case '\0': | ... | ... |
vl.c
| ... | ... | @@ -83,8 +83,6 @@ |
| 83 | 83 | |
| 84 | 84 | #include "exec-all.h" |
| 85 | 85 | |
| 86 | -//#define DO_TB_FLUSH | |
| 87 | - | |
| 88 | 86 | #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" |
| 89 | 87 | |
| 90 | 88 | //#define DEBUG_UNUSED_IOPORT |
| ... | ... | @@ -109,8 +107,6 @@ |
| 109 | 107 | |
| 110 | 108 | const char *bios_dir = CONFIG_QEMU_SHAREDIR; |
| 111 | 109 | char phys_ram_file[1024]; |
| 112 | -CPUState *global_env; | |
| 113 | -CPUState *cpu_single_env; | |
| 114 | 110 | void *ioport_opaque[MAX_IOPORTS]; |
| 115 | 111 | IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; |
| 116 | 112 | IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; |
| ... | ... | @@ -156,6 +152,7 @@ int usb_enabled = 0; |
| 156 | 152 | USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; |
| 157 | 153 | USBDevice *vm_usb_hub; |
| 158 | 154 | static VLANState *first_vlan; |
| 155 | +int smp_cpus = 1; | |
| 159 | 156 | |
| 160 | 157 | /***********************************************************/ |
| 161 | 158 | /* x86 ISA bus support */ |
| ... | ... | @@ -427,16 +424,20 @@ int cpu_inl(CPUState *env, int addr) |
| 427 | 424 | void hw_error(const char *fmt, ...) |
| 428 | 425 | { |
| 429 | 426 | va_list ap; |
| 427 | + CPUState *env; | |
| 430 | 428 | |
| 431 | 429 | va_start(ap, fmt); |
| 432 | 430 | fprintf(stderr, "qemu: hardware error: "); |
| 433 | 431 | vfprintf(stderr, fmt, ap); |
| 434 | 432 | fprintf(stderr, "\n"); |
| 433 | + for(env = first_cpu; env != NULL; env = env->next_cpu) { | |
| 434 | + fprintf(stderr, "CPU #%d:\n", env->cpu_index); | |
| 435 | 435 | #ifdef TARGET_I386 |
| 436 | - cpu_dump_state(global_env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); | |
| 436 | + cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU); | |
| 437 | 437 | #else |
| 438 | - cpu_dump_state(global_env, stderr, fprintf, 0); | |
| 438 | + cpu_dump_state(env, stderr, fprintf, 0); | |
| 439 | 439 | #endif |
| 440 | + } | |
| 440 | 441 | va_end(ap); |
| 441 | 442 | abort(); |
| 442 | 443 | } |
| ... | ... | @@ -879,13 +880,16 @@ static void host_alarm_handler(int host_signum) |
| 879 | 880 | qemu_get_clock(vm_clock)) || |
| 880 | 881 | qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], |
| 881 | 882 | qemu_get_clock(rt_clock))) { |
| 882 | - /* stop the cpu because a timer occured */ | |
| 883 | - cpu_interrupt(global_env, CPU_INTERRUPT_EXIT); | |
| 883 | + CPUState *env = cpu_single_env; | |
| 884 | + if (env) { | |
| 885 | + /* stop the currently executing cpu because a timer occured */ | |
| 886 | + cpu_interrupt(env, CPU_INTERRUPT_EXIT); | |
| 884 | 887 | #ifdef USE_KQEMU |
| 885 | - if (global_env->kqemu_enabled) { | |
| 886 | - kqemu_cpu_interrupt(global_env); | |
| 887 | - } | |
| 888 | + if (env->kqemu_enabled) { | |
| 889 | + kqemu_cpu_interrupt(env); | |
| 890 | + } | |
| 888 | 891 | #endif |
| 892 | + } | |
| 889 | 893 | } |
| 890 | 894 | } |
| 891 | 895 | |
| ... | ... | @@ -2970,9 +2974,6 @@ int qemu_loadvm(const char *filename) |
| 2970 | 2974 | goto the_end; |
| 2971 | 2975 | } |
| 2972 | 2976 | for(;;) { |
| 2973 | -#if defined (DO_TB_FLUSH) | |
| 2974 | - tb_flush(global_env); | |
| 2975 | -#endif | |
| 2976 | 2977 | len = qemu_get_byte(f); |
| 2977 | 2978 | if (feof(f)) |
| 2978 | 2979 | break; |
| ... | ... | @@ -3583,27 +3584,22 @@ void qemu_system_reset(void) |
| 3583 | 3584 | void qemu_system_reset_request(void) |
| 3584 | 3585 | { |
| 3585 | 3586 | reset_requested = 1; |
| 3586 | - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); | |
| 3587 | + if (cpu_single_env) | |
| 3588 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); | |
| 3587 | 3589 | } |
| 3588 | 3590 | |
| 3589 | 3591 | void qemu_system_shutdown_request(void) |
| 3590 | 3592 | { |
| 3591 | 3593 | shutdown_requested = 1; |
| 3592 | - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); | |
| 3594 | + if (cpu_single_env) | |
| 3595 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); | |
| 3593 | 3596 | } |
| 3594 | 3597 | |
| 3595 | 3598 | void qemu_system_powerdown_request(void) |
| 3596 | 3599 | { |
| 3597 | 3600 | powerdown_requested = 1; |
| 3598 | - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); | |
| 3599 | -} | |
| 3600 | - | |
| 3601 | -static void main_cpu_reset(void *opaque) | |
| 3602 | -{ | |
| 3603 | -#if defined(TARGET_I386) || defined(TARGET_SPARC) | |
| 3604 | - CPUState *env = opaque; | |
| 3605 | - cpu_reset(env); | |
| 3606 | -#endif | |
| 3601 | + if (cpu_single_env) | |
| 3602 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); | |
| 3607 | 3603 | } |
| 3608 | 3604 | |
| 3609 | 3605 | void main_loop_wait(int timeout) |
| ... | ... | @@ -3684,14 +3680,42 @@ void main_loop_wait(int timeout) |
| 3684 | 3680 | qemu_get_clock(rt_clock)); |
| 3685 | 3681 | } |
| 3686 | 3682 | |
| 3683 | +static CPUState *cur_cpu; | |
| 3684 | + | |
| 3685 | +static CPUState *find_next_cpu(void) | |
| 3686 | +{ | |
| 3687 | + CPUState *env; | |
| 3688 | + env = cur_cpu; | |
| 3689 | + for(;;) { | |
| 3690 | + /* get next cpu */ | |
| 3691 | + env = env->next_cpu; | |
| 3692 | + if (!env) | |
| 3693 | + env = first_cpu; | |
| 3694 | + if (!env->cpu_halted) | |
| 3695 | + break; | |
| 3696 | + /* all CPUs are halted ? */ | |
| 3697 | + if (env == cur_cpu) | |
| 3698 | + return NULL; | |
| 3699 | + } | |
| 3700 | + cur_cpu = env; | |
| 3701 | + return env; | |
| 3702 | +} | |
| 3703 | + | |
| 3687 | 3704 | int main_loop(void) |
| 3688 | 3705 | { |
| 3689 | 3706 | int ret, timeout; |
| 3690 | - CPUState *env = global_env; | |
| 3707 | + CPUState *env; | |
| 3691 | 3708 | |
| 3709 | + cur_cpu = first_cpu; | |
| 3692 | 3710 | for(;;) { |
| 3693 | 3711 | if (vm_running) { |
| 3694 | - ret = cpu_exec(env); | |
| 3712 | + /* find next cpu to run */ | |
| 3713 | + /* XXX: handle HLT correctly */ | |
| 3714 | + env = find_next_cpu(); | |
| 3715 | + if (!env) | |
| 3716 | + ret = EXCP_HLT; | |
| 3717 | + else | |
| 3718 | + ret = cpu_exec(env); | |
| 3695 | 3719 | if (shutdown_requested) { |
| 3696 | 3720 | ret = EXCP_INTERRUPT; |
| 3697 | 3721 | break; |
| ... | ... | @@ -3774,7 +3798,7 @@ void help(void) |
| 3774 | 3798 | " connect the host TAP network interface to VLAN 'n' and use\n" |
| 3775 | 3799 | " the network script 'file' (default=%s);\n" |
| 3776 | 3800 | " use 'fd=h' to connect to an already opened TAP interface\n" |
| 3777 | - "-net socket[,vlan=n][,fd=x][,listen=[host]:port][,connect=host:port]\n" | |
| 3801 | + "-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n" | |
| 3778 | 3802 | " connect the vlan 'n' to another VLAN using a socket connection\n" |
| 3779 | 3803 | #endif |
| 3780 | 3804 | "-net none use it alone to have zero network devices; if no -net option\n" |
| ... | ... | @@ -3899,6 +3923,7 @@ enum { |
| 3899 | 3923 | QEMU_OPTION_win2k_hack, |
| 3900 | 3924 | QEMU_OPTION_usb, |
| 3901 | 3925 | QEMU_OPTION_usbdevice, |
| 3926 | + QEMU_OPTION_smp, | |
| 3902 | 3927 | }; |
| 3903 | 3928 | |
| 3904 | 3929 | typedef struct QEMUOption { |
| ... | ... | @@ -3965,6 +3990,7 @@ const QEMUOption qemu_options[] = { |
| 3965 | 3990 | { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, |
| 3966 | 3991 | { "win2k-hack", 0, QEMU_OPTION_win2k_hack }, |
| 3967 | 3992 | { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, |
| 3993 | + { "smp", HAS_ARG, QEMU_OPTION_smp }, | |
| 3968 | 3994 | |
| 3969 | 3995 | /* temporary options */ |
| 3970 | 3996 | { "usb", 0, QEMU_OPTION_usb }, |
| ... | ... | @@ -4120,7 +4146,6 @@ int main(int argc, char **argv) |
| 4120 | 4146 | #endif |
| 4121 | 4147 | int i, cdrom_index; |
| 4122 | 4148 | int snapshot, linux_boot; |
| 4123 | - CPUState *env; | |
| 4124 | 4149 | const char *initrd_filename; |
| 4125 | 4150 | const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; |
| 4126 | 4151 | const char *kernel_filename, *kernel_cmdline; |
| ... | ... | @@ -4511,6 +4536,13 @@ int main(int argc, char **argv) |
| 4511 | 4536 | optarg); |
| 4512 | 4537 | usb_devices_index++; |
| 4513 | 4538 | break; |
| 4539 | + case QEMU_OPTION_smp: | |
| 4540 | + smp_cpus = atoi(optarg); | |
| 4541 | + if (smp_cpus < 1 || smp_cpus > 8) { | |
| 4542 | + fprintf(stderr, "Invalid number of CPUs\n"); | |
| 4543 | + exit(1); | |
| 4544 | + } | |
| 4545 | + break; | |
| 4514 | 4546 | } |
| 4515 | 4547 | } |
| 4516 | 4548 | } |
| ... | ... | @@ -4659,15 +4691,8 @@ int main(int argc, char **argv) |
| 4659 | 4691 | } |
| 4660 | 4692 | } |
| 4661 | 4693 | |
| 4662 | - /* init CPU state */ | |
| 4663 | - env = cpu_init(); | |
| 4664 | - global_env = env; | |
| 4665 | - cpu_single_env = env; | |
| 4666 | - | |
| 4667 | - register_savevm("timer", 0, 1, timer_save, timer_load, env); | |
| 4668 | - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); | |
| 4694 | + register_savevm("timer", 0, 1, timer_save, timer_load, NULL); | |
| 4669 | 4695 | register_savevm("ram", 0, 1, ram_save, ram_load, NULL); |
| 4670 | - qemu_register_reset(main_cpu_reset, global_env); | |
| 4671 | 4696 | |
| 4672 | 4697 | init_ioports(); |
| 4673 | 4698 | cpu_calibrate_ticks(); | ... | ... |
vl.h
| ... | ... | @@ -142,6 +142,7 @@ extern const char *keyboard_layout; |
| 142 | 142 | extern int kqemu_allowed; |
| 143 | 143 | extern int win2k_install_hack; |
| 144 | 144 | extern int usb_enabled; |
| 145 | +extern int smp_cpus; | |
| 145 | 146 | |
| 146 | 147 | /* XXX: make it dynamic */ |
| 147 | 148 | #if defined (TARGET_PPC) |
| ... | ... | @@ -429,6 +430,9 @@ int register_savevm(const char *idstr, |
| 429 | 430 | void qemu_get_timer(QEMUFile *f, QEMUTimer *ts); |
| 430 | 431 | void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); |
| 431 | 432 | |
| 433 | +void cpu_save(QEMUFile *f, void *opaque); | |
| 434 | +int cpu_load(QEMUFile *f, void *opaque, int version_id); | |
| 435 | + | |
| 432 | 436 | /* block.c */ |
| 433 | 437 | typedef struct BlockDriverState BlockDriverState; |
| 434 | 438 | typedef struct BlockDriver BlockDriver; |
| ... | ... | @@ -774,6 +778,9 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time); |
| 774 | 778 | extern QEMUMachine pc_machine; |
| 775 | 779 | extern QEMUMachine isapc_machine; |
| 776 | 780 | |
| 781 | +void ioport_set_a20(int enable); | |
| 782 | +int ioport_get_a20(void); | |
| 783 | + | |
| 777 | 784 | /* ppc.c */ |
| 778 | 785 | extern QEMUMachine prep_machine; |
| 779 | 786 | extern QEMUMachine core99_machine; | ... | ... |