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