1 // Copyright 2024, Linaro Limited
2 // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4
5 use std::{
6 ffi::{c_int, c_void, CStr},
7 mem::size_of,
8 ptr::NonNull,
9 };
10
11 use qemu_api::{
12 bindings::{qdev_prop_bool, qdev_prop_chr},
13 chardev::{CharBackend, Chardev, Event},
14 impl_vmstate_forward,
15 irq::{IRQState, InterruptSource},
16 log::Log,
17 log_mask_ln,
18 memory::{hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder},
19 prelude::*,
20 qdev::{Clock, ClockEvent, DeviceImpl, DeviceState, Property, ResetType, ResettablePhasesImpl},
21 qom::{ObjectImpl, Owned, ParentField, ParentInit},
22 static_assert,
23 sysbus::{SysBusDevice, SysBusDeviceImpl},
24 uninit_field_mut,
25 vmstate::VMStateDescription,
26 vmstate_clock, vmstate_fields, vmstate_of, vmstate_struct, vmstate_subsections, vmstate_unused,
27 zeroable::Zeroable,
28 };
29
30 use crate::registers::{self, Interrupt, RegisterOffset};
31
32 // TODO: You must disable the UART before any of the control registers are
33 // reprogrammed. When the UART is disabled in the middle of transmission or
34 // reception, it completes the current character before stopping
35
36 /// Integer Baud Rate Divider, `UARTIBRD`
37 const IBRD_MASK: u32 = 0xffff;
38
39 /// Fractional Baud Rate Divider, `UARTFBRD`
40 const FBRD_MASK: u32 = 0x3f;
41
42 /// QEMU sourced constant.
43 pub const PL011_FIFO_DEPTH: u32 = 16;
44
45 #[derive(Clone, Copy)]
46 struct DeviceId(&'static [u8; 8]);
47
48 impl std::ops::Index<hwaddr> for DeviceId {
49 type Output = u8;
50
index(&self, idx: hwaddr) -> &Self::Output51 fn index(&self, idx: hwaddr) -> &Self::Output {
52 &self.0[idx as usize]
53 }
54 }
55
56 // FIFOs use 32-bit indices instead of usize, for compatibility with
57 // the migration stream produced by the C version of this device.
58 #[repr(transparent)]
59 #[derive(Debug, Default)]
60 pub struct Fifo([registers::Data; PL011_FIFO_DEPTH as usize]);
61 impl_vmstate_forward!(Fifo);
62
63 impl Fifo {
len(&self) -> u3264 const fn len(&self) -> u32 {
65 self.0.len() as u32
66 }
67 }
68
69 impl std::ops::IndexMut<u32> for Fifo {
index_mut(&mut self, idx: u32) -> &mut Self::Output70 fn index_mut(&mut self, idx: u32) -> &mut Self::Output {
71 &mut self.0[idx as usize]
72 }
73 }
74
75 impl std::ops::Index<u32> for Fifo {
76 type Output = registers::Data;
77
index(&self, idx: u32) -> &Self::Output78 fn index(&self, idx: u32) -> &Self::Output {
79 &self.0[idx as usize]
80 }
81 }
82
83 #[repr(C)]
84 #[derive(Debug, Default)]
85 pub struct PL011Registers {
86 #[doc(alias = "fr")]
87 pub flags: registers::Flags,
88 #[doc(alias = "lcr")]
89 pub line_control: registers::LineControl,
90 #[doc(alias = "rsr")]
91 pub receive_status_error_clear: registers::ReceiveStatusErrorClear,
92 #[doc(alias = "cr")]
93 pub control: registers::Control,
94 pub dmacr: u32,
95 pub int_enabled: Interrupt,
96 pub int_level: Interrupt,
97 pub read_fifo: Fifo,
98 pub ilpr: u32,
99 pub ibrd: u32,
100 pub fbrd: u32,
101 pub ifl: u32,
102 pub read_pos: u32,
103 pub read_count: u32,
104 pub read_trigger: u32,
105 }
106
107 #[repr(C)]
108 #[derive(qemu_api_macros::Object)]
109 /// PL011 Device Model in QEMU
110 pub struct PL011State {
111 pub parent_obj: ParentField<SysBusDevice>,
112 pub iomem: MemoryRegion,
113 #[doc(alias = "chr")]
114 pub char_backend: CharBackend,
115 pub regs: BqlRefCell<PL011Registers>,
116 /// QEMU interrupts
117 ///
118 /// ```text
119 /// * sysbus MMIO region 0: device registers
120 /// * sysbus IRQ 0: `UARTINTR` (combined interrupt line)
121 /// * sysbus IRQ 1: `UARTRXINTR` (receive FIFO interrupt line)
122 /// * sysbus IRQ 2: `UARTTXINTR` (transmit FIFO interrupt line)
123 /// * sysbus IRQ 3: `UARTRTINTR` (receive timeout interrupt line)
124 /// * sysbus IRQ 4: `UARTMSINTR` (momem status interrupt line)
125 /// * sysbus IRQ 5: `UARTEINTR` (error interrupt line)
126 /// ```
127 #[doc(alias = "irq")]
128 pub interrupts: [InterruptSource; IRQMASK.len()],
129 #[doc(alias = "clk")]
130 pub clock: Owned<Clock>,
131 #[doc(alias = "migrate_clk")]
132 pub migrate_clock: bool,
133 }
134
135 // Some C users of this device embed its state struct into their own
136 // structs, so the size of the Rust version must not be any larger
137 // than the size of the C one. If this assert triggers you need to
138 // expand the padding_for_rust[] array in the C PL011State struct.
139 static_assert!(size_of::<PL011State>() <= size_of::<qemu_api::bindings::PL011State>());
140
141 qom_isa!(PL011State : SysBusDevice, DeviceState, Object);
142
143 #[repr(C)]
144 pub struct PL011Class {
145 parent_class: <SysBusDevice as ObjectType>::Class,
146 /// The byte string that identifies the device.
147 device_id: DeviceId,
148 }
149
150 trait PL011Impl: SysBusDeviceImpl + IsA<PL011State> {
151 const DEVICE_ID: DeviceId;
152 }
153
154 impl PL011Class {
class_init<T: PL011Impl>(&mut self)155 fn class_init<T: PL011Impl>(&mut self) {
156 self.device_id = T::DEVICE_ID;
157 self.parent_class.class_init::<T>();
158 }
159 }
160
161 unsafe impl ObjectType for PL011State {
162 type Class = PL011Class;
163 const TYPE_NAME: &'static CStr = crate::TYPE_PL011;
164 }
165
166 impl PL011Impl for PL011State {
167 const DEVICE_ID: DeviceId = DeviceId(&[0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1]);
168 }
169
170 impl ObjectImpl for PL011State {
171 type ParentType = SysBusDevice;
172
173 const INSTANCE_INIT: Option<unsafe fn(ParentInit<Self>)> = Some(Self::init);
174 const INSTANCE_POST_INIT: Option<fn(&Self)> = Some(Self::post_init);
175 const CLASS_INIT: fn(&mut Self::Class) = Self::Class::class_init::<Self>;
176 }
177
178 impl DeviceImpl for PL011State {
properties() -> &'static [Property]179 fn properties() -> &'static [Property] {
180 &PL011_PROPERTIES
181 }
vmsd() -> Option<&'static VMStateDescription>182 fn vmsd() -> Option<&'static VMStateDescription> {
183 Some(&VMSTATE_PL011)
184 }
185 const REALIZE: Option<fn(&Self) -> qemu_api::Result<()>> = Some(Self::realize);
186 }
187
188 impl ResettablePhasesImpl for PL011State {
189 const HOLD: Option<fn(&Self, ResetType)> = Some(Self::reset_hold);
190 }
191
192 impl SysBusDeviceImpl for PL011State {}
193
194 impl PL011Registers {
read(&mut self, offset: RegisterOffset) -> (bool, u32)195 pub(self) fn read(&mut self, offset: RegisterOffset) -> (bool, u32) {
196 use RegisterOffset::*;
197
198 let mut update = false;
199 let result = match offset {
200 DR => self.read_data_register(&mut update),
201 RSR => u32::from(self.receive_status_error_clear),
202 FR => u32::from(self.flags),
203 FBRD => self.fbrd,
204 ILPR => self.ilpr,
205 IBRD => self.ibrd,
206 LCR_H => u32::from(self.line_control),
207 CR => u32::from(self.control),
208 FLS => self.ifl,
209 IMSC => u32::from(self.int_enabled),
210 RIS => u32::from(self.int_level),
211 MIS => u32::from(self.int_level & self.int_enabled),
212 ICR => {
213 // "The UARTICR Register is the interrupt clear register and is write-only"
214 // Source: ARM DDI 0183G 3.3.13 Interrupt Clear Register, UARTICR
215 0
216 }
217 DMACR => self.dmacr,
218 };
219 (update, result)
220 }
221
write( &mut self, offset: RegisterOffset, value: u32, char_backend: &CharBackend, ) -> bool222 pub(self) fn write(
223 &mut self,
224 offset: RegisterOffset,
225 value: u32,
226 char_backend: &CharBackend,
227 ) -> bool {
228 // eprintln!("write offset {offset} value {value}");
229 use RegisterOffset::*;
230 match offset {
231 DR => return self.write_data_register(value),
232 RSR => {
233 self.receive_status_error_clear = 0.into();
234 }
235 FR => {
236 // flag writes are ignored
237 }
238 ILPR => {
239 self.ilpr = value;
240 }
241 IBRD => {
242 self.ibrd = value;
243 }
244 FBRD => {
245 self.fbrd = value;
246 }
247 LCR_H => {
248 let new_val: registers::LineControl = value.into();
249 // Reset the FIFO state on FIFO enable or disable
250 if self.line_control.fifos_enabled() != new_val.fifos_enabled() {
251 self.reset_rx_fifo();
252 self.reset_tx_fifo();
253 }
254 let update = (self.line_control.send_break() != new_val.send_break()) && {
255 let break_enable = new_val.send_break();
256 let _ = char_backend.send_break(break_enable);
257 self.loopback_break(break_enable)
258 };
259 self.line_control = new_val;
260 self.set_read_trigger();
261 return update;
262 }
263 CR => {
264 // ??? Need to implement the enable bit.
265 self.control = value.into();
266 return self.loopback_mdmctrl();
267 }
268 FLS => {
269 self.ifl = value;
270 self.set_read_trigger();
271 }
272 IMSC => {
273 self.int_enabled = Interrupt::from(value);
274 return true;
275 }
276 RIS => {}
277 MIS => {}
278 ICR => {
279 self.int_level &= !Interrupt::from(value);
280 return true;
281 }
282 DMACR => {
283 self.dmacr = value;
284 if value & 3 > 0 {
285 log_mask_ln!(Log::Unimp, "pl011: DMA not implemented");
286 }
287 }
288 }
289 false
290 }
291
read_data_register(&mut self, update: &mut bool) -> u32292 fn read_data_register(&mut self, update: &mut bool) -> u32 {
293 self.flags.set_receive_fifo_full(false);
294 let c = self.read_fifo[self.read_pos];
295
296 if self.read_count > 0 {
297 self.read_count -= 1;
298 self.read_pos = (self.read_pos + 1) & (self.fifo_depth() - 1);
299 }
300 if self.read_count == 0 {
301 self.flags.set_receive_fifo_empty(true);
302 }
303 if self.read_count + 1 == self.read_trigger {
304 self.int_level &= !Interrupt::RX;
305 }
306 self.receive_status_error_clear.set_from_data(c);
307 *update = true;
308 u32::from(c)
309 }
310
write_data_register(&mut self, value: u32) -> bool311 fn write_data_register(&mut self, value: u32) -> bool {
312 if !self.control.enable_uart() {
313 log_mask_ln!(Log::GuestError, "PL011 data written to disabled UART");
314 }
315 if !self.control.enable_transmit() {
316 log_mask_ln!(Log::GuestError, "PL011 data written to disabled TX UART");
317 }
318 // interrupts always checked
319 let _ = self.loopback_tx(value.into());
320 self.int_level |= Interrupt::TX;
321 true
322 }
323
324 #[inline]
325 #[must_use]
loopback_tx(&mut self, value: registers::Data) -> bool326 fn loopback_tx(&mut self, value: registers::Data) -> bool {
327 // Caveat:
328 //
329 // In real hardware, TX loopback happens at the serial-bit level
330 // and then reassembled by the RX logics back into bytes and placed
331 // into the RX fifo. That is, loopback happens after TX fifo.
332 //
333 // Because the real hardware TX fifo is time-drained at the frame
334 // rate governed by the configured serial format, some loopback
335 // bytes in TX fifo may still be able to get into the RX fifo
336 // that could be full at times while being drained at software
337 // pace.
338 //
339 // In such scenario, the RX draining pace is the major factor
340 // deciding which loopback bytes get into the RX fifo, unless
341 // hardware flow-control is enabled.
342 //
343 // For simplicity, the above described is not emulated.
344 self.loopback_enabled() && self.fifo_rx_put(value)
345 }
346
347 #[must_use]
loopback_mdmctrl(&mut self) -> bool348 fn loopback_mdmctrl(&mut self) -> bool {
349 if !self.loopback_enabled() {
350 return false;
351 }
352
353 /*
354 * Loopback software-driven modem control outputs to modem status inputs:
355 * FR.RI <= CR.Out2
356 * FR.DCD <= CR.Out1
357 * FR.CTS <= CR.RTS
358 * FR.DSR <= CR.DTR
359 *
360 * The loopback happens immediately even if this call is triggered
361 * by setting only CR.LBE.
362 *
363 * CTS/RTS updates due to enabled hardware flow controls are not
364 * dealt with here.
365 */
366
367 self.flags.set_ring_indicator(self.control.out_2());
368 self.flags.set_data_carrier_detect(self.control.out_1());
369 self.flags.set_clear_to_send(self.control.request_to_send());
370 self.flags
371 .set_data_set_ready(self.control.data_transmit_ready());
372
373 // Change interrupts based on updated FR
374 let mut il = self.int_level;
375
376 il &= !Interrupt::MS;
377
378 if self.flags.data_set_ready() {
379 il |= Interrupt::DSR;
380 }
381 if self.flags.data_carrier_detect() {
382 il |= Interrupt::DCD;
383 }
384 if self.flags.clear_to_send() {
385 il |= Interrupt::CTS;
386 }
387 if self.flags.ring_indicator() {
388 il |= Interrupt::RI;
389 }
390 self.int_level = il;
391 true
392 }
393
loopback_break(&mut self, enable: bool) -> bool394 fn loopback_break(&mut self, enable: bool) -> bool {
395 enable && self.loopback_tx(registers::Data::BREAK)
396 }
397
set_read_trigger(&mut self)398 fn set_read_trigger(&mut self) {
399 self.read_trigger = 1;
400 }
401
reset(&mut self)402 pub fn reset(&mut self) {
403 self.line_control.reset();
404 self.receive_status_error_clear.reset();
405 self.dmacr = 0;
406 self.int_enabled = 0.into();
407 self.int_level = 0.into();
408 self.ilpr = 0;
409 self.ibrd = 0;
410 self.fbrd = 0;
411 self.read_trigger = 1;
412 self.ifl = 0x12;
413 self.control.reset();
414 self.flags.reset();
415 self.reset_rx_fifo();
416 self.reset_tx_fifo();
417 }
418
reset_rx_fifo(&mut self)419 pub fn reset_rx_fifo(&mut self) {
420 self.read_count = 0;
421 self.read_pos = 0;
422
423 // Reset FIFO flags
424 self.flags.set_receive_fifo_full(false);
425 self.flags.set_receive_fifo_empty(true);
426 }
427
reset_tx_fifo(&mut self)428 pub fn reset_tx_fifo(&mut self) {
429 // Reset FIFO flags
430 self.flags.set_transmit_fifo_full(false);
431 self.flags.set_transmit_fifo_empty(true);
432 }
433
434 #[inline]
fifo_enabled(&self) -> bool435 pub fn fifo_enabled(&self) -> bool {
436 self.line_control.fifos_enabled() == registers::Mode::FIFO
437 }
438
439 #[inline]
loopback_enabled(&self) -> bool440 pub fn loopback_enabled(&self) -> bool {
441 self.control.enable_loopback()
442 }
443
444 #[inline]
fifo_depth(&self) -> u32445 pub fn fifo_depth(&self) -> u32 {
446 // Note: FIFO depth is expected to be power-of-2
447 if self.fifo_enabled() {
448 return PL011_FIFO_DEPTH;
449 }
450 1
451 }
452
453 #[must_use]
fifo_rx_put(&mut self, value: registers::Data) -> bool454 pub fn fifo_rx_put(&mut self, value: registers::Data) -> bool {
455 let depth = self.fifo_depth();
456 assert!(depth > 0);
457 let slot = (self.read_pos + self.read_count) & (depth - 1);
458 self.read_fifo[slot] = value;
459 self.read_count += 1;
460 self.flags.set_receive_fifo_empty(false);
461 if self.read_count == depth {
462 self.flags.set_receive_fifo_full(true);
463 }
464
465 if self.read_count == self.read_trigger {
466 self.int_level |= Interrupt::RX;
467 return true;
468 }
469 false
470 }
471
post_load(&mut self) -> Result<(), ()>472 pub fn post_load(&mut self) -> Result<(), ()> {
473 /* Sanity-check input state */
474 if self.read_pos >= self.read_fifo.len() || self.read_count > self.read_fifo.len() {
475 return Err(());
476 }
477
478 if !self.fifo_enabled() && self.read_count > 0 && self.read_pos > 0 {
479 // Older versions of PL011 didn't ensure that the single
480 // character in the FIFO in FIFO-disabled mode is in
481 // element 0 of the array; convert to follow the current
482 // code's assumptions.
483 self.read_fifo[0] = self.read_fifo[self.read_pos];
484 self.read_pos = 0;
485 }
486
487 self.ibrd &= IBRD_MASK;
488 self.fbrd &= FBRD_MASK;
489
490 Ok(())
491 }
492 }
493
494 impl PL011State {
495 /// Initializes a pre-allocated, uninitialized instance of `PL011State`.
496 ///
497 /// # Safety
498 ///
499 /// `self` must point to a correctly sized and aligned location for the
500 /// `PL011State` type. It must not be called more than once on the same
501 /// location/instance. All its fields are expected to hold uninitialized
502 /// values with the sole exception of `parent_obj`.
init(mut this: ParentInit<Self>)503 unsafe fn init(mut this: ParentInit<Self>) {
504 static PL011_OPS: MemoryRegionOps<PL011State> = MemoryRegionOpsBuilder::<PL011State>::new()
505 .read(&PL011State::read)
506 .write(&PL011State::write)
507 .native_endian()
508 .impl_sizes(4, 4)
509 .build();
510
511 // SAFETY: this and this.iomem are guaranteed to be valid at this point
512 MemoryRegion::init_io(
513 &mut uninit_field_mut!(*this, iomem),
514 &PL011_OPS,
515 "pl011",
516 0x1000,
517 );
518
519 uninit_field_mut!(*this, regs).write(Default::default());
520
521 let clock = DeviceState::init_clock_in(
522 &mut this,
523 "clk",
524 &Self::clock_update,
525 ClockEvent::ClockUpdate,
526 );
527 uninit_field_mut!(*this, clock).write(clock);
528 }
529
clock_update(&self, _event: ClockEvent)530 const fn clock_update(&self, _event: ClockEvent) {
531 /* pl011_trace_baudrate_change(s); */
532 }
533
post_init(&self)534 fn post_init(&self) {
535 self.init_mmio(&self.iomem);
536 for irq in self.interrupts.iter() {
537 self.init_irq(irq);
538 }
539 }
540
read(&self, offset: hwaddr, _size: u32) -> u64541 fn read(&self, offset: hwaddr, _size: u32) -> u64 {
542 match RegisterOffset::try_from(offset) {
543 Err(v) if (0x3f8..0x400).contains(&(v >> 2)) => {
544 let device_id = self.get_class().device_id;
545 u64::from(device_id[(offset - 0xfe0) >> 2])
546 }
547 Err(_) => {
548 log_mask_ln!(Log::GuestError, "PL011State::read: Bad offset {offset}");
549 0
550 }
551 Ok(field) => {
552 let (update_irq, result) = self.regs.borrow_mut().read(field);
553 if update_irq {
554 self.update();
555 self.char_backend.accept_input();
556 }
557 result.into()
558 }
559 }
560 }
561
write(&self, offset: hwaddr, value: u64, _size: u32)562 fn write(&self, offset: hwaddr, value: u64, _size: u32) {
563 let mut update_irq = false;
564 if let Ok(field) = RegisterOffset::try_from(offset) {
565 // qemu_chr_fe_write_all() calls into the can_receive
566 // callback, so handle writes before entering PL011Registers.
567 if field == RegisterOffset::DR {
568 // ??? Check if transmitter is enabled.
569 let ch: [u8; 1] = [value as u8];
570 // XXX this blocks entire thread. Rewrite to use
571 // qemu_chr_fe_write and background I/O callbacks
572 let _ = self.char_backend.write_all(&ch);
573 }
574
575 update_irq = self
576 .regs
577 .borrow_mut()
578 .write(field, value as u32, &self.char_backend);
579 } else {
580 log_mask_ln!(
581 Log::GuestError,
582 "PL011State::write: Bad offset {offset} value {value}"
583 );
584 }
585 if update_irq {
586 self.update();
587 }
588 }
589
can_receive(&self) -> u32590 fn can_receive(&self) -> u32 {
591 let regs = self.regs.borrow();
592 // trace_pl011_can_receive(s->lcr, s->read_count, r);
593 regs.fifo_depth() - regs.read_count
594 }
595
receive(&self, buf: &[u8])596 fn receive(&self, buf: &[u8]) {
597 let mut regs = self.regs.borrow_mut();
598 if regs.loopback_enabled() {
599 // In loopback mode, the RX input signal is internally disconnected
600 // from the entire receiving logics; thus, all inputs are ignored,
601 // and BREAK detection on RX input signal is also not performed.
602 return;
603 }
604
605 let mut update_irq = false;
606 for &c in buf {
607 let c: u32 = c.into();
608 update_irq |= regs.fifo_rx_put(c.into());
609 }
610
611 // Release the BqlRefCell before calling self.update()
612 drop(regs);
613 if update_irq {
614 self.update();
615 }
616 }
617
event(&self, event: Event)618 fn event(&self, event: Event) {
619 let mut update_irq = false;
620 let mut regs = self.regs.borrow_mut();
621 if event == Event::CHR_EVENT_BREAK && !regs.loopback_enabled() {
622 update_irq = regs.fifo_rx_put(registers::Data::BREAK);
623 }
624 // Release the BqlRefCell before calling self.update()
625 drop(regs);
626
627 if update_irq {
628 self.update()
629 }
630 }
631
realize(&self) -> qemu_api::Result<()>632 fn realize(&self) -> qemu_api::Result<()> {
633 self.char_backend
634 .enable_handlers(self, Self::can_receive, Self::receive, Self::event);
635 Ok(())
636 }
637
reset_hold(&self, _type: ResetType)638 fn reset_hold(&self, _type: ResetType) {
639 self.regs.borrow_mut().reset();
640 }
641
update(&self)642 fn update(&self) {
643 let regs = self.regs.borrow();
644 let flags = regs.int_level & regs.int_enabled;
645 for (irq, i) in self.interrupts.iter().zip(IRQMASK) {
646 irq.set(flags.any_set(i));
647 }
648 }
649
post_load(&self, _version_id: u32) -> Result<(), ()>650 pub fn post_load(&self, _version_id: u32) -> Result<(), ()> {
651 self.regs.borrow_mut().post_load()
652 }
653 }
654
655 /// Which bits in the interrupt status matter for each outbound IRQ line ?
656 const IRQMASK: [Interrupt; 6] = [
657 Interrupt::all(),
658 Interrupt::RX,
659 Interrupt::TX,
660 Interrupt::RT,
661 Interrupt::MS,
662 Interrupt::E,
663 ];
664
665 /// # Safety
666 ///
667 /// We expect the FFI user of this function to pass a valid pointer for `chr`
668 /// and `irq`.
669 #[no_mangle]
pl011_create( addr: u64, irq: *mut IRQState, chr: *mut Chardev, ) -> *mut DeviceState670 pub unsafe extern "C" fn pl011_create(
671 addr: u64,
672 irq: *mut IRQState,
673 chr: *mut Chardev,
674 ) -> *mut DeviceState {
675 // SAFETY: The callers promise that they have owned references.
676 // They do not gift them to pl011_create, so use `Owned::from`.
677 let irq = unsafe { Owned::<IRQState>::from(&*irq) };
678
679 let dev = PL011State::new();
680 if !chr.is_null() {
681 let chr = unsafe { Owned::<Chardev>::from(&*chr) };
682 dev.prop_set_chr("chardev", &chr);
683 }
684 dev.sysbus_realize();
685 dev.mmio_map(0, addr);
686 dev.connect_irq(0, &irq);
687
688 // The pointer is kept alive by the QOM tree; drop the owned ref
689 dev.as_mut_ptr()
690 }
691
692 #[repr(C)]
693 #[derive(qemu_api_macros::Object)]
694 /// PL011 Luminary device model.
695 pub struct PL011Luminary {
696 parent_obj: ParentField<PL011State>,
697 }
698
699 qom_isa!(PL011Luminary : PL011State, SysBusDevice, DeviceState, Object);
700
701 unsafe impl ObjectType for PL011Luminary {
702 type Class = <PL011State as ObjectType>::Class;
703 const TYPE_NAME: &'static CStr = crate::TYPE_PL011_LUMINARY;
704 }
705
706 impl ObjectImpl for PL011Luminary {
707 type ParentType = PL011State;
708
709 const CLASS_INIT: fn(&mut Self::Class) = Self::Class::class_init::<Self>;
710 }
711
712 impl PL011Impl for PL011Luminary {
713 const DEVICE_ID: DeviceId = DeviceId(&[0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1]);
714 }
715
716 impl DeviceImpl for PL011Luminary {}
717 impl ResettablePhasesImpl for PL011Luminary {}
718 impl SysBusDeviceImpl for PL011Luminary {}
719
pl011_clock_needed(opaque: *mut c_void) -> bool720 extern "C" fn pl011_clock_needed(opaque: *mut c_void) -> bool {
721 let state = NonNull::new(opaque).unwrap().cast::<PL011State>();
722 unsafe { state.as_ref().migrate_clock }
723 }
724
725 /// Migration subsection for [`PL011State`] clock.
726 static VMSTATE_PL011_CLOCK: VMStateDescription = VMStateDescription {
727 name: c"pl011/clock".as_ptr(),
728 version_id: 1,
729 minimum_version_id: 1,
730 needed: Some(pl011_clock_needed),
731 fields: vmstate_fields! {
732 vmstate_clock!(PL011State, clock),
733 },
734 ..Zeroable::ZERO
735 };
736
pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int737 extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int {
738 let state = NonNull::new(opaque).unwrap().cast::<PL011State>();
739 let result = unsafe { state.as_ref().post_load(version_id as u32) };
740 if result.is_err() {
741 -1
742 } else {
743 0
744 }
745 }
746
747 static VMSTATE_PL011_REGS: VMStateDescription = VMStateDescription {
748 name: c"pl011/regs".as_ptr(),
749 version_id: 2,
750 minimum_version_id: 2,
751 fields: vmstate_fields! {
752 vmstate_of!(PL011Registers, flags),
753 vmstate_of!(PL011Registers, line_control),
754 vmstate_of!(PL011Registers, receive_status_error_clear),
755 vmstate_of!(PL011Registers, control),
756 vmstate_of!(PL011Registers, dmacr),
757 vmstate_of!(PL011Registers, int_enabled),
758 vmstate_of!(PL011Registers, int_level),
759 vmstate_of!(PL011Registers, read_fifo),
760 vmstate_of!(PL011Registers, ilpr),
761 vmstate_of!(PL011Registers, ibrd),
762 vmstate_of!(PL011Registers, fbrd),
763 vmstate_of!(PL011Registers, ifl),
764 vmstate_of!(PL011Registers, read_pos),
765 vmstate_of!(PL011Registers, read_count),
766 vmstate_of!(PL011Registers, read_trigger),
767 },
768 ..Zeroable::ZERO
769 };
770
771 pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
772 name: c"pl011".as_ptr(),
773 version_id: 2,
774 minimum_version_id: 2,
775 post_load: Some(pl011_post_load),
776 fields: vmstate_fields! {
777 vmstate_unused!(core::mem::size_of::<u32>()),
778 vmstate_struct!(PL011State, regs, &VMSTATE_PL011_REGS, BqlRefCell<PL011Registers>),
779 },
780 subsections: vmstate_subsections! {
781 VMSTATE_PL011_CLOCK
782 },
783 ..Zeroable::ZERO
784 };
785
786 qemu_api::declare_properties! {
787 PL011_PROPERTIES,
788 qemu_api::define_property!(
789 c"chardev",
790 PL011State,
791 char_backend,
792 unsafe { &qdev_prop_chr },
793 CharBackend
794 ),
795 qemu_api::define_property!(
796 c"migrate-clk",
797 PL011State,
798 migrate_clock,
799 unsafe { &qdev_prop_bool },
800 bool,
801 default = true
802 ),
803 }
804