aboutsummaryrefslogtreecommitdiff
path: root/src/arm/PL1/kernel/interrupts.c
blob: 121d79c4ef4d28dffe990394f37766796cf1f812 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include "io.h"
#include "uart.h"
#include "svc_interface.h"
#include "armclock.h"
#include "scheduler.h"
/**
    @brief The undefined instruction interrupt handler
**/


void __attribute__((noreturn)) setup(void);

// from what I've heard, reset is never used on the Pi;
// in our case it should run once - when stage1 of the kernel
// jumps to stage2
void reset_handler(void)
{
  setup();
}

void undefined_instruction_vector(void)
{
  error("Undefined instruction occured");
}

uint32_t supervisor_call_handler(uint32_t regs[14])
{
  switch(regs[0]) {
  case UART_PUTCHAR:
    if (putchar_non_blocking(regs[1]))
      schedule_wait_for_output(regs, regs[1]);
    break;
  case UART_GETCHAR:
    {
      int c;
      if ((c = getchar_non_blocking()) == -1)
	schedule_wait_for_input(regs);

      regs[0] = c;
      break;
    }
  case UART_WRITE:
    error("UART_WRITE not implemented!!!!!");
    break;
  default:
    // perhaps we should kill the process now?
    error("unknown supervisor call type!!!!!");
  }

  return 0; // a dummy value
}

void abort_handler(void)
{
  // TODO maybe dump registers here?
  error("re-entered system due to data/prefetch abort");
}

void generic_handler(void)
{
  error("something weird happened");
}

void irq_handler(uint32_t regs[14])
{
  if (armclk_irq_pending())
    {
      write_SPSR(PL1_PSR);
      asm volatile("mov r0, %[context]\n\r"
		   "mov lr, %[return_func]\n\r"
		   "subs pc, lr, #0" ::
		   [context]"r" (regs),
		   [return_func]"r" (schedule_save_context) :
		   "memory");
    }
  else if (uart_irq_pending())
    {
      if (uart_recv_irq_pending())
	{
	  uart_clear_recv_irq();
	  scheduler_try_input();
	}
      if (uart_send_irq_pending())
	{
	  uart_clear_send_irq();
	  scheduler_try_output();
	}

      if (read_SPSR().fields.PSR_MODE_4_0 != MODE_USER)
	{
	  write_SPSR(PL1_PSR);
	  asm volatile("mov lr, %0\n\r"
		       "subs pc, lr, #0" ::
		       "r" (schedule) : "memory");
	}
    }
  else
    error("unknown irq");

  // important - don't allow this handler to return if irq came from
  // PL1 (likely supervisor, because we don't really use system) mode
}

void fiq_handler(void)
{
  error("fiq happened");
}


/* Here is your interrupt function */
//void
//__attribute__((interrupt("IRQ")))
//__attribute__((section(".interrupt_vectors.text")))
//irq_handler2(void) {
//    /* You code goes here */
////    uart_puts("GOT INTERRUPT!\r\n");
//
//    local_timer_clr_reload_reg_t temp = { .IntClear = 1, .Reload = 1 };
//    QA7->TimerClearReload  = temp;									// Clear interrupt & reload
//}

///* here is your main */
//int enable_timer(void) {
//
//    QA7->TimerRouting.Routing = LOCALTIMER_TO_CORE0_IRQ;			// Route local timer IRQ to Core0
//    QA7->TimerControlStatus.ReloadValue = 100;						// Timer period set
//    QA7->TimerControlStatus.TimerEnable = 1;						// Timer enabled
//    QA7->TimerControlStatus.IntEnable = 1;							// Timer IRQ enabled
//    QA7->TimerClearReload.IntClear = 1;								// Clear interrupt
//    QA7->TimerClearReload.Reload = 1;								// Reload now
//    QA7->Core0TimerIntControl.nCNTPNSIRQ_IRQ = 1;					// We are in NS EL1 so enable IRQ to core0 that level
//    QA7->Core0TimerIntControl.nCNTPNSIRQ_FIQ = 0;					// Make sure FIQ is zero
////    uart_puts("Enabled Timer\r\n");
//    return(0);
//}