Add rustfmt from relibc and apply it with cargo fmt
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
use rustc_cfg::Cfg;
|
||||
use std::{env, path::Path, process::Command};
|
||||
use toml::Table;
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
fn parse_kconfig(arch: &str) -> Option<()> {
|
||||
println!("cargo:rerun-if-changed=config.toml");
|
||||
@@ -14,9 +12,16 @@ fn parse_kconfig(arch: &str) -> Option<()> {
|
||||
let config_str = std::fs::read_to_string("config.toml").unwrap();
|
||||
let root: Table = toml::from_str(&config_str).unwrap();
|
||||
|
||||
let altfeatures = root.get("arch")?.as_table().unwrap()
|
||||
.get(arch)?.as_table().unwrap()
|
||||
.get("features")?.as_table().unwrap();
|
||||
let altfeatures = root
|
||||
.get("arch")?
|
||||
.as_table()
|
||||
.unwrap()
|
||||
.get(arch)?
|
||||
.as_table()
|
||||
.unwrap()
|
||||
.get("features")?
|
||||
.as_table()
|
||||
.unwrap();
|
||||
|
||||
for (name, value) in altfeatures {
|
||||
let choice = value.as_str().unwrap();
|
||||
@@ -45,30 +50,34 @@ fn main() {
|
||||
.target("aarch64-unknown-redox")
|
||||
.compile("early_init");
|
||||
*/
|
||||
},
|
||||
}
|
||||
"x86" => {
|
||||
println!("cargo:rerun-if-changed=src/asm/x86/trampoline.asm");
|
||||
|
||||
let status = Command::new("nasm")
|
||||
.arg("-f").arg("bin")
|
||||
.arg("-o").arg(format!("{}/trampoline", out_dir))
|
||||
.arg("-f")
|
||||
.arg("bin")
|
||||
.arg("-o")
|
||||
.arg(format!("{}/trampoline", out_dir))
|
||||
.arg("src/asm/x86/trampoline.asm")
|
||||
.status()
|
||||
.expect("failed to run nasm");
|
||||
if ! status.success() {
|
||||
if !status.success() {
|
||||
panic!("nasm failed with exit status {}", status);
|
||||
}
|
||||
},
|
||||
}
|
||||
"x86_64" => {
|
||||
println!("cargo:rerun-if-changed=src/asm/x86_64/trampoline.asm");
|
||||
|
||||
let status = Command::new("nasm")
|
||||
.arg("-f").arg("bin")
|
||||
.arg("-o").arg(format!("{}/trampoline", out_dir))
|
||||
.arg("-f")
|
||||
.arg("bin")
|
||||
.arg("-o")
|
||||
.arg(format!("{}/trampoline", out_dir))
|
||||
.arg("src/asm/x86_64/trampoline.asm")
|
||||
.status()
|
||||
.expect("failed to run nasm");
|
||||
if ! status.success() {
|
||||
if !status.success() {
|
||||
panic!("nasm failed with exit status {}", status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
blank_lines_lower_bound = 0
|
||||
blank_lines_upper_bound = 1
|
||||
brace_style = "SameLineWhere"
|
||||
disable_all_formatting = false
|
||||
edition = "2018"
|
||||
empty_item_single_line = true
|
||||
fn_single_line = false
|
||||
force_explicit_abi = true
|
||||
format_strings = false
|
||||
hard_tabs = false
|
||||
hide_parse_errors = false
|
||||
imports_granularity = "Crate"
|
||||
imports_indent = "Block"
|
||||
imports_layout = "Mixed"
|
||||
indent_style = "Block"
|
||||
max_width = 100
|
||||
newline_style = "Unix"
|
||||
skip_children = false
|
||||
tab_spaces = 4
|
||||
trailing_comma = "Vertical"
|
||||
where_single_line = false
|
||||
+31
-13
@@ -2,12 +2,12 @@ use core::{mem, ptr};
|
||||
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
|
||||
use crate::memory::Frame;
|
||||
use crate::paging::{KernelMapper, PhysicalAddress, PageFlags};
|
||||
use crate::paging::entry::EntryFlags;
|
||||
use crate::{
|
||||
memory::Frame,
|
||||
paging::{entry::EntryFlags, KernelMapper, PageFlags, PhysicalAddress},
|
||||
};
|
||||
|
||||
use super::sdt::Sdt;
|
||||
use super::{ACPI_TABLE, find_sdt};
|
||||
use super::{find_sdt, sdt::Sdt, ACPI_TABLE};
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
@@ -32,7 +32,7 @@ pub struct Hpet {
|
||||
|
||||
pub hpet_number: u8,
|
||||
pub min_periodic_clk_tick: u16,
|
||||
pub oem_attribute: u8
|
||||
pub oem_attribute: u8,
|
||||
}
|
||||
|
||||
impl Hpet {
|
||||
@@ -75,13 +75,21 @@ impl GenericAddressStructure {
|
||||
|
||||
mapper
|
||||
.get_mut()
|
||||
.expect("KernelMapper locked re-entrant while mapping memory for GenericAddressStructure")
|
||||
.map_phys(page.start_address(), frame.start_address(), PageFlags::new().write(true).custom_flag(EntryFlags::NO_CACHE.bits(), true))
|
||||
.expect(
|
||||
"KernelMapper locked re-entrant while mapping memory for GenericAddressStructure",
|
||||
)
|
||||
.map_phys(
|
||||
page.start_address(),
|
||||
frame.start_address(),
|
||||
PageFlags::new()
|
||||
.write(true)
|
||||
.custom_flag(EntryFlags::NO_CACHE.bits(), true),
|
||||
)
|
||||
.expect("failed to map memory for GenericAddressStructure")
|
||||
.flush();
|
||||
}
|
||||
|
||||
pub unsafe fn read_u64(&self, offset: usize) -> u64{
|
||||
pub unsafe fn read_u64(&self, offset: usize) -> u64 {
|
||||
read_volatile((crate::HPET_OFFSET + offset) as *const u64)
|
||||
}
|
||||
|
||||
@@ -96,17 +104,27 @@ impl GenericAddressStructure {
|
||||
let frame = Frame::containing_address(PhysicalAddress::new(self.address as usize));
|
||||
let (_, result) = mapper
|
||||
.get_mut()
|
||||
.expect("KernelMapper locked re-entrant while mapping memory for GenericAddressStructure")
|
||||
.map_linearly(frame.start_address(), PageFlags::new().write(true).custom_flag(EntryFlags::NO_CACHE.bits(), true))
|
||||
.expect(
|
||||
"KernelMapper locked re-entrant while mapping memory for GenericAddressStructure",
|
||||
)
|
||||
.map_linearly(
|
||||
frame.start_address(),
|
||||
PageFlags::new()
|
||||
.write(true)
|
||||
.custom_flag(EntryFlags::NO_CACHE.bits(), true),
|
||||
)
|
||||
.expect("failed to map memory for GenericAddressStructure");
|
||||
result.flush();
|
||||
}
|
||||
|
||||
pub unsafe fn read_u64(&self, offset: usize) -> u64{
|
||||
pub unsafe fn read_u64(&self, offset: usize) -> u64 {
|
||||
read_volatile((self.address as usize + offset + crate::PHYS_OFFSET) as *const u64)
|
||||
}
|
||||
|
||||
pub unsafe fn write_u64(&mut self, offset: usize, value: u64) {
|
||||
write_volatile((self.address as usize + offset + crate::PHYS_OFFSET) as *mut u64, value);
|
||||
write_volatile(
|
||||
(self.address as usize + offset + crate::PHYS_OFFSET) as *mut u64,
|
||||
value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+139
-110
@@ -1,23 +1,26 @@
|
||||
use core::mem;
|
||||
|
||||
use crate::memory::{allocate_frames, Frame};
|
||||
use crate::paging::{KernelMapper, Page, PageFlags, PhysicalAddress, RmmA, RmmArch, VirtualAddress};
|
||||
use crate::{
|
||||
memory::{allocate_frames, Frame},
|
||||
paging::{KernelMapper, Page, PageFlags, PhysicalAddress, RmmA, RmmArch, VirtualAddress},
|
||||
};
|
||||
|
||||
use super::sdt::Sdt;
|
||||
use super::find_sdt;
|
||||
use super::{find_sdt, sdt::Sdt};
|
||||
|
||||
use core::sync::atomic::{AtomicU8, Ordering};
|
||||
|
||||
use crate::device::local_apic::LOCAL_APIC;
|
||||
use crate::interrupt;
|
||||
use crate::start::{kstart_ap, CPU_COUNT, AP_READY};
|
||||
use crate::{
|
||||
device::local_apic::LOCAL_APIC,
|
||||
interrupt,
|
||||
start::{kstart_ap, AP_READY, CPU_COUNT},
|
||||
};
|
||||
|
||||
/// The Multiple APIC Descriptor Table
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Madt {
|
||||
sdt: &'static Sdt,
|
||||
pub local_address: u32,
|
||||
pub flags: u32
|
||||
pub flags: u32,
|
||||
}
|
||||
|
||||
const TRAMPOLINE: usize = 0x8000;
|
||||
@@ -80,85 +83,96 @@ impl Madt {
|
||||
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().data() + crate::PHYS_OFFSET;
|
||||
let stack_end = stack_start + 64 * 4096;
|
||||
|
||||
let ap_ready = (TRAMPOLINE + 8) as *mut u64;
|
||||
let ap_cpu_id = unsafe { ap_ready.add(1) };
|
||||
let ap_page_table = unsafe { ap_ready.add(2) };
|
||||
let ap_stack_start = unsafe { ap_ready.add(3) };
|
||||
let ap_stack_end = unsafe { ap_ready.add(4) };
|
||||
let ap_code = unsafe { ap_ready.add(5) };
|
||||
|
||||
// Set the ap_ready to 0, volatile
|
||||
unsafe {
|
||||
ap_ready.write(0);
|
||||
ap_cpu_id.write(ap_local_apic.id.into());
|
||||
ap_page_table.write(page_table_physaddr as u64);
|
||||
ap_stack_start.write(stack_start as u64);
|
||||
ap_stack_end.write(stack_end as u64);
|
||||
ap_code.write(kstart_ap as u64);
|
||||
|
||||
// TODO: Is this necessary (this fence)?
|
||||
core::arch::asm!("");
|
||||
};
|
||||
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 = (TRAMPOLINE >> 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 { (*ap_ready.cast::<AtomicU8>()).load(Ordering::SeqCst) } == 0 {
|
||||
interrupt::pause();
|
||||
}
|
||||
print!(" Trampoline...");
|
||||
while ! AP_READY.load(Ordering::SeqCst) {
|
||||
interrupt::pause();
|
||||
}
|
||||
println!(" Ready");
|
||||
|
||||
unsafe { RmmA::invalidate_all(); }
|
||||
MadtEntry::LocalApic(ap_local_apic) => {
|
||||
if ap_local_apic.id == me {
|
||||
println!(" This is my local APIC");
|
||||
} else {
|
||||
println!(" CPU Disabled");
|
||||
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()
|
||||
.data()
|
||||
+ crate::PHYS_OFFSET;
|
||||
let stack_end = stack_start + 64 * 4096;
|
||||
|
||||
let ap_ready = (TRAMPOLINE + 8) as *mut u64;
|
||||
let ap_cpu_id = unsafe { ap_ready.add(1) };
|
||||
let ap_page_table = unsafe { ap_ready.add(2) };
|
||||
let ap_stack_start = unsafe { ap_ready.add(3) };
|
||||
let ap_stack_end = unsafe { ap_ready.add(4) };
|
||||
let ap_code = unsafe { ap_ready.add(5) };
|
||||
|
||||
// Set the ap_ready to 0, volatile
|
||||
unsafe {
|
||||
ap_ready.write(0);
|
||||
ap_cpu_id.write(ap_local_apic.id.into());
|
||||
ap_page_table.write(page_table_physaddr as u64);
|
||||
ap_stack_start.write(stack_start as u64);
|
||||
ap_stack_end.write(stack_end as u64);
|
||||
ap_code.write(kstart_ap as u64);
|
||||
|
||||
// TODO: Is this necessary (this fence)?
|
||||
core::arch::asm!("");
|
||||
};
|
||||
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 = (TRAMPOLINE >> 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 {
|
||||
(*ap_ready.cast::<AtomicU8>()).load(Ordering::SeqCst)
|
||||
} == 0
|
||||
{
|
||||
interrupt::pause();
|
||||
}
|
||||
print!(" Trampoline...");
|
||||
while !AP_READY.load(Ordering::SeqCst) {
|
||||
interrupt::pause();
|
||||
}
|
||||
println!(" Ready");
|
||||
|
||||
unsafe {
|
||||
RmmA::invalidate_all();
|
||||
}
|
||||
} else {
|
||||
println!(" CPU Disabled");
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,14 +190,15 @@ 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
|
||||
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,
|
||||
local_address,
|
||||
flags
|
||||
flags,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -193,7 +208,7 @@ impl Madt {
|
||||
pub fn iter(&self) -> MadtIter {
|
||||
MadtIter {
|
||||
sdt: self.sdt,
|
||||
i: 8 // Skip local controller address and flags
|
||||
i: 8, // Skip local controller address and flags
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,7 +222,7 @@ pub struct MadtLocalApic {
|
||||
/// Local APIC ID
|
||||
pub id: u8,
|
||||
/// Flags. 1 means that the processor is enabled
|
||||
pub flags: u32
|
||||
pub flags: u32,
|
||||
}
|
||||
|
||||
/// MADT I/O APIC
|
||||
@@ -221,7 +236,7 @@ pub struct MadtIoApic {
|
||||
/// I/O APIC address
|
||||
pub address: u32,
|
||||
/// Global system interrupt base
|
||||
pub gsi_base: u32
|
||||
pub gsi_base: u32,
|
||||
}
|
||||
|
||||
/// MADT Interrupt Source Override
|
||||
@@ -235,7 +250,7 @@ pub struct MadtIntSrcOverride {
|
||||
/// Global system interrupt base
|
||||
pub gsi_base: u32,
|
||||
/// Flags
|
||||
pub flags: u16
|
||||
pub flags: u16,
|
||||
}
|
||||
|
||||
/// MADT Entries
|
||||
@@ -247,12 +262,12 @@ pub enum MadtEntry {
|
||||
InvalidIoApic(usize),
|
||||
IntSrcOverride(&'static MadtIntSrcOverride),
|
||||
InvalidIntSrcOverride(usize),
|
||||
Unknown(u8)
|
||||
Unknown(u8),
|
||||
}
|
||||
|
||||
pub struct MadtIter {
|
||||
sdt: &'static Sdt,
|
||||
i: usize
|
||||
i: usize,
|
||||
}
|
||||
|
||||
impl Iterator for MadtIter {
|
||||
@@ -260,26 +275,40 @@ impl Iterator for MadtIter {
|
||||
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).add(self.i) };
|
||||
let entry_len = unsafe { *(self.sdt.data_address() as *const u8).add(self.i + 1) } as usize;
|
||||
let entry_len =
|
||||
unsafe { *(self.sdt.data_address() as *const u8).add(self.i + 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)
|
||||
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;
|
||||
|
||||
+22
-18
@@ -1,38 +1,37 @@
|
||||
//! # ACPI
|
||||
//! Code to parse the ACPI tables
|
||||
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::{boxed::Box, string::String, vec::Vec};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use spin::{Once, RwLock};
|
||||
|
||||
use crate::log::info;
|
||||
use crate::paging::{KernelMapper, PageFlags, PhysicalAddress, RmmA, RmmArch};
|
||||
use crate::{
|
||||
log::info,
|
||||
paging::{KernelMapper, PageFlags, PhysicalAddress, RmmA, RmmArch},
|
||||
};
|
||||
|
||||
use self::madt::Madt;
|
||||
use self::rsdt::Rsdt;
|
||||
use self::sdt::Sdt;
|
||||
use self::xsdt::Xsdt;
|
||||
use self::hpet::Hpet;
|
||||
use self::rxsdt::Rxsdt;
|
||||
use self::rsdp::RSDP;
|
||||
use self::{hpet::Hpet, madt::Madt, rsdp::RSDP, rsdt::Rsdt, rxsdt::Rxsdt, sdt::Sdt, xsdt::Xsdt};
|
||||
|
||||
pub mod hpet;
|
||||
pub mod madt;
|
||||
mod rsdp;
|
||||
mod rsdt;
|
||||
mod rxsdt;
|
||||
pub mod sdt;
|
||||
mod xsdt;
|
||||
mod rxsdt;
|
||||
mod rsdp;
|
||||
|
||||
unsafe fn map_linearly(addr: PhysicalAddress, len: usize, mapper: &mut crate::paging::PageMapper) {
|
||||
let base = PhysicalAddress::new(crate::paging::round_down_pages(addr.data()));
|
||||
let aligned_len = crate::paging::round_up_pages(len + (addr.data() - base.data()));
|
||||
|
||||
for page_idx in 0..aligned_len / crate::memory::PAGE_SIZE {
|
||||
let (_, flush) = mapper.map_linearly(base.add(page_idx * crate::memory::PAGE_SIZE), PageFlags::new()).expect("failed to linearly map SDT");
|
||||
let (_, flush) = mapper
|
||||
.map_linearly(
|
||||
base.add(page_idx * crate::memory::PAGE_SIZE),
|
||||
PageFlags::new(),
|
||||
)
|
||||
.expect("failed to linearly map SDT");
|
||||
flush.flush();
|
||||
}
|
||||
}
|
||||
@@ -52,7 +51,11 @@ pub fn get_sdt(sdt_address: usize, mapper: &mut KernelMapper) -> &'static Sdt {
|
||||
|
||||
sdt = &*(RmmA::phys_to_virt(physaddr).data() as *const Sdt);
|
||||
|
||||
map_linearly(physaddr.add(SDT_SIZE), sdt.length as usize - SDT_SIZE, mapper);
|
||||
map_linearly(
|
||||
physaddr.add(SDT_SIZE),
|
||||
sdt.length as usize - SDT_SIZE,
|
||||
mapper,
|
||||
);
|
||||
}
|
||||
sdt
|
||||
}
|
||||
@@ -151,7 +154,7 @@ pub type SdtSignature = (String, [u8; 6], [u8; 8]);
|
||||
pub static SDT_POINTERS: RwLock<Option<HashMap<SdtSignature, &'static Sdt>>> = RwLock::new(None);
|
||||
|
||||
pub fn find_sdt(name: &str) -> Vec<&'static Sdt> {
|
||||
let mut sdts: Vec<&'static Sdt> = vec!();
|
||||
let mut sdts: Vec<&'static Sdt> = vec![];
|
||||
|
||||
if let Some(ref ptrs) = *(SDT_POINTERS.read()) {
|
||||
for (signature, sdt) in ptrs {
|
||||
@@ -165,7 +168,8 @@ pub fn find_sdt(name: &str) -> Vec<&'static Sdt> {
|
||||
}
|
||||
|
||||
pub fn get_sdt_signature(sdt: &'static Sdt) -> SdtSignature {
|
||||
let signature = String::from_utf8(sdt.signature.to_vec()).expect("Error converting signature to string");
|
||||
let signature =
|
||||
String::from_utf8(sdt.signature.to_vec()).expect("Error converting signature to string");
|
||||
(signature, sdt.oem_id, sdt.oem_table_id)
|
||||
}
|
||||
|
||||
|
||||
+41
-15
@@ -1,8 +1,9 @@
|
||||
use core::convert::TryFrom;
|
||||
use core::mem;
|
||||
use core::{convert::TryFrom, mem};
|
||||
|
||||
use crate::memory::Frame;
|
||||
use crate::paging::{KernelMapper, Page, PageFlags, PhysicalAddress, VirtualAddress};
|
||||
use crate::{
|
||||
memory::Frame,
|
||||
paging::{KernelMapper, Page, PageFlags, PhysicalAddress, VirtualAddress},
|
||||
};
|
||||
|
||||
/// RSDP
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@@ -16,7 +17,7 @@ pub struct RSDP {
|
||||
_length: u32,
|
||||
xsdt_address: u64,
|
||||
_extended_checksum: u8,
|
||||
_reserved: [u8; 3]
|
||||
_reserved: [u8; 3],
|
||||
}
|
||||
|
||||
impl RSDP {
|
||||
@@ -36,12 +37,16 @@ impl RSDP {
|
||||
type Item = &'a [u8];
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.buf.len() < 4 { return None }
|
||||
if self.buf.len() < 4 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let length_bytes = <[u8; 4]>::try_from(&self.buf[..4]).ok()?;
|
||||
let length = u32::from_ne_bytes(length_bytes) as usize;
|
||||
|
||||
if (4 + length as usize) > self.buf.len() { return None }
|
||||
if (4 + length as usize) > self.buf.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let buf = &self.buf[4..4 + length];
|
||||
self.buf = &self.buf[4 + length..];
|
||||
@@ -56,24 +61,36 @@ impl RSDP {
|
||||
let rsdp = unsafe { &*(slice.as_ptr() as *const RSDP) };
|
||||
// TODO: Validate
|
||||
Some(rsdp)
|
||||
} else { None }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// first, find an RSDP for ACPI 2.0
|
||||
if let Some(rsdp_2_0) = (Iter { buf: area }.filter_map(slice_to_rsdp).find(|rsdp| rsdp.is_acpi_2_0())) {
|
||||
if let Some(rsdp_2_0) = (Iter { buf: area }
|
||||
.filter_map(slice_to_rsdp)
|
||||
.find(|rsdp| rsdp.is_acpi_2_0()))
|
||||
{
|
||||
return Some(*rsdp_2_0);
|
||||
}
|
||||
|
||||
// secondly, find an RSDP for ACPI 1.0
|
||||
if let Some(rsdp_1_0) = (Iter { buf: area }.filter_map(slice_to_rsdp).find(|rsdp| rsdp.is_acpi_1_0())) {
|
||||
if let Some(rsdp_1_0) = (Iter { buf: area }
|
||||
.filter_map(slice_to_rsdp)
|
||||
.find(|rsdp| rsdp.is_acpi_1_0()))
|
||||
{
|
||||
return Some(*rsdp_1_0);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
pub fn get_rsdp(mapper: &mut KernelMapper, already_supplied_rsdps: Option<(u64, u64)>) -> Option<RSDP> {
|
||||
pub fn get_rsdp(
|
||||
mapper: &mut KernelMapper,
|
||||
already_supplied_rsdps: Option<(u64, u64)>,
|
||||
) -> Option<RSDP> {
|
||||
if let Some((base, size)) = already_supplied_rsdps {
|
||||
let area = unsafe { core::slice::from_raw_parts(base as usize as *const u8, size as usize) };
|
||||
let area =
|
||||
unsafe { core::slice::from_raw_parts(base as usize as *const u8, size as usize) };
|
||||
Self::get_already_supplied_rsdps(area).or_else(|| Self::get_rsdp_by_searching(mapper))
|
||||
} else {
|
||||
Self::get_rsdp_by_searching(mapper)
|
||||
@@ -89,9 +106,18 @@ impl RSDP {
|
||||
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().data()));
|
||||
let page =
|
||||
Page::containing_address(VirtualAddress::new(frame.start_address().data()));
|
||||
let result = unsafe {
|
||||
mapper.get_mut().expect("KernelMapper locked re-entrant while locating RSDPs").map_phys(page.start_address(), frame.start_address(), PageFlags::new()).expect("failed to map page while searching for RSDP")
|
||||
mapper
|
||||
.get_mut()
|
||||
.expect("KernelMapper locked re-entrant while locating RSDPs")
|
||||
.map_phys(
|
||||
page.start_address(),
|
||||
frame.start_address(),
|
||||
PageFlags::new(),
|
||||
)
|
||||
.expect("failed to map page while searching for RSDP")
|
||||
};
|
||||
result.flush();
|
||||
}
|
||||
@@ -101,7 +127,7 @@ impl RSDP {
|
||||
}
|
||||
|
||||
fn search(start_addr: usize, end_addr: usize) -> Option<RSDP> {
|
||||
for i in 0 .. (end_addr + 1 - start_addr)/16 {
|
||||
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);
|
||||
|
||||
+8
-15
@@ -1,9 +1,7 @@
|
||||
use core::convert::TryFrom;
|
||||
use core::mem;
|
||||
use alloc::boxed::Box;
|
||||
use core::{convert::TryFrom, mem};
|
||||
|
||||
use super::sdt::Sdt;
|
||||
use super::rxsdt::Rxsdt;
|
||||
use super::{rxsdt::Rxsdt, sdt::Sdt};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Rsdt(&'static Sdt);
|
||||
@@ -17,33 +15,28 @@ impl Rsdt {
|
||||
}
|
||||
}
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
let length = usize::try_from(self.0.length)
|
||||
.expect("expected 32-bit length to fit within usize");
|
||||
let length =
|
||||
usize::try_from(self.0.length).expect("expected 32-bit length to fit within usize");
|
||||
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(self.0 as *const _ as *const u8, length)
|
||||
}
|
||||
unsafe { core::slice::from_raw_parts(self.0 as *const _ as *const u8, length) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Rxsdt for Rsdt {
|
||||
fn iter(&self) -> Box<dyn Iterator<Item = usize>> {
|
||||
Box::new(RsdtIter {
|
||||
sdt: self.0,
|
||||
i: 0
|
||||
})
|
||||
Box::new(RsdtIter { sdt: self.0, i: 0 })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RsdtIter {
|
||||
sdt: &'static Sdt,
|
||||
i: usize
|
||||
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>() {
|
||||
if self.i < self.sdt.data_len() / mem::size_of::<u32>() {
|
||||
let item = unsafe { *(self.sdt.data_address() as *const u32).add(self.i) };
|
||||
self.i += 1;
|
||||
Some(item as usize)
|
||||
|
||||
+7
-3
@@ -2,8 +2,7 @@ use alloc::boxed::Box;
|
||||
|
||||
use crate::paging::KernelMapper;
|
||||
|
||||
use super::sdt::Sdt;
|
||||
use super::get_sdt;
|
||||
use super::{get_sdt, sdt::Sdt};
|
||||
|
||||
pub trait Rxsdt {
|
||||
fn iter(&self) -> Box<dyn Iterator<Item = usize>>;
|
||||
@@ -15,7 +14,12 @@ pub trait Rxsdt {
|
||||
}
|
||||
}
|
||||
|
||||
fn find(&self, signature: [u8; 4], oem_id: [u8; 6], oem_table_id: [u8; 8]) -> Option<&'static Sdt> {
|
||||
fn find(
|
||||
&self,
|
||||
signature: [u8; 4],
|
||||
oem_id: [u8; 6],
|
||||
oem_table_id: [u8; 8],
|
||||
) -> Option<&'static Sdt> {
|
||||
for sdt in self.iter() {
|
||||
let sdt = unsafe { &*(sdt as *const Sdt) };
|
||||
|
||||
|
||||
+16
-12
@@ -1,18 +1,17 @@
|
||||
use core::mem;
|
||||
use core::slice;
|
||||
use core::{mem, slice};
|
||||
|
||||
#[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
|
||||
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 {
|
||||
@@ -36,7 +35,12 @@ impl Sdt {
|
||||
unsafe { slice::from_raw_parts(self.data_address() as *const u8, self.data_len()) }
|
||||
}
|
||||
|
||||
pub fn match_pattern(&self, signature: [u8; 4], oem_id: [u8; 6], oem_table_id: [u8; 8]) -> bool{
|
||||
pub fn match_pattern(
|
||||
&self,
|
||||
signature: [u8; 4],
|
||||
oem_id: [u8; 6],
|
||||
oem_table_id: [u8; 8],
|
||||
) -> bool {
|
||||
self.signature == signature && self.oem_id == oem_id && self.oem_table_id == oem_table_id
|
||||
}
|
||||
}
|
||||
|
||||
+8
-15
@@ -1,9 +1,7 @@
|
||||
use core::convert::TryFrom;
|
||||
use core::mem;
|
||||
use alloc::boxed::Box;
|
||||
use core::{convert::TryFrom, mem};
|
||||
|
||||
use super::sdt::Sdt;
|
||||
use super::rxsdt::Rxsdt;
|
||||
use super::{rxsdt::Rxsdt, sdt::Sdt};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Xsdt(&'static Sdt);
|
||||
@@ -17,33 +15,28 @@ impl Xsdt {
|
||||
}
|
||||
}
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
let length = usize::try_from(self.0.length)
|
||||
.expect("expected 32-bit length to fit within usize");
|
||||
let length =
|
||||
usize::try_from(self.0.length).expect("expected 32-bit length to fit within usize");
|
||||
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(self.0 as *const _ as *const u8, length)
|
||||
}
|
||||
unsafe { core::slice::from_raw_parts(self.0 as *const _ as *const u8, length) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Rxsdt for Xsdt {
|
||||
fn iter(&self) -> Box<dyn Iterator<Item = usize>> {
|
||||
Box::new(XsdtIter {
|
||||
sdt: self.0,
|
||||
i: 0
|
||||
})
|
||||
Box::new(XsdtIter { sdt: self.0, i: 0 })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XsdtIter {
|
||||
sdt: &'static Sdt,
|
||||
i: usize
|
||||
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>() {
|
||||
if self.i < self.sdt.data_len() / mem::size_of::<u64>() {
|
||||
let item = unsafe { *(self.sdt.data_address() as *const u64).add(self.i) };
|
||||
self.i += 1;
|
||||
Some(item as usize)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::ptr::{self, NonNull};
|
||||
use core::{
|
||||
alloc::{GlobalAlloc, Layout},
|
||||
ptr::{self, NonNull},
|
||||
};
|
||||
use linked_list_allocator::Heap;
|
||||
use spin::Mutex;
|
||||
|
||||
@@ -21,10 +23,18 @@ unsafe impl GlobalAlloc for Allocator {
|
||||
match heap.allocate_first_fit(layout) {
|
||||
Err(()) => {
|
||||
let size = heap.size();
|
||||
super::map_heap(&mut KernelMapper::lock(), crate::KERNEL_HEAP_OFFSET + size, crate::KERNEL_HEAP_SIZE);
|
||||
super::map_heap(
|
||||
&mut KernelMapper::lock(),
|
||||
crate::KERNEL_HEAP_OFFSET + size,
|
||||
crate::KERNEL_HEAP_SIZE,
|
||||
);
|
||||
heap.extend(crate::KERNEL_HEAP_SIZE);
|
||||
},
|
||||
other => return other.ok().map_or(ptr::null_mut(), |allocation| allocation.as_ptr()),
|
||||
}
|
||||
other => {
|
||||
return other
|
||||
.ok()
|
||||
.map_or(ptr::null_mut(), |allocation| allocation.as_ptr())
|
||||
}
|
||||
}
|
||||
}
|
||||
panic!("__rust_allocate: heap not initialized");
|
||||
|
||||
+16
-8
@@ -1,26 +1,34 @@
|
||||
use crate::paging::{mapper::PageFlushAll, KernelMapper, Page, PageFlags, VirtualAddress};
|
||||
use rmm::Flusher;
|
||||
use crate::paging::{KernelMapper, Page, PageFlags, VirtualAddress, mapper::PageFlushAll};
|
||||
|
||||
#[cfg(not(feature="slab"))]
|
||||
#[cfg(not(feature = "slab"))]
|
||||
pub use self::linked_list::Allocator;
|
||||
|
||||
#[cfg(feature="slab")]
|
||||
#[cfg(feature = "slab")]
|
||||
pub use self::slab::Allocator;
|
||||
|
||||
#[cfg(not(feature="slab"))]
|
||||
#[cfg(not(feature = "slab"))]
|
||||
mod linked_list;
|
||||
|
||||
#[cfg(feature="slab")]
|
||||
#[cfg(feature = "slab")]
|
||||
mod slab;
|
||||
|
||||
unsafe fn map_heap(mapper: &mut KernelMapper, offset: usize, size: usize) {
|
||||
let mapper = mapper.get_mut().expect("failed to obtain exclusive access to KernelMapper while extending heap");
|
||||
let mapper = mapper
|
||||
.get_mut()
|
||||
.expect("failed to obtain exclusive access to KernelMapper while extending heap");
|
||||
let mut flush_all = PageFlushAll::new();
|
||||
|
||||
let heap_start_page = Page::containing_address(VirtualAddress::new(offset));
|
||||
let heap_end_page = Page::containing_address(VirtualAddress::new(offset + size-1));
|
||||
let heap_end_page = Page::containing_address(VirtualAddress::new(offset + size - 1));
|
||||
for page in Page::range_inclusive(heap_start_page, heap_end_page) {
|
||||
let result = mapper.map(page.start_address(), PageFlags::new().write(true).global(cfg!(not(feature = "pti"))))
|
||||
let result = mapper
|
||||
.map(
|
||||
page.start_address(),
|
||||
PageFlags::new()
|
||||
.write(true)
|
||||
.global(cfg!(not(feature = "pti"))),
|
||||
)
|
||||
.expect("failed to map kernel heap");
|
||||
flush_all.consume(result);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use core::alloc::{Alloc, AllocErr, Layout};
|
||||
use spin::Mutex;
|
||||
use slab_allocator::Heap;
|
||||
use spin::Mutex;
|
||||
|
||||
static HEAP: Mutex<Option<Heap>> = Mutex::new(None);
|
||||
|
||||
|
||||
@@ -8,15 +8,15 @@ pub const PML4_MASK: usize = 0x0000_ff80_0000_0000;
|
||||
|
||||
/// Offset of recursive paging (deprecated, but still reserved)
|
||||
pub const RECURSIVE_PAGE_OFFSET: usize = (-(PML4_SIZE as isize)) as usize;
|
||||
pub const RECURSIVE_PAGE_PML4: usize = (RECURSIVE_PAGE_OFFSET & PML4_MASK)/PML4_SIZE;
|
||||
pub const RECURSIVE_PAGE_PML4: usize = (RECURSIVE_PAGE_OFFSET & PML4_MASK) / PML4_SIZE;
|
||||
|
||||
/// Offset of kernel
|
||||
pub const KERNEL_OFFSET: usize = RECURSIVE_PAGE_OFFSET - PML4_SIZE;
|
||||
pub const KERNEL_PML4: usize = (KERNEL_OFFSET & PML4_MASK)/PML4_SIZE;
|
||||
pub const KERNEL_PML4: usize = (KERNEL_OFFSET & PML4_MASK) / PML4_SIZE;
|
||||
|
||||
/// Offset to kernel heap
|
||||
pub const KERNEL_HEAP_OFFSET: usize = KERNEL_OFFSET - PML4_SIZE;
|
||||
pub const KERNEL_HEAP_PML4: usize = (KERNEL_HEAP_OFFSET & PML4_MASK)/PML4_SIZE;
|
||||
pub const KERNEL_HEAP_PML4: usize = (KERNEL_HEAP_OFFSET & PML4_MASK) / PML4_SIZE;
|
||||
/// Size of kernel heap
|
||||
pub const KERNEL_HEAP_SIZE: usize = 1 * 1024 * 1024; // 1 MB
|
||||
|
||||
@@ -25,7 +25,7 @@ pub const KERNEL_TMP_MISC_OFFSET: usize = KERNEL_HEAP_OFFSET - PML4_SIZE;
|
||||
|
||||
/// Offset to kernel percpu variables
|
||||
pub const KERNEL_PERCPU_OFFSET: usize = KERNEL_TMP_MISC_OFFSET - PML4_SIZE;
|
||||
pub const KERNEL_PERCPU_PML4: usize = (KERNEL_PERCPU_OFFSET & PML4_MASK)/PML4_SIZE;
|
||||
pub const KERNEL_PERCPU_PML4: usize = (KERNEL_PERCPU_OFFSET & PML4_MASK) / PML4_SIZE;
|
||||
/// Size of kernel percpu variables
|
||||
pub const KERNEL_PERCPU_SHIFT: u8 = 16; // 2^16 = 64 KiB
|
||||
pub const KERNEL_PERCPU_SIZE: usize = 1_usize << KERNEL_PERCPU_SHIFT;
|
||||
@@ -33,7 +33,7 @@ pub const KERNEL_PERCPU_SIZE: usize = 1_usize << KERNEL_PERCPU_SHIFT;
|
||||
/// Offset of physmap
|
||||
// This needs to match RMM's PHYS_OFFSET
|
||||
pub const PHYS_OFFSET: usize = 0xFFFF_8000_0000_0000;
|
||||
pub const PHYS_PML4: usize = (PHYS_OFFSET & PML4_MASK)/PML4_SIZE;
|
||||
pub const PHYS_PML4: usize = (PHYS_OFFSET & PML4_MASK) / PML4_SIZE;
|
||||
|
||||
/// End offset of the user image, i.e. kernel start
|
||||
pub const USER_END_OFFSET: usize = 256 * PML4_SIZE;
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
use core::fmt;
|
||||
use spin::MutexGuard;
|
||||
|
||||
use crate::log::{LOG, Log};
|
||||
use crate::log::{Log, LOG};
|
||||
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
use crate::devices::graphical_debug::{DEBUG_DISPLAY, DebugDisplay};
|
||||
#[cfg(feature = "serial_debug")]
|
||||
use super::device::{
|
||||
serial::COM1,
|
||||
uart_pl011::SerialPort,
|
||||
};
|
||||
use super::device::{serial::COM1, uart_pl011::SerialPort};
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
use crate::devices::graphical_debug::{DebugDisplay, DEBUG_DISPLAY};
|
||||
|
||||
pub struct Writer<'a> {
|
||||
log: MutexGuard<'a, Option<Log>>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use core::fmt::{Result, Write};
|
||||
|
||||
use crate::device::cpu::registers::{control_regs};
|
||||
use crate::device::cpu::registers::control_regs;
|
||||
|
||||
pub mod registers;
|
||||
|
||||
@@ -29,28 +29,15 @@ enum ImplementerID {
|
||||
}
|
||||
|
||||
const IMPLEMENTERS: [&'static str; 12] = [
|
||||
"Unknown",
|
||||
"Arm",
|
||||
"Broadcom",
|
||||
"Cavium",
|
||||
"Digital",
|
||||
"Infineon",
|
||||
"Motorola",
|
||||
"Nvidia",
|
||||
"AMCC",
|
||||
"Qualcomm",
|
||||
"Marvell",
|
||||
"Intel",
|
||||
"Unknown", "Arm", "Broadcom", "Cavium", "Digital", "Infineon", "Motorola", "Nvidia", "AMCC",
|
||||
"Qualcomm", "Marvell", "Intel",
|
||||
];
|
||||
|
||||
|
||||
enum VariantID {
|
||||
Unknown,
|
||||
}
|
||||
|
||||
const VARIANTS: [&'static str; 1] = [
|
||||
"Unknown",
|
||||
];
|
||||
const VARIANTS: [&'static str; 1] = ["Unknown"];
|
||||
|
||||
enum ArchitectureID {
|
||||
Unknown,
|
||||
@@ -63,16 +50,8 @@ enum ArchitectureID {
|
||||
V6,
|
||||
}
|
||||
|
||||
const ARCHITECTURES: [&'static str; 8] = [
|
||||
"Unknown",
|
||||
"v4",
|
||||
"v4T",
|
||||
"v5",
|
||||
"v5T",
|
||||
"v5TE",
|
||||
"v5TEJ",
|
||||
"v6",
|
||||
];
|
||||
const ARCHITECTURES: [&'static str; 8] =
|
||||
["Unknown", "v4", "v4T", "v5", "v5T", "v5TE", "v5TEJ", "v6"];
|
||||
|
||||
enum PartNumberID {
|
||||
Unknown,
|
||||
@@ -106,11 +85,7 @@ enum RevisionID {
|
||||
Thunder1_1,
|
||||
}
|
||||
|
||||
const REVISIONS: [&'static str; 3] = [
|
||||
"Unknown",
|
||||
"Thunder-1.0",
|
||||
"Thunder-1.1",
|
||||
];
|
||||
const REVISIONS: [&'static str; 3] = ["Unknown", "Thunder-1.0", "Thunder-1.1"];
|
||||
|
||||
struct CpuInfo {
|
||||
implementer: &'static str,
|
||||
@@ -177,7 +152,7 @@ impl CpuInfo {
|
||||
_ => REVISIONS[RevisionID::Unknown as usize],
|
||||
};
|
||||
val
|
||||
},
|
||||
}
|
||||
_ => REVISIONS[RevisionID::Unknown as usize],
|
||||
};
|
||||
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
use crate::log::{debug, info};
|
||||
use alloc::boxed::Box;
|
||||
use crate::log::{info, debug};
|
||||
|
||||
use crate::{
|
||||
arch::device::irqchip::IRQ_CHIP, context, context::timeout,
|
||||
device::cpu::registers::control_regs, dtb::DTB_BINARY, init::device_tree::find_compatible_node,
|
||||
interrupt::irq::trigger, time,
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use crate::arch::device::irqchip::IRQ_CHIP;
|
||||
use crate::context::timeout;
|
||||
use crate::device::cpu::registers::control_regs;
|
||||
use crate::init::device_tree::find_compatible_node;
|
||||
use crate::interrupt::irq::trigger;
|
||||
use crate::time;
|
||||
use crate::context;
|
||||
use crate::dtb::DTB_BINARY;
|
||||
|
||||
use super::irqchip::InterruptHandler;
|
||||
use super::irqchip::register_irq;
|
||||
use super::irqchip::{register_irq, InterruptHandler};
|
||||
|
||||
bitflags! {
|
||||
struct TimerCtrlFlags: u32 {
|
||||
@@ -24,19 +20,28 @@ bitflags! {
|
||||
}
|
||||
|
||||
pub unsafe fn init() {
|
||||
let mut timer = GenericTimer{ clk_freq: 0, reload_count: 0};
|
||||
let mut timer = GenericTimer {
|
||||
clk_freq: 0,
|
||||
reload_count: 0,
|
||||
};
|
||||
timer.init();
|
||||
let data = DTB_BINARY.get().unwrap();
|
||||
let fdt = fdt::DeviceTree::new(data).unwrap();
|
||||
if let Some(node) = find_compatible_node(&fdt, "arm,armv7-timer") {
|
||||
let interrupts = node.properties().find(|p| p.name.contains("interrupts")).unwrap();
|
||||
let interrupts = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("interrupts"))
|
||||
.unwrap();
|
||||
let mut intr_data = Vec::new();
|
||||
for chunk in interrupts.data.chunks(4) {
|
||||
let val = BE::read_u32(chunk);
|
||||
intr_data.push(val);
|
||||
}
|
||||
let mut ic_idx = IRQ_CHIP.irq_chip_list.root_idx;
|
||||
if let Some(interrupt_parent) = node.properties().find(|p| p.name.contains("interrupt-parent")) {
|
||||
if let Some(interrupt_parent) = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("interrupt-parent"))
|
||||
{
|
||||
let phandle = BE::read_u32(interrupt_parent.data);
|
||||
let mut i = 0;
|
||||
while i < IRQ_CHIP.irq_chip_list.chips.len() {
|
||||
@@ -49,7 +54,10 @@ pub unsafe fn init() {
|
||||
}
|
||||
}
|
||||
//PHYS_NONSECURE_PPI only
|
||||
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_xlate(&intr_data, 1).unwrap();
|
||||
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx]
|
||||
.ic
|
||||
.irq_xlate(&intr_data, 1)
|
||||
.unwrap();
|
||||
info!("generic_timer virq = {}", virq);
|
||||
register_irq(virq as u32, Box::new(timer));
|
||||
IRQ_CHIP.irq_enable(virq as u32);
|
||||
@@ -109,7 +117,6 @@ impl GenericTimer {
|
||||
|
||||
impl InterruptHandler for GenericTimer {
|
||||
fn irq_handler(&mut self, irq: u32) {
|
||||
|
||||
self.clear_irq();
|
||||
{
|
||||
*time::OFFSET.lock() += self.clk_freq as u128;
|
||||
@@ -119,7 +126,9 @@ impl InterruptHandler for GenericTimer {
|
||||
|
||||
context::switch::tick();
|
||||
|
||||
unsafe { trigger(irq); }
|
||||
unsafe {
|
||||
trigger(irq);
|
||||
}
|
||||
self.reload_count();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
|
||||
use fdt::{DeviceTree, Node};
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use fdt::{DeviceTree, Node};
|
||||
|
||||
use crate::init::device_tree::find_compatible_node;
|
||||
use crate::log::{info, debug};
|
||||
use syscall::{Result, error::{Error, EINVAL}};
|
||||
use crate::{
|
||||
init::device_tree::find_compatible_node,
|
||||
log::{debug, info},
|
||||
};
|
||||
use syscall::{
|
||||
error::{Error, EINVAL},
|
||||
Result,
|
||||
};
|
||||
|
||||
use super::{InterruptController, IrqDesc};
|
||||
|
||||
@@ -35,11 +40,13 @@ impl GenericInterruptController {
|
||||
ncpus: 0,
|
||||
nirqs: 0,
|
||||
};
|
||||
let gic_cpu_if = GicCpuIf {
|
||||
address: 0,
|
||||
};
|
||||
let gic_cpu_if = GicCpuIf { address: 0 };
|
||||
|
||||
GenericInterruptController { gic_dist_if, gic_cpu_if, irq_range: (0, 0) }
|
||||
GenericInterruptController {
|
||||
gic_dist_if,
|
||||
gic_cpu_if,
|
||||
irq_range: (0, 0),
|
||||
}
|
||||
}
|
||||
pub fn parse(fdt: &DeviceTree) -> Result<(usize, usize, usize, usize)> {
|
||||
if let Some(node) = find_compatible_node(fdt, "arm,cortex-a15-gic") {
|
||||
@@ -76,11 +83,18 @@ impl GenericInterruptController {
|
||||
}
|
||||
|
||||
impl InterruptController for GenericInterruptController {
|
||||
fn irq_init(&mut self, fdt: &DeviceTree, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize) -> Result<Option<usize>> {
|
||||
let (dist_addr, dist_size, cpu_addr, cpu_size) = match GenericInterruptController::parse(fdt) {
|
||||
Ok(regs) => regs,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
fn irq_init(
|
||||
&mut self,
|
||||
fdt: &DeviceTree,
|
||||
irq_desc: &mut [IrqDesc; 1024],
|
||||
ic_idx: usize,
|
||||
irq_idx: &mut usize,
|
||||
) -> Result<Option<usize>> {
|
||||
let (dist_addr, dist_size, cpu_addr, cpu_size) =
|
||||
match GenericInterruptController::parse(fdt) {
|
||||
Ok(regs) => regs,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
self.gic_cpu_if.init(crate::PHYS_OFFSET + cpu_addr);
|
||||
@@ -92,7 +106,11 @@ impl InterruptController for GenericInterruptController {
|
||||
self.gic_cpu_if.write(GICC_PMR, 0xff);
|
||||
}
|
||||
let idx = *irq_idx;
|
||||
let cnt = if self.gic_dist_if.nirqs > 1024 { 1024 } else { self.gic_dist_if.nirqs as usize };
|
||||
let cnt = if self.gic_dist_if.nirqs > 1024 {
|
||||
1024
|
||||
} else {
|
||||
self.gic_dist_if.nirqs as usize
|
||||
};
|
||||
let mut i: usize = 0;
|
||||
//only support linear irq map now.
|
||||
while i < cnt && (idx + i < 1024) {
|
||||
@@ -145,9 +163,7 @@ impl InterruptController for GenericInterruptController {
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_handler(&mut self, _irq: u32) {
|
||||
|
||||
}
|
||||
fn irq_handler(&mut self, _irq: u32) {}
|
||||
}
|
||||
|
||||
pub struct GicDistIf {
|
||||
@@ -166,7 +182,10 @@ impl GicDistIf {
|
||||
let typer = self.read(GICD_TYPER);
|
||||
self.ncpus = ((typer & (0x7 << 5)) >> 5) + 1;
|
||||
self.nirqs = ((typer & 0x1f) + 1) * 32;
|
||||
info!("gic: Distributor supports {:?} CPUs and {:?} IRQs", self.ncpus, self.nirqs);
|
||||
info!(
|
||||
"gic: Distributor supports {:?} CPUs and {:?} IRQs",
|
||||
self.ncpus, self.nirqs
|
||||
);
|
||||
|
||||
// Set all SPIs to level triggered
|
||||
for irq in (32..self.nirqs).step_by(16) {
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::arch::device::irqchip::IRQ_CHIP;
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use fdt::{DeviceTree, Node};
|
||||
use crate::arch::device::irqchip::IRQ_CHIP;
|
||||
|
||||
use crate::init::device_tree::find_compatible_node;
|
||||
use crate::log::{info, debug, error};
|
||||
use syscall::{Result, error::{Error, EINVAL}};
|
||||
use crate::{
|
||||
init::device_tree::find_compatible_node,
|
||||
log::{debug, error, info},
|
||||
};
|
||||
use syscall::{
|
||||
error::{Error, EINVAL},
|
||||
Result,
|
||||
};
|
||||
|
||||
use super::{InterruptController, IrqDesc, InterruptHandler};
|
||||
use super::{InterruptController, InterruptHandler, IrqDesc};
|
||||
|
||||
#[inline(always)]
|
||||
fn ffs(num: u32) -> u32 {
|
||||
@@ -39,7 +43,7 @@ fn ffs(num: u32) -> u32 {
|
||||
x >>= 1;
|
||||
r += 1;
|
||||
}
|
||||
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
@@ -59,10 +63,12 @@ pub struct Bcm2835ArmInterruptController {
|
||||
pub irq_range: (usize, usize),
|
||||
}
|
||||
|
||||
|
||||
impl Bcm2835ArmInterruptController {
|
||||
pub fn new() -> Self {
|
||||
Bcm2835ArmInterruptController { address: 0, irq_range: (0, 0) }
|
||||
Bcm2835ArmInterruptController {
|
||||
address: 0,
|
||||
irq_range: (0, 0),
|
||||
}
|
||||
}
|
||||
pub fn parse(fdt: &DeviceTree) -> Result<(usize, usize, Option<usize>)> {
|
||||
//TODO: try to parse dtb using stable library
|
||||
@@ -79,10 +85,16 @@ impl Bcm2835ArmInterruptController {
|
||||
let base = BE::read_u32(base);
|
||||
let size = BE::read_u32(size);
|
||||
let mut ret_virq = None;
|
||||
|
||||
if let Some(interrupt_parent) = node.properties().find(|p| p.name.contains("interrupt-parent")) {
|
||||
|
||||
if let Some(interrupt_parent) = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("interrupt-parent"))
|
||||
{
|
||||
let phandle = BE::read_u32(interrupt_parent.data);
|
||||
let interrupts = node.properties().find(|p| p.name.contains("interrupts")).unwrap();
|
||||
let interrupts = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("interrupts"))
|
||||
.unwrap();
|
||||
let mut intr_data = Vec::new();
|
||||
for chunk in interrupts.data.chunks(4) {
|
||||
let val = BE::read_u32(chunk);
|
||||
@@ -99,7 +111,10 @@ impl Bcm2835ArmInterruptController {
|
||||
i += 1;
|
||||
}
|
||||
//PHYS_NONSECURE_PPI only
|
||||
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_xlate(&intr_data, 0).unwrap();
|
||||
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx]
|
||||
.ic
|
||||
.irq_xlate(&intr_data, 0)
|
||||
.unwrap();
|
||||
info!("bcm2835arm_ctrl virq = {}", virq);
|
||||
ret_virq = Some(virq);
|
||||
}
|
||||
@@ -127,7 +142,13 @@ impl Bcm2835ArmInterruptController {
|
||||
}
|
||||
|
||||
impl InterruptController for Bcm2835ArmInterruptController {
|
||||
fn irq_init(&mut self, fdt: &DeviceTree, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize) -> Result<Option<usize>> {
|
||||
fn irq_init(
|
||||
&mut self,
|
||||
fdt: &DeviceTree,
|
||||
irq_desc: &mut [IrqDesc; 1024],
|
||||
ic_idx: usize,
|
||||
irq_idx: &mut usize,
|
||||
) -> Result<Option<usize>> {
|
||||
let (base, size, virq) = match Bcm2835ArmInterruptController::parse(fdt) {
|
||||
Ok((a, b, c)) => (a, b, c),
|
||||
Err(_) => return Err(Error::new(EINVAL)),
|
||||
@@ -161,8 +182,17 @@ impl InterruptController for Bcm2835ArmInterruptController {
|
||||
let sources = unsafe { self.read(PENDING_0) };
|
||||
let pending_num = ffs(sources) - 1;
|
||||
let fast_irq = [
|
||||
7 + 32, 9 + 32, 10 + 32, 18 + 32, 19 + 32,
|
||||
21 + 64, 22 + 64, 23 + 64, 24 + 64, 25 + 64, 30 + 64
|
||||
7 + 32,
|
||||
9 + 32,
|
||||
10 + 32,
|
||||
18 + 32,
|
||||
19 + 32,
|
||||
21 + 64,
|
||||
22 + 64,
|
||||
23 + 64,
|
||||
24 + 64,
|
||||
25 + 64,
|
||||
30 + 64,
|
||||
];
|
||||
|
||||
//fast irq
|
||||
@@ -172,66 +202,76 @@ impl InterruptController for Bcm2835ArmInterruptController {
|
||||
|
||||
let pending_num = ffs(sources & 0x3ff) - 1;
|
||||
match pending_num {
|
||||
num@0..=7 => {
|
||||
return num
|
||||
},
|
||||
num @ 0..=7 => return num,
|
||||
8 => {
|
||||
let sources1 = unsafe { self.read(PENDING_1) };
|
||||
let irq_0_31 = ffs(sources1) - 1;
|
||||
return irq_0_31 + 32;
|
||||
},
|
||||
}
|
||||
9 => {
|
||||
let sources2 = unsafe { self.read(PENDING_2) };
|
||||
let irq_32_63 = ffs(sources2) - 1;
|
||||
return irq_32_63 + 64;
|
||||
},
|
||||
}
|
||||
num => {
|
||||
error!("unexpected irq pending in BASIC PENDING: 0x{}, sources = 0x{:08x}", num, sources);
|
||||
error!(
|
||||
"unexpected irq pending in BASIC PENDING: 0x{}, sources = 0x{:08x}",
|
||||
num, sources
|
||||
);
|
||||
return num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_eoi(&mut self, _irq_num: u32) {
|
||||
|
||||
}
|
||||
fn irq_eoi(&mut self, _irq_num: u32) {}
|
||||
|
||||
fn irq_enable(&mut self, irq_num: u32) {
|
||||
debug!("bcm2835 enable {} {}", irq_num, irq_num & 0x1f);
|
||||
match irq_num {
|
||||
num @0..=31 => {
|
||||
num @ 0..=31 => {
|
||||
let val = 1 << num;
|
||||
unsafe { self.write(ENABLE_0, val); }
|
||||
},
|
||||
num @32..=63 => {
|
||||
unsafe {
|
||||
self.write(ENABLE_0, val);
|
||||
}
|
||||
}
|
||||
num @ 32..=63 => {
|
||||
let val = 1 << (num & 0x1f);
|
||||
unsafe { self.write(ENABLE_1, val); }
|
||||
},
|
||||
num @64..=95 => {
|
||||
unsafe {
|
||||
self.write(ENABLE_1, val);
|
||||
}
|
||||
}
|
||||
num @ 64..=95 => {
|
||||
let val = 1 << (num & 0x1f);
|
||||
unsafe { self.write(ENABLE_2, val); }
|
||||
},
|
||||
unsafe {
|
||||
self.write(ENABLE_2, val);
|
||||
}
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_disable(&mut self, irq_num: u32) {
|
||||
match irq_num {
|
||||
num @0..=31 => {
|
||||
num @ 0..=31 => {
|
||||
let val = 1 << num;
|
||||
unsafe { self.write(DISABLE_0, val); }
|
||||
},
|
||||
num @32..=63 => {
|
||||
unsafe {
|
||||
self.write(DISABLE_0, val);
|
||||
}
|
||||
}
|
||||
num @ 32..=63 => {
|
||||
let val = 1 << (num & 0x1f);
|
||||
unsafe { self.write(DISABLE_1, val); }
|
||||
},
|
||||
num @64..=95 => {
|
||||
unsafe {
|
||||
self.write(DISABLE_1, val);
|
||||
}
|
||||
}
|
||||
num @ 64..=95 => {
|
||||
let val = 1 << (num & 0x1f);
|
||||
unsafe { self.write(DISABLE_2, val); }
|
||||
},
|
||||
unsafe {
|
||||
self.write(DISABLE_2, val);
|
||||
}
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
|
||||
}
|
||||
fn irq_xlate(&mut self, irq_data: &[u32], idx: usize) -> Result<usize> {
|
||||
//assert interrupt-cells == 0x2
|
||||
@@ -260,7 +300,6 @@ impl InterruptController for Bcm2835ArmInterruptController {
|
||||
}
|
||||
|
||||
fn irq_handler(&mut self, _irq: u32) {
|
||||
|
||||
unsafe {
|
||||
let irq = self.irq_ack();
|
||||
if let Some(virq) = self.irq_to_virq(irq) && virq < 1024 {
|
||||
@@ -277,7 +316,6 @@ impl InterruptController for Bcm2835ArmInterruptController {
|
||||
|
||||
impl InterruptHandler for Bcm2835ArmInterruptController {
|
||||
fn irq_handler(&mut self, _irq: u32) {
|
||||
|
||||
unsafe {
|
||||
let irq = self.irq_ack();
|
||||
if let Some(virq) = self.irq_to_virq(irq) && virq < 1024 {
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
use core::{ptr::{read_volatile, write_volatile}, arch::asm};
|
||||
use core::{
|
||||
arch::asm,
|
||||
ptr::{read_volatile, write_volatile},
|
||||
};
|
||||
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use fdt::{DeviceTree, Node};
|
||||
|
||||
use crate::init::device_tree::find_compatible_node;
|
||||
use crate::log::{info, debug};
|
||||
use syscall::{Result, error::{Error, EINVAL}};
|
||||
use crate::{
|
||||
init::device_tree::find_compatible_node,
|
||||
log::{debug, info},
|
||||
};
|
||||
use syscall::{
|
||||
error::{Error, EINVAL},
|
||||
Result,
|
||||
};
|
||||
|
||||
use super::{InterruptController, IrqDesc};
|
||||
|
||||
@@ -55,7 +63,7 @@ fn ffs(num: u32) -> u32 {
|
||||
x >>= 1;
|
||||
r += 1;
|
||||
}
|
||||
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
@@ -65,10 +73,13 @@ pub struct Bcm2836ArmInterruptController {
|
||||
pub active_cpu: u32,
|
||||
}
|
||||
|
||||
|
||||
impl Bcm2836ArmInterruptController {
|
||||
pub fn new() -> Self {
|
||||
Bcm2836ArmInterruptController { address: 0, irq_range: (0, 0), active_cpu: 0 }
|
||||
Bcm2836ArmInterruptController {
|
||||
address: 0,
|
||||
irq_range: (0, 0),
|
||||
active_cpu: 0,
|
||||
}
|
||||
}
|
||||
pub fn parse(fdt: &DeviceTree) -> Result<(usize, usize)> {
|
||||
//TODO: try to parse dtb using stable library
|
||||
@@ -84,7 +95,7 @@ impl Bcm2836ArmInterruptController {
|
||||
let (base, size) = reg.data.split_at(4);
|
||||
let base = BE::read_u32(base);
|
||||
let size = BE::read_u32(size);
|
||||
|
||||
|
||||
Ok((base as usize, size as usize))
|
||||
}
|
||||
|
||||
@@ -111,7 +122,13 @@ impl Bcm2836ArmInterruptController {
|
||||
}
|
||||
|
||||
impl InterruptController for Bcm2836ArmInterruptController {
|
||||
fn irq_init(&mut self, fdt: &DeviceTree, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize) -> Result<Option<usize>> {
|
||||
fn irq_init(
|
||||
&mut self,
|
||||
fdt: &DeviceTree,
|
||||
irq_desc: &mut [IrqDesc; 1024],
|
||||
ic_idx: usize,
|
||||
irq_idx: &mut usize,
|
||||
) -> Result<Option<usize>> {
|
||||
let (base, size) = match Bcm2836ArmInterruptController::parse(fdt) {
|
||||
Ok((a, b)) => (a, b),
|
||||
Err(_) => return Err(Error::new(EINVAL)),
|
||||
@@ -145,15 +162,15 @@ impl InterruptController for Bcm2836ArmInterruptController {
|
||||
|
||||
fn irq_ack(&mut self) -> u32 {
|
||||
let mut cpuid: usize = 0;
|
||||
unsafe { asm!("mrs {}, mpidr_el1", out(reg) cpuid); }
|
||||
unsafe {
|
||||
asm!("mrs {}, mpidr_el1", out(reg) cpuid);
|
||||
}
|
||||
let cpu = cpuid as u32 & 0x3;
|
||||
let sources: u32 = unsafe { self.read(LOCAL_IRQ_PENDING + 4 * cpu) };
|
||||
ffs(sources) - 1
|
||||
}
|
||||
|
||||
fn irq_eoi(&mut self, _irq_num: u32) {
|
||||
|
||||
}
|
||||
fn irq_eoi(&mut self, _irq_num: u32) {}
|
||||
|
||||
fn irq_enable(&mut self, irq_num: u32) {
|
||||
match irq_num {
|
||||
@@ -167,7 +184,7 @@ impl InterruptController for Bcm2836ArmInterruptController {
|
||||
},
|
||||
LOCAL_IRQ_GPU_FAST => {
|
||||
//GPU IRQ always enable
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
//ignore
|
||||
}
|
||||
@@ -178,7 +195,9 @@ impl InterruptController for Bcm2836ArmInterruptController {
|
||||
match irq_num {
|
||||
LOCAL_IRQ_CNTPNSIRQ => unsafe {
|
||||
let mut cpuid: usize = 0;
|
||||
unsafe { asm!("mrs {}, mpidr_el1", out(reg) cpuid); }
|
||||
unsafe {
|
||||
asm!("mrs {}, mpidr_el1", out(reg) cpuid);
|
||||
}
|
||||
let mut cpu = cpuid as u32 & 0x3;
|
||||
let mut reg_val = self.read(LOCAL_TIMER_INT_CONTROL0 + 4 * cpu);
|
||||
reg_val &= !0x2;
|
||||
@@ -186,7 +205,7 @@ impl InterruptController for Bcm2836ArmInterruptController {
|
||||
},
|
||||
LOCAL_IRQ_GPU_FAST => {
|
||||
//GPU IRQ always enable
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
//ignore
|
||||
}
|
||||
@@ -213,7 +232,5 @@ impl InterruptController for Bcm2836ArmInterruptController {
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_handler(&mut self, irq: u32) {
|
||||
|
||||
}
|
||||
fn irq_handler(&mut self, irq: u32) {}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
use alloc::{boxed::Box, vec::Vec, string::{String, ToString}};
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use syscall::Result;
|
||||
use fdt::DeviceTree;
|
||||
use syscall::Result;
|
||||
|
||||
use crate::log::{debug, error};
|
||||
use crate::init::device_tree::travel_interrupt_ctrl;
|
||||
use crate::{
|
||||
init::device_tree::travel_interrupt_ctrl,
|
||||
log::{debug, error},
|
||||
};
|
||||
|
||||
mod gic;
|
||||
mod irq_bcm2835;
|
||||
@@ -18,7 +24,13 @@ pub const IRQ_TYPE_LEVEL_HIGH: u32 = 4;
|
||||
pub const IRQ_TYPE_LEVEL_LOW: u32 = 8;
|
||||
|
||||
pub trait InterruptController {
|
||||
fn irq_init(&mut self, fdt: &DeviceTree, irq_desc: &mut [IrqDesc; 1024], ic_idx: usize, irq_idx: &mut usize) -> Result<Option<usize>>;
|
||||
fn irq_init(
|
||||
&mut self,
|
||||
fdt: &DeviceTree,
|
||||
irq_desc: &mut [IrqDesc; 1024],
|
||||
ic_idx: usize,
|
||||
irq_idx: &mut usize,
|
||||
) -> Result<Option<usize>>;
|
||||
fn irq_ack(&mut self) -> u32;
|
||||
fn irq_eoi(&mut self, irq_num: u32);
|
||||
fn irq_enable(&mut self, irq_num: u32);
|
||||
@@ -38,7 +50,7 @@ pub struct IrqChipItem {
|
||||
pub parent_phandle: Option<u32>,
|
||||
pub intr_cell_size: u32,
|
||||
pub parent: Option<usize>, //parent idx in chiplist
|
||||
pub childs: Vec<usize>, //child idx in chiplist
|
||||
pub childs: Vec<usize>, //child idx in chiplist
|
||||
pub interrupts: Vec<u32>,
|
||||
pub ic: Box<dyn InterruptController>,
|
||||
}
|
||||
@@ -51,10 +63,10 @@ pub struct IrqChipList {
|
||||
|
||||
pub struct IrqDescItem {
|
||||
pub idx: usize,
|
||||
pub ic_idx: usize, //ic idx in irq chip list
|
||||
pub ic_idx: usize, //ic idx in irq chip list
|
||||
pub child_ic_idx: Option<usize>, //ic idx in irq chip list
|
||||
pub ic_irq: u32, //hwirq in ic
|
||||
pub used: bool,
|
||||
pub ic_irq: u32, //hwirq in ic
|
||||
pub used: bool,
|
||||
}
|
||||
|
||||
pub struct IrqDesc {
|
||||
@@ -66,27 +78,50 @@ impl IrqChipList {
|
||||
fn init_inner1(&mut self, fdt: &fdt::DeviceTree) {
|
||||
let root_node = fdt.nodes().nth(0).unwrap();
|
||||
let mut idx = 0;
|
||||
let intr = root_node.properties().find(|p| p.name.contains("interrupt-parent")).unwrap();
|
||||
let intr = root_node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("interrupt-parent"))
|
||||
.unwrap();
|
||||
|
||||
let root_intr_parent = BE::read_u32(&intr.data);
|
||||
debug!("root parent = 0x{:08x}", root_intr_parent);
|
||||
self.root_phandle = root_intr_parent;
|
||||
for node in fdt.nodes() {
|
||||
if node.properties().find(|p| p.name.contains("interrupt-controller")).is_some() {
|
||||
let compatible = node.properties().find(|p| p.name.contains("compatible")).unwrap();
|
||||
let phandle = node.properties().find(|p| p.name.contains("phandle")).unwrap();
|
||||
let intr_cells = node.properties().find(|p| p.name.contains("#interrupt-cells")).unwrap();
|
||||
let _intr = node.properties().find(|p| p.name.contains("interrupt-parent"));
|
||||
if node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("interrupt-controller"))
|
||||
.is_some()
|
||||
{
|
||||
let compatible = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("compatible"))
|
||||
.unwrap();
|
||||
let phandle = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("phandle"))
|
||||
.unwrap();
|
||||
let intr_cells = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("#interrupt-cells"))
|
||||
.unwrap();
|
||||
let _intr = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("interrupt-parent"));
|
||||
let _intr_data = node.properties().find(|p| p.name.contains("interrupts"));
|
||||
|
||||
let s = core::str::from_utf8(compatible.data).unwrap();
|
||||
debug!("{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}", node.name, s, BE::read_u32(intr_cells.data),
|
||||
BE::read_u32(phandle.data));
|
||||
debug!(
|
||||
"{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}",
|
||||
node.name,
|
||||
s,
|
||||
BE::read_u32(intr_cells.data),
|
||||
BE::read_u32(phandle.data)
|
||||
);
|
||||
let mut item = IrqChipItem {
|
||||
compatible: s.to_string(),
|
||||
phandle: BE::read_u32(phandle.data),
|
||||
parent_phandle: None,
|
||||
intr_cell_size: BE::read_u32(intr_cells.data),
|
||||
intr_cell_size: BE::read_u32(intr_cells.data),
|
||||
parent: None,
|
||||
childs: Vec::new(),
|
||||
interrupts: Vec::new(),
|
||||
@@ -111,7 +146,6 @@ impl IrqChipList {
|
||||
self.chips.push(item);
|
||||
|
||||
idx += 1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,7 +169,6 @@ impl IrqChipList {
|
||||
}
|
||||
x += 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn init_inner3(&mut self, fdt: &fdt::DeviceTree, irq_desc: &mut [IrqDesc; 1024]) {
|
||||
@@ -146,13 +179,14 @@ impl IrqChipList {
|
||||
while !queue.is_empty() {
|
||||
let cur_idx = queue.pop().unwrap();
|
||||
queue.extend_from_slice(&self.chips[cur_idx].childs);
|
||||
let virq = self.chips[cur_idx].ic.irq_init(fdt, irq_desc, cur_idx, &mut irq_idx);
|
||||
let virq = self.chips[cur_idx]
|
||||
.ic
|
||||
.irq_init(fdt, irq_desc, cur_idx, &mut irq_idx);
|
||||
if let Ok(Some(virq)) = virq {
|
||||
irq_desc[virq].basic.child_ic_idx = Some(cur_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub struct IrqChipCore {
|
||||
@@ -164,7 +198,9 @@ pub struct IrqChipCore {
|
||||
|
||||
impl IrqChipCore {
|
||||
pub fn irq_ack(&mut self) -> u32 {
|
||||
self.irq_chip_list.chips[self.irq_chip_list.root_idx].ic.irq_ack()
|
||||
self.irq_chip_list.chips[self.irq_chip_list.root_idx]
|
||||
.ic
|
||||
.irq_ack()
|
||||
}
|
||||
|
||||
pub fn irq_eoi(&mut self, virq: u32) {
|
||||
@@ -192,7 +228,9 @@ impl IrqChipCore {
|
||||
}
|
||||
|
||||
pub fn irq_to_virq(&mut self, hwirq: u32) -> Option<usize> {
|
||||
self.irq_chip_list.chips[self.irq_chip_list.root_idx].ic.irq_to_virq(hwirq)
|
||||
self.irq_chip_list.chips[self.irq_chip_list.root_idx]
|
||||
.ic
|
||||
.irq_to_virq(hwirq)
|
||||
}
|
||||
|
||||
pub fn init(&mut self, fdt: &DeviceTree) {
|
||||
@@ -202,7 +240,6 @@ impl IrqChipCore {
|
||||
self.irq_chip_list.init_inner1(fdt);
|
||||
self.irq_chip_list.init_inner2();
|
||||
self.irq_chip_list.init_inner3(fdt, &mut self.irq_desc);
|
||||
|
||||
}
|
||||
|
||||
pub fn new_ic(ic_str: &str) -> Option<Box<dyn InterruptController>> {
|
||||
@@ -229,7 +266,7 @@ const INIT_IRQ_DESC: IrqDesc = IrqDesc {
|
||||
},
|
||||
handler: INIT_HANDLER,
|
||||
};
|
||||
pub static mut IRQ_CHIP: IrqChipCore = IrqChipCore {
|
||||
pub static mut IRQ_CHIP: IrqChipCore = IrqChipCore {
|
||||
irq_chip_list: IrqChipList {
|
||||
chips: Vec::new(),
|
||||
root_phandle: 0,
|
||||
@@ -239,7 +276,6 @@ pub static mut IRQ_CHIP: IrqChipCore = IrqChipCore {
|
||||
irq_desc: [INIT_IRQ_DESC; 1024],
|
||||
};
|
||||
|
||||
|
||||
pub fn init(fdt: &DeviceTree) {
|
||||
travel_interrupt_ctrl(fdt);
|
||||
unsafe {
|
||||
@@ -250,13 +286,13 @@ pub fn init(fdt: &DeviceTree) {
|
||||
pub fn register_irq(virq: u32, handler: Box<dyn InterruptHandler>) {
|
||||
if virq >= 1024 {
|
||||
error!("irq {} exceed 1024!!!", virq);
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
if IRQ_CHIP.irq_desc[virq as usize].handler.is_some() {
|
||||
error!("irq {} has already been registered!", virq);
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
IRQ_CHIP.irq_desc[virq as usize].handler = Some(handler);
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
use core::arch::asm;
|
||||
|
||||
use crate::memory::Frame;
|
||||
use crate::paging::{KernelMapper, PhysicalAddress, Page, PageFlags, VirtualAddress};
|
||||
use crate::dtb::DTB_BINARY;
|
||||
use crate::log::info;
|
||||
use crate::{
|
||||
dtb::DTB_BINARY,
|
||||
log::info,
|
||||
memory::Frame,
|
||||
paging::{KernelMapper, Page, PageFlags, PhysicalAddress, VirtualAddress},
|
||||
};
|
||||
|
||||
pub mod cpu;
|
||||
pub mod irqchip;
|
||||
pub mod generic_timer;
|
||||
pub mod serial;
|
||||
pub mod irqchip;
|
||||
pub mod rtc;
|
||||
pub mod serial;
|
||||
pub mod uart_pl011;
|
||||
|
||||
pub unsafe fn init() {
|
||||
@@ -28,8 +30,7 @@ pub unsafe fn init_noncore() {
|
||||
rtc::init();
|
||||
}
|
||||
|
||||
pub unsafe fn init_ap() {
|
||||
}
|
||||
pub unsafe fn init_ap() {}
|
||||
|
||||
//map physical addr X to virtual addr PHYS_OFFSET + X
|
||||
pub unsafe fn io_mmap(addr: usize, io_size: usize) {
|
||||
@@ -38,13 +39,18 @@ pub unsafe fn io_mmap(addr: usize, io_size: usize) {
|
||||
let start_frame = Frame::containing_address(PhysicalAddress::new(addr));
|
||||
let end_frame = Frame::containing_address(PhysicalAddress::new(addr + io_size - 1));
|
||||
for frame in Frame::range_inclusive(start_frame, end_frame) {
|
||||
let page = Page::containing_address(VirtualAddress::new(frame.start_address().data() + crate::PHYS_OFFSET));
|
||||
let page = Page::containing_address(VirtualAddress::new(
|
||||
frame.start_address().data() + crate::PHYS_OFFSET,
|
||||
));
|
||||
mapper
|
||||
.get_mut()
|
||||
.expect("failed to access KernelMapper for mapping GIC distributor")
|
||||
.map_phys(page.start_address(), frame.start_address(), PageFlags::new().write(true))
|
||||
.map_phys(
|
||||
page.start_address(),
|
||||
frame.start_address(),
|
||||
PageFlags::new().write(true),
|
||||
)
|
||||
.expect("failed to map GIC distributor")
|
||||
.flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
|
||||
use crate::memory::Frame;
|
||||
use crate::paging::{KernelMapper, PhysicalAddress, Page, PageFlags, TableKind, VirtualAddress};
|
||||
use crate::time;
|
||||
use crate::{
|
||||
memory::Frame,
|
||||
paging::{KernelMapper, Page, PageFlags, PhysicalAddress, TableKind, VirtualAddress},
|
||||
time,
|
||||
};
|
||||
|
||||
static RTC_DR: u32 = 0x000;
|
||||
static RTC_MR: u32 = 0x004;
|
||||
@@ -13,9 +15,7 @@ static RTC_RIS: u32 = 0x014;
|
||||
static RTC_MIS: u32 = 0x018;
|
||||
static RTC_ICR: u32 = 0x01c;
|
||||
|
||||
static mut PL031_RTC: Pl031rtc = Pl031rtc {
|
||||
address: 0,
|
||||
};
|
||||
static mut PL031_RTC: Pl031rtc = Pl031rtc { address: 0 };
|
||||
|
||||
pub unsafe fn init() {
|
||||
PL031_RTC.init();
|
||||
@@ -34,11 +34,17 @@ impl Pl031rtc {
|
||||
let end_frame = Frame::containing_address(PhysicalAddress::new(0x09010000 + 0x1000 - 1));
|
||||
|
||||
for frame in Frame::range_inclusive(start_frame, end_frame) {
|
||||
let page = Page::containing_address(VirtualAddress::new(frame.start_address().data() + crate::PHYS_OFFSET));
|
||||
let page = Page::containing_address(VirtualAddress::new(
|
||||
frame.start_address().data() + crate::PHYS_OFFSET,
|
||||
));
|
||||
mapper
|
||||
.get_mut()
|
||||
.expect("failed to access KernelMapper for mapping RTC")
|
||||
.map_phys(page.start_address(), frame.start_address(), PageFlags::new().write(true))
|
||||
.map_phys(
|
||||
page.start_address(),
|
||||
frame.start_address(),
|
||||
PageFlags::new().write(true),
|
||||
)
|
||||
.expect("failed to map RTC")
|
||||
.flush();
|
||||
}
|
||||
|
||||
@@ -1,31 +1,33 @@
|
||||
use alloc::boxed::Box;
|
||||
use spin::Mutex;
|
||||
|
||||
use crate::{device::uart_pl011::SerialPort, interrupt::irq::trigger};
|
||||
use crate::init::device_tree;
|
||||
use crate::log::{info, debug};
|
||||
use crate::{
|
||||
device::uart_pl011::SerialPort,
|
||||
init::device_tree,
|
||||
interrupt::irq::trigger,
|
||||
log::{debug, info},
|
||||
};
|
||||
|
||||
use super::irqchip::{register_irq, IRQ_CHIP, InterruptHandler};
|
||||
use crate::dtb::DTB_BINARY;
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use crate::init::device_tree::find_compatible_node;
|
||||
use super::irqchip::{register_irq, InterruptHandler, IRQ_CHIP};
|
||||
use crate::{dtb::DTB_BINARY, init::device_tree::find_compatible_node};
|
||||
use alloc::vec::Vec;
|
||||
use byteorder::{ByteOrder, BE};
|
||||
|
||||
pub static COM1: Mutex<Option<SerialPort>> = Mutex::new(None);
|
||||
|
||||
pub struct Com1Irq {
|
||||
}
|
||||
pub struct Com1Irq {}
|
||||
|
||||
impl InterruptHandler for Com1Irq {
|
||||
fn irq_handler(&mut self, irq: u32) {
|
||||
if let Some(ref mut serial_port) = *COM1.lock() {
|
||||
serial_port.receive();
|
||||
};
|
||||
unsafe { trigger(irq); }
|
||||
unsafe {
|
||||
trigger(irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub unsafe fn init_early(dtb_base: usize, dtb_size: usize) {
|
||||
if COM1.lock().is_some() {
|
||||
// Hardcoded UART
|
||||
@@ -47,14 +49,20 @@ pub unsafe fn init() {
|
||||
let data = DTB_BINARY.get().unwrap();
|
||||
let fdt = fdt::DeviceTree::new(data).unwrap();
|
||||
if let Some(node) = find_compatible_node(&fdt, "arm,pl011") {
|
||||
let interrupts = node.properties().find(|p| p.name.contains("interrupts")).unwrap();
|
||||
let interrupts = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("interrupts"))
|
||||
.unwrap();
|
||||
let mut intr_data = Vec::new();
|
||||
for chunk in interrupts.data.chunks(4) {
|
||||
let val = BE::read_u32(chunk);
|
||||
intr_data.push(val);
|
||||
}
|
||||
let mut ic_idx = IRQ_CHIP.irq_chip_list.root_idx;
|
||||
if let Some(interrupt_parent) = node.properties().find(|p| p.name.contains("interrupt-parent")) {
|
||||
if let Some(interrupt_parent) = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("interrupt-parent"))
|
||||
{
|
||||
let phandle = BE::read_u32(interrupt_parent.data);
|
||||
let mut i = 0;
|
||||
while i < IRQ_CHIP.irq_chip_list.chips.len() {
|
||||
@@ -66,7 +74,10 @@ pub unsafe fn init() {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx].ic.irq_xlate(&intr_data, 0).unwrap();
|
||||
let virq = IRQ_CHIP.irq_chip_list.chips[ic_idx]
|
||||
.ic
|
||||
.irq_xlate(&intr_data, 0)
|
||||
.unwrap();
|
||||
info!("serial_port virq = {}", virq);
|
||||
register_irq(virq as u32, Box::new(Com1Irq {}));
|
||||
IRQ_CHIP.irq_enable(virq as u32);
|
||||
|
||||
@@ -135,13 +135,14 @@ impl SerialPort {
|
||||
}
|
||||
|
||||
pub fn write_reg(&self, register: u8, data: u32) {
|
||||
unsafe { ptr::write_volatile((self.base + register as usize) as *mut u32, data); }
|
||||
unsafe {
|
||||
ptr::write_volatile((self.base + register as usize) as *mut u32, data);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self, with_irq: bool) {
|
||||
|
||||
if self.skip_init {
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
|
||||
//Disable UART first
|
||||
@@ -175,7 +176,7 @@ impl SerialPort {
|
||||
}
|
||||
|
||||
pub fn drain_fifo(&mut self) {
|
||||
for _ in 0..self.fifo_size*2 {
|
||||
for _ in 0..self.fifo_size * 2 {
|
||||
if self.line_sts().contains(UartFrFlags::RXFE) {
|
||||
break;
|
||||
}
|
||||
@@ -187,7 +188,6 @@ impl SerialPort {
|
||||
let mut flags = self.intr_stats();
|
||||
let chk_flags = UartRisFlags::RTIS | UartRisFlags::RXIS;
|
||||
while (flags & chk_flags).bits != 0 {
|
||||
|
||||
if self.cts_event_walkaround {
|
||||
self.write_reg(self.intr_clr_reg, 0x00);
|
||||
let _ = self.read_reg(self.intr_clr_reg);
|
||||
@@ -213,7 +213,7 @@ impl SerialPort {
|
||||
}
|
||||
|
||||
pub fn send(&mut self, data: u8) {
|
||||
while ! self.line_sts().contains(UartFrFlags::TXFE) {}
|
||||
while !self.line_sts().contains(UartFrFlags::TXFE) {}
|
||||
self.write_reg(self.data_reg, data as u32);
|
||||
}
|
||||
|
||||
@@ -227,7 +227,6 @@ impl SerialPort {
|
||||
}
|
||||
|
||||
pub fn enable_irq(&mut self) {
|
||||
|
||||
self.clear_all_irqs();
|
||||
|
||||
self.drain_fifo();
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
extern crate fdt;
|
||||
extern crate byteorder;
|
||||
extern crate fdt;
|
||||
|
||||
use crate::log::{info, debug};
|
||||
use fdt::Node;
|
||||
use core::slice;
|
||||
use crate::memory::MemoryArea;
|
||||
use self::byteorder::{ByteOrder, BE};
|
||||
use crate::{
|
||||
log::{debug, info},
|
||||
memory::MemoryArea,
|
||||
};
|
||||
use core::slice;
|
||||
use fdt::Node;
|
||||
|
||||
pub static mut MEMORY_MAP: [MemoryArea; 512] = [MemoryArea {
|
||||
base_addr: 0,
|
||||
@@ -16,29 +18,61 @@ pub static mut MEMORY_MAP: [MemoryArea; 512] = [MemoryArea {
|
||||
|
||||
pub fn root_cell_sz(dt: &fdt::DeviceTree) -> Option<(u32, u32)> {
|
||||
let root_node = dt.nodes().nth(0).unwrap();
|
||||
let address_cells = root_node.properties().find(|p| p.name.contains("#address-cells")).unwrap();
|
||||
let size_cells = root_node.properties().find(|p| p.name.contains("#size-cells")).unwrap();
|
||||
let address_cells = root_node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("#address-cells"))
|
||||
.unwrap();
|
||||
let size_cells = root_node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("#size-cells"))
|
||||
.unwrap();
|
||||
|
||||
Some((BE::read_u32(&size_cells.data), BE::read_u32(&size_cells.data)))
|
||||
Some((
|
||||
BE::read_u32(&size_cells.data),
|
||||
BE::read_u32(&size_cells.data),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn travel_interrupt_ctrl(fdt: &fdt::DeviceTree) {
|
||||
let root_node = fdt.nodes().nth(0).unwrap();
|
||||
let intr = root_node.properties().find(|p| p.name.contains("interrupt-parent")).unwrap();
|
||||
let intr = root_node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("interrupt-parent"))
|
||||
.unwrap();
|
||||
|
||||
let root_intr_parent = BE::read_u32(&intr.data);
|
||||
debug!("root parent = 0x{:08x}", root_intr_parent);
|
||||
for node in fdt.nodes() {
|
||||
if node.properties().find(|p| p.name.contains("interrupt-controller")).is_some() {
|
||||
let compatible = node.properties().find(|p| p.name.contains("compatible")).unwrap();
|
||||
let phandle = node.properties().find(|p| p.name.contains("phandle")).unwrap();
|
||||
let intr_cells = node.properties().find(|p| p.name.contains("#interrupt-cells")).unwrap();
|
||||
let _intr = node.properties().find(|p| p.name.contains("interrupt-parent"));
|
||||
if node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("interrupt-controller"))
|
||||
.is_some()
|
||||
{
|
||||
let compatible = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("compatible"))
|
||||
.unwrap();
|
||||
let phandle = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("phandle"))
|
||||
.unwrap();
|
||||
let intr_cells = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("#interrupt-cells"))
|
||||
.unwrap();
|
||||
let _intr = node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("interrupt-parent"));
|
||||
let _intr_data = node.properties().find(|p| p.name.contains("interrupts"));
|
||||
|
||||
let s = core::str::from_utf8(compatible.data).unwrap();
|
||||
debug!("{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}", node.name, s, BE::read_u32(intr_cells.data),
|
||||
BE::read_u32(phandle.data));
|
||||
debug!(
|
||||
"{}, compatible = {}, #interrupt-cells = 0x{:08x}, phandle = 0x{:08x}",
|
||||
node.name,
|
||||
s,
|
||||
BE::read_u32(intr_cells.data),
|
||||
BE::read_u32(phandle.data)
|
||||
);
|
||||
if let Some(intr) = _intr {
|
||||
if let Some(intr_data) = _intr_data {
|
||||
debug!("interrupt-parent = 0x{:08x}", BE::read_u32(intr.data));
|
||||
@@ -53,10 +87,17 @@ pub fn travel_interrupt_ctrl(fdt: &fdt::DeviceTree) {
|
||||
}
|
||||
}
|
||||
|
||||
fn memory_ranges(dt: &fdt::DeviceTree, address_cells: usize, size_cells: usize, ranges: &mut [(usize, usize); 10]) -> usize {
|
||||
|
||||
fn memory_ranges(
|
||||
dt: &fdt::DeviceTree,
|
||||
address_cells: usize,
|
||||
size_cells: usize,
|
||||
ranges: &mut [(usize, usize); 10],
|
||||
) -> usize {
|
||||
let (memory_node, _memory_cells) = dt.find_node("/memory").unwrap();
|
||||
let reg = memory_node.properties().find(|p| p.name.contains("reg")).unwrap();
|
||||
let reg = memory_node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("reg"))
|
||||
.unwrap();
|
||||
let chunk_sz = (address_cells + size_cells) * 4;
|
||||
let chunk_count = (reg.data.len() / chunk_sz);
|
||||
let mut index = 0;
|
||||
@@ -79,8 +120,12 @@ fn memory_ranges(dt: &fdt::DeviceTree, address_cells: usize, size_cells: usize,
|
||||
index
|
||||
}
|
||||
|
||||
fn dev_memory_ranges(dt: &fdt::DeviceTree, address_cells: usize, size_cells: usize, ranges: &mut [(usize, usize); 10]) -> usize {
|
||||
|
||||
fn dev_memory_ranges(
|
||||
dt: &fdt::DeviceTree,
|
||||
address_cells: usize,
|
||||
size_cells: usize,
|
||||
ranges: &mut [(usize, usize); 10],
|
||||
) -> usize {
|
||||
// work around for qemu-arm64
|
||||
// dev mem: 128MB - 1GB, see https://github.com/qemu/qemu/blob/master/hw/arm/virt.c for details
|
||||
let root_node = dt.nodes().nth(0).unwrap();
|
||||
@@ -100,7 +145,10 @@ fn dev_memory_ranges(dt: &fdt::DeviceTree, address_cells: usize, size_cells: usi
|
||||
}
|
||||
|
||||
let (memory_node, _memory_cells) = dt.find_node("/soc").unwrap();
|
||||
let reg = memory_node.properties().find(|p| p.name.contains("ranges")).unwrap();
|
||||
let reg = memory_node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("ranges"))
|
||||
.unwrap();
|
||||
let chunk_sz = (address_cells * 2 + size_cells) * 4;
|
||||
let chunk_count = (reg.data.len() / chunk_sz);
|
||||
let mut index = 0;
|
||||
@@ -137,7 +185,10 @@ fn dev_memory_ranges(dt: &fdt::DeviceTree, address_cells: usize, size_cells: usi
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
debug!("dev mem 0x{:08x} 0x{:08x} 0x{:08x}", child_bus_addr, parent_bus_addr, addr_size);
|
||||
debug!(
|
||||
"dev mem 0x{:08x} 0x{:08x} 0x{:08x}",
|
||||
child_bus_addr, parent_bus_addr, addr_size
|
||||
);
|
||||
|
||||
ranges[index] = (parent_bus_addr as usize, addr_size as usize);
|
||||
index += 1;
|
||||
@@ -150,17 +201,33 @@ pub fn diag_uart_range(dtb_base: usize, dtb_size: usize) -> Option<(usize, usize
|
||||
let dt = fdt::DeviceTree::new(data).unwrap();
|
||||
|
||||
let (chosen_node, _chosen_cells) = dt.find_node("/chosen").unwrap();
|
||||
let stdout_path = chosen_node.properties().find(|p| p.name.contains("stdout-path")).unwrap();
|
||||
let uart_node_name = core::str::from_utf8(stdout_path.data).unwrap()
|
||||
let stdout_path = chosen_node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("stdout-path"))
|
||||
.unwrap();
|
||||
let uart_node_name = core::str::from_utf8(stdout_path.data)
|
||||
.unwrap()
|
||||
.split('/')
|
||||
.nth(1)?
|
||||
.trim_end();
|
||||
let len = uart_node_name.len();
|
||||
let uart_node_name = &uart_node_name[0..len-1];
|
||||
let uart_node = dt.nodes().find(|n| n.name.contains(uart_node_name)).unwrap();
|
||||
let skip_init = uart_node.properties().find(|p| p.name.contains("skip-init")).is_some();
|
||||
let cts_event_walkaround = uart_node.properties().find(|p| p.name.contains("cts-event-walkaround")).is_some();
|
||||
let reg = uart_node.properties().find(|p| p.name.contains("reg")).unwrap();
|
||||
let uart_node_name = &uart_node_name[0..len - 1];
|
||||
let uart_node = dt
|
||||
.nodes()
|
||||
.find(|n| n.name.contains(uart_node_name))
|
||||
.unwrap();
|
||||
let skip_init = uart_node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("skip-init"))
|
||||
.is_some();
|
||||
let cts_event_walkaround = uart_node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("cts-event-walkaround"))
|
||||
.is_some();
|
||||
let reg = uart_node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("reg"))
|
||||
.unwrap();
|
||||
|
||||
let (address_cells, size_cells) = root_cell_sz(&dt).unwrap();
|
||||
let chunk_sz = (address_cells + size_cells) * 4;
|
||||
@@ -188,7 +255,10 @@ fn compatible_node_present<'a>(dt: &fdt::DeviceTree<'a>, compat_string: &str) ->
|
||||
false
|
||||
}
|
||||
|
||||
pub fn find_compatible_node<'a>(dt: &'a fdt::DeviceTree<'a>, compat_string: &str) -> Option<Node<'a, 'a>> {
|
||||
pub fn find_compatible_node<'a>(
|
||||
dt: &'a fdt::DeviceTree<'a>,
|
||||
compat_string: &str,
|
||||
) -> Option<Node<'a, 'a>> {
|
||||
for node in dt.nodes() {
|
||||
if let Some(compatible) = node.properties().find(|p| p.name.contains("compatible")) {
|
||||
let s = core::str::from_utf8(compatible.data).unwrap();
|
||||
@@ -205,10 +275,14 @@ pub fn fill_env_data(dtb_base: usize, dtb_size: usize, env_base: usize) -> usize
|
||||
let dt = fdt::DeviceTree::new(data).unwrap();
|
||||
|
||||
let (chosen_node, _chosen_cells) = dt.find_node("/chosen").unwrap();
|
||||
if let Some(bootargs) = chosen_node.properties().find(|p| p.name.contains("bootargs")) {
|
||||
if let Some(bootargs) = chosen_node
|
||||
.properties()
|
||||
.find(|p| p.name.contains("bootargs"))
|
||||
{
|
||||
let bootargs_len = bootargs.data.len();
|
||||
|
||||
let env_base_slice = unsafe { slice::from_raw_parts_mut(env_base as *mut u8, bootargs_len) };
|
||||
let env_base_slice =
|
||||
unsafe { slice::from_raw_parts_mut(env_base as *mut u8, bootargs_len) };
|
||||
env_base_slice[..bootargs_len].clone_from_slice(bootargs.data);
|
||||
|
||||
bootargs_len
|
||||
@@ -222,11 +296,16 @@ pub fn fill_memory_map(dtb_base: usize, dtb_size: usize) {
|
||||
let dt = fdt::DeviceTree::new(data).unwrap();
|
||||
|
||||
let (address_cells, size_cells) = root_cell_sz(&dt).unwrap();
|
||||
let mut ranges: [(usize, usize); 10] = [(0,0); 10];
|
||||
let mut ranges: [(usize, usize); 10] = [(0, 0); 10];
|
||||
|
||||
//in uefi boot mode, ignore memory node, just read the device memory range
|
||||
//in uefi boot mode, ignore memory node, just read the device memory range
|
||||
//let nranges = memory_ranges(&dt, address_cells as usize, size_cells as usize, &mut ranges);
|
||||
let nranges = dev_memory_ranges(&dt, address_cells as usize, size_cells as usize, &mut ranges);
|
||||
let nranges = dev_memory_ranges(
|
||||
&dt,
|
||||
address_cells as usize,
|
||||
size_cells as usize,
|
||||
&mut ranges,
|
||||
);
|
||||
|
||||
for index in 0..nranges {
|
||||
let (base, size) = ranges[index];
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use rmm::VirtualAddress;
|
||||
|
||||
use crate::memory::{ArchIntCtx, GenericPfFlags};
|
||||
use crate::{
|
||||
exception_stack,
|
||||
interrupt::stack_trace,
|
||||
memory::{ArchIntCtx, GenericPfFlags},
|
||||
syscall,
|
||||
syscall::flag::*,
|
||||
|
||||
with_exception_stack,
|
||||
exception_stack,
|
||||
};
|
||||
|
||||
use super::InterruptStack;
|
||||
@@ -32,7 +31,12 @@ unsafe fn far_el1() -> usize {
|
||||
ret
|
||||
}
|
||||
|
||||
unsafe fn instr_data_abort_inner(stack: &mut InterruptStack, from_user: bool, instr_not_data: bool, from: &str) -> bool {
|
||||
unsafe fn instr_data_abort_inner(
|
||||
stack: &mut InterruptStack,
|
||||
from_user: bool,
|
||||
instr_not_data: bool,
|
||||
from: &str,
|
||||
) -> bool {
|
||||
let iss = iss(stack.iret.esr_el1);
|
||||
let fsc = iss & 0x3F;
|
||||
//dbg!(fsc);
|
||||
@@ -46,7 +50,10 @@ unsafe fn instr_data_abort_inner(stack: &mut InterruptStack, from_user: bool, in
|
||||
|
||||
// TODO: RMW instructions may "involve" writing to (possibly invalid) memory, but AArch64
|
||||
// doesn't appear to require that flag to be set if the read alone would trigger a fault.
|
||||
flags.set(GenericPfFlags::INVOLVED_WRITE, write_not_read_if_data && !instr_not_data);
|
||||
flags.set(
|
||||
GenericPfFlags::INVOLVED_WRITE,
|
||||
write_not_read_if_data && !instr_not_data,
|
||||
);
|
||||
flags.set(GenericPfFlags::INSTR_NOT_DATA, instr_not_data);
|
||||
flags.set(GenericPfFlags::USER_NOT_SUPERVISOR, from_user);
|
||||
|
||||
@@ -74,7 +81,12 @@ unsafe fn cntvct_el0() -> usize {
|
||||
ret
|
||||
}
|
||||
|
||||
unsafe fn instr_trapped_msr_mrs_inner(stack: &mut InterruptStack, from_user: bool, instr_not_data: bool, from: &str) -> bool {
|
||||
unsafe fn instr_trapped_msr_mrs_inner(
|
||||
stack: &mut InterruptStack,
|
||||
from_user: bool,
|
||||
instr_not_data: bool,
|
||||
from: &str,
|
||||
) -> bool {
|
||||
let iss = iss(stack.iret.esr_el1);
|
||||
let res0 = (iss & 0x1C0_0000) >> 22;
|
||||
let op0 = (iss & 0x030_0000) >> 20;
|
||||
@@ -99,7 +111,7 @@ unsafe fn instr_trapped_msr_mrs_inner(stack: &mut InterruptStack, from_user: boo
|
||||
stack.store_reg(rt as usize, reg_val);
|
||||
//skip faulting instruction, A64 instructions are always 32-bits
|
||||
stack.iret.elr_el1 += 4;
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
//MRS <Xt>, CNTPCT_EL0
|
||||
(0b11, 0b011, 0b1110, 0b0000, 0b001, 0b1) => {
|
||||
@@ -107,7 +119,7 @@ unsafe fn instr_trapped_msr_mrs_inner(stack: &mut InterruptStack, from_user: boo
|
||||
stack.store_reg(rt as usize, reg_val);
|
||||
//skip faulting instruction, A64 instructions are always 32-bits
|
||||
stack.iret.elr_el1 += 4;
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
//MRS <Xt>, CNTVCT_EL0
|
||||
(0b11, 0b011, 0b1110, 0b0000, 0b010, 0b1) => {
|
||||
@@ -115,22 +127,25 @@ unsafe fn instr_trapped_msr_mrs_inner(stack: &mut InterruptStack, from_user: boo
|
||||
stack.store_reg(rt as usize, reg_val);
|
||||
//skip faulting instruction, A64 instructions are always 32-bits
|
||||
stack.iret.elr_el1 += 4;
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
exception_stack!(synchronous_exception_at_el1_with_spx, |stack| {
|
||||
if !pf_inner(stack, exception_code(stack.iret.esr_el1), "sync_exc_el1_spx") {
|
||||
if !pf_inner(
|
||||
stack,
|
||||
exception_code(stack.iret.esr_el1),
|
||||
"sync_exc_el1_spx",
|
||||
) {
|
||||
println!("Synchronous exception at EL1 with SPx");
|
||||
if exception_code(stack.iret.esr_el1) == 0b100101 {
|
||||
let far_el1 = far_el1();
|
||||
println!("FAR_EL1 = 0x{:08x}", far_el1);
|
||||
}
|
||||
else if exception_code(stack.iret.esr_el1) == 0b100100 {
|
||||
} else if exception_code(stack.iret.esr_el1) == 0b100100 {
|
||||
let far_el1 = far_el1();
|
||||
println!("USER FAR_EL1 = 0x{:08x}", far_el1);
|
||||
}
|
||||
@@ -160,16 +175,23 @@ exception_stack!(synchronous_exception_at_el0, |stack| {
|
||||
match exception_code(stack.iret.esr_el1) {
|
||||
0b010101 => with_exception_stack!(|stack| {
|
||||
let scratch = &stack.scratch;
|
||||
syscall::syscall(scratch.x8, scratch.x0, scratch.x1, scratch.x2, scratch.x3, scratch.x4, stack)
|
||||
syscall::syscall(
|
||||
scratch.x8, scratch.x0, scratch.x1, scratch.x2, scratch.x3, scratch.x4, stack,
|
||||
)
|
||||
}),
|
||||
|
||||
ty => if !pf_inner(stack, ty as u8, "sync_exc_el0") {
|
||||
log::error!("FATAL: Not an SVC induced synchronous exception (ty={:b})", ty);
|
||||
println!("FAR_EL1: {:#0x}", far_el1());
|
||||
//crate::debugger::debugger(None);
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
crate::ksignal(SIGSEGV);
|
||||
ty => {
|
||||
if !pf_inner(stack, ty as u8, "sync_exc_el0") {
|
||||
log::error!(
|
||||
"FATAL: Not an SVC induced synchronous exception (ty={:b})",
|
||||
ty
|
||||
);
|
||||
println!("FAR_EL1: {:#0x}", far_el1());
|
||||
//crate::debugger::debugger(None);
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
crate::ksignal(SIGSEGV);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -87,9 +87,9 @@ impl PreservedRegisters {
|
||||
#[derive(Default)]
|
||||
#[repr(packed)]
|
||||
pub struct IretRegisters {
|
||||
// occurred
|
||||
// The exception vector disambiguates at which EL the interrupt
|
||||
pub sp_el0: usize, // Shouldn't be used if interrupt occurred at EL1
|
||||
// occurred
|
||||
// The exception vector disambiguates at which EL the interrupt
|
||||
pub sp_el0: usize, // Shouldn't be used if interrupt occurred at EL1
|
||||
pub esr_el1: usize,
|
||||
pub spsr_el1: usize,
|
||||
pub elr_el1: usize,
|
||||
@@ -238,12 +238,14 @@ impl InterruptStack {
|
||||
28 => self.preserved.x28 = val,
|
||||
29 => self.preserved.x29 = val,
|
||||
30 => self.preserved.x30 = val,
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
pub fn is_singlestep(&self) -> bool { false }
|
||||
pub fn is_singlestep(&self) -> bool {
|
||||
false
|
||||
}
|
||||
pub fn set_singlestep(&mut self, singlestep: bool) {}
|
||||
}
|
||||
|
||||
@@ -276,7 +278,8 @@ macro_rules! function {
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! push_scratch {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Push scratch registers
|
||||
str x18, [sp, #-16]!
|
||||
stp x16, x17, [sp, #-16]!
|
||||
@@ -288,12 +291,14 @@ macro_rules! push_scratch {
|
||||
stp x4, x5, [sp, #-16]!
|
||||
stp x2, x3, [sp, #-16]!
|
||||
stp x0, x1, [sp, #-16]!
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! pop_scratch {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Pop scratch registers
|
||||
ldp x0, x1, [sp], #16
|
||||
ldp x2, x3, [sp], #16
|
||||
@@ -305,12 +310,14 @@ macro_rules! pop_scratch {
|
||||
ldp x14, x15, [sp], #16
|
||||
ldp x16, x17, [sp], #16
|
||||
ldr x18, [sp], #16
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! push_preserved {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Push preserved registers
|
||||
stp x29, x30, [sp, #-16]!
|
||||
stp x27, x28, [sp, #-16]!
|
||||
@@ -318,12 +325,14 @@ macro_rules! push_preserved {
|
||||
stp x23, x24, [sp, #-16]!
|
||||
stp x21, x22, [sp, #-16]!
|
||||
stp x19, x20, [sp, #-16]!
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! pop_preserved {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Pop preserved registers
|
||||
ldp x19, x20, [sp], #16
|
||||
ldp x21, x22, [sp], #16
|
||||
@@ -331,12 +340,14 @@ macro_rules! pop_preserved {
|
||||
ldp x25, x26, [sp], #16
|
||||
ldp x27, x28, [sp], #16
|
||||
ldp x29, x30, [sp], #16
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! push_special {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
mrs x14, spsr_el1
|
||||
mrs x15, elr_el1
|
||||
stp x14, x15, [sp, #-16]!
|
||||
@@ -344,12 +355,14 @@ macro_rules! push_special {
|
||||
mrs x14, sp_el0
|
||||
mrs x15, esr_el1
|
||||
stp x14, x15, [sp, #-16]!
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! pop_special {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
ldp x14, x15, [sp], 16
|
||||
msr esr_el1, x15
|
||||
msr sp_el0, x14
|
||||
@@ -357,7 +370,8 @@ macro_rules! pop_special {
|
||||
ldp x14, x15, [sp], 16
|
||||
msr elr_el1, x15
|
||||
msr spsr_el1, x14
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
//use crate::device::generic_timer::{GENTIMER};
|
||||
use crate::device::irqchip::IRQ_CHIP;
|
||||
use crate::device::serial::COM1;
|
||||
use crate::device::{irqchip::IRQ_CHIP, serial::COM1};
|
||||
|
||||
pub struct IrqDesc {
|
||||
pub virq: u32,
|
||||
@@ -33,10 +32,9 @@ exception_stack!(irq_at_el1, |stack| {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//TODO
|
||||
pub unsafe fn trigger(irq: u32) {
|
||||
extern {
|
||||
extern "C" {
|
||||
fn irq_trigger(irq: u32);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ pub mod trace;
|
||||
|
||||
use crate::LogicalCpuId;
|
||||
|
||||
pub use self::handler::InterruptStack;
|
||||
pub use self::trace::stack_trace;
|
||||
pub use self::{handler::InterruptStack, trace::stack_trace};
|
||||
|
||||
/// Clear interrupts
|
||||
#[inline(always)]
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
use crate::{
|
||||
arch::{interrupt::InterruptStack},
|
||||
context,
|
||||
syscall,
|
||||
syscall::flag::{PTRACE_FLAG_IGNORE, PTRACE_STOP_PRE_SYSCALL, PTRACE_STOP_POST_SYSCALL},
|
||||
arch::interrupt::InterruptStack,
|
||||
context, syscall,
|
||||
syscall::flag::{PTRACE_FLAG_IGNORE, PTRACE_STOP_POST_SYSCALL, PTRACE_STOP_PRE_SYSCALL},
|
||||
};
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn do_exception_unhandled() {}
|
||||
pub unsafe extern "C" fn do_exception_unhandled() {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn do_exception_synchronous() {}
|
||||
pub unsafe extern "C" fn do_exception_synchronous() {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(packed)]
|
||||
@@ -57,7 +56,7 @@ pub struct SyscallStack {
|
||||
#[macro_export]
|
||||
macro_rules! with_exception_stack {
|
||||
(|$stack:ident| $code:block) => {{
|
||||
let $stack = &mut *$stack;
|
||||
(*$stack).scratch.x0 = $code;
|
||||
}}
|
||||
let $stack = &mut *$stack;
|
||||
(*$stack).scratch.x0 = $code;
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ pub unsafe fn stack_trace() {
|
||||
for _frame in 0..64 {
|
||||
if let Some(pc_fp) = fp.checked_add(mem::size_of::<usize>()) {
|
||||
if mapper.translate(VirtualAddress::new(fp)).is_some()
|
||||
&& mapper.translate(VirtualAddress::new(pc_fp)).is_some() {
|
||||
&& mapper.translate(VirtualAddress::new(pc_fp)).is_some()
|
||||
{
|
||||
let pc = *(pc_fp as *const usize);
|
||||
if pc == 0 {
|
||||
println!(" {:>016x}: EMPTY RETURN", fp);
|
||||
@@ -41,11 +42,12 @@ pub unsafe fn stack_trace() {
|
||||
//TODO: Do not create Elf object for every symbol lookup
|
||||
#[inline(never)]
|
||||
pub unsafe fn symbol_trace(addr: usize) {
|
||||
use core::slice;
|
||||
use core::sync::atomic::Ordering;
|
||||
use core::{slice, sync::atomic::Ordering};
|
||||
|
||||
use crate::elf::Elf;
|
||||
use crate::start::{KERNEL_BASE, KERNEL_SIZE};
|
||||
use crate::{
|
||||
elf::Elf,
|
||||
start::{KERNEL_BASE, KERNEL_SIZE},
|
||||
};
|
||||
|
||||
let kernel_ptr = (KERNEL_BASE.load(Ordering::SeqCst) + crate::KERNEL_OFFSET) as *const u8;
|
||||
let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst));
|
||||
@@ -70,76 +72,80 @@ pub unsafe fn symbol_trace(addr: usize) {
|
||||
for sym in symbols {
|
||||
if sym::st_type(sym.st_info) == sym::STT_FUNC
|
||||
&& addr >= sym.st_value as usize
|
||||
&& addr < (sym.st_value + sym.st_size) as usize
|
||||
{
|
||||
println!(" {:>016X}+{:>04X}", sym.st_value, addr - sym.st_value as usize);
|
||||
&& addr < (sym.st_value + sym.st_size) as usize
|
||||
{
|
||||
println!(
|
||||
" {:>016X}+{:>04X}",
|
||||
sym.st_value,
|
||||
addr - sym.st_value as usize
|
||||
);
|
||||
|
||||
if let Some(strtab) = strtab_opt {
|
||||
let start = strtab.sh_offset as usize + sym.st_name as usize;
|
||||
let mut end = start;
|
||||
while end < elf.data.len() {
|
||||
let b = elf.data[end];
|
||||
end += 1;
|
||||
if b == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if end > start {
|
||||
let sym_name = &elf.data[start .. end];
|
||||
|
||||
print!(" ");
|
||||
|
||||
if sym_name.starts_with(b"_ZN") {
|
||||
// Skip _ZN
|
||||
let mut i = 3;
|
||||
let mut first = true;
|
||||
while i < sym_name.len() {
|
||||
// E is the end character
|
||||
if sym_name[i] == b'E' {
|
||||
break;
|
||||
}
|
||||
|
||||
// Parse length string
|
||||
let mut len = 0;
|
||||
while i < sym_name.len() {
|
||||
let b = sym_name[i];
|
||||
if b >= b'0' && b <= b'9' {
|
||||
i += 1;
|
||||
len *= 10;
|
||||
len += (b - b'0') as usize;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Print namespace seperator, if required
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
print!("::");
|
||||
}
|
||||
|
||||
// Print name string
|
||||
let end = i + len;
|
||||
while i < sym_name.len() && i < end {
|
||||
print!("{}", sym_name[i] as char);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for &b in sym_name.iter() {
|
||||
print!("{}", b as char);
|
||||
}
|
||||
}
|
||||
|
||||
println!("");
|
||||
}
|
||||
if let Some(strtab) = strtab_opt {
|
||||
let start = strtab.sh_offset as usize + sym.st_name as usize;
|
||||
let mut end = start;
|
||||
while end < elf.data.len() {
|
||||
let b = elf.data[end];
|
||||
end += 1;
|
||||
if b == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if end > start {
|
||||
let sym_name = &elf.data[start..end];
|
||||
|
||||
print!(" ");
|
||||
|
||||
if sym_name.starts_with(b"_ZN") {
|
||||
// Skip _ZN
|
||||
let mut i = 3;
|
||||
let mut first = true;
|
||||
while i < sym_name.len() {
|
||||
// E is the end character
|
||||
if sym_name[i] == b'E' {
|
||||
break;
|
||||
}
|
||||
|
||||
// Parse length string
|
||||
let mut len = 0;
|
||||
while i < sym_name.len() {
|
||||
let b = sym_name[i];
|
||||
if b >= b'0' && b <= b'9' {
|
||||
i += 1;
|
||||
len *= 10;
|
||||
len += (b - b'0') as usize;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Print namespace seperator, if required
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
print!("::");
|
||||
}
|
||||
|
||||
// Print name string
|
||||
let end = i + len;
|
||||
while i < sym_name.len() && i < end {
|
||||
print!("{}", sym_name[i] as char);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for &b in sym_name.iter() {
|
||||
print!("{}", b as char);
|
||||
}
|
||||
}
|
||||
|
||||
println!("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("WTF ?");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use crate::LogicalCpuId;
|
||||
use crate::paging::{RmmA, RmmArch};
|
||||
use crate::percpu::PercpuBlock;
|
||||
use crate::{
|
||||
paging::{RmmA, RmmArch},
|
||||
percpu::PercpuBlock,
|
||||
LogicalCpuId,
|
||||
};
|
||||
|
||||
impl PercpuBlock {
|
||||
pub fn current() -> &'static Self {
|
||||
|
||||
+10
-4
@@ -46,7 +46,8 @@ pub use arch_copy_to_user as arch_copy_from_user;
|
||||
#[link_section = ".usercopy-fns"]
|
||||
pub unsafe extern "C" fn arch_copy_to_user(dst: usize, src: usize, len: usize) -> u8 {
|
||||
// x0, x1, x2
|
||||
core::arch::asm!("
|
||||
core::arch::asm!(
|
||||
"
|
||||
mov x4, x0
|
||||
mov x0, 0
|
||||
2:
|
||||
@@ -63,13 +64,18 @@ pub unsafe extern "C" fn arch_copy_to_user(dst: usize, src: usize, len: usize) -
|
||||
b 2b
|
||||
3:
|
||||
ret
|
||||
", options(noreturn));
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
pub unsafe fn bootstrap_mem(bootstrap: &crate::Bootstrap) -> &'static [u8] {
|
||||
use ::rmm::Arch;
|
||||
use crate::memory::PAGE_SIZE;
|
||||
use ::rmm::Arch;
|
||||
|
||||
core::slice::from_raw_parts(CurrentRmmArch::phys_to_virt(bootstrap.base.start_address()).data() as *const u8, bootstrap.page_count * PAGE_SIZE)
|
||||
core::slice::from_raw_parts(
|
||||
CurrentRmmArch::phys_to_virt(bootstrap.base.start_address()).data() as *const u8,
|
||||
bootstrap.page_count * PAGE_SIZE,
|
||||
)
|
||||
}
|
||||
|
||||
pub const KFX_SIZE: usize = 1024;
|
||||
|
||||
@@ -11,4 +11,3 @@ bitflags! {
|
||||
const DEV_MEM = 2 << 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,16 +4,22 @@ use super::RmmA;
|
||||
|
||||
pub use rmm::{Flusher, PageFlush, PageFlushAll};
|
||||
|
||||
pub struct InactiveFlusher { _inner: () }
|
||||
pub struct InactiveFlusher {
|
||||
_inner: (),
|
||||
}
|
||||
impl InactiveFlusher {
|
||||
// TODO: cpu id
|
||||
pub fn new() -> Self { Self { _inner: () } }
|
||||
pub fn new() -> Self {
|
||||
Self { _inner: () }
|
||||
}
|
||||
}
|
||||
|
||||
impl Flusher<RmmA> for InactiveFlusher {
|
||||
fn consume(&mut self, flush: PageFlush<RmmA>) {
|
||||
// TODO: Push to TLB "mailbox" or tell it to reload CR3 if there are too many entries.
|
||||
unsafe { flush.ignore(); }
|
||||
unsafe {
|
||||
flush.ignore();
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Drop for InactiveFlusher {
|
||||
|
||||
@@ -7,15 +7,8 @@ use crate::device::cpu::registers::{control_regs, tlb};
|
||||
|
||||
use self::mapper::PageFlushAll;
|
||||
|
||||
pub use rmm::{
|
||||
Arch as RmmArch,
|
||||
Flusher,
|
||||
PageFlags,
|
||||
PhysicalAddress,
|
||||
TableKind,
|
||||
VirtualAddress,
|
||||
};
|
||||
pub use super::CurrentRmmArch as RmmA;
|
||||
pub use rmm::{Arch as RmmArch, Flusher, PageFlags, PhysicalAddress, TableKind, VirtualAddress};
|
||||
|
||||
pub type PageMapper = rmm::PageMapper<RmmA, crate::arch::rmm::LockedAllocator>;
|
||||
pub use crate::rmm::KernelMapper;
|
||||
@@ -83,7 +76,10 @@ impl Page {
|
||||
}
|
||||
|
||||
pub fn range_inclusive(start: Page, r#final: Page) -> PageIter {
|
||||
PageIter { start, end: r#final.next() }
|
||||
PageIter {
|
||||
start,
|
||||
end: r#final.next(),
|
||||
}
|
||||
}
|
||||
pub fn range_exclusive(start: Page, end: Page) -> PageIter {
|
||||
PageIter { start, end }
|
||||
|
||||
+144
-98
@@ -1,28 +1,15 @@
|
||||
use core::{
|
||||
cmp,
|
||||
mem,
|
||||
slice,
|
||||
sync::atomic::{self, AtomicUsize, Ordering}, cell::SyncUnsafeCell,
|
||||
cell::SyncUnsafeCell,
|
||||
cmp, mem, slice,
|
||||
sync::atomic::{self, AtomicUsize, Ordering},
|
||||
};
|
||||
use rmm::{
|
||||
KILOBYTE,
|
||||
MEGABYTE,
|
||||
Arch,
|
||||
BuddyAllocator,
|
||||
BumpAllocator,
|
||||
FrameAllocator,
|
||||
FrameCount,
|
||||
FrameUsage,
|
||||
MemoryArea,
|
||||
PageFlags,
|
||||
PageMapper,
|
||||
PhysicalAddress,
|
||||
TableKind,
|
||||
VirtualAddress,
|
||||
Arch, BuddyAllocator, BumpAllocator, FrameAllocator, FrameCount, FrameUsage, MemoryArea,
|
||||
PageFlags, PageMapper, PhysicalAddress, TableKind, VirtualAddress, KILOBYTE, MEGABYTE,
|
||||
};
|
||||
use spin::Mutex;
|
||||
|
||||
use crate::{LogicalCpuId, init::device_tree::MEMORY_MAP, paging::entry::EntryFlags};
|
||||
use crate::{init::device_tree::MEMORY_MAP, paging::entry::EntryFlags, LogicalCpuId};
|
||||
|
||||
use super::CurrentRmmArch as RmmA;
|
||||
|
||||
@@ -63,11 +50,16 @@ unsafe fn page_flags<A: Arch>(virt: VirtualAddress) -> PageFlags<A> {
|
||||
|
||||
unsafe fn inner<A: Arch>(
|
||||
areas: &'static [MemoryArea],
|
||||
kernel_base: usize, kernel_size_aligned: usize,
|
||||
stack_base: usize, stack_size_aligned: usize,
|
||||
env_base: usize, env_size_aligned: usize,
|
||||
acpi_base: usize, acpi_size_aligned: usize,
|
||||
initfs_base: usize, initfs_size_aligned: usize,
|
||||
kernel_base: usize,
|
||||
kernel_size_aligned: usize,
|
||||
stack_base: usize,
|
||||
stack_size_aligned: usize,
|
||||
env_base: usize,
|
||||
env_size_aligned: usize,
|
||||
acpi_base: usize,
|
||||
acpi_size_aligned: usize,
|
||||
initfs_base: usize,
|
||||
initfs_size_aligned: usize,
|
||||
) -> BuddyAllocator<A> {
|
||||
// First, calculate how much memory we have
|
||||
let mut size = 0;
|
||||
@@ -84,10 +76,8 @@ unsafe fn inner<A: Arch>(
|
||||
let mut bump_allocator = BumpAllocator::<A>::new(areas, 0);
|
||||
|
||||
{
|
||||
let mut mapper = PageMapper::<A, _>::create(
|
||||
TableKind::Kernel,
|
||||
&mut bump_allocator
|
||||
).expect("failed to create Mapper");
|
||||
let mut mapper = PageMapper::<A, _>::create(TableKind::Kernel, &mut bump_allocator)
|
||||
.expect("failed to create Mapper");
|
||||
|
||||
// Map all physical areas at PHYS_OFFSET
|
||||
for area in areas.iter() {
|
||||
@@ -95,11 +85,9 @@ unsafe fn inner<A: Arch>(
|
||||
let phys = area.base.add(i * A::PAGE_SIZE);
|
||||
let virt = A::phys_to_virt(phys);
|
||||
let flags = page_flags::<A>(virt);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
}
|
||||
@@ -109,19 +97,15 @@ unsafe fn inner<A: Arch>(
|
||||
let phys = PhysicalAddress::new(kernel_base + i * A::PAGE_SIZE);
|
||||
let virt = VirtualAddress::new(crate::KERNEL_OFFSET + i * A::PAGE_SIZE);
|
||||
let flags = page_flags::<A>(virt);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
|
||||
let virt = A::phys_to_virt(phys);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
|
||||
@@ -131,11 +115,9 @@ unsafe fn inner<A: Arch>(
|
||||
let phys = PhysicalAddress::new(base + i * A::PAGE_SIZE);
|
||||
let virt = A::phys_to_virt(phys);
|
||||
let flags = page_flags::<A>(virt);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
};
|
||||
@@ -163,7 +145,8 @@ unsafe fn inner<A: Arch>(
|
||||
//map dev mem
|
||||
for mem in MEMORY_MAP {
|
||||
if mem._type == 2 {
|
||||
let size_aligned = ((mem.length as usize + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let size_aligned =
|
||||
((mem.length as usize + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let base = mem.base_addr as usize;
|
||||
for i in 0..size_aligned / A::PAGE_SIZE {
|
||||
let phys = PhysicalAddress::new(base + i * A::PAGE_SIZE);
|
||||
@@ -171,13 +154,10 @@ unsafe fn inner<A: Arch>(
|
||||
// use the same mair_el1 value with bootloader,
|
||||
// mair_el1 == 0x00000000000044FF
|
||||
// set mem_attr == device memory
|
||||
let flags = page_flags::<A>(virt)
|
||||
.custom_flag(EntryFlags::DEV_MEM.bits(), true);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flags = page_flags::<A>(virt).custom_flag(EntryFlags::DEV_MEM.bits(), true);
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
}
|
||||
@@ -195,12 +175,10 @@ unsafe fn inner<A: Arch>(
|
||||
let phys = PhysicalAddress::new(phys + i * A::PAGE_SIZE);
|
||||
let virt = VirtualAddress::new(virt + i * A::PAGE_SIZE);
|
||||
let flags = PageFlags::new().write(true);
|
||||
//TODO: Write combining flag
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
//TODO: Write combining flag
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
}
|
||||
@@ -220,7 +198,10 @@ unsafe fn inner<A: Arch>(
|
||||
|
||||
// Create the physical memory map
|
||||
let offset = bump_allocator.offset();
|
||||
log::info!("Permanently used: {} KB", (offset + (KILOBYTE - 1)) / KILOBYTE);
|
||||
log::info!(
|
||||
"Permanently used: {} KB",
|
||||
(offset + (KILOBYTE - 1)) / KILOBYTE
|
||||
);
|
||||
|
||||
BuddyAllocator::<A>::new(bump_allocator).expect("failed to create BuddyAllocator")
|
||||
}
|
||||
@@ -264,10 +245,12 @@ impl core::fmt::Debug for LockedAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
static AREAS: SyncUnsafeCell<[MemoryArea; 512]> = SyncUnsafeCell::new([MemoryArea {
|
||||
base: PhysicalAddress::new(0),
|
||||
size: 0,
|
||||
}; 512]);
|
||||
static AREAS: SyncUnsafeCell<[MemoryArea; 512]> = SyncUnsafeCell::new(
|
||||
[MemoryArea {
|
||||
base: PhysicalAddress::new(0),
|
||||
size: 0,
|
||||
}; 512],
|
||||
);
|
||||
static AREA_COUNT: SyncUnsafeCell<u16> = SyncUnsafeCell::new(0);
|
||||
|
||||
// TODO: Share code
|
||||
@@ -300,7 +283,12 @@ pub struct KernelMapper {
|
||||
impl KernelMapper {
|
||||
fn lock_inner(current_processor: usize) -> bool {
|
||||
loop {
|
||||
match LOCK_OWNER.compare_exchange_weak(NO_PROCESSOR, current_processor, Ordering::Acquire, Ordering::Relaxed) {
|
||||
match LOCK_OWNER.compare_exchange_weak(
|
||||
NO_PROCESSOR,
|
||||
current_processor,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => break,
|
||||
// already owned by this hardware thread
|
||||
Err(id) if id == current_processor => break,
|
||||
@@ -314,15 +302,20 @@ impl KernelMapper {
|
||||
|
||||
prev_count > 0
|
||||
}
|
||||
pub unsafe fn lock_for_manual_mapper(current_processor: LogicalCpuId, mapper: crate::paging::PageMapper) -> Self {
|
||||
pub unsafe fn lock_for_manual_mapper(
|
||||
current_processor: LogicalCpuId,
|
||||
mapper: crate::paging::PageMapper,
|
||||
) -> Self {
|
||||
let ro = Self::lock_inner(current_processor.get() as usize);
|
||||
Self {
|
||||
mapper,
|
||||
ro,
|
||||
}
|
||||
Self { mapper, ro }
|
||||
}
|
||||
pub fn lock_manually(current_processor: LogicalCpuId) -> Self {
|
||||
unsafe { Self::lock_for_manual_mapper(current_processor, PageMapper::current(TableKind::Kernel, FRAME_ALLOCATOR)) }
|
||||
unsafe {
|
||||
Self::lock_for_manual_mapper(
|
||||
current_processor,
|
||||
PageMapper::current(TableKind::Kernel, FRAME_ALLOCATOR),
|
||||
)
|
||||
}
|
||||
}
|
||||
pub fn lock() -> Self {
|
||||
Self::lock_manually(crate::cpu_id())
|
||||
@@ -357,12 +350,18 @@ impl Drop for KernelMapper {
|
||||
}
|
||||
|
||||
pub unsafe fn init(
|
||||
kernel_base: usize, kernel_size: usize,
|
||||
stack_base: usize, stack_size: usize,
|
||||
env_base: usize, env_size: usize,
|
||||
acpi_base: usize, acpi_size: usize,
|
||||
areas_base: usize, areas_size: usize,
|
||||
initfs_base: usize, initfs_size: usize,
|
||||
kernel_base: usize,
|
||||
kernel_size: usize,
|
||||
stack_base: usize,
|
||||
stack_size: usize,
|
||||
env_base: usize,
|
||||
env_size: usize,
|
||||
acpi_base: usize,
|
||||
acpi_size: usize,
|
||||
areas_base: usize,
|
||||
areas_size: usize,
|
||||
initfs_base: usize,
|
||||
initfs_size: usize,
|
||||
) {
|
||||
type A = RmmA;
|
||||
|
||||
@@ -370,24 +369,24 @@ pub unsafe fn init(
|
||||
let real_size = 0x100000;
|
||||
let real_end = real_base + real_size;
|
||||
|
||||
let kernel_size_aligned = ((kernel_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let kernel_size_aligned = ((kernel_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let kernel_end = kernel_base + kernel_size_aligned;
|
||||
|
||||
let stack_size_aligned = ((stack_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let stack_size_aligned = ((stack_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let stack_end = stack_base + stack_size_aligned;
|
||||
|
||||
let env_size_aligned = ((env_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let env_size_aligned = ((env_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let env_end = env_base + env_size_aligned;
|
||||
|
||||
let acpi_size_aligned = ((acpi_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let acpi_size_aligned = ((acpi_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let acpi_end = acpi_base + acpi_size_aligned;
|
||||
|
||||
let initfs_size_aligned = ((initfs_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let initfs_size_aligned = ((initfs_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let initfs_end = initfs_base + initfs_size_aligned;
|
||||
|
||||
let bootloader_areas = slice::from_raw_parts(
|
||||
areas_base as *const BootloaderMemoryEntry,
|
||||
areas_size / mem::size_of::<BootloaderMemoryEntry>()
|
||||
areas_size / mem::size_of::<BootloaderMemoryEntry>(),
|
||||
);
|
||||
|
||||
let areas = &mut *AREAS.get();
|
||||
@@ -422,42 +421,84 @@ pub unsafe fn init(
|
||||
|
||||
// Ensure real-mode areas are not used
|
||||
if base < real_end && base + size > real_base {
|
||||
log::warn!("{:X}:{:X} overlaps with real mode {:X}:{:X}", base, size, real_base, real_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with real mode {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
real_base,
|
||||
real_size
|
||||
);
|
||||
new_base = cmp::max(new_base, real_end);
|
||||
}
|
||||
|
||||
// Ensure kernel areas are not used
|
||||
if base < kernel_end && base + size > kernel_base {
|
||||
log::warn!("{:X}:{:X} overlaps with kernel {:X}:{:X}", base, size, kernel_base, kernel_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with kernel {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
kernel_base,
|
||||
kernel_size
|
||||
);
|
||||
new_base = cmp::max(new_base, kernel_end);
|
||||
}
|
||||
|
||||
// Ensure stack areas are not used
|
||||
if base < stack_end && base + size > stack_base {
|
||||
log::warn!("{:X}:{:X} overlaps with stack {:X}:{:X}", base, size, stack_base, stack_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with stack {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
stack_base,
|
||||
stack_size
|
||||
);
|
||||
new_base = cmp::max(new_base, stack_end);
|
||||
}
|
||||
|
||||
// Ensure env areas are not used
|
||||
if base < env_end && base + size > env_base {
|
||||
log::warn!("{:X}:{:X} overlaps with env {:X}:{:X}", base, size, env_base, env_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with env {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
env_base,
|
||||
env_size
|
||||
);
|
||||
new_base = cmp::max(new_base, env_end);
|
||||
}
|
||||
|
||||
// Ensure acpi areas are not used
|
||||
if base < acpi_end && base + size > acpi_base {
|
||||
log::warn!("{:X}:{:X} overlaps with acpi {:X}:{:X}", base, size, acpi_base, acpi_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with acpi {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
acpi_base,
|
||||
acpi_size
|
||||
);
|
||||
new_base = cmp::max(new_base, acpi_end);
|
||||
}
|
||||
if base < initfs_end && base + size > initfs_base {
|
||||
log::warn!("{:X}:{:X} overlaps with initfs {:X}:{:X}", base, size, initfs_base, initfs_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with initfs {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
initfs_base,
|
||||
initfs_size
|
||||
);
|
||||
new_base = cmp::max(new_base, initfs_end);
|
||||
}
|
||||
|
||||
if new_base != base {
|
||||
let end = base + size;
|
||||
let new_size = end.checked_sub(new_base).unwrap_or(0);
|
||||
log::info!("{:X}:{:X} moved to {:X}:{:X}", base, size, new_base, new_size);
|
||||
log::info!(
|
||||
"{:X}:{:X} moved to {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
new_base,
|
||||
new_size
|
||||
);
|
||||
base = new_base;
|
||||
size = new_size;
|
||||
}
|
||||
@@ -475,11 +516,16 @@ pub unsafe fn init(
|
||||
|
||||
let allocator = inner::<A>(
|
||||
areas,
|
||||
kernel_base, kernel_size_aligned,
|
||||
stack_base, stack_size_aligned,
|
||||
env_base, env_size_aligned,
|
||||
acpi_base, acpi_size_aligned,
|
||||
initfs_base, initfs_size_aligned,
|
||||
kernel_base,
|
||||
kernel_size_aligned,
|
||||
stack_base,
|
||||
stack_size_aligned,
|
||||
env_base,
|
||||
env_size_aligned,
|
||||
acpi_base,
|
||||
acpi_size_aligned,
|
||||
initfs_base,
|
||||
initfs_size_aligned,
|
||||
);
|
||||
*INNER_ALLOCATOR.lock() = Some(allocator);
|
||||
}
|
||||
|
||||
+66
-29
@@ -2,21 +2,23 @@
|
||||
/// It is increcibly unsafe, and should be minimal in nature
|
||||
/// It must create the IDT with the correct entries, those entries are
|
||||
/// defined in other files inside of the `arch` module
|
||||
|
||||
use core::slice;
|
||||
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering, AtomicU32};
|
||||
use core::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering};
|
||||
|
||||
use crate::memory::{Frame};
|
||||
use crate::paging::{Page, PAGE_SIZE, PhysicalAddress, VirtualAddress};
|
||||
use crate::{
|
||||
memory::Frame,
|
||||
paging::{Page, PhysicalAddress, VirtualAddress, PAGE_SIZE},
|
||||
};
|
||||
|
||||
use crate::{allocator, dtb};
|
||||
use crate::device;
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
use crate::devices::graphical_debug;
|
||||
use crate::init::device_tree;
|
||||
use crate::interrupt;
|
||||
use crate::log::{self, info};
|
||||
use crate::paging::{self, KernelMapper};
|
||||
use crate::{
|
||||
allocator, device, dtb,
|
||||
init::device_tree,
|
||||
interrupt,
|
||||
log::{self, info},
|
||||
paging::{self, KernelMapper},
|
||||
};
|
||||
|
||||
/// Test of zero values in BSS.
|
||||
static BSS_TEST_ZERO: usize = 0;
|
||||
@@ -71,7 +73,10 @@ pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
}
|
||||
|
||||
// Convert env to slice
|
||||
let env = slice::from_raw_parts((crate::PHYS_OFFSET + args.env_base) as *const u8, args.env_size);
|
||||
let env = slice::from_raw_parts(
|
||||
(crate::PHYS_OFFSET + args.env_base) as *const u8,
|
||||
args.env_size,
|
||||
);
|
||||
|
||||
// Set up graphical debug
|
||||
//#[cfg(feature = "graphical_debug")]
|
||||
@@ -90,13 +95,37 @@ pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
});
|
||||
|
||||
info!("Redox OS starting...");
|
||||
info!("Kernel: {:X}:{:X}", {args.kernel_base}, args.kernel_base + args.kernel_size);
|
||||
info!("Stack: {:X}:{:X}", {args.stack_base}, args.stack_base + args.stack_size);
|
||||
info!("Env: {:X}:{:X}", {args.env_base}, args.env_base + args.env_size);
|
||||
info!("RSDPs: {:X}:{:X}", {args.dtb_base}, args.dtb_base + args.dtb_size);
|
||||
info!("Areas: {:X}:{:X}", {args.areas_base}, args.areas_base + args.areas_size);
|
||||
info!("Bootstrap: {:X}:{:X}", {args.bootstrap_base}, args.bootstrap_base + args.bootstrap_size);
|
||||
info!("Bootstrap entry point: {:X}", {args.bootstrap_entry});
|
||||
info!(
|
||||
"Kernel: {:X}:{:X}",
|
||||
{ args.kernel_base },
|
||||
args.kernel_base + args.kernel_size
|
||||
);
|
||||
info!(
|
||||
"Stack: {:X}:{:X}",
|
||||
{ args.stack_base },
|
||||
args.stack_base + args.stack_size
|
||||
);
|
||||
info!(
|
||||
"Env: {:X}:{:X}",
|
||||
{ args.env_base },
|
||||
args.env_base + args.env_size
|
||||
);
|
||||
info!(
|
||||
"RSDPs: {:X}:{:X}",
|
||||
{ args.dtb_base },
|
||||
args.dtb_base + args.dtb_size
|
||||
);
|
||||
info!(
|
||||
"Areas: {:X}:{:X}",
|
||||
{ args.areas_base },
|
||||
args.areas_base + args.areas_size
|
||||
);
|
||||
info!(
|
||||
"Bootstrap: {:X}:{:X}",
|
||||
{ args.bootstrap_base },
|
||||
args.bootstrap_base + args.bootstrap_size
|
||||
);
|
||||
info!("Bootstrap entry point: {:X}", { args.bootstrap_entry });
|
||||
|
||||
// Setup interrupt handlers
|
||||
core::arch::asm!(
|
||||
@@ -108,8 +137,8 @@ pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
);
|
||||
|
||||
if args.dtb_base != 0 {
|
||||
//Try to read device memory map
|
||||
device_tree::fill_memory_map(crate::PHYS_OFFSET + args.dtb_base, args.dtb_size);
|
||||
//Try to read device memory map
|
||||
device_tree::fill_memory_map(crate::PHYS_OFFSET + args.dtb_base, args.dtb_size);
|
||||
}
|
||||
|
||||
/* NOT USED WITH UEFI
|
||||
@@ -118,12 +147,18 @@ pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
|
||||
// Initialize RMM
|
||||
crate::arch::rmm::init(
|
||||
args.kernel_base, args.kernel_size,
|
||||
args.stack_base, args.stack_size,
|
||||
args.env_base, args.env_size,
|
||||
args.dtb_base, args.dtb_size,
|
||||
args.areas_base, args.areas_size,
|
||||
args.bootstrap_base, args.bootstrap_size,
|
||||
args.kernel_base,
|
||||
args.kernel_size,
|
||||
args.stack_base,
|
||||
args.stack_size,
|
||||
args.env_base,
|
||||
args.env_size,
|
||||
args.dtb_base,
|
||||
args.dtb_size,
|
||||
args.areas_base,
|
||||
args.areas_size,
|
||||
args.bootstrap_base,
|
||||
args.bootstrap_size,
|
||||
);
|
||||
|
||||
// Initialize paging
|
||||
@@ -163,7 +198,9 @@ pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
BSP_READY.store(true, Ordering::SeqCst);
|
||||
|
||||
crate::Bootstrap {
|
||||
base: crate::memory::Frame::containing_address(crate::paging::PhysicalAddress::new(args.bootstrap_base)),
|
||||
base: crate::memory::Frame::containing_address(crate::paging::PhysicalAddress::new(
|
||||
args.bootstrap_base,
|
||||
)),
|
||||
page_count: args.bootstrap_size / crate::memory::PAGE_SIZE,
|
||||
entry: args.bootstrap_entry,
|
||||
env,
|
||||
@@ -182,8 +219,8 @@ pub struct KernelArgsAp {
|
||||
}
|
||||
|
||||
/// Entry to rust for an AP
|
||||
pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
|
||||
loop{}
|
||||
pub unsafe extern "C" fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[naked]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use core::arch::asm;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn kreset() -> ! {
|
||||
pub unsafe extern "C" fn kreset() -> ! {
|
||||
println!("kreset");
|
||||
|
||||
let val: u32 = 0x8400_0009;
|
||||
@@ -16,7 +16,7 @@ pub unsafe fn emergency_reset() -> ! {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn kstop() -> ! {
|
||||
pub unsafe extern "C" fn kstop() -> ! {
|
||||
println!("kstop");
|
||||
|
||||
let val: u32 = 0x8400_0008;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
core::arch::global_asm!(
|
||||
"
|
||||
"
|
||||
// Exception vector stubs
|
||||
//
|
||||
// Unhandled exceptions spin in a wfi loop for the moment
|
||||
@@ -108,4 +108,5 @@ __vec_15:
|
||||
|
||||
.align 7
|
||||
exception_vector_end:
|
||||
");
|
||||
"
|
||||
);
|
||||
|
||||
+21
-21
@@ -3,30 +3,30 @@
|
||||
// Each PML4 entry references up to 512 GB of memory
|
||||
// The second from the top (510) PML4 is reserved for the kernel
|
||||
|
||||
/// Offset of kernel (256 MiB max)
|
||||
pub const KERNEL_OFFSET: usize = 0xC000_0000;
|
||||
/// Offset of kernel (256 MiB max)
|
||||
pub const KERNEL_OFFSET: usize = 0xC000_0000;
|
||||
|
||||
// Framebuffer mapped by bootloader to 0xD000_0000 (128 MiB max)
|
||||
// Framebuffer mapped by bootloader to 0xD000_0000 (128 MiB max)
|
||||
|
||||
// Offset to APIC mappings (optional)
|
||||
pub const LAPIC_OFFSET: usize = 0xD800_0000;
|
||||
pub const IOAPIC_OFFSET: usize = LAPIC_OFFSET + 4096;
|
||||
pub const HPET_OFFSET: usize = IOAPIC_OFFSET + 4096;
|
||||
// Offset to APIC mappings (optional)
|
||||
pub const LAPIC_OFFSET: usize = 0xD800_0000;
|
||||
pub const IOAPIC_OFFSET: usize = LAPIC_OFFSET + 4096;
|
||||
pub const HPET_OFFSET: usize = IOAPIC_OFFSET + 4096;
|
||||
|
||||
/// Offset to kernel heap (256 MiB max)
|
||||
pub const KERNEL_HEAP_OFFSET: usize = 0xE000_0000;
|
||||
/// Size of kernel heap
|
||||
pub const KERNEL_HEAP_SIZE: usize = rmm::MEGABYTE;
|
||||
/// Offset to kernel heap (256 MiB max)
|
||||
pub const KERNEL_HEAP_OFFSET: usize = 0xE000_0000;
|
||||
/// Size of kernel heap
|
||||
pub const KERNEL_HEAP_SIZE: usize = rmm::MEGABYTE;
|
||||
|
||||
/// Offset to kernel percpu variables (256 MiB max)
|
||||
pub const KERNEL_PERCPU_OFFSET: usize = 0xF000_0000;
|
||||
/// Size of kernel percpu variables
|
||||
pub const KERNEL_PERCPU_SHIFT: u8 = 16; // 2^16 = 64 KiB
|
||||
pub const KERNEL_PERCPU_SIZE: usize = 1_usize << KERNEL_PERCPU_SHIFT;
|
||||
/// Offset to kernel percpu variables (256 MiB max)
|
||||
pub const KERNEL_PERCPU_OFFSET: usize = 0xF000_0000;
|
||||
/// Size of kernel percpu variables
|
||||
pub const KERNEL_PERCPU_SHIFT: u8 = 16; // 2^16 = 64 KiB
|
||||
pub const KERNEL_PERCPU_SIZE: usize = 1_usize << KERNEL_PERCPU_SHIFT;
|
||||
|
||||
/// Offset of physmap (1 GiB max)
|
||||
// This needs to match RMM's PHYS_OFFSET
|
||||
pub const PHYS_OFFSET: usize = 0x8000_0000;
|
||||
/// Offset of physmap (1 GiB max)
|
||||
// This needs to match RMM's PHYS_OFFSET
|
||||
pub const PHYS_OFFSET: usize = 0x8000_0000;
|
||||
|
||||
/// End offset of the user image, i.e. kernel start
|
||||
pub const USER_END_OFFSET: usize = 0x8000_0000;
|
||||
/// End offset of the user image, i.e. kernel start
|
||||
pub const USER_END_OFFSET: usize = 0x8000_0000;
|
||||
|
||||
+12
-12
@@ -3,24 +3,24 @@ use core::fmt;
|
||||
use spin::Mutex;
|
||||
use spin::MutexGuard;
|
||||
|
||||
use crate::log::{LOG, Log};
|
||||
#[cfg(feature = "qemu_debug")]
|
||||
use syscall::io::Io;
|
||||
#[cfg(any(feature = "qemu_debug", feature = "serial_debug"))]
|
||||
use crate::syscall::io::Pio;
|
||||
#[cfg(feature = "lpss_debug")]
|
||||
use crate::syscall::io::Mmio;
|
||||
#[cfg(any(feature = "lpss_debug", feature = "serial_debug"))]
|
||||
use crate::devices::uart_16550::SerialPort;
|
||||
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
use crate::devices::graphical_debug::{DEBUG_DISPLAY, DebugDisplay};
|
||||
use crate::log::{Log, LOG};
|
||||
#[cfg(feature = "lpss_debug")]
|
||||
use super::device::serial::LPSS;
|
||||
use crate::syscall::io::Mmio;
|
||||
#[cfg(any(feature = "qemu_debug", feature = "serial_debug"))]
|
||||
use crate::syscall::io::Pio;
|
||||
#[cfg(feature = "qemu_debug")]
|
||||
use syscall::io::Io;
|
||||
|
||||
#[cfg(feature = "serial_debug")]
|
||||
use super::device::serial::COM1;
|
||||
#[cfg(feature = "lpss_debug")]
|
||||
use super::device::serial::LPSS;
|
||||
#[cfg(feature = "system76_ec_debug")]
|
||||
use super::device::system76_ec::{SYSTEM76_EC, System76Ec};
|
||||
use super::device::system76_ec::{System76Ec, SYSTEM76_EC};
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
use crate::devices::graphical_debug::{DebugDisplay, DEBUG_DISPLAY};
|
||||
|
||||
#[cfg(feature = "qemu_debug")]
|
||||
pub static QEMU: Mutex<Pio<u8>> = Mutex::new(Pio::<u8>::new(0x402));
|
||||
|
||||
+234
-78
@@ -28,101 +28,257 @@ pub fn cpu_info<W: Write>(w: &mut W) -> Result {
|
||||
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_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_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_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_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_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_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_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 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_processor_and_feature_identifiers() {
|
||||
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_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 let Some(info) = cpuid.get_advanced_power_mgmt_info() {
|
||||
if info.has_invariant_tsc() { write!(w, " constant_tsc")? };
|
||||
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_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")? };
|
||||
if info.has_fpu_cs_ds_deprecated() {
|
||||
write!(w, " fpu_seg")?
|
||||
};
|
||||
if info.has_mpx() {
|
||||
write!(w, " mpx")?
|
||||
};
|
||||
}
|
||||
|
||||
writeln!(w)?;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::acpi::hpet::Hpet;
|
||||
use super::pit;
|
||||
use crate::acpi::hpet::Hpet;
|
||||
|
||||
const LEG_RT_CNF: u64 = 2;
|
||||
const ENABLE_CNF: u64 = 1;
|
||||
@@ -27,7 +27,8 @@ pub unsafe fn init(hpet: &mut Hpet) -> bool {
|
||||
{
|
||||
let mut config_word = hpet.base_address.read_u64(GENERAL_CONFIG_OFFSET);
|
||||
config_word &= !(LEG_RT_CNF | ENABLE_CNF);
|
||||
hpet.base_address.write_u64(GENERAL_CONFIG_OFFSET, config_word);
|
||||
hpet.base_address
|
||||
.write_u64(GENERAL_CONFIG_OFFSET, config_word);
|
||||
}
|
||||
|
||||
let capability = hpet.base_address.read_u64(CAPABILITY_OFFSET);
|
||||
@@ -48,9 +49,11 @@ pub unsafe fn init(hpet: &mut Hpet) -> bool {
|
||||
let counter = hpet.base_address.read_u64(MAIN_COUNTER_OFFSET);
|
||||
|
||||
let t0_config_word: u64 = TN_VAL_SET_CNF | TN_TYPE_CNF | TN_INT_ENB_CNF;
|
||||
hpet.base_address.write_u64(T0_CONFIG_CAPABILITY_OFFSET, t0_config_word);
|
||||
hpet.base_address
|
||||
.write_u64(T0_CONFIG_CAPABILITY_OFFSET, t0_config_word);
|
||||
// set accumulator value
|
||||
hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, counter + divisor);
|
||||
hpet.base_address
|
||||
.write_u64(T0_COMPARATOR_OFFSET, counter + divisor);
|
||||
// set interval
|
||||
hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, divisor);
|
||||
|
||||
@@ -58,7 +61,8 @@ pub unsafe fn init(hpet: &mut Hpet) -> bool {
|
||||
{
|
||||
let mut config_word: u64 = hpet.base_address.read_u64(GENERAL_CONFIG_OFFSET);
|
||||
config_word |= LEG_RT_CNF | ENABLE_CNF;
|
||||
hpet.base_address.write_u64(GENERAL_CONFIG_OFFSET, config_word);
|
||||
hpet.base_address
|
||||
.write_u64(GENERAL_CONFIG_OFFSET, config_word);
|
||||
}
|
||||
|
||||
println!("HPET After Init");
|
||||
@@ -76,7 +80,10 @@ pub unsafe fn debug(hpet: &mut Hpet) {
|
||||
println!(" clock period: {}", (capability >> 32) as u32);
|
||||
println!(" ID: {:#x}", (capability >> 16) as u16);
|
||||
println!(" LEG_RT_CAP: {}", capability & (1 << 15) == (1 << 15));
|
||||
println!(" COUNT_SIZE_CAP: {}", capability & (1 << 13) == (1 << 13));
|
||||
println!(
|
||||
" COUNT_SIZE_CAP: {}",
|
||||
capability & (1 << 13) == (1 << 13)
|
||||
);
|
||||
println!(" timers: {}", (capability >> 8) as u8 & 0x1F);
|
||||
println!(" revision: {}", capability as u8);
|
||||
}
|
||||
@@ -92,7 +99,10 @@ pub unsafe fn debug(hpet: &mut Hpet) {
|
||||
|
||||
let t0_capabilities = hpet.base_address.read_u64(T0_CONFIG_CAPABILITY_OFFSET);
|
||||
println!(" T0 caps: {:#x}", t0_capabilities);
|
||||
println!(" interrupt routing: {:#x}", (t0_capabilities >> 32) as u32);
|
||||
println!(
|
||||
" interrupt routing: {:#x}",
|
||||
(t0_capabilities >> 32) as u32
|
||||
);
|
||||
println!(" flags: {:#x}", t0_capabilities as u16);
|
||||
|
||||
let t0_comparator = hpet.base_address.read_u64(T0_COMPARATOR_OFFSET);
|
||||
|
||||
@@ -4,15 +4,18 @@ use alloc::vec::Vec;
|
||||
use spin::Mutex;
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
use crate::acpi::madt::{self, Madt, MadtEntry, MadtIoApic, MadtIntSrcOverride};
|
||||
use crate::acpi::madt::{self, Madt, MadtEntry, MadtIntSrcOverride, MadtIoApic};
|
||||
|
||||
use crate::arch::interrupt::irq;
|
||||
use crate::memory::Frame;
|
||||
use crate::paging::{KernelMapper, Page, PageFlags, PhysicalAddress, RmmA, RmmArch, VirtualAddress};
|
||||
use crate::paging::entry::EntryFlags;
|
||||
use crate::{
|
||||
arch::interrupt::irq,
|
||||
memory::Frame,
|
||||
paging::{
|
||||
entry::EntryFlags, KernelMapper, Page, PageFlags, PhysicalAddress, RmmA, RmmArch,
|
||||
VirtualAddress,
|
||||
},
|
||||
};
|
||||
|
||||
use super::super::cpuid::cpuid;
|
||||
use super::pic;
|
||||
use super::{super::cpuid::cpuid, pic};
|
||||
|
||||
pub struct IoApicRegs {
|
||||
pointer: *const u32,
|
||||
@@ -131,12 +134,12 @@ pub enum DestinationMode {
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum DeliveryMode {
|
||||
Fixed = 0b000,
|
||||
LowestPriority = 0b001,
|
||||
Smi = 0b010,
|
||||
Nmi = 0b100,
|
||||
Init = 0b101,
|
||||
ExtInt = 0b111,
|
||||
Fixed = 0b000,
|
||||
LowestPriority = 0b001,
|
||||
Smi = 0b010,
|
||||
Nmi = 0b100,
|
||||
Init = 0b101,
|
||||
ExtInt = 0b111,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@@ -176,7 +179,9 @@ impl fmt::Debug for IoApic {
|
||||
let mut guard = self.0.lock();
|
||||
|
||||
let count = guard.max_redirection_table_entries();
|
||||
f.debug_list().entries((0..count).map(|i| guard.read_ioredtbl(i))).finish()
|
||||
f.debug_list()
|
||||
.entries((0..count).map(|i| guard.read_ioredtbl(i)))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,14 +224,10 @@ static mut IOAPICS: Option<Vec<IoApic>> = None;
|
||||
static mut SRC_OVERRIDES: Option<Vec<Override>> = None;
|
||||
|
||||
pub fn ioapics() -> &'static [IoApic] {
|
||||
unsafe {
|
||||
IOAPICS.as_ref().map_or(&[], |vector| &vector[..])
|
||||
}
|
||||
unsafe { IOAPICS.as_ref().map_or(&[], |vector| &vector[..]) }
|
||||
}
|
||||
pub fn src_overrides() -> &'static [Override] {
|
||||
unsafe {
|
||||
SRC_OVERRIDES.as_ref().map_or(&[], |vector| &vector[..])
|
||||
}
|
||||
unsafe { SRC_OVERRIDES.as_ref().map_or(&[], |vector| &vector[..]) }
|
||||
}
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
@@ -241,14 +242,24 @@ pub unsafe fn handle_ioapic(mapper: &mut KernelMapper, madt_ioapic: &'static Mad
|
||||
mapper
|
||||
.get_mut()
|
||||
.expect("expected KernelMapper not to be locked re-entrant while mapping I/O APIC memory")
|
||||
.map_phys(page.start_address(), frame.start_address(), PageFlags::new().write(true).custom_flag(EntryFlags::NO_CACHE.bits(), true))
|
||||
.map_phys(
|
||||
page.start_address(),
|
||||
frame.start_address(),
|
||||
PageFlags::new()
|
||||
.write(true)
|
||||
.custom_flag(EntryFlags::NO_CACHE.bits(), true),
|
||||
)
|
||||
.expect("failed to map I/O APIC")
|
||||
.flush();
|
||||
|
||||
let ioapic_registers = page.start_address().data() as *const u32;
|
||||
let ioapic = IoApic::new(ioapic_registers, madt_ioapic.gsi_base);
|
||||
|
||||
assert_eq!(ioapic.regs.lock().id(), madt_ioapic.id, "mismatched ACPI MADT I/O APIC ID, and the ID reported by the I/O APIC");
|
||||
assert_eq!(
|
||||
ioapic.regs.lock().id(),
|
||||
madt_ioapic.id,
|
||||
"mismatched ACPI MADT I/O APIC ID, and the ID reported by the I/O APIC"
|
||||
);
|
||||
|
||||
IOAPICS.get_or_insert_with(Vec::new).push(ioapic);
|
||||
}
|
||||
@@ -286,7 +297,11 @@ pub unsafe fn handle_src_override(src_override: &'static MadtIntSrcOverride) {
|
||||
}
|
||||
|
||||
pub unsafe fn init(active_table: &mut KernelMapper) {
|
||||
let bsp_apic_id = cpuid().unwrap().get_feature_info().unwrap().initial_local_apic_id(); // TODO: remove unwraps
|
||||
let bsp_apic_id = cpuid()
|
||||
.unwrap()
|
||||
.get_feature_info()
|
||||
.unwrap()
|
||||
.initial_local_apic_id(); // TODO: remove unwraps
|
||||
|
||||
// search the madt for all IOAPICs.
|
||||
#[cfg(feature = "acpi")]
|
||||
@@ -310,7 +325,11 @@ pub unsafe fn init(active_table: &mut KernelMapper) {
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("I/O APICs: {:?}, overrides: {:?}", ioapics(), src_overrides());
|
||||
println!(
|
||||
"I/O APICs: {:?}, overrides: {:?}",
|
||||
ioapics(),
|
||||
src_overrides()
|
||||
);
|
||||
|
||||
// map the legacy PC-compatible IRQs (0-15) to 32-47, just like we did with 8259 PIC (if it
|
||||
// wouldn't have been disabled due to this I/O APIC)
|
||||
@@ -318,11 +337,21 @@ pub unsafe fn init(active_table: &mut KernelMapper) {
|
||||
let (gsi, trigger_mode, polarity) = match get_override(legacy_irq) {
|
||||
Some(over) => (over.gsi, over.trigger_mode, over.polarity),
|
||||
None => {
|
||||
if src_overrides().iter().any(|over| over.gsi == u32::from(legacy_irq) && over.bus_irq != legacy_irq) && !src_overrides().iter().any(|over| over.bus_irq == legacy_irq) {
|
||||
if src_overrides()
|
||||
.iter()
|
||||
.any(|over| over.gsi == u32::from(legacy_irq) && over.bus_irq != legacy_irq)
|
||||
&& !src_overrides()
|
||||
.iter()
|
||||
.any(|over| over.bus_irq == legacy_irq)
|
||||
{
|
||||
// there's an IRQ conflict, making this legacy IRQ inaccessible.
|
||||
continue;
|
||||
}
|
||||
(legacy_irq.into(), TriggerMode::ConformsToSpecs, Polarity::ConformsToSpecs)
|
||||
(
|
||||
legacy_irq.into(),
|
||||
TriggerMode::ConformsToSpecs,
|
||||
Polarity::ConformsToSpecs,
|
||||
)
|
||||
}
|
||||
};
|
||||
let apic = match find_ioapic(gsi) {
|
||||
@@ -354,7 +383,11 @@ pub unsafe fn init(active_table: &mut KernelMapper) {
|
||||
};
|
||||
apic.map(redir_tbl_index, map_info);
|
||||
}
|
||||
println!("I/O APICs: {:?}, overrides: {:?}", ioapics(), src_overrides());
|
||||
println!(
|
||||
"I/O APICs: {:?}, overrides: {:?}",
|
||||
ioapics(),
|
||||
src_overrides()
|
||||
);
|
||||
irq::set_irq_method(irq::IrqMethod::Apic);
|
||||
|
||||
// tell the firmware that we're using APIC rather than the default 8259 PIC.
|
||||
@@ -385,7 +418,9 @@ fn resolve(irq: u8) -> u32 {
|
||||
get_override(irq).map_or(u32::from(irq), |over| over.gsi)
|
||||
}
|
||||
fn find_ioapic(gsi: u32) -> Option<&'static IoApic> {
|
||||
ioapics().iter().find(|apic| gsi >= apic.gsi_start && gsi < apic.gsi_start + u32::from(apic.count))
|
||||
ioapics()
|
||||
.iter()
|
||||
.find(|apic| gsi >= apic.gsi_start && gsi < apic.gsi_start + u32::from(apic.count))
|
||||
}
|
||||
|
||||
pub unsafe fn mask(irq: u8) {
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
use core::sync::atomic::{self, AtomicU32};
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
use core::{
|
||||
ptr::{read_volatile, write_volatile},
|
||||
sync::atomic::{self, AtomicU32},
|
||||
};
|
||||
use x86::msr::*;
|
||||
|
||||
use crate::paging::{KernelMapper, PhysicalAddress, PageFlags, RmmA, RmmArch, VirtualAddress};
|
||||
use crate::paging::{KernelMapper, PageFlags, PhysicalAddress, RmmA, RmmArch, VirtualAddress};
|
||||
|
||||
use super::super::cpuid::cpuid;
|
||||
|
||||
pub static mut LOCAL_APIC: LocalApic = LocalApic {
|
||||
address: 0,
|
||||
x2: false
|
||||
x2: false,
|
||||
};
|
||||
|
||||
pub unsafe fn init(active_table: &mut KernelMapper) {
|
||||
@@ -22,7 +24,7 @@ pub unsafe fn init_ap() {
|
||||
/// Local APIC
|
||||
pub struct LocalApic {
|
||||
pub address: usize,
|
||||
pub x2: bool
|
||||
pub x2: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -42,19 +44,21 @@ pub fn bsp_apic_id() -> Option<u32> {
|
||||
|
||||
impl LocalApic {
|
||||
unsafe fn init(&mut self, mapper: &mut KernelMapper) {
|
||||
let mapper = mapper.get_mut().expect("expected KernelMapper not to be locked re-entrant while initializing LAPIC");
|
||||
let mapper = mapper
|
||||
.get_mut()
|
||||
.expect("expected KernelMapper not to be locked re-entrant while initializing LAPIC");
|
||||
|
||||
let physaddr = PhysicalAddress::new(rdmsr(IA32_APIC_BASE) as usize & 0xFFFF_0000);
|
||||
let virtaddr = VirtualAddress::new(crate::LAPIC_OFFSET);
|
||||
|
||||
self.address = virtaddr.data();
|
||||
self.x2 = cpuid().map_or(false, |cpuid| {
|
||||
cpuid.get_feature_info().map_or(false, |feature_info| {
|
||||
feature_info.has_x2apic()
|
||||
})
|
||||
cpuid
|
||||
.get_feature_info()
|
||||
.map_or(false, |feature_info| feature_info.has_x2apic())
|
||||
});
|
||||
|
||||
if ! self.x2 {
|
||||
if !self.x2 {
|
||||
log::info!("Detected xAPIC at {:#x}", physaddr.data());
|
||||
if let Some((_entry, _, flush)) = mapper.unmap_phys(virtaddr, true) {
|
||||
// Unmap xAPIC page if already mapped
|
||||
@@ -111,15 +115,15 @@ impl LocalApic {
|
||||
if self.x2 {
|
||||
unsafe { rdmsr(IA32_X2APIC_ICR) }
|
||||
} else {
|
||||
unsafe {
|
||||
(self.read(0x310) as u64) << 32 | self.read(0x300) as u64
|
||||
}
|
||||
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); }
|
||||
unsafe {
|
||||
wrmsr(IA32_X2APIC_ICR, value);
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
const PENDING: u32 = 1 << 12;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
pub mod cpu;
|
||||
#[cfg(feature = "acpi")]
|
||||
pub mod hpet;
|
||||
pub mod ioapic;
|
||||
pub mod local_apic;
|
||||
pub mod pic;
|
||||
pub mod pit;
|
||||
pub mod rtc;
|
||||
pub mod serial;
|
||||
#[cfg(feature = "acpi")]
|
||||
pub mod hpet;
|
||||
#[cfg(feature = "system76_ec_debug")]
|
||||
pub mod system76_ec;
|
||||
|
||||
@@ -16,7 +16,7 @@ pub unsafe fn init() {
|
||||
pic::init();
|
||||
local_apic::init(&mut KernelMapper::lock());
|
||||
}
|
||||
pub unsafe fn init_after_acpi() {
|
||||
pub unsafe fn init_after_acpi() {
|
||||
// this will disable the IOAPIC if needed.
|
||||
//ioapic::init(mapper);
|
||||
}
|
||||
@@ -37,7 +37,9 @@ unsafe fn init_hpet() -> bool {
|
||||
}
|
||||
|
||||
pub unsafe fn init_noncore() {
|
||||
if false /*TODO: init_hpet()*/ {
|
||||
if false
|
||||
/*TODO: init_hpet()*/
|
||||
{
|
||||
log::info!("HPET used as system timer");
|
||||
} else {
|
||||
pit::init();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::syscall::io::{Io, Pio};
|
||||
use crate::arch::interrupt::irq;
|
||||
use crate::{
|
||||
arch::interrupt::irq,
|
||||
syscall::io::{Io, Pio},
|
||||
};
|
||||
|
||||
pub static mut MASTER: Pic = Pic::new(0x20);
|
||||
pub static mut SLAVE: Pic = Pic::new(0xA0);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::syscall::io::{Io, Pio};
|
||||
use crate::time;
|
||||
use crate::{
|
||||
syscall::io::{Io, Pio},
|
||||
time,
|
||||
};
|
||||
|
||||
pub fn init() {
|
||||
let mut rtc = Rtc::new();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::devices::uart_16550::SerialPort;
|
||||
#[cfg(feature = "lpss_debug")]
|
||||
use crate::syscall::io::Mmio;
|
||||
use crate::syscall::io::Pio;
|
||||
use crate::{devices::uart_16550::SerialPort, syscall::io::Pio};
|
||||
use spin::Mutex;
|
||||
|
||||
pub static COM1: Mutex<SerialPort<Pio<u8>>> = Mutex::new(SerialPort::<Pio<u8>>::new(0x3F8));
|
||||
@@ -22,19 +21,24 @@ pub unsafe fn init() {
|
||||
let address = crate::PHYS_OFFSET + 0xFE032000;
|
||||
|
||||
{
|
||||
use crate::paging::{ActivePageTable, Page, VirtualAddress, entry::EntryFlags};
|
||||
use crate::memory::{Frame, PhysicalAddress};
|
||||
use crate::{
|
||||
memory::{Frame, PhysicalAddress},
|
||||
paging::{entry::EntryFlags, ActivePageTable, Page, VirtualAddress},
|
||||
};
|
||||
|
||||
let mut active_table = ActivePageTable::new();
|
||||
let page = Page::containing_address(VirtualAddress::new(address));
|
||||
let frame = Frame::containing_address(PhysicalAddress::new(address - crate::PHYS_OFFSET));
|
||||
let result = active_table.map_to(page, frame, EntryFlags::PRESENT | EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE);
|
||||
let frame =
|
||||
Frame::containing_address(PhysicalAddress::new(address - crate::PHYS_OFFSET));
|
||||
let result = active_table.map_to(
|
||||
page,
|
||||
frame,
|
||||
EntryFlags::PRESENT | EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE,
|
||||
);
|
||||
result.flush(&mut active_table);
|
||||
}
|
||||
|
||||
let lpss = SerialPort::<Mmio<u32>>::new(
|
||||
crate::PHYS_OFFSET + 0xFE032000
|
||||
);
|
||||
let lpss = SerialPort::<Mmio<u32>>::new(crate::PHYS_OFFSET + 0xFE032000);
|
||||
lpss.init();
|
||||
|
||||
*LPSS.lock() = Some(lpss);
|
||||
|
||||
@@ -13,9 +13,7 @@ pub struct System76Ec {
|
||||
|
||||
impl System76Ec {
|
||||
pub fn new() -> Option<Self> {
|
||||
let mut system76_ec = Self {
|
||||
base: 0x0E00,
|
||||
};
|
||||
let mut system76_ec = Self { base: 0x0E00 };
|
||||
if system76_ec.probe() {
|
||||
Some(system76_ec)
|
||||
} else {
|
||||
|
||||
+69
-25
@@ -1,16 +1,15 @@
|
||||
//! Global descriptor table
|
||||
|
||||
use core::convert::TryInto;
|
||||
use core::mem;
|
||||
use core::ptr::addr_of_mut;
|
||||
use core::{convert::TryInto, mem, ptr::addr_of_mut};
|
||||
|
||||
use crate::LogicalCpuId;
|
||||
|
||||
use x86::bits32::task::TaskStateSegment;
|
||||
use x86::Ring;
|
||||
use x86::dtables::{self, DescriptorTablePointer};
|
||||
use x86::segmentation::{self, Descriptor as SegmentDescriptor, SegmentSelector};
|
||||
use x86::task;
|
||||
use x86::{
|
||||
bits32::task::TaskStateSegment,
|
||||
dtables::{self, DescriptorTablePointer},
|
||||
segmentation::{self, Descriptor as SegmentDescriptor, SegmentSelector},
|
||||
task, Ring,
|
||||
};
|
||||
|
||||
use crate::paging::{RmmA, RmmArch, PAGE_SIZE};
|
||||
|
||||
@@ -48,28 +47,73 @@ static INIT_GDT: [GdtEntry; 3] = [
|
||||
// Null
|
||||
GdtEntry::new(0, 0, 0, 0),
|
||||
// Kernel code
|
||||
GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0xFFFFF,
|
||||
GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE,
|
||||
GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE,
|
||||
),
|
||||
// Kernel data
|
||||
GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0xFFFFF,
|
||||
GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE,
|
||||
GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE,
|
||||
),
|
||||
];
|
||||
|
||||
const BASE_GDT: [GdtEntry; 9] = [
|
||||
// Null
|
||||
GdtEntry::new(0, 0, 0, 0),
|
||||
// Kernel code
|
||||
GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0xFFFFF,
|
||||
GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE,
|
||||
GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE,
|
||||
),
|
||||
// Kernel data
|
||||
GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0xFFFFF,
|
||||
GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE,
|
||||
GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE,
|
||||
),
|
||||
// Kernel TLS
|
||||
GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0xFFFFF,
|
||||
GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE,
|
||||
GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE,
|
||||
),
|
||||
// User (32-bit) code
|
||||
GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0xFFFFF,
|
||||
GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE,
|
||||
GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE,
|
||||
),
|
||||
// User data
|
||||
GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0xFFFFF,
|
||||
GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE,
|
||||
GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE,
|
||||
),
|
||||
// User FS (for TLS)
|
||||
GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0xFFFFF,
|
||||
GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE,
|
||||
GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE,
|
||||
),
|
||||
// User GS (for TLS)
|
||||
GdtEntry::new(0, 0xFFFFF, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0xFFFFF,
|
||||
GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE,
|
||||
GDT_F_PAGE_SIZE | GDT_F_PROTECTED_MODE,
|
||||
),
|
||||
// TSS
|
||||
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_TSS_AVAIL, 0),
|
||||
];
|
||||
@@ -96,9 +140,10 @@ pub unsafe fn pcr() -> *mut ProcessorControlRegion {
|
||||
|
||||
#[cfg(feature = "pti")]
|
||||
pub unsafe fn set_tss_stack(stack: usize) {
|
||||
use super::pti::{PTI_CPU_STACK, PTI_CONTEXT_STACK};
|
||||
use super::pti::{PTI_CONTEXT_STACK, PTI_CPU_STACK};
|
||||
addr_of_mut!((*pcr()).tss.0.ss0).write((GDT_KERNEL_DATA << 3) as u16);
|
||||
addr_of_mut!((*pcr()).tss.0.esp0).write((PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len()) as u32);
|
||||
addr_of_mut!((*pcr()).tss.0.esp0)
|
||||
.write((PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len()) as u32);
|
||||
PTI_CONTEXT_STACK = stack;
|
||||
}
|
||||
|
||||
@@ -128,7 +173,8 @@ pub unsafe fn init() {
|
||||
/// Initialize GDT and configure percpu.
|
||||
pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) {
|
||||
let pcr_frame = crate::memory::allocate_frames(1).expect("failed to allocate PCR frame");
|
||||
let pcr = &mut *(RmmA::phys_to_virt(pcr_frame.start_address()).data() as *mut ProcessorControlRegion);
|
||||
let pcr =
|
||||
&mut *(RmmA::phys_to_virt(pcr_frame.start_address()).data() as *mut ProcessorControlRegion);
|
||||
|
||||
pcr.self_ref = pcr as *const _ as usize;
|
||||
pcr.gdt = BASE_GDT;
|
||||
@@ -179,7 +225,7 @@ pub struct GdtEntry {
|
||||
pub offsetm: u8,
|
||||
pub access: u8,
|
||||
pub flags_limith: u8,
|
||||
pub offseth: u8
|
||||
pub offseth: u8,
|
||||
}
|
||||
|
||||
impl GdtEntry {
|
||||
@@ -190,14 +236,12 @@ impl GdtEntry {
|
||||
offsetm: (offset >> 16) as u8,
|
||||
access,
|
||||
flags_limith: flags & 0xF0 | ((limit >> 16) as u8) & 0x0F,
|
||||
offseth: (offset >> 24) as u8
|
||||
offseth: (offset >> 24) as u8,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> u32 {
|
||||
(self.offsetl as u32) |
|
||||
((self.offsetm as u32) << 16) |
|
||||
((self.offseth as u32) << 24)
|
||||
(self.offsetl as u32) | ((self.offsetm as u32) << 16) | ((self.offseth as u32) << 24)
|
||||
}
|
||||
|
||||
pub fn set_offset(&mut self, offset: u32) {
|
||||
|
||||
+55
-19
@@ -1,21 +1,24 @@
|
||||
use core::num::NonZeroU8;
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
use core::mem;
|
||||
use core::{
|
||||
mem,
|
||||
num::NonZeroU8,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use x86::segmentation::Descriptor as X86IdtEntry;
|
||||
use x86::dtables::{self, DescriptorTablePointer};
|
||||
use x86::{
|
||||
dtables::{self, DescriptorTablePointer},
|
||||
segmentation::Descriptor as X86IdtEntry,
|
||||
};
|
||||
|
||||
use crate::{interrupt::*, LogicalCpuId};
|
||||
use crate::ipi::IpiKind;
|
||||
use crate::{interrupt::*, ipi::IpiKind, LogicalCpuId};
|
||||
|
||||
use spin::RwLock;
|
||||
|
||||
pub static mut INIT_IDTR: DescriptorTablePointer<X86IdtEntry> = DescriptorTablePointer {
|
||||
limit: 0,
|
||||
base: 0 as *const X86IdtEntry
|
||||
base: 0 as *const X86IdtEntry,
|
||||
};
|
||||
|
||||
pub type IdtEntries = [IdtEntry; 256];
|
||||
@@ -46,7 +49,8 @@ impl Idt {
|
||||
let byte_index = index / 32;
|
||||
let bit = index % 32;
|
||||
|
||||
{ &self.reservations[usize::from(byte_index)] }.fetch_or(u32::from(reserved) << bit, Ordering::AcqRel);
|
||||
{ &self.reservations[usize::from(byte_index)] }
|
||||
.fetch_or(u32::from(reserved) << bit, Ordering::AcqRel);
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_reserved_mut(&mut self, index: u8) -> bool {
|
||||
@@ -61,7 +65,8 @@ impl Idt {
|
||||
let byte_index = index / 32;
|
||||
let bit = index % 32;
|
||||
|
||||
*{ &mut self.reservations[usize::from(byte_index)] }.get_mut() |= u32::from(reserved) << bit;
|
||||
*{ &mut self.reservations[usize::from(byte_index)] }.get_mut() |=
|
||||
u32::from(reserved) << bit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +80,18 @@ pub fn is_reserved(cpu_id: LogicalCpuId, index: u8) -> bool {
|
||||
let byte_index = index / 32;
|
||||
let bit = index % 32;
|
||||
|
||||
{ &IDTS.read().as_ref().unwrap().get(&cpu_id).unwrap().reservations[usize::from(byte_index)] }.load(Ordering::Acquire) & (1 << bit) != 0
|
||||
{
|
||||
&IDTS
|
||||
.read()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get(&cpu_id)
|
||||
.unwrap()
|
||||
.reservations[usize::from(byte_index)]
|
||||
}
|
||||
.load(Ordering::Acquire)
|
||||
& (1 << bit)
|
||||
!= 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -83,13 +99,22 @@ pub fn set_reserved(cpu_id: LogicalCpuId, index: u8, reserved: bool) {
|
||||
let byte_index = index / 32;
|
||||
let bit = index % 32;
|
||||
|
||||
{ &IDTS.read().as_ref().unwrap().get(&cpu_id).unwrap().reservations[usize::from(byte_index)] }.fetch_or(u32::from(reserved) << bit, Ordering::AcqRel);
|
||||
{
|
||||
&IDTS
|
||||
.read()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get(&cpu_id)
|
||||
.unwrap()
|
||||
.reservations[usize::from(byte_index)]
|
||||
}
|
||||
.fetch_or(u32::from(reserved) << bit, Ordering::AcqRel);
|
||||
}
|
||||
|
||||
pub fn allocate_interrupt() -> Option<NonZeroU8> {
|
||||
let cpu_id = crate::cpu_id();
|
||||
for number in 50..=254 {
|
||||
if ! is_reserved(cpu_id, number) {
|
||||
if !is_reserved(cpu_id, number) {
|
||||
set_reserved(cpu_id, number, true);
|
||||
return Some(unsafe { NonZeroU8::new_unchecked(number) });
|
||||
}
|
||||
@@ -120,8 +145,14 @@ pub unsafe fn init() {
|
||||
|
||||
const fn new_idt_reservations() -> [AtomicU32; 8] {
|
||||
[
|
||||
AtomicU32::new(0), AtomicU32::new(0), AtomicU32::new(0), AtomicU32::new(0),
|
||||
AtomicU32::new(0), AtomicU32::new(0), AtomicU32::new(0), AtomicU32::new(0)
|
||||
AtomicU32::new(0),
|
||||
AtomicU32::new(0),
|
||||
AtomicU32::new(0),
|
||||
AtomicU32::new(0),
|
||||
AtomicU32::new(0),
|
||||
AtomicU32::new(0),
|
||||
AtomicU32::new(0),
|
||||
AtomicU32::new(0),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -133,7 +164,9 @@ pub unsafe fn init_paging_post_heap(is_bsp: bool, cpu_id: LogicalCpuId) {
|
||||
if is_bsp {
|
||||
idts_btree.insert(cpu_id, &mut INIT_BSP_IDT);
|
||||
} else {
|
||||
let idt = idts_btree.entry(cpu_id).or_insert_with(|| Box::leak(Box::new(Idt::new())));
|
||||
let idt = idts_btree
|
||||
.entry(cpu_id)
|
||||
.or_insert_with(|| Box::leak(Box::new(Idt::new())));
|
||||
init_generic(is_bsp, idt);
|
||||
}
|
||||
}
|
||||
@@ -238,7 +271,6 @@ pub unsafe fn init_generic(is_bsp: bool, idt: &mut Idt) {
|
||||
current_idt[48].set_func(irq::lapic_timer);
|
||||
current_idt[49].set_func(irq::lapic_error);
|
||||
|
||||
|
||||
// reserve bits 49:32, which are for the standard IRQs, and for the local apic timer and error.
|
||||
*current_reservations[1].get_mut() |= 0x0003_FFFF;
|
||||
} else {
|
||||
@@ -309,7 +341,11 @@ impl IdtEntry {
|
||||
}
|
||||
|
||||
pub fn set_ist(&mut self, ist: u8) {
|
||||
assert_eq!(ist & 0x07, ist, "interrupt stack table must be within 0..=7");
|
||||
assert_eq!(
|
||||
ist & 0x07,
|
||||
ist,
|
||||
"interrupt stack table must be within 0..=7"
|
||||
);
|
||||
self.zero &= 0xF8;
|
||||
self.zero |= ist;
|
||||
}
|
||||
@@ -321,7 +357,7 @@ impl IdtEntry {
|
||||
}
|
||||
|
||||
// A function to set the offset more easily
|
||||
pub fn set_func(&mut self, func: unsafe extern fn()) {
|
||||
pub fn set_func(&mut self, func: unsafe extern "C" fn()) {
|
||||
self.set_flags(IdtFlags::PRESENT | IdtFlags::RING_0 | IdtFlags::INTERRUPT);
|
||||
self.set_offset((crate::gdt::GDT_KERNEL_CODE as u16) << 3, func as usize);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
use rmm::TableKind;
|
||||
use x86::irq::PageFaultError;
|
||||
|
||||
use crate::memory::GenericPfFlags;
|
||||
use crate::paging::VirtualAddress;
|
||||
use crate::{
|
||||
interrupt::stack_trace,
|
||||
ptrace,
|
||||
syscall::flag::*,
|
||||
|
||||
interrupt_stack,
|
||||
interrupt_error,
|
||||
interrupt::stack_trace, interrupt_error, interrupt_stack, memory::GenericPfFlags,
|
||||
paging::VirtualAddress, ptrace, syscall::flag::*,
|
||||
};
|
||||
|
||||
extern {
|
||||
extern "C" {
|
||||
fn ksignal(signal: usize);
|
||||
}
|
||||
|
||||
@@ -140,11 +134,26 @@ interrupt_error!(page, |stack| {
|
||||
let arch_flags = PageFaultError::from_bits_truncate(stack.code as u32);
|
||||
let mut generic_flags = GenericPfFlags::empty();
|
||||
|
||||
generic_flags.set(GenericPfFlags::PRESENT, arch_flags.contains(PageFaultError::P));
|
||||
generic_flags.set(GenericPfFlags::INVOLVED_WRITE, arch_flags.contains(PageFaultError::WR));
|
||||
generic_flags.set(GenericPfFlags::USER_NOT_SUPERVISOR, arch_flags.contains(PageFaultError::US));
|
||||
generic_flags.set(GenericPfFlags::INVL, arch_flags.contains(PageFaultError::RSVD));
|
||||
generic_flags.set(GenericPfFlags::INSTR_NOT_DATA, arch_flags.contains(PageFaultError::ID));
|
||||
generic_flags.set(
|
||||
GenericPfFlags::PRESENT,
|
||||
arch_flags.contains(PageFaultError::P),
|
||||
);
|
||||
generic_flags.set(
|
||||
GenericPfFlags::INVOLVED_WRITE,
|
||||
arch_flags.contains(PageFaultError::WR),
|
||||
);
|
||||
generic_flags.set(
|
||||
GenericPfFlags::USER_NOT_SUPERVISOR,
|
||||
arch_flags.contains(PageFaultError::US),
|
||||
);
|
||||
generic_flags.set(
|
||||
GenericPfFlags::INVL,
|
||||
arch_flags.contains(PageFaultError::RSVD),
|
||||
);
|
||||
generic_flags.set(
|
||||
GenericPfFlags::INSTR_NOT_DATA,
|
||||
arch_flags.contains(PageFaultError::ID),
|
||||
);
|
||||
|
||||
if crate::memory::page_fault_handler(&mut stack.inner, generic_flags, cr2).is_err() {
|
||||
println!("Page fault: {:>08X} {:#?}", cr2.data(), arch_flags);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use core::mem;
|
||||
|
||||
use crate::memory::ArchIntCtx;
|
||||
use crate::syscall::IntRegisters;
|
||||
use crate::{memory::ArchIntCtx, syscall::IntRegisters};
|
||||
|
||||
use super::super::flags::*;
|
||||
|
||||
@@ -50,9 +49,8 @@ pub struct IretRegisters {
|
||||
// The following will only be present if interrupt is raised from another
|
||||
// privilege ring. Otherwise, they are undefined values.
|
||||
// ----
|
||||
|
||||
pub esp: usize,
|
||||
pub ss: usize
|
||||
pub ss: usize,
|
||||
}
|
||||
|
||||
impl IretRegisters {
|
||||
@@ -169,61 +167,73 @@ impl InterruptErrorStack {
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! push_scratch {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Push scratch registers (minus eax)
|
||||
push ecx
|
||||
push edx
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! pop_scratch {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Pop scratch registers
|
||||
pop edx
|
||||
pop ecx
|
||||
pop eax
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! push_preserved {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Push preserved registers
|
||||
push ebx
|
||||
push edi
|
||||
push esi
|
||||
push ebp
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! pop_preserved {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Pop preserved registers
|
||||
pop ebp
|
||||
pop esi
|
||||
pop edi
|
||||
pop ebx
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
// Must always happen after push_scratch
|
||||
macro_rules! enter_gs {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Enter kernel GS segment
|
||||
mov ecx, gs
|
||||
push ecx
|
||||
mov ecx, 0x18
|
||||
mov gs, ecx
|
||||
" }
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
// Must always happen before pop_scratch
|
||||
macro_rules! exit_gs {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Exit kernel GS segment
|
||||
pop ecx
|
||||
mov gs, ecx
|
||||
" }
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
@@ -411,13 +421,16 @@ macro_rules! interrupt_error {
|
||||
}
|
||||
#[naked]
|
||||
unsafe extern "C" fn usercopy_trampoline() {
|
||||
core::arch::asm!("
|
||||
core::arch::asm!(
|
||||
"
|
||||
pop esi
|
||||
pop edi
|
||||
|
||||
mov eax, 1
|
||||
ret
|
||||
", options(noreturn));
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
|
||||
impl ArchIntCtx for InterruptStack {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use x86::tlb;
|
||||
|
||||
use crate::context;
|
||||
use crate::device::local_apic::LOCAL_APIC;
|
||||
use crate::{context, device::local_apic::LOCAL_APIC};
|
||||
|
||||
interrupt!(wakeup, || {
|
||||
LOCAL_APIC.eoi();
|
||||
|
||||
@@ -2,14 +2,21 @@ use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{interrupt, interrupt_stack};
|
||||
use crate::context::timeout;
|
||||
use crate::device::{local_apic, ioapic, pic, pit};
|
||||
use crate::device::serial::{COM1, COM2};
|
||||
use crate::ipi::{ipi, IpiKind, IpiTarget};
|
||||
use crate::scheme::debug::{debug_input, debug_notify};
|
||||
use crate::scheme::serio::serio_input;
|
||||
use crate::{context, time};
|
||||
use crate::{
|
||||
context,
|
||||
context::timeout,
|
||||
device::{
|
||||
ioapic, local_apic, pic, pit,
|
||||
serial::{COM1, COM2},
|
||||
},
|
||||
interrupt, interrupt_stack,
|
||||
ipi::{ipi, IpiKind, IpiTarget},
|
||||
scheme::{
|
||||
debug::{debug_input, debug_notify},
|
||||
serio::serio_input,
|
||||
},
|
||||
time,
|
||||
};
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
@@ -33,9 +40,13 @@ pub fn spurious_count() -> usize {
|
||||
pub fn spurious_irq_resource() -> syscall::Result<Vec<u8>> {
|
||||
match irq_method() {
|
||||
IrqMethod::Apic => Ok(Vec::from(&b"(not implemented for APIC yet)"[..])),
|
||||
IrqMethod::Pic => {
|
||||
Ok(format!("{}\tIRQ7\n{}\tIRQ15\n{}\ttotal\n", spurious_count_irq7(), spurious_count_irq15(), spurious_count()).into_bytes())
|
||||
}
|
||||
IrqMethod::Pic => Ok(format!(
|
||||
"{}\tIRQ7\n{}\tIRQ15\n{}\ttotal\n",
|
||||
spurious_count_irq7(),
|
||||
spurious_count_irq15(),
|
||||
spurious_count()
|
||||
)
|
||||
.into_bytes()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +66,7 @@ fn irq_method() -> IrqMethod {
|
||||
}
|
||||
}
|
||||
|
||||
extern {
|
||||
extern "C" {
|
||||
// triggers irq scheme
|
||||
fn irq_trigger(irq: u8);
|
||||
}
|
||||
@@ -64,7 +75,11 @@ extern {
|
||||
/// scheme user unmasks it ("acknowledges" it).
|
||||
unsafe fn trigger(irq: u8) {
|
||||
match irq_method() {
|
||||
IrqMethod::Pic => if irq < 16 { pic_mask(irq) },
|
||||
IrqMethod::Pic => {
|
||||
if irq < 16 {
|
||||
pic_mask(irq)
|
||||
}
|
||||
}
|
||||
IrqMethod::Apic => ioapic_mask(irq),
|
||||
}
|
||||
irq_trigger(irq);
|
||||
@@ -74,7 +89,11 @@ unsafe fn trigger(irq: u8) {
|
||||
/// processed the IRQ.
|
||||
pub unsafe fn acknowledge(irq: usize) {
|
||||
match irq_method() {
|
||||
IrqMethod::Pic => if irq < 16 { pic_unmask(irq) },
|
||||
IrqMethod::Pic => {
|
||||
if irq < 16 {
|
||||
pic_unmask(irq)
|
||||
}
|
||||
}
|
||||
IrqMethod::Apic => ioapic_unmask(irq),
|
||||
}
|
||||
}
|
||||
@@ -82,7 +101,11 @@ pub unsafe fn acknowledge(irq: usize) {
|
||||
/// Sends an end-of-interrupt, so that the interrupt controller can go on to the next one.
|
||||
pub unsafe fn eoi(irq: u8) {
|
||||
match irq_method() {
|
||||
IrqMethod::Pic => if irq < 16 { pic_eoi(irq) },
|
||||
IrqMethod::Pic => {
|
||||
if irq < 16 {
|
||||
pic_eoi(irq)
|
||||
}
|
||||
}
|
||||
IrqMethod::Apic => lapic_eoi(),
|
||||
}
|
||||
}
|
||||
@@ -242,7 +265,7 @@ interrupt!(ata2, || {
|
||||
if irq_method() == IrqMethod::Pic && pic::SLAVE.isr() & (1 << 7) == 0 {
|
||||
SPURIOUS_COUNT_IRQ15.fetch_add(1, Ordering::Relaxed);
|
||||
pic::MASTER.ack();
|
||||
return
|
||||
return;
|
||||
}
|
||||
trigger(15);
|
||||
eoi(15);
|
||||
@@ -254,7 +277,10 @@ interrupt!(lapic_timer, || {
|
||||
});
|
||||
|
||||
interrupt!(lapic_error, || {
|
||||
println!("Local apic internal error: ESR={:#0x}", local_apic::LOCAL_APIC.esr());
|
||||
println!(
|
||||
"Local apic internal error: ESR={:#0x}",
|
||||
local_apic::LOCAL_APIC.esr()
|
||||
);
|
||||
lapic_eoi();
|
||||
});
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@ pub mod irq;
|
||||
pub mod syscall;
|
||||
pub mod trace;
|
||||
|
||||
pub use self::handler::InterruptStack;
|
||||
pub use self::trace::stack_trace;
|
||||
pub use self::{handler::InterruptStack, trace::stack_trace};
|
||||
|
||||
pub use super::idt::{available_irqs_iter, is_reserved, set_reserved};
|
||||
pub use super::device::local_apic::bsp_apic_id;
|
||||
pub use super::{
|
||||
device::local_apic::bsp_apic_id,
|
||||
idt::{available_irqs_iter, is_reserved, set_reserved},
|
||||
};
|
||||
|
||||
/// Clear interrupts
|
||||
#[inline(always)]
|
||||
@@ -53,5 +54,7 @@ pub unsafe fn halt() {
|
||||
/// Safe because it is similar to a NOP, and has no memory effects
|
||||
#[inline(always)]
|
||||
pub fn pause() {
|
||||
unsafe { core::arch::asm!("pause", options(nomem, nostack)); }
|
||||
unsafe {
|
||||
core::arch::asm!("pause", options(nomem, nostack));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use crate::{
|
||||
arch::{gdt, interrupt::InterruptStack},
|
||||
context,
|
||||
ptrace,
|
||||
syscall,
|
||||
syscall::flag::{PTRACE_FLAG_IGNORE, PTRACE_STOP_PRE_SYSCALL, PTRACE_STOP_POST_SYSCALL},
|
||||
context, ptrace, syscall,
|
||||
syscall::flag::{PTRACE_FLAG_IGNORE, PTRACE_STOP_POST_SYSCALL, PTRACE_STOP_PRE_SYSCALL},
|
||||
};
|
||||
use core::mem::offset_of;
|
||||
use x86::{bits32::task::TaskStateSegment, msr, segmentation::SegmentSelector};
|
||||
@@ -25,33 +23,44 @@ macro_rules! with_interrupt_stack {
|
||||
}
|
||||
|
||||
ptrace::breakpoint_callback(PTRACE_STOP_POST_SYSCALL, None);
|
||||
}}
|
||||
}};
|
||||
}
|
||||
|
||||
interrupt_stack!(syscall, |stack| {
|
||||
with_interrupt_stack!(|stack| {
|
||||
let scratch = &stack.scratch;
|
||||
let preserved = &stack.preserved;
|
||||
syscall::syscall(scratch.eax, preserved.ebx, scratch.ecx, scratch.edx, preserved.esi, preserved.edi, stack)
|
||||
syscall::syscall(
|
||||
scratch.eax,
|
||||
preserved.ebx,
|
||||
scratch.ecx,
|
||||
scratch.edx,
|
||||
preserved.esi,
|
||||
preserved.edi,
|
||||
stack,
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
#[naked]
|
||||
pub unsafe extern "C" fn clone_ret() {
|
||||
core::arch::asm!(concat!(
|
||||
// The address of this instruction is injected by `clone` in process.rs, on
|
||||
// top of the stack syscall->inner in this file, which is done using the ebp
|
||||
// register we save there.
|
||||
//
|
||||
// The top of our stack here is the address pointed to by ebp, which is:
|
||||
//
|
||||
// - the previous ebp
|
||||
// - the return location
|
||||
//
|
||||
// Our goal is to return from the parent function, inner, so we restore
|
||||
// ebp...
|
||||
"pop ebp\n",
|
||||
// ...and we return to the address at the top of the stack
|
||||
"ret\n",
|
||||
), options(noreturn));
|
||||
core::arch::asm!(
|
||||
concat!(
|
||||
// The address of this instruction is injected by `clone` in process.rs, on
|
||||
// top of the stack syscall->inner in this file, which is done using the ebp
|
||||
// register we save there.
|
||||
//
|
||||
// The top of our stack here is the address pointed to by ebp, which is:
|
||||
//
|
||||
// - the previous ebp
|
||||
// - the return location
|
||||
//
|
||||
// Our goal is to return from the parent function, inner, so we restore
|
||||
// ebp...
|
||||
"pop ebp\n",
|
||||
// ...and we return to the address at the top of the stack
|
||||
"ret\n",
|
||||
),
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use core::{mem, str};
|
||||
use goblin::elf::sym;
|
||||
use rustc_demangle::demangle;
|
||||
|
||||
use crate::{paging::{KernelMapper, VirtualAddress}};
|
||||
use crate::paging::{KernelMapper, VirtualAddress};
|
||||
|
||||
/// Get a stack trace
|
||||
//TODO: Check for stack being mapped before dereferencing
|
||||
@@ -45,11 +45,12 @@ pub unsafe fn stack_trace() {
|
||||
//TODO: Do not create Elf object for every symbol lookup
|
||||
#[inline(never)]
|
||||
pub unsafe fn symbol_trace(addr: usize) {
|
||||
use core::slice;
|
||||
use core::sync::atomic::Ordering;
|
||||
use core::{slice, sync::atomic::Ordering};
|
||||
|
||||
use crate::elf::Elf;
|
||||
use crate::start::{KERNEL_BASE, KERNEL_SIZE};
|
||||
use crate::{
|
||||
elf::Elf,
|
||||
start::{KERNEL_BASE, KERNEL_SIZE},
|
||||
};
|
||||
|
||||
let kernel_ptr = (KERNEL_BASE.load(Ordering::SeqCst) + crate::PHYS_OFFSET) as *const u8;
|
||||
let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst));
|
||||
@@ -65,10 +66,14 @@ pub unsafe fn symbol_trace(addr: usize) {
|
||||
if let Some(symbols) = elf.symbols() {
|
||||
for sym in symbols {
|
||||
if sym::st_type(sym.st_info) == sym::STT_FUNC
|
||||
&& addr >= sym.st_value as usize
|
||||
&& addr < (sym.st_value + sym.st_size) as usize
|
||||
&& addr >= sym.st_value as usize
|
||||
&& addr < (sym.st_value + sym.st_size) as usize
|
||||
{
|
||||
println!(" {:>016X}+{:>04X}", sym.st_value, addr - sym.st_value as usize);
|
||||
println!(
|
||||
" {:>016X}+{:>04X}",
|
||||
sym.st_value,
|
||||
addr - sym.st_value as usize
|
||||
);
|
||||
|
||||
if let Some(strtab) = strtab_opt {
|
||||
let start = strtab.sh_offset as usize + sym.st_name as usize;
|
||||
@@ -82,7 +87,7 @@ pub unsafe fn symbol_trace(addr: usize) {
|
||||
}
|
||||
|
||||
if end > start {
|
||||
let sym_slice = &elf.data[start .. end - 1];
|
||||
let sym_slice = &elf.data[start..end - 1];
|
||||
if let Ok(sym_name) = str::from_utf8(sym_slice) {
|
||||
println!(" {:#}", demangle(sym_name));
|
||||
}
|
||||
|
||||
+11
-5
@@ -42,9 +42,9 @@ pub mod stop;
|
||||
|
||||
pub mod time;
|
||||
|
||||
pub use ::rmm::X86Arch as CurrentRmmArch;
|
||||
use crate::{memory::PAGE_SIZE, Bootstrap};
|
||||
use ::rmm::Arch;
|
||||
use crate::{Bootstrap, memory::PAGE_SIZE};
|
||||
pub use ::rmm::X86Arch as CurrentRmmArch;
|
||||
|
||||
// Flags
|
||||
pub mod flags {
|
||||
@@ -56,7 +56,8 @@ pub mod flags {
|
||||
#[naked]
|
||||
#[link_section = ".usercopy-fns"]
|
||||
pub unsafe extern "C" fn arch_copy_to_user(dst: usize, src: usize, len: usize) -> u8 {
|
||||
core::arch::asm!("
|
||||
core::arch::asm!(
|
||||
"
|
||||
push edi
|
||||
push esi
|
||||
|
||||
@@ -70,12 +71,17 @@ pub unsafe extern "C" fn arch_copy_to_user(dst: usize, src: usize, len: usize) -
|
||||
|
||||
xor eax, eax
|
||||
ret
|
||||
", options(noreturn));
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
pub use arch_copy_to_user as arch_copy_from_user;
|
||||
|
||||
pub unsafe fn bootstrap_mem(bootstrap: &Bootstrap) -> &'static [u8] {
|
||||
core::slice::from_raw_parts(CurrentRmmArch::phys_to_virt(bootstrap.base.start_address()).data() as *const u8, bootstrap.page_count * PAGE_SIZE)
|
||||
core::slice::from_raw_parts(
|
||||
CurrentRmmArch::phys_to_virt(bootstrap.base.start_address()).data() as *const u8,
|
||||
bootstrap.page_count * PAGE_SIZE,
|
||||
)
|
||||
}
|
||||
pub const KFX_SIZE: usize = 512;
|
||||
|
||||
|
||||
@@ -4,16 +4,22 @@ use super::RmmA;
|
||||
|
||||
pub use rmm::{Flusher, PageFlush, PageFlushAll};
|
||||
|
||||
pub struct InactiveFlusher { _inner: () }
|
||||
pub struct InactiveFlusher {
|
||||
_inner: (),
|
||||
}
|
||||
impl InactiveFlusher {
|
||||
// TODO: cpu id
|
||||
pub fn new() -> Self { Self { _inner: () } }
|
||||
pub fn new() -> Self {
|
||||
Self { _inner: () }
|
||||
}
|
||||
}
|
||||
|
||||
impl Flusher<RmmA> for InactiveFlusher {
|
||||
fn consume(&mut self, flush: PageFlush<RmmA>) {
|
||||
// TODO: Push to TLB "mailbox" or tell it to reload CR3 if there are too many entries.
|
||||
unsafe { flush.ignore(); }
|
||||
unsafe {
|
||||
flush.ignore();
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Drop for InactiveFlusher {
|
||||
|
||||
@@ -6,15 +6,8 @@ use x86::msr;
|
||||
|
||||
use self::mapper::PageFlushAll;
|
||||
|
||||
pub use rmm::{
|
||||
Arch as RmmArch,
|
||||
Flusher,
|
||||
PageFlags,
|
||||
PhysicalAddress,
|
||||
TableKind,
|
||||
VirtualAddress,
|
||||
};
|
||||
pub use super::CurrentRmmArch as RmmA;
|
||||
pub use rmm::{Arch as RmmArch, Flusher, PageFlags, PhysicalAddress, TableKind, VirtualAddress};
|
||||
|
||||
pub type PageMapper = rmm::PageMapper<RmmA, crate::arch::rmm::LockedAllocator>;
|
||||
pub use crate::rmm::KernelMapper;
|
||||
@@ -111,7 +104,10 @@ impl Page {
|
||||
}
|
||||
|
||||
pub fn range_inclusive(start: Page, r#final: Page) -> PageIter {
|
||||
PageIter { start, end: r#final.next() }
|
||||
PageIter {
|
||||
start,
|
||||
end: r#final.next(),
|
||||
}
|
||||
}
|
||||
pub fn range_exclusive(start: Page, end: Page) -> PageIter {
|
||||
PageIter { start, end }
|
||||
|
||||
+11
-9
@@ -4,9 +4,9 @@ use core::ptr;
|
||||
#[cfg(feature = "pti")]
|
||||
use crate::memory::Frame;
|
||||
#[cfg(feature = "pti")]
|
||||
use crate::paging::ActivePageTable;
|
||||
#[cfg(feature = "pti")]
|
||||
use crate::paging::entry::EntryFlags;
|
||||
#[cfg(feature = "pti")]
|
||||
use crate::paging::ActivePageTable;
|
||||
|
||||
#[cfg(feature = "pti")]
|
||||
#[thread_local]
|
||||
@@ -26,11 +26,7 @@ unsafe fn switch_stack(old: usize, new: usize) {
|
||||
|
||||
let new_rsp = new - offset_rsp;
|
||||
|
||||
ptr::copy_nonoverlapping(
|
||||
old_rsp as *const u8,
|
||||
new_rsp as *mut u8,
|
||||
offset_rsp
|
||||
);
|
||||
ptr::copy_nonoverlapping(old_rsp as *const u8, new_rsp as *mut u8, offset_rsp);
|
||||
|
||||
asm!("", out("rsp") new_rsp);
|
||||
}
|
||||
@@ -53,14 +49,20 @@ pub unsafe fn map() {
|
||||
// }
|
||||
|
||||
// Switch to per-context stack
|
||||
switch_stack(PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len(), PTI_CONTEXT_STACK);
|
||||
switch_stack(
|
||||
PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len(),
|
||||
PTI_CONTEXT_STACK,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "pti")]
|
||||
#[inline(always)]
|
||||
pub unsafe extern "C" fn unmap() {
|
||||
// Switch to per-CPU stack
|
||||
switch_stack(PTI_CONTEXT_STACK, PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len());
|
||||
switch_stack(
|
||||
PTI_CONTEXT_STACK,
|
||||
PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len(),
|
||||
);
|
||||
|
||||
// {
|
||||
// let mut active_table = unsafe { ActivePageTable::new() };
|
||||
|
||||
+163
-94
@@ -1,26 +1,12 @@
|
||||
use core::{
|
||||
cell::SyncUnsafeCell,
|
||||
cmp,
|
||||
mem,
|
||||
slice,
|
||||
cmp, mem, slice,
|
||||
sync::atomic::{self, AtomicUsize, Ordering},
|
||||
};
|
||||
use rmm::{
|
||||
KILOBYTE,
|
||||
Arch, BuddyAllocator, BumpAllocator, FrameAllocator, FrameCount, FrameUsage, MemoryArea,
|
||||
PageEntry, PageFlags, PageMapper, PhysicalAddress, TableKind, VirtualAddress, KILOBYTE,
|
||||
MEGABYTE,
|
||||
Arch,
|
||||
BuddyAllocator,
|
||||
BumpAllocator,
|
||||
FrameAllocator,
|
||||
FrameCount,
|
||||
FrameUsage,
|
||||
MemoryArea,
|
||||
PageEntry,
|
||||
PageFlags,
|
||||
PageMapper,
|
||||
PhysicalAddress,
|
||||
TableKind,
|
||||
VirtualAddress,
|
||||
};
|
||||
use spin::Mutex;
|
||||
|
||||
@@ -65,11 +51,16 @@ unsafe fn page_flags<A: Arch>(virt: VirtualAddress) -> PageFlags<A> {
|
||||
|
||||
unsafe fn inner<A: Arch>(
|
||||
areas: &'static [MemoryArea],
|
||||
kernel_base: usize, kernel_size_aligned: usize,
|
||||
stack_base: usize, stack_size_aligned: usize,
|
||||
env_base: usize, env_size_aligned: usize,
|
||||
acpi_base: usize, acpi_size_aligned: usize,
|
||||
initfs_base: usize, initfs_size_aligned: usize,
|
||||
kernel_base: usize,
|
||||
kernel_size_aligned: usize,
|
||||
stack_base: usize,
|
||||
stack_size_aligned: usize,
|
||||
env_base: usize,
|
||||
env_size_aligned: usize,
|
||||
acpi_base: usize,
|
||||
acpi_size_aligned: usize,
|
||||
initfs_base: usize,
|
||||
initfs_size_aligned: usize,
|
||||
) -> BuddyAllocator<A> {
|
||||
// First, calculate how much memory we have
|
||||
let mut size = 0;
|
||||
@@ -86,17 +77,20 @@ unsafe fn inner<A: Arch>(
|
||||
let mut bump_allocator = BumpAllocator::<A>::new(areas, 0);
|
||||
|
||||
{
|
||||
let mut mapper = PageMapper::<A, _>::create(
|
||||
TableKind::Kernel,
|
||||
&mut bump_allocator
|
||||
).expect("failed to create Mapper");
|
||||
let mut mapper = PageMapper::<A, _>::create(TableKind::Kernel, &mut bump_allocator)
|
||||
.expect("failed to create Mapper");
|
||||
|
||||
// Pre-allocate all kernel PD entries so that when the page table is copied,
|
||||
// these entries are synced between processes
|
||||
for i in 512..1024 {
|
||||
let phys = mapper.allocator_mut().allocate_one().expect("failed to map page table");
|
||||
let phys = mapper
|
||||
.allocator_mut()
|
||||
.allocate_one()
|
||||
.expect("failed to map page table");
|
||||
let flags = A::ENTRY_FLAG_READWRITE | A::ENTRY_FLAG_DEFAULT_TABLE;
|
||||
mapper.table().set_entry(i, PageEntry::new(phys.data() | flags));
|
||||
mapper
|
||||
.table()
|
||||
.set_entry(i, PageEntry::new(phys.data() | flags));
|
||||
}
|
||||
|
||||
// Map all physical areas at PHYS_OFFSET
|
||||
@@ -105,11 +99,9 @@ unsafe fn inner<A: Arch>(
|
||||
let phys = area.base.add(i * A::PAGE_SIZE);
|
||||
let virt = A::phys_to_virt(phys);
|
||||
let flags = page_flags::<A>(virt);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
}
|
||||
@@ -119,19 +111,15 @@ unsafe fn inner<A: Arch>(
|
||||
let phys = PhysicalAddress::new(kernel_base + i * A::PAGE_SIZE);
|
||||
let virt = VirtualAddress::new(crate::KERNEL_OFFSET + i * A::PAGE_SIZE);
|
||||
let flags = page_flags::<A>(virt);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
|
||||
let virt = A::phys_to_virt(phys);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
|
||||
@@ -141,11 +129,9 @@ unsafe fn inner<A: Arch>(
|
||||
let phys = PhysicalAddress::new(base + i * A::PAGE_SIZE);
|
||||
let virt = A::phys_to_virt(phys);
|
||||
let flags = page_flags::<A>(virt);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
};
|
||||
@@ -158,8 +144,8 @@ unsafe fn inner<A: Arch>(
|
||||
// Ensure graphical debug region remains paged
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
{
|
||||
use crate::devices::graphical_debug::FRAMEBUFFER;
|
||||
use super::paging::entry::EntryFlags;
|
||||
use crate::devices::graphical_debug::FRAMEBUFFER;
|
||||
|
||||
let (phys, virt, size) = *FRAMEBUFFER.lock();
|
||||
|
||||
@@ -167,14 +153,13 @@ unsafe fn inner<A: Arch>(
|
||||
for i in 0..pages {
|
||||
let phys = PhysicalAddress::new(phys + i * A::PAGE_SIZE);
|
||||
let virt = VirtualAddress::new(virt + i * A::PAGE_SIZE);
|
||||
let flags = PageFlags::new().write(true)
|
||||
let flags = PageFlags::new()
|
||||
.write(true)
|
||||
// Write combining flag
|
||||
.custom_flag(EntryFlags::HUGE_PAGE.bits(), true);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
}
|
||||
@@ -194,7 +179,10 @@ unsafe fn inner<A: Arch>(
|
||||
|
||||
// Create the physical memory map
|
||||
let offset = bump_allocator.offset();
|
||||
log::info!("Permanently used: {} KB", (offset + (KILOBYTE - 1)) / KILOBYTE);
|
||||
log::info!(
|
||||
"Permanently used: {} KB",
|
||||
(offset + (KILOBYTE - 1)) / KILOBYTE
|
||||
);
|
||||
|
||||
BuddyAllocator::<A>::new(bump_allocator).expect("failed to create BuddyAllocator")
|
||||
}
|
||||
@@ -238,10 +226,12 @@ impl core::fmt::Debug for LockedAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
static AREAS: SyncUnsafeCell<[MemoryArea; 512]> = SyncUnsafeCell::new([MemoryArea {
|
||||
base: PhysicalAddress::new(0),
|
||||
size: 0,
|
||||
}; 512]);
|
||||
static AREAS: SyncUnsafeCell<[MemoryArea; 512]> = SyncUnsafeCell::new(
|
||||
[MemoryArea {
|
||||
base: PhysicalAddress::new(0),
|
||||
size: 0,
|
||||
}; 512],
|
||||
);
|
||||
static AREA_COUNT: SyncUnsafeCell<u16> = SyncUnsafeCell::new(0);
|
||||
|
||||
pub fn areas() -> &'static [MemoryArea] {
|
||||
@@ -271,7 +261,12 @@ pub struct KernelMapper {
|
||||
impl KernelMapper {
|
||||
fn lock_inner(current_processor: usize) -> bool {
|
||||
loop {
|
||||
match LOCK_OWNER.compare_exchange_weak(NO_PROCESSOR, current_processor, Ordering::Acquire, Ordering::Relaxed) {
|
||||
match LOCK_OWNER.compare_exchange_weak(
|
||||
NO_PROCESSOR,
|
||||
current_processor,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => break,
|
||||
// already owned by this hardware thread
|
||||
Err(id) if id == current_processor => break,
|
||||
@@ -285,15 +280,20 @@ impl KernelMapper {
|
||||
|
||||
prev_count > 0
|
||||
}
|
||||
pub unsafe fn lock_for_manual_mapper(current_processor: LogicalCpuId, mapper: crate::paging::PageMapper) -> Self {
|
||||
pub unsafe fn lock_for_manual_mapper(
|
||||
current_processor: LogicalCpuId,
|
||||
mapper: crate::paging::PageMapper,
|
||||
) -> Self {
|
||||
let ro = Self::lock_inner(current_processor.get() as usize);
|
||||
Self {
|
||||
mapper,
|
||||
ro,
|
||||
}
|
||||
Self { mapper, ro }
|
||||
}
|
||||
pub fn lock_manually(current_processor: LogicalCpuId) -> Self {
|
||||
unsafe { Self::lock_for_manual_mapper(current_processor, PageMapper::current(TableKind::Kernel, FRAME_ALLOCATOR)) }
|
||||
unsafe {
|
||||
Self::lock_for_manual_mapper(
|
||||
current_processor,
|
||||
PageMapper::current(TableKind::Kernel, FRAME_ALLOCATOR),
|
||||
)
|
||||
}
|
||||
}
|
||||
pub fn lock() -> Self {
|
||||
Self::lock_manually(crate::cpu_id())
|
||||
@@ -328,12 +328,18 @@ impl Drop for KernelMapper {
|
||||
}
|
||||
|
||||
pub unsafe fn init(
|
||||
kernel_base: usize, kernel_size: usize,
|
||||
stack_base: usize, stack_size: usize,
|
||||
env_base: usize, env_size: usize,
|
||||
acpi_base: usize, acpi_size: usize,
|
||||
areas_base: usize, areas_size: usize,
|
||||
initfs_base: usize, initfs_size: usize,
|
||||
kernel_base: usize,
|
||||
kernel_size: usize,
|
||||
stack_base: usize,
|
||||
stack_size: usize,
|
||||
env_base: usize,
|
||||
env_size: usize,
|
||||
acpi_base: usize,
|
||||
acpi_size: usize,
|
||||
areas_base: usize,
|
||||
areas_size: usize,
|
||||
initfs_base: usize,
|
||||
initfs_size: usize,
|
||||
) {
|
||||
type A = RmmA;
|
||||
|
||||
@@ -341,26 +347,26 @@ pub unsafe fn init(
|
||||
let real_size = 0x100000;
|
||||
let real_end = real_base + real_size;
|
||||
|
||||
let kernel_size_aligned = ((kernel_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let kernel_size_aligned = ((kernel_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let kernel_end = kernel_base + kernel_size_aligned;
|
||||
|
||||
let stack_size_aligned = ((stack_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let stack_size_aligned = ((stack_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let stack_end = stack_base + stack_size_aligned;
|
||||
|
||||
let env_size_aligned = ((env_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let env_size_aligned = ((env_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let env_end = env_base + env_size_aligned;
|
||||
|
||||
let acpi_size_aligned = ((acpi_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let acpi_size_aligned = ((acpi_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let acpi_end = acpi_base + acpi_size_aligned;
|
||||
|
||||
let initfs_size_aligned = ((initfs_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let initfs_size_aligned = ((initfs_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let initfs_end = initfs_base + initfs_size_aligned;
|
||||
|
||||
let areas = &mut *AREAS.get();
|
||||
|
||||
let bootloader_areas = slice::from_raw_parts(
|
||||
areas_base as *const BootloaderMemoryEntry,
|
||||
areas_size / mem::size_of::<BootloaderMemoryEntry>()
|
||||
areas_size / mem::size_of::<BootloaderMemoryEntry>(),
|
||||
);
|
||||
|
||||
// Copy memory map from bootloader location, and page align it
|
||||
@@ -393,44 +399,86 @@ pub unsafe fn init(
|
||||
|
||||
// Ensure real-mode areas are not used
|
||||
if base < real_end && base + size > real_base {
|
||||
log::warn!("{:X}:{:X} overlaps with real mode {:X}:{:X}", base, size, real_base, real_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with real mode {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
real_base,
|
||||
real_size
|
||||
);
|
||||
new_base = cmp::max(new_base, real_end);
|
||||
}
|
||||
|
||||
// Ensure kernel areas are not used
|
||||
if base < kernel_end && base + size > kernel_base {
|
||||
log::warn!("{:X}:{:X} overlaps with kernel {:X}:{:X}", base, size, kernel_base, kernel_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with kernel {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
kernel_base,
|
||||
kernel_size
|
||||
);
|
||||
new_base = cmp::max(new_base, kernel_end);
|
||||
}
|
||||
|
||||
// Ensure stack areas are not used
|
||||
if base < stack_end && base + size > stack_base {
|
||||
log::warn!("{:X}:{:X} overlaps with stack {:X}:{:X}", base, size, stack_base, stack_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with stack {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
stack_base,
|
||||
stack_size
|
||||
);
|
||||
new_base = cmp::max(new_base, stack_end);
|
||||
}
|
||||
|
||||
// Ensure env areas are not used
|
||||
if base < env_end && base + size > env_base {
|
||||
log::warn!("{:X}:{:X} overlaps with env {:X}:{:X}", base, size, env_base, env_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with env {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
env_base,
|
||||
env_size
|
||||
);
|
||||
new_base = cmp::max(new_base, env_end);
|
||||
}
|
||||
|
||||
// Ensure acpi areas are not used
|
||||
if base < acpi_end && base + size > acpi_base {
|
||||
log::warn!("{:X}:{:X} overlaps with acpi {:X}:{:X}", base, size, acpi_base, acpi_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with acpi {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
acpi_base,
|
||||
acpi_size
|
||||
);
|
||||
new_base = cmp::max(new_base, acpi_end);
|
||||
}
|
||||
|
||||
// Ensure initfs areas are not used
|
||||
if base < initfs_end && base + size > initfs_base {
|
||||
log::warn!("{:X}:{:X} overlaps with initfs {:X}:{:X}", base, size, initfs_base, initfs_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with initfs {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
initfs_base,
|
||||
initfs_size
|
||||
);
|
||||
new_base = cmp::max(new_base, initfs_end);
|
||||
}
|
||||
|
||||
if new_base != base {
|
||||
let end = base + size;
|
||||
let new_size = end.checked_sub(new_base).unwrap_or(0);
|
||||
log::info!("{:X}:{:X} moved to {:X}:{:X}", base, size, new_base, new_size);
|
||||
log::info!(
|
||||
"{:X}:{:X} moved to {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
new_base,
|
||||
new_size
|
||||
);
|
||||
base = new_base;
|
||||
size = new_size;
|
||||
}
|
||||
@@ -443,7 +491,13 @@ pub unsafe fn init(
|
||||
size = 0; // Skip area
|
||||
} else if base + size > physmap_size {
|
||||
let new_size = physmap_size.checked_sub(base).unwrap_or(0);
|
||||
log::warn!("{:X}:{:X} outside of physmap, moved to {:X}:{:X}", base, size, base, new_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} outside of physmap, moved to {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
base,
|
||||
new_size
|
||||
);
|
||||
size = new_size;
|
||||
}
|
||||
|
||||
@@ -454,8 +508,18 @@ pub unsafe fn init(
|
||||
let other_end = other_base + other.size;
|
||||
if base < other_end && base + size > other_base {
|
||||
let new_base = cmp::min(base, other_base);
|
||||
let new_size = cmp::max(base + size, other_end).checked_sub(new_base).unwrap_or(0);
|
||||
log::warn!("{:X}:{:X} overlaps with area {:X}:{:X}, combining into {:X}:{:X}", base, size, other_base, other.size, new_base, new_size);
|
||||
let new_size = cmp::max(base + size, other_end)
|
||||
.checked_sub(new_base)
|
||||
.unwrap_or(0);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with area {:X}:{:X}, combining into {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
other_base,
|
||||
other.size,
|
||||
new_base,
|
||||
new_size
|
||||
);
|
||||
areas[other_i].base = PhysicalAddress::new(new_base);
|
||||
areas[other_i].size = new_size;
|
||||
size = 0; // Skip area
|
||||
@@ -475,11 +539,16 @@ pub unsafe fn init(
|
||||
|
||||
let allocator = inner::<A>(
|
||||
areas,
|
||||
kernel_base, kernel_size_aligned,
|
||||
stack_base, stack_size_aligned,
|
||||
env_base, env_size_aligned,
|
||||
acpi_base, acpi_size_aligned,
|
||||
initfs_base, initfs_size_aligned,
|
||||
kernel_base,
|
||||
kernel_size_aligned,
|
||||
stack_base,
|
||||
stack_size_aligned,
|
||||
env_base,
|
||||
env_size_aligned,
|
||||
acpi_base,
|
||||
acpi_size_aligned,
|
||||
initfs_base,
|
||||
initfs_size_aligned,
|
||||
);
|
||||
*INNER_ALLOCATOR.lock() = Some(allocator);
|
||||
}
|
||||
|
||||
+70
-31
@@ -2,24 +2,22 @@
|
||||
/// It is increcibly unsafe, and should be minimal in nature
|
||||
/// It must create the IDT with the correct entries, those entries are
|
||||
/// defined in other files inside of the `arch` module
|
||||
|
||||
use core::slice;
|
||||
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering, AtomicU32};
|
||||
use core::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering};
|
||||
|
||||
use crate::{allocator, LogicalCpuId};
|
||||
#[cfg(feature = "acpi")]
|
||||
use crate::acpi;
|
||||
use crate::arch::pti;
|
||||
use crate::arch::flags::*;
|
||||
use crate::device;
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
use crate::devices::graphical_debug;
|
||||
use crate::gdt;
|
||||
use crate::idt;
|
||||
use crate::interrupt;
|
||||
use crate::log::{self, info};
|
||||
use crate::memory;
|
||||
use crate::paging::{self, KernelMapper, PhysicalAddress, RmmA, RmmArch, TableKind};
|
||||
use crate::{
|
||||
allocator,
|
||||
arch::{flags::*, pti},
|
||||
device, gdt, idt, interrupt,
|
||||
log::{self, info},
|
||||
memory,
|
||||
paging::{self, KernelMapper, PhysicalAddress, RmmA, RmmArch, TableKind},
|
||||
LogicalCpuId,
|
||||
};
|
||||
|
||||
/// Test of zero values in BSS.
|
||||
static BSS_TEST_ZERO: usize = 0;
|
||||
@@ -68,7 +66,7 @@ pub struct KernelArgs {
|
||||
|
||||
/// The entry to Rust, all things must be initialized
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
let bootstrap = {
|
||||
let args = args_ptr.read();
|
||||
|
||||
@@ -82,7 +80,10 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
KERNEL_SIZE.store(args.kernel_size as usize, Ordering::SeqCst);
|
||||
|
||||
// Convert env to slice
|
||||
let env = slice::from_raw_parts((args.env_base as usize + crate::PHYS_OFFSET) as *const u8, args.env_size as usize);
|
||||
let env = slice::from_raw_parts(
|
||||
(args.env_base as usize + crate::PHYS_OFFSET) as *const u8,
|
||||
args.env_size as usize,
|
||||
);
|
||||
|
||||
// Set up graphical debug
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
@@ -104,12 +105,36 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
});
|
||||
|
||||
info!("Redox OS starting...");
|
||||
info!("Kernel: {:X}:{:X}", { args.kernel_base }, { args.kernel_base } + { args.kernel_size });
|
||||
info!("Stack: {:X}:{:X}", { args.stack_base }, { args.stack_base } + { args.stack_size });
|
||||
info!("Env: {:X}:{:X}", { args.env_base }, { args.env_base } + { args.env_size });
|
||||
info!("RSDPs: {:X}:{:X}", { args.acpi_rsdps_base }, { args.acpi_rsdps_base } + { args.acpi_rsdps_size });
|
||||
info!("Areas: {:X}:{:X}", { args.areas_base }, { args.areas_base } + { args.areas_size });
|
||||
info!("Bootstrap: {:X}:{:X}", { args.bootstrap_base }, { args.bootstrap_base } + { args.bootstrap_size });
|
||||
info!(
|
||||
"Kernel: {:X}:{:X}",
|
||||
{ args.kernel_base },
|
||||
{ args.kernel_base } + { args.kernel_size }
|
||||
);
|
||||
info!(
|
||||
"Stack: {:X}:{:X}",
|
||||
{ args.stack_base },
|
||||
{ args.stack_base } + { args.stack_size }
|
||||
);
|
||||
info!(
|
||||
"Env: {:X}:{:X}",
|
||||
{ args.env_base },
|
||||
{ args.env_base } + { args.env_size }
|
||||
);
|
||||
info!(
|
||||
"RSDPs: {:X}:{:X}",
|
||||
{ args.acpi_rsdps_base },
|
||||
{ args.acpi_rsdps_base } + { args.acpi_rsdps_size }
|
||||
);
|
||||
info!(
|
||||
"Areas: {:X}:{:X}",
|
||||
{ args.areas_base },
|
||||
{ args.areas_base } + { args.areas_size }
|
||||
);
|
||||
info!(
|
||||
"Bootstrap: {:X}:{:X}",
|
||||
{ args.bootstrap_base },
|
||||
{ args.bootstrap_base } + { args.bootstrap_size }
|
||||
);
|
||||
info!("Bootstrap entry point: {:X}", { args.bootstrap_entry });
|
||||
|
||||
// Set up GDT before paging
|
||||
@@ -120,18 +145,27 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
|
||||
// Initialize RMM
|
||||
crate::arch::rmm::init(
|
||||
args.kernel_base as usize, args.kernel_size as usize,
|
||||
args.stack_base as usize, args.stack_size as usize,
|
||||
args.env_base as usize, args.env_size as usize,
|
||||
args.acpi_rsdps_base as usize, args.acpi_rsdps_size as usize,
|
||||
args.areas_base as usize, args.areas_size as usize,
|
||||
args.bootstrap_base as usize, args.bootstrap_size as usize,
|
||||
args.kernel_base as usize,
|
||||
args.kernel_size as usize,
|
||||
args.stack_base as usize,
|
||||
args.stack_size as usize,
|
||||
args.env_base as usize,
|
||||
args.env_size as usize,
|
||||
args.acpi_rsdps_base as usize,
|
||||
args.acpi_rsdps_size as usize,
|
||||
args.areas_base as usize,
|
||||
args.areas_size as usize,
|
||||
args.bootstrap_base as usize,
|
||||
args.bootstrap_size as usize,
|
||||
);
|
||||
// Initialize paging
|
||||
paging::init();
|
||||
|
||||
// Set up GDT after paging with TLS
|
||||
gdt::init_paging(args.stack_base as usize + args.stack_size as usize, LogicalCpuId::BSP);
|
||||
gdt::init_paging(
|
||||
args.stack_base as usize + args.stack_size as usize,
|
||||
LogicalCpuId::BSP,
|
||||
);
|
||||
|
||||
// Set up IDT
|
||||
idt::init_paging_bsp();
|
||||
@@ -163,7 +197,10 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
#[cfg(feature = "acpi")]
|
||||
{
|
||||
acpi::init(if args.acpi_rsdps_base != 0 && args.acpi_rsdps_size > 0 {
|
||||
Some(((args.acpi_rsdps_base as usize + crate::PHYS_OFFSET) as u64, args.acpi_rsdps_size as u64))
|
||||
Some((
|
||||
(args.acpi_rsdps_base as usize + crate::PHYS_OFFSET) as u64,
|
||||
args.acpi_rsdps_size as u64,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
});
|
||||
@@ -183,7 +220,9 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
BSP_READY.store(true, Ordering::SeqCst);
|
||||
|
||||
crate::Bootstrap {
|
||||
base: crate::memory::Frame::containing_address(crate::paging::PhysicalAddress::new(args.bootstrap_base as usize)),
|
||||
base: crate::memory::Frame::containing_address(crate::paging::PhysicalAddress::new(
|
||||
args.bootstrap_base as usize,
|
||||
)),
|
||||
page_count: (args.bootstrap_size as usize) / crate::memory::PAGE_SIZE,
|
||||
entry: args.bootstrap_entry as usize,
|
||||
env,
|
||||
@@ -202,7 +241,7 @@ pub struct KernelArgsAp {
|
||||
}
|
||||
|
||||
/// Entry to rust for an AP
|
||||
pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
|
||||
pub unsafe extern "C" fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
|
||||
let cpu_id = {
|
||||
let args = &*args_ptr;
|
||||
let cpu_id = LogicalCpuId::new(args.cpu_id as u32);
|
||||
@@ -240,7 +279,7 @@ pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
|
||||
cpu_id
|
||||
};
|
||||
|
||||
while ! BSP_READY.load(Ordering::SeqCst) {
|
||||
while !BSP_READY.load(Ordering::SeqCst) {
|
||||
interrupt::pause();
|
||||
}
|
||||
|
||||
|
||||
+9
-10
@@ -1,14 +1,10 @@
|
||||
#[cfg(feature = "acpi")]
|
||||
use crate::{
|
||||
context,
|
||||
scheme::acpi,
|
||||
time,
|
||||
};
|
||||
use crate::{context, scheme::acpi, time};
|
||||
|
||||
use crate::syscall::io::{Io, Pio};
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn kreset() -> ! {
|
||||
pub unsafe extern "C" fn kreset() -> ! {
|
||||
println!("kreset");
|
||||
|
||||
// 8042 reset
|
||||
@@ -24,11 +20,14 @@ pub unsafe extern fn kreset() -> ! {
|
||||
|
||||
pub unsafe fn emergency_reset() -> ! {
|
||||
// Use triple fault to guarantee reset
|
||||
core::arch::asm!("
|
||||
core::arch::asm!(
|
||||
"
|
||||
cli
|
||||
lidt cs:0
|
||||
int $3
|
||||
", options(noreturn));
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
@@ -36,7 +35,7 @@ fn userspace_acpi_shutdown() {
|
||||
log::info!("Notifying any potential ACPI driver");
|
||||
// Tell whatever driver that handles ACPI, that it should enter the S5 state (i.e.
|
||||
// shutdown).
|
||||
if ! acpi::register_kstop() {
|
||||
if !acpi::register_kstop() {
|
||||
// There was no context to switch to.
|
||||
log::info!("No ACPI driver was alive to handle shutdown.");
|
||||
return;
|
||||
@@ -63,7 +62,7 @@ fn userspace_acpi_shutdown() {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn kstop() -> ! {
|
||||
pub unsafe extern "C" fn kstop() -> ! {
|
||||
log::info!("Running kstop()");
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
|
||||
@@ -5,9 +5,11 @@ use core::mem::size_of;
|
||||
use spin::Once;
|
||||
use x86::controlregs::{Cr4, Xcr0};
|
||||
|
||||
use crate::context::memory::PageSpan;
|
||||
use crate::cpuid::{has_ext_feat, cpuid_always, feature_info};
|
||||
use crate::paging::{KernelMapper, Page, PageFlags, PAGE_SIZE, VirtualAddress};
|
||||
use crate::{
|
||||
context::memory::PageSpan,
|
||||
cpuid::{cpuid_always, feature_info, has_ext_feat},
|
||||
paging::{KernelMapper, Page, PageFlags, VirtualAddress, PAGE_SIZE},
|
||||
};
|
||||
|
||||
#[cfg(all(cpu_feature_never = "xsave", not(cpu_feature_never = "xsaveopt")))]
|
||||
compile_error!("cannot force-disable xsave without force-disabling xsaveopt");
|
||||
@@ -31,7 +33,10 @@ pub unsafe fn early_init(bsp: bool) {
|
||||
let relocs_size = crate::kernel_executable_offsets::__altrelocs_end() - relocs_offset;
|
||||
|
||||
assert_eq!(relocs_size % size_of::<AltReloc>(), 0);
|
||||
let relocs = core::slice::from_raw_parts(relocs_offset as *const AltReloc, relocs_size / size_of::<AltReloc>());
|
||||
let relocs = core::slice::from_raw_parts(
|
||||
relocs_offset as *const AltReloc,
|
||||
relocs_size / size_of::<AltReloc>(),
|
||||
);
|
||||
|
||||
let mut enable = KcpuFeatures::empty();
|
||||
|
||||
@@ -62,12 +67,16 @@ pub unsafe fn early_init(bsp: bool) {
|
||||
|
||||
#[cfg(not(cpu_feature_never = "xsave"))]
|
||||
if feature_info().has_xsave() {
|
||||
use raw_cpuid::{ExtendedRegisterType, ExtendedRegisterStateLocation};
|
||||
use raw_cpuid::{ExtendedRegisterStateLocation, ExtendedRegisterType};
|
||||
|
||||
x86::controlregs::cr4_write(x86::controlregs::cr4() | x86::controlregs::Cr4::CR4_ENABLE_OS_XSAVE);
|
||||
x86::controlregs::cr4_write(
|
||||
x86::controlregs::cr4() | x86::controlregs::Cr4::CR4_ENABLE_OS_XSAVE,
|
||||
);
|
||||
|
||||
let mut xcr0 = Xcr0::XCR0_FPU_MMX_STATE | Xcr0::XCR0_SSE_STATE;
|
||||
let ext_state_info = cpuid_always().get_extended_state_info().expect("must be present if XSAVE is supported");
|
||||
let ext_state_info = cpuid_always()
|
||||
.get_extended_state_info()
|
||||
.expect("must be present if XSAVE is supported");
|
||||
|
||||
enable |= KcpuFeatures::XSAVE;
|
||||
enable.set(KcpuFeatures::XSAVEOPT, ext_state_info.has_xsaveopt());
|
||||
@@ -77,10 +86,13 @@ pub unsafe fn early_init(bsp: bool) {
|
||||
xcr0 |= Xcr0::XCR0_AVX_STATE;
|
||||
x86::controlregs::xcr0_write(xcr0);
|
||||
|
||||
let state = ext_state_info.iter().find(|state| {
|
||||
state.register() == ExtendedRegisterType::Avx
|
||||
&& state.location() == ExtendedRegisterStateLocation::Xcr0
|
||||
}).expect("CPUID said AVX was supported but there's no state info");
|
||||
let state = ext_state_info
|
||||
.iter()
|
||||
.find(|state| {
|
||||
state.register() == ExtendedRegisterType::Avx
|
||||
&& state.location() == ExtendedRegisterStateLocation::Xcr0
|
||||
})
|
||||
.expect("CPUID said AVX was supported but there's no state info");
|
||||
|
||||
if state.size() as usize != 16 * core::mem::size_of::<u128>() {
|
||||
log::warn!("Unusual AVX state size {}", state.size());
|
||||
@@ -123,20 +135,37 @@ pub unsafe fn early_init(bsp: bool) {
|
||||
unsafe fn overwrite(relocs: &[AltReloc], enable: KcpuFeatures) {
|
||||
let mut mapper = KernelMapper::lock();
|
||||
for reloc in relocs.iter().copied() {
|
||||
let name = core::str::from_utf8(core::slice::from_raw_parts(reloc.name_start, reloc.name_len)).expect("invalid feature name");
|
||||
let name = core::str::from_utf8(core::slice::from_raw_parts(
|
||||
reloc.name_start,
|
||||
reloc.name_len,
|
||||
))
|
||||
.expect("invalid feature name");
|
||||
let altcode = core::slice::from_raw_parts(reloc.altcode_start, reloc.altcode_len);
|
||||
|
||||
let dst_pages = PageSpan::between(
|
||||
Page::containing_address(VirtualAddress::new(reloc.code_start as usize)),
|
||||
Page::containing_address(VirtualAddress::new((reloc.code_start as usize + reloc.origcode_len).next_multiple_of(PAGE_SIZE))),
|
||||
Page::containing_address(VirtualAddress::new(
|
||||
(reloc.code_start as usize + reloc.origcode_len).next_multiple_of(PAGE_SIZE),
|
||||
)),
|
||||
);
|
||||
for page in dst_pages.pages() {
|
||||
mapper.remap(page.start_address(), PageFlags::new().write(true).execute(true).global(true)).unwrap().flush();
|
||||
mapper
|
||||
.remap(
|
||||
page.start_address(),
|
||||
PageFlags::new().write(true).execute(true).global(true),
|
||||
)
|
||||
.unwrap()
|
||||
.flush();
|
||||
}
|
||||
|
||||
let code = core::slice::from_raw_parts_mut(reloc.code_start, reloc.padded_len);
|
||||
|
||||
log::trace!("feature {} current {:x?} altcode {:x?}", name, code, altcode);
|
||||
log::trace!(
|
||||
"feature {} current {:x?} altcode {:x?}",
|
||||
name,
|
||||
code,
|
||||
altcode
|
||||
);
|
||||
|
||||
let feature_is_enabled = match name {
|
||||
"smap" => enable.contains(KcpuFeatures::SMAP),
|
||||
@@ -170,7 +199,9 @@ unsafe fn overwrite(relocs: &[AltReloc], enable: KcpuFeatures) {
|
||||
&[0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
&[0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
&[0x66, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
&[0x66, 0x66, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
&[
|
||||
0x66, 0x66, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
],
|
||||
];
|
||||
|
||||
for chunk in dst_nops.chunks_mut(NOPS_TABLE.len()) {
|
||||
@@ -179,7 +210,13 @@ unsafe fn overwrite(relocs: &[AltReloc], enable: KcpuFeatures) {
|
||||
log::trace!("feature {} new {:x?} altcode {:x?}", name, code, altcode);
|
||||
|
||||
for page in dst_pages.pages() {
|
||||
mapper.remap(page.start_address(), PageFlags::new().write(false).execute(true).global(true)).unwrap().flush();
|
||||
mapper
|
||||
.remap(
|
||||
page.start_address(),
|
||||
PageFlags::new().write(false).execute(true).global(true),
|
||||
)
|
||||
.unwrap()
|
||||
.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,7 +245,7 @@ mod xsave {
|
||||
pub ymm_upper_offset: Option<u32>,
|
||||
pub xsave_size: u32,
|
||||
}
|
||||
pub(in super) static XSAVE_INFO: Once<XsaveInfo> = Once::new();
|
||||
pub(super) static XSAVE_INFO: Once<XsaveInfo> = Once::new();
|
||||
|
||||
pub fn info() -> Option<&'static XsaveInfo> {
|
||||
XSAVE_INFO.get()
|
||||
|
||||
@@ -15,18 +15,18 @@ pub const PML4_MASK: usize = 0x0000_ff80_0000_0000;
|
||||
/// Offset of kernel
|
||||
pub const KERNEL_MAX_SIZE: usize = 1_usize << 31;
|
||||
pub const KERNEL_OFFSET: usize = KERNEL_MAX_SIZE.wrapping_neg();
|
||||
pub const KERNEL_PML4: usize = (KERNEL_OFFSET & PML4_MASK)/PML4_SIZE;
|
||||
pub const KERNEL_PML4: usize = (KERNEL_OFFSET & PML4_MASK) / PML4_SIZE;
|
||||
|
||||
/// Offset to kernel heap
|
||||
pub const KERNEL_HEAP_OFFSET: usize = KERNEL_OFFSET - PML4_SIZE;
|
||||
pub const KERNEL_HEAP_PML4: usize = (KERNEL_HEAP_OFFSET & PML4_MASK)/PML4_SIZE;
|
||||
pub const KERNEL_HEAP_PML4: usize = (KERNEL_HEAP_OFFSET & PML4_MASK) / PML4_SIZE;
|
||||
/// Size of kernel heap
|
||||
pub const KERNEL_HEAP_SIZE: usize = 1 * 1024 * 1024; // 1 MB
|
||||
|
||||
/// Offset of physmap
|
||||
// This needs to match RMM's PHYS_OFFSET
|
||||
pub const PHYS_OFFSET: usize = 0xFFFF_8000_0000_0000;
|
||||
pub const PHYS_PML4: usize = (PHYS_OFFSET & PML4_MASK)/PML4_SIZE;
|
||||
pub const PHYS_PML4: usize = (PHYS_OFFSET & PML4_MASK) / PML4_SIZE;
|
||||
|
||||
/// End offset of the user image, i.e. kernel start
|
||||
pub const USER_END_OFFSET: usize = 256 * PML4_SIZE;
|
||||
|
||||
@@ -17,7 +17,9 @@ pub fn cpuid_always() -> CpuId {
|
||||
}
|
||||
|
||||
pub fn feature_info() -> FeatureInfo {
|
||||
cpuid_always().get_feature_info().expect("x86_64 requires CPUID leaf=0x01 to be present")
|
||||
cpuid_always()
|
||||
.get_feature_info()
|
||||
.expect("x86_64 requires CPUID leaf=0x01 to be present")
|
||||
}
|
||||
|
||||
pub fn has_ext_feat(feat: impl FnOnce(ExtendedFeatures) -> bool) -> bool {
|
||||
|
||||
+12
-12
@@ -3,24 +3,24 @@ use core::fmt;
|
||||
use spin::Mutex;
|
||||
use spin::MutexGuard;
|
||||
|
||||
use crate::log::{LOG, Log};
|
||||
#[cfg(feature = "qemu_debug")]
|
||||
use syscall::io::Io;
|
||||
#[cfg(any(feature = "qemu_debug", feature = "serial_debug"))]
|
||||
use crate::syscall::io::Pio;
|
||||
#[cfg(feature = "lpss_debug")]
|
||||
use crate::syscall::io::Mmio;
|
||||
#[cfg(any(feature = "lpss_debug", feature = "serial_debug"))]
|
||||
use crate::devices::uart_16550::SerialPort;
|
||||
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
use crate::devices::graphical_debug::{DEBUG_DISPLAY, DebugDisplay};
|
||||
use crate::log::{Log, LOG};
|
||||
#[cfg(feature = "lpss_debug")]
|
||||
use super::device::serial::LPSS;
|
||||
use crate::syscall::io::Mmio;
|
||||
#[cfg(any(feature = "qemu_debug", feature = "serial_debug"))]
|
||||
use crate::syscall::io::Pio;
|
||||
#[cfg(feature = "qemu_debug")]
|
||||
use syscall::io::Io;
|
||||
|
||||
#[cfg(feature = "serial_debug")]
|
||||
use super::device::serial::COM1;
|
||||
#[cfg(feature = "lpss_debug")]
|
||||
use super::device::serial::LPSS;
|
||||
#[cfg(feature = "system76_ec_debug")]
|
||||
use super::device::system76_ec::{SYSTEM76_EC, System76Ec};
|
||||
use super::device::system76_ec::{System76Ec, SYSTEM76_EC};
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
use crate::devices::graphical_debug::{DebugDisplay, DEBUG_DISPLAY};
|
||||
|
||||
#[cfg(feature = "qemu_debug")]
|
||||
pub static QEMU: Mutex<Pio<u8>> = Mutex::new(Pio::<u8>::new(0x402));
|
||||
|
||||
+234
-78
@@ -28,101 +28,257 @@ pub fn cpu_info<W: Write>(w: &mut W) -> Result {
|
||||
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_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_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_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_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_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_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_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 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_processor_and_feature_identifiers() {
|
||||
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_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 let Some(info) = cpuid.get_advanced_power_mgmt_info() {
|
||||
if info.has_invariant_tsc() { write!(w, " constant_tsc")? };
|
||||
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_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")? };
|
||||
if info.has_fpu_cs_ds_deprecated() {
|
||||
write!(w, " fpu_seg")?
|
||||
};
|
||||
if info.has_mpx() {
|
||||
write!(w, " mpx")?
|
||||
};
|
||||
}
|
||||
|
||||
writeln!(w)?;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::acpi::hpet::Hpet;
|
||||
use super::pit;
|
||||
use crate::acpi::hpet::Hpet;
|
||||
|
||||
const LEG_RT_CNF: u64 = 2;
|
||||
const ENABLE_CNF: u64 = 1;
|
||||
@@ -27,7 +27,8 @@ pub unsafe fn init(hpet: &mut Hpet) -> bool {
|
||||
{
|
||||
let mut config_word = hpet.base_address.read_u64(GENERAL_CONFIG_OFFSET);
|
||||
config_word &= !(LEG_RT_CNF | ENABLE_CNF);
|
||||
hpet.base_address.write_u64(GENERAL_CONFIG_OFFSET, config_word);
|
||||
hpet.base_address
|
||||
.write_u64(GENERAL_CONFIG_OFFSET, config_word);
|
||||
}
|
||||
|
||||
let capability = hpet.base_address.read_u64(CAPABILITY_OFFSET);
|
||||
@@ -48,9 +49,11 @@ pub unsafe fn init(hpet: &mut Hpet) -> bool {
|
||||
let counter = hpet.base_address.read_u64(MAIN_COUNTER_OFFSET);
|
||||
|
||||
let t0_config_word: u64 = TN_VAL_SET_CNF | TN_TYPE_CNF | TN_INT_ENB_CNF;
|
||||
hpet.base_address.write_u64(T0_CONFIG_CAPABILITY_OFFSET, t0_config_word);
|
||||
hpet.base_address
|
||||
.write_u64(T0_CONFIG_CAPABILITY_OFFSET, t0_config_word);
|
||||
// set accumulator value
|
||||
hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, counter + divisor);
|
||||
hpet.base_address
|
||||
.write_u64(T0_COMPARATOR_OFFSET, counter + divisor);
|
||||
// set interval
|
||||
hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, divisor);
|
||||
|
||||
@@ -58,7 +61,8 @@ pub unsafe fn init(hpet: &mut Hpet) -> bool {
|
||||
{
|
||||
let mut config_word: u64 = hpet.base_address.read_u64(GENERAL_CONFIG_OFFSET);
|
||||
config_word |= LEG_RT_CNF | ENABLE_CNF;
|
||||
hpet.base_address.write_u64(GENERAL_CONFIG_OFFSET, config_word);
|
||||
hpet.base_address
|
||||
.write_u64(GENERAL_CONFIG_OFFSET, config_word);
|
||||
}
|
||||
|
||||
println!("HPET After Init");
|
||||
@@ -76,7 +80,10 @@ pub unsafe fn debug(hpet: &mut Hpet) {
|
||||
println!(" clock period: {}", (capability >> 32) as u32);
|
||||
println!(" ID: {:#x}", (capability >> 16) as u16);
|
||||
println!(" LEG_RT_CAP: {}", capability & (1 << 15) == (1 << 15));
|
||||
println!(" COUNT_SIZE_CAP: {}", capability & (1 << 13) == (1 << 13));
|
||||
println!(
|
||||
" COUNT_SIZE_CAP: {}",
|
||||
capability & (1 << 13) == (1 << 13)
|
||||
);
|
||||
println!(" timers: {}", (capability >> 8) as u8 & 0x1F);
|
||||
println!(" revision: {}", capability as u8);
|
||||
}
|
||||
@@ -92,7 +99,10 @@ pub unsafe fn debug(hpet: &mut Hpet) {
|
||||
|
||||
let t0_capabilities = hpet.base_address.read_u64(T0_CONFIG_CAPABILITY_OFFSET);
|
||||
println!(" T0 caps: {:#x}", t0_capabilities);
|
||||
println!(" interrupt routing: {:#x}", (t0_capabilities >> 32) as u32);
|
||||
println!(
|
||||
" interrupt routing: {:#x}",
|
||||
(t0_capabilities >> 32) as u32
|
||||
);
|
||||
println!(" flags: {:#x}", t0_capabilities as u16);
|
||||
|
||||
let t0_comparator = hpet.base_address.read_u64(T0_COMPARATOR_OFFSET);
|
||||
|
||||
@@ -4,15 +4,15 @@ use alloc::vec::Vec;
|
||||
use spin::Mutex;
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
use crate::acpi::madt::{self, Madt, MadtEntry, MadtIoApic, MadtIntSrcOverride};
|
||||
use crate::acpi::madt::{self, Madt, MadtEntry, MadtIntSrcOverride, MadtIoApic};
|
||||
|
||||
use crate::arch::interrupt::irq;
|
||||
use crate::memory::Frame;
|
||||
use crate::paging::{KernelMapper, Page, PageFlags, PhysicalAddress, RmmA, RmmArch};
|
||||
use crate::paging::entry::EntryFlags;
|
||||
use crate::{
|
||||
arch::interrupt::irq,
|
||||
memory::Frame,
|
||||
paging::{entry::EntryFlags, KernelMapper, Page, PageFlags, PhysicalAddress, RmmA, RmmArch},
|
||||
};
|
||||
|
||||
use super::super::cpuid::cpuid;
|
||||
use super::pic;
|
||||
use super::{super::cpuid::cpuid, pic};
|
||||
|
||||
pub struct IoApicRegs {
|
||||
pointer: *const u32,
|
||||
@@ -131,12 +131,12 @@ pub enum DestinationMode {
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum DeliveryMode {
|
||||
Fixed = 0b000,
|
||||
LowestPriority = 0b001,
|
||||
Smi = 0b010,
|
||||
Nmi = 0b100,
|
||||
Init = 0b101,
|
||||
ExtInt = 0b111,
|
||||
Fixed = 0b000,
|
||||
LowestPriority = 0b001,
|
||||
Smi = 0b010,
|
||||
Nmi = 0b100,
|
||||
Init = 0b101,
|
||||
ExtInt = 0b111,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@@ -176,7 +176,9 @@ impl fmt::Debug for IoApic {
|
||||
let mut guard = self.0.lock();
|
||||
|
||||
let count = guard.max_redirection_table_entries();
|
||||
f.debug_list().entries((0..count).map(|i| guard.read_ioredtbl(i))).finish()
|
||||
f.debug_list()
|
||||
.entries((0..count).map(|i| guard.read_ioredtbl(i)))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,14 +221,10 @@ static mut IOAPICS: Option<Vec<IoApic>> = None;
|
||||
static mut SRC_OVERRIDES: Option<Vec<Override>> = None;
|
||||
|
||||
pub fn ioapics() -> &'static [IoApic] {
|
||||
unsafe {
|
||||
IOAPICS.as_ref().map_or(&[], |vector| &vector[..])
|
||||
}
|
||||
unsafe { IOAPICS.as_ref().map_or(&[], |vector| &vector[..]) }
|
||||
}
|
||||
pub fn src_overrides() -> &'static [Override] {
|
||||
unsafe {
|
||||
SRC_OVERRIDES.as_ref().map_or(&[], |vector| &vector[..])
|
||||
}
|
||||
unsafe { SRC_OVERRIDES.as_ref().map_or(&[], |vector| &vector[..]) }
|
||||
}
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
@@ -241,14 +239,24 @@ pub unsafe fn handle_ioapic(mapper: &mut KernelMapper, madt_ioapic: &'static Mad
|
||||
mapper
|
||||
.get_mut()
|
||||
.expect("expected KernelMapper not to be locked re-entrant while mapping I/O APIC memory")
|
||||
.map_phys(page.start_address(), frame.start_address(), PageFlags::new().write(true).custom_flag(EntryFlags::NO_CACHE.bits(), true))
|
||||
.map_phys(
|
||||
page.start_address(),
|
||||
frame.start_address(),
|
||||
PageFlags::new()
|
||||
.write(true)
|
||||
.custom_flag(EntryFlags::NO_CACHE.bits(), true),
|
||||
)
|
||||
.expect("failed to map I/O APIC")
|
||||
.flush();
|
||||
|
||||
let ioapic_registers = page.start_address().data() as *const u32;
|
||||
let ioapic = IoApic::new(ioapic_registers, madt_ioapic.gsi_base);
|
||||
|
||||
assert_eq!(ioapic.regs.lock().id(), madt_ioapic.id, "mismatched ACPI MADT I/O APIC ID, and the ID reported by the I/O APIC");
|
||||
assert_eq!(
|
||||
ioapic.regs.lock().id(),
|
||||
madt_ioapic.id,
|
||||
"mismatched ACPI MADT I/O APIC ID, and the ID reported by the I/O APIC"
|
||||
);
|
||||
|
||||
IOAPICS.get_or_insert_with(Vec::new).push(ioapic);
|
||||
}
|
||||
@@ -286,7 +294,11 @@ pub unsafe fn handle_src_override(src_override: &'static MadtIntSrcOverride) {
|
||||
}
|
||||
|
||||
pub unsafe fn init(active_table: &mut KernelMapper) {
|
||||
let bsp_apic_id = cpuid().unwrap().get_feature_info().unwrap().initial_local_apic_id(); // TODO: remove unwraps
|
||||
let bsp_apic_id = cpuid()
|
||||
.unwrap()
|
||||
.get_feature_info()
|
||||
.unwrap()
|
||||
.initial_local_apic_id(); // TODO: remove unwraps
|
||||
|
||||
// search the madt for all IOAPICs.
|
||||
#[cfg(feature = "acpi")]
|
||||
@@ -310,7 +322,11 @@ pub unsafe fn init(active_table: &mut KernelMapper) {
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("I/O APICs: {:?}, overrides: {:?}", ioapics(), src_overrides());
|
||||
println!(
|
||||
"I/O APICs: {:?}, overrides: {:?}",
|
||||
ioapics(),
|
||||
src_overrides()
|
||||
);
|
||||
|
||||
// map the legacy PC-compatible IRQs (0-15) to 32-47, just like we did with 8259 PIC (if it
|
||||
// wouldn't have been disabled due to this I/O APIC)
|
||||
@@ -318,11 +334,21 @@ pub unsafe fn init(active_table: &mut KernelMapper) {
|
||||
let (gsi, trigger_mode, polarity) = match get_override(legacy_irq) {
|
||||
Some(over) => (over.gsi, over.trigger_mode, over.polarity),
|
||||
None => {
|
||||
if src_overrides().iter().any(|over| over.gsi == u32::from(legacy_irq) && over.bus_irq != legacy_irq) && !src_overrides().iter().any(|over| over.bus_irq == legacy_irq) {
|
||||
if src_overrides()
|
||||
.iter()
|
||||
.any(|over| over.gsi == u32::from(legacy_irq) && over.bus_irq != legacy_irq)
|
||||
&& !src_overrides()
|
||||
.iter()
|
||||
.any(|over| over.bus_irq == legacy_irq)
|
||||
{
|
||||
// there's an IRQ conflict, making this legacy IRQ inaccessible.
|
||||
continue;
|
||||
}
|
||||
(legacy_irq.into(), TriggerMode::ConformsToSpecs, Polarity::ConformsToSpecs)
|
||||
(
|
||||
legacy_irq.into(),
|
||||
TriggerMode::ConformsToSpecs,
|
||||
Polarity::ConformsToSpecs,
|
||||
)
|
||||
}
|
||||
};
|
||||
let apic = match find_ioapic(gsi) {
|
||||
@@ -354,7 +380,11 @@ pub unsafe fn init(active_table: &mut KernelMapper) {
|
||||
};
|
||||
apic.map(redir_tbl_index, map_info);
|
||||
}
|
||||
println!("I/O APICs: {:?}, overrides: {:?}", ioapics(), src_overrides());
|
||||
println!(
|
||||
"I/O APICs: {:?}, overrides: {:?}",
|
||||
ioapics(),
|
||||
src_overrides()
|
||||
);
|
||||
irq::set_irq_method(irq::IrqMethod::Apic);
|
||||
|
||||
// tell the firmware that we're using APIC rather than the default 8259 PIC.
|
||||
@@ -385,7 +415,9 @@ fn resolve(irq: u8) -> u32 {
|
||||
get_override(irq).map_or(u32::from(irq), |over| over.gsi)
|
||||
}
|
||||
fn find_ioapic(gsi: u32) -> Option<&'static IoApic> {
|
||||
ioapics().iter().find(|apic| gsi >= apic.gsi_start && gsi < apic.gsi_start + u32::from(apic.count))
|
||||
ioapics()
|
||||
.iter()
|
||||
.find(|apic| gsi >= apic.gsi_start && gsi < apic.gsi_start + u32::from(apic.count))
|
||||
}
|
||||
|
||||
pub unsafe fn mask(irq: u8) {
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
use core::sync::atomic::{self, AtomicU64};
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
use core::{
|
||||
ptr::{read_volatile, write_volatile},
|
||||
sync::atomic::{self, AtomicU64},
|
||||
};
|
||||
use x86::msr::*;
|
||||
|
||||
use crate::paging::{KernelMapper, PhysicalAddress, PageFlags, RmmA, RmmArch};
|
||||
use crate::paging::{KernelMapper, PageFlags, PhysicalAddress, RmmA, RmmArch};
|
||||
|
||||
use super::super::cpuid::cpuid;
|
||||
|
||||
pub static mut LOCAL_APIC: LocalApic = LocalApic {
|
||||
address: 0,
|
||||
x2: false
|
||||
x2: false,
|
||||
};
|
||||
|
||||
pub unsafe fn init(active_table: &mut KernelMapper) {
|
||||
@@ -22,7 +24,7 @@ pub unsafe fn init_ap() {
|
||||
/// Local APIC
|
||||
pub struct LocalApic {
|
||||
pub address: usize,
|
||||
pub x2: bool
|
||||
pub x2: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -42,19 +44,21 @@ pub fn bsp_apic_id() -> Option<u32> {
|
||||
|
||||
impl LocalApic {
|
||||
unsafe fn init(&mut self, mapper: &mut KernelMapper) {
|
||||
let mapper = mapper.get_mut().expect("expected KernelMapper not to be locked re-entrant while initializing LAPIC");
|
||||
let mapper = mapper
|
||||
.get_mut()
|
||||
.expect("expected KernelMapper not to be locked re-entrant while initializing LAPIC");
|
||||
|
||||
let physaddr = PhysicalAddress::new(rdmsr(IA32_APIC_BASE) as usize & 0xFFFF_0000);
|
||||
let virtaddr = RmmA::phys_to_virt(physaddr);
|
||||
|
||||
self.address = virtaddr.data();
|
||||
self.x2 = cpuid().map_or(false, |cpuid| {
|
||||
cpuid.get_feature_info().map_or(false, |feature_info| {
|
||||
feature_info.has_x2apic()
|
||||
})
|
||||
cpuid
|
||||
.get_feature_info()
|
||||
.map_or(false, |feature_info| feature_info.has_x2apic())
|
||||
});
|
||||
|
||||
if ! self.x2 {
|
||||
if !self.x2 {
|
||||
log::info!("Detected xAPIC at {:#x}", physaddr.data());
|
||||
if let Some((_entry, _, flush)) = mapper.unmap_phys(virtaddr, true) {
|
||||
// Unmap xAPIC page if already mapped
|
||||
@@ -112,15 +116,15 @@ impl LocalApic {
|
||||
if self.x2 {
|
||||
unsafe { rdmsr(IA32_X2APIC_ICR) }
|
||||
} else {
|
||||
unsafe {
|
||||
(self.read(0x310) as u64) << 32 | self.read(0x300) as u64
|
||||
}
|
||||
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); }
|
||||
unsafe {
|
||||
wrmsr(IA32_X2APIC_ICR, value);
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
const PENDING: u32 = 1 << 12;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
pub mod cpu;
|
||||
#[cfg(feature = "acpi")]
|
||||
pub mod hpet;
|
||||
pub mod ioapic;
|
||||
pub mod local_apic;
|
||||
pub mod pic;
|
||||
pub mod pit;
|
||||
pub mod rtc;
|
||||
pub mod serial;
|
||||
#[cfg(feature = "acpi")]
|
||||
pub mod hpet;
|
||||
#[cfg(feature = "system76_ec_debug")]
|
||||
pub mod system76_ec;
|
||||
|
||||
@@ -16,7 +16,7 @@ pub unsafe fn init() {
|
||||
pic::init();
|
||||
local_apic::init(&mut KernelMapper::lock());
|
||||
}
|
||||
pub unsafe fn init_after_acpi() {
|
||||
pub unsafe fn init_after_acpi() {
|
||||
// this will disable the IOAPIC if needed.
|
||||
//ioapic::init(mapper);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::syscall::io::{Io, Pio};
|
||||
use crate::arch::interrupt::irq;
|
||||
use crate::{
|
||||
arch::interrupt::irq,
|
||||
syscall::io::{Io, Pio},
|
||||
};
|
||||
|
||||
pub static mut MASTER: Pic = Pic::new(0x20);
|
||||
pub static mut SLAVE: Pic = Pic::new(0xA0);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::syscall::io::{Io, Pio};
|
||||
use crate::time;
|
||||
use crate::{
|
||||
syscall::io::{Io, Pio},
|
||||
time,
|
||||
};
|
||||
|
||||
pub fn init() {
|
||||
let mut rtc = Rtc::new();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use crate::devices::uart_16550::SerialPort;
|
||||
#[cfg(feature = "lpss_debug")]
|
||||
use crate::syscall::io::Mmio;
|
||||
use crate::syscall::io::Pio;
|
||||
use crate::{devices::uart_16550::SerialPort, syscall::io::Pio};
|
||||
use spin::Mutex;
|
||||
|
||||
pub static COM1: Mutex<SerialPort<Pio<u8>>> = Mutex::new(SerialPort::<Pio<u8>>::new(0x3F8));
|
||||
@@ -22,19 +21,24 @@ pub unsafe fn init() {
|
||||
let address = crate::PHYS_OFFSET + 0xFE032000;
|
||||
|
||||
{
|
||||
use crate::paging::{ActivePageTable, Page, VirtualAddress, entry::EntryFlags};
|
||||
use crate::memory::{Frame, PhysicalAddress};
|
||||
use crate::{
|
||||
memory::{Frame, PhysicalAddress},
|
||||
paging::{entry::EntryFlags, ActivePageTable, Page, VirtualAddress},
|
||||
};
|
||||
|
||||
let mut active_table = ActivePageTable::new();
|
||||
let page = Page::containing_address(VirtualAddress::new(address));
|
||||
let frame = Frame::containing_address(PhysicalAddress::new(address - crate::PHYS_OFFSET));
|
||||
let result = active_table.map_to(page, frame, EntryFlags::PRESENT | EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE);
|
||||
let frame =
|
||||
Frame::containing_address(PhysicalAddress::new(address - crate::PHYS_OFFSET));
|
||||
let result = active_table.map_to(
|
||||
page,
|
||||
frame,
|
||||
EntryFlags::PRESENT | EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE,
|
||||
);
|
||||
result.flush(&mut active_table);
|
||||
}
|
||||
|
||||
let lpss = SerialPort::<Mmio<u32>>::new(
|
||||
crate::PHYS_OFFSET + 0xFE032000
|
||||
);
|
||||
let lpss = SerialPort::<Mmio<u32>>::new(crate::PHYS_OFFSET + 0xFE032000);
|
||||
lpss.init();
|
||||
|
||||
*LPSS.lock() = Some(lpss);
|
||||
|
||||
@@ -13,9 +13,7 @@ pub struct System76Ec {
|
||||
|
||||
impl System76Ec {
|
||||
pub fn new() -> Option<Self> {
|
||||
let mut system76_ec = Self {
|
||||
base: 0x0E00,
|
||||
};
|
||||
let mut system76_ec = Self { base: 0x0E00 };
|
||||
if system76_ec.probe() {
|
||||
Some(system76_ec)
|
||||
} else {
|
||||
|
||||
+65
-27
@@ -1,17 +1,19 @@
|
||||
//! Global descriptor table
|
||||
|
||||
use core::convert::TryInto;
|
||||
use core::mem;
|
||||
use core::{convert::TryInto, mem};
|
||||
|
||||
use crate::LogicalCpuId;
|
||||
use crate::paging::{RmmA, RmmArch};
|
||||
use crate::percpu::PercpuBlock;
|
||||
use crate::{
|
||||
paging::{RmmA, RmmArch},
|
||||
percpu::PercpuBlock,
|
||||
LogicalCpuId,
|
||||
};
|
||||
|
||||
use x86::bits64::task::TaskStateSegment;
|
||||
use x86::Ring;
|
||||
use x86::dtables::{self, DescriptorTablePointer};
|
||||
use x86::segmentation::{self, Descriptor as SegmentDescriptor, SegmentSelector};
|
||||
use x86::task;
|
||||
use x86::{
|
||||
bits64::task::TaskStateSegment,
|
||||
dtables::{self, DescriptorTablePointer},
|
||||
segmentation::{self, Descriptor as SegmentDescriptor, SegmentSelector},
|
||||
task, Ring,
|
||||
};
|
||||
|
||||
pub const GDT_NULL: usize = 0;
|
||||
pub const GDT_KERNEL_CODE: usize = 1;
|
||||
@@ -44,9 +46,19 @@ static mut INIT_GDT: [GdtEntry; 3] = [
|
||||
// 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),
|
||||
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),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0,
|
||||
GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE,
|
||||
GDT_F_LONG_MODE,
|
||||
),
|
||||
];
|
||||
|
||||
// Later copied into the actual GDT with various fields set.
|
||||
@@ -54,15 +66,40 @@ const BASE_GDT: [GdtEntry; 8] = [
|
||||
// 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),
|
||||
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),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0,
|
||||
GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_PRIVILEGE,
|
||||
GDT_F_LONG_MODE,
|
||||
),
|
||||
// Dummy 32-bit user code - apparently necessary for SYSRET. We restrict it to ring 0 anyway.
|
||||
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE, GDT_F_PROTECTED_MODE),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0,
|
||||
GDT_A_PRESENT | GDT_A_RING_0 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | GDT_A_PRIVILEGE,
|
||||
GDT_F_PROTECTED_MODE,
|
||||
),
|
||||
// User data
|
||||
GdtEntry::new(0, 0, GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE, GDT_F_LONG_MODE),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0,
|
||||
GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_PRIVILEGE,
|
||||
GDT_F_LONG_MODE,
|
||||
),
|
||||
// User (64-bit) 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),
|
||||
GdtEntry::new(
|
||||
0,
|
||||
0,
|
||||
GDT_A_PRESENT | GDT_A_RING_3 | GDT_A_SYSTEM | GDT_A_EXECUTABLE | 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
|
||||
@@ -104,8 +141,9 @@ pub unsafe fn pcr() -> *mut ProcessorControlRegion {
|
||||
|
||||
#[cfg(feature = "pti")]
|
||||
pub unsafe fn set_tss_stack(stack: usize) {
|
||||
use super::pti::{PTI_CPU_STACK, PTI_CONTEXT_STACK};
|
||||
core::ptr::addr_of_mut!((*pcr()).tss.rsp[0]).write((PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len()) as u64);
|
||||
use super::pti::{PTI_CONTEXT_STACK, PTI_CPU_STACK};
|
||||
core::ptr::addr_of_mut!((*pcr()).tss.rsp[0])
|
||||
.write((PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len()) as u64);
|
||||
PTI_CONTEXT_STACK = stack;
|
||||
}
|
||||
|
||||
@@ -145,7 +183,8 @@ unsafe fn load_segments() {
|
||||
#[cold]
|
||||
pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) {
|
||||
let pcr_frame = crate::memory::allocate_frames(1).expect("failed to allocate PCR");
|
||||
let pcr = &mut *(RmmA::phys_to_virt(pcr_frame.start_address()).data() as *mut ProcessorControlRegion);
|
||||
let pcr =
|
||||
&mut *(RmmA::phys_to_virt(pcr_frame.start_address()).data() as *mut ProcessorControlRegion);
|
||||
|
||||
pcr.self_ref = pcr as *mut ProcessorControlRegion as usize;
|
||||
|
||||
@@ -157,10 +196,7 @@ pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) {
|
||||
.expect("main GDT way too large");
|
||||
let base = pcr.gdt.as_ptr() as *const SegmentDescriptor;
|
||||
|
||||
let gdtr: DescriptorTablePointer<SegmentDescriptor> = DescriptorTablePointer {
|
||||
limit,
|
||||
base,
|
||||
};
|
||||
let gdtr: DescriptorTablePointer<SegmentDescriptor> = DescriptorTablePointer { limit, base };
|
||||
|
||||
{
|
||||
pcr.tss.iomap_base = 0xFFFF;
|
||||
@@ -172,7 +208,9 @@ pub unsafe fn init_paging(stack_offset: usize, cpu_id: LogicalCpuId) {
|
||||
pcr.gdt[GDT_TSS].set_offset(tss_lo);
|
||||
pcr.gdt[GDT_TSS].set_limit(mem::size_of::<TaskStateSegment>() as u32);
|
||||
|
||||
(&mut pcr.gdt[GDT_TSS_HIGH] as *mut GdtEntry).cast::<u32>().write(tss_hi);
|
||||
(&mut pcr.gdt[GDT_TSS_HIGH] as *mut GdtEntry)
|
||||
.cast::<u32>()
|
||||
.write(tss_hi);
|
||||
}
|
||||
|
||||
// Load the new GDT, which is correctly located in thread local storage.
|
||||
@@ -214,7 +252,7 @@ pub struct GdtEntry {
|
||||
pub offsetm: u8,
|
||||
pub access: u8,
|
||||
pub flags_limith: u8,
|
||||
pub offseth: u8
|
||||
pub offseth: u8,
|
||||
}
|
||||
|
||||
impl GdtEntry {
|
||||
@@ -225,7 +263,7 @@ impl GdtEntry {
|
||||
offsetm: (offset >> 16) as u8,
|
||||
access,
|
||||
flags_limith: flags & 0xF0 | ((limit >> 16) as u8) & 0x0F,
|
||||
offseth: (offset >> 24) as u8
|
||||
offseth: (offset >> 24) as u8,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+66
-21
@@ -1,22 +1,31 @@
|
||||
use core::num::NonZeroU8;
|
||||
use core::sync::atomic::{AtomicU64, Ordering};
|
||||
use core::mem;
|
||||
use core::{
|
||||
mem,
|
||||
num::NonZeroU8,
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
};
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use x86::segmentation::Descriptor as X86IdtEntry;
|
||||
use x86::dtables::{self, DescriptorTablePointer};
|
||||
use x86::{
|
||||
dtables::{self, DescriptorTablePointer},
|
||||
segmentation::Descriptor as X86IdtEntry,
|
||||
};
|
||||
|
||||
use crate::{interrupt::*, LogicalCpuId};
|
||||
use crate::interrupt::irq::{__generic_interrupts_end, __generic_interrupts_start};
|
||||
use crate::ipi::IpiKind;
|
||||
use crate::{
|
||||
interrupt::{
|
||||
irq::{__generic_interrupts_end, __generic_interrupts_start},
|
||||
*,
|
||||
},
|
||||
ipi::IpiKind,
|
||||
LogicalCpuId,
|
||||
};
|
||||
|
||||
use spin::RwLock;
|
||||
|
||||
pub static mut INIT_IDTR: DescriptorTablePointer<X86IdtEntry> = DescriptorTablePointer {
|
||||
limit: 0,
|
||||
base: 0 as *const X86IdtEntry
|
||||
base: 0 as *const X86IdtEntry,
|
||||
};
|
||||
|
||||
pub type IdtEntries = [IdtEntry; 256];
|
||||
@@ -47,7 +56,8 @@ impl Idt {
|
||||
let byte_index = index / 64;
|
||||
let bit = index % 64;
|
||||
|
||||
{ &self.reservations[usize::from(byte_index)] }.fetch_or(u64::from(reserved) << bit, Ordering::AcqRel);
|
||||
{ &self.reservations[usize::from(byte_index)] }
|
||||
.fetch_or(u64::from(reserved) << bit, Ordering::AcqRel);
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_reserved_mut(&mut self, index: u8) -> bool {
|
||||
@@ -62,7 +72,8 @@ impl Idt {
|
||||
let byte_index = index / 64;
|
||||
let bit = index % 64;
|
||||
|
||||
*{ &mut self.reservations[usize::from(byte_index)] }.get_mut() |= u64::from(reserved) << bit;
|
||||
*{ &mut self.reservations[usize::from(byte_index)] }.get_mut() |=
|
||||
u64::from(reserved) << bit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +87,18 @@ pub fn is_reserved(cpu_id: LogicalCpuId, index: u8) -> bool {
|
||||
let byte_index = index / 64;
|
||||
let bit = index % 64;
|
||||
|
||||
{ &IDTS.read().as_ref().unwrap().get(&cpu_id).unwrap().reservations[usize::from(byte_index)] }.load(Ordering::Acquire) & (1 << bit) != 0
|
||||
{
|
||||
&IDTS
|
||||
.read()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get(&cpu_id)
|
||||
.unwrap()
|
||||
.reservations[usize::from(byte_index)]
|
||||
}
|
||||
.load(Ordering::Acquire)
|
||||
& (1 << bit)
|
||||
!= 0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -84,13 +106,22 @@ pub fn set_reserved(cpu_id: LogicalCpuId, index: u8, reserved: bool) {
|
||||
let byte_index = index / 64;
|
||||
let bit = index % 64;
|
||||
|
||||
{ &IDTS.read().as_ref().unwrap().get(&cpu_id).unwrap().reservations[usize::from(byte_index)] }.fetch_or(u64::from(reserved) << bit, Ordering::AcqRel);
|
||||
{
|
||||
&IDTS
|
||||
.read()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get(&cpu_id)
|
||||
.unwrap()
|
||||
.reservations[usize::from(byte_index)]
|
||||
}
|
||||
.fetch_or(u64::from(reserved) << bit, Ordering::AcqRel);
|
||||
}
|
||||
|
||||
pub fn allocate_interrupt() -> Option<NonZeroU8> {
|
||||
let cpu_id = crate::cpu_id();
|
||||
for number in 50..=254 {
|
||||
if ! is_reserved(cpu_id, number) {
|
||||
if !is_reserved(cpu_id, number) {
|
||||
set_reserved(cpu_id, number, true);
|
||||
return Some(unsafe { NonZeroU8::new_unchecked(number) });
|
||||
}
|
||||
@@ -107,7 +138,12 @@ pub unsafe fn init() {
|
||||
}
|
||||
|
||||
const fn new_idt_reservations() -> [AtomicU64; 4] {
|
||||
[AtomicU64::new(0), AtomicU64::new(0), AtomicU64::new(0), AtomicU64::new(0)]
|
||||
[
|
||||
AtomicU64::new(0),
|
||||
AtomicU64::new(0),
|
||||
AtomicU64::new(0),
|
||||
AtomicU64::new(0),
|
||||
]
|
||||
}
|
||||
|
||||
/// Initialize the IDT for a
|
||||
@@ -118,7 +154,9 @@ pub unsafe fn init_paging_post_heap(cpu_id: LogicalCpuId) {
|
||||
if cpu_id == LogicalCpuId::BSP {
|
||||
idts_btree.insert(cpu_id, &mut INIT_BSP_IDT);
|
||||
} else {
|
||||
let idt = idts_btree.entry(cpu_id).or_insert_with(|| Box::leak(Box::new(Idt::new())));
|
||||
let idt = idts_btree
|
||||
.entry(cpu_id)
|
||||
.or_insert_with(|| Box::leak(Box::new(Idt::new())));
|
||||
init_generic(cpu_id, idt);
|
||||
}
|
||||
}
|
||||
@@ -199,7 +237,10 @@ pub unsafe fn init_generic(cpu_id: LogicalCpuId, idt: &mut Idt) {
|
||||
current_idt[30].set_func(exception::security);
|
||||
// 31 reserved
|
||||
|
||||
assert_eq!(__generic_interrupts_end as usize - __generic_interrupts_start as usize, 224 * 8);
|
||||
assert_eq!(
|
||||
__generic_interrupts_end as usize - __generic_interrupts_start as usize,
|
||||
224 * 8
|
||||
);
|
||||
|
||||
for i in 0..224 {
|
||||
current_idt[i + 32].set_func(mem::transmute(__generic_interrupts_start as usize + i * 8));
|
||||
@@ -282,7 +323,7 @@ pub struct IdtEntry {
|
||||
attribute: u8,
|
||||
offsetm: u16,
|
||||
offseth: u32,
|
||||
_zero2: u32
|
||||
_zero2: u32,
|
||||
}
|
||||
|
||||
impl IdtEntry {
|
||||
@@ -294,7 +335,7 @@ impl IdtEntry {
|
||||
attribute: 0,
|
||||
offsetm: 0,
|
||||
offseth: 0,
|
||||
_zero2: 0
|
||||
_zero2: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,7 +344,11 @@ impl IdtEntry {
|
||||
}
|
||||
|
||||
pub fn set_ist(&mut self, ist: u8) {
|
||||
assert_eq!(ist & 0x07, ist, "interrupt stack table must be within 0..=7");
|
||||
assert_eq!(
|
||||
ist & 0x07,
|
||||
ist,
|
||||
"interrupt stack table must be within 0..=7"
|
||||
);
|
||||
self.zero &= 0xF8;
|
||||
self.zero |= ist;
|
||||
}
|
||||
@@ -316,7 +361,7 @@ impl IdtEntry {
|
||||
}
|
||||
|
||||
// A function to set the offset more easily
|
||||
pub fn set_func(&mut self, func: unsafe extern fn()) {
|
||||
pub fn set_func(&mut self, func: unsafe extern "C" fn()) {
|
||||
self.set_flags(IdtFlags::PRESENT | IdtFlags::RING_0 | IdtFlags::INTERRUPT);
|
||||
self.set_offset((crate::gdt::GDT_KERNEL_CODE as u16) << 3, func as usize);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
use x86::irq::PageFaultError;
|
||||
|
||||
use crate::memory::GenericPfFlags;
|
||||
use crate::ptrace;
|
||||
use crate::{
|
||||
interrupt::stack_trace,
|
||||
paging::VirtualAddress,
|
||||
syscall::flag::*,
|
||||
|
||||
interrupt_stack,
|
||||
interrupt_error,
|
||||
interrupt::stack_trace, interrupt_error, interrupt_stack, memory::GenericPfFlags,
|
||||
paging::VirtualAddress, ptrace, syscall::flag::*,
|
||||
};
|
||||
|
||||
extern {
|
||||
extern "C" {
|
||||
fn ksignal(signal: usize);
|
||||
}
|
||||
|
||||
@@ -145,11 +139,26 @@ interrupt_error!(page, |stack, code| {
|
||||
let arch_flags = PageFaultError::from_bits_truncate(code as u32);
|
||||
let mut generic_flags = GenericPfFlags::empty();
|
||||
|
||||
generic_flags.set(GenericPfFlags::PRESENT, arch_flags.contains(PageFaultError::P));
|
||||
generic_flags.set(GenericPfFlags::INVOLVED_WRITE, arch_flags.contains(PageFaultError::WR));
|
||||
generic_flags.set(GenericPfFlags::USER_NOT_SUPERVISOR, arch_flags.contains(PageFaultError::US));
|
||||
generic_flags.set(GenericPfFlags::INVL, arch_flags.contains(PageFaultError::RSVD));
|
||||
generic_flags.set(GenericPfFlags::INSTR_NOT_DATA, arch_flags.contains(PageFaultError::ID));
|
||||
generic_flags.set(
|
||||
GenericPfFlags::PRESENT,
|
||||
arch_flags.contains(PageFaultError::P),
|
||||
);
|
||||
generic_flags.set(
|
||||
GenericPfFlags::INVOLVED_WRITE,
|
||||
arch_flags.contains(PageFaultError::WR),
|
||||
);
|
||||
generic_flags.set(
|
||||
GenericPfFlags::USER_NOT_SUPERVISOR,
|
||||
arch_flags.contains(PageFaultError::US),
|
||||
);
|
||||
generic_flags.set(
|
||||
GenericPfFlags::INVL,
|
||||
arch_flags.contains(PageFaultError::RSVD),
|
||||
);
|
||||
generic_flags.set(
|
||||
GenericPfFlags::INSTR_NOT_DATA,
|
||||
arch_flags.contains(PageFaultError::ID),
|
||||
);
|
||||
|
||||
if crate::memory::page_fault_handler(stack, generic_flags, cr2).is_err() {
|
||||
println!("Page fault: {:>016X} {:#?}", cr2.data(), arch_flags);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use core::mem;
|
||||
|
||||
use crate::memory::ArchIntCtx;
|
||||
use crate::syscall::IntRegisters;
|
||||
use crate::{memory::ArchIntCtx, syscall::IntRegisters};
|
||||
|
||||
use super::super::flags::*;
|
||||
|
||||
@@ -65,7 +64,6 @@ pub struct IretRegisters {
|
||||
// In x86 Protected Mode, i.e. 32-bit kernels, the following two registers are conditionally
|
||||
// pushed if the privilege ring changes. In x86 Long Mode however, i.e. 64-bit kernels, they
|
||||
// are unconditionally pushed, mostly due to stack alignment requirements.
|
||||
|
||||
pub rsp: usize,
|
||||
pub ss: usize,
|
||||
}
|
||||
@@ -83,7 +81,10 @@ impl IretRegisters {
|
||||
let fsbase = x86::msr::rdmsr(x86::msr::IA32_FS_BASE);
|
||||
let gsbase = x86::msr::rdmsr(x86::msr::IA32_KERNEL_GSBASE);
|
||||
let kgsbase = x86::msr::rdmsr(x86::msr::IA32_GS_BASE);
|
||||
println!("FSBASE {:016x}\nGSBASE {:016x}\nKGSBASE {:016x}", fsbase, gsbase, kgsbase);
|
||||
println!(
|
||||
"FSBASE {:016x}\nGSBASE {:016x}\nKGSBASE {:016x}",
|
||||
fsbase, gsbase, kgsbase
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,7 +191,8 @@ impl InterruptStack {
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! push_scratch {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Push scratch registers
|
||||
push rcx
|
||||
push rdx
|
||||
@@ -200,11 +202,13 @@ macro_rules! push_scratch {
|
||||
push r9
|
||||
push r10
|
||||
push r11
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! pop_scratch {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Pop scratch registers
|
||||
pop r11
|
||||
pop r10
|
||||
@@ -215,12 +219,14 @@ macro_rules! pop_scratch {
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rax
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! push_preserved {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Push preserved registers
|
||||
push rbx
|
||||
push rbp
|
||||
@@ -228,11 +234,13 @@ macro_rules! push_preserved {
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! pop_preserved {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Pop preserved registers
|
||||
pop r15
|
||||
pop r14
|
||||
@@ -240,27 +248,32 @@ macro_rules! pop_preserved {
|
||||
pop r12
|
||||
pop rbp
|
||||
pop rbx
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
macro_rules! swapgs_iff_ring3_fast {
|
||||
// TODO: Spectre V1: LFENCE?
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Check whether the last two bits RSP+8 (code segment) are equal to zero.
|
||||
test QWORD PTR [rsp + 8], 0x3
|
||||
// Skip the SWAPGS instruction if CS & 0b11 == 0b00.
|
||||
jz 1f
|
||||
swapgs
|
||||
1:
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
macro_rules! swapgs_iff_ring3_fast_errorcode {
|
||||
// TODO: Spectre V1: LFENCE?
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
test QWORD PTR [rsp + 16], 0x3
|
||||
jz 1f
|
||||
swapgs
|
||||
1:
|
||||
" };
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! conditional_swapgs_paranoid {
|
||||
@@ -328,17 +341,21 @@ macro_rules! conditional_swapgs_paranoid {
|
||||
) }
|
||||
}
|
||||
macro_rules! conditional_swapgs_back_paranoid {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
test bl, bl
|
||||
jnz 1f
|
||||
swapgs
|
||||
1:
|
||||
" }
|
||||
"
|
||||
};
|
||||
}
|
||||
macro_rules! nop {
|
||||
() => { "
|
||||
() => {
|
||||
"
|
||||
// Unused: {IA32_GS_BASE} {PCR_GDT_OFFSET}
|
||||
" }
|
||||
"
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use x86::tlb;
|
||||
|
||||
use crate::context;
|
||||
use crate::device::local_apic::LOCAL_APIC;
|
||||
use crate::{context, device::local_apic::LOCAL_APIC};
|
||||
|
||||
interrupt!(wakeup, || {
|
||||
LOCAL_APIC.eoi();
|
||||
|
||||
@@ -2,14 +2,21 @@ use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{interrupt, interrupt_stack};
|
||||
use crate::context::timeout;
|
||||
use crate::device::{local_apic, ioapic, pic, pit};
|
||||
use crate::device::serial::{COM1, COM2};
|
||||
use crate::ipi::{ipi, IpiKind, IpiTarget};
|
||||
use crate::scheme::debug::{debug_input, debug_notify};
|
||||
use crate::scheme::serio::serio_input;
|
||||
use crate::{context, time};
|
||||
use crate::{
|
||||
context,
|
||||
context::timeout,
|
||||
device::{
|
||||
ioapic, local_apic, pic, pit,
|
||||
serial::{COM1, COM2},
|
||||
},
|
||||
interrupt, interrupt_stack,
|
||||
ipi::{ipi, IpiKind, IpiTarget},
|
||||
scheme::{
|
||||
debug::{debug_input, debug_notify},
|
||||
serio::serio_input,
|
||||
},
|
||||
time,
|
||||
};
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
@@ -33,9 +40,13 @@ pub fn spurious_count() -> usize {
|
||||
pub fn spurious_irq_resource() -> syscall::Result<Vec<u8>> {
|
||||
match irq_method() {
|
||||
IrqMethod::Apic => Ok(Vec::from(&b"(not implemented for APIC yet)"[..])),
|
||||
IrqMethod::Pic => {
|
||||
Ok(format!("{}\tIRQ7\n{}\tIRQ15\n{}\ttotal\n", spurious_count_irq7(), spurious_count_irq15(), spurious_count()).into_bytes())
|
||||
}
|
||||
IrqMethod::Pic => Ok(format!(
|
||||
"{}\tIRQ7\n{}\tIRQ15\n{}\ttotal\n",
|
||||
spurious_count_irq7(),
|
||||
spurious_count_irq15(),
|
||||
spurious_count()
|
||||
)
|
||||
.into_bytes()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +66,7 @@ fn irq_method() -> IrqMethod {
|
||||
}
|
||||
}
|
||||
|
||||
extern {
|
||||
extern "C" {
|
||||
// triggers irq scheme
|
||||
fn irq_trigger(irq: u8);
|
||||
}
|
||||
@@ -64,7 +75,11 @@ extern {
|
||||
/// scheme user unmasks it ("acknowledges" it).
|
||||
unsafe fn trigger(irq: u8) {
|
||||
match irq_method() {
|
||||
IrqMethod::Pic => if irq < 16 { pic_mask(irq) },
|
||||
IrqMethod::Pic => {
|
||||
if irq < 16 {
|
||||
pic_mask(irq)
|
||||
}
|
||||
}
|
||||
IrqMethod::Apic => ioapic_mask(irq),
|
||||
}
|
||||
irq_trigger(irq);
|
||||
@@ -74,7 +89,11 @@ unsafe fn trigger(irq: u8) {
|
||||
/// processed the IRQ.
|
||||
pub unsafe fn acknowledge(irq: usize) {
|
||||
match irq_method() {
|
||||
IrqMethod::Pic => if irq < 16 { pic_unmask(irq) },
|
||||
IrqMethod::Pic => {
|
||||
if irq < 16 {
|
||||
pic_unmask(irq)
|
||||
}
|
||||
}
|
||||
IrqMethod::Apic => ioapic_unmask(irq),
|
||||
}
|
||||
}
|
||||
@@ -82,7 +101,11 @@ pub unsafe fn acknowledge(irq: usize) {
|
||||
/// Sends an end-of-interrupt, so that the interrupt controller can go on to the next one.
|
||||
pub unsafe fn eoi(irq: u8) {
|
||||
match irq_method() {
|
||||
IrqMethod::Pic => if irq < 16 { pic_eoi(irq) },
|
||||
IrqMethod::Pic => {
|
||||
if irq < 16 {
|
||||
pic_eoi(irq)
|
||||
}
|
||||
}
|
||||
IrqMethod::Apic => lapic_eoi(),
|
||||
}
|
||||
}
|
||||
@@ -242,7 +265,7 @@ interrupt!(ata2, || {
|
||||
if irq_method() == IrqMethod::Pic && pic::SLAVE.isr() & (1 << 7) == 0 {
|
||||
SPURIOUS_COUNT_IRQ15.fetch_add(1, Ordering::Relaxed);
|
||||
pic::MASTER.ack();
|
||||
return
|
||||
return;
|
||||
}
|
||||
trigger(15);
|
||||
eoi(15);
|
||||
@@ -259,7 +282,10 @@ interrupt!(aux_timer, || {
|
||||
});
|
||||
|
||||
interrupt!(lapic_error, || {
|
||||
println!("Local apic internal error: ESR={:#0x}", local_apic::LOCAL_APIC.esr());
|
||||
println!(
|
||||
"Local apic internal error: ESR={:#0x}",
|
||||
local_apic::LOCAL_APIC.esr()
|
||||
);
|
||||
lapic_eoi();
|
||||
});
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@ pub mod irq;
|
||||
pub mod syscall;
|
||||
pub mod trace;
|
||||
|
||||
pub use self::handler::InterruptStack;
|
||||
pub use self::trace::stack_trace;
|
||||
pub use self::{handler::InterruptStack, trace::stack_trace};
|
||||
|
||||
pub use super::idt::{available_irqs_iter, is_reserved, set_reserved};
|
||||
pub use super::device::local_apic::bsp_apic_id;
|
||||
pub use super::{
|
||||
device::local_apic::bsp_apic_id,
|
||||
idt::{available_irqs_iter, is_reserved, set_reserved},
|
||||
};
|
||||
|
||||
/// Clear interrupts
|
||||
#[inline(always)]
|
||||
@@ -53,5 +54,7 @@ pub unsafe fn halt() {
|
||||
/// Safe because it is similar to a NOP, and has no memory effects
|
||||
#[inline(always)]
|
||||
pub fn pause() {
|
||||
unsafe { core::arch::asm!("pause", options(nomem, nostack)); }
|
||||
unsafe {
|
||||
core::arch::asm!("pause", options(nomem, nostack));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use crate::{
|
||||
arch::{gdt, interrupt::InterruptStack},
|
||||
context,
|
||||
ptrace,
|
||||
syscall,
|
||||
syscall::flag::{PTRACE_FLAG_IGNORE, PTRACE_STOP_PRE_SYSCALL, PTRACE_STOP_POST_SYSCALL},
|
||||
context, ptrace, syscall,
|
||||
syscall::flag::{PTRACE_FLAG_IGNORE, PTRACE_STOP_POST_SYSCALL, PTRACE_STOP_PRE_SYSCALL},
|
||||
};
|
||||
use core::mem::offset_of;
|
||||
use x86::{bits64::{rflags::RFlags, task::TaskStateSegment}, msr, segmentation::SegmentSelector};
|
||||
use x86::{
|
||||
bits64::{rflags::RFlags, task::TaskStateSegment},
|
||||
msr,
|
||||
segmentation::SegmentSelector,
|
||||
};
|
||||
|
||||
pub unsafe fn init() {
|
||||
// IA32_STAR[31:0] are reserved.
|
||||
@@ -46,7 +48,12 @@ pub unsafe fn init() {
|
||||
// user and kernel mode), VM8086 (not used at all), and VIF/VIP (system-level status flags?).
|
||||
|
||||
let mask_critical = RFlags::FLAGS_DF | RFlags::FLAGS_IF | RFlags::FLAGS_TF | RFlags::FLAGS_AC;
|
||||
let mask_other = RFlags::FLAGS_CF | RFlags::FLAGS_PF | RFlags::FLAGS_AF | RFlags::FLAGS_ZF | RFlags::FLAGS_SF | RFlags::FLAGS_OF;
|
||||
let mask_other = RFlags::FLAGS_CF
|
||||
| RFlags::FLAGS_PF
|
||||
| RFlags::FLAGS_AF
|
||||
| RFlags::FLAGS_ZF
|
||||
| RFlags::FLAGS_SF
|
||||
| RFlags::FLAGS_OF;
|
||||
msr::wrmsr(msr::IA32_FMASK, (mask_critical | mask_other).bits());
|
||||
|
||||
let efer = msr::rdmsr(msr::IA32_EFER);
|
||||
@@ -68,7 +75,7 @@ macro_rules! with_interrupt_stack {
|
||||
}
|
||||
|
||||
ptrace::breakpoint_callback(PTRACE_STOP_POST_SYSCALL, None);
|
||||
}}
|
||||
}};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -76,7 +83,15 @@ pub unsafe extern "C" fn __inner_syscall_instruction(stack: *mut InterruptStack)
|
||||
let _guard = ptrace::set_process_regs(stack);
|
||||
with_interrupt_stack!(|stack| {
|
||||
let scratch = &stack.scratch;
|
||||
syscall::syscall(scratch.rax, scratch.rdi, scratch.rsi, scratch.rdx, scratch.r10, scratch.r8, stack)
|
||||
syscall::syscall(
|
||||
scratch.rax,
|
||||
scratch.rdi,
|
||||
scratch.rsi,
|
||||
scratch.rdx,
|
||||
scratch.r10,
|
||||
scratch.r8,
|
||||
stack,
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -193,13 +208,24 @@ interrupt_stack!(syscall, |stack| {
|
||||
let context = contexts.current();
|
||||
if let Some(current) = context {
|
||||
let current = current.read();
|
||||
println!("Warning: Context {} used deprecated `int 0x80` construct", current.name);
|
||||
println!(
|
||||
"Warning: Context {} used deprecated `int 0x80` construct",
|
||||
current.name
|
||||
);
|
||||
} else {
|
||||
println!("Warning: Unknown context used deprecated `int 0x80` construct");
|
||||
}
|
||||
}
|
||||
|
||||
let scratch = &stack.scratch;
|
||||
syscall::syscall(scratch.rax, stack.preserved.rbx, scratch.rcx, scratch.rdx, scratch.rsi, scratch.rdi, stack)
|
||||
syscall::syscall(
|
||||
scratch.rax,
|
||||
stack.preserved.rbx,
|
||||
scratch.rcx,
|
||||
scratch.rdx,
|
||||
scratch.rsi,
|
||||
scratch.rdi,
|
||||
stack,
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
@@ -3,7 +3,10 @@ use core::{mem, str};
|
||||
use goblin::elf::sym;
|
||||
use rustc_demangle::demangle;
|
||||
|
||||
use crate::{paging::{KernelMapper, VirtualAddress}, USER_END_OFFSET};
|
||||
use crate::{
|
||||
paging::{KernelMapper, VirtualAddress},
|
||||
USER_END_OFFSET,
|
||||
};
|
||||
|
||||
/// Get a stack trace
|
||||
//TODO: Check for stack being mapped before dereferencing
|
||||
@@ -21,7 +24,11 @@ pub unsafe fn stack_trace() {
|
||||
if let Some(rip_rbp) = rbp.checked_add(mem::size_of::<usize>()) {
|
||||
let rbp_virt = VirtualAddress::new(rbp);
|
||||
let rip_rbp_virt = VirtualAddress::new(rip_rbp);
|
||||
if rbp_virt.data() >= USER_END_OFFSET && rip_rbp_virt.data() >= USER_END_OFFSET && mapper.translate(rbp_virt).is_some() && mapper.translate(rip_rbp_virt).is_some() {
|
||||
if rbp_virt.data() >= USER_END_OFFSET
|
||||
&& rip_rbp_virt.data() >= USER_END_OFFSET
|
||||
&& mapper.translate(rbp_virt).is_some()
|
||||
&& mapper.translate(rip_rbp_virt).is_some()
|
||||
{
|
||||
let rip = (rip_rbp as *const usize).read();
|
||||
if rip == 0 {
|
||||
println!(" {:>016X}: EMPTY RETURN", rbp);
|
||||
@@ -45,11 +52,12 @@ pub unsafe fn stack_trace() {
|
||||
//TODO: Do not create Elf object for every symbol lookup
|
||||
#[inline(never)]
|
||||
pub unsafe fn symbol_trace(addr: usize) {
|
||||
use core::slice;
|
||||
use core::sync::atomic::Ordering;
|
||||
use core::{slice, sync::atomic::Ordering};
|
||||
|
||||
use crate::elf::Elf;
|
||||
use crate::start::{KERNEL_BASE, KERNEL_SIZE};
|
||||
use crate::{
|
||||
elf::Elf,
|
||||
start::{KERNEL_BASE, KERNEL_SIZE},
|
||||
};
|
||||
|
||||
let kernel_ptr = (KERNEL_BASE.load(Ordering::SeqCst) + crate::PHYS_OFFSET) as *const u8;
|
||||
let kernel_slice = slice::from_raw_parts(kernel_ptr, KERNEL_SIZE.load(Ordering::SeqCst));
|
||||
@@ -65,10 +73,14 @@ pub unsafe fn symbol_trace(addr: usize) {
|
||||
if let Some(symbols) = elf.symbols() {
|
||||
for sym in symbols {
|
||||
if sym::st_type(sym.st_info) == sym::STT_FUNC
|
||||
&& addr >= sym.st_value as usize
|
||||
&& addr < (sym.st_value + sym.st_size) as usize
|
||||
&& addr >= sym.st_value as usize
|
||||
&& addr < (sym.st_value + sym.st_size) as usize
|
||||
{
|
||||
println!(" {:>016X}+{:>04X}", sym.st_value, addr - sym.st_value as usize);
|
||||
println!(
|
||||
" {:>016X}+{:>04X}",
|
||||
sym.st_value,
|
||||
addr - sym.st_value as usize
|
||||
);
|
||||
|
||||
if let Some(strtab) = strtab_opt {
|
||||
let start = strtab.sh_offset as usize + sym.st_name as usize;
|
||||
@@ -82,7 +94,7 @@ pub unsafe fn symbol_trace(addr: usize) {
|
||||
}
|
||||
|
||||
if end > start {
|
||||
let sym_slice = &elf.data[start .. end - 1];
|
||||
let sym_slice = &elf.data[start..end - 1];
|
||||
if let Ok(sym_name) = str::from_utf8(sym_slice) {
|
||||
println!(" {:#}", demangle(sym_name));
|
||||
}
|
||||
|
||||
@@ -95,4 +95,3 @@ macro_rules! alternative_auto(
|
||||
",
|
||||
) }
|
||||
);
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use x86::controlregs::Cr4;
|
||||
|
||||
use crate::LogicalCpuId;
|
||||
use crate::cpuid::{cpuid_always, has_ext_feat};
|
||||
use crate::{
|
||||
cpuid::{cpuid_always, has_ext_feat},
|
||||
LogicalCpuId,
|
||||
};
|
||||
|
||||
pub unsafe fn init(cpu_id: LogicalCpuId) {
|
||||
if has_ext_feat(|feat| feat.has_umip()) {
|
||||
|
||||
+12
-6
@@ -68,9 +68,10 @@ pub mod flags {
|
||||
pub unsafe extern "C" fn arch_copy_to_user(dst: usize, src: usize, len: usize) -> u8 {
|
||||
// TODO: spectre_v1
|
||||
|
||||
core::arch::asm!(alternative!(
|
||||
feature: "smap",
|
||||
then: ["
|
||||
core::arch::asm!(
|
||||
alternative!(
|
||||
feature: "smap",
|
||||
then: ["
|
||||
xor eax, eax
|
||||
mov rcx, rdx
|
||||
stac
|
||||
@@ -78,19 +79,24 @@ pub unsafe extern "C" fn arch_copy_to_user(dst: usize, src: usize, len: usize) -
|
||||
clac
|
||||
ret
|
||||
"],
|
||||
default: ["
|
||||
default: ["
|
||||
xor eax, eax
|
||||
mov rcx, rdx
|
||||
rep movsb
|
||||
ret
|
||||
"]
|
||||
), options(noreturn));
|
||||
),
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
pub use arch_copy_to_user as arch_copy_from_user;
|
||||
|
||||
// TODO: This doesn't need to be arch-specific, right?
|
||||
pub unsafe fn bootstrap_mem(bootstrap: &Bootstrap) -> &'static [u8] {
|
||||
core::slice::from_raw_parts(CurrentRmmArch::phys_to_virt(bootstrap.base.start_address()).data() as *const u8, bootstrap.page_count * PAGE_SIZE)
|
||||
core::slice::from_raw_parts(
|
||||
CurrentRmmArch::phys_to_virt(bootstrap.base.start_address()).data() as *const u8,
|
||||
bootstrap.page_count * PAGE_SIZE,
|
||||
)
|
||||
}
|
||||
|
||||
pub use alternative::kfx_size;
|
||||
|
||||
@@ -4,16 +4,22 @@ use super::RmmA;
|
||||
|
||||
pub use rmm::{Flusher, PageFlush, PageFlushAll};
|
||||
|
||||
pub struct InactiveFlusher { _inner: () }
|
||||
pub struct InactiveFlusher {
|
||||
_inner: (),
|
||||
}
|
||||
impl InactiveFlusher {
|
||||
// TODO: cpu id
|
||||
pub fn new() -> Self { Self { _inner: () } }
|
||||
pub fn new() -> Self {
|
||||
Self { _inner: () }
|
||||
}
|
||||
}
|
||||
|
||||
impl Flusher<RmmA> for InactiveFlusher {
|
||||
fn consume(&mut self, flush: PageFlush<RmmA>) {
|
||||
// TODO: Push to TLB "mailbox" or tell it to reload CR3 if there are too many entries.
|
||||
unsafe { flush.ignore(); }
|
||||
unsafe {
|
||||
flush.ignore();
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Drop for InactiveFlusher {
|
||||
|
||||
@@ -5,15 +5,8 @@ use core::fmt::Debug;
|
||||
|
||||
use x86::msr;
|
||||
|
||||
pub use rmm::{
|
||||
Arch as RmmArch,
|
||||
Flusher,
|
||||
PageFlags,
|
||||
PhysicalAddress,
|
||||
TableKind,
|
||||
VirtualAddress,
|
||||
};
|
||||
pub use super::CurrentRmmArch as RmmA;
|
||||
pub use rmm::{Arch as RmmArch, Flusher, PageFlags, PhysicalAddress, TableKind, VirtualAddress};
|
||||
|
||||
pub type PageMapper = rmm::PageMapper<RmmA, crate::arch::rmm::LockedAllocator>;
|
||||
pub use crate::rmm::KernelMapper;
|
||||
@@ -92,7 +85,10 @@ impl Page {
|
||||
}
|
||||
|
||||
pub fn range_inclusive(start: Page, r#final: Page) -> PageIter {
|
||||
PageIter { start, end: r#final.next() }
|
||||
PageIter {
|
||||
start,
|
||||
end: r#final.next(),
|
||||
}
|
||||
}
|
||||
pub fn range_exclusive(start: Page, end: Page) -> PageIter {
|
||||
PageIter { start, end }
|
||||
@@ -112,7 +108,11 @@ impl Page {
|
||||
}
|
||||
impl Debug for Page {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "[page at {:p}]", self.start_address().data() as *const u8)
|
||||
write!(
|
||||
f,
|
||||
"[page at {:p}]",
|
||||
self.start_address().data() as *const u8
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-9
@@ -4,9 +4,9 @@ use core::ptr;
|
||||
#[cfg(feature = "pti")]
|
||||
use crate::memory::Frame;
|
||||
#[cfg(feature = "pti")]
|
||||
use crate::paging::ActivePageTable;
|
||||
#[cfg(feature = "pti")]
|
||||
use crate::paging::entry::EntryFlags;
|
||||
#[cfg(feature = "pti")]
|
||||
use crate::paging::ActivePageTable;
|
||||
|
||||
#[cfg(feature = "pti")]
|
||||
#[thread_local]
|
||||
@@ -26,11 +26,7 @@ unsafe fn switch_stack(old: usize, new: usize) {
|
||||
|
||||
let new_rsp = new - offset_rsp;
|
||||
|
||||
ptr::copy_nonoverlapping(
|
||||
old_rsp as *const u8,
|
||||
new_rsp as *mut u8,
|
||||
offset_rsp
|
||||
);
|
||||
ptr::copy_nonoverlapping(old_rsp as *const u8, new_rsp as *mut u8, offset_rsp);
|
||||
|
||||
asm!("", out("rsp") new_rsp);
|
||||
}
|
||||
@@ -53,14 +49,20 @@ pub unsafe fn map() {
|
||||
// }
|
||||
|
||||
// Switch to per-context stack
|
||||
switch_stack(PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len(), PTI_CONTEXT_STACK);
|
||||
switch_stack(
|
||||
PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len(),
|
||||
PTI_CONTEXT_STACK,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "pti")]
|
||||
#[inline(always)]
|
||||
pub unsafe extern "C" fn unmap() {
|
||||
// Switch to per-CPU stack
|
||||
switch_stack(PTI_CONTEXT_STACK, PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len());
|
||||
switch_stack(
|
||||
PTI_CONTEXT_STACK,
|
||||
PTI_CPU_STACK.as_ptr() as usize + PTI_CPU_STACK.len(),
|
||||
);
|
||||
|
||||
// {
|
||||
// let mut active_table = unsafe { ActivePageTable::new() };
|
||||
|
||||
+139
-90
@@ -1,24 +1,11 @@
|
||||
use core::{
|
||||
cmp,
|
||||
mem,
|
||||
slice,
|
||||
sync::atomic::{self, AtomicUsize, Ordering}, cell::SyncUnsafeCell,
|
||||
cell::SyncUnsafeCell,
|
||||
cmp, mem, slice,
|
||||
sync::atomic::{self, AtomicUsize, Ordering},
|
||||
};
|
||||
use rmm::{
|
||||
KILOBYTE,
|
||||
MEGABYTE,
|
||||
Arch,
|
||||
BuddyAllocator,
|
||||
BumpAllocator,
|
||||
FrameAllocator,
|
||||
FrameCount,
|
||||
FrameUsage,
|
||||
MemoryArea,
|
||||
PageFlags,
|
||||
PageMapper,
|
||||
PhysicalAddress,
|
||||
TableKind,
|
||||
VirtualAddress,
|
||||
Arch, BuddyAllocator, BumpAllocator, FrameAllocator, FrameCount, FrameUsage, MemoryArea,
|
||||
PageFlags, PageMapper, PhysicalAddress, TableKind, VirtualAddress, KILOBYTE, MEGABYTE,
|
||||
};
|
||||
use spin::Mutex;
|
||||
|
||||
@@ -63,11 +50,16 @@ unsafe fn page_flags<A: Arch>(virt: VirtualAddress) -> PageFlags<A> {
|
||||
|
||||
unsafe fn inner<A: Arch>(
|
||||
areas: &'static [MemoryArea],
|
||||
kernel_base: usize, kernel_size_aligned: usize,
|
||||
stack_base: usize, stack_size_aligned: usize,
|
||||
env_base: usize, env_size_aligned: usize,
|
||||
acpi_base: usize, acpi_size_aligned: usize,
|
||||
initfs_base: usize, initfs_size_aligned: usize,
|
||||
kernel_base: usize,
|
||||
kernel_size_aligned: usize,
|
||||
stack_base: usize,
|
||||
stack_size_aligned: usize,
|
||||
env_base: usize,
|
||||
env_size_aligned: usize,
|
||||
acpi_base: usize,
|
||||
acpi_size_aligned: usize,
|
||||
initfs_base: usize,
|
||||
initfs_size_aligned: usize,
|
||||
) -> BuddyAllocator<A> {
|
||||
// First, calculate how much memory we have
|
||||
let mut size = 0;
|
||||
@@ -84,10 +76,8 @@ unsafe fn inner<A: Arch>(
|
||||
let mut bump_allocator = BumpAllocator::<A>::new(areas, 0);
|
||||
|
||||
{
|
||||
let mut mapper = PageMapper::<A, _>::create(
|
||||
TableKind::Kernel,
|
||||
&mut bump_allocator
|
||||
).expect("failed to create Mapper");
|
||||
let mut mapper = PageMapper::<A, _>::create(TableKind::Kernel, &mut bump_allocator)
|
||||
.expect("failed to create Mapper");
|
||||
|
||||
// Map all physical areas at PHYS_OFFSET
|
||||
for area in areas.iter() {
|
||||
@@ -95,11 +85,9 @@ unsafe fn inner<A: Arch>(
|
||||
let phys = area.base.add(i * A::PAGE_SIZE);
|
||||
let virt = A::phys_to_virt(phys);
|
||||
let flags = page_flags::<A>(virt);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
}
|
||||
@@ -109,19 +97,15 @@ unsafe fn inner<A: Arch>(
|
||||
let phys = PhysicalAddress::new(kernel_base + i * A::PAGE_SIZE);
|
||||
let virt = VirtualAddress::new(crate::KERNEL_OFFSET + i * A::PAGE_SIZE);
|
||||
let flags = page_flags::<A>(virt);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
|
||||
let virt = A::phys_to_virt(phys);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
|
||||
@@ -131,11 +115,9 @@ unsafe fn inner<A: Arch>(
|
||||
let phys = PhysicalAddress::new(base + i * A::PAGE_SIZE);
|
||||
let virt = A::phys_to_virt(phys);
|
||||
let flags = page_flags::<A>(virt);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
};
|
||||
@@ -148,8 +130,8 @@ unsafe fn inner<A: Arch>(
|
||||
// Ensure graphical debug region remains paged
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
{
|
||||
use crate::devices::graphical_debug::FRAMEBUFFER;
|
||||
use super::paging::entry::EntryFlags;
|
||||
use crate::devices::graphical_debug::FRAMEBUFFER;
|
||||
|
||||
let (phys, virt, size) = *FRAMEBUFFER.lock();
|
||||
|
||||
@@ -157,14 +139,13 @@ unsafe fn inner<A: Arch>(
|
||||
for i in 0..pages {
|
||||
let phys = PhysicalAddress::new(phys + i * A::PAGE_SIZE);
|
||||
let virt = VirtualAddress::new(virt + i * A::PAGE_SIZE);
|
||||
let flags = PageFlags::new().write(true)
|
||||
let flags = PageFlags::new()
|
||||
.write(true)
|
||||
// Write combining flag
|
||||
.custom_flag(EntryFlags::HUGE_PAGE.bits(), true);
|
||||
let flush = mapper.map_phys(
|
||||
virt,
|
||||
phys,
|
||||
flags
|
||||
).expect("failed to map frame");
|
||||
let flush = mapper
|
||||
.map_phys(virt, phys, flags)
|
||||
.expect("failed to map frame");
|
||||
flush.ignore(); // Not the active table
|
||||
}
|
||||
}
|
||||
@@ -184,7 +165,10 @@ unsafe fn inner<A: Arch>(
|
||||
|
||||
// Create the physical memory map
|
||||
let offset = bump_allocator.offset();
|
||||
log::info!("Permanently used: {} KB", (offset + (KILOBYTE - 1)) / KILOBYTE);
|
||||
log::info!(
|
||||
"Permanently used: {} KB",
|
||||
(offset + (KILOBYTE - 1)) / KILOBYTE
|
||||
);
|
||||
|
||||
BuddyAllocator::<A>::new(bump_allocator).expect("failed to create BuddyAllocator")
|
||||
}
|
||||
@@ -228,10 +212,12 @@ impl core::fmt::Debug for LockedAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
static AREAS: SyncUnsafeCell<[MemoryArea; 512]> = SyncUnsafeCell::new([MemoryArea {
|
||||
base: PhysicalAddress::new(0),
|
||||
size: 0,
|
||||
}; 512]);
|
||||
static AREAS: SyncUnsafeCell<[MemoryArea; 512]> = SyncUnsafeCell::new(
|
||||
[MemoryArea {
|
||||
base: PhysicalAddress::new(0),
|
||||
size: 0,
|
||||
}; 512],
|
||||
);
|
||||
static AREA_COUNT: SyncUnsafeCell<u16> = SyncUnsafeCell::new(0);
|
||||
|
||||
pub fn areas() -> &'static [MemoryArea] {
|
||||
@@ -263,7 +249,12 @@ pub struct KernelMapper {
|
||||
impl KernelMapper {
|
||||
fn lock_inner(current_processor: usize) -> bool {
|
||||
loop {
|
||||
match LOCK_OWNER.compare_exchange_weak(NO_PROCESSOR, current_processor, Ordering::Acquire, Ordering::Relaxed) {
|
||||
match LOCK_OWNER.compare_exchange_weak(
|
||||
NO_PROCESSOR,
|
||||
current_processor,
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => break,
|
||||
// already owned by this hardware thread
|
||||
Err(id) if id == current_processor => break,
|
||||
@@ -277,15 +268,20 @@ impl KernelMapper {
|
||||
|
||||
prev_count > 0
|
||||
}
|
||||
pub unsafe fn lock_for_manual_mapper(current_processor: LogicalCpuId, mapper: crate::paging::PageMapper) -> Self {
|
||||
pub unsafe fn lock_for_manual_mapper(
|
||||
current_processor: LogicalCpuId,
|
||||
mapper: crate::paging::PageMapper,
|
||||
) -> Self {
|
||||
let ro = Self::lock_inner(current_processor.get() as usize);
|
||||
Self {
|
||||
mapper,
|
||||
ro,
|
||||
}
|
||||
Self { mapper, ro }
|
||||
}
|
||||
pub fn lock_manually(current_processor: LogicalCpuId) -> Self {
|
||||
unsafe { Self::lock_for_manual_mapper(current_processor, PageMapper::current(TableKind::Kernel, FRAME_ALLOCATOR)) }
|
||||
unsafe {
|
||||
Self::lock_for_manual_mapper(
|
||||
current_processor,
|
||||
PageMapper::current(TableKind::Kernel, FRAME_ALLOCATOR),
|
||||
)
|
||||
}
|
||||
}
|
||||
pub fn lock() -> Self {
|
||||
Self::lock_manually(crate::cpu_id())
|
||||
@@ -320,12 +316,18 @@ impl Drop for KernelMapper {
|
||||
}
|
||||
|
||||
pub unsafe fn init(
|
||||
kernel_base: usize, kernel_size: usize,
|
||||
stack_base: usize, stack_size: usize,
|
||||
env_base: usize, env_size: usize,
|
||||
acpi_base: usize, acpi_size: usize,
|
||||
areas_base: usize, areas_size: usize,
|
||||
initfs_base: usize, initfs_size: usize,
|
||||
kernel_base: usize,
|
||||
kernel_size: usize,
|
||||
stack_base: usize,
|
||||
stack_size: usize,
|
||||
env_base: usize,
|
||||
env_size: usize,
|
||||
acpi_base: usize,
|
||||
acpi_size: usize,
|
||||
areas_base: usize,
|
||||
areas_size: usize,
|
||||
initfs_base: usize,
|
||||
initfs_size: usize,
|
||||
) {
|
||||
type A = RmmA;
|
||||
|
||||
@@ -333,24 +335,24 @@ pub unsafe fn init(
|
||||
let real_size = 0x100000;
|
||||
let real_end = real_base + real_size;
|
||||
|
||||
let kernel_size_aligned = ((kernel_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let kernel_size_aligned = ((kernel_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let kernel_end = kernel_base + kernel_size_aligned;
|
||||
|
||||
let stack_size_aligned = ((stack_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let stack_size_aligned = ((stack_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let stack_end = stack_base + stack_size_aligned;
|
||||
|
||||
let env_size_aligned = ((env_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let env_size_aligned = ((env_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let env_end = env_base + env_size_aligned;
|
||||
|
||||
let acpi_size_aligned = ((acpi_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let acpi_size_aligned = ((acpi_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let acpi_end = acpi_base + acpi_size_aligned;
|
||||
|
||||
let initfs_size_aligned = ((initfs_size + (A::PAGE_SIZE - 1))/A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let initfs_size_aligned = ((initfs_size + (A::PAGE_SIZE - 1)) / A::PAGE_SIZE) * A::PAGE_SIZE;
|
||||
let initfs_end = initfs_base + initfs_size_aligned;
|
||||
|
||||
let bootloader_areas = slice::from_raw_parts(
|
||||
areas_base as *const BootloaderMemoryEntry,
|
||||
areas_size / mem::size_of::<BootloaderMemoryEntry>()
|
||||
areas_size / mem::size_of::<BootloaderMemoryEntry>(),
|
||||
);
|
||||
|
||||
// Copy memory map from bootloader location, and page align it
|
||||
@@ -383,44 +385,86 @@ pub unsafe fn init(
|
||||
|
||||
// Ensure real-mode areas are not used
|
||||
if base < real_end && base + size > real_base {
|
||||
log::warn!("{:X}:{:X} overlaps with real mode {:X}:{:X}", base, size, real_base, real_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with real mode {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
real_base,
|
||||
real_size
|
||||
);
|
||||
new_base = cmp::max(new_base, real_end);
|
||||
}
|
||||
|
||||
// Ensure kernel areas are not used
|
||||
if base < kernel_end && base + size > kernel_base {
|
||||
log::warn!("{:X}:{:X} overlaps with kernel {:X}:{:X}", base, size, kernel_base, kernel_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with kernel {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
kernel_base,
|
||||
kernel_size
|
||||
);
|
||||
new_base = cmp::max(new_base, kernel_end);
|
||||
}
|
||||
|
||||
// Ensure stack areas are not used
|
||||
if base < stack_end && base + size > stack_base {
|
||||
log::warn!("{:X}:{:X} overlaps with stack {:X}:{:X}", base, size, stack_base, stack_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with stack {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
stack_base,
|
||||
stack_size
|
||||
);
|
||||
new_base = cmp::max(new_base, stack_end);
|
||||
}
|
||||
|
||||
// Ensure env areas are not used
|
||||
if base < env_end && base + size > env_base {
|
||||
log::warn!("{:X}:{:X} overlaps with env {:X}:{:X}", base, size, env_base, env_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with env {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
env_base,
|
||||
env_size
|
||||
);
|
||||
new_base = cmp::max(new_base, env_end);
|
||||
}
|
||||
|
||||
// Ensure acpi areas are not used
|
||||
if base < acpi_end && base + size > acpi_base {
|
||||
log::warn!("{:X}:{:X} overlaps with acpi {:X}:{:X}", base, size, acpi_base, acpi_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with acpi {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
acpi_base,
|
||||
acpi_size
|
||||
);
|
||||
new_base = cmp::max(new_base, acpi_end);
|
||||
}
|
||||
|
||||
// Ensure initfs areas are not used
|
||||
if base < initfs_end && base + size > initfs_base {
|
||||
log::warn!("{:X}:{:X} overlaps with initfs {:X}:{:X}", base, size, initfs_base, initfs_size);
|
||||
log::warn!(
|
||||
"{:X}:{:X} overlaps with initfs {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
initfs_base,
|
||||
initfs_size
|
||||
);
|
||||
new_base = cmp::max(new_base, initfs_end);
|
||||
}
|
||||
|
||||
if new_base != base {
|
||||
let end = base + size;
|
||||
let new_size = end.checked_sub(new_base).unwrap_or(0);
|
||||
log::info!("{:X}:{:X} moved to {:X}:{:X}", base, size, new_base, new_size);
|
||||
log::info!(
|
||||
"{:X}:{:X} moved to {:X}:{:X}",
|
||||
base,
|
||||
size,
|
||||
new_base,
|
||||
new_size
|
||||
);
|
||||
base = new_base;
|
||||
size = new_size;
|
||||
}
|
||||
@@ -439,11 +483,16 @@ pub unsafe fn init(
|
||||
|
||||
let allocator = inner::<A>(
|
||||
areas(),
|
||||
kernel_base, kernel_size_aligned,
|
||||
stack_base, stack_size_aligned,
|
||||
env_base, env_size_aligned,
|
||||
acpi_base, acpi_size_aligned,
|
||||
initfs_base, initfs_size_aligned,
|
||||
kernel_base,
|
||||
kernel_size_aligned,
|
||||
stack_base,
|
||||
stack_size_aligned,
|
||||
env_base,
|
||||
env_size_aligned,
|
||||
acpi_base,
|
||||
acpi_size_aligned,
|
||||
initfs_base,
|
||||
initfs_size_aligned,
|
||||
);
|
||||
*INNER_ALLOCATOR.lock() = Some(allocator);
|
||||
}
|
||||
|
||||
+70
-31
@@ -2,24 +2,22 @@
|
||||
/// It is increcibly unsafe, and should be minimal in nature
|
||||
/// It must create the IDT with the correct entries, those entries are
|
||||
/// defined in other files inside of the `arch` module
|
||||
|
||||
use core::slice;
|
||||
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering, AtomicU32};
|
||||
use core::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering};
|
||||
|
||||
use crate::{allocator, memory, LogicalCpuId};
|
||||
#[cfg(feature = "acpi")]
|
||||
use crate::acpi;
|
||||
use crate::arch::pti;
|
||||
use crate::arch::flags::*;
|
||||
use crate::device;
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
use crate::devices::graphical_debug;
|
||||
use crate::gdt;
|
||||
use crate::idt;
|
||||
use crate::interrupt;
|
||||
use crate::misc;
|
||||
use crate::log::{self, info};
|
||||
use crate::paging::{self, PhysicalAddress, RmmA, RmmArch, TableKind};
|
||||
use crate::{
|
||||
allocator,
|
||||
arch::{flags::*, pti},
|
||||
device, gdt, idt, interrupt,
|
||||
log::{self, info},
|
||||
memory, misc,
|
||||
paging::{self, PhysicalAddress, RmmA, RmmArch, TableKind},
|
||||
LogicalCpuId,
|
||||
};
|
||||
|
||||
/// Test of zero values in BSS.
|
||||
static BSS_TEST_ZERO: usize = 0;
|
||||
@@ -68,7 +66,7 @@ pub struct KernelArgs {
|
||||
|
||||
/// The entry to Rust, all things must be initialized
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
let bootstrap = {
|
||||
let args = args_ptr.read();
|
||||
|
||||
@@ -82,7 +80,10 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
KERNEL_SIZE.store(args.kernel_size as usize, Ordering::SeqCst);
|
||||
|
||||
// Convert env to slice
|
||||
let env = slice::from_raw_parts((args.env_base as usize + crate::PHYS_OFFSET) as *const u8, args.env_size as usize);
|
||||
let env = slice::from_raw_parts(
|
||||
(args.env_base as usize + crate::PHYS_OFFSET) as *const u8,
|
||||
args.env_size as usize,
|
||||
);
|
||||
|
||||
// Set up graphical debug
|
||||
#[cfg(feature = "graphical_debug")]
|
||||
@@ -104,12 +105,36 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
});
|
||||
|
||||
info!("Redox OS starting...");
|
||||
info!("Kernel: {:X}:{:X}", { args.kernel_base }, { args.kernel_base } + { args.kernel_size });
|
||||
info!("Stack: {:X}:{:X}", { args.stack_base }, { args.stack_base } + { args.stack_size });
|
||||
info!("Env: {:X}:{:X}", { args.env_base }, { args.env_base } + { args.env_size });
|
||||
info!("RSDPs: {:X}:{:X}", { args.acpi_rsdps_base }, { args.acpi_rsdps_base } + { args.acpi_rsdps_size });
|
||||
info!("Areas: {:X}:{:X}", { args.areas_base }, { args.areas_base } + { args.areas_size });
|
||||
info!("Bootstrap: {:X}:{:X}", { args.bootstrap_base }, { args.bootstrap_base } + { args.bootstrap_size });
|
||||
info!(
|
||||
"Kernel: {:X}:{:X}",
|
||||
{ args.kernel_base },
|
||||
{ args.kernel_base } + { args.kernel_size }
|
||||
);
|
||||
info!(
|
||||
"Stack: {:X}:{:X}",
|
||||
{ args.stack_base },
|
||||
{ args.stack_base } + { args.stack_size }
|
||||
);
|
||||
info!(
|
||||
"Env: {:X}:{:X}",
|
||||
{ args.env_base },
|
||||
{ args.env_base } + { args.env_size }
|
||||
);
|
||||
info!(
|
||||
"RSDPs: {:X}:{:X}",
|
||||
{ args.acpi_rsdps_base },
|
||||
{ args.acpi_rsdps_base } + { args.acpi_rsdps_size }
|
||||
);
|
||||
info!(
|
||||
"Areas: {:X}:{:X}",
|
||||
{ args.areas_base },
|
||||
{ args.areas_base } + { args.areas_size }
|
||||
);
|
||||
info!(
|
||||
"Bootstrap: {:X}:{:X}",
|
||||
{ args.bootstrap_base },
|
||||
{ args.bootstrap_base } + { args.bootstrap_size }
|
||||
);
|
||||
info!("Bootstrap entry point: {:X}", { args.bootstrap_entry });
|
||||
|
||||
// Set up GDT before paging
|
||||
@@ -120,19 +145,28 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
|
||||
// Initialize RMM
|
||||
crate::arch::rmm::init(
|
||||
args.kernel_base as usize, args.kernel_size as usize,
|
||||
args.stack_base as usize, args.stack_size as usize,
|
||||
args.env_base as usize, args.env_size as usize,
|
||||
args.acpi_rsdps_base as usize, args.acpi_rsdps_size as usize,
|
||||
args.areas_base as usize, args.areas_size as usize,
|
||||
args.bootstrap_base as usize, args.bootstrap_size as usize,
|
||||
args.kernel_base as usize,
|
||||
args.kernel_size as usize,
|
||||
args.stack_base as usize,
|
||||
args.stack_size as usize,
|
||||
args.env_base as usize,
|
||||
args.env_size as usize,
|
||||
args.acpi_rsdps_base as usize,
|
||||
args.acpi_rsdps_size as usize,
|
||||
args.areas_base as usize,
|
||||
args.areas_size as usize,
|
||||
args.bootstrap_base as usize,
|
||||
args.bootstrap_size as usize,
|
||||
);
|
||||
|
||||
// Initialize PAT
|
||||
paging::init();
|
||||
|
||||
// Set up GDT after paging with TLS
|
||||
gdt::init_paging(args.stack_base as usize + args.stack_size as usize, LogicalCpuId::BSP);
|
||||
gdt::init_paging(
|
||||
args.stack_base as usize + args.stack_size as usize,
|
||||
LogicalCpuId::BSP,
|
||||
);
|
||||
|
||||
// Set up IDT
|
||||
idt::init_paging_bsp();
|
||||
@@ -172,7 +206,10 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
#[cfg(feature = "acpi")]
|
||||
{
|
||||
acpi::init(if args.acpi_rsdps_base != 0 && args.acpi_rsdps_size > 0 {
|
||||
Some(((args.acpi_rsdps_base as usize + crate::PHYS_OFFSET) as u64, args.acpi_rsdps_size as u64))
|
||||
Some((
|
||||
(args.acpi_rsdps_base as usize + crate::PHYS_OFFSET) as u64,
|
||||
args.acpi_rsdps_size as u64,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
});
|
||||
@@ -192,7 +229,9 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
|
||||
BSP_READY.store(true, Ordering::SeqCst);
|
||||
|
||||
crate::Bootstrap {
|
||||
base: crate::memory::Frame::containing_address(crate::paging::PhysicalAddress::new(args.bootstrap_base as usize)),
|
||||
base: crate::memory::Frame::containing_address(crate::paging::PhysicalAddress::new(
|
||||
args.bootstrap_base as usize,
|
||||
)),
|
||||
page_count: (args.bootstrap_size as usize) / crate::memory::PAGE_SIZE,
|
||||
entry: args.bootstrap_entry as usize,
|
||||
env,
|
||||
@@ -213,7 +252,7 @@ pub struct KernelArgsAp {
|
||||
}
|
||||
|
||||
/// Entry to rust for an AP
|
||||
pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
|
||||
pub unsafe extern "C" fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
|
||||
let cpu_id = {
|
||||
let args = &*args_ptr;
|
||||
let cpu_id = LogicalCpuId::new(args.cpu_id as u32);
|
||||
@@ -259,7 +298,7 @@ pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
|
||||
cpu_id
|
||||
};
|
||||
|
||||
while ! BSP_READY.load(Ordering::SeqCst) {
|
||||
while !BSP_READY.load(Ordering::SeqCst) {
|
||||
interrupt::pause();
|
||||
}
|
||||
|
||||
|
||||
+9
-10
@@ -1,14 +1,10 @@
|
||||
#[cfg(feature = "acpi")]
|
||||
use crate::{
|
||||
context,
|
||||
scheme::acpi,
|
||||
time,
|
||||
};
|
||||
use crate::{context, scheme::acpi, time};
|
||||
|
||||
use crate::syscall::io::{Io, Pio};
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn kreset() -> ! {
|
||||
pub unsafe extern "C" fn kreset() -> ! {
|
||||
println!("kreset");
|
||||
|
||||
// 8042 reset
|
||||
@@ -24,11 +20,14 @@ pub unsafe extern fn kreset() -> ! {
|
||||
|
||||
pub unsafe fn emergency_reset() -> ! {
|
||||
// Use triple fault to guarantee reset
|
||||
core::arch::asm!("
|
||||
core::arch::asm!(
|
||||
"
|
||||
cli
|
||||
lidt cs:0
|
||||
int $3
|
||||
", options(noreturn));
|
||||
",
|
||||
options(noreturn)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
@@ -36,7 +35,7 @@ fn userspace_acpi_shutdown() {
|
||||
log::info!("Notifying any potential ACPI driver");
|
||||
// Tell whatever driver that handles ACPI, that it should enter the S5 state (i.e.
|
||||
// shutdown).
|
||||
if ! acpi::register_kstop() {
|
||||
if !acpi::register_kstop() {
|
||||
// There was no context to switch to.
|
||||
log::info!("No ACPI driver was alive to handle shutdown.");
|
||||
return;
|
||||
@@ -63,7 +62,7 @@ fn userspace_acpi_shutdown() {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn kstop() -> ! {
|
||||
pub unsafe extern "C" fn kstop() -> ! {
|
||||
log::info!("Running kstop()");
|
||||
|
||||
#[cfg(feature = "acpi")]
|
||||
|
||||
+24
-10
@@ -1,8 +1,6 @@
|
||||
use core::alloc::Layout;
|
||||
use core::alloc::GlobalAlloc;
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
|
||||
use crate::common::unique::Unique;
|
||||
use crate::memory::Enomem;
|
||||
use crate::{common::unique::Unique, memory::Enomem};
|
||||
|
||||
// Necessary because GlobalAlloc::dealloc requires the layout to be the same, and therefore Box
|
||||
// cannot be used for increased alignment directly.
|
||||
@@ -24,7 +22,11 @@ impl<T: ?Sized, const ALIGN: usize> AlignedBox<T, ALIGN> {
|
||||
}
|
||||
const fn layout_upgrade_align(layout: Layout, align: usize) -> Layout {
|
||||
const fn max(a: usize, b: usize) -> usize {
|
||||
if a > b { a } else { b }
|
||||
if a > b {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
}
|
||||
}
|
||||
let Ok(x) = Layout::from_size_align(layout.size(), max(align, layout.align())) else {
|
||||
panic!("failed to calculate layout");
|
||||
@@ -39,7 +41,8 @@ impl<T, const ALIGN: usize> AlignedBox<T, ALIGN> {
|
||||
T: ValidForZero,
|
||||
{
|
||||
Ok(unsafe {
|
||||
let ptr = crate::ALLOCATOR.alloc_zeroed(layout_upgrade_align(Layout::new::<T>(), ALIGN));
|
||||
let ptr =
|
||||
crate::ALLOCATOR.alloc_zeroed(layout_upgrade_align(Layout::new::<T>(), ALIGN));
|
||||
if ptr.is_null() {
|
||||
return Err(Enomem);
|
||||
}
|
||||
@@ -56,7 +59,10 @@ impl<T, const ALIGN: usize> AlignedBox<[T], ALIGN> {
|
||||
T: ValidForZero,
|
||||
{
|
||||
Ok(unsafe {
|
||||
let ptr = crate::ALLOCATOR.alloc_zeroed(layout_upgrade_align(Layout::array::<T>(len).unwrap(), ALIGN));
|
||||
let ptr = crate::ALLOCATOR.alloc_zeroed(layout_upgrade_align(
|
||||
Layout::array::<T>(len).unwrap(),
|
||||
ALIGN,
|
||||
));
|
||||
if ptr.is_null() {
|
||||
return Err(Enomem);
|
||||
}
|
||||
@@ -69,7 +75,13 @@ impl<T, const ALIGN: usize> AlignedBox<[T], ALIGN> {
|
||||
|
||||
impl<T: ?Sized, const ALIGN: usize> core::fmt::Debug for AlignedBox<T, ALIGN> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "[aligned box at {:p}, size {} alignment {}]", self.inner.as_ptr(), self.layout().size(), self.layout().align())
|
||||
write!(
|
||||
f,
|
||||
"[aligned box at {:p}, size {} alignment {}]",
|
||||
self.inner.as_ptr(),
|
||||
self.layout().size(),
|
||||
self.layout().align()
|
||||
)
|
||||
}
|
||||
}
|
||||
impl<T: ?Sized, const ALIGN: usize> Drop for AlignedBox<T, ALIGN> {
|
||||
@@ -95,14 +107,16 @@ impl<T: ?Sized, const ALIGN: usize> core::ops::DerefMut for AlignedBox<T, ALIGN>
|
||||
}
|
||||
impl<T: Clone + ValidForZero, const ALIGN: usize> Clone for AlignedBox<T, ALIGN> {
|
||||
fn clone(&self) -> Self {
|
||||
let mut new = Self::try_zeroed().unwrap_or_else(|_| alloc::alloc::handle_alloc_error(self.layout()));
|
||||
let mut new =
|
||||
Self::try_zeroed().unwrap_or_else(|_| alloc::alloc::handle_alloc_error(self.layout()));
|
||||
T::clone_from(&mut new, self);
|
||||
new
|
||||
}
|
||||
}
|
||||
impl<T: Clone + ValidForZero, const ALIGN: usize> Clone for AlignedBox<[T], ALIGN> {
|
||||
fn clone(&self) -> Self {
|
||||
let mut new = Self::try_zeroed_slice(self.len()).unwrap_or_else(|_| alloc::alloc::handle_alloc_error(self.layout()));
|
||||
let mut new = Self::try_zeroed_slice(self.len())
|
||||
.unwrap_or_else(|_| alloc::alloc::handle_alloc_error(self.layout()));
|
||||
for i in 0..self.len() {
|
||||
new[i].clone_from(&self[i]);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user