Code: Select all
struct gdt_entry
{// 128-Bit
uint16_t limit_low; // Lower 16 bits of the segment limit
uint16_t base_low; // Lower 16 bits of the base address
uint8_t base_middle; // Next 8 bits of the base address
uint8_t access; // Access byte
uint8_t granularity; // Flags and upper limit
uint8_t base_high; // Next 8 bits of the base address
uint32_t base_upper; // Upper 32 bits of the base address (for 64-bit TSS)
uint32_t reserved; // Reserved, must be zero
}__attribute__((packed, aligned(16)));
typedef struct gdt_entry gdt_entry_t;
Code: Select all
// Structure for GDTR
struct gdtr {
uint16_t limit;
uint64_t base; // Use uint64_t for 64-bit systems
} __attribute__((packed));
typedef struct gdtr gdtr_t;
Code: Select all
struct tss_entry{ // 576 bit
uint32_t reserved0;
uint64_t rsp0; // Ring 0 Stack Pointer
uint64_t rsp1;
uint64_t rsp2;
uint64_t reserved1;
uint64_t ist1; // Interrupt Stack Table (optional)
uint64_t ist2;
uint64_t ist3;
uint64_t reserved2;
uint16_t reserved3;
uint16_t iopb_offset;
} __attribute__((packed, aligned(16)));
typedef struct tss_entry tss_entry_t;
Code: Select all
#define STACK_SIZE 0x4000 // 16 KB
#define GDT_ENTRIES_COUNT 6
extern void gdt_flush(gdtr_t *gdtr_instance);
extern void tss_flush(uint16_t selector);
gdt_entry_t gdt_entries_bootstrap[GDT_ENTRIES_COUNT]; // GDT entries
gdtr_t gdtr_bootstrap; // Global Descriptor Table Register
tss_entry_t tss_entry_bootstrap;
// Setup GDT entry
void gdt_setup_bootstrap(uint8_t idx, uint64_t base, uint32_t limit, uint8_t access, uint8_t granularity) {
gdt_entries_bootstrap[idx].limit_low = limit & 0xFFFF; // Lower 16 bits of limit
gdt_entries_bootstrap[idx].base_low = base & 0xFFFF; // Lower 16 bits of base
gdt_entries_bootstrap[idx].base_middle = (base >> 16) & 0xFF; // Middle 8 bits of base
gdt_entries_bootstrap[idx].access = access; // Access byte
gdt_entries_bootstrap[idx].granularity = (limit >> 16) & 0x0F; // Upper 4 bits of limit
gdt_entries_bootstrap[idx].granularity |= granularity & 0xF0; // Flags
gdt_entries_bootstrap[idx].base_high = (base >> 24) & 0xFF; // Next 8 bits of base
gdt_entries_bootstrap[idx].base_upper = (base >> 32) & 0xFFFFFFFF; // Upper 32 bits of base
gdt_entries_bootstrap[idx].reserved = 0; // Reserved, set to 0
printf("GDT Entry %d: Base: %x, Limit: %x, Access: %x, Granularity: %x\n", idx, base, limit, access, granularity);
}
// Initialize GDT for Bootstrap CPU
void init_gdt_bootstrap_cpu() {
gdt_setup_bootstrap(0, 0, 0x0, 0x0, 0x0); // Null descriptor selector : 0x0
gdt_setup_bootstrap(1, 0, 0xFFFF, 0x9A, 0xA0); // Kernel mode code segment, selector : 0x8
gdt_setup_bootstrap(2, 0, 0xFFFF, 0x92, 0xA0); // Kernel mode data segment, selector : 0x10
gdt_setup_bootstrap(3, 0, 0xFFFF, 0xFA, 0xA0); // User mode code segment, selector : 0x18
gdt_setup_bootstrap(4, 0, 0xFFFF, 0xF2, 0xA0); // User mode data segment, selector : 0x20
// Calculate the GDT limit and base address
gdtr_bootstrap.limit = (uint16_t) (GDT_ENTRIES_COUNT * sizeof(gdt_entry_t) - 1);
gdtr_bootstrap.base = (uint64_t) &gdt_entries_bootstrap;
printf("Loading GDT: Base: %x, Limit: %x\n", gdtr_bootstrap.base, gdtr_bootstrap.limit);
// Load the new GDT
gdt_flush((gdtr_t *) &gdtr_bootstrap);
printf("Successfully GDT initialized for Bootstrap CPU.\n");
}
// Setup TSS entry in GDT
void tss_setup_bootstrap(uint8_t idx, uint64_t base, uint32_t limit, uint8_t access, uint8_t granularity) {
gdt_entries_bootstrap[idx].limit_low = limit & 0xFFFF;
gdt_entries_bootstrap[idx].base_low = base & 0xFFFF;
gdt_entries_bootstrap[idx].base_middle = (base >> 16) & 0xFF;
gdt_entries_bootstrap[idx].access = access;
gdt_entries_bootstrap[idx].granularity = (limit >> 16) & 0x0F;
gdt_entries_bootstrap[idx].granularity |= (granularity & 0xF0);
gdt_entries_bootstrap[idx].base_high = (base >> 24) & 0xFF;
gdt_entries_bootstrap[idx].base_upper = (base >> 32) & 0xFFFFFFFF;
gdt_entries_bootstrap[idx].reserved = 0;
printf("TSS Entry: Base: %x, Limit: %x\n", base, limit);
printf("TSS Entry: %x %x %x %x %x %x %x %x\n",
gdt_entries_bootstrap[idx].limit_low,
gdt_entries_bootstrap[idx].base_low,
gdt_entries_bootstrap[idx].base_middle,
gdt_entries_bootstrap[idx].access,
gdt_entries_bootstrap[idx].granularity,
gdt_entries_bootstrap[idx].base_high,
gdt_entries_bootstrap[idx].base_upper,
gdt_entries_bootstrap[idx].reserved);
}
// Initialize TSS for Bootstrap CPU
void init_tss_bootstrap_cpu() {
printf("Starting TSS setup\n");
// Clear the TSS structure
memset(&tss_entry_bootstrap, 0, sizeof(tss_entry_t));
// Allocate a kernel stack for Ring 0
tss_entry_bootstrap.rsp0 = (uint64_t) kmalloc_a(STACK_SIZE, true);
if (!tss_entry_bootstrap.rsp0) {
printf("Error: Failed to allocate kernel stack for TSS.\n");
return;
}
// Set I/O Permission Bitmap offset (no I/O bitmap)
tss_entry_bootstrap.iopb_offset = sizeof(tss_entry_t);
// Add the TSS to GDT (selector 0x28)
tss_setup_bootstrap(5, (uint64_t)&tss_entry_bootstrap, sizeof(tss_entry_t) - 1, 0x89, 0x00);
// Load the TSS into the CPU's TR register
tss_flush(0x28);
printf("Successfully TSS initialized for Bootstrap CPU.\n");
printf("Kernel stack allocated at: %x\n", tss_entry_bootstrap.rsp0);
}
// Initialize GDT and TSS for Bootstrap CPU
void start_bootstrap_gdt_tss() {
// Setting GDTs
gdt_setup_bootstrap(0, 0, 0x0, 0x0, 0x0); // Null descriptor selector : 0x0
gdt_setup_bootstrap(1, 0, 0xFFFF, 0x9A, 0xA0); // Kernel mode code segment, selector : 0x8
gdt_setup_bootstrap(2, 0, 0xFFFF, 0x92, 0xA0); // Kernel mode data segment, selector : 0x10
gdt_setup_bootstrap(3, 0, 0xFFFF, 0xFA, 0xA0); // User mode code segment, selector : 0x18
gdt_setup_bootstrap(4, 0, 0xFFFF, 0xF2, 0xA0); // User mode data segment, selector : 0x20
// Setting TSS
memset(&tss_entry_bootstrap, 0, sizeof(tss_entry_t));
// Allocate a kernel stack for Ring 0
tss_entry_bootstrap.rsp0 = (uint64_t) kmalloc_a(STACK_SIZE, true);
if (!tss_entry_bootstrap.rsp0) {
printf("Error: Failed to allocate kernel stack for TSS.\n");
return;
}
// Set I/O Permission Bitmap offset (no I/O bitmap)
tss_entry_bootstrap.iopb_offset = sizeof(tss_entry_t);
// Add the TSS to GDT (selector 0x28)
tss_setup_bootstrap(5, (uint64_t)&tss_entry_bootstrap, sizeof(tss_entry_t) - 1, 0x89, 0x00);
gdtr_bootstrap.limit = (uint16_t) (GDT_ENTRIES_COUNT * sizeof(gdt_entry_t)) - 1; // 6*16 - 1 = 95 bytes
gdtr_bootstrap.base = (uint64_t) &gdt_entries_bootstrap; // 0xFFFFFFFF80459F80
for (int i = 0; i < GDT_ENTRIES_COUNT; i++) {
printf("GDT Entry %d: %x %x %x\n", i,
*(uint64_t*)&gdt_entries_bootstrap[i],
*((uint64_t*)&gdt_entries_bootstrap[i] + 1),
*((uint64_t*)&gdt_entries_bootstrap[i] + 1));
}
printf("limit: %d\n", gdtr_bootstrap.limit);
printf("base: %x\n", gdtr_bootstrap.base);
gdt_flush((gdtr_t *) &gdtr_bootstrap);
printf("gdt flush completed.\n");
tss_flush(0x28);
printf("tss flush completed.\n");
printf("Successfully started GDT and TSS for Bootstrap CPU.\n");
}
Code: Select all
%define KERNEL_CODE 0x08
%define KERNEL_DATA 0x10
section .text
global gdt_flush
global reloadSegments
global tss_flush
gdt_flush:
cli
LGDT [RDI]
jmp reloadSegments
sti
RET
reloadSegments:
; Reload CS register:
PUSH KERNEL_CODE ; Push code segment to stack, 0x08 is a stand-in for kernel code segment
LEA RAX, [rel reload_CS] ; Load address of reload_CS into RAX, LEA (Load Effective Address),
PUSH RAX ; Push this value to the stack
RETFQ ; Perform a far return, RETFQ or LRETQ depending on syntax
reload_CS:
; Reload data segment registers
MOV AX, KERNEL_DATA ; 0x10 is a stand-in for kernel data segment
MOV DS, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
MOV SS, AX
RET
tss_flush:
mov ax, di ; Move the selector into AX (DI is used to pass the argument in x86_64 System V ABI)
ltr ax ; Load Task Register with the selector in AX
ret
Code: Select all
GDT Entry 0: Base: 0x0, Limit: 0x0, Access: 0x0, Granularity: 0x0
GDT Entry 1: Base: 0x0, Limit: 0xFFFF, Access: 0x9A, Granularity: 0xA0
GDT Entry 2: Base: 0x0, Limit: 0xFFFF, Access: 0x92, Granularity: 0xA0
GDT Entry 3: Base: 0x0, Limit: 0xFFFF, Access: 0xFA, Granularity: 0xA0
GDT Entry 4: Base: 0x0, Limit: 0xFFFF, Access: 0xF2, Granularity: 0xA0
TSS Entry: Base: 0xFFFFFFFF8045A000, Limit: 0x4F
TSS Entry: 0x4F 0xA000 0x45 0x89 0x0 0x80 0xFFFFFFFF 0x0
GDT Entry 0: 0x0 0x0 0x0
GDT Entry 1: 0xA09A000000FFFF 0x0 0x0
GDT Entry 2: 0xA092000000FFFF 0x0 0x0
GDT Entry 3: 0xA0FA000000FFFF 0x0 0x0
GDT Entry 4: 0xA0F2000000FFFF 0x0 0x0
GDT Entry 5: 0x80008945A000004F 0xFFFFFFFF 0xFFFFFFFF
limit: 95
base: 0xFFFFFFFF80459F80
I need help to resolve this issue. I have checked 64 bit gdt_entries without TSS worked fine with same gdt_flush but not in this case.