ftp.nice.ch/pub/next/developer/languages/c/djgpp-NS.s.tar.gz#/djgpp/go32/valloc.c

This is valloc.c in view mode; [Download] [Up]

/* This is file VALLOC.C */
/*
** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
**
** This file is distributed under the terms listed in the document
** "copying.dj", available from DJ Delorie at the address above.
** A copy of "copying.dj" should accompany this file; if not, a copy
** should be available from where this file was obtained.  This file
** may not be distributed without a verbatim copy of "copying.dj".
**
** This file is distributed WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

/* Modified for VCPI Implement by Y.Shibata Aug 5th 1991 */
/* Bugs in large memory usage (both RAM & virtual) fixed Greg Galperin 2AUG93 */

/*
Note: The functions here assume that memory is never really freed, just
reused through page_out, unless we're exiting or running another
program.  In either case, we don't need to keep track of what's freed
since it's all going anyway.  Thus, vfree() is empty and the rest of the
routines are relatively simple.  Note that VCPI may blow you up if you
try to be clever in here. 
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dos.h>

#include "gotypes.h"
#include "valloc.h"
#include "xms.h"
#include "mono.h"
#include "vcpi.h"
#include "utils.h"
#include "paging.h"
#include "stubinfo.h"
#include "proginfo.h"
#include "control.h"
#include "mswitch.h"

#define VA_FREE 0
#define VA_USED 1

#define DOS_PAGE 256            /*  1MB / 4KB = 256 Pages  */

extern char use_DPMI;

int valloc_initted = 0;
static word8 map[4096];         /* Expanded/Extended paged, allocated with VA_1M */

word32 mem_avail, mem_used;     /* Kbytes */

static unsigned pn_lo_first, pn_lo_last, pn_hi_first, pn_hi_last;
static unsigned pn_lo_next, pn_hi_next;
static unsigned vcpi_flush_ok = 0;
static char use_vcpi = 0;

extern int debug_mode;
extern word16 vcpi_installed;   /* If VCPI is installed, set this not Zero  */
extern word32 far *vcpi_pt;

void valloc_update_status(void)
{
  char buf[20];
  int i;
  if (!valloc_initted)
    return;
  sprintf(buf, "%6ldk", mem_avail);
  for (i=0; i<7; i++)
    poke(screen_seg, (i+70)*2, buf[i] | 0x0a00);
  sprintf(buf, "%6ldk", mem_used);
  for (i=0; i<7; i++)
    poke(screen_seg, (i+62)*2, buf[i] | 0x0a00);
}


emb_handle_t emb_handle=-1;

void
xms_free(void)
{
  if(use_xms && emb_handle != -1)
  {
    xms_unlock_emb(emb_handle);
    xms_emb_free(emb_handle);
    emb_handle = -1;
  }
}

void
xms_alloc_init(void)
{
  xms_extended_info *x = xms_query_extended_memory();
  emb_off_t linear_base;
  emb_size_K_t emb_size;
  emb_size = x->max_free_block;
  emb_handle = xms_emb_allocate(emb_size);
  linear_base = xms_lock_emb(emb_handle);
  pn_hi_first = (word16)((linear_base + 4095)/4096);
  pn_hi_last = (word16)((linear_base + emb_size * 1024L)/4096 - 1);
  if (cpumode() && !vcpi_installed )
  {
    fprintf(stderr, "\nGo32 error: Using XMS switches the CPU into V86 mode.\n");
    fprintf(stderr, "If you are using QEMM, add the `on' parameter to the entry\n");
    fprintf(stderr, "in your CONFIG.SYS file.  See the FAQ for details.\n\n");
    xms_free();
    if (!show_memory_info)
      exit(1);
  }
}


static int valloc_lowmem_page;
static unsigned lol;

