[comp.os.minix] minix on a Gateway 2000 386 & Automatic reboot fix

clk@splash.Princeton.EDU (Christopher Kranz) (02/22/91)

The original problem that I posted was that I was unable to boot minix
on a Gateway 2000 386 with any of the boot disks that came with the PH
distribution disks.  The following messages would flash across the top
of my screen until I removed the boot disk:

"Booting MINIX 1.5.  Copyright 1990 Prentice-Hall, Inc."
"Read error.  Automatic reboot."

Several people responded to my post and indicated to me that it was
indeed possible to run minix on a Gateway 2000 386 because they were
doing so.  I was also informed that there is a known bug in the boot
block code that causes the problem I have described on some high
density 5 1/4" drives.

After reading people's suggestions and doing some poking around on my
own I have come up with three different solutions.  The first two
require that I find another system to build minix and the last is a
patch for the boot disk itself.  I'll describe briefly the first two
and go into more detail on the third since I believe that is the better
way to go.

The first and obvious solution is find a system that you can boot on,
load minix on that system, get a patched version of bootblok.s, and
finally rebuild the system using the new boot code.  I heard from at
least three people who actually went through this very procedure.  One
kind person was nice enough to mail me a fixed version of bootblok.s
and I have appended it to the end of this post.

The second solution is similar to the first.  Basically it was
suggested that I could get some code via ftp to enable minix to boot
from a hard disk.  The code I found was shoelace.  In addition to being
able to boot from a hard disk it also would allow me to build a floppy
disk that would also boot up automatically.  I found shoelace at
plains.nodak.edu in the pub/Minix/oz directory.  Again it would require
me to find an alternate system to build the new boot disk.

The solution that I finally went with was to patch the code that was on
the boot disk itself.  First make a copy of the AT boot disk using
diskcopy.  Then make another.  You don't want to take any chances.
Insert one of the copies into drive 0 and invoke debug using the debug
script found towards the end of this post.  Be sure to include all
blank lines, they are very important to how debug interprets the
script.  The invocation might look like this:

C:> debug < boot.fix

This assumes you have saved the debug script as a file called
boot.fix.  What this script does is read in the the boot block, make
some changes to the boot code, and then write the modified boot block
back out to disk.

I want to thank everyone who responded with special thanks to the
following people:

bk0y+@andrew.cmu.edu (Brian Christopher Kircher)
seb3@gte.com (Steve Belczyk)
chiting@garfield.cs.wisc.edu (Chiting Lam)
martine@serena.cs.pdx.edu (Martine Wedlake)

I hope this information helps somebody out there.

	Chris Kranz
	clk@gfdl.princeton.edu

---------------------Begin Debug Script-------------------------------------
a100
mov cx,0001
mov bx,0200
mov ax,0201
int 13
jc 0106
int 20

g=100
a261
nop
nop

a269
jmp 02af

a100
mov cx,0001
mov bx,0200
mov ax,0301
int 13
jc 0106
int 20

g=100
q

---------------------End Debug Script---------------------------------------

---------------------Begin bootblok.s---------------------------------------
| When the PC is powered on, it reads the first block from the floppy
| disk into address 0x7C00 and jumps to it.  This boot block must contain
| the boot program in this file.  The boot program first copies itself to
| address 256K - 1536 (to get itself out of the way).  Then it loads the 
| operating system from the boot diskette into memory, and then jumps to menu.
| Loading is not trivial because the PC is unable to read a track into
| memory across a 64K boundary, so the positioning of everything is critical.
| The number of sectors to load is contained at address 504 of this block.
| The value is put there by the build program after it has discovered how
| big the operating system is.  When the bootblok program is finished loading,
| it jumps indirectly to the program (menu) which address is given by the
| last two words in the boot block. 
|
| Summary of the words patched into the boot block by build:
| Word at 504: # sectors to load
| Word at 506: # DS value for menu
| Word at 508: # PC value for menu
| Word at 510: # CS value for menu
|
| This version of the boot block must be assembled without separate I & D
| space.  
|
| Guy Helmer - 1/6/91:
| Fixed to properly handle 1.44M, 1.2M, 720K, and 360K disk types.

        LOADSEG = 0x0060         | here the boot block will start loading
        BIOSSEG = 0x07C0         | here the boot block itself is loaded
        BOOTSEG = 0x3FA0         | here it will copy itself (256K-1.5K)
        DSKBASE = 120            | 120 = 4 * 0x1E = ptr to disk parameters

final   = 504
menu_ds = 506
menu_pc = 508
menu_cs = 510


.globl begtext, begdata, begbss, endtext, enddata, endbss  | asld needs these
.text
begtext:
.data
begdata:
.bss
begbss:
.text

| copy bootblock to bootseg
        mov     ax,#BIOSSEG
        mov     ds,ax
        xor     si,si           | ds:si - original block
        mov     ax,#BOOTSEG
        mov     es,ax
        xor     di,di           | es:di - new block
        mov     cx,#256         | #  words to move
	rep
	movw			| copy loop
    
	
