[comp.unix.microport] 25 Sector disk with Uport: "FIX"

elwiz@killer.DALLAS.TX.US (Chert Pellett) (07/25/88)

I did it... I got MicroPort unix to BOOT off a 25 sector drive! Compaq 386/20.
Now if I could just get floating point to work.....sigh, have to wait on that.


    In any event, I thought that you all might be interrested in what
needs to be done to get it to work....


    Here's what you need to do as I see it:

    1) Backup your system.  Be sure to mount a floppy and use

       find /dev -print | cpio -pdmvl /mnt
	
       Note: You will have to use 'mkfs /dev/dsk/fd096 2400:5500' as if your
             System is like mine, you will have in excess of 5,000 Devices
	     in the /dev directory!

       to backup all of your devices, (if whatever backup you use does not do
       this...Most don't)  I forgot to do this and had to reload dosmerge in 
       order to get back my Virtual consoles..

    2) Build a bootable floppy system, I just copied the one supplied by 
       Microport. (install boot disk). There is an documented command
       mkboot (1M), well sorta, I found a reference to it in one of the
       intro sections, but I can't find the executable or man page....
       This may well be in the famous 'next release'...

    3) recompile the kernel to load in the new hd.o, I also loaded
       the new asy.o, but that's your choice.

    4) Mount the floppy as /mnt         (mount /dev/dsk/0s25 /mnt)

    5) copy a stripped copy of /unix to /mnt/unix. (I would NOT strip
       /unix, but copy it then strip it)  I stripped it to reduce it
       from a 490K kernel to a 360K kernel. (I have digiboard drivers
       installed for Ipx/8)

    6) copy the following files to /mnt/bin:
        cat - Not needed if you like using cp FILE /dev/console
        ls  - I like to see what's going on! (not critial either)
        cmos_setup - I used this too, but not critial
        whatever restore program you need.

        If it will fit:
        ed/vi   - I didn't have this, but really needed it
              Or some editor....

    7) Using either UNIX or DOS, compile the patch program at end of this
       file, it will be needed later. Sorry, I can't say that this patch
       code is well tested, I ran it in bits at a time.  `It should work'
       On UNIX, you will have to modify the sector read/write calls to
       use seeks and write()'s into /dev/dsk/0s0. If on unix be sure to
       copy the executable to /mnt/bin.

    8) Boot the new floppy, (You may need to use dos to set the disk
       type, cmos_setup will not allow drive type 16-19!! I have a type
       17 as my 2nd drive.. and 47 as my main drive)

    9) Follow all of the installation instructions,  When it asks you to
       remove floppy and reboot, you may attempt to do so, but it won't
       work.. You will get a row of dots, then it will hang...

    10) Either:
        1) Reboot using the floppy (hit DEL at 1st prompt)
           edit /etc/partitions so that:
           vtocsec = 25 (not 17), altsec=26, (not 18)
           (If you were unable to put any form of editor on the disk
            you will have to use option 2 here...)

        OR: 2) Using Nortons NU, search the disk for the string 'vtocsec'
               (somewhere around sector 2350), patch it using the HEX
           patch utiltiy in norton.

           (or any other sector editor you like)

	OR: 3) If you happen to have another unix machine just laying around,
	       mount the floppy and edit the file...

    11) Execute the following string of commands:  [May not even be needed]

        /* Taken from INSTALL script */

        mkpart -i disk0
        mkpart -P rootus -P swap -P reserved -P alts disk0

    Execute the rest of /INSTALL, I did it by hand as I had no editor...
    Note: Do not execute all of /INSTALL as this would overwrite
          /etc/partitions and you would be back to square one.

    12) Install the patches by running the patch program. Basiclly what
        it does is this:

        Patches one compare instruction at:
              Cylinder 1, Head 0, Sec 3, Offset 0xA0 from 17 to 25.

        Installs a patch to the code at: (Before call to int 13)
              Cylinder 1, Head 0, Sec 2, Offset 0x5E
            From : {0xB2, 0x80, 0xCD, 0x13};
            To   : {0xE8, 0x9F, 0x15, 0x90};

        The old code:
            mov dx, 80h
            int 13h

        The New code:
            call near ptr 1800h ; call to patch code.
            nop         ; had an extra byte...
    
        Copys patch code into unused (but LOADED after boot code!) sector.
              Cylinder 1, Head 0, Sec 13

        This patch code changes the value in ds:[13B2] to 25..ie:

            proc patch near
                cmp word ptr ds:[13B2h], 17 ; Right spot?/First time?
                jne skip
                mov word ptr ds:[13B2h], 25 ; 25 Sectors per track!
            skip:
                mov dl, 80h
                int 13h
                ret

            The hex bytes are as follows:
                 83 3E B2 13 11 75 06 C7 06 B2 13 19 00 B2 80 CD 13 C3

        [The above patch was needed because The location [13B2] is somehow
        initilized AFTER the program is loaded into memory.  I tried to patch
        all of the "17's" on the disk to "25's", and of the 10 I found, 
        2 hung the computer, 1 trashed the clock, 6 did nothing, and the
        other one is patch #1...]
        
        [The next step may not be needed...]
        copys:
              Cylinder 0, Head 1, Sec 0
          to
              Cylinder 0, Head 0, Sec 17

        This is the PD/VTOC sector, I copied it over to the old location
        so it didn't matter where the OS or Boot code looked for it, as
        long as it found the correct one! (the one made by the LAST
        mkpart -i part0, using 25 sectors..)

    13) Reboot and pray that your system was close enough to mine that the
        above patches worked... If they did, you should get the boot:
        prompt, and things should work fine when you hit return...

All in all, I only had a week of down time for this little adventure....
Isn't working on the bare metal fun?  Having your boss bitch at ya for
spending $1500 on an OS (We got MERGE & Development [Unlimited]) and have
cute little problems like this...All in all tho, I do like microport, only
wish that they would hurry with this next wonderous version!  The above
patch comes with ABSOLUTELY NO GUARENTEE, It is Simi-tested, as noted I
did make 7 patches that "did nothing" (so I unpatched them...But they might
have made other patches when they ran..).  I am not willing to reformat my
system to test to make sure that the above instructions will work for you..
(unless ya want to send me some pretty hefty bucks, I can on request send
you a hex dump of the first 2 tracks. This might help you if the above did
not do it for ya)  I wrote several versions of the patch in sector 13, one
dumped out what Cyl, Head, and Sector the boot program was reading as
well as allowing you to look at any location in memory... (I was getting
rather despate to get this going... After all I had spent some 75 hours on
it, and was almost ready to write my own loader... the only thing that
kept me from doing it was I didn't know where UNIX wanted to be loaded and
if it needed anything setup for it.

    For your information, the boot process is as follows:

    ROM reads in sector # 0,0,0   (cyl, head, Sec). and Jumps to start of it.
        This sector holds Initial boot code as well as the partition table.
        (last half)

    This then reads in Sector (0,1,0) (Track #2, sector 0) This is UNIX's
        Initial boot sector.

    This code then reparses sector 0,0,0 to find out where UNIX is at (again)
        and loads in sectors (0,1,1) to (0,1,16) This is the Third stage
        boot code, presumably /etc/boot. (I have not verified this tho).

    This code then reparses sector 0,0,0 to find out where UNIX is at (again)
        And loads in Sector 0,0,1 and 0,1,1  From these it computes where the
        Physical description sector should be at. The Pd points to the VTOC
        sector (It is Just after the Physical description, In the same sector)
        (This sector is 0, 1, 2 on my system, I think that it is here on all
        Uports disks..)

        Then the code puts out the boot: prompt, and waits for a filename,
        a <CR> or a timeout.

        When it has those, it reads in the first INODE block, Grabs a block
        number from there and (The one for the 2nd INODE, 1st one is reserved),
        This will be the Root directory INODE.  It reads it and obtains a
        block list block number, gets that block (which is a list of blocks
        that are in the file). Reads in that block (which is the first block
        in the / directory). searches it for the file specified (/unix or 
        whatever).  If it finds it then it repeats the last to indirections
        to find the blocks in /unix.  It then loads unix and jumps to it...

        I presume that Unix once loaded, will have to grab sector 0,0,0 and
        use it to initilize the hard disk driver so that it knows what part
        of the disk is it's.  I doubt that there are any information passed
        from the 3rd stage boot to the 4th stage boot (/unix).


    Good Luck, I'm sure that you will need it.

        -- Chert Pellett        {ihnp4, etc}!killer!spdyne!root
           Spectra Dyne Inc.

---------- Cut/Hack/Rip/Chop/Etc here ----------

/* Apply patchs to allow 25 sectors on Microport's unix.

   1) replace call to INT 13 with call to cs:1800 (Relative)
   2) Build new sector to jump out to
   3) Patch 2nd stage boot code to look for 25 sectors
   4) make a 2nd copy of VTOC/PD at the 17th sector...

*/


unsigned char buf[512];

#define WARN    1		/* Warn the person if ORG Code is not correct */
#define NOWARN  0		/* Just make the patch, don't ask about anything */

char ORG_1[] = {0xB2, 0x80, 0xCD, 0x13};
char PCH_1[] = {0xE8, 0x9F, 0x15, 0x90};
#define SIZ_1  4
#define OFF_1  0x5E		/* Offset into block.. */

char ORG_2[] = {0};	/* It doesn't matter, it is not used */
char PCH_2[] = {0x83, 0x3E, 0xB2, 0x13, 0x11, 0x75, 0x06, 0xC7, 0x06, 0xB2, 
                0x13, 0x19, 0x00, 0xB2, 0x80, 0xCD, 0x13, 0xC3};
#define SIZ_2  sizeof (PCH_2)
#define OFF_2  0		/* Offset into block.. */

char ORG_3[] = {0x11};
char PCH_3[] = {0x19};
#define SIZ_3  1
#define OFF_3  0xA0		/* Offset into block.. */

main ()
{

patch (1,0,2,  OFF_1, ORG_1, PCH_1, SIZ_1, WARN);	/* Patch 2nd boot loader */
patch (1,0,13, OFF_2, ORG_2, PCH_2, SIZ_2, NOWARN);	/* Patch code in unused area */
patch (1,0,3,  OFF_3, ORG_3, PCH_3, SIZ_3, WARN);	/* Patch 2nd boot loader */

#ifdef UNIX
Need to do the calls below via seeking into /dev/dsk/0s0 as shown below
#else
biosdisk (READ_DISK, 0x80, 0, 1, 0, 1, buf);	/* Read in VTOC/PD sector */
biosdisk (WRITE_DISK, 0x80, 0, 0, 17, 1, buf);	/* Update other location */
#endif

printf ("If you are luckly, it should now be bootable...\n");
}

#ifdef UNIX
patch (cyl, head, sec, offset, orig, pch, size, warn)
int cyl, head, sec, offset, size, warn;
unsigned char *orig, *pch;
{
/* You will have to open /dev/dsk/0s0, and seek into it by
   512L * (cly * 125 + head * 25 + sec)
   read in 512 bytes, apply patch as below, seek back there again
   and write the sector back.. (or you could seek to the exact byte location
   that you want and only read in those bytes, but it is all the same..)
*/
}

#else

#define READ_DISK  2
#define WRITE_DISK 3

patch (cyl, head, sec, offset, orig, pch, size, warn)
int cyl, head, sec, offset, size, warn;
unsigned char *orig, *pch;
{
	int I;

biosdisk (READ_DISK, 0x80, head, cyl, sec, 1, buf);	/* Read in the sector */

if (warn)	/* do we check to see if we should do the patch? */
	{
	for (I=0; I < size; I++)
		if (buf[offset+I] != orig[I])
			{
			printf ("Hum, looks like the patch might not work, as the\n");
			printf ("Bytes I am expecting arn't there.\n");
			printf ("Press <ENTER> to patch anyway (^C to abort)\n");
			getchar ();
			}
		else
			buf[off+I] = pch[I];	/* Apply patch as we scan... */
	}

biosdisk (WRITE_DISK, 0x80, head, cyl, sec, 1, buf);	/* Update the sector */
}


/* Biosdisk is a Turbo C built in, it calls int 13 as follows:

   es = ds;
   bx = (int) buf;
   cl = sec;		 Upper 2 used for the Cyl, but it never exceeds 255
                       in our program, so this will work
   ch = Cyl;
   dl = Drive #, 0x80 for Hard disk C.
   dh = head;
   Ah = Opcode;  (First parm to biosdisk)
   Al = # of sectors to read;	never pass in 0...

*/
#endif