PatchworkOS  69292a3
A non-POSIX operating system.
Loading...
Searching...
No Matches
percpu.h
Go to the documentation of this file.
1#pragma once
2
3#include <kernel/cpu/cpu.h>
4#include <stddef.h>
5#include <stdint.h>
6
7/**
8 * @brief Per CPU data.
9 * @defgroup kernel_cpu_percpu Per-CPU Data
10 * @ingroup kernel_cpu
11 *
12 * In the x86 architecture the `gs` and `fs` segment registers can be used to access data relative to the address stored
13 * in the `MSR_GS_BASE` or `MSR_FS_BASE` MSRs. In AT&T assembly this would look like this:
14 *
15 * ```
16 * mov %gs:0x10, %rax ; Load the value at address in `MSR_GS_BASE` + 0x10 into rax
17 * ```
18 *
19 * This means that, since each cpu has its own `MSR_GS_BASE`, we can store the address of each CPU's structure in its
20 * own `MSR_GS_BASE` and then access data within that structure using offsets.
21 *
22 * Allocating a percpu variable then becomes as simple as allocating an offset within the `percpu` buffer in the CPU
23 * structure, and accessing it using the `gs` segment register.
24 *
25 * @note Its important to be aware of the distinction that the `gs` register does not store an address directly, rather
26 * it allows us to access memory relative to the address stored in the `MSR_GS_BASE` MSR. This is why we define Per-CPU
27 * variables as offsets within the CPU structure rather than absolute addresses.
28 *
29 * ## Defining Per-CPU Variables
30 *
31 * To define a Per-CPU variable use the `PERCPU_DEFINE()` macro. This will add a `percpu_def_t` entry to the `._percpu`
32 * section. The PERCPU_INIT()` macro can be used to allocate and initialize all Per-CPU variables defined in the
33 * module's `._percpu` section, potentially invoking any needed constructors.
34 *
35 * @note All percpu variables should use the `pcpu_` prefix for clarity.
36 *
37 * ## Constructors and Destructors
38 *
39 * All Per-CPU variables can optionally have constructors (ctor) and destructors (dtor) defined. These will be called on
40 * each CPU either during boot, when the CPU is initialized, or via a call to `percpu_update()`.
41 *
42 * By default, all variables are zero-initialized when allocated.
43 *
44 * @{
45 */
46
47/**
48 * @brief The `PERCPU_ALIGNMENT` constant defines the alignment for per-CPU variables.
49 *
50 * @note This value should be a power of 2.
51 */
52#define PERCPU_ALIGNMENT 64
53
54/**
55 * @brief The type that the compiler uses to store per-CPU variables.
56 */
57typedef size_t percpu_t;
58
59/**
60 * @brief Structure to define a percpu variable.
61 * @struct percpu_def_t
62 */
63typedef struct
64{
66 size_t size;
67 void (*ctor)(void);
68 void (*dtor)(void);
70
71/**
72 * @brief Attribute specifying that the variable is an offset into the `GS` segment register.
73 * @def PERCPU
74 */
75#define PERCPU __seg_gs*
76
77/**
78 * @brief Macro to access data in the current cpu.
79 *
80 * Intended to be used as a pointer to the current cpu structure.
81 *
82 * @warning The value of this macro is not the address of the current cpu structure, to actually retrieve the address
83 * use `SELF->self`.
84 */
85#define SELF ((cpu_t PERCPU)0)
86
87/**
88 * @brief Macro to get a pointer to a percpu variable on the current CPU.
89 *
90 * @param ptr The percpu variable pointer.
91 * @return A pointer to the percpu variable for the current CPU.
92 */
93#define SELF_PTR(ptr) ((void*)((uintptr_t)(SELF->self->percpu) + ((uintptr_t)(ptr) - offsetof(cpu_t, percpu))))
94
95/**
96 * @brief Macro to get a pointer to a percpu variable on a specific CPU.
97 *
98 * @param id The ID of the CPU.
99 * @param ptr The percpu variable pointer.
100 * @return A pointer to the percpu variable for the specified CPU.
101 */
102#define CPU_PTR(id, ptr) \
103 ((void*)((uintptr_t)(cpu_get_by_id(id)->percpu) + ((uintptr_t)(ptr) - offsetof(cpu_t, percpu))))
104
105/**
106 * @brief Macro to define a percpu variable.
107 *
108 * This macro defines a percpu variable and registers it in the `._percpu` section, so that it can be initialized by
109 * `PERCPU_INIT()`.
110 *
111 * @param type The type of the percpu variable.
112 * @param name The name of the percpu variable.
113 * @param ... Optional constructor and destructor functions for the percpu variable.
114 */
115#define PERCPU_DEFINE(type, name, ...) \
116 type PERCPU name; \
117 static const percpu_def_t __attribute__((used, section("._percpu"))) _percpu##name = {.ptr = (percpu_t*)&(name), \
118 .size = sizeof(typeof(*name)), \
119 ##__VA_ARGS__}
120
121/**
122 * @brief Macro to define a percpu variable with a constructor.
123 *
124 * This macro defines a percpu variable with a constructor and registers it in the `._percpu` section, so that it can
125 * be initialized by `PERCPU_INIT()`.
126 *
127 * @param type The type of the percpu variable.
128 * @param name The name of the percpu variable.
129 */
130#define PERCPU_DEFINE_CTOR(type, name) \
131 static void name##_ctor(void); \
132 PERCPU_DEFINE(type, name, .ctor = name##_ctor, .dtor = NULL); \
133 static void name##_ctor(void)
134
135/**
136 * @brief Macro to define a percpu variable with a destructor.
137 *
138 * This macro defines a percpu variable with a destructor and registers it in the `._percpu` section, so that it can
139 * be deinitialized by `PERCPU_FINIT()`.
140 *
141 * @param type The type of the percpu variable.
142 * @param name The name of the percpu variable.
143 */
144#define PERCPU_DEFINE_DTOR(type, name) \
145 static void name##_dtor(void); \
146 PERCPU_DEFINE(type, name, .ctor = NULL, .dtor = name##_dtor); \
147 static void name##_dtor(void)
148
149/**
150 * @brief Initialize the percpu system.
151 *
152 * This will setup the `gs` segment register to point to the CPU structure.
153 *
154 * @param cpu The CPU to initialize percpu for, should be the current CPU.
155 */
156void percpu_init(cpu_t* cpu);
157
158/**
159 * @brief Allocates a percpu variable.
160 *
161 * @param size The size of the percpu variable.
162 * @return The offset into the `GS` segment register, or `ERR` on failure.
163 */
164percpu_t percpu_alloc(size_t size);
165
166/**
167 * @brief Frees a percpu variable.
168 *
169 * @param ptr The offset into the `GS` segment register.
170 * @param size The size of the percpu variable.
171 */
172void percpu_free(percpu_t ptr, size_t size);
173
174/**
175 * @brief Update percpu sections on the current CPU.
176 *
177 * This will run any pending constructors or destructors for percpu sections.
178 */
179void percpu_update(void);
180
181/**
182 * @brief Register a percpu section and run constructors.
183 */
185
186/**
187 * @brief Unregister a percpu section and run destructors.
188 */
190
191/**
192 * @brief Initialize all percpu variables within the current modules `.percpu` section.
193 */
194#define PERCPU_INIT() \
195 do \
196 { \
197 extern percpu_def_t _percpu_start; \
198 extern percpu_def_t _percpu_end; \
199 percpu_section_init(&_percpu_start, &_percpu_end); \
200 } while (0)
201
202/**
203 * @brief Deinitialize all percpu variables within the current modules `.percpu` section.
204 */
205#define PERCPU_DEINIT() \
206 do \
207 { \
208 extern percpu_def_t _percpu_start; \
209 extern percpu_def_t _percpu_end; \
210 percpu_section_deinit(&_percpu_start, &_percpu_end); \
211 } while (0)
212
213/** @} */
static void start()
Definition main.c:542
void percpu_update(void)
Update percpu sections on the current CPU.
Definition percpu.c:99
void percpu_free(percpu_t ptr, size_t size)
Frees a percpu variable.
Definition percpu.c:63
void percpu_init(cpu_t *cpu)
Initialize the percpu system.
Definition percpu.c:33
void percpu_section_deinit(percpu_def_t *start, percpu_def_t *end)
Unregister a percpu section and run destructors.
Definition percpu.c:159
void percpu_section_init(percpu_def_t *start, percpu_def_t *end)
Register a percpu section and run constructors.
Definition percpu.c:130
percpu_t percpu_alloc(size_t size)
Allocates a percpu variable.
Definition percpu.c:39
size_t percpu_t
The type that the compiler uses to store per-CPU variables.
Definition percpu.h:57
CPU structure.
Definition cpu.h:84
Structure to define a percpu variable.
Definition percpu.h:64
size_t size
Definition percpu.h:66
percpu_t * ptr
Definition percpu.h:65