bootblock.s
Skip to line: 2025 - 2050 - 2075 - 2100 - 2125 - 2150 - 2175 - 2206


Highlighted entries were made in the last day
Select a different time increment to highlight entries
Current GMT time: Jul 23 2008 21:46:02

If you have a comment for bootblock.s, please click here.
Name: John V. ShahidEmail:  jvictor@myrealbox.comDate: Feb 18 2006 04:48:31 GMT
Subject:  second sector is missing
Reponse: i looked in both masterboot.s and bootblock.s and i couldn't find the code the loads the second sector in the boot block where 1block = 2sectors = 1024bytes, if the masterboot loads the first sector at offset 0x07c0, and the bootblock makes no effort to read its second sector how we can proceed through reading the addresses of the boot monitor which for me doesn't exist yet in memory??????
Name: sushil MayengbamEmail:  memsana.sushil@gmail.comDate: Jul 22 2008 19:25:53 GMT
Subject: Re: second sector is missing
Reponse: The second sector is not actually missing but it's actually loading properly by this code in an unusual manner(which seems to miss it!). If you see the first _comment_paragraph, it's saying that the sector_number (relative to the partition; not an absolute sector_number) and the count (no of sectors to be read) is patched into this code(by installboot) at #LOADOFF+addresses. And the line number 2117:2118 is actually reading those parameters (count(8 bit), _relative_sector_no(24 bit). So, the secondary boot code is located at:
x + _relative_sector_no, where x is the absolute sector no of the first sector of the partition. And this actually read at line:2141 !!!
 
 Continue discussion.
 
 
Name: christosEmail:  Date: Sep 25 2005 07:06:54 GMT
Subject:  line 2087
Reponse: line 2087 is in the wrong place
 
Respond to christos's comment.
 
 
Name: RayWillEmail:  Date: Apr 08 2005 09:22:26 GMT
Subject:  Good,I am looking forward this site for a long tim
Reponse: Thank you ,web master.
Good Site!

www.websamba.com/thehust is my site.
 
Respond to RayWill's comment.
 
 
Name: roylarsEmail:  roylars@yahoo.comDate: Mar 11 2004 12:59:24 GMT
Subject:  recocer bios bootblock
Reponse: I recently bought a board at a computer show. It was sold "AS IS". Anyway it won't boot. I had a heck of a time finding who the manufacurer is, but I found it to be yours, with a little bit of looking. I was wondering what are the tell tale signs of a bad bios? The board I have will not boot, and does not give any beep codes. I'll try gounding the prongs of the battery holder to the case, but I'm sure it won't work. Please, you guys know your boars, unless something else went horribly wrong like a magnite was passed over the board, does it sound like a incorrectly flashed BIOS? Give me any suggestions and feel free to ask me any question to help get to the bottom of this.

Thank you for your time. Roy

Name: DURMUSEmail:  demir_pence@hotmail.comDate: Apr 03 2004 23:43:31 GMT
Subject: Re: recocer bios bootblock
Reponse: B U / S A N A / G I R E ======D
sub Add something below DURMUS's comment...
Name: itaEmail:  Date: Jun 09 2005 15:56:29 GMT
Subject: Re: recocer bios bootblock
Reponse: e3
Add something below ita's comment...
Name: jawadraoEmail:  devil_of_net1Date: Mar 27 2005 21:58:25 GMT
Subject: Re: recocer bios bootblock
Reponse: hi.i want yahoo boot .can u send me in a my mail account .i need veyr much plz plz plz send me in my mail account .ok bye &tc
 
 Continue discussion.
 
 
