Revert "新的内存管理模块 (#301)" (#302)

This reverts commit d8ad0a5e77.
This commit is contained in:
LoGin
2023-07-22 16:24:55 +08:00
committed by GitHub
parent d8ad0a5e77
commit bb5f098a86
124 changed files with 5151 additions and 8278 deletions

27
kernel/src/mm/Makefile Normal file
View File

@ -0,0 +1,27 @@
CFLAGS += -I .
all:mm.o slab.o mm-stat.o vma.o mmap.o utils.o mmio.o
mm.o: mm.c
$(CC) $(CFLAGS) -c mm.c -o mm.o
slab.o: slab.c
$(CC) $(CFLAGS) -c slab.c -o slab.o
mm-stat.o: mm-stat.c
$(CC) $(CFLAGS) -c mm-stat.c -o mm-stat.o
vma.o: vma.c
$(CC) $(CFLAGS) -c vma.c -o vma.o
mmap.o: mmap.c
$(CC) $(CFLAGS) -c mmap.c -o mmap.o
utils.o: utils.c
$(CC) $(CFLAGS) -c utils.c -o utils.o
mmio.o: mmio.c
$(CC) $(CFLAGS) -c mmio.c -o mmio.o

View File

@ -0,0 +1,55 @@
use super::gfp::__GFP_ZERO;
use crate::include::bindings::bindings::{gfp_t, kfree, kmalloc, PAGE_2M_SIZE};
use core::alloc::{GlobalAlloc, Layout};
/// 类kmalloc的分配器应当实现的trait
pub trait LocalAlloc {
unsafe fn local_alloc(&self, layout: Layout, gfp: gfp_t) -> *mut u8;
unsafe fn local_alloc_zeroed(&self, layout: Layout, gfp: gfp_t) -> *mut u8;
unsafe fn local_dealloc(&self, ptr: *mut u8, layout: Layout);
}
pub struct KernelAllocator {}
/// 为内核SLAB分配器实现LocalAlloc的trait
impl LocalAlloc for KernelAllocator {
unsafe fn local_alloc(&self, layout: Layout, gfp: gfp_t) -> *mut u8 {
if layout.size() > (PAGE_2M_SIZE as usize / 2) {
return core::ptr::null_mut();
}
return kmalloc(layout.size() as u64, gfp) as *mut u8;
}
unsafe fn local_alloc_zeroed(&self, layout: Layout, gfp: gfp_t) -> *mut u8 {
if layout.size() > (PAGE_2M_SIZE as usize / 2) {
return core::ptr::null_mut();
}
return kmalloc(layout.size() as u64, gfp | __GFP_ZERO) as *mut u8;
}
#[allow(unused_variables)]
unsafe fn local_dealloc(&self, ptr: *mut u8, layout: Layout) {
kfree(ptr as *mut ::core::ffi::c_void);
}
}
/// 为内核slab分配器实现GlobalAlloc特性
unsafe impl GlobalAlloc for KernelAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
self.local_alloc(layout, 0)
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
self.local_alloc_zeroed(layout, 0)
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.local_dealloc(ptr, layout);
}
}
/// 内存分配错误处理函数
#[alloc_error_handler]
pub fn global_alloc_err_handler(layout: Layout) -> ! {
panic!("global_alloc_error, layout: {:?}", layout);
}

View File

@ -1,667 +0,0 @@
/// @Author: longjin@dragonos.org
/// @Author: kongweichao@dragonos.org
/// @Date: 2023-03-28 16:03:47
/// @FilePath: /DragonOS/kernel/src/mm/allocator/buddy.rs
/// @Description: 伙伴分配器
use crate::arch::MMArch;
use crate::mm::allocator::bump::BumpAllocator;
use crate::mm::allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage};
use crate::mm::{MemoryManagementArch, PhysAddr, VirtAddr};
use crate::{kdebug, kerror, kwarn};
use core::cmp::{max, min};
use core::fmt::Debug;
use core::intrinsics::{likely, unlikely};
use core::{marker::PhantomData, mem};
// 一个全局变量MAX_ORDER用来表示buddy算法的最大阶数 [MIN_ORDER, MAX_ORDER)左闭右开区间
const MAX_ORDER: usize = 31;
// 4KB
const MIN_ORDER: usize = 12;
/// 保存buddy算法中每一页存放的BuddyEntry的信息占据每个页的起始位置
#[derive(Debug)]
pub struct PageList<A> {
// 页存放entry的数量
entry_num: usize,
// 下一个页面的地址
next_page: PhysAddr,
phantom: PhantomData<A>,
}
impl<A> Clone for PageList<A> {
fn clone(&self) -> Self {
Self {
entry_num: self.entry_num,
next_page: self.next_page,
phantom: PhantomData,
}
}
}
impl<A> PageList<A> {
#[allow(dead_code)]
fn empty() -> Self {
Self {
entry_num: 0,
next_page: PhysAddr::new(0),
phantom: PhantomData,
}
}
fn new(entry_num: usize, next_page: PhysAddr) -> Self {
Self {
entry_num,
next_page,
phantom: PhantomData,
}
}
}
/// @brief: 用来表示 buddy 算法中的一个 buddy 块整体存放在area的头部
// 这种方式会出现对齐问题
// #[repr(packed)]
#[repr(C)]
#[derive(Debug)]
pub struct BuddyAllocator<A> {
// 存放每个阶的空闲“链表”的头部地址
free_area: [PhysAddr; (MAX_ORDER - MIN_ORDER) as usize],
phantom: PhantomData<A>,
}
impl<A: MemoryManagementArch> BuddyAllocator<A> {
const BUDDY_ENTRIES: usize =
// 定义一个变量记录buddy表的大小
(A::PAGE_SIZE - mem::size_of::<PageList<A>>()) / mem::size_of::<PhysAddr>();
pub unsafe fn new(mut bump_allocator: BumpAllocator<A>) -> Option<Self> {
let initial_free_pages = bump_allocator.usage().free();
kdebug!("Free pages before init buddy: {:?}", initial_free_pages);
kdebug!("Buddy entries: {}", Self::BUDDY_ENTRIES);
// 最高阶的链表页数
let max_order_linked_list_page_num = max(
1,
(((initial_free_pages.data() * A::PAGE_SIZE) >> (MAX_ORDER - 1)) + Self::BUDDY_ENTRIES
- 1)
/ Self::BUDDY_ENTRIES,
);
let mut free_area: [PhysAddr; (MAX_ORDER - MIN_ORDER) as usize] =
[PhysAddr::new(0); (MAX_ORDER - MIN_ORDER) as usize];
// Buddy初始占用的空间从bump分配
for f in free_area.iter_mut() {
let curr_page = bump_allocator.allocate_one();
// 保存每个阶的空闲链表的头部地址
*f = curr_page.unwrap();
// 清空当前页
core::ptr::write_bytes(MMArch::phys_2_virt(*f)?.data() as *mut u8, 0, A::PAGE_SIZE);
let page_list: PageList<A> = PageList::new(0, PhysAddr::new(0));
Self::write_page(*f, page_list);
}
// 分配最高阶的链表页
for _ in 1..max_order_linked_list_page_num {
let curr_page = bump_allocator.allocate_one().unwrap();
// 清空当前页
core::ptr::write_bytes(
MMArch::phys_2_virt(curr_page)?.data() as *mut u8,
0,
A::PAGE_SIZE,
);
let page_list: PageList<A> =
PageList::new(0, free_area[Self::order2index((MAX_ORDER - 1) as u8)]);
Self::write_page(curr_page, page_list);
free_area[Self::order2index((MAX_ORDER - 1) as u8)] = curr_page;
}
let initial_bump_offset = bump_allocator.offset();
let pages_to_buddy = bump_allocator.usage().free();
kdebug!("pages_to_buddy {:?}", pages_to_buddy);
// kdebug!("initial_bump_offset {:#x}", initial_bump_offset);
let mut paddr = initial_bump_offset;
let mut remain_pages = pages_to_buddy;
// 设置entry,这里假设了bump_allocator当前offset之后所有的area的地址是连续的.
// TODO: 这里需要修改按照area来处理
for i in MIN_ORDER..MAX_ORDER {
// kdebug!("i {i}, remain pages={}", remain_pages.data());
if remain_pages.data() < (1 << (i - MIN_ORDER)) {
break;
}
assert!(paddr & ((1 << i) - 1) == 0);
if likely(i != MAX_ORDER - 1) {
// 要填写entry
if paddr & (1 << i) != 0 {
let page_list_paddr: PhysAddr = free_area[Self::order2index(i as u8)];
let mut page_list: PageList<A> = Self::read_page(page_list_paddr);
A::write(
Self::entry_virt_addr(page_list_paddr, page_list.entry_num),
paddr,
);
page_list.entry_num += 1;
Self::write_page(page_list_paddr, page_list);
paddr += 1 << i;
remain_pages -= 1 << (i - MIN_ORDER);
};
} else {
// 往最大的阶数的链表中添加entry注意要考虑到最大阶数的链表可能有多页
// 断言剩余页面数量是MAX_ORDER-1阶的整数倍
let mut entries = (remain_pages.data() * A::PAGE_SIZE) >> i;
let mut page_list_paddr: PhysAddr = free_area[Self::order2index(i as u8)];
let block_size = 1usize << i;
if entries > Self::BUDDY_ENTRIES {
// 在第一页填写一些entries
let num = entries % Self::BUDDY_ENTRIES;
entries -= num;
let mut page_list: PageList<A> = Self::read_page(page_list_paddr);
for _j in 0..num {
A::write(
Self::entry_virt_addr(page_list_paddr, page_list.entry_num),
paddr,
);
page_list.entry_num += 1;
paddr += block_size;
remain_pages -= 1 << (i - MIN_ORDER);
}
page_list_paddr = page_list.next_page;
Self::write_page(page_list_paddr, page_list);
assert!(!page_list_paddr.is_null());
}
while entries > 0 {
let mut page_list: PageList<A> = Self::read_page(page_list_paddr);
for _ in 0..Self::BUDDY_ENTRIES {
A::write(
Self::entry_virt_addr(page_list_paddr, page_list.entry_num),
paddr,
);
page_list.entry_num += 1;
paddr += block_size;
remain_pages -= 1 << (i - MIN_ORDER);
entries -= 1;
if entries == 0 {
break;
}
}
page_list_paddr = page_list.next_page;
Self::write_page(page_list_paddr, page_list);
if likely(entries > 0) {
assert!(!page_list_paddr.is_null());
}
}
}
}
let mut remain_bytes = remain_pages.data() * A::PAGE_SIZE;
assert!(remain_bytes < (1 << MAX_ORDER - 1));
for i in (MIN_ORDER..MAX_ORDER).rev() {
if remain_bytes & (1 << i) != 0 {
let page_list_paddr: PhysAddr = free_area[Self::order2index(i as u8)];
let mut page_list: PageList<A> = Self::read_page(page_list_paddr);
A::write(
Self::entry_virt_addr(page_list_paddr, page_list.entry_num),
paddr,
);
page_list.entry_num += 1;
Self::write_page(page_list_paddr, page_list);
paddr += 1 << i;
remain_bytes -= 1 << i;
}
}
assert!(remain_bytes == 0);
assert!(paddr == initial_bump_offset + pages_to_buddy.data() * A::PAGE_SIZE);
// Self::print_free_area(free_area);
let allocator = Self {
free_area,
phantom: PhantomData,
};
Some(allocator)
}
/// 获取第j个entry的虚拟地址
/// j从0开始计数
pub fn entry_virt_addr(base_addr: PhysAddr, j: usize) -> VirtAddr {
let entry_virt_addr = unsafe { A::phys_2_virt(Self::entry_addr(base_addr, j)) };
return entry_virt_addr.unwrap();
}
pub fn entry_addr(base_addr: PhysAddr, j: usize) -> PhysAddr {
let entry_addr = base_addr + mem::size_of::<PageList<A>>() + j * mem::size_of::<PhysAddr>();
return entry_addr;
}
pub fn read_page<T>(addr: PhysAddr) -> T {
let page_list = unsafe { A::read(A::phys_2_virt(addr).unwrap()) };
return page_list;
}
pub fn write_page(curr_page: PhysAddr, page_list: PageList<A>) {
// 把物理地址转换为虚拟地址
let virt_addr = unsafe { A::phys_2_virt(curr_page) };
let virt_addr = virt_addr.unwrap();
unsafe { A::write(virt_addr, page_list) };
}
/// 从order转换为free_area的下标
///
/// # 参数
///
/// - `order` - order
///
/// # 返回值
///
/// free_area的下标
#[inline]
fn order2index(order: u8) -> usize {
(order as usize - MIN_ORDER) as usize
}
/// 从空闲链表的开头取出1个指定阶数的伙伴块如果没有则返回None
///
/// ## 参数
///
/// - `order` - 伙伴块的阶数
fn pop_front(&mut self, order: u8) -> Option<PhysAddr> {
let mut alloc_in_specific_order = |spec_order: u8| {
// 先尝试在order阶的“空闲链表”的开头位置分配一个伙伴块
let mut page_list_addr = self.free_area[Self::order2index(spec_order)];
let mut page_list: PageList<A> = Self::read_page(page_list_addr);
// kdebug!("page_list={page_list:?}");
// 循环删除头部的空闲链表页
while page_list.entry_num == 0 {
let next_page_list_addr = page_list.next_page;
// 找完了,都是空的
if next_page_list_addr.is_null() {
return None;
}
if !next_page_list_addr.is_null() {
// 此时page_list已经没有空闲伙伴块了又因为非唯一页需要删除该page_list
self.free_area[Self::order2index(spec_order)] = next_page_list_addr;
drop(page_list);
// kdebug!("FREE: page_list_addr={:b}", page_list_addr.data());
unsafe {
self.buddy_free(page_list_addr, MMArch::PAGE_SHIFT as u8);
}
}
// 由于buddy_free可能导致首部的链表页发生变化因此需要重新读取
let next_page_list_addr = self.free_area[Self::order2index(spec_order)];
assert!(!next_page_list_addr.is_null());
page_list = Self::read_page(next_page_list_addr);
page_list_addr = next_page_list_addr;
}
// 有空闲页面,直接分配
if page_list.entry_num > 0 {
let entry: PhysAddr = unsafe {
A::read(Self::entry_virt_addr(
page_list_addr,
page_list.entry_num - 1,
))
};
if entry.is_null() {
kerror!(
"entry is null, entry={:?}, order={}, entry_num = {}",
entry,
spec_order,
page_list.entry_num - 1
);
}
// kdebug!("entry={entry:?}");
// 更新page_list的entry_num
page_list.entry_num -= 1;
let tmp_current_entry_num = page_list.entry_num;
if page_list.entry_num == 0 {
if !page_list.next_page.is_null() {
// 此时page_list已经没有空闲伙伴块了又因为非唯一页需要删除该page_list
self.free_area[Self::order2index(spec_order)] = page_list.next_page;
drop(page_list);
unsafe { self.buddy_free(page_list_addr, MMArch::PAGE_SHIFT as u8) };
} else {
Self::write_page(page_list_addr, page_list);
}
} else {
// 若entry_num不为0说明该page_list还有空闲伙伴块需要更新该page_list
// 把更新后的page_list写回
Self::write_page(page_list_addr, page_list.clone());
}
// 检测entry 是否对齐
if !entry.check_aligned(1 << spec_order) {
panic!("entry={:?} is not aligned, spec_order={spec_order}, page_list.entry_num={}", entry,tmp_current_entry_num);
}
return Some(entry);
}
return None;
};
let result: Option<PhysAddr> = alloc_in_specific_order(order as u8);
// kdebug!("result={:?}", result);
if result.is_some() {
return result;
}
// 尝试从更大的链表中分裂
let mut current_order = (order + 1) as usize;
let mut x: Option<PhysAddr> = None;
while current_order < MAX_ORDER {
x = alloc_in_specific_order(current_order as u8);
// kdebug!("current_order={:?}", current_order);
if x.is_some() {
break;
}
current_order += 1;
}
// kdebug!("x={:?}", x);
// 如果找到一个大的块,就进行分裂
if x.is_some() {
// 分裂到order阶
while current_order > order as usize {
current_order -= 1;
// 把后面那半块放回空闲链表
let buddy = *x.as_ref().unwrap() + (1 << current_order);
// kdebug!("x={:?}, buddy={:?}", x, buddy);
// kdebug!("current_order={:?}, buddy={:?}", current_order, buddy);
unsafe { self.buddy_free(buddy, current_order as u8) };
}
return x;
}
return None;
}
/// 从伙伴系统中分配count个页面
///
/// ## 参数
///
/// - `count`:需要分配的页面数
///
/// ## 返回值
///
/// 返回分配的页面的物理地址和页面数
fn buddy_alloc(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
assert!(count.data().is_power_of_two());
// 计算需要分配的阶数
let mut order = log2(count.data() as usize);
if count.data() & ((1 << order) - 1) != 0 {
order += 1;
}
let order = (order + MIN_ORDER) as u8;
if order as usize >= MAX_ORDER {
return None;
}
// kdebug!("buddy_alloc: order = {}", order);
// 获取该阶数的一个空闲页面
let free_addr = self.pop_front(order);
// kdebug!(
// "buddy_alloc: order = {}, free_addr = {:?}",
// order,
// free_addr
// );
return free_addr
.map(|addr| (addr, PageFrameCount::new(1 << (order as usize - MIN_ORDER))));
}
/// 释放一个块
///
/// ## 参数
///
/// - `base` - 块的起始地址
/// - `order` - 块的阶数
unsafe fn buddy_free(&mut self, mut base: PhysAddr, order: u8) {
// kdebug!("buddy_free: base = {:?}, order = {}", base, order);
let mut order = order as usize;
while order < MAX_ORDER {
// 检测地址是否合法
if base.data() & ((1 << (order)) - 1) != 0 {
panic!(
"buddy_free: base is not aligned, base = {:#x}, order = {}",
base.data(),
order
);
}
// 在链表中寻找伙伴块
// 伙伴块的地址是base ^ (1 << order)
let buddy_addr = PhysAddr::new(base.data() ^ (1 << order));
let first_page_list_paddr = self.free_area[Self::order2index(order as u8)];
let mut page_list_paddr = first_page_list_paddr;
let mut page_list: PageList<A> = Self::read_page(page_list_paddr);
let first_page_list = page_list.clone();
let mut buddy_entry_virt_vaddr = None;
let mut buddy_entry_page_list_paddr = None;
// 除非order是最大的否则尝试查找伙伴块
if likely(order != MAX_ORDER - 1) {
'outer: loop {
for i in 0..page_list.entry_num {
let entry_virt_addr = Self::entry_virt_addr(page_list_paddr, i);
let entry: PhysAddr = unsafe { A::read(entry_virt_addr) };
if entry == buddy_addr {
// 找到了伙伴块记录该entry相关信息然后退出查找
buddy_entry_virt_vaddr = Some(entry_virt_addr);
buddy_entry_page_list_paddr = Some(page_list_paddr);
break 'outer;
}
}
if page_list.next_page.is_null() {
break;
}
page_list_paddr = page_list.next_page;
page_list = Self::read_page(page_list_paddr);
}
}
// 如果没有找到伙伴块
if buddy_entry_virt_vaddr.is_none() {
assert!(
page_list.entry_num <= Self::BUDDY_ENTRIES,
"buddy_free: page_list.entry_num > Self::BUDDY_ENTRIES"
);
// 当前第一个page_list没有空间了
if first_page_list.entry_num == Self::BUDDY_ENTRIES {
// 如果当前order是最小的那么就把这个块当作新的page_list使用
let new_page_list_addr = if order == MIN_ORDER {
base
} else {
// 否则分配新的page_list
// 请注意分配之后有可能当前的entry_num会减1伙伴块分裂造成出现整个链表为null的entry数量为Self::BUDDY_ENTRIES+1的情况
// 但是不影响我们在后面插入链表项的时候会处理这种情况检查链表中的第2个页是否有空位
self.buddy_alloc(PageFrameCount::new(1))
.expect("buddy_alloc failed: no enough memory")
.0
};
// 清空这个页面
core::ptr::write_bytes(
A::phys_2_virt(new_page_list_addr)
.expect(
"Buddy free: failed to get virt address of [new_page_list_addr]",
)
.as_ptr::<u8>(),
0,
1 << order,
);
assert!(
first_page_list_paddr == self.free_area[Self::order2index(order as u8)]
);
// 初始化新的page_list
let new_page_list = PageList::new(0, first_page_list_paddr);
Self::write_page(new_page_list_addr, new_page_list);
self.free_area[Self::order2index(order as u8)] = new_page_list_addr;
}
// 由于上面可能更新了第一个链表页,因此需要重新获取这个值
let first_page_list_paddr = self.free_area[Self::order2index(order as u8)];
let first_page_list: PageList<A> = Self::read_page(first_page_list_paddr);
// 检查第二个page_list是否有空位
let second_page_list = if first_page_list.next_page.is_null() {
None
} else {
Some(Self::read_page::<PageList<A>>(first_page_list.next_page))
};
let (paddr, mut page_list) = if let Some(second) = second_page_list {
// 第二个page_list有空位
// 应当符合之前的假设还有1个空位
assert!(second.entry_num == Self::BUDDY_ENTRIES - 1);
(first_page_list.next_page, second)
} else {
// 在第一个page list中分配
(first_page_list_paddr, first_page_list)
};
// kdebug!("to write entry, page_list_base={paddr:?}, page_list.entry_num={}, value={base:?}", page_list.entry_num);
assert!(page_list.entry_num < Self::BUDDY_ENTRIES);
// 把要归还的块,写入到链表项中
unsafe { A::write(Self::entry_virt_addr(paddr, page_list.entry_num), base) }
page_list.entry_num += 1;
Self::write_page(paddr, page_list);
return;
} else {
// 如果找到了伙伴块,合并,向上递归
// 伙伴块所在的表项的虚拟地址
let buddy_entry_virt_addr = buddy_entry_virt_vaddr.unwrap();
// 伙伴块所在的page_list的物理地址
let buddy_entry_page_list_paddr = buddy_entry_page_list_paddr.unwrap();
let mut page_list_paddr = self.free_area[Self::order2index(order as u8)];
let mut page_list = Self::read_page::<PageList<A>>(page_list_paddr);
// 找第一个有空闲块的链表页。跳过空闲链表页。不进行回收的原因是担心出现死循环
while page_list.entry_num == 0 {
if page_list.next_page.is_null() {
panic!(
"buddy_free: page_list.entry_num == 0 && page_list.next_page.is_null()"
);
}
page_list_paddr = page_list.next_page;
page_list = Self::read_page(page_list_paddr);
}
// 如果伙伴块不在第一个链表页,则把第一个链表中的某个空闲块替换到伙伴块的位置
if page_list_paddr != buddy_entry_page_list_paddr {
let entry: PhysAddr = unsafe {
A::read(Self::entry_virt_addr(
page_list_paddr,
page_list.entry_num - 1,
))
};
// 把这个空闲块写入到伙伴块的位置
unsafe {
A::write(buddy_entry_virt_addr, entry);
}
// 设置刚才那个entry为空
unsafe {
A::write(
Self::entry_virt_addr(page_list_paddr, page_list.entry_num - 1),
PhysAddr::new(0),
);
}
// 更新当前链表页的统计数据
page_list.entry_num -= 1;
Self::write_page(page_list_paddr, page_list);
} else {
// 伙伴块所在的链表页就是第一个链表页
let last_entry: PhysAddr = unsafe {
A::read(Self::entry_virt_addr(
page_list_paddr,
page_list.entry_num - 1,
))
};
// 如果最后一个空闲块不是伙伴块,则把最后一个空闲块移动到伙伴块的位置
// 否则后面的操作也将删除这个伙伴块
if last_entry != buddy_addr {
unsafe {
A::write(buddy_entry_virt_addr, last_entry);
A::write(
Self::entry_virt_addr(page_list_paddr, page_list.entry_num - 1),
PhysAddr::new(0),
);
}
} else {
unsafe {
A::write(
Self::entry_virt_addr(page_list_paddr, page_list.entry_num - 1),
PhysAddr::new(0),
);
}
}
// 更新当前链表页的统计数据
page_list.entry_num -= 1;
Self::write_page(page_list_paddr, page_list);
}
}
base = min(base, buddy_addr);
order += 1;
}
// 走到这一步order应该为MAX_ORDER-1
assert!(order == MAX_ORDER - 1);
}
}
impl<A: MemoryManagementArch> FrameAllocator for BuddyAllocator<A> {
unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
return self.buddy_alloc(count);
}
/// 释放一个块
///
/// ## 参数
///
/// - `base` - 块的起始地址
/// - `count` - 块的页数必须是2的幂
///
/// ## Panic
///
/// 如果count不是2的幂会panic
unsafe fn free(&mut self, base: PhysAddr, count: PageFrameCount) {
// 要求count是2的幂
if unlikely(!count.data().is_power_of_two()) {
kwarn!("buddy free: count is not power of two");
}
let mut order = log2(count.data() as usize);
if count.data() & ((1 << order) - 1) != 0 {
order += 1;
}
let order = (order + MIN_ORDER) as u8;
// kdebug!("free: base={:?}, count={:?}", base, count);
self.buddy_free(base, order);
}
unsafe fn usage(&self) -> PageFrameUsage {
todo!("BuddyAllocator::usage")
}
}
/// 一个用于计算整数的对数的函数,会向下取整。(由于内核不能进行浮点运算,因此需要这个函数)
fn log2(x: usize) -> usize {
let leading_zeros = x.leading_zeros() as usize;
let log2x = 63 - leading_zeros;
return log2x;
}

View File

@ -1,112 +0,0 @@
/// @Auther: Kong
/// @Date: 2023-03-27 06:54:08
/// @FilePath: /DragonOS/kernel/src/mm/allocator/bump.rs
/// @Description: bump allocator线性分配器
use super::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage};
use crate::mm::{MemoryManagementArch, PhysAddr, PhysMemoryArea};
use core::marker::PhantomData;
/// 线性分配器
pub struct BumpAllocator<MMA> {
// 表示可用物理内存区域的数组。每个 PhysMemoryArea 结构体描述一个物理内存区域的起始地址和大小。
areas: &'static [PhysMemoryArea],
// 表示当前分配的物理内存的偏移量.
offset: usize,
// 一个占位类型,用于标记 A 类型在结构体中的存在。但是,它并不会占用任何内存空间,因为它的大小为 0。
phantom: PhantomData<MMA>,
}
/// 为BumpAllocator实现FrameAllocator
impl<MMA: MemoryManagementArch> BumpAllocator<MMA> {
/// @brief: 创建一个线性分配器
/// @param Fareas 当前的内存区域
/// @param offset 当前的偏移量
/// @return 分配器本身
pub fn new(areas: &'static [PhysMemoryArea], offset: usize) -> Self {
Self {
areas,
offset,
phantom: PhantomData,
}
}
// @brief 获取页帧使用情况
pub fn areas(&self) -> &'static [PhysMemoryArea] {
return self.areas;
}
// @brief 获取当前分配的物理内存的偏移量
pub fn offset(&self) -> usize {
return self.offset;
}
}
impl<MMA: MemoryManagementArch> FrameAllocator for BumpAllocator<MMA> {
/// @brief: 分配count个物理页帧
/// @param mut self
/// @param count 分配的页帧数量
/// @return 分配后的物理地址
unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
let mut offset = self.offset();
// 遍历所有的物理内存区域
for area in self.areas().iter() {
// 将area的base地址与PAGE_SIZE对齐对齐时向上取整
// let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
let area_base = (area.base.data() + (MMA::PAGE_SIZE - 1)) & !(MMA::PAGE_SIZE - 1);
// 将area的末尾地址与PAGE_SIZE对齐对齐时向下取整
// let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SIZE - 1);
// 如果offset大于area_end说明当前的物理内存区域已经分配完了需要跳到下一个物理内存区域
if offset >= area_end {
continue;
}
// 如果offset小于area_base ,说明当前的物理内存区域还没有分配过页帧将offset设置为area_base
if offset < area_base {
offset = area_base;
} else if offset < area_end {
// 将offset对齐到PAGE_SIZE
offset = (offset + (MMA::PAGE_SIZE - 1)) & !(MMA::PAGE_SIZE - 1);
}
// 如果当前offset到area_end的距离大于等于count.data() * PAGE_SIZE说明当前的物理内存区域足以分配count个页帧
if offset + count.data() * MMA::PAGE_SIZE <= area_end {
let res_page_phys = offset;
// 将offset增加至分配后的内存
self.offset = offset + count.data() * MMA::PAGE_SIZE;
return Some((PhysAddr(res_page_phys), count));
}
}
return None;
}
unsafe fn free(&mut self, _address: PhysAddr, _count: PageFrameCount) {
// TODO: 支持释放页帧
unimplemented!("BumpAllocator::free not implemented");
}
/// @brief: 获取内存区域页帧的使用情况
/// @param self
/// @return 页帧的使用情况
unsafe fn usage(&self) -> PageFrameUsage {
let mut total = 0;
let mut used = 0;
for area in self.areas().iter() {
// 将area的base地址与PAGE_SIZE对齐对其时向上取整
let area_base = (area.base.data() + MMA::PAGE_SHIFT) & !(MMA::PAGE_SHIFT);
// 将area的末尾地址与PAGE_SIZE对齐对其时向下取整
let area_end = (area.base.data() + area.size) & !(MMA::PAGE_SHIFT);
total += (area_end - area_base) >> MMA::PAGE_SHIFT;
// 如果offset大于area_end说明当前物理区域被分配完都需要加到used中
if self.offset >= area_end {
used += (area_end - area_base) >> MMA::PAGE_SHIFT;
} else if self.offset < area_base {
// 如果offset小于area_base说明当前物理区域还没有分配过页帧都不需要加到used中
continue;
} else {
used += (self.offset - area_base) >> MMA::PAGE_SHIFT;
}
}
let frame = PageFrameUsage::new(PageFrameCount::new(used), PageFrameCount::new(total));
return frame;
}
}

View File

