在 Cortex-M3 裸机工程里,MPU 的难点通常不在寄存器,而在链接布局。
MPU 只能保护按规则对齐的连续内存区域。如果用户代码、用户数据、共享数据和特权数据在链接阶段混在一起,运行时再配置 MPU,也无法做到细粒度隔离。
这个工程用三个步骤解决问题:
- 用 scatter 链接脚本把不同代码和数据放到独立区域。
- 用链接器生成的
Image$$xxx$$Base符号作为 MPU 基地址。 - 用 3 个 MPU 区域给用户态开放必要权限,再通过 SVC 进入特权服务。
在 Cortex-M3 裸机工程里,MPU 的难点通常不在寄存器,而在链接布局。
MPU 只能保护按规则对齐的连续内存区域。如果用户代码、用户数据、共享数据和特权数据在链接阶段混在一起,运行时再配置 MPU,也无法做到细粒度隔离。
这个工程用三个步骤解决问题:
Image$$xxx$$Base 符号作为 MPU 基地址。| 方法 | 命令 | 适用场景 |
|---|---|---|
| 启动时传参 | gdb --args ./exe 1 2 "3 4",然后 run |
固定参数调试,首选 |
| 进入 GDB 后设置 | gdb ./exe → set args 1 2 "3 4" → run |
需要反复修改参数 |
| 直接跟参数运行 | gdb ./exe → run 1 2 "3 4" |
临时测试,最简洁 |
两次握手的致命缺陷在于服务端资源分配过早,缺乏最终确认机制。
服务端在收到第一次握手(SYN)并发出 SYN+ACK 后,就立刻分配完整连接资源并进入 ESTABLISHED 状态。它没有 SYN_RCVD 这个中间状态来做缓冲。
这就导致:无论收到的是序列号不同的历史报文,还是序列号相同的超时重传报文,服务端都会盲目地分配一份完整资源。等到后续发现不对劲,只能靠发送 RST 来强制重置连接,此时刚刚分配的资源已经浪费掉了。
UART 的 ORE(Overrun Error,溢出错误) 本质就一句话:
上一字节还没被软件取走,下一字节又到了,把接收数据寄存器顶掉了。
假设 UART 接收寄存器一次只能保存 1 个字节。
UART收到 A
↓
接收寄存器 = A
↓
CPU还没读取
↓
UART又收到 B
↓
接收寄存器还没空
↓
ORE = 1
MPU(内存保护单元)的规矩,完全可以用“势力范围”来理解。它管得宽不宽、让不让进,全看地盘归谁管。
只要这块地盘被 MPU 划进了它的势力范围,访问就要看它定的“规矩”(AP 权限):
接下来就是要对mpu的覆盖范围进行设置,并且设置访问的权限
设置的话,只会涉及到两个寄存器
首先是基地址的设置寄存器
然后配置基地址处内存保护单元的大小,
PRIVDEFENA 开关控制:0 就是全封杀,1 就是特权放行,非特权封杀)。CPU有两种运行模式,一个是线程模式,一个是处理模式
对一些程序的权限呢,我们要做一些划分,权限高的就可以用一些比较底层的汇编指令
对这个特殊寄存器control register来进行编程可以控制当前的特权级别和栈
在下面的图片中可以看见,在普通的非特权模式下,要想从非特权模式到特权模式是没有反应的,没有效果的。
所以要在特权模式下触发从非特权模式到特权模式的转换
上面一讲有一张PPT里面就有说中断和异常都是特权模式,所以我们要在这里面来进行由非特权模式向特权模式的转换
这里的话,在执行完从特权级向非特权级的转变之后,我们在调试界面手动触发interrupt1,在中断里面进行特权级的切换
可以看见进入中断前呢,是非特权级,然后我们把这个NVIC控制器的这两个给它勾选上,
上一讲里面呢,我们是用中断来触发一次特权及切换的。但是这个中断呢,试的时候使用调试器手动触发的
中断是程序收到外部的信息,然后才去执行。但是我们这里呢,我们希望程序它能够自己的执行,不需要外界的输入。所以就使用异常。这里使用SVC异常
可以看见,我们先执行一次权限切换,切换到非特权级,然后准备进行触发SVC异常
