Subversion Repositories HelenOS

Rev

Rev 2298 | Rev 2318 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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