Home | History | Annotate | Download | only in mbr
      1 /* -----------------------------------------------------------------------
      2  *
      3  *   Copyright 2010-2011 Gene Cumm
      4  *
      5  *   Portions from mbr.S:
      6  *   Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
      7  *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
      8  *
      9  *   Permission is hereby granted, free of charge, to any person
     10  *   obtaining a copy of this software and associated documentation
     11  *   files (the "Software"), to deal in the Software without
     12  *   restriction, including without limitation the rights to use,
     13  *   copy, modify, merge, publish, distribute, sublicense, and/or
     14  *   sell copies of the Software, and to permit persons to whom
     15  *   the Software is furnished to do so, subject to the following
     16  *   conditions:
     17  *
     18  *   The above copyright notice and this permission notice shall
     19  *   be included in all copies or substantial portions of the Software.
     20  *
     21  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     22  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
     23  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     24  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     25  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     26  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     27  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     28  *   OTHER DEALINGS IN THE SOFTWARE.
     29  *
     30  * ----------------------------------------------------------------------- */
     31 
     32 /*
     33  * handoff.S: MBR/VBR-like codeblock to display handoff data
     34  *
     35  * Displays the values of DL, DS, SI, the contents of [DS:SI] (16 bytes),
     36  * the values of ES, DI, the contents of [ES:DI] (4 bytes), scans memory for
     37  * $PnP then reports a boot failure.
     38  *
     39  * This should (hopefully) be only 8086 code
     40  */
     41 
     42 /*
     43  * Install instructions (assuming your target is /dev/dev; file or block device):
     44  *
     45  * MBR:
     46  * dd conv=notrunc bs=440 count=1 if=handoff.bin of=/dev/dev
     47  *
     48  * VBR/PBR (should work for FAT12/16/32, ext[234]fs, btrfs):
     49  * echo -en "\0353\0130\0220" |dd conv=notrunc bs=1 count=3 of=/dev/dev
     50  * dd conv=notrunc bs=2 count=210 seek=45 if=handoff.bin of=/dev/dev
     51  */
     52 
     53 // #define DEBUG_MARKER1	/* Insert markers in binary */
     54 // #define DEBUG_START	/* Print entry addresses at start */
     55 // #define DEBUG_LOADE	/* movw versus pop */
     56 #define DEBUG_PNP	/* Scan for $PnP and show address */
     57 #define DEBUG_PAK	/* Press Any Key before boot fail */
     58 // #define DEBUG_ENTRY_REG	/* Store (manually as pusha is 80186) registers */
     59 // #define DEBUG_FDT	/* Print the floppy descriptor table; INT 1Eh*/
     60 
     61 #ifdef DEBUG_MARKER1
     62 	.macro ASCII_MARKER1 s:vararg
     63 	.ascii	\s
     64 	.endm
     65 #else	/* DEBUG_MARKER1 */
     66 	.macro ASCII_MARKER1 s:vararg
     67 	.endm
     68 #endif	/* DEBUG_MARKER1 */
     69 
     70 #ifdef DEBUG_LOADE
     71 	.macro LOADE r:req, t:req
     72 	movw	(es_\r), %\t
     73 	.endm
     74 #else	/* DEBUG_LOADE */
     75 	.macro LOADE r:req, t:req
     76 	popw %\t
     77 	.endm
     78 #endif	/* DEBUG_LOADE */
     79 
     80 	.code16
     81 	.text
     82 
     83 entry		= 0x7c00
     84 stack		= (entry)
     85 e_start		= (stack)
     86 e_ax		= (e_start-2)
     87 e_ss		= (e_ax-2)
     88 e_sp		= (e_ss-2)
     89 e_bot		= (e_ss)
     90 /* Doubtful this will be used */
     91 e0_beg		= (e_bot)
     92 e0_ax		= (e0_beg-2)
     93 e0_cx		= (e0_ax-2)
     94 e0_dx		= (e0_cx-2)
     95 e0_bx		= (e0_dx-2)
     96 e0_sp		= (e0_bx-2)
     97 e0_bp		= (e0_sp-2)
     98 e0_si		= (e0_bp-2)
     99 e0_di		= (e0_si-2)
    100 e0_ds		= (e0_di-2)
    101 e0_es		= (e0_ds-2)
    102 e0_bot		= (e0_es)
    103 es_beg		= (e0_bot)	/* Original register values from entry point */
    104 es_di		= (es_beg-2)
    105 es_es		= (es_di-2)
    106 es_si		= (es_es-2)
    107 es_ds		= (es_si-2)
    108 es_bot		= (es_ds)
    109 
    110 BIOS_page	= 0x462
    111 
    112 int_1e		= (4*0x1e)
    113 int_1e_seg	= (int_1e)
    114 int_1e_off	= (int_1e+2)
    115 
    116 	.globl	_start
    117 _start:
    118 	cli
    119 #ifdef DEBUG_ENTRY_REG
    120 	movw	%ax, e_ax
    121 	movw	%ss, e_ss
    122 	movw	%sp, e_sp
    123 #endif /* DEBUG_ENTRY_REG */
    124 	xorw	%ax, %ax
    125 	movw	%ax, %ss
    126 #ifdef DEBUG_ENTRY_REG
    127 	movw	$e0_beg, %sp
    128 	/* pushaw */		/* 80186 */
    129 	pushw	%ax
    130 	pushw	%cx
    131 	pushw	%dx
    132 	pushw	%bx
    133 	pushw	%sp
    134 	pushw	%bp
    135 	pushw	%si
    136 	pushw	%di
    137 	pushw	%ds
    138 	pushw	%es
    139 #else /* DEBUG_ENTRY_REG */
    140 	movw	$es_beg, %sp
    141 #endif /* DEBUG_ENTRY_REG */
    142 	pushw	%di		/* es:di -> $PnP header */
    143 	pushw	%es
    144 	pushw	%si
    145 	pushw	%ds
    146 	sti
    147 	cld
    148 	pushw	%cs
    149 	popw	%ds
    150 
    151 #ifdef DEBUG_START
    152 	pushw	%dx
    153 	call	crlf
    154 	movw	$(_start),%dx	/* 0x0600 mbr.ld .text address */
    155 	call	wrhexw
    156 	call	crlf
    157 	call	caddr
    158 caddr:
    159 	popw	%dx
    160 	subw	$(caddr - _start), %dx
    161 	call	wrhexw
    162 	call	crlf
    163 	popw	%dx
    164 #endif	/* DEBUG_START */
    165 
    166 	/* write DL */
    167 pr_dl:	call	wrstr
    168 	.ascii	"DL: \0"
    169 	call	wrhexb
    170 	/* DS */
    171 pr_ds:	call	wrstr
    172 	.ascii	"  DS: \0"
    173 	LOADE	ds, dx
    174 	pushw	%dx
    175 	popw	%es
    176 	call	wrhexw
    177 	/* SI */
    178 pr_si:	call	wrstr
    179 	.ascii	"  SI: \0"
    180 	LOADE	si, dx
    181 	pushw	%dx
    182 	popw	%di
    183 	call	wrhexw
    184 	call	crlf
    185 	/* DS:SI */
    186 	movw	$16, %cx
    187 	call	wrhexbses
    188 	call	crlf
    189 
    190 	/* ES */
    191 pr_es:	call	wrstr
    192 	.ascii	"ES: \0"
    193 	LOADE	es, dx
    194 	pushw	%dx
    195 	popw	%es
    196 	call	wrhexw
    197 pr_di:	call	wrstr
    198 	.ascii	"  DI: \0"
    199 	LOADE	di, dx
    200 	pushw	%dx
    201 	popw	%di
    202 	call	wrhexw
    203 	call	crlf
    204 	/* ES:DI */	/* %es:0(%di) */
    205 	movw	$4, %cx
    206 	call	wrhexbses
    207 
    208 #ifdef DEBUG_PNP
    209 	subw	$4, %si
    210 	es lodsw
    211 	cmpw	$0x5024, %ax
    212 	jne	scn_pnp
    213 	es lodsw
    214 	cmpw	$0x506E, %ax
    215 	jne	scn_pnp
    216 	call	wrstr
    217 	.ascii	" =$PnP\0"
    218 scn_pnp:
    219 	call	crlf
    220 	/* $PnP Scan */
    221 	movw	$0xf000, %dx
    222 	pushw	%dx
    223 	popw	%es
    224 	movw	$0, %si
    225 	movw	$0x1000, %cx
    226 	/* 0x506E5024 */
    227 	movw	$0x5024, %dx
    228 	movw	$0x506E, %bx
    229 ch_pnp:	es lodsw	/* Check for $PnP */
    230 	cmpw	%dx, %ax
    231 	jne	ch_pnp_l
    232 	es lodsw
    233 	cmpw	%bx, %ax
    234 	je	pr_pnp
    235 ch_pnp_l:		/* Check $PnP failed; loop to next address */
    236 	addw	$14, %si
    237 	andw	$0xFFF0, %si
    238 	loopw	ch_pnp
    239 	jmp	pnp_end
    240 pr_pnp:
    241 	pushw	%si
    242 	call	wrstr
    243 	.ascii	"$PnP-\0"
    244 	movw	%es, %dx
    245 	call	wrhexw
    246 	movb	$':, %al
    247 	call	wrchr
    248 	popw	%dx
    249 	andw	$0xFFF0, %dx
    250 	call	wrhexw
    251 #endif	/* DEBUG_PNP */
    252 	call	crlf
    253 pnp_end:
    254 
    255 #ifdef DEBUG_FDT
    256 	/* INT 1Eh: Floppy Parameter Table Pointer */
    257 pr_1e:	call	wrstr
    258 	.ascii	"INT 1Eh: \0"
    259 	mov	$int_1e,%bx
    260 	les	(%bx),%di
    261 	pushw	%es
    262 	popw	%dx
    263 	call	wrhexw
    264 	movb	$':, %al
    265 	call	wrchr
    266 	pushw	%di
    267 	popw	%dx
    268 	call	wrhexw
    269 	call	crlf
    270 	/* [INT 1Eh] */
    271 	movw	$14, %cx
    272 	call	wrhexbses
    273 	call	crlf
    274 #endif	/* DEBUG_FDT */
    275 
    276 end:
    277 	jmp	bootfail
    278 
    279 	ASCII_MARKER1	"wc"
    280 wrchr:
    281 	movb	$0x0e, %ah
    282 	movb	(BIOS_page), %bh
    283 	movb	$0x07, %bl
    284 	int	$0x10		/* May destroy %bp */
    285 	ret
    286 
    287 	ASCII_MARKER1	"ws"
    288 wrstr:
    289 	pop	%si
    290 wrstr_l:
    291 	lodsb
    292 	cmpb	$0, %al
    293 	je	wrstr_d
    294 	call	wrchr
    295 	jmp	wrstr_l
    296 wrstr_d:
    297 	push	%si
    298 	ret
    299 
    300 crlf:
    301 	call	wrstr
    302 	.ascii	"\r\n\0"
    303 	ret
    304 
    305 	ASCII_MARKER1	"hx"
    306 wrhexn:
    307 	and	$0x0F, %al
    308 	cmpb	$10, %al
    309 	jae	.alph
    310 	addb	$'0, %al
    311 	jmp	.wc
    312 .alph:
    313 	addb	$('A - 10), %al
    314 .wc:
    315 	call wrchr
    316 	ret
    317 
    318 wrhexb:
    319 	pushw	%cx
    320 	movb	%dl, %al
    321 	pushw	%ax
    322 	movb	$4, %cl
    323 	rorw	%cl, %ax
    324 	call	wrhexn
    325 	popw	%ax
    326 	call	wrhexn
    327 	popw	%cx
    328 	ret
    329 
    330 wrhexw:
    331 	pushw	%cx
    332 	movb	$8, %cl
    333 	rorw	%cl, %dx
    334 	call wrhexb
    335 	rorw	%cl, %dx
    336 	call wrhexb
    337 	popw	%cx
    338 	ret
    339 
    340 	ASCII_MARKER1	"HE"
    341 wrhexbses:
    342 	pushw	%di
    343 	popw	%si
    344 wrhexbses_l:
    345 	movb	$' , %al
    346 	call	wrchr
    347 	es lodsb
    348 	movw	%ax, %dx
    349 	call	wrhexb
    350 	loop	wrhexbses_l
    351 	ret
    352 
    353 data:
    354 	ASCII_MARKER1	"bf"
    355 bootfail:
    356 #ifdef DEBUG_PAK
    357 	call wrstr
    358 	.ascii	"\r\n\r\nPress any key\r\n\0"
    359 	xor	%ax, %ax
    360 	int	$0x16
    361 #endif
    362 	int	$0x18		/* Boot failure */
    363 die:
    364 	hlt
    365 	jmp	die
    366