Compare commits

...

2 Commits

@ -159,6 +159,8 @@ GLOBL _start
rep stosb
mov %di, %sp /* %sp = 0x7800:8000 = 0x80000 */
sti /* we're safe again, i think */
/* say hello */
mov $msg_loader_info, %si
call print
@ -222,10 +224,10 @@ GLOBL _start
push %ax /* save CRC[15:0] */ /* '1 v */
xor %si, %si
mov $0x5c, %cl
call crc32
call crc32 /* %ebx = ~CRC, CF = 1 */
pop %ax /* restore CRC[15:0] */ /* '1 ^ */
test %eax, %ebx
jnz err_bad_gpt_csum
adc %eax, %ebx /* check CRC and set %ebx = 0 if equal */
jne err_bad_gpt_csum
/* store everything we need to rember from the GPT header (we assert there
* to be no more than 65535 partitions and that each entry is no more than
@ -330,58 +332,81 @@ LOCAL start2
pop %cx /* restore table size in bytes */ /* '3 ^ */
push %si /* save entry count */ /* '3 v */
xor %si, %si
call crc32
call crc32 /* %ebx = ~CRC, CF = 1 */
pop %cx /* restore entry count */ /* '3 ^ */
pop %di /* restore CRC[15:0] */ /* '2 ^ */
and %ebx, %edi /* %edi = 0 (crc32 returns the inverted value) */
adc %ebx, %edi /* %edi = 0 if checksum matches */
jnz err_bad_gpt_csum
/* search the partition table for our GUID */
/*
* Step 5: Search the GPT for stage1
*/
pop %bx /* restore entry size */ /* '1 ^ */
sub $(bussy_guid_end - bussy_guid), %bx /* entry size -= sizeof(bussy_guid) */
/* this loop uses %ax for temporarily storing `entry count` and
* `sizeof(bussy_guid)` because xchg with %ax is only one byte */
xor %si, %si
1: push %cx /* save remaining entry count */ /* '1 v */
mov $bussy_guid, %si
push %si /* save current position */ /* '2 v */
mov $bussy_guid, %di
mov $(bussy_guid_end - bussy_guid), %cx
repe cmpsb %es:(%di), %fs:(%si)
pop %si /* restore current position */ /* '2 ^ */
pop %cx /* restore remaining entry count */ /* '1 ^ */
je 2f /* found it */
add %bx, %di /* %di += entry size */
add %bx, %si /* %si += entry size */
loopne 1b /* only loop if %di didn't wrap around */
jmp err_no_stage1
/* gotcha! now load the first 64 K from the partition */
/*
* Step 6: Load stage1 to the beginning of low memory (0x0500)
*
* stage1 must not exceed 32 K because some BIOSes freak out when asked
* to load 64 K or more at once (which would cross a segment boundary).
* We take advantage of that fact by "hardcoding" the number of bytes to
* be loaded: We start with 64 K - 1 B, and divide that through the
* logical sector size. The result is a sector count that definitely
* spans at least 32 K unless we're dealing with 64 K sectors or larger,
* in which case we wouldn't have made it this far anyway.
*/
2: push %dx /* save drive number */ /* '1 v */
xor %ax, %ax
mov $1, %dl /* %dh is known to be 0x00 */
divw (drive_params + 0x18) /* %ax = 0x10000 / sector size = sector count */
or $-1, %ax
xor %dx, %dx
divw (drive_params + 0x18) /* %ax = 0x8000 / sector size = sector count */
xchg %ax, %cx /* %cx = sector count (xchg saves 1 byte) */
mov %fs:0x20(%di), %eax /* %eax = LBA[31:0] */
mov %fs:0x24(%di), %bx /* %bx = LBA[47:32] */
mov %fs:0x20(%si), %eax /* %eax = LBA[31:0] */
mov %fs:0x24(%si), %bx /* %bx = LBA[47:32] */
xor %di, %di
pop %dx /* restore drive number */ /* '1 ^ */
call read_lba
/* check the stage1 header */
lods %fs:(%di), %ax /* offset 0x00: magic number */
cmp $0xacab, %ax
/* these values are for stage1 */
push %eax /* boot partition LBA[31:0] */ /* '1 v */
push %bx /* boot partition LBA[47:32] */ /* '2 v */
push %dx /* boot drive number */ /* '3 v */
/*
* Step 7: Check stage1's magic number and CRC
*/
xor %si, %si
cmp $0xacab, %fs:(%si) /* offset 0x00: magic number */
jne err_bad_stage1_magic
lods %fs:(%di), %ax /* offset 0x02: byte count for CRC */
xchg %cx, %ax
mov %fs:0x02(%si), %cx /* offset 0x02: byte count for CRC */
xor %eax, %eax
xchg %fs:(%di), %eax /* offset 0x04: CRC (replace with 0) */
push %ax /* save CRC[15:0] (crc32 clobbers %al) */ /* '1 v */
call crc32
pop %ax /* restore CRC[15:0] */ /* '1 ^ */
and %ebx, %eax /* check CRC and clear %eax */
xchg %fs:0x04(%si), %eax /* offset 0x04: CRC (replace with 0) */
push %ax /* save CRC[15:0] (crc32 clobbers %al) */ /* '4 v */
call crc32 /* %ebx = ~CRC, CF = 1 */
pop %ax /* restore CRC[15:0] */ /* '4 ^ */
adc %ebx, %eax /* check CRC */
jnz err_bad_stage1_csum
/*
* Step 8: Jump to stage1 (finally)
*
* The three remaining items on the stack are for stage1
*/
ljmp $0x0000, $0x0508 /* entry point is right after the 8-byte header */
ljmp $0x0000, $0x0510 /* entry point is right after the 16-byte header */
END start2
/*
@ -432,11 +457,13 @@ LOCAL read_lba
END read_lba
/*
* Do a CCITT32 ANSI CRC (polynomial 0x04c11db7) of %cx bytes at %fs:%si
* and return THE COMPLEMENT (i.e. bitwise NOT of the CRC) in %ebx.
* Calculate the CCITT32 ANSI CRC (polynomial 0x04c11db7) of %cx bytes
* at %fs:%si and return THE COMPLEMENT of the result in %ebx.
* Clobbers %al, %cx, and %si. Does not check for overflows (%si + %cx
* must be <= 0x10000). If %cx is 0, the size is 64 KiB (0x10000), in
* which case %si should also be 0 because of the missing wrap check.
* This also sets CF = 1 because that allows for comparing the CRC with
* the expected value through a single `adc` instruction.
*
* Stolen from "Hacker's Delight", second edition by Henry S. Warren, Jr.
* and painstakingly ported to x86 assembly with focus on minimum size.
@ -444,10 +471,11 @@ END read_lba
* optimizations.
*
* %al: clobber
* %ebx: return value (ATTENTION: COMPLEMENT of CRC)
* %ebx: return value
* %cx: byte count (clobber)
* %si: data (clobber)
* %fs: data segment
* CF = 1
*/
LOCAL crc32
/* this is expressed as an imm8 w/ sign extension */
@ -466,6 +494,7 @@ LOCAL crc32
loop 1b
stc
ret
END crc32

Loading…
Cancel
Save