2008-10-22 22:26:29 -07:00
# ifndef _ASM_X86_SEGMENT_H
# define _ASM_X86_SEGMENT_H
2008-01-30 13:31:09 +01:00
2011-02-14 18:33:55 -08:00
# include <linux/const.h>
2015-03-24 20:45:42 +01:00
/*
* Constructor for a conventional segment GDT ( or LDT ) entry .
* This is a macro so it can be used in initializers .
*/
2008-07-17 11:29:24 -07:00
# define GDT_ENTRY(flags, base, limit) \
2011-02-14 18:33:55 -08:00
( ( ( ( base ) & _AC ( 0xff000000 , ULL ) ) < < ( 56 - 24 ) ) | \
( ( ( flags ) & _AC ( 0x0000f0ff , ULL ) ) < < 40 ) | \
( ( ( limit ) & _AC ( 0x000f0000 , ULL ) ) < < ( 48 - 16 ) ) | \
( ( ( base ) & _AC ( 0x00ffffff , ULL ) ) < < 16 ) | \
( ( ( limit ) & _AC ( 0x0000ffff , ULL ) ) ) )
2008-07-17 11:29:24 -07:00
2015-03-24 20:45:42 +01:00
/* Simple and small GDT entries for booting only: */
2008-01-30 13:33:01 +01:00
# define GDT_ENTRY_BOOT_CS 2
2015-03-22 22:01:12 +01:00
# define GDT_ENTRY_BOOT_DS 3
# define GDT_ENTRY_BOOT_TSS 4
2015-03-24 20:45:42 +01:00
# define __BOOT_CS (GDT_ENTRY_BOOT_CS*8)
# define __BOOT_DS (GDT_ENTRY_BOOT_DS*8)
# define __BOOT_TSS (GDT_ENTRY_BOOT_TSS*8)
/*
* Bottom two bits of selector give the ring
* privilege level
*/
# define SEGMENT_RPL_MASK 0x3
/* User mode is privilege level 3: */
# define USER_RPL 0x3
/* Bit 2 is Table Indicator (TI): selects between LDT or GDT */
# define SEGMENT_TI_MASK 0x4
/* LDT segment has TI set ... */
# define SEGMENT_LDT 0x4
/* ... GDT has it cleared */
# define SEGMENT_GDT 0x0
2014-12-09 13:25:59 +01:00
2015-04-03 14:25:28 +02:00
# define GDT_ENTRY_INVALID_SEG 0
2007-10-11 11:20:03 +02:00
# ifdef CONFIG_X86_32
2008-01-30 13:31:09 +01:00
/*
* The layout of the per - CPU GDT under Linux :
*
2015-03-24 20:45:42 +01:00
* 0 - null < = = = cacheline # 1
2008-01-30 13:31:09 +01:00
* 1 - reserved
* 2 - reserved
* 3 - reserved
*
2015-03-24 20:45:42 +01:00
* 4 - unused < = = = cacheline # 2
2008-01-30 13:31:09 +01:00
* 5 - unused
*
* - - - - - - - start of TLS ( Thread - Local Storage ) segments :
*
* 6 - TLS segment # 1 [ glibc ' s TLS segment ]
* 7 - TLS segment # 2 [ Wine ' s % fs Win32 segment ]
2015-03-24 20:45:42 +01:00
* 8 - TLS segment # 3 < = = = cacheline # 3
2008-01-30 13:31:09 +01:00
* 9 - reserved
* 10 - reserved
* 11 - reserved
*
* - - - - - - - start of kernel segments :
*
2015-03-24 20:45:42 +01:00
* 12 - kernel code segment < = = = cacheline # 4
2008-01-30 13:31:09 +01:00
* 13 - kernel data segment
* 14 - default user CS
* 15 - default user DS
2015-03-24 20:45:42 +01:00
* 16 - TSS < = = = cacheline # 5
2008-01-30 13:31:09 +01:00
* 17 - LDT
* 18 - PNPBIOS support ( 16 - > 32 gate )
* 19 - PNPBIOS support
2015-03-24 20:45:42 +01:00
* 20 - PNPBIOS support < = = = cacheline # 6
2008-01-30 13:31:09 +01:00
* 21 - PNPBIOS support
* 22 - PNPBIOS support
* 23 - APM BIOS support
2015-03-24 20:45:42 +01:00
* 24 - APM BIOS support < = = = cacheline # 7
2008-01-30 13:31:09 +01:00
* 25 - APM BIOS support
*
* 26 - ESPFIX small SS
* 27 - per - cpu [ offset to per - cpu data area ]
2015-03-24 20:45:42 +01:00
* 28 - stack_canary - 20 [ for stack protector ] < = = = cacheline # 8
2008-01-30 13:31:09 +01:00
* 29 - unused
* 30 - unused
* 31 - TSS for double fault handler
*/
2015-03-24 20:45:42 +01:00
# define GDT_ENTRY_TLS_MIN 6
# define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1)
2008-01-30 13:31:09 +01:00
2015-03-22 22:01:12 +01:00
# define GDT_ENTRY_KERNEL_CS 12
# define GDT_ENTRY_KERNEL_DS 13
2008-01-30 13:31:09 +01:00
# define GDT_ENTRY_DEFAULT_USER_CS 14
# define GDT_ENTRY_DEFAULT_USER_DS 15
2015-03-22 22:01:12 +01:00
# define GDT_ENTRY_TSS 16
# define GDT_ENTRY_LDT 17
# define GDT_ENTRY_PNPBIOS_CS32 18
# define GDT_ENTRY_PNPBIOS_CS16 19
# define GDT_ENTRY_PNPBIOS_DS 20
# define GDT_ENTRY_PNPBIOS_TS1 21
# define GDT_ENTRY_PNPBIOS_TS2 22
# define GDT_ENTRY_APMBIOS_BASE 23
# define GDT_ENTRY_ESPFIX_SS 26
# define GDT_ENTRY_PERCPU 27
# define GDT_ENTRY_STACK_CANARY 28
2008-01-30 13:31:09 +01:00
2015-03-22 22:01:12 +01:00
# define GDT_ENTRY_DOUBLEFAULT_TSS 31
2008-01-30 13:31:09 +01:00
2015-03-24 20:45:42 +01:00
/*
* Number of entries in the GDT table :
*/
# define GDT_ENTRIES 32
/*
* Segment selector values corresponding to the above entries :
*/
2015-03-22 22:01:12 +01:00
# define __KERNEL_CS (GDT_ENTRY_KERNEL_CS*8)
# define __KERNEL_DS (GDT_ENTRY_KERNEL_DS*8)
2015-03-24 20:45:42 +01:00
# define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS*8 + 3)
# define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS*8 + 3)
2010-10-19 14:52:26 +01:00
# define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS*8)
2015-03-24 20:45:42 +01:00
/* segment for calling fn: */
# define PNP_CS32 (GDT_ENTRY_PNPBIOS_CS32*8)
/* code segment for BIOS: */
# define PNP_CS16 (GDT_ENTRY_PNPBIOS_CS16*8)
2015-03-22 22:01:12 +01:00
/* "Is this PNP code selector (PNP_CS32 or PNP_CS16)?" */
2015-03-24 20:45:42 +01:00
# define SEGMENT_IS_PNP_CODE(x) (((x) & 0xf4) == PNP_CS32)
/* data segment for BIOS: */
# define PNP_DS (GDT_ENTRY_PNPBIOS_DS*8)
/* transfer data segment: */
# define PNP_TS1 (GDT_ENTRY_PNPBIOS_TS1*8)
/* another data segment: */
# define PNP_TS2 (GDT_ENTRY_PNPBIOS_TS2*8)
2008-01-30 13:31:09 +01:00
# ifdef CONFIG_SMP
2015-03-24 20:45:42 +01:00
# define __KERNEL_PERCPU (GDT_ENTRY_PERCPU*8)
2008-01-30 13:31:09 +01:00
# else
2015-03-24 20:45:42 +01:00
# define __KERNEL_PERCPU 0
2008-01-30 13:31:09 +01:00
# endif
2015-03-24 20:45:42 +01:00
2009-02-09 22:17:40 +09:00
# ifdef CONFIG_CC_STACKPROTECTOR
2015-03-24 20:45:42 +01:00
# define __KERNEL_STACK_CANARY (GDT_ENTRY_STACK_CANARY*8)
2009-02-09 22:17:40 +09:00
# else
2015-03-24 20:45:42 +01:00
# define __KERNEL_STACK_CANARY 0
2009-02-09 22:17:40 +09:00
# endif
2015-03-22 22:01:12 +01:00
# else /* 64-bit: */
2008-01-30 13:31:09 +01:00
# include <asm/cache.h>
2015-03-24 20:45:42 +01:00
# define GDT_ENTRY_KERNEL32_CS 1
# define GDT_ENTRY_KERNEL_CS 2
# define GDT_ENTRY_KERNEL_DS 3
2008-01-30 13:31:09 +01:00
/*
2015-03-24 20:45:42 +01:00
* We cannot use the same code segment descriptor for user and kernel mode ,
* not even in long flat mode , because of different DPL .
*
* GDT layout to get 64 - bit SYSCALL / SYSRET support right . SYSRET hardcodes
* selectors :
*
* if returning to 32 - bit userspace : cs = STAR . SYSRET_CS ,
* if returning to 64 - bit userspace : cs = STAR . SYSRET_CS + 16 ,
*
2015-03-22 22:01:12 +01:00
* ss = STAR . SYSRET_CS + 8 ( in either case )
2015-03-24 20:45:42 +01:00
*
2015-03-22 22:01:12 +01:00
* thus USER_DS should be between 32 - bit and 64 - bit code selectors :
2008-01-30 13:31:09 +01:00
*/
2015-03-24 20:45:42 +01:00
# define GDT_ENTRY_DEFAULT_USER32_CS 4
# define GDT_ENTRY_DEFAULT_USER_DS 5
# define GDT_ENTRY_DEFAULT_USER_CS 6
/* Needs two entries */
# define GDT_ENTRY_TSS 8
/* Needs two entries */
# define GDT_ENTRY_LDT 10
2008-01-30 13:31:09 +01:00
2015-03-24 20:45:42 +01:00
# define GDT_ENTRY_TLS_MIN 12
# define GDT_ENTRY_TLS_MAX 14
2008-01-30 13:31:09 +01:00
2015-03-24 20:45:42 +01:00
/* Abused to load per CPU data from limit */
# define GDT_ENTRY_PER_CPU 15
2015-03-22 22:01:12 +01:00
2015-03-24 20:45:42 +01:00
/*
* Number of entries in the GDT table :
*/
# define GDT_ENTRIES 16
2008-01-30 13:31:09 +01:00
2015-03-24 20:45:42 +01:00
/*
* Segment selector values corresponding to the above entries :
*
* Note , selectors also need to have a correct RPL ,
* expressed with the + 3 value for user - space selectors :
*/
# define __KERNEL32_CS (GDT_ENTRY_KERNEL32_CS*8)
# define __KERNEL_CS (GDT_ENTRY_KERNEL_CS*8)
# define __KERNEL_DS (GDT_ENTRY_KERNEL_DS*8)
# define __USER32_CS (GDT_ENTRY_DEFAULT_USER32_CS*8 + 3)
# define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS*8 + 3)
# define __USER32_DS __USER_DS
# define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS*8 + 3)
# define __PER_CPU_SEG (GDT_ENTRY_PER_CPU*8 + 3)
2008-01-30 13:31:09 +01:00
2015-03-24 20:45:42 +01:00
/* TLS indexes for 64-bit - hardcoded in arch_prctl(): */
# define FS_TLS 0
# define GS_TLS 1
2008-01-30 13:31:09 +01:00
2015-03-24 20:45:42 +01:00
# define GS_TLS_SEL ((GDT_ENTRY_TLS_MIN+GS_TLS)*8 + 3)
# define FS_TLS_SEL ((GDT_ENTRY_TLS_MIN+FS_TLS)*8 + 3)
2008-01-30 13:31:09 +01:00
2007-10-11 11:20:03 +02:00
# endif
2008-01-30 13:31:09 +01:00
# ifndef CONFIG_PARAVIRT
2015-03-24 20:45:42 +01:00
# define get_kernel_rpl() 0
2008-01-30 13:31:09 +01:00
# endif
2015-03-24 20:45:42 +01:00
# define IDT_ENTRIES 256
# define NUM_EXCEPTION_VECTORS 32
/* Bitmask of exception vectors which push an error code on the stack: */
# define EXCEPTION_ERRCODE_MASK 0x00027d00
# define GDT_SIZE (GDT_ENTRIES*8)
# define GDT_ENTRY_TLS_ENTRIES 3
# define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES* 8)
2008-01-30 13:31:09 +01:00
2008-01-30 13:33:06 +01:00
# ifdef __KERNEL__
2015-05-22 16:15:47 -07:00
/*
* early_idt_handler_array is an array of entry points referenced in the
* early IDT . For simplicity , it ' s a real array with one entry point
* every nine bytes . That leaves room for an optional ' push $ 0 ' if the
* vector has no error code ( two bytes ) , a ' push $ vector_number ' ( two
* bytes ) , and a jump to the common entry code ( up to five bytes ) .
*/
# define EARLY_IDT_HANDLER_SIZE 9
2008-01-30 13:33:06 +01:00
# ifndef __ASSEMBLY__
2015-03-24 20:45:42 +01:00
2015-05-22 16:15:47 -07:00
extern const char early_idt_handler_array [ NUM_EXCEPTION_VECTORS ] [ EARLY_IDT_HANDLER_SIZE ] ;
2013-10-30 16:37:00 -04:00
# ifdef CONFIG_TRACING
2015-05-22 16:15:47 -07:00
# define trace_early_idt_handler_array early_idt_handler_array
2013-10-30 16:37:00 -04:00
# endif
2012-03-28 18:11:12 +01:00
/*
* Load a segment . Fall back on loading the zero
* segment if something goes wrong . .
*/
# define loadsegment(seg, value) \
do { \
unsigned short __val = ( value ) ; \
\
asm volatile ( " \n " \
" 1: movl %k0,%% " # seg " \n " \
\
" .section .fixup, \" ax \" \n " \
" 2: xorl %k0,%k0 \n " \
" jmp 1b \n " \
" .previous \n " \
\
_ASM_EXTABLE ( 1 b , 2 b ) \
\
: " +r " ( __val ) : : " memory " ) ; \
} while ( 0 )
/*
2015-03-24 20:45:42 +01:00
* Save a segment register away :
2012-03-28 18:11:12 +01:00
*/
# define savesegment(seg, value) \
asm ( " mov %% " # seg " ,%0 " : " =r " ( value ) : : " memory " )
/*
2015-03-24 20:45:42 +01:00
* x86 - 32 user GS accessors :
2012-03-28 18:11:12 +01:00
*/
# ifdef CONFIG_X86_32
2015-03-24 20:45:42 +01:00
# ifdef CONFIG_X86_32_LAZY_GS
# define get_user_gs(regs) (u16)({ unsigned long v; savesegment(gs, v); v; })
# define set_user_gs(regs, v) loadsegment(gs, (unsigned long)(v))
# define task_user_gs(tsk) ((tsk)->thread.gs)
# define lazy_save_gs(v) savesegment(gs, (v))
# define lazy_load_gs(v) loadsegment(gs, (v))
# else /* X86_32_LAZY_GS */
# define get_user_gs(regs) (u16)((regs)->gs)
# define set_user_gs(regs, v) do { (regs)->gs = (v); } while (0)
# define task_user_gs(tsk) (task_pt_regs(tsk)->gs)
# define lazy_save_gs(v) do { } while (0)
# define lazy_load_gs(v) do { } while (0)
# endif /* X86_32_LAZY_GS */
2012-03-28 18:11:12 +01:00
# endif /* X86_32 */
# endif /* !__ASSEMBLY__ */
# endif /* __KERNEL__ */
2008-01-30 13:33:06 +01:00
2008-10-22 22:26:29 -07:00
# endif /* _ASM_X86_SEGMENT_H */