diff --git a/CMakeLists.txt b/CMakeLists.txt index e479064..18b9e2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,8 @@ set(CAPSTONE_PPC_SUPPORT ON) add_subdirectory(external/capstone) add_executable(weee main.cpp core/mem.cpp core/loaders/elf.cpp - core/loaders/dol.cpp) + core/loaders/dol.cpp + core/broadway.cpp + core/broadway/instructions.cpp) target_link_libraries(weee PUBLIC capstone) target_include_directories(weee PUBLIC core) \ No newline at end of file diff --git a/core/broadway.cpp b/core/broadway.cpp new file mode 100644 index 0000000..09535f4 --- /dev/null +++ b/core/broadway.cpp @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include + +namespace weee::core { +broadway::broadway() { + if (cs_open(CS_ARCH_PPC, cs_mode(CS_MODE_BIG_ENDIAN | CS_MODE_32), &capstone) != CS_ERR_OK) { + std::println("warning: could not initialize capstone. Disassembly is disabled"); + disasm_available = false; + } +} + +void broadway::set_pc(ircolib::u32 value) { pc = value; } + +void broadway::run(mem &mem) { + for (int i = 0; i < 100000; i++) { + execute(fetch(mem), mem); + } +} + +ircolib::u32 broadway::fetch(mem &mem) { + ircolib::u32 val = mem.read(pc); + pc += 4; + + return val; +} + +void broadway::execute(ircolib::u32 instr, mem &mem) { + ircolib::u8 primary = (instr >> 26) & 0x3f; + switch (primary) { + case 15: // addis rd, ra, simm + addis(instr); + break; + default: + std::println("broadway::execute unimplemented instruction 0x{:08X} / 0b{:032b}", instr, instr); + std::println("disassembly:"); + print_disasm(instr); + ircolib::panic(""); + } +} + +void broadway::print_disasm(ircolib::u32 instr) { + if (!disasm_available) + return; + + cs_insn *insn; + auto instr_buff = ircolib::integral_to_slice(std::byteswap(instr)); + size_t count = cs_disasm(capstone, instr_buff.data(), instr_buff.size(), pc - 4, 1, &insn); + if (count <= 0) + return; + + size_t j; + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + } + + cs_free(insn, count); +} +} // namespace weee::core diff --git a/core/broadway.hpp b/core/broadway.hpp index dcdc05a..8d663d0 100644 --- a/core/broadway.hpp +++ b/core/broadway.hpp @@ -1,7 +1,26 @@ #pragma once +#include +#include +#include namespace weee::core { +struct mem; struct broadway { - + broadway(); + void set_pc(ircolib::u32); + void run(mem &); + + private: + ircolib::u32 fetch(mem &); + void print_disasm(ircolib::u32); + void execute(ircolib::u32, mem &); + + bool disasm_available = true; + ircolib::u32 pc = 0; + std::array gpr{}; + csh capstone; + + // instructions + void addis(ircolib::u32); }; } // namespace weee::core diff --git a/core/broadway/instructions.cpp b/core/broadway/instructions.cpp new file mode 100644 index 0000000..23a5f3c --- /dev/null +++ b/core/broadway/instructions.cpp @@ -0,0 +1,7 @@ +#include + +namespace weee::core { +void broadway::addis(ircolib::u32 instr) { + +} +} // namespace weee::core diff --git a/core/loaders/dol.cpp b/core/loaders/dol.cpp index 7bfc34d..bd533fc 100644 --- a/core/loaders/dol.cpp +++ b/core/loaders/dol.cpp @@ -1,12 +1,13 @@ #include #include +#include #include #include #include #include namespace weee::core { -bool load_dol(const std::string &path, mem &mem) { +bool load_dol(const std::string &path, mem &mem, broadway &broadway) { auto bin = ircolib::read_file_binary(path); if (bin.size() <= 0) return false; @@ -45,6 +46,7 @@ bool load_dol(const std::string &path, mem &mem) { mem.set(0, hdr.bss_size, hdr.bss_address & 0x0FFFFFFF); hdr.entry_point = std::byteswap(ircolib::read_access(bin, 0xE0)); + broadway.set_pc(hdr.entry_point); for (const auto §ion : hdr.text) { if (section.offset == 0) diff --git a/core/loaders/dol.hpp b/core/loaders/dol.hpp index 80048b0..edc89e2 100644 --- a/core/loaders/dol.hpp +++ b/core/loaders/dol.hpp @@ -4,6 +4,7 @@ namespace weee::core { struct mem; +struct broadway; -bool load_dol(const std::string &, mem &); +bool load_dol(const std::string &, mem &, broadway &); } // namespace weee::core diff --git a/core/loaders/elf.cpp b/core/loaders/elf.cpp index 3ed81c8..4436202 100644 --- a/core/loaders/elf.cpp +++ b/core/loaders/elf.cpp @@ -1,10 +1,11 @@ #include #include +#include #include #include namespace weee::core { -bool load_elf(const std::string &path, mem &mem) { +bool load_elf(const std::string &path, mem &mem, broadway &broadway) { ELFIO::elfio reader; if (!reader.load(path)) return false; @@ -39,10 +40,12 @@ bool load_elf(const std::string &path, mem &mem) { continue; } - mem.copy((const ircolib::u8 *)segment->get_data(), segment->get_file_size(), + mem.copy((ircolib::u8 *)segment->get_data(), segment->get_file_size(), segment->get_virtual_address() & 0x0FFFFFFF); } + broadway.set_pc(reader.get_entry()); + return true; } } // namespace weee::core diff --git a/core/loaders/elf.hpp b/core/loaders/elf.hpp index 7ebb71f..7c96e7b 100644 --- a/core/loaders/elf.hpp +++ b/core/loaders/elf.hpp @@ -4,6 +4,7 @@ namespace weee::core { struct mem; +struct broadway; -bool load_elf(const std::string &, mem &); +bool load_elf(const std::string &, mem &, broadway &); } // namespace weee::core diff --git a/core/mem.cpp b/core/mem.cpp index 0480236..2d67693 100644 --- a/core/mem.cpp +++ b/core/mem.cpp @@ -1,6 +1,7 @@ #include #include #include +#include "ircolib/mem_access.hpp" namespace weee::core { mem::mem() { @@ -8,18 +9,20 @@ mem::mem() { std::fill(mem1.begin(), mem1.end(), 0); } -void mem::copy(const std::vector &src, const ircolib::u32 offset) { +void mem::copy(std::vector &src, const ircolib::u32 offset) { if (offset + src.size() >= mem1.size()) ircolib::panic("mem::copy outside mem1 range (src @ 0x{:08} for size 0x{:08X})", offset, src.size()); + ircolib::swap_buffer(src); std::println("Copying {} bytes to mem1[{}]", src.size(), offset); std::copy(src.begin(), src.end(), mem1.begin() + offset); } -void mem::copy(const ircolib::u8 *src, const ircolib::u32 size, const ircolib::u32 offset) { +void mem::copy(ircolib::u8 *src, const ircolib::u32 size, const ircolib::u32 offset) { if (offset + size >= mem1.size()) ircolib::panic("mem::copy outside mem1 range (src @ 0x{:08} for size 0x{:08X})", offset, size); + ircolib::swap_buffer(src, size); std::println("Copying {} bytes to mem1[{}]", size, offset); memcpy(&mem1[offset], src, size); } @@ -31,4 +34,20 @@ void mem::set(const ircolib::u8 val, const ircolib::u32 size, const ircolib::u32 std::println("Setting {} bytes to {} from mem1[{}]", size, val, offset); memset(&mem1[offset], val, size); } + +ircolib::u32 mem::read(ircolib::u32 addr) { + addr &= 0x0FFFFFFF; + if (addr > 0x017FFFFF) + ircolib::panic("mem::read unimplemented outside mem1 (0x{:08X})", addr); + + return ircolib::read_access(mem1, addr); +} + +void mem::write(ircolib::u32 addr, ircolib::u32 value) { + addr &= 0x0FFFFFFF; + if (addr > 0x017FFFFF) + ircolib::panic("mem::write unimplemented outside mem1 (0x{:08X} = 0x{:08X})", addr, value); + + ircolib::write_access(mem1, addr, value); +} } // namespace weee::core diff --git a/core/mem.hpp b/core/mem.hpp index f1920e1..74c191e 100644 --- a/core/mem.hpp +++ b/core/mem.hpp @@ -6,8 +6,10 @@ namespace weee::core { struct mem { mem(); - void copy(const std::vector &src, const ircolib::u32 offset); - void copy(const ircolib::u8 *src, const ircolib::u32 size, const ircolib::u32 offset); + ircolib::u32 read(ircolib::u32); + void write(ircolib::u32, ircolib::u32); + void copy(std::vector &src, const ircolib::u32 offset); + void copy(ircolib::u8 *src, const ircolib::u32 size, const ircolib::u32 offset); void set(const ircolib::u8 val, const ircolib::u32 size, const ircolib::u32 offset); private: diff --git a/external/ircolib/mem_access.hpp b/external/ircolib/mem_access.hpp index 51f1c11..05d8d97 100644 --- a/external/ircolib/mem_access.hpp +++ b/external/ircolib/mem_access.hpp @@ -144,6 +144,14 @@ static constexpr inline void swap_buffer(std::array &data) { } } +template +static constexpr inline void swap_buffer(u8 *data, size_t size) { + for (size_t i = 0; i < size; i += sizeof(T)) { + const T original = *reinterpret_cast(&data[i]); + *reinterpret_cast(&data[i]) = std::byteswap(original); + } +} + #ifdef _WIN32 inline void *aligned_alloc(const size_t alignment, const size_t size) { return _aligned_malloc(size, alignment); } diff --git a/main.cpp b/main.cpp index c6e4e8f..8017522 100644 --- a/main.cpp +++ b/main.cpp @@ -4,15 +4,17 @@ #include #include #include +#include int main(int argc, char **argv) { weee::core::mem mem; + weee::core::broadway broadway; cflags::cflags flags; flags.add_string_callback( '\0', "elf", [&](const std::string &v) { - if (!weee::core::load_elf(v, mem)) + if (!weee::core::load_elf(v, mem, broadway)) ircolib::panic("Could not load '{}'", v); }, "ELF binary to load"); @@ -20,7 +22,7 @@ int main(int argc, char **argv) { flags.add_string_callback( '\0', "dol", [&](const std::string &v) { - if (!weee::core::load_dol(v, mem)) + if (!weee::core::load_dol(v, mem, broadway)) ircolib::panic("Could not load '{}'", v); }, "DOL binary to load"); @@ -28,5 +30,8 @@ int main(int argc, char **argv) { if (!flags.parse(argc, argv)) return -1; + while (true) + broadway.run(mem); + return 0; }