Cleanup Redox repo, update Rust, remove old target

This commit is contained in:
Jeremy Soller 2017-01-03 15:55:00 -07:00
commit 7cd2eff74c
93 changed files with 24 additions and 79 deletions

37
kernel/Cargo.toml Normal file
View file

@ -0,0 +1,37 @@
[package]
name = "kernel"
version = "0.1.0"
[lib]
name = "kernel"
path = "src/lib.rs"
crate-type = ["staticlib"]
[dependencies]
bitflags = "*"
spin = "*"
redox_syscall = { path = "../syscall/" }
[dependencies.goblin]
git = "https://github.com/m4b/goblin.git"
default-features = false
features = ["elf32", "elf64"]
[dev-dependencies]
arch_test = { path = "arch/test" }
[target.'cfg(target_arch = "arm")'.dependencies]
arch_arm = { path = "arch/arm" }
[target.'cfg(target_arch = "x86_64")'.dependencies]
arch_x86_64 = { path = "arch/x86_64" }
[features]
default = []
live = []
[profile.dev]
panic = "unwind"
[profile.release]
panic = "abort"

View file

@ -0,0 +1,8 @@
[package]
name = "arch_arm"
version = "0.1.0"
[dependencies]
bitflags = "*"
hole_list_allocator = { path = "../../../crates/hole_list_allocator"}
spin = "*"

View file

@ -0,0 +1,9 @@
#[derive(Debug)]
pub struct Context;
impl Context {
pub fn new() -> Self {
Context
}
}

View file

@ -0,0 +1,70 @@
/// Memcpy
///
/// Copy N bytes of memory from one location to another.
#[no_mangle]
pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8,
n: usize) -> *mut u8 {
let mut i = 0;
while i < n {
*dest.offset(i as isize) = *src.offset(i as isize);
i += 1;
}
dest
}
/// Memmove
///
/// Copy N bytes of memory from src to dest. The memory areas may overlap.
#[no_mangle]
pub unsafe extern fn memmove(dest: *mut u8, src: *const u8,
n: usize) -> *mut u8 {
if src < dest as *const u8 {
let mut i = n;
while i != 0 {
i -= 1;
*dest.offset(i as isize) = *src.offset(i as isize);
}
} else {
let mut i = 0;
while i < n {
*dest.offset(i as isize) = *src.offset(i as isize);
i += 1;
}
}
dest
}
/// Memset
///
/// Fill a block of memory with a specified value.
#[no_mangle]
pub unsafe extern fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 {
let mut i = 0;
while i < n {
*s.offset(i as isize) = c as u8;
i += 1;
}
s
}
/// Memcmp
///
/// Compare two blocks of memory.
#[no_mangle]
pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
let mut i = 0;
while i < n {
let a = *s1.offset(i as isize);
let b = *s2.offset(i as isize);
if a != b {
return a as i32 - b as i32
}
i += 1;
}
0
}

View file

@ -0,0 +1,30 @@
//! Interrupt instructions
/// Clear interrupts
#[inline(always)]
pub unsafe fn disable() {
}
/// Set interrupts
#[inline(always)]
pub unsafe fn enable() {
}
/// Set interrupts and halt
#[inline(always)]
pub unsafe fn enable_and_halt() {
halt();
}
/// Halt instruction
#[inline(always)]
pub unsafe fn halt() {
//asm!("wfi" : : : : "volatile");
asm!("nop" : : : : "volatile");
}
/// Get a stack trace
//TODO: Check for stack being mapped before dereferencing
#[inline(never)]
pub unsafe fn stack_trace() {
}

View file

