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
37 changed files with 24 additions and 79 deletions

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
}
}
}

View file

@ -0,0 +1,41 @@
use core::mem;
use super::sdt::Sdt;
#[derive(Debug)]
pub struct Rsdt(&'static Sdt);
impl Rsdt {
pub fn new(sdt: &'static Sdt) -> Option<Rsdt> {
if &sdt.signature == b"RSDT" {
Some(Rsdt(sdt))
} else {
None
}
}
pub fn iter(&self) -> RsdtIter {
RsdtIter {
sdt: self.0,
i: 0
}
}
}
pub struct RsdtIter {
sdt: &'static Sdt,
i: usize
}
impl Iterator for RsdtIter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.i < self.sdt.data_len()/mem::size_of::<u32>() {
let item = unsafe { *(self.sdt.data_address() as *const u32).offset(self.i as isize) };
self.i += 1;
Some(item as usize)
} else {
None
}
}
}

View file

@ -0,0 +1,33 @@
use core::mem;
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct Sdt {
pub signature: [u8; 4],
pub length: u32,
pub revision: u8,
pub checksum: u8,
pub oem_id: [u8; 6],
pub oem_table_id: [u8; 8],
pub oem_revision: u32,
pub creator_id: u32,
pub creator_revision: u32
}
impl Sdt {
/// Get the address of this tables data
pub fn data_address(&'static self) -> usize {
self as *const _ as usize + mem::size_of::<Sdt>()
}
/// Get the length of this tables data
pub fn data_len(&'static self) -> usize {
let total_size = self.length as usize;
let header_size = mem::size_of::<Sdt>();
if total_size >= header_size {
total_size - header_size
} else {
0
}
}
}

View file

@ -0,0 +1,41 @@
use core::mem;
use super::sdt::Sdt;
#[derive(Debug)]
pub struct Xsdt(&'static Sdt);
impl Xsdt {
pub fn new(sdt: &'static Sdt) -> Option<Xsdt> {
if &sdt.signature == b"XSDT" {
Some(Xsdt(sdt))
} else {
None
}
}
pub fn iter(&self) -> XsdtIter {
XsdtIter {
sdt: self.0,
i: 0
}
}
}
pub struct XsdtIter {
sdt: &'static Sdt,
i: usize
}
impl Iterator for XsdtIter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.i < self.sdt.data_len()/mem::size_of::<u64>() {
let item = unsafe { *(self.sdt.data_address() as *const u64).offset(self.i as isize) };
self.i += 1;
Some(item as usize)
} else {
None
}
}
}

View file

@ -0,0 +1,14 @@
use core::fmt::{self, Write};
use spin::Mutex;
use device::serial::COM1;
pub static CONSOLE: Mutex<Console> = Mutex::new(Console);
pub struct Console;
impl Write for Console {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
COM1.lock().write_str(s)
}
}

View file

