Subversion Repositories HelenOS

Rev

Rev 2258 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2128 jermar 1
/*
2238 kebrt 2
 * Copyright (c) 2007 Pavel Jancik, Michal Kebrt
2128 jermar 3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
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
15
 *   derived from this software without specific prior written permission.
16
 *
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
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
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
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
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
 
29
/** @addtogroup arm32mm
30
 * @{
31
 */
32
/** @file
33
 */
34
 
35
#include <arch/mm/page.h>
36
#include <genarch/mm/page_pt.h>
2258 jancik 37
#include <arch.h>
2128 jermar 38
#include <mm/page.h>
2182 jancik 39
#include <align.h>
40
#include <config.h>
2258 jancik 41
#include <arch/exception.h>
42
#include <typedefs.h>
43
#include <arch/types.h>
44
#include <interrupt.h>
45
 
46
//TODO: remove in final version
2182 jancik 47
#include "../aux_print/printf.h"
2128 jermar 48
 
2258 jancik 49
 
50
// localy used types
51
/**
52
 * Decribes structure of fault status register in coprocessor 15
53
 */
54
typedef struct {
55
        unsigned status              : 3;
56
        unsigned domain              : 4;
57
        unsigned zero            : 1;
58
        unsigned should_be_zero      : 24;
59
} __attribute__ ((packed)) fault_status_t;
60
 
61
/**
62
 * Help union used for overcasting integer value into fault_status_t type
63
 */
64
typedef union {
65
    fault_status_t  fsr;
66
    uint32_t    dummy;
67
} fault_status_union_t;
68
 
69
/**
70
 * Very simplyfied description of instruction code structure intended for
71
 * recognising memmory access of instruction ( reads or writes into memmory)
72
 * more details: see ARM architecture preference chapter:3.1 Instruction set encoding
73
 */
74
typedef struct {
75
        unsigned dummy1              : 4;
76
        unsigned bit4                : 1;
77
        unsigned bits567             : 3;
78
        unsigned dummy               : 12;
79
        unsigned access              : 1;
80
        unsigned opcode              : 4;
81
        unsigned instr_type          : 3;
82
        unsigned condition       : 4;
83
} __attribute__ ((packed)) instruction_t;
84
 
85
/**
86
 *  Help union used for overcasting ip register (uint_32_t) value into instruction_t pointer
87
 */
88
typedef union {
89
    instruction_t*  instr;
90
    uint32_t    ip;
91
} instruction_union_t;
92
 
93
// localy used functions
94
static fault_status_t read_fault_status_register();
95
static uintptr_t read_fault_address_register();
96
static pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr);
97
 
98
 
99
/**
100
 * Initializes kernel adress space page tables, sets abourts exceptions vectors
101
 */
2128 jermar 102
void page_arch_init(void)
103
{
2238 kebrt 104
    uintptr_t cur;
2182 jancik 105
    int flags;
106
 
2128 jermar 107
    page_mapping_operations = &pt_mapping_operations;
2182 jancik 108
 
109
    flags = PAGE_CACHEABLE;
2238 kebrt 110
 
2243 kebrt 111
    /* PA2KA(identity) mapping for all frames until last_frame */
112
    for (cur = 0; cur < last_frame; cur += FRAME_SIZE) {
113
        page_mapping_insert(AS_KERNEL, PA2KA(cur), cur, flags);
114
    }
115
 
2256 kebrt 116
    // TODO: move to the kernel space
117
    page_mapping_insert(AS_KERNEL, 0x00000000, 0x00000000, flags);
2263 kebrt 118
    // TODO: remove when aux_printf not needed
2256 kebrt 119
    page_mapping_insert(AS_KERNEL, 0x10000000, 0x10000000, flags);
120
 
2263 kebrt 121
    exc_register(EXC_DATA_ABORT,     "page_fault data abort",     (iroutine) data_abourt);
122
    exc_register(EXC_PREFETCH_ABORT, "page_fault prefetch abort", (iroutine) prefetch_abourt);
2256 kebrt 123
 
2263 kebrt 124
    as_switch(NULL, AS_KERNEL);
2258 jancik 125
 
2243 kebrt 126
    // TODO: register fault routine
2128 jermar 127
}
128
 
