ppcmmu: add debug memory reading function.

This function saves and restores the MMU state
so no invalid user input can break CPU execution.
This commit is contained in:
Maxim Poliakovski 2020-02-23 16:41:44 +01:00
parent 403c19ca39
commit 461d859e73
6 changed files with 135 additions and 8 deletions

View File

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

View File

@ -1,6 +1,8 @@
/** @file Handling of low-level PPC exceptions. */
#include <setjmp.h>
#include <string>
#include <stdexcept>
#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);
}

View File

@ -9,6 +9,7 @@
#include <string>
#include <iostream>
#include <stdexcept>
#include <algorithm>
#include <map>
#include <unordered_map>
#include <chrono>
@ -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;
}

View File

@ -18,12 +18,16 @@
#include <cstdint>
#include <cinttypes>
#include <string>
#include <stdexcept>
#include <array>
#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;
}

View File

@ -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

View File

@ -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;
}