summaryrefslogtreecommitdiffstats
path: root/cpukit/score/cpu/i386/cpu_asm.S
blob: 906407836b2e17d733cfb7f0037beda8afeef75c (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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/*  cpu_asm.s
 *
 *  This file contains all assembly code for the Intel i386 implementation
 *  of RTEMS.
 *
 *  COPYRIGHT (c) 1989-1998.
 *  On-Line Applications Research Corporation (OAR).
 *  Copyright assigned to U.S. Government, 1994.
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.OARcorp.com/rtems/license.html.
 *
 *  $Id$
 */

#include <asm.h>

/*
 * Format of i386 Register structure
 */

.set REG_EFLAGS,  0
.set REG_ESP,     REG_EFLAGS + 4
.set REG_EBP,     REG_ESP + 4
.set REG_EBX,     REG_EBP + 4
.set REG_ESI,     REG_EBX + 4
.set REG_EDI,     REG_ESI + 4
.set SIZE_REGS,   REG_EDI + 4

        BEGIN_CODE

/*
 *  void _CPU_Context_switch( run_context, heir_context )
 *
 *  This routine performs a normal non-FP context.
 */

        .p2align  1
        PUBLIC (_CPU_Context_switch)

.set RUNCONTEXT_ARG,   4                   # save context argument
.set HEIRCONTEXT_ARG,  8                   # restore context argument

SYM (_CPU_Context_switch):
        movl      RUNCONTEXT_ARG(esp),eax  # eax = running threads context
        pushf                              # push eflags
        popl      REG_EFLAGS(eax)          # save eflags
        movl      esp,REG_ESP(eax)         # save stack pointer
        movl      ebp,REG_EBP(eax)         # save base pointer
        movl      ebx,REG_EBX(eax)         # save ebx
        movl      esi,REG_ESI(eax)         # save source register
        movl      edi,REG_EDI(eax)         # save destination register

        movl      HEIRCONTEXT_ARG(esp),eax # eax = heir threads context

restore:
        pushl     REG_EFLAGS(eax)          # push eflags
        popf                               # restore eflags
        movl      REG_ESP(eax),esp         # restore stack pointer
        movl      REG_EBP(eax),ebp         # restore base pointer
        movl      REG_EBX(eax),ebx         # restore ebx
        movl      REG_ESI(eax),esi         # restore source register
        movl      REG_EDI(eax),edi         # restore destination register
        ret

/*
 *  NOTE: May be unnecessary to reload some registers.
 */

/*
 *  void _CPU_Context_restore( new_context )
 *
 *  This routine performs a normal non-FP context.
 */

        PUBLIC (_CPU_Context_restore)

.set NEWCONTEXT_ARG,   4                   # context to restore argument

SYM (_CPU_Context_restore):

        movl      NEWCONTEXT_ARG(esp),eax  # eax = running threads context
        jmp       restore

/*PAGE
 *  void _CPU_Context_save_fp_context( &fp_context_ptr )
 *  void _CPU_Context_restore_fp_context( &fp_context_ptr )
 *
 *  This section is used to context switch an i80287, i80387,
 *  the built-in coprocessor or the i80486 or compatible.
 */

.set FPCONTEXT_ARG,   4                    # FP context argument

        .p2align  1
        PUBLIC (_CPU_Context_save_fp)
SYM (_CPU_Context_save_fp):
        movl      FPCONTEXT_ARG(esp),eax   # eax = &ptr to FP context area
        movl      (eax),eax                # eax = FP context area
        fsave     (eax)                    # save FP context
        ret

        .p2align  1
        PUBLIC (_CPU_Context_restore_fp)
SYM (_CPU_Context_restore_fp):
        movl      FPCONTEXT_ARG(esp),eax   # eax = &ptr to FP context area
        movl      (eax),eax                # eax = FP context area
        frstor    (eax)                    # restore FP context
        ret

        PUBLIC (_Exception_Handler)
SYM (_Exception_Handler):
	pusha				   # Push general purpose registers
	pushl	esp			   # Push exception frame address
	movl	_currentExcHandler, eax	   # Call function storead in _currentExcHandler
	call	* eax
	addl	$4, esp
	popa				   # restore general purpose registers
	addl	$8, esp			   # skill vector number and faultCode
	iret
		
#define DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY(_vector) \
        .p2align 4                         ; \
        PUBLIC (rtems_exception_prologue_ ## _vector ) ; \
SYM (rtems_exception_prologue_ ## _vector ):             \
	pushl	$ _vector	; \
        jmp   SYM (_Exception_Handler) ;

#define DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY(_vector) \
        .p2align 4                         ; \
        PUBLIC (rtems_exception_prologue_ ## _vector ) ; \
SYM (rtems_exception_prologue_ ## _vector ):             \
	pushl	$ 0		; \
	pushl	$ _vector	; \
        jmp   SYM (_Exception_Handler) ;

/*
 * Divide Error
 */	
DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (0)
/*
 * Debug Exception
 */	
DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (1)
/*
 * NMI
 */	
DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (2)
/*
 * Breakpoint
 */	
DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (3)
/*
 * Overflow
 */	
DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (4)
/*
 * Bound Range Exceeded
 */	
DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (5)
/*
 * Invalid Opcode
 */	
DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (6)
/*
 * No Math Coproc
 */	
DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (7)
/*
 * Double Fault
 */	
DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (8)
/*
 * Coprocessor segment overrun
 */	
DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (9)
/*
 * Invalid TSS
 */	
DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (10)
/*
 * Segment Not Present
 */	
DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (11)
/*
 * Stack segment Fault
 */	
DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (12)
/*
 * General Protection Fault
 */	
DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (13)
/*
 * Page Fault
 */	
DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (14)
/*
 * Floating point error (NB 15 is reserved it is therefor skipped)
 */	
DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (16)
/*
 * Aligment Check
 */	
DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (17)
/*
 * Machine Check
 */	
DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (18)
	

/*
 *  void *i386_Logical_to_physical(
 *     rtems_unsigned16  segment,
 *     void             *address
 *  );
 *
 *  Returns thirty-two bit physical address for segment:address.
 */

.set SEGMENT_ARG, 4
.set ADDRESS_ARG, 8

             PUBLIC (i386_Logical_to_physical)

SYM (i386_Logical_to_physical):

        xorl    eax,eax                # clear eax
        movzwl  SEGMENT_ARG(esp),ecx   # ecx = segment value
        movl    $ SYM (_Global_descriptor_table),edx
                                       # edx = address of our GDT
        addl    ecx,edx                # edx = address of desired entry
        movb    7(edx),ah              # ah = base 31:24
        movb    4(edx),al              # al = base 23:16
        shll    $16,eax                # move ax into correct bits
        movw    2(edx),ax              # ax = base 0:15
        movl    ADDRESS_ARG(esp),ecx   # ecx = address to convert
        addl    eax,ecx                # ecx = physical address equivalent
        movl    ecx,eax                # eax = ecx
        ret

/*
 *  void *i386_Physical_to_logical(
 *     rtems_unsigned16  segment,
 *     void             *address
 *  );
 *
 *  Returns thirty-two bit physical address for segment:address.
 */

/*
 *.set SEGMENT_ARG, 4
 *.set ADDRESS_ARG, 8   -- use sets from above
 */

       PUBLIC (i386_Physical_to_logical)

SYM (i386_Physical_to_logical):
        xorl    eax,eax                # clear eax
        movzwl  SEGMENT_ARG(esp),ecx   # ecx = segment value
        movl    $ SYM (_Global_descriptor_table),edx
                                       # edx = address of our GDT
        addl    ecx,edx                # edx = address of desired entry
        movb    7(edx),ah              # ah = base 31:24
        movb    4(edx),al              # al = base 23:16
        shll    $16,eax                # move ax into correct bits
        movw    2(edx),ax              # ax = base 0:15
        movl    ADDRESS_ARG(esp),ecx   # ecx = address to convert
        subl    eax,ecx                # ecx = logical address equivalent
        movl    ecx,eax                # eax = ecx
        ret

END_CODE

END