diff --git a/alloc.ccp b/alloc.ccp index 79b819c..15501f1 100644 --- a/alloc.ccp +++ b/alloc.ccp @@ -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): diff --git a/kernel.hhp b/kernel.hhp index f0214b0..093a72c 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -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): diff --git a/mips/arch.ccp b/mips/arch.ccp index 374971f..df773fc 100644 --- a/mips/arch.ccp +++ b/mips/arch.ccp @@ -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 diff --git a/mips/arch.hhp b/mips/arch.hhp index 21afc14..9e7eb84 100644 --- a/mips/arch.hhp +++ b/mips/arch.hhp @@ -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": diff --git a/mips/init.ccp b/mips/init.ccp index 9339c21..58505bd 100644 --- a/mips/init.ccp +++ b/mips/init.ccp @@ -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") diff --git a/mips/interrupts.ccp b/mips/interrupts.ccp index 6fca975..59a5f45 100644 --- a/mips/interrupts.ccp +++ b/mips/interrupts.ccp @@ -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 diff --git a/mips/jz4730.hhp b/mips/jz4730.hhp index a752554..3ad0a78 100644 --- a/mips/jz4730.hhp +++ b/mips/jz4730.hhp @@ -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 -// 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 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 ():