1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2017 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryFrom;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::result;
8*bb4ee6a4SAndroid Build Coastguard Worker
9*bb4ee6a4SAndroid Build Coastguard Worker use devices::PciAddress;
10*bb4ee6a4SAndroid Build Coastguard Worker use devices::PciInterruptPin;
11*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
12*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error;
13*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
14*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
15*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
16*bb4ee6a4SAndroid Build Coastguard Worker
17*bb4ee6a4SAndroid Build Coastguard Worker use crate::mpspec::*;
18*bb4ee6a4SAndroid Build Coastguard Worker
19*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
20*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)]
21*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
22*bb4ee6a4SAndroid Build Coastguard Worker /// The MP table has too little address space to be stored.
23*bb4ee6a4SAndroid Build Coastguard Worker #[error("The MP table has too little address space to be stored")]
24*bb4ee6a4SAndroid Build Coastguard Worker AddressOverflow,
25*bb4ee6a4SAndroid Build Coastguard Worker /// Failure while zeroing out the memory for the MP table.
26*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failure while zeroing out the memory for the MP table")]
27*bb4ee6a4SAndroid Build Coastguard Worker Clear,
28*bb4ee6a4SAndroid Build Coastguard Worker /// There was too little guest memory to store the entire MP table.
29*bb4ee6a4SAndroid Build Coastguard Worker #[error("There was too little guest memory to store the MP table")]
30*bb4ee6a4SAndroid Build Coastguard Worker NotEnoughMemory,
31*bb4ee6a4SAndroid Build Coastguard Worker /// Failure to write MP bus entry.
32*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failure to write MP bus entry")]
33*bb4ee6a4SAndroid Build Coastguard Worker WriteMpcBus,
34*bb4ee6a4SAndroid Build Coastguard Worker /// Failure to write MP CPU entry.
35*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failure to write MP CPU entry")]
36*bb4ee6a4SAndroid Build Coastguard Worker WriteMpcCpu,
37*bb4ee6a4SAndroid Build Coastguard Worker /// Failure to write MP interrupt source entry.
38*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failure to write MP interrupt source entry")]
39*bb4ee6a4SAndroid Build Coastguard Worker WriteMpcIntsrc,
40*bb4ee6a4SAndroid Build Coastguard Worker /// Failure to write MP ioapic entry.
41*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failure to write MP ioapic entry")]
42*bb4ee6a4SAndroid Build Coastguard Worker WriteMpcIoapic,
43*bb4ee6a4SAndroid Build Coastguard Worker /// Failure to write MP local interrupt source entry.
44*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failure to write MP local interrupt source entry")]
45*bb4ee6a4SAndroid Build Coastguard Worker WriteMpcLintsrc,
46*bb4ee6a4SAndroid Build Coastguard Worker /// Failure to write MP table header.
47*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failure to write MP table header")]
48*bb4ee6a4SAndroid Build Coastguard Worker WriteMpcTable,
49*bb4ee6a4SAndroid Build Coastguard Worker /// Failure to write the MP floating pointer.
50*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failure to write the MP floating pointer")]
51*bb4ee6a4SAndroid Build Coastguard Worker WriteMpfIntel,
52*bb4ee6a4SAndroid Build Coastguard Worker }
53*bb4ee6a4SAndroid Build Coastguard Worker
54*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = result::Result<T, Error>;
55*bb4ee6a4SAndroid Build Coastguard Worker
56*bb4ee6a4SAndroid Build Coastguard Worker // Most of these variables are sourced from the Intel MP Spec 1.4.
57*bb4ee6a4SAndroid Build Coastguard Worker const SMP_MAGIC_IDENT: [u8; 4] = *b"_MP_";
58*bb4ee6a4SAndroid Build Coastguard Worker const MPC_SIGNATURE: [u8; 4] = *b"PCMP";
59*bb4ee6a4SAndroid Build Coastguard Worker const MPC_SPEC: i8 = 4;
60*bb4ee6a4SAndroid Build Coastguard Worker const MPC_OEM: [u8; 8] = *b"CROSVM ";
61*bb4ee6a4SAndroid Build Coastguard Worker const MPC_PRODUCT_ID: [u8; 12] = *b"000000000000";
62*bb4ee6a4SAndroid Build Coastguard Worker const BUS_TYPE_ISA: [u8; 6] = *b"ISA ";
63*bb4ee6a4SAndroid Build Coastguard Worker const BUS_TYPE_PCI: [u8; 6] = *b"PCI ";
64*bb4ee6a4SAndroid Build Coastguard Worker // source: linux/arch/x86/include/asm/apicdef.h
65*bb4ee6a4SAndroid Build Coastguard Worker pub const IO_APIC_DEFAULT_PHYS_BASE: u32 = 0xfec00000;
66*bb4ee6a4SAndroid Build Coastguard Worker // source: linux/arch/x86/include/asm/apicdef.h
67*bb4ee6a4SAndroid Build Coastguard Worker pub const APIC_DEFAULT_PHYS_BASE: u32 = 0xfee00000;
68*bb4ee6a4SAndroid Build Coastguard Worker const APIC_VERSION: u8 = 0x14;
69*bb4ee6a4SAndroid Build Coastguard Worker const CPU_STEPPING: u32 = 0x600;
70*bb4ee6a4SAndroid Build Coastguard Worker const CPU_FEATURE_APIC: u32 = 0x200;
71*bb4ee6a4SAndroid Build Coastguard Worker const CPU_FEATURE_FPU: u32 = 0x001;
72*bb4ee6a4SAndroid Build Coastguard Worker const MPTABLE_START: u64 = 0x400 * 639; // Last 1k of Linux's 640k base RAM.
73*bb4ee6a4SAndroid Build Coastguard Worker
compute_checksum<T: AsBytes>(v: &T) -> u874*bb4ee6a4SAndroid Build Coastguard Worker fn compute_checksum<T: AsBytes>(v: &T) -> u8 {
75*bb4ee6a4SAndroid Build Coastguard Worker let mut checksum: u8 = 0;
76*bb4ee6a4SAndroid Build Coastguard Worker for i in v.as_bytes() {
77*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(*i);
78*bb4ee6a4SAndroid Build Coastguard Worker }
79*bb4ee6a4SAndroid Build Coastguard Worker checksum
80*bb4ee6a4SAndroid Build Coastguard Worker }
81*bb4ee6a4SAndroid Build Coastguard Worker
mpf_intel_compute_checksum(v: &mpf_intel) -> u882*bb4ee6a4SAndroid Build Coastguard Worker fn mpf_intel_compute_checksum(v: &mpf_intel) -> u8 {
83*bb4ee6a4SAndroid Build Coastguard Worker let checksum = compute_checksum(v).wrapping_sub(v.checksum);
84*bb4ee6a4SAndroid Build Coastguard Worker (!checksum).wrapping_add(1)
85*bb4ee6a4SAndroid Build Coastguard Worker }
86*bb4ee6a4SAndroid Build Coastguard Worker
compute_mp_size(num_cpus: u8) -> usize87*bb4ee6a4SAndroid Build Coastguard Worker fn compute_mp_size(num_cpus: u8) -> usize {
88*bb4ee6a4SAndroid Build Coastguard Worker mem::size_of::<mpf_intel>()
89*bb4ee6a4SAndroid Build Coastguard Worker + mem::size_of::<mpc_table>()
90*bb4ee6a4SAndroid Build Coastguard Worker + mem::size_of::<mpc_cpu>() * (num_cpus as usize)
91*bb4ee6a4SAndroid Build Coastguard Worker + mem::size_of::<mpc_ioapic>()
92*bb4ee6a4SAndroid Build Coastguard Worker + mem::size_of::<mpc_bus>() * 2
93*bb4ee6a4SAndroid Build Coastguard Worker + mem::size_of::<mpc_intsrc>()
94*bb4ee6a4SAndroid Build Coastguard Worker + mem::size_of::<mpc_intsrc>() * 16
95*bb4ee6a4SAndroid Build Coastguard Worker + mem::size_of::<mpc_lintsrc>() * 2
96*bb4ee6a4SAndroid Build Coastguard Worker }
97*bb4ee6a4SAndroid Build Coastguard Worker
98*bb4ee6a4SAndroid Build Coastguard Worker /// Performs setup of the MP table for the given `num_cpus`.
setup_mptable( mem: &GuestMemory, num_cpus: u8, pci_irqs: &[(PciAddress, u32, PciInterruptPin)], ) -> Result<()>99*bb4ee6a4SAndroid Build Coastguard Worker pub fn setup_mptable(
100*bb4ee6a4SAndroid Build Coastguard Worker mem: &GuestMemory,
101*bb4ee6a4SAndroid Build Coastguard Worker num_cpus: u8,
102*bb4ee6a4SAndroid Build Coastguard Worker pci_irqs: &[(PciAddress, u32, PciInterruptPin)],
103*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
104*bb4ee6a4SAndroid Build Coastguard Worker // Used to keep track of the next base pointer into the MP table.
105*bb4ee6a4SAndroid Build Coastguard Worker let mut base_mp = GuestAddress(MPTABLE_START);
106*bb4ee6a4SAndroid Build Coastguard Worker
107*bb4ee6a4SAndroid Build Coastguard Worker // Calculate ISA bus number in the system, report at least one PCI bus.
108*bb4ee6a4SAndroid Build Coastguard Worker let isa_bus_id = match pci_irqs.iter().max_by_key(|v| v.0.bus) {
109*bb4ee6a4SAndroid Build Coastguard Worker Some(pci_irq) => pci_irq.0.bus + 1,
110*bb4ee6a4SAndroid Build Coastguard Worker _ => 1,
111*bb4ee6a4SAndroid Build Coastguard Worker };
112*bb4ee6a4SAndroid Build Coastguard Worker let mp_size = compute_mp_size(num_cpus);
113*bb4ee6a4SAndroid Build Coastguard Worker
114*bb4ee6a4SAndroid Build Coastguard Worker // The checked_add here ensures the all of the following base_mp.unchecked_add's will be without
115*bb4ee6a4SAndroid Build Coastguard Worker // overflow.
116*bb4ee6a4SAndroid Build Coastguard Worker if let Some(end_mp) = base_mp.checked_add(mp_size as u64 - 1) {
117*bb4ee6a4SAndroid Build Coastguard Worker if !mem.address_in_range(end_mp) {
118*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::NotEnoughMemory);
119*bb4ee6a4SAndroid Build Coastguard Worker }
120*bb4ee6a4SAndroid Build Coastguard Worker } else {
121*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::AddressOverflow);
122*bb4ee6a4SAndroid Build Coastguard Worker }
123*bb4ee6a4SAndroid Build Coastguard Worker
124*bb4ee6a4SAndroid Build Coastguard Worker mem.get_slice_at_addr(base_mp, mp_size)
125*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::Clear)?
126*bb4ee6a4SAndroid Build Coastguard Worker .write_bytes(0);
127*bb4ee6a4SAndroid Build Coastguard Worker
128*bb4ee6a4SAndroid Build Coastguard Worker {
129*bb4ee6a4SAndroid Build Coastguard Worker let size = mem::size_of::<mpf_intel>();
130*bb4ee6a4SAndroid Build Coastguard Worker let mut mpf_intel = mpf_intel::default();
131*bb4ee6a4SAndroid Build Coastguard Worker mpf_intel.signature = SMP_MAGIC_IDENT;
132*bb4ee6a4SAndroid Build Coastguard Worker mpf_intel.length = 1;
133*bb4ee6a4SAndroid Build Coastguard Worker mpf_intel.specification = 4;
134*bb4ee6a4SAndroid Build Coastguard Worker mpf_intel.physptr = (base_mp.offset() + mem::size_of::<mpf_intel>() as u64) as u32;
135*bb4ee6a4SAndroid Build Coastguard Worker mpf_intel.checksum = mpf_intel_compute_checksum(&mpf_intel);
136*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpf_intel, base_mp)
137*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpfIntel)?;
138*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(size as u64);
139*bb4ee6a4SAndroid Build Coastguard Worker }
140*bb4ee6a4SAndroid Build Coastguard Worker
141*bb4ee6a4SAndroid Build Coastguard Worker // We set the location of the mpc_table here but we can't fill it out until we have the length
142*bb4ee6a4SAndroid Build Coastguard Worker // of the entire table later.
143*bb4ee6a4SAndroid Build Coastguard Worker let table_base = base_mp;
144*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(mem::size_of::<mpc_table>() as u64);
145*bb4ee6a4SAndroid Build Coastguard Worker
146*bb4ee6a4SAndroid Build Coastguard Worker let mut checksum: u8 = 0;
147*bb4ee6a4SAndroid Build Coastguard Worker let ioapicid: u8 = num_cpus + 1;
148*bb4ee6a4SAndroid Build Coastguard Worker
149*bb4ee6a4SAndroid Build Coastguard Worker for cpu_id in 0..num_cpus {
150*bb4ee6a4SAndroid Build Coastguard Worker let size = mem::size_of::<mpc_cpu>();
151*bb4ee6a4SAndroid Build Coastguard Worker let mpc_cpu = mpc_cpu {
152*bb4ee6a4SAndroid Build Coastguard Worker type_: MP_PROCESSOR as u8,
153*bb4ee6a4SAndroid Build Coastguard Worker apicid: cpu_id,
154*bb4ee6a4SAndroid Build Coastguard Worker apicver: APIC_VERSION,
155*bb4ee6a4SAndroid Build Coastguard Worker cpuflag: CPU_ENABLED as u8
156*bb4ee6a4SAndroid Build Coastguard Worker | if cpu_id == 0 {
157*bb4ee6a4SAndroid Build Coastguard Worker CPU_BOOTPROCESSOR as u8
158*bb4ee6a4SAndroid Build Coastguard Worker } else {
159*bb4ee6a4SAndroid Build Coastguard Worker 0
160*bb4ee6a4SAndroid Build Coastguard Worker },
161*bb4ee6a4SAndroid Build Coastguard Worker cpufeature: CPU_STEPPING,
162*bb4ee6a4SAndroid Build Coastguard Worker featureflag: CPU_FEATURE_APIC | CPU_FEATURE_FPU,
163*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
164*bb4ee6a4SAndroid Build Coastguard Worker };
165*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpc_cpu, base_mp)
166*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpcCpu)?;
167*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(size as u64);
168*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(compute_checksum(&mpc_cpu));
169*bb4ee6a4SAndroid Build Coastguard Worker }
170*bb4ee6a4SAndroid Build Coastguard Worker {
171*bb4ee6a4SAndroid Build Coastguard Worker let size = mem::size_of::<mpc_ioapic>();
172*bb4ee6a4SAndroid Build Coastguard Worker let mpc_ioapic = mpc_ioapic {
173*bb4ee6a4SAndroid Build Coastguard Worker type_: MP_IOAPIC as u8,
174*bb4ee6a4SAndroid Build Coastguard Worker apicid: ioapicid,
175*bb4ee6a4SAndroid Build Coastguard Worker apicver: APIC_VERSION,
176*bb4ee6a4SAndroid Build Coastguard Worker flags: MPC_APIC_USABLE as u8,
177*bb4ee6a4SAndroid Build Coastguard Worker apicaddr: IO_APIC_DEFAULT_PHYS_BASE,
178*bb4ee6a4SAndroid Build Coastguard Worker };
179*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpc_ioapic, base_mp)
180*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpcIoapic)?;
181*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(size as u64);
182*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(compute_checksum(&mpc_ioapic));
183*bb4ee6a4SAndroid Build Coastguard Worker }
184*bb4ee6a4SAndroid Build Coastguard Worker for pci_bus_id in 0..isa_bus_id {
185*bb4ee6a4SAndroid Build Coastguard Worker let size = mem::size_of::<mpc_bus>();
186*bb4ee6a4SAndroid Build Coastguard Worker let mpc_bus = mpc_bus {
187*bb4ee6a4SAndroid Build Coastguard Worker type_: MP_BUS as u8,
188*bb4ee6a4SAndroid Build Coastguard Worker busid: pci_bus_id,
189*bb4ee6a4SAndroid Build Coastguard Worker bustype: BUS_TYPE_PCI,
190*bb4ee6a4SAndroid Build Coastguard Worker };
191*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpc_bus, base_mp)
192*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpcBus)?;
193*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(size as u64);
194*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(compute_checksum(&mpc_bus));
195*bb4ee6a4SAndroid Build Coastguard Worker }
196*bb4ee6a4SAndroid Build Coastguard Worker {
197*bb4ee6a4SAndroid Build Coastguard Worker let size = mem::size_of::<mpc_bus>();
198*bb4ee6a4SAndroid Build Coastguard Worker let mpc_bus = mpc_bus {
199*bb4ee6a4SAndroid Build Coastguard Worker type_: MP_BUS as u8,
200*bb4ee6a4SAndroid Build Coastguard Worker busid: isa_bus_id,
201*bb4ee6a4SAndroid Build Coastguard Worker bustype: BUS_TYPE_ISA,
202*bb4ee6a4SAndroid Build Coastguard Worker };
203*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpc_bus, base_mp)
204*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpcBus)?;
205*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(size as u64);
206*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(compute_checksum(&mpc_bus));
207*bb4ee6a4SAndroid Build Coastguard Worker }
208*bb4ee6a4SAndroid Build Coastguard Worker {
209*bb4ee6a4SAndroid Build Coastguard Worker let size = mem::size_of::<mpc_intsrc>();
210*bb4ee6a4SAndroid Build Coastguard Worker let mpc_intsrc = mpc_intsrc {
211*bb4ee6a4SAndroid Build Coastguard Worker type_: MP_LINTSRC as u8,
212*bb4ee6a4SAndroid Build Coastguard Worker irqtype: mp_irq_source_types_mp_INT as u8,
213*bb4ee6a4SAndroid Build Coastguard Worker irqflag: MP_IRQDIR_DEFAULT as u16,
214*bb4ee6a4SAndroid Build Coastguard Worker srcbus: isa_bus_id,
215*bb4ee6a4SAndroid Build Coastguard Worker srcbusirq: 0,
216*bb4ee6a4SAndroid Build Coastguard Worker dstapic: 0,
217*bb4ee6a4SAndroid Build Coastguard Worker dstirq: 0,
218*bb4ee6a4SAndroid Build Coastguard Worker };
219*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpc_intsrc, base_mp)
220*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpcIntsrc)?;
221*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(size as u64);
222*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
223*bb4ee6a4SAndroid Build Coastguard Worker }
224*bb4ee6a4SAndroid Build Coastguard Worker let sci_irq = super::X86_64_SCI_IRQ as u8;
225*bb4ee6a4SAndroid Build Coastguard Worker // Per kvm_setup_default_irq_routing() in kernel
226*bb4ee6a4SAndroid Build Coastguard Worker for i in (0..sci_irq).chain(std::iter::once(devices::cmos::RTC_IRQ)) {
227*bb4ee6a4SAndroid Build Coastguard Worker let size = mem::size_of::<mpc_intsrc>();
228*bb4ee6a4SAndroid Build Coastguard Worker let mpc_intsrc = mpc_intsrc {
229*bb4ee6a4SAndroid Build Coastguard Worker type_: MP_INTSRC as u8,
230*bb4ee6a4SAndroid Build Coastguard Worker irqtype: mp_irq_source_types_mp_INT as u8,
231*bb4ee6a4SAndroid Build Coastguard Worker irqflag: MP_IRQDIR_DEFAULT as u16,
232*bb4ee6a4SAndroid Build Coastguard Worker srcbus: isa_bus_id,
233*bb4ee6a4SAndroid Build Coastguard Worker srcbusirq: i,
234*bb4ee6a4SAndroid Build Coastguard Worker dstapic: ioapicid,
235*bb4ee6a4SAndroid Build Coastguard Worker dstirq: i,
236*bb4ee6a4SAndroid Build Coastguard Worker };
237*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpc_intsrc, base_mp)
238*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpcIntsrc)?;
239*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(size as u64);
240*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
241*bb4ee6a4SAndroid Build Coastguard Worker }
242*bb4ee6a4SAndroid Build Coastguard Worker // Insert SCI interrupt before PCI interrupts. Set the SCI interrupt
243*bb4ee6a4SAndroid Build Coastguard Worker // to be the default trigger/polarity of PCI bus, which is level/low.
244*bb4ee6a4SAndroid Build Coastguard Worker // This setting can be changed in future if necessary.
245*bb4ee6a4SAndroid Build Coastguard Worker {
246*bb4ee6a4SAndroid Build Coastguard Worker let size = mem::size_of::<mpc_intsrc>();
247*bb4ee6a4SAndroid Build Coastguard Worker let mpc_intsrc = mpc_intsrc {
248*bb4ee6a4SAndroid Build Coastguard Worker type_: MP_INTSRC as u8,
249*bb4ee6a4SAndroid Build Coastguard Worker irqtype: mp_irq_source_types_mp_INT as u8,
250*bb4ee6a4SAndroid Build Coastguard Worker irqflag: (MP_IRQDIR_HIGH | MP_LEVEL_TRIGGER) as u16,
251*bb4ee6a4SAndroid Build Coastguard Worker srcbus: isa_bus_id,
252*bb4ee6a4SAndroid Build Coastguard Worker srcbusirq: sci_irq,
253*bb4ee6a4SAndroid Build Coastguard Worker dstapic: ioapicid,
254*bb4ee6a4SAndroid Build Coastguard Worker dstirq: sci_irq,
255*bb4ee6a4SAndroid Build Coastguard Worker };
256*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpc_intsrc, base_mp)
257*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpcIntsrc)?;
258*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(size as u64);
259*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
260*bb4ee6a4SAndroid Build Coastguard Worker }
261*bb4ee6a4SAndroid Build Coastguard Worker
262*bb4ee6a4SAndroid Build Coastguard Worker // Insert PCI interrupts after platform IRQs.
263*bb4ee6a4SAndroid Build Coastguard Worker for (address, irq_num, irq_pin) in pci_irqs.iter() {
264*bb4ee6a4SAndroid Build Coastguard Worker let size = mem::size_of::<mpc_intsrc>();
265*bb4ee6a4SAndroid Build Coastguard Worker let mpc_intsrc = mpc_intsrc {
266*bb4ee6a4SAndroid Build Coastguard Worker type_: MP_INTSRC as u8,
267*bb4ee6a4SAndroid Build Coastguard Worker irqtype: mp_irq_source_types_mp_INT as u8,
268*bb4ee6a4SAndroid Build Coastguard Worker irqflag: MP_IRQDIR_DEFAULT as u16,
269*bb4ee6a4SAndroid Build Coastguard Worker srcbus: address.bus,
270*bb4ee6a4SAndroid Build Coastguard Worker srcbusirq: address.dev << 2 | irq_pin.to_mask() as u8,
271*bb4ee6a4SAndroid Build Coastguard Worker dstapic: ioapicid,
272*bb4ee6a4SAndroid Build Coastguard Worker dstirq: u8::try_from(*irq_num).map_err(|_| Error::WriteMpcIntsrc)?,
273*bb4ee6a4SAndroid Build Coastguard Worker };
274*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpc_intsrc, base_mp)
275*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpcIntsrc)?;
276*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(size as u64);
277*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
278*bb4ee6a4SAndroid Build Coastguard Worker }
279*bb4ee6a4SAndroid Build Coastguard Worker
280*bb4ee6a4SAndroid Build Coastguard Worker let starting_isa_irq_num = pci_irqs
281*bb4ee6a4SAndroid Build Coastguard Worker .iter()
282*bb4ee6a4SAndroid Build Coastguard Worker .map(|(_, irq_num, _)| irq_num + 1)
283*bb4ee6a4SAndroid Build Coastguard Worker .fold(super::X86_64_IRQ_BASE, u32::max) as u8;
284*bb4ee6a4SAndroid Build Coastguard Worker
285*bb4ee6a4SAndroid Build Coastguard Worker // Finally insert ISA interrupts.
286*bb4ee6a4SAndroid Build Coastguard Worker for i in starting_isa_irq_num..16 {
287*bb4ee6a4SAndroid Build Coastguard Worker let size = mem::size_of::<mpc_intsrc>();
288*bb4ee6a4SAndroid Build Coastguard Worker let mpc_intsrc = mpc_intsrc {
289*bb4ee6a4SAndroid Build Coastguard Worker type_: MP_INTSRC as u8,
290*bb4ee6a4SAndroid Build Coastguard Worker irqtype: mp_irq_source_types_mp_INT as u8,
291*bb4ee6a4SAndroid Build Coastguard Worker irqflag: MP_IRQDIR_DEFAULT as u16,
292*bb4ee6a4SAndroid Build Coastguard Worker srcbus: isa_bus_id,
293*bb4ee6a4SAndroid Build Coastguard Worker srcbusirq: i,
294*bb4ee6a4SAndroid Build Coastguard Worker dstapic: ioapicid,
295*bb4ee6a4SAndroid Build Coastguard Worker dstirq: i,
296*bb4ee6a4SAndroid Build Coastguard Worker };
297*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpc_intsrc, base_mp)
298*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpcIntsrc)?;
299*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(size as u64);
300*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
301*bb4ee6a4SAndroid Build Coastguard Worker }
302*bb4ee6a4SAndroid Build Coastguard Worker {
303*bb4ee6a4SAndroid Build Coastguard Worker let size = mem::size_of::<mpc_lintsrc>();
304*bb4ee6a4SAndroid Build Coastguard Worker let mpc_lintsrc = mpc_lintsrc {
305*bb4ee6a4SAndroid Build Coastguard Worker type_: MP_LINTSRC as u8,
306*bb4ee6a4SAndroid Build Coastguard Worker irqtype: mp_irq_source_types_mp_ExtINT as u8,
307*bb4ee6a4SAndroid Build Coastguard Worker irqflag: MP_IRQDIR_DEFAULT as u16,
308*bb4ee6a4SAndroid Build Coastguard Worker srcbusid: isa_bus_id,
309*bb4ee6a4SAndroid Build Coastguard Worker srcbusirq: 0,
310*bb4ee6a4SAndroid Build Coastguard Worker destapic: 0,
311*bb4ee6a4SAndroid Build Coastguard Worker destapiclint: 0,
312*bb4ee6a4SAndroid Build Coastguard Worker };
313*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpc_lintsrc, base_mp)
314*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpcLintsrc)?;
315*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(size as u64);
316*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(compute_checksum(&mpc_lintsrc));
317*bb4ee6a4SAndroid Build Coastguard Worker }
318*bb4ee6a4SAndroid Build Coastguard Worker {
319*bb4ee6a4SAndroid Build Coastguard Worker let size = mem::size_of::<mpc_lintsrc>();
320*bb4ee6a4SAndroid Build Coastguard Worker let mpc_lintsrc = mpc_lintsrc {
321*bb4ee6a4SAndroid Build Coastguard Worker type_: MP_LINTSRC as u8,
322*bb4ee6a4SAndroid Build Coastguard Worker irqtype: mp_irq_source_types_mp_NMI as u8,
323*bb4ee6a4SAndroid Build Coastguard Worker irqflag: MP_IRQDIR_DEFAULT as u16,
324*bb4ee6a4SAndroid Build Coastguard Worker srcbusid: isa_bus_id,
325*bb4ee6a4SAndroid Build Coastguard Worker srcbusirq: 0,
326*bb4ee6a4SAndroid Build Coastguard Worker destapic: 0xFF, // Per SeaBIOS
327*bb4ee6a4SAndroid Build Coastguard Worker destapiclint: 1,
328*bb4ee6a4SAndroid Build Coastguard Worker };
329*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpc_lintsrc, base_mp)
330*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpcLintsrc)?;
331*bb4ee6a4SAndroid Build Coastguard Worker base_mp = base_mp.unchecked_add(size as u64);
332*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(compute_checksum(&mpc_lintsrc));
333*bb4ee6a4SAndroid Build Coastguard Worker }
334*bb4ee6a4SAndroid Build Coastguard Worker
335*bb4ee6a4SAndroid Build Coastguard Worker // At this point we know the size of the mp_table.
336*bb4ee6a4SAndroid Build Coastguard Worker let table_end = base_mp;
337*bb4ee6a4SAndroid Build Coastguard Worker
338*bb4ee6a4SAndroid Build Coastguard Worker {
339*bb4ee6a4SAndroid Build Coastguard Worker let mut mpc_table = mpc_table {
340*bb4ee6a4SAndroid Build Coastguard Worker signature: MPC_SIGNATURE,
341*bb4ee6a4SAndroid Build Coastguard Worker length: table_end.offset_from(table_base) as u16,
342*bb4ee6a4SAndroid Build Coastguard Worker spec: MPC_SPEC,
343*bb4ee6a4SAndroid Build Coastguard Worker oem: MPC_OEM,
344*bb4ee6a4SAndroid Build Coastguard Worker productid: MPC_PRODUCT_ID,
345*bb4ee6a4SAndroid Build Coastguard Worker lapic: APIC_DEFAULT_PHYS_BASE,
346*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
347*bb4ee6a4SAndroid Build Coastguard Worker };
348*bb4ee6a4SAndroid Build Coastguard Worker checksum = checksum.wrapping_add(compute_checksum(&mpc_table));
349*bb4ee6a4SAndroid Build Coastguard Worker mpc_table.checksum = (!checksum).wrapping_add(1) as i8;
350*bb4ee6a4SAndroid Build Coastguard Worker mem.write_obj_at_addr(mpc_table, table_base)
351*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::WriteMpcTable)?;
352*bb4ee6a4SAndroid Build Coastguard Worker }
353*bb4ee6a4SAndroid Build Coastguard Worker
354*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
355*bb4ee6a4SAndroid Build Coastguard Worker }
356*bb4ee6a4SAndroid Build Coastguard Worker
357*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
358*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
359*bb4ee6a4SAndroid Build Coastguard Worker use base::pagesize;
360*bb4ee6a4SAndroid Build Coastguard Worker
361*bb4ee6a4SAndroid Build Coastguard Worker use super::*;
362*bb4ee6a4SAndroid Build Coastguard Worker
compute_page_aligned_mp_size(num_cpus: u8) -> u64363*bb4ee6a4SAndroid Build Coastguard Worker fn compute_page_aligned_mp_size(num_cpus: u8) -> u64 {
364*bb4ee6a4SAndroid Build Coastguard Worker let mp_size = compute_mp_size(num_cpus);
365*bb4ee6a4SAndroid Build Coastguard Worker let pg_size = pagesize();
366*bb4ee6a4SAndroid Build Coastguard Worker (mp_size + pg_size - (mp_size % pg_size)) as u64
367*bb4ee6a4SAndroid Build Coastguard Worker }
368*bb4ee6a4SAndroid Build Coastguard Worker
table_entry_size(type_: u8) -> usize369*bb4ee6a4SAndroid Build Coastguard Worker fn table_entry_size(type_: u8) -> usize {
370*bb4ee6a4SAndroid Build Coastguard Worker match type_ as u32 {
371*bb4ee6a4SAndroid Build Coastguard Worker MP_PROCESSOR => mem::size_of::<mpc_cpu>(),
372*bb4ee6a4SAndroid Build Coastguard Worker MP_BUS => mem::size_of::<mpc_bus>(),
373*bb4ee6a4SAndroid Build Coastguard Worker MP_IOAPIC => mem::size_of::<mpc_ioapic>(),
374*bb4ee6a4SAndroid Build Coastguard Worker MP_INTSRC => mem::size_of::<mpc_intsrc>(),
375*bb4ee6a4SAndroid Build Coastguard Worker MP_LINTSRC => mem::size_of::<mpc_lintsrc>(),
376*bb4ee6a4SAndroid Build Coastguard Worker _ => panic!("unrecognized mpc table entry type: {}", type_),
377*bb4ee6a4SAndroid Build Coastguard Worker }
378*bb4ee6a4SAndroid Build Coastguard Worker }
379*bb4ee6a4SAndroid Build Coastguard Worker
380*bb4ee6a4SAndroid Build Coastguard Worker #[test]
bounds_check()381*bb4ee6a4SAndroid Build Coastguard Worker fn bounds_check() {
382*bb4ee6a4SAndroid Build Coastguard Worker let num_cpus = 4;
383*bb4ee6a4SAndroid Build Coastguard Worker let mem = GuestMemory::new(&[(
384*bb4ee6a4SAndroid Build Coastguard Worker GuestAddress(MPTABLE_START),
385*bb4ee6a4SAndroid Build Coastguard Worker compute_page_aligned_mp_size(num_cpus),
386*bb4ee6a4SAndroid Build Coastguard Worker )])
387*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
388*bb4ee6a4SAndroid Build Coastguard Worker
389*bb4ee6a4SAndroid Build Coastguard Worker setup_mptable(&mem, num_cpus, &[]).unwrap();
390*bb4ee6a4SAndroid Build Coastguard Worker }
391*bb4ee6a4SAndroid Build Coastguard Worker
392*bb4ee6a4SAndroid Build Coastguard Worker #[test]
bounds_check_fails()393*bb4ee6a4SAndroid Build Coastguard Worker fn bounds_check_fails() {
394*bb4ee6a4SAndroid Build Coastguard Worker let num_cpus = 255;
395*bb4ee6a4SAndroid Build Coastguard Worker let mem = GuestMemory::new(&[(GuestAddress(MPTABLE_START), 0x1000)]).unwrap();
396*bb4ee6a4SAndroid Build Coastguard Worker
397*bb4ee6a4SAndroid Build Coastguard Worker assert!(setup_mptable(&mem, num_cpus, &[]).is_err());
398*bb4ee6a4SAndroid Build Coastguard Worker }
399*bb4ee6a4SAndroid Build Coastguard Worker
400*bb4ee6a4SAndroid Build Coastguard Worker #[test]
mpf_intel_checksum()401*bb4ee6a4SAndroid Build Coastguard Worker fn mpf_intel_checksum() {
402*bb4ee6a4SAndroid Build Coastguard Worker let num_cpus = 1;
403*bb4ee6a4SAndroid Build Coastguard Worker let mem = GuestMemory::new(&[(
404*bb4ee6a4SAndroid Build Coastguard Worker GuestAddress(MPTABLE_START),
405*bb4ee6a4SAndroid Build Coastguard Worker compute_page_aligned_mp_size(num_cpus),
406*bb4ee6a4SAndroid Build Coastguard Worker )])
407*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
408*bb4ee6a4SAndroid Build Coastguard Worker
409*bb4ee6a4SAndroid Build Coastguard Worker setup_mptable(&mem, num_cpus, &[]).unwrap();
410*bb4ee6a4SAndroid Build Coastguard Worker
411*bb4ee6a4SAndroid Build Coastguard Worker let mpf_intel = mem.read_obj_from_addr(GuestAddress(MPTABLE_START)).unwrap();
412*bb4ee6a4SAndroid Build Coastguard Worker
413*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(mpf_intel_compute_checksum(&mpf_intel), mpf_intel.checksum);
414*bb4ee6a4SAndroid Build Coastguard Worker }
415*bb4ee6a4SAndroid Build Coastguard Worker
416*bb4ee6a4SAndroid Build Coastguard Worker #[test]
mpc_table_checksum()417*bb4ee6a4SAndroid Build Coastguard Worker fn mpc_table_checksum() {
418*bb4ee6a4SAndroid Build Coastguard Worker let num_cpus = 4;
419*bb4ee6a4SAndroid Build Coastguard Worker let mem = GuestMemory::new(&[(
420*bb4ee6a4SAndroid Build Coastguard Worker GuestAddress(MPTABLE_START),
421*bb4ee6a4SAndroid Build Coastguard Worker compute_page_aligned_mp_size(num_cpus),
422*bb4ee6a4SAndroid Build Coastguard Worker )])
423*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
424*bb4ee6a4SAndroid Build Coastguard Worker
425*bb4ee6a4SAndroid Build Coastguard Worker setup_mptable(&mem, num_cpus, &[]).unwrap();
426*bb4ee6a4SAndroid Build Coastguard Worker
427*bb4ee6a4SAndroid Build Coastguard Worker let mpf_intel: mpf_intel = mem.read_obj_from_addr(GuestAddress(MPTABLE_START)).unwrap();
428*bb4ee6a4SAndroid Build Coastguard Worker let mpc_offset = GuestAddress(mpf_intel.physptr as u64);
429*bb4ee6a4SAndroid Build Coastguard Worker let mpc_table: mpc_table = mem.read_obj_from_addr(mpc_offset).unwrap();
430*bb4ee6a4SAndroid Build Coastguard Worker
431*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = vec![0; mpc_table.length as usize];
432*bb4ee6a4SAndroid Build Coastguard Worker mem.read_at_addr(&mut buf[..], mpc_offset).unwrap();
433*bb4ee6a4SAndroid Build Coastguard Worker let mut sum: u8 = 0;
434*bb4ee6a4SAndroid Build Coastguard Worker for &v in &buf {
435*bb4ee6a4SAndroid Build Coastguard Worker sum = sum.wrapping_add(v);
436*bb4ee6a4SAndroid Build Coastguard Worker }
437*bb4ee6a4SAndroid Build Coastguard Worker
438*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(sum, 0);
439*bb4ee6a4SAndroid Build Coastguard Worker }
440*bb4ee6a4SAndroid Build Coastguard Worker
441*bb4ee6a4SAndroid Build Coastguard Worker #[test]
cpu_entry_count()442*bb4ee6a4SAndroid Build Coastguard Worker fn cpu_entry_count() {
443*bb4ee6a4SAndroid Build Coastguard Worker const MAX_CPUS: u8 = 0xff;
444*bb4ee6a4SAndroid Build Coastguard Worker let mem = GuestMemory::new(&[(
445*bb4ee6a4SAndroid Build Coastguard Worker GuestAddress(MPTABLE_START),
446*bb4ee6a4SAndroid Build Coastguard Worker compute_page_aligned_mp_size(MAX_CPUS),
447*bb4ee6a4SAndroid Build Coastguard Worker )])
448*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
449*bb4ee6a4SAndroid Build Coastguard Worker
450*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..MAX_CPUS {
451*bb4ee6a4SAndroid Build Coastguard Worker setup_mptable(&mem, i, &[]).unwrap();
452*bb4ee6a4SAndroid Build Coastguard Worker
453*bb4ee6a4SAndroid Build Coastguard Worker let mpf_intel: mpf_intel = mem.read_obj_from_addr(GuestAddress(MPTABLE_START)).unwrap();
454*bb4ee6a4SAndroid Build Coastguard Worker let mpc_offset = GuestAddress(mpf_intel.physptr as u64);
455*bb4ee6a4SAndroid Build Coastguard Worker let mpc_table: mpc_table = mem.read_obj_from_addr(mpc_offset).unwrap();
456*bb4ee6a4SAndroid Build Coastguard Worker let mpc_end = mpc_offset.checked_add(mpc_table.length as u64).unwrap();
457*bb4ee6a4SAndroid Build Coastguard Worker
458*bb4ee6a4SAndroid Build Coastguard Worker let mut entry_offset = mpc_offset
459*bb4ee6a4SAndroid Build Coastguard Worker .checked_add(mem::size_of::<mpc_table>() as u64)
460*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
461*bb4ee6a4SAndroid Build Coastguard Worker let mut cpu_count = 0;
462*bb4ee6a4SAndroid Build Coastguard Worker while entry_offset < mpc_end {
463*bb4ee6a4SAndroid Build Coastguard Worker let entry_type: u8 = mem.read_obj_from_addr(entry_offset).unwrap();
464*bb4ee6a4SAndroid Build Coastguard Worker entry_offset = entry_offset
465*bb4ee6a4SAndroid Build Coastguard Worker .checked_add(table_entry_size(entry_type) as u64)
466*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
467*bb4ee6a4SAndroid Build Coastguard Worker assert!(entry_offset <= mpc_end);
468*bb4ee6a4SAndroid Build Coastguard Worker if entry_type as u32 == MP_PROCESSOR {
469*bb4ee6a4SAndroid Build Coastguard Worker cpu_count += 1;
470*bb4ee6a4SAndroid Build Coastguard Worker }
471*bb4ee6a4SAndroid Build Coastguard Worker }
472*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(cpu_count, i);
473*bb4ee6a4SAndroid Build Coastguard Worker }
474*bb4ee6a4SAndroid Build Coastguard Worker }
475*bb4ee6a4SAndroid Build Coastguard Worker }
476