From c5795487dd5db0a108921b15bbfb57a9160199a4 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Fri, 15 Mar 2024 02:02:43 +0100 Subject: [PATCH] Extended mem_init_region_io API It's now possible to update the io handlers of an existing region after it's been created --- include/lib86cpu.h | 2 +- lib86cpu/core/internal.h | 3 +- lib86cpu/core/translate.cpp | 31 ++++++++-- lib86cpu/interface.cpp | 120 ++++++++++++++++++++++++------------ lib86cpu/lib86cpu_priv.h | 8 +++ 5 files changed, 118 insertions(+), 46 deletions(-) diff --git a/include/lib86cpu.h b/include/lib86cpu.h index ab60940..f4103c1 100644 --- a/include/lib86cpu.h +++ b/include/lib86cpu.h @@ -123,7 +123,7 @@ API_FUNC void write_fstatus(cpu_t *cpu, uint16_t value); API_FUNC uint8_t *get_ram_ptr(cpu_t *cpu); API_FUNC uint8_t* get_host_ptr(cpu_t *cpu, addr_t addr); API_FUNC lc86_status mem_init_region_ram(cpu_t *cpu, addr_t start, uint32_t size, bool should_int = false); -API_FUNC lc86_status mem_init_region_io(cpu_t *cpu, addr_t start, uint32_t size, bool io_space, io_handlers_t handlers, void *opaque, bool should_int = false); +API_FUNC lc86_status mem_init_region_io(cpu_t *cpu, addr_t start, uint32_t size, bool io_space, io_handlers_t handlers, void *opaque, bool should_int = false, int update = 0); API_FUNC lc86_status mem_init_region_alias(cpu_t *cpu, addr_t alias_start, addr_t ori_start, uint32_t ori_size, bool should_int = false); API_FUNC lc86_status mem_init_region_rom(cpu_t *cpu, addr_t start, uint32_t size, uint8_t *buffer, bool should_int = false); API_FUNC lc86_status mem_destroy_region(cpu_t *cpu, addr_t start, uint32_t size, bool io_space, bool should_int = false); diff --git a/lib86cpu/core/internal.h b/lib86cpu/core/internal.h index d382646..c9ec7f6 100644 --- a/lib86cpu/core/internal.h +++ b/lib86cpu/core/internal.h @@ -81,7 +81,8 @@ void JIT_API tlb_invalidate_(cpu_ctx_t *cpu_ctx, addr_t addr); #define CPU_REGION_INT (1 << 3) #define CPU_TIMEOUT_INT (1 << 4) // never set, only returned as a status #define CPU_SUSPEND_INT (1 << 5) -#define CPU_NON_HW_INT (CPU_ABORT_INT | CPU_A20_INT | CPU_REGION_INT | CPU_SUSPEND_INT) +#define CPU_HANDLER_INT (1 << 6) +#define CPU_NON_HW_INT (CPU_ABORT_INT | CPU_A20_INT | CPU_REGION_INT | CPU_SUSPEND_INT | CPU_HANDLER_INT) #define CPU_ALL_INT (CPU_HW_INT | CPU_NON_HW_INT) // mmu flags diff --git a/lib86cpu/core/translate.cpp b/lib86cpu/core/translate.cpp index 7c7c0fc..f10f048 100644 --- a/lib86cpu/core/translate.cpp +++ b/lib86cpu/core/translate.cpp @@ -1652,11 +1652,32 @@ cpu_do_int(cpu_ctx_t *cpu_ctx, uint32_t int_flg) } } - if (int_flg & (CPU_A20_INT | CPU_REGION_INT)) { + if (int_flg & (CPU_A20_INT | CPU_REGION_INT | CPU_HANDLER_INT)) { cpu_t *cpu = cpu_ctx->cpu; - uint32_t int_clear_flg; + uint32_t int_clear_flg = 0; + if (int_flg & CPU_HANDLER_INT) { + int_clear_flg |= CPU_HANDLER_INT; + std::for_each(cpu->regions_updated.begin(), cpu->regions_updated.end(), [cpu](const auto &data) { + if (data.io_space) { + auto io = const_cast *>(cpu->io_space_tree->search(data.start)); + if (io->type == mem_type::pmio) { + io->handlers = data.handlers; + io->opaque = data.opaque; + } + } + else { + auto mmio = const_cast *>(cpu->memory_space_tree->search(data.start)); + if (mmio->type == mem_type::mmio) { + mmio->handlers = data.handlers; + mmio->opaque = data.opaque; + } + } + }); + cpu->regions_updated.clear(); + } + if (int_flg & CPU_A20_INT) { - int_clear_flg = CPU_A20_INT; + int_clear_flg |= CPU_A20_INT; cpu->a20_mask = cpu->new_a20; tlb_flush(cpu); tc_cache_clear(cpu); @@ -1674,8 +1695,8 @@ cpu_do_int(cpu_ctx_t *cpu_ctx, uint32_t int_flg) cpu->regions_changed.clear(); } } - else { - int_clear_flg = CPU_REGION_INT; + else if (int_flg & CPU_REGION_INT) { + int_clear_flg |= CPU_REGION_INT; std::for_each(cpu->regions_changed.begin(), cpu->regions_changed.end(), [cpu](auto &pair) { addr_t start = pair.second->start, end = pair.second->end; if (pair.first) { diff --git a/lib86cpu/interface.cpp b/lib86cpu/interface.cpp index dc9636a..2507288 100644 --- a/lib86cpu/interface.cpp +++ b/lib86cpu/interface.cpp @@ -629,57 +629,99 @@ mem_init_region_ram(cpu_t *cpu, addr_t start, uint32_t size, bool should_int) * handlers: a struct of function pointers to call back when the region is accessed from the guest * opaque: an arbitrary host pointer which is passed to the registered r/w function for the region * should_int: raises a guest interrupt when true, otherwise the change takes effect immediately +* update: if 0, creates a new region. If 1, request an update to the handlers and the opaque member of an existing region that owns start. If 2, +* also request an interrupt to make visible the updated region to the cpu. When 3, only request the interrupt (the region arguments are ignored in this case). +* The last behaviour is useful to cache multiple update requests and only trigger the interrupt at the end. When not 0, should_int must be true. * ret: the status of the operation */ lc86_status -mem_init_region_io(cpu_t *cpu, addr_t start, uint32_t size, bool io_space, io_handlers_t handlers, void *opaque, bool should_int) +mem_init_region_io(cpu_t *cpu, addr_t start, uint32_t size, bool io_space, io_handlers_t handlers, void *opaque, bool should_int, int update) { - if (size == 0) { - return set_last_error(lc86_status::invalid_parameter); - } - - if (io_space) { - if ((start > 65535) || ((start + size) > 65536)) { + if (update) { + if (!should_int) { return set_last_error(lc86_status::invalid_parameter); } - std::unique_ptr> io(new memory_region_t); - io->start = static_cast(start); - uint64_t end_io1 = io->start + size - 1; - io->end = std::min(end_io1, to_u64(0xFFFF)); - io->type = mem_type::pmio; - io->handlers.fnr8 = handlers.fnr8 ? handlers.fnr8 : default_pmio_read_handler8; - io->handlers.fnr16 = handlers.fnr16 ? handlers.fnr16 : default_pmio_read_handler16; - io->handlers.fnr32 = handlers.fnr32 ? handlers.fnr32 : default_pmio_read_handler32; - io->handlers.fnw8 = handlers.fnw8 ? handlers.fnw8 : default_pmio_write_handler8; - io->handlers.fnw16 = handlers.fnw16 ? handlers.fnw16 : default_pmio_write_handler16; - io->handlers.fnw32 = handlers.fnw32 ? handlers.fnw32 : default_pmio_write_handler32; - io->opaque = opaque; - - cpu->io_space_tree->insert(std::move(io)); + if ((update == 1) || (update == 2)) { + if (io_space) { + handlers.fnr8 = handlers.fnr8 ? handlers.fnr8 : default_pmio_read_handler8; + handlers.fnr16 = handlers.fnr16 ? handlers.fnr16 : default_pmio_read_handler16; + handlers.fnr32 = handlers.fnr32 ? handlers.fnr32 : default_pmio_read_handler32; + handlers.fnw8 = handlers.fnw8 ? handlers.fnw8 : default_pmio_write_handler8; + handlers.fnw16 = handlers.fnw16 ? handlers.fnw16 : default_pmio_write_handler16; + handlers.fnw32 = handlers.fnw32 ? handlers.fnw32 : default_pmio_write_handler32; + } + else { + handlers.fnr8 = handlers.fnr8 ? handlers.fnr8 : default_mmio_read_handler8; + handlers.fnr16 = handlers.fnr16 ? handlers.fnr16 : default_mmio_read_handler16; + handlers.fnr32 = handlers.fnr32 ? handlers.fnr32 : default_mmio_read_handler32; + handlers.fnr64 = handlers.fnr64 ? handlers.fnr64 : default_mmio_read_handler64; + handlers.fnw8 = handlers.fnw8 ? handlers.fnw8 : default_mmio_write_handler8; + handlers.fnw16 = handlers.fnw16 ? handlers.fnw16 : default_mmio_write_handler16; + handlers.fnw32 = handlers.fnw32 ? handlers.fnw32 : default_mmio_write_handler32; + handlers.fnw64 = handlers.fnw64 ? handlers.fnw64 : default_mmio_write_handler64; + } + + cpu->regions_updated.emplace_back(start, io_space, handlers, opaque); + if (update == 2) { + cpu->raise_int_fn(&cpu->cpu_ctx, CPU_HANDLER_INT); + } + } + else if (update == 3) { + cpu->raise_int_fn(&cpu->cpu_ctx, CPU_HANDLER_INT); + } + else { + return set_last_error(lc86_status::invalid_parameter); + } } else { - std::unique_ptr> mmio(new memory_region_t); - mmio->start = start; - mmio->end = std::min(static_cast(start) + size - 1, to_u64(0xFFFFFFFF)); - mmio->type = mem_type::mmio; - mmio->handlers.fnr8 = handlers.fnr8 ? handlers.fnr8 : default_mmio_read_handler8; - mmio->handlers.fnr16 = handlers.fnr16 ? handlers.fnr16 : default_mmio_read_handler16; - mmio->handlers.fnr32 = handlers.fnr32 ? handlers.fnr32 : default_mmio_read_handler32; - mmio->handlers.fnr64 = handlers.fnr64 ? handlers.fnr64 : default_mmio_read_handler64; - mmio->handlers.fnw8 = handlers.fnw8 ? handlers.fnw8 : default_mmio_write_handler8; - mmio->handlers.fnw16 = handlers.fnw16 ? handlers.fnw16 : default_mmio_write_handler16; - mmio->handlers.fnw32 = handlers.fnw32 ? handlers.fnw32 : default_mmio_write_handler32; - mmio->handlers.fnw64 = handlers.fnw64 ? handlers.fnw64 : default_mmio_write_handler64; - mmio->opaque = opaque; + if (size == 0) { + return set_last_error(lc86_status::invalid_parameter); + } - if (should_int) { - cpu->regions_changed.push_back(std::make_pair(true, std::move(mmio))); - cpu->raise_int_fn(&cpu->cpu_ctx, CPU_REGION_INT); + if (io_space) { + if ((start > 65535) || ((start + size) > 65536)) { + return set_last_error(lc86_status::invalid_parameter); + } + + std::unique_ptr> io(new memory_region_t); + io->start = static_cast(start); + uint64_t end_io1 = io->start + size - 1; + io->end = std::min(end_io1, to_u64(0xFFFF)); + io->type = mem_type::pmio; + io->handlers.fnr8 = handlers.fnr8 ? handlers.fnr8 : default_pmio_read_handler8; + io->handlers.fnr16 = handlers.fnr16 ? handlers.fnr16 : default_pmio_read_handler16; + io->handlers.fnr32 = handlers.fnr32 ? handlers.fnr32 : default_pmio_read_handler32; + io->handlers.fnw8 = handlers.fnw8 ? handlers.fnw8 : default_pmio_write_handler8; + io->handlers.fnw16 = handlers.fnw16 ? handlers.fnw16 : default_pmio_write_handler16; + io->handlers.fnw32 = handlers.fnw32 ? handlers.fnw32 : default_pmio_write_handler32; + io->opaque = opaque; + + cpu->io_space_tree->insert(std::move(io)); } else { - cpu->memory_space_tree->insert(std::move(mmio)); - tc_should_clear_cache_and_tlb(cpu, start, start + size - 1); + std::unique_ptr> mmio(new memory_region_t); + mmio->start = start; + mmio->end = std::min(static_cast(start) + size - 1, to_u64(0xFFFFFFFF)); + mmio->type = mem_type::mmio; + mmio->handlers.fnr8 = handlers.fnr8 ? handlers.fnr8 : default_mmio_read_handler8; + mmio->handlers.fnr16 = handlers.fnr16 ? handlers.fnr16 : default_mmio_read_handler16; + mmio->handlers.fnr32 = handlers.fnr32 ? handlers.fnr32 : default_mmio_read_handler32; + mmio->handlers.fnr64 = handlers.fnr64 ? handlers.fnr64 : default_mmio_read_handler64; + mmio->handlers.fnw8 = handlers.fnw8 ? handlers.fnw8 : default_mmio_write_handler8; + mmio->handlers.fnw16 = handlers.fnw16 ? handlers.fnw16 : default_mmio_write_handler16; + mmio->handlers.fnw32 = handlers.fnw32 ? handlers.fnw32 : default_mmio_write_handler32; + mmio->handlers.fnw64 = handlers.fnw64 ? handlers.fnw64 : default_mmio_write_handler64; + mmio->opaque = opaque; + + if (should_int) { + cpu->regions_changed.push_back(std::make_pair(true, std::move(mmio))); + cpu->raise_int_fn(&cpu->cpu_ctx, CPU_REGION_INT); + } + else { + cpu->memory_space_tree->insert(std::move(mmio)); + tc_should_clear_cache_and_tlb(cpu, start, start + size - 1); + } } } diff --git a/lib86cpu/lib86cpu_priv.h b/lib86cpu/lib86cpu_priv.h index 7bb65f1..3ff8a15 100644 --- a/lib86cpu/lib86cpu_priv.h +++ b/lib86cpu/lib86cpu_priv.h @@ -75,6 +75,13 @@ struct memory_region_t { memory_region_t(T s, T e) : memory_region_t() { start = buff_off_start = s; end = e; } }; +struct region_update_info_t { + addr_t start; + bool io_space; + io_handlers_t handlers; + void *opaque; +}; + #include "as.h" struct tlb_t { @@ -187,6 +194,7 @@ struct cpu_t { std::vector> wp_data; std::vector> wp_io; std::vector>>> regions_changed; + std::vector regions_updated; std::bitset smc; // self-modifying code tracking tlb_t itlb[ITLB_NUM_SETS][ITLB_NUM_LINES]; // instruction tlb tlb_t dtlb[DTLB_NUM_SETS][DTLB_NUM_LINES]; // data tlb