/* * AdjustMods - adjust the demand info offsets in all the modules * - allocate module index table * - allocate demand load link table */ dip_status AdjustMods( section_info *inf, unsigned long adjust ) { info_block *blk; unsigned count; unsigned mod_off; mod_table *tbl; mod_info *mod; dword num_links; dword first_link; dword last_link; demand_kind dk; unsigned num; pointer_int *lnk; pointer_int **lnk_tbl; unsigned long off; dip_status ok; last_link = 0; first_link = (dword)-1L; num_links = 1; for( blk = inf->mod_info; blk != NULL; blk = blk->next ) { mod = (mod_info *)blk->info; count = 0; for( mod_off = 0; mod_off < blk->size; mod_off += MODINFO_SIZE( (byte *)mod + mod_off ) ) { ++count; } tbl = DCAlloc( sizeof( mod_table ) + ( count - 1 ) * sizeof( mod_info * ) ); if( tbl == NULL ) { DCStatus( DS_ERR|DS_NO_MEM ); return( DS_ERR|DS_NO_MEM ); } tbl->count = count; blk->link = tbl; count = 0; for( mod_off = 0; mod_off < blk->size; mod_off += MODINFO_SIZE( mod ) ) { tbl->mod_off[count++] = mod_off; mod = (mod_info *)((byte *)blk->info + mod_off); for( dk = 0; dk < MAX_DMND; ++dk ) { if( inf->ctl->v2 ) { if( mod->di[dk].u.size != 0 ) { ++num_links; } } else { if( mod->di[dk].u.entries != 0 ) { num_links = mod->di[dk].info_off; if( first_link > num_links ) { first_link = num_links; } num_links += mod->di[dk].u.entries * sizeof( pointer_int ); if( last_link < num_links ) { last_link = num_links; } } } } } } if( !inf->ctl->v2 ) { off = first_link + adjust; if( DCSeek( inf->ctl->sym_fid, off, DIG_ORG) != off ) { DCStatus( DS_ERR|DS_FSEEK_FAILED ); return( DS_ERR|DS_FSEEK_FAILED ); } num_links = (last_link - first_link) / sizeof( pointer_int ) + 2; } ok = AllocLinkTable( inf, num_links, first_link ); if( ok != DS_OK ) return( ok ); num = 0; lnk_tbl = inf->dmnd_link; lnk = *lnk_tbl; for( ; num_links-- > 0; ) { if( num >= MAX_LINK_ENTRIES ) { lnk = *++lnk_tbl; num = 0; } /* * shift over one bit so as to leave the lower bit * clear for testing if it is allocated or not */ lnk[num] = (lnk[num] + adjust) << 1; ++num; } return( DS_OK ); }
void *VMBlock( imp_image_handle *ii, virt_mem start, size_t len ) { unsigned dir_idx; unsigned pg_idx; unsigned tmp_idx; int i; int j; unsigned num_pages; virt_mem pg_start; virt_page *pg; virt_page *zero; loaded_block *block; dir_idx = GET_DIR( start ); if( ii->virt[dir_idx] == NULL ) { if( !InitPageDir( ii, dir_idx ) ) { return( NULL ); } } pg_idx = GET_PAGE( start ); len += start % VM_PAGE_SIZE; pg_start = start & ~(virt_mem)(VM_PAGE_SIZE - 1); pg = ii->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( ;; ) { ii->virt[tmp_idx][i] = NULL; if( pg->offset == 0 ) break; if( i == 0 ) { --tmp_idx; i = DIR_SIZE; } --i; --pg; } vmFreeBlock( ii, 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( ii->virt[tmp_idx] == NULL ) { if( !InitPageDir( ii, 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; } ii->virt[dir_idx][pg_idx] = NULL; } DCFree( pg ); return( NULL ); } } if( ii->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( ii, tmp_idx, j ); } ii->virt[tmp_idx][j] = &pg[i]; } /* read in new block */ len = num_pages * VM_PAGE_SIZE; block->len = len; block->first_dtor = NULL; pg_start += ii->bias; if( DCSeek( ii->sym_file, pg_start, DIG_ORG ) != pg_start ) { DCStatus( DS_ERR | DS_FSEEK_FAILED ); return( NULL ); } /* last block might be a short read */ if( DCRead( ii->sym_file, pg->block->data, len ) == DIG_READ_ERROR ) { DCStatus( DS_ERR | DS_FREAD_FAILED ); return( NULL ); } pg = ii->virt[dir_idx][pg_idx]; } ++TimeStamp; if( TimeStamp == 0 ) { /* deal with wrap-around */ for( ii = ImageList; ii != NULL; ii = ii->next_image ) { if( ii->virt != NULL ) { for( i = ii->vm_dir_num-1; i >= 0; --i ) { if( ii->virt[i] != NULL ) { for( j = DIR_SIZE-1; j >= 0; --j ) { zero = ii->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 ] ); }