让vdsp与uclinux共舞(12):应用程序开发

来源:互联网 发布:linux 修改文件名称 编辑:程序博客网 时间:2024/04/29 02:34

快乐虾

http://blog.csdn.net/lights_joy/

lights@hb165.com

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

本文适用于

ADSP-BF561

Visual DSP++ 5.0(update 6)

Bfin-uclinux-2009r1.6

 

 

欢迎转载,但请保留作者信息

 

下面我们尝试在vdsp下开发uclinux应用程序。

1.1.1   空间分配

与驱动的开发类似,我们在内核代码之前挪用一段空间来使用。这样我们就可以在vdsp下使用固定地址的方式进行开发。

1.1.2   Uclibc移植

我们需要在应用程序中使用uclinux内核提供的服务,因此,uclibc就是必不可少的内容,我们将之移植到vdsp下编译。需要注意的是我们仅移植其中的libc。至于libdsp之类的我们直接可以使用vdsp的库,嘿嘿。

1.1.3   程序的运行方式

在开发的时候,我们使用vdsp进行编译并下载,然后使用一个stub程序接受命令行输入,并跳转到我们指定的位置开始执行。

开发完成后,我们通过stub程序加载dxe文件并跳转到正确的位置运行。

1.1.4   Ldf文件

vdsp下开发时,我们仅需要使用单核方式进行开发,当然,在实际运行时,我们的程序可能会在两个核之间进行切换,我们需要在下载完成后为ab核重新加载一次符号信息。

根据这种方式,写一个简单的ldf文件:

 

ARCHITECTURE(ADSP-BF561)

 

SEARCH_DIR($ADI_DSP/Blackfin/lib)

 

 

$LIBRARIES_CORE_A =

   libc.dlb

   , libdsp561.dlb

   , libf64ieee561.dlb

   , librt561.dlb

   , libevent561.dlb

   , libmc561.dlb

   , libx561.dlb

   , libsmall561.dlb

   , libdrv561.dlb

   , main.doj

   ;

 

 

#define VDSP_COMM_BEGIN           0x00010000  

#define VDSP_COMM_END                     0x00010039  

#define VDSP_DRIVER_CODE_BEGIN      0x00010040

#define VDSP_DRIVER_CODE_END  0x0001ffff

#define VDSP_DRIVER_DATA_BEGIN       0x00020000

#define VDSP_DRIVER_DATA_END   0x0002ffff

 

PROCESSOR p0

{

  

   MEMORY

   {

      MEM_VDSP_COMM        { TYPE(RAM) START(VDSP_COMM_BEGIN) END(VDSP_COMM_END) WIDTH(8) }

      MEM_DRIVER_CODE   { TYPE(RAM) START(VDSP_DRIVER_CODE_BEGIN) END(VDSP_DRIVER_CODE_END) WIDTH(8) }

      MEM_DRIVER_DATA   { TYPE(RAM) START(VDSP_DRIVER_DATA_BEGIN) END(VDSP_DRIVER_DATA_END) WIDTH(8) }

   } /* MEMORY */

  

   OUTPUT($COMMAND_LINE_OUTPUT_DIRECTORY/p0.dxe)

  

   SECTIONS

   {

      .vdsp_comm

      {

         INPUT_SECTION_ALIGN(4)

         INPUT_SECTIONS($LIBRARIES_CORE_A(.vdsp_comm))

      } > MEM_VDSP_COMM

 

      .code

      {

         INPUT_SECTION_ALIGN(4)

         INPUT_SECTIONS($LIBRARIES_CORE_A(program))

      } > MEM_DRIVER_CODE

 

      .data

      {

         INPUT_SECTION_ALIGN(4)

         INPUT_SECTIONS($LIBRARIES_CORE_A(data1))

         INPUT_SECTIONS($LIBRARIES_CORE_A(constdata))

         INPUT_SECTIONS( $LIBRARIES_CORE_A(voldata))

         INPUT_SECTIONS( $LIBRARIES_CORE_A(primio_atomic_lock))

      } > MEM_DRIVER_DATA

     

      bsz ZERO_INIT

      {

         INPUT_SECTION_ALIGN(4)

         _bsz_begin = .;

         INPUT_SECTIONS($LIBRARIES_CORE_A(bsz))

         _bsz_end = .;

      } > MEM_DRIVER_DATA

     

   } /* SECTIONS */

} /* p0 */

