Subversion Repositories HelenOS

Rev

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

Rev 2278 Rev 2284
1
/*
1
/*
2
 * Copyright (c) 2007 Pavel Jancik, Michal Kebrt
2
 * Copyright (c) 2007 Pavel Jancik, Michal Kebrt
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
/** @addtogroup arm32mm
29
/** @addtogroup arm32mm
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
#include <panic.h>
34
#include <panic.h>
35
#include <arch/exception.h>
35
#include <arch/exception.h>
36
#include <arch/debug_print/print.h>
36
#include <arch/debug_print/print.h>
37
#include <arch/mm/page_fault.h>
37
#include <arch/mm/page_fault.h>
38
#include <mm/as.h>
38
#include <mm/as.h>
39
#include <genarch/mm/page_pt.h>
39
#include <genarch/mm/page_pt.h>
40
#include <arch.h>
40
#include <arch.h>
-
 
41
#include <interrupt.h>
41
 
42
 
42
 
43
 
43
//TODO: remove in final version
44
//TODO: remove in final version
44
static void print_istate(istate_t* istate);
45
static void print_istate(istate_t* istate);
45
static void print_istate(istate_t* istate) {
46
static void print_istate(istate_t* istate) {
46
 dprintf("\nIstate dump:\n");
47
 dprintf("\nIstate dump:\n");
47
 dprintf("    r0:%X    r1:%X    r2:%X    r3:%X\n", istate->r0,  istate->r1, istate->r2,  istate->r3);
48
 dprintf("    r0:%X    r1:%X    r2:%X    r3:%X\n", istate->r0,  istate->r1, istate->r2,  istate->r3);
48
 dprintf("    r4:%X    r5:%X    r6:%X    r7:%X\n", istate->r4,  istate->r5, istate->r6,  istate->r7);
49
 dprintf("    r4:%X    r5:%X    r6:%X    r7:%X\n", istate->r4,  istate->r5, istate->r6,  istate->r7);
49
 dprintf("    r8:%X    r8:%X   r10:%X   r11:%X\n", istate->r8,  istate->r9, istate->r10, istate->r11);
50
 dprintf("    r8:%X    r8:%X   r10:%X   r11:%X\n", istate->r8,  istate->r9, istate->r10, istate->r11);
50
 dprintf("   r12:%X    sp:%X    lr:%X  spsr:%X\n", istate->r12, istate->sp, istate->lr,  istate->spsr);
51
 dprintf("   r12:%X    sp:%X    lr:%X  spsr:%X\n", istate->r12, istate->sp, istate->lr,  istate->spsr);
51
}
52
}
52
 
53
 
53
/**
54
/**
54
 * \return Value stored in fault status register
55
 * \return Value stored in fault status register
55
 */
56
 */
56
static inline fault_status_t read_fault_status_register() {
57
static inline fault_status_t read_fault_status_register() {
57
        fault_status_union_t tmp;
58
        fault_status_union_t tmp;
58
        asm volatile (
59
        asm volatile (
59
        "mrc p15, 0, %0, c5, c0, 0"
60
        "mrc p15, 0, %0, c5, c0, 0"
60
            : "=r"(tmp.dummy)
61
            : "=r"(tmp.dummy)
61
    );
62
    );
62
    return tmp.fsr;
63
    return tmp.fsr;
63
}
64
}
64
 
65
 
65
/**
66
/**
66
 * \return Virtual adress. Access on this addres caused exception
67
 * \return Virtual adress. Access on this addres caused exception
67
 */
68
 */
68
static inline uintptr_t read_fault_address_register() {
69
static inline uintptr_t read_fault_address_register() {
69
        uintptr_t tmp;
70
        uintptr_t tmp;
70
    // Fault adress is stored in coprocessor15, register 6
71
    // Fault adress is stored in coprocessor15, register 6
71
    asm volatile (
72
    asm volatile (
72
        "mrc p15, 0, %0, c6, c0, 0"
73
        "mrc p15, 0, %0, c6, c0, 0"
73
        : "=r"(tmp)
74
        : "=r"(tmp)
74
    );
75
    );
75
    return tmp;
76
    return tmp;
76
};
77
};
77
 
78
 
78
/** Check type of instruction
79
/** Check type of instruction
79
 * \param i_code Instruction op code
80
 * \param i_code Instruction op code
80
 * \return true if instruction is load or store, false otherwise
81
 * \return true if instruction is load or store, false otherwise
81
 */
82
 */
