#include threads/loader.h
#### Kernel loader.
#### This code should be stored in the first sector of a hard disk.
#### When the BIOS runs, it loads this code at physical address
#### 0x7c00-0x7e00 (512 bytes) and jumps to the beginning of it,
#### in real mode.The loader loads the kernel into memory and jumps
#### to its entry point, which is the start function in start.S.
####
#### The BIOS passes in the drive that the loader was read from as
#### DL, with floppy drives numbered 0x00, 0x01, and hard drives
#### numbered 0x80, 0x81, We want to support booting a kernel on
#### a different drive from the loader, so we dont take advantage of
#### this.
# Runs in real mode, which is a 16-bit segment.
.code16
# Set up segment registers.
# Set stack to grow downward from 60 kB (after boot, the kernel
# continues to use this stack for its initial thread).
sub %ax, %ax
mov %ax, %ds
mov %ax, %ss
mov $0xf000, %esp
# Configure serial port so we can report progress without connected VGA.
# See [IntrList] for details.
sub %dx, %dx# Serial port 0.
mov $0xe3, %al# 9600 bps, N-8-1.
# AH is already 0 (Initialize Port).
int $0x14# Destroys AX.
call puts
.string PiLo
#### Read the partition table on each system hard disk and scan for a
#### partition of type 0x20, which is the type that we use for a
#### Pintos kernel.
####
#### Read [Partitions] for a description of the partition table format
#### that we parse.
####
#### We print out status messages to show the disk and partition being
#### scanned, e.g. hda1234 as we scan four partitions on the first
#### hard disk.
mov $0x80, %dl# Hard disk 0.
read_mbr:
sub %ebx, %ebx# Sector 0.
mov $0x2000, %ax# Use 0x20000 for buffer.
mov %ax, %es
call read_sector
jc no_such_drive
# Print hd[a-z].
call puts
.string hd
mov %dl, %al
add $a 0x80, %al
call putc
# Check for MBR signatureif not present, its not a
# partitioned hard disk.
cmpw $0xaa55, %es:510
jne next_drive
mov $446, %si# Offset of partition table entry 1.
mov $1, %al
check_partition:
# Is it an unused partition?
cmpl $0, %es:(%si)
je next_partition
# Print [1-4].
call putc
# Is it a Pintos kernel partition?
cmpb $0x20, %es:4(%si)
jne next_partition
# Is it a bootable partition?
cmpb $0x80, %es:(%si)
je load_kernel
next_partition:
# No match for this partition, go on to the next one.
add $16, %si# Offset to next partition table entry.
inc %al
cmp $510, %si
jb check_partition
next_drive:
# No match on this drive, go on to the next one.
inc %dl
jnc read_mbr
no_such_drive:
no_boot_partition:
# Didnt find a Pintos kernel partition anywhere, give up.
call puts
.string rNot foundr
# Notify BIOS that boot failed.See [IntrList].
int $0x18
#### We found a kernel.The kernels drive is in DL.The partition
#### table entry for the kernels partition is at ES:SI.Our job now
#### is to read the kernel from disk and jump to its start address.
load_kernel:
call puts
.string rLoading
# Figure out number of sectors to read.A Pintos kernel is
# just an ELF format object, which doesnt have an
# easy-to-read field to identify its own size (see [ELF1]).
# But we limit Pintos kernels to 512 kB for other reasons, so
# its easy enough to just read the entire contents of the
# partition or 512 kB from disk, whichever is smaller.
mov %es:12(%si), %ecx# EBP = number of sectors
cmp $1024, %ecx# Cap size at 512 kB
jbe 1f
mov $1024, %cx
1:
mov %es:8(%si), %ebx# EBX = first sector
mov $0x2000, %ax# Start load address: 0x20000
next_sector:
# Read one sector into memory.
mov %ax, %es# ES:0000 -> load address
call read_sector
jc read_failed
# Print . as progress indicator once every 16 sectors == 8 kB.
test $15, %bl
jnz 1f
call puts
.string .
1:
# Advance memory pointer and disk sector.
add $0x20, %ax
inc %bx
loop next_sector
call puts
.string r
#### Transfer control to the kernel that we loaded.We read the start
#### address out of the ELF header (see [ELF1]) and convert it from a
#### 32-bit linear address into a 16:16 segment:offset address for
#### real mode, then jump to the converted address.The 8086 doesnt
#### have an instruction to jump to an absolute segment:offset kept in
#### registers, so in fact we store the address in a temporary memory
#### location, then jump indirectly through that location.To save 4
#### bytes in the loader, we reuse 4 bytes of the loaders code for
#### this temporary pointer.
mov $0x2000, %ax
mov %ax, %es
mov %es:0x18, %dx
mov %dx, start
movw $0x2000, start + 2
ljmp *start
read_failed:
start:
# Disk sector read failed.
call puts
1:.string rBad readr
# Notify BIOS that boot failed.See [IntrList].
int $0x18
#### Print string subroutine.To save space in the loader, this
#### subroutine takes its null-terminated string argument from the
#### code stream just after the call, and then returns to the byte
#### just after the terminating null.This subroutine preserves all
#### general-purpose registers.
puts:xchg %si, %ss:(%esp)
push %ax
next_char:
mov %cs:(%si), %al
inc %si
test %al, %al
jz 1f
call putc
jmp next_char
1:pop %ax
xchg %si, %ss:(%esp)
ret
#### Character output subroutine.Prints the character in AL to the
#### VGA display and serial port 0, using BIOS services (see
#### [IntrList]).Preserves all general-purpose registers.
####
#### If called upon to output a carriage return, this subroutine
#### automatically supplies the following line feed.
putc:pusha
1:sub %bh, %bh# Page 0.
mov $0x0e, %ah# Teletype output service.
int $0x10
mov $0x01, %ah# Serial port output service.
sub %dx, %dx# Serial port 0.
2:int $0x14# Destroys AH.
test $0x80, %ah# Output timed out?
jz 3f
movw $0x9090, 2b# Turn int $0x14 above into NOPs.
3:
cmp $r, %al
jne popa_ret
mov $
, %al
jmp 1b
#### Sector read subroutine.Takes a drive number in DL (0x80 = hard
#### disk 0, 0x81 = hard disk 1, ) and a sector number in EBX, and
#### reads the specified sector into memory at ES:0000.Returns with
#### carry set on error, clear otherwise.Preserves all
#### general-purpose registers.
read_sector:
pusha
sub %ax, %ax
push %ax# LBA sector number [48:63]
push %ax# LBA sector number [32:47]
push %ebx# LBA sector number [0:31]
push %es# Buffer segment
push %ax# Buffer offset (always 0)
push $1# Number of sectors to read
push $16# Packet size
mov $0x42, %ah# Extended read
mov %sp, %si# DS:SI -> packet
int $0x13# Error code in CF
popa# Pop 16 bytes, preserve flags
popa_ret:
popa
ret# Error code still in CF
#### Command-line arguments and their count.
#### This is written by the `pintos utility and read by the kernel.
#### The loader itself does not do anything with the command line.
.org LOADER_ARG_CNT LOADER_BASE
.fill LOADER_ARG_CNT_LEN, 1, 0
.org LOADER_ARGS LOADER_BASE
.fill LOADER_ARGS_LEN, 1, 0
#### Partition table.
.org LOADER_PARTS LOADER_BASE
.fill LOADER_PARTS_LEN, 1, 0
#### Boot-sector signature for BIOS inspection.
.org LOADER_SIG LOADER_BASE
.word 0xaa55
Reviews
There are no reviews yet.