//----------------------------------------------- // return: 0 if error, otherwise ok static int module_do_action( char* actionname, uint32_t offset, uint32_t count, uint32_t segment_size, _module_action_t func ) { if ( count > 0 ) { if ( offset != lseek(module_fd, offset, SEEK_SET) ) { moduleload_error("action %s",(int)actionname); return 0; } if ( segment_size != read(module_fd, buf_load, segment_size) ) { moduleload_error("action %s", (int)actionname); return 0; } // make relocations if ( !func( flat_buf, (uint32_t*)buf_load, count ) ) { moduleload_error("bad import symbol",0); return 0; } } return 1; }
static int _module_load(module_handler_t* hMod) { int idx; // Check if module loaded idx = module_find(hMod->name); if ( idx>=0 ) return idx; // Find empty slot for ( idx=0; idx<MAX_NUM_LOADED_MODULES && modules[idx].hdr; idx++ ); if ( idx == MAX_NUM_LOADED_MODULES ) { moduleload_error("%d already loaded",MAX_NUM_LOADED_MODULES); return -1; } if (module_preload(hMod->name, hMod->version) != 0) { // Module is valid. Finalize binding modules[idx].hdr = flat_buf; // store runtime params flat_module_name_make(modules[idx].modulename, module_filename); modules[idx].hMod = hMod; int bind_err = bind_module( hMod, flat_buf->_module_info->lib ); if ( flat_buf->_module_info->lib->loader ) { uint32_t x = flat_buf->_module_info->lib->loader(); bind_err = bind_err || x; } if ( bind_err ) { module_unload(module_filename); moduleload_error("chdk mismatch",0); return -1; } return idx; } return -1; }
static int alloc_reloc_buf(uint32_t reloc_size, uint32_t import_size) { // Get larger size int sz = (reloc_size > import_size) ? reloc_size : import_size; if (sz > BUFFER_FOR_READ_SIZE) // If larger than already allocated { if (buf_load) ufree(buf_load); buf_load = umalloc(sz); if ( buf_load == 0 ) { moduleload_error("malloc",0); return 0; } } return 1; }
struct flat_hdr* module_preload(const char *name, _version_t ver) { module_fd = -1; module_filename = name; flat_buf = 0; buf_load = 0; char path[60]; struct flat_hdr flat; int size_flat; flat_module_path_make(path,module_filename); module_fd = open( path, O_RDONLY, 0777 ); if ( module_fd <=0 ) { moduleload_error("file not found",0); return 0; } // @tsv TODO - compare loaded with requested b_read( module_fd, (char*)&flat, sizeof(flat) ); if ( flat.rev!=FLAT_VERSION || memcmp( flat.magic, FLAT_MAGIC_NUMBER, 4) ) { moduleload_error("bad magicnum", 0); return 0; } size_flat = flat.reloc_start; flat_buf = (struct flat_hdr*)malloc( size_flat ); if ( !flat_buf ) { moduleload_error("malloc",0); return 0; } module_log_load(module_filename,flat_buf); if ( 0!= lseek(module_fd, 0, SEEK_SET) ) { moduleload_error("read",0); return 0; } if ( size_flat != b_read(module_fd, (char*)flat_buf, size_flat) ) { moduleload_error("read",0); return 0; } // Module info checks struct ModuleInfo *mod_info = flat_buf->_module_info = (struct ModuleInfo*)((unsigned int)flat_buf+flat_buf->_module_info_offset); if ( mod_info->magicnum != MODULEINFO_V1_MAGICNUM || mod_info->sizeof_struct != sizeof(struct ModuleInfo) ) { moduleload_error("Malformed module info", 0 ); return 0; } if ( mod_info->chdk_required_branch && mod_info->chdk_required_branch != CURRENT_CHDK_BRANCH ) { moduleload_error("require different CHDK branch",0 ); return 0; } if ( mod_info->chdk_required_ver > CHDK_BUILD_NUM) { moduleload_error("require CHDK%05d", mod_info->chdk_required_ver); return 0; } if ( mod_info->chdk_required_platfid && mod_info->chdk_required_platfid != conf.platformid ) { moduleload_error("require platfid %d", mod_info->chdk_required_platfid); return 0; } if ( !API_VERSION_MATCH_REQUIREMENT( mod_info->module_version, ver ) ) { moduleload_error("incorrect module version", 0); return 0; } if ( !API_VERSION_MATCH_REQUIREMENT( conf.api_version, mod_info->conf_ver ) ) { moduleload_error("incorrect CONF version", 0); return 0; } if ( !API_VERSION_MATCH_REQUIREMENT( camera_screen.api_version, mod_info->cam_screen_ver ) ) { moduleload_error("incorrect CAM SCREEN version", 0); return 0; } if ( !API_VERSION_MATCH_REQUIREMENT( camera_sensor.api_version, mod_info->cam_sensor_ver ) ) { moduleload_error("incorrect CAM SENSOR version", 0); return 0; } if ( !API_VERSION_MATCH_REQUIREMENT( camera_info.api_version, mod_info->cam_info_ver ) ) { moduleload_error("incorrect CAM INFO version", 0); return 0; } // Make relocations int reloc_size = flat.import_start - flat.reloc_start; int reloc_count = reloc_size/sizeof(uint32_t); int import_size = flat.file_size - flat.import_start; int import_count = import_size/sizeof(uint32_t); if (!alloc_reloc_buf(reloc_size, import_size)) return 0; if ( !module_do_action( "reloc", flat.reloc_start, reloc_count, reloc_size, module_do_relocations ) ) return 0; if ( !module_do_action( "export", flat.import_start, import_count, import_size, module_do_imports ) ) return 0; b_close( module_fd ); module_fd = -1; // TODO these could be changed to operate on affected address ranges only // after relocating but before attempting to execute loaded code // clean data cache to ensure code is in main memory dcache_clean_all(); // then flush instruction cache to ensure no addresses containing new code are cached icache_flush_all(); return flat_buf; }
// Load a module referenced by a 'module_handler_t' structure // Returns index into modules array if successful (or module already loaded) // otherwise returns -1 static int _module_load(module_handler_t* hMod) { int idx; // Get full path to module file, and hash of path char path[60]; unsigned int hash = get_module_path(path, hMod->name); // Check if module already loaded idx = module_find(hash); if (idx >= 0) return idx; // Reset lib (should not be needed, loader should only be called from 'default' lib) *hMod->lib = hMod->default_lib; // Simple lock to prevent multiple attempts to load modules simultaneously (in different tasks) // Not perfect; but should be sufficient static int isLoading = 0; while (isLoading != 0) msleep(10); isLoading = 1; // Find empty slot for (idx=0; idx<MAX_NUM_LOADED_MODULES && modules[idx].hdr; idx++) ; // If no slot found return error if (idx == MAX_NUM_LOADED_MODULES) { moduleload_error(hMod->name, "too many modules loaded"); idx = -1; } else { // Load and relocate module (returns 0 if error) flat_hdr* mod = module_preload(path, hMod->name, hMod->version); if (mod != 0) { // Module is valid. Finalize binding modules[idx].hdr = mod; modules[idx].hName = hash; modules[idx].hMod = hMod; int bind_err = bind_module(hMod, mod->_module_info->lib); // Call module loader if required if (!bind_err && mod->_module_info->lib->loader) { bind_err = mod->_module_info->lib->loader(); } // If any errors, unload module and display error message if (bind_err) { module_unload_idx(idx); moduleload_error(hMod->name, "loader error"); idx = -1; } } else { // module did not load, return invalid index idx = -1; } } // Release lock isLoading = 0; return idx; }
// Attempt to load a module file. // If file found and is a valid module, then load into memory, relocate and link to CHDK core // Returns memory address of module if successful, 0 if failure. flat_hdr* module_preload(const char *path, const char *name, _version_t ver) { // Allocate buffer and open file int module_fd = b_open(path); if (module_fd <= 0) { moduleload_error(name, "open error"); return 0; } // Read module header only to get size info flat_hdr flat; b_read(module_fd, (char*)&flat, sizeof(flat)); // TODO - compare loaded with requested size // Error message char *msg = 0; // Pointer to memory allocated to load module flat_hdr* flat_buf = 0; // Check version and magic number - make sure it is a CHDK module file if ((flat.rev == FLAT_VERSION) && (flat.magic == FLAT_MAGIC_NUMBER)) { // Allocate module memory, and load module code msg = load_module_file(module_fd, name, flat.reloc_start, flat.bss_size, &flat_buf); if (msg == 0) { // Module info checks ModuleInfo *mod_info = flat_buf->_module_info = (ModuleInfo*)((unsigned int)flat_buf+flat_buf->_module_info_offset); // Validate version requirements msg = validate(mod_info, ver); if (msg == 0) { // Make relocations msg = link_module(module_fd, flat_buf); } } } else msg = "bad magicnum"; // Close file b_close(module_fd); // If any error found, free module memory and display error if (msg) { if (flat_buf) free(flat_buf); moduleload_error(name, msg); return 0; } // TODO these could be changed to operate on affected address ranges only // after relocating but before attempting to execute loaded code // clean data cache to ensure code is in main memory dcache_clean_all(); // then flush instruction cache to ensure no addresses containing new code are cached icache_flush_all(); // Return module memory address return flat_buf; }