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#*    start16.asm
13#*
14#*   Abstract:
15#*
16#------------------------------------------------------------------------------
17
18        #.MODEL small
19        .stack:
20        .486p:
21        .code16
22
23.equ                        FAT_DIRECTORY_ENTRY_SIZE,   0x0020
24.equ                        FAT_DIRECTORY_ENTRY_SHIFT,  5
25.equ                        BLOCK_SIZE,                 0x0200
26.equ                        BLOCK_MASK,                 0x01ff
27.equ                        BLOCK_SHIFT,                9
28
29        .org 0x00
30
31.global _start
32_start:
33
34Ia32Jump:
35  jmp   BootSectorEntryPoint  # JMP inst    - 3 bytes
36  nop
37
38OemId:             .ascii  "INTEL   "    # OemId               - 8 bytes
39
40SectorSize:        .word  0              # Sector Size         - 16 bits
41SectorsPerCluster: .byte  0              # Sector Per Cluster  - 8 bits
42ReservedSectors:   .word  0              # Reserved Sectors    - 16 bits
43NoFats:            .byte  0              # Number of FATs      - 8 bits
44RootEntries:       .word  0              # Root Entries        - 16 bits
45Sectors:           .word  0              # Number of Sectors   - 16 bits
46Media:             .byte  0              # Media               - 8 bits  - ignored
47SectorsPerFat:     .word  0              # Sectors Per FAT     - 16 bits
48SectorsPerTrack:   .word  0              # Sectors Per Track   - 16 bits - ignored
49Heads:             .word  0              # Heads               - 16 bits - ignored
50HiddenSectors:     .long  0              # Hidden Sectors      - 32 bits - ignored
51LargeSectors:      .long  0              # Large Sectors       - 32 bits
52PhysicalDrive:     .byte  0              # PhysicalDriveNumber - 8 bits  - ignored
53CurrentHead:       .byte  0              # Current Head        - 8 bits
54Signature:         .byte  0              # Signature           - 8 bits  - ignored
55VolId:             .ascii  "    "        # Volume Serial Number- 4 bytes
56FatLabel:          .ascii  "           " # Label               - 11 bytes
57SystemId:          .ascii  "FAT16   "    # SystemId            - 8 bytes
58
59BootSectorEntryPoint:
60        #ASSUME ds:@code
61        #ASSUME ss:@code
62      # ds = 1000, es = 2000 + x (size of first cluster >> 4)
63      # cx = Start Cluster of EfiLdr
64      # dx = Start Cluster of Efivar.bin
65
66# Re use the BPB data stored in Boot Sector
67        movw    $0x7c00, %bp
68
69        pushw   %cx
70# Read Efivar.bin
71#       1000:dx    = DirectoryEntry of Efivar.bin -> BS.com has filled already
72        movw    $0x1900, %ax
73        movw    %ax, %es
74        testw   %dx, %dx
75        jnz     CheckVarStoreSize
76
77        movb    $1, %al
78NoVarStore:
79        pushw   %es
80# Set the 5th byte start @ 0:19000 to non-zero indicating we should init var store header in DxeIpl
81        movb    %al, %es:4
82        jmp     SaveVolumeId
83
84CheckVarStoreSize:
85        movw    %dx, %di
86        cmpl    $0x4000, %ds:2(%di)
87        movb    $2, %al
88        jne     NoVarStore
89
90LoadVarStore:
91        movb    $0, %al
92        movb    %al, %es:4
93        movw    (%di), %cx
94#       ES:DI = 1500:0
95        xorw    %di, %di
96        pushw   %es
97        movw    $0x1500, %ax
98        movw    %ax, %es
99        call    ReadFile
100SaveVolumeId:
101        popw    %es
102        movw    VolId(%bp), %ax
103        movw    %ax, %es:0                      # Save Volume Id to 0:19000. we will find the correct volume according to this VolumeId
104        movw    VolId+2(%bp), %ax
105        movw    %ax, %es:2
106
107# Read Efildr
108        popw    %cx
109#       cx    = Start Cluster of Efildr -> BS.com has filled already
110#       ES:DI = 2000:0, first cluster will be read again
111        xorw    %di, %di                            # di = 0
112        movw    $0x2000, %ax
113        movw    %ax, %es
114        call    ReadFile
115        movw    %cs, %ax
116        movw    %ax, %cs:JumpSegment
117
118JumpFarInstruction:
119        .byte   0xea
120JumpOffset:
121        .word   0x200
122JumpSegment:
123        .word   0x2000
124
125
126
127# ****************************************************************************
128# ReadFile
129#
130# Arguments:
131#   CX    = Start Cluster of File
132#   ES:DI = Buffer to store file content read from disk
133#
134# Return:
135#   (ES << 4 + DI) = end of file content Buffer
136#
137# ****************************************************************************
138ReadFile:
139# si      = NumberOfClusters
140# cx      = ClusterNumber
141# dx      = CachedFatSectorNumber
142# ds:0000 = CacheFatSectorBuffer
143# es:di   = Buffer to load file
144# bx      = NextClusterNumber
145        pusha
146        movw    $1, %si                             # NumberOfClusters = 1
147        pushw   %cx                                 # Push Start Cluster onto stack
148        movw    $0xfff, %dx                         # CachedFatSectorNumber = 0xfff
149FatChainLoop:
150        movw    %cx, %ax                            # ax = ClusterNumber
151        andw    $0xfff8, %ax                        # ax = ax & 0xfff8
152        cmpw    $0xfff8, %ax                        # See if this is the last cluster
153        je      FoundLastCluster                    # Jump if last cluster found
154        movw    %cx, %ax                            # ax = ClusterNumber
155        shlw    %ax                                 # FatOffset = ClusterNumber * 2
156        pushw   %si                                 # Save si
157        movw    %ax, %si                            # si = FatOffset
158        shrw    $BLOCK_SHIFT, %ax                   # ax = FatOffset >> BLOCK_SHIFT
159        addw    ReservedSectors(%bp), %ax           # ax = FatSectorNumber = ReservedSectors + (FatOffset >> BLOCK_OFFSET)
160        andw    $BLOCK_MASK, %si                    # si = FatOffset & BLOCK_MASK
161        cmpw    %dx, %ax                            # Compare FatSectorNumber to CachedFatSectorNumber
162        je      SkipFatRead
163        movw    $2, %bx
164        pushw   %es
165        pushw   %ds
166        popw    %es
167        call    ReadBlocks                          # Read 2 blocks starting at AX storing at ES:DI
168        popw    %es
169        movw    %ax, %dx                            # CachedFatSectorNumber = FatSectorNumber
170SkipFatRead:
171        movw    (%si), %bx                          # bx = NextClusterNumber
172        movw    %cx, %ax                            # ax = ClusterNumber
173        popw    %si                                 # Restore si
174        decw    %bx                                 # bx = NextClusterNumber - 1
175        cmpw    %cx, %bx                            # See if (NextClusterNumber-1)==ClusterNumber
176        jne     ReadClusters
177        incw    %bx                                 # bx = NextClusterNumber
178        incw    %si                                 # NumberOfClusters++
179        movw    %bx, %cx                            # ClusterNumber = NextClusterNumber
180        jmp     FatChainLoop
181ReadClusters:
182        incw    %bx
183        popw    %ax                                 # ax = StartCluster
184        pushw   %bx                                 # StartCluster = NextClusterNumber
185        movw    %bx, %cx                            # ClusterNumber = NextClusterNumber
186        subw    $2, %ax                             # ax = StartCluster - 2
187        xorb    %bh, %bh
188        movb    SectorsPerCluster(%bp), %bl         # bx = SectorsPerCluster
189        mulw    %bx                                 # ax = (StartCluster - 2) * SectorsPerCluster
190        addw    (%bp), %ax                          # ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
191        pushw   %ax                                 # save start sector
192        movw    %si, %ax                            # ax = NumberOfClusters
193        mulw    %bx                                 # ax = NumberOfClusters * SectorsPerCluster
194        movw    %ax, %bx                            # bx = Number of Sectors
195        popw    %ax                                 # ax = Start Sector
196        call    ReadBlocks
197        movw    $1, %si                             # NumberOfClusters = 1
198        jmp     FatChainLoop
199FoundLastCluster:
200        popw    %cx
201        popa
202        ret
203
204
205# ****************************************************************************
206# ReadBlocks - Reads a set of blocks from a block device
207#
208# AX    = Start LBA
209# BX    = Number of Blocks to Read
210# ES:DI = Buffer to store sectors read from disk
211# ****************************************************************************
212
213# cx = Blocks
214# bx = NumberOfBlocks
215# si = StartLBA
216
217ReadBlocks:
218        pusha
219        addl    LBAOffsetForBootSector(%bp), %eax            # Add LBAOffsetForBootSector to Start LBA
220        addl    HiddenSectors(%bp), %eax            # Add HiddenSectors to Start LBA
221        movl    %eax, %esi                          # esi = Start LBA
222        movw    %bx, %cx                            # cx = Number of blocks to read
223ReadCylinderLoop:
224        movw    $0x7bfc, %bp                        # bp = 0x7bfc
225        movl    %esi, %eax                          # eax = Start LBA
226        xorl    %edx, %edx                          # edx = 0
227        movzwl  (%bp), %ebx                         # bx = MaxSector
228        divl    %ebx                                # ax = StartLBA / MaxSector
229        incw    %dx                                 # dx = (StartLBA % MaxSector) + 1
230
231        movw    (%bp), %bx                          # bx = MaxSector
232        subw    %dx, %bx                            # bx = MaxSector - Sector
233        incw    %bx                                 # bx = MaxSector - Sector + 1
234        cmpw    %bx, %cx                            # Compare (Blocks) to (MaxSector - Sector + 1)
235        jg      LimitTransfer
236        movw    %cx, %bx                            # bx = Blocks
237LimitTransfer:
238        pushw   %ax                                 # save ax
239        movw    %es, %ax                            # ax = es
240        shrw    $(BLOCK_SHIFT-4), %ax               # ax = Number of blocks into mem system
241        andw    $0x7f, %ax                          # ax = Number of blocks into current seg
242        addw    %bx, %ax                            # ax = End Block number of transfer
243        cmpw    $0x80, %ax                          # See if it crosses a 64K boundry
244        jle     NotCrossing64KBoundry               # Branch if not crossing 64K boundry
245        subw    $0x80, %ax                          # ax = Number of blocks past 64K boundry
246        subw    %ax, %bx                            # Decrease transfer size by block overage
247NotCrossing64KBoundry:
248        popw    %ax                                 # restore ax
249
250        pushw   %cx
251        movb    %dl, %cl                            # cl = (StartLBA % MaxSector) + 1 = Sector
252        xorw    %dx, %dx                            # dx = 0
253        divw    2(%bp)                              # ax = ax / (MaxHead + 1) = Cylinder
254                                                    # dx = ax % (MaxHead + 1) = Head
255
256        pushw   %bx                                 # Save number of blocks to transfer
257        movb    %dl, %dh                            # dh = Head
258        movw    $0x7c00, %bp                        # bp = 0x7c00
259        movb    PhysicalDrive(%bp), %dl             # dl = Drive Number
260        movb    %al, %ch                            # ch = Cylinder
261        movb    %bl, %al                            # al = Blocks
262        movb    $2, %ah                             # ah = Function 2
263        movw    %di, %bx                            # es:bx = Buffer address
264        int     $0x13
265        jc      DiskError
266        popw    %bx
267        popw    %cx
268        movzwl  %bx, %ebx
269        addl    %ebx, %esi                          # StartLBA = StartLBA + NumberOfBlocks
270        subw    %bx, %cx                            # Blocks = Blocks - NumberOfBlocks
271        movw    %es, %ax
272        shlw    $(BLOCK_SHIFT-4), %bx
273        addw    %bx, %ax
274        movw    %ax, %es                            # es:di = es:di + NumberOfBlocks*BLOCK_SIZE
275        cmpw    $0, %cx
276        jne     ReadCylinderLoop
277        popa
278        ret
279
280DiskError:
281        pushw %cs
282        popw %ds
283        leaw ErrorString, %si
284        movw $7, %cx
285        jmp  PrintStringAndHalt
286
287PrintStringAndHalt:
288        movw $0xb800, %ax
289        movw %ax, %es
290        movw $160, %di
291        rep
292        movsw
293Halt:
294        jmp   Halt
295
296ErrorString:
297        .byte 'S', 0x0c, 'E', 0x0c, 'r', 0x0c, 'r', 0x0c, 'o', 0x0c, 'r', 0x0c, '!', 0x0c
298
299        # .org     0x01fa # Just for passing build.
300LBAOffsetForBootSector:
301        .long   0x0
302
303        # .org     0x01fe # Just for passing build.
304        .word   0xaa55
305
306#******************************************************************************
307#******************************************************************************
308#******************************************************************************
309
310.equ                 DELAY_PORT,            0x0ed     # Port to use for 1uS delay
311.equ                 KBD_CONTROL_PORT,      0x060     # 8042 control port
312.equ                 KBD_STATUS_PORT,       0x064     # 8042 status port
313.equ                 WRITE_DATA_PORT_CMD,   0x0d1     # 8042 command to write the data port
314.equ                 ENABLE_A20_CMD,        0x0df     # 8042 command to enable A20
315
316        # .org     0x0200 # Just for passing build.
317        jmp start
318Em64String:
319        .byte 'E', 0x0c, 'm', 0x0c, '6', 0x0c, '4', 0x0c, 'T', 0x0c, ' ', 0x0c, 'U', 0x0c, 'n', 0x0c, 's', 0x0c, 'u', 0x0c, 'p', 0x0c, 'p', 0x0c, 'o', 0x0c, 'r', 0x0c, 't', 0x0c, 'e', 0x0c, 'd', 0x0c, '!', 0x0c
320
321start:
322        movw %cs, %ax
323        movw %ax, %ds
324        movw %ax, %es
325        movw %ax, %ss
326        movw $MyStack, %sp
327
328#        mov ax,0b800h
329#        mov es,ax
330#        mov byte ptr es:[160],'a'
331#        mov ax,cs
332#        mov es,ax
333
334        movl $0, %ebx
335        leal MemoryMap, %edi
336MemMapLoop:
337        movl $0xe820, %eax
338        movl $20, %ecx
339        movl $0x534d4150, %edx  # 0x534d4150  stands for 'SMAP'
340        int $0x15
341        jc  MemMapDone
342        addl $20, %edi
343        cmpl $0, %ebx
344        je  MemMapDone
345        jmp MemMapLoop
346MemMapDone:
347        leal MemoryMap, %eax
348        subl %eax, %edi                     # Get the address of the memory map
349        movl %edi, MemoryMapSize            # Save the size of the memory map
350
351        xorl    %ebx, %ebx
352        movw    %cs, %bx                    # BX=segment
353        shll    $4, %ebx                    # BX="linear" address of segment base
354        leal    GDT_BASE(%ebx), %eax        # EAX=PHYSICAL address of gdt
355        movl    %eax, gdtr + 2              # Put address of gdt into the gdtr
356        leal    IDT_BASE(%ebx), %eax        # EAX=PHYSICAL address of idt
357        movl    %eax, idtr + 2              # Put address of idt into the idtr
358        leal    MemoryMapSize(%ebx), %edx   # Physical base address of the memory map
359
360        addl $0x1000, %ebx                  # Source of EFI32
361        movl %ebx, JUMP+2
362        addl $0x1000, %ebx
363        movl %ebx, %esi                     # Source of EFILDR32
364
365#        mov ax,0b800h
366#        mov es,ax
367#        mov byte ptr es:[162],'b'
368#        mov ax,cs
369#        mov es,ax
370
371#
372# Enable A20 Gate
373#
374
375        movw $0x2401, %ax                   # Enable A20 Gate
376        int $0x15
377        jnc A20GateEnabled                  # Jump if it suceeded
378
379#
380# If INT 15 Function 2401 is not supported, then attempt to Enable A20 manually.
381#
382
383        call    Empty8042InputBuffer        # Empty the Input Buffer on the 8042 controller
384        jnz     Timeout8042                 # Jump if the 8042 timed out
385        outw    %ax, $DELAY_PORT            # Delay 1 uS
386        movb    $WRITE_DATA_PORT_CMD, %al   # 8042 cmd to write output port
387        outb    %al, $KBD_STATUS_PORT       # Send command to the 8042
388        call    Empty8042InputBuffer        # Empty the Input Buffer on the 8042 controller
389        jnz     Timeout8042                 # Jump if the 8042 timed out
390        movb    $ENABLE_A20_CMD, %al        # gate address bit 20 on
391        outb    %al, $KBD_CONTROL_PORT      # Send command to thre 8042
392        call    Empty8042InputBuffer        # Empty the Input Buffer on the 8042 controller
393        movw    $25, %cx                    # Delay 25 uS for the command to complete on the 8042
394Delay25uS:
395        outw    %ax, $DELAY_PORT            # Delay 1 uS
396        loop    Delay25uS
397Timeout8042:
398
399
400A20GateEnabled:
401        movw    $0x0008, %bx                # Flat data descriptor
402#
403# DISABLE INTERRUPTS - Entering Protected Mode
404#
405
406        cli
407
408#        mov ax,0b800h
409#        mov es,ax
410#        mov byte ptr es:[164],'c'
411#        mov ax,cs
412#        mov es,ax
413
414        .byte   0x66
415        lgdt    gdtr
416        .byte   0x66
417        lidt    idtr
418
419        movl    %cr0, %eax
420        orb     $1, %al
421        movl    %eax, %cr0
422JUMP:
423# jmp far 0010:00020000
424        .byte 0x66
425        .byte 0xea
426        .long 0x00020000
427        .word 0x0010
428
429Empty8042InputBuffer:
430        movw $0, %cx
431Empty8042Loop:
432        outw    %ax, $DELAY_PORT            # Delay 1us
433        inb     $KBD_STATUS_PORT, %al       # Read the 8042 Status Port
434        andb    $0x2, %al                   # Check the Input Buffer Full Flag
435        loopnz  Empty8042Loop               # Loop until the input buffer is empty or a timout of 65536 uS
436        ret
437
438##############################################################################
439# data
440##############################################################################
441
442        .p2align 1
443
444gdtr:   .word  GDT_END - GDT_BASE - 1       # GDT limit
445        .long 0                             # (GDT base gets set above)
446##############################################################################
447#   global descriptor table (GDT)
448##############################################################################
449
450        .p2align 1
451
452GDT_BASE:
453# null descriptor
454.equ                NULL_SEL, .-GDT_BASE
455        .word 0         # limit 15:0
456        .word 0         # base 15:0
457        .byte 0         # base 23:16
458        .byte 0         # type
459        .byte 0         # limit 19:16, flags
460        .byte 0         # base 31:24
461
462# linear data segment descriptor
463.equ            LINEAR_SEL, .-GDT_BASE
464        .word 0xFFFF    # limit 0xFFFFF
465        .word 0         # base 0
466        .byte 0
467        .byte 0x92      # present, ring 0, data, expand-up, writable
468        .byte 0xCF              # page-granular, 32-bit
469        .byte 0
470
471# linear code segment descriptor
472.equ            LINEAR_CODE_SEL, .-GDT_BASE
473        .word 0xFFFF    # limit 0xFFFFF
474        .word 0         # base 0
475        .byte 0
476        .byte 0x9A      # present, ring 0, data, expand-up, writable
477        .byte 0xCF              # page-granular, 32-bit
478        .byte 0
479
480# system data segment descriptor
481.equ            SYS_DATA_SEL, .-GDT_BASE
482        .word 0xFFFF    # limit 0xFFFFF
483        .word 0         # base 0
484        .byte 0
485        .byte 0x92      # present, ring 0, data, expand-up, writable
486        .byte 0xCF              # page-granular, 32-bit
487        .byte 0
488
489# system code segment descriptor
490.equ            SYS_CODE_SEL, .-GDT_BASE
491        .word 0xFFFF    # limit 0xFFFFF
492        .word 0         # base 0
493        .byte 0
494        .byte 0x9A      # present, ring 0, data, expand-up, writable
495        .byte 0xCF              # page-granular, 32-bit
496        .byte 0
497
498# spare segment descriptor
499.equ        SPARE3_SEL, .-GDT_BASE
500        .word 0         # limit 0xFFFFF
501        .word 0         # base 0
502        .byte 0
503        .byte 0         # present, ring 0, data, expand-up, writable
504        .byte 0         # page-granular, 32-bit
505        .byte 0
506
507# spare segment descriptor
508.equ        SPARE4_SEL, .-GDT_BASE
509        .word 0         # limit 0xFFFFF
510        .word 0         # base 0
511        .byte 0
512        .byte 0         # present, ring 0, data, expand-up, writable
513        .byte 0         # page-granular, 32-bit
514        .byte 0
515
516# spare segment descriptor
517.equ        SPARE5_SEL, .-GDT_BASE
518        .word 0         # limit 0xFFFFF
519        .word 0         # base 0
520        .byte 0
521        .byte 0         # present, ring 0, data, expand-up, writable
522        .byte 0         # page-granular, 32-bit
523        .byte 0
524
525GDT_END:
526
527        .p2align 1
528
529
530
531idtr:   .word IDT_END - IDT_BASE - 1  # IDT limit
532        .long 0                       # (IDT base gets set above)
533##############################################################################
534#   interrupt descriptor table (IDT)
535#
536#   Note: The hardware IRQ's specified in this table are the normal PC/AT IRQ
537#       mappings.  This implementation only uses the system timer and all other
538#       IRQs will remain masked.  The descriptors for vectors 33+ are provided
539#       for convenience.
540##############################################################################
541
542#idt_tag db "IDT",0
543        .p2align 1
544
545IDT_BASE:
546# divide by zero (INT 0)
547.equ                DIV_ZERO_SEL, .-IDT_BASE
548        .word 0             # offset 15:0
549        .word SYS_CODE_SEL  # selector 15:0
550        .byte 0             # 0 for interrupt gate
551        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
552        .word 0             # offset 31:16
553
554# debug exception (INT 1)
555.equ                DEBUG_EXCEPT_SEL, .-IDT_BASE
556        .word 0             # offset 15:0
557        .word SYS_CODE_SEL  # selector 15:0
558        .byte 0             # 0 for interrupt gate
559        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
560        .word 0             # offset 31:16
561
562# NMI (INT 2)
563.equ                NMI_SEL, .-IDT_BASE
564        .word 0             # offset 15:0
565        .word SYS_CODE_SEL  # selector 15:0
566        .byte 0             # 0 for interrupt gate
567        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
568        .word 0             # offset 31:16
569
570# soft breakpoint (INT 3)
571.equ                BREAKPOINT_SEL, .-IDT_BASE
572        .word 0             # offset 15:0
573        .word SYS_CODE_SEL  # selector 15:0
574        .byte 0             # 0 for interrupt gate
575        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
576        .word 0             # offset 31:16
577
578# overflow (INT 4)
579.equ                OVERFLOW_SEL, .-IDT_BASE
580        .word 0             # offset 15:0
581        .word SYS_CODE_SEL  # selector 15:0
582        .byte 0             # 0 for interrupt gate
583        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
584        .word 0             # offset 31:16
585
586# bounds check (INT 5)
587.equ                BOUNDS_CHECK_SEL, .-IDT_BASE
588        .word 0             # offset 15:0
589        .word SYS_CODE_SEL  # selector 15:0
590        .byte 0             # 0 for interrupt gate
591        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
592        .word 0             # offset 31:16
593
594# invalid opcode (INT 6)
595.equ                INVALID_OPCODE_SEL, .-IDT_BASE
596        .word 0             # offset 15:0
597        .word SYS_CODE_SEL  # selector 15:0
598        .byte 0             # 0 for interrupt gate
599        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
600        .word 0             # offset 31:16
601
602# device not available (INT 7)
603.equ                DEV_NOT_AVAIL_SEL, .-IDT_BASE
604        .word 0             # offset 15:0
605        .word SYS_CODE_SEL  # selector 15:0
606        .byte 0             # 0 for interrupt gate
607        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
608        .word 0             # offset 31:16
609
610# double fault (INT 8)
611.equ                DOUBLE_FAULT_SEL, .-IDT_BASE
612        .word 0             # offset 15:0
613        .word SYS_CODE_SEL  # selector 15:0
614        .byte 0             # 0 for interrupt gate
615        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
616        .word 0             # offset 31:16
617
618# Coprocessor segment overrun - reserved (INT 9)
619.equ                RSVD_INTR_SEL1, .-IDT_BASE
620        .word 0             # offset 15:0
621        .word SYS_CODE_SEL  # selector 15:0
622        .byte 0             # 0 for interrupt gate
623        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
624        .word 0             # offset 31:16
625
626# invalid TSS (INT 0ah)
627.equ                INVALID_TSS_SEL, .-IDT_BASE
628        .word 0             # offset 15:0
629        .word SYS_CODE_SEL  # selector 15:0
630        .byte 0             # 0 for interrupt gate
631        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
632        .word 0             # offset 31:16
633
634# segment not present (INT 0bh)
635.equ                SEG_NOT_PRESENT_SEL, .-IDT_BASE
636        .word 0             # offset 15:0
637        .word SYS_CODE_SEL  # selector 15:0
638        .byte 0             # 0 for interrupt gate
639        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
640        .word 0             # offset 31:16
641
642# stack fault (INT 0ch)
643.equ                STACK_FAULT_SEL, .-IDT_BASE
644        .word 0             # offset 15:0
645        .word SYS_CODE_SEL  # selector 15:0
646        .byte 0             # 0 for interrupt gate
647        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
648        .word 0             # offset 31:16
649
650# general protection (INT 0dh)
651.equ                GP_FAULT_SEL, .-IDT_BASE
652        .word 0             # offset 15:0
653        .word SYS_CODE_SEL  # selector 15:0
654        .byte 0             # 0 for interrupt gate
655        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
656        .word 0             # offset 31:16
657
658# page fault (INT 0eh)
659.equ                PAGE_FAULT_SEL, .-IDT_BASE
660        .word 0             # offset 15:0
661        .word SYS_CODE_SEL  # selector 15:0
662        .byte 0             # 0 for interrupt gate
663        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
664        .word 0             # offset 31:16
665
666# Intel reserved - do not use (INT 0fh)
667.equ                RSVD_INTR_SEL2, .-IDT_BASE
668        .word 0             # offset 15:0
669        .word SYS_CODE_SEL  # selector 15:0
670        .byte 0             # 0 for interrupt gate
671        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
672        .word 0             # offset 31:16
673
674# floating point error (INT 10h)
675.equ                FLT_POINT_ERR_SEL, .-IDT_BASE
676        .word 0             # offset 15:0
677        .word SYS_CODE_SEL  # selector 15:0
678        .byte 0             # 0 for interrupt gate
679        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
680        .word 0             # offset 31:16
681
682# alignment check (INT 11h)
683.equ                ALIGNMENT_CHECK_SEL, .-IDT_BASE
684        .word 0             # offset 15:0
685        .word SYS_CODE_SEL  # selector 15:0
686        .byte 0             # 0 for interrupt gate
687        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
688        .word 0             # offset 31:16
689
690# machine check (INT 12h)
691.equ                MACHINE_CHECK_SEL, .-IDT_BASE
692        .word 0             # offset 15:0
693        .word SYS_CODE_SEL  # selector 15:0
694        .byte 0             # 0 for interrupt gate
695        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
696        .word 0             # offset 31:16
697
698# SIMD floating-point exception (INT 13h)
699.equ                SIMD_EXCEPTION_SEL, .-IDT_BASE
700        .word 0             # offset 15:0
701        .word SYS_CODE_SEL  # selector 15:0
702        .byte 0             # 0 for interrupt gate
703        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
704        .word 0             # offset 31:16
705
706# 85 unspecified descriptors, First 12 of them are reserved, the rest are avail
707        .fill  85 * 8, 1, 0
708
709# IRQ 0 (System timer) - (INT 68h)
710.equ                IRQ0_SEL, .-IDT_BASE
711        .word 0             # offset 15:0
712        .word SYS_CODE_SEL  # selector 15:0
713        .byte 0             # 0 for interrupt gate
714        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
715        .word 0             # offset 31:16
716
717# IRQ 1 (8042 Keyboard controller) - (INT 69h)
718.equ                IRQ1_SEL, .-IDT_BASE
719        .word 0             # offset 15:0
720        .word SYS_CODE_SEL  # selector 15:0
721        .byte 0             # 0 for interrupt gate
722        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
723        .word 0             # offset 31:16
724
725# Reserved - IRQ 2 redirect (IRQ 2) - DO NOT USE!!! - (INT 6ah)
726.equ                IRQ2_SEL, .-IDT_BASE
727        .word 0             # offset 15:0
728        .word SYS_CODE_SEL  # selector 15:0
729        .byte 0             # 0 for interrupt gate
730        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
731        .word 0             # offset 31:16
732
733# IRQ 3 (COM 2) - (INT 6bh)
734.equ                IRQ3_SEL, .-IDT_BASE
735        .word 0             # offset 15:0
736        .word SYS_CODE_SEL  # selector 15:0
737        .byte 0             # 0 for interrupt gate
738        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
739        .word 0             # offset 31:16
740
741# IRQ 4 (COM 1) - (INT 6ch)
742.equ                IRQ4_SEL, .-IDT_BASE
743        .word 0             # offset 15:0
744        .word SYS_CODE_SEL  # selector 15:0
745        .byte 0             # 0 for interrupt gate
746        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
747        .word 0             # offset 31:16
748
749# IRQ 5 (LPT 2) - (INT 6dh)
750.equ                IRQ5_SEL, .-IDT_BASE
751        .word 0             # offset 15:0
752        .word SYS_CODE_SEL  # selector 15:0
753        .byte 0             # 0 for interrupt gate
754        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
755        .word 0             # offset 31:16
756
757# IRQ 6 (Floppy controller) - (INT 6eh)
758.equ                IRQ6_SEL, .-IDT_BASE
759        .word 0             # offset 15:0
760        .word SYS_CODE_SEL  # selector 15:0
761        .byte 0             # 0 for interrupt gate
762        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
763        .word 0             # offset 31:16
764
765# IRQ 7 (LPT 1) - (INT 6fh)
766.equ                IRQ7_SEL, .-IDT_BASE
767        .word 0             # offset 15:0
768        .word SYS_CODE_SEL  # selector 15:0
769        .byte 0             # 0 for interrupt gate
770        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
771        .word 0             # offset 31:16
772
773# IRQ 8 (RTC Alarm) - (INT 70h)
774.equ                IRQ8_SEL, .-IDT_BASE
775        .word 0             # offset 15:0
776        .word SYS_CODE_SEL  # selector 15:0
777        .byte 0             # 0 for interrupt gate
778        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
779        .word 0             # offset 31:16
780
781# IRQ 9 - (INT 71h)
782.equ                IRQ9_SEL, .-IDT_BASE
783        .word 0             # offset 15:0
784        .word SYS_CODE_SEL  # selector 15:0
785        .byte 0             # 0 for interrupt gate
786        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
787        .word 0             # offset 31:16
788
789# IRQ 10 - (INT 72h)
790.equ                 IRQ10_SEL, .-IDT_BASE
791        .word 0             # offset 15:0
792        .word SYS_CODE_SEL  # selector 15:0
793        .byte 0             # 0 for interrupt gate
794        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
795        .word 0             # offset 31:16
796
797# IRQ 11 - (INT 73h)
798.equ                 IRQ11_SEL, .-IDT_BASE
799        .word 0             # offset 15:0
800        .word SYS_CODE_SEL  # selector 15:0
801        .byte 0             # 0 for interrupt gate
802        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
803        .word 0             # offset 31:16
804
805# IRQ 12 (PS/2 mouse) - (INT 74h)
806.equ                 IRQ12_SEL, .-IDT_BASE
807        .word 0             # offset 15:0
808        .word SYS_CODE_SEL  # selector 15:0
809        .byte 0             # 0 for interrupt gate
810        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
811        .word 0             # offset 31:16
812
813# IRQ 13 (Floating point error) - (INT 75h)
814.equ                 IRQ13_SEL, .-IDT_BASE
815        .word 0             # offset 15:0
816        .word SYS_CODE_SEL  # selector 15:0
817        .byte 0             # 0 for interrupt gate
818        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
819        .word 0             # offset 31:16
820
821# IRQ 14 (Secondary IDE) - (INT 76h)
822.equ                 IRQ14_SEL, .-IDT_BASE
823        .word 0             # offset 15:0
824        .word SYS_CODE_SEL  # selector 15:0
825        .byte 0             # 0 for interrupt gate
826        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
827        .word 0             # offset 31:16
828
829# IRQ 15 (Primary IDE) - (INT 77h)
830.equ                 IRQ15_SEL, .-IDT_BASE
831        .word 0             # offset 15:0
832        .word SYS_CODE_SEL  # selector 15:0
833        .byte 0             # 0 for interrupt gate
834        .byte 0x0e | 0x80  # (10001110)type = 386 interrupt gate, present
835        .word 0             # offset 31:16
836
837IDT_END:
838
839        .p2align 1
840
841MemoryMapSize:  .long 0
842MemoryMap:  .long 0,0,0,0,0,0,0,0
843        .long 0,0,0,0,0,0,0,0
844        .long 0,0,0,0,0,0,0,0
845        .long 0,0,0,0,0,0,0,0
846        .long 0,0,0,0,0,0,0,0
847        .long 0,0,0,0,0,0,0,0
848        .long 0,0,0,0,0,0,0,0
849        .long 0,0,0,0,0,0,0,0
850        .long 0,0,0,0,0,0,0,0
851        .long 0,0,0,0,0,0,0,0
852        .long 0,0,0,0,0,0,0,0
853        .long 0,0,0,0,0,0,0,0
854        .long 0,0,0,0,0,0,0,0
855        .long 0,0,0,0,0,0,0,0
856        .long 0,0,0,0,0,0,0,0
857        .long 0,0,0,0,0,0,0,0
858        .long 0,0,0,0,0,0,0,0
859        .long 0,0,0,0,0,0,0,0
860        .long 0,0,0,0,0,0,0,0
861        .long 0,0,0,0,0,0,0,0
862        .long 0,0,0,0,0,0,0,0
863        .long 0,0,0,0,0,0,0,0
864        .long 0,0,0,0,0,0,0,0
865        .long 0,0,0,0,0,0,0,0
866        .long 0,0,0,0,0,0,0,0
867        .long 0,0,0,0,0,0,0,0
868        .long 0,0,0,0,0,0,0,0
869        .long 0,0,0,0,0,0,0,0
870        .long 0,0,0,0,0,0,0,0
871        .long 0,0,0,0,0,0,0,0
872
873        .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
874        .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
875
876        .org 0x0fe0
877MyStack:
878        # below is the pieces of the IVT that is used to redirect INT 68h - 6fh
879        #    back to INT 08h - 0fh  when in real mode...  It is 'org'ed to a
880        #    known low address (20f00) so it can be set up by PlMapIrqToVect in
881        #    8259.c
882
883        int $8
884        iret
885
886        int $9
887        iret
888
889        int $10
890        iret
891
892        int $11
893        iret
894
895        int $12
896        iret
897
898        int $13
899        iret
900
901        int $14
902        iret
903
904        int $15
905        iret
906
907
908        .org 0x0ffe
909BlockSignature:
910        .word 0xaa55
911