@ -0,0 +1,39 @@
//! Architecture support for ARM
#![feature(asm)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![no_std]
extern crate hole_list_allocator as allocator;
#[macro_use]
extern crate bitflags;
extern crate spin;
/// Print to console
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ({});
}
/// Print with new line to console
#[macro_export]
macro_rules! println {
($fmt:expr) => (print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}
/// Context switching
pub mod context;
/// Memset, memcpy, etc.
pub mod externs;
/// Interrupt handling
pub mod interrupt;
/// Panic support
pub mod panic;
/// Initialization function
pub mod start;

View file

@ -0,0 +1,60 @@
ENTRY(kstart)
OUTPUT_ARCH(arm)
OUTPUT_FORMAT(elf32-littlearm)
KERNEL_OFFSET = 0;
SECTIONS {
. = KERNEL_OFFSET;
.text : AT(ADDR(.text) - KERNEL_OFFSET) {
__text_start = .;
*(.text*)
. = ALIGN(4096);
__text_end = .;
}
.rodata : AT(ADDR(.rodata) - KERNEL_OFFSET) {
__rodata_start = .;
*(.rodata*)
. = ALIGN(4096);
__rodata_end = .;
}
.data : AT(ADDR(.data) - KERNEL_OFFSET) {
__data_start = .;
*(.data*)
. = ALIGN(4096);
__data_end = .;
}
.tdata : AT(ADDR(.tdata) - KERNEL_OFFSET) {
__tdata_start = .;
*(.tdata*)
. = ALIGN(4096);
__tdata_end = .;
__tbss_start = .;
*(.tbss*)
. += 8;
. = ALIGN(4096);
__tbss_end = .;
}
.bss : AT(ADDR(.bss) - KERNEL_OFFSET) {
__bss_start = .;
*(.bss*)
. = ALIGN(4096);
__bss_end = .;
}
__end = .;
/DISCARD/ : {
*(.comment*)
*(.debug*)
*(.eh_frame*)
*(.gcc_except_table*)
*(.note*)
*(.rel.eh_frame*)
}
}

View file

@ -0,0 +1,38 @@
//! Intrinsics for panic handling
use interrupt;
#[cfg(not(test))]
#[lang = "eh_personality"]
extern "C" fn eh_personality() {}
#[cfg(not(test))]
/// Required to handle panics
#[lang = "panic_fmt"]
extern "C" fn panic_fmt(fmt: ::core::fmt::Arguments, file: &str, line: u32) -> ! {
println!("PANIC: {}", fmt);
println!("FILE: {}", file);
println!("LINE: {}", line);
unsafe { interrupt::stack_trace(); }
println!("HALT");
loop {
unsafe { interrupt::halt(); }
}
}
#[allow(non_snake_case)]
#[no_mangle]
/// Required to handle panics
pub extern "C" fn _Unwind_Resume() -> ! {
loop {
unsafe { interrupt::halt(); }
}
}
/// Required for linker
#[no_mangle]
pub extern "C" fn __aeabi_unwind_cpp_pr0() {
loop {}
}

View file

@ -0,0 +1,27 @@
const SERIAL_BASE: *mut u8 = 0x16000000 as *mut u8;
const SERIAL_FLAG_REGISTER: *const u8 = 0x16000018 as *const u8;
const SERIAL_BUFFER_FULL: u8 = (1 << 5);
unsafe fn putc (c: u8)
{
/* Wait until the serial buffer is empty */
while *SERIAL_FLAG_REGISTER & SERIAL_BUFFER_FULL == SERIAL_BUFFER_FULL {}
/* Put our character, c, into the serial buffer */
*SERIAL_BASE = c;
}
unsafe fn puts(string: &str)
{
for b in string.bytes() {
putc(b);
}
}
#[no_mangle]
#[naked]
pub unsafe extern fn kstart() -> ! {
asm!("mov sp, 0x18000" : : : : "volatile");
puts("TEST\r\n");
loop {}
}

View file

@ -0,0 +1,3 @@
[package]
name = "arch_test"
version = "0.1.0"

View file

@ -0,0 +1,43 @@
//! Interrupt instructions
static mut INTERRUPTS_ENABLED: bool = false;
/// Clear interrupts
#[inline(always)]
pub unsafe fn disable() {
println!("CLEAR INTERRUPTS");
INTERRUPTS_ENABLED = false;
}
/// Set interrupts
#[inline(always)]
pub unsafe fn enable() {
println!("SET INTERRUPTS");
INTERRUPTS_ENABLED = true;
}
/// Halt instruction
#[inline(always)]
pub unsafe fn halt() {
assert!(INTERRUPTS_ENABLED);
::std::thread::yield_now();
}
/// Pause instruction
#[inline(always)]
pub unsafe fn pause() {
}
/// Set interrupts and nop
#[inline(always)]
pub unsafe fn enable_and_nop() {
enable();
}
/// Set interrupts and halt
#[inline(always)]
pub unsafe fn enable_and_halt() {
enable();
halt();
}

View file

@ -0,0 +1,43 @@
//! Architecture support for testing
pub use std::io;
/// Print to console
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ({
use $crate::io::Write;
let _ = write!($crate::io::stdout(), $($arg)*);
});
}
/// Print with new line to console
#[macro_export]
macro_rules! println {
($fmt:expr) => (print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}
/// Create an interrupt function that can safely run rust code
#[macro_export]
macro_rules! interrupt {
($name:ident, $func:block) => {
pub unsafe extern fn $name () {
unsafe fn inner() {
$func
}
// Call inner rust function
inner();
}
};
}
/// Interrupt instructions
pub mod interrupt;
/// Initialization and main function
pub mod main;
/// Time functions
pub mod time;

View file

@ -0,0 +1,11 @@
/// This function is where the kernel sets up IRQ handlers
/// It is increcibly unsafe, and should be minimal in nature
extern {
fn kmain() -> !;
}
#[no_mangle]
pub unsafe extern fn kstart() -> ! {
kmain();
}

View file

@ -0,0 +1,7 @@
pub fn monotonic() -> (u64, u64) {
(0, 0)
}
pub fn realtime() -> (u64, u64) {
(0, 0)
}

View file

@ -0,0 +1,15 @@
[package]
name = "arch_x86_64"
version = "0.1.0"
[dependencies]
bitflags = "*"
hole_list_allocator = { path = "../../../crates/hole_list_allocator/" }
io = { path = "../../../crates/io/" }
raw-cpuid = { git = "https://github.com/gz/rust-cpuid" }
spin = "*"
redox_syscall = { path = "../../../syscall/" }
[dependencies.x86]
version = "0.7"
default-features = false

View file

@ -0,0 +1,77 @@
#[repr(packed)]
pub struct DrhdFault {
pub sts: u32,
pub ctrl: u32,
pub data: u32,
pub addr: [u32; 2],
_rsv: [u64; 2],
pub log: u64,
}
#[repr(packed)]
pub struct DrhdProtectedMemory {
pub en: u32,
pub low_base: u32,
pub low_limit: u32,
pub high_base: u64,
pub high_limit: u64,
}
#[repr(packed)]
pub struct DrhdInvalidation {
pub queue_head: u64,
pub queue_tail: u64,
pub queue_addr: u64,
_rsv: u32,
pub cmpl_sts: u32,
pub cmpl_ctrl: u32,
pub cmpl_data: u32,
pub cmpl_addr: [u32; 2],
}
#[repr(packed)]
pub struct DrhdPageRequest {
pub queue_head: u64,
pub queue_tail: u64,
pub queue_addr: u64,
_rsv: u32,
pub sts: u32,
pub ctrl: u32,
pub data: u32,
pub addr: [u32; 2],
}
#[repr(packed)]
pub struct DrhdMtrrVariable {
pub base: u64,
pub mask: u64,
}
#[repr(packed)]
pub struct DrhdMtrr {
pub cap: u64,
pub def_type: u64,
pub fixed: [u64; 11],
pub variable: [DrhdMtrrVariable; 10],
}
#[repr(packed)]
pub struct Drhd {
pub version: u32,
_rsv: u32,
pub cap: u64,
pub ext_cap: u64,
pub gl_cmd: u32,
pub gl_sts: u32,
pub root_table: u64,
pub ctx_cmd: u64,
_rsv1: u32,
pub fault: DrhdFault,
_rsv2: u32,
pub pm: DrhdProtectedMemory,
pub invl: DrhdInvalidation,
_rsv3: u64,
pub intr_table: u64,
pub page_req: DrhdPageRequest,
pub mtrr: DrhdMtrr,
}

View file

@ -0,0 +1,183 @@
use core::mem;
use super::sdt::Sdt;
use self::drhd::Drhd;
use memory::Frame;
use paging::{entry, ActivePageTable, PhysicalAddress};
pub mod drhd;
/// The DMA Remapping Table
#[derive(Debug)]
pub struct Dmar {
sdt: &'static Sdt,
pub addr_width: u8,
pub flags: u8,
_rsv: [u8; 10],
}
impl Dmar {
pub fn new(sdt: &'static Sdt) -> Option<Dmar> {
if &sdt.signature == b"DMAR" && sdt.data_len() >= 12 { //Not valid if no local address and flags
let addr_width = unsafe { *(sdt.data_address() as *const u8) };
let flags = unsafe { *(sdt.data_address() as *const u8).offset(1) };
let rsv: [u8; 10] = unsafe { *((sdt.data_address() as *const u8).offset(2) as *const [u8; 10]) };
Some(Dmar {
sdt: sdt,
addr_width: addr_width,
flags: flags,
_rsv: rsv,
})
} else {
None
}
}
pub fn iter(&self) -> DmarIter {
DmarIter {
sdt: self.sdt,
i: 12 // Skip address width and flags
}
}
}
///
/// DMAR DMA Remapping Hardware Unit Definition
// TODO: Implement iterator on DmarDrhd scope
#[derive(Debug)]
#[repr(packed)]
pub struct DmarDrhd {
kind: u16,
length: u16,
flags: u8,
_rsv: u8,
segment: u16,
base: u64,
}
impl DmarDrhd {
pub fn get(&self, active_table: &mut ActivePageTable) -> &'static mut Drhd {
let result = active_table.identity_map(Frame::containing_address(PhysicalAddress::new(self.base as usize)), entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
result.flush(active_table);
unsafe { &mut *(self.base as *mut Drhd) }
}
}
/// DMAR Reserved Memory Region Reporting
// TODO: Implement iterator on DmarRmrr scope
#[derive(Debug)]
#[repr(packed)]
pub struct DmarRmrr {
kind: u16,
length: u16,
_rsv: u16,
segment: u16,
base: u64,
limit: u64,
}
/// DMAR Root Port ATS Capability Reporting
// TODO: Implement iterator on DmarAtsr scope
#[derive(Debug)]
#[repr(packed)]
pub struct DmarAtsr {
kind: u16,
length: u16,
flags: u8,
_rsv: u8,
segment: u16,
}
/// DMAR Remapping Hardware Static Affinity
#[derive(Debug)]
#[repr(packed)]
pub struct DmarRhsa {
kind: u16,
length: u16,
_rsv: u32,
base: u64,
domain: u32,
}
/// DMAR ACPI Name-space Device Declaration
// TODO: Implement iterator on DmarAndd object name
#[derive(Debug)]
#[repr(packed)]
pub struct DmarAndd {
kind: u16,
length: u16,
_rsv: [u8; 3],
acpi_dev: u8,
}
/// DMAR Entries
#[derive(Debug)]
pub enum DmarEntry {
Drhd(&'static DmarDrhd),
InvalidDrhd(usize),
Rmrr(&'static DmarRmrr),
InvalidRmrr(usize),
Atsr(&'static DmarAtsr),
InvalidAtsr(usize),
Rhsa(&'static DmarRhsa),
InvalidRhsa(usize),
Andd(&'static DmarAndd),
InvalidAndd(usize),
Unknown(u16)
}
pub struct DmarIter {
sdt: &'static Sdt,
i: usize
}
impl Iterator for DmarIter {
type Item = DmarEntry;
fn next(&mut self) -> Option<Self::Item> {
if self.i + 4 <= self.sdt.data_len() {
let entry_type = unsafe { *((self.sdt.data_address() as *const u8).offset(self.i as isize) as *const u16) };
let entry_len = unsafe { *((self.sdt.data_address() as *const u8).offset(self.i as isize + 2) as *const u16) } as usize;
if self.i + entry_len <= self.sdt.data_len() {
let item = match entry_type {
0 => if entry_len >= mem::size_of::<DmarDrhd>() {
DmarEntry::Drhd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarDrhd) })
} else {
DmarEntry::InvalidDrhd(entry_len)
},
1 => if entry_len >= mem::size_of::<DmarRmrr>() {
DmarEntry::Rmrr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRmrr) })
} else {
DmarEntry::InvalidRmrr(entry_len)
},
2 => if entry_len >= mem::size_of::<DmarAtsr>() {
DmarEntry::Atsr(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAtsr) })
} else {
DmarEntry::InvalidAtsr(entry_len)
},
3 => if entry_len == mem::size_of::<DmarRhsa>() {
DmarEntry::Rhsa(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarRhsa) })
} else {
DmarEntry::InvalidRhsa(entry_len)
},
4 => if entry_len >= mem::size_of::<DmarAndd>() {
DmarEntry::Andd(unsafe { &*((self.sdt.data_address() + self.i) as *const DmarAndd) })
} else {
DmarEntry::InvalidAndd(entry_len)
},
_ => DmarEntry::Unknown(entry_type)
};
self.i += entry_len;
Some(item)
} else {
None
}
} else {
None
}
}
}

