// SPDX-License-Identifier: MPL-2.0 #ifndef SH_LIB_GDT_H #define SH_LIB_GDT_H #include "std/status.h" #include "std/type.h" #include "irq/tss.h" // Long mode GDT part // GDT entry 64 bits structure #pragma pack(1) typedef struct { sh_uint16 limit_low; sh_uint16 base_low; sh_uint8 base_mid; sh_uint8 access; sh_uint8 flags_limit_high; sh_uint8 base_high; } sh_gdt_GDT_ENTRY_64; #pragma pack() // GDT entry 128 bits (special TSS) structure #pragma pack(1) typedef struct { sh_uint16 limit_low; sh_uint16 base_low; sh_uint8 base_mid; sh_uint8 access; sh_uint8 flags_limit_high; sh_uint8 base_high; sh_uint32 base_upper; sh_uint32 reserved; } sh_gdt_GDT_ENTRY_128; #pragma pack() // GDTR structure #pragma pack(1) typedef struct { sh_uint16 limit; sh_uint64 base; } sh_gdt_GDTR; #pragma pack() // GDT structure for bootstrap core #pragma pack(1) typedef struct { sh_gdt_GDT_ENTRY_64 null; sh_gdt_GDT_ENTRY_64 kernel_code; sh_gdt_GDT_ENTRY_64 kernel_data; sh_gdt_GDT_ENTRY_64 user_code; sh_gdt_GDT_ENTRY_64 user_data; sh_gdt_GDT_ENTRY_128 tss; } sh_gdt_GDT; #pragma pack() // GDT structure for all APs #pragma pack(1) typedef struct { sh_gdt_GDT_ENTRY_64 null; sh_gdt_GDT_ENTRY_64 kernel_code; sh_gdt_GDT_ENTRY_64 kernel_data; sh_gdt_GDT_ENTRY_64 user_code; sh_gdt_GDT_ENTRY_64 user_data; sh_gdt_GDT_ENTRY_128 tss[256]; } sh_gdt_GDT_AP; #pragma pack() // Generate access byte inline sh_uint8 sh_gdt_fill_access_byte(sh_bool present,sh_uint8 dpl,sh_bool descriptor_type,sh_uint8 segment_type) { return ((present?1:0)<<7)|((dpl&0x3)<<5)|((descriptor_type?1:0)<<4)|(segment_type&0xF); } // Generate flags byte (put all 4 bits in bit 0-3 of the returned byte) inline sh_uint8 sh_gdt_fill_flags_byte(sh_bool g,sh_bool db,sh_bool l,sh_bool avl) { return ((g?1:0)<<3)|((db?1:0)<<2)|((l?1:0)<<1)|((avl?1:0)<<0); } // Fill GDT entry 64 bits, expect flags as sh_gdt_fill_flags_byte would return it sh_gdt_GDT_ENTRY_64 sh_gdt_fill_gdt_entry_64(sh_uint32 limit,sh_uint32 base,sh_uint8 access,sh_uint8 flags); // Fill GDT entry 128 bits, expect flags as sh_gdt_fill_flags_byte would return it sh_gdt_GDT_ENTRY_128 sh_gdt_fill_gdt_entry_128(sh_uint32 limit,sh_uint64 base,sh_uint8 access,sh_uint8 flags); // Fill GDT with provided TSS SH_STATUS sh_gdt_fill_gdt(sh_tss_TSS *tss,sh_gdt_GDT *gdt); // Fill APs common GDT with provided TSS array SH_STATUS sh_gdt_fill_gdt_ap(sh_tss_TSS *tss,sh_uint64 tss_count,sh_gdt_GDT_AP *gdt); // Generate GDTR for AP GDT sh_gdt_GDTR sh_gdt_make_gdtr_ap(sh_gdt_GDT_AP *gdt); // Fill and load GDTR SH_STATUS sh_gdt_load_gdtr(sh_gdt_GDT *gdt); // Reload registers SH_STATUS sh_gdt_reload_registers(); // 16/32 bits mode GDT part // GDT entry 32 bits structure #pragma pack(1) typedef struct { sh_uint16 limit_low; sh_uint16 base_low; sh_uint8 base_middle; sh_uint8 access; sh_uint8 granularity; sh_uint8 base_high; } sh_gdt_GDT_ENTRY_32; #pragma pack() // GDT 32 bits structure #pragma pack(1) typedef struct { sh_gdt_GDT_ENTRY_32 null; sh_gdt_GDT_ENTRY_32 code_64; sh_gdt_GDT_ENTRY_32 code; sh_gdt_GDT_ENTRY_32 data; } sh_gdt_GDT_32; #pragma pack() // Generate access byte inline sh_uint8 sh_gdt_fill_access_byte_32(sh_bool present,sh_uint8 dpl,sh_bool descriptor_type,sh_uint8 segment_type) { sh_uint8 access=0; access|=(present?1:0)<<7; access|=(dpl&0x3)<<5; access|=(descriptor_type?1:0)<<4; access|=(segment_type&0xF); return access; } // Generate granularity byte inline sh_uint8 sh_gdt_fill_granularity_byte_32(sh_bool granularity,sh_bool db,sh_bool l,sh_bool avl) { sh_uint8 g=0; g|=(granularity?1:0)<<7; g|=(db?1:0)<<6; g|=(l?1:0)<<5; g|=(avl?1:0)<<4; return g; } // Fill GDT entry 32 bits, expect granularity as sh_gdt_fill_granularity_byte_32 would return it sh_gdt_GDT_ENTRY_32 sh_gdt_fill_gdt_entry_32(sh_uint32 limit,sh_uint32 base,sh_uint8 access,sh_uint8 granularity); // Fill GDT 32 bits SH_STATUS sh_gdt_fill_gdt_32(sh_gdt_GDT_32 *gdt_32); #endif