Skip to content

Commit

Permalink
feat: use a different frame allocator
Browse files Browse the repository at this point in the history
  • Loading branch information
Celve committed Jun 19, 2023
1 parent 30eb0a6 commit dd95657
Show file tree
Hide file tree
Showing 17 changed files with 243 additions and 240 deletions.
10 changes: 6 additions & 4 deletions kernel/src/drivers/blockdev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use virtio_drivers::{BlkResp, Hal, RespStatus, VirtIOBlk, VirtIOHeader};

use crate::{
config::VIRT_IO_HEADER,
mm::{frame::Frame, page_table::KERNEL_PAGE_TABLE},
mem::normal::page::NormalPageHandle,
mm::page_table::KERNEL_PAGE_TABLE,
sync::{condvar::Condvar, mcs::Mcs},
};

Expand All @@ -20,7 +21,8 @@ pub struct BlkDev {
pub struct VirIoHal;

lazy_static! {
pub static ref VIRT_IO_FRAMES: Mcs<BTreeMap<usize, Vec<Frame>>> = Mcs::new(BTreeMap::new());
pub static ref VIRT_IO_FRAMES: Mcs<BTreeMap<usize, Vec<NormalPageHandle>>> =
Mcs::new(BTreeMap::new());
}

impl DiskManager for BlkDev {
Expand Down Expand Up @@ -88,8 +90,8 @@ impl BlkDev {

impl Hal for VirIoHal {
fn dma_alloc(pages: usize) -> virtio_drivers::PhysAddr {
let frames: Vec<Frame> = (0..pages).map(|_| Frame::fresh()).collect();
let ptr = frames[0].ppn().into();
let frames: Vec<NormalPageHandle> = (0..pages).map(|_| NormalPageHandle::new()).collect();
let ptr = frames[0].ppn.into();
VIRT_IO_FRAMES.lock().insert(ptr, frames);
ptr
}
Expand Down
9 changes: 7 additions & 2 deletions kernel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,18 @@ use drivers::{
plic::{TargetPriority, PLIC},
uart::UART,
};
use mm::{frame::init_frame_allocator, page_table::activate_page_table};
use mm::page_table::activate_page_table;
use proc::manager::PROC_MANAGER;
use riscv::register::*;
use task::processor::{Processor, PROCESSORS};
use time::init_timer;

use crate::{fs::FUSE, mem::slab::init_slab, time::get_time, trap::set_kernel_stvec};
use crate::{
fs::FUSE,
mem::{normal::init_frame_allocator, slab::init_slab},
time::get_time,
trap::set_kernel_stvec,
};

#[link_section = ".bss.stack"]
static mut BOOTLOADER_STACK_SPACE: [[u8; BOOTLOADER_STACK_SIZE]; CPUS] =
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/mem/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub mod allocator;
pub mod empty;
pub mod normal;
pub mod page;
pub mod pt;
pub mod section;
pub mod slab;
pub mod user;
61 changes: 61 additions & 0 deletions kernel/src/mem/normal/allocator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use alloc::vec::Vec;
use spin::Spin;

use crate::{mem::allocator::PageAllocator, mm::address::PhyPageNum};

pub struct FrameAllocator {
inner: Spin<FrameAllocatorInner>,
}

/// The allocator for page table.
pub struct FrameAllocatorInner {
start: PhyPageNum,
end: PhyPageNum,
recycled: Vec<PhyPageNum>,
}

impl const Default for FrameAllocatorInner {
fn default() -> Self {
Self {
start: PhyPageNum(0),
end: PhyPageNum(0),
recycled: Default::default(),
}
}
}

impl const Default for FrameAllocator {
fn default() -> Self {
Self {
inner: Spin::new(FrameAllocatorInner::default()),
}
}
}

impl PageAllocator for FrameAllocator {
/// The init could be done only once.
unsafe fn init(&self, start: PhyPageNum, end: PhyPageNum) {
let mut guard = self.inner.lock();
guard.start = start;
guard.end = end;
guard.recycled.clear();
}

fn alloc_page(&self) -> PhyPageNum {
let mut guard = self.inner.lock();
let candidate = guard.recycled.pop();
if let Some(ppn) = candidate {
ppn
} else if guard.start < guard.end {
let ppn = guard.start;
guard.start += 1;
ppn
} else {
PhyPageNum::null()
}
}

fn dealloc_page(&self, ppn: PhyPageNum) {
self.inner.lock().recycled.push(ppn);
}
}
15 changes: 15 additions & 0 deletions kernel/src/mem/normal/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use crate::{config::MEMORY_END, mem::allocator::PageAllocator};

use self::allocator::FrameAllocator;

pub mod allocator;
pub mod page;

pub static FRAME_ALLOCATOR: FrameAllocator = FrameAllocator::default();

pub fn init_frame_allocator() {
extern "C" {
fn ekernel();
}
unsafe { FRAME_ALLOCATOR.init((ekernel as usize).into(), MEMORY_END.into()) };
}
90 changes: 90 additions & 0 deletions kernel/src/mem/normal/page.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use core::ops::{Deref, DerefMut};

use spin::SpinGuard;

use crate::{
config::PAGE_SIZE,
mem::{allocator::PageAllocator, page::Page},
mm::address::PhyPageNum,
};

use super::FRAME_ALLOCATOR;

/// One possible representation of metadata of page, when the page is used by the page table.
///
/// Here, **pt** stands for page table.
#[derive(Debug)]
pub struct NormalPage {
pub ppn: PhyPageNum,
pub refcnt: usize,
}

pub struct NormalPageHandle {
pub ppn: PhyPageNum,
}

/// Automatically fetch the lock, returning the guard.
pub struct NormalPageGuard<'a> {
pub ppn: PhyPageNum,
guard: SpinGuard<'a, Page>,
}

impl NormalPage {
/// Create a page with referencing count is equal to 1.
pub fn alloc(ppn: PhyPageNum) {
*Page::from_ppn(ppn).lock() = Page::Normal(Self { ppn, refcnt: 1 });
}
}

impl NormalPageHandle {
pub fn new() -> Self {
let ppn = FRAME_ALLOCATOR.alloc_page();
NormalPage::alloc(ppn);

// init
let handle = Self { ppn };
handle.init();
handle
}

pub fn init(&self) {
let ptr = usize::from(self.ppn) as *mut u8;
unsafe {
core::slice::from_raw_parts_mut(ptr, PAGE_SIZE).fill(0);
}
}
}

impl Drop for NormalPageHandle {
fn drop(&mut self) {
let cnt = {
let mut page = NormalPageGuard::new(self.ppn);
page.refcnt -= 1;
page.refcnt
};
if cnt == 0 {
FRAME_ALLOCATOR.dealloc_page(self.ppn);
}
}
}

impl<'a> NormalPageGuard<'a> {
pub fn new(ppn: PhyPageNum) -> Self {
let guard = Page::from_ppn(ppn).lock();
Self { ppn, guard }
}
}

impl<'a> Deref for NormalPageGuard<'a> {
type Target = NormalPage;

fn deref(&self) -> &Self::Target {
self.guard.as_normal()
}
}

impl<'a> DerefMut for NormalPageGuard<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.guard.as_normal_mut()
}
}
20 changes: 8 additions & 12 deletions kernel/src/mem/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,18 @@ use crate::{
mm::address::PhyPageNum,
};

use super::{pt::PtPage, slab::page::SlabPage, user::UserPage};
use super::{normal::page::NormalPage, slab::page::SlabPage, user::UserPage};

pub static mut MEM_MAP: [MaybeUninit<Spin<Page>>; KERNEL_PAGE_NUM] =
MaybeUninit::uninit_array::<KERNEL_PAGE_NUM>();

#[derive(Debug)]
pub enum Page {
Slab(SlabPage),
Pt(PtPage),
Normal(NormalPage),
User(UserPage),
}

pub trait Pageable {
fn new_page(pa: PhyPageNum) -> Page;
}

impl Page {
pub fn from_pa(pa: usize) -> &'static Spin<Page> {
unsafe { MEM_MAP[(pa - KERNEL_START) / PAGE_SIZE].assume_init_ref() }
Expand All @@ -48,17 +44,17 @@ impl Page {
}
}

pub fn as_pt(&self) -> &PtPage {
pub fn as_normal(&self) -> &NormalPage {
match self {
Page::Pt(pt) => pt,
_ => panic!("Page is not a page table page"),
Page::Normal(normal) => normal,
_ => panic!("Page is not a normal page"),
}
}

pub fn as_pt_mut(&mut self) -> &mut PtPage {
pub fn as_normal_mut(&mut self) -> &mut NormalPage {
match self {
Page::Pt(pt) => pt,
_ => panic!("Page is not a page table page"),
Page::Normal(normal) => normal,
_ => panic!("Page is not a normal page"),
}
}

Expand Down
13 changes: 0 additions & 13 deletions kernel/src/mem/pt.rs

This file was deleted.

1 change: 0 additions & 1 deletion kernel/src/mem/slab/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use core::alloc::GlobalAlloc;
use core::cmp::{max, min};
use core::mem::size_of;
use core::ptr::null_mut;
use core::sync::atomic::AtomicUsize;
use spin::{Spin, SpinGuard};

const BUDDY_ALLOCATOR_LEVEL: usize = 32;
Expand Down
4 changes: 2 additions & 2 deletions kernel/src/mem/slab/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ impl Cache {
page.ppn
} else {
// allocate new from buddy allocator
let ptr = usize::from(unsafe { SLAB_MEM_SECTION.alloc() });
debugln!("Buddy allocates {:#x}.", ptr);
let ptr = unsafe { SLAB_MEM_SECTION.alloc() };
debugln!("Buddy allocates {:#x}.", usize::from(ptr));
SlabPage::alloc(ptr, self.order as u8);
ptr.into()
};
Expand Down
38 changes: 9 additions & 29 deletions kernel/src/mem/slab/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@ use core::ops::{Deref, DerefMut};
use allocator::linked_list::LinkedList;
use spin::SpinGuard;

use crate::{
config::PAGE_SIZE,
mem::page::{Page, Pageable},
mm::address::PhyPageNum,
};
use crate::{config::PAGE_SIZE, mem::page::Page, mm::address::PhyPageNum};

/// One possible representation of metadata of page, when the page is used by slab allocator.
///
/// We need to guarantee that all operations toward it is atomic.
#[derive(Debug)]
pub struct SlabPage {
pa: usize,
ppn: PhyPageNum,

order: u8,

Expand All @@ -31,37 +27,27 @@ pub struct SlabPageGuard<'a> {
}

impl SlabPage {
pub fn new(pa: usize, order: u8) -> SlabPage {
pub fn alloc(ppn: PhyPageNum, order: u8) {
let mut slab_page = Self {
pa,
ppn,
order,
prev: PhyPageNum::null(),
next: PhyPageNum::null(),
free: LinkedList::new(),
inuse: 0,
};
slab_page.init();
slab_page
}

pub fn alloc(pa: usize, order: u8) {
let mut slab_page = Self {
pa,
order,
prev: PhyPageNum::null(),
next: PhyPageNum::null(),
free: LinkedList::new(),
inuse: 0,
};
slab_page.init();
*Page::from_pa(pa).lock() = Page::Slab(slab_page);
*Page::from_ppn(ppn).lock() = Page::Slab(slab_page);
}

pub fn init(&mut self) {
let size = 1 << self.order;
self.free = LinkedList::new();
(0..PAGE_SIZE / size).rev().for_each(|i| {
unsafe { self.free.push_front((self.pa + i * size) as *mut usize) };
unsafe {
self.free
.push_front((usize::from(self.ppn) + i * size) as *mut usize)
};
});
}

Expand Down Expand Up @@ -89,12 +75,6 @@ impl SlabPage {
}
}

impl Pageable for SlabPage {
fn new_page(pa: PhyPageNum) -> Page {
Page::Slab(SlabPage::new(pa.into(), 0))
}
}

impl<'a> SlabPageGuard<'a> {
pub fn new(ppn: PhyPageNum) -> Self {
let guard = Page::from_ppn(ppn).lock();
Expand Down
Loading

0 comments on commit dd95657

Please sign in to comment.