Mon 14 Oct 23:06:38 CEST 2024
This commit is contained in:
parent
45aa067b85
commit
eb18aae083
187
kernel/bootblock.S
Normal file
187
kernel/bootblock.S
Normal file
|
@ -0,0 +1,187 @@
|
|||
# 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
|
Loading…
Reference in New Issue
Block a user