Zephyr API Documentation  3.6.99
A Scalable Open Source RTOS
Loading...
Searching...
No Matches
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>
21#include <zephyr/sys/util.h>
25
26#ifndef _ASMLANGUAGE
27#include <stddef.h> /* for size_t */
28
31#include <zephyr/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_X86_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
120#define NANO_CPU_INT_REGISTER(r, n, p, v, d) \
121 static ISR_LIST __attribute__((section(".intList"))) \
122 __attribute__((used)) MK_ISR_NAME(r) = \
123 { \
124 .fnc = &(r), \
125 .irq = (n), \
126 .priority = (p), \
127 .vec = (v), \
128 .dpl = (d), \
129 .tss = 0 \
130 }
131
145#define _X86_IDT_TSS_REGISTER(tss_p, irq_p, priority_p, vec_p, dpl_p) \
146 static ISR_LIST __attribute__((section(".intList"))) \
147 __attribute__((used)) MK_ISR_NAME(vec_p) = \
148 { \
149 .fnc = NULL, \
150 .irq = (irq_p), \
151 .priority = (priority_p), \
152 .vec = (vec_p), \
153 .dpl = (dpl_p), \
154 .tss = (tss_p) \
155 }
156
171#define _VECTOR_ARG(irq_p) (-1)
172
173#ifdef CONFIG_LINKER_USE_PINNED_SECTION
174#define IRQSTUBS_TEXT_SECTION ".pinned_text.irqstubs"
175#else
176#define IRQSTUBS_TEXT_SECTION ".text.irqstubs"
177#endif
178
179/* Internally this function does a few things:
180 *
181 * 1. There is a declaration of the interrupt parameters in the .intList
182 * section, used by gen_idt to create the IDT. This does the same thing
183 * as the NANO_CPU_INT_REGISTER() macro, but is done in assembly as we
184 * need to populate the .fnc member with the address of the assembly
185 * IRQ stub that we generate immediately afterwards.
186 *
187 * 2. The IRQ stub itself is declared. The code will go in its own named
188 * section .text.irqstubs section (which eventually gets linked into 'text')
189 * and the stub shall be named (isr_name)_irq(irq_line)_stub
190 *
191 * 3. The IRQ stub pushes the ISR routine and its argument onto the stack
192 * and then jumps to the common interrupt handling code in _interrupt_enter().
193 *
194 * 4. z_irq_controller_irq_config() is called at runtime to set the mapping
195 * between the vector and the IRQ line as well as triggering flags
196 */
197#define ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p) \
198{ \
199 __asm__ __volatile__( \
200 ".pushsection .intList\n\t" \
201 ".long %c[isr]_irq%c[irq]_stub\n\t" /* ISR_LIST.fnc */ \
202 ".long %c[irq]\n\t" /* ISR_LIST.irq */ \
203 ".long %c[priority]\n\t" /* ISR_LIST.priority */ \
204 ".long %c[vector]\n\t" /* ISR_LIST.vec */ \
205 ".long 0\n\t" /* ISR_LIST.dpl */ \
206 ".long 0\n\t" /* ISR_LIST.tss */ \
207 ".popsection\n\t" \
208 ".pushsection " IRQSTUBS_TEXT_SECTION "\n\t" \
209 ".global %c[isr]_irq%c[irq]_stub\n\t" \
210 "%c[isr]_irq%c[irq]_stub:\n\t" \
211 "pushl %[isr_param]\n\t" \
212 "pushl %[isr]\n\t" \
213 "jmp _interrupt_enter\n\t" \
214 ".popsection\n\t" \
215 : \
216 : [isr] "i" (isr_p), \
217 [isr_param] "i" (isr_param_p), \
218 [priority] "i" (priority_p), \
219 [vector] "i" _VECTOR_ARG(irq_p), \
220 [irq] "i" (irq_p)); \
221 z_irq_controller_irq_config(Z_IRQ_TO_INTERRUPT_VECTOR(irq_p), (irq_p), \
222 (flags_p)); \
223}
224
225#ifdef CONFIG_PCIE
226
227#define ARCH_PCIE_IRQ_CONNECT(bdf_p, irq_p, priority_p, \
228 isr_p, isr_param_p, flags_p) \
229 ARCH_IRQ_CONNECT(irq_p, priority_p, isr_p, isr_param_p, flags_p)
230
231#endif /* CONFIG_PCIE */
232
233/* Direct interrupts won't work as expected with KPTI turned on, because
234 * all non-user accessible pages in the page table are marked non-present.
235 * It's likely possible to add logic to ARCH_ISR_DIRECT_HEADER/FOOTER to do
236 * the necessary trampolining to switch page tables / stacks, but this
237 * probably loses all the latency benefits that direct interrupts provide
238 * and one might as well use a regular interrupt anyway.
239 */
240#ifndef CONFIG_X86_KPTI
241#define ARCH_IRQ_DIRECT_CONNECT(irq_p, priority_p, isr_p, flags_p) \
242{ \
243 NANO_CPU_INT_REGISTER(isr_p, irq_p, priority_p, -1, 0); \
244 z_irq_controller_irq_config(Z_IRQ_TO_INTERRUPT_VECTOR(irq_p), (irq_p), \
245 (flags_p)); \
246}
247
248#ifdef CONFIG_PM
249static inline void arch_irq_direct_pm(void)
250{
251 if (_kernel.idle) {
252 _kernel.idle = 0;
253 z_pm_save_idle_exit();
254 }
255}
256
257#define ARCH_ISR_DIRECT_PM() arch_irq_direct_pm()
258#else
259#define ARCH_ISR_DIRECT_PM() do { } while (false)
260#endif
261
262#define ARCH_ISR_DIRECT_HEADER() arch_isr_direct_header()
263#define ARCH_ISR_DIRECT_FOOTER(swap) arch_isr_direct_footer(swap)
264
265/* FIXME:
266 * tracing/tracing.h cannot be included here due to circular dependency
267 */
268#if defined(CONFIG_TRACING)
269void sys_trace_isr_enter(void);
270void sys_trace_isr_exit(void);
271#endif
272
273static inline void arch_isr_direct_header(void)
274{
275#if defined(CONFIG_TRACING)
277#endif
278
279 /* We're not going to unlock IRQs, but we still need to increment this
280 * so that arch_is_in_isr() works
281 */
282 ++_kernel.cpus[0].nested;
283}
284
285/*
286 * FIXME: z_swap_irqlock is an inline function declared in a private header and
287 * cannot be referenced from a public header, so we move it to an
288 * external function.
289 */
290void arch_isr_direct_footer_swap(unsigned int key);
291
292static inline void arch_isr_direct_footer(int swap)
293{
294 z_irq_controller_eoi();
295#if defined(CONFIG_TRACING)
297#endif
298 --_kernel.cpus[0].nested;
299
300 /* Call swap if all the following is true:
301 *
302 * 1) swap argument was enabled to this function
303 * 2) We are not in a nested interrupt
304 * 3) Next thread to run in the ready queue is not this thread
305 */
306 if (swap != 0 && _kernel.cpus[0].nested == 0 &&
307 _kernel.ready_q.cache != _current) {
308 unsigned int flags;
309
310 /* Fetch EFLAGS argument to z_swap() */
311 __asm__ volatile (
312 "pushfl\n\t"
313 "popl %0\n\t"
314 : "=g" (flags)
315 :
316 : "memory"
317 );
318
320 }
321}
322
323#define ARCH_ISR_DIRECT_DECLARE(name) \
324 static inline int name##_body(void); \
325 __attribute__ ((interrupt)) void name(void *stack_frame) \
326 { \
327 ARG_UNUSED(stack_frame); \
328 int check_reschedule; \
329 ISR_DIRECT_HEADER(); \
330 check_reschedule = name##_body(); \
331 ISR_DIRECT_FOOTER(check_reschedule); \
332 } \
333 static inline int name##_body(void)
334#endif /* !CONFIG_X86_KPTI */
335
349typedef struct nanoEsf {
350#ifdef CONFIG_GDBSTUB
351 unsigned int ss;
352 unsigned int gs;
353 unsigned int fs;
354 unsigned int es;
355 unsigned int ds;
356#endif
357 unsigned int esp;
358 unsigned int ebp;
359 unsigned int ebx;
360 unsigned int esi;
361 unsigned int edi;
362 unsigned int edx;
363 unsigned int eax;
364 unsigned int ecx;
365 unsigned int errorCode;
366 unsigned int eip;
367 unsigned int cs;
368 unsigned int eflags;
369} z_arch_esf_t;
370
371extern unsigned int z_x86_exception_vector;
372
373struct _x86_syscall_stack_frame {
374 uint32_t eip;
375 uint32_t cs;
376 uint32_t eflags;
377
378 /* These are only present if cs = USER_CODE_SEG */
379 uint32_t esp;
380 uint32_t ss;
381};
382
383static ALWAYS_INLINE unsigned int arch_irq_lock(void)
384{
385 unsigned int key;
386
387 __asm__ volatile ("pushfl; cli; popl %0" : "=g" (key) :: "memory");
388
389 return key;
390}
391
392
398#define NANO_SOFT_IRQ ((unsigned int) (-1))
399
400#ifdef CONFIG_X86_ENABLE_TSS
401extern struct task_state_segment _main_tss;
402#endif
403
404#define ARCH_EXCEPT(reason_p) do { \
405 __asm__ volatile( \
406 "push %[reason]\n\t" \
407 "int %[vector]\n\t" \
408 : \
409 : [vector] "i" (Z_X86_OOPS_VECTOR), \
410 [reason] "i" (reason_p)); \
411 CODE_UNREACHABLE; /* LCOV_EXCL_LINE */ \
412} while (false)
413
414/*
415 * Dynamic thread object memory alignment.
416 *
417 * If support for SSEx extensions is enabled a 16 byte boundary is required,
418 * since the 'fxsave' and 'fxrstor' instructions require this. In all other
419 * cases a 4 byte boundary is sufficient.
420 */
421#if defined(CONFIG_EAGER_FPU_SHARING) || defined(CONFIG_LAZY_FPU_SHARING)
422#ifdef CONFIG_SSE
423#define ARCH_DYNAMIC_OBJ_K_THREAD_ALIGNMENT 16
424#else
425#define ARCH_DYNAMIC_OBJ_K_THREAD_ALIGNMENT (sizeof(void *))
426#endif
427#else
428/* No special alignment requirements, simply align on pointer size. */
429#define ARCH_DYNAMIC_OBJ_K_THREAD_ALIGNMENT (sizeof(void *))
430#endif /* CONFIG_*_FP_SHARING */
431
432
433#ifdef __cplusplus
434}
435#endif
436
437#endif /* !_ASMLANGUAGE */
438
439#endif /* ZEPHYR_INCLUDE_ARCH_X86_IA32_ARCH_H_ */
IA-32 specific gdbstub interface header.
x86 (IA32) specific syscall header
Per-arch thread definition.
#define ALWAYS_INLINE
Definition: common.h:129
void sys_trace_isr_enter(void)
Called when entering an ISR.
void sys_trace_isr_exit(void)
Called when exiting an ISR.
static ALWAYS_INLINE unsigned int arch_irq_lock(void)
Definition: arch.h:63
flags
Definition: parser.h:96
__UINT32_TYPE__ uint32_t
Definition: stdint.h:90
Exception Stack Frame.
Definition: arch.h:349
unsigned int eax
Definition: arch.h:363
unsigned int ecx
Definition: arch.h:364
unsigned int edi
Definition: arch.h:361
unsigned int ebp
Definition: arch.h:358
unsigned int ss
Definition: arch.h:351
unsigned int es
Definition: arch.h:354
unsigned int ds
Definition: arch.h:355
unsigned int gs
Definition: arch.h:352
unsigned int fs
Definition: arch.h:353
unsigned int cs
Definition: arch.h:367
unsigned int edx
Definition: arch.h:362
unsigned int esp
Definition: arch.h:357
unsigned int eflags
Definition: arch.h:368
unsigned int errorCode
Definition: arch.h:365
unsigned int eip
Definition: arch.h:366
unsigned int ebx
Definition: arch.h:359
unsigned int esi
Definition: arch.h:360
Definition: arch.h:74
unsigned int tss
If nonzero, specifies a TSS segment selector.
Definition: arch.h:95
void * fnc
Address of ISR/stub.
Definition: arch.h:76
unsigned int dpl
Privilege level associated with ISR/stub.
Definition: arch.h:89
unsigned int irq
IRQ associated with the ISR/stub, or -1 if this is not associated with a real interrupt; in this case...
Definition: arch.h:81
unsigned int vec
Vector number associated with ISR/stub, or -1 to assign based on priority.
Definition: arch.h:87
unsigned int priority
Priority associated with the IRQ.
Definition: arch.h:83
Definition: segmentation.h:54
Misc utilities.
static void arch_isr_direct_footer(int swap)
Definition: arch.h:292
void arch_isr_direct_footer_swap(unsigned int key)
struct s_isrList ISR_LIST
static void arch_isr_direct_header(void)
Definition: arch.h:273