void valloc_init(void)
{
  word32 left_lo, left_hi;
  unsigned char far *vdisk;
  int has_vdisk=1;
  unsigned free_pages;
  unsigned i;
  struct REGPACK r;

  if (valloc_initted)
    return;  

  if (vcpi_installed)
  {
    pn_hi_first = 0;
    pn_hi_last  = vcpi_maxpage();
    i = vcpi_capacity();
    if ( i )
    {
      use_vcpi = 1;
      if (show_memory_info)
	fprintf(stderr, "VCPI (Expanded) memory available: %ld Kb\n", i * 4L);
    }
    else if(use_xms) 
    {
    xms_alloc_init();   /*  Try XMS allocation  */
    if (show_memory_info)
      fprintf(stderr, "XMS memory available: %ld Kb\n", ((word32)pn_hi_last-pn_hi_first) * 4);
    }
    prog_info.run_mode = _GO32_RUN_MODE_VCPI;
  }
  else if (use_xms)
  {
    xms_alloc_init();   /*  Try XMS allocation  */
    if (show_memory_info)
      fprintf(stderr, "XMS memory available: %ld Kb\n", ((word32)pn_hi_last-pn_hi_first) * 4);
    prog_info.run_mode = _GO32_RUN_MODE_XMS;
  }
  else
  {
    /*
    ** int 15/vdisk memory allocation
    */
    r.r_ax = 0x8800;    /* get extended memory size */
    intr(0x15, &r);
    pn_hi_last = r.r_ax / 4 + 255;

    /* get ivec 19h, seg only */
    vdisk = (unsigned char far *)(*(long far *)0x64L & 0xFFFF0000L);
    for (i=0; i<5; i++)
    if (vdisk[i+18] != "VDISK"[i])
      has_vdisk = 0;
    if (has_vdisk)
    {
      pn_hi_first = ( (vdisk[46]<<4) | (vdisk[45]>>4) );
      if (vdisk[44] | (vdisk[45]&0xf))
	pn_hi_first ++;
    }
    else
      pn_hi_first = 256;
    if (show_memory_info)
      fprintf(stderr, "Extended memory available: %ld Kb\n", ((word32)pn_hi_last-pn_hi_first) * 4);
    prog_info.run_mode = _GO32_RUN_MODE_RAW;
  }

  r.r_ax= 0x4800;       /* get real memory size */
  r.r_bx = 0xffff;
  intr(0x21, &r);       /* lol == size of largest free memory block */

  lol = r.r_bx;
/*  printf("max pages is %u\n", lol); */
  if (lol < 8*256)
  {
    fprintf(stderr, "Error: not enough memory to run go32!\n");
    exit(1);
  }

  free_pages = (unsigned)(stub_info.free_conventional_memory / 16);
/*  printf("free pages desired is %u\n", free_pages); */
  if (lol - 8*256 > free_pages)
  {
    lol -= free_pages;
/*    printf("subtracting, lol now %u\n", lol); */
  }
  else
  {
    lol = 8*256;
/*    printf("best we can do is %u\n", lol); */
  }

  r.r_ax = 0x4800;
  r.r_bx = lol;
/*  printf("go32 uses %u para", lol); */
  intr(0x21, &r);       /* get the block */
/*  printf(" at %x, %d, %x\n", r.r_ax, r.r_flags, r.r_bx); */
  pn_lo_first = (r.r_ax+0xFF) >> 8;     /* lowest real mem 4K block */
  pn_lo_last = ((r.r_ax+lol-0x100)>>8); /* highest real mem 4K block */
  if (r.r_flags & 1)
  {
    fprintf(stderr, "Error: could not allocate memory for go32\n");
    exit(1);
  }

  valloc_lowmem_page = r.r_ax;

  pn_lo_next = pn_lo_first;
  pn_hi_next = pn_hi_first;

  memset(map, 0, 4096);
  vcpi_flush_ok = 1;

  mem_used = 0;
  left_lo  = ((long)pn_lo_last - pn_lo_first + 1)*4;
  left_hi  = (use_vcpi)? vcpi_capacity()*4:((long)pn_hi_last-pn_hi_first+1)*4;
  mem_avail = left_lo + left_hi;

  if (debug_mode)
    fprintf(stderr, "%ld Kb conventional, %ld Kb %s - %ld Kb total RAM available\n",
      left_lo, left_hi,
      use_DPMI ? "dpmi" : use_vcpi ? "expanded" : use_xms ? "XMS" : "extended",
      mem_avail);

  if (topline_info)
    valloc_update_status();

  valloc_initted = 1;
}

