summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc_hdl.c
blob: d4a5022fc309109466e8798502d3cba367c350e1 (plain) (blame)
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* PowerPC exception handling middleware; consult README for more
 * information.
 *
 * Author: Till Straumann <strauman@slac.stanford.edu>, 2007
 *
 *  The license and distribution terms for this file may be
 *  found in found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 *
 *  $Id$
 */

#include	<stdint.h>
#include	<string.h>

#include	<rtems.h>
#include	<rtems/score/cpu.h>
#include	<libcpu/raw_exception.h>
#include	<libcpu/spr.h>
#include	<rtems/score/apiext.h>

#include	"vectors.h"
#include	"ppc_exc_bspsupp.h"

/* offset into min-prolog where vector # is hardcoded */
#define		PPC_EXC_PROLOG_VEC_OFFSET	2

/* Provide temp. storage space for a few registers.
 * This is used by the assembly code prior to setting up
 * the stack.
 * One set is needed for each exception type with its
 * own SRR0/SRR1 pair since such exceptions may nest.
 *
 * NOTE: The assembly code needs these variables to
 *       be in the .sdata section and accesses them
 *       via R13.
 */
uint32_t ppc_exc_lock_std  = 0;
uint32_t ppc_exc_lock_crit = 0;
uint32_t ppc_exc_lock_mchk = 0;

uint32_t ppc_exc_vector_register_std     = 0;
uint32_t ppc_exc_vector_register_crit    = 0;
uint32_t ppc_exc_vector_register_mchk    = 0;

/* MSR bits to enable once critical status info is saved and the stack
 * is switched; must be set depending on CPU type
 *
 * Default is set here for classic PPC CPUs with a MMU
 * but is overridden from vectors_init.c
 */
uint32_t ppc_exc_msr_bits     = MSR_IR | MSR_DR | MSR_RI;

int ppc_exc_handler_default( BSP_Exception_frame *f, unsigned int vector)
{
	return 1;
}

/* Table of C-handlers */
ppc_exc_handler_t ppc_exc_handler_table [LAST_VALID_EXC + 1] = {
	[0 ... LAST_VALID_EXC] = ppc_exc_handler_default
};

ppc_exc_handler_t ppc_exc_get_handler( unsigned vector)
{
	ppc_exc_handler_t handler = NULL;
	if (vector > LAST_VALID_EXC) {
		return 0;
	}
	if (ppc_exc_handler_table [vector] != ppc_exc_handler_default) {
		handler = ppc_exc_handler_table [vector];
	}
	return handler;
}

int ppc_exc_set_handler( unsigned vector, ppc_exc_handler_t handler)
{
	if (vector > LAST_VALID_EXC) {
		return -1;
	}
	if (handler == NULL) {
		ppc_exc_handler_table [vector] = ppc_exc_handler_default;
	} else {
		ppc_exc_handler_table [vector] = handler;
	}
	return 0;
}

void
ppc_exc_wrapup( BSP_Exception_frame *f)
{
	/* dispatch_disable level is decremented from assembly code.  */
	if ( _Context_Switch_necessary ) {
		/* FIXME: I believe it should be OK to re-enable
		 *        interrupts around the execution of _Thread_Dispatch();
		 */
		_Thread_Dispatch();
	} else if ( _ISR_Signals_to_thread_executing ) {
		_ISR_Signals_to_thread_executing = 0;
		/*
		 * Process pending signals that have not already been
		 * processed by _Thread_Dispatch. This happens quite
		 * unfrequently : the ISR must have posted an action
		 * to the current running thread.
		 */
		if ( _Thread_Do_post_task_switch_extension ||
				_Thread_Executing->do_post_task_switch_extension ) {
			_Thread_Executing->do_post_task_switch_extension = false;
			_API_extensions_Run_postswitch();
		}
	}
}

void
ppc_exc_min_prolog_expand(ppc_exc_min_prolog_t buf, ppc_exc_min_prolog_template_t templ, uint16_t vec)
{
	memcpy(&buf[0], templ, sizeof(ppc_exc_min_prolog_t));
	/* fixup the vector */
	buf[PPC_EXC_PROLOG_VEC_OFFSET] = (buf[PPC_EXC_PROLOG_VEC_OFFSET] & 0xffff8000) | (vec & 0x7fff);
}

#undef TESTING
#ifdef TESTING

static void noop(const struct __rtems_raw_except_connect_data__*x) {}

rtems_raw_except_connect_data exc_conn = {
	exceptIndex: ASM_SYS_VECTOR,
	hdl        : {
					vector: ASM_SYS_VECTOR,
					raw_hdl: 0,
					raw_hdl_size: 0
	             },
	on         : noop,
	off        : noop,
	isOn       : 0	/* never used AFAIK */
};

void
ppc_exc_raise()
{
	asm volatile("li 3, 0xffffdead; sc");
}


int
exc_conn_do()
{
	exc_conn.hdl.raw_hdl      = ppc_exc_min_prolog_auto;
	exc_conn.hdl.raw_hdl_size = 16;
	return ppc_set_exception(&exc_conn);
}
#endif