Port MP & RSDP detecting

toolchain_update
WangRunji 7 years ago
parent eb9a5e9241
commit 936c485ab9

@ -27,7 +27,7 @@ clean:
@rm -r build @rm -r build
run: $(iso) run: $(iso)
@qemu-system-$(arch) -cdrom $(iso) @qemu-system-$(arch) -cdrom $(iso) -smp 2
iso: $(iso) iso: $(iso)

@ -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.
*/

@ -7,6 +7,7 @@
#![feature(allocator_api)] #![feature(allocator_api)]
#![feature(global_allocator)] #![feature(global_allocator)]
#![feature(abi_x86_interrupt)] #![feature(abi_x86_interrupt)]
#![feature(iterator_step_by)]
#![no_std] #![no_std]
@ -32,6 +33,8 @@ mod io;
mod memory; mod memory;
mod interrupts; mod interrupts;
mod lang; mod lang;
#[macro_use]
mod util;
#[allow(dead_code)] #[allow(dead_code)]
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@ -42,6 +45,12 @@ mod arch;
#[no_mangle] #[no_mangle]
pub extern "C" fn rust_main(multiboot_information_address: usize) { pub extern "C" fn rust_main(multiboot_information_address: usize) {
// ATTENTION: we have a very small stack and no guard page // ATTENTION: we have a very small stack and no guard page
println!("MP = {:?}", arch::driver::mp::find_mp());
println!("RDSP = {:?}", arch::driver::acpi::find_rdsp());
loop {
}
arch::driver::ioapic::init();
io::init(); io::init();
println!("Hello World{}", "!"); println!("Hello World{}", "!");

@ -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…
Cancel
Save