1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-07-04 23:21:59 +03:00

use interrupt controller

This commit is contained in:
Bas Wijnen 2009-06-25 23:09:42 +02:00
parent 7c5ea99cba
commit c2dbe6e1e9
7 changed files with 146 additions and 85 deletions

View File

@ -41,9 +41,9 @@ unsigned raw_zalloc ():
FreePage *ret = zero_pages FreePage *ret = zero_pages
if !ret: if !ret:
ret = junk_pages ret = junk_pages
for unsigned i = 1; i < (PAGE_SIZE >> 2); ++i:
((unsigned *)ret)[i] = 0
junk_pages = ret->next junk_pages = ret->next
for unsigned i = 0; i < (PAGE_SIZE >> 2); ++i:
((unsigned *)ret)[i] = 0
else: else:
zero_pages = ret->next zero_pages = ret->next
ret->next = NULL ret->next = NULL

View File

@ -19,6 +19,9 @@
#ifndef _KERNEL_HH #ifndef _KERNEL_HH
#define _KERNEL_HH #define _KERNEL_HH
// Number of clock interrupts per second.
#define HZ 10
// Include definitions which are shared with user space. // Include definitions which are shared with user space.
#define __KERNEL #define __KERNEL
#include "iris.h" #include "iris.h"
@ -207,7 +210,6 @@ bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write)
void Memory_arch_unmap (Memory *mem, Page *page, unsigned address) void Memory_arch_unmap (Memory *mem, Page *page, unsigned address)
Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable) Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable)
void Page_arch_update_mapping (Page *page) void Page_arch_update_mapping (Page *page)
void arch_invoke ()
void arch_register_interrupt (unsigned num, Receiver *r) void arch_register_interrupt (unsigned num, Receiver *r)
bool Memory::map (Page *page, unsigned address, bool write): bool Memory::map (Page *page, unsigned address, bool write):

View File

