1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
use crate::{sdt::SdtHeader, Acpi, AcpiError, AcpiHandler, AmlTable, GenericAddress, PhysicalMapping};

type ExtendedField<T> = crate::sdt::ExtendedField<T, typenum::U2>;

/// Represents the Fixed ACPI Description Table (FADT). This table contains various fixed hardware
/// details, such as the addresses of the hardware register blocks. It also contains a pointer to
/// the Differentiated Definition Block (DSDT).
///
/// In cases where the FADT contains both a 32-bit and 64-bit field for the same address, we should
/// always prefer the 64-bit one. Only if it's zero or the CPU will not allow us to access that
/// address should the 32-bit one be used.
#[repr(C, packed)]
pub struct Fadt {
    header: SdtHeader,

    firmware_ctrl: u32,
    dsdt_address: u32,

    // used in acpi 1.0; compatibility only, should be zero
    _reserved: u8,

    preferred_pm_profile: u8,
    sci_interrupt: u16,
    smi_cmd_port: u32,
    acpi_enable: u8,
    acpi_disable: u8,
    s4bios_req: u8,
    pstate_control: u8,
    pm1a_event_block: u32,
    pm1b_event_block: u32,
    pm1a_control_block: u32,
    pm1b_control_block: u32,
    pm2_control_block: u32,
    pm_timer_block: u32,
    gpe0_block: u32,
    gpe1_block: u32,
    pm1_event_length: u8,
    pm1_control_length: u8,
    pm2_control_length: u8,
    pm_timer_length: u8,
    gpe0_block_length: u8,
    gpe1_block_length: u8,
    gpe1_base: u8,
    c_state_control: u8,
    worst_c2_latency: u16,
    worst_c3_latency: u16,
    flush_size: u16,
    flush_stride: u16,
    duty_offset: u8,
    duty_width: u8,
    day_alarm: u8,
    month_alarm: u8,
    century: u8,
    iapc_boot_arch: u16,
    _reserved2: u8, // must be 0
    flags: u32,
    reset_reg: GenericAddress,
    reset_value: u8,
    arm_boot_arch: u16,
    fadt_minor_version: u8,
    x_firmware_ctrl: ExtendedField<u64>,
    x_dsdt_address: ExtendedField<u64>,
    x_pm1a_event_block: ExtendedField<GenericAddress>,
    x_pm1b_event_block: ExtendedField<GenericAddress>,
    x_pm1a_control_block: ExtendedField<GenericAddress>,
    x_pm1b_control_block: ExtendedField<GenericAddress>,
    x_pm2_control_block: ExtendedField<GenericAddress>,
    x_pm_timer_block: ExtendedField<GenericAddress>,
    x_gpe0_block: ExtendedField<GenericAddress>,
    x_gpe1_block: ExtendedField<GenericAddress>,
    sleep_control_reg: ExtendedField<GenericAddress>,
    sleep_status_reg: ExtendedField<GenericAddress>,
    hypervisor_vendor_id: ExtendedField<u64>,
}

pub(crate) fn parse_fadt<H>(
    acpi: &mut Acpi,
    handler: &mut H,
    mapping: &PhysicalMapping<Fadt>,
) -> Result<(), AcpiError>
where
    H: AcpiHandler,
{
    let fadt = &*mapping;
    fadt.header.validate(b"FACP")?;

    let dsdt_address = unsafe {
        fadt.x_dsdt_address
            .get(fadt.header.revision())
            .filter(|p| *p != 0)
            .or(Some(fadt.dsdt_address as u64))
            .filter(|p| *p != 0)
            .map(|p| p as usize)
    };

    acpi.dsdt = dsdt_address.map(|address| {
        let dsdt_header = crate::sdt::peek_at_sdt_header(handler, address);
        AmlTable::new(address, dsdt_header.length())
    });

    Ok(())
}