这里最重要的是要保证我们移植的libcvdsp库之前,这样才能正确使用uclinux内核提供的功能。

1.1.5   appstub

我们自己写一个appstub程序,辅助完成程序的调试,这个程序使用gcc编译,目前尚未实现dxe文件加载:

#include <getopt.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <fcntl.h>

#include <sys/ioctl.h>

#include <linux/types.h>

#include <linux/watchdog.h>

#include <signal.h>

#include <paths.h>

#include <sched.h>

 

 

 

/*

 * The main program.

 */

typedef int (*pfcall)(int argc, char *argv[]);

int main(int argc, char *argv[])

{

    unsigned int addr = 0;

    unsigned int *p;

    if(argc < 2)

    {

        printf("not enough param.");

        return 1;

    }

    addr = strtoul(argv[1], NULL, 16);

    p = (unsigned int*)addr;

    if(p[0])

    {

        printf("detect new app at %08x/n", p);

        p[0] = 0;

        if(p[1])

        {

            printf("prepare call %08x/n", p[1]);

            argv[1] = argv[0];

            ((pfcall)p[1])(argc-1, argv+1);

            printf("function call over./n");

        }

        else

            printf("no function entry found./n");

    }

    else

        printf("old app exist.");

    return 0;

}

 

这段代码功能和简单,就是检测指定位置的内存,如果发现变化就跳转到指定位置继续运行,同时传递argcargv参数。

1.1.6   目标程序

我们的目标是在vdsp下开发uclinux应用程序,下面是一段很简单的代码:

#include <stdio.h>

 

static int app_main(int argc, char** argv);

 

typedef struct _vdsp_comm

{

     int app_loaded;

     void (*app_load)();

}vdsp_comm;

 

#pragma section(".vdsp_comm")

static vdsp_comm comm_param =

{

     .app_loaded = 1,

     .app_load = app_main,

};

 

 

static int main(int argc, char** argv, char** envp)

{

     FILE* f = fdopen(1, "wt");

     fprintf(f, "hello world!/n");

     return 0;

}

 

extern void __uClibc_main(int (*main)(int, char **, char **), int argc,

             char **argv, void (*app_init)(void), void (*app_fini)(void),

             void (*rtld_fini)(void), void *stack_end) attribute_noreturn;

extern char bsz_begin[], bsz_end[];

 

static int app_main(int argc, char** argv)

{

     memset(bsz_begin, 0, bsz_end - bsz_begin);

     __uClibc_main(main, argc, argv, NULL, NULL, NULL, NULL);

     return 0;

}

这段代码指定了程序入口是app_main,因为我们略过了uclibccrt代码,因此在此函数的入口直接调用了uClibc_mainuclibc进行初始化。

这里需要注意的是bss段,在uclinuxflat格式的文件中,bss段是由加载器读取flat文件时清零的。对于我们这种情况就只能自己动手了,因此在uclibc_main调用之前插入了一个memset

1.1.7   输出结果

可以在console里看到程序的运行结果:

root:/> appstub 10000

detect new app at 00010000

prepare call 0001480e

hello world!

root:/>

下面是vdsp调试的截图:

 

我们可以像不带系统样的进行各种调试工作!

 

 

 

2       参考资料

vdspuclinux共舞(11):方案改进(2009-11-6)

vdspuclinux共舞(10):加载SMP内核(2009-11-4)

vdspuclinux共舞(9):查找内核函数(2009-11-3)

vdspuclinux共舞(8):vdsp驱动框架(2009-11-3)

vdspuclinux共舞(7):在内核为驱动预留空间(2009-11-2)

vdspuclinux共舞(6):用vdsp开发驱动的设想(2009-11-2)

vdspuclinux共舞(5):加入dwarf调试信息(2009-11-2)

vdspuclinux共舞(4):加载uclinux(2009-11-2)

vdspuclinux共舞(3):boot kernel(2009-10-31)

vdspuclinux共舞(2):vdsp的影(2009-10-31)

VDSPuclinux共舞(1):开篇(2009-10-30)

 

 

 

 

 

近日,我家6岁的小姑娘参加了第六届POP全国少儿英语风采大赛,拉票进行中(2011-6-15前)。

请帮忙点击新东方网站的链接:

http://popdasai.xdf.cn/toupiao.php?do=space&uid=4237

投她一票,谢谢!

原创粉丝点击