2258 jancik 129
/**
130
 * Map device into kernel space.
131
 *
132
 * This function adds mapping of physical address that is read/write only
133
 *  from kernel and not bufferable.
134
 *
135
 * \param physaddr Physical addres where device is connected
136
 * \param size Length of area where device is present
137
 * \return Virtual address where device will be accessable
138
 * Note: This is copy of IA32 hw_map code
139
 */
2128 jermar 140
uintptr_t hw_map(uintptr_t physaddr, size_t size)
141
{
2258 jancik 142
    if (last_frame + ALIGN_UP(size, PAGE_SIZE) > KA2PA(KERNEL_ADDRESS_SPACE_END_ARCH))
143
        panic("Unable to map physical memory %p (%d bytes)", physaddr, size)
144
 
145
    uintptr_t virtaddr = PA2KA(last_frame);
146
    pfn_t i;
147
    for (i = 0; i < ADDR2PFN(ALIGN_UP(size, PAGE_SIZE)); i++)
148
        page_mapping_insert(AS_KERNEL, virtaddr + PFN2ADDR(i), physaddr + PFN2ADDR(i), PAGE_NOT_CACHEABLE | PAGE_READ | PAGE_WRITE | PAGE_KERNEL);
149
 
150
    last_frame = ALIGN_UP(last_frame + size, FRAME_SIZE);
151
 
152
    return virtaddr;
2128 jermar 153
}
154
 
2258 jancik 155
//TODO: remove in final version
156
static void print_istate(istate_t* istate);
157
static void print_istate(istate_t* istate) {
158
 aux_printf("\nIstate dump:\n");
159
 aux_printf("    r0:%X    r1:%X    r2:%X    r3:%X\n", istate->r0,  istate->r1, istate->r2,  istate->r3);
160
 aux_printf("    r4:%X    r5:%X    r6:%X    r7:%X\n", istate->r4,  istate->r5, istate->r6,  istate->r7);
161
 aux_printf("    r8:%X    r8:%X   r10:%X   r11:%X\n", istate->r8,  istate->r9, istate->r10, istate->r11);
162
 aux_printf("   r12:%X    sp:%X    lr:%X  spsr:%X\n", istate->r12, istate->sp, istate->lr,  istate->spsr);
163
}
164
 
165
/**
166
 * \return Value stored in fault status register
167
 */
168
static fault_status_t read_fault_status_register() {
169
        fault_status_union_t tmp;
170
        asm volatile (
171
        "mrc p15, 0, %0, c5, c0, 0"
172
            : "=r"(tmp.dummy)
173
    );
174
    return tmp.fsr;
175
}
176
 
177
/**
178
 * \return Virtual adress. Access on this addres caused exception
179
 */
180
static uintptr_t read_fault_address_register() {
181
        uintptr_t tmp;
182
    // Fault adress is stored in coprocessor15, register 6
183
    asm volatile (
184
        "mrc p15, 0, %0, c6, c0, 0"
185
        : "=r"(tmp)
186
    );
187
    return tmp;
188
};
189
 
190
/**
191
 * Decode instruction and decide if try to read or write into memmory.
192
 *
193
 * \param instr_addr address of instruction which attempts to access into memmory
194
 * \param badvaddr Virtual address on which instruction tries to access
195
 * \return type of access into memmory
196
 *  Note: return PF_ACESS_EXEC if no memmory acess
197
 */
