Subversion Repositories shark

Rev

Rev 444 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/* Project:     OSLib
 * Description: The OS Construction Kit
 * Date:                1.6.2000
 * Idea by:             Luca Abeni & Gerardo Lamastra
 *
 * OSLib is an SO project aimed at developing a common, easy-to-use
 * low-level infrastructure for developing OS kernels and Embedded
 * Applications; it partially derives from the HARTIK project but it
 * currently is independently developed.
 *
 * OSLib is distributed under GPL License, and some of its code has
 * been derived from the Linux kernel source; also some important
 * ideas come from studying the DJGPP go32 extender.
 *
 * We acknowledge the Linux Community, Free Software Foundation,
 * D.J. Delorie and all the other developers who believe in the
 * freedom of software and ideas.
 *
 * For legalese, check out the included GPL license.
 */

/*      Exc/IRQ handlers (asm part)     */
/* TODO: Unify the Exc/Int Mechanism... */

#include <ll/i386/sel.h>
#include <ll/i386/linkage.h>
#include <ll/i386/int.h>
#include <ll/i386/defs.h>

.extern SYMBOL_NAME(GDT_base)
.extern SYMBOL_NAME(global_regs)
.extern SYMBOL_NAME(VM86_ret_ctx)

.data          

ASMFILE(Exc)

.globl SYMBOL_NAME(ll_irq_table)
                
SYMBOL_NAME_LABEL(ll_irq_table) .space  1024, 0

.text

.extern  SYMBOL_NAME(ll_exc_hook)
.extern  SYMBOL_NAME(ll_FPU_hook)

.globl SYMBOL_NAME(h13_bis)
.globl SYMBOL_NAME(exc7)

/* These are the hardware handlers; they all jump to ll_handler setting */
/* the interrupt number into EAX & save the registers on stack          */
INT(0)
INT(1)
INT(2)
INT(3)
INT(4)
INT(5)
INT(6)
INT(8)
INT(9)
INT(10)
INT(11)
INT(12)
INT(13)
INT(14)
INT(15)
NONE(16)
INT(17)
INT(18)
INT(19)
INT(20)
INT(21)
INT(22)
INT(23)
INT(24)
INT(25)
INT(26)
INT(27)
INT(28)
INT(29)
INT(30)
INT(31)

INT(32)
INT(33)
INT(34)
INT(35)
INT(36)
INT(37)
INT(38)
INT(39)
INT(40)
INT(41)
INT(42)
INT(43)
INT(44)
INT(45)
INT(46)
INT(47)
INT(48)
INT(49)
INT(50)
INT(51)
INT(52)
INT(53)
INT(54)
INT(55)
INT(56)
INT(57)
INT(58)
INT(59)
INT(60)
INT(61)
INT(62)
INT(63)

/* Master PIC... (int 0x40, see ll/i386/pic.h)*/
INT_1(64)
INT_1(65)
INT_1(66)
INT_1(67)
INT_1(68)
INT_1(69)
INT_1(70)
INT_1(71)

VM86(72)
INT(73)
INT(74)
INT(75)
INT(76)
INT(77)
INT(78)
INT(79)
INT(80)
INT(81)
INT(82)
INT(83)
INT(84)
INT(85)
INT(86)
INT(87)
INT(88)
INT(89)
INT(90)
INT(91)
INT(92)
INT(93)
INT(94)
INT(95)
INT(96)
INT(97)
INT(98)
INT(99)
INT(100)
INT(101)
INT(102)
INT(103)
INT(104)
INT(105)
INT(106)
INT(107)
INT(108)
INT(109)
INT(110)
INT(111)

/* Slave PIC... (int 0x70, see ll/i386/pic.h)*/
INT_2(112)
INT_2(113)
INT_2(114)
INT_2(115)
INT_2(116)
INT_2(117)
INT_2(118)
INT_2(119)

