mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-16 05:46:48 +00:00
feat: debug kernel stack (#1176)
* feat: debug kernel stack Signed-off-by: Godones <chenlinfeng25@outlook.com> * fix: Create guard pages for the kstack through remap Signed-off-by: Godones <chenlinfeng25@outlook.com> * feat(arch/x86_64): 启用内核态写保护功能 添加enable_kernel_wp函数来设置CR0的WP位,防止内核错误写入只读页面 Signed-off-by: longjin <longjin@DragonOS.org> * fix(x86_64/mm): 在内核地址错误处理中添加RIP寄存器信息 Signed-off-by: longjin <longjin@DragonOS.org> * fix: Fixed the error introduced by enabling WP flag on x86 Restore accidentally deleted functions. Signed-off-by: Godones <chenlinfeng25@outlook.com> * refactor: 移除kstack_protect默认特性并优化内存管理 - 从default特性中移除kstack_protect - 为X86_64MMBootstrapInfo添加kernel_rodata_start字段 - 调整内核页标志对rodata区域的判断逻辑 Signed-off-by: longjin <longjin@DragonOS.org> * fix(mm): 解决加载二进制文件到用户空间的时候,忘记关闭wp的问题 Signed-off-by: longjin <longjin@DragonOS.org> * fix Signed-off-by: longjin <longjin@DragonOS.org> --------- Signed-off-by: Godones <chenlinfeng25@outlook.com> Signed-off-by: longjin <longjin@DragonOS.org> Co-authored-by: longjin <longjin@DragonOS.org>
This commit is contained in:
parent
bb79f7fe3c
commit
799e573259
@ -25,6 +25,9 @@ driver_ps2_mouse = []
|
||||
kprobe_test = []
|
||||
static_keys_test = []
|
||||
|
||||
# kstack_protect 开启该功能后,会开启内核栈保护功能。用于辅助检测栈溢出。(内核栈占用会*2)
|
||||
kstack_protect = []
|
||||
|
||||
# 运行时依赖项
|
||||
[dependencies]
|
||||
acpi = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/acpi-rs.git", rev = "282df2af7b" }
|
||||
@ -79,7 +82,9 @@ static-keys = { version = "=0.7" }
|
||||
|
||||
defer = "0.2.1"
|
||||
cfg-if = { version = "1.0.0" }
|
||||
derive_builder = { version = "0.20.2", default-features = false, features = ["alloc"] }
|
||||
derive_builder = { version = "0.20.2", default-features = false, features = [
|
||||
"alloc",
|
||||
] }
|
||||
|
||||
|
||||
# target为x86_64时,使用下面的依赖
|
||||
|
@ -137,6 +137,10 @@ impl MemoryManagementArch for LoongArch64MMArch {
|
||||
fn make_entry(paddr: crate::mm::PhysAddr, page_flags: usize) -> usize {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn enable_kernel_wp() {}
|
||||
|
||||
fn disable_kernel_wp() {}
|
||||
}
|
||||
|
||||
/// 获取内核地址默认的页面标志
|
||||
|
@ -284,6 +284,10 @@ impl MemoryManagementArch for RiscV64MMArch {
|
||||
const PAGE_READONLY_EXEC: usize = 0;
|
||||
|
||||
const PROTECTION_MAP: [EntryFlags<MMArch>; 16] = protection_map();
|
||||
|
||||
fn enable_kernel_wp() {}
|
||||
|
||||
fn disable_kernel_wp() {}
|
||||
}
|
||||
|
||||
const fn protection_map() -> [EntryFlags<MMArch>; 16] {
|
||||
|
@ -149,18 +149,37 @@ impl X86_64MMArch {
|
||||
/// - `error_code`: 错误标志
|
||||
/// - `address`: 发生缺页异常的虚拟地址
|
||||
pub fn do_kern_addr_fault(
|
||||
_regs: &'static TrapFrame,
|
||||
regs: &'static TrapFrame,
|
||||
error_code: X86PfErrorCode,
|
||||
address: VirtAddr,
|
||||
) {
|
||||
unsafe { crate::debug::traceback::lookup_kallsyms(regs.rip, 0xff) };
|
||||
let pcb = crate::process::ProcessManager::current_pcb();
|
||||
let kstack_guard_addr = pcb.kernel_stack().guard_page_address();
|
||||
if let Some(guard_page) = kstack_guard_addr {
|
||||
let guard_page_size = pcb.kernel_stack().guard_page_size().unwrap();
|
||||
if address.data() >= guard_page.data()
|
||||
&& address.data() < guard_page.data() + guard_page_size
|
||||
{
|
||||
// 发生在内核栈保护页上
|
||||
error!(
|
||||
"kernel stack guard page fault at {:#x}, guard page range: {:#x} - {:#x}",
|
||||
address.data(),
|
||||
guard_page.data(),
|
||||
guard_page.data() + guard_page_size
|
||||
);
|
||||
}
|
||||
}
|
||||
panic!(
|
||||
"do_kern_addr_fault has not yet been implemented,
|
||||
fault address: {:#x},
|
||||
fault address: {:#x},
|
||||
rip: {:#x},
|
||||
error_code: {:#b},
|
||||
pid: {}\n",
|
||||
address.data(),
|
||||
regs.rip,
|
||||
error_code,
|
||||
crate::process::ProcessManager::current_pid().data()
|
||||
pcb.pid().data()
|
||||
);
|
||||
//TODO https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/mm/fault.c#do_kern_addr_fault
|
||||
}
|
||||
|
@ -42,12 +42,14 @@ static mut INITIAL_CR3_VALUE: PhysAddr = PhysAddr::new(0);
|
||||
|
||||
static INNER_ALLOCATOR: SpinLock<Option<BuddyAllocator<MMArch>>> = SpinLock::new(None);
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct X86_64MMBootstrapInfo {
|
||||
kernel_load_base_paddr: usize,
|
||||
kernel_code_start: usize,
|
||||
kernel_code_end: usize,
|
||||
kernel_data_end: usize,
|
||||
kernel_rodata_start: usize,
|
||||
kernel_rodata_end: usize,
|
||||
start_brk: usize,
|
||||
}
|
||||
@ -134,6 +136,7 @@ impl MemoryManagementArch for X86_64MMArch {
|
||||
fn _text();
|
||||
fn _etext();
|
||||
fn _edata();
|
||||
fn _rodata();
|
||||
fn _erodata();
|
||||
fn _end();
|
||||
fn _default_kernel_load_base();
|
||||
@ -146,6 +149,7 @@ impl MemoryManagementArch for X86_64MMArch {
|
||||
kernel_code_start: _text as usize,
|
||||
kernel_code_end: _etext as usize,
|
||||
kernel_data_end: _edata as usize,
|
||||
kernel_rodata_start: _rodata as usize,
|
||||
kernel_rodata_end: _erodata as usize,
|
||||
start_brk: _end as usize,
|
||||
};
|
||||
@ -158,15 +162,14 @@ impl MemoryManagementArch for X86_64MMArch {
|
||||
boot_callbacks()
|
||||
.early_init_memory_blocks()
|
||||
.expect("init memory area failed");
|
||||
|
||||
debug!("bootstrap info: {:?}", unsafe { BOOTSTRAP_MM_INFO });
|
||||
debug!("bootstrap info: {:#x?}", unsafe { BOOTSTRAP_MM_INFO });
|
||||
debug!("phys[0]=virt[0x{:x}]", unsafe {
|
||||
MMArch::phys_2_virt(PhysAddr::new(0)).unwrap().data()
|
||||
});
|
||||
|
||||
// 初始化内存管理器
|
||||
unsafe { allocator_init() };
|
||||
|
||||
Self::enable_kernel_wp();
|
||||
send_to_default_serial8250_port("x86 64 mm init done\n\0".as_bytes());
|
||||
}
|
||||
|
||||
@ -366,10 +369,35 @@ impl MemoryManagementArch for X86_64MMArch {
|
||||
const PAGE_WRITE: usize = 0;
|
||||
const PAGE_WRITE_EXEC: usize = 0;
|
||||
const PAGE_EXEC: usize = 0;
|
||||
|
||||
/// 启用 内核态的 Write Protect
|
||||
/// 这样即使在内核态,CPU也会检查页面的写保护位
|
||||
/// 防止内核错误地写入只读页面
|
||||
fn enable_kernel_wp() {
|
||||
unsafe {
|
||||
use x86::controlregs::{cr0, cr0_write, Cr0};
|
||||
let mut cr0_val = cr0();
|
||||
cr0_val.insert(Cr0::CR0_WRITE_PROTECT);
|
||||
cr0_write(cr0_val);
|
||||
// log::debug!("CR0.WP bit enabled for kernel write protection");
|
||||
}
|
||||
}
|
||||
|
||||
/// 禁用 内核态的 Write Protect
|
||||
fn disable_kernel_wp() {
|
||||
unsafe {
|
||||
use x86::controlregs::{cr0, cr0_write, Cr0};
|
||||
let mut cr0_val = cr0();
|
||||
cr0_val.remove(Cr0::CR0_WRITE_PROTECT);
|
||||
cr0_write(cr0_val);
|
||||
// log::debug!("CR0.WP bit disabled for kernel write protection");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取保护标志的映射表
|
||||
///
|
||||
/// 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/mm/pgprot.c#8
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - `[usize; 16]`: 长度为16的映射表
|
||||
@ -681,7 +709,7 @@ pub unsafe fn kernel_page_flags<A: MemoryManagementArch>(virt: VirtAddr) -> Entr
|
||||
if virt.data() >= info.kernel_code_start && virt.data() < info.kernel_code_end {
|
||||
// Remap kernel code execute
|
||||
return EntryFlags::new().set_execute(true).set_write(true);
|
||||
} else if virt.data() >= info.kernel_data_end && virt.data() < info.kernel_rodata_end {
|
||||
} else if virt.data() >= info.kernel_rodata_start && virt.data() < info.kernel_rodata_end {
|
||||
// Remap kernel rodata read only
|
||||
return EntryFlags::new().set_execute(true);
|
||||
} else {
|
||||
|
@ -347,6 +347,7 @@ impl KernelCmdlineManager {
|
||||
log::warn!("cmdline: parameter {} is set twice", p.name);
|
||||
continue;
|
||||
}
|
||||
|
||||
p.value = Some(CString::new(value.unwrap()).unwrap());
|
||||
p.initialized = true;
|
||||
}
|
||||
|
@ -220,7 +220,10 @@ impl ElfLoader {
|
||||
map_flags: &MapFlags,
|
||||
total_size: usize,
|
||||
) -> Result<(VirtAddr, bool), SystemError> {
|
||||
// debug!("load_elf_segment: addr_to_map={:?}", addr_to_map);
|
||||
// log::debug!("load_elf_segment: addr_to_map={:?}", addr_to_map);
|
||||
// defer!({
|
||||
// log::debug!("load_elf_segment done");
|
||||
// });
|
||||
|
||||
// 映射位置的偏移量(页内偏移)
|
||||
let beginning_page_offset = Self::elf_page_offset(addr_to_map);
|
||||
@ -343,6 +346,9 @@ impl ElfLoader {
|
||||
load_bias: usize,
|
||||
) -> Result<BinaryLoaderResult, ExecError> {
|
||||
// log::debug!("loading elf interp");
|
||||
// defer!({
|
||||
// log::debug!("load_elf_interp done");
|
||||
// });
|
||||
let mut head_buf = [0u8; 512];
|
||||
interp_elf_ex
|
||||
.file_mut()
|
||||
|
@ -653,50 +653,8 @@ impl MMIOSpaceGuard {
|
||||
/// 传入的物理地址【一定要是设备的物理地址】。
|
||||
/// 如果物理地址是从内存分配器中分配的,那么会造成内存泄露。因为mmio_release的时候,只取消映射,不会释放内存。
|
||||
pub unsafe fn map_phys(&self, paddr: PhysAddr, length: usize) -> Result<(), SystemError> {
|
||||
if length > self.size {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let check = self
|
||||
.mapped
|
||||
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst);
|
||||
if check.is_err() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let flags = EntryFlags::mmio_flags();
|
||||
|
||||
let mut kernel_mapper = KernelMapper::lock();
|
||||
let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true);
|
||||
return r;
|
||||
}
|
||||
|
||||
/// 将物理地址填写到虚拟地址空间中
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// 传入的物理地址【一定要是设备的物理地址】。
|
||||
/// 如果物理地址是从内存分配器中分配的,那么会造成内存泄露。因为mmio_release的时候,只取消映射,不会释放内存。
|
||||
pub unsafe fn map_phys_with_flags(
|
||||
&self,
|
||||
paddr: PhysAddr,
|
||||
length: usize,
|
||||
flags: EntryFlags<MMArch>,
|
||||
) -> Result<(), SystemError> {
|
||||
if length > self.size {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let check = self
|
||||
.mapped
|
||||
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst);
|
||||
if check.is_err() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let mut kernel_mapper = KernelMapper::lock();
|
||||
let r = kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true);
|
||||
return r;
|
||||
self.map_phys_with_flags(paddr, length, flags)
|
||||
}
|
||||
|
||||
/// # map_any_phys - 将任意物理地址映射到虚拟地址
|
||||
@ -734,6 +692,33 @@ impl MMIOSpaceGuard {
|
||||
return Ok(vaddr);
|
||||
}
|
||||
|
||||
/// 将物理地址填写到虚拟地址空间中
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// 传入的物理地址【一定要是设备的物理地址】。
|
||||
/// 如果物理地址是从内存分配器中分配的,那么会造成内存泄露。因为mmio_release的时候,只取消映射,不会释放内存。
|
||||
pub unsafe fn map_phys_with_flags(
|
||||
&self,
|
||||
paddr: PhysAddr,
|
||||
length: usize,
|
||||
flags: EntryFlags<MMArch>,
|
||||
) -> Result<(), SystemError> {
|
||||
if length > self.size {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let check = self
|
||||
.mapped
|
||||
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst);
|
||||
if check.is_err() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let mut kernel_mapper = KernelMapper::lock();
|
||||
kernel_mapper.map_phys_with_size(self.vaddr, paddr, length, flags, true)
|
||||
}
|
||||
|
||||
/// 泄露一个MMIO space guard,不会释放映射的空间
|
||||
pub unsafe fn leak(self) {
|
||||
core::mem::forget(self);
|
||||
|
@ -694,6 +694,14 @@ pub trait MemoryManagementArch: Clone + Copy + Debug {
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
/// 启用 内核态的 Write Protect
|
||||
/// 这样即使在内核态,CPU也会检查页面的写保护位
|
||||
/// 防止内核错误地写入只读页面
|
||||
fn enable_kernel_wp();
|
||||
|
||||
/// 禁用 内核态的 Write Protect
|
||||
fn disable_kernel_wp();
|
||||
}
|
||||
|
||||
/// @brief 虚拟地址范围
|
||||
|
@ -26,7 +26,7 @@ pub fn do_execve(
|
||||
}
|
||||
})?;
|
||||
|
||||
// debug!("load binary file done");
|
||||
// log::debug!("load binary file done");
|
||||
// debug!("argv: {:?}, envp: {:?}", argv, envp);
|
||||
param.init_info_mut().args = argv;
|
||||
param.init_info_mut().envs = envp;
|
||||
|
@ -54,7 +54,7 @@ use crate::{
|
||||
percpu::{PerCpu, PerCpuVar},
|
||||
set_IDLE_PROCESS_ADDRESS_SPACE,
|
||||
ucontext::AddressSpace,
|
||||
VirtAddr,
|
||||
PhysAddr, VirtAddr,
|
||||
},
|
||||
namespaces::{mnt_namespace::FsStruct, pid_namespace::PidStrcut, NsProxy},
|
||||
net::socket::SocketInode,
|
||||
@ -1596,24 +1596,143 @@ impl ProcessSchedulerInfo {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct KernelStack {
|
||||
stack: Option<AlignedBox<[u8; KernelStack::SIZE], { KernelStack::ALIGN }>>,
|
||||
/// 标记该内核栈是否可以被释放
|
||||
can_be_freed: bool,
|
||||
ty: KernelStackType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum KernelStackType {
|
||||
KernelSpace(VirtAddr, PhysAddr),
|
||||
Static,
|
||||
Dynamic,
|
||||
}
|
||||
|
||||
// 为什么需要这个锁?
|
||||
// alloc_from_kernel_space 使用该函数分配内核栈时,如果该函数被中断打断,
|
||||
// 而切换的任务使用dealloc_from_kernel_space回收内核栈,对
|
||||
// KernelMapper的可变引用获取将会失败造成错误
|
||||
static KSTACK_LOCK: SpinLock<()> = SpinLock::new(());
|
||||
|
||||
unsafe fn alloc_from_kernel_space() -> (VirtAddr, PhysAddr) {
|
||||
use crate::arch::MMArch;
|
||||
use crate::mm::allocator::page_frame::{allocate_page_frames, PageFrameCount};
|
||||
use crate::mm::kernel_mapper::KernelMapper;
|
||||
use crate::mm::page::EntryFlags;
|
||||
use crate::mm::MemoryManagementArch;
|
||||
|
||||
// Layout
|
||||
// ---------------
|
||||
// | KernelStack |
|
||||
// | guard page | size == KernelStack::SIZE
|
||||
// | KernelStack |
|
||||
// | guard page |
|
||||
// | .......... |
|
||||
// ---------------
|
||||
|
||||
let _guard = KSTACK_LOCK.try_lock_irqsave().unwrap();
|
||||
let need_size = KernelStack::SIZE * 2;
|
||||
let page_num = PageFrameCount::new(need_size.div_ceil(MMArch::PAGE_SIZE).next_power_of_two());
|
||||
|
||||
let (paddr, _count) = allocate_page_frames(page_num).expect("kernel stack alloc failed");
|
||||
|
||||
let guard_vaddr = MMArch::phys_2_virt(paddr).unwrap();
|
||||
let _kstack_paddr = paddr + KernelStack::SIZE;
|
||||
let kstack_vaddr = guard_vaddr + KernelStack::SIZE;
|
||||
|
||||
core::ptr::write_bytes(kstack_vaddr.data() as *mut u8, 0, KernelStack::SIZE);
|
||||
|
||||
let guard_flags = EntryFlags::new();
|
||||
|
||||
let mut kernel_mapper = KernelMapper::lock();
|
||||
let kernel_mapper = kernel_mapper.as_mut().unwrap();
|
||||
|
||||
for i in 0..KernelStack::SIZE / MMArch::PAGE_SIZE {
|
||||
let guard_page_vaddr = guard_vaddr + i * MMArch::PAGE_SIZE;
|
||||
// Map the guard page
|
||||
let flusher = kernel_mapper.remap(guard_page_vaddr, guard_flags).unwrap();
|
||||
flusher.flush();
|
||||
}
|
||||
|
||||
// unsafe {
|
||||
// log::debug!(
|
||||
// "trigger kernel stack guard page :{:#x}",
|
||||
// (kstack_vaddr.data() - 8)
|
||||
// );
|
||||
// let guard_ptr = (kstack_vaddr.data() - 8) as *mut usize;
|
||||
// guard_ptr.write(0xfff); // Invalid
|
||||
// }
|
||||
|
||||
// log::info!(
|
||||
// "[kernel stack alloc]: virt: {:#x}, phy: {:#x}",
|
||||
// kstack_vaddr.data(),
|
||||
// _kstack_paddr.data()
|
||||
// );
|
||||
(guard_vaddr, paddr)
|
||||
}
|
||||
|
||||
unsafe fn dealloc_from_kernel_space(vaddr: VirtAddr, paddr: PhysAddr) {
|
||||
use crate::arch::mm::kernel_page_flags;
|
||||
use crate::arch::MMArch;
|
||||
use crate::mm::allocator::page_frame::{deallocate_page_frames, PageFrameCount, PhysPageFrame};
|
||||
use crate::mm::kernel_mapper::KernelMapper;
|
||||
use crate::mm::MemoryManagementArch;
|
||||
|
||||
let _guard = KSTACK_LOCK.try_lock_irqsave().unwrap();
|
||||
|
||||
let need_size = KernelStack::SIZE * 2;
|
||||
let page_num = PageFrameCount::new(need_size.div_ceil(MMArch::PAGE_SIZE).next_power_of_two());
|
||||
|
||||
// log::info!(
|
||||
// "[kernel stack dealloc]: virt: {:#x}, phy: {:#x}",
|
||||
// vaddr.data(),
|
||||
// paddr.data()
|
||||
// );
|
||||
|
||||
let mut kernel_mapper = KernelMapper::lock();
|
||||
let kernel_mapper = kernel_mapper.as_mut().unwrap();
|
||||
|
||||
// restore the guard page flags
|
||||
for i in 0..KernelStack::SIZE / MMArch::PAGE_SIZE {
|
||||
let guard_page_vaddr = vaddr + i * MMArch::PAGE_SIZE;
|
||||
let flusher = kernel_mapper
|
||||
.remap(guard_page_vaddr, kernel_page_flags(vaddr))
|
||||
.unwrap();
|
||||
flusher.flush();
|
||||
}
|
||||
|
||||
// release the physical page
|
||||
unsafe { deallocate_page_frames(PhysPageFrame::new(paddr), page_num) };
|
||||
}
|
||||
|
||||
impl KernelStack {
|
||||
pub const SIZE: usize = 0x8000;
|
||||
pub const ALIGN: usize = 0x8000;
|
||||
pub const SIZE: usize = 0x4000;
|
||||
pub const ALIGN: usize = 0x4000;
|
||||
|
||||
pub fn new() -> Result<Self, SystemError> {
|
||||
return Ok(Self {
|
||||
stack: Some(
|
||||
AlignedBox::<[u8; KernelStack::SIZE], { KernelStack::ALIGN }>::new_zeroed()?,
|
||||
),
|
||||
can_be_freed: true,
|
||||
});
|
||||
if cfg!(feature = "kstack_protect") {
|
||||
unsafe {
|
||||
let (kstack_vaddr, kstack_paddr) = alloc_from_kernel_space();
|
||||
let real_kstack_vaddr = kstack_vaddr + KernelStack::SIZE;
|
||||
Ok(Self {
|
||||
stack: Some(
|
||||
AlignedBox::<[u8; KernelStack::SIZE], { KernelStack::ALIGN }>::new_unchecked(
|
||||
real_kstack_vaddr.data() as *mut [u8; KernelStack::SIZE],
|
||||
),
|
||||
),
|
||||
ty: KernelStackType::KernelSpace(kstack_vaddr, kstack_paddr),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Ok(Self {
|
||||
stack: Some(
|
||||
AlignedBox::<[u8; KernelStack::SIZE], { KernelStack::ALIGN }>::new_zeroed()?,
|
||||
),
|
||||
ty: KernelStackType::Dynamic,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// 根据已有的空间,构造一个内核栈结构体
|
||||
@ -1624,14 +1743,38 @@ impl KernelStack {
|
||||
return Err(SystemError::EFAULT);
|
||||
}
|
||||
|
||||
return Ok(Self {
|
||||
Ok(Self {
|
||||
stack: Some(
|
||||
AlignedBox::<[u8; KernelStack::SIZE], { KernelStack::ALIGN }>::new_unchecked(
|
||||
base.data() as *mut [u8; KernelStack::SIZE],
|
||||
),
|
||||
),
|
||||
can_be_freed: false,
|
||||
});
|
||||
ty: KernelStackType::Static,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn guard_page_address(&self) -> Option<VirtAddr> {
|
||||
match self.ty {
|
||||
KernelStackType::KernelSpace(kstack_virt_addr, _) => {
|
||||
return Some(kstack_virt_addr);
|
||||
}
|
||||
_ => {
|
||||
// 静态内核栈和动态内核栈没有guard page
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn guard_page_size(&self) -> Option<usize> {
|
||||
match self.ty {
|
||||
KernelStackType::KernelSpace(_, _) => {
|
||||
return Some(KernelStack::SIZE);
|
||||
}
|
||||
_ => {
|
||||
// 静态内核栈和动态内核栈没有guard page
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 返回内核栈的起始虚拟地址(低地址)
|
||||
@ -1708,10 +1851,20 @@ impl Drop for KernelStack {
|
||||
drop(pcb_ptr);
|
||||
}
|
||||
}
|
||||
// 如果该内核栈不可以被释放,那么,这里就forget,不调用AlignedBox的drop函数
|
||||
if !self.can_be_freed {
|
||||
let bx = self.stack.take();
|
||||
core::mem::forget(bx);
|
||||
match self.ty {
|
||||
KernelStackType::KernelSpace(kstack_virt_addr, kstack_phy_addr) => {
|
||||
// 释放内核栈
|
||||
unsafe {
|
||||
dealloc_from_kernel_space(kstack_virt_addr, kstack_phy_addr);
|
||||
}
|
||||
let bx = self.stack.take();
|
||||
core::mem::forget(bx);
|
||||
}
|
||||
KernelStackType::Static => {
|
||||
let bx = self.stack.take();
|
||||
core::mem::forget(bx);
|
||||
}
|
||||
KernelStackType::Dynamic => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,12 @@ use core::{
|
||||
};
|
||||
|
||||
use alloc::{ffi::CString, vec::Vec};
|
||||
use defer::defer;
|
||||
|
||||
use crate::mm::{verify_area, VirtAddr};
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
mm::{verify_area, MemoryManagementArch, VirtAddr},
|
||||
};
|
||||
|
||||
use super::SystemError;
|
||||
|
||||
@ -37,6 +41,10 @@ pub unsafe fn clear_user(dest: VirtAddr, len: usize) -> Result<usize, SystemErro
|
||||
|
||||
pub unsafe fn copy_to_user(dest: VirtAddr, src: &[u8]) -> Result<usize, SystemError> {
|
||||
verify_area(dest, src.len()).map_err(|_| SystemError::EFAULT)?;
|
||||
MMArch::disable_kernel_wp();
|
||||
defer!({
|
||||
MMArch::enable_kernel_wp();
|
||||
});
|
||||
|
||||
let p = dest.data() as *mut u8;
|
||||
// 拷贝数据
|
||||
|
Loading…
x
Reference in New Issue
Block a user