OS in Rust
static variables are stored at a fixed memory location for the complete lifetime of the program.push and pop operations.outer function called the inner function.outer are first.inner call, the parameter 1 and the return address were pushed.inner which pushed its local array.inner function returns:
outer remain.returns a reference to data owned by the current function
'static lifetime and can always be referenced from local variables.inner function returns, its part of the call stack is “destroyed”.
&Z[1] reference is still valid after the return.Z was not defined within inner.allocate and deallocate.
allocate returns a free chunk of memory of the specified size that can be used to store a variable.deallocate function.inner stores z to heap.
ptr::writeoffsetdeallocated.z[1] slot is free again and can be reusedz[0] and z[2] are never freed!deallocate is a use-after-free vulnerability.BoxBox::new, which is the Rust allocator.Drop traitdrop<T>(_x: T) functionThis pattern has the strange name resource acquisition is initialization (or RAII for short). It originated in C++, where it is used to implement a similar abstraction type called
std::unique_ptr.
rustc complainserror[E0597]: `y[_]` does not live long enough
--> src/main.rs:4:9
|
2 | let x = {
| - borrow later stored here
3 | let y = Box::new(["Hello", "World"]);
| - binding `y` declared here
4 | &y[0] // No semi-colon.
| ^^^^^ borrowed value does not live long enough
5 | }; // Semi-colon.
| - `y[_]` dropped here while still borrowedRc]
std::rc::RcBTreeMap which I used in code I actually wrote that I wanted to work once..cargo/config.toml
build-stdalloc where we added corealloc crate requires a heap allocator
allocate and deallocateGlobalAlloc (referred to in error)To set the heap allocator for the crate, the
#[global_allocator]attribute must be applied to astaticvariable that implements theGlobalAlloctrait.
GlobalAllocallocLayout instance as an argument
alloc method returns a null pointer to signal an allocation error.deallocdealloc method is the counterpart to alloc.allocLayout that was used for the allocation.alloc_zeroed is equivalent to calling alloc and then setting the allocated memory block to zero.realloc method allows to grow or shrink an allocation.
DummyAllocatorallocator module:#[global_allocator]static whichGlobalAlloc.configalloc and allocator, both, to src/lib.rsstruct with some methods, and…static.src/main.rs
extern crate alloc; in any file where we use Box.Box from within alloc using whatever means we prefer.Box::new calls alloc.Box::new null-checks the return value.
OptionBox::new panics if it sees null.alloc return), it’s all just language features.Mapper we previously implemented.
src/allocator.rs
pub fn init_heap(
mapper: &mut impl x86_64::structures::paging::Mapper<x86_64::structures::paging::Size4KiB>,
frame_allocator: &mut impl x86_64::structures::paging::FrameAllocator<
x86_64::structures::paging::Size4KiB,
>,
) -> Option<()> {
let page_range = {
let heap_start = x86_64::VirtAddr::new(HEAP_START as u64);
let heap_end = heap_start + HEAP_SIZE - 1u64;
let heap_start_page = x86_64::structures::paging::Page::containing_address(heap_start);
let heap_end_page = x86_64::structures::paging::Page::containing_address(heap_end);
x86_64::structures::paging::Page::range_inclusive(heap_start_page, heap_end_page)
};
let flags = x86_64::structures::paging::PageTableFlags::PRESENT
| x86_64::structures::paging::PageTableFlags::WRITABLE;
for page in page_range {
let frame = match frame_allocator.allocate_frame() {
Some(f) => f,
_ => return None,
};
unsafe {
match mapper.map_to(page, frame, flags, frame_allocator) {
Ok(m) => m.flush(),
_ => return None,
};
}
}
return Some(());
}HEAP_START pointer to a VirtAddr type.HEAP_SIZE.Page types using the containing_address function.Page::range_inclusive function.FrameAllocator::allocate_frame.flush updates the TLB.cargo r to make sure your code doesn’t explode, then let’s head over to src/main.rs to run this thing.src/main.rssrc/main.rs
pub extern "C" fn _start(boot_info: &'static bootloader::BootInfo) -> ! {
osirs::init();
let offset = x86_64::VirtAddr::new(boot_info.physical_memory_offset);
let mut mapper = unsafe { osirs::memory::init(offset) };
let mut frame_allocator =
unsafe { osirs::memory::BootInfoFrameAllocator::init(&boot_info.memory_map) };
osirs::allocator::init_heap(&mut mapper, &mut frame_allocator).unwrap();
println!("Hello world{}", "!");