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