@ -132,17 +132,6 @@ void Memory_arch_init (Memory *mem):
mem->arch.directory = NULL mem->arch.directory = NULL
mem->arch.shadow = NULL mem->arch.shadow = NULL
static void flush_tlb (unsigned asid):
for unsigned tlb = 1; tlb < 32; ++tlb:
cp0_set (CP0_INDEX, tlb)
__asm__ volatile ("tlbr")
unsigned hi
cp0_get (CP0_ENTRY_HI, hi)
if (hi & 0x1f) == asid:
// Set asid to 0, which is only used by the idle task.
cp0_set (CP0_ENTRY_HI, 0x2000 * tlb)
__asm__ volatile ("tlbwi")
void Memory_arch_free (Memory *mem): void Memory_arch_free (Memory *mem):
while mem->arch.first_page_table: while mem->arch.first_page_table:
mem->unmap (mem->arch.first_page_table->first_page->page, mem->arch.first_page_table->first_page->mapping) mem->unmap (mem->arch.first_page_table->first_page->page, mem->arch.first_page_table->first_page->mapping)
@ -322,61 +311,6 @@ void Page_arch_update_mapping (Page *page):
as->arch.directory[de][te] = t as->arch.directory[de][te] = t
tlb_reset (p->mapping & ~1, as->arch.asid, t) tlb_reset (p->mapping & ~1, as->arch.asid, t)
void arch_invoke ():
Capability *target
bool wait
Thread *caller = current
target = caller->address_space->find_capability (caller->arch.v0, &wait)
if !target:
// TODO: there must be no action here. This is just because the rest doesn't work yet.
dbg_send (3, 2)
//dbg_send (caller->arch.v0)
schedule ()
// Calling an invalid capability always fails.
caller->arch.v0 = 0
else:
if wait:
caller->wait ()
Capability::Context c
c.cap[0] = caller->address_space->find_capability (caller->arch.a0, &c.copy[0])
c.cap[1] = caller->address_space->find_capability (caller->arch.a1, &c.copy[1])
c.cap[2] = caller->address_space->find_capability (caller->arch.a2, &c.copy[2])
c.cap[3] = caller->address_space->find_capability (caller->arch.a3, &c.copy[3])
c.data[0] = caller->arch.t0
c.data[1] = caller->arch.t1
c.data[2] = caller->arch.t2
c.data[3] = caller->arch.t3
caller->arch.v0 = target->invoke (&c) ? 1 : 0
if !current:
if caller != &idle && (caller->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING:
current = caller
else:
schedule ()
if !current:
current = &idle
if caller != current:
if (Memory *)asids[current->address_space->arch.asid] != current->address_space:
if asids[0]:
current->address_space->arch.asid = asids[0]
asids[0] = asids[asids[0]]
else:
static unsigned random = 1
current->address_space->arch.asid = random
// Overwrite used asid, so flush those values from tlb.
flush_tlb (random)
++random
if random >= 64:
random = 1
asids[current->address_space->arch.asid] = (unsigned)current->address_space
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
directory = current->address_space->arch.directory
unsigned status
cp0_get (CP0_STATUS, status)
status &= 0x0fffffff
if current->flags & THREAD_FLAG_PRIV:
status |= 0x10000000
cp0_set (CP0_STATUS, status | 0x13)
void arch_register_interrupt (unsigned num, Receiver *r): void arch_register_interrupt (unsigned num, Receiver *r):
arch_interrupt_receiver[num] = r arch_interrupt_receiver[num] = r
unsigned status unsigned status

View File

@ -106,6 +106,8 @@
#ifndef ASM #ifndef ASM
void flush_tlb (unsigned asid)
struct Thread_arch: struct Thread_arch:
unsigned at, v0, v1, a0, a1, a2, a3 unsigned at, v0, v1, a0, a1, a2, a3
unsigned t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 unsigned t0, t1, t2, t3, t4, t5, t6, t7, t8, t9
@ -140,7 +142,7 @@ struct Memory_arch:
// Pointers to Memory when asid is taken, index of next free, or 0, if free. // Pointers to Memory when asid is taken, index of next free, or 0, if free.
// asid[0] is used as index to first free asid. // asid[0] is used as index to first free asid.
EXTERN unsigned asids[64] EXTERN unsigned asids[64]
EXTERN Receiver *arch_interrupt_receiver[8] EXTERN Receiver *arch_interrupt_receiver[32]
// Functions which can be called from assembly must not be mangled. // Functions which can be called from assembly must not be mangled.
extern "C": extern "C":

View File

@ -207,7 +207,7 @@ void init ():
junk_pages = (FreePage *)(((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK) junk_pages = (FreePage *)(((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK)
FreePage *p, *next FreePage *p, *next
unsigned count = 1 unsigned count = 1
for p = junk_pages, next = p; (unsigned)next - 0x80000000 < (1 << 27); p = next, next = (FreePage *)((unsigned)p + ~PAGE_MASK + 1): for p = junk_pages, next = p; (unsigned)next - 0x80000000 < (1 << 27); p = next, next = (FreePage *)((unsigned)p + PAGE_SIZE):
p->next = next p->next = next
++count ++count
p->next = NULL p->next = NULL
@ -228,15 +228,47 @@ void init ():
top_memory.arch.directory = NULL top_memory.arch.directory = NULL
top_memory.arch.asid = 0 top_memory.arch.asid = 0
// Record all asids as unused.
for unsigned i = 0; i < 63; ++i: for unsigned i = 0; i < 63; ++i:
asids[i] = i + 1 asids[i] = i + 1
asids[63] = 0 asids[63] = 0
// Set up initial threads.
init_threads () init_threads ()
// Say we're handling an exception. Don't enable interrupts; this will happen when handlers are registered. // Set up the rest of the hardware (copied from Linux).
// Since we're going to enter the idle task, allow access to cp0. cpm_idle_mode ()
cp0_set (CP0_STATUS, 0x10000013) cpm_enable_cko1 ()
cpm_start_all ()
harb_set_priority (0x08)
dmac_enable_all_channels ()
harb_usb0_uhc ()
gpio_as_emc ()
gpio_as_uart0 ()
gpio_as_dma ()
gpio_as_eth ()
gpio_as_usb ()
gpio_as_lcd_master ()
gpio_as_msc ()
GPIO_GPDIR (GPIO_PWM0_PORT) |= 1 << GPIO_PWM0
GPIO_GPDR (GPIO_PWM0_PORT) |= 1 << GPIO_PWM0
GPIO_GPDIR (GPIO_USB_CLK_EN_PORT) |= 1 << GPIO_USB_CLK_EN
GPIO_GPDR (GPIO_USB_CLK_EN_PORT) |= 1 << GPIO_USB_CLK_EN
// Start the operating system timer.
unsigned latch = (JZ_EXTAL + (HZ>>1)) / HZ
ost_set_mode (0, OST_TCSR_UIE | OST_TCSR_CKS_EXTAL)
ost_set_reload (0, latch)
ost_set_count (0, latch)
ost_enable_channel (0)
// Unset all interrupt handlers.
for unsigned i = 0; i < 32; ++i:
arch_interrupt_receiver[i] = NULL
// Say we're handling an exception. Since we're going to enter the idle task, allow access to cp0.
// All interrupts enter the CPU through the interrupt controller at IP2, so enable that.
cp0_set (CP0_STATUS, 0x10000413)
// Done; return to user space (the idle task). // Done; return to user space (the idle task).
__asm__ volatile ("eret") __asm__ volatile ("eret")

View File

@ -43,16 +43,16 @@ Thread *tlb_refill ():
__asm__ volatile ("tlbwr") __asm__ volatile ("tlbwr")
return current return current
static void timer_interrupt ():
/// An interrupt which is not an exception has occurred. /// An interrupt which is not an exception has occurred.
Thread *interrupt (): Thread *interrupt ():
panic (0x88877722, "Interrupt") panic (0x88877722, "Interrupt")
unsigned cause, status unsigned ipr = INTC_IPR
cp0_get (CP0_CAUSE, cause) for unsigned i = 1; i < 32; ++i:
cp0_get (CP0_STATUS, status) if ipr & (1 << i):
for unsigned i = 0; i < 8; ++i:
if cause & (1 << (i + 8)):
// Disable the interrupt while handling it. // Disable the interrupt while handling it.
status &= ~(1 << (i + 8)) intc_mask_irq (i)
// Send message to interrupt handler. // Send message to interrupt handler.
if arch_interrupt_receiver[i]: if arch_interrupt_receiver[i]:
Capability::Context c Capability::Context c
@ -61,8 +61,78 @@ Thread *interrupt ():
c.cap[j] = NULL c.cap[j] = NULL
c.copy[j] = false c.copy[j] = false
arch_interrupt_receiver[i]->send_message (i, &c) arch_interrupt_receiver[i]->send_message (i, &c)
if ipr & 1:
ost_clear_uf (0)
intc_ack_irq (0)
timer_interrupt ()
return current return current
void flush_tlb (unsigned asid):
for unsigned tlb = 1; tlb < 32; ++tlb:
cp0_set (CP0_INDEX, tlb)
__asm__ volatile ("tlbr")
unsigned hi
cp0_get (CP0_ENTRY_HI, hi)
if (hi & 0x1f) == asid:
// Set asid to 0, which is only used by the idle task.
cp0_set (CP0_ENTRY_HI, 0x2000 * tlb)
__asm__ volatile ("tlbwi")
static void arch_invoke ():
Capability *target
bool wait
Thread *caller = current
target = caller->address_space->find_capability (caller->arch.v0, &wait)
if !target:
// TODO: there must be no action here. This is just because the rest doesn't work yet.
dbg_send (3, 2)
//dbg_send (caller->arch.v0)
schedule ()
// Calling an invalid capability always fails.
caller->arch.v0 = 0
else:
if wait:
caller->wait ()
Capability::Context c
c.cap[0] = caller->address_space->find_capability (caller->arch.a0, &c.copy[0])
c.cap[1] = caller->address_space->find_capability (caller->arch.a1, &c.copy[1])
c.cap[2] = caller->address_space->find_capability (caller->arch.a2, &c.copy[2])
c.cap[3] = caller->address_space->find_capability (caller->arch.a3, &c.copy[3])
c.data[0] = caller->arch.t0
c.data[1] = caller->arch.t1
c.data[2] = caller->arch.t2
c.data[3] = caller->arch.t3
caller->arch.v0 = target->invoke (&c) ? 1 : 0
if !current:
if caller != &idle && (caller->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING:
current = caller
else:
schedule ()
if !current:
current = &idle
if caller != current:
if (Memory *)asids[current->address_space->arch.asid] != current->address_space:
if asids[0]:
current->address_space->arch.asid = asids[0]
asids[0] = asids[asids[0]]
else:
static unsigned random = 1
current->address_space->arch.asid = random
// Overwrite used asid, so flush those values from tlb.
flush_tlb (random)
++random
if random >= 64:
random = 1
asids[current->address_space->arch.asid] = (unsigned)current->address_space
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
directory = current->address_space->arch.directory
unsigned status
cp0_get (CP0_STATUS, status)
status &= 0x0fffffff
if current->flags & THREAD_FLAG_PRIV:
status |= 0x10000000
cp0_set (CP0_STATUS, status | 0x13)
/// A general exception has occurred. /// A general exception has occurred.
Thread *exception (): Thread *exception ():
unsigned cause unsigned cause

View File

@ -21,10 +21,12 @@
#ifndef __JZ4730_HH__ #ifndef __JZ4730_HH__
#define __JZ4730_HH__ #define __JZ4730_HH__
// Main clock, for cpu, serial port, and with divisors for most other hardware
#define JZ_EXTAL 3686400 #define JZ_EXTAL 3686400
// RTC clock
#define RTC_CLOCK 32768
// Physical addresses are where they really are. // Physical addresses are where they really are.
// (In kernel space you need to add 0xa0000000 to see them unmapped uncached in kseg2.)
#define HARB_PHYSICAL 0x13000000 #define HARB_PHYSICAL 0x13000000
#define EMC_PHYSICAL 0x13010000 #define EMC_PHYSICAL 0x13010000
#define DMAC_PHYSICAL 0x13020000 #define DMAC_PHYSICAL 0x13020000
@ -59,6 +61,7 @@
#define KBC_PHYSICAL 0x10062000 #define KBC_PHYSICAL 0x10062000
#ifdef __KERNEL #ifdef __KERNEL
// In kernel space you need to add 0xa0000000 to see them unmapped uncached in kseg2.
#define HARB_BASE (HARB_PHYSICAL + 0xa0000000) #define HARB_BASE (HARB_PHYSICAL + 0xa0000000)
#define EMC_BASE (EMC_PHYSICAL + 0xa0000000) #define EMC_BASE (EMC_PHYSICAL + 0xa0000000)
#define DMAC_BASE (DMAC_PHYSICAL + 0xa0000000) #define DMAC_BASE (DMAC_PHYSICAL + 0xa0000000)
@ -93,8 +96,7 @@
#define KBC_BASE (KBC_PHYSICAL + 0xa0000000) #define KBC_BASE (KBC_PHYSICAL + 0xa0000000)
#else #else
#include <iris.h> // In user space, they just need a mapping.
// Base addresses are the place where the pages are mapped.
#define HARB_BASE 0x00000000 #define HARB_BASE 0x00000000
#define EMC_BASE 0x00001000 #define EMC_BASE 0x00001000
#define DMAC_BASE 0x00002000 #define DMAC_BASE 0x00002000
@ -129,6 +131,7 @@
#define KBC_BASE 0x0001f000 #define KBC_BASE 0x0001f000
// Map IO memory (requires a priviledged __my_thread capability). // Map IO memory (requires a priviledged __my_thread capability).
#include <iris.h>
static void __map_io (unsigned physical, unsigned mapping): static void __map_io (unsigned physical, unsigned mapping):
Capability page = memory_create_page (__my_memory) Capability page = memory_create_page (__my_memory)
// 0 means not cachable. // 0 means not cachable.
@ -138,7 +141,6 @@ static void __map_io (unsigned physical, unsigned mapping):
//drop (page) //drop (page)
#endif #endif
// Physical addresses are where they really are.
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0) #define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0)
#define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0) #define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0)
#define map_dmac() do { __map_io (DMAC_PHYSICAL, DMAC_BASE); } while (0) #define map_dmac() do { __map_io (DMAC_PHYSICAL, DMAC_BASE); } while (0)
@ -2822,6 +2824,25 @@ static __inline__ unsigned msc_calc_slow_clk_divisor (bool is_sd):
* GPIO * GPIO
***************************************************************************/ ***************************************************************************/
#define GPIO_PW_I_PORT 3
#define GPIO_PW_I 1
#define GPIO_PW_O_PORT 2
#define GPIO_PW_O 2
#define GPIO_LED_EN_PORT 2
#define GPIO_LED_EN 28
#define GPIO_DISP_OFF_N_PORT 2
#define GPIO_DISP_OFF_N 29
#define GPIO_PWM0_PORT 2
#define GPIO_PWM0 30
#define GPIO_RTC_IRQ_PORT 3
#define GPIO_RTC_IRQ 0
#define GPIO_USB_CLK_EN_PORT 0
#define GPIO_USB_CLK_EN 29
#define GPIO_CHARG_STAT_PORT 3
#define GPIO_CHARG_STAT 29
#define GPIO_TS_PENIRQ_PORT 2
#define GPIO_TS_PENIRQ 4
/* Init the alternate function pins */ /* Init the alternate function pins */
static __inline__ void gpio_as_ssi (): static __inline__ void gpio_as_ssi ():