@ -1,101 +0,0 @@
use crate::{
arch::mm::LockedFrameAllocator,
libs::align::page_align_up,
mm::{MMArch, MemoryManagementArch, VirtAddr},
};
use core::{
alloc::{AllocError, GlobalAlloc, Layout},
intrinsics::unlikely,
ptr::NonNull,
};
use super::page_frame::{FrameAllocator, PageFrameCount};
/// 类kmalloc的分配器应当实现的trait
pub trait LocalAlloc {
unsafe fn local_alloc(&self, layout: Layout) -> *mut u8;
unsafe fn local_alloc_zeroed(&self, layout: Layout) -> *mut u8;
unsafe fn local_dealloc(&self, ptr: *mut u8, layout: Layout);
}
pub struct KernelAllocator;
impl KernelAllocator {
unsafe fn alloc_in_buddy(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
// 计算需要申请的页数,向上取整
let count = (page_align_up(layout.size()) / MMArch::PAGE_SIZE).next_power_of_two();
let page_frame_count = PageFrameCount::new(count);
let (phy_addr, allocated_frame_count) = LockedFrameAllocator
.allocate(page_frame_count)
.ok_or(AllocError)?;
let virt_addr = unsafe { MMArch::phys_2_virt(phy_addr).ok_or(AllocError)? };
if unlikely(virt_addr.is_null()) {
return Err(AllocError);
}
let slice = unsafe {
core::slice::from_raw_parts_mut(
virt_addr.data() as *mut u8,
allocated_frame_count.data() * MMArch::PAGE_SIZE,
)
};
return Ok(NonNull::from(slice));
}
unsafe fn free_in_buddy(&self, ptr: *mut u8, layout: Layout) {
// 由于buddy分配的页数量是2的幂因此释放的时候也需要按照2的幂向上取整。
let count = (page_align_up(layout.size()) / MMArch::PAGE_SIZE).next_power_of_two();
let page_frame_count = PageFrameCount::new(count);
let phy_addr = MMArch::virt_2_phys(VirtAddr::new(ptr as usize)).unwrap();
LockedFrameAllocator.free(phy_addr, page_frame_count);
}
}
/// 为内核SLAB分配器实现LocalAlloc的trait
impl LocalAlloc for KernelAllocator {
unsafe fn local_alloc(&self, layout: Layout) -> *mut u8 {
return self
.alloc_in_buddy(layout)
.map(|x| x.as_mut_ptr() as *mut u8)
.unwrap_or(core::ptr::null_mut() as *mut u8);
}
unsafe fn local_alloc_zeroed(&self, layout: Layout) -> *mut u8 {
return self
.alloc_in_buddy(layout)
.map(|x| {
let ptr: *mut u8 = x.as_mut_ptr();
core::ptr::write_bytes(ptr, 0, x.len());
ptr
})
.unwrap_or(core::ptr::null_mut() as *mut u8);
}
unsafe fn local_dealloc(&self, ptr: *mut u8, layout: Layout) {
self.free_in_buddy(ptr, layout);
}
}
/// 为内核slab分配器实现GlobalAlloc特性
unsafe impl GlobalAlloc for KernelAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
return self.local_alloc(layout);
// self.local_alloc_zeroed(layout, 0)
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
self.local_alloc_zeroed(layout)
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.local_dealloc(ptr, layout);
}
}
/// 内存分配错误处理函数
#[alloc_error_handler]
pub fn global_alloc_err_handler(layout: Layout) -> ! {
panic!("global_alloc_error, layout: {:?}", layout);
}

View File

@ -1,5 +0,0 @@
pub mod buddy;
pub mod bump;
pub mod kernel_allocator;
pub mod page_frame;
pub mod slab;

View File

@ -1,338 +0,0 @@
use core::{
intrinsics::unlikely,
ops::{Add, AddAssign, Mul, Sub, SubAssign},
};
use crate::{
arch::{mm::LockedFrameAllocator, MMArch},
mm::{MemoryManagementArch, PhysAddr, VirtAddr},
};
/// @brief 物理页帧的表示
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct PhysPageFrame {
/// 物理页页号
number: usize,
}
#[allow(dead_code)]
impl PhysPageFrame {
pub fn new(paddr: PhysAddr) -> Self {
return Self {
number: paddr.data() / MMArch::PAGE_SIZE,
};
}
/// @brief 获取当前页对应的物理地址
pub fn phys_address(&self) -> PhysAddr {
return PhysAddr::new(self.number * MMArch::PAGE_SIZE);
}
pub fn next_by(&self, n: usize) -> Self {
return Self {
number: self.number + n,
};
}
pub fn next(&self) -> Self {
return self.next_by(1);
}
/// 构造物理页帧的迭代器,范围为[start, end)
pub fn iter_range(start: Self, end: Self) -> PhysPageFrameIter {
return PhysPageFrameIter::new(start, end);
}
}
/// @brief 物理页帧的迭代器
#[derive(Debug)]
pub struct PhysPageFrameIter {
current: PhysPageFrame,
/// 结束的物理页帧(不包含)
end: PhysPageFrame,
}
impl PhysPageFrameIter {
pub fn new(start: PhysPageFrame, end: PhysPageFrame) -> Self {
return Self {
current: start,
end,
};
}
}
impl Iterator for PhysPageFrameIter {
type Item = PhysPageFrame;
fn next(&mut self) -> Option<Self::Item> {
if unlikely(self.current == self.end) {
return None;
}
let current = self.current.next();
return Some(current);
}
}
/// 虚拟页帧的表示
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct VirtPageFrame {
/// 虚拟页页号
number: usize,
}
impl VirtPageFrame {
pub fn new(vaddr: VirtAddr) -> Self {
return Self {
number: vaddr.data() / MMArch::PAGE_SIZE,
};
}
/// 获取当前虚拟页对应的虚拟地址
pub fn virt_address(&self) -> VirtAddr {
return VirtAddr::new(self.number * MMArch::PAGE_SIZE);
}
pub fn next_by(&self, n: usize) -> Self {
return Self {
number: self.number + n,
};
}
pub fn next(&self) -> Self {
return self.next_by(1);
}
/// 构造虚拟页帧的迭代器,范围为[start, end)
pub fn iter_range(start: Self, end: Self) -> VirtPageFrameIter {
return VirtPageFrameIter {
current: start,
end,
};
}
pub fn add(&self, n: PageFrameCount) -> Self {
return Self {
number: self.number + n.data(),
};
}
}
/// 虚拟页帧的迭代器
#[derive(Debug)]
pub struct VirtPageFrameIter {
current: VirtPageFrame,
/// 结束的虚拟页帧(不包含)
end: VirtPageFrame,
}
impl VirtPageFrameIter {
/// @brief 构造虚拟页帧的迭代器,范围为[start, end)
pub fn new(start: VirtPageFrame, end: VirtPageFrame) -> Self {
return Self {
current: start,
end,
};
}
}
impl Iterator for VirtPageFrameIter {
type Item = VirtPageFrame;
fn next(&mut self) -> Option<Self::Item> {
if unlikely(self.current == self.end) {
return None;
}
let current: VirtPageFrame = self.current;
self.current = self.current.next_by(1);
return Some(current);
}
}
/// 页帧使用的数量
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct PageFrameCount(usize);
impl PageFrameCount {
// @brief 初始化PageFrameCount
pub const fn new(count: usize) -> Self {
return Self(count);
}
// @brief 获取页帧数量
pub fn data(&self) -> usize {
return self.0;
}
/// 计算这一段页帧占用的字节数
pub fn bytes(&self) -> usize {
return self.0 * MMArch::PAGE_SIZE;
}
/// 将字节数转换为页帧数量
///
/// 如果字节数不是页帧大小的整数倍则返回None. 否则返回页帧数量
pub fn from_bytes(bytes: usize) -> Option<Self> {
if bytes & MMArch::PAGE_OFFSET_MASK != 0 {
return None;
} else {
return Some(Self(bytes / MMArch::PAGE_SIZE));
}
}
}
impl Add for PageFrameCount {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
return Self(self.0 + rhs.0);
}
}
impl AddAssign for PageFrameCount {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl Sub for PageFrameCount {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
return Self(self.0 - rhs.0);
}
}
impl SubAssign for PageFrameCount {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
impl Mul for PageFrameCount {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
return Self(self.0 * rhs.0);
}
}
impl Add<usize> for PageFrameCount {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
return Self(self.0 + rhs);
}
}
impl AddAssign<usize> for PageFrameCount {
fn add_assign(&mut self, rhs: usize) {
self.0 += rhs;
}
}
impl Sub<usize> for PageFrameCount {
type Output = Self;
fn sub(self, rhs: usize) -> Self::Output {
return Self(self.0 - rhs);
}
}
impl SubAssign<usize> for PageFrameCount {
fn sub_assign(&mut self, rhs: usize) {
self.0 -= rhs;
}
}
impl Mul<usize> for PageFrameCount {
type Output = Self;
fn mul(self, rhs: usize) -> Self::Output {
return Self(self.0 * rhs);
}
}
// 页帧使用情况
#[derive(Debug)]
pub struct PageFrameUsage {
used: PageFrameCount,
total: PageFrameCount,
}
#[allow(dead_code)]
impl PageFrameUsage {
/// @brief: 初始化FrameUsage
/// @param PageFrameCount used 已使用的页帧数量
/// @param PageFrameCount total 总的页帧数量
pub fn new(used: PageFrameCount, total: PageFrameCount) -> Self {
return Self { used, total };
}
// @brief 获取已使用的页帧数量
pub fn used(&self) -> PageFrameCount {
return self.used;
}
// @brief 获取空闲的页帧数量
pub fn free(&self) -> PageFrameCount {
return PageFrameCount(self.total.0 - self.used.0);
}
// @brief 获取总的页帧数量
pub fn total(&self) -> PageFrameCount {
return self.total;
}
}
/// 能够分配页帧的分配器需要实现的trait
pub trait FrameAllocator {
// @brief 分配count个页帧
unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)>;
// @brief 通过地址释放count个页帧
unsafe fn free(&mut self, address: PhysAddr, count: PageFrameCount);
// @brief 分配一个页帧
unsafe fn allocate_one(&mut self) -> Option<PhysAddr> {
return self.allocate(PageFrameCount::new(1)).map(|(addr, _)| addr);
}
// @brief 通过地址释放一个页帧
unsafe fn free_one(&mut self, address: PhysAddr) {
return self.free(address, PageFrameCount::new(1));
}
// @brief 获取页帧使用情况
unsafe fn usage(&self) -> PageFrameUsage;
}
/// @brief 通过一个 &mut T 的引用来对一个实现了 FrameAllocator trait 的类型进行调用,使代码更加灵活
impl<T: FrameAllocator> FrameAllocator for &mut T {
unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
return T::allocate(self, count);
}
unsafe fn free(&mut self, address: PhysAddr, count: PageFrameCount) {
return T::free(self, address, count);
}
unsafe fn allocate_one(&mut self) -> Option<PhysAddr> {
return T::allocate_one(self);
}
unsafe fn free_one(&mut self, address: PhysAddr) {
return T::free_one(self, address);
}
unsafe fn usage(&self) -> PageFrameUsage {
return T::usage(self);
}
}
/// @brief 从全局的页帧分配器中分配连续count个页帧
///
/// @param count 请求分配的页帧数量
pub unsafe fn allocate_page_frames(count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
let frame = unsafe { LockedFrameAllocator.allocate(count)? };
return Some(frame);
}
/// @brief 向全局页帧分配器释放连续count个页帧
///
/// @param frame 要释放的第一个页帧
/// @param count 要释放的页帧数量 (必须是2的n次幂)
pub unsafe fn deallocate_page_frames(frame: PhysPageFrame, count: PageFrameCount) {
unsafe {
LockedFrameAllocator.free(frame.phys_address(), count);
}
}

View File

@ -1,123 +0,0 @@
//! 当前slab分配器暂时不使用等待后续完善后合并主线
#![allow(dead_code)]
use core::alloc::Layout;
// 定义Slab用来存放空闲块
pub struct Slab {
block_size: usize,
free_block_list: FreeBlockList,
}
impl Slab {
/// @brief: 初始化一个slab
/// @param {usize} start_addr
/// @param {usize} slab_size
/// @param {usize} block_size
pub unsafe fn new(start_addr: usize, slab_size: usize, block_size: usize) -> Slab {
let blocks_num = slab_size / block_size;
return Slab {
block_size: block_size,
free_block_list: FreeBlockList::new(start_addr, block_size, blocks_num),
};
}
/// @brief: 获取slab中可用的block数
pub fn used_blocks(&self) -> usize {
return self.free_block_list.len();
}
/// @brief: 扩大free_block_list
/// @param {*} mut
/// @param {usize} start_addr
/// @param {usize} slab_size
pub fn grow(&mut self, start_addr: usize, slab_size: usize) {
let num_of_blocks = slab_size / self.block_size;
let mut block_list =
unsafe { FreeBlockList::new(start_addr, self.block_size, num_of_blocks) };
// 将新链表接到原链表的后面
while let Some(block) = block_list.pop() {
self.free_block_list.push(block);
}
}
/// @brief: 从slab中分配一个block
/// @return 分配的内存地址
pub fn allocate(&mut self, _layout: Layout) -> Option<*mut u8> {
match self.free_block_list.pop() {
Some(block) => return Some(block.addr() as *mut u8),
None => return None,
}
}
/// @brief: 将block归还给slab
pub fn free(&mut self, ptr: *mut u8) {
let ptr = ptr as *mut FreeBlock;
unsafe {
self.free_block_list.push(&mut *ptr);
}
}
}
/// slab中的空闲块
struct FreeBlockList {
len: usize,
head: Option<&'static mut FreeBlock>,
}
impl FreeBlockList {
unsafe fn new(start_addr: usize, block_size: usize, num_of_blocks: usize) -> FreeBlockList {
let mut new_list = FreeBlockList::new_empty();
for i in (0..num_of_blocks).rev() {
// 从后往前分配,避免内存碎片
let new_block = (start_addr + i * block_size) as *mut FreeBlock;
new_list.push(&mut *new_block);
}
return new_list;
}
fn new_empty() -> FreeBlockList {
return FreeBlockList { len: 0, head: None };
}
fn len(&self) -> usize {
return self.len;
}
/// @brief: 将空闲块从链表中弹出
fn pop(&mut self) -> Option<&'static mut FreeBlock> {
// 从链表中弹出一个空闲块
let block = self.head.take().map(|node| {
self.head = node.next.take();
self.len -= 1;
node
});
return block;
}
/// @brief: 将空闲块压入链表
fn push(&mut self, free_block: &'static mut FreeBlock) {
free_block.next = self.head.take();
self.len += 1;
self.head = Some(free_block);
}
fn is_empty(&self) -> bool {
return self.head.is_none();
}
}
impl Drop for FreeBlockList {
fn drop(&mut self) {
while let Some(_) = self.pop() {}
}
}
struct FreeBlock {
next: Option<&'static mut FreeBlock>,
}
impl FreeBlock {
/// @brief: 获取FreeBlock的地址
/// @return {*}
fn addr(&self) -> usize {
return self as *const _ as usize;
}
}

View File

@ -1,135 +0,0 @@
//! 这是暴露给C的接口用于在C语言中使用Rust的内存分配器。
use core::intrinsics::unlikely;
use alloc::vec::Vec;
use hashbrown::HashMap;
use crate::{
arch::mm::LowAddressRemapping,
include::bindings::bindings::{gfp_t, PAGE_U_S},
kerror,
libs::{align::page_align_up, spinlock::SpinLock},
mm::MMArch,
syscall::SystemError,
};
use super::{
allocator::page_frame::PageFrameCount, kernel_mapper::KernelMapper, no_init::pseudo_map_phys,
page::PageFlags, MemoryManagementArch, PhysAddr, VirtAddr,
};
lazy_static! {
// 用于记录内核分配给C的空间信息
static ref C_ALLOCATION_MAP: SpinLock<HashMap<VirtAddr, (VirtAddr, usize, usize)>> = SpinLock::new(HashMap::new());
}
/// [EXTERN TO C] Use pseudo mapper to map physical memory to virtual memory.
#[no_mangle]
pub unsafe extern "C" fn rs_pseudo_map_phys(vaddr: usize, paddr: usize, size: usize) {
let vaddr = VirtAddr::new(vaddr);
let paddr = PhysAddr::new(paddr);
let count = PageFrameCount::new(page_align_up(size) / MMArch::PAGE_SIZE);
pseudo_map_phys(vaddr, paddr, count);
}
/// [EXTERN TO C] Use kernel mapper to map physical memory to virtual memory.
#[no_mangle]
pub unsafe extern "C" fn rs_map_phys(vaddr: usize, paddr: usize, size: usize, flags: usize) {
let mut vaddr = VirtAddr::new(vaddr);
let mut paddr = PhysAddr::new(paddr);
let count = PageFrameCount::new(page_align_up(size) / MMArch::PAGE_SIZE);
// kdebug!("rs_map_phys: vaddr: {vaddr:?}, paddr: {paddr:?}, count: {count:?}, flags: {flags:?}");
let mut page_flags: PageFlags<MMArch> = PageFlags::new().set_execute(true).set_write(true);
if flags & PAGE_U_S as usize != 0 {
page_flags = page_flags.set_user(true);
}
let mut kernel_mapper = KernelMapper::lock();
let mut kernel_mapper = kernel_mapper.as_mut();
assert!(kernel_mapper.is_some());
for _i in 0..count.data() {
let flusher = kernel_mapper
.as_mut()
.unwrap()
.map_phys(vaddr, paddr, page_flags)
.unwrap();
flusher.flush();
vaddr += MMArch::PAGE_SIZE;
paddr += MMArch::PAGE_SIZE;
}
}
#[no_mangle]
pub unsafe extern "C" fn kzalloc(size: usize, _gfp: gfp_t) -> usize {
// kdebug!("kzalloc: size: {size}");
return do_kmalloc(size, true);
}
#[no_mangle]
pub unsafe extern "C" fn kmalloc(size: usize, _gfp: gfp_t) -> usize {
// kdebug!("kmalloc: size: {size}");
// 由于C代码不规范因此都全部清空
return do_kmalloc(size, true);
}
fn do_kmalloc(size: usize, zero: bool) -> usize {
let space: Vec<u8> = if zero {
vec![0u8; size]
} else {
let mut v = Vec::with_capacity(size);
unsafe {
v.set_len(size);
}
v
};
assert!(space.len() == size);
let (ptr, len, cap) = space.into_raw_parts();
if !ptr.is_null() {
let vaddr = VirtAddr::new(ptr as usize);
let len = len as usize;
let cap = cap as usize;
let mut guard = C_ALLOCATION_MAP.lock();
if unlikely(guard.contains_key(&vaddr)) {
drop(guard);
unsafe {
drop(Vec::from_raw_parts(vaddr.data() as *mut u8, len, cap));
}
panic!(
"do_kmalloc: vaddr {:?} already exists in C Allocation Map, query size: {size}, zero: {zero}",
vaddr
);
}
// 插入到C Allocation Map中
guard.insert(vaddr, (vaddr, len, cap));
return vaddr.data();
} else {
return SystemError::ENOMEM.to_posix_errno() as i64 as usize;
}
}
#[no_mangle]
pub unsafe extern "C" fn kfree(vaddr: usize) -> usize {
let vaddr = VirtAddr::new(vaddr);
let mut guard = C_ALLOCATION_MAP.lock();
let p = guard.remove(&vaddr);
drop(guard);
if p.is_none() {
kerror!("kfree: vaddr {:?} not found in C Allocation Map", vaddr);
return SystemError::EINVAL.to_posix_errno() as i64 as usize;
}
let (vaddr, len, cap) = p.unwrap();
drop(Vec::from_raw_parts(vaddr.data() as *mut u8, len, cap));
return 0;
}
#[no_mangle]
pub unsafe extern "C" fn rs_unmap_at_low_addr() -> usize {
LowAddressRemapping::unmap_at_low_address(true);
return 0;
}

79
kernel/src/mm/internal.h Normal file
View File

@ -0,0 +1,79 @@
#pragma once
#include "mm.h"
// 当vma被成功合并后的返回值
#define __VMA_MERGED 1
/**
* @brief 将vma结构体插入mm_struct的链表之中
*
* @param mm 内存空间分布结构体
* @param vma 待插入的VMA结构体
* @param prev 链表的前一个结点
*/
void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev);
/**
* @brief 将vma给定结构体从vma链表的结点之中删除
*
* @param mm 内存空间分布结构体
* @param vma 待插入的VMA结构体
*/
void __vma_unlink_list(struct mm_struct *mm, struct vm_area_struct *vma);
/**
* @brief 获取指定虚拟地址处映射的物理地址
*
* @param mm 内存空间分布结构体
* @param vaddr 虚拟地址
* @return uint64_t 已映射的物理地址
*/
uint64_t __mm_get_paddr(struct mm_struct *mm, uint64_t vaddr);
/**
* @brief 创建anon_vma并将其与页面结构体进行绑定
* 若提供的页面结构体指针为NULL则只创建不绑定
*
* @param page 页面结构体的指针
* @param lock_page 是否将页面结构体加锁
* @return struct anon_vma_t* 创建好的anon_vma
*/
struct anon_vma_t *__anon_vma_create_alloc(struct Page *page, bool lock_page);
/**
* @brief 释放anon vma结构体
*
* @param anon_vma 待释放的anon_vma结构体
* @return int 返回码
*/
int __anon_vma_free(struct anon_vma_t *anon_vma);
/**
* @brief 将指定的vma加入到anon_vma的管理范围之中
*
* @param anon_vma 页面的anon_vma
* @param vma 待加入的vma
* @return int 返回码
*/
int __anon_vma_add(struct anon_vma_t *anon_vma, struct vm_area_struct *vma);
/**
* @brief 从anon_vma的管理范围中删除指定的vma
* (在进入这个函数之前应该要对anon_vma加锁)
* @param vma 将要取消对应的anon_vma管理的vma结构体
* @return int 返回码
*/
int __anon_vma_del(struct vm_area_struct *vma);
/**
* @brief 创建mmio对应的页结构体
*
* @param paddr 物理地址
* @return struct Page* 创建成功的page
*/
struct Page* __create_mmio_page_struct(uint64_t paddr);
// 判断给定的两个值是否跨越了2M边界
#define CROSS_2M_BOUND(val1, val2) ((val1 & PAGE_2M_MASK) != (val2 & PAGE_2M_MASK))

View File

@ -1,145 +0,0 @@
use super::{page::PageFlags, PageTableKind, PhysAddr, VirtAddr};
use crate::{
arch::{
asm::irqflags::{local_irq_restore, local_irq_save},
mm::{LockedFrameAllocator, PageMapper},
},
libs::align::page_align_up,
mm::allocator::page_frame::PageFrameCount,
mm::{MMArch, MemoryManagementArch},
smp::core::smp_get_processor_id,
syscall::SystemError,
};
use core::{
ops::Deref,
sync::atomic::{compiler_fence, AtomicUsize, Ordering},
};
/// 标志当前没有处理器持有内核映射器的锁
/// 之所以需要这个标志是因为AtomicUsize::new(0)会把0当作一个处理器的id
const KERNEL_MAPPER_NO_PROCESSOR: usize = !0;
/// 当前持有内核映射器锁的处理器
static KERNEL_MAPPER_LOCK_OWNER: AtomicUsize = AtomicUsize::new(KERNEL_MAPPER_NO_PROCESSOR);
/// 内核映射器的锁计数器
static KERNEL_MAPPER_LOCK_COUNT: AtomicUsize = AtomicUsize::new(0);
pub struct KernelMapper {
/// 内核空间映射器
mapper: PageMapper,
/// 标记当前映射器是否为只读
readonly: bool,
}
impl KernelMapper {
fn lock_cpu(cpuid: usize, mapper: PageMapper) -> Self {
loop {
match KERNEL_MAPPER_LOCK_OWNER.compare_exchange_weak(
KERNEL_MAPPER_NO_PROCESSOR,
cpuid,
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(_) => break,
// 当前处理器已经持有了锁
Err(id) if id == cpuid => break,
// either CAS failed, or some other hardware thread holds the lock
Err(_) => core::hint::spin_loop(),
}
}
let prev_count = KERNEL_MAPPER_LOCK_COUNT.fetch_add(1, Ordering::Relaxed);
compiler_fence(Ordering::Acquire);
// 本地核心已经持有过锁,因此标记当前加锁获得的映射器为只读
let readonly = prev_count > 0;
return Self { mapper, readonly };
}
/// @brief 锁定内核映射器, 并返回一个内核映射器对象
#[inline(always)]
pub fn lock() -> Self {
let cpuid = smp_get_processor_id() as usize;
let mapper = unsafe { PageMapper::current(PageTableKind::Kernel, LockedFrameAllocator) };
return Self::lock_cpu(cpuid, mapper);
}
/// @brief 获取内核映射器的page mapper的可变引用。如果当前映射器为只读则返回 None
#[inline(always)]
pub fn as_mut(&mut self) -> Option<&mut PageMapper> {
if self.readonly {
return None;
} else {
return Some(&mut self.mapper);
}
}
/// @brief 获取内核映射器的page mapper的不可变引用
#[inline(always)]
pub fn as_ref(&self) -> &PageMapper {
return &self.mapper;
}
/// 映射一段物理地址到指定的虚拟地址。
///
/// ## 参数
///
/// - `vaddr`: 要映射的虚拟地址
/// - `paddr`: 要映射的物理地址
/// - `size`: 要映射的大小(字节,必须是页大小的整数倍,否则会向上取整)
/// - `flags`: 页面标志
/// - `flush`: 是否刷新TLB
///
/// ## 返回
///
/// - 成功返回Ok(())
/// - 失败: 如果当前映射器为只读则返回EAGAIN_OR_EWOULDBLOCK
pub unsafe fn map_phys_with_size(
&mut self,
mut vaddr: VirtAddr,
mut paddr: PhysAddr,
size: usize,
flags: PageFlags<MMArch>,
flush: bool,
) -> Result<(), SystemError> {
if self.readonly {
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
}
let count = PageFrameCount::new(page_align_up(size) / MMArch::PAGE_SIZE);
// kdebug!("kernel mapper: map_phys: vaddr: {vaddr:?}, paddr: {paddr:?}, count: {count:?}, flags: {flags:?}");
for _ in 0..count.data() {
let flusher = self.mapper.map_phys(vaddr, paddr, flags).unwrap();
if flush {
flusher.flush();
}
vaddr += MMArch::PAGE_SIZE;
paddr += MMArch::PAGE_SIZE;
}
return Ok(());
}
}
impl Drop for KernelMapper {
fn drop(&mut self) {
// 为了防止fetch_sub和store之间由于中断导致store错误清除了owner导致错误因此需要关中断。
let flags = local_irq_save();
let prev_count = KERNEL_MAPPER_LOCK_COUNT.fetch_sub(1, Ordering::Relaxed);
if prev_count == 1 {
KERNEL_MAPPER_LOCK_OWNER.store(KERNEL_MAPPER_NO_PROCESSOR, Ordering::Release);
}
local_irq_restore(flags);
compiler_fence(Ordering::Release);
}
}
impl Deref for KernelMapper {
type Target = PageMapper;
fn deref(&self) -> &Self::Target {
return self.as_ref();
}
}

196
kernel/src/mm/mm-stat.c Normal file
View File

@ -0,0 +1,196 @@
/**
* @file mm-stat.c
* @author longjin(longjin@RinGoTek.cn)
* @brief 查询内存信息
* @version 0.1
* @date 2022-08-06
*
* @copyright Copyright (c) 2022
*
*/
#include "mm.h"
#include "slab.h"
#include <common/errno.h>
#include <process/ptrace.h>
extern const struct slab kmalloc_cache_group[16];
static int __empty_2m_pages(int zone);
static int __count_in_using_2m_pages(int zone);
static uint64_t __count_kmalloc_free();
static uint64_t __count_kmalloc_using();
static uint64_t __count_kmalloc_total();
uint64_t sys_mm_stat(struct pt_regs *regs);
/**
* @brief 获取指定zone中的空闲2M页的数量
*
* @param zone 内存zone号
* @return int 空闲2M页数量
*/
static int __count_empty_2m_pages(int zone)
{
int zone_start = 0, zone_end = 0;
uint64_t attr = 0;
switch (zone)
{
case ZONE_DMA:
// DMA区域
zone_start = 0;
zone_end = ZONE_DMA_INDEX;
attr |= PAGE_PGT_MAPPED;
break;
case ZONE_NORMAL:
zone_start = ZONE_DMA_INDEX;
zone_end = ZONE_NORMAL_INDEX;
attr |= PAGE_PGT_MAPPED;
break;
case ZONE_UNMAPPED_IN_PGT:
zone_start = ZONE_NORMAL_INDEX;
zone_end = ZONE_UNMAPPED_INDEX;
attr = 0;
break;
default:
kerror("In __count_empty_2m_pages: param: zone invalid.");
// 返回错误码
return -EINVAL;
break;
}
uint64_t result = 0;
for (int i = zone_start; i <= zone_end; ++i)
{
result += (memory_management_struct.zones_struct + i)->count_pages_free;
}
return result;
}
/**
* @brief 获取指定zone中的正在使用的2M页的数量
*
* @param zone 内存zone号
* @return int 空闲2M页数量
*/
static int __count_in_using_2m_pages(int zone)
{
int zone_start = 0, zone_end = 0;
uint64_t attr = 0;
switch (zone)
{
case ZONE_DMA:
// DMA区域
zone_start = 0;
zone_end = ZONE_DMA_INDEX;
attr |= PAGE_PGT_MAPPED;
break;
case ZONE_NORMAL:
zone_start = ZONE_DMA_INDEX;
zone_end = ZONE_NORMAL_INDEX;
attr |= PAGE_PGT_MAPPED;
break;
case ZONE_UNMAPPED_IN_PGT:
zone_start = ZONE_NORMAL_INDEX;
zone_end = ZONE_UNMAPPED_INDEX;
attr = 0;
break;
default:
kerror("In __count_in_using_2m_pages: param: zone invalid.");
// 返回错误码
return -EINVAL;
break;
}
uint64_t result = 0;
for (int i = zone_start; i <= zone_end; ++i)
{
result += (memory_management_struct.zones_struct + i)->count_pages_using;
}
return result;
}
/**
* @brief 计算kmalloc缓冲区中的空闲内存
*
* @return uint64_t 空闲内存(字节)
*/
static uint64_t __count_kmalloc_free()
{
uint64_t result = 0;
for (int i = 0; i < sizeof(kmalloc_cache_group) / sizeof(struct slab); ++i)
{
result += kmalloc_cache_group[i].size * kmalloc_cache_group[i].count_total_free;
}
return result;
}
/**
* @brief 计算kmalloc缓冲区中已使用的内存
*
* @return uint64_t 已使用的内存(字节)
*/
static uint64_t __count_kmalloc_using()
{
uint64_t result = 0;
for (int i = 0; i < sizeof(kmalloc_cache_group) / sizeof(struct slab); ++i)
{
result += kmalloc_cache_group[i].size * kmalloc_cache_group[i].count_total_using;
}
return result;
}
/**
* @brief 计算kmalloc缓冲区中总共占用的内存
*
* @return uint64_t 缓冲区占用的内存(字节)
*/
static uint64_t __count_kmalloc_total()
{
uint64_t result = 0;
for (int i = 0; i < sizeof(kmalloc_cache_group) / sizeof(struct slab); ++i)
{
result += kmalloc_cache_group[i].size *
(kmalloc_cache_group[i].count_total_free + kmalloc_cache_group[i].count_total_using);
}
return result;
}
/**
* @brief 获取系统当前的内存信息(未上锁,不一定精准)
*
* @return struct mm_stat_t 内存信息结构体
*/
struct mm_stat_t mm_stat()
{
struct mm_stat_t tmp = {0};
// 统计物理页的信息
tmp.used = __count_in_using_2m_pages(ZONE_NORMAL) * PAGE_2M_SIZE;
tmp.free = __count_empty_2m_pages(ZONE_NORMAL) * PAGE_2M_SIZE;
tmp.total = tmp.used + tmp.free;
tmp.shared = 0;
// 统计kmalloc slab中的信息
tmp.cache_free = __count_kmalloc_free();
tmp.cache_used = __count_kmalloc_using();
tmp.available = tmp.free + tmp.cache_free;
return tmp;
}
/**
* @brief 获取内存信息的系统调用
*
* @param r8 返回的内存信息结构体的地址
* @return uint64_t
*/
uint64_t sys_do_mstat(struct mm_stat_t *dst, bool from_user)
{
if (dst == NULL)
return -EFAULT;
struct mm_stat_t stat = mm_stat();
if (from_user)
copy_to_user((void *)dst, &stat, sizeof(struct mm_stat_t));
else
memcpy((void *)dst, &stat, sizeof(struct mm_stat_t));
return 0;
}

