Subversion Repositories HelenOS

Rev

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