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