parent
eb9a5e9241
commit
936c485ab9
@ -0,0 +1,18 @@
|
|||||||
|
// Migrate from xv6-x86_64 acpi.c
|
||||||
|
|
||||||
|
mod structs;
|
||||||
|
use self::structs::*;
|
||||||
|
|
||||||
|
/// See https://wiki.osdev.org/RSDP -- Detecting the RSDP
|
||||||
|
pub fn find_rdsp() -> Option<*const rsdp> {
|
||||||
|
use util::{Checkable, find_in_memory};
|
||||||
|
let ebda = unsafe { *(0x40E as *const u16) as usize } << 4;
|
||||||
|
println!("EBDA at {:#x}", ebda);
|
||||||
|
if ebda != 0 {
|
||||||
|
if let Some(addr) = unsafe{ find_in_memory::<rsdp>(ebda as usize, 1024, 4) } {
|
||||||
|
return Some(addr as *const rsdp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe{ find_in_memory::<rsdp>(0xE0000, 0x20000, 4).map(|addr| addr as *const rsdp) }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
|||||||
|
// Reference: xv6-x86_64 acpi.h
|
||||||
|
// Copy from crate 'acpica-sys'
|
||||||
|
|
||||||
|
use util::{Checkable, bytes_sum};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct rsdp {
|
||||||
|
pub Signature: [u8; 8],
|
||||||
|
pub Checksum: u8,
|
||||||
|
pub OemId: [i8; 6],
|
||||||
|
pub Revision: u8,
|
||||||
|
pub RsdtPhysicalAddress: u32,
|
||||||
|
pub Length: u32,
|
||||||
|
pub XsdtPhysicalAddress: u64,
|
||||||
|
pub ExtendedChecksum: u8,
|
||||||
|
pub Reserved: [u8; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Checkable for rsdp {
|
||||||
|
fn check(&self) -> bool {
|
||||||
|
&self.Signature == b"RSD PTR " && bytes_sum(self) == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct header {
|
||||||
|
pub Signature: [i8; 4],
|
||||||
|
pub Length: u32,
|
||||||
|
pub Revision: u8,
|
||||||
|
pub Checksum: u8,
|
||||||
|
pub OemId: [i8; 6],
|
||||||
|
pub OemTableId: [i8; 8],
|
||||||
|
pub OemRevision: u32,
|
||||||
|
pub AslCompilerId: [i8; 4],
|
||||||
|
pub AslCompilerRevision: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct rsdt {
|
||||||
|
pub Header: header,
|
||||||
|
pub TableOffsetEntry: [u32; 1],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct madt {
|
||||||
|
pub Header: header,
|
||||||
|
pub Address: u32,
|
||||||
|
pub Flags: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
const MADT_SIGNATURE: [u8; 4] = *b"APIC";
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct madt_local_apic {
|
||||||
|
pub Type: u8,
|
||||||
|
pub Length: u8,
|
||||||
|
pub ProcessorId: u8,
|
||||||
|
pub Id: u8,
|
||||||
|
pub LapicFlags: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct madt_io_apic {
|
||||||
|
pub Type: u8,
|
||||||
|
pub Length: u8,
|
||||||
|
pub Id: u8,
|
||||||
|
pub Reserved: u8,
|
||||||
|
pub Address: u32,
|
||||||
|
pub GlobalIrqBase: u32,
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
// Migrate from xv6 ioapic.c
|
||||||
|
|
||||||
|
/// The I/O APIC manages hardware interrupts for an SMP system.
|
||||||
|
/// http://www.intel.com/design/chipsets/datashts/29056601.pdf
|
||||||
|
/// See also picirq.c.
|
||||||
|
|
||||||
|
use core::ptr::{read_volatile, write_volatile};
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const IOAPIC_ADDRESS : u32 = 0xFEC00000; // Default physical address of IO APIC
|
||||||
|
|
||||||
|
const REG_ID : u32 = 0x00; // Register index: ID
|
||||||
|
const REG_VER : u32 = 0x01; // Register index: version
|
||||||
|
const REG_TABLE : u32 = 0x10; // Redirection table base
|
||||||
|
|
||||||
|
// The redirection table starts at REG_TABLE and uses
|
||||||
|
// two registers to configure each interrupt.
|
||||||
|
// The first (low) register in a pair contains configuration bits.
|
||||||
|
// The second (high) register contains a bitmask telling which
|
||||||
|
// CPUs can serve that interrupt.
|
||||||
|
const INT_DISABLED : u32 = 0x00010000; // Interrupt disabled
|
||||||
|
const INT_LEVEL : u32 = 0x00008000; // Level-triggered (vs edge-)
|
||||||
|
const INT_ACTIVELOW : u32 = 0x00002000; // Active low (vs high)
|
||||||
|
const INT_LOGICAL : u32 = 0x00000800; // Destination is CPU id (vs APIC ID)
|
||||||
|
|
||||||
|
// static IOAPIC: *mut IoApic = IOAPIC_ADDRESS as *mut _;
|
||||||
|
|
||||||
|
const ioapicid: u32 = 0; // TODO fix
|
||||||
|
const T_IRQ0: u32 = 32;
|
||||||
|
|
||||||
|
// IO APIC MMIO structure: write reg, then read or write data.
|
||||||
|
#[repr(C)]
|
||||||
|
struct IoApic {
|
||||||
|
reg: u32,
|
||||||
|
pad: [u32; 3],
|
||||||
|
data: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IoApic {
|
||||||
|
unsafe fn read(&mut self, reg: u32) -> u32
|
||||||
|
{
|
||||||
|
write_volatile(&mut self.reg as *mut _, reg);
|
||||||
|
read_volatile(&self.data as *const _)
|
||||||
|
}
|
||||||
|
unsafe fn write(&mut self, reg: u32, data: u32)
|
||||||
|
{
|
||||||
|
write_volatile(&mut self.reg as *mut _, reg);
|
||||||
|
write_volatile(&mut self.data as *mut _, data);
|
||||||
|
}
|
||||||
|
unsafe fn init(&mut self)
|
||||||
|
{
|
||||||
|
let maxintr = (self.read(REG_VER) >> 16) & 0xFF;
|
||||||
|
let id = self.read(REG_ID) >> 24;
|
||||||
|
if id != ioapicid {
|
||||||
|
println!("ioapicinit: id isn't equal to ioapicid; not a MP");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark all interrupts edge-triggered, active high, disabled,
|
||||||
|
// and not routed to any CPUs.
|
||||||
|
for i in 0 .. maxintr+1 {
|
||||||
|
self.write(REG_TABLE+2*i, INT_DISABLED | (T_IRQ0 + i));
|
||||||
|
self.write(REG_TABLE+2*i+1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe fn enable(&mut self, irq: u32, cpunum: u32)
|
||||||
|
{
|
||||||
|
// Mark interrupt edge-triggered, active high,
|
||||||
|
// enabled, and routed to the given cpunum,
|
||||||
|
// which happens to be that cpu's APIC ID.
|
||||||
|
self.write(REG_TABLE+2*irq, T_IRQ0 + irq);
|
||||||
|
self.write(REG_TABLE+2*irq+1, cpunum << 24);
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,4 @@
|
|||||||
pub mod vga;
|
pub mod vga;
|
||||||
|
pub mod acpi;
|
||||||
|
pub mod ioapic;
|
||||||
|
pub mod mp;
|
@ -0,0 +1,113 @@
|
|||||||
|
// Migrate from xv6 mp.c
|
||||||
|
|
||||||
|
// Multiprocessor support
|
||||||
|
// Search memory for MP description structures.
|
||||||
|
// http://developer.intel.com/design/pentium/datashts/24201606.pdf
|
||||||
|
|
||||||
|
mod structs;
|
||||||
|
use self::structs::*;
|
||||||
|
|
||||||
|
/// Search for the MP Floating Pointer Structure, which according to the
|
||||||
|
/// spec is in one of the following three locations:
|
||||||
|
/// 1) in the first KB of the EBDA;
|
||||||
|
/// 2) in the last KB of system base memory;
|
||||||
|
/// 3) in the BIOS ROM address space between 0F0000h and 0FFFFFh.
|
||||||
|
pub fn find_mp() -> Option<*const MP>
|
||||||
|
{
|
||||||
|
use core::mem::size_of;
|
||||||
|
use util::find_in_memory;
|
||||||
|
let ebda = unsafe { *(0x40E as *const u16) as usize } << 4;
|
||||||
|
if ebda != 0 {
|
||||||
|
let res = unsafe{ find_in_memory::<MP>(ebda, 1024, size_of::<MP>()) };
|
||||||
|
if let Some(addr) = res {
|
||||||
|
return Some(addr as *const MP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let p = unsafe { *(0x413 as *const u16) as usize } << 10;
|
||||||
|
let res = unsafe{ find_in_memory::<MP>(p-1024, 1024, size_of::<MP>()) };
|
||||||
|
if let Some(addr) = res {
|
||||||
|
return Some(addr as *const MP);
|
||||||
|
}
|
||||||
|
let res = unsafe{ find_in_memory::<MP>(0xF0000, 0x10000, size_of::<MP>()) };
|
||||||
|
res.map(|addr| addr as *const MP)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
struct cpu cpus[NCPU];
|
||||||
|
int ncpu;
|
||||||
|
uchar ioapicid;
|
||||||
|
|
||||||
|
// Search for an MP configuration table. For now,
|
||||||
|
// don't accept the default configurations (physaddr == 0).
|
||||||
|
// Check for correct signature, calculate the checksum and,
|
||||||
|
// if correct, check the version.
|
||||||
|
// To do: check extended table checksum.
|
||||||
|
static struct mpconf*
|
||||||
|
mpconfig(struct mp **pmp)
|
||||||
|
{
|
||||||
|
struct mpconf *conf;
|
||||||
|
struct mp *mp;
|
||||||
|
|
||||||
|
if((mp = mpsearch()) == 0 || mp->physaddr == 0)
|
||||||
|
return 0;
|
||||||
|
conf = (struct mpconf*) P2V((uint) mp->physaddr);
|
||||||
|
if(memcmp(conf, "PCMP", 4) != 0)
|
||||||
|
return 0;
|
||||||
|
if(conf->version != 1 && conf->version != 4)
|
||||||
|
return 0;
|
||||||
|
if(sum((uchar*)conf, conf->length) != 0)
|
||||||
|
return 0;
|
||||||
|
*pmp = mp;
|
||||||
|
return conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mpinit(void)
|
||||||
|
{
|
||||||
|
uchar *p, *e;
|
||||||
|
int ismp;
|
||||||
|
struct mp *mp;
|
||||||
|
struct mpconf *conf;
|
||||||
|
struct mpproc *proc;
|
||||||
|
struct mpioapic *ioapic;
|
||||||
|
|
||||||
|
if((conf = mpconfig(&mp)) == 0)
|
||||||
|
panic("Expect to run on an SMP");
|
||||||
|
ismp = 1;
|
||||||
|
lapic = (uint*)conf->lapicaddr;
|
||||||
|
for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
|
||||||
|
switch(*p){
|
||||||
|
case MPPROC:
|
||||||
|
proc = (struct mpproc*)p;
|
||||||
|
if(ncpu < NCPU) {
|
||||||
|
cpus[ncpu].apicid = proc->apicid; // apicid may differ from ncpu
|
||||||
|
ncpu++;
|
||||||
|
}
|
||||||
|
p += sizeof(struct mpproc);
|
||||||
|
continue;
|
||||||
|
case MPIOAPIC:
|
||||||
|
ioapic = (struct mpioapic*)p;
|
||||||
|
ioapicid = ioapic->apicno;
|
||||||
|
p += sizeof(struct mpioapic);
|
||||||
|
continue;
|
||||||
|
case MPBUS:
|
||||||
|
case MPIOINTR:
|
||||||
|
case MPLINTR:
|
||||||
|
p += 8;
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
ismp = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!ismp)
|
||||||
|
panic("Didn't find a suitable machine");
|
||||||
|
|
||||||
|
if(mp->imcrp){
|
||||||
|
// Bochs doesn't support IMCR, so this doesn't run on Bochs.
|
||||||
|
// But it would on real hardware.
|
||||||
|
outb(0x22, 0x70); // Select IMCR
|
||||||
|
outb(0x23, inb(0x23) | 1); // Mask external interrupts.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
@ -0,0 +1,74 @@
|
|||||||
|
// Migrate from xv6 mp.h
|
||||||
|
|
||||||
|
// See MultiProcessor Specification Version 1.[14]
|
||||||
|
|
||||||
|
use util::{Checkable, bytes_sum};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MP { // floating pointer
|
||||||
|
signature: [u8; 4], // "_MP_"
|
||||||
|
physaddr: u32, // phys addr of MP config table
|
||||||
|
length: u8, // 1
|
||||||
|
specrev: u8, // [14]
|
||||||
|
checksum: u8, // all bytes must add up to 0
|
||||||
|
type_: u8, // MP system config type
|
||||||
|
imcrp: u8,
|
||||||
|
reserved: [u8; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Checkable for MP {
|
||||||
|
fn check(&self) -> bool {
|
||||||
|
&self.signature == b"_MP_" && bytes_sum(self) == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct mpconf { // configuration table header
|
||||||
|
signature: [byte; 4]; // "PCMP"
|
||||||
|
length: u16, // total table length
|
||||||
|
version: u8, // [14]
|
||||||
|
checksum: u8, // all bytes must add up to 0
|
||||||
|
product: [u8; 20], // product id
|
||||||
|
uint *oemtable, // OEM table pointer
|
||||||
|
ushort oemlength, // OEM table length
|
||||||
|
ushort entry, // entry count
|
||||||
|
uint *lapicaddr, // address of local APIC
|
||||||
|
ushort xlength, // extended table length
|
||||||
|
u8 xchecksum, // extended table checksum
|
||||||
|
u8 reserved,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct mpproc { // processor table entry
|
||||||
|
u8 type; // entry type (0)
|
||||||
|
u8 apicid; // local APIC id
|
||||||
|
u8 version; // local APIC verison
|
||||||
|
u8 flags; // CPU flags
|
||||||
|
#define MPBOOT 0x02 // This proc is the bootstrap processor.
|
||||||
|
u8 signature[4]; // CPU signature
|
||||||
|
uint feature; // feature flags from CPUID instruction
|
||||||
|
u8 reserved[8];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mpioapic { // I/O APIC table entry
|
||||||
|
u8 type; // entry type (2)
|
||||||
|
u8 apicno; // I/O APIC id
|
||||||
|
u8 version; // I/O APIC version
|
||||||
|
u8 flags; // I/O APIC flags
|
||||||
|
uint *addr; // I/O APIC address
|
||||||
|
}
|
||||||
|
|
||||||
|
// Table entry types
|
||||||
|
const MPPROC : u8 = 0x00; // One per processor
|
||||||
|
const MPBUS : u8 = 0x01; // One per bus
|
||||||
|
const MPIOAPIC : u8 = 0x02; // One per I/O APIC
|
||||||
|
const MPIOINTR : u8 = 0x03; // One per bus interrupt source
|
||||||
|
const MPLINTR : u8 = 0x04; // One per system interrupt source
|
||||||
|
|
||||||
|
//PAGEBREAK!
|
||||||
|
// Blank page.
|
||||||
|
|
||||||
|
*/
|
@ -0,0 +1,20 @@
|
|||||||
|
pub fn bytes_sum<T>(p: &T) -> u8 {
|
||||||
|
use core::mem::size_of_val;
|
||||||
|
let len = size_of_val(p);
|
||||||
|
let p = p as *const T as *const u8;
|
||||||
|
(0..len).map(|i| unsafe { &*p.offset(i as isize) })
|
||||||
|
.fold(0, |a, &b| a.overflowing_add(b).0)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
pub trait Checkable {
|
||||||
|
fn check(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Scan memory to find the struct
|
||||||
|
pub unsafe fn find_in_memory<T: Checkable>
|
||||||
|
(begin: usize, len: usize, step: usize) -> Option<usize> {
|
||||||
|
|
||||||
|
(begin .. begin + len).step_by(step)
|
||||||
|
.find(|&addr| { (&*(addr as *const T)).check() })
|
||||||
|
}
|
Loading…
Reference in new issue