Subversion Repositories HelenOS-historic

Rev

Rev 955 | Rev 959 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 955 Rev 958
1
/*
1
/*
2
 * Copyright (C) 2003-2004 Jakub Jermar
2
 * Copyright (C) 2003-2004 Jakub Jermar
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
#include <arch/exception.h>
29
#include <arch/exception.h>
30
#include <arch/interrupt.h>
30
#include <arch/interrupt.h>
31
#include <panic.h>
31
#include <panic.h>
32
#include <arch/cp0.h>
32
#include <arch/cp0.h>
33
#include <arch/types.h>
33
#include <arch/types.h>
34
#include <arch.h>
34
#include <arch.h>
35
#include <debug.h>
35
#include <debug.h>
36
#include <proc/thread.h>
36
#include <proc/thread.h>
37
#include <symtab.h>
37
#include <symtab.h>
38
#include <print.h>
38
#include <print.h>
39
#include <interrupt.h>
39
#include <interrupt.h>
40
#include <func.h>
40
#include <func.h>
41
#include <console/kconsole.h>
41
#include <console/kconsole.h>
42
#include <arch/debugger.h>
42
#include <arch/debugger.h>
43
#include <syscall/syscall.h>
43
#include <syscall/syscall.h>
44
 
44
 
45
static char * exctable[] = {
45
static char * exctable[] = {
46
    "Interrupt","TLB Modified","TLB Invalid","TLB Invalid Store",
46
    "Interrupt","TLB Modified","TLB Invalid","TLB Invalid Store",
47
        "Address Error - load/instr. fetch",
47
        "Address Error - load/instr. fetch",
48
        "Address Error - store",
48
        "Address Error - store",
49
        "Bus Error - fetch instruction",
49
        "Bus Error - fetch instruction",
50
        "Bus Error - data reference",
50
        "Bus Error - data reference",
51
        "Syscall",
51
        "Syscall",
52
        "BreakPoint",
52
        "BreakPoint",
53
        "Reserved Instruction",
53
        "Reserved Instruction",
54
        "Coprocessor Unusable",
54
        "Coprocessor Unusable",
55
        "Arithmetic Overflow",
55
        "Arithmetic Overflow",
56
        "Trap",
56
        "Trap",
57
        "Virtual Coherency - instruction",
57
        "Virtual Coherency - instruction",
58
        "Floating Point",
58
        "Floating Point",
59
        NULL, NULL, NULL, NULL, NULL, NULL, NULL,
59
        NULL, NULL, NULL, NULL, NULL, NULL, NULL,
60
        "WatchHi/WatchLo", /* 23 */
60
        "WatchHi/WatchLo", /* 23 */
61
        NULL, NULL, NULL, NULL, NULL, NULL, NULL,
61
        NULL, NULL, NULL, NULL, NULL, NULL, NULL,
62
        "Virtual Coherency - data",
62
        "Virtual Coherency - data",
63
};
63
};
64
 
64
 
65
static void print_regdump(struct exception_regdump *pstate)
65
static void print_regdump(istate_t *istate)
66
{
66
{
67
    char *pcsymbol = "";
67
    char *pcsymbol = "";
68
    char *rasymbol = "";
68
    char *rasymbol = "";
69
 
69
 
70
    char *s = get_symtab_entry(pstate->epc);
70
    char *s = get_symtab_entry(istate->epc);
71
    if (s)
71
    if (s)
72
        pcsymbol = s;
72
        pcsymbol = s;
73
    s = get_symtab_entry(pstate->ra);
73
    s = get_symtab_entry(istate->ra);
74
    if (s)
74
    if (s)
75
        rasymbol = s;
75
        rasymbol = s;
76
   
76
   
77
    printf("PC: %X(%s) RA: %X(%s), SP(%P)\n",pstate->epc,pcsymbol,
77
    printf("PC: %X(%s) RA: %X(%s), SP(%P)\n",istate->epc,pcsymbol,
78
           pstate->ra,rasymbol, pstate->sp);
78
           istate->ra,rasymbol, istate->sp);
79
}
79
}
80
 
80
 
81
static void unhandled_exception(int n, struct exception_regdump *pstate)
81
static void unhandled_exception(int n, istate_t *istate)
82
{
82
{
83
    print_regdump(pstate);
83
    print_regdump(istate);
84
    panic("unhandled exception %s\n", exctable[n]);
84
    panic("unhandled exception %s\n", exctable[n]);
85
}
85
}
86
 
