2021-10-11 22:19:34 -03:00

338 lines
8.0 KiB
C

static char sccsid[] = "@(#)21 1.3 src/bos/kernel/io/ramio.c, sysio, bos411, 9428A410j 4/5/93 17:17:24";
/*
* COMPONENT_NAME: SYSIO
*
* FUNCTIONS: Read and write blocks to compressed ram image
*
* ORIGINS: 27
*
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
* combined with the aggregated modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1990, 1993
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
#include <sys/types.h>
#include <sys/syspest.h>
#include <sys/param.h>
#include <sys/ramdd.h>
#ifdef _KERNEL
#include <sys/low.h>
#else
#include <assert.h>
#define halt_display(a,b,c) assert(0)
#endif
BUGXDEF(ramdd_dbg);
#define HALT_NOMEM 0x55800000
/*
* NAME: pack_ram
*
* FUNCTION: pack ram image, adjusting offsets
*
* EXECUTION ENVIORNMENT:
* called from cram_write when high water mark of ram disk
* segment is reached.
* This routine is NOT reentrant
*
* RETURNS: NONE
*/
void
ram_pack(rd)
struct ramimage *rd;
{
int dcount; /* debug count of blocks moved */
int block; /* block to relocate */
int offset; /* current offset in segment */
struct ramblock *rb; /* block struct for block being */
/* relocated */
BUGLPR(ramdd_dbg, 10, ("pack ram\n"));
dcount = 0;
offset = DATA_START(rd); /* start of packed data */
block = rd->r_first;
/*
* loop till reaching the last block in the disk. Copy data to
* the lowest available address and adjust the data offsets for
* each block
*/
while (block != LAST_BLOCK) {
rb = &rd->r_block[block];
bcopy((char *)rd + rb->rb_addr, (char *)rd + offset,
rb->rb_size);
rb->rb_addr = offset;
offset += rb->rb_size;
block = rb->rb_next;
dcount++;
ASSERT(dcount <= rd->r_blocks);
}
ASSERT(dcount == rd->r_blocks);
/*
* set the allocation off set to next available byte
*/
rd->r_alloc = offset;
ASSERT(rd->r_high >= offset);
}
void
ram_alloc(rd)
struct ramimage *rd;
{
if (rd->r_high + RAM_ALLOC > rd->r_segsize)
rd->r_high = rd->r_segsize;
else
rd->r_high += RAM_ALLOC;
BUGLPR(ramdd_dbg, 10,("alloc %d\n", rd->r_high));
ASSERT(rd->r_high <= rd->r_blocks * PSIZE + DATA_START(rd));
}
/*
* NAME: read_ram
*
* FUNCTION: read block from ram disk
*
* EXECUTION ENVIRONMENT:
* called from the ram disk strategy routine
* this routine is NOT reentrant
*
* RETURNS: NONE
*
*/
void
cram_read(rd, block, ibuf)
struct ramimage *rd;
int block;
char *ibuf;
{
struct ramblock *rb;
BUGLPR(ramdd_dbg, 10, ("cram_read: %x %x %x\n", rd, block, ibuf));
ASSERT(rd->r_blocks >= block);
ASSERT(block >= 0);
rb = &rd->r_block[block];
ram_decompress((char *)rd + rb->rb_addr, ibuf, rb->rb_size);
}
/*
* NAME: cram_write:
*
* FUNCTION: pack and write a block of data to the ram disk
*
* EXECUTION ENVIRONMENT:
* called from ram disk strategy routine to write a block of data
* to compressed ram disk
*
* RETURNS: NONE
*/
void
cram_write(rd, block, obuf)
struct ramimage *rd; /* ram disk image */
int block; /* disk block to write */
char *obuf; /* data to write */
{
struct ramblock *rb; /* ram disk block info of block to write */
char *addr; /* ram disk address to write to */
int size; /* size of packed block */
ASSERT(rd->r_blocks > block);
ASSERT(block >= 0);
/*
* at least PSIZE bytes are needed to write block to ram disk. If
* we are within PSIZE bytes of high water mark then pack the
* segment
*/
if (rd->r_alloc + PSIZE > rd->r_high) {
ram_pack(rd);
/*
* if the allocation offset is within RAM_ALLOC of the high
* water mark after packing then raise the high water mark
*/
if (rd->r_alloc + RAM_ALLOC > rd->r_high) {
ram_alloc(rd);
BUGLPR(ramdd_dbg, 10,
("%d %d\n", rd->r_alloc, rd->r_segsize));
/*
* if we still don't have enough memory then give up
*/
if (rd->r_alloc + PSIZE > rd->r_high)
halt_display(csa, HALT_NOMEM, 0);
}
}
/*
* compress the block
*/
addr = (char *)rd + rd->r_alloc;
if (rd->r_flag == RAM_WPACK) {
ram_compress(obuf, addr, &size);
} else {
ASSERT(rd->r_flag == RAM_WCOPY);
bcopy(obuf, addr, PSIZE);
size = PSIZE;
}
rb = &rd->r_block[block];
/*
* check if this is the last block (highest address) in the ram
* ram disk segment. If it is the last block then we don't
* need to adust block list
*/
if (rb->rb_next != LAST_BLOCK) {
/*
* remove block form ordered list, and place
* it at the end.
*/
rd->r_block[rb->rb_next].rb_prev = rb->rb_prev;
rd->r_block[rd->r_last].rb_next = block;
/*
* check if this is the first block on the list. If it
* is not the first block then adjust the previous
* blocks next pointer
*/
if (rb->rb_prev != LAST_BLOCK) {
rd->r_block[rb->rb_prev].rb_next = rb->rb_next;
} else {
/*
* make the next block the first one on list
*/
ASSERT(rd->r_first == block);
rd->r_first = rb->rb_next;
rd->r_block[rb->rb_next].rb_prev = LAST_BLOCK;
}
/*
* newly written block is always place at the end of list
*/
rb->rb_prev = rd->r_last;
rb->rb_next = LAST_BLOCK;
rd->r_last = block;
} else {
/*
* nothing to do if block is the last one on the list
*/
ASSERT(rd->r_last == block);
}
rb->rb_addr = rd->r_alloc;
rb->rb_size = size;
rd->r_alloc += size;
}
/*
* NAME: update_rmap
*
* FUNCTION: Update the map in a compressed ram disk when new ramblocks
* have been added.
*
* EXECUTION ENVIRONMENT:
* called from the ram disk ioctl IOCCONFIG
* this routine is not reentrant
*
* LOGIC:
* If there is enough space between the end of map and first data
* block, new ramblocks are allocated there. Otherwise
* enough blocks are moved to the end to make room for new ramblocks.
*
* RETURNS: NONE
*
*/
void
update_rmap(rd, nblocks)
struct ramimage *rd;
int nblocks; /* number of new ramblocks */
{
int blk, prev_blk, tot_blocks, last_block;
size_t map_offset; /* offset to end of new map */
struct ramblock *rb;
/* update segsize here so ram_alloc will work */
if( ram_low_mem() )
rd->r_segsize = (rd->r_blocks + nblocks + 1 )/2*PSIZE
+ DATA_START(rd) ;
else
rd->r_segsize += nblocks*PSIZE;
map_offset = sizeof( struct ramblock ) * nblocks + DATA_START(rd);
blk = rd->r_first;
rb = &rd->r_block[blk];
prev_blk = rd->r_last;
if( rb->rb_addr < map_offset ) {
/*
* There are data blocks where the new map needs to be, so
* move data blocks out of area where new ramblocks need to be
*/
ram_pack(rd); /* ensure enough space at the end */
while( rb->rb_addr < map_offset ) {
/* copy data block to next available offset */
bcopy((char *)rd + rb->rb_addr, (char *)rd + rd->r_alloc,
rb->rb_size);
rb->rb_addr = rd->r_alloc; /* new offset of data block */
rd->r_alloc += rb->rb_size; /* update next avail offset */
/* link block moved after previous last block */
rb->rb_prev = prev_blk;
rd->r_block[prev_blk].rb_next = blk;
/* get set for next block */
prev_blk = blk;
blk = rb->rb_next;
rb = &rd->r_block[blk];
}
/*
* Now that we have made room for the new map, update fields
* to make blk the first (lowest address) block and
* prev_blk the last (highest address) block.
*/
rd->r_first = blk;
rd->r_last = prev_blk;
rd->r_block[blk].rb_prev = LAST_BLOCK;
rd->r_block[ prev_blk ].rb_next = LAST_BLOCK;
}
last_block = rd->r_last;
tot_blocks = rd->r_blocks + nblocks;
rd->r_block[ last_block ].rb_next = rd->r_blocks;
/*
* Link the new blocks together, and make each start at the
* end of the data area and have a length of zero.
*/
for( blk = rd->r_blocks; blk < tot_blocks; blk++) {
rd->r_block[blk].rb_next = blk + 1;
rd->r_block[blk].rb_prev = last_block;
rd->r_block[blk].rb_addr = rd->r_alloc;
rd->r_block[blk].rb_size = 0;
last_block = blk;
}
/* set up last block */
rd->r_last = tot_blocks - 1 ;
rd->r_block[rd->r_last].rb_next = LAST_BLOCK;
rd->r_high = rd->r_alloc;
rd->r_blocks += nblocks; /* total number of blocks in ram disk */
}