module.c 38.3 KB
Newer Older
qiuyiuestc's avatar
qiuyiuestc 已提交
1 2 3
/*
 * File      : module.c
 * This file is part of RT-Thread RTOS
D
dzzxzz 已提交
4
 * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
qiuyiuestc's avatar
qiuyiuestc 已提交
5
 *
B
Bernard Xiong 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
qiuyiuestc's avatar
qiuyiuestc 已提交
19 20
 *
 * Change Logs:
D
dzzxzz 已提交
21 22 23 24 25 26
 * Date           Author       Notes
 * 2010-01-09     Bernard      first version
 * 2010-04-09     yi.qiu       implement based on first version
 * 2010-10-23     yi.qiu       implement module memory allocator
 * 2011-05-25     yi.qiu       implement module hook function
 * 2011-06-23     yi.qiu       rewrite module memory allocator
27
 * 2012-11-23     Bernard      using RT_DEBUG_LOG instead of rt_kprintf.
B
Bernard Xiong 已提交
28
 * 2012-11-28     Bernard      remove rt_current_module and user
29
 *                             can use rt_module_unload to remove a module.
30
 * 2017-08-20     parai        support intel 386 machine
qiuyiuestc's avatar
qiuyiuestc 已提交
31
 */
qiuyiuestc's avatar
qiuyiuestc 已提交
32

33
#include <rthw.h>
qiuyiuestc's avatar
qiuyiuestc 已提交
34
#include <rtthread.h>
qiuyiuestc's avatar
qiuyiuestc 已提交
35
#include <rtm.h>
qiuyiuestc's avatar
qiuyiuestc 已提交
36

37 38 39 40
#ifdef RT_USING_FINSH
#include <finsh.h>
#endif

qiuyiuestc's avatar
qiuyiuestc 已提交
41
#ifdef RT_USING_MODULE
42
#include "module.h"
qiuyiuestc's avatar
qiuyiuestc 已提交
43

44 45 46 47 48 49 50 51 52 53 54
#define elf_module        ((Elf32_Ehdr *)module_ptr)
#define shdr              ((Elf32_Shdr *)((rt_uint8_t *)module_ptr + elf_module->e_shoff))
#define phdr              ((Elf32_Phdr *)((rt_uint8_t *)module_ptr + elf_module->e_phoff))

#define IS_PROG(s)        (s.sh_type == SHT_PROGBITS)
#define IS_NOPROG(s)      (s.sh_type == SHT_NOBITS)
#define IS_REL(s)         (s.sh_type == SHT_REL)
#define IS_RELA(s)        (s.sh_type == SHT_RELA)
#define IS_ALLOC(s)       (s.sh_flags == SHF_ALLOC)
#define IS_AX(s)          ((s.sh_flags & SHF_ALLOC) && (s.sh_flags & SHF_EXECINSTR))
#define IS_AW(s)          ((s.sh_flags & SHF_ALLOC) && (s.sh_flags & SHF_WRITE))
qiuyiuestc's avatar
qiuyiuestc 已提交
55

56 57 58 59 60 61 62 63 64 65 66 67
#ifdef RT_USING_MODULE_STKSZ
#undef RT_USING_MODULE_STKSZ
#endif

#ifndef RT_USING_MODULE_STKSZ
#define RT_USING_MODULE_STKSZ (4096 * 2)
#endif

#ifndef RT_USING_MODULE_PRIO
#define RT_USING_MODULE_PRIO (RT_THREAD_PRIORITY_MAX - 2)
#endif

68
#ifdef RT_USING_SLAB
69
#define PAGE_COUNT_MAX    256
qiuyiuestc's avatar
qiuyiuestc 已提交
70

qiuyiuestc's avatar
qiuyiuestc 已提交
71 72 73
/* module memory allocator */
struct rt_mem_head
{
74 75
    rt_size_t size;                /* size of memory block */
    struct rt_mem_head *next;      /* next valid memory block */
qiuyiuestc's avatar
qiuyiuestc 已提交
76 77
};

qiuyiuestc's avatar
qiuyiuestc 已提交
78 79
struct rt_page_info
{
80 81
    rt_uint32_t *page_ptr;
    rt_uint32_t npage;
qiuyiuestc's avatar
qiuyiuestc 已提交
82 83 84
};

static void *rt_module_malloc_page(rt_size_t npages);
85 86 87
static void rt_module_free_page(rt_module_t module,
                                void       *page_ptr,
                                rt_size_t   npages);
qiuyiuestc's avatar
qiuyiuestc 已提交
88

qiuyiuestc's avatar
qiuyiuestc 已提交
89
static struct rt_semaphore mod_sem;
90 91
#endif

92
static struct rt_module_symtab *_rt_module_symtab_begin = RT_NULL;
93
static struct rt_module_symtab *_rt_module_symtab_end   = RT_NULL;
qiuyiuestc's avatar
qiuyiuestc 已提交
94

95 96 97 98
#if defined(__IAR_SYSTEMS_ICC__) /* for IAR compiler */
    #pragma section="RTMSymTab"
#endif

99 100 101
/**
 * @ingroup SystemInit
 *
B
bernard.xiong@gmail.com 已提交
102
 * This function will initialize system module
103
 */
B
bernard 已提交
104
int rt_system_module_init(void)
105
{
106
#if defined(__GNUC__) && !defined(__CC_ARM)
107 108
    extern int __rtmsymtab_start;
    extern int __rtmsymtab_end;
109

110 111
    _rt_module_symtab_begin = (struct rt_module_symtab *)&__rtmsymtab_start;
    _rt_module_symtab_end   = (struct rt_module_symtab *)&__rtmsymtab_end;
D
dzzxzz 已提交
112
#elif defined (__CC_ARM)
113 114
    extern int RTMSymTab$$Base;
    extern int RTMSymTab$$Limit;
D
dzzxzz 已提交
115

116
    _rt_module_symtab_begin = (struct rt_module_symtab *)&RTMSymTab$$Base;
117
    _rt_module_symtab_end   = (struct rt_module_symtab *)&RTMSymTab$$Limit;
118 119
#elif defined (__IAR_SYSTEMS_ICC__)
    _rt_module_symtab_begin = __section_begin("RTMSymTab");
120
    _rt_module_symtab_end   = __section_end("RTMSymTab");
qiuyiuestc's avatar
qiuyiuestc 已提交
121
#endif
122

123
    return 0;
124
}
B
Bernard Xiong 已提交
125
INIT_COMPONENT_EXPORT(rt_system_module_init);
126

