-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3a926e9
commit 2f928d7
Showing
13 changed files
with
635 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[package] | ||
name = "ysos_kernel" | ||
version = "0.2.0" | ||
edition = "2021" | ||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
boot = { package = "ysos_boot", path = "../boot", default-features = false } | ||
lazy_static = { version = "1.4", features = ["spin_no_std"] } | ||
paste = "1.0" | ||
spin = "0.9" | ||
x86 = "0.52" | ||
x86_64 = "0.14" | ||
log = "0.4" | ||
bitflags = "2.3" | ||
libm = "0.2" | ||
linked_list_allocator = "0.10" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/// The I/O APIC manages hardware interrupts for an SMP system. | ||
/// | ||
/// [Intel Doc](http://www.intel.com/design/chipsets/datashts/29056601.pdf) | ||
/// Default physical address of IO APIC | ||
pub const IOAPIC_ADDR: u64 = 0xFEC00000; | ||
|
||
bitflags! { | ||
/// The redirection table starts at REG_TABLE and uses | ||
/// two registers to configure each interrupt. | ||
/// The first (low) register in a pair contains configuration bits. | ||
/// The second (high) register contains a bitmask telling which | ||
/// CPUs can serve that interrupt. | ||
struct RedirectionEntry: u32 { | ||
/// Interrupt disabled | ||
const DISABLED = 0x00010000; | ||
/// Level-triggered (vs edge-) | ||
const LEVEL = 0x00008000; | ||
/// Active low (vs high) | ||
const ACTIVELOW = 0x00002000; | ||
/// Destination is CPU id (vs APIC ID) | ||
const LOGICAL = 0x00000800; | ||
/// None | ||
const NONE = 0x00000000; | ||
} | ||
} | ||
|
||
|
||
pub struct IoApic { | ||
reg: *mut u32, | ||
data: *mut u32, | ||
} | ||
|
||
impl IoApic { | ||
pub unsafe fn new(addr: u64) -> Self { | ||
IoApic { | ||
reg: addr as *mut u32, | ||
data: (addr + 0x10) as *mut u32, | ||
} | ||
} | ||
|
||
pub fn disable_all(&mut self) { | ||
// Mark all interrupts edge-triggered, active high, disabled, | ||
// and not routed to any CPUs. | ||
for i in 0..=self.maxintr() { | ||
self.write_irq(i, RedirectionEntry::DISABLED, 0); | ||
} | ||
} | ||
|
||
unsafe fn read(&mut self, reg: u8) -> u32 { | ||
self.reg.write_volatile(reg as u32); | ||
self.data.read_volatile() | ||
} | ||
|
||
unsafe fn write(&mut self, reg: u8, data: u32) { | ||
self.reg.write_volatile(reg as u32); | ||
self.data.write_volatile(data); | ||
} | ||
|
||
fn write_irq(&mut self, irq: u8, flags: RedirectionEntry, dest: u8) { | ||
unsafe { | ||
self.write(0x10 + 2 * irq, (32 + irq) as u32 | flags.bits()); | ||
self.write(0x10 + 2 * irq + 1, (dest as u32) << 24); | ||
} | ||
} | ||
|
||
pub fn enable(&mut self, irq: u8, cpunum: u8) { | ||
// Mark interrupt edge-triggered, active high, | ||
// enabled, and routed to the given cpunum, | ||
// which happens to be that cpu's APIC ID. | ||
self.write_irq(irq, RedirectionEntry::NONE, cpunum); | ||
trace!("Enable IOApic: IRQ={}, CPU={}", irq, cpunum); | ||
} | ||
|
||
pub fn disable(&mut self, irq: u8) { | ||
self.write_irq(irq, RedirectionEntry::DISABLED, 0); | ||
} | ||
|
||
pub fn id(&mut self) -> u8 { | ||
unsafe { self.read(0x00).get_bits(24..28) as u8 } | ||
} | ||
|
||
pub fn version(&mut self) -> u8 { | ||
unsafe { self.read(0x01).get_bits(0..8) as u8 } | ||
} | ||
|
||
pub fn maxintr(&mut self) -> u8 { | ||
unsafe { self.read(0x01).get_bits(16..24) as u8 } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
//! APIC (Advanced Programmable Interrupt Controller) | ||
//! | ||
//! For x86 kernel multi-core support. | ||
//! | ||
//! Migrate from: | ||
//! * [Redox](https://github.com/redox-os/kernel/blob/master/src/arch/x86_64/device/local_apic.rs) | ||
//! * [sv6](https://github.com/aclements/sv6/blob/master/kernel/xapic.cc) | ||
//! | ||
//! Reference: [OSDev Wiki](https://wiki.osdev.org/APIC) | ||
pub use ioapic::{IoApic, IOAPIC_ADDR}; | ||
pub use xapic::{XApic, LAPIC_ADDR}; | ||
|
||
mod ioapic; | ||
mod xapic; | ||
|
||
pub trait LocalApic { | ||
/// If this type APIC is supported | ||
fn support() -> bool; | ||
|
||
/// Initialize the LAPIC for the current CPU | ||
fn cpu_init(&mut self); | ||
|
||
/// Return this CPU's LAPIC ID | ||
fn id(&self) -> u32; | ||
|
||
fn version(&self) -> u32; | ||
|
||
/// Interrupt Command Register | ||
fn icr(&self) -> u64; | ||
|
||
fn set_icr(&mut self, value: u64); | ||
|
||
/// Acknowledge interrupt on the current CPU | ||
fn eoi(&mut self); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
use super::LocalApic; | ||
use bit_field::BitField; | ||
use core::fmt::{Debug, Error, Formatter}; | ||
use core::ptr::{read_volatile, write_volatile}; | ||
use x86::cpuid::CpuId; | ||
|
||
/// Default physical address of xAPIC | ||
pub const LAPIC_ADDR: u64 = 0xFEE00000; | ||
|
||
pub struct XApic { | ||
addr: u64, | ||
} | ||
|
||
impl XApic { | ||
pub unsafe fn new(addr: u64) -> Self { | ||
XApic { addr } | ||
} | ||
|
||
unsafe fn read(&self, reg: u32) -> u32 { | ||
read_volatile((self.addr + reg as u64) as *const u32) | ||
} | ||
|
||
unsafe fn write(&mut self, reg: u32, value: u32) { | ||
write_volatile((self.addr + reg as u64) as *mut u32, value); | ||
self.read(0x20); | ||
} | ||
} | ||
|
||
impl LocalApic for XApic { | ||
/// If this type APIC is supported | ||
fn support() -> bool { | ||
// FIXME: Check CPUID to see if xAPIC is supported. | ||
} | ||
|
||
/// Initialize the xAPIC for the current CPU. | ||
fn cpu_init(&mut self) { | ||
unsafe { | ||
// FIXME: Enable local APIC; set spurious interrupt vector. | ||
|
||
// FIXME: The timer repeatedly counts down at bus frequency | ||
|
||
// FIXME: Disable logical interrupt lines. | ||
|
||
// FIXME: Disable performance counter overflow interrupts | ||
// on machines that provide that interrupt entry. | ||
|
||
// FIXME: Map error interrupt to IRQ_ERROR. | ||
|
||
// FIXME: Clear error status register (requires back-to-back writes). | ||
|
||
// FIXME: Ack any outstanding interrupts. | ||
|
||
// FIXME: Send an Init Level De-Assert to synchronise arbitration ID's. | ||
|
||
// FIXME: Enable interrupts on the APIC (but not on the processor). | ||
} | ||
|
||
// NOTE: Try to use bitflags! macro to set the flags. | ||
} | ||
|
||
fn id(&self) -> u32 { | ||
// NOTE: Maybe you can handle regs like `0x0300` as a const. | ||
unsafe { self.read(0x0020) >> 24 } | ||
} | ||
|
||
fn version(&self) -> u32 { | ||
unsafe { self.read(0x0030) } | ||
} | ||
|
||
fn icr(&self) -> u64 { | ||
unsafe { (self.read(0x0310) as u64) << 32 | self.read(0x0300) as u64 } | ||
} | ||
|
||
fn set_icr(&mut self, value: u64) { | ||
unsafe { | ||
while self.read(0x0300).get_bit(12) {} | ||
self.write(0x0310, (value >> 32) as u32); | ||
self.write(0x0300, value as u32); | ||
while self.read(0x0300).get_bit(12) {} | ||
} | ||
} | ||
|
||
fn eoi(&mut self) { | ||
unsafe { | ||
self.write(0x00B0, 0); | ||
} | ||
} | ||
} | ||
|
||
impl Debug for XApic { | ||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { | ||
f.debug_struct("Xapic") | ||
.field("id", &self.id()) | ||
.field("version", &self.version()) | ||
.field("icr", &self.icr()) | ||
.finish() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// This is from https://github.com/rcore-os/rCore/blob/master/kernel/src/arch/x86_64/interrupt/consts.rs | ||
// Reference: https://wiki.osdev.org/Exceptions | ||
|
||
#[repr(u8)] | ||
pub enum Interrupts { | ||
DivideError = 0, | ||
Debug = 1, | ||
NonMaskableInterrupt = 2, | ||
Breakpoint = 3, | ||
Overflow = 4, | ||
BoundRangeExceeded = 5, | ||
InvalidOpcode = 6, | ||
DeviceNotAvailable = 7, | ||
DoubleFault = 8, | ||
CoprocessorSegmentOverrun = 9, | ||
InvalidTSS = 10, | ||
SegmentNotPresent = 11, | ||
StackSegmentFault = 12, | ||
GeneralProtectionFault = 13, | ||
PageFault = 14, | ||
FloatingPointException = 16, | ||
AlignmentCheck = 17, | ||
MachineCheck = 18, | ||
SIMDFloatingPointException = 19, | ||
VirtualizationException = 20, | ||
SecurityException = 30, | ||
|
||
IrqBase = 0x20, | ||
Syscall = 0x80, | ||
} | ||
|
||
/// https://www.computerhope.com/jargon/i/irq.htm | ||
/// https://wiki.osdev.org/IRQ | ||
/// https://github.com/qemu/qemu/blob/aab8cfd4c3614a049b60333a3747aedffbd04150/include/hw/i386/microvm.h#L30-L50 | ||
#[repr(u8)] | ||
pub enum Irq { | ||
Timer = 0, | ||
Keyboard = 1, | ||
Serial1 = 3, | ||
Serial0 = 4, | ||
Floppy = 6, | ||
Parallel = 7, | ||
RealTimeClock = 8, | ||
Ide0 = 14, | ||
Ide1 = 15, | ||
Error = 19, | ||
Spurious = 31, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
use crate::memory::*; | ||
use x86_64::registers::control::Cr2; | ||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; | ||
|
||
pub unsafe fn register_idt(idt: &mut InterruptDescriptorTable) { | ||
idt.divide_error.set_handler_fn(divide_error_handler); | ||
idt.double_fault | ||
.set_handler_fn(double_fault_handler) | ||
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX); | ||
idt.page_fault | ||
.set_handler_fn(page_fault_handler) | ||
.set_stack_index(gdt::PAGE_FAULT_IST_INDEX); | ||
|
||
// FIXME: handle other exceptions | ||
} | ||
|
||
pub extern "x86-interrupt" fn divide_error_handler(stack_frame: InterruptStackFrame) { | ||
panic!("EXCEPTION: DIVIDE ERROR\n\n{:#?}", stack_frame); | ||
} | ||
|
||
pub extern "x86-interrupt" fn double_fault_handler( | ||
stack_frame: InterruptStackFrame, | ||
error_code: u64, | ||
) -> ! { | ||
panic!( | ||
"EXCEPTION: DOUBLE FAULT, ERROR_CODE: 0x{:016x}\n\n{:#?}", | ||
error_code, stack_frame | ||
); | ||
} | ||
|
||
pub extern "x86-interrupt" fn page_fault_handler( | ||
stack_frame: InterruptStackFrame, | ||
err_code: PageFaultErrorCode, | ||
) { | ||
panic!( | ||
"EXCEPTION: PAGE FAULT, ERROR_CODE: {:?}\n\nTrying to access: {:#x}\n{:#?}", | ||
err_code, | ||
Cr2::read(), | ||
stack_frame | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
mod apic; | ||
mod consts; | ||
// mod clock; | ||
// mod serial; | ||
mod exceptions; | ||
|
||
use apic::*; | ||
use x86_64::structures::idt::InterruptDescriptorTable; | ||
use crate::memory::physical_to_virtual; | ||
|
||
lazy_static! { | ||
static ref IDT: InterruptDescriptorTable = { | ||
let mut idt = InterruptDescriptorTable::new(); | ||
unsafe { | ||
exceptions::register_idt(&mut idt); | ||
// TODO: clock::register_idt(&mut idt); | ||
// TODO: serial::register_idt(&mut idt); | ||
} | ||
idt | ||
}; | ||
} | ||
|
||
/// init interrupts system | ||
pub fn init() { | ||
IDT.load(); | ||
|
||
// FIXME: check and init APIC | ||
|
||
// FIXME: enable serial irq with IO APIC (use enable_irq) | ||
|
||
info!("Interrupts Initialized."); | ||
} | ||
|
||
#[inline(always)] | ||
pub fn enable_irq(irq: u8) { | ||
let mut ioapic = unsafe { IoApic::new(physical_to_virtual(IOAPIC_ADDR)) }; | ||
ioapic.enable(irq, 0); | ||
} |
Oops, something went wrong.