@ -0,0 +1,184 @@
use core::mem;
use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
/// This must be used by the kernel to ensure that context switches are done atomically
/// Compare and exchange this to true when beginning a context switch on any CPU
/// The Context::switch_to function will set it back to false, allowing other CPU's to switch
/// This must be done, as no locks can be held on the stack during switch
pub static CONTEXT_SWITCH_LOCK: AtomicBool = ATOMIC_BOOL_INIT;
#[derive(Clone, Debug)]
pub struct Context {
/// FX valid?
loadable: bool,
/// FX location
fx: usize,
/// Page table pointer
cr3: usize,
/// RFLAGS register
rflags: usize,
/// RBX register
rbx: usize,
/// R12 register
r12: usize,
/// R13 register
r13: usize,
/// R14 register
r14: usize,
/// R15 register
r15: usize,
/// Base pointer
rbp: usize,
/// Stack pointer
rsp: usize
}
impl Context {
pub fn new() -> Context {
Context {
loadable: false,
fx: 0,
cr3: 0,
rflags: 0,
rbx: 0,
r12: 0,
r13: 0,
r14: 0,
r15: 0,
rbp: 0,
rsp: 0
}
}
pub fn get_page_table(&self) -> usize {
self.cr3
}
pub fn set_fx(&mut self, address: usize) {
self.fx = address;
}
pub fn set_page_table(&mut self, address: usize) {
self.cr3 = address;
}
pub fn set_stack(&mut self, address: usize) {
self.rsp = address;
}
pub unsafe fn signal_stack(&mut self, handler: extern fn(usize), sig: u8) {
self.push_stack(sig as usize);
self.push_stack(handler as usize);
self.push_stack(signal_handler_wrapper as usize);
}
pub unsafe fn push_stack(&mut self, value: usize) {
self.rsp -= mem::size_of::<usize>();
*(self.rsp as *mut usize) = value;
}
pub unsafe fn pop_stack(&mut self) -> usize {
let value = *(self.rsp as *const usize);
self.rsp += mem::size_of::<usize>();
value
}
/// Switch to the next context by restoring its stack and registers
#[cold]
#[inline(never)]
#[naked]
pub unsafe fn switch_to(&mut self, next: &mut Context) {
asm!("fxsave [$0]" : : "r"(self.fx) : "memory" : "intel", "volatile");
self.loadable = true;
if next.loadable {
asm!("fxrstor [$0]" : : "r"(next.fx) : "memory" : "intel", "volatile");
}else{
asm!("fninit" : : : "memory" : "intel", "volatile");
}
asm!("mov $0, cr3" : "=r"(self.cr3) : : "memory" : "intel", "volatile");
if next.cr3 != self.cr3 {
asm!("mov cr3, $0" : : "r"(next.cr3) : "memory" : "intel", "volatile");
}
asm!("pushfq ; pop $0" : "=r"(self.rflags) : : "memory" : "intel", "volatile");
asm!("push $0 ; popfq" : : "r"(next.rflags) : "memory" : "intel", "volatile");
asm!("mov $0, rbx" : "=r"(self.rbx) : : "memory" : "intel", "volatile");
asm!("mov rbx, $0" : : "r"(next.rbx) : "memory" : "intel", "volatile");
asm!("mov $0, r12" : "=r"(self.r12) : : "memory" : "intel", "volatile");
asm!("mov r12, $0" : : "r"(next.r12) : "memory" : "intel", "volatile");
asm!("mov $0, r13" : "=r"(self.r13) : : "memory" : "intel", "volatile");
asm!("mov r13, $0" : : "r"(next.r13) : "memory" : "intel", "volatile");
asm!("mov $0, r14" : "=r"(self.r14) : : "memory" : "intel", "volatile");
asm!("mov r14, $0" : : "r"(next.r14) : "memory" : "intel", "volatile");
asm!("mov $0, r15" : "=r"(self.r15) : : "memory" : "intel", "volatile");
asm!("mov r15, $0" : : "r"(next.r15) : "memory" : "intel", "volatile");
asm!("mov $0, rsp" : "=r"(self.rsp) : : "memory" : "intel", "volatile");
asm!("mov rsp, $0" : : "r"(next.rsp) : "memory" : "intel", "volatile");
asm!("mov $0, rbp" : "=r"(self.rbp) : : "memory" : "intel", "volatile");
asm!("mov rbp, $0" : : "r"(next.rbp) : "memory" : "intel", "volatile");
}
}
#[repr(packed)]
pub struct SignalHandlerStack {
r11: usize,
r10: usize,
r9: usize,
r8: usize,
rsi: usize,
rdi: usize,
rdx: usize,
rcx: usize,
rax: usize,
handler: extern fn(usize),
sig: usize,
rip: usize,
}
#[naked]
unsafe extern fn signal_handler_wrapper() {
#[inline(never)]
unsafe fn inner(stack: &SignalHandlerStack) {
(stack.handler)(stack.sig);
}
// Push scratch registers
asm!("push rax
push rcx
push rdx
push rdi
push rsi
push r8
push r9
push r10
push r11"
: : : : "intel", "volatile");
// Get reference to stack variables
let rsp: usize;
asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");
// Call inner rust function
inner(&*(rsp as *const SignalHandlerStack));
// Pop scratch registers, error code, and return
asm!("pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rdx
pop rcx
pop rax
add rsp, 16"
: : : : "intel", "volatile");
}

View file

