LoGin b5b571e026
修复内核的clippy检查报错 (#637)
修复内核的clippy检查报错
---------

Co-authored-by: Samuel Dai <947309196@qq.com>
Co-authored-by: Donkey Kane <109840258+xiaolin2004@users.noreply.github.com>
Co-authored-by: themildwind <107623059+themildwind@users.noreply.github.com>
Co-authored-by: GnoCiYeH <heyicong@dragonos.org>
Co-authored-by: MemoryShore <105195940+MemoryShore@users.noreply.github.com>
Co-authored-by: 曾俊 <110876916+ZZJJWarth@users.noreply.github.com>
Co-authored-by: sun5etop <146408999+sun5etop@users.noreply.github.com>
Co-authored-by: hmt <114841534+1037827920@users.noreply.github.com>
Co-authored-by: laokengwt <143977175+laokengwt@users.noreply.github.com>
Co-authored-by: TTaq <103996388+TTaq@users.noreply.github.com>
Co-authored-by: Jomo <2512364506@qq.com>
Co-authored-by: Samuel Dai <samuka007@qq.com>
Co-authored-by: sspphh <112558065+sspphh@users.noreply.github.com>
2024-03-22 23:26:39 +08:00

616 lines
18 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use core::sync::atomic::Ordering;
use atomic_enum::atomic_enum;
use system_error::SystemError;
use x86::{apic::Icr, msr::IA32_APIC_BASE};
use crate::{
arch::{
driver::apic::{hw_irq::ApicId, x2apic::X2Apic, xapic::XApic},
io::PortIOArch,
CurrentPortIOArch,
},
kdebug, kinfo,
mm::PhysAddr,
smp::core::smp_get_processor_id,
};
use self::{
apic_timer::LocalApicTimerMode,
xapic::{current_xapic_instance, XApicOffset},
};
pub mod apic_timer;
mod c_adapter;
pub mod hw_irq;
pub mod ioapic;
pub mod lapic_vector;
pub mod x2apic;
pub mod xapic;
/// 当前启用的APIC类型
#[atomic_enum]
#[derive(PartialEq, Eq)]
pub enum LocalApicEnableType {
XApic,
X2Apic,
}
static LOCAL_APIC_ENABLE_TYPE: AtomicLocalApicEnableType =
AtomicLocalApicEnableType::new(LocalApicEnableType::XApic);
pub trait LocalAPIC {
/// @brief 判断当前处理器是否支持这个类型的apic
///
/// @return true 当前处理器支持这个类型的apic
/// @return false 当前处理器不支持这个类型的apic
fn support() -> bool;
/// @brief 为当前处理器初始化local apic
///
/// @return true 初始化成功
/// @return false 初始化失败
fn init_current_cpu(&mut self) -> bool;
/// @brief 发送EOI信号End of interrupt
fn send_eoi(&self);
/// @brief 获取APIC版本号
fn version(&self) -> u8;
/// @brief 判断当前处理器是否支持EOI广播抑制
fn support_eoi_broadcast_suppression(&self) -> bool;
/// 获取最多支持的LVT寄存器数量
fn max_lvt_entry(&self) -> u8;
/// @brief 获取当前处理器的APIC ID
fn id(&self) -> ApicId;
/// @brief 设置LVT寄存器
///
/// @param register 寄存器
/// @param lvt 要被设置成的值
fn set_lvt(&mut self, lvt: LVT);
/// 读取LVT寄存器
fn read_lvt(&self, reg: LVTRegister) -> LVT;
fn mask_all_lvt(&mut self);
/// 写入ICR寄存器
fn write_icr(&self, icr: Icr);
}
/// @brief 所有LVT寄存器的枚举类型
#[allow(dead_code)]
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum LVTRegister {
/// CMCI寄存器
///
/// 如果支持CMCI功能那么当修正的机器错误超过阈值时Local APIC通过CMCI寄存器的配置
/// 向处理器核心投递中断消息
CMCI = 0x82f,
/// 定时器寄存器
///
/// 当APIC定时器产生中断信号时Local APIC通过定时器寄存器的设置向处理器投递中断消息
Timer = 0x832,
/// 温度传感器寄存器
///
/// 当处理器内部的温度传感器产生中断请求信号时Local APIC会通过温度传感器寄存器的设置
/// 向处理器投递中断消息。
Thermal = 0x833,
/// 性能监控计数器寄存器
///
/// 当性能检测计数器寄存器溢出产生中断请求时Local APIC将会根据这个寄存器的配置
/// 向处理器投递中断消息
PerformanceMonitor = 0x834,
/// 当处理器的LINT0引脚接收到中断请求信号时Local APIC会根据这个寄存器的配置
/// 向处理器投递中断消息
LINT0 = 0x835,
/// 当处理器的LINT0引脚接收到中断请求信号时Local APIC会根据这个寄存器的配置
/// 向处理器投递中断消息
LINT1 = 0x836,
/// 错误寄存器
///
/// 当APIC检测到内部错误而产生中断请求信号时它将会通过错误寄存器的设置向处理器投递中断消息
ErrorReg = 0x837,
}
impl From<LVTRegister> for u32 {
fn from(val: LVTRegister) -> Self {
val as u32
}
}
#[derive(Debug)]
pub struct LVT {
register: LVTRegister,
data: u32,
}
impl LVT {
/// 当第16位为1时表示屏蔽中断
pub const MASKED: u32 = 1 << 16;
pub fn new(register: LVTRegister, data: u32) -> Option<Self> {
// vector: u8, mode: DeliveryMode, status: DeliveryStatus
let mut result = Self { register, data: 0 };
result.set_vector((data & 0xFF) as u8);
match result.register {
LVTRegister::Timer | LVTRegister::ErrorReg => {}
_ => {
result
.set_delivery_mode(DeliveryMode::try_from(((data >> 8) & 0b111) as u8).ok()?)
.ok()?;
}
}
if let LVTRegister::LINT0 | LVTRegister::LINT1 = result.register {
result.set_interrupt_input_pin_polarity((data & (1 << 13)) == 0);
if data & (1 << 15) != 0 {
result.set_trigger_mode(TriggerMode::Level).ok()?;
} else {
result.set_trigger_mode(TriggerMode::Edge).ok()?;
}
}
result.set_mask((data & (1 << 16)) != 0);
if let LVTRegister::Timer = result.register {
result
.set_timer_mode(LocalApicTimerMode::try_from(((data >> 17) & 0b11) as u8).ok()?)
.ok()?;
}
return Some(result);
}
/// 获取LVT寄存器的原始值
#[allow(dead_code)]
pub fn data(&self) -> u32 {
return self.data;
}
pub fn register(&self) -> LVTRegister {
return self.register;
}
pub fn set_vector(&mut self, vector: u8) {
self.data &= !((1 << 8) - 1);
self.data |= vector as u32;
}
/// 获取中断向量号
#[allow(dead_code)]
pub fn vector(&self) -> u8 {
return (self.data & 0xFF) as u8;
}
/// 设置中断投递模式
///
/// Timer、ErrorReg寄存器不支持这个功能
///
/// ## 参数
///
/// - `mode`:投递模式
pub fn set_delivery_mode(&mut self, mode: DeliveryMode) -> Result<(), SystemError> {
match self.register {
LVTRegister::Timer | LVTRegister::ErrorReg => {
return Err(SystemError::EINVAL);
}
_ => {}
}
self.data &= 0xFFFF_F8FF;
self.data |= ((mode as u32) & 0x7) << 8;
return Ok(());
}
/// 获取中断投递模式
/// Timer、ErrorReg寄存器不支持这个功能
#[allow(dead_code)]
pub fn delivery_mode(&self) -> Option<DeliveryMode> {
if let LVTRegister::Timer | LVTRegister::ErrorReg = self.register {
return None;
}
return DeliveryMode::try_from(((self.data >> 8) & 0b111) as u8).ok();
}
/// Get the delivery status of the interrupt
#[allow(dead_code)]
pub fn delivery_status(&self) -> DeliveryStatus {
return DeliveryStatus::from(self.data);
}
/// 设置中断输入引脚的极性
///
/// ## 参数
///
/// - `high`true表示高电平有效false表示低电平有效
pub fn set_interrupt_input_pin_polarity(&mut self, high: bool) {
self.data &= 0xFFFF_DFFF;
// 0表示高电平有效1表示低电平有效
if !high {
self.data |= 1 << 13;
}
}
/// 获取中断输入引脚的极性
///
/// true表示高电平有效false表示低电平有效
#[allow(dead_code)]
pub fn interrupt_input_pin_polarity(&self) -> bool {
return (self.data & (1 << 13)) == 0;
}
/// 设置中断输入引脚的触发模式
///
/// 只有LINT0和LINT1寄存器支持这个功能
///
/// ## 参数
///
/// - `trigger_mode`:触发模式
pub fn set_trigger_mode(&mut self, trigger_mode: TriggerMode) -> Result<(), SystemError> {
match self.register {
LVTRegister::LINT0 | LVTRegister::LINT1 => {
self.data &= 0xFFFF_7FFF;
if trigger_mode == TriggerMode::Level {
self.data |= 1 << 15;
}
return Ok(());
}
_ => {
return Err(SystemError::EINVAL);
}
}
}
/// 获取中断输入引脚的触发模式
///
/// 只有LINT0和LINT1寄存器支持这个功能
#[allow(dead_code)]
pub fn trigger_mode(&self) -> Option<TriggerMode> {
match self.register {
LVTRegister::LINT0 | LVTRegister::LINT1 => {
if self.data & (1 << 15) != 0 {
return Some(TriggerMode::Level);
} else {
return Some(TriggerMode::Edge);
}
}
_ => {
return None;
}
}
}
/// 设置是否屏蔽中断
///
/// ## 参数
///
/// - `mask`true表示屏蔽中断false表示不屏蔽中断
pub fn set_mask(&mut self, mask: bool) {
self.data &= 0xFFFE_FFFF;
if mask {
self.data |= 1 << 16;
}
}
/// Check if the interrupt is masked
///
/// true表示屏蔽中断false表示不屏蔽中断
#[allow(dead_code)]
pub fn mask(&self) -> bool {
return (self.data & (1 << 16)) != 0;
}
/// 设置定时器模式
pub fn set_timer_mode(&mut self, mode: LocalApicTimerMode) -> Result<(), SystemError> {
match self.register {
LVTRegister::Timer => {
self.data &= 0xFFF9_FFFF;
match mode {
LocalApicTimerMode::Oneshot => {
self.data |= 0b00 << 17;
}
LocalApicTimerMode::Periodic => {
self.data |= 0b01 << 17;
}
LocalApicTimerMode::Deadline => {
self.data |= 0b10 << 17;
}
}
return Ok(());
}
_ => {
return Err(SystemError::EINVAL);
}
}
}
/// 获取定时器模式
#[allow(dead_code)]
pub fn timer_mode(&self) -> Option<LocalApicTimerMode> {
if let LVTRegister::Timer = self.register {
let mode = (self.data >> 17) & 0b11;
match mode {
0b00 => {
return Some(LocalApicTimerMode::Oneshot);
}
0b01 => {
return Some(LocalApicTimerMode::Periodic);
}
0b10 => {
return Some(LocalApicTimerMode::Deadline);
}
_ => {
return None;
}
}
}
return None;
}
}
/// @brief
#[allow(dead_code)]
#[derive(Debug, PartialEq)]
pub enum DeliveryMode {
/// 由LVT寄存器的向量号区域指定中断向量号
Fixed = 0b000,
/// 通过处理器的SMI信号线向处理器投递SMI中断请求。
/// 由于兼容性的原因使用此投递模式时LVT的中断向量号区域必须设置为0。
SMI = 0b010,
/// 向处理器投递不可屏蔽中断,并忽略向量号区域
NMI = 0b100,
/// 向处理器投递INIT中断请求处理器会执行初始化的过程。
/// 由于兼容性的原因使用此投递模式时LVT的中断向量号区域必须设置为0。
/// CMCI、温度传感器、性能监控计数器等寄存器均不支持INIT投递模式
INIT = 0b101,
/// 向目标处理器投递Start-Up IPI。
///
/// 这个向量通常由多核引导模块调用请参阅Intel开发手册Volume3 Section 8.4,
/// Multiple-Processor (MP) Initialization
/// 如果源APIC无法投递这个IPI它不会自动重发。如果Start-Up IPI未成功投递
/// 则交由软件决定是否在必要时重新投递SIPI
StartUp = 0b110,
/// ExtINT模式可以将类8259A中断控制器产生的中断请求投递到处理器并接收类
/// 8259A中断控制器提供的中断向量号。
/// CMCI、温度传感器、性能监控计数器等寄存器均不支持ExtINT投递模式
ExtINT = 0b111,
}
impl TryFrom<u8> for DeliveryMode {
type Error = SystemError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0b000 => {
return Ok(DeliveryMode::Fixed);
}
0b010 => {
return Ok(DeliveryMode::SMI);
}
0b100 => {
return Ok(DeliveryMode::NMI);
}
0b101 => {
return Ok(DeliveryMode::INIT);
}
0b110 => {
return Ok(DeliveryMode::StartUp);
}
0b111 => {
return Ok(DeliveryMode::ExtINT);
}
_ => {
return Err(SystemError::EINVAL);
}
}
}
}
/// @brief 投递状态
#[derive(Debug)]
#[allow(dead_code)]
pub enum DeliveryStatus {
/// 空闲态。
/// 此状态表明,当前中断源未产生中断,或者产生的中断已经投递到处理器,并被处理器处理。
Idle = 0,
/// 发送挂起状态。
/// 此状态表明,中断源产生的请求已经投递至处理器,但尚未被处理器处理。
SendPending = 1,
}
impl DeliveryStatus {
pub fn from(data: u32) -> Self {
if data & (1 << 12) == 0 {
return DeliveryStatus::Idle;
} else {
return DeliveryStatus::SendPending;
}
}
}
/// IPI Trigger Mode
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum TriggerMode {
Edge = 0,
Level = 1,
}
#[derive(Debug)]
pub struct CurrentApic;
impl CurrentApic {
/// x2apic是否启用
pub fn x2apic_enabled(&self) -> bool {
return LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic;
}
pub(self) unsafe fn write_xapic_register(&self, reg: XApicOffset, value: u32) {
if let Some(xapic) = current_xapic_instance().borrow_mut().as_mut() {
xapic.write(reg, value);
}
}
/// 屏蔽类8259A芯片
unsafe fn mask8259a(&self) {
CurrentPortIOArch::out8(0x21, 0xff);
CurrentPortIOArch::out8(0xa1, 0xff);
// 写入8259A pic的EOI位
CurrentPortIOArch::out8(0x20, 0x20);
CurrentPortIOArch::out8(0xa0, 0x20);
kdebug!("8259A Masked.");
// enable IMCR
CurrentPortIOArch::out8(0x22, 0x70);
CurrentPortIOArch::out8(0x23, 0x01);
}
}
impl LocalAPIC for CurrentApic {
fn support() -> bool {
true
}
fn init_current_cpu(&mut self) -> bool {
let cpu_id = smp_get_processor_id();
if cpu_id.data() == 0 {
unsafe {
self.mask8259a();
}
}
kinfo!("Initializing apic for cpu {:?}", cpu_id);
if X2Apic::support() && X2Apic.init_current_cpu() {
if cpu_id.data() == 0 {
LOCAL_APIC_ENABLE_TYPE.store(LocalApicEnableType::X2Apic, Ordering::SeqCst);
}
kinfo!("x2APIC initialized for cpu {:?}", cpu_id);
} else {
kinfo!("x2APIC not supported or failed to initialize, fallback to xAPIC.");
if cpu_id.data() == 0 {
LOCAL_APIC_ENABLE_TYPE.store(LocalApicEnableType::XApic, Ordering::SeqCst);
}
let apic_base =
PhysAddr::new(unsafe { x86::msr::rdmsr(IA32_APIC_BASE) as usize & 0xFFFF_0000 });
let xapic_instance = unsafe { XApic::new(apic_base) };
let mut cur = current_xapic_instance().borrow_mut();
if cur.is_none() {
*cur = Some(xapic_instance);
} else {
panic!("xapic instance already initialized.");
}
if let Some(xapic) = cur.as_mut() {
xapic.init_current_cpu();
}
kinfo!("xAPIC initialized for cpu {:?}", cpu_id);
}
kinfo!("Apic initialized.");
return true;
}
fn send_eoi(&self) {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
X2Apic.send_eoi();
} else if let Some(xapic) = current_xapic_instance().borrow().as_ref() {
xapic.send_eoi();
}
}
fn version(&self) -> u8 {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
return X2Apic.version();
} else {
return current_xapic_instance()
.borrow()
.as_ref()
.map(|xapic| xapic.version())
.unwrap_or(0);
}
}
fn support_eoi_broadcast_suppression(&self) -> bool {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
return X2Apic.support_eoi_broadcast_suppression();
} else {
return current_xapic_instance()
.borrow()
.as_ref()
.map(|xapic| xapic.support_eoi_broadcast_suppression())
.unwrap_or(false);
}
}
fn max_lvt_entry(&self) -> u8 {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
return X2Apic.max_lvt_entry();
} else {
return current_xapic_instance()
.borrow()
.as_ref()
.map(|xapic| xapic.max_lvt_entry())
.unwrap_or(0);
}
}
fn id(&self) -> ApicId {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
return X2Apic.id();
} else {
return current_xapic_instance()
.borrow()
.as_ref()
.map(|xapic| xapic.id())
.unwrap_or(ApicId::new(0));
}
}
fn set_lvt(&mut self, lvt: LVT) {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
X2Apic.set_lvt(lvt);
} else if let Some(xapic) = current_xapic_instance().borrow_mut().as_mut() {
xapic.set_lvt(lvt);
}
}
fn read_lvt(&self, reg: LVTRegister) -> LVT {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
return X2Apic.read_lvt(reg);
} else {
return current_xapic_instance()
.borrow()
.as_ref()
.map(|xapic| xapic.read_lvt(reg))
.expect("xapic instance not initialized.");
}
}
fn mask_all_lvt(&mut self) {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
X2Apic.mask_all_lvt();
} else if let Some(xapic) = current_xapic_instance().borrow_mut().as_mut() {
xapic.mask_all_lvt();
}
}
fn write_icr(&self, icr: Icr) {
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
X2Apic.write_icr(icr);
} else if let Some(xapic) = current_xapic_instance().borrow().as_ref() {
xapic.write_icr(icr);
}
}
}