/branches/arm/kernel/arch/arm32/include/drivers/gxemul.h |
---|
41,6 → 41,18 |
void gxemul_kbd_release(void); |
void gxemul_kbd_grab(void); |
#define GXEMUL_IRQC_MAX_IRQ 8 |
inline uint32_t gxemul_irqc_get_sources(void); |
inline void gxemul_irqc_mask(uint32_t irq); |
inline void gxemul_irqc_unmask(uint32_t irq); |
#define GXEMUL_TIMER_FREQ 2 |
void gxemul_timer_irq_init(void); |
void gxemul_timer_start(uint32_t frequency); |
#endif |
/** @} |
/branches/arm/kernel/arch/arm32/src/exception.c |
---|
38,8 → 38,8 |
#include <arch/memstr.h> |
#include <arch/regutils.h> |
#include <interrupt.h> |
#include <arch/drivers/gxemul.h> |
#define PREFETCH_OFFSET 0x8 |
#define BRANCH_OPCODE 0xea000000 |
#define LDR_OPCODE 0xe59ff000 |
47,21 → 47,7 |
#define EXC_VECTORS_SIZE 0x20 |
#define EXC_VECTORS 0x8 |
/* GXEmul interrupt controller macros |
TODO might go to drivers/ together with servicing functions |
*/ |
/* IRQ Controller device is added in a special premium gxemul |
* edition at www.ms.mff.cuni.cz/~stepp3am/mygxemul-0.4.4.1.tar.gz |
* :) |
*/ |
#define IRQ_CONTROLLER_CAUSE 0x0000000016000000 |
#define IRQ_CONTROLLER_MAX_IRQ 8 |
/* IRQs */ |
#define CONSOLE_IRQ 2 |
#define TIMER_IRQ 4 |
#define SAVE_REGS_TO_STACK \ |
asm("stmfd sp!, {r0-r12, sp, lr}"); \ |
asm("mrs r14, spsr"); \ |
157,15 → 143,22 |
*/ |
static void irq_exception(int exc_no, istate_t* istate) |
{ |
/* TODO this will call interrupt dispatching routine |
* |
*/ |
uint32_t sources = *(uint32_t*) IRQ_CONTROLLER_CAUSE; |
uint32_t sources = gxemul_irqc_get_sources(); |
int i = 0; |
int noirq = 1; |
for (; i < IRQ_CONTROLLER_MAX_IRQ; i++) { |
for (; 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.*/ |
aux_printf("cpu%d: spurious interrupt (inum=%d)\n", CPU->id, i); |
} |
} |
} |
/* TODO remove after testing the above code |
noirq = 0; |
if (i == CONSOLE_IRQ) { |
char readchar = *(char*)0x10000000; |
179,7 → 172,7 |
} |
else if (i == TIMER_IRQ) { |
aux_printf("\n.\n"); |
/* acknowledge */ |
//acknowledge |
*(uint32_t*)0x15000110 = 0; |
} |
} |
186,7 → 179,7 |
} |
if (noirq) |
aux_puts("IRQ exception without source\n"); |
aux_puts("IRQ exception without source\n");*/ |
} |
/** Fills exception vectors with appropriate exception handlers. |
215,9 → 208,15 |
(unsigned*)EXC_FIQ_VEC); |
} |
/** Registers exceptions and their handlers to kernel exception dispatcher. */ |
/** Initializes exception handling. |
* |
* Installs low-level exception handlers and then registers |
* exceptions and their handlers to kernel exception dispatcher. |
*/ |
void exception_init(void) |
{ |
install_exception_handlers(); |
exc_register(EXC_IRQ, "interrupt", (iroutine) irq_exception); |
/* TODO add next */ |
} |
232,6 → 231,10 |
); |
asm("ldr sp, =irq_stack"); |
current_status_reg_control_write( cspr); |
/* TODO if you want to test other exceptions than IRQ, |
make stack analogous to irq_stack (in start.S), |
and then set stack pointer here */ |
} |
/** @} |
/branches/arm/kernel/arch/arm32/src/arm32.c |
---|
42,6 → 42,8 |
#include "aux_print/printf.h" |
#include <print.h> |
#include <config.h> |
#include <interrupt.h> |
bootinfo_t bootinfo; |
void arch_pre_main(void) |
59,17 → 61,8 |
// aux_printf("%L, %d\n", bootinfo.tasks[i].addr, bootinfo.tasks[i].size); |
} |
/* TODO this code just setups irq testing bed |
*/ |
/* TODO this code just setups irq testing bed */ |
setup_exception_stacks(); |
exception_init(); |
install_exception_handlers(); |
interrupts_enable(); |
/* activate timer interrupts */ |
*(uint32_t*)0x15000100 = 1; |
while(1) ; |
} |
#include <ddi/irq.h> |
77,16 → 70,25 |
{ |
aux_printf("arch_pre_mm_init\n"); |
/* It is not assumed by default */ |
interrupts_disable(); |
/* Initialize dispatch table */ |
exception_init(); |
} |
void arch_post_mm_init(void) |
{ |
aux_printf("arch_post_mm_init\n"); |
// irq_init(8, 8); /// needs malloc ... so after mm init |
// console_init(device_assign_devno()); // need hash table of irq ... so after irq_init |
interrupt_init(); // needs malloc ... so after mm init |
console_init(device_assign_devno()); // need hash table of irq ... so after irq_init |
/* TODO */ |
interrupts_enable(); |
while(1); |
} |
void arch_post_cpu_init(void) |
/branches/arm/kernel/arch/arm32/src/interrupt.c |
---|
1,5 → 1,5 |
/* |
* Copyright (c) 2007 Petr Stepan, Michal Kebrt |
* Copyright (c) 2007 Petr Stepan |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
34,9 → 34,10 |
#include <arch/asm.h> |
#include <arch/regutils.h> |
#include <ddi/irq.h> |
#include <arch/drivers/gxemul.h> |
#include <interrupt.h> |
#define IRQ_COUNT 8 |
85,9 → 86,17 |
return current_status_reg_read(); |
} |
void interrupt_init(void) { |
/** Initialize basic tables for exception dispatching |
* and starts the timer. |
*/ |
void interrupt_init(void) |
{ |
irq_init(IRQ_COUNT, IRQ_COUNT); |
gxemul_timer_irq_init(); |
gxemul_timer_start(GXEMUL_TIMER_FREQ); |
} |
/** @} |
*/ |
/branches/arm/kernel/arch/arm32/src/drivers/gxemul.c |
---|
1,5 → 1,5 |
/* |
* Copyright (c) 2005-2007 Ondrej Palkovsky, Michal Kebrt |
* Copyright (c) 2005-2007 Ondrej Palkovsky, Michal Kebrt, Petr Stepan |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
39,14 → 39,25 |
#include <console/console.h> |
#include <sysinfo/sysinfo.h> |
#include <print.h> |
#include <ddi/device.h> |
/** Address of devices. */ |
#define GXEMUL_VIDEORAM 0x10000000 |
#define GXEMUL_KBD_ADDRESS 0x10000000 |
#define GXEMUL_KBD_IRQ 0 |
#define GXEMUL_RTC 0x15000000 |
#define GXEMUL_RTC_FREQ 0x15000100 |
#define GXEMUL_RTC_ACK 0x15000110 |
#define GXEMUL_IRQC 0x16000000 |
#define GXEMUL_IRQC_MASK 0x16000004 |
#define GXEMUL_IRQC_UNMASK 0x16000008 |
/** IRQs */ |
#define GXEMUL_KBD_IRQ 2 |
#define GXEMUL_TIMER_IRQ 4 |
static chardev_t console; |
static irq_t gxemul_irq; |
static irq_t gxemul_timer_irq; |
static void gxemul_write(chardev_t *dev, const char ch); |
static void gxemul_enable(chardev_t *dev); |
70,6 → 81,7 |
void gxemul_enable(chardev_t *dev) |
{ |
// cp0_unmask_int(GXEMUL_KBD_IRQ); |
gxemul_irqc_unmask(GXEMUL_KBD_IRQ); |
} |
/* Called from getc(). */ |
76,6 → 88,7 |
void gxemul_disable(chardev_t *dev) |
{ |
// cp0_mask_int(GXEMUL_KBD_IRQ); |
gxemul_irqc_mask(GXEMUL_KBD_IRQ); |
} |
/** Read character using polling, assume interrupts disabled */ |
108,7 → 121,8 |
ch = '\n'; |
if (ch == 0x7f) |
ch = '\b'; |
chardev_push_character(&console, ch); |
//chardev_push_character(&console, ch); |
printf("%c", ch); |
} |
} |
137,7 → 151,7 |
} |
/* Return console object representing msim console */ |
/** Return console object representing msim console */ |
void gxemul_console(devno_t devno) |
{ |
chardev_initialize("msim_console", &console, &gxemul_ops); |
152,6 → 166,7 |
irq_register(&gxemul_irq); |
// cp0_unmask_int(GXEMUL_KBD_IRQ); |
gxemul_irqc_unmask(GXEMUL_KBD_IRQ); |
sysinfo_set_item_val("kbd", NULL, true); |
sysinfo_set_item_val("kbd.devno", NULL, devno); |
159,5 → 174,87 |
sysinfo_set_item_val("kbd.address.virtual", NULL, GXEMUL_KBD_ADDRESS); |
} |
/** Return the mask of active interrupts. */ |
inline uint32_t gxemul_irqc_get_sources(void) |
{ |
return *(uint32_t*) GXEMUL_IRQC; |
} |
/** Masks interrupt. |
* |
* @param irq interrupt number |
*/ |
inline void gxemul_irqc_mask(uint32_t irq) |
{ |
*(uint32_t*) GXEMUL_IRQC_MASK = irq; |
} |
/** Unmasks interrupt. |
* |
* @param irq interrupt number |
*/ |
inline void gxemul_irqc_unmask(uint32_t irq) |
{ |
*(uint32_t*) GXEMUL_IRQC_UNMASK = irq; |
} |
/** Starts gxemul Real Time Clock device, which asserts regular interrupts. |
* |
* @param frequency interrupts frequency (0 disables RTC) |
*/ |
void gxemul_timer_start(uint32_t frequency) |
{ |
*(uint32_t*) GXEMUL_RTC_FREQ = frequency; |
} |
static irq_ownership_t gxemul_timer_claim(void) |
{ |
return IRQ_ACCEPT; |
} |
static void gxemul_timer_irq_handler(irq_t *irq, void *arg, ...) |
{ |
/* TODO time drifts ?? |
unsigned long drift; |
drift = cp0_count_read() - nextcount; |
while (drift > cp0_compare_value) { |
drift -= cp0_compare_value; |
CPU->missed_clock_ticks++; |
} |
nextcount = cp0_count_read() + cp0_compare_value - drift; |
cp0_compare_write(nextcount); |
*/ |
/* |
* We are holding a lock which prevents preemption. |
* Release the lock, call clock() and reacquire the lock again. |
*/ |
spinlock_unlock(&irq->lock); |
//clock(); |
puts(" "); |
spinlock_lock(&irq->lock); |
/* TODO what's that? * |
if (virtual_timer_fnc != NULL) |
virtual_timer_fnc(); |
*/ |
} |
/** |
* Initializes and registers timer interrupt handler. |
*/ |
void gxemul_timer_irq_init() |
{ |
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); |
} |
/** @} |
*/ |
/branches/arm/kernel/arch/arm32/src/start.S |
---|
56,7 → 56,7 |
bl arch_pre_main |
# bl main_bsp |
bl main_bsp |
b halt |