[syslinux] [PATCH 1/1] v2 Add Diagnostic MBR for trouble-shooting

Michael A mikearm77 at hotmail.com
Mon Mar 30 05:39:24 PDT 2009


How cam I stop your emails frome coming to my address please? I get all sorts of emails from syslimux.

 

Mike
 
> From: ubuntu at tjworld.net
> To: syslinux at zytor.com
> Date: Mon, 30 Mar 2009 13:28:32 +0100
> Subject: [syslinux] [PATCH 1/1] v2 Add Diagnostic MBR for trouble-shooting
> 
> ---
> mbr/Makefile | 6 +-
> mbr/mbr-diag.S | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 377 insertions(+), 1 deletions(-)
> create mode 100644 mbr/mbr-diag.S
> 
> diff --git a/mbr/Makefile b/mbr/Makefile
> index 0bdf7e3..b9d743d 100644
> --- a/mbr/Makefile
> +++ b/mbr/Makefile
> @@ -17,7 +17,7 @@
> topdir = ..
> include $(topdir)/MCONFIG.embedded
> 
> -all: mbr.bin gptmbr.bin isohdpfx.bin
> +all: mbr.bin gptmbr.bin isohdpfx.bin mbr-diag.bin
> 
> .PRECIOUS: %.o
> %.o: %.S
> @@ -31,6 +31,10 @@ mbr.bin: mbr.elf checksize.pl
> $(OBJCOPY) -O binary $< $@
> $(PERL) checksize.pl $@ 440
> 
> +mbr-diag.bin: mbr-diag.elf checksize.pl
> + $(OBJCOPY) -O binary $< $@
> + $(PERL) checksize.pl mbr-diag.bin 440
> +
> isohdpfx.bin: isohdpfx.elf checksize.pl
> $(OBJCOPY) -O binary $< $@
> $(PERL) checksize.pl $@ 432
> diff --git a/mbr/mbr-diag.S b/mbr/mbr-diag.S
> new file mode 100644
> index 0000000..c428d28
> --- /dev/null
> +++ b/mbr/mbr-diag.S
> @@ -0,0 +1,372 @@
> +/*
> + Diagnostic Master Boot Record
> + Copyright 2009 TJ <linux at tjworld.net> <ubuntu at tjworld.net>
> + Licensed on the terms of the GNU General Public License, version 2
> +
> + This is a diagnsotic master boot record (MBR) with the sole purpose of 
> + reporting the BIOS values received at boot-time for addressing mode, drive-number,
> + device geometry, active partition and magic bytes of active partition boot sector.
> +
> + It is an aid to determining why some devices fail to boot correctly when
> + using the 'default' MBR.
> +
> + NOTE: If a shift key is held down at boot, CHS addressing mode is forced
> +
> + It is also an educational tool and commented in a way which should increase
> + a user's understanding of both assembly programming and the boot process.
> +
> + The jump-off web page for the GNU documentation is http://www.gnu.org/software/binutils/
> + The current (binutils 2.19.1) GNU 'as' documentation is at: http://sourceware.org/binutils/docs-2.19/as/index.html
> +
> + In comments 'doc:' refers to the binutils 'as' documentation section.
> +
> + This code uses the 'AT & T' form of instructions: op [[source] [destination]] doc: 9.13.3
> + Ops explicitly use the size suffix to prevent GNU 'as' creating 32-bit op-codes. doc: 9.13.12
> +
> + Due to the severe space constraints the output uses 1-character description codes to prefix each printed value.
> + Hex values are suffixed with 'h' (saves 1 byte against using 0x).
> +
> + Description Codes:
> + L | C LBA or CHS addressing mode
> + D drive number BIOS-reported drive number
> + C cylinders Geometry of drive according to BIOS
> + H heads
> + S sectors
> + P partition active partition number (first partition flagged active). '?' if no active partition
> + O offset absolute sector offset of active partition . '????????' if no active partition
> + M magic magic bytes of active partition boot sector (sector <offset> as read by BIOS).
> + '????' if no active partition. Value is reset to 0xDEAD before the sector is read
> + to avoid inheriting the MBR magic on error
> + E error error code returned by BIOS 'read sector' interrupt (0x02 or 0x42, int 0x13).
> + '??' if no active partition.
> +
> + Examples:
> + L D80h C3D9h HFFh S3Fh P1 O00000020h MAA55h E00h
> + C D80h C3D9h HFFh S3Fh P1 O00000020h M0000h E04h
> +
> + Usage:
> + # set device to write diagnostic MBR to
> + DEV=/dev/sdc
> + # back-up existing MBR
> + sudo dd if=$DEV of=mbr-backup.bin bs=440 count=1
> + # write diagnostic MBR to device
> + sudo dd if=mbr-diag.bin of=$DEV
> + # example: test in a virtual machine (uses sudo because it is accessing raw device)
> + sudo kvm -m 128 -hda $DEV
> + # restore original MBR
> + sudo dd if=mbr-backup.bin of=$DEV
> +
> +*/
> +
> + .code16 /* generate 16-bit code. doc: 9.13.12 */
> + .text /* sub-section (default 0). doc: 7.109 */
> +
> +video_page = 0x462 /* I/O port for video controller page selection (bitmask 0x07) */
> +flag_active = 0x80 /* partition table entry active (bootable) flag */
> +
> +stack = 0x7C00 /* top of stack is immediately below where the BIOS loaded this MBR */
> +pnp_header = (stack-4) /* The Plug'n'Play header received from BIOS in ES:DI */
> +drive_number = (stack-6) /* The boot device as reported by BIOS in DL */
> +cylinders = (stack-8)
> +heads = (stack-10)
> +sectors = (stack-12)
> +sectors_cylinder= (stack-16)
> +
> + .section ".bootsec", "a", @nobits /* assemble into; ELF: allocatable, no data. doc: 7.95 */
> + .global bootsec /* externally visible. doc: 7.56 */
> +bootsec:
> + .space 512 /* set 512 bytes to zero. doc: 7.102 */
> +
> + .text
> + .global _start
> +_start:
> +
> + /* All code from here until the relocation operation does nothing that relies */
> + /* on the value of the instruction pointer */
> + cli /* disable interrupts */
> + xorw %ax, %ax /* reset to 0 */
> + movw %ax, %ds /* reset data segment base */
> + movw %ax, %ss /* reset stack segment base */
> + movw $stack, %sp /* set stack pointer */
> + movw %sp, %si /* address where BIOS loaded MBR, used as source address for relocation */
> + pushw %es /* save Plug'n'Play header provided by BIOS in ES:DI */
> + pushw %di
> + pushw %dx /* save drive number provided by BIOS in DL */
> + movw %ax, %es /* reset extra segment base */
> + sti /* enable interrupts */
> + cld /* increment direction for relocation operation */
> +relocate:
> + movw $_start, %di /* destination address for relocation */
> + movw $(512/2), %cx /* number of words to relocate */
> + rep; movsw /* repeat the move CX times, incrementing SI and DI after each move */
> +
> + ljmpw $0, $get_shift_keys /* far jump to ensure CS:IP are set correctly to 0000:0600+get_shift_keys */
> + /* rather than the current CS:IP which will be based on 0x7C00 */
> +
> +get_shift_keys: /* Provide a way for the user to force CHS addressing mode by pressing either Shift key */
> + movb $0x02, %ah /* function: get keyboard shift flags */
> + int $0x16 /* read keys; shift flags returned in AL */
> + testb $0x03, %al /* left or right shift-keys pressed? */
> + jnz use_chs_addressing /* if so, skip detection of BIOS type */
> +
> +detect_bios_type:
> + /* try to use the BIOS extension for LBA (Logical Block Addressing). */
> + movb (drive_number), %dl
> + movw $0x55aa, %bx /* required */
> + movb $0x41, %ah /* query presence of extended BIOS functions (EBIOS) */
> + int $0x13 /* call BIOS */
> + jc use_chs_addressing /* carry flag will be set on return if extensions are NOT supported */
> + cmpw $0xaa55, %bx /* bytes returned swapped if successful */
> + jne use_chs_addressing
> + shrw %cx /* Shift right once into carry flag. Bit 0: extended (LBA) disk functions available */
> + jnc use_chs_addressing
> + jmp use_lba_addressing
> +
> +use_chs_addressing:
> + movb $0x02, read_op /* set the BIOS function to use when reading CHS sectors */
> + movb $'C', (msg_address_mode) /* over-write 'L' with 'C' in boot message */
> +
> +use_lba_addressing:
> + /* convert drive-number to two hex characters and insert them into the boot message */
> + movw (drive_number), %dx
> + pushw %dx /* preserve for use by calculate_geometry */
> + movw $msg_drive_number, %di
> + movb $0x02, %cl /* write two nibbles */
> + call write_hex_value
> +
> +calculate_geometry:
> + popw %dx /* retrieve drive number */
> + movb $0x08, %ah
> + int $0x13 /* get drive parameters; returns CH LSB of max cyl., CL(7-6) MSb max cyl., */
> + /* CL(5-0) max sector, DH max head, DL drive qty, ES:DI floppy parameter table */
> + movb %ch, %bl /* transfer maximum cylinder number */
> + movb %cl, %bh
> + shrb $6, %bh /* move bits into correct positions */
> + pushw %bx /* preserve maximum cylinder number */
> + incb %dh /* convert zero-based maximum to quantity */
> + movzbw %dh, %ax /* DH = maximum head number */
> + pushw %ax /* preserve maximum head number */
> + andw $0x3f, %cx /* mask to enforce maximum sector number 63 */
> + pushw %cx /* preserve sector count */
> + incw %ax /* convert zero-based maximum head number to quantity */
> + mulw %cx /* sectors per cylinder = heads*sectors */
> + pushw %dx /* preserve sectors per cylinder DX:AX */
> + pushw %ax
> +
> +msg_format_cylinders:
> + movw $msg_cylinders, %di
> + movw (cylinders), %dx
> + movb $0x03, %cl /* write three nibbles */
> + call write_hex_value
> +
> +msg_format_heads:
> + movw $msg_heads, %di
> + movw (heads), %dx
> + movb $0x02, %cl /* write two nibbles */
> + push %cx /* preserve for sectors */
> + call write_hex_value
> +
> +msg_format_sectors:
> + movw $msg_sectors, %di
> + movw (sectors), %dx
> + popw %cx /* write two nibbles */
> + call write_hex_value
> +
> +partition_table_scan:
> + movw $partition_table, %si
> + movw $0x04, %cx /* number of table entries */
> +
> +partition_entry_next:
> + testb $flag_active, (%si) /* is active (bootable) flag set? */
> + jnz msg_partition_active
> +
> + addw $16, %si /* next entry */
> + loopw partition_entry_next
> +
> + jmp print_boot_message /* no active parition, so don't try to read a sector */
> +
> +msg_partition_active:
> + movb $0x05, %ch /* convert CL countdown to partition number */
> + subb %cl, %ch /* CL:partition translations 4:1, 3:2, 2:3, 1:4 */
> + movb %ch, %dl /* value to write is partition number [1-4] */
> + movw $msg_partition, %di
> + movb $0x01, %cl /* one nibble */
> + call write_hex_value
> +
> +partition_get_offset:
> + movl 8(%si), %edx /* absolute starting sector (DWORD: partition_table[8]) */
> + pushl %edx /* preserve for use in partition_read_sector */
> + rorl $16, %edx /* swap low and high WORDs - high WORD needed in DX first */
> + movw $msg_partition_offset_high, %di /* high WORD of DWORD */
> + movb $0x04, %cl /* four nibbles */
> + pushw %cx /* use again for low WORD */
> + call write_hex_value
> +
> + /* at this point DI should be pointing to first character of low WORD in the string */
> + shrl $16, %edx /* shift high WORD into low WORD */
> + popw %cx /* use again for low WORD */
> + call write_hex_value
> +
> +partition_read_sector:
> + movw $0xDEAD, %cx /* over-write current 'magic' indicator in sector buffer */
> + /* this ensures that if read_sector fails the MBR magic isn't still there */
> + movw %cx, (bootsec + 510)
> + popl %eax /* retrieve boot sector of active partition into buffer */
> + call read_sector
> + pushw %ax /* preserve read error code (0 = success) */
> +
> +msg_partition_magic:
> + movw $msg_boot_sector_magic, %di
> + movb $0x04, %cl /* four nibbles */
> + movw (bootsec + 510), %dx /* get last two bytes of sector */
> + call write_hex_value
> +
> +msg_read_error_code:
> + movw $msg_read_error, %di
> + movb $0x02, %cl /* two nibbles */
> + popw %dx /* retrieve read error code */
> + shrw $8, %dx /* error code in high byte needs to be in low byte for writing */
> + call write_hex_value
> +
> +print_boot_message:
> + mov $msg_boot, %si
> + call print /* print the boot message */
> +
> +stop:
> + hlt /* stop nicely; don't burn the CPU up */
> + jmp stop
> +
> +/*
> + * read_sector: read a single sector pointed to by %eax to 0x7c00.
> + * CF is set on error. All registers saved.
> + */
> +read_sector:
> + xorl %edx, %edx /* reset to 0 */
> + /* create a disk address packet structure on the stack */
> + pushl %edx /* most significant double-word of LBA (upper part of 48-bit LBAs) */
> + pushl %eax /* least significant double-word of LBA */
> + pushw %es /* buffer segment */
> + movw $bootsec, %bx /* address of buffer that will receive the sector (should be 0x7C00) */
> + pushw %bx /* buffer offset */
> + pushw $1 /* sector count always 1 */
> + pushw $16 /* size of disk address packet */
> + movw %sp, %si /* address of disk address packet (on stack) */
> +
> + testb $0x42, read_op /* using LBa addressing? */
> + jz read_common /* Use LBA extended addressing */
> +
> +read_sector_chs:
> + divl (sectors_cylinder) /* LBA in DX:AX inherited from above */
> + shlb $6, %ah /* quotient is the cylinder number */
> + movb %ah, %cl /* cylinder high bits (7-6) */
> + movb %al, %ch /* cylinder low bits (7-0) */
> + xchgw %dx, %ax /* remainder is the sector-offset into the cylinder */
> + divb (sectors)
> + movb %al, %dh /* head number */
> + orb %ah, %cl /* sector offset ORed into CL since CL(7-6) already contain two high bits of cylinder number */
> + incw %cx /* sector counts start at 1 not 0 */
> +
> +read_common:
> +read_op = .+2 /* address of operand to be moved into AH (0x42 in the following instruction) */
> + movw $0x4201, %ax /* default is 0x42 (LBA) but may be over-written with 0x02 (CHS). AL = number of sectors */
> + movb (drive_number), %dl
> + int $0x13 /* read disk */
> +
> + addw $16, %sp /* discard disk address packet */
> + ret
> +
> +/* write value as hex.
> + writes CL (max 4) hex digits representing the value of DX starting at DI
> + The choice of nibbles is right-aligned so the least-significant will always be processed.
> +*/
> +write_hex_value:
> + xorb %ch, %ch /* reset to 0 to ensure CX loop uses only CL value passed in */
> +
> +write_hex_next:
> + pushw %dx /* preserve value */
> + cmpb $0x02, %cl /* is this the high byte? */
> + jle write_hex_byte
> + movb %dh, %dl /* move high-byte into low byte for processing */
> +
> +write_hex_byte:
> + btw $0x00, %cx /* low nibble? (CX = 4,2: high nibble. CX = 3,1: low nibble) */
> + jc write_hex_nibble
> +
> +write_hex_high_nibble:
> + shrb $4, %dl /* high nibble required; shift into low nibble */
> +
> +write_hex_nibble:
> + andb $0x0F, %dl /* mask to retain only the low nibble */
> + call hex_ascii_format
> + movb %dl, (%di) /* over-write character in string */
> + incw %di /* next character */
> + pop %dx /* retrieve value for next iteration */
> + loopw write_hex_next
> +
> + ret
> +
> +/* low nibble of DL contains value to be converted. returns ASCII code in DL */
> +hex_ascii_format:
> + addb $'0', %dl /* offset into ASCII table; value 0 == ASCII "0" */
> + cmpb $'9', %dl
> + jle nibble_set /* value is 0-9; no need to adjust */
> + addb $('A' - ':'), %dl /* adjust 0x0a-0x0f to map to ASCII characters 'A' to 'F' */
> +nibble_set:
> + ret
> +
> +/* print a zero-terminated string of characters whose address is in SI */
> +print:
> + cld /* move left-to-right in string */
> + movb (video_page), %bh /* get current page from video controller's memory-mapped I/O register */
> + movb $0x07, %bl /* colour attribute */
> + movb $0x0e, %ah /* BIOS function: display char */
> +
> +print_next:
> + lodsb /* load a character into AL */
> + orb %al, %al /* is it the string zero terminator? */
> + jz print_end /* finished */
> +
> + call print_char
> + jmp print_next /* next character */
> +
> +print_char:
> + int $0x10 /* display */
> + ret
> +
> +print_end:
> + ret
> +
> +msg_boot:
> + .ascii "DIAG "
> +msg_address_mode:
> + .ascii "L" /* These entries make up ONE zero-terminated string */
> + .ascii " D"
> +msg_drive_number:
> + .ascii "??h" /* ?? will be over-written with drive number */
> + .ascii " C"
> +msg_cylinders:
> + .ascii "???h"
> + .ascii " H"
> +msg_heads:
> + .ascii "??h"
> + .ascii " S"
> +msg_sectors:
> + .ascii "??h"
> + .ascii " P"
> +msg_partition:
> + .ascii "?"
> + .ascii " O"
> +msg_partition_offset_high:
> + .ascii "????"
> +msg_partition_offset_low:
> + .ascii "????h"
> + .ascii " M"
> +msg_boot_sector_magic:
> + .ascii "????h"
> + .ascii " E"
> +msg_read_error:
> + .ascii "??h"
> + .asciz "\r\n"
> +
> +partition_table = _start + 446 /* location of partition table */
> +
> -- 
> 1.6.0.4
> 
> _______________________________________________
> Syslinux mailing list
> Submissions to Syslinux at zytor.com
> Unsubscribe or set options at:
> http://www.zytor.com/mailman/listinfo/syslinux
> Please do not send private replies to mailing list traffic.
> 

_________________________________________________________________
Need a new place to rent, share or buy? Let ninemsn property help.
http://a.ninemsn.com.au/b.aspx?URL=http%3A%2F%2Fninemsn%2Edomain%2Ecom%2Eau%2F%3Fs%5Fcid%3DFDMedia%3ANineMSN%5FHotmail%5FTagline&_t=774152450&_r=Domain_tagline&_m=EXT


More information about the Syslinux mailing list