Skip to content

Commit

Permalink
Revert "Introduction of IOMMU QEMU type,"
Browse files Browse the repository at this point in the history
This reverts commit 7d56052.
  • Loading branch information
androm3da committed Aug 27, 2024
1 parent 2765ab1 commit 3366fb8
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 606 deletions.
125 changes: 118 additions & 7 deletions qemu-components/common/include/dmi-manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class QemuInstanceDmiManager
* start and an end address as it it requested from the point of view of an
* initiator's address map.
*/
class DmiRegionAlias : public qemu::DmiRegionAliasBase
class DmiRegionAlias
{
private:
uint64_t m_start;
Expand Down Expand Up @@ -223,6 +223,73 @@ class QemuInstanceDmiManager
*/
DmiRegionMap m_regions;

/**
* @brief "Merge" two memory region boundaries together
*
* @details "Merging" means deleting the previous region, and updating tlm_dmi boundaries
* to create a larger TlmDmi region which spans both the previous and the requested
* boundaries.
*
* @return This function updates the out parameter `dmi_out` and returns the priority of the new
* region to create.
*/
int merge_left(const DmiRegionMap::iterator& it, tlm::tlm_dmi& dmi_out)
{
const DmiRegion& prev_region = it->second;
int priority = prev_region.get_mr().get_priority();

// We need to make sure we can actually update tlm_dmi address by
// avoiding any underflow
if (dmi_out.get_start_address() >= prev_region.get_size()) {
SCP_INFO("DMI.Libqbox") << std::hex << "Merge " << dmi_out << " with previous " << prev_region;

dmi_out.set_start_address(dmi_out.get_start_address() - prev_region.get_size());
dmi_out.set_dmi_ptr(prev_region.get_ptr());
// The new region is going to overlap this one that got retired, so its
// priority should be higher
assert(priority < std::numeric_limits<int>::max());
priority += 1;
// Finally, delete previous region
m_root.del_subregion(prev_region.get_mr());
m_regions.erase(it);
}

return priority;
}

/**
* @brief "Merge" two memory region boundaries together
*
* @details "Merging" means deleting the next region, and updating tlm_dmi boundaries
* to create a larger TlmDmi region which spans both the next and the requested
* boundaries.
*
* @return This function updates the out parameter `dmi_out` and returns the priority of the
* new region to create.
*/
int merge_right(const DmiRegionMap::iterator& it, tlm::tlm_dmi& dmi_out)
{
const DmiRegion& next_region = it->second;
int priority = next_region.get_mr().get_priority();

// We need to make sure we can actually update tlm_dmi address by
// avoiding any overflow
if (dmi_out.get_end_address() <= std::numeric_limits<uint64_t>::max() - next_region.get_size()) {
SCP_INFO("DMI.Libqbox") << std::hex << "Merge " << dmi_out << " with next " << next_region;

dmi_out.set_end_address(dmi_out.get_end_address() + next_region.get_size());
// The new region is going to overlap this one that got retired, so its
// priority should be higher
assert(priority < std::numeric_limits<int>::max());
priority += 1;
// Finally, delete next region
m_root.del_subregion(next_region.get_mr());
m_regions.erase(it);
}

return priority;
}

public:
/**
* @brief This regions are added as subregions of the manager root memory
Expand All @@ -242,15 +309,59 @@ class QemuInstanceDmiManager

std::lock_guard<std::mutex> lock(m_mutex);

int priority = 0;

if (m_regions.size() > 0) {
// Find "next", the first region starting after after `start`
auto next = m_regions.upper_bound(start);

// If "next" is not the first region, it means there is a region before
if (next != m_regions.begin()) {
auto prev = std::prev(next);
// The previus region starts "before" or "at" start
DmiRegion& prev_region = prev->second;
assert(prev_region.get_key() <= start);
auto prev_end = prev_region.get_end();

// Check whether previos region spans the requested boundaries
if (prev_end >= end) {
SCP_INFO("DMI.Libqbox") << "Already have " << prev_region << " covering " << info;
return;
}

// If previous region does not span the requested boundaries, it means it ends
// before `end`. Here we check whether the previos region ends exactly ad `end`,
// in which case we proceed with a merge
if ((prev->first < start) && (prev_end + 1 == start)) {
priority = merge_left(prev, dmi);
}
}

// At this point there is a possibility that `merge_left` deleted a DMI region, so we
// call `upper_bound` again.
next = m_regions.upper_bound(start);
if (next != m_regions.end()) {
// In this case we have a region which is starting after `start`
DmiRegion& next_region = next->second;
// If it starts exactly at the end of the requested region, we can merge.
if (next_region.get_key() == end + 1) {
priority = merge_right(next, dmi);
}
}
}

// Another case to consider is when there is already a smaller memory region at `start`,
// so we should erase that and create the new one with increased priority.
auto existing_it = m_regions.find(start);
if (existing_it != m_regions.end()) {
if (existing_it->second.get_size() != size) {
SCP_FATAL("DMI.Libqbox")("Overlapping DMI regions!");
}
return; // Identicle region exists
DmiRegion& existing_region = existing_it->second;
priority = existing_region.get_mr().get_priority() + 1;
m_root.del_subregion(existing_region.get_mr());
m_regions.erase(existing_it);
}
DmiRegion region = DmiRegion(dmi, 0, m_inst, fd);
m_root.add_subregion(region.get_mut_mr(), region.get_key());

DmiRegion region = DmiRegion(dmi, priority, m_inst, fd);
m_root.add_subregion_overlap(region.get_mut_mr(), region.get_key());

auto res = m_regions.emplace(region.get_key(), std::move(region));
if (!res.second) {
Expand Down
5 changes: 0 additions & 5 deletions qemu-components/common/include/internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class LibQemuInternals

LibQemuObjectCallback<Cpu::EndOfLoopCallbackFn> m_cpu_end_of_loop_cbs;
LibQemuObjectCallback<Cpu::CpuKickCallbackFn> m_cpu_kick_cbs;
LibQemuObjectCallback<IOMMUMemoryRegion::IOMMUTranslateCallbackFn> m_iommu_translate_cbs;
LibQemuObjectCallback<CpuRiscv64::MipUpdateCallbackFn> m_riscv_mip_update_cbs;

std::vector<LibQemuObjectCallbackBase*> m_cbs{
Expand All @@ -78,10 +77,6 @@ class LibQemuInternals
LibQemuObjectCallback<Cpu::EndOfLoopCallbackFn>& get_cpu_end_of_loop_cb() { return m_cpu_end_of_loop_cbs; }

LibQemuObjectCallback<Cpu::CpuKickCallbackFn>& get_cpu_kick_cb() { return m_cpu_kick_cbs; }
LibQemuObjectCallback<IOMMUMemoryRegion::IOMMUTranslateCallbackFn>& get_iommu_translate_cb()
{
return m_iommu_translate_cbs;
}

LibQemuObjectCallback<CpuRiscv64::MipUpdateCallbackFn>& get_cpu_riscv_mip_update_cb()
{
Expand Down
57 changes: 0 additions & 57 deletions qemu-components/common/include/libqemu-cxx/libqemu-cxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,12 @@

#pragma once

// SID this one for you to play with!
// #define UNORD

#include <string>
#include <unordered_map>
#include <memory>
#include <functional>
#include <set>
#include <vector>
#include <map>

#include <libqemu-cxx/target_info.h>
#include <libqemu-cxx/exceptions.h>
Expand All @@ -39,7 +35,6 @@ struct DisplayChangeListener;
struct MemTxAttrs;
struct QemuMemoryRegion;
struct QemuMemoryRegionOps;
struct QemuIOMMUMemoryRegion;
struct QemuAddressSpace;
struct QemuMemoryListener;
struct QemuTimer;
Expand Down Expand Up @@ -67,7 +62,6 @@ class LibQemuInternals;
class Object;
class MemoryRegion;
class MemoryRegionOps;
class IOMMUMemoryRegion;
class AddressSpace;
class MemoryListener;
class Gpio;
Expand Down Expand Up @@ -239,7 +233,6 @@ class Object

void set_prop_bool(const char* name, bool val);
void set_prop_int(const char* name, int64_t val);
void set_prop_uint(const char* name, uint64_t val);
void set_prop_str(const char* name, const char* val);
void set_prop_link(const char* name, const Object& link);
void set_prop_parse(const char* name, const char* value);
Expand Down Expand Up @@ -426,56 +419,6 @@ class AddressSpace
void update_topology();
};

struct DmiRegionAliasBase {
};
class IOMMUMemoryRegion : public MemoryRegion
{
public:
static constexpr const char* const TYPE = "libqemu-iommu-memory-region";

qemu::MemoryRegion m_root_te;
std::shared_ptr<qemu::AddressSpace> m_as_te;
qemu::MemoryRegion m_root;
std::shared_ptr<qemu::AddressSpace> m_as;
std::map<uint64_t, std::shared_ptr<DmiRegionAliasBase>> m_dmi_aliases;
uint64_t min_page_sz;

IOMMUMemoryRegion(const Object& o)
: MemoryRegion(o)
, m_root_te(get_inst().object_new_unparented<qemu::MemoryRegion>())
, m_as_te(get_inst().address_space_new())
, m_root(get_inst().object_new_unparented<qemu::MemoryRegion>())
, m_as(get_inst().address_space_new())
{
}

typedef enum {
IOMMU_NONE = 0,
IOMMU_RO = 1,
IOMMU_WO = 2,
IOMMU_RW = 3,
} IOMMUAccessFlags;

typedef struct {
QemuAddressSpace* target_as;
uint64_t iova;
uint64_t translated_addr;
uint64_t addr_mask;
IOMMUAccessFlags perm;
} IOMMUTLBEntry;

#ifdef UNORD
std::unordered_map<uint64_t, qemu::IOMMUMemoryRegion::IOMMUTLBEntry> m_mapped_te;
#else
std::map<uint64_t, qemu::IOMMUMemoryRegion::IOMMUTLBEntry> m_mapped_te;
#endif

using IOMMUTranslateCallbackFn = std::function<void(IOMMUTLBEntry*, uint64_t, IOMMUAccessFlags, int)>;
void init(const Object& owner, const char* name, uint64_t size, MemoryRegionOpsPtr ops,
IOMMUTranslateCallbackFn cb);
void iommu_unmap(IOMMUTLBEntry*);
};

class MemoryListener
{
public:
Expand Down
Loading

0 comments on commit 3366fb8

Please sign in to comment.