@ -0,0 +1,126 @@
extern crate raw_cpuid;
use core::fmt::{Result, Write};
use self::raw_cpuid::CpuId;
pub fn cpu_info<W: Write>(w: &mut W) -> Result {
let cpuid = CpuId::new();
if let Some(info) = cpuid.get_vendor_info() {
write!(w, "Vendor: {}\n", info.as_string())?;
}
if let Some(info) = cpuid.get_extended_function_info() {
if let Some(brand) = info.processor_brand_string() {
write!(w, "Model: {}\n", brand)?;
}
}
if let Some(info) = cpuid.get_processor_frequency_info() {
write!(w, "CPU Base MHz: {}\n", info.processor_base_frequency())?;
write!(w, "CPU Max MHz: {}\n", info.processor_max_frequency())?;
write!(w, "Bus MHz: {}\n", info.bus_frequency())?;
}
write!(w, "Features:")?;
if let Some(info) = cpuid.get_feature_info() {
if info.has_fpu() { write!(w, " fpu")? };
if info.has_vme() { write!(w, " vme")? };
if info.has_de() { write!(w, " de")? };
if info.has_pse() { write!(w, " pse")? };
if info.has_tsc() { write!(w, " tsc")? };
if info.has_msr() { write!(w, " msr")? };
if info.has_pae() { write!(w, " pae")? };
if info.has_mce() { write!(w, " mce")? };
if info.has_cmpxchg8b() { write!(w, " cx8")? };
if info.has_apic() { write!(w, " apic")? };
if info.has_sysenter_sysexit() { write!(w, " sep")? };
if info.has_mtrr() { write!(w, " mtrr")? };
if info.has_pge() { write!(w, " pge")? };
if info.has_mca() { write!(w, " mca")? };
if info.has_cmov() { write!(w, " cmov")? };
if info.has_pat() { write!(w, " pat")? };
if info.has_pse36() { write!(w, " pse36")? };
if info.has_psn() { write!(w, " psn")? };
if info.has_clflush() { write!(w, " clflush")? };
if info.has_ds() { write!(w, " ds")? };
if info.has_acpi() { write!(w, " acpi")? };
if info.has_mmx() { write!(w, " mmx")? };
if info.has_fxsave_fxstor() { write!(w, " fxsr")? };
if info.has_sse() { write!(w, " sse")? };
if info.has_sse2() { write!(w, " sse2")? };
if info.has_ss() { write!(w, " ss")? };
if info.has_htt() { write!(w, " ht")? };
if info.has_tm() { write!(w, " tm")? };
if info.has_pbe() { write!(w, " pbe")? };
if info.has_sse3() { write!(w, " sse3")? };
if info.has_pclmulqdq() { write!(w, " pclmulqdq")? };
if info.has_ds_area() { write!(w, " dtes64")? };
if info.has_monitor_mwait() { write!(w, " monitor")? };
if info.has_cpl() { write!(w, " ds_cpl")? };
if info.has_vmx() { write!(w, " vmx")? };
if info.has_smx() { write!(w, " smx")? };
if info.has_eist() { write!(w, " est")? };
if info.has_tm2() { write!(w, " tm2")? };
if info.has_ssse3() { write!(w, " ssse3")? };
if info.has_cnxtid() { write!(w, " cnxtid")? };
if info.has_fma() { write!(w, " fma")? };
if info.has_cmpxchg16b() { write!(w, " cx16")? };
if info.has_pdcm() { write!(w, " pdcm")? };
if info.has_pcid() { write!(w, " pcid")? };
if info.has_dca() { write!(w, " dca")? };
if info.has_sse41() { write!(w, " sse4_1")? };
if info.has_sse42() { write!(w, " sse4_2")? };
if info.has_x2apic() { write!(w, " x2apic")? };
if info.has_movbe() { write!(w, " movbe")? };
if info.has_popcnt() { write!(w, " popcnt")? };
if info.has_tsc_deadline() { write!(w, " tsc_deadline_timer")? };
if info.has_aesni() { write!(w, " aes")? };
if info.has_xsave() { write!(w, " xsave")? };
if info.has_oxsave() { write!(w, " xsaveopt")? };
if info.has_avx() { write!(w, " avx")? };
if info.has_f16c() { write!(w, " f16c")? };
if info.has_rdrand() { write!(w, " rdrand")? };
}
if let Some(info) = cpuid.get_extended_function_info() {
if info.has_64bit_mode() { write!(w, " lm")? };
if info.has_rdtscp() { write!(w, " rdtscp")? };
if info.has_1gib_pages() { write!(w, " pdpe1gb")? };
if info.has_execute_disable() { write!(w, " nx")? };
if info.has_syscall_sysret() { write!(w, " syscall")? };
if info.has_prefetchw() { write!(w, " prefetchw")? };
if info.has_lzcnt() { write!(w, " lzcnt")? };
if info.has_lahf_sahf() { write!(w, " lahf_lm")? };
if info.has_invariant_tsc() { write!(w, " constant_tsc")? };
}
if let Some(info) = cpuid.get_extended_feature_info() {
if info.has_fsgsbase() { write!(w, " fsgsbase")? };
if info.has_tsc_adjust_msr() { write!(w, " tsc_adjust")? };
if info.has_bmi1() { write!(w, " bmi1")? };
if info.has_hle() { write!(w, " hle")? };
if info.has_avx2() { write!(w, " avx2")? };
if info.has_smep() { write!(w, " smep")? };
if info.has_bmi2() { write!(w, " bmi2")? };
if info.has_rep_movsb_stosb() { write!(w, " erms")? };
if info.has_invpcid() { write!(w, " invpcid")? };
if info.has_rtm() { write!(w, " rtm")? };
if info.has_qm() { write!(w, " qm")? };
if info.has_fpu_cs_ds_deprecated() { write!(w, " fpu_seg")? };
if info.has_mpx() { write!(w, " mpx")? };
}
write!(w, "\n")?;
Ok(())
}

View file

