530 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			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"
 |