home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
diskutil
/
noahdi
/
hd_inst.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-05
|
24KB
|
626 lines
/*
File: HD_INST.C Harddisk Driver Installer. AHDI Compatible.
*/
/*
Copyright (c) 1988 - 1991 by Ted Schipper.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation.
This software is provided AS IS with no warranties of any kind. The author
shall have no liability with respect to the infringement of copyrights,
trade secrets or any patents by this file or any part thereof. In no
event will the author be liable for any lost revenue or profits or
other special, indirect and consequential damages.
*/
#include "bootsec.h"
#include "hddriver.h"
#include "system.h"
#include <osbind.h>
#include <bios.h>
/***************************************************************************
Installer
-----------
HISTORY
---------
Feb 1989. THS. Started. Tested ppu, pread, getbpb. Made some corrections
to bootsector structure (allignment). Added a dirty
vector installer with hd debug messages.
Mar 1989. THS. Added pool_install.
Apr 1989. THS. Removed dirty vector installer. Added normal installer,
exec_res, exec_auto stuff.
May 1989. THS. Added some extra stuff to pread. Pread now generates an
error when a non existing drive is selected on a
existing controller. Can be done better.
Jun 1989. THS. Runs nice (still from auto folder). Added assembly startup
code to get it compatible Atari HD boot. Seems to work OK.
V0.00
***************************************************************************/
/***************************************************************************
Global Variables
***************************************************************************/
extern short puns;
extern struct bpb bpbs[];
extern struct hd_drv pun[];
extern func o_init;
extern func o_bpb;
extern func o_rw;
extern func o_mediach;
extern short hd_boot_flg;
extern long base_pg_addr;
/* Initialize variables to get them into the driver code */
short clun = 0; /* current logical unit */
short cpun = 0; /* current physical unit */
short installed = 0; /* number of installed partitions */
long cdbit = 0; /* current drive bit */
struct hd_boot pbuf, lbuf; /* sector buffers */
char *copy_msg =
"----------------------------\r\n\
ASCI/SCSI Hard Disk Driver\r\n\
NOAHDI V0.00 Sept-26-1989\r\n\
by T.Schipper Installed\r\n\
----------------------------\r\n";
char *env_str = "PATH=\0C:\\\0"; /* enviroment string */
char *nothing = "\0"; /* empry string */
char *auto_path = "C:\\AUTO\\*.PRG"; /* search string for Fsfirst */
char *command = "COMMAND.PRG"; /* prg to execute if comload is true */
long auto_base_pg = 0L; /* temp storage for basepage addr */
char dta[44] = {0,0}; /* DTA buffer */
char exec_path[32] = {0,0}; /* filename build string */
char *dvr_nld =
"Hard disk driver not loaded; hit RETURN\r\nkey to continue:\r\n";
char *dsk_bsd = "*** WARNING ***\r\n\a\
This hard disk driver may not work with\r\n\a\\
a disk-based version of TOS; files on\r\n\a\
your hard disk may be damaged.\r\n\a\r\n\a";
char *unf_rel = "*** WARNING ***\r\n\a\
You are using an unofficial ROM release\r\n\a\
of the operating system. This driver\r\n\a\
may not work correctly with it. Files\r\n\a\
on your hard disk may be damaged.\r\n\a\r\n\a";
struct rom_rev {
long rel_date; /* ROM release date */
long pool_list; /* free list addr of release */
};
struct rom_rev revtable[4] = { 0x11201985L, 0x000056FAL,
0x02061986L, 0x000056FAL,
0x04241986L, 0x000056FAL,
0x00000000L, 0x00000000L
};
/***************************************************************************
Installer
***************************************************************************/
/***************************************************************************
*
* Function name : exec_res. Execute memory resident programs.
* Parameters : None
* Returns : None
* Description : Check physical memory every 512 bytes for a long magic
* number. If magic number found, check if next long points
* to magic number. If pointer to magic number is valid,
* calculate the checksum of the first 256 words. If the
* check is magic too, execute memory resident program at
* the address specified in the 3rd long.
* Comments :
*/
void exec_res()
{
func res_prg;
unsigned short checksum;
short *chksum_ptr, i;
long *mem_ptr;
mem_ptr = (long *)PHYSTOP; /* get end of memory */
while ((mem_ptr -= 0x80) > (long *)0x0400L)
{ /* dec 512 bytes, untill 0x600, then */
if (*mem_ptr == 0x12123456L) /* magic long word at 512b boundary */
{
if (*(mem_ptr + 1) == (long)mem_ptr) /* pointer to magic OK */
{
checksum = 0; /* clear checksum */
chksum_ptr = (short *)mem_ptr; /* set pointer to first word */
for (i=0; i<256; i++) /* calc checksum from 256 words */
checksum += *chksum_ptr++;
if (checksum == 0x5678) /* is the checksum magic */
{
res_prg = (func)*(mem_ptr + 2); /* set pointer to entry point */
(*res_prg)(); /* execute memory resident programm */
}
}
}
}
}
/***************************************************************************
*
* Function name : exec_auto_prg. Start auto-folder execute process.
* Parameters : None
* Returns : None
* Description : Create a basepage for, and start the auto-folder program
* which executes all the programs in the auto folder.
* Comments : Since we can't read the micro registers, the basepage
* address is stored in a global variable. This variable
* is used by the auto-folder executer to find its basepage.
*/
void exec_auto_prg()
{
void auto_prg();
long *basepage;
basepage = (long *)Pexec(5,nothing,nothing,nothing); /* create a basepage */
*(basepage + 2) = (long)auto_prg; /* set process start address */
auto_base_pg = (long)basepage; /* save basepage address */
Pexec(4,nothing,basepage,nothing); /* execute auto_prg as a process */
}
/***************************************************************************
*
* Function name : auto_prg. Auto folder search and execute program.
* Parameters : None
* Returns : None
* Description : Search the auto folder for programs. Execute each found
* program. Set SYSBASE variable. Check if command load
* flag is set, and execute command.prg if set. Else build
* a basepage and execute the AES.
* Comments :
*/
void auto_prg()
{
char *ptr_s, *ptr_d, *ptr_m;
long *base_page;
func reset;
Dsetdrv(2); /* set the default drive to C: */
Super(auto_base_pg + 0x100L); /* supervisor mode, stack at end of basepage */
if (Mshrink(auto_base_pg,0x100L) == 0); /* return unused memory */
{
Fsetdta(dta); /* set disk transfer address */
if (Fsfirst(auto_path,7) == 0) /* check for auto prg's */
{
do
{
ptr_s = auto_path;
ptr_d = exec_path;
ptr_m = &auto_path[8];
while (ptr_s != ptr_m) /* copy C:\AUTO\ to exec filename string */
*ptr_d++ = *ptr_s++;
ptr_s = &dta[30]; /* ptr to found program filename */
while(*ptr_s != 0) /* copy filename from dta buffer */
*ptr_d++ = *ptr_s++;
Pexec(0,exec_path,nothing,nothing); /* load and execute prog */
Fsetdta(dta);
} while (Fsnext() == 0); /* find next auto prg */
}
}
reset = (func) RESET; /* set pointer to reset routine */
SYSBASE = 0xFC0000L; /* set OS entry back to ROM's */
if (COMLOAD) /* command load flag set */
Pexec(0,command,nothing,nothing); /* load and execute command.prg */
else /* start AES */
{
base_page = (long *)Pexec(5,nothing,nothing,env_str);
/* create a basepage */
*(base_page + 2) = EXEC_OS; /* set the AES entry point */
Pexec(4,nothing,base_page,env_str); /* start AES */
}
(*reset)(); /* should never return from AES or COMMAND, */
/* but if it may happen, jump to reset vector */
}
/***************************************************************************
*
* Function name : pool_install. Extend the OS pool buffer.
* Parameters : none.
* Returns : short. Number of bytes used to install pool.
* Description : Try to extend the OS pool buffer with 128 directory
* control blocks. Check if the right ROM's are used.
* Comments :
*/
short pool_install()
{
long *rel;
long *pool;
struct DCB *dcb, *tmp;
short *dos_date;
short i;
char *txt;
if (SYSBASE >= 0x800000L) /* ROM based OS */
{
i = 0;
rel = (long *)(SYSBASE + 0x18); /* pointer to ROM release date */
while (revtable[i].rel_date != 0x0L)
{
if (*rel == revtable[i].rel_date) /* compare with known releases */
{
pool = (long *)(revtable[i].pool_list + 16);
dcb = (struct DCB *) dvr_nld; /* get addr of end of program */
for (i=0; i<128; i++) /* install 128 DCB's into pool */
{
dcb->size = 4; /* DCB size in paragraphs */
tmp = dcb + 1; /* pointer to next DCB */
dcb->next = &tmp->next; /* put it in current DCB */
dcb = tmp; /* make next current */
}
dcb--; /* point to last DCB */
dcb->next = (struct DCB *) *pool; /* chain in old DCB's */
return(128 * 66); /* return bytes used for pool */
}
i++;
}
txt = unf_rel; /* assume unofficial ROM Release */
}
else
txt = dsk_bsd; /* assume disk based OS */
dos_date = (short *)(SYSBASE + 0x1E); /* pointer to ROM dos date */
if (*dos_date >= 0xCA1) /* new release ? */
return(0); /* assume new release with no folder problems */
Cconws(txt); /* print message if not 'new release' */
Cconws(dvr_nld); /* print driver not loaded */
while (Bconin(2) != '\r'); /* wait for a CR */
return(0); /* return with zero bytes pool installed */
}
/***************************************************************************
*
* Function name : i_sasi1. Normal entry point.
* Parameters : None
* Returns : int. 0xE0. Should not return.
* Description : Scans all ASCI devices by trying to read there boot
* sectors. When a PUN is found, its partitioned and the
* LUN is installed. If a LUN is found, the driver vectors
* are installed. If the driver was executed from the
* hard disk boot program, memory resident programs are
* executed and the auto folder execute process is started.
* Comments :
*/
i_sasi1()
{
short i;
long size;
long savssp;
void exec_auto_prg();
extern char _start[]; /* start of driver */
if (!hd_boot_flg) /* not called from HD boot */
savssp = Super(0L); /* then go into SUPERVISOR mode */
for (i=0; i < MAX_UNITS; i++) /* clear all physical units */
pun[i].dev_addr = -1;
clun = 2; /* set current logical unit number (C) */
cdbit = 4; /* set current drive bit (C) */
cpun = 0; /* set current physical unit number */
installed = 0; /* nothing installed yet */
puns = 0; /* no physical units found yet */
do
{
if (pread(0L,1,&pbuf,cpun) != 0L) /* read boot sector of each physical unit */
continue; /* next physical unit */
/* break; */ /* stop scanning if error */
puns ++; /* found a physical unit */
ppu(); /* partition it */
/* cpun ++;*/ /* next physical unit number */
} while (++cpun < MAX_UNITS);
if (puns) /* if a drive and partitions where found */
{
o_bpb = (func) HDV_BPB; /* store pointers to old functions */
o_rw = (func) HDV_RW;
o_mediach = (func) HDV_MEDI;
HDV_BPB = (long) hbpb; /* store pointer to new functions */
HDV_RW = (long) hrw;
HDV_MEDI = (long) hmediach;
PUN_PTR = (long) &puns;
i = pool_install(); /* install extra folders, get used bytes */
if (!hd_boot_flg) /* called from HD boot */
Super(savssp); /* no go into USER mode again */
size = (long)((long)dvr_nld - (long)&_start[0]) + 0x100 + i;
/* calc driver size */
if (!hd_boot_flg) /* not called from HD boot */
Ptermres(size,0); /* terminate and stay resident */
Cconws(copy_msg); /* print copy-right message */
BOOTDEV = 2; /* set boot device */
Mshrink(base_pg_addr,size); /* shrink allocated memory to size bytes */
exec_res(); /* execute memory resident programs */
exec_auto_prg(); /* start auto folder executer process */
/* we should never come back here */
}
else
{
if (!hd_boot_flg) /* not called by HD boot */
{
Super(savssp); /* back to user mode */
Pterm(-1); /* and quit */
}
else /* called by HD boot */
{
Mfree(base_pg_addr); /* free allocated memory */
return(0xE0); /* return highest ASCI unit number to stop */
/* BIOS DMA boot loop */
}
}
}
/***************************************************************************
*
* Function name : pread. Read physical sectors from harddisk with retries.
* Parameters : long sector number. 21 bits address.
* short sector count. 8 bits count.
* long buffer addr. 32 bits address.
* short device number. 4 bits: bit 0 = drive # (0 or 1)
* bit 1-3 = controller # (0-7)
* Returns : long OK = sectors are read.
* ERROR = (-1) timeout, sectors (drive) does not exist.
* >0 = read error on sector.
* Description : Try to read a physical sector(s) from harddisk. If a read
* error occurded, try again. Used to test if a drive is
* present on the ASCI bus.
* Comments : Assumes processor is in supervisor mode. A workaround
* for the HAC bug has been added to generate an error when
* a sector is read on a non existing drive.
*/
long pread(sect_nr,sect_cnt,buf_addr,dev)
long sect_nr;
short sect_cnt;
long buf_addr;
short dev;
{
short retrycnt = NRETRIES;
long status;
char *ptr;
short cnt;
ptr = (char *)buf_addr; /* get pointer to transfer buffer */
for (cnt=0; cnt < 512; cnt++) /* zap it */
*ptr++ = 0;
do
{
status = hread(sect_nr,sect_cnt,buf_addr,dev); /* read sectors */
} while ((status > 0L) && ((retrycnt --) > 0)) ; /* try again if read error */
if (status < 0L) /* timeout, return */
return(status);
ptr = (char *)buf_addr; /* get pointer to tranfer buffer */
for (cnt=0; cnt < 512; cnt++) /* check if still zapped */
{
if (*ptr++ != 0) /* no, return */
return(status);
}
return(ERROR); /* still zapped, return timeout error */
}
/***************************************************************************
*
* Function name : ppu. Partition physical unit.
* Parameters : None
* Returns : None
* Description : Check a boot sector for valid partition data. When OK
* build BPB's and record the PUN and start sector of each
* partition. If no partition is found, assume harddisk is
* one big partition.
* Comments :
*/
void ppu()
{
short i, npart;
npart = 0; /* reset partition count */
if (pbuf.hi_size) /* HD size > 0 */
{
/* printf("HD size unit %d = %ld\n",cpun,pbuf.hi_size); */
for (i=0; i < 4; i++) /* check the 4 partitions */
{
if (pbuf.p[i].pi_flag) /* active partition */
{
/* printf("Part %d is active: %d\n",i,pbuf.p[i].pi_flag); */
npart ++; /* count number of partitions on drive */
if (pbuf.p[i].pi_id[0] == 'G') /* check for valid partition name */
{
/* printf("found %c\n",pbuf.p[i].pi_id[0]); */
if (pbuf.p[i].pi_id[1] == 'E')
{
/* printf("found %c\n",pbuf.p[i].pi_id[1]); */
if (pbuf.p[i].pi_id[2] == 'M')
{
/* printf("found %c\n",pbuf.p[i].pi_id[2]); */
if (pbuf.p[i].pi_size) /* partition size OK */
{
/* printf("Part %d size = %ld\n",i,pbuf.p[i].pi_size); */
if (nxtdrv() >= 0) /* add partition to TOS, check */
{
/* printf("next Part OK\n"); */
if (getbpb(pbuf.p[i].pi_start) == 0L) /* build BPB */
{
/* printf("Part %d BPB build\n",i); */
pun[clun].dev_addr = cpun; /* set dev addr */
pun[clun].part_start = pbuf.p[i].pi_start; /* set start sector */
clun ++;
installed ++; /* actually installed a harddisk */
/* printf("partition %d found\n",clun-1);*/
/* Cconws("Partition found\r\n");*/
}
}
}
}
}
}
}
}
}
if (npart) /* did we find any partitions */
{
return; /* yes, then return */
}
else /* no, so build one BPB */
{
/* printf("No Partitions found\n");*/
/* Cconws("No Partitions found\r\n");*/
nxtdrv(); /* no valid partitions found, assume the whole */
pun[clun].dev_addr = cpun; /* thing is one big GEM disk */
pun[clun].part_start = 0L; /* starts at 0 */
bpbs[clun].bp_recsiz = 512; /* build BPB for GEM disk */
bpbs[clun].bp_clsiz = 2;
bpbs[clun].bp_clsizb = 1024;
bpbs[clun].bp_rdlen = 16;
bpbs[clun].bp_fsiz = 41;
bpbs[clun].bp_fatrec = 42;
bpbs[clun].bp_datrec = 99;
bpbs[clun].bp_numcl = 10300;
bpbs[clun].bp_flags = 1;
clun ++;
installed ++;
}
}
/***************************************************************************
*
* Function name : nxtdrv. Set TOS logical drive, check next drive.
* Parameters : None
* Returns : short >= 0 : Next Current Logical Unit (CLUN).
* ERROR: To many TOS drives installed already.
* Description : Check if clun is not overranged. If not, set drivebit
* in TOS variable, make mask for next drivebit and return
* clun.
* Comments :
*/
short nxtdrv()
{
if (clun >= MAX_UNITS) /* have we already hit the maximum */
return(ERROR); /* yes, so signal error */
DRVBITS |= cdbit; /* tell TOS we have the drive */
cdbit = (cdbit << 1); /* set next drive bit */
return(clun);
}
/***************************************************************************
*
* Function name : getbpb. Build a BPB block for a partition.
* Parameters : long partition sector number.
* Returns : long OK : always went OK.
* Description : Read the partition root sector. Build from root sector
* data a TOS BPB block.
* Comments :
*/
long getbpb(sectorno)
long sectorno;
{
short i,res_cnt,sec_cnt;
if (pread(sectorno,1,&lbuf,cpun) == OK) /* read partition boot sector */
{
bpbs[clun].bp_recsiz = getlhw(&lbuf,0x0B); /* sector size in H/L */
/* printf("CLUN %d: recsiz = %d\n",clun,bpbs[clun].bp_recsiz); */
bpbs[clun].bp_clsiz = lbuf.bp_spc; /* sectors per cluster */
/* printf("CLUN %d: clsiz = %d\n",clun,bpbs[clun].bp_clsiz); */
bpbs[clun].bp_clsizb = bpbs[clun].bp_recsiz * bpbs[clun].bp_clsiz; /* bytes per cluster */
/* printf("CLUN %d: clsizb = %d\n",clun,bpbs[clun].bp_clsizb); */
i = getlhw(&lbuf,0x11) * 32; /* bytes needed for root dir */
if (i % bpbs[clun].bp_recsiz) /* part of sector needed */
sec_cnt = i / bpbs[clun].bp_recsiz + 1; /* sectors for dir */
else
sec_cnt = i / bpbs[clun].bp_recsiz; /* sectors for dir */
bpbs[clun].bp_rdlen = sec_cnt; /* sectors for dir */
/* printf("CLUN %d: rd_len = %d\n",clun,bpbs[clun].bp_rdlen); */
i = getlhw(&lbuf,0x16); /* get FAT size in sectors */
bpbs[clun].bp_fsiz = i; /* store FAT size in sectors */
/* printf("CLUN %d: fsiz = %d\n",clun,bpbs[clun].bp_fsiz); */
res_cnt = i; /* count reserved sectors */
i = getlhw(&lbuf,0x0E); /* get reserved sectors */
bpbs[clun].bp_fatrec = res_cnt + i; /* start of 2nd FAT */
/* printf("CLUN %d: fatrec = %d\n",clun,bpbs[clun].bp_fatrec); */
sec_cnt += (res_cnt * 2 + i); /* total reserved sectors */
bpbs[clun].bp_datrec = sec_cnt; /* set start of data sector */
/* printf("CLUN %d: datrec = %d\n",clun,bpbs[clun].bp_datrec); */
i = getlhw(&lbuf,0x13); /* get total # sectors */
i -= sec_cnt; /* calc remaining # sectors */
i /= lbuf.bp_spc; /* calc remaining # clusters */
bpbs[clun].bp_numcl = i; /* set # data clusters */
/* printf("CLUN %d: numcl = %d\n",clun,bpbs[clun].bp_numcl); */
bpbs[clun].bp_flags = 1; /* set 16-bit FAT's */
return(OK);
}
}
/***************************************************************************
*
* Function name : getlhw. Swop short from INTEL to MOTOROLA format.
* Parameters : char *start. pointer to start boot sector.
* short offset. offset into boot sector where short is.
* Returns : short. Motorola format.
* Description : Swop the 2 bytes, beginning at address + offset. return
* the swopped bytes.
* Comments :
*/
short getlhw(addr,offset)
char *addr;
short offset;
{
char *ptr;
short temp;
ptr = (char *) &temp; /* get pointer to temporary short */
ptr[1] = addr[offset]; /* swop short bytes to MOTOROLA short */
ptr[0] = addr[offset+1];
return(temp); /* return swopt short */
}