| start boot procedure
	jmpi	start, BOOTSEG	| set cs to BOOTSEG

start:
	mov     dx,cs
        mov     ds,dx           | set ds to cs
        xor     ax,ax
        mov     es,ax           | set es to 0
        mov     ss,dx           | set ss to cs i.e., stack in high core
        mov     sp,#1536        | initialize sp to high core

| print greeting
	mov	ax,#2		| reset video
	int	0x10

        mov     ax,#0x0200	| BIOS call in put cursor in ul corner
        xor     bx,bx
        xor     dx,dx
        int     0x10
        mov     bx,#greet
        call    print

| Initialize disk parameters, then
| try 1.44M diskette by trying to read sector 18

| tracksiz has been initialized to 18 for dshd3 test
	mov	ax,#dshd3	| double sided, high density 3.5" parms
	call	sdp

	xor	ax,ax		| reset drive
	int	0x13

| Procedure sdp leaves es set to 0
|	xor	ax,ax
|	mov	es,ax
	mov	ax,#0x0201	| read sector, #sector = 1
	mov	bx,#0x0600	| es:bx buffer
	mov	cx,#0x0012	| track 0, sector 18
	xor	dx,dx		| drive 0, head 0
	int	0x13
	jnb	L1

| Error. It wasn't 1.44M. Now set up for 1.2M
	mov	tracksiz,#15	| 15 sectors per track
	mov	ax,#dshd5	| double sided, high density 5.25" parms
	call	sdp

	xor	ax,ax		| reset drive
	int	0x13

| Procedure sdp leaves es set to 0
|	xor	ax,ax
|	mov	es,ax
	mov	ax,#0x0201	| read sector, #sector = 1
	mov	bx,#0x0600	| es:bx buffer
	mov	cx,#0x000F	| track 0, sector 15
	xor	dx,dx		| drive 0, head 0
	int	0x13
	jnb	L1

| Try 720K by trying to read track 41.  360K has 40 tracks; 720K has
| 80.  Old code used to try to read track 64, which would grind the
| heck out of some drives.
|
	mov	tracksiz,#9
	mov	ax,#dsdd3	| double sided, double density 3.5" parms
	call	sdp

	xor	ax,ax		| reset drive
	int	0x13

| Procedure sdp leaves es set to 0
|	xor	ax,ax
|	mov	es,ax
	mov	ax,#0x0201	| read sector, number of sectors is 1
	mov	bx,#0x0600	| es:bx buffer
	mov	cx,#0x2901	| track 41, sector 1
	xor	dx,dx		| drive 0, head 0
	int	0x13
	jnb	L1

| It wasn't 720K either, so set up for last possible
| disk type (360K) and hope it works.

	mov	ax,#dsdd5	| double sided, double density 5.25" parms
	call	sdp

	xor	ax,ax		| reset drive
	int	0x13

L1:

| Load the operating system from diskette.
load:
	call	setreg		| set up ah, cx, dx
	mov	bx,disksec	| bx = number of next sector to read
	add	bx,#2		| diskette sector 1 goes at 1536 ("sector" 3)
	shl	bx,#1		| multiply sector number by 32
	shl	bx,#1		| ditto
	shl	bx,#1		| ditto
	shl	bx,#1		| ditto
	shl	bx,#1		| ditto
	mov	es,bx		| core address is es:bx (with bx = 0)
	xor	bx,bx		| see above
	add	disksec,ax	| ax tells how many sectors to read
	movb	ah,#2		| opcode for read
	int	0x13		| call the BIOS for a read
	jb	error		| jump on diskette error
	mov	ax,disksec	| see if we are done loading
	cmp	ax,final	| ditto
	jb	load		| jump if there is more to load

| Loading done.  Finish up.
        mov     dx,#0x03F2      | kill the motor
        mov     ax,#0x000C
        out
        cli
	mov	bx,tracksiz	| menu expects # sectors/track in bx
        mov     ax,menu_ds      | set segment registers
        mov     ds,ax           | when sep I&D DS != CS
        mov     es,ax           | otherwise they are the same.
        mov     ss,ax           | words 504 - 510 are patched by build

	seg cs
	jmpi	@menu_pc	| jmp to menu

