source: trunk/core/module_load.c @ 1527

Revision 1527, 14.5 KB checked in by philmoz, 17 months ago (diff)

Merge latest code from reyalp-flt branch to main trunk.

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