Subversion Repositories HelenOS-historic

Rev

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

Rev 794 Rev 799
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(struct exception_regdump *pstate)
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(pstate->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(pstate->ra);
74
    if (s)
74
    if (s)
75
        rasymbol = s;
75
        rasymbol = s;
76
   
76
   
77
    printf("PC: %X(%s) RA: %X(%s)\n",pstate->epc,pcsymbol,
77
    printf("PC: %X(%s) RA: %X(%s)\n",pstate->epc,pcsymbol,
78
           pstate->ra,rasymbol);
78
           pstate->ra,rasymbol);
79
}
79
}
80
 
80
 
81
static void unhandled_exception(int n, void *data)
81
static void unhandled_exception(int n, struct exception_regdump *pstate)
82
{
82
{
83
    struct exception_regdump *pstate = (struct exception_regdump *)data;
-
 
84
 
-
 
85
    print_regdump(pstate);
83
    print_regdump(pstate);
86
    panic("unhandled exception %s\n", exctable[n]);
84
    panic("unhandled exception %s\n", exctable[n]);
87
}
85
}
88
 
86
 
89
static void breakpoint_exception(int n, void *data)
87
static void breakpoint_exception(int n, struct exception_regdump *pstate)
90
{
88
{
91
    struct exception_regdump *pstate = (struct exception_regdump *)data;
-
 
92
 
-
 
93
#ifdef CONFIG_DEBUG
89
#ifdef CONFIG_DEBUG
94
    debugger_bpoint(pstate);
90
    debugger_bpoint(pstate);
95
#else
91
#else
96
    /* it is necessary to not re-execute BREAK instruction after
92
    /* it is necessary to not re-execute BREAK instruction after
97
       returning from Exception handler
93
       returning from Exception handler
98
       (see page 138 in R4000 Manual for more information) */
94
       (see page 138 in R4000 Manual for more information) */
99
    pstate->epc += 4;
95
    pstate->epc += 4;
100
#endif
96
#endif
101
}
97
}
102
 
98
 
103
static void tlbmod_exception(int n, void *data)
99
static void tlbmod_exception(int n, struct exception_regdump *pstate)
104
{
100
{
105
    struct exception_regdump *pstate = (struct exception_regdump *)data;
-
 
106
    tlb_modified(pstate);
101
    tlb_modified(pstate);
107
}
102
}
108
 
103
 
109
static void tlbinv_exception(int n, void *data)
104
static void tlbinv_exception(int n, struct exception_regdump *pstate)
110
{
105
{
111
    struct exception_regdump *pstate = (struct exception_regdump *)data;
-
 
112
    tlb_invalid(pstate);
106
    tlb_invalid(pstate);
113
}
107
}
114
 
108
 
115
#ifdef CONFIG_FPU_LAZY
109
#ifdef CONFIG_FPU_LAZY
116
static void cpuns_exception(int n, void *data)
110
static void cpuns_exception(int n, struct exception_regdump *pstate)
117
{
111
{
118
    if (cp0_cause_coperr(cp0_cause_read()) == fpu_cop_id)
112
    if (cp0_cause_coperr(cp0_cause_read()) == fpu_cop_id)
119
        scheduler_fpu_lazy_request();
113
        scheduler_fpu_lazy_request();
120
    else
114
    else
121
        panic("unhandled Coprocessor Unusable Exception\n");
115
        panic("unhandled Coprocessor Unusable Exception\n");
122
}
116
}
123
#endif
117
#endif
124
 
118
 
125
static void interrupt_exception(int n, void *pstate)
119
static void interrupt_exception(int n, struct exception_regdump *pstate)
126
{
120
{
127
    __u32 cause;
121
    __u32 cause;
128
    int i;
122
    int i;
129
   
123
   
130
    /* decode interrupt number and process the interrupt */
124
    /* decode interrupt number and process the interrupt */
131
    cause = (cp0_cause_read() >> 8) &0xff;
125
    cause = (cp0_cause_read() >> 8) &0xff;
132
   
126
   
133
    for (i = 0; i < 8; i++)
127
    for (i = 0; i < 8; i++)
134
        if (cause & (1 << i))
128
        if (cause & (1 << i))
135
            exc_dispatch(i+INT_OFFSET, pstate);
129
            exc_dispatch(i+INT_OFFSET, pstate);
136
}
130
}
137
 
131
 
138
#include <debug.h>
132
#include <debug.h>
139
/** Handle syscall userspace call */
133
/** Handle syscall userspace call */
140
static void syscall_exception(int n, void *data)
134
static void syscall_exception(int n, struct exception_regdump *pstate)
141
{
135
{
142
    struct exception_regdump *pstate = (struct exception_regdump *)data;
-
 
143
   
-
 
144
    if (pstate->a3 < SYSCALL_END)
136
    if (pstate->a3 < SYSCALL_END)
145
        pstate->v0 = syscall_table[pstate->a3](pstate->a0,
137
        pstate->v0 = syscall_table[pstate->a3](pstate->a0,
146
                               pstate->a1,
138
                               pstate->a1,
147
                               pstate->a2);
139
                               pstate->a2);
148
    else
140
    else
149
        panic("Undefined syscall %d", pstate->a3);
141
        panic("Undefined syscall %d", pstate->a3);
150
    pstate->epc += 4;
142
    pstate->epc += 4;
151
}
143
}
152
 
