Chinaunix首页 | 论坛 | 博客
  • 博客访问: 120851
  • 博文数量: 20
  • 博客积分: 125
  • 博客等级: 入伍新兵
  • 技术积分: 985
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-08 13:48
个人简介

热爱开源,喜欢分析操作系统架构

文章分类

全部博文(20)

文章存档

2013年(17)

2012年(3)

分类: 嵌入式

2013-08-03 14:40:49

之前说了MPU,现在说说MQX是如何使用MPU的。对于Privileged级,一般来说对整体0x00000000~0xffffffff都是有rwx权限的,(当然这个只是MPU的权限,就算是Privileged级,访问了不该访问的地址还是会出现异常错误的,不过不是MPU引发的而已)关于Unprivileged的MPU设置就比较复杂一点,具体设置的地方在_bsp_enable_card函数里:

点击(此处)折叠或打开

  1. _kinetis_mpu_add_region(0, ((uchar_ptr)kernel_data->INIT.START_OF_USER_NO_MEMORY) - 1, \
  2.         MPU_WORD_M3SM(MPU_SM_RWX) | MPU_WORD_M3UM(MPU_UM_R | MPU_UM_X) | \
  3.         MPU_WORD_M2SM(MPU_SM_RWX) | MPU_WORD_M2UM(MPU_UM_R | MPU_UM_X) | \
  4.         MPU_WORD_M1SM(MPU_SM_RWX) | MPU_WORD_M1UM(MPU_UM_R | MPU_UM_X) | \
  5.         MPU_WORD_M0SM(MPU_SM_RWX) | MPU_WORD_M0UM(MPU_UM_R | MPU_UM_X));

  6.     _kinetis_mpu_add_region(((uchar_ptr)kernel_data->INIT.START_OF_USER_RO_MEMORY), (uchar_ptr)0xffffffff, \
  7.         MPU_WORD_M3SM(MPU_SM_RWX) | MPU_WORD_M3UM(MPU_UM_R | MPU_UM_X) | \
  8.         MPU_WORD_M2SM(MPU_SM_RWX) | MPU_WORD_M2UM(MPU_UM_R | MPU_UM_X) | \
  9.         MPU_WORD_M1SM(MPU_SM_RWX) | MPU_WORD_M1UM(MPU_UM_R | MPU_UM_X) | \
  10.         MPU_WORD_M0SM(MPU_SM_RWX) | MPU_WORD_M0UM(MPU_UM_R | MPU_UM_X));
  11.     
  12.     ....
  13.     
  14.       if (kernel_data->INIT.START_OF_USER_RW_MEMORY < kernel_data->INIT.END_OF_USER_RW_MEMORY) {
  15.         _kinetis_mpu_add_region(kernel_data->INIT.START_OF_USER_RW_MEMORY, ((uchar_ptr)kernel_data->INIT.END_OF_USER_RW_MEMORY) - 1, \
  16.             MPU_WORD_M1SM(MPU_SM_RWX) | MPU_WORD_M1UM(MPU_UM_R | MPU_UM_W) | \
  17.             MPU_WORD_M0SM(MPU_SM_RWX) | MPU_WORD_M0UM(MPU_UM_R | MPU_UM_W));
  18.     }

  19.     // set access for user read-only memory area
  20.     if (kernel_data->INIT.START_OF_USER_RO_MEMORY < kernel_data->INIT.END_OF_USER_RO_MEMORY) {
  21.         _kinetis_mpu_add_region(kernel_data->INIT.START_OF_USER_RO_MEMORY, ((uchar_ptr)kernel_data->INIT.END_OF_USER_RO_MEMORY) - 1, \
  22.             MPU_WORD_M1SM(MPU_SM_RWX) | MPU_WORD_M1UM(MPU_UM_R) | \
  23.             MPU_WORD_M0SM(MPU_SM_RWX) | MPU_WORD_M0UM(MPU_UM_R));
  24.     }

  25.     // set access for user no access memory area
  26.     if (kernel_data->INIT.START_OF_USER_NO_MEMORY < kernel_data->INIT.END_OF_USER_NO_MEMORY) {
  27.         _kinetis_mpu_add_region(kernel_data->INIT.START_OF_USER_NO_MEMORY, ((uchar_ptr)kernel_data->INIT.END_OF_USER_NO_MEMORY) - 1, \
  28.             MPU_WORD_M1SM(MPU_SM_RWX) | MPU_WORD_M1UM(0) | \
  29.             MPU_WORD_M0SM(MPU_SM_RWX) | MPU_WORD_M0UM(0));
  30.     }


    这里定义多块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环境的时候这个定义如下:


