Zephyr API Documentation  2.7.0-rc2
A Scalable Open Source RTOS
arch.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010-2014 Wind River Systems, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
14#ifndef ZEPHYR_INCLUDE_ARCH_X86_IA32_ARCH_H_
15#define ZEPHYR_INCLUDE_ARCH_X86_IA32_ARCH_H_
16
17#include "sys_io.h"
18#include <stdbool.h>
19#include <kernel_structs.h>
20#include <arch/common/ffs.h>
21#include <sys/util.h>
25
26#ifndef _ASMLANGUAGE
27#include <stddef.h> /* for size_t */
28
31#include <pm/pm.h>
32
33#endif /* _ASMLANGUAGE */
34
35/* GDT layout */
36#define CODE_SEG 0x08
37#define DATA_SEG 0x10
38#define MAIN_TSS 0x18
39#define DF_TSS 0x20
40
41/*
42 * Use for thread local storage.
43 * Match these to gen_gdt.py.
44 * The 0x03 is added to limit privilege.
45 */
46#if defined(CONFIG_USERSPACE)
47#define GS_TLS_SEG (0x38 | 0x03)
48#elif defined(CONFIG_HW_STACK_PROTECTION)
49#define GS_TLS_SEG (0x28 | 0x03)
50#else
51#define GS_TLS_SEG (0x18 | 0x03)
52#endif
53
58#define MK_ISR_NAME(x) __isr__##x
59
60#define Z_DYN_STUB_SIZE 4
61#define Z_DYN_STUB_OFFSET 0
62#define Z_DYN_STUB_LONG_JMP_EXTRA_SIZE 3
63#define Z_DYN_STUB_PER_BLOCK 32
64
65
66#ifndef _ASMLANGUAGE
67
68#ifdef __cplusplus
69extern "C" {
70#endif
71
72/* interrupt/exception/error related definitions */
73
74typedef struct s_isrList {
76 void *fnc;
81 unsigned int irq;
83 unsigned int priority;
87 unsigned int vec;
89 unsigned int dpl;
90
95 unsigned int tss;
97
98
123#define NANO_CPU_INT_REGISTER(r, n, p, v, d) \
124 static ISR_LIST __attribute__((section(".intList"))) \
125 __attribute__((used)) MK_ISR_NAME(r) = \
126 { \
127 .fnc = &(r), \
128 .irq = (n), \
129 .priority = (p), \
130 .vec = (v), \
131 .dpl = (d), \
132 .tss = 0 \
133 }
134
148#define _X86_IDT_TSS_REGISTER(tss_p, irq_p, priority_p, vec_p, dpl_p) \
149 static ISR_LIST __attribute__((section(".intList"))) \
150 __attribute__((used)) MK_ISR_NAME(r) = \
151 { \
152 .fnc = NULL, \
153 .irq = (irq_p), \
154 .priority = (priority_p), \
155 .vec = (vec_p), \
156 .dpl = (dpl_p), \
157 .tss = (tss_p) \
158 }
159
174#define _VECTOR_ARG(irq_p) (-1)
175
176#ifdef CONFIG_LINKER_USE_PINNED_SECTION
177#define IRQSTUBS_TEXT_SECTION ".pinned_text.irqstubs"
178#else
179#define IRQSTUBS_TEXT_SECTION ".text.irqstubs"
180#endif
181
182/* Internally this function does a few things:
183 *
184 * 1. There is a declaration of the interrupt parameters in the .intList
185 * section, used by gen_idt to create the IDT. This does the same thing
186 * as the NANO_CPU_INT_REGISTER() macro, but is done in assembly as we
187 * need to populate the .fnc member with the address of the assembly
188 * IRQ stub that we generate immediately afterwards.
189 *
190 * 2. The IRQ stub itself is declared. The code will go in its own named
191 * section .text.irqstubs section (which eventually gets linked into 'text')
192 * and the stub shall be named (isr_name)_irq(irq_line)_stub
193 *
194 * 3. The IRQ stub pushes the ISR routine and its argument onto the stack
195 * and then jumps to the common interrupt handling code in _interrupt_enter().
196 *
197 * 4. z_irq_controller_irq_config() is called at runtime to set the mapping
198 * between the vector and the IRQ line as well as triggering flags
199 */
200#define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \
201{ \
202 __asm__ __volatile__( \
203 ".pushsection .intList\n\t" \
204 ".long %c[isr]_irq%c[irq]_stub\n\t" /* ISR_LIST.fnc */ \
205 ".long %c[irq]\n\t" /* ISR_LIST.irq */ \
206 ".long %c[priority]\n\t" /* ISR_LIST.priority */ \
207 ".long %c[vector]\n\t" /* ISR_LIST.vec */ \
208 ".long 0\n\t" /* ISR_LIST.dpl */ \
209 ".long 0\n\t" /* ISR_LIST.tss */ \
210 ".popsection\n\t" \
211 ".pushsection " IRQSTUBS_TEXT_SECTION "\n\t" \
212 ".global %c[isr]_irq%c[irq]_stub\n\t" \
213 "%c[isr]_irq%c[irq]_stub:\n\t" \
214 "pushl %[isr_param]\n\t" \
215 "pushl %[isr]\n\t" \
216 "jmp _interrupt_enter\n\t" \
217 ".popsection\n\t" \
218 : \
219 : [isr] "i" (isr_p), \
220 [isr_param] "i" (isr_param_p), \
221 [priority] "i" (priority_p), \
222 [vector] "i" _VECTOR_ARG(irq_p), \
223 [irq] "i" (irq_p)); \
224 z_irq_controller_irq_config(Z_IRQ_TO_INTERRUPT_VECTOR(irq_p), (irq_p), \
225 (flags_p)); \
226}
227
228/* Direct interrupts won't work as expected with KPTI turned on, because
229 * all non-user accessible pages in the page table are marked non-present.
230 * It's likely possible to add logic to ARCH_ISR_DIRECT_HEADER/FOOTER to do
231 * the necessary trampolining to switch page tables / stacks, but this
232 * probably loses all the latency benefits that direct interrupts provide
233 * and one might as well use a regular interrupt anyway.
234 */
235#ifndef CONFIG_X86_KPTI
236#define ARCH_IRQ_DIRECT_CONNECT(irq_p, priority_p, isr_p, flags_p) \
237{ \
238 NANO_CPU_INT_REGISTER(isr_p, irq_p, priority_p, -1, 0); \
239 z_irq_controller_irq_config(Z_IRQ_TO_INTERRUPT_VECTOR(irq_p), (irq_p), \
240 (flags_p)); \
241}
242
243#ifdef CONFIG_PM
244static inline void arch_irq_direct_pm(void)
245{
246 if (_kernel.idle) {
247 int32_t idle_val = _kernel.idle;
248
249 _kernel.idle = 0;
250 z_pm_save_idle_exit(idle_val);
251 }
252}
253
254#define ARCH_ISR_DIRECT_PM() arch_irq_direct_pm()
255#else
256#define ARCH_ISR_DIRECT_PM() do { } while (false)
257#endif
258
259#define ARCH_ISR_DIRECT_HEADER() arch_isr_direct_header()
260#define ARCH_ISR_DIRECT_FOOTER(swap) arch_isr_direct_footer(swap)
261
262/* FIXME:
263 * tracing/tracing.h cannot be included here due to circular dependency
264 */
265#if defined(CONFIG_TRACING)
266extern void sys_trace_isr_enter(void);
267extern void sys_trace_isr_exit(void);
268#endif
269
270static inline void arch_isr_direct_header(void)
271{
272#if defined(CONFIG_TRACING)
274#endif
275
276 /* We're not going to unlock IRQs, but we still need to increment this
277 * so that arch_is_in_isr() works
278 */
279 ++_kernel.cpus[0].nested;
280}
281
282/*
283 * FIXME: z_swap_irqlock is an inline function declared in a private header and
284 * cannot be referenced from a public header, so we move it to an
285 * external function.
286 */
287extern void arch_isr_direct_footer_swap(unsigned int key);
288
289static inline void arch_isr_direct_footer(int swap)
290{
291 z_irq_controller_eoi();
292#if defined(CONFIG_TRACING)
294#endif
295 --_kernel.cpus[0].nested;
296
297 /* Call swap if all the following is true:
298 *
299 * 1) swap argument was enabled to this function
300 * 2) We are not in a nested interrupt
301 * 3) Next thread to run in the ready queue is not this thread
302 */
303 if (swap != 0 && _kernel.cpus[0].nested == 0 &&
304 _kernel.ready_q.cache != _current) {
305 unsigned int flags;
306
307 /* Fetch EFLAGS argument to z_swap() */
308 __asm__ volatile (
309 "pushfl\n\t"
310 "popl %0\n\t"
311 : "=g" (flags)
312 :
313 : "memory"
314 );
315
317 }
318}
319
320#define ARCH_ISR_DIRECT_DECLARE(name) \
321 static inline int name##_body(void); \
322 __attribute__ ((interrupt)) void name(void *stack_frame) \
323 { \
324 ARG_UNUSED(stack_frame); \
325 int check_reschedule; \
326 ISR_DIRECT_HEADER(); \
327 check_reschedule = name##_body(); \
328 ISR_DIRECT_FOOTER(check_reschedule); \
329 } \
330 static inline int name##_body(void)
331#endif /* !CONFIG_X86_KPTI */
332
346typedef struct nanoEsf {
347#ifdef CONFIG_GDBSTUB
348 unsigned int ss;
349 unsigned int gs;
350 unsigned int fs;
351 unsigned int es;
352 unsigned int ds;
353#endif
354 unsigned int esp;
355 unsigned int ebp;
356 unsigned int ebx;
357 unsigned int esi;
358 unsigned int edi;
359 unsigned int edx;
360 unsigned int eax;
361 unsigned int ecx;
362 unsigned int errorCode;
363 unsigned int eip;
364 unsigned int cs;
365 unsigned int eflags;
366} z_arch_esf_t;
367
368extern unsigned int z_x86_exception_vector;
369
370struct _x86_syscall_stack_frame {
371 uint32_t eip;
372 uint32_t cs;
373 uint32_t eflags;
374
375 /* These are only present if cs = USER_CODE_SEG */
376 uint32_t esp;
377 uint32_t ss;
378};
379
380static ALWAYS_INLINE unsigned int arch_irq_lock(void)
381{
382 unsigned int key;
383
384 __asm__ volatile ("pushfl; cli; popl %0" : "=g" (key) :: "memory");
385
386 return key;
387}
388
389
395#define NANO_SOFT_IRQ ((unsigned int) (-1))
396
403struct k_thread;
404
409#ifdef CONFIG_X86_ENABLE_TSS
410extern struct task_state_segment _main_tss;
411#endif
412
413#define ARCH_EXCEPT(reason_p) do { \
414 __asm__ volatile( \
415 "push %[reason]\n\t" \
416 "int %[vector]\n\t" \
417 : \
418 : [vector] "i" (Z_X86_OOPS_VECTOR), \
419 [reason] "i" (reason_p)); \
420 CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ \
421} while (false)
422
423/*
424 * Dynamic thread object memory alignment.
425 *
426 * If support for SSEx extensions is enabled a 16 byte boundary is required,
427 * since the 'fxsave' and 'fxrstor' instructions require this. In all other
428 * cases a 4 byte boundary is sufficient.
429 */
430#if defined(CONFIG_EAGER_FPU_SHARING) || defined(CONFIG_LAZY_FPU_SHARING)
431#ifdef CONFIG_SSE
432#define ARCH_DYMANIC_OBJ_K_THREAD_ALIGNMENT 16
433#else
434#define ARCH_DYMANIC_OBJ_K_THREAD_ALIGNMENT (sizeof(void *))
435#endif
436#else
437/* No special alignment requirements, simply align on pointer size. */
438#define ARCH_DYMANIC_OBJ_K_THREAD_ALIGNMENT (sizeof(void *))
439#endif /* CONFIG_*_FP_SHARING */
440
441
442#ifdef __cplusplus
443}
444#endif
445
446#endif /* !_ASMLANGUAGE */
447
448#endif /* ZEPHYR_INCLUDE_ARCH_X86_IA32_ARCH_H_ */
IA-32 specific gdbstub interface header.
x86 (IA32) specific sycall header
Per-arch thread definition.
#define ALWAYS_INLINE
Definition: common.h:116
void sys_trace_isr_enter(void)
Called when entering an ISR.
void sys_trace_isr_exit(void)
Called when exiting an ISR.
flags
Definition: http_parser.h:131
static k_spinlock_key_t key
Definition: spinlock_error_case.c:14
__UINT32_TYPE__ uint32_t
Definition: stdint.h:60
__INT32_TYPE__ int32_t
Definition: stdint.h:44
Definition: thread.h:201
Exception Stack Frame.
Definition: arch.h:346
unsigned int eax
Definition: arch.h:360
unsigned int ecx
Definition: arch.h:361
unsigned int edi
Definition: arch.h:358
unsigned int ebp
Definition: arch.h:355
unsigned int ss
Definition: arch.h:348
unsigned int es
Definition: arch.h:351
unsigned int ds
Definition: arch.h:352
unsigned int gs
Definition: arch.h:349
unsigned int fs
Definition: arch.h:350
unsigned int cs
Definition: arch.h:364
unsigned int edx
Definition: arch.h:359
unsigned int esp
Definition: arch.h:354
unsigned int eflags
Definition: arch.h:365
unsigned int errorCode
Definition: arch.h:362
unsigned int eip
Definition: arch.h:363
unsigned int ebx
Definition: arch.h:356
unsigned int esi
Definition: arch.h:357
Definition: arch.h:74
unsigned int tss
Definition: arch.h:95
void * fnc
Definition: arch.h:76
unsigned int dpl
Definition: arch.h:89
unsigned int irq
Definition: arch.h:81
unsigned int vec
Definition: arch.h:87
unsigned int priority
Definition: arch.h:83
Definition: segmentation.h:54
Misc utilities.
static void arch_isr_direct_footer(int swap)
Definition: arch.h:289
static ALWAYS_INLINE unsigned int arch_irq_lock(void)
Definition: arch.h:380
void arch_isr_direct_footer_swap(unsigned int key)
struct s_isrList ISR_LIST
static void arch_isr_direct_header(void)
Definition: arch.h:270