==== //depot/projects/linuxolator/src/sys/amd64/amd64/cpu_switch.S#2 - /home/jkim/p4/linuxolator/src/sys/amd64/amd64/cpu_switch.S ==== @@ -183,22 +183,26 @@ rdmsr movl PCB_GS(%r8),%gs wrmsr + + testl $PCB_GS32,PCB_FLAGS(%r8) + jz 3f /* no, skip over */ jmp 2f + 1: - /* Restore userland %fs */ movl $MSR_FSBASE,%ecx movl PCB_FSBASE(%r8),%eax movl PCB_FSBASE+4(%r8),%edx wrmsr +2: /* Restore userland %gs */ movl $MSR_KGSBASE,%ecx movl PCB_GSBASE(%r8),%eax movl PCB_GSBASE+4(%r8),%edx wrmsr -2: +3: /* Update the TSS_RSP0 pointer for the next interrupt */ movq PCPU(TSSP), %rax addq $COMMON_TSS_RSP0, %rax ==== //depot/projects/linuxolator/src/sys/amd64/amd64/genassym.c#4 - /home/jkim/p4/linuxolator/src/sys/amd64/amd64/genassym.c ==== @@ -136,6 +136,7 @@ ASSYM(PCB_DR7, offsetof(struct pcb, pcb_dr7)); ASSYM(PCB_DBREGS, PCB_DBREGS); ASSYM(PCB_32BIT, PCB_32BIT); +ASSYM(PCB_GS32, PCB_GS32); ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags)); ASSYM(PCB_FULLCTX, PCB_FULLCTX); ==== //depot/projects/linuxolator/src/sys/amd64/amd64/machdep.c#11 - /home/jkim/p4/linuxolator/src/sys/amd64/amd64/machdep.c ==== @@ -156,7 +156,7 @@ extern vm_offset_t ksym_start, ksym_end; #endif -int _udatasel, _ucodesel, _ucode32sel; +int _udatasel, _ucodesel, _ucode32sel, _ugs32sel; int cold = 1; @@ -725,6 +725,15 @@ 0, /* long */ 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, +/* GUGS32_SEL 8 32 bit GS Descriptor for user */ +{ 0x0, /* segment base address */ + 0xfffff, /* length - all address space */ + SDT_MEMRWA, /* segment type */ + SEL_UPL, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, /* long */ + 1, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, }; void @@ -1279,6 +1288,7 @@ _ucodesel = GSEL(GUCODE_SEL, SEL_UPL); _udatasel = GSEL(GUDATA_SEL, SEL_UPL); _ucode32sel = GSEL(GUCODE32_SEL, SEL_UPL); + _ugs32sel = GSEL(GUGS32_SEL, SEL_UPL); /* setup proc 0's pcb */ thread0.td_pcb->pcb_flags = 0; /* XXXKSE */ ==== //depot/projects/linuxolator/src/sys/amd64/include/pcb.h#1 - /home/jkim/p4/linuxolator/src/sys/amd64/include/pcb.h ==== @@ -67,10 +67,11 @@ struct savefpu pcb_save; u_long pcb_flags; -#define PCB_DBREGS 0x02 /* process using debug registers */ -#define PCB_FPUINITDONE 0x08 /* fpu state is initialized */ -#define PCB_32BIT 0x40 /* process has 32 bit context (segs etc) */ -#define PCB_FULLCTX 0x80 /* full context restore on sysret */ +#define PCB_DBREGS 0x0002 /* process using debug registers */ +#define PCB_FPUINITDONE 0x0008 /* fpu state is initialized */ +#define PCB_32BIT 0x0040 /* process has 32 bit context (segs etc) */ +#define PCB_FULLCTX 0x0080 /* full context restore on sysret */ +#define PCB_GS32 0x0100 /* process has 32 bit GS context */ caddr_t pcb_onfault; /* copyin/out fault recovery */ }; ==== //depot/projects/linuxolator/src/sys/amd64/include/segments.h#1 - /home/jkim/p4/linuxolator/src/sys/amd64/include/segments.h ==== @@ -200,9 +200,10 @@ #define GUCODE32_SEL 3 /* User 32 bit code Descriptor */ #define GUDATA_SEL 4 /* User 32/64 bit Data Descriptor */ #define GUCODE_SEL 5 /* User 64 bit Code Descriptor */ -#define GPROC0_SEL 6 /* TSS for entering kernel etc */ +#define GPROC0_SEL 6 /* TSS for entering kernel etc */ /* slot 6 is second half of GPROC0_SEL */ -#define NGDT 8 +#define GUGS32_SEL 8 /* User 32 bit GS Descriptor */ +#define NGDT 9 #ifdef _KERNEL extern struct user_segment_descriptor gdt[]; ==== //depot/projects/linuxolator/src/sys/amd64/linux32/linux.h#14 - /home/jkim/p4/linuxolator/src/sys/amd64/linux32/linux.h ==== @@ -768,7 +768,6 @@ l_uint limit_in_pages:1; l_uint seg_not_present:1; l_uint useable:1; - l_uint lm:1; }; struct l_desc_struct { @@ -792,7 +791,6 @@ #define ENTRY_B_USEABLE 20 #define ENTRY_B_SEG32BIT 22 #define ENTRY_B_LIMIT 23 -#define ENTRY_B_LONGMODE 21 #define LDT_entry_b(info) \ (((info)->base_addr & 0xff000000) | \ @@ -813,8 +811,7 @@ (info)->read_exec_only == 1 && \ (info)->seg_32bit == 0 && \ (info)->limit_in_pages == 0 && \ - (info)->useable == 0 && \ - (info)->lm == 0) + (info)->useable == 0 ) /* macros for converting segments, they do the same as those in arch/i386/kernel/process.c */ #define GET_BASE(desc) ( \ @@ -832,7 +829,6 @@ #define GET_LIMIT_PAGES(desc) (((desc)->b >> ENTRY_B_LIMIT) & 1) #define GET_PRESENT(desc) (((desc)->b >> ENTRY_B_SEG_NOT_PRESENT) & 1) #define GET_USEABLE(desc) (((desc)->b >> ENTRY_B_USEABLE) & 1) -#define GET_LONGMODE(desc) (((desc)->b >> ENTRY_B_LONGMODE) & 1) #define LINUX_CLOCK_REALTIME 0 #define LINUX_CLOCK_MONOTONIC 1 ==== //depot/projects/linuxolator/src/sys/amd64/linux32/linux32_machdep.c#27 - /home/jkim/p4/linuxolator/src/sys/amd64/linux32/linux32_machdep.c ==== @@ -52,6 +52,7 @@ #include #include +#include #include #include @@ -684,24 +685,27 @@ * looks like we're getting the idx we returned * in the set_thread_area() syscall */ - if (idx != 6 && idx != 4) + if (idx != 6 && idx != GUGS32_SEL) return (EINVAL); /* this doesnt happen in practice */ if (idx == 6) { - /* we might copy out the entry_number as 4 */ - info.entry_number = 4; + /* we might copy out the entry_number as GUGS32_SEL */ + info.entry_number = GUGS32_SEL; error = copyout(&info, (void *) td->td_frame->tf_rsi, sizeof(struct l_user_desc)); if (error) return (error); } - /* this is taken from amd64 version of cpu_set_user_tls() */ critical_enter(); - /* set %gs */ td2->td_pcb->pcb_gsbase = (register_t)info.base_addr; + td2->td_pcb->pcb_flags |= PCB_GS32; #if 0 - wrmsr(MSR_KGSBASE, td->td_pcb->pcb_fsbase); + wrmsr(MSR_KGSBASE, td2->td_pcb->pcb_gsbase); + gdt[GUGS32_SEL].sd_lobase = info.base_addr & 0xffffff; + gdt[GUGS32_SEL].sd_hibase = (info.base_addr >> 24) & 0xff; + gdt[GUGS32_SEL].sd_lolimit = info.limit & 0xffff; + gdt[GUGS32_SEL].sd_hilimit = (info.limit >> 16) & 0xf; #endif critical_exit(); } @@ -1248,7 +1252,7 @@ #ifdef DEBUG if (ldebug(set_thread_area)) - printf(ARGS(set_thread_area, "%i, %x, %x, %i, %i, %i, %i, %i, %i, %i\n"), + printf(ARGS(set_thread_area, "%i, %x, %x, %i, %i, %i, %i, %i, %i"), info.entry_number, info.base_addr, info.limit, @@ -1257,8 +1261,7 @@ info.read_exec_only, info.limit_in_pages, info.seg_not_present, - info.useable, - info.lm); + info.useable); #endif idx = info.entry_number; @@ -1282,25 +1285,28 @@ * we should let 4 proceed as well because we use this segment so * if code does two subsequent calls it should succeed */ - if (idx != 6 && idx != -1 && idx != 4) + if (idx != 6 && idx != -1 && idx != GUGS32_SEL) return (EINVAL); /* * we have to copy out the GDT entry we use - * FreeBSD uses GDT entry #3 for storing %gs so load that + * FreeBSD uses GUGS32_SEL for storing %gs so load that * XXX: what if userspace program doesnt check this value and tries * to use 6, 7 or 8? */ - idx = info.entry_number = 4; + idx = info.entry_number = GUGS32_SEL; error = copyout(&info, args->desc, sizeof(struct l_user_desc)); if (error) return (error); critical_enter(); - /* set %gs */ td->td_pcb->pcb_gsbase = (register_t)info.base_addr; + td->td_pcb->pcb_flags |= PCB_GS32; wrmsr(MSR_KGSBASE, td->td_pcb->pcb_gsbase); - + gdt[GUGS32_SEL].sd_lobase = info.base_addr & 0xffffff; + gdt[GUGS32_SEL].sd_hibase = (info.base_addr >> 24) & 0xff; + gdt[GUGS32_SEL].sd_lolimit = info.limit & 0xffff; + gdt[GUGS32_SEL].sd_hilimit = (info.limit >> 16) & 0xf; critical_exit(); return (0); ==== //depot/projects/linuxolator/src/sys/amd64/linux32/linux32_sysvec.c#6 - /home/jkim/p4/linuxolator/src/sys/amd64/linux32/linux32_sysvec.c ==== @@ -280,7 +280,7 @@ return 0; } -extern int _ucodesel, _ucode32sel, _udatasel; +extern int _ucodesel, _ucode32sel, _udatasel, _ugs32sel; extern unsigned long linux_sznonrtsigcode; static void @@ -820,11 +820,11 @@ load_ds(_udatasel); load_es(_udatasel); load_fs(_udatasel); - load_gs(0); + load_gs(_ugs32sel); pcb->pcb_ds = _udatasel; pcb->pcb_es = _udatasel; pcb->pcb_fs = _udatasel; - pcb->pcb_gs = 0; + pcb->pcb_gs = _ugs32sel; bzero((char *)regs, sizeof(struct trapframe)); regs->tf_rip = entry;