2005-04-17 02:20:36 +04:00
/* Written 2000 by Andi Kleen */
# ifndef __ARCH_DESC_H
# define __ARCH_DESC_H
# include <linux/threads.h>
# include <asm/ldt.h>
# ifndef __ASSEMBLY__
# include <linux/string.h>
2005-09-17 06:27:55 +04:00
# include <linux/smp.h>
2006-12-07 04:14:04 +03:00
# include <asm/desc_defs.h>
2005-09-17 06:27:55 +04:00
2005-04-17 02:20:36 +04:00
# include <asm/segment.h>
# include <asm/mmu.h>
2006-01-12 00:43:57 +03:00
extern struct desc_struct cpu_gdt_table [ GDT_ENTRIES ] ;
2005-04-17 02:20:36 +04:00
# define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8))
# define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8))
# define clear_LDT() asm volatile("lldt %w0"::"r" (0))
/*
* This is the ldt that every process will get unless we need
* something other than this .
*/
extern struct desc_struct default_ldt [ ] ;
extern struct gate_struct idt_table [ ] ;
2005-07-29 08:15:30 +04:00
extern struct desc_ptr cpu_gdt_descr [ ] ;
2005-04-17 02:20:36 +04:00
2006-01-12 00:43:57 +03:00
/* the cpu gdt accessor */
# define cpu_gdt(_cpu) ((struct desc_struct *)cpu_gdt_descr[_cpu].address)
2005-04-17 02:20:36 +04:00
static inline void _set_gate ( void * adr , unsigned type , unsigned long func , unsigned dpl , unsigned ist )
{
struct gate_struct s ;
s . offset_low = PTR_LOW ( func ) ;
s . segment = __KERNEL_CS ;
s . ist = ist ;
s . p = 1 ;
s . dpl = dpl ;
s . zero0 = 0 ;
s . zero1 = 0 ;
s . type = type ;
s . offset_middle = PTR_MIDDLE ( func ) ;
s . offset_high = PTR_HIGH ( func ) ;
/* does not need to be atomic because it is only done once at setup time */
memcpy ( adr , & s , 16 ) ;
}
static inline void set_intr_gate ( int nr , void * func )
{
2005-11-05 19:25:53 +03:00
BUG_ON ( ( unsigned ) nr > 0xFF ) ;
2005-04-17 02:20:36 +04:00
_set_gate ( & idt_table [ nr ] , GATE_INTERRUPT , ( unsigned long ) func , 0 , 0 ) ;
}
static inline void set_intr_gate_ist ( int nr , void * func , unsigned ist )
{
2005-11-05 19:25:53 +03:00
BUG_ON ( ( unsigned ) nr > 0xFF ) ;
2005-04-17 02:20:36 +04:00
_set_gate ( & idt_table [ nr ] , GATE_INTERRUPT , ( unsigned long ) func , 0 , ist ) ;
}
static inline void set_system_gate ( int nr , void * func )
{
2005-11-05 19:25:53 +03:00
BUG_ON ( ( unsigned ) nr > 0xFF ) ;
2005-04-17 02:20:36 +04:00
_set_gate ( & idt_table [ nr ] , GATE_INTERRUPT , ( unsigned long ) func , 3 , 0 ) ;
}
2006-01-12 00:43:00 +03:00
static inline void set_system_gate_ist ( int nr , void * func , unsigned ist )
{
_set_gate ( & idt_table [ nr ] , GATE_INTERRUPT , ( unsigned long ) func , 3 , ist ) ;
}
2005-04-17 02:20:36 +04:00
static inline void set_tssldt_descriptor ( void * ptr , unsigned long tss , unsigned type ,
unsigned size )
{
struct ldttss_desc d ;
memset ( & d , 0 , sizeof ( d ) ) ;
d . limit0 = size & 0xFFFF ;
d . base0 = PTR_LOW ( tss ) ;
d . base1 = PTR_MIDDLE ( tss ) & 0xFF ;
d . type = type ;
d . p = 1 ;
d . limit1 = ( size > > 16 ) & 0xF ;
d . base2 = ( PTR_MIDDLE ( tss ) > > 8 ) & 0xFF ;
d . base3 = PTR_HIGH ( tss ) ;
memcpy ( ptr , & d , 16 ) ;
}
static inline void set_tss_desc ( unsigned cpu , void * addr )
{
2005-11-14 03:06:21 +03:00
/*
* sizeof ( unsigned long ) coming from an extra " long " at the end
* of the iobitmap . See tss_struct definition in processor . h
*
* - 1 ? seg base + limit should be pointing to the address of the
* last valid byte
*/
2006-01-12 00:43:57 +03:00
set_tssldt_descriptor ( & cpu_gdt ( cpu ) [ GDT_ENTRY_TSS ] ,
2005-11-14 03:06:21 +03:00
( unsigned long ) addr , DESC_TSS ,
IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof ( unsigned long ) - 1 ) ;
2005-04-17 02:20:36 +04:00
}
static inline void set_ldt_desc ( unsigned cpu , void * addr , int size )
{
2006-01-12 00:43:57 +03:00
set_tssldt_descriptor ( & cpu_gdt ( cpu ) [ GDT_ENTRY_LDT ] , ( unsigned long ) addr ,
2005-04-17 02:20:36 +04:00
DESC_LDT , size * 8 - 1 ) ;
}
static inline void set_seg_base ( unsigned cpu , int entry , void * base )
{
2006-01-12 00:43:57 +03:00
struct desc_struct * d = & cpu_gdt ( cpu ) [ entry ] ;
2005-04-17 02:20:36 +04:00
u32 addr = ( u32 ) ( u64 ) base ;
BUG_ON ( ( u64 ) base > > 32 ) ;
d - > base0 = addr & 0xffff ;
d - > base1 = ( addr > > 16 ) & 0xff ;
d - > base2 = ( addr > > 24 ) & 0xff ;
}
# define LDT_entry_a(info) \
( ( ( ( info ) - > base_addr & 0x0000ffff ) < < 16 ) | ( ( info ) - > limit & 0x0ffff ) )
/* Don't allow setting of the lm bit. It is useless anyways because
64 bit system calls require __USER_CS . */
# define LDT_entry_b(info) \
( ( ( info ) - > base_addr & 0xff000000 ) | \
( ( ( info ) - > base_addr & 0x00ff0000 ) > > 16 ) | \
( ( info ) - > limit & 0xf0000 ) | \
( ( ( info ) - > read_exec_only ^ 1 ) < < 9 ) | \
( ( info ) - > contents < < 10 ) | \
( ( ( info ) - > seg_not_present ^ 1 ) < < 15 ) | \
( ( info ) - > seg_32bit < < 22 ) | \
( ( info ) - > limit_in_pages < < 23 ) | \
( ( info ) - > useable < < 20 ) | \
/* ((info)->lm << 21) | */ \
0x7000 )
# define LDT_empty(info) (\
( info ) - > base_addr = = 0 & & \
( info ) - > limit = = 0 & & \
( info ) - > contents = = 0 & & \
( info ) - > read_exec_only = = 1 & & \
( info ) - > seg_32bit = = 0 & & \
( info ) - > limit_in_pages = = 0 & & \
( info ) - > seg_not_present = = 1 & & \
( info ) - > useable = = 0 & & \
( info ) - > lm = = 0 )
# if TLS_SIZE != 24
# error update this code.
# endif
static inline void load_TLS ( struct thread_struct * t , unsigned int cpu )
{
2006-01-12 00:43:57 +03:00
u64 * gdt = ( u64 * ) ( cpu_gdt ( cpu ) + GDT_ENTRY_TLS_MIN ) ;
2005-04-17 02:20:36 +04:00
gdt [ 0 ] = t - > tls_array [ 0 ] ;
gdt [ 1 ] = t - > tls_array [ 1 ] ;
gdt [ 2 ] = t - > tls_array [ 2 ] ;
}
/*
* load one particular LDT into the current CPU
*/
2005-09-12 20:49:24 +04:00
static inline void load_LDT_nolock ( mm_context_t * pc , int cpu )
2005-04-17 02:20:36 +04:00
{
int count = pc - > size ;
if ( likely ( ! count ) ) {
clear_LDT ( ) ;
return ;
}
set_ldt_desc ( cpu , pc - > ldt , count ) ;
load_LDT_desc ( ) ;
}
static inline void load_LDT ( mm_context_t * pc )
{
int cpu = get_cpu ( ) ;
load_LDT_nolock ( pc , cpu ) ;
put_cpu ( ) ;
}
extern struct desc_ptr idt_descr ;
# endif /* !__ASSEMBLY__ */
# endif