/branches/tracing/kernel/arch/arm32/src/debug/print.c |
---|
File deleted |
/branches/tracing/kernel/arch/arm32/src/console.c |
---|
File deleted |
/branches/tracing/kernel/arch/arm32/src/exception.c |
---|
34,13 → 34,12 |
*/ |
#include <arch/exception.h> |
#include <arch/debug/print.h> |
#include <arch/memstr.h> |
#include <arch/regutils.h> |
#include <interrupt.h> |
#include <arch/machine.h> |
#include <arch/mm/page_fault.h> |
#include <arch/barrier.h> |
#include <arch/drivers/gxemul.h> |
#include <print.h> |
#include <syscall/syscall.h> |
#include <udebug/udebug.h> |
64,57 → 63,60 |
* |
* Temporary exception stack is used to save a few registers |
* before stack switch takes place. |
* |
*/ |
inline static void setup_stack_and_save_regs() |
{ |
asm volatile( |
"ldr r13, =exc_stack \n" |
"stmfd r13!, {r0} \n" |
"mrs r0, spsr \n" |
"and r0, r0, #0x1f \n" |
"cmp r0, #0x10 \n" |
"bne 1f \n" |
asm volatile ( |
"ldr r13, =exc_stack\n" |
"stmfd r13!, {r0}\n" |
"mrs r0, spsr\n" |
"and r0, r0, #0x1f\n" |
"cmp r0, #0x10\n" |
"bne 1f\n" |
/* prev mode was usermode */ |
"ldmfd r13!, {r0} \n" |
"ldr r13, =supervisor_sp \n" |
"ldr r13, [r13] \n" |
"stmfd r13!, {lr} \n" |
"stmfd r13!, {r0-r12} \n" |
"stmfd r13!, {r13, lr}^ \n" |
"mrs r0, spsr \n" |
"stmfd r13!, {r0} \n" |
"b 2f \n" |
"ldmfd r13!, {r0}\n" |
"ldr r13, =supervisor_sp\n" |
"ldr r13, [r13]\n" |
"stmfd r13!, {lr}\n" |
"stmfd r13!, {r0-r12}\n" |
"stmfd r13!, {r13, lr}^\n" |
"mrs r0, spsr\n" |
"stmfd r13!, {r0}\n" |
"b 2f\n" |
/* mode was not usermode */ |
"1:\n" |
"stmfd r13!, {r1, r2, r3} \n" |
"mrs r1, cpsr \n" |
"mov r2, lr \n" |
"bic r1, r1, #0x1f \n" |
"orr r1, r1, r0 \n" |
"mrs r0, cpsr \n" |
"msr cpsr_c, r1 \n" |
"mov r3, r13 \n" |
"stmfd r13!, {r2} \n" |
"mov r2, lr \n" |
"stmfd r13!, {r4-r12} \n" |
"mov r1, r13 \n" |
/* the following two lines are for debugging */ |
"mov sp, #0 \n" |
"mov lr, #0 \n" |
"msr cpsr_c, r0 \n" |
"ldmfd r13!, {r4, r5, r6, r7} \n" |
"stmfd r1!, {r4, r5, r6} \n" |
"stmfd r1!, {r7} \n" |
"stmfd r1!, {r2} \n" |
"stmfd r1!, {r3} \n" |
"mrs r0, spsr \n" |
"stmfd r1!, {r0} \n" |
"mov r13, r1 \n" |
"2:\n" |
"1:\n" |
"stmfd r13!, {r1, r2, r3}\n" |
"mrs r1, cpsr\n" |
"mov r2, lr\n" |
"bic r1, r1, #0x1f\n" |
"orr r1, r1, r0\n" |
"mrs r0, cpsr\n" |
"msr cpsr_c, r1\n" |
"mov r3, r13\n" |
"stmfd r13!, {r2}\n" |
"mov r2, lr\n" |
"stmfd r13!, {r4-r12}\n" |
"mov r1, r13\n" |
/* the following two lines are for debugging */ |
"mov sp, #0\n" |
"mov lr, #0\n" |
"msr cpsr_c, r0\n" |
"ldmfd r13!, {r4, r5, r6, r7}\n" |
"stmfd r1!, {r4, r5, r6}\n" |
"stmfd r1!, {r7}\n" |
"stmfd r1!, {r2}\n" |
"stmfd r1!, {r3}\n" |
"mrs r0, spsr\n" |
"stmfd r1!, {r0}\n" |
"mov r13, r1\n" |
"2:\n" |
); |
} |
190,10 → 192,13 |
} |
/** Calls exception dispatch routine. */ |
#define CALL_EXC_DISPATCH(exception) \ |
asm("mov r0, %0" : : "i" (exception)); \ |
asm("mov r1, r13"); \ |
asm("bl exc_dispatch"); |
#define CALL_EXC_DISPATCH(exception) \ |
asm volatile ( \ |
"mov r0, %[exc]\n" \ |
"mov r1, r13\n" \ |
"bl exc_dispatch\n" \ |
:: [exc] "i" (exception) \ |
);\ |
/** General exception handler. |
* |
202,9 → 207,9 |
* |
* @param exception Exception number. |
*/ |
#define PROCESS_EXCEPTION(exception) \ |
setup_stack_and_save_regs(); \ |
CALL_EXC_DISPATCH(exception) \ |
#define PROCESS_EXCEPTION(exception) \ |
setup_stack_and_save_regs(); \ |
CALL_EXC_DISPATCH(exception) \ |
load_regs(); |
/** Updates specified exception vector to jump to given handler. |
255,7 → 260,10 |
/** Low-level Prefetch Abort Exception handler. */ |
static void prefetch_abort_exception_entry(void) |
{ |
asm("sub lr, lr, #4"); |
asm volatile ( |
"sub lr, lr, #4" |
); |
PROCESS_EXCEPTION(EXC_PREFETCH_ABORT); |
} |
262,7 → 270,10 |
/** Low-level Data Abort Exception handler. */ |
static void data_abort_exception_entry(void) |
{ |
asm("sub lr, lr, #8"); |
asm volatile ( |
"sub lr, lr, #8" |
); |
PROCESS_EXCEPTION(EXC_DATA_ABORT); |
} |
274,7 → 285,10 |
*/ |
static void irq_exception_entry(void) |
{ |
asm("sub lr, lr, #4"); |
asm volatile ( |
"sub lr, lr, #4" |
); |
setup_stack_and_save_regs(); |
switch_to_irq_servicing_mode(); |
294,6 → 308,12 |
istate->r3, istate->r4, istate->r5, istate->r6); |
} |
/** Returns the mask of active interrupts. */ |
static inline uint32_t gxemul_irqc_get_sources(void) |
{ |
return *((uint32_t *) gxemul_irqc); |
} |
/** Interrupt Exception handler. |
* |
* Determines the sources of interrupt and calls their handlers. |
300,7 → 320,23 |
*/ |
static void irq_exception(int exc_no, istate_t *istate) |
{ |
machine_irq_exception(exc_no, istate); |
uint32_t sources = gxemul_irqc_get_sources(); |
unsigned int i; |
for (i = 0; i < GXEMUL_IRQC_MAX_IRQ; i++) { |
if (sources & (1 << i)) { |
irq_t *irq = irq_dispatch_and_lock(i); |
if (irq) { |
/* The IRQ handler was found. */ |
irq->handler(irq); |
spinlock_unlock(&irq->lock); |
} else { |
/* Spurious interrupt.*/ |
printf("cpu%d: spurious interrupt (inum=%d)\n", |
CPU->id, i); |
} |
} |
} |
} |
/** Fills exception vectors with appropriate exception handlers. */ |
324,7 → 360,7 |
install_handler((unsigned) irq_exception_entry, |
(unsigned *) EXC_IRQ_VEC); |
install_handler((unsigned)fiq_exception_entry, |
install_handler((unsigned) fiq_exception_entry, |
(unsigned *) EXC_FIQ_VEC); |
} |
334,17 → 370,23 |
{ |
uint32_t control_reg; |
asm volatile("mrc p15, 0, %0, c1, c1" : "=r" (control_reg)); |
asm volatile ( |
"mrc p15, 0, %[control_reg], c1, c1" |
: [control_reg] "=r" (control_reg) |
); |
/* switch on the high vectors bit */ |
control_reg |= CP15_R1_HIGH_VECTORS_BIT; |
asm volatile("mcr p15, 0, %0, c1, c1" : : "r" (control_reg)); |
asm volatile ( |
"mcr p15, 0, %[control_reg], c1, c1" |
:: [control_reg] "r" (control_reg) |
); |
} |
#endif |
/** Initializes exception handling. |
* |
* |
* Installs low-level exception handlers and then registers |
* exceptions and their handlers to kernel exception dispatcher. |
*/ |
368,18 → 410,18 |
*/ |
void print_istate(istate_t *istate) |
{ |
dprintf("istate dump:\n"); |
dprintf(" r0: %x r1: %x r2: %x r3: %x\n", |
printf("istate dump:\n"); |
printf(" 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", |
printf(" 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", |
printf(" 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", |
printf(" r12: %x sp: %x lr: %x spsr: %x\n", |
istate->r12, istate->sp, istate->lr, istate->spsr); |
dprintf(" pc: %x\n", istate->pc); |
printf(" pc: %x\n", istate->pc); |
} |
/** @} |
/branches/tracing/kernel/arch/arm32/src/asm.S |
---|
30,6 → 30,7 |
.text |
.global memsetb |
.global memsetw |
.global memcpy |
.global memcpy_from_uspace |
.global memcpy_to_uspace |
39,6 → 40,9 |
memsetb: |
b _memsetb |
memsetw: |
b _memsetw |
memcpy: |
memcpy_from_uspace: |
memcpy_to_uspace: |
/branches/tracing/kernel/arch/arm32/src/arm32.c |
---|
34,36 → 34,37 |
*/ |
#include <arch.h> |
#include <arch/boot.h> |
#include <config.h> |
#include <arch/console.h> |
#include <ddi/device.h> |
#include <genarch/fb/fb.h> |
#include <genarch/fb/visuals.h> |
#include <genarch/drivers/dsrln/dsrlnin.h> |
#include <genarch/drivers/dsrln/dsrlnout.h> |
#include <genarch/srln/srln.h> |
#include <sysinfo/sysinfo.h> |
#include <console/console.h> |
#include <ddi/irq.h> |
#include <arch/debug/print.h> |
#include <arch/drivers/gxemul.h> |
#include <print.h> |
#include <config.h> |
#include <interrupt.h> |
#include <arch/regutils.h> |
#include <arch/machine.h> |
#include <userspace.h> |
#include <macros.h> |
#include <string.h> |
/** Information about loaded tasks. */ |
bootinfo_t bootinfo; |
/** Performs arm32 specific initialization before main_bsp() is called. */ |
void arch_pre_main(void) |
/** Performs arm32-specific initialization before main_bsp() is called. */ |
void arch_pre_main(void *entry __attribute__((unused)), bootinfo_t *bootinfo) |
{ |
unsigned int i; |
init.cnt = bootinfo.cnt; |
for (i = 0; i < bootinfo.cnt; ++i) { |
init.tasks[i].addr = bootinfo.tasks[i].addr; |
init.tasks[i].size = bootinfo.tasks[i].size; |
init.cnt = bootinfo->cnt; |
for (i = 0; i < min3(bootinfo->cnt, TASKMAP_MAX_RECORDS, CONFIG_INIT_TASKS); ++i) { |
init.tasks[i].addr = bootinfo->tasks[i].addr; |
init.tasks[i].size = bootinfo->tasks[i].size; |
str_cpy(init.tasks[i].name, CONFIG_TASK_NAME_BUFLEN, |
bootinfo->tasks[i].name); |
} |
} |
/** Performs arm32 specific initialization before mm is initialized. */ |
76,26 → 77,27 |
/** Performs arm32 specific initialization afterr mm is initialized. */ |
void arch_post_mm_init(void) |
{ |
machine_hw_map_init(); |
gxemul_init(); |
/* Initialize exception dispatch table */ |
exception_init(); |
interrupt_init(); |
console_init(device_assign_devno()); |
#ifdef CONFIG_FB |
fb_properties_t prop = { |
.addr = machine_get_fb_address(), |
.addr = GXEMUL_FB_ADDRESS, |
.offset = 0, |
.x = 640, |
.y = 480, |
.scan = 1920, |
.visual = VISUAL_RGB_8_8_8, |
.visual = VISUAL_BGR_8_8_8, |
}; |
fb_init(&prop); |
#endif |
#else |
#ifdef CONFIG_ARM_PRN |
dsrlnout_init((ioport8_t *) gxemul_kbd); |
#endif /* CONFIG_ARM_PRN */ |
#endif /* CONFIG_FB */ |
} |
/** Performs arm32 specific tasks needed after cpu is initialized. |
124,6 → 126,30 |
*/ |
void arch_post_smp_init(void) |
{ |
#ifdef CONFIG_ARM_KBD |
/* |
* Initialize the GXemul keyboard port. Then initialize the serial line |
* module and connect it to the GXemul keyboard. |
*/ |
dsrlnin_instance_t *dsrlnin_instance |
= dsrlnin_init((dsrlnin_t *) gxemul_kbd, GXEMUL_KBD_IRQ); |
if (dsrlnin_instance) { |
srln_instance_t *srln_instance = srln_init(); |
if (srln_instance) { |
indev_t *sink = stdin_wire(); |
indev_t *srln = srln_wire(srln_instance, sink); |
dsrlnin_wire(dsrlnin_instance, srln); |
} |
} |
/* |
* This is the necessary evil until the userspace driver is entirely |
* self-sufficient. |
*/ |
sysinfo_set_item_val("kbd", NULL, true); |
sysinfo_set_item_val("kbd.inr", NULL, GXEMUL_KBD_IRQ); |
sysinfo_set_item_val("kbd.address.virtual", NULL, (unative_t) gxemul_kbd); |
#endif |
} |
157,7 → 183,8 |
/** Halts CPU. */ |
void cpu_halt(void) |
{ |
machine_cpu_halt(); |
*((char *) (gxemul_kbd + GXEMUL_HALT_OFFSET)) |
= 0; |
} |
/** Reboot. */ |
164,9 → 191,35 |
void arch_reboot() |
{ |
/* not implemented */ |
for (;;) |
; |
while (1); |
} |
/** Construct function pointer |
* |
* @param fptr function pointer structure |
* @param addr function address |
* @param caller calling function address |
* |
* @return address of the function pointer |
* |
*/ |
void *arch_construct_function(fncptr_t *fptr, void *addr, void *caller) |
{ |
return addr; |
} |
/** Acquire console back for kernel. */ |
void arch_grab_console(void) |
{ |
#ifdef CONFIG_FB |
fb_redraw(); |
#endif |
} |
/** Return console to userspace. */ |
void arch_release_console(void) |
{ |
} |
/** @} |
*/ |
/branches/tracing/kernel/arch/arm32/src/cpu/cpu.c |
---|
36,7 → 36,7 |
#include <arch/cpu.h> |
#include <cpu.h> |
#include <arch.h> |
#include <print.h> |
#include <print.h> |
/** Number of indexes left out in the #imp_data array */ |
#define IMP_DATA_START_OFFSET 0x40 |
82,10 → 82,10 |
{ |
uint32_t ident; |
asm volatile ( |
"mrc p15, 0, %0, c0, c0, 0\n" |
: "=r" (ident) |
"mrc p15, 0, %[ident], c0, c0, 0\n" |
: [ident] "=r" (ident) |
); |
cpu->imp_num = ident >> 24; |
cpu->variant_num = (ident << 8) >> 28; |
cpu->arch_num = (ident << 12) >> 28; |
/branches/tracing/kernel/arch/arm32/src/mm/tlb.c |
---|
48,7 → 48,7 |
asm volatile ( |
"eor r1, r1\n" |
"mcr p15, 0, r1, c8, c7, 0\n" |
: : : "r1" |
::: "r1" |
); |
} |
68,9 → 68,8 |
static inline void invalidate_page(uintptr_t page) |
{ |
asm volatile ( |
"mcr p15, 0, %0, c8, c7, 1" |
: |
: "r" (page) |
"mcr p15, 0, %[page], c8, c7, 1\n" |
:: [page] "r" (page) |
); |
} |
81,7 → 80,7 |
* @param page Address of the first page whose entry is to be invalidated. |
* @param cnt Number of entries to invalidate. |
*/ |
void tlb_invalidate_pages(asid_t asid, uintptr_t page, count_t cnt) |
void tlb_invalidate_pages(asid_t asid __attribute__((unused)), uintptr_t page, count_t cnt) |
{ |
unsigned int i; |
89,5 → 88,13 |
invalidate_page(page + i * PAGE_SIZE); |
} |
void tlb_arch_init(void) |
{ |
} |
void tlb_print(void) |
{ |
} |
/** @} |
*/ |
/branches/tracing/kernel/arch/arm32/src/mm/page_fault.c |
---|
34,7 → 34,6 |
*/ |
#include <panic.h> |
#include <arch/exception.h> |
#include <arch/debug/print.h> |
#include <arch/mm/page_fault.h> |
#include <mm/as.h> |
#include <genarch/mm/page_pt.h> |
49,12 → 48,13 |
static inline fault_status_t read_fault_status_register(void) |
{ |
fault_status_union_t fsu; |
/* fault status is stored in CP15 register 5 */ |
asm volatile ( |
"mrc p15, 0, %0, c5, c0, 0" |
: "=r"(fsu.dummy) |
"mrc p15, 0, %[dummy], c5, c0, 0" |
: [dummy] "=r" (fsu.dummy) |
); |
return fsu.fs; |
} |
61,17 → 61,18 |
/** Returns FAR (fault address register) content. |
* |
* @return FAR (fault address register) content (address that caused a page |
* fault) |
* fault) |
*/ |
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"(ret) |
"mrc p15, 0, %[ret], c6, c0, 0" |
: [ret] "=r" (ret) |
); |
return ret; |
} |
80,29 → 81,26 |
* @param instr Instruction |
* |
* @return true when instruction is load/store, false otherwise |
* |
*/ |
static inline bool is_load_store_instruction(instruction_t instr) |
{ |
/* load store immediate offset */ |
if (instr.type == 0x2) { |
if (instr.type == 0x2) |
return true; |
} |
/* load store register offset */ |
if (instr.type == 0x3 && instr.bit4 == 0) { |
if ((instr.type == 0x3) && (instr.bit4 == 0)) |
return true; |
} |
/* load store multiple */ |
if (instr.type == 0x4) { |
if (instr.type == 0x4) |
return true; |
} |
/* oprocessor load/store */ |
if (instr.type == 0x6) { |
if (instr.type == 0x6) |
return true; |
} |
return false; |
} |
115,12 → 113,11 |
static inline bool is_swap_instruction(instruction_t instr) |
{ |
/* swap, swapb instruction */ |
if (instr.type == 0x0 && |
(instr.opcode == 0x8 || instr.opcode == 0xa) && |
instr.access == 0x0 && instr.bits567 == 0x4 && instr.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; |
} |
142,8 → 139,8 |
/* undefined instructions */ |
if (instr.condition == 0xf) { |
panic("page_fault - instruction doesn't access memory " |
"(instr_code: %x, badvaddr:%x)", instr, badvaddr); |
panic("page_fault - instruction does not access memory " |
"(instr_code: %x, badvaddr:%x).", instr, badvaddr); |
return PF_ACCESS_EXEC; |
} |
162,7 → 159,7 |
} |
panic("page_fault - instruction doesn't access memory " |
"(instr_code: %x, badvaddr:%x)", instr, badvaddr); |
"(instr_code: %x, badvaddr:%x).", instr, badvaddr); |
return PF_ACCESS_EXEC; |
} |
184,12 → 181,12 |
if (ret == AS_PF_FAULT) { |
print_istate(istate); |
dprintf("page fault - pc: %x, va: %x, status: %x(%x), " |
printf("page fault - pc: %x, va: %x, status: %x(%x), " |
"access:%d\n", istate->pc, badvaddr, fsr.status, fsr, |
access); |
fault_if_from_uspace(istate, "Page fault: %#x", badvaddr); |
panic("page fault\n"); |
fault_if_from_uspace(istate, "Page fault: %#x.", badvaddr); |
panic("Page fault."); |
} |
} |
232,9 → 229,9 |
int ret = as_page_fault(istate->pc, PF_ACCESS_EXEC, istate); |
if (ret == AS_PF_FAULT) { |
dprintf("prefetch_abort\n"); |
printf("prefetch_abort\n"); |
print_istate(istate); |
panic("page fault - prefetch_abort at address: %x\n", |
panic("page fault - prefetch_abort at address: %x.", |
istate->pc); |
} |
/branches/tracing/kernel/arch/arm32/src/mm/frame.c |
---|
26,7 → 26,7 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup arm32mm |
/** @addtogroup arm32mm |
* @{ |
*/ |
/** @file |
35,9 → 35,8 |
#include <mm/frame.h> |
#include <arch/mm/frame.h> |
#include <arch/machine.h> |
#include <arch/drivers/gxemul.h> |
#include <config.h> |
#include <arch/debug/print.h> |
/** Address of the last frame in the memory. */ |
uintptr_t last_frame = 0; |
45,11 → 44,12 |
/** Creates memory zones. */ |
void frame_arch_init(void) |
{ |
/* all memory as one zone */ |
zone_create(0, ADDR2PFN(machine_get_memory_size()), |
last_frame = *((uintptr_t *) (GXEMUL_MP_ADDRESS + GXEMUL_MP_MEMSIZE_OFFSET)); |
/* All memory as one zone */ |
zone_create(0, ADDR2PFN(last_frame), |
BOOT_PAGE_TABLE_START_FRAME + BOOT_PAGE_TABLE_SIZE_IN_FRAMES, 0); |
last_frame = machine_get_memory_size(); |
/* blacklist boot page table */ |
frame_mark_unavailable(BOOT_PAGE_TABLE_START_FRAME, |
BOOT_PAGE_TABLE_SIZE_IN_FRAMES); |
58,10 → 58,9 |
/** Frees the boot page table. */ |
void boot_page_table_free(void) |
{ |
int i; |
for (i = 0; i < BOOT_PAGE_TABLE_SIZE_IN_FRAMES; i++) { |
unsigned int i; |
for (i = 0; i < BOOT_PAGE_TABLE_SIZE_IN_FRAMES; i++) |
frame_free(i * FRAME_SIZE + BOOT_PAGE_TABLE_ADDRESS); |
} |
} |
/** @} |
/branches/tracing/kernel/arch/arm32/src/mm/page.c |
---|
51,19 → 51,15 |
*/ |
void page_arch_init(void) |
{ |
int flags = PAGE_CACHEABLE; |
page_mapping_operations = &pt_mapping_operations; |
uintptr_t cur; |
int flags; |
page_mapping_operations = &pt_mapping_operations; |
flags = PAGE_CACHEABLE; |
/* PA2KA(identity) mapping for all frames until last_frame */ |
for (cur = 0; cur < last_frame; cur += FRAME_SIZE) { |
/* Kernel identity mapping */ |
for (cur = 0; cur < last_frame; cur += FRAME_SIZE) |
page_mapping_insert(AS_KERNEL, PA2KA(cur), cur, flags); |
} |
/* create mapping for exception table at high offset */ |
/* Create mapping for exception table at high offset */ |
#ifdef HIGH_EXCEPTION_VECTORS |
void *virtaddr = frame_alloc(ONE_FRAME, FRAME_KA); |
page_mapping_insert(AS_KERNEL, EXC_BASE_ADDRESS, KA2PA(virtaddr), flags); |
70,9 → 66,9 |
#else |
#error "Only high exception vector supported now" |
#endif |
as_switch(NULL, AS_KERNEL); |
boot_page_table_free(); |
} |
90,10 → 86,10 |
{ |
if (last_frame + ALIGN_UP(size, PAGE_SIZE) > |
KA2PA(KERNEL_ADDRESS_SPACE_END_ARCH)) { |
panic("Unable to map physical memory %p (%d bytes)", |
panic("Unable to map physical memory %p (%d bytes).", |
physaddr, size) |
} |
uintptr_t virtaddr = PA2KA(last_frame); |
pfn_t i; |
for (i = 0; i < ADDR2PFN(ALIGN_UP(size, PAGE_SIZE)); i++) { |
101,7 → 97,7 |
physaddr + PFN2ADDR(i), |
PAGE_NOT_CACHEABLE | PAGE_READ | PAGE_WRITE | PAGE_KERNEL); |
} |
last_frame = ALIGN_UP(last_frame + size, FRAME_SIZE); |
return virtaddr; |
} |
/branches/tracing/kernel/arch/arm32/src/panic.S |
---|
31,5 → 31,5 |
.global panic_printf |
panic_printf: |
bl debug_printf |
bl printf |
bl cpu_halt |
/branches/tracing/kernel/arch/arm32/src/userspace.c |
---|
90,12 → 90,11 |
/* set user mode, set registers, jump */ |
asm volatile ( |
"mov sp, %0 \n" |
"msr spsr_c, %1 \n" |
"ldmfd sp!, {r0-r12, sp, lr}^ \n" |
"mov sp, %[ustate]\n" |
"msr spsr_c, %[user_mode]\n" |
"ldmfd sp!, {r0-r12, sp, lr}^\n" |
"ldmfd sp!, {pc}^\n" |
: |
: "r" (&ustate), "r" (user_mode) |
:: [ustate] "r" (&ustate), [user_mode] "r" (user_mode) |
); |
/* unreachable */ |
/branches/tracing/kernel/arch/arm32/src/interrupt.c |
---|
35,13 → 35,16 |
#include <arch/asm.h> |
#include <arch/regutils.h> |
#include <arch/drivers/gxemul.h> |
#include <ddi/irq.h> |
#include <arch/machine.h> |
#include <ddi/device.h> |
#include <interrupt.h> |
/** Initial size of a table holding interrupt handlers. */ |
#define IRQ_COUNT 8 |
static irq_t gxemul_timer_irq; |
/** Disable interrupts. |
* |
* @return Old interrupt priority level. |
49,7 → 52,7 |
ipl_t interrupts_disable(void) |
{ |
ipl_t ipl = current_status_reg_read(); |
current_status_reg_control_write(STATUS_REG_IRQ_DISABLED_BIT | ipl); |
return ipl; |
62,9 → 65,9 |
ipl_t interrupts_enable(void) |
{ |
ipl_t ipl = current_status_reg_read(); |
current_status_reg_control_write(ipl & ~STATUS_REG_IRQ_DISABLED_BIT); |
return ipl; |
} |
88,6 → 91,41 |
return current_status_reg_read(); |
} |
/** Starts gxemul Real Time Clock device, which asserts regular interrupts. |
* |
* @param frequency Interrupts frequency (0 disables RTC). |
*/ |
static void gxemul_timer_start(uint32_t frequency) |
{ |
*((uint32_t *) (gxemul_rtc + GXEMUL_RTC_FREQ_OFFSET)) |
= frequency; |
} |
static irq_ownership_t gxemul_timer_claim(irq_t *irq) |
{ |
return IRQ_ACCEPT; |
} |
/** Timer interrupt handler. |
* |
* @param irq Interrupt information. |
* @param arg Not used. |
*/ |
static void gxemul_timer_irq_handler(irq_t *irq) |
{ |
/* |
* We are holding a lock which prevents preemption. |
* Release the lock, call clock() and reacquire the lock again. |
*/ |
spinlock_unlock(&irq->lock); |
clock(); |
spinlock_lock(&irq->lock); |
/* acknowledge tick */ |
*((uint32_t *) (gxemul_rtc + GXEMUL_RTC_ACK_OFFSET)) |
= 0; |
} |
/** Initialize basic tables for exception dispatching |
* and starts the timer. |
*/ |
94,7 → 132,16 |
void interrupt_init(void) |
{ |
irq_init(IRQ_COUNT, IRQ_COUNT); |
machine_timer_irq_start(); |
irq_initialize(&gxemul_timer_irq); |
gxemul_timer_irq.devno = device_assign_devno(); |
gxemul_timer_irq.inr = GXEMUL_TIMER_IRQ; |
gxemul_timer_irq.claim = gxemul_timer_claim; |
gxemul_timer_irq.handler = gxemul_timer_irq_handler; |
irq_register(&gxemul_timer_irq); |
gxemul_timer_start(GXEMUL_TIMER_FREQ); |
} |
/** @} |
/branches/tracing/kernel/arch/arm32/src/drivers/gxemul.c |
---|
33,361 → 33,19 |
* @brief GXemul drivers. |
*/ |
#include <interrupt.h> |
#include <ipc/irq.h> |
#include <console/chardev.h> |
#include <arch/drivers/gxemul.h> |
#include <console/console.h> |
#include <sysinfo/sysinfo.h> |
#include <print.h> |
#include <ddi/device.h> |
#include <mm/page.h> |
#include <arch/machine.h> |
#include <arch/debug/print.h> |
/* Addresses of devices. */ |
#define GXEMUL_VIDEORAM 0x10000000 |
#define GXEMUL_KBD 0x10000000 |
#define GXEMUL_HALT_OFFSET 0x10 |
#define GXEMUL_RTC 0x15000000 |
#define GXEMUL_RTC_FREQ_OFFSET 0x100 |
#define GXEMUL_RTC_ACK_OFFSET 0x110 |
#define GXEMUL_IRQC 0x16000000 |
#define GXEMUL_IRQC_MASK_OFFSET 0x4 |
#define GXEMUL_IRQC_UNMASK_OFFSET 0x8 |
#define GXEMUL_MP 0x11000000 |
#define GXEMUL_MP_MEMSIZE_OFFSET 0x0090 |
#define GXEMUL_FB 0x12000000 |
void *gxemul_kbd; |
void *gxemul_rtc; |
void *gxemul_irqc; |
/* IRQs */ |
#define GXEMUL_KBD_IRQ 2 |
#define GXEMUL_TIMER_IRQ 4 |
static gxemul_hw_map_t gxemul_hw_map; |
static chardev_t console; |
static irq_t gxemul_console_irq; |
static irq_t gxemul_timer_irq; |
static bool hw_map_init_called = false; |
static void gxemul_kbd_enable(chardev_t *dev); |
static void gxemul_kbd_disable(chardev_t *dev); |
static void gxemul_write(chardev_t *dev, const char ch); |
static char gxemul_do_read(chardev_t *dev); |
static chardev_operations_t gxemul_ops = { |
.resume = gxemul_kbd_enable, |
.suspend = gxemul_kbd_disable, |
.write = gxemul_write, |
.read = gxemul_do_read, |
}; |
/** Returns the mask of active interrupts. */ |
static inline uint32_t gxemul_irqc_get_sources(void) |
void gxemul_init(void) |
{ |
return *((uint32_t *) gxemul_hw_map.irqc); |
gxemul_kbd = (void *) hw_map(GXEMUL_KBD_ADDRESS, PAGE_SIZE); |
gxemul_rtc = (void *) hw_map(GXEMUL_RTC_ADDRESS, PAGE_SIZE); |
gxemul_irqc = (void *) hw_map(GXEMUL_IRQC_ADDRESS, PAGE_SIZE); |
} |
/** Masks interrupt. |
* |
* @param irq interrupt number |
*/ |
static inline void gxemul_irqc_mask(uint32_t irq) |
{ |
*((uint32_t *) gxemul_hw_map.irqc_mask) = irq; |
} |
/** Unmasks interrupt. |
* |
* @param irq interrupt number |
*/ |
static inline void gxemul_irqc_unmask(uint32_t irq) |
{ |
*((uint32_t *) gxemul_hw_map.irqc_unmask) = irq; |
} |
/** Initializes #gxemul_hw_map. */ |
void gxemul_hw_map_init(void) |
{ |
gxemul_hw_map.videoram = hw_map(GXEMUL_VIDEORAM, PAGE_SIZE); |
gxemul_hw_map.kbd = hw_map(GXEMUL_KBD, PAGE_SIZE); |
gxemul_hw_map.rtc = hw_map(GXEMUL_RTC, PAGE_SIZE); |
gxemul_hw_map.irqc = hw_map(GXEMUL_IRQC, PAGE_SIZE); |
gxemul_hw_map.rtc_freq = gxemul_hw_map.rtc + GXEMUL_RTC_FREQ_OFFSET; |
gxemul_hw_map.rtc_ack = gxemul_hw_map.rtc + GXEMUL_RTC_ACK_OFFSET; |
gxemul_hw_map.irqc_mask = gxemul_hw_map.irqc + GXEMUL_IRQC_MASK_OFFSET; |
gxemul_hw_map.irqc_unmask = gxemul_hw_map.irqc + |
GXEMUL_IRQC_UNMASK_OFFSET; |
hw_map_init_called = true; |
} |
/** Putchar that works with gxemul. |
* |
* @param dev Not used. |
* @param ch Characted to be printed. |
*/ |
static void gxemul_write(chardev_t *dev, const char ch) |
{ |
*((char *) gxemul_hw_map.videoram) = ch; |
} |
/** Enables gxemul keyboard (interrupt unmasked). |
* |
* @param dev Not used. |
* |
* Called from getc(). |
*/ |
static void gxemul_kbd_enable(chardev_t *dev) |
{ |
gxemul_irqc_unmask(GXEMUL_KBD_IRQ); |
} |
/** Disables gxemul keyboard (interrupt masked). |
* |
* @param dev not used |
* |
* Called from getc(). |
*/ |
static void gxemul_kbd_disable(chardev_t *dev) |
{ |
gxemul_irqc_mask(GXEMUL_KBD_IRQ); |
} |
/** Read character using polling, assume interrupts disabled. |
* |
* @param dev Not used. |
*/ |
static char gxemul_do_read(chardev_t *dev) |
{ |
char ch; |
while (1) { |
ch = *((volatile char *) gxemul_hw_map.kbd); |
if (ch) { |
if (ch == '\r') |
return '\n'; |
if (ch == 0x7f) |
return '\b'; |
return ch; |
} |
} |
} |
/** Process keyboard interrupt. |
* |
* @param irq IRQ information. |
* @param arg Not used. |
*/ |
static void gxemul_irq_handler(irq_t *irq, void *arg, ...) |
{ |
if ((irq->notif_cfg.notify) && (irq->notif_cfg.answerbox)) { |
ipc_irq_send_notif(irq); |
} else { |
char ch = 0; |
ch = *((char *) gxemul_hw_map.kbd); |
if (ch == '\r') { |
ch = '\n'; |
} |
if (ch == 0x7f) { |
ch = '\b'; |
} |
chardev_push_character(&console, ch); |
} |
} |
static irq_ownership_t gxemul_claim(void) |
{ |
return IRQ_ACCEPT; |
} |
/** Acquire console back for kernel. */ |
void gxemul_grab_console(void) |
{ |
ipl_t ipl = interrupts_disable(); |
spinlock_lock(&gxemul_console_irq.lock); |
gxemul_console_irq.notif_cfg.notify = false; |
spinlock_unlock(&gxemul_console_irq.lock); |
interrupts_restore(ipl); |
} |
/** Return console to userspace. */ |
void gxemul_release_console(void) |
{ |
ipl_t ipl = interrupts_disable(); |
spinlock_lock(&gxemul_console_irq.lock); |
if (gxemul_console_irq.notif_cfg.answerbox) { |
gxemul_console_irq.notif_cfg.notify = true; |
} |
spinlock_unlock(&gxemul_console_irq.lock); |
interrupts_restore(ipl); |
} |
/** Initializes console object representing gxemul console. |
* |
* @param devno device number. |
*/ |
void gxemul_console_init(devno_t devno) |
{ |
chardev_initialize("gxemul_console", &console, &gxemul_ops); |
stdin = &console; |
stdout = &console; |
irq_initialize(&gxemul_console_irq); |
gxemul_console_irq.devno = devno; |
gxemul_console_irq.inr = GXEMUL_KBD_IRQ; |
gxemul_console_irq.claim = gxemul_claim; |
gxemul_console_irq.handler = gxemul_irq_handler; |
irq_register(&gxemul_console_irq); |
gxemul_irqc_unmask(GXEMUL_KBD_IRQ); |
sysinfo_set_item_val("kbd", NULL, true); |
sysinfo_set_item_val("kbd.devno", NULL, devno); |
sysinfo_set_item_val("kbd.inr", NULL, GXEMUL_KBD_IRQ); |
sysinfo_set_item_val("kbd.address.virtual", NULL, gxemul_hw_map.kbd); |
} |
/** Starts gxemul Real Time Clock device, which asserts regular interrupts. |
* |
* @param frequency Interrupts frequency (0 disables RTC). |
*/ |
static void gxemul_timer_start(uint32_t frequency) |
{ |
*((uint32_t*) gxemul_hw_map.rtc_freq) = frequency; |
} |
static irq_ownership_t gxemul_timer_claim(void) |
{ |
return IRQ_ACCEPT; |
} |
/** Timer interrupt handler. |
* |
* @param irq Interrupt information. |
* @param arg Not used. |
*/ |
static void gxemul_timer_irq_handler(irq_t *irq, void *arg, ...) |
{ |
/* |
* We are holding a lock which prevents preemption. |
* Release the lock, call clock() and reacquire the lock again. |
*/ |
spinlock_unlock(&irq->lock); |
clock(); |
spinlock_lock(&irq->lock); |
/* acknowledge tick */ |
*((uint32_t*) gxemul_hw_map.rtc_ack) = 0; |
} |
/** Initializes and registers timer interrupt handler. */ |
static void gxemul_timer_irq_init(void) |
{ |
irq_initialize(&gxemul_timer_irq); |
gxemul_timer_irq.devno = device_assign_devno(); |
gxemul_timer_irq.inr = GXEMUL_TIMER_IRQ; |
gxemul_timer_irq.claim = gxemul_timer_claim; |
gxemul_timer_irq.handler = gxemul_timer_irq_handler; |
irq_register(&gxemul_timer_irq); |
} |
/** Starts timer. |
* |
* Initiates regular timer interrupts after initializing |
* corresponding interrupt handler. |
*/ |
void gxemul_timer_irq_start(void) |
{ |
gxemul_timer_irq_init(); |
gxemul_timer_start(GXEMUL_TIMER_FREQ); |
} |
/** Returns the size of emulated memory. |
* |
* @return Size in bytes. |
*/ |
size_t gxemul_get_memory_size(void) |
{ |
return *((int *) (GXEMUL_MP + GXEMUL_MP_MEMSIZE_OFFSET)); |
} |
/** Prints a character. |
* |
* @param ch Character to be printed. |
*/ |
void gxemul_debug_putc(char ch) |
{ |
char *addr = 0; |
if (!hw_map_init_called) { |
addr = (char *) GXEMUL_KBD; |
} else { |
addr = (char *) gxemul_hw_map.videoram; |
} |
*(addr) = ch; |
} |
/** Stops gxemul. */ |
void gxemul_cpu_halt(void) |
{ |
char * addr = 0; |
if (!hw_map_init_called) { |
addr = (char *) GXEMUL_KBD; |
} else { |
addr = (char *) gxemul_hw_map.videoram; |
} |
*(addr + GXEMUL_HALT_OFFSET) = '\0'; |
} |
/** Gxemul specific interrupt exception handler. |
* |
* Determines sources of the interrupt from interrupt controller and |
* calls high-level handlers for them. |
* |
* @param exc_no Interrupt exception number. |
* @param istate Saved processor state. |
*/ |
void gxemul_irq_exception(int exc_no, istate_t *istate) |
{ |
uint32_t sources = gxemul_irqc_get_sources(); |
int i; |
for (i = 0; i < GXEMUL_IRQC_MAX_IRQ; i++) { |
if (sources & (1 << i)) { |
irq_t *irq = irq_dispatch_and_lock(i); |
if (irq) { |
/* The IRQ handler was found. */ |
irq->handler(irq, irq->arg); |
spinlock_unlock(&irq->lock); |
} else { |
/* Spurious interrupt.*/ |
dprintf("cpu%d: spurious interrupt (inum=%d)\n", |
CPU->id, i); |
} |
} |
} |
} |
/** Returns address of framebuffer device. |
* |
* @return Address of framebuffer device. |
*/ |
uintptr_t gxemul_get_fb_address(void) |
{ |
return (uintptr_t) GXEMUL_FB; |
} |
/** @} |
*/ |
/branches/tracing/kernel/arch/arm32/src/start.S |
---|
40,30 → 40,12 |
mrs r3, cpsr |
bic r3, r3, #0x1f |
orr r3, r3, #0x13 |
msr cpsr_c, r3 |
msr cpsr_c, r3 |
ldr sp, =temp_stack |
cmp r2, #0 |
beq bootinfo_end |
ldr r3, =bootinfo |
bootinfo_loop: |
ldr r4, [r1] |
str r4, [r3] |
add r1, r1, #4 |
add r3, r3, #4 |
add r2, r2, #-4 |
cmp r2, #0 |
bne bootinfo_loop |
bootinfo_end: |
bl arch_pre_main |
bl main_bsp |
.space TEMP_STACK_SIZE |
74,4 → 56,3 |
supervisor_sp: |
.space 4 |