1use crate::rtt::Error;
2use crate::{Core, MemoryInterface};
3use probe_rs_target::RegionMergeIterator;
4use std::cmp::min;
5use std::ffi::CStr;
6use std::num::NonZeroU64;
7use zerocopy::{FromBytes, Immutable, KnownLayout};
8
9pub trait RttChannel {
11 fn number(&self) -> usize;
13
14 fn name(&self) -> Option<&str>;
16
17 fn buffer_size(&self) -> usize;
20}
21
22#[repr(C)]
23#[derive(Debug, FromBytes, Immutable, KnownLayout, Clone)]
24pub(crate) struct RttChannelBufferInner<T> {
25 standard_name_pointer: T,
26 buffer_start_pointer: T,
27 size_of_buffer: T,
28 write_offset: T,
29 read_offset: T,
30 flags: T,
31}
32
33impl<T> RttChannelBufferInner<T> {
34 pub fn write_buffer_ptr_offset(&self) -> usize {
35 std::mem::offset_of!(RttChannelBufferInner<T>, write_offset)
36 }
37
38 pub fn read_buffer_ptr_offset(&self) -> usize {
39 std::mem::offset_of!(RttChannelBufferInner<T>, read_offset)
40 }
41
42 pub fn flags_offset(&self) -> usize {
43 std::mem::offset_of!(RttChannelBufferInner<T>, flags)
44 }
45
46 pub fn size() -> usize {
47 std::mem::size_of::<RttChannelBufferInner<T>>()
48 }
49}
50
51#[derive(Debug, Clone)]
52pub(crate) enum RttChannelBuffer {
53 Buffer32(RttChannelBufferInner<u32>),
54 Buffer64(RttChannelBufferInner<u64>),
55}
56
57impl RttChannelBuffer {
58 pub fn size(&self) -> usize {
59 match self {
60 RttChannelBuffer::Buffer32(_) => RttChannelBufferInner::<u32>::size(),
61 RttChannelBuffer::Buffer64(_) => RttChannelBufferInner::<u64>::size(),
62 }
63 }
64}
65
66impl From<RttChannelBufferInner<u32>> for RttChannelBuffer {
67 fn from(value: RttChannelBufferInner<u32>) -> Self {
68 RttChannelBuffer::Buffer32(value)
69 }
70}
71
72impl From<RttChannelBufferInner<u64>> for RttChannelBuffer {
73 fn from(value: RttChannelBufferInner<u64>) -> Self {
74 RttChannelBuffer::Buffer64(value)
75 }
76}
77
78impl RttChannelBuffer {
79 pub fn buffer_start_pointer(&self) -> u64 {
80 match self {
81 RttChannelBuffer::Buffer32(x) => u64::from(x.buffer_start_pointer),
82 RttChannelBuffer::Buffer64(x) => x.buffer_start_pointer,
83 }
84 }
85
86 pub fn standard_name_pointer(&self) -> Option<NonZeroU64> {
87 match self {
88 RttChannelBuffer::Buffer32(x) => NonZeroU64::new(u64::from(x.standard_name_pointer)),
89 RttChannelBuffer::Buffer64(x) => NonZeroU64::new(x.standard_name_pointer),
90 }
91 }
92
93 pub fn size_of_buffer(&self) -> u64 {
94 match self {
95 RttChannelBuffer::Buffer32(x) => u64::from(x.size_of_buffer),
96 RttChannelBuffer::Buffer64(x) => x.size_of_buffer,
97 }
98 }
99
100 pub fn read_buffer_offsets(&self, core: &mut Core, ptr: u64) -> Result<(u64, u64), Error> {
102 Ok(match self {
103 RttChannelBuffer::Buffer32(h32) => {
104 let mut block = [0u32; 2];
105 core.read_32(ptr + h32.write_buffer_ptr_offset() as u64, block.as_mut())?;
106 (u64::from(block[0]), u64::from(block[1]))
107 }
108 RttChannelBuffer::Buffer64(h64) => {
109 let mut block = [0u64; 2];
110 core.read_64(ptr + h64.write_buffer_ptr_offset() as u64, block.as_mut())?;
111 (block[0], block[1])
112 }
113 })
114 }
115
116 pub fn write_write_buffer_ptr(
117 &self,
118 core: &mut Core,
119 ptr: u64,
120 buffer_ptr: u64,
121 ) -> Result<(), Error> {
122 match self {
123 RttChannelBuffer::Buffer32(h32) => {
124 core.write_word_32(
125 ptr + h32.write_buffer_ptr_offset() as u64,
126 buffer_ptr.try_into().unwrap(),
127 )?;
128 }
129 RttChannelBuffer::Buffer64(h64) => {
130 core.write_word_64(ptr + h64.write_buffer_ptr_offset() as u64, buffer_ptr)?;
131 }
132 };
133 Ok(())
134 }
135
136 pub fn write_read_buffer_ptr(
137 &self,
138 core: &mut Core,
139 ptr: u64,
140 buffer_ptr: u64,
141 ) -> Result<(), Error> {
142 match self {
143 RttChannelBuffer::Buffer32(h32) => {
144 core.write_word_32(
145 ptr + h32.read_buffer_ptr_offset() as u64,
146 buffer_ptr.try_into().unwrap(),
147 )?;
148 }
149 RttChannelBuffer::Buffer64(h64) => {
150 core.write_word_64(ptr + h64.read_buffer_ptr_offset() as u64, buffer_ptr)?;
151 }
152 };
153 Ok(())
154 }
155
156 pub fn read_flags(&self, core: &mut Core, ptr: u64) -> Result<u64, Error> {
157 Ok(match self {
158 RttChannelBuffer::Buffer32(h32) => {
159 u64::from(core.read_word_32(ptr + h32.flags_offset() as u64)?)
160 }
161 RttChannelBuffer::Buffer64(h64) => {
162 core.read_word_64(ptr + h64.flags_offset() as u64)?
163 }
164 })
165 }
166
167 pub fn write_flags(&self, core: &mut Core, ptr: u64, flags: u64) -> Result<(), Error> {
168 match self {
169 RttChannelBuffer::Buffer32(h32) => {
170 core.write_word_32(ptr + h32.flags_offset() as u64, flags.try_into().unwrap())?;
171 }
172 RttChannelBuffer::Buffer64(h64) => {
173 core.write_word_64(ptr + h64.flags_offset() as u64, flags)?;
174 }
175 };
176 Ok(())
177 }
178}
179
180#[derive(Debug)]
181pub(crate) struct Channel {
182 number: usize,
183 core_id: usize,
184 name: Option<String>,
185 metadata_ptr: u64,
186 info: RttChannelBuffer,
187 last_read_ptr: Option<u64>,
188}
189
190impl Channel {
204 pub(crate) fn from(
205 core: &mut Core,
206 number: usize,
207 metadata_ptr: u64,
208 info: RttChannelBuffer,
209 ) -> Result<Option<Channel>, Error> {
210 let buffer_ptr = info.buffer_start_pointer();
211 if buffer_ptr == 0 {
212 return Ok(None);
214 };
215
216 let mut this = Channel {
217 number,
218 core_id: core.id(),
219 metadata_ptr,
220 name: None,
221 info,
222 last_read_ptr: None,
223 };
224
225 this.read_pointers(core, "")?;
229 this.name = if let Some(ptr) = this.info.standard_name_pointer() {
231 read_c_string(core, ptr)?
232 } else {
233 None
234 };
235 this.mode(core)?;
236
237 Ok(Some(this))
238 }
239
240 pub(crate) fn validate_core_id(&self, core: &mut Core) -> Result<(), Error> {
242 if core.id() != self.core_id {
243 return Err(Error::IncorrectCoreSpecified(self.core_id, core.id()));
244 }
245
246 Ok(())
247 }
248
249 pub fn name(&self) -> Option<&str> {
250 self.name.as_deref()
251 }
252
253 pub fn buffer_size(&self) -> usize {
254 self.info.size_of_buffer() as usize
255 }
256
257 pub fn mode(&self, core: &mut Core) -> Result<ChannelMode, Error> {
261 self.validate_core_id(core)?;
262 let flags = self.info.read_flags(core, self.metadata_ptr)?;
263
264 ChannelMode::try_from(flags & ChannelMode::MASK)
265 }
266
267 pub fn set_mode(&self, core: &mut Core, mode: ChannelMode) -> Result<(), Error> {
271 tracing::debug!("Setting RTT channel {} mode to {:?}", self.number, mode);
272 self.validate_core_id(core)?;
273 let flags = self.info.read_flags(core, self.metadata_ptr)?;
274
275 let new_flags = ChannelMode::set(mode, flags);
276 self.info.write_flags(core, self.metadata_ptr, new_flags)?;
277
278 Ok(())
279 }
280
281 fn read_pointers(&self, core: &mut Core, channel_kind: &str) -> Result<(u64, u64), Error> {
282 self.validate_core_id(core)?;
283
284 let (write, read) = self.info.read_buffer_offsets(core, self.metadata_ptr)?;
285
286 let validate = |which, value| {
288 let buffer_offset_larger_than_size_of_buffer = value >= self.info.size_of_buffer();
289
290 if buffer_offset_larger_than_size_of_buffer {
291 return Err(Error::ControlBlockCorrupted(format!(
292 "{which} pointer is {value:#010x} while buffer size is {:#010x} for {channel_kind}channel {} ({})",
293 self.info.size_of_buffer(),
294 self.number,
295 self.name().unwrap_or("no name"),
296 )));
297 }
298
299 let buffer_fully_in_memory_region = core
300 .target()
301 .memory_map
302 .iter()
303 .filter_map(|mr| mr.as_ram_region())
304 .merge_consecutive()
305 .any(|rr| {
306 let start = self.info.buffer_start_pointer();
307 let end = self.info.buffer_start_pointer() + self.info.size_of_buffer();
308
309 rr.range.contains(&start) && end <= rr.range.end
313 });
314
315 if !buffer_fully_in_memory_region {
316 return Err(Error::ControlBlockCorrupted(format!(
317 "the {which} buffer doesn't fully fit in any known (consecutive) ram region according to its own pointers: (start_pointer: {:#X}, size: {})",
318 self.info.buffer_start_pointer(),
319 self.info.size_of_buffer(),
320 )));
321 }
322
323 Ok(())
324 };
325
326 validate("write", write)?;
327 validate("read", read)?;
328
329 Ok((write, read))
330 }
331}
332
333#[derive(Debug)]
335pub struct UpChannel(pub(crate) Channel);
336
337impl UpChannel {
338 pub fn number(&self) -> usize {
340 self.0.number
341 }
342
343 pub fn name(&self) -> Option<&str> {
345 self.0.name()
346 }
347
348 pub fn buffer_size(&self) -> usize {
351 self.0.buffer_size()
352 }
353
354 pub fn mode(&self, core: &mut Core) -> Result<ChannelMode, Error> {
358 self.0.mode(core)
359 }
360
361 pub fn set_mode(&self, core: &mut Core, mode: ChannelMode) -> Result<(), Error> {
365 self.0.set_mode(core, mode)
366 }
367
368 fn read_core(&mut self, core: &mut Core, mut buf: &mut [u8]) -> Result<(u64, usize), Error> {
369 let (write, mut read) = self.0.read_pointers(core, "up ")?;
370
371 let mut total = 0;
372
373 if let Some(ptr) = self.0.last_read_ptr {
374 if read != ptr {
376 return Err(Error::ReadPointerChanged);
377 }
378 }
379
380 while !buf.is_empty() {
382 let count = min(self.readable_contiguous(write, read), buf.len());
383 if count == 0 {
384 break;
385 }
386
387 core.read(self.0.info.buffer_start_pointer() + read, &mut buf[..count])?;
388
389 total += count;
390 read += count as u64;
391
392 if read >= self.0.info.size_of_buffer() {
393 read = 0;
395 }
396
397 buf = &mut buf[count..];
398 }
399 self.0.last_read_ptr = Some(read);
400
401 Ok((read, total))
402 }
403
404 pub fn read(&mut self, core: &mut Core, buf: &mut [u8]) -> Result<usize, Error> {
410 let (read, total) = self.read_core(core, buf)?;
411
412 if total > 0 {
413 self.0
415 .info
416 .write_read_buffer_ptr(core, self.0.metadata_ptr, read)?;
417 }
418
419 Ok(total)
420 }
421
422 pub fn peek(&mut self, core: &mut Core, buf: &mut [u8]) -> Result<usize, Error> {
428 Ok(self.read_core(core, buf)?.1)
429 }
430
431 fn readable_contiguous(&self, write: u64, read: u64) -> usize {
433 let end = if read > write {
434 self.0.info.size_of_buffer()
435 } else {
436 write
437 };
438
439 (end - read) as usize
440 }
441}
442
443impl RttChannel for UpChannel {
444 fn number(&self) -> usize {
446 self.0.number
447 }
448
449 fn name(&self) -> Option<&str> {
450 self.0.name()
451 }
452
453 fn buffer_size(&self) -> usize {
454 self.0.buffer_size()
455 }
456}
457
458#[derive(Debug)]
460pub struct DownChannel(pub(crate) Channel);
461
462impl DownChannel {
463 pub fn number(&self) -> usize {
465 self.0.number
466 }
467
468 pub fn name(&self) -> Option<&str> {
470 self.0.name()
471 }
472
473 pub fn buffer_size(&self) -> usize {
476 self.0.buffer_size()
477 }
478
479 pub fn write(&mut self, core: &mut Core, mut buf: &[u8]) -> Result<usize, Error> {
484 let (mut write, read) = self.0.read_pointers(core, "down ")?;
485
486 let mut total = 0;
487
488 while !buf.is_empty() {
490 let count = min(self.writable_contiguous(write, read), buf.len());
491 if count == 0 {
492 break;
493 }
494
495 core.write(self.0.info.buffer_start_pointer() + write, &buf[..count])?;
496
497 total += count;
498 write += count as u64;
499
500 if write >= self.0.info.size_of_buffer() {
501 write = 0;
503 }
504
505 buf = &buf[count..];
506 }
507
508 self.0
510 .info
511 .write_write_buffer_ptr(core, self.0.metadata_ptr, write)?;
512
513 Ok(total)
514 }
515
516 fn writable_contiguous(&self, write: u64, read: u64) -> usize {
518 (if read > write {
519 read - write - 1
520 } else if read == 0 {
521 self.0.info.size_of_buffer() - write - 1
522 } else {
523 self.0.info.size_of_buffer() - write
524 }) as usize
525 }
526}
527
528impl RttChannel for DownChannel {
529 fn number(&self) -> usize {
531 self.0.number
532 }
533
534 fn name(&self) -> Option<&str> {
535 self.0.name()
536 }
537
538 fn buffer_size(&self) -> usize {
539 self.0.buffer_size()
540 }
541}
542
543fn read_c_string(core: &mut Core, ptr: NonZeroU64) -> Result<Option<String>, Error> {
545 let ptr = ptr.get();
546 let Some(range) = core
547 .memory_regions()
548 .filter(|r| r.is_ram() || r.is_nvm())
549 .find_map(|r| r.contains(ptr).then_some(r.address_range()))
550 else {
551 return Err(Error::ControlBlockCorrupted(format!(
552 "The channel name pointer is not in a valid memory region: {ptr:#X}"
553 )));
554 };
555
556 let mut bytes = vec![0u8; min(128, (range.end - ptr) as usize)];
558 core.read(ptr, bytes.as_mut())?;
559
560 let return_value = CStr::from_bytes_until_nul(&bytes)
562 .map(|s| s.to_string_lossy().into_owned())
563 .ok();
564
565 tracing::trace!("read_c_string() result = {:?}", return_value);
566 Ok(return_value)
567}
568
569#[derive(Clone, Copy, Eq, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
572#[repr(u32)]
573pub enum ChannelMode {
574 NoBlockSkip = 0,
576
577 NoBlockTrim = 1,
579
580 BlockIfFull = 2,
584}
585
586impl ChannelMode {
587 const MASK: u64 = 0x3;
588
589 fn set(self, flags: u64) -> u64 {
590 (flags & !Self::MASK) | (self as u64)
591 }
592}
593
594impl TryFrom<u64> for ChannelMode {
595 type Error = Error;
596
597 fn try_from(value: u64) -> Result<Self, Self::Error> {
598 match value {
599 0 => Ok(ChannelMode::NoBlockSkip),
600 1 => Ok(ChannelMode::NoBlockTrim),
601 2 => Ok(ChannelMode::BlockIfFull),
602 _ => Err(Error::ControlBlockCorrupted(format!(
603 "The channel mode flags are invalid: {value}"
604 ))),
605 }
606 }
607}