INT(120)
INT(121)
INT(122)
INT(123)
INT(124)
INT(125)
INT(126)
INT(127)
INT(128)
INT(129)
INT(130)
INT(131)
INT(132)
INT(133)
INT(134)
INT(135)
INT(136)
INT(137)
INT(138)
INT(139)
INT(140)
INT(141)
INT(142)
INT(143)
INT(144)
INT(145)
INT(146)
INT(147)
INT(148)
INT(149)
INT(150)
INT(151)
INT(152)
INT(153)
INT(154)
INT(155)
INT(156)
INT(157)
INT(158)
INT(159)
INT(160)
INT(161)
INT(162)
INT(163)
INT(164)
INT(165)
INT(166)
INT(167)
INT(168)
INT(169)
INT(170)
INT(171)
INT(172)
INT(173)
INT(174)
INT(175)
INT(176)
INT(177)
INT(178)
INT(179)
INT(180)
INT(181)
INT(182)
INT(183)
INT(184)
INT(185)
INT(186)
INT(187)
INT(188)
INT(189)
INT(190)
INT(191)
INT(192)
INT(193)
INT(194)
INT(195)
INT(196)
INT(197)
INT(198)
INT(199)
INT(200)
INT(201)
INT(202)
INT(203)
INT(204)
INT(205)
INT(206)
INT(207)
INT(208)
INT(209)
INT(210)
INT(211)
INT(212)
INT(213)
INT(214)
INT(215)
INT(216)
INT(217)
INT(218)
INT(219)
INT(220)
INT(221)
INT(222)
INT(223)
INT(224)
INT(225)
INT(226)
INT(227)
INT(228)
INT(229)
INT(230)
INT(231)
INT(232)
INT(233)
INT(234)
INT(235)
INT(236)
INT(237)
INT(238)
INT(239)
INT(240)
INT(241)
INT(242)
INT(243)
INT(244)
INT(245)
INT(246)
INT(247)
INT(248)
INT(249)
INT(250)
INT(251)
INT(252)
INT(253)
INT(254)
INT(255)

/* The ll_handler process the request using the kernel function act_int() */
/* Then sends EOI & schedules any eventual new task!                      */

ll_handler:             
                        /* We do not know what is the DS value  */
                        /* Then we save it & set it correctly   */
                        
                        pushl   %ds
                        pushl   %ss
                        pushl   %es
                        pushl   %fs
                        pushl   %gs
                        /* But we first transfer to the _act_int  */
                        /* the interrupt number which is required */
                        /* as second argument                     */
                        pushl   %eax
                        movw    $(X_FLATDATA_SEL),%ax
                        movw    %ax,%es
                        mov     %ax,%ds
        movw    %ax, %fs
        movw    %ax, %gs
                        
                        /* Now save the actual context on stack         */
                        /* to pass it to _act_int (C caling convention) */
                        /* CLD is necessary when calling a C function   */
                
                        cld
                        
                        /* The following could be optimized a little... */
                        popl %eax
                        xorl %ebx, %ebx
                        movw %ss, %bx
                        /* We must switch to a ``safe stack'' */
        /*
         * OK, this is the idea: in %esp we have the address of the
         * stack pointer in the APPLICATION address space...
         * We assume that address spaces are implemented through segments...
         * What we have to do is to add the segment base to %esp:
         *      - Load the GDT base in a register
         *      - Add DS * 8 to that value
         *      - Read the corresponding GDT entry (the segment descriptor)
         *      - Compute the base...
         *      It is (*p & 0xFC) | (*(p +1)  & 0x0F) << 16) | *(p + 2)
         */
                        movl SYMBOL_NAME(GDT_base), %edi
                        addl %ebx, %edi
                        xorl %ebx, %ebx
                        movb 7(%edi), %bh
                        movb 4(%edi), %bl
                        shl $16, %ebx
                        movw 2(%edi), %bx
                        /* Is it correct? I think so... Test it!!! */
                        addl %ebx, %esp
                        /* Save EBX for returning to our stack... */
                        movw %ss, %dx
                        movw %ds, %cx
                        movw %cx, %ss
                        pushl %ebx
                        pushl %edx
                        pushl %eax

                        movl    SYMBOL_NAME(ll_irq_table)(, %eax, 4), %ebx
                        call    *%ebx
                
                        popl    %ebx    /* Store in EBX the Int number  */
                        popl    %eax
                        popl    %ecx    /* We must subtract it from ESP...*/
                        subl    %ecx, %esp
                        movw    %ax, %ss
                        
                        /* Resume the return value of _act_int          */
                        /* & do the context switch if necessary!        */
