1 pub mod interrupt; 2 3 use crate::{ 4 address::GenericAddress, 5 fadt::Fadt, 6 madt::Madt, 7 AcpiError, 8 AcpiHandler, 9 AcpiResult, 10 AcpiTables, 11 ManagedSlice, 12 PowerProfile, 13 }; 14 use core::alloc::Allocator; 15 use interrupt::InterruptModel; 16 17 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 18 pub enum ProcessorState { 19 /// A processor in this state is unusable, and you must not attempt to bring it up. 20 Disabled, 21 22 /// A processor waiting for a SIPI (Startup Inter-processor Interrupt) is currently not active, 23 /// but may be brought up. 24 WaitingForSipi, 25 26 /// A Running processor is currently brought up and running code. 27 Running, 28 } 29 30 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 31 pub struct Processor { 32 /// Corresponds to the `_UID` object of the processor's `Device`, or the `ProcessorId` field of the `Processor` 33 /// object, in AML. 34 pub processor_uid: u32, 35 /// The ID of the local APIC of the processor. Will be less than `256` if the APIC is being used, but can be 36 /// greater than this if the X2APIC is being used. 37 pub local_apic_id: u32, 38 39 /// The state of this processor. Check that the processor is not `Disabled` before attempting to bring it up! 40 pub state: ProcessorState, 41 42 /// Whether this processor is the Bootstrap Processor (BSP), or an Application Processor (AP). 43 /// When the bootloader is entered, the BSP is the only processor running code. To run code on 44 /// more than one processor, you need to "bring up" the APs. 45 pub is_ap: bool, 46 } 47 48 #[derive(Debug)] 49 pub struct ProcessorInfo<'a, A> 50 where 51 A: Allocator, 52 { 53 pub boot_processor: Processor, 54 /// Application processors should be brought up in the order they're defined in this list. 55 pub application_processors: ManagedSlice<'a, Processor, A>, 56 } 57 58 impl<'a, A> ProcessorInfo<'a, A> 59 where 60 A: Allocator, 61 { new(boot_processor: Processor, application_processors: ManagedSlice<'a, Processor, A>) -> Self62 pub(crate) fn new(boot_processor: Processor, application_processors: ManagedSlice<'a, Processor, A>) -> Self { 63 Self { boot_processor, application_processors } 64 } 65 } 66 67 /// Information about the ACPI Power Management Timer (ACPI PM Timer). 68 #[derive(Debug)] 69 pub struct PmTimer { 70 /// A generic address to the register block of ACPI PM Timer. 71 pub base: GenericAddress, 72 /// This field is `true` if the hardware supports 32-bit timer, and `false` if the hardware supports 24-bit timer. 73 pub supports_32bit: bool, 74 } 75 76 impl PmTimer { new(fadt: &Fadt) -> Result<Option<PmTimer>, AcpiError>77 pub fn new(fadt: &Fadt) -> Result<Option<PmTimer>, AcpiError> { 78 match fadt.pm_timer_block()? { 79 Some(base) => Ok(Some(PmTimer { base, supports_32bit: { fadt.flags }.pm_timer_is_32_bit() })), 80 None => Ok(None), 81 } 82 } 83 } 84 85 /// `PlatformInfo` allows the collection of some basic information about the platform from some of the fixed-size 86 /// tables in a nice way. It requires access to the `FADT` and `MADT`. It is the easiest way to get information 87 /// about the processors and interrupt controllers on a platform. 88 #[derive(Debug)] 89 pub struct PlatformInfo<'a, A> 90 where 91 A: Allocator, 92 { 93 pub power_profile: PowerProfile, 94 pub interrupt_model: InterruptModel<'a, A>, 95 /// On `x86_64` platforms that support the APIC, the processor topology must also be inferred from the 96 /// interrupt model. That information is stored here, if present. 97 pub processor_info: Option<ProcessorInfo<'a, A>>, 98 pub pm_timer: Option<PmTimer>, 99 /* 100 * TODO: we could provide a nice view of the hardware register blocks in the FADT here. 101 */ 102 } 103 104 #[cfg(feature = "alloc")] 105 impl<'a> PlatformInfo<'a, alloc::alloc::Global> { new<H>(tables: &AcpiTables<H>) -> AcpiResult<Self> where H: AcpiHandler,106 pub fn new<H>(tables: &AcpiTables<H>) -> AcpiResult<Self> 107 where 108 H: AcpiHandler, 109 { 110 Self::new_in(tables, alloc::alloc::Global) 111 } 112 } 113 114 impl<'a, A> PlatformInfo<'a, A> 115 where 116 A: Allocator + Clone, 117 { new_in<H>(tables: &AcpiTables<H>, allocator: A) -> AcpiResult<Self> where H: AcpiHandler,118 pub fn new_in<H>(tables: &AcpiTables<H>, allocator: A) -> AcpiResult<Self> 119 where 120 H: AcpiHandler, 121 { 122 let fadt = tables.find_table::<Fadt>()?; 123 let power_profile = fadt.power_profile(); 124 125 let madt = tables.find_table::<Madt>(); 126 let (interrupt_model, processor_info) = match madt { 127 Ok(madt) => madt.parse_interrupt_model_in(allocator)?, 128 Err(_) => (InterruptModel::Unknown, None), 129 }; 130 let pm_timer = PmTimer::new(&fadt)?; 131 132 Ok(PlatformInfo { power_profile, interrupt_model, processor_info, pm_timer }) 133 } 134 } 135