patch-2.4.10 linux/arch/i386/boot/bootsect.S

Next file: linux/arch/i386/boot/compressed/Makefile
Previous file: linux/arch/cris/kernel/ptrace.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.9/linux/arch/i386/boot/bootsect.S linux/arch/i386/boot/bootsect.S
@@ -5,8 +5,12 @@
  *	modified by Bruce Evans (bde)
  *	modified by Chris Noe (May 1999) (as86 -> gas)
  *
- * bootsect is loaded at 0x7c00 by the bios-startup routines, and moves
- * itself out of the way to address 0x90000, and jumps there.
+ * 360k/720k disk support: Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl>
+ *
+ * BIG FAT NOTE: We're in real mode using 64k segments.  Therefore segment
+ * addresses must be multiplied by 16 to obtain their respective linear
+ * addresses. To avoid confusion, linear addresses are written using leading
+ * hex while segment addresses are written as segment:offset.
  *
  * bde - should not jump blindly, there may be systems with only 512K low
  * memory.  Use int 0x12 to get the top of memory, etc.
@@ -43,7 +47,7 @@
 
 #ifndef RAMDISK
 #define RAMDISK 0
-#endif 
+#endif
 
 #ifndef ROOT_RDONLY
 #define ROOT_RDONLY 1
@@ -55,14 +59,12 @@
 .global _start
 _start:
 
-#if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */
-	int	$0x3
-#endif
+# First things first. Move ourself from 0x7C00 -> 0x90000 and jump there.
 
 	movw	$BOOTSEG, %ax
-	movw	%ax, %ds
+	movw	%ax, %ds		# %ds = BOOTSEG
 	movw	$INITSEG, %ax
-	movw	%ax, %es
+	movw	%ax, %es		# %ax = %es = INITSEG
 	movw	$256, %cx
 	subw	%si, %si
 	subw	%di, %di
@@ -81,7 +83,7 @@
 					# length of bootsect + length of
 					# setup + room for stack;
 					# 12 is disk parm size.
-	movw	%ax, %ds		# ax and es already contain INITSEG
+	movw	%ax, %ds		# %ax and %es already contain INITSEG
 	movw	%ax, %ss
 	movw	%di, %sp		# put stack at INITSEG:0x4000-12.
 
@@ -97,52 +99,29 @@
 #
 # High doesn't hurt.  Low does.
 #
-# Segments are as follows: ds = es = ss = cs - INITSEG, fs = 0,
-# and gs is unused.
+# Segments are as follows: %cs = %ds = %es = %ss = INITSEG, %fs = 0,
+# and %gs is unused.
 
-	movw	%cx, %fs		# set fs to 0
-	movw	$0x78, %bx		# fs:bx is parameter table address
+	movw	%cx, %fs		# %fs = 0
+	movw	$0x78, %bx		# %fs:%bx is parameter table address
 	pushw	%ds
-	ldsw	%fs:(%bx), %si		# ds:si is source
+	ldsw	%fs:(%bx), %si		# %ds:%si is source
 	movb	$6, %cl			# copy 12 bytes
-	pushw	%di			# di = 0x4000-12.
-	rep				# don't need cld -> done on line 66
-	movsw
+	pushw	%di			# %di = 0x4000-12.
+	rep				# don't worry about cld
+	movsw				# already done above
 	popw	%di
 	popw	%ds
 	movb	$36, 0x4(%di)		# patch sector count
 	movw	%di, %fs:(%bx)
 	movw	%es, %fs:2(%bx)
 
-# Load the setup-sectors directly after the bootblock.
-# Note that 'es' is already set up.
-# Also, cx = 0 from rep movsw above.
-
-load_setup:
-	xorb	%ah, %ah		# reset FDC 
-	xorb	%dl, %dl
-	int 	$0x13	
-	xorw	%dx, %dx		# drive 0, head 0
-	movb	$0x02, %cl		# sector 2, track 0
-	movw	$0x0200, %bx		# address = 512, in INITSEG
-	movb	$0x02, %ah		# service 2, "read sector(s)"
-	movb	setup_sects, %al	# (assume all on head 0, track 0)
-	int	$0x13			# read it
-	jnc	ok_load_setup		# ok - continue
-
-	pushw	%ax			# dump error code
-	call	print_nl
-	movw	%sp, %bp
-	call	print_hex
-	popw	%ax	
-	jmp	load_setup
-
-ok_load_setup:
 # Get disk drive parameters, specifically number of sectors/track.
 
 # It seems that there is no BIOS call to get the number of sectors.
 # Guess 36 sectors if sector 36 can be read, 18 sectors if sector 18
 # can be read, 15 if sector 15 can be read.  Otherwise guess 9.
