打印

VSF然并卵 -- 动态加载

[复制链接]
1705|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Simon21ic|  楼主 | 2015-8-6 11:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Simon21ic 于 2015-8-6 11:23 编辑

最近有人提起了动态加载,自己也抽空评估了一下这个技术,虽然并没有什么卵用,不过还是玩了一下。

动态加载,顾名思义,就是动态加载应用,应用程序可以不在芯片内部的flash里,比如外接的U盘里,然后载入到内存中运行。然而,一般的嵌入式操作系统,都不具备这种能力。
由于编译器具备ropi选项,所以程序部分,比较容易实现地址无关(不管程序在哪个地址,都可以正常运行)。但是,即便编译器具备rwpi,也一般是通过R9寄存器,来设置rw段的基地址。这样虽然可行,但是会非常麻烦,所有应用中的函数,被调用时,都需要保证R9被正确设置。

VSF构架,由于给应用层的接口都是面向对象的,使得能够非常容易的解决这个问题,就是应用程序不需要静态内存,应用需要的内存资源都使用动态分配。VSF的进程,以及回调函数等等,都可以设置一个用户定义的指针,正好可以用来指向这个分配的内存。

系统代码:
#include "vsf.h"
#include "app_hw_cfg.h"

struct vsfapp_t
{
        struct app_hwcfg_t hwcfg;
        
        uint8_t bufmgr_buffer[64 * 1024];
} static app =
{
        {
                {
                        {
                                2,                                        // uint8_t port;
                                13,                                        // uint8_t pin;
                        },                                                // struct usb_pullup;
                },                                                        // struct usbd;
        {
            {3, 4, 3, 6},
            {4, 1, 4, 0},
            {3, 5, 3, 3},
            {3, 9, 3, 10},
            {4, 15, 3, 8},
            {4, 13, 4, 14},
            {4, 11, 4, 12},
            {4, 9, 4, 10},
            {4, 7, 4, 8},
            {3, 0, 3, 1},
            {3, 14, 3, 15},
            {6, 13, 6, 14},
            {4, 6, 4, 2},
            {4, 4, 4, 5},
            {3, 13, 4, 3},
            {3, 11, 3, 12},
            {6, 4, 6, 5},
            {6, 2, 6, 3},
            {6, 0, 6, 1},
            {5, 14, 5, 15},
            {5, 12, 6, 13},
            {5, 4, 5, 5},
            {5, 2, 5, 3},
            {5, 0, 5, 1},
        },                            // struct led_t led[24];
        },                                                                // struct app_hwcfg_t hwcfg;
};

// tickclk interrupt, simply call vsftimer_callback_int
static void app_tickclk_callback_int(void *param)
{
        vsftimer_callback_int();
}

