1use std::mem::size_of;
7
8use vm_memory::{Address, Bytes, GuestAddress, GuestMemory};
9use zerocopy::little_endian::U32;
10use zerocopy::{Immutable, IntoBytes};
11
12use crate::{AcpiError, Result, Sdt, SdtHeader, checksum};
13
14const MADT_CPU_ENABLE_FLAG: u32 = 0;
15
16#[allow(dead_code)]
20#[repr(C, packed)]
21#[derive(Copy, Clone, Debug, Default, IntoBytes, Immutable)]
22pub struct LocalAPIC {
23 r#type: u8,
24 length: u8,
25 processor_uid: u8,
26 apic_id: u8,
27 flags: U32,
28}
29
30impl LocalAPIC {
31 pub fn new(cpu_id: u8) -> Self {
32 Self {
33 r#type: 0,
34 length: 8,
35 processor_uid: cpu_id,
36 apic_id: cpu_id,
37 flags: U32::new(1u32 << MADT_CPU_ENABLE_FLAG),
38 }
39 }
40}
41
42#[allow(dead_code)]
46#[repr(C, packed)]
47#[derive(Copy, Clone, Debug, Default, IntoBytes, Immutable)]
48pub struct IoAPIC {
49 r#type: u8,
50 length: u8,
51 ioapic_id: u8,
52 reserved: u8,
53 apic_address: U32,
54 gsi_base: U32,
55}
56
57impl IoAPIC {
58 pub fn new(ioapic_id: u8, apic_address: u32) -> Self {
59 IoAPIC {
60 r#type: 1,
61 length: 12,
62 ioapic_id,
63 reserved: 0,
64 apic_address: U32::new(apic_address),
65 gsi_base: U32::ZERO,
66 }
67 }
68}
69
70#[allow(dead_code)]
74#[repr(C, packed)]
75#[derive(Debug, IntoBytes, Immutable)]
76struct MadtHeader {
77 sdt: SdtHeader,
78 base_address: U32,
79 flags: U32,
80}
81
82#[derive(Debug)]
88pub struct Madt {
89 header: MadtHeader,
90 interrupt_controllers: Vec<u8>,
91}
92
93impl Madt {
94 pub fn new(
95 oem_id: [u8; 6],
96 oem_table_id: [u8; 8],
97 oem_revision: u32,
98 base_address: u32,
99 interrupt_controllers: Vec<u8>,
100 ) -> Self {
101 let length = size_of::<MadtHeader>() + interrupt_controllers.len();
102 let sdt_header = SdtHeader::new(
103 *b"APIC",
104 length.try_into().unwrap(),
107 6,
108 oem_id,
109 oem_table_id,
110 oem_revision,
111 );
112
113 let mut header = MadtHeader {
114 sdt: sdt_header,
115 base_address: U32::new(base_address),
116 flags: U32::ZERO,
117 };
118
119 header.sdt.checksum = checksum(&[header.as_bytes(), interrupt_controllers.as_bytes()]);
120
121 Madt {
122 header,
123 interrupt_controllers,
124 }
125 }
126}
127
128impl Sdt for Madt {
129 fn len(&self) -> usize {
130 self.header.sdt.length.get().try_into().unwrap()
131 }
132
133 fn write_to_guest<M: GuestMemory>(&mut self, mem: &M, address: GuestAddress) -> Result<()> {
134 mem.write_slice(self.header.as_bytes(), address)?;
135 let address = address
136 .checked_add(size_of::<MadtHeader>() as u64)
137 .ok_or(AcpiError::InvalidGuestAddress)?;
138 mem.write_slice(self.interrupt_controllers.as_bytes(), address)?;
139
140 Ok(())
141 }
142}