[comp.sys.ibm.pc] Setup RAM information: here is the info + program

ogilvie@klipper.cs.vu.nl (Ogilvie) (09/17/88)

Here follows some code to deal with the AT-setup,  but first the theory:

Setup information is kept in the Motorola MC146818 CMOS RTC RAM, which
is a battery-powered chip with a real-time  clock (so the PC knows
time and date at startup) and 64 bytes of RAM (also battery powered so
the information is secured over power-downs).

I have a quiestion too: Does anyone knows if the number of hard disk
definitions in the BIOS is recorded somewhere?

Here follows what I kow about the SETUP.

I/O addresses:		to chip:	70h
			from chip:	71h

Internal RAM usage:
address		meaning
-----------	------------------
0		seconds (real time)
1		seconds (alarm)
2		minutes (real time)
3		minutes (alarm)
4		hours (real time)
5		hours (alarm)
6		day of the week
7		day-number
8		month-number
9		year
10		status reg. A
11		status reg. B
12		status reg. C
13		status reg. D
14		chip diagnostics status
15		shutdown reason
16		diskette types for A and B (see below)
17		reserved
18		hard disk types C and D (see below
19		reserved
20		equipment byte
21		low byte amount of standard memory
22		high byte amount of standard memory
23		low byte expansion memory
24		high byte " "
25		hard disk type C if byte 18, bits 7-4 == 15
26		hard disk type D if byte 18, bits 3-0 == 15
-45		reserved
46-47		RTC checksum
48		as byte 16, actual
49		as byte 18, actual
50		eon
51		flags
52-63		reserved


Diskette types (byte 16)
------------------------
bits 7-4: A-drive
	  0: not present
	  1: 320/360Kb
	  2: 1.2Mb
bits 3-0: B-drive (same)


Hard disk types (byte 18)
-------------------------
bits 7-4: first hard disk
	  0: not installed
	  1-14: index into BIOS table with definitions (see below)
	  15: installed, see byte 25 for actual type
bits 3-0: second hard disk (same)

Now follows some code. The first is in assembler. The routines can read
any byte from the RTC-RAM. The second copies the ROM-BIOS stored HD
definitons to user memory.
Next follows a C-program that displays the definitons found in the BIOS.

-------------------------------------- cut ----------------------------
; Assembler to be linked with MS-C (4.0)

	PUBLIC _getrtc, _gettab

rtc_port0 equ 70h
rtc_port1 equ 71h
CMOSDIAG  equ 10h

_TEXT	SEGMENT	PUBLIC BYTE 'CODE'	; start the code segment
	ASSUME CS:_TEXT,DS:nothing

_getrtc	PROC NEAR
;
;   ret= getrtc (regnum)
;
	push	bp
	mov	bp,sp

	mov	ax,CMOSDIAG
	out	rtc_port0,al
	jmp	$+2		; delay a little for chip
	jmp	$+2		; before reading it's answer
	in	al,rtc_port1	; Get the answer
	test	al,0C0h		; battery and checksum ok?
	jz	ok
	mov	ax, -1
	jmp	eind		; (dutch for end, but end is reserved)

     ok:mov	al,[bp+4]
	out	rtc_port0,al
	jmp	$+2
	jmp	$+2
	in	al, rtc_port1
	xor	ah,ah
   eind:pop	bp
	ret
_getrtc	ENDP


_gettab	PROC NEAR	; get the disk definition tabel in the BIOS
;
; gettab (table, curr_ptr)
;
; The disk table in the BIOS is copied into a user-structure (see below).
; In order to know where it starts, the caller got the current definition
; which is just an index into this table, and transformed this into a
; negative offset to be used by this routine. The current pointer of
; the interrupt 41h vector points to this definition in the ROM-BIOS.
;
	push	bp
	mov	bp,sp
	push	ds
	push	ds

	mov	di,[bp+4]	; destination
	mov	cx,[bp+6]	; length
	shr	cx,1		; move words

	xor	ax,ax
	mov	es,ax
	mov	ax,es:[104h+2]	; FDBtab segment at int 41h location
	mov	ds,ax		; source segment at int 41h location

	mov	ax,es:[104h]	; FDBtab offset + index
	sub	ax,[bp+8]	; base of table
	mov	si,ax		; source offset

	pop	es		; es=ds (destination segment)
	cld
	rep	movsw		; copy it.

	pop	ds
	pop	bp
	ret
_gettab	ENDP

ENDS
	end
-------------------------------- cut ----------------------

/* File to read out the disk types defined in your BIOS and display
 * them on the screen. Uses the previous assembler
 */

#include <stdio.h>

int i, disktype;

typedef unsigned int word;
typedef unsigned char byte;

struct FDBTAB {		/* fixed disk base table */
    word	ncyls;
    byte	nheads;
    word	dummy1;
    word	wr_pre;
    byte	eccburst;
    byte	control;
    byte	dummy2;
    byte	dummy3;
    byte	dummy4;
    word	landing;
    byte	sects;
    byte	reserved;
} FDBtab [60];

char header[]="\
nr.  cyls.  heads  wr-pre  ecc  control  landing  sects\n\
---  -----  -----  ------  ---  -------  -------  -----\n";

main(argc,argv)
int argc;
char *argv[];
{
    if (argc>1)
	if (stricmp(argv[1],"-i")==0)
	    ignore= 1;			/* don't stop after null definiton */
    if ((disktype=getrtc(0x12)) == -1) {
	    puts ("RTC-diagnose bad or not an AT");
	    exit(1);
    }
    disktype = (disktype & 0xF0) >> 4;
    if (disktype==15)
	disktype= getrtc(0x19);
    printf ("current type HD1: %d\n\n",disktype);
    gettab (FDBtab, 60*sizeof(struct FDBTAB), (disktype-1)*sizeof(struct FDBTAB));

    i=0; printf (header);
    while (FDBtab[i].ncyls || FDBtab[i+1].ncyls || ignore) {
	printf ("%2d%8u%7d%8d%5d%9x%9d%7d\n",i+1,
			FDBtab[i].ncyls,
			FDBtab[i].nheads,
			FDBtab[i].wr_pre,
			FDBtab[i].eccburst,
			FDBtab[i].control,
			FDBtab[i].landing,
			FDBtab[i].sects );
	i++;
    }
}
------------------------ cut ------------------

Kind regards, Paul Ogilvie