Skip to content

Commit dd95657

Browse files
committed
feat: use a different frame allocator
1 parent 30eb0a6 commit dd95657

File tree

17 files changed

+243
-240
lines changed

17 files changed

+243
-240
lines changed

kernel/src/drivers/blockdev.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use virtio_drivers::{BlkResp, Hal, RespStatus, VirtIOBlk, VirtIOHeader};
77

88
use crate::{
99
config::VIRT_IO_HEADER,
10-
mm::{frame::Frame, page_table::KERNEL_PAGE_TABLE},
10+
mem::normal::page::NormalPageHandle,
11+
mm::page_table::KERNEL_PAGE_TABLE,
1112
sync::{condvar::Condvar, mcs::Mcs},
1213
};
1314

@@ -20,7 +21,8 @@ pub struct BlkDev {
2021
pub struct VirIoHal;
2122

2223
lazy_static! {
23-
pub static ref VIRT_IO_FRAMES: Mcs<BTreeMap<usize, Vec<Frame>>> = Mcs::new(BTreeMap::new());
24+
pub static ref VIRT_IO_FRAMES: Mcs<BTreeMap<usize, Vec<NormalPageHandle>>> =
25+
Mcs::new(BTreeMap::new());
2426
}
2527

2628
impl DiskManager for BlkDev {
@@ -88,8 +90,8 @@ impl BlkDev {
8890

8991
impl Hal for VirIoHal {
9092
fn dma_alloc(pages: usize) -> virtio_drivers::PhysAddr {
91-
let frames: Vec<Frame> = (0..pages).map(|_| Frame::fresh()).collect();
92-
let ptr = frames[0].ppn().into();
93+
let frames: Vec<NormalPageHandle> = (0..pages).map(|_| NormalPageHandle::new()).collect();
94+
let ptr = frames[0].ppn.into();
9395
VIRT_IO_FRAMES.lock().insert(ptr, frames);
9496
ptr
9597
}

kernel/src/main.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,18 @@ use drivers::{
4545
plic::{TargetPriority, PLIC},
4646
uart::UART,
4747
};
48-
use mm::{frame::init_frame_allocator, page_table::activate_page_table};
48+
use mm::page_table::activate_page_table;
4949
use proc::manager::PROC_MANAGER;
5050
use riscv::register::*;
5151
use task::processor::{Processor, PROCESSORS};
5252
use time::init_timer;
5353

54-
use crate::{fs::FUSE, mem::slab::init_slab, time::get_time, trap::set_kernel_stvec};
54+
use crate::{
55+
fs::FUSE,
56+
mem::{normal::init_frame_allocator, slab::init_slab},
57+
time::get_time,
58+
trap::set_kernel_stvec,
59+
};
5560

5661
#[link_section = ".bss.stack"]
5762
static mut BOOTLOADER_STACK_SPACE: [[u8; BOOTLOADER_STACK_SIZE]; CPUS] =

kernel/src/mem/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pub mod allocator;
22
pub mod empty;
3+
pub mod normal;
34
pub mod page;
4-
pub mod pt;
55
pub mod section;
66
pub mod slab;
77
pub mod user;

kernel/src/mem/normal/allocator.rs

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use alloc::vec::Vec;
2+
use spin::Spin;
3+
4+
use crate::{mem::allocator::PageAllocator, mm::address::PhyPageNum};
5+
6+
pub struct FrameAllocator {
7+
inner: Spin<FrameAllocatorInner>,
8+
}
9+
10+
/// The allocator for page table.
11+
pub struct FrameAllocatorInner {
12+
start: PhyPageNum,
13+
end: PhyPageNum,
14+
recycled: Vec<PhyPageNum>,
15+
}
16+
17+
impl const Default for FrameAllocatorInner {
18+
fn default() -> Self {
19+
Self {
20+
start: PhyPageNum(0),
21+
end: PhyPageNum(0),
22+
recycled: Default::default(),
23+
}
24+
}
25+
}
26+
27+
impl const Default for FrameAllocator {
28+
fn default() -> Self {
29+
Self {
30+
inner: Spin::new(FrameAllocatorInner::default()),
31+
}
32+
}
33+
}
34+
35+
impl PageAllocator for FrameAllocator {
36+
/// The init could be done only once.
37+
unsafe fn init(&self, start: PhyPageNum, end: PhyPageNum) {
38+
let mut guard = self.inner.lock();
39+
guard.start = start;
40+
guard.end = end;
41+
guard.recycled.clear();
42+
}
43+
44+
fn alloc_page(&self) -> PhyPageNum {
45+
let mut guard = self.inner.lock();
46+
let candidate = guard.recycled.pop();
47+
if let Some(ppn) = candidate {
48+
ppn
49+
} else if guard.start < guard.end {
50+
let ppn = guard.start;
51+
guard.start += 1;
52+
ppn
53+
} else {
54+
PhyPageNum::null()
55+
}
56+
}
57+
58+
fn dealloc_page(&self, ppn: PhyPageNum) {
59+
self.inner.lock().recycled.push(ppn);
60+
}
61+
}

kernel/src/mem/normal/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use crate::{config::MEMORY_END, mem::allocator::PageAllocator};
2+
3+
use self::allocator::FrameAllocator;
4+
5+
pub mod allocator;
6+
pub mod page;
7+
8+
pub static FRAME_ALLOCATOR: FrameAllocator = FrameAllocator::default();
9+
10+
pub fn init_frame_allocator() {
11+
extern "C" {
12+
fn ekernel();
13+
}
14+
unsafe { FRAME_ALLOCATOR.init((ekernel as usize).into(), MEMORY_END.into()) };
15+
}

kernel/src/mem/normal/page.rs

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use core::ops::{Deref, DerefMut};
2+
3+
use spin::SpinGuard;
4+
5+
use crate::{
6+
config::PAGE_SIZE,
7+
mem::{allocator::PageAllocator, page::Page},
8+
mm::address::PhyPageNum,
9+
};
10+
11+
use super::FRAME_ALLOCATOR;
12+
13+
/// One possible representation of metadata of page, when the page is used by the page table.
14+
///
15+
/// Here, **pt** stands for page table.
16+
#[derive(Debug)]
17+
pub struct NormalPage {
18+
pub ppn: PhyPageNum,
19+
pub refcnt: usize,
20+
}
21+
22+
pub struct NormalPageHandle {
23+
pub ppn: PhyPageNum,
24+
}
25+
26+
/// Automatically fetch the lock, returning the guard.
27+
pub struct NormalPageGuard<'a> {
28+
pub ppn: PhyPageNum,
29+
guard: SpinGuard<'a, Page>,
30+
}
31+
32+
impl NormalPage {
33+
/// Create a page with referencing count is equal to 1.
34+
pub fn alloc(ppn: PhyPageNum) {
35+
*Page::from_ppn(ppn).lock() = Page::Normal(Self { ppn, refcnt: 1 });
36+
}
37+
}
38+
39+
impl NormalPageHandle {
40+
pub fn new() -> Self {
41+
let ppn = FRAME_ALLOCATOR.alloc_page();
42+
NormalPage::alloc(ppn);
43+
44+
// init
45+
let handle = Self { ppn };
46+
handle.init();
47+
handle
48+
}
49+
50+
pub fn init(&self) {
51+
let ptr = usize::from(self.ppn) as *mut u8;
52+
unsafe {
53+
core::slice::from_raw_parts_mut(ptr, PAGE_SIZE).fill(0);
54+
}
55+
}
56+
}
57+
58+
impl Drop for NormalPageHandle {
59+
fn drop(&mut self) {
60+
let cnt = {
61+
let mut page = NormalPageGuard::new(self.ppn);
62+
page.refcnt -= 1;
63+
page.refcnt
64+
};
65+
if cnt == 0 {
66+
FRAME_ALLOCATOR.dealloc_page(self.ppn);
67+
}
68+
}
69+
}
70+
71+
impl<'a> NormalPageGuard<'a> {
72+
pub fn new(ppn: PhyPageNum) -> Self {
73+
let guard = Page::from_ppn(ppn).lock();
74+
Self { ppn, guard }
75+
}
76+
}
77+
78+
impl<'a> Deref for NormalPageGuard<'a> {
79+
type Target = NormalPage;
80+
81+
fn deref(&self) -> &Self::Target {
82+
self.guard.as_normal()
83+
}
84+
}
85+
86+
impl<'a> DerefMut for NormalPageGuard<'a> {
87+
fn deref_mut(&mut self) -> &mut Self::Target {
88+
self.guard.as_normal_mut()
89+
}
90+
}

kernel/src/mem/page.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,18 @@ use crate::{
77
mm::address::PhyPageNum,
88
};
99

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

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

1515
#[derive(Debug)]
1616
pub enum Page {
1717
Slab(SlabPage),
18-
Pt(PtPage),
18+
Normal(NormalPage),
1919
User(UserPage),
2020
}
2121

22-
pub trait Pageable {
23-
fn new_page(pa: PhyPageNum) -> Page;
24-
}
25-
2622
impl Page {
2723
pub fn from_pa(pa: usize) -> &'static Spin<Page> {
2824
unsafe { MEM_MAP[(pa - KERNEL_START) / PAGE_SIZE].assume_init_ref() }
@@ -48,17 +44,17 @@ impl Page {
4844
}
4945
}
5046

51-
pub fn as_pt(&self) -> &PtPage {
47+
pub fn as_normal(&self) -> &NormalPage {
5248
match self {
53-
Page::Pt(pt) => pt,
54-
_ => panic!("Page is not a page table page"),
49+
Page::Normal(normal) => normal,
50+
_ => panic!("Page is not a normal page"),
5551
}
5652
}
5753

58-
pub fn as_pt_mut(&mut self) -> &mut PtPage {
54+
pub fn as_normal_mut(&mut self) -> &mut NormalPage {
5955
match self {
60-
Page::Pt(pt) => pt,
61-
_ => panic!("Page is not a page table page"),
56+
Page::Normal(normal) => normal,
57+
_ => panic!("Page is not a normal page"),
6258
}
6359
}
6460

kernel/src/mem/pt.rs

-13
This file was deleted.

kernel/src/mem/slab/allocator.rs

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use core::alloc::GlobalAlloc;
88
use core::cmp::{max, min};
99
use core::mem::size_of;
1010
use core::ptr::null_mut;
11-
use core::sync::atomic::AtomicUsize;
1211
use spin::{Spin, SpinGuard};
1312

1413
const BUDDY_ALLOCATOR_LEVEL: usize = 32;

kernel/src/mem/slab/cache.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ impl Cache {
3030
page.ppn
3131
} else {
3232
// allocate new from buddy allocator
33-
let ptr = usize::from(unsafe { SLAB_MEM_SECTION.alloc() });
34-
debugln!("Buddy allocates {:#x}.", ptr);
33+
let ptr = unsafe { SLAB_MEM_SECTION.alloc() };
34+
debugln!("Buddy allocates {:#x}.", usize::from(ptr));
3535
SlabPage::alloc(ptr, self.order as u8);
3636
ptr.into()
3737
};

kernel/src/mem/slab/page.rs

+9-29
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,14 @@ use core::ops::{Deref, DerefMut};
33
use allocator::linked_list::LinkedList;
44
use spin::SpinGuard;
55

6-
use crate::{
7-
config::PAGE_SIZE,
8-
mem::page::{Page, Pageable},
9-
mm::address::PhyPageNum,
10-
};
6+
use crate::{config::PAGE_SIZE, mem::page::Page, mm::address::PhyPageNum};
117

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

1915
order: u8,
2016

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

3329
impl SlabPage {
34-
pub fn new(pa: usize, order: u8) -> SlabPage {
30+
pub fn alloc(ppn: PhyPageNum, order: u8) {
3531
let mut slab_page = Self {
36-
pa,
32+
ppn,
3733
order,
3834
prev: PhyPageNum::null(),
3935
next: PhyPageNum::null(),
4036
free: LinkedList::new(),
4137
inuse: 0,
4238
};
4339
slab_page.init();
44-
slab_page
45-
}
46-
47-
pub fn alloc(pa: usize, order: u8) {
48-
let mut slab_page = Self {
49-
pa,
50-
order,
51-
prev: PhyPageNum::null(),
52-
next: PhyPageNum::null(),
53-
free: LinkedList::new(),
54-
inuse: 0,
55-
};
56-
slab_page.init();
57-
*Page::from_pa(pa).lock() = Page::Slab(slab_page);
40+
*Page::from_ppn(ppn).lock() = Page::Slab(slab_page);
5841
}
5942

6043
pub fn init(&mut self) {
6144
let size = 1 << self.order;
6245
self.free = LinkedList::new();
6346
(0..PAGE_SIZE / size).rev().for_each(|i| {
64-
unsafe { self.free.push_front((self.pa + i * size) as *mut usize) };
47+
unsafe {
48+
self.free
49+
.push_front((usize::from(self.ppn) + i * size) as *mut usize)
50+
};
6551
});
6652
}
6753

@@ -89,12 +75,6 @@ impl SlabPage {
8975
}
9076
}
9177

92-
impl Pageable for SlabPage {
93-
fn new_page(pa: PhyPageNum) -> Page {
94-
Page::Slab(SlabPage::new(pa.into(), 0))
95-
}
96-
}
97-
9878
impl<'a> SlabPageGuard<'a> {
9979
pub fn new(ppn: PhyPageNum) -> Self {
10080
let guard = Page::from_ppn(ppn).lock();

0 commit comments

Comments
 (0)