/* ----------------------------------------------------------------------- * * 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