Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2303 → Rev 2304

/branches/arm/kernel/arch/arm32/include/exception.h
1,6 → 1,5
/*
* Copyright (c) 2007 Michal Kebrt
* Copyright (c) 2007 Petr Stepan
* Copyright (c) 2007 Michal Kebrt, Petr Stepan
*
* All rights reserved.
*
49,43 → 48,43
#endif
 
/* Exception Vectors */
#define EXC_RESET_VEC (EXC_BASE_ADDRESS + 0x0)
#define EXC_UNDEF_INSTR_VEC (EXC_BASE_ADDRESS + 0x4)
#define EXC_SWI_VEC (EXC_BASE_ADDRESS + 0x8)
#define EXC_PREFETCH_ABORT_VEC (EXC_BASE_ADDRESS + 0xc)
#define EXC_DATA_ABORT_VEC (EXC_BASE_ADDRESS + 0x10)
#define EXC_IRQ_VEC (EXC_BASE_ADDRESS + 0x18)
#define EXC_FIQ_VEC (EXC_BASE_ADDRESS + 0x1c)
#define EXC_RESET_VEC (EXC_BASE_ADDRESS + 0x0)
#define EXC_UNDEF_INSTR_VEC (EXC_BASE_ADDRESS + 0x4)
#define EXC_SWI_VEC (EXC_BASE_ADDRESS + 0x8)
#define EXC_PREFETCH_ABORT_VEC (EXC_BASE_ADDRESS + 0xc)
#define EXC_DATA_ABORT_VEC (EXC_BASE_ADDRESS + 0x10)
#define EXC_IRQ_VEC (EXC_BASE_ADDRESS + 0x18)
#define EXC_FIQ_VEC (EXC_BASE_ADDRESS + 0x1c)
 
/* Exception numbers */
#define EXC_RESET 0
#define EXC_UNDEF_INSTR 1
#define EXC_SWI 2
#define EXC_PREFETCH_ABORT 3
#define EXC_DATA_ABORT 4
#define EXC_IRQ 5
#define EXC_FIQ 6
#define EXC_RESET 0
#define EXC_UNDEF_INSTR 1
#define EXC_SWI 2
#define EXC_PREFETCH_ABORT 3
#define EXC_DATA_ABORT 4
#define EXC_IRQ 5
#define EXC_FIQ 6
 
typedef struct {
uint32_t spsr;
uint32_t spsr;
uint32_t sp;
uint32_t lr;
 
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r4;
uint32_t r5;
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t r12;
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r4;
uint32_t r5;
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t r12;
 
uint32_t pc;
uint32_t pc;
} istate_t;
 
 
108,6 → 107,7
extern void setup_exception_stacks(void);
extern void install_exception_handlers(void);
extern void exception_init(void);
extern void print_istate(istate_t *istate);
 
#endif
 
/branches/arm/kernel/arch/arm32/include/mm/page_fault.h
36,50 → 36,51
 
#include <arch/types.h>
 
