home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
mint
/
mint095s
/
mem.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-03
|
25KB
|
1,109 lines
/*
Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
*/
/*
* mem.c:: routines for managing memory regions
*/
#include "mint.h"
static long core_malloc P_((long, int));
/* macro for testing whether a memory region is free */
#define ISFREE(m) ((m)->links == 0)
/*
* initialize memory routines
*/
/* initial number of memory regions */
#define NREGIONS 512
/* number of new regions to allocate when the initial ones are used up */
#define NEWREGIONS 256
static MEMREGION use_regions[NREGIONS+1];
MEMREGION *rfreelist;
void
init_mem()
{
int i;
use_regions[NREGIONS].next = 0;
for (i = 0; i < NREGIONS; i++) {
use_regions[i].next = &use_regions[i+1];
}
rfreelist = use_regions;
init_core();
init_swap();
}
/*
* init_core(): initialize the core memory map (normal ST ram) and also
* the alternate memory map (fast ram on the TT)
*/
static MEMREGION *_core_regions = 0, *_alt_regions = 0,
*_ker_regions = 0;
MMAP core = &_core_regions;
MMAP alt = &_alt_regions;
MMAP ker = &_ker_regions;
/* note: add_region must adjust both the size and starting
* address of the region being added so that memory is
* always properly aligned
*/
int
add_region(map, place, size, mflags)
MMAP map;
ulong place, size;
unsigned mflags; /* initial flags for region */
{
MEMREGION *m;
ulong newplace;
newplace = ROUND(place);
size = (place + size) - newplace;
size &= ~MASKBITS;
if (size <= 0) /* region too small to use */
return 1;
m = new_region();
if (m == 0)
return 0; /* failure */
m->links = 0;
m->len = size;
m->loc = newplace;
m->next = *map;
m->mflags = mflags;
*map = m;
return 1; /* success */
}
static long
core_malloc(amt, mode)
long amt;
int mode;
{
static int mxalloc = -1; /* does GEMDOS know about Mxalloc? */
long ret;
if (mxalloc < 0) {
ret = (long)Mxalloc(-1L, 0);
if (ret == -32) mxalloc = 0; /* unknown function */
else if (ret >= 0) mxalloc = 1;
else {
ALERT("GEMDOS returned %ld from Mxalloc", ret);
mxalloc = 0;
}
}
if (mxalloc)
return Mxalloc(amt, mode);
else if (mode == 1)
return 0L;
else
return Malloc(amt);
}
void
init_core()
{
#ifdef JUNK_MEM
extern void fillwjunk();
#endif
ulong size;
ulong place;
void *tossave;
tossave = (void *)core_malloc((long)TOS_MEM, 0);
if (!tossave) {
FATAL("Not enough memory to run MiNT");
}
/* initialize kernel memory */
place = (ulong)core_malloc(KERNEL_MEM, 3);
if (place != 0) {
(void)add_region(ker, place, KERNEL_MEM, M_KER);
#ifdef JUNK_MEM
fillwjunk(place, (long)KERNEL_MEM);
#endif
}
/* initialize ST RAM */
size = (ulong)core_malloc(-1L, 0);
while (size > 0) {
place = (ulong)core_malloc(size, 0);
if (!add_region(core, place, size, M_CORE))
FATAL("init_mem: unable to add a region");
#ifdef JUNK_MEM
fillwjunk(place, size);
#endif
size = (ulong)core_malloc(-1L, 0);
}
/* initialize alternate RAM */
size = (ulong)core_malloc(-1L, 1);
while (size > 0) {
place = (ulong)core_malloc(size, 1);
if (!add_region(alt, place, size, M_ALT))
FATAL("init_mem: unable to add a region");
size = (ulong)core_malloc(-1L, 1);
}
(void)Mfree(tossave); /* leave some memory for TOS to use */
}
/*
* init_swap(): initialize the swap area; for now, this does nothing
*/
MEMREGION *_swap_regions = 0;
MMAP swap = &_swap_regions;
void
init_swap()
{
}
/*
* routines for allocating/deallocating memory regions
*/
/*
* new_region returns a new memory region descriptor, or NULL
*/
MEMREGION *
new_region()
{
MEMREGION *m, *newfrees;
int i;
m = rfreelist;
if (!m) {
ALERT("new_region: ran out of free regions");
return 0;
}
assert(ISFREE(m));
rfreelist = m->next;
m->next = 0;
/* if we're running low on free regions, allocate some more
* we have to do this with at least 1 free region left so that get_region
* has a chance of working
*/
if (rfreelist && !rfreelist->next) {
MEMREGION *newstuff;
TRACE("get_region: getting new region descriptors");
newstuff = get_region(ker, NEWREGIONS*SIZEOF(MEMREGION));
if (!newstuff)
newstuff = get_region(alt,NEWREGIONS*SIZEOF(MEMREGION));
if (!newstuff)
newstuff = get_region(core, NEWREGIONS*SIZEOF(MEMREGION));
newfrees = newstuff ? (MEMREGION *)newstuff->loc : 0;
if (newfrees) {
newfrees[NEWREGIONS-1].next = 0;
newfrees[NEWREGIONS-1].links = 0;
for (i = 0; i < NEWREGIONS-1; i++) {
newfrees[i].next = &newfrees[i+1];
newfrees[i].links = 0;
}
rfreelist = newfrees;
} else {
DEBUG("couldn't get new region descriptors!");
}
}
return m;
}
/*
* dispose_region destroys a memory region descriptor
*/
void
dispose_region(m)
MEMREGION *m;
{
assert(ISFREE(m));
m->next = rfreelist;
rfreelist = m;
}
/*
* virtaddr
* attach_region(proc, reg): attach the region to the given process:
* returns the address at which it was attached, or NULL if the process
* cannot attach more regions. The region link count is incremented if
* the attachment is successful.
*/
virtaddr
attach_region(proc, reg)
PROC *proc;
MEMREGION *reg;
{
int i;
MEMREGION **newmem;
virtaddr *newaddr;
if (!reg || !reg->loc) {
ALERT("attach_region: attaching a null region??");
return 0;
}
for (i = 0; i < proc->num_reg; i++) {
if (!proc->mem[i]) {
assert(proc->addr[i] == 0);
reg->links++;
proc->mem[i] = reg;
proc->addr[i] = (virtaddr) reg->loc;
return proc->addr[i];
}
}
/* Hmmm, OK, we have to expand the process' memory table */
TRACE("Expanding process memory table");
i = proc->num_reg + NUM_REGIONS;
newmem = kmalloc(i * SIZEOF(MEMREGION *));
newaddr = kmalloc(i * SIZEOF(virtaddr));
if (newmem && newaddr) {
/* copy over the old address mapping */
for (i = 0; i < proc->num_reg; i++) {
newmem[i] = proc->mem[i];
newaddr[i] = proc->addr[i];
if (newmem[i] == 0)
assert(newaddr[i] == 0);
}
/* initialize the rest of the tables */
for(; i < proc->num_reg + NUM_REGIONS; i++) {
newmem[i] = 0;
newaddr[i] = 0;
}
/* free the old tables */
kfree(proc->mem); kfree(proc->addr);
proc->mem = newmem;
proc->addr = newaddr;
proc->num_reg += NUM_REGIONS;
/* this call will succeed */
TRACE("recursively calling attach_region");
return attach_region(proc, reg);
}
DEBUG("attach_region: failed");
return 0;
}
/*
* detach_region(proc, reg): remove region from the procedure's address
* space. If no more processes reference the region, return it to the
* system. Note that we search backwards, so that the most recent
* attachment of memory gets detached!
*/
void
detach_region(proc, reg)
PROC *proc;
MEMREGION *reg;
{
int i;
if (!reg) return;
for (i = proc->num_reg - 1; i >= 0; i--) {
if (proc->mem[i] == reg) {
reg->links--;
proc->mem[i] = 0; proc->addr[i] = 0;
if (reg->links == 0) {
free_region(reg);
}
return;
}
}
DEBUG("detach_region: region not attached");
}
/*
* get_region(MMAP map, ulong size) -- allocate a new region of the
* given size in the given memory map. if no region big enough is available,
* return NULL, otherwise return a pointer to the region.
* the "links" field in the region is set to 1
*
* BEWARE: new_region may call get_region (indirectly), so we have to be
* _very_ careful with re-entrancy in this function
*/
MEMREGION *
get_region(map, size)
MMAP map;
ulong size;
{
MEMREGION *m, *n;
/* precautionary measures */
if (size == 0) {
DEBUG("request for 0 bytes??");
size = 1;
}
size = ROUND(size);
n = *map;
sanity_check(map);
/* exact matches are likely to be rare, so we pre-allocate a new
* region here; this helps us to avoid re-entrancy problems
* when new_region calls get_region
*/
m = new_region();
while (n) {
if (ISFREE(n)) {
if (n->len == size) {
if (m) dispose_region(m);
n->links++;
return n;
}
else if (n->len > size) {
/* split a new region, 'm', which will contain the free bytes after n */
if (m) {
m->next = n->next;
n->next = m;
m->mflags = n->mflags & M_MAP;
m->loc = n->loc + size;
m->len = n->len - size;
n->len = size;
n->links++;
return n;
} else {
DEBUG("get_region: no regions left");
return 0;
}
}
}
n = n->next;
}
if (m)
dispose_region(m);
return NULL;
}
/*
* free_region(MEMREGION *reg): free the indicated region. The map
* in which the region is contained is given by reg->mflags.
* the caller is responsible for making sure that the region
* really should be freed, i.e. that reg->links == 0.
*/
void
free_region(reg)
MEMREGION *reg;
{
MMAP map;
MEMREGION *m;
if (!reg) return;
assert(ISFREE(reg));
if (reg->mflags & M_CORE)
map = core;
else if (reg->mflags & M_ALT)
map = alt;
else if (reg->mflags & M_KER)
map = ker;
else {
FATAL("free_region: region flags not valid (%x)", reg->mflags);
}
reg->mflags &= M_MAP;
m = *map;
assert(m);
if (m == reg) goto merge_after;
/* merge previous region if it's free and contiguous with 'reg' */
/* first, we find the region */
while (m && m->next != reg)
m = m->next;
assert(m != NULL);
if (ISFREE(m) && (m->loc + m->len == reg->loc)) {
m->len += reg->len;
assert(m->next == reg);
m->next = reg->next;
reg->next = 0;
dispose_region(reg);
reg = m;
}
/* merge next region if it's free and contiguous with 'reg' */
merge_after:
m = reg->next;
if (m && ISFREE(m) && reg->loc + reg->len == m->loc) {
reg->len += m->len;
reg->next = m->next;
m->next = 0;
dispose_region(m);
}
sanity_check(map);
}
/*
* shrink_region(MEMREGION *reg, ulong newsize):
* shrink region 'reg', so that it is now 'newsize' bytes long.
* if 'newsize' is bigger than the region's current size, return EGSBF;
* otherwise return 0.
*/
long
shrink_region(reg, newsize)
MEMREGION *reg;
ulong newsize;
{
MMAP map;
MEMREGION *n;
ulong diff;
newsize = ROUND(newsize);
assert(reg->links > 0);
if (reg->mflags & M_CORE)
map = core;
else if (reg->mflags & M_ALT)
map = alt;
else if (reg->mflags & M_KER)
map = ker;
else {
FATAL("shrink_region: bad region flags (%x)", reg->mflags);
}
/* shrinking to 0 is the same as freeing */
if (newsize == 0) {
detach_region(curproc, reg);
return 0;
}
/* if new size is the same as old size, don't do anything */
if (newsize == reg->len) {
return 0; /* nothing to do */
}
if (newsize > reg->len) {
DEBUG("shrink_region: request to make region bigger");
return EGSBF; /* growth failure */
}
/* OK, we're going to free (reg->len - newsize) bytes at the end of
this block. If the block after us is already free, simply add the
space to that block.
*/
n = reg->next;
diff = reg->len - newsize;
if (n && ISFREE(n) && reg->loc + reg->len == n->loc) {
reg->len = newsize;
n->loc -= diff;
n->len += diff;
return 0;
}
else {
n = new_region();
if (!n) {
DEBUG("shrink_region: new_region failed");
return EINTRN;
}
reg->len = newsize;
n->loc = reg->loc + newsize;
n->len = diff;
n->mflags = reg->mflags & M_MAP;
n->next = reg->next;
reg->next = n;
}
return 0;
}
/*
* max_rsize(map): return the length of the biggest free region
* in the given memory map, or 0 if no regions remain.
*/
long
max_rsize(map)
MMAP map;
{
MEMREGION *m, *max = 0;
long size = 0;
for (m = *map; m; m = m->next) {
if (ISFREE(m)) {
if (m->len > size) {
max = m;
size = m->len;
}
}
}
return size;
}
/*
* tot_rsize(map, flag): if flag == 1, return the total number of bytes in
* the given memory map; if flag == 0, return only the number of free
* bytes
*/
long
tot_rsize(map, flag)
MMAP map;
int flag;
{
MEMREGION *m;
long size = 0;
for (m = *map; m; m = m->next) {
if (flag || ISFREE(m)) {
size += m->len;
}
}
return size;
}
/*
* alloc_region(MMAP map, ulong size): allocate a new region and attach
* it to the current process; returns the address at which the region
* was attached, or NULL. If not enough memory is found, wait a bit
* and try again before giving up (maybe someone else will free some
* memory)
*/
virtaddr
alloc_region(map, size)
MMAP map;
ulong size;
{
MEMREGION *m;
PROC *proc = curproc;
virtaddr v;
m = get_region(map, size);
if (!m) {
return 0;
}
v = attach_region(proc, m);
/* NOTE: get_region returns a region with link count 1; since attach_region
* increments the link count, we restore it after calling attach_region
*/
m->links = 1;
if (!v) {
m->links = 0;
free_region(m);
return 0;
}
return v;
}
/*
* routines for creating a copy of an environment, and a new basepage.
* note that the memory regions created should immediately be attached to
* a process! Also note that create_env always operates in ST RAM, but
* create_base might not.
*/
MEMREGION *
create_env(env)
const char *env;
{
long size;
MEMREGION *m;
virtaddr v;
const char *old;
char *new;
if (!env) {
env = ((BASEPAGE *)curproc->base)->p_env;
/* duplicate parent's environment */
}
size = 2;
old = env;
while (*env || *(env+1))
env++,size++;
v = alloc_region(core, size);
if (!v) {
DEBUG("create_env: alloc_region failed");
return (MEMREGION *)0;
}
m = addr2mem(v);
/* copy the old environment into the new */
new = (char *) m->loc;
while (size > 0) {
*new++ = *old++;
--size;
}
return m;
}
MEMREGION *
create_base(cmd, env, flags, prgsize)
const char *cmd;
MEMREGION *env;
ulong flags, prgsize;
{
long len, coresize, altsize;
MMAP map;
MEMREGION *m;
BASEPAGE *b;
/* if flags & F_ALTLOAD == 1, then we might decide to load in alternate
RAM if enough is available. "enough" is: if more alt ram than ST ram,
load there; otherwise, if more than (minalt+1)*128K alt ram available
for heap space, load in alt ram ("minalt" is the high byte of flags)
*/
if (flags & F_ALTLOAD) {
coresize = max_rsize(core);
altsize = max_rsize(alt);
if (altsize >= coresize)
map = alt;
else {
len = (flags & 0xf0000000) >> 28L;
len = (len+1)*128*1024L + prgsize + 256;
if (altsize >= len)
map = alt;
else
map = core;
}
}
else
map = core;
len = max_rsize(map);
/* make sure that a little bit of memory is left over */
if (len > 2*KEEP_MEM) {
len -= KEEP_MEM;
}
m = addr2mem(alloc_region(map, len));
if (!m) {
DEBUG("create_base: alloc_region failed");
return 0;
}
b = (BASEPAGE *)(m->loc);
zero((char *)b, (long)sizeof(BASEPAGE));
b->p_lowtpa = (long)b;
b->p_hitpa = m->loc + m->len;
b->p_env = (char *)env->loc;
b->p_flags = flags;
if (cmd)
strncpy(b->p_cmdlin, cmd, 126);
return m;
}
/*
* load_region(filename): loads the program with the given file name
* into a new region, and returns a pointer to that region. On an error,
* returns 0 and leaves the error number in mint_errno.
*/
static struct fileheader {
short fmagic;
long ftext;
long fdata;
long fbss;
long fsym;
long reserved;
long flag;
short reloc;
} fh;
MEMREGION *
load_region(filename, env, cmdlin, xp)
const char *filename;
MEMREGION *env;
const char *cmdlin;
XATTR *xp; /* attributes for the file just loaded */
{
FILEPTR *f;
DEVDRV *dev;
MEMREGION *reg;
BASEPAGE *b;
long size, fixup, base, bytes_read;
unsigned char c, *next;
#define LRBUFSIZ 8196
static unsigned char buffer[LRBUFSIZ];
int trycount = 0;
next = buffer;
f = do_open(filename, O_DENYNONE | O_EXEC, 0, xp);
if (!f) {
return 0; /* mint_errno set by do_open */
}
dev = f->dev; /* could be different from fs */
if ( (*dev->read)(f, (void *)&fh, (long)sizeof(fh)) != sizeof(fh) ||
fh.fmagic != 0x601a ) {
DEBUG("load_region: file not executable");
mint_errno = ENOEXEC;
failed:
do_close(f);
return 0;
}
size = fh.ftext + fh.fdata + fh.fbss;
reg = 0;
for (trycount = 0; (trycount < 1) && (reg == 0); trycount++) {
reg = create_base(cmdlin, env, fh.flag, size);
if (size+1024L > reg->len) {
DEBUG("load_region: insufficient memory to load");
detach_region(curproc, reg);
reg = 0;
}
if (!reg) {
/* maybe the memory shortage is short-term; sleep a bit to see */
nap(10);
}
}
if (reg == 0) {
mint_errno = ENSMEM;
goto failed;
}
b = (BASEPAGE *)reg->loc;
b->p_flags = fh.flag;
b->p_tbase = b->p_lowtpa + 256;
b->p_tlen = fh.ftext;
b->p_dbase = b->p_tbase + b->p_tlen;
b->p_dlen = fh.fdata;
b->p_bbase = b->p_dbase + b->p_dlen;
size = (*dev->read)(f, (void *)b->p_tbase, fh.ftext+fh.fdata);
if (size != fh.ftext + fh.fdata) {
DEBUG("load_region: unexpected EOF");
failed_reloc: /* come here when loading/relocation fails */
mint_errno = ENOEXEC;
detach_region(curproc, reg);
goto failed;
}
b->p_blen = fh.fbss;
if (fh.flag & F_FASTLOAD) /* fastload bit */
size = b->p_blen;
else
size = b->p_hitpa - b->p_bbase;
zero((char *)b->p_bbase, size);
(*dev->lseek)(f, fh.fsym, SEEK_CUR); /* skip over symbol table */
base = b->p_tbase;
/* now read the relocation info; we use the temporary buffer provided
* above to speed things up
*/
if (fh.reloc == 0 && (*dev->read)(f, (char *)&fixup, 4L) && fixup) {
fixup += base;
size = LRBUFSIZ;
bytes_read = 0;
do {
if (fixup >= b->p_hitpa) {
DEBUG("load_region: bad relocation");
goto failed_reloc;
}
else
*((long *)fixup) += base;
do {
if (!bytes_read) {
bytes_read =
(*dev->read)(f,(char *)buffer,size);
next = buffer;
}
if (bytes_read < 0) {
DEBUG("load_region: EOF in relocation");
goto failed_reloc;
}
else if (bytes_read == 0)
c = 0;
else {
c = *next++; bytes_read--;
}
if (c == 1) fixup += 254;
} while (c == 1);
fixup += ( (unsigned) c) & 0xff;
} while (c);
}
do_close(f);
return reg;
}
/*
* exec_region(p, mem, thread): create a child process out of a mem region
* "p" is the process structure set up by the parent; it may be "curproc",
* if we're overlaying. "mem" is the loaded memory region returned by
* "load region". Any open files (other than the standard handles) owned
* by "p" are closed, and if thread !=0 all memory is released; the caller
* must explicitly attach the environment and base region. The caller must
* also put "p" on the appropriate queue (most likely READY_Q).
*/
extern long mint_dos(), mint_bios();
void rts() {} /* dummy termination routine */
PROC *
exec_region(p, mem, thread)
PROC *p;
MEMREGION *mem;
int thread;
{
BASEPAGE *b;
FILEPTR *f;
int i;
MEMREGION *m;
TRACE("exec_region");
b = (BASEPAGE *) mem->loc;
/* set some (undocumented) variables in the basepage */
b->p_defdrv = p->curdrv;
for (i = 0; i < 6; i++)
b->p_devx[i] = i;
p->dta = (DTABUF *)(b->p_dta = &b->p_cmdlin[0]);
p->base = b;
/* close extra open files */
for (i = MIN_OPEN; i < MAX_OPEN; i++) {
if ( (f = p->handle[i]) && (p->fdflags[i] & FD_CLOEXEC) ) {
do_pclose(p, f);
p->handle[i] = 0;
}
}
/* initialize memory */
recalc_maxmem(p);
if (p->maxmem) {
shrink_region(mem, p->maxmem);
b->p_hitpa = b->p_lowtpa + mem->len;
}
p->memflags = b->p_flags;
if (!thread) {
for (i = 0; i < p->num_reg; i++) {
m = p->mem[i];
if (m) {
m->links--;
if (m->links <= 0)
free_region(m);
}
}
if (p->num_reg > NUM_REGIONS) {
kfree(p->mem); kfree(p->addr);
p->mem = kmalloc(NUM_REGIONS * SIZEOF(MEMREGION *));
p->addr = kmalloc(NUM_REGIONS * SIZEOF(virtaddr));
/* note: the mallocs have succeeded, since we just freed bigger areas */
assert(p->mem && p->addr);
p->num_reg = NUM_REGIONS;
}
zero((char *)p->mem, (p->num_reg)*SIZEOF(MEMREGION *));
zero((char *)p->addr, (p->num_reg)*SIZEOF(virtaddr));
}
/* initialize signals */
p->sigmask = 0;
for (i = 0; i < NSIG; i++) {
if (p->sighandle[i] != SIG_IGN) {
p->sighandle[i] = SIG_DFL;
p->sigflags[i] = 0;
p->sigextra[i] = 0;
}
}
/* zero the user registers, and set the FPU in a "clear" state */
for (i = 0; i < 15; i++)
p->ctxt[CURRENT].regs[i] = 0;
p->ctxt[CURRENT].sr = 0;
p->ctxt[CURRENT].fstate[0] = 0;
/* set PC, stack registers, etc. appropriately */
p->ctxt[CURRENT].pc = b->p_tbase;
/* The "-0x20" is to make sure that syscall.s won't run past the end of
* memory when the user makes a system call and doesn't push very many
* parameters -- syscall always tries to copy the maximum possible number
* of parms.
*
* NOTE: there's a sanity check here in case programs Mshrink a basepage
* without fixing the p_hitpa field in the basepage; this is to ensure
* compatibility with older versions of MiNT, which ignore p_hitpa.
*/
if (valid_address(b->p_hitpa - 0x20))
p->ctxt[CURRENT].usp = b->p_hitpa - 0x20;
else
p->ctxt[CURRENT].usp = mem->loc + mem->len - 0x20;
p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
p->ctxt[CURRENT].term_vec = (long)rts;
/* set up stack for process */
*((long *)(p->ctxt[CURRENT].usp + 4)) = (long) b;
/* check for a valid text region. some compilers (e.g. Lattice 3) just throw
everything into the text region, including data; fork() must be careful
to save the whole region, then. We assume that if the compiler (or
assembler, or whatever) goes to the trouble of making separate text, data,
and bss regions, then the text region is code and isn't modified and
fork doesn't have to save it.
*/
if (b->p_tlen != 0 && b->p_blen != 0 && b->p_dlen != 0)
p->txtsize = b->p_tlen;
else
p->txtsize = 0;
/*
* An ugly hack: dLibs tries to poke around in the parent's address space
* to find stuff. For now, we'll allow this by faking a pointer into
* the parent's address space in the place in the basepage where dLibs is
* expecting it. This ugly hack only works correctly if the Pexec'ing
* program (i.e. curproc) is in user mode.
*/
curproc->base->p_usp = curproc->ctxt[SYSCALL].usp - 0x32;
return p;
}
/*
* misc. utility routines
*/
/*
* long memused(p): return total memory allocated to process p
*/
long
memused(p)
PROC *p;
{
int i;
long size;
size = 0;
for (i = 0; i < p->num_reg; i++) {
if (p->mem[i])
size += p->mem[i]->len;
}
return size;
}
/*
* recalculate the maximum memory limit on a process; this limit depends
* on the max. allocated memory and max. total memory limits set by
* p_setlimit (see dos.c), and (perhaps) on the size of the program
* that the process is executing. whenever any of these things
* change (through p_exec or p_setlimit) this routine must be called
*/
void
recalc_maxmem(p)
PROC *p;
{
BASEPAGE *b;
long siz;
b = (BASEPAGE *)p->base;
if (b)
siz = b->p_tlen + b->p_dlen + b->p_blen;
else
siz = 0;
p->maxmem = 0;
if (p->maxdata) {
p->maxmem = p->maxdata + siz;
}
if (p->maxcore) {
if (p->maxmem == 0 || p->maxmem > p->maxcore)
p->maxmem = p->maxcore;
}
if (p->maxmem && p->maxmem < siz)
p->maxmem = siz;
}
/*
* valid_address: checks to see if the indicated address falls within
* memory attached to the current process
*/
int
valid_address(addr)
long addr;
{
int i;
MEMREGION *m;
for (i = 0; i < curproc->num_reg; i++) {
if ((m = curproc->mem[i]) != 0) {
if (addr >= m->loc && addr <= m->loc + m->len)
return 1;
}
}
return 0;
}
/*
* some debugging stuff
*/
void
DUMPMEM(map)
MMAP map;
{
MEMREGION *m;
m = *map;
ALERT("memory dump: starting at region %lx", m);
while (m) {
ALERT("%ld bytes at %lx (%d links); next region %lx", m->len, m->loc,
m->links, m->next);
m = m->next;
}
}
void
sanity_check(map)
MMAP map;
{
#ifdef SANITY_CHECK
MEMREGION *m, *nxt;
long end;
m = *map;
while (m) {
nxt = m->next;
if (nxt) {
end = m->loc + m->len;
if (m->loc < nxt->loc && end > nxt->loc) {
FATAL("MEMORY CHAIN CORRUPTED");
}
else if (end == nxt->loc && ISFREE(m) && ISFREE(nxt)) {
ALERT("Continguous memory regions not merged!");
}
}
m = nxt;
}
#endif
}