mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 16:46:16 +00:00
Optimize MMIO handling
This commit is contained in:
@@ -4,8 +4,8 @@
|
||||
|
||||
#include "memory_permission.hpp"
|
||||
|
||||
using mmio_read_callback = std::function<uint64_t(uint64_t addr, size_t size)>;
|
||||
using mmio_write_callback = std::function<void(uint64_t addr, size_t size, uint64_t data)>;
|
||||
using mmio_read_callback = std::function<void(uint64_t addr, void* data, size_t size)>;
|
||||
using mmio_write_callback = std::function<void(uint64_t addr, const void* data, size_t size)>;
|
||||
|
||||
class memory_manager;
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ extern "C"
|
||||
using violation_func = int32_t(void*, uint64_t address, uint8_t operation, int32_t unmapped);
|
||||
using data_accessor_func = void(void* user, const void* data, size_t length);
|
||||
|
||||
using icicle_mmio_read_func = void(void* user, uint64_t address, size_t length, void* data);
|
||||
using icicle_mmio_write_func = void(void* user, uint64_t address, size_t length, const void* data);
|
||||
using icicle_mmio_read_func = void(void* user, uint64_t address, void* data, size_t length);
|
||||
using icicle_mmio_write_func = void(void* user, uint64_t address, const void* data, size_t length);
|
||||
|
||||
icicle_emulator* icicle_create_emulator();
|
||||
int32_t icicle_protect_memory(icicle_emulator*, uint64_t address, uint64_t length, uint8_t permissions);
|
||||
@@ -185,31 +185,14 @@ namespace icicle
|
||||
auto* ptr = wrapper.get();
|
||||
this->storage_.push_back(std::move(wrapper));
|
||||
|
||||
auto* read_wrapper = +[](void* user, const uint64_t addr, const size_t length, void* data) {
|
||||
constexpr auto limit = sizeof(uint64_t);
|
||||
auto* read_wrapper = +[](void* user, const uint64_t addr, void* data, const size_t length) {
|
||||
const auto* w = static_cast<mmio_wrapper*>(user);
|
||||
|
||||
// TODO: Change interface to get rid of loop
|
||||
for (size_t offset = 0; offset < length; offset += limit)
|
||||
{
|
||||
const auto max_read = std::min(limit, length - offset);
|
||||
const auto value = w->read_cb(addr + offset - w->base, max_read);
|
||||
memcpy(static_cast<uint8_t*>(data) + offset, &value, max_read);
|
||||
}
|
||||
w->read_cb(addr - w->base, data, length);
|
||||
};
|
||||
|
||||
auto* write_wrapper = +[](void* user, const uint64_t addr, const size_t length, const void* data) {
|
||||
constexpr auto limit = sizeof(uint64_t);
|
||||
auto* write_wrapper = +[](void* user, const uint64_t addr, const void* data, const size_t length) {
|
||||
const auto* w = static_cast<mmio_wrapper*>(user);
|
||||
|
||||
// TODO: Change interface to get rid of loop
|
||||
for (size_t offset = 0; offset < length; offset += limit)
|
||||
{
|
||||
uint64_t value{};
|
||||
const auto max_read = std::min(limit, length - offset);
|
||||
memcpy(&value, static_cast<const uint8_t*>(data) + offset, max_read);
|
||||
w->write_cb(addr + offset - w->base, max_read, value);
|
||||
}
|
||||
w->write_cb(addr + w->base, data, length);
|
||||
};
|
||||
|
||||
icicle_map_mmio(this->emu_, address, size, read_wrapper, ptr, write_wrapper, ptr);
|
||||
|
||||
@@ -38,8 +38,8 @@ pub fn icicle_stop(ptr: *mut c_void) {
|
||||
type RawFunction = extern "C" fn(*mut c_void);
|
||||
type PtrFunction = extern "C" fn(*mut c_void, u64);
|
||||
type DataFunction = extern "C" fn(*mut c_void, *const c_void, usize);
|
||||
type MmioReadFunction = extern "C" fn(*mut c_void, u64, usize, *mut c_void);
|
||||
type MmioWriteFunction = extern "C" fn(*mut c_void, u64, usize, *const c_void);
|
||||
type MmioReadFunction = extern "C" fn(*mut c_void, u64, *mut c_void, usize);
|
||||
type MmioWriteFunction = extern "C" fn(*mut c_void, u64, *const c_void, usize);
|
||||
type ViolationFunction = extern "C" fn(*mut c_void, u64, u8, i32) -> i32;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -57,12 +57,12 @@ pub fn icicle_map_mmio(
|
||||
|
||||
let read_wrapper = Box::new(move |addr: u64, data: &mut [u8]| {
|
||||
let raw_pointer: *mut u8 = data.as_mut_ptr();
|
||||
read_cb(read_data, addr, data.len(), raw_pointer as *mut c_void);
|
||||
read_cb(read_data, addr, raw_pointer as *mut c_void, data.len());
|
||||
});
|
||||
|
||||
let write_wrapper = Box::new(move |addr: u64, data: &[u8]| {
|
||||
let raw_pointer: *const u8 = data.as_ptr();
|
||||
write_cb(write_data, addr, data.len(), raw_pointer as *const c_void);
|
||||
write_cb(write_data, addr, raw_pointer as *const c_void, data.len());
|
||||
});
|
||||
|
||||
let res = emulator.map_mmio(address, length, read_wrapper, write_wrapper);
|
||||
|
||||
@@ -243,6 +243,14 @@ namespace unicorn
|
||||
return block;
|
||||
}
|
||||
|
||||
void assert_64bit_limit(const size_t size)
|
||||
{
|
||||
if (size > sizeof(uint64_t))
|
||||
{
|
||||
throw std::runtime_error("Exceeded uint64_t size limit");
|
||||
}
|
||||
}
|
||||
|
||||
class unicorn_x64_emulator : public x64_emulator
|
||||
{
|
||||
public:
|
||||
@@ -370,13 +378,23 @@ namespace unicorn
|
||||
void map_mmio(const uint64_t address, const size_t size, mmio_read_callback read_cb,
|
||||
mmio_write_callback write_cb) override
|
||||
{
|
||||
mmio_callbacks cb{.read = mmio_callbacks::read_wrapper(
|
||||
[c = std::move(read_cb)](uc_engine*, const uint64_t addr, const uint32_t s) {
|
||||
return c(addr, s);
|
||||
}),
|
||||
.write = mmio_callbacks::write_wrapper(
|
||||
[c = std::move(write_cb)](uc_engine*, const uint64_t addr, const uint32_t s,
|
||||
const uint64_t value) { c(addr, s, value); })};
|
||||
auto read_wrapper = [c = std::move(read_cb)](uc_engine*, const uint64_t addr, const uint32_t s) {
|
||||
assert_64bit_limit(s);
|
||||
uint64_t value{};
|
||||
c(addr, &value, s);
|
||||
return value;
|
||||
};
|
||||
|
||||
auto write_wrapper = [c = std::move(write_cb)](uc_engine*, const uint64_t addr, const uint32_t s,
|
||||
const uint64_t value) {
|
||||
assert_64bit_limit(s);
|
||||
c(addr, &value, s);
|
||||
};
|
||||
|
||||
mmio_callbacks cb{
|
||||
.read = mmio_callbacks::read_wrapper(std::move(read_wrapper)),
|
||||
.write = mmio_callbacks::write_wrapper(std::move(write_wrapper)),
|
||||
};
|
||||
|
||||
uce(uc_mmio_map(*this, address, size, cb.read.get_c_function(), cb.read.get_user_data(),
|
||||
cb.write.get_c_function(), cb.write.get_user_data()));
|
||||
|
||||
@@ -83,13 +83,13 @@ namespace
|
||||
|
||||
namespace utils
|
||||
{
|
||||
inline void serialize(buffer_serializer& buffer, const KUSER_SHARED_DATA64& kusd)
|
||||
static void serialize(buffer_serializer& buffer, const KUSER_SHARED_DATA64& kusd)
|
||||
{
|
||||
static_assert(KUSD_SIZE == sizeof(kusd));
|
||||
buffer.write(&kusd, KUSD_SIZE);
|
||||
}
|
||||
|
||||
inline void deserialize(buffer_deserializer& buffer, KUSER_SHARED_DATA64& kusd)
|
||||
static void deserialize(buffer_deserializer& buffer, KUSER_SHARED_DATA64& kusd)
|
||||
{
|
||||
buffer.read(&kusd, KUSD_SIZE);
|
||||
}
|
||||
@@ -130,30 +130,21 @@ void kusd_mmio::deserialize(utils::buffer_deserializer& buffer)
|
||||
this->register_mmio();
|
||||
}
|
||||
|
||||
uint64_t kusd_mmio::read(const uint64_t addr, const size_t size)
|
||||
void kusd_mmio::read(const uint64_t addr, void* data, const size_t size)
|
||||
{
|
||||
uint64_t result{};
|
||||
|
||||
this->update();
|
||||
|
||||
if (addr >= KUSD_SIZE)
|
||||
{
|
||||
return result;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto end = addr + size;
|
||||
const auto valid_end = std::min(end, static_cast<uint64_t>(KUSD_SIZE));
|
||||
const auto real_size = valid_end - addr;
|
||||
|
||||
if (real_size > sizeof(result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto* kusd_buffer = reinterpret_cast<uint8_t*>(&this->kusd_);
|
||||
memcpy(&result, kusd_buffer + addr, real_size);
|
||||
|
||||
return result;
|
||||
memcpy(data, kusd_buffer + addr, real_size);
|
||||
}
|
||||
|
||||
uint64_t kusd_mmio::address()
|
||||
@@ -178,8 +169,10 @@ void kusd_mmio::register_mmio()
|
||||
|
||||
this->memory_->allocate_mmio(
|
||||
KUSD_ADDRESS, KUSD_BUFFER_SIZE,
|
||||
[this](const uint64_t addr, const size_t size) { return this->read(addr, size); },
|
||||
[](const uint64_t, const size_t, const uint64_t) {
|
||||
[this](const uint64_t addr, void* data, const size_t size) {
|
||||
this->read(addr, data, size); //
|
||||
},
|
||||
[](const uint64_t, const void*, const size_t) {
|
||||
// Writing not supported!
|
||||
});
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class kusd_mmio
|
||||
|
||||
KUSER_SHARED_DATA64 kusd_{};
|
||||
|
||||
uint64_t read(uint64_t addr, size_t size);
|
||||
void read(uint64_t addr, void* data, size_t size);
|
||||
|
||||
void update();
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ struct region_info : basic_memory_region
|
||||
bool is_committed{};
|
||||
};
|
||||
|
||||
using mmio_read_callback = std::function<uint64_t(uint64_t addr, size_t size)>;
|
||||
using mmio_write_callback = std::function<void(uint64_t addr, size_t size, uint64_t data)>;
|
||||
using mmio_read_callback = std::function<void(uint64_t addr, void* data, size_t size)>;
|
||||
using mmio_write_callback = std::function<void(uint64_t addr, const void* data, size_t size)>;
|
||||
|
||||
class memory_manager : public memory_interface
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user