86
 
87
static void breakpoint_exception(int n, struct exception_regdump *pstate)
87
static void breakpoint_exception(int n, istate_t *istate)
88
{
88
{
89
#ifdef CONFIG_DEBUG
89
#ifdef CONFIG_DEBUG
90
    debugger_bpoint(pstate);
90
    debugger_bpoint(istate);
91
#else
91
#else
92
    /* it is necessary to not re-execute BREAK instruction after
92
    /* it is necessary to not re-execute BREAK instruction after
93
       returning from Exception handler
93
       returning from Exception handler
94
       (see page 138 in R4000 Manual for more information) */
94
       (see page 138 in R4000 Manual for more information) */
95
    pstate->epc += 4;
95
    istate->epc += 4;
96
#endif
96
#endif
97
}
97
}
98
 
98
 
99
static void tlbmod_exception(int n, struct exception_regdump *pstate)
99
static void tlbmod_exception(int n, istate_t *istate)
100
{
100
{
101
    tlb_modified(pstate);
101
    tlb_modified(istate);
102
}
102
}
103
 
103
 
104
static void tlbinv_exception(int n, struct exception_regdump *pstate)
104
static void tlbinv_exception(int n, istate_t *istate)
105
{
105
{
106
    tlb_invalid(pstate);
106
    tlb_invalid(istate);
107
}
107
}
108
 
108
 
109
#ifdef CONFIG_FPU_LAZY
109
#ifdef CONFIG_FPU_LAZY
110
static void cpuns_exception(int n, struct exception_regdump *pstate)
110
static void cpuns_exception(int n, istate_t *istate)
111
{
111
{
112
    if (cp0_cause_coperr(cp0_cause_read()) == fpu_cop_id)
112
    if (cp0_cause_coperr(cp0_cause_read()) == fpu_cop_id)
113
        scheduler_fpu_lazy_request();
113
        scheduler_fpu_lazy_request();
114
    else
114
    else
115
        panic("unhandled Coprocessor Unusable Exception\n");
115
        panic("unhandled Coprocessor Unusable Exception\n");
116
}
116
}
117
#endif
117
#endif
118
 
118
 
119
static void interrupt_exception(int n, struct exception_regdump *pstate)
119
static void interrupt_exception(int n, istate_t *istate)
120
{
120
{
121
    __u32 cause;
121
    __u32 cause;
122
    int i;
122
    int i;
123
   
123
   
124
    /* decode interrupt number and process the interrupt */
124
    /* decode interrupt number and process the interrupt */
125
    cause = (cp0_cause_read() >> 8) &0xff;
125
    cause = (cp0_cause_read() >> 8) &0xff;
126
   
126
   
127
    for (i = 0; i < 8; i++)
127
    for (i = 0; i < 8; i++)
128
        if (cause & (1 << i))
128
        if (cause & (1 << i))
129
            exc_dispatch(i+INT_OFFSET, pstate);
129
            exc_dispatch(i+INT_OFFSET, istate);
130
}
130
}
131
 
131
 
132
#include <debug.h>
132
#include <debug.h>
133
/** Handle syscall userspace call */
133
/** Handle syscall userspace call */
134
static void syscall_exception(int n, struct exception_regdump *pstate)
134
static void syscall_exception(int n, istate_t *istate)
135
{
135
{
136
    interrupts_enable();
136
    interrupts_enable();
137
    if (pstate->a3 < SYSCALL_END)
137
    if (istate->a3 < SYSCALL_END)
138
        pstate->v0 = syscall_table[pstate->a3](pstate->a0,
138
        istate->v0 = syscall_table[istate->a3](istate->a0,
139
                               pstate->a1,
139
                               istate->a1,
140
                               pstate->a2);
140
                               istate->a2);
141
    else
141
    else
142
        panic("Undefined syscall %d", pstate->a3);
142
        panic("Undefined syscall %d", istate->a3);
-
 
143
    istate->epc += 4;
143
    interrupts_disable();
144
    interrupts_disable();
144
    pstate->epc += 4;
-
 
145
}
145
}
146
 
146
 
147
 
-
 
