Skip to content

Instantly share code, notes, and snippets.

@elazarl
Last active Oct 19, 2015
Embed
What would you like to do?
Boot loader failure
/*
* Copyright (C) 2013 Cloudius Systems, Ltd.
*
* This work is open source software, licensed under the terms of the
* BSD license as described in the LICENSE file in the top-level directory.
*/
OUTPUT_FORMAT(binary)
MEMORY
{
BOOTSECT : ORIGIN = 0, LENGTH = 0x10000
}
SECTIONS
{
.text 0x7c00 : { *(.text) } > BOOTSECT
}
# Copyright (C) 2013 Cloudius Systems, Ltd.
#
# This work is open source software, licensed under the terms of the
# BSD license as described in the LICENSE file in the top-level directory.
.code16
tmp = 0x80000
bootsect = 0x7c00
cmdline = 0x7e00
target = 0x1800000
elf_entry_point_header_offset = 0x18
lzentry = target+elf_entry_point_header_offset
loader = 0x200000 # OSV_KERNEL_BASE
entry = loader+elf_entry_point_header_offset
mb_info = 0x1000
// OSv information lays in the end of this struct, which is 88 bytes in size.
mb_tsc1_lo = (mb_info + 88)
mb_tsc1_hi = (mb_info + 88 + 4)
mb_tsc_disk_lo = (mb_info + 88 + 8)
mb_tsc_disk_hi = (mb_info + 88 + 12)
mb_cmdline = (mb_info + 16)
mb_mmap_len = (mb_info + 44)
mb_mmap_addr = (mb_info + 48)
e820data = 0x2000
.text
start:
ljmp $0, $init
# Be conservative, we should not be in the 10th byte so far, but better safe than sorry
.org 0x10
# count32 will be overwritten by imgedit.py setsize <int>,
# to specify the exact loader size after it is compiled
count32: .short 4096 # in 32k units, 4096=128MB
int1342_struct:
.byte 0x10
.byte 0
.short 0x40 # 32k
.short 0
.short tmp / 16
lba:
.quad 128
int1342_boot_struct: # for command line
.byte 0x10
.byte 0
.short 0x3f # 31.5k
.short cmdline
.short 0
.quad 1
xfer: .long target
gdt:
.short gdt_size - 1
.short gdt
.long 0
.quad 0x00cf9b000000ffff # 32-bit code segment
.quad 0x00cf93000000ffff # 32-bit data segment
.quad 0x00009b000000ffff # 16-bit code segment
.quad 0x000093000000ffff # 16-bit data segment
gdt_size = . - gdt
init:
rdtsc
mov %eax, mb_tsc1_lo
mov %edx, mb_tsc1_hi
xor %ax, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %ss
mov $0x7c00, %sp
mov $0x2401, %ax # enable a20 gate
int $0x15
lea int1342_boot_struct, %si
mov $0x42, %ah
mov $0x80, %dl
int $0x13
movl $cmdline, mb_cmdline
read_disk:
lea int1342_struct, %si
mov $0x42, %ah
mov $0x80, %dl
int $0x13
jc done_disk # in case of errors, we don't really know what to do.
cli
lgdtw gdt
mov $0x11, %ax
lmsw %ax
ljmp $8, $1f
1:
.code32
mov $0x10, %ax
mov %eax, %ds
mov %eax, %es
mov $tmp, %esi
mov xfer, %edi
mov $0x8000, %ecx
rep movsb
mov %edi, xfer
mov $0x20, %al
mov %eax, %ds
mov %eax, %es
ljmpw $0x18, $1f
1:
.code16
mov $0x10, %eax
mov %eax, %cr0
ljmpw $0, $1f
1:
xor %ax, %ax
mov %ax, %ds
mov %ax, %es
sti
addl $(0x8000 / 0x200), lba
decw count32
jnz read_disk
done_disk:
rdtsc
mov %eax, mb_tsc_disk_lo
mov %edx, mb_tsc_disk_hi
mov $e820data, %edi
mov %edi, mb_mmap_addr
xor %ebx, %ebx
more_e820:
mov $100, %ecx
mov $0x534d4150, %edx
mov $0xe820, %ax
add $4, %edi
int $0x15
jc done_e820
mov %ecx, -4(%edi)
add %ecx, %edi
test %ebx, %ebx
jnz more_e820
done_e820:
sub $e820data, %edi
mov %edi, mb_mmap_len
cli
mov $0x11, %ax
lmsw %ax
ljmp $8, $1f
1:
.code32
mov $0x10, %ax
mov %eax, %ds
mov %eax, %es
mov %eax, %gs
mov %eax, %fs
mov %eax, %ss
call *lzentry
mov $loader, %eax
mov $mb_info, %ebx
call *entry
.org 0x1b8
.byte 0x56, 0x53, 0x4F, 0, 0, 0
.org 0x1be
.space 16, 0
.org 0x1ce
.space 16, 0
.org 0x1de
.space 16, 0
.org 0x1ee
.space 16, 0
.org 0x1fe
.byte 0x55, 0xaa
#!/bin/bash
set -e
rm -rf out
[ -f .pid ] && (kill `cat .pid`; rm .pid)
make
qemu-system-x86_64 -snapshot -hda out/loader.img -serial file:/dev/stdout -pidfile .pid -s -S &
echo 'set arch i8086
target remote localhost:1234
hbr boot16.S:89
commands
x/h count32
c
end
hbr boot16.S:90
commands 2
i r eflags
end' >out/gdb.script
gdb out/boot16.elf -quiet -x out/gdb.script
This is a demonstration of how INT 13, ah=42 fails after a while.
Run 'bash debug.sh`, then hit `c` a couple of times, you should
see that INT 13 returns with CF set, which means it had an error.
Why is it happening? The code is pretty simple, all it does is reading
a sector from the disk, and copying it to some place in the memory.
quiet = $(if $V, $1, @echo " $2"; $1)
very-quiet = $(if $V, $1, @$1)
OUT=out
.PHONY: all
block=$(shell expr 512 \* 64)
image-size=$(shell expr 4 \* $(block) - 513 )
all: $(OUT)/loader.img $(OUT)/boot16.elf
$(OUT)/boot16.elf: boot16.ld $(OUT)/boot16.o
$(call quiet, $(LD) $(OUT)/boot16.o boot16.ld -o $@, LD $@)
$(OUT)/boot16.bin: boot16.ld $(OUT)/boot16.o
$(call quiet, $(LD) -o $@ -T $^, LD $@)
$(OUT)/lzloader.elf:
$(call quiet, tr '\0' '\377' < /dev/zero | dd count=$(image-size) bs=1 of=$@)
$(OUT)/loader.img: $(OUT)/boot16.bin $(OUT)/lzloader.elf
$(call quiet, dd if=$(OUT)/boot16.bin of=$@ > /dev/null 2>&1, DD $@ boot16.bin)
$(call quiet, cat $(OUT)/lzloader.elf /dev/zero|dd count=`python -c 'print max(192, ($(image-size)-1)/512+1)'` of=$@ conv=notrunc seek=128 > /dev/null 2>&1, \
DD $@ lzloader.elf)
$(call quiet, python setsize.py $@ $(OUT)/lzloader.elf, DD $@ boot16.bin)
makedir = $(call very-quiet, mkdir -p $(dir $@))
build-s = $(CXX) $(CXXFLAGS) $(ASFLAGS) -g -c -o $@ $<
q-build-s = $(call quiet, $(build-s), AS $@)
$(OUT)/%.o: %.S
$(makedir)
$(q-build-s)
#!/usr/bin/python
import io
import os
import sys
if __name__ == '__main__':
img = sys.argv[1]
elf = sys.argv[2]
block_size = 32*1024
elf_size_in_bytes = os.stat(elf).st_size
img_size = os.stat(img).st_size
# round up
elf_size_in_blocks = (elf_size_in_bytes-1)//block_size+1
elf_data = bytearray(img_size)
with io.FileIO(img, 'r') as fp:
n = fp.readinto(elf_data)
elf_data = elf_data[:n]
elf_data[0x11] = (elf_size_in_blocks & 0xff00) >> 8
elf_data[0x10] = elf_size_in_blocks & 0xff
with open(img, 'w') as fp:
fp.write(elf_data)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment