1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-06-30 22:36:23 +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,12 +41,12 @@ unsigned raw_zalloc ():
FreePage *ret = zero_pages
if !ret:
ret = junk_pages
for unsigned i = 1; i < (PAGE_SIZE >> 2); ++i:
((unsigned *)ret)[i] = 0
junk_pages = ret->next
for unsigned i = 0; i < (PAGE_SIZE >> 2); ++i:
((unsigned *)ret)[i] = 0
else:
zero_pages = ret->next
ret->next = NULL
ret->next = NULL
return (unsigned)ret
void raw_pfree (unsigned page):

View File

@ -19,6 +19,9 @@
#ifndef _KERNEL_HH
#define _KERNEL_HH
// Number of clock interrupts per second.
#define HZ 10
// Include definitions which are shared with user space.
#define __KERNEL
#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)
Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable)
void Page_arch_update_mapping (Page *page)
void arch_invoke ()
void arch_register_interrupt (unsigned num, Receiver *r)
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.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):
while mem->arch.first_page_table:
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
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):
arch_interrupt_receiver[num] = r
unsigned status

View File

@ -106,6 +106,8 @@
#ifndef ASM
void flush_tlb (unsigned asid)
struct Thread_arch:
unsigned at, v0, v1, a0, a1, a2, a3
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.
// asid[0] is used as index to first free asid.
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.
extern "C":

View File

@ -207,7 +207,7 @@ void init ():
junk_pages = (FreePage *)(((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK)
FreePage *p, *next
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
++count
p->next = NULL
@ -228,15 +228,47 @@ void init ():
top_memory.arch.directory = NULL
top_memory.arch.asid = 0
// Record all asids as unused.
for unsigned i = 0; i < 63; ++i:
asids[i] = i + 1
asids[63] = 0
// Set up initial threads.
init_threads ()
// Say we're handling an exception. Don't enable interrupts; this will happen when handlers are registered.
// Since we're going to enter the idle task, allow access to cp0.
cp0_set (CP0_STATUS, 0x10000013)
// Set up the rest of the hardware (copied from Linux).
cpm_idle_mode ()
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).
__asm__ volatile ("eret")

View File

@ -43,16 +43,16 @@ Thread *tlb_refill ():
__asm__ volatile ("tlbwr")
return current
static void timer_interrupt ():
/// An interrupt which is not an exception has occurred.
Thread *interrupt ():
panic (0x88877722, "Interrupt")
unsigned cause, status
cp0_get (CP0_CAUSE, cause)
cp0_get (CP0_STATUS, status)
for unsigned i = 0; i < 8; ++i:
if cause & (1 << (i + 8)):
unsigned ipr = INTC_IPR
for unsigned i = 1; i < 32; ++i:
if ipr & (1 << i):
// Disable the interrupt while handling it.
status &= ~(1 << (i + 8))
intc_mask_irq (i)
// Send message to interrupt handler.
if arch_interrupt_receiver[i]:
Capability::Context c
@ -61,8 +61,78 @@ Thread *interrupt ():
c.cap[j] = NULL
c.copy[j] = false
arch_interrupt_receiver[i]->send_message (i, &c)
if ipr & 1:
ost_clear_uf (0)
intc_ack_irq (0)
timer_interrupt ()
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.
Thread *exception ():
unsigned cause

View File

@ -21,10 +21,12 @@
#ifndef __JZ4730_HH__
#define __JZ4730_HH__
// Main clock, for cpu, serial port, and with divisors for most other hardware
#define JZ_EXTAL 3686400
// RTC clock
#define RTC_CLOCK 32768
// 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 EMC_PHYSICAL 0x13010000
#define DMAC_PHYSICAL 0x13020000
@ -59,6 +61,7 @@
#define KBC_PHYSICAL 0x10062000
#ifdef __KERNEL
// In kernel space you need to add 0xa0000000 to see them unmapped uncached in kseg2.
#define HARB_BASE (HARB_PHYSICAL + 0xa0000000)
#define EMC_BASE (EMC_PHYSICAL + 0xa0000000)
#define DMAC_BASE (DMAC_PHYSICAL + 0xa0000000)
@ -93,8 +96,7 @@
#define KBC_BASE (KBC_PHYSICAL + 0xa0000000)
#else
#include <iris.h>
// Base addresses are the place where the pages are mapped.
// In user space, they just need a mapping.
#define HARB_BASE 0x00000000
#define EMC_BASE 0x00001000
#define DMAC_BASE 0x00002000
@ -129,6 +131,7 @@
#define KBC_BASE 0x0001f000
// Map IO memory (requires a priviledged __my_thread capability).
#include <iris.h>
static void __map_io (unsigned physical, unsigned mapping):
Capability page = memory_create_page (__my_memory)
// 0 means not cachable.
@ -138,7 +141,6 @@ static void __map_io (unsigned physical, unsigned mapping):
//drop (page)
#endif
// Physical addresses are where they really are.
#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_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
***************************************************************************/
#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 */
static __inline__ void gpio_as_ssi ():