@ -0,0 +1,115 @@
use core::intrinsics::{volatile_load, volatile_store};
use x86::cpuid::CpuId;
use x86::msr::*;
use memory::Frame;
use paging::{entry, ActivePageTable, PhysicalAddress, Page, VirtualAddress};
pub static mut LOCAL_APIC: LocalApic = LocalApic {
address: 0,
x2: false
};
pub unsafe fn init(active_table: &mut ActivePageTable) {
LOCAL_APIC.init(active_table);
}
pub unsafe fn init_ap() {
LOCAL_APIC.init_ap();
}
/// Local APIC
pub struct LocalApic {
pub address: usize,
pub x2: bool
}
impl LocalApic {
unsafe fn init(&mut self, active_table: &mut ActivePageTable) {
self.address = (rdmsr(IA32_APIC_BASE) as usize & 0xFFFF0000) + ::KERNEL_OFFSET;
self.x2 = CpuId::new().get_feature_info().unwrap().has_x2apic();
if ! self.x2 {
let page = Page::containing_address(VirtualAddress::new(self.address));
let frame = Frame::containing_address(PhysicalAddress::new(self.address - ::KERNEL_OFFSET));
let result = active_table.map_to(page, frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
result.flush(active_table);
}
self.init_ap();
}
unsafe fn init_ap(&mut self) {
if self.x2 {
wrmsr(IA32_APIC_BASE, rdmsr(IA32_APIC_BASE) | 1 << 10);
wrmsr(IA32_X2APIC_SIVR, 0x100);
} else {
self.write(0xF0, 0x100);
}
}
unsafe fn read(&self, reg: u32) -> u32 {
volatile_load((self.address + reg as usize) as *const u32)
}
unsafe fn write(&mut self, reg: u32, value: u32) {
volatile_store((self.address + reg as usize) as *mut u32, value);
}
pub fn id(&self) -> u32 {
if self.x2 {
unsafe { rdmsr(IA32_X2APIC_APICID) as u32 }
} else {
unsafe { self.read(0x20) }
}
}
pub fn version(&self) -> u32 {
if self.x2 {
unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 }
} else {
unsafe { self.read(0x30) }
}
}
pub fn icr(&self) -> u64 {
if self.x2 {
unsafe { rdmsr(IA32_X2APIC_ICR) }
} else {
unsafe {
(self.read(0x310) as u64) << 32 | self.read(0x300) as u64
}
}
}
pub fn set_icr(&mut self, value: u64) {
if self.x2 {
unsafe { wrmsr(IA32_X2APIC_ICR, value); }
} else {
unsafe {
while self.read(0x300) & 1 << 12 == 1 << 12 {}
self.write(0x310, (value >> 32) as u32);
self.write(0x300, value as u32);
while self.read(0x300) & 1 << 12 == 1 << 12 {}
}
}
}
pub fn ipi(&mut self, apic_id: usize) {
let mut icr = 0x4040;
if self.x2 {
icr |= (apic_id as u64) << 32;
} else {
icr |= (apic_id as u64) << 56;
}
self.set_icr(icr);
}
pub unsafe fn eoi(&mut self) {
if self.x2 {
wrmsr(IA32_X2APIC_EOI, 0);
} else {
self.write(0xB0, 0);
}
}
}

View file

@ -0,0 +1,16 @@
use paging::ActivePageTable;
pub mod cpu;
pub mod local_apic;
pub mod rtc;
pub mod serial;
pub unsafe fn init(active_table: &mut ActivePageTable){
local_apic::init(active_table);
rtc::init();
serial::init();
}
pub unsafe fn init_ap() {
local_apic::init_ap();
}

View file

@ -0,0 +1,109 @@
use io::{Io, Pio};
use time;
pub fn init() {
let mut rtc = Rtc::new();
time::START.lock().0 = rtc.time();
}
fn cvt_bcd(value: usize) -> usize {
(value & 0xF) + ((value / 16) * 10)
}
/// RTC
pub struct Rtc {
addr: Pio<u8>,
data: Pio<u8>,
}
impl Rtc {
/// Create new empty RTC
pub fn new() -> Self {
return Rtc {
addr: Pio::<u8>::new(0x70),
data: Pio::<u8>::new(0x71),
};
}
/// Read
unsafe fn read(&mut self, reg: u8) -> u8 {
self.addr.write(reg);
return self.data.read();
}
/// Wait
unsafe fn wait(&mut self) {
while self.read(0xA) & 0x80 != 0x80 {}
while self.read(0xA) & 0x80 == 0x80 {}
}
/// Get time
pub fn time(&mut self) -> u64 {
let mut second;
let mut minute;
let mut hour;
let mut day;
let mut month;
let mut year;
let register_b;
unsafe {
self.wait();
second = self.read(0) as usize;
minute = self.read(2) as usize;
hour = self.read(4) as usize;
day = self.read(7) as usize;
month = self.read(8) as usize;
year = self.read(9) as usize;
register_b = self.read(0xB);
}
if register_b & 4 != 4 {
second = cvt_bcd(second);
minute = cvt_bcd(minute);
hour = cvt_bcd(hour & 0x7F) | (hour & 0x80);
day = cvt_bcd(day);
month = cvt_bcd(month);
year = cvt_bcd(year);
}
if register_b & 2 != 2 || hour & 0x80 == 0x80 {
hour = ((hour & 0x7F) + 12) % 24;
}
// TODO: Century Register
year += 2000;
// Unix time from clock
let mut secs: u64 = (year as u64 - 1970) * 31536000;
let mut leap_days = (year as u64 - 1972) / 4 + 1;
if year % 4 == 0 {
if month <= 2 {
leap_days -= 1;
}
}
secs += leap_days * 86400;
match month {
2 => secs += 2678400,
3 => secs += 5097600,
4 => secs += 7776000,
5 => secs += 10368000,
6 => secs += 13046400,
7 => secs += 15638400,
8 => secs += 18316800,
9 => secs += 20995200,
10 => secs += 23587200,
11 => secs += 26265600,
12 => secs += 28857600,
_ => (),
}
secs += (day as u64 - 1) * 86400;
secs += hour as u64 * 3600;
secs += minute as u64 * 60;
secs += second as u64;
secs
}
}