127 128 129 130 131 132 133 134 135 136
#ifdef RT_USING_FINSH
void list_symbol(void)
{
    /* find in kernel symbol table */
    struct rt_module_symtab *index;

    for (index = _rt_module_symtab_begin;
         index != _rt_module_symtab_end;
         index ++)
    {
137
        rt_kprintf("%s => 0x%08x\n", index->name, index->addr);
138 139 140 141 142 143 144 145
    }

    return ;
}
FINSH_FUNCTION_EXPORT(list_symbol, list symbol for module);
MSH_CMD_EXPORT(list_symbol, list symbol for module);
#endif

D
dzzxzz 已提交
146
static rt_uint32_t rt_module_symbol_find(const char *sym_str)
147
{
148 149
    /* find in kernel symbol table */
    struct rt_module_symtab *index;
150 151 152 153

    for (index = _rt_module_symtab_begin;
         index != _rt_module_symtab_end;
         index ++)
154 155 156 157 158 159
    {
        if (rt_strcmp(index->name, sym_str) == 0)
            return (rt_uint32_t)index->addr;
    }

    return 0;
160
}
qiuyiuestc's avatar
qiuyiuestc 已提交
161

qiuyiuestc's avatar
qiuyiuestc 已提交
162 163 164
/**
 * This function will return self module object
 *
qiuyiuestc's avatar
qiuyiuestc 已提交
165
 * @return the self module object
qiuyiuestc's avatar
qiuyiuestc 已提交
166
 */
D
dzzxzz 已提交
167
rt_module_t rt_module_self(void)
qiuyiuestc's avatar
qiuyiuestc 已提交
168
{
169
    rt_thread_t tid;
qiuyiuestc's avatar
qiuyiuestc 已提交
170

171 172 173
    tid = rt_thread_self();
    if (tid == RT_NULL)
        return RT_NULL;
qiuyiuestc's avatar
qiuyiuestc 已提交
174

175 176
    /* return current module */
    return (rt_module_t)tid->module_id;
qiuyiuestc's avatar
qiuyiuestc 已提交
177
}
178
RTM_EXPORT(rt_module_self);
qiuyiuestc's avatar
qiuyiuestc 已提交
179

180 181 182
static int rt_module_arm_relocate(struct rt_module *module,
                                  Elf32_Rel        *rel,
                                  Elf32_Addr        sym_val)
qiuyiuestc's avatar
qiuyiuestc 已提交
183
{
184 185 186 187
    Elf32_Addr *where, tmp;
    Elf32_Sword addend, offset;
    rt_uint32_t upper, lower, sign, j1, j2;

188 189 190
    where = (Elf32_Addr *)((rt_uint8_t *)module->module_space
                           + rel->r_offset
                           - module->vstart_addr);
191 192 193 194 195 196
    switch (ELF32_R_TYPE(rel->r_info))
    {
    case R_ARM_NONE:
        break;
    case R_ARM_ABS32:
        *where += (Elf32_Addr)sym_val;
197 198
        RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_ABS32: %x -> %x\n",
                                       where, *where));
199 200 201 202 203 204 205 206 207 208 209
        break;
    case R_ARM_PC24:
    case R_ARM_PLT32:
    case R_ARM_CALL:
    case R_ARM_JUMP24:
        addend = *where & 0x00ffffff;
        if (addend & 0x00800000)
            addend |= 0xff000000;
        tmp = sym_val - (Elf32_Addr)where + (addend << 2);
        tmp >>= 2;
        *where = (*where & 0xff000000) | (tmp & 0x00ffffff);
210 211
        RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_PC24: %x -> %x\n",
                                       where, *where));
212 213 214
        break;
    case R_ARM_REL32:
        *where += sym_val - (Elf32_Addr)where;
215 216 217
        RT_DEBUG_LOG(RT_DEBUG_MODULE,
                     ("R_ARM_REL32: %x -> %x, sym %x, offset %x\n",
                      where, *where, sym_val, rel->r_offset));
218 219 220 221 222
        break;
    case R_ARM_V4BX:
        *where &= 0xf000000f;
        *where |= 0x01a0f000;
        break;
223 224 225 226
#ifdef MODULE_USING_386
    case R_386_GLOB_DAT:
    case R_386_JUMP_SLOT:
#endif
227 228 229
    case R_ARM_GLOB_DAT:
    case R_ARM_JUMP_SLOT:
        *where = (Elf32_Addr)sym_val;
230 231
        RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_JUMP_SLOT: 0x%x -> 0x%x 0x%x\n",
                                       where, *where, sym_val));
232 233 234
        break;
#if 0        /* To do */
    case R_ARM_GOT_BREL:
235
        temp   = (Elf32_Addr)sym_val;
236
        *where = (Elf32_Addr)&temp;
237 238
        RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_GOT_BREL: 0x%x -> 0x%x 0x%x\n",
                                       where, *where, sym_val));
239
        break;
240 241 242
#endif
#ifdef MODULE_USING_386
    case R_386_RELATIVE:
B
bernard.xiong@gmail.com 已提交
243
#endif
244 245
    case R_ARM_RELATIVE:
        *where = (Elf32_Addr)sym_val + *where;
246 247
        RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_RELATIVE: 0x%x -> 0x%x 0x%x\n",
                                       where, *where, sym_val));
248 249 250
        break;
    case R_ARM_THM_CALL:
    case R_ARM_THM_JUMP24:
251 252 253 254 255 256 257
        upper  = *(rt_uint16_t *)where;
        lower  = *(rt_uint16_t *)((Elf32_Addr)where + 2);

        sign   = (upper >> 10) & 1;
        j1     = (lower >> 13) & 1;
        j2     = (lower >> 11) & 1;
        offset = (sign << 24) |
258 259 260 261
                 ((~(j1 ^ sign) & 1) << 23) |
                 ((~(j2 ^ sign) & 1) << 22) |
                 ((upper & 0x03ff) << 12) |
                 ((lower & 0x07ff) << 1);
262
        if (offset & 0x01000000)
263
            offset -= 0x02000000;
264 265
        offset += sym_val - (Elf32_Addr)where;

266 267 268
        if (!(offset & 1) ||
            offset <= (rt_int32_t)0xff000000 ||
            offset >= (rt_int32_t)0x01000000)
269
        {
270
            rt_kprintf("Module: Only Thumb addresses allowed\n");
271

272 273 274 275
            return -1;
        }

        sign = (offset >> 24) & 1;
