SMP support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1640 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
f0aca8227f
commit
6a00d60127
@ -96,6 +96,7 @@ typedef struct CPUTLBEntry {
|
||||
|
||||
#define CPU_COMMON \
|
||||
struct TranslationBlock *current_tb; /* currently executing TB */ \
|
||||
int cpu_halted; /* TRUE if cpu is halted (sleep mode) */ \
|
||||
/* soft mmu support */ \
|
||||
/* in order to avoid passing too many arguments to the memory \
|
||||
write helpers, we store some rarely used information in the CPU \
|
||||
@ -115,9 +116,9 @@ typedef struct CPUTLBEntry {
|
||||
int nb_breakpoints; \
|
||||
int singlestep_enabled; \
|
||||
\
|
||||
void *next_cpu; /* next CPU sharing TB cache */ \
|
||||
int cpu_index; /* CPU index (informative) */ \
|
||||
/* user data */ \
|
||||
void *opaque;
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -251,6 +251,8 @@ int cpu_exec(CPUState *env1)
|
||||
TranslationBlock *tb;
|
||||
uint8_t *tc_ptr;
|
||||
|
||||
cpu_single_env = env1;
|
||||
|
||||
/* first we save global registers */
|
||||
saved_env = env;
|
||||
env = env1;
|
||||
@ -755,6 +757,8 @@ int cpu_exec(CPUState *env1)
|
||||
T2 = saved_T2;
|
||||
#endif
|
||||
env = saved_env;
|
||||
/* fail safe : never use cpu_single_env outside cpu_exec() */
|
||||
cpu_single_env = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
10
disas.c
10
disas.c
@ -138,6 +138,7 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info)
|
||||
values:
|
||||
i386 - nonzero means 16 bit code
|
||||
arm - nonzero means thumb code
|
||||
ppc - nonzero means little endian
|
||||
other targets - unused
|
||||
*/
|
||||
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)
|
||||
disasm_info.mach = bfd_mach_sparc_v9b;
|
||||
#endif
|
||||
#elif defined(TARGET_PPC)
|
||||
if (cpu_single_env->msr[MSR_LE])
|
||||
if (flags)
|
||||
disasm_info.endian = BFD_ENDIAN_LITTLE;
|
||||
#ifdef TARGET_PPC64
|
||||
disasm_info.mach = bfd_mach_ppc64;
|
||||
@ -314,6 +315,7 @@ void term_vprintf(const char *fmt, va_list ap);
|
||||
void term_printf(const char *fmt, ...);
|
||||
|
||||
static int monitor_disas_is_physical;
|
||||
static CPUState *monitor_disas_env;
|
||||
|
||||
static int
|
||||
monitor_read_memory (memaddr, myaddr, length, info)
|
||||
@ -325,7 +327,7 @@ monitor_read_memory (memaddr, myaddr, length, info)
|
||||
if (monitor_disas_is_physical) {
|
||||
cpu_physical_memory_rw(memaddr, myaddr, length, 0);
|
||||
} else {
|
||||
cpu_memory_rw_debug(cpu_single_env, memaddr,myaddr, length, 0);
|
||||
cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -339,7 +341,8 @@ static int monitor_fprintf(FILE *stream, const char *fmt, ...)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
|
||||
void monitor_disas(CPUState *env,
|
||||
target_ulong pc, int nb_insn, int is_physical, int flags)
|
||||
{
|
||||
int count, i;
|
||||
struct disassemble_info disasm_info;
|
||||
@ -347,6 +350,7 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
|
||||
|
||||
INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf);
|
||||
|
||||
monitor_disas_env = env;
|
||||
monitor_disas_is_physical = is_physical;
|
||||
disasm_info.read_memory_func = monitor_read_memory;
|
||||
|
||||
|
@ -91,7 +91,7 @@ int cpu_restore_state_copy(struct TranslationBlock *tb,
|
||||
CPUState *env, unsigned long searched_pc,
|
||||
void *puc);
|
||||
void cpu_resume_from_signal(CPUState *env1, void *puc);
|
||||
void cpu_exec_init(void);
|
||||
void cpu_exec_init(CPUState *env);
|
||||
int page_unprotect(unsigned long address, unsigned long pc, void *puc);
|
||||
void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
|
||||
int is_cpu_write_access);
|
||||
|
104
exec.c
104
exec.c
@ -74,6 +74,11 @@ int phys_ram_fd;
|
||||
uint8_t *phys_ram_base;
|
||||
uint8_t *phys_ram_dirty;
|
||||
|
||||
CPUState *first_cpu;
|
||||
/* current CPU in the current thread. It is only valid inside
|
||||
cpu_exec() */
|
||||
CPUState *cpu_single_env;
|
||||
|
||||
typedef struct PageDesc {
|
||||
/* list of TBs intersecting this ram page */
|
||||
TranslationBlock *first_tb;
|
||||
@ -233,19 +238,30 @@ static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr,
|
||||
target_ulong vaddr);
|
||||
static void tlb_protect_code(ram_addr_t ram_addr);
|
||||
static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
|
||||
target_ulong vaddr);
|
||||
#endif
|
||||
|
||||
void cpu_exec_init(void)
|
||||
void cpu_exec_init(CPUState *env)
|
||||
{
|
||||
CPUState **penv;
|
||||
int cpu_index;
|
||||
|
||||
if (!code_gen_ptr) {
|
||||
code_gen_ptr = code_gen_buffer;
|
||||
page_init();
|
||||
io_mem_init();
|
||||
}
|
||||
env->next_cpu = NULL;
|
||||
penv = &first_cpu;
|
||||
cpu_index = 0;
|
||||
while (*penv != NULL) {
|
||||
penv = (CPUState **)&(*penv)->next_cpu;
|
||||
cpu_index++;
|
||||
}
|
||||
env->cpu_index = cpu_index;
|
||||
*penv = env;
|
||||
}
|
||||
|
||||
static inline void invalidate_page_bitmap(PageDesc *p)
|
||||
@ -277,8 +293,9 @@ static void page_flush_tb(void)
|
||||
|
||||
/* flush all the translation blocks */
|
||||
/* XXX: tb_flush is currently not thread safe */
|
||||
void tb_flush(CPUState *env)
|
||||
void tb_flush(CPUState *env1)
|
||||
{
|
||||
CPUState *env;
|
||||
#if defined(DEBUG_FLUSH)
|
||||
printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
|
||||
code_gen_ptr - code_gen_buffer,
|
||||
@ -286,7 +303,10 @@ void tb_flush(CPUState *env)
|
||||
nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
|
||||
#endif
|
||||
nb_tbs = 0;
|
||||
memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
|
||||
|
||||
for(env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
|
||||
}
|
||||
|
||||
memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
|
||||
page_flush_tb();
|
||||
@ -424,6 +444,7 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n)
|
||||
|
||||
static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
|
||||
{
|
||||
CPUState *env;
|
||||
PageDesc *p;
|
||||
unsigned int h, n1;
|
||||
target_ulong phys_pc;
|
||||
@ -451,7 +472,10 @@ static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_ad
|
||||
|
||||
/* remove the TB from the hash list */
|
||||
h = tb_jmp_cache_hash_func(tb->pc);
|
||||
cpu_single_env->tb_jmp_cache[h] = NULL;
|
||||
for(env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
if (env->tb_jmp_cache[h] == tb)
|
||||
env->tb_jmp_cache[h] = NULL;
|
||||
}
|
||||
|
||||
/* suppress this TB from the two jump lists */
|
||||
tb_jmp_remove(tb, 0);
|
||||
@ -818,10 +842,7 @@ static inline void tb_alloc_page(TranslationBlock *tb,
|
||||
protected. So we handle the case where only the first TB is
|
||||
allocated in a physical page */
|
||||
if (!last_first_tb) {
|
||||
target_ulong virt_addr;
|
||||
|
||||
virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS);
|
||||
tlb_protect_code(cpu_single_env, page_addr, virt_addr);
|
||||
tlb_protect_code(page_addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1246,40 +1267,13 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
|
||||
{
|
||||
if (addr == (tlb_entry->address &
|
||||
(TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
|
||||
(tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
|
||||
tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
|
||||
}
|
||||
}
|
||||
|
||||
/* update the TLBs so that writes to code in the virtual page 'addr'
|
||||
can be detected */
|
||||
static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr,
|
||||
target_ulong vaddr)
|
||||
static void tlb_protect_code(ram_addr_t ram_addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
vaddr &= TARGET_PAGE_MASK;
|
||||
i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
tlb_protect_code1(&env->tlb_write[0][i], vaddr);
|
||||
tlb_protect_code1(&env->tlb_write[1][i], vaddr);
|
||||
|
||||
#ifdef USE_KQEMU
|
||||
if (env->kqemu_enabled) {
|
||||
kqemu_set_notdirty(env, ram_addr);
|
||||
}
|
||||
#endif
|
||||
phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] &= ~CODE_DIRTY_FLAG;
|
||||
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
/* NOTE: as we generated the code for this page, it is already at
|
||||
least readable */
|
||||
if (vaddr < MMAP_AREA_END)
|
||||
mprotect((void *)vaddr, TARGET_PAGE_SIZE, PROT_READ);
|
||||
#endif
|
||||
cpu_physical_memory_reset_dirty(ram_addr,
|
||||
ram_addr + TARGET_PAGE_SIZE,
|
||||
CODE_DIRTY_FLAG);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
if (length == 0)
|
||||
return;
|
||||
len = length >> TARGET_PAGE_BITS;
|
||||
env = cpu_single_env;
|
||||
#ifdef USE_KQEMU
|
||||
/* XXX: should not depend on cpu context */
|
||||
env = first_cpu;
|
||||
if (env->kqemu_enabled) {
|
||||
ram_addr_t addr;
|
||||
addr = start;
|
||||
@ -1336,10 +1331,12 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
|
||||
/* we modify the TLB cache so that the dirty bit will be set again
|
||||
when accessing the range */
|
||||
start1 = start + (unsigned long)phys_ram_base;
|
||||
for(i = 0; i < CPU_TLB_SIZE; i++)
|
||||
tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
|
||||
for(i = 0; i < CPU_TLB_SIZE; i++)
|
||||
tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
|
||||
for(env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
for(i = 0; i < CPU_TLB_SIZE; i++)
|
||||
tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
|
||||
for(i = 0; i < CPU_TLB_SIZE; i++)
|
||||
tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_SOFTMMU)
|
||||
/* XXX: this is expensive */
|
||||
@ -1407,9 +1404,9 @@ static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
|
||||
|
||||
/* update the TLB corresponding to virtual page vaddr and phys addr
|
||||
addr so that it is no longer dirty */
|
||||
static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
|
||||
static inline void tlb_set_dirty(CPUState *env,
|
||||
unsigned long addr, target_ulong vaddr)
|
||||
{
|
||||
CPUState *env = cpu_single_env;
|
||||
int i;
|
||||
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
@ -1723,7 +1720,8 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
|
||||
static inline void tlb_set_dirty(CPUState *env,
|
||||
unsigned long addr, target_ulong vaddr)
|
||||
{
|
||||
}
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
@ -1787,7 +1785,7 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t
|
||||
/* we remove the notdirty callback only if the code has been
|
||||
flushed */
|
||||
if (dirty_flags == 0xff)
|
||||
tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
|
||||
tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
|
||||
}
|
||||
|
||||
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
|
||||
/* we remove the notdirty callback only if the code has been
|
||||
flushed */
|
||||
if (dirty_flags == 0xff)
|
||||
tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
|
||||
tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
|
||||
}
|
||||
|
||||
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
|
||||
/* we remove the notdirty callback only if the code has been
|
||||
flushed */
|
||||
if (dirty_flags == 0xff)
|
||||
tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
|
||||
tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc *error_mem_read[3] = {
|
||||
@ -1953,6 +1951,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
|
||||
if (is_write) {
|
||||
if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
|
||||
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
||||
/* XXX: could force cpu_single_env to NULL to avoid
|
||||
potential bugs */
|
||||
if (l >= 4 && ((addr & 3) == 0)) {
|
||||
/* 32 bit write access */
|
||||
val = ldl_p(buf);
|
||||
|
13
gdbstub.c
13
gdbstub.c
@ -47,6 +47,7 @@ enum RSState {
|
||||
static int gdbserver_fd = -1;
|
||||
|
||||
typedef struct GDBState {
|
||||
CPUState *env; /* current CPU */
|
||||
enum RSState state; /* parsing state */
|
||||
int fd;
|
||||
char line_buf[4096];
|
||||
@ -576,10 +577,10 @@ static void gdb_vm_stopped(void *opaque, int reason)
|
||||
int ret;
|
||||
|
||||
/* disable single step if it was enable */
|
||||
cpu_single_step(cpu_single_env, 0);
|
||||
cpu_single_step(s->env, 0);
|
||||
|
||||
if (reason == EXCP_DEBUG) {
|
||||
tb_flush(cpu_single_env);
|
||||
tb_flush(s->env);
|
||||
ret = SIGTRAP;
|
||||
}
|
||||
else
|
||||
@ -589,8 +590,9 @@ static void gdb_vm_stopped(void *opaque, int reason)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void gdb_read_byte(GDBState *s, CPUState *env, int ch)
|
||||
static void gdb_read_byte(GDBState *s, int ch)
|
||||
{
|
||||
CPUState *env = s->env;
|
||||
int i, csum;
|
||||
char reply[1];
|
||||
|
||||
@ -676,7 +678,7 @@ gdb_handlesig (CPUState *env, int sig)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
gdb_read_byte (s, env, buf[i]);
|
||||
gdb_read_byte (s, buf[i]);
|
||||
}
|
||||
else if (n == 0 || errno != EAGAIN)
|
||||
{
|
||||
@ -721,7 +723,7 @@ static void gdb_read(void *opaque)
|
||||
vm_start();
|
||||
} else {
|
||||
for(i = 0; i < size; i++)
|
||||
gdb_read_byte(s, cpu_single_env, buf[i]);
|
||||
gdb_read_byte(s, buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -759,6 +761,7 @@ static void gdb_accept(void *opaque)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
s->env = first_cpu; /* XXX: allow to change CPU */
|
||||
s->fd = fd;
|
||||
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
|
190
monitor.c
190
monitor.c
@ -64,6 +64,8 @@ static int term_outbuf_index;
|
||||
|
||||
static void monitor_start_input(void);
|
||||
|
||||
CPUState *mon_cpu = NULL;
|
||||
|
||||
void term_flush(void)
|
||||
{
|
||||
if (term_outbuf_index > 0) {
|
||||
@ -201,17 +203,69 @@ static void do_info_block(void)
|
||||
bdrv_info();
|
||||
}
|
||||
|
||||
/* get the current CPU defined by the user */
|
||||
int mon_set_cpu(int cpu_index)
|
||||
{
|
||||
CPUState *env;
|
||||
|
||||
for(env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
if (env->cpu_index == cpu_index) {
|
||||
mon_cpu = env;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
CPUState *mon_get_cpu(void)
|
||||
{
|
||||
if (!mon_cpu) {
|
||||
mon_set_cpu(0);
|
||||
}
|
||||
return mon_cpu;
|
||||
}
|
||||
|
||||
static void do_info_registers(void)
|
||||
{
|
||||
CPUState *env;
|
||||
env = mon_get_cpu();
|
||||
if (!env)
|
||||
return;
|
||||
#ifdef TARGET_I386
|
||||
cpu_dump_state(cpu_single_env, NULL, monitor_fprintf,
|
||||
cpu_dump_state(env, NULL, monitor_fprintf,
|
||||
X86_DUMP_FPU);
|
||||
#else
|
||||
cpu_dump_state(cpu_single_env, NULL, monitor_fprintf,
|
||||
cpu_dump_state(env, NULL, monitor_fprintf,
|
||||
0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void do_info_cpus(void)
|
||||
{
|
||||
CPUState *env;
|
||||
|
||||
/* just to set the default cpu if not already done */
|
||||
mon_get_cpu();
|
||||
|
||||
for(env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
term_printf("%c CPU #%d:",
|
||||
(env == mon_cpu) ? '*' : ' ',
|
||||
env->cpu_index);
|
||||
#if defined(TARGET_I386)
|
||||
term_printf(" pc=0x" TARGET_FMT_lx, env->eip + env->segs[R_CS].base);
|
||||
if (env->cpu_halted)
|
||||
term_printf(" (halted)");
|
||||
#endif
|
||||
term_printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void do_cpu_set(int index)
|
||||
{
|
||||
if (mon_set_cpu(index) < 0)
|
||||
term_printf("Invalid CPU index\n");
|
||||
}
|
||||
|
||||
static void do_info_jit(void)
|
||||
{
|
||||
dump_exec_info(NULL, monitor_fprintf);
|
||||
@ -381,6 +435,7 @@ static void term_printc(int c)
|
||||
static void memory_dump(int count, int format, int wsize,
|
||||
target_ulong addr, int is_physical)
|
||||
{
|
||||
CPUState *env;
|
||||
int nb_per_line, l, line_size, i, max_digits, len;
|
||||
uint8_t buf[16];
|
||||
uint64_t v;
|
||||
@ -388,19 +443,22 @@ static void memory_dump(int count, int format, int wsize,
|
||||
if (format == 'i') {
|
||||
int flags;
|
||||
flags = 0;
|
||||
env = mon_get_cpu();
|
||||
if (!env && !is_physical)
|
||||
return;
|
||||
#ifdef TARGET_I386
|
||||
if (wsize == 2) {
|
||||
flags = 1;
|
||||
} else if (wsize == 4) {
|
||||
flags = 0;
|
||||
} else {
|
||||
/* as default we use the current CS size */
|
||||
/* as default we use the current CS size */
|
||||
flags = 0;
|
||||
if (!(cpu_single_env->segs[R_CS].flags & DESC_B_MASK))
|
||||
if (env && !(env->segs[R_CS].flags & DESC_B_MASK))
|
||||
flags = 1;
|
||||
}
|
||||
#endif
|
||||
monitor_disas(addr, count, is_physical, flags);
|
||||
monitor_disas(env, addr, count, is_physical, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -437,7 +495,10 @@ static void memory_dump(int count, int format, int wsize,
|
||||
if (is_physical) {
|
||||
cpu_physical_memory_rw(addr, buf, l, 0);
|
||||
} else {
|
||||
cpu_memory_rw_debug(cpu_single_env, addr, buf, l, 0);
|
||||
env = mon_get_cpu();
|
||||
if (!env)
|
||||
break;
|
||||
cpu_memory_rw_debug(env, addr, buf, l, 0);
|
||||
}
|
||||
i = 0;
|
||||
while (i < l) {
|
||||
@ -776,10 +837,14 @@ static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask)
|
||||
|
||||
static void tlb_info(void)
|
||||
{
|
||||
CPUState *env = cpu_single_env;
|
||||
CPUState *env;
|
||||
int l1, l2;
|
||||
uint32_t pgd, pde, pte;
|
||||
|
||||
env = mon_get_cpu();
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
if (!(env->cr[0] & CR0_PG_MASK)) {
|
||||
term_printf("PG disabled\n");
|
||||
return;
|
||||
@ -830,10 +895,14 @@ static void mem_print(uint32_t *pstart, int *plast_prot,
|
||||
|
||||
static void mem_info(void)
|
||||
{
|
||||
CPUState *env = cpu_single_env;
|
||||
CPUState *env;
|
||||
int l1, l2, prot, last_prot;
|
||||
uint32_t pgd, pde, pte, start, end;
|
||||
|
||||
env = mon_get_cpu();
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
if (!(env->cr[0] & CR0_PG_MASK)) {
|
||||
term_printf("PG disabled\n");
|
||||
return;
|
||||
@ -874,10 +943,15 @@ static void mem_info(void)
|
||||
static void do_info_kqemu(void)
|
||||
{
|
||||
#ifdef USE_KQEMU
|
||||
CPUState *env;
|
||||
int val;
|
||||
val = 0;
|
||||
if (cpu_single_env)
|
||||
val = cpu_single_env->kqemu_enabled;
|
||||
env = mon_get_cpu();
|
||||
if (!env) {
|
||||
term_printf("No cpu initialized yet");
|
||||
return;
|
||||
}
|
||||
val = env->kqemu_enabled;
|
||||
term_printf("kqemu is %s\n", val ? "enabled" : "disabled");
|
||||
#else
|
||||
term_printf("kqemu support is not compiled\n");
|
||||
@ -934,6 +1008,8 @@ static term_cmd_t term_cmds[] = {
|
||||
"device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" },
|
||||
{ "usb_del", "s", do_usb_del,
|
||||
"device", "remove USB device 'bus.addr'" },
|
||||
{ "cpu", "i", do_cpu_set,
|
||||
"index", "set the default CPU" },
|
||||
{ NULL, NULL, },
|
||||
};
|
||||
|
||||
@ -946,6 +1022,8 @@ static term_cmd_t info_cmds[] = {
|
||||
"", "show the block devices" },
|
||||
{ "registers", "", do_info_registers,
|
||||
"", "show the cpu registers" },
|
||||
{ "cpus", "", do_info_cpus,
|
||||
"", "show infos for each CPU" },
|
||||
{ "history", "", do_info_history,
|
||||
"", "show the command line history", },
|
||||
{ "irq", "", irq_info,
|
||||
@ -989,63 +1067,85 @@ typedef struct MonitorDef {
|
||||
#if defined(TARGET_I386)
|
||||
static target_long monitor_get_pc (struct MonitorDef *md, int val)
|
||||
{
|
||||
return cpu_single_env->eip + cpu_single_env->segs[R_CS].base;
|
||||
CPUState *env = mon_get_cpu();
|
||||
if (!env)
|
||||
return 0;
|
||||
return env->eip + env->segs[R_CS].base;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_PPC)
|
||||
static target_long monitor_get_ccr (struct MonitorDef *md, int val)
|
||||
{
|
||||
CPUState *env = mon_get_cpu();
|
||||
unsigned int u;
|
||||
int i;
|
||||
|
||||
if (!env)
|
||||
return 0;
|
||||
|
||||
u = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
u |= cpu_single_env->crf[i] << (32 - (4 * i));
|
||||
u |= env->crf[i] << (32 - (4 * i));
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
static target_long monitor_get_msr (struct MonitorDef *md, int val)
|
||||
{
|
||||
return (cpu_single_env->msr[MSR_POW] << MSR_POW) |
|
||||
(cpu_single_env->msr[MSR_ILE] << MSR_ILE) |
|
||||
(cpu_single_env->msr[MSR_EE] << MSR_EE) |
|
||||
(cpu_single_env->msr[MSR_PR] << MSR_PR) |
|
||||
(cpu_single_env->msr[MSR_FP] << MSR_FP) |
|
||||
(cpu_single_env->msr[MSR_ME] << MSR_ME) |
|
||||
(cpu_single_env->msr[MSR_FE0] << MSR_FE0) |
|
||||
(cpu_single_env->msr[MSR_SE] << MSR_SE) |
|
||||
(cpu_single_env->msr[MSR_BE] << MSR_BE) |
|
||||
(cpu_single_env->msr[MSR_FE1] << MSR_FE1) |
|
||||
(cpu_single_env->msr[MSR_IP] << MSR_IP) |
|
||||
(cpu_single_env->msr[MSR_IR] << MSR_IR) |
|
||||
(cpu_single_env->msr[MSR_DR] << MSR_DR) |
|
||||
(cpu_single_env->msr[MSR_RI] << MSR_RI) |
|
||||
(cpu_single_env->msr[MSR_LE] << MSR_LE);
|
||||
CPUState *env = mon_get_cpu();
|
||||
if (!env)
|
||||
return 0;
|
||||
return (env->msr[MSR_POW] << MSR_POW) |
|
||||
(env->msr[MSR_ILE] << MSR_ILE) |
|
||||
(env->msr[MSR_EE] << MSR_EE) |
|
||||
(env->msr[MSR_PR] << MSR_PR) |
|
||||
(env->msr[MSR_FP] << MSR_FP) |
|
||||
(env->msr[MSR_ME] << MSR_ME) |
|
||||
(env->msr[MSR_FE0] << MSR_FE0) |
|
||||
(env->msr[MSR_SE] << MSR_SE) |
|
||||
(env->msr[MSR_BE] << MSR_BE) |
|
||||
(env->msr[MSR_FE1] << MSR_FE1) |
|
||||
(env->msr[MSR_IP] << MSR_IP) |
|
||||
(env->msr[MSR_IR] << MSR_IR) |
|
||||
(env->msr[MSR_DR] << MSR_DR) |
|
||||
(env->msr[MSR_RI] << MSR_RI) |
|
||||
(env->msr[MSR_LE] << MSR_LE);
|
||||
}
|
||||
|
||||
static target_long monitor_get_xer (struct MonitorDef *md, int val)
|
||||
{
|
||||
return (cpu_single_env->xer[XER_SO] << XER_SO) |
|
||||
(cpu_single_env->xer[XER_OV] << XER_OV) |
|
||||
(cpu_single_env->xer[XER_CA] << XER_CA) |
|
||||
(cpu_single_env->xer[XER_BC] << XER_BC);
|
||||
CPUState *env = mon_get_cpu();
|
||||
if (!env)
|
||||
return 0;
|
||||
return (env->xer[XER_SO] << XER_SO) |
|
||||
(env->xer[XER_OV] << XER_OV) |
|
||||
(env->xer[XER_CA] << XER_CA) |
|
||||
(env->xer[XER_BC] << XER_BC);
|
||||
}
|
||||
|
||||
static target_long monitor_get_decr (struct MonitorDef *md, int val)
|
||||
{
|
||||
return cpu_ppc_load_decr(cpu_single_env);
|
||||
CPUState *env = mon_get_cpu();
|
||||
if (!env)
|
||||
return 0;
|
||||
return cpu_ppc_load_decr(env);
|
||||
}
|
||||
|
||||
static target_long monitor_get_tbu (struct MonitorDef *md, int val)
|
||||
{
|
||||
return cpu_ppc_load_tbu(cpu_single_env);
|
||||
CPUState *env = mon_get_cpu();
|
||||
if (!env)
|
||||
return 0;
|
||||
return cpu_ppc_load_tbu(env);
|
||||
}
|
||||
|
||||
static target_long monitor_get_tbl (struct MonitorDef *md, int val)
|
||||
{
|
||||
return cpu_ppc_load_tbl(cpu_single_env);
|
||||
CPUState *env = mon_get_cpu();
|
||||
if (!env)
|
||||
return 0;
|
||||
return cpu_ppc_load_tbl(env);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1053,13 +1153,19 @@ static target_long monitor_get_tbl (struct MonitorDef *md, int val)
|
||||
#ifndef TARGET_SPARC64
|
||||
static target_long monitor_get_psr (struct MonitorDef *md, int val)
|
||||
{
|
||||
return GET_PSR(cpu_single_env);
|
||||
CPUState *env = mon_get_cpu();
|
||||
if (!env)
|
||||
return 0;
|
||||
return GET_PSR(env);
|
||||
}
|
||||
#endif
|
||||
|
||||
static target_long monitor_get_reg(struct MonitorDef *md, int val)
|
||||
{
|
||||
return cpu_single_env->regwptr[val];
|
||||
CPUState *env = mon_get_cpu();
|
||||
if (!env)
|
||||
return 0;
|
||||
return env->regwptr[val];
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1269,6 +1375,7 @@ static void expr_error(const char *fmt)
|
||||
longjmp(expr_env, 1);
|
||||
}
|
||||
|
||||
/* return 0 if OK, -1 if not found, -2 if no CPU defined */
|
||||
static int get_monitor_def(target_long *pval, const char *name)
|
||||
{
|
||||
MonitorDef *md;
|
||||
@ -1279,7 +1386,10 @@ static int get_monitor_def(target_long *pval, const char *name)
|
||||
if (md->get_value) {
|
||||
*pval = md->get_value(md, md->offset);
|
||||
} else {
|
||||
ptr = (uint8_t *)cpu_single_env + md->offset;
|
||||
CPUState *env = mon_get_cpu();
|
||||
if (!env)
|
||||
return -2;
|
||||
ptr = (uint8_t *)env + md->offset;
|
||||
switch(md->type) {
|
||||
case MD_I32:
|
||||
*pval = *(int32_t *)ptr;
|
||||
@ -1313,6 +1423,7 @@ static target_long expr_unary(void)
|
||||
{
|
||||
target_long n;
|
||||
char *p;
|
||||
int ret;
|
||||
|
||||
switch(*pch) {
|
||||
case '+':
|
||||
@ -1362,8 +1473,11 @@ static target_long expr_unary(void)
|
||||
while (isspace(*pch))
|
||||
pch++;
|
||||
*q = 0;
|
||||
if (get_monitor_def(&n, buf))
|
||||
ret = get_monitor_def(&n, buf);
|
||||
if (ret == -1)
|
||||
expr_error("unknown register");
|
||||
else if (ret == -2)
|
||||
expr_error("no cpu defined");
|
||||
}
|
||||
break;
|
||||
case '\0':
|
||||
|
99
vl.c
99
vl.c
@ -83,8 +83,6 @@
|
||||
|
||||
#include "exec-all.h"
|
||||
|
||||
//#define DO_TB_FLUSH
|
||||
|
||||
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
|
||||
|
||||
//#define DEBUG_UNUSED_IOPORT
|
||||
@ -109,8 +107,6 @@
|
||||
|
||||
const char *bios_dir = CONFIG_QEMU_SHAREDIR;
|
||||
char phys_ram_file[1024];
|
||||
CPUState *global_env;
|
||||
CPUState *cpu_single_env;
|
||||
void *ioport_opaque[MAX_IOPORTS];
|
||||
IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
|
||||
IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
|
||||
@ -156,6 +152,7 @@ int usb_enabled = 0;
|
||||
USBPort *vm_usb_ports[MAX_VM_USB_PORTS];
|
||||
USBDevice *vm_usb_hub;
|
||||
static VLANState *first_vlan;
|
||||
int smp_cpus = 1;
|
||||
|
||||
/***********************************************************/
|
||||
/* x86 ISA bus support */
|
||||
@ -427,16 +424,20 @@ int cpu_inl(CPUState *env, int addr)
|
||||
void hw_error(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
CPUState *env;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "qemu: hardware error: ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
for(env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
fprintf(stderr, "CPU #%d:\n", env->cpu_index);
|
||||
#ifdef TARGET_I386
|
||||
cpu_dump_state(global_env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
|
||||
cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU);
|
||||
#else
|
||||
cpu_dump_state(global_env, stderr, fprintf, 0);
|
||||
cpu_dump_state(env, stderr, fprintf, 0);
|
||||
#endif
|
||||
}
|
||||
va_end(ap);
|
||||
abort();
|
||||
}
|
||||
@ -879,13 +880,16 @@ static void host_alarm_handler(int host_signum)
|
||||
qemu_get_clock(vm_clock)) ||
|
||||
qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
|
||||
qemu_get_clock(rt_clock))) {
|
||||
/* stop the cpu because a timer occured */
|
||||
cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
|
||||
CPUState *env = cpu_single_env;
|
||||
if (env) {
|
||||
/* stop the currently executing cpu because a timer occured */
|
||||
cpu_interrupt(env, CPU_INTERRUPT_EXIT);
|
||||
#ifdef USE_KQEMU
|
||||
if (global_env->kqemu_enabled) {
|
||||
kqemu_cpu_interrupt(global_env);
|
||||
}
|
||||
if (env->kqemu_enabled) {
|
||||
kqemu_cpu_interrupt(env);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2970,9 +2974,6 @@ int qemu_loadvm(const char *filename)
|
||||
goto the_end;
|
||||
}
|
||||
for(;;) {
|
||||
#if defined (DO_TB_FLUSH)
|
||||
tb_flush(global_env);
|
||||
#endif
|
||||
len = qemu_get_byte(f);
|
||||
if (feof(f))
|
||||
break;
|
||||
@ -3583,27 +3584,22 @@ void qemu_system_reset(void)
|
||||
void qemu_system_reset_request(void)
|
||||
{
|
||||
reset_requested = 1;
|
||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
|
||||
if (cpu_single_env)
|
||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
|
||||
}
|
||||
|
||||
void qemu_system_shutdown_request(void)
|
||||
{
|
||||
shutdown_requested = 1;
|
||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
|
||||
if (cpu_single_env)
|
||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
|
||||
}
|
||||
|
||||
void qemu_system_powerdown_request(void)
|
||||
{
|
||||
powerdown_requested = 1;
|
||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
|
||||
}
|
||||
|
||||
static void main_cpu_reset(void *opaque)
|
||||
{
|
||||
#if defined(TARGET_I386) || defined(TARGET_SPARC)
|
||||
CPUState *env = opaque;
|
||||
cpu_reset(env);
|
||||
#endif
|
||||
if (cpu_single_env)
|
||||
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
|
||||
}
|
||||
|
||||
void main_loop_wait(int timeout)
|
||||
@ -3684,14 +3680,42 @@ void main_loop_wait(int timeout)
|
||||
qemu_get_clock(rt_clock));
|
||||
}
|
||||
|
||||
static CPUState *cur_cpu;
|
||||
|
||||
static CPUState *find_next_cpu(void)
|
||||
{
|
||||
CPUState *env;
|
||||
env = cur_cpu;
|
||||
for(;;) {
|
||||
/* get next cpu */
|
||||
env = env->next_cpu;
|
||||
if (!env)
|
||||
env = first_cpu;
|
||||
if (!env->cpu_halted)
|
||||
break;
|
||||
/* all CPUs are halted ? */
|
||||
if (env == cur_cpu)
|
||||
return NULL;
|
||||
}
|
||||
cur_cpu = env;
|
||||
return env;
|
||||
}
|
||||
|
||||
int main_loop(void)
|
||||
{
|
||||
int ret, timeout;
|
||||
CPUState *env = global_env;
|
||||
CPUState *env;
|
||||
|
||||
cur_cpu = first_cpu;
|
||||
for(;;) {
|
||||
if (vm_running) {
|
||||
ret = cpu_exec(env);
|
||||
/* find next cpu to run */
|
||||
/* XXX: handle HLT correctly */
|
||||
env = find_next_cpu();
|
||||
if (!env)
|
||||
ret = EXCP_HLT;
|
||||
else
|
||||
ret = cpu_exec(env);
|
||||
if (shutdown_requested) {
|
||||
ret = EXCP_INTERRUPT;
|
||||
break;
|
||||
@ -3774,7 +3798,7 @@ void help(void)
|
||||
" connect the host TAP network interface to VLAN 'n' and use\n"
|
||||
" the network script 'file' (default=%s);\n"
|
||||
" use 'fd=h' to connect to an already opened TAP interface\n"
|
||||
"-net socket[,vlan=n][,fd=x][,listen=[host]:port][,connect=host:port]\n"
|
||||
"-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n"
|
||||
" connect the vlan 'n' to another VLAN using a socket connection\n"
|
||||
#endif
|
||||
"-net none use it alone to have zero network devices; if no -net option\n"
|
||||
@ -3899,6 +3923,7 @@ enum {
|
||||
QEMU_OPTION_win2k_hack,
|
||||
QEMU_OPTION_usb,
|
||||
QEMU_OPTION_usbdevice,
|
||||
QEMU_OPTION_smp,
|
||||
};
|
||||
|
||||
typedef struct QEMUOption {
|
||||
@ -3965,6 +3990,7 @@ const QEMUOption qemu_options[] = {
|
||||
{ "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
|
||||
{ "win2k-hack", 0, QEMU_OPTION_win2k_hack },
|
||||
{ "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice },
|
||||
{ "smp", HAS_ARG, QEMU_OPTION_smp },
|
||||
|
||||
/* temporary options */
|
||||
{ "usb", 0, QEMU_OPTION_usb },
|
||||
@ -4120,7 +4146,6 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
int i, cdrom_index;
|
||||
int snapshot, linux_boot;
|
||||
CPUState *env;
|
||||
const char *initrd_filename;
|
||||
const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD];
|
||||
const char *kernel_filename, *kernel_cmdline;
|
||||
@ -4511,6 +4536,13 @@ int main(int argc, char **argv)
|
||||
optarg);
|
||||
usb_devices_index++;
|
||||
break;
|
||||
case QEMU_OPTION_smp:
|
||||
smp_cpus = atoi(optarg);
|
||||
if (smp_cpus < 1 || smp_cpus > 8) {
|
||||
fprintf(stderr, "Invalid number of CPUs\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4659,15 +4691,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
/* init CPU state */
|
||||
env = cpu_init();
|
||||
global_env = env;
|
||||
cpu_single_env = env;
|
||||
|
||||
register_savevm("timer", 0, 1, timer_save, timer_load, env);
|
||||
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
|
||||
register_savevm("timer", 0, 1, timer_save, timer_load, NULL);
|
||||
register_savevm("ram", 0, 1, ram_save, ram_load, NULL);
|
||||
qemu_register_reset(main_cpu_reset, global_env);
|
||||
|
||||
init_ioports();
|
||||
cpu_calibrate_ticks();
|
||||
|
7
vl.h
7
vl.h
@ -142,6 +142,7 @@ extern const char *keyboard_layout;
|
||||
extern int kqemu_allowed;
|
||||
extern int win2k_install_hack;
|
||||
extern int usb_enabled;
|
||||
extern int smp_cpus;
|
||||
|
||||
/* XXX: make it dynamic */
|
||||
#if defined (TARGET_PPC)
|
||||
@ -429,6 +430,9 @@ int register_savevm(const char *idstr,
|
||||
void qemu_get_timer(QEMUFile *f, QEMUTimer *ts);
|
||||
void qemu_put_timer(QEMUFile *f, QEMUTimer *ts);
|
||||
|
||||
void cpu_save(QEMUFile *f, void *opaque);
|
||||
int cpu_load(QEMUFile *f, void *opaque, int version_id);
|
||||
|
||||
/* block.c */
|
||||
typedef struct BlockDriverState BlockDriverState;
|
||||
typedef struct BlockDriver BlockDriver;
|
||||
@ -774,6 +778,9 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time);
|
||||
extern QEMUMachine pc_machine;
|
||||
extern QEMUMachine isapc_machine;
|
||||
|
||||
void ioport_set_a20(int enable);
|
||||
int ioport_get_a20(void);
|
||||
|
||||
/* ppc.c */
|
||||
extern QEMUMachine prep_machine;
|
||||
extern QEMUMachine core99_machine;
|
||||
|
Loading…
Reference in New Issue
Block a user