148
void exception(struct exception_regdump *pstate)
147
void exception(istate_t *istate)
149
{
148
{
150
    int cause;
149
    int cause;
151
    int excno;
150
    int excno;
152
 
151
 
153
    ASSERT(CPU != NULL);
152
    ASSERT(CPU != NULL);
154
 
153
 
155
    /*
154
    /*
156
     * NOTE ON OPERATION ORDERING
155
     * NOTE ON OPERATION ORDERING
157
     *
156
     *
158
     * On entry, interrupts_disable() must be called before
157
     * On entry, interrupts_disable() must be called before
159
     * exception bit is cleared.
158
     * exception bit is cleared.
160
     */
159
     */
161
 
160
 
162
    interrupts_disable();
161
    interrupts_disable();
163
    cp0_status_write(cp0_status_read() & ~ (cp0_status_exl_exception_bit |
162
    cp0_status_write(cp0_status_read() & ~ (cp0_status_exl_exception_bit |
164
                        cp0_status_um_bit));
163
                        cp0_status_um_bit));
165
 
164
 
166
    /* Save pstate so that the threads can access it */
165
    /* Save istate so that the threads can access it */
167
    /* If THREAD->pstate is set, this is nested exception,
166
    /* If THREAD->istate is set, this is nested exception,
168
     * do not rewrite it
167
     * do not rewrite it
169
     */
168
     */
170
    if (THREAD && !THREAD->pstate)
169
    if (THREAD && !THREAD->istate)
171
        THREAD->pstate = pstate;
170
        THREAD->istate = istate;
172
 
171
 
173
    cause = cp0_cause_read();
172
    cause = cp0_cause_read();
174
    excno = cp0_cause_excno(cause);
173
    excno = cp0_cause_excno(cause);
175
    /* Dispatch exception */
174
    /* Dispatch exception */
176
    exc_dispatch(excno, pstate);
175
    exc_dispatch(excno, istate);
177
 
176
 
178
    /* Set to NULL, so that we can still support nested
177
    /* Set to NULL, so that we can still support nested
179
     * exceptions
178
     * exceptions
180
     * TODO: We should probably set EXL bit before this command,
179
     * TODO: We should probably set EXL bit before this command,
181
     * nesting. On the other hand, if some exception occurs between
180
     * nesting. On the other hand, if some exception occurs between
182
     * here and ERET, it won't set anything on the pstate anyway.
181
     * here and ERET, it won't set anything on the istate anyway.
183
     */
182
     */
184
    if (THREAD)
183
    if (THREAD)
185
        THREAD->pstate = NULL;
184
        THREAD->istate = NULL;
186
}
185
}
187
 
186
 
188
void exception_init(void)
187
void exception_init(void)
189
{
188
{
190
    int i;
189
    int i;
191
 
190
 
192
    /* Clear exception table */
191
    /* Clear exception table */
193
    for (i=0;i < IVT_ITEMS; i++)
192
    for (i=0;i < IVT_ITEMS; i++)
194
        exc_register(i, "undef", (iroutine) unhandled_exception);
193
        exc_register(i, "undef", (iroutine) unhandled_exception);
195
    exc_register(EXC_Bp, "bkpoint", (iroutine) breakpoint_exception);
194
    exc_register(EXC_Bp, "bkpoint", (iroutine) breakpoint_exception);
196
    exc_register(EXC_Mod, "tlb_mod", (iroutine) tlbmod_exception);
195
    exc_register(EXC_Mod, "tlb_mod", (iroutine) tlbmod_exception);
197
    exc_register(EXC_TLBL, "tlbinvl", (iroutine) tlbinv_exception);
196
    exc_register(EXC_TLBL, "tlbinvl", (iroutine) tlbinv_exception);
198
    exc_register(EXC_TLBS, "tlbinvl", (iroutine) tlbinv_exception);
197
    exc_register(EXC_TLBS, "tlbinvl", (iroutine) tlbinv_exception);
199
    exc_register(EXC_Int, "interrupt", (iroutine) interrupt_exception);
198
    exc_register(EXC_Int, "interrupt", (iroutine) interrupt_exception);
200
#ifdef CONFIG_FPU_LAZY
199
#ifdef CONFIG_FPU_LAZY
201
    exc_register(EXC_CpU, "cpunus", (iroutine) cpuns_exception);
200
    exc_register(EXC_CpU, "cpunus", (iroutine) cpuns_exception);
202
#endif
201
#endif
203
    exc_register(EXC_Sys, "syscall", (iroutine) syscall_exception);
202
    exc_register(EXC_Sys, "syscall", (iroutine) syscall_exception);
204
}
203
}
205
 
204