在Cortex-M内核中,**特权级(Privileged)和非特权级(Unprivileged,也称用户级)**是重要的安全保护机制。以下是它们的详细差别:
1. 权限对比总览
2. 具体的权限差异
2.1 特殊寄存器访问
void demonstrate_register_access(void) {
// 以下操作在特权级可以,在非特权级会触发UsageFault:
// CONTROL寄存器(模式控制)
__set_CONTROL(0x3); // 非特权级:故障
// MSP/PSP切换
__set_MSP(stack_ptr); // 非特权级:故障
__set_PSP(stack_ptr); // 非特权级:故障
// 中断控制
__disable_irq(); // 非特权级:故障(CPSID I)
__enable_irq(); // 非特权级:故障(CPSIE I)
// 系统控制块
SCB->SHCSR = value; // 非特权级:故障
}
2.2 内存系统权限
void demonstrate_memory_access(void) {
// MPU(内存保护单元)配置
MPU->CTRL = 1; // 非特权级:故障
MPU->RNR = region; // 非特权级:故障
MPU->RBAR = address; // 非特权级:故障
// 内存访问限制
uint32_t system_data = *(uint32_t*)0xE0000000; // 可能被MPU阻止
// 外设访问可能被限制
GPIOA->MODER = value; // 可能被MPU阻止
}
3. 实际应用场景
场景1:操作系统中的权限分离
// 特权级代码(操作系统内核)
void privileged_kernel_function(void) {
// 可以配置MPU保护内存区域
setup_mpu_protection();
// 可以创建新任务
create_new_task(user_task_function, user_stack);
// 可以修改系统配置
configure_system_clock();
}
// 非特权级代码(用户应用程序)
void user_task_function(void) {
// 只能访问分配的内存区域
user_data* data = (user_data*)0x20001000; // 允许的RAM区域
// 不能修改系统设置
// SCB->ICSR = ...; // 这会触发UsageFault!
// 需要通过系统调用请求服务
make_system_call(SVC_OPEN_FILE, filename);
}
场景2:系统调用机制(SVC)
// 用户代码(非特权级)
void user_application(void) {
// 需要执行特权操作时,使用SVC
__asm volatile ("SVC #0x10"); // 请求文件打开服务
}
// SVC处理程序(自动提升到特权级)
void SVC_Handler(void) {
// 进入Handler模式,自动获得特权级
// 解析SVC编号并执行服务
uint8_t svc_number = get_svc_number();
switch(svc_number) {
case 0x10:
privileged_file_open(); // 执行实际的特权操作
break;
}
// 返回用户模式
}
4. 权限级别控制
CONTROL寄存器
void demonstrate_control_register(void) {
uint32_t control = __get_CONTROL();
// CONTROL[0]: 0=MSP, 1=PSP
// CONTROL[1]: 0=特权级, 1=非特权级
printf("当前权限: %s\n",
(control & 0x02) ? "非特权级" : "特权级");
printf("当前堆栈: %s\n",
(control & 0x01) ? "PSP" : "MSP");
}
权限切换示例
// 从特权级切换到非特权级
void switch_to_unprivileged(void) {
// 前提:当前是特权级
// 设置进程堆栈指针
__set_PSP(user_stack_top);
// 切换到非特权级 + PSP
__set_CONTROL(0x03); // Bit0=1(PSP), Bit1=1(非特权级)
// 必须使用ISB指令
__ISB();
// 现在运行在非特权级
// 不能再修改CONTROL、MSP等特殊寄存器
}
// 从非特权级返回特权级(只能通过异常)
void request_privileged_access(void) {
// 在非特权级中,只能通过SVC异常返回特权级
__asm volatile ("SVC #0x20");
}
5. 故障处理
非特权级访问违规
// UsageFault处理程序
void UsageFault_Handler(void) {
uint32_t cfsr = SCB->CFSR; // 配置故障状态寄存器
if (cfsr & (1 << 4)) { // STKERR: 堆栈操作违规
printf("非特权级堆栈访问违规!\n");
}
if (cfsr & (1 << 3)) { // UNSTKERR: 异常返回时堆栈违规
printf("异常返回堆栈违规!\n");
}
if (cfsr & (1 << 1)) { // UNDEFINSTR: 未定义指令
printf("执行了特权指令!\n");
}
// 处理故障...
while(1);
}
6. 实际工程应用
嵌入式操作系统设计
// 操作系统启动流程
void os_startup(void) {
// 1. 启动时是特权级(Thread模式 + MSP)
// 2. 初始化MPU,保护系统区域
mpu_init();
// 3. 创建用户任务
task_t* user_task = create_task(user_app, user_stack);
// 4. 切换到用户模式运行第一个任务
switch_to_user_task(user_task);
}
// 用户任务运行环境
void user_app(void) {
// 运行在:Thread模式 + PSP + 非特权级
while(1) {
// 应用程序逻辑
process_data();
// 需要系统服务时使用SVC
if (need_file_access) {
__asm volatile ("SVC #0x30");
}
}
}
安全检查函数
// 验证当前权限级别
bool is_privileged(void) {
uint32_t control = __get_CONTROL();
return ((control & 0x02) == 0);
}
// 安全执行特权操作
void safe_privileged_operation(void (*func)(void)) {
if (is_privileged()) {
func(); // 直接执行
} else {
// 非特权级:通过SVC调用
register void (*f)(void) asm("r0") = func;
__asm volatile ("SVC #0x40" : : "r" (f));
}
}
7. 总结
特权级的优势
完全系统访问权限
可以配置保护机制
适合操作系统内核、系统服务
非特权级的优势
提高系统安全性
防止应用程序破坏系统
支持多任务隔离
典型应用
特权级:操作系统内核、设备驱动、启动代码
非特权级:用户应用程序、第三方库、不信任的代码
这种权限分离机制是构建安全、稳定嵌入式系统的基础,特别是在运行复杂应用程序或使用第三方代码时尤为重要。
————————————————
版权声明:本文为CSDN博主「Just_BLei」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011764302/article/details/154021540
|
|