LCOV - code coverage report
Current view: top level - zephyr/arch/x86/ia32 - segmentation.h Coverage Total Hit
Test: new.info Lines: 1.8 % 114 2
Test Date: 2025-09-05 16:43:28

            Line data    Source code
       1            0 : /*
       2              :  * Copyright (c) 2016 Intel Corporation
       3              :  *
       4              :  * SPDX-License-Identifier: Apache-2.0
       5              :  */
       6              : 
       7              : #ifndef ZEPHYR_INCLUDE_ARCH_X86_IA32_SEGMENTATION_H_
       8              : #define ZEPHYR_INCLUDE_ARCH_X86_IA32_SEGMENTATION_H_
       9              : 
      10              : #include <zephyr/types.h>
      11              : 
      12              : /* Host gen_idt uses this header as well, don't depend on toolchain.h */
      13              : #ifndef __packed
      14              : #define __packed __attribute__((packed))
      15              : #endif
      16              : 
      17              : #ifdef __cplusplus
      18              : extern "C" {
      19              : #endif
      20              : 
      21              : /* NOTE: We currently do not have definitions for 16-bit segment, currently
      22              :  * assume everything we are working with is 32-bit
      23              :  */
      24              : 
      25            0 : #define SEG_TYPE_LDT            0x2
      26            0 : #define SEG_TYPE_TASK_GATE      0x5
      27            0 : #define SEG_TYPE_TSS            0x9
      28            0 : #define SEG_TYPE_TSS_BUSY       0xB
      29            0 : #define SEG_TYPE_CALL_GATE      0xC
      30            0 : #define SEG_TYPE_IRQ_GATE       0xE
      31            0 : #define SEG_TYPE_TRAP_GATE      0xF
      32              : 
      33            0 : #define DT_GRAN_BYTE    0
      34            0 : #define DT_GRAN_PAGE    1
      35              : 
      36            0 : #define DT_READABLE     1
      37            0 : #define DT_NON_READABLE 0
      38              : 
      39            0 : #define DT_WRITABLE     1
      40            0 : #define DT_NON_WRITABLE 0
      41              : 
      42            0 : #define DT_EXPAND_DOWN  1
      43            0 : #define DT_EXPAND_UP    0
      44              : 
      45            0 : #define DT_CONFORM      1
      46            0 : #define DT_NONCONFORM   0
      47              : 
      48            0 : #define DT_TYPE_SYSTEM          0
      49            0 : #define DT_TYPE_CODEDATA        1
      50              : 
      51              : #ifndef _ASMLANGUAGE
      52              : 
      53              : /* Section 8.2.1 of IA architecture SW developer manual, Vol 3. */
      54            0 : struct __packed task_state_segment {
      55            0 :         uint16_t backlink;
      56            0 :         uint16_t reserved_1;
      57            0 :         uint32_t esp0;
      58            0 :         uint16_t ss0;
      59            0 :         uint16_t reserved_2;
      60            0 :         uint32_t esp1;
      61            0 :         uint16_t ss1;
      62            0 :         uint16_t reserved_3;
      63            0 :         uint32_t esp2;
      64            0 :         uint16_t ss2;
      65            0 :         uint16_t reserved_4;
      66            0 :         uint32_t cr3;
      67            0 :         uint32_t eip;
      68            0 :         uint32_t eflags;
      69            0 :         uint32_t eax;
      70            0 :         uint32_t ecx;
      71            0 :         uint32_t edx;
      72            0 :         uint32_t ebx;
      73            0 :         uint32_t esp;
      74            0 :         uint32_t ebp;
      75            0 :         uint32_t esi;
      76            0 :         uint32_t edi;
      77            0 :         uint16_t es;
      78            0 :         uint16_t reserved_5;
      79            0 :         uint16_t cs;
      80            0 :         uint16_t reserved_6;
      81            0 :         uint16_t ss;
      82            0 :         uint16_t reserved_7;
      83            0 :         uint16_t ds;
      84            0 :         uint16_t reserved_8;
      85            0 :         uint16_t fs;
      86            0 :         uint16_t reserved_9;
      87            0 :         uint16_t gs;
      88            0 :         uint16_t reserved_10;
      89            0 :         uint16_t ldt_ss;
      90            0 :         uint16_t reserved_11;
      91            0 :         uint8_t t:1;            /* Trap bit */
      92            0 :         uint16_t reserved_12:15;
      93            0 :         uint16_t iomap;
      94            0 :         uint32_t ssp;
      95              : };
      96              : 
      97            0 : #define SEG_SELECTOR(index, table, dpl) (index << 3 | table << 2 | dpl)
      98              : 
      99              : /* References
     100              :  *
     101              :  * Section 5.8.3 (Call gates)
     102              :  * Section 7.2.2 (TSS Descriptor)
     103              :  * Section 3.4.5 (Segment descriptors)
     104              :  * Section 6.11 (IDT Descriptors)
     105              :  *
     106              :  * IA architecture SW developer manual, Vol 3.
     107              :  */
     108            0 : struct __packed segment_descriptor {
     109              : 
     110              :         /* First DWORD: 0-15 */
     111              :         union {
     112              :                 /* IRQ, call, trap gates */
     113            0 :                 uint16_t limit_low;
     114              : 
     115              :                 /* Task gates */
     116            0 :                 uint16_t reserved_task_gate_0;
     117              : 
     118              :                 /* Everything else */
     119            0 :                 uint16_t offset_low;
     120            0 :         };
     121              : 
     122              :         /* First DWORD: 16-31 */
     123              :         union {
     124              :                 /* Call/Task/Interrupt/Trap gates */
     125            0 :                 uint16_t segment_selector;
     126              : 
     127              :                 /* TSS/LDT/Segments */
     128            0 :                 uint16_t base_low;      /* Bits 0-15 */
     129            0 :         };
     130              : 
     131              :         /* Second DWORD: 0-7 */
     132              :         union {
     133              :                 /* TSS/LDT/Segments */
     134            0 :                 uint8_t base_mid;       /* Bits 16-23 */
     135              : 
     136              :                 /* Task gates */
     137            0 :                 uint8_t reserved_task_gate_1;
     138              : 
     139              :                 /* IRQ/Trap/Call Gates */
     140              :                 struct {
     141              :                         /* Reserved except in case of call gates */
     142            0 :                         uint8_t reserved_or_param:5;
     143              : 
     144              :                         /* Bits 5-7 0 0 0 per CPU manual */
     145            0 :                         uint8_t always_0_0:3;
     146              :                 };
     147            0 :         };
     148              : 
     149              :         /* Second DWORD: 8-15 */
     150              :         union {
     151              :                 /* Code or data Segments */
     152              :                 struct {
     153              :                         /* Set by the processor, init to 0 */
     154            0 :                         uint8_t accessed:1;
     155              : 
     156              :                         /* executable ? readable : writable */
     157            0 :                         uint8_t rw:1;
     158              :                         /* executable ? conforming : direction */
     159            0 :                         uint8_t cd:1;
     160              :                         /* 1=code 0=data */
     161            0 :                         uint8_t executable:1;
     162              : 
     163              :                         /* Next 3 fields actually common to all */
     164              : 
     165              :                         /* 1=code or data, 0=system type */
     166            0 :                         uint8_t descriptor_type:1;
     167              : 
     168            0 :                         uint8_t dpl:2;
     169            0 :                         uint8_t present:1;
     170              :                 };
     171              : 
     172              :                 /* System types */
     173              :                 struct {
     174              :                         /* One of the SEG_TYPE_* macros above */
     175            0 :                         uint8_t type:4;
     176              : 
     177              :                         /* Alas, C doesn't let you do a union of the first
     178              :                          * 4 bits of a bitfield and put the rest outside of it,
     179              :                          * it ends up getting padded.
     180              :                          */
     181            0 :                         uint8_t use_other_union:4;
     182              :                 };
     183            0 :         };
     184              : 
     185              :         /* Second DWORD: 16-31 */
     186              :         union {
     187              :                 /* Call/IRQ/trap gates */
     188            0 :                 uint16_t offset_hi;
     189              : 
     190              :                 /* Task Gates */
     191            0 :                 uint16_t reserved_task_gate_2;
     192              : 
     193              :                 /* segment/LDT/TSS */
     194              :                 struct {
     195            0 :                         uint8_t limit_hi:4;
     196              : 
     197              :                         /* flags */
     198            0 :                         uint8_t avl:1;          /* CPU ignores this */
     199              : 
     200              :                         /* 1=Indicates 64-bit code segment in IA-32e mode */
     201            0 :                         uint8_t flags_l:1; /* L field */
     202              : 
     203            0 :                         uint8_t db:1; /* D/B field 1=32-bit 0=16-bit*/
     204            0 :                         uint8_t granularity:1;
     205              : 
     206            0 :                         uint8_t base_hi;        /* Bits 24-31 */
     207              :                 };
     208            0 :         };
     209              : 
     210              : };
     211              : 
     212              : 
     213              : /* Address of this passed to lidt/lgdt.
     214              :  * IA manual calls this a 'pseudo descriptor'.
     215              :  */
     216            0 : struct __packed pseudo_descriptor {
     217            0 :         uint16_t size;
     218            0 :         struct segment_descriptor *entries;
     219              : };
     220              : 
     221              : 
     222              : /*
     223              :  * Full linear address (segment selector+offset), for far jumps/calls
     224              :  */
     225            0 : struct __packed far_ptr {
     226              :         /** Far pointer offset, unused when invoking a task. */
     227            1 :         void *offset;
     228              :         /** Far pointer segment/gate selector. */
     229            1 :         uint16_t sel;
     230              : };
     231              : 
     232              : 
     233            0 : #define DT_ZERO_ENTRY { { 0 } }
     234              : 
     235              : /* NOTE: the below macros only work for fixed addresses provided at build time.
     236              :  * Base addresses or offsets cannot be &some_variable, as pointer values are not
     237              :  * known until link time and the compiler has to split the address into various
     238              :  * fields in the segment selector well before that.
     239              :  *
     240              :  * If you really need to put &some_variable as the base address in some
     241              :  * segment descriptor, you will either need to do the assignment at runtime
     242              :  * or implement some tool to populate values post-link like gen_idt does.
     243              :  */
     244              : #define _LIMIT_AND_BASE(base_p, limit_p, granularity_p) \
     245              :         .base_low = (((uint32_t)base_p) & 0xFFFF), \
     246              :         .base_mid = (((base_p) >> 16) & 0xFF), \
     247              :         .base_hi = (((base_p) >> 24) & 0xFF), \
     248              :         .limit_low = ((limit_p) & 0xFFFF), \
     249              :         .limit_hi = (((limit_p) >> 16) & 0xF), \
     250              :         .granularity = (granularity_p), \
     251              :         .flags_l = 0, \
     252              :         .db = 1, \
     253              :         .avl = 0
     254              : 
     255              : #define _SEGMENT_AND_OFFSET(segment_p, offset_p) \
     256              :         .segment_selector = (segment_p), \
     257              :         .offset_low = ((offset_p) & 0xFFFF), \
     258              :         .offset_hi = ((offset_p) >> 16)
     259              : 
     260              : #define _DESC_COMMON(dpl_p) \
     261              :         .dpl = (dpl_p), \
     262              :         .present = 1
     263              : 
     264              : #define _SYS_DESC(type_p) \
     265              :         .type = type_p, \
     266              :         .descriptor_type = 0
     267              : 
     268              : #define DT_CODE_SEG_ENTRY(base_p, limit_p, granularity_p, dpl_p, readable_p, \
     269            0 :                        conforming_p) \
     270              :         { \
     271              :                 _DESC_COMMON(dpl_p), \
     272              :                 _LIMIT_AND_BASE(base_p, limit_p, granularity_p), \
     273              :                 .accessed = 0, \
     274              :                 .rw = (readable_p), \
     275              :                 .cd = (conforming_p), \
     276              :                 .executable = 1, \
     277              :                 .descriptor_type = 1 \
     278              :         }
     279              : 
     280              : #define DT_DATA_SEG_ENTRY(base_p, limit_p, granularity_p, dpl_p, writable_p, \
     281            0 :                        direction_p) \
     282              :         { \
     283              :                 _DESC_COMMON(dpl_p), \
     284              :                 _LIMIT_AND_BASE(base_p, limit_p, granularity_p), \
     285              :                 .accessed = 0, \
     286              :                 .rw = (writable_p), \
     287              :                 .cd = (direction_p), \
     288              :                 .executable = 0, \
     289              :                 .descriptor_type = 1 \
     290              :         }
     291              : 
     292            0 : #define DT_LDT_ENTRY(base_p, limit_p, granularity_p, dpl_p) \
     293              :         { \
     294              :                 _DESC_COMMON(dpl_p), \
     295              :                 _LIMIT_AND_BASE(base_p, limit_p, granularity_p), \
     296              :                 _SYS_DESC(SEG_TYPE_LDT) \
     297              :         }
     298              : 
     299            0 : #define DT_TSS_ENTRY(base_p, limit_p, granularity_p, dpl_p) \
     300              :         { \
     301              :                 _DESC_COMMON(dpl_p), \
     302              :                 _LIMIT_AND_BASE(base_p, limit_p, granularity_p), \
     303              :                 _SYS_DESC(SEG_TYPE_TSS) \
     304              :         }
     305              : 
     306              : /* "standard" TSS segments that don't stuff extra data past the end of the
     307              :  * TSS struct
     308              :  */
     309            0 : #define DT_TSS_STD_ENTRY(base_p, dpl_p) \
     310              :         DT_TSS_ENTRY(base_p, sizeof(struct task_state_segment), DT_GRAN_BYTE, \
     311              :                      dpl_p)
     312              : 
     313            0 : #define DT_TASK_GATE_ENTRY(segment_p, dpl_p) \
     314              :         { \
     315              :                 _DESC_COMMON(dpl_p), \
     316              :                 _SYS_DESC(SEG_TYPE_TASK_GATE), \
     317              :                 .segment_selector = (segment_p) \
     318              :         }
     319              : 
     320            0 : #define DT_IRQ_GATE_ENTRY(segment_p, offset_p, dpl_p) \
     321              :         { \
     322              :                 _DESC_COMMON(dpl_p), \
     323              :                 _SEGMENT_AND_OFFSET(segment_p, offset_p), \
     324              :                 _SYS_DESC(SEG_TYPE_IRQ_GATE), \
     325              :                 .always_0_0 = 0 \
     326              :         }
     327              : 
     328            0 : #define DT_TRAP_GATE_ENTRY(segment_p, offset_p, dpl_p) \
     329              :         { \
     330              :                 _DESC_COMMON(dpl_p), \
     331              :                 _SEGMENT_AND_OFFSET(segment_p, offset_p), \
     332              :                 _SYS_DESC(SEG_TYPE_TRAP_GATE), \
     333              :                 .always_0_0 = 0 \
     334              :         }
     335              : 
     336            0 : #define DT_CALL_GATE_ENTRY(segment_p, offset_p, dpl_p, param_count_p) \
     337              :         { \
     338              :                 _DESC_COMMON(dpl_p), \
     339              :                 _SEGMENT_AND_OFFSET(segment_p, offset_p), \
     340              :                 _SYS_DESC(SEG_TYPE_TRAP_GATE), \
     341              :                 .reserved_or_param = (param_count_p), \
     342              :                 .always_0_0 = 0 \
     343              :         }
     344              : 
     345            0 : #define DTE_BASE(dt_entry) ((dt_entry)->base_low | \
     346              :                             ((dt_entry)->base_mid << 16) | \
     347              :                             ((dt_entry)->base_hi << 24))
     348              : 
     349            0 : #define DTE_LIMIT(dt_entry) ((dt_entry)->limit_low | \
     350              :                              ((dt_entry)->limit_hi << 16))
     351              : 
     352            0 : #define DTE_OFFSET(dt_entry) ((dt_entry)->offset_low | \
     353              :                               ((dt_entry)->offset_hi << 16))
     354              : 
     355            0 : #define DT_INIT(entries) { sizeof(entries) - 1, &entries[0] }
     356              : 
     357              : #ifdef CONFIG_SET_GDT
     358              : /* This is either the ROM-based GDT in crt0.S or generated by gen_gdt.py,
     359              :  * depending on CONFIG_GDT_DYNAMIC
     360              :  */
     361              : extern struct pseudo_descriptor _gdt;
     362              : #endif
     363              : 
     364              : extern const struct pseudo_descriptor z_idt;
     365              : 
     366              : /**
     367              :  * Properly set the segment descriptor segment and offset
     368              :  *
     369              :  * Used for call/interrupt/trap gates
     370              :  *
     371              :  * @param sd Segment descriptor
     372              :  * @param offset Offset within segment
     373              :  * @param segment_selector Segment selector
     374              :  */
     375              : static inline void z_sd_set_seg_offset(struct segment_descriptor *sd,
     376              :                                       uint16_t segment_selector,
     377              :                                       uint32_t offset)
     378              : {
     379              :         sd->offset_low = offset & 0xFFFFU;
     380              :         sd->offset_hi = offset >> 16U;
     381              :         sd->segment_selector = segment_selector;
     382              :         sd->always_0_0 = 0U;
     383              : }
     384              : 
     385              : 
     386              : /**
     387              :  * Initialize an segment descriptor to be a 32-bit IRQ gate
     388              :  *
     389              :  * @param sd Segment descriptor memory
     390              :  * @param seg_selector Segment selector of handler
     391              :  * @param offset offset of handler
     392              :  * @param dpl descriptor privilege level
     393              :  */
     394              : static inline void z_init_irq_gate(struct segment_descriptor *sd,
     395              :                                   uint16_t seg_selector, uint32_t offset,
     396              :                                   uint32_t dpl)
     397              : {
     398              :         z_sd_set_seg_offset(sd, seg_selector, offset);
     399              :         sd->dpl = dpl;
     400              :         sd->descriptor_type = DT_TYPE_SYSTEM;
     401              :         sd->present = 1U;
     402              :         sd->type = SEG_TYPE_IRQ_GATE;
     403              : }
     404              : 
     405              : /**
     406              :  * Set current IA task TSS
     407              :  *
     408              :  * @param sel Segment selector in GDT for desired TSS
     409              :  */
     410              : static inline void _set_tss(uint16_t sel)
     411              : {
     412              :         __asm__ __volatile__ ("ltr %0" :: "r" (sel));
     413              : }
     414              : 
     415              : 
     416              : /**
     417              :  * Get the TSS segment selector in the GDT for the current IA task
     418              :  *
     419              :  * @return Segment selector for current IA task
     420              :  */
     421              : static inline uint16_t _get_tss(void)
     422              : {
     423              :         uint16_t sel;
     424              : 
     425              :         __asm__ __volatile__ ("str %0" : "=r" (sel));
     426              :         return sel;
     427              : }
     428              : 
     429              : 
     430              : /**
     431              :  * Get the current global descriptor table
     432              :  *
     433              :  * @param gdt Pointer to memory to receive GDT pseudo descriptor information
     434              :  */
     435              : static inline void _get_gdt(struct pseudo_descriptor *gdt)
     436              : {
     437              :         __asm__ __volatile__ ("sgdt %0" : "=m" (*gdt));
     438              : }
     439              : 
     440              : 
     441              : /**
     442              :  * Get the current interrupt descriptor table
     443              :  *
     444              :  * @param idt Pointer to memory to receive IDT pseudo descriptor information
     445              :  */
     446              : static inline void _get_idt(struct pseudo_descriptor *idt)
     447              : {
     448              :         __asm__ __volatile__ ("sidt %0" : "=m" (*idt));
     449              : }
     450              : 
     451              : 
     452              : /**
     453              :  * Get the current local descriptor table (LDT)
     454              :  *
     455              :  * @return Segment selector in the GDT for the current LDT
     456              :  */
     457              : static inline uint16_t _get_ldt(void)
     458              : {
     459              :         uint16_t ret;
     460              : 
     461              :         __asm__ __volatile__ ("sldt %0" : "=m" (ret));
     462              :         return ret;
     463              : }
     464              : 
     465              : 
     466              : /**
     467              :  * Set the local descriptor table for the current IA Task
     468              :  *
     469              :  * @param ldt Segment selector in the GDT for an LDT
     470              :  */
     471              : static inline void _set_ldt(uint16_t ldt)
     472              : {
     473              :         __asm__ __volatile__ ("lldt %0" :: "m" (ldt));
     474              : 
     475              : }
     476              : 
     477              : /**
     478              :  * Set the global descriptor table
     479              :  *
     480              :  * You will most likely need to update all the data segment registers
     481              :  * and do a far call to the code segment.
     482              :  *
     483              :  * @param gdt Pointer to GDT pseudo descriptor.
     484              :  */
     485              : static inline void _set_gdt(const struct pseudo_descriptor *gdt)
     486              : {
     487              :         __asm__ __volatile__ ("lgdt %0" :: "m" (*gdt));
     488              : }
     489              : 
     490              : 
     491              : /**
     492              :  * Set the interrupt descriptor table
     493              :  *
     494              :  * @param idt Pointer to IDT pseudo descriptor.
     495              :  */
     496              : static inline void z_set_idt(const struct pseudo_descriptor *idt)
     497              : {
     498              :         __asm__ __volatile__ ("lidt %0" :: "m" (*idt));
     499              : }
     500              : 
     501              : 
     502              : /**
     503              :  * Get the segment selector for the current code segment
     504              :  *
     505              :  * @return Segment selector
     506              :  */
     507              : static inline uint16_t _get_cs(void)
     508              : {
     509              :         uint16_t cs = 0U;
     510              : 
     511              :         __asm__ __volatile__ ("mov %%cs, %0" : "=r" (cs));
     512              :         return cs;
     513              : }
     514              : 
     515              : 
     516              : /**
     517              :  * Get the segment selector for the current data segment
     518              :  *
     519              :  * @return Segment selector
     520              :  */
     521              : static inline uint16_t _get_ds(void)
     522              : {
     523              :         uint16_t ds = 0U;
     524              : 
     525              :         __asm__ __volatile__ ("mov %%ds, %0" : "=r" (ds));
     526              :         return ds;
     527              : }
     528              : 
     529              : 
     530              : #endif /* _ASMLANGUAGE */
     531              : 
     532              : #ifdef __cplusplus
     533              : }
     534              : #endif
     535              : 
     536              : #endif /* ZEPHYR_INCLUDE_ARCH_X86_IA32_SEGMENTATION_H_ */
        

Generated by: LCOV version 2.0-1