+# Note that %cx = 0 from rep movsw above.
 
 	movw	$disksizes, %si		# table of sizes to try
 probe_loop:
@@ -151,30 +130,56 @@
 	movw	%ax, sectors
 	cmpw	$disksizes+4, %si
 	jae	got_sectors		# If all else fails, try 9
-	
-	xchgw	%cx, %ax		# cx = track and sector
+
+	xchgw	%cx, %ax		# %cx = track and sector
 	xorw	%dx, %dx		# drive 0, head 0
-	xorb	%bl, %bl
-	movb	setup_sects, %bh
-	incb	%bh
-	shlb	%bh			# address after setup (es = cs) 
+	movw	$0x0200, %bx		# address = 512, in INITSEG (%es = %cs)
 	movw	$0x0201, %ax		# service 2, 1 sector
 	int	$0x13
 	jc	probe_loop		# try next value
 
 got_sectors:
-	movw	$INITSEG, %ax
-	movw	%ax, %es		# set up es
 	movb	$0x03, %ah		# read cursor pos
 	xorb	%bh, %bh
 	int	$0x10
 	movw	$9, %cx
-	movw	$0x0007, %bx		# page 0, attribute 7 (normal)
-	movw    $msg1, %bp
-	movw    $0x1301, %ax		# write string, move cursor
+	movb	$0x07, %bl		# page 0, attribute 7 (normal)
+					# %bh is set above; int10 doesn't
+					# modify it
+	movw	$msg1, %bp
+	movw	$0x1301, %ax		# write string, move cursor
 	int	$0x10			# tell the user we're loading..
-	movw	$SYSSEG, %ax		# ok, we've written the message, now
-	movw	%ax, %es		# we want to load system (at 0x10000)
+
+# Load the setup-sectors directly after the moved bootblock (at 0x90200).
+# We should know the drive geometry to do it, as setup may exceed first
+# cylinder (for 9-sector 360K and 720K floppies).
+
+	movw	$0x0001, %ax		# set sread (sector-to-read) to 1 as
+	movw	$sread, %si		# the boot sector has already been read
+	movw	%ax, (%si)
+
+	xorw	%ax, %ax		# reset FDC
+	xorb	%dl, %dl
+	int	$0x13
+	movw	$0x0200, %bx		# address = 512, in INITSEG
+next_step:
+	movb	setup_sects, %al
+	movw	sectors, %cx
+	subw	(%si), %cx		# (%si) = sread
+	cmpb	%cl, %al
+	jbe	no_cyl_crossing
+	movw	sectors, %ax
+	subw	(%si), %ax		# (%si) = sread
+no_cyl_crossing:
+	call	read_track
+	pushw	%ax			# save it
+	call	set_next		# set %bx properly; it uses %ax,%cx,%dx
+	popw	%ax			# restore
+	subb	%al, setup_sects	# rest - for next step
+	jnz	next_step
+
+	pushw	$SYSSEG
+	popw	%es			# %es = SYSSEG
 	call	read_it
 	call	kill_motor
 	call	print_nl
@@ -184,23 +189,26 @@
 # Otherwise, one of /dev/fd0H2880 (2,32) or /dev/PS0 (2,28) or /dev/at0 (2,8)
 # depending on the number of sectors we pretend to know we have.
 
+# Segments are as follows: %cs = %ds = %ss = INITSEG,
+#	%es = SYSSEG, %fs = 0, %gs is unused.
+
 	movw	root_dev, %ax
 	orw	%ax, %ax
 	jne	root_defined
-	
+
 	movw	sectors, %bx
 	movw	$0x0208, %ax		# /dev/ps0 - 1.2Mb
 	cmpw	$15, %bx
 	je	root_defined