276 277 278
        j1   = sign ^ (~(offset >> 23) & 1);
        j2   = sign ^ (~(offset >> 22) & 1);
        *(rt_uint16_t *)where = (rt_uint16_t)((upper & 0xf800) |
279 280
                                              (sign << 10) |
                                              ((offset >> 12) & 0x03ff));
281
        *(rt_uint16_t *)(where + 2) = (rt_uint16_t)((lower & 0xd000) |
282 283
                                                    (j1 << 13) | (j2 << 11) |
                                                    ((offset >> 1) & 0x07ff));
284 285 286 287 288 289 290 291
        upper = *(rt_uint16_t *)where;
        lower = *(rt_uint16_t *)((Elf32_Addr)where + 2);
        break;
    default:
        return -1;
    }

    return 0;
qiuyiuestc's avatar
qiuyiuestc 已提交
292 293
}

qiuyiuestc's avatar
qiuyiuestc 已提交
294 295 296 297 298 299 300
#ifdef RT_USING_HOOK
static void (*rt_module_load_hook)(rt_module_t module);
static void (*rt_module_unload_hook)(rt_module_t module);

/**
 * @addtogroup Hook
 */
D
dzzxzz 已提交
301

D
dogandog 已提交
302
/**@{*/
qiuyiuestc's avatar
qiuyiuestc 已提交
303 304 305 306 307 308 309 310 311

/**
 * This function will set a hook function, which will be invoked when module
 * be loaded to system.
 *
 * @param hook the hook function
 */
void rt_module_load_sethook(void (*hook)(rt_module_t module))
{
312
    rt_module_load_hook = hook;
qiuyiuestc's avatar
qiuyiuestc 已提交
313 314 315 316 317 318 319 320 321 322
}

/**
 * This function will set a hook function, which will be invoked when module
 * be unloaded from system.
 *
 * @param hook the hook function
 */
void rt_module_unload_sethook(void (*hook)(rt_module_t module))
{
323
    rt_module_unload_hook = hook;
qiuyiuestc's avatar
qiuyiuestc 已提交
324 325
}

D
dogandog 已提交
326
/**@}*/
qiuyiuestc's avatar
qiuyiuestc 已提交
327 328
#endif

329 330
static struct rt_module *_load_shared_object(const char *name,
                                             void       *module_ptr)