82
static inline bool load_store_instruction(instruction_t i_code) {
83
static inline bool load_store_instruction(instruction_t i_code) {
83
 
84
 
84
     // load store immediate offset
85
     // load store immediate offset
85
    if (i_code.instr_type == 0x2) {
86
    if (i_code.instr_type == 0x2) {
86
        return true;
87
        return true;
87
    };
88
    };
88
 
89
 
89
        // load store register offset
90
        // load store register offset
90
        if (i_code.instr_type == 0x3 && i_code.bit4 == 0) {
91
        if (i_code.instr_type == 0x3 && i_code.bit4 == 0) {
91
        return true;
92
        return true;
92
    };
93
    };
93
 
94
 
94
        // load store multiple
95
        // load store multiple
95
        if (i_code.instr_type == 0x4) {
96
        if (i_code.instr_type == 0x4) {
96
        return true;
97
        return true;
97
    };
98
    };
98
 
99
 
99
        // coprocessor load / strore
100
        // coprocessor load / strore
100
    if (i_code.instr_type == 0x6) {
101
    if (i_code.instr_type == 0x6) {
101
        return true;
102
        return true;
102
    };
103
    };
103
 
104
 
104
    return false;
105
    return false;
105
}
106
}
106
 
107
 
107
/** Check type of instruction
108
/** Check type of instruction
108
 * \param i_code Instruction op code
109
 * \param i_code Instruction op code
109
 * \return true if instruction is swap, false otherwise
110
 * \return true if instruction is swap, false otherwise
110
 */
111
 */
111
static inline bool swap_instruction(instruction_t i_code) {
112
static inline bool swap_instruction(instruction_t i_code) {
112
 
113
 
113
    // swap, swapb instruction
114
    // swap, swapb instruction
114
    if (i_code.instr_type == 0x0 &&
115
    if (i_code.instr_type == 0x0 &&
115
        (i_code.opcode == 0x8 || i_code.opcode == 0xA) &&
116
        (i_code.opcode == 0x8 || i_code.opcode == 0xA) &&
116
        i_code.access == 0x0 && i_code.bits567 == 0x4 &&
117
        i_code.access == 0x0 && i_code.bits567 == 0x4 &&
117
        i_code.bit4 == 1) {
118
        i_code.bit4 == 1) {
118
        return true;
119
        return true;
119
    };
120
    };
120
 
121
 
121
    return false;
122
    return false;
122
}
123
}
123
 
124
 
124
 
125
 
125
/**
126
/**
126
 * Decode instruction and decide if try to read or write into memmory.
127
 * Decode instruction and decide if try to read or write into memmory.
127
 *
128
 *
128
 * \param instr_addr address of instruction which attempts access into memmory
129
 * \param instr_addr address of instruction which attempts access into memmory
129
 * \param badvaddr Virtual address on which instruction tries to access
130
 * \param badvaddr Virtual address on which instruction tries to access
130
 * \return type of access into memmory
131
 * \return type of access into memmory
131
 *  Note: return PF_ACESS_EXEC if no memmory acess
132
 *  Note: return PF_ACESS_EXEC if no memmory acess
132
 */
133
 */
