boot1.S revision 62660
140269Srnordier#
240269Srnordier# Copyright (c) 1998 Robert Nordier
340269Srnordier# All rights reserved.
440269Srnordier#
540269Srnordier# Redistribution and use in source and binary forms are freely
640269Srnordier# permitted provided that the above copyright notice and this
740269Srnordier# paragraph and the following disclaimer are duplicated in all
840269Srnordier# such forms.
940269Srnordier#
1040269Srnordier# This software is provided "AS IS" and without any express or
1140269Srnordier# implied warranties, including, without limitation, the implied
1240269Srnordier# warranties of merchantability and fitness for a particular
1340269Srnordier# purpose.
1440269Srnordier#
1540269Srnordier
1650477Speter# $FreeBSD: head/sys/boot/i386/boot2/boot1.S 62660 2000-07-06 00:29:40Z jhb $
1740269Srnordier
1861836Sjhb# Memory Locations
1942478Speter		.set MEM_REL,0x700		# Relocation address
2042478Speter		.set MEM_ARG,0x900		# Arguments
2140269Srnordier		.set MEM_ORG,0x7c00		# Origin
2240269Srnordier		.set MEM_BUF,0x8c00		# Load area
2340269Srnordier		.set MEM_BTX,0x9000		# BTX start
2440269Srnordier		.set MEM_JMP,0x9010		# BTX entry point
2540269Srnordier		.set MEM_USR,0xa000		# Client start
2662138Sjhb		.set BDA_BOOT,0x472		# Boot howto flag
2761836Sjhb
2861836Sjhb# Partition Constants
2940269Srnordier		.set PRT_OFF,0x1be		# Partition offset
3040269Srnordier		.set PRT_NUM,0x4		# Partitions
3140269Srnordier		.set PRT_BSD,0xa5		# Partition type
3240269Srnordier
3361836Sjhb# Flag Bits
3461836Sjhb		.set FL_PACKET,0x80		# Packet mode
3561836Sjhb
3661836Sjhb# Misc. Constants
3740269Srnordier		.set SIZ_PAG,0x1000		# Page size
3840269Srnordier		.set SIZ_SEC,0x200		# Sector size
3940269Srnordier
4040269Srnordier		.globl start
4140269Srnordier		.globl xread
4260821Sjhb		.code16
4340269Srnordier
4440269Srnordierstart:		jmp main			# Start recognizably
4540269Srnordier
4640269Srnordier		.org 0x4,0x90
4761836Sjhb#
4861836Sjhb# Trampoline used by boot2 to call read to read data from the disk via
4961836Sjhb# the BIOS.  Call with:
5061836Sjhb#
5161836Sjhb# %cx:%ax	- long    - LBA to read in
5261836Sjhb# %es:(%bx)	- caddr_t - buffer to read data into
5361836Sjhb# %dl		- byte    - drive to read from
5461836Sjhb# %dh		- byte    - num sectors to read
5561836Sjhb#
5640269Srnordier
5760821Sjhbxread:		push %ss			# Address
5860821Sjhb		pop %ds				#  data
5961836Sjhb#
6061836Sjhb# Setup an EDD disk packet and pass it to read
6161836Sjhb#
6260821Sjhbxread.1:					# Starting
6360821Sjhb		pushl $0x0			#  absolute
6460821Sjhb		push %cx			#  block
6560821Sjhb		push %ax			#  number
6660821Sjhb		push %es			# Address of
6760821Sjhb		push %bx			#  transfer buffer
6860821Sjhb		xor %ax,%ax			# Number of
6948919Srnordier		movb %dh,%al			#  blocks to
7060821Sjhb		push %ax			#  transfer
7160821Sjhb		push $0x10			# Size of packet
7260821Sjhb		mov %sp,%bp			# Packet pointer
7360821Sjhb		callw read			# Read from disk
7460821Sjhb		lea 0x10(%bp),%sp		# Clear stack
7541008Srnordier		lret				# To far caller
7661836Sjhb#
7761836Sjhb# Load the rest of boot2 and BTX up, copy the parts to the right locations,
7861836Sjhb# and start it all up.
7961836Sjhb#
8040269Srnordier
8161836Sjhb#
8261836Sjhb# Setup the segment registers to flat addressing (segment 0) and setup the
8361836Sjhb# stack to end just below the start of our code.
8461836Sjhb#
8540269Srnordiermain:		cld				# String ops inc
8660821Sjhb		xor %cx,%cx			# Zero
8760821Sjhb		mov %cx,%es			# Address
8860821Sjhb		mov %cx,%ds			#  data
8960821Sjhb		mov %cx,%ss			# Set up
9060821Sjhb		mov $start,%sp			#  stack
9161836Sjhb#
9261836Sjhb# Relocate ourself to MEM_REL.  Since %cx == 0, the inc %ch sets
9361836Sjhb# %cx == 0x100.
9461836Sjhb#
9560821Sjhb		mov %sp,%si			# Source
9660821Sjhb		mov $MEM_REL,%di		# Destination
9741008Srnordier		incb %ch			# Word count
9840269Srnordier		rep				# Copy
9960821Sjhb		movsw				#  code
10061836Sjhb#
10161836Sjhb# If we are on a hard drive, then load the MBR and look for the first
10261836Sjhb# FreeBSD slice.  We use the fake partition entry below that points to
10361836Sjhb# the MBR when we call nread.  The first pass looks for the first active
10461836Sjhb# FreeBSD slice.  The second pass looks for the first non-active FreeBSD
10561836Sjhb# slice if the first one fails.
10661836Sjhb#
10760821Sjhb		mov $part4,%si			# Partition
10840269Srnordier		cmpb $0x80,%dl			# Hard drive?
10940269Srnordier		jb main.4			# No
11041008Srnordier		movb $0x1,%dh			# Block count
11160821Sjhb		callw nread			# Read MBR
11260821Sjhb		mov $0x1,%cx	 		# Two passes
11360821Sjhbmain.1: 	mov $MEM_BUF+PRT_OFF,%si	# Partition table
11440269Srnordier		movb $0x1,%dh			# Partition
11560821Sjhbmain.2: 	cmpb $PRT_BSD,0x4(%si)		# Our partition type?
11640269Srnordier		jne main.3			# No
11760821Sjhb		jcxz main.5			# If second pass
11860821Sjhb		testb $0x80,(%si)		# Active?
11940269Srnordier		jnz main.5			# Yes
12060821Sjhbmain.3: 	add $0x10,%si	 		# Next entry
12140269Srnordier		incb %dh			# Partition
12241008Srnordier		cmpb $0x1+PRT_NUM,%dh		# In table?
12341008Srnordier		jb main.2			# Yes
12460821Sjhb		dec %cx				# Do two
12560821Sjhb		jcxz main.1			#  passes
12661836Sjhb#
12761836Sjhb# If we get here, we didn't find any FreeBSD slices at all, so print an
12861836Sjhb# error message and die.
12961836Sjhb#
13060821Sjhb		mov $msg_part,%si		# Message
13140269Srnordier		jmp error			# Error
13261836Sjhb#
13361836Sjhb# Floppies use partition 0 of drive 0.
13461836Sjhb#
13560821Sjhbmain.4: 	xor %dx,%dx			# Partition:drive
13661836Sjhb#
13761836Sjhb# Ok, we have a slice and drive in %dx now, so use that to locate and load
13861836Sjhb# boot2.  %si references the start of the slice we are looking for, so go
13961836Sjhb# ahead and load up the first 16 sectors (boot1 + boot2) from that.  When
14061836Sjhb# we read it in, we conveniently use 0x8c00 as our transfer buffer.  Thus,
14161836Sjhb# boot1 ends up at 0x8c00, and boot2 starts at 0x8c00 + 0x200 = 0x8e00.
14262660Sjhb# The first part of boot2 is the disklabel, which is 0x200 bytes long.
14361836Sjhb# The second part is BTX, which is thus loaded into 0x9000, which is where
14461836Sjhb# it also runs from.  The boot2.bin binary starts right after the end of
14561836Sjhb# BTX, so we have to figure out where the start of it is and then move the
14661836Sjhb# binary to 0xb000.  Normally, BTX clients start at MEM_USR, or 0xa000, but
14761836Sjhb# when we use btxld create boot2, we use an entry point of 0x1000.  That
14862658Sjhb# entry point is relative to MEM_USR; thus boot2.bin starts at 0xb000.
14961836Sjhb#
15060821Sjhbmain.5: 	mov %dx,MEM_ARG			# Save args
15141008Srnordier		movb $0x10,%dh			# Sector count
15260821Sjhb		callw nread			# Read disk
15360821Sjhb		mov $MEM_BTX,%bx		# BTX
15461836Sjhb		mov 0xa(%bx),%si		# Get BTX length and set
15561836Sjhb		add %bx,%si			#  %si to start of boot2.bin
15660821Sjhb		mov $MEM_USR+SIZ_PAG,%di	# Client page 1
15760821Sjhb		mov $MEM_BTX+0xe*SIZ_SEC,%cx	# Byte
15860821Sjhb		sub %si,%cx			#  count
15940269Srnordier		rep				# Relocate
16040269Srnordier		movsb				#  client
16160821Sjhb		sub %di,%cx			# Byte count
16261836Sjhb		xorb %al,%al			# Zero assumed bss from
16361836Sjhb		rep				#  the end of boot2.bin
16461836Sjhb		stosb				#  up to 0x10000
16560821Sjhb		callw seta20			# Enable A20
16660821Sjhb		jmp start+MEM_JMP-MEM_ORG	# Start BTX
16761836Sjhb#
16861836Sjhb# Enable A20 so we can access memory above 1 meg.
16961836Sjhb#
17040675Srnordierseta20: 	cli				# Disable interrupts
17140675Srnordierseta20.1:	inb $0x64,%al			# Get status
17240269Srnordier		testb $0x2,%al			# Busy?
17340675Srnordier		jnz seta20.1			# Yes
17440269Srnordier		movb $0xd1,%al			# Command: Write
17540269Srnordier		outb %al,$0x64			#  output port
17640675Srnordierseta20.2:	inb $0x64,%al			# Get status
17740269Srnordier		testb $0x2,%al			# Busy?
17840675Srnordier		jnz seta20.2			# Yes
17940269Srnordier		movb $0xdf,%al			# Enable
18040269Srnordier		outb %al,$0x60			#  A20
18140675Srnordier		sti				# Enable interrupts
18260821Sjhb		retw				# To caller
18361836Sjhb#
18461836Sjhb# Trampoline used to call read from within boot1.
18561836Sjhb#
18660821Sjhbnread:		mov $MEM_BUF,%bx		# Transfer buffer
18760821Sjhb		mov 0x8(%si),%ax		# Get
18860821Sjhb		mov 0xa(%si),%cx		#  LBA
18960821Sjhb		push %cs			# Read from
19060821Sjhb		callw xread.1	 		#  disk
19161836Sjhb		jnc return			# If success, return
19261836Sjhb		mov $msg_read,%si		# Otherwise, set the error
19361836Sjhb						#  message and fall through to
19461836Sjhb						#  the error routine
19561836Sjhb#
19661836Sjhb# Print out the error message pointed to by %ds:(%si) followed
19761836Sjhb# by a prompt, wait for a keypress, and then reboot the machine.
19861836Sjhb#
19960821Sjhberror:		callw putstr			# Display message
20060821Sjhb		mov $prompt,%si			# Display
20160821Sjhb		callw putstr			#  prompt
20240269Srnordier		xorb %ah,%ah			# BIOS: Get
20340269Srnordier		int $0x16			#  keypress
20462138Sjhb		movw $0x1234, BDA_BOOT		# Do a warm boot
20562138Sjhb		ljmp $0xffff,$0x0		# reboot the machine
20661836Sjhb#
20761836Sjhb# Display a null-terminated string using the BIOS output.
20861836Sjhb#
20960821Sjhbputstr.0:	mov $0x7,%bx	 		# Page:attribute
21040269Srnordier		movb $0xe,%ah			# BIOS: Display
21140269Srnordier		int $0x10			#  character
21240269Srnordierputstr: 	lodsb				# Get char
21340269Srnordier		testb %al,%al			# End of string?
21440269Srnordier		jne putstr.0			# No
21540269Srnordier
21661836Sjhb#
21761836Sjhb# Overused return code.  ereturn is used to return an error from the
21861836Sjhb# read function.  Since we assume putstr succeeds, we (ab)use the
21961836Sjhb# same code when we return from putstr.
22061836Sjhb#
22141008Srnordierereturn:	movb $0x1,%ah			# Invalid
22241008Srnordier		stc				#  argument
22360821Sjhbreturn: 	retw				# To caller
22461836Sjhb#
22561836Sjhb# Reads sectors from the disk.  If EDD is enabled, then check if it is
22661836Sjhb# installed and use it if it is.  If it is not installed or not enabled, then
22761836Sjhb# fall back to using CHS.  Since we use a LBA, if we are using CHS, we have to
22861836Sjhb# fetch the drive parameters from the BIOS and divide it out ourselves.
22961836Sjhb# Call with:
23061836Sjhb#
23161836Sjhb# %dl	- byte     - drive number
23261836Sjhb# stack - 10 bytes - EDD Packet
23362138Sjhb#
23462138Sjhbread:	 	push %dx			# Save
23540269Srnordier		movb $0x8,%ah			# BIOS: Get drive
23640269Srnordier		int $0x13			#  parameters
23740269Srnordier		movb %dh,%ch			# Max head number
23860821Sjhb		pop %dx				# Restore
23941008Srnordier		jc return			# If error
24040269Srnordier		andb $0x3f,%cl			# Sectors per track
24141008Srnordier		jz ereturn			# If zero
24241008Srnordier		cli				# Disable interrupts
24360821Sjhb		mov 0x8(%bp),%eax		# Get LBA
24460821Sjhb		push %dx			# Save
24560821Sjhb		movzbl %cl,%ebx			# Divide by
24660821Sjhb		xor %edx,%edx			#  sectors
24760821Sjhb		div %ebx			#  per track
24840269Srnordier		movb %ch,%bl			# Max head number
24940269Srnordier		movb %dl,%ch			# Sector number
25060821Sjhb		inc %bx				# Divide by
25141008Srnordier		xorb %dl,%dl			#  number
25260821Sjhb		div %ebx			#  of heads
25340269Srnordier		movb %dl,%bh			# Head number
25460821Sjhb		pop %dx				# Restore
25560821Sjhb		cmpl $0x3ff,%eax		# Cylinder number supportable?
25641008Srnordier		sti				# Enable interrupts
25762138Sjhb		ja read.7			# No, try EDD
25840269Srnordier		xchgb %al,%ah			# Set up cylinder
25940269Srnordier		rorb $0x2,%al			#  number
26040269Srnordier		orb %ch,%al			# Merge
26160821Sjhb		inc %ax				#  sector
26260821Sjhb		xchg %ax,%cx	 		#  number
26340269Srnordier		movb %bh,%dh			# Head number
26440269Srnordier		subb %ah,%al			# Sectors this track
26560821Sjhb		mov 0x2(%bp),%ah		# Blocks to read
26640269Srnordier		cmpb %ah,%al			# To read
26748919Srnordier		jb read.2			#  this
26840269Srnordier		movb %ah,%al			#  track
26960821Sjhbread.2: 	mov $0x5,%di	 		# Try count
27060821Sjhbread.3: 	les 0x4(%bp),%bx		# Transfer buffer
27160821Sjhb		push %ax			# Save
27241008Srnordier		movb $0x2,%ah			# BIOS: Read
27341008Srnordier		int $0x13			#  from disk
27460821Sjhb		pop %bx				# Restore
27548919Srnordier		jnc read.4			# If success
27660821Sjhb		dec %di				# Retry?
27748919Srnordier		jz read.6			# No
27840269Srnordier		xorb %ah,%ah			# BIOS: Reset
27940269Srnordier		int $0x13			#  disk system
28060821Sjhb		xchg %bx,%ax	 		# Block count
28148919Srnordier		jmp read.3			# Continue
28260821Sjhbread.4: 	movzbw %bl,%ax	 		# Sectors read
28360821Sjhb		add %ax,0x8(%bp)		# Adjust
28448919Srnordier		jnc read.5			#  LBA,
28560821Sjhb		incw 0xa(%bp)	 		#  transfer
28648919Srnordierread.5: 	shlb %bl			#  buffer
28760821Sjhb		add %bl,0x5(%bp)		#  pointer,
28860821Sjhb		sub %al,0x2(%bp)		#  block count
28962138Sjhb		ja read				# If not done
29060821Sjhbread.6: 	retw				# To caller
29162138Sjhbread.7:		testb $FL_PACKET,%cs:MEM_REL+flags-start # LBA support enabled?
29262138Sjhb		jz ereturn			# No, so return an error
29362138Sjhb		mov $0x55aa,%bx			# Magic
29462138Sjhb		push %dx			# Save
29562138Sjhb		movb $0x41,%ah			# BIOS: Check
29662138Sjhb		int $0x13			#  extensions present
29762138Sjhb		pop %dx				# Restore
29862138Sjhb		jc return			# If error, return an error
29962138Sjhb		cmp $0xaa55,%bx			# Magic?
30062138Sjhb		jne ereturn			# No, so return an error
30162138Sjhb		testb $0x1,%cl			# Packet interface?
30262138Sjhb		jz ereturn			# No, so return an error
30362138Sjhb		mov %bp,%si			# Disk packet
30462138Sjhb		movb $0x42,%ah			# BIOS: Extended
30562138Sjhb		int $0x13			#  read
30662138Sjhb		retw				# To caller
30740269Srnordier
30840269Srnordier# Messages
30940269Srnordier
31041008Srnordiermsg_read:	.asciz "Read"
31141008Srnordiermsg_part:	.asciz "Boot"
31240269Srnordier
31341085Srnordierprompt: 	.asciz " error\r\n"
31440940Srnordier
31548919Srnordierflags:		.byte FLAGS			# Flags
31648919Srnordier
31740269Srnordier		.org PRT_OFF,0x90
31840269Srnordier
31940269Srnordier# Partition table
32040269Srnordier
32140269Srnordier		.fill 0x30,0x1,0x0
32240269Srnordierpart4:		.byte 0x80, 0x00, 0x01, 0x00
32340269Srnordier		.byte 0xa5, 0xff, 0xff, 0xff
32440269Srnordier		.byte 0x00, 0x00, 0x00, 0x00
32561836Sjhb		.byte 0x50, 0xc3, 0x00, 0x00	# 50000 sectors long, bleh
32640269Srnordier
32740269Srnordier		.word 0xaa55			# Magic number
328