diff --git a/src/framework/jinux-frame/Cargo.toml b/src/framework/jinux-frame/Cargo.toml index c5ac8f425..7511fd4dd 100644 --- a/src/framework/jinux-frame/Cargo.toml +++ b/src/framework/jinux-frame/Cargo.toml @@ -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" diff --git a/src/framework/jinux-frame/src/device/mod.rs b/src/framework/jinux-frame/src/device/mod.rs index 6bb240b3b..dc1ccce45 100644 --- a/src/framework/jinux-frame/src/device/mod.rs +++ b/src/framework/jinux-frame/src/device/mod.rs @@ -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(); } diff --git a/src/framework/jinux-frame/src/device/serial.rs b/src/framework/jinux-frame/src/device/serial.rs index 41d7a26d5..446c5bb74 100644 --- a/src/framework/jinux-frame/src/device/serial.rs +++ b/src/framework/jinux-frame/src/device/serial.rs @@ -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 = { - let irq = Cell::new(pic::allocate_irq(4).unwrap()); - irq.get().on_active(handle_serial_input); - irq - }; - static ref SERIAL_INPUT_CALLBACKS: Mutex>> = - Mutex::new(Vec::new()); -} + +static CONSOLE_IRQ_CALLBACK: Once> = Once::new(); +static SERIAL_INPUT_CALLBACKS: Mutex>> = + 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(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) { diff --git a/src/framework/jinux-frame/src/driver/apic.rs b/src/framework/jinux-frame/src/driver/apic.rs deleted file mode 100644 index 0015a868f..000000000 --- a/src/framework/jinux-frame/src/driver/apic.rs +++ /dev/null @@ -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 = 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 -} diff --git a/src/framework/jinux-frame/src/driver/ioapic.rs b/src/framework/jinux-frame/src/driver/ioapic.rs index 7b8ce5820..7d80ce6cc 100644 --- a/src/framework/jinux-frame/src/driver/ioapic.rs +++ b/src/framework/jinux-frame/src/driver/ioapic.rs @@ -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 = - 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 { - let id = self.entry_allocator.alloc(); - if id == usize::MAX { - return None; - } - Some(IoApicEntryHandle { index: id as u8 }) - } -} +pub(crate) static IO_APIC: Once> = 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))); } diff --git a/src/framework/jinux-frame/src/driver/mod.rs b/src/framework/jinux-frame/src/driver/mod.rs index a8bafb16d..58099cdcf 100644 --- a/src/framework/jinux-frame/src/driver/mod.rs +++ b/src/framework/jinux-frame/src/driver/mod.rs @@ -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(); } diff --git a/src/framework/jinux-frame/src/driver/timer/apic.rs b/src/framework/jinux-frame/src/driver/timer/apic.rs index 714fe69fe..f97374269 100644 --- a/src/framework/jinux-frame/src/driver/timer/apic.rs +++ b/src/framework/jinux-frame/src/driver/timer/apic.rs @@ -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", diff --git a/src/framework/jinux-frame/src/driver/timer/hpet.rs b/src/framework/jinux-frame/src/driver/timer/hpet.rs index 6d6c2bee4..c535b95ca 100644 --- a/src/framework/jinux-frame/src/driver/timer/hpet.rs +++ b/src/framework/jinux-frame/src/driver/timer/hpet.rs @@ -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 = - unsafe { Cell::new(core::mem::MaybeUninit::zeroed().assume_init()) }; -} +use crate::driver::{acpi::ACPI_TABLES, ioapic}; +static HPET_INSTANCE: Once = 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(()) } diff --git a/src/framework/jinux-frame/src/driver/timer/mod.rs b/src/framework/jinux-frame/src/driver/timer/mod.rs index df7314ab4..5799c76f5 100644 --- a/src/framework/jinux-frame/src/driver/timer/mod.rs +++ b/src/framework/jinux-frame/src/driver/timer/mod.rs @@ -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 = Mutex::new( - crate::trap::allocate_target_irq(TIMER_IRQ_NUM).expect("Timer irq Allocate error") - ); -} +static TIMER_IRQ: Once = 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> = 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>> = Cell::new(BinaryHeap::new()); -} +static TIMEOUT_LIST: Once>>> = Once::new(); pub struct TimerCallback { expire_ms: u64, data: Arc, callback: Box, - enable: Cell, + enable: Mutex, } 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 } } diff --git a/src/framework/jinux-frame/src/driver/xapic.rs b/src/framework/jinux-frame/src/driver/xapic.rs new file mode 100644 index 000000000..407783769 --- /dev/null +++ b/src/framework/jinux-frame/src/driver/xapic.rs @@ -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> = 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 +} diff --git a/src/framework/jinux-frame/src/trap/handler.rs b/src/framework/jinux-frame/src/trap/handler.rs index 48d6bbbb5..2d5d0ca9e 100644 --- a/src/framework/jinux-frame/src/trap/handler.rs +++ b/src/framework/jinux-frame/src/trap/handler.rs @@ -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(); } }