1 /*
2  * Copyright (c) 2010-2015 Wind River Systems, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Thread support primitives
10  *
11  * This module provides core thread related primitives for the IA-32
12  * processor architecture.
13  */
14 
15 #include <zephyr/kernel.h>
16 #include <ksched.h>
17 #include <zephyr/arch/x86/mmustructs.h>
18 #include <kswap.h>
19 #include <x86_mmu.h>
20 
21 /* forward declaration */
22 
23 /* Initial thread stack frame, such that everything is laid out as expected
24  * for when z_swap() switches to it for the first time.
25  */
26 struct _x86_initial_frame {
27 	uint32_t swap_retval;
28 	uint32_t ebp;
29 	uint32_t ebx;
30 	uint32_t esi;
31 	uint32_t edi;
32 	void *thread_entry;
33 	uint32_t eflags;
34 	k_thread_entry_t entry;
35 	void *p1;
36 	void *p2;
37 	void *p3;
38 };
39 
40 #ifdef CONFIG_X86_USERSPACE
41 /* Implemented in userspace.S */
42 extern void z_x86_syscall_entry_stub(void);
43 
44 /* Syscalls invoked by 'int 0x80'. Installed in the IDT at DPL=3 so that
45  * userspace can invoke it.
46  */
47 NANO_CPU_INT_REGISTER(z_x86_syscall_entry_stub, -1, -1, 0x80, 3);
48 #endif /* CONFIG_X86_USERSPACE */
49 
50 #if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)
51 
52 extern int z_float_disable(struct k_thread *thread);
53 
arch_float_disable(struct k_thread * thread)54 int arch_float_disable(struct k_thread *thread)
55 {
56 #if defined(CONFIG_LAZY_FPU_SHARING)
57 	return z_float_disable(thread);
58 #else
59 	return -ENOTSUP;
60 #endif /* CONFIG_LAZY_FPU_SHARING */
61 }
62 
63 extern int z_float_enable(struct k_thread *thread, unsigned int options);
64 
arch_float_enable(struct k_thread * thread,unsigned int options)65 int arch_float_enable(struct k_thread *thread, unsigned int options)
66 {
67 #if defined(CONFIG_LAZY_FPU_SHARING)
68 	return z_float_enable(thread, options);
69 #else
70 	return -ENOTSUP;
71 #endif /* CONFIG_LAZY_FPU_SHARING */
72 }
73 #endif /* CONFIG_FPU && CONFIG_FPU_SHARING */
74 
arch_new_thread(struct k_thread * thread,k_thread_stack_t * stack,char * stack_ptr,k_thread_entry_t entry,void * p1,void * p2,void * p3)75 void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
76 		     char *stack_ptr, k_thread_entry_t entry,
77 		     void *p1, void *p2, void *p3)
78 {
79 	void *swap_entry;
80 	struct _x86_initial_frame *initial_frame;
81 
82 #if defined(CONFIG_X86_STACK_PROTECTION) && !defined(CONFIG_THREAD_STACK_MEM_MAPPED)
83 	/* This unconditionally set the first page of stack as guard page,
84 	 * which is only needed if the stack is not memory mapped.
85 	 */
86 	z_x86_set_stack_guard(stack);
87 #endif
88 
89 #ifdef CONFIG_USERSPACE
90 	swap_entry = z_x86_userspace_prepare_thread(thread);
91 #else
92 	swap_entry = z_thread_entry;
93 #endif
94 
95 	/* Create an initial context on the stack expected by z_swap() */
96 	initial_frame = Z_STACK_PTR_TO_FRAME(struct _x86_initial_frame,
97 					     stack_ptr);
98 
99 	/* z_thread_entry() arguments */
100 	initial_frame->entry = entry;
101 	initial_frame->p1 = p1;
102 	initial_frame->p2 = p2;
103 	initial_frame->p3 = p3;
104 	initial_frame->eflags = EFLAGS_INITIAL;
105 #ifdef _THREAD_WRAPPER_REQUIRED
106 	initial_frame->edi = (uint32_t)swap_entry;
107 	initial_frame->thread_entry = z_x86_thread_entry_wrapper;
108 #else
109 	initial_frame->thread_entry = swap_entry;
110 #endif /* _THREAD_WRAPPER_REQUIRED */
111 
112 	/* Remaining _x86_initial_frame members can be garbage, z_thread_entry()
113 	 * doesn't care about their state when execution begins
114 	 */
115 	thread->callee_saved.esp = (unsigned long)initial_frame;
116 #if defined(CONFIG_LAZY_FPU_SHARING)
117 	thread->arch.excNestCount = 0;
118 #endif /* CONFIG_LAZY_FPU_SHARING */
119 	thread->arch.flags = 0;
120 
121 	/*
122 	 * When "eager FPU sharing" mode is enabled, FPU registers must be
123 	 * initialised at the time of thread creation because the floating-point
124 	 * context is always active and no further FPU initialisation is performed
125 	 * later.
126 	 */
127 #if defined(CONFIG_EAGER_FPU_SHARING)
128 	thread->arch.preempFloatReg.floatRegsUnion.fpRegs.fcw = 0x037f;
129 	thread->arch.preempFloatReg.floatRegsUnion.fpRegs.ftw = 0xffff;
130 #if defined(CONFIG_X86_SSE)
131 	thread->arch.preempFloatReg.floatRegsUnion.fpRegsEx.mxcsr = 0x1f80;
132 #endif /* CONFIG_X86_SSE */
133 #endif /* CONFIG_EAGER_FPU_SHARING */
134 }
135