aboutsummaryrefslogtreecommitdiff
path: root/kernel/util
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/util')
-rw-r--r--kernel/util/lock.c20
-rw-r--r--kernel/util/mutex.c110
-rw-r--r--kernel/util/status.c133
-rw-r--r--kernel/util/time.c76
4 files changed, 339 insertions, 0 deletions
diff --git a/kernel/util/lock.c b/kernel/util/lock.c
new file mode 100644
index 0000000..c9fe654
--- /dev/null
+++ b/kernel/util/lock.c
@@ -0,0 +1,20 @@
+#include <cpu.h>
+#include <cpu/atomic/swap.h>
+#include <util/mutex.h>
+#include <util/lock.h>
+
+void lock(struct Lock* l)
+{
+ unsigned long mode = getmode() & 0x1F;
+ if (mode == 0x10) {
+ sys1(SYS_LOCK, l);
+ }
+}
+
+void unlock(struct Lock* l)
+{
+ unsigned long mode = getmode() & 0x1F;
+ if (mode == 0x10) {
+ sys1(SYS_UNLOCK, l);
+ }
+}
diff --git a/kernel/util/mutex.c b/kernel/util/mutex.c
new file mode 100644
index 0000000..8e85f8f
--- /dev/null
+++ b/kernel/util/mutex.c
@@ -0,0 +1,110 @@
+#include <cpu.h>
+#include <drivers/uart.h>
+#include <util/mutex.h>
+#include <util/lock.h>
+#include <globals.h>
+
+void mutex_init(void)
+{
+ for (unsigned long m = 0; m < MAX_MUTEXS; m++) {
+ mutexs[m].pid = 0;
+ mutexs[m].addr = 0;
+ mutex_entries[m].value = &mutexs[m];
+ mutex_entries[m].entry_type = VALUE_ENTRY;
+ mutex_entries[m].next = &mutex_entries[m+1];
+ }
+ // Initialize Free Mutexs
+ mutex_manager.free.start.value = 0;
+ mutex_manager.free.start.next = &mutex_entries[0];
+ mutex_manager.free.start.entry_type = START_ENTRY;
+ mutex_manager.free.end.value = 0;
+ mutex_manager.free.end.next = &mutex_entries[MAX_MUTEXS-1];
+ mutex_entries[MAX_MUTEXS-1].next = &mutex_manager.free.end;
+ mutex_manager.free.end.entry_type = END_ENTRY;
+ // Initialize In-use Mutexs
+ mutex_manager.used.start.value = 0;
+ mutex_manager.used.start.next = &mutex_manager.used.end;
+ mutex_manager.used.start.entry_type = START_ENTRY;
+ mutex_manager.used.end.value = 0;
+ mutex_manager.used.end.next = &mutex_manager.used.start;
+ mutex_manager.used.end.entry_type = END_ENTRY;
+}
+
+struct Mutex* create_mutex(void* addr)
+{
+ struct Entry* e = pop_from_queue(&mutex_manager.free);
+ if (e == 0)
+ return 0;
+ struct Mutex* m = e->value;
+ m->pid = 0;
+ m->addr = addr;
+ push_to_queue(e, &mutex_manager.used);
+ return e->value;
+}
+
+unsigned char delete_mutex(struct Mutex* m)
+{
+ struct Entry* entry = find_value(m, &mutex_manager.used);
+ if (entry == 0)
+ return 1;
+ // Remove it from the queue
+ struct Entry* theentry = remove_next_from_queue(entry);
+ // Add it to the free queue
+ prepend_to_queue(theentry, &mutex_manager.free);
+ return 0;
+}
+
+void uart_mutexes(void)
+{
+ struct Entry* entry = mutex_manager.used.start.next;
+ while (entry->entry_type == VALUE_ENTRY)
+ {
+ struct Mutex* m = entry->value;
+ uart_hex((unsigned long)m);
+ uart_char(' ');
+ uart_hex(m->pid);
+ uart_char(' ');
+ uart_hexn((unsigned long)m->addr);
+ entry = entry->next;
+ }
+ unsigned long count = 0;
+ entry = mutex_manager.free.start.next;
+ while (entry->entry_type == VALUE_ENTRY) {
+ count++;
+ entry = entry->next;
+ }
+ uart_hexn(count);
+}
+
+void lock_mutex(struct Mutex* m)
+{
+ struct Thread* rthread = scheduler.rthread;
+ unsigned long rpid = rthread->pid;
+ unsigned long mode = getmode() & 0x1F;
+ if (mode == 0x10) {
+ // Find this mutex
+ struct Entry* mentry = find_value(m, &mutex_manager.used);
+ // If it is not a managed mutex, break away
+ if (mentry == 0)
+ return;
+ struct Entry* entry = mutex_manager.used.start.next;
+ // Ensure this thread locks all mutexs sequentially
+ // To avoid a deadlock
+ while (entry->entry_type == VALUE_ENTRY) {
+ struct Mutex* vmutex = entry->value;
+ // If this thread had locked it
+ // Toggle the lock to prevent deadlock
+ if (vmutex->pid == rpid) {
+ sys1(SYS_UNLOCK, vmutex);
+ sys1(SYS_LOCK, vmutex);
+ }
+ entry = entry->next;
+ }
+ sys1(SYS_LOCK, m);
+ }
+}
+
+void unlock_mutex(struct Mutex* m)
+{
+ unlock((struct Lock*)m);
+}
diff --git a/kernel/util/status.c b/kernel/util/status.c
new file mode 100644
index 0000000..456e89d
--- /dev/null
+++ b/kernel/util/status.c
@@ -0,0 +1,133 @@
+#include <cpu.h>
+#include <globals.h>
+#include <graphics/lfb.h>
+#include <symbols.h>
+#include <lib/strings.h>
+#include <lib/kmem.h>
+#include <sys/core.h>
+#include <sys/schedule.h>
+#include <util/mutex.h>
+#include <util/status.h>
+#include <util/time.h>
+
+void output_irq_status(void)
+{
+ // Basic IRQ
+ unsigned long ib_val = load32(IRQ_BASIC_ENABLE);
+ // IRQ 1
+ unsigned long i1_val = load32(IRQ_ENABLE1);
+ // IRQ 2
+ unsigned long i2_val = load32(IRQ_ENABLE2);
+ // FIQ
+ unsigned long f_val = load32(FIQ_CONTROL);
+
+ // Check GPU Interrupt Routing
+ unsigned long g_val = load32(GPU_INTERRUPTS_ROUTING);
+ draw_cletter(0, 1, (g_val & 0b11) + 0x30, 0x1EA1A1);
+ draw_cletter(1, 1, ((g_val >> 2) & 0b11) + 0x30, 0x1EA1A1);
+
+ draw_chex32(4, 1, ib_val, 0x1EA1A1);
+ draw_chex32(4+9, 1, i1_val, 0x1EA1A1);
+ draw_chex32(4+9*2, 1, i2_val, 0x1EA1A1);
+ draw_chex32(4+9*3, 1, f_val, 0x1EA1A1);
+
+ // Check UART IRQ
+ if (i2_val & (1<<25)) {
+ draw_cstring(0, 2, "UART", 0x00FF00);
+ } else if (f_val == 57) {
+ draw_cstring(0, 2, "UART", 0xFFA500);
+ } else {
+ draw_cstring(0, 2, "UART", 0xFF0000);
+ }
+
+ // Check UART IRQ
+ if (i1_val & (1<<0)) {
+ draw_cstring(5, 2, "STIMERCMP", 0x00FF00);
+ } else if (f_val == 1) {
+ draw_cstring(5, 2, "STIMERCMP", 0xFFA500);
+ } else {
+ draw_cstring(5, 2, "STIMERCMP", 0xFF0000);
+ }
+
+ if (load32(CORE0_TIMER_IRQCNTL) & 0xF) {
+ draw_cstring(4+9+2, 2, "LTIMER", 0x00FF00);
+ } else if (load32(CORE0_TIMER_IRQCNTL) & 0xF0) {
+ draw_cstring(4+9+2, 2, "LTIMER", 0xFFA500);
+ } else {
+ draw_cstring(4+9+2, 2, "LTIMER", 0xFF0000);
+ }
+}
+
+void time_status(void)
+{
+ // Report Sys Timer Stataus
+ unsigned long systime;
+ draw_string(0, 8, "Sys Timer Status");
+ systime = *(volatile unsigned long*)SYS_TIMER_CS;
+ draw_hex32(17, 8, systime);
+ draw_string(17+8, 8, ":");
+ unsigned long long tval = get_time();
+ draw_hex32(17+8, 8, (tval >> 32));
+ draw_hex32(17+8+8, 8, tval);
+ systime = *(volatile unsigned long*)SYS_TIMER_C0;
+ draw_hex32(19+14+8+1, 8, systime);
+ draw_string(19+14+9+8, 8, "|");
+ draw_string(19+14+18, 8, " ");
+ draw_u10(19+14+18, 8, ((unsigned long)tval)/1000000);
+}
+
+void status(void)
+{
+ // OS Info
+ draw_cstring(7, 0, "v", 0x00FFFF);
+ draw_cstring(0, 0, os_name, 0xFF0000);
+ draw_cstring(8, 0, os_info_v, 0x00FFFF);
+
+ // GPU IRQ Statuses
+ output_irq_status();
+
+ // Timer Status
+ draw_cstring(0, 3, "TIMER", 0x00FF00);
+ // Output the frequency
+ draw_string(6, 3, "@");
+ unsigned long frq = read_cntfrq()/1000;
+ unsigned long fs_len = draw_u10(8, 3, frq) + 1;
+ draw_string(8+fs_len, 3, "kHz");
+ // Output the value
+ unsigned long v = read_cntv_tval();
+ unsigned long vs_len = draw_u10(8+fs_len+4, 3, v)+1;
+ draw_string(8+fs_len+4 +vs_len, 3, " ");
+ draw_letter(8+fs_len+4 +vs_len+1, 3, '|');
+ draw_hex32(8+fs_len+7+vs_len, 3, v);
+
+ // Video Status
+ draw_cstring(0, 4, "VIDEO", 0x00FF00);
+ unsigned long gw_len = draw_u10(6, 4, gwidth);
+ unsigned long gh_len = draw_u10(6+gw_len+1, 4, gheight) + 1;
+ draw_letter(6+gw_len, 4, 'x');
+ if(gisrgb)
+ draw_string(6+gw_len+gh_len + 1, 4, "RGB");
+ else
+ draw_string(6+gw_len+gh_len + 1, 4, "BGR");
+
+ // Core Stacks
+ draw_string(0, 5, "SVC IRQ FIQ User/SYS\n");
+ unsigned long sp = (unsigned long)getsvcstack();
+ draw_hex32(0, 6, sp);
+ sp = (unsigned long)getirqstack();
+ draw_hex32(9, 6, sp);
+ sp = (unsigned long)getfiqstack();
+ draw_hex32(9*2, 6, sp);
+ sp = (unsigned long)getsysstack();
+ draw_hex32(9*3, 6, sp);
+
+ // Report Core that updated status
+ unsigned long coren;
+ asm volatile (
+ "mrc p15, #0, %0, c0, c0, #5\n"
+ "and %0, %0, #3" : "=r"(coren) :: "cc");
+ draw_string(0, 7, "Status Updated by Core #");
+ draw_hex32(24, 7, coren);
+
+ time_status();
+}
diff --git a/kernel/util/time.c b/kernel/util/time.c
new file mode 100644
index 0000000..abb9c8d
--- /dev/null
+++ b/kernel/util/time.c
@@ -0,0 +1,76 @@
+#include <symbols.h>
+#include <sys/core.h>
+
+// CCNT - Cycle Timer (Close to ns resolution)
+
+void routing_core0cntv_to_core0fiq(void)
+{
+ store32(0x80, CORE0_TIMER_IRQCNTL);
+}
+
+void routing_core0cntv_to_core0irq(void)
+{
+ store32(0x08, CORE0_TIMER_IRQCNTL);
+}
+
+unsigned long read_core0timer_pending(void)
+{
+ unsigned long tmp;
+ tmp = load32(CORE0_IRQ_SOURCE);
+ return tmp;
+}
+
+unsigned long long read_cntvct(void)
+{
+ unsigned long long val;
+ asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (val));
+ return (val);
+}
+
+unsigned long long read_cntvoff(void)
+{
+ unsigned long long val;
+ asm volatile("mrrc p15, 4, %Q0, %R0, c14" : "=r" (val));
+ return (val);
+}
+
+unsigned long read_cntv_tval(void)
+{
+ unsigned long val;
+ asm volatile ("mrc p15, 0, %0, c14, c3, 0" : "=r"(val) );
+ return val;
+}
+
+void write_cntv_tval(unsigned long val)
+{
+ asm volatile ("mcr p15, 0, %0, c14, c3, 0" :: "r"(val) );
+ return;
+}
+
+unsigned long read_cntfrq(void)
+{
+ unsigned long val;
+ asm volatile ("mrc p15, 0, %0, c14, c0, 0" : "=r"(val) );
+ return val;
+}
+
+unsigned long long get_time(void)
+{
+ union {
+ unsigned long long tval;
+ struct {
+ unsigned long high;
+ unsigned long low;
+ } tvalb;
+ } t;
+ t.tvalb.low = *(unsigned long*)SYS_TIMER_CLO;
+ t.tvalb.high = *(unsigned long*)SYS_TIMER_CHI;
+ return t.tval;
+}
+
+void wait_msec(unsigned int n)
+{
+ unsigned long start = *(volatile unsigned long*)SYS_TIMER_CHI;
+ while (*(volatile unsigned long*)SYS_TIMER_CHI - start < n)
+ asm volatile("nop");
+}