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;
55 LibLoader& m_loader = qemu::get_default_lib_loader();
71 LibLoader& get_loader() {
return m_loader; }
88 std::shared_ptr<gs::tlm_quantumkeeper_extended> m_first_qk =
NULL;
90 std::list<QemuDeviceBaseIF*> devices;
91 cci::cci_broker_handle m_conf_broker;
93 bool m_running =
false;
100 std::mutex g_signaled_lock;
101 std::condition_variable g_signaled_cond;
102 bool g_signaled =
false;
103 std::recursive_mutex g_rec_qemu_io_lock;
107 std::lock_guard<std::mutex>
lock(m_lock);
108 devices.push_back(
d);
113 std::lock_guard<std::mutex>
lock(m_lock);
119 if (!m_running)
return false;
120 std::lock_guard<std::mutex>
lock(m_lock);
121 bool can_run =
false;
123 for (
auto const&
i : devices) {
131 using Target = qemu::Target;
140 TcgMode StringToTcgMode(std::string s)
142 if (s ==
"SINGLE")
return TCG_SINGLE;
143 if (s ==
"COROUTINE")
return TCG_COROUTINE;
144 if (s ==
"MULTI")
return TCG_MULTI;
145 SCP_WARN(()) <<
"Unknown TCG mode " << s;
146 return TCG_UNSPECIFIED;
153 cci::cci_param<std::string> p_tcg_mode;
154 cci::cci_param<std::string> p_sync_policy;
157 cci::cci_param<bool> p_icount;
158 cci::cci_param<int> p_icount_mips;
160 cci::cci_param<std::string> p_args;
161 std::string m_display_argument;
163 cci::cci_param<std::string> p_accel;
165 void push_default_args()
167 const size_t l =
strlen(name()) + 1;
169 m_inst.push_qemu_arg(
"libqbox");
170 m_inst.push_qemu_arg({
177 const char* args =
"qemu_args.";
178 for (
auto p : m_conf_broker.get_unconsumed_preset_values([&](
const std::pair<std::string, cci::cci_value>&
iv) {
179 return iv.first.find(std::string(name()) +
"." + args) == 0;
181 if (
p.second.get_string().is_string()) {
183 const std::string
arg_value =
p.second.get_string();
187 SCP_FATAL(()) <<
"The value of the argument is not a string";
191 std::stringstream
ss_args(p_args);
194 m_inst.push_qemu_arg(
arg.c_str());
198 void push_icount_mode_args()
200 std::ostringstream
ss;
201 if (p_icount_mips > 0) {
205 p_icount_mips.lock();
206 if (!p_icount)
return;
207 if (m_tcg_mode == TCG_MULTI) {
208 SCP_FATAL(()) <<
"MULTI threading can not be used with icount";
209 assert(m_tcg_mode != TCG_MULTI);
211 m_inst.push_qemu_arg(
"-icount");
213 ss << p_icount_mips <<
",sleep=off";
214 m_inst.push_qemu_arg(
ss.str().c_str());
217 void push_tcg_mode_args()
219 switch (m_tcg_mode) {
221 m_inst.push_qemu_arg(
"tcg,thread=single");
225 m_inst.push_qemu_arg(
"tcg,thread=single,coroutine=on");
229 m_inst.push_qemu_arg(
"tcg,thread=multi");
231 SCP_FATAL(()) <<
"MULTI threading can not be used with icount";
241 void push_accelerator_args()
243 m_inst.push_qemu_arg(
"-accel");
245 auto&
accel = p_accel.get_value();
247 if (
accel ==
"tcg") {
248 push_tcg_mode_args();
249 }
else if (
accel ==
"hvf" ||
accel ==
"kvm") {
250 m_inst.push_qemu_arg(
accel.c_str());
265 Target strtotarget(std::string s)
267 if (s ==
"AARCH64") {
268 return QemuInstance::Target::AARCH64;
269 }
else if (s ==
"RISCV64") {
270 return QemuInstance::Target::RISCV64;
271 }
else if (s ==
"RISCV32") {
272 return QemuInstance::Target::RISCV32;
273 }
else if (s ==
"HEXAGON") {
274 return QemuInstance::Target::HEXAGON;
276 SCP_FATAL(()) <<
"Unable to find QEMU target container";
282 QemuInstance(
const sc_core::sc_module_name&
n, sc_core::sc_object*
o, std::string
arch)
291 : sc_core::sc_module(
n)
292 , m_conf_broker(cci::cci_get_broker())
296 , p_tcg_mode(
"tcg_mode",
"MULTI",
"The TCG mode required, SINGLE, COROUTINE or MULTI")
297 , p_sync_policy(
"sync_policy",
"multithread-quantum",
"Synchronization Policy to use")
298 , m_tcg_mode(StringToTcgMode(p_tcg_mode))
299 , p_icount(
"icount",
false,
"Enable virtual instruction counter")
300 , p_icount_mips(
"icount_mips_shift", 0,
"The MIPS shift value for icount mode (1 insn = 2^(mips) ns)")
301 , p_args(
"qemu_args",
"",
"additional space separated arguments")
302 , p_accel(
"accel",
"tcg",
"Virtualization accelerator")
304 SCP_DEBUG(()) <<
"Libqbox QemuInstance constructor";
306 auto resetcb = std::bind(&QemuInstance::reset_cb,
this, sc_unnamed::_1);
307 reset.register_value_changed_cb(
resetcb);
318 bool operator==(
const QemuInstance&
b)
const {
return this == &
b; }
320 bool operator!=(
const QemuInstance&
b)
const {
return this != &
b; }
338 if (
arg == m_display_argument) {
343 if (!m_display_argument.empty()) {
344 SCP_FATAL(()) <<
"Display argument has already been set to '" << m_display_argument
345 <<
"' and cannot be changed to '" <<
arg
346 <<
"'. This may occur when mixed display modules are created (display/vnc).";
350 m_display_argument =
arg;
351 m_inst.push_qemu_arg(
"-display");
352 m_inst.push_qemu_arg(m_display_argument.c_str());
362 m_inst.push_qemu_arg(
"-vnc");
374 bool is_kvm_enabled()
const {
return p_accel.get_value() ==
"kvm"; }
375 bool is_hvf_enabled()
const {
return p_accel.get_value() ==
"hvf"; }
376 bool is_tcg_enabled()
const {
return p_accel.get_value() ==
"tcg"; }
386 std::shared_ptr<gs::tlm_quantumkeeper_extended>
qk;
388 if (m_first_qk && m_tcg_mode != TCG_MULTI) {
391 qk = gs::tlm_quantumkeeper_factory(p_sync_policy);
393 if (!
qk)
SCP_FATAL(())(
"No quantum keeper found with name : {}", p_sync_policy.get_value());
394 if (!m_first_qk) m_first_qk =
qk;
395 if (
qk->get_thread_type() == gs::SyncPolicy::SYSTEMC_THREAD) {
396 assert(m_tcg_mode == TCG_COROUTINE);
399 p_sync_policy.lock();
416 if (m_tcg_mode == TCG_UNSPECIFIED) {
417 SCP_FATAL(()) <<
"Unknown tcg mode : " << std::string(p_tcg_mode);
421 if (m_first_qk->get_thread_type() == gs::SyncPolicy::SYSTEMC_THREAD) {
422 if (p_tcg_mode.is_preset_value() && m_tcg_mode != TCG_COROUTINE) {
423 SCP_WARN(()) <<
"This quantum keeper can only be used with TCG_COROUTINES";
425 m_tcg_mode = TCG_COROUTINE;
427 if (m_tcg_mode == TCG_COROUTINE) {
428 SCP_FATAL(()) <<
"Please select a suitable threading mode for this quantum "
429 "keeper, it can't be used with COROUTINES";
434 push_accelerator_args();
435 push_icount_mode_args();
437 if (m_display_argument.empty()) {
438 m_inst.push_qemu_arg({
443 bool trace = (SCP_LOGGER_NAME().level >= sc_core::SC_FULL);
445 SCP_WARN(())(
"Enabling QEMU debug logging");
446 m_inst.push_qemu_arg({
"-d",
"in_asm,int,mmu,unimp,guest_errors" });
449 SCP_INFO(()) <<
"Initializing QEMU instance with args:";
451 for (
const char*
arg : m_inst.get_qemu_args()) {
489 int number_devices() {
return devices.size(); }
492 void start_of_simulation(
void) {
get().finish_qemu_init(); }
494 void reset_cb(
const bool val)
497 m_inst.system_reset();
503GSC_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:69
This class encapsulates a libqemu-cxx qemu::LibQemu instance. It handles QEMU parameters and instance...
Definition qemu-instance.h:86
void set_vnc_args(const std::string &vnc_options)
Add the VNC command line argument to the qemu instance.
Definition qemu-instance.h:360
qemu::LibQemu & get()
Returns the underlying qemu::LibQemu instance.
Definition qemu-instance.h:471
TcgMode get_tcg_mode()
Get the TCG mode for this instance.
Definition qemu-instance.h:372
std::shared_ptr< gs::tlm_quantumkeeper_extended > create_quantum_keeper()
Get the TCG mode for this instance.
Definition qemu-instance.h:384
void set_display_arg(const std::string &arg)
Add a the display command line argument to the qemu instance.
Definition qemu-instance.h:335
bool is_inited() const
Returns true if the instance is initialized.
Definition qemu-instance.h:462
QemuInstanceDmiManager & get_dmi_manager()
Returns the locked QemuInstanceDmiManager instance.
Definition qemu-instance.h:487
void add_arg(const char *arg)
Add a command line argument to the qemu instance.
Definition qemu-instance.h:327
void init()
Initialize the QEMU instance.
Definition qemu-instance.h:412
Definition libqemu-cxx.h:87