-	
+
 	movb	$0x1c, %al		# /dev/PS0 - 1.44Mb
 	cmpw	$18, %bx
 	je	root_defined
-	
+
 	movb	$0x20, %al		# /dev/fd0H2880 - 2.88Mb
 	cmpw	$36, %bx
 	je	root_defined
-	
+
 	movb	$0, %al			# /dev/fd0 - autodetect
 root_defined:
 	movw	%ax, root_dev
@@ -210,46 +218,45 @@
 
 	ljmp	$SETUPSEG, $0
 
-# This routine loads the system at address 0x10000, making sure
-# no 64kB boundaries are crossed. We try to load it as fast as
-# possible, loading whole tracks whenever we can.
-
-# es = starting address segment (normally 0x1000)
+# These variables are addressed via %si register as it gives shorter code.
 
 sread:	.word 0				# sectors read of current track
 head:	.word 0				# current head
 track:	.word 0				# current track
 
+# This routine loads the system at address SYSSEG, making sure
+# no 64kB boundaries are crossed. We try to load it as fast as
+# possible, loading whole tracks whenever we can.
+
 read_it:
-	movb	setup_sects, %al
-	incb	%al
-	movb	%al, sread
-	movw	%es, %ax
+	movw	%es, %ax		# %es = SYSSEG when called
 	testw	$0x0fff, %ax
-die:	jne	die			# es must be at 64kB boundary
-
-	xorw	%bx, %bx		# bx is starting address within segment
+die:	jne	die			# %es must be at 64kB boundary
+	xorw	%bx, %bx		# %bx is starting address within segment
 rp_read:
-#ifdef __BIG_KERNEL__
-	bootsect_kludge = 0x220		# 0x200 (size of bootsector) + 0x20 (offset
-	lcall	bootsect_kludge		# of bootsect_kludge in setup.S)
+#ifdef __BIG_KERNEL__			# look in setup.S for bootsect_kludge
+	bootsect_kludge = 0x220		# 0x200 + 0x20 which is the size of the
+	lcall	bootsect_kludge		# bootsector + bootsect_kludge offset
 #else
 	movw	%es, %ax
 	subw	$SYSSEG, %ax
+	movw	%bx, %cx
+	shr	$4, %cx
+	add	%cx, %ax		# check offset
 #endif
-	cmpw	syssize, %ax		# have we loaded all yet?
+	cmpw	syssize, %ax		# have we loaded everything yet?
 	jbe	ok1_read
 
 	ret
 
 ok1_read:
 	movw	sectors, %ax
-	subw	sread, %ax
+	subw	(%si), %ax		# (%si) = sread
 	movw	%ax, %cx
 	shlw	$9, %cx
 	addw	%bx, %cx
 	jnc	ok2_read
-	
+
 	je	ok2_read
 
 	xorw	%ax, %ax
@@ -257,60 +264,64 @@
 	shrw	$9, %ax
 ok2_read:
 	call	read_track
-	movw	%ax, %cx
-	addw	sread, %ax
-	cmpw	sectors, %ax
-	jne	ok3_read
-	
-	movw	$1, %ax
-	subw	head, %ax
-	jne	ok4_read
-	
-	incw	track
-ok4_read:
-	movw	%ax, head
-	xorw	%ax, %ax
-ok3_read:
-	movw	%ax, sread
-	shlw	$9, %cx
-	addw	%cx, %bx
-	jnc	rp_read
-	
-	movw	%es, %ax
-	addb	$0x10, %ah
-	movw	%ax, %es
-	xorw	%bx, %bx
+	call	set_next
 	jmp	rp_read
 
 read_track:
 	pusha
 	pusha	
-	movw	$0xe2e, %ax 			# loading... message 2e = .
+	movw	$0xe2e, %ax 		# loading... message 2e = .
 	movw	$7, %bx
  	int	$0x10
 	popa		
-	movw	track, %dx
-	movw	sread, %cx
+
+# Accessing head, track, sread via %si gives shorter code.
+
+	movw	4(%si), %dx		# 4(%si) = track
+	movw	(%si), %cx		# (%si)  = sread
 	incw	%cx
 	movb	%dl, %ch
