diff --git a/cpu/ppc/ppcemu.h b/cpu/ppc/ppcemu.h index 79245ac..3c1cd8b 100644 --- a/cpu/ppc/ppcemu.h +++ b/cpu/ppc/ppcemu.h @@ -232,6 +232,7 @@ extern uint32_t supervisor_inst_num; //Function prototypes extern void ppc_cpu_init(uint32_t proc_version); +extern void ppc_mmu_init(void); void ppc_illegalop(); void ppc_opcode4(); @@ -276,8 +277,12 @@ void ppc_changecrf0(uint32_t set_result); void ppc_fp_changecrf1(); void ppc_tbr_update(); + +/* Exception handlers. */ [[noreturn]] void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits); +[[noreturn]] void dbg_exception_handler(Except_Type exception_type, + uint32_t srr1_bits); //MEMORY DECLARATIONS extern MemCtrlBase* mem_ctrl_instance; diff --git a/cpu/ppc/ppcexceptions.cpp b/cpu/ppc/ppcexceptions.cpp index 05514cc..2b7870b 100644 --- a/cpu/ppc/ppcexceptions.cpp +++ b/cpu/ppc/ppcexceptions.cpp @@ -1,6 +1,8 @@ /** @file Handling of low-level PPC exceptions. */ #include +#include +#include #include "ppcemu.h" jmp_buf exc_env; /* Global exception environment. */ @@ -91,3 +93,64 @@ jmp_buf exc_env; /* Global exception environment. */ longjmp(exc_env, 2); /* return to the main execution loop. */ } + + +[[noreturn]] void dbg_exception_handler(Except_Type exception_type, + uint32_t srr1_bits) +{ + std::string exc_descriptor; + + switch(exception_type) { + case Except_Type::EXC_SYSTEM_RESET: + exc_descriptor = "System reset exception occured"; + break; + + case Except_Type::EXC_MACHINE_CHECK: + exc_descriptor = "Machine check exception occured"; + break; + + case Except_Type::EXC_DSI: + case Except_Type::EXC_ISI: + if (ppc_state.ppc_spr[SPR::DSISR] & 0x40000000) + exc_descriptor = "DSI/ISI exception: unmapped memory access"; + else if (ppc_state.ppc_spr[SPR::DSISR] & 0x08000000) + exc_descriptor = "DSI/ISI exception: access protection violation"; + else { + if (exception_type == Except_Type::EXC_DSI) + exc_descriptor = "DSI exception"; + else + exc_descriptor = "ISI exception"; + } + break; + + case Except_Type::EXC_EXT_INT: + exc_descriptor = "External interrupt exception occured"; + break; + + case Except_Type::EXC_ALIGNMENT: + exc_descriptor = "Alignment exception occured"; + break; + + case Except_Type::EXC_PROGRAM: + exc_descriptor = "Program exception occured"; + break; + + case Except_Type::EXC_NO_FPU: + exc_descriptor = "Floating-Point unavailable exception occured"; + break; + + case Except_Type::EXC_DECR: + exc_descriptor = "Decrementer exception occured"; + break; + + case Except_Type::EXC_SYSCALL: + exc_descriptor = "Syscall exception occured"; + break; + + case Except_Type::EXC_TRACE: + exc_descriptor = "Trace exception occured"; + break; + } + + throw std::invalid_argument(exc_descriptor); +} diff --git a/cpu/ppc/ppcexec.cpp b/cpu/ppc/ppcexec.cpp index f9b5d75..0264290 100644 --- a/cpu/ppc/ppcexec.cpp +++ b/cpu/ppc/ppcexec.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -792,6 +793,8 @@ void ppc_cpu_init(uint32_t proc_version) ppc_state.ppc_spr[SPR::DEC] = 0xFFFFFFFFUL; } + ppc_mmu_init(); + /* redirect code execution to reset vector */ ppc_state.ppc_pc = 0xFFF00100; } diff --git a/cpu/ppc/ppcmmu.cpp b/cpu/ppc/ppcmmu.cpp index 4190583..31e43c6 100644 --- a/cpu/ppc/ppcmmu.cpp +++ b/cpu/ppc/ppcmmu.cpp @@ -18,12 +18,16 @@ #include #include #include +#include #include #include "memreadwrite.h" #include "ppcemu.h" #include "ppcmmu.h" #include "devices/memctrlbase.h" +/* pointer to exception handler to be called when a MMU exception is occured. */ +void (*mmu_exception_handler)(Except_Type exception_type, uint32_t srr1_bits); + /** PowerPC-style MMU BAT arrays (NULL initialization isn't prescribed). */ PPC_BAT_entry ibat_array[4] = { {0} }; PPC_BAT_entry dbat_array[4] = { {0} }; @@ -222,7 +226,7 @@ static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch, /* instruction fetch from a no-execute segment will cause ISI exception */ if ((sr_val & 0x10000000) && is_instr_fetch) { - ppc_exception_handler(Except_Type::EXC_ISI, 0x10000000); + mmu_exception_handler(Except_Type::EXC_ISI, 0x10000000); } page_index = (la >> 12) & 0xFFFF; @@ -232,12 +236,12 @@ static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch, if (!search_pteg(calc_pteg_addr(pteg_hash1), &pte_addr, vsid, page_index, 0)) { if (!search_pteg(calc_pteg_addr(~pteg_hash1), &pte_addr, vsid, page_index, 1)) { if (is_instr_fetch) { - ppc_exception_handler(Except_Type::EXC_ISI, 0x40000000); + mmu_exception_handler(Except_Type::EXC_ISI, 0x40000000); } else { ppc_state.ppc_spr[SPR::DSISR] = 0x40000000 | (is_write << 25); ppc_state.ppc_spr[SPR::DAR] = la; - ppc_exception_handler(Except_Type::EXC_DSI, 0); + mmu_exception_handler(Except_Type::EXC_DSI, 0); } } } @@ -255,12 +259,12 @@ static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch, // write access with PP = %11 if ((key && (!pp || (pp == 1 && is_write))) || (pp == 3 && is_write)) { if (is_instr_fetch) { - ppc_exception_handler(Except_Type::EXC_ISI, 0x08000000); + mmu_exception_handler(Except_Type::EXC_ISI, 0x08000000); } else { ppc_state.ppc_spr[SPR::DSISR] = 0x08000000 | (is_write << 25); ppc_state.ppc_spr[SPR::DAR] = la; - ppc_exception_handler(Except_Type::EXC_DSI, 0); + mmu_exception_handler(Except_Type::EXC_DSI, 0); } } @@ -296,7 +300,7 @@ static uint32_t ppc_mmu_instr_translate(uint32_t la) bat_hit = true; if (!bat_entry->prot) { - ppc_exception_handler(Except_Type::EXC_ISI, 0x08000000); + mmu_exception_handler(Except_Type::EXC_ISI, 0x08000000); } // logical to physical translation @@ -340,7 +344,7 @@ static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write) if (!bat_entry->prot || ((bat_entry->prot & 1) && is_write)) { ppc_state.ppc_spr[SPR::DSISR] = 0x08000000 | (is_write << 25); ppc_state.ppc_spr[SPR::DAR] = la; - ppc_exception_handler(Except_Type::EXC_DSI, 0); + mmu_exception_handler(Except_Type::EXC_DSI, 0); } // logical to physical translation @@ -554,3 +558,54 @@ uint8_t* quickinstruction_translate(uint32_t addr) return real_addr; } + +uint64_t mem_read_dbg(uint32_t virt_addr, uint32_t size) +{ + uint32_t save_dsisr, save_dar; + uint64_t ret_val; + + /* save MMU-related CPU state */ + save_dsisr = ppc_state.ppc_spr[SPR::DSISR]; + save_dar = ppc_state.ppc_spr[SPR::DAR]; + mmu_exception_handler = dbg_exception_handler; + + try { + switch(size) { + case 1: + ret_val = mem_grab_byte(virt_addr); + break; + case 2: + ret_val = mem_grab_word(virt_addr); + break; + case 4: + ret_val = mem_grab_dword(virt_addr); + break; + case 8: + ret_val = mem_grab_qword(virt_addr); + break; + default: + ret_val = mem_grab_byte(virt_addr); + } + } + catch (std::invalid_argument& exc) { + /* restore MMU-related CPU state */ + mmu_exception_handler = ppc_exception_handler; + ppc_state.ppc_spr[SPR::DSISR] = save_dsisr; + ppc_state.ppc_spr[SPR::DAR] = save_dar; + + /* rethrow MMU exception */ + throw exc; + } + + /* restore MMU-related CPU state */ + mmu_exception_handler = ppc_exception_handler; + ppc_state.ppc_spr[SPR::DSISR] = save_dsisr; + ppc_state.ppc_spr[SPR::DAR] = save_dar; + + return ret_val; +} + +void ppc_mmu_init() +{ + mmu_exception_handler = ppc_exception_handler; +} diff --git a/cpu/ppc/ppcmmu.h b/cpu/ppc/ppcmmu.h index f6ac961..97fe266 100644 --- a/cpu/ppc/ppcmmu.h +++ b/cpu/ppc/ppcmmu.h @@ -39,6 +39,7 @@ extern uint8_t mem_grab_byte(uint32_t addr); extern uint16_t mem_grab_word(uint32_t addr); extern uint32_t mem_grab_dword(uint32_t addr); extern uint64_t mem_grab_qword(uint32_t addr); +extern uint64_t mem_read_dbg(uint32_t virt_addr, uint32_t size); extern uint8_t* quickinstruction_translate(uint32_t address_grab); #endif // PPCMEMORY_H diff --git a/debugger/debugger.cpp b/debugger/debugger.cpp index bd12a3a..b196069 100644 --- a/debugger/debugger.cpp +++ b/debugger/debugger.cpp @@ -58,7 +58,7 @@ static void disasm(uint32_t inst_num = 1UL, uint32_t address = ppc_state.ppc_pc) ctx.simplified = true; for (int i = 0; i < inst_num; i++) { - ctx.instr_code = mem_grab_dword(ctx.instr_addr); + ctx.instr_code = mem_read_dbg(ctx.instr_addr, 4); cout << uppercase << hex << ctx.instr_addr << " " << disassemble_single(&ctx) << endl; }