# GDT The GDT management is defined in `shelter/lib/include/irq/gdt.h` and implemented in `shelter/lib/include/irq/gdt.c`. ## 64 bits GDT The 64 bits GDT can contains two types of entries: - `sh_gdt_GDT_ENTRY_64`: standard GDT entry - `sh_gdt_GDT_ENTRY_128`: special 128 bits GDT entry for TSS The standard 64 bits GDT used during the boot process is contained in this structure: ``` C #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() ``` We also use this struct for generating the 10 bytes to use with `lgdt`: ``` C #pragma pack(1) typedef struct { sh_uint16 limit; sh_uint64 base; } sh_gdt_GDTR; #pragma pack() ``` Regarding the API, we provide the following functions: - `sh_gdt_fill_access_byte(sh_bool present,sh_uint8 dpl,sh_bool descriptor_type,sh_uint8 segment_type)`: generate access byte - `sh_gdt_fill_flags_byte(sh_bool g,sh_bool db,sh_bool l,sh_bool avl)`: generate flags byte - `sh_gdt_fill_gdt_entry_64(sh_uint32 limit,sh_uint32 base,sh_uint8 access,sh_uint8 flags)`: fill a 64 bits GDT entry, expect flags as `sh_gdt_fill_flags_byte` would return it - `sh_gdt_fill_gdt_entry_128(sh_uint32 limit,sh_uint64 base,sh_uint8 access,sh_uint8 flags)`: fill a 128 bits GDT entry, expect flags as `sh_gdt_fill_flags_byte` would return it - `sh_gdt_fill_gdt(sh_tss_TSS *tss,sh_gdt_GDT *gdt)`: fill the standard 64 bits GDT with the provided TSS - `sh_gdt_load_gdtr(sh_gdt_GDT *gdt)`: load the standard 64 bits GDT using `lgdt` - `sh_gdt_reload_registers()`: an ASM stub to reload segment registers All these functions are intended to be used with the standard 64 bits GDT defined with `sh_gdt_GDT`, which should only be used on the bootstrap CPU ## APs GDT The APs use a special GDT containing sufficient spaces for the TSS entries of all APs. For that we use a special shared 64 bits GDT between all APs, defined in this struct: ``` C #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() ``` The APs GDT is generated using the function `sh_gdt_fill_gdt_ap(sh_tss_TSS *tss,sh_uint64 tss_count,sh_gdt_GDT_AP *gdt)`. This allows to fill a GDT with up to 256 TSS entries. The GDTR for this shared GDT is generated using `sh_gdt_make_gdtr_ap(sh_gdt_GDT_AP *gdt)`. ## 32 bits GDT In order for the APs to exit 16 bits mode, they need a 32 bits GDT. Here is the structure for a 32 bits GDT entry: ``` C #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() ``` The 32 bits GDT used to exit 16 bits mode is structured like this: ``` C #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() ``` The 32 bits GDT implementation provides the following functions: - `sh_gdt_fill_access_byte_32(sh_bool present,sh_uint8 dpl,sh_bool descriptor_type,sh_uint8 segment_type)`: generate access byte - `sh_gdt_fill_granularity_byte_32(sh_bool granularity,sh_bool db,sh_bool l,sh_bool avl)`: generate granularity byte - `sh_gdt_fill_gdt_entry_32(sh_uint32 limit,sh_uint32 base,sh_uint8 access,sh_uint8 granularity)`: fill a GDT entry for a 32 bits GDT, expect flags as `sh_gdt_fill_flags_byte_32` would return it - `sh_gdt_fill_gdt_32(sh_gdt_GDT_32 *gdt_32)`: fill the 32 bits GDT structure