xref: /minix/minix/kernel/arch/i386/mpx.S (revision c9278f91)
1433d6423SLionel Sambuc/* This file is part of the lowest layer of the MINIX kernel.  (The other part
2433d6423SLionel Sambuc * is "proc.c".)  The lowest layer does process switching and message handling.
3433d6423SLionel Sambuc * Furthermore it contains the assembler startup code for Minix and the 32-bit
4433d6423SLionel Sambuc * interrupt handlers.  It cooperates with the code in "start.c" to set up a
5433d6423SLionel Sambuc * good environment for main().
6433d6423SLionel Sambuc *
7433d6423SLionel Sambuc * Kernel is entered either because of kernel-calls, ipc-calls, interrupts or
8433d6423SLionel Sambuc * exceptions. TSS is set so that the kernel stack is loaded. The user context is
9433d6423SLionel Sambuc * saved to the proc table and the handler of the event is called. Once the
10433d6423SLionel Sambuc * handler is done, switch_to_user() function is called to pick a new process,
11433d6423SLionel Sambuc * finish what needs to be done for the next process to run, sets its context
12433d6423SLionel Sambuc * and switch to userspace.
13433d6423SLionel Sambuc *
14433d6423SLionel Sambuc * For communication with the boot monitor at startup time some constant
15433d6423SLionel Sambuc * data are compiled into the beginning of the text segment. This facilitates
16433d6423SLionel Sambuc * reading the data at the start of the boot process, since only the first
17433d6423SLionel Sambuc * sector of the file needs to be read.
18433d6423SLionel Sambuc *
19433d6423SLionel Sambuc * Some data storage is also allocated at the end of this file. This data
20433d6423SLionel Sambuc * will be at the start of the data segment of the kernel and will be read
21433d6423SLionel Sambuc * and modified by the boot monitor before the kernel starts.
22433d6423SLionel Sambuc */
23433d6423SLionel Sambuc
24433d6423SLionel Sambuc#include "kernel/kernel.h" /* configures the kernel */
25433d6423SLionel Sambuc
26433d6423SLionel Sambuc/* sections */
27433d6423SLionel Sambuc
28433d6423SLionel Sambuc#include <machine/vm.h>
29433d6423SLionel Sambuc#include "kernel/kernel.h"
30433d6423SLionel Sambuc#include <minix/config.h>
31433d6423SLionel Sambuc#include <minix/const.h>
32433d6423SLionel Sambuc#include <minix/ipcconst.h>
33433d6423SLionel Sambuc#include <minix/com.h>
34433d6423SLionel Sambuc#include <machine/asm.h>
35433d6423SLionel Sambuc#include <machine/interrupt.h>
36433d6423SLionel Sambuc#include "archconst.h"
37433d6423SLionel Sambuc#include "kernel/const.h"
38433d6423SLionel Sambuc#include "kernel/proc.h"
39433d6423SLionel Sambuc#include "sconst.h"
40433d6423SLionel Sambuc#include <machine/multiboot.h>
41433d6423SLionel Sambuc
42433d6423SLionel Sambuc#include "arch_proto.h" /* K_STACK_SIZE */
43433d6423SLionel Sambuc
44433d6423SLionel Sambuc#ifdef CONFIG_SMP
45433d6423SLionel Sambuc#include "kernel/smp.h"
46433d6423SLionel Sambuc#endif
47433d6423SLionel Sambuc
48433d6423SLionel Sambuc/* Selected 386 tss offsets. */
49433d6423SLionel Sambuc#define TSS3_S_SP0	4
50433d6423SLionel Sambuc
51433d6423SLionel SambucIMPORT(usermapped_offset)
52433d6423SLionel SambucIMPORT(copr_not_available_handler)
53433d6423SLionel SambucIMPORT(params_size)
54433d6423SLionel SambucIMPORT(params_offset)
55433d6423SLionel SambucIMPORT(switch_to_user)
56433d6423SLionel SambucIMPORT(multiboot_init)
57433d6423SLionel Sambuc
58433d6423SLionel Sambuc.text
59433d6423SLionel Sambuc/*===========================================================================*/
60433d6423SLionel Sambuc/*				interrupt handlers			     */
61433d6423SLionel Sambuc/*		interrupt handlers for 386 32-bit protected mode	     */
62433d6423SLionel Sambuc/*===========================================================================*/
63433d6423SLionel Sambuc
64433d6423SLionel Sambuc#define PIC_IRQ_HANDLER(irq)	\
65433d6423SLionel Sambuc	push	$irq							    	;\
66433d6423SLionel Sambuc	call	_C_LABEL(irq_handle)	/* intr_handle(irq_handlers[irq]) */	;\
67433d6423SLionel Sambuc	add	$4, %esp						    	;
68433d6423SLionel Sambuc
69433d6423SLionel Sambuc/*===========================================================================*/
70433d6423SLionel Sambuc/*				hwint00 - 07				     */
71433d6423SLionel Sambuc/*===========================================================================*/
72433d6423SLionel Sambuc/* Note this is a macro, it just looks like a subroutine. */
73433d6423SLionel Sambuc
74433d6423SLionel Sambuc#define hwint_master(irq) \
75433d6423SLionel Sambuc	TEST_INT_IN_KERNEL(4, 0f)					;\
76433d6423SLionel Sambuc									\
77433d6423SLionel Sambuc	SAVE_PROCESS_CTX(0, KTS_INT_HARD)				;\
78433d6423SLionel Sambuc	push	%ebp							;\
79433d6423SLionel Sambuc	movl	$0, %ebp	/* for stack trace */			;\
80433d6423SLionel Sambuc	call	_C_LABEL(context_stop)					;\
81433d6423SLionel Sambuc	add	$4, %esp						;\
82433d6423SLionel Sambuc	PIC_IRQ_HANDLER(irq)						;\
83433d6423SLionel Sambuc	movb	$END_OF_INT, %al					;\
84433d6423SLionel Sambuc	outb	$INT_CTL	/* reenable interrupts in master pic */	;\
85433d6423SLionel Sambuc	jmp	_C_LABEL(switch_to_user)				;\
86433d6423SLionel Sambuc									\
87433d6423SLionel Sambuc0:									\
88433d6423SLionel Sambuc	pusha								;\
89433d6423SLionel Sambuc	call	_C_LABEL(context_stop_idle)				;\
90433d6423SLionel Sambuc	PIC_IRQ_HANDLER(irq)						;\
91433d6423SLionel Sambuc	movb	$END_OF_INT, %al					;\
92433d6423SLionel Sambuc	outb	$INT_CTL	/* reenable interrupts in master pic */	;\
93433d6423SLionel Sambuc	CLEAR_IF(10*4(%esp))						;\
94433d6423SLionel Sambuc	popa								;\
95433d6423SLionel Sambuc	iret								;
96433d6423SLionel Sambuc
97433d6423SLionel Sambuc/* Each of these entry points is an expansion of the hwint_master macro */
98433d6423SLionel SambucENTRY(hwint00)
99433d6423SLionel Sambuc/* Interrupt routine for irq 0 (the clock). */
100433d6423SLionel Sambuc	hwint_master(0)
101433d6423SLionel Sambuc
102433d6423SLionel SambucENTRY(hwint01)
103433d6423SLionel Sambuc/* Interrupt routine for irq 1 (keyboard) */
104433d6423SLionel Sambuc	hwint_master(1)
105433d6423SLionel Sambuc
106433d6423SLionel SambucENTRY(hwint02)
107433d6423SLionel Sambuc/* Interrupt routine for irq 2 (cascade!) */
108433d6423SLionel Sambuc	hwint_master(2)
109433d6423SLionel Sambuc
110433d6423SLionel SambucENTRY(hwint03)
111433d6423SLionel Sambuc/* Interrupt routine for irq 3 (second serial) */
112433d6423SLionel Sambuc	hwint_master(3)
113433d6423SLionel Sambuc
114433d6423SLionel SambucENTRY(hwint04)
115433d6423SLionel Sambuc/* Interrupt routine for irq 4 (first serial) */
116433d6423SLionel Sambuc	hwint_master(4)
117433d6423SLionel Sambuc
118433d6423SLionel SambucENTRY(hwint05)
119433d6423SLionel Sambuc/* Interrupt routine for irq 5 (XT winchester) */
120433d6423SLionel Sambuc	hwint_master(5)
121433d6423SLionel Sambuc
122433d6423SLionel SambucENTRY(hwint06)
123433d6423SLionel Sambuc/* Interrupt routine for irq 6 (floppy) */
124433d6423SLionel Sambuc	hwint_master(6)
125433d6423SLionel Sambuc
126433d6423SLionel SambucENTRY(hwint07)
127433d6423SLionel Sambuc/* Interrupt routine for irq 7 (printer) */
128433d6423SLionel Sambuc	hwint_master(7)
129433d6423SLionel Sambuc
130433d6423SLionel Sambuc/*===========================================================================*/
131433d6423SLionel Sambuc/*				hwint08 - 15				     */
132433d6423SLionel Sambuc/*===========================================================================*/
133433d6423SLionel Sambuc/* Note this is a macro, it just looks like a subroutine. */
134433d6423SLionel Sambuc#define hwint_slave(irq)	\
135433d6423SLionel Sambuc	TEST_INT_IN_KERNEL(4, 0f)					;\
136433d6423SLionel Sambuc									\
137433d6423SLionel Sambuc	SAVE_PROCESS_CTX(0, KTS_INT_HARD)				;\
138433d6423SLionel Sambuc	push	%ebp							;\
139433d6423SLionel Sambuc	movl	$0, %ebp	/* for stack trace */			;\
140433d6423SLionel Sambuc	call	_C_LABEL(context_stop)					;\
141433d6423SLionel Sambuc	add	$4, %esp						;\
142433d6423SLionel Sambuc	PIC_IRQ_HANDLER(irq)						;\
143433d6423SLionel Sambuc	movb	$END_OF_INT, %al					;\
144433d6423SLionel Sambuc	outb	$INT_CTL	/* reenable interrupts in master pic */	;\
145433d6423SLionel Sambuc	outb	$INT2_CTL	/* reenable slave 8259		  */	;\
146433d6423SLionel Sambuc	jmp	_C_LABEL(switch_to_user)				;\
147433d6423SLionel Sambuc									\
148433d6423SLionel Sambuc0:									\
149433d6423SLionel Sambuc	pusha								;\
150433d6423SLionel Sambuc	call	_C_LABEL(context_stop_idle)				;\
151433d6423SLionel Sambuc	PIC_IRQ_HANDLER(irq)						;\
152433d6423SLionel Sambuc	movb	$END_OF_INT, %al					;\
153433d6423SLionel Sambuc	outb	$INT_CTL	/* reenable interrupts in master pic */	;\
154433d6423SLionel Sambuc	outb	$INT2_CTL	/* reenable slave 8259		  */	;\
155433d6423SLionel Sambuc	CLEAR_IF(10*4(%esp))						;\
156433d6423SLionel Sambuc	popa								;\
157433d6423SLionel Sambuc	iret								;
158433d6423SLionel Sambuc
159433d6423SLionel Sambuc/* Each of these entry points is an expansion of the hwint_slave macro */
160433d6423SLionel SambucENTRY(hwint08)
161433d6423SLionel Sambuc/* Interrupt routine for irq 8 (realtime clock) */
162433d6423SLionel Sambuc	hwint_slave(8)
163433d6423SLionel Sambuc
164433d6423SLionel SambucENTRY(hwint09)
165433d6423SLionel Sambuc/* Interrupt routine for irq 9 (irq 2 redirected) */
166433d6423SLionel Sambuc	hwint_slave(9)
167433d6423SLionel Sambuc
168433d6423SLionel SambucENTRY(hwint10)
169433d6423SLionel Sambuc/* Interrupt routine for irq 10 */
170433d6423SLionel Sambuc	hwint_slave(10)
171433d6423SLionel Sambuc
172433d6423SLionel SambucENTRY(hwint11)
173433d6423SLionel Sambuc/* Interrupt routine for irq 11 */
174433d6423SLionel Sambuc	hwint_slave(11)
175433d6423SLionel Sambuc
176433d6423SLionel SambucENTRY(hwint12)
177433d6423SLionel Sambuc/* Interrupt routine for irq 12 */
178433d6423SLionel Sambuc	hwint_slave(12)
179433d6423SLionel Sambuc
180433d6423SLionel SambucENTRY(hwint13)
181433d6423SLionel Sambuc/* Interrupt routine for irq 13 (FPU exception) */
182433d6423SLionel Sambuc	hwint_slave(13)
183433d6423SLionel Sambuc
184433d6423SLionel SambucENTRY(hwint14)
185433d6423SLionel Sambuc/* Interrupt routine for irq 14 (AT winchester) */
186433d6423SLionel Sambuc	hwint_slave(14)
187433d6423SLionel Sambuc
188433d6423SLionel SambucENTRY(hwint15)
189433d6423SLionel Sambuc/* Interrupt routine for irq 15 */
190433d6423SLionel Sambuc	hwint_slave(15)
191433d6423SLionel Sambuc
192433d6423SLionel Sambuc/* differences with sysenter:
193433d6423SLionel Sambuc *   - we have to find our own per-cpu stack (i.e. post-SYSCALL
194433d6423SLionel Sambuc *     %esp is not configured)
195433d6423SLionel Sambuc *   - we have to save the post-SYSRET %eip, provided by the cpu
196433d6423SLionel Sambuc *     in %ecx
197433d6423SLionel Sambuc *   - the system call parameters are passed in %ecx, so we userland
198433d6423SLionel Sambuc *     code that executes SYSCALL copies %ecx to %edx. So the roles
199433d6423SLionel Sambuc *     of %ecx and %edx are reversed
200433d6423SLionel Sambuc *   - we can use %esi as a scratch register
201433d6423SLionel Sambuc */
202433d6423SLionel Sambuc#define ipc_entry_syscall_percpu(cpu)			;\
203433d6423SLionel SambucENTRY(ipc_entry_syscall_cpu ## cpu)			;\
204433d6423SLionel Sambuc	xchg	%ecx, %edx				;\
205433d6423SLionel Sambuc	mov	k_percpu_stacks+4*cpu, %esi		;\
206433d6423SLionel Sambuc	mov	(%esi), %ebp 				;\
207433d6423SLionel Sambuc	movl	$KTS_SYSCALL, P_KERN_TRAP_STYLE(%ebp)	;\
208433d6423SLionel Sambuc	xchg	%esp, %esi				;\
209433d6423SLionel Sambuc	jmp	syscall_sysenter_common
210433d6423SLionel Sambuc
211433d6423SLionel Sambucipc_entry_syscall_percpu(0)
212433d6423SLionel Sambucipc_entry_syscall_percpu(1)
213433d6423SLionel Sambucipc_entry_syscall_percpu(2)
214433d6423SLionel Sambucipc_entry_syscall_percpu(3)
215433d6423SLionel Sambucipc_entry_syscall_percpu(4)
216433d6423SLionel Sambucipc_entry_syscall_percpu(5)
217433d6423SLionel Sambucipc_entry_syscall_percpu(6)
218433d6423SLionel Sambucipc_entry_syscall_percpu(7)
219433d6423SLionel Sambuc
220433d6423SLionel SambucENTRY(ipc_entry_sysenter)
221433d6423SLionel Sambuc	/* SYSENTER simply sets kernel segments, EIP to here, and ESP
222433d6423SLionel Sambuc	 * to tss->sp0 (through MSR). so no automatic context saving is done.
223433d6423SLionel Sambuc	 * interrupts are disabled.
224433d6423SLionel Sambuc	 *
225433d6423SLionel Sambuc	 * register usage:
226433d6423SLionel Sambuc	 * edi: call type (IPCVEC, KERVEC)
227433d6423SLionel Sambuc	 * ebx, eax, ecx: syscall params, set by userland
228433d6423SLionel Sambuc	 * esi, edx: esp, eip to restore, set by userland
229433d6423SLionel Sambuc	 *
230433d6423SLionel Sambuc	 * no state is automatically saved; userland does all of that.
231433d6423SLionel Sambuc	 */
232433d6423SLionel Sambuc	mov	(%esp), %ebp /* get proc saved by arch_finish_switch_to_user */
233433d6423SLionel Sambuc
234433d6423SLionel Sambuc	/* inform kernel we entered by sysenter and should
235433d6423SLionel Sambuc	 * therefore exit through restore_user_context_sysenter
236433d6423SLionel Sambuc	 */
237433d6423SLionel Sambuc	movl	$KTS_SYSENTER, P_KERN_TRAP_STYLE(%ebp)
238433d6423SLionel Sambuc	add	usermapped_offset, %edx	/* compensate for mapping difference */
239433d6423SLionel Sambuc
240433d6423SLionel Sambucsyscall_sysenter_common:
241433d6423SLionel Sambuc	mov	%esi, SPREG(%ebp)	/* esi is return esp */
242433d6423SLionel Sambuc	mov	%edx, PCREG(%ebp)	/* edx is return eip */
243433d6423SLionel Sambuc
244433d6423SLionel Sambuc	/* save PSW */
245433d6423SLionel Sambuc	pushf
246433d6423SLionel Sambuc	pop	%edx
247433d6423SLionel Sambuc	mov	%edx, PSWREG(%ebp)
248433d6423SLionel Sambuc
249433d6423SLionel Sambuc	/* check for call type; do_ipc? */
250433d6423SLionel Sambuc	cmp	$IPCVEC_UM, %edi
251433d6423SLionel Sambuc	jz	ipc_entry_common
252433d6423SLionel Sambuc
253433d6423SLionel Sambuc	/* check for kernel trap */
254433d6423SLionel Sambuc	cmp	$KERVEC_UM, %edi
255433d6423SLionel Sambuc	jz	kernel_call_entry_common
256433d6423SLionel Sambuc
257433d6423SLionel Sambuc	/* unrecognized call number; restore user with error */
258433d6423SLionel Sambuc	movl	$-1, AXREG(%ebp)
259433d6423SLionel Sambuc	push	%ebp
260433d6423SLionel Sambuc	call	restore_user_context	/* restore_user_context(%ebp); */
261433d6423SLionel Sambuc
262433d6423SLionel Sambuc/*
263433d6423SLionel Sambuc * IPC is only from a process to kernel
264433d6423SLionel Sambuc */
265433d6423SLionel SambucENTRY(ipc_entry_softint_orig)
266433d6423SLionel Sambuc	SAVE_PROCESS_CTX(0, KTS_INT_ORIG)
267433d6423SLionel Sambuc	jmp ipc_entry_common
268433d6423SLionel Sambuc
269433d6423SLionel SambucENTRY(ipc_entry_softint_um)
270433d6423SLionel Sambuc	SAVE_PROCESS_CTX(0, KTS_INT_UM)
271433d6423SLionel Sambuc	jmp ipc_entry_common
272433d6423SLionel Sambuc
273433d6423SLionel SambucENTRY(ipc_entry_common)
274433d6423SLionel Sambuc	/* save the pointer to the current process */
275433d6423SLionel Sambuc	push	%ebp
276433d6423SLionel Sambuc
277433d6423SLionel Sambuc	/*
278433d6423SLionel Sambuc	 * pass the syscall arguments from userspace to the handler.
279433d6423SLionel Sambuc	 * SAVE_PROCESS_CTX() does not clobber these registers, they are still
280433d6423SLionel Sambuc	 * set as the userspace have set them
281433d6423SLionel Sambuc	 */
282433d6423SLionel Sambuc	push	%ebx
283433d6423SLionel Sambuc	push	%eax
284433d6423SLionel Sambuc	push	%ecx
285433d6423SLionel Sambuc
286433d6423SLionel Sambuc	/* stop user process cycles */
287433d6423SLionel Sambuc	push	%ebp
288433d6423SLionel Sambuc	/* for stack trace */
289433d6423SLionel Sambuc	movl	$0, %ebp
290433d6423SLionel Sambuc	call	_C_LABEL(context_stop)
291433d6423SLionel Sambuc	add	$4, %esp
292433d6423SLionel Sambuc
293433d6423SLionel Sambuc	call	_C_LABEL(do_ipc)
294433d6423SLionel Sambuc
295433d6423SLionel Sambuc	/* restore the current process pointer and save the return value */
296433d6423SLionel Sambuc	add	$3 * 4, %esp
297433d6423SLionel Sambuc	pop	%esi
298433d6423SLionel Sambuc	mov     %eax, AXREG(%esi)
299433d6423SLionel Sambuc
300433d6423SLionel Sambuc	jmp	_C_LABEL(switch_to_user)
301433d6423SLionel Sambuc
302433d6423SLionel Sambuc
303433d6423SLionel Sambuc/*
304433d6423SLionel Sambuc * kernel call is only from a process to kernel
305433d6423SLionel Sambuc */
306433d6423SLionel SambucENTRY(kernel_call_entry_orig)
307433d6423SLionel Sambuc	SAVE_PROCESS_CTX(0, KTS_INT_ORIG)
308433d6423SLionel Sambuc	jmp	kernel_call_entry_common
309433d6423SLionel Sambuc
310433d6423SLionel SambucENTRY(kernel_call_entry_um)
311433d6423SLionel Sambuc	SAVE_PROCESS_CTX(0, KTS_INT_UM)
312433d6423SLionel Sambuc	jmp	kernel_call_entry_common
313433d6423SLionel Sambuc
314433d6423SLionel SambucENTRY(kernel_call_entry_common)
315433d6423SLionel Sambuc	/* save the pointer to the current process */
316433d6423SLionel Sambuc	push	%ebp
317433d6423SLionel Sambuc
318433d6423SLionel Sambuc	/*
319433d6423SLionel Sambuc	 * pass the syscall arguments from userspace to the handler.
320433d6423SLionel Sambuc	 * SAVE_PROCESS_CTX() does not clobber these registers, they are still
321433d6423SLionel Sambuc	 * set as the userspace have set them
322433d6423SLionel Sambuc	 */
323433d6423SLionel Sambuc	push	%eax
324433d6423SLionel Sambuc
325433d6423SLionel Sambuc	/* stop user process cycles */
326433d6423SLionel Sambuc	push	%ebp
327433d6423SLionel Sambuc	/* for stack trace */
328433d6423SLionel Sambuc	movl	$0, %ebp
329433d6423SLionel Sambuc	call	_C_LABEL(context_stop)
330433d6423SLionel Sambuc	add	$4, %esp
331433d6423SLionel Sambuc
332433d6423SLionel Sambuc	call	_C_LABEL(kernel_call)
333433d6423SLionel Sambuc
334433d6423SLionel Sambuc	/* restore the current process pointer and save the return value */
335433d6423SLionel Sambuc	add	$8, %esp
336433d6423SLionel Sambuc
337433d6423SLionel Sambuc	jmp	_C_LABEL(switch_to_user)
338433d6423SLionel Sambuc
339433d6423SLionel Sambuc
340433d6423SLionel Sambuc.balign 16
341433d6423SLionel Sambuc/*
342433d6423SLionel Sambuc * called by the exception interrupt vectors. If the exception does not push
343433d6423SLionel Sambuc * errorcode, we assume that the vector handler pushed 0 instead. Next pushed
344433d6423SLionel Sambuc * thing is the vector number. From this point on we can continue as if every
345433d6423SLionel Sambuc * exception pushes an error code
346433d6423SLionel Sambuc */
347433d6423SLionel Sambucexception_entry:
348433d6423SLionel Sambuc	/*
349433d6423SLionel Sambuc	 * check if it is a nested trap by comparing the saved code segment
350433d6423SLionel Sambuc	 * descriptor with the kernel CS first
351433d6423SLionel Sambuc	 */
352433d6423SLionel Sambuc	TEST_INT_IN_KERNEL(12, exception_entry_nested)
353433d6423SLionel Sambuc
354433d6423SLionel Sambucexception_entry_from_user:
355433d6423SLionel Sambuc	SAVE_PROCESS_CTX(8, KTS_INT_HARD)
356433d6423SLionel Sambuc
357433d6423SLionel Sambuc	/* stop user process cycles */
358433d6423SLionel Sambuc	push	%ebp
359433d6423SLionel Sambuc	/* for stack trace clear %ebp */
360433d6423SLionel Sambuc	movl	$0, %ebp
361433d6423SLionel Sambuc	call	_C_LABEL(context_stop)
362433d6423SLionel Sambuc	add	$4, %esp
363433d6423SLionel Sambuc
364433d6423SLionel Sambuc	/*
365433d6423SLionel Sambuc	 * push a pointer to the interrupt state pushed by the cpu and the
366433d6423SLionel Sambuc	 * vector number pushed by the vector handler just before calling
367433d6423SLionel Sambuc	 * exception_entry and call the exception handler.
368433d6423SLionel Sambuc	 */
369433d6423SLionel Sambuc	push	%esp
370433d6423SLionel Sambuc	push	$0	/* it's not a nested exception */
371433d6423SLionel Sambuc	call 	_C_LABEL(exception_handler)
372433d6423SLionel Sambuc
373433d6423SLionel Sambuc	jmp	_C_LABEL(switch_to_user)
374433d6423SLionel Sambuc
375433d6423SLionel Sambucexception_entry_nested:
376433d6423SLionel Sambuc
377433d6423SLionel Sambuc	pusha
378433d6423SLionel Sambuc	mov	%esp, %eax
379433d6423SLionel Sambuc	add	$(8 * 4), %eax
380433d6423SLionel Sambuc	push	%eax
381433d6423SLionel Sambuc	pushl	$1			/* it's a nested exception */
382433d6423SLionel Sambuc	call	_C_LABEL(exception_handler)
383433d6423SLionel Sambuc	add	$8, %esp
384433d6423SLionel Sambuc	popa
385433d6423SLionel Sambuc
386433d6423SLionel Sambuc	/* clear the error code and the exception number */
387433d6423SLionel Sambuc	add	$8, %esp
388433d6423SLionel Sambuc	/* resume execution at the point of exception */
389433d6423SLionel Sambuc	iret
390433d6423SLionel Sambuc
391433d6423SLionel SambucENTRY(restore_user_context_sysenter)
392433d6423SLionel Sambuc	/* return to userspace using sysexit.
393433d6423SLionel Sambuc	 * most of the context saving the userspace process is
394433d6423SLionel Sambuc	 * responsible for, we just have to take care of the right EIP
395433d6423SLionel Sambuc	 * and ESP restoring here to resume execution, and set EAX and
396433d6423SLionel Sambuc	 * EBX to the saved status values.
397433d6423SLionel Sambuc	 */
398433d6423SLionel Sambuc	mov	4(%esp), %ebp		/* retrieve proc ptr arg */
399433d6423SLionel Sambuc	movw	$USER_DS_SELECTOR, %ax
400433d6423SLionel Sambuc	movw	%ax, %ds
401433d6423SLionel Sambuc	mov	PCREG(%ebp), %edx	/* sysexit restores EIP using EDX */
402433d6423SLionel Sambuc	mov	SPREG(%ebp), %ecx	/* sysexit restores ESP using ECX */
403433d6423SLionel Sambuc	mov	AXREG(%ebp), %eax	/* trap return value */
404433d6423SLionel Sambuc	mov	BXREG(%ebp), %ebx	/* secondary return value */
4059393439aSLionel Sambuc
4069393439aSLionel Sambuc        /* restore PSW */
407433d6423SLionel Sambuc        movl    PSWREG(%ebp), %edi      /* load desired PSW to EDI */
4089393439aSLionel Sambuc        push    %edi
4099393439aSLionel Sambuc        popf
4109393439aSLionel Sambuc
411433d6423SLionel Sambuc	sti				/* enable interrupts */
412433d6423SLionel Sambuc	sysexit				/* jump to EIP in user */
413433d6423SLionel Sambuc
414433d6423SLionel SambucENTRY(restore_user_context_syscall)
415433d6423SLionel Sambuc	/* return to userspace using sysret.
416433d6423SLionel Sambuc	 * the procedure is very similar to sysexit; it requires
417433d6423SLionel Sambuc	 * manual %esp restoring, new EIP in ECX, does not require
418433d6423SLionel Sambuc	 * enabling interrupts, and of course sysret instead of sysexit.
419433d6423SLionel Sambuc	 */
420433d6423SLionel Sambuc	mov	4(%esp), %ebp		/* retrieve proc ptr arg */
421*c9278f91SBen Gras
422*c9278f91SBen Gras        /* restore PSW (before we switch to user stack!) */
423*c9278f91SBen Gras        movl    PSWREG(%ebp), %edi      /* load desired PSW to EDI */
424*c9278f91SBen Gras        push    %edi
425*c9278f91SBen Gras        popf
426*c9278f91SBen Gras
427433d6423SLionel Sambuc	mov	PCREG(%ebp), %ecx	/* sysret restores EIP using ECX */
428433d6423SLionel Sambuc	mov	SPREG(%ebp), %esp	/* restore ESP directly */
429433d6423SLionel Sambuc	mov	AXREG(%ebp), %eax	/* trap return value */
430433d6423SLionel Sambuc	mov	BXREG(%ebp), %ebx	/* secondary return value */
431*c9278f91SBen Gras
432433d6423SLionel Sambuc	sysret				/* jump to EIP in user */
433433d6423SLionel Sambuc
434433d6423SLionel SambucENTRY(restore_user_context_int)
435433d6423SLionel Sambuc	mov	4(%esp), %ebp	/* will assume P_STACKBASE == 0 */
436433d6423SLionel Sambuc
437433d6423SLionel Sambuc	/* reconstruct the stack for iret */
438433d6423SLionel Sambuc	push	$USER_DS_SELECTOR	/* ss */
439433d6423SLionel Sambuc	movl	SPREG(%ebp), %eax
440433d6423SLionel Sambuc	push	%eax
441433d6423SLionel Sambuc	movl	PSWREG(%ebp), %eax
442433d6423SLionel Sambuc	push	%eax
443433d6423SLionel Sambuc	push	$USER_CS_SELECTOR	/* cs */
444433d6423SLionel Sambuc	movl	PCREG(%ebp), %eax
445433d6423SLionel Sambuc	push	%eax
446433d6423SLionel Sambuc
447433d6423SLionel Sambuc	/* Restore segments as the user should see them. */
448433d6423SLionel Sambuc	movw	$USER_DS_SELECTOR, %si
449433d6423SLionel Sambuc        movw    %si, %ds
450433d6423SLionel Sambuc        movw    %si, %es
451433d6423SLionel Sambuc        movw    %si, %fs
452433d6423SLionel Sambuc        movw    %si, %gs
453433d6423SLionel Sambuc
454433d6423SLionel Sambuc	/* Same for general-purpose registers. */
455433d6423SLionel Sambuc	RESTORE_GP_REGS(%ebp)
456433d6423SLionel Sambuc
457433d6423SLionel Sambuc	movl	BPREG(%ebp), %ebp
458433d6423SLionel Sambuc
459433d6423SLionel Sambuc	iret	/* continue process */
460433d6423SLionel Sambuc
461433d6423SLionel Sambuc/*===========================================================================*/
462433d6423SLionel Sambuc/*				exception handlers			     */
463433d6423SLionel Sambuc/*===========================================================================*/
464433d6423SLionel Sambuc
465433d6423SLionel Sambuc#define EXCEPTION_ERR_CODE(vector)	\
466433d6423SLionel Sambuc	push	$vector			;\
467433d6423SLionel Sambuc	jmp	exception_entry
468433d6423SLionel Sambuc
469433d6423SLionel Sambuc#define EXCEPTION_NO_ERR_CODE(vector)	\
470433d6423SLionel Sambuc	pushl	$0		;\
471433d6423SLionel Sambuc	EXCEPTION_ERR_CODE(vector)
472433d6423SLionel Sambuc
473433d6423SLionel SambucLABEL(divide_error)
474433d6423SLionel Sambuc	EXCEPTION_NO_ERR_CODE(DIVIDE_VECTOR)
475433d6423SLionel Sambuc
476433d6423SLionel SambucLABEL(single_step_exception)
477433d6423SLionel Sambuc	EXCEPTION_NO_ERR_CODE(DEBUG_VECTOR)
478433d6423SLionel Sambuc
479433d6423SLionel SambucLABEL(nmi)
480433d6423SLionel Sambuc#ifndef USE_WATCHDOG
481433d6423SLionel Sambuc	EXCEPTION_NO_ERR_CODE(NMI_VECTOR)
482433d6423SLionel Sambuc#else
483433d6423SLionel Sambuc	/*
484433d6423SLionel Sambuc	 * We have to be very careful as this interrupt can occur anytime. On
485433d6423SLionel Sambuc	 * the other hand, if it interrupts a user process, we will resume the
486433d6423SLionel Sambuc	 * same process which makes things a little simpler. We know that we are
487433d6423SLionel Sambuc	 * already on kernel stack whenever it happened and we can be
488433d6423SLionel Sambuc	 * conservative and save everything as we don't need to be extremely
489433d6423SLionel Sambuc	 * efficient as the interrupt is infrequent and some overhead is already
490433d6423SLionel Sambuc	 * expected.
491433d6423SLionel Sambuc	 */
492433d6423SLionel Sambuc
493433d6423SLionel Sambuc	/*
494433d6423SLionel Sambuc	 * save the important registers. We don't save %cs and %ss and they are
495433d6423SLionel Sambuc	 * saved and restored by CPU
496433d6423SLionel Sambuc	 */
497433d6423SLionel Sambuc	pushw	%ds
498433d6423SLionel Sambuc	pushw	%es
499433d6423SLionel Sambuc	pushw	%fs
500433d6423SLionel Sambuc	pushw	%gs
501433d6423SLionel Sambuc	pusha
502433d6423SLionel Sambuc
503433d6423SLionel Sambuc	/*
504433d6423SLionel Sambuc	 * We cannot be sure about the state of the kernel segment register,
505433d6423SLionel Sambuc	 * however, we always set %ds and %es to the same as %ss
506433d6423SLionel Sambuc	 */
507433d6423SLionel Sambuc	mov	%ss, %si
508433d6423SLionel Sambuc	mov	%si, %ds
509433d6423SLionel Sambuc	mov	%si, %es
510433d6423SLionel Sambuc
511433d6423SLionel Sambuc	push	%esp
512433d6423SLionel Sambuc	call	_C_LABEL(nmi_watchdog_handler)
513433d6423SLionel Sambuc	add	$4, %esp
514433d6423SLionel Sambuc
515433d6423SLionel Sambuc	/* restore all the important registers as they were before the trap */
516433d6423SLionel Sambuc	popa
517433d6423SLionel Sambuc	popw	%gs
518433d6423SLionel Sambuc	popw	%fs
519433d6423SLionel Sambuc	popw	%es
520433d6423SLionel Sambuc	popw	%ds
521433d6423SLionel Sambuc
522433d6423SLionel Sambuc	iret
523433d6423SLionel Sambuc#endif
524433d6423SLionel Sambuc
525433d6423SLionel SambucLABEL(breakpoint_exception)
526433d6423SLionel Sambuc	EXCEPTION_NO_ERR_CODE(BREAKPOINT_VECTOR)
527433d6423SLionel Sambuc
528433d6423SLionel SambucLABEL(overflow)
529433d6423SLionel Sambuc	EXCEPTION_NO_ERR_CODE(OVERFLOW_VECTOR)
530433d6423SLionel Sambuc
531433d6423SLionel SambucLABEL(bounds_check)
532433d6423SLionel Sambuc	EXCEPTION_NO_ERR_CODE(BOUNDS_VECTOR)
533433d6423SLionel Sambuc
534433d6423SLionel SambucLABEL(inval_opcode)
535433d6423SLionel Sambuc	EXCEPTION_NO_ERR_CODE(INVAL_OP_VECTOR)
536433d6423SLionel Sambuc
537433d6423SLionel SambucLABEL(copr_not_available)
538433d6423SLionel Sambuc	TEST_INT_IN_KERNEL(4, copr_not_available_in_kernel)
539433d6423SLionel Sambuc	cld			/* set direction flag to a known value */
540433d6423SLionel Sambuc	SAVE_PROCESS_CTX(0, KTS_INT_HARD)
541433d6423SLionel Sambuc	/* stop user process cycles */
542433d6423SLionel Sambuc	push	%ebp
543433d6423SLionel Sambuc	mov	$0, %ebp
544433d6423SLionel Sambuc	call	_C_LABEL(context_stop)
545433d6423SLionel Sambuc	call	_C_LABEL(copr_not_available_handler)
546433d6423SLionel Sambuc	/* reached upon failure only */
547433d6423SLionel Sambuc	jmp	_C_LABEL(switch_to_user)
548433d6423SLionel Sambuc
549433d6423SLionel Sambuccopr_not_available_in_kernel:
550433d6423SLionel Sambuc	pushl	$0
551433d6423SLionel Sambuc	pushl	$COPROC_NOT_VECTOR
552433d6423SLionel Sambuc	jmp	exception_entry_nested
553433d6423SLionel Sambuc
554433d6423SLionel SambucLABEL(double_fault)
555433d6423SLionel Sambuc	EXCEPTION_ERR_CODE(DOUBLE_FAULT_VECTOR)
556433d6423SLionel Sambuc
557433d6423SLionel SambucLABEL(copr_seg_overrun)
558433d6423SLionel Sambuc	EXCEPTION_NO_ERR_CODE(COPROC_SEG_VECTOR)
559433d6423SLionel Sambuc
560433d6423SLionel SambucLABEL(inval_tss)
561433d6423SLionel Sambuc	EXCEPTION_ERR_CODE(INVAL_TSS_VECTOR)
562433d6423SLionel Sambuc
563433d6423SLionel SambucLABEL(segment_not_present)
564433d6423SLionel Sambuc	EXCEPTION_ERR_CODE(SEG_NOT_VECTOR)
565433d6423SLionel Sambuc
566433d6423SLionel SambucLABEL(stack_exception)
567433d6423SLionel Sambuc	EXCEPTION_ERR_CODE(STACK_FAULT_VECTOR)
568433d6423SLionel Sambuc
569433d6423SLionel SambucLABEL(general_protection)
570433d6423SLionel Sambuc	EXCEPTION_ERR_CODE(PROTECTION_VECTOR)
571433d6423SLionel Sambuc
572433d6423SLionel SambucLABEL(page_fault)
573433d6423SLionel Sambuc	EXCEPTION_ERR_CODE(PAGE_FAULT_VECTOR)
574433d6423SLionel Sambuc
575433d6423SLionel SambucLABEL(copr_error)
576433d6423SLionel Sambuc	EXCEPTION_NO_ERR_CODE(COPROC_ERR_VECTOR)
577433d6423SLionel Sambuc
578433d6423SLionel SambucLABEL(alignment_check)
579433d6423SLionel Sambuc	EXCEPTION_NO_ERR_CODE(ALIGNMENT_CHECK_VECTOR)
580433d6423SLionel Sambuc
581433d6423SLionel SambucLABEL(machine_check)
582433d6423SLionel Sambuc	EXCEPTION_NO_ERR_CODE(MACHINE_CHECK_VECTOR)
583433d6423SLionel Sambuc
584433d6423SLionel SambucLABEL(simd_exception)
585433d6423SLionel Sambuc	EXCEPTION_NO_ERR_CODE(SIMD_EXCEPTION_VECTOR)
586433d6423SLionel Sambuc
587433d6423SLionel Sambuc/*===========================================================================*/
588433d6423SLionel Sambuc/*				reload_cr3				     */
589433d6423SLionel Sambuc/*===========================================================================*/
590433d6423SLionel Sambuc/* PUBLIC void reload_cr3(void); */
591433d6423SLionel SambucENTRY(reload_cr3)
592433d6423SLionel Sambuc	push    %ebp
593433d6423SLionel Sambuc	mov     %esp, %ebp
594433d6423SLionel Sambuc	mov	%cr3, %eax
595433d6423SLionel Sambuc	mov	%eax, %cr3
596433d6423SLionel Sambuc	pop     %ebp
597433d6423SLionel Sambuc	ret
598433d6423SLionel Sambuc
599433d6423SLionel Sambuc#ifdef CONFIG_SMP
600433d6423SLionel SambucENTRY(startup_ap_32)
601433d6423SLionel Sambuc	/*
602433d6423SLionel Sambuc	 * we are in protected mode now, %cs is correct and we need to set the
603433d6423SLionel Sambuc	 * data descriptors before we can touch anything
604433d6423SLionel Sambuc	 *
605433d6423SLionel Sambuc	 * first load the regular, highly mapped idt, gdt
606433d6423SLionel Sambuc	 */
607433d6423SLionel Sambuc
608433d6423SLionel Sambuc	/*
609433d6423SLionel Sambuc	 * use the boot stack for now. The running CPUs are already using their
610433d6423SLionel Sambuc	 * own stack, the rest is still waiting to be booted
611433d6423SLionel Sambuc	 */
612433d6423SLionel Sambuc	movw	$KERN_DS_SELECTOR, %ax
613433d6423SLionel Sambuc	mov	%ax, %ds
614433d6423SLionel Sambuc	mov	%ax, %ss
615433d6423SLionel Sambuc	mov	$_C_LABEL(k_boot_stktop) - 4, %esp
616433d6423SLionel Sambuc
617433d6423SLionel Sambuc	/* load the highly mapped idt, gdt, per-cpu tss */
618433d6423SLionel Sambuc	call	_C_LABEL(prot_load_selectors)
619433d6423SLionel Sambuc
620433d6423SLionel Sambuc	jmp	_C_LABEL(smp_ap_boot)
621433d6423SLionel Sambuc	hlt
622433d6423SLionel Sambuc#endif
623433d6423SLionel Sambuc
624433d6423SLionel Sambuc/*===========================================================================*/
625433d6423SLionel Sambuc/*				data					     */
626433d6423SLionel Sambuc/*===========================================================================*/
627433d6423SLionel Sambuc
628433d6423SLionel Sambuc.data
629433d6423SLionel Sambuc.short	0x526F	/* this must be the first data entry (magic #) */
630433d6423SLionel Sambuc
631433d6423SLionel Sambuc.bss
632433d6423SLionel Sambuck_initial_stack:
633433d6423SLionel Sambuc.space	K_STACK_SIZE
634433d6423SLionel SambucLABEL(__k_unpaged_k_initial_stktop)
635433d6423SLionel Sambuc
636433d6423SLionel Sambuc/*
637433d6423SLionel Sambuc * the kernel stack
638433d6423SLionel Sambuc */
639433d6423SLionel Sambuck_boot_stack:
640433d6423SLionel Sambuc.space	K_STACK_SIZE	/* kernel stack */ /* FIXME use macro here */
641433d6423SLionel SambucLABEL(k_boot_stktop)	/* top of kernel stack */
642433d6423SLionel Sambuc
643433d6423SLionel Sambuc.balign K_STACK_SIZE
644433d6423SLionel SambucLABEL(k_stacks_start)
645433d6423SLionel Sambuc
646433d6423SLionel Sambuc/* two pages for each stack, one for data, other as a sandbox */
647433d6423SLionel Sambuc.space	2 * (K_STACK_SIZE * CONFIG_MAX_CPUS)
648433d6423SLionel Sambuc
649433d6423SLionel SambucLABEL(k_stacks_end)
650433d6423SLionel Sambuc
651433d6423SLionel Sambuc/* top of kernel stack */
652