From 515a11b818e4140845f69bb26a19d270a9e42178 Mon Sep 17 00:00:00 2001 From: Alexey Gavrilov Date: Wed, 10 Apr 2024 12:58:20 +0700 Subject: MSR + IDT + test ISRs --- arch/x86/PrimaryInit.cpp | 264 +++++++++++++++++++++++++++++++++++++++++++-- arch/x86/idt/Idt.cpp | 46 +++++++- arch/x86/idt/Idt.h | 10 ++ arch/x86/io/VGADisplay.cpp | 10 ++ arch/x86/io/VGADisplay.h | 2 + arch/x86/msr/Msr.cpp | 106 ++++++++++++++++++ arch/x86/msr/Msr.h | 58 ++++++++++ include/types.h | 6 ++ kernel/boot.s | 1 - makefile | 2 +- 10 files changed, 492 insertions(+), 13 deletions(-) create mode 100644 arch/x86/msr/Msr.cpp create mode 100644 arch/x86/msr/Msr.h diff --git a/arch/x86/PrimaryInit.cpp b/arch/x86/PrimaryInit.cpp index 5359978..498a22b 100644 --- a/arch/x86/PrimaryInit.cpp +++ b/arch/x86/PrimaryInit.cpp @@ -1,13 +1,170 @@ #include "PrimaryInit.h" #include "idt/Idt.h" +#include "io/VGADisplay.h" -// Function to test idt work. Should remove -void isr() +struct InterruptFrame { - out::display << "The kernel has finished" << '\n'; +#ifdef X86_64 + const uint64 ip; + const uint64 cs; + const uint64 flags; +#else + const uint32 ip; + const uint32 cs; + const uint32 flags; +#endif }; +// Test ISRs define start +__attribute__((interrupt)) void isr0(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "Divide error" << '\n'; +}; + +__attribute__((interrupt)) void isr1(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "Debug exception" << '\n'; +}; + +__attribute__((interrupt)) void isr2(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "NMI interrupt" << '\n'; +}; + +__attribute__((interrupt)) void isr3(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "Breakpoint" << '\n'; +}; + +__attribute__((interrupt)) void isr4(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "Overflow" << '\n'; +}; + +__attribute__((interrupt)) void isr5(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "Bound range exceed" << '\n'; +}; + +__attribute__((interrupt)) void isr6(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "Invalid opcode" << '\n'; +}; + +__attribute__((interrupt)) void isr7(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "No math coprocessor" << '\n'; +}; + +__attribute__((interrupt)) void isr8(struct InterruptFrame *frame, uword errorCode) +{ + asm("cli\n\t"); + out::display << "Double fault" << '\n'; +}; + +__attribute__((interrupt)) void isr10(struct InterruptFrame *frame, uword errorCode) +{ + asm("cli\n\t"); + out::display << "Invalid TSS" << "\n"; +}; + +__attribute__((interrupt)) void isr11(struct InterruptFrame *frame, uword errorCode) +{ + asm("cli\n\t"); + out::display << "Segment not present" << "\n"; +}; + +__attribute__((interrupt)) void isr12(struct InterruptFrame *frame, uword errorCode) +{ + asm("cli\n\t"); + out::display << "Stack segment fault" << "\n"; +}; + +__attribute__((interrupt)) void isr13(struct InterruptFrame *frame, uword errorCode) +{ + asm("cli\n\t"); + out::display << "#GP" << "\n"; +}; + +__attribute__((interrupt)) void isr14(struct InterruptFrame *frame, uword errorCode) +{ + asm("cli\n\t"); + out::display << "Page fault" << "\n"; +}; + +__attribute__((interrupt)) void isr16(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "Math fault" << "\n"; +}; + +__attribute__((interrupt)) void isr17(struct InterruptFrame *frame, uword errorCode) +{ + asm("cli\n\t"); + out::display << "Alignment check" << "\n"; +}; + +__attribute__((interrupt)) void isr18(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "Machine check" << "\n"; +}; + +__attribute__((interrupt)) void isr19(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "SIMD point exception" << "\n"; +}; + +__attribute__((interrupt)) void isr20(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "Virtualization exception" << "\n"; +}; + +__attribute__((interrupt)) void isr21(struct InterruptFrame *frame, uword errorCode) +{ + asm("cli\n\t"); + out::display << "Control protection exception" << "\n"; +}; + +__attribute__((interrupt)) void isrUser(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "User-defined interrupt" << "\n"; +}; + +__attribute__((interrupt)) void isrKeyboard(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "KINT "; + uint8 buff[2]; + + // PIC write EOI + asm("in $0x60, %al"); + asm("mov %%al, %0" : "=r"(buff[0])); + asm("in $0x64, %al"); + asm("mov %%al, %0" : "=r"(buff[1])); + asm("mov $0x20, %al\n\t"); + asm("outb %al, $0x20\n\t"); + out::display << (uint32)buff[0] << ' ' << (uint32)buff[1] << '\n'; +}; +__attribute__((interrupt)) void isrTimer(struct InterruptFrame *frame) +{ + asm("cli\n\t"); + out::display << "Timer interrupt" << "\n"; +}; +//Test ISRs define end ------------------- + void PrimaryInitialization::processorInitialize() { MngIdt &mngIdt = MngIdt::getInstance(); @@ -17,12 +174,103 @@ void PrimaryInitialization::processorInitialize() mngGdt.addDescriptor(DescSeg32::flatDataKernel()); mngGdt.loadGdt(); - mngIdt.setDescriptor( - DescInterrupt32::InterruptKernelLong( - (uint32)isr, - mngGdt.getCodeSegmentKernel()), - 0x20); +// Filling IDT start !!!REWRITE!! + DescInterrupt32 descInt = DescInterrupt32::TrapKernelLong + ( + (uint32)isr0, + mngGdt.getCodeSegmentKernel() + ); + // Int 0 + mngIdt.addDescriptor(descInt); + + // Int 1 + descInt.setOffset((uint32)isr1); + mngIdt.addDescriptor(descInt); + + // Int 2 + descInt.setOffset((uint32)isr2); + mngIdt.addDescriptor(descInt); + + // Int 3 + descInt.setOffset((uint32)isr3); + mngIdt.addDescriptor(descInt); + + // Int 4 + descInt.setOffset((uint32)isr4); + mngIdt.addDescriptor(descInt); + + // Int 5 + descInt.setOffset((uint32)isr5); + mngIdt.addDescriptor(descInt); + + // Int 6 + descInt.setOffset((uint32)isr6); + mngIdt.addDescriptor(descInt); + + // Int 7 + descInt.setOffset((uint32)isr7); + mngIdt.addDescriptor(descInt); + + // Int 8 + descInt.setOffset((uint32)isr8); + mngIdt.addDescriptor(descInt); + + // Int 10 + descInt.setOffset((uint32)isr10); + mngIdt.addDescriptor(descInt); + + // Int 11 + descInt.setOffset((uint32)isr11); + mngIdt.addDescriptor(descInt); + + // Int 12 + descInt.setOffset((uint32)isr12); + mngIdt.addDescriptor(descInt); + + // Int 13 + descInt.setOffset((uint32)isr13); + mngIdt.addDescriptor(descInt); + + // Int 14 + descInt.setOffset((uint32)isr14); + mngIdt.addDescriptor(descInt); + + // Int 16 + descInt.setOffset((uint32)isr16); + mngIdt.addDescriptor(descInt); + + // Int 17 + descInt.setOffset((uint32)isr17); + mngIdt.addDescriptor(descInt); + + // Int 18 + descInt.setOffset((uint32)isr18); + mngIdt.addDescriptor(descInt); + + // Int 19 + descInt.setOffset((uint32)isr19); + mngIdt.addDescriptor(descInt); + + // Int 20 + descInt.setOffset((uint32)isr20); + mngIdt.addDescriptor(descInt); + + // Int 21 + descInt.setOffset((uint32)isr21); + mngIdt.addDescriptor(descInt); + + // Int 32 + descInt.setOffset((uint32)isrTimer); + mngIdt.setDescriptor(descInt, 32); + + // Int 33 + descInt.setOffset((uint32)isrKeyboard); + mngIdt.setDescriptor(descInt, 33); +//Filling IDT end ------------------------------ + mngIdt.loadIdt(); + +//------------ }; void PrimaryInitialization::devicesInitialize() diff --git a/arch/x86/idt/Idt.cpp b/arch/x86/idt/Idt.cpp index d489f0e..cd263fb 100644 --- a/arch/x86/idt/Idt.cpp +++ b/arch/x86/idt/Idt.cpp @@ -69,6 +69,15 @@ DescInterrupt32 DescInterrupt32::TaskKernel(uint16 selector) ); }; +bool MngIdt::isIntReserved(uint8 interrupt) +{ + for(uint8 indx = 0; indx < reservedIntSize; indx++) + { + if(reservedInts[indx] == interrupt) return true; + } + return false; +}; + MngIdt::MngIdt() { if(!isInitialize) @@ -88,9 +97,10 @@ bool MngIdt::canDescriptorWrite(uint8 idx) bool MngIdt::addDescriptor(DescInterrupt32 desc) { - if(!canDescriptorWrite(currIdx)) return false; + if(!canDescriptorWrite(currIdx) or isIntReserved(currIdx)) return false; - idt[currIdx++] = desc.getDescriptor(); + idt[currIdx] = desc.getDescriptor(); + while(isIntReserved(++currIdx)); return true; }; @@ -108,7 +118,7 @@ bool MngIdt::loadIdt() //Set descriptor uint64 descriptor = 0; - uint16 size = sizeof(uint64) * size - 1; + uint16 size = sizeof(uint64) * this->size - 1; uint32 offset = (uint32)(&idt); descriptor |= offset; @@ -128,3 +138,33 @@ MngIdt &MngIdt::getInstance() if(!isInitialize) mngIdt = MngIdt(); return mngIdt; }; + +void DescInterrupt32::setOffset(uint32 offset) +{ + uint8 gateType = attributes & 0x0f; + + if(!(gateType == TSK_GATE and offset != 0)) + { + offsetLow = offset & 0xffff; + offsetHight = (offset & 0xffff0000) >> 16; + } +}; +void DescInterrupt32::setGateType(uint8 gateType) +{ + if(gateType < TSK_GATE + or (gateType > TRAP_GATE_16 and gateType < INT_GATE_32) + or gateType > TRAP_GATE_32 + ) return; + else if(gateType == TSK_GATE) + { + offsetLow = offsetHight = 0; + } + + attributes &= 0xfff0; + attributes |= (gateType & 0x0f); +}; + +void DescInterrupt32::setDpl(uint8 dpl) +{ + attributes = (dpl & 0x03) << 5; +}; diff --git a/arch/x86/idt/Idt.h b/arch/x86/idt/Idt.h index c90b674..7370526 100644 --- a/arch/x86/idt/Idt.h +++ b/arch/x86/idt/Idt.h @@ -32,6 +32,9 @@ class DescInterrupt32 DescInterrupt32() = default; DescInterrupt32(const DescInterrupt32 &) = default; DescInterrupt32(uint32 offset, uint16 selector, uint8 attr); + void setOffset(uint32 offset); + void setGateType(uint8 gateType); + void setDpl(uint8 dpl); uint64 getDescriptor(); static DescInterrupt32 InterruptKernelLong(uint32 offset, uint16 selector); @@ -43,6 +46,13 @@ class DescInterrupt32 class MngIdt { private: + const static uint8 reservedIntSize = 12; + constexpr static uint8 reservedInts[reservedIntSize] = + { + 9, 15, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 + }; + // If false interrupt number isn't reserved, true - reserved + bool isIntReserved(uint8 interrupt); const static uint8 size = 255; static uint64 idt[size]; static bool isInitialize; diff --git a/arch/x86/io/VGADisplay.cpp b/arch/x86/io/VGADisplay.cpp index ceb4862..5075351 100644 --- a/arch/x86/io/VGADisplay.cpp +++ b/arch/x86/io/VGADisplay.cpp @@ -1,4 +1,5 @@ #include "VGADisplay.h" +#include "VGADisplayInfo.h" VGADisplay out::display; @@ -137,3 +138,12 @@ bool VGADisplay::printChar(const char &c) } } }; + +void VGADisplay::clearScreen() +{ + xCurr = yCurr = 0; + videoMem = (dchar *)VGADisplayInfo::videoMemAddr; + uint16 maxPos = VGADisplayInfo::height * VGADisplayInfo::width * 2; + + for(uint16 pos = 0; pos < maxPos; pos++) *this << ' '; +}; diff --git a/arch/x86/io/VGADisplay.h b/arch/x86/io/VGADisplay.h index 326ae95..98c2250 100644 --- a/arch/x86/io/VGADisplay.h +++ b/arch/x86/io/VGADisplay.h @@ -35,6 +35,8 @@ class VGADisplay void setColor(char colorAttr); void setBlink(bool blinkAttr); void setBright(bool brigthAttr); + // Rewrite + void clearScreen(); }; // Global variables diff --git a/arch/x86/msr/Msr.cpp b/arch/x86/msr/Msr.cpp new file mode 100644 index 0000000..6d21b54 --- /dev/null +++ b/arch/x86/msr/Msr.cpp @@ -0,0 +1,106 @@ +#include "Msr.h" + +Msr::Msr() +{ + Cpuinfo cpuinfo; + cpuinfo.cpuid(Cpuinfo::VersionInfo); + + msrSupport = cpuinfo.getRegs().edx & Cpuinfo::MSR; +}; + +bool Msr::rdmsr(MsrCommand *cmd) +{ + if(!msrSupport or cmd == nullptr) return true; + + uint64 rdmsrResult = 0; + uint32 regs[2]; + asm( + "mov %2, %%ecx\n\t" + "rdmsr\n\t" + "mov %%eax, %0\n\t" + "mov %%edx, %1\n\t" + : "=&r"(regs[0]), "=&r"(regs[1]) + : "r"(cmd->getCommand())); + + MemoryOperations::copy(regs, &rdmsrResult, sizeof(uint64)); + cmd->decode(rdmsrResult); + + return false; +}; + +bool Msr::wrmsr(MsrCommand *cmd) +{ + if(!msrSupport or cmd == nullptr) return true; + + uint32 regs[2]; + uint64 msr = cmd->getMsr(); + + MemoryOperations::copy(&msr, regs, sizeof(uint64)); + + asm( + "mov %0, %%eax\n\t" + "mov %1, %%edx\n\t" + "mov %2, %%ecx\n\t" + "wrmsr\n\t" + : "=r"(regs[0]), "=r"(regs[1]) + : "r"(cmd->getCommand())); + + return false; +}; + +Ia32ApicBase::Ia32ApicBase() +{ + Cpuinfo cpuinfo; + bool cpuidAddrSzNotSupport = cpuinfo.cpuid(Cpuinfo::AddressSize); + cpuidOutputRegisters AddrSzRegs = cpuinfo.getRegs(); + + cpuinfo.cpuid(Cpuinfo::VersionInfo); + if(cpuinfo.getRegs().edx & Cpuinfo::PAE + and cpuidAddrSzNotSupport) maxPhyAddr = 36; + else if(cpuidAddrSzNotSupport) maxPhyAddr = 32; + else if(!cpuidAddrSzNotSupport) maxPhyAddr = (uint8)AddrSzRegs.edx; + + bspFlag = enableFlag = false; + baseField = NULL; +}; + +uint32 Ia32ApicBase::getCommand() +{ + return 0x1b; +}; + +void Ia32ApicBase::decode(uint64 rdmsrResult) +{ + bspFlag = rdmsrResult & BSP_FLAG; + enableFlag = rdmsrResult & APIC_ENABLE_FLAG; + setBaseField(rdmsrResult); +}; + +uint64 Ia32ApicBase::getMsr() +{ + uint64 msr = 0; + + MemoryOperations::copy(&baseField, &msr, sizeof(uint64)); + msr |= bspFlag << 8; + msr |= enableFlag << 11; + + return msr; +}; + +void Ia32ApicBase::setBaseField(uint64 fieldAddr) +{ + uint64 mask = BASE_FIELD_MASK_LOW | + ((UINT64_HIGH<< (maxPhyAddr - 32)) ^ UINT64_HIGH); + + baseField = fieldAddr & mask; +}; + +void Ia32ApicBase::setBspFlag(bool flag) +{ + bspFlag = flag; +}; + +void Ia32ApicBase::setEnableFlag(bool flag) +{ + enableFlag = flag; +}; diff --git a/arch/x86/msr/Msr.h b/arch/x86/msr/Msr.h new file mode 100644 index 0000000..98c1b02 --- /dev/null +++ b/arch/x86/msr/Msr.h @@ -0,0 +1,58 @@ +// Tasks: +// 1) Implement msr write and save functions +// 2) Ia32ApicBase field + +#include "../cpuinfo/Cpuinfo.h" +#include + +#ifndef MSR_H +#define MSR_H + +// defines for Ia32ApicBase + +#define BSP_FLAG 0x100 +#define APIC_ENABLE_FLAG 0x800 +#define BASE_FIELD_MASK_LOW 0xfffff000 +#define UINT64_HIGH 0xffffffff00000000 + +//------------------------ + +class MsrCommand +{ + public: + virtual uint32 getCommand() = 0; + virtual void decode(uint64 rdmsrResult) = 0; + virtual uint64 getMsr() = 0; +}; + +class Ia32ApicBase : public MsrCommand +{ + private: + // Get through Cpuinfo instance + uint8 maxPhyAddr; + bool bspFlag, enableFlag; + uint64 baseField; + + public: + Ia32ApicBase(); + virtual uint32 getCommand() override final; + virtual void decode(uint64 rdmrResult) override final; + virtual uint64 getMsr() override final; + void setBspFlag(bool flag); + void setEnableFlag(bool flag); + void setBaseField(uint64 fieldAddr); +}; + +class Msr +{ + private: + bool msrSupport; + public: + Msr(); + // Return true if MSR not supported (CPUID.01H:EDX[5] = 0) + bool rdmsr(MsrCommand *cmd); + // Return value same as rdmsr method + bool wrmsr(MsrCommand *cmd); +}; + +#endif diff --git a/include/types.h b/include/types.h index 9fef833..16f67d9 100644 --- a/include/types.h +++ b/include/types.h @@ -12,6 +12,12 @@ typedef unsigned short int uint16; typedef unsigned long uint32; typedef unsigned long long uint64; +#if defined(__x86_64__) + typedef uint64 uword; +#else + typedef uint32 uword; +#endif + #if defined(__x86_64) || defined(__i686) typedef uint64 uintptr; #else diff --git a/kernel/boot.s b/kernel/boot.s index 710bb7b..798e7e3 100644 --- a/kernel/boot.s +++ b/kernel/boot.s @@ -21,7 +21,6 @@ global _start:function (_start.end - _start) _start: mov esp, stack_top call main - int 0x20 cli .hang: hlt jmp .hang diff --git a/makefile b/makefile index 439c42e..aaf6cc3 100644 --- a/makefile +++ b/makefile @@ -2,7 +2,7 @@ CC = i686-elf-g++ LD = ld ASM = nasm # test -O2 flag -CFLAGS = -c -m32 -Wall -ffreestanding -nostdinc -nostdlib -fno-rtti +CFLAGS = -c -m32 -Wall -ffreestanding -nostdinc -nostdlib -fno-rtti -mgeneral-regs-only AFLAGS = -f elf32 LDFLAGS = -m elf_i386 $(patsubst %,-L%,$(subst :, ,$(LIBS_PATH))) -lgcc QEMUFLAGS = -- cgit v1.2.3 From 0c56a0300b7ffbab787a4c974bc164d9a2a57ad2 Mon Sep 17 00:00:00 2001 From: Alexey Gavrilov Date: Wed, 10 Apr 2024 13:06:48 +0700 Subject: VGADisplay some updates --- arch/x86/io/VGADisplay.cpp | 1 - arch/x86/io/VGADisplay.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/arch/x86/io/VGADisplay.cpp b/arch/x86/io/VGADisplay.cpp index 5075351..7246102 100644 --- a/arch/x86/io/VGADisplay.cpp +++ b/arch/x86/io/VGADisplay.cpp @@ -1,5 +1,4 @@ #include "VGADisplay.h" -#include "VGADisplayInfo.h" VGADisplay out::display; diff --git a/arch/x86/io/VGADisplay.h b/arch/x86/io/VGADisplay.h index 98c2250..562b1ae 100644 --- a/arch/x86/io/VGADisplay.h +++ b/arch/x86/io/VGADisplay.h @@ -35,12 +35,10 @@ class VGADisplay void setColor(char colorAttr); void setBlink(bool blinkAttr); void setBright(bool brigthAttr); - // Rewrite void clearScreen(); }; // Global variables - namespace out { extern VGADisplay display; -- cgit v1.2.3