From 5fbf41e967ed8e413ecf1e6abb72e8d285169df4 Mon Sep 17 00:00:00 2001 From: Alexey Gavrilov Date: Fri, 24 May 2024 14:07:47 +0700 Subject: Pic + Tuple + refactor PrimaryInitialization class --- arch/x86/ic/IPic.h | 40 +++++++ arch/x86/ic/Pic.cpp | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/ic/Pic.h | 115 ++++++++++++++++++++ 3 files changed, 459 insertions(+) create mode 100644 arch/x86/ic/IPic.h create mode 100644 arch/x86/ic/Pic.cpp create mode 100644 arch/x86/ic/Pic.h (limited to 'arch/x86/ic') diff --git a/arch/x86/ic/IPic.h b/arch/x86/ic/IPic.h new file mode 100644 index 0000000..9bb1b4f --- /dev/null +++ b/arch/x86/ic/IPic.h @@ -0,0 +1,40 @@ +#ifndef IPIC_H +#define IPIC_H + +#include + + +// Defines +// ICW1 + +#define IC4 1 +#define SNGL 2 +#define ADI 4 +#define LTIM 8 + +// ICW4 + +#define PM 1 +#define AEOI 2 +#define MSBUF 4 +#define BUF 8 +#define SFNM 16 + +// PIC + +#define PICM_CTRL 0x20 +#define PICM_DATA 0x21 +#define PICS_CTRL 0xA0 +#define PICS_DATA 0xA1 + +//------------- + +class ICW +{ + public: + virtual const uint8 toByteMasterPic() const = 0; + virtual const uint8 toByteSlavePic() const = 0; + virtual const uint8 getNumber() const = 0; +}; + +#endif diff --git a/arch/x86/ic/Pic.cpp b/arch/x86/ic/Pic.cpp new file mode 100644 index 0000000..77d9041 --- /dev/null +++ b/arch/x86/ic/Pic.cpp @@ -0,0 +1,304 @@ +#include "Pic.h" + + +bool SingletonPic::isEntityAfter = false; + +ICW1::ICW1(const uint8 icw) +{ + word = byteHigh | (icw & 0x0f); +}; + +ICW1::ICW1() +{ + word = wordDefault; +}; + +bool ICW1::isExpectIcw4() +{ + return word & IC4; +}; + +const uint8 ICW1::toByteMasterPic() const +{ + return word; +} + +const uint8 ICW1::toByteSlavePic() const +{ + return word; +} + +const uint8 ICW1::getNumber() const +{ + return 1; +}; + +ICW2::ICW2() +{ + lvtAddr = mngIdt.getIrqInterruptStart(); +}; + +ICW2::ICW2(const uint8 icw) +{ + if(icw >= 0xff - Pic::numberIrq) lvtAddr = MngIdt::firstSystemIntNumber; + else lvtAddr = icw; +}; + +const uint8 ICW2::getNumber() const +{ + return 2; +}; + +const uint8 ICW2::toByteMasterPic() const +{ + if(lvtAddr >= 0xff - Pic::numberIrq) return MngIdt::firstSystemIntNumber; + else return lvtAddr; +}; + +const uint8 ICW2::toByteSlavePic() const +{ + if(lvtAddr >= 0xff - 8) return MngIdt::firstSystemIntNumber + 8; + else return lvtAddr + 8; +}; + +ICW3::ICW3() +{ + irqConnPrimaryPic = irqTwoLine; + irqConnSecondaryPic = irqTwoLineBinary; +}; + +ICW3::ICW3(const uint8 icwMaster) +{ + uint8 oneAmount = 0; + uint8 icwMasterCpy = icwMaster; + + while(icwMasterCpy) + { + oneAmount += icwMasterCpy & 0x01; + icwMasterCpy >>= 1; + } + + if(oneAmount > 1) + { + *this = ICW3(); + } + else + { + irqConnPrimaryPic = icwMaster; + + uint8 icwMasterBinary = 0; + icwMasterCpy = icwMaster; + + while(icwMasterCpy) + { + icwMasterBinary++; + icwMasterCpy >>= 1; + } + irqConnSecondaryPic = icwMasterBinary; + } +}; + + +const uint8 ICW3::toByteMasterPic() const +{ + return irqConnPrimaryPic; +}; + +const uint8 ICW3::toByteSlavePic() const +{ + return irqConnSecondaryPic; +}; + +const uint8 ICW3::getNumber() const +{ + return 3; +}; + +ICW4::ICW4() +{ + word = defaultWord; +}; + +ICW4::ICW4(uint8 icw) +{ + word = icw & 0x1f; +}; + +const uint8 ICW4::toByteMasterPic() const +{ + return word; +}; + +const uint8 ICW4::toByteSlavePic() const +{ + return word; +}; + +const uint8 ICW4::getNumber() const +{ + return 4; +}; + +bool Pic::isIcwsCorrect(const ICW *icws[numberWords]) +{ + for(uint8 idx = 0; idx < numberWords; idx++) + { + const ICW *currIcw = icws[idx]; + if(currIcw->getNumber() != idx + 1) + { + return false; + } + } + + return true; +}; + +void Pic::disableIrq(uint8 irqNumber) +{ + bool isMasterPic = irqNumber < 8; + uint8 irqBits = 0x1 << (isMasterPic ? irqNumber : irqNumber - 8); + uint8 imr = PortOps::inb(isMasterPic ? PICM_DATA : PICS_DATA); + + uint8 port = isMasterPic ? PICM_DATA : PICS_DATA; + PortOps::outb(port, imr | irqBits); +}; + +bool Pic::enableIrq(uint8 irqNumber) +{ + bool isMasterPic = irqNumber < 8; + uint8 irqBits = ~(0x1 << (isMasterPic ? irqNumber : irqNumber - 8)); + uint8 imr = PortOps::inb(isMasterPic ? PICM_DATA : PICS_DATA); + + if(!mngIdt.isInterruptSet(mngIdt.getIrqInterruptStart() + irqNumber)) + { + // ISR not set in IDT + return true; + } + + uint8 port = isMasterPic ? PICM_DATA : PICS_DATA; + PortOps::outb(port, imr & irqBits); + + return false; +}; + +void Pic::disable() +{ + // Stop recive interrupts + PortOps::outb(PICM_DATA, 0xff); + PortOps::outb(PICS_DATA, 0xff); +}; + +Pic::Pic(const ICW *icws[numberWords]) +{ + if(!isIcwsCorrect(icws)) + { + *this = Pic(); + return; + } + + // Set ICW1 to command registers + PortOps::outb(PICM_CTRL, icws[NULL]->toByteMasterPic()); + PortOps::outb(PICS_CTRL, icws[NULL]->toByteSlavePic()); + + for(uint8 idx = 1; idx < numberWords; idx++) + { + const ICW *currIcw = icws[idx]; + + if((icws[0]->toByteMasterPic() & IC4) or idx < 3) + { + PortOps::outb(PICM_DATA, currIcw->toByteMasterPic()); + PortOps::outb(PICS_DATA, currIcw->toByteSlavePic()); + } + } + + // Clear data registers + PortOps::outb(PICM_DATA, 0x0); + PortOps::outb(PICS_DATA, 0x0); + + // Set properties + icw1 = ICW1(*(ICW1 *)icws[0]); + icw2 = ICW2(*(ICW2 *)icws[1]); + icw2 = ICW2(*(ICW2 *)icws[2]); + icw2 = ICW2(*(ICW2 *)icws[3]); + + // Disable interrupt recieve + Pic::disable(); +}; + +Pic::Pic() +{ + ICW1 icw1; + ICW2 icw2; + ICW3 icw3; + ICW4 icw4; + + const ICW *icws[numberWords] = {&icw1, &icw2, &icw3, &icw4}; + *this = Pic(icws); +}; + +uint8 Pic::getIsrMaster() +{ + PortOps::outb(PICM_CTRL, readIsr); + return PortOps::inb(PICM_CTRL); +}; + +uint8 Pic::getIsrSlave() +{ + PortOps::outb(PICS_CTRL, readIsr); + return PortOps::inb(PICS_CTRL); +}; + +void Pic::sendEoi() +{ + // Recognize is the interrupt running and on which PIC is it + // Further, check AEOI bit in ICW4 + // Send EOI if AEOI bit not set + uint16 isrFull = (uint16)getIsrSlave() << Pic::numberIrq | (uint16)getIsrMaster(); + bool intOnMaster = (isrFull & 0x00ff) > 0; + bool intOnSlave = (isrFull & 0xff00) > 0; + + // Interrupt not executed - EOI not send + if(intOnMaster == 0 and intOnSlave == 0) return; + // Interrupt expected only on master PIC + else if(intOnMaster and !intOnSlave) + { + PortOps::outb(PICM_CTRL, eoiCommand); + } + // Interrupt expected only on slave PIC + else if(!intOnMaster and intOnSlave) + { + PortOps::outb(PICS_CTRL, eoiCommand); + } +}; + +SingletonPic::SingletonPic() : Pic() +{ + if(isEntityAfter == false) + { + isEntityFirst = true; + isEntityAfter = true; + } + else + { + isEntityFirst = false; + } +}; + +SingletonPic::SingletonPic(const ICW *icws[numberWords]) : Pic(icws) +{ + if(isEntityAfter == false) + { + isEntityFirst = true; + isEntityAfter = true; + } + else + { + isEntityFirst = false; + } +}; + +Pic *SingletonPic::getInstance() +{ + if(isEntityFirst) return (Pic *)this; + return nullptr; +}; diff --git a/arch/x86/ic/Pic.h b/arch/x86/ic/Pic.h new file mode 100644 index 0000000..9739e05 --- /dev/null +++ b/arch/x86/ic/Pic.h @@ -0,0 +1,115 @@ +#ifndef PIC_H +#define PIC_H + +#include "../idt/Idt.h" +#include "../port/Operations" +#include "IPic.h" +#include + +class ICW1 : public ICW +{ + private: + uint8 word; + public: + // Const part of ICW1 is high byte + const static uint8 byteHigh = 0x10; + // Inittialize bit and ICW4 recieve bit + const static uint8 wordDefault = byteHigh | 0x01; + ICW1(); + ICW1(const uint8 icw); + bool isExpectIcw4(); + virtual const uint8 toByteMasterPic() const override final; + virtual const uint8 toByteSlavePic() const override final; + virtual const uint8 getNumber() const override final; +}; + +class ICW2 : public ICW +{ + private: + uint8 lvtAddr; + public: + ICW2(); + ICW2(const uint8 icw); + virtual const uint8 toByteMasterPic() const override final; + virtual const uint8 toByteSlavePic() const override final; + virtual const uint8 getNumber() const override final; +}; + +class ICW3 : public ICW +{ + private: + const static uint8 irqTwoLine = 0x4; + const static uint8 irqTwoLineBinary = 0x2; + uint8 irqConnPrimaryPic; + uint8 irqConnSecondaryPic; + public: + ICW3(); + ICW3(const uint8 icwMaster); + virtual const uint8 toByteMasterPic() const override final; + virtual const uint8 toByteSlavePic() const override final; + virtual const uint8 getNumber() const override final; +}; + +class ICW4 : public ICW +{ + private: + static const uint8 defaultWord = 0x01; + uint8 word; + public: + ICW4(); + ICW4(const uint8 icw); + virtual const uint8 toByteMasterPic() const override final; + virtual const uint8 toByteSlavePic() const override final; + virtual const uint8 getNumber() const override final; +}; + +class Pic +{ + protected: + + static const uint8 numberWords = 4; + static const uint8 readIrr = 0xa; + static const uint8 readIsr = 0xb; + static const uint8 eoiCommand = 0x20; + + private: + ICW1 icw1; + ICW2 icw2; + ICW3 icw3; + ICW4 icw4; + bool isIcwsCorrect(const ICW *icws[numberWords]); + + protected: + Pic(); + Pic(const ICW *icws[numberWords]); + Pic(const Pic &) = default; + + public: + static const uint8 numberIrq = 16; + // Valid equals from 0 to 7 and from 8 to 15 + // Return true if ISR not set, false is success + bool enableIrq(uint8 irqNumber); + void disableIrq(uint8 irqNumber); + static uint8 getIsrMaster(); + static uint8 getIsrSlave(); + static uint8 getIrrMaster(); + static void sendEoi(); + // Set IMR to -xff + static void disable(); +}; + +// Be more careful with instance of Pic. +// When SingletonPic instance been deleted, Pic instance not be more exist +class SingletonPic : public Pic, public ISingleton +{ + private: + static bool isEntityAfter; + bool isEntityFirst; + + public: + SingletonPic(); + SingletonPic(const ICW *icws[numberWords]); + virtual Pic *getInstance() override final; +}; + +#endif -- cgit v1.2.3