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