View File

@ -4,4 +4,179 @@
#include <common/spinlock.h>
#include <common/atomic.h>
struct mm_struct;
struct anon_vma_t;
typedef uint64_t vm_flags_t;
/**
* @brief 内存页表结构体
*
*/
typedef struct
{
unsigned long pml4t;
} pml4t_t;
typedef struct
{
unsigned long pdpt;
} pdpt_t;
typedef struct
{
unsigned long pdt;
} pdt_t;
typedef struct
{
unsigned long pt;
} pt_t;
// Address Range Descriptor Structure 地址范围描述符
struct ARDS
{
ul BaseAddr; // 基地址
ul Length; // 内存长度 以字节为单位
unsigned int type; // 本段内存的类型
// type=1 表示可以被操作系统使用
// type=2 ARR - 内存使用中或被保留,操作系统不能使用
// 其他 未定义操作系统需要将其视为ARR
} __attribute__((packed)); // 修饰该结构体不会生成对齐空间,改用紧凑格式
struct memory_desc
{
struct ARDS e820[32]; // 物理内存段结构数组
ul len_e820; // 物理内存段长度
ul *bmp; // 物理空间页映射位图
ul bmp_len; // bmp的长度
ul bits_size; // 物理地址空间页数量
struct Page *pages_struct;
ul count_pages; // struct page结构体的总数
ul pages_struct_len; // pages_struct链表的长度
struct Zone *zones_struct;
ul count_zones; // zone结构体的数量
ul zones_struct_len; // zones_struct列表的长度
ul kernel_code_start, kernel_code_end; // 内核程序代码段起始地址、结束地址
ul kernel_data_end, rodata_end; // 内核程序数据段结束地址、 内核程序只读段结束地址
uint64_t start_brk; // 堆地址的起始位置
ul end_of_struct; // 内存页管理结构的结束地址
};
struct Zone
{
// 指向内存页的指针
struct Page *pages_group;
ul count_pages; // 本区域的struct page结构体总数
// 本内存区域的起始、结束的页对齐地址
ul zone_addr_start;
ul zone_addr_end;
ul zone_length; // 区域长度
// 本区域空间的属性
ul attr;
struct memory_desc *gmd_struct;
// 本区域正在使用中和空闲中的物理页面数量
ul count_pages_using;
ul count_pages_free;
// 物理页被引用次数
ul total_pages_link;
};
struct Page
{
// 本页所属的内存域结构体
struct Zone *zone;
// 本页对应的物理地址
ul addr_phys;
// 页面属性
ul attr;
// 页面被引用的次数
ul ref_counts;
// 本页的创建时间
ul age;
struct anon_vma_t *anon_vma; // 本页对应的anon_vma
spinlock_t op_lock; // 页面操作锁
};
/**
* @brief 虚拟内存区域(VMA)结构体
*
*/
struct vm_area_struct
{
struct vm_area_struct *vm_prev, *vm_next;
// 虚拟内存区域的范围是一个左闭右开的区间:[vm_start, vm_end)
uint64_t vm_start; // 区域的起始地址
uint64_t vm_end; // 区域的结束地址
struct mm_struct *vm_mm; // 虚拟内存区域对应的mm结构体
vm_flags_t vm_flags; // 虚拟内存区域的标志位, 具体可选值请见mm.h
struct List anon_vma_list; // anon_vma的链表结点
struct anon_vma_t * anon_vma; // 属于的anon_vma
struct vm_operations_t *vm_ops; // 操作方法
atomic_t ref_count; // 引用计数
pgoff_t page_offset; // 起始地址在当前VMA所占的2M物理页中的偏移量
void *private_data;
};
/**
* @brief 内存空间分布结构体
* 包含了进程内存空间分布的信息
*/
struct mm_struct
{
pml4t_t *pgd; // 内存页表指针
struct vm_area_struct *vmas; // VMA列表
// 代码段空间
uint64_t code_addr_start, code_addr_end;
// 数据段空间
uint64_t data_addr_start, data_addr_end;
// 只读数据段空间
uint64_t rodata_addr_start, rodata_addr_end;
// BSS段的空间
uint64_t bss_start, bss_end;
// 动态内存分配区(堆区域)
uint64_t brk_start, brk_end;
// 应用层栈基地址
uint64_t stack_start;
};
/**
* @brief 匿名vma对象的结构体
*
* anon_vma与每个内存页结构体进行一对一绑定
* anon_vma也连接着一切使用到该内存页的vma当发生页面换出时应当更新与该page相关的所有vma在页表中的映射信息。
*/
struct anon_vma_t
{
// anon vma的操作信号量
semaphore_t sem;
/**
* 记录当前有多少个vma与该anon_vma关联当vma被释放时
* 应当检查这个值。当该值为0时应当释放anon_vma结构体
*/
atomic_t ref_count;
// todo: 把下面的循环链表更换成红黑树
// 与当前anon_vma相关的vma的列表
struct List vma_list;
// 当前anon vma对应的page
struct Page* page;
};

686
kernel/src/mm/mm.c Normal file
View File

@ -0,0 +1,686 @@
#include "mm.h"
#include "mm-types.h"
#include "mmio.h"
#include "slab.h"
#include <common/printk.h>
#include <common/kprint.h>
#include <driver/multiboot2/multiboot2.h>
#include <process/process.h>
#include <common/compiler.h>
#include <common/errno.h>
#include <debug/traceback/traceback.h>
uint64_t mm_Total_Memory = 0;
uint64_t mm_total_2M_pages = 0;
struct mm_struct initial_mm = {0};
struct memory_desc memory_management_struct = {{0}, 0};
/**
* @brief 从页表中获取pdt页表项的内容
*
* @param proc_page_table_addr 页表的地址
* @param is_phys 页表地址是否为物理地址
* @param virt_addr_start 要清除的虚拟地址的起始地址
* @param length 要清除的区域的长度
* @param clear 是否清除标志位
*/
uint64_t mm_get_PDE(ul proc_page_table_addr, bool is_phys, ul virt_addr, bool clear);
/**
* @brief 检查页表是否存在不为0的页表项
*
* @param ptr 页表基指针
* @return int8_t 存在 -> 1
* 不存在 -> 0
*/
int8_t mm_check_page_table(uint64_t *ptr)
{
for (int i = 0; i < 512; ++i, ++ptr)
{
if (*ptr != 0)
return 1;
}
return 0;
}
void mm_init()
{
kinfo("Initializing memory management unit...");
// 设置内核程序不同部分的起止地址
memory_management_struct.kernel_code_start = (ul)&_text;
memory_management_struct.kernel_code_end = (ul)&_etext;
memory_management_struct.kernel_data_end = (ul)&_edata;
memory_management_struct.rodata_end = (ul)&_erodata;
memory_management_struct.start_brk = (ul)&_end;
struct multiboot_mmap_entry_t mb2_mem_info[512];
int count;
multiboot2_iter(multiboot2_get_memory, mb2_mem_info, &count);
io_mfence();
for (int i = 0; i < count; ++i)
{
io_mfence();
// 可用的内存
if (mb2_mem_info->type == 1)
mm_Total_Memory += mb2_mem_info->len;
// kdebug("[i=%d] mb2_mem_info[i].type=%d, mb2_mem_info[i].addr=%#018lx", i, mb2_mem_info[i].type, mb2_mem_info[i].addr);
// 保存信息到mms
memory_management_struct.e820[i].BaseAddr = mb2_mem_info[i].addr;
memory_management_struct.e820[i].Length = mb2_mem_info[i].len;
memory_management_struct.e820[i].type = mb2_mem_info[i].type;
memory_management_struct.len_e820 = i;
// 脏数据
if (mb2_mem_info[i].type > 4 || mb2_mem_info[i].len == 0 || mb2_mem_info[i].type < 1)
break;
}
printk("[ INFO ] Total amounts of RAM : %ld bytes\n", mm_Total_Memory);
// 计算有效内存页数
io_mfence();
for (int i = 0; i < memory_management_struct.len_e820; ++i)
{
if (memory_management_struct.e820[i].type != 1)
continue;
io_mfence();
// 将内存段的起始物理地址按照2M进行对齐
ul addr_start = PAGE_2M_ALIGN(memory_management_struct.e820[i].BaseAddr);
// 将内存段的终止物理地址的低2M区域清空以实现对齐
ul addr_end = ((memory_management_struct.e820[i].BaseAddr + memory_management_struct.e820[i].Length) & PAGE_2M_MASK);
// 内存段不可用
if (addr_end <= addr_start)
continue;
io_mfence();
mm_total_2M_pages += ((addr_end - addr_start) >> PAGE_2M_SHIFT);
}
kinfo("Total amounts of 2M pages : %ld.", mm_total_2M_pages);
// 物理地址空间的最大地址包含了物理内存、内存空洞、ROM等
ul max_addr = memory_management_struct.e820[memory_management_struct.len_e820].BaseAddr + memory_management_struct.e820[memory_management_struct.len_e820].Length;
// 初始化mms的bitmap
// bmp的指针指向截止位置的4k对齐的上边界防止修改了别的数据
io_mfence();
memory_management_struct.bmp = (unsigned long *)((memory_management_struct.start_brk + PAGE_4K_SIZE - 1) & PAGE_4K_MASK);
memory_management_struct.bits_size = max_addr >> PAGE_2M_SHIFT; // 物理地址空间的最大页面数
memory_management_struct.bmp_len = (((unsigned long)(max_addr >> PAGE_2M_SHIFT) + sizeof(unsigned long) * 8 - 1) / 8) & (~(sizeof(unsigned long) - 1)); // bmp由多少个unsigned long变量组成
io_mfence();
// 初始化bitmap 先将整个bmp空间全部置位。稍后再将可用物理内存页复位。
memset(memory_management_struct.bmp, 0xff, memory_management_struct.bmp_len);
io_mfence();
// 初始化内存页结构
// 将页结构映射于bmp之后
memory_management_struct.pages_struct = (struct Page *)(((unsigned long)memory_management_struct.bmp + memory_management_struct.bmp_len + PAGE_4K_SIZE - 1) & PAGE_4K_MASK);
memory_management_struct.count_pages = max_addr >> PAGE_2M_SHIFT;
memory_management_struct.pages_struct_len = ((max_addr >> PAGE_2M_SHIFT) * sizeof(struct Page) + sizeof(long) - 1) & (~(sizeof(long) - 1));
// 将pages_struct全部清空以备后续初始化
memset(memory_management_struct.pages_struct, 0x00, memory_management_struct.pages_struct_len); // init pages memory
io_mfence();
// 初始化内存区域
memory_management_struct.zones_struct = (struct Zone *)(((ul)memory_management_struct.pages_struct + memory_management_struct.pages_struct_len + PAGE_4K_SIZE - 1) & PAGE_4K_MASK);
io_mfence();
// 由于暂时无法计算zone结构体的数量因此先将其设为0
memory_management_struct.count_zones = 0;
io_mfence();
// zones-struct 成员变量暂时按照5个来计算
memory_management_struct.zones_struct_len = (10 * sizeof(struct Zone) + sizeof(ul) - 1) & (~(sizeof(ul) - 1));
io_mfence();
memset(memory_management_struct.zones_struct, 0x00, memory_management_struct.zones_struct_len);
// ==== 遍历e820数组完成成员变量初始化工作 ===
for (int i = 0; i < memory_management_struct.len_e820; ++i)
{
io_mfence();
if (memory_management_struct.e820[i].type != 1) // 不是操作系统可以使用的物理内存
continue;
ul addr_start = PAGE_2M_ALIGN(memory_management_struct.e820[i].BaseAddr);
ul addr_end = (memory_management_struct.e820[i].BaseAddr + memory_management_struct.e820[i].Length) & PAGE_2M_MASK;
if (addr_end <= addr_start)
continue;
// zone init
struct Zone *z = memory_management_struct.zones_struct + memory_management_struct.count_zones;
++memory_management_struct.count_zones;
z->zone_addr_start = addr_start;
z->zone_addr_end = addr_end;
z->zone_length = addr_end - addr_start;
z->count_pages_using = 0;
z->count_pages_free = (addr_end - addr_start) >> PAGE_2M_SHIFT;
z->total_pages_link = 0;
z->attr = 0;
z->gmd_struct = &memory_management_struct;
z->count_pages = (addr_end - addr_start) >> PAGE_2M_SHIFT;
z->pages_group = (struct Page *)(memory_management_struct.pages_struct + (addr_start >> PAGE_2M_SHIFT));
// 初始化页
struct Page *p = z->pages_group;
for (int j = 0; j < z->count_pages; ++j, ++p)
{
p->zone = z;
p->addr_phys = addr_start + PAGE_2M_SIZE * j;
p->attr = 0;
p->ref_counts = 0;
p->age = 0;
// 将bmp中对应的位 复位
*(memory_management_struct.bmp + ((p->addr_phys >> PAGE_2M_SHIFT) >> 6)) ^= (1UL << ((p->addr_phys >> PAGE_2M_SHIFT) % 64));
}
}
// 初始化0~2MB的物理页
// 由于这个区间的内存由多个内存段组成因此不会被以上代码初始化需要我们手动配置page[0]。
io_mfence();
memory_management_struct.pages_struct->zone = memory_management_struct.zones_struct;
memory_management_struct.pages_struct->addr_phys = 0UL;
set_page_attr(memory_management_struct.pages_struct, PAGE_PGT_MAPPED | PAGE_KERNEL_INIT | PAGE_KERNEL);
memory_management_struct.pages_struct->ref_counts = 1;
memory_management_struct.pages_struct->age = 0;
// 将第0页的标志位给置上
//*(memory_management_struct.bmp) |= 1UL;
// 计算zone结构体的总长度按照64位对齐
memory_management_struct.zones_struct_len = (memory_management_struct.count_zones * sizeof(struct Zone) + sizeof(ul) - 1) & (~(sizeof(ul) - 1));
ZONE_DMA_INDEX = 0;
ZONE_NORMAL_INDEX = memory_management_struct.count_zones ;
ZONE_UNMAPPED_INDEX = 0;
//kdebug("ZONE_DMA_INDEX=%d\tZONE_NORMAL_INDEX=%d\tZONE_UNMAPPED_INDEX=%d", ZONE_DMA_INDEX, ZONE_NORMAL_INDEX, ZONE_UNMAPPED_INDEX);
// 设置内存页管理结构的地址,预留了一段空间,防止内存越界。
memory_management_struct.end_of_struct = (ul)((ul)memory_management_struct.zones_struct + memory_management_struct.zones_struct_len + sizeof(long) * 32) & (~(sizeof(long) - 1));
// 初始化内存管理单元结构所占的物理页的结构体
ul mms_max_page = (virt_2_phys(memory_management_struct.end_of_struct) >> PAGE_2M_SHIFT); // 内存管理单元所占据的序号最大的物理页
// kdebug("mms_max_page=%ld", mms_max_page);
struct Page *tmp_page = NULL;
ul page_num;
// 第0个page已经在上方配置
for (ul j = 1; j <= mms_max_page; ++j)
{
barrier();
tmp_page = memory_management_struct.pages_struct + j;
page_init(tmp_page, PAGE_PGT_MAPPED | PAGE_KERNEL | PAGE_KERNEL_INIT);
barrier();
page_num = tmp_page->addr_phys >> PAGE_2M_SHIFT;
*(memory_management_struct.bmp + (page_num >> 6)) |= (1UL << (page_num % 64));
++tmp_page->zone->count_pages_using;
--tmp_page->zone->count_pages_free;
}
kinfo("Memory management unit initialize complete!");
flush_tlb();
// todo: 在这里增加代码暂时停止视频输出否则可能会导致图像数据写入slab的区域从而造成异常
// 初始化slab内存池
slab_init();
page_table_init();
initial_mm.pgd = (pml4t_t *)get_CR3();
initial_mm.code_addr_start = memory_management_struct.kernel_code_start;
initial_mm.code_addr_end = memory_management_struct.kernel_code_end;
initial_mm.data_addr_start = (ul)&_data;
initial_mm.data_addr_end = memory_management_struct.kernel_data_end;
initial_mm.rodata_addr_start = (ul)&_rodata;
initial_mm.rodata_addr_end = (ul)&_erodata;
initial_mm.bss_start = (uint64_t)&_bss;
initial_mm.bss_end = (uint64_t)&_ebss;
initial_mm.brk_start = memory_management_struct.start_brk;
initial_mm.brk_end = current_pcb->addr_limit;
initial_mm.stack_start = _stack_start;
initial_mm.vmas = NULL;
mmio_init();
}
/**
* @brief 初始化内存页
*
* @param page 内存页结构体
* @param flags 标志位
* 本函数只负责初始化内存页,允许对同一页面进行多次初始化
* 而维护计数器及置位bmp标志位的功能应当在分配页面的时候手动完成
* @return unsigned long
*/
unsigned long page_init(struct Page *page, ul flags)
{
page->attr |= flags;
// 若页面的引用计数为0或是共享页增加引用计数
if ((!page->ref_counts) || (page->attr & PAGE_SHARED))
{
++page->ref_counts;
barrier();
if (page->zone)
++page->zone->total_pages_link;
}
page->anon_vma = NULL;
spin_init(&(page->op_lock));
return 0;
}
/**
* @brief 从已初始化的页结构中搜索符合申请条件的、连续num个struct page
*
* @param zone_select 选择内存区域, 可选项dma, mapped in pgt(normal), unmapped in pgt
* @param num 需要申请的连续内存页的数量 num<64
* @param flags 将页面属性设置成flag
* @return struct Page*
*/
struct Page *alloc_pages(unsigned int zone_select, int num, ul flags)
{
ul zone_start = 0, zone_end = 0;
if (num >= 64 && num <= 0)
{
kerror("alloc_pages(): num is invalid.");
return NULL;
}
ul attr = flags;
switch (zone_select)
{
case ZONE_DMA:
// DMA区域
zone_start = 0;
zone_end = ZONE_DMA_INDEX;
attr |= PAGE_PGT_MAPPED;
break;
case ZONE_NORMAL:
zone_start = ZONE_DMA_INDEX;
zone_end = ZONE_NORMAL_INDEX;
attr |= PAGE_PGT_MAPPED;
break;
case ZONE_UNMAPPED_IN_PGT:
zone_start = ZONE_NORMAL_INDEX;
zone_end = ZONE_UNMAPPED_INDEX;
attr = 0;
break;
default:
kerror("In alloc_pages: param: zone_select incorrect.");
// 返回空
return NULL;
break;
}
for (int i = zone_start; i < zone_end; ++i)
{
if ((memory_management_struct.zones_struct + i)->count_pages_free < num)
continue;
struct Zone *z = memory_management_struct.zones_struct + i;
// 区域对应的起止页号
ul page_start = (z->zone_addr_start >> PAGE_2M_SHIFT);
ul page_end = (z->zone_addr_end >> PAGE_2M_SHIFT);
ul tmp = 64 - page_start % 64;
for (ul j = page_start; j < page_end; j += ((j % 64) ? tmp : 64))
{
// 按照bmp中的每一个元素进行查找
// 先将p定位到bmp的起始元素
ul *p = memory_management_struct.bmp + (j >> 6);
ul shift = j % 64;
ul tmp_num = ((1UL << num) - 1);
for (ul k = shift; k < 64; ++k)
{
// 寻找连续num个空页
if (!((k ? ((*p >> k) | (*(p + 1) << (64 - k))) : *p) & tmp_num))
{
ul start_page_num = j + k - shift; // 计算得到要开始获取的内存页的页号
for (ul l = 0; l < num; ++l)
{
struct Page *x = memory_management_struct.pages_struct + start_page_num + l;
// 分配页面,手动配置属性及计数器
// 置位bmp
*(memory_management_struct.bmp + ((x->addr_phys >> PAGE_2M_SHIFT) >> 6)) |= (1UL << (x->addr_phys >> PAGE_2M_SHIFT) % 64);
++(z->count_pages_using);
--(z->count_pages_free);
page_init(x, attr);
}
// 成功分配了页面,返回第一个页面的指针
// kwarn("start page num=%d\n", start_page_num);
return (struct Page *)(memory_management_struct.pages_struct + start_page_num);
}
}
}
}
kBUG("Cannot alloc page, ZONE=%d\tnums=%d, mm_total_2M_pages=%d", zone_select, num, mm_total_2M_pages);
return NULL;
}
/**
* @brief 清除页面的引用计数, 计数为0时清空除页表已映射以外的所有属性
*
* @param p 物理页结构体
* @return unsigned long
*/
unsigned long page_clean(struct Page *p)
{
--p->ref_counts;
--p->zone->total_pages_link;
// 若引用计数为空则清空除PAGE_PGT_MAPPED以外的所有属性
if (!p->ref_counts)
{
p->attr &= PAGE_PGT_MAPPED;
}
return 0;
}
/**
* @brief Get the page's attr
*
* @param page 内存页结构体
* @return ul 属性
*/
ul get_page_attr(struct Page *page)
{
if (page == NULL)
{
kBUG("get_page_attr(): page == NULL");
return EPAGE_NULL;
}
else
return page->attr;
}
/**
* @brief Set the page's attr
*
* @param page 内存页结构体
* @param flags 属性
* @return ul 错误码
*/
ul set_page_attr(struct Page *page, ul flags)
{
if (page == NULL)
{
kBUG("get_page_attr(): page == NULL");
return EPAGE_NULL;
}
else
{
page->attr = flags;
return 0;
}
}
/**
* @brief 释放连续number个内存页
*
* @param page 第一个要被释放的页面的结构体
* @param number 要释放的内存页数量 number<64
*/
void free_pages(struct Page *page, int number)
{
if (page == NULL)
{
kerror("free_pages() page is invalid.");
return;
}
if (number >= 64 || number <= 0)
{
kerror("free_pages(): number %d is invalid.", number);
return;
}
ul page_num;
for (int i = 0; i < number; ++i, ++page)
{
page_num = page->addr_phys >> PAGE_2M_SHIFT;
// 复位bmp
*(memory_management_struct.bmp + (page_num >> 6)) &= ~(1UL << (page_num % 64));
// 更新计数器
--page->zone->count_pages_using;
++page->zone->count_pages_free;
page->attr = 0;
}
return;
}
/**
* @brief 重新初始化页表的函数
* 将所有物理页映射到线性地址空间
*/
void page_table_init()
{
kinfo("Re-Initializing page table...");
ul *global_CR3 = get_CR3();
int js = 0;
ul *tmp_addr;
for (int i = 0; i < memory_management_struct.count_zones; ++i)
{
struct Zone *z = memory_management_struct.zones_struct + i;
struct Page *p = z->pages_group;
if (i == ZONE_UNMAPPED_INDEX && ZONE_UNMAPPED_INDEX != 0)
break;
for (int j = 0; j < z->count_pages; ++j)
{
mm_map_proc_page_table((uint64_t)get_CR3(), true, (ul)phys_2_virt(p->addr_phys), p->addr_phys, PAGE_2M_SIZE, PAGE_KERNEL_PAGE, false, true, false);
++p;
++js;
}
}
barrier();
// ========= 在IDLE进程的顶层页表中添加对内核地址空间的映射 =====================
// 由于IDLE进程的顶层页表的高地址部分会被后续进程所复制为了使所有进程能够共享相同的内核空间
// 因此需要先在IDLE进程的顶层页表内映射二级页表
uint64_t *idle_pml4t_vaddr = (uint64_t *)phys_2_virt((uint64_t)get_CR3() & (~0xfffUL));
for (int i = 256; i < 512; ++i)
{
uint64_t *tmp = idle_pml4t_vaddr + i;
barrier();
if (*tmp == 0)
{
void *pdpt = kmalloc(PAGE_4K_SIZE, 0);
barrier();
memset(pdpt, 0, PAGE_4K_SIZE);
barrier();
set_pml4t(tmp, mk_pml4t(virt_2_phys(pdpt), PAGE_KERNEL_PGT));
}
}
barrier();
flush_tlb();
kinfo("Page table Initialized. Affects:%d", js);
}
/**
* @brief 从页表中获取pdt页表项的内容
*
* @param proc_page_table_addr 页表的地址
* @param is_phys 页表地址是否为物理地址
* @param virt_addr_start 要清除的虚拟地址的起始地址
* @param length 要清除的区域的长度
* @param clear 是否清除标志位
*/
uint64_t mm_get_PDE(ul proc_page_table_addr, bool is_phys, ul virt_addr, bool clear)
{
ul *tmp;
if (is_phys)
tmp = phys_2_virt((ul *)((ul)proc_page_table_addr & (~0xfffUL)) + ((virt_addr >> PAGE_GDT_SHIFT) & 0x1ff));
else
tmp = (ul *)((ul)proc_page_table_addr & (~0xfffUL)) + ((virt_addr >> PAGE_GDT_SHIFT) & 0x1ff);
// pml4页表项为0
if (*tmp == 0)
return 0;
tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((virt_addr >> PAGE_1G_SHIFT) & 0x1ff));
// pdpt页表项为0
if (*tmp == 0)
return 0;
// 读取pdt页表项
tmp = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr) >> PAGE_2M_SHIFT) & 0x1ff)));
if (clear) // 清除页表项的标志位
return *tmp & (~0x1fff);
else
return *tmp;
}
/**
* @brief 从mms中寻找Page结构体
*
* @param phys_addr
* @return struct Page*
*/
static struct Page *mm_find_page(uint64_t phys_addr, uint32_t zone_select)
{
uint32_t zone_start, zone_end;
switch (zone_select)
{
case ZONE_DMA:
// DMA区域
zone_start = 0;
zone_end = ZONE_DMA_INDEX;
break;
case ZONE_NORMAL:
zone_start = ZONE_DMA_INDEX;
zone_end = ZONE_NORMAL_INDEX;
break;
case ZONE_UNMAPPED_IN_PGT:
zone_start = ZONE_NORMAL_INDEX;
zone_end = ZONE_UNMAPPED_INDEX;
break;
default:
kerror("In mm_find_page: param: zone_select incorrect.");
// 返回空
return NULL;
break;
}
for (int i = zone_start; i <= zone_end; ++i)
{
if ((memory_management_struct.zones_struct + i)->count_pages_using == 0)
continue;
struct Zone *z = memory_management_struct.zones_struct + i;
// 区域对应的起止页号
ul page_start = (z->zone_addr_start >> PAGE_2M_SHIFT);
ul page_end = (z->zone_addr_end >> PAGE_2M_SHIFT);
ul tmp = 64 - page_start % 64;
for (ul j = page_start; j < page_end; j += ((j % 64) ? tmp : 64))
{
// 按照bmp中的每一个元素进行查找
// 先将p定位到bmp的起始元素
ul *p = memory_management_struct.bmp + (j >> 6);
ul shift = j % 64;
for (ul k = shift; k < 64; ++k)
{
if ((*p >> k) & 1) // 若当前页已分配
{
uint64_t page_num = j + k - shift;
struct Page *x = memory_management_struct.pages_struct + page_num;
if (x->addr_phys == phys_addr) // 找到对应的页
return x;
}
}
}
}
return NULL;
}
/**
* @brief 调整堆区域的大小(暂时只能增加堆区域)
*
* @todo 缩小堆区域
* @param old_brk_end_addr 原本的堆内存区域的结束地址
* @param offset 新的地址相对于原地址的偏移量
* @return uint64_t
*/
uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset)
{
uint64_t end_addr = PAGE_2M_ALIGN(old_brk_end_addr + offset);
if (offset >= 0)
{
for (uint64_t i = old_brk_end_addr; i < end_addr; i += PAGE_2M_SIZE)
{
struct vm_area_struct *vma = NULL;
mm_create_vma(current_pcb->mm, i, PAGE_2M_SIZE, VM_USER | VM_ACCESS_FLAGS, NULL, &vma);
mm_map(current_pcb->mm, i, PAGE_2M_SIZE, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys);
// mm_map_vma(vma, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, 0, PAGE_2M_SIZE);
}
current_pcb->mm->brk_end = end_addr;
}
else
{
// 释放堆内存
for (uint64_t i = end_addr; i < old_brk_end_addr; i += PAGE_2M_SIZE)
{
uint64_t phys = mm_get_PDE((uint64_t)phys_2_virt((uint64_t)current_pcb->mm->pgd), false, i, true);
// 找到对应的页
struct Page *p = mm_find_page(phys, ZONE_NORMAL);
if (p == NULL)
{
kerror("cannot find page addr=%#018lx", phys);
return end_addr;
}
free_pages(p, 1);
}
mm_unmap_proc_table((uint64_t)phys_2_virt((uint64_t)current_pcb->mm->pgd), false, end_addr, PAGE_2M_ALIGN(ABS(offset)));
// 在页表中取消映射
}
return end_addr;
}
/**
* @brief 创建mmio对应的页结构体
*
* @param paddr 物理地址
* @return struct Page* 创建成功的page
*/
struct Page *__create_mmio_page_struct(uint64_t paddr)
{
struct Page *p = (struct Page *)kzalloc(sizeof(struct Page), 0);
if (p == NULL)
return NULL;
p->addr_phys = paddr;
page_init(p, PAGE_DEVICE);
return p;
}

View File

