diff options
| author | H. Peter Anvin <hpa@zytor.com> | 2007-02-10 13:22:40 -0800 |
|---|---|---|
| committer | H. Peter Anvin <hpa@zytor.com> | 2007-02-10 13:22:40 -0800 |
| commit | 14df2f8046001f2dc24e1f65bb17c6e31dfbbd09 (patch) | |
| tree | e1aa9c709cd2e3ff208d2160157bac9f3acff61c /mbr | |
| parent | 1970446f95df5ac0a0d3b2b0e90b72e0dd353699 (diff) | |
| parent | d48bb2b249d996587cfe6e39e810a9805d013abe (diff) | |
| download | syslinux-3.40-pre5.tar.gz | |
Merge with git+ssh://master.kernel.org/pub/scm/boot/syslinux/syslinux.git#syslinux-3.3xsyslinux-3.40-pre5
Diffstat (limited to 'mbr')
| -rw-r--r-- | mbr/Makefile | 47 | ||||
| -rwxr-xr-x | mbr/checksize.pl | 31 | ||||
| -rw-r--r-- | mbr/mbr.S | 299 | ||||
| -rw-r--r-- | mbr/mbr.ld | 73 | ||||
| -rw-r--r-- | mbr/oldmbr.asm | 229 |
5 files changed, 679 insertions, 0 deletions
diff --git a/mbr/Makefile b/mbr/Makefile new file mode 100644 index 00000000..d61f7f1c --- /dev/null +++ b/mbr/Makefile @@ -0,0 +1,47 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2007 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +# +# Makefile for MBR +# + +gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \ + then echo $(1); else echo $(2); fi) + +M32 := $(call gcc_ok,-m32,) $(call gcc_ok,-ffreestanding,) $(call gcc_ok,-fno-stack-protector) + +CC = gcc +LD = ld -m elf_i386 +SFLAGS = $(M32) -march=i386 +OBJCOPY = objcopy +PERL = perl + +.SUFFIXES: .S .s .o .elf + +all: mbr.bin + +.PRECIOUS: %.o +%.o: %.S + $(CC) $(SFLAGS) -Wa,-a=$*.lst -c -o $@ $< + +mbr.elf: mbr.o mbr.ld + $(LD) -T mbr.ld -e _start -o $@ $< + +mbr.bin: mbr.elf checksize.pl + $(OBJCOPY) -O binary $< $@ + $(PERL) checksize.pl mbr.bin 440 + +tidy: + rm -f *.o *.elf *.lst + +clean: tidy + rm -f *.bin diff --git a/mbr/checksize.pl b/mbr/checksize.pl new file mode 100755 index 00000000..b7d560a0 --- /dev/null +++ b/mbr/checksize.pl @@ -0,0 +1,31 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2007 H. Peter Anvin - All Rights Reserved +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + +## +## checksize.pl +## +## Check the size of a binary file +## + +($file, $maxsize) = @ARGV; + +@st = stat($file); +if (!defined($size = $st[7])) { + die "$0: $file: $!\n"; +} +if ($size > $maxsize) { + print STDERR "$file: too big ($size > $maxsize)\n"; + exit 1; +} else { + exit 0; +} + diff --git a/mbr/mbr.S b/mbr/mbr.S new file mode 100644 index 00000000..81e5dd00 --- /dev/null +++ b/mbr/mbr.S @@ -0,0 +1,299 @@ +/* ----------------------------------------------------------------------- + * + * Copyright 2007 H. Peter Anvin - All Rights Reserved + * + * 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. + * + * ----------------------------------------------------------------------- */ + + .code16 + .text + + .globl bootsec +stack = 0x7c00 +driveno = (stack-6) +heads = (stack-8) +sectors = (stack-10) + +BIOS_page = 0x462 + + /* gas/ld has issues with doing this as absolute addresses... */ + .section ".bootsec", "a", @nobits + .globl bootsec +bootsec: + .space 512 + + .text + .globl _start +_start: + cli + xorw %ax, %ax + movw %ax, %ds + movw %ax, %ss + movw $stack, %sp + movw %sp, %si + pushw %es /* es:di -> $PnP header */ + pushw %di + pushw %dx /* dl -> drive number */ + movw %ax, %es + sti + cld + + /* Copy down to 0:0x600 */ + movw $_start, %di + movw $(512/2), %cx + rep; movsw + + ljmpw $0, $next + +next: + /* Check to see if we have EBIOS */ + pushw %dx /* drive number */ + movw $0x4100, %ax + movw $0x55aa, %bx + xorw %cx, %cx + xorb %dh, %dh + stc + int $0x13 + jc 1f + cmpw $0xaa55, %bx + jne 1f + testb $0x01, %cl + jz 1f + + /* We have EBIOS; patch in a jump to read_sector_ebios */ + movw $0xeb+((read_sector_ebios-read_sector_cbios-2)<< 8), (read_sector_cbios) + +1: + popw %dx + + /* Get (C)HS geometry */ + movb $0x08, %ah + int $0x13 + xorw %ax, %ax + movb %dh, %al /* dh = number of heads */ + incw %ax /* From 0-based to count */ + pushw %ax /* Save heads on the stack */ + andw $0x3f, %cx /* Sector count */ + pushw %cx /* Save sectors on the stack */ + + xorl %eax, %eax + pushl %eax /* Base */ + pushl %eax /* Root */ + call scan_partition_table + + /* If we get here, we have no OS */ + jmp missing_os + +/* + * read_sector: read a single sector pointed to by %eax to 0x7c00. + * CF is set on error. All registers clobbered. + */ +read_sector: +read_sector_cbios: + movl %eax, %edx + shrl $16, %edx + divw (sectors) + incw %dx + movw %dx, %cx + xorw %dx, %dx + divw (heads) + /* dx = head, ax = cylinder */ + movb %al, %ch + shrw $2, %ax + shrw %ax + andb $0xc0, %al + orb %al, %cl + movb %dl, %dh + movw $bootsec, %bx + movw $0x0201, %ax + jmp read_common +read_sector_ebios: + movw $dapa, %si + movl %eax, 8(%si) + movb $0x42, %ah +read_common: + movb (driveno), %dl + int $0x13 + ret + +/* + * read_partition_table: + * Read a partition table (pointed to by %eax), and copy + * the partition table into the ptab buffer. + * Preserve registers. + */ +ptab = _start+446 + +read_partition_table: + pushal + call read_sector + jc 20f + movw $bootsec+446, %si + movw $ptab, %di + movw $(16*4/2), %cx + rep ; movsw +20: + popal + ret + +/* + * scan_partition_table: + * Scan a partition table currently loaded in the partition table + * area. Preserve 16-bit registers. + * + * On stack: + * 18(%bp) - root (offset from MBR, or 0 for MBR) + * 22(%bp) - base (location of this partition table) + */ + +scan_partition_table: + pusha + movw %sp, %bp + + /* Search for active partitions */ + movw $ptab, %di + movw $4, %cx + xorw %ax, %ax +5: + testb $0x80, (%di) + jz 6f + incw %ax + movw %di, %si +6: + addw $16, %di + loopw 5b + + cmpw $1, %ax /* Number of active partitions found */ + je boot + ja too_many_active + + /* No active partitions found, look for extended partitions */ + movw $ptab, %di + movb $4, %cl /* cx == 0 here */ +7: + movb 4(%di), %al + cmpb $0x05, %al /* MS-DOS extended */ + je 8f + cmpb $0x0f, %al /* Win9x extended */ + je 8f + cmpb $0x85, %al /* Linux extended */ + jne 9f + + /* It is an extended partition. Read the extended partition and + try to scan it. If the scan returns, re-load the current + partition table and resume scan. */ +8: + movl 8(%di), %eax /* Partition table offset */ + movl 18(%bp), %edx /* "Root" */ + addl %edx, %eax /* Compute location of new ptab */ + andl %edx, %edx /* Is this the MBR? */ + jnz 10f + movl %eax, %edx /* Offset -> root if this was MBR */ +10: + pushl %eax /* Push new base */ + pushl %edx /* Push new root */ + call read_partition_table + jc 11f + call scan_partition_table +11: + addw $8, %sp + /* This returned, so we need to reload the current partition table */ + movl 22(%bp), %eax + call read_partition_table + + /* fall through */ +9: + /* Not an extended partition */ + addw $16, %di + loopw 7b + + /* Nothing found, return */ + popa + ret + +/* + * boot: invoke the actual bootstrap. (%si) points to the partition + * table entry, and 22(%bp) has the partition table base. + */ +boot: + movl 8(%si), %eax + addl 22(%bp), %eax + movl %eax, 8(%si) + pushw %si + call read_sector + popw %si + jc disk_error + cmpw $0xaa55, (bootsec+510) + jne missing_os /* Not a valid boot sector */ + movw $driveno, %sp + popw %dx /* dl -> drive number */ + popw %di /* es:di -> $PnP vector */ + popw %es + cli + jmp bootsec + +/* + * error messages + */ +missing_os: + movw $missing_os_msg, %si + jmp error +disk_error: + movw $disk_error_msg, %si + jmp error +too_many_active: + movw $too_many_active_msg, %si + /* jmp error */ + +error: +2: + lodsb + andb %al, %al + jz 3f + movb $0x0e, %ah + movb (BIOS_page), %bh + movb $0x07, %bl + int $0x10 + jmp 2b +3: + int $0x18 /* Boot failure */ + jmp . /* Die */ + +missing_os_msg: + .ascii "Missing operating system." + .byte 0 +disk_error_msg: + .ascii "Operating system load error." + .byte 0 +too_many_active_msg: + .ascii "Multiple active partitions." + .byte 0 + + .balign 4 +dapa: + .short 16 /* Size of packet */ + .short 1 /* Sector count */ + .short 0x7c00 /* Buffer offset */ + .short 0 /* Buffer segment */ + .long 0 /* LSW of LBA */ + .long 0 /* MSW of LBA */ diff --git a/mbr/mbr.ld b/mbr/mbr.ld new file mode 100644 index 00000000..d14ba802 --- /dev/null +++ b/mbr/mbr.ld @@ -0,0 +1,73 @@ +/* + * Linker script for MBR + */ + +/* Script for -z combreloc: combine and sort reloc sections */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +EXTERN(_start) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x600; + .text : + { + *(.text*) + *(.rodata*) + } =0x90909090 + + . = ALIGN(4); + .data : + { + *(.data*) + } + + . = ALIGN(128); + .bss : + { + *(.bss*) + } + + . = 0x7c00; + .bootsec : + { + *(.bootsec) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/mbr/oldmbr.asm b/mbr/oldmbr.asm new file mode 100644 index 00000000..31bf1fdf --- /dev/null +++ b/mbr/oldmbr.asm @@ -0,0 +1,229 @@ +; ----------------------------------------------------------------------- +; +; Copyright 2003-2004 H. Peter Anvin - All Rights Reserved +; +; 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. +; +; ----------------------------------------------------------------------- + +; +; mbr.asm +; +; Simple Master Boot Record, including support for EBIOS extensions. +; +; The MBR lives in front of the boot sector, and is responsible for +; loading the boot sector of the active partition. The EBIOS support +; is needed if the active partition starts beyond cylinder 1024. +; +; This MBR determines all geometry info at runtime. It uses only the +; linear block field in the partition table. It does, however, pass +; the partition table information unchanged to the target OS. +; +; This MBR should be "8086-clean", i.e. not require a 386. +; + +%include "bios.inc" + +; +; Note: The MBR is actually loaded at 0:7C00h, but we quickly move it down to +; 0600h. +; + section .text + cpu 8086 + org 0600h + +_start: cli + xor ax,ax + mov ds,ax + mov es,ax + mov ss,ax + mov sp,7C00h + sti + cld + mov si,sp ; Start address + mov di,0600h ; Destination address + mov cx,512/2 + rep movsw + +; +; Now, jump to the copy at 0600h so we can load the boot sector at 7C00h. +; Since some BIOSes seem to think 0000:7C00h and 07C0:0000h are the same +; thing, use a far jump to canonicalize the address. This also makes +; sure that it is a code speculation barrier. +; + + jmp 0:next ; Jump to copy at 0600h + +next: + mov [DriveNo], dl ; Drive number stored in DL +; +; Check for CHS parameters. This doesn't work on floppy disks, +; but for an MBR we don't care. +; + mov ah,08h ; Get drive parameters + int 13h + xor ax,ax + mov al,dh + inc ax ; From 0-based to count + mov [Heads],ax + and cl,3Fh ; Max sector number + mov [Sectors],cl + ; Note: we actually don't care about the number of + ; cylinders, since that's the highest-order division + +; +; Now look for one (and only one) active partition. +; + mov si,PartitionTable + xor ax,ax + mov cx,4 +checkpartloop: + test byte [si],80h + jz .notactive + inc ax + mov di,si +.notactive: add si,byte 16 + loop checkpartloop + + cmp ax,byte 1 ; Better be only one + jnz not_one_partition + +; +; Now we have the active partition partition information in DS:DI. +; Check to see if we support EBIOS. +; + mov dl,[DriveNo] + mov ax,4100h + mov bx,055AAh + xor cx,cx + xor dh,dh + stc + int 13h + jc no_ebios + cmp bx,0AA55h + jne no_ebios + test cl,1 ; LBA device access + jz no_ebios +; +; We have EBIOS. Load the boot sector using LBA. +; + push di + mov si,dapa + mov bx,[di+8] ; Copy the block address + mov [si+8],bx + mov bx,[di+10] + mov [si+10],bx + mov dl,[DriveNo] + mov ah,42h ; Extended Read + jmp short common_tail +; +; No EBIOS. Load the boot sector using CHS. +; +no_ebios: + push di + mov ax,[di+8] + mov dx,[di+10] + div word [Sectors] + inc dx + mov cx,dx ; Sector # + xor dx,dx + div word [Heads] + ; DX = head #, AX = cylinder # + mov ch,al + shr ax,1 + shr ax,1 + and al,0C0h + or cl,al + mov dh,dl ; Head # + mov dl,[DriveNo] + mov bx,7C00h + mov ax,0201h ; Read one sector +common_tail: + int 13h + jc disk_error + pop si ; DS:SI -> partition table entry +; +; Verify that we have a boot sector, jump +; + cmp word [7C00h+510],0AA55h + jne missing_os + cli + jmp 0:7C00h ; Jump to boot sector; far + ; jump is speculation barrier + ; (Probably not neecessary, but + ; there is plenty of space.) + +not_one_partition: + ja too_many_os +missing_os: + mov si,missing_os_msg + jmp short die +too_many_os: +disk_error: + mov si,bad_disk_msg +die: +.msgloop: + lodsb + and al,al + jz .now + mov ah,0Eh ; TTY output + mov bh,[BIOS_page] ; Current page + mov bl,07h + int 10h + jmp short .msgloop +.now: + jmp short .now + + align 4, db 0 ; Begin data area + +; +; EBIOS disk address packet +; +dapa: + dw 16 ; Packet size +.count: dw 1 ; Block count +.off: dw 7C00h ; Offset of buffer +.seg: dw 0 ; Segment of buffer +.lba: dd 0 ; LBA (LSW) + dd 0 ; LBA (MSW) + +; CHS information +Heads: dw 0 +Sectors: dw 0 + +; Error messages +missing_os_msg db 'Missing operating system', 13, 10, 0 +bad_disk_msg db 'Operating system loading error', 13, 10, 0 + +; +; Maximum MBR size: 446 bytes; end-of-boot-sector signature also needed. +; Note that some operating systems (NT, DR-DOS) put additional stuff at +; the end of the MBR, so shorter is better. Location 440 is known to +; have a 4-byte attempt-at-unique-ID for some OSes. +; + +PartitionTable equ $$+446 ; Start of partition table + +; +; BSS data; put at 800h +; +DriveNo equ 0800h |