133
//TODO: remove debug print in final version ... instead panic return PF_ACESS_EXEC
134
//TODO: remove debug print in final version ... instead panic return PF_ACESS_EXEC
134
static pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr) {
135
static pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr) {
135
        instruction_union_t tmp;
136
        instruction_union_t tmp;
136
        tmp.ip = instr_addr;
137
        tmp.ip = instr_addr;
137
    // get instruction op code
138
    // get instruction op code
138
    instruction_t i_code = *(tmp.instr);
139
    instruction_t i_code = *(tmp.instr);
139
 
140
 
140
        dprintf("get_instruction_memmory_access\n");
141
//         dprintf("get_instruction_memmory_access\n");
141
    dprintf(" instr_addr:%X\n",instr_addr);
142
//  dprintf(" instr_addr:%X\n",instr_addr);
142
    dprintf(" i_code:%X\n",i_code);
143
//  dprintf(" i_code:%X\n",i_code);
143
    dprintf(" i_code.condition:%d\n", i_code.condition);
144
//  dprintf(" i_code.condition:%d\n", i_code.condition);
144
    dprintf(" i_code.instr_type:%d\n",i_code.instr_type);
145
//  dprintf(" i_code.instr_type:%d\n",i_code.instr_type);
145
    dprintf(" i_code.opcode:%d\n",i_code.opcode);
146
//  dprintf(" i_code.opcode:%d\n",i_code.opcode);
146
    dprintf(" i_code.acess:%d\n", i_code.access);
147
//  dprintf(" i_code.acess:%d\n", i_code.access);
147
    dprintf(" i_code.dummy:%d\n", i_code.dummy);
148
//  dprintf(" i_code.dummy:%d\n", i_code.dummy);
148
    dprintf(" i_code.bits567%d\n", i_code.bits567);
149
//  dprintf(" i_code.bits567%d\n", i_code.bits567);
149
    dprintf(" i_code.bit4:%d\n", i_code.bit4);
150
//  dprintf(" i_code.bit4:%d\n", i_code.bit4);
150
    dprintf(" i_code.dummy1:%d\n", i_code.dummy1);
151
//  dprintf(" i_code.dummy1:%d\n", i_code.dummy1);
151
 
152
 
152
 
153
 
153
        // undefined instructions ... (or special instructions)
154
        // undefined instructions ... (or special instructions)
154
    if (i_code.condition == 0xf) {
155
    if (i_code.condition == 0xf) {
155
        panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
156
        panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
156
        return PF_ACCESS_EXEC;
157
        return PF_ACCESS_EXEC;
157
    };
158
    };
158
 
159
 
159
    // load store instructions
160
    // load store instructions
160
        if (load_store_instruction(i_code)) {
161
        if (load_store_instruction(i_code)) {
161
        if ( i_code.access == 1) {
162
        if ( i_code.access == 1) {
162
            return PF_ACCESS_READ;
163
            return PF_ACCESS_READ;
163
        } else {
164
        } else {
164
            return PF_ACCESS_WRITE;
165
            return PF_ACCESS_WRITE;
165
        }
166
        }
166
    };
167
    };
167
 
168
 
168
    // swap, swpb instruction
169
    // swap, swpb instruction
169
    if (swap_instruction(i_code))
170
    if (swap_instruction(i_code))
170
     {
171
     {
171
        /* Swap instructions make read and write in one step.
172
        /* Swap instructions make read and write in one step.
172
         * Type of access that caused exception have to page tables
173
         * Type of access that caused exception have to page tables
173
         *  and access rights.
174
         *  and access rights.
174
         */
175
         */
175
//TODO: ALF!!!!! cann't use AS as is define as THE->as and THE structure is sored after stack_base of current thread
176
//TODO: ALF!!!!! cann't use AS as is define as THE->as and THE structure is sored after stack_base of current thread
176
//      but now ... in exception we have separate stacks <==> different stack_pointer ... so AS contains nonsence data
177
//      but now ... in exception we have separate stacks <==> different stack_pointer ... so AS contains nonsence data
177
//  same case as_page_fault .... it's nessesary to solve "stack" problem
178
//  same case as_page_fault .... it's nessesary to solve "stack" problem
178
                pte_level1_t* pte = (pte_level1_t*)
179
                pte_level1_t* pte = (pte_level1_t*)
179
            pt_mapping_operations.mapping_find(AS, badvaddr);
180
            pt_mapping_operations.mapping_find(AS, badvaddr);
180
 
181
 
181
        ASSERT(pte);
182
        ASSERT(pte);
182
 
183
 
183
                /* check if read possible
184
                /* check if read possible
184
                 * Note: Don't check PTE_READABLE because it returns 1 everytimes */
185
                 * Note: Don't check PTE_READABLE because it returns 1 everytimes */
185
        if ( !PTE_PRESENT(pte) ) {
186
        if ( !PTE_PRESENT(pte) ) {
186
                return PF_ACCESS_READ;
187
                return PF_ACCESS_READ;
187
        }
188
        }
188
        if ( !PTE_WRITABLE(pte) ) {
189
        if ( !PTE_WRITABLE(pte) ) {
189
            return PF_ACCESS_WRITE;
190
            return PF_ACCESS_WRITE;
190
        }
191
        }
191
        else
192
        else
192
            // badvaddr is present readable and writeable but error occured ... why?
193
            // badvaddr is present readable and writeable but error occured ... why?
193
            panic("page_fault - swap instruction, but address readable and writeable (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
194
            panic("page_fault - swap instruction, but address readable and writeable (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
194
    }
195
    }
195
    panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
196
    panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
196
    return PF_ACCESS_EXEC;
197
    return PF_ACCESS_EXEC;
197
}
198
}
198
 
199
 
199
/**
200
/**
200
 * Routine that solves exception data_abourt
201
 * Routine that solves exception data_abourt
201
 *  ... you try to load or store value into invalid memmory address
202
 *  ... you try to load or store value into invalid memmory address
202
 * \param istate State of CPU when data abourt occured
203
 * \param istate State of CPU when data abourt occured
203
 * \param n number of exception
204
 * \param n number of exception
204
 */
205
 */
205
//TODO: remove debug prints in final tested version
206
//TODO: remove debug prints in final tested version
206
void data_abort(int n, istate_t *istate) {
207
void data_abort(int n, istate_t *istate) {
207
        fault_status_t fsr = read_fault_status_register();
208
        fault_status_t fsr = read_fault_status_register();
208
        uintptr_t  page = read_fault_address_register();
209
        uintptr_t  page = read_fault_address_register();
209
 
210
 
210
    pf_access_t access = get_memmory_access_type( istate->lr, page);
211
    pf_access_t access = get_memmory_access_type( istate->lr, page);
211
 
212
 
212
    print_istate(istate);
213
//  print_istate(istate);
213
    dprintf(" page fault : ip:%X, va:%X, status:%x(%x), access:%d\n", istate->lr, page, fsr.status,fsr, access);
214
    dprintf(" page fault : ip:%X, va:%X, status:%x(%x), access:%d\n", istate->lr, page, fsr.status,fsr, access);
214
 
215
 
215
/* Alf: Will be commented until stack problem will be solved ...
216
/* Alf: Will be commented until stack problem will be solved ...
216
    as_page_fault make consequent page faults
217
    as_page_fault make consequent page faults*/
217
 
218
 
218
        int ret = as_page_fault(page, access, istate);
219
        int ret = as_page_fault(page, access, istate);
219
    dprintf(" as_page_fault ret:%d\n", ret);
220
    dprintf(" as_page_fault ret:%d\n", ret);
220
        if (ret == AS_PF_FAULT) {
221
        if (ret == AS_PF_FAULT) {
221
        fault_if_from_uspace(istate, "Page fault: %#x", page);
222
        fault_if_from_uspace(istate, "Page fault: %#x", page);
222
 
223
 
223
                panic("page fault\n");
224
                panic("page fault\n");
224
        }
225
        }
225
*/
226
 
226
    // TODO: Remove this ... now for testing purposes ... it's bad to test page faults in kernel, where no page faults should occures
227
    // TODO: Remove this ... now for testing purposes ... it's bad to test page faults in kernel, where no page faults should occures
227
    panic("page fault ... solved\n");
228
    panic("page fault ... solved\n");
228
 
229
 
229
}
230
}
230
 
231
 
231
/**
232
/**
232
 * Routine that solves exception prefetch_about
233
 * Routine that solves exception prefetch_about
233
 *  ... you try to execute instruction on invalid address
234
 *  ... you try to execute instruction on invalid address
234
 * \param istate State of CPU when prefetch abourt occured
235
 * \param istate State of CPU when prefetch abourt occured
235
 * \param n number of exception
236
 * \param n number of exception
236
 */
237
 */
237
void prefetch_abort(int n, istate_t *istate) {
238
void prefetch_abort(int n, istate_t *istate) {
238
 // Prefetch can be made be bkpt instruction
239
 // Prefetch can be made be bkpt instruction
239
    print_istate(istate);
240
    print_istate(istate);
240
    dprintf(" prefetch_abourt ... instruction on adress:%x can't be fetched\n", istate->lr);
241
    dprintf(" prefetch_abourt ... instruction on adress:%x can't be fetched\n", istate->lr);
241
 
242
 
242
/* Alf: Will be commented until stack problem will be solved ...
243
/* Alf: Will be commented until stack problem will be solved ...
243
    as_page_fault make consequent page faults
244
    as_page_fault make consequent page faults*/
244
 
245
 
245
    int ret = as_page_fault(istate->lr, PF_ACCESS_EXEC, istate);
246
    int ret = as_page_fault(istate->lr, PF_ACCESS_EXEC, istate);
246
    dprintf(" as_page_fault ret:%d\n", ret);
247
    dprintf(" as_page_fault ret:%d\n", ret);
247
        if (ret == AS_PF_FAULT) {
248
        if (ret == AS_PF_FAULT) {
248
                panic("page fault - instruction fetch at addr:%X\n", istate->lr);
249
                panic("page fault - instruction fetch at addr:%X\n", istate->lr);
249
        }
250
        }
250
*/
251
 
251
 
252
 
252
    panic("Prefetch abourt ... solved");
253
    panic("Prefetch abourt ... solved");
253
}
254
}
254
 
255
 
255
/** @}
256
/** @}
256
 */
257
 */
257
 
258
 
258
 
259