@ -6,9 +6,9 @@
#include <mm/mm-types.h>
#include <process/process.h>
extern void rs_pseudo_map_phys(uint64_t virt_addr, uint64_t phys_addr, uint64_t size);
extern void rs_map_phys(uint64_t virt_addr, uint64_t phys_addr, uint64_t size, uint64_t flags);
extern uint64_t rs_unmap_at_low_addr();
// 每个页表的项数
// 64位下每个页表4k每条页表项8B故一个页表有512条
#define PTRS_PER_PGT 512
// 内核层的起始地址
#define PAGE_OFFSET 0xffff800000000000UL
@ -39,6 +39,9 @@ extern uint64_t rs_unmap_at_low_addr();
// 虚拟地址与物理地址转换
#define virt_2_phys(addr) ((unsigned long)(addr)-PAGE_OFFSET)
#define phys_2_virt(addr) ((unsigned long *)((unsigned long)(addr) + PAGE_OFFSET))
// 获取对应的页结构体
#define Virt_To_2M_Page(kaddr) (memory_management_struct.pages_struct + (virt_2_phys(kaddr) >> PAGE_2M_SHIFT))
#define Phy_to_2M_Page(kaddr) (memory_management_struct.pages_struct + ((unsigned long)(kaddr) >> PAGE_2M_SHIFT))
// 在这个地址以上的虚拟空间,用来进行特殊的映射
#define SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE 0xffffa00000000000UL
@ -46,6 +49,7 @@ extern uint64_t rs_unmap_at_low_addr();
#define IO_APIC_MAPPING_OFFSET 0xfec00000UL
#define LOCAL_APIC_MAPPING_OFFSET 0xfee00000UL
#define AHCI_MAPPING_OFFSET 0xff200000UL // AHCI 映射偏移量,之后使用了4M的地址
#define XHCI_MAPPING_OFFSET 0x100000000 // XHCI控制器映射偏移量(后方请预留1GB的虚拟空间来映射不同的controller)
// ===== 内存区域属性 =====
// DMA区域
@ -134,21 +138,59 @@ extern uint64_t rs_unmap_at_low_addr();
#define PAGE_USER_4K_PAGE (PAGE_U_S | PAGE_R_W | PAGE_PRESENT)
// ===== 错误码定义 ====
// 物理页结构体为空
#define EPAGE_NULL 1
/**
* @brief 刷新TLB的宏定义
* 由于任何写入cr3的操作都会刷新TLB因此这个宏定义可以刷新TLB
*/
#define flush_tlb() \
do \
{ \
ul tmp; \
io_mfence(); \
__asm__ __volatile__("movq %%cr3, %0\n\t" \
"movq %0, %%cr3\n\t" \
: "=r"(tmp)::"memory"); \
\
#define flush_tlb() \
do \
{ \
ul tmp; \
io_mfence(); \
__asm__ __volatile__("movq %%cr3, %0\n\t" \
"movq %0, %%cr3\n\t" \
: "=r"(tmp)::"memory"); \
\
} while (0);
/**
* @brief 系统内存信息结构体(单位:字节)
*
*/
struct mm_stat_t
{
uint64_t total; // 计算机的总内存数量大小
uint64_t used; // 已使用的内存大小
uint64_t free; // 空闲物理页所占的内存大小
uint64_t shared; // 共享的内存大小
uint64_t cache_used; // 位于slab缓冲区中的已使用的内存大小
uint64_t cache_free; // 位于slab缓冲区中的空闲的内存大小
uint64_t available; // 系统总空闲内存大小包括kmalloc缓冲区
};
/**
* @brief 虚拟内存区域的操作方法的结构体
*
*/
struct vm_operations_t
{
/**
* @brief vm area 被打开时的回调函数
*
*/
void (*open)(struct vm_area_struct *area);
/**
* @brief vm area将要被移除的时候将会调用该回调函数
*
*/
void (*close)(struct vm_area_struct *area);
};
extern struct memory_desc memory_management_struct;
// 导出内核程序的几个段的起止地址
extern char _text;
@ -161,6 +203,26 @@ extern char _bss;
extern char _ebss;
extern char _end;
// 每个区域的索引
int ZONE_DMA_INDEX = 0;
int ZONE_NORMAL_INDEX = 0;
int ZONE_UNMAPPED_INDEX = 0;
// 初始化内存管理单元
void mm_init();
/**
* @brief 初始化内存页
*
* @param page 内存页结构体
* @param flags 标志位
* 本函数只负责初始化内存页,允许对同一页面进行多次初始化
* 而维护计数器及置位bmp标志位的功能应当在分配页面的时候手动完成
* @return unsigned long
*/
unsigned long page_init(struct Page *page, ul flags);
/**
* @brief 读取CR3寄存器的值存储了页目录的基地址
*
@ -169,11 +231,70 @@ extern char _end;
unsigned long *get_CR3()
{
ul *tmp;
__asm__ __volatile__("movq %%cr3, %0\n\t"
: "=r"(tmp)::"memory");
__asm__ __volatile__("movq %%cr3, %0\n\t" : "=r"(tmp)::"memory");
return tmp;
}
/**
* @brief 从已初始化的页结构中搜索符合申请条件的、连续num个struct page
*
* @param zone_select 选择内存区域, 可选项dma, mapped in pgt(normal), unmapped in pgt
* @param num 需要申请的内存页的数量 num<64
* @param flags 将页面属性设置成flag
* @return struct Page*
*/
struct Page *alloc_pages(unsigned int zone_select, int num, ul flags);
/**
* @brief 清除页面的引用计数, 计数为0时清空除页表已映射以外的所有属性
*
* @param p 物理页结构体
* @return unsigned long
*/
unsigned long page_clean(struct Page *page);
/**
* @brief 释放连续number个内存页
*
* @param page 第一个要被释放的页面的结构体
* @param number 要释放的内存页数量 number<64
*/
void free_pages(struct Page *page, int number);
/**
* @brief Get the page's attr
*
* @param page 内存页结构体
* @return ul 属性
*/
ul get_page_attr(struct Page *page);
/**
* @brief Set the page's attr
*
* @param page 内存页结构体
* @param flags 属性
* @return ul 错误码
*/
ul set_page_attr(struct Page *page, ul flags);
#define mk_pml4t(addr, attr) ((unsigned long)(addr) | (unsigned long)(attr))
/**
* @brief 设置pml4页表的页表项
* @param pml4tptr pml4页表项的地址
* @param pml4val pml4页表项的值
*/
#define set_pml4t(pml4tptr, pml4tval) (*(pml4tptr) = (pml4tval))
#define mk_pdpt(addr, attr) ((unsigned long)(addr) | (unsigned long)(attr))
#define set_pdpt(pdptptr, pdptval) (*(pdptptr) = (pdptval))
#define mk_pdt(addr, attr) ((unsigned long)(addr) | (unsigned long)(attr))
#define set_pdt(pdtptr, pdtval) (*(pdtptr) = (pdtval))
#define mk_pt(addr, attr) ((unsigned long)(addr) | (unsigned long)(attr))
#define set_pt(ptptr, ptval) (*(ptptr) = (ptval))
/*
* vm_area_struct中的vm_flags的可选值
* 对应的结构体请见mm-types.h
@ -191,3 +312,233 @@ unsigned long *get_CR3()
/* VMA basic access permission flags */
#define VM_ACCESS_FLAGS (VM_READ | VM_WRITE | VM_EXEC)
/**
* @brief 初始化虚拟内存区域结构体
*
* @param vma
* @param mm
*/
static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
{
memset(vma, 0, sizeof(struct vm_area_struct));
vma->vm_mm = mm;
vma->vm_prev = vma->vm_next = NULL;
vma->vm_ops = NULL;
list_init(&vma->anon_vma_list);
}
/**
* @brief 判断给定的vma是否为当前进程所属的vma
*
* @param vma 给定的vma结构体
* @return true
* @return false
*/
static inline bool vma_is_foreign(struct vm_area_struct *vma)
{
if (current_pcb->mm == NULL)
return true;
if (current_pcb->mm != vma->vm_mm)
return true;
return false;
}
static inline bool vma_is_accessible(struct vm_area_struct *vma)
{
return vma->vm_flags & VM_ACCESS_FLAGS;
}
/**
* @brief 获取一块新的vma结构体并将其与指定的mm进行绑定
*
* @param mm 与VMA绑定的内存空间分布结构体
* @return struct vm_area_struct* 新的VMA
*/
struct vm_area_struct *vm_area_alloc(struct mm_struct *mm);
/**
* @brief 释放vma结构体
*
* @param vma 待释放的vma结构体
*/
void vm_area_free(struct vm_area_struct *vma);
/**
* @brief 从链表中删除指定的vma结构体
*
* @param vma
*/
void vm_area_del(struct vm_area_struct *vma);
/**
* @brief 查找第一个符合“addr < vm_end”条件的vma
*
* @param mm 内存空间分布结构体
* @param addr 虚拟地址
* @return struct vm_area_struct* 符合条件的vma
*/
struct vm_area_struct *vma_find(struct mm_struct *mm, uint64_t addr);
/**
* @brief 插入vma
*
* @param mm
* @param vma
* @return int
*/
int vma_insert(struct mm_struct *mm, struct vm_area_struct *vma);
/**
* @brief 重新初始化页表的函数
* 将所有物理页映射到线性地址空间
*/
void page_table_init();
/**
* @brief 将物理地址映射到页表的函数
*
* @param virt_addr_start 要映射到的虚拟地址的起始位置
* @param phys_addr_start 物理地址的起始位置
* @param length 要映射的区域的长度(字节)
* @param flags 标志位
* @param use4k 是否使用4k页
*/
int mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool use4k);
/**
* @brief 将将物理地址填写到进程的页表的函数
*
* @param proc_page_table_addr 页表的基地址
* @param is_phys 页表的基地址是否为物理地址
* @param virt_addr_start 要映射到的虚拟地址的起始位置
* @param phys_addr_start 物理地址的起始位置
* @param length 要映射的区域的长度(字节)
* @param user 用户态是否可访问
* @param flush 是否刷新tlb
* @param use4k 是否使用4k页
*/
int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul phys_addr_start, ul length,
ul flags, bool user, bool flush, bool use4k);
int mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul flags);
/**
* @brief 从页表中清除虚拟地址的映射
*
* @param proc_page_table_addr 页表的地址
* @param is_phys 页表地址是否为物理地址
* @param virt_addr_start 要清除的虚拟地址的起始地址
* @param length 要清除的区域的长度
*/
void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul length);
/**
* @brief 取消当前进程的页表中的虚拟地址映射
*
* @param virt_addr 虚拟地址
* @param length 地址长度
*/
#define mm_unmap_addr(virt_addr, length) ({ mm_unmap_proc_table((uint64_t)get_CR3(), true, virt_addr, length); })
/**
* @brief 创建VMA
*
* @param mm 要绑定的内存空间分布结构体
* @param vaddr 起始虚拟地址
* @param length 长度(字节)
* @param vm_flags vma的标志
* @param vm_ops vma的操作接口
* @param res_vma 返回的vma指针
* @return int 错误码
*/
int mm_create_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, vm_flags_t vm_flags,
struct vm_operations_t *vm_ops, struct vm_area_struct **res_vma);
/**
* @brief 将指定的物理地址映射到指定的vma处
*
* @param vma 要进行映射的VMA结构体
* @param paddr 起始物理地址
* @param offset 要映射的起始位置在vma中的偏移量
* @param length 要映射的长度
* @return int 错误码
*/
int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr, uint64_t offset, uint64_t length);
/**
* @brief 在页表中映射物理地址到指定的虚拟地址需要页表中已存在对应的vma
*
* @param mm 内存管理结构体
* @param vaddr 虚拟地址
* @param length 长度(字节)
* @param paddr 物理地址
* @return int 返回码
*/
int mm_map(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t paddr);
/**
* @brief 在页表中取消指定的vma的映射
*
* @param mm 指定的mm
* @param vma 待取消映射的vma
* @param paddr 返回的被取消映射的起始物理地址
* @return int 返回码
*/
int mm_unmap_vma(struct mm_struct *mm, struct vm_area_struct *vma, uint64_t *paddr);
/**
* @brief 解除一段虚拟地址的映射这些地址必须在vma中存在
*
* @param mm 内存空间结构体
* @param vaddr 起始地址
* @param length 结束地址
* @param destroy 是否释放vma结构体
* @return int 错误码
*/
int mm_unmap(struct mm_struct *mm, uint64_t vaddr, uint64_t length, bool destroy);
/**
* @brief 检测是否为有效的2M页(物理内存页)
*
* @param paddr 物理地址
* @return int8_t 是 -> 1
* 否 -> 0
*/
int8_t mm_is_2M_page(uint64_t paddr);
/**
* @brief 检查页表是否存在不为0的页表项
*
* @param ptr 页表基指针
* @return int8_t 存在 -> 1
* 不存在 -> 0
*/
int8_t mm_check_page_table(uint64_t *ptr);
/**
* @brief 调整堆区域的大小(暂时只能增加堆区域)
*
* @todo 缩小堆区域
* @param old_brk_end_addr 原本的堆内存区域的结束地址
* @param offset 新的地址相对于原地址的偏移量
* @return uint64_t
*/
uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset);
/**
* @brief 获取系统当前的内存信息(未上锁,不一定精准)
*
* @return struct mm_stat_t 内存信息结构体
*/
struct mm_stat_t mm_stat();
/**
* @brief 检测指定地址是否已经被映射
*
* @param page_table_phys_addr 页表的物理地址
* @param virt_addr 要检测的地址
* @return true 已经被映射
* @return false
*/
bool mm_check_mapped(ul page_table_phys_addr, uint64_t virt_addr);

582
kernel/src/mm/mmap.c Normal file
View File

@ -0,0 +1,582 @@
#include "mm.h"
#include "slab.h"
#include "internal.h"
#include <common/compiler.h>
#include <debug/bug.h>
extern uint64_t mm_total_2M_pages;
/**
* @brief 虚拟地址长度所需要的entry数量
*
*/
typedef struct
{
int64_t num_PML4E;
int64_t num_PDPTE;
int64_t num_PDE;
int64_t num_PTE;
} mm_pgt_entry_num_t;
/**
* @brief 计算虚拟地址长度对应的页表entry数量
*
* @param length 长度
* @param ent 返回的entry数量结构体
*/
static void mm_calculate_entry_num(uint64_t length, mm_pgt_entry_num_t *ent)
{
if (ent == NULL)
return;
ent->num_PML4E = (length + (1UL << PAGE_GDT_SHIFT) - 1) >> PAGE_GDT_SHIFT;
ent->num_PDPTE = (length + PAGE_1G_SIZE - 1) >> PAGE_1G_SHIFT;
ent->num_PDE = (length + PAGE_2M_SIZE - 1) >> PAGE_2M_SHIFT;
ent->num_PTE = (length + PAGE_4K_SIZE - 1) >> PAGE_4K_SHIFT;
}
/**
* @brief 将物理地址映射到页表的函数
*
* @param virt_addr_start 要映射到的虚拟地址的起始位置
* @param phys_addr_start 物理地址的起始位置
* @param length 要映射的区域的长度(字节)
* @param flags 标志位
* @param use4k 是否使用4k页
*/
int mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool use4k)
{
uint64_t global_CR3 = (uint64_t)get_CR3();
return mm_map_proc_page_table(global_CR3, true, virt_addr_start, phys_addr_start, length, flags, false, true, use4k);
}
int mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul flags)
{
uint64_t global_CR3 = (uint64_t)get_CR3();
return mm_map_proc_page_table(global_CR3, true, virt_addr_start, phys_addr_start, length, flags, true, true, false);
}
/**
* @brief 将将物理地址填写到进程的页表的函数
*
* @param proc_page_table_addr 页表的基地址
* @param is_phys 页表的基地址是否为物理地址
* @param virt_addr_start 要映射到的虚拟地址的起始位置
* @param phys_addr_start 物理地址的起始位置
* @param length 要映射的区域的长度(字节)
* @param user 用户态是否可访问
* @param flush 是否刷新tlb
* @param use4k 是否使用4k页
*/
int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool user, bool flush, bool use4k)
{
// 计算线性地址对应的pml4页表项的地址
mm_pgt_entry_num_t pgt_num;
mm_calculate_entry_num(length, &pgt_num);
// 已映射的内存大小
uint64_t length_mapped = 0;
// 对user标志位进行校正
if ((flags & PAGE_U_S) != 0)
user = true;
else
user = false;
uint64_t pml4e_id = ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff);
uint64_t *pml4_ptr;
if (is_phys)
pml4_ptr = phys_2_virt((ul *)((ul)proc_page_table_addr & (~0xfffUL)));
else
pml4_ptr = (ul *)((ul)proc_page_table_addr & (~0xfffUL));
// 循环填写顶层页表
for (; (pgt_num.num_PML4E > 0) && pml4e_id < 512; ++pml4e_id)
{
// 剩余需要处理的pml4E -1
--(pgt_num.num_PML4E);
ul *pml4e_ptr = pml4_ptr + pml4e_id;
// 创建新的二级页表
if (*pml4e_ptr == 0)
{
ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
memset(virt_addr, 0, PAGE_4K_SIZE);
set_pml4t(pml4e_ptr, mk_pml4t(virt_2_phys(virt_addr), (user ? PAGE_USER_PGT : PAGE_KERNEL_PGT)));
}
uint64_t pdpte_id = (((virt_addr_start + length_mapped) >> PAGE_1G_SHIFT) & 0x1ff);
uint64_t *pdpt_ptr = (uint64_t *)phys_2_virt(*pml4e_ptr & (~0xfffUL));
// 循环填写二级页表
for (; (pgt_num.num_PDPTE > 0) && pdpte_id < 512; ++pdpte_id)
{
--pgt_num.num_PDPTE;
uint64_t *pdpte_ptr = (pdpt_ptr + pdpte_id);
// 创建新的三级页表
if (*pdpte_ptr == 0)
{
ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
memset(virt_addr, 0, PAGE_4K_SIZE);
set_pdpt(pdpte_ptr, mk_pdpt(virt_2_phys(virt_addr), (user ? PAGE_USER_DIR : PAGE_KERNEL_DIR)));
}
uint64_t pde_id = (((virt_addr_start + length_mapped) >> PAGE_2M_SHIFT) & 0x1ff);
uint64_t *pd_ptr = (uint64_t *)phys_2_virt(*pdpte_ptr & (~0xfffUL));
// 循环填写三级页表初始化2M物理页
for (; (pgt_num.num_PDE > 0) && pde_id < 512; ++pde_id)
{
--pgt_num.num_PDE;
// 计算当前2M物理页对应的pdt的页表项的物理地址
ul *pde_ptr = pd_ptr + pde_id;
// ====== 使用4k页 =======
if (unlikely(use4k))
{
// kdebug("use 4k");
if (*pde_ptr == 0)
{
// 创建四级页表
uint64_t *vaddr = kmalloc(PAGE_4K_SIZE, 0);
memset(vaddr, 0, PAGE_4K_SIZE);
set_pdt(pde_ptr, mk_pdt(virt_2_phys(vaddr), (user ? PAGE_USER_PDE : PAGE_KERNEL_PDE)));
}
else if (unlikely(*pde_ptr & (1 << 7)))
{
// 当前页表项已经被映射了2MB物理页
goto failed;
}
uint64_t pte_id = (((virt_addr_start + length_mapped) >> PAGE_4K_SHIFT) & 0x1ff);
uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0xfffUL));
// 循环填写4级页表初始化4K页
for (; (pgt_num.num_PTE > 0) && pte_id < 512; ++pte_id)
{
--pgt_num.num_PTE;
uint64_t *pte_ptr = pt_ptr + pte_id;
if (unlikely(*pte_ptr != 0))
kwarn("pte already exists.");
else
set_pt(pte_ptr, mk_pt((ul)phys_addr_start + length_mapped, flags | (user ? PAGE_USER_4K_PAGE : PAGE_KERNEL_4K_PAGE)));
length_mapped += PAGE_4K_SIZE;
}
}
// ======= 使用2M页 ========
else
{
if (unlikely((*pde_ptr != 0) && user == true))
{
// 如果是用户态可访问的页,则释放当前新获取的物理页
if (likely((((ul)phys_addr_start + length_mapped) >> PAGE_2M_SHIFT) < mm_total_2M_pages)) // 校验是否为内存中的物理页
free_pages(Phy_to_2M_Page((ul)phys_addr_start + length_mapped), 1);
length_mapped += PAGE_2M_SIZE;
continue;
}
// 页面写穿,禁止缓存
set_pdt(pde_ptr, mk_pdt((ul)phys_addr_start + length_mapped, flags | (user ? PAGE_USER_PAGE : PAGE_KERNEL_PAGE)));
length_mapped += PAGE_2M_SIZE;
}
}
}
}
if (likely(flush))
flush_tlb();
return 0;
failed:;
kerror("Map memory failed. use4k=%d, vaddr=%#018lx, paddr=%#018lx", use4k, virt_addr_start, phys_addr_start);
return -EFAULT;
}
/**
* @brief 从页表中清除虚拟地址的映射
*
* @param proc_page_table_addr 页表的地址
* @param is_phys 页表地址是否为物理地址
* @param virt_addr_start 要清除的虚拟地址的起始地址
* @param length 要清除的区域的长度
*/
void mm_unmap_proc_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul length)
{
// 计算线性地址对应的pml4页表项的地址
mm_pgt_entry_num_t pgt_num;
mm_calculate_entry_num(length, &pgt_num);
// 已取消映射的内存大小
uint64_t length_unmapped = 0;
uint64_t pml4e_id = ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff);
uint64_t *pml4_ptr;
if (is_phys)
pml4_ptr = phys_2_virt((ul *)((ul)proc_page_table_addr & (~0xfffUL)));
else
pml4_ptr = (ul *)((ul)proc_page_table_addr & (~0xfffUL));
// 循环填写顶层页表
for (; (pgt_num.num_PML4E > 0) && pml4e_id < 512; ++pml4e_id)
{
// 剩余需要处理的pml4E -1
--(pgt_num.num_PML4E);
ul *pml4e_ptr = NULL;
pml4e_ptr = pml4_ptr + pml4e_id;
// 二级页表不存在
if (*pml4e_ptr == 0)
{
continue;
}
uint64_t pdpte_id = (((virt_addr_start + length_unmapped) >> PAGE_1G_SHIFT) & 0x1ff);
uint64_t *pdpt_ptr = (uint64_t *)phys_2_virt(*pml4e_ptr & (~0xfffUL));
// kdebug("pdpt_ptr=%#018lx", pdpt_ptr);
// 循环处理二级页表
for (; (pgt_num.num_PDPTE > 0) && pdpte_id < 512; ++pdpte_id)
{
--pgt_num.num_PDPTE;
uint64_t *pdpte_ptr = (pdpt_ptr + pdpte_id);
// kdebug("pgt_num.num_PDPTE=%ld pdpte_ptr=%#018lx", pgt_num.num_PDPTE, pdpte_ptr);
// 三级页表为空
if (*pdpte_ptr == 0)
{
continue;
}
uint64_t pde_id = (((virt_addr_start + length_unmapped) >> PAGE_2M_SHIFT) & 0x1ff);
uint64_t *pd_ptr = (uint64_t *)phys_2_virt(*pdpte_ptr & (~0xfffUL));
// kdebug("pd_ptr=%#018lx, *pd_ptr=%#018lx", pd_ptr, *pd_ptr);
// 循环处理三级页表
for (; (pgt_num.num_PDE > 0) && pde_id < 512; ++pde_id)
{
--pgt_num.num_PDE;
// 计算当前2M物理页对应的pdt的页表项的物理地址
ul *pde_ptr = pd_ptr + pde_id;
// 存在4级页表
if (((*pde_ptr) & (1 << 7)) == 0)
{
// 存在4K页
uint64_t pte_id = (((virt_addr_start + length_unmapped) >> PAGE_4K_SHIFT) & 0x1ff);
uint64_t *pt_ptr = (uint64_t *)phys_2_virt(*pde_ptr & (~0xfffUL));
// 循环处理4K页表
for (; pgt_num.num_PTE > 0 && pte_id < 512; ++pte_id)
{
uint64_t *pte_ptr = pt_ptr + pte_id;
--pgt_num.num_PTE;
*pte_ptr = 0;
length_unmapped += PAGE_4K_SIZE;
}
// 4级页表已经空了释放页表
if (unlikely(mm_check_page_table(pt_ptr)) == 0)
{
*pde_ptr = 0;
kfree(pt_ptr);
}
}
else
{
*pde_ptr = 0;
length_unmapped += PAGE_2M_SIZE;
pgt_num.num_PTE -= 512;
}
}
// 3级页表已经空了释放页表
if (unlikely(mm_check_page_table(pd_ptr)) == 0)
{
*pdpte_ptr = 0;
kfree(pd_ptr);
}
}
// 2级页表已经空了释放页表
if (unlikely(mm_check_page_table(pdpt_ptr)) == 0)
{
*pml4e_ptr = 0;
kfree(pdpt_ptr);
}
}
flush_tlb();
}
/**
* @brief 创建VMA
*
* @param mm 要绑定的内存空间分布结构体
* @param vaddr 起始虚拟地址
* @param length 长度(字节)
* @param vm_flags vma的标志
* @param vm_ops vma的操作接口
* @param res_vma 返回的vma指针
* @return int 错误码
*/
int mm_create_vma(struct mm_struct *mm, uint64_t vaddr, uint64_t length, vm_flags_t vm_flags, struct vm_operations_t *vm_ops, struct vm_area_struct **res_vma)
{
int retval = 0;
// 输入的地址如果不是4K对齐则报错
if (unlikely(vaddr & (PAGE_4K_SIZE - 1)))
return -EINVAL;
struct vm_area_struct *vma = vm_area_alloc(mm);
if (unlikely(vma == NULL))
return -ENOMEM;
vma->vm_ops = vm_ops;
vma->vm_flags = vm_flags;
vma->vm_start = vaddr;
vma->vm_end = vaddr + length;
// 将VMA加入mm的链表
retval = vma_insert(mm, vma);
if (retval == -EEXIST || retval == __VMA_MERGED) // 之前已经存在了相同的vma直接返回
{
*res_vma = vma_find(mm, vma->vm_start);
kfree(vma);
if (retval == -EEXIST)
return -EEXIST;
else
return 0;
}
if (res_vma != NULL)
*res_vma = vma;
return 0;
}
/**
* @brief 将指定的物理地址映射到指定的vma处
*
* @param vma 要进行映射的VMA结构体
* @param paddr 起始物理地址
* @param offset 要映射的起始位置在vma中的偏移量
* @param length 要映射的长度
* @return int 错误码
*/
int mm_map_vma(struct vm_area_struct *vma, uint64_t paddr, uint64_t offset, uint64_t length)
{
int retval = 0;
uint64_t mapped = 0;
BUG_ON((offset & (PAGE_4K_SIZE - 1)) != 0);
length = PAGE_4K_ALIGN(length); // 将length按照4K进行对齐
// 获取物理地址对应的页面
struct Page *pg;
uint64_t page_flags = 0;
if (vma->vm_flags & VM_IO) // 对于mmio的内存创建新的page结构体
{
page_flags = PAGE_PWT | PAGE_PCD;
if (unlikely(vma->anon_vma == NULL || vma->anon_vma->page == NULL))
pg = __create_mmio_page_struct(paddr);
else
pg = vma->anon_vma->page;
}
else
pg = Phy_to_2M_Page(paddr);
if (unlikely(pg->anon_vma == NULL)) // 若页面不存在anon_vma则为页面创建anon_vma
{
spin_lock(&pg->op_lock);
if (unlikely(pg->anon_vma == NULL))
__anon_vma_create_alloc(pg, false);
spin_unlock(&pg->op_lock);
}
barrier();
// 将anon vma与vma进行绑定
__anon_vma_add(pg->anon_vma, vma);
barrier();
// 长度超过界限
BUG_ON(vma->vm_start + offset + length > vma->vm_end);
/*
todo: 限制页面的读写权限
*/
// ==== 将地址映射到页表 ====
uint64_t len_4k, len_2m;
// 将地址使用4k页填补使得地址按照2M对齐
len_4k = PAGE_2M_ALIGN(vma->vm_start + offset) - (vma->vm_start + offset);
if (len_4k > 0)
len_4k = (len_4k > length) ? length : len_4k;
if (len_4k)
{
if (vma->vm_flags & VM_USER)
page_flags |= PAGE_USER_4K_PAGE;
else
page_flags |= PAGE_KERNEL_4K_PAGE;
// 这里直接设置user标志位为false因为该函数内部会对其进行自动校正
retval = mm_map_proc_page_table((uint64_t)vma->vm_mm->pgd, true, vma->vm_start + offset, paddr, len_4k, page_flags, false, false, true);
if (unlikely(retval != 0))
goto failed;
mapped += len_4k;
length -= len_4k;
}
len_4k = length % PAGE_2M_SIZE;
len_2m = length / PAGE_2M_SIZE;
// 映射连续的2M页
if (likely(len_2m > 0))
{
if (vma->vm_flags & VM_USER)
page_flags |= PAGE_USER_PAGE;
else
page_flags |= PAGE_KERNEL_PAGE;
// 这里直接设置user标志位为false因为该函数内部会对其进行自动校正
retval = mm_map_proc_page_table((uint64_t)vma->vm_mm->pgd, true, vma->vm_start + offset + mapped, paddr + mapped, len_2m, page_flags, false, false, false);
if (unlikely(retval != 0))
goto failed;
mapped += len_2m;
}
// 最后再使用4K页填补
if (likely(len_4k > 0))
{
if (vma->vm_flags & VM_USER)
page_flags |= PAGE_USER_4K_PAGE;
else
page_flags |= PAGE_KERNEL_4K_PAGE;
// 这里直接设置user标志位为false因为该函数内部会对其进行自动校正
retval = mm_map_proc_page_table((uint64_t)vma->vm_mm->pgd, true, vma->vm_start + offset + mapped, paddr + mapped, len_4k, page_flags, false, false, true);
if (unlikely(retval != 0))
goto failed;
mapped += len_4k;
}
if (vma->vm_flags & VM_IO)
vma->page_offset = 0;
flush_tlb();
return 0;
failed:;
kdebug("map VMA failed.");
return retval;
}
/**
* @brief 在页表中映射物理地址到指定的虚拟地址需要页表中已存在对应的vma
*
* @param mm 内存管理结构体
* @param vaddr 虚拟地址
* @param length 长度(字节)
* @param paddr 物理地址
* @return int 返回码
*/
int mm_map(struct mm_struct *mm, uint64_t vaddr, uint64_t length, uint64_t paddr)
{
int retval = 0;
uint64_t offset = 0;
for (uint64_t mapped = 0; mapped < length;)
{
struct vm_area_struct *vma = vma_find(mm, vaddr + mapped);
if (unlikely(vma == NULL))
{
kerror("Map addr failed: vma not found. At address: %#018lx, pid=%ld", vaddr + mapped, current_pcb->pid);
return -EINVAL;
}
// if (unlikely(vma->vm_start != (vaddr + mapped)))
// {
// kerror("Map addr failed: addr_start is not equal to current: %#018lx.", vaddr + mapped);
// return -EINVAL;
// }
offset = vaddr + mapped - vma->vm_start;
uint64_t m_len = vma->vm_end - vma->vm_start - offset;
// kdebug("start=%#018lx, offset=%ld", vma->vm_start, offset);
retval = mm_map_vma(vma, paddr + mapped, offset, m_len);
if (unlikely(retval != 0))
goto failed;
mapped += m_len;
}
return 0;
failed:;
kerror("Map addr failed.");
return retval;
}
/**
* @brief 在页表中取消指定的vma的映射
*
* @param mm 指定的mm
* @param vma 待取消映射的vma
* @param paddr 返回的被取消映射的起始物理地址
* @return int 返回码
*/
int mm_unmap_vma(struct mm_struct *mm, struct vm_area_struct *vma, uint64_t *paddr)
{
// 确保vma对应的mm与指定的mm相一致
if (unlikely(vma->vm_mm != mm))
return -EINVAL;
struct anon_vma_t *anon = vma->anon_vma;
if (paddr != NULL)
*paddr = __mm_get_paddr(mm, vma->vm_start);
if (anon == NULL)
kwarn("anon is NULL");
semaphore_down(&anon->sem);
mm_unmap_proc_table((uint64_t)mm->pgd, true, vma->vm_start, vma->vm_end - vma->vm_start);
__anon_vma_del(vma);
/** todo: 这里应该会存在bug应修复。
* 若anon_vma的等待队列上有其他的进程由于anon_vma被释放
* 这些在等待队列上的进程将无法被唤醒。
*/
list_init(&vma->anon_vma_list);
semaphore_up(&anon->sem);
return 0;
}
/**
* @brief 解除一段虚拟地址的映射这些地址必须在vma中存在
*
* @param mm 内存空间结构体
* @param vaddr 起始地址
* @param length 结束地址
* @param destroy 是否释放vma结构体
* @return int 错误码
*/
int mm_unmap(struct mm_struct *mm, uint64_t vaddr, uint64_t length, bool destroy)
{
int retval = 0;
for (uint64_t unmapped = 0; unmapped < length;)
{
struct vm_area_struct *vma = vma_find(mm, vaddr + unmapped);
if (unlikely(vma == NULL))
{
kerror("Unmap addr failed: vma not found. At address: %#018lx, pid=%ld", vaddr + unmapped, current_pcb->pid);
return -EINVAL;
}
if (unlikely(vma->vm_start != (vaddr + unmapped)))
{
kerror("Unmap addr failed: addr_start is not equal to current: %#018lx.", vaddr + unmapped);
return -EINVAL;
}
if (vma->anon_vma != NULL)
mm_unmap_vma(mm, vma, NULL);
unmapped += vma->vm_end - vma->vm_start;
// 释放vma结构体
if (destroy)
{
vm_area_del(vma);
vm_area_free(vma);
}
}
return 0;
failed:;
kerror("Unmap addr failed.");
return retval;
}

