1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
use x86_64::registers::model_specific::Msr;
#[cfg(target_arch = "x86_64")]
const APIC_FLAG: u64 = 0x0800;
const APIC_BASE_MSR: u32 = 0x1b;
pub fn is_x2apic() -> bool {
let info: u32;
unsafe {
asm!("cpuid" : "={ecx}" (info) : "{eax}" (1) : "memory");
}
info & (1 << 21) != 0
}
pub fn is_apic() -> bool {
let info: u32;
unsafe {
asm!("cpuid" : "={edx}" (info) : "{eax}" (1) : "memory");
}
info & (1 << 9) != 0
}
pub fn set_apic_base(v: u64) {
unsafe { Msr::new(APIC_BASE_MSR).write(v) }
}
#[repr(C)]
pub struct InterruptCommand {
low: u32,
_rsv: [u32; 3],
high: u32
}
#[repr(isize)]
pub enum ApicRegister {
ApicId=8,
ApicVer=12,
TaskPriority=32,
ArbitrationPriority=36,
ProcessorPriority=40,
EndOfInterrupt=44,
LogicalDst=52,
DstFmt=56,
SpuriousInterruptVec=60,
InService=64,
TriggerMode=96,
InterruptRequest=128,
ErrorStatus=160,
InterruptCommand=192,
InterruptCommandHigh=196,
LvtTimer=200,
LvtThermalSensor=204,
LvtPerformanceMonitor=208,
LvtLint1=212,
LvtError=220,
TimerInitialCount=224,
TimerCurrentCount=228,
TimerDivideConfig=248,
ExtApicFeature=256,
ExtApicControl=260,
SpecificEndOfInterrupt=264,
InterruptEnable=288,
ExtInterruptLocalVectorTable=320,
}
#[repr(C)]
pub struct ApicRegisters {
regs32: *mut [u32; 1024],
}
impl ApicRegisters {
fn from_base_apic(base_apic: u64) -> Self {
Self { regs32:
((base_apic >> 12) & 0xfffffffff) as *mut [u32; 1024]
}
}
fn ptr(&self) -> *const u32 { self.regs32 as *const u32 }
fn ptr_mut(&mut self) -> *mut u32 { self.regs32 as *mut u32 }
pub fn get(&self, register: ApicRegister) -> u32 {
unsafe { self.ptr().offset(register as isize).read_volatile() }
}
pub fn set(&mut self, register: ApicRegister, val: u32) {
unsafe { self.ptr_mut().offset(register as isize).write_volatile(val) }
}
pub fn set_interrupt_command(&mut self, dst: u8, v: u8) {
let (dst, v): (u32, u32) = (dst.into(), v.into());
self.set(ApicRegister::InterruptCommandHigh, dst << 24);
self.set(ApicRegister::InterruptCommand, v)
}
}
pub struct Apic {
base_apic: u64,
regs: ApicRegisters,
}
impl Apic {
pub fn new() -> Option<Self> {
use core::fmt::Write;
let mut stdout = crate::io::vga_text::OStream::new();
stdout.clear();
if !is_apic() { return None; }
let mut base_apic = unsafe { Msr::new(APIC_BASE_MSR).read() };
let mut regs = ApicRegisters::from_base_apic(base_apic);
let spurious = regs.get(ApicRegister::SpuriousInterruptVec) | 0x1ff;
unsafe { Msr::new(APIC_BASE_MSR).write(base_apic | APIC_FLAG) };
regs.set(ApicRegister::SpuriousInterruptVec, spurious);
Some(Self {
base_apic, regs
})
}
}
|