Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Huge pages support for x86 #1016

Open
wants to merge 11 commits into
base: theseus_main
Choose a base branch
from
18 changes: 18 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions applications/test_1gb_huge_pages/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "test_1gb_huge_pages"
version = "0.1.0"
authors = ["Noah Mogensen <noah.mogen@protonmail.com>"]
description = "Application for testing allocation, mapping, and memory access for 1gb huge pages."

[dependencies]

[dependencies.memory]
path = "../../kernel/memory"

[dependencies.app_io]
path = "../../kernel/app_io"

# [dependencies.application_main_fn]
# path = "../../compiler_plugins"
62 changes: 62 additions & 0 deletions applications/test_1gb_huge_pages/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#![no_std]
#[macro_use] extern crate alloc;
#[macro_use] extern crate app_io;

extern crate memory;

use alloc::vec::Vec;
use alloc::string::String;
use memory::{
PteFlags,
VirtualAddress, PhysicalAddress,
allocate_frames_at, allocate_pages_at
};

pub fn main(_args: Vec<String>) -> isize {
println!("NOTE: Before running, make sure you Theseus has been run with enough memory (make orun QEMU_MEMORY=5G).");
let kernel_mmi_ref = memory::get_kernel_mmi_ref()
.ok_or("KERNEL_MMI was not yet initialized!")
.unwrap();

// Now the same for 1gb pages
let mut aligned_1gb_page = allocate_pages_at(
VirtualAddress::new_canonical(0x40000000),
512*512).expect("Failed to allocate range for 1GiB page. Make sure you have enough memory for the kernel (compile with make orun QEMU_MEMORY=3G).");
aligned_1gb_page.to_1gb_allocated_pages();

let aligned_4k_frames = allocate_frames_at(
PhysicalAddress::new_canonical(0x40000000), //0x1081A000
512 * 512).expect("Failed to allocate enough frames at desired address. Make sure you have enough memory for the kernel (compile with make orun QEMU_MEMORY=3G).");

let mut mapped_1gb_page = kernel_mmi_ref.lock().page_table.map_allocated_pages_to(
aligned_1gb_page,
aligned_4k_frames,
PteFlags::new().valid(true).writable(true),
).expect("test_huge_pages: call to map_allocated_pages failed for 1GiB page");

kernel_mmi_ref.lock().page_table.dump_pte(mapped_1gb_page.start_address());

// See if address can be translated
let translated = kernel_mmi_ref.lock()
.page_table.translate(VirtualAddress::new_canonical(0x40000000))
.unwrap();
println!("Virtual address 0x40000000-> {}", translated);

let val = mapped_1gb_page
.as_type_mut::<u8>(0)
.expect("test huge pages: call to as_type_mut() on mapped 2Mb page failed");
println!("Value at offset of 1GiB huge page before updating is {}", *val);

*val = 35;

let updated_val = mapped_1gb_page
.as_type::<u8>(0)
.expect("test huge pages: call to as_type() on mapped 2Mb page failed");
println!("Value at offset of 1GiB huge page after updating is {}", *updated_val);

// Dump entries to see if dropping has unmapped everything properly
drop(mapped_1gb_page);
kernel_mmi_ref.lock().page_table.dump_pte(VirtualAddress::new_canonical(0x40000000));

0
}
22 changes: 22 additions & 0 deletions applications/test_huge_pages/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "test_huge_pages"
version = "0.1.0"
authors = ["Noah Mogensen <noah.mogen@protonmail.com>"]
description = "Application for testing allocation, mapping, and memory access for 2mb huge pages."

[dependencies]

[dependencies.memory]
path = "../../kernel/memory"

[dependencies.frame_allocator]
path = "../../kernel/frame_allocator"

[dependencies.page_allocator]
path = "../../kernel/page_allocator"

[dependencies.app_io]
path = "../../kernel/app_io"

# [dependencies.application_main_fn]
# path = "../../compiler_plugins"
96 changes: 96 additions & 0 deletions applications/test_huge_pages/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#![no_std]
#[macro_use] extern crate alloc;
#[macro_use] extern crate app_io;

