Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2303 → Rev 2304

/branches/arm/kernel/arch/arm32/src/mm/page_fault.c
41,216 → 41,199
#include <interrupt.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);
dprintf(" pc:%X\n", istate->pc);
}
/** Returns value stored in fault status register.
*
* \return Value stored in CP15 fault status register (FSR).
*/
static inline fault_status_t read_fault_status_register(void)
{
fault_status_union_t fsu;
 
/**
* \return Value stored in fault status register
*/
static inline fault_status_t read_fault_status_register() {
fault_status_union_t tmp;
asm volatile (
// fault adress is stored in CP15 register 5
asm volatile (
"mrc p15, 0, %0, c5, c0, 0"
: "=r"(tmp.dummy)
: "=r"(fsu.dummy)
);
return tmp.fsr;
return fsu.fs;
}
 
/**
* \return Virtual adress. Access on this addres caused exception
 
/** Returns FAR (fault address register) content.
*
* \return FAR (fault address register) content (address that caused a page fault)
*/
static inline uintptr_t read_fault_address_register() {
uintptr_t tmp;
// Fault adress is stored in coprocessor15, register 6
static inline uintptr_t read_fault_address_register(void)
{
uintptr_t ret;
// fault adress is stored in CP15 register 6
asm volatile (
"mrc p15, 0, %0, c6, c0, 0"
: "=r"(tmp)
: "=r"(ret)
);
return tmp;
};
return ret;
}
 
/** Check type of instruction
* \param i_code Instruction op code
* \return true if instruction is load or store, false otherwise
 
/** Decides whether the instructions is load/store or not.
*
* \param instr Instruction
*
* \return true when instruction is load/store, false otherwise
*/
static inline bool load_store_instruction(instruction_t i_code) {
 
// load store immediate offset
if (i_code.instr_type == 0x2) {
static inline bool is_load_store_instruction(instruction_t instr)
{
// load store immediate offset
if (instr.type == 0x2) {
return true;
};
}
 
// load store register offset
if (i_code.instr_type == 0x3 && i_code.bit4 == 0) {
// load store register offset
if (instr.type == 0x3 && instr.bit4 == 0) {
return true;
};
}
 
// load store multiple
if (i_code.instr_type == 0x4) {
// load store multiple
if (instr.type == 0x4) {
return true;
};
}
 
// coprocessor load / strore
if (i_code.instr_type == 0x6) {
// coprocessor load/store
if (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
 
/** Decides whether the instructions is swap or not.
*
* \param instr Instruction
*
* \return true when instruction is swap, false otherwise
*/
static inline bool swap_instruction(instruction_t i_code) {
 
static inline bool is_swap_instruction(instruction_t instr)
{
// 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) {
if (instr.type == 0x0 &&
(instr.opcode == 0x8 || instr.opcode == 0xa) &&
instr.access == 0x0 && instr.bits567 == 0x4 && instr.bit4 == 1) {
return true;
};
}
 
return false;
}
 
 
/**
* Decode instruction and decide if try to read or write into memmory.
/** Decides whether read or write into memory is requested.
*
* \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
* \param instr_addr Address of instruction which tries to access memory
* \param badvaddr Virtual address the instruction tries to access
*
* \return Type of access into memmory
* \note Returns #PF_ACESS_EXEC if no memory access is requested
*/
//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);
static pf_access_t get_memory_access_type(uint32_t instr_addr, uintptr_t badvaddr)
{
instruction_union_t instr_union;
instr_union.pc = instr_addr;
 
// 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);
instruction_t instr = *(instr_union.instr);
 
 
// 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);
// undefined instructions
if (instr.condition == 0xf) {
panic("page_fault - instruction not access memmory (instr_code: %x, badvaddr:%x)",
instr, badvaddr);
return PF_ACCESS_EXEC;
};
}
 
// load store instructions
if (load_store_instruction(i_code)) {
if ( i_code.access == 1) {
if (is_load_store_instruction(instr)) {
if (instr.access == 1) {
return PF_ACCESS_READ;
} else {
return PF_ACCESS_WRITE;
}
};
}
 
// swap, swpb instruction
if (swap_instruction(i_code))
{
if (is_swap_instruction(instr)) {
/* 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);
//TODO: ALF!!!!! cann't use AS asi 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 */
/* check if read possible
* Note: Don't check PTE_READABLE because it returns 1 everytimes */
if ( !PTE_PRESENT(pte) ) {
return PF_ACCESS_READ;
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)", instr, badvaddr);
}
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);
 
panic("page_fault - instruction not access memory (instr_code: %x, badvaddr:%x)",
instr, 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
/** Handles "data abort" exception (load or store at invalid address).
*
* \param exc_no exception number
* \param istate CPU state when exception occured
*/
//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();
void data_abort(int exc_no, istate_t *istate)
{
fault_status_t fsr = read_fault_status_register();
uintptr_t badvaddr = read_fault_address_register();
 
pf_access_t access = get_memmory_access_type( istate->pc, page);
pf_access_t access = get_memory_access_type(istate->pc, badvaddr);
int ret = as_page_fault(badvaddr, access, istate);
 
// print_istate(istate);
dprintf(" page fault : ip:%X, va:%X, status:%x(%x), access:%d\n", istate->pc, page, fsr.status,fsr, access);
if (ret == AS_PF_FAULT) {
print_istate(istate);
dprintf("page fault - pc: %x, va: %x, status: %x(%x), access:%d\n",
istate->pc, badvaddr, 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);
fault_if_from_uspace(istate, "Page fault: %#x", badvaddr);
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
/** Handles "prefetch abort" exception (instruction couldn't be executed).
*
* \param exc_no exception number
* \param istate CPU state when exception occured
*/
void prefetch_abort(int n, istate_t *istate) {
print_istate(istate);
dprintf(" prefetch_abourt ... instruction on adress:%x can't be fetched\n", istate->pc);
 
/* Alf: Will be commented until stack problem will be solved ...
as_page_fault make consequent page faults*/
 
void prefetch_abort(int exc_no, istate_t *istate)
{
int ret = as_page_fault(istate->pc, 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->pc);
}
 
 
// panic("Prefetch abourt ... solved");
if (ret == AS_PF_FAULT) {
dprintf("prefetch_abort\n");
print_istate(istate);
panic("page fault - prefetch_abort at address: %x\n", istate->pc);
}
}
 
/** @}