mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-28 16:14:04 +02:00
Port Intel .asm to GNU .S
These .S files now is not for compiler but for us to control the version. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@7549 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
32f9b796d3
commit
819958c65f
258
DuetPkg/BootSector/Mbr.S
Normal file
258
DuetPkg/BootSector/Mbr.S
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
#------------------------------------------------------------------------------
|
||||||
|
#*
|
||||||
|
#* Copyright 2006 - 2007, Intel Corporation
|
||||||
|
#* All rights reserved. This program and the accompanying materials
|
||||||
|
#* are licensed and made available under the terms and conditions of the BSD License
|
||||||
|
#* which accompanies this distribution. The full text of the license may be found at
|
||||||
|
#* http://opensource.org/licenses/bsd-license.php
|
||||||
|
#*
|
||||||
|
#* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||||
|
#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
|
#*
|
||||||
|
#* Mbr.asm
|
||||||
|
#*
|
||||||
|
#* Abstract:
|
||||||
|
#*
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
.equ BLOCK_SIZE, 0x0200
|
||||||
|
.equ BLOCK_MASK, 0x01ff
|
||||||
|
.equ BLOCK_SHIFT, 9
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Code loaded by BIOS at 0x0000:0x7C00
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
.org 0x0
|
||||||
|
Start:
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Start Print
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
movw $0xb800, %ax
|
||||||
|
movw %ax, %es
|
||||||
|
movw $0x7c0, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
leaw %cs:StartString, %si
|
||||||
|
movw $10, %cx
|
||||||
|
movw $160, %di
|
||||||
|
rep
|
||||||
|
movsw
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Print over
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Initialize segment registers and copy code at 0x0000:0x7c00 to 0x0000:0x0600
|
||||||
|
# ****************************************************************************
|
||||||
|
xorw %ax, %ax # AX = 0x0000
|
||||||
|
movw $0x7c00, %bx # BX = 0x7C00
|
||||||
|
movw $0x600, %bp # BP = 0x0600
|
||||||
|
movw RelocatedStart, %si # SI = Offset(RelocatedStart)
|
||||||
|
movw $0x200, %cx # CX = 0x0200
|
||||||
|
subw %si, %cx # CS = 0x0200 - Offset(RelocatedStart)
|
||||||
|
leaw (%bp,%si,), %di # DI = 0x0600 + Offset(RelocatedStart)
|
||||||
|
leaw (%bx,%si,), %si # BX = 0x7C00 + Offset(RelocatedStart)
|
||||||
|
movw %ax, %ss # SS = 0x0000
|
||||||
|
movw %bx, %sp # SP = 0x7C00
|
||||||
|
movw %ax, %es # ES = 0x0000
|
||||||
|
movw %ax, %ds # DS = 0x0000
|
||||||
|
pushw %ax # PUSH 0x0000
|
||||||
|
pushw %di # PUSH 0x0600 + Offset(RelocatedStart)
|
||||||
|
cld # Clear the direction flag
|
||||||
|
rep
|
||||||
|
movsb # Copy 0x0200 bytes from 0x7C00 to 0x0600
|
||||||
|
retl # JMP 0x0000:0x0600 + Offset(RelocatedStart)
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Code relocated to 0x0000:0x0600
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
RelocatedStart:
|
||||||
|
# ****************************************************************************
|
||||||
|
# Get Driver Parameters to 0x0000:0x7BFC
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
xorw %ax, %ax # AX = 0
|
||||||
|
movw %ax, %ss # SS = 0
|
||||||
|
addw $0x1000, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
|
||||||
|
movw $0x7c00, %sp # SP = 0x7c00
|
||||||
|
movw %sp, %bp # BP = 0x7c00
|
||||||
|
|
||||||
|
movb $8, %ah # AH = 8 - Get Drive Parameters Function
|
||||||
|
movb %dl, PhysicalDrive(%bp) # BBS defines that BIOS would pass the booting driver number to the loader through DL
|
||||||
|
int $0x13 # Get Drive Parameters
|
||||||
|
xorw %ax, %ax # AX = 0
|
||||||
|
movb %dh, %al # AL = DH
|
||||||
|
incb %al # MaxHead = AL + 1
|
||||||
|
pushw %ax # 0000:7bfe = MaxHead
|
||||||
|
movb %cl, %al # AL = CL
|
||||||
|
andb $0x3f, %al # MaxSector = AL & 0x3f
|
||||||
|
pushw %ax # 0000:7bfc = MaxSector
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Read Target DBR from hard disk to 0x0000:0x7C00
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
xorw %ax, %ax
|
||||||
|
movb MbrPartitionIndicator(%bp), %al # AX = MbrPartitionIndex
|
||||||
|
cmpb $0xff, %al # 0xFF means do legacy MBR boot
|
||||||
|
jnz EfiDbr
|
||||||
|
LegacyMbr:
|
||||||
|
movl $0x0000600, %eax # Assume LegacyMBR is backuped in Sector 6
|
||||||
|
jmp StartReadTo7C00 # EAX = Header/Sector/Tracker/Zero
|
||||||
|
|
||||||
|
EfiDbr:
|
||||||
|
cmpb $4, %al # MbrPartitionIndex should < 4
|
||||||
|
jae BadDbr
|
||||||
|
shlw $4, %ax # AX = MBREntrySize * Index
|
||||||
|
addw $0x1be, %ax # AX = MBREntryOffset
|
||||||
|
movw %ax, %di # DI = MBREntryOffset
|
||||||
|
|
||||||
|
# Here we don't use the C/H/S information provided by Partition table
|
||||||
|
# but calculate C/H/S from LBA ourselves
|
||||||
|
# Ci: Cylinder number
|
||||||
|
# Hi: Header number
|
||||||
|
# Si: Sector number
|
||||||
|
movl %es:8(%bp,%di,), %eax # Start LBA
|
||||||
|
movl %eax, %edx
|
||||||
|
shrl $16, %edx # DX:AX = Start LBA
|
||||||
|
# = Ci * (H * S) + Hi * S + (Si - 1)
|
||||||
|
|
||||||
|
# Calculate C/H/S according to LBA
|
||||||
|
movw $0x7bfa, %bp
|
||||||
|
divw 2(%bp) # AX = Hi + H*Ci
|
||||||
|
# DX = Si - 1
|
||||||
|
incw %dx # DX = Si
|
||||||
|
pushw %dx # 0000:7bfa = Si <----
|
||||||
|
xorw %dx, %dx # DX:AX = Hi + H*Ci
|
||||||
|
divw 4(%bp) # AX = Ci <----
|
||||||
|
# DX = Hi <----
|
||||||
|
|
||||||
|
StartReadTo7C00:
|
||||||
|
|
||||||
|
movb (%bp), %cl # Si
|
||||||
|
movb %al, %ch # Ci[0-7]
|
||||||
|
orb %ah, %cl # Ci[8,9]
|
||||||
|
movw $0x7c00, %bx # ES:BX = 0000:7C00h
|
||||||
|
movb $0x2, %ah # Function 02h
|
||||||
|
movb $1, %al # 1 Sector
|
||||||
|
movb %dl, %dh # Hi
|
||||||
|
movw $0x600, %bp
|
||||||
|
movb PhysicalDrive(%bp), %dl # Drive number
|
||||||
|
int $0x13
|
||||||
|
jc BadDbr
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Transfer control to BootSector - Jump to 0x0000:0x7C00
|
||||||
|
# ****************************************************************************
|
||||||
|
xorw %ax, %ax
|
||||||
|
pushw %ax # PUSH 0x0000 - Segment
|
||||||
|
movw $0x7c00, %di
|
||||||
|
pushw %di # PUSH 0x7C00 - Offset
|
||||||
|
retl # JMP 0x0000:0x7C00
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# ERROR Condition:
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
BadDbr:
|
||||||
|
pushw %ax
|
||||||
|
movw $0xb800, %ax
|
||||||
|
movw %ax, %es
|
||||||
|
movw $0x60, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
leaw %cs:ErrorString, %si
|
||||||
|
movw $320, %di
|
||||||
|
popw %ax
|
||||||
|
call A2C
|
||||||
|
movb %ah, 16(%si)
|
||||||
|
movb %al, 18(%si)
|
||||||
|
movw $10, %cx
|
||||||
|
rep
|
||||||
|
movsw
|
||||||
|
Halt:
|
||||||
|
jmp Halt
|
||||||
|
|
||||||
|
StartString:
|
||||||
|
.byte 'M', 0x0c, 'B', 0x0c, 'R', 0x0c, ' ', 0x0c, 'S', 0x0c, 't', 0x0c, 'a', 0x0c, 'r', 0x0c, 't', 0x0c, '!', 0x0c
|
||||||
|
ErrorString:
|
||||||
|
.byte 'M', 0x0c, 'B', 0x0c, 'R', 0x0c, ' ', 0x0c, 'E', 0x0c, 'r', 0x0c, 'r', 0x0c, ':', 0x0c, '?', 0x0c, '?', 0x0c
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# A2C - convert Ascii code stored in AH to character stored in AX
|
||||||
|
# ****************************************************************************
|
||||||
|
A2C:
|
||||||
|
movb %ah, %al
|
||||||
|
shrb $4, %ah
|
||||||
|
andb $0xF, %al
|
||||||
|
addb '0', %ah
|
||||||
|
addb '0', %al
|
||||||
|
|
||||||
|
cmpb '9', %ah
|
||||||
|
jle A2C_L1
|
||||||
|
addb $7, %ah
|
||||||
|
A2C_L1:
|
||||||
|
|
||||||
|
cmpb '9', %al
|
||||||
|
jle A2C_L2
|
||||||
|
addb $7, %al
|
||||||
|
A2C_L2:
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# PhysicalDrive - Used to indicate which disk to be boot
|
||||||
|
# Can be patched by tool
|
||||||
|
# ****************************************************************************
|
||||||
|
.org 0x01B6
|
||||||
|
PhysicalDrive: .byte 0x80
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# MbrPartitionIndicator - Used to indicate which MBR partition to be boot
|
||||||
|
# Can be patched by tool
|
||||||
|
# OxFF means boot to legacy MBR. (LBA OFFSET 6)
|
||||||
|
# ****************************************************************************
|
||||||
|
.org 0x01B7
|
||||||
|
MbrPartitionIndicator: .byte 0
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Unique MBR signature
|
||||||
|
# ****************************************************************************
|
||||||
|
.org 0x01B8
|
||||||
|
.ascii "DUET"
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Unknown
|
||||||
|
# ****************************************************************************
|
||||||
|
.org 0x01BC
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# MBR Entry - To be patched
|
||||||
|
# ****************************************************************************
|
||||||
|
.org 0x01BE
|
||||||
|
.long 0,0,0,0
|
||||||
|
.org 0x01CE
|
||||||
|
.long 0,0,0,0
|
||||||
|
.org 0x01DE
|
||||||
|
.long 0,0,0,0
|
||||||
|
.org 0x01EE
|
||||||
|
.long 0,0,0,0
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Sector Signature
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
.org 0x01FE
|
||||||
|
SectorSignature:
|
||||||
|
.word 0xaa55 # Boot Sector Signature
|
||||||
|
|
||||||
|
|
||||||
|
|
289
DuetPkg/BootSector/bootsect.S
Normal file
289
DuetPkg/BootSector/bootsect.S
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
#------------------------------------------------------------------------------
|
||||||
|
#*
|
||||||
|
#* Copyright 2006 - 2007, Intel Corporation
|
||||||
|
#* All rights reserved. This program and the accompanying materials
|
||||||
|
#* are licensed and made available under the terms and conditions of the BSD License
|
||||||
|
#* which accompanies this distribution. The full text of the license may be found at
|
||||||
|
#* http://opensource.org/licenses/bsd-license.php
|
||||||
|
#*
|
||||||
|
#* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||||
|
#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
|
#*
|
||||||
|
#* bootsect.asm
|
||||||
|
#*
|
||||||
|
#* Abstract:
|
||||||
|
#*
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#.MODEL small
|
||||||
|
.stack:
|
||||||
|
.486p:
|
||||||
|
.code:
|
||||||
|
|
||||||
|
.equ FAT_DIRECTORY_ENTRY_SIZE, 0x020
|
||||||
|
.equ FAT_DIRECTORY_ENTRY_SHIFT, 5
|
||||||
|
.equ BLOCK_SIZE, 0x0200
|
||||||
|
.equ BLOCK_MASK, 0x01ff
|
||||||
|
.equ BLOCK_SHIFT, 9
|
||||||
|
# "EFILDR_____"
|
||||||
|
.equ LOADER_FILENAME_PART1, 0x04c494645 # "EFIL"
|
||||||
|
.equ LOADER_FILENAME_PART2, 0x020205244 # "DR__"
|
||||||
|
.equ LOADER_FILENAME_PART3, 0x020202020 # "____"
|
||||||
|
|
||||||
|
.org 0x0
|
||||||
|
Ia32Jump:
|
||||||
|
jmp BootSectorEntryPoint # JMP inst - 3 bytes
|
||||||
|
nop
|
||||||
|
|
||||||
|
OemId: .ascii "INTEL " # OemId - 8 bytes
|
||||||
|
# BPB data below will be fixed by tool
|
||||||
|
SectorSize: .word 0 # Sector Size - 16 bits
|
||||||
|
SectorsPerCluster: .byte 0 # Sector Per Cluster - 8 bits
|
||||||
|
ReservedSectors: .word 0 # Reserved Sectors - 16 bits
|
||||||
|
NoFats: .byte 0 # Number of FATs - 8 bits
|
||||||
|
RootEntries: .word 0 # Root Entries - 16 bits
|
||||||
|
Sectors: .word 0 # Number of Sectors - 16 bits
|
||||||
|
Media: .byte 0 # Media - 8 bits - ignored
|
||||||
|
SectorsPerFat: .word 0 # Sectors Per FAT - 16 bits
|
||||||
|
SectorsPerTrack: .word 0 # Sectors Per Track - 16 bits - ignored
|
||||||
|
Heads: .word 0 # Heads - 16 bits - ignored
|
||||||
|
HiddenSectors: .long 0 # Hidden Sectors - 32 bits - ignored
|
||||||
|
LargeSectors: .long 0 # Large Sectors - 32 bits
|
||||||
|
PhysicalDrive: .byte 0 # PhysicalDriveNumber - 8 bits - ignored
|
||||||
|
CurrentHead: .byte 0 # Current Head - 8 bits
|
||||||
|
Signature: .byte 0 # Signature - 8 bits - ignored
|
||||||
|
VolId: .ascii " " # Volume Serial Number- 4 bytes
|
||||||
|
FatLabel: .ascii " " # Label - 11 bytes
|
||||||
|
SystemId: .ascii "FAT12 " # SystemId - 8 bytes
|
||||||
|
|
||||||
|
BootSectorEntryPoint:
|
||||||
|
#ASSUME ds:@code
|
||||||
|
#ASSUME ss:@code
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Start Print
|
||||||
|
# ****************************************************************************
|
||||||
|
leaw %cs:StartString, %si
|
||||||
|
call PrintString
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Print over
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
movw %cs, %ax # ax = 0
|
||||||
|
movw %ax, %ss # ss = 0
|
||||||
|
addw $0x1000, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
|
||||||
|
movw $0x7c00, %sp # sp = 0x7c00
|
||||||
|
movw %sp, %bp # bp = 0x7c00
|
||||||
|
|
||||||
|
movb $8, %ah # ah = 8 - Get Drive Parameters Function
|
||||||
|
movb %dl, PhysicalDrive(%bp) # BBS defines that BIOS would pass the booting driver number to the loader through DL
|
||||||
|
int $0x13 # Get Drive Parameters
|
||||||
|
xorw %ax, %ax # ax = 0
|
||||||
|
movb %dh, %al # al = dh
|
||||||
|
incb %al # MaxHead = al + 1
|
||||||
|
pushw %ax # 0000:7bfe = MaxHead
|
||||||
|
movb %cl, %al # al = cl
|
||||||
|
andb $0x3f, %al # MaxSector = al & 0x3f
|
||||||
|
pushw %ax # 0000:7bfc = MaxSector
|
||||||
|
|
||||||
|
cmpw $0xaa55, SectorSignature(%bp) # Verify Boot Sector Signature
|
||||||
|
jne BadBootSector
|
||||||
|
movw RootEntries(%bp), %cx # cx = RootEntries
|
||||||
|
shlw $FAT_DIRECTORY_ENTRY_SHIFT, %cx # cx = cx * 32 = cx * sizeof(FAT_DIRECTORY_ENTRY) = Size of Root Directory in bytes
|
||||||
|
movw %cx, %bx # bx = size of the Root Directory in bytes
|
||||||
|
andw $BLOCK_MASK, %bx # See if it is an even number of sectors long
|
||||||
|
jne BadBootSector # If is isn't, then the boot sector is bad.
|
||||||
|
movw %cx, %bx # bx = size of the Root Directory in bytes
|
||||||
|
shrw $BLOCK_SHIFT, %bx # bx = size of Root Directory in sectors
|
||||||
|
movb NoFats(%bp), %al # al = NoFats
|
||||||
|
xorb %ah, %ah # ah = 0 ==> ax = NoFats
|
||||||
|
mulw SectorsPerFat(%bp) # ax = NoFats * SectorsPerFat
|
||||||
|
addw ReservedSectors(%bp), %ax # ax = NoFats * SectorsPerFat + ReservedSectors = RootLBA
|
||||||
|
pushw %ds
|
||||||
|
popw %es
|
||||||
|
xorw %di, %di # Store directory in es:di = 1000:0000
|
||||||
|
call ReadBlocks # Read entire Root Directory
|
||||||
|
addw %bx, %ax # ax = NoFats * SectorsPerFat + ReservedSectors + RootDirSectors = FirstClusterLBA (FirstDataSector)
|
||||||
|
movw %ax, (%bp) # Save FirstClusterLBA (FirstDataSector) for later use
|
||||||
|
|
||||||
|
# dx - variable storage (initial value is 0)
|
||||||
|
# bx - loader (initial value is 0)
|
||||||
|
xorw %dx, %dx
|
||||||
|
xorw %bx, %bx
|
||||||
|
|
||||||
|
FindEFILDR:
|
||||||
|
cmpl $LOADER_FILENAME_PART1, (%di) # Compare to "EFIL"
|
||||||
|
jne FindVARSTORE
|
||||||
|
cmpl $LOADER_FILENAME_PART2, 4(%di)
|
||||||
|
jne FindVARSTORE
|
||||||
|
cmpl $LOADER_FILENAME_PART3, 7(%di)
|
||||||
|
jne FindVARSTORE
|
||||||
|
movw 26(%di), %bx # bx = Start Cluster for EFILDR <----------------------------------
|
||||||
|
testw %dx, %dx
|
||||||
|
je FindNext # Efivar.bin is not loaded
|
||||||
|
jmp FoundAll
|
||||||
|
|
||||||
|
FindVARSTORE:
|
||||||
|
## if the file is not loader file, see if it's "EFIVAR BIN"
|
||||||
|
cmpl $0x56494645, (%di) # Compare to "EFIV"
|
||||||
|
jne FindNext
|
||||||
|
cmpl $0x20205241, 4(%di) # Compare to "AR "
|
||||||
|
jne FindNext
|
||||||
|
cmpl $0x4e494220, 7(%di) # Compare to " BIN"
|
||||||
|
jne FindNext
|
||||||
|
movw %di, %dx # dx = Offset of Start Cluster for Efivar.bin <---------------------
|
||||||
|
addw $26, %dx
|
||||||
|
testw %bx, %bx
|
||||||
|
je FindNext # Efildr is not loaded
|
||||||
|
jmp FoundAll
|
||||||
|
|
||||||
|
FindNext:
|
||||||
|
# go to next find
|
||||||
|
addw $FAT_DIRECTORY_ENTRY_SIZE, %di # Increment di
|
||||||
|
subw $FAT_DIRECTORY_ENTRY_SIZE, %cx # Decrement cx
|
||||||
|
# TODO: jump to FindVarStore if ...
|
||||||
|
jne FindEFILDR
|
||||||
|
jmp NotFoundAll
|
||||||
|
|
||||||
|
FoundAll:
|
||||||
|
FoundEFILDR:
|
||||||
|
movw %bx, %cx # cx = Start Cluster for EFILDR <----------------------------------
|
||||||
|
movw %cs, %ax # Destination = 2000:0000
|
||||||
|
addw $0x2000, %ax
|
||||||
|
movw %ax, %es
|
||||||
|
xorw %di, %di
|
||||||
|
ReadFirstClusterOfEFILDR:
|
||||||
|
movw %cx, %ax # ax = StartCluster
|
||||||
|
subw $2, %ax # ax = StartCluster - 2
|
||||||
|
xorb %bh, %bh
|
||||||
|
movb SectorsPerCluster(%bp), %bl # bx = SectorsPerCluster
|
||||||
|
pushw %dx
|
||||||
|
mulw %bx
|
||||||
|
popw %dx # ax = (StartCluster - 2) * SectorsPerCluster
|
||||||
|
addw (%bp), %ax # ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
|
||||||
|
xorb %bh, %bh
|
||||||
|
movb SectorsPerCluster(%bp), %bl # bx = Number of Sectors in a cluster
|
||||||
|
pushw %es
|
||||||
|
call ReadBlocks
|
||||||
|
popw %ax
|
||||||
|
JumpIntoFirstSectorOfEFILDR:
|
||||||
|
movw %ax, JumpSegment(%bp)
|
||||||
|
JumpFarInstruction:
|
||||||
|
.byte 0xea
|
||||||
|
JumpOffset:
|
||||||
|
.word 0x000
|
||||||
|
JumpSegment:
|
||||||
|
.word 0x2000
|
||||||
|
|
||||||
|
|
||||||
|
PrintString:
|
||||||
|
movw $0xb800, %ax
|
||||||
|
movw %ax, %es
|
||||||
|
movw $0x7c0, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw $7, %cx
|
||||||
|
movw $160, %di
|
||||||
|
rep
|
||||||
|
movsw
|
||||||
|
ret
|
||||||
|
# ****************************************************************************
|
||||||
|
# ReadBlocks - Reads a set of blocks from a block device
|
||||||
|
#
|
||||||
|
# AX = Start LBA
|
||||||
|
# BX = Number of Blocks to Read
|
||||||
|
# ES:DI = Buffer to store sectors read from disk
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
# cx = Blocks
|
||||||
|
# bx = NumberOfBlocks
|
||||||
|
# si = StartLBA
|
||||||
|
|
||||||
|
ReadBlocks:
|
||||||
|
pusha
|
||||||
|
addl LBAOffsetForBootSector(%bp), %eax # Add LBAOffsetForBootSector to Start LBA
|
||||||
|
addl HiddenSectors(%bp), %eax # Add HiddenSectors to Start LBA
|
||||||
|
movl %eax, %esi # esi = Start LBA
|
||||||
|
movw %bx, %cx # cx = Number of blocks to read
|
||||||
|
ReadCylinderLoop:
|
||||||
|
movw $0x7bfc, %bp # bp = 0x7bfc
|
||||||
|
movl %esi, %eax # eax = Start LBA
|
||||||
|
xorl %edx, %edx # edx = 0
|
||||||
|
movzwl (%bp), %ebx # bx = MaxSector
|
||||||
|
divl %ebx # ax = StartLBA / MaxSector
|
||||||
|
incw %dx # dx = (StartLBA % MaxSector) + 1
|
||||||
|
subw %dx, %bx # bx = MaxSector - Sector
|
||||||
|
incw %bx # bx = MaxSector - Sector + 1
|
||||||
|
cmpw %bx, %cx # Compare (Blocks) to (MaxSector - Sector + 1)
|
||||||
|
jg LimitTransfer
|
||||||
|
movw %cx, %bx # bx = Blocks
|
||||||
|
LimitTransfer:
|
||||||
|
pushw %cx
|
||||||
|
movb %dl, %cl # cl = (StartLBA % MaxSector) + 1 = Sector
|
||||||
|
xorw %dx, %dx # dx = 0
|
||||||
|
divw 2(%bp) # ax = ax / (MaxHead + 1) = Cylinder
|
||||||
|
# dx = ax % (MaxHead + 1) = Head
|
||||||
|
|
||||||
|
pushw %bx # Save number of blocks to transfer
|
||||||
|
movb %dl, %dh # dh = Head
|
||||||
|
movw $0x7c00, %bp # bp = 0x7c00
|
||||||
|
movb PhysicalDrive(%bp), %dl # dl = Drive Number
|
||||||
|
movb %al, %ch # ch = Cylinder
|
||||||
|
movb %bl, %al # al = Blocks
|
||||||
|
movb $2, %ah # ah = Function 2
|
||||||
|
movw %di, %bx # es:bx = Buffer address
|
||||||
|
int $0x13
|
||||||
|
jc DiskError
|
||||||
|
popw %bx
|
||||||
|
popw %cx
|
||||||
|
movzwl %bx, %ebx
|
||||||
|
addl %ebx, %esi # StartLBA = StartLBA + NumberOfBlocks
|
||||||
|
subw %bx, %cx # Blocks = Blocks - NumberOfBlocks
|
||||||
|
movw %es, %ax
|
||||||
|
shlw $(BLOCK_SHIFT-4), %bx
|
||||||
|
addw %bx, %ax
|
||||||
|
movw %ax, %es # es:di = es:di + NumberOfBlocks*BLOCK_SIZE
|
||||||
|
cmpw $0, %cx
|
||||||
|
jne ReadCylinderLoop
|
||||||
|
popa
|
||||||
|
ret
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# ERROR Condition:
|
||||||
|
# ****************************************************************************
|
||||||
|
NotFoundAll:
|
||||||
|
## if we found EFILDR, continue
|
||||||
|
testw %bx, %bx
|
||||||
|
jne FoundEFILDR
|
||||||
|
BadBootSector:
|
||||||
|
DiskError:
|
||||||
|
leaw %cs:ErrorString, %si
|
||||||
|
call PrintString
|
||||||
|
Halt:
|
||||||
|
jmp Halt
|
||||||
|
|
||||||
|
StartString:
|
||||||
|
.byte 'B', 0x0c, 'S', 0x0c, 't', 0x0c, 'a', 0x0c, 'r', 0x0c, 't', 0x0c, '!', 0x0c
|
||||||
|
ErrorString:
|
||||||
|
.byte 'B', 0x0c, 'E', 0x0c, 'r', 0x0c, 'r', 0x0c, 'o', 0x0c, 'r', 0x0c, '!', 0x0c
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# LBA Offset for BootSector, need patched by tool for HD boot.
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
# .org 0x01fa # Comment it for pass build. Should optimise code size.
|
||||||
|
LBAOffsetForBootSector:
|
||||||
|
.long 0x0
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Sector Signature
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
# .org 0x01fe # Comment it for pass build.
|
||||||
|
SectorSignature:
|
||||||
|
.word 0xaa55 # Boot Sector Signature
|
||||||
|
|
||||||
|
|
||||||
|
|
289
DuetPkg/BootSector/bs16.S
Normal file
289
DuetPkg/BootSector/bs16.S
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
#------------------------------------------------------------------------------
|
||||||
|
#*
|
||||||
|
#* Copyright 2006 - 2007, Intel Corporation
|
||||||
|
#* All rights reserved. This program and the accompanying materials
|
||||||
|
#* are licensed and made available under the terms and conditions of the BSD License
|
||||||
|
#* which accompanies this distribution. The full text of the license may be found at
|
||||||
|
#* http://opensource.org/licenses/bsd-license.php
|
||||||
|
#*
|
||||||
|
#* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||||
|
#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
|
#*
|
||||||
|
#* bs16.asm
|
||||||
|
#*
|
||||||
|
#* Abstract:
|
||||||
|
#*
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#.MODEL small
|
||||||
|
.stack:
|
||||||
|
.486p:
|
||||||
|
.code:
|
||||||
|
|
||||||
|
.equ FAT_DIRECTORY_ENTRY_SIZE, 0x020
|
||||||
|
.equ FAT_DIRECTORY_ENTRY_SHIFT, 5
|
||||||
|
.equ BLOCK_SIZE, 0x0200
|
||||||
|
.equ BLOCK_MASK, 0x01ff
|
||||||
|
.equ BLOCK_SHIFT, 9
|
||||||
|
# "EFILDR_____"
|
||||||
|
.equ LOADER_FILENAME_PART1, 0x04c494645 # "EFIL"
|
||||||
|
.equ LOADER_FILENAME_PART2, 0x036315244 # "DR16"
|
||||||
|
.equ LOADER_FILENAME_PART3, 0x020202036 # "6___"
|
||||||
|
|
||||||
|
.org 0x0
|
||||||
|
Ia32Jump:
|
||||||
|
jmp BootSectorEntryPoint # JMP inst - 3 bytes
|
||||||
|
nop
|
||||||
|
|
||||||
|
OemId: .ascii "INTEL " # OemId - 8 bytes
|
||||||
|
# BPB data below will be fixed by tool
|
||||||
|
SectorSize: .word 0 # Sector Size - 16 bits
|
||||||
|
SectorsPerCluster: .byte 0 # Sector Per Cluster - 8 bits
|
||||||
|
ReservedSectors: .word 0 # Reserved Sectors - 16 bits
|
||||||
|
NoFats: .byte 0 # Number of FATs - 8 bits
|
||||||
|
RootEntries: .word 0 # Root Entries - 16 bits
|
||||||
|
Sectors: .word 0 # Number of Sectors - 16 bits
|
||||||
|
Media: .byte 0 # Media - 8 bits - ignored
|
||||||
|
SectorsPerFat: .word 0 # Sectors Per FAT - 16 bits
|
||||||
|
SectorsPerTrack: .word 0 # Sectors Per Track - 16 bits - ignored
|
||||||
|
Heads: .word 0 # Heads - 16 bits - ignored
|
||||||
|
HiddenSectors: .long 0 # Hidden Sectors - 32 bits - ignored
|
||||||
|
LargeSectors: .long 0 # Large Sectors - 32 bits
|
||||||
|
PhysicalDrive: .byte 0 # PhysicalDriveNumber - 8 bits - ignored
|
||||||
|
CurrentHead: .byte 0 # Current Head - 8 bits
|
||||||
|
Signature: .byte 0 # Signature - 8 bits - ignored
|
||||||
|
VolId: .ascii " " # Volume Serial Number- 4 bytes
|
||||||
|
FatLabel: .ascii " " # Label - 11 bytes
|
||||||
|
SystemId: .ascii "FAT12 " # SystemId - 8 bytes
|
||||||
|
|
||||||
|
BootSectorEntryPoint:
|
||||||
|
#ASSUME ds:@code
|
||||||
|
#ASSUME ss:@code
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Start Print
|
||||||
|
# ****************************************************************************
|
||||||
|
leaw %cs:StartString, %si
|
||||||
|
call PrintString
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Print over
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
movw %cs, %ax # ax = 0
|
||||||
|
movw %ax, %ss # ss = 0
|
||||||
|
addw $0x1000, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
|
||||||
|
movw $0x7c00, %sp # sp = 0x7c00
|
||||||
|
movw %sp, %bp # bp = 0x7c00
|
||||||
|
|
||||||
|
movb $8, %ah # ah = 8 - Get Drive Parameters Function
|
||||||
|
movb %dl, PhysicalDrive(%bp) # BBS defines that BIOS would pass the booting driver number to the loader through DL
|
||||||
|
int $0x13 # Get Drive Parameters
|
||||||
|
xorw %ax, %ax # ax = 0
|
||||||
|
movb %dh, %al # al = dh
|
||||||
|
incb %al # MaxHead = al + 1
|
||||||
|
pushw %ax # 0000:7bfe = MaxHead
|
||||||
|
movb %cl, %al # al = cl
|
||||||
|
andb $0x3f, %al # MaxSector = al & 0x3f
|
||||||
|
pushw %ax # 0000:7bfc = MaxSector
|
||||||
|
|
||||||
|
cmpw $0xaa55, SectorSignature(%bp) # Verify Boot Sector Signature
|
||||||
|
jne BadBootSector
|
||||||
|
movw RootEntries(%bp), %cx # cx = RootEntries
|
||||||
|
shlw $FAT_DIRECTORY_ENTRY_SHIFT, %cx # cx = cx * 32 = cx * sizeof(FAT_DIRECTORY_ENTRY) = Size of Root Directory in bytes
|
||||||
|
movw %cx, %bx # bx = size of the Root Directory in bytes
|
||||||
|
andw $BLOCK_MASK, %bx # See if it is an even number of sectors long
|
||||||
|
jne BadBootSector # If is isn't, then the boot sector is bad.
|
||||||
|
movw %cx, %bx # bx = size of the Root Directory in bytes
|
||||||
|
shrw $BLOCK_SHIFT, %bx # bx = size of Root Directory in sectors
|
||||||
|
movb NoFats(%bp), %al # al = NoFats
|
||||||
|
xorb %ah, %ah # ah = 0 ==> ax = NoFats
|
||||||
|
mulw SectorsPerFat(%bp) # ax = NoFats * SectorsPerFat
|
||||||
|
addw ReservedSectors(%bp), %ax # ax = NoFats * SectorsPerFat + ReservedSectors = RootLBA
|
||||||
|
pushw %ds
|
||||||
|
popw %es
|
||||||
|
xorw %di, %di # Store directory in es:di = 1000:0000
|
||||||
|
call ReadBlocks # Read entire Root Directory
|
||||||
|
addw %bx, %ax # ax = NoFats * SectorsPerFat + ReservedSectors + RootDirSectors = FirstClusterLBA (FirstDataSector)
|
||||||
|
movw %ax, (%bp) # Save FirstClusterLBA (FirstDataSector) for later use
|
||||||
|
|
||||||
|
# dx - variable storage (initial value is 0)
|
||||||
|
# bx - loader (initial value is 0)
|
||||||
|
xorw %dx, %dx
|
||||||
|
xorw %bx, %bx
|
||||||
|
|
||||||
|
FindEFILDR:
|
||||||
|
cmpl $LOADER_FILENAME_PART1, (%di) # Compare to "EFIL"
|
||||||
|
jne FindVARSTORE
|
||||||
|
cmpl $LOADER_FILENAME_PART2, 4(%di)
|
||||||
|
jne FindVARSTORE
|
||||||
|
cmpl $LOADER_FILENAME_PART3, 7(%di)
|
||||||
|
jne FindVARSTORE
|
||||||
|
movw 26(%di), %bx # bx = Start Cluster for EFILDR <----------------------------------
|
||||||
|
testw %dx, %dx
|
||||||
|
je FindNext # Efivar.bin is not loaded
|
||||||
|
jmp FoundAll
|
||||||
|
|
||||||
|
FindVARSTORE:
|
||||||
|
##if the file is not loader file, see if it's "EFIVAR BIN"
|
||||||
|
cmpl $0x56494645, (%di) # Compare to "EFIV"
|
||||||
|
jne FindNext
|
||||||
|
cmpl $0x20205241, 4(%di) # Compare to "AR "
|
||||||
|
jne FindNext
|
||||||
|
cmpl $0x4e494220, 7(%di) # Compare to " BIN"
|
||||||
|
jne FindNext
|
||||||
|
movw %di, %dx # dx = Offset of Start Cluster for Efivar.bin <---------------------
|
||||||
|
addw $26, %dx
|
||||||
|
testw %bx, %bx
|
||||||
|
je FindNext # Efildr is not loaded
|
||||||
|
jmp FoundAll
|
||||||
|
|
||||||
|
FindNext:
|
||||||
|
# go to next find
|
||||||
|
addw $FAT_DIRECTORY_ENTRY_SIZE, %di # Increment di
|
||||||
|
subw $FAT_DIRECTORY_ENTRY_SIZE, %cx # Decrement cx
|
||||||
|
# TODO: jump to FindVarStore if ...
|
||||||
|
jne FindEFILDR
|
||||||
|
jmp NotFoundAll
|
||||||
|
|
||||||
|
FoundAll:
|
||||||
|
FoundEFILDR:
|
||||||
|
movw %bx, %cx # cx = Start Cluster for EFILDR <----------------------------------
|
||||||
|
movw %cs, %ax # Destination = 2000:0000
|
||||||
|
addw $0x2000, %ax
|
||||||
|
movw %ax, %es
|
||||||
|
xorw %di, %di
|
||||||
|
ReadFirstClusterOfEFILDR:
|
||||||
|
movw %cx, %ax # ax = StartCluster
|
||||||
|
subw $2, %ax # ax = StartCluster - 2
|
||||||
|
xorb %bh, %bh
|
||||||
|
movb SectorsPerCluster(%bp), %bl # bx = SectorsPerCluster
|
||||||
|
pushw %dx
|
||||||
|
mulw %bx
|
||||||
|
popw %dx # ax = (StartCluster - 2) * SectorsPerCluster
|
||||||
|
addw (%bp), %ax # ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
|
||||||
|
xorb %bh, %bh
|
||||||
|
movb SectorsPerCluster(%bp), %bl # bx = Number of Sectors in a cluster
|
||||||
|
pushw %es
|
||||||
|
call ReadBlocks
|
||||||
|
popw %ax
|
||||||
|
JumpIntoFirstSectorOfEFILDR:
|
||||||
|
movw %ax, JumpSegment(%bp)
|
||||||
|
JumpFarInstruction:
|
||||||
|
.byte 0xea
|
||||||
|
JumpOffset:
|
||||||
|
.word 0x000
|
||||||
|
JumpSegment:
|
||||||
|
.word 0x2000
|
||||||
|
|
||||||
|
|
||||||
|
PrintString:
|
||||||
|
movw $0xb800, %ax
|
||||||
|
movw %ax, %es
|
||||||
|
movw $0x7c0, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw $7, %cx
|
||||||
|
movw $160, %di
|
||||||
|
rep
|
||||||
|
movsw
|
||||||
|
ret
|
||||||
|
# ****************************************************************************
|
||||||
|
# ReadBlocks - Reads a set of blocks from a block device
|
||||||
|
#
|
||||||
|
# AX = Start LBA
|
||||||
|
# BX = Number of Blocks to Read
|
||||||
|
# ES:DI = Buffer to store sectors read from disk
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
# cx = Blocks
|
||||||
|
# bx = NumberOfBlocks
|
||||||
|
# si = StartLBA
|
||||||
|
|
||||||
|
ReadBlocks:
|
||||||
|
pusha
|
||||||
|
addl LBAOffsetForBootSector(%bp), %eax # Add LBAOffsetForBootSector to Start LBA
|
||||||
|
addl HiddenSectors(%bp), %eax # Add HiddenSectors to Start LBA
|
||||||
|
movl %eax, %esi # esi = Start LBA
|
||||||
|
movw %bx, %cx # cx = Number of blocks to read
|
||||||
|
ReadCylinderLoop:
|
||||||
|
movw $0x7bfc, %bp # bp = 0x7bfc
|
||||||
|
movl %esi, %eax # eax = Start LBA
|
||||||
|
xorl %edx, %edx # edx = 0
|
||||||
|
movzwl (%bp), %ebx # bx = MaxSector
|
||||||
|
divl %ebx # ax = StartLBA / MaxSector
|
||||||
|
incw %dx # dx = (StartLBA % MaxSector) + 1
|
||||||
|
subw %dx, %bx # bx = MaxSector - Sector
|
||||||
|
incw %bx # bx = MaxSector - Sector + 1
|
||||||
|
cmpw %bx, %cx # Compare (Blocks) to (MaxSector - Sector + 1)
|
||||||
|
jg LimitTransfer
|
||||||
|
movw %cx, %bx # bx = Blocks
|
||||||
|
LimitTransfer:
|
||||||
|
pushw %cx
|
||||||
|
movb %dl, %cl # cl = (StartLBA % MaxSector) + 1 = Sector
|
||||||
|
xorw %dx, %dx # dx = 0
|
||||||
|
divw 2(%bp) # ax = ax / (MaxHead + 1) = Cylinder
|
||||||
|
# dx = ax % (MaxHead + 1) = Head
|
||||||
|
|
||||||
|
pushw %bx # Save number of blocks to transfer
|
||||||
|
movb %dl, %dh # dh = Head
|
||||||
|
movw $0x7c00, %bp # bp = 0x7c00
|
||||||
|
movb PhysicalDrive(%bp), %dl # dl = Drive Number
|
||||||
|
movb %al, %ch # ch = Cylinder
|
||||||
|
movb %bl, %al # al = Blocks
|
||||||
|
movb $2, %ah # ah = Function 2
|
||||||
|
movw %di, %bx # es:bx = Buffer address
|
||||||
|
int $0x13
|
||||||
|
jc DiskError
|
||||||
|
popw %bx
|
||||||
|
popw %cx
|
||||||
|
movzwl %bx, %ebx
|
||||||
|
addl %ebx, %esi # StartLBA = StartLBA + NumberOfBlocks
|
||||||
|
subw %bx, %cx # Blocks = Blocks - NumberOfBlocks
|
||||||
|
movw %es, %ax
|
||||||
|
shlw $(BLOCK_SHIFT-4),%bx
|
||||||
|
addw %bx, %ax
|
||||||
|
movw %ax, %es # es:di = es:di + NumberOfBlocks*BLOCK_SIZE
|
||||||
|
cmpw $0, %cx
|
||||||
|
jne ReadCylinderLoop
|
||||||
|
popa
|
||||||
|
ret
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# ERROR Condition:
|
||||||
|
# ****************************************************************************
|
||||||
|
NotFoundAll:
|
||||||
|
## if we found EFILDR, continue
|
||||||
|
testw %bx, %bx
|
||||||
|
jne FoundEFILDR
|
||||||
|
BadBootSector:
|
||||||
|
DiskError:
|
||||||
|
leaw %cs:ErrorString, %si
|
||||||
|
call PrintString
|
||||||
|
Halt:
|
||||||
|
jmp Halt
|
||||||
|
|
||||||
|
StartString:
|
||||||
|
.byte 'B', 0x0c, 'S', 0x0c, 't', 0x0c, 'a', 0x0c, 'r', 0x0c, 't', 0x0c, '!', 0x0c
|
||||||
|
ErrorString:
|
||||||
|
.byte 'B', 0x0c, 'E', 0x0c, 'r', 0x0c, 'r', 0x0c, 'o', 0x0c, 'r', 0x0c, '!', 0x0c
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# LBA Offset for BootSector, need patched by tool for HD boot.
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
# .org 0x01fa # Comment it for pass build. Should optimise code size.
|
||||||
|
LBAOffsetForBootSector:
|
||||||
|
.long 0x0
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# Sector Signature
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
# .org 0x01fe # Comment it for pass build. Should optimise code size.
|
||||||
|
SectorSignature:
|
||||||
|
.word 0xaa55 # Boot Sector Signature
|
||||||
|
|
||||||
|
|
||||||
|
|
916
DuetPkg/BootSector/start.S
Normal file
916
DuetPkg/BootSector/start.S
Normal file
@ -0,0 +1,916 @@
|
|||||||
|
#------------------------------------------------------------------------------
|
||||||
|
#*
|
||||||
|
#* Copyright 2006 - 2007, Intel Corporation
|
||||||
|
#* All rights reserved. This program and the accompanying materials
|
||||||
|
#* are licensed and made available under the terms and conditions of the BSD License
|
||||||
|
#* which accompanies this distribution. The full text of the license may be found at
|
||||||
|
#* http://opensource.org/licenses/bsd-license.php
|
||||||
|
#*
|
||||||
|
#* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||||
|
#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
|
#*
|
||||||
|
#* start.S
|
||||||
|
#*
|
||||||
|
#* Abstract:
|
||||||
|
#*
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
.equ FAT_DIRECTORY_ENTRY_SIZE, 0x020
|
||||||
|
.equ FAT_DIRECTORY_ENTRY_SHIFT, 5
|
||||||
|
.equ BLOCK_SIZE, 0x0200
|
||||||
|
.equ BLOCK_MASK, 0x01ff
|
||||||
|
.equ BLOCK_SHIFT, 9
|
||||||
|
|
||||||
|
.org 0x0
|
||||||
|
Ia32Jump:
|
||||||
|
jmp BootSectorEntryPoint # JMP inst - 3 bytes
|
||||||
|
nop
|
||||||
|
|
||||||
|
OemId: .ascii "INTEL " # OemId - 8 bytes
|
||||||
|
|
||||||
|
SectorSize: .word 0 # Sector Size - 16 bits
|
||||||
|
SectorsPerCluster: .byte 0 # Sector Per Cluster - 8 bits
|
||||||
|
ReservedSectors: .word 0 # Reserved Sectors - 16 bits
|
||||||
|
NoFats: .byte 0 # Number of FATs - 8 bits
|
||||||
|
RootEntries: .word 0 # Root Entries - 16 bits
|
||||||
|
Sectors: .word 0 # Number of Sectors - 16 bits
|
||||||
|
Media: .byte 0 # Media - 8 bits - ignored
|
||||||
|
SectorsPerFat: .word 0 # Sectors Per FAT - 16 bits
|
||||||
|
SectorsPerTrack: .word 0 # Sectors Per Track - 16 bits - ignored
|
||||||
|
Heads: .word 0 # Heads - 16 bits - ignored
|
||||||
|
HiddenSectors: .long 0 # Hidden Sectors - 32 bits - ignored
|
||||||
|
LargeSectors: .long 0 # Large Sectors - 32 bits
|
||||||
|
PhysicalDrive: .byte 0 # PhysicalDriveNumber - 8 bits - ignored
|
||||||
|
CurrentHead: .byte 0 # Current Head - 8 bits
|
||||||
|
Signature: .byte 0 # Signature - 8 bits - ignored
|
||||||
|
VolId: .ascii " " # Volume Serial Number- 4 bytes
|
||||||
|
FatLabel: .ascii " " # Label - 11 bytes
|
||||||
|
SystemId: .ascii "FAT12 " # SystemId - 8 bytes
|
||||||
|
|
||||||
|
BootSectorEntryPoint:
|
||||||
|
#ASSUME ds:@code
|
||||||
|
#ASSUME ss:@code
|
||||||
|
# ds = 1000, es = 2000 + x (size of first cluster >> 4)
|
||||||
|
# cx = Start Cluster of EfiLdr
|
||||||
|
# dx = Start Cluster of Efivar.bin
|
||||||
|
|
||||||
|
# Re use the BPB data stored in Boot Sector
|
||||||
|
movw $0x7c00, %bp
|
||||||
|
|
||||||
|
pushw %cx
|
||||||
|
# Read Efivar.bin
|
||||||
|
# 1000:dx = DirectoryEntry of Efivar.bin -> BS.com has filled already
|
||||||
|
movw $0x1900, %ax
|
||||||
|
movw %ax, %es
|
||||||
|
testw %dx, %dx
|
||||||
|
jnz CheckVarStoreSize
|
||||||
|
|
||||||
|
movb $1, %al
|
||||||
|
NoVarStore:
|
||||||
|
pushw %es
|
||||||
|
# Set the 5th byte start @ 0:19000 to non-zero indicating we should init var store header in DxeIpl
|
||||||
|
movb %al, %es:($4)
|
||||||
|
jmp SaveVolumeId
|
||||||
|
|
||||||
|
CheckVarStoreSize:
|
||||||
|
movw %dx, %di
|
||||||
|
cmpl $0x4000, %ds:2(%di)
|
||||||
|
movb $2, %al
|
||||||
|
jne NoVarStore
|
||||||
|
|
||||||
|
LoadVarStore:
|
||||||
|
movb $0, %al
|
||||||
|
movb %al, %es:($4)
|
||||||
|
movw (%di), %cx
|
||||||
|
# ES:DI = 1500:0
|
||||||
|
xorw %di, %di
|
||||||
|
pushw %es
|
||||||
|
movw $0x1500, %ax
|
||||||
|
movw %ax, %es
|
||||||
|
call ReadFile
|
||||||
|
SaveVolumeId:
|
||||||
|
popw %es
|
||||||
|
movw VolId(%bp), %ax
|
||||||
|
movw %ax, %es:($0) # Save Volume Id to 0:19000. we will find the correct volume according to this VolumeId
|
||||||
|
movw VolId+2(%bp), %ax
|
||||||
|
movw %ax, %es:($2)
|
||||||
|
|
||||||
|
# Read Efildr
|
||||||
|
popw %cx
|
||||||
|
# cx = Start Cluster of Efildr -> BS.com has filled already
|
||||||
|
# ES:DI = 2000:0, first cluster will be read again
|
||||||
|
xorw %di, %di # di = 0
|
||||||
|
movw $0x2000, %ax
|
||||||
|
movw %ax, %es
|
||||||
|
call ReadFile
|
||||||
|
movw %cs, %ax
|
||||||
|
movw %ax, %cs:JumpSegment
|
||||||
|
|
||||||
|
JumpFarInstruction:
|
||||||
|
.byte 0xea
|
||||||
|
JumpOffset:
|
||||||
|
.word 0x200
|
||||||
|
JumpSegment:
|
||||||
|
.word 0x2000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# ReadFile
|
||||||
|
#
|
||||||
|
# Arguments:
|
||||||
|
# CX = Start Cluster of File
|
||||||
|
# ES:DI = Buffer to store file content read from disk
|
||||||
|
#
|
||||||
|
# Return:
|
||||||
|
# (ES << 4 + DI) = end of file content Buffer
|
||||||
|
#
|
||||||
|
# ****************************************************************************
|
||||||
|
ReadFile:
|
||||||
|
# si = NumberOfClusters
|
||||||
|
# cx = ClusterNumber
|
||||||
|
# dx = CachedFatSectorNumber
|
||||||
|
# ds:0000 = CacheFatSectorBuffer
|
||||||
|
# es:di = Buffer to load file
|
||||||
|
# bx = NextClusterNumber
|
||||||
|
pusha
|
||||||
|
movw $1, %si # NumberOfClusters = 1
|
||||||
|
pushw %cx # Push Start Cluster onto stack
|
||||||
|
movw $0xfff, %dx # CachedFatSectorNumber = 0xfff
|
||||||
|
FatChainLoop:
|
||||||
|
movw %cx, %ax # ax = ClusterNumber
|
||||||
|
andw $0xff8, %ax # ax = ax & 0xff8
|
||||||
|
cmpw $0xff8, %ax # See if this is the last cluster
|
||||||
|
je FoundLastCluster # Jump if last cluster found
|
||||||
|
movw %cx, %ax # ax = ClusterNumber
|
||||||
|
shlw %ax # ax = ClusterNumber * 2
|
||||||
|
addw %cx, %ax # ax = ClusterNumber * 2 + ClusterNumber = ClusterNumber * 3
|
||||||
|
shrw %ax # FatOffset = ClusterNumber*3 / 2
|
||||||
|
pushw %si # Save si
|
||||||
|
movw %ax, %si # si = FatOffset
|
||||||
|
shrw %ax # ax = FatOffset >> BLOCK_SHIFT
|
||||||
|
addw ReservedSectors(%bp), %ax # ax = FatSectorNumber = ReservedSectors + (FatOffset >> BLOCK_OFFSET)
|
||||||
|
andw BLOCK_MASK,%si # si = FatOffset & BLOCK_MASK
|
||||||
|
cmpw %dx, %ax # Compare FatSectorNumber to CachedFatSectorNumber
|
||||||
|
je SkipFatRead
|
||||||
|
movw $2, %bx
|
||||||
|
pushw %es
|
||||||
|
pushw %ds
|
||||||
|
popw %es
|
||||||
|
call ReadBlocks # Read 2 blocks starting at AX storing at ES:DI
|
||||||
|
popw %es
|
||||||
|
movw %ax, %dx # CachedFatSectorNumber = FatSectorNumber
|
||||||
|
SkipFatRead:
|
||||||
|
movw (%si), %bx # bx = NextClusterNumber
|
||||||
|
movw %cx, %ax # ax = ClusterNumber
|
||||||
|
andw $1, %ax # See if this is an odd cluster number
|
||||||
|
je EvenFatEntry
|
||||||
|
shrw $4, %bx # NextClusterNumber = NextClusterNumber >> 4
|
||||||
|
EvenFatEntry:
|
||||||
|
andw $0xfff, %bx # Strip upper 4 bits of NextClusterNumber
|
||||||
|
popw %si # Restore si
|
||||||
|
decw %bx # bx = NextClusterNumber - 1
|
||||||
|
cmpw %cx, %bx # See if (NextClusterNumber-1)==ClusterNumber
|
||||||
|
jne ReadClusters
|
||||||
|
incw %bx # bx = NextClusterNumber
|
||||||
|
incw %si # NumberOfClusters++
|
||||||
|
movw %bx, %cx # ClusterNumber = NextClusterNumber
|
||||||
|
jmp FatChainLoop
|
||||||
|
ReadClusters:
|
||||||
|
incw %bx
|
||||||
|
popw %ax # ax = StartCluster
|
||||||
|
pushw %bx # StartCluster = NextClusterNumber
|
||||||
|
movw %bx, %cx # ClusterNumber = NextClusterNumber
|
||||||
|
subw $2, %ax # ax = StartCluster - 2
|
||||||
|
xorb %bh, %bh
|
||||||
|
movb SectorsPerCluster(%bp), %bl # bx = SectorsPerCluster
|
||||||
|
mulw %bx # ax = (StartCluster - 2) * SectorsPerCluster
|
||||||
|
addw (%bp), %ax # ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
|
||||||
|
pushw %ax # save start sector
|
||||||
|
movw %si, %ax # ax = NumberOfClusters
|
||||||
|
mulw %bx # ax = NumberOfClusters * SectorsPerCluster
|
||||||
|
movw %ax, %bx # bx = Number of Sectors
|
||||||
|
popw %ax # ax = Start Sector
|
||||||
|
call ReadBlocks
|
||||||
|
movw $1, %si # NumberOfClusters = 1
|
||||||
|
jmp FatChainLoop
|
||||||
|
FoundLastCluster:
|
||||||
|
popw %cx
|
||||||
|
popa
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
# ****************************************************************************
|
||||||
|
# ReadBlocks - Reads a set of blocks from a block device
|
||||||
|
#
|
||||||
|
# AX = Start LBA
|
||||||
|
# BX = Number of Blocks to Read
|
||||||
|
# ES:DI = Buffer to store sectors read from disk
|
||||||
|
# ****************************************************************************
|
||||||
|
|
||||||
|
# cx = Blocks
|
||||||
|
# bx = NumberOfBlocks
|
||||||
|
# si = StartLBA
|
||||||
|
|
||||||
|
ReadBlocks:
|
||||||
|
pusha
|
||||||
|
addl LBAOffsetForBootSector(%bp), %eax # Add LBAOffsetForBootSector to Start LBA
|
||||||
|
addl HiddenSectors(%bp), %eax # Add HiddenSectors to Start LBA
|
||||||
|
movl %eax, %esi # esi = Start LBA
|
||||||
|
movw %bx, %cx # cx = Number of blocks to read
|
||||||
|
ReadCylinderLoop:
|
||||||
|
movw $0x7bfc, %bp # bp = 0x7bfc
|
||||||
|
movl %esi, %eax # eax = Start LBA
|
||||||
|
xorl %edx, %edx # edx = 0
|
||||||
|
movzwl (%bp), %ebx # bx = MaxSector
|
||||||
|
divl %ebx # ax = StartLBA / MaxSector
|
||||||
|
incw %dx # dx = (StartLBA % MaxSector) + 1
|
||||||
|
|
||||||
|
movw (%bp), %bx # bx = MaxSector
|
||||||
|
subw %dx, %bx # bx = MaxSector - Sector
|
||||||
|
incw %bx # bx = MaxSector - Sector + 1
|
||||||
|
cmpw %bx, %cx # Compare (Blocks) to (MaxSector - Sector + 1)
|
||||||
|
jg LimitTransfer
|
||||||
|
movw %cx, %bx # bx = Blocks
|
||||||
|
LimitTransfer:
|
||||||
|
pushw %ax # save ax
|
||||||
|
movw %es, %ax # ax = es
|
||||||
|
shrw %ax # ax = Number of blocks into mem system
|
||||||
|
andw $0x7f, %ax # ax = Number of blocks into current seg
|
||||||
|
addw %bx, %ax # ax = End Block number of transfer
|
||||||
|
cmpw $0x80, %ax # See if it crosses a 64K boundry
|
||||||
|
jle NotCrossing64KBoundry # Branch if not crossing 64K boundry
|
||||||
|
subw $0x80, %ax # ax = Number of blocks past 64K boundry
|
||||||
|
subw %ax, %bx # Decrease transfer size by block overage
|
||||||
|
NotCrossing64KBoundry:
|
||||||
|
popw %ax # restore ax
|
||||||
|
|
||||||
|
pushw %cx
|
||||||
|
movb %dl, %cl # cl = (StartLBA % MaxSector) + 1 = Sector
|
||||||
|
xorw %dx, %dx # dx = 0
|
||||||
|
divw 2(%bp) # ax = ax / (MaxHead + 1) = Cylinder
|
||||||
|
# dx = ax % (MaxHead + 1) = Head
|
||||||
|
|
||||||
|
pushw %bx # Save number of blocks to transfer
|
||||||
|
movb %dl, %dh # dh = Head
|
||||||
|
movw $0x7c00, %bp # bp = 0x7c00
|
||||||
|
movb PhysicalDrive(%bp), %dl # dl = Drive Number
|
||||||
|
movb %al, %ch # ch = Cylinder
|
||||||
|
movb %bl, %al # al = Blocks
|
||||||
|
movb $2, %ah # ah = Function 2
|
||||||
|
movw %di, %bx # es:bx = Buffer address
|
||||||
|
int $0x13
|
||||||
|
jc DiskError
|
||||||
|
popw %bx
|
||||||
|
popw %cx
|
||||||
|
movzwl %bx, %ebx
|
||||||
|
addl %ebx, %esi # StartLBA = StartLBA + NumberOfBlocks
|
||||||
|
subw %bx, %cx # Blocks = Blocks - NumberOfBlocks
|
||||||
|
movw %es, %ax
|
||||||
|
shlw %bx
|
||||||
|
addw %bx, %ax
|
||||||
|
movw %ax, %es # es:di = es:di + NumberOfBlocks*BLOCK_SIZE
|
||||||
|
cmpw $0, %cx
|
||||||
|
jne ReadCylinderLoop
|
||||||
|
popa
|
||||||
|
ret
|
||||||
|
|
||||||
|
DiskError:
|
||||||
|
pushw %cs
|
||||||
|
popw %ds
|
||||||
|
leaw %cs:ErrorString, %si
|
||||||
|
movw $7, %cx
|
||||||
|
jmp PrintStringAndHalt
|
||||||
|
|
||||||
|
PrintStringAndHalt:
|
||||||
|
movw $0xb800, %ax
|
||||||
|
movw %ax, %es
|
||||||
|
movw $160, %di
|
||||||
|
rep
|
||||||
|
movsw
|
||||||
|
Halt:
|
||||||
|
jmp Halt
|
||||||
|
|
||||||
|
ErrorString:
|
||||||
|
.byte 'S', 0x0c, 'E', 0x0c, 'r', 0x0c, 'r', 0x0c, 'o', 0x0c, 'r', 0x0c, '!',0x0c
|
||||||
|
|
||||||
|
#.org 0x0242 # For Code size overflow, Modified this just for pass build
|
||||||
|
LBAOffsetForBootSector:
|
||||||
|
.long 0x0
|
||||||
|
|
||||||
|
#.org 0x0227 # For Code size overflow, Modified this just for pass build
|
||||||
|
.word 0xaa55
|
||||||
|
|
||||||
|
#******************************************************************************
|
||||||
|
#******************************************************************************
|
||||||
|
#******************************************************************************
|
||||||
|
|
||||||
|
.equ DELAY_PORT, 0x0ed # Port to use for 1uS delay
|
||||||
|
.equ KBD_CONTROL_PORT, 0x060 # 8042 control port
|
||||||
|
.equ KBD_STATUS_PORT, 0x064 # 8042 status port
|
||||||
|
.equ WRITE_DATA_PORT_CMD, 0x0d1 # 8042 command to write the data port
|
||||||
|
.equ ENABLE_A20_CMD, 0x0df # 8042 command to enable A20
|
||||||
|
|
||||||
|
#.org 0x200
|
||||||
|
jmp start
|
||||||
|
Em64String:
|
||||||
|
.byte 'E', 0x0c, 'm', 0x0c, '6', 0x0c, '4', 0x0c, 'T', 0x0c, ' ', 0x0c, 'U', 0x0c, 'n', 0x0c, 's', 0x0c, 'u', 0x0c, 'p', 0x0c, 'p', 0x0c, 'o', 0x0c, 'r', 0x0c, 't', 0x0c, 'e', 0x0c, 'd', 0x0c, '!', 0x0c
|
||||||
|
|
||||||
|
start:
|
||||||
|
movw %cs, %ax
|
||||||
|
movw %ax, %ds
|
||||||
|
movw %ax, %es
|
||||||
|
movw %ax, %ss
|
||||||
|
movw $MyStack, %sp
|
||||||
|
|
||||||
|
# mov ax,0b800h
|
||||||
|
# mov es,ax
|
||||||
|
# mov byte ptr es:[160],'a'
|
||||||
|
# mov ax,cs
|
||||||
|
# mov es,ax
|
||||||
|
|
||||||
|
movl $0, %ebx
|
||||||
|
leal MemoryMap, %edi
|
||||||
|
MemMapLoop:
|
||||||
|
movl $0xe820, %eax
|
||||||
|
movl $20, %ecx
|
||||||
|
movl 0x534d4150, %edx # SMAP
|
||||||
|
int $0x15
|
||||||
|
jc MemMapDone
|
||||||
|
addl $20, %edi
|
||||||
|
cmpl $0, %ebx
|
||||||
|
je MemMapDone
|
||||||
|
jmp MemMapLoop
|
||||||
|
MemMapDone:
|
||||||
|
leal MemoryMap, %eax
|
||||||
|
subl %eax, %edi # Get the address of the memory map
|
||||||
|
movl %edi, MemoryMapSize # Save the size of the memory map
|
||||||
|
|
||||||
|
xorl %ebx, %ebx
|
||||||
|
movw %cs, %bx # BX=segment
|
||||||
|
shll $4, %ebx # BX="linear" address of segment base
|
||||||
|
leal GDT_BASE(%ebx), %eax #
|
||||||
|
movl %eax, (gdtr + 2) #
|
||||||
|
leal IDT_BASE(%ebx), %eax #
|
||||||
|
movl %eax, (idtr + 2) #
|
||||||
|
leal MemoryMapSize(%ebx), %edx #
|
||||||
|
|
||||||
|
addl $0x1000, %ebx # Source of EFI32
|
||||||
|
movl %ebx, JUMP+2
|
||||||
|
addl $0x1000, %ebx
|
||||||
|
movl %ebx, %esi # Source of EFILDR32
|
||||||
|
|
||||||
|
# mov ax,0b800h
|
||||||
|
# mov es,ax
|
||||||
|
# mov byte ptr es:[162],'b'
|
||||||
|
# mov ax,cs
|
||||||
|
# mov es,ax
|
||||||
|
|
||||||
|
#
|
||||||
|
# Enable A20 Gate
|
||||||
|
#
|
||||||
|
|
||||||
|
movw $0x2401, %ax # Enable A20 Gate
|
||||||
|
int $0x15
|
||||||
|
jnc A20GateEnabled # Jump if it suceeded
|
||||||
|
|
||||||
|
#
|
||||||
|
# If INT 15 Function 2401 is not supported, then attempt to Enable A20 manually.
|
||||||
|
#
|
||||||
|
|
||||||
|
call Empty8042InputBuffer # Empty the Input Buffer on the 8042 controller
|
||||||
|
jnz Timeout8042 # Jump if the 8042 timed out
|
||||||
|
outw %ax, $DELAY_PORT # Delay 1 uS
|
||||||
|
mov $WRITE_DATA_PORT_CMD, %al # 8042 cmd to write output port
|
||||||
|
out %al, $KBD_STATUS_PORT # Send command to the 8042
|
||||||
|
call Empty8042InputBuffer # Empty the Input Buffer on the 8042 controller
|
||||||
|
jnz Timeout8042 # Jump if the 8042 timed out
|
||||||
|
mov $ENABLE_A20_CMD, %al # gate address bit 20 on
|
||||||
|
out %al, $KBD_CONTROL_PORT # Send command to thre 8042
|
||||||
|
call Empty8042InputBuffer # Empty the Input Buffer on the 8042 controller
|
||||||
|
movw $25, %cx # Delay 25 uS for the command to complete on the 8042
|
||||||
|
Delay25uS:
|
||||||
|
outw %ax, $DELAY_PORT # Delay 1 uS
|
||||||
|
loop Delay25uS
|
||||||
|
Timeout8042:
|
||||||
|
|
||||||
|
|
||||||
|
A20GateEnabled:
|
||||||
|
|
||||||
|
#
|
||||||
|
# DISABLE INTERRUPTS - Entering Protected Mode
|
||||||
|
#
|
||||||
|
|
||||||
|
cli
|
||||||
|
|
||||||
|
# mov ax,0b800h
|
||||||
|
# mov es,ax
|
||||||
|
# mov byte ptr es:[164],'c'
|
||||||
|
# mov ax,cs
|
||||||
|
# mov es,ax
|
||||||
|
|
||||||
|
.byte 0x66
|
||||||
|
lgdt gdtr
|
||||||
|
.byte 0x66
|
||||||
|
lidt idtr
|
||||||
|
|
||||||
|
movl %cr0, %eax
|
||||||
|
orb $1, %al
|
||||||
|
movl %eax, %cr0
|
||||||
|
|
||||||
|
movl $0x008, %eax # Flat data descriptor
|
||||||
|
movl $0x00400000, %ebp # Destination of EFILDR32
|
||||||
|
movl $0x00070000, %ebx # Length of copy
|
||||||
|
|
||||||
|
JUMP:
|
||||||
|
# jmp far 0010:00020000
|
||||||
|
.byte 0x66
|
||||||
|
.byte 0xea
|
||||||
|
.long 0x00020000
|
||||||
|
.word 0x0010
|
||||||
|
|
||||||
|
Empty8042InputBuffer:
|
||||||
|
movw $0, %cx
|
||||||
|
Empty8042Loop:
|
||||||
|
outw %ax, $DELAY_PORT # Delay 1us
|
||||||
|
in $KBD_STATUS_PORT, %al # Read the 8042 Status Port
|
||||||
|
andb $0x2, %al # Check the Input Buffer Full Flag
|
||||||
|
loopnz Empty8042Loop # Loop until the input buffer is empty or a timout of 65536 uS
|
||||||
|
ret
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# data
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
.align 0x2
|
||||||
|
|
||||||
|
gdtr: .long GDT_END - GDT_BASE - 1 # GDT limit
|
||||||
|
.long 0 # (GDT base gets set above)
|
||||||
|
##############################################################################
|
||||||
|
# global descriptor table (GDT)
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
.align 0x2
|
||||||
|
|
||||||
|
GDT_BASE:
|
||||||
|
# null descriptor
|
||||||
|
.equ NULL_SEL, .-GDT_BASE
|
||||||
|
.word 0 # limit 15:0
|
||||||
|
.word 0 # base 15:0
|
||||||
|
.byte 0 # base 23:16
|
||||||
|
.byte 0 # type
|
||||||
|
.byte 0 # limit 19:16, flags
|
||||||
|
.byte 0 # base 31:24
|
||||||
|
|
||||||
|
# linear data segment descriptor
|
||||||
|
.equ LINEAR_SEL, .-GDT_BASE
|
||||||
|
.word 0xFFFF # limit 0xFFFFF
|
||||||
|
.word 0 # base 0
|
||||||
|
.byte 0
|
||||||
|
.byte 0x92 # present, ring 0, data, expand-up, writable
|
||||||
|
.byte 0xCF # page-granular, 32-bit
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
# linear code segment descriptor
|
||||||
|
.equ LINEAR_CODE_SEL, .-GDT_BASE
|
||||||
|
.word 0xFFFF # limit 0xFFFFF
|
||||||
|
.word 0 # base 0
|
||||||
|
.byte 0
|
||||||
|
.byte 0x9A # present, ring 0, data, expand-up, writable
|
||||||
|
.byte 0xCF # page-granular, 32-bit
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
# system data segment descriptor
|
||||||
|
.equ SYS_DATA_SEL, .-GDT_BASE
|
||||||
|
.word 0xFFFF # limit 0xFFFFF
|
||||||
|
.word 0 # base 0
|
||||||
|
.byte 0
|
||||||
|
.byte 0x92 # present, ring 0, data, expand-up, writable
|
||||||
|
.byte 0xCF # page-granular, 32-bit
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
# system code segment descriptor
|
||||||
|
.equ SYS_CODE_SEL, .-GDT_BASE
|
||||||
|
.word 0xFFFF # limit 0xFFFFF
|
||||||
|
.word 0 # base 0
|
||||||
|
.byte 0
|
||||||
|
.byte 0x9A # present, ring 0, data, expand-up, writable
|
||||||
|
.byte 0xCF # page-granular, 32-bit
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
# spare segment descriptor
|
||||||
|
.equ SPARE3_SEL, .-GDT_BASE
|
||||||
|
.word 0 # limit 0xFFFFF
|
||||||
|
.word 0 # base 0
|
||||||
|
.byte 0
|
||||||
|
.byte 0 # present, ring 0, data, expand-up, writable
|
||||||
|
.byte 0 # page-granular, 32-bit
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
# spare segment descriptor
|
||||||
|
.equ SPARE4_SEL, .-GDT_BASE
|
||||||
|
.word 0 # limit 0xFFFFF
|
||||||
|
.word 0 # base 0
|
||||||
|
.byte 0
|
||||||
|
.byte 0 # present, ring 0, data, expand-up, writable
|
||||||
|
.byte 0 # page-granular, 32-bit
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
# spare segment descriptor
|
||||||
|
.equ SPARE5_SEL, .-GDT_BASE
|
||||||
|
.word 0 # limit 0xFFFFF
|
||||||
|
.word 0 # base 0
|
||||||
|
.byte 0
|
||||||
|
.byte 0 # present, ring 0, data, expand-up, writable
|
||||||
|
.byte 0 # page-granular, 32-bit
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
GDT_END:
|
||||||
|
|
||||||
|
.align 0x2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
idtr: .long IDT_END - IDT_BASE - 1 # IDT limit
|
||||||
|
.long 0 # (IDT base gets set above)
|
||||||
|
##############################################################################
|
||||||
|
# interrupt descriptor table (IDT)
|
||||||
|
#
|
||||||
|
# Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ
|
||||||
|
# mappings. This implementation only uses the system timer and all other
|
||||||
|
# IRQs will remain masked. The descriptors for vectors 33+ are provided
|
||||||
|
# for convenience.
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
#idt_tag db "IDT",0
|
||||||
|
.align 0x2
|
||||||
|
|
||||||
|
IDT_BASE:
|
||||||
|
# divide by zero (INT 0)
|
||||||
|
.equ DIV_ZERO_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# debug exception (INT 1)
|
||||||
|
.equ DEBUG_EXCEPT_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# NMI (INT 2)
|
||||||
|
.equ NMI_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# soft breakpoint (INT 3)
|
||||||
|
.equ BREAKPOINT_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# overflow (INT 4)
|
||||||
|
.equ OVERFLOW_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# bounds check (INT 5)
|
||||||
|
.equ BOUNDS_CHECK_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# invalid opcode (INT 6)
|
||||||
|
.equ INVALID_OPCODE_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# device not available (INT 7)
|
||||||
|
.equ DEV_NOT_AVAIL_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# double fault (INT 8)
|
||||||
|
.equ DOUBLE_FAULT_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# Coprocessor segment overrun - reserved (INT 9)
|
||||||
|
.equ RSVD_INTR_SEL1, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# invalid TSS (INT 0x0a)
|
||||||
|
.equ INVALID_TSS_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# segment not present (INT 0x0b)
|
||||||
|
.equ SEG_NOT_PRESENT_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# stack fault (INT 0x0c)
|
||||||
|
.equ STACK_FAULT_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# general protection (INT 0x0d)
|
||||||
|
.equ GP_FAULT_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# page fault (INT 0x0e)
|
||||||
|
.equ PAGE_FAULT_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# Intel reserved - do not use (INT 0x0f)
|
||||||
|
.equ RSVD_INTR_SEL2, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# floating point error (INT 0x10)
|
||||||
|
.equ FLT_POINT_ERR_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# alignment check (INT 0x11)
|
||||||
|
.equ ALIGNMENT_CHECK_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# machine check (INT 0x12)
|
||||||
|
.equ MACHINE_CHECK_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# SIMD floating-point exception (INT 0x13)
|
||||||
|
.equ SIMD_EXCEPTION_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# 85 unspecified descriptors, First 12 of them are reserved, the rest are avail
|
||||||
|
.fill 85 * 8, 1, 0 # db (85 * 8) dup(0)
|
||||||
|
|
||||||
|
# IRQ 0 (System timer) - (INT 0x68)
|
||||||
|
.equ IRQ0_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 1 (8042 Keyboard controller) - (INT 0x69)
|
||||||
|
.equ IRQ1_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 0x6a)
|
||||||
|
.equ IRQ2_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 3 (COM 2) - (INT 0x6b)
|
||||||
|
.equ IRQ3_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 4 (COM 1) - (INT 0x6c)
|
||||||
|
.equ IRQ4_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 5 (LPT 2) - (INT 0x6d)
|
||||||
|
.equ IRQ5_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 6 (Floppy controller) - (INT 0x6e)
|
||||||
|
.equ IRQ6_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 7 (LPT 1) - (INT 0x6f)
|
||||||
|
.equ IRQ7_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 8 (RTC Alarm) - (INT 0x70)
|
||||||
|
.equ IRQ8_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 9 - (INT 0x71)
|
||||||
|
.equ IRQ9_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 10 - (INT 0x72)
|
||||||
|
.equ IRQ10_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 11 - (INT 0x73)
|
||||||
|
.equ IRQ11_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 12 (PS/2 mouse) - (INT 0x74)
|
||||||
|
.equ IRQ12_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 13 (Floating point error) - (INT 0x75)
|
||||||
|
.equ IRQ13_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 14 (Secondary IDE) - (INT 0x76)
|
||||||
|
.equ IRQ14_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
# IRQ 15 (Primary IDE) - (INT 0x77)
|
||||||
|
.equ IRQ15_SEL, .-IDT_BASE
|
||||||
|
.word 0 # offset 15:0
|
||||||
|
.long SYS_CODE_SEL # selector 15:0
|
||||||
|
.byte 0 # 0 for interrupt gate
|
||||||
|
.byte 0x0e | 0x80 # (10001110)type = 386 interrupt gate, present
|
||||||
|
.word 0 # offset 31:16
|
||||||
|
|
||||||
|
IDT_END:
|
||||||
|
|
||||||
|
.align 0x2
|
||||||
|
|
||||||
|
MemoryMapSize: .long 0
|
||||||
|
MemoryMap: .long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0
|
||||||
|
|
||||||
|
.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
|
||||||
|
.org 0x0fe0
|
||||||
|
MyStack:
|
||||||
|
# below is the pieces of the IVT that is used to redirect INT 68h - 6fh
|
||||||
|
# back to INT 08h - 0fh when in real mode... It is 'org'ed to a
|
||||||
|
# known low address (20f00) so it can be set up by PlMapIrqToVect in
|
||||||
|
# 8259.c
|
||||||
|
|
||||||
|
int $8
|
||||||
|
iret
|
||||||
|
|
||||||
|
int $9
|
||||||
|
iret
|
||||||
|
|
||||||
|
int $10
|
||||||
|
iret
|
||||||
|
|
||||||
|
int $11
|
||||||
|
iret
|
||||||
|
|
||||||
|
int $12
|
||||||
|
iret
|
||||||
|
|
||||||
|
int $13
|
||||||
|
iret
|
||||||
|
|
||||||
|
int $14
|
||||||
|
iret
|
||||||
|
|
||||||
|
int $15
|
||||||
|
iret
|
||||||
|
|
||||||
|
|
||||||
|
.org 0x0ffe
|
||||||
|
BlockSignature:
|
||||||
|
.word 0xaa55
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user