void valloc_shrink_rmem(int pages)
{
  if (pn_lo_last - pn_lo_next > pages)
  {
    struct REGPACK r;
/*    printf("Changing allocation down %d pages from %d ", pages, lol); */
    lol -= pages * 256;
    r.r_ax = 0x4a00;    /* modify real memory size */
    r.r_bx = lol;
    r.r_es = valloc_lowmem_page;
/*    printf("to %d (0x%04x)\n", lol, valloc_lowmem_page); */
    intr(0x21, &r);
    /* GWJ change 1994-05-06 */
    pn_lo_last = ((valloc_lowmem_page+lol-0x100)>>8); /* highest real mem 4K block */
  }
/*  else
  {
    printf("most avail pages is %d (wanted %d)\n", pn_lo_last - pn_lo_next, pages);
  } */
}

void valloc_uninit(void)
{
  struct REGPACK r;
  if (!valloc_initted)
    return;

  r.r_es = valloc_lowmem_page;  /* free the block we allocated */
  r.r_ax = 0x4900;
  intr(0x21, &r);

  xms_free();
  valloc_initted = 0;
}

unsigned valloc(where)
{
  unsigned pn;
  if (!valloc_initted)
    valloc_init();
  switch (where)
  {
    case VA_640:
      if (pn_lo_next <= pn_lo_last)
      {
	mem_avail -= 4;
	mem_used += 4;
	if (topline_info)
	  valloc_update_status();
	return pn_lo_next++;
      }

      pn = page_out(VA_640);
      if (pn != 0xffff)
      {
	return pn;
      }
      fprintf(stderr, "Error: out of conventional memory\n");
      exit(1);
    case VA_1M:
      if (use_vcpi)
      {
	if ((pn = vcpi_alloc()) != 0)
	{
	  mem_avail -= 4;
	  mem_used += 4;
	  if (topline_info)
	    valloc_update_status();
	  map[pn>>3] |= 1 << (pn&7);
	  return pn;
	}
      }
      else
      {
	if (pn_hi_next <= pn_hi_last)
	{
	  mem_avail -= 4;
	  mem_used += 4;
	  if (topline_info)
	    valloc_update_status();
	  return pn_hi_next++;
	}
      }
      /* Difference is -1 when there are no pages left, so
	 use signed compare. */
      if ((signed)pn_lo_last-(signed)pn_lo_next > 3) /* save last four for VA_640 */
      {
	mem_avail -= 4;
	mem_used += 4;
	if (topline_info)
	  valloc_update_status();
	return (word16)(vcpi_pt[pn_lo_next++] >> 12);
      }

      pn = page_out(VA_1M);
      if (pn != 0xffff)
      {
	return pn;
      }
      fprintf(stderr, "Error: out of extended memory\n");
      exit(1);
  }
  return 0;
}

void vfree_640()
{
  struct REGPACK r;

  r.r_es = valloc_lowmem_page;  /* free the block we allocated */
  r.r_ax = 0x4900;
  intr(0x21, &r);
}

void vrecover_640()
{
  struct REGPACK r;

  r.r_ax= 0x4800;       /* get real memory size */
  r.r_bx = 0xffff;
  intr(0x21, &r);       /* lol == size of largest free memory block */

  if (lol != r.r_bx)
  {
    fprintf(stderr, "Error: unable to realloc conventional memory (wrong size)\n");
    exit(1);
  }
  r.r_ax = 0x4800;
  intr(0x21, &r);       /* get the block */
  if (r.r_ax != valloc_lowmem_page)
  {
    fprintf(stderr, "Error: unable to realloc conventional memory (wrong address)\n");
    exit(1);
  }
  pn_lo_next = pn_lo_first;
}

void vfree(void)
{
  mem_avail += 4;
  mem_used -= 4;
  if (topline_info)
    valloc_update_status();
}

void vcpi_flush(void)           /* only called on exit */
{
  word16 pn;

  if (!vcpi_flush_ok || !use_vcpi)
    return;                     /*  Not Initaialized Map[]  */
  for(pn = pn_hi_first; pn <= pn_hi_last; pn++)
    if (map[pn>>3] & (1 << (pn&7)))
      vcpi_free(pn);
}

unsigned valloc_max_size(void)
{
  return (unsigned)((mem_avail + mem_used) / 4);
}

unsigned valloc_used(void)
{
  return (unsigned)(mem_used / 4);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.