kernel_thread/task/
mem.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
//! 进程内存相关的模块
//!
//!
use alloc::{collections::btree_map::BTreeMap, vec::Vec};
use common::{config::PAGE_SIZE, page::PhysPage};
use core::cmp;

use crate::consts::task::{DEF_HEAP_ADDR, DEF_STACK_BOTTOM, DEF_STACK_TOP};

use super::Sel4Task;

pub struct TaskMemInfo {
    /// 已经映射的页表
    pub mapped_pt: Vec<sel4::cap::PT>,
    /// 已经映射的页
    pub mapped_page: BTreeMap<usize, PhysPage>,
    /// 堆地址,方便进行堆增长
    pub heap: usize,
}

impl Default for TaskMemInfo {
    fn default() -> Self {
        Self {
            mapped_pt: Default::default(),
            mapped_page: Default::default(),
            heap: DEF_HEAP_ADDR,
        }
    }
}

impl Sel4Task {
    /// 进行 brk 操作
    ///
    /// - `value` 是需要调整的堆地址
    ///
    /// ### 说明
    /// 如果 `value` 的值为 0,则返回当前的堆地址,否则就将堆扩展到指定的地址
    pub fn brk(&self, value: usize) -> usize {
        let mut mem_info = self.mem.lock();
        if value == 0 {
            return mem_info.heap;
        }
        let origin = mem_info.heap;
        mem_info.heap = value;
        drop(mem_info);
        for vaddr in (origin..value).step_by(PAGE_SIZE) {
            self.map_blank_page(vaddr);
        }
        value
    }

    /// 在当前任务 [Sel4Task] 的地址空间 [Sel4Task::vspace] 下读取特定地址的指令
    ///
    /// - `vaddr` 是需要读取指令的虚拟地址
    ///
    /// 说明:
    /// - 如果地址空间不存在或者地址未映射,返回 [Option::None]
    pub fn read_ins(&self, vaddr: usize) -> Option<u32> {
        self.mem
            .lock()
            .mapped_page
            .get(&(vaddr / PAGE_SIZE * PAGE_SIZE))
            .map(|page| {
                let offset = vaddr % PAGE_SIZE;
                let ins = page.lock()[offset..offset + 4].try_into().unwrap();
                u32::from_le_bytes(ins)
            })
    }

    /// 在当前任务 [Sel4Task] 的地址空间 [Sel4Task::vspace] 下读取特定地址的数据
    ///
    /// - `vaddr` 是需要读取数据的虚拟地址
    /// - `len`   是需要读取的数据长度
    ///
    /// 说明:
    /// - 如果地址空间不存在或者地址未映射,返回 [Option::None]
    pub fn read_bytes(&self, mut vaddr: usize, len: usize) -> Option<Vec<u8>> {
        self.check_addr(vaddr, len);

        let mut data = Vec::new();
        let mem_info = self.mem.lock();
        let vaddr_end = vaddr + len;
        while vaddr < vaddr_end {
            let page = mem_info.mapped_page.get(&(vaddr / PAGE_SIZE * PAGE_SIZE))?;
            let offset = vaddr % PAGE_SIZE;
            let rsize = cmp::min(PAGE_SIZE - offset, vaddr_end - vaddr);
            data.extend_from_slice(&page.lock()[offset..offset + rsize]);
            vaddr += rsize;
        }
        Some(data)
    }

    /// 在当前任务 [Sel4Task] 的地址空间 [Sel4Task::vspace] 下读取 C 语言的字符串信息,直到遇到 \0
    ///
    /// - `vaddr` 是需要读取数据的虚拟地址
    ///
    /// 说明:
    /// - 如果地址空间不存在或者地址未映射,返回 [Option::None]
    pub fn read_cstr(&self, mut vaddr: usize) -> Option<Vec<u8>> {
        let mut data = Vec::new();
        let mem_info = self.mem.lock();
        loop {
            let page = mem_info.mapped_page.get(&(vaddr / PAGE_SIZE * PAGE_SIZE))?;
            let offset = vaddr % PAGE_SIZE;
            let position = page.lock()[offset..].iter().position(|x| *x == 0);

            if let Some(position) = position {
                data.extend_from_slice(&page.lock()[offset..offset + position]);
                break;
            }
            data.extend_from_slice(&page.lock()[offset..]);
            vaddr += PAGE_SIZE - offset;
        }
        Some(data)
    }

