LCOV - code coverage report
Current view: top level - zephyr/arch/x86 - arch.h Coverage Total Hit
Test: new.info Lines: 3.1 % 32 1
Test Date: 2025-09-05 16:43:28

            Line data    Source code
       1            1 : /*
       2              :  * Copyright (c) 2019 Intel Corp.
       3              :  * SPDX-License-Identifier: Apache-2.0
       4              :  */
       5              : 
       6              : /**
       7              :  * @file
       8              :  * @brief X86 specific kernel interface header
       9              :  *
      10              :  * This header contains the X86 specific kernel interfaces for both
      11              :  * IA-32 and Intel-64.  It is included by the kernel interface
      12              :  * architecture-abstraction header (include/zephyr/arch/cpu.h).
      13              :  */
      14              : 
      15              : #ifndef ZEPHYR_INCLUDE_ARCH_X86_ARCH_H_
      16              : #define ZEPHYR_INCLUDE_ARCH_X86_ARCH_H_
      17              : 
      18              : #include <zephyr/devicetree.h>
      19              : 
      20              : /* Changing this value will require manual changes to exception and IDT setup
      21              :  * in locore.S for intel64
      22              :  */
      23              : #define Z_X86_OOPS_VECTOR       32
      24              : 
      25              : #if !defined(_ASMLANGUAGE)
      26              : 
      27              : #include <zephyr/sys/sys_io.h>
      28              : #include <zephyr/types.h>
      29              : #include <stddef.h>
      30              : #include <stdbool.h>
      31              : #include <zephyr/irq.h>
      32              : #include <zephyr/arch/x86/mmustructs.h>
      33              : #include <zephyr/arch/x86/thread_stack.h>
      34              : #include <zephyr/arch/x86/cet.h>
      35              : #include <zephyr/linker/sections.h>
      36              : 
      37              : #ifdef __cplusplus
      38              : extern "C" {
      39              : #endif
      40              : 
      41              : #ifdef CONFIG_PCIE_MSI
      42              : 
      43              : struct x86_msi_vector {
      44              :         unsigned int irq;
      45              :         uint8_t vector;
      46              : #ifdef CONFIG_INTEL_VTD_ICTL
      47              :         bool remap;
      48              :         uint8_t irte;
      49              : #endif
      50              : };
      51              : 
      52              : typedef struct x86_msi_vector arch_msi_vector_t;
      53              : 
      54              : #endif /* CONFIG_PCIE_MSI */
      55              : 
      56            0 : static ALWAYS_INLINE void arch_irq_unlock(unsigned int key)
      57              : {
      58              :         if ((key & 0x00000200U) != 0U) { /* 'IF' bit */
      59              :                 __asm__ volatile ("sti" ::: "memory");
      60              :         }
      61              : }
      62              : 
      63            0 : static ALWAYS_INLINE void sys_out8(uint8_t data, io_port_t port)
      64              : {
      65              :         __asm__ volatile("outb %b0, %w1" :: "a"(data), "Nd"(port));
      66              : }
      67              : 
      68            0 : static ALWAYS_INLINE uint8_t sys_in8(io_port_t port)
      69              : {
      70              :         uint8_t ret;
      71              : 
      72              :         __asm__ volatile("inb %w1, %b0" : "=a"(ret) : "Nd"(port));
      73              : 
      74              :         return ret;
      75              : }
      76              : 
      77            0 : static ALWAYS_INLINE void sys_out16(uint16_t data, io_port_t port)
      78              : {
      79              :         __asm__ volatile("outw %w0, %w1" :: "a"(data), "Nd"(port));
      80              : }
      81              : 
      82            0 : static ALWAYS_INLINE uint16_t sys_in16(io_port_t port)
      83              : {
      84              :         uint16_t ret;
      85              : 
      86              :         __asm__ volatile("inw %w1, %w0" : "=a"(ret) : "Nd"(port));
      87              : 
      88              :         return ret;
      89              : }
      90              : 
      91            0 : static ALWAYS_INLINE void sys_out32(uint32_t data, io_port_t port)
      92              : {
      93              :         __asm__ volatile("outl %0, %w1" :: "a"(data), "Nd"(port));
      94              : }
      95              : 
      96            0 : static ALWAYS_INLINE uint32_t sys_in32(io_port_t port)
      97              : {
      98              :         uint32_t ret;
      99              : 
     100              :         __asm__ volatile("inl %w1, %0" : "=a"(ret) : "Nd"(port));
     101              : 
     102              :         return ret;
     103              : }
     104              : 
     105            0 : static ALWAYS_INLINE void sys_write8(uint8_t data, mm_reg_t addr)
     106              : {
     107              :         __asm__ volatile("movb %0, %1"
     108              :                          :
     109              :                          : "q"(data), "m" (*(volatile uint8_t *)(uintptr_t) addr)
     110              :                          : "memory");
     111              : }
     112              : 
     113            0 : static ALWAYS_INLINE uint8_t sys_read8(mm_reg_t addr)
     114              : {
     115              :         uint8_t ret;
     116              : 
     117              :         __asm__ volatile("movb %1, %0"
     118              :                          : "=q"(ret)
     119              :                          : "m" (*(volatile uint8_t *)(uintptr_t) addr)
     120              :                          : "memory");
     121              : 
     122              :         return ret;
     123              : }
     124              : 
     125            0 : static ALWAYS_INLINE void sys_write16(uint16_t data, mm_reg_t addr)
     126              : {
     127              :         __asm__ volatile("movw %0, %1"
     128              :                          :
     129              :                          : "r"(data), "m" (*(volatile uint16_t *)(uintptr_t) addr)
     130              :                          : "memory");
     131              : }
     132              : 
     133            0 : static ALWAYS_INLINE uint16_t sys_read16(mm_reg_t addr)
     134              : {
     135              :         uint16_t ret;
     136              : 
     137              :         __asm__ volatile("movw %1, %0"
     138              :                          : "=r"(ret)
     139              :                          : "m" (*(volatile uint16_t *)(uintptr_t) addr)
     140              :                          : "memory");
     141              : 
     142              :         return ret;
     143              : }
     144              : 
     145            0 : static ALWAYS_INLINE void sys_write32(uint32_t data, mm_reg_t addr)
     146              : {
     147              :         __asm__ volatile("movl %0, %1"
     148              :                          :
     149              :                          : "r"(data), "m" (*(volatile uint32_t *)(uintptr_t) addr)
     150              :                          : "memory");
     151              : }
     152              : 
     153            0 : static ALWAYS_INLINE uint32_t sys_read32(mm_reg_t addr)
     154              : {
     155              :         uint32_t ret;
     156              : 
     157              :         __asm__ volatile("movl %1, %0"
     158              :                          : "=r"(ret)
     159              :                          : "m" (*(volatile uint32_t *)(uintptr_t) addr)
     160              :                          : "memory");
     161              : 
     162              :         return ret;
     163              : }
     164              : 
     165            0 : static ALWAYS_INLINE void sys_set_bit(mem_addr_t addr, unsigned int bit)
     166              : {
     167              :         __asm__ volatile("btsl %1, %0"
     168              :                          : "+m" (*(volatile uint8_t *) (addr))
     169              :                          : "Ir" (bit)
     170              :                          : "memory");
     171              : }
     172              : 
     173            0 : static ALWAYS_INLINE void sys_clear_bit(mem_addr_t addr, unsigned int bit)
     174              : {
     175              :         __asm__ volatile("btrl %1, %0"
     176              :                          : "+m" (*(volatile uint8_t *) (addr))
     177              :                          : "Ir" (bit));
     178              : }
     179              : 
     180            0 : static ALWAYS_INLINE int sys_test_bit(mem_addr_t addr, unsigned int bit)
     181              : {
     182              :         int ret;
     183              : 
     184              :         __asm__ volatile("btl %2, %1;"
     185              :                          "sbb %0, %0"
     186              :                          : "=r" (ret), "+m" (*(volatile uint8_t *) (addr))
     187              :                          : "Ir" (bit));
     188              : 
     189              :         return ret;
     190              : }
     191              : 
     192            0 : static ALWAYS_INLINE int sys_test_and_set_bit(mem_addr_t addr,
     193              :                                               unsigned int bit)
     194              : {
     195              :         int ret;
     196              : 
     197              :         __asm__ volatile("btsl %2, %1;"
     198              :                          "sbb %0, %0"
     199              :                          : "=r" (ret), "+m" (*(volatile uint8_t *) (addr))
     200              :                          : "Ir" (bit));
     201              : 
     202              :         return ret;
     203              : }
     204              : 
     205            0 : static ALWAYS_INLINE int sys_test_and_clear_bit(mem_addr_t addr,
     206              :                                                 unsigned int bit)
     207              : {
     208              :         int ret;
     209              : 
     210              :         __asm__ volatile("btrl %2, %1;"
     211              :                          "sbb %0, %0"
     212              :                          : "=r" (ret), "+m" (*(volatile uint8_t *) (addr))
     213              :                          : "Ir" (bit));
     214              : 
     215              :         return ret;
     216              : }
     217              : 
     218            0 : #define sys_bitfield_set_bit sys_set_bit
     219            0 : #define sys_bitfield_clear_bit sys_clear_bit
     220            0 : #define sys_bitfield_test_bit sys_test_bit
     221            0 : #define sys_bitfield_test_and_set_bit sys_test_and_set_bit
     222            0 : #define sys_bitfield_test_and_clear_bit sys_test_and_clear_bit
     223              : 
     224              : /*
     225              :  * Map of IRQ numbers to their assigned vectors. On IA32, this is generated
     226              :  * at build time and defined via the linker script. On Intel64, it's an array.
     227              :  */
     228              : 
     229              : extern unsigned char _irq_to_interrupt_vector[CONFIG_MAX_IRQ_LINES];
     230              : 
     231              : #define Z_IRQ_TO_INTERRUPT_VECTOR(irq) \
     232              :         ((unsigned int) _irq_to_interrupt_vector[(irq)])
     233              : 
     234              : 
     235              : #endif /* _ASMLANGUAGE */
     236              : 
     237              : #ifdef __cplusplus
     238              : }
     239              : #endif
     240              : 
     241              : #include <zephyr/drivers/interrupt_controller/sysapic.h>
     242              : 
     243              : #ifdef CONFIG_X86_64
     244              : #include <zephyr/arch/x86/intel64/arch.h>
     245              : #else
     246              : #include <zephyr/arch/x86/ia32/arch.h>
     247              : #endif
     248              : 
     249              : #include <zephyr/arch/common/ffs.h>
     250              : 
     251              : #ifdef __cplusplus
     252              : extern "C" {
     253              : #endif
     254              : 
     255              : #ifndef _ASMLANGUAGE
     256              : 
     257            0 : void arch_irq_enable(unsigned int irq);
     258            0 : void arch_irq_disable(unsigned int irq);
     259              : 
     260            0 : uint32_t sys_clock_cycle_get_32(void);
     261              : 
     262              : __pinned_func
     263            0 : static inline uint32_t arch_k_cycle_get_32(void)
     264              : {
     265              :         return sys_clock_cycle_get_32();
     266              : }
     267              : 
     268            0 : uint64_t sys_clock_cycle_get_64(void);
     269              : 
     270              : __pinned_func
     271            0 : static inline uint64_t arch_k_cycle_get_64(void)
     272              : {
     273              :         return sys_clock_cycle_get_64();
     274              : }
     275              : 
     276            0 : static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key)
     277              : {
     278              :         return (key & 0x200) != 0;
     279              : }
     280              : 
     281              : /**
     282              :  * @brief read timestamp register, 32-bits only, unserialized
     283              :  */
     284              : 
     285              : static ALWAYS_INLINE uint32_t z_do_read_cpu_timestamp32(void)
     286              : {
     287              :         uint32_t rv;
     288              : 
     289              :         __asm__ volatile("rdtsc" : "=a" (rv) : : "%edx");
     290              : 
     291              :         return rv;
     292              : }
     293              : 
     294              : /**
     295              :  *  @brief read timestamp register ensuring serialization
     296              :  */
     297              : 
     298              : __pinned_func
     299              : static inline uint64_t z_tsc_read(void)
     300              : {
     301              :         union {
     302              :                 struct  {
     303              :                         uint32_t lo;
     304              :                         uint32_t hi;
     305              :                 };
     306              :                 uint64_t  value;
     307              :         }  rv;
     308              : 
     309              : #ifdef CONFIG_X86_64
     310              :         /*
     311              :          * According to Intel 64 and IA-32 Architectures Software
     312              :          * Developer’s Manual, volume 3, chapter 8.2.5, LFENCE provides
     313              :          * a more efficient method of controlling memory ordering than
     314              :          * the CPUID instruction. So use LFENCE here, as all 64-bit
     315              :          * CPUs have LFENCE.
     316              :          */
     317              :         __asm__ volatile ("lfence");
     318              : #else
     319              :         /* rdtsc & cpuid clobbers eax, ebx, ecx and edx registers */
     320              :         __asm__ volatile (/* serialize */
     321              :                 "xorl %%eax,%%eax;"
     322              :                 "cpuid"
     323              :                 :
     324              :                 :
     325              :                 : "%eax", "%ebx", "%ecx", "%edx"
     326              :                 );
     327              : #endif
     328              : 
     329              : #ifdef CONFIG_X86_64
     330              :         /*
     331              :          * We cannot use "=A", since this would use %rax on x86_64 and
     332              :          * return only the lower 32bits of the TSC
     333              :          */
     334              :         __asm__ volatile ("rdtsc" : "=a" (rv.lo), "=d" (rv.hi));
     335              : #else
     336              :         /* "=A" means that value is in eax:edx pair. */
     337              :         __asm__ volatile ("rdtsc" : "=A" (rv.value));
     338              : #endif
     339              : 
     340              :         return rv.value;
     341              : }
     342              : 
     343            0 : static ALWAYS_INLINE void arch_nop(void)
     344              : {
     345              :         __asm__ volatile("nop");
     346              : }
     347              : 
     348              : #endif /* _ASMLANGUAGE */
     349              : 
     350              : #ifdef __cplusplus
     351              : }
     352              : #endif
     353              : 
     354              : #endif /* ZEPHYR_INCLUDE_ARCH_X86_ARCH_H_ */
        

Generated by: LCOV version 2.0-1