use crate::lapic::lapic_msr::*;
use crate::lapic::{LocalApic, LocalApicMode};
use raw_cpuid::CpuId;
#[derive(Debug, Default)]
pub struct LocalApicBuilder {
timer_vector: Option<usize>,
error_vector: Option<usize>,
spurious_vector: Option<usize>,
timer_mode: Option<TimerMode>,
timer_divide: Option<TimerDivide>,
timer_initial: Option<u32>,
ipi_destination_mode: Option<IpiDestMode>,
xapic_base: Option<u64>,
}
impl LocalApicBuilder {
pub fn new() -> Self {
Default::default()
}
pub fn timer_vector(&mut self, index: usize) -> &mut Self {
self.timer_vector = Some(index);
self
}
pub fn error_vector(&mut self, index: usize) -> &mut Self {
self.error_vector = Some(index);
self
}
pub fn spurious_vector(&mut self, index: usize) -> &mut Self {
self.spurious_vector = Some(index);
self
}
pub fn timer_mode(&mut self, mode: TimerMode) -> &mut Self {
self.timer_mode = Some(mode);
self
}
pub fn timer_divide(&mut self, divide: TimerDivide) -> &mut Self {
self.timer_divide = Some(divide);
self
}
pub fn timer_initial(&mut self, initial: u32) -> &mut Self {
self.timer_initial = Some(initial);
self
}
pub fn ipi_destination_mode(&mut self, mode: IpiDestMode) -> &mut Self {
self.ipi_destination_mode = Some(mode);
self
}
pub fn set_xapic_base(&mut self, value: u64) -> &mut Self {
self.xapic_base = Some(value);
self
}
pub fn build(&mut self) -> Result<LocalApic, &'static str> {
let mode = if cpu_has_x2apic() {
LocalApicMode::X2Apic
} else {
if self.xapic_base.is_none() {
return Err("LocalApicBuilder: XApic base is required.");
}
LocalApicMode::XApic {
xapic_base: self.xapic_base.unwrap(),
}
};
if self.timer_vector.is_none()
|| self.error_vector.is_none()
|| self.spurious_vector.is_none()
{
return Err("LocalApicBuilder: required field(s) empty");
}
Ok(LocalApic {
timer_vector: self.timer_vector.unwrap(),
error_vector: self.error_vector.unwrap(),
spurious_vector: self.spurious_vector.unwrap(),
timer_mode: self.timer_mode.unwrap_or(TimerMode::Periodic),
timer_divide: self.timer_divide.unwrap_or(TimerDivide::Div1),
timer_initial: self.timer_initial.unwrap_or(10_000_000),
ipi_destination_mode: self
.ipi_destination_mode
.unwrap_or(IpiDestMode::Physical),
regs: LocalApicRegisters::new(mode),
mode,
})
}
}
fn cpu_has_x2apic() -> bool {
let cpuid = CpuId::new();
match cpuid.get_feature_info() {
Some(finfo) => finfo.has_x2apic(),
None => false,
}
}
pub unsafe fn xapic_base() -> u64 {
x86_64::registers::model_specific::Msr::new(IA32_APIC_BASE).read()
& 0xFFFFFF000 as u64
}