点击(此处)折叠或打开

  1. const MQX_INITIALIZATION_STRUCT MQX_init_struct =
  2. {
  3.     ....
  4. #if MQX_ENABLE_USER_MODE
  5.    BSP_DEFAULT_START_OF_KERNEL_AREA,
  6.    BSP_DEFAULT_END_OF_KERNEL_AREA,
  7.    
  8.    BSP_DEFAULT_START_OF_USER_DEFAULT_MEMORY,
  9.    BSP_DEFAULT_END_OF_USER_DEFAULT_MEMORY,
  10.    
  11.    BSP_DEFAULT_START_OF_USER_HEAP,
  12.    BSP_DEFAULT_END_OF_USER_HEAP,
  13.    
  14.    BSP_DEFAULT_START_OF_USER_RW_MEMORY,
  15.    BSP_DEFAULT_END_OF_USER_RW_MEMORY,
  16.    
  17.    BSP_DEFAULT_START_OF_USER_RO_MEMORY,
  18.    BSP_DEFAULT_END_OF_USER_RO_MEMORY,
  19.    
  20.    BSP_DEFAULT_START_OF_USER_NO_MEMORY,
  21.    BSP_DEFAULT_END_OF_USER_NO_MEMORY,

  22.    BSP_DEFAULT_MAX_USER_TASK_PRIORITY,
  23.    BSP_DEFAULT_MAX_USER_TASK_COUNT,
  24. #endif
  25. };

  26. #define BSP_DEFAULT_START_OF_USER_RW_MEMORY ((pointer)&Image$$RWUSER$$Base)
  27. #define BSP_DEFAULT_END_OF_USER_RW_MEMORY ((pointer)&Image$$DATA$$Base)
  28. #define BSP_DEFAULT_START_OF_USER_RO_MEMORY ((pointer)&Image$$ROUSER$$Base)
  29. #define BSP_DEFAULT_END_OF_USER_RO_MEMORY ((pointer)&Image$$RWUSER$$Base)
  30. #define BSP_DEFAULT_START_OF_USER_NO_MEMORY ((pointer)&Image$$NOUSER$$Base)
  31. #define BSP_DEFAULT_END_OF_USER_NO_MEMORY ((pointer)&Image$$ROUSER$$Base)


         看来这个和NOUSER、ROUSER、RWUSER有关,而这些东西是链接文件intflash.scf里定义的

点击(此处)折叠或打开

  1. LOAD_REGION_INTFLASH INTFLASH_BASE_ADDR INTFLASH_SIZE
  2. {
  3.     VECTORS INTFLASH_BASE_ADDR
  4.     {
  5.         vectors.o (.vectors_rom,+FIRST)
  6.         vectors.o (.cfmconfig)
  7.     }
  8.     
  9.     ....
  10.     
  11.     RAM_VECTORS 0x1FFF0000 ; For ram vector table. Used when MQX_ROM_VECTORS is set to zero.
  12.     {
  13.         vectors.o (.vectors_ram)
  14.     }
  15.     
  16.     NOUSER +0
  17.     {
  18.         * (.nouser)
  19.     }

  20.     ROUSER MY_ALIGN(ImageLimit(NOUSER), 32)
  21.     {
  22.         * (.rouser)
  23.     }

  24.     RWUSER MY_ALIGN(ImageLimit(ROUSER), 32)
  25.     {
  26.         * (.rwuser)
  27.     }
  28.     
  29.     .....
  30.  }


         关于intflash.scf,我在博文“代码之始”就介绍了它的功能,不过当时着重的是中断向量表,现在我们来分析的是NOUSER、ROUSER和RWUSER这个3个段。这3个段按顺序在运行的时候加载在0x1FFF000+sizeof(vectors.o)的内存空间上。具体这里面是什么东西呢,这个就要看我们在编译的时候装进去什么了,我以MQX官方例程usermode举例。查看这个工程的map:

点击(此处)折叠或打开

  1. .....
  2.     Image$$NOUSER$$Base 0x1fff0000 Number 0 anon$$obj.o(linker$$defined$$symbols)
  3.     Image$$ROUSER$$Base 0x1fff0000 Number 0 anon$$obj.o(linker$$defined$$symbols)
  4.     Image$$RWUSER$$Base 0x1fff0000 Number 0 usermode.o(.rwuser)
  5.     que 0x1fff0000 Data 4 usermode.o(.rwuser)
  6.     usr_pool_id 0x1fff0004 Data 4 usermode.o(.rwuser)
  7.     Image$$DATA$$Base 0x1fff0020 Number 0 psp_mstiq.o(.data)
  8.     .....


 因为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里有如下代码:


点击(此处)折叠或打开

  1. USER_RW_ACCESS uint_32 *que;
  2. USER_RW_ACCESS _lwmem_pool_id usr_pool_id;

  3. #define USER_RW_ACCESS __attribute__((section(".rwuser")))
  4. #define USER_RO_ACCESS __attribute__((section(".rouser")))
  5. #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的默认配置下,用户级别任务不允许写寄存器和写外部总线,而这些关于底层硬件操作全是交给系统调用来完成的。

阅读(1386) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~