/****************************************************************/ /* */ /* memmgr.c */ /* */ /* Memory Manager for Core Allocation */ /* */ /* Copyright (c) 1995 */ /* Pasquale J. Villani */ /* All Rights Reserved */ /* */ /* This file is part of DOS-C. */ /* */ /* DOS-C is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU General Public License */ /* as published by the Free Software Foundation; either version */ /* 2, or (at your option) any later version. */ /* */ /* DOS-C is distributed in the hope that it will be useful, but */ /* WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ /* the GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public */ /* License along with DOS-C; see the file COPYING. If not, */ /* write to the Free Software Foundation, 675 Mass Ave, */ /* Cambridge, MA 02139, USA. */ /****************************************************************/ #include "../../hdr/portab.h" #include "globals.h" /* $Logfile*/ #ifndef IPL static BYTE *memmgrRcsId = "$Header: C:/dos-c/src/kernel/memmgr.c_v 1.2 01 Sep 1995 17:54:20 patv $"; #endif /* * $Log: C:/dos-c/src/kernel/memmgr.c_v $ * * Rev 1.2 01 Sep 1995 17:54:20 patv * First GPL release. * * Rev 1.1 30 Jul 1995 20:51:58 patv * Eliminated version strings in ipl * * Rev 1.0 02 Jul 1995 8:33:08 patv * Initial revision. */ VOID mcb_init(); VOID mcb_print(); VOID show_chain(); /* The following code is 8086 dependant */ #ifdef KERNEL VOID mcb_init (mcb FAR *mcbp, int size) { COUNT i; mcbp -> m_type = MCB_LAST; mcbp -> m_psp = FREE_PSP; mcbp -> m_size = size; for(i = 0; i < 8; i++) mcbp -> m_name[i] = '\0'; mem_access_mode = FIRST_FIT; } #endif seg far2para (VOID FAR *p) { seg u1 = FP_SEG(p); offset u2 = FP_OFF(p); ULONG phy_addr; phy_addr = (((long)u1) << 4) + u2; return (phy_addr>>4); } seg long2para (LONG size) { return ((size + 0x0f)>>4); } VOID FAR * add_far (VOID FAR *fp, ULONG off) { UWORD seg_val; UWORD off_val; /* Break far pointer into components */ seg_val = FP_SEG(fp); off_val = FP_OFF(fp); /* add the offset to the fp's offset part */ off += off_val; /* make off_val equal to lower part of new value */ off_val = off & 0xffff; /* and add top part into seg */ seg_val += ((off & 0x000f0000l) / 0x10); /* and send back the new pointer */ return (VOID FAR *)MK_FP(seg_val, off_val); } VOID FAR * adjust_far (VOID FAR *fp) { ULONG linear; UWORD seg_val; UWORD off_val; /* First, convert the segmented pointer to a linear address */ linear = (((ULONG)FP_SEG(fp)) << 4) + FP_OFF(fp); /* Break it into segments. */ seg_val = (UWORD)(linear >> 4); off_val = (UWORD)(linear & 0xf); /* and return an adddress adjusted to the nearest paragraph */ /* boundary. */ return MK_FP(seg_val, off_val); } #ifdef KERNEL COUNT DosMemAlloc (int size, COUNT mode, seg FAR *para, UWORD FAR *asize) { REG mcb FAR *p; mcb FAR *q; COUNT i; BOOL found; /* Initialize */ p = (mcb FAR *)(MK_FP(first_mcb, 0)); /* Search through memory blocks */ for(q = (mcb FAR *)0, i = 0, found = FALSE; !found; ) { /* check for corruption */ if(p -> m_type != MCB_NORMAL && p -> m_type != MCB_LAST) return DE_MCBDESTRY; /* Test if free based on mode rules */ switch(mode) { case LAST_FIT: default: /* Check for a last fit candidate */ if(p -> m_size >= size && p -> m_psp == FREE_PSP) /* keep the last know fit */ q = p; /* not free - bump the pointer */ if(p -> m_type != MCB_LAST) p = MK_FP(far2para((VOID FAR *)p) + p -> m_size + 1, 0); /* was there no room (q == 0)? */ else if(p -> m_type == MCB_LAST && q == (mcb FAR *)0) return DE_NOMEM; /* something was found - continue */ else found = TRUE; break; case FIRST_FIT: /* Check for a first fit candidate */ if(p -> m_size >= size && p -> m_psp == FREE_PSP) { q = p; found = TRUE; break; } /* not free - bump the pointer */ if(p -> m_type != MCB_LAST) p = MK_FP(far2para((VOID FAR *)p) + p -> m_size + 1, 0); /* nothing found till end - no room */ else return DE_NOMEM; break; case BEST_FIT: /* Check for a best fit candidate */ if(p -> m_size >= size && p -> m_psp == FREE_PSP) { if(i == 0 || p -> m_size < i) { i = p -> m_size; q = p; } } /* not free - bump the pointer */ if(p -> m_type != MCB_LAST) p = MK_FP(far2para((VOID FAR *)p) + p -> m_size + 1, 0); /* was there no room (q == 0)? */ else if(p -> m_type == MCB_LAST && q == (mcb FAR *)0) return DE_NOMEM; /* something was found - continue */ else found = TRUE; break; case LARGEST: /* Check for a first fit candidate */ if((p -> m_psp == FREE_PSP) && (i == 0 || p -> m_size > i)) { size = *asize = i = p -> m_size; q = p; } /* not free - bump the pointer */ if(p -> m_type != MCB_LAST) p = MK_FP(far2para((VOID FAR *)p) + p -> m_size + 1, 0); /* was there no room (q == 0)? */ else if(p -> m_type == MCB_LAST && q == (mcb FAR *)0) return DE_NOMEM; /* something was found - continue */ else found = TRUE; break; } } p = q; /* Larger fit case */ if(p -> m_size > size) { if(mode != LAST_FIT) { q = MK_FP(far2para((VOID FAR *)p) + size + 1, 0); /* Always flow m_type up */ /* on alloc */ q -> m_type = p -> m_type; p -> m_type = MCB_NORMAL; p -> m_psp = cu_psp; q -> m_psp = FREE_PSP; q -> m_size = p -> m_size - size - 1; p -> m_size = size; for(i = 0; i < 8; i++) p -> m_name[i] = q -> m_name[i] = '\0'; } else { q = MK_FP(far2para((VOID FAR *)p) + (p -> m_size - size), 0); /* Always flow m_type up */ /* on alloc */ q -> m_type = p -> m_type; p -> m_type = MCB_NORMAL; q -> m_psp = cu_psp; p -> m_psp = FREE_PSP; p -> m_size = p -> m_size - size - 1; q -> m_size = size; for(i = 0; i < 8; i++) p -> m_name[i] = q -> m_name[i] = '\0'; } /* Found - return good */ *para = far2para((VOID FAR *)(mode == LAST_FIT ? (VOID FAR *)q : (VOID FAR *)p)); return SUCCESS; } /* Exact fit case */ else if(p -> m_size == size) { p -> m_psp = cu_psp; for(i = 0; i < 8; i++) p -> m_name[i] = '\0'; /* Found - return good */ *para = far2para((VOID FAR *)(BYTE FAR *)p); return SUCCESS; } else return DE_MCBDESTRY; } seg DosMemLargest (seg FAR *size) { REG mcb FAR *p; mcb FAR *q; COUNT found; /* Initialize */ p = (mcb FAR *)(MK_FP(first_mcb, 0)); /* Search through memory blocks */ for(q = (mcb FAR *)0, *size = 0, found = FALSE; !found; ) { /* check for corruption */ if(p -> m_type != MCB_NORMAL && p -> m_type != MCB_LAST) return DE_MCBDESTRY; /* Test for largest fit/available */ if((p -> m_psp == FREE_PSP) && (p -> m_size > *size)) { *size = p -> m_size; q = p; } /* not free - bump the pointer */ if(p -> m_type != MCB_LAST) p = MK_FP(far2para((VOID FAR *)p) + p -> m_size + 1, 0); /* was there no room (q == 0)? */ else if(p -> m_type == MCB_LAST && q == (mcb FAR *)0) return DE_NOMEM; /* something was found - continue */ else found = TRUE; } if( q != 0) return SUCCESS; else return DE_NOMEM; } COUNT DosMemFree (int para) { REG mcb FAR *p, FAR *q; COUNT i; /* Initialize */ p = (mcb FAR *)(MK_FP(para, 0)); /* check for corruption */ if(p -> m_type != MCB_NORMAL && p -> m_type != MCB_LAST) return DE_INVLDMCB; /* Mark the mcb as free so that we can later */ /* merge with other surrounding free mcb's */ p -> m_psp = FREE_PSP; for(i = 0; i < 8; i++) p -> m_name[i] = '\0'; /* Now merge free blocks */ for(p = (mcb FAR *)(MK_FP(first_mcb, 0)); p -> m_type != MCB_LAST; p = q) { /* make q a pointer to the next block */ q = MK_FP(far2para((VOID FAR *)p) + p -> m_size + 1, 0); /* and test for corruption */ if(q -> m_type != MCB_NORMAL && q -> m_type != MCB_LAST) return DE_MCBDESTRY; if(p -> m_psp != FREE_PSP) continue; /* test if next is free - if so merge */ if(q -> m_psp == FREE_PSP) { /* Always flow type down on free */ p -> m_type = q -> m_type; p -> m_size += q -> m_size + 1; /* and make pointers the same */ /* since the next free is now */ /* this block */ q = p; } } return SUCCESS; } COUNT DosMemChange (int para, int size) { REG mcb FAR *p, FAR *q; REG COUNT i; /* Initialize */ p = (mcb FAR *)(MK_FP(--para, 0)); /* check for corruption */ if(p -> m_type != MCB_NORMAL && p -> m_type != MCB_LAST) return DE_MCBDESTRY; /* check for wrong allocation */ if(size > p -> m_size) { REG COUNT delta; /* make q a pointer to the next block */ q = MK_FP(far2para((VOID FAR *)p) + p -> m_size + 1, 0); /* if next mcb is not free, error no memory */ if(q -> m_psp != FREE_PSP) return DE_NOMEM; /* reduce the size of q and add difference to p */ /* but check that q is big enough first */ delta = size - p -> m_size; if(q -> m_size < delta) return DE_NOMEM; q -> m_size -= delta; p -> m_size += delta; /* Now go back and adjust q, we'll make p new q */ p = MK_FP(far2para((VOID FAR *)q) + delta, 0); p -> m_type = q -> m_type; p -> m_psp = q -> m_psp; p -> m_size = q -> m_size; for(i = 0; i < 8; i++) p -> m_name[i] = q -> m_name[i]; /* and finished */ return SUCCESS; } /* else, shrink it down */ else if(size < p -> m_size) { /* make q a pointer to the new next block */ q = MK_FP(far2para((VOID FAR *)p) + size + 1, 0); /* reduce the size of p and add difference to q */ q -> m_type = p -> m_type; q -> m_size = p -> m_size - size - 1; p -> m_size = size; /* Make certian the old psp is not last (if it was) */ p -> m_type = MCB_NORMAL; /* Mark the mcb as free so that we can later */ /* merge with other surrounding free mcb's */ q -> m_psp = FREE_PSP; for(i = 0; i < 8; i++) q -> m_name[i] = '\0'; /* now free it so that we have a complete block */ return DosMemFree(far2para((VOID FAR *)q)); } /* otherwise, its a no-op */ else return SUCCESS; } COUNT DosMemCheck (void) { REG mcb FAR *p; /* Initialize */ p = (mcb FAR *)(MK_FP(first_mcb, 0)); /* Search through memory blocks */ for( ; ; ) { /* check for corruption */ if(p -> m_type != MCB_NORMAL && p -> m_type != MCB_LAST) return DE_MCBDESTRY; /* not corrupted - if last we're OK! */ if(p -> m_type == MCB_LAST) return SUCCESS; /* not corrupted - but not end, bump the pointer */ else if(p -> m_type != MCB_LAST) p = MK_FP(far2para((VOID FAR *)p) + p -> m_size + 1, 0); /* totally lost - bad exit */ else return DE_MCBDESTRY; } } # ifdef DEBUG VOID show_chain (void) { mcb FAR *p = (mcb FAR *)(MK_FP(first_mcb, 0)); for(;;) { mcb_print(p); if(p -> m_type == MCB_LAST || p -> m_type != MCB_NORMAL) return; else p = (mcb FAR *)(MK_FP(far2para((VOID FAR *)p)+p -> m_size+1,0)); } } VOID mcb_print (mcb FAR *mcbp) { static BYTE buff[9]; VOID _fmemcpy(); _fmemcpy((BYTE FAR *)buff, (BYTE FAR *)(mcbp -> m_name), 8); buff[8] = '\0'; printf("%04x:%04x -> |%s| m_type = 0x%02x; m_psp = 0x%04x; m_size = 0x%04x\n", FP_SEG(mcbp), FP_OFF(mcbp), *buff == '\0' ? "*NO-ID*" : buff, mcbp -> m_type, mcbp -> m_psp, mcbp -> m_size); } VOID _fmemcpy(BYTE FAR *d, BYTE FAR *s, REG COUNT n) { while(n--) *d++ = *s++; } # endif #endif