forked from rcore-os/zCore
drivers: refactor x86 local & IO APIC drivers
This commit is contained in:
parent
4021ef4c30
commit
d13afc3d24
|
@ -21,5 +21,9 @@ bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev =
|
||||||
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "2b3c6cf", optional = true }
|
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "2b3c6cf", optional = true }
|
||||||
async-std = { version = "1.10", optional = true }
|
async-std = { version = "1.10", optional = true }
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "x86_64")'.dependencies]
|
||||||
|
acpi = "4.0"
|
||||||
|
x2apic = { git = "https://github.com/equation314/x2apic-rs", rev = "a14b1d8" }
|
||||||
|
|
||||||
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
|
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
|
||||||
riscv = { version = "0.7", features = ["inline-asm"] }
|
riscv = { version = "0.7", features = ["inline-asm"] }
|
||||||
|
|
|
@ -3,7 +3,15 @@ cfg_if::cfg_if! {
|
||||||
mod riscv_intc;
|
mod riscv_intc;
|
||||||
mod riscv_plic;
|
mod riscv_plic;
|
||||||
|
|
||||||
pub use riscv_intc::{RiscvIntc, RiscvScauseIntCode};
|
pub mod riscv {
|
||||||
pub use riscv_plic::RiscvPlic;
|
pub use super::riscv_intc::{Intc, ScauseIntCode};
|
||||||
|
pub use super::riscv_plic::Plic;
|
||||||
|
}
|
||||||
|
} else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
|
||||||
|
mod x86_apic;
|
||||||
|
|
||||||
|
pub mod x86 {
|
||||||
|
pub use super::x86_apic::Apic;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,19 +9,19 @@ const S_TIMER: usize = 5;
|
||||||
const S_EXT: usize = 9;
|
const S_EXT: usize = 9;
|
||||||
|
|
||||||
#[repr(usize)]
|
#[repr(usize)]
|
||||||
pub enum RiscvScauseIntCode {
|
pub enum ScauseIntCode {
|
||||||
SupervisorSoft = S_SOFT,
|
SupervisorSoft = S_SOFT,
|
||||||
SupervisorTimer = S_TIMER,
|
SupervisorTimer = S_TIMER,
|
||||||
SupervisorExternal = S_EXT,
|
SupervisorExternal = S_EXT,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RiscvIntc {
|
pub struct Intc {
|
||||||
soft_handler: Mutex<Option<IrqHandler>>,
|
soft_handler: Mutex<Option<IrqHandler>>,
|
||||||
timer_handler: Mutex<Option<IrqHandler>>,
|
timer_handler: Mutex<Option<IrqHandler>>,
|
||||||
ext_handler: Mutex<Option<IrqHandler>>,
|
ext_handler: Mutex<Option<IrqHandler>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RiscvIntc {
|
impl Intc {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
soft_handler: Mutex::new(None),
|
soft_handler: Mutex::new(None),
|
||||||
|
@ -46,13 +46,13 @@ impl RiscvIntc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RiscvIntc {
|
impl Default for Intc {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scheme for RiscvIntc {
|
impl Scheme for Intc {
|
||||||
fn handle_irq(&self, cause: usize) {
|
fn handle_irq(&self, cause: usize) {
|
||||||
self.with_handler(cause, |opt| {
|
self.with_handler(cause, |opt| {
|
||||||
if let Some(h) = opt {
|
if let Some(h) = opt {
|
||||||
|
@ -66,7 +66,7 @@ impl Scheme for RiscvIntc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrqScheme for RiscvIntc {
|
impl IrqScheme for Intc {
|
||||||
fn mask(&self, cause: usize) {
|
fn mask(&self, cause: usize) {
|
||||||
unsafe {
|
unsafe {
|
||||||
match cause {
|
match cause {
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct PlicUnlocked {
|
||||||
manager: IrqManager<1024>,
|
manager: IrqManager<1024>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RiscvPlic {
|
pub struct Plic {
|
||||||
inner: Mutex<PlicUnlocked>,
|
inner: Mutex<PlicUnlocked>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ impl PlicUnlocked {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RiscvPlic {
|
impl Plic {
|
||||||
pub fn new(base: usize) -> Self {
|
pub fn new(base: usize) -> Self {
|
||||||
let mut inner = PlicUnlocked {
|
let mut inner = PlicUnlocked {
|
||||||
priority_base: unsafe { Mmio::<u32>::from_base(base + PLIC_PRIORITY_BASE) },
|
priority_base: unsafe { Mmio::<u32>::from_base(base + PLIC_PRIORITY_BASE) },
|
||||||
|
@ -85,11 +85,11 @@ impl RiscvPlic {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scheme for RiscvPlic {
|
impl Scheme for Plic {
|
||||||
fn handle_irq(&self, _unused: usize) {
|
fn handle_irq(&self, _unused: usize) {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
while let Some(irq_num) = inner.pending_irq() {
|
while let Some(irq_num) = inner.pending_irq() {
|
||||||
if inner.manager.handle(irq_num as _).is_err() {
|
if inner.manager.handle(irq_num).is_err() {
|
||||||
warn!("no registered handler for IRQ {}!", irq_num);
|
warn!("no registered handler for IRQ {}!", irq_num);
|
||||||
}
|
}
|
||||||
inner.eoi(irq_num);
|
inner.eoi(irq_num);
|
||||||
|
@ -97,7 +97,7 @@ impl Scheme for RiscvPlic {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrqScheme for RiscvPlic {
|
impl IrqScheme for Plic {
|
||||||
fn mask(&self, irq_num: usize) {
|
fn mask(&self, irq_num: usize) {
|
||||||
self.inner.lock().toggle(irq_num, false)
|
self.inner.lock().toggle(irq_num, false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
// TODO: configurable
|
||||||
|
|
||||||
|
pub const X86_INT_BASE: usize = 0x20;
|
||||||
|
pub const X86_INT_MAX: usize = 0xff;
|
||||||
|
|
||||||
|
pub const X86_INT_LOCAL_APIC_BASE: usize = 0xf0;
|
||||||
|
pub const X86_INT_APIC_SPURIOUS: usize = X86_INT_LOCAL_APIC_BASE + 0x0;
|
||||||
|
pub const X86_INT_APIC_TIMER: usize = X86_INT_LOCAL_APIC_BASE + 0x1;
|
||||||
|
pub const X86_INT_APIC_ERROR: usize = X86_INT_LOCAL_APIC_BASE + 0x2;
|
|
@ -0,0 +1,146 @@
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::{fmt, ptr::NonNull};
|
||||||
|
|
||||||
|
use acpi::platform::interrupt::InterruptModel;
|
||||||
|
use acpi::{AcpiHandler, AcpiTables, PhysicalMapping};
|
||||||
|
use spin::Mutex;
|
||||||
|
use x2apic::ioapic::IoApic as IoApicInner;
|
||||||
|
|
||||||
|
use super::Phys2VirtFn;
|
||||||
|
|
||||||
|
const PAGE_SIZE: usize = 4096;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct AcpiMapHandler {
|
||||||
|
phys_to_virt: Phys2VirtFn,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AcpiHandler for AcpiMapHandler {
|
||||||
|
unsafe fn map_physical_region<T>(
|
||||||
|
&self,
|
||||||
|
physical_address: usize,
|
||||||
|
size: usize,
|
||||||
|
) -> PhysicalMapping<Self, T> {
|
||||||
|
let aligned_start = physical_address & !(PAGE_SIZE - 1);
|
||||||
|
let aligned_end = (physical_address + size + PAGE_SIZE - 1) & !(PAGE_SIZE - 1);
|
||||||
|
let phys_to_virt = self.phys_to_virt;
|
||||||
|
PhysicalMapping::new(
|
||||||
|
physical_address,
|
||||||
|
NonNull::new_unchecked(phys_to_virt(physical_address) as *mut T),
|
||||||
|
size,
|
||||||
|
aligned_end - aligned_start,
|
||||||
|
self.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IoApic {
|
||||||
|
id: u8,
|
||||||
|
gsi_start: u32,
|
||||||
|
max_entry: u8,
|
||||||
|
inner: Mutex<IoApicInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IoApicList {
|
||||||
|
io_apics: Vec<IoApic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IoApic {
|
||||||
|
pub fn new(id: u8, base_vaddr: usize, gsi_start: u32) -> Self {
|
||||||
|
let mut inner = unsafe { IoApicInner::new(base_vaddr as u64) };
|
||||||
|
let max_entry = unsafe { inner.max_table_entry() };
|
||||||
|
unsafe {
|
||||||
|
assert_eq!(id, inner.id());
|
||||||
|
inner.init(super::consts::X86_INT_BASE as _);
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
gsi_start,
|
||||||
|
max_entry,
|
||||||
|
inner: Mutex::new(inner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle(&self, gsi: u32, enabled: bool) {
|
||||||
|
let idx = (gsi - self.gsi_start) as u8;
|
||||||
|
unsafe {
|
||||||
|
if enabled {
|
||||||
|
self.inner.lock().enable_irq(idx);
|
||||||
|
} else {
|
||||||
|
self.inner.lock().disable_irq(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_vector(&self, gsi: u32) -> u8 {
|
||||||
|
let idx = (gsi - self.gsi_start) as u8;
|
||||||
|
unsafe { self.inner.lock().table_entry(idx).vector() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_vector(&self, gsi: u32, vector: u8) {
|
||||||
|
let idx = (gsi - self.gsi_start) as u8;
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
unsafe {
|
||||||
|
let mut entry = inner.table_entry(idx);
|
||||||
|
entry.set_vector(vector);
|
||||||
|
inner.set_table_entry(idx, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IoApicList {
|
||||||
|
pub fn new(acpi_rsdp: usize, phys_to_virt: Phys2VirtFn) -> Self {
|
||||||
|
let handler = AcpiMapHandler { phys_to_virt };
|
||||||
|
let tables = unsafe { AcpiTables::from_rsdp(handler, acpi_rsdp).unwrap() };
|
||||||
|
let io_apics =
|
||||||
|
if let InterruptModel::Apic(apic) = tables.platform_info().unwrap().interrupt_model {
|
||||||
|
apic.io_apics
|
||||||
|
.iter()
|
||||||
|
.map(|i| {
|
||||||
|
IoApic::new(
|
||||||
|
i.id,
|
||||||
|
phys_to_virt(i.address as usize),
|
||||||
|
i.global_system_interrupt_base,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
Self { io_apics }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find(&self, gsi: u32) -> Option<&IoApic> {
|
||||||
|
self.io_apics
|
||||||
|
.iter()
|
||||||
|
.find(|i| i.gsi_start <= gsi && gsi <= i.gsi_start + i.max_entry as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for IoApic {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
struct RedirTable<'a>(&'a IoApic);
|
||||||
|
|
||||||
|
impl<'a> fmt::Debug for RedirTable<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut inner = self.0.inner.lock();
|
||||||
|
let count = self.0.max_entry + 1;
|
||||||
|
f.debug_list()
|
||||||
|
.entries((0..count).map(|i| unsafe { inner.table_entry(i) }))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let version = unsafe { self.inner.lock().version() };
|
||||||
|
f.debug_struct("IoApic")
|
||||||
|
.field("id", &self.id)
|
||||||
|
.field("version", &version)
|
||||||
|
.field("gsi_start", &self.gsi_start)
|
||||||
|
.field("max_entry", &self.max_entry)
|
||||||
|
.field("redir_table", &RedirTable(self))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
use x2apic::lapic::{xapic_base, LocalApic as LocalApicInner, LocalApicBuilder};
|
||||||
|
|
||||||
|
use super::{consts, Phys2VirtFn};
|
||||||
|
|
||||||
|
static mut LOCAL_APIC: Option<LocalApic> = None;
|
||||||
|
|
||||||
|
pub struct LocalApic {
|
||||||
|
inner: LocalApicInner,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocalApic {
|
||||||
|
pub fn eoi(&mut self) {
|
||||||
|
unsafe { self.inner.end_of_interrupt() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_local_apic<'a>() -> &'a mut LocalApic {
|
||||||
|
LOCAL_APIC
|
||||||
|
.as_mut()
|
||||||
|
.expect("Local APIC is not initialized by BSP")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn init_bsp(phys_to_virt: Phys2VirtFn) {
|
||||||
|
let base_vaddr = phys_to_virt(xapic_base() as usize);
|
||||||
|
let mut inner = LocalApicBuilder::new()
|
||||||
|
.timer_vector(consts::X86_INT_APIC_TIMER)
|
||||||
|
.error_vector(consts::X86_INT_APIC_ERROR)
|
||||||
|
.spurious_vector(consts::X86_INT_APIC_SPURIOUS)
|
||||||
|
.set_xapic_base(base_vaddr as u64)
|
||||||
|
.build()
|
||||||
|
.unwrap_or_else(|err| panic!("{}", err));
|
||||||
|
assert!(inner.is_bsp());
|
||||||
|
|
||||||
|
inner.enable();
|
||||||
|
LOCAL_APIC = Some(LocalApic { inner });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn init_ap() {
|
||||||
|
get_local_apic().inner.enable()
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
mod consts;
|
||||||
|
mod ioapic;
|
||||||
|
mod lapic;
|
||||||
|
|
||||||
|
use core::ops::Range;
|
||||||
|
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
use self::consts::{X86_INT_BASE, X86_INT_LOCAL_APIC_BASE, X86_INT_MAX};
|
||||||
|
use self::ioapic::{IoApic, IoApicList};
|
||||||
|
use self::lapic::LocalApic;
|
||||||
|
use crate::scheme::{IrqHandler, IrqScheme, Scheme};
|
||||||
|
use crate::{utils::IrqManager, DeviceError, DeviceResult};
|
||||||
|
|
||||||
|
const IRQ_RANGE: Range<usize> = X86_INT_BASE..X86_INT_MAX + 1;
|
||||||
|
|
||||||
|
type Phys2VirtFn = fn(usize) -> usize;
|
||||||
|
|
||||||
|
pub struct Apic {
|
||||||
|
ioapic_list: IoApicList,
|
||||||
|
manager: Mutex<IrqManager<256>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Apic {
|
||||||
|
pub fn new(acpi_rsdp: usize, phys_to_virt: Phys2VirtFn) -> Self {
|
||||||
|
Self {
|
||||||
|
manager: Mutex::new(IrqManager::new(IRQ_RANGE)),
|
||||||
|
ioapic_list: IoApicList::new(acpi_rsdp, phys_to_virt),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_ioapic<F>(&self, gsi: u32, op: F) -> DeviceResult
|
||||||
|
where
|
||||||
|
F: FnOnce(&IoApic) -> DeviceResult,
|
||||||
|
{
|
||||||
|
if let Some(apic) = self.ioapic_list.find(gsi) {
|
||||||
|
op(apic)
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"cannot find IOAPIC for global system interrupt number {}",
|
||||||
|
gsi
|
||||||
|
);
|
||||||
|
Err(DeviceError::InvalidParam)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_local_apic_bsp(phys_to_virt: Phys2VirtFn) {
|
||||||
|
unsafe { self::lapic::init_bsp(phys_to_virt) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_local_apic_ap() {
|
||||||
|
unsafe { self::lapic::init_ap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn local_apic<'a>() -> &'a mut LocalApic {
|
||||||
|
unsafe { self::lapic::get_local_apic() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_local_apic_handler(&self, vector: usize, handler: IrqHandler) -> DeviceResult {
|
||||||
|
if vector >= X86_INT_LOCAL_APIC_BASE {
|
||||||
|
self.manager.lock().register_handler(vector, handler)?;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
error!("invalid local APIC interrupt vector {}", vector);
|
||||||
|
Err(DeviceError::InvalidParam)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scheme for Apic {
|
||||||
|
fn handle_irq(&self, vector: usize) {
|
||||||
|
if self.manager.lock().handle(vector).is_err() {
|
||||||
|
warn!("no registered handler for interrupt vector {}!", vector);
|
||||||
|
}
|
||||||
|
Self::local_apic().eoi();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqScheme for Apic {
|
||||||
|
fn mask(&self, gsi: usize) {
|
||||||
|
self.with_ioapic(gsi as _, |apic| Ok(apic.toggle(gsi as _, false)))
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmask(&self, gsi: usize) {
|
||||||
|
self.with_ioapic(gsi as _, |apic| Ok(apic.toggle(gsi as _, true)))
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_handler(&self, gsi: usize, handler: IrqHandler) -> DeviceResult {
|
||||||
|
let gsi = gsi as u32;
|
||||||
|
self.with_ioapic(gsi, |apic| {
|
||||||
|
let vector = apic.get_vector(gsi) as _; // if not mapped, allocate an available vector by `register_handler()`.
|
||||||
|
let vector = self.manager.lock().register_handler(vector, handler)? as u8;
|
||||||
|
apic.map_vector(gsi, vector);
|
||||||
|
apic.toggle(gsi, true);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,15 +33,18 @@ impl<const IRQ_COUNT: usize> IrqManager<IRQ_COUNT> {
|
||||||
self.allocator.free(start, count)
|
self.allocator.free(start, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a handler to IRQ table. Return the specified irq or an allocated irq on success
|
/// Add a handler to IRQ table. if `irq_num == 0`, we need to allocate one.
|
||||||
|
/// Returns the specified IRQ number or an allocated IRQ on success.
|
||||||
pub fn register_handler(&mut self, irq_num: usize, handler: IrqHandler) -> DeviceResult<usize> {
|
pub fn register_handler(&mut self, irq_num: usize, handler: IrqHandler) -> DeviceResult<usize> {
|
||||||
info!("IRQ add handler {:#x?}", irq_num);
|
info!("IRQ add handler {:#x?}", irq_num);
|
||||||
let irq_num = if !self.irq_range.contains(&irq_num) {
|
let irq_num = if irq_num == 0 {
|
||||||
// allocate a valid irq number
|
// allocate a valid IRQ number
|
||||||
self.allocator.alloc()?
|
self.allocator.alloc()?
|
||||||
} else {
|
} else if self.irq_range.contains(&irq_num) {
|
||||||
self.allocator.alloc_fixed(irq_num)?;
|
self.allocator.alloc_fixed(irq_num)?;
|
||||||
irq_num
|
irq_num
|
||||||
|
} else {
|
||||||
|
return Err(DeviceError::InvalidParam);
|
||||||
};
|
};
|
||||||
self.table[irq_num] = Some(handler);
|
self.table[irq_num] = Some(handler);
|
||||||
Ok(irq_num)
|
Ok(irq_num)
|
||||||
|
|
|
@ -20,7 +20,6 @@ numeric-enum-macro = "0.2"
|
||||||
spin = "0.9"
|
spin = "0.9"
|
||||||
git-version = "0.3"
|
git-version = "0.3"
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
acpi = "1.1"
|
|
||||||
zcore-drivers = { path = "../drivers" }
|
zcore-drivers = { path = "../drivers" }
|
||||||
|
|
||||||
# LibOS mode
|
# LibOS mode
|
||||||
|
@ -41,7 +40,6 @@ bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev =
|
||||||
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]
|
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]
|
||||||
x86_64 = "0.14"
|
x86_64 = "0.14"
|
||||||
raw-cpuid = "9.0"
|
raw-cpuid = "9.0"
|
||||||
apic = { git = "https://github.com/rcore-os/apic-rs", rev = "fb86bd7" }
|
|
||||||
x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "43ffedf" }
|
x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "43ffedf" }
|
||||||
|
|
||||||
# Bare-metal mode on riscv64
|
# Bare-metal mode on riscv64
|
||||||
|
|
|
@ -1,39 +1,35 @@
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
use zcore_drivers::irq::{RiscvIntc, RiscvPlic, RiscvScauseIntCode};
|
use zcore_drivers::irq::riscv::{Intc, Plic, ScauseIntCode};
|
||||||
use zcore_drivers::scheme::{AsScheme, EventListener, IrqScheme};
|
use zcore_drivers::scheme::{AsScheme, EventListener, IrqScheme};
|
||||||
use zcore_drivers::uart::Uart16550Mmio;
|
use zcore_drivers::uart::Uart16550Mmio;
|
||||||
|
use zcore_drivers::DeviceResult;
|
||||||
|
|
||||||
use super::{consts, trap};
|
use super::{consts, trap};
|
||||||
use crate::drivers::{IRQ, UART};
|
use crate::drivers::{IRQ, UART};
|
||||||
use crate::mem::phys_to_virt;
|
use crate::mem::phys_to_virt;
|
||||||
use crate::utils::init_once::InitOnce;
|
use crate::utils::init_once::InitOnce;
|
||||||
|
|
||||||
static PLIC: InitOnce<RiscvPlic> = InitOnce::new();
|
static PLIC: InitOnce<Plic> = InitOnce::new();
|
||||||
|
|
||||||
pub(super) fn init() {
|
pub(super) fn init() -> DeviceResult {
|
||||||
IRQ.init_by(Box::new(RiscvIntc::new()));
|
|
||||||
UART.init_by(Box::new(EventListener::new(unsafe {
|
UART.init_by(Box::new(EventListener::new(unsafe {
|
||||||
Uart16550Mmio::<u8>::new(phys_to_virt(consts::UART_BASE))
|
Uart16550Mmio::<u8>::new(phys_to_virt(consts::UART_BASE))
|
||||||
})));
|
})));
|
||||||
|
IRQ.init_by(Box::new(Intc::new()));
|
||||||
|
|
||||||
PLIC.init_by(RiscvPlic::new(phys_to_virt(consts::PLIC_BASE)));
|
PLIC.init_by(Plic::new(phys_to_virt(consts::PLIC_BASE)));
|
||||||
PLIC.register_device(consts::UART0_INT_NUM, UART.as_scheme())
|
PLIC.register_device(consts::UART0_INT_NUM, UART.as_scheme())?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
IRQ.register_handler(
|
IRQ.register_handler(
|
||||||
RiscvScauseIntCode::SupervisorSoft as _,
|
ScauseIntCode::SupervisorSoft as _,
|
||||||
Box::new(|_| trap::super_soft()),
|
Box::new(|_| trap::super_soft()),
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
IRQ.register_handler(
|
IRQ.register_handler(
|
||||||
RiscvScauseIntCode::SupervisorTimer as _,
|
ScauseIntCode::SupervisorTimer as _,
|
||||||
Box::new(|_| trap::super_timer()),
|
Box::new(|_| trap::super_timer()),
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
IRQ.register_device(ScauseIntCode::SupervisorExternal as _, PLIC.as_scheme())?;
|
||||||
IRQ.register_device(
|
|
||||||
RiscvScauseIntCode::SupervisorExternal as _,
|
Ok(())
|
||||||
PLIC.as_scheme(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub mod vm;
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
vm::remap_the_kernel().unwrap();
|
vm::remap_the_kernel().unwrap();
|
||||||
drivers::init();
|
drivers::init().unwrap();
|
||||||
interrupt::init();
|
interrupt::init();
|
||||||
timer::init();
|
timer::init();
|
||||||
|
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use core::ptr::NonNull;
|
|
||||||
|
|
||||||
use acpi::interrupt::{InterruptModel, InterruptSourceOverride, IoApic, Polarity, TriggerMode};
|
|
||||||
use acpi::{parse_rsdp, Acpi, AcpiHandler, PhysicalMapping};
|
|
||||||
use spin::Mutex;
|
|
||||||
|
|
||||||
use crate::{mem::phys_to_virt, PAGE_SIZE};
|
|
||||||
|
|
||||||
pub struct AcpiTable {
|
|
||||||
inner: Acpi,
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref ACPI_TABLE: Mutex<Option<AcpiTable>> = Mutex::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build ACPI Table
|
|
||||||
struct AcpiHelper;
|
|
||||||
|
|
||||||
impl AcpiHandler for AcpiHelper {
|
|
||||||
unsafe fn map_physical_region<T>(
|
|
||||||
&mut self,
|
|
||||||
physical_address: usize,
|
|
||||||
size: usize,
|
|
||||||
) -> PhysicalMapping<T> {
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
let OFFSET = 0;
|
|
||||||
let page_start = physical_address / PAGE_SIZE;
|
|
||||||
let page_end = (physical_address + size + PAGE_SIZE - 1) / PAGE_SIZE;
|
|
||||||
PhysicalMapping::<T> {
|
|
||||||
physical_start: physical_address,
|
|
||||||
virtual_start: NonNull::new_unchecked(phys_to_virt(physical_address + OFFSET) as *mut T),
|
|
||||||
mapped_length: size,
|
|
||||||
region_length: PAGE_SIZE * (page_end - page_start),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn unmap_physical_region<T>(&mut self, _region: PhysicalMapping<T>) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_acpi_table() -> Option<Acpi> {
|
|
||||||
let mut handler = AcpiHelper;
|
|
||||||
match unsafe {
|
|
||||||
parse_rsdp(
|
|
||||||
&mut handler,
|
|
||||||
super::special::pc_firmware_tables().0 as usize,
|
|
||||||
)
|
|
||||||
} {
|
|
||||||
Ok(table) => Some(table),
|
|
||||||
Err(info) => {
|
|
||||||
warn!("get_acpi_table error: {:#x?}", info);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AcpiTable {
|
|
||||||
fn initialize_check() {
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
{
|
|
||||||
let mut table = ACPI_TABLE.lock();
|
|
||||||
if table.is_none() {
|
|
||||||
*table = get_acpi_table().map(|x| AcpiTable { inner: x });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn invalidate() {
|
|
||||||
*ACPI_TABLE.lock() = None;
|
|
||||||
}
|
|
||||||
pub fn get_ioapic() -> Vec<IoApic> {
|
|
||||||
Self::initialize_check();
|
|
||||||
let table = ACPI_TABLE.lock();
|
|
||||||
match &*table {
|
|
||||||
None => Vec::default(),
|
|
||||||
Some(table) => match table.inner.interrupt_model.as_ref().unwrap() {
|
|
||||||
InterruptModel::Apic(apic) => {
|
|
||||||
apic.io_apics.iter().map(|x| IoApic { ..*x }).collect()
|
|
||||||
}
|
|
||||||
_ => Vec::default(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn get_interrupt_source_overrides() -> Vec<InterruptSourceOverride> {
|
|
||||||
Self::initialize_check();
|
|
||||||
let table = ACPI_TABLE.lock();
|
|
||||||
match &*table {
|
|
||||||
None => Vec::default(),
|
|
||||||
Some(table) => match table.inner.interrupt_model.as_ref().unwrap() {
|
|
||||||
InterruptModel::Apic(apic) => apic
|
|
||||||
.interrupt_source_overrides
|
|
||||||
.iter()
|
|
||||||
.map(|x| InterruptSourceOverride {
|
|
||||||
polarity: Self::clone_polarity(&x.polarity),
|
|
||||||
trigger_mode: Self::clone_trigger_mode(&x.trigger_mode),
|
|
||||||
..*x
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
_ => Vec::default(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn clone_polarity(x: &Polarity) -> Polarity {
|
|
||||||
match x {
|
|
||||||
Polarity::SameAsBus => Polarity::SameAsBus,
|
|
||||||
Polarity::ActiveHigh => Polarity::ActiveHigh,
|
|
||||||
Polarity::ActiveLow => Polarity::ActiveLow,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn clone_trigger_mode(x: &TriggerMode) -> TriggerMode {
|
|
||||||
match x {
|
|
||||||
TriggerMode::SameAsBus => TriggerMode::SameAsBus,
|
|
||||||
TriggerMode::Edge => TriggerMode::Edge,
|
|
||||||
TriggerMode::Level => TriggerMode::Level,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
use apic::{IoApic, LocalApic, XApic};
|
|
||||||
|
|
||||||
use crate::mem::phys_to_virt;
|
|
||||||
|
|
||||||
const LAPIC_ADDR: usize = 0xfee0_0000;
|
|
||||||
const IOAPIC_ADDR: usize = 0xfec0_0000;
|
|
||||||
|
|
||||||
pub fn get_lapic() -> XApic {
|
|
||||||
unsafe { XApic::new(phys_to_virt(LAPIC_ADDR)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_ioapic() -> IoApic {
|
|
||||||
unsafe { IoApic::new(phys_to_virt(IOAPIC_ADDR)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lapic_id() -> u8 {
|
|
||||||
get_lapic().id() as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init() {
|
|
||||||
get_lapic().cpu_init();
|
|
||||||
}
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
use raw_cpuid::CpuId;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref TSC_FREQUENCY: u16 = {
|
static ref TSC_FREQUENCY: u16 = {
|
||||||
const DEFAULT: u16 = 2600;
|
const DEFAULT: u16 = 4000;
|
||||||
if let Some(info) = raw_cpuid::CpuId::new().get_processor_frequency_info() {
|
if let Some(info) = CpuId::new().get_processor_frequency_info() {
|
||||||
let f = info.processor_base_frequency();
|
let f = info.processor_base_frequency();
|
||||||
return if f == 0 { DEFAULT } else { f };
|
return if f == 0 { DEFAULT } else { f };
|
||||||
}
|
}
|
||||||
|
@ -13,7 +15,10 @@ lazy_static! {
|
||||||
hal_fn_impl! {
|
hal_fn_impl! {
|
||||||
impl mod crate::hal_fn::cpu {
|
impl mod crate::hal_fn::cpu {
|
||||||
fn cpu_id() -> u8 {
|
fn cpu_id() -> u8 {
|
||||||
super::apic::lapic_id()
|
CpuId::new()
|
||||||
|
.get_feature_info()
|
||||||
|
.unwrap()
|
||||||
|
.initial_local_apic_id() as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cpu_frequency() -> u16 {
|
fn cpu_frequency() -> u16 {
|
||||||
|
|
|
@ -1,10 +1,27 @@
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
use zcore_drivers::scheme::EventListener;
|
use zcore_drivers::irq::x86::Apic;
|
||||||
|
use zcore_drivers::scheme::{EventListener, IrqScheme};
|
||||||
use zcore_drivers::uart::Uart16550Pio;
|
use zcore_drivers::uart::Uart16550Pio;
|
||||||
|
use zcore_drivers::DeviceResult;
|
||||||
|
|
||||||
use crate::drivers::UART;
|
use super::trap;
|
||||||
|
use crate::drivers::{IRQ, UART};
|
||||||
|
|
||||||
pub(super) fn init() {
|
pub(super) fn init() -> DeviceResult {
|
||||||
UART.init_by(Box::new(EventListener::new(Uart16550Pio::new(0x3F8))));
|
UART.init_by(Box::new(EventListener::new(Uart16550Pio::new(0x3F8))));
|
||||||
|
|
||||||
|
Apic::init_local_apic_bsp(crate::mem::phys_to_virt);
|
||||||
|
let irq = Box::new(Apic::new(
|
||||||
|
super::special::pc_firmware_tables().0 as usize,
|
||||||
|
crate::mem::phys_to_virt,
|
||||||
|
));
|
||||||
|
irq.register_device(trap::X86_ISA_IRQ_COM1, UART.as_scheme())?;
|
||||||
|
irq.register_local_apic_handler(
|
||||||
|
trap::X86_INT_APIC_TIMER,
|
||||||
|
Box::new(|_| crate::timer::timer_tick()),
|
||||||
|
)?;
|
||||||
|
IRQ.init_by(irq);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +1,9 @@
|
||||||
#![allow(dead_code)]
|
use alloc::boxed::Box;
|
||||||
#![allow(non_upper_case_globals)]
|
|
||||||
|
|
||||||
use alloc::{boxed::Box, vec::Vec};
|
|
||||||
use core::ops::Range;
|
use core::ops::Range;
|
||||||
|
|
||||||
use apic::IoApic;
|
use crate::HalResult;
|
||||||
use spin::Mutex;
|
|
||||||
|
|
||||||
use super::acpi_table::AcpiTable;
|
type IrqHandler = Box<dyn Fn() + Send + Sync>;
|
||||||
use crate::utils::irq_manager::{IrqHandler, IrqManager};
|
|
||||||
use crate::{mem::phys_to_virt, HalError, HalResult};
|
|
||||||
|
|
||||||
const IRQ0: u32 = 32;
|
|
||||||
|
|
||||||
const IRQ_MIN_ID: u32 = 0x20;
|
|
||||||
const IRQ_MAX_ID: u32 = 0xff;
|
|
||||||
|
|
||||||
// IRQ
|
|
||||||
const Timer: u32 = 0;
|
|
||||||
const Keyboard: u32 = 1;
|
|
||||||
const COM2: u32 = 3;
|
|
||||||
const COM1: u32 = 4;
|
|
||||||
const Mouse: u32 = 12;
|
|
||||||
const IDE: u32 = 14;
|
|
||||||
const Error: u32 = 19;
|
|
||||||
const Spurious: u32 = 31;
|
|
||||||
|
|
||||||
const IO_APIC_NUM_REDIRECTIONS: u8 = 120;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref IRQ_MANAGER: Mutex<IrqManager> = Mutex::new(IrqManager::new(0x20, 0xff));
|
|
||||||
static ref MAX_INSTR_TABLE: Mutex<Vec<(usize, u8)>> = Mutex::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -64,158 +36,42 @@ fn mouse() {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn ioapic_maxinstr(ioapic_addr: u32) -> Option<u8> {
|
|
||||||
let mut table = MAX_INSTR_TABLE.lock();
|
|
||||||
for (addr, v) in table.iter() {
|
|
||||||
if *addr == ioapic_addr as usize {
|
|
||||||
return Some(*v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut ioapic = unsafe { IoApic::new(phys_to_virt(ioapic_addr as usize)) };
|
|
||||||
let v = ioapic.maxintr();
|
|
||||||
table.push((ioapic_addr as usize, v));
|
|
||||||
Some(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn init_ioapic() {
|
|
||||||
for ioapic in AcpiTable::get_ioapic() {
|
|
||||||
info!("Ioapic found: {:#x?}", ioapic);
|
|
||||||
let mut ip = IoApic::new(phys_to_virt(ioapic.address as usize));
|
|
||||||
ip.disable_all();
|
|
||||||
}
|
|
||||||
let mut ip = super::apic::get_ioapic();
|
|
||||||
ip.disable_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_ioapic(irq: u32) -> Option<acpi::interrupt::IoApic> {
|
|
||||||
for i in AcpiTable::get_ioapic() {
|
|
||||||
let num_instr = core::cmp::min(
|
|
||||||
ioapic_maxinstr(i.address).unwrap(),
|
|
||||||
IO_APIC_NUM_REDIRECTIONS - 1,
|
|
||||||
);
|
|
||||||
if i.global_system_interrupt_base <= irq
|
|
||||||
&& irq <= i.global_system_interrupt_base + num_instr as u32
|
|
||||||
{
|
|
||||||
return Some(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ioapic_controller(i: &acpi::interrupt::IoApic) -> IoApic {
|
|
||||||
unsafe { IoApic::new(phys_to_virt(i.address as usize)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
hal_fn_impl! {
|
hal_fn_impl! {
|
||||||
impl mod crate::hal_fn::interrupt {
|
impl mod crate::hal_fn::interrupt {
|
||||||
fn enable_irq(irq: u32) {
|
fn enable_irq(irq: u32) {
|
||||||
info!("enable_irq irq={:#x?}", irq);
|
todo!()
|
||||||
// if irq == 1 {
|
|
||||||
// irq_enable_raw(irq as u8, irq as u8 + IRQ0);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
if let Some(x) = get_ioapic(irq) {
|
|
||||||
let mut ioapic = ioapic_controller(&x);
|
|
||||||
ioapic.enable((irq - x.global_system_interrupt_base) as u8, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disable_irq(irq: u32) {
|
fn disable_irq(irq: u32) {
|
||||||
info!("disable_irq");
|
todo!()
|
||||||
if let Some(x) = get_ioapic(irq) {
|
|
||||||
let mut ioapic = ioapic_controller(&x);
|
|
||||||
ioapic.disable((irq - x.global_system_interrupt_base) as u8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_valid_irq(irq: u32) -> bool {
|
fn is_valid_irq(irq: u32) -> bool {
|
||||||
trace!("is_valid_irq: irq={:#x?}", irq);
|
todo!()
|
||||||
get_ioapic(irq).is_some()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_irq(vector: u32, trig_mode: bool, polarity: bool) -> HalResult {
|
fn configure_irq(vector: u32, trig_mode: bool, polarity: bool) -> HalResult {
|
||||||
info!(
|
todo!()
|
||||||
"configure_irq: vector={:#x?}, trig_mode={:#x?}, polarity={:#x?}",
|
|
||||||
vector, trig_mode, polarity
|
|
||||||
);
|
|
||||||
let dest = super::apic::lapic_id();
|
|
||||||
get_ioapic(vector)
|
|
||||||
.map(|x| {
|
|
||||||
let mut ioapic = ioapic_controller(&x);
|
|
||||||
ioapic.config(
|
|
||||||
(vector - x.global_system_interrupt_base) as u8,
|
|
||||||
0,
|
|
||||||
dest,
|
|
||||||
trig_mode,
|
|
||||||
polarity,
|
|
||||||
false, /* physical */
|
|
||||||
true, /* mask */
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.ok_or(HalError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_irq_handler(global_irq: u32, handler: IrqHandler) -> HalResult<u32> {
|
fn register_irq_handler(global_irq: u32, handler: IrqHandler) -> HalResult<u32> {
|
||||||
info!("register_irq_handler irq={:#x?}", global_irq);
|
todo!()
|
||||||
// if global_irq == 1 {
|
|
||||||
// irq_add_handler(global_irq as u8 + IRQ0, handler);
|
|
||||||
// return Some(global_irq as u8 + IRQ0);
|
|
||||||
// }
|
|
||||||
let ioapic_info = get_ioapic(global_irq).ok_or(HalError)?;
|
|
||||||
let mut ioapic = ioapic_controller(&ioapic_info);
|
|
||||||
let offset = (global_irq - ioapic_info.global_system_interrupt_base) as u8;
|
|
||||||
let x86_vector = ioapic.irq_vector(offset);
|
|
||||||
let new_handler = if global_irq == 0x1 {
|
|
||||||
Box::new(move || {
|
|
||||||
handler();
|
|
||||||
// keyboard();
|
|
||||||
// mouse();
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
handler
|
|
||||||
};
|
|
||||||
let x86_vector = IRQ_MANAGER
|
|
||||||
.lock()
|
|
||||||
.register_handler(x86_vector as u32, new_handler)?;
|
|
||||||
info!(
|
|
||||||
"irq_set_handle: mapping from {:#x?} to {:#x?}",
|
|
||||||
global_irq, x86_vector
|
|
||||||
);
|
|
||||||
ioapic.set_irq_vector(offset, x86_vector as u8);
|
|
||||||
Ok(x86_vector)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unregister_irq_handler(global_irq: u32) -> HalResult {
|
fn unregister_irq_handler(global_irq: u32) -> HalResult {
|
||||||
info!("unregister_irq_handler irq={:#x}", global_irq);
|
todo!()
|
||||||
let ioapic_info = if let Some(x) = get_ioapic(global_irq) {
|
|
||||||
x
|
|
||||||
} else {
|
|
||||||
return Err(HalError);
|
|
||||||
};
|
|
||||||
let mut ioapic = ioapic_controller(&ioapic_info);
|
|
||||||
let offset = (global_irq - ioapic_info.global_system_interrupt_base) as u8;
|
|
||||||
let x86_vector = ioapic.irq_vector(offset);
|
|
||||||
// TODO: ioapic redirection entries associated with this should be reset.
|
|
||||||
IRQ_MANAGER.lock().unregister_handler(x86_vector as u32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_irq(vector: u32) {
|
fn handle_irq(vector: u32) {
|
||||||
use apic::LocalApic;
|
crate::drivers::IRQ.handle_irq(vector as usize);
|
||||||
let mut lapic = super::apic::get_lapic();
|
|
||||||
lapic.eoi();
|
|
||||||
IRQ_MANAGER.lock().handle(vector);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn msi_allocate_block(requested_irqs: u32) -> HalResult<Range<u32>> {
|
fn msi_allocate_block(requested_irqs: u32) -> HalResult<Range<u32>> {
|
||||||
let alloc_size = requested_irqs.next_power_of_two();
|
todo!()
|
||||||
let start = IRQ_MANAGER.lock().alloc_block(alloc_size)?;
|
|
||||||
Ok(start..start + alloc_size)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn msi_free_block(block: Range<u32>) -> HalResult {
|
fn msi_free_block(block: Range<u32>) -> HalResult {
|
||||||
IRQ_MANAGER
|
todo!()
|
||||||
.lock()
|
|
||||||
.free_block(block.start, block.len() as u32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn msi_register_handler(
|
fn msi_register_handler(
|
||||||
|
@ -223,22 +79,11 @@ hal_fn_impl! {
|
||||||
msi_id: u32,
|
msi_id: u32,
|
||||||
handler: Box<dyn Fn() + Send + Sync>,
|
handler: Box<dyn Fn() + Send + Sync>,
|
||||||
) -> HalResult {
|
) -> HalResult {
|
||||||
IRQ_MANAGER
|
todo!()
|
||||||
.lock()
|
|
||||||
.overwrite_handler(block.start + msi_id, handler)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn irq57test() {
|
|
||||||
warn!("irq 57");
|
|
||||||
// poll_ifaces();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn timer() {
|
|
||||||
crate::timer::timer_tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fn keyboard() {
|
fn keyboard() {
|
||||||
use pc_keyboard::{DecodedKey, KeyCode};
|
use pc_keyboard::{DecodedKey, KeyCode};
|
||||||
|
@ -261,33 +106,3 @@ fn keyboard() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn irq_enable_raw(irq: u32, vector: u32) {
|
|
||||||
info!("irq_enable_raw: irq={:#x?}, vector={:#x?}", irq, vector);
|
|
||||||
let mut ioapic = super::apic::get_ioapic();
|
|
||||||
ioapic.set_irq_vector(irq as u8, vector as u8);
|
|
||||||
ioapic.enable(irq as u8, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn init() {
|
|
||||||
// MOUSE.lock().init().unwrap();
|
|
||||||
// MOUSE.lock().set_on_complete(mouse_on_complete);
|
|
||||||
unsafe {
|
|
||||||
init_ioapic();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut im = IRQ_MANAGER.lock();
|
|
||||||
im.register_handler(Timer + IRQ_MIN_ID, Box::new(timer))
|
|
||||||
.ok();
|
|
||||||
// im.register_handler(Keyboard + IRQ_MIN_ID, Box::new(keyboard));
|
|
||||||
// im.register_handler(Mouse + IRQ_MIN_ID, Box::new(mouse));
|
|
||||||
im.register_handler(
|
|
||||||
COM1 + IRQ_MIN_ID,
|
|
||||||
Box::new(|| crate::drivers::UART.handle_irq(COM1 as usize)),
|
|
||||||
)
|
|
||||||
.ok();
|
|
||||||
im.register_handler(57u32, Box::new(irq57test)).ok();
|
|
||||||
// register_handler(Keyboard, Keyboard + IRQ_MIN_ID);
|
|
||||||
// register_handler(Mouse, Mouse + IRQ_MIN_ID);
|
|
||||||
irq_enable_raw(COM1, COM1 + IRQ_MIN_ID);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
mod acpi_table;
|
// mod acpi_table;
|
||||||
mod apic;
|
// mod apic;
|
||||||
mod drivers;
|
mod drivers;
|
||||||
mod trap;
|
mod trap;
|
||||||
|
|
||||||
|
@ -15,30 +15,33 @@ pub mod vm;
|
||||||
use x86_64::registers::control::{Cr4, Cr4Flags};
|
use x86_64::registers::control::{Cr4, Cr4Flags};
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
apic::init();
|
drivers::init().unwrap();
|
||||||
drivers::init();
|
|
||||||
interrupt::init();
|
|
||||||
|
|
||||||
fn ap_main() {
|
let stack_fn = |pid: usize| -> usize {
|
||||||
info!("processor {} started", cpu::cpu_id());
|
|
||||||
unsafe { trapframe::init() };
|
|
||||||
apic::init();
|
|
||||||
let ap_fn = crate::KCONFIG.ap_fn;
|
|
||||||
ap_fn();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stack_fn(pid: usize) -> usize {
|
|
||||||
// split and reuse the current stack
|
// split and reuse the current stack
|
||||||
let mut stack: usize;
|
let mut stack: usize;
|
||||||
unsafe { asm!("mov {}, rsp", out(reg) stack) };
|
unsafe { asm!("mov {}, rsp", out(reg) stack) };
|
||||||
stack -= 0x4000 * pid;
|
stack -= 0x4000 * pid;
|
||||||
stack
|
stack
|
||||||
}
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// enable global page
|
// enable global page
|
||||||
Cr4::update(|f| f.insert(Cr4Flags::PAGE_GLOBAL));
|
Cr4::update(|f| f.insert(Cr4Flags::PAGE_GLOBAL));
|
||||||
// start multi-processors
|
// start multi-processors
|
||||||
x86_smpboot::start_application_processors(ap_main, stack_fn, crate::mem::phys_to_virt);
|
x86_smpboot::start_application_processors(
|
||||||
|
|| {
|
||||||
|
init_ap();
|
||||||
|
let ap_fn = crate::KCONFIG.ap_fn;
|
||||||
|
ap_fn();
|
||||||
|
},
|
||||||
|
stack_fn,
|
||||||
|
crate::mem::phys_to_virt,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn init_ap() {
|
||||||
|
info!("processor {} started", cpu::cpu_id());
|
||||||
|
unsafe { trapframe::init() };
|
||||||
|
zcore_drivers::irq::x86::Apic::init_local_apic_ap();
|
||||||
|
}
|
||||||
|
|
|
@ -1,32 +1,48 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#![allow(non_upper_case_globals)]
|
|
||||||
|
|
||||||
use trapframe::TrapFrame;
|
use trapframe::TrapFrame;
|
||||||
|
|
||||||
// Reference: https://wiki.osdev.org/Exceptions
|
// Reference: https://wiki.osdev.org/Exceptions
|
||||||
const DivideError: u8 = 0;
|
const DIVIDE_ERROR: usize = 0;
|
||||||
const Debug: u8 = 1;
|
const DEBUG: usize = 1;
|
||||||
const NonMaskableInterrupt: u8 = 2;
|
const NON_MASKABLE_INTERRUPT: usize = 2;
|
||||||
const Breakpoint: u8 = 3;
|
const BREAKPOINT: usize = 3;
|
||||||
const Overflow: u8 = 4;
|
const OVERFLOW: usize = 4;
|
||||||
const BoundRangeExceeded: u8 = 5;
|
const BOUND_RANGE_EXCEEDED: usize = 5;
|
||||||
const InvalidOpcode: u8 = 6;
|
const INVALID_OPCODE: usize = 6;
|
||||||
const DeviceNotAvailable: u8 = 7;
|
const DEVICE_NOT_AVAILABLE: usize = 7;
|
||||||
const DoubleFault: u8 = 8;
|
const DOUBLE_FAULT: usize = 8;
|
||||||
const CoprocessorSegmentOverrun: u8 = 9;
|
const COPROCESSOR_SEGMENT_OVERRUN: usize = 9;
|
||||||
const InvalidTSS: u8 = 10;
|
const INVALID_TSS: usize = 10;
|
||||||
const SegmentNotPresent: u8 = 11;
|
const SEGMENT_NOT_PRESENT: usize = 11;
|
||||||
const StackSegmentFault: u8 = 12;
|
const STACK_SEGMENT_FAULT: usize = 12;
|
||||||
const GeneralProtectionFault: u8 = 13;
|
const GENERAL_PROTECTION_FAULT: usize = 13;
|
||||||
const PageFault: u8 = 14;
|
const PAGE_FAULT: usize = 14;
|
||||||
const FloatingPointException: u8 = 16;
|
const FLOATING_POINTEXCEPTION: usize = 16;
|
||||||
const AlignmentCheck: u8 = 17;
|
const ALIGNMENT_CHECK: usize = 17;
|
||||||
const MachineCheck: u8 = 18;
|
const MACHINE_CHECK: usize = 18;
|
||||||
const SIMDFloatingPointException: u8 = 19;
|
const SIMD_FLOATING_POINT_EXCEPTION: usize = 19;
|
||||||
const VirtualizationException: u8 = 20;
|
const VIRTUALIZATION_EXCEPTION: usize = 20;
|
||||||
const SecurityException: u8 = 30;
|
const SECURITY_EXCEPTION: usize = 30;
|
||||||
|
|
||||||
const IRQ0: u8 = 32;
|
// IRQ vectors
|
||||||
|
pub(super) const X86_INT_BASE: usize = 0x20;
|
||||||
|
pub(super) const X86_INT_MAX: usize = 0xff;
|
||||||
|
|
||||||
|
pub(super) const X86_INT_LOCAL_APIC_BASE: usize = 0xf0;
|
||||||
|
pub(super) const X86_INT_APIC_SPURIOUS: usize = X86_INT_LOCAL_APIC_BASE + 0x0;
|
||||||
|
pub(super) const X86_INT_APIC_TIMER: usize = X86_INT_LOCAL_APIC_BASE + 0x1;
|
||||||
|
pub(super) const X86_INT_APIC_ERROR: usize = X86_INT_LOCAL_APIC_BASE + 0x2;
|
||||||
|
|
||||||
|
// ISA IRQ numbers
|
||||||
|
pub(super) const X86_ISA_IRQ_PIT: usize = 0;
|
||||||
|
pub(super) const X86_ISA_IRQ_KEYBOARD: usize = 1;
|
||||||
|
pub(super) const X86_ISA_IRQ_PIC2: usize = 2;
|
||||||
|
pub(super) const X86_ISA_IRQ_COM2: usize = 3;
|
||||||
|
pub(super) const X86_ISA_IRQ_COM1: usize = 4;
|
||||||
|
pub(super) const X86_ISA_IRQ_CMOSRTC: usize = 8;
|
||||||
|
pub(super) const X86_ISA_IRQ_MOUSE: usize = 12;
|
||||||
|
pub(super) const X86_ISA_IRQ_IDE: usize = 14;
|
||||||
|
|
||||||
fn breakpoint() {
|
fn breakpoint() {
|
||||||
panic!("\nEXCEPTION: Breakpoint");
|
panic!("\nEXCEPTION: Breakpoint");
|
||||||
|
@ -44,11 +60,11 @@ fn page_fault(tf: &mut TrapFrame) {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
||||||
trace!("Interrupt: {:#x} @ CPU{}", tf.trap_num, 0); // TODO 0 should replace in multi-core case
|
trace!("Interrupt: {:#x} @ CPU{}", tf.trap_num, 0); // TODO 0 should replace in multi-core case
|
||||||
match tf.trap_num as u8 {
|
match tf.trap_num {
|
||||||
Breakpoint => breakpoint(),
|
BREAKPOINT => breakpoint(),
|
||||||
DoubleFault => double_fault(tf),
|
DOUBLE_FAULT => double_fault(tf),
|
||||||
PageFault => page_fault(tf),
|
PAGE_FAULT => page_fault(tf),
|
||||||
IRQ0..=63 => crate::interrupt::handle_irq(tf.trap_num as u32),
|
X86_INT_BASE..=X86_INT_MAX => crate::interrupt::handle_irq(tf.trap_num as u32),
|
||||||
_ => panic!("Unhandled interrupt {:x} {:#x?}", tf.trap_num, tf),
|
_ => panic!("Unhandled interrupt {:x} {:#x?}", tf.trap_num, tf),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ hal_fn_def! {
|
||||||
/// Is a valid IRQ number.
|
/// Is a valid IRQ number.
|
||||||
pub fn is_valid_irq(vector: u32) -> bool;
|
pub fn is_valid_irq(vector: u32) -> bool;
|
||||||
|
|
||||||
/// Configure the specified interrupt vector. If it is invoked, it muust be
|
/// Configure the specified interrupt vector. If it is invoked, it must be
|
||||||
/// invoked prior to interrupt registration.
|
/// invoked prior to interrupt registration.
|
||||||
pub fn configure_irq(vector: u32, trig_mode: bool, polarity: bool) -> HalResult;
|
pub fn configure_irq(vector: u32, trig_mode: bool, polarity: bool) -> HalResult;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#![cfg_attr(not(feature = "libos"), no_std)]
|
#![cfg_attr(not(feature = "libos"), no_std)]
|
||||||
#![feature(asm)]
|
#![feature(asm)]
|
||||||
#![deny(warnings)]
|
// #![deny(warnings)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
use alloc::boxed::Box;
|
|
||||||
use bitmap_allocator::{BitAlloc, BitAlloc256};
|
|
||||||
use core::ops::Range;
|
|
||||||
|
|
||||||
use crate::{HalError, HalResult};
|
|
||||||
|
|
||||||
pub type IrqHandler = Box<dyn Fn() + Send + Sync>;
|
|
||||||
|
|
||||||
const IRQ_COUNT: usize = 256;
|
|
||||||
|
|
||||||
pub struct IrqManager {
|
|
||||||
irq_range: Range<u32>,
|
|
||||||
table: [Option<IrqHandler>; IRQ_COUNT],
|
|
||||||
allocator: BitAlloc256,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IrqManager {
|
|
||||||
pub fn new(irq_min_id: u32, irq_max_id: u32) -> Self {
|
|
||||||
const EMPTY_HANDLER: Option<Box<dyn Fn() + Send + Sync>> = None;
|
|
||||||
let mut allocator = BitAlloc256::DEFAULT;
|
|
||||||
allocator.insert(irq_min_id as usize..irq_max_id as usize + 1);
|
|
||||||
Self {
|
|
||||||
irq_range: irq_min_id..irq_max_id + 1,
|
|
||||||
table: [EMPTY_HANDLER; IRQ_COUNT],
|
|
||||||
allocator,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc_block(&mut self, count: u32) -> HalResult<u32> {
|
|
||||||
debug_assert!(count.is_power_of_two());
|
|
||||||
let align_log2 = 31 - count.leading_zeros();
|
|
||||||
self.allocator
|
|
||||||
.alloc_contiguous(count as usize, align_log2 as usize)
|
|
||||||
.map(|start| start as u32)
|
|
||||||
.ok_or(HalError)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn free_block(&mut self, start: u32, count: u32) -> HalResult {
|
|
||||||
self.allocator
|
|
||||||
.insert(start as usize..(start + count) as usize);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a handler to IRQ table. Return the specified irq or an allocated irq on success
|
|
||||||
pub fn register_handler(&mut self, vector: u32, handler: IrqHandler) -> HalResult<u32> {
|
|
||||||
info!("IRQ add handler {:#x?}", vector);
|
|
||||||
let vector = if !self.irq_range.contains(&vector) {
|
|
||||||
// allocate a valid irq number
|
|
||||||
self.alloc_block(1)?
|
|
||||||
} else if self.allocator.test(vector as usize) {
|
|
||||||
self.allocator.remove(vector as usize..vector as usize + 1);
|
|
||||||
vector
|
|
||||||
} else {
|
|
||||||
return Err(HalError);
|
|
||||||
};
|
|
||||||
self.table[vector as usize] = Some(handler);
|
|
||||||
Ok(vector)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unregister_handler(&mut self, vector: u32) -> HalResult {
|
|
||||||
info!("IRQ remove handler {:#x?}", vector);
|
|
||||||
if self.allocator.test(vector as usize) {
|
|
||||||
Err(HalError)
|
|
||||||
} else {
|
|
||||||
self.free_block(vector, 1)?;
|
|
||||||
self.table[vector as usize] = None;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn overwrite_handler(&mut self, vector: u32, handler: IrqHandler) -> HalResult {
|
|
||||||
info!("IRQ overwrite handle {:#x?}", vector);
|
|
||||||
if self.allocator.test(vector as usize) {
|
|
||||||
Err(HalError)
|
|
||||||
} else {
|
|
||||||
self.table[vector as usize] = Some(handler);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle(&self, vector: u32) {
|
|
||||||
match &self.table[vector as usize] {
|
|
||||||
Some(f) => f(),
|
|
||||||
None => panic!("unhandled external IRQ number: {}", vector),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(not(feature = "libos"))] {
|
if #[cfg(not(feature = "libos"))] {
|
||||||
pub(crate) mod irq_manager;
|
|
||||||
pub(crate) mod page_table;
|
pub(crate) mod page_table;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ async fn new_thread(thread: CurrentThread) {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
match cx.trap_num {
|
match cx.trap_num {
|
||||||
0x100 => handle_syscall(&thread, &mut cx.general).await,
|
0x100 => handle_syscall(&thread, &mut cx.general).await,
|
||||||
0x20..=0x3f => {
|
0x20..=0xff => {
|
||||||
kernel_hal::interrupt::handle_irq(cx.trap_num as u32);
|
kernel_hal::interrupt::handle_irq(cx.trap_num as u32);
|
||||||
if cx.trap_num == 0x20 {
|
if cx.trap_num == 0x20 {
|
||||||
kernel_hal::thread::yield_now().await;
|
kernel_hal::thread::yield_now().await;
|
||||||
|
|
|
@ -216,7 +216,7 @@ async fn new_thread(thread: CurrentThread) {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
match trap_num {
|
match trap_num {
|
||||||
0x100 => handle_syscall(&thread).await,
|
0x100 => handle_syscall(&thread).await,
|
||||||
0x20..=0x3f => {
|
0x20..=0xff => {
|
||||||
kernel_hal::interrupt::handle_irq(trap_num as u32);
|
kernel_hal::interrupt::handle_irq(trap_num as u32);
|
||||||
if trap_num == 0x20 {
|
if trap_num == 0x20 {
|
||||||
EXCEPTIONS_TIMER.add(1);
|
EXCEPTIONS_TIMER.add(1);
|
||||||
|
|
Loading…
Reference in New Issue