-	movw	head, %dx
+	movw	2(%si), %dx		# 2(%si) = head
 	movb	%dl, %dh
 	andw	$0x0100, %dx
 	movb	$2, %ah
-	pushw	%dx				# save for error dump
+	pushw	%dx			# save for error dump
 	pushw	%cx
 	pushw	%bx
 	pushw	%ax
 	int	$0x13
 	jc	bad_rt
-	
+
 	addw	$8, %sp
 	popa
 	ret
 
+set_next:
+	movw	%ax, %cx
+	addw	(%si), %ax		# (%si) = sread
+	cmp	sectors, %ax
+	jne	ok3_set
+	movw	$0x0001, %ax
+	xorw	%ax, 2(%si)		# change head
+	jne	ok4_set
+	incw	4(%si)			# next track
+ok4_set:
+	xorw	%ax, %ax
+ok3_set:
+	movw	%ax, (%si)		# set sread
+	shlw	$9, %cx
+	addw	%cx, %bx
+	jnc	set_next_fin
+	movw	%es, %ax
+	addb	$0x10, %ah
+	movw	%ax, %es
+	xorw	%bx, %bx
+set_next_fin:
+	ret
+
 bad_rt:
-	pushw	%ax				# save error code
-	call	print_all			# ah = error, al = read
+	pushw	%ax			# save error code
+	call	print_all		# %ah = error, %al = read
 	xorb	%ah, %ah
 	xorb	%dl, %dl
 	int	$0x13
@@ -331,13 +342,13 @@
 #	ret <- %sp
  
 print_all:
-	movw	$5, %cx				# error code + 4 registers
+	movw	$5, %cx			# error code + 4 registers
 	movw	%sp, %bp
 print_loop:
-	pushw	%cx				# save count left
-	call	print_nl			# nl for readability
+	pushw	%cx			# save count remaining
+	call	print_nl		# <-- for readability
 	cmpb	$5, %cl
-	jae	no_reg				# see if register name is needed
+	jae	no_reg			# see if register name is needed
 	
 	movw	$0xe05 + 'A' - 1, %ax
 	subb	%cl, %al
@@ -347,31 +358,31 @@
 	movb	$':', %al
 	int	$0x10
 no_reg:
-	addw	$2, %bp				# next register
-	call	print_hex			# print it
+	addw	$2, %bp			# next register
+	call	print_hex		# print it
 	popw	%cx
 	loop	print_loop
 	ret
 
 print_nl:
-	movw	$0xe0d, %ax			# CR
+	movw	$0xe0d, %ax		# CR
 	int	$0x10
-	movb	$0xa, %al			# LF
+	movb	$0xa, %al		# LF
 	int 	$0x10
 	ret
 
 # print_hex is for debugging purposes, and prints the word
-# pointed to by ss:bp in hexadecimal.
+# pointed to by %ss:%bp in hexadecimal.
 
 print_hex:
-	movw	$4, %cx				# 4 hex digits
-	movw	(%bp), %dx			# load word into dx
+	movw	$4, %cx			# 4 hex digits
+	movw	(%bp), %dx		# load word into %dx
 print_digit:
-	rolw	$4, %dx				# rotate to use low 4 bits
-	movw	$0xe0f, %ax			# ah = request
-	andb	%dl, %al			# al = mask for nybble
-	addb	$0x90, %al			# convert al to ascii hex
-	daa					# in only four instructions!
+	rolw	$4, %dx			# rotate to use low 4 bits
+	movw	$0xe0f, %ax		# %ah = request
+	andb	%dl, %al		# %al = mask for nybble
+	addb	$0x90, %al		# convert %al to ascii hex
+	daa				# in only four instructions!
 	adc	$0x40, %al
 	daa
 	int	$0x10
@@ -381,6 +392,7 @@
 # This procedure turns off the floppy drive motor, so
 # that we enter the kernel in a known state, and
 # don't have to worry about it later.
+# NOTE: Doesn't save %ax or %dx; do it yourself if you need to.
 
 kill_motor:
 	movw	$0x3f2, %dx

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)