### PIC Initialization and Interrupt Handling Source: https://context7.com/rust-osdev/pic8259/llms.txt This section outlines the setup for the ChainedPics structure and the implementation of interrupt handlers, including the critical EOI notification. ```APIDOC ## Initialize and Manage PICs ### Description This setup involves defining the PIC offsets, initializing the ChainedPics instance within a Mutex, and ensuring that every hardware interrupt handler signals the end of the interrupt to the PIC. ### Method Rust Library Interface ### Endpoint `pic8259::ChainedPics` ### Parameters #### Request Body - **PIC_1_OFFSET** (u8) - Required - The base interrupt vector for the master PIC. - **PIC_2_OFFSET** (u8) - Required - The base interrupt vector for the slave PIC. ### Request Example ```rust let mut pics = ChainedPics::new(0x20, 0x28); unsafe { pics.initialize(); } ``` ### Response #### Success Response (200) - **notify_end_of_interrupt** (function) - Signals the PIC that the interrupt has been processed. #### Response Example ```rust unsafe { PICS.lock().notify_end_of_interrupt(interrupt_id); } ``` ``` -------------------------------- ### Create Contiguous ChainedPics Interface Source: https://context7.com/rust-osdev/pic8259/llms.txt Creates a `ChainedPics` interface where both PICs are mapped to a single, contiguous range of interrupts starting from a specified offset. This is a convenience function equivalent to `ChainedPics::new(offset, offset + 8)`, simplifying the common configuration pattern. ```Rust use pic8259::ChainedPics; use spin::Mutex; // Map all 16 PIC interrupts contiguously starting at 0x20 // PIC1: 0x20-0x27, PIC2: 0x28-0x2F pub static PICS: Mutex = Mutex::new(unsafe { ChainedPics::new_contiguous(0x20) }); // This is equivalent to: // Mutex::new(unsafe { ChainedPics::new(0x20, 0x28) }); ``` -------------------------------- ### Initialize and Use ChainedPics Source: https://github.com/rust-osdev/pic8259/blob/main/README.md Demonstrates how to declare a global ChainedPics instance, initialize the controllers, and signal the end of an interrupt. ```rust use pic8259::ChainedPics; use spin::Mutex; // Map PIC interrupts to 0x20 through 0x2f. static PICS: Mutex = Mutex::new(unsafe { ChainedPics::new(0x20, 0x28) }); // Initialize the PICs PICS.lock().initialize(); // Notify end of interrupt PICS.lock().notify_end_of_interrupt(interrupt_id); ``` -------------------------------- ### PIC Initialization and Management Source: https://github.com/rust-osdev/pic8259/blob/main/README.md Methods for initializing the chained PICs and signaling the end of an interrupt. ```APIDOC ## Initialize PICs ### Description Initializes the 8259 PICs with specified offset values to map hardware interrupts. ### Method Rust Method (unsafe) ### Endpoint ChainedPics::initialize() ### Parameters #### Request Body - **offset1** (u8) - Required - Offset for the master PIC - **offset2** (u8) - Required - Offset for the slave PIC ### Request Example static PICS: Mutex = Mutex::new(unsafe { ChainedPics::new(0x20, 0x28) }); PICS.lock().initialize(); ## Notify End of Interrupt ### Description Signals the PIC that an interrupt has been handled, allowing the controller to send further interrupts. ### Method Rust Method (unsafe) ### Endpoint ChainedPics::notify_end_of_interrupt(interrupt_id) ### Parameters #### Path Parameters - **interrupt_id** (u8) - Required - The ID of the interrupt that was handled ### Request Example PICS.lock().notify_end_of_interrupt(0x20); ``` -------------------------------- ### Kernel PIC and IDT Integration in Rust Source: https://context7.com/rust-osdev/pic8259/llms.txt This snippet demonstrates how to initialize the ChainedPics, define an Interrupt Descriptor Table, and implement interrupt handlers for hardware events like timer ticks and keyboard input. It requires the x86_64 and spin crates to manage CPU interrupts and thread-safe access to the PIC. ```rust use pic8259::ChainedPics; use spin::Mutex; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; use lazy_static::lazy_static; pub const PIC_1_OFFSET: u8 = 32; pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8; pub static PICS: Mutex = Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) }); #[derive(Debug, Clone, Copy)] #[repr(u8)] pub enum InterruptIndex { Timer = PIC_1_OFFSET, Keyboard, } lazy_static! { static ref IDT: InterruptDescriptorTable = { let mut idt = InterruptDescriptorTable::new(); idt.breakpoint.set_handler_fn(breakpoint_handler); idt.double_fault.set_handler_fn(double_fault_handler); idt[InterruptIndex::Timer as usize].set_handler_fn(timer_handler); idt[InterruptIndex::Keyboard as usize].set_handler_fn(keyboard_handler); idt }; } extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {} extern "x86-interrupt" fn double_fault_handler( stack_frame: InterruptStackFrame, _error_code: u64 ) -> ! { panic!("DOUBLE FAULT\n{:#?}", stack_frame); } extern "x86-interrupt" fn timer_handler(_stack_frame: InterruptStackFrame) { unsafe { PICS.lock().notify_end_of_interrupt(InterruptIndex::Timer as u8); } } extern "x86-interrupt" fn keyboard_handler(_stack_frame: InterruptStackFrame) { use x86_64::instructions::port::Port; let mut port = Port::new(0x60); let scancode: u8 = unsafe { port.read() }; unsafe { PICS.lock().notify_end_of_interrupt(InterruptIndex::Keyboard as u8); } } pub fn init() { IDT.load(); unsafe { PICS.lock().initialize(); } x86_64::instructions::interrupts::enable(); } ``` -------------------------------- ### Initialize PICs for 8086 Mode Source: https://context7.com/rust-osdev/pic8259/llms.txt Initializes both PIC chips into the standard 8086 mode. This involves sending a 3-byte initialization sequence to each PIC to configure their interrupt offsets and the cascade connection. This function must be called with CPU interrupts disabled before they are re-enabled. ```Rust use pic8259::ChainedPics; use spin::Mutex; pub static PICS: Mutex = Mutex::new(unsafe { ChainedPics::new_contiguous(0x20) }); pub fn init_interrupts() { // Initialize the Interrupt Descriptor Table (IDT) first // idt::init(); // Initialize the PICs // SAFETY: Must be called with interrupts disabled unsafe { PICS.lock().initialize(); } // Now safe to enable CPU interrupts // x86_64::instructions::interrupts::enable(); } // Complete kernel initialization example pub fn kernel_main() { // Set up IDT with interrupt handlers init_idt(); // Initialize PICs before enabling interrupts unsafe { PICS.lock().initialize(); } // Enable interrupts - hardware interrupts will now be delivered x86_64::instructions::interrupts::enable(); // Kernel main loop loop { x86_64::instructions::hlt(); // Halt until next interrupt } } ``` -------------------------------- ### Configure Cargo Dependencies for PIC8259 Source: https://github.com/rust-osdev/pic8259/blob/main/README.md Add the pic8259 crate and a mutex implementation to your Cargo.toml file to enable interrupt controller management. ```toml [dependencies] pic8259 = "0.10.0" spin = "0.9.0" ``` -------------------------------- ### Check and Dispatch Hardware Interrupts Source: https://context7.com/rust-osdev/pic8259/llms.txt Shows how to use handles_interrupt to distinguish between hardware interrupts and CPU exceptions or software interrupts, allowing for proper routing in an interrupt dispatcher. ```rust use pic8259::ChainedPics; use spin::Mutex; pub static PICS: Mutex = Mutex::new(unsafe { ChainedPics::new_contiguous(0x20) }); pub fn dispatch_interrupt(interrupt_id: u8) { if interrupt_id < 0x20 { handle_cpu_exception(interrupt_id); } else if PICS.lock().handles_interrupt(interrupt_id) { handle_hardware_interrupt(interrupt_id); unsafe { PICS.lock().notify_end_of_interrupt(interrupt_id); } } else { handle_software_interrupt(interrupt_id); } } ``` -------------------------------- ### Rust: Disable PICs and Manage Interrupt Context Source: https://context7.com/rust-osdev/pic8259/llms.txt Demonstrates disabling both PICs by masking all interrupts, typically used when transitioning to APIC mode. Also includes a utility function to temporarily disable all hardware interrupts, execute a closure, and then restore the previous interrupt mask state. ```rust use pic8259::ChainedPics; use spin::Mutex; pub static PICS: Mutex = Mutex::new(unsafe { ChainedPics::new_contiguous(0x20) }); // Disable legacy PIC when switching to APIC pub fn switch_to_apic() { // First, disable all PIC interrupts unsafe { PICS.lock().disable(); } // Now initialize and enable APIC // apic::initialize(); // ioapic::initialize(); } // Temporarily disable all hardware interrupts pub fn with_interrupts_disabled(f: F) -> R where F: FnOnce() -> R, { // Save current masks let saved_masks = unsafe { PICS.lock().read_masks() }; // Disable all PIC interrupts unsafe { PICS.lock().disable(); } // Execute the closure let result = f(); // Restore previous masks unsafe { PICS.lock().write_masks(saved_masks[0], saved_masks[1]); } result } ``` -------------------------------- ### Create ChainedPics Interface with Custom Offsets Source: https://context7.com/rust-osdev/pic8259/llms.txt Constructs a new `ChainedPics` interface for the standard PIC1 and PIC2 controllers, allowing custom interrupt offsets. This is essential for avoiding conflicts with CPU exceptions (0x00-0x1F) by remapping PIC interrupts to a safe range (e.g., 0x20-0x2F). The `Mutex` ensures thread-safe access to the PICs. ```Rust use pic8259::ChainedPics; use spin::Mutex; // Standard configuration: Map PIC1 interrupts to 0x20-0x27, PIC2 to 0x28-0x2F // This avoids conflicts with CPU exceptions (0x00-0x1F) pub const PIC_1_OFFSET: u8 = 0x20; pub const PIC_2_OFFSET: u8 = 0x28; // Create a global, mutex-protected PIC interface // SAFETY: The offsets must not overlap with CPU exception vectors (0x00-0x1F) pub static PICS: Mutex = Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) }); // Define interrupt indices for common hardware interrupts #[derive(Debug, Clone, Copy)] #[repr(u8)] pub enum InterruptIndex { Timer = PIC_1_OFFSET, // IRQ0 - System timer Keyboard = PIC_1_OFFSET + 1, // IRQ1 - Keyboard Cascade = PIC_1_OFFSET + 2, // IRQ2 - Cascade (used internally) Com2 = PIC_1_OFFSET + 3, // IRQ3 - COM2 Com1 = PIC_1_OFFSET + 4, // IRQ4 - COM1 Lpt2 = PIC_1_OFFSET + 5, // IRQ5 - LPT2 Floppy = PIC_1_OFFSET + 6, // IRQ6 - Floppy disk Lpt1 = PIC_1_OFFSET + 7, // IRQ7 - LPT1 / Spurious Rtc = PIC_2_OFFSET, // IRQ8 - Real-time clock Acpi = PIC_2_OFFSET + 1, // IRQ9 - ACPI Available1 = PIC_2_OFFSET + 2, // IRQ10 - Available Available2 = PIC_2_OFFSET + 3, // IRQ11 - Available Mouse = PIC_2_OFFSET + 4, // IRQ12 - PS/2 Mouse Coprocessor = PIC_2_OFFSET + 5, // IRQ13 - FPU PrimaryAta = PIC_2_OFFSET + 6, // IRQ14 - Primary ATA SecondaryAta = PIC_2_OFFSET + 7,// IRQ15 - Secondary ATA } ``` -------------------------------- ### Notify End of Interrupt with ChainedPics Source: https://context7.com/rust-osdev/pic8259/llms.txt Demonstrates how to signal the end of an interrupt to the PICs. This is essential for re-enabling future interrupts and handles cascading logic automatically for IRQ 8-15. ```rust use pic8259::ChainedPics; use spin::Mutex; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; pub const PIC_1_OFFSET: u8 = 0x20; pub static PICS: Mutex = Mutex::new(unsafe { ChainedPics::new_contiguous(PIC_1_OFFSET) }); extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) { unsafe { PICS.lock().notify_end_of_interrupt(PIC_1_OFFSET); } } extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) { use x86_64::instructions::port::Port; let mut port = Port::new(0x60); let scancode: u8 = unsafe { port.read() }; unsafe { PICS.lock().notify_end_of_interrupt(PIC_1_OFFSET + 1); } } ``` -------------------------------- ### Rust: Read and Write PIC Interrupt Masks Source: https://context7.com/rust-osdev/pic8259/llms.txt Provides functions to read the current interrupt mask registers of both master and slave PICs, and to write new masks. Each bit in the mask corresponds to an IRQ line; a set bit (1) disables the interrupt, while a clear bit (0) enables it. This is crucial for selectively enabling or disabling hardware interrupts. ```rust use pic8259::ChainedPics; use spin::Mutex; pub static PICS: Mutex = Mutex::new(unsafe { ChainedPics::new_contiguous(0x20) }); // Read current interrupt masks pub fn get_interrupt_masks() -> [u8; 2] { unsafe { PICS.lock().read_masks() } } // Enable only timer and keyboard interrupts, mask all others pub fn enable_basic_interrupts() { // PIC1 mask: bit 0 = timer, bit 1 = keyboard // 0xFC = 11111100 binary -> only IRQ0 (timer) and IRQ1 (keyboard) enabled let pic1_mask: u8 = 0xFC; // PIC2 mask: all masked (no PIC2 interrupts needed for basic setup) let pic2_mask: u8 = 0xFF; unsafe { PICS.lock().write_masks(pic1_mask, pic2_mask); } } // Enable a specific IRQ pub fn enable_irq(irq: u8) { let mut pics = PICS.lock(); let masks = unsafe { pics.read_masks() }; if irq < 8 { // IRQ 0-7: PIC1 let new_mask = masks[0] & !(1 << irq); unsafe { pics.write_masks(new_mask, masks[1]); } } else if irq < 16 { // IRQ 8-15: PIC2 let new_mask = masks[1] & !(1 << (irq - 8)); unsafe { pics.write_masks(masks[0], new_mask); } } } // Disable a specific IRQ pub fn disable_irq(irq: u8) { let mut pics = PICS.lock(); let masks = unsafe { pics.read_masks() }; if irq < 8 { let new_mask = masks[0] | (1 << irq); unsafe { pics.write_masks(new_mask, masks[1]); } } else if irq < 16 { let new_mask = masks[1] | (1 << (irq - 8)); unsafe { pics.write_masks(masks[0], new_mask); } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.