mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-13 16:29:21 +00:00
Add implementation for GDT & IDT on x32 and QoL fixes
This commit is contained in:
@ -22,14 +22,15 @@
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
|
||||
|
||||
namespace ACPI
|
||||
{
|
||||
void *ACPI::FindTable(ACPI::ACPIHeader *ACPIHeader, char *Signature)
|
||||
__no_sanitize("alignment") void *ACPI::FindTable(ACPI::ACPIHeader *ACPIHeader, char *Signature)
|
||||
{
|
||||
for (uint64_t t = 0; t < ((ACPIHeader->Length - sizeof(ACPI::ACPIHeader)) / (XSDTSupported ? 8 : 4)); t++)
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
|
||||
|
||||
// TODO: Should I be concerned about unaligned memory access?
|
||||
ACPI::ACPIHeader *SDTHdr = nullptr;
|
||||
if (XSDTSupported)
|
||||
@ -37,6 +38,8 @@ namespace ACPI
|
||||
else
|
||||
SDTHdr = (ACPI::ACPIHeader *)(*(uint32_t *)((uint64_t)ACPIHeader + sizeof(ACPI::ACPIHeader) + (t * 4)));
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (SDTHdr->Signature[i] != Signature[i])
|
||||
|
@ -27,17 +27,18 @@ namespace GlobalDescriptorTable
|
||||
static GlobalDescriptorTableEntries GDTEntriesTemplate = {
|
||||
.Null =
|
||||
{
|
||||
.Length = 0x0,
|
||||
.Limit0 = 0x0,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {.Raw = 0x0},
|
||||
// .Limit1 = 0x0,
|
||||
.Flags = {.Raw = 0x0},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.Code =
|
||||
{
|
||||
.Length = 0x0,
|
||||
.Limit0 = 0xFFFF,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {
|
||||
@ -49,15 +50,20 @@ namespace GlobalDescriptorTable
|
||||
.DPL = 0,
|
||||
.P = 1,
|
||||
},
|
||||
// .Limit1 = 0xF,
|
||||
.Flags = {
|
||||
.Unknown = 0x0,
|
||||
.Reserved = 0xF, /* Workaround for Limit1 */
|
||||
|
||||
.AVL = 0,
|
||||
.L = 1,
|
||||
.DB = 0,
|
||||
.G = 1,
|
||||
},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.Data = {
|
||||
.Length = 0x0,
|
||||
.Limit0 = 0xFFFF,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {
|
||||
@ -69,12 +75,20 @@ namespace GlobalDescriptorTable
|
||||
.DPL = 0,
|
||||
.P = 1,
|
||||
},
|
||||
.Flags = {.Raw = 0x0},
|
||||
// .Limit1 = 0xF,
|
||||
.Flags = {
|
||||
.Reserved = 0xF, /* Workaround for Limit1 */
|
||||
|
||||
.AVL = 0,
|
||||
.L = 0,
|
||||
.DB = 1,
|
||||
.G = 1,
|
||||
},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.UserData = {
|
||||
.Length = 0x0,
|
||||
.Limit0 = 0xFFFF,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {
|
||||
@ -86,14 +100,20 @@ namespace GlobalDescriptorTable
|
||||
.DPL = 3,
|
||||
.P = 1,
|
||||
},
|
||||
// .Limit1 = 0xF,
|
||||
.Flags = {
|
||||
.Raw = 0x0,
|
||||
.Reserved = 0xF, /* Workaround for Limit1 */
|
||||
|
||||
.AVL = 0,
|
||||
.L = 0,
|
||||
.DB = 1,
|
||||
.G = 1,
|
||||
},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.UserCode = {
|
||||
.Length = 0x0,
|
||||
.Limit0 = 0xFFFF,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {
|
||||
@ -105,9 +125,14 @@ namespace GlobalDescriptorTable
|
||||
.DPL = 3,
|
||||
.P = 1,
|
||||
},
|
||||
// .Limit1 = 0xF,
|
||||
.Flags = {
|
||||
.Unknown = 0x0,
|
||||
.Reserved = 0xF, /* Workaround for Limit1 */
|
||||
|
||||
.AVL = 0,
|
||||
.L = 1,
|
||||
.DB = 0,
|
||||
.G = 1,
|
||||
},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
@ -135,10 +160,47 @@ namespace GlobalDescriptorTable
|
||||
memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries));
|
||||
gdt[Core] = {.Length = sizeof(GlobalDescriptorTableEntries) - 1, .Entries = &GDTEntries[Core]};
|
||||
|
||||
debug("Kernel: Code Access: %ld; Data Access: %ld", GDTEntries[Core].Code.Access.Raw, GDTEntries[Core].Data.Access.Raw);
|
||||
debug("Kernel: Code Flags: %ld; Data Flags: %ld", GDTEntries[Core].Code.Flags.Raw, GDTEntries[Core].Data.Flags.Raw);
|
||||
debug("User: Code Access: %ld; Data Access: %ld", GDTEntries[Core].UserCode.Access.Raw, GDTEntries[Core].UserData.Access.Raw);
|
||||
debug("User: Code Flags: %ld; Data Flags: %ld", GDTEntries[Core].UserCode.Flags.Raw, GDTEntries[Core].UserData.Flags.Raw);
|
||||
debug("GDT: %#lx", &gdt[Core]);
|
||||
debug("GDT KERNEL: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
|
||||
GDT_KERNEL_CODE,
|
||||
GDTEntries[Core].Code.Limit0,
|
||||
GDTEntries[Core].Code.BaseLow,
|
||||
GDTEntries[Core].Code.BaseMiddle,
|
||||
GDTEntries[Core].Code.Access.Raw,
|
||||
GDTEntries[Core].Code.Flags.Reserved,
|
||||
GDTEntries[Core].Code.Flags.Raw & ~0xF,
|
||||
GDTEntries[Core].Code.BaseHigh);
|
||||
|
||||
debug("GDT KERNEL: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
|
||||
GDT_KERNEL_DATA,
|
||||
GDTEntries[Core].Data.Limit0,
|
||||
GDTEntries[Core].Data.BaseLow,
|
||||
GDTEntries[Core].Data.BaseMiddle,
|
||||
GDTEntries[Core].Data.Access.Raw,
|
||||
GDTEntries[Core].Data.Flags.Reserved,
|
||||
GDTEntries[Core].Data.Flags.Raw & ~0xF,
|
||||
GDTEntries[Core].Data.BaseHigh);
|
||||
|
||||
debug("GDT USER: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
|
||||
GDT_USER_CODE,
|
||||
GDTEntries[Core].UserCode.Limit0,
|
||||
GDTEntries[Core].UserCode.BaseLow,
|
||||
GDTEntries[Core].UserCode.BaseMiddle,
|
||||
GDTEntries[Core].UserCode.Access.Raw,
|
||||
GDTEntries[Core].UserCode.Flags.Reserved,
|
||||
GDTEntries[Core].UserCode.Flags.Raw & ~0xF,
|
||||
GDTEntries[Core].UserCode.BaseHigh);
|
||||
|
||||
debug("GDT USER: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
|
||||
GDT_USER_DATA,
|
||||
GDTEntries[Core].UserData.Limit0,
|
||||
GDTEntries[Core].UserData.BaseLow,
|
||||
GDTEntries[Core].UserData.BaseMiddle,
|
||||
GDTEntries[Core].UserData.Access.Raw,
|
||||
GDTEntries[Core].UserData.Flags.Reserved,
|
||||
GDTEntries[Core].UserData.Flags.Raw & ~0xF,
|
||||
GDTEntries[Core].UserData.BaseHigh);
|
||||
|
||||
CPU::x64::lgdt(&gdt[Core]);
|
||||
|
||||
asmv("movq %%rsp, %%rax\n"
|
||||
@ -162,16 +224,18 @@ namespace GlobalDescriptorTable
|
||||
|
||||
uintptr_t Base = (uintptr_t)&tss[Core];
|
||||
size_t Limit = Base + sizeof(TaskStateSegment);
|
||||
gdt[Core].Entries->TaskStateSegment.Length = Limit & 0xFFFF;
|
||||
gdt[Core].Entries->TaskStateSegment.Limit = Limit & 0xFFFF;
|
||||
gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF;
|
||||
gdt[Core].Entries->TaskStateSegment.BaseMiddle = (Base >> 16) & 0xFF;
|
||||
gdt[Core].Entries->TaskStateSegment.BaseHigh = (Base >> 24) & 0xFF;
|
||||
gdt[Core].Entries->TaskStateSegment.BaseUpper = s_cst(uint32_t, (Base >> 32) & 0xFFFFFFFF);
|
||||
gdt[Core].Entries->TaskStateSegment.Flags = {.A = 1, .RW = 0, .DC = 0, .E = 1, .S = 0, .DPL = 0, .P = 1};
|
||||
gdt[Core].Entries->TaskStateSegment.Access = {.A = 1, .RW = 0, .DC = 0, .E = 1, .S = 0, .DPL = 0, .P = 1};
|
||||
gdt[Core].Entries->TaskStateSegment.Granularity = (0 << 4) | ((Limit >> 16) & 0xF);
|
||||
|
||||
tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
|
||||
tss[Core].StackPointer[0] = (uint64_t)CPUStackPointer[Core] + STACK_SIZE;
|
||||
tss[Core].StackPointer[1] = 0x0;
|
||||
tss[Core].StackPointer[2] = 0x0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(tss[Core].InterruptStackTable) / sizeof(tss[Core].InterruptStackTable[7]); i++)
|
||||
{
|
||||
@ -183,12 +247,6 @@ namespace GlobalDescriptorTable
|
||||
}
|
||||
|
||||
CPU::x64::ltr(GDT_TSS);
|
||||
|
||||
debug("GDT_KERNEL_CODE: %#lx", GDT_KERNEL_CODE);
|
||||
debug("GDT_KERNEL_DATA: %#lx", GDT_KERNEL_DATA);
|
||||
debug("GDT_USER_CODE: %#lx", GDT_USER_CODE);
|
||||
debug("GDT_USER_DATA: %#lx", GDT_USER_DATA);
|
||||
debug("GDT_TSS: %#lx", GDT_TSS);
|
||||
debug("Global Descriptor Table initialized");
|
||||
}
|
||||
|
||||
|
@ -22,88 +22,66 @@
|
||||
|
||||
namespace GlobalDescriptorTable
|
||||
{
|
||||
/** @brief The GDT Access Table
|
||||
* @details For more information, see https://wiki.osdev.org/Global_Descriptor_Table
|
||||
*/
|
||||
union GlobalDescriptorTableAccess
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Access bit.
|
||||
* @note The CPU sets this bit to 1 when the segment is accessed.
|
||||
*/
|
||||
uint64_t A : 1;
|
||||
|
||||
/** @brief Readable bit for code segments, writable bit for data segments.
|
||||
* @details For code segments, this bit must be 1 for the segment to be readable.
|
||||
* @details For data segments, this bit must be 1 for the segment to be writable.
|
||||
*/
|
||||
uint64_t RW : 1;
|
||||
|
||||
/** @brief Direction bit for data segments, conforming bit for code segments.
|
||||
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
|
||||
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
|
||||
*/
|
||||
uint64_t DC : 1;
|
||||
|
||||
/** @brief Executable bit.
|
||||
* @details This bit must be 1 for code-segment descriptors.
|
||||
* @details This bit must be 0 for data-segment and system descriptors.
|
||||
*/
|
||||
uint64_t E : 1;
|
||||
|
||||
/** @brief Descriptor type.
|
||||
* @details This bit must be 0 for system descriptors.
|
||||
* @details This bit must be 1 for code or data segment descriptor.
|
||||
*/
|
||||
uint64_t S : 1;
|
||||
|
||||
/** @brief Descriptor privilege level.
|
||||
* @details This field determines the privilege level of the segment.
|
||||
* @details 0 = kernel mode, 3 = user mode.
|
||||
*/
|
||||
uint64_t DPL : 2;
|
||||
|
||||
/** @brief Present bit.
|
||||
* @details This bit must be 1 for all valid descriptors.
|
||||
*/
|
||||
uint64_t P : 1;
|
||||
} __packed;
|
||||
uint8_t Raw;
|
||||
};
|
||||
|
||||
union GlobalDescriptorTableFlags
|
||||
{
|
||||
// TODO: Add more flags.
|
||||
struct
|
||||
{
|
||||
/** @brief Unknown. */
|
||||
uint64_t Unknown : 5;
|
||||
|
||||
/** @brief Long mode.
|
||||
* @details If the long mode bit is clear, the segment is in 32-bit protected mode.
|
||||
* @details If the long mode bit is set, the segment is in 64-bit long mode.
|
||||
*/
|
||||
uint64_t L : 1;
|
||||
} __packed;
|
||||
uint8_t Raw;
|
||||
};
|
||||
|
||||
typedef struct _TaskStateSegmentEntry
|
||||
struct TaskStateSegmentEntry
|
||||
{
|
||||
/* LOW */
|
||||
uint16_t Length;
|
||||
uint16_t Limit;
|
||||
uint16_t BaseLow;
|
||||
uint8_t BaseMiddle;
|
||||
GlobalDescriptorTableAccess Flags;
|
||||
union GlobalDescriptorTableAccess
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Access bit.
|
||||
* @note The CPU sets this bit to 1 when the segment is accessed.
|
||||
*/
|
||||
uint8_t A : 1;
|
||||
|
||||
/** @brief Readable bit for code segments, writable bit for data segments.
|
||||
* @details For code segments, this bit must be 1 for the segment to be readable.
|
||||
* @details For data segments, this bit must be 1 for the segment to be writable.
|
||||
*/
|
||||
uint8_t RW : 1;
|
||||
|
||||
/** @brief Direction bit for data segments, conforming bit for code segments.
|
||||
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
|
||||
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
|
||||
*/
|
||||
uint8_t DC : 1;
|
||||
|
||||
/** @brief Executable bit.
|
||||
* @details This bit must be 1 for code-segment descriptors.
|
||||
* @details This bit must be 0 for data-segment and system descriptors.
|
||||
*/
|
||||
uint8_t E : 1;
|
||||
|
||||
/** @brief Descriptor type.
|
||||
* @details This bit must be 0 for system descriptors.
|
||||
* @details This bit must be 1 for code or data segment descriptor.
|
||||
*/
|
||||
uint8_t S : 1;
|
||||
|
||||
/** @brief Descriptor privilege level.
|
||||
* @details This field determines the privilege level of the segment.
|
||||
* @details 0 = kernel mode, 3 = user mode.
|
||||
*/
|
||||
uint8_t DPL : 2;
|
||||
|
||||
/** @brief Present bit.
|
||||
* @details This bit must be 1 for all valid descriptors.
|
||||
*/
|
||||
uint8_t P : 1;
|
||||
} __packed;
|
||||
uint8_t Raw : 8;
|
||||
} Access;
|
||||
uint8_t Granularity;
|
||||
uint8_t BaseHigh;
|
||||
/* HIGH */
|
||||
uint32_t BaseUpper;
|
||||
uint32_t Reserved;
|
||||
} __packed TaskStateSegmentEntry;
|
||||
} __packed;
|
||||
|
||||
typedef struct _TaskStateSegment
|
||||
struct TaskStateSegment
|
||||
{
|
||||
uint32_t Reserved0 __aligned(16);
|
||||
uint64_t StackPointer[3];
|
||||
@ -112,25 +90,107 @@ namespace GlobalDescriptorTable
|
||||
uint64_t Reserved2;
|
||||
uint16_t Reserved3;
|
||||
uint16_t IOMapBaseAddressOffset;
|
||||
} __packed TaskStateSegment;
|
||||
} __packed;
|
||||
|
||||
typedef struct _GlobalDescriptorTableEntry
|
||||
struct GlobalDescriptorTableEntry
|
||||
{
|
||||
/** @brief Length */
|
||||
uint16_t Length;
|
||||
/** @brief Low Base */
|
||||
uint16_t BaseLow;
|
||||
/** @brief Middle Base */
|
||||
uint8_t BaseMiddle;
|
||||
/** @brief Access */
|
||||
GlobalDescriptorTableAccess Access;
|
||||
/** @brief Flags */
|
||||
GlobalDescriptorTableFlags Flags;
|
||||
/** @brief High Base */
|
||||
uint8_t BaseHigh;
|
||||
} __packed GlobalDescriptorTableEntry;
|
||||
/** @brief Limit 0:15 */
|
||||
uint16_t Limit0 : 16;
|
||||
|
||||
typedef struct _GlobalDescriptorTableEntries
|
||||
/** @brief Low Base 0:15 */
|
||||
uint16_t BaseLow : 16;
|
||||
|
||||
/** @brief Middle Base 16:23 */
|
||||
uint8_t BaseMiddle : 8;
|
||||
|
||||
/** @brief Access */
|
||||
union GlobalDescriptorTableAccess
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Access bit.
|
||||
* @note The CPU sets this bit to 1 when the segment is accessed.
|
||||
*/
|
||||
uint8_t A : 1;
|
||||
|
||||
/** @brief Readable bit for code segments, writable bit for data segments.
|
||||
* @details For code segments, this bit must be 1 for the segment to be readable.
|
||||
* @details For data segments, this bit must be 1 for the segment to be writable.
|
||||
*/
|
||||
uint8_t RW : 1;
|
||||
|
||||
/** @brief Direction bit for data segments, conforming bit for code segments.
|
||||
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
|
||||
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
|
||||
*/
|
||||
uint8_t DC : 1;
|
||||
|
||||
/** @brief Executable bit.
|
||||
* @details This bit must be 1 for code-segment descriptors.
|
||||
* @details This bit must be 0 for data-segment and system descriptors.
|
||||
*/
|
||||
uint8_t E : 1;
|
||||
|
||||
/** @brief Descriptor type.
|
||||
* @details This bit must be 0 for system descriptors.
|
||||
* @details This bit must be 1 for code or data segment descriptor.
|
||||
*/
|
||||
uint8_t S : 1;
|
||||
|
||||
/** @brief Descriptor privilege level.
|
||||
* @details This field determines the privilege level of the segment.
|
||||
* @details 0 = kernel mode, 3 = user mode.
|
||||
*/
|
||||
uint8_t DPL : 2;
|
||||
|
||||
/** @brief Present bit.
|
||||
* @details This bit must be 1 for all valid descriptors.
|
||||
*/
|
||||
uint8_t P : 1;
|
||||
} __packed;
|
||||
uint8_t Raw : 8;
|
||||
} Access;
|
||||
|
||||
// /** @brief Limit 16:19 */
|
||||
// uint16_t Limit1 : 4;
|
||||
|
||||
/** @brief Flags */
|
||||
union GlobalDescriptorTableFlags
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t Reserved : 4; /* FIXME: Without this, the kernel crashes. */
|
||||
/** @brief Available bit.
|
||||
* @details This bit is available for use by system software.
|
||||
*/
|
||||
uint8_t AVL : 1;
|
||||
|
||||
/** @brief Long mode.
|
||||
* @details If the long mode bit is clear, the segment is in 32-bit protected mode.
|
||||
* @details If the long mode bit is set, the segment is in 64-bit long mode.
|
||||
*/
|
||||
uint8_t L : 1;
|
||||
|
||||
/** @brief Size flag.
|
||||
* @details If the size bit is clear, the segment is in 16-bit protected mode.
|
||||
* @details If the size bit is set, the segment is in 32-bit protected mode.
|
||||
*/
|
||||
uint8_t DB : 1;
|
||||
|
||||
/** @brief Granularity bit.
|
||||
* @details If the granularity bit is clear, the segment limit is in 1 B blocks.
|
||||
* @details If the granularity bit is set, the segment limit is in 4 KiB blocks.
|
||||
*/
|
||||
uint8_t G : 1;
|
||||
} __packed;
|
||||
uint8_t Raw : 8;
|
||||
} Flags;
|
||||
|
||||
/** @brief High Base 24:31 */
|
||||
uint8_t BaseHigh : 8;
|
||||
} __packed;
|
||||
|
||||
struct GlobalDescriptorTableEntries
|
||||
{
|
||||
GlobalDescriptorTableEntry Null;
|
||||
GlobalDescriptorTableEntry Code;
|
||||
@ -138,15 +198,15 @@ namespace GlobalDescriptorTable
|
||||
GlobalDescriptorTableEntry UserData;
|
||||
GlobalDescriptorTableEntry UserCode;
|
||||
TaskStateSegmentEntry TaskStateSegment;
|
||||
} __packed GlobalDescriptorTableEntries;
|
||||
} __packed;
|
||||
|
||||
typedef struct _GlobalDescriptorTableDescriptor
|
||||
struct GlobalDescriptorTableDescriptor
|
||||
{
|
||||
/** @brief GDT entries length */
|
||||
uint16_t Length;
|
||||
/** @brief GDT entries address */
|
||||
GlobalDescriptorTableEntries *Entries;
|
||||
} __packed GlobalDescriptorTableDescriptor;
|
||||
} __packed;
|
||||
|
||||
extern void *CPUStackPointer[];
|
||||
extern TaskStateSegment tss[];
|
||||
|
Reference in New Issue
Block a user