| ; ----------------------------------------------------------------------- |
| ; |
| ; Copyright 2003-2008 H. Peter Anvin - All Rights Reserved |
| ; |
| ; Permission is hereby granted, free of charge, to any person |
| ; obtaining a copy of this software and associated documentation |
| ; files (the "Software"), to deal in the Software without |
| ; restriction, including without limitation the rights to use, |
| ; copy, modify, merge, publish, distribute, sublicense, and/or |
| ; sell copies of the Software, and to permit persons to whom |
| ; the Software is furnished to do so, subject to the following |
| ; conditions: |
| ; |
| ; The above copyright notice and this permission notice shall |
| ; be included in all copies or substantial portions of the Software. |
| ; |
| ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| ; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
| ; OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| ; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| ; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| ; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| ; OTHER DEALINGS IN THE SOFTWARE. |
| ; |
| ; ----------------------------------------------------------------------- |
| |
| ; |
| ; mbr.asm |
| ; |
| ; Simple Master Boot Record, including support for EBIOS extensions. |
| ; |
| ; The MBR lives in front of the boot sector, and is responsible for |
| ; loading the boot sector of the active partition. The EBIOS support |
| ; is needed if the active partition starts beyond cylinder 1024. |
| ; |
| ; This MBR determines all geometry info at runtime. It uses only the |
| ; linear block field in the partition table. It does, however, pass |
| ; the partition table information unchanged to the target OS. |
| ; |
| ; This MBR should be "8086-clean", i.e. not require a 386. |
| ; |
| |
| %include "bios.inc" |
| |
| ; |
| ; Note: The MBR is actually loaded at 0:7C00h, but we quickly move it down to |
| ; 0600h. |
| ; |
| section .text |
| cpu 8086 |
| org 0600h |
| |
| _start: cli |
| xor ax,ax |
| mov ds,ax |
| mov es,ax |
| mov ss,ax |
| mov sp,7C00h |
| sti |
| cld |
| mov si,sp ; Start address |
| mov di,0600h ; Destination address |
| mov cx,512/2 |
| rep movsw |
| |
| ; |
| ; Now, jump to the copy at 0600h so we can load the boot sector at 7C00h. |
| ; Since some BIOSes seem to think 0000:7C00h and 07C0:0000h are the same |
| ; thing, use a far jump to canonicalize the address. This also makes |
| ; sure that it is a code speculation barrier. |
| ; |
| |
| jmp 0:next ; Jump to copy at 0600h |
| |
| next: |
| mov [DriveNo], dl ; Drive number stored in DL |
| ; |
| ; Check for CHS parameters. This doesn't work on floppy disks, |
| ; but for an MBR we don't care. |
| ; |
| mov ah,08h ; Get drive parameters |
| int 13h |
| and cx,3Fh ; Max sector number |
| mov [Sectors],cx |
| xor ax,ax |
| mov al,dh |
| inc ax ; From 0-based to count |
| mul cx ; Heads*Sectors |
| mov [SecPerCyl],ax |
| ; Note: we actually don't care about the number of |
| ; cylinders, since that's the highest-order division |
| |
| ; |
| ; Now look for one (and only one) active partition. |
| ; |
| mov si,PartitionTable |
| xor ax,ax |
| mov cx,4 |
| checkpartloop: |
| test byte [si],80h |
| jz .notactive |
| inc ax |
| mov di,si |
| .notactive: add si,byte 16 |
| loop checkpartloop |
| |
| cmp ax,byte 1 ; Better be only one |
| jnz not_one_partition |
| |
| ; |
| ; Now we have the active partition partition information in DS:DI. |
| ; Check to see if we support EBIOS. |
| ; |
| mov dl,[DriveNo] |
| mov ax,4100h |
| mov bx,055AAh |
| xor cx,cx |
| xor dh,dh |
| stc |
| int 13h |
| jc no_ebios |
| cmp bx,0AA55h |
| jne no_ebios |
| test cl,1 ; LBA device access |
| jz no_ebios |
| ; |
| ; We have EBIOS. Load the boot sector using LBA. |
| ; |
| push di |
| mov si,dapa |
| mov bx,[di+8] ; Copy the block address |
| mov [si+8],bx |
| mov bx,[di+10] |
| mov [si+10],bx |
| mov dl,[DriveNo] |
| mov ah,42h ; Extended Read |
| jmp short common_tail |
| ; |
| ; No EBIOS. Load the boot sector using CHS. |
| ; |
| no_ebios: |
| push di |
| mov ax,[di+8] |
| mov dx,[di+10] |
| div word [SecPerCyl] ; AX = cylinder DX = sec in cyl |
| ror ah,1 |
| ror ah,1 |
| mov cl,ah |
| mov ch,al ; CL = cyl[9:8], CH = cyl[7:0] |
| |
| mov ax,dx |
| div byte [Sectors] ; AL = head AH = sector |
| mov dh,al |
| inc ah |
| or cl,ah ; CX = cylinder and sector |
| |
| mov dl,[DriveNo] |
| mov bx,7C00h |
| mov ax,0201h ; Read one sector |
| common_tail: |
| int 13h |
| jc disk_error |
| pop si ; DS:SI -> partition table entry |
| ; |
| ; Verify that we have a boot sector, jump |
| ; |
| cmp word [7C00h+510],0AA55h |
| jne missing_os |
| cli |
| jmp 0:7C00h ; Jump to boot sector; far |
| ; jump is speculation barrier |
| ; (Probably not neecessary, but |
| ; there is plenty of space.) |
| |
| not_one_partition: |
| ja too_many_os |
| missing_os: |
| mov si,missing_os_msg |
| jmp short die |
| too_many_os: |
| disk_error: |
| mov si,bad_disk_msg |
| die: |
| .msgloop: |
| lodsb |
| and al,al |
| jz .now |
| mov ah,0Eh ; TTY output |
| mov bh,[BIOS_page] ; Current page |
| mov bl,07h |
| int 10h |
| jmp short .msgloop |
| .now: |
| jmp short .now |
| |
| align 4, db 0 ; Begin data area |
| |
| ; |
| ; EBIOS disk address packet |
| ; |
| dapa: |
| dw 16 ; Packet size |
| .count: dw 1 ; Block count |
| .off: dw 7C00h ; Offset of buffer |
| .seg: dw 0 ; Segment of buffer |
| .lba: dd 0 ; LBA (LSW) |
| dd 0 ; LBA (MSW) |
| |
| ; CHS information |
| SecPerCyl: dw 0 ; Heads*Sectors |
| Sectors: dw 0 |
| |
| ; Error messages |
| missing_os_msg db 'Missing operating system', 13, 10, 0 |
| bad_disk_msg db 'Operating system loading error', 13, 10, 0 |
| |
| ; |
| ; Maximum MBR size: 446 bytes; end-of-boot-sector signature also needed. |
| ; Note that some operating systems (NT, DR-DOS) put additional stuff at |
| ; the end of the MBR, so shorter is better. Location 440 is known to |
| ; have a 4-byte attempt-at-unique-ID for some OSes. |
| ; |
| |
| PartitionTable equ $$+446 ; Start of partition table |
| |
| ; |
| ; BSS data; put at 800h |
| ; |
| DriveNo equ 0800h |