Build the MP Table correctly

This commit is contained in:
Bruce Leidl 2023-08-02 09:31:37 -04:00
parent 8ef4220adf
commit 97d9ef95c5

View File

@ -1,10 +1,9 @@
use byteorder::{LittleEndian, WriteBytesExt};
use std::io::Write;
use std::iter;
use crate::io::PciIrq;
use crate::memory::GuestRam;
use crate::virtio::PciIrq;
use crate::system::Result;
use crate::util::ByteBuffer;
const APIC_DEFAULT_PHYS_BASE: u32 = 0xfee00000;
const IO_APIC_DEFAULT_PHYS_BASE: u32 = 0xfec00000;
@ -37,16 +36,20 @@ const PCI_BUSTYPE: &[u8] = b"PCI ";
const ISA_BUSID: u8 = 1;
const ISA_BUSTYPE: &[u8] = b"ISA ";
const MPTABLE_START: u64 = 0x9fc00;
const MPC_TABLE_SIZE: usize = 44;
const MPF_INTEL_SIZE: usize = 16;
struct Buffer {
vec: Vec<u8>,
buffer: ByteBuffer<Vec<u8>>,
count: usize,
}
impl Buffer {
fn new() -> Buffer {
Buffer {
vec: Vec::new(),
buffer: ByteBuffer::new_empty().little_endian(),
count: 0,
}
}
@ -81,7 +84,7 @@ impl Buffer {
}
fn write_mpc_bus(&mut self, busid: u8, bustype: &[u8]) -> &mut Self {
assert!(bustype.len() == 6);
assert_eq!(bustype.len(), 6);
self.count += 1;
self.w8(MP_BUS)
.w8(busid)
@ -117,20 +120,24 @@ impl Buffer {
.w8(dstirq) // dest apid lint
}
fn write_mpf_intel(&mut self, address: u32) -> &mut Self {
let start = self.vec.len();
fn write_mpf_intel(&mut self) -> &mut Self {
let start = self.buffer.len();
let config_address = (MPTABLE_START + MPF_INTEL_SIZE as u64) as u32;
self.align(16)
.bytes(b"_MP_") // Signature
.w32(address) // Configuration table address
.w32(config_address) // Configuration table address
.w8(1) // Our length (paragraphs)
.w8(4) // Specification version
.w8(0) // checksum (offset 10)
.pad(5) // feature1 - feature5
.checksum(start, 16, 10)
.checksum(start, MPF_INTEL_SIZE, 10)
}
fn write_mpctable(&mut self, ncpus: u16, body: &Buffer) -> &mut Self {
let len = 44 + body.vec.len();
fn write_mpc_table(&mut self, offset: usize) -> &mut Self {
let old = self.buffer.len();
let len = old - offset;
self.buffer.set_offset(offset);
self.bytes(b"PCMP") // 0 Signature
.w16(len as u16) // 4 length
.w8(4) // 6 Specification version
@ -138,48 +145,50 @@ impl Buffer {
.bytes(b"SUBGRAPH") // 8 oem[8]
.bytes(b"0.1 ") // 16 productid[12]
.w32(0) // 28 oem ptr (0 if not present)
.w16(body.count as u16) // 32 oem size
.w16(ncpus) // 34 oem count
.w16(0) // 32 oem size
.w16(0) // 34 oem count
.w32(APIC_DEFAULT_PHYS_BASE) // 36 APIC address
.w32(0) // 40 reserved
.bytes(&body.vec)
.checksum(0, len, 7)
.checksum(offset, len, 7);
self.buffer.set_offset(old);
self
}
fn w8(&mut self, val: u8) -> &mut Self {
self.vec.push(val);
self.buffer.write(val);
self
}
fn w16(&mut self, data: u16) -> &mut Self {
self.vec.write_u16::<LittleEndian>(data).unwrap();
self.buffer.write(data);
self
}
fn w32(&mut self, data: u32) -> &mut Self {
self.vec.write_u32::<LittleEndian>(data).unwrap();
self.buffer.write(data);
self
}
fn bytes(&mut self, data: &[u8]) -> &mut Self {
self.vec.write(data).unwrap();
self.buffer.write(data);
self
}
fn pad(&mut self, count: usize) -> &mut Self {
if count > 0 {
self.vec.extend(iter::repeat(0).take(count));
let zeros = iter::repeat(0).take(count).collect::<Vec<u8>>();
self.buffer.write(zeros.as_slice());
}
self
}
fn align(&mut self, n: usize) -> &mut Self {
let aligned = align(self.vec.len(), n);
let padlen = aligned - self.vec.len();
let aligned = align(self.buffer.len(), n);
let padlen = aligned - self.buffer.len();
self.pad(padlen)
}
fn checksum(&mut self, start: usize, len: usize, csum_off: usize) -> &mut Self {
{
let slice = &mut self.vec[start..start + len];
let slice = self.buffer.mut_at(start, len);
let csum = slice.iter().fold(0i32, |acc, &x| acc.wrapping_add(x as i32));
let b = (-csum & 0xFF) as u8;
slice[csum_off] = b;
@ -194,19 +203,19 @@ fn align(sz: usize, n: usize) -> usize {
pub fn setup_mptable(memory: &GuestRam, ncpus: usize, pci_irqs: &[PciIrq]) -> Result<()> {
let ioapicid = (ncpus + 1) as u8;
let mut body = Buffer::new();
let address = 0;
let mut buffer = Buffer::new();
let address = MPTABLE_START;
body.write_all_mpc_cpu(ncpus)
buffer.write_mpf_intel()
.pad(MPC_TABLE_SIZE)
.write_all_mpc_cpu(ncpus)
.write_mpc_bus(PCI_BUSID, PCI_BUSTYPE)
.write_mpc_bus(ISA_BUSID, ISA_BUSTYPE)
.write_mpc_ioapic(ioapicid)
.write_all_mpc_intsrc(ioapicid, &pci_irqs)
.write_mpc_lintsrc(MP_IRQ_SRC_INT, 0)
.write_mpc_lintsrc(MP_IRQ_SRC_NMI, 1)
.write_mpf_intel(address);
.write_mpc_table(MPF_INTEL_SIZE);
let mut table = Buffer::new();
table.write_mpctable(ncpus as u16, &body);
memory.write_bytes(address as u64, &table.vec)
memory.write_bytes(address, buffer.buffer.as_ref())
}