Reuse x86::apic

This commit is contained in:
Yuke Peng 2023-03-08 00:09:34 -08:00 committed by Tate, Hongliang Tian
parent 691b8cd598
commit cd2d516be1
11 changed files with 216 additions and 420 deletions

View File

@ -8,6 +8,7 @@ edition = "2021"
[dependencies]
bitflags = "1.3"
x86_64 = "0.14.2"
x86 = "0.52.0"
spin = "0.9.4"
volatile = { version = "0.4.5", features = ["unstable"] }
buddy_system_allocator = "0.6"

View File

@ -10,5 +10,5 @@ pub use self::io_port::IoPort;
/// Call after the memory allocator init
pub(crate) fn init() {
framebuffer::init();
serial::register_serial_input_irq_handler(|trap| {});
serial::callback_init();
}

View File

@ -1,9 +1,8 @@
use alloc::{sync::Arc, vec::Vec};
use lazy_static::lazy_static;
use log::debug;
use spin::Mutex;
use spin::{Mutex, Once};
use crate::{cell::Cell, driver::pic, x86_64_util::*, IrqAllocateHandle, TrapFrame};
use crate::{driver::pic_allocate_irq, x86_64_util::*, IrqAllocateHandle, TrapFrame};
use core::fmt::{self, Write};
bitflags::bitflags! {
@ -20,15 +19,10 @@ const SERIAL_FIFO_CTRL: u16 = SERIAL_DATA + 2;
const SERIAL_LINE_CTRL: u16 = SERIAL_DATA + 3;
const SERIAL_MODEM_CTRL: u16 = SERIAL_DATA + 4;
const SERIAL_LINE_STS: u16 = SERIAL_DATA + 5;
lazy_static! {
static ref CONSOLE_IRQ_CALLBACK: Cell<IrqAllocateHandle> = {
let irq = Cell::new(pic::allocate_irq(4).unwrap());
irq.get().on_active(handle_serial_input);
irq
};
static ref SERIAL_INPUT_CALLBACKS: Mutex<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>>> =
Mutex::new(Vec::new());
}
static CONSOLE_IRQ_CALLBACK: Once<Mutex<IrqAllocateHandle>> = Once::new();
static SERIAL_INPUT_CALLBACKS: Mutex<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>>> =
Mutex::new(Vec::new());
/// Initializes the serial port.
pub(crate) fn init() {
@ -55,11 +49,21 @@ pub fn register_serial_input_callback(f: impl Fn(u8) + Send + Sync + 'static) {
SERIAL_INPUT_CALLBACKS.lock().push(Arc::new(f));
}
pub(crate) fn callback_init() {
let mut irq = pic_allocate_irq(4).unwrap();
irq.on_active(handle_serial_input);
CONSOLE_IRQ_CALLBACK.call_once(|| Mutex::new(irq));
}
pub(crate) fn register_serial_input_irq_handler<F>(callback: F)
where
F: Fn(&TrapFrame) + Sync + Send + 'static,
{
CONSOLE_IRQ_CALLBACK.get().on_active(callback);
CONSOLE_IRQ_CALLBACK
.get()
.unwrap()
.lock()
.on_active(callback);
}
fn handle_serial_input(trap_frame: &TrapFrame) {

View File

@ -1,211 +0,0 @@
use crate::{cell::Cell, x86_64_util};
use lazy_static::lazy_static;
use log::debug;
use volatile::{
access::{ReadOnly, ReadWrite, WriteOnly},
Volatile,
};
pub(crate) const IA32_APIC_BASE_MSR: u32 = 0x1B;
pub(crate) const IA32_APIC_BASE_MSR_BSP: u32 = 0x100; // Processor is a BSP
pub(crate) const IA32_APIC_BASE_MSR_ENABLE: u32 = 0x800;
const APIC_LVT_MASK_BITS: u32 = 1 << 16;
lazy_static! {
pub static ref APIC_INSTANCE: Cell<APIC> = Cell::new(APIC::new());
}
#[derive(Debug)]
pub struct APIC {
local_apic_id_register: Volatile<&'static mut u32, ReadWrite>,
local_apic_version_register: Volatile<&'static u32, ReadOnly>,
task_priority_register: Volatile<&'static mut u32, ReadWrite>,
arbitration_priority_register: Volatile<&'static u32, ReadOnly>,
processor_priority_register: Volatile<&'static u32, ReadOnly>,
pub eoi_register: Volatile<&'static mut u32, WriteOnly>,
remote_read_register: Volatile<&'static u32, ReadOnly>,
logical_destination_register: Volatile<&'static mut u32, ReadWrite>,
destination_format_register: Volatile<&'static mut u32, ReadWrite>,
spurious_interrupt_vector_register: Volatile<&'static mut u32, ReadWrite>,
/// total 256 bits, 32 bits per element
isr_per_32_bits: [Volatile<&'static u32, ReadOnly>; 8],
/// total 256 bits, 32 bits per element
tmr_per_32_bits: [Volatile<&'static u32, ReadOnly>; 8],
/// total 256 bits, 32 bits per element
irr_per_32_bits: [Volatile<&'static u32, ReadOnly>; 8],
pub error_status_register: Volatile<&'static u32, ReadOnly>,
lvt_cmci_register: Volatile<&'static mut u32, ReadWrite>,
icr_bits_31_0: Volatile<&'static mut u32, ReadWrite>,
icr_bits_63_32: Volatile<&'static mut u32, ReadWrite>,
pub lvt_timer_register: Volatile<&'static mut u32, ReadWrite>,
lvt_thermal_sensor_register: Volatile<&'static mut u32, ReadWrite>,
lvt_performance_monitoring_counters_register: Volatile<&'static mut u32, ReadWrite>,
lvt_lint0_register: Volatile<&'static mut u32, ReadWrite>,
lvt_lint1_register: Volatile<&'static mut u32, ReadWrite>,
lvt_error_register: Volatile<&'static mut u32, ReadWrite>,
pub initial_count_register: Volatile<&'static mut u32, ReadWrite>,
pub current_count_register: Volatile<&'static u32, ReadOnly>,
pub divide_configuration_register: Volatile<&'static mut u32, ReadWrite>,
}
impl APIC {
pub fn new() -> Self {
let base_address = get_apic_base_address();
let local_apic_id_register = Self::new_read_write_volatile(base_address + 0x0020);
let local_apic_version_register = Self::new_read_only_volatile(base_address + 0x0030);
let task_priority_register = Self::new_read_write_volatile(base_address + 0x0080);
let arbitration_priority_register = Self::new_read_only_volatile(base_address + 0x0090);
let processor_priority_register = Self::new_read_only_volatile(base_address + 0x00A0);
let eoi_register = Self::new_write_only_volatile(base_address + 0x00B0);
let remote_read_register = Self::new_read_only_volatile(base_address + 0x00C0);
let logical_destination_register = Self::new_read_write_volatile(base_address + 0x00D0);
let destination_format_register = Self::new_read_write_volatile(base_address + 0x00E0);
let spurious_interrupt_vector_register =
Self::new_read_write_volatile(base_address + 0x00F0);
let mut isr_per_32_bits: [Volatile<&'static u32, ReadOnly>; 8] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
for i in 0..8 {
isr_per_32_bits[i] = Self::new_read_only_volatile(base_address + 0x0100 + i * 0x0010);
}
let mut tmr_per_32_bits: [Volatile<&'static u32, ReadOnly>; 8] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
for i in 0..8 {
tmr_per_32_bits[i] = Self::new_read_only_volatile(base_address + 0x0180 + i * 0x0010);
}
let mut irr_per_32_bits: [Volatile<&'static u32, ReadOnly>; 8] =
unsafe { core::mem::MaybeUninit::uninit().assume_init() };
for i in 0..8 {
irr_per_32_bits[i] = Self::new_read_only_volatile(base_address + 0x0200 + i * 0x0010);
}
let error_status_register = Self::new_read_only_volatile(base_address + 0x0280);
let lvt_cmci_register = Self::new_read_write_volatile(base_address + 0x02F0);
let icr_bits_31_0 = Self::new_read_write_volatile(base_address + 0x0300);
let icr_bits_63_32 = Self::new_read_write_volatile(base_address + 0x0310);
let lvt_timer_register = Self::new_read_write_volatile(base_address + 0x0320);
let lvt_thermal_sensor_register = Self::new_read_write_volatile(base_address + 0x0330);
let lvt_performance_monitoring_counters_register =
Self::new_read_write_volatile(base_address + 0x0340);
let lvt_lint0_register = Self::new_read_write_volatile(base_address + 0x0350);
let lvt_lint1_register = Self::new_read_write_volatile(base_address + 0x0360);
let lvt_error_register = Self::new_read_write_volatile(base_address + 0x0370);
let initial_count_register = Self::new_read_write_volatile(base_address + 0x0380);
let current_count_register = Self::new_read_only_volatile(base_address + 0x0390);
let divide_configuration_register = Self::new_read_write_volatile(base_address + 0x03E0);
Self {
local_apic_id_register,
local_apic_version_register,
task_priority_register,
arbitration_priority_register,
processor_priority_register,
eoi_register,
remote_read_register,
logical_destination_register,
destination_format_register,
spurious_interrupt_vector_register,
isr_per_32_bits,
tmr_per_32_bits,
irr_per_32_bits,
error_status_register,
lvt_cmci_register,
icr_bits_31_0,
icr_bits_63_32,
lvt_timer_register,
lvt_thermal_sensor_register,
lvt_performance_monitoring_counters_register,
lvt_lint0_register,
lvt_lint1_register,
lvt_error_register,
initial_count_register,
current_count_register,
divide_configuration_register,
}
}
#[inline(always)]
fn new_read_only_volatile(pa: usize) -> Volatile<&'static u32, ReadOnly> {
Volatile::new_read_only(Self::convert_pa_to_u32_ref(pa))
}
#[inline(always)]
fn new_read_write_volatile(pa: usize) -> Volatile<&'static mut u32, ReadWrite> {
Volatile::new(Self::convert_pa_to_u32_ref(pa))
}
#[inline(always)]
fn new_write_only_volatile(pa: usize) -> Volatile<&'static mut u32, WriteOnly> {
Volatile::new_write_only(Self::convert_pa_to_u32_ref(pa))
}
#[inline(always)]
fn convert_pa_to_u32_ref(pa: usize) -> &'static mut u32 {
unsafe { &mut *(crate::mm::address::phys_to_virt(pa) as *mut usize as *mut u32) }
}
}
pub(crate) fn has_apic() -> bool {
let value = unsafe { x86_64_util::cpuid(1) };
value.edx & 0x100 != 0
}
pub(crate) fn init() {
super::pic::disable_temp();
let apic_lock = APIC_INSTANCE.get();
// enable apic
set_apic_base_address(get_apic_base_address());
let spurious = apic_lock.spurious_interrupt_vector_register.read();
apic_lock
.spurious_interrupt_vector_register
.write(spurious | (0x100));
let apic_id = apic_lock.local_apic_id_register.read() >> 24;
let apic_ver = apic_lock.local_apic_version_register.read();
debug!(
"APIC ID:{:x}, Version:{:x}, Max LVT:{:x}",
apic_id,
apic_ver & 0xff,
(apic_ver >> 16) & 0xff
);
debug!(
"LDR:{:x}, DFR:{:x}",
apic_lock.logical_destination_register.read(),
apic_lock.destination_format_register.read()
);
debug!("spurious:{:x}", spurious);
drop(apic_lock);
}
#[inline(always)]
pub fn ack() {
let lock = APIC_INSTANCE.get();
lock.eoi_register.write(0);
}
/// set APIC base address and enable it
fn set_apic_base_address(address: usize) {
x86_64_util::set_msr(
IA32_APIC_BASE_MSR,
address | IA32_APIC_BASE_MSR_ENABLE as usize,
)
}
/// get APIC base address
fn get_apic_base_address() -> usize {
x86_64_util::get_msr(IA32_APIC_BASE_MSR) & 0xf_ffff_f000
}

View File

@ -1,153 +1,74 @@
use acpi::PlatformInfo;
use log::debug;
use log::info;
use spin::{Mutex, Once};
use x86::apic::ioapic::IoApic;
use super::acpi::ACPI_TABLES;
use crate::cell::Cell;
use crate::mm::address::phys_to_virt;
use crate::util::recycle_allocator::RecycleAllocator;
use lazy_static::lazy_static;
lazy_static! {
pub static ref IO_APIC: Cell<IoApic> =
unsafe { Cell::new(core::mem::MaybeUninit::zeroed().assume_init()) };
}
const IOAPICID: u32 = 0x00;
const IOAPICVER: u32 = 0x01;
const IOAPICARB: u32 = 0x02;
const fn IoApicRedtbl(index: u8) -> u32 {
0x10 + 2 * index as u32
pub(crate) struct IoApicWrapper {
io_apic: IoApic,
}
#[derive(Debug)]
#[repr(C)]
struct IoApicRegister {
address: u32,
reserved: [u8; 0x10 - 0x04],
data: u32,
}
impl IoApicRegister {
pub fn read(self: &mut Self, reg: u32) -> u32 {
self.address = reg & 0xff;
self.data
impl IoApicWrapper {
fn new(io_apic: IoApic) -> Self {
Self { io_apic }
}
pub fn write(self: &mut Self, reg: u32, value: u32) {
self.address = reg & 0xff;
self.data = value;
pub(crate) fn disable_all(&mut self) {
self.io_apic.disable_all()
}
pub(crate) fn enable(&mut self, irq: u8, cpunum: u8) {
self.io_apic.enable(irq, cpunum);
}
pub(crate) fn id(&mut self) -> u8 {
self.io_apic.id()
}
pub(crate) fn version(&mut self) -> u8 {
self.io_apic.version()
}
pub(crate) fn supported_interrupts(&mut self) -> u8 {
self.io_apic.supported_interrupts()
}
}
#[derive(Debug)]
pub struct IoApicEntryHandle {
index: u8,
}
/// # Safety: The pointer inside the IoApic will not change
unsafe impl Send for IoApicWrapper {}
/// # Safety: The pointer inside the IoApic will not change
unsafe impl Sync for IoApicWrapper {}
impl IoApicEntryHandle {
pub fn read(&mut self) -> u64 {
let io_apic = IO_APIC.get();
io_apic.read_irq(self.index)
}
pub fn write(&mut self, value: u64) {
let io_apic = IO_APIC.get();
io_apic.write_irq(self.index, value);
}
pub fn get_index(&self) -> u8 {
self.index
}
}
impl Drop for IoApicEntryHandle {
fn drop(&mut self) {
let io_apic = IO_APIC.get();
// mask
io_apic.write_irq(self.index, 1 << 16);
io_apic.entry_allocator.dealloc(self.index as usize);
}
}
#[derive(Debug)]
pub struct IoApic {
id: u8,
version: u32,
max_redirection_entry: u32,
io_apic_register: &'static mut IoApicRegister,
entry_allocator: RecycleAllocator,
}
impl IoApic {
fn read_irq(&mut self, irq_index: u8) -> u64 {
let low = self.io_apic_register.read(IoApicRedtbl(irq_index)) as u64;
let high = self.io_apic_register.read(IoApicRedtbl(irq_index) + 1) as u64;
high << 32 | low
}
fn write_irq(&mut self, irq_index: u8, value: u64) {
let low = value as u32;
let high = (value >> 32) as u32;
self.io_apic_register.write(IoApicRedtbl(irq_index), low);
self.io_apic_register
.write(IoApicRedtbl(irq_index) + 1, high);
}
pub fn allocate_entry(&mut self) -> Option<IoApicEntryHandle> {
let id = self.entry_allocator.alloc();
if id == usize::MAX {
return None;
}
Some(IoApicEntryHandle { index: id as u8 })
}
}
pub(crate) static IO_APIC: Once<Mutex<IoApicWrapper>> = Once::new();
pub fn init() {
let c = ACPI_TABLES.lock();
let platform_info = PlatformInfo::new(&*c).unwrap();
let mut ioapic_address = 0;
match platform_info.interrupt_model {
let ioapic_address = match platform_info.interrupt_model {
acpi::InterruptModel::Unknown => panic!("not found APIC in ACPI Table"),
acpi::InterruptModel::Apic(apic) => {
for io_apic in apic.io_apics.iter() {
ioapic_address = io_apic.address;
}
apic.io_apics
.iter()
.next()
.expect("There must be at least one IO APIC")
.address
}
_ => todo!(),
}
if ioapic_address == 0 {
return;
}
let io_apic_register =
unsafe { &mut *(phys_to_virt(ioapic_address as usize) as *mut IoApicRegister) };
_ => {
panic!("Unknown interrupt model")
}
};
let mut io_apic =
unsafe { IoApic::new(crate::mm::address::phys_to_virt(ioapic_address as usize)) };
let id = (read_io_apic(io_apic_register, IOAPICID) & (0xF00_0000) >> 24) as u8;
let raw_version = read_io_apic(io_apic_register, IOAPICVER);
let version = raw_version & 0x1ff;
let max_redirection_entry = ((raw_version & (0xFF_0000)) >> 16) + 1;
debug!(
let id = io_apic.id();
let version = io_apic.version();
let max_redirection_entry = io_apic.supported_interrupts();
info!(
"IOAPIC id: {}, version:{}, max_redirection_entry:{}",
id, version, max_redirection_entry
);
let io_apic = IoApic {
id,
version,
max_redirection_entry,
io_apic_register,
entry_allocator: RecycleAllocator::with_start_max(0, max_redirection_entry as usize),
};
*IO_APIC.get() = io_apic;
}
fn read_io_apic(io_apic_register: &mut IoApicRegister, reg: u32) -> u32 {
io_apic_register.address = reg & 0xff;
io_apic_register.data
}
fn write_io_apic(io_apic_register: &mut IoApicRegister, reg: u32, value: u32) {
io_apic_register.address = reg & 0xff;
io_apic_register.data = value;
IO_APIC.call_once(|| Mutex::new(IoApicWrapper::new(io_apic)));
}

View File

@ -2,30 +2,31 @@
//! This module should inaccessible by other crate such as std, virtio etc.
//!
pub mod acpi;
pub mod apic;
pub mod ioapic;
pub mod pic;
pub mod rtc;
pub mod timer;
mod acpi;
mod ioapic;
mod pic;
pub(crate) mod rtc;
mod timer;
mod xapic;
pub use apic::ack;
pub(crate) use self::pic::ack as pic_ack;
pub(crate) use self::pic::allocate_irq as pic_allocate_irq;
pub(crate) use self::xapic::ack as xapic_ack;
use log::info;
pub use timer::TimerCallback;
pub(crate) use timer::{add_timeout_list, TICK};
pub(crate) use timer::{add_timeout_list, TimerCallback, TICK};
pub(crate) fn init() {
acpi::init();
timer::init();
if apic::has_apic() {
if xapic::has_apic() {
ioapic::init();
apic::init();
xapic::init();
} else {
info!("No apic exists, using pic instead");
unsafe {
pic::enable();
}
}
timer::init();
pic::init();
rtc::init();
}

View File

@ -2,17 +2,18 @@ use log::info;
use crate::{
config,
driver::{apic::APIC_INSTANCE, pic, timer},
driver::{pic, timer, xapic::XAPIC_INSTANCE},
x86_64_util, TrapFrame,
};
use x86::apic::xapic;
pub fn init() {
let apic_lock = APIC_INSTANCE.get();
let mut apic_lock = XAPIC_INSTANCE.get().unwrap().lock();
let handle = unsafe { crate::trap::IrqLine::acquire(timer::TIMER_IRQ_NUM) };
let a = handle.on_active(init_function);
// divide by 64
apic_lock.divide_configuration_register.write(0b1001);
apic_lock.initial_count_register.write(0xFFFF_FFFF);
apic_lock.write(xapic::XAPIC_TIMER_DIV_CONF, 0b1001);
apic_lock.write(xapic::XAPIC_TIMER_INIT_COUNT, 0xFFFF_FFFF);
// apic_lock.lvt_timer_register.write(timer::TIMER_IRQ_NUM as u32);
drop(apic_lock);
@ -39,8 +40,8 @@ pub fn init() {
if IS_FINISH || IN_TIME == 0 {
// drop the first entry, since it may not be the time we want
IN_TIME += 1;
let apic_lock = APIC_INSTANCE.get();
let remain_ticks = apic_lock.current_count_register.read();
let apic_lock = XAPIC_INSTANCE.get().unwrap().lock();
let remain_ticks = apic_lock.read(xapic::XAPIC_TIMER_CURRENT_COUNT);
FIRST_TIME_COUNT = 0xFFFF_FFFF - remain_ticks;
pic::ack();
return;
@ -48,16 +49,17 @@ pub fn init() {
}
pic::disable_temp();
// stop APIC Timer, get the number of tick we need
let apic_lock = APIC_INSTANCE.get();
let remain_ticks = apic_lock.current_count_register.read();
apic_lock.initial_count_register.write(0);
let mut apic_lock = XAPIC_INSTANCE.get().unwrap().lock();
let remain_ticks = apic_lock.read(xapic::XAPIC_TIMER_CURRENT_COUNT);
apic_lock.write(xapic::XAPIC_TIMER_INIT_COUNT, 0);
let ticks = unsafe { 0xFFFF_FFFF - remain_ticks - FIRST_TIME_COUNT };
// periodic mode, divide 64, freq: TIMER_FREQ Hz
apic_lock.initial_count_register.write(ticks as u32);
apic_lock
.lvt_timer_register
.write(timer::TIMER_IRQ_NUM as u32 | (1 << 17));
apic_lock.divide_configuration_register.write(0b1001);
apic_lock.write(xapic::XAPIC_TIMER_INIT_COUNT, ticks as u32);
apic_lock.write(
xapic::XAPIC_LVT_TIMER,
timer::TIMER_IRQ_NUM as u32 | (1 << 17),
);
apic_lock.write(xapic::XAPIC_TIMER_DIV_CONF, 0b1001);
info!(
"APIC Timer ticks count:{:x}, remain ticks: {:x},Timer Freq:{} Hz",

View File

@ -1,23 +1,13 @@
use acpi::{AcpiError, HpetInfo};
use alloc::vec::Vec;
use spin::Once;
use volatile::{
access::{ReadOnly, ReadWrite},
Volatile,
};
use crate::{
cell::Cell,
driver::{
acpi::ACPI_TABLES,
ioapic::{self, IoApicEntryHandle},
},
};
use lazy_static::lazy_static;
lazy_static! {
static ref HPET_INSTANCE: Cell<HPET> =
unsafe { Cell::new(core::mem::MaybeUninit::zeroed().assume_init()) };
}
use crate::driver::{acpi::ACPI_TABLES, ioapic};
static HPET_INSTANCE: Once<HPET> = Once::new();
const OFFSET_ID_REGISTER: usize = 0x000;
const OFFSET_CONFIGURATION_REGISTER: usize = 0x010;
@ -35,7 +25,6 @@ struct HPETTimerRegister {
}
struct HPET {
io_apic_entry: IoApicEntryHandle,
information_register: Volatile<&'static u32, ReadOnly>,
general_configuration_register: Volatile<&'static mut u32, ReadWrite>,
general_interrupt_status_register: Volatile<&'static mut u32, ReadWrite>,
@ -75,16 +64,17 @@ impl HPET {
comparators.push(comp);
}
let mut io_apic_entry = ioapic::IO_APIC.get().allocate_entry().unwrap();
let vector = super::TIMER_IRQ_NUM;
// 0 for now
let destination_apic_id: u8 = 0;
let write_value = (destination_apic_id as u64) << 56 | vector as u64;
io_apic_entry.write(write_value);
ioapic::IO_APIC
.get()
.unwrap()
.lock()
.enable(vector, destination_apic_id);
HPET {
io_apic_entry,
information_register,
general_configuration_register,
general_interrupt_status_register,
@ -121,6 +111,6 @@ pub fn init() -> Result<(), AcpiError> {
// config IO APIC entry
let hpet = HPET::new(hpet_info.base_address);
*HPET_INSTANCE.get() = hpet;
HPET_INSTANCE.call_once(|| hpet);
Ok(())
}

View File

@ -5,28 +5,26 @@ pub mod pit;
use core::any::Any;
use alloc::{boxed::Box, collections::BinaryHeap, sync::Arc, vec::Vec};
use lazy_static::lazy_static;
use spin::Mutex;
use spin::{Mutex, Once};
use crate::{cell::Cell, IrqAllocateHandle, TrapFrame};
use crate::{IrqAllocateHandle, TrapFrame};
pub(crate) const TIMER_IRQ_NUM: u8 = 32;
pub static mut TICK: u64 = 0;
lazy_static! {
static ref TIMER_IRQ: Mutex<IrqAllocateHandle> = Mutex::new(
crate::trap::allocate_target_irq(TIMER_IRQ_NUM).expect("Timer irq Allocate error")
);
}
static TIMER_IRQ: Once<IrqAllocateHandle> = Once::new();
pub fn init() {
if super::apic::has_apic() {
TIMEOUT_LIST.call_once(|| Mutex::new(BinaryHeap::new()));
if super::xapic::has_apic() {
apic::init();
} else {
pit::init();
}
TIMER_IRQ.lock().on_active(timer_callback);
let mut timer_irq =
crate::trap::allocate_target_irq(TIMER_IRQ_NUM).expect("Timer irq Allocate error");
timer_irq.on_active(timer_callback);
TIMER_IRQ.call_once(|| timer_irq);
}
fn timer_callback(trap_frame: &TrapFrame) {
@ -35,7 +33,7 @@ fn timer_callback(trap_frame: &TrapFrame) {
current_ms = TICK;
TICK += 1;
}
let timeout_list = TIMEOUT_LIST.get();
let mut timeout_list = TIMEOUT_LIST.get().unwrap().lock();
let mut callbacks: Vec<Arc<TimerCallback>> = Vec::new();
while let Some(t) = timeout_list.peek() {
if t.expire_ms <= current_ms && t.is_enable() {
@ -44,21 +42,20 @@ fn timer_callback(trap_frame: &TrapFrame) {
break;
}
}
drop(timeout_list);
for callback in callbacks {
callback.callback.call((&callback,));
}
// crate::interrupt_ack();
}
lazy_static! {
static ref TIMEOUT_LIST: Cell<BinaryHeap<Arc<TimerCallback>>> = Cell::new(BinaryHeap::new());
}
static TIMEOUT_LIST: Once<Mutex<BinaryHeap<Arc<TimerCallback>>>> = Once::new();
pub struct TimerCallback {
expire_ms: u64,
data: Arc<dyn Any + Send + Sync>,
callback: Box<dyn Fn(&TimerCallback) + Send + Sync>,
enable: Cell<bool>,
enable: Mutex<bool>,
}
impl TimerCallback {
@ -71,7 +68,7 @@ impl TimerCallback {
expire_ms: timeout_ms,
data,
callback,
enable: Cell::new(true),
enable: Mutex::new(true),
}
}
@ -81,16 +78,16 @@ impl TimerCallback {
/// disable this timeout
pub fn disable(&self) {
*self.enable.get() = false;
*self.enable.lock() = false;
}
/// enable this timeout
pub fn enable(&self) {
*self.enable.get() = true;
*self.enable.lock() = true;
}
pub fn is_enable(&self) -> bool {
*self.enable
*self.enable.lock()
}
}
@ -126,7 +123,7 @@ where
unsafe {
let timer_callback = TimerCallback::new(TICK + timeout, Arc::new(data), Box::new(callback));
let arc = Arc::new(timer_callback);
TIMEOUT_LIST.get().push(arc.clone());
TIMEOUT_LIST.get().unwrap().lock().push(arc.clone());
arc
}
}

View File

@ -0,0 +1,91 @@
use crate::{mm, x86_64_util};
use log::debug;
use spin::{Mutex, Once};
use x86::apic::xapic;
pub(crate) const IA32_APIC_BASE_MSR: u32 = 0x1B;
pub(crate) const IA32_APIC_BASE_MSR_BSP: u32 = 0x100; // Processor is a BSP
pub(crate) const IA32_APIC_BASE_MSR_ENABLE: u32 = 0x800;
const APIC_LVT_MASK_BITS: u32 = 1 << 16;
pub(crate) static XAPIC_INSTANCE: Once<Mutex<XAPIC>> = Once::new();
#[derive(Debug)]
pub struct XAPIC {
mmio_region: &'static mut [u32],
}
impl XAPIC {
pub fn new(address: usize) -> Self {
let region: &'static mut [u32] = unsafe { &mut *(address as *mut [u32; 256]) };
Self {
mmio_region: region,
}
}
/// Read a register from the MMIO region.
pub(crate) fn read(&self, offset: u32) -> u32 {
assert!(offset as usize % 4 == 0);
let index = offset as usize / 4;
unsafe { core::ptr::read_volatile(&self.mmio_region[index]) }
}
/// write a register in the MMIO region.
pub(crate) fn write(&mut self, offset: u32, val: u32) {
assert!(offset as usize % 4 == 0);
let index = offset as usize / 4;
unsafe { core::ptr::write_volatile(&mut self.mmio_region[index], val) }
}
}
pub(crate) fn has_apic() -> bool {
let value = unsafe { x86_64_util::cpuid(1) };
value.edx & 0x100 != 0
}
pub(crate) fn init() {
super::pic::disable_temp();
let mut apic = XAPIC::new(mm::address::phys_to_virt(get_apic_base_address()));
// enable apic
set_apic_base_address(get_apic_base_address());
let spurious = apic.read(xapic::XAPIC_SVR);
apic.write(xapic::XAPIC_SVR, spurious | (0x100));
let apic_id = apic.read(xapic::XAPIC_ID) >> 24;
let apic_ver = apic.read(xapic::XAPIC_VERSION);
debug!(
"APIC ID:{:x}, Version:{:x}, Max LVT:{:x}",
apic_id,
apic_ver & 0xff,
(apic_ver >> 16) & 0xff
);
debug!("spurious:{:x}", spurious);
XAPIC_INSTANCE.call_once(|| Mutex::new(apic));
}
#[inline(always)]
pub fn ack() {
XAPIC_INSTANCE
.get()
.unwrap()
.lock()
.write(xapic::XAPIC_EOI, 0);
}
/// set APIC base address and enable it
fn set_apic_base_address(address: usize) {
x86_64_util::set_msr(
IA32_APIC_BASE_MSR,
address | IA32_APIC_BASE_MSR_ENABLE as usize,
)
}
/// get APIC base address
fn get_apic_base_address() -> usize {
x86_64_util::get_msr(IA32_APIC_BASE_MSR) & 0xf_ffff_f000
}

View File

@ -45,8 +45,8 @@ pub(crate) extern "C" fn trap_handler(f: &mut TrapFrame) {
callback_function.call(f);
}
if f.id >= 0x20 {
crate::driver::apic::ack();
crate::driver::pic::ack();
crate::driver::xapic_ack();
crate::driver::pic_ack();
}
}