From a541f297a37e64673aac52abc858e0904e316b48 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 12 Apr 2004 20:39:29 +0000 Subject: PowerPC system emulation fixes (Jocelyn Mayer) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@722 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/cpu.h | 50 +-- target-ppc/exec.h | 5 + target-ppc/helper.c | 349 +++++++++--------- target-ppc/hw.c | 935 ------------------------------------------------- target-ppc/op.c | 21 +- target-ppc/op_helper.c | 50 +-- target-ppc/translate.c | 48 ++- 7 files changed, 271 insertions(+), 1187 deletions(-) delete mode 100644 target-ppc/hw.c (limited to 'target-ppc') diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3809f20..6cd0895 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -20,9 +20,6 @@ #if !defined (__CPU_PPC_H__) #define __CPU_PPC_H__ -#include -#include - #define TARGET_LONG_BITS 32 #include "cpu-defs.h" @@ -157,14 +154,26 @@ typedef struct CPUPPCState { int error_code; int access_type; /* when a memory exception occurs, the access type is stored here */ +#if 0 /* TODO */ + uint32_t pending_exceptions; /* For external & decr exception, + * that can be delayed */ +#else uint32_t exceptions; /* exception queue */ - uint32_t errors[16]; + uint32_t errors[32]; +#endif int user_mode_only; /* user mode only simulation */ struct TranslationBlock *current_tb; /* currently executing TB */ /* soft mmu support */ - /* 0 = kernel, 1 = user */ + /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */ CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; + + /* ice debug support */ + uint32_t breakpoints[MAX_BREAKPOINTS]; + int nb_breakpoints; + int brkstate; + int singlestep_enabled; + /* user data */ void *opaque; } CPUPPCState; @@ -179,14 +188,21 @@ struct siginfo; int cpu_ppc_signal_handler(int host_signum, struct siginfo *info, void *puc); -void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); +void do_interrupt (CPUPPCState *env); void cpu_loop_exit(void); + +void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); void dump_stack (CPUPPCState *env); -uint32_t _load_xer (void); -void _store_xer (uint32_t value); -uint32_t _load_msr (void); -void _store_msr (uint32_t value); -void do_interrupt (CPUPPCState *env); + +uint32_t _load_xer (CPUPPCState *env); +void _store_xer (CPUPPCState *env, uint32_t value); +uint32_t _load_msr (CPUPPCState *env); +void _store_msr (CPUPPCState *env, uint32_t value); + +void PPC_init_hw (uint32_t mem_size, + uint32_t kernel_addr, uint32_t kernel_size, + uint32_t stack_addr, int boot_device, + const unsigned char *initrd_file); #define TARGET_PAGE_BITS 12 #include "cpu-all.h" @@ -277,14 +293,6 @@ void do_interrupt (CPUPPCState *env); #define TARGET_PAGE_BITS 12 #include "cpu-all.h" -CPUPPCState *cpu_ppc_init(void); -int cpu_ppc_exec(CPUPPCState *s); -void cpu_ppc_close(CPUPPCState *s); -void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags); -void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, - uint32_t kernel_addr, uint32_t kernel_size, - uint32_t stack_addr, int boot_device); - /* Memory access type : * may be needed for precise access rights control and precise exceptions. */ @@ -351,12 +359,14 @@ enum { /* flags for EXCP_DSI */ EXCP_DSI_DIRECT = 0x10, EXCP_DSI_STORE = 0x20, - EXCP_ECXW = 0x40, + EXCP_DSI_ECXW = 0x40, /* Exception subtypes for EXCP_ISI */ EXCP_ISI_TRANSLATE = 0x01, /* Code address can't be translated */ EXCP_ISI_NOEXEC = 0x02, /* Try to fetch from a data segment */ EXCP_ISI_GUARD = 0x03, /* Fetch from guarded memory */ EXCP_ISI_PROT = 0x04, /* Memory protection violation */ + EXCP_ISI_DIRECT = 0x05, /* Trying to fetch from * + * a direct store segment */ /* Exception subtypes for EXCP_ALIGN */ EXCP_ALIGN_FP = 0x01, /* FP alignment exception */ EXCP_ALIGN_LST = 0x02, /* Unaligned mult/extern load/store */ diff --git a/target-ppc/exec.h b/target-ppc/exec.h index 8a255ec..72bd03e 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -36,7 +36,11 @@ register uint32_t T2 asm(AREG3); #define FTS1 ((float)env->ft1) #define FTS2 ((float)env->ft2) +#if defined (DEBUG_OP) +#define RETURN() __asm__ __volatile__("nop"); +#else #define RETURN() __asm__ __volatile__(""); +#endif #include "cpu.h" #include "exec-all.h" @@ -149,6 +153,7 @@ void do_icbi (void); void do_tlbia (void); void do_tlbie (void); +void dump_state (void); void dump_rfi (void); void dump_store_sr (int srnum); void dump_store_ibat (int ul, int nr); diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 4e8206e..e4bc054 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -21,6 +21,7 @@ #include "exec.h" #if defined (USE_OPEN_FIRMWARE) +#include #include "of.h" #endif @@ -28,7 +29,7 @@ //#define DEBUG_BATS //#define DEBUG_EXCEPTIONS -extern FILE *logfile, *stderr; +extern FILE *logfile, *stdout, *stderr; void exit (int); void abort (void); @@ -74,6 +75,9 @@ int check_exception_state (CPUState *env) /*****************************************************************************/ /* PPC MMU emulation */ +int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, + int is_user, int is_softmmu); + /* Perform BAT hit & translation */ static int get_bat (CPUState *env, uint32_t *real, int *prot, uint32_t virtual, int rw, int type) @@ -88,8 +92,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__, type == ACCESS_CODE ? 'I' : 'D', virtual); } - printf("%s: %cBAT v 0x%08x\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', virtual); #endif switch (type) { case ACCESS_CODE: @@ -106,8 +108,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__, type == ACCESS_CODE ? 'I' : 'D', virtual); } - printf("%s...: %cBAT v 0x%08x\n", __func__, - type == ACCESS_CODE ? 'I' : 'D', virtual); #endif base = virtual & 0xFFFC0000; for (i = 0; i < 4; i++) { @@ -121,10 +121,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, fprintf(logfile, "%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl); - } else { - printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", - __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, - *BATu, *BATl); } #endif if ((virtual & 0xF0000000) == BEPIu && @@ -135,7 +131,7 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, /* Get physical address */ *real = (*BATl & 0xF0000000) | ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | - (virtual & 0x0001FFFF); + (virtual & 0x0001F000); if (*BATl & 0x00000001) *prot = PROT_READ; if (*BATl & 0x00000002) @@ -145,10 +141,6 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n", i, *real, *prot & PROT_READ ? 'R' : '-', *prot & PROT_WRITE ? 'W' : '-'); - } else { - printf("BAT %d match: 0x%08x => 0x%08x prot=%c%c\n", - i, virtual, *real, *prot & PROT_READ ? 'R' : '-', - *prot & PROT_WRITE ? 'W' : '-'); } #endif ret = 0; @@ -181,7 +173,7 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot, static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, int h, int key, int rw) { - uint32_t pte0, pte1, keep = 0; + uint32_t pte0, pte1, keep = 0, access = 0; int i, good = -1, store = 0; int ret = -1; /* No entry found */ @@ -189,85 +181,97 @@ static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, pte0 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8))); pte1 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8) + 4)); #if defined (DEBUG_MMU) - printf("Load pte from 0x%08x => 0x%08x 0x%08x\n", base + (i * 8), - pte0, pte1); + if (loglevel > 0) { + fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x " + "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1, + pte0 >> 31, h, (pte0 >> 6) & 1, va); + } #endif /* Check validity and table match */ if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) { -#if defined (DEBUG_MMU) - printf("PTE is valid and table matches... compare 0x%08x:%08x\n", - pte0 & 0x7FFFFFBF, va); -#endif /* Check vsid & api */ if ((pte0 & 0x7FFFFFBF) == va) { -#if defined (DEBUG_MMU) - printf("PTE match !\n"); -#endif if (good == -1) { good = i; keep = pte1; } else { /* All matches should have equal RPN, WIMG & PP */ if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) { - printf("Bad RPN/WIMG/PP\n"); + if (loglevel > 0) + fprintf(logfile, "Bad RPN/WIMG/PP\n"); return -1; } } /* Check access rights */ if (key == 0) { - *prot = PROT_READ; + access = PROT_READ; if ((pte1 & 0x00000003) != 0x3) - *prot |= PROT_WRITE; + access |= PROT_WRITE; } else { switch (pte1 & 0x00000003) { case 0x0: - *prot = 0; + access = 0; break; case 0x1: case 0x3: - *prot = PROT_READ; + access = PROT_READ; break; case 0x2: - *prot = PROT_READ | PROT_WRITE; + access = PROT_READ | PROT_WRITE; break; } } - if ((rw == 0 && *prot != 0) || - (rw == 1 && (*prot & PROT_WRITE))) { + if (ret < 0) { + if ((rw == 0 && (access & PROT_READ)) || + (rw == 1 && (access & PROT_WRITE))) { #if defined (DEBUG_MMU) - printf("PTE access granted !\n"); + if (loglevel > 0) + fprintf(logfile, "PTE access granted !\n"); #endif good = i; keep = pte1; ret = 0; - } else if (ret == -1) { - ret = -2; /* Access right violation */ + } else { + /* Access right violation */ + ret = -2; #if defined (DEBUG_MMU) - printf("PTE access rejected\n"); + if (loglevel > 0) + fprintf(logfile, "PTE access rejected\n"); #endif } + *prot = access; + } } } } if (good != -1) { *RPN = keep & 0xFFFFF000; #if defined (DEBUG_MMU) - printf("found PTE at addr 0x%08x prot=0x%01x ret=%d\n", + if (loglevel > 0) { + fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n", *RPN, *prot, ret); + } #endif /* Update page flags */ if (!(keep & 0x00000100)) { + /* Access flag */ keep |= 0x00000100; store = 1; } - if (rw) { if (!(keep & 0x00000080)) { + if (rw && ret == 0) { + /* Change flag */ keep |= 0x00000080; store = 1; + } else { + /* Force page fault for first write access */ + *prot &= ~PROT_WRITE; } } - if (store) - stl_raw((void *)(base + (good * 2) + 1), keep); + if (store) { + stl_raw((void *)((uint32_t)phys_ram_base + base + (good * 8) + 4), + keep); + } } return ret; @@ -290,29 +294,37 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot, sr = env->sr[virtual >> 28]; #if defined (DEBUG_MMU) - printf("Check segment v=0x%08x %d 0x%08x nip=0x%08x lr=0x%08x ir=%d dr=%d " - "pr=%d t=%d\n", virtual, virtual >> 28, sr, env->nip, - env->lr, msr_ir, msr_dr, msr_pr, type); + if (loglevel > 0) { + fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x " + "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n", + virtual, virtual >> 28, sr, env->nip, + env->lr, msr_ir, msr_dr, msr_pr, rw, type); + } #endif - key = ((sr & 0x20000000) && msr_pr == 1) || - ((sr & 0x40000000) && msr_pr == 0) ? 1 : 0; + key = (((sr & 0x20000000) && msr_pr == 1) || + ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0; if ((sr & 0x80000000) == 0) { #if defined (DEBUG_MMU) - printf("pte segment: key=%d n=0x%08x\n", key, sr & 0x10000000); + if (loglevel > 0) + fprintf(logfile, "pte segment: key=%d n=0x%08x\n", + key, sr & 0x10000000); #endif /* Check if instruction fetch is allowed, if needed */ if (type != ACCESS_CODE || (sr & 0x10000000) == 0) { /* Page address translation */ vsid = sr & 0x00FFFFFF; pgidx = (virtual >> 12) & 0xFFFF; - sdr = env->spr[SDR1]; - hash = ((vsid ^ pgidx) & 0x07FFFF) << 6; + sdr = env->sdr1; + hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6; mask = ((sdr & 0x000001FF) << 16) | 0xFFC0; pg_addr = get_pgaddr(sdr, hash, mask); ptem = (vsid << 7) | (pgidx >> 10); #if defined (DEBUG_MMU) - printf("0 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%07x " - "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr); + if (loglevel > 0) { + fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x " + "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, + pg_addr); + } #endif /* Primary table lookup */ ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw); @@ -321,25 +333,27 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot, hash = (~hash) & 0x01FFFFC0; pg_addr = get_pgaddr(sdr, hash, mask); #if defined (DEBUG_MMU) - printf("1 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%05x " - "pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr); + if (virtual != 0xEFFFFFFF && loglevel > 0) { + fprintf(logfile, "1 sdr1=0x%08x vsid=0x%06x api=0x%04x " + "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, pgidx, + hash, pg_addr); + } #endif ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw); if (ret2 != -1) ret = ret2; } - if (ret != -1) - *real |= (virtual & 0x00000FFF); - if (ret == -2 && type == ACCESS_CODE && (sr & 0x10000000)) - ret = -3; } else { #if defined (DEBUG_MMU) - printf("No access allowed\n"); + if (loglevel > 0) + fprintf(logfile, "No access allowed\n"); #endif + ret = -3; } } else { #if defined (DEBUG_MMU) - printf("direct store...\n"); + if (loglevel > 0) + fprintf(logfile, "direct store...\n"); #endif /* Direct-store segment : absolutely *BUGGY* for now */ switch (type) { @@ -393,9 +407,10 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, if (loglevel > 0) { fprintf(logfile, "%s\n", __func__); } + if ((access_type == ACCESS_CODE && msr_ir == 0) || msr_dr == 0) { /* No address translation */ - *physical = address; + *physical = address & ~0xFFF; *prot = PROT_READ | PROT_WRITE; ret = 0; } else { @@ -406,6 +421,10 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot, ret = get_segment(env, physical, prot, address, rw, access_type); } } + if (loglevel > 0) { + fprintf(logfile, "%s address %08x => %08x\n", + __func__, address, *physical); + } return ret; } @@ -448,18 +467,17 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ /* XXX: fix it to restore all registers */ -void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) +void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) { TranslationBlock *tb; - int ret, is_user; - unsigned long pc; CPUState *saved_env; + unsigned long pc; + int ret; /* XXX: hack to restore env in all cases, even if not called from generated code */ saved_env = env; env = cpu_single_env; - is_user = flags & 0x01; { unsigned long tlb_addrr, tlb_addrw; int index; @@ -474,7 +492,7 @@ void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); #endif } - ret = cpu_handle_mmu_fault(env, addr, is_write, flags, 1); + ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1); if (ret) { if (retaddr) { /* now we have a real cpu fault */ @@ -506,7 +524,7 @@ void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr) env = saved_env; } -void cpu_ppc_init_mmu(CPUPPCState *env) +void cpu_ppc_init_mmu(CPUState *env) { /* Nothing to do: all translation are disabled */ } @@ -514,59 +532,36 @@ void cpu_ppc_init_mmu(CPUPPCState *env) /* Perform address translation */ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, - int flags, int is_softmmu) + int is_user, int is_softmmu) { uint32_t physical; int prot; int exception = 0, error_code = 0; - int is_user, access_type; + int access_type; int ret = 0; // printf("%s 0\n", __func__); - is_user = flags & 0x01; access_type = env->access_type; if (env->user_mode_only) { /* user mode only emulation */ ret = -1; goto do_fault; } + /* NASTY BUG workaround */ + if (access_type == ACCESS_CODE && rw) { + // printf("%s: ERROR WRITE CODE ACCESS\n", __func__); + access_type = ACCESS_INT; + } ret = get_physical_address(env, &physical, &prot, address, rw, access_type); if (ret == 0) { - ret = tlb_set_page(env, address, physical, prot, is_user, is_softmmu); + ret = tlb_set_page(env, address & ~0xFFF, physical, prot, + is_user, is_softmmu); } else if (ret < 0) { do_fault: #if defined (DEBUG_MMU) - printf("%s 5\n", __func__); - printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x TBL=0x%08x\n", - env->nip, env->lr, env->ctr, /*msr*/0, env->tb[0]); - { - int i; - for (i = 0; i < 32; i++) { - if ((i & 7) == 0) - printf("GPR%02d:", i); - printf(" %08x", env->gpr[i]); - if ((i & 7) == 7) - printf("\n"); - } - printf("CR: 0x"); - for (i = 0; i < 8; i++) - printf("%01x", env->crf[i]); - printf(" ["); - for (i = 0; i < 8; i++) { - char a = '-'; - if (env->crf[i] & 0x08) - a = 'L'; - else if (env->crf[i] & 0x04) - a = 'G'; - else if (env->crf[i] & 0x02) - a = 'E'; - printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); - } - printf(" ] "); - } - printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); - printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]); + if (loglevel > 0) + cpu_ppc_dump_state(env, logfile, 0); #endif if (access_type == ACCESS_CODE) { exception = EXCP_ISI; @@ -580,13 +575,13 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, error_code = EXCP_ISI_PROT; break; case -3: + /* No execute protection violation */ error_code = EXCP_ISI_NOEXEC; break; case -4: /* Direct store exception */ /* No code fetch is allowed in direct-store areas */ - exception = EXCP_ISI; - error_code = EXCP_ISI_NOEXEC; + error_code = EXCP_ISI_DIRECT; break; } } else { @@ -612,15 +607,15 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, /* lwarx, ldarx or srwcx. */ exception = EXCP_DSI; error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT; - if (rw) - error_code |= EXCP_DSI_STORE; break; case ACCESS_EXT: /* eciwx or ecowx */ exception = EXCP_DSI; - error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | EXCP_ECXW; + error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | + EXCP_DSI_ECXW; break; default: + printf("DSI: invalid exception (%d)\n", ret); exception = EXCP_PROGRAM; error_code = EXCP_INVAL | EXCP_INVAL_INVAL; break; @@ -628,27 +623,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, } if (rw) error_code |= EXCP_DSI_STORE; - /* Should find a better solution: - * this will be invalid for some exception if more than one - * exception occurs for one instruction - */ - env->spr[DSISR] = 0; - if (error_code & EXCP_DSI_DIRECT) { - env->spr[DSISR] |= 0x80000000; - if (access_type == ACCESS_EXT || - access_type == ACCESS_RES) - env->spr[DSISR] |= 0x04000000; - } - if ((error_code & 0xF) == EXCP_DSI_TRANSLATE) - env->spr[DSISR] |= 0x40000000; - if (error_code & EXCP_DSI_PROT) - env->spr[DSISR] |= 0x08000000; - if (error_code & EXCP_DSI_STORE) - env->spr[DSISR] |= 0x02000000; - if ((error_code & 0xF) == EXCP_DSI_DABR) - env->spr[DSISR] |= 0x00400000; - if (access_type == ACCESS_EXT) - env->spr[DSISR] |= 0x00100000; + /* Store fault address */ + env->spr[DAR] = address; } #if 0 printf("%s: set exception to %d %02x\n", @@ -656,15 +632,13 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, #endif env->exception_index = exception; env->error_code = error_code; - /* Store fault address */ - env->spr[DAR] = address; ret = 1; } return ret; } -uint32_t _load_xer (void) +uint32_t _load_xer (CPUState *env) { return (xer_so << XER_SO) | (xer_ov << XER_OV) | @@ -672,7 +646,7 @@ uint32_t _load_xer (void) (xer_bc << XER_BC); } -void _store_xer (uint32_t value) +void _store_xer (CPUState *env, uint32_t value) { xer_so = (value >> XER_SO) & 0x01; xer_ov = (value >> XER_OV) & 0x01; @@ -680,7 +654,7 @@ void _store_xer (uint32_t value) xer_bc = (value >> XER_BC) & 0x1f; } -uint32_t _load_msr (void) +uint32_t _load_msr (CPUState *env) { return (msr_pow << MSR_POW) | (msr_ile << MSR_ILE) | @@ -699,8 +673,13 @@ uint32_t _load_msr (void) (msr_le << MSR_LE); } -void _store_msr (uint32_t value) +void _store_msr (CPUState *env, uint32_t value) { + if (((T0 >> MSR_IR) & 0x01) != msr_ir || + ((T0 >> MSR_DR) & 0x01) != msr_dr) { + /* Flush all tlb when changing translation mode or privilege level */ + do_tlbia(); + } msr_pow = (value >> MSR_POW) & 0x03; msr_ile = (value >> MSR_ILE) & 0x01; msr_ee = (value >> MSR_EE) & 0x01; @@ -729,47 +708,16 @@ void do_interrupt (CPUState *env) /* Dequeue PPC exceptions */ if (excp < EXCP_PPC_MAX) env->exceptions &= ~(1 << excp); - msr = _load_msr(); + msr = _load_msr(env); #if defined (DEBUG_EXCEPTIONS) - if (excp != EXCP_DECR && excp == EXCP_PROGRAM && excp < EXCP_PPC_MAX) + if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) { if (loglevel > 0) { fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n", env->nip, excp << 8, env->error_code); - } else { - printf("Raise exception at 0x%08x => 0x%08x (%02x)\n", - env->nip, excp << 8, env->error_code); - } - printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x DECR=0x%08x\n", - env->nip, env->lr, env->ctr, msr, env->decr); - { - int i; - for (i = 0; i < 32; i++) { - if ((i & 7) == 0) - printf("GPR%02d:", i); - printf(" %08x", env->gpr[i]); - if ((i & 7) == 7) - printf("\n"); - } - printf("CR: 0x"); - for (i = 0; i < 8; i++) - printf("%01x", env->crf[i]); - printf(" ["); - for (i = 0; i < 8; i++) { - char a = '-'; - if (env->crf[i] & 0x08) - a = 'L'; - else if (env->crf[i] & 0x04) - a = 'G'; - else if (env->crf[i] & 0x02) - a = 'E'; - printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); } - printf(" ] "); - } - printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); - printf("XER 0x%08x SRR0 0x%08x SRR1 0x%08x\n", - _load_xer(), env->spr[SRR0], env->spr[SRR1]); + if (loglevel > 0) + cpu_ppc_dump_state(env, logfile, 0); } #endif /* Generate informations in save/restore registers */ @@ -812,26 +760,63 @@ void do_interrupt (CPUState *env) /* data location address has been stored * when the fault has been detected */ - goto store_current; + msr &= ~0xFFFF0000; + env->spr[DSISR] = 0; + if (env->error_code & EXCP_DSI_TRANSLATE) + env->spr[DSISR] |= 0x40000000; + else if (env->error_code & EXCP_DSI_PROT) + env->spr[DSISR] |= 0x08000000; + else if (env->error_code & EXCP_DSI_NOTSUP) { + env->spr[DSISR] |= 0x80000000; + if (env->error_code & EXCP_DSI_DIRECT) + env->spr[DSISR] |= 0x04000000; + } + if (env->error_code & EXCP_DSI_STORE) + env->spr[DSISR] |= 0x02000000; + if ((env->error_code & 0xF) == EXCP_DSI_DABR) + env->spr[DSISR] |= 0x00400000; + if (env->error_code & EXCP_DSI_ECXW) + env->spr[DSISR] |= 0x00100000; +#if defined (DEBUG_EXCEPTIONS) + if (loglevel) { + fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n", + env->spr[DSISR], env->spr[DAR]); + } else { + printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n", + env->spr[DSISR], env->spr[DAR], env->nip); + } +#endif + goto store_next; case EXCP_ISI: /* Store exception cause */ + msr &= ~0xFFFF0000; if (env->error_code == EXCP_ISI_TRANSLATE) msr |= 0x40000000; else if (env->error_code == EXCP_ISI_NOEXEC || - env->error_code == EXCP_ISI_GUARD) + env->error_code == EXCP_ISI_GUARD || + env->error_code == EXCP_ISI_DIRECT) msr |= 0x10000000; else msr |= 0x08000000; +#if defined (DEBUG_EXCEPTIONS) + if (loglevel) { + fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n", + msr, env->nip); + } else { + printf("ISI exception: msr=0x%08x, nip=0x%08x tbl:0x%08x\n", + msr, env->nip, env->spr[V_TBL]); + } +#endif goto store_next; case EXCP_EXTERNAL: if (msr_ee == 0) { #if defined (DEBUG_EXCEPTIONS) if (loglevel > 0) { fprintf(logfile, "Skipping hardware interrupt\n"); - } else { - printf("Skipping hardware interrupt\n"); } #endif + /* Requeue it */ + do_queue_exception(EXCP_EXTERNAL); return; } goto store_next; @@ -863,6 +848,7 @@ void do_interrupt (CPUState *env) env->fpscr[7] |= 0x4; break; case EXCP_INVAL: + printf("Invalid instruction at 0x%08x\n", env->nip); msr |= 0x00080000; break; case EXCP_PRIV: @@ -888,8 +874,17 @@ void do_interrupt (CPUState *env) goto store_next; case EXCP_SYSCALL: #if defined (DEBUG_EXCEPTIONS) - printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", - env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]); + if (msr_pr) { + if (loglevel) { + fprintf(logfile, "syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", + env->gpr[0], env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6]); + } else { + printf("syscall %d from 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", + env->gpr[0], env->nip, env->gpr[3], env->gpr[4], + env->gpr[5], env->gpr[6]); + } + } #endif goto store_next; case EXCP_TRACE: @@ -898,20 +893,16 @@ void do_interrupt (CPUState *env) goto store_next; case EXCP_MTMSR: /* Nothing to do */ -#if defined (DEBUG_EXCEPTIONS) - printf("%s: escape EXCP_MTMSR\n", __func__); -#endif return; case EXCP_BRANCH: /* Nothing to do */ -#if defined (DEBUG_EXCEPTIONS) - printf("%s: escape EXCP_BRANCH\n", __func__); -#endif return; case EXCP_RFI: /* Restore user-mode state */ + tb_flush(env); #if defined (DEBUG_EXCEPTIONS) - printf("%s: escape EXCP_RFI\n", __func__); + if (msr_pr == 1) + printf("Return from exception => 0x%08x\n", (uint32_t)env->nip); #endif return; store_current: diff --git a/target-ppc/hw.c b/target-ppc/hw.c deleted file mode 100644 index 090b610..0000000 --- a/target-ppc/hw.c +++ /dev/null @@ -1,935 +0,0 @@ -/* - * Hardware simulation for PPC target. - * For now, this is only a 'minimal' collection of hacks needed to boot Linux. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpu.h" -#include "vl.h" - -//#define HARD_DEBUG_PPC_IO -#define DEBUG_PPC_IO - -extern int loglevel; -extern FILE *logfile; - -#if defined (HARD_DEBUG_PPC_IO) && !defined (DEBUG_PPC_IO) -#define DEBUG_PPC_IO -#endif - -#if defined (HARD_DEBUG_PPC_IO) -#define PPC_IO_DPRINTF(fmt, args...) \ -do { \ - if (loglevel > 0) { \ - fprintf(logfile, "%s: " fmt, __func__ , ##args); \ - } else { \ - printf("%s : " fmt, __func__ , ##args); \ - } \ -} while (0) -#elif defined (DEBUG_PPC_IO) -#define PPC_IO_DPRINTF(fmt, args...) \ -do { \ - if (loglevel > 0) { \ - fprintf(logfile, "%s: " fmt, __func__ , ##args); \ - } \ -} while (0) -#else -#define PPC_IO_DPRINTF(fmt, args...) do { } while (0) -#endif - -#if defined (USE_OPEN_FIRMWARE) -#include "of.h" -#else -#define NVRAM_SIZE 0x2000 -#endif - -/* IO ports emulation */ -#define PPC_IO_BASE 0x80000000 - -static void PPC_io_writeb (uint32_t addr, uint32_t value) -{ - /* Don't polute serial port output */ - if ((addr < 0x800003F0 || addr > 0x80000400) && - (addr < 0x80000074 || addr > 0x80000077) && - (addr < 0x80000020 || addr > 0x80000021) && - (addr < 0x800000a0 || addr > 0x800000a1) && - (addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177)) { - PPC_IO_DPRINTF("0x%08x => 0x%02x\n", addr - PPC_IO_BASE, value); - } - cpu_outb(NULL, addr - PPC_IO_BASE, value); -} - -static uint32_t PPC_io_readb (uint32_t addr) -{ - uint32_t ret = cpu_inb(NULL, addr - PPC_IO_BASE); - - if ((addr < 0x800003F0 || addr > 0x80000400) && - (addr < 0x80000074 || addr > 0x80000077) && - (addr < 0x80000020 || addr > 0x80000021) && - (addr < 0x800000a0 || addr > 0x800000a1) && - (addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177) && - (addr < 0x8000060 || addr > 0x8000064)) { -// PPC_IO_DPRINTF("0x%08x <= 0x%02x\n", addr - PPC_IO_BASE, ret); - } - - return ret; -} - -static void PPC_io_writew (uint32_t addr, uint32_t value) -{ - if ((addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177)) { - PPC_IO_DPRINTF("0x%08x => 0x%04x\n", addr - PPC_IO_BASE, value); - } - cpu_outw(NULL, addr - PPC_IO_BASE, value); -} - -static uint32_t PPC_io_readw (uint32_t addr) -{ - uint32_t ret = cpu_inw(NULL, addr - PPC_IO_BASE); - - if ((addr < 0x800001f0 || addr > 0x800001f7) && - (addr < 0x80000170 || addr > 0x80000177)) { - PPC_IO_DPRINTF("0x%08x <= 0x%04x\n", addr - PPC_IO_BASE, ret); - } - - return ret; -} - -static void PPC_io_writel (uint32_t addr, uint32_t value) -{ - PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr - PPC_IO_BASE, value); - cpu_outl(NULL, addr - PPC_IO_BASE, value); -} - -static uint32_t PPC_io_readl (uint32_t addr) -{ - uint32_t ret = cpu_inl(NULL, addr - PPC_IO_BASE); - - PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr - PPC_IO_BASE, ret); - - return ret; -} - -static CPUWriteMemoryFunc *PPC_io_write[] = { - &PPC_io_writeb, - &PPC_io_writew, - &PPC_io_writel, -}; - -static CPUReadMemoryFunc *PPC_io_read[] = { - &PPC_io_readb, - &PPC_io_readw, - &PPC_io_readl, -}; - -uint32_t pic_intack_read(CPUState *env); - -/* Read-only register (?) */ -static void _PPC_ioB_write (uint32_t addr, uint32_t value) -{ - PPC_IO_DPRINTF("0x%08x => 0x%08x\n", addr, value); -} - -static uint32_t _PPC_ioB_read (uint32_t addr) -{ - uint32_t retval = 0; - - if (addr == 0xBFFFFFF0) - retval = pic_intack_read(NULL); - PPC_IO_DPRINTF("0x%08x <= 0x%08x\n", addr, retval); - - return retval; -} - -static CPUWriteMemoryFunc *PPC_ioB_write[] = { - &_PPC_ioB_write, - &_PPC_ioB_write, - &_PPC_ioB_write, -}; - -static CPUReadMemoryFunc *PPC_ioB_read[] = { - &_PPC_ioB_read, - &_PPC_ioB_read, - &_PPC_ioB_read, -}; - -#if 0 -static CPUWriteMemoryFunc *PPC_io3_write[] = { - &PPC_io3_writeb, - &PPC_io3_writew, - &PPC_io3_writel, -}; - -static CPUReadMemoryFunc *PPC_io3_read[] = { - &PPC_io3_readb, - &PPC_io3_readw, - &PPC_io3_readl, -}; -#endif - -/* Fake super-io ports for PREP platform (Intel 82378ZB) */ -static uint8_t PREP_fake_io[2]; -static uint8_t NVRAM_lock; - -static void PREP_io_write (CPUState *env, uint32_t addr, uint32_t val) -{ - PREP_fake_io[addr - 0x0398] = val; -} - -static uint32_t PREP_io_read (CPUState *env, uint32_t addr) -{ - return PREP_fake_io[addr - 0x0398]; -} - -static uint8_t syscontrol; - -static void PREP_io_800_writeb (CPUState *env, uint32_t addr, uint32_t val) -{ - switch (addr) { - case 0x0092: - /* Special port 92 */ - /* Check soft reset asked */ - if (val & 0x80) { - printf("Soft reset asked... Stop emulation\n"); - abort(); - } - /* Check LE mode */ - if (val & 0x40) { - printf("Little Endian mode isn't supported (yet ?)\n"); - abort(); - } - break; - case 0x0808: - /* Hardfile light register: don't care */ - break; - case 0x0810: - /* Password protect 1 register */ - NVRAM_lock ^= 0x01; - break; - case 0x0812: - /* Password protect 2 register */ - NVRAM_lock ^= 0x02; - break; - case 0x0814: - /* L2 invalidate register: don't care */ - break; - case 0x081C: - /* system control register */ - syscontrol = val; - break; - case 0x0850: - /* I/O map type register */ - if (val & 0x80) { - printf("No support for non-continuous I/O map mode\n"); - abort(); - } - break; - default: - break; - } -} - -static uint32_t PREP_io_800_readb (CPUState *env, uint32_t addr) -{ - uint32_t retval = 0xFF; - - switch (addr) { - case 0x0092: - /* Special port 92 */ - retval = 0x40; - break; - case 0x080C: - /* Equipment present register: - * no L2 cache - * no upgrade processor - * no cards in PCI slots - * SCSI fuse is bad - */ - retval = 0xFC; - break; - case 0x0818: - /* Keylock */ - retval = 0x00; - break; - case 0x081C: - /* system control register - * 7 - 6 / 1 - 0: L2 cache enable - */ - retval = syscontrol; - break; - case 0x0823: - /* */ - retval = 0x03; /* no L2 cache */ - break; - case 0x0850: - /* I/O map type register */ - retval = 0x00; - break; - default: - break; - } - - return retval; -} - -/* M48T59 NVRAM/RTC emulation */ -static uint8_t NVRAM[NVRAM_SIZE]; - -/* RTC */ -static time_t time_offset; - -time_t get_time (void) -{ - return time(NULL) + time_offset; -} - -void set_time_offset (time_t new_time) -{ - time_t now = time(NULL); - - time_offset = new_time - now; -} - -static void NVRAM_init (void) -{ - /* NVRAM header */ - /* 0x00: NVRAM size in kB */ - NVRAM[0x00] = (NVRAM_SIZE >> 12) & 0xFF; - NVRAM[0x01] = (NVRAM_SIZE >> 10) & 0xFF; - /* 0x02: NVRAM version */ - NVRAM[0x02] = 0x01; - /* 0x03: NVRAM revision */ - NVRAM[0x03] = 0x00; - /* 0x04: checksum 0 => OS area */ - /* 0x06: checksum of config area */ - /* 0x08: last OS */ - NVRAM[0x08] = 0x00; /* Unknown */ - /* 0x09: endian */ - NVRAM[0x09] = 'B'; - /* 0x0B: PM mode */ - NVRAM[0x0B] = 0x00; - /* Restart block description record */ - /* 0x0C: restart block version */ - NVRAM[0x0C] = 0x00; - NVRAM[0x0D] = 0x01; - /* 0x0E: restart block revision */ - NVRAM[0x0E] = 0x00; - NVRAM[0x0F] = 0x00; - /* 0x1C: checksum of restart block */ - /* 0x20: restart address */ - NVRAM[0x20] = 0x00; - NVRAM[0x21] = 0x00; - NVRAM[0x22] = 0x00; - NVRAM[0x23] = 0x00; - /* 0x24: save area address */ - NVRAM[0x24] = 0x00; - NVRAM[0x25] = 0x00; - NVRAM[0x26] = 0x00; - NVRAM[0x27] = 0x00; - /* 0x28: save area length */ - NVRAM[0x28] = 0x00; - NVRAM[0x29] = 0x00; - NVRAM[0x2A] = 0x00; - NVRAM[0x2B] = 0x00; - /* Security section */ - /* Set all to zero */ - /* 0xC4: pointer to global environment area */ - NVRAM[0xC4] = 0x00; - NVRAM[0xC5] = 0x00; - NVRAM[0xC6] = 0x01; - NVRAM[0xC7] = 0x00; - /* 0xC8: size of global environment area */ - NVRAM[0xC8] = 0x00; - NVRAM[0xC9] = 0x00; - NVRAM[0xCA] = 0x07; - NVRAM[0xCB] = 0x00; - /* 0xD4: pointer to configuration area */ - NVRAM[0xD4] = 0x00; - NVRAM[0xD5] = 0x00; - NVRAM[0xD6] = 0x08; - NVRAM[0xD7] = 0x00; - /* 0xD8: size of configuration area */ - NVRAM[0xD8] = 0x00; - NVRAM[0xD9] = 0x00; - NVRAM[0xDA] = 0x08; - NVRAM[0xDB] = 0x00; - /* 0xE8: pointer to OS specific area */ - NVRAM[0xE8] = 0x00; - NVRAM[0xE9] = 0x00; - NVRAM[0xEA] = 0x10; - NVRAM[0xEB] = 0x00; - /* 0xD8: size of OS specific area */ - NVRAM[0xEC] = 0x00; - NVRAM[0xED] = 0x00; - NVRAM[0xEE] = 0x0F; - NVRAM[0xEF] = 0xF0; - /* CRC */ - /* RTC init */ - NVRAM[0x1FFC] = 0x50; -} - -static uint16_t NVRAM_addr; - -/* Direct access to NVRAM */ -void NVRAM_write (CPUState *env, uint32_t addr, uint32_t val) -{ - switch (addr) { - case 0x1FF0: - /* flags register */ - break; - case 0x1FF1: - /* unused */ - break; - case 0x1FF2: - /* alarm seconds */ - break; - case 0x1FF3: - /* alarm minutes */ - break; - case 0x1FF4: - /* alarm hours */ - break; - case 0x1FF5: - /* alarm date */ - break; - case 0x1FF6: - /* interrupts */ - break; - case 0x1FF7: - /* watchdog */ - break; - case 0x1FF8: - /* control */ - break; - case 0x1FF9: - /* seconds (BCD) */ - break; - case 0x1FFA: - /* minutes (BCD) */ - break; - case 0x1FFB: - /* hours (BCD) */ - break; - case 0x1FFC: - /* day of the week / century */ - NVRAM[0x1FFC] = val & 0x50; - break; - case 0x1FFD: - /* date */ - break; - case 0x1FFE: - /* month */ - break; - case 0x1FFF: - /* year */ - break; - default: - if (addr < NVRAM_SIZE) - NVRAM[addr] = val & 0xFF; - break; - } -} - -uint32_t NVRAM_read (CPUState *env, uint32_t addr) -{ - struct tm tm; - time_t t; - uint32_t retval = 0xFF; - - switch (addr) { - case 0x1FF0: - /* flags register */ - break; - case 0x1FF1: - /* unused */ - break; - case 0x1FF2: - /* alarm seconds */ - break; - case 0x1FF3: - /* alarm minutes */ - break; - case 0x1FF4: - /* alarm hours */ - break; - case 0x1FF5: - /* alarm date */ - break; - case 0x1FF6: - /* interrupts */ - break; - case 0x1FF7: - /* watchdog */ - break; - case 0x1FF8: - /* control */ - break; - case 0x1FF9: - /* seconds (BCD) */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_sec / 10) << 4) | (tm.tm_sec % 10); -// printf("return seconds=%d\n", tm.tm_sec); - break; - case 0x1FFA: - /* minutes (BCD) */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_min / 10) << 4) | (tm.tm_min % 10); - break; - case 0x1FFB: - /* hours (BCD) */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_hour / 10) << 4) | (tm.tm_hour % 10); - break; - case 0x1FFC: - /* day of the week / century */ - t = get_time(); - localtime_r(&t, &tm); - retval = (NVRAM[0x1FFC] & 0x50) | tm.tm_wday; - break; - case 0x1FFD: - /* date */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_mday / 10) << 4) | (tm.tm_mday % 10); - break; - case 0x1FFE: - /* month */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_mon / 10) << 4) | (tm.tm_mon % 10); - break; - case 0x1FFF: - /* year */ - t = get_time(); - localtime_r(&t, &tm); - retval = ((tm.tm_year / 10) << 4) | (tm.tm_year % 10); - break; - default: - if (NVRAM_addr < NVRAM_SIZE) - retval = NVRAM[NVRAM_addr]; - break; - } - - return retval; -} - -/* IO access to NVRAM */ -static void NVRAM_writeb (CPUState *env, uint32_t addr, uint32_t val) -{ - switch (addr) { - case 0x74: - NVRAM_addr &= ~0x00FF; - NVRAM_addr |= val; - break; - case 0x75: - NVRAM_addr &= ~0xFF00; - NVRAM_addr |= val << 8; - break; - case 0x77: - NVRAM_write(env, NVRAM_addr, val); - NVRAM_addr = 0x0000; - break; - default: - break; - } -} - -static uint32_t NVRAM_readb (CPUState *env, uint32_t addr) -{ - if (addr == 0x77) - return NVRAM_read(env, NVRAM_addr); - - return 0xFF; -} - -int load_initrd (const char *filename, uint8_t *addr) -{ - int fd, size; - - printf("Load initrd\n"); - fd = open(filename, O_RDONLY); - if (fd < 0) - return -1; - size = read(fd, addr, 16 * 1024 * 1024); - if (size < 0) - goto fail; - close(fd); - printf("Load initrd: %d\n", size); - return size; - fail: - close(fd); - printf("Load initrd failed\n"); - return -1; -} - -/* Quick hack for PPC memory infos... */ -static void put_long (void *addr, uint32_t l) -{ - char *pos = addr; - pos[0] = (l >> 24) & 0xFF; - pos[1] = (l >> 16) & 0xFF; - pos[2] = (l >> 8) & 0xFF; - pos[3] = l & 0xFF; -} - -/* bootloader infos are in the form: - * uint32_t TAG - * uint32_t TAG_size (from TAG to next TAG). - * datas - * .... - */ -#if !defined (USE_OPEN_FIRMWARE) -static void *set_bootinfo_tag (void *addr, uint32_t tag, uint32_t size, - void *data) -{ - char *pos = addr; - - put_long(pos, tag); - pos += 4; - put_long(pos, size + 8); - pos += 4; - memcpy(pos, data, size); - pos += size; - - return pos; -} -#endif - -typedef struct boot_dev_t { - const unsigned char *name; - int major; - int minor; -} boot_dev_t; - -static boot_dev_t boot_devs[] = -{ - { "/dev/fd0", 2, 0, }, - { "/dev/fd1", 2, 1, }, - { "/dev/hda1", 3, 1, }, -// { "/dev/ide/host0/bus0/target0/lun0/part1", 3, 1, }, - { "/dev/hdc", 22, 0, }, - { "/dev/ram0 init=/linuxrc", 1, 0, }, -}; - -/* BATU: - * BEPI : bloc virtual address - * BL : area size bits (128 kB is 0, 256 1, 512 3, ... - * Vs/Vp - * BATL: - * BPRN : bloc real address align on 4MB boundary - * WIMG : cache access mode : not used - * PP : protection bits - */ -static void setup_BAT (CPUPPCState *env, int BAT, - uint32_t virtual, uint32_t physical, - uint32_t size, int Vs, int Vp, int PP) -{ - uint32_t sz_bits, tmp_sz, align, tmp; - - sz_bits = 0; - align = 131072; - for (tmp_sz = size / 131072; tmp_sz != 1; tmp_sz = tmp_sz >> 1) { - sz_bits = (sz_bits << 1) + 1; - align = align << 1; - } - tmp = virtual & ~(align - 1); /* Align virtual area start */ - tmp |= sz_bits << 2; /* Fix BAT size */ - tmp |= Vs << 1; /* Supervisor access */ - tmp |= Vp; /* User access */ - env->DBAT[0][BAT] = tmp; - env->IBAT[0][BAT] = tmp; - tmp = physical & ~(align - 1); /* Align physical area start */ - tmp |= 0; /* Don't care about WIMG */ - tmp |= PP; /* Protection */ - env->DBAT[1][BAT] = tmp; - env->IBAT[1][BAT] = tmp; - printf("Set BATU0 to 0x%08x BATL0 to 0x%08x\n", - env->DBAT[0][BAT], env->DBAT[1][BAT]); -} - -static void VGA_printf (uint8_t *s) -{ - uint16_t *arg_ptr; - unsigned int format_width, i; - int in_format; - uint16_t arg, digit, nibble; - uint8_t c; - - arg_ptr = (uint16_t *)(&s); - in_format = 0; - format_width = 0; - while ((c = *s) != '\0') { - if (c == '%') { - in_format = 1; - format_width = 0; - } else if (in_format) { - if ((c >= '0') && (c <= '9')) { - format_width = (format_width * 10) + (c - '0'); - } else if (c == 'x') { - arg_ptr++; // increment to next arg - arg = *arg_ptr; - if (format_width == 0) - format_width = 4; - digit = format_width - 1; - for (i = 0; i < format_width; i++) { - nibble = (arg >> (4 * digit)) & 0x000f; - if (nibble <= 9) - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + '0'); - else - PPC_io_writeb(PPC_IO_BASE + 0x500, nibble + 'A'); - digit--; - } - in_format = 0; - } - //else if (c == 'd') { - // in_format = 0; - // } - } else { - PPC_io_writeb(PPC_IO_BASE + 0x500, c); - } - s++; - } -} - -static void VGA_init (void) -{ - /* Basic VGA init, inspired by plex86 VGAbios */ - printf("Init VGA...\n"); - /* switch to color mode and enable CPU access 480 lines */ - PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3); - /* more than 64k 3C4/04 */ - PPC_io_writeb(PPC_IO_BASE + 0x3C4, 0x04); - PPC_io_writeb(PPC_IO_BASE + 0x3C5, 0x02); - VGA_printf("PPC VGA BIOS...\n"); -} - -void PPC_init_hw (CPUPPCState *env, uint32_t mem_size, - uint32_t kernel_addr, uint32_t kernel_size, - uint32_t stack_addr, int boot_device) -{ - char *p; -#if !defined (USE_OPEN_FIRMWARE) - char *tmp; - uint32_t tmpi[2]; -#endif - int PPC_io_memory; - -#if defined (USE_OPEN_FIRMWARE) - setup_memory(env, mem_size); -#endif - /* Register 64 kB of IO space */ - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write); - cpu_register_physical_memory(0x80000000, 0x10000, PPC_io_memory); - /* Register fake IO ports for PREP */ - register_ioport_read(0x398, 2, PREP_io_read, 1); - register_ioport_write(0x398, 2, PREP_io_write, 1); - /* System control ports */ - register_ioport_write(0x0092, 0x1, PREP_io_800_writeb, 1); - register_ioport_read(0x0800, 0x52, PREP_io_800_readb, 1); - register_ioport_write(0x0800, 0x52, PREP_io_800_writeb, 1); - /* PCI intack location */ - PPC_io_memory = cpu_register_io_memory(0, PPC_ioB_read, PPC_ioB_write); - cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); - /* NVRAM ports */ - NVRAM_init(); - register_ioport_read(0x0074, 0x04, NVRAM_readb, 1); - register_ioport_write(0x0074, 0x04, NVRAM_writeb, 1); - - /* Fake bootloader */ - env->nip = kernel_addr + (3 * sizeof(uint32_t)); - /* Set up msr according to PREP specification */ - msr_ee = 0; - msr_fp = 1; - msr_pr = 0; /* Start in supervisor mode */ - msr_me = 1; - msr_fe0 = msr_fe1 = 0; - msr_ip = 0; - msr_ir = msr_dr = 1; -// msr_sf = 0; - msr_le = msr_ile = 0; - env->gpr[1] = stack_addr; /* Let's have a stack */ - env->gpr[2] = 0; - env->gpr[8] = kernel_addr; - /* There is a bug in 2.4 kernels: - * if a decrementer exception is pending when it enables msr_ee, - * it's not ready to handle it... - */ - env->decr = 0xFFFFFFFF; - p = (void *)(phys_ram_base + kernel_addr); -#if !defined (USE_OPEN_FIRMWARE) - /* Let's register the whole memory available only in supervisor mode */ - setup_BAT(env, 0, 0x00000000, 0x00000000, mem_size, 1, 0, 2); - /* Avoid open firmware init call (to get a console) - * This will make the kernel think we are a PREP machine... - */ - put_long(p, 0xdeadc0de); - /* Build a real stack room */ - p = (void *)(phys_ram_base + stack_addr); - put_long(p, stack_addr); - p -= 32; - env->gpr[1] -= 32; - /* Pretend there are no residual data */ - env->gpr[3] = 0; -#if 1 - { - int size; - env->gpr[4] = 0x00800000; - size = load_initrd("initrd", - (void *)((uint32_t)phys_ram_base + env->gpr[4])); - if (size < 0) { - /* No initrd */ - env->gpr[4] = env->gpr[5] = 0; - } else { - env->gpr[5] = size; - boot_device = 'e'; - } - printf("Initrd loaded at 0x%08x (%d)\n", env->gpr[4], env->gpr[5]); - } -#else - env->gpr[4] = env->gpr[5] = 0; -#endif - /* We have to put bootinfos after the BSS - * The BSS starts after the kernel end. - */ -#if 0 - p = (void *)(((uint32_t)phys_ram_base + kernel_addr + - kernel_size + (1 << 20) - 1) & ~((1 << 20) - 1)); -#else - p = (void *)((uint32_t)phys_ram_base + kernel_addr + 0x400000); -#endif - if (loglevel > 0) { - fprintf(logfile, "bootinfos: %p 0x%08x\n", - p, (uint32_t)p - (uint32_t)phys_ram_base); - } else { - printf("bootinfos: %p 0x%08x\n", - p, (uint32_t)p - (uint32_t)phys_ram_base); - } - /* Command line: let's put it after bootinfos */ -#if 0 - sprintf(p + 0x1000, "console=ttyS0,9600 root=%02x%02x mem=%dM", - boot_devs[boot_device - 'a'].major, - boot_devs[boot_device - 'a'].minor, - phys_ram_size >> 20); -#else - sprintf(p + 0x1000, "console=ttyS0,9600 console=tty0 root=%s mem=%dM load_ramdisk=1", - boot_devs[boot_device - 'a'].name, - phys_ram_size >> 20); -#endif - env->gpr[6] = (uint32_t)p + 0x1000 - (uint32_t)phys_ram_base; - env->gpr[7] = env->gpr[6] + strlen(p + 0x1000); - if (loglevel > 0) { - fprintf(logfile, "cmdline: %p 0x%08x [%s]\n", - p + 0x1000, env->gpr[6], p + 0x1000); - } else { - printf("cmdline: %p 0x%08x [%s]\n", - p + 0x1000, env->gpr[6], p + 0x1000); - } - /* BI_FIRST */ - p = set_bootinfo_tag(p, 0x1010, 0, 0); - /* BI_CMD_LINE */ - p = set_bootinfo_tag(p, 0x1012, env->gpr[7] - env->gpr[6], - (void *)(env->gpr[6] + (uint32_t)phys_ram_base)); - /* BI_MEM_SIZE */ - tmp = (void *)tmpi; - tmp[0] = (phys_ram_size >> 24) & 0xFF; - tmp[1] = (phys_ram_size >> 16) & 0xFF; - tmp[2] = (phys_ram_size >> 8) & 0xFF; - tmp[3] = phys_ram_size & 0xFF; - p = set_bootinfo_tag(p, 0x1017, 4, tmpi); - /* BI_INITRD */ - tmp[0] = (env->gpr[4] >> 24) & 0xFF; - tmp[1] = (env->gpr[4] >> 16) & 0xFF; - tmp[2] = (env->gpr[4] >> 8) & 0xFF; - tmp[3] = env->gpr[4] & 0xFF; - tmp[4] = (env->gpr[5] >> 24) & 0xFF; - tmp[5] = (env->gpr[5] >> 16) & 0xFF; - tmp[6] = (env->gpr[5] >> 8) & 0xFF; - tmp[7] = env->gpr[5] & 0xFF; - p = set_bootinfo_tag(p, 0x1014, 8, tmpi); - /* BI_LAST */ - p = set_bootinfo_tag(p, 0x1011, 0, 0); -#else - /* Set up MMU: - * kernel is loaded at kernel_addr and wants to be seen at 0x01000000 - */ - setup_BAT(env, 0, 0x01000000, kernel_addr, 0x00400000, 1, 0, 2); - { -#if 0 - uint32_t offset = - *((uint32_t *)((uint32_t)phys_ram_base + kernel_addr)); -#else - uint32_t offset = 12; -#endif - env->nip = 0x01000000 | (kernel_addr + offset); - printf("Start address: 0x%08x\n", env->nip); - } - env->gpr[1] = env->nip + (1 << 22); - p = (void *)(phys_ram_base + stack_addr); - put_long(p - 32, stack_addr); - env->gpr[1] -= 32; - printf("Kernel starts at 0x%08x stack 0x%08x\n", env->nip, env->gpr[1]); - /* We want all lower address not to be translated */ - setup_BAT(env, 1, 0x00000000, 0x00000000, 0x010000000, 1, 1, 2); - /* We also need a BAT to access OF */ - setup_BAT(env, 2, 0xFFFE0000, mem_size - 131072, 131072, 1, 0, 1); - /* Setup OF entry point */ - { - char *p; - p = (char *)phys_ram_base + mem_size - 131072; - /* Special opcode to call OF */ - *p++ = 0x18; *p++ = 0x00; *p++ = 0x00; *p++ = 0x02; - /* blr */ - *p++ = 0x4E; *p++ = 0x80; *p++ = 0x00; *p++ = 0x20; - } - env->gpr[5] = 0xFFFE0000; - /* Register translations */ - { - OF_transl_t translations[3] = { - { 0x01000000, 0x00400000, kernel_addr, 0x00000002, }, - { 0x00000000, 0x01000000, 0x00000000, 0x00000002, }, - { 0xFFFE0000, 0x00020000, mem_size - (128 * 1024), - 0x00000001, }, - }; - OF_register_translations(3, translations); - } - /* Quite artificial, for now */ - OF_register_bus("isa", "isa"); - OF_register_serial("isa", "serial", 4, 0x3f8); - OF_register_stdio("serial", "serial"); - /* Set up RTAS service */ - RTAS_init(); - /* Command line: let's put it just over the stack */ -#if 1 - sprintf(p, "console=ttyS0,9600 root=%02x%02x mem=%dM", - boot_devs[boot_device - 'a'].major, - boot_devs[boot_device - 'a'].minor, - phys_ram_size >> 20); -#else - sprintf(p, "console=ttyS0,9600 root=%s mem=%dM ne2000=0x300,9", - boot_devs[boot_device - 'a'].name, - phys_ram_size >> 20); -#endif - OF_register_bootargs(p); -#endif -} - -void PPC_end_init (void) -{ - VGA_init(); -} diff --git a/target-ppc/op.c b/target-ppc/op.c index e47e245..12c9289 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -18,11 +18,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +//#define DEBUG_OP + #include "config.h" #include "exec.h" -//#define DEBUG_OP - #define regs (env) #define Ts0 (int32_t)T0 #define Ts1 (int32_t)T1 @@ -226,6 +226,17 @@ PPC_OP(process_exceptions) } } +PPC_OP(debug) +{ + env->nip = PARAM(1); + env->brkstate = 1; +#if defined (DEBUG_OP) + dump_state(); +#endif + do_queue_exception(EXCP_DEBUG); + RETURN(); +} + /* Segment registers load and store with immediate index */ PPC_OP(load_srin) { @@ -1443,10 +1454,9 @@ PPC_OP(fneg) } /* Load and store */ -#if defined(CONFIG_USER_ONLY) #define MEMSUFFIX _raw #include "op_mem.h" -#else +#if !defined(CONFIG_USER_ONLY) #define MEMSUFFIX _user #include "op_mem.h" @@ -1460,8 +1470,11 @@ PPC_OP(rfi) T0 = regs->spr[SRR1] & ~0xFFFF0000; do_store_msr(); do_tlbia(); +#if defined (DEBUG_OP) dump_rfi(); +#endif regs->nip = regs->spr[SRR0] & ~0x00000003; + do_queue_exception(EXCP_RFI); if (env->exceptions != 0) { do_check_exception_state(); } diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 5bd138d..0bb48e7 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -20,10 +20,9 @@ #include #include "exec.h" -#if defined(CONFIG_USER_ONLY) #define MEMSUFFIX _raw #include "op_helper_mem.h" -#else +#if !defined(CONFIG_USER_ONLY) #define MEMSUFFIX _user #include "op_helper_mem.h" #define MEMSUFFIX _kernel @@ -122,8 +121,7 @@ void do_load_msr (void) void do_store_msr (void) { if (((T0 >> MSR_IR) & 0x01) != msr_ir || - ((T0 >> MSR_DR) & 0x01) != msr_dr || - ((T0 >> MSR_PR) & 0x01) != msr_pr) { + ((T0 >> MSR_DR) & 0x01) != msr_dr) { /* Flush all tlb when changing translation mode or privilege level */ do_tlbia(); } @@ -371,44 +369,18 @@ void do_tlbie (void) /*****************************************************************************/ /* Special helpers for debug */ +extern FILE *stdout; + +void dump_state (void) +{ + cpu_ppc_dump_state(env, stdout, 0); +} + void dump_rfi (void) { #if 0 - printf("Return from interrupt\n"); - printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x\n", - env->nip, env->lr, env->ctr, - (msr_pow << MSR_POW) | (msr_ile << MSR_ILE) | (msr_ee << MSR_EE) | - (msr_pr << MSR_PR) | (msr_fp << MSR_FP) | (msr_me << MSR_ME) | - (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) | (msr_be << MSR_BE) | - (msr_fe1 << MSR_FE1) | (msr_ip << MSR_IP) | (msr_ir << MSR_IR) | - (msr_dr << MSR_DR) | (msr_ri << MSR_RI) | (msr_le << MSR_LE)); - { - int i; - for (i = 0; i < 32; i++) { - if ((i & 7) == 0) - printf("GPR%02d:", i); - printf(" %08x", env->gpr[i]); - if ((i & 7) == 7) - printf("\n"); - } - printf("CR: 0x"); - for (i = 0; i < 8; i++) - printf("%01x", env->crf[i]); - printf(" ["); - for (i = 0; i < 8; i++) { - char a = '-'; - if (env->crf[i] & 0x08) - a = 'L'; - else if (env->crf[i] & 0x04) - a = 'G'; - else if (env->crf[i] & 0x02) - a = 'E'; - printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); - } - printf(" ] "); - } - printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); - printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]); + printf("Return from interrupt %d => 0x%08x\n", pos, env->nip); + // cpu_ppc_dump_state(env, stdout, 0); #endif } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 97a0d27..bd0dc67 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2168,22 +2168,48 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) /* dcbf */ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) { + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } + op_ldst(lbz); } /* dcbi (Supervisor only) */ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) { -#if !defined(CONFIG_USER_ONLY) - if (!ctx->supervisor) -#endif - { +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(); +#else + if (!ctx->supervisor) { RET_PRIVOPC(); } + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } + op_ldst(lbz); + op_ldst(stb); +#endif } /* dcdst */ GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE) { + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } + op_ldst(lbz); } /* dcbt */ @@ -2863,7 +2889,7 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) fprintf(f, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x " "MSR=0x%08x\n", env->nip, env->lr, env->ctr, - _load_xer(), _load_msr()); + _load_xer(env), _load_msr(env)); for (i = 0; i < 32; i++) { if ((i & 7) == 0) fprintf(f, "GPR%02d:", i); @@ -2894,8 +2920,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) if ((i & 3) == 3) fprintf(f, "\n"); } - fprintf(f, "SRR0 0x%08x SRR1 0x%08x\n", - env->spr[SRR0], env->spr[SRR1]); + fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x excp:0x%08x\n", + env->spr[SRR0], env->spr[SRR1], env->decr, env->exceptions); fprintf(f, "reservation 0x%08x\n", env->reserve); fflush(f); } @@ -2934,6 +2960,7 @@ CPUPPCState *cpu_ppc_init(void) #if defined(CONFIG_USER_ONLY) msr_pr = 1; #endif + env->access_type = ACCESS_INT; return env; } @@ -2977,6 +3004,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, /* Single step trace mode */ msr_se = 1; #endif + env->access_type = ACCESS_CODE; /* Set env in case of segfault during code fetch */ while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) { if (search_pc) { @@ -3073,9 +3101,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.exception = EXCP_TRACE; } } - /* if too long translation, stop generation too */ - if (gen_opc_ptr >= gen_opc_end || - ((uint32_t)ctx.nip - pc_start) >= (TARGET_PAGE_SIZE - 32)) { + /* if we reach a page boundary, stop generation */ + if (((uint32_t)ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { if (ctx.exception == EXCP_NONE) { gen_op_b((long)ctx.tb, (uint32_t)ctx.nip); ctx.exception = EXCP_BRANCH; @@ -3111,6 +3138,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } else { tb->size = (uint32_t)ctx.nip - pc_start; } + env->access_type = ACCESS_INT; #ifdef DEBUG_DISAS if (loglevel > 0) { fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); -- cgit v1.1