Subversion Repositories HelenOS

Rev

Rev 2264 | 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
    }
2270 jancik 113
 
114
    // Create mapping for exception table at high offcet
115
    #ifdef HIGH_EXCEPTION_VECTORS
116
    /* Note: this mapping cann't be done by hw_map because fixed exception
117
       vector is stored at fixed virtual address
118
     */
119
    // reserve frame for exception table
120
    void* virtaddr = frame_alloc( ONE_FRAME ,FRAME_KA);
121
    page_mapping_insert(AS_KERNEL, EXC_BASE_ADDRESS, KA2PA(virtaddr), flags );
122
    #endif
2243 kebrt 123
 
2256 kebrt 124
    // TODO: move to the kernel space
2270 jancik 125
//  page_mapping_insert(AS_KERNEL, 0xffff0000, 0x00000000, flags);
2263 kebrt 126
    // TODO: remove when aux_printf not needed
2256 kebrt 127
    page_mapping_insert(AS_KERNEL, 0x10000000, 0x10000000, flags);
128
 
129
 
2263 kebrt 130
    as_switch(NULL, AS_KERNEL);
2258 jancik 131
 
2128 jermar 132
}
133
 
2258 jancik 134
/**
135
 * Map device into kernel space.
136
 *
137
 * This function adds mapping of physical address that is read/write only
138
 *  from kernel and not bufferable.
139
 *
140
 * \param physaddr Physical addres where device is connected
141
 * \param size Length of area where device is present
142
 * \return Virtual address where device will be accessable
143
 * Note: This is copy of IA32 hw_map code
144
 */
2128 jermar 145
uintptr_t hw_map(uintptr_t physaddr, size_t size)
146
{
2258 jancik 147
    if (last_frame + ALIGN_UP(size, PAGE_SIZE) > KA2PA(KERNEL_ADDRESS_SPACE_END_ARCH))
148
        panic("Unable to map physical memory %p (%d bytes)", physaddr, size)
149
 
150
    uintptr_t virtaddr = PA2KA(last_frame);
151
    pfn_t i;
152
    for (i = 0; i < ADDR2PFN(ALIGN_UP(size, PAGE_SIZE)); i++)
153
        page_mapping_insert(AS_KERNEL, virtaddr + PFN2ADDR(i), physaddr + PFN2ADDR(i), PAGE_NOT_CACHEABLE | PAGE_READ | PAGE_WRITE | PAGE_KERNEL);
154
 
155
    last_frame = ALIGN_UP(last_frame + size, FRAME_SIZE);
156
 
157
    return virtaddr;
2128 jermar 158
}
159
 
2258 jancik 160
//TODO: remove in final version
161
static void print_istate(istate_t* istate);
162
static void print_istate(istate_t* istate) {
2264 kebrt 163
 dprintf("\nIstate dump:\n");
164
 dprintf("    r0:%X    r1:%X    r2:%X    r3:%X\n", istate->r0,  istate->r1, istate->r2,  istate->r3);
165
 dprintf("    r4:%X    r5:%X    r6:%X    r7:%X\n", istate->r4,  istate->r5, istate->r6,  istate->r7);
166
 dprintf("    r8:%X    r8:%X   r10:%X   r11:%X\n", istate->r8,  istate->r9, istate->r10, istate->r11);
167
 dprintf("   r12:%X    sp:%X    lr:%X  spsr:%X\n", istate->r12, istate->sp, istate->lr,  istate->spsr);
2258 jancik 168
}
169
 
170
/**
171
 * \return Value stored in fault status register
172
 */
173
static fault_status_t read_fault_status_register() {
174
        fault_status_union_t tmp;
175
        asm volatile (
176
        "mrc p15, 0, %0, c5, c0, 0"
177
            : "=r"(tmp.dummy)
178
    );
179
    return tmp.fsr;
180
}
181
 
182
/**
183
 * \return Virtual adress. Access on this addres caused exception
184
 */
185
static uintptr_t read_fault_address_register() {
186
        uintptr_t tmp;
187
    // Fault adress is stored in coprocessor15, register 6
188
    asm volatile (
189
        "mrc p15, 0, %0, c6, c0, 0"
190
        : "=r"(tmp)
191
    );
192
    return tmp;
193
};
194
 
195
/**
196
 * Decode instruction and decide if try to read or write into memmory.
197
 *
198
 * \param instr_addr address of instruction which attempts to access into memmory
199
 * \param badvaddr Virtual address on which instruction tries to access
200
 * \return type of access into memmory
201
 *  Note: return PF_ACESS_EXEC if no memmory acess
202
 */