View file

@ -0,0 +1,115 @@
use core::fmt::{self, Write};
use spin::Mutex;
use io::{Io, Pio, ReadOnly};
pub static COM1: Mutex<SerialPort> = Mutex::new(SerialPort::new(0x3F8));
pub static COM2: Mutex<SerialPort> = Mutex::new(SerialPort::new(0x2F8));
pub unsafe fn init() {
COM1.lock().init();
COM2.lock().init();
}
bitflags! {
/// Interrupt enable flags
flags IntEnFlags: u8 {
const RECEIVED = 1,
const SENT = 1 << 1,
const ERRORED = 1 << 2,
const STATUS_CHANGE = 1 << 3,
// 4 to 7 are unused
}
}
bitflags! {
/// Line status flags
flags LineStsFlags: u8 {
const INPUT_FULL = 1,
// 1 to 4 unknown
const OUTPUT_EMPTY = 1 << 5,
// 6 and 7 unknown
}
}
#[allow(dead_code)]
pub struct SerialPort {
/// Data register, read to receive, write to send
data: Pio<u8>,
/// Interrupt enable
int_en: Pio<u8>,
/// FIFO control
fifo_ctrl: Pio<u8>,
/// Line control
line_ctrl: Pio<u8>,
/// Modem control
modem_ctrl: Pio<u8>,
/// Line status
line_sts: ReadOnly<Pio<u8>>,
/// Modem status
modem_sts: ReadOnly<Pio<u8>>,
}
impl SerialPort {
const fn new(base: u16) -> SerialPort {
SerialPort {
data: Pio::new(base),
int_en: Pio::new(base + 1),
fifo_ctrl: Pio::new(base + 2),
line_ctrl: Pio::new(base + 3),
modem_ctrl: Pio::new(base + 4),
line_sts: ReadOnly::new(Pio::new(base + 5)),
modem_sts: ReadOnly::new(Pio::new(base + 6))
}
}
fn line_sts(&self) -> LineStsFlags {
LineStsFlags::from_bits_truncate(self.line_sts.read())
}
fn write(&mut self, data: u8) {
while ! self.line_sts().contains(OUTPUT_EMPTY) {}
self.data.write(data)
}
fn init(&mut self) {
//TODO: Cleanup
self.int_en.write(0x00);
self.line_ctrl.write(0x80);
self.data.write(0x03);
self.int_en.write(0x00);
self.line_ctrl.write(0x03);
self.fifo_ctrl.write(0xC7);
self.modem_ctrl.write(0x0B);
self.int_en.write(0x01);
}
pub fn on_receive(&mut self) {
let data = self.data.read();
extern {
fn debug_input(byte: u8);
}
unsafe { debug_input(data) };
}
}
impl Write for SerialPort {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
for byte in s.bytes() {
match byte {
8 | 0x7F => {
self.write(8);
self.write(b' ');
self.write(8);
},
_ => {
self.write(byte);
}
}
}
Ok(())
}
}

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 as usize + i) as *mut u8) = *((src as usize + i) as *const u8);
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 as usize + i) as *mut u8) = *((src as usize + i) as *const u8);
}
} else {
let mut i = 0;
while i < n {
*((dest as usize + i) as *mut u8) = *((src as usize + i) as *const u8);
i += 1;
}
}
dest
}
/// Memset
///
/// Fill a block of memory with a specified value.
#[no_mangle]
pub unsafe extern fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8 {
let mut i = 0;
while i < n {
*((dest as usize + i) as *mut u8) = c as u8;
i += 1;
}
dest
}
/// 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 as usize + i) as *const u8);
let b = *((s2 as usize + i) as *const u8);
if a != b {
return a as i32 - b as i32
}
i += 1;
}
0
}

View file

