Rod Pemberton <EmailN...@voenflacbe.cpm> writes:
>On Tue, 7 Nov 2017 14:55:58 -0800 (PST)
>"
s_dub...@yahoo.com" <
s_dub...@yahoo.com> wrote:
>
>> > I'm not seeing hidden sectors with the actual floppy images, only
>> > with the "errant" hard disk image that has a partition that starts
>> > at sector 63.
>>
>> How did you determine this, from the MBR originally?
>
>No, not the MBR. I wrote a image of random bytes to the USB stick after
>booting it. The USB was being emulated by BIOS for the booted image.
>For the booted "errant" hard disk image, the random image was offset by
>63 sectors from the start of the USB stick. For a booted floppy image,
>the random image had no offset from the start of the USB stick.
The USB drive looks like a hard disk, not a floppy disk. The partition
table at the end of the MBR defines the first sector of the first
partition (which often is offset 63 sectors from the start of the device).
The BIOS will load 512-byte MBR into memory and transfer control to the
first byte of the MBR. Those ~450 bytes of code will typically read
the secondary bootstrap from the sector immediately following the MBR
and transfer control to that. That code will then load the boot loader
(NTLDR, LILO, GRUB) from the hard disk and transfer control to it. The
boot loader will subsequently load the operating system from one of the
partitions on the disk and transfer control to it. The operating system
will then transition from real-mode to protected mode, then will enable
paging and transition to long mode.
Here's an example of the primary bootstrap code in the first ~450 bytes
of the MBR:
#
# Master Boot Record
#
RELO_ADDR=0x600
BASE_ADDR=0x7c00
S2_SEG=0x9020
S2_ADDR=0x0000
#
# These values must match the offsets in geometry_info
#
SECTORS_PER_TRACK=0
MAXIMUM_HEADS=4
MAXIMUM_CYLS=8
SECTOR=10
HEAD=11
CYLINDER=12
STAGE2SECTOR=1
DVMM_SECTOR=5
.code16
.text
#
# These 512 bytes of code and data are loaded by the bios at 0x0000:0x7c00.
#
# Called with
# %dl Drive number booted from (00 = floppy A, 80 = hard disk C)
# %es:%di PnP Installation Check structure
#
.global start
start:
cli # Disable interrupts
xorw %ax, %ax # Clear %ax
movw %ax, %ss # Set stack segment
movw $BASE_ADDR, %sp # Set stack pointer
#
# Relocate the master boot record from the initial 0000:7c00
# address to 0000:0600 and transfer control to the newly relocated
# code.
#
movw %sp, %si # Pointer to starting byte to move
pushw %ax
popw %es # Set ES register to 0000
pushw %ax
popw %ds # Set DS register to 0000
sti # Enable interrupts
cld # Set direction forward
movw $RELO_ADDR, %di # Pointer to destination address
movw $0x100, %cx # Move 256 words
repz movsw # Move 512 bytes from 0000:7c00 to 0000:0600
ljmp $0x0, $RELO_ADDR+1f # Branch to relocated code
1:
#
# Save the drive number that we were loaded from.
#
movb %dl, (RELO_ADDR+drive_num)
#
# Get drive geometry.
#
pushw %dx
movb $0x8, %ah # Get drive information
movw $0x7c00, %di # Just in case
int $0x13 # Get geometry
jc read_error # Jump if error
#
# Convert the drive geometry from zero-based values to one-based values.
#
movw $(RELO_ADDR+geometry_info), %si
xorl %eax, %eax
movb %dh, %al # Maximum heads
incw %ax # Turn "max" into "count"
movl %eax, 4(%si) # Store
xorw %dx, %dx
movb %cl, %dl # Copy composite value
shlw $2, %dx # shift left twice
movb %ch, %al # Copy low 8 bits of max cyl
movb %dh, %ah # And the upper two bits
incw %ax # Turn "max" into "count"
movw %ax, 8(%si) # Store
xorw %ax, %ax
movb %dl, %al # Get max sector
shrb $2, %al # Normalize
movl %eax, (%si) # Save it
#
# Read in the second stage bootstrap
#
xorw %dx, %dx # Clear high order sector number
movw $STAGE2SECTOR, %ax # Low order sector number
movw $S2_SEG, %bx # Segment Address to read into
movw %bx, %es # Set segment register and
xorw %bx, %bx # clear the offset.
movw RELO_ADDR+s2sectors, %cx # Number of sectors to read
call readblocks # Fetch it
jc read_error # Bail on error
#
# Read in the Hypervisor, 32K at a time.
#
xorl %ecx, %ecx # Clear register
xorl %edi, %edi
movw RELO_ADDR+syssize, %di
shll $4, %edi # Convert from "clicks" to bytes
movw $STAGE2SECTOR, %ax # Stage2 sector #
addw RELO_ADDR+s2sectors, %ax # Add size of stage2 bootstrap
movw $0x1000, %bx # Segment address
movw %bx, %es # Set segment register
loop:
cmpl $0, %edi # Are we done?
je done # Yep.
cmpl $0x7fff, %edi # Do we have more than 1 segment left?
movw $0x7fff, %si
cmovge %si, %cx # If yes, read one segment
cmovl %di, %cx # If no, read the remainder
subl %ecx, %edi # Subtract the read amount off of the total
# We have to do this before we convert %cx
# to sectors.
addl $511, %ecx # 512-1
shrl $9, %ecx # Divide by 512 to get sectors
xorw %dx, %dx # clear high order sector number
xorw %bx, %bx # Clear offset
pushw %ax # Save sector offset
pushw %cx # Save sector count
call readblocks # Fetch it
jc read_error # Bail on error
popw %cx # Restore sector count
popw %ax # Restore sector offset
addw %cx, %ax # Increment the sector ptr by the # read
movw %es, %si
addw $0x800, %si # Increment %es to point to the next segment
movw %si, %es
jmp loop # repeat.
done:
#
# The BIOS uses a PIT timer (channel) zero to establish a 2-second
# timeout period after which it will turn off the floppy drive motor.
# Since the DVMM will re-purpose the PIT0 timer, we'll turn off
# the floppy motor here.
#
movw $0x3f2,%dx # Address of floppy controller
xorb %al, %al # Turn off floppy motor
outb %al, %dx # send the command
#
# Invoke stage2 bootstrap code
#
movw $(RELO_ADDR+missingos), %si # Message, if necessary
movw $S2_SEG, %bx # Stage 2 loader
movw %bx, %fs # Segment
movw $0x1fe, %di # 510 bytes into stage 2 loader is signature
cmpw $0xaa55, %fs:(%di) # Check for signature
jnz printmsg # If not there, print message
ljmp $S2_SEG, $S2_ADDR # Invoke secondary bootstrap
#
# Convert a Logical Block Address to a CHS address
#
# LBA - provided in AX:DX
# Cylinder is returned in global variable cylinder
# head head
# sector sector
#
# Returns:
# Carry set on error
# Carry clear on success
#
convert:
movw $(RELO_ADDR+geometry_info), %si # Pointer to geometry info
# cmpw %dx, SECTORS_PER_TRACK(%si) # Compare to sectors per track
# jg 1f # Branch if so
divw SECTORS_PER_TRACK(%si) # Divide %DX:%AX by sectors_per_track
incb %dl # Make one-relative
movb %dl, SECTOR(%si) # Sector to read
xorw %dx, %dx # Zero
divw MAXIMUM_HEADS(%si) # Divide by # heads
movb %dl, HEAD(%si) # Head to use
movw %ax, CYLINDER(%si) # Cylinder from which to read.
clc # Clear carry
ret # Return to caller
1:
stc # Set carry - LBA out of range
ret # return to caller
#
# Read a block into memory
#
# Disk Address is in %dx:%ax
# Memory Address to read into is %es:%bx
# Number of sectors to read in %cx
#
# Returns:
# Carry set on error
# Carry clear on success
readblocks:
movw %dx,(RELO_ADDR+next_sector+2) # save High order word
movw %ax,(RELO_ADDR+next_sector) # Low order word
movw %cx,(RELO_ADDR+sector_count) # Number of sectors to read
3:
call convert # Convert LBA to CHS
jc 2f # Failed. Bail.
movb %cl, %al # Number of sectors to read
movb $0x02, %ah # INT 0x13 AH=0x02 (READ SECTORS)
movw CYLINDER(%si), %dx # Get cylinder number
shlb $6, %dh # Shift left 6 bits
orb SECTOR(%si), %dh # Or in sector number
movw %dx, %cx # Copy
xchg %cl, %ch # CH=cyl lo, CL=cyl hi+sect
movb (RELO_ADDR+drive_num), %dl # Drive number
movb HEAD(%si), %dh # Head number
int $0x13 # Go do the IO
jc 1f # Branch if failure
ret
1:
testb $0xff, %al # Any sectors transferred?
jnz 9f # no, real read error
#
# This is a nasty hack. The SimNow cheetah BIOS returns 00 in AL
# even when it reads an entire track. This hack breaks if there is
# a real error!
#
movb $0x12, %al # HACK-COUGH-KLUDGE SimNow BIOS
9: movzbw %al, %dx # Setup for multiply
shlw $9, %dx # Multiply by 512
addw %dx, %bx # Bump start address by # read
movzbl %al, %edx # zero extend number sectors read
subw %dx, (RELO_ADDR+sector_count) # Decrement by # sectors read
addl %edx, (RELO_ADDR+next_sector) # Increment next sector address
movw (RELO_ADDR+next_sector+2), %dx # reload high-order word
movw (RELO_ADDR+next_sector), %ax # reload low-order word
movw (RELO_ADDR+sector_count), %cx # reload count of sectors to fetch
jmp 3b # and read the rest.
2:
stc # Indicate error
ret # and return.
geometry_error:
read_error:
movw $(RELO_ADDR+readerr), %si
#
# Print a message
#
# Message is in %si
# **THIS FUNCTION DOES NOT RETURN! **
#
printmsg:
lodsb
cmpb $0x00, %al # Terminate on zero byte
jz halt
pushw %si # Save
movw $0x7, %bx # Video Attribute
movb $0xe, %ah # Write TTY
int $0x10 # write byte to screen
popw %si # Restore
jmp printmsg # loop
halt:
jmp halt
errorloading:
.string "Error Loading OS"
missingos:
.string "Missing OS"
readerr:
.string "Read error"
geometry_info: # Geometry information
sectors: # Sectors per track
.long 0
heads: # Number of heads
.long 0
cylinders: # Number of cylinders
.word 0
sector_start: # Starting Sector #
.byte 0
head_start: # Starting Head #
.byte 0
cylinder_start: # Starting Cylinder #
.word 0
next_sector: # Next linear block number to read
.long 0
sector_count: # Count of sectors to read
.word 0
drive_num: # The drive number the BIOS loaded us from.
.byte 0
.org 497
#
# This byte is written by the boot/build.c program to contain
# the number of sectors in the secondary boot code.
#
s2sectors:
.byte 4 # Number of sectors of setup code
.word 0 # Root Flags
#
# This word is written by built/build.c to contain the number of
# bytes of system code divided by 16.
#
syssize:
.word 0 # System Size
.word 0 # Swap device
.word 0 # RAM size
.word 0 # SVGA mode
.word 0 # ROOT device
.word 0xAA55 # Boot sector signature.