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