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