quic/qbox
Loading...
Searching...
No Matches
dmi-manager.h
1/*
2 * This file is part of libqbox
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
4 * Author: GreenSocs 2021
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9#ifndef LIBQBOX_DMI_MANAGER_H_
10#define LIBQBOX_DMI_MANAGER_H_
11
12#include <map>
13#include <mutex>
14#include <limits>
15#include <cassert>
16#include <memory>
17
18#include <tlm>
19
20#include <libqemu-cxx/libqemu-cxx.h>
21
22#include <libgsutils.h>
23
24#include <scp/report.h>
25
26std::ostream& operator<<(std::ostream& os, const tlm::tlm_dmi& region);
27
47{
48public:
49 /* Simple container object used to parent the memory regions we create */
51 {
52 public:
53 static constexpr const char* const TYPE = "container";
54
55 QemuContainer() = default;
56 QemuContainer(const QemuContainer& o) = default;
57 QemuContainer(const Object& o): Object(o) {}
58 };
59
77 {
78 public:
79 using Key = uintptr_t;
80 using Ptr = std::shared_ptr<DmiRegion>;
81
82 private:
83 unsigned char* m_ptr;
84
85 QemuContainer m_container;
87 uint64_t m_size;
88
89 bool m_retiring = false;
90
91 static uint64_t size_from_tlm_dmi(const tlm::tlm_dmi& info)
92 {
93 uint64_t start = info.get_start_address();
94 uint64_t end = info.get_end_address();
95 assert(start < end);
96 assert(!((start == 0) && (end == std::numeric_limits<uint64_t>::max())));
97 return end - start + 1;
98 }
99
100 public:
101 DmiRegion() = default;
102
103 DmiRegion(const tlm::tlm_dmi& info, int priority, qemu::LibQemu& inst, int fd = -1)
104 : m_ptr(info.get_dmi_ptr())
105 , m_container(inst.object_new_unparented<QemuContainer>())
106 , m_mr(inst.object_new_unparented<qemu::MemoryRegion>())
107 , m_size(size_from_tlm_dmi(info))
108 {
109 // This will parent the objects
110 m_mr.init_ram_ptr(m_container, "dmi", m_size, m_ptr, fd);
111 m_mr.set_priority(priority);
112 SCP_INFO("DMI.Libqbox") << "Creating " << *this;
113 }
114
115 virtual ~DmiRegion() { SCP_INFO("DMI.Libqbox") << "Destroying " << *this; }
116
117 uint64_t get_size() const { return m_size; }
118
119 const qemu::MemoryRegion& get_mr() const { return m_mr; }
120 qemu::MemoryRegion& get_mut_mr() { return m_mr; }
121
122 Key get_key() const { return reinterpret_cast<Key>(m_ptr); }
123 Key get_end() const { return get_key() + (m_size - 1); }
124 unsigned char* get_ptr() const { return m_ptr; }
125
126 static Key key_from_tlm_dmi(const tlm::tlm_dmi& info) { return reinterpret_cast<Key>(info.get_dmi_ptr()); }
127
128 friend std::ostream& operator<<(std::ostream& os, const DmiRegion& region);
129 };
130
140 {
141 private:
142 uint64_t m_start;
143 uint64_t m_end;
144 unsigned char* m_ptr;
145
146 QemuContainer m_container;
147 qemu::MemoryRegion m_alias;
148
149 bool m_installed = false;
150
151 friend std::ostream& operator<<(std::ostream& os, const DmiRegionAlias& alias);
152
153 public:
154 using Ptr = std::shared_ptr<DmiRegionAlias>;
155
156 /* Construct an invalid alias */
157 DmiRegionAlias() {}
158
159 DmiRegionAlias(qemu::MemoryRegion& root, const tlm::tlm_dmi& info, qemu::LibQemu& inst)
160 : m_start(info.get_start_address())
161 , m_end(info.get_end_address())
162 , m_ptr(info.get_dmi_ptr())
163 , m_container(inst.object_new_unparented<QemuContainer>())
164 , m_alias(inst.object_new_unparented<qemu::MemoryRegion>())
165 {
166 SCP_INFO("DMI.Libqbox") << "Creating Alias " << *this;
167 /* Offset is just the host pointer. That is the same value used as offset
168 * when "overlap-adding" the RAM regions to the DMI-manager root container. */
169 uint64_t offset = DmiRegion::key_from_tlm_dmi(info);
170 m_alias.init_alias(m_container, "dmi-alias", root, offset, (m_end - m_start) + 1);
171 }
172
173 /* helpful for debugging */
174 ~DmiRegionAlias() { SCP_INFO("DMI.Libqbox") << "Destroying " << *this; }
175
176 DmiRegionAlias(DmiRegionAlias&&) = delete;
177
178 uint64_t get_start() const { return m_start; }
179
180 uint64_t get_end() const { return m_end; }
181
182 uint64_t get_size() const { return (m_end - m_start) + 1; }
183
184 qemu::MemoryRegion get_alias_mr() const { return m_alias; }
185
186 unsigned char* get_dmi_ptr() const { return m_ptr; }
187
193 void set_installed() { m_installed = true; }
194
200 bool is_installed() const { return m_installed; }
201 };
202
203protected:
204 qemu::LibQemu& m_inst;
205
206 QemuContainer m_root_container;
215
216 std::mutex m_mutex;
217
218 using DmiRegionMap = std::map<DmiRegion::Key, DmiRegion>;
224 DmiRegionMap m_regions;
225
226public:
232 void get_region(const tlm::tlm_dmi& info, int fd = -1)
233 {
234 DmiRegion::Key start = DmiRegion::key_from_tlm_dmi(info);
235 uint64_t size = (info.get_end_address() - info.get_start_address()) + 1;
236
237 tlm::tlm_dmi dmi;
238 dmi.set_start_address(info.get_start_address());
239 dmi.set_end_address(info.get_end_address());
240 dmi.set_dmi_ptr(info.get_dmi_ptr());
241
242 std::lock_guard<std::mutex> lock(m_mutex);
243
244 auto existing_it = m_regions.find(start);
245 if (existing_it != m_regions.end()) {
246 if (existing_it->second.get_size() != size) {
247 SCP_INFO("DMI.Libqbox")
248 ("Overlapping DMI regions old size {:x} new size {:x}!", existing_it->second.get_size(), size);
249 m_root.del_subregion(existing_it->second.get_mut_mr());
250 m_regions.erase(existing_it);
251 } else {
252 return; // Identical region exists
253 }
254 }
255 DmiRegion region = DmiRegion(dmi, 0, m_inst, fd);
256 m_root.add_subregion(region.get_mut_mr(), region.get_key());
257
258 auto res = m_regions.emplace(region.get_key(), std::move(region));
259 if (!res.second) {
260 DmiRegion& existing_region = res.first->second;
261 SCP_FATAL("DMI.Libqbox") << "Failed to add " << info << " for already existing " << existing_region;
262 }
263 }
264
265public:
266 QemuInstanceDmiManager(qemu::LibQemu& inst): m_inst(inst) { SCP_DEBUG("DMI.Libqbox") << "DmiManager Constructor"; }
267
270
271 ~QemuInstanceDmiManager() { m_root.removeSubRegions(); }
272
273 void init()
274 {
275 m_root_container = m_inst.object_new_unparented<QemuContainer>();
276 m_root = m_inst.object_new_unparented<qemu::MemoryRegion>();
277 m_root.init(m_root_container, "dmi-manager", std::numeric_limits<uint64_t>::max());
278 }
279
283 DmiRegionAlias::Ptr get_new_region_alias(const tlm::tlm_dmi& info, int fd = -1)
284 {
286 return std::make_shared<DmiRegionAlias>(m_root, info, m_inst);
287 }
288};
289#endif
An alias to a DMI region.
Definition dmi-manager.h:140
bool is_installed() const
Return true if the alias is mapped onto QEMU root MR.
Definition dmi-manager.h:200
void set_installed()
Mark the alias as mapped onto QEMU root MR.
Definition dmi-manager.h:193
a DMI region
Definition dmi-manager.h:77
Definition dmi-manager.h:51
Handles the DMI regions at the QEMU instance level.
Definition dmi-manager.h:47
DmiRegionMap m_regions
A copy of each RAM memory region is kept here. Another is stored in the m_root.m_subregions vector....
Definition dmi-manager.h:224
void get_region(const tlm::tlm_dmi &info, int fd=-1)
This regions are added as subregions of the manager root memory region container. They can overlap,...
Definition dmi-manager.h:232
qemu::MemoryRegion m_root
The DMI manager maintains a "container" memory region as a root where "RAM" memory regions are added ...
Definition dmi-manager.h:214
DmiRegionAlias::Ptr get_new_region_alias(const tlm::tlm_dmi &info, int fd=-1)
Create a new alias for the DMI region designated by info
Definition dmi-manager.h:283
Definition target.h:160
Definition libqemu-cxx.h:92
Definition libqemu-cxx.h:362
Definition libqemu-cxx.h:229
Definition libqemu-cxx.h:440