PatchworkOS  da8a090
A non-POSIX operating system.
Loading...
Searching...
No Matches
gdt.h
Go to the documentation of this file.
1#pragma once
2
3#include <kernel/cpu/tss.h>
4#include <kernel/defs.h>
5
6#include <stdint.h>
7
8/**
9 * @brief Global Descriptor Table
10 * @defgroup kernel_cpu_gdt GDT
11 * @ingroup kernel_cpu
12 *
13 * The global descriptor table is a legacy feature from the days of 32-bit x86 and older. Most of its features are
14 * unused, but is still required in 64-bit mode to specify the current privilage level and to load the TSS.
15 *
16 * @see [OSDev Wiki GDT](https://wiki.osdev.org/Global_Descriptor_Table)
17 *
18 * @{
19 */
20
21typedef enum
22{
26 GDT_RING3 = 3
28
29/**
30 * @brief Segment selectors.
31 * @enum gdt_segment_selector_t
32 *
33 * These values are stored in the segment registers (CS, DS, ES, FS, GS, SS) to tell the CPU which segment of the GDT to
34 * use.
35 */
36typedef enum
37{
38 GDT_NULL = 0, ///< Null segment selector, unused but the gdt must start with it.
39 GDT_KERNEL_CODE = 0x08, ///< Kernel code segment selector.
40 GDT_KERNEL_DATA = 0x10, ///< Kernel data segment selector.
41 GDT_USER_DATA = 0x18, ///< User data segment selector.
42 GDT_USER_CODE = 0x20, ///< User code segment selector.
43 GDT_TSS = 0x28, ///< TSS segment selector.
44
45 GDT_CS_RING0 = GDT_KERNEL_CODE | GDT_RING0, ///< Value to load into the CS register for kernel code.
46 GDT_SS_RING0 = GDT_KERNEL_DATA | GDT_RING0, ///< Value to load into the SS register for kernel data.
47
48 GDT_CS_RING3 = GDT_USER_CODE | GDT_RING3, ///< Value to load into the CS register for user code.
49 GDT_SS_RING3 = GDT_USER_DATA | GDT_RING3, ///< Value to load into the SS register for user data.
51
52/**
53 * @brief Access byte.
54 * @enum gdt_access_t
55 */
56typedef enum
57{
58 GDT_ACCESS_ACCESSED = 1 << 0, ///< Will be set to 1 when accessed, but its best to set it to 1 manually.
59 GDT_ACCESS_READ_WRITE = 1 << 1, ///< If set on a code segment, its readable. If set on a data segment, its writable.
60 GDT_ACCESS_DIRECTION_CONFORMING = 1 << 2, ///< If set on a data segment, the segment grows downwards. If
61 /// set on a code segment, conforming.
62 GDT_ACCESS_EXEC = 1 << 3, ///< If set, the segment is a code segment. If clear, its a data segment.
63 GDT_ACCESS_SYSTEM = 0 << 4, ///< Is a system segment.
64 GDT_ACCESS_DATA_CODE = 1 << 4, ///< Is a data or code segment.
65
66 GDT_ACCESS_TYPE_LDT = 0x2, ///< Local Descriptor Table. Only used if the SYSTEM bit is 0.
67 GDT_ACCESS_TYPE_TSS_AVAILABLE = 0x9, ///< Available 64-bit Task State Segment. Only used if the SYSTEM bit is 0.
68 GDT_ACCESS_TYPE_TSS_BUSY = 0xB, ///< Busy 64-bit Task State Segment. Only used if the SYSTEM bit is 0.
69
70 GDT_ACCESS_RING0 = 0 << 5, ///< Descriptor Privilege Level 0 (kernel).
71 GDT_ACCESS_RING1 = 1 << 5, ///< Descriptor Privilege Level 1, unused.
72 GDT_ACCESS_RING2 = 2 << 5, ///< Descriptor Privilege Level 2, unused.
73 GDT_ACCESS_RING3 = 3 << 5, ///< Descriptor Privilege Level 3 (user).
74
75 GDT_ACCESS_PRESENT = 1 << 7, ///< Must be 1 for all valid segments.
77
78/**
79 * @brief Flags byte.
80 * @enum gdt_flags_t
81 */
82typedef enum
83{
84 GDT_FLAGS_NONE = 0, ///< No flags set.
85 GDT_FLAGS_RESERVED = 1 << 0, ///< Must be 0.
86 GDT_FLAGS_LONG_MODE = 1 << 1, ///< If set, its a 64-bit code segment.
87 GDT_FLAGS_SIZE = 1 << 2, ///< If set, its a 32-bit segment. If clear, its a 16-bit segment. Ignored in 64-bit mode.
88 GDT_FLAGS_4KB = 1 << 3 ///< If set, the limit is in 4KiB blocks. If clear, the limit is in bytes.
90
91/**
92 * @brief GDT descriptor structure.
93 *
94 * Used to load the GDT with the `lgdt` instruction.
95 */
96typedef struct PACKED
97{
98 uint16_t size; ///< Size of the GDT - 1.
99 uint64_t offset; ///< Address of the GDT.
100} gdt_desc_t;
101
102/**
103 * @brief A single GDT segment descriptor.
104 * @struct gdt_segment_t
105 *
106 * This stucture is the same for both 32-bit and 64-bit mode.
107 */
117
118/**
119 * @brief A long mode system segment descriptor, used for TSS and LDT.
120 * @struct gdt_long_system_segment_t
121 *
122 * This structure is used for 64-bit TSS and LDT descriptors.
123 */
135
136/**
137 * @brief The actual GDT structure
138 * @struct gdt_t
139 *
140 * Note that we actually only need one TTS descriptor, not one per cpu, as its only used while loading a TTS, after that
141 * its just useless.
142 */
152
153/**
154 * @brief Loads a GDT descriptor.
155 *
156 * Dont use this directly use `gdt_cpu_load()` instead.
157 *
158 * @param descriptor The GDT descriptor to load.
159 */
160extern void gdt_load_descriptor(gdt_desc_t* descriptor);
161
162/**
163 * @brief Initialize the GDT.
164 *
165 * This will setup the GDT structure in memory, but will not load it. Loading is done in `gdt_cpu_load()`.
166 */
167void gdt_init(void);
168
169/**
170 * @brief Load the GDT on the current CPU.
171 *
172 * This will load the GDT using the `lgdt` instruction and then reload all segment registers to use the new GDT.
173 *
174 * Must be called after `gdt_init()`.
175 */
176void gdt_cpu_load(void);
177
178/**
179 * @brief Load a TSS into the GDT and load it using the `ltr` instruction on the current CPU.
180 *
181 * Note that the actual TTS descriptor in the GDT can be shared between CPUs, as its only used while loading the TSS,
182 * after that its just useless.
183 *
184 * @param tss The TSS to load.
185 */
186void gdt_cpu_tss_load(tss_t* tss);
187
188/** @} */
gdt_segment_selector_t
Segment selectors.
Definition gdt.h:37
void gdt_cpu_tss_load(tss_t *tss)
Load a TSS into the GDT and load it using the ltr instruction on the current CPU.
Definition gdt.c:63
gdt_flags_t
Flags byte.
Definition gdt.h:83
gdt_ring_t
Definition gdt.h:22
gdt_access_t
Access byte.
Definition gdt.h:57
void gdt_init(void)
Initialize the GDT.
Definition gdt.c:35
void gdt_load_descriptor(gdt_desc_t *descriptor)
Loads a GDT descriptor.
void gdt_cpu_load(void)
Load the GDT on the current CPU.
Definition gdt.c:55
@ GDT_KERNEL_DATA
Kernel data segment selector.
Definition gdt.h:40
@ GDT_CS_RING3
Value to load into the CS register for user code.
Definition gdt.h:48
@ GDT_USER_DATA
User data segment selector.
Definition gdt.h:41
@ GDT_KERNEL_CODE
Kernel code segment selector.
Definition gdt.h:39
@ GDT_TSS
TSS segment selector.
Definition gdt.h:43
@ GDT_CS_RING0
Value to load into the CS register for kernel code.
Definition gdt.h:45
@ GDT_SS_RING3
Value to load into the SS register for user data.
Definition gdt.h:49
@ GDT_SS_RING0
Value to load into the SS register for kernel data.
Definition gdt.h:46
@ GDT_NULL
Null segment selector, unused but the gdt must start with it.
Definition gdt.h:38
@ GDT_USER_CODE
User code segment selector.
Definition gdt.h:42
@ GDT_FLAGS_SIZE
If set, its a 32-bit segment. If clear, its a 16-bit segment. Ignored in 64-bit mode.
Definition gdt.h:87
@ GDT_FLAGS_RESERVED
Must be 0.
Definition gdt.h:85
@ GDT_FLAGS_4KB
If set, the limit is in 4KiB blocks. If clear, the limit is in bytes.
Definition gdt.h:88
@ GDT_FLAGS_NONE
No flags set.
Definition gdt.h:84
@ GDT_FLAGS_LONG_MODE
If set, its a 64-bit code segment.
Definition gdt.h:86
@ GDT_RING2
Definition gdt.h:25
@ GDT_RING3
Definition gdt.h:26
@ GDT_RING1
Definition gdt.h:24
@ GDT_RING0
Definition gdt.h:23
@ GDT_ACCESS_RING0
Descriptor Privilege Level 0 (kernel).
Definition gdt.h:70
@ GDT_ACCESS_RING1
Descriptor Privilege Level 1, unused.
Definition gdt.h:71
@ GDT_ACCESS_ACCESSED
Will be set to 1 when accessed, but its best to set it to 1 manually.
Definition gdt.h:58
@ GDT_ACCESS_TYPE_LDT
Local Descriptor Table. Only used if the SYSTEM bit is 0.
Definition gdt.h:66
@ GDT_ACCESS_EXEC
If set, the segment is a code segment. If clear, its a data segment.
Definition gdt.h:62
@ GDT_ACCESS_DIRECTION_CONFORMING
Definition gdt.h:60
@ GDT_ACCESS_SYSTEM
Is a system segment.
Definition gdt.h:63
@ GDT_ACCESS_READ_WRITE
If set on a code segment, its readable. If set on a data segment, its writable.
Definition gdt.h:59
@ GDT_ACCESS_PRESENT
Must be 1 for all valid segments.
Definition gdt.h:75
@ GDT_ACCESS_DATA_CODE
Is a data or code segment.
Definition gdt.h:64
@ GDT_ACCESS_TYPE_TSS_BUSY
Busy 64-bit Task State Segment. Only used if the SYSTEM bit is 0.
Definition gdt.h:68
@ GDT_ACCESS_RING2
Descriptor Privilege Level 2, unused.
Definition gdt.h:72
@ GDT_ACCESS_RING3
Descriptor Privilege Level 3 (user).
Definition gdt.h:73
@ GDT_ACCESS_TYPE_TSS_AVAILABLE
Available 64-bit Task State Segment. Only used if the SYSTEM bit is 0.
Definition gdt.h:67
#define PACKED
GCC packed attribute.
Definition defs.h:32
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
__UINT16_TYPE__ uint16_t
Definition stdint.h:13
GDT descriptor structure.
Definition gdt.h:97
uint64_t offset
Address of the GDT.
Definition gdt.h:99
uint16_t size
Size of the GDT - 1.
Definition gdt.h:98
A long mode system segment descriptor, used for TSS and LDT.
Definition gdt.h:125
uint8_t baseUpperMiddle
Definition gdt.h:131
uint8_t baseLowerMiddle
Definition gdt.h:128
uint8_t flagsAndLimitHigh
Definition gdt.h:130
A single GDT segment descriptor.
Definition gdt.h:109
uint16_t baseLow
Definition gdt.h:111
uint8_t baseHigh
Definition gdt.h:115
uint16_t limitLow
Definition gdt.h:110
uint8_t baseMiddle
Definition gdt.h:112
uint8_t flagsAndLimitHigh
Definition gdt.h:114
uint8_t access
Definition gdt.h:113
The actual GDT structure.
Definition gdt.h:144
gdt_segment_t kernelCode
Definition gdt.h:146
gdt_segment_t userData
Definition gdt.h:148
gdt_segment_t userCode
Definition gdt.h:149
gdt_long_system_segment_t tssDesc
Definition gdt.h:150
gdt_segment_t null
Definition gdt.h:145
gdt_segment_t kernelData
Definition gdt.h:147
Task State Segment structure.
Definition tss.h:94