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