2000   !       Bootblock 1.4 - Minix boot block.               Author: Kees J. Bot
2001   !                                                               21 Dec 1991
2002   !
2003   ! When the PC is powered on, it will try to read the first sector of floppy
2004   ! disk 0 at address 0x7C00.  If this fails due to the absence of flexible
2005   ! magnetic media, it will read the master boot record from the first sector
2006   ! of the hard disk.  This sector not only contains executable code, but also
2007   ! the partition table of the hard disk.  When executed, it will select the
2008   ! active partition and load the first sector of that at address 0x7C00.
2009   ! This file contains the code that is eventually read from either the floppy
2010   ! disk, or the hard disk partition.  It is just smart enough to load the
2011   ! secondary boot code from the boot device into memory at address 0x10000 and
2012   ! execute that.  The disk addresses for this secondary boot code are patched
2013   ! into this code by installboot as 24-bit sector numbers and 8-bit sector
2014   ! counts above enddata upwards.  The secondary boot code is in turn smart
2015   ! enough to load the different parts of the Minix kernel into memory and
2016   ! execute them to finally get Minix started.
Expand/Collapse Item2017   !
It's also important to know that dl contains the drive that was booted (in other words, the drive from which this code originated).  This is 0x00 or 0x01 for the first or second floppy drives or 0x80, 0x81, 0x82, or 0x83 for the first through fourth hard drives.

If this code originated from a hard drive and the master boot code loaded this code, then the partition table entry that corresponds to the booted partition is passed in es:si.

2018
2019           LOADOFF    =    0x7C00  ! 0x0000:LOADOFF is where this code is loaded
2020           BOOTSEG    =    0x1000  ! Secondary boot code segment.
2021           BOOTOFF    =    0x0030  ! Offset into secondary boot above header
Expand/Collapse Item2022           BUFFER     =    0x0600  ! First free memory
Expand/Collapse Item2023            LOWSEC     =         8  ! Offset of logical first sector in partition
2024                                   ! table
2025
Expand/Collapse Item2026  ! Variables addressed using bp register
Expand/Collapse Item2027            device     =         0  ! The boot device
Expand/Collapse Item2028            lowsec     =         2  ! Offset of boot partition within drive
Expand/Collapse Item2029            secpcyl    =         6  ! Sectors per cylinder = heads * sectors
This is fairly common practice in assembler.  Several values are pushed on the stack (lines 2043, 2044, and 2046) and then the stack pointer, sp , is saved in bp (mov bp, sp - line 2047).  If 2 byte values are pushed on the stack, then the last 2 bytes are accessed by 0(bp) , the next-to-last 2 bytes are accessed by 2(bp) , and so on (see line 2095).

While these 3 variables take up 8 bytes, only 6 bytes are pushed onto the stack.  lowsec (lines 2043 and 2044) and device (line 2046) are pushed, but what about secpcyl ?  When a value is finally stored in secpcyl (line 2110), the first 2 bytes of the bootblock code are overwritten - the first xor ax, ax instruction (line 2036) is overwritten.  This doesn't matter since the code never jumps back to the beginning.  This saves not only the 2 bytes needed for the variable but also the memory required for a push instruction.

