61 :
public tlm::tlm_initiator_socket<BUSWIDTH, tlm::tlm_base_protocol_types, 1, sc_core::SC_ZERO_OR_MORE_BOUND>,
62 public tlm::tlm_bw_transport_if<>
66 std::vector<std::pair<sc_dt::uint64, sc_dt::uint64>> m_ranges;
71 using TlmInitiatorSocket = tlm::tlm_initiator_socket<
BUSWIDTH, tlm::tlm_base_protocol_types, 1,
72 sc_core::SC_ZERO_OR_MORE_BOUND>;
73 using TlmPayload = tlm::tlm_generic_payload;
74 using MemTxResult = qemu::MemoryRegionOps::MemTxResult;
88 bool m_finished =
false;
90 std::shared_ptr<qemu::AddressSpace> m_as;
91 std::shared_ptr<qemu::MemoryListener> m_listener;
92 std::map<uint64_t, std::shared_ptr<qemu::IOMMUMemoryRegion>> m_mmio_mrs;
97 std::shared_ptr<qemu::MemoryRegion> m_root;
104 std::map<DmiRegionAliasKey, DmiRegionAlias::Ptr> m_dmi_aliases;
105 using AliasesIterator = std::map<DmiRegionAliasKey, DmiRegionAlias::Ptr>::iterator;
111 trans.set_data_ptr(
reinterpret_cast<unsigned char*
>(
val));
112 trans.set_data_length(size);
113 trans.set_streaming_width(size);
114 trans.set_byte_enable_length(0);
115 trans.set_dmi_allowed(
false);
116 trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
118 m_initiator.initiator_customize_tlm_payload(
trans);
121 void add_dmi_mr_alias(DmiRegionAlias::Ptr
alias)
126 alias->set_installed();
129 void del_dmi_mr_alias(
const DmiRegionAlias::Ptr
alias)
131 if (!
alias->is_installed()) {
135 m_r->m_root->del_subregion(
alias->get_alias_mr());
164 std::lock_guard<std::mutex>
lock(m_mutex);
168 if (
m !=
iommumr->m_mapped_te.end()) {
171 (
"FAST (unord) translate for 0x{:x} : 0x{:x}->0x{:x} (mask 0x{:x}) perm={}",
addr,
te->iova,
172 te->translated_addr,
te->addr_mask,
te->perm);
177 if (
iommumr->m_mapped_te.size() > 0) {
179 if (
it !=
iommumr->m_mapped_te.begin()) {
181 if (
it !=
iommumr->m_mapped_te.end() && (
it->first) == (
addr & ~
it->second.addr_mask)) {
188 (
"FAST translate for 0x{:x} : 0x{:x}->0x{:x} (mask 0x{:x}) perl={}",
addr,
te->iova,
189 te->translated_addr,
te->addr_mask,
te->perm);
220 if (
lu_dmi.has_dmi(gs::tlm_dmi_ex::dmi_iommu)) {
230 (
"Adding IOMMU DMI Region start 0x{:x} - 0x{:x}",
lu_dmi_data.get_start_address(),
236 te->target_as =
iommumr->m_as_te->get_ptr();
241 te->perm = (qemu::IOMMUMemoryRegion::IOMMUAccessFlags)
ldmi_data.get_granted_access();
244 (
"Translate IOMMU 0x{:x}->0x{:x} (mask 0x{:x})",
te->iova,
te->translated_addr,
te->addr_mask);
254 alias->set_installed();
258 te->target_as =
iommumr->m_as->get_ptr();
262 te->perm = (qemu::IOMMUMemoryRegion::IOMMUAccessFlags)
ldmi_data.get_granted_access();
265 (
"Translate 1-1 passthrough 0x{:x}->0x{:x} (mask 0x{:x})",
te->iova,
te->translated_addr,
270 SCP_WARN(())(
"Could have used the cache! {:x}\n",
addr);
278 std::lock_guard<std::mutex>
lock(m_mutex);
285 (
"Caching TE at addr 0x{:x} (mask {:x})",
addr &
~te->addr_mask,
te->addr_mask);
291 te->target_as =
iommumr->m_as->get_ptr();
292 te->addr_mask = (1 <<
iommumr->min_page_sz) - 1;
295 te->perm = qemu::IOMMUMemoryRegion::IOMMU_RW;
298 (
"Translate 1-1 limited passthrough 0x{:x}->0x{:x} (mask 0x{:x})",
te->iova,
te->translated_addr,
347 tlm::tlm_dmi dmi_data;
350 SCP_INFO(()) <<
"DMI request for address 0x" << std::hex <<
trans.get_address();
357 bool dmi_valid = (*this)->get_direct_mem_ptr(
trans, dmi_data);
360 SCP_INFO(())(
"No DMI available for {:x}",
trans.get_address());
364 if (
u_dmi.has_dmi(gs::tlm_dmi_ex::dmi_mapped)) {
365 tlm::tlm_dmi
first_map =
u_dmi.get_first(gs::tlm_dmi_ex::dmi_mapped);
368 if (
u_dmi.has_dmi(gs::tlm_dmi_ex::dmi_nomap)) {
385 if (
u_dmi.has_dmi(gs::tlm_dmi_ex::dmi_iommu)) {
387 SCP_INFO(())(
"IOMMU DMI available for {:x}",
trans.get_address());
390 tlm::tlm_dmi
first_map =
u_dmi.get_first(gs::tlm_dmi_ex::dmi_mapped);
395 auto itr = m_mmio_mrs.find(start);
396 if (
itr == m_mmio_mrs.end()) {
402 invalidate_single_range(start, start + size);
405 (
"Adding IOMMU for VA 0x{:x} [0x{:x} - 0x{:x}]",
trans.get_address(), start, start + size);
407 using namespace std::placeholders;
408 qemu::MemoryRegionOpsPtr
ops;
409 ops = m_inst.
get().memory_region_ops_new();
410 ops->set_read_callback(std::bind(&QemuInitiatorSocket::qemu_io_read,
this,
_1,
_2,
_3,
_4));
411 ops->set_write_callback(std::bind(&QemuInitiatorSocket::qemu_io_write,
this,
_1,
_2,
_3,
_4));
412 ops->set_max_access_size(8);
414 auto iommumr = std::make_shared<qemu::IOMMUMemoryRegion>(
419 qemu::IOMMUMemoryRegion::IOMMUAccessFlags flags,
422 std::lock_guard<std::mutex>
lock(m_mutex);
425 m_r->m_root->add_subregion(*
iommumr, start);
434 (
"Memory request should be directed via MMIO interface {:x} {:x}", start,
trans.get_address());
453 SCP_INFO(()) <<
"DMI Adding for address 0x" << std::hex <<
trans.get_address();
470 if (m_dmi_aliases.size() > MAX_MAP) {
471 SCP_FATAL(())(
"Too many DMI regions requested, consider using an IOMMU");
473 uint64_t start = dmi_data.get_start_address();
474 uint64_t end = dmi_data.get_end_address();
476 if (0 == m_dmi_aliases.count(start)) {
477 SCP_INFO(()) <<
"Adding DMI for range [0x" << std::hex << dmi_data.get_start_address() <<
"-0x" << std::hex
478 << dmi_data.get_end_address() <<
"]";
482 m_dmi_aliases[start] =
alias;
483 add_dmi_mr_alias(m_dmi_aliases[start]);
485 SCP_INFO(())(
"Already have DMI for 0x{:x}", start);
490 void check_qemu_mr_hint(TlmPayload&
trans)
497 if (
ext ==
nullptr) {
503 if (
target_mr.get_inst_id() != m_dev.get_inst_id()) {
515 void do_regular_access(TlmPayload&
trans)
517 using sc_core::sc_time;
520 sc_time
now = m_initiator.initiator_get_local_time();
522 m_inst.
get().unlock_iothread();
524 m_inst.
get().lock_iothread();
530 check_qemu_mr_hint(
trans);
531 if (
trans.is_dmi_allowed()) {
535 m_initiator.initiator_set_local_time(
now);
538 void do_debug_access(TlmPayload&
trans)
540 m_inst.
get().unlock_iothread();
542 m_inst.
get().lock_iothread();
545 void do_direct_access(TlmPayload&
trans)
547 sc_core::sc_time
now = m_initiator.initiator_get_local_time();
555 if (m_finished)
return qemu::MemoryRegionOps::MemTxError;
563 do_direct_access(
trans);
565 if (!m_inst.g_rec_qemu_io_lock.try_lock()) {
571 m_inst.
get().unlock_iothread();
572 m_inst.g_rec_qemu_io_lock.lock();
573 m_inst.
get().lock_iothread();
578 if (reentrancy > 1) {
579 do_direct_access(
trans);
580 }
else if (
attrs.debug) {
581 do_debug_access(
trans);
583 do_regular_access(
trans);
587 m_inst.g_rec_qemu_io_lock.unlock();
589 m_initiator.initiator_tidy_tlm_payload(
trans);
591 switch (
trans.get_response_status()) {
592 case tlm::TLM_OK_RESPONSE:
593 return qemu::MemoryRegionOps::MemTxOK;
595 case tlm::TLM_ADDRESS_ERROR_RESPONSE:
596 return qemu::MemoryRegionOps::MemTxDecodeError;
599 return qemu::MemoryRegionOps::MemTxError;
606 return qemu_io_access(tlm::TLM_READ_COMMAND,
addr,
val, size,
attrs);
611 return qemu_io_access(tlm::TLM_WRITE_COMMAND,
addr, &
val, size,
attrs);
615 : TlmInitiatorSocket(name)
620 SCP_DEBUG(()) <<
"QemuInitiatorSocket constructor";
621 TlmInitiatorSocket::bind(*
static_cast<tlm::tlm_bw_transport_if<>*
>(
this));
626 using namespace std::placeholders;
629 qemu::MemoryRegionOpsPtr
ops;
631 m_r =
new m_mem_obj(inst);
632 ops = inst.memory_region_ops_new();
634 ops->set_read_callback(std::bind(&QemuInitiatorSocket::qemu_io_read,
this,
_1,
_2,
_3,
_4));
635 ops->set_write_callback(std::bind(&QemuInitiatorSocket::qemu_io_write,
this,
_1,
_2,
_3,
_4));
636 ops->set_max_access_size(8);
638 m_r->m_root->init_io(
dev, TlmInitiatorSocket::name(), std::numeric_limits<uint64_t>::max(),
ops);
639 dev.set_prop_link(
prop, *m_r->m_root);
644 void end_of_simulation()
657 m_r->m_root->removeSubRegions();
668 if (m_finished)
return;
670 SCP_DEBUG(()) <<
"Mapping request for address [0x" << std::hex <<
addr <<
"-0x" <<
addr +
len <<
"]";
676 trans.set_dmi_allowed(
true);
684 SCP_INFO(()) <<
"0x" << std::hex <<
current_addr <<
" mapped [0x" << dmi_data.get_start_address() <<
"-0x"
685 << dmi_data.get_end_address() <<
"]";
695 m_initiator.initiator_tidy_tlm_payload(
trans);
700 using namespace std::placeholders;
703 qemu::MemoryRegionOpsPtr
ops;
704 ops = inst.memory_region_ops_new();
706 ops->set_read_callback(std::bind(&QemuInitiatorSocket::qemu_io_read,
this,
_1,
_2,
_3,
_4));
707 ops->set_write_callback(std::bind(&QemuInitiatorSocket::qemu_io_write,
this,
_1,
_2,
_3,
_4));
708 ops->set_max_access_size(8);
711 system_memory->init_io(
dev, TlmInitiatorSocket::name(), std::numeric_limits<uint64_t>::max() - 1,
ops);
714 m_as = inst.address_space_get_system_memory();
717 m_as->update_topology();
719 m_listener = inst.memory_listener_new();
720 m_listener->set_map_callback(std::bind(&QemuInitiatorSocket::qemu_map,
this,
_1,
_2,
_3));
721 m_listener->register_as(m_as);
729 virtual tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload&
trans, tlm::tlm_phase&
phase,
734 return tlm::TLM_COMPLETED;
737 virtual AliasesIterator remove_alias(AliasesIterator
it)
739 DmiRegionAlias::Ptr r =
it->second;
756 assert(r->is_installed());
779 return m_dmi_aliases.erase(
it);
787 if (
it != m_dmi_aliases.begin()) {
794 while (
it != m_dmi_aliases.end()) {
795 DmiRegionAlias::Ptr r =
it->second;
808 it = remove_alias(
it);
810 SCP_DEBUG(()) <<
"Invalidated region [0x" << std::hex << r->get_start() <<
", 0x" << std::hex
811 << r->get_end() <<
"]";
815 void invalidate_ranges_safe_cb()
817 std::lock_guard<std::mutex>
lock(m_mutex);
819 SCP_DEBUG(()) <<
"Invalidating " << m_ranges.size() <<
" ranges";
820 auto rit = m_ranges.begin();
821 while (
rit != m_ranges.end()) {
822 invalidate_single_range(
rit->first,
rit->second);
823 rit = m_ranges.erase(
rit);
830 if (m_finished)
return;
834 std::lock_guard<std::mutex>
lock(m_mutex);
836 for (
auto m : m_mmio_mrs) {
838 auto mr_end =
m.first +
m.second->get_size();
841 for (
auto it =
m.second->m_mapped_te.begin();
it !=
m.second->m_mapped_te.end();) {
848 m.second->iommu_unmap(&(
it->second));
849 it =
m.second->m_mapped_te.erase(
it);
858 std::lock_guard<std::mutex>
lock(m_mutex);
862 m_initiator.initiator_async_run([&]() { invalidate_ranges_safe_cb(); });
869 std::lock_guard<std::mutex>
lock(m_mutex);
871 for (
auto m : m_mmio_mrs) {
872 m.second->m_mapped_te.clear();
873 auto it = m_dmi_aliases.begin();
874 while (
it != m_dmi_aliases.end()) {
875 DmiRegionAlias::Ptr r =
it->second;
876 it = remove_alias(
it);