@ -0,0 +1,177 @@
//! Global descriptor table
use core::mem;
use x86::dtables::{self, DescriptorTablePointer};
use x86::segmentation::{self, SegmentSelector};
use x86::task::{self, TaskStateSegment};
pub const GDT_NULL: usize = 0;
pub const GDT_KERNEL_CODE: usize = 1;
pub const GDT_KERNEL_DATA: usize = 2;
pub const GDT_KERNEL_TLS: usize = 3;
pub const GDT_USER_CODE: usize = 4;
pub const GDT_USER_DATA: usize = 5;
pub const GDT_USER_TLS: usize = 6;
pub const GDT_TSS: usize = 7;
pub const GDT_TSS_HIGH: usize = 8;
pub const GDT_A_PRESENT: u8 = 1 << 7;
pub const GDT_A_RING_0: u8 = 0 << 5;
pub const GDT_A_RING_1: u8 = 1 << 5;
pub const GDT_A_RING_2: u8 = 2 << 5;
pub const GDT_A_RING_3: u8 = 3 << 5;
pub const GDT_A_SYSTEM: u8 = 1 << 4;
pub const GDT_A_EXECUTABLE: u8 = 1 << 3;
pub const GDT_A_CONFORMING: u8 = 1 << 2;
pub const GDT_A_PRIVILEGE: u8 = 1 << 1;
pub const GDT_A_DIRTY: u8 = 1;
pub const GDT_A_TSS_AVAIL: u8 = 0x9;
pub const GDT_A_TSS_BUSY: u8 = 0xB;
pub const GDT_F_PAGE_SIZE: u8 = 1 << 7;
pub const GDT_F_PROTECTED_MODE: u8 = 1 << 6;
pub const GDT_F_LONG_MODE: u8 = 1 << 5;
static mut INIT_GDTR: DescriptorTablePointer = DescriptorTablePointer {
limit: 0,
base: 0
};
static mut INIT_GDT: [GdtEntry; 4] = [
// Null
GdtEntry::new(0, 0, 0, 0),
// Kernel code
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
// Kernel data
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
// Kernel TLS
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE)
];
#[thread_local]
pub static mut GDTR: DescriptorTablePointer = DescriptorTablePointer {
limit: 0,
base: 0
};
#[thread_local]
pub static mut GDT: [GdtEntry; 9] = [
// Null
GdtEntry::new(0, 0, 0, 0),
// Kernel code
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
// Kernel data
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
// Kernel TLS
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
// User code
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
// User data
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
// User TLS
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
// TSS
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_TSS_AVAIL, 0),
// TSS must be 16 bytes long, twice the normal size
GdtEntry::new(0, 0, 0, 0),
];
#[thread_local]
pub static mut TSS: TaskStateSegment = TaskStateSegment {
reserved: 0,
rsp: [0; 3],
reserved2: 0,
ist: [0; 7],
reserved3: 0,
reserved4: 0,
iomap_base: 0xFFFF
};
/// Initialize GDT
pub unsafe fn init(tcb_offset: usize, stack_offset: usize) {
// Setup the initial GDT with TLS, so we can setup the TLS GDT (a little confusing)
// This means that each CPU will have its own GDT, but we only need to define it once as a thread local
INIT_GDTR.limit = (INIT_GDT.len() * mem::size_of::<GdtEntry>() - 1) as u16;
INIT_GDTR.base = INIT_GDT.as_ptr() as u64;
// Set the TLS segment to the offset of the Thread Control Block
INIT_GDT[GDT_KERNEL_TLS].set_offset(tcb_offset as u32);
// Load the initial GDT, before we have access to thread locals
dtables::lgdt(&INIT_GDTR);
// Load the segment descriptors
segmentation::load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16));
segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16));
segmentation::load_es(SegmentSelector::new(GDT_KERNEL_DATA as u16));
segmentation::load_fs(SegmentSelector::new(GDT_KERNEL_TLS as u16));
segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_DATA as u16));
segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16));
// Now that we have access to thread locals, setup the AP's individual GDT
GDTR.limit = (GDT.len() * mem::size_of::<GdtEntry>() - 1) as u16;
GDTR.base = GDT.as_ptr() as u64;
// Set the TLS segment to the offset of the Thread Control Block
GDT[GDT_KERNEL_TLS].set_offset(tcb_offset as u32);
// Set the User TLS segment to the offset of the user TCB
GDT[GDT_USER_TLS].set_offset(::USER_TCB_OFFSET as u32);
// We can now access our TSS, which is a thread local
GDT[GDT_TSS].set_offset(&TSS as *const _ as u32);
GDT[GDT_TSS].set_limit(mem::size_of::<TaskStateSegment>() as u32);
// Set the stack pointer when coming back from userspace
TSS.rsp[0] = stack_offset as u64;
// Load the new GDT, which is correctly located in thread local storage
dtables::lgdt(&GDTR);
// Reload the segment descriptors
segmentation::load_cs(SegmentSelector::new(GDT_KERNEL_CODE as u16));
segmentation::load_ds(SegmentSelector::new(GDT_KERNEL_DATA as u16));
segmentation::load_es(SegmentSelector::new(GDT_KERNEL_DATA as u16));
segmentation::load_fs(SegmentSelector::new(GDT_KERNEL_TLS as u16));
segmentation::load_gs(SegmentSelector::new(GDT_KERNEL_DATA as u16));
segmentation::load_ss(SegmentSelector::new(GDT_KERNEL_DATA as u16));
// Load the task register
task::load_ltr(SegmentSelector::new(GDT_TSS as u16));
}
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct GdtEntry {
pub limitl: u16,
pub offsetl: u16,
pub offsetm: u8,
pub access: u8,
pub flags_limith: u8,
pub offseth: u8
}
impl GdtEntry {
pub const fn new(offset: u32, limit: u32, access: u8, flags: u8) -> Self {
GdtEntry {
limitl: limit as u16,
offsetl: offset as u16,
offsetm: (offset >> 16) as u8,
access: access,
flags_limith: flags & 0xF0 | ((limit >> 16) as u8) & 0x0F,
offseth: (offset >> 24) as u8
}
}
pub fn set_offset(&mut self, offset: u32) {
self.offsetl = offset as u16;
self.offsetm = (offset >> 16) as u8;
self.offseth = (offset >> 24) as u8;
}
pub fn set_limit(&mut self, limit: u32) {
self.limitl = limit as u16;
self.flags_limith = self.flags_limith & 0xF0 | ((limit >> 16) as u8) & 0x0F;
}
}