View file

@ -0,0 +1,96 @@
use core::{mem, ptr};
use super::sdt::Sdt;
#[repr(packed)]
#[derive(Debug)]
pub struct Fadt {
pub header: Sdt,
pub firmware_ctrl: u32,
pub dsdt: u32,
// field used in ACPI 1.0; no longer in use, for compatibility only
reserved: u8,
pub preferred_power_managament: u8,
pub sci_interrupt: u16,
pub smi_command_port: u32,
pub acpi_enable: u8,
pub acpi_disable: u8,
pub s4_bios_req: u8,
pub pstate_control: u8,
pub pm1a_event_block: u32,
pub pm1b_event_block: u32,
pub pm1a_control_block: u32,
pub pm1b_control_block: u32,
pub pm2_control_block: u32,
pub pm_timer_block: u32,
pub gpe0_block: u32,
pub gpe1_block: u32,
pub pm1_event_length: u8,
pub pm1_control_length: u8,
pub pm2_control_length: u8,
pub pm_timer_length: u8,
pub gpe0_ength: u8,
pub gpe1_length: u8,
pub gpe1_base: u8,
pub c_state_control: u8,
pub worst_c2_latency: u16,
pub worst_c3_latency: u16,
pub flush_size: u16,
pub flush_stride: u16,
pub duty_offset: u8,
pub duty_width: u8,
pub day_alarm: u8,
pub month_alarm: u8,
pub century: u8,
// reserved in ACPI 1.0; used since ACPI 2.0+
pub boot_architecture_flags: u16,
reserved2: u8,
pub flags: u32,
}
/* ACPI 2 structure
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
pub struct GenericAddressStructure {
address_space: u8,
bit_width: u8,
bit_offset: u8,
access_size: u8,
address: u64,
}
{
// 12 byte structure; see below for details
pub reset_reg: GenericAddressStructure,
pub reset_value: u8,
reserved3: [u8; 3],
// 64bit pointers - Available on ACPI 2.0+
pub x_firmware_control: u64,
pub x_dsdt: u64,
pub x_pm1a_event_block: GenericAddressStructure,
pub x_pm1b_event_block: GenericAddressStructure,
pub x_pm1a_control_block: GenericAddressStructure,
pub x_pm1b_control_block: GenericAddressStructure,
pub x_pm2_control_block: GenericAddressStructure,
pub x_pm_timer_block: GenericAddressStructure,
pub x_gpe0_block: GenericAddressStructure,
pub x_gpe1_block: GenericAddressStructure,
}
*/
impl Fadt {
pub fn new(sdt: &'static Sdt) -> Option<Fadt> {
if &sdt.signature == b"FACP" && sdt.length as usize >= mem::size_of::<Fadt>() {
Some(unsafe { ptr::read((sdt as *const Sdt) as *const Fadt) })
} else {
None
}
}
}