#ifdef __VIRCSW__
                        movw SYMBOL_NAME(currCtx), %ax
                        cmpw    JmpSel,%ax
                        je      NoPreempt3
                        movw    %ax,JmpSel
                        ljmp    *JmpZone 
#endif                  
NoPreempt3:             popl    %gs
                        popl    %fs
                        popl    %es
                        popl    %ss
                        popl    %ds
                        popal
                        iret

ll_handler_master_pic:             
                        /* We do not know what is the DS value  */
                        /* Then we save it & set it correctly   */
                        
                        pushl   %ds
                        pushl   %ss
                        pushl   %es
                        pushl   %fs
                        pushl   %gs
                        /* But we first transfer to the _act_int  */
                        /* the interrupt number which is required */
                        /* as second argument                     */
                        pushl   %eax
                        movw    $(X_FLATDATA_SEL),%ax
                        movw    %ax,%es
                        mov     %ax,%ds
        movw    %ax, %fs
        movw    %ax, %gs
                        
                        /* Now save the actual context on stack         */
                        /* to pass it to _act_int (C caling convention) */
                        /* CLD is necessary when calling a C function   */
                
                        cld
                        
                        /* The following could be optimized a little... */
                        popl %eax
                        xorl %ebx, %ebx
                        movw %ss, %bx
                        /* We must switch to a ``safe stack'' */
        /*
         * OK, this is the idea: in %esp we have the address of the
         * stack pointer in the APPLICATION address space...
         * We assume that address spaces are implemented through segments...
         * What we have to do is to add the segment base to %esp:
         *      - Load the GDT base in a register
         *      - Add DS * 8 to that value
         *      - Read the corresponding GDT entry (the segment descriptor)
         *      - Compute the base...
         *      It is (*p & 0xFC) | (*(p +1)  & 0x0F) << 16) | *(p + 2)
         */
                        movl SYMBOL_NAME(GDT_base), %edi
                        addl %ebx, %edi
                        xorl %ebx, %ebx
                        movb 7(%edi), %bh
                        movb 4(%edi), %bl
                        shl $16, %ebx
                        movw 2(%edi), %bx
                        /* Is it correct? I think so... Test it!!! */
                        addl %ebx, %esp
                        /* Save EBX for returning to our stack... */
                        movw %ss, %dx
                        movw %ds, %cx
                        movw %cx, %ss
                        pushl %ebx
                        pushl %edx
                        pushl %eax

                        movl    SYMBOL_NAME(ll_irq_table)(, %eax, 4), %ebx
                        call    *%ebx
                
                        popl    %ebx    /* Store in EBX the Int number  */
                        popl    %eax
                        popl    %ecx    /* We must subtract it from ESP...*/
                        subl    %ecx, %esp
                        movw    %ax, %ss
                        
                        /* Send EOI to master PIC */
                        movb    $0x20,%al
                        movl    $0x20,%edx
                        outb    %al,%dx

                        /* Resume the return value of _act_int          */
                        /* & do the context switch if necessary!        */
#ifdef __VIRCSW__
                        movw SYMBOL_NAME(currCtx), %ax
                        cmpw    JmpSel,%ax
                        je      NoPreempt4
                        movw    %ax,JmpSel
                        ljmp    *JmpZone 
#endif                  
NoPreempt4:             popl    %gs
                        popl    %fs
                        popl    %es
                        popl    %ss
                        popl    %ds
                        popal
                        iret