9
kernel/src/mm/mmio.c Normal file
View File

@ -0,0 +1,9 @@
#include "mmio.h"
#include <common/math.h>
extern void __mmio_buddy_init();
void mmio_init()
{
__mmio_buddy_init();
kinfo("mmio_init success");
}

View File

@ -1,5 +1,7 @@
#pragma once
#include "mm.h"
extern void mmio_create(uint32_t size, uint64_t vm_flagsu, uint64_t* res_vaddr, uint64_t* res_length);
extern void mmio_buddy_init();
extern void mmio_create();
extern int mmio_release(int vaddr, int length);
void mmio_init();

View File

@ -1,19 +1,16 @@
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
use crate::mm::kernel_mapper::KernelMapper;
use crate::syscall::SystemError;
use crate::{
arch::asm::current::current_pcb,
include::bindings::bindings::{vm_flags_t, PAGE_1G_SHIFT, PAGE_4K_SHIFT, PAGE_4K_SIZE},
kdebug,
mm::{MMArch, MemoryManagementArch},
include::bindings::bindings::{
initial_mm, mm_create_vma, mm_unmap, vm_area_del, vm_area_free, vm_area_struct, vm_flags_t,
vma_find, MMIO_BASE, MMIO_TOP, PAGE_1G_SHIFT, PAGE_1G_SIZE, PAGE_2M_SIZE, PAGE_4K_SHIFT,
PAGE_4K_SIZE, VM_DONTCOPY, VM_IO,
},
kdebug, kerror,
};
use crate::{kerror, kinfo, kwarn};
use alloc::{collections::LinkedList, vec::Vec};
use core::mem;
use core::mem::MaybeUninit;
use core::sync::atomic::{compiler_fence, Ordering};
use super::VirtAddr;
use alloc::{boxed::Box, collections::LinkedList, vec::Vec};
use core::{mem, ptr::null_mut};
// 最大的伙伴块的幂
const MMIO_BUDDY_MAX_EXP: u32 = PAGE_1G_SHIFT;
@ -22,15 +19,8 @@ const MMIO_BUDDY_MIN_EXP: u32 = PAGE_4K_SHIFT;
// 内存池数组的范围
const MMIO_BUDDY_REGION_COUNT: u32 = MMIO_BUDDY_MAX_EXP - MMIO_BUDDY_MIN_EXP + 1;
const MMIO_BASE: VirtAddr = VirtAddr::new(0xffffa10000000000);
const MMIO_TOP: VirtAddr = VirtAddr::new(0xffffa20000000000);
const PAGE_1G_SIZE: usize = 1 << 30;
static mut __MMIO_POOL: Option<MmioBuddyMemPool> = None;
pub fn mmio_pool() -> &'static mut MmioBuddyMemPool {
unsafe { __MMIO_POOL.as_mut().unwrap() }
lazy_static! {
pub static ref MMIO_POOL: MmioBuddyMemPool = MmioBuddyMemPool::new();
}
pub enum MmioResult {
@ -42,49 +32,25 @@ pub enum MmioResult {
}
/// @brief buddy内存池
#[derive(Debug)]
pub struct MmioBuddyMemPool {
pool_start_addr: VirtAddr,
pool_size: usize,
pool_start_addr: u64,
pool_size: u64,
free_regions: [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize],
}
impl Default for MmioBuddyMemPool {
fn default() -> Self {
MmioBuddyMemPool {
pool_start_addr: MMIO_BASE as u64,
pool_size: (MMIO_TOP - MMIO_BASE) as u64,
free_regions: unsafe { mem::zeroed() },
}
}
}
impl MmioBuddyMemPool {
fn new() -> Self {
let mut free_regions: [MaybeUninit<SpinLock<MmioFreeRegionList>>;
MMIO_BUDDY_REGION_COUNT as usize] = unsafe { MaybeUninit::uninit().assume_init() };
for i in 0..MMIO_BUDDY_REGION_COUNT {
free_regions[i as usize] = MaybeUninit::new(SpinLock::new(MmioFreeRegionList::new()));
}
let free_regions = unsafe {
mem::transmute::<_, [SpinLock<MmioFreeRegionList>; MMIO_BUDDY_REGION_COUNT as usize]>(
free_regions,
)
return MmioBuddyMemPool {
..Default::default()
};
let pool = MmioBuddyMemPool {
pool_start_addr: MMIO_BASE,
pool_size: MMIO_TOP - MMIO_BASE,
free_regions,
};
kdebug!("MMIO buddy pool init: created");
let cnt_1g_blocks = (MMIO_TOP - MMIO_BASE) >> 30;
let mut vaddr_base = MMIO_BASE;
kdebug!("total 1G blocks: {cnt_1g_blocks}");
for _i in 0..cnt_1g_blocks {
compiler_fence(Ordering::SeqCst);
match pool.give_back_block(vaddr_base, PAGE_1G_SHIFT) {
Ok(_) => {
vaddr_base += PAGE_1G_SIZE;
}
Err(_) => {
panic!("MMIO buddy pool init failed");
}
}
}
kdebug!("MMIO buddy pool init success");
return pool;
}
/// @brief 创建新的地址区域结构体
@ -92,12 +58,9 @@ impl MmioBuddyMemPool {
/// @param vaddr 虚拟地址
///
/// @return 创建好的地址区域结构体
fn create_region(&self, vaddr: VirtAddr) -> MmioBuddyAddrRegion {
// kdebug!("create_region for vaddr: {vaddr:?}");
let region: MmioBuddyAddrRegion = MmioBuddyAddrRegion::new(vaddr);
// kdebug!("create_region for vaddr: {vaddr:?} OK!!!");
fn create_region(&self, vaddr: u64) -> Box<MmioBuddyAddrRegion> {
let mut region: Box<MmioBuddyAddrRegion> = Box::new(MmioBuddyAddrRegion::new());
region.vaddr = vaddr;
return region;
}
@ -112,16 +75,16 @@ impl MmioBuddyMemPool {
/// @return Ok(i32) 返回0
///
/// @return Err(SystemError) 返回错误码
fn give_back_block(&self, vaddr: VirtAddr, exp: u32) -> Result<i32, SystemError> {
fn give_back_block(&self, vaddr: u64, exp: u32) -> Result<i32, SystemError> {
// 确保内存对齐低位都要为0
if (vaddr.data() & ((1 << exp) - 1)) != 0 {
if (vaddr & ((1 << exp) - 1)) != 0 {
return Err(SystemError::EINVAL);
}
let region: MmioBuddyAddrRegion = self.create_region(vaddr);
let region: Box<MmioBuddyAddrRegion> = self.create_region(vaddr);
// 加入buddy
let mut list_guard = self.free_regions[exp2index(exp)].lock();
self.push_block(region, &mut list_guard);
let list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
&mut self.free_regions[exp2index(exp)].lock();
self.push_block(region, list_guard);
return Ok(0);
}
@ -134,12 +97,12 @@ impl MmioBuddyMemPool {
/// @param list_guard 【exp-1】对应的链表
fn split_block(
&self,
region: MmioBuddyAddrRegion,
region: Box<MmioBuddyAddrRegion>,
exp: u32,
low_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) {
let vaddr = self.calculate_block_vaddr(region.vaddr, exp - 1);
let new_region: MmioBuddyAddrRegion = self.create_region(vaddr);
let vaddr: u64 = self.calculate_block_vaddr(region.vaddr, exp - 1);
let new_region: Box<MmioBuddyAddrRegion> = self.create_region(vaddr);
self.push_block(region, low_list_guard);
self.push_block(new_region, low_list_guard);
}
@ -150,7 +113,7 @@ impl MmioBuddyMemPool {
///
/// @param list_guard exp对应的链表
///
/// @return Ok(MmioBuddyAddrRegion) 符合要求的内存区域。
/// @return Ok(Box<MmioBuddyAddrRegion>) 符合要求的内存区域。
///
/// @return Err(MmioResult)
/// - 没有满足要求的内存块时返回ENOFOUND
@ -160,7 +123,7 @@ impl MmioBuddyMemPool {
&self,
exp: u32,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<MmioBuddyAddrRegion, MmioResult> {
) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> {
// 申请范围错误
if exp < MMIO_BUDDY_MIN_EXP || exp > MMIO_BUDDY_MAX_EXP {
kdebug!("query_addr_region: exp wrong");
@ -293,9 +256,12 @@ impl MmioBuddyMemPool {
///
/// @param exp 内存区域的大小(2^exp)
///
/// @return Ok(MmioBuddyAddrRegion)符合要求的内存块信息结构体。
/// @return Ok(Box<MmioBuddyAddrRegion>)符合要求的内存块信息结构体。
/// @return Err(MmioResult) 没有满足要求的内存块时返回__query_addr_region的错误码。
fn mmio_buddy_query_addr_region(&self, exp: u32) -> Result<MmioBuddyAddrRegion, MmioResult> {
fn mmio_buddy_query_addr_region(
&self,
exp: u32,
) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> {
let list_guard: &mut SpinLockGuard<MmioFreeRegionList> =
&mut self.free_regions[exp2index(exp)].lock();
match self.query_addr_region(exp, list_guard) {
@ -313,7 +279,7 @@ impl MmioBuddyMemPool {
/// @param list_guard 目标链表
fn push_block(
&self,
region: MmioBuddyAddrRegion,
region: Box<MmioBuddyAddrRegion>,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) {
list_guard.list.push_back(region);
@ -322,8 +288,8 @@ impl MmioBuddyMemPool {
/// @brief 根据地址和内存块大小,计算伙伴块虚拟内存的地址
#[inline(always)]
fn calculate_block_vaddr(&self, vaddr: VirtAddr, exp: u32) -> VirtAddr {
return VirtAddr::new(vaddr.data() ^ (1 << exp as usize));
fn calculate_block_vaddr(&self, vaddr: u64, exp: u32) -> u64 {
return vaddr ^ (1 << exp);
}
/// @brief 寻找并弹出指定内存块的伙伴块
@ -340,10 +306,10 @@ impl MmioBuddyMemPool {
/// - 没有找到伙伴块返回ENOFOUND
fn pop_buddy_block(
&self,
vaddr: VirtAddr,
vaddr: u64,
exp: u32,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<MmioBuddyAddrRegion, MmioResult> {
) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> {
if list_guard.list.len() == 0 {
return Err(MmioResult::ISEMPTY);
} else {
@ -351,7 +317,7 @@ impl MmioBuddyMemPool {
let buddy_vaddr = self.calculate_block_vaddr(vaddr, exp);
// element 只会有一个元素
let mut element: Vec<MmioBuddyAddrRegion> = list_guard
let mut element: Vec<Box<MmioBuddyAddrRegion>> = list_guard
.list
.drain_filter(|x| x.vaddr == buddy_vaddr)
.collect();
@ -369,13 +335,13 @@ impl MmioBuddyMemPool {
///
/// @param list_guard 【exp】对应的链表
///
/// @return Ok(MmioBuddyAddrRegion) 内存块信息结构体的引用。
/// @return Ok(Box<MmioBuddyAddrRegion>) 内存块信息结构体的引用。
///
/// @return Err(MmioResult) 当链表为空无法删除时返回ISEMPTY
fn pop_block(
&self,
list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<MmioBuddyAddrRegion, MmioResult> {
) -> Result<Box<MmioBuddyAddrRegion>, MmioResult> {
if !list_guard.list.is_empty() {
list_guard.num_free -= 1;
return Ok(list_guard.list.pop_back().unwrap());
@ -411,15 +377,17 @@ impl MmioBuddyMemPool {
break;
}
// 获取内存块
let vaddr: VirtAddr = list_guard.list.back().unwrap().vaddr;
let vaddr: u64 = list_guard.list.back().unwrap().vaddr;
// 获取伙伴内存块
match self.pop_buddy_block(vaddr, exp, list_guard) {
Err(err) => {
return Err(err);
}
Ok(buddy_region) => {
let region: MmioBuddyAddrRegion = list_guard.list.pop_back().unwrap();
let copy_region = region.clone();
let region: Box<MmioBuddyAddrRegion> = list_guard.list.pop_back().unwrap();
let copy_region: Box<MmioBuddyAddrRegion> = Box::new(MmioBuddyAddrRegion {
vaddr: region.vaddr,
});
// 在两块内存都被取出之后才进行合并
match self.merge_blocks(region, buddy_region, exp, high_list_guard) {
Err(err) => {
@ -447,8 +415,8 @@ impl MmioBuddyMemPool {
/// @return Err(MmioResult) 两个内存块不是伙伴块,返回EINVAL
fn merge_blocks(
&self,
region_1: MmioBuddyAddrRegion,
region_2: MmioBuddyAddrRegion,
region_1: Box<MmioBuddyAddrRegion>,
region_2: Box<MmioBuddyAddrRegion>,
exp: u32,
high_list_guard: &mut SpinLockGuard<MmioFreeRegionList>,
) -> Result<MmioResult, MmioResult> {
@ -476,43 +444,102 @@ impl MmioBuddyMemPool {
/// @return Err(SystemError) 失败返回错误码
pub fn create_mmio(
&self,
size: usize,
_vm_flags: vm_flags_t,
size: u32,
vm_flags: vm_flags_t,
res_vaddr: *mut u64,
res_length: *mut u64,
) -> Result<i32, SystemError> {
if size > PAGE_1G_SIZE || size == 0 {
return Err(SystemError::EPERM);
}
let retval: i32 = 0;
let mut retval: i32 = 0;
// 计算前导0
#[cfg(target_arch = "x86_64")]
let mut size_exp: u32 = 63 - size.leading_zeros();
let mut size_exp: u32 = 31 - size.leading_zeros();
// 记录最终申请的空间大小
let mut new_size = size;
let mut new_size: u32 = size;
// 对齐要申请的空间大小
// 如果要申请的空间大小小于4k则分配4k
if size_exp < PAGE_4K_SHIFT {
new_size = PAGE_4K_SIZE as usize;
new_size = PAGE_4K_SIZE;
size_exp = PAGE_4K_SHIFT;
} else if (new_size & (!(1 << size_exp))) != 0 {
// 向左对齐空间大小
size_exp += 1;
new_size = 1 << size_exp;
}
match self.mmio_buddy_query_addr_region(size_exp) {
match MMIO_POOL.mmio_buddy_query_addr_region(size_exp) {
Ok(region) => {
// todo: 是否需要创建vma或者用新重写的机制去做
// kdebug!(
// "create_mmio: vaddr = {:?}, length = {}",
// region.vaddr,
// new_size
// );
unsafe { *res_vaddr = region.vaddr.data() as u64 };
unsafe { *res_length = new_size as u64 };
unsafe {
*res_vaddr = region.vaddr;
*res_length = new_size as u64;
}
// 创建vma
let flags: u64 = vm_flags | (VM_IO | VM_DONTCOPY) as u64;
let len_4k: u64 = (new_size % PAGE_2M_SIZE) as u64;
let len_2m: u64 = new_size as u64 - len_4k;
let mut loop_i: u64 = 0;
// 先分配2M的vma
loop {
if loop_i >= len_2m {
break;
}
let vma: *mut *mut vm_area_struct = null_mut();
retval = unsafe {
mm_create_vma(
&mut initial_mm,
region.vaddr + loop_i,
PAGE_2M_SIZE.into(),
flags,
null_mut(),
vma,
)
};
if retval != 0 {
kdebug!(
"failed to create mmio 2m vma. pid = {:?}",
current_pcb().pid
);
unsafe {
vm_area_del(*vma);
vm_area_free(*vma);
}
return Err(SystemError::from_posix_errno(retval).unwrap());
}
loop_i += PAGE_2M_SIZE as u64;
}
// 分配4K的vma
loop_i = len_2m;
loop {
if loop_i >= size as u64 {
break;
}
let vma: *mut *mut vm_area_struct = null_mut();
retval = unsafe {
mm_create_vma(
&mut initial_mm,
region.vaddr + loop_i,
PAGE_4K_SIZE.into(),
flags,
null_mut(),
vma,
)
};
if retval != 0 {
kdebug!(
"failed to create mmio 4k vma. pid = {:?}",
current_pcb().pid
);
unsafe {
vm_area_del(*vma);
vm_area_free(*vma);
}
return Err(SystemError::from_posix_errno(retval).unwrap());
}
loop_i += PAGE_4K_SIZE as u64;
}
}
Err(_) => {
kerror!("failed to create mmio. pid = {:?}", current_pcb().pid);
kdebug!("failed to create mmio vma.pid = {:?}", current_pcb().pid);
return Err(SystemError::ENOMEM);
}
}
@ -528,62 +555,83 @@ impl MmioBuddyMemPool {
/// @return Ok(i32) 成功返回0
///
/// @return Err(SystemError) 失败返回错误码
pub fn release_mmio(&self, vaddr: VirtAddr, length: usize) -> Result<i32, SystemError> {
assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
assert!(length & (MMArch::PAGE_SIZE - 1) == 0);
if vaddr < self.pool_start_addr
|| vaddr.data() >= self.pool_start_addr.data() + self.pool_size
{
return Err(SystemError::EINVAL);
pub fn release_mmio(&self, vaddr: u64, length: u64) -> Result<i32, SystemError> {
//先将要释放的空间取消映射
unsafe {
mm_unmap(&mut initial_mm, vaddr, length, false);
}
// todo: 重构MMIO管理机制创建类似全局的manager之类的管理MMIO的空间
// 暂时认为传入的vaddr都是正确的
let page_count = length / MMArch::PAGE_SIZE;
// 取消映射
let mut bindings = KernelMapper::lock();
let mut kernel_mapper = bindings.as_mut();
if kernel_mapper.is_none() {
kwarn!("release_mmio: kernel_mapper is read only");
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
let mut loop_i: u64 = 0;
loop {
if loop_i >= length {
break;
}
// 获取要释放的vma的结构体
let vma: *mut vm_area_struct = unsafe { vma_find(&mut initial_mm, vaddr + loop_i) };
if vma == null_mut() {
kdebug!(
"mmio_release failed: vma not found. At address: {:?}, pid = {:?}",
vaddr + loop_i,
current_pcb().pid
);
return Err(SystemError::EINVAL);
}
// 检查vma起始地址是否正确
if unsafe { (*vma).vm_start != (vaddr + loop_i) } {
kdebug!(
"mmio_release failed: addr_start is not equal to current: {:?}. pid = {:?}",
vaddr + loop_i,
current_pcb().pid
);
return Err(SystemError::EINVAL);
}
// 将vma对应空间归还
match MMIO_POOL.give_back_block(unsafe { (*vma).vm_start }, unsafe {
31 - ((*vma).vm_end - (*vma).vm_start).leading_zeros()
}) {
Ok(_) => {
loop_i += unsafe { (*vma).vm_end - (*vma).vm_start };
unsafe {
vm_area_del(vma);
vm_area_free(vma);
}
}
Err(err) => {
// vma对应空间没有成功归还的话就不删除vma
kdebug!(
"mmio_release give_back failed: pid = {:?}",
current_pcb().pid
);
return Err(err);
}
}
}
for i in 0..page_count {
unsafe {
kernel_mapper
.as_mut()
.unwrap()
.unmap(vaddr + i * MMArch::PAGE_SIZE, true)
};
}
// todo: 归还到buddy
return Ok(0);
}
}
/// @brief mmio伙伴系统内部的地址区域结构体
#[derive(Debug, Clone)]
struct MmioBuddyAddrRegion {
vaddr: VirtAddr,
pub struct MmioBuddyAddrRegion {
vaddr: u64,
}
impl MmioBuddyAddrRegion {
pub fn new(vaddr: VirtAddr) -> Self {
return MmioBuddyAddrRegion { vaddr };
pub fn new() -> Self {
return MmioBuddyAddrRegion {
..Default::default()
};
}
#[allow(dead_code)]
pub fn vaddr(&self) -> VirtAddr {
return self.vaddr;
}
impl Default for MmioBuddyAddrRegion {
fn default() -> Self {
MmioBuddyAddrRegion {
vaddr: Default::default(),
}
}
}
/// @brief 空闲页数组结构体
#[derive(Debug)]
pub struct MmioFreeRegionList {
/// 存储mmio_buddy的地址链表
list: LinkedList<MmioBuddyAddrRegion>,
list: LinkedList<Box<MmioBuddyAddrRegion>>,
/// 空闲块的数量
num_free: i64,
}
@ -604,6 +652,25 @@ impl Default for MmioFreeRegionList {
}
}
/// @brief 初始化mmio的伙伴系统
#[no_mangle]
pub extern "C" fn __mmio_buddy_init() {
// 创建一堆1GB的地址块
let cnt_1g_blocks: u32 = ((MMIO_TOP - MMIO_BASE) / PAGE_1G_SIZE as i64) as u32;
let mut vaddr_base: u64 = MMIO_BASE as u64;
for _ in 0..cnt_1g_blocks {
match MMIO_POOL.give_back_block(vaddr_base, PAGE_1G_SHIFT) {
Ok(_) => {
vaddr_base += PAGE_1G_SIZE as u64;
}
Err(_) => {
kerror!("__mmio_buddy_init failed");
return;
}
}
}
}
/// @brief 将内存对象大小的幂转换成内存池中的数组的下标
///
/// @param exp内存大小
@ -614,15 +681,6 @@ fn exp2index(exp: u32) -> usize {
return (exp - 12) as usize;
}
pub fn mmio_init() {
kdebug!("Initializing MMIO buddy memory pool...");
// 初始化mmio内存池
unsafe {
__MMIO_POOL = Some(MmioBuddyMemPool::new());
}
kinfo!("MMIO buddy memory pool init done");
}
/// @brief 创建一块mmio区域并将vma绑定到initial_mm
///
/// @param size mmio区域的大小字节
@ -641,8 +699,7 @@ pub extern "C" fn mmio_create(
res_vaddr: *mut u64,
res_length: *mut u64,
) -> i32 {
// kdebug!("mmio_create");
if let Err(err) = mmio_pool().create_mmio(size as usize, vm_flags, res_vaddr, res_length) {
if let Err(err) = MMIO_POOL.create_mmio(size, vm_flags, res_vaddr, res_length) {
return err.to_posix_errno();
} else {
return 0;
@ -660,7 +717,9 @@ pub extern "C" fn mmio_create(
/// @return Err(i32) 失败返回错误码
#[no_mangle]
pub extern "C" fn mmio_release(vaddr: u64, length: u64) -> i32 {
return mmio_pool()
.release_mmio(VirtAddr::new(vaddr as usize), length as usize)
.unwrap_or_else(|err| err.to_posix_errno());
if let Err(err) = MMIO_POOL.release_mmio(vaddr, length) {
return err.to_posix_errno();
} else {
return 0;
}
}

View File

@ -1,63 +1,9 @@
use alloc::sync::Arc;
use crate::{
arch::MMArch,
include::bindings::bindings::{process_control_block, PAGE_OFFSET},
syscall::SystemError,
};
use core::{
cmp,
fmt::Debug,
intrinsics::unlikely,
ops::{Add, AddAssign, Sub, SubAssign},
ptr,
sync::atomic::{AtomicBool, Ordering},
};
use self::{
allocator::page_frame::{VirtPageFrame, VirtPageFrameIter},
page::round_up_to_page_size,
ucontext::{AddressSpace, UserMapper},
};
use crate::include::bindings::bindings::{mm_struct, process_control_block, PAGE_OFFSET};
pub mod allocator;
pub mod c_adapter;
pub mod gfp;
pub mod kernel_mapper;
pub mod mmio_buddy;
pub mod no_init;
pub mod page;
pub mod syscall;
pub mod ucontext;
/// 内核INIT进程的用户地址空间结构体仅在process_init中初始化
static mut __INITIAL_PROCESS_ADDRESS_SPACE: Option<Arc<AddressSpace>> = None;
/// 获取内核INIT进程的用户地址空间结构体
#[allow(non_snake_case)]
#[inline(always)]
pub fn INITIAL_PROCESS_ADDRESS_SPACE() -> Arc<AddressSpace> {
unsafe {
return __INITIAL_PROCESS_ADDRESS_SPACE
.as_ref()
.expect("INITIAL_PROCESS_ADDRESS_SPACE is null")
.clone();
}
}
/// 设置内核INIT进程的用户地址空间结构体全局变量
#[allow(non_snake_case)]
pub unsafe fn set_INITIAL_PROCESS_ADDRESS_SPACE(address_space: Arc<AddressSpace>) {
static INITIALIZED: AtomicBool = AtomicBool::new(false);
if INITIALIZED
.compare_exchange(false, true, Ordering::SeqCst, Ordering::Acquire)
.is_err()
{
panic!("INITIAL_PROCESS_ADDRESS_SPACE is already initialized");
}
__INITIAL_PROCESS_ADDRESS_SPACE = Some(address_space);
}
/// @brief 将内核空间的虚拟地址转换为物理地址
#[inline(always)]
@ -71,561 +17,10 @@ pub fn phys_2_virt(addr: usize) -> usize {
addr + PAGE_OFFSET as usize
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub enum PageTableKind {
/// 用户可访问的页表
User,
/// 内核页表
Kernel,
}
/// 物理内存地址
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Hash)]
#[repr(transparent)]
pub struct PhysAddr(usize);
impl PhysAddr {
#[inline(always)]
pub const fn new(address: usize) -> Self {
Self(address)
}
/// @brief 获取物理地址的值
#[inline(always)]
pub fn data(&self) -> usize {
self.0
}
/// @brief 将物理地址加上一个偏移量
#[inline(always)]
pub fn add(self, offset: usize) -> Self {
Self(self.0 + offset)
}
/// @brief 判断物理地址是否按照指定要求对齐
#[inline(always)]
pub fn check_aligned(&self, align: usize) -> bool {
return self.0 & (align - 1) == 0;
}
#[inline(always)]
pub fn is_null(&self) -> bool {
return self.0 == 0;
}
}
impl Debug for PhysAddr {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "PhysAddr({:#x})", self.0)
}
}
impl core::ops::Add<usize> for PhysAddr {
type Output = Self;
#[inline(always)]
fn add(self, rhs: usize) -> Self::Output {
return Self(self.0 + rhs);
}
}
impl core::ops::AddAssign<usize> for PhysAddr {
#[inline(always)]
fn add_assign(&mut self, rhs: usize) {
self.0 += rhs;
}
}
impl core::ops::Add<PhysAddr> for PhysAddr {
type Output = Self;
#[inline(always)]
fn add(self, rhs: PhysAddr) -> Self::Output {
return Self(self.0 + rhs.0);
}
}
impl core::ops::AddAssign<PhysAddr> for PhysAddr {
#[inline(always)]
fn add_assign(&mut self, rhs: PhysAddr) {
self.0 += rhs.0;
}
}
impl core::ops::Sub<usize> for PhysAddr {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: usize) -> Self::Output {
return Self(self.0 - rhs);
}
}
impl core::ops::SubAssign<usize> for PhysAddr {
#[inline(always)]
fn sub_assign(&mut self, rhs: usize) {
self.0 -= rhs;
}
}
impl core::ops::Sub<PhysAddr> for PhysAddr {
type Output = usize;
#[inline(always)]
fn sub(self, rhs: PhysAddr) -> Self::Output {
return self.0 - rhs.0;
}
}
impl core::ops::SubAssign<PhysAddr> for PhysAddr {
#[inline(always)]
fn sub_assign(&mut self, rhs: PhysAddr) {
self.0 -= rhs.0;
}
}
/// 虚拟内存地址
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Hash)]
#[repr(transparent)]
pub struct VirtAddr(usize);
impl VirtAddr {
#[inline(always)]
pub const fn new(address: usize) -> Self {
return Self(address);
}
/// @brief 获取虚拟地址的值
#[inline(always)]
pub fn data(&self) -> usize {
return self.0;
}
/// @brief 判断虚拟地址的类型
#[inline(always)]
pub fn kind(&self) -> PageTableKind {
if self.check_user() {
return PageTableKind::User;
} else {
return PageTableKind::Kernel;
}
}
/// @brief 判断虚拟地址是否按照指定要求对齐
#[inline(always)]
pub fn check_aligned(&self, align: usize) -> bool {
return self.0 & (align - 1) == 0;
}
/// @brief 判断虚拟地址是否在用户空间
#[inline(always)]
pub fn check_user(&self) -> bool {
if self < &MMArch::USER_END_VADDR {
return true;
} else {
return false;
}
}
#[inline(always)]
pub fn as_ptr<T>(self) -> *mut T {
return self.0 as *mut T;
}
#[inline(always)]
pub fn is_null(&self) -> bool {
return self.0 == 0;
}
}
impl Add<VirtAddr> for VirtAddr {
type Output = Self;
#[inline(always)]
fn add(self, rhs: VirtAddr) -> Self::Output {
return Self(self.0 + rhs.0);
}
}
impl Add<usize> for VirtAddr {
type Output = Self;
#[inline(always)]
fn add(self, rhs: usize) -> Self::Output {
return Self(self.0 + rhs);
}
}
impl Sub<VirtAddr> for VirtAddr {
type Output = usize;
#[inline(always)]
fn sub(self, rhs: VirtAddr) -> Self::Output {
return self.0 - rhs.0;
}
}
impl Sub<usize> for VirtAddr {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: usize) -> Self::Output {
return Self(self.0 - rhs);
}
}
impl AddAssign<usize> for VirtAddr {
#[inline(always)]
fn add_assign(&mut self, rhs: usize) {
self.0 += rhs;
}
}
impl AddAssign<VirtAddr> for VirtAddr {
#[inline(always)]
fn add_assign(&mut self, rhs: VirtAddr) {
self.0 += rhs.0;
}
}
impl SubAssign<usize> for VirtAddr {
#[inline(always)]
fn sub_assign(&mut self, rhs: usize) {
self.0 -= rhs;
}
}
impl SubAssign<VirtAddr> for VirtAddr {
#[inline(always)]
fn sub_assign(&mut self, rhs: VirtAddr) {
self.0 -= rhs.0;
}
}
impl Debug for VirtAddr {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "VirtAddr({:#x})", self.0)
}
}
/// @brief 物理内存区域
#[derive(Clone, Copy, Debug)]
pub struct PhysMemoryArea {
/// 物理基地址
pub base: PhysAddr,
/// 该区域的物理内存大小
pub size: usize,
}
pub trait MemoryManagementArch: Clone + Copy + Debug {
/// 页面大小的shift假如页面4K那么这个值就是12,因为2^12=4096
const PAGE_SHIFT: usize;
/// 每个页表的页表项数目。以2^n次幂来表示假如有512个页表项那么这个值就是9
const PAGE_ENTRY_SHIFT: usize;
/// 页表层级数量
const PAGE_LEVELS: usize;
/// 页表项的有效位的index假如页表项的第0-51位有效那么这个值就是52
const ENTRY_ADDRESS_SHIFT: usize;
/// 页面的页表项的默认值
const ENTRY_FLAG_DEFAULT_PAGE: usize;
/// 页表的页表项的默认值
const ENTRY_FLAG_DEFAULT_TABLE: usize;
/// 页表项的present位被置位之后的值
const ENTRY_FLAG_PRESENT: usize;
/// 页表项为read only时的值
const ENTRY_FLAG_READONLY: usize;
/// 页表项为可读写状态的值
const ENTRY_FLAG_READWRITE: usize;
/// 页面项标记页面为user page的值
const ENTRY_FLAG_USER: usize;
/// 页面项标记页面为write through的值
const ENTRY_FLAG_WRITE_THROUGH: usize;
/// 页面项标记页面为cache disable的值
const ENTRY_FLAG_CACHE_DISABLE: usize;
/// 标记当前页面不可执行的标志位Execute disable也就是说不能从这段内存里面获取处理器指令
const ENTRY_FLAG_NO_EXEC: usize;
/// 标记当前页面可执行的标志位Execute enable
const ENTRY_FLAG_EXEC: usize;
/// 虚拟地址与物理地址的偏移量
const PHYS_OFFSET: usize;
/// 每个页面的大小
const PAGE_SIZE: usize = 1 << Self::PAGE_SHIFT;
/// 通过这个mask获取地址的页内偏移量
const PAGE_OFFSET_MASK: usize = Self::PAGE_SIZE - 1;
/// 页表项的地址、数据部分的shift。
/// 打个比方如果这个值为52,那么意味着页表项的[0, 52)位,用于表示地址以及其他的标志位
const PAGE_ADDRESS_SHIFT: usize = Self::PAGE_LEVELS * Self::PAGE_ENTRY_SHIFT + Self::PAGE_SHIFT;
/// 最大的虚拟地址对于不同的架构由于上述PAGE_ADDRESS_SHIFT可能包括了reserved bits, 事实上能表示的虚拟地址应该比这个值要小)
const PAGE_ADDRESS_SIZE: usize = 1 << Self::PAGE_ADDRESS_SHIFT;
/// 页表项的值与这个常量进行与运算,得到的结果是所填写的物理地址
const PAGE_ADDRESS_MASK: usize = Self::PAGE_ADDRESS_SIZE - Self::PAGE_SIZE;
/// 每个页表项的大小
const PAGE_ENTRY_SIZE: usize = 1 << (Self::PAGE_SHIFT - Self::PAGE_ENTRY_SHIFT);
/// 每个页表的页表项数目
const PAGE_ENTRY_NUM: usize = 1 << Self::PAGE_ENTRY_SHIFT;
/// 该字段用于根据虚拟地址,获取该虚拟地址在对应的页表中是第几个页表项
const PAGE_ENTRY_MASK: usize = Self::PAGE_ENTRY_NUM - 1;
const PAGE_NEGATIVE_MASK: usize = !((Self::PAGE_ADDRESS_SIZE) - 1);
const ENTRY_ADDRESS_SIZE: usize = 1 << Self::ENTRY_ADDRESS_SHIFT;
/// 该mask用于获取页表项中地址字段
const ENTRY_ADDRESS_MASK: usize = Self::ENTRY_ADDRESS_SIZE - Self::PAGE_SIZE;
/// 这个mask用于获取页表项中的flags
const ENTRY_FLAGS_MASK: usize = !Self::ENTRY_ADDRESS_MASK;
/// 用户空间的最高地址
const USER_END_VADDR: VirtAddr;
/// 用户堆的起始地址
const USER_BRK_START: VirtAddr;
/// 用户栈起始地址(向下生长,不包含该值)
const USER_STACK_START: VirtAddr;
/// @brief 用于初始化内存管理模块与架构相关的信息。
/// 该函数应调用其他模块的接口生成内存区域结构体提供给BumpAllocator使用
unsafe fn init() -> &'static [PhysMemoryArea];
/// @brief 读取指定虚拟地址的值并假设它是类型T的指针
#[inline(always)]
unsafe fn read<T>(address: VirtAddr) -> T {
return ptr::read(address.data() as *const T);
}
/// @brief 将value写入到指定的虚拟地址
#[inline(always)]
unsafe fn write<T>(address: VirtAddr, value: T) {
ptr::write(address.data() as *mut T, value);
}
#[inline(always)]
unsafe fn write_bytes(address: VirtAddr, value: u8, count: usize) {
ptr::write_bytes(address.data() as *mut u8, value, count);
}
/// @brief 刷新TLB中关于指定虚拟地址的条目
unsafe fn invalidate_page(address: VirtAddr);
/// @brief 刷新TLB中所有的条目
unsafe fn invalidate_all();
/// @brief 获取顶级页表的物理地址
unsafe fn table(table_kind: PageTableKind) -> PhysAddr;
/// @brief 设置顶级页表的物理地址到处理器中
unsafe fn set_table(table_kind: PageTableKind, table: PhysAddr);
/// @brief 将物理地址转换为虚拟地址.
///
/// @param phys 物理地址
///
/// @return 转换后的虚拟地址。如果转换失败返回None
#[inline(always)]
unsafe fn phys_2_virt(phys: PhysAddr) -> Option<VirtAddr> {
if let Some(vaddr) = phys.data().checked_add(Self::PHYS_OFFSET) {
return Some(VirtAddr::new(vaddr));
} else {
return None;
}
}
/// 将虚拟地址转换为物理地址
///
/// ## 参数
///
/// - `virt` 虚拟地址
///
/// ## 返回值
///
/// 转换后的物理地址。如果转换失败返回None
#[inline(always)]
unsafe fn virt_2_phys(virt: VirtAddr) -> Option<PhysAddr> {
if let Some(paddr) = virt.data().checked_sub(Self::PHYS_OFFSET) {
return Some(PhysAddr::new(paddr));
} else {
return None;
}
}
/// @brief 判断指定的虚拟地址是否正确(符合规范)
fn virt_is_valid(virt: VirtAddr) -> bool;
/// 获取内存管理初始化时,创建的第一个内核页表的地址
fn initial_page_table() -> PhysAddr;
/// 初始化新的usermapper为用户进程创建页表
fn setup_new_usermapper() -> Result<UserMapper, SystemError>;
}
/// @brief 虚拟地址范围
/// 该结构体用于表示一个虚拟地址范围,包括起始地址与大小
///
/// 请注意与VMA进行区分该结构体被VMA所包含
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct VirtRegion {
start: VirtAddr,
size: usize,
}
#[allow(dead_code)]
impl VirtRegion {
/// # 创建一个新的虚拟地址范围
pub fn new(start: VirtAddr, size: usize) -> Self {
VirtRegion { start, size }
}
/// 获取虚拟地址范围的起始地址
#[inline(always)]
pub fn start(&self) -> VirtAddr {
self.start
}
/// 获取虚拟地址范围的截止地址(不包括返回的地址)
#[inline(always)]
pub fn end(&self) -> VirtAddr {
return self.start().add(self.size);
}
/// # Create a new VirtRegion from a range [start, end)
///
/// If end <= start, return None
pub fn between(start: VirtAddr, end: VirtAddr) -> Option<Self> {
if unlikely(end.data() <= start.data()) {
return None;
}
let size = end.data() - start.data();
return Some(VirtRegion::new(start, size));
}
/// # 取两个虚拟地址范围的交集
///
/// 如果两个虚拟地址范围没有交集返回None
pub fn intersect(&self, other: &VirtRegion) -> Option<VirtRegion> {
let start = self.start.max(other.start);
let end = self.end().min(other.end());
return VirtRegion::between(start, end);
}
/// 设置虚拟地址范围的起始地址
#[inline(always)]
pub fn set_start(&mut self, start: VirtAddr) {
self.start = start;
}
#[inline(always)]
pub fn size(&self) -> usize {
self.size
}
/// 设置虚拟地址范围的大小
#[inline(always)]
pub fn set_size(&mut self, size: usize) {
self.size = size;
}
/// 判断虚拟地址范围是否为空
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.size == 0
}
/// 将虚拟地址区域的大小向上对齐到页大小
#[inline(always)]
pub fn round_up_size_to_page(self) -> Self {
return VirtRegion::new(self.start, round_up_to_page_size(self.size));
}
/// 判断两个虚拟地址范围是否由于具有交集而导致冲突
#[inline(always)]
pub fn collide(&self, other: &VirtRegion) -> bool {
return self.intersect(other).is_some();
}
pub fn iter_pages(&self) -> VirtPageFrameIter {
return VirtPageFrame::iter_range(
VirtPageFrame::new(self.start),
VirtPageFrame::new(self.end()),
);
}
/// 获取[self.start(), region.start())的虚拟地址范围
///
/// 如果self.start() >= region.start()返回None
pub fn before(self, region: &VirtRegion) -> Option<Self> {
return Self::between(self.start(), region.start());
}
/// 获取[region.end(),self.end())的虚拟地址范围
///
/// 如果 self.end() >= region.end() 返回None
pub fn after(self, region: &VirtRegion) -> Option<Self> {
// if self.end() > region.end() none
return Self::between(region.end(), self.end());
}
/// 把当前虚拟地址范围内的某个虚拟地址,转换为另一个虚拟地址范围内的虚拟地址
///
/// 如果vaddr不在当前虚拟地址范围内返回None
///
/// 如果vaddr在当前虚拟地址范围内返回vaddr在new_base中的虚拟地址
pub fn rebase(self, vaddr: VirtAddr, new_base: &VirtRegion) -> Option<VirtAddr> {
if !self.contains(vaddr) {
return None;
}
let offset = vaddr.data() - self.start().data();
let new_start = new_base.start().data() + offset;
return Some(VirtAddr::new(new_start));
}
/// 判断虚拟地址范围是否包含指定的虚拟地址
pub fn contains(&self, addr: VirtAddr) -> bool {
return self.start() <= addr && addr < self.end();
}
/// 创建当前虚拟地址范围的页面迭代器
pub fn pages(&self) -> VirtPageFrameIter {
return VirtPageFrame::iter_range(
VirtPageFrame::new(self.start()),
VirtPageFrame::new(self.end()),
);
}
}
impl PartialOrd for VirtRegion {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
return self.start.partial_cmp(&other.start);
}
}
impl Ord for VirtRegion {
fn cmp(&self, other: &Self) -> cmp::Ordering {
return self.start.cmp(&other.start);
}
}
/// ## 判断虚拟地址是否超出了用户空间
///
/// 如果虚拟地址超出了用户空间返回Err(SystemError::EFAULT).
/// 如果end < start返回Err(SystemError::EOVERFLOW)
///
/// 否则返回Ok(())
pub fn verify_area(addr: VirtAddr, size: usize) -> Result<(), SystemError> {
let end = addr.add(size);
if unlikely(end.data() < addr.data()) {
return Err(SystemError::EOVERFLOW);
}
if !addr.check_user() || !end.check_user() {
return Err(SystemError::EFAULT);
}
return Ok(());
}
// ====== 重构内存管理、进程管理后,请删除这几行 BEGIN ======
// ====== 重构内存管理后请删除18-24行 ======
//BUG pcb问题
unsafe impl Send for process_control_block {}
unsafe impl Sync for process_control_block {}
// ====== 重构内存管理后,请删除这几行 END =======
unsafe impl Send for mm_struct {}
unsafe impl Sync for mm_struct {}

View File

@ -1,79 +0,0 @@
//! 该文件用于系统启动早期,内存管理器初始化之前,提供一些简单的内存映射功能
//!
//! 这里假设在内核引导文件中已经填写了前100M的内存映射关系因此这里不需要任何动态分配。
//!
//! 映射关系为:
//!
//! 虚拟地址 0-100M与虚拟地址 0x8000_0000_0000 - 0x8000_0640_0000 之间具有重映射关系。
//! 也就是说他们的第二级页表在最顶级页表中占用了第0和第256个页表项。
//!
use crate::mm::{MMArch, MemoryManagementArch, PhysAddr};
use core::marker::PhantomData;
use super::{
allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage},
page::PageFlags,
PageTableKind, VirtAddr,
};
/// 伪分配器
struct PseudoAllocator<MMA> {
phantom: PhantomData<MMA>,
}
impl<MMA: MemoryManagementArch> PseudoAllocator<MMA> {
pub const fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
/// 为NoInitAllocator实现FrameAllocator
impl<MMA: MemoryManagementArch> FrameAllocator for PseudoAllocator<MMA> {
unsafe fn allocate(&mut self, _count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
panic!("NoInitAllocator can't allocate page frame");
}
unsafe fn free(&mut self, _address: PhysAddr, _count: PageFrameCount) {
panic!("NoInitAllocator can't free page frame");
}
/// @brief: 获取内存区域页帧的使用情况
/// @param self
/// @return 页帧的使用情况
unsafe fn usage(&self) -> PageFrameUsage {
panic!("NoInitAllocator can't get page frame usage");
}
}
/// Use pseudo mapper to map physical memory to virtual memory.
///
/// ## Safety
///
/// 调用该函数时,必须保证内存管理器尚未初始化。否则将导致未定义的行为
///
/// 并且内核引导文件必须以4K页为粒度填写了前100M的内存映射关系。具体以本文件开头的注释为准
pub unsafe fn pseudo_map_phys(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount) {
assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
assert!(paddr.check_aligned(MMArch::PAGE_SIZE));
let mut pseudo_allocator = PseudoAllocator::<MMArch>::new();
let mut mapper = crate::mm::page::PageMapper::<MMArch, _>::new(
PageTableKind::Kernel,
MMArch::table(PageTableKind::Kernel),
&mut pseudo_allocator,
);
let flags: PageFlags<MMArch> = PageFlags::new().set_write(true).set_execute(true);
for i in 0..count.data() {
let vaddr = vaddr + i * MMArch::PAGE_SIZE;
let paddr = paddr + i * MMArch::PAGE_SIZE;
let flusher = mapper.map_phys(vaddr, paddr, flags).unwrap();
flusher.ignore();
}
mapper.make_current();
}

View File

@ -1,924 +0,0 @@
use core::{
fmt::{self, Debug, Error, Formatter},
marker::PhantomData,
mem,
ops::Add,
sync::atomic::{compiler_fence, Ordering},
};
use crate::{
arch::{interrupt::ipi::send_ipi, MMArch},
exception::ipi::{IpiKind, IpiTarget},
kerror, kwarn,
};
use super::{
allocator::page_frame::FrameAllocator, syscall::ProtFlags, MemoryManagementArch, PageTableKind,
PhysAddr, VirtAddr,
};
#[derive(Debug)]
pub struct PageTable<Arch> {
/// 当前页表表示的虚拟地址空间的起始地址
base: VirtAddr,
/// 当前页表所在的物理地址
phys: PhysAddr,
/// 当前页表的层级请注意最顶级页表的level为[Arch::PAGE_LEVELS - 1]
level: usize,
phantom: PhantomData<Arch>,
}
#[allow(dead_code)]
impl<Arch: MemoryManagementArch> PageTable<Arch> {
pub unsafe fn new(base: VirtAddr, phys: PhysAddr, level: usize) -> Self {
Self {
base,
phys,
level,
phantom: PhantomData,
}
}
/// 获取顶级页表
///
/// ## 参数
///
/// - table_kind 页表类型
///
/// ## 返回值
///
/// 返回顶级页表
pub unsafe fn top_level_table(table_kind: PageTableKind) -> Self {
return Self::new(
VirtAddr::new(0),
Arch::table(table_kind),
Arch::PAGE_LEVELS - 1,
);
}
/// 获取当前页表的物理地址
#[inline(always)]
pub fn phys(&self) -> PhysAddr {
self.phys
}
/// 当前页表表示的虚拟地址空间的起始地址
#[inline(always)]
pub fn base(&self) -> VirtAddr {
self.base
}
/// 获取当前页表的层级
#[inline(always)]
pub fn level(&self) -> usize {
self.level
}
/// 获取当前页表自身所在的虚拟地址
#[inline(always)]
pub unsafe fn virt(&self) -> VirtAddr {
return Arch::phys_2_virt(self.phys).unwrap();
}
/// 获取第i个页表项所表示的虚拟内存空间的起始地址
pub fn entry_base(&self, i: usize) -> Option<VirtAddr> {
if i < Arch::PAGE_ENTRY_NUM {
let shift = self.level * Arch::PAGE_ENTRY_SHIFT + Arch::PAGE_SHIFT;
return Some(self.base.add(i << shift));
} else {
return None;
}
}
/// 获取当前页表的第i个页表项所在的虚拟地址注意与entry_base进行区分
pub unsafe fn entry_virt(&self, i: usize) -> Option<VirtAddr> {
if i < Arch::PAGE_ENTRY_NUM {
return Some(self.virt().add(i * Arch::PAGE_ENTRY_SIZE));
} else {
return None;
}
}
/// 获取当前页表的第i个页表项
pub unsafe fn entry(&self, i: usize) -> Option<PageEntry<Arch>> {
let entry_virt = self.entry_virt(i)?;
return Some(PageEntry::new(Arch::read::<usize>(entry_virt)));
}
/// 设置当前页表的第i个页表项
pub unsafe fn set_entry(&self, i: usize, entry: PageEntry<Arch>) -> Option<()> {
let entry_virt = self.entry_virt(i)?;
Arch::write::<usize>(entry_virt, entry.data());
return Some(());
}
/// 判断当前页表的第i个页表项是否已经填写了值
///
/// ## 参数
/// - Some(true) 如果已经填写了值
/// - Some(false) 如果未填写值
/// - None 如果i超出了页表项的范围
pub fn entry_mapped(&self, i: usize) -> Option<bool> {
let etv = unsafe { self.entry_virt(i) }?;
if unsafe { Arch::read::<usize>(etv) } != 0 {
return Some(true);
} else {
return Some(false);
}
}
/// 根据虚拟地址,获取对应的页表项在页表中的下标
///
/// ## 参数
///
/// - addr: 虚拟地址
///
/// ## 返回值
///
/// 页表项在页表中的下标。如果addr不在当前页表所表示的虚拟地址空间中则返回None
pub unsafe fn index_of(&self, addr: VirtAddr) -> Option<usize> {
let addr = VirtAddr::new(addr.data() & Arch::PAGE_ADDRESS_MASK);
let shift = self.level * Arch::PAGE_ENTRY_SHIFT + Arch::PAGE_SHIFT;
let mask = (MMArch::PAGE_ENTRY_NUM << shift) - 1;
if addr < self.base || addr >= self.base.add(mask) {
return None;
} else {
return Some((addr.data() >> shift) & MMArch::PAGE_ENTRY_MASK);
}
}
/// 获取第i个页表项指向的下一级页表
pub unsafe fn next_level_table(&self, index: usize) -> Option<Self> {
if self.level == 0 {
return None;
}
// 返回下一级页表
return Some(PageTable::new(
self.entry_base(index)?,
self.entry(index)?.address().ok()?,
self.level - 1,
));
}
}
/// 页表项
#[derive(Copy, Clone)]
pub struct PageEntry<Arch> {
data: usize,
phantom: PhantomData<Arch>,
}
impl<Arch> Debug for PageEntry<Arch> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.write_fmt(format_args!("PageEntry({:#x})", self.data))
}
}
impl<Arch: MemoryManagementArch> PageEntry<Arch> {
#[inline(always)]
pub fn new(data: usize) -> Self {
Self {
data,
phantom: PhantomData,
}
}
#[inline(always)]
pub fn data(&self) -> usize {
self.data
}
/// 获取当前页表项指向的物理地址
///
/// ## 返回值
///
/// - Ok(PhysAddr) 如果当前页面存在于物理内存中, 返回物理地址
/// - Err(PhysAddr) 如果当前页表项不存在, 返回物理地址
#[inline(always)]
pub fn address(&self) -> Result<PhysAddr, PhysAddr> {
let paddr = PhysAddr::new(self.data & Arch::PAGE_ADDRESS_MASK);
if self.present() {
Ok(paddr)
} else {
Err(paddr)
}
}
#[inline(always)]
pub fn flags(&self) -> PageFlags<Arch> {
unsafe { PageFlags::from_data(self.data & Arch::ENTRY_FLAGS_MASK) }
}
#[inline(always)]
pub fn set_flags(&mut self, flags: PageFlags<Arch>) {
self.data = (self.data & !Arch::ENTRY_FLAGS_MASK) | flags.data();
}
#[inline(always)]
pub fn present(&self) -> bool {
return self.data & Arch::ENTRY_FLAG_PRESENT != 0;
}
}
/// 页表项的标志位
#[derive(Copy, Clone, Hash)]
pub struct PageFlags<Arch> {
data: usize,
phantom: PhantomData<Arch>,
}
#[allow(dead_code)]
impl<Arch: MemoryManagementArch> PageFlags<Arch> {
#[inline(always)]
pub fn new() -> Self {
let mut r = unsafe {
Self::from_data(
Arch::ENTRY_FLAG_DEFAULT_PAGE
| Arch::ENTRY_FLAG_READONLY
| Arch::ENTRY_FLAG_NO_EXEC,
)
};
#[cfg(target_arch = "x86_64")]
{
if crate::arch::mm::X86_64MMArch::is_xd_reserved() {
r = r.set_execute(true);
}
}
return r;
}
/// 根据ProtFlags生成PageFlags
///
/// ## 参数
///
/// - prot_flags: 页的保护标志
/// - user: 用户空间是否可访问
pub fn from_prot_flags(prot_flags: ProtFlags, user: bool) -> PageFlags<Arch> {
let flags: PageFlags<Arch> = PageFlags::new()
.set_user(user)
.set_execute(prot_flags.contains(ProtFlags::PROT_EXEC))
.set_write(prot_flags.contains(ProtFlags::PROT_WRITE));
return flags;
}
#[inline(always)]
pub fn data(&self) -> usize {
self.data
}
#[inline(always)]
pub const unsafe fn from_data(data: usize) -> Self {
return Self {
data: data,
phantom: PhantomData,
};
}
/// 为新页表的页表项设置默认值
///
/// 默认值为:
/// - present
/// - read only
/// - kernel space
/// - no exec
#[inline(always)]
pub fn new_page_table(user: bool) -> Self {
return unsafe {
let r = Self::from_data(Arch::ENTRY_FLAG_DEFAULT_TABLE | Arch::ENTRY_FLAG_READWRITE);
if user {
r.set_user(true)
} else {
r
}
};
}
/// 取得当前页表项的所有权,更新当前页表项的标志位,并返回更新后的页表项。
///
/// ## 参数
/// - flag 要更新的标志位的值
/// - value 如果为true那么将flag对应的位设置为1否则设置为0
///
/// ## 返回值
///
/// 更新后的页表项
#[inline(always)]
#[must_use]
pub fn update_flags(mut self, flag: usize, value: bool) -> Self {
if value {
self.data |= flag;
} else {
self.data &= !flag;
}
return self;
}
/// 判断当前页表项是否存在指定的flag只有全部flag都存在才返回true
#[inline(always)]
pub fn has_flag(&self, flag: usize) -> bool {
return self.data & flag == flag;
}
#[inline(always)]
pub fn present(&self) -> bool {
return self.has_flag(Arch::ENTRY_FLAG_PRESENT);
}
/// 设置当前页表项的权限
///
/// @param value 如果为true那么将当前页表项的权限设置为用户态可访问
#[must_use]
#[inline(always)]
pub fn set_user(self, value: bool) -> Self {
return self.update_flags(Arch::ENTRY_FLAG_USER, value);
}
/// 用户态是否可以访问当前页表项
#[inline(always)]
pub fn has_user(&self) -> bool {
return self.has_flag(Arch::ENTRY_FLAG_USER);
}
/// 设置当前页表项的可写性, 如果为true那么将当前页表项的权限设置为可写, 否则设置为只读
///
/// ## 返回值
///
/// 更新后的页表项.
///
/// **请注意,**本函数会取得当前页表项的所有权,因此返回的页表项不是原来的页表项
#[must_use]
#[inline(always)]
pub fn set_write(self, value: bool) -> Self {
// 有的架构同时具有可写和不可写的标志位,因此需要同时更新
return self
.update_flags(Arch::ENTRY_FLAG_READONLY, !value)
.update_flags(Arch::ENTRY_FLAG_READWRITE, value);
}
/// 当前页表项是否可写
#[inline(always)]
pub fn has_write(&self) -> bool {
// 有的架构同时具有可写和不可写的标志位,因此需要同时判断
return self.data & (Arch::ENTRY_FLAG_READWRITE | Arch::ENTRY_FLAG_READONLY)
== Arch::ENTRY_FLAG_READWRITE;
}
/// 设置当前页表项的可执行性, 如果为true那么将当前页表项的权限设置为可执行, 否则设置为不可执行
#[must_use]
#[inline(always)]
pub fn set_execute(self, mut value: bool) -> Self {
#[cfg(target_arch = "x86_64")]
{
// 如果xd位被保留那么将可执行性设置为true
if crate::arch::mm::X86_64MMArch::is_xd_reserved() {
value = true;
}
}
// 有的架构同时具有可执行和不可执行的标志位,因此需要同时更新
return self
.update_flags(Arch::ENTRY_FLAG_NO_EXEC, !value)
.update_flags(Arch::ENTRY_FLAG_EXEC, value);
}
/// 当前页表项是否可执行
#[inline(always)]
pub fn has_execute(&self) -> bool {
// 有的架构同时具有可执行和不可执行的标志位,因此需要同时判断
return self.data & (Arch::ENTRY_FLAG_EXEC | Arch::ENTRY_FLAG_NO_EXEC)
== Arch::ENTRY_FLAG_EXEC;
}
/// 设置当前页表项的缓存策略
///
/// ## 参数
///
/// - value: 如果为true那么将当前页表项的缓存策略设置为不缓存。
#[inline(always)]
pub fn set_page_cache_disable(self, value: bool) -> Self {
return self.update_flags(Arch::ENTRY_FLAG_CACHE_DISABLE, value);
}
/// 获取当前页表项的缓存策略
///
/// ## 返回值
///
/// 如果当前页表项的缓存策略为不缓存那么返回true否则返回false。
#[inline(always)]
pub fn has_page_cache_disable(&self) -> bool {
return self.has_flag(Arch::ENTRY_FLAG_CACHE_DISABLE);
}
/// 设置当前页表项的写穿策略
///
/// ## 参数
///
/// - value: 如果为true那么将当前页表项的写穿策略设置为写穿。
#[inline(always)]
pub fn set_page_write_through(self, value: bool) -> Self {
return self.update_flags(Arch::ENTRY_FLAG_WRITE_THROUGH, value);
}
/// 获取当前页表项的写穿策略
///
/// ## 返回值
///
/// 如果当前页表项的写穿策略为写穿那么返回true否则返回false。
#[inline(always)]
pub fn has_page_write_through(&self) -> bool {
return self.has_flag(Arch::ENTRY_FLAG_WRITE_THROUGH);
}
/// MMIO内存的页表项标志
#[inline(always)]
pub fn mmio_flags() -> Self {
return Self::new()
.set_user(false)
.set_write(true)
.set_execute(true)
.set_page_cache_disable(true)
.set_page_write_through(true);
}
}
impl<Arch: MemoryManagementArch> fmt::Debug for PageFlags<Arch> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PageFlags")
.field("bits", &format_args!("{:#0x}", self.data))
.field("present", &self.present())
.field("has_write", &self.has_write())
.field("has_execute", &self.has_execute())
.field("has_user", &self.has_user())
.finish()
}
}
/// 页表映射器
#[derive(Hash)]
pub struct PageMapper<Arch, F> {
/// 页表类型
table_kind: PageTableKind,
/// 根页表物理地址
table_paddr: PhysAddr,
/// 页分配器
frame_allocator: F,
phantom: PhantomData<fn() -> Arch>,
}
impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
/// 创建新的页面映射器
///
/// ## 参数
/// - table_kind 页表类型
/// - table_paddr 根页表物理地址
/// - allocator 页分配器
///
/// ## 返回值
///
/// 页面映射器
pub unsafe fn new(table_kind: PageTableKind, table_paddr: PhysAddr, allocator: F) -> Self {
return Self {
table_kind,
table_paddr,
frame_allocator: allocator,
phantom: PhantomData,
};
}
/// 创建页表,并为这个页表创建页面映射器
pub unsafe fn create(table_kind: PageTableKind, mut allocator: F) -> Option<Self> {
let table_paddr = allocator.allocate_one()?;
// 清空页表
let table_vaddr = Arch::phys_2_virt(table_paddr)?;
Arch::write_bytes(table_vaddr, 0, Arch::PAGE_SIZE);
return Some(Self::new(table_kind, table_paddr, allocator));
}
/// 获取当前页表的页面映射器
#[inline(always)]
pub unsafe fn current(table_kind: PageTableKind, allocator: F) -> Self {
let table_paddr = Arch::table(table_kind);
return Self::new(table_kind, table_paddr, allocator);
}
/// 判断当前页表分配器所属的页表是否是当前页表
#[inline(always)]
pub fn is_current(&self) -> bool {
return unsafe { self.table().phys() == Arch::table(self.table_kind) };
}
/// 将当前页表分配器所属的页表设置为当前页表
#[inline(always)]
pub unsafe fn make_current(&self) {
Arch::set_table(self.table_kind, self.table_paddr);
}
/// 获取当前页表分配器所属的根页表的结构体
#[inline(always)]
pub fn table(&self) -> PageTable<Arch> {
// 由于只能通过new方法创建PageMapper因此这里假定table_paddr是有效的
return unsafe {
PageTable::new(VirtAddr::new(0), self.table_paddr, Arch::PAGE_LEVELS - 1)
};
}
/// 获取当前PageMapper所对应的页分配器实例的引用
#[inline(always)]
#[allow(dead_code)]
pub fn allocator_ref(&self) -> &F {
return &self.frame_allocator;
}
/// 获取当前PageMapper所对应的页分配器实例的可变引用
#[inline(always)]
pub fn allocator_mut(&mut self) -> &mut F {
return &mut self.frame_allocator;
}
/// 从当前PageMapper的页分配器中分配一个物理页并将其映射到指定的虚拟地址
pub unsafe fn map(
&mut self,
virt: VirtAddr,
flags: PageFlags<Arch>,
) -> Option<PageFlush<Arch>> {
compiler_fence(Ordering::SeqCst);
let phys: PhysAddr = self.frame_allocator.allocate_one()?;
compiler_fence(Ordering::SeqCst);
return self.map_phys(virt, phys, flags);
}
/// 映射一个物理页到指定的虚拟地址
pub unsafe fn map_phys(
&mut self,
virt: VirtAddr,
phys: PhysAddr,
flags: PageFlags<Arch>,
) -> Option<PageFlush<Arch>> {
// 验证虚拟地址和物理地址是否对齐
if !(virt.check_aligned(Arch::PAGE_SIZE) && phys.check_aligned(Arch::PAGE_SIZE)) {
kerror!(
"Try to map unaligned page: virt={:?}, phys={:?}",
virt,
phys
);
return None;
}
let virt = VirtAddr::new(virt.data() & (!Arch::PAGE_NEGATIVE_MASK));
// TODO 验证flags是否合法
// 创建页表项
let entry = PageEntry::new(phys.data() | flags.data());
let mut table = self.table();
loop {
let i = table.index_of(virt)?;
assert!(i < Arch::PAGE_ENTRY_NUM);
if table.level() == 0 {
// todo: 检查是否已经映射
// 现在不检查的原因是,刚刚启动系统时,内核会映射一些页。
if table.entry_mapped(i)? == true {
kwarn!("Page {:?} already mapped", virt);
}
// kdebug!("Mapping {:?} to {:?}, i = {i}, entry={:?}, flags={:?}", virt, phys, entry, flags);
compiler_fence(Ordering::SeqCst);
table.set_entry(i, entry);
compiler_fence(Ordering::SeqCst);
return Some(PageFlush::new(virt));
} else {
let next_table = table.next_level_table(i);
if let Some(next_table) = next_table {
table = next_table;
// kdebug!("Mapping {:?} to next level table...", virt);
} else {
// kdebug!("Allocating next level table for {:?}..., i={i}", virt);
// 分配下一级页表
let frame = self.frame_allocator.allocate_one()?;
// 清空这个页帧
MMArch::write_bytes(MMArch::phys_2_virt(frame).unwrap(), 0, MMArch::PAGE_SIZE);
// 设置页表项的flags
// let flags = Arch::ENTRY_FLAG_READWRITE
// | Arch::ENTRY_FLAG_DEFAULT_TABLE
// | if virt.kind() == PageTableKind::User {
// Arch::ENTRY_FLAG_USER
// } else {
// 0
// };
let flags: PageFlags<MMArch> =
PageFlags::new_page_table(virt.kind() == PageTableKind::User);
// kdebug!("Flags: {:?}", flags);
// 把新分配的页表映射到当前页表
table.set_entry(i, PageEntry::new(frame.data() | flags.data()));
// 获取新分配的页表
table = table.next_level_table(i)?;
}
}
}
}
/// 将物理地址映射到具有线性偏移量的虚拟地址
#[allow(dead_code)]
pub unsafe fn map_linearly(
&mut self,
phys: PhysAddr,
flags: PageFlags<Arch>,
) -> Option<(VirtAddr, PageFlush<Arch>)> {
let virt: VirtAddr = Arch::phys_2_virt(phys)?;
return self.map_phys(virt, phys, flags).map(|flush| (virt, flush));
}
/// 修改虚拟地址的页表项的flags并返回页表项刷新器
///
/// 请注意需要在修改完flags后调用刷新器的flush方法才能使修改生效
///
/// ## 参数
/// - virt 虚拟地址
/// - flags 新的页表项的flags
///
/// ## 返回值
///
/// 如果修改成功返回刷新器否则返回None
pub unsafe fn remap(
&mut self,
virt: VirtAddr,
flags: PageFlags<Arch>,
) -> Option<PageFlush<Arch>> {
return self
.visit(virt, |p1, i| {
let mut entry = p1.entry(i)?;
entry.set_flags(flags);
p1.set_entry(i, entry);
Some(PageFlush::new(virt))
})
.flatten();
}
/// 根据虚拟地址查找页表获取对应的物理地址和页表项的flags
///
/// ## 参数
///
/// - virt 虚拟地址
///
/// ## 返回值
///
/// 如果查找成功返回物理地址和页表项的flags否则返回None
pub fn translate(&self, virt: VirtAddr) -> Option<(PhysAddr, PageFlags<Arch>)> {
let entry: PageEntry<Arch> = self.visit(virt, |p1, i| unsafe { p1.entry(i) })??;
let paddr = entry.address().ok()?;
let flags = entry.flags();
return Some((paddr, flags));
}
/// 取消虚拟地址的映射,释放页面,并返回页表项刷新器
///
/// 请注意需要在取消映射后调用刷新器的flush方法才能使修改生效
///
/// ## 参数
///
/// - virt 虚拟地址
/// - unmap_parents 是否在父页表内,取消空闲子页表的映射
///
/// ## 返回值
/// 如果取消成功返回刷新器否则返回None
pub unsafe fn unmap(&mut self, virt: VirtAddr, unmap_parents: bool) -> Option<PageFlush<Arch>> {
let (paddr, _, flusher) = self.unmap_phys(virt, unmap_parents)?;
self.frame_allocator.free_one(paddr);
return Some(flusher);
}
/// 取消虚拟地址的映射并返回物理地址和页表项的flags
///
/// ## 参数
///
/// - vaddr 虚拟地址
/// - unmap_parents 是否在父页表内,取消空闲子页表的映射
///
/// ## 返回值
///
/// 如果取消成功返回物理地址和页表项的flags否则返回None
pub unsafe fn unmap_phys(
&mut self,
virt: VirtAddr,
unmap_parents: bool,
) -> Option<(PhysAddr, PageFlags<Arch>, PageFlush<Arch>)> {
if !virt.check_aligned(Arch::PAGE_SIZE) {
kerror!("Try to unmap unaligned page: virt={:?}", virt);
return None;
}
let mut table = self.table();
return unmap_phys_inner(virt, &mut table, unmap_parents, self.allocator_mut())
.map(|(paddr, flags)| (paddr, flags, PageFlush::<Arch>::new(virt)));
}
/// 在页表中访问虚拟地址对应的页表项并调用传入的函数F
fn visit<T>(
&self,
virt: VirtAddr,
f: impl FnOnce(&mut PageTable<Arch>, usize) -> T,
) -> Option<T> {
let mut table = self.table();
unsafe {
loop {
let i = table.index_of(virt)?;
if table.level() == 0 {
return Some(f(&mut table, i));
} else {
table = table.next_level_table(i)?;
}
}
}
}
}
/// 取消页面映射返回被取消映射的页表项的【物理地址】和【flags】
///
/// ## 参数
///
/// - vaddr 虚拟地址
/// - table 页表
/// - unmap_parents 是否在父页表内,取消空闲子页表的映射
/// - allocator 页面分配器(如果页表从这个分配器分配,那么在取消映射时,也需要归还到这个分配器内)
///
/// ## 返回值
///
/// 如果取消成功返回被取消映射的页表项的【物理地址】和【flags】否则返回None
unsafe fn unmap_phys_inner<Arch: MemoryManagementArch>(
vaddr: VirtAddr,
table: &mut PageTable<Arch>,
unmap_parents: bool,
allocator: &mut impl FrameAllocator,
) -> Option<(PhysAddr, PageFlags<Arch>)> {
// 获取页表项的索引
let i = table.index_of(vaddr)?;
// 如果当前是最后一级页表,直接取消页面映射
if table.level() == 0 {
let entry = table.entry(i)?;
table.set_entry(i, PageEntry::new(0));
return Some((entry.address().ok()?, entry.flags()));
}
let mut subtable = table.next_level_table(i)?;
// 递归地取消映射
let result = unmap_phys_inner(vaddr, &mut subtable, unmap_parents, allocator)?;
// TODO: This is a bad idea for architectures where the kernel mappings are done in the process tables,
// as these mappings may become out of sync
if unmap_parents {
// 如果子页表已经没有映射的页面了,就取消子页表的映射
// 检查子页表中是否还有映射的页面
let x = (0..Arch::PAGE_ENTRY_NUM)
.map(|k| subtable.entry(k).expect("invalid page entry"))
.any(|e| e.present());
if !x {
// 如果没有,就取消子页表的映射
table.set_entry(i, PageEntry::new(0));
// 释放子页表
allocator.free_one(subtable.phys());
}
}
return Some(result);
}
impl<Arch, F: Debug> Debug for PageMapper<Arch, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PageMapper")
.field("table_paddr", &self.table_paddr)
.field("frame_allocator", &self.frame_allocator)
.finish()
}
}
/// 页表刷新器的trait
pub trait Flusher<Arch> {
/// 取消对指定的page flusher的刷新
fn consume(&mut self, flush: PageFlush<Arch>);
}
/// 用于刷新某个虚拟地址的刷新器。这个刷新器一经产生就必须调用flush()方法,
/// 否则会造成对页表的更改被忽略,这是不安全的
#[must_use = "The flusher must call the 'flush()', or the changes to page table will be unsafely ignored."]
pub struct PageFlush<Arch> {
virt: VirtAddr,
phantom: PhantomData<Arch>,
}
impl<Arch: MemoryManagementArch> PageFlush<Arch> {
pub fn new(virt: VirtAddr) -> Self {
return Self {
virt,
phantom: PhantomData,
};
}
pub fn flush(self) {
unsafe { Arch::invalidate_page(self.virt) };
}
/// 忽略掉这个刷新器
pub unsafe fn ignore(self) {
mem::forget(self);
}
}
/// 用于刷新整个页表的刷新器。这个刷新器一经产生就必须调用flush()方法,
/// 否则会造成对页表的更改被忽略,这是不安全的
#[must_use = "The flusher must call the 'flush()', or the changes to page table will be unsafely ignored."]
pub struct PageFlushAll<Arch: MemoryManagementArch> {
phantom: PhantomData<fn() -> Arch>,
}
#[allow(dead_code)]
impl<Arch: MemoryManagementArch> PageFlushAll<Arch> {
pub fn new() -> Self {
return Self {
phantom: PhantomData,
};
}
pub fn flush(self) {
unsafe { Arch::invalidate_all() };
}
/// 忽略掉这个刷新器
pub unsafe fn ignore(self) {
mem::forget(self);
}
}
impl<Arch: MemoryManagementArch> Flusher<Arch> for PageFlushAll<Arch> {
/// 为page flush all 实现consume消除对单个页面的刷新。刷新整个页表了就不需要刷新单个页面了
fn consume(&mut self, flush: PageFlush<Arch>) {
unsafe { flush.ignore() };
}
}
impl<Arch: MemoryManagementArch, T: Flusher<Arch> + ?Sized> Flusher<Arch> for &mut T {
/// 允许一个flusher consume掉另一个flusher
fn consume(&mut self, flush: PageFlush<Arch>) {
<T as Flusher<Arch>>::consume(self, flush);
}
}
impl<Arch: MemoryManagementArch> Flusher<Arch> for () {
fn consume(&mut self, _flush: PageFlush<Arch>) {}
}
impl<Arch: MemoryManagementArch> Drop for PageFlushAll<Arch> {
fn drop(&mut self) {
unsafe {
Arch::invalidate_all();
}
}
}
/// 未在当前CPU上激活的页表的刷新器
///
/// 如果页表没有在当前cpu上激活那么需要发送ipi到其他核心尝试在其他核心上刷新页表
///
/// TODO: 这个方式很暴力,也许把它改成在指定的核心上刷新页表会更好。(可以测试一下开销)
#[derive(Debug)]
pub struct InactiveFlusher;
impl InactiveFlusher {
pub fn new() -> Self {
return Self {};
}
}
impl Flusher<MMArch> for InactiveFlusher {
fn consume(&mut self, flush: PageFlush<MMArch>) {
unsafe {
flush.ignore();
}
}
}
impl Drop for InactiveFlusher {
fn drop(&mut self) {
// 发送刷新页表的IPI
send_ipi(IpiKind::FlushTLB, IpiTarget::Other);
}
}
/// # 把一个地址向下对齐到页大小
pub fn round_down_to_page_size(addr: usize) -> usize {
addr & !(MMArch::PAGE_SIZE - 1)
}
/// # 把一个地址向上对齐到页大小
pub fn round_up_to_page_size(addr: usize) -> usize {
round_down_to_page_size(addr + MMArch::PAGE_SIZE - 1)
}

713
kernel/src/mm/slab.c Normal file
View File

@ -0,0 +1,713 @@
#include "slab.h"
#include <common/compiler.h>
struct slab kmalloc_cache_group[16] =
{
{32, 0, 0, NULL, NULL, NULL, NULL},
{64, 0, 0, NULL, NULL, NULL, NULL},
{128, 0, 0, NULL, NULL, NULL, NULL},
{256, 0, 0, NULL, NULL, NULL, NULL},
{512, 0, 0, NULL, NULL, NULL, NULL},
{1024, 0, 0, NULL, NULL, NULL, NULL}, // 1KB
{2048, 0, 0, NULL, NULL, NULL, NULL},
{4096, 0, 0, NULL, NULL, NULL, NULL}, // 4KB
{8192, 0, 0, NULL, NULL, NULL, NULL},
{16384, 0, 0, NULL, NULL, NULL, NULL},
{32768, 0, 0, NULL, NULL, NULL, NULL},
{65536, 0, 0, NULL, NULL, NULL, NULL},
{131072, 0, 0, NULL, NULL, NULL, NULL}, // 128KB
{262144, 0, 0, NULL, NULL, NULL, NULL},
{524288, 0, 0, NULL, NULL, NULL, NULL},
{1048576, 0, 0, NULL, NULL, NULL, NULL}, // 1MB
};
/**
* @brief 创建一个内存池
*
* @param size 内存池容量大小
* @param constructor 构造函数
* @param destructor 析构函数
* @param arg 参数
* @return struct slab* 构建好的内存池对象
*/
struct slab *slab_create(ul size, void *(*constructor)(void *vaddr, ul arg), void *(*destructor)(void *vaddr, ul arg), ul arg)
{
struct slab *slab_pool = (struct slab *)kmalloc(sizeof(struct slab), 0);
// BUG
if (slab_pool == NULL)
{
kBUG("slab_create()->kmalloc()->slab == NULL");
return NULL;
}
memset(slab_pool, 0, sizeof(struct slab));
slab_pool->size = SIZEOF_LONG_ALIGN(size);
slab_pool->count_total_using = 0;
slab_pool->count_total_free = 0;
// 直接分配cache_pool_entry结构体避免每次访问都要检测是否为NULL提升效率
slab_pool->cache_pool_entry = (struct slab_obj *)kmalloc(sizeof(struct slab_obj), 0);
// BUG
if (slab_pool->cache_pool_entry == NULL)
{
kBUG("slab_create()->kmalloc()->slab->cache_pool_entry == NULL");
kfree(slab_pool);
return NULL;
}
memset(slab_pool->cache_pool_entry, 0, sizeof(struct slab_obj));
// dma内存池设置为空
slab_pool->cache_dma_pool_entry = NULL;
// 设置构造及析构函数
slab_pool->constructor = constructor;
slab_pool->destructor = destructor;
list_init(&slab_pool->cache_pool_entry->list);
// 分配属于内存池的内存页
slab_pool->cache_pool_entry->page = alloc_pages(ZONE_NORMAL, 1, PAGE_KERNEL);
// BUG
if (slab_pool->cache_pool_entry->page == NULL)
{
kBUG("slab_create()->kmalloc()->slab->cache_pool_entry == NULL");
kfree(slab_pool->cache_pool_entry);
kfree(slab_pool);
return NULL;
}
// page_init(slab_pool->cache_pool_entry->page, PAGE_KERNEL);
slab_pool->cache_pool_entry->count_using = 0;
slab_pool->cache_pool_entry->count_free = PAGE_2M_SIZE / slab_pool->size;
slab_pool->count_total_free = slab_pool->cache_pool_entry->count_free;
slab_pool->cache_pool_entry->vaddr = phys_2_virt(slab_pool->cache_pool_entry->page->addr_phys);
// bitmap有多少有效位
slab_pool->cache_pool_entry->bmp_count = slab_pool->cache_pool_entry->count_free;
// 计算位图所占的空间 占用多少byte按unsigned long大小的上边缘对齐
slab_pool->cache_pool_entry->bmp_len = ((slab_pool->cache_pool_entry->bmp_count + sizeof(ul) * 8 - 1) >> 6) << 3;
// 初始化位图
slab_pool->cache_pool_entry->bmp = (ul *)kmalloc(slab_pool->cache_pool_entry->bmp_len, 0);
// BUG
if (slab_pool->cache_pool_entry->bmp == NULL)
{
kBUG("slab_create()->kmalloc()->slab->cache_pool_entry == NULL");
free_pages(slab_pool->cache_pool_entry->page, 1);
kfree(slab_pool->cache_pool_entry);
kfree(slab_pool);
return NULL;
}
// 将位图清空
memset(slab_pool->cache_pool_entry->bmp, 0, slab_pool->cache_pool_entry->bmp_len);
return slab_pool;
}
/**
* @brief 销毁内存池
* 只有当slab是空的时候才能销毁
* @param slab_pool 要销毁的内存池
* @return ul
*
*/
ul slab_destroy(struct slab *slab_pool)
{
struct slab_obj *slab_obj_ptr = slab_pool->cache_pool_entry;
if (slab_pool->count_total_using)
{
kBUG("slab_cache->count_total_using != 0");
return ESLAB_NOTNULL;
}
struct slab_obj *tmp_slab_obj = NULL;
while (!list_empty(&slab_obj_ptr->list))
{
tmp_slab_obj = slab_obj_ptr;
// 获取下一个slab_obj的起始地址
slab_obj_ptr = container_of(list_next(&slab_obj_ptr->list), struct slab_obj, list);
list_del(&tmp_slab_obj->list);
kfree(tmp_slab_obj->bmp);
page_clean(tmp_slab_obj->page);
free_pages(tmp_slab_obj->page, 1);
kfree(tmp_slab_obj);
}
kfree(slab_obj_ptr->bmp);
page_clean(slab_obj_ptr->page);
free_pages(slab_obj_ptr->page, 1);
kfree(slab_obj_ptr);
kfree(slab_pool);
return 0;
}
/**
* @brief 分配SLAB内存池中的内存对象
*
* @param slab_pool slab内存池
* @param arg 传递给内存对象构造函数的参数
* @return void* 内存空间的虚拟地址
*/
void *slab_malloc(struct slab *slab_pool, ul arg)
{
struct slab_obj *slab_obj_ptr = slab_pool->cache_pool_entry;
struct slab_obj *tmp_slab_obj = NULL;
// slab内存池中已经没有空闲的内存对象进行扩容
if (slab_pool->count_total_free == 0)
{
tmp_slab_obj = (struct slab_obj *)kmalloc(sizeof(struct slab_obj), 0);
// BUG
if (tmp_slab_obj == NULL)
{
kBUG("slab_malloc()->kmalloc()->slab->tmp_slab_obj == NULL");
return NULL;
}
memset(tmp_slab_obj, 0, sizeof(struct slab_obj));
list_init(&tmp_slab_obj->list);
tmp_slab_obj->page = alloc_pages(ZONE_NORMAL, 1, PAGE_KERNEL);
// BUG
if (tmp_slab_obj->page == NULL)
{
kBUG("slab_malloc()->kmalloc()=>tmp_slab_obj->page == NULL");
kfree(tmp_slab_obj);
return NULL;
}
tmp_slab_obj->count_using = 0;
tmp_slab_obj->count_free = PAGE_2M_SIZE / slab_pool->size;
tmp_slab_obj->vaddr = phys_2_virt(tmp_slab_obj->page->addr_phys);
tmp_slab_obj->bmp_count = tmp_slab_obj->count_free;
// 计算位图所占的空间 占用多少byte按unsigned long大小的上边缘对齐
tmp_slab_obj->bmp_len = ((tmp_slab_obj->bmp_count + sizeof(ul) * 8 - 1) >> 6) << 3;
tmp_slab_obj->bmp = (ul *)kmalloc(tmp_slab_obj->bmp_len, 0);
// BUG
if (tmp_slab_obj->bmp == NULL)
{
kBUG("slab_malloc()->kmalloc()=>tmp_slab_obj->bmp == NULL");
free_pages(tmp_slab_obj->page, 1);
kfree(tmp_slab_obj);
return NULL;
}
memset(tmp_slab_obj->bmp, 0, tmp_slab_obj->bmp_len);
list_add(&slab_pool->cache_pool_entry->list, &tmp_slab_obj->list);
slab_pool->count_total_free += tmp_slab_obj->count_free;
slab_obj_ptr = tmp_slab_obj;
}
// 扩容完毕或无需扩容,开始分配内存对象
int tmp_md;
do
{
if (slab_obj_ptr->count_free == 0)
{
slab_obj_ptr = container_of(list_next(&slab_obj_ptr->list), struct slab_obj, list);
continue;
}
for (int i = 0; i < slab_obj_ptr->bmp_count; ++i)
{
// 当前bmp对应的内存对象都已经被分配
if (*(slab_obj_ptr->bmp + (i >> 6)) == 0xffffffffffffffffUL)
{
i += 63;
continue;
}
// 第i个内存对象是空闲的
tmp_md = i % 64;
if ((*(slab_obj_ptr->bmp + (i >> 6)) & (1UL << tmp_md)) == 0)
{
// 置位bmp
*(slab_obj_ptr->bmp + (i >> 6)) |= (1UL << tmp_md);
// 更新当前slab对象的计数器
++(slab_obj_ptr->count_using);
--(slab_obj_ptr->count_free);
// 更新slab内存池的计数器
++(slab_pool->count_total_using);
--(slab_pool->count_total_free);
if (slab_pool->constructor != NULL)
{
// 返回内存对象指针(要求构造函数返回内存对象指针)
return slab_pool->constructor((char *)slab_obj_ptr->vaddr + slab_pool->size * i, arg);
}
// 返回内存对象指针
else
return (void *)((char *)slab_obj_ptr->vaddr + slab_pool->size * i);
}
}
} while (slab_obj_ptr != slab_pool->cache_pool_entry);
// should not be here
kBUG("slab_malloc() ERROR: can't malloc");
// 释放内存
if (tmp_slab_obj != NULL)
{
list_del(&tmp_slab_obj->list);
kfree(tmp_slab_obj->bmp);
page_clean(tmp_slab_obj->page);
free_pages(tmp_slab_obj->page, 1);
kfree(tmp_slab_obj);
}
return NULL;
}
/**
* @brief 回收slab内存池中的对象
*
* @param slab_pool 对应的内存池
* @param addr 内存对象的虚拟地址
* @param arg 传递给虚构函数的参数
* @return ul
*/
ul slab_free(struct slab *slab_pool, void *addr, ul arg)
{
struct slab_obj *slab_obj_ptr = slab_pool->cache_pool_entry;
do
{
// 虚拟地址不在当前内存池对象的管理范围内
if (!(slab_obj_ptr->vaddr <= addr && addr <= (slab_obj_ptr->vaddr + PAGE_2M_SIZE)))
{
slab_obj_ptr = container_of(list_next(&slab_obj_ptr->list), struct slab_obj, list);
}
else
{
// 计算出给定内存对象是第几个
int index = (addr - slab_obj_ptr->vaddr) / slab_pool->size;
// 复位位图中对应的位
*(slab_obj_ptr->bmp + (index >> 6)) ^= (1UL << index % 64);
++(slab_obj_ptr->count_free);
--(slab_obj_ptr->count_using);
++(slab_pool->count_total_free);
--(slab_pool->count_total_using);
// 有对应的析构函数,调用析构函数
if (slab_pool->destructor != NULL)
slab_pool->destructor((char *)slab_obj_ptr->vaddr + slab_pool->size * index, arg);
// 当前内存对象池的正在使用的内存对象为0且内存池的空闲对象大于当前对象池的2倍则销毁当前对象池以减轻系统内存压力
if ((slab_obj_ptr->count_using == 0) && ((slab_pool->count_total_free >> 1) >= slab_obj_ptr->count_free) && (slab_obj_ptr != slab_pool->cache_pool_entry))
{
list_del(&slab_obj_ptr->list);
slab_pool->count_total_free -= slab_obj_ptr->count_free;
kfree(slab_obj_ptr->bmp);
page_clean(slab_obj_ptr->page);
free_pages(slab_obj_ptr->page, 1);
kfree(slab_obj_ptr);
}
}
return 0;
} while (slab_obj_ptr != slab_pool->cache_pool_entry);
kwarn("slab_free(): address not in current slab");
return ENOT_IN_SLAB;
}
/**
* @brief 初始化内存池组
* 在初始化通用内存管理单元期间尚无内存空间分配函数需要我们手动为SLAB内存池指定存储空间
* @return ul
*/
ul slab_init()
{
kinfo("Initializing SLAB...");
// 将slab的内存池空间放置在mms的后方
ul tmp_addr = memory_management_struct.end_of_struct;
for (int i = 0; i < 16; ++i)
{
io_mfence();
spin_init(&kmalloc_cache_group[i].lock);
// 将slab内存池对象的空间放置在mms的后面并且预留4个unsigned long 的空间以防止内存越界
kmalloc_cache_group[i].cache_pool_entry = (struct slab_obj *)memory_management_struct.end_of_struct;
memory_management_struct.end_of_struct += sizeof(struct slab_obj) + (sizeof(ul) << 2);
list_init(&kmalloc_cache_group[i].cache_pool_entry->list);
// 初始化内存池对象
kmalloc_cache_group[i].cache_pool_entry->count_using = 0;
kmalloc_cache_group[i].cache_pool_entry->count_free = PAGE_2M_SIZE / kmalloc_cache_group[i].size;
kmalloc_cache_group[i].cache_pool_entry->bmp_len = (((kmalloc_cache_group[i].cache_pool_entry->count_free + sizeof(ul) * 8 - 1) >> 6) << 3);
kmalloc_cache_group[i].cache_pool_entry->bmp_count = kmalloc_cache_group[i].cache_pool_entry->count_free;
// 在slab对象后方放置bmp
kmalloc_cache_group[i].cache_pool_entry->bmp = (ul *)memory_management_struct.end_of_struct;
// bmp后方预留4个unsigned long的空间防止内存越界,且按照8byte进行对齐
memory_management_struct.end_of_struct = (ul)(memory_management_struct.end_of_struct + kmalloc_cache_group[i].cache_pool_entry->bmp_len + (sizeof(ul) << 2)) & (~(sizeof(ul) - 1));
io_mfence();
// @todo此处可优化直接把所有位设置为0然后再对部分不存在对应的内存对象的位设置为1
memset(kmalloc_cache_group[i].cache_pool_entry->bmp, 0xff, kmalloc_cache_group[i].cache_pool_entry->bmp_len);
for (int j = 0; j < kmalloc_cache_group[i].cache_pool_entry->bmp_count; ++j)
*(kmalloc_cache_group[i].cache_pool_entry->bmp + (j >> 6)) ^= 1UL << (j % 64);
kmalloc_cache_group[i].count_total_using = 0;
kmalloc_cache_group[i].count_total_free = kmalloc_cache_group[i].cache_pool_entry->count_free;
io_mfence();
}
struct Page *page = NULL;
// 将上面初始化内存池组时,所占用的内存页进行初始化
ul tmp_page_mms_end = virt_2_phys(memory_management_struct.end_of_struct) >> PAGE_2M_SHIFT;
ul page_num = 0;
for (int i = PAGE_2M_ALIGN(virt_2_phys(tmp_addr)) >> PAGE_2M_SHIFT; i <= tmp_page_mms_end; ++i)
{
page = memory_management_struct.pages_struct + i;
page_num = page->addr_phys >> PAGE_2M_SHIFT;
*(memory_management_struct.bmp + (page_num >> 6)) |= (1UL << (page_num % 64));
++page->zone->count_pages_using;
io_mfence();
--page->zone->count_pages_free;
page_init(page, PAGE_KERNEL_INIT | PAGE_KERNEL | PAGE_PGT_MAPPED);
}
io_mfence();
// 为slab内存池对象分配内存空间
ul *virt = NULL;
for (int i = 0; i < 16; ++i)
{
// 获取一个新的空页并添加到空页表,然后返回其虚拟地址
virt = (ul *)((memory_management_struct.end_of_struct + PAGE_2M_SIZE * i + PAGE_2M_SIZE - 1) & PAGE_2M_MASK);
page = Virt_To_2M_Page(virt);
page_num = page->addr_phys >> PAGE_2M_SHIFT;
*(memory_management_struct.bmp + (page_num >> 6)) |= (1UL << (page_num % 64));
++page->zone->count_pages_using;
io_mfence(); // 该位置必须加一个mfence否则O3优化运行时会报错
--page->zone->count_pages_free;
page_init(page, PAGE_PGT_MAPPED | PAGE_KERNEL | PAGE_KERNEL_INIT);
kmalloc_cache_group[i].cache_pool_entry->page = page;
kmalloc_cache_group[i].cache_pool_entry->vaddr = virt;
}
kinfo("SLAB initialized successfully!");
return 0;
}
/**
* @brief 在kmalloc中创建slab_obj的函数与slab_malloc()中的类似)
*
* @param size
* @return struct slab_obj* 创建好的slab_obj
*/
struct slab_obj *kmalloc_create_slab_obj(ul size)
{
struct Page *page = alloc_pages(ZONE_NORMAL, 1, 0);
// BUG
if (page == NULL)
{
kBUG("kmalloc_create()->alloc_pages()=>page == NULL");
return NULL;
}
page_init(page, PAGE_KERNEL);
ul *vaddr = NULL;
ul struct_size = 0;
struct slab_obj *slab_obj_ptr;
// 根据size大小选择不同的分支来处理
// 之所以选择512byte为分界点是因为此时bmp大小刚好为512byte。显而易见选择过小的话会导致kmalloc函数与当前函数反复互相调用最终导致栈溢出
switch (size)
{
// ============ 对于size<=512byte的内存池对象将slab_obj结构体和bmp放置在物理页的内部 ========
// 由于这些对象的特征是bmp占的空间大而内存块的空间小这样做的目的是避免再去申请一块内存来存储bmp减少浪费。
case 32:
case 64:
case 128:
case 256:
case 512:
vaddr = phys_2_virt(page->addr_phys);
// slab_obj结构体的大小 (本身的大小+bmp的大小
struct_size = sizeof(struct slab_obj) + PAGE_2M_SIZE / size / 8;
// 将slab_obj放置到物理页的末尾
slab_obj_ptr = (struct slab_obj *)((unsigned char *)vaddr + PAGE_2M_SIZE - struct_size);
slab_obj_ptr->bmp = (void *)slab_obj_ptr + sizeof(struct slab_obj);
slab_obj_ptr->count_free = (PAGE_2M_SIZE - struct_size) / size;
slab_obj_ptr->count_using = 0;
slab_obj_ptr->bmp_count = slab_obj_ptr->count_free;
slab_obj_ptr->vaddr = vaddr;
slab_obj_ptr->page = page;
list_init(&slab_obj_ptr->list);
slab_obj_ptr->bmp_len = ((slab_obj_ptr->bmp_count + sizeof(ul) * 8 - 1) >> 6) << 3;
// @todo此处可优化直接把所有位设置为0然后再对部分不存在对应的内存对象的位设置为1
memset(slab_obj_ptr->bmp, 0xff, slab_obj_ptr->bmp_len);
for (int i = 0; i < slab_obj_ptr->bmp_count; ++i)
*(slab_obj_ptr->bmp + (i >> 6)) ^= 1UL << (i % 64);
break;
// ================= 较大的size时slab_obj和bmp不再放置于当前物理页内部 ============
// 因为在这种情况下bmp很短继续放置在当前物理页内部则会造成可分配的对象少加剧了内存空间的浪费
case 1024: // 1KB
case 2048:
case 4096: // 4KB
case 8192:
case 16384:
case 32768:
case 65536:
case 131072: // 128KB
case 262144:
case 524288:
case 1048576: // 1MB
slab_obj_ptr = (struct slab_obj *)kmalloc(sizeof(struct slab_obj), 0);
slab_obj_ptr->count_free = PAGE_2M_SIZE / size;
slab_obj_ptr->count_using = 0;
slab_obj_ptr->bmp_count = slab_obj_ptr->count_free;
slab_obj_ptr->bmp_len = ((slab_obj_ptr->bmp_count + sizeof(ul) * 8 - 1) >> 6) << 3;
slab_obj_ptr->bmp = (ul *)kmalloc(slab_obj_ptr->bmp_len, 0);
// @todo此处可优化直接把所有位设置为0然后再对部分不存在对应的内存对象的位设置为1
memset(slab_obj_ptr->bmp, 0xff, slab_obj_ptr->bmp_len);
for (int i = 0; i < slab_obj_ptr->bmp_count; ++i)
*(slab_obj_ptr->bmp + (i >> 6)) ^= 1UL << (i % 64);
slab_obj_ptr->vaddr = phys_2_virt(page->addr_phys);
slab_obj_ptr->page = page;
list_init(&slab_obj_ptr->list);
break;
// size 错误
default:
kerror("kamlloc_create(): Wrong size%d", size);
free_pages(page, 1);
return NULL;
break;
}
return slab_obj_ptr;
}
/**
* @brief 通用内存分配函数
*
* @param size 要分配的内存大小
* @param gfp 内存的flag
* @return void* 内核内存虚拟地址
*/
void *kmalloc(unsigned long size, gfp_t gfp)
{
void *result = NULL;
if (size > 1048576)
{
kwarn("kmalloc(): Can't alloc such memory: %ld bytes, because it is too large.", size);
return NULL;
}
int index;
for (int i = 0; i < 16; ++i)
{
if (kmalloc_cache_group[i].size >= size)
{
index = i;
break;
}
}
// 对当前内存池加锁
spin_lock(&kmalloc_cache_group[index].lock);
struct slab_obj *slab_obj_ptr = kmalloc_cache_group[index].cache_pool_entry;
// 内存池没有可用的内存对象,需要进行扩容
if (unlikely(kmalloc_cache_group[index].count_total_free == 0))
{
// 创建slab_obj
slab_obj_ptr = kmalloc_create_slab_obj(kmalloc_cache_group[index].size);
// BUG
if (unlikely(slab_obj_ptr == NULL))
{
kBUG("kmalloc()->kmalloc_create_slab_obj()=>slab == NULL");
goto failed;
}
kmalloc_cache_group[index].count_total_free += slab_obj_ptr->count_free;
list_add(&kmalloc_cache_group[index].cache_pool_entry->list, &slab_obj_ptr->list);
}
else // 内存对象充足
{
do
{
// 跳转到下一个内存池对象
if (slab_obj_ptr->count_free == 0)
slab_obj_ptr = container_of(list_next(&slab_obj_ptr->list), struct slab_obj, list);
else
break;
} while (slab_obj_ptr != kmalloc_cache_group[index].cache_pool_entry);
}
// 寻找一块可用的内存对象
int md;
for (int i = 0; i < slab_obj_ptr->bmp_count; ++i)
{
// 当前bmp全部被使用
if (*(slab_obj_ptr->bmp + (i >> 6)) == 0xffffffffffffffffUL)
{
i += 63;
continue;
}
md = i % 64;
// 找到相应的内存对象
if ((*(slab_obj_ptr->bmp + (i >> 6)) & (1UL << md)) == 0)
{
*(slab_obj_ptr->bmp + (i >> 6)) |= (1UL << md);
++(slab_obj_ptr->count_using);
--(slab_obj_ptr->count_free);
--kmalloc_cache_group[index].count_total_free;
++kmalloc_cache_group[index].count_total_using;
// 放锁
spin_unlock(&kmalloc_cache_group[index].lock);
// 返回内存对象
result = (void *)((char *)slab_obj_ptr->vaddr + kmalloc_cache_group[index].size * i);
goto done;
}
}
goto failed;
done:;
if (gfp & __GFP_ZERO)
memset(result, 0, size);
return result;
failed:;
spin_unlock(&kmalloc_cache_group[index].lock);
kerror("kmalloc(): Cannot alloc more memory: %d bytes", size);
return NULL;
}
/**
* @brief 通用内存释放函数
*
* @param address 要释放的内存线性地址
* @return unsigned long
*/
unsigned long kfree(void *address)
{
if (unlikely(address == NULL))
return 0;
struct slab_obj *slab_obj_ptr = NULL;
// 将线性地址按照2M物理页对齐, 获得所在物理页的起始线性地址
void *page_base_addr = (void *)((ul)address & PAGE_2M_MASK);
int index;
for (int i = 0; i < 16; ++i)
{
slab_obj_ptr = kmalloc_cache_group[i].cache_pool_entry;
do
{
// 不属于当前slab_obj的管理范围
if (likely(slab_obj_ptr->vaddr != page_base_addr))
{
slab_obj_ptr = container_of(list_next(&slab_obj_ptr->list), struct slab_obj, list);
}
else
{
// 对当前内存池加锁
spin_lock(&kmalloc_cache_group[i].lock);
// 计算地址属于哪一个内存对象
index = (address - slab_obj_ptr->vaddr) / kmalloc_cache_group[i].size;
// 复位bmp
*(slab_obj_ptr->bmp + (index >> 6)) ^= 1UL << (index % 64);
++(slab_obj_ptr->count_free);
--(slab_obj_ptr->count_using);
++kmalloc_cache_group[i].count_total_free;
--kmalloc_cache_group[i].count_total_using;
// 回收空闲的slab_obj
// 条件当前slab_obj_ptr的使用为0、总空闲内存对象>=当前slab_obj的总对象的2倍 且当前slab_pool不为起始slab_obj
if ((slab_obj_ptr->count_using == 0) && (kmalloc_cache_group[i].count_total_free >= ((slab_obj_ptr->bmp_count) << 1)) && (kmalloc_cache_group[i].cache_pool_entry != slab_obj_ptr))
{
switch (kmalloc_cache_group[i].size)
{
case 32:
case 64:
case 128:
case 256:
case 512:
// 在这种情况下slab_obj是被安放在page内部的
list_del(&slab_obj_ptr->list);
kmalloc_cache_group[i].count_total_free -= slab_obj_ptr->bmp_count;
page_clean(slab_obj_ptr->page);
free_pages(slab_obj_ptr->page, 1);
break;
default:
// 在这种情况下slab_obj是被安放在额外获取的内存对象中的
list_del(&slab_obj_ptr->list);
kmalloc_cache_group[i].count_total_free -= slab_obj_ptr->bmp_count;
kfree(slab_obj_ptr->bmp);
page_clean(slab_obj_ptr->page);
free_pages(slab_obj_ptr->page, 1);
kfree(slab_obj_ptr);
break;
}
}
// 放锁
spin_unlock(&kmalloc_cache_group[i].lock);
return 0;
}
} while (slab_obj_ptr != kmalloc_cache_group[i].cache_pool_entry);
}
kBUG("kfree(): Can't free memory. address=%#018lx", address);
return ECANNOT_FREE_MEM;
}

View File

@ -1,6 +1,54 @@
#pragma once
#include "mm.h"
#include <common/glib.h>
#include <common/printk.h>
#include <common/kprint.h>
#include <common/spinlock.h>
#define SIZEOF_LONG_ALIGN(size) ((size + sizeof(long) - 1) & ~(sizeof(long) - 1))
#define SIZEOF_INT_ALIGN(size) ((size + sizeof(int) - 1) & ~(sizeof(int) - 1))
// SLAB存储池count_using不为空
#define ESLAB_NOTNULL 101
#define ENOT_IN_SLAB 102 // 地址不在当前slab内存池中
#define ECANNOT_FREE_MEM 103 // 无法释放内存
struct slab_obj
{
struct List list;
// 当前slab对象所使用的内存页
struct Page *page;
ul count_using;
ul count_free;
// 当前页面所在的线性地址
void *vaddr;
// 位图
ul bmp_len; // 位图的长度(字节)
ul bmp_count; // 位图的有效位数
ul *bmp;
};
// slab内存池
struct slab
{
ul size; // 单位byte
ul count_total_using;
ul count_total_free;
// 内存池对象
struct slab_obj *cache_pool_entry;
// dma内存池对象
struct slab_obj *cache_dma_pool_entry;
spinlock_t lock; // 当前内存池的操作锁
// 内存池的构造函数和析构函数
void *(*constructor)(void *vaddr, ul arg);
void *(*destructor)(void *vaddr, ul arg);
};
/**
* @brief 通用内存分配函数
@ -9,16 +57,19 @@
* @param gfp 内存的flag
* @return void* 分配得到的内存的指针
*/
extern void *kmalloc(unsigned long size, gfp_t gfp);
void *kmalloc(unsigned long size, gfp_t gfp);
/**
* @brief 从kmalloc申请一块内存并将这块内存清空
*
*
* @param size 要分配的内存大小
* @param gfp 内存的flag
* @return void* 分配得到的内存的指针
*/
extern void *kzalloc(size_t size, gfp_t gfp);
static __always_inline void *kzalloc(size_t size, gfp_t gfp)
{
return kmalloc(size, gfp | __GFP_ZERO);
}
/**
* @brief 通用内存释放函数
@ -26,4 +77,58 @@ extern void *kzalloc(size_t size, gfp_t gfp);
* @param address 要释放的内存地址
* @return unsigned long
*/
extern unsigned long kfree(void *address);
unsigned long kfree(void *address);
/**
* @brief 创建一个内存池
*
* @param size 内存池容量大小
* @param constructor 构造函数
* @param destructor 析构函数
* @param arg 参数
* @return struct slab* 构建好的内存池对象
*/
struct slab *slab_create(ul size, void *(*constructor)(void *vaddr, ul arg), void *(*destructor)(void *vaddr, ul arg), ul arg);
/**
* @brief 销毁内存池对象
* 只有当slab对象是空的时候才能销毁
* @param slab_pool 要销毁的内存池对象
* @return ul
*
*/
ul slab_destroy(struct slab *slab_pool);
/**
* @brief 分配SLAB内存池中的内存对象
*
* @param slab_pool slab内存池
* @param arg 传递给内存对象构造函数的参数
* @return void* 内存空间的虚拟地址
*/
void *slab_malloc(struct slab *slab_pool, ul arg);
/**
* @brief 回收slab内存池中的对象
*
* @param slab_pool 对应的内存池
* @param addr 内存对象的虚拟地址
* @param arg 传递给虚构函数的参数
* @return ul
*/
ul slab_free(struct slab *slab_pool, void *addr, ul arg);
/**
* @brief 在kmalloc中创建slab_obj的函数与slab_malloc()类似)
*
* @param size
* @return struct slab_obj* 创建好的slab_obj
*/
struct slab_obj *kmalloc_create_slab_obj(ul size);
/**
* @brief 初始化内存池组
* 在初始化通用内存管理单元期间尚无内存空间分配函数需要我们手动为SLAB内存池指定存储空间
* @return ul
*/
ul slab_init();

View File

@ -1,219 +1,43 @@
use core::intrinsics::unlikely;
use alloc::sync::Arc;
use crate::{
arch::MMArch,
kerror,
libs::align::{check_aligned, page_align_up},
mm::MemoryManagementArch,
include::bindings::bindings::mm_stat_t,
syscall::{Syscall, SystemError},
};
use super::{
allocator::page_frame::{PageFrameCount, VirtPageFrame},
ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR},
verify_area, VirtAddr,
};
bitflags! {
/// Memory protection flags
pub struct ProtFlags: u64 {
const PROT_NONE = 0x0;
const PROT_READ = 0x1;
const PROT_WRITE = 0x2;
const PROT_EXEC = 0x4;
}
/// Memory mapping flags
pub struct MapFlags: u64 {
const MAP_NONE = 0x0;
/// share changes
const MAP_SHARED = 0x1;
/// changes are private
const MAP_PRIVATE = 0x2;
/// Interpret addr exactly
const MAP_FIXED = 0x10;
/// don't use a file
const MAP_ANONYMOUS = 0x20;
// linux-6.1-rc5/include/uapi/asm-generic/mman.h#7
/// stack-like segment
const MAP_GROWSDOWN = 0x100;
/// ETXTBSY
const MAP_DENYWRITE = 0x800;
/// Mark it as an executable
const MAP_EXECUTABLE = 0x1000;
/// Pages are locked
const MAP_LOCKED = 0x2000;
/// don't check for reservations
const MAP_NORESERVE = 0x4000;
/// populate (prefault) pagetables
const MAP_POPULATE = 0x8000;
/// do not block on IO
const MAP_NONBLOCK = 0x10000;
/// give out an address that is best suited for process/thread stacks
const MAP_STACK = 0x20000;
/// create a huge page mapping
const MAP_HUGETLB = 0x40000;
/// perform synchronous page faults for the mapping
const MAP_SYNC = 0x80000;
/// MAP_FIXED which doesn't unmap underlying mapping
const MAP_FIXED_NOREPLACE = 0x100000;
/// For anonymous mmap, memory could be uninitialized
const MAP_UNINITIALIZED = 0x4000000;
}
extern "C" {
fn sys_do_brk(new_addr: usize) -> usize;
fn sys_do_sbrk(incr: isize) -> usize;
fn sys_do_mstat(dst: *mut mm_stat_t, from_user: bool) -> usize;
}
impl Syscall {
pub fn brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError> {
// kdebug!("brk: new_addr={:?}", new_addr);
let address_space = AddressSpace::current()?;
let mut address_space = address_space.write();
unsafe {
address_space
.set_brk(VirtAddr::new(page_align_up(new_addr.data())))
.ok();
return Ok(address_space.sbrk(0).unwrap());
}
}
pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> {
// kdebug!("pid:{}, sbrk: incr={}", current_pcb().pid, incr);
let address_space = AddressSpace::current()?;
let mut address_space = address_space.write();
let r = unsafe { address_space.sbrk(incr) };
// kdebug!("pid:{}, sbrk: r={:?}", current_pcb().pid, r);
return r;
}
/// ## mmap系统调用
///
/// 该函数的实现参考了Linux内核的实现但是并不完全相同。因为有些功能咱们还没实现
///
/// ## 参数
///
/// - `start_vaddr`:映射的起始地址
/// - `len`:映射的长度
/// - `prot`:保护标志
/// - `flags`:映射标志
/// - `fd`:文件描述符(暂时不支持)
/// - `offset`:文件偏移量 (暂时不支持)
///
/// ## 返回值
///
/// 成功时返回映射的起始地址,失败时返回错误码
pub fn mmap(
start_vaddr: VirtAddr,
len: usize,
prot_flags: usize,
map_flags: usize,
_fd: i32,
_offset: usize,
) -> Result<usize, SystemError> {
let map_flags = MapFlags::from_bits_truncate(map_flags as u64);
let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64);
if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR)
&& map_flags.contains(MapFlags::MAP_FIXED)
{
kerror!(
"mmap: MAP_FIXED is not supported for address below {}",
DEFAULT_MMAP_MIN_ADDR
pub fn brk(new_addr: usize) -> Result<usize, SystemError> {
let ret = unsafe { sys_do_brk(new_addr) };
if (ret as isize) < 0 {
return Err(
SystemError::from_posix_errno(-(ret as isize) as i32).expect("brk: Invalid errno")
);
return Err(SystemError::EINVAL);
}
// 暂时不支持除匿名页以外的映射
if !map_flags.contains(MapFlags::MAP_ANONYMOUS) {
kerror!("mmap: not support file mapping");
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
// 暂时不支持巨页映射
if map_flags.contains(MapFlags::MAP_HUGETLB) {
kerror!("mmap: not support huge page mapping");
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
let current_address_space = AddressSpace::current()?;
let start_page = current_address_space.write().map_anonymous(
start_vaddr,
len,
prot_flags,
map_flags,
true,
)?;
return Ok(start_page.virt_address().data());
return Ok(ret);
}
/// ## munmap系统调用
///
/// ## 参数
///
/// - `start_vaddr`:取消映射的起始地址(已经对齐到页)
/// - `len`:取消映射的字节数(已经对齐到页)
///
/// ## 返回值
///
/// 成功时返回0失败时返回错误码
pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> {
assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
assert!(check_aligned(len, MMArch::PAGE_SIZE));
if unlikely(verify_area(start_vaddr, len).is_err()) {
return Err(SystemError::EINVAL);
pub fn sbrk(incr: isize) -> Result<usize, SystemError> {
let ret = unsafe { sys_do_sbrk(incr) };
if (ret as isize) < 0 {
return Err(
SystemError::from_posix_errno(-(ret as isize) as i32).expect("sbrk: Invalid errno")
);
}
if unlikely(len == 0) {
return Err(SystemError::EINVAL);
}
let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
let start_frame = VirtPageFrame::new(start_vaddr);
let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
current_address_space
.write()
.munmap(start_frame, page_count)
.map_err(|_| SystemError::EINVAL)?;
return Ok(0);
return Ok(ret);
}
/// ## mprotect系统调用
/// 获取内存统计信息
///
/// ## 参数
///
/// - `start_vaddr`:起始地址(已经对齐到页)
/// - `len`:长度(已经对齐到页)
/// - `prot_flags`:保护标志
pub fn mprotect(
start_vaddr: VirtAddr,
len: usize,
prot_flags: usize,
) -> Result<usize, SystemError> {
assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
assert!(check_aligned(len, MMArch::PAGE_SIZE));
if unlikely(verify_area(start_vaddr, len).is_err()) {
return Err(SystemError::EINVAL);
/// TODO: 该函数不是符合POSIX标准的在将来需要删除
pub fn mstat(dst: *mut mm_stat_t, from_user: bool) -> Result<usize, SystemError> {
let ret = unsafe { sys_do_mstat(dst, from_user) };
if (ret as isize) < 0 {
return Err(SystemError::from_posix_errno(-(ret as isize) as i32)
.expect("mstat: Invalid errno"));
}
if unlikely(len == 0) {
return Err(SystemError::EINVAL);
}
let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?;
let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
let start_frame = VirtPageFrame::new(start_vaddr);
let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
current_address_space
.write()
.mprotect(start_frame, page_count, prot_flags)
.map_err(|_| SystemError::EINVAL)?;
return Ok(0);
return Ok(ret);
}
}

File diff suppressed because it is too large Load Diff

109
kernel/src/mm/utils.c Normal file
View File

@ -0,0 +1,109 @@
#include "internal.h"
extern uint64_t mm_total_2M_pages;
/**
* @brief 获取指定虚拟地址处映射的物理地址
*
* @param mm 内存空间分布结构体
* @param vaddr 虚拟地址
* @return uint64_t 已映射的物理地址
*/
uint64_t __mm_get_paddr(struct mm_struct *mm, uint64_t vaddr)
{
ul *tmp;
tmp = phys_2_virt((ul *)(((ul)mm->pgd) & (~0xfffUL)) + ((vaddr >> PAGE_GDT_SHIFT) & 0x1ff));
// pml4页表项为0
if (*tmp == 0)
return 0;
tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((vaddr >> PAGE_1G_SHIFT) & 0x1ff));
// pdpt页表项为0
if (*tmp == 0)
return 0;
// 读取pdt页表项
tmp = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(vaddr) >> PAGE_2M_SHIFT) & 0x1ff)));
// pde页表项为0
if (*tmp == 0)
return 0;
if (*tmp & (1 << 7))
{
// 当前为2M物理页
return (*tmp) & (~0x1fffUL);
}
else
{
// 存在4级页表
tmp = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(vaddr) >> PAGE_4K_SHIFT) & 0x1ff)));
return (*tmp) & (~0x1ffUL);
}
}
/**
* @brief 检测指定地址是否已经被映射
*
* @param page_table_phys_addr 页表的物理地址
* @param virt_addr 要检测的地址
* @return true 已经被映射
* @return false
*/
bool mm_check_mapped(ul page_table_phys_addr, uint64_t virt_addr)
{
ul *tmp;
tmp = phys_2_virt((ul *)((ul)page_table_phys_addr & (~0xfffUL)) + ((virt_addr >> PAGE_GDT_SHIFT) & 0x1ff));
// pml4页表项为0
if (*tmp == 0)
return 0;
tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((virt_addr >> PAGE_1G_SHIFT) & 0x1ff));
// pdpt页表项为0
if (*tmp == 0)
return 0;
// 读取pdt页表项
tmp = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr) >> PAGE_2M_SHIFT) & 0x1ff)));
// pde页表项为0
if (*tmp == 0)
return 0;
if (*tmp & (1 << 7))
{
// 当前为2M物理页
return true;
}
else
{
// 存在4级页表
tmp = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr) >> PAGE_4K_SHIFT) & 0x1ff)));
if (*tmp != 0)
return true;
else
return false;
}
}
/**
* @brief 检测是否为有效的2M页(物理内存页)
*
* @param paddr 物理地址
* @return int8_t 是 -> 1
* 否 -> 0
*/
int8_t mm_is_2M_page(uint64_t paddr)
{
if (likely((paddr >> PAGE_2M_SHIFT) < mm_total_2M_pages))
return 1;
else
return 0;
}

275
kernel/src/mm/vma.c Normal file
View File

@ -0,0 +1,275 @@
#include "mm.h"
#include "slab.h"
#include "internal.h"
/**
* @brief 获取一块新的vma结构体并将其与指定的mm进行绑定
*
* @param mm 与VMA绑定的内存空间分布结构体
* @return struct vm_area_struct* 新的VMA
*/
struct vm_area_struct *vm_area_alloc(struct mm_struct *mm)
{
struct vm_area_struct *vma = (struct vm_area_struct *)kmalloc(sizeof(struct vm_area_struct), 0);
if (vma)
vma_init(vma, mm);
return vma;
}
/**
* @brief 从链表中删除指定的vma结构体
*
* @param vma
*/
void vm_area_del(struct vm_area_struct *vma)
{
if (vma->vm_mm == NULL)
return;
__vma_unlink_list(vma->vm_mm, vma);
}
/**
* @brief 释放vma结构体
*
* @param vma 待释放的vma结构体
*/
void vm_area_free(struct vm_area_struct *vma)
{
if (vma->vm_prev == NULL && vma->vm_next == NULL) // 如果当前是剩余的最后一个vma
vma->vm_mm->vmas = NULL;
kfree(vma);
}
/**
* @brief 将vma结构体插入mm_struct的链表之中
*
* @param mm 内存空间分布结构体
* @param vma 待插入的VMA结构体
* @param prev 链表的前一个结点
*/
void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev)
{
struct vm_area_struct *next = NULL;
vma->vm_prev = prev;
if (prev) // 若指定了前一个结点,则直接连接
{
next = prev->vm_next;
prev->vm_next = vma;
}
else // 否则将vma直接插入到给定的mm的vma链表之中
{
next = mm->vmas;
mm->vmas = vma;
}
vma->vm_next = next;
if (next != NULL)
next->vm_prev = vma;
}
/**
* @brief 将vma给定结构体从vma链表的结点之中删除
*
* @param mm 内存空间分布结构体
* @param vma 待插入的VMA结构体
*/
void __vma_unlink_list(struct mm_struct *mm, struct vm_area_struct *vma)
{
struct vm_area_struct *prev, *next;
next = vma->vm_next;
prev = vma->vm_prev;
if (prev)
prev->vm_next = next;
else // 当前vma是链表中的第一个vma
mm->vmas = next;
if (next)
next->vm_prev = prev;
}
/**
* @brief 查找第一个符合“addr < vm_end”条件的vma
*
* @param mm 内存空间分布结构体
* @param addr 虚拟地址
* @return struct vm_area_struct* 符合条件的vma
*/
struct vm_area_struct *vma_find(struct mm_struct *mm, uint64_t addr)
{
struct vm_area_struct *vma = mm->vmas;
struct vm_area_struct *result = NULL;
while (vma != NULL)
{
if (vma->vm_end > addr)
{
result = vma;
break;
}
vma = vma->vm_next;
}
return result;
}
/**
* @brief 插入vma
*
* @param mm
* @param vma
* @return int
*/
int vma_insert(struct mm_struct *mm, struct vm_area_struct *vma)
{
struct vm_area_struct *prev;
prev = vma_find(mm, vma->vm_start);
if (prev && prev->vm_start <= vma->vm_start && prev->vm_end >= vma->vm_end)
{
// 已经存在了相同的vma
return -EEXIST;
}
// todo: bugfix: 这里的第二种情况貌似从来不会满足
else if (prev && ((vma->vm_start >= prev->vm_start && vma->vm_start <= prev->vm_end) || (prev->vm_start <= vma->vm_end && prev->vm_start >= vma->vm_start)))
{
//部分重叠
if ((!CROSS_2M_BOUND(vma->vm_start, prev->vm_start)) && (!CROSS_2M_BOUND(vma->vm_end, prev->vm_end))&& vma->vm_end)
{
//合并vma 并改变链表vma的范围
kdebug("before combining vma:vm_start = %#018lx, vm_end = %#018lx\n", vma->vm_start, vma->vm_end);
prev->vm_start = (vma->vm_start < prev->vm_start )? vma->vm_start : prev->vm_start;
prev->vm_end = (vma->vm_end > prev->vm_end) ? vma->vm_end : prev->vm_end;
// 计算page_offset
prev->page_offset = prev->vm_start - (prev->vm_start & PAGE_2M_MASK);
kdebug("combined vma:vm_start = %#018lx, vm_end = %#018lx\nprev:vm_start = %018lx, vm_end = %018lx\n", vma->vm_start, vma->vm_end, prev->vm_start, prev->vm_end);
kinfo("vma has same part\n");
return __VMA_MERGED;
}
}
// prev = vma_find(mm, vma->vm_start);
if (prev == NULL) // 要将当前vma插入到链表的尾部
{
struct vm_area_struct *ptr = mm->vmas;
while (ptr)
{
if (ptr->vm_next)
ptr = ptr->vm_next;
else
{
prev = ptr;
break;
}
}
}
else
prev = prev->vm_prev;
__vma_link_list(mm, vma, prev);
return 0;
}
/**
* @brief 创建anon_vma并将其与页面结构体进行绑定
* 若提供的页面结构体指针为NULL则只创建不绑定
*
* @param page 页面结构体的指针
* @param lock_page 是否将页面结构体加锁
* @return struct anon_vma_t* 创建好的anon_vma
*/
struct anon_vma_t *__anon_vma_create_alloc(struct Page *page, bool lock_page)
{
struct anon_vma_t *anon_vma = (struct anon_vma_t *)kmalloc(sizeof(struct anon_vma_t), 0);
if (unlikely(anon_vma == NULL))
return NULL;
memset(anon_vma, 0, sizeof(struct anon_vma_t));
list_init(&anon_vma->vma_list);
semaphore_init(&anon_vma->sem, 1);
// 需要和page进行绑定
if (page != NULL)
{
if (lock_page == true) // 需要加锁
{
uint64_t rflags;
spin_lock(&page->op_lock);
page->anon_vma = anon_vma;
spin_unlock(&page->op_lock);
}
else
page->anon_vma = anon_vma;
anon_vma->page = page;
}
return anon_vma;
}
/**
* @brief 将指定的vma加入到anon_vma的管理范围之中
*
* @param anon_vma 页面的anon_vma
* @param vma 待加入的vma
* @return int 返回码
*/
int __anon_vma_add(struct anon_vma_t *anon_vma, struct vm_area_struct *vma)
{
semaphore_down(&anon_vma->sem);
list_add(&anon_vma->vma_list, &vma->anon_vma_list);
vma->anon_vma = anon_vma;
atomic_inc(&anon_vma->ref_count);
semaphore_up(&anon_vma->sem);
return 0;
}
/**
* @brief 释放anon vma结构体
*
* @param anon_vma 待释放的anon_vma结构体
* @return int 返回码
*/
int __anon_vma_free(struct anon_vma_t *anon_vma)
{
if (anon_vma->page != NULL)
{
spin_lock(&anon_vma->page->op_lock);
anon_vma->page->anon_vma = NULL;
spin_unlock(&anon_vma->page->op_lock);
}
kfree(anon_vma);
return 0;
}
/**
* @brief 从anon_vma的管理范围中删除指定的vma
* (在进入这个函数之前应该要对anon_vma加锁)
* @param vma 将要取消对应的anon_vma管理的vma结构体
* @return int 返回码
*/
int __anon_vma_del(struct vm_area_struct *vma)
{
// 当前vma没有绑定anon_vma
if (vma->anon_vma == NULL)
return -EINVAL;
list_del(&vma->anon_vma_list);
atomic_dec(&vma->anon_vma->ref_count);
// 若当前anon_vma的引用计数归零则意味着可以释放内存页
if (unlikely(atomic_read(&vma->anon_vma->ref_count) == 0)) // 应当释放该anon_vma
{
// 若页面结构体是mmio创建的则释放页面结构体
if (vma->anon_vma->page->attr & PAGE_DEVICE)
kfree(vma->anon_vma->page);
else
free_pages(vma->anon_vma->page, 1);
__anon_vma_free(vma->anon_vma);
}
// 清理当前vma的关联数据
vma->anon_vma = NULL;
list_init(&vma->anon_vma_list);
}