Skip to content

Commit cad88ac

Browse files
committed
make the GDT base address configurable
1 parent fed860a commit cad88ac

File tree

3 files changed

+64
-17
lines changed

3 files changed

+64
-17
lines changed

api/build.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ fn main() {
1515
(31, 9),
1616
(40, 9),
1717
(49, 9),
18-
(58, 10),
19-
(68, 10),
20-
(78, 1),
21-
(79, 9),
18+
(58, 9),
19+
(67, 10),
20+
(77, 10),
21+
(87, 1),
2222
(88, 9),
2323
(97, 9),
2424
(106, 9),
25+
(115, 9),
2526
];
2627

2728
let mut code = String::new();

api/src/config.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ impl BootloaderConfig {
3535
0x3D,
3636
];
3737
#[doc(hidden)]
38-
pub const SERIALIZED_LEN: usize = 115;
38+
pub const SERIALIZED_LEN: usize = 124;
3939

4040
/// Creates a new default configuration with the following values:
4141
///
@@ -72,6 +72,7 @@ impl BootloaderConfig {
7272
kernel_stack,
7373
boot_info,
7474
framebuffer,
75+
gdt,
7576
physical_memory,
7677
page_table_recursive,
7778
aslr,
@@ -94,45 +95,46 @@ impl BootloaderConfig {
9495
let buf = concat_31_9(buf, kernel_stack.serialize());
9596
let buf = concat_40_9(buf, boot_info.serialize());
9697
let buf = concat_49_9(buf, framebuffer.serialize());
98+
let buf = concat_58_9(buf, gdt.serialize());
9799

98-
let buf = concat_58_10(
100+
let buf = concat_67_10(
99101
buf,
100102
match physical_memory {
101103
Option::None => [0; 10],
102104
Option::Some(m) => concat_1_9([1], m.serialize()),
103105
},
104106
);
105-
let buf = concat_68_10(
107+
let buf = concat_77_10(
106108
buf,
107109
match page_table_recursive {
108110
Option::None => [0; 10],
109111
Option::Some(m) => concat_1_9([1], m.serialize()),
110112
},
111113
);
112-
let buf = concat_78_1(buf, [(*aslr) as u8]);
113-
let buf = concat_79_9(
114+
let buf = concat_87_1(buf, [(*aslr) as u8]);
115+
let buf = concat_88_9(
114116
buf,
115117
match dynamic_range_start {
116118
Option::None => [0; 9],
117119
Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
118120
},
119121
);
120-
let buf = concat_88_9(
122+
let buf = concat_97_9(
121123
buf,
122124
match dynamic_range_end {
123125
Option::None => [0; 9],
124126
Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
125127
},
126128
);
127129

128-
let buf = concat_97_9(
130+
let buf = concat_106_9(
129131
buf,
130132
match minimum_framebuffer_height {
131133
Option::None => [0; 9],
132134
Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
133135
},
134136
);
135-
let buf = concat_106_9(
137+
let buf = concat_115_9(
136138
buf,
137139
match minimum_framebuffer_width {
138140
Option::None => [0; 9],
@@ -189,6 +191,7 @@ impl BootloaderConfig {
189191
let (&kernel_stack, s) = split_array_ref(s);
190192
let (&boot_info, s) = split_array_ref(s);
191193
let (&framebuffer, s) = split_array_ref(s);
194+
let (&gdt, s) = split_array_ref(s);
192195
let (&physical_memory_some, s) = split_array_ref(s);
193196
let (&physical_memory, s) = split_array_ref(s);
194197
let (&page_table_recursive_some, s) = split_array_ref(s);
@@ -203,6 +206,7 @@ impl BootloaderConfig {
203206
kernel_stack: Mapping::deserialize(&kernel_stack)?,
204207
boot_info: Mapping::deserialize(&boot_info)?,
205208
framebuffer: Mapping::deserialize(&framebuffer)?,
209+
gdt: Mapping::deserialize(&gdt)?,
206210
physical_memory: match physical_memory_some {
207211
[0] if physical_memory == [0; 9] => Option::None,
208212
[1] => Option::Some(Mapping::deserialize(&physical_memory)?),
@@ -351,6 +355,8 @@ pub struct Mappings {
351355
pub boot_info: Mapping,
352356
/// Specifies the mapping of the frame buffer memory region.
353357
pub framebuffer: Mapping,
358+
/// Specifies the mapping of the GDT.
359+
pub gdt: Mapping,
354360
/// The bootloader supports to map the whole physical memory into the virtual address
355361
/// space at some offset. This is useful for accessing and modifying the page tables set
356362
/// up by the bootloader.
@@ -388,6 +394,7 @@ impl Mappings {
388394
kernel_stack: Mapping::new_default(),
389395
boot_info: Mapping::new_default(),
390396
framebuffer: Mapping::new_default(),
397+
gdt: Mapping::new_default(),
391398
physical_memory: Option::None,
392399
page_table_recursive: Option::None,
393400
aslr: false,
@@ -404,6 +411,7 @@ impl Mappings {
404411
kernel_stack: Mapping::random(),
405412
boot_info: Mapping::random(),
406413
framebuffer: Mapping::random(),
414+
gdt: Mapping::random(),
407415
physical_memory: if phys {
408416
Option::Some(Mapping::random())
409417
} else {

common/src/lib.rs

+43-5
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,22 @@ use bootloader_api::{
88
info::{FrameBuffer, FrameBufferInfo, MemoryRegion, TlsTemplate},
99
BootInfo, BootloaderConfig,
1010
};
11-
use core::{alloc::Layout, arch::asm, mem::MaybeUninit, slice};
11+
use core::{
12+
alloc::Layout,
13+
arch::asm,
14+
mem::{size_of, MaybeUninit},
15+
slice,
16+
};
1217
use level_4_entries::UsedLevel4Entries;
1318
use usize_conversions::{FromUsize, IntoUsize};
1419
use x86_64::{
15-
structures::paging::{
16-
page_table::PageTableLevel, FrameAllocator, Mapper, OffsetPageTable, Page, PageSize,
17-
PageTable, PageTableFlags, PageTableIndex, PhysFrame, Size2MiB, Size4KiB,
20+
instructions::tables::{lgdt, sgdt},
21+
structures::{
22+
gdt::GlobalDescriptorTable,
23+
paging::{
24+
page_table::PageTableLevel, FrameAllocator, Mapper, OffsetPageTable, Page, PageSize,
25+
PageTable, PageTableFlags, PageTableIndex, PhysFrame, Size2MiB, Size4KiB,
26+
},
1827
},
1928
PhysAddr, VirtAddr,
2029
};
@@ -201,8 +210,20 @@ where
201210
.allocate_frame()
202211
.expect("failed to allocate GDT frame");
203212
gdt::create_and_load(gdt_frame);
213+
let gdt = mapping_addr(
214+
config.mappings.gdt,
215+
u64::from_usize(size_of::<GlobalDescriptorTable>()),
216+
4096,
217+
&mut used_entries,
218+
);
219+
let gdt_page = Page::from_start_address(gdt).unwrap();
204220
match unsafe {
205-
kernel_page_table.identity_map(gdt_frame, PageTableFlags::PRESENT, frame_allocator)
221+
kernel_page_table.map_to(
222+
gdt_page,
223+
gdt_frame,
224+
PageTableFlags::PRESENT,
225+
frame_allocator,
226+
)
206227
} {
207228
Ok(tlb) => tlb.flush(),
208229
Err(err) => panic!("failed to identity map frame {:?}: {:?}", gdt_frame, err),
@@ -459,6 +480,7 @@ where
459480

460481
kernel_slice_start,
461482
kernel_slice_len,
483+
gdt,
462484
context_switch_trampoline: trampoline_page.start_address(),
463485
context_switch_page_table,
464486
context_switch_page_table_frame,
@@ -488,6 +510,8 @@ pub struct Mappings {
488510
pub kernel_slice_start: u64,
489511
/// Size of the kernel slice allocation in memory.
490512
pub kernel_slice_len: u64,
513+
/// The address of the GDT in the kernel's address space.
514+
pub gdt: VirtAddr,
491515
/// The address of the context switch trampoline in the bootloader's address space.
492516
pub context_switch_trampoline: VirtAddr,
493517
/// The page table used for context switch from the bootloader to the kernel.
@@ -611,6 +635,7 @@ pub fn switch_to_kernel(
611635
..
612636
} = page_tables;
613637
let addresses = Addresses {
638+
gdt: mappings.gdt,
614639
context_switch_trampoline: mappings.context_switch_trampoline,
615640
context_switch_page_table: mappings.context_switch_page_table_frame,
616641
context_switch_addr: mappings.context_switch_addr,
@@ -645,6 +670,18 @@ pub struct PageTables {
645670

646671
/// Performs the actual context switch.
647672
unsafe fn context_switch(addresses: Addresses) -> ! {
673+
// Update the GDT base address.
674+
let mut gdt_pointer = sgdt();
675+
gdt_pointer.base = addresses.gdt;
676+
unsafe {
677+
// SAFETY: Note that the base address points to memory that is only
678+
// mapped in the kernel's page table. We can do this because
679+
// just loading the GDT doesn't cause any immediate loads and
680+
// by the time the base address is dereferenced the context
681+
// switch will be done.
682+
lgdt(&gdt_pointer);
683+
}
684+
648685
unsafe {
649686
asm!(
650687
"mov rsp, {}; sub rsp, 8; jmp {}",
@@ -661,6 +698,7 @@ unsafe fn context_switch(addresses: Addresses) -> ! {
661698

662699
/// Memory addresses required for the context switch.
663700
struct Addresses {
701+
gdt: VirtAddr,
664702
context_switch_trampoline: VirtAddr,
665703
context_switch_page_table: PhysFrame,
666704
context_switch_addr: VirtAddr,

0 commit comments

Comments
 (0)