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; | ... | ... |