Skip to content

Commit

Permalink
make the GDT base address configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
Freax13 committed Oct 29, 2022
1 parent fed860a commit cad88ac
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 17 deletions.
9 changes: 5 additions & 4 deletions api/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ fn main() {
(31, 9),
(40, 9),
(49, 9),
(58, 10),
(68, 10),
(78, 1),
(79, 9),
(58, 9),
(67, 10),
(77, 10),
(87, 1),
(88, 9),
(97, 9),
(106, 9),
(115, 9),
];

let mut code = String::new();
Expand Down
24 changes: 16 additions & 8 deletions api/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl BootloaderConfig {
0x3D,
];
#[doc(hidden)]
pub const SERIALIZED_LEN: usize = 115;
pub const SERIALIZED_LEN: usize = 124;

/// Creates a new default configuration with the following values:
///
Expand Down Expand Up @@ -72,6 +72,7 @@ impl BootloaderConfig {
kernel_stack,
boot_info,
framebuffer,
gdt,
physical_memory,
page_table_recursive,
aslr,
Expand All @@ -94,45 +95,46 @@ impl BootloaderConfig {
let buf = concat_31_9(buf, kernel_stack.serialize());
let buf = concat_40_9(buf, boot_info.serialize());
let buf = concat_49_9(buf, framebuffer.serialize());
let buf = concat_58_9(buf, gdt.serialize());

let buf = concat_58_10(
let buf = concat_67_10(
buf,
match physical_memory {
Option::None => [0; 10],
Option::Some(m) => concat_1_9([1], m.serialize()),
},
);
let buf = concat_68_10(
let buf = concat_77_10(
buf,
match page_table_recursive {
Option::None => [0; 10],
Option::Some(m) => concat_1_9([1], m.serialize()),
},
);
let buf = concat_78_1(buf, [(*aslr) as u8]);
let buf = concat_79_9(
let buf = concat_87_1(buf, [(*aslr) as u8]);
let buf = concat_88_9(
buf,
match dynamic_range_start {
Option::None => [0; 9],
Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
},
);
let buf = concat_88_9(
let buf = concat_97_9(
buf,
match dynamic_range_end {
Option::None => [0; 9],
Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
},
);

let buf = concat_97_9(
let buf = concat_106_9(
buf,
match minimum_framebuffer_height {
Option::None => [0; 9],
Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
},
);
let buf = concat_106_9(
let buf = concat_115_9(
buf,
match minimum_framebuffer_width {
Option::None => [0; 9],
Expand Down Expand Up @@ -189,6 +191,7 @@ impl BootloaderConfig {
let (&kernel_stack, s) = split_array_ref(s);
let (&boot_info, s) = split_array_ref(s);
let (&framebuffer, s) = split_array_ref(s);
let (&gdt, s) = split_array_ref(s);
let (&physical_memory_some, s) = split_array_ref(s);
let (&physical_memory, s) = split_array_ref(s);
let (&page_table_recursive_some, s) = split_array_ref(s);
Expand All @@ -203,6 +206,7 @@ impl BootloaderConfig {
kernel_stack: Mapping::deserialize(&kernel_stack)?,
boot_info: Mapping::deserialize(&boot_info)?,
framebuffer: Mapping::deserialize(&framebuffer)?,
gdt: Mapping::deserialize(&gdt)?,
physical_memory: match physical_memory_some {
[0] if physical_memory == [0; 9] => Option::None,
[1] => Option::Some(Mapping::deserialize(&physical_memory)?),
Expand Down Expand Up @@ -351,6 +355,8 @@ pub struct Mappings {
pub boot_info: Mapping,
/// Specifies the mapping of the frame buffer memory region.
pub framebuffer: Mapping,
/// Specifies the mapping of the GDT.
pub gdt: Mapping,
/// The bootloader supports to map the whole physical memory into the virtual address
/// space at some offset. This is useful for accessing and modifying the page tables set
/// up by the bootloader.
Expand Down Expand Up @@ -388,6 +394,7 @@ impl Mappings {
kernel_stack: Mapping::new_default(),
boot_info: Mapping::new_default(),
framebuffer: Mapping::new_default(),
gdt: Mapping::new_default(),
physical_memory: Option::None,
page_table_recursive: Option::None,
aslr: false,
Expand All @@ -404,6 +411,7 @@ impl Mappings {
kernel_stack: Mapping::random(),
boot_info: Mapping::random(),
framebuffer: Mapping::random(),
gdt: Mapping::random(),
physical_memory: if phys {
Option::Some(Mapping::random())
} else {
Expand Down
48 changes: 43 additions & 5 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,22 @@ use bootloader_api::{
info::{FrameBuffer, FrameBufferInfo, MemoryRegion, TlsTemplate},
BootInfo, BootloaderConfig,
};
use core::{alloc::Layout, arch::asm, mem::MaybeUninit, slice};
use core::{
alloc::Layout,
arch::asm,
mem::{size_of, MaybeUninit},
slice,
};
use level_4_entries::UsedLevel4Entries;
use usize_conversions::{FromUsize, IntoUsize};
use x86_64::{
structures::paging::{
page_table::PageTableLevel, FrameAllocator, Mapper, OffsetPageTable, Page, PageSize,
PageTable, PageTableFlags, PageTableIndex, PhysFrame, Size2MiB, Size4KiB,
instructions::tables::{lgdt, sgdt},
structures::{
gdt::GlobalDescriptorTable,
paging::{
page_table::PageTableLevel, FrameAllocator, Mapper, OffsetPageTable, Page, PageSize,
PageTable, PageTableFlags, PageTableIndex, PhysFrame, Size2MiB, Size4KiB,
},
},
PhysAddr, VirtAddr,
};
Expand Down Expand Up @@ -201,8 +210,20 @@ where
.allocate_frame()
.expect("failed to allocate GDT frame");
gdt::create_and_load(gdt_frame);
let gdt = mapping_addr(
config.mappings.gdt,
u64::from_usize(size_of::<GlobalDescriptorTable>()),
4096,
&mut used_entries,
);
let gdt_page = Page::from_start_address(gdt).unwrap();
match unsafe {
kernel_page_table.identity_map(gdt_frame, PageTableFlags::PRESENT, frame_allocator)
kernel_page_table.map_to(
gdt_page,
gdt_frame,
PageTableFlags::PRESENT,
frame_allocator,
)
} {
Ok(tlb) => tlb.flush(),
Err(err) => panic!("failed to identity map frame {:?}: {:?}", gdt_frame, err),
Expand Down Expand Up @@ -459,6 +480,7 @@ where

kernel_slice_start,
kernel_slice_len,
gdt,
context_switch_trampoline: trampoline_page.start_address(),
context_switch_page_table,
context_switch_page_table_frame,
Expand Down Expand Up @@ -488,6 +510,8 @@ pub struct Mappings {
pub kernel_slice_start: u64,
/// Size of the kernel slice allocation in memory.
pub kernel_slice_len: u64,
/// The address of the GDT in the kernel's address space.
pub gdt: VirtAddr,
/// The address of the context switch trampoline in the bootloader's address space.
pub context_switch_trampoline: VirtAddr,
/// The page table used for context switch from the bootloader to the kernel.
Expand Down Expand Up @@ -611,6 +635,7 @@ pub fn switch_to_kernel(
..
} = page_tables;
let addresses = Addresses {
gdt: mappings.gdt,
context_switch_trampoline: mappings.context_switch_trampoline,
context_switch_page_table: mappings.context_switch_page_table_frame,
context_switch_addr: mappings.context_switch_addr,
Expand Down Expand Up @@ -645,6 +670,18 @@ pub struct PageTables {

/// Performs the actual context switch.
unsafe fn context_switch(addresses: Addresses) -> ! {
// Update the GDT base address.
let mut gdt_pointer = sgdt();
gdt_pointer.base = addresses.gdt;
unsafe {
// SAFETY: Note that the base address points to memory that is only
// mapped in the kernel's page table. We can do this because
// just loading the GDT doesn't cause any immediate loads and
// by the time the base address is dereferenced the context
// switch will be done.
lgdt(&gdt_pointer);
}

unsafe {
asm!(
"mov rsp, {}; sub rsp, 8; jmp {}",
Expand All @@ -661,6 +698,7 @@ unsafe fn context_switch(addresses: Addresses) -> ! {

/// Memory addresses required for the context switch.
struct Addresses {
gdt: VirtAddr,
context_switch_trampoline: VirtAddr,
context_switch_page_table: PhysFrame,
context_switch_addr: VirtAddr,
Expand Down

0 comments on commit cad88ac

Please sign in to comment.