| Given the number of the next disk block to read, disksec, compute the
| cylinder, sector, head, and number of sectors to read as follows:
| ah = # sectors to read;  cl = sector #;  ch = cyl;  dh = head; dl = 0
setreg:	
	mov	si,tracksiz	| 9, 15, or 18 sectors per track
	mov 	ax,disksec	| ax = next sector to read
	xor	dx,dx		| dx:ax = 32-bit dividend
	div	si		| divide sector # by track size
	mov	cx,ax		| cx = track #; dx = sector (0-origin)
	mov	bx,dx		| bx = sector number (0-origin)
	mov	ax,disksec	| ax = next sector to read
	add	ax,si		| ax = last sector to read + 1
	dec	ax		| ax = last sector to read
	xor	dx,dx		| dx:ax = 32-bit dividend
	div	tracksiz	| divide last sector by track size
	cmpb	al,cl		| is starting track = ending track
	je	set1		| jump if whole read on 1 cylinder
	sub	si,dx		| compute lower sector count
	dec	si		| si = # sectors to read

| Check to see if this read crosses a 64K boundary (128 sectors).
| Such calls must be avoided.  The BIOS gets them wrong.
set1:	mov	ax,disksec	| ax = next sector to read
	add	ax,#2		| disk sector 1 goes in core sector 3
	mov	dx,ax		| dx = next sector to read
	add	dx,si		| dx = one sector beyond end of read
	dec	dx		| dx = last sector to read
	shl	ax,#1		| ah = which 64K bank does read start at
	shl	dx,#1		| dh = which 64K bank foes read end in
	cmpb	ah,dh		| ah != dh means read crosses 64K boundary
	je	set2		| jump if no boundary crossed
	shrb	dl,#1		| dl = excess beyond 64K boundary
	xorb	dh,dh		| dx = excess beyond 64K boundary
	sub	si,dx		| adjust si
	dec	si		| si = number of sectors to read

set2:	mov	ax,si		| ax = number of sectors to read
	xor	dx,dx		| dh = head, dl = drive
	movb	dh,cl		| dh = track
	andb	dh,#0x01	| dh = head
	movb	ch,cl		| ch = track to read
	shrb	ch,#1		| ch = cylinder
	movb	cl,bl		| cl = sector number (0-origin)
	incb	cl		| cl = sector number (1-origin)
	xorb	dl,dl		| dl = drive number (0)
	ret			| return values in ax, cx, dx


|-------------------------------+
|    error & print routines     |
|-------------------------------+

error:
        push    ax
        mov     bx,#fderr
        call    print           | print msg
| Wait for user to hit a key
	xor	ax,ax
	int	0x16
|	xor	cx,cx
|err1:	mul	0		| delay
|	loop	err1
	int	0x19


print:                          | print string (bx)
        movb	al,(bx)	        | al contains char to be printed
        testb   al,al           | null char?
        jne     prt1            | no
        ret                     | else return
prt1:   movb    ah,#14          | 14 = print char
        inc     bx              | increment string pointer
        push    bx              | save bx
        movb    bl,#1           | foreground color
	xorb	bh,bh		| page 0
        int     0x10            | call BIOS VIDEO_IO
        pop     bx              | restore bx
        jmp     print           | next character

| Sets disk parameter pointer (vector 0x1E) to offset given in ax
| and segment given in ds
| Leaves es set to 0 and destroys bx
sdp:
	xor	bx,bx
	mov	es,bx
	mov	bx,ds
	seg	es
	mov	DSKBASE,ax
	seg	es
	mov	DSKBASE+2,bx
	ret

disksec:.word 1
| For 3.5" drives (the format gap length parms might be wrong, but
| that won't matter):
dshd3:	.byte	0xAF, 0x02, 25, 2,18, 0x1B, 0xFF, 0x54, 0xF6, 1, 8
| To save space, we use the same parameters for dsdd3 as dsdd5,
| since they're close enough:
| dsdd3:.byte	0xDF, 0x02, 25, 2, 9, 0x2A, 0xFF, 0x54, 0xF6, 1, 8
dsdd3:
| For 5.25" drives:
dsdd5:	.byte	0xDF, 0x02, 25, 2, 9, 0x2A, 0xFF, 0x50, 0xF6, 1, 3
dshd5:	.byte	0xDF, 0x02, 25, 2,15, 0x1B, 0xFF, 0x54, 0xF6, 1, 8

fderr:	.asciz "Read error.  Automatic reboot.\r\n"
greet:	.asciz "\rBooting MINIX 1.5.  Copyright 1990 Prentice-Hall, Inc.\r\n"
tracksiz:.word 18	| Changed to 15 for 1.2M or 9 for 360K and 720K

| Don't forget that words 504 - 510 are filled in by build.  The regular
| code had better not get that far.
.text
endtext:
.data
enddata:
.bss
endbss:
---------------------End bootblok.s-----------------------------------------
-------------------------------------------------------------------------------
            Christopher L. Kranz                     GFDL
         Computer Systems Programmer                 P.O. Box 308
    Geophysical Fluid Dynamics Laboratory            Princeton, NJ  08542
-------------------------------------------------------------------------------
  Internet Address: clk@gfdl.princeton.edu        Commercial: (609)452-6585
      UUCP Address: princeton!gfdl!clk                   FTS:      298-6585
                                                         FAX: (609)987-5063
===============================================================================