summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornatrixaeria <upezu@student.kit.edu>2019-11-15 20:01:26 +0100
committernatrixaeria <upezu@student.kit.edu>2019-11-15 20:01:26 +0100
commit57850278fd6540dbf485db38d6819cbf40e0adf0 (patch)
treea1a57019e739333557eea469ac57c75b85990673
parent307571308b115eb737281711c780fa4cd1ed837f (diff)
Add apic module
-rw-r--r--kernel/.cargo/config2
-rwxr-xr-xkernel/run2
-rw-r--r--kernel/src/interrupts/apic.rs121
-rw-r--r--kernel/src/interrupts/mod.rs1
-rw-r--r--kernel/src/lib.rs1
-rw-r--r--kernel/src/main.rs4
6 files changed, 129 insertions, 2 deletions
diff --git a/kernel/.cargo/config b/kernel/.cargo/config
index 4a80025..b74f97c 100644
--- a/kernel/.cargo/config
+++ b/kernel/.cargo/config
@@ -3,4 +3,4 @@ target = "x86_64-uff.json"
rustflags = ["-Clink-arg=-r","-Clink-dead-code"]
[target.'cfg(target_os = "none")']
-runner = "./run test -serial -test"
+runner = "./run test -test"
diff --git a/kernel/run b/kernel/run
index 8c52bd9..d7d6e85 100755
--- a/kernel/run
+++ b/kernel/run
@@ -90,7 +90,7 @@ build() {
run() {
case "$target" in
"x86_64")
- qemu="qemu-system-x86_64 -cdrom $iso_path/$name.iso"
+ qemu="qemu-system-x86_64 -cdrom $iso_path/$name.iso -cpu kvm64,+apic"
if $test_mode; then
qemu="$qemu -device isa-debug-exit,iobase=0xf4,iosize=0x04 -serial stdio -no-reboot "
if $serial_mode; then
diff --git a/kernel/src/interrupts/apic.rs b/kernel/src/interrupts/apic.rs
new file mode 100644
index 0000000..519caf2
--- /dev/null
+++ b/kernel/src/interrupts/apic.rs
@@ -0,0 +1,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
+ })
+ }
+}
diff --git a/kernel/src/interrupts/mod.rs b/kernel/src/interrupts/mod.rs
index 4ff3c4d..9753b6b 100644
--- a/kernel/src/interrupts/mod.rs
+++ b/kernel/src/interrupts/mod.rs
@@ -1,3 +1,4 @@
+pub mod apic;
pub mod exceptions;
pub mod gdt;
pub mod idt;
diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs
index 8ab660d..adf14b4 100644
--- a/kernel/src/lib.rs
+++ b/kernel/src/lib.rs
@@ -3,6 +3,7 @@
#![feature(custom_test_frameworks)]
#![feature(abi_x86_interrupt)]
#![feature(panic_info_message)]
+#![feature(asm)]
#![test_runner(crate::testing::serial_test_runner)]
#![reexport_test_harness_main = "test_main"]
#![no_std]
diff --git a/kernel/src/main.rs b/kernel/src/main.rs
index bb1dcec..1613292 100644
--- a/kernel/src/main.rs
+++ b/kernel/src/main.rs
@@ -3,6 +3,7 @@
#![feature(custom_test_frameworks)]
#![feature(abi_x86_interrupt)]
#![feature(panic_info_message)]
+#![feature(asm)]
#![test_runner(crate::testing::test_runner)]
#![no_std]
@@ -18,6 +19,9 @@ pub use io::{qemu, serial, vga_text};
#[no_mangle]
extern "C" fn _start() -> ! {
kernel::init();
+
+ let apic = interrupts::apic::Apic::new();
+
if cfg!(test) {
qemu::exit_qemu(qemu::QemuExitCode::Success);
}