Skip to main content

tg_kernel_vm/space/
mod.rs

1mod mapper;
2mod visitor;
3
4extern crate alloc;
5
6use crate::PageManager;
7use alloc::vec::Vec;
8use core::{fmt, ops::Range, ptr::NonNull};
9use mapper::Mapper;
10use page_table::{PageTable, PageTableFormatter, Pos, VAddr, VmFlags, VmMeta, PPN, VPN};
11use visitor::Visitor;
12
13/// 地址空间。
14pub struct AddressSpace<Meta: VmMeta, M: PageManager<Meta>> {
15    /// 虚拟地址块(只记录已映射 VPN 区间,便于 clone/unmap 管理)
16    pub areas: Vec<Range<VPN<Meta>>>,
17    page_manager: M,
18}
19
20impl<Meta: VmMeta, M: PageManager<Meta>> AddressSpace<Meta, M> {
21    /// 创建新地址空间。
22    #[inline]
23    pub fn new() -> Self {
24        Self {
25            areas: Vec::new(),
26            page_manager: M::new_root(),
27        }
28    }
29
30    /// 地址空间根页表的物理页号。
31    #[inline]
32    pub fn root_ppn(&self) -> PPN<Meta> {
33        self.page_manager.root_ppn()
34    }
35
36    /// 地址空间根页表
37    #[inline]
38    pub fn root(&self) -> PageTable<Meta> {
39        // SAFETY: page_manager.root_ptr() 返回的是有效的根页表指针,
40        // 由 PageManager::new_root() 创建时保证其有效性
41        unsafe { PageTable::from_root(self.page_manager.root_ptr()) }
42    }
43
44    /// 向地址空间增加映射关系。
45    pub fn map_extern(&mut self, range: Range<VPN<Meta>>, pbase: PPN<Meta>, flags: VmFlags<Meta>) {
46        // map_extern 假设物理页已由外部准备好,此处只负责建立页表项。
47        self.areas.push(range.start..range.end);
48        let count = range.end.val() - range.start.val();
49        let mut root = self.root();
50        let mut mapper = Mapper::new(self, pbase..pbase + count, flags);
51        root.walk_mut(Pos::new(range.start, 0), &mut mapper);
52        if !mapper.ans() {
53            // 映射失败,需要回滚吗?
54            todo!()
55        }
56    }
57
58    /// 分配新的物理页,拷贝数据并建立映射。
59    pub fn map(
60        &mut self,
61        range: Range<VPN<Meta>>,
62        data: &[u8],
63        offset: usize,
64        mut flags: VmFlags<Meta>,
65    ) {
66        // map 的语义是“分配新物理页 + 拷贝初始数据 + 建立映射”。
67        let count = range.end.val() - range.start.val();
68        let size = count << Meta::PAGE_BITS;
69        assert!(size >= data.len() + offset);
70        let page = self.page_manager.allocate(count, &mut flags);
71        // SAFETY: page 是刚分配的有效内存,大小为 size 字节。
72        // 我们按顺序填充:[0, offset) 清零,[offset, offset+data.len()) 拷贝数据,
73        // [offset+data.len(), size) 清零。
74        unsafe {
75            use core::slice::from_raw_parts_mut as slice;
76            let mut ptr = page.as_ptr();
77            slice(ptr, offset).fill(0);
78            ptr = ptr.add(offset);
79            slice(ptr, data.len()).copy_from_slice(data);
80            ptr = ptr.add(data.len());
81            slice(ptr, page.as_ptr().add(size).offset_from(ptr) as _).fill(0);
82        }
83        self.map_extern(range, self.page_manager.v_to_p(page), flags)
84    }
85
86    /// 取消指定 VPN 范围的映射
87    pub fn unmap(&mut self, range: Range<VPN<Meta>>) {
88        // 教学提醒:这里主要做“撤销页表映射”,并未回收物理页到分配器。
89        // 若课程实验需要严格回收,可在此基础上补充 deallocate 路径。
90        // 从 areas 中移除该范围(可能需要拆分现有区域)
91        let mut new_areas = Vec::new();
92        for area in self.areas.drain(..) {
93            if area.end <= range.start || area.start >= range.end {
94                // 不重叠,保留原区域
95                new_areas.push(area);
96            } else {
97                // 有重叠,需要拆分
98                if area.start < range.start {
99                    new_areas.push(area.start..range.start);
100                }
101                if area.end > range.end {
102                    new_areas.push(range.end..area.end);
103                }
104            }
105        }
106        self.areas = new_areas;
107
108        // 清除页表项(将 PTE 设为无效,即写入 0)
109        let mut vpn = range.start;
110        while vpn < range.end {
111            // 使用 visitor 找到 PTE 并清除
112            if let Some(pte_ptr) = self.find_pte_mut(vpn) {
113                unsafe {
114                    core::ptr::write_bytes(
115                        pte_ptr as *mut u8,
116                        0,
117                        core::mem::size_of::<page_table::Pte<Meta>>(),
118                    )
119                };
120            }
121            vpn = vpn + 1;
122        }
123
124        // 刷新地址空间
125        #[cfg(target_arch = "riscv64")]
126        unsafe {
127            core::arch::asm!("sfence.vma")
128        };
129    }
130
131    /// 查找指定 VPN 的 PTE 指针(用于修改)
132    fn find_pte_mut(&self, vpn: VPN<Meta>) -> Option<*mut page_table::Pte<Meta>> {
133        let mut current = self.page_manager.root_ptr();
134
135        for level in (0..=Meta::MAX_LEVEL).rev() {
136            let idx = vpn.index_in(level);
137            let pte_ptr = unsafe { current.as_ptr().add(idx) };
138            let pte = unsafe { *pte_ptr };
139
140            if level == 0 {
141                return Some(pte_ptr);
142            }
143
144            if !pte.is_valid() {
145                return None;
146            }
147
148            // 如果是叶子节点(大页),也返回
149            // 检查 R 或 X 位来判断是否是叶子节点
150            let flags_raw = pte.flags().val();
151            let is_leaf = (flags_raw & 0b1010) != 0; // R=bit1, X=bit3
152            if is_leaf {
153                return Some(pte_ptr);
154            }
155
156            current = self.page_manager.p_to_v(pte.ppn());
157        }
158        None
159    }
160
161    /// 检查 `flags` 的属性要求,然后将地址空间中的一个虚地址翻译成当前地址空间中的指针。
162    pub fn translate<T>(&self, addr: VAddr<Meta>, flags: VmFlags<Meta>) -> Option<NonNull<T>> {
163        let mut visitor = Visitor::new(self);
164        self.root().walk(Pos::new(addr.floor(), 0), &mut visitor);
165        visitor
166            .ans()
167            .filter(|pte| pte.flags().contains(flags))
168            .map(|pte| {
169                // SAFETY: pte 是有效的页表项,ppn 对应有效的物理页。
170                // p_to_v 返回当前地址空间中的有效指针。
171                // add(addr.offset()) 计算页内偏移,不会越界(offset < PAGE_SIZE)。
172                // 使用 new_unchecked 是因为 p_to_v 返回的是 NonNull,不可能为空。
173                unsafe {
174                    NonNull::new_unchecked(
175                        self.page_manager
176                            .p_to_v::<u8>(pte.ppn())
177                            .as_ptr()
178                            .add(addr.offset())
179                            .cast(),
180                    )
181                }
182            })
183    }
184
185    /// 遍历地址空间,将其中的地址映射添加进自己的地址空间中,重新分配物理页并拷贝所有数据及代码
186    pub fn cloneself(&self, new_addrspace: &mut AddressSpace<Meta, M>) {
187        // 这是“深拷贝地址空间”语义,不共享物理页(非 COW)。
188        let root = self.root();
189        let areas = &self.areas;
190        for (_, range) in areas.iter().enumerate() {
191            let mut visitor = Visitor::new(self);
192            // 虚拟地址块的首地址的 vpn
193            let vpn = range.start;
194            // 利用 visitor 访问页表,并获取这个虚拟地址块的页属性
195            root.walk(Pos::new(vpn, 0), &mut visitor);
196            // 利用 visitor 获取这个虚拟地址块的页属性,以及起始地址
197            let (mut flags, mut data_ptr) = visitor
198                .ans()
199                .filter(|pte| pte.is_valid())
200                .map(|pte| {
201                    // SAFETY: pte 是有效的页表项,p_to_v 返回有效的指针
202                    (pte.flags(), unsafe {
203                        NonNull::new_unchecked(self.page_manager.p_to_v::<u8>(pte.ppn()).as_ptr())
204                    })
205                })
206                .unwrap();
207            let vpn_range = range.start..range.end;
208            // 虚拟地址块中页数量
209            let count = range.end.val() - range.start.val();
210            let size = count << Meta::PAGE_BITS;
211            // 分配 count 个 flags 属性的物理页面
212            let paddr = new_addrspace.page_manager.allocate(count, &mut flags);
213            let ppn = new_addrspace.page_manager.v_to_p(paddr);
214            // SAFETY: data_ptr 指向源地址空间中 size 字节的有效数据,
215            // paddr 指向新分配的 size 字节内存,两者不重叠
216            unsafe {
217                use core::slice::from_raw_parts_mut as slice;
218                let data = slice(data_ptr.as_mut(), size);
219                let ptr = paddr.as_ptr();
220                slice(ptr, size).copy_from_slice(data);
221            }
222            new_addrspace.map_extern(vpn_range, ppn, flags);
223        }
224    }
225}
226
227impl<Meta: VmMeta, P: PageManager<Meta>> fmt::Debug for AddressSpace<Meta, P> {
228    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229        writeln!(f, "root: {:#x}", self.root_ppn().val())?;
230        write!(
231            f,
232            "{:?}",
233            PageTableFormatter {
234                pt: self.root(),
235                f: |ppn| self.page_manager.p_to_v(ppn)
236            }
237        )
238    }
239}