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,6 +96,7 @@ typedef struct CPUTLBEntry { | ||
96 | 96 | ||
97 | #define CPU_COMMON \ | 97 | #define CPU_COMMON \ |
98 | struct TranslationBlock *current_tb; /* currently executing TB */ \ | 98 | struct TranslationBlock *current_tb; /* currently executing TB */ \ |
99 | + int cpu_halted; /* TRUE if cpu is halted (sleep mode) */ \ | ||
99 | /* soft mmu support */ \ | 100 | /* soft mmu support */ \ |
100 | /* in order to avoid passing too many arguments to the memory \ | 101 | /* in order to avoid passing too many arguments to the memory \ |
101 | write helpers, we store some rarely used information in the CPU \ | 102 | write helpers, we store some rarely used information in the CPU \ |
@@ -115,9 +116,9 @@ typedef struct CPUTLBEntry { | @@ -115,9 +116,9 @@ typedef struct CPUTLBEntry { | ||
115 | int nb_breakpoints; \ | 116 | int nb_breakpoints; \ |
116 | int singlestep_enabled; \ | 117 | int singlestep_enabled; \ |
117 | \ | 118 | \ |
119 | + void *next_cpu; /* next CPU sharing TB cache */ \ | ||
120 | + int cpu_index; /* CPU index (informative) */ \ | ||
118 | /* user data */ \ | 121 | /* user data */ \ |
119 | void *opaque; | 122 | void *opaque; |
120 | 123 | ||
121 | - | ||
122 | - | ||
123 | #endif | 124 | #endif |
cpu-exec.c
@@ -251,6 +251,8 @@ int cpu_exec(CPUState *env1) | @@ -251,6 +251,8 @@ int cpu_exec(CPUState *env1) | ||
251 | TranslationBlock *tb; | 251 | TranslationBlock *tb; |
252 | uint8_t *tc_ptr; | 252 | uint8_t *tc_ptr; |
253 | 253 | ||
254 | + cpu_single_env = env1; | ||
255 | + | ||
254 | /* first we save global registers */ | 256 | /* first we save global registers */ |
255 | saved_env = env; | 257 | saved_env = env; |
256 | env = env1; | 258 | env = env1; |
@@ -755,6 +757,8 @@ int cpu_exec(CPUState *env1) | @@ -755,6 +757,8 @@ int cpu_exec(CPUState *env1) | ||
755 | T2 = saved_T2; | 757 | T2 = saved_T2; |
756 | #endif | 758 | #endif |
757 | env = saved_env; | 759 | env = saved_env; |
760 | + /* fail safe : never use cpu_single_env outside cpu_exec() */ | ||
761 | + cpu_single_env = NULL; | ||
758 | return ret; | 762 | return ret; |
759 | } | 763 | } |
760 | 764 |
disas.c
@@ -138,6 +138,7 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info) | @@ -138,6 +138,7 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info) | ||
138 | values: | 138 | values: |
139 | i386 - nonzero means 16 bit code | 139 | i386 - nonzero means 16 bit code |
140 | arm - nonzero means thumb code | 140 | arm - nonzero means thumb code |
141 | + ppc - nonzero means little endian | ||
141 | other targets - unused | 142 | other targets - unused |
142 | */ | 143 | */ |
143 | void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) | 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,7 +178,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) | ||
177 | disasm_info.mach = bfd_mach_sparc_v9b; | 178 | disasm_info.mach = bfd_mach_sparc_v9b; |
178 | #endif | 179 | #endif |
179 | #elif defined(TARGET_PPC) | 180 | #elif defined(TARGET_PPC) |
180 | - if (cpu_single_env->msr[MSR_LE]) | 181 | + if (flags) |
181 | disasm_info.endian = BFD_ENDIAN_LITTLE; | 182 | disasm_info.endian = BFD_ENDIAN_LITTLE; |
182 | #ifdef TARGET_PPC64 | 183 | #ifdef TARGET_PPC64 |
183 | disasm_info.mach = bfd_mach_ppc64; | 184 | disasm_info.mach = bfd_mach_ppc64; |
@@ -314,6 +315,7 @@ void term_vprintf(const char *fmt, va_list ap); | @@ -314,6 +315,7 @@ void term_vprintf(const char *fmt, va_list ap); | ||
314 | void term_printf(const char *fmt, ...); | 315 | void term_printf(const char *fmt, ...); |
315 | 316 | ||
316 | static int monitor_disas_is_physical; | 317 | static int monitor_disas_is_physical; |
318 | +static CPUState *monitor_disas_env; | ||
317 | 319 | ||
318 | static int | 320 | static int |
319 | monitor_read_memory (memaddr, myaddr, length, info) | 321 | monitor_read_memory (memaddr, myaddr, length, info) |
@@ -325,7 +327,7 @@ monitor_read_memory (memaddr, myaddr, length, info) | @@ -325,7 +327,7 @@ monitor_read_memory (memaddr, myaddr, length, info) | ||
325 | if (monitor_disas_is_physical) { | 327 | if (monitor_disas_is_physical) { |
326 | cpu_physical_memory_rw(memaddr, myaddr, length, 0); | 328 | cpu_physical_memory_rw(memaddr, myaddr, length, 0); |
327 | } else { | 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 | return 0; | 332 | return 0; |
331 | } | 333 | } |
@@ -339,7 +341,8 @@ static int monitor_fprintf(FILE *stream, const char *fmt, ...) | @@ -339,7 +341,8 @@ static int monitor_fprintf(FILE *stream, const char *fmt, ...) | ||
339 | return 0; | 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 | int count, i; | 347 | int count, i; |
345 | struct disassemble_info disasm_info; | 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,6 +350,7 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags) | ||
347 | 350 | ||
348 | INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf); | 351 | INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf); |
349 | 352 | ||
353 | + monitor_disas_env = env; | ||
350 | monitor_disas_is_physical = is_physical; | 354 | monitor_disas_is_physical = is_physical; |
351 | disasm_info.read_memory_func = monitor_read_memory; | 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,7 +91,7 @@ int cpu_restore_state_copy(struct TranslationBlock *tb, | ||
91 | CPUState *env, unsigned long searched_pc, | 91 | CPUState *env, unsigned long searched_pc, |
92 | void *puc); | 92 | void *puc); |
93 | void cpu_resume_from_signal(CPUState *env1, void *puc); | 93 | void cpu_resume_from_signal(CPUState *env1, void *puc); |
94 | -void cpu_exec_init(void); | 94 | +void cpu_exec_init(CPUState *env); |
95 | int page_unprotect(unsigned long address, unsigned long pc, void *puc); | 95 | int page_unprotect(unsigned long address, unsigned long pc, void *puc); |
96 | void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, | 96 | void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, |
97 | int is_cpu_write_access); | 97 | int is_cpu_write_access); |
exec.c
@@ -74,6 +74,11 @@ int phys_ram_fd; | @@ -74,6 +74,11 @@ int phys_ram_fd; | ||
74 | uint8_t *phys_ram_base; | 74 | uint8_t *phys_ram_base; |
75 | uint8_t *phys_ram_dirty; | 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 | typedef struct PageDesc { | 82 | typedef struct PageDesc { |
78 | /* list of TBs intersecting this ram page */ | 83 | /* list of TBs intersecting this ram page */ |
79 | TranslationBlock *first_tb; | 84 | TranslationBlock *first_tb; |
@@ -233,19 +238,30 @@ static inline PhysPageDesc *phys_page_find(target_phys_addr_t index) | @@ -233,19 +238,30 @@ static inline PhysPageDesc *phys_page_find(target_phys_addr_t index) | ||
233 | } | 238 | } |
234 | 239 | ||
235 | #if !defined(CONFIG_USER_ONLY) | 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 | static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, | 242 | static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, |
239 | target_ulong vaddr); | 243 | target_ulong vaddr); |
240 | #endif | 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 | if (!code_gen_ptr) { | 251 | if (!code_gen_ptr) { |
245 | code_gen_ptr = code_gen_buffer; | 252 | code_gen_ptr = code_gen_buffer; |
246 | page_init(); | 253 | page_init(); |
247 | io_mem_init(); | 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 | static inline void invalidate_page_bitmap(PageDesc *p) | 267 | static inline void invalidate_page_bitmap(PageDesc *p) |
@@ -277,8 +293,9 @@ static void page_flush_tb(void) | @@ -277,8 +293,9 @@ static void page_flush_tb(void) | ||
277 | 293 | ||
278 | /* flush all the translation blocks */ | 294 | /* flush all the translation blocks */ |
279 | /* XXX: tb_flush is currently not thread safe */ | 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 | #if defined(DEBUG_FLUSH) | 299 | #if defined(DEBUG_FLUSH) |
283 | printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", | 300 | printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", |
284 | code_gen_ptr - code_gen_buffer, | 301 | code_gen_ptr - code_gen_buffer, |
@@ -286,7 +303,10 @@ void tb_flush(CPUState *env) | @@ -286,7 +303,10 @@ void tb_flush(CPUState *env) | ||
286 | nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); | 303 | nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); |
287 | #endif | 304 | #endif |
288 | nb_tbs = 0; | 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 | memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *)); | 311 | memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *)); |
292 | page_flush_tb(); | 312 | page_flush_tb(); |
@@ -424,6 +444,7 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n) | @@ -424,6 +444,7 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n) | ||
424 | 444 | ||
425 | static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr) | 445 | static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr) |
426 | { | 446 | { |
447 | + CPUState *env; | ||
427 | PageDesc *p; | 448 | PageDesc *p; |
428 | unsigned int h, n1; | 449 | unsigned int h, n1; |
429 | target_ulong phys_pc; | 450 | target_ulong phys_pc; |
@@ -451,7 +472,10 @@ static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_ad | @@ -451,7 +472,10 @@ static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_ad | ||
451 | 472 | ||
452 | /* remove the TB from the hash list */ | 473 | /* remove the TB from the hash list */ |
453 | h = tb_jmp_cache_hash_func(tb->pc); | 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 | /* suppress this TB from the two jump lists */ | 480 | /* suppress this TB from the two jump lists */ |
457 | tb_jmp_remove(tb, 0); | 481 | tb_jmp_remove(tb, 0); |
@@ -818,10 +842,7 @@ static inline void tb_alloc_page(TranslationBlock *tb, | @@ -818,10 +842,7 @@ static inline void tb_alloc_page(TranslationBlock *tb, | ||
818 | protected. So we handle the case where only the first TB is | 842 | protected. So we handle the case where only the first TB is |
819 | allocated in a physical page */ | 843 | allocated in a physical page */ |
820 | if (!last_first_tb) { | 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 | #endif | 847 | #endif |
827 | 848 | ||
@@ -1246,40 +1267,13 @@ void tlb_flush_page(CPUState *env, target_ulong addr) | @@ -1246,40 +1267,13 @@ void tlb_flush_page(CPUState *env, target_ulong addr) | ||
1246 | #endif | 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 | /* update the TLBs so that writes to code in the virtual page 'addr' | 1270 | /* update the TLBs so that writes to code in the virtual page 'addr' |
1259 | can be detected */ | 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 | /* update the TLB so that writes in physical page 'phys_addr' are no longer | 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,8 +1311,9 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, | ||
1317 | if (length == 0) | 1311 | if (length == 0) |
1318 | return; | 1312 | return; |
1319 | len = length >> TARGET_PAGE_BITS; | 1313 | len = length >> TARGET_PAGE_BITS; |
1320 | - env = cpu_single_env; | ||
1321 | #ifdef USE_KQEMU | 1314 | #ifdef USE_KQEMU |
1315 | + /* XXX: should not depend on cpu context */ | ||
1316 | + env = first_cpu; | ||
1322 | if (env->kqemu_enabled) { | 1317 | if (env->kqemu_enabled) { |
1323 | ram_addr_t addr; | 1318 | ram_addr_t addr; |
1324 | addr = start; | 1319 | addr = start; |
@@ -1336,10 +1331,12 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, | @@ -1336,10 +1331,12 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, | ||
1336 | /* we modify the TLB cache so that the dirty bit will be set again | 1331 | /* we modify the TLB cache so that the dirty bit will be set again |
1337 | when accessing the range */ | 1332 | when accessing the range */ |
1338 | start1 = start + (unsigned long)phys_ram_base; | 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 | #if !defined(CONFIG_SOFTMMU) | 1341 | #if !defined(CONFIG_SOFTMMU) |
1345 | /* XXX: this is expensive */ | 1342 | /* XXX: this is expensive */ |
@@ -1407,9 +1404,9 @@ static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, | @@ -1407,9 +1404,9 @@ static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, | ||
1407 | 1404 | ||
1408 | /* update the TLB corresponding to virtual page vaddr and phys addr | 1405 | /* update the TLB corresponding to virtual page vaddr and phys addr |
1409 | addr so that it is no longer dirty */ | 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 | int i; | 1410 | int i; |
1414 | 1411 | ||
1415 | addr &= TARGET_PAGE_MASK; | 1412 | addr &= TARGET_PAGE_MASK; |
@@ -1723,7 +1720,8 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size) | @@ -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 | #endif /* defined(CONFIG_USER_ONLY) */ | 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,7 +1785,7 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t | ||
1787 | /* we remove the notdirty callback only if the code has been | 1785 | /* we remove the notdirty callback only if the code has been |
1788 | flushed */ | 1786 | flushed */ |
1789 | if (dirty_flags == 0xff) | 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 | static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) | 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,7 +1806,7 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t | ||
1808 | /* we remove the notdirty callback only if the code has been | 1806 | /* we remove the notdirty callback only if the code has been |
1809 | flushed */ | 1807 | flushed */ |
1810 | if (dirty_flags == 0xff) | 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 | static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) | 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,7 +1827,7 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t | ||
1829 | /* we remove the notdirty callback only if the code has been | 1827 | /* we remove the notdirty callback only if the code has been |
1830 | flushed */ | 1828 | flushed */ |
1831 | if (dirty_flags == 0xff) | 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 | static CPUReadMemoryFunc *error_mem_read[3] = { | 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,6 +1951,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, | ||
1953 | if (is_write) { | 1951 | if (is_write) { |
1954 | if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { | 1952 | if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) { |
1955 | io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); | 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 | if (l >= 4 && ((addr & 3) == 0)) { | 1956 | if (l >= 4 && ((addr & 3) == 0)) { |
1957 | /* 32 bit write access */ | 1957 | /* 32 bit write access */ |
1958 | val = ldl_p(buf); | 1958 | val = ldl_p(buf); |
gdbstub.c
@@ -47,6 +47,7 @@ enum RSState { | @@ -47,6 +47,7 @@ enum RSState { | ||
47 | static int gdbserver_fd = -1; | 47 | static int gdbserver_fd = -1; |
48 | 48 | ||
49 | typedef struct GDBState { | 49 | typedef struct GDBState { |
50 | + CPUState *env; /* current CPU */ | ||
50 | enum RSState state; /* parsing state */ | 51 | enum RSState state; /* parsing state */ |
51 | int fd; | 52 | int fd; |
52 | char line_buf[4096]; | 53 | char line_buf[4096]; |
@@ -576,10 +577,10 @@ static void gdb_vm_stopped(void *opaque, int reason) | @@ -576,10 +577,10 @@ static void gdb_vm_stopped(void *opaque, int reason) | ||
576 | int ret; | 577 | int ret; |
577 | 578 | ||
578 | /* disable single step if it was enable */ | 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 | if (reason == EXCP_DEBUG) { | 582 | if (reason == EXCP_DEBUG) { |
582 | - tb_flush(cpu_single_env); | 583 | + tb_flush(s->env); |
583 | ret = SIGTRAP; | 584 | ret = SIGTRAP; |
584 | } | 585 | } |
585 | else | 586 | else |
@@ -589,8 +590,9 @@ static void gdb_vm_stopped(void *opaque, int reason) | @@ -589,8 +590,9 @@ static void gdb_vm_stopped(void *opaque, int reason) | ||
589 | } | 590 | } |
590 | #endif | 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 | int i, csum; | 596 | int i, csum; |
595 | char reply[1]; | 597 | char reply[1]; |
596 | 598 | ||
@@ -676,7 +678,7 @@ gdb_handlesig (CPUState *env, int sig) | @@ -676,7 +678,7 @@ gdb_handlesig (CPUState *env, int sig) | ||
676 | int i; | 678 | int i; |
677 | 679 | ||
678 | for (i = 0; i < n; i++) | 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 | else if (n == 0 || errno != EAGAIN) | 683 | else if (n == 0 || errno != EAGAIN) |
682 | { | 684 | { |
@@ -721,7 +723,7 @@ static void gdb_read(void *opaque) | @@ -721,7 +723,7 @@ static void gdb_read(void *opaque) | ||
721 | vm_start(); | 723 | vm_start(); |
722 | } else { | 724 | } else { |
723 | for(i = 0; i < size; i++) | 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,6 +761,7 @@ static void gdb_accept(void *opaque) | ||
759 | return; | 761 | return; |
760 | } | 762 | } |
761 | #endif | 763 | #endif |
764 | + s->env = first_cpu; /* XXX: allow to change CPU */ | ||
762 | s->fd = fd; | 765 | s->fd = fd; |
763 | 766 | ||
764 | fcntl(fd, F_SETFL, O_NONBLOCK); | 767 | fcntl(fd, F_SETFL, O_NONBLOCK); |
monitor.c
@@ -64,6 +64,8 @@ static int term_outbuf_index; | @@ -64,6 +64,8 @@ static int term_outbuf_index; | ||
64 | 64 | ||
65 | static void monitor_start_input(void); | 65 | static void monitor_start_input(void); |
66 | 66 | ||
67 | +CPUState *mon_cpu = NULL; | ||
68 | + | ||
67 | void term_flush(void) | 69 | void term_flush(void) |
68 | { | 70 | { |
69 | if (term_outbuf_index > 0) { | 71 | if (term_outbuf_index > 0) { |
@@ -201,17 +203,69 @@ static void do_info_block(void) | @@ -201,17 +203,69 @@ static void do_info_block(void) | ||
201 | bdrv_info(); | 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 | static void do_info_registers(void) | 228 | static void do_info_registers(void) |
205 | { | 229 | { |
230 | + CPUState *env; | ||
231 | + env = mon_get_cpu(); | ||
232 | + if (!env) | ||
233 | + return; | ||
206 | #ifdef TARGET_I386 | 234 | #ifdef TARGET_I386 |
207 | - cpu_dump_state(cpu_single_env, NULL, monitor_fprintf, | 235 | + cpu_dump_state(env, NULL, monitor_fprintf, |
208 | X86_DUMP_FPU); | 236 | X86_DUMP_FPU); |
209 | #else | 237 | #else |
210 | - cpu_dump_state(cpu_single_env, NULL, monitor_fprintf, | 238 | + cpu_dump_state(env, NULL, monitor_fprintf, |
211 | 0); | 239 | 0); |
212 | #endif | 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 | static void do_info_jit(void) | 269 | static void do_info_jit(void) |
216 | { | 270 | { |
217 | dump_exec_info(NULL, monitor_fprintf); | 271 | dump_exec_info(NULL, monitor_fprintf); |
@@ -381,6 +435,7 @@ static void term_printc(int c) | @@ -381,6 +435,7 @@ static void term_printc(int c) | ||
381 | static void memory_dump(int count, int format, int wsize, | 435 | static void memory_dump(int count, int format, int wsize, |
382 | target_ulong addr, int is_physical) | 436 | target_ulong addr, int is_physical) |
383 | { | 437 | { |
438 | + CPUState *env; | ||
384 | int nb_per_line, l, line_size, i, max_digits, len; | 439 | int nb_per_line, l, line_size, i, max_digits, len; |
385 | uint8_t buf[16]; | 440 | uint8_t buf[16]; |
386 | uint64_t v; | 441 | uint64_t v; |
@@ -388,19 +443,22 @@ static void memory_dump(int count, int format, int wsize, | @@ -388,19 +443,22 @@ static void memory_dump(int count, int format, int wsize, | ||
388 | if (format == 'i') { | 443 | if (format == 'i') { |
389 | int flags; | 444 | int flags; |
390 | flags = 0; | 445 | flags = 0; |
446 | + env = mon_get_cpu(); | ||
447 | + if (!env && !is_physical) | ||
448 | + return; | ||
391 | #ifdef TARGET_I386 | 449 | #ifdef TARGET_I386 |
392 | if (wsize == 2) { | 450 | if (wsize == 2) { |
393 | flags = 1; | 451 | flags = 1; |
394 | } else if (wsize == 4) { | 452 | } else if (wsize == 4) { |
395 | flags = 0; | 453 | flags = 0; |
396 | } else { | 454 | } else { |
397 | - /* as default we use the current CS size */ | 455 | + /* as default we use the current CS size */ |
398 | flags = 0; | 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 | flags = 1; | 458 | flags = 1; |
401 | } | 459 | } |
402 | #endif | 460 | #endif |
403 | - monitor_disas(addr, count, is_physical, flags); | 461 | + monitor_disas(env, addr, count, is_physical, flags); |
404 | return; | 462 | return; |
405 | } | 463 | } |
406 | 464 | ||
@@ -437,7 +495,10 @@ static void memory_dump(int count, int format, int wsize, | @@ -437,7 +495,10 @@ static void memory_dump(int count, int format, int wsize, | ||
437 | if (is_physical) { | 495 | if (is_physical) { |
438 | cpu_physical_memory_rw(addr, buf, l, 0); | 496 | cpu_physical_memory_rw(addr, buf, l, 0); |
439 | } else { | 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 | i = 0; | 503 | i = 0; |
443 | while (i < l) { | 504 | while (i < l) { |
@@ -776,10 +837,14 @@ static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask) | @@ -776,10 +837,14 @@ static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask) | ||
776 | 837 | ||
777 | static void tlb_info(void) | 838 | static void tlb_info(void) |
778 | { | 839 | { |
779 | - CPUState *env = cpu_single_env; | 840 | + CPUState *env; |
780 | int l1, l2; | 841 | int l1, l2; |
781 | uint32_t pgd, pde, pte; | 842 | uint32_t pgd, pde, pte; |
782 | 843 | ||
844 | + env = mon_get_cpu(); | ||
845 | + if (!env) | ||
846 | + return; | ||
847 | + | ||
783 | if (!(env->cr[0] & CR0_PG_MASK)) { | 848 | if (!(env->cr[0] & CR0_PG_MASK)) { |
784 | term_printf("PG disabled\n"); | 849 | term_printf("PG disabled\n"); |
785 | return; | 850 | return; |
@@ -830,10 +895,14 @@ static void mem_print(uint32_t *pstart, int *plast_prot, | @@ -830,10 +895,14 @@ static void mem_print(uint32_t *pstart, int *plast_prot, | ||
830 | 895 | ||
831 | static void mem_info(void) | 896 | static void mem_info(void) |
832 | { | 897 | { |
833 | - CPUState *env = cpu_single_env; | 898 | + CPUState *env; |
834 | int l1, l2, prot, last_prot; | 899 | int l1, l2, prot, last_prot; |
835 | uint32_t pgd, pde, pte, start, end; | 900 | uint32_t pgd, pde, pte, start, end; |
836 | 901 | ||
902 | + env = mon_get_cpu(); | ||
903 | + if (!env) | ||
904 | + return; | ||
905 | + | ||
837 | if (!(env->cr[0] & CR0_PG_MASK)) { | 906 | if (!(env->cr[0] & CR0_PG_MASK)) { |
838 | term_printf("PG disabled\n"); | 907 | term_printf("PG disabled\n"); |
839 | return; | 908 | return; |
@@ -874,10 +943,15 @@ static void mem_info(void) | @@ -874,10 +943,15 @@ static void mem_info(void) | ||
874 | static void do_info_kqemu(void) | 943 | static void do_info_kqemu(void) |
875 | { | 944 | { |
876 | #ifdef USE_KQEMU | 945 | #ifdef USE_KQEMU |
946 | + CPUState *env; | ||
877 | int val; | 947 | int val; |
878 | val = 0; | 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 | term_printf("kqemu is %s\n", val ? "enabled" : "disabled"); | 955 | term_printf("kqemu is %s\n", val ? "enabled" : "disabled"); |
882 | #else | 956 | #else |
883 | term_printf("kqemu support is not compiled\n"); | 957 | term_printf("kqemu support is not compiled\n"); |
@@ -934,6 +1008,8 @@ static term_cmd_t term_cmds[] = { | @@ -934,6 +1008,8 @@ static term_cmd_t term_cmds[] = { | ||
934 | "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" }, | 1008 | "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" }, |
935 | { "usb_del", "s", do_usb_del, | 1009 | { "usb_del", "s", do_usb_del, |
936 | "device", "remove USB device 'bus.addr'" }, | 1010 | "device", "remove USB device 'bus.addr'" }, |
1011 | + { "cpu", "i", do_cpu_set, | ||
1012 | + "index", "set the default CPU" }, | ||
937 | { NULL, NULL, }, | 1013 | { NULL, NULL, }, |
938 | }; | 1014 | }; |
939 | 1015 | ||
@@ -946,6 +1022,8 @@ static term_cmd_t info_cmds[] = { | @@ -946,6 +1022,8 @@ static term_cmd_t info_cmds[] = { | ||
946 | "", "show the block devices" }, | 1022 | "", "show the block devices" }, |
947 | { "registers", "", do_info_registers, | 1023 | { "registers", "", do_info_registers, |
948 | "", "show the cpu registers" }, | 1024 | "", "show the cpu registers" }, |
1025 | + { "cpus", "", do_info_cpus, | ||
1026 | + "", "show infos for each CPU" }, | ||
949 | { "history", "", do_info_history, | 1027 | { "history", "", do_info_history, |
950 | "", "show the command line history", }, | 1028 | "", "show the command line history", }, |
951 | { "irq", "", irq_info, | 1029 | { "irq", "", irq_info, |
@@ -989,63 +1067,85 @@ typedef struct MonitorDef { | @@ -989,63 +1067,85 @@ typedef struct MonitorDef { | ||
989 | #if defined(TARGET_I386) | 1067 | #if defined(TARGET_I386) |
990 | static target_long monitor_get_pc (struct MonitorDef *md, int val) | 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 | #endif | 1075 | #endif |
995 | 1076 | ||
996 | #if defined(TARGET_PPC) | 1077 | #if defined(TARGET_PPC) |
997 | static target_long monitor_get_ccr (struct MonitorDef *md, int val) | 1078 | static target_long monitor_get_ccr (struct MonitorDef *md, int val) |
998 | { | 1079 | { |
1080 | + CPUState *env = mon_get_cpu(); | ||
999 | unsigned int u; | 1081 | unsigned int u; |
1000 | int i; | 1082 | int i; |
1001 | 1083 | ||
1084 | + if (!env) | ||
1085 | + return 0; | ||
1086 | + | ||
1002 | u = 0; | 1087 | u = 0; |
1003 | for (i = 0; i < 8; i++) | 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 | return u; | 1091 | return u; |
1007 | } | 1092 | } |
1008 | 1093 | ||
1009 | static target_long monitor_get_msr (struct MonitorDef *md, int val) | 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 | static target_long monitor_get_xer (struct MonitorDef *md, int val) | 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 | static target_long monitor_get_decr (struct MonitorDef *md, int val) | 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 | static target_long monitor_get_tbu (struct MonitorDef *md, int val) | 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 | static target_long monitor_get_tbl (struct MonitorDef *md, int val) | 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 | #endif | 1150 | #endif |
1051 | 1151 | ||
@@ -1053,13 +1153,19 @@ static target_long monitor_get_tbl (struct MonitorDef *md, int val) | @@ -1053,13 +1153,19 @@ static target_long monitor_get_tbl (struct MonitorDef *md, int val) | ||
1053 | #ifndef TARGET_SPARC64 | 1153 | #ifndef TARGET_SPARC64 |
1054 | static target_long monitor_get_psr (struct MonitorDef *md, int val) | 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 | #endif | 1161 | #endif |
1059 | 1162 | ||
1060 | static target_long monitor_get_reg(struct MonitorDef *md, int val) | 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 | #endif | 1170 | #endif |
1065 | 1171 | ||
@@ -1269,6 +1375,7 @@ static void expr_error(const char *fmt) | @@ -1269,6 +1375,7 @@ static void expr_error(const char *fmt) | ||
1269 | longjmp(expr_env, 1); | 1375 | longjmp(expr_env, 1); |
1270 | } | 1376 | } |
1271 | 1377 | ||
1378 | +/* return 0 if OK, -1 if not found, -2 if no CPU defined */ | ||
1272 | static int get_monitor_def(target_long *pval, const char *name) | 1379 | static int get_monitor_def(target_long *pval, const char *name) |
1273 | { | 1380 | { |
1274 | MonitorDef *md; | 1381 | MonitorDef *md; |
@@ -1279,7 +1386,10 @@ static int get_monitor_def(target_long *pval, const char *name) | @@ -1279,7 +1386,10 @@ static int get_monitor_def(target_long *pval, const char *name) | ||
1279 | if (md->get_value) { | 1386 | if (md->get_value) { |
1280 | *pval = md->get_value(md, md->offset); | 1387 | *pval = md->get_value(md, md->offset); |
1281 | } else { | 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 | switch(md->type) { | 1393 | switch(md->type) { |
1284 | case MD_I32: | 1394 | case MD_I32: |
1285 | *pval = *(int32_t *)ptr; | 1395 | *pval = *(int32_t *)ptr; |
@@ -1313,6 +1423,7 @@ static target_long expr_unary(void) | @@ -1313,6 +1423,7 @@ static target_long expr_unary(void) | ||
1313 | { | 1423 | { |
1314 | target_long n; | 1424 | target_long n; |
1315 | char *p; | 1425 | char *p; |
1426 | + int ret; | ||
1316 | 1427 | ||
1317 | switch(*pch) { | 1428 | switch(*pch) { |
1318 | case '+': | 1429 | case '+': |
@@ -1362,8 +1473,11 @@ static target_long expr_unary(void) | @@ -1362,8 +1473,11 @@ static target_long expr_unary(void) | ||
1362 | while (isspace(*pch)) | 1473 | while (isspace(*pch)) |
1363 | pch++; | 1474 | pch++; |
1364 | *q = 0; | 1475 | *q = 0; |
1365 | - if (get_monitor_def(&n, buf)) | 1476 | + ret = get_monitor_def(&n, buf); |
1477 | + if (ret == -1) | ||
1366 | expr_error("unknown register"); | 1478 | expr_error("unknown register"); |
1479 | + else if (ret == -2) | ||
1480 | + expr_error("no cpu defined"); | ||
1367 | } | 1481 | } |
1368 | break; | 1482 | break; |
1369 | case '\0': | 1483 | case '\0': |
vl.c
@@ -83,8 +83,6 @@ | @@ -83,8 +83,6 @@ | ||
83 | 83 | ||
84 | #include "exec-all.h" | 84 | #include "exec-all.h" |
85 | 85 | ||
86 | -//#define DO_TB_FLUSH | ||
87 | - | ||
88 | #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" | 86 | #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" |
89 | 87 | ||
90 | //#define DEBUG_UNUSED_IOPORT | 88 | //#define DEBUG_UNUSED_IOPORT |
@@ -109,8 +107,6 @@ | @@ -109,8 +107,6 @@ | ||
109 | 107 | ||
110 | const char *bios_dir = CONFIG_QEMU_SHAREDIR; | 108 | const char *bios_dir = CONFIG_QEMU_SHAREDIR; |
111 | char phys_ram_file[1024]; | 109 | char phys_ram_file[1024]; |
112 | -CPUState *global_env; | ||
113 | -CPUState *cpu_single_env; | ||
114 | void *ioport_opaque[MAX_IOPORTS]; | 110 | void *ioport_opaque[MAX_IOPORTS]; |
115 | IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; | 111 | IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; |
116 | IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; | 112 | IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; |
@@ -156,6 +152,7 @@ int usb_enabled = 0; | @@ -156,6 +152,7 @@ int usb_enabled = 0; | ||
156 | USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; | 152 | USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; |
157 | USBDevice *vm_usb_hub; | 153 | USBDevice *vm_usb_hub; |
158 | static VLANState *first_vlan; | 154 | static VLANState *first_vlan; |
155 | +int smp_cpus = 1; | ||
159 | 156 | ||
160 | /***********************************************************/ | 157 | /***********************************************************/ |
161 | /* x86 ISA bus support */ | 158 | /* x86 ISA bus support */ |
@@ -427,16 +424,20 @@ int cpu_inl(CPUState *env, int addr) | @@ -427,16 +424,20 @@ int cpu_inl(CPUState *env, int addr) | ||
427 | void hw_error(const char *fmt, ...) | 424 | void hw_error(const char *fmt, ...) |
428 | { | 425 | { |
429 | va_list ap; | 426 | va_list ap; |
427 | + CPUState *env; | ||
430 | 428 | ||
431 | va_start(ap, fmt); | 429 | va_start(ap, fmt); |
432 | fprintf(stderr, "qemu: hardware error: "); | 430 | fprintf(stderr, "qemu: hardware error: "); |
433 | vfprintf(stderr, fmt, ap); | 431 | vfprintf(stderr, fmt, ap); |
434 | fprintf(stderr, "\n"); | 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 | #ifdef TARGET_I386 | 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 | #else | 437 | #else |
438 | - cpu_dump_state(global_env, stderr, fprintf, 0); | 438 | + cpu_dump_state(env, stderr, fprintf, 0); |
439 | #endif | 439 | #endif |
440 | + } | ||
440 | va_end(ap); | 441 | va_end(ap); |
441 | abort(); | 442 | abort(); |
442 | } | 443 | } |
@@ -879,13 +880,16 @@ static void host_alarm_handler(int host_signum) | @@ -879,13 +880,16 @@ static void host_alarm_handler(int host_signum) | ||
879 | qemu_get_clock(vm_clock)) || | 880 | qemu_get_clock(vm_clock)) || |
880 | qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], | 881 | qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], |
881 | qemu_get_clock(rt_clock))) { | 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 | #ifdef USE_KQEMU | 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 | #endif | 891 | #endif |
892 | + } | ||
889 | } | 893 | } |
890 | } | 894 | } |
891 | 895 | ||
@@ -2970,9 +2974,6 @@ int qemu_loadvm(const char *filename) | @@ -2970,9 +2974,6 @@ int qemu_loadvm(const char *filename) | ||
2970 | goto the_end; | 2974 | goto the_end; |
2971 | } | 2975 | } |
2972 | for(;;) { | 2976 | for(;;) { |
2973 | -#if defined (DO_TB_FLUSH) | ||
2974 | - tb_flush(global_env); | ||
2975 | -#endif | ||
2976 | len = qemu_get_byte(f); | 2977 | len = qemu_get_byte(f); |
2977 | if (feof(f)) | 2978 | if (feof(f)) |
2978 | break; | 2979 | break; |
@@ -3583,27 +3584,22 @@ void qemu_system_reset(void) | @@ -3583,27 +3584,22 @@ void qemu_system_reset(void) | ||
3583 | void qemu_system_reset_request(void) | 3584 | void qemu_system_reset_request(void) |
3584 | { | 3585 | { |
3585 | reset_requested = 1; | 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 | void qemu_system_shutdown_request(void) | 3591 | void qemu_system_shutdown_request(void) |
3590 | { | 3592 | { |
3591 | shutdown_requested = 1; | 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 | void qemu_system_powerdown_request(void) | 3598 | void qemu_system_powerdown_request(void) |
3596 | { | 3599 | { |
3597 | powerdown_requested = 1; | 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 | void main_loop_wait(int timeout) | 3605 | void main_loop_wait(int timeout) |
@@ -3684,14 +3680,42 @@ void main_loop_wait(int timeout) | @@ -3684,14 +3680,42 @@ void main_loop_wait(int timeout) | ||
3684 | qemu_get_clock(rt_clock)); | 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 | int main_loop(void) | 3704 | int main_loop(void) |
3688 | { | 3705 | { |
3689 | int ret, timeout; | 3706 | int ret, timeout; |
3690 | - CPUState *env = global_env; | 3707 | + CPUState *env; |
3691 | 3708 | ||
3709 | + cur_cpu = first_cpu; | ||
3692 | for(;;) { | 3710 | for(;;) { |
3693 | if (vm_running) { | 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 | if (shutdown_requested) { | 3719 | if (shutdown_requested) { |
3696 | ret = EXCP_INTERRUPT; | 3720 | ret = EXCP_INTERRUPT; |
3697 | break; | 3721 | break; |
@@ -3774,7 +3798,7 @@ void help(void) | @@ -3774,7 +3798,7 @@ void help(void) | ||
3774 | " connect the host TAP network interface to VLAN 'n' and use\n" | 3798 | " connect the host TAP network interface to VLAN 'n' and use\n" |
3775 | " the network script 'file' (default=%s);\n" | 3799 | " the network script 'file' (default=%s);\n" |
3776 | " use 'fd=h' to connect to an already opened TAP interface\n" | 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 | " connect the vlan 'n' to another VLAN using a socket connection\n" | 3802 | " connect the vlan 'n' to another VLAN using a socket connection\n" |
3779 | #endif | 3803 | #endif |
3780 | "-net none use it alone to have zero network devices; if no -net option\n" | 3804 | "-net none use it alone to have zero network devices; if no -net option\n" |
@@ -3899,6 +3923,7 @@ enum { | @@ -3899,6 +3923,7 @@ enum { | ||
3899 | QEMU_OPTION_win2k_hack, | 3923 | QEMU_OPTION_win2k_hack, |
3900 | QEMU_OPTION_usb, | 3924 | QEMU_OPTION_usb, |
3901 | QEMU_OPTION_usbdevice, | 3925 | QEMU_OPTION_usbdevice, |
3926 | + QEMU_OPTION_smp, | ||
3902 | }; | 3927 | }; |
3903 | 3928 | ||
3904 | typedef struct QEMUOption { | 3929 | typedef struct QEMUOption { |
@@ -3965,6 +3990,7 @@ const QEMUOption qemu_options[] = { | @@ -3965,6 +3990,7 @@ const QEMUOption qemu_options[] = { | ||
3965 | { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, | 3990 | { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, |
3966 | { "win2k-hack", 0, QEMU_OPTION_win2k_hack }, | 3991 | { "win2k-hack", 0, QEMU_OPTION_win2k_hack }, |
3967 | { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, | 3992 | { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, |
3993 | + { "smp", HAS_ARG, QEMU_OPTION_smp }, | ||
3968 | 3994 | ||
3969 | /* temporary options */ | 3995 | /* temporary options */ |
3970 | { "usb", 0, QEMU_OPTION_usb }, | 3996 | { "usb", 0, QEMU_OPTION_usb }, |
@@ -4120,7 +4146,6 @@ int main(int argc, char **argv) | @@ -4120,7 +4146,6 @@ int main(int argc, char **argv) | ||
4120 | #endif | 4146 | #endif |
4121 | int i, cdrom_index; | 4147 | int i, cdrom_index; |
4122 | int snapshot, linux_boot; | 4148 | int snapshot, linux_boot; |
4123 | - CPUState *env; | ||
4124 | const char *initrd_filename; | 4149 | const char *initrd_filename; |
4125 | const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; | 4150 | const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; |
4126 | const char *kernel_filename, *kernel_cmdline; | 4151 | const char *kernel_filename, *kernel_cmdline; |
@@ -4511,6 +4536,13 @@ int main(int argc, char **argv) | @@ -4511,6 +4536,13 @@ int main(int argc, char **argv) | ||
4511 | optarg); | 4536 | optarg); |
4512 | usb_devices_index++; | 4537 | usb_devices_index++; |
4513 | break; | 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,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 | register_savevm("ram", 0, 1, ram_save, ram_load, NULL); | 4695 | register_savevm("ram", 0, 1, ram_save, ram_load, NULL); |
4670 | - qemu_register_reset(main_cpu_reset, global_env); | ||
4671 | 4696 | ||
4672 | init_ioports(); | 4697 | init_ioports(); |
4673 | cpu_calibrate_ticks(); | 4698 | cpu_calibrate_ticks(); |
vl.h
@@ -142,6 +142,7 @@ extern const char *keyboard_layout; | @@ -142,6 +142,7 @@ extern const char *keyboard_layout; | ||
142 | extern int kqemu_allowed; | 142 | extern int kqemu_allowed; |
143 | extern int win2k_install_hack; | 143 | extern int win2k_install_hack; |
144 | extern int usb_enabled; | 144 | extern int usb_enabled; |
145 | +extern int smp_cpus; | ||
145 | 146 | ||
146 | /* XXX: make it dynamic */ | 147 | /* XXX: make it dynamic */ |
147 | #if defined (TARGET_PPC) | 148 | #if defined (TARGET_PPC) |
@@ -429,6 +430,9 @@ int register_savevm(const char *idstr, | @@ -429,6 +430,9 @@ int register_savevm(const char *idstr, | ||
429 | void qemu_get_timer(QEMUFile *f, QEMUTimer *ts); | 430 | void qemu_get_timer(QEMUFile *f, QEMUTimer *ts); |
430 | void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); | 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 | /* block.c */ | 436 | /* block.c */ |
433 | typedef struct BlockDriverState BlockDriverState; | 437 | typedef struct BlockDriverState BlockDriverState; |
434 | typedef struct BlockDriver BlockDriver; | 438 | typedef struct BlockDriver BlockDriver; |
@@ -774,6 +778,9 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time); | @@ -774,6 +778,9 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time); | ||
774 | extern QEMUMachine pc_machine; | 778 | extern QEMUMachine pc_machine; |
775 | extern QEMUMachine isapc_machine; | 779 | extern QEMUMachine isapc_machine; |
776 | 780 | ||
781 | +void ioport_set_a20(int enable); | ||
782 | +int ioport_get_a20(void); | ||
783 | + | ||
777 | /* ppc.c */ | 784 | /* ppc.c */ |
778 | extern QEMUMachine prep_machine; | 785 | extern QEMUMachine prep_machine; |
779 | extern QEMUMachine core99_machine; | 786 | extern QEMUMachine core99_machine; |