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"); |
} |
|
/** @} |
*/ |
|