@@ -118,6 +118,7 @@ pub struct ArchTask {
118
118
context_switch_rsp : VirtAddr ,
119
119
120
120
fs_base : VirtAddr ,
121
+ gs_base : VirtAddr ,
121
122
}
122
123
123
124
impl ArchTask {
@@ -129,7 +130,9 @@ impl ArchTask {
129
130
// Since the IDLE task is a special kernel task, we use the kernel's
130
131
// address space here and we also use the kernel privilage level here.
131
132
address_space : AddressSpace :: this ( ) ,
133
+
132
134
fs_base : VirtAddr :: zero ( ) ,
135
+ gs_base : VirtAddr :: zero ( ) ,
133
136
}
134
137
}
135
138
@@ -166,7 +169,9 @@ impl ArchTask {
166
169
context : unsafe { Unique :: new_unchecked ( context) } ,
167
170
address_space,
168
171
context_switch_rsp : VirtAddr :: new ( task_stack as u64 ) ,
172
+
169
173
fs_base : VirtAddr :: zero ( ) ,
174
+ gs_base : VirtAddr :: zero ( ) ,
170
175
}
171
176
}
172
177
@@ -225,8 +230,10 @@ impl ArchTask {
225
230
context : unsafe { Unique :: new_unchecked ( context) } ,
226
231
context_switch_rsp : VirtAddr :: new ( switch_stack as u64 ) ,
227
232
address_space : new_address_space,
228
- // The FS base is inherited from the parent process.
233
+
234
+ // The FS and GS bases are inherited from the parent process.
229
235
fs_base : self . fs_base . clone ( ) ,
236
+ gs_base : self . gs_base . clone ( ) ,
230
237
} )
231
238
}
232
239
@@ -327,7 +334,23 @@ impl ArchTask {
327
334
Ok ( ( ) )
328
335
}
329
336
330
- /// Returns the FS base for this instance.
337
+ /// Returns the saved GS base for this task.
338
+ pub fn get_gs_base ( & self ) -> VirtAddr {
339
+ self . gs_base
340
+ }
341
+
342
+ /// Sets the GS base to the provided `base`.
343
+ ///
344
+ /// ## Safety
345
+ /// This function **must** be called by the process that this [`ArchTask`] instance
346
+ /// belongs to. This is required since we also update the GS base register with the
347
+ /// `base` immediately (not waiting for a switch).
348
+ pub unsafe fn set_gs_base ( & mut self , base : VirtAddr ) {
349
+ io:: wrmsr ( io:: IA32_KERNEL_GSBASE , base. as_u64 ( ) ) ;
350
+ self . gs_base = base;
351
+ }
352
+
353
+ /// Returns the saved FS base for this task.
331
354
pub fn get_fs_base ( & self ) -> VirtAddr {
332
355
self . fs_base
333
356
}
@@ -358,5 +381,10 @@ pub fn arch_task_spinup(from: &mut ArchTask, to: &ArchTask) {
358
381
from. fs_base = VirtAddr :: new ( io:: rdmsr ( io:: IA32_FS_BASE ) ) ;
359
382
// switch to the new FS base.
360
383
io:: wrmsr ( io:: IA32_FS_BASE , to. fs_base . as_u64 ( ) ) ;
384
+
385
+ // make a restore point for the current GS base.
386
+ from. gs_base = VirtAddr :: new ( io:: rdmsr ( io:: IA32_KERNEL_GSBASE ) ) ;
387
+ // update the swap GS target to point to the new GS base.
388
+ io:: wrmsr ( io:: IA32_KERNEL_GSBASE , to. gs_base . as_u64 ( ) ) ;
361
389
}
362
390
}
0 commit comments