View file

@ -0,0 +1,142 @@
use core::mem;
use x86::dtables::{self, DescriptorTablePointer};
use interrupt::*;
pub static mut IDTR: DescriptorTablePointer = DescriptorTablePointer {
limit: 0,
base: 0
};
pub static mut IDT: [IdtEntry; 256] = [IdtEntry::new(); 256];
pub unsafe fn init() {
IDTR.limit = (IDT.len() * mem::size_of::<IdtEntry>() - 1) as u16;
IDTR.base = IDT.as_ptr() as u64;
// Set up exceptions
IDT[0].set_func(exception::divide_by_zero);
IDT[1].set_func(exception::debug);
IDT[2].set_func(exception::non_maskable);
IDT[3].set_func(exception::breakpoint);
IDT[4].set_func(exception::overflow);
IDT[5].set_func(exception::bound_range);
IDT[6].set_func(exception::invalid_opcode);
IDT[7].set_func(exception::device_not_available);
IDT[8].set_func(exception::double_fault);
// 9 no longer available
IDT[10].set_func(exception::invalid_tss);
IDT[11].set_func(exception::segment_not_present);
IDT[12].set_func(exception::stack_segment);
IDT[13].set_func(exception::protection);
IDT[14].set_func(exception::page);
// 15 reserved
IDT[16].set_func(exception::fpu);
IDT[17].set_func(exception::alignment_check);
IDT[18].set_func(exception::machine_check);
IDT[19].set_func(exception::simd);
IDT[20].set_func(exception::virtualization);
// 21 through 29 reserved
IDT[30].set_func(exception::security);
// 31 reserved
// Set up IRQs
IDT[32].set_func(irq::pit);
IDT[33].set_func(irq::keyboard);
IDT[34].set_func(irq::cascade);
IDT[35].set_func(irq::com2);
IDT[36].set_func(irq::com1);
IDT[37].set_func(irq::lpt2);
IDT[38].set_func(irq::floppy);
IDT[39].set_func(irq::lpt1);
IDT[40].set_func(irq::rtc);
IDT[41].set_func(irq::pci1);
IDT[42].set_func(irq::pci2);
IDT[43].set_func(irq::pci3);
IDT[44].set_func(irq::mouse);
IDT[45].set_func(irq::fpu);
IDT[46].set_func(irq::ata1);
IDT[47].set_func(irq::ata2);
// Set IPI handler (null)
IDT[0x40].set_func(ipi::ipi);
// Set syscall function
IDT[0x80].set_func(syscall::syscall);
IDT[0x80].set_flags(IDT_PRESENT | IDT_RING_3 | IDT_INTERRUPT);
dtables::lidt(&IDTR);
}
bitflags! {
pub flags IdtFlags: u8 {
const IDT_PRESENT = 1 << 7,
const IDT_RING_0 = 0 << 5,
const IDT_RING_1 = 1 << 5,
const IDT_RING_2 = 2 << 5,
const IDT_RING_3 = 3 << 5,
const IDT_SS = 1 << 4,
const IDT_INTERRUPT = 0xE,
const IDT_TRAP = 0xF,
}
}
#[repr(packed)]
pub struct IdtDescriptor {
size: u16,
offset: u64
}
impl IdtDescriptor {
pub fn set_slice(&mut self, slice: &'static [IdtEntry]) {
self.size = (slice.len() * mem::size_of::<IdtEntry>() - 1) as u16;
self.offset = slice.as_ptr() as u64;
}
pub unsafe fn load(&self) {
asm!("lidt [rax]" : : "{rax}"(self as *const _ as usize) : : "intel", "volatile");
}
}
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct IdtEntry {
offsetl: u16,
selector: u16,
zero: u8,
attribute: u8,
offsetm: u16,
offseth: u32,
zero2: u32
}
impl IdtEntry {
pub const fn new() -> IdtEntry {
IdtEntry {
offsetl: 0,
selector: 0,
zero: 0,
attribute: 0,
offsetm: 0,
offseth: 0,
zero2: 0
}
}
pub fn set_flags(&mut self, flags: IdtFlags) {
self.attribute = flags.bits;
}
pub fn set_offset(&mut self, selector: u16, base: usize) {
self.selector = selector;
self.offsetl = base as u16;
self.offsetm = (base >> 16) as u16;
self.offseth = (base >> 32) as u32;
}
// A function to set the offset more easily
pub fn set_func(&mut self, func: unsafe extern fn()) {
self.set_flags(IDT_PRESENT | IDT_RING_0 | IDT_INTERRUPT);
self.set_offset(8, func as usize);
}
}