View file

@ -0,0 +1,133 @@
use core::mem;
use super::sdt::Sdt;
/// The Multiple APIC Descriptor Table
#[derive(Debug)]
pub struct Madt {
sdt: &'static Sdt,
pub local_address: u32,
pub flags: u32
}
impl Madt {
pub fn new(sdt: &'static Sdt) -> Option<Madt> {
if &sdt.signature == b"APIC" && sdt.data_len() >= 8 { //Not valid if no local address and flags
let local_address = unsafe { *(sdt.data_address() as *const u32) };
let flags = unsafe { *(sdt.data_address() as *const u32).offset(1) };
Some(Madt {
sdt: sdt,
local_address: local_address,
flags: flags
})
} else {
None
}
}
pub fn iter(&self) -> MadtIter {
MadtIter {
sdt: self.sdt,
i: 8 // Skip local controller address and flags
}
}
}
///
/// MADT Local APIC
#[derive(Debug)]
#[repr(packed)]
pub struct MadtLocalApic {
/// Processor ID
pub processor: u8,
/// Local APIC ID
pub id: u8,
/// Flags. 1 means that the processor is enabled
pub flags: u32
}
/// MADT I/O APIC
#[derive(Debug)]
#[repr(packed)]
pub struct MadtIoApic {
/// I/O APIC ID
pub id: u8,
/// reserved
reserved: u8,
/// I/O APIC address
pub address: u32,
/// Global system interrupt base
pub gsi_base: u32
}
/// MADT Interrupt Source Override
#[derive(Debug)]
#[repr(packed)]
pub struct MadtIntSrcOverride {
/// Bus Source
pub bus_source: u8,
/// IRQ Source
pub irq_source: u8,
/// Global system interrupt base
pub gsi_base: u32,
/// Flags
pub flags: u16
}
/// MADT Entries
#[derive(Debug)]
pub enum MadtEntry {
LocalApic(&'static MadtLocalApic),
InvalidLocalApic(usize),
IoApic(&'static MadtIoApic),
InvalidIoApic(usize),
IntSrcOverride(&'static MadtIntSrcOverride),
InvalidIntSrcOverride(usize),
Unknown(u8)
}
pub struct MadtIter {
sdt: &'static Sdt,
i: usize
}
impl Iterator for MadtIter {
type Item = MadtEntry;
fn next(&mut self) -> Option<Self::Item> {
if self.i + 1 < self.sdt.data_len() {
let entry_type = unsafe { *(self.sdt.data_address() as *const u8).offset(self.i as isize) };
let entry_len = unsafe { *(self.sdt.data_address() as *const u8).offset(self.i as isize + 1) } as usize;
if self.i + entry_len <= self.sdt.data_len() {
let item = match entry_type {
0 => if entry_len == mem::size_of::<MadtLocalApic>() + 2 {
MadtEntry::LocalApic(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtLocalApic) })
} else {
MadtEntry::InvalidLocalApic(entry_len)
},
1 => if entry_len == mem::size_of::<MadtIoApic>() + 2 {
MadtEntry::IoApic(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtIoApic) })
} else {
MadtEntry::InvalidIoApic(entry_len)
},
2 => if entry_len == mem::size_of::<MadtIntSrcOverride>() + 2 {
MadtEntry::IntSrcOverride(unsafe { &*((self.sdt.data_address() + self.i + 2) as *const MadtIntSrcOverride) })
} else {
MadtEntry::InvalidIntSrcOverride(entry_len)
},
_ => MadtEntry::Unknown(entry_type)
};
self.i += entry_len;
Some(item)
} else {
None
}
} else {
None
}
}
}

