aboutsummaryrefslogtreecommitdiff
path: root/rust
diff options
context:
space:
mode:
Diffstat (limited to 'rust')
-rw-r--r--rust/Cargo.lock8
-rw-r--r--rust/Cargo.toml1
-rw-r--r--rust/hw/char/pl011/Cargo.toml1
-rw-r--r--rust/hw/char/pl011/meson.build1
-rw-r--r--rust/hw/char/pl011/src/device.rs57
-rw-r--r--rust/hw/core/src/qdev.rs33
-rw-r--r--rust/meson.build2
-rw-r--r--rust/trace/Cargo.toml19
-rw-r--r--rust/trace/meson.build19
-rw-r--r--rust/trace/src/lib.rs39
-rw-r--r--rust/util/src/log.rs2
11 files changed, 163 insertions, 19 deletions
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index 8315f98..444ef51 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -159,6 +159,7 @@ dependencies = [
"migration",
"qom",
"system",
+ "trace",
"util",
]
@@ -259,6 +260,13 @@ dependencies = [
]
[[package]]
+name = "trace"
+version = "0.1.0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index d8183c6..f372d7d 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -11,6 +11,7 @@ members = [
"hw/core",
"hw/char/pl011",
"hw/timer/hpet",
+ "trace",
"util",
"tests",
]
diff --git a/rust/hw/char/pl011/Cargo.toml b/rust/hw/char/pl011/Cargo.toml
index b2418ab..dc41d0e 100644
--- a/rust/hw/char/pl011/Cargo.toml
+++ b/rust/hw/char/pl011/Cargo.toml
@@ -24,6 +24,7 @@ qom = { path = "../../../qom" }
chardev = { path = "../../../chardev" }
system = { path = "../../../system" }
hwcore = { path = "../../../hw/core" }
+trace = { path = "../../../trace" }
[lints]
workspace = true
diff --git a/rust/hw/char/pl011/meson.build b/rust/hw/char/pl011/meson.build
index a33f329..07b3da1 100644
--- a/rust/hw/char/pl011/meson.build
+++ b/rust/hw/char/pl011/meson.build
@@ -40,6 +40,7 @@ _libpl011_rs = static_library(
chardev_rs,
system_rs,
hwcore_rs,
+ trace_rs
],
)
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
index 1b4587d..8889d6e 100644
--- a/rust/hw/char/pl011/src/device.rs
+++ b/rust/hw/char/pl011/src/device.rs
@@ -21,6 +21,8 @@ use util::{log::Log, log_mask_ln};
use crate::registers::{self, Interrupt, RegisterOffset};
+::trace::include_trace!("hw_char");
+
// TODO: You must disable the UART before any of the control registers are
// reprogrammed. When the UART is disabled in the middle of transmission or
// reception, it completes the current character before stopping
@@ -208,13 +210,7 @@ impl PL011Registers {
(update, result)
}
- pub(self) fn write(
- &mut self,
- offset: RegisterOffset,
- value: u32,
- char_backend: &CharBackend,
- ) -> bool {
- // eprintln!("write offset {offset} value {value}");
+ pub(self) fn write(&mut self, offset: RegisterOffset, value: u32, device: &PL011State) -> bool {
use RegisterOffset::*;
match offset {
DR => return self.write_data_register(value),
@@ -229,9 +225,11 @@ impl PL011Registers {
}
IBRD => {
self.ibrd = value;
+ device.trace_baudrate_change(self.ibrd, self.fbrd);
}
FBRD => {
self.fbrd = value;
+ device.trace_baudrate_change(self.ibrd, self.fbrd);
}
LCR_H => {
let new_val: registers::LineControl = value.into();
@@ -242,7 +240,7 @@ impl PL011Registers {
}
let update = (self.line_control.send_break() != new_val.send_break()) && {
let break_enable = new_val.send_break();
- let _ = char_backend.send_break(break_enable);
+ let _ = device.char_backend.send_break(break_enable);
self.loopback_break(break_enable)
};
self.line_control = new_val;
@@ -279,12 +277,13 @@ impl PL011Registers {
}
fn read_data_register(&mut self, update: &mut bool) -> u32 {
+ let depth = self.fifo_depth();
self.flags.set_receive_fifo_full(false);
let c = self.read_fifo[self.read_pos];
if self.read_count > 0 {
self.read_count -= 1;
- self.read_pos = (self.read_pos + 1) & (self.fifo_depth() - 1);
+ self.read_pos = (self.read_pos + 1) & (depth - 1);
}
if self.read_count == 0 {
self.flags.set_receive_fifo_empty(true);
@@ -292,6 +291,7 @@ impl PL011Registers {
if self.read_count + 1 == self.read_trigger {
self.int_level &= !Interrupt::RX;
}
+ trace::trace_pl011_read_fifo(self.read_count, depth);
self.receive_status_error_clear.set_from_data(c);
*update = true;
u32::from(c)
@@ -447,7 +447,9 @@ impl PL011Registers {
self.read_fifo[slot] = value;
self.read_count += 1;
self.flags.set_receive_fifo_empty(false);
+ trace::trace_pl011_fifo_rx_put(value.into(), self.read_count, depth);
if self.read_count == depth {
+ trace::trace_pl011_fifo_rx_full();
self.flags.set_receive_fifo_full(true);
}
@@ -516,8 +518,21 @@ impl PL011State {
uninit_field_mut!(*this, clock).write(clock);
}
- const fn clock_update(&self, _event: ClockEvent) {
- /* pl011_trace_baudrate_change(s); */
+ pub fn trace_baudrate_change(&self, ibrd: u32, fbrd: u32) {
+ let divider = 4.0 / f64::from(ibrd * (FBRD_MASK + 1) + fbrd);
+ let hz = self.clock.hz();
+ let rate = if ibrd == 0 {
+ 0
+ } else {
+ ((hz as f64) * divider) as u32
+ };
+ trace::trace_pl011_baudrate_change(rate, hz, ibrd, fbrd);
+ }
+
+ fn clock_update(&self, _event: ClockEvent) {
+ let regs = self.regs.borrow();
+ let (ibrd, fbrd) = (regs.ibrd, regs.fbrd);
+ self.trace_baudrate_change(ibrd, fbrd)
}
pub fn clock_needed(&self) -> bool {
@@ -543,6 +558,7 @@ impl PL011State {
}
Ok(field) => {
let (update_irq, result) = self.regs.borrow_mut().read(field);
+ trace::trace_pl011_read(offset, result, c"");
if update_irq {
self.update();
self.char_backend.accept_input();
@@ -557,6 +573,7 @@ impl PL011State {
if let Ok(field) = RegisterOffset::try_from(offset) {
// qemu_chr_fe_write_all() calls into the can_receive
// callback, so handle writes before entering PL011Registers.
+ trace::trace_pl011_write(offset, value as u32, c"");
if field == RegisterOffset::DR {
// ??? Check if transmitter is enabled.
let ch: [u8; 1] = [value as u8];
@@ -565,10 +582,7 @@ impl PL011State {
let _ = self.char_backend.write_all(&ch);
}
- update_irq = self
- .regs
- .borrow_mut()
- .write(field, value as u32, &self.char_backend);
+ update_irq = self.regs.borrow_mut().write(field, value as u32, self);
} else {
log_mask_ln!(
Log::GuestError,
@@ -582,11 +596,19 @@ impl PL011State {
fn can_receive(&self) -> u32 {
let regs = self.regs.borrow();
- // trace_pl011_can_receive(s->lcr, s->read_count, r);
- regs.fifo_depth() - regs.read_count
+ let fifo_available = regs.fifo_depth() - regs.read_count;
+ trace::trace_pl011_can_receive(
+ regs.line_control.into(),
+ regs.read_count,
+ regs.fifo_depth(),
+ fifo_available,
+ );
+ fifo_available
}
fn receive(&self, buf: &[u8]) {
+ trace::trace_pl011_receive(buf.len());
+
let mut regs = self.regs.borrow_mut();
if regs.loopback_enabled() {
// In loopback mode, the RX input signal is internally disconnected
@@ -635,6 +657,7 @@ impl PL011State {
fn update(&self) {
let regs = self.regs.borrow();
let flags = regs.int_level & regs.int_enabled;
+ trace::trace_pl011_irq_state(flags != 0);
for (irq, i) in self.interrupts.iter().zip(IRQMASK) {
irq.set(flags.any_set(i));
}
diff --git a/rust/hw/core/src/qdev.rs b/rust/hw/core/src/qdev.rs
index a4493db..c3097a2 100644
--- a/rust/hw/core/src/qdev.rs
+++ b/rust/hw/core/src/qdev.rs
@@ -411,6 +411,39 @@ where
impl<R: ObjectDeref> DeviceMethods for R where R::Target: IsA<DeviceState> {}
+impl Clock {
+ pub const PERIOD_1SEC: u64 = bindings::CLOCK_PERIOD_1SEC;
+
+ pub const fn period_from_ns(ns: u64) -> u64 {
+ ns * Self::PERIOD_1SEC / 1_000_000_000
+ }
+
+ pub const fn period_from_hz(hz: u64) -> u64 {
+ if hz == 0 {
+ 0
+ } else {
+ Self::PERIOD_1SEC / hz
+ }
+ }
+
+ pub const fn period_to_hz(period: u64) -> u64 {
+ if period == 0 {
+ 0
+ } else {
+ Self::PERIOD_1SEC / period
+ }
+ }
+
+ pub const fn period(&self) -> u64 {
+ // SAFETY: Clock is returned by init_clock_in with zero value for period
+ unsafe { &*self.0.as_ptr() }.period
+ }
+
+ pub const fn hz(&self) -> u64 {
+ Self::period_to_hz(self.period())
+ }
+}
+
unsafe impl ObjectType for Clock {
type Class = ObjectClass;
const TYPE_NAME: &'static CStr =
diff --git a/rust/meson.build b/rust/meson.build
index b3ac3a7..695d5a6 100644
--- a/rust/meson.build
+++ b/rust/meson.build
@@ -34,7 +34,7 @@ subdir('system')
subdir('chardev')
subdir('hw/core')
subdir('tests')
-
+subdir('trace')
subdir('hw')
cargo = find_program('cargo', required: false)
diff --git a/rust/trace/Cargo.toml b/rust/trace/Cargo.toml
new file mode 100644
index 0000000..fc81bce
--- /dev/null
+++ b/rust/trace/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "trace"
+version = "0.1.0"
+authors = ["Tanish Desai <tanishdesai37@gmail.com>"]
+description = "QEMU tracing infrastructure support"
+resolver = "2"
+publish = false
+
+edition.workspace = true
+homepage.workspace = true
+license.workspace = true
+repository.workspace = true
+rust-version.workspace = true
+
+[dependencies]
+libc = { workspace = true }
+
+[lints]
+workspace = true
diff --git a/rust/trace/meson.build b/rust/trace/meson.build
new file mode 100644
index 0000000..adca57e
--- /dev/null
+++ b/rust/trace/meson.build
@@ -0,0 +1,19 @@
+rust = import('rust')
+
+lib_rs = configure_file(
+ input: 'src/lib.rs',
+ output: 'lib.rs',
+ configuration: {
+ 'MESON_BUILD_ROOT': meson.project_build_root(),
+ })
+
+_trace_rs = static_library(
+ 'trace', # Library name,
+ lib_rs,
+ trace_rs_targets, # List of generated `.rs` custom targets
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ dependencies: [libc_rs],
+ rust_abi: 'rust',
+)
+
+trace_rs = declare_dependency(link_with: _trace_rs)
diff --git a/rust/trace/src/lib.rs b/rust/trace/src/lib.rs
new file mode 100644
index 0000000..e03bce4
--- /dev/null
+++ b/rust/trace/src/lib.rs
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//! This crate provides macros that aid in using QEMU's tracepoint
+//! functionality.
+
+#[doc(hidden)]
+/// Re-exported item to avoid adding libc as a dependency everywhere.
+pub use libc::{syslog, LOG_INFO};
+
+#[macro_export]
+/// Define the trace-points from the named directory (which should have slashes
+/// replaced by underscore characters) as functions in a module called `trace`.
+///
+/// ```ignore
+/// ::trace::include_trace!("hw_char");
+/// // ...
+/// trace::trace_pl011_read_fifo_rx_full();
+/// ```
+macro_rules! include_trace {
+ ($name:literal) => {
+ #[allow(
+ clippy::ptr_as_ptr,
+ clippy::cast_lossless,
+ clippy::used_underscore_binding
+ )]
+ mod trace {
+ #[cfg(not(MESON))]
+ include!(concat!(
+ env!("MESON_BUILD_ROOT"),
+ "/trace/trace-",
+ $name,
+ ".rs"
+ ));
+
+ #[cfg(MESON)]
+ include!(concat!("@MESON_BUILD_ROOT@/trace/trace-", $name, ".rs"));
+ }
+ };
+}
diff --git a/rust/util/src/log.rs b/rust/util/src/log.rs
index af9a3e9..0a4bc42 100644
--- a/rust/util/src/log.rs
+++ b/rust/util/src/log.rs
@@ -142,7 +142,7 @@ macro_rules! log_mask_ln {
let _: $crate::log::Log = $mask;
if unsafe {
- ($crate::bindings::qemu_loglevel & ($mask as std::os::raw::c_int)) != 0
+ ($crate::bindings::qemu_loglevel & ($mask as std::os::raw::c_uint)) != 0
} {
_ = $crate::log::LogGuard::log_fmt(
format_args!("{}\n", format_args!($fmt $($args)*)));