Files
exectos/boot/bootsect/espboot.S
Aiken Harris 52afd31e77
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in 41s
Builds / ExectOS (amd64, debug) (push) Successful in 38s
Builds / ExectOS (i686, release) (push) Successful in 37s
Builds / ExectOS (i686, debug) (push) Successful in 36s
Implement Stage2 loading in VBR code
2025-10-17 20:44:57 +02:00

530 lines
10 KiB
ArmAsm

/**
* PROJECT: ExectOS
* COPYRIGHT: See COPYING.md in the top level directory
* FILE: boot/bootsect/espboot.S
* DESCRIPTION: XT Boot Loader ESP boot code (FAT32)
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
*/
.text
.code16
.global Start
Start:
/* Jump to the real start to omit the BPB (BIOS Parameter Block) */
jmp RealStart
nop
/* BIOS Parameter Block */
OsName:
.ascii "XTOS "
OsVersion:
.ascii "1.0"
BytesPerSector:
.word 512
SectorsPerCluster:
.byte 2
ReservedSectors:
.word 8
FatCopies:
.byte 1
RootDirEntries:
.word 1024
TotalSectors:
.word 0
MediaType:
.byte 0xF8
SectorsPerFat:
.word 0
SectorsPerTrack:
.word 17
NumberOfHeads:
.word 0
HiddenSectors:
.long 0
TotalBigSectors:
.long 0x200000
BigSectorsPerFat:
.long 0x1FE0
ExtendedFlags:
.word 0
FsVersion:
.word 0
RootDirStartCluster:
.long 0
FSInfoSector:
.word 0
BackupBootSector:
.word 6
Reserved:
.fill 12, 1, 0
DriveNumber:
.byte 0x80
CurrentHead:
.byte 0
Signature:
.byte 0x29
SerialNumber:
.long 0
VolumeLabel:
.ascii "NO NAME "
FileSystem:
.ascii "FAT32 "
RealStart:
/* Set segments and stack */
cli
cld
xorw %ax, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw $0x7C00, %bp
leaw -16(%bp), %sp
sti
/* Get drive number */
cmpb $0xFF, DriveNumber - Start(%bp)
jne GetDriveParameters
movb %dl, DriveNumber - Start(%bp)
GetDriveParameters:
/* Get drive parameters from the BIOS */
movb DriveNumber - Start(%bp), %dl
movb $0x08, %ah
movb $0x00, %al
int $0x13
jnc GetDriveSize
movw $0xFFFF, %cx
movb %cl, %dh
GetDriveSize:
/* Get drive size from the BIOS */
movzbl %dh, %eax
incw %ax
movzbl %cl, %edx
andb $0x3F, %dl
mulw %dx
xchgb %cl, %ch
shrb $0x06, %ch
incw %cx
movzwl %cx, %ecx
mull %ecx
movl %eax, %edi
VerifyBiosParameterBlock:
/* Verify the FAT32 BPB */
cmpw $0x00, SectorsPerFat - Start(%bp)
jne FsError
cmpw $0x00, FsVersion - Start(%bp)
ja FsError
ReadExtraCode:
/* Read second VBR sector with extra boot code (3 sectors starting from sector 2) */
movl HiddenSectors - Start(%bp), %eax
addl $0x02, %eax
movw $0x03, %cx
xorw %bx, %bx
movw %bx, %es
movw $0x7E00, %bx
call ReadSectors
jmp StartExtraCode
ReadSectors:
/* Check for extended BIOS functions and use it only if available */
pushw %es
pushal
movb $0x41, %ah
movw $0x55AA, %bx
movb DriveNumber - Start(%bp), %dl
int $0x13
jc .ReadCHS
cmpw $0xAA55, %bx
jne .ReadCHS
testb $0x01, %cl
jz .ReadCHS
/* Verify drive size and determine whether to use CHS or LBA */
cmpl %edi, %eax
jnb .ReadLBA
.ReadCHS:
/* Read sectors using CHS */
popal
.CHSLoop:
/* Read sector by sector using CHS */
pushw %cx
pushal
xorl %edx, %edx
movzwl SectorsPerTrack - Start(%bp), %ecx
divl %ecx
incb %dl
movb %dl, %cl
movl %eax, %edx
shrl $0x10, %edx
divw NumberOfHeads - Start(%bp)
movb %dl, %dh
movb DriveNumber - Start(%bp), %dl
movb %al, %ch
rorb $0x01, %ah
rorb $0x01, %ah
orb %ah, %cl
movw $0x0201, %ax
int $0x13
popal
popw %cx
jc DiskError
incl %eax
movw %es, %dx
addw $0x20, %dx
movw %dx, %es
loop .CHSLoop
popw %es
ret
.ReadLBA:
/* Prepare DAP packet and read sectors using LBA */
popal
pushw %cx
pushal
pushw $0x00
pushw $0x00
pushl %eax
pushw %es
pushw %bx
pushw %cx
pushw $0x10
movw %sp, %si
movb DriveNumber - Start(%bp), %dl
movb $0x42, %ah
int $0x13
jc DiskError
addw $0x10, %sp
popal
popw %si
pushw %bx
movzwl %si, %ebx
addl %ebx, %eax
shll $0x05, %ebx
movw %es, %dx
addw %bx, %dx
movw %dx, %es
popw %bx
subw %si, %cx
jnz .ReadLBA
popw %es
ret
DiskError:
/* Display disk error message and reboot */
movw $.MsgDiskError, %si
call Print
jmp Reboot
FsError:
/* Display FS error message and reboot */
movw $.MsgFsError, %si
call Print
jmp Reboot
Print:
/* Simple routine to print messages */
lodsb
orb %al, %al
jz .DonePrint
movb $0x0E, %ah
movw $0x07, %bx
int $0x10
jmp Print
.DonePrint:
retw
Reboot:
/* Display a message, wait for a key press and reboot */
movw $.MsgAnyKey, %si
call Print
xorw %ax, %ax
int $0x16
int $0x19
.MsgAnyKey:
.ascii "Press any key to restart...\r\n\0"
.MsgDiskError:
.ascii "Disk error!\r\n\0"
.MsgFsError:
.ascii "File system error!\r\n\0"
/* Fill the rest of the VBR with zeros and add VBR signature at the end */
.fill (510 - (. - Start)), 1, 0
.word 0xAA55
StartExtraCode:
/* Load XTLDR file from disk */
call LoadStage2
/* Enable A20 gate */
call EnableA20
/* Call architecture specific initialization code */
call InitializeCpu
/* Jump to Stage2 */
call RunStage2
Clear8042:
/* Clear 8042 PS/2 buffer */
nop
nop
nop
nop
inb $0x64, %al
cmpb $0xff, %al
je .Clear8042_Done
testb $0x02, %al
jnz Clear8042
.Clear8042_Done:
ret
EnableA20:
/* Enable A20 gate */
pushaw
call Clear8042
movb $0xD1, %al
outb %al, $0x64
call Clear8042
movb $0xDF, %al
outb %al, $0x60
call Clear8042
movb $0xFF, %al
outb %al, $0x64
call Clear8042
popaw
ret
FindFatEntry:
/* Find a file or directory in the FAT table */
pushw %bx
pushw %cx
pushw %dx
pushw %si
pushw %di
.FindFatCluster:
/* Find FAT32 cluster holding the entry */
cmp $0x0FFFFFF8, %eax
jae .FindEntryFail
pushl %eax
movw $0x0200, %bx
movw %bx, %es
call ReadCluster
popl %eax
movb SectorsPerCluster - Start(%bp), %cl
shlw $0x04, %cx
xorw %di, %di
.FindEntryLoop:
/* Find the entry */
movb %es:(%di), %al
cmpb $0x00, %al
je .FindEntryFail
cmpb $0xE5, %al
je .FindSkipEntry
movb %es:0x0B(%di), %ah
cmpb $0x0F, %ah
je .FindSkipEntry
pushw %di
pushw %si
pushw %cx
movw $0x0B, %cx
repe cmpsb
popw %cx
popw %si
popw %di
jnz .FindSkipEntry
movw %es:0x1A(%di), %ax
movw %es:0x14(%di), %dx
shll $0x10, %edx
orl %edx, %eax
clc
jmp .FindEntryDone
.FindSkipEntry:
/* Skip to the next entry */
addw $0x20, %di
decw %cx
jnz .FindEntryLoop
call GetFatEntry
jmp .FindFatCluster
.FindEntryFail:
/* Error, file/directory not found */
stc
.FindEntryDone:
/* Clean up the stack */
popw %di
popw %si
popw %dx
popw %cx
popw %bx
ret
GetFatEntry:
/* Get FAT32 sector and offset from FAT table */
shll $0x02, %eax
movl %eax, %ecx
xorl %edx, %edx
movzwl BytesPerSector - Start(%bp), %ebx
pushl %ebx
divl %ebx
movzwl ReservedSectors - Start(%bp), %ebx
addl %ebx, %eax
movl HiddenSectors - Start(%bp), %ebx
addl %ebx, %eax
popl %ebx
decl %ebx
andl %ebx, %ecx
movzwl ExtendedFlags - Start(%bp), %ebx
andw $0x0F, %bx
jz LoadFatSector
cmpb FatCopies - Start(%bp), %bl
jae FsError
pushl %eax
movl BigSectorsPerFat - Start(%bp), %eax
mull %ebx
popl %edx
addl %edx, %eax
LoadFatSector:
/* Load FAT32 sector from disk */
pushl %ecx
movw $0x9000, %bx
movw %bx, %es
cmpl %esi, %eax
je .LoadFatSectorDone
movl %eax, %esi
xorw %bx, %bx
movw $0x01, %cx
call ReadSectors
.LoadFatSectorDone:
/* Clean up the stack */
popl %ecx
movl %es:(%ecx), %eax
andl $0x0FFFFFFF, %eax
ret
LoadStage2:
/* Load Stage2 executable, first find file in the path */
movl $0xFFFFFFFF, %esi
pushl %esi
movl 0x7C2C, %eax
movw $.EfiDirName, %si
call FindFatEntry
jc Stage2NotLoaded
movw $.BootDirName, %si
call FindFatEntry
jc Stage2NotLoaded
movw $.Stage2FileName, %si
call FindFatEntry
jc Stage2NotLoaded
popl %esi
/* Load XTLDR file from disk */
cmpl $0x02, %eax
jb FileNotFound
cmpl $0x0FFFFFF8, %eax
jae FileNotFound
movw $(0xF800 / 16), %bx
movw %bx, %es
.LoadStage2Loop:
/* Load file data from disk */
pushl %eax
xorw %bx, %bx
pushw %es
call ReadCluster
popw %es
xorw %bx, %bx
movb SectorsPerCluster - Start(%bp), %bl
shlw $0x05, %bx
movw %es, %ax
addw %bx, %ax
movw %ax, %es
popl %eax
pushw %es
call GetFatEntry
popw %es
cmpl $0x0FFFFFF8, %eax
jb .LoadStage2Loop
ret
ParseExecutableHeader:
/* Parse Stage2 PE/COFF executable header */
pushw %es
movw $(0xF800 / 16), %ax
movw %ax, %es
movl %es:60, %eax
addl $(4 + 20), %eax
movl %es:16(%eax), %eax
addl $0xF800, %eax
popw %es
ret
ReadCluster:
/* Read FAT32 cluster from disk */
decl %eax
decl %eax
xorl %edx, %edx
movzbl SectorsPerCluster - Start(%bp), %ebx
mull %ebx
pushl %eax
xorl %edx, %edx
movzbl FatCopies - Start(%bp), %eax
mull BigSectorsPerFat - Start(%bp)
movzwl ReservedSectors - Start(%bp), %ebx
addl %ebx, %eax
addl HiddenSectors - Start(%bp), %eax
popl %ebx
addl %ebx, %eax
xorw %bx, %bx
movzbw SectorsPerCluster - Start(%bp), %cx
call ReadSectors
ret
/* Include architecture specific code */
.include ARCH_ESP_SOURCE
CpuUnsupported:
/* Display CPU unsupported message and reboot */
popal
movw $.MsgCpuUnsupported, %si
call Print
jmp Reboot
FileNotFound:
/* Display XTLDR not found message and reboot */
movw $.MsgXtLdrNotFound, %si
call Print
jmp Reboot
Stage2NotLoaded:
/* Clean up the stack and display XTLDR not found message and reboot */
popl %esi
jmp FileNotFound
.BootDirName:
/* Boot directory name */
.ascii "BOOT "
.EfiDirName:
/* EFI directory name */
.ascii "EFI "
.MsgCpuUnsupported:
.ascii "CPU not supported!\r\n\0"
.MsgXtLdrNotFound:
.ascii "XTLDR Stage2 not found!\r\n\0"
/* Fill the rest of the extra VBR with zeros and add signature */
.fill (2043 - (. - Start)), 1, 0
.ascii "XTLDR"