203
//TODO: remove debug print in final version ... instead panic return PF_ACESS_EXEC
204
pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr) {
205
        instruction_union_t tmp;
206
        tmp.ip = instr_addr;
207
    // get instruction op code
208
    instruction_t i_code = *(tmp.instr);
209
 
2264 kebrt 210
        dprintf("get_instruction_memmory_access\n");
211
    dprintf(" i_code:%X\n",i_code);
212
    dprintf(" i_code.condition:%d\n", i_code.condition);
213
    dprintf(" i_code.instr_type:%d\n",i_code.instr_type);
214
    dprintf(" i_code.opcode:%d\n",i_code.opcode);
215
    dprintf(" i_code.acess:%d\n", i_code.access);
216
    dprintf(" i_code.dummy:%d\n", i_code.dummy);
217
    dprintf(" i_code.bits567%d\n", i_code.bits567);
218
    dprintf(" i_code.bit4:%d\n", i_code.bit4);
219
    dprintf(" i_code.dummy1:%d\n", i_code.dummy1);
2258 jancik 220
 
221
 
222
        // undefined instructions ... (or special instructions)
223
    if ( i_code.condition == 0xf ) {
224
        panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
225
        return PF_ACCESS_EXEC;
226
    }
227
 
228
    // load store instructions
229
        if ( ( i_code.instr_type == 0x2 ) || // load store immediate offset
230
             ( i_code.instr_type == 0x3 && i_code.bit4 == 0) || // load store register offset
231
             ( i_code.instr_type == 0x4 ) || // load store multiple
232
         ( i_code.instr_type == 0x6 )    // coprocessor load / strore
233
       ) {
234
        if ( i_code.access == 1) {
235
            return PF_ACCESS_READ;
236
        } else {
237
            return PF_ACCESS_WRITE;
238
        }
239
    };
240
 
241
    // swap, swpb instruction
242
    if ( i_code.instr_type == 0x0 && (i_code.opcode == 0x8 || i_code.opcode == 0xA) &&
243
         i_code.access == 0x0 && i_code.bits567 == 0x4 && i_code.bit4 == 1 )
244
     {
245
        /* Swap instructions make read and write in one step.
246
         * Type of access that caused exception have to page tables and access rights.
247
         */
248
//TODO: ALF!!!!! cann't use AS as is define as THE->as and THE structure is sored after stack_base of current thread
249
//      but now ... in exception we have separate stacks <==> different stack_pointer ... so AS contains nonsence data
250
//  same case as_page_fault .... it's nessesary to solve "stack" problem
251
                pte_level1_t* pte = (pte_level1_t*)pt_mapping_operations.mapping_find(AS, badvaddr);
252
 
253
        ASSERT(pte);
254
 
255
                /* check if read possible
256
                 * Note: Don't check PTE_READABLE because it returns 1 everytimes */
257
        if ( !PTE_PRESENT(pte) ) {
258
                return PF_ACCESS_READ;
259
        }
260
        if ( !PTE_WRITABLE(pte) ) {
261
            return PF_ACCESS_WRITE;
262
        }
263
        else
264
            // badvaddr is present readable and writeable but error occured ... why?
265
            panic("page_fault - swap instruction, but address readable and writeable (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
266
    }
267
    panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr);
268
    return PF_ACCESS_EXEC;
269
}
270
 
271
/**
272
 * Routine that solves exception data_abourt
273
 *  ... you try to load or store value into invalid memmory address
274
 * \param istate State of CPU when data abourt occured
275
 * \param n number of exception
276
 */
277
//TODO: remove debug prints in final tested version
278
void data_abourt(int n, istate_t *istate) {
279
        fault_status_t fsr = read_fault_status_register();
280
        uintptr_t  page = read_fault_address_register();
281
 
282
    pf_access_t access = get_memmory_access_type( istate->lr, page);
283
 
284
    print_istate(istate);
2264 kebrt 285
    dprintf(" page fault : ip:%X, va:%X, status:%x(%x), access:%d\n", istate->lr, page, fsr.status,fsr, access);
2258 jancik 286
 
287
        int ret = as_page_fault(page, access, istate);
2264 kebrt 288
    dprintf(" as_page_fault ret:%d\n", ret);
2258 jancik 289
        if (ret == AS_PF_FAULT) {
290
        fault_if_from_uspace(istate, "Page fault: %#x", page);
291
 
292
                panic("page fault\n");
293
        }
294
 
295
    // TODO: Remove this ... now for testing purposes ... it's bad to test page faults in kernel, where no page faults should occures
296
    panic("page fault ... solved\n");
297
 
298
}
299
 
300
/**
301
 * Routine that solves exception prefetch_about
302
 *  ... you try to execute instruction on invalid address
303
 * \param istate State of CPU when prefetch abourt occured
304
 * \param n number of exception
305
 */
306
void prefetch_abourt(int n, istate_t *istate) {
307
 // Prefetch can be made be bkpt instruction
308
    print_istate(istate);
2264 kebrt 309
    dprintf(" prefetch_abourt ... instruction on adress:%x can't be fetched\n", istate->lr);
2258 jancik 310
 
311
        int ret = as_page_fault(istate->lr, PF_ACCESS_EXEC, istate);
2264 kebrt 312
    dprintf(" as_page_fault ret:%d\n", ret);
2258 jancik 313
        if (ret == AS_PF_FAULT) {
314
                panic("page fault - instruction fetch at addr:%X\n", istate->lr);
315
        }
316
 
317
    panic("Prefetch abourt ... solved");
318
}
319
 
2128 jermar 320
/** @}
321
 */
2182 jancik 322