1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22/* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#pragma ident "%Z%%M% %I% %E% SMI" 28 29#include <sys/asm_linkage.h> 30#include <sys/asm_misc.h> 31#include <sys/regset.h> 32#include <sys/panic.h> 33#include <sys/ontrap.h> 34#include <sys/privregs.h> 35#include <sys/segments.h> 36 37#if defined(__lint) 38#include <sys/types.h> 39#include <sys/systm.h> 40#include <sys/thread.h> 41#include <sys/archsystm.h> 42#include <sys/byteorder.h> 43#include <sys/dtrace.h> 44#include <sys/x86_archext.h> 45#else /* __lint */ 46#include "assym.h" 47#endif /* __lint */ 48 49#if defined(__lint) 50 51/*ARGSUSED*/ 52void rd_idtr(desctbr_t *idtr) 53{} 54 55/*ARGSUSED*/ 56void wr_idtr(desctbr_t *idtr) 57{} 58 59#else /* __lint */ 60 61#if defined(__amd64) 62 63 ENTRY_NP(rd_idtr) 64 sidt (%rdi) 65 ret 66 SET_SIZE(rd_idtr) 67 68 ENTRY_NP(wr_idtr) 69 lidt (%rdi) 70 ret 71 SET_SIZE(wr_idtr) 72 73#elif defined(__i386) 74 75 ENTRY_NP(rd_idtr) 76 pushl %ebp 77 movl %esp, %ebp 78 movl 8(%ebp), %edx 79 sidt (%edx) 80 leave 81 ret 82 SET_SIZE(rd_idtr) 83 84 ENTRY_NP(wr_idtr) 85 pushl %ebp 86 movl %esp, %ebp 87 movl 8(%ebp), %edx 88 lidt (%edx) 89 leave 90 ret 91 SET_SIZE(wr_idtr) 92 93#endif /* __i386 */ 94#endif /* __lint */ 95 96#if defined(__lint) 97 98/*ARGSUSED*/ 99void rd_gdtr(desctbr_t *gdtr) 100{} 101 102/*ARGSUSED*/ 103void wr_gdtr(desctbr_t *gdtr) 104{} 105 106#else /* __lint */ 107 108#if defined(__amd64) 109 110 ENTRY_NP(rd_gdtr) 111 sgdt (%rdi) 112 ret 113 SET_SIZE(rd_gdtr) 114 115 ENTRY_NP(wr_gdtr) 116 lgdt (%rdi) 117 jmp 1f 118 nop 1191: 120 movl $KDS_SEL, %eax 121 movw %ax, %ss 122 /* 123 * zero %ds and %es - they're ignored anyway 124 */ 125 xorl %eax, %eax 126 movw %ax, %ds 127 movw %ax, %es 128 /* 129 * set %fs and %gs (probably to zero also) 130 */ 131 movl $KFS_SEL, %eax 132 movw %ax, %fs 133 movl $KGS_SEL, %eax 134 movw %ax, %gs 135 popq %rax 136 pushq $KCS_SEL 137 pushq %rax 138 lretq 139 SET_SIZE(wr_gdtr) 140 141#elif defined(__i386) 142 143 ENTRY_NP(rd_gdtr) 144 pushl %ebp 145 movl %esp, %ebp 146 movl 8(%ebp), %edx 147 sgdt (%edx) 148 leave 149 ret 150 SET_SIZE(rd_gdtr) 151 152 ENTRY_NP(wr_gdtr) 153 pushl %ebp 154 movl %esp, %ebp 155 movl 8(%ebp), %edx 156 lgdt (%edx) 157 nop 158 ljmp $KCS_SEL, $.next 159.next: 160 movl $KDS_SEL, %eax 161 movw %ax, %ds 162 movw %ax, %es 163 movw %ax, %ss 164 movl $KFS_SEL, %eax 165 movw %ax, %fs 166 movl $KGS_SEL, %eax 167 movw %ax, %gs 168 leave 169 ret 170 SET_SIZE(wr_gdtr) 171 172#endif /* __i386 */ 173#endif /* __lint */ 174 175#if defined(__lint) 176 177/*ARGSUSED*/ 178void wr_ldtr(selector_t ldtsel) 179{} 180 181selector_t rd_ldtr(void) 182{ return (0); } 183 184#if defined(__amd64) 185void clr_ldt_sregs(void) 186{} 187#endif 188 189#else /* __lint */ 190 191#if defined(__amd64) 192 193 ENTRY_NP(wr_ldtr) 194 movq %rdi, %rax 195 lldt %ax 196 ret 197 SET_SIZE(wr_ldtr) 198 199 ENTRY_NP(rd_ldtr) 200 xorl %eax, %eax 201 sldt %ax 202 ret 203 SET_SIZE(rd_ldtr) 204 205 /* 206 * Make sure any stale ldt selectors are cleared by loading 207 * KDS_SEL (kernel %ds gdt selector). This is necessary 208 * since the kernel does not use %es, %fs and %ds. %cs and 209 * %ss are necessary and setup by the kernel along with %gs 210 * to point to current cpu struct. If we take a kmdb breakpoint 211 * in the kernel and resume with a stale ldt selector kmdb 212 * would #gp fault if it points to a ldt in the context of 213 * another process. 214 * 215 * WARNING: Nocona and AMD have different behaviour about storing 216 * the null selector into %fs and %gs while in long mode. On AMD 217 * chips fsbase and gsbase is not cleared. But on nocona storing 218 * null selector into %fs or %gs has the side effect of clearing 219 * fsbase or gsbase. For that reason we use KDS_SEL which has 220 * consistent behavoir between AMD and Nocona. 221 */ 222 ENTRY_NP(clr_ldt_sregs) 223 224 /* 225 * Save GSBASE before resetting %gs to KDS_SEL 226 * then restore GSBASE. 227 */ 228 cli 229 movq %rbx, %rdi 230 movw $KDS_SEL, %bx 231 movl $MSR_AMD_GSBASE, %ecx 232 rdmsr 233 movw %bx, %gs 234 wrmsr 235 sti 236 movw %bx, %ds 237 movw %bx, %es 238 movw %bx, %fs 239 movq %rdi, %rbx 240 ret 241 SET_SIZE(clr_ldt_sregs) 242 243#elif defined(__i386) 244 245 ENTRY_NP(wr_ldtr) 246 movw 4(%esp), %ax 247 lldt %ax 248 ret 249 SET_SIZE(wr_ldtr) 250 251 ENTRY_NP(rd_ldtr) 252 xorl %eax, %eax 253 sldt %ax 254 ret 255 SET_SIZE(rd_ldtr) 256 257#endif /* __i386 */ 258#endif /* __lint */ 259 260#if defined(__lint) 261 262/*ARGSUSED*/ 263void wr_tsr(selector_t tsssel) 264{} 265 266#else /* __lint */ 267 268#if defined(__amd64) 269 270 ENTRY_NP(wr_tsr) 271 movq %rdi, %rax 272 ltr %ax 273 ret 274 SET_SIZE(wr_tsr) 275 276#elif defined(__i386) 277 278 ENTRY_NP(wr_tsr) 279 movw 4(%esp), %ax 280 ltr %ax 281 ret 282 SET_SIZE(wr_tsr) 283 284#endif /* __i386 */ 285#endif /* __lint */ 286