aboutsummaryrefslogtreecommitdiff
#include "io.h"
#include "uart.h"
#include "svc_interface.h"
#include "armclock.h"
#include "scheduler.h"

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)
	{
	  // TODO set supervisor mode's stack pointer
	  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");
}