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
Possibly Parallel 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