188 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| # Copyright (C) 2015 The University of Notre Dame
 | |
| # This software is distributed under the GNU General Public License.
 | |
| # See the file LICENSE for details.
 | |
| 
 | |
| # This is the raw bootblock code, a 512-byte chunk of assembly
 | |
| # found on the first sector of the boot disk.  The BIOS is responsible
 | |
| # for starting the machine, loading this sector into memory,
 | |
| # and then transferring control here.  The bootblock must call
 | |
| # to the BIOS to load the remaining sectors containing the
 | |
| # kernel code, and then jump there.
 | |
| 
 | |
| # Constants describing our basic memory layout are in this
 | |
| # header file, which is shared between C and assembly modules:
 | |
| 	
 | |
| #include "memorylayout.h"
 | |
| 	
 | |
| # When we receive control from the BIOS, the following are set:
 | |
| # %dl - the device number this block was loaded from
 | |
| # %es:%si - the partition table entry we were loaded from
 | |
| 
 | |
| # To set the code segment appropriately, the first thing we
 | |
| # do is a long jump to _start2, which sets cs=BOOTBLOCK_SEGMENT
 | |
| 	
 | |
| .code16
 | |
| .text
 | |
| .global _start
 | |
| _start:
 | |
| 	ljmp	$BOOTBLOCK_SEGMENT,$_start2
 | |
| 
 | |
| # Now we begin setting up the execution environment
 | |
| # for loading the rest of the kernel.
 | |
| 
 | |
| _start2:	
 | |
| 	sti				# disable interrupts
 | |
| 	cld				# clear the direction flag
 | |
| 	mov	%cs, %ax		# set all segments to code
 | |
| 	mov	%ax, %ds
 | |
| 	mov	%ax, %es
 | |
| 	mov	$INTERRUPT_STACK_SEGMENT, %ax     # set up the stack
 | |
| 	mov	%ax, %ss
 | |
| 	mov	$INTERRUPT_STACK_OFFSET, %sp
 | |
| 
 | |
| 	mov	%dl, (disk_number)	# save the disk number
 | |
| 	mov	partition_status,%di	# set the partition table as dest
 | |
| 	mov	$12, %cx		# copy 12 bytes from si to di
 | |
| 	rep	movsb
 | |
| 		
 | |
| 	mov	$(loadmsg),%si		# print initial message
 | |
|         call	bios_putstring
 | |
| 
 | |
| 	mov	$0,%ah			# reset the disk system
 | |
| 	int	$0x13
 | |
| 
 | |
| 	mov	$0x08, %ah		# get the drive geometry
 | |
| 	int	$0x13
 | |
| 	and	$0x3f, %cl		# mask off high tracks
 | |
| 	mov	%cl, (disk_sectors)
 | |
| 	mov	%ch, (disk_cylinders)
 | |
| 	mov	%dh, (disk_heads)
 | |
| 	
 | |
| 	mov	$KERNEL_SEGMENT,%ax	# load happens at es:bx
 | |
| 	mov	%ax, %es		# which we set to
 | |
| 	mov	$KERNEL_OFFSET,%bx	# KERNEL_SEGMENT:KERNEL_OFFSET
 | |
| 
 | |
| 					# disk parameters:
 | |
| 	mov	(disk_number), %dl	#	device
 | |
| 	mov	$0,%ch			#	cylinder 0
 | |
| 	mov	$0,%dh			#	head 0
 | |
| 	mov	$2,%cl			#	sector 2
 | |
| 
 | |
| loadsector:
 | |
| 	mov	$1,%al			# load 1 sector
 | |
| 	mov	$0x02, %ah		# load command
 | |
| 	int	$0x13			# execute load
 | |
| 	
 | |
| 	mov	$'.', %al		# display a dot
 | |
| 	call	bios_putchar		# for each sector loaded
 | |
| 	
 | |
| 	mov	(sectors_left),%ax	# how many sectors left?
 | |
| 	cmp	$0xffff, %ax		# has it been initialized?
 | |
| 	jne	gotsectors		# yes - use the value
 | |
| 	mov	%es:(KERNEL_SIZE_OFFSET),%eax	# no - get size of kernel
 | |
| 	shr	$9, %eax		# convert into blocks
 | |
| 	inc	%eax			# add one for good measure
 | |
| 	
 | |
| gotsectors:		
 | |
