Reuse x86::apic
This commit is contained in:
parent
691b8cd598
commit
cd2d516be1
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue