inline bool b_read(std::vector<std::string>& o, FILE* fp) { unsigned s; o.clear(); if(!b_read(s, fp))return false; if(s==0)return true; o.resize(s); for(std::vector<std::string>::iterator i = o.begin(); i!=o.end(); i++) { if(!b_read(*i, fp))return false; } return true; }
inline bool b_read(std::vector<ModelMatch*>& o, unsigned num_param, FILE* fp) { unsigned s; for(std::vector<ModelMatch*>::iterator i=o.begin(); i!=o.end();i++)delete *i; o.clear(); if(!b_read(s, fp))return false; for(unsigned i=0;i<s; i++) { unsigned index; if(!b_read(index, fp))return false; ModelMatch* model = new ModelMatch(index, num_param, 0); if(!b_read(model->fParam, model->fNumParam, fp))return false; o.push_back(model); } return true; }
inline bool b_read(std::vector<double>& o, FILE* fp) { unsigned s; o.clear(); if(!b_read(s, fp))return false; if(s==0)return true; double* buffer = new double[s]; if(fread(buffer, sizeof(*buffer), s, fp) != s) { delete[] buffer; return false; } o.insert(o.begin(), buffer, buffer+s); delete[] buffer; return true; }
inline bool b_read(std::string& o, FILE* fp) { unsigned s; o.erase(); if(!b_read(s, fp))return false; if(s==0)return true; char* buffer = new char[s]; if(fread(buffer, sizeof(*buffer), s, fp) != s) { delete[] buffer; return false; } o.append(buffer,s); delete[] buffer; return true; }
// Allocate module memory and load file // Returns 0 if all ok, otherwise returns error message static char* load_module_file(int fd, const char* name, int size, int bss_size, flat_hdr** flat_buf) { *flat_buf = (flat_hdr*)malloc(size+bss_size); if (!*flat_buf) return "malloc"; module_log_load(name, *flat_buf); if (lseek(fd, 0, SEEK_SET) == 0) { if (b_read(fd, (char*)*flat_buf, size) == size) { memset((unsigned char*)(*flat_buf)+size, 0, bss_size); return 0; } } // Load failed, free memory free(*flat_buf); *flat_buf = 0; return "read"; }
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; }
// 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; }
PUBLIC void test_combi() { errstat err; bool ok, ok1; capability new_cap, tmp_cap; b_fsize size; (void)strcpy(testname, "test_many()"); if (verbose) printf("\n---- %s ----\n", testname); /* Create an uncommitted file with the same contents as the original. */ err = b_create(&commit_cap, write_buf, AVG_SIZE, 0, &new_cap); if (test_good(err, "1a, b_create()")) { TEST_ASSERT(ok = !obj_cmp(&new_cap, &commit_cap), TEST_SERIOUS, ("%s, 1a: new object expected\n", testname)); /* Modify it. */ err = b_modify(&new_cap, AVG_OFFS, write_buf, AUX_SIZE, 0, &tmp_cap); if (test_good(err, "1a, b_modify()")) { /* The capability shouldn't change. */ TEST_ASSERT(ok1 = cap_cmp(&tmp_cap, &new_cap), TEST_SERIOUS, ("%s, 1a: previous capability expected\n", testname)); /* Clean up possible debris. */ if (!ok1) { if (ok) { err = std_destroy(&new_cap); (void)test_good(err, "std_destroy()"); } new_cap = tmp_cap; err = std_destroy(&tmp_cap); (void)test_good(err, "std_destroy()"); TEST_ASSERT(ok = !obj_cmp(&new_cap, &commit_cap), TEST_SERIOUS, ("%s, 1a: new object expected\n", testname)); } /* Delete some. */ err = b_delete(&new_cap, AVG_OFFS, AUX_SIZE, 0, &tmp_cap); if (test_good(err, "1a, b_delete()")) { TEST_ASSERT(ok1 = cap_cmp(&tmp_cap, &new_cap), TEST_SERIOUS, ("%s, 1a: previous capability expected\n", testname)); if (!ok1) { if (ok) { err = std_destroy(&new_cap); (void)test_good(err, "std_destroy()"); } new_cap = tmp_cap; err = std_destroy(&tmp_cap); (void)test_good(err, "std_destroy()"); TEST_ASSERT(ok = !obj_cmp(&new_cap, &commit_cap), TEST_SERIOUS, ("%s, 1a: new object expected\n", testname)); } /* Insert some (restore original contents) and commit. */ err = b_insert(&new_cap, AVG_OFFS, write_buf + (int)AVG_OFFS, AUX_SIZE, SAFE_COMMIT, &tmp_cap); if (test_good(err, "1a, b_insert()")) { /* The capability should be the same as the original one. */ TEST_ASSERT(ok1 = cap_cmp(&tmp_cap, &commit_cap), TEST_SERIOUS, ("%s, 1a: original capability expected\n", testname)); TEST_ASSERT(!obj_cmp(&tmp_cap, &new_cap), TEST_SERIOUS, ("%s, 1a: new object expected\n", testname)); err = b_size(&tmp_cap, &size); if (test_good(err, "1a, b_size()")) TEST_ASSERT(size == AVG_SIZE, TEST_SERIOUS, ("%s, 1a: size should be %ld but is %ld\n", testname, (long)AVG_SIZE, (long)size)); memset(read_buf, 0, (size_t)BIG_SIZE); err = b_read(&tmp_cap, ZERO, read_buf, BIG_SIZE, &size); if (test_good(err, "1a, b_read()")) { TEST_ASSERT(size == AVG_SIZE, TEST_SERIOUS, ("%s, 1a: bytes read should be %ld but is %ld\n", testname, (long)AVG_SIZE, (long)size)); TEST_ASSERT(memcmp(read_buf, write_buf, (size_t)size)==0,TEST_SERIOUS, ("%s, 1a: data read do not match original data\n", testname)); } if (!ok1) { err = std_destroy(&tmp_cap); (void)test_good(err, "1a, std_destroy()"); } ok = FALSE; /* Nothing left to destroy. */ } } } if (ok) { err = std_destroy(&new_cap); (void)test_good(err, "1a, std_destroy()"); } } } /* test_many() */
PUBLIC void test_b_read() { errstat err; capability tmp_cap; b_fsize size; (void)strcpy(testname, "test_b_read()"); if (verbose) printf("\n---- %s ----\n", testname); /* Read some bytes from the beginning of an empty file. */ err = b_read(&empty_cap, ZERO, read_buf, AVG_SIZE, &size); if (test_good(err, "1a")) TEST_ASSERT(size == ZERO, TEST_SERIOUS, ("%s, 1a: bytes read should be 0 but is %ld\n", testname, (long)size)); /* Read some bytes from the beginning of a full file. */ memset(read_buf, 0, (size_t)AUX_SIZE); err = b_read(&commit_cap, ZERO, read_buf, AUX_SIZE, &size); if (test_good(err, "1b")) { /* Check the size and contents of the file. */ TEST_ASSERT(size == AUX_SIZE, TEST_SERIOUS, ("%s, 1b: bytes read should be %ld but is %ld\n", testname, (long)AUX_SIZE, (long)size)); TEST_ASSERT(memcmp(read_buf, write_buf, (size_t)size) == 0, TEST_SERIOUS, ("%s, 1b: data read do not match original data\n", testname)); } /* Read all bytes from the middle of a full file. */ memset(read_buf, 0, (size_t)AUX_SIZE); err = b_read(&commit_cap, AVG_OFFS, read_buf, AUX_SIZE, &size); if (test_good(err, "1c")) { TEST_ASSERT(size == AUX_SIZE, TEST_SERIOUS, ("%s, 1c: bytes read should be %ld but is %ld\n", testname, (long)AUX_SIZE, (long)size)); TEST_ASSERT(memcmp(read_buf, write_buf + (int)AVG_OFFS, (size_t)size) == 0, TEST_SERIOUS,("%s, 1c: data read do not match original data\n", testname)); } /* Read 0 bytes from the middle of a full file. */ err = b_read(&commit_cap, AVG_OFFS, read_buf, ZERO, &size); if (test_good(err, "1d")) TEST_ASSERT(size == ZERO, TEST_SERIOUS, ("%s, 1d: bytes read should be 0 but is %ld\n", testname, (long)size)); /* Read some bytes from the end of a full file. */ err = b_read(&commit_cap, AVG_SIZE, read_buf, AUX_SIZE, &size); if (test_good(err, "1e")) TEST_ASSERT(size == ZERO, TEST_SERIOUS, ("%s, 1e: bytes read should be 0 but is %ld\n", testname, (long)size)); /* Read beyond the end from the middle of a full file. */ memset(read_buf, 0, (size_t)AVG_SIZE); err = b_read(&commit_cap, AVG_OFFS, read_buf, AVG_SIZE, &size); if (test_good(err, "1f")) { TEST_ASSERT(size == AVG_SIZE-AVG_OFFS, TEST_SERIOUS, ("%s, 1f: bytes read should be %ld but is %ld\n", testname, (long)(AVG_SIZE-AVG_OFFS), (long)size)); TEST_ASSERT(memcmp(read_buf, write_buf + (int)AVG_OFFS, (size_t)size) == 0, TEST_SERIOUS,("%s, 1f: data read do not match original data\n", testname)); } /* Read an entire full file plus one extra byte. */ memset(read_buf, 0, (size_t)(AVG_SIZE+ONE)); err = b_read(&commit_cap, ZERO, read_buf, AVG_SIZE+ONE, &size); if (test_good(err, "1g")) { TEST_ASSERT(size == AVG_SIZE, TEST_SERIOUS, ("%s, 1g: bytes read should be %ld but is %ld\n", testname, (long)AVG_SIZE, (long)size)); TEST_ASSERT(memcmp(read_buf, write_buf, (size_t)size) == 0, TEST_SERIOUS, ("%s, 1g: data read do not match original data\n", testname)); } /* Read one byte in the middle of a file. */ memset(read_buf, 0, (size_t)AVG_SIZE); read_buf[0] = ~write_buf[(int)AVG_OFFS]; err = b_read(&commit_cap, AVG_OFFS, read_buf, ONE, &size); if (test_good(err, "1h")) { TEST_ASSERT(size == ONE, TEST_SERIOUS, ("%s, 1h: bytes read should be 1 but is %ld\n", testname, (long)size)); TEST_ASSERT(memcmp(read_buf, write_buf + (int)AVG_OFFS, (size_t)size) == 0, TEST_SERIOUS,("%s, 1h: data read do not match original data\n", testname)); } /* Read some bytes from a file with one byte. */ memset(read_buf, 0, (size_t)AVG_SIZE); read_buf[0] = ~write_buf[0]; err = b_read(&one_cap, ZERO, read_buf, AUX_SIZE, &size); if (test_good(err, "1i")) { TEST_ASSERT(size == ONE, TEST_SERIOUS, ("%s, 1i: bytes read should be 1 but is %ld\n", testname, (long)size)); TEST_ASSERT(memcmp(read_buf, write_buf, (size_t)size) == 0, TEST_SERIOUS, ("%s, 1i: data read do not match original data\n", testname)); } /* Read 0 bytes from an empty file. */ err = b_read(&empty_cap, ZERO, read_buf, ZERO , &size); if (test_good(err, "1j")) TEST_ASSERT(size == ZERO, TEST_SERIOUS, ("%s, 1j: bytes read should be 0 but is %ld\n", testname, (long)size)); /* Read an entire full file with the minimum required rights. */ err = std_restrict(&commit_cap, BS_RGT_READ, &tmp_cap); if (test_good(err, "1k, std_restrict()")) { memset(read_buf, 0, (size_t)AVG_SIZE); err = b_read(&tmp_cap, ZERO, read_buf, AVG_SIZE, &size); if (test_good(err, "1k")) { TEST_ASSERT(size == AVG_SIZE, TEST_SERIOUS, ("%s, 1k: bytes read should be %ld but is %ld\n", testname, (long)AVG_SIZE, (long)size)); TEST_ASSERT(memcmp(read_buf, write_buf, (size_t)size) == 0, TEST_SERIOUS, ("%s, 1k: data read do not match original data\n", testname)); } } } /* test_b_read() */