14ed4da16SPaolo Bonzini // Copyright 2024 Red Hat, Inc. 24ed4da16SPaolo Bonzini // Author(s): Paolo Bonzini <pbonzini@redhat.com> 34ed4da16SPaolo Bonzini // SPDX-License-Identifier: GPL-2.0-or-later 44ed4da16SPaolo Bonzini 5ebacd14aSPaolo Bonzini //! Bindings to access `sysbus` functionality from Rust. 6ebacd14aSPaolo Bonzini 77630ca2aSPaolo Bonzini use std::{ffi::CStr, ptr::addr_of_mut}; 84ed4da16SPaolo Bonzini 9*f4751c7aSPaolo Bonzini pub use bindings::SysBusDeviceClass; 104ed4da16SPaolo Bonzini 116dd818fbSPaolo Bonzini use crate::{ 12f50cd85cSPaolo Bonzini bindings, 13*f4751c7aSPaolo Bonzini cell::{bql_locked, Opaque}, 147630ca2aSPaolo Bonzini irq::{IRQState, InterruptSource}, 15590faa03SPaolo Bonzini memory::MemoryRegion, 16f50cd85cSPaolo Bonzini prelude::*, 17d556226dSPaolo Bonzini qdev::{DeviceImpl, DeviceState}, 18d556226dSPaolo Bonzini qom::Owned, 196dd818fbSPaolo Bonzini }; 207bd8e3efSPaolo Bonzini 21*f4751c7aSPaolo Bonzini /// A safe wrapper around [`bindings::SysBusDevice`]. 22*f4751c7aSPaolo Bonzini #[repr(transparent)] 23*f4751c7aSPaolo Bonzini #[derive(Debug, qemu_api_macros::Wrapper)] 24*f4751c7aSPaolo Bonzini pub struct SysBusDevice(Opaque<bindings::SysBusDevice>); 25*f4751c7aSPaolo Bonzini 26*f4751c7aSPaolo Bonzini unsafe impl Send for SysBusDevice {} 27*f4751c7aSPaolo Bonzini unsafe impl Sync for SysBusDevice {} 28*f4751c7aSPaolo Bonzini 297bd8e3efSPaolo Bonzini unsafe impl ObjectType for SysBusDevice { 307bd8e3efSPaolo Bonzini type Class = SysBusDeviceClass; 317bd8e3efSPaolo Bonzini const TYPE_NAME: &'static CStr = 327bd8e3efSPaolo Bonzini unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_SYS_BUS_DEVICE) }; 337bd8e3efSPaolo Bonzini } 34f50cd85cSPaolo Bonzini qom_isa!(SysBusDevice: DeviceState, Object); 354ed4da16SPaolo Bonzini 363212da00SPaolo Bonzini // TODO: add virtual methods 373212da00SPaolo Bonzini pub trait SysBusDeviceImpl: DeviceImpl + IsA<SysBusDevice> {} 383212da00SPaolo Bonzini 39d556226dSPaolo Bonzini impl SysBusDeviceClass { 40d556226dSPaolo Bonzini /// Fill in the virtual methods of `SysBusDeviceClass` based on the 41d556226dSPaolo Bonzini /// definitions in the `SysBusDeviceImpl` trait. class_init<T: SysBusDeviceImpl>(self: &mut SysBusDeviceClass)42d556226dSPaolo Bonzini pub fn class_init<T: SysBusDeviceImpl>(self: &mut SysBusDeviceClass) { 43d556226dSPaolo Bonzini self.parent_class.class_init::<T>(); 446dd818fbSPaolo Bonzini } 456dd818fbSPaolo Bonzini } 466dd818fbSPaolo Bonzini 47559a779cSPaolo Bonzini /// Trait for methods of [`SysBusDevice`] and its subclasses. 48559a779cSPaolo Bonzini pub trait SysBusDeviceMethods: ObjectDeref 49559a779cSPaolo Bonzini where 50559a779cSPaolo Bonzini Self::Target: IsA<SysBusDevice>, 51559a779cSPaolo Bonzini { 52af68b41dSPaolo Bonzini /// Expose a memory region to the board so that it can give it an address 53af68b41dSPaolo Bonzini /// in guest memory. Note that the ordering of calls to `init_mmio` is 54af68b41dSPaolo Bonzini /// important, since whoever creates the sysbus device will refer to the 55af68b41dSPaolo Bonzini /// region with a number that corresponds to the order of calls to 56af68b41dSPaolo Bonzini /// `init_mmio`. init_mmio(&self, iomem: &MemoryRegion)57590faa03SPaolo Bonzini fn init_mmio(&self, iomem: &MemoryRegion) { 58af68b41dSPaolo Bonzini assert!(bql_locked()); 59af68b41dSPaolo Bonzini unsafe { 60*f4751c7aSPaolo Bonzini bindings::sysbus_init_mmio(self.upcast().as_mut_ptr(), iomem.as_mut_ptr()); 61af68b41dSPaolo Bonzini } 62af68b41dSPaolo Bonzini } 63af68b41dSPaolo Bonzini 644ed4da16SPaolo Bonzini /// Expose an interrupt source outside the device as a qdev GPIO output. 654ed4da16SPaolo Bonzini /// Note that the ordering of calls to `init_irq` is important, since 664ed4da16SPaolo Bonzini /// whoever creates the sysbus device will refer to the interrupts with 674ed4da16SPaolo Bonzini /// a number that corresponds to the order of calls to `init_irq`. init_irq(&self, irq: &InterruptSource)68559a779cSPaolo Bonzini fn init_irq(&self, irq: &InterruptSource) { 694ed4da16SPaolo Bonzini assert!(bql_locked()); 704ed4da16SPaolo Bonzini unsafe { 71*f4751c7aSPaolo Bonzini bindings::sysbus_init_irq(self.upcast().as_mut_ptr(), irq.as_ptr()); 724ed4da16SPaolo Bonzini } 734ed4da16SPaolo Bonzini } 747630ca2aSPaolo Bonzini 757630ca2aSPaolo Bonzini // TODO: do we want a type like GuestAddress here? mmio_addr(&self, id: u32) -> Option<u64>7609fda8f5SPaolo Bonzini fn mmio_addr(&self, id: u32) -> Option<u64> { 7709fda8f5SPaolo Bonzini assert!(bql_locked()); 78*f4751c7aSPaolo Bonzini // SAFETY: the BQL ensures that no one else writes to sbd.mmio[], and 79*f4751c7aSPaolo Bonzini // the SysBusDevice must be initialized to get an IsA<SysBusDevice>. 80*f4751c7aSPaolo Bonzini let sbd = unsafe { *self.upcast().as_ptr() }; 8109fda8f5SPaolo Bonzini let id: usize = id.try_into().unwrap(); 8209fda8f5SPaolo Bonzini if sbd.mmio[id].memory.is_null() { 8309fda8f5SPaolo Bonzini None 8409fda8f5SPaolo Bonzini } else { 8509fda8f5SPaolo Bonzini Some(sbd.mmio[id].addr) 8609fda8f5SPaolo Bonzini } 8709fda8f5SPaolo Bonzini } 8809fda8f5SPaolo Bonzini 8909fda8f5SPaolo Bonzini // TODO: do we want a type like GuestAddress here? mmio_map(&self, id: u32, addr: u64)907630ca2aSPaolo Bonzini fn mmio_map(&self, id: u32, addr: u64) { 917630ca2aSPaolo Bonzini assert!(bql_locked()); 927630ca2aSPaolo Bonzini let id: i32 = id.try_into().unwrap(); 937630ca2aSPaolo Bonzini unsafe { 94*f4751c7aSPaolo Bonzini bindings::sysbus_mmio_map(self.upcast().as_mut_ptr(), id, addr); 957630ca2aSPaolo Bonzini } 967630ca2aSPaolo Bonzini } 977630ca2aSPaolo Bonzini 987630ca2aSPaolo Bonzini // Owned<> is used here because sysbus_connect_irq (via 997630ca2aSPaolo Bonzini // object_property_set_link) adds a reference to the IRQState, 1007630ca2aSPaolo Bonzini // which can prolong its life connect_irq(&self, id: u32, irq: &Owned<IRQState>)1017630ca2aSPaolo Bonzini fn connect_irq(&self, id: u32, irq: &Owned<IRQState>) { 1027630ca2aSPaolo Bonzini assert!(bql_locked()); 1037630ca2aSPaolo Bonzini let id: i32 = id.try_into().unwrap(); 1049c9a6a88SPaolo Bonzini let irq: &IRQState = irq; 1057630ca2aSPaolo Bonzini unsafe { 106*f4751c7aSPaolo Bonzini bindings::sysbus_connect_irq(self.upcast().as_mut_ptr(), id, irq.as_mut_ptr()); 1077630ca2aSPaolo Bonzini } 1087630ca2aSPaolo Bonzini } 1097630ca2aSPaolo Bonzini sysbus_realize(&self)1107630ca2aSPaolo Bonzini fn sysbus_realize(&self) { 1117630ca2aSPaolo Bonzini // TODO: return an Error 1127630ca2aSPaolo Bonzini assert!(bql_locked()); 1137630ca2aSPaolo Bonzini unsafe { 114*f4751c7aSPaolo Bonzini bindings::sysbus_realize( 115*f4751c7aSPaolo Bonzini self.upcast().as_mut_ptr(), 116*f4751c7aSPaolo Bonzini addr_of_mut!(bindings::error_fatal), 117*f4751c7aSPaolo Bonzini ); 1187630ca2aSPaolo Bonzini } 1197630ca2aSPaolo Bonzini } 1204ed4da16SPaolo Bonzini } 121559a779cSPaolo Bonzini 122559a779cSPaolo Bonzini impl<R: ObjectDeref> SysBusDeviceMethods for R where R::Target: IsA<SysBusDevice> {} 123