boot1.S revision 48919
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
1648919Srnordier#	$Id: boot1.s,v 1.8 1999/01/13 23:30:07 rnordier Exp $
1740269Srnordier
1842478Speter		.set MEM_REL,0x700		# Relocation address
1942478Speter		.set MEM_ARG,0x900		# Arguments
2040269Srnordier		.set MEM_ORG,0x7c00		# Origin
2140269Srnordier		.set MEM_BUF,0x8c00		# Load area
2240269Srnordier		.set MEM_BTX,0x9000		# BTX start
2340269Srnordier		.set MEM_JMP,0x9010		# BTX entry point
2440269Srnordier		.set MEM_USR,0xa000		# Client start
2540269Srnordier
2640269Srnordier		.set PRT_OFF,0x1be		# Partition offset
2740269Srnordier		.set PRT_NUM,0x4		# Partitions
2840269Srnordier		.set PRT_BSD,0xa5		# Partition type
2940269Srnordier
3040269Srnordier		.set SIZ_PAG,0x1000		# Page size
3140269Srnordier		.set SIZ_SEC,0x200		# Sector size
3240269Srnordier
3340269Srnordier		.globl start
3440269Srnordier		.globl xread
3540269Srnordier
3640269Srnordierstart:		jmp main			# Start recognizably
3740269Srnordier
3840269Srnordier		.org 0x4,0x90
3940269Srnordier
4041008Srnordier# External read from disk
4141008Srnordier
4248919Srnordierxread:		pushl %ss			# Address
4348919Srnordier		popl %ds			#  data
4448919Srnordierxread.1:	o16				# Starting
4548919Srnordier		pushb $0x0			#  absolute
4648919Srnordier		pushl %ecx			#  block
4748919Srnordier		pushl %eax			#  number
4848919Srnordier		pushl %es			# Address of
4948919Srnordier		pushl %ebx			#  transfer buffer
5048919Srnordier		xorl %eax,%eax			# Number of
5148919Srnordier		movb %dh,%al			#  blocks to
5248919Srnordier		pushl %eax			#  transfer
5348919Srnordier		pushb $0x10			# Size of packet
5448919Srnordier		movl %esp,%ebp			# Packet pointer
5540269Srnordier		callwi(read)			# Read from disk
5648919Srnordier		leaw1r(0x10,_bp_,_sp)		# Clear stack
5741008Srnordier		lret				# To far caller
5840269Srnordier
5941008Srnordier# Bootstrap
6041008Srnordier
6140269Srnordiermain:		cld				# String ops inc
6241008Srnordier		xorl %ecx,%ecx			# Zero
6341008Srnordier		movl %cx,%es			# Address
6441008Srnordier		movl %cx,%ds			#  data
6541008Srnordier		movl %cx,%ss			# Set up
6640269Srnordier		movwir(start,_sp)		#  stack
6740269Srnordier		movl %esp,%esi			# Source
6840269Srnordier		movwir(MEM_REL,_di)		# Destination
6941008Srnordier		incb %ch			# Word count
7040269Srnordier		rep				# Copy
7140269Srnordier		movsl				#  code
7241008Srnordier		movwir(part4,_si)		# Partition
7340269Srnordier		cmpb $0x80,%dl			# Hard drive?
7440269Srnordier		jb main.4			# No
7541008Srnordier		movb $0x1,%dh			# Block count
7641008Srnordier		callwi(nread)			# Read MBR
7741008Srnordier		movwir(0x1,_cx) 		# Two passes
7840269Srnordiermain.1: 	movwir(MEM_BUF+PRT_OFF,_si)	# Partition table
7940269Srnordier		movb $0x1,%dh			# Partition
8040269Srnordiermain.2: 	cmpbi1(PRT_BSD,0x4,_si_)	# Our partition type?
8140269Srnordier		jne main.3			# No
8241008Srnordier		jecxz main.5			# If second pass
8340269Srnordier		tstbi0(0x80,_si_)		# Active?
8440269Srnordier		jnz main.5			# Yes
8540269Srnordiermain.3: 	addl $0x10,%esi 		# Next entry
8640269Srnordier		incb %dh			# Partition
8741008Srnordier		cmpb $0x1+PRT_NUM,%dh		# In table?
8841008Srnordier		jb main.2			# Yes
8941008Srnordier		decl %ecx			# Do two
9041008Srnordier		jecxz main.1			#  passes
9140269Srnordier		movwir(msg_part,_si)		# Message
9240269Srnordier		jmp error			# Error
9340269Srnordiermain.4: 	xorl %edx,%edx			# Partition:drive
9440269Srnordiermain.5: 	movwrm(_dx,MEM_ARG)		# Save args
9541008Srnordier		movb $0x10,%dh			# Sector count
9640269Srnordier		callwi(nread)			# Read disk
9740269Srnordier		movwir(MEM_BTX,_bx)		# BTX
9840269Srnordier		movw1r(0xa,_bx_,_si)		# Point past
9940269Srnordier		addl %ebx,%esi			#  it
10040269Srnordier		movwir(MEM_USR+SIZ_PAG,_di)	# Client page 1
10140314Srnordier		movwir(MEM_BTX+0xe*SIZ_SEC,_cx) # Byte
10240269Srnordier		subl %esi,%ecx			#  count
10340269Srnordier		rep				# Relocate
10440269Srnordier		movsb				#  client
10540269Srnordier		subl %edi,%ecx			# Byte count
10640269Srnordier		xorb %al,%al			# Zero
10740269Srnordier		rep				#  assumed
10840269Srnordier		stosb				#  bss
10940269Srnordier		callwi(seta20)			# Enable A20
11040269Srnordier		jmpnwi(start+MEM_JMP-MEM_ORG)	# Start BTX
11140269Srnordier
11240269Srnordier# Enable A20
11340269Srnordier
11440675Srnordierseta20: 	cli				# Disable interrupts
11540675Srnordierseta20.1:	inb $0x64,%al			# Get status
11640269Srnordier		testb $0x2,%al			# Busy?
11740675Srnordier		jnz seta20.1			# Yes
11840269Srnordier		movb $0xd1,%al			# Command: Write
11940269Srnordier		outb %al,$0x64			#  output port
12040675Srnordierseta20.2:	inb $0x64,%al			# Get status
12140269Srnordier		testb $0x2,%al			# Busy?
12240675Srnordier		jnz seta20.2			# Yes
12340269Srnordier		movb $0xdf,%al			# Enable
12440269Srnordier		outb %al,$0x60			#  A20
12540675Srnordier		sti				# Enable interrupts
12640269Srnordier		ret				# To caller
12740269Srnordier
12841008Srnordier# Local read from disk
12940269Srnordier
13041008Srnordiernread:		movwir(MEM_BUF,_bx)		# Transfer buffer
13141008Srnordier		movw1r(0x8,_si_,_ax)		# Get
13241008Srnordier		movw1r(0xa,_si_,_cx)		#  LBA
13340269Srnordier		pushl %cs			# Read from
13448919Srnordier		callwi(xread.1) 		#  disk
13540269Srnordier		jnc return			# If success
13640269Srnordier		movwir(msg_read,_si)		# Message
13740269Srnordier
13840269Srnordier# Error exit
13940269Srnordier
14040269Srnordiererror:		callwi(putstr)			# Display message
14141008Srnordier		movwir(prompt,_si)		# Display
14240269Srnordier		callwi(putstr)			#  prompt
14340269Srnordier		xorb %ah,%ah			# BIOS: Get
14440269Srnordier		int $0x16			#  keypress
14540269Srnordier		int $0x19			# BIOS: Reboot
14640269Srnordier
14740269Srnordier# Display string
14840269Srnordier
14940269Srnordierputstr.0:	movwir(0x7,_bx) 		# Page:attribute
15040269Srnordier		movb $0xe,%ah			# BIOS: Display
15140269Srnordier		int $0x10			#  character
15240269Srnordierputstr: 	lodsb				# Get char
15340269Srnordier		testb %al,%al			# End of string?
15440269Srnordier		jne putstr.0			# No
15540269Srnordier
15641008Srnordierereturn:	movb $0x1,%ah			# Invalid
15741008Srnordier		stc				#  argument
15841008Srnordierreturn: 	ret				# To caller
15940269Srnordier
16040269Srnordier# Read from disk
16140269Srnordier
16248919Srnordierread:		cs_				# LBA support
16348919Srnordier		tstbim(0x80,MEM_REL+flags-start)#  enabled?
16448919Srnordier		jz read.1			# No
16548919Srnordier		movwir(0x55aa,_bx)		# Magic
16640269Srnordier		pushl %edx			# Save
16748919Srnordier		movb $0x41,%ah			# BIOS: Check
16848919Srnordier		int $0x13			#  extensions present
16948919Srnordier		popl %edx			# Restore
17048919Srnordier		jc read.1			# If error
17148919Srnordier		cmpwir(0xaa55,_bx)		# Magic?
17248919Srnordier		jne read.1			# No
17348919Srnordier		testb $0x1,%cl			# Packet interface?
17448919Srnordier		jz read.1			# No
17548919Srnordier		movl %ebp,%esi			# Disk packet
17648919Srnordier		movb $0x42,%ah			# BIOS: Extended
17748919Srnordier		int $0x13			#  read
17848919Srnordier		ret				# To caller
17948919Srnordier
18048919Srnordierread.1: 	pushl %edx			# Save
18140269Srnordier		movb $0x8,%ah			# BIOS: Get drive
18240269Srnordier		int $0x13			#  parameters
18340269Srnordier		movb %dh,%ch			# Max head number
18440269Srnordier		popl %edx			# Restore
18541008Srnordier		jc return			# If error
18640269Srnordier		andb $0x3f,%cl			# Sectors per track
18741008Srnordier		jz ereturn			# If zero
18841008Srnordier		cli				# Disable interrupts
18940269Srnordier		o16				# Get
19041008Srnordier		movw1r(0x8,_bp_,_ax)		#  LBA
19140269Srnordier		pushl %edx			# Save
19240269Srnordier		movzbw %cl,%bx			# Divide by
19340269Srnordier		xorw %dx,%dx			#  sectors
19440269Srnordier		divw %bx,%ax			#  per track
19540269Srnordier		movb %ch,%bl			# Max head number
19640269Srnordier		movb %dl,%ch			# Sector number
19740269Srnordier		incl %ebx			# Divide by
19841008Srnordier		xorb %dl,%dl			#  number
19941008Srnordier		divw %bx,%ax			#  of heads
20040269Srnordier		movb %dl,%bh			# Head number
20140269Srnordier		popl %edx			# Restore
20240269Srnordier		o16				# Cylinder number
20340269Srnordier		cmpl $0x3ff,%eax		#  supportable?
20441008Srnordier		sti				# Enable interrupts
20541008Srnordier		ja ereturn			# No
20640269Srnordier		xchgb %al,%ah			# Set up cylinder
20740269Srnordier		rorb $0x2,%al			#  number
20840269Srnordier		orb %ch,%al			# Merge
20940269Srnordier		incl %eax			#  sector
21040269Srnordier		xchgl %eax,%ecx 		#  number
21140269Srnordier		movb %bh,%dh			# Head number
21240269Srnordier		subb %ah,%al			# Sectors this track
21348919Srnordier		movb1r(0x2,_bp_,_ah)		# Blocks to read
21440269Srnordier		cmpb %ah,%al			# To read
21548919Srnordier		jb read.2			#  this
21640269Srnordier		movb %ah,%al			#  track
21748919Srnordierread.2: 	movwir(0x5,_di) 		# Try count
21848919Srnordierread.3: 	lesw1r(0x4,_bp_,_bx)		# Transfer buffer
21940269Srnordier		pushl %eax			# Save
22041008Srnordier		movb $0x2,%ah			# BIOS: Read
22141008Srnordier		int $0x13			#  from disk
22240269Srnordier		popl %ebx			# Restore
22348919Srnordier		jnc read.4			# If success
22441008Srnordier		decl %edi			# Retry?
22548919Srnordier		jz read.6			# No
22640269Srnordier		xorb %ah,%ah			# BIOS: Reset
22740269Srnordier		int $0x13			#  disk system
22841008Srnordier		xchgl %ebx,%eax 		# Block count
22948919Srnordier		jmp read.3			# Continue
23048919Srnordierread.4: 	movzbl %bl,%eax 		# Sectors read
23141008Srnordier		addwr1(_ax,0x8,_bp_)		# Adjust
23248919Srnordier		jnc read.5			#  LBA,
23341008Srnordier		incw1(0xa,_bp_) 		#  transfer
23448919Srnordierread.5: 	shlb %bl			#  buffer
23541008Srnordier		addbr1(_bl,0x5,_bp_)		#  pointer,
23648919Srnordier		subbr1(_al,0x2,_bp_)		#  block count
23748919Srnordier		ja read.1			# If not done
23848919Srnordierread.6: 	ret				# To caller
23940269Srnordier
24040269Srnordier# Messages
24140269Srnordier
24241008Srnordiermsg_read:	.asciz "Read"
24341008Srnordiermsg_part:	.asciz "Boot"
24440269Srnordier
24541085Srnordierprompt: 	.asciz " error\r\n"
24640940Srnordier
24748919Srnordierflags:		.byte FLAGS			# Flags
24848919Srnordier
24940269Srnordier		.org PRT_OFF,0x90
25040269Srnordier
25140269Srnordier# Partition table
25240269Srnordier
25340269Srnordier		.fill 0x30,0x1,0x0
25440269Srnordierpart4:		.byte 0x80, 0x00, 0x01, 0x00
25540269Srnordier		.byte 0xa5, 0xff, 0xff, 0xff
25640269Srnordier		.byte 0x00, 0x00, 0x00, 0x00
25740269Srnordier		.byte 0x50, 0xc3, 0x00, 0x00
25840269Srnordier
25940269Srnordier		.word 0xaa55			# Magic number
260