aboutsummaryrefslogtreecommitdiff
path: root/kernel/task/mcu/atmega2560/include/mcu/task/context.h
blob: b71799193697797b84accb923072adae19079750 (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
#ifndef CONTEXT_H
#define CONTEXT_H

#include <avr/interrupt.h>
#define ret() asm volatile ( "ret" )

/* 
 * The macros save_context(), restore_context() as well as the code contained in 
 * init_stack is adapted from the FreeRTOS kernel (http://www.freertos.org/).
 * Here by copyright, credits attributed to wherever they belong.
 */

/** 
 * Save context to memory location specified by first two chars of
 * a symbol named 'current' (this is why 'sp' has to be the first element of
 * of task control blocks). After executing this macro, the stack pointer will
 * be set to the address contained in 'kstack'.
 */
#define context_save() \
  asm volatile ( \
    "push r0 \n\t" \
    "in r0, __SREG__ \n\t" \
    "push r0 \n\t" \
    "push r1 \n\t" \
    "clr r1 \n\t" \
    "push r2 \n\t" \
    "push r3 \n\t" \
    "push r4 \n\t" \
    "push r5 \n\t" \
    "push r6 \n\t" \
    "push r7 \n\t" \
    "push r8 \n\t" \
    "push r9 \n\t" \
    "push r10 \n\t" \
    "push r11 \n\t" \
    "push r12 \n\t" \
    "push r13 \n\t" \
    "push r14 \n\t" \
    "push r15 \n\t" \
    "push r16 \n\t" \
    "push r17 \n\t" \
    "push r18 \n\t" \
    "push r19 \n\t" \
    "push r20 \n\t" \
    "push r21 \n\t" \
    "push r22 \n\t" \
    "push r23 \n\t" \
    "push r24 \n\t" \
    "push r25 \n\t" \
    "push r26 \n\t" \
    "push r27 \n\t" \
    "push r28 \n\t" \
    "push r29 \n\t" \
    "push r30 \n\t" \
    "push r31 \n\t" \
    "lds r26, current \n\t" \
    "lds r27, current +1 \n\t" \
    "in r0, __SP_L__ \n\t" \
    "st x+, r0 	\n\t" \
    "in r0, __SP_H__ \n\t" \
    "st x+, r0 \n\t" \
    "lds r26, kstack \n\t" \
    "lds r27, kstack + 1 \n\t" \
    "ld r28, x+ \n\t" \
    "out __SP_L__, r28 \n\t" \
    "ld r29, x+ \n\t" \
    "out __SP_H__, r29 \n\t" \
  )


/** 
 * Restore context to memory location specified by first two chars of
 * a symbol named 'current'.
 */
#define context_restore() \
  asm volatile ( \
    "lds r26, kstack \n\t" \
    "lds r27, kstack +1 \n\t" \
    "in r0, __SP_L__ \n\t" \
    "st x+, r0  \n\t" \
    "in r0, __SP_H__ \n\t" \
    "st x+, r0  \n\t" \
    "lds r26, current \n\t" \
    "lds r27, current + 1 \n\t" \
    "ld r28, x+ \n\t" \
    "out __SP_L__, r28 \n\t" \
    "ld r29, x+ \n\t" \
    "out __SP_H__, r29 \n\t" \
    "pop r31 \n\t" \
    "pop r30 \n\t" \
    "pop r29 \n\t" \
    "pop r28 \n\t" \
    "pop r27 \n\t" \
    "pop r26 \n\t" \
    "pop r25 \n\t" \
    "pop r24 \n\t" \
    "pop r23 \n\t" \
    "pop r22 \n\t" \
    "pop r21 \n\t" \
    "pop r20 \n\t" \
    "pop r19 \n\t" \
    "pop r18 \n\t" \
    "pop r17 \n\t" \
    "pop r16 \n\t" \
    "pop r15 \n\t" \
    "pop r14 \n\t" \
    "pop r13 \n\t" \
    "pop r12 \n\t" \
    "pop r11 \n\t" \
    "pop r10 \n\t" \
    "pop r9 \n\t" \
    "pop r8 \n\t" \
    "pop r7 \n\t" \
    "pop r6 \n\t" \
    "pop r5 \n\t" \
    "pop r4 \n\t" \
    "pop r3 \n\t" \
    "pop r2 \n\t" \
    "pop r1 \n\t" \
    "pop r0 \n\t" \
    "out __SREG__, r0 \n\t" \
    "pop r0 \n\t" \
  )

/** Initialize the given memory addresses to contain a valid, initial stackframe. */
char* stack_init(const char* const mem_low, const char* const mem_high, void (*entry)(char), char args);

/** Initialize the given memory addresses to contain a valid, initial stackframe. */
static inline void kstack_init(void **kstack) {
  //this sets the kernel stack to the default stack location
  //of this mcu, namely the top (stacks of tasks will typically
  //be contained in memory allocated on the head and thus should
  //overflow with the kernel stack)
  *kstack = (void*) SP; 
}

#endif