Home | History | Annotate | Download | only in BootSector
      1 ;------------------------------------------------------------------------------
      2 ;*
      3 ;*   Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
      4 ;*   This program and the accompanying materials                          
      5 ;*   are licensed and made available under the terms and conditions of the BSD License         
      6 ;*   which accompanies this distribution.  The full text of the license may be found at        
      7 ;*   http://opensource.org/licenses/bsd-license.php                                            
      8 ;*                                                                                             
      9 ;*   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
     10 ;*   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
     11 ;*   
     12 ;*    st16_64.asm
     13 ;*  
     14 ;*   Abstract:
     15 ;*
     16 ;------------------------------------------------------------------------------
     17 
     18         .model  small
     19         .stack
     20         .486p
     21         .code
     22 
     23 FAT_DIRECTORY_ENTRY_SIZE    EQU     020h
     24 FAT_DIRECTORY_ENTRY_SHIFT   EQU     5
     25 BLOCK_SIZE                  EQU     0200h
     26 BLOCK_MASK                  EQU     01ffh
     27 BLOCK_SHIFT                 EQU     9
     28 
     29         org 0h
     30 Ia32Jump:
     31   jmp   BootSectorEntryPoint  ; JMP inst    - 3 bytes
     32   nop
     33 
     34 OemId             db  "INTEL   "    ; OemId               - 8 bytes
     35 
     36 SectorSize        dw  0             ; Sector Size         - 16 bits
     37 SectorsPerCluster db  0             ; Sector Per Cluster  - 8 bits
     38 ReservedSectors   dw  0             ; Reserved Sectors    - 16 bits
     39 NoFats            db  0             ; Number of FATs      - 8 bits
     40 RootEntries       dw  0             ; Root Entries        - 16 bits
     41 Sectors           dw  0             ; Number of Sectors   - 16 bits
     42 Media             db  0             ; Media               - 8 bits  - ignored
     43 SectorsPerFat     dw  0             ; Sectors Per FAT     - 16 bits
     44 SectorsPerTrack   dw  0             ; Sectors Per Track   - 16 bits - ignored
     45 Heads             dw  0             ; Heads               - 16 bits - ignored
     46 HiddenSectors     dd  0             ; Hidden Sectors      - 32 bits - ignored
     47 LargeSectors      dd  0             ; Large Sectors       - 32 bits 
     48 PhysicalDrive     db  0             ; PhysicalDriveNumber - 8 bits  - ignored
     49 CurrentHead       db  0             ; Current Head        - 8 bits
     50 Signature         db  0             ; Signature           - 8 bits  - ignored
     51 VolId             db  "    "        ; Volume Serial Number- 4 bytes
     52 FatLabel          db  "           " ; Label               - 11 bytes
     53 SystemId          db  "FAT16   "    ; SystemId            - 8 bytes
     54 
     55 BootSectorEntryPoint:
     56         ASSUME  ds:@code
     57         ASSUME  ss:@code
     58       ; ds = 1000, es = 2000 + x (size of first cluster >> 4)
     59       ; cx = Start Cluster of EfiLdr
     60       ; dx = Start Cluster of Efivar.bin
     61 
     62 ; Re use the BPB data stored in Boot Sector
     63         mov     bp,07c00h
     64 
     65         push    cx
     66 ; Read Efivar.bin
     67 ;       1000:dx    = DirectoryEntry of Efivar.bin -> BS.com has filled already
     68         mov     ax,01900h
     69         mov     es,ax
     70         test    dx,dx
     71         jnz     CheckVarStoreSize
     72 
     73         mov     al,1
     74 NoVarStore:
     75         push    es
     76 ; Set the 5th byte start @ 0:19000 to non-zero indicating we should init var store header in DxeIpl
     77         mov     byte ptr es:[4],al
     78         jmp     SaveVolumeId
     79 
     80 CheckVarStoreSize:
     81         mov     di,dx
     82         cmp     dword ptr ds:[di+2], 04000h
     83         mov     al,2
     84         jne     NoVarStore
     85 
     86 LoadVarStore:
     87         mov     al,0
     88         mov     byte ptr es:[4],al
     89         mov     cx,word ptr[di]
     90 ;       ES:DI = 1500:0
     91         xor     di,di
     92         push    es
     93         mov     ax,01500h
     94         mov     es,ax
     95         call    ReadFile
     96 SaveVolumeId:
     97         pop     es
     98         mov     ax,word ptr [bp+VolId]
     99         mov     word ptr es:[0],ax                  ; Save Volume Id to 0:19000. we will find the correct volume according to this VolumeId
    100         mov     ax,word ptr [bp+VolId+2]
    101         mov     word ptr es:[2],ax
    102 
    103 ; Read Efildr
    104         pop     cx
    105 ;       cx    = Start Cluster of Efildr -> BS.com has filled already
    106 ;       ES:DI = 2000:0, first cluster will be read again
    107         xor     di,di                               ; di = 0
    108         mov     ax,02000h
    109         mov     es,ax
    110         call    ReadFile
    111         mov     ax,cs
    112         mov     word ptr cs:[JumpSegment],ax
    113 
    114 CheckEm64T:
    115         mov  eax, 080000001h
    116 ;        cpuid
    117         dw   0A20Fh
    118         bt   edx, 29
    119         jc   CheckEm64TPass
    120         push cs
    121         pop  ds
    122         lea  si, [Em64String]
    123         mov  cx, 18
    124         jmp  PrintStringAndHalt
    125 CheckEm64TPass:
    126 JumpFarInstruction:
    127         db      0eah
    128 JumpOffset:
    129         dw      0200h
    130 JumpSegment:
    131         dw      2000h
    132 
    133 
    134 
    135 ; ****************************************************************************
    136 ; ReadFile
    137 ;
    138 ; Arguments:
    139 ;   CX    = Start Cluster of File
    140 ;   ES:DI = Buffer to store file content read from disk
    141 ;
    142 ; Return:
    143 ;   (ES << 4 + DI) = end of file content Buffer
    144 ;
    145 ; ****************************************************************************
    146 ReadFile:
    147 ; si      = NumberOfClusters
    148 ; cx      = ClusterNumber
    149 ; dx      = CachedFatSectorNumber
    150 ; ds:0000 = CacheFatSectorBuffer
    151 ; es:di   = Buffer to load file
    152 ; bx      = NextClusterNumber
    153         pusha
    154         mov     si,1                                ; NumberOfClusters = 1
    155         push    cx                                  ; Push Start Cluster onto stack
    156         mov     dx,0fffh                            ; CachedFatSectorNumber = 0xfff
    157 FatChainLoop:
    158         mov     ax,cx                               ; ax = ClusterNumber    
    159         and     ax,0fff8h                           ; ax = ax & 0xfff8
    160         cmp     ax,0fff8h                           ; See if this is the last cluster
    161         je      FoundLastCluster                    ; Jump if last cluster found
    162         mov     ax,cx                               ; ax = ClusterNumber
    163         shl     ax,1                                ; FatOffset = ClusterNumber * 2
    164         push    si                                  ; Save si
    165         mov     si,ax                               ; si = FatOffset
    166         shr     ax,BLOCK_SHIFT                      ; ax = FatOffset >> BLOCK_SHIFT
    167         add     ax,word ptr [bp+ReservedSectors]    ; ax = FatSectorNumber = ReservedSectors + (FatOffset >> BLOCK_OFFSET)
    168         and     si,BLOCK_MASK                       ; si = FatOffset & BLOCK_MASK
    169         cmp     ax,dx                               ; Compare FatSectorNumber to CachedFatSectorNumber
    170         je      SkipFatRead
    171         mov     bx,2                                
    172         push    es
    173         push    ds
    174         pop     es
    175         call    ReadBlocks                          ; Read 2 blocks starting at AX storing at ES:DI
    176         pop     es
    177         mov     dx,ax                               ; CachedFatSectorNumber = FatSectorNumber
    178 SkipFatRead:
    179         mov     bx,word ptr [si]                    ; bx = NextClusterNumber
    180         mov     ax,cx                               ; ax = ClusterNumber
    181         pop     si                                  ; Restore si
    182         dec     bx                                  ; bx = NextClusterNumber - 1
    183         cmp     bx,cx                               ; See if (NextClusterNumber-1)==ClusterNumber
    184         jne     ReadClusters
    185         inc     bx                                  ; bx = NextClusterNumber
    186         inc     si                                  ; NumberOfClusters++
    187         mov     cx,bx                               ; ClusterNumber = NextClusterNumber
    188         jmp     FatChainLoop
    189 ReadClusters:
    190         inc     bx
    191         pop     ax                                  ; ax = StartCluster
    192         push    bx                                  ; StartCluster = NextClusterNumber
    193         mov     cx,bx                               ; ClusterNumber = NextClusterNumber
    194         sub     ax,2                                ; ax = StartCluster - 2
    195         xor     bh,bh                               
    196         mov     bl,byte ptr [bp+SectorsPerCluster]  ; bx = SectorsPerCluster
    197         mul     bx                                  ; ax = (StartCluster - 2) * SectorsPerCluster
    198         add     ax, word ptr [bp]                   ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
    199         push    ax                                  ; save start sector
    200         mov     ax,si                               ; ax = NumberOfClusters
    201         mul     bx                                  ; ax = NumberOfClusters * SectorsPerCluster
    202         mov     bx,ax                               ; bx = Number of Sectors
    203         pop     ax                                  ; ax = Start Sector
    204         call    ReadBlocks
    205         mov     si,1                                ; NumberOfClusters = 1
    206         jmp     FatChainLoop
    207 FoundLastCluster:
    208         pop     cx
    209         popa
    210         ret
    211 
    212 
    213 ; ****************************************************************************
    214 ; ReadBlocks - Reads a set of blocks from a block device
    215 ;
    216 ; AX    = Start LBA
    217 ; BX    = Number of Blocks to Read
    218 ; ES:DI = Buffer to store sectors read from disk
    219 ; ****************************************************************************
    220 
    221 ; cx = Blocks
    222 ; bx = NumberOfBlocks
    223 ; si = StartLBA
    224 
    225 ReadBlocks:
    226         pusha
    227         add     eax,dword ptr [bp+LBAOffsetForBootSector]    ; Add LBAOffsetForBootSector to Start LBA
    228         add     eax,dword ptr [bp+HiddenSectors]    ; Add HiddenSectors to Start LBA
    229         mov     esi,eax                             ; esi = Start LBA
    230         mov     cx,bx                               ; cx = Number of blocks to read
    231 ReadCylinderLoop:
    232         mov     bp,07bfch                           ; bp = 0x7bfc
    233         mov     eax,esi                             ; eax = Start LBA
    234         xor     edx,edx                             ; edx = 0
    235         movzx   ebx,word ptr [bp]                   ; bx = MaxSector
    236         div     ebx                                 ; ax = StartLBA / MaxSector
    237         inc     dx                                  ; dx = (StartLBA % MaxSector) + 1
    238 
    239         mov     bx,word ptr [bp]                    ; bx = MaxSector
    240         sub     bx,dx                               ; bx = MaxSector - Sector
    241         inc     bx                                  ; bx = MaxSector - Sector + 1
    242         cmp     cx,bx                               ; Compare (Blocks) to (MaxSector - Sector + 1)
    243         jg      LimitTransfer
    244         mov     bx,cx                               ; bx = Blocks
    245 LimitTransfer:
    246         push    ax                                  ; save ax
    247         mov     ax,es                               ; ax = es
    248         shr     ax,(BLOCK_SHIFT-4)                  ; ax = Number of blocks into mem system
    249         and     ax,07fh                             ; ax = Number of blocks into current seg
    250         add     ax,bx                               ; ax = End Block number of transfer
    251         cmp     ax,080h                             ; See if it crosses a 64K boundry
    252         jle     NotCrossing64KBoundry               ; Branch if not crossing 64K boundry
    253         sub     ax,080h                             ; ax = Number of blocks past 64K boundry
    254         sub     bx,ax                               ; Decrease transfer size by block overage
    255 NotCrossing64KBoundry:
    256         pop     ax                                  ; restore ax
    257 
    258         push    cx
    259         mov     cl,dl                               ; cl = (StartLBA % MaxSector) + 1 = Sector
    260         xor     dx,dx                               ; dx = 0
    261         div     word ptr [bp+2]                     ; ax = ax / (MaxHead + 1) = Cylinder  
    262                                                     ; dx = ax % (MaxHead + 1) = Head
    263 
    264         push    bx                                  ; Save number of blocks to transfer
    265         mov     dh,dl                               ; dh = Head
    266         mov     bp,07c00h                           ; bp = 0x7c00
    267         mov     dl,byte ptr [bp+PhysicalDrive]      ; dl = Drive Number
    268         mov     ch,al                               ; ch = Cylinder
    269         mov     al,bl                               ; al = Blocks
    270         mov     ah,2                                ; ah = Function 2
    271         mov     bx,di                               ; es:bx = Buffer address
    272         int     013h
    273         jc      DiskError
    274         pop     bx
    275         pop     cx
    276         movzx   ebx,bx
    277         add     esi,ebx                             ; StartLBA = StartLBA + NumberOfBlocks
    278         sub     cx,bx                               ; Blocks = Blocks - NumberOfBlocks
    279         mov     ax,es
    280         shl     bx,(BLOCK_SHIFT-4)
    281         add     ax,bx
    282         mov     es,ax                               ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE
    283         cmp     cx,0
    284         jne     ReadCylinderLoop
    285         popa
    286         ret
    287 
    288 DiskError:
    289         push cs
    290         pop  ds
    291         lea  si, [ErrorString]
    292         mov  cx, 7
    293         jmp  PrintStringAndHalt
    294 
    295 PrintStringAndHalt:
    296         mov  ax,0b800h
    297         mov  es,ax
    298         mov  di,160
    299         rep  movsw
    300 Halt:
    301         jmp   Halt
    302 
    303 ErrorString:
    304         db 'S', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch
    305 
    306         org     01fah
    307 LBAOffsetForBootSector:
    308         dd      0h
    309 
    310         org     01feh
    311         dw      0aa55h
    312 
    313 ;******************************************************************************
    314 ;******************************************************************************
    315 ;******************************************************************************
    316 
    317 DELAY_PORT           equ     0edh    ; Port to use for 1uS delay
    318 KBD_CONTROL_PORT     equ     060h    ; 8042 control port     
    319 KBD_STATUS_PORT      equ     064h    ; 8042 status port      
    320 WRITE_DATA_PORT_CMD  equ     0d1h    ; 8042 command to write the data port
    321 ENABLE_A20_CMD       equ     0dfh    ; 8042 command to enable A20
    322 
    323         org     200h
    324         jmp start
    325 Em64String:
    326         db 'E', 0ch, 'm', 0ch, '6', 0ch, '4', 0ch, 'T', 0ch, ' ', 0ch, 'U', 0ch, 'n', 0ch, 's', 0ch, 'u', 0ch, 'p', 0ch, 'p', 0ch, 'o', 0ch, 'r', 0ch, 't', 0ch, 'e', 0ch, 'd', 0ch, '!', 0ch
    327 
    328 start:  
    329         mov ax,cs
    330         mov ds,ax
    331         mov es,ax
    332         mov ss,ax
    333         mov sp,MyStack
    334 
    335 ;        mov ax,0b800h
    336 ;        mov es,ax
    337 ;        mov byte ptr es:[160],'a'
    338 ;        mov ax,cs
    339 ;        mov es,ax
    340 
    341         mov ebx,0
    342         lea edi,MemoryMap
    343 MemMapLoop:
    344         mov eax,0e820h
    345         mov ecx,20
    346         mov edx,'SMAP'
    347         int 15h
    348         jc  MemMapDone
    349         add edi,20
    350         cmp ebx,0
    351         je  MemMapDone
    352         jmp MemMapLoop
    353 MemMapDone:
    354         lea eax,MemoryMap
    355         sub edi,eax                         ; Get the address of the memory map
    356         mov dword ptr [MemoryMapSize],edi   ; Save the size of the memory map
    357 
    358         xor     ebx,ebx
    359         mov     bx,cs                       ; BX=segment
    360         shl     ebx,4                       ; BX="linear" address of segment base
    361         lea     eax,[GDT_BASE + ebx]        ; EAX=PHYSICAL address of gdt
    362         mov     dword ptr [gdtr + 2],eax    ; Put address of gdt into the gdtr
    363         lea     eax,[IDT_BASE + ebx]        ; EAX=PHYSICAL address of idt
    364         mov     dword ptr [idtr + 2],eax    ; Put address of idt into the idtr
    365         lea     edx,[MemoryMapSize + ebx]   ; Physical base address of the memory map
    366 
    367 ;        mov ax,0b800h
    368 ;        mov es,ax
    369 ;        mov byte ptr es:[162],'b'
    370 ;        mov ax,cs
    371 ;        mov es,ax
    372 
    373 ;
    374 ; Enable A20 Gate 
    375 ;
    376 
    377         mov ax,2401h                        ; Enable A20 Gate
    378         int 15h
    379         jnc A20GateEnabled                  ; Jump if it suceeded
    380 
    381 ;
    382 ; If INT 15 Function 2401 is not supported, then attempt to Enable A20 manually.
    383 ;
    384 
    385         call    Empty8042InputBuffer        ; Empty the Input Buffer on the 8042 controller
    386         jnz     Timeout8042                 ; Jump if the 8042 timed out
    387         out     DELAY_PORT,ax               ; Delay 1 uS
    388         mov     al,WRITE_DATA_PORT_CMD      ; 8042 cmd to write output port
    389         out     KBD_STATUS_PORT,al          ; Send command to the 8042
    390         call    Empty8042InputBuffer        ; Empty the Input Buffer on the 8042 controller
    391         jnz     Timeout8042                 ; Jump if the 8042 timed out
    392         mov     al,ENABLE_A20_CMD           ; gate address bit 20 on
    393         out     KBD_CONTROL_PORT,al         ; Send command to thre 8042
    394         call    Empty8042InputBuffer        ; Empty the Input Buffer on the 8042 controller
    395         mov     cx,25                       ; Delay 25 uS for the command to complete on the 8042
    396 Delay25uS:
    397         out     DELAY_PORT,ax               ; Delay 1 uS
    398         loop    Delay25uS                       
    399 Timeout8042:
    400 
    401 
    402 A20GateEnabled:
    403 
    404 ;
    405 ; DISABLE INTERRUPTS - Entering Protected Mode
    406 ;
    407 
    408         cli                             
    409 
    410 ;        mov ax,0b800h
    411 ;        mov es,ax
    412 ;        mov byte ptr es:[164],'c'
    413 ;        mov ax,cs
    414 ;        mov es,ax
    415 
    416     lea eax, OffsetIn32BitProtectedMode
    417     add eax, 20000h + 6h
    418     mov dword ptr[OffsetIn32BitProtectedMode], eax
    419 
    420     lea eax, OffsetInLongMode
    421     add eax, 20000h + 6h
    422     mov dword ptr[OffsetInLongMode], eax
    423 
    424     ;
    425     ; load GDT
    426     ;
    427     db      66h     
    428     lgdt    fword ptr [gdtr]
    429 
    430     ;
    431     ; Enable Protect Mode (set CR0.PE=1)
    432     ;
    433     mov   eax, cr0        ; Read CR0.
    434     or    eax, 1h         ; Set PE=1
    435     mov   cr0, eax        ; Write CR0.
    436     db    066h
    437     db    0eah                        ; jmp far 16:32
    438 OffsetIn32BitProtectedMode:
    439     dd    00000000h                   ; offset $+8   (In32BitProtectedMode)
    440     dw    10h                         ; selector  (flat CS)
    441 In32BitProtectedMode:
    442 
    443 ;
    444 ; Entering Long Mode
    445 ;
    446     db   66h
    447     mov  ax, 8
    448     mov  ds, ax
    449     mov  es, ax
    450     mov  ss, ax
    451 
    452     ;
    453     ; Enable the 64-bit page-translation-table entries by
    454     ; setting CR4.PAE=1 (this is _required_ before activating
    455     ; long mode). Paging is not enabled until after long mode
    456     ; is enabled.
    457     ;
    458     db 0fh
    459     db 20h
    460     db 0e0h
    461 ;    mov eax, cr4
    462     bts eax, 5
    463     db 0fh
    464     db 22h
    465     db 0e0h
    466 ;    mov cr4, eax
    467 
    468     ;
    469     ; This is the Trapolean Page Tables that are guarenteed
    470     ;  under 4GB.
    471     ;
    472     ; Address Map:
    473     ;    10000 ~    12000 - efildr (loaded)
    474     ;    20000 ~    21000 - start64.com
    475     ;    21000 ~    22000 - efi64.com
    476     ;    22000 ~    90000 - efildr
    477     ;    90000 ~    96000 - 4G pagetable (will be reload later)
    478     ;
    479     db  0b8h
    480     dd  90000h
    481 ;    mov eax, 90000h
    482     mov cr3, eax
    483 
    484     ;
    485     ; Enable long mode (set EFER.LME=1).
    486     ;
    487     db  0b9h
    488     dd  0c0000080h
    489 ;    mov   ecx, 0c0000080h ; EFER MSR number.
    490     db 0fh
    491     db 32h
    492 ;    rdmsr                 ; Read EFER.
    493     db    0fh
    494     db    0bah
    495     db    0e8h
    496     db    08h
    497 ;    bts   eax, 8          ; Set LME=1.
    498     db 0fh
    499     db 30h
    500 ;    wrmsr                 ; Write EFER.
    501 
    502     ;
    503     ; Enable paging to activate long mode (set CR0.PG=1)
    504     ;
    505     mov   eax, cr0        ; Read CR0.
    506     db    0fh
    507     db    0bah
    508     db    0e8h
    509     db    01fh
    510 ;    bts   eax, 31         ; Set PG=1.
    511     mov   cr0, eax        ; Write CR0.
    512     jmp   GoToLongMode
    513 GoToLongMode:
    514 
    515     db      067h
    516     db      0eah                ; Far Jump $+9:Selector to reload CS
    517 OffsetInLongMode:
    518     dd      00000000            ;   $+9 Offset is ensuing instruction boundary
    519     dw      038h                ;   Selector is our code selector, 38h
    520 
    521 InLongMode:
    522     db   66h
    523     mov     ax, 30h
    524     mov     ds, ax
    525 
    526     db   66h
    527     mov     ax, 18h
    528     mov     es, ax
    529     mov     ss, ax
    530     mov     ds, ax
    531 
    532     db 0bdh
    533     dd 400000h
    534 ;    mov ebp,000400000h                  ; Destination of EFILDR32
    535     db 0bbh
    536     dd 70000h
    537 ;    mov ebx,000070000h                  ; Length of copy
    538 
    539     ;
    540     ; load idt later
    541     ;
    542     db 48h
    543     db 33h
    544     db 0c0h
    545 ;    xor rax, rax
    546     db 66h
    547     mov ax, offset idtr
    548     db 48h
    549     db 05h
    550     dd 20000h
    551 ;    add rax, 20000h
    552 
    553     db 0fh
    554     db 01h
    555     db 18h
    556 ;    lidt    fword ptr [rax]
    557 
    558     db 48h
    559     db 0c7h
    560     db 0c0h
    561     dd 21000h
    562 ;   mov rax, 21000h
    563     db 50h
    564 ;   push rax
    565 
    566 ; ret
    567     db 0c3h
    568 
    569 Empty8042InputBuffer:
    570         mov cx,0
    571 Empty8042Loop:
    572         out     DELAY_PORT,ax               ; Delay 1us
    573         in      al,KBD_STATUS_PORT          ; Read the 8042 Status Port
    574         and     al,02h                      ; Check the Input Buffer Full Flag
    575         loopnz  Empty8042Loop               ; Loop until the input buffer is empty or a timout of 65536 uS
    576         ret
    577 
    578 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    579 ; data
    580 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    581 
    582         align 02h
    583 
    584 gdtr    dw GDT_END - GDT_BASE - 1   ; GDT limit
    585         dd 0                        ; (GDT base gets set above)
    586 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    587 ;   global descriptor table (GDT)
    588 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    589 
    590         align 02h
    591 
    592 public GDT_BASE
    593 GDT_BASE:
    594 ; null descriptor
    595 NULL_SEL            equ $-GDT_BASE          ; Selector [0x0]
    596         dw 0            ; limit 15:0
    597         dw 0            ; base 15:0
    598         db 0            ; base 23:16
    599         db 0            ; type
    600         db 0            ; limit 19:16, flags
    601         db 0            ; base 31:24
    602 
    603 ; linear data segment descriptor
    604 LINEAR_SEL      equ $-GDT_BASE          ; Selector [0x8]
    605         dw 0FFFFh       ; limit 0xFFFFF
    606         dw 0            ; base 0
    607         db 0
    608         db 092h         ; present, ring 0, data, expand-up, writable
    609         db 0CFh                 ; page-granular, 32-bit
    610         db 0
    611 
    612 ; linear code segment descriptor
    613 LINEAR_CODE_SEL equ $-GDT_BASE          ; Selector [0x10]
    614         dw 0FFFFh       ; limit 0xFFFFF
    615         dw 0            ; base 0
    616         db 0
    617         db 09Ah         ; present, ring 0, data, expand-up, writable
    618         db 0CFh                 ; page-granular, 32-bit
    619         db 0
    620 
    621 ; system data segment descriptor
    622 SYS_DATA_SEL    equ $-GDT_BASE          ; Selector [0x18]
    623         dw 0FFFFh       ; limit 0xFFFFF
    624         dw 0            ; base 0
    625         db 0
    626         db 092h         ; present, ring 0, data, expand-up, writable
    627         db 0CFh                 ; page-granular, 32-bit
    628         db 0
    629 
    630 ; system code segment descriptor
    631 SYS_CODE_SEL    equ $-GDT_BASE          ; Selector [0x20]
    632         dw 0FFFFh       ; limit 0xFFFFF
    633         dw 0            ; base 0
    634         db 0
    635         db 09Ah         ; present, ring 0, data, expand-up, writable
    636         db 0CFh                 ; page-granular, 32-bit
    637         db 0
    638 
    639 ; spare segment descriptor
    640 SPARE3_SEL  equ $-GDT_BASE          ; Selector [0x28]
    641         dw 0            ; limit 0xFFFFF
    642         dw 0            ; base 0
    643         db 0
    644         db 0            ; present, ring 0, data, expand-up, writable
    645         db 0            ; page-granular, 32-bit
    646         db 0
    647 
    648 ;
    649 ; system data segment descriptor
    650 ;
    651 SYS_DATA64_SEL    equ $-GDT_BASE          ; Selector [0x30]
    652         dw 0FFFFh       ; limit 0xFFFFF
    653         dw 0            ; base 0
    654         db 0
    655         db 092h         ; P | DPL [1..2] | 1   | 1   | C | R | A
    656         db 0CFh         ; G | D   | L    | AVL | Segment [19..16]
    657         db 0
    658 
    659 ;
    660 ; system code segment descriptor
    661 ;
    662 SYS_CODE64_SEL    equ $-GDT_BASE          ; Selector [0x38]
    663         dw 0FFFFh       ; limit 0xFFFFF
    664         dw 0            ; base 0
    665         db 0
    666         db 09Ah         ; P | DPL [1..2] | 1   | 1   | C | R | A
    667         db 0AFh         ; G | D   | L    | AVL | Segment [19..16]
    668         db 0
    669 
    670 ; spare segment descriptor
    671 SPARE4_SEL  equ $-GDT_BASE            ; Selector [0x40]
    672         dw 0            ; limit 0xFFFFF
    673         dw 0            ; base 0
    674         db 0
    675         db 0            ; present, ring 0, data, expand-up, writable
    676         db 0            ; page-granular, 32-bit
    677         db 0
    678 
    679 GDT_END:
    680 
    681         align 02h
    682 
    683 
    684 
    685 idtr            dw IDT_END - IDT_BASE - 1   ; IDT limit
    686         dq 0                        ; (IDT base gets set above)
    687 
    688 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    689 ;   interrupt descriptor table (IDT)
    690 ;
    691 ;   Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ
    692 ;       mappings.  This implementation only uses the system timer and all other
    693 ;       IRQs will remain masked.  The descriptors for vectors 33+ are provided
    694 ;       for convenience.
    695 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    696 
    697 ;idt_tag db "IDT",0     
    698         align 02h
    699 
    700 public IDT_BASE
    701 IDT_BASE:
    702 ; divide by zero (INT 0)
    703 DIV_ZERO_SEL        equ $-IDT_BASE
    704         dw 0            ; offset 15:0
    705         dw SYS_CODE64_SEL ; selector 15:0
    706         db 0            ; 0 for interrupt gate
    707         db 0eh OR 80h   ; type = 386 interrupt gate, present
    708         dw 0            ; offset 31:16
    709         dd 0            ; offset 63:32
    710         dd 0            ; 0 for reserved
    711 
    712 ; debug exception (INT 1)
    713 DEBUG_EXCEPT_SEL    equ $-IDT_BASE
    714         dw 0            ; offset 15:0
    715         dw SYS_CODE64_SEL ; selector 15:0
    716         db 0            ; 0 for interrupt gate
    717         db 0eh OR 80h   ; type = 386 interrupt gate, present
    718         dw 0            ; offset 31:16
    719         dd 0            ; offset 63:32
    720         dd 0            ; 0 for reserved
    721 
    722 ; NMI (INT 2)
    723 NMI_SEL             equ $-IDT_BASE
    724         dw 0            ; offset 15:0
    725         dw SYS_CODE64_SEL ; selector 15:0
    726         db 0            ; 0 for interrupt gate
    727         db 0eh OR 80h   ; type = 386 interrupt gate, present
    728         dw 0            ; offset 31:16
    729         dd 0            ; offset 63:32
    730         dd 0            ; 0 for reserved
    731 
    732 ; soft breakpoint (INT 3)
    733 BREAKPOINT_SEL      equ $-IDT_BASE
    734         dw 0            ; offset 15:0
    735         dw SYS_CODE64_SEL ; selector 15:0
    736         db 0            ; 0 for interrupt gate
    737         db 0eh OR 80h   ; type = 386 interrupt gate, present
    738         dw 0            ; offset 31:16
    739         dd 0            ; offset 63:32
    740         dd 0            ; 0 for reserved
    741 
    742 ; overflow (INT 4)
    743 OVERFLOW_SEL        equ $-IDT_BASE
    744         dw 0            ; offset 15:0
    745         dw SYS_CODE64_SEL ; selector 15:0
    746         db 0            ; 0 for interrupt gate
    747         db 0eh OR 80h   ; type = 386 interrupt gate, present
    748         dw 0            ; offset 31:16
    749         dd 0            ; offset 63:32
    750         dd 0            ; 0 for reserved
    751 
    752 ; bounds check (INT 5)
    753 BOUNDS_CHECK_SEL    equ $-IDT_BASE
    754         dw 0            ; offset 15:0
    755         dw SYS_CODE64_SEL ; selector 15:0
    756         db 0            ; 0 for interrupt gate
    757         db 0eh OR 80h   ; type = 386 interrupt gate, present
    758         dw 0            ; offset 31:16
    759         dd 0            ; offset 63:32
    760         dd 0            ; 0 for reserved
    761 
    762 ; invalid opcode (INT 6)
    763 INVALID_OPCODE_SEL  equ $-IDT_BASE
    764         dw 0            ; offset 15:0
    765         dw SYS_CODE64_SEL ; selector 15:0
    766         db 0            ; 0 for interrupt gate
    767         db 0eh OR 80h   ; type = 386 interrupt gate, present
    768         dw 0            ; offset 31:16
    769         dd 0            ; offset 63:32
    770         dd 0            ; 0 for reserved
    771 
    772 ; device not available (INT 7)
    773 DEV_NOT_AVAIL_SEL   equ $-IDT_BASE
    774         dw 0            ; offset 15:0
    775         dw SYS_CODE64_SEL ; selector 15:0
    776         db 0            ; 0 for interrupt gate
    777         db 0eh OR 80h   ; type = 386 interrupt gate, present
    778         dw 0            ; offset 31:16
    779         dd 0            ; offset 63:32
    780         dd 0            ; 0 for reserved
    781 
    782 ; double fault (INT 8)
    783 DOUBLE_FAULT_SEL    equ $-IDT_BASE
    784         dw 0            ; offset 15:0
    785         dw SYS_CODE64_SEL ; selector 15:0
    786         db 0            ; 0 for interrupt gate
    787         db 0eh OR 80h   ; type = 386 interrupt gate, present
    788         dw 0            ; offset 31:16
    789         dd 0            ; offset 63:32
    790         dd 0            ; 0 for reserved
    791 
    792 ; Coprocessor segment overrun - reserved (INT 9)
    793 RSVD_INTR_SEL1      equ $-IDT_BASE
    794         dw 0            ; offset 15:0
    795         dw SYS_CODE64_SEL ; selector 15:0
    796         db 0            ; 0 for interrupt gate
    797         db 0eh OR 80h   ; type = 386 interrupt gate, present
    798         dw 0            ; offset 31:16
    799         dd 0            ; offset 63:32
    800         dd 0            ; 0 for reserved
    801 
    802 ; invalid TSS (INT 0ah)
    803 INVALID_TSS_SEL     equ $-IDT_BASE
    804         dw 0            ; offset 15:0
    805         dw SYS_CODE64_SEL ; selector 15:0
    806         db 0            ; 0 for interrupt gate
    807         db 0eh OR 80h   ; type = 386 interrupt gate, present
    808         dw 0            ; offset 31:16
    809         dd 0            ; offset 63:32
    810         dd 0            ; 0 for reserved
    811 
    812 ; segment not present (INT 0bh)
    813 SEG_NOT_PRESENT_SEL equ $-IDT_BASE
    814         dw 0            ; offset 15:0
    815         dw SYS_CODE64_SEL ; selector 15:0
    816         db 0            ; 0 for interrupt gate
    817         db 0eh OR 80h   ; type = 386 interrupt gate, present
    818         dw 0            ; offset 31:16
    819         dd 0            ; offset 63:32
    820         dd 0            ; 0 for reserved
    821 
    822 ; stack fault (INT 0ch)
    823 STACK_FAULT_SEL     equ $-IDT_BASE
    824         dw 0            ; offset 15:0
    825         dw SYS_CODE64_SEL ; selector 15:0
    826         db 0            ; 0 for interrupt gate
    827         db 0eh OR 80h   ; type = 386 interrupt gate, present
    828         dw 0            ; offset 31:16
    829         dd 0            ; offset 63:32
    830         dd 0            ; 0 for reserved
    831 
    832 ; general protection (INT 0dh)
    833 GP_FAULT_SEL        equ $-IDT_BASE
    834         dw 0            ; offset 15:0
    835         dw SYS_CODE64_SEL ; selector 15:0
    836         db 0            ; 0 for interrupt gate
    837         db 0eh OR 80h   ; type = 386 interrupt gate, present
    838         dw 0            ; offset 31:16
    839         dd 0            ; offset 63:32
    840         dd 0            ; 0 for reserved
    841 
    842 ; page fault (INT 0eh)
    843 PAGE_FAULT_SEL      equ $-IDT_BASE
    844         dw 0            ; offset 15:0
    845         dw SYS_CODE64_SEL ; selector 15:0
    846         db 0            ; 0 for interrupt gate
    847         db 0eh OR 80h   ; type = 386 interrupt gate, present
    848         dw 0            ; offset 31:16
    849         dd 0            ; offset 63:32
    850         dd 0            ; 0 for reserved
    851 
    852 ; Intel reserved - do not use (INT 0fh)
    853 RSVD_INTR_SEL2      equ $-IDT_BASE
    854         dw 0            ; offset 15:0
    855         dw SYS_CODE64_SEL ; selector 15:0
    856         db 0            ; 0 for interrupt gate
    857         db 0eh OR 80h   ; type = 386 interrupt gate, present
    858         dw 0            ; offset 31:16
    859         dd 0            ; offset 63:32
    860         dd 0            ; 0 for reserved
    861 
    862 ; floating point error (INT 10h)
    863 FLT_POINT_ERR_SEL   equ $-IDT_BASE
    864         dw 0            ; offset 15:0
    865         dw SYS_CODE64_SEL ; selector 15:0
    866         db 0            ; 0 for interrupt gate
    867         db 0eh OR 80h   ; type = 386 interrupt gate, present
    868         dw 0            ; offset 31:16
    869         dd 0            ; offset 63:32
    870         dd 0            ; 0 for reserved
    871 
    872 ; alignment check (INT 11h)
    873 ALIGNMENT_CHECK_SEL equ $-IDT_BASE
    874         dw 0            ; offset 15:0
    875         dw SYS_CODE64_SEL ; selector 15:0
    876         db 0            ; 0 for interrupt gate
    877         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
    878         dw 0            ; offset 31:16
    879         dd 0            ; offset 63:32
    880         dd 0            ; 0 for reserved
    881 
    882 ; machine check (INT 12h)
    883 MACHINE_CHECK_SEL   equ $-IDT_BASE
    884         dw 0            ; offset 15:0
    885         dw SYS_CODE64_SEL ; selector 15:0
    886         db 0            ; 0 for interrupt gate
    887         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
    888         dw 0            ; offset 31:16
    889         dd 0            ; offset 63:32
    890         dd 0            ; 0 for reserved
    891 
    892 ; SIMD floating-point exception (INT 13h)
    893 SIMD_EXCEPTION_SEL  equ $-IDT_BASE
    894         dw 0            ; offset 15:0
    895         dw SYS_CODE64_SEL ; selector 15:0
    896         db 0            ; 0 for interrupt gate
    897         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
    898         dw 0            ; offset 31:16
    899         dd 0            ; offset 63:32
    900         dd 0            ; 0 for reserved
    901 
    902 ; 85 unspecified descriptors, First 12 of them are reserved, the rest are avail
    903         db (85 * 16) dup(0)
    904         
    905 ; IRQ 0 (System timer) - (INT 68h)
    906 IRQ0_SEL            equ $-IDT_BASE
    907         dw 0            ; offset 15:0
    908         dw SYS_CODE64_SEL ; selector 15:0
    909         db 0            ; 0 for interrupt gate
    910         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
    911         dw 0            ; offset 31:16
    912         dd 0            ; offset 63:32
    913         dd 0            ; 0 for reserved
    914 
    915 ; IRQ 1 (8042 Keyboard controller) - (INT 69h)
    916 IRQ1_SEL            equ $-IDT_BASE
    917         dw 0            ; offset 15:0
    918         dw SYS_CODE64_SEL ; selector 15:0
    919         db 0            ; 0 for interrupt gate
    920         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
    921         dw 0            ; offset 31:16
    922         dd 0            ; offset 63:32
    923         dd 0            ; 0 for reserved
    924 
    925 ; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah)
    926 IRQ2_SEL            equ $-IDT_BASE
    927         dw 0            ; offset 15:0
    928         dw SYS_CODE64_SEL ; selector 15:0
    929         db 0            ; 0 for interrupt gate
    930         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
    931         dw 0            ; offset 31:16
    932         dd 0            ; offset 63:32
    933         dd 0            ; 0 for reserved
    934 
    935 ; IRQ 3 (COM 2) - (INT 6bh)
    936 IRQ3_SEL            equ $-IDT_BASE
    937         dw 0            ; offset 15:0
    938         dw SYS_CODE64_SEL ; selector 15:0
    939         db 0            ; 0 for interrupt gate
    940         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
    941         dw 0            ; offset 31:16
    942         dd 0            ; offset 63:32
    943         dd 0            ; 0 for reserved
    944 
    945 ; IRQ 4 (COM 1) - (INT 6ch)
    946 IRQ4_SEL            equ $-IDT_BASE
    947         dw 0            ; offset 15:0
    948         dw SYS_CODE64_SEL ; selector 15:0
    949         db 0            ; 0 for interrupt gate
    950         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
    951         dw 0            ; offset 31:16
    952         dd 0            ; offset 63:32
    953         dd 0            ; 0 for reserved
    954 
    955 ; IRQ 5 (LPT 2) - (INT 6dh)
    956 IRQ5_SEL            equ $-IDT_BASE
    957         dw 0            ; offset 15:0
    958         dw SYS_CODE64_SEL ; selector 15:0
    959         db 0            ; 0 for interrupt gate
    960         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
    961         dw 0            ; offset 31:16
    962         dd 0            ; offset 63:32
    963         dd 0            ; 0 for reserved
    964 
    965 ; IRQ 6 (Floppy controller) - (INT 6eh)
    966 IRQ6_SEL            equ $-IDT_BASE
    967         dw 0            ; offset 15:0
    968         dw SYS_CODE64_SEL ; selector 15:0
    969         db 0            ; 0 for interrupt gate
    970         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
    971         dw 0            ; offset 31:16
    972         dd 0            ; offset 63:32
    973         dd 0            ; 0 for reserved
    974 
    975 ; IRQ 7 (LPT 1) - (INT 6fh)
    976 IRQ7_SEL            equ $-IDT_BASE
    977         dw 0            ; offset 15:0
    978         dw SYS_CODE64_SEL ; selector 15:0
    979         db 0            ; 0 for interrupt gate
    980         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
    981         dw 0            ; offset 31:16
    982         dd 0            ; offset 63:32
    983         dd 0            ; 0 for reserved
    984 
    985 ; IRQ 8 (RTC Alarm) - (INT 70h)
    986 IRQ8_SEL            equ $-IDT_BASE
    987         dw 0            ; offset 15:0
    988         dw SYS_CODE64_SEL ; selector 15:0
    989         db 0            ; 0 for interrupt gate
    990         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
    991         dw 0            ; offset 31:16
    992         dd 0            ; offset 63:32
    993         dd 0            ; 0 for reserved
    994 
    995 ; IRQ 9 - (INT 71h)
    996 IRQ9_SEL            equ $-IDT_BASE
    997         dw 0            ; offset 15:0
    998         dw SYS_CODE64_SEL ; selector 15:0
    999         db 0            ; 0 for interrupt gate
   1000         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
   1001         dw 0            ; offset 31:16
   1002         dd 0            ; offset 63:32
   1003         dd 0            ; 0 for reserved
   1004 
   1005 ; IRQ 10 - (INT 72h)
   1006 IRQ10_SEL            equ $-IDT_BASE
   1007         dw 0            ; offset 15:0
   1008         dw SYS_CODE64_SEL ; selector 15:0
   1009         db 0            ; 0 for interrupt gate
   1010         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
   1011         dw 0            ; offset 31:16
   1012         dd 0            ; offset 63:32
   1013         dd 0            ; 0 for reserved
   1014 
   1015 ; IRQ 11 - (INT 73h)
   1016 IRQ11_SEL            equ $-IDT_BASE
   1017         dw 0            ; offset 15:0
   1018         dw SYS_CODE64_SEL ; selector 15:0
   1019         db 0            ; 0 for interrupt gate
   1020         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
   1021         dw 0            ; offset 31:16
   1022         dd 0            ; offset 63:32
   1023         dd 0            ; 0 for reserved
   1024 
   1025 ; IRQ 12 (PS/2 mouse) - (INT 74h)
   1026 IRQ12_SEL            equ $-IDT_BASE
   1027         dw 0            ; offset 15:0
   1028         dw SYS_CODE64_SEL ; selector 15:0
   1029         db 0            ; 0 for interrupt gate
   1030         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
   1031         dw 0            ; offset 31:16
   1032         dd 0            ; offset 63:32
   1033         dd 0            ; 0 for reserved
   1034 
   1035 ; IRQ 13 (Floating point error) - (INT 75h)
   1036 IRQ13_SEL            equ $-IDT_BASE
   1037         dw 0            ; offset 15:0
   1038         dw SYS_CODE64_SEL ; selector 15:0
   1039         db 0            ; 0 for interrupt gate
   1040         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
   1041         dw 0            ; offset 31:16
   1042         dd 0            ; offset 63:32
   1043         dd 0            ; 0 for reserved
   1044 
   1045 ; IRQ 14 (Secondary IDE) - (INT 76h)
   1046 IRQ14_SEL            equ $-IDT_BASE
   1047         dw 0            ; offset 15:0
   1048         dw SYS_CODE64_SEL ; selector 15:0
   1049         db 0            ; 0 for interrupt gate
   1050         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
   1051         dw 0            ; offset 31:16
   1052         dd 0            ; offset 63:32
   1053         dd 0            ; 0 for reserved
   1054 
   1055 ; IRQ 15 (Primary IDE) - (INT 77h)
   1056 IRQ15_SEL            equ $-IDT_BASE
   1057         dw 0            ; offset 15:0
   1058         dw SYS_CODE64_SEL ; selector 15:0
   1059         db 0            ; 0 for interrupt gate
   1060         db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
   1061         dw 0            ; offset 31:16
   1062         dd 0            ; offset 63:32
   1063         dd 0            ; 0 for reserved
   1064 
   1065 IDT_END:
   1066 
   1067         align 02h
   1068 
   1069 MemoryMapSize   dd  0
   1070 MemoryMap   dd  0,0,0,0,0,0,0,0
   1071         dd  0,0,0,0,0,0,0,0
   1072         dd  0,0,0,0,0,0,0,0
   1073         dd  0,0,0,0,0,0,0,0
   1074         dd  0,0,0,0,0,0,0,0
   1075         dd  0,0,0,0,0,0,0,0
   1076         dd  0,0,0,0,0,0,0,0
   1077         dd  0,0,0,0,0,0,0,0
   1078         dd  0,0,0,0,0,0,0,0
   1079         dd  0,0,0,0,0,0,0,0
   1080         dd  0,0,0,0,0,0,0,0
   1081         dd  0,0,0,0,0,0,0,0
   1082         dd  0,0,0,0,0,0,0,0
   1083         dd  0,0,0,0,0,0,0,0
   1084         dd  0,0,0,0,0,0,0,0
   1085         dd  0,0,0,0,0,0,0,0
   1086         dd  0,0,0,0,0,0,0,0
   1087         dd  0,0,0,0,0,0,0,0
   1088         dd  0,0,0,0,0,0,0,0
   1089         dd  0,0,0,0,0,0,0,0
   1090         dd  0,0,0,0,0,0,0,0
   1091         dd  0,0,0,0,0,0,0,0
   1092         dd  0,0,0,0,0,0,0,0
   1093         dd  0,0,0,0,0,0,0,0
   1094         dd  0,0,0,0,0,0,0,0
   1095         dd  0,0,0,0,0,0,0,0
   1096         dd  0,0,0,0,0,0,0,0
   1097         dd  0,0,0,0,0,0,0,0
   1098         dd  0,0,0,0,0,0,0,0
   1099         dd  0,0,0,0,0,0,0,0
   1100 
   1101         dd  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
   1102         dd  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
   1103 
   1104         org 0fe0h
   1105 MyStack:    
   1106         ; below is the pieces of the IVT that is used to redirect INT 68h - 6fh
   1107         ;    back to INT 08h - 0fh  when in real mode...  It is 'org'ed to a
   1108         ;    known low address (20f00) so it can be set up by PlMapIrqToVect in
   1109         ;    8259.c
   1110                 
   1111         int 8
   1112         iret
   1113         
   1114         int 9
   1115         iret
   1116         
   1117         int 10
   1118         iret
   1119         
   1120         int 11
   1121         iret
   1122         
   1123         int 12
   1124         iret
   1125         
   1126         int 13
   1127         iret
   1128         
   1129         int 14
   1130         iret
   1131         
   1132         int 15
   1133         iret
   1134         
   1135         
   1136         org 0ffeh
   1137 BlockSignature:
   1138         dw  0aa55h
   1139 
   1140         end 
   1141