source: trunk/core/module_load.c @ 1610

Revision 1610, 14.8 KB checked in by philmoz, 16 months ago (diff)

Code cleanup:

  • re-factor rbf_font loading code to reduce number of functions being called (and simplify interface for text reader to rbf_font handler)
  • change draw_char to use compressed font data directly when drawing rather than unpack data into current_font array on startup (saves 3.5K of RAM)
  • use stat instead of open/close in module_check_is_exist
  • fix to prevent un-necessary loading of motion detect module when a script exits
  • Property svn:eol-style set to native
Line 
1/*
2 *   CHDK-FLAT Module System. 
3 *
4 *   (c)2011 Sergey Taranenko aka tsvstar
5 *
6 *   This is main file of module processing system. Module load/unload/service functions
7 */
8
9#include "stdlib.h"
10#include "console.h"
11#include "gui.h"
12#include "platform.h"
13
14#include "flt.h"
15#include "module_load.h"
16#include "module_exportlist.h"
17
18
19//********************************************************/
20//**    TEMPORARY FROM .H FILES   **
21//********************************************************/
22
23#define MAX_NUM_LOADED_MODULES 10
24#define BUFFER_FOR_READ_SIZE   4096
25
26//********************************************************/
27//**    Small library for safe io to cacheable memory   **
28//**  use smaller buffer then fopen so bigger could     **
29//**  be loaded                                                                             **
30//********************************************************/
31
32static char* buf_load=0;
33
34int b_read(int fd, char* buf, int len)
35{
36  if (buf_load==0) {
37    buf_load = umalloc( BUFFER_FOR_READ_SIZE );
38    if (buf_load==0)
39       return 0;
40  }
41  int loaded=0, now=1;
42
43  while (now && loaded<len)
44  {
45     now = len-loaded;
46     if ( now > BUFFER_FOR_READ_SIZE )
47       now = BUFFER_FOR_READ_SIZE;
48
49     now = read(fd,buf_load,now);
50     
51     memcpy(buf+loaded, buf_load, now);
52     loaded+=now;
53  }
54  return loaded;
55}
56
57void b_close(int fd)
58{
59  if (fd >=0 )
60  close(fd);
61
62  if (buf_load)
63   ufree(buf_load);
64  buf_load=0;
65}
66
67
68
69//********************************************************/
70//**       Auxilary module system functions             **
71//********************************************************/
72
73// array of pointer to loaded modules (NULL - slot is empty)
74static struct flat_hdr* modules[MAX_NUM_LOADED_MODULES];
75
76// >0- if correspondend module require to unload it
77static unsigned char module_unload_request[MAX_NUM_LOADED_MODULES];
78
79// =1- if correspondend module ask to unload it on exit from main menu
80static unsigned char module_flags[MAX_NUM_LOADED_MODULES];
81
82//-----------------------------------------------
83// Cut module name to 11 sym + make it uppercase
84//-----------------------------------------------
85static void flat_module_name_make( char* tgt, char* name )
86{
87        char *p=tgt;
88
89        for (; *name; name++ ){
90                if ( *name=='/') {
91                        p=tgt;
92                } else if ( (p-tgt) < 11 ) {
93                        *p=*name; p++;
94                }
95    }
96    *p=0;
97}
98
99//-----------------------------------------------
100// Do path to module
101//-----------------------------------------------
102static void flat_module_path_make( char* tgt, char* name )
103{
104        // check is name absolute path
105        if ( name[0]=='A' && name[1]=='/')
106                strcpy(tgt,name);
107        else
108   sprintf(tgt,"%s/%s",MODULES_PATH,name);
109}
110
111//-----------------------------------------------
112// PURPOSE: Find idx_loaded by module name or by module idx
113// RETURN: -1 if module not loaded yet, otherwise idx in modules[]
114//-----------------------------------------------
115int module_find(char * name )
116{
117   char namebuf[12];
118   int i = (uint32_t)name;
119
120   // Check if given parameter is idx
121   if (i < MAX_NUM_LOADED_MODULES)
122    return (modules[i] ? i : -1);
123
124   flat_module_name_make(namebuf,name);
125
126   for ( i=0; i<MAX_NUM_LOADED_MODULES; i++ )
127   {
128    if ( modules[i] &&  !strcmp(namebuf, modules[i]->modulename) ) {
129        return i;
130    }
131   }
132   return -1;
133}
134
135
136//-----------------------------------------------
137
138typedef int (*module_action_t)( struct flat_hdr* flat, void* relocbuf, uint32_t count );
139
140static int module_do_relocations( struct flat_hdr* flat, void* relocbuf, uint32_t reloc_count )
141{
142   int i;
143   unsigned int offs;
144   unsigned char* buf = (unsigned char*)flat;
145
146   for ( i=0; i < reloc_count; i++ )
147   {
148      offs = *(uint32_t*)relocbuf;
149      relocbuf = ((uint32_t*)relocbuf)+1;
150          //@tsv todo: if (offs>=flat->reloc_start) error_out_of_bound
151      *(uint32_t*)(buf+offs) += (uint32_t)buf;
152   } 
153   return 1;
154}
155
156// Find symbol address in array from hash id
157void* module_find_symbol_address(uint32_t importid)
158{
159    // binary search (first entry is magic number & entry count)
160    int min = 1, max = EXPORTLIST_LAST_IDX;
161    do
162    {
163        int mid = (min + max) >> 1;
164        if (importid == symbol_hash_table[mid].hash)
165            return symbol_hash_table[mid].address;
166        else if (importid > symbol_hash_table[mid].hash)
167            min = mid + 1;
168        else
169            max = mid - 1;
170    } while (min <= max);
171    return 0;
172}
173
174static int module_do_imports( struct flat_hdr* flat, void* relocbuf, uint32_t import_count )
175{
176        int i;
177        void* importaddress;
178        uint32_t* ptr;
179        unsigned char* buf = (unsigned char*)flat;
180   
181
182        for ( i=0; i < import_count; i++ )
183        {
184                ptr = (uint32_t*)( buf + ((import_record_t*)relocbuf)->offs );
185                importaddress = module_find_symbol_address(((import_record_t*)relocbuf)->importidx);
186
187        if (importaddress == 0) return 0;
188
189                *ptr += (int)importaddress;  //(uint32_t)CHDK_EXPORT_LIST[importidx];
190        relocbuf = ((import_record_t*)relocbuf)+1;
191        } 
192    return 1;
193}
194
195// variables to quick error
196static char* module_filename;
197static int module_fd;
198static char* flat_buf;
199static char* reloc_buf;
200
201//-----------------------------------------------
202static int moduleload_error(char* text, int value)
203{
204  if ( module_fd >=0 )
205    b_close( module_fd);
206
207  if ( flat_buf )
208      free(flat_buf);
209  if ( reloc_buf )
210      ufree(reloc_buf);   
211
212  //extern int console_is_inited();
213  extern volatile int chdk_started_flag;
214  if ( chdk_started_flag ) {
215  char fmt[50];
216  strcpy(fmt,"Fail to load %s: ");
217  strcpy(fmt+17,text);
218
219  char buf[100];
220  sprintf(buf, fmt, module_filename, value);
221
222  console_clear();
223  console_add_line(buf);
224          msleep(1000);
225  }
226
227  return -1;
228}
229
230
231//-----------------------------------------------
232// return: 0 if error, otherwise ok
233static int module_do_action( char* actionname, uint32_t offset, uint32_t count, uint32_t segment_size, module_action_t func )
234{
235   if ( !count )
236                return 1;
237
238   reloc_buf = umalloc( segment_size );
239   if ( !reloc_buf )
240        return (int)moduleload_error("malloc",0);   
241
242   if ( offset != lseek(module_fd, offset, SEEK_SET) )
243        return (int)moduleload_error("action %s",(int)actionname);
244   if ( segment_size != read(module_fd, reloc_buf, segment_size) )
245        return (int)moduleload_error("action %s", (int)actionname);
246
247   // make relocations
248   if ( !func( (struct flat_hdr*) flat_buf, (uint32_t*)reloc_buf, count ) ) 
249        return (int)moduleload_error("bad import symbol",0);
250
251   ufree(reloc_buf); reloc_buf=0;
252   return 1;
253}
254
255//********************************************************/
256//**           Main module system functions             **
257//********************************************************/
258
259//-----------------------------------------------
260// PARAMETER:  name - filename of module
261//             callback - function which bind/unbind chdk
262//         local pointers with module symbols.
263//         Optional ( NULL - do not bind )
264// RETURN:    -1 - failed, >=0 =idx of module
265//-----------------------------------------------
266int module_load( char* name, _module_bind_t callback)
267{
268   int idx;
269
270   module_fd = -1;
271   module_filename = name;
272   flat_buf = 0;
273   reloc_buf = 0;
274
275/* possible to have idx=0. so no checks
276   if (!name)           
277      return -1;
278*/
279
280   //moduleload_error("Loading module %s", (uint32_t)name);
281
282   // Check if module loaded
283   idx = module_find(name);
284   if ( idx>=0 ) {
285          // reset possible unload request
286          module_unload_request[idx]=0;
287      if ( callback )
288          callback( (void**) modules[idx]->_module_exportlist );
289      return idx;
290   }
291
292   // Find empty slot   
293   for ( idx=0; idx<MAX_NUM_LOADED_MODULES && modules[idx]; idx++ );
294
295   if  ( idx == MAX_NUM_LOADED_MODULES )
296      return moduleload_error("%d already loaded",MAX_NUM_LOADED_MODULES);
297
298   module_unload_request[idx]=0;
299   module_flags[idx]=0;
300
301   char path[60];
302   struct flat_hdr flat;
303   int size_flat;
304
305   flat_module_path_make(path,name);
306
307   module_fd = open( path, O_RDONLY, 0777 );
308   if ( module_fd <=0 )
309      return moduleload_error("file not found",0);
310
311   // @tsv TODO - compare loaded with requested
312   b_read( module_fd, (char*)&flat, sizeof(flat) );
313
314   if  ( flat.rev!=FLAT_VERSION || memcmp( flat.magic, FLAT_MAGIC_NUMBER, 4) )
315      return moduleload_error("bad magicnum", 0);
316
317   size_flat = flat.reloc_start;
318
319   flat_buf = malloc( size_flat );
320   if ( !flat_buf )
321      return moduleload_error("malloc",0);
322   
323   if ( 0!= lseek(module_fd, 0, SEEK_SET) )
324        return moduleload_error("read",0);
325   if ( size_flat != b_read(module_fd, flat_buf, size_flat) )
326        return moduleload_error("read",0);
327
328   b_close(-1); // filebuf not needed below
329
330
331   // Module info checks
332
333   struct ModuleInfo* _module_info = 0;
334   if ( flat._module_info )   
335   {
336         _module_info = (struct ModuleInfo* ) ((unsigned int)flat_buf+flat._module_info);
337
338         if  ( _module_info->magicnum != MODULEINFO_V1_MAGICNUM ||
339                   _module_info->sizeof_struct != sizeof(struct ModuleInfo) )
340       return moduleload_error("Malformed module info", 0 );
341
342         if  ( _module_info->chdk_required_branch &&
343                   _module_info->chdk_required_branch != CURRENT_CHDK_BRANCH )
344       return moduleload_error("require different CHDK branch",0 );
345
346         if  ( _module_info->chdk_required_ver > CHDK_BUILD_NUM)
347       return moduleload_error("require CHDK%05d", _module_info->chdk_required_ver);
348
349     if  ( _module_info->chdk_required_platfid &&
350                   _module_info->chdk_required_platfid != PLATFORMID )
351       return moduleload_error("require platfid %d", _module_info->chdk_required_platfid);
352   }
353
354   // Make relocations
355
356   int reloc_size = flat.import_start - flat.reloc_start;
357   int reloc_count = reloc_size/sizeof(reloc_record_t);
358   if ( !module_do_action( "reloc", flat.reloc_start, reloc_count, reloc_size, module_do_relocations ) )
359          return -1;
360
361   int import_size = flat.file_size - flat.import_start;
362   int import_count = import_size/sizeof(import_record_t);
363   if ( !module_do_action( "export", flat.import_start, import_count, import_size, module_do_imports ) )
364          return -1;
365
366   b_close( module_fd );
367   module_fd = -1;
368
369   // Module is valid. Finalize binding
370
371   modules[idx] = (struct flat_hdr* )flat_buf;
372
373   modules[idx]->_module_info = (uint32_t) _module_info;
374   if ( flat._module_loader )    { modules[idx]->_module_loader += (unsigned int)flat_buf; }
375   if ( flat._module_unloader )  { modules[idx]->_module_unloader += (unsigned int)flat_buf; }
376   if ( flat._module_run )       { modules[idx]->_module_run += (unsigned int)flat_buf; }
377
378   // store runtime params
379   flat_module_name_make(modules[idx]->modulename, name);
380   modules[idx]->runtime_bind_callback = (uint32_t) callback;     //@tsv reuse unneeded entry to store valuable
381
382   int bind_err=0;
383   if ( flat._module_exportlist ) {
384        modules[idx]->_module_exportlist += (unsigned int)flat_buf;
385        if ( * ((uint32_t*)modules[idx]->_module_exportlist) != EXPORTLIST_MAGIC_NUMBER )
386            return moduleload_error("wrong import magic",0);
387
388        if ( callback )
389            bind_err = callback( (void**) modules[idx]->_module_exportlist );
390   }
391
392   if ( modules[idx]->_module_loader ) {
393                uint32_t x = ((_module_loader_t) modules[idx]->_module_loader )((unsigned int*)&symbol_hash_table[0]);
394        bind_err = bind_err || x;
395   }
396
397   if ( bind_err )
398   {
399        module_unload(name); flat_buf=0;
400        return moduleload_error("chdk mismatch",0);
401   }
402
403   return idx;
404}
405
406//-----------------------------------------------
407// PURPOSE:     run module "name" with argn/argv arguments.
408//                              callback = chdk-bind/unbind exported by module symbols.
409//                              unload_after = 0 - do not unload
410//                                                         1 - unload if load and no run handler
411//                                                         2 - unload always
412// RETURN VALUE: passed from module. -1 if something was failed
413//-----------------------------------------------
414int module_run(char* name, _module_bind_t callback, int argn, void* args, enum ModuleUnloadMode unload_after)
415{
416   int rv = -1;
417   int loadflag=0;
418
419   int moduleidx = module_find(name);
420        if ( moduleidx<0 )
421        {
422                loadflag=1;
423       
424                moduleidx = module_load( name, callback );
425                if ( moduleidx<0 )
426                return -1;
427        }
428
429   if ( modules[moduleidx]->_module_run ) {
430      kbd_key_release_all();
431          module_unload_request[moduleidx]=0;   // sanity stability clean
432      rv = ( (_module_run_t) modules[moduleidx]->_module_run )(moduleidx, argn, args);
433        }
434        else if ( unload_after==UNLOAD_IF_ERR && loadflag)
435                unload_after=UNLOAD_ALWAYS;
436
437   if ( unload_after==UNLOAD_ALWAYS )
438      module_unload(name);
439   return rv;
440}
441
442
443//-----------------------------------------------
444void module_unload_idx(int idx)
445{
446   _module_loader_t callback;
447
448   if ( idx>=0 ) {
449        // Make finalization module
450        if ( modules[idx]->_module_unloader )
451           ((_module_unloader_t) modules[idx]->_module_unloader )();
452        // Unbind pointers to module (chdk core callback)
453        if ( modules[idx]->runtime_bind_callback ) {
454           callback = (_module_loader_t)modules[idx]->runtime_bind_callback;
455           callback(0);
456        }
457       
458        // Free slot
459        free ( modules[idx] );
460        modules[idx]=0;
461        module_unload_request[idx]=0;
462        module_flags[idx]=0;
463   }
464}
465
466void module_unload(char* name)
467{
468    module_unload_idx(module_find(name));
469}
470
471//-----------------------------------------------
472// Return: 0 no such module exist, !=0 found
473//-----------------------------------------------
474int module_check_is_exist(char* name)
475{
476    char path[60];
477    flat_module_path_make(path, name);
478
479    struct stat st;
480    if (stat(path,&st) != 0) return 0;  // file does not exist
481
482    return 1;
483}
484
485//-----------------------------------------------
486void module_async_unload(unsigned int idx)
487{
488  if (idx <MAX_NUM_LOADED_MODULES)
489     module_unload_request[idx]=2;
490}
491
492void module_set_flags(unsigned int idx, char value)
493{
494  if (idx <MAX_NUM_LOADED_MODULES)
495     module_flags[idx]=value;
496}
497
498//-----------------------------------------------
499// Close all runned modules
500//   1. Called when goto GUI_MODE_NONE
501//   2. Close in 0.1sec to finalize possible in-module flow
502//       3. Close only modules which are raised flag autounload
503//-----------------------------------------------
504void module_async_unload_allrunned(int enforce)
505{
506        int idx;
507
508    for( idx=0; idx<MAX_NUM_LOADED_MODULES; idx++) {
509                if ( modules[idx] &&
510                                ( enforce ||
511                                 (module_flags[idx]&MODULE_FLAG_DISABLE_AUTOUNLOAD)==0 ) )
512                        module_unload_request[idx]=10;
513        }         
514     
515}
516
517
518
519//-----------------------------------------------
520// Called on each tick to safe asynchronous unload module by its requests
521//-----------------------------------------------
522void module_tick_unloader()
523{
524  int idx;
525
526  for( idx=0; idx<MAX_NUM_LOADED_MODULES; idx++) {
527    if ( module_unload_request[idx] >0 ) {
528        module_unload_request[idx]--;
529        //do unload on second tick to give module time to finish
530            // (even if we set it right before return from function tick could happen at same moment)
531        if ( module_unload_request[idx] == 0 )
532            module_unload_idx(idx);
533    }
534  }
535}
536
537void* module_get_adr(unsigned int idx)
538{
539        if (idx < MAX_NUM_LOADED_MODULES)
540                return modules[idx];
541        return 0;
542}
Note: See TracBrowser for help on using the repository browser.