summaryrefslogtreecommitdiffstats
path: root/arch/x86/ic
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/ic')
-rw-r--r--arch/x86/ic/IPic.h40
-rw-r--r--arch/x86/ic/Pic.cpp304
-rw-r--r--arch/x86/ic/Pic.h115
3 files changed, 459 insertions, 0 deletions
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 <types.h>
+
+
+// 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 <ISingleton.h>
+
+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<Pic>
+{
+ private:
+ static bool isEntityAfter;
+ bool isEntityFirst;
+
+ public:
+ SingletonPic();
+ SingletonPic(const ICW *icws[numberWords]);
+ virtual Pic *getInstance() override final;
+};
+
+#endif