qiuyiuestc's avatar
qiuyiuestc 已提交
331
{
332
    rt_module_t module = RT_NULL;
333
    rt_bool_t linked   = RT_FALSE;
334
    rt_uint32_t index, module_size = 0;
335 336
    Elf32_Addr vstart_addr, vend_addr;
    rt_bool_t has_vstart;
337 338 339

    RT_ASSERT(module_ptr != RT_NULL);

340
    if (rt_memcmp(elf_module->e_ident, RTMMAG, SELFMAG) == 0)
341 342 343 344
    {
        /* rtmlinker finished */
        linked = RT_TRUE;
    }
345

346
    /* get the ELF image size */
347 348
    has_vstart = RT_FALSE;
    vstart_addr = vend_addr = RT_NULL;
349 350
    for (index = 0; index < elf_module->e_phnum; index++)
    {
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
        if (phdr[index].p_type != PT_LOAD)
            continue;

        RT_DEBUG_LOG(RT_DEBUG_MODULE, ("LOAD segment: %d, 0x%p, 0x%08x\n",
                                       index, phdr[index].p_vaddr, phdr[index].p_memsz));

        if (phdr[index].p_memsz < phdr[index].p_filesz)
        {
            rt_kprintf("invalid elf: segment %d: p_memsz: %d, p_filesz: %d\n",
                       index, phdr[index].p_memsz, phdr[index].p_filesz);
            return RT_NULL;
        }
        if (!has_vstart)
        {
            vstart_addr = phdr[index].p_vaddr;
            vend_addr = phdr[index].p_vaddr + phdr[index].p_memsz;
            has_vstart = RT_TRUE;
            if (vend_addr < vstart_addr)
            {
                rt_kprintf("invalid elf: segment %d: p_vaddr: %d, p_memsz: %d\n",
                           index, phdr[index].p_vaddr, phdr[index].p_memsz);
                return RT_NULL;
            }
        }
        else
        {
            if (phdr[index].p_vaddr < vend_addr)
            {
                rt_kprintf("invalid elf: segment should be sorted and not overlapped\n");
                return RT_NULL;
            }
            if (phdr[index].p_vaddr > vend_addr + 16)
            {
                /* There should not be too much padding in the object files. */
                rt_kprintf("warning: too much padding before segment %d\n", index);
            }

            vend_addr = phdr[index].p_vaddr + phdr[index].p_memsz;
            if (vend_addr < phdr[index].p_vaddr)
            {
                rt_kprintf("invalid elf: "
                           "segment %d address overflow\n", index);
                return RT_NULL;
            }
        }
396 397
    }

398 399 400 401 402
    module_size = vend_addr - vstart_addr;

    RT_DEBUG_LOG(RT_DEBUG_MODULE, ("module size: %d, vstart_addr: 0x%p\n",
                                   module_size, vstart_addr));

403 404
    if (module_size == 0)
    {
405
        rt_kprintf("Module: size error\n");
406

407
        return RT_NULL;
408
    }
409 410

    /* allocate module */
411 412 413 414
    module = (struct rt_module *)rt_object_allocate(RT_Object_Class_Module,
                                                    name);
    if (!module)
        return RT_NULL;
415

416 417
    module->vstart_addr = vstart_addr;

418
    module->nref = 0;
419

420 421 422 423
    /* allocate module space */
    module->module_space = rt_malloc(module_size);
    if (module->module_space == RT_NULL)
    {
424
        rt_kprintf("Module: allocate space failed.\n");
425 426 427 428 429 430
        rt_object_delete(&(module->parent));

        return RT_NULL;
    }

    /* zero all space */
431
    rt_memset(module->module_space, 0, module_size);
432 433 434 435 436

    for (index = 0; index < elf_module->e_phnum; index++)
    {
        if (phdr[index].p_type == PT_LOAD)
        {
437
            rt_memcpy(module->module_space + phdr[index].p_vaddr - vstart_addr,
438 439
                      (rt_uint8_t *)elf_module + phdr[index].p_offset,
                      phdr[index].p_filesz);
440 441
        }
    }
442 443

    /* set module entry */
444
    module->module_entry = module->module_space
445
                           + elf_module->e_entry - vstart_addr;
446

447 448 449 450 451 452 453 454
    /* handle relocation section */
    for (index = 0; index < elf_module->e_shnum; index ++)
    {
        rt_uint32_t i, nr_reloc;
        Elf32_Sym *symtab;
        Elf32_Rel *rel;
        rt_uint8_t *strtab;
        static rt_bool_t unsolved = RT_FALSE;
455

456 457
        if (!IS_REL(shdr[index]))
            continue;
458 459 460 461 462

        /* get relocate item */
        rel = (Elf32_Rel *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset);

        /* locate .rel.plt and .rel.dyn section */
463 464 465
        symtab = (Elf32_Sym *)((rt_uint8_t *)module_ptr +
                               shdr[shdr[index].sh_link].sh_offset);
        strtab = (rt_uint8_t *)module_ptr +
466
                 shdr[shdr[shdr[index].sh_link].sh_link].sh_offset;
467
        nr_reloc = (rt_uint32_t)(shdr[index].sh_size / sizeof(Elf32_Rel));
468 469 470 471 472 473

        /* relocate every items */
        for (i = 0; i < nr_reloc; i ++)
        {
            Elf32_Sym *sym = &symtab[ELF32_R_SYM(rel->r_info)];

474 475 476
            RT_DEBUG_LOG(RT_DEBUG_MODULE, ("relocate symbol %s shndx %d\n",
                                           strtab + sym->st_name,
                                           sym->st_shndx));
477

478
            if ((sym->st_shndx != SHT_NULL) ||
479 480 481 482
                (ELF_ST_BIND(sym->st_info) == STB_LOCAL)
#ifdef MODULE_USING_386
                || ( (ELF_ST_BIND(sym->st_info) == STB_GLOBAL) && (ELF_ST_TYPE(sym->st_info) == STT_OBJECT) )
#endif
483
               )
484
            {
485
                rt_module_arm_relocate(module, rel,
486 487 488
                                       (Elf32_Addr)(module->module_space
                                                    + sym->st_value
                                                    - vstart_addr));
489
            }
490
            else if (!linked)
491 492 493
            {
                Elf32_Addr addr;

494 495
                RT_DEBUG_LOG(RT_DEBUG_MODULE, ("relocate symbol: %s\n",
                                               strtab + sym->st_name));
496 497 498 499 500

                /* need to resolve symbol in kernel symbol table */
                addr = rt_module_symbol_find((const char *)(strtab + sym->st_name));
                if (addr == 0)
                {
501
                    rt_kprintf("Module: can't find %s in kernel symbol table\n",
502
                               strtab + sym->st_name);
503
                    unsolved = RT_TRUE;
504
                }
505 506 507 508 509 510 511 512 513 514 515
                else
                    rt_module_arm_relocate(module, rel, addr);
            }
            rel ++;
        }

        if (unsolved)
        {
            rt_object_delete(&(module->parent));

            return RT_NULL;
516
        }
517 518 519 520
    }

    /* construct module symbol table */
    for (index = 0; index < elf_module->e_shnum; index ++)
521
    {
522
        /* find .dynsym section */
523
        rt_uint8_t *shstrab;
524
        shstrab = (rt_uint8_t *)module_ptr +
525
                  shdr[elf_module->e_shstrndx].sh_offset;
526 527 528 529 530 531 532 533
        if (rt_strcmp((const char *)(shstrab + shdr[index].sh_name), ELF_DYNSYM) == 0)
            break;
    }

    /* found .dynsym section */
    if (index != elf_module->e_shnum)
    {
        int i, count = 0;
534
        Elf32_Sym  *symtab = RT_NULL;
535 536
        rt_uint8_t *strtab = RT_NULL;

537
        symtab = (Elf32_Sym *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset);
538 539
        strtab = (rt_uint8_t *)module_ptr + shdr[shdr[index].sh_link].sh_offset;

540
        for (i = 0; i < shdr[index].sh_size / sizeof(Elf32_Sym); i++)
541
        {
542
            if ((ELF_ST_BIND(symtab[i].st_info) == STB_GLOBAL) &&
543 544 545 546 547
                (ELF_ST_TYPE(symtab[i].st_info) == STT_FUNC))
                count ++;
        }

        module->symtab = (struct rt_module_symtab *)rt_malloc
548
                         (count * sizeof(struct rt_module_symtab));
549
        module->nsym = count;
550
        for (i = 0, count = 0; i < shdr[index].sh_size / sizeof(Elf32_Sym); i++)
551 552
        {
            rt_size_t length;
553 554

            if ((ELF_ST_BIND(symtab[i].st_info) != STB_GLOBAL) ||
555 556
                (ELF_ST_TYPE(symtab[i].st_info) != STT_FUNC))
                continue;
557 558 559

            length = rt_strlen((const char *)(strtab + symtab[i].st_name)) + 1;

560
            module->symtab[count].addr =
561
                (void *)(module->module_space + symtab[i].st_value - module->vstart_addr);
562 563
            module->symtab[count].name = rt_malloc(length);
            rt_memset((void *)module->symtab[count].name, 0, length);
564
            rt_memcpy((void *)module->symtab[count].name,
565 566
                      strtab + symtab[i].st_name,
                      length);
567
            count ++;
568
        }
569 570 571
    }

    return module;
572 573
}

574 575
static struct rt_module* _load_relocated_object(const char *name,
                                                void       *module_ptr)
576
{
577 578 579 580 581 582
    rt_uint32_t index, rodata_addr = 0, bss_addr = 0, data_addr = 0;
    rt_uint32_t module_addr = 0, module_size = 0;
    struct rt_module *module = RT_NULL;
    rt_uint8_t *ptr, *strtab, *shstrab;

    /* get the ELF image size */
583
    for (index = 0; index < elf_module->e_shnum; index ++)
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
    {
        /* text */
        if (IS_PROG(shdr[index]) && IS_AX(shdr[index]))
        {
            module_size += shdr[index].sh_size;
            module_addr = shdr[index].sh_addr;
        }
        /* rodata */
        if (IS_PROG(shdr[index]) && IS_ALLOC(shdr[index]))
        {
            module_size += shdr[index].sh_size;
        }
        /* data */
        if (IS_PROG(shdr[index]) && IS_AW(shdr[index]))
        {
            module_size += shdr[index].sh_size;
        }
        /* bss */
        if (IS_NOPROG(shdr[index]) && IS_AW(shdr[index]))
        {
            module_size += shdr[index].sh_size;
        }
    }

    /* no text, data and bss on image */
    if (module_size == 0)
        return RT_NULL;

    /* allocate module */
613
    module = (struct rt_module *)
614
             rt_object_allocate(RT_Object_Class_Module, (const char *)name);
615 616 617
    if (module == RT_NULL)
        return RT_NULL;

618 619
    module->vstart_addr = 0;

620 621 622 623
    /* allocate module space */
    module->module_space = rt_malloc(module_size);
    if (module->module_space == RT_NULL)
    {
624
        rt_kprintf("Module: allocate space failed.\n");
625 626 627 628 629 630 631 632 633 634
        rt_object_delete(&(module->parent));

        return RT_NULL;
    }

    /* zero all space */
    ptr = module->module_space;
    rt_memset(ptr, 0, module_size);

    /* load text and data section */
635
    for (index = 0; index < elf_module->e_shnum; index ++)
636 637 638 639
    {
        /* load text section */
        if (IS_PROG(shdr[index]) && IS_AX(shdr[index]))
        {
640 641 642
            rt_memcpy(ptr,
                      (rt_uint8_t *)elf_module + shdr[index].sh_offset,
                      shdr[index].sh_size);
643 644
            RT_DEBUG_LOG(RT_DEBUG_MODULE, ("load text 0x%x, size %d\n",
                                           ptr, shdr[index].sh_size));
645 646 647 648 649 650
            ptr += shdr[index].sh_size;
        }

        /* load rodata section */
        if (IS_PROG(shdr[index]) && IS_ALLOC(shdr[index]))
        {
651 652 653
            rt_memcpy(ptr,
                      (rt_uint8_t *)elf_module + shdr[index].sh_offset,
                      shdr[index].sh_size);
654
            rodata_addr = (rt_uint32_t)ptr;
655 656 657
            RT_DEBUG_LOG(RT_DEBUG_MODULE,
                         ("load rodata 0x%x, size %d, rodata 0x%x\n",
                          ptr, shdr[index].sh_size, *(rt_uint32_t *)data_addr));
658 659 660 661 662 663
            ptr += shdr[index].sh_size;
        }

        /* load data section */
        if (IS_PROG(shdr[index]) && IS_AW(shdr[index]))
        {
664 665 666
            rt_memcpy(ptr,
                      (rt_uint8_t *)elf_module + shdr[index].sh_offset,
                      shdr[index].sh_size);
667
            data_addr = (rt_uint32_t)ptr;
668 669 670
            RT_DEBUG_LOG(RT_DEBUG_MODULE,
                         ("load data 0x%x, size %d, data 0x%x\n",
                          ptr, shdr[index].sh_size, *(rt_uint32_t *)data_addr));
671 672 673 674 675 676 677 678
            ptr += shdr[index].sh_size;
        }

        /* load bss section */
        if (IS_NOPROG(shdr[index]) && IS_AW(shdr[index]))
        {
            rt_memset(ptr, 0, shdr[index].sh_size);
            bss_addr = (rt_uint32_t)ptr;
679 680
            RT_DEBUG_LOG(RT_DEBUG_MODULE, ("load bss 0x%x, size %d,\n",
                                           ptr, shdr[index].sh_size));
681 682 683 684
        }
    }

    /* set module entry */
685 686
    module->module_entry =
        (rt_uint8_t *)module->module_space + elf_module->e_entry - module_addr;
687 688 689 690 691 692 693

    /* handle relocation section */
    for (index = 0; index < elf_module->e_shnum; index ++)
    {
        rt_uint32_t i, nr_reloc;
        Elf32_Sym *symtab;
        Elf32_Rel *rel;
694

695 696
        if (!IS_REL(shdr[index]))
            continue;
697

698
        /* get relocate item */
699
        rel = (Elf32_Rel *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset);
700 701

        /* locate .dynsym and .dynstr */
702
        symtab   = (Elf32_Sym *)((rt_uint8_t *)module_ptr +
703
                                 shdr[shdr[index].sh_link].sh_offset);
704
        strtab   = (rt_uint8_t *)module_ptr +
705
                   shdr[shdr[shdr[index].sh_link].sh_link].sh_offset;
706
        shstrab  = (rt_uint8_t *)module_ptr +
707
                   shdr[elf_module->e_shstrndx].sh_offset;
708
        nr_reloc = (rt_uint32_t)(shdr[index].sh_size / sizeof(Elf32_Rel));
709 710 711 712 713

        /* relocate every items */
        for (i = 0; i < nr_reloc; i ++)
        {
            Elf32_Sym *sym = &symtab[ELF32_R_SYM(rel->r_info)];
714

715 716
            RT_DEBUG_LOG(RT_DEBUG_MODULE, ("relocate symbol: %s\n",
                                           strtab + sym->st_name));
717 718 719

            if (sym->st_shndx != STN_UNDEF)
            {
720 721
                if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) ||
                    (ELF_ST_TYPE(sym->st_info) == STT_OBJECT))
722
                {
723
                    if (rt_strncmp((const char *)(shstrab +
724
                                                  shdr[sym->st_shndx].sh_name), ELF_RODATA, 8) == 0)
725 726
                    {
                        /* relocate rodata section */
727
                        RT_DEBUG_LOG(RT_DEBUG_MODULE, ("rodata\n"));
728
                        rt_module_arm_relocate(module, rel,
729
                                               (Elf32_Addr)(rodata_addr + sym->st_value));
730
                    }
731
                    else if (rt_strncmp((const char *)
732
                                        (shstrab + shdr[sym->st_shndx].sh_name), ELF_BSS, 5) == 0)
733 734
                    {
                        /* relocate bss section */
735
                        RT_DEBUG_LOG(RT_DEBUG_MODULE, ("bss\n"));
736
                        rt_module_arm_relocate(module, rel,
737
                                               (Elf32_Addr)bss_addr + sym->st_value);
738
                    }
739
                    else if (rt_strncmp((const char *)(shstrab + shdr[sym->st_shndx].sh_name),
740
                                        ELF_DATA, 6) == 0)
741 742
                    {
                        /* relocate data section */
743
                        RT_DEBUG_LOG(RT_DEBUG_MODULE, ("data\n"));
744
                        rt_module_arm_relocate(module, rel,
745
                                               (Elf32_Addr)data_addr + sym->st_value);
746 747
                    }
                }
748 749 750 751 752 753 754 755 756
                else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC)
                {
                    /* relocate function */
                    rt_module_arm_relocate(module, rel,
                                           (Elf32_Addr)((rt_uint8_t *)
                                                        module->module_space
                                                        - module_addr
                                                        + sym->st_value));
                }
757
            }
758
            else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC)
759 760
            {
                /* relocate function */
761 762 763 764 765
                rt_module_arm_relocate(module, rel,
                                       (Elf32_Addr)((rt_uint8_t *)
                                                    module->module_space
                                                    - module_addr
                                                    + sym->st_value));
766 767 768 769 770
            }
            else
            {
                Elf32_Addr addr;

771
                if (ELF32_R_TYPE(rel->r_info) != R_ARM_V4BX)
772
                {
773 774
                    RT_DEBUG_LOG(RT_DEBUG_MODULE, ("relocate symbol: %s\n",
                                                   strtab + sym->st_name));
775

776
                    /* need to resolve symbol in kernel symbol table */
777
                    addr = rt_module_symbol_find((const char *)(strtab + sym->st_name));
778 779 780
                    if (addr != (Elf32_Addr)RT_NULL)
                    {
                        rt_module_arm_relocate(module, rel, addr);
781 782
                        RT_DEBUG_LOG(RT_DEBUG_MODULE, ("symbol addr 0x%x\n",
                                                       addr));
783 784
                    }
                    else
785
                        rt_kprintf("Module: can't find %s in kernel symbol table\n",
786
                                   strtab + sym->st_name);
787 788 789
                }
                else
                {
790
                    rt_module_arm_relocate(module, rel,
791
                                           (Elf32_Addr)((rt_uint8_t *)
792 793 794
                                                        module->module_space
                                                        - module_addr
                                                        + sym->st_value));
795 796 797 798 799 800 801
                }
            }
            rel ++;
        }
    }

    return module;
802 803
}

804
#define RT_MODULE_ARG_MAX    8
805
static int _rt_module_split_arg(char *cmd, rt_size_t length, char *argv[])
806 807 808 809 810 811 812
{
    int argc = 0;
    char *ptr = cmd;

    while ((ptr - cmd) < length)
    {
        /* strip bank and tab */
813
        while ((*ptr == ' ' || *ptr == '\t') && (ptr - cmd) < length)
814 815
            *ptr++ = '\0';
        /* check whether it's the end of line */
816
        if ((ptr - cmd) >= length) break;
817 818 819 820 821 822 823

        /* handle string with quote */
        if (*ptr == '"')
        {
            argv[argc++] = ++ptr;

            /* skip this string */
824
            while (*ptr != '"' && (ptr - cmd) < length)
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
                if (*ptr ++ == '\\')  ptr ++;
            if ((ptr - cmd) >= length) break;

            /* skip '"' */
            *ptr ++ = '\0';
        }
        else
        {
            argv[argc++] = ptr;
            while ((*ptr != ' ' && *ptr != '\t') && (ptr - cmd) < length)
                ptr ++;
        }

        if (argc >= RT_MODULE_ARG_MAX) break;
    }

    return argc;
}

/* module main thread entry */
845
static void module_main_entry(void *parameter)
846 847 848
{
    int argc;
    char *argv[RT_MODULE_ARG_MAX];
849
    typedef int (*main_func_t)(int argc, char **argv);
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870

    rt_module_t module = (rt_module_t) parameter;
    if (module == RT_NULL)
        return;

    if (module->module_cmd_line == RT_NULL && module->module_cmd_size != 0)
        /* malloc for module_cmd_line failed. */
        return;

    /* FIXME: we should run some C++ initialize code before jump into the
     * entry. */

    if (module->module_cmd_line == RT_NULL)
    {
        RT_DEBUG_LOG(RT_DEBUG_MODULE, ("run bare entry: 0x%p\n",
                                       module->module_entry));
        ((main_func_t)module->module_entry)(0, RT_NULL);
        return;
    }

    rt_memset(argv, 0x00, sizeof(argv));
871
    argc = _rt_module_split_arg((char *)module->module_cmd_line,
872 873 874 875 876 877 878 879 880 881 882 883
                                module->module_cmd_size, argv);
    if (argc == 0)
        return;

    RT_DEBUG_LOG(RT_DEBUG_MODULE, ("run main entry: 0x%p with %s\n",
                                   module->module_entry,
                                   module->module_cmd_line));
    /* do the main function */
    ((main_func_t)module->module_entry)(argc, argv);
    return;
}

884
/**
885
 * This function will load a module with a main function from memory and create a
886
 * main thread for it
887 888 889
 *
 * @param name the name of module, which shall be unique
 * @param module_ptr the memory address of module image
890
 * @argc the count of argument
891
 * @argd the argument data, which should be a
892 893 894
 *
 * @return the module object
 */
895 896
rt_module_t rt_module_do_main(const char *name,
                              void *module_ptr,
897
                              const char *cmd_line,
898
                              int line_size)
899
{
900 901 902 903
    rt_module_t module;

    RT_DEBUG_NOT_IN_INTERRUPT;

904
    RT_DEBUG_LOG(RT_DEBUG_MODULE, ("rt_module_load: %s\n", name));
905 906

    /* check ELF header */
907 908
    if (rt_memcmp(elf_module->e_ident, RTMMAG, SELFMAG) != 0 &&
        rt_memcmp(elf_module->e_ident, ELFMAG, SELFMAG) != 0)
909
    {
910
        rt_kprintf("Module: magic error\n");
911 912 913 914 915

        return RT_NULL;
    }

    /* check ELF class */
916
    if (elf_module->e_ident[EI_CLASS] != ELFCLASS32)
917
    {
918
        rt_kprintf("Module: ELF class error\n");
919 920 921 922

        return RT_NULL;
    }

923
    if (elf_module->e_type == ET_REL)
924 925 926
    {
        module = _load_relocated_object(name, module_ptr);
    }
927
    else if (elf_module->e_type == ET_DYN)
928 929 930 931 932
    {
        module = _load_shared_object(name, module_ptr);
    }
    else
    {
933
        rt_kprintf("Module: unsupported elf type\n");
934 935 936 937

        return RT_NULL;
    }

938
    if (module == RT_NULL)
939 940
        return RT_NULL;

941 942 943
    if (line_size && cmd_line)
    {
        /* set module argument */
944
        module->module_cmd_line = (rt_uint8_t *)rt_malloc(line_size + 1);
945 946 947 948 949 950 951 952 953 954 955 956 957 958
        if (module->module_cmd_line)
        {
            rt_memcpy(module->module_cmd_line, cmd_line, line_size);
            module->module_cmd_line[line_size] = '\0';
        }
        module->module_cmd_size = line_size;
    }
    else
    {
        /* initialize an empty command */
        module->module_cmd_line = RT_NULL;
        module->module_cmd_size = 0;
    }

959 960 961 962
    /* increase module reference count */
    module->nref ++;

    if (elf_module->e_entry != 0)
963 964
    {
        /* create module thread */
965
        module->module_thread = rt_thread_create(name,
966 967 968
                                                 module_main_entry, module,
                                                 RT_USING_MODULE_STKSZ,
                                                 RT_USING_MODULE_PRIO, 10);
969

970 971
        RT_DEBUG_LOG(RT_DEBUG_MODULE, ("thread entry 0x%x\n",
                                       module->module_entry));
972 973 974

        /* set module id */
        module->module_thread->module_id = (void *)module;
975 976 977 978
        module->parent.flag = RT_MODULE_FLAG_WITHENTRY;

        /* startup module thread */
        rt_thread_startup(module->module_thread);
979
    }
980 981 982 983
    else
    {
        /* without entry point */
        module->parent.flag |= RT_MODULE_FLAG_WITHOUTENTRY;
984
    }
qiuyiuestc's avatar
qiuyiuestc 已提交
985

qiuyiuestc's avatar
qiuyiuestc 已提交
986
#ifdef RT_USING_HOOK
987 988 989 990
    if (rt_module_load_hook != RT_NULL)
    {
        rt_module_load_hook(module);
    }
qiuyiuestc's avatar
qiuyiuestc 已提交
991 992
#endif

993
    return module;
994 995
}

996
/**
997
 * This function will load a module from memory and create a thread for it
998 999 1000 1001 1002 1003
 *
 * @param name the name of module, which shall be unique
 * @param module_ptr the memory address of module image
 *
 * @return the module object
 */
1004
rt_module_t rt_module_load(const char *name, void *module_ptr)
1005
{
1006
    return rt_module_do_main(name, module_ptr, RT_NULL, 0);
1007 1008
}

1009 1010
#ifdef RT_USING_DFS
#include <dfs_posix.h>
qiuyiuestc's avatar
qiuyiuestc 已提交
1011

1012
static char *_module_name(const char *path)
qiuyiuestc's avatar
qiuyiuestc 已提交
1013
{
1014
    const char *first, *end, *ptr;
1015
    char *name;
qiuyiuestc's avatar
qiuyiuestc 已提交
1016
    int size;
1017

1018 1019 1020 1021 1022
    ptr   = (char *)path;
    first = ptr;
    end   = path + rt_strlen(path);

    while (*ptr != '\0')
qiuyiuestc's avatar
qiuyiuestc 已提交
1023
    {
1024 1025 1026 1027
        if (*ptr == '/')
            first = ptr + 1;
        if (*ptr == '.')
            end = ptr - 1;
1028

1029
        ptr ++;
qiuyiuestc's avatar
qiuyiuestc 已提交
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
    }

    size = end - first + 1;
    name = rt_malloc(size);
    rt_strncpy(name, first, size);
    name[size] = '\0';

    return name;
}

qiuyiuestc's avatar
qiuyiuestc 已提交
1040
/**
B
bernard.xiong@gmail.com 已提交
1041
 * This function will load a module from a file
qiuyiuestc's avatar
qiuyiuestc 已提交
1042
 *
B
bernard.xiong@gmail.com 已提交
1043
 * @param path the full path of application module
qiuyiuestc's avatar
qiuyiuestc 已提交
1044 1045 1046
 *
 * @return the module object
 */
D
dzzxzz 已提交
1047
rt_module_t rt_module_open(const char *path)
qiuyiuestc's avatar
qiuyiuestc 已提交
1048
{
1049 1050 1051 1052
    int fd, length;
    struct rt_module *module;
    struct stat s;
    char *buffer, *offset_ptr;
1053
    char *name;
1054 1055 1056 1057 1058 1059

    RT_DEBUG_NOT_IN_INTERRUPT;

    /* check parameters */
    RT_ASSERT(path != RT_NULL);

1060
    if (stat(path, &s) != 0)
1061
    {
1062
        rt_kprintf("Module: access %s failed\n", path);
1063 1064 1065 1066 1067 1068

        return RT_NULL;
    }
    buffer = (char *)rt_malloc(s.st_size);
    if (buffer == RT_NULL)
    {
1069
        rt_kprintf("Module: out of memory\n");
1070 1071 1072 1073 1074 1075 1076 1077

        return RT_NULL;
    }

    offset_ptr = buffer;
    fd = open(path, O_RDONLY, 0);
    if (fd < 0)
    {
1078
        rt_kprintf("Module: open %s failed\n", path);
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
        rt_free(buffer);

        return RT_NULL;
    }

    do
    {
        length = read(fd, offset_ptr, 4096);
        if (length > 0)
        {
            offset_ptr += length;
        }
    }while (length > 0);

    /* close fd */
    close(fd);

    if ((rt_uint32_t)offset_ptr - (rt_uint32_t)buffer != s.st_size)
    {
1098
        rt_kprintf("Module: read file failed\n");
1099 1100 1101 1102 1103
        rt_free(buffer);

        return RT_NULL;
    }

1104 1105
    name   = _module_name(path);
    module = rt_module_load(name, (void *)buffer);
1106
    rt_free(buffer);
qiuyiuestc's avatar
qiuyiuestc 已提交
1107
    rt_free(name);
1108 1109

    return module;
qiuyiuestc's avatar
qiuyiuestc 已提交
1110
}
qiuyiuestc's avatar
qiuyiuestc 已提交
1111

1112 1113 1114 1115
/**
 * This function will do a excutable program with main function and parameters.
 *
 * @param path the full path of application module
1116 1117
 * @param cmd_line the command line of program
 * @param size the size of command line of program
1118 1119 1120
 *
 * @return the module object
 */
