mirror of
https://github.com/Plexi09/Nadir-Kernel.git
synced 2026-10-20 15:07:27 +02:00
Nadir 8259 PIC driver
This commit is contained in:
parent
6ee1900c1a
commit
b1b78bb5b9
2 changed files with 148 additions and 0 deletions
58
include/pic.h
Normal file
58
include/pic.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/* Nadir 8259 PIC driver: remap, EOI, IRQ masking.
|
||||
*
|
||||
* Runs in 64-bit long mode at Ring 0 (CPL 0) with the stage-2 GDT.
|
||||
* Privileged instructions: `outb`/`inb` (via io.h) trap with #GP(0)
|
||||
* when CPL > IOPL, so every entry point below is Ring 0 only.
|
||||
* Fault behavior: no CPU fault is possible beyond a programming bug;
|
||||
* a wrong sequence masks the wrong IRQ or loses an EOI (hung line),
|
||||
* never a triple fault by itself. IF stays cleared by the caller;
|
||||
* this driver never executes `sti`/`cli`.
|
||||
*/
|
||||
|
||||
#ifndef NADIR_PIC_H
|
||||
#define NADIR_PIC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Command/data ports for the master (PIC1) and slave (PIC2). */
|
||||
#define PIC1_CMD 0x20U
|
||||
#define PIC1_DATA 0x21U
|
||||
#define PIC2_CMD 0xA0U
|
||||
#define PIC2_DATA 0xA1U
|
||||
|
||||
/* End-of-interrupt command byte. */
|
||||
#define PIC_EOI 0x20U
|
||||
|
||||
/* Remapped vector bases: IRQ 0-7 -> vectors 32-39, IRQ 8-15 -> 40-47. */
|
||||
#define PIC_IRQ0_VECTOR 0x20U
|
||||
#define PIC_IRQ8_VECTOR 0x28U
|
||||
|
||||
/* Number of IRQ lines behind the cascaded 8259 pair. */
|
||||
#define PIC_IRQ_COUNT 16U
|
||||
|
||||
/* Remap the cascaded 8259 pair to vectors 32-47 and mask everything.
|
||||
* After reset IRQs overlap CPU exceptions 0-15, so without a
|
||||
* remap a timer tick looks like a fault. Mask-all leaves each device
|
||||
* opt-in via pic_unmask().
|
||||
* Preconditions: Ring 0, called once before idt_install_irqs().
|
||||
* Failure modes: none. */
|
||||
void pic_remap(void);
|
||||
|
||||
/* Signal end-of-interrupt for IRQ line `irq` (0-15).
|
||||
* WHY cascade order: the slave must be acked before the master or the
|
||||
* master keeps the cascade line busy and IRQ 2 stops firing.
|
||||
* Preconditions: Ring 0, `irq` < 16.
|
||||
* Failure modes: out-of-range `irq` is ignored. */
|
||||
void pic_eoi(uint8_t irq);
|
||||
|
||||
/* Mask (disable) IRQ line `irq` (0-15).
|
||||
* Preconditions: Ring 0, `irq` < 16.
|
||||
* Failure modes: out-of-range `irq` is ignored. */
|
||||
void pic_mask(uint8_t irq);
|
||||
|
||||
/* Unmask (enable) IRQ line `irq` (0-15).
|
||||
* Preconditions: Ring 0, `irq` < 16, PIC already remapped.
|
||||
* Failure modes: out-of-range `irq` is ignored. */
|
||||
void pic_unmask(uint8_t irq);
|
||||
|
||||
#endif /* NADIR_PIC_H */
|
||||
90
kernel/arch/x86_64/pic.c
Normal file
90
kernel/arch/x86_64/pic.c
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/* Nadir 8259 PIC driver: cascaded master/slave remap + EOI + masking.
|
||||
*
|
||||
* Runs in 64-bit long mode at Ring 0 (CPL 0) with the stage-2 GDT.
|
||||
* Privileged instructions: `outb`/`inb` via io.h (trap #GP if CPL >
|
||||
* IOPL); no `cli`/`sti`/`lidt`.
|
||||
* Fault behavior: no CPU fault possible a wrong ICW order only
|
||||
* misroutes IRQs.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "io.h"
|
||||
#include "pic.h"
|
||||
|
||||
/* Init control words: ICW1 starts init, ICW2 sets the vector base,
|
||||
* ICW3 wires the cascade (master IRQ2 <-> slave identity 2), ICW4
|
||||
* selects 8086 mode. io_wait() after each byte gives the slow 8259
|
||||
* time to latch it. */
|
||||
#define PIC_ICW1_INIT 0x11U
|
||||
#define PIC_ICW3_MASTER_SLAVE_LINE 0x04U
|
||||
#define PIC_ICW3_SLAVE_ID 0x02U
|
||||
#define PIC_ICW4_8086 0x01U
|
||||
|
||||
void pic_remap(void)
|
||||
{
|
||||
/* WHY this exact order: the 8259 latches ICW2-4 only while in init
|
||||
* mode, and the cascade identities must match or slave IRQs never
|
||||
* reach the CPU. Mask-all at the end keeps devices quiet until
|
||||
* their driver calls pic_unmask(). */
|
||||
outb(PIC1_CMD, PIC_ICW1_INIT);
|
||||
io_wait();
|
||||
outb(PIC2_CMD, PIC_ICW1_INIT);
|
||||
io_wait();
|
||||
outb(PIC1_DATA, PIC_IRQ0_VECTOR);
|
||||
io_wait();
|
||||
outb(PIC2_DATA, PIC_IRQ8_VECTOR);
|
||||
io_wait();
|
||||
outb(PIC1_DATA, PIC_ICW3_MASTER_SLAVE_LINE);
|
||||
io_wait();
|
||||
outb(PIC2_DATA, PIC_ICW3_SLAVE_ID);
|
||||
io_wait();
|
||||
outb(PIC1_DATA, PIC_ICW4_8086);
|
||||
io_wait();
|
||||
outb(PIC2_DATA, PIC_ICW4_8086);
|
||||
io_wait();
|
||||
outb(PIC1_DATA, 0xFFU);
|
||||
io_wait();
|
||||
outb(PIC2_DATA, 0xFFU);
|
||||
io_wait();
|
||||
}
|
||||
|
||||
void pic_eoi(uint8_t irq)
|
||||
{
|
||||
if (irq >= PIC_IRQ_COUNT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (irq >= 8U) {
|
||||
outb(PIC2_CMD, PIC_EOI);
|
||||
}
|
||||
outb(PIC1_CMD, PIC_EOI);
|
||||
}
|
||||
|
||||
void pic_mask(uint8_t irq)
|
||||
{
|
||||
uint16_t port;
|
||||
uint8_t mask;
|
||||
|
||||
if (irq >= PIC_IRQ_COUNT) {
|
||||
return;
|
||||
}
|
||||
|
||||
port = (irq < 8U) ? PIC1_DATA : PIC2_DATA;
|
||||
mask = inb(port) | (uint8_t)(1U << (irq & 7U));
|
||||
outb(port, mask);
|
||||
}
|
||||
|
||||
void pic_unmask(uint8_t irq)
|
||||
{
|
||||
uint16_t port;
|
||||
uint8_t mask;
|
||||
|
||||
if (irq >= PIC_IRQ_COUNT) {
|
||||
return;
|
||||
}
|
||||
|
||||
port = (irq < 8U) ? PIC1_DATA : PIC2_DATA;
|
||||
mask = inb(port) & (uint8_t) ~(1U << (irq & 7U));
|
||||
outb(port, mask);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue