]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Port Intel .asm to GNU .S
authorgikidy <gikidy@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 20 Feb 2009 03:11:41 +0000 (03:11 +0000)
committergikidy <gikidy@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 20 Feb 2009 03:11:41 +0000 (03:11 +0000)
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

DuetPkg/BootSector/Mbr.S [new file with mode: 0644]
DuetPkg/BootSector/bootsect.S [new file with mode: 0644]
DuetPkg/BootSector/bs16.S [new file with mode: 0644]
DuetPkg/BootSector/start.S [new file with mode: 0644]

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