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