int main(void)
{
        int (*app_main)(const struct vsf_t *vsf, struct app_hwcfg_t *hwcfg) = NULL;
        
        vsf_leave_critical();
        
        // system initialize
        vsf_bufmgr_init(app.bufmgr_buffer, sizeof(app.bufmgr_buffer));
        core_interfaces.core.init(NULL);
        core_interfaces.tickclk.init();
        core_interfaces.tickclk.start();
        vsftimer_init();
        core_interfaces.tickclk.set_callback(app_tickclk_callback_int, NULL);
        
        // load and call application
        // TODO: try to load app_main address
        app_main = (int (*)(const struct vsf_t *vsf, struct app_hwcfg_t *hwcfg))0x08008000;
        if (app_main != NULL)
        {
                app_main(&vsf, &app.hwcfg);
        }
        
        while (1)
        {
                vsfsm_poll();
               
                vsf_enter_critical();
                if (!vsfsm_get_event_pending())
                {
                        // sleep, will also enable interrupt
                        core_interfaces.core.sleep(SLEEP_WFI);
                }
                else
                {
                        vsf_leave_critical();
                }
        }
}
应用层序只是做了系统初始化,包括系统初始化,定时器管理初始化,内存管理初始化后,就可以调用应用程序了,这里假定应用程序位于0x08008000的位置。当然,应用程序可以是多个,也可以不在内部flash里(这个就需要先把应用程序复制到内存中)。应用程序的第一个32位数据,是放应用程序用,main函数的偏移。应用中的main函数,参数为vsf和硬件配置。vsf提供了可以使用的系统的所有接口,包括访问硬件的接口,简单的定义如下:
const struct vsf_t vsf =
{
        &core_interfaces,
        
        {
                vsfsm_init,
                vsfsm_pt_init,
                vsfsm_post_evt,
                vsfsm_post_evt_pending,
                vsfsm_enter_critical_internal,
                vsfsm_leave_critical_internal,
                vsfsm_sem_init_internal,
                vsfsm_sem_post_internal,
                vsfsm_sem_pend_internal,
                vsfsm_crit_init_internal,
                vsfsm_crit_enter_internal,
                vsfsm_crit_leave_internal,
                vsftimer_register,
                vsftimer_unregister,
        },                                                // struct vsf_framework_t framework;
        
        {
                {
                        vsf_fifo_init,
                        vsf_fifo_push8,
                        vsf_fifo_pop8,
                        vsf_fifo_push,
                        vsf_fifo_pop,
                        vsf_fifo_get_data_length,
                        vsf_fifo_get_avail_length,
                },                                        // struct fifo
                {
                        vsf_bufmgr_malloc,
                        vsf_bufmgr_malloc_aligned,
                        vsf_bufmgr_free,
                },                                        // struct bufmgr;
        },                                                // struct buffer;
};
当然,这个还只是测试的代码,很多协议栈的接口还都没放进去。

应用部分:
应用程序,只需要知道芯片是什么类型的,用来指定编译用的指令集。比如,本例程中芯片使用stm32,所以应用程序的工程可以选择CortexM3的芯片。当然,如果选择CortexM0,那就各种CortexM的处理器都可以兼容。简单的说就是硬件可以使用stm32f1,也可以用新塘的M0,或者atmel的M4,应用程序的二进制文件都不用修改。上代码吧:
#include "vsf.h"
#include "app_hw_cfg.h"

#define LED_EVT_CARRY                                        (VSFSM_EVT_USER_LOCAL + 0)

struct vsfapp_t
{
        struct
        {
                struct vsf_t const *vsf;
        } sys;
        
        struct vsfsm_t sm;
        struct vsftimer_timer_t timer;
        
        // Application
        uint8_t led_num;
        struct app_led_t
        {
                struct led_t const *hw;
                bool on;
               
                struct vsfsm_pt_t pt;
                struct vsfsm_t *sm_carry;
               
                struct vsfsm_t sm;
                struct vsfapp_t *app;
        } led[24];
};

static vsf_err_t app_led_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt)
{
        struct app_led_t *led = (struct app_led_t *)pt->user_data;
        struct vsfapp_t *app = led->app;
        struct interfaces_info_t const *ifs = app->sys.vsf->ifs;
        struct vsf_framework_t const *framework = &app->sys.vsf->framework;
        
        vsfsm_pt_begin(pt);
        
        while (1)
        {
                vsfsm_pt_wfe(pt, LED_EVT_CARRY);
               
                if (led->on)
                {
                        ifs->gpio.clear(led->hw->hport, 1 << led->hw->hpin);
                        if (led->sm_carry != NULL)
                        {
                                framework->post_evt(led->sm_carry, LED_EVT_CARRY);
                        }
                }
                else
                {
                        ifs->gpio.set(led->hw->hport, 1 << led->hw->hpin);
                }
                led->on = !led->on;
        }
        
        vsfsm_pt_end(pt);
        return VSFERR_NONE;
}

