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 94ed4da16SPaolo Bonzini pub use bindings::{SysBusDevice, SysBusDeviceClass}; 104ed4da16SPaolo Bonzini 116dd818fbSPaolo Bonzini use crate::{ 12f50cd85cSPaolo Bonzini bindings, 13f50cd85cSPaolo Bonzini cell::bql_locked, 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 217bd8e3efSPaolo Bonzini unsafe impl ObjectType for SysBusDevice { 227bd8e3efSPaolo Bonzini type Class = SysBusDeviceClass; 237bd8e3efSPaolo Bonzini const TYPE_NAME: &'static CStr = 247bd8e3efSPaolo Bonzini unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_SYS_BUS_DEVICE) }; 257bd8e3efSPaolo Bonzini } 26f50cd85cSPaolo Bonzini qom_isa!(SysBusDevice: DeviceState, Object); 274ed4da16SPaolo Bonzini 283212da00SPaolo Bonzini // TODO: add virtual methods 293212da00SPaolo Bonzini pub trait SysBusDeviceImpl: DeviceImpl + IsA<SysBusDevice> {} 303212da00SPaolo Bonzini 31d556226dSPaolo Bonzini impl SysBusDeviceClass { 32d556226dSPaolo Bonzini /// Fill in the virtual methods of `SysBusDeviceClass` based on the 33d556226dSPaolo Bonzini /// definitions in the `SysBusDeviceImpl` trait. 34d556226dSPaolo Bonzini pub fn class_init<T: SysBusDeviceImpl>(self: &mut SysBusDeviceClass) { 35d556226dSPaolo Bonzini self.parent_class.class_init::<T>(); 366dd818fbSPaolo Bonzini } 376dd818fbSPaolo Bonzini } 386dd818fbSPaolo Bonzini 39559a779cSPaolo Bonzini /// Trait for methods of [`SysBusDevice`] and its subclasses. 40559a779cSPaolo Bonzini pub trait SysBusDeviceMethods: ObjectDeref 41559a779cSPaolo Bonzini where 42559a779cSPaolo Bonzini Self::Target: IsA<SysBusDevice>, 43559a779cSPaolo Bonzini { 44af68b41dSPaolo Bonzini /// Expose a memory region to the board so that it can give it an address 45af68b41dSPaolo Bonzini /// in guest memory. Note that the ordering of calls to `init_mmio` is 46af68b41dSPaolo Bonzini /// important, since whoever creates the sysbus device will refer to the 47af68b41dSPaolo Bonzini /// region with a number that corresponds to the order of calls to 48af68b41dSPaolo Bonzini /// `init_mmio`. 49590faa03SPaolo Bonzini fn init_mmio(&self, iomem: &MemoryRegion) { 50af68b41dSPaolo Bonzini assert!(bql_locked()); 51af68b41dSPaolo Bonzini unsafe { 52590faa03SPaolo Bonzini bindings::sysbus_init_mmio(self.as_mut_ptr(), iomem.as_mut_ptr()); 53af68b41dSPaolo Bonzini } 54af68b41dSPaolo Bonzini } 55af68b41dSPaolo Bonzini 564ed4da16SPaolo Bonzini /// Expose an interrupt source outside the device as a qdev GPIO output. 574ed4da16SPaolo Bonzini /// Note that the ordering of calls to `init_irq` is important, since 584ed4da16SPaolo Bonzini /// whoever creates the sysbus device will refer to the interrupts with 594ed4da16SPaolo Bonzini /// a number that corresponds to the order of calls to `init_irq`. 60559a779cSPaolo Bonzini fn init_irq(&self, irq: &InterruptSource) { 614ed4da16SPaolo Bonzini assert!(bql_locked()); 624ed4da16SPaolo Bonzini unsafe { 634ed4da16SPaolo Bonzini bindings::sysbus_init_irq(self.as_mut_ptr(), irq.as_ptr()); 644ed4da16SPaolo Bonzini } 654ed4da16SPaolo Bonzini } 667630ca2aSPaolo Bonzini 677630ca2aSPaolo Bonzini // TODO: do we want a type like GuestAddress here? 68*09fda8f5SPaolo Bonzini fn mmio_addr(&self, id: u32) -> Option<u64> { 69*09fda8f5SPaolo Bonzini assert!(bql_locked()); 70*09fda8f5SPaolo Bonzini let sbd = self.upcast(); 71*09fda8f5SPaolo Bonzini let id: usize = id.try_into().unwrap(); 72*09fda8f5SPaolo Bonzini if sbd.mmio[id].memory.is_null() { 73*09fda8f5SPaolo Bonzini None 74*09fda8f5SPaolo Bonzini } else { 75*09fda8f5SPaolo Bonzini Some(sbd.mmio[id].addr) 76*09fda8f5SPaolo Bonzini } 77*09fda8f5SPaolo Bonzini } 78*09fda8f5SPaolo Bonzini 79*09fda8f5SPaolo Bonzini // TODO: do we want a type like GuestAddress here? 807630ca2aSPaolo Bonzini fn mmio_map(&self, id: u32, addr: u64) { 817630ca2aSPaolo Bonzini assert!(bql_locked()); 827630ca2aSPaolo Bonzini let id: i32 = id.try_into().unwrap(); 837630ca2aSPaolo Bonzini unsafe { 847630ca2aSPaolo Bonzini bindings::sysbus_mmio_map(self.as_mut_ptr(), id, addr); 857630ca2aSPaolo Bonzini } 867630ca2aSPaolo Bonzini } 877630ca2aSPaolo Bonzini 887630ca2aSPaolo Bonzini // Owned<> is used here because sysbus_connect_irq (via 897630ca2aSPaolo Bonzini // object_property_set_link) adds a reference to the IRQState, 907630ca2aSPaolo Bonzini // which can prolong its life 917630ca2aSPaolo Bonzini fn connect_irq(&self, id: u32, irq: &Owned<IRQState>) { 927630ca2aSPaolo Bonzini assert!(bql_locked()); 937630ca2aSPaolo Bonzini let id: i32 = id.try_into().unwrap(); 949c9a6a88SPaolo Bonzini let irq: &IRQState = irq; 957630ca2aSPaolo Bonzini unsafe { 967630ca2aSPaolo Bonzini bindings::sysbus_connect_irq(self.as_mut_ptr(), id, irq.as_mut_ptr()); 977630ca2aSPaolo Bonzini } 987630ca2aSPaolo Bonzini } 997630ca2aSPaolo Bonzini 1007630ca2aSPaolo Bonzini fn sysbus_realize(&self) { 1017630ca2aSPaolo Bonzini // TODO: return an Error 1027630ca2aSPaolo Bonzini assert!(bql_locked()); 1037630ca2aSPaolo Bonzini unsafe { 1047630ca2aSPaolo Bonzini bindings::sysbus_realize(self.as_mut_ptr(), addr_of_mut!(bindings::error_fatal)); 1057630ca2aSPaolo Bonzini } 1067630ca2aSPaolo Bonzini } 1074ed4da16SPaolo Bonzini } 108559a779cSPaolo Bonzini 109559a779cSPaolo Bonzini impl<R: ObjectDeref> SysBusDeviceMethods for R where R::Target: IsA<SysBusDevice> {} 110