mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-12-29 19:44:16 +02:00
use interrupt controller
This commit is contained in:
parent
7c5ea99cba
commit
c2dbe6e1e9
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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":
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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 ():
|
||||
|
Loading…
Reference in New Issue
Block a user