2030
2031   .text
2032
2033   ! Start boot procedure.
2034
2035   boot:
Expand/Collapse Item2036            xor     ax, ax          ! ax = 0x0000, the vector segment
Expand/Collapse Item2037            mov     ds, ax
The first instruction zeroes the ax register (any number xor'ed with itself is zero).  This is a pretty common practice.  The instruction

mov ax, #0

is slower and is 3 bytes compared with xor's 2 bytes.

One thing that initially confuses people with assembler is the order of the operands.  The syntax of the mov instruction is:

mov destination, source

This seems a little strange to me but most assemblers use this syntax.

Expand/Collapse Item2038            cli                     ! Ignore interrupts while setting stack
Expand/Collapse Item2039            mov     ss, ax          ! ss = ds = vector segment
Expand/Collapse Item2040            mov     sp, #LOADOFF    ! Usual place for a bootstrap stack
Expand/Collapse Item2041            sti
Whenever a value is moved to the stack register (ss) or the stack pointer (sp), the interrupts must be disabled first.  The stack holds the address to which an interrupt returns after its completion.  If the ss and sp registers are in flux and an interrupt occurs, it's impossible to predict where the code will return.

The interrupts are disabled with the cli (clear interrupts) instruction and reenabled with the sti (set interrupts) instruction.

What's the pound (#) sign all about?  The pound sign indicates that the value of LOADOFF (0x7C00 - see line 2019) is moved to the register rather than the contents of the memory location LOADOFF.

2042
2043           push    ax
2044           push    ax              ! Push a zero lowsec(bp)
2045
2046           push    dx              ! Boot device in dl will be device(bp)
Expand/Collapse Item2047           mov     bp, sp          ! Using var(bp) is one byte cheaper then var.
This is a little technical, but I believe the idea is that an immediate instruction is one byte larger than a special address mode instruction (ss:disp[bp]).  For example, the instruction on line 2095 is one byte smaller than it would have been if 2 bytes had been set aside (using .data2) for lowsec and the mov es, LOADOFF+lowsec instruction were used.  Since the bootblock code and sector addresses (see lines 2204-2206) must fit in a single block (1 block = 2 sectors = 2 * 512 bytes = 1024 bytes), space needs to be conserved.  Since a stack doesn't take up any hard drive space, hard drive space is saved by not allocating space within the code (using .data1 or .data2).
2048
2049           push    es
2050           push    si              ! es:si = partition table entry if hard disk
2051
Expand/Collapse Item2052            mov     di, #LOADOFF+sectors    ! char *di = sectors;
di now points to sectors (line 2200).
2053
Expand/Collapse Item2054            testb   dl, dl          ! Winchester disks if dl >= 0x80
Expand/Collapse Item2055            jge     floppy
testb sets the sign flag if the value in dl is negative.  If dl is not negative, jge jumps to floppy.  When is the value negative?  In two's complement notation, if the rightmost bit is a 1 then the value is negative.  So for a one byte value, anything greater than 0x7F (=0111111) is negative.  Remember that 0x00 and 0x01 correspond to the first and second floppy drives and 0x80, 0x81, 0x82, and 0x83 correspond to hard drives 1-4.
2056
2057   winchester:
2058
2059   ! Get the offset of the first sector of the boot partition from the partition
2060   ! table.  The table is found at es:si, the lowsec parameter at offset LOWSEC.
2061
Expand/Collapse Item2062            eseg
Expand/Collapse Item2063            les     ax, LOWSEC(si)    ! es:ax = LOWSEC+2(si):LOWSEC(si)
Expand/Collapse Item2064            mov     lowsec+0(bp), ax  ! Low 16 bits of partition's first sector
Expand/Collapse Item2065            mov     lowsec+2(bp), es  ! High 16 bits of partition's first sector

An instruction prepended by
eseg uses es (instead of ds) as the segment register.

The les instruction loads the register specified by the first operand (in this case ax) with an offset address and es with a segment register.  The value at es:LOWSEC(si) is loaded in ax and the value at es:LOWSEC+2(si) is loaded in es.  The eseg prefix is needed since es:LOWSEC(si), not ds:LOWSEC(si),  is the memory address that holds the lowest sector (see comment for line 2017). Note that the es and ax registers are overwritten by the eseg les ax, LOWSEC(si) instruction. For this reason, the es and ax registers were pushed onto the stack on lines 2049-2050.

2066
2067   ! Get the drive parameters, the number of sectors is bluntly written into the
2068   ! floppy disk sectors/track array.
2069
2070           movb    ah, #0x08       ! Code for drive parameters
Expand/Collapse Item2071            int     0x13            ! dl still contains drive
int 0x13, ah=0x08 returns the device geometry of the drive specified by dldl will be 0x80 for the first drive, 0x81 for the second, 0x82 for the third and 0x83 for the fourth. int 0x13, ah=0x08 returns the maximum sector number in bits 0-6 of cl and the maximum head number in dh.  Adding to the confusion, the value that int 0x13, ah=0x08 returns for the maximum head number has a 0-origin.  This means that if int 0x13, ah=0x08 returns a 15 for the maximum head number, there are actually 16 heads; dh is incremented on line 2074 to move to a 1-origin.
2072           andb    cl, #0x3F       ! cl = max sector number (1-origin)
2073           movb    (di), cl        ! Number of sectors per track
2074           incb    dh              ! dh = 1 + max head number (0-origin)
2075           jmp     loadboot
2076
Expand/Collapse Item2077    ! Floppy:
Expand/Collapse Item2078    ! Execute three read tests to determine the drive type.  Test for each floppy
Expand/Collapse Item2079    ! type by reading the last sector on the first track.  If it fails, try a type
Expand/Collapse Item2080    ! that has less sectors.  Therefore we start with 1.44M (18 sectors) then 1.2M
Expand/Collapse Item2081    ! (15 sectors) ending with 720K/360K (both 9 sectors).
An attempt to read the 18th sector on the first track of the floppy is first made.  If that attempt fails, the drive specified by dl (either 0x00 or 0x01) is not a functioning 1.44M floppy drive.  An attempt to read the 15th sector on the first track is next made.  If that fails, the drive specified by dl is not a functioning 1.2M floppy drive.  An attempt to read the 9th sector is the final attempt (for 720K/360K floppy drives).
2082
Expand/Collapse Item2083    next:   inc     di              ! Next number of sectors per track
di points to sectors (see lines 2052 and 2200).
2084
Expand/Collapse Item2085    floppy: xorb    ah, ah          ! Reset drive
int 0x13, ah=0x00 resets the drive specified by dl.
2086           int     0x13 2087
2088           movb    cl, (di)        ! cl = number of last sector on track
2089
2090           cmpb    cl, #9          ! No need to do the last 720K/360K test
2091           je      success
2092
2093   ! Try to read the last sector on track 0
2094
2095           mov     es, lowsec(bp)  ! es = vector segment (lowsec = 0)
Expand/Collapse Item2096            mov     bx, #BUFFER     ! es:bx buffer = 0x0000:0x0600
The memory region beginning at address BUFFER is not being used for anything now, so this region can be used as scratch area and hard drive sectors can be copied there to test out the floppy drives.
2097           mov     ax, #0x0201     ! Read sector, #sectors = 1
2098           xorb    ch, ch          ! Track 0, last sector
2099           xorb    dh, dh          ! Drive dl, head 0
Expand/Collapse Item2100            int     0x13
int 0x13, ah=0x02 copies sectors from a hard drive or floppy to memory.  al specifies the number of sectors to copy, bits 0-5 of cl specify the sector number, dh specifies the head number and ch specifies the low 8 bits of the cylinder number and bits 6-7 of cl specify the high bits of the cylinder number.  es:bx specifies where in memory to load the sectors.  If the int 0x13, ah=0x02 call fails, the carry (C) flag is set.  If the carry flag is set, the jc instruction (line 2101) jumps to memory address next (line 2083).
2101           jc      next            ! Error, try the next floppy type
2102
Expand/Collapse Item2103    success:movb    dh, #2          ! Load number of heads for multiply
A floppy is a single disk with 2 heads, one for each side.
2104
Expand/Collapse Item2105    loadboot:
Lines 2105-2153 are the heart of bootblock.  The sectors listed at memory address addresses (line 2204) are loaded; these sectors make up the secondary boot.  The sector numbers were patched at addresses by the installboot utility program.

Grinding through this code isn't fun.  Everything until line 2141 sets things up for the int 0x13 bios call.

2106   ! Load the secondary boot code from the boot device
2107
2108           movb    al, (di)        ! al = (di) = sectors per track
Expand/Collapse Item2109            mulb    dh              ! dh = heads, ax = heads * sectors
mulb multiplies al by the operand (in this case dh).  The result is placed in ax.
2110           mov     secpcyl(bp), ax ! Sectors per cylinder = heads * sectors
2111
2112           mov     ax, #BOOTSEG    ! Segment to load secondary boot code into
2113           mov     es, ax
2114           xor     bx, bx          ! Load first sector at es:bx = BOOTSEG:0x0000
2115           mov     si, #LOADOFF+addresses  ! Start of the boot code addresses
2116   load:
Expand/Collapse Item2117            mov     ax, 1(si)       ! Get next sector number: low 16 bits
Expand/Collapse Item2118            movb    dl, 3(si)       ! Bits 16-23 for your 8GB disk
Expand/Collapse Item2119            xorb    dh, dh          ! dx:ax = sector within partition
The installboot utility patches in 2 values for each 4 byte entry at addresses.  It uses the 1st byte of the entry for the count and the 2nd, 3rd and 4th bytes of the entry for the sector number (actually, it's the offset of the sector within the partition - see comments for 2120-2121).  The best way to describe the count is with an example.  If the secondary boot code is found at sectors 500, 501, 502, 509, and 510, there would be two entries at addresses - the first entry would be count=3, sector number=500 and the second entry would be count=2, sector number=509.
Expand/Collapse Item2120            add     ax, lowsec+0(bp)
Expand/Collapse Item2121            adc     dx, lowsec+2(bp)! dx:ax = sector within drive
The value patched at addresses is the offset of the sector within the partition, not the absolute sector number.  The int 0x13, ah=0x02 bios call needs the absolute sector number so lowsec is added to the offset (lowsec is the first sector of the partition).
2122           div     secpcyl(bp)     ! ax = cylinder, dx = sector within cylinder
2123           xchg    ax, dx          ! ax = sector within cylinder, dx = cylinder
2124           movb    ch, dl          ! ch = low 8 bits of cylinder
Expand/Collapse Item2125            divb    (di)            ! al = head, ah = sector (0-origin)
The divb instruction divides ax by the operand (in our example (di) - di points to the memory address that holds the number of sectors per track) and puts the quotient into al and the remainder into ah.
2126           xorb    dl, dl          ! About to shift bits 8-9 of cylinder into dl
2127           shr     dx, #1
2128           shr     dx, #1          ! dl[6..7] = high cylinder
2129           orb     dl, ah          ! dl[0..5] = sector (0-origin)
2130           movb    cl, dl          ! cl[0..5] = sector, cl[6..7] = high cyl
2131           incb    cl              ! cl[0..5] = sector (1-origin)
2132           movb    dh, al          ! dh = al = head
2133           movb    dl, device(bp)  ! dl = device to read
Expand/Collapse Item2134            movb    al, (di)        ! Sectors per track - Sector number (0-origin)
Expand/Collapse Item2135            subb    al, ah          ! = Sectors left on this track
Expand/Collapse Item2136            cmpb    al, (si)        ! Compare with # sectors to read
Expand/Collapse Item2137            jbe     read            ! Can't read past the end of a cylinder?
Expand/Collapse Item2138            movb    al, (si)        ! (si) < sectors left on this track
The int 0x13, ah=0x02 bios call can only read sectors from a single track at a time.  Lines 2134-2138 calculate the maximum numbers of sectors that can be read without crossing a track boundary.

cmp is a subtraction that only affects the flag register. jbe (line 2137) jumps if the first operand in cmp is below or equal to the second operand.

2139   read:   push    ax              ! Save al = sectors to read
2140           movb    ah, #2          ! Code for disk read (all registers in use now!)
Expand/Collapse Item2141            int     0x13            ! Call the BIOS for a read
int 0x13, ah=0x02 copies sectors from a hard drive or floppy to memory.  al specifies the number of sectors to copy, bits 0-5 of cl specify the sector number, dh specifies the head number and ch specifies the low 8 bits of the cylinder number and bits 6-7 of cl specify the high bits of the cylinder number.  es:bx specifies the memory address where the sectors are loaded.  If the int 0x13, ah=0x02 call fails, the carry (C) flag is set and an error code is placed in ah.  If the carry flag is set, the jc instruction jumps to memory address error (line 2170).
2142           pop     cx              ! Restore al in cl
2143           jc      error           ! Jump on disk read error
2144           movb    al, cl          ! Restore al = sectors read
Expand/Collapse Item2145            addb    bh, al          ! bx += 2 * al * 256 (add bytes read)
Expand/Collapse Item2146            addb    bh, al          ! es:bx = where next sector must be read
int 0x13, ah=0x02 writes the sectors to es:bx.

What's done here is somewhat tricky.  If 1 is added to bh, it is equivalent to adding 256 to bx.  If 2 is added to bh, it is equivalent to adding 512 to bx (remember that 1 sector = 512 bytes).

Expand/Collapse Item2147            add     1(si), ax       ! Update address by sectors read
Expand/Collapse Item2148            adcb    3(si), ah       ! Don't forget bits 16-23 (add ah = 0)
Expand/Collapse Item2149            subb    (si), al        ! Decrement sector count by sectors read
Lines 2147-2149 modify the count and sector number in case the consecutive sectors crossed a track boundary and all the sectors could not be read.
2150           jnz     load            ! Not all sectors have been read
Expand/Collapse Item2151            add     si, #4          ! Next (address, count) pair
si points to the current entry.  To move to the next entry, 4 is added to si (each entry is 4 bytes).
2152           cmpb    ah, (si)        ! Done when no sectors to read
2153           jnz     load            ! Read next chunk of secondary boot code
2154
Expand/Collapse Item2155    done:
When the entire secondary boot has been loaded, the code falls through to done .