    /// 在当前任务 [Sel4Task] 的地址空间 [Sel4Task::vspace] 下读取 C 语言的字符串信息,直到遇到 \0
    ///
    /// - `vaddr` 是需要读取数据的虚拟地址
    ///
    /// 说明:
    /// - 如果地址空间不存在或者地址未映射,返回 [Option::None]
    pub fn read_vec(&self, mut vaddr: usize) -> Option<Vec<usize>> {
        let mut data = Vec::new();
        let mem_info = self.mem.lock();
        loop {
            let page = mem_info.mapped_page.get(&(vaddr / PAGE_SIZE * PAGE_SIZE))?;
            let mut offset = vaddr % PAGE_SIZE;
            while offset < PAGE_SIZE {
                let value = page.lock().read_usize(offset);
                if value == 0 {
                    return Some(data);
                }
                offset += size_of::<usize>();
                data.push(value);
            }
            vaddr += PAGE_SIZE - offset;
        }
    }

    /// 在当前任务 [Sel4Task] 的地址空间 [Sel4Task::vspace] 下写入数据到特定地址
    ///
    /// - `vaddr` 是需要写入数据的虚拟地址
    /// - `data`  是需要写入的数据
    ///
    /// 说明:
    /// - 如果地址空间不存在或者地址未映射,返回 [Option::None]
    ///   TODO: 在写入之前检测所有的地址是否可以写入
    pub fn write_bytes(&self, mut vaddr: usize, data: &[u8]) -> Option<()> {
        let mem_info = self.mem.lock();
        let vaddr_end = vaddr + data.len();
        while vaddr < vaddr_end {
            let page = mem_info.mapped_page.get(&(vaddr / PAGE_SIZE * PAGE_SIZE))?;
            let offset = vaddr % PAGE_SIZE;
            let rsize = cmp::min(PAGE_SIZE - offset, vaddr_end - vaddr);
            page.lock()[offset..offset + rsize].copy_from_slice(&data[..rsize]);
            vaddr += rsize;
        }
        Some(())
    }

    /// 检测地址是否在栈上,如果在栈上且没有映射内存,那么直接映射内存
    ///
    /// # 参数
    /// - `vaddr` 需要检测内存的开始
    /// - `size`  需要检测内存的大小
    pub fn check_addr(&self, vaddr: usize, size: usize) {
        let bottom = vaddr / PAGE_SIZE * PAGE_SIZE;
        let top = (vaddr + size).div_ceil(PAGE_SIZE) * PAGE_SIZE;
        for vaddr in (bottom..top).step_by(PAGE_SIZE) {
            if self.mem.lock().mapped_page.contains_key(&vaddr) {
                continue;
            }
            if (DEF_STACK_BOTTOM..DEF_STACK_TOP).contains(&vaddr) {
                self.map_blank_page(vaddr);
            }
        }
    }

    /// 清理映射的内存
    ///
    /// 如果有已经映射的内存, 清理
    pub fn clear_maped(&self) {
        self.mem.lock().mapped_page.values().for_each(|x| {
            x.cap().frame_unmap().unwrap();
            // self.capset.lock().recycle_page(x.cap());
            let slot = sel4_kit::slot_manager::LeafSlot::from_cap(x.cap());
            slot.revoke().unwrap();
            slot.delete().unwrap();
            common::slot::recycle_slot(slot);
        });
        self.mem.lock().mapped_page.clear();
    }
}