Build the MP Table correctly
This commit is contained in:
parent
8ef4220adf
commit
97d9ef95c5
@ -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())
|
||||
}
|
Loading…
Reference in New Issue
Block a user