static struct vsfsm_state_t *
app_evt_handler(struct vsfsm_t *sm, vsfsm_evt_t evt)
{
        struct vsfapp_t *app = (struct vsfapp_t *)sm->user_data;
        struct interfaces_info_t const *ifs = app->sys.vsf->ifs;
        struct vsf_framework_t const *framework = &app->sys.vsf->framework;
        struct app_led_t *led;
        struct led_t const *hwled;
        uint8_t i;
        
        switch (evt)
        {
        case VSFSM_EVT_INIT:
                // Application
                for (i = 0; i < app->led_num; i++)
                {
                        led = &app->led[i];
                        hwled = led->hw;
                        
                        led->on = false;
                        led->pt.thread = app_led_thread;
                        led->pt.user_data = led;
                        led->sm_carry = (i < (app->led_num - 1)) ? &app->led[i + 1].sm : NULL;
                        led->app = app;
                        
                        ifs->gpio.init(hwled->lport);
                        ifs->gpio.clear(hwled->lport, 1 << hwled->lpin);
                        ifs->gpio.config_pin(hwled->lport, hwled->lpin, ifs->gpio.constants.OUTPP);
                        ifs->gpio.init(hwled->hport);
                        ifs->gpio.clear(hwled->hport, 1 << hwled->hpin);
                        ifs->gpio.config_pin(hwled->hport, hwled->hpin, ifs->gpio.constants.OUTPP);
                        
                        framework->pt_init(&led->sm, &led->pt);
                }
               
                app->timer.interval = 1;
                app->timer.evt = LED_EVT_CARRY;
                app->timer.sm = sm;
                framework->timer_register(&app->timer);
                break;
        case LED_EVT_CARRY:
                framework->post_evt(&app->led[0].sm, LED_EVT_CARRY);
                break;
        }
        return NULL;
}

vsf_err_t __iar_program_start(struct vsf_t const *vsf, struct app_hwcfg_t const *hwcfg)
{
        int i;
        struct vsfapp_t *app = vsf->buffer.bufmgr.malloc(sizeof(struct vsfapp_t));
        
        if (NULL == app)
        {
                return VSFERR_NOT_ENOUGH_RESOURCES;
        }
        
        memset(app, 0, sizeof(*app));
        app->sys.vsf = vsf;
        app->led_num = dimof(hwcfg->led);
        for (i = 0; i < app->led_num; i++)
        {
                app->led[i].hw = &hwcfg->led[i];
        }
        
        app->sm.init_state.evt_handler = app_evt_handler;
        app->sm.user_data = app;
        vsf->framework.sm_init(&app->sm);
        return VSFERR_NONE;
}
应用程序里,定义了struct vsfapp_t结构,但是并没有使用静态分配的内存,所以应用程序编译后,只占用flash,不占用ram。运行应用程序的main后,调用vsf提供的内存管理接口,分配app的内存,并设置给相应的结构。应用中,并没有实现main函数,而是实现了__iar_program_start,这个是iar的程序入口,如果实现这个的话,IAR就不会自己添加调用main的代码(因为main是在系统里调用的,不需要程序自己调用),这里可以认为__iar_program_start就是应用的main函数。应用中的其他部分,都只是访问指向app内存的指针,来访问内存资源。当然,还有一个,就是编译后的镜像的第一个32为,需要是main函数的指针,IAR下可以这么实现,在startup.s文件中:
        SECTION .entry:CODE:ROOT(4)
        EXTERN  __iar_program_start
        DATA
        DCD     __iar_program_start
        END
并且,在linker文件中,把这个放在地址0。

相关帖子

沙发
mmuuss586| | 2015-8-6 12:32 | 只看该作者

似乎和ST版块没啥关系

使用特权

评论回复
板凳
Simon21ic|  楼主 | 2015-8-6 12:39 | 只看该作者
mmuuss586 发表于 2015-8-6 12:32
似乎和ST版块没啥关系

不知道应该发那个板块,帮我移一下吧

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:www.versaloon.com --- under construction

266

主题

2597

帖子

104

粉丝