basekernel/kernel/bootblock.S

188 lines
4.7 KiB
ArmAsm
Raw Permalink Normal View History

2024-10-14 23:07:29 +02:00
# 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