View file

@ -0,0 +1,284 @@
//! # ACPI
//! Code to parse the ACPI tables
use core::intrinsics::{atomic_load, atomic_store};
use core::sync::atomic::Ordering;
use device::local_apic::LOCAL_APIC;
use interrupt;
use memory::{allocate_frames, Frame};
use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress};
use start::{kstart_ap, CPU_COUNT, AP_READY};
use self::dmar::{Dmar, DmarEntry};
use self::fadt::Fadt;
use self::madt::{Madt, MadtEntry};
use self::rsdt::Rsdt;
use self::sdt::Sdt;
use self::xsdt::Xsdt;
pub mod dmar;
pub mod fadt;
pub mod madt;
pub mod rsdt;
pub mod sdt;
pub mod xsdt;
const TRAMPOLINE: usize = 0x7E00;
const AP_STARTUP: usize = TRAMPOLINE + 512;
pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
print!(" ");
for &c in sdt.signature.iter() {
print!("{}", c as char);
}
if let Some(fadt) = Fadt::new(sdt) {
println!(": {:#?}", fadt);
} else if let Some(madt) = Madt::new(sdt) {
println!(": {:>08X}: {}", madt.local_address, madt.flags);
let mut local_apic = unsafe { &mut LOCAL_APIC };
let me = local_apic.id() as u8;
if local_apic.x2 {
println!(" X2APIC {}", me);
} else {
println!(" XAPIC {}: {:>08X}", me, local_apic.address);
}
let trampoline_frame = Frame::containing_address(PhysicalAddress::new(TRAMPOLINE));
let trampoline_page = Page::containing_address(VirtualAddress::new(TRAMPOLINE));
// Map trampoline
let result = active_table.map_to(trampoline_page, trampoline_frame, entry::PRESENT | entry::WRITABLE);
result.flush(active_table);
for madt_entry in madt.iter() {
println!(" {:?}", madt_entry);
match madt_entry {
MadtEntry::LocalApic(ap_local_apic) => if ap_local_apic.id == me {
println!(" This is my local APIC");
} else {
if ap_local_apic.flags & 1 == 1 {
// Increase CPU ID
CPU_COUNT.fetch_add(1, Ordering::SeqCst);
// Allocate a stack
let stack_start = allocate_frames(64).expect("no more frames in acpi stack_start").start_address().get() + ::KERNEL_OFFSET;
let stack_end = stack_start + 64 * 4096;
let ap_ready = TRAMPOLINE as *mut u64;
let ap_cpu_id = unsafe { ap_ready.offset(1) };
let ap_page_table = unsafe { ap_ready.offset(2) };
let ap_stack_start = unsafe { ap_ready.offset(3) };
let ap_stack_end = unsafe { ap_ready.offset(4) };
let ap_code = unsafe { ap_ready.offset(5) };
// Set the ap_ready to 0, volatile
unsafe { atomic_store(ap_ready, 0) };
unsafe { atomic_store(ap_cpu_id, ap_local_apic.id as u64) };
unsafe { atomic_store(ap_page_table, active_table.address() as u64) };
unsafe { atomic_store(ap_stack_start, stack_start as u64) };
unsafe { atomic_store(ap_stack_end, stack_end as u64) };
unsafe { atomic_store(ap_code, kstart_ap as u64) };
AP_READY.store(false, Ordering::SeqCst);
print!(" AP {}:", ap_local_apic.id);
// Send INIT IPI
{
let mut icr = 0x4500;
if local_apic.x2 {
icr |= (ap_local_apic.id as u64) << 32;
} else {
icr |= (ap_local_apic.id as u64) << 56;
}
print!(" IPI...");
local_apic.set_icr(icr);
}
// Send START IPI
{
//Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there
let ap_segment = (AP_STARTUP >> 12) & 0xFF;
let mut icr = 0x4600 | ap_segment as u64;
if local_apic.x2 {
icr |= (ap_local_apic.id as u64) << 32;
} else {
icr |= (ap_local_apic.id as u64) << 56;
}
print!(" SIPI...");
local_apic.set_icr(icr);
}
// Wait for trampoline ready
print!(" Wait...");
while unsafe { atomic_load(ap_ready) } == 0 {
interrupt::pause();
}
print!(" Trampoline...");
while ! AP_READY.load(Ordering::SeqCst) {
interrupt::pause();
}
println!(" Ready");
active_table.flush_all();
} else {
println!(" CPU Disabled");
}
},
_ => ()
}
}
// Unmap trampoline
let result = active_table.unmap(trampoline_page);
result.flush(active_table);
} else if let Some(dmar) = Dmar::new(sdt) {
println!(": {}: {}", dmar.addr_width, dmar.flags);
for dmar_entry in dmar.iter() {
println!(" {:?}", dmar_entry);
match dmar_entry {
DmarEntry::Drhd(dmar_drhd) => {
let drhd = dmar_drhd.get(active_table);
println!("VER: {:X}", drhd.version);
println!("CAP: {:X}", drhd.cap);
println!("EXT_CAP: {:X}", drhd.ext_cap);
println!("GCMD: {:X}", drhd.gl_cmd);
println!("GSTS: {:X}", drhd.gl_sts);
println!("RT: {:X}", drhd.root_table);
},
_ => ()
}
}
} else {
println!(": Unknown");
}
}
/// Parse the ACPI tables to gather CPU, interrupt, and timer information
pub unsafe fn init(active_table: &mut ActivePageTable) -> Option<Acpi> {
let start_addr = 0xE0000;
let end_addr = 0xFFFFF;
// Map all of the ACPI RSDP space
{
let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
for frame in Frame::range_inclusive(start_frame, end_frame) {
let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
result.flush(active_table);
}
}
// Search for RSDP
if let Some(rsdp) = RSDP::search(start_addr, end_addr) {
let get_sdt = |sdt_address: usize, active_table: &mut ActivePageTable| -> (&'static Sdt, bool) {
let mapped = if active_table.translate_page(Page::containing_address(VirtualAddress::new(sdt_address))).is_none() {
let sdt_frame = Frame::containing_address(PhysicalAddress::new(sdt_address));
let sdt_page = Page::containing_address(VirtualAddress::new(sdt_address));
let result = active_table.map_to(sdt_page, sdt_frame, entry::PRESENT | entry::NO_EXECUTE);
result.flush(active_table);
true
} else {
false
};
(&*(sdt_address as *const Sdt), mapped)
};
let drop_sdt = |sdt: &'static Sdt, mapped: bool, active_table: &mut ActivePageTable| {
let sdt_address = sdt as *const Sdt as usize;
drop(sdt);
if mapped {
let sdt_page = Page::containing_address(VirtualAddress::new(sdt_address));
let result = active_table.unmap(sdt_page);
result.flush(active_table);
}
};
let (rxsdt, rxmapped) = get_sdt(rsdp.sdt_address(), active_table);
for &c in rxsdt.signature.iter() {
print!("{}", c as char);
}
println!(":");
if let Some(rsdt) = Rsdt::new(rxsdt) {
for sdt_address in rsdt.iter() {
let (sdt, mapped) = get_sdt(sdt_address, active_table);
init_sdt(sdt, active_table);
drop_sdt(sdt, mapped, active_table);
}
} else if let Some(xsdt) = Xsdt::new(rxsdt) {
for sdt_address in xsdt.iter() {
let (sdt, mapped) = get_sdt(sdt_address, active_table);
init_sdt(sdt, active_table);
drop_sdt(sdt, mapped, active_table);
}
} else {
println!("UNKNOWN RSDT OR XSDT SIGNATURE");
}
drop_sdt(rxsdt, rxmapped, active_table);
} else {
println!("NO RSDP FOUND");
}
// Unmap all of the ACPI RSDP space
{
let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
for frame in Frame::range_inclusive(start_frame, end_frame) {
let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
let result = active_table.unmap(page);
result.flush(active_table);
}
}
None
}
pub struct Acpi;
/// RSDP
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct RSDP {
signature: [u8; 8],
checksum: u8,
oemid: [u8; 6],
revision: u8,
rsdt_address: u32,
length: u32,
xsdt_address: u64,
extended_checksum: u8,
reserved: [u8; 3]
}
impl RSDP {
/// Search for the RSDP
pub fn search(start_addr: usize, end_addr: usize) -> Option<RSDP> {
for i in 0 .. (end_addr + 1 - start_addr)/16 {
let rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) };
if &rsdp.signature == b"RSD PTR " {
return Some(*rsdp);
}
}
None
}
/// Get the RSDT or XSDT address
pub fn sdt_address(&self) -> usize {
if self.revision >= 2 {
self.xsdt_address as usize
} else {
self.rsdt_address as usize
}
}
}

Some files were not shown because too many files have changed in this diff Show more