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