| 	dec	%ax			# remove one block
 | |
| 	mov	%ax,(sectors_left)	# store the value
 | |
| 	cmp	$0, %ax			# are we done?
 | |
| 	je	loaddone		# yes - jump to bottom
 | |
| 			
 | |
| checksegment:
 | |
| 	add	$512,%bx		# move data pointer by 512 bytes
 | |
| 	cmp	$0, %bx			# did we reach segment end?
 | |
| 	jnz	nextsector		# no - find next sector
 | |
| 	mov	%es, %ax		# yes - retrieve seg register
 | |
| 	add	$0x1000, %ax		# move to next 64k block
 | |
| 	mov	%ax, %es		# store segment register
 | |
| 
 | |
| nextsector:
 | |
| 	inc	%cl			# advance by one sector
 | |
| 	mov	(disk_sectors),%al	# what is the maximum sector?
 | |
| 	cmp	%al, %cl		# is this the last sector?
 | |
| 	jle	loadsector		# no - load the next sector
 | |
| 	mov	$1,%cl			# yes - go to sector zero..
 | |
| 
 | |
| 	inc	%dh			# advance to next head
 | |
| 	mov	(disk_heads), %al	# what is the maximum head?
 | |
| 	cmp	%al, %dh		# is this the last head?
 | |
| 	jle	loadsector		# no - read the next sector
 | |
| 	mov	$0,%dh			# yes - go to head zero
 | |
| 
 | |
| 	inc	%ch			# advance to next cylinder
 | |
| 	mov	(disk_cylinders), %al	# what is the maximum cylinder?
 | |
| 	cmp	%al, %ch		# is this the last cylinder?
 | |
| 	jle	loadsector		# no - read the next sector
 | |
| 					# yes - fall through here
 | |
| loaddone:
 | |
| 	mov	$0,%ah			# reset the disk system
 | |
| 	int	$0x13
 | |
| 	
 | |
| 	mov	$(bootmsg),%si		# print boot message
 | |
|         call	bios_putstring
 | |
| 	
 | |
| 	mov	$KERNEL_SEGMENT, %ax    # jump to the kernel code
 | |
| 	mov	%ax, %ds
 | |
| 	ljmp	$KERNEL_SEGMENT, $KERNEL_OFFSET
 | |
| 	
 | |
| bios_putstring:				# routine to print an entire string
 | |
| 	mov	(%si), %al
 | |
| 	cmp	$0, %al
 | |
| 	jz	bios_putstring_done
 | |
|         call	bios_putchar
 | |
| 	inc	%si
 | |
| 	jmp	bios_putstring
 | |
| bios_putstring_done:
 | |
|         ret
 | |
| 
 | |
| bios_putchar:				# routine to print a single char
 | |
| 	push	%ax
 | |
| 	push	%bx
 | |
|         mov	$14,%ah
 | |
|         mov	$1,%bl
 | |
|         int	$0x10
 | |
| 	pop	%bx
 | |
| 	pop	%ax
 | |
| 	ret
 | |
| 
 | |
| loadmsg:
 | |
|         .asciz "bootblock: loading kernel...\r\n"
 | |
| bootmsg:
 | |
| 	.asciz "\r\nbootblock: booting kernel...\r\n"
 | |
| 
 | |
| disk_number:
 | |
| 	.byte 0
 | |
| disk_cylinders:
 | |
| 	.byte 0
 | |
| disk_heads:
 | |
| 	.byte 0
 | |
| disk_sectors:
 | |
| 	.byte 0
 | |
| sectors_left:	
 | |
| 	.word 0xffff
 | |
| 
 | |
| partition_status:
 | |
| 	.byte 0
 | |
| partition_start_chs:	
 | |
| 	.byte 0
 | |
| 	.byte 0
 | |
| 	.byte 0
 | |
| partition_type:	
 | |
| 	.byte 0
 | |
| partition_stop_chs:	
 | |
| 	.byte 0
 | |
| 	.byte 0
 | |
| 	.byte 0
 | |
| partition_start_lba:
 | |
| 	.long 0
 | |
| partition_length:
 | |
| 	.long 0
 | |
| 				
 | |
| # A bootblock must have 0xaa55 in its two final bytes.
 | |
| # The .org directive forces this data to that point.
 | |
| 
 | |
| .org 510
 | |
| bootflag:
 | |
| 	.word 0xaa55
 |