144
 
153
 
145
 
154
void exception(struct exception_regdump *pstate)
146
void exception(struct exception_regdump *pstate)
155
{
147
{
156
    int cause;
148
    int cause;
157
    int excno;
149
    int excno;
158
 
150
 
159
    ASSERT(CPU != NULL);
151
    ASSERT(CPU != NULL);
160
 
152
 
161
    /*
153
    /*
162
     * NOTE ON OPERATION ORDERING
154
     * NOTE ON OPERATION ORDERING
163
     *
155
     *
164
     * On entry, interrupts_disable() must be called before
156
     * On entry, interrupts_disable() must be called before
165
     * exception bit is cleared.
157
     * exception bit is cleared.
166
     */
158
     */
167
 
159
 
168
    interrupts_disable();
160
    interrupts_disable();
169
    cp0_status_write(cp0_status_read() & ~ (cp0_status_exl_exception_bit |
161
    cp0_status_write(cp0_status_read() & ~ (cp0_status_exl_exception_bit |
170
                        cp0_status_um_bit));
162
                        cp0_status_um_bit));
171
 
163
 
172
    /* Save pstate so that the threads can access it */
164
    /* Save pstate so that the threads can access it */
173
    /* If THREAD->pstate is set, this is nested exception,
165
    /* If THREAD->pstate is set, this is nested exception,
174
     * do not rewrite it
166
     * do not rewrite it
175
     */
167
     */
176
    if (THREAD && !THREAD->pstate)
168
    if (THREAD && !THREAD->pstate)
177
        THREAD->pstate = pstate;
169
        THREAD->pstate = pstate;
178
 
170
 
179
    cause = cp0_cause_read();
171
    cause = cp0_cause_read();
180
    excno = cp0_cause_excno(cause);
172
    excno = cp0_cause_excno(cause);
181
    /* Dispatch exception */
173
    /* Dispatch exception */
182
    exc_dispatch(excno, pstate);
174
    exc_dispatch(excno, pstate);
183
 
175
 
184
    /* Set to NULL, so that we can still support nested
176
    /* Set to NULL, so that we can still support nested
185
     * exceptions
177
     * exceptions
186
     * TODO: We should probably set EXL bit before this command,
178
     * TODO: We should probably set EXL bit before this command,
187
     * nesting. On the other hand, if some exception occurs between
179
     * nesting. On the other hand, if some exception occurs between
188
     * here and ERET, it won't set anything on the pstate anyway.
180
     * here and ERET, it won't set anything on the pstate anyway.
189
     */
181
     */
190
    if (THREAD)
182
    if (THREAD)
191
        THREAD->pstate = NULL;
183
        THREAD->pstate = NULL;
192
}
184
}
193
 
185
 
194
void exception_init(void)
186
void exception_init(void)
195
{
187
{
196
    int i;
188
    int i;
197
 
189
 
198
    /* Clear exception table */
190
    /* Clear exception table */
199
    for (i=0;i < IVT_ITEMS; i++)
191
    for (i=0;i < IVT_ITEMS; i++)
200
        exc_register(i, "undef", unhandled_exception);
192
        exc_register(i, "undef", (iroutine) unhandled_exception);
201
    exc_register(EXC_Bp, "bkpoint", breakpoint_exception);
193
    exc_register(EXC_Bp, "bkpoint", (iroutine) breakpoint_exception);
202
    exc_register(EXC_Mod, "tlb_mod", tlbmod_exception);
194
    exc_register(EXC_Mod, "tlb_mod", (iroutine) tlbmod_exception);
203
    exc_register(EXC_TLBL, "tlbinvl", tlbinv_exception);
195
    exc_register(EXC_TLBL, "tlbinvl", (iroutine) tlbinv_exception);
204
    exc_register(EXC_TLBS, "tlbinvl", tlbinv_exception);
196
    exc_register(EXC_TLBS, "tlbinvl", (iroutine) tlbinv_exception);
205
    exc_register(EXC_Int, "interrupt", interrupt_exception);
197
    exc_register(EXC_Int, "interrupt", (iroutine) interrupt_exception);
206
#ifdef CONFIG_FPU_LAZY
198
#ifdef CONFIG_FPU_LAZY
207
    exc_register(EXC_CpU, "cpunus", cpuns_exception);
199
    exc_register(EXC_CpU, "cpunus", (iroutine) cpuns_exception);
208
#endif
200
#endif
209
    exc_register(EXC_Sys, "syscall", syscall_exception);
201
    exc_register(EXC_Sys, "syscall", (iroutine) syscall_exception);
210
}
202
}
211
 
203