delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1996/10/07/08:22:20

Date: Mon, 7 Oct 1996 14:17:03 +0200 (IST)
From: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
To: "John M. Aldrich" <fighteer AT cs DOT com>
Cc: Charles Sandmann <sandmann AT clio DOT rice DOT edu>, DJ Delorie <dj AT delorie DOT com>,
djgpp-workers AT delorie DOT com
Subject: Re: Stub error messages (Was: Re: 'Cannot open')
In-Reply-To: <9610041405.AA12939@clio.rice.edu>
Message-Id: <Pine.SUN.3.91.961007134857.4142A-100000@is>
Mime-Version: 1.0

On Fri, 4 Oct 1996, Charles Sandmann wrote:

> numbers might not be very meaningful.  Your best bet is to examine 
> Int 15/XMS/VCPI memory before trying to run a PM program, which is why
> my meminfo program was a TCC based image.

Instead of falling back to Turbo C, why not read the CMOS?  Surely, if 
there is *any* place in the PC which knows about the correct amount of 
memory, it will be there, right?

The following small program reports the amount of installed physical RAM
as known to the CMOS setup.  The registers I access are all documented and
thus should be supported by any AT and above.  I tried this with 3
different machines (one of them a Pentium) with 3 different BIOSes, and it
worked OK.  I don't have access to MCA machines, and so don't know what
will happen there, but at least in theory it should work.  I also have no 
experience with CMOS compatibilities in the first 20h registers.  DJ?

The reported value sometimes excludes the memory put aside for shadowing,
but that's usually something like 256K or 384K, so what the heck. 

Caveats:

	1) The code reads and writes ports, so NT might not allow it.  
But I'm not sure that NT will at all let you use all of the available 
memory in the DOS box anyway.  Charles?

	2) The function which reads the CMOS disables NMI and re-enables 
it before exit.  I would rather not change the NMI flag, but there is no 
way known to me that you can read that flag.  Since reading CMOS involves 
writing to the same register which sets ot resets the NMI flag, I chose 
the least dangerous way of disabling and re-enabling it.  Stll, if there 
are machines which run with NMI disabled (laptops?), this code will have 
a side-effect on them.  If this is of any concern, you can always tell 
people to reboot after they run djverify.

	3) My sources indicate that you should disable interrupts when
reading the CMOS, for those cases where the interrupt handler accesses
CMOS itself (like for reading the real-time clock maybe?).  However, since
the DPMI spec says that you cannot really disable interrupts under DPMI,
only stop them from being delivered to *your program*, I didn't bother. 
I've run the program time after time and never saw a garbled value
printed.  But maybe a precaution of calling the function twice in a row
and comparing the results is due. 

	4) The function that forces a delay between `inportb' and
`outportb' is just a kludge.  I wanted to prevent the optimizer from
messing up with the integer division (which might yield zero) and so
forced the compiler to go to floating point.  But that is a bad idea for
djverify, since it should run on machines without an FPU and without an
emulator (if the installation is screwed up).  So that code has to be
changed. 

Other than that--enjoy.

------------------------ memsize.c -----------------------------------
#include <time.h>

static void
usec_sleep (usec)
{
  uclock_t start_time = uclock ();
  uclock_t end_time = start_time + usec * 0.000001 * UCLOCKS_PER_SEC;

  while (uclock () < end_time)
    ;
}

#include <pc.h>

static unsigned char
read_cmos (int reg)
{
  unsigned char al = (reg & 0xff) | 0x80; /* disable NMI */

  outportb (0x70, al);
  usec_sleep (2);	/* delay for 2 microseconds */
  al = inportb (0x71);
  usec_sleep (2);
  outportb (0x70, 0);	/* enable NMI */

  return al;
}

int
installed_memory_size (void)
{
  unsigned base_lo, base_hi, ext_lo, ext_hi;

  base_lo = read_cmos (0x15);
  base_hi = read_cmos (0x16);
  ext_lo  = read_cmos (0x17);
  ext_hi  = read_cmos (0x18);

  return ( (base_hi + ext_hi) << 8 ) + base_lo + ext_lo;
}

#ifdef TEST
#include <stdio.h>

int
main (void)
{
  printf ("I think this machine has %dKB of main memory\n",
	  installed_memory_size ());
  return 0;
}

#endif


- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019