/branches/arm/kernel/arch/arm32/include/mm/page.h |
---|
276,8 → 276,6 |
extern void page_arch_init(void); |
extern void prefetch_abort(int n, istate_t *istate); |
extern void data_abort(int n, istate_t *istate); |
#endif /* __ASM__ */ |
/branches/arm/kernel/arch/arm32/include/mm/page_fault.h |
---|
0,0 → 1,90 |
/* |
* Copyright (c) 2007 Pavel Jancik, Michal Kebrt |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup arm32mm |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_arm32_PAGE_FAULT_H_ |
#define KERN_arm32_PAGE_FAULT_H |
#include <arch/types.h> |
/** |
* Decribes structure of fault status register in coprocessor 15 |
*/ |
typedef struct { |
unsigned status : 3; |
unsigned domain : 4; |
unsigned zero : 1; |
unsigned should_be_zero : 24; |
} __attribute__ ((packed)) fault_status_t; |
/** |
* Help union used for overcasting integer value into fault_status_t type |
*/ |
typedef union { |
fault_status_t fsr; |
uint32_t dummy; |
} fault_status_union_t; |
/** |
* Very simplyfied description of instruction code structure intended for |
* recognising memmory access of instruction ( reads or writes into memmory) |
* more details: see ARM architecture preference |
* chapter:3.1 Instruction set encoding |
*/ |
typedef struct { |
unsigned dummy1 : 4; |
unsigned bit4 : 1; |
unsigned bits567 : 3; |
unsigned dummy : 12; |
unsigned access : 1; |
unsigned opcode : 4; |
unsigned instr_type : 3; |
unsigned condition : 4; |
} __attribute__ ((packed)) instruction_t; |
/** |
* Help union used for overcasting ip register (uint_32_t) value into |
* instruction_t pointer |
*/ |
typedef union { |
instruction_t* instr; |
uint32_t ip; |
} instruction_union_t; |
extern void prefetch_abort(int n, istate_t *istate); |
extern void data_abort(int n, istate_t *istate); |
#endif |
/** @} |
*/ |
/branches/arm/kernel/arch/arm32/Makefile.inc |
---|
85,7 → 85,8 |
arch/$(ARCH)/src/debug_print/io.c \ |
arch/$(ARCH)/src/console.c \ |
arch/$(ARCH)/src/exception.c \ |
arch/$(ARCH)/src/mm/memory_init.c |
arch/$(ARCH)/src/mm/memory_init.c \ |
arch/$(ARCH)/src/mm/page_fault.c |
ifeq ($(MACHINE), gxemul_testarm) |
ARCH_SOURCES += arch/$(ARCH)/src/drivers/gxemul.c |
/branches/arm/kernel/arch/arm32/src/mm/page_fault.c |
---|
0,0 → 1,257 |
/* |
* Copyright (c) 2007 Pavel Jancik, Michal Kebrt |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup arm32mm |
* @{ |
*/ |
/** @file |
*/ |
#include <panic.h> |
#include <arch/exception.h> |
#include <arch/debug_print/print.h> |
#include <arch/mm/page_fault.h> |
#include <mm/as.h> |
#include <genarch/mm/page_pt.h> |
#include <arch.h> |
//TODO: remove in final version |
static void print_istate(istate_t* istate); |
static void print_istate(istate_t* istate) { |
dprintf("\nIstate dump:\n"); |
dprintf(" r0:%X r1:%X r2:%X r3:%X\n", istate->r0, istate->r1, istate->r2, istate->r3); |
dprintf(" r4:%X r5:%X r6:%X r7:%X\n", istate->r4, istate->r5, istate->r6, istate->r7); |
dprintf(" r8:%X r8:%X r10:%X r11:%X\n", istate->r8, istate->r9, istate->r10, istate->r11); |
dprintf(" r12:%X sp:%X lr:%X spsr:%X\n", istate->r12, istate->sp, istate->lr, istate->spsr); |
} |
/** |
* \return Value stored in fault status register |
*/ |
static inline fault_status_t read_fault_status_register() { |
fault_status_union_t tmp; |
asm volatile ( |
"mrc p15, 0, %0, c5, c0, 0" |
: "=r"(tmp.dummy) |
); |
return tmp.fsr; |
} |
/** |
* \return Virtual adress. Access on this addres caused exception |
*/ |
static inline uintptr_t read_fault_address_register() { |
uintptr_t tmp; |
// Fault adress is stored in coprocessor15, register 6 |
asm volatile ( |
"mrc p15, 0, %0, c6, c0, 0" |
: "=r"(tmp) |
); |
return tmp; |
}; |
/** Check type of instruction |
* \param i_code Instruction op code |
* \return true if instruction is load or store, false otherwise |
*/ |
static inline bool load_store_instruction(instruction_t i_code) { |
// load store immediate offset |
if (i_code.instr_type == 0x2) { |
return true; |
}; |
// load store register offset |
if (i_code.instr_type == 0x3 && i_code.bit4 == 0) { |
return true; |
}; |
// load store multiple |
if (i_code.instr_type == 0x4) { |
return true; |
}; |
// coprocessor load / strore |
if (i_code.instr_type == 0x6) { |
return true; |
}; |
return false; |
} |
/** Check type of instruction |
* \param i_code Instruction op code |
* \return true if instruction is swap, false otherwise |
*/ |
static inline bool swap_instruction(instruction_t i_code) { |
// swap, swapb instruction |
if (i_code.instr_type == 0x0 && |
(i_code.opcode == 0x8 || i_code.opcode == 0xA) && |
i_code.access == 0x0 && i_code.bits567 == 0x4 && |
i_code.bit4 == 1) { |
return true; |
}; |
return false; |
} |
/** |
* Decode instruction and decide if try to read or write into memmory. |
* |
* \param instr_addr address of instruction which attempts access into memmory |
* \param badvaddr Virtual address on which instruction tries to access |
* \return type of access into memmory |
* Note: return PF_ACESS_EXEC if no memmory acess |
*/ |
//TODO: remove debug print in final version ... instead panic return PF_ACESS_EXEC |
static pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr) { |
instruction_union_t tmp; |
tmp.ip = instr_addr; |
// get instruction op code |
instruction_t i_code = *(tmp.instr); |
dprintf("get_instruction_memmory_access\n"); |
dprintf(" instr_addr:%X\n",instr_addr); |
dprintf(" i_code:%X\n",i_code); |
dprintf(" i_code.condition:%d\n", i_code.condition); |
dprintf(" i_code.instr_type:%d\n",i_code.instr_type); |
dprintf(" i_code.opcode:%d\n",i_code.opcode); |
dprintf(" i_code.acess:%d\n", i_code.access); |
dprintf(" i_code.dummy:%d\n", i_code.dummy); |
dprintf(" i_code.bits567%d\n", i_code.bits567); |
dprintf(" i_code.bit4:%d\n", i_code.bit4); |
dprintf(" i_code.dummy1:%d\n", i_code.dummy1); |
// undefined instructions ... (or special instructions) |
if (i_code.condition == 0xf) { |
panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr); |
return PF_ACCESS_EXEC; |
}; |
// load store instructions |
if (load_store_instruction(i_code)) { |
if ( i_code.access == 1) { |
return PF_ACCESS_READ; |
} else { |
return PF_ACCESS_WRITE; |
} |
}; |
// swap, swpb instruction |
if (swap_instruction(i_code)) |
{ |
/* Swap instructions make read and write in one step. |
* Type of access that caused exception have to page tables |
* and access rights. |
*/ |
//TODO: ALF!!!!! cann't use AS as is define as THE->as and THE structure is sored after stack_base of current thread |
// but now ... in exception we have separate stacks <==> different stack_pointer ... so AS contains nonsence data |
// same case as_page_fault .... it's nessesary to solve "stack" problem |
pte_level1_t* pte = (pte_level1_t*) |
pt_mapping_operations.mapping_find(AS, badvaddr); |
ASSERT(pte); |
/* check if read possible |
* Note: Don't check PTE_READABLE because it returns 1 everytimes */ |
if ( !PTE_PRESENT(pte) ) { |
return PF_ACCESS_READ; |
} |
if ( !PTE_WRITABLE(pte) ) { |
return PF_ACCESS_WRITE; |
} |
else |
// badvaddr is present readable and writeable but error occured ... why? |
panic("page_fault - swap instruction, but address readable and writeable (instr_code:%X, badvaddr:%X)",i_code, badvaddr); |
} |
panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr); |
return PF_ACCESS_EXEC; |
} |
/** |
* Routine that solves exception data_abourt |
* ... you try to load or store value into invalid memmory address |
* \param istate State of CPU when data abourt occured |
* \param n number of exception |
*/ |
//TODO: remove debug prints in final tested version |
void data_abort(int n, istate_t *istate) { |
fault_status_t fsr = read_fault_status_register(); |
uintptr_t page = read_fault_address_register(); |
pf_access_t access = get_memmory_access_type( istate->lr, page); |
print_istate(istate); |
dprintf(" page fault : ip:%X, va:%X, status:%x(%x), access:%d\n", istate->lr, page, fsr.status,fsr, access); |
/* Alf: Will be commented until stack problem will be solved ... |
as_page_fault make consequent page faults |
int ret = as_page_fault(page, access, istate); |
dprintf(" as_page_fault ret:%d\n", ret); |
if (ret == AS_PF_FAULT) { |
fault_if_from_uspace(istate, "Page fault: %#x", page); |
panic("page fault\n"); |
} |
*/ |
// TODO: Remove this ... now for testing purposes ... it's bad to test page faults in kernel, where no page faults should occures |
panic("page fault ... solved\n"); |
} |
/** |
* Routine that solves exception prefetch_about |
* ... you try to execute instruction on invalid address |
* \param istate State of CPU when prefetch abourt occured |
* \param n number of exception |
*/ |
void prefetch_abort(int n, istate_t *istate) { |
// Prefetch can be made be bkpt instruction |
print_istate(istate); |
dprintf(" prefetch_abourt ... instruction on adress:%x can't be fetched\n", istate->lr); |
/* Alf: Will be commented until stack problem will be solved ... |
as_page_fault make consequent page faults |
int ret = as_page_fault(istate->lr, PF_ACCESS_EXEC, istate); |
dprintf(" as_page_fault ret:%d\n", ret); |
if (ret == AS_PF_FAULT) { |
panic("page fault - instruction fetch at addr:%X\n", istate->lr); |
} |
*/ |
panic("Prefetch abourt ... solved"); |
} |
/** @} |
*/ |
/branches/arm/kernel/arch/arm32/src/mm/page.c |
---|
34,7 → 34,6 |
#include <arch/mm/page.h> |
#include <genarch/mm/page_pt.h> |
#include <arch.h> |
#include <mm/page.h> |
#include <align.h> |
#include <config.h> |
45,56 → 44,7 |
#include <arch/debug_print/print.h> |
// localy used types |
/** |
* Decribes structure of fault status register in coprocessor 15 |
*/ |
typedef struct { |
unsigned status : 3; |
unsigned domain : 4; |
unsigned zero : 1; |
unsigned should_be_zero : 24; |
} __attribute__ ((packed)) fault_status_t; |
/** |
* Help union used for overcasting integer value into fault_status_t type |
*/ |
typedef union { |
fault_status_t fsr; |
uint32_t dummy; |
} fault_status_union_t; |
/** |
* Very simplyfied description of instruction code structure intended for |
* recognising memmory access of instruction ( reads or writes into memmory) |
* more details: see ARM architecture preference chapter:3.1 Instruction set encoding |
*/ |
typedef struct { |
unsigned dummy1 : 4; |
unsigned bit4 : 1; |
unsigned bits567 : 3; |
unsigned dummy : 12; |
unsigned access : 1; |
unsigned opcode : 4; |
unsigned instr_type : 3; |
unsigned condition : 4; |
} __attribute__ ((packed)) instruction_t; |
/** |
* Help union used for overcasting ip register (uint_32_t) value into instruction_t pointer |
*/ |
typedef union { |
instruction_t* instr; |
uint32_t ip; |
} instruction_union_t; |
// localy used functions |
static fault_status_t read_fault_status_register(); |
static uintptr_t read_fault_address_register(); |
static pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr); |
/** |
* Initializes kernel adress space page tables, sets abourts exceptions vectors |
*/ |
void page_arch_init(void) |
157,173 → 107,7 |
return virtaddr; |
} |
//TODO: remove in final version |
static void print_istate(istate_t* istate); |
static void print_istate(istate_t* istate) { |
dprintf("\nIstate dump:\n"); |
dprintf(" r0:%X r1:%X r2:%X r3:%X\n", istate->r0, istate->r1, istate->r2, istate->r3); |
dprintf(" r4:%X r5:%X r6:%X r7:%X\n", istate->r4, istate->r5, istate->r6, istate->r7); |
dprintf(" r8:%X r8:%X r10:%X r11:%X\n", istate->r8, istate->r9, istate->r10, istate->r11); |
dprintf(" r12:%X sp:%X lr:%X spsr:%X\n", istate->r12, istate->sp, istate->lr, istate->spsr); |
} |
/** |
* \return Value stored in fault status register |
*/ |
static fault_status_t read_fault_status_register() { |
fault_status_union_t tmp; |
asm volatile ( |
"mrc p15, 0, %0, c5, c0, 0" |
: "=r"(tmp.dummy) |
); |
return tmp.fsr; |
} |
/** |
* \return Virtual adress. Access on this addres caused exception |
*/ |
static uintptr_t read_fault_address_register() { |
uintptr_t tmp; |
// Fault adress is stored in coprocessor15, register 6 |
asm volatile ( |
"mrc p15, 0, %0, c6, c0, 0" |
: "=r"(tmp) |
); |
return tmp; |
}; |
/** |
* Decode instruction and decide if try to read or write into memmory. |
* |
* \param instr_addr address of instruction which attempts to access into memmory |
* \param badvaddr Virtual address on which instruction tries to access |
* \return type of access into memmory |
* Note: return PF_ACESS_EXEC if no memmory acess |
*/ |
//TODO: remove debug print in final version ... instead panic return PF_ACESS_EXEC |
pf_access_t get_memmory_access_type(uint32_t instr_addr, uintptr_t badvaddr) { |
instruction_union_t tmp; |
tmp.ip = instr_addr; |
// get instruction op code |
instruction_t i_code = *(tmp.instr); |
dprintf("get_instruction_memmory_access\n"); |
dprintf(" i_code:%X\n",i_code); |
dprintf(" i_code.condition:%d\n", i_code.condition); |
dprintf(" i_code.instr_type:%d\n",i_code.instr_type); |
dprintf(" i_code.opcode:%d\n",i_code.opcode); |
dprintf(" i_code.acess:%d\n", i_code.access); |
dprintf(" i_code.dummy:%d\n", i_code.dummy); |
dprintf(" i_code.bits567%d\n", i_code.bits567); |
dprintf(" i_code.bit4:%d\n", i_code.bit4); |
dprintf(" i_code.dummy1:%d\n", i_code.dummy1); |
// undefined instructions ... (or special instructions) |
if ( i_code.condition == 0xf ) { |
panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr); |
return PF_ACCESS_EXEC; |
} |
// load store instructions |
if ( ( i_code.instr_type == 0x2 ) || // load store immediate offset |
( i_code.instr_type == 0x3 && i_code.bit4 == 0) || // load store register offset |
( i_code.instr_type == 0x4 ) || // load store multiple |
( i_code.instr_type == 0x6 ) // coprocessor load / strore |
) { |
if ( i_code.access == 1) { |
return PF_ACCESS_READ; |
} else { |
return PF_ACCESS_WRITE; |
} |
}; |
// swap, swpb instruction |
if ( i_code.instr_type == 0x0 && (i_code.opcode == 0x8 || i_code.opcode == 0xA) && |
i_code.access == 0x0 && i_code.bits567 == 0x4 && i_code.bit4 == 1 ) |
{ |
/* Swap instructions make read and write in one step. |
* Type of access that caused exception have to page tables and access rights. |
*/ |
//TODO: ALF!!!!! cann't use AS as is define as THE->as and THE structure is sored after stack_base of current thread |
// but now ... in exception we have separate stacks <==> different stack_pointer ... so AS contains nonsence data |
// same case as_page_fault .... it's nessesary to solve "stack" problem |
pte_level1_t* pte = (pte_level1_t*)pt_mapping_operations.mapping_find(AS, badvaddr); |
ASSERT(pte); |
/* check if read possible |
* Note: Don't check PTE_READABLE because it returns 1 everytimes */ |
if ( !PTE_PRESENT(pte) ) { |
return PF_ACCESS_READ; |
} |
if ( !PTE_WRITABLE(pte) ) { |
return PF_ACCESS_WRITE; |
} |
else |
// badvaddr is present readable and writeable but error occured ... why? |
panic("page_fault - swap instruction, but address readable and writeable (instr_code:%X, badvaddr:%X)",i_code, badvaddr); |
} |
panic("page_fault - on instruction not acessing to memmory (instr_code:%X, badvaddr:%X)",i_code, badvaddr); |
return PF_ACCESS_EXEC; |
} |
/** |
* Routine that solves exception data_abourt |
* ... you try to load or store value into invalid memmory address |
* \param istate State of CPU when data abourt occured |
* \param n number of exception |
*/ |
//TODO: remove debug prints in final tested version |
void data_abort(int n, istate_t *istate) { |
fault_status_t fsr = read_fault_status_register(); |
uintptr_t page = read_fault_address_register(); |
pf_access_t access = get_memmory_access_type( istate->lr, page); |
print_istate(istate); |
dprintf(" page fault : ip:%X, va:%X, status:%x(%x), access:%d\n", istate->lr, page, fsr.status,fsr, access); |
/* Alf: Will be commented until stack problem will be solved ... |
as_page_fault make consequent page faults |
int ret = as_page_fault(page, access, istate); |
dprintf(" as_page_fault ret:%d\n", ret); |
if (ret == AS_PF_FAULT) { |
fault_if_from_uspace(istate, "Page fault: %#x", page); |
panic("page fault\n"); |
} |
*/ |
// TODO: Remove this ... now for testing purposes ... it's bad to test page faults in kernel, where no page faults should occures |
panic("page fault ... solved\n"); |
} |
/** |
* Routine that solves exception prefetch_about |
* ... you try to execute instruction on invalid address |
* \param istate State of CPU when prefetch abourt occured |
* \param n number of exception |
*/ |
void prefetch_abort(int n, istate_t *istate) { |
// Prefetch can be made be bkpt instruction |
print_istate(istate); |
dprintf(" prefetch_abourt ... instruction on adress:%x can't be fetched\n", istate->lr); |
/* Alf: Will be commented until stack problem will be solved ... |
as_page_fault make consequent page faults |
int ret = as_page_fault(istate->lr, PF_ACCESS_EXEC, istate); |
dprintf(" as_page_fault ret:%d\n", ret); |
if (ret == AS_PF_FAULT) { |
panic("page fault - instruction fetch at addr:%X\n", istate->lr); |
} |
*/ |
panic("Prefetch abourt ... solved"); |
} |
/** @} |
*/ |