extern crate memory;
extern crate frame_allocator;
extern crate page_allocator;

use alloc::vec::Vec;
use alloc::string::String;
use memory::{
Page, PteFlags,
VirtualAddress, PhysicalAddress,
Page1G, Page2M,
allocate_frames_at, allocate_pages_at
};
// For checking valid test addresses, if necessary
// use frame_allocator::dump_frame_allocator_state;
// use page_allocator::dump_page_allocator_state;

pub fn main(_args: Vec<String>) -> isize {
println!("NOTE: Before running, make sure you Theseus has been run with enough memory (make orun QEMU_MEMORY=3G).");

let kernel_mmi_ref = memory::get_kernel_mmi_ref()
.ok_or("KERNEL_MMI was not yet initialized!")
.unwrap();

// Preliminary tests
let page1g = Page::<Page1G>::containing_address_1gb(VirtualAddress::zero());
println!("Size of page 1 is {:?}", page1g.page_size());
let page2m = Page::<Page2M>::containing_address_2mb(VirtualAddress::zero());
println!("Size of page 2 is {:?}", page2m.page_size());


// match page1g.page_size() {
// PAGE_1GB_SIZE => println!("Page 1 recognized as 1GiB"),
// _ => println!("Page 1 not recognized as 1GiB"),
// }
// match page2m.page_size() {
// PAGE_2MB_SIZE => println!("Page 2 recognized as 2MiB"),
// _ => println!("Page 2 not recognized as 2MiB"),
// }
// let _allocated_1g = allocate_1gb_pages(1)
// .ok_or("test_huge_pages: could not allocate 1GiB page")
// .unwrap();
// let _allocated_2m = allocate_2mb_pages(1)
// .ok_or("test_huge_pages: could not allocate 2MiB page")
// .unwrap();
// println!("Huge pages successfully allocated!");
// // end preliminary tests

let mut aligned_2mb_page = allocate_pages_at(
VirtualAddress::new_canonical(0x60000000),
512).expect("Could not allocate pages. Make sure you have enough memory for the kernel (compile with make orun QEMU_MEMORY=3G).");
aligned_2mb_page.to_2mb_allocated_pages();

// frame allocator has not been modified to deal with huge frames yet
let aligned_4k_frames = allocate_frames_at(
PhysicalAddress::new_canonical(0x60000000),
512).expect("Could not allocate frames. Make sure you have enough memory for the kernel (compile with make orun QEMU_MEMORY=3G).");

let allocated_2mb_frames = aligned_4k_frames.into_2mb_allocated_frames().expect("Could not convert range of allocated frames into huge allocated frames");

let mut mapped_2mb_page = kernel_mmi_ref.lock().page_table.map_allocated_pages_to(
aligned_2mb_page,
allocated_2mb_frames,
PteFlags::new().valid(true).writable(true),
).expect("test_huge_pages: call to map_allocated_pages failed");

kernel_mmi_ref.lock().page_table.dump_pte(mapped_2mb_page.start_address());

// See if address can be translated
let translated = kernel_mmi_ref.lock()
.page_table.translate(mapped_2mb_page.start_address())
.unwrap();
println!("Virtual address {} -> {}", mapped_2mb_page.start_address(), translated);


// Testing mem access with huge pages
let val = mapped_2mb_page
.as_type_mut::<u8>(0)
.expect("test huge pages: call to as_type_mut() on mapped 2Mb page failed");
println!("Value at offset of 2Mib huge page before updating is {}", *val);

*val = 35;

let updated_val = mapped_2mb_page
.as_type::<u8>(0)
.expect("test huge pages: call to as_type() on mapped 2Mb page failed");
println!("Value at offset of 2Mib huge page after updating is {}", *updated_val);

// Dump entries to see if dropping has unmapped everything properly
drop(mapped_2mb_page);
kernel_mmi_ref.lock().page_table.dump_pte(VirtualAddress::new_canonical(0x20000000));
0
}
Loading
Loading