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