1121
rt_module_t rt_module_exec_cmd(const char *path, const char *cmd_line, int size)
1122 1123 1124 1125 1126 1127
{
    struct stat s;
    int fd, length;
    char *name, *buffer, *offset_ptr;
    struct rt_module *module = RT_NULL;

1128
    name = buffer = RT_NULL;
1129 1130 1131 1132 1133 1134

    RT_DEBUG_NOT_IN_INTERRUPT;

    /* check parameters */
    RT_ASSERT(path != RT_NULL);

1135
    /* get file size */
1136
    if (stat(path, &s) != 0)
1137 1138 1139 1140 1141
    {
        rt_kprintf("Module: access %s failed\n", path);
        goto __exit;
    }

1142
    /* allocate buffer to save program */
1143 1144 1145 1146
    offset_ptr = buffer = (char *)rt_malloc(s.st_size);
    if (buffer == RT_NULL)
    {
        rt_kprintf("Module: out of memory\n");
1147
        goto __exit;
1148 1149 1150 1151 1152 1153
    }

    fd = open(path, O_RDONLY, 0);
    if (fd < 0)
    {
        rt_kprintf("Module: open %s failed\n", path);
1154
        goto __exit;
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
    }

    do
    {
        length = read(fd, offset_ptr, 4096);
        if (length > 0)
        {
            offset_ptr += length;
        }
    }while (length > 0);
    /* close fd */
    close(fd);

    if ((rt_uint32_t)offset_ptr - (rt_uint32_t)buffer != s.st_size)
    {
        rt_kprintf("Module: read file failed\n");
1171
        goto __exit;
1172 1173
    }

1174
    /* get module */
1175
    name   = _module_name(path);
1176
    /* execute module */
1177 1178 1179 1180 1181 1182 1183 1184 1185
    module = rt_module_do_main(name, (void *)buffer, cmd_line, size);

__exit:
    rt_free(buffer);
    rt_free(name);

    return module;
}

qiuyiuestc's avatar
qiuyiuestc 已提交
1186 1187
#if defined(RT_USING_FINSH)
#include <finsh.h>
1188
FINSH_FUNCTION_EXPORT_ALIAS(rt_module_open, exec, exec module from a file);
qiuyiuestc's avatar
qiuyiuestc 已提交
1189
#endif
1190

qiuyiuestc's avatar
qiuyiuestc 已提交
1191 1192
#endif

qiuyiuestc's avatar
qiuyiuestc 已提交
1193
/**
1194
 * This function will destroy a module and release its resource.
qiuyiuestc's avatar
qiuyiuestc 已提交
1195
 *
1196
 * @param module the module to be destroyed.
qiuyiuestc's avatar
qiuyiuestc 已提交
1197 1198 1199
 *
 * @return the operation status, RT_EOK on OK; -RT_ERROR on error
 */
1200
rt_err_t rt_module_destroy(rt_module_t module)
qiuyiuestc's avatar
qiuyiuestc 已提交
1201
{
1202 1203 1204 1205 1206 1207
    int i;

    RT_DEBUG_NOT_IN_INTERRUPT;

    /* check parameter */
    RT_ASSERT(module != RT_NULL);
1208
    RT_ASSERT(module->nref == 0);
1209

1210 1211
    RT_DEBUG_LOG(RT_DEBUG_MODULE, ("rt_module_destroy: %8.*s\n",
                                   RT_NAME_MAX, module->parent.name));
1212 1213 1214 1215

    /* module has entry point */
    if (!(module->parent.flag & RT_MODULE_FLAG_WITHOUTENTRY))
    {
1216 1217 1218 1219 1220
        /* delete command line */
        if (module->module_cmd_line != RT_NULL)
        {
            rt_free(module->module_cmd_line);
        }
1221
    }
qiuyiuestc's avatar
qiuyiuestc 已提交
1222

1223 1224
    /* release module space memory */
    rt_free(module->module_space);
qiuyiuestc's avatar
qiuyiuestc 已提交
1225

1226
    /* release module symbol table */
1227
    for (i = 0; i < module->nsym; i ++)
1228
    {
1229
        rt_free((void *)module->symtab[i].name);
1230
    }
1231 1232
    if (module->symtab != RT_NULL)
        rt_free(module->symtab);
qiuyiuestc's avatar
qiuyiuestc 已提交
1233

1234 1235
    /* delete module object */
    rt_object_delete((rt_object_t)module);
qiuyiuestc's avatar
qiuyiuestc 已提交
1236

1237
    return RT_EOK;
qiuyiuestc's avatar
qiuyiuestc 已提交
1238 1239
}

1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
/**
 * This function will unload a module from memory and release resources
 *
 * @param module the module to be unloaded
 *
 * @return the operation status, RT_EOK on OK; -RT_ERROR on error
 */
rt_err_t rt_module_unload(rt_module_t module)
{
    RT_DEBUG_NOT_IN_INTERRUPT;

    /* check parameter */
1252 1253
    if (module == RT_NULL)
        return -RT_ERROR;
1254

1255
    rt_enter_critical();
1256
    /* invoke module cleanup */
1257
    rt_exit_critical();
1258 1259

#ifdef RT_USING_HOOK
1260 1261 1262 1263
    if (rt_module_unload_hook != RT_NULL)
    {
        rt_module_unload_hook(module);
    }
1264 1265
#endif

1266
    return RT_EOK;
1267 1268
}

qiuyiuestc's avatar
qiuyiuestc 已提交
1269 1270 1271 1272 1273 1274 1275
/**
 * This function will find the specified module.
 *
 * @param name the name of module finding
 *
 * @return the module
 */
D
dzzxzz 已提交
1276
rt_module_t rt_module_find(const char *name)
qiuyiuestc's avatar
qiuyiuestc 已提交
1277
{
1278 1279 1280
    struct rt_object_information *information;
    struct rt_object *object;
    struct rt_list_node *node;
qiuyiuestc's avatar
qiuyiuestc 已提交
1281

1282
    RT_DEBUG_NOT_IN_INTERRUPT;
1283

1284 1285
    /* enter critical */
    rt_enter_critical();
B
bernard.xiong 已提交
1286

1287
    /* try to find device object */
1288 1289
    information = rt_object_get_information(RT_Object_Class_Module);
    RT_ASSERT(information != RT_NULL);
1290
    for (node = information->object_list.next;
1291 1292
         node != &(information->object_list);
         node = node->next)
1293 1294 1295 1296 1297 1298
    {
        object = rt_list_entry(node, struct rt_object, list);
        if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
        {
            /* leave critical */
            rt_exit_critical();
B
bernard.xiong 已提交
1299

1300 1301 1302
            return (rt_module_t)object;
        }
    }
B
bernard.xiong 已提交
1303

1304 1305
    /* leave critical */
    rt_exit_critical();
B
bernard.xiong 已提交
1306

1307 1308
    /* not found */
    return RT_NULL;
qiuyiuestc's avatar
qiuyiuestc 已提交
1309
}
1310
RTM_EXPORT(rt_module_find);
qiuyiuestc's avatar
qiuyiuestc 已提交
1311

qiuyiuestc's avatar
qiuyiuestc 已提交
1312
#endif