198
//TODO: remove debug print in final version ... instead panic return PF_ACESS_EXEC
199
pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr) {
200
        instruction_union_t tmp;
201
        tmp.ip = instr_addr;
202
    // get instruction op code
203
    instruction_t i_code = *(tmp.instr);
204
 
205
        aux_printf("get_instruction_memmory_access\n");
206
    aux_printf(" i_code:%X\n",i_code);
207
    aux_printf(" i_code.condition:%d\n", i_code.condition);
208
    aux_printf(" i_code.instr_type:%d\n",i_code.instr_type);
209
    aux_printf(" i_code.opcode:%d\n",i_code.opcode);
210
    aux_printf(" i_code.acess:%d\n", i_code.access);
211
    aux_printf(" i_code.dummy:%d\n", i_code.dummy);
212
    aux_printf(" i_code.bits567%d\n", i_code.bits567);
213
    aux_printf(" i_code.bit4:%d\n", i_code.bit4);
214
    aux_printf(" i_code.dummy1:%d\n", i_code.dummy1);
215
 
216
 
217
        // undefined instructions ... (or special instructions)
218
    if ( i_code.condition == 0xf ) {
219
        panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
220
        return PF_ACCESS_EXEC;
221
    }
222
 
223
    // load store instructions
224
        if ( ( i_code.instr_type == 0x2 ) || // load store immediate offset
225
             ( i_code.instr_type == 0x3 && i_code.bit4 == 0) || // load store register offset
226
             ( i_code.instr_type == 0x4 ) || // load store multiple
227
         ( i_code.instr_type == 0x6 )    // coprocessor load / strore
228
       ) {
229
        if ( i_code.access == 1) {
230
            return PF_ACCESS_READ;
231
        } else {
232
            return PF_ACCESS_WRITE;
233
        }
234
    };
235
 
236
    // swap, swpb instruction
237
    if ( i_code.instr_type == 0x0 && (i_code.opcode == 0x8 || i_code.opcode == 0xA) &&
238
         i_code.access == 0x0 && i_code.bits567 == 0x4 && i_code.bit4 == 1 )
239
     {
240
        /* Swap instructions make read and write in one step.
241
         * Type of access that caused exception have to page tables and access rights.
242
         */
243
//TODO: ALF!!!!! cann't use AS as is define as THE->as and THE structure is sored after stack_base of current thread
244
//      but now ... in exception we have separate stacks <==> different stack_pointer ... so AS contains nonsence data
245
//  same case as_page_fault .... it's nessesary to solve "stack" problem
246
                pte_level1_t* pte = (pte_level1_t*)pt_mapping_operations.mapping_find(AS, badvaddr);
247
 
248
        ASSERT(pte);
249
 
250
                /* check if read possible
251
                 * Note: Don't check PTE_READABLE because it returns 1 everytimes */
252
        if ( !PTE_PRESENT(pte) ) {
253
                return PF_ACCESS_READ;
254
        }
255
        if ( !PTE_WRITABLE(pte) ) {
256
            return PF_ACCESS_WRITE;
257
        }
258
        else
259
            // badvaddr is present readable and writeable but error occured ... why?
260
            panic("page_fault - swap instruction, but address readable and writeable (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
261
    }
262
    panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
263
    return PF_ACCESS_EXEC;
264
}
265
 
266
/**
267
 * Routine that solves exception data_abourt
268
 *  ... you try to load or store value into invalid memmory address
269
 * \param istate State of CPU when data abourt occured
270
 * \param n number of exception
271
 */
272
//TODO: remove debug prints in final tested version
273
void data_abourt(int n, istate_t *istate) {
274
        fault_status_t fsr = read_fault_status_register();
275
        uintptr_t  page = read_fault_address_register();
276
 
277
    pf_access_t access = get_memmory_access_type( istate->lr, page);
278
 
279
    print_istate(istate);
280
    aux_printf(" page fault : ip:%X, va:%X, status:%x(%x), access:%d\n", istate->lr, page, fsr.status,fsr, access);
281
 
282
        int ret = as_page_fault(page, access, istate);
283
    aux_printf(" as_page_fault ret:%d\n", ret);
284
        if (ret == AS_PF_FAULT) {
285
        fault_if_from_uspace(istate, "Page fault: %#x", page);
286
 
287
                panic("page fault\n");
288
        }
289
 
290
    // TODO: Remove this ... now for testing purposes ... it's bad to test page faults in kernel, where no page faults should occures
291
    panic("page fault ... solved\n");
292
 
293
}
294
 
295
/**
296
 * Routine that solves exception prefetch_about
297
 *  ... you try to execute instruction on invalid address
298
 * \param istate State of CPU when prefetch abourt occured
299
 * \param n number of exception
300
 */
301
void prefetch_abourt(int n, istate_t *istate) {
302
 // Prefetch can be made be bkpt instruction
303
    print_istate(istate);
304
    aux_printf(" prefetch_abourt ... instruction on adress:%x can't be fetched\n", istate->lr);
305
 
306
        int ret = as_page_fault(istate->lr, PF_ACCESS_EXEC, istate);
307
    aux_printf(" as_page_fault ret:%d\n", ret);
308
        if (ret == AS_PF_FAULT) {
309
                panic("page fault - instruction fetch at addr:%X\n", istate->lr);
310
        }
311
 
312
    panic("Prefetch abourt ... solved");
313
}
314
 
2128 jermar 315
/** @}
316
 */
2182 jancik 317