之前说了MPU,现在说说MQX是如何使用MPU的。对于Privileged级,一般来说对整体0x00000000~0xffffffff都是有rwx权限的,(当然这个只是MPU的权限,就算是Privileged级,访问了不该访问的地址还是会出现异常错误的,不过不是MPU引发的而已)关于Unprivileged的MPU设置就比较复杂一点,具体设置的地方在_bsp_enable_card函数里:
-
_kinetis_mpu_add_region(0, ((uchar_ptr)kernel_data->INIT.START_OF_USER_NO_MEMORY) - 1, \
-
MPU_WORD_M3SM(MPU_SM_RWX) | MPU_WORD_M3UM(MPU_UM_R | MPU_UM_X) | \
-
MPU_WORD_M2SM(MPU_SM_RWX) | MPU_WORD_M2UM(MPU_UM_R | MPU_UM_X) | \
-
MPU_WORD_M1SM(MPU_SM_RWX) | MPU_WORD_M1UM(MPU_UM_R | MPU_UM_X) | \
-
MPU_WORD_M0SM(MPU_SM_RWX) | MPU_WORD_M0UM(MPU_UM_R | MPU_UM_X));
-
-
_kinetis_mpu_add_region(((uchar_ptr)kernel_data->INIT.START_OF_USER_RO_MEMORY), (uchar_ptr)0xffffffff, \
-
MPU_WORD_M3SM(MPU_SM_RWX) | MPU_WORD_M3UM(MPU_UM_R | MPU_UM_X) | \
-
MPU_WORD_M2SM(MPU_SM_RWX) | MPU_WORD_M2UM(MPU_UM_R | MPU_UM_X) | \
-
MPU_WORD_M1SM(MPU_SM_RWX) | MPU_WORD_M1UM(MPU_UM_R | MPU_UM_X) | \
-
MPU_WORD_M0SM(MPU_SM_RWX) | MPU_WORD_M0UM(MPU_UM_R | MPU_UM_X));
-
-
....
-
-
if (kernel_data->INIT.START_OF_USER_RW_MEMORY < kernel_data->INIT.END_OF_USER_RW_MEMORY) {
-
_kinetis_mpu_add_region(kernel_data->INIT.START_OF_USER_RW_MEMORY, ((uchar_ptr)kernel_data->INIT.END_OF_USER_RW_MEMORY) - 1, \
-
MPU_WORD_M1SM(MPU_SM_RWX) | MPU_WORD_M1UM(MPU_UM_R | MPU_UM_W) | \
-
MPU_WORD_M0SM(MPU_SM_RWX) | MPU_WORD_M0UM(MPU_UM_R | MPU_UM_W));
-
}
-
-
// set access for user read-only memory area
-
if (kernel_data->INIT.START_OF_USER_RO_MEMORY < kernel_data->INIT.END_OF_USER_RO_MEMORY) {
-
_kinetis_mpu_add_region(kernel_data->INIT.START_OF_USER_RO_MEMORY, ((uchar_ptr)kernel_data->INIT.END_OF_USER_RO_MEMORY) - 1, \
-
MPU_WORD_M1SM(MPU_SM_RWX) | MPU_WORD_M1UM(MPU_UM_R) | \
-
MPU_WORD_M0SM(MPU_SM_RWX) | MPU_WORD_M0UM(MPU_UM_R));
-
}
-
-
// set access for user no access memory area
-
if (kernel_data->INIT.START_OF_USER_NO_MEMORY < kernel_data->INIT.END_OF_USER_NO_MEMORY) {
-
_kinetis_mpu_add_region(kernel_data->INIT.START_OF_USER_NO_MEMORY, ((uchar_ptr)kernel_data->INIT.END_OF_USER_NO_MEMORY) - 1, \
-
MPU_WORD_M1SM(MPU_SM_RWX) | MPU_WORD_M1UM(0) | \
-
MPU_WORD_M0SM(MPU_SM_RWX) | MPU_WORD_M0UM(0));
-
}
这里定义多块MPU区域,0~START_OF_USER_NO_MEMORY、START_OF_USER_RO_MEMORY~0xfffffff、START_OF_USER_RW_MEMORY~END_OF_USER_RW_MEMOR、START_OF_USER_RO_MEMORY~END_OF_USER_RO_MEMORY、START_OF_USER_NO_MEMORY~END_OF_USER_NO_MEMORY,针对每块区域都有不同的设定。
而这些诸如START_OF_USER_NO_MEMORY之流的又是什么呢?它们定义在MQX_init_struct里,在使用MDK环境的时候这个定义如下:
-
const MQX_INITIALIZATION_STRUCT MQX_init_struct =
-
{
-
....
-
#if MQX_ENABLE_USER_MODE
-
BSP_DEFAULT_START_OF_KERNEL_AREA,
-
BSP_DEFAULT_END_OF_KERNEL_AREA,
-
-
BSP_DEFAULT_START_OF_USER_DEFAULT_MEMORY,
-
BSP_DEFAULT_END_OF_USER_DEFAULT_MEMORY,
-
-
BSP_DEFAULT_START_OF_USER_HEAP,
-
BSP_DEFAULT_END_OF_USER_HEAP,
-
-
BSP_DEFAULT_START_OF_USER_RW_MEMORY,
-
BSP_DEFAULT_END_OF_USER_RW_MEMORY,
-
-
BSP_DEFAULT_START_OF_USER_RO_MEMORY,
-
BSP_DEFAULT_END_OF_USER_RO_MEMORY,
-
-
BSP_DEFAULT_START_OF_USER_NO_MEMORY,
-
BSP_DEFAULT_END_OF_USER_NO_MEMORY,
-
-
BSP_DEFAULT_MAX_USER_TASK_PRIORITY,
-
BSP_DEFAULT_MAX_USER_TASK_COUNT,
-
#endif
-
};
-
-
#define BSP_DEFAULT_START_OF_USER_RW_MEMORY ((pointer)&Image$$RWUSER$$Base)
-
#define BSP_DEFAULT_END_OF_USER_RW_MEMORY ((pointer)&Image$$DATA$$Base)
-
#define BSP_DEFAULT_START_OF_USER_RO_MEMORY ((pointer)&Image$$ROUSER$$Base)
-
#define BSP_DEFAULT_END_OF_USER_RO_MEMORY ((pointer)&Image$$RWUSER$$Base)
-
#define BSP_DEFAULT_START_OF_USER_NO_MEMORY ((pointer)&Image$$NOUSER$$Base)
-
#define BSP_DEFAULT_END_OF_USER_NO_MEMORY ((pointer)&Image$$ROUSER$$Base)
看来这个和NOUSER、ROUSER、RWUSER有关,而这些东西是链接文件intflash.scf里定义的
-
LOAD_REGION_INTFLASH INTFLASH_BASE_ADDR INTFLASH_SIZE
-
{
-
VECTORS INTFLASH_BASE_ADDR
-
{
-
vectors.o (.vectors_rom,+FIRST)
-
vectors.o (.cfmconfig)
-
}
-
-
....
-
-
RAM_VECTORS 0x1FFF0000 ; For ram vector table. Used when MQX_ROM_VECTORS is set to zero.
-
{
-
vectors.o (.vectors_ram)
-
}
-
-
NOUSER +0
-
{
-
* (.nouser)
-
}
-
-
ROUSER MY_ALIGN(ImageLimit(NOUSER), 32)
-
{
-
* (.rouser)
-
}
-
-
RWUSER MY_ALIGN(ImageLimit(ROUSER), 32)
-
{
-
* (.rwuser)
-
}
-
-
.....
-
}
关于intflash.scf,我在博文“代码之始”就介绍了它的功能,不过当时着重的是中断向量表,现在我们来分析的是NOUSER、ROUSER和RWUSER这个3个段。这3个段按顺序在运行的时候加载在0x1FFF000+sizeof(vectors.o)的内存空间上。具体这里面是什么东西呢,这个就要看我们在编译的时候装进去什么了,我以MQX官方例程usermode举例。查看这个工程的map:
-
.....
-
Image$$NOUSER$$Base 0x1fff0000 Number 0 anon$$obj.o(linker$$defined$$symbols)
-
Image$$ROUSER$$Base 0x1fff0000 Number 0 anon$$obj.o(linker$$defined$$symbols)
-
Image$$RWUSER$$Base 0x1fff0000 Number 0 usermode.o(.rwuser)
-
que 0x1fff0000 Data 4 usermode.o(.rwuser)
-
usr_pool_id 0x1fff0004 Data 4 usermode.o(.rwuser)
-
Image$$DATA$$Base 0x1fff0020 Number 0 psp_mstiq.o(.data)
-
.....
因为usermode程序里的中断向量表vectors在flash里,内存段的vectors.o大小为0。而NOUSER和ROUSER段都是空的,只有RWUSER有que和usr_pool_id一个8字节的变量。不过由于intflash.scf将其设置为32字节对齐,因此RWUSER大小是32字节。
现在来说明que和usr_pool_id是如何被放到RWUSER里的,在usermode.c和comp.h里有如下代码:
-
USER_RW_ACCESS uint_32 *que;
-
USER_RW_ACCESS _lwmem_pool_id usr_pool_id;
-
-
#define USER_RW_ACCESS __attribute__((section(".rwuser")))
-
#define USER_RO_ACCESS __attribute__((section(".rouser")))
-
#define USER_NO_ACCESS __attribute__((section(".nouser")))
在mdk环境下,使用__attribute__((section(".XXX")))前缀就可以将一个变量在链接的时候放到链接脚本的对应的XXX的段里。通过这样的手段,我们就可以随意的控制静态变量的位置,这是一个非常有用的技巧。
知道了MPU各个区域的地址范围,我现在给出这个的MPU地址空间表。要注意的是对于重复定义的地址空间MPU的权限是采用or运算的,比如MPU某区域规定0~0x200空间内M0的Unprivileged的权限是rx,而还有一块区域定义在0x100~0x300里M0的Unprivileged的权限是rw,那么在0x100~0x200的地址空间内M0设备Unprivileged实际权限是rx|rw=rwx。
从图中可以看出,对于Privileged权限,MPU允许全体地址空间都是RWX,而对于Unprivileged权限,在flash段是RX,这样我们的用户任务还是可以运行存储在flash里的指令程序的。在内存段里面NOUSER是不允许访问,ROUSER只允许读,RWUSER只允许读写,而其他内存段是RX。对于0x40000000~0xffffffff里主要是寄存器和FlexBus,Unprivileged权限是不允许写的,即MQX的默认配置下,用户级别任务不允许写寄存器和写外部总线,而这些关于底层硬件操作全是交给系统调用来完成的。
阅读(1854) | 评论(0) | 转发(0) |