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

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

文章分类

全部博文(20)

文章存档

2013年(17)

2012年(3)

分类: 嵌入式

2013-08-03 16:16:14

按照我之前给出的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提出了一个功能,总是能起到作用的吧。


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

shaomengchao2013-08-10 21:55:24

你估计没怎么看我的文章,MQX的系统调用少的可怜,涉及驱动方面的系统调用几乎没有,对于这样的一个系统去真的要使用用户模式对于个人开发者来说费时费力。我并非否认用户模式,只是说不建议在MQX上使用。

回复 | 举报