blob: ab8582b76a9259c9c0099f9e61cd67006deaf4b4 [file] [log] [blame]
/* -----------------------------------------------------------------------
*
* Copyright 2010-2011 Gene Cumm
*
* Portions from mbr.S:
* Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
* Copyright 2009 Intel Corporation; author: H. Peter Anvin
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall
* be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* ----------------------------------------------------------------------- */
/*
* handoff.S: MBR/VBR-like codeblock to display handoff data
*
* Displays the values of DL, DS, SI, the contents of [DS:SI] (16 bytes),
* the values of ES, DI, the contents of [ES:DI] (4 bytes), scans memory for
* $PnP then reports a boot failure.
*
* This should (hopefully) be only 8086 code
*/
/*
* Install instructions (assuming your target is /dev/dev; file or block device):
*
* MBR:
* dd conv=notrunc bs=440 count=1 if=handoff.bin of=/dev/dev
*
* VBR/PBR (should work for FAT12/16/32, ext[234]fs, btrfs):
* echo -en "\0353\0130\0220" |dd conv=notrunc bs=1 count=3 of=/dev/dev
* dd conv=notrunc bs=2 count=210 seek=45 if=handoff.bin of=/dev/dev
*/
// #define DEBUG_MARKER1 /* Insert markers in binary */
// #define DEBUG_START /* Print entry addresses at start */
// #define DEBUG_LOADE /* movw versus pop */
#define DEBUG_PNP /* Scan for $PnP and show address */
#define DEBUG_PAK /* Press Any Key before boot fail */
// #define DEBUG_ENTRY_REG /* Store (manually as pusha is 80186) registers */
// #define DEBUG_FDT /* Print the floppy descriptor table; INT 1Eh*/
#ifdef DEBUG_MARKER1
.macro ASCII_MARKER1 s:vararg
.ascii \s
.endm
#else /* DEBUG_MARKER1 */
.macro ASCII_MARKER1 s:vararg
.endm
#endif /* DEBUG_MARKER1 */
#ifdef DEBUG_LOADE
.macro LOADE r:req, t:req
movw (es_\r), %\t
.endm
#else /* DEBUG_LOADE */
.macro LOADE r:req, t:req
popw %\t
.endm
#endif /* DEBUG_LOADE */
.code16
.text
entry = 0x7c00
stack = (entry)
e_start = (stack)
e_ax = (e_start-2)
e_ss = (e_ax-2)
e_sp = (e_ss-2)
e_bot = (e_ss)
/* Doubtful this will be used */
e0_beg = (e_bot)
e0_ax = (e0_beg-2)
e0_cx = (e0_ax-2)
e0_dx = (e0_cx-2)
e0_bx = (e0_dx-2)
e0_sp = (e0_bx-2)
e0_bp = (e0_sp-2)
e0_si = (e0_bp-2)
e0_di = (e0_si-2)
e0_ds = (e0_di-2)
e0_es = (e0_ds-2)
e0_bot = (e0_es)
es_beg = (e0_bot) /* Original register values from entry point */
es_di = (es_beg-2)
es_es = (es_di-2)
es_si = (es_es-2)
es_ds = (es_si-2)
es_bot = (es_ds)
BIOS_page = 0x462
int_1e = (4*0x1e)
int_1e_seg = (int_1e)
int_1e_off = (int_1e+2)
.globl _start
_start:
cli
#ifdef DEBUG_ENTRY_REG
movw %ax, e_ax
movw %ss, e_ss
movw %sp, e_sp
#endif /* DEBUG_ENTRY_REG */
xorw %ax, %ax
movw %ax, %ss
#ifdef DEBUG_ENTRY_REG
movw $e0_beg, %sp
/* pushaw */ /* 80186 */
pushw %ax
pushw %cx
pushw %dx
pushw %bx
pushw %sp
pushw %bp
pushw %si
pushw %di
pushw %ds
pushw %es
#else /* DEBUG_ENTRY_REG */
movw $es_beg, %sp
#endif /* DEBUG_ENTRY_REG */
pushw %di /* es:di -> $PnP header */
pushw %es
pushw %si
pushw %ds
sti
cld
pushw %cs
popw %ds
#ifdef DEBUG_START
pushw %dx
call crlf
movw $(_start),%dx /* 0x0600 mbr.ld .text address */
call wrhexw
call crlf
call caddr
caddr:
popw %dx
subw $(caddr - _start), %dx
call wrhexw
call crlf
popw %dx
#endif /* DEBUG_START */
/* write DL */
pr_dl: call wrstr
.ascii "DL: \0"
call wrhexb
/* DS */
pr_ds: call wrstr
.ascii " DS: \0"
LOADE ds, dx
pushw %dx
popw %es
call wrhexw
/* SI */
pr_si: call wrstr
.ascii " SI: \0"
LOADE si, dx
pushw %dx
popw %di
call wrhexw
call crlf
/* DS:SI */
movw $16, %cx
call wrhexbses
call crlf
/* ES */
pr_es: call wrstr
.ascii "ES: \0"
LOADE es, dx
pushw %dx
popw %es
call wrhexw
pr_di: call wrstr
.ascii " DI: \0"
LOADE di, dx
pushw %dx
popw %di
call wrhexw
call crlf
/* ES:DI */ /* %es:0(%di) */
movw $4, %cx
call wrhexbses
#ifdef DEBUG_PNP
subw $4, %si
es lodsw
cmpw $0x5024, %ax
jne scn_pnp
es lodsw
cmpw $0x506E, %ax
jne scn_pnp
call wrstr
.ascii " =$PnP\0"
scn_pnp:
call crlf
/* $PnP Scan */
movw $0xf000, %dx
pushw %dx
popw %es
movw $0, %si
movw $0x1000, %cx
/* 0x506E5024 */
movw $0x5024, %dx
movw $0x506E, %bx
ch_pnp: es lodsw /* Check for $PnP */
cmpw %dx, %ax
jne ch_pnp_l
es lodsw
cmpw %bx, %ax
je pr_pnp
ch_pnp_l: /* Check $PnP failed; loop to next address */
addw $14, %si
andw $0xFFF0, %si
loopw ch_pnp
jmp pnp_end
pr_pnp:
pushw %si
call wrstr
.ascii "$PnP-\0"
movw %es, %dx
call wrhexw
movb $':, %al
call wrchr
popw %dx
andw $0xFFF0, %dx
call wrhexw
#endif /* DEBUG_PNP */
call crlf
pnp_end:
#ifdef DEBUG_FDT
/* INT 1Eh: Floppy Parameter Table Pointer */
pr_1e: call wrstr
.ascii "INT 1Eh: \0"
mov $int_1e,%bx
les (%bx),%di
pushw %es
popw %dx
call wrhexw
movb $':, %al
call wrchr
pushw %di
popw %dx
call wrhexw
call crlf
/* [INT 1Eh] */
movw $14, %cx
call wrhexbses
call crlf
#endif /* DEBUG_FDT */
end:
jmp bootfail
ASCII_MARKER1 "wc"
wrchr:
movb $0x0e, %ah
movb (BIOS_page), %bh
movb $0x07, %bl
int $0x10 /* May destroy %bp */
ret
ASCII_MARKER1 "ws"
wrstr:
pop %si
wrstr_l:
lodsb
cmpb $0, %al
je wrstr_d
call wrchr
jmp wrstr_l
wrstr_d:
push %si
ret
crlf:
call wrstr
.ascii "\r\n\0"
ret
ASCII_MARKER1 "hx"
wrhexn:
and $0x0F, %al
cmpb $10, %al
jae .alph
addb $'0, %al
jmp .wc
.alph:
addb $('A - 10), %al
.wc:
call wrchr
ret
wrhexb:
pushw %cx
movb %dl, %al
pushw %ax
movb $4, %cl
rorw %cl, %ax
call wrhexn
popw %ax
call wrhexn
popw %cx
ret
wrhexw:
pushw %cx
movb $8, %cl
rorw %cl, %dx
call wrhexb
rorw %cl, %dx
call wrhexb
popw %cx
ret
ASCII_MARKER1 "HE"
wrhexbses:
pushw %di
popw %si
wrhexbses_l:
movb $' , %al
call wrchr
es lodsb
movw %ax, %dx
call wrhexb
loop wrhexbses_l
ret
data:
ASCII_MARKER1 "bf"
bootfail:
#ifdef DEBUG_PAK
call wrstr
.ascii "\r\n\r\nPress any key\r\n\0"
xor %ax, %ax
int $0x16
#endif
int $0x18 /* Boot failure */
die:
hlt
jmp die