1;------------------------------------------------------------------------------
2;*
3;*   Copyright (c) 2006 - 2011, 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;*    start.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
114JumpFarInstruction:
115        db      0eah
116JumpOffset:
117        dw      0200h
118JumpSegment:
119        dw      2000h
120
121
122
123; ****************************************************************************
124; ReadFile
125;
126; Arguments:
127;   CX    = Start Cluster of File
128;   ES:DI = Buffer to store file content read from disk
129;
130; Return:
131;   (ES << 4 + DI) = end of file content Buffer
132;
133; ****************************************************************************
134ReadFile:
135; si      = NumberOfClusters
136; cx      = ClusterNumber
137; dx      = CachedFatSectorNumber
138; ds:0000 = CacheFatSectorBuffer
139; es:di   = Buffer to load file
140; bx      = NextClusterNumber
141        pusha
142        mov     si,1                                ; NumberOfClusters = 1
143        push    cx                                  ; Push Start Cluster onto stack
144        mov     dx,0fffh                            ; CachedFatSectorNumber = 0xfff
145FatChainLoop:
146        mov     ax,cx                               ; ax = ClusterNumber
147        and     ax,0ff8h                            ; ax = ax & 0xff8
148        cmp     ax,0ff8h                            ; See if this is the last cluster
149        je      FoundLastCluster                    ; Jump if last cluster found
150        mov     ax,cx                               ; ax = ClusterNumber
151        shl     ax,1                                ; ax = ClusterNumber * 2
152        add     ax,cx                               ; ax = ClusterNumber * 2 + ClusterNumber = ClusterNumber * 3
153        shr     ax,1                                ; FatOffset = ClusterNumber*3 / 2
154        push    si                                  ; Save si
155        mov     si,ax                               ; si = FatOffset
156        shr     ax,BLOCK_SHIFT                      ; ax = FatOffset >> BLOCK_SHIFT
157        add     ax,word ptr [bp+ReservedSectors]    ; ax = FatSectorNumber = ReservedSectors + (FatOffset >> BLOCK_OFFSET)
158        and     si,BLOCK_MASK                       ; si = FatOffset & BLOCK_MASK
159        cmp     ax,dx                               ; Compare FatSectorNumber to CachedFatSectorNumber
160        je      SkipFatRead
161        mov     bx,2
162        push    es
163        push    ds
164        pop     es
165        call    ReadBlocks                          ; Read 2 blocks starting at AX storing at ES:DI
166        pop     es
167        mov     dx,ax                               ; CachedFatSectorNumber = FatSectorNumber
168SkipFatRead:
169        mov     bx,word ptr [si]                    ; bx = NextClusterNumber
170        mov     ax,cx                               ; ax = ClusterNumber
171        and     ax,1                                ; See if this is an odd cluster number
172        je      EvenFatEntry
173        shr     bx,4                                ; NextClusterNumber = NextClusterNumber >> 4
174EvenFatEntry:
175        and     bx,0fffh                            ; Strip upper 4 bits of NextClusterNumber
176        pop     si                                  ; Restore si
177        dec     bx                                  ; bx = NextClusterNumber - 1
178        cmp     bx,cx                               ; See if (NextClusterNumber-1)==ClusterNumber
179        jne     ReadClusters
180        inc     bx                                  ; bx = NextClusterNumber
181        inc     si                                  ; NumberOfClusters++
182        mov     cx,bx                               ; ClusterNumber = NextClusterNumber
183        jmp     FatChainLoop
184ReadClusters:
185        inc     bx
186        pop     ax                                  ; ax = StartCluster
187        push    bx                                  ; StartCluster = NextClusterNumber
188        mov     cx,bx                               ; ClusterNumber = NextClusterNumber
189        sub     ax,2                                ; ax = StartCluster - 2
190        xor     bh,bh
191        mov     bl,byte ptr [bp+SectorsPerCluster]  ; bx = SectorsPerCluster
192        mul     bx                                  ; ax = (StartCluster - 2) * SectorsPerCluster
193        add     ax, word ptr [bp]                   ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
194        push    ax                                  ; save start sector
195        mov     ax,si                               ; ax = NumberOfClusters
196        mul     bx                                  ; ax = NumberOfClusters * SectorsPerCluster
197        mov     bx,ax                               ; bx = Number of Sectors
198        pop     ax                                  ; ax = Start Sector
199        call    ReadBlocks
200        mov     si,1                                ; NumberOfClusters = 1
201        jmp     FatChainLoop
202FoundLastCluster:
203        pop     cx
204        popa
205        ret
206
207
208; ****************************************************************************
209; ReadBlocks - Reads a set of blocks from a block device
210;
211; AX    = Start LBA
212; BX    = Number of Blocks to Read
213; ES:DI = Buffer to store sectors read from disk
214; ****************************************************************************
215
216; cx = Blocks
217; bx = NumberOfBlocks
218; si = StartLBA
219
220ReadBlocks:
221        pusha
222        add     eax,dword ptr [bp+LBAOffsetForBootSector]    ; Add LBAOffsetForBootSector to Start LBA
223        add     eax,dword ptr [bp+HiddenSectors]    ; Add HiddenSectors to Start LBA
224        mov     esi,eax                             ; esi = Start LBA
225        mov     cx,bx                               ; cx = Number of blocks to read
226ReadCylinderLoop:
227        mov     bp,07bfch                           ; bp = 0x7bfc
228        mov     eax,esi                             ; eax = Start LBA
229        xor     edx,edx                             ; edx = 0
230        movzx   ebx,word ptr [bp]                   ; bx = MaxSector
231        div     ebx                                 ; ax = StartLBA / MaxSector
232        inc     dx                                  ; dx = (StartLBA % MaxSector) + 1
233
234        mov     bx,word ptr [bp]                    ; bx = MaxSector
235        sub     bx,dx                               ; bx = MaxSector - Sector
236        inc     bx                                  ; bx = MaxSector - Sector + 1
237        cmp     cx,bx                               ; Compare (Blocks) to (MaxSector - Sector + 1)
238        jg      LimitTransfer
239        mov     bx,cx                               ; bx = Blocks
240LimitTransfer:
241        push    ax                                  ; save ax
242        mov     ax,es                               ; ax = es
243        shr     ax,(BLOCK_SHIFT-4)                  ; ax = Number of blocks into mem system
244        and     ax,07fh                             ; ax = Number of blocks into current seg
245        add     ax,bx                               ; ax = End Block number of transfer
246        cmp     ax,080h                             ; See if it crosses a 64K boundry
247        jle     NotCrossing64KBoundry               ; Branch if not crossing 64K boundry
248        sub     ax,080h                             ; ax = Number of blocks past 64K boundry
249        sub     bx,ax                               ; Decrease transfer size by block overage
250NotCrossing64KBoundry:
251        pop     ax                                  ; restore ax
252
253        push    cx
254        mov     cl,dl                               ; cl = (StartLBA % MaxSector) + 1 = Sector
255        xor     dx,dx                               ; dx = 0
256        div     word ptr [bp+2]                     ; ax = ax / (MaxHead + 1) = Cylinder
257                                                    ; dx = ax % (MaxHead + 1) = Head
258
259        push    bx                                  ; Save number of blocks to transfer
260        mov     dh,dl                               ; dh = Head
261        mov     bp,07c00h                           ; bp = 0x7c00
262        mov     dl,byte ptr [bp+PhysicalDrive]      ; dl = Drive Number
263        mov     ch,al                               ; ch = Cylinder
264        mov     al,bl                               ; al = Blocks
265        mov     ah,2                                ; ah = Function 2
266        mov     bx,di                               ; es:bx = Buffer address
267        int     013h
268        jc      DiskError
269        pop     bx
270        pop     cx
271        movzx   ebx,bx
272        add     esi,ebx                             ; StartLBA = StartLBA + NumberOfBlocks
273        sub     cx,bx                               ; Blocks = Blocks - NumberOfBlocks
274        mov     ax,es
275        shl     bx,(BLOCK_SHIFT-4)
276        add     ax,bx
277        mov     es,ax                               ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE
278        cmp     cx,0
279        jne     ReadCylinderLoop
280        popa
281        ret
282
283DiskError:
284        push cs
285        pop  ds
286        lea  si, [ErrorString]
287        mov  cx, 7
288        jmp  PrintStringAndHalt
289
290PrintStringAndHalt:
291        mov  ax,0b800h
292        mov  es,ax
293        mov  di,160
294        rep  movsw
295Halt:
296        jmp   Halt
297
298ErrorString:
299        db 'S', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch
300
301        org     01fah
302LBAOffsetForBootSector:
303        dd      0h
304
305        org     01feh
306        dw      0aa55h
307
308;******************************************************************************
309;******************************************************************************
310;******************************************************************************
311
312DELAY_PORT           equ     0edh    ; Port to use for 1uS delay
313KBD_CONTROL_PORT     equ     060h    ; 8042 control port
314KBD_STATUS_PORT      equ     064h    ; 8042 status port
315WRITE_DATA_PORT_CMD  equ     0d1h    ; 8042 command to write the data port
316ENABLE_A20_CMD       equ     0dfh    ; 8042 command to enable A20
317
318        org     200h
319        jmp start
320Em64String:
321        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
322
323start:
324        mov ax,cs
325        mov ds,ax
326        mov es,ax
327        mov ss,ax
328        mov sp,MyStack
329
330;        mov ax,0b800h
331;        mov es,ax
332;        mov byte ptr es:[160],'a'
333;        mov ax,cs
334;        mov es,ax
335
336        mov ebx,0
337        lea edi,MemoryMap
338MemMapLoop:
339        mov eax,0e820h
340        mov ecx,20
341        mov edx,'SMAP'
342        int 15h
343        jc  MemMapDone
344        add edi,20
345        cmp ebx,0
346        je  MemMapDone
347        jmp MemMapLoop
348MemMapDone:
349        lea eax,MemoryMap
350        sub edi,eax                         ; Get the address of the memory map
351        mov dword ptr [MemoryMapSize],edi   ; Save the size of the memory map
352
353        xor     ebx,ebx
354        mov     bx,cs                       ; BX=segment
355        shl     ebx,4                       ; BX="linear" address of segment base
356        lea     eax,[GDT_BASE + ebx]        ; EAX=PHYSICAL address of gdt
357        mov     dword ptr [gdtr + 2],eax    ; Put address of gdt into the gdtr
358        lea     eax,[IDT_BASE + ebx]        ; EAX=PHYSICAL address of idt
359        mov     dword ptr [idtr + 2],eax    ; Put address of idt into the idtr
360        lea     edx,[MemoryMapSize + ebx]   ; Physical base address of the memory map
361
362        add ebx,01000h                      ; Source of EFI32
363        mov dword ptr [JUMP+2],ebx
364        add ebx,01000h
365        mov esi,ebx                         ; Source of EFILDR32
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        mov     bx,0008h                    ; Flat data descriptor
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        db      66h
417        lgdt    fword ptr [gdtr]
418        db      66h
419        lidt    fword ptr [idtr]
420
421        mov     eax,cr0
422        or      al,1
423        mov     cr0,eax
424JUMP:
425; jmp far 0010:00020000
426        db  066h
427        db  0eah
428        dd  000020000h
429        dw  00010h
430
431Empty8042InputBuffer:
432        mov cx,0
433Empty8042Loop:
434        out     DELAY_PORT,ax               ; Delay 1us
435        in      al,KBD_STATUS_PORT          ; Read the 8042 Status Port
436        and     al,02h                      ; Check the Input Buffer Full Flag
437        loopnz  Empty8042Loop               ; Loop until the input buffer is empty or a timout of 65536 uS
438        ret
439
440;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
441; data
442;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
443
444        align 02h
445
446gdtr    dw GDT_END - GDT_BASE - 1   ; GDT limit
447        dd 0                        ; (GDT base gets set above)
448;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
449;   global descriptor table (GDT)
450;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
451
452        align 02h
453
454public GDT_BASE
455GDT_BASE:
456; null descriptor
457NULL_SEL            equ $-GDT_BASE
458        dw 0            ; limit 15:0
459        dw 0            ; base 15:0
460        db 0            ; base 23:16
461        db 0            ; type
462        db 0            ; limit 19:16, flags
463        db 0            ; base 31:24
464
465; linear data segment descriptor
466LINEAR_SEL      equ $-GDT_BASE
467        dw 0FFFFh       ; limit 0xFFFFF
468        dw 0            ; base 0
469        db 0
470        db 092h         ; present, ring 0, data, expand-up, writable
471        db 0CFh                 ; page-granular, 32-bit
472        db 0
473
474; linear code segment descriptor
475LINEAR_CODE_SEL equ $-GDT_BASE
476        dw 0FFFFh       ; limit 0xFFFFF
477        dw 0            ; base 0
478        db 0
479        db 09Ah         ; present, ring 0, data, expand-up, writable
480        db 0CFh                 ; page-granular, 32-bit
481        db 0
482
483; system data segment descriptor
484SYS_DATA_SEL    equ $-GDT_BASE
485        dw 0FFFFh       ; limit 0xFFFFF
486        dw 0            ; base 0
487        db 0
488        db 092h         ; present, ring 0, data, expand-up, writable
489        db 0CFh                 ; page-granular, 32-bit
490        db 0
491
492; system code segment descriptor
493SYS_CODE_SEL    equ $-GDT_BASE
494        dw 0FFFFh       ; limit 0xFFFFF
495        dw 0            ; base 0
496        db 0
497        db 09Ah         ; present, ring 0, data, expand-up, writable
498        db 0CFh                 ; page-granular, 32-bit
499        db 0
500
501; spare segment descriptor
502SPARE3_SEL  equ $-GDT_BASE
503        dw 0            ; limit 0xFFFFF
504        dw 0            ; base 0
505        db 0
506        db 0            ; present, ring 0, data, expand-up, writable
507        db 0            ; page-granular, 32-bit
508        db 0
509
510; spare segment descriptor
511SPARE4_SEL  equ $-GDT_BASE
512        dw 0            ; limit 0xFFFFF
513        dw 0            ; base 0
514        db 0
515        db 0            ; present, ring 0, data, expand-up, writable
516        db 0            ; page-granular, 32-bit
517        db 0
518
519; spare segment descriptor
520SPARE5_SEL  equ $-GDT_BASE
521        dw 0            ; limit 0xFFFFF
522        dw 0            ; base 0
523        db 0
524        db 0            ; present, ring 0, data, expand-up, writable
525        db 0            ; page-granular, 32-bit
526        db 0
527
528GDT_END:
529
530        align 02h
531
532
533
534idtr            dw IDT_END - IDT_BASE - 1   ; IDT limit
535        dd 0                        ; (IDT base gets set above)
536;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
537;   interrupt descriptor table (IDT)
538;
539;   Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ
540;       mappings.  This implementation only uses the system timer and all other
541;       IRQs will remain masked.  The descriptors for vectors 33+ are provided
542;       for convenience.
543;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
544
545;idt_tag db "IDT",0
546        align 02h
547
548public IDT_BASE
549IDT_BASE:
550; divide by zero (INT 0)
551DIV_ZERO_SEL        equ $-IDT_BASE
552        dw 0            ; offset 15:0
553        dw SYS_CODE_SEL ; selector 15:0
554        db 0            ; 0 for interrupt gate
555        db 0eh OR 80h   ; type = 386 interrupt gate, present
556        dw 0            ; offset 31:16
557
558; debug exception (INT 1)
559DEBUG_EXCEPT_SEL    equ $-IDT_BASE
560        dw 0            ; offset 15:0
561        dw SYS_CODE_SEL ; selector 15:0
562        db 0            ; 0 for interrupt gate
563        db 0eh OR 80h   ; type = 386 interrupt gate, present
564        dw 0            ; offset 31:16
565
566; NMI (INT 2)
567NMI_SEL             equ $-IDT_BASE
568        dw 0            ; offset 15:0
569        dw SYS_CODE_SEL ; selector 15:0
570        db 0            ; 0 for interrupt gate
571        db 0eh OR 80h   ; type = 386 interrupt gate, present
572        dw 0            ; offset 31:16
573
574; soft breakpoint (INT 3)
575BREAKPOINT_SEL      equ $-IDT_BASE
576        dw 0            ; offset 15:0
577        dw SYS_CODE_SEL ; selector 15:0
578        db 0            ; 0 for interrupt gate
579        db 0eh OR 80h   ; type = 386 interrupt gate, present
580        dw 0            ; offset 31:16
581
582; overflow (INT 4)
583OVERFLOW_SEL        equ $-IDT_BASE
584        dw 0            ; offset 15:0
585        dw SYS_CODE_SEL ; selector 15:0
586        db 0            ; 0 for interrupt gate
587        db 0eh OR 80h   ; type = 386 interrupt gate, present
588        dw 0            ; offset 31:16
589
590; bounds check (INT 5)
591BOUNDS_CHECK_SEL    equ $-IDT_BASE
592        dw 0            ; offset 15:0
593        dw SYS_CODE_SEL ; selector 15:0
594        db 0            ; 0 for interrupt gate
595        db 0eh OR 80h   ; type = 386 interrupt gate, present
596        dw 0            ; offset 31:16
597
598; invalid opcode (INT 6)
599INVALID_OPCODE_SEL  equ $-IDT_BASE
600        dw 0            ; offset 15:0
601        dw SYS_CODE_SEL ; selector 15:0
602        db 0            ; 0 for interrupt gate
603        db 0eh OR 80h   ; type = 386 interrupt gate, present
604        dw 0            ; offset 31:16
605
606; device not available (INT 7)
607DEV_NOT_AVAIL_SEL   equ $-IDT_BASE
608        dw 0            ; offset 15:0
609        dw SYS_CODE_SEL ; selector 15:0
610        db 0            ; 0 for interrupt gate
611        db 0eh OR 80h   ; type = 386 interrupt gate, present
612        dw 0            ; offset 31:16
613
614; double fault (INT 8)
615DOUBLE_FAULT_SEL    equ $-IDT_BASE
616        dw 0            ; offset 15:0
617        dw SYS_CODE_SEL ; selector 15:0
618        db 0            ; 0 for interrupt gate
619        db 0eh OR 80h   ; type = 386 interrupt gate, present
620        dw 0            ; offset 31:16
621
622; Coprocessor segment overrun - reserved (INT 9)
623RSVD_INTR_SEL1      equ $-IDT_BASE
624        dw 0            ; offset 15:0
625        dw SYS_CODE_SEL ; selector 15:0
626        db 0            ; 0 for interrupt gate
627        db 0eh OR 80h   ; type = 386 interrupt gate, present
628        dw 0            ; offset 31:16
629
630; invalid TSS (INT 0ah)
631INVALID_TSS_SEL     equ $-IDT_BASE
632        dw 0            ; offset 15:0
633        dw SYS_CODE_SEL ; selector 15:0
634        db 0            ; 0 for interrupt gate
635        db 0eh OR 80h   ; type = 386 interrupt gate, present
636        dw 0            ; offset 31:16
637
638; segment not present (INT 0bh)
639SEG_NOT_PRESENT_SEL equ $-IDT_BASE
640        dw 0            ; offset 15:0
641        dw SYS_CODE_SEL ; selector 15:0
642        db 0            ; 0 for interrupt gate
643        db 0eh OR 80h   ; type = 386 interrupt gate, present
644        dw 0            ; offset 31:16
645
646; stack fault (INT 0ch)
647STACK_FAULT_SEL     equ $-IDT_BASE
648        dw 0            ; offset 15:0
649        dw SYS_CODE_SEL ; selector 15:0
650        db 0            ; 0 for interrupt gate
651        db 0eh OR 80h   ; type = 386 interrupt gate, present
652        dw 0            ; offset 31:16
653
654; general protection (INT 0dh)
655GP_FAULT_SEL        equ $-IDT_BASE
656        dw 0            ; offset 15:0
657        dw SYS_CODE_SEL ; selector 15:0
658        db 0            ; 0 for interrupt gate
659        db 0eh OR 80h   ; type = 386 interrupt gate, present
660        dw 0            ; offset 31:16
661
662; page fault (INT 0eh)
663PAGE_FAULT_SEL      equ $-IDT_BASE
664        dw 0            ; offset 15:0
665        dw SYS_CODE_SEL ; selector 15:0
666        db 0            ; 0 for interrupt gate
667        db 0eh OR 80h   ; type = 386 interrupt gate, present
668        dw 0            ; offset 31:16
669
670; Intel reserved - do not use (INT 0fh)
671RSVD_INTR_SEL2      equ $-IDT_BASE
672        dw 0            ; offset 15:0
673        dw SYS_CODE_SEL ; selector 15:0
674        db 0            ; 0 for interrupt gate
675        db 0eh OR 80h   ; type = 386 interrupt gate, present
676        dw 0            ; offset 31:16
677
678; floating point error (INT 10h)
679FLT_POINT_ERR_SEL   equ $-IDT_BASE
680        dw 0            ; offset 15:0
681        dw SYS_CODE_SEL ; selector 15:0
682        db 0            ; 0 for interrupt gate
683        db 0eh OR 80h   ; type = 386 interrupt gate, present
684        dw 0            ; offset 31:16
685
686; alignment check (INT 11h)
687ALIGNMENT_CHECK_SEL equ $-IDT_BASE
688        dw 0            ; offset 15:0
689        dw SYS_CODE_SEL ; selector 15:0
690        db 0            ; 0 for interrupt gate
691        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
692        dw 0            ; offset 31:16
693
694; machine check (INT 12h)
695MACHINE_CHECK_SEL   equ $-IDT_BASE
696        dw 0            ; offset 15:0
697        dw SYS_CODE_SEL ; selector 15:0
698        db 0            ; 0 for interrupt gate
699        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
700        dw 0            ; offset 31:16
701
702; SIMD floating-point exception (INT 13h)
703SIMD_EXCEPTION_SEL  equ $-IDT_BASE
704        dw 0            ; offset 15:0
705        dw SYS_CODE_SEL ; selector 15:0
706        db 0            ; 0 for interrupt gate
707        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
708        dw 0            ; offset 31:16
709
710; 85 unspecified descriptors, First 12 of them are reserved, the rest are avail
711        db (85 * 8) dup(0)
712
713; IRQ 0 (System timer) - (INT 68h)
714IRQ0_SEL            equ $-IDT_BASE
715        dw 0            ; offset 15:0
716        dw SYS_CODE_SEL ; selector 15:0
717        db 0            ; 0 for interrupt gate
718        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
719        dw 0            ; offset 31:16
720
721; IRQ 1 (8042 Keyboard controller) - (INT 69h)
722IRQ1_SEL            equ $-IDT_BASE
723        dw 0            ; offset 15:0
724        dw SYS_CODE_SEL ; selector 15:0
725        db 0            ; 0 for interrupt gate
726        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
727        dw 0            ; offset 31:16
728
729; Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah)
730IRQ2_SEL            equ $-IDT_BASE
731        dw 0            ; offset 15:0
732        dw SYS_CODE_SEL ; selector 15:0
733        db 0            ; 0 for interrupt gate
734        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
735        dw 0            ; offset 31:16
736
737; IRQ 3 (COM 2) - (INT 6bh)
738IRQ3_SEL            equ $-IDT_BASE
739        dw 0            ; offset 15:0
740        dw SYS_CODE_SEL ; selector 15:0
741        db 0            ; 0 for interrupt gate
742        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
743        dw 0            ; offset 31:16
744
745; IRQ 4 (COM 1) - (INT 6ch)
746IRQ4_SEL            equ $-IDT_BASE
747        dw 0            ; offset 15:0
748        dw SYS_CODE_SEL ; selector 15:0
749        db 0            ; 0 for interrupt gate
750        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
751        dw 0            ; offset 31:16
752
753; IRQ 5 (LPT 2) - (INT 6dh)
754IRQ5_SEL            equ $-IDT_BASE
755        dw 0            ; offset 15:0
756        dw SYS_CODE_SEL ; selector 15:0
757        db 0            ; 0 for interrupt gate
758        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
759        dw 0            ; offset 31:16
760
761; IRQ 6 (Floppy controller) - (INT 6eh)
762IRQ6_SEL            equ $-IDT_BASE
763        dw 0            ; offset 15:0
764        dw SYS_CODE_SEL ; selector 15:0
765        db 0            ; 0 for interrupt gate
766        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
767        dw 0            ; offset 31:16
768
769; IRQ 7 (LPT 1) - (INT 6fh)
770IRQ7_SEL            equ $-IDT_BASE
771        dw 0            ; offset 15:0
772        dw SYS_CODE_SEL ; selector 15:0
773        db 0            ; 0 for interrupt gate
774        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
775        dw 0            ; offset 31:16
776
777; IRQ 8 (RTC Alarm) - (INT 70h)
778IRQ8_SEL            equ $-IDT_BASE
779        dw 0            ; offset 15:0
780        dw SYS_CODE_SEL ; selector 15:0
781        db 0            ; 0 for interrupt gate
782        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
783        dw 0            ; offset 31:16
784
785; IRQ 9 - (INT 71h)
786IRQ9_SEL            equ $-IDT_BASE
787        dw 0            ; offset 15:0
788        dw SYS_CODE_SEL ; selector 15:0
789        db 0            ; 0 for interrupt gate
790        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
791        dw 0            ; offset 31:16
792
793; IRQ 10 - (INT 72h)
794IRQ10_SEL            equ $-IDT_BASE
795        dw 0            ; offset 15:0
796        dw SYS_CODE_SEL ; selector 15:0
797        db 0            ; 0 for interrupt gate
798        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
799        dw 0            ; offset 31:16
800
801; IRQ 11 - (INT 73h)
802IRQ11_SEL            equ $-IDT_BASE
803        dw 0            ; offset 15:0
804        dw SYS_CODE_SEL ; selector 15:0
805        db 0            ; 0 for interrupt gate
806        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
807        dw 0            ; offset 31:16
808
809; IRQ 12 (PS/2 mouse) - (INT 74h)
810IRQ12_SEL            equ $-IDT_BASE
811        dw 0            ; offset 15:0
812        dw SYS_CODE_SEL ; selector 15:0
813        db 0            ; 0 for interrupt gate
814        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
815        dw 0            ; offset 31:16
816
817; IRQ 13 (Floating point error) - (INT 75h)
818IRQ13_SEL            equ $-IDT_BASE
819        dw 0            ; offset 15:0
820        dw SYS_CODE_SEL ; selector 15:0
821        db 0            ; 0 for interrupt gate
822        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
823        dw 0            ; offset 31:16
824
825; IRQ 14 (Secondary IDE) - (INT 76h)
826IRQ14_SEL            equ $-IDT_BASE
827        dw 0            ; offset 15:0
828        dw SYS_CODE_SEL ; selector 15:0
829        db 0            ; 0 for interrupt gate
830        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
831        dw 0            ; offset 31:16
832
833; IRQ 15 (Primary IDE) - (INT 77h)
834IRQ15_SEL            equ $-IDT_BASE
835        dw 0            ; offset 15:0
836        dw SYS_CODE_SEL ; selector 15:0
837        db 0            ; 0 for interrupt gate
838        db 0eh OR 80h   ; (10001110)type = 386 interrupt gate, present
839        dw 0            ; offset 31:16
840
841IDT_END:
842
843        align 02h
844
845MemoryMapSize   dd  0
846MemoryMap   dd  0,0,0,0,0,0,0,0
847        dd  0,0,0,0,0,0,0,0
848        dd  0,0,0,0,0,0,0,0
849        dd  0,0,0,0,0,0,0,0
850        dd  0,0,0,0,0,0,0,0
851        dd  0,0,0,0,0,0,0,0
852        dd  0,0,0,0,0,0,0,0
853        dd  0,0,0,0,0,0,0,0
854        dd  0,0,0,0,0,0,0,0
855        dd  0,0,0,0,0,0,0,0
856        dd  0,0,0,0,0,0,0,0
857        dd  0,0,0,0,0,0,0,0
858        dd  0,0,0,0,0,0,0,0
859        dd  0,0,0,0,0,0,0,0
860        dd  0,0,0,0,0,0,0,0
861        dd  0,0,0,0,0,0,0,0
862        dd  0,0,0,0,0,0,0,0
863        dd  0,0,0,0,0,0,0,0
864        dd  0,0,0,0,0,0,0,0
865        dd  0,0,0,0,0,0,0,0
866        dd  0,0,0,0,0,0,0,0
867        dd  0,0,0,0,0,0,0,0
868        dd  0,0,0,0,0,0,0,0
869        dd  0,0,0,0,0,0,0,0
870        dd  0,0,0,0,0,0,0,0
871        dd  0,0,0,0,0,0,0,0
872        dd  0,0,0,0,0,0,0,0
873        dd  0,0,0,0,0,0,0,0
874        dd  0,0,0,0,0,0,0,0
875        dd  0,0,0,0,0,0,0,0
876
877        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
878        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
879
880        org 0fe0h
881MyStack:
882        ; below is the pieces of the IVT that is used to redirect INT 68h - 6fh
883        ;    back to INT 08h - 0fh  when in real mode...  It is 'org'ed to a
884        ;    known low address (20f00) so it can be set up by PlMapIrqToVect in
885        ;    8259.c
886
887        int 8
888        iret
889
890        int 9
891        iret
892
893        int 10
894        iret
895
896        int 11
897        iret
898
899        int 12
900        iret
901
902        int 13
903        iret
904
905        int 14
906        iret
907
908        int 15
909        iret
910
911
912        org 0ffeh
913BlockSignature:
914        dw  0aa55h
915
916        end
917