/**
* Decribes structure of fault status register in coprocessor 15
 
/** Decribes CP15 "fault status register" (FSR).
*/
typedef struct {
unsigned status : 3;
unsigned domain : 4;
unsigned zero : 1;
unsigned should_be_zero : 24;
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
 
/** Help union used for casting integer value into #fault_status_t.
*/
typedef union {
fault_status_t fsr;
uint32_t dummy;
fault_status_t fs;
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
 
/** Simplified description of instruction code.
*
* \note Used for recognizing memory access instructions.
* \see ARM architecture reference (chapter 3.1)
*/
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;
unsigned dummy1 : 4;
unsigned bit4 : 1;
unsigned bits567 : 3;
unsigned dummy : 12;
unsigned access : 1;
unsigned opcode : 4;
unsigned type : 3;
unsigned condition : 4;
} __attribute__ ((packed)) instruction_t;
 
/**
* Help union used for overcasting ip register (uint_32_t) value into
* instruction_t pointer
 
/** Help union used for casting pc register (uint_32_t) value into
* #instruction_t pointer.
*/
typedef union {
instruction_t* instr;
uint32_t ip;
instruction_t* instr;
uint32_t pc;
} instruction_union_t;
 
 
extern void prefetch_abort(int n, istate_t *istate);
extern void data_abort(int n, istate_t *istate);
 
/branches/arm/kernel/arch/arm32/src/exception.c
244,9 → 244,9
*
* Dispatches the syscall.
*/
static void swi_exception(int exc_no, istate_t* istate)
static void swi_exception(int exc_no, istate_t *istate)
{
dprintf("SYSCALL: r0-r4: %x, %x, %x, %x, %x; pc: %x", istate->r0,
dprintf("SYSCALL: r0-r4: %x, %x, %x, %x, %x; pc: %x\n", istate->r0,
istate->r1, istate->r2, istate->r3, istate->r4, istate->pc);
 
istate->r0 = syscall_handler(
261,7 → 261,7
*
* Determines the sources of interrupt, and calls their handlers.
*/
static void irq_exception(int exc_no, istate_t* istate)
static void irq_exception(int exc_no, istate_t *istate)
{
// TODO: move somewhere to gxemul.c and use machine_irq_exception (or some similar
// name) to avoid using MACHINE == MACHINE_GXEMUL_TESTARM
396,5 → 396,23
 
}
 
 
void print_istate(istate_t *istate)
{
dprintf("istate 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);
}
 
 
/** @}
*/
/branches/arm/kernel/arch/arm32/src/arm32.c
54,40 → 54,6
// // uintptr_t supervisor_sp /*__attribute__ ((section (".text")))*/;
extern uintptr_t supervisor_sp;
 
//TODO: Remove include and move into exceptio.c
#include <arch/exception.h>
 
#include <syscall/syscall.h>
void tmp_swi_exception(int exc_no, istate_t* istate);
void tmp_swi_exception(int exc_no, istate_t* istate)
{
ASSERT(exc_no == EXC_SWI);
ASSERT(istate);
// TODO: Alf ... remove aftet swi_exception is tested
dprintf("\nSWI - istate dump input :\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 r13:%X lr:%X spsr:%X\n", istate->r12, istate->sp, istate->lr, istate->spsr);
// dprintf(" prev_lr:%X prev_sp:%X\n", istate->r12, istate->prev_lr, istate->prev_sp);
// call kernel to serve syscall
istate->r0 = syscall_handler(
istate->r0,
istate->r1,
istate->r2,
istate->r3,
istate->r4);
 
// TODO: Alf ... remove aftet swi_exception is tested
dprintf("\nSWI - Istate dump after :\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 r13:%X lr:%X spsr:%X\n", istate->r12, istate->sp, istate->lr, istate->spsr);
// dprintf(" prev_lr:%X prev_sp:%X\n", istate->r12, istate->prev_lr, istate->prev_sp);
}
 
 
void arch_pre_main(void)
{
int i;
126,6 → 92,7
//fb_init(0x12000000, 640, 480, 1920, VISUAL_RGB_8_8_8);
interrupts_enable();
 
}
 
void arch_post_cpu_init(void)
188,41 → 155,37
 
}
 
/** Change processor mode and jump into addres specified in
* kernel_uarg.uspace_entry
* \param kernel_uarg information needed for correct setting of userspace
/** Changes processor mode and jumps to the address specified in the first parameter.
*
* \param kernel_uarg userspace settings (entry point, stack, ...)
*/
void userspace(uspace_arg_t *kernel_uarg)
{
dprintf("userspace\n");
dprintf("Userspace: .uspace_uarg(%X), .uspace_entry(%X), .uspace_stack(%X)\n",
(unsigned int)(kernel_uarg->uspace_uarg), kernel_uarg->uspace_entry,
kernel_uarg->uspace_stack);
 
dprintf("userspce krnl_uard .uspace_uarg(%X), .uspace_entry(%X), .uspace_stack(%X)\n",
(unsigned int)(kernel_uarg->uspace_uarg),
kernel_uarg->uspace_entry,
kernel_uarg->uspace_stack);
volatile ustate_t ustate;
 
volatile ustate_t ustate;
 
//Step 1 ... prepare user space environment
//set first paramater
// set first parameter
ustate.r0 = (uintptr_t) kernel_uarg->uspace_uarg;
 
//clear other registers
// clear other registers
ustate.r1 = ustate.r2 = ustate.r3 = ustate.r4 =
ustate.r5 = ustate.r6 = ustate.r7 = ustate.r8 =
ustate.r9 = ustate.r10 = ustate.r11 = ustate.r12 = 1;
ustate.lr = 3;
ustate.r5 = ustate.r6 = ustate.r7 = ustate.r8 =
ustate.r9 = ustate.r10 = ustate.r11 = ustate.r12 = 1;
 
ustate.lr = 3;
 
//set user stack
ustate.sp = ((uint32_t)kernel_uarg->uspace_stack)+PAGE_SIZE;
ustate.sp = ((uint32_t)kernel_uarg->uspace_stack) + PAGE_SIZE;
 
//set where uspace executin starts
ustate.pc = (uintptr_t) kernel_uarg->uspace_entry;
//set where uspace execution starts
ustate.pc = (uintptr_t) kernel_uarg->uspace_entry;
 
 
//status register in user mode
ipl_t cpsr = current_status_reg_read();
cpsr &= ~STATUS_REG_MODE_MASK | USER_MODE;
cpsr &= ~STATUS_REG_MODE_MASK | USER_MODE;
ipl_t tmpsr = (cpsr & ~STATUS_REG_MODE_MASK) | SUPERVISOR_MODE;
 
/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);
}
}
 
/** @}