View file

@ -0,0 +1,123 @@
use interrupt::stack_trace;
use syscall::flag::*;
extern {
fn ksignal(signal: usize);
}
interrupt_stack!(divide_by_zero, stack, {
println!("Divide by zero fault at {:>02X}:{:>016X}", stack.cs, stack.rip);
stack_trace();
ksignal(SIGFPE);
});
interrupt_stack!(debug, stack, {
println!("Debug trap at {:>02X}:{:>016X}", stack.cs, stack.rip);
ksignal(SIGTRAP);
});
interrupt_stack!(non_maskable, stack, {
println!("Non-maskable interrupt at {:>02X}:{:>016X}", stack.cs, stack.rip);
});
interrupt_stack!(breakpoint, stack, {
println!("Breakpoint trap at {:>02X}:{:>016X}", stack.cs, stack.rip);
ksignal(SIGTRAP);
});
interrupt_stack!(overflow, stack, {
println!("Overflow trap at {:>02X}:{:>016X}", stack.cs, stack.rip);
ksignal(SIGFPE);
});
interrupt_stack!(bound_range, stack, {
println!("Bound range exceeded fault at {:>02X}:{:>016X}", stack.cs, stack.rip);
stack_trace();
ksignal(SIGSEGV);
});
interrupt_stack!(invalid_opcode, stack, {
println!("Invalid opcode fault at {:>02X}:{:>016X}", stack.cs, stack.rip);
stack_trace();
ksignal(SIGILL);
});
interrupt_stack!(device_not_available, stack, {
println!("Device not available fault at {:>02X}:{:>016X}", stack.cs, stack.rip);
stack_trace();
ksignal(SIGILL);
});
interrupt_error!(double_fault, stack, {
println!("Double fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip);
stack_trace();
ksignal(SIGSEGV);
});
interrupt_error!(invalid_tss, stack, {
println!("Invalid TSS fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip);
stack_trace();
ksignal(SIGSEGV);
});
interrupt_error!(segment_not_present, stack, {
println!("Segment not present fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip);
stack_trace();
ksignal(SIGSEGV);
});
interrupt_error!(stack_segment, stack, {
println!("Stack segment fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip);
stack_trace();
ksignal(SIGSEGV);
});
interrupt_error!(protection, stack, {
println!("Protection fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip);
stack_trace();
ksignal(SIGSEGV);
});
interrupt_error!(page, stack, {
let cr2: usize;
asm!("mov rax, cr2" : "={rax}"(cr2) : : : "intel", "volatile");
println!("Page fault: {:>02X}:{:>016X} at {:>02X}:{:>016X}", stack.code, cr2, stack.cs, stack.rip);
stack_trace();
ksignal(SIGSEGV);
});
interrupt_stack!(fpu, stack, {
println!("FPU floating point fault at {:>02X}:{:>016X}", stack.cs, stack.rip);
stack_trace();
ksignal(SIGFPE);
});
interrupt_error!(alignment_check, stack, {
println!("Alignment check fault: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip);
stack_trace();
ksignal(SIGBUS);
});
interrupt_stack!(machine_check, stack, {
println!("Machine check fault at {:>02X}:{:>016X}", stack.cs, stack.rip);
stack_trace();
ksignal(SIGBUS);
});
interrupt_stack!(simd, stack, {
println!("SIMD floating point fault at {:>02X}:{:>016X}", stack.cs, stack.rip);
stack_trace();
ksignal(SIGFPE);
});
interrupt_stack!(virtualization, stack, {
println!("Virtualization fault at {:>02X}:{:>016X}", stack.cs, stack.rip);
stack_trace();
ksignal(SIGBUS);
});
interrupt_error!(security, stack, {
println!("Security exception: {:X} at {:>02X}:{:>016X}", stack.code, stack.cs, stack.rip);
stack_trace();
ksignal(SIGBUS);
});

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