ll_handler_slave_pic:             
                        /* We do not know what is the DS value  */
                        /* Then we save it & set it correctly   */
                        
                        pushl   %ds
                        pushl   %ss
                        pushl   %es
                        pushl   %fs
                        pushl   %gs
                        /* But we first transfer to the _act_int  */
                        /* the interrupt number which is required */
                        /* as second argument                     */
                        pushl   %eax
                        movw    $(X_FLATDATA_SEL),%ax
                        movw    %ax,%es
                        mov     %ax,%ds
        movw    %ax, %fs
        movw    %ax, %gs
                        
                        /* Now save the actual context on stack         */
                        /* to pass it to _act_int (C caling convention) */
                        /* CLD is necessary when calling a C function   */
                
                        cld
                        
                        /* The following could be optimized a little... */
                        popl %eax
                        xorl %ebx, %ebx
                        movw %ss, %bx
                        /* We must switch to a ``safe stack'' */
        /*
         * OK, this is the idea: in %esp we have the address of the
         * stack pointer in the APPLICATION address space...
         * We assume that address spaces are implemented through segments...
         * What we have to do is to add the segment base to %esp:
         *      - Load the GDT base in a register
         *      - Add DS * 8 to that value
         *      - Read the corresponding GDT entry (the segment descriptor)
         *      - Compute the base...
         *      It is (*p & 0xFC) | (*(p +1)  & 0x0F) << 16) | *(p + 2)
         */
                        movl SYMBOL_NAME(GDT_base), %edi
                        addl %ebx, %edi
                        xorl %ebx, %ebx
                        movb 7(%edi), %bh
                        movb 4(%edi), %bl
                        shl $16, %ebx
                        movw 2(%edi), %bx
                        /* Is it correct? I think so... Test it!!! */
                        addl %ebx, %esp
                        /* Save EBX for returning to our stack... */
                        movw %ss, %dx
                        movw %ds, %cx
                        movw %cx, %ss
                        pushl %ebx
                        pushl %edx
                        pushl %eax

                        movl    SYMBOL_NAME(ll_irq_table)(, %eax, 4), %ebx
                        call    *%ebx
                
                        popl    %ebx    /* Store in EBX the Int number  */
                        popl    %eax
                        popl    %ecx    /* We must subtract it from ESP...*/
                        subl    %ecx, %esp
                        movw    %ax, %ss
                        
                        /* Send EOI to master & slave PIC */
                        movb    $0x20,%al
                        movl    $0xA0,%edx
                        outb    %al,%dx
                        movl    $0x20,%edx
                        outb    %al,%dx
                

                        /* Resume the return value of _act_int          */
                        /* & do the context switch if necessary!        */
#ifdef __VIRCSW__
                        movw SYMBOL_NAME(currCtx), %ax
                        cmpw    JmpSel,%ax
                        je      NoPreempt5
                        movw    %ax,JmpSel
                        ljmp    *JmpZone 
#endif                  
NoPreempt5:             popl    %gs
                        popl    %fs
                        popl    %es
                        popl    %ss
                        popl    %ds
                        popal
                        iret

ll_handler_vm86:
                        pushl   %ds
                        pushl   %ss
                        pushl   %es
                        pushl   %fs
                        pushl   %gs

                        pushl   %eax

                        movw    $(X_FLATDATA_SEL),%ax
                        movw    %ax,%es
                        movw    %ax,%ds
                        movw    %ax,%fs
                        movw    %ax,%gs

                        popl    %eax
                        pushl   %ebx

                        movl SYMBOL_NAME(global_regs),%ebx
                        movl %eax,56(%ebx)
                        movl %ecx,52(%ebx)
                        movl %edx,48(%ebx)
                        movl %edi,28(%ebx)
                        movl %esi,32(%ebx)

                        movl %ebx,%edi
                        popl %ebx
                        movl %ebx,44(%edi)

                        pushfl
                        popl %ebx
                        movl %ebx,68(%edi)

                        movw SYMBOL_NAME(VM86_ret_ctx), %ax
                        movw %ax,SYMBOL_NAME(currCtx)
                        movw %ax,JmpSel
                        ljmp *JmpZone

                        popl    %gs
                        popl    %fs
                        popl    %es
                        popl    %ss
                        popl    %ds
                        popal
                        iret


/* OK, this is Exception 7, and it is generated when an ESC or WAIT
 * intruction is reached, and the MP and TS bits are set... Basically,
 * it means that the FPU context must be switched
 */
SYMBOL_NAME_LABEL(exc7) pushal
                        pushl   %ds
                        pushl   %ss
                        pushl   %es
                        pushl   %fs
                        pushl   %gs
                        movw    $(X_FLATDATA_SEL),%ax
                        movw    %ax,%es
                        movw    %ax,%ds
                        cld
                        call    SYMBOL_NAME(ll_FPU_hook)
                        popl    %gs
                        popl    %fs
                        popl    %es
                        popl    %ss
                        popl    %ds
                        popal
                        iret