/* * Finds a subsection directory entry for a specific module. */ hll_dir_entry *hllFindDirEntry( imp_image_handle *ii, imp_mod_handle im, hll_sst sst ) { unsigned i; unsigned block; unsigned full_blocks; unsigned remainder; hll_dir_entry *p; full_blocks = BLOCK_FACTOR( ii->dir_count, DIRECTORY_BLOCK_ENTRIES ) - 1; for( block = 0; block < full_blocks; ++block ) { for( i = 0; i < DIRECTORY_BLOCK_ENTRIES; ++i ) { p = &ii->directory[block][i]; if( p->iMod == im && p->subsection == sst) { return( p ); } } } remainder = ii->dir_count - (full_blocks * DIRECTORY_BLOCK_ENTRIES); for( i = 0; i < remainder; ++i ) { p = &ii->directory[block][i]; if( p->iMod == im && p->subsection == sst) { return( p ); } } return( NULL ); }
/* * Walks the subsection directory. * * Use 'sst' to limit the callbacks to one specific type. A 'sst' of 0 * means everything. */ walk_result hllWalkDirList( imp_image_handle *ii, hll_sst sst, DIR_WALKER *wk, void *d ) { unsigned i; unsigned block; unsigned full_blocks; unsigned remainder; walk_result wr; hll_dir_entry *p; full_blocks = BLOCK_FACTOR( ii->dir_count, DIRECTORY_BLOCK_ENTRIES ) - 1; for( block = 0; block < full_blocks; ++block ) { for( i = 0; i < DIRECTORY_BLOCK_ENTRIES; ++i ) { p = &ii->directory[block][i]; if( p->subsection == sst || sst == 0) { wr = wk( ii, p, d ); if( wr != WR_CONTINUE ) { return( wr ); } } } } remainder = ii->dir_count - (full_blocks * DIRECTORY_BLOCK_ENTRIES); for( i = 0; i < remainder; ++i ) { p = &ii->directory[block][i]; if( p->subsection == sst || sst == 0) { wr = wk( ii, p, d ); if( wr != WR_CONTINUE ) { return( wr ); } } } return( WR_CONTINUE ); }
/* * Frees resources associated with a image handle. */ static void Cleanup( imp_image_handle *ii ) { imp_image_handle **owner; imp_image_handle *curr; unsigned blocks; unsigned i; /* unlink it */ owner = &ImageList; for( ;; ) { curr = *owner; if( curr == ii ) { break; } owner = &curr->next_image; } *owner = ii->next_image; /* free memory */ if( ii->directory != NULL ) { blocks = BLOCK_FACTOR( ii->dir_count, DIRECTORY_BLOCK_ENTRIES ); for( i = 0; i < blocks; ++i ) { if( ii->directory[i] != NULL ) { DCFree( ii->directory[i] ); } } DCFree( ii->directory ); } DCFree( ii->segments ); VMFini( ii ); }
dip_status VMInit( imp_image_handle *ii, unsigned long size ) { ii->vm_dir_num = BLOCK_FACTOR( size, DIR_SIZE * VM_PAGE_SIZE ); ii->virt = DCAllocZ( ii->vm_dir_num * sizeof( ii->virt ) ); if( ii->virt == NULL ) { DCStatus( DS_ERR|DS_NO_MEM ); return( DS_ERR|DS_NO_MEM ); } return( DS_OK ); }
static dip_status LoadDirectory( imp_image_handle *ii, unsigned long off ) { unsigned_32 directory; cv_subsection_directory dir_header; unsigned block_count; unsigned i; unsigned left; size_t block_size; unsigned num; if( DCSeek( ii->sym_fid, off, DIG_ORG ) != off ) { return( DS_ERR|DS_FSEEK_FAILED ); } if( DCRead( ii->sym_fid, &directory, sizeof( directory ) ) != sizeof( directory ) ) { return( DS_ERR|DS_FREAD_FAILED ); } if( DCSeek( ii->sym_fid, ii->bias + directory, DIG_ORG ) != (ii->bias + directory) ) { return( DS_ERR|DS_FSEEK_FAILED ); } if( DCRead( ii->sym_fid, &dir_header, sizeof( dir_header ) ) != sizeof( dir_header ) ) { return( DS_ERR|DS_FREAD_FAILED ); } if( dir_header.cbDirHeader != sizeof( dir_header ) || dir_header.cbDirEntry != sizeof( cv_directory_entry ) ) { return( DS_ERR|DS_INFO_INVALID ); } ii->dir_count = dir_header.cDir; block_count = BLOCK_FACTOR( ii->dir_count, DIRECTORY_BLOCK_ENTRIES ); ii->directory = DCAlloc( block_count * sizeof( cv_directory_entry * ) ); if( ii->directory == NULL ) { return( DS_ERR|DS_NO_MEM ); } memset( ii->directory, 0, block_count * sizeof( cv_directory_entry * ) ); i = 0; left = ii->dir_count; for( ;; ) { num = left; if( num > DIRECTORY_BLOCK_ENTRIES ) num = DIRECTORY_BLOCK_ENTRIES; block_size = num * sizeof( cv_directory_entry ); ii->directory[i] = DCAlloc( block_size ); if( ii->directory[i] == NULL ) { return( DS_ERR|DS_NO_MEM ); } if( DCRead( ii->sym_fid, ii->directory[i], block_size ) != block_size ) { return( DS_ERR|DS_FREAD_FAILED ); } ++i; left -= num; if( left == 0 ) { break; } } return( DS_OK ); }
/* * Loads the HLL directory. * * 'offent' is the file offset of the first directory entry. */ static dip_status LoadDirectory( imp_image_handle *ii, unsigned long offent ) { unsigned block_count; unsigned i; unsigned left; size_t block_size; unsigned num; /* * Read the directory entries. We're using a two-level table here, * probably to avoid allocating big chunks of memory... */ block_count = BLOCK_FACTOR( ii->dir_count, DIRECTORY_BLOCK_ENTRIES ); ii->directory = DCAlloc( block_count * sizeof( void * ) ); if( ii->directory == NULL ) { return( DS_ERR | DS_NO_MEM ); } memset( ii->directory, 0, block_count * sizeof( void * ) ); /* skip to the first entry */ if( DCSeek( ii->sym_file, offent, DIG_ORG ) != offent) { return( DS_ERR | DS_FSEEK_FAILED ); } i = 0; left = ii->dir_count; do { num = left; if( num > DIRECTORY_BLOCK_ENTRIES ) { num = DIRECTORY_BLOCK_ENTRIES; } block_size = num * sizeof( hll_dir_entry ); ii->directory[i] = DCAlloc( block_size ); if( ii->directory[i] == NULL ) { return( DS_ERR | DS_NO_MEM ); } if( ii->format_lvl >= HLL_LVL_NB04 ) { if( DCRead( ii->sym_file, ii->directory[i], block_size ) != block_size ) { return( DS_ERR | DS_FREAD_FAILED ); } } else { /* Slow but simple. */ int j; hll_dir_entry *ent = ii->directory[i]; for( j = 0; j < num; j++, ent++ ) { cv3_dir_entry cv3ent; if( DCRead( ii->sym_file, &cv3ent, sizeof( cv3ent ) ) != sizeof( cv3ent ) ) { return( DS_ERR | DS_FREAD_FAILED ); } ent->subsection = cv3ent.subsection; ent->iMod = cv3ent.iMod; ent->lfo = cv3ent.lfo; ent->cb = cv3ent.cb; } } ++i; left -= num; } while( left != 0 ); return( DS_OK ); }
void *VMBlock( imp_image_handle *iih, virt_mem start, size_t len ) { unsigned dir_idx; unsigned pg_idx; unsigned tmp_idx; unsigned i; unsigned j; unsigned num_pages; virt_mem pg_start; virt_page *pg; virt_page *zero; loaded_block *block; dir_idx = GET_DIR( start ); if( iih->virt[dir_idx] == NULL ) { if( !InitPageDir( iih, dir_idx ) ) { return( NULL ); } } pg_idx = GET_PAGE( start ); len += start % VM_PAGE_SIZE; pg_start = start & ~(virt_mem)(VM_PAGE_SIZE - 1); pg = iih->virt[dir_idx][pg_idx]; if( pg == NULL || ( pg->block->len - pg->offset ) < len ) { /* unloaded previously loaded block */ if( pg != NULL ) { tmp_idx = dir_idx; /* find first page of the block */ i = pg_idx; for( ;; ) { iih->virt[tmp_idx][i] = NULL; if( pg->offset == 0 ) break; if( i == 0 ) { --tmp_idx; i = DIR_SIZE; } --i; --pg; } DCFree( pg ); } num_pages = BLOCK_FACTOR( len, VM_PAGE_SIZE ); pg = DCAlloc( num_pages * ( sizeof( *pg ) + VM_PAGE_SIZE ) + sizeof( loaded_block ) - 1 ); if( pg == NULL ) { DCStatus( DS_ERR | DS_NO_MEM ); return( NULL ); } /* set up new page table entries */ block = (loaded_block *)&pg[num_pages]; tmp_idx = dir_idx; for( j = pg_idx, i = 0; i < num_pages; ++j, ++i ) { pg[i].block = block; pg[i].offset = i * VM_PAGE_SIZE; if( j >= DIR_SIZE ) { ++tmp_idx; j = 0; } if( iih->virt[tmp_idx] == NULL ) { if( !InitPageDir( iih, tmp_idx ) ) { /* unwind the setup already done */ num_pages = i; for( i = 0; i < num_pages; ++i, ++pg_idx ) { if( pg_idx >= DIR_SIZE ) { ++dir_idx; pg_idx = 0; } iih->virt[dir_idx][pg_idx] = NULL; } DCFree( pg ); return( NULL ); } } if( iih->virt[tmp_idx][j] != NULL ) { /* We just ran into another allocated block, so we have to kill all the pages mapped in by it. We know that if the page pointer is non-NULL, it will be offset==0 since KillPages will clean out the others. */ KillPages( iih, tmp_idx, j ); } iih->virt[tmp_idx][j] = &pg[i]; } /* read in new block */ len = num_pages * VM_PAGE_SIZE; block->len = len; pg_start += iih->bias; if( DCSeek( iih->sym_fp, pg_start, DIG_ORG ) ) { DCStatus( DS_ERR | DS_FSEEK_FAILED ); return( NULL ); } /* last block might be a short read */ if( DCRead( iih->sym_fp, pg->block->data, len ) == DIG_RW_ERROR ) { DCStatus( DS_ERR | DS_FREAD_FAILED ); return( NULL ); } pg = iih->virt[dir_idx][pg_idx]; } ++TimeStamp; if( TimeStamp == 0 ) { /* deal with wrap-around */ for( iih = ImageList; iih != NULL; iih = iih->next_image ) { if( iih->virt != NULL ) { for( i = iih->vm_dir_num; i-- > 0; ) { if( iih->virt[i] != NULL ) { for( j = DIR_SIZE; j-- > 0; ) { zero = iih->virt[i][j]; if( zero != NULL ) { zero->block->time_stamp = 0; } } } } } } ++TimeStamp; } pg->block->time_stamp = TimeStamp; return( &pg->block->data[(start & (VM_PAGE_SIZE - 1)) + pg->offset] ); }