Chinaunix首页 | 论坛 | 博客
  • 博客访问: 46277
  • 博文数量: 15
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-06 15:00
文章分类

全部博文(15)

文章存档

2013年(15)

我的朋友

分类: 嵌入式

2013-10-15 15:13:24

按照我之前给出的MPU地址空间表,Unprivileged似乎只能对内存段的RWUSER里进行写操作,而这个RWUSER段也是必须事前通过宏USER_RW_ACCESS前缀来定义的静态变量。那用户任务运行必定需要堆栈,堆栈如果不允许写,那如何运行程序呢?其实,我之前介绍的只是MQX中静态定义Unprivileged权限地址段的一种方法,而真正在使用中MQX使用的最多的还是动态的创建一个Unprivileged可读写的内存空间用来提供用户任务的相关操作。

首先我要补充一下MQX的动态内存分配机制,MQX的动态内存机制其实是基于内存池的分配机制。在系统初始化的时候会建立第一级内存池,包括系统的整个内存空间。如果任务没有明确指出要求分配内存空间的内存池,就是默认从这个一级内存池中分配。而MQX可以从这个一级内存池中分配出一块区域,建立二级内存池。如果任务指明了要求分配的内存池,就从该内存池对于的内存空间里利用block机制动态分配内存。而在同样在MQX的初始化过程中,在函数_bsp_enable_card里,MQX创建了一个叫做KD_USER_POOL 的二级内存池:

点击(此处)折叠或打开

  1. // create user heap automaticaly, we have specified only size of heap (end of heap is zero, start of heap mean size)
  2.         LWMEM_POOL_STRUCT_PTR lwmem_pool_ptr;
  3.         uchar_ptr start;

  4.         //start = _lwmem_alloc((char*)kernel_data->INIT.END_OF_USER_HEAP - (char*)kernel_data->INIT.START_OF_USER_HEAP + sizeof(LWMEM_POOL_STRUCT));
  5.         start = _lwmem_alloc((uint_32)kernel_data->INIT.START_OF_USER_HEAP + sizeof(LWMEM_POOL_STRUCT));
  6.         lwmem_pool_ptr = (LWMEM_POOL_STRUCT_PTR)start;
  7.         start = (pointer)((uchar_ptr)start + sizeof(LWMEM_POOL_STRUCT));
  8.         _lwmem_create_pool(lwmem_pool_ptr, start, (uint_32)kernel_data->INIT.START_OF_USER_HEAP);
  9.         _mem_set_pool_access(lwmem_pool_ptr, POOL_USER_RW_ACCESS);

  10.         kernel_data->KD_USER_POOL = lwmem_pool_ptr;

    这个内存池的大小是16K,而MPU将其实Unprivileged权限设置为了RW。于是从这块内存池里分配出的内存都是可以被用户任务读写的。

    现在回到开头我们提到的用户任务堆栈的问题,在分配任务堆栈函数_task_alloc_td_internal中:


点击(此处)折叠或打开

  1. ...
  2. #if MQX_ENABLE_USER_MODE
  3.             if (user)
  4.             {
  5.                 new_td_ptr->STACK_ALLOC_BLOCK = (TD_STRUCT_PTR)_mem_alloc_from(kernel_data->KD_USER_POOL, stack_size);
  6.             }
  7.             else
  8.             {
  9.                 new_td_ptr->STACK_ALLOC_BLOCK = (TD_STRUCT_PTR)_mem_alloc(stack_size);
  10.             }
  11. #else
  12.             new_td_ptr->STACK_ALLOC_BLOCK = (TD_STRUCT_PTR)_mem_alloc(stack_size);
  13. #endif /* MQX_ENABLE_USER_MODE */
  14.     ....

这个user标志是由任务模板的属性是否含有MQX_USER_TASK来决定的,果然一个任务是用户任务,那堆栈就从KD_USER_POOL这个二级内存池中分配。通过这样用户任务就拥有了可以读写自己堆栈的能力。

当然KD_USER_POOL 内存池大小有限,一直从它里面分配会导致它容量不足。所以我们也可以根据自己的具体需要来创建一个用户内存池,像usermode例程里,它就是自己创建的内存池。


点击(此处)折叠或打开

  1. mem_pool_start = _mem_alloc(1024);
  2.     mem_pool_id = _lwmem_create_pool(&mem_pool, mem_pool_start, 1024);
  3.     _mem_set_pool_access(mem_pool_id, POOL_USER_RO_ACCESS);

    虽然用户任务可以使用用户内存池里的内存,但用户任务并不能直接从用户内存池里分配内存,道理很简单_mem_set_pool_access只是将内存池里的内存空间赋予了Unprivileged的读写权限,但没有修改内存池本身结构体的权限。分配内存必定要修改对于的内存池结构体,因此用户任务是不能直接分配内存的,还是要老老实实的靠系统调用。

点击(此处)折叠或打开

  1. _mqx_uint _mem_set_pool_access
  2. (
  3.     _lwmem_pool_id mem_pool_id,
  4.     uint_32 access
  5. )
  6. {
  7.     _mqx_uint res = MQX_LWMEM_POOL_INVALID;
  8.     LWMEM_POOL_STRUCT_PTR mem_pool_ptr = (_lwmem_pool_id)mem_pool_id;

  9.     if (LWMEM_POOL_VALID == mem_pool_ptr->VALID)
  10.     {
  11.         res = _psp_mpu_add_region(mem_pool_ptr->POOL_ALLOC_START_PTR, mem_pool_ptr->POOL_ALLOC_END_PTR, access);
  12.     }

  13.     return res;
  14. }

    对于一个用户任务而言,动态分配用户空间往往适用于于分配较大内存的场合,对于一些零散的变量还是通过静态定义的方式完成,毕竟系统调用和block模式分配都是耗资源和时间的。

 

    到这里用户模式就介绍的差不多,总而言之用户任务的限制条件还是相当多,涉及底层或是内存的操作都要交由系统调用来完成。而相对而言,MQX关于底层驱动的系统调用接口还不是很丰富,如果是一个任务和底层驱动密切相关的话,是非常不建议使用用户模式的,当然如果能够针对性的编写相应的系统调用的也是可以的。对于个人开发者而言,这个用户模式是完全没有必要的,而对于大型的项目开发,由于本人没有实际的开发经验,也不是很清楚,既然freescale提出了一个功能,总是能起到作用的吧。


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