From bca7ac41b8b54932d044302ea1b6d2ccdf5ff0cd Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 29 Jan 2023 10:54:52 +0100 Subject: [PATCH] Initialize boot CPU structures inside kernel on i686 architecture --- xtoskrnl/ar/i686/globals.c | 9 ++ xtoskrnl/ar/i686/procsup.c | 182 +++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) diff --git a/xtoskrnl/ar/i686/globals.c b/xtoskrnl/ar/i686/globals.c index 0c986b1..963fb5d 100644 --- a/xtoskrnl/ar/i686/globals.c +++ b/xtoskrnl/ar/i686/globals.c @@ -8,3 +8,12 @@ #include "xtos.h" + +/* Initial GDT */ +KGDTENTRY ArInitialGdt[GDT_ENTRIES] = {0}; + +/* Initial IDT */ +KIDTENTRY ArInitialIdt[IDT_ENTRIES] = {0}; + +/* Initial TSS */ +KTSS ArInitialTss; diff --git a/xtoskrnl/ar/i686/procsup.c b/xtoskrnl/ar/i686/procsup.c index e5431be..5e69328 100644 --- a/xtoskrnl/ar/i686/procsup.c +++ b/xtoskrnl/ar/i686/procsup.c @@ -20,4 +20,186 @@ XTAPI VOID ArInitializeProcessor(VOID) { + PKGDTENTRY Gdt; + PKTSS Tss; + KDESCRIPTOR GdtDescriptor; + + /* Use initial structures */ + Gdt = ArInitialGdt; + Tss = &ArInitialTss; + + /* Initialize GDT and TSS */ + ArpInitializeGdt(Gdt); + ArpInitializeTss(Tss, Gdt); + + /* Set GDT descriptor */ + GdtDescriptor.Base = Gdt; + GdtDescriptor.Limit = (GDT_ENTRIES * sizeof(PKGDTENTRY)) - 1; + + /* Load GDT and TSS */ + ArLoadGlobalDescriptorTable(&GdtDescriptor.Limit); + ArLoadTaskRegister((UINT32)KGDT_SYS_TSS); +} + +/** + * Initializes the kernel's Global Descriptor Table (GDT). + * + * @param Gdt + * Supplies a pointer to the GDT to use. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +ArpInitializeGdt(IN PKGDTENTRY Gdt) +{ + /* Initialize GDT entries */ + ArpInitializeGdtEntry(Gdt, KGDT_NULL, 0x0, 0x0, 0, KGDT_DPL_SYSTEM, 0); + ArpInitializeGdtEntry(Gdt, KGDT_R0_CODE, 0x0, 0xFFFFFFFF, KGDT_TYPE_CODE, KGDT_DPL_SYSTEM, 2); + ArpInitializeGdtEntry(Gdt, KGDT_R0_DATA, 0x0, 0xFFFFFFFF, KGDT_TYPE_DATA, KGDT_DPL_SYSTEM, 2); + ArpInitializeGdtEntry(Gdt, KGDT_R3_CODE, 0x0, 0xFFFFFFFF, KGDT_TYPE_CODE, KGDT_DPL_USER, 2); + ArpInitializeGdtEntry(Gdt, KGDT_R3_DATA, 0x0, 0xFFFFFFFF, KGDT_TYPE_DATA, KGDT_DPL_USER, 2); + ArpInitializeGdtEntry(Gdt, KGDT_R3_TEB, 0x0, 0xFFF, KGDT_TYPE_DATA | KGDT_DESCRIPTOR_ACCESSED, KGDT_DPL_USER, 2); + ArpInitializeGdtEntry(Gdt, KGDT_R0_LDT, 0x0, 0x0, 0, KGDT_DPL_SYSTEM, 0); + ArpInitializeGdtEntry(Gdt, KGDT_VDM_TILE, 0x0400, 0xFFFF, KGDT_TYPE_DATA, KGDT_DPL_USER, 0); + ArpInitializeGdtEntry(Gdt, KGDT_R0_PCR, 0x0, 0x1, KGDT_TYPE_DATA, KGDT_DPL_SYSTEM, 2); + ArpInitializeGdtEntry(Gdt, KGDT_SYS_TSS, 0x0, sizeof(KTSS) - 1, I686_TSS, KGDT_DPL_SYSTEM, 0); + ArpInitializeGdtEntry(Gdt, KGDT_DF_TSS, 0x20000, 0xFFFF, I686_TSS, KGDT_DPL_SYSTEM, 0); + ArpInitializeGdtEntry(Gdt, KGDT_NMI_TSS, 0x20000, 0xFFFF, KGDT_TYPE_CODE, KGDT_DPL_SYSTEM, 0); +} + +/** + * Fills in an AMD64 GDT entry. + * + * @param Gdt + * Supplies a pointer to the GDT. + * + * @param Selector + * Specifies a segment selector of the GDT entry. + * + * @param Base + * Specifies a base address value of the descriptor. + * + * @param Limit + * Specifies a descriptor limit. + * + * @param Type + * Specifies a type of the descriptor. + * + * @param Dpl + * Specifies the descriptor privilege level. + * + * @param SegmentMode + * Specifies a segment mode of the descriptor. + * + * @return This routine does not return any value + * + * @since XT 1.0 + */ +XTAPI +VOID +ArpInitializeGdtEntry(IN PKGDTENTRY Gdt, + IN USHORT Selector, + IN ULONGLONG Base, + IN ULONG Limit, + IN UCHAR Type, + IN UCHAR Dpl, + IN UCHAR SegmentMode) +{ + PKGDTENTRY GdtEntry; + UCHAR Granularity; + + /* Set the granularity flag depending on descriptor limit */ + if(Limit < 0x100000) + { + /* Limit is in 1B blocks */ + Granularity = 0; + } + else + { + /* Limit is in 4KB blocks */ + Granularity = 1; + Limit >>= 12; + } + + /* Get GDT entry */ + GdtEntry = (PKGDTENTRY)((ULONG64)Gdt + (Selector & ~RPL_MASK)); + + /* Set GDT descriptor base */ + GdtEntry->BaseLow = Base & 0xFFFF; + GdtEntry->Bits.BaseMiddle = (Base >> 16) & 0xFF; + GdtEntry->Bits.BaseHigh = (Base >> 24) & 0xFF; + + /* Set descriptor limit */ + GdtEntry->LimitLow = Limit & 0xFFFF; + GdtEntry->Bits.LimitHigh = (Limit >> 16) & 0xF; + + /* Initialize GDT entry */ + GdtEntry->Bits.DefaultBig = (SegmentMode & 2); + GdtEntry->Bits.Dpl = (Dpl & 0x3); + GdtEntry->Bits.Granularity = Granularity; + GdtEntry->Bits.Reserved0 = 0; + GdtEntry->Bits.Present = (Type != 0); + GdtEntry->Bits.System = 0; + GdtEntry->Bits.Type = (Type & 0x1F); +} + +/** + * Initializes the kernel's Task State Segment (TSS). + * + * @param Tss + * Supplies a pointer to the TSS to use. + * + * @param Gdt + * Supplies a pointer to the GDT to use. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +ArpInitializeTss(IN PKTSS Tss, + IN PKGDTENTRY Gdt) +{ + PKGDTENTRY TssEntry; + + /* Get TSS entry from GDT */ + TssEntry = (PKGDTENTRY)(&(Gdt[KGDT_SYS_TSS / sizeof(KGDTENTRY)])); + + /* Initialize TSS entry */ + TssEntry->Bits.Dpl = 0; + TssEntry->Bits.Present = 1; + TssEntry->Bits.Type = I686_TSS; + TssEntry->LimitLow = sizeof(KTSS) - 1; + TssEntry->Bits.LimitHigh = 0; + + /* Clear I/O map */ + RtlFillMemory(Tss->IoMaps[0].IoMap, IOPM_FULL_SIZE, 0xFF); + + /* Fill Interrupt Direction Maps with zeroes */ + RtlZeroMemory(Tss->IoMaps[0].DirectionMap, IOPM_DIRECTION_MAP_SIZE); + + /* Enable DPMI support */ + Tss->IoMaps[0].DirectionMap[0] = 4; + Tss->IoMaps[0].DirectionMap[3] = 0x18; + Tss->IoMaps[0].DirectionMap[4] = 0x18; + + /* Fill default Interrupt Direction Map with zeroes */ + RtlZeroMemory(Tss->IntDirectionMap, IOPM_DIRECTION_MAP_SIZE); + + /* Enable DPMI support */ + Tss->IntDirectionMap[0] = 4; + Tss->IntDirectionMap[3] = 0x18; + Tss->IntDirectionMap[4] = 0x18; + + /* Set I/O map base and disable traps */ + Tss->IoMapBase = 0x68; + Tss->Flags = 0; + + /* Set LDT and SS */ + Tss->LDT = KGDT_R0_LDT; + Tss->Ss0 = KGDT_R0_DATA; }