| FILE_LICENCE ( GPL2_OR_LATER ) |
| |
| #define BOOT_SEG 0x07c0 |
| #define EXEC_SEG 0x0100 |
| #define STACK_SEG 0x0200 |
| #define STACK_SIZE 0x2000 |
| |
| .text |
| .arch i386 |
| .section ".prefix", "awx", @progbits |
| .code16 |
| |
| /* |
| * Find active partition |
| * |
| * Parameters: |
| * %dl : BIOS drive number |
| * %bp : Active partition handler routine |
| */ |
| find_active_partition: |
| /* Set up stack at STACK_SEG:STACK_SIZE */ |
| movw $STACK_SEG, %ax |
| movw %ax, %ss |
| movw $STACK_SIZE, %sp |
| |
| /* Relocate self to EXEC_SEG */ |
| pushw $BOOT_SEG |
| popw %ds |
| pushw $EXEC_SEG |
| popw %es |
| xorw %si, %si |
| xorw %di, %di |
| movw $0x200, %cx |
| rep movsb |
| ljmp $EXEC_SEG, $1f |
| 1: pushw %ds |
| popw %es |
| pushw %cs |
| popw %ds |
| |
| /* Check for LBA extensions */ |
| movb $0x41, %ah |
| movw $0x55aa, %bx |
| stc |
| int $0x13 |
| jc 1f |
| cmpw $0xaa55, %bx |
| jne 1f |
| movw $read_lba, read_sectors |
| 1: |
| /* Read and process root partition table */ |
| xorb %dh, %dh |
| movw $0x0001, %cx |
| xorl %esi, %esi |
| xorl %edi, %edi |
| call process_table |
| |
| /* Print failure message */ |
| movw $10f, %si |
| jmp boot_error |
| 10: .asciz "Could not locate active partition\r\n" |
| |
| /* |
| * Print failure message and boot next device |
| * |
| * Parameters: |
| * %si : Failure string |
| */ |
| boot_error: |
| cld |
| movw $0x0007, %bx |
| movb $0x0e, %ah |
| 1: lodsb |
| testb %al, %al |
| je 99f |
| int $0x10 |
| jmp 1b |
| 99: /* Boot next device */ |
| int $0x18 |
| |
| /* |
| * Process partition table |
| * |
| * Parameters: |
| * %dl : BIOS drive number |
| * %dh : Head |
| * %cl : Sector (bits 0-5), high two bits of cylinder (bits 6-7) |
| * %ch : Low eight bits of cylinder |
| * %esi:%edi : LBA address |
| * %bp : Active partition handler routine |
| * |
| * Returns: |
| * CF set on error |
| */ |
| process_table: |
| pushal |
| call read_boot_sector |
| jc 99f |
| movw $446, %bx |
| 1: call process_partition |
| addw $16, %bx |
| cmpw $510, %bx |
| jne 1b |
| 99: popal |
| ret |
| |
| /* |
| * Process partition |
| * |
| * Parameters: |
| * %dl : BIOS drive number |
| * %dh : Head |
| * %cl : Sector (bits 0-5), high two bits of cylinder (bits 6-7) |
| * %ch : Low eight bits of cylinder |
| * %esi:%edi : LBA address |
| * %bx : Offset within partition table |
| * %bp : Active partition handler routine |
| */ |
| process_partition: |
| pushal |
| /* Load C/H/S values from partition entry */ |
| movb %es:1(%bx), %dh |
| movw %es:2(%bx), %cx |
| /* Update LBA address from partition entry */ |
| addl %es:8(%bx), %edi |
| adcl $0, %esi |
| /* Check active flag */ |
| testb $0x80, %es:(%bx) |
| jz 1f |
| call read_boot_sector |
| jc 99f |
| jmp *%bp |
| 1: /* Check for extended partition */ |
| movb %es:4(%bx), %al |
| cmpb $0x05, %al |
| je 2f |
| cmpb $0x0f, %al |
| je 2f |
| cmpb $0x85, %al |
| jne 99f |
| 2: call process_table |
| 99: popal |
| /* Reload original partition table */ |
| call read_boot_sector |
| ret |
| |
| /* |
| * Read single sector to %es:0000 and verify 0x55aa signature |
| * |
| * Parameters: |
| * %dl : BIOS drive number |
| * %dh : Head |
| * %cl : Sector (bits 0-5), high two bits of cylinder (bits 6-7) |
| * %ch : Low eight bits of cylinder |
| * %esi:%edi : LBA address |
| * |
| * Returns: |
| * CF set on error |
| */ |
| read_boot_sector: |
| pushw %ax |
| movw $1, %ax |
| call *read_sectors |
| jc 99f |
| cmpw $0xaa55, %es:(510) |
| je 99f |
| stc |
| 99: popw %ax |
| ret |
| |
| /* |
| * Read sectors to %es:0000 |
| * |
| * Parameters: |
| * %dl : BIOS drive number |
| * %dh : Head |
| * %cl : Sector (bits 0-5), high two bits of cylinder (bits 6-7) |
| * %ch : Low eight bits of cylinder |
| * %esi:%edi : LBA address |
| * %ax : Number of sectors (max 127) |
| * |
| * Returns: |
| * CF set on error |
| */ |
| read_sectors: .word read_chs |
| |
| read_chs: |
| /* Read sectors using C/H/S address */ |
| pushal |
| xorw %bx, %bx |
| movb $0x02, %ah |
| stc |
| int $0x13 |
| sti |
| popal |
| ret |
| |
| read_lba: |
| /* Read sectors using LBA address */ |
| pushal |
| movw %ax, (lba_desc + 2) |
| pushw %es |
| popw (lba_desc + 6) |
| movl %edi, (lba_desc + 8) |
| movl %esi, (lba_desc + 12) |
| movw $lba_desc, %si |
| movb $0x42, %ah |
| int $0x13 |
| popal |
| ret |
| |
| lba_desc: |
| .byte 0x10 |
| .byte 0 |
| .word 1 |
| .word 0x0000 |
| .word 0x0000 |
| .long 0, 0 |