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