9#ifndef LIBQBOX_QEMU_INSTANCE_H_
10#define LIBQBOX_QEMU_INSTANCE_H_
16#include <cci_configuration>
23#include <libqemu-cxx/libqemu-cxx.h>
25#include <dmi-manager.h>
26#include <exceptions.h>
28#include <scp/report.h>
30#include "ports/qemu-target-signal-socket.h"
35 virtual bool can_run() {
return true; }
51 using Target = qemu::Target;
63 : sc_core::sc_module(
n), m_loader(qemu::get_default_lib_loader())
74 LibLoader& get_loader() {
return *m_loader; }
91 std::shared_ptr<gs::tlm_quantumkeeper_extended> m_first_qk =
NULL;
93 std::list<QemuDeviceBaseIF*> devices;
94 cci::cci_broker_handle m_conf_broker;
96 bool m_running =
false;
103 std::mutex g_signaled_lock;
104 std::condition_variable g_signaled_cond;
105 bool g_signaled =
false;
106 std::recursive_mutex g_rec_qemu_io_lock;
110 std::lock_guard<std::mutex>
lock(m_lock);
111 devices.push_back(
d);
116 std::lock_guard<std::mutex>
lock(m_lock);
122 if (!m_running)
return false;
123 std::lock_guard<std::mutex>
lock(m_lock);
124 bool can_run =
false;
126 for (
auto const&
i : devices) {
134 using Target = qemu::Target;
143 TcgMode StringToTcgMode(std::string s)
145 if (s ==
"SINGLE")
return TCG_SINGLE;
146 if (s ==
"COROUTINE")
return TCG_COROUTINE;
147 if (s ==
"MULTI")
return TCG_MULTI;
148 SCP_WARN(()) <<
"Unknown TCG mode " << s;
149 return TCG_UNSPECIFIED;
156 cci::cci_param<std::string> p_tcg_mode;
157 cci::cci_param<std::string> p_sync_policy;
160 cci::cci_param<bool> p_icount;
161 cci::cci_param<int> p_icount_mips;
163 cci::cci_param<std::string> p_args;
164 bool p_display_argument_set;
166 cci::cci_param<std::string> p_accel;
168 void push_default_args()
170 const size_t l =
strlen(name()) + 1;
172 m_inst.push_qemu_arg(
"libqbox");
173 m_inst.push_qemu_arg({
180 const char* args =
"qemu_args.";
181 for (
auto p : m_conf_broker.get_unconsumed_preset_values([&](
const std::pair<std::string, cci::cci_value>&
iv) {
182 return iv.first.find(std::string(name()) +
"." + args) == 0;
184 if (
p.second.get_string().is_string()) {
186 const std::string
arg_value =
p.second.get_string();
190 SCP_FATAL(()) <<
"The value of the argument is not a string";
194 std::stringstream
ss_args(p_args);
197 m_inst.push_qemu_arg(
arg.c_str());
201 void push_icount_mode_args()
203 std::ostringstream
ss;
204 if (p_icount_mips > 0) {
208 p_icount_mips.lock();
209 if (!p_icount)
return;
210 if (m_tcg_mode == TCG_MULTI) {
211 SCP_FATAL(()) <<
"MULTI threading can not be used with icount";
212 assert(m_tcg_mode != TCG_MULTI);
214 m_inst.push_qemu_arg(
"-icount");
216 ss << p_icount_mips <<
",sleep=off";
217 m_inst.push_qemu_arg(
ss.str().c_str());
220 void push_tcg_mode_args()
222 switch (m_tcg_mode) {
224 m_inst.push_qemu_arg(
"tcg,thread=single");
228 m_inst.push_qemu_arg(
"tcg,thread=single,coroutine=on");
232 m_inst.push_qemu_arg(
"tcg,thread=multi");
234 SCP_FATAL(()) <<
"MULTI threading can not be used with icount";
244 void push_accelerator_args()
246 m_inst.push_qemu_arg(
"-accel");
248 auto&
accel = p_accel.get_value();
250 if (
accel ==
"tcg") {
251 push_tcg_mode_args();
252 }
else if (
accel ==
"hvf" ||
accel ==
"kvm") {
253 m_inst.push_qemu_arg(
accel.c_str());
268 Target strtotarget(std::string s)
270 if (s ==
"AARCH64") {
271 return QemuInstance::Target::AARCH64;
272 }
else if (s ==
"RISCV64") {
273 return QemuInstance::Target::RISCV64;
274 }
else if (s ==
"HEXAGON") {
275 return QemuInstance::Target::HEXAGON;
277 SCP_FATAL(()) <<
"Unable to find QEMU target container";
283 QemuInstance(
const sc_core::sc_module_name&
n, sc_core::sc_object*
o, std::string
arch)
292 : sc_core::sc_module(
n)
293 , m_conf_broker(cci::cci_get_broker())
297 , p_tcg_mode(
"tcg_mode",
"MULTI",
"The TCG mode required, SINGLE, COROUTINE or MULTI")
298 , p_sync_policy(
"sync_policy",
"multithread-quantum",
"Synchronization Policy to use")
299 , m_tcg_mode(StringToTcgMode(p_tcg_mode))
300 , p_icount(
"icount",
false,
"Enable virtual instruction counter")
301 , p_icount_mips(
"icount_mips_shift", 0,
"The MIPS shift value for icount mode (1 insn = 2^(mips) ns)")
302 , p_args(
"qemu_args",
"",
"additional space separated arguments")
303 , p_display_argument_set(
false)
304 , p_accel(
"accel",
"tcg",
"Virtualization accelerator")
306 SCP_DEBUG(()) <<
"Libqbox QemuInstance constructor";
308 auto resetcb = std::bind(&QemuInstance::reset_cb,
this, sc_unnamed::_1);
309 reset.register_value_changed_cb(
resetcb);
320 bool operator==(
const QemuInstance&
b)
const {
return this == &
b; }
322 bool operator!=(
const QemuInstance&
b)
const {
return this != &
b; }
338 p_display_argument_set =
true;
339 m_inst.push_qemu_arg(
"-display");
340 m_inst.push_qemu_arg(
arg);
351 bool is_kvm_enabled()
const {
return p_accel.get_value() ==
"kvm"; }
352 bool is_hvf_enabled()
const {
return p_accel.get_value() ==
"hvf"; }
353 bool is_tcg_enabled()
const {
return p_accel.get_value() ==
"tcg"; }
363 std::shared_ptr<gs::tlm_quantumkeeper_extended>
qk;
365 if (m_first_qk && m_tcg_mode != TCG_MULTI) {
368 qk = gs::tlm_quantumkeeper_factory(p_sync_policy);
370 if (!
qk)
SCP_FATAL(())(
"No quantum keeper found with name : {}", p_sync_policy.get_value());
371 if (!m_first_qk) m_first_qk =
qk;
372 if (
qk->get_thread_type() == gs::SyncPolicy::SYSTEMC_THREAD) {
373 assert(m_tcg_mode == TCG_COROUTINE);
376 p_sync_policy.lock();
393 if (m_tcg_mode == TCG_UNSPECIFIED) {
394 SCP_FATAL(()) <<
"Unknown tcg mode : " << std::string(p_tcg_mode);
398 if (m_first_qk->get_thread_type() == gs::SyncPolicy::SYSTEMC_THREAD) {
399 if (p_tcg_mode.is_preset_value() && m_tcg_mode != TCG_COROUTINE) {
400 SCP_WARN(()) <<
"This quantum keeper can only be used with TCG_COROUTINES";
402 m_tcg_mode = TCG_COROUTINE;
404 if (m_tcg_mode == TCG_COROUTINE) {
405 SCP_FATAL(()) <<
"Please select a suitable threading mode for this quantum "
406 "keeper, it can't be used with COROUTINES";
411 push_accelerator_args();
412 push_icount_mode_args();
414 if (!p_display_argument_set) {
415 m_inst.push_qemu_arg({
420 bool trace = (SCP_LOGGER_NAME().level >= sc_core::SC_FULL);
422 SCP_WARN(())(
"Enabling QEMU debug logging");
423 m_inst.push_qemu_arg({
"-d",
"in_asm,int,mmu,unimp,guest_errors" });
426 SCP_INFO(()) <<
"Initializing QEMU instance with args:";
428 for (
const char*
arg : m_inst.get_qemu_args()) {
466 int number_devices() {
return devices.size(); }
469 void start_of_simulation(
void) {
get().finish_qemu_init(); }
471 void reset_cb(
const bool val)
474 m_inst.system_reset();
480GSC_MODULE_REGISTER(
QemuInstance, sc_core::sc_object*, std::string);
Definition qemu-instance.h:33
Handles the DMI regions at the QEMU instance level.
Definition dmi-manager.h:47
QEMU instance manager class.
Definition qemu-instance.h:49
QemuInstanceManager(const sc_core::sc_module_name &n="QemuInstanceManager")
Construct a QemuInstanceManager. The manager will use the default library loader provided by libqemu-...
Definition qemu-instance.h:62
QemuInstanceManager(const sc_core::sc_module_name &n, LibLoader *loader)
Construct a QemuInstanceManager by providing a custom library loader.
Definition qemu-instance.h:72
This class encapsulates a libqemu-cxx qemu::LibQemu instance. It handles QEMU parameters and instance...
Definition qemu-instance.h:89
qemu::LibQemu & get()
Returns the underlying qemu::LibQemu instance.
Definition qemu-instance.h:448
TcgMode get_tcg_mode()
Get the TCG mode for this instance.
Definition qemu-instance.h:349
std::shared_ptr< gs::tlm_quantumkeeper_extended > create_quantum_keeper()
Get the TCG mode for this instance.
Definition qemu-instance.h:361
bool is_inited() const
Returns true if the instance is initialized.
Definition qemu-instance.h:439
void set_display_arg(const char *arg)
Add a the display command line argument to the qemu instance.
Definition qemu-instance.h:336
QemuInstanceDmiManager & get_dmi_manager()
Returns the locked QemuInstanceDmiManager instance.
Definition qemu-instance.h:464
void add_arg(const char *arg)
Add a command line argument to the qemu instance.
Definition qemu-instance.h:329
void init()
Initialize the QEMU instance.
Definition qemu-instance.h:389
Definition libqemu-cxx.h:92