Chroma/chroma/system/cpu.c

270 lines
8.5 KiB
C

#include <kernel/chroma.h>
#include <kernel/system/interrupts.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
/* This class provides functions for setting up and preparing the CPU for the things the kernel will do.
* Mainly, it allows you to:
*
* Set up and install the GDT and IDT
* Refresh the Code Segment to force ourselves into our own GDT
* Install new ISR and IRQ handlers.
* It also has (unused) functionality for extra stacks, to be used with Non-Maskable Interrupt, Double Fault, Machine Check and Breakpoint Exceptions.
* //TODO
*
*/
#define NMI_STACK 4096
#define DF_STACK 4096
#define MC_STACK 4096
#define BP_STACK 4096
void InvalidatePage(size_t Page) {
__asm__ __volatile__("invlpg (%%eax)" : : "a" (Page) );
}
__attribute__((aligned(64))) static volatile unsigned char NMIStack[NMI_STACK] = {0};
__attribute__((aligned(64))) static volatile unsigned char DFStack[DF_STACK] = {0};
__attribute__((aligned(64))) static volatile unsigned char MCStack[MC_STACK] = {0};
__attribute__((aligned(64))) static volatile unsigned char BPStack[BP_STACK] = {0};
__attribute__((aligned(64))) static volatile size_t InitGDT[5] = {
0,
0x00af9a000000ffff,
0x00cf92000000ffff,
0x0080890000000067,
0
};
__attribute__((aligned(64))) static volatile TSS64 TSSEntries = {0};
__attribute__((aligned(64))) static volatile IDT_GATE IDTEntries[256] = {0};
static void RefreshCS() {
__asm__ __volatile__ ("mov $16, %ax \n\t" // 16 = 0x10 = index 2 of GDT
"mov %ax, %ds \n\t" // Next few lines prepare the processor for the sudden change into the data segment
"mov %ax, %es \n\t" //
"mov %ax, %fs \n\t" //
"mov %ax, %gs \n\t" //
"mov %ax, %ss \n\t" //
"movq $8, %rdx \n\t" // 8 = 0x8 = index 1 of GDT
"leaq 4(%rip), %rax \n\t" // Returns execution to immediately after the iret, required for changing %cs while in long mode. - this is currently literally the only way to do it.
"pushq %rdx \n\t" //
"pushq %rax \n\t" //
"lretq \n\t"); //
}
void PrepareCPU() {
SetupInitialGDT();
SetupIDT();
SetupExtensions();
InitInterrupts();
}
void SetupExtensions() {
// Enable SSE
size_t CR0 = ReadControlRegister(0);
CR0 &= ~(1 << 2);
CR0 |= 1;
WriteControlRegister(0, CR0);
// Enable OSXSAVE and gang
size_t CR4 = ReadControlRegister(4);
CR4 |= (1 << 9);
CR4 |= (1 << 10);
CR4 |= (1 << 18);
WriteControlRegister(4, CR4);
// Enable AVX (and AVX-512 in future)
CR0 = ReadExtendedControlRegister(0);
SerialPrintf("XCR0 is currently %x.\n", CR0);
CR0 |= (1 << 0);
CR0 |= (1 << 1);
CR0 |= (1 << 2);
/*CR0 |= (1 << 5);
CR0 |= (1 << 6);
CR0 |= (1 << 7);*/
SerialPrintf("About to write xcr0: %x\n", CR0);
WriteExtendedControlRegister(0, CR0);
}
void SetupInitialGDT() {
DESC_TBL GDTData = {0};
size_t TSSBase = (uint64_t) (&TSSEntries);
uint16_t TSSLower = (uint16_t) TSSBase;
uint8_t TSSMid1 = (uint8_t) (TSSBase >> 16);
uint8_t TSSMid2 = (uint8_t) (TSSBase >> 24);
uint32_t TSSHigher = (uint32_t) (TSSBase >> 32);
GDTData.Limit = sizeof(InitGDT) - 1;
GDTData.Base = (size_t) InitGDT;
( (TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]) )->BaseLow = TSSLower;
( (TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]) )->BaseMid1 = TSSMid1;
( (TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]) )->BaseMid2 = TSSMid2;
( (TSS_ENTRY*) (&((GDT_ENTRY*) InitGDT)[3]) )->BaseHigh = TSSHigher;
WriteGDT(GDTData);
WriteTSR(3 << 3);
RefreshCS();
}
static void SetISR(size_t ISRNum, size_t ISRAddr) {
uint16_t ISRBaseLow = (uint16_t) ISRAddr;
uint16_t ISRBaseMid = (uint16_t) (ISRAddr >> 16);
uint32_t ISRBaseHigh = (uint32_t) (ISRAddr >> 32);
IDTEntries[ISRNum].BaseLow = ISRBaseLow;
IDTEntries[ISRNum].Segment = 0x08;
IDTEntries[ISRNum].ISTAndZero = 0;
IDTEntries[ISRNum].SegmentType = 0x8E;
IDTEntries[ISRNum].BaseMid = ISRBaseMid;
IDTEntries[ISRNum].BaseHigh = ISRBaseHigh;
IDTEntries[ISRNum].Reserved = 0;
}
static void SetISRNMI(size_t ISRNum, size_t ISRAddr) {
uint16_t ISRBaseLow = (uint16_t) ISRAddr;
uint16_t ISRBaseMid = (uint16_t) (ISRAddr >> 16);
uint32_t ISRBaseHigh = (uint32_t) (ISRAddr >> 32);
IDTEntries[ISRNum].BaseLow = ISRBaseLow;
IDTEntries[ISRNum].Segment = 0x08;
IDTEntries[ISRNum].ISTAndZero = 1;
IDTEntries[ISRNum].SegmentType = 0x8E;
IDTEntries[ISRNum].BaseMid = ISRBaseMid;
IDTEntries[ISRNum].BaseHigh = ISRBaseHigh;
IDTEntries[ISRNum].Reserved = 0;
}
static void SetISRDF(size_t ISRNum, size_t ISRAddr) {
uint16_t ISRBaseLow = (uint16_t) ISRAddr;
uint16_t ISRBaseMid = (uint16_t) (ISRAddr >> 16);
uint32_t ISRBaseHigh = (uint32_t) (ISRAddr >> 32);
IDTEntries[ISRNum].BaseLow = ISRBaseLow;
IDTEntries[ISRNum].Segment = 0x08;
IDTEntries[ISRNum].ISTAndZero = 2;
IDTEntries[ISRNum].SegmentType = 0x8E;
IDTEntries[ISRNum].BaseMid = ISRBaseMid;
IDTEntries[ISRNum].BaseHigh = ISRBaseHigh;
IDTEntries[ISRNum].Reserved = 0;
}
static void SetISRMC(size_t ISRNum, size_t ISRAddr) {
uint16_t ISRBaseLow = (uint16_t) ISRAddr;
uint16_t ISRBaseMid = (uint16_t) (ISRAddr >> 16);
uint32_t ISRBaseHigh = (uint32_t) (ISRAddr >> 32);
IDTEntries[ISRNum].BaseLow = ISRBaseLow;
IDTEntries[ISRNum].Segment = 0x08;
IDTEntries[ISRNum].ISTAndZero = 3;
IDTEntries[ISRNum].SegmentType = 0x8E;
IDTEntries[ISRNum].BaseMid = ISRBaseMid;
IDTEntries[ISRNum].BaseHigh = ISRBaseHigh;
IDTEntries[ISRNum].Reserved = 0;
}
static void SetISRBP(size_t ISRNum, size_t ISRAddr) {
uint16_t ISRBaseLow = (uint16_t) ISRAddr;
uint16_t ISRBaseMid = (uint16_t) (ISRAddr >> 16);
uint32_t ISRBaseHigh = (uint32_t) (ISRAddr >> 32);
IDTEntries[ISRNum].BaseLow = ISRBaseLow;
IDTEntries[ISRNum].Segment = 0x08;
IDTEntries[ISRNum].ISTAndZero = 4;
IDTEntries[ISRNum].SegmentType = 0x8E;
IDTEntries[ISRNum].BaseMid = ISRBaseMid;
IDTEntries[ISRNum].BaseHigh = ISRBaseHigh;
IDTEntries[ISRNum].Reserved = 0;
}
void SetupIDT() {
DESC_TBL IDTData = {0};
IDTData.Limit = (sizeof(IDT_GATE) * 256) - 1;
IDTData.Base = (size_t) &IDTEntries;
//memset(&IDTEntries, 0, sizeof(IDT_GATE) * 256);
RemapIRQControllers();
*(size_t*) (&TSSEntries.IST1) = (size_t) (NMIStack + NMI_STACK);
*(size_t*) (&TSSEntries.IST2) = (size_t) (DFStack + DF_STACK);
*(size_t*) (&TSSEntries.IST3) = (size_t) (MCStack + MC_STACK);
*(size_t*) (&TSSEntries.IST4) = (size_t) (BPStack + BP_STACK);
SetISR (0, (size_t) ISR0Handler);
SetISRBP (1, (size_t) ISR1Handler);
SetISRNMI (2, (size_t) ISR2Handler);
SetISRBP (3, (size_t) ISR3Handler);
SetISR (4, (size_t) ISR4Handler);
SetISR (5, (size_t) ISR5Handler);
SetISR (6, (size_t) ISR6Handler);
SetISR (7, (size_t) ISR7Handler);
SetISRDF (8, (size_t) ISR8Handler);
SetISR (9, (size_t) ISR9Handler);
SetISR (10, (size_t) ISR10Handler);
SetISR (11, (size_t) ISR11Handler);
SetISR (12, (size_t) ISR12Handler);
SetISR (13, (size_t) ISR13Handler);
SetISR (14, (size_t) ISR14Handler);
SetISR (15, (size_t) ISR15Handler);
SetISR (16, (size_t) ISR16Handler);
SetISR (17, (size_t) ISR17Handler);
SetISRMC (18, (size_t) ISR18Handler);
SetISR (19, (size_t) ISR19Handler);
SetISR (20, (size_t) ISR20Handler);
SetISR (30, (size_t) ISR30Handler);
for(size_t i = 1; i < 11; i++) {
if(i != 9) {
SetISR(i + 20, (size_t) ReservedISRHandler);
}
}
SetISR(32, (size_t) IRQ0Handler);
SetISR(33, (size_t) IRQ1Handler);
SetISR(34, (size_t) IRQ2Handler);
SetISR(35, (size_t) IRQ3Handler);
SetISR(36, (size_t) IRQ4Handler);
SetISR(37, (size_t) IRQ5Handler);
SetISR(38, (size_t) IRQ6Handler);
SetISR(39, (size_t) IRQ7Handler);
SetISR(40, (size_t) IRQ8Handler);
SetISR(41, (size_t) IRQ9Handler);
SetISR(42, (size_t) IRQ10Handler);
SetISR(43, (size_t) IRQ11Handler);
SetISR(44, (size_t) IRQ12Handler);
SetISR(45, (size_t) IRQ13Handler);
SetISR(46, (size_t) IRQ14Handler);
SetISR(47, (size_t) IRQ15Handler);
//TODO: ISRs 32 to 256
WriteIDT(IDTData);
}