TJ
2009-Mar-30 12:28 UTC
[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
Michael A
2009-Mar-30 12:39 UTC
[syslinux] [PATCH 1/1] v2 Add Diagnostic MBR for trouble-shooting
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
Gene Cumm
2009-Mar-30 13:49 UTC
[syslinux] [PATCH 1/1] v2 Add Diagnostic MBR for trouble-shooting
On Mon, Mar 30, 2009 at 8:39 AM, Michael A <mikearm77 at hotmail.com> wrote:> > How cam I stop your emails frome coming to my address please? I get all sorts of emails from syslimux. >Unsubscribe information is at a web page listed at the bottom of every e-mail.> _______________________________________________ > 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. >-Gene
Reasonably Related Threads
- [PATCH 1/1] Add Diagnostic MBR for trouble-shooting
- [PATCH 1/1] v3: Add Diagnostic MBR for trouble-shooting BIOS boot-order problems.
- "isolinux.bin missing or corrupt" when booting USB flash drive in old PC
- "isolinux.bin missing or corrupt" when booting USB flash drive in old PC
- [PATCH] 4k_sector: Support dynamic sectors in GPT MBR