1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 2006 andrei * Common Development and Distribution License (the "License"). 6 2006 andrei * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 3446 mrj 22 0 stevel /* 23 10395 gerald * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 28 0 stevel /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 29 0 stevel /* All Rights Reserved */ 30 0 stevel 31 0 stevel /* Copyright (c) 1987, 1988 Microsoft Corporation */ 32 0 stevel /* All Rights Reserved */ 33 0 stevel 34 0 stevel 35 0 stevel #include <sys/asm_linkage.h> 36 0 stevel #include <sys/asm_misc.h> 37 0 stevel #include <sys/regset.h> 38 0 stevel #include <sys/privregs.h> 39 0 stevel #include <sys/psw.h> 40 0 stevel #include <sys/reboot.h> 41 0 stevel #include <sys/x86_archext.h> 42 2006 andrei #include <sys/machparam.h> 43 0 stevel 44 0 stevel #if defined(__lint) 45 0 stevel 46 0 stevel #include <sys/types.h> 47 0 stevel #include <sys/thread.h> 48 0 stevel #include <sys/systm.h> 49 0 stevel #include <sys/lgrp.h> 50 0 stevel #include <sys/regset.h> 51 0 stevel #include <sys/link.h> 52 0 stevel #include <sys/bootconf.h> 53 0 stevel #include <sys/bootsvcs.h> 54 0 stevel 55 0 stevel #else /* __lint */ 56 0 stevel 57 0 stevel #include <sys/segments.h> 58 0 stevel #include <sys/pcb.h> 59 0 stevel #include <sys/trap.h> 60 0 stevel #include <sys/ftrace.h> 61 0 stevel #include <sys/traptrace.h> 62 0 stevel #include <sys/clock.h> 63 0 stevel #include <sys/cmn_err.h> 64 0 stevel #include <sys/pit.h> 65 0 stevel #include <sys/panic.h> 66 5084 johnlev 67 5084 johnlev #if defined(__xpv) 68 5084 johnlev #include <sys/hypervisor.h> 69 5084 johnlev #endif 70 3446 mrj 71 0 stevel #include "assym.h" 72 0 stevel 73 0 stevel /* 74 0 stevel * Our assumptions: 75 0 stevel * - We are running in protected-paged mode. 76 0 stevel * - Interrupts are disabled. 77 0 stevel * - The GDT and IDT are the callers; we need our copies. 78 0 stevel * - The kernel's text, initialized data and bss are mapped. 79 0 stevel * 80 0 stevel * Our actions: 81 0 stevel * - Save arguments 82 0 stevel * - Initialize our stack pointer to the thread 0 stack (t0stack) 83 0 stevel * and leave room for a phony "struct regs". 84 0 stevel * - Our GDT and IDT need to get munged. 85 0 stevel * - Since we are using the boot's GDT descriptors, we need 86 0 stevel * to copy them into our GDT before we switch to ours. 87 0 stevel * - We start using our GDT by loading correct values in the 88 0 stevel * selector registers (cs=KCS_SEL, ds=es=ss=KDS_SEL, fs=KFS_SEL, 89 0 stevel * gs=KGS_SEL). 90 0 stevel * - The default LDT entry for syscall is set. 91 0 stevel * - We load the default LDT into the hardware LDT register. 92 0 stevel * - We load the default TSS into the hardware task register. 93 0 stevel * - Check for cpu type, i.e. 486 vs. P5 vs. P6 etc. 94 0 stevel * - mlsetup(%esp) gets called. 95 0 stevel * - We change our appearance to look like the real thread 0. 96 0 stevel * (NOTE: making ourselves to be a real thread may be a noop) 97 0 stevel * - main() gets called. (NOTE: main() never returns). 98 0 stevel * 99 0 stevel * NOW, the real code! 100 0 stevel */ 101 3446 mrj /* 102 3446 mrj * The very first thing in the kernel's text segment must be a jump 103 3446 mrj * to the os/fakebop.c startup code. 104 3446 mrj */ 105 3446 mrj .text 106 3446 mrj jmp _start 107 0 stevel 108 0 stevel /* 109 0 stevel * Globals: 110 0 stevel */ 111 3446 mrj .globl _locore_start 112 0 stevel .globl mlsetup 113 0 stevel .globl main 114 0 stevel .globl panic 115 0 stevel .globl t0stack 116 0 stevel .globl t0 117 0 stevel .globl sysp 118 0 stevel .globl edata 119 0 stevel 120 0 stevel /* 121 0 stevel * call back into boot - sysp (bootsvcs.h) and bootops (bootconf.h) 122 0 stevel */ 123 0 stevel .globl bootops 124 0 stevel .globl bootopsp 125 0 stevel 126 0 stevel /* 127 0 stevel * NOTE: t0stack should be the first thing in the data section so that 128 0 stevel * if it ever overflows, it will fault on the last kernel text page. 129 0 stevel */ 130 0 stevel .data 131 0 stevel .comm t0stack, DEFAULTSTKSZ, 32 132 0 stevel .comm t0, 4094, 32 133 0 stevel 134 0 stevel #endif /* __lint */ 135 0 stevel 136 0 stevel 137 0 stevel #if defined(__amd64) 138 0 stevel 139 0 stevel #if defined(__lint) 140 0 stevel 141 0 stevel /* ARGSUSED */ 142 0 stevel void 143 3446 mrj _locore_start(struct boot_syscalls *sysp, ulong_t rsi, struct bootops *bop) 144 0 stevel {} 145 0 stevel 146 0 stevel #else /* __lint */ 147 0 stevel 148 3446 mrj /* 149 3446 mrj * kobj_init() vectors us back to here with (note) a slightly different 150 3446 mrj * set of arguments than _start is given (see lint prototypes above). 151 5084 johnlev * 152 5084 johnlev * XXX Make this less vile, please. 153 3446 mrj */ 154 3446 mrj ENTRY_NP(_locore_start) 155 0 stevel 156 0 stevel /* 157 0 stevel * %rdi = boot services (should die someday) 158 0 stevel * %rdx = bootops 159 0 stevel * end 160 0 stevel */ 161 0 stevel 162 0 stevel leaq edata(%rip), %rbp /* reference edata for ksyms */ 163 0 stevel movq $0, (%rbp) /* limit stack back trace */ 164 0 stevel 165 0 stevel /* 166 0 stevel * Initialize our stack pointer to the thread 0 stack (t0stack) 167 0 stevel * and leave room for a "struct regs" for lwp0. Note that the 168 0 stevel * stack doesn't actually align to a 16-byte boundary until just 169 0 stevel * before we call mlsetup because we want to use %rsp to point at 170 0 stevel * our regs structure. 171 0 stevel */ 172 0 stevel leaq t0stack(%rip), %rsp 173 0 stevel addq $_CONST(DEFAULTSTKSZ - REGSIZE), %rsp 174 0 stevel #if (REGSIZE & 15) == 0 175 0 stevel subq $8, %rsp 176 0 stevel #endif 177 0 stevel /* 178 0 stevel * Save call back for special x86 boot services vector 179 0 stevel */ 180 0 stevel movq %rdi, sysp(%rip) 181 0 stevel 182 0 stevel movq %rdx, bootops(%rip) /* save bootops */ 183 0 stevel movq $bootops, bootopsp(%rip) 184 0 stevel 185 0 stevel /* 186 0 stevel * Save arguments and flags, if only for debugging .. 187 0 stevel */ 188 0 stevel movq %rdi, REGOFF_RDI(%rsp) 189 0 stevel movq %rsi, REGOFF_RSI(%rsp) 190 0 stevel movq %rdx, REGOFF_RDX(%rsp) 191 0 stevel movq %rcx, REGOFF_RCX(%rsp) 192 0 stevel movq %r8, REGOFF_R8(%rsp) 193 0 stevel movq %r9, REGOFF_R9(%rsp) 194 0 stevel pushf 195 0 stevel popq %r11 196 0 stevel movq %r11, REGOFF_RFL(%rsp) 197 0 stevel 198 5084 johnlev #if !defined(__xpv) 199 0 stevel /* 200 0 stevel * Enable write protect and alignment check faults. 201 0 stevel */ 202 0 stevel movq %cr0, %rax 203 0 stevel orq $_CONST(CR0_WP|CR0_AM), %rax 204 0 stevel andq $_BITNOT(CR0_WT|CR0_CE), %rax 205 0 stevel movq %rax, %cr0 206 5084 johnlev #endif /* __xpv */ 207 0 stevel 208 0 stevel /* 209 0 stevel * (We just assert this works by virtue of being here) 210 0 stevel */ 211 0 stevel orl $X86_CPUID, x86_feature(%rip) 212 0 stevel 213 0 stevel /* 214 0 stevel * mlsetup() gets called with a struct regs as argument, while 215 0 stevel * main takes no args and should never return. 216 0 stevel */ 217 0 stevel xorl %ebp, %ebp 218 0 stevel movq %rsp, %rdi 219 0 stevel pushq %rbp 220 0 stevel /* (stack pointer now aligned on 16-byte boundary right here) */ 221 0 stevel movq %rsp, %rbp 222 0 stevel call mlsetup 223 0 stevel call main 224 0 stevel /* NOTREACHED */ 225 0 stevel leaq __return_from_main(%rip), %rdi 226 0 stevel xorl %eax, %eax 227 0 stevel call panic 228 3446 mrj SET_SIZE(_locore_start) 229 0 stevel 230 0 stevel #endif /* __amd64 */ 231 0 stevel #endif /* __lint */ 232 0 stevel 233 0 stevel #if !defined(__lint) 234 0 stevel 235 0 stevel __return_from_main: 236 0 stevel .string "main() returned" 237 0 stevel __unsupported_cpu: 238 0 stevel .string "486 style cpu detected - no longer supported!" 239 0 stevel 240 0 stevel #endif /* !__lint */ 241 0 stevel 242 0 stevel #if !defined(__amd64) 243 0 stevel 244 0 stevel #if defined(__lint) 245 0 stevel 246 3446 mrj /* ARGSUSED */ 247 0 stevel void 248 3446 mrj _locore_start(struct boot_syscalls *sysp, struct bootops *bop) 249 0 stevel {} 250 0 stevel 251 0 stevel #else /* __lint */ 252 0 stevel 253 0 stevel /* 254 3446 mrj * kobj_init() vectors us back to here with (note) a slightly different 255 3446 mrj * set of arguments than _start is given (see lint prototypes above). 256 5084 johnlev * 257 5084 johnlev * XXX Make this less vile, please. 258 0 stevel */ 259 3446 mrj ENTRY_NP(_locore_start) 260 0 stevel 261 0 stevel /* 262 0 stevel * %ecx = boot services (should die someday) 263 0 stevel * %ebx = bootops 264 414 kchow */ 265 0 stevel mov $edata, %ebp / edata needs to be defined for ksyms 266 0 stevel movl $0, (%ebp) / limit stack back trace 267 0 stevel 268 0 stevel /* 269 0 stevel * Initialize our stack pointer to the thread 0 stack (t0stack) 270 0 stevel * and leave room for a phony "struct regs". 271 0 stevel */ 272 0 stevel movl $t0stack + DEFAULTSTKSZ - REGSIZE, %esp 273 0 stevel 274 0 stevel /* 275 0 stevel * Save call back for special x86 boot services vector 276 0 stevel */ 277 0 stevel mov %ecx, sysp / save call back for boot services 278 0 stevel 279 0 stevel mov %ebx, bootops / save bootops 280 0 stevel movl $bootops, bootopsp 281 0 stevel 282 3446 mrj 283 0 stevel /* 284 0 stevel * Save all registers and flags 285 0 stevel */ 286 0 stevel pushal 287 0 stevel pushfl 288 0 stevel 289 5084 johnlev #if !defined(__xpv) 290 0 stevel /* 291 0 stevel * Override bios settings and enable write protect and 292 0 stevel * alignment check faults. 293 0 stevel */ 294 0 stevel movl %cr0, %eax 295 0 stevel 296 0 stevel /* 297 0 stevel * enable WP for detecting faults, and enable alignment checking. 298 0 stevel */ 299 0 stevel orl $_CONST(CR0_WP|CR0_AM), %eax 300 0 stevel andl $_BITNOT(CR0_WT|CR0_CE), %eax 301 0 stevel movl %eax, %cr0 / set the cr0 register correctly and 302 0 stevel / override the BIOS setup 303 3446 mrj 304 0 stevel /* 305 0 stevel * If bit 21 of eflags can be flipped, then cpuid is present 306 0 stevel * and enabled. 307 0 stevel */ 308 0 stevel pushfl 309 0 stevel popl %ecx 310 0 stevel movl %ecx, %eax 311 0 stevel xorl $PS_ID, %eax / try complemented bit 312 0 stevel pushl %eax 313 0 stevel popfl 314 0 stevel pushfl 315 0 stevel popl %eax 316 0 stevel cmpl %eax, %ecx 317 0 stevel jne have_cpuid 318 0 stevel 319 0 stevel /* 320 0 stevel * cpuid may be disabled on Cyrix, try to detect Cyrix by the 5/2 test 321 0 stevel * div does not modify the cc flags on Cyrix, even though this may 322 0 stevel * also be true for other vendors, this is generally true only for 323 0 stevel * newer models from those vendors that support and do not disable 324 0 stevel * cpuid (usually because cpuid cannot be disabled) 325 0 stevel */ 326 0 stevel 327 0 stevel /* 328 0 stevel * clear cc flags 329 0 stevel */ 330 0 stevel xorb %ah, %ah 331 0 stevel sahf 332 0 stevel 333 0 stevel /* 334 0 stevel * perform 5/2 test 335 0 stevel */ 336 0 stevel movw $5, %ax 337 0 stevel movb $2, %bl 338 0 stevel divb %bl 339 0 stevel 340 0 stevel lahf 341 0 stevel cmpb $2, %ah 342 0 stevel jne cpu_486 343 0 stevel 344 0 stevel /* 345 0 stevel * div did not modify the cc flags, chances are the vendor is Cyrix 346 0 stevel * assume the vendor is Cyrix and use the CCR's to enable cpuid 347 0 stevel */ 348 0 stevel .set CYRIX_CRI, 0x22 / CR Index Register 349 0 stevel .set CYRIX_CRD, 0x23 / CR Data Register 350 0 stevel 351 0 stevel .set CYRIX_CCR3, 0xc3 / Config Control Reg 3 352 0 stevel .set CYRIX_CCR4, 0xe8 / Config Control Reg 4 353 0 stevel .set CYRIX_DIR0, 0xfe / Device Identification Reg 0 354 0 stevel .set CYRIX_DIR1, 0xff / Device Identification Reg 1 355 0 stevel 356 0 stevel /* 357 0 stevel * even if the cpu vendor is Cyrix and the motherboard/chipset 358 0 stevel * vendor decided to ignore lines A1-A4 for I/O addresses, I/O port 359 0 stevel * 0x21 corresponds with 0x23 and since 0x22 is still untouched, 360 0 stevel * the reads and writes of 0x21 are guaranteed to be off-chip of 361 0 stevel * the cpu 362 0 stevel */ 363 0 stevel 364 0 stevel /* 365 0 stevel * enable read of ISR at I/O port 0x20 366 0 stevel */ 367 0 stevel movb $0xb, %al 368 0 stevel outb $MCMD_PORT 369 0 stevel 370 0 stevel /* 371 0 stevel * read IMR and store in %bl 372 0 stevel */ 373 0 stevel inb $MIMR_PORT 374 0 stevel movb %al, %bl 375 0 stevel 376 0 stevel /* 377 0 stevel * mask out all interrupts so that ISR will not change 378 0 stevel */ 379 0 stevel movb $0xff, %al 380 0 stevel outb $MIMR_PORT 381 0 stevel 382 0 stevel /* 383 0 stevel * reads of I/O port 0x22 on Cyrix are always directed off-chip 384 0 stevel * make use of I/O pull-up to test for an unknown device on 0x22 385 0 stevel */ 386 0 stevel inb $CYRIX_CRI 387 0 stevel cmpb $0xff, %al 388 0 stevel je port_22_free 389 0 stevel 390 0 stevel /* 391 0 stevel * motherboard/chipset vendor may be ignoring line A1 of I/O address 392 0 stevel */ 393 0 stevel movb %al, %cl 394 0 stevel 395 0 stevel /* 396 0 stevel * if the ISR and the value read from 0x22 do not match then we have 397 0 stevel * detected some unknown device, probably a chipset, at 0x22 398 0 stevel */ 399 0 stevel inb $MCMD_PORT 400 0 stevel cmpb %al, %cl 401 0 stevel jne restore_IMR 402 0 stevel 403 0 stevel port_22_free: 404 0 stevel /* 405 0 stevel * now test to see if some unknown device is using I/O port 0x23 406 0 stevel * 407 0 stevel * read the external I/O port at 0x23 408 0 stevel */ 409 0 stevel inb $CYRIX_CRD 410 0 stevel 411 0 stevel /* 412 0 stevel * Test for pull-up at 0x23 or if I/O address line A1 is being ignored. 413 0 stevel * IMR is 0xff so both tests are performed simultaneously. 414 0 stevel */ 415 0 stevel cmpb $0xff, %al 416 0 stevel jne restore_IMR 417 0 stevel 418 0 stevel /* 419 0 stevel * We are a Cyrix part. In case we are some model of Cx486 or a Cx586, 420 0 stevel * record the type and fix it later if not. 421 0 stevel */ 422 0 stevel movl $X86_VENDOR_Cyrix, x86_vendor 423 0 stevel movl $X86_TYPE_CYRIX_486, x86_type 424 0 stevel 425 0 stevel /* 426 0 stevel * Try to read CCR3. All Cyrix cpu's which support cpuid have CCR3. 427 0 stevel * 428 0 stevel * load CCR3 index into CCR index register 429 0 stevel */ 430 0 stevel 431 0 stevel movb $CYRIX_CCR3, %al 432 0 stevel outb $CYRIX_CRI 433 0 stevel 434 0 stevel /* 435 0 stevel * If we are not a Cyrix cpu, then we have performed an external I/O 436 0 stevel * cycle. If the CCR index was not valid for this Cyrix model, we may 437 0 stevel * have performed an external I/O cycle as well. In these cases and 438 0 stevel * if the motherboard/chipset vendor ignores I/O address line A1, 439 0 stevel * then the PIC will have IRQ3 set at the lowest priority as a side 440 0 stevel * effect of the above outb. We are reasonalbly confident that there 441 0 stevel * is not an unknown device on I/O port 0x22, so there should have been 442 0 stevel * no unpredictable side-effect of the above outb. 443 0 stevel */ 444 0 stevel 445 0 stevel /* 446 0 stevel * read CCR3 447 0 stevel */ 448 0 stevel inb $CYRIX_CRD 449 0 stevel 450 0 stevel /* 451 0 stevel * If we are not a Cyrix cpu the inb above produced an external I/O 452 0 stevel * cycle. If we are a Cyrix model that does not support CCR3 wex 453 0 stevel * produced an external I/O cycle. In all known Cyrix models 6x86 and 454 0 stevel * above, bit 3 of CCR3 is reserved and cannot be set to 1. In all 455 0 stevel * Cyrix models prior to the 6x86 that supported CCR3, bits 4-7 are 456 0 stevel * reserved as well. It is highly unlikely that CCR3 contains the value 457 0 stevel * 0xff. We test to see if I/O port 0x23 is pull-up or the IMR and 458 0 stevel * deduce we are not a Cyrix with support for cpuid if so. 459 0 stevel */ 460 0 stevel cmpb $0xff, %al 461 0 stevel je restore_PIC 462 0 stevel 463 0 stevel /* 464 0 stevel * There exist 486 ISA Cyrix chips that support CCR3 but do not support 465 0 stevel * DIR0 and DIR1. If we try to read DIR0, we may generate external I/O 466 0 stevel * cycles, the exact behavior is model specific and undocumented. 467 0 stevel * Unfortunately these external I/O cycles may confuse some PIC's beyond 468 0 stevel * recovery. Fortunatetly we can use the following undocumented trick: 469 0 stevel * if bit 4 of CCR3 can be toggled, then DIR0 and DIR1 are supported. 470 0 stevel * Pleasantly MAPEN contains bit 4 of CCR3, so this trick is guaranteed 471 0 stevel * to work on all Cyrix cpu's which support cpuid. 472 0 stevel */ 473 0 stevel movb %al, %dl 474 0 stevel xorb $0x10, %dl 475 0 stevel movb %al, %cl 476 0 stevel 477 0 stevel /* 478 0 stevel * write back CRR3 with toggled bit 4 to CCR3 479 0 stevel */ 480 0 stevel movb $CYRIX_CCR3, %al 481 0 stevel outb $CYRIX_CRI 482 0 stevel 483 0 stevel movb %dl, %al 484 0 stevel outb $CYRIX_CRD 485 0 stevel 486 0 stevel /* 487 0 stevel * read CCR3 488 0 stevel */ 489 0 stevel movb $CYRIX_CCR3, %al 490 0 stevel outb $CYRIX_CRI 491 0 stevel inb $CYRIX_CRD 492 0 stevel movb %al, %dl 493 0 stevel 494 0 stevel /* 495 0 stevel * restore CCR3 496 0 stevel */ 497 0 stevel movb $CYRIX_CCR3, %al 498 0 stevel outb $CYRIX_CRI 499 0 stevel 500 0 stevel movb %cl, %al 501 0 stevel outb $CYRIX_CRD 502 0 stevel 503 0 stevel /* 504 0 stevel * if bit 4 was not toggled DIR0 and DIR1 are not supported in which 505 0 stevel * case we do not have cpuid anyway 506 0 stevel */ 507 0 stevel andb $0x10, %al 508 0 stevel andb $0x10, %dl 509 0 stevel cmpb %al, %dl 510 0 stevel je restore_PIC 511 0 stevel 512 0 stevel /* 513 0 stevel * read DIR0 514 0 stevel */ 515 0 stevel movb $CYRIX_DIR0, %al 516 0 stevel outb $CYRIX_CRI 517 0 stevel inb $CYRIX_CRD 518 0 stevel 519 0 stevel /* 520 0 stevel * test for pull-up 521 0 stevel */ 522 0 stevel cmpb $0xff, %al 523 0 stevel je restore_PIC 524 0 stevel 525 0 stevel /* 526 0 stevel * Values of 0x20-0x27 in DIR0 are currently reserved by Cyrix for 527 0 stevel * future use. If Cyrix ever produces a cpu that supports cpuid with 528 0 stevel * these ids, the following test will have to change. For now we remain 529 0 stevel * pessimistic since the formats of the CRR's may be different then. 530 0 stevel * 531 0 stevel * test for at least a 6x86, to see if we support both MAPEN and CPUID 532 0 stevel */ 533 0 stevel cmpb $0x30, %al 534 0 stevel jb restore_IMR 535 0 stevel 536 0 stevel /* 537 0 stevel * enable MAPEN 538 0 stevel */ 539 0 stevel movb $CYRIX_CCR3, %al 540 0 stevel outb $CYRIX_CRI 541 0 stevel 542 0 stevel andb $0xf, %cl 543 0 stevel movb %cl, %al 544 0 stevel orb $0x10, %al 545 0 stevel outb $CYRIX_CRD 546 0 stevel 547 0 stevel /* 548 0 stevel * select CCR4 549 0 stevel */ 550 0 stevel movb $CYRIX_CCR4, %al 551 0 stevel outb $CYRIX_CRI 552 0 stevel 553 0 stevel /* 554 0 stevel * read CCR4 555 0 stevel */ 556 0 stevel inb $CYRIX_CRD 557 0 stevel 558 0 stevel /* 559 0 stevel * enable cpuid 560 0 stevel */ 561 0 stevel orb $0x80, %al 562 0 stevel movb %al, %dl 563 0 stevel 564 0 stevel /* 565 0 stevel * select CCR4 566 0 stevel */ 567 0 stevel movb $CYRIX_CCR4, %al 568 0 stevel outb $CYRIX_CRI 569 0 stevel 570 0 stevel /* 571 0 stevel * write CCR4 572 0 stevel */ 573 0 stevel movb %dl, %al 574 0 stevel outb $CYRIX_CRD 575 0 stevel 576 0 stevel /* 577 0 stevel * select CCR3 578 0 stevel */ 579 0 stevel movb $CYRIX_CCR3, %al 580 0 stevel outb $CYRIX_CRI 581 0 stevel 582 0 stevel /* 583 0 stevel * disable MAPEN and write CCR3 584 0 stevel */ 585 0 stevel movb %cl, %al 586 0 stevel outb $CYRIX_CRD 587 0 stevel 588 0 stevel /* 589 0 stevel * restore IMR 590 0 stevel */ 591 0 stevel movb %bl, %al 592 0 stevel outb $MIMR_PORT 593 0 stevel 594 0 stevel /* 595 0 stevel * test to see if cpuid available 596 0 stevel */ 597 0 stevel pushfl 598 0 stevel popl %ecx 599 0 stevel movl %ecx, %eax 600 0 stevel xorl $PS_ID, %eax / try complemented bit 601 0 stevel pushl %eax 602 0 stevel popfl 603 0 stevel pushfl 604 0 stevel popl %eax 605 0 stevel cmpl %eax, %ecx 606 0 stevel jne have_cpuid 607 0 stevel jmp cpu_486 608 0 stevel 609 0 stevel restore_PIC: 610 0 stevel /* 611 0 stevel * In case the motherboard/chipset vendor is ignoring line A1 of the 612 0 stevel * I/O address, we set the PIC priorities to sane values. 613 0 stevel */ 614 0 stevel movb $0xc7, %al / irq 7 lowest priority 615 0 stevel outb $MCMD_PORT 616 0 stevel 617 0 stevel restore_IMR: 618 0 stevel movb %bl, %al 619 0 stevel outb $MIMR_PORT 620 0 stevel jmp cpu_486 621 0 stevel 622 0 stevel have_cpuid: 623 0 stevel /* 624 0 stevel * cpuid instruction present 625 0 stevel */ 626 0 stevel orl $X86_CPUID, x86_feature 627 0 stevel movl $0, %eax 628 0 stevel cpuid 629 0 stevel 630 0 stevel movl %ebx, cpu_vendor 631 0 stevel movl %edx, cpu_vendor+4 632 0 stevel movl %ecx, cpu_vendor+8 633 0 stevel 634 0 stevel /* 635 0 stevel * early cyrix cpus are somewhat strange and need to be 636 0 stevel * probed in curious ways to determine their identity 637 0 stevel */ 638 0 stevel 639 0 stevel leal cpu_vendor, %esi 640 0 stevel leal CyrixInstead, %edi 641 0 stevel movl $12, %ecx 642 0 stevel repz 643 0 stevel cmpsb 644 0 stevel je vendor_is_cyrix 645 0 stevel 646 0 stevel / let mlsetup()/cpuid_pass1() handle everything else in C 647 0 stevel 648 0 stevel jmp cpu_done 649 0 stevel 650 0 stevel is486: 651 0 stevel /* 652 0 stevel * test to see if a useful cpuid 653 0 stevel */ 654 0 stevel testl %eax, %eax 655 0 stevel jz isa486 656 0 stevel 657 0 stevel movl $1, %eax 658 0 stevel cpuid 659 0 stevel 660 0 stevel movl %eax, %ebx 661 0 stevel andl $0xF00, %ebx 662 0 stevel cmpl $0x400, %ebx 663 0 stevel je isa486 664 0 stevel 665 545 kalai rep; ret /* use 2 byte return instruction */ 666 545 kalai /* AMD Software Optimization Guide - Section 6.2 */ 667 0 stevel isa486: 668 0 stevel /* 669 0 stevel * lose the return address 670 0 stevel */ 671 0 stevel popl %eax 672 0 stevel jmp cpu_486 673 0 stevel 674 0 stevel vendor_is_cyrix: 675 0 stevel call is486 676 0 stevel 677 0 stevel /* 678 0 stevel * Processor signature and feature flags for Cyrix are insane. 679 0 stevel * BIOS can play with semi-documented registers, so cpuid must be used 680 0 stevel * cautiously. Since we are Cyrix that has cpuid, we have DIR0 and DIR1 681 0 stevel * Keep the family in %ebx and feature flags in %edx until not needed 682 0 stevel */ 683 0 stevel 684 0 stevel /* 685 0 stevel * read DIR0 686 0 stevel */ 687 0 stevel movb $CYRIX_DIR0, %al 688 0 stevel outb $CYRIX_CRI 689 0 stevel inb $CYRIX_CRD 690 0 stevel 691 0 stevel /* 692 0 stevel * First we handle the cases where we are a 6x86 or 6x86L. 693 0 stevel * The 6x86 is basically a 486, the only reliable bit in the 694 0 stevel * feature flags is for FPU. The 6x86L is better, unfortunately 695 0 stevel * there is no really good way to distinguish between these two 696 0 stevel * cpu's. We are pessimistic and when in doubt assume 6x86. 697 0 stevel */ 698 0 stevel 699 0 stevel cmpb $0x40, %al 700 0 stevel jae maybeGX 701 0 stevel 702 0 stevel /* 703 0 stevel * We are an M1, either a 6x86 or 6x86L. 704 0 stevel */ 705 0 stevel cmpb $0x30, %al 706 0 stevel je maybe6x86L 707 0 stevel cmpb $0x31, %al 708 0 stevel je maybe6x86L 709 0 stevel cmpb $0x34, %al 710 0 stevel je maybe6x86L 711 0 stevel cmpb $0x35, %al 712 0 stevel je maybe6x86L 713 0 stevel 714 0 stevel /* 715 0 stevel * although it is possible that we are a 6x86L, the cpu and 716 0 stevel * documentation are so buggy, we just do not care. 717 0 stevel */ 718 0 stevel jmp likely6x86 719 0 stevel 720 0 stevel maybe6x86L: 721 0 stevel /* 722 0 stevel * read DIR1 723 0 stevel */ 724 0 stevel movb $CYRIX_DIR1, %al 725 0 stevel outb $CYRIX_CRI 726 0 stevel inb $CYRIX_CRD 727 0 stevel cmpb $0x22, %al 728 0 stevel jb likely6x86 729 0 stevel 730 0 stevel /* 731 0 stevel * We are a 6x86L, or at least a 6x86 with honest cpuid feature flags 732 0 stevel */ 733 0 stevel movl $X86_TYPE_CYRIX_6x86L, x86_type 734 0 stevel jmp coma_bug 735 0 stevel 736 0 stevel likely6x86: 737 0 stevel /* 738 0 stevel * We are likely a 6x86, or a 6x86L without a way of knowing 739 0 stevel * 740 0 stevel * The 6x86 has NO Pentium or Pentium Pro compatible features even 741 0 stevel * though it claims to be a Pentium Pro compatible! 742 0 stevel * 743 0 stevel * The 6x86 core used in the 6x86 may have most of the Pentium system 744 0 stevel * registers and largely conform to the Pentium System Programming 745 0 stevel * Reference. Documentation on these parts is long gone. Treat it as 746 0 stevel * a crippled Pentium and hope for the best. 747 0 stevel */ 748 0 stevel 749 0 stevel movl $X86_TYPE_CYRIX_6x86, x86_type 750 0 stevel jmp coma_bug 751 0 stevel 752 0 stevel maybeGX: 753 0 stevel /* 754 0 stevel * Now we check whether we are a MediaGX or GXm. We have particular 755 0 stevel * reason for concern here. Even though most of the GXm's 756 0 stevel * report having TSC in the cpuid feature flags, the TSC may be 757 0 stevel * horribly broken. What is worse, is that MediaGX's are basically 758 0 stevel * 486's while the good GXm's are more like Pentium Pro's! 759 0 stevel */ 760 0 stevel 761 0 stevel cmpb $0x50, %al 762 0 stevel jae maybeM2 763 0 stevel 764 0 stevel /* 765 0 stevel * We are either a MediaGX (sometimes called a Gx86) or GXm 766 0 stevel */ 767 0 stevel 768 0 stevel cmpb $41, %al 769 0 stevel je maybeMediaGX 770 0 stevel 771 0 stevel cmpb $44, %al 772 0 stevel jb maybeGXm 773 0 stevel 774 0 stevel cmpb $47, %al 775 0 stevel jbe maybeMediaGX 776 0 stevel 777 0 stevel /* 778 0 stevel * We do not honestly know what we are, so assume a MediaGX 779 0 stevel */ 780 0 stevel jmp media_gx 781 0 stevel 782 0 stevel maybeGXm: 783 0 stevel /* 784 0 stevel * It is still possible we are either a MediaGX or GXm, trust cpuid 785 0 stevel * family should be 5 on a GXm 786 0 stevel */ 787 0 stevel cmpl $0x500, %ebx 788 0 stevel je GXm 789 0 stevel 790 0 stevel /* 791 0 stevel * BIOS/Cyrix might set family to 6 on a GXm 792 0 stevel */ 793 0 stevel cmpl $0x600, %ebx 794 0 stevel jne media_gx 795 0 stevel 796 0 stevel GXm: 797 0 stevel movl $X86_TYPE_CYRIX_GXm, x86_type 798 0 stevel jmp cpu_done 799 0 stevel 800 0 stevel maybeMediaGX: 801 0 stevel /* 802 0 stevel * read DIR1 803 0 stevel */ 804 0 stevel movb $CYRIX_DIR1, %al 805 0 stevel outb $CYRIX_CRI 806 0 stevel inb $CYRIX_CRD 807 0 stevel 808 0 stevel cmpb $0x30, %al 809 0 stevel jae maybeGXm 810 0 stevel 811 0 stevel /* 812 0 stevel * we are a MediaGX for which we do not trust cpuid 813 0 stevel */ 814 0 stevel media_gx: 815 0 stevel movl $X86_TYPE_CYRIX_MediaGX, x86_type 816 0 stevel jmp cpu_486 817 0 stevel 818 0 stevel maybeM2: 819 0 stevel /* 820 0 stevel * Now we check whether we are a 6x86MX or MII. These cpu's are 821 0 stevel * virtually identical, but we care because for the 6x86MX, we 822 0 stevel * must work around the coma bug. Also for 6x86MX prior to revision 823 0 stevel * 1.4, the TSC may have serious bugs. 824 0 stevel */ 825 0 stevel 826 0 stevel cmpb $0x60, %al 827 0 stevel jae maybeM3 828 0 stevel 829 0 stevel /* 830 0 stevel * family should be 6, but BIOS/Cyrix might set it to 5 831 0 stevel */ 832 0 stevel cmpl $0x600, %ebx 833 0 stevel ja cpu_486 834 0 stevel 835 0 stevel /* 836 0 stevel * read DIR1 837 0 stevel */ 838 0 stevel movb $CYRIX_DIR1, %al 839 0 stevel outb $CYRIX_CRI 840 0 stevel inb $CYRIX_CRD 841 0 stevel 842 0 stevel cmpb $0x8, %al 843 0 stevel jb cyrix6x86MX 844 0 stevel cmpb $0x80, %al 845 0 stevel jb MII 846 0 stevel 847 0 stevel cyrix6x86MX: 848 0 stevel /* 849 0 stevel * It is altogether unclear how the revision stamped on the cpu 850 0 stevel * maps to the values in DIR0 and DIR1. Just assume TSC is broken. 851 0 stevel */ 852 0 stevel movl $X86_TYPE_CYRIX_6x86MX, x86_type 853 0 stevel jmp coma_bug 854 0 stevel 855 0 stevel MII: 856 0 stevel movl $X86_TYPE_CYRIX_MII, x86_type 857 0 stevel likeMII: 858 0 stevel jmp cpu_done 859 0 stevel 860 0 stevel maybeM3: 861 0 stevel /* 862 0 stevel * We are some chip that we cannot identify yet, an MIII perhaps. 863 0 stevel * We will be optimistic and hope that the chip is much like an MII, 864 0 stevel * and that cpuid is sane. Cyrix seemed to have gotten it right in 865 0 stevel * time for the MII, we can only hope it stayed that way. 866 0 stevel * Maybe the BIOS or Cyrix is trying to hint at something 867 0 stevel */ 868 0 stevel cmpl $0x500, %ebx 869 0 stevel je GXm 870 0 stevel 871 0 stevel cmpb $0x80, %al 872 0 stevel jae likelyM3 873 0 stevel 874 0 stevel /* 875 0 stevel * Just test for the features Cyrix is known for 876 0 stevel */ 877 0 stevel 878 0 stevel jmp MII 879 0 stevel 880 0 stevel likelyM3: 881 0 stevel /* 882 0 stevel * DIR0 with values from 0x80 to 0x8f indicates a VIA Cyrix III, aka 883 0 stevel * the Cyrix MIII. There may be parts later that use the same ranges 884 0 stevel * for DIR0 with special values in DIR1, maybe the VIA CIII, but for 885 0 stevel * now we will call anything with a DIR0 of 0x80 or higher an MIII. 886 0 stevel * The MIII is supposed to support large pages, but we will believe 887 0 stevel * it when we see it. For now we just enable and test for MII features. 888 0 stevel */ 889 0 stevel movl $X86_TYPE_VIA_CYRIX_III, x86_type 890 0 stevel jmp likeMII 891 0 stevel 892 0 stevel coma_bug: 893 0 stevel 894 0 stevel /* 895 0 stevel * With NO_LOCK set to 0 in CCR1, the usual state that BIOS enforces, some 896 0 stevel * bus cycles are issued with LOCK# asserted. With NO_LOCK set to 1, all bus 897 0 stevel * cycles except page table accesses and interrupt ACK cycles do not assert 898 0 stevel * LOCK#. xchgl is an instruction that asserts LOCK# if NO_LOCK is set to 0. 899 0 stevel * Due to a bug in the cpu core involving over-optimization of branch 900 0 stevel * prediction, register renaming, and execution of instructions down both the 901 0 stevel * X and Y pipes for the xchgl instruction, short loops can be written that 902 0 stevel * never de-assert LOCK# from one invocation of the loop to the next, ad 903 0 stevel * infinitum. The undesirable effect of this situation is that interrupts are 904 0 stevel * not serviced. The ideal workaround to this bug would be to set NO_LOCK to 905 0 stevel * 1. Unfortunately bus cycles that would otherwise have asserted LOCK# no 906 0 stevel * longer do, unless they are page table accesses or interrupt ACK cycles. 907 0 stevel * With LOCK# not asserted, these bus cycles are now cached. This can cause 908 0 stevel * undesirable behaviour if the ARR's are not configured correctly. Solaris 909 0 stevel * does not configure the ARR's, nor does it provide any useful mechanism for 910 0 stevel * doing so, thus the ideal workaround is not viable. Fortunately, the only 911 0 stevel * known exploits for this bug involve the xchgl instruction specifically. 912 0 stevel * There is a group of undocumented registers on Cyrix 6x86, 6x86L, and 913 0 stevel * 6x86MX cpu's which can be used to specify one instruction as a serializing 914 0 stevel * instruction. With the xchgl instruction serialized, LOCK# is still 915 0 stevel * asserted, but it is the sole instruction for which LOCK# is asserted. 916 0 stevel * There is now some added penalty for the xchgl instruction, but the usual 917 0 stevel * bus locking is preserved. This ingenious workaround was discovered by 918 0 stevel * disassembling a binary provided by Cyrix as a workaround for this bug on 919 0 stevel * Windows, but its not documented anywhere by Cyrix, nor is the bug actually 920 0 stevel * mentioned in any public errata! The only concern for this workaround is 921 0 stevel * that there may be similar undiscovered bugs with other instructions that 922 0 stevel * assert LOCK# that may be leveraged to similar ends. The fact that Cyrix 923 0 stevel * fixed this bug sometime late in 1997 and no other exploits other than 924 0 stevel * xchgl have been discovered is good indication that this workaround is 925 0 stevel * reasonable. 926 0 stevel */ 927 0 stevel 928 0 stevel .set CYRIX_DBR0, 0x30 / Debug Register 0 929 0 stevel .set CYRIX_DBR1, 0x31 / Debug Register 1 930 0 stevel .set CYRIX_DBR2, 0x32 / Debug Register 2 931 0 stevel .set CYRIX_DBR3, 0x33 / Debug Register 3 932 0 stevel .set CYRIX_DOR, 0x3c / Debug Opcode Register 933 0 stevel 934 0 stevel /* 935 0 stevel * What is known about DBR1, DBR2, DBR3, and DOR is that for normal 936 0 stevel * cpu execution DBR1, DBR2, and DBR3 are set to 0. To obtain opcode 937 0 stevel * serialization, DBR1, DBR2, and DBR3 are loaded with 0xb8, 0x7f, 938 0 stevel * and 0xff. Then, DOR is loaded with the one byte opcode. 939 0 stevel */ 940 0 stevel 941 0 stevel /* 942 0 stevel * select CCR3 943 0 stevel */ 944 0 stevel movb $CYRIX_CCR3, %al 945 0 stevel outb $CYRIX_CRI 946 0 stevel 947 0 stevel /* 948 0 stevel * read CCR3 and mask out MAPEN 949 0 stevel */ 950 0 stevel inb $CYRIX_CRD 951 0 stevel andb $0xf, %al 952 0 stevel 953 0 stevel /* 954 0 stevel * save masked CCR3 in %ah 955 0 stevel */ 956 0 stevel movb %al, %ah 957 0 stevel 958 0 stevel /* 959 0 stevel * select CCR3 960 0 stevel */ 961 0 stevel movb $CYRIX_CCR3, %al 962 0 stevel outb $CYRIX_CRI 963 0 stevel 964 0 stevel /* 965 0 stevel * enable MAPEN 966 0 stevel */ 967 0 stevel movb %ah, %al 968 0 stevel orb $0x10, %al 969 0 stevel outb $CYRIX_CRD 970 0 stevel 971 0 stevel /* 972 0 stevel * read DBR0 973 0 stevel */ 974 0 stevel movb $CYRIX_DBR0, %al 975 0 stevel outb $CYRIX_CRI 976 0 stevel inb $CYRIX_CRD 977 0 stevel 978 0 stevel /* 979 0 stevel * disable MATCH and save in %bh 980 0 stevel */ 981 0 stevel orb $0x80, %al 982 0 stevel movb %al, %bh 983 0 stevel 984 0 stevel /* 985 0 stevel * write DBR0 986 0 stevel */ 987 0 stevel movb $CYRIX_DBR0, %al 988 0 stevel outb $CYRIX_CRI 989 0 stevel movb %bh, %al 990 0 stevel outb $CYRIX_CRD 991 0 stevel 992 0 stevel /* 993 0 stevel * write DBR1 994 0 stevel */ 995 0 stevel movb $CYRIX_DBR1, %al 996 0 stevel outb $CYRIX_CRI 997 0 stevel movb $0xf8, %al 998 0 stevel outb $CYRIX_CRD 999 0 stevel 1000 0 stevel /* 1001 0 stevel * write DBR2 1002 0 stevel */ 1003 0 stevel movb $CYRIX_DBR2, %al 1004 0 stevel outb $CYRIX_CRI 1005 0 stevel movb $0x7f, %al 1006 0 stevel outb $CYRIX_CRD 1007 0 stevel 1008 0 stevel /* 1009 0 stevel * write DBR3 1010 0 stevel */ 1011 0 stevel movb $CYRIX_DBR3, %al 1012 0 stevel outb $CYRIX_CRI 1013 0 stevel xorb %al, %al 1014 0 stevel outb $CYRIX_CRD 1015 0 stevel 1016 0 stevel /* 1017 0 stevel * write DOR 1018 0 stevel */ 1019 0 stevel movb $CYRIX_DOR, %al 1020 0 stevel outb $CYRIX_CRI 1021 0 stevel movb $0x87, %al 1022 0 stevel outb $CYRIX_CRD 1023 0 stevel 1024 0 stevel /* 1025 0 stevel * enable MATCH 1026 0 stevel */ 1027 0 stevel movb $CYRIX_DBR0, %al 1028 0 stevel outb $CYRIX_CRI 1029 0 stevel movb %bh, %al 1030 0 stevel andb $0x7f, %al 1031 0 stevel outb $CYRIX_CRD 1032 0 stevel 1033 0 stevel /* 1034 0 stevel * disable MAPEN 1035 0 stevel */ 1036 0 stevel movb $0xc3, %al 1037 0 stevel outb $CYRIX_CRI 1038 0 stevel movb %ah, %al 1039 0 stevel outb $CYRIX_CRD 1040 0 stevel 1041 0 stevel jmp cpu_done 1042 0 stevel 1043 0 stevel cpu_done: 1044 3446 mrj 1045 0 stevel popfl /* Restore original FLAGS */ 1046 0 stevel popal /* Restore all registers */ 1047 0 stevel 1048 5084 johnlev #endif /* !__xpv */ 1049 5084 johnlev 1050 0 stevel /* 1051 0 stevel * mlsetup(%esp) gets called. 1052 0 stevel */ 1053 0 stevel pushl %esp 1054 0 stevel call mlsetup 1055 0 stevel addl $4, %esp 1056 0 stevel 1057 0 stevel /* 1058 0 stevel * We change our appearance to look like the real thread 0. 1059 0 stevel * (NOTE: making ourselves to be a real thread may be a noop) 1060 0 stevel * main() gets called. (NOTE: main() never returns). 1061 0 stevel */ 1062 0 stevel call main 1063 0 stevel /* NOTREACHED */ 1064 0 stevel pushl $__return_from_main 1065 0 stevel call panic 1066 0 stevel 1067 0 stevel /* NOTREACHED */ 1068 0 stevel cpu_486: 1069 0 stevel pushl $__unsupported_cpu 1070 0 stevel call panic 1071 3446 mrj SET_SIZE(_locore_start) 1072 0 stevel 1073 0 stevel #endif /* __lint */ 1074 0 stevel #endif /* !__amd64 */ 1075 0 stevel 1076 0 stevel 1077 0 stevel /* 1078 3446 mrj * For stack layout, see privregs.h 1079 0 stevel * When cmntrap gets called, the error code and trap number have been pushed. 1080 3446 mrj * When cmntrap_pushed gets called, the entire struct regs has been pushed. 1081 0 stevel */ 1082 0 stevel 1083 0 stevel #if defined(__lint) 1084 0 stevel 1085 0 stevel /* ARGSUSED */ 1086 0 stevel void 1087 0 stevel cmntrap() 1088 0 stevel {} 1089 0 stevel 1090 0 stevel #else /* __lint */ 1091 0 stevel 1092 0 stevel .globl trap /* C handler called below */ 1093 0 stevel 1094 0 stevel #if defined(__amd64) 1095 0 stevel 1096 0 stevel ENTRY_NP2(cmntrap, _cmntrap) 1097 0 stevel 1098 3446 mrj INTR_PUSH 1099 5084 johnlev 1100 3446 mrj ALTENTRY(cmntrap_pushed) 1101 3446 mrj 1102 3446 mrj movq %rsp, %rbp 1103 3446 mrj 1104 3446 mrj /* 1105 3446 mrj * - if this is a #pf i.e. T_PGFLT, %r15 is live 1106 3446 mrj * and contains the faulting address i.e. a copy of %cr2 1107 3446 mrj * 1108 3446 mrj * - if this is a #db i.e. T_SGLSTP, %r15 is live 1109 3446 mrj * and contains the value of %db6 1110 3446 mrj */ 1111 3446 mrj 1112 3446 mrj TRACE_PTR(%rdi, %rbx, %ebx, %rcx, $TT_TRAP) /* Uses labels 8 and 9 */ 1113 3446 mrj TRACE_REGS(%rdi, %rsp, %rbx, %rcx) /* Uses label 9 */ 1114 3446 mrj TRACE_STAMP(%rdi) /* Clobbers %eax, %edx, uses 9 */ 1115 0 stevel 1116 0 stevel /* 1117 0 stevel * We must first check if DTrace has set its NOFAULT bit. This 1118 3446 mrj * regrettably must happen before the trap stack is recorded, because 1119 3446 mrj * this requires a call to getpcstack() and may induce recursion if an 1120 3446 mrj * fbt::getpcstack: enabling is inducing the bad load. 1121 0 stevel */ 1122 0 stevel movl %gs:CPU_ID, %eax 1123 0 stevel shlq $CPU_CORE_SHIFT, %rax 1124 0 stevel leaq cpu_core(%rip), %r8 1125 0 stevel addq %r8, %rax 1126 0 stevel movw CPUC_DTRACE_FLAGS(%rax), %cx 1127 191 ahl testw $CPU_DTRACE_NOFAULT, %cx 1128 0 stevel jnz .dtrace_induced 1129 0 stevel 1130 3446 mrj TRACE_STACK(%rdi) 1131 3446 mrj 1132 3446 mrj movq %rbp, %rdi 1133 3446 mrj movq %r15, %rsi 1134 3446 mrj movl %gs:CPU_ID, %edx 1135 0 stevel 1136 0 stevel /* 1137 3446 mrj * We know that this isn't a DTrace non-faulting load; we can now safely 1138 3446 mrj * reenable interrupts. (In the case of pagefaults, we enter through an 1139 3446 mrj * interrupt gate.) 1140 0 stevel */ 1141 0 stevel ENABLE_INTR_FLAGS 1142 0 stevel 1143 0 stevel call trap /* trap(rp, addr, cpuid) handles all traps */ 1144 3446 mrj jmp _sys_rtt 1145 0 stevel 1146 0 stevel .dtrace_induced: 1147 3446 mrj cmpw $KCS_SEL, REGOFF_CS(%rbp) /* test CS for user-mode trap */ 1148 3446 mrj jne 2f /* if from user, panic */ 1149 0 stevel 1150 0 stevel cmpl $T_PGFLT, REGOFF_TRAPNO(%rbp) 1151 3446 mrj je 0f 1152 0 stevel 1153 0 stevel cmpl $T_GPFLT, REGOFF_TRAPNO(%rbp) 1154 3446 mrj jne 3f /* if not PF or GP, panic */ 1155 0 stevel 1156 0 stevel /* 1157 0 stevel * If we've taken a GPF, we don't (unfortunately) have the address that 1158 0 stevel * induced the fault. So instead of setting the fault to BADADDR, 1159 0 stevel * we'll set the fault to ILLOP. 1160 0 stevel */ 1161 0 stevel orw $CPU_DTRACE_ILLOP, %cx 1162 0 stevel movw %cx, CPUC_DTRACE_FLAGS(%rax) 1163 0 stevel jmp 1f 1164 0 stevel 0: 1165 0 stevel orw $CPU_DTRACE_BADADDR, %cx 1166 0 stevel movw %cx, CPUC_DTRACE_FLAGS(%rax) /* set fault to bad addr */ 1167 3446 mrj movq %r15, CPUC_DTRACE_ILLVAL(%rax) 1168 0 stevel /* fault addr is illegal value */ 1169 0 stevel 1: 1170 0 stevel movq REGOFF_RIP(%rbp), %rdi 1171 0 stevel movq %rdi, %r12 1172 0 stevel call dtrace_instr_size 1173 0 stevel addq %rax, %r12 1174 0 stevel movq %r12, REGOFF_RIP(%rbp) 1175 0 stevel INTR_POP 1176 3446 mrj IRET 1177 3446 mrj /*NOTREACHED*/ 1178 0 stevel 2: 1179 0 stevel leaq dtrace_badflags(%rip), %rdi 1180 0 stevel xorl %eax, %eax 1181 0 stevel call panic 1182 0 stevel 3: 1183 0 stevel leaq dtrace_badtrap(%rip), %rdi 1184 0 stevel xorl %eax, %eax 1185 0 stevel call panic 1186 0 stevel SET_SIZE(cmntrap) 1187 0 stevel SET_SIZE(_cmntrap) 1188 0 stevel 1189 0 stevel #elif defined(__i386) 1190 0 stevel 1191 3446 mrj 1192 0 stevel ENTRY_NP2(cmntrap, _cmntrap) 1193 0 stevel 1194 0 stevel INTR_PUSH 1195 3446 mrj 1196 3446 mrj ALTENTRY(cmntrap_pushed) 1197 3446 mrj 1198 3446 mrj movl %esp, %ebp 1199 3446 mrj 1200 3446 mrj /* 1201 3446 mrj * - if this is a #pf i.e. T_PGFLT, %esi is live 1202 3446 mrj * and contains the faulting address i.e. a copy of %cr2 1203 3446 mrj * 1204 3446 mrj * - if this is a #db i.e. T_SGLSTP, %esi is live 1205 3446 mrj * and contains the value of %db6 1206 3446 mrj */ 1207 0 stevel 1208 0 stevel TRACE_PTR(%edi, %ebx, %ebx, %ecx, $TT_TRAP) /* Uses labels 8 and 9 */ 1209 0 stevel TRACE_REGS(%edi, %esp, %ebx, %ecx) /* Uses label 9 */ 1210 0 stevel TRACE_STAMP(%edi) /* Clobbers %eax, %edx, uses 9 */ 1211 0 stevel 1212 0 stevel /* 1213 3446 mrj * We must first check if DTrace has set its NOFAULT bit. This 1214 3446 mrj * regrettably must happen before the trap stack is recorded, because 1215 3446 mrj * this requires a call to getpcstack() and may induce recursion if an 1216 3446 mrj * fbt::getpcstack: enabling is inducing the bad load. 1217 0 stevel */ 1218 0 stevel movl %gs:CPU_ID, %eax 1219 0 stevel shll $CPU_CORE_SHIFT, %eax 1220 0 stevel addl $cpu_core, %eax 1221 0 stevel movw CPUC_DTRACE_FLAGS(%eax), %cx 1222 191 ahl testw $CPU_DTRACE_NOFAULT, %cx 1223 3446 mrj jnz .dtrace_induced 1224 3446 mrj 1225 3446 mrj TRACE_STACK(%edi) 1226 3446 mrj 1227 3446 mrj pushl %gs:CPU_ID 1228 3446 mrj pushl %esi /* fault address for PGFLTs */ 1229 3446 mrj pushl %ebp /* ®s */ 1230 0 stevel 1231 0 stevel /* 1232 0 stevel * We know that this isn't a DTrace non-faulting load; we can now safely 1233 0 stevel * reenable interrupts. (In the case of pagefaults, we enter through an 1234 0 stevel * interrupt gate.) 1235 0 stevel */ 1236 0 stevel ENABLE_INTR_FLAGS 1237 0 stevel 1238 0 stevel call trap /* trap(rp, addr, cpuid) handles all traps */ 1239 0 stevel addl $12, %esp /* get argument off stack */ 1240 0 stevel jmp _sys_rtt 1241 0 stevel 1242 3446 mrj .dtrace_induced: 1243 3446 mrj cmpw $KCS_SEL, REGOFF_CS(%ebp) /* test CS for user-mode trap */ 1244 3446 mrj jne 2f /* if from user, panic */ 1245 0 stevel 1246 0 stevel cmpl $T_PGFLT, REGOFF_TRAPNO(%ebp) 1247 3446 mrj je 0f 1248 0 stevel 1249 0 stevel cmpl $T_GPFLT, REGOFF_TRAPNO(%ebp) 1250 3446 mrj jne 3f /* if not PF or GP, panic */ 1251 0 stevel 1252 0 stevel /* 1253 0 stevel * If we've taken a GPF, we don't (unfortunately) have the address that 1254 0 stevel * induced the fault. So instead of setting the fault to BADADDR, 1255 0 stevel * we'll set the fault to ILLOP. 1256 0 stevel */ 1257 0 stevel orw $CPU_DTRACE_ILLOP, %cx 1258 0 stevel movw %cx, CPUC_DTRACE_FLAGS(%eax) 1259 0 stevel jmp 1f 1260 0 stevel 0: 1261 0 stevel orw $CPU_DTRACE_BADADDR, %cx 1262 0 stevel movw %cx, CPUC_DTRACE_FLAGS(%eax) /* set fault to bad addr */ 1263 3446 mrj movl %esi, CPUC_DTRACE_ILLVAL(%eax) 1264 0 stevel /* fault addr is illegal value */ 1265 0 stevel 1: 1266 0 stevel pushl REGOFF_EIP(%ebp) 1267 0 stevel call dtrace_instr_size 1268 3446 mrj addl $4, %esp 1269 0 stevel movl REGOFF_EIP(%ebp), %ecx 1270 0 stevel addl %eax, %ecx 1271 0 stevel movl %ecx, REGOFF_EIP(%ebp) 1272 0 stevel INTR_POP_KERNEL 1273 3446 mrj IRET 1274 5084 johnlev /*NOTREACHED*/ 1275 0 stevel 2: 1276 0 stevel pushl $dtrace_badflags 1277 0 stevel call panic 1278 0 stevel 3: 1279 0 stevel pushl $dtrace_badtrap 1280 0 stevel call panic 1281 0 stevel SET_SIZE(cmntrap) 1282 0 stevel SET_SIZE(_cmntrap) 1283 0 stevel 1284 0 stevel #endif /* __i386 */ 1285 0 stevel 1286 0 stevel /* 1287 0 stevel * Declare a uintptr_t which has the size of _cmntrap to enable stack 1288 0 stevel * traceback code to know when a regs structure is on the stack. 1289 0 stevel */ 1290 0 stevel .globl _cmntrap_size 1291 0 stevel .align CLONGSIZE 1292 0 stevel _cmntrap_size: 1293 0 stevel .NWORD . - _cmntrap 1294 0 stevel .type _cmntrap_size, @object 1295 0 stevel 1296 0 stevel dtrace_badflags: 1297 0 stevel .string "bad DTrace flags" 1298 0 stevel 1299 0 stevel dtrace_badtrap: 1300 0 stevel .string "bad DTrace trap" 1301 0 stevel 1302 0 stevel #endif /* __lint */ 1303 0 stevel 1304 0 stevel #if defined(__lint) 1305 0 stevel 1306 0 stevel /* ARGSUSED */ 1307 0 stevel void 1308 0 stevel cmninttrap() 1309 0 stevel {} 1310 0 stevel 1311 5084 johnlev #if !defined(__xpv) 1312 3446 mrj void 1313 3446 mrj bop_trap_handler(void) 1314 3446 mrj {} 1315 5084 johnlev #endif 1316 3446 mrj 1317 0 stevel #else /* __lint */ 1318 0 stevel 1319 0 stevel .globl trap /* C handler called below */ 1320 0 stevel 1321 0 stevel #if defined(__amd64) 1322 0 stevel 1323 0 stevel ENTRY_NP(cmninttrap) 1324 0 stevel 1325 0 stevel INTR_PUSH 1326 3446 mrj INTGATE_INIT_KERNEL_FLAGS 1327 0 stevel 1328 0 stevel TRACE_PTR(%rdi, %rbx, %ebx, %rcx, $TT_TRAP) /* Uses labels 8 and 9 */ 1329 0 stevel TRACE_REGS(%rdi, %rsp, %rbx, %rcx) /* Uses label 9 */ 1330 0 stevel TRACE_STAMP(%rdi) /* Clobbers %eax, %edx, uses 9 */ 1331 0 stevel 1332 0 stevel movq %rsp, %rbp 1333 0 stevel 1334 0 stevel movl %gs:CPU_ID, %edx 1335 0 stevel xorl %esi, %esi 1336 0 stevel movq %rsp, %rdi 1337 0 stevel call trap /* trap(rp, addr, cpuid) handles all traps */ 1338 0 stevel jmp _sys_rtt 1339 0 stevel SET_SIZE(cmninttrap) 1340 3446 mrj 1341 5084 johnlev #if !defined(__xpv) 1342 3446 mrj /* 1343 3446 mrj * Handle traps early in boot. Just revectors into C quickly as 1344 3446 mrj * these are always fatal errors. 1345 10993 Dan * 1346 10993 Dan * Adjust %rsp to get same stack layout as in 32bit mode for bop_trap(). 1347 3446 mrj */ 1348 3446 mrj ENTRY(bop_trap_handler) 1349 3446 mrj movq %rsp, %rdi 1350 10993 Dan sub $8, %rsp 1351 3446 mrj call bop_trap 1352 3446 mrj SET_SIZE(bop_trap_handler) 1353 5084 johnlev #endif 1354 0 stevel 1355 0 stevel #elif defined(__i386) 1356 0 stevel 1357 0 stevel ENTRY_NP(cmninttrap) 1358 0 stevel 1359 0 stevel INTR_PUSH 1360 3446 mrj INTGATE_INIT_KERNEL_FLAGS 1361 3446 mrj 1362 3446 mrj TRACE_PTR(%edi, %ebx, %ebx, %ecx, $TT_TRAP) /* Uses labels 8 and 9 */ 1363 3446 mrj TRACE_REGS(%edi, %esp, %ebx, %ecx) /* Uses label 9 */ 1364 3446 mrj TRACE_STAMP(%edi) /* Clobbers %eax, %edx, uses 9 */ 1365 0 stevel 1366 0 stevel movl %esp, %ebp 1367 0 stevel 1368 3446 mrj TRACE_STACK(%edi) 1369 3446 mrj 1370 0 stevel pushl %gs:CPU_ID 1371 3446 mrj pushl $0 1372 3446 mrj pushl %ebp 1373 0 stevel call trap /* trap(rp, addr, cpuid) handles all traps */ 1374 3446 mrj addl $12, %esp 1375 0 stevel jmp _sys_rtt 1376 0 stevel SET_SIZE(cmninttrap) 1377 3446 mrj 1378 5084 johnlev #if !defined(__xpv) 1379 3446 mrj /* 1380 3446 mrj * Handle traps early in boot. Just revectors into C quickly as 1381 3446 mrj * these are always fatal errors. 1382 3446 mrj */ 1383 3446 mrj ENTRY(bop_trap_handler) 1384 3446 mrj movl %esp, %eax 1385 3446 mrj pushl %eax 1386 3446 mrj call bop_trap 1387 3446 mrj SET_SIZE(bop_trap_handler) 1388 5084 johnlev #endif 1389 0 stevel 1390 0 stevel #endif /* __i386 */ 1391 0 stevel 1392 0 stevel #endif /* __lint */ 1393 0 stevel 1394 0 stevel #if defined(__lint) 1395 0 stevel 1396 0 stevel /* ARGSUSED */ 1397 0 stevel void 1398 0 stevel dtrace_trap() 1399 0 stevel {} 1400 0 stevel 1401 0 stevel #else /* __lint */ 1402 0 stevel 1403 0 stevel .globl dtrace_user_probe 1404 0 stevel 1405 0 stevel #if defined(__amd64) 1406 0 stevel 1407 0 stevel ENTRY_NP(dtrace_trap) 1408 0 stevel 1409 0 stevel INTR_PUSH 1410 0 stevel 1411 0 stevel TRACE_PTR(%rdi, %rbx, %ebx, %rcx, $TT_TRAP) /* Uses labels 8 and 9 */ 1412 0 stevel TRACE_REGS(%rdi, %rsp, %rbx, %rcx) /* Uses label 9 */ 1413 0 stevel TRACE_STAMP(%rdi) /* Clobbers %eax, %edx, uses 9 */ 1414 0 stevel 1415 0 stevel movq %rsp, %rbp 1416 0 stevel 1417 0 stevel movl %gs:CPU_ID, %edx 1418 5084 johnlev #if defined(__xpv) 1419 5084 johnlev movq %gs:CPU_VCPU_INFO, %rsi 1420 5084 johnlev movq VCPU_INFO_ARCH_CR2(%rsi), %rsi 1421 5084 johnlev #else 1422 0 stevel movq %cr2, %rsi 1423 5084 johnlev #endif 1424 0 stevel movq %rsp, %rdi 1425 0 stevel 1426 0 stevel ENABLE_INTR_FLAGS 1427 0 stevel 1428 0 stevel call dtrace_user_probe /* dtrace_user_probe(rp, addr, cpuid) */ 1429 0 stevel jmp _sys_rtt 1430 0 stevel 1431 0 stevel SET_SIZE(dtrace_trap) 1432 0 stevel 1433 0 stevel #elif defined(__i386) 1434 0 stevel 1435 0 stevel ENTRY_NP(dtrace_trap) 1436 0 stevel 1437 0 stevel INTR_PUSH 1438 0 stevel 1439 0 stevel TRACE_PTR(%edi, %ebx, %ebx, %ecx, $TT_TRAP) /* Uses labels 8 and 9 */ 1440 0 stevel TRACE_REGS(%edi, %esp, %ebx, %ecx) /* Uses label 9 */ 1441 0 stevel TRACE_STAMP(%edi) /* Clobbers %eax, %edx, uses 9 */ 1442 0 stevel 1443 0 stevel movl %esp, %ebp 1444 0 stevel 1445 0 stevel pushl %gs:CPU_ID 1446 5084 johnlev #if defined(__xpv) 1447 5084 johnlev movl %gs:CPU_VCPU_INFO, %eax 1448 5084 johnlev movl VCPU_INFO_ARCH_CR2(%eax), %eax 1449 5084 johnlev #else 1450 0 stevel movl %cr2, %eax 1451 5084 johnlev #endif 1452 0 stevel pushl %eax 1453 0 stevel pushl %ebp 1454 0 stevel 1455 3446 mrj ENABLE_INTR_FLAGS 1456 0 stevel 1457 0 stevel call dtrace_user_probe /* dtrace_user_probe(rp, addr, cpuid) */ 1458 0 stevel addl $12, %esp /* get argument off stack */ 1459 0 stevel 1460 0 stevel jmp _sys_rtt 1461 0 stevel SET_SIZE(dtrace_trap) 1462 0 stevel 1463 0 stevel #endif /* __i386 */ 1464 0 stevel 1465 0 stevel #endif /* __lint */ 1466 0 stevel 1467 0 stevel /* 1468 0 stevel * Return from _sys_trap routine. 1469 0 stevel */ 1470 0 stevel 1471 0 stevel #if defined(__lint) 1472 0 stevel 1473 0 stevel void 1474 0 stevel lwp_rtt_initial(void) 1475 0 stevel {} 1476 0 stevel 1477 0 stevel void 1478 0 stevel lwp_rtt(void) 1479 0 stevel {} 1480 0 stevel 1481 0 stevel void 1482 0 stevel _sys_rtt(void) 1483 0 stevel {} 1484 0 stevel 1485 0 stevel #else /* __lint */ 1486 0 stevel 1487 0 stevel #if defined(__amd64) 1488 0 stevel 1489 0 stevel ENTRY_NP(lwp_rtt_initial) 1490 0 stevel movq %gs:CPU_THREAD, %r15 1491 0 stevel movq T_STACK(%r15), %rsp /* switch to the thread stack */ 1492 7656 Sherry movq %rsp, %rbp 1493 0 stevel call __dtrace_probe___proc_start 1494 0 stevel jmp _lwp_rtt 1495 0 stevel 1496 0 stevel ENTRY_NP(lwp_rtt) 1497 0 stevel 1498 0 stevel /* 1499 0 stevel * r14 lwp 1500 0 stevel * rdx lwp->lwp_procp 1501 0 stevel * r15 curthread 1502 0 stevel */ 1503 0 stevel 1504 0 stevel movq %gs:CPU_THREAD, %r15 1505 0 stevel movq T_STACK(%r15), %rsp /* switch to the thread stack */ 1506 7656 Sherry movq %rsp, %rbp 1507 0 stevel _lwp_rtt: 1508 0 stevel call __dtrace_probe___proc_lwp__start 1509 0 stevel movq %gs:CPU_LWP, %r14 1510 0 stevel movq LWP_PROCP(%r14), %rdx 1511 0 stevel 1512 0 stevel /* 1513 0 stevel * XX64 Is the stack misaligned correctly at this point? 1514 0 stevel * If not, we need to do a push before calling anything .. 1515 0 stevel */ 1516 0 stevel 1517 0 stevel #if defined(DEBUG) 1518 0 stevel /* 1519 0 stevel * If we were to run lwp_savectx at this point -without- 1520 4503 sudheer * pcb_rupdate being set to 1, we'd end up sampling the hardware 1521 0 stevel * state left by the previous running lwp, rather than setting 1522 0 stevel * the values requested by the lwp creator. Bad. 1523 0 stevel */ 1524 4503 sudheer testb $0x1, PCB_RUPDATE(%r14) 1525 0 stevel jne 1f 1526 0 stevel leaq _no_pending_updates(%rip), %rdi 1527 0 stevel movl $__LINE__, %esi 1528 0 stevel movq %r14, %rdx 1529 0 stevel xorl %eax, %eax 1530 0 stevel call panic 1531 0 stevel _no_pending_updates: 1532 4503 sudheer .string "locore.s:%d lwp_rtt(lwp %p) but pcb_rupdate != 1" 1533 0 stevel 1: 1534 0 stevel #endif 1535 0 stevel 1536 0 stevel /* 1537 0 stevel * If agent lwp, clear %fs and %gs 1538 0 stevel */ 1539 0 stevel cmpq %r15, P_AGENTTP(%rdx) 1540 0 stevel jne 1f 1541 0 stevel xorl %ecx, %ecx 1542 0 stevel movq %rcx, REGOFF_FS(%rsp) 1543 0 stevel movq %rcx, REGOFF_GS(%rsp) 1544 0 stevel movw %cx, LWP_PCB_FS(%r14) 1545 0 stevel movw %cx, LWP_PCB_GS(%r14) 1546 0 stevel 1: 1547 0 stevel call dtrace_systrace_rtt 1548 0 stevel movq REGOFF_RDX(%rsp), %rsi 1549 0 stevel movq REGOFF_RAX(%rsp), %rdi 1550 0 stevel call post_syscall /* post_syscall(rval1, rval2) */ 1551 3446 mrj 1552 3446 mrj /* 1553 3446 mrj * set up to take fault on first use of fp 1554 3446 mrj */ 1555 3446 mrj STTS(%rdi) 1556 3446 mrj 1557 3446 mrj /* 1558 3446 mrj * XXX - may want a fast path that avoids sys_rtt_common in the 1559 3446 mrj * most common case. 1560 3446 mrj */ 1561 0 stevel ALTENTRY(_sys_rtt) 1562 3446 mrj CLI(%rax) /* disable interrupts */ 1563 5084 johnlev ALTENTRY(_sys_rtt_ints_disabled) 1564 3446 mrj movq %rsp, %rdi /* pass rp to sys_rtt_common */ 1565 3446 mrj call sys_rtt_common /* do common sys_rtt tasks */ 1566 3446 mrj testq %rax, %rax /* returning to userland? */ 1567 0 stevel jz sr_sup 1568 0 stevel 1569 0 stevel /* 1570 0 stevel * Return to user 1571 0 stevel */ 1572 3446 mrj ASSERT_UPCALL_MASK_IS_SET 1573 0 stevel cmpw $UCS_SEL, REGOFF_CS(%rsp) /* test for native (64-bit) lwp? */ 1574 0 stevel je sys_rtt_syscall 1575 0 stevel 1576 0 stevel /* 1577 3446 mrj * Return to 32-bit userland 1578 0 stevel */ 1579 0 stevel ALTENTRY(sys_rtt_syscall32) 1580 3446 mrj USER32_POP 1581 3446 mrj IRET 1582 3446 mrj /*NOTREACHED*/ 1583 5084 johnlev 1584 3446 mrj ALTENTRY(sys_rtt_syscall) 1585 0 stevel /* 1586 3446 mrj * Return to 64-bit userland 1587 0 stevel */ 1588 3446 mrj USER_POP 1589 5084 johnlev ALTENTRY(nopop_sys_rtt_syscall) 1590 3446 mrj IRET 1591 0 stevel /*NOTREACHED*/ 1592 5084 johnlev SET_SIZE(nopop_sys_rtt_syscall) 1593 0 stevel 1594 0 stevel /* 1595 0 stevel * Return to supervisor 1596 3446 mrj * NOTE: to make the check in trap() that tests if we are executing 1597 3446 mrj * segment register fixup/restore code work properly, sr_sup MUST be 1598 3446 mrj * after _sys_rtt . 1599 0 stevel */ 1600 0 stevel ALTENTRY(sr_sup) 1601 0 stevel /* 1602 0 stevel * Restore regs before doing iretq to kernel mode 1603 0 stevel */ 1604 0 stevel INTR_POP 1605 3446 mrj IRET 1606 5084 johnlev .globl _sys_rtt_end 1607 5084 johnlev _sys_rtt_end: 1608 3446 mrj /*NOTREACHED*/ 1609 0 stevel SET_SIZE(sr_sup) 1610 5084 johnlev SET_SIZE(_sys_rtt_end) 1611 0 stevel SET_SIZE(lwp_rtt) 1612 0 stevel SET_SIZE(lwp_rtt_initial) 1613 5084 johnlev SET_SIZE(_sys_rtt_ints_disabled) 1614 0 stevel SET_SIZE(_sys_rtt) 1615 0 stevel SET_SIZE(sys_rtt_syscall) 1616 0 stevel SET_SIZE(sys_rtt_syscall32) 1617 0 stevel 1618 0 stevel #elif defined(__i386) 1619 0 stevel 1620 0 stevel ENTRY_NP(lwp_rtt_initial) 1621 0 stevel movl %gs:CPU_THREAD, %eax 1622 0 stevel movl T_STACK(%eax), %esp /* switch to the thread stack */ 1623 7656 Sherry movl %esp, %ebp 1624 0 stevel call __dtrace_probe___proc_start 1625 0 stevel jmp _lwp_rtt 1626 0 stevel 1627 0 stevel ENTRY_NP(lwp_rtt) 1628 0 stevel movl %gs:CPU_THREAD, %eax 1629 0 stevel movl T_STACK(%eax), %esp /* switch to the thread stack */ 1630 7656 Sherry movl %esp, %ebp 1631 0 stevel _lwp_rtt: 1632 0 stevel call __dtrace_probe___proc_lwp__start 1633 0 stevel 1634 0 stevel /* 1635 0 stevel * If agent lwp, clear %fs and %gs. 1636 0 stevel */ 1637 0 stevel movl %gs:CPU_LWP, %eax 1638 0 stevel movl LWP_PROCP(%eax), %edx 1639 0 stevel 1640 0 stevel cmpl %eax, P_AGENTTP(%edx) 1641 0 stevel jne 1f 1642 0 stevel movl $0, REGOFF_FS(%esp) 1643 0 stevel movl $0, REGOFF_GS(%esp) 1644 0 stevel 1: 1645 0 stevel call dtrace_systrace_rtt 1646 0 stevel movl REGOFF_EDX(%esp), %edx 1647 0 stevel movl REGOFF_EAX(%esp), %eax 1648 0 stevel pushl %edx 1649 0 stevel pushl %eax 1650 0 stevel call post_syscall /* post_syscall(rval1, rval2) */ 1651 0 stevel addl $8, %esp 1652 0 stevel 1653 3446 mrj /* 1654 3446 mrj * set up to take fault on first use of fp 1655 3446 mrj */ 1656 3446 mrj STTS(%eax) 1657 3446 mrj 1658 3446 mrj /* 1659 3446 mrj * XXX - may want a fast path that avoids sys_rtt_common in the 1660 3446 mrj * most common case. 1661 3446 mrj */ 1662 0 stevel ALTENTRY(_sys_rtt) 1663 3446 mrj CLI(%eax) /* disable interrupts */ 1664 5084 johnlev ALTENTRY(_sys_rtt_ints_disabled) 1665 3446 mrj pushl %esp /* pass rp to sys_rtt_common */ 1666 3446 mrj call sys_rtt_common 1667 3446 mrj addl $4, %esp /* pop arg */ 1668 3446 mrj testl %eax, %eax /* test for return to user mode */ 1669 0 stevel jz sr_sup 1670 0 stevel 1671 0 stevel /* 1672 0 stevel * Return to User. 1673 0 stevel */ 1674 0 stevel ALTENTRY(sys_rtt_syscall) 1675 0 stevel INTR_POP_USER 1676 5084 johnlev 1677 5084 johnlev /* 1678 5084 johnlev * There can be no instructions between this label and IRET or 1679 5084 johnlev * we could end up breaking linux brand support. See label usage 1680 5084 johnlev * in lx_brand_int80_callback for an example. 1681 5084 johnlev */ 1682 5084 johnlev ALTENTRY(nopop_sys_rtt_syscall) 1683 3446 mrj IRET 1684 5084 johnlev /*NOTREACHED*/ 1685 5084 johnlev SET_SIZE(nopop_sys_rtt_syscall) 1686 5084 johnlev 1687 5084 johnlev ALTENTRY(_sys_rtt_end) 1688 0 stevel 1689 0 stevel /* 1690 0 stevel * Return to supervisor 1691 0 stevel */ 1692 0 stevel ALTENTRY(sr_sup) 1693 0 stevel 1694 0 stevel /* 1695 0 stevel * Restore regs before doing iret to kernel mode 1696 0 stevel */ 1697 3446 mrj INTR_POP_KERNEL 1698 3446 mrj IRET 1699 5084 johnlev /*NOTREACHED*/ 1700 0 stevel 1701 0 stevel SET_SIZE(sr_sup) 1702 5084 johnlev SET_SIZE(_sys_rtt_end) 1703 0 stevel SET_SIZE(lwp_rtt) 1704 0 stevel SET_SIZE(lwp_rtt_initial) 1705 5084 johnlev SET_SIZE(_sys_rtt_ints_disabled) 1706 0 stevel SET_SIZE(_sys_rtt) 1707 0 stevel SET_SIZE(sys_rtt_syscall) 1708 0 stevel 1709 0 stevel #endif /* __i386 */ 1710 0 stevel 1711 0 stevel #endif /* __lint */ 1712 0 stevel 1713 0 stevel #if defined(__lint) 1714 0 stevel 1715 0 stevel /* 1716 0 stevel * So why do we have to deal with all this crud in the world of ia32? 1717 0 stevel * 1718 0 stevel * Basically there are four classes of ia32 implementations, those that do not 1719 0 stevel * have a TSC, those that have a marginal TSC that is broken to the extent 1720 0 stevel * that it is useless, those that have a marginal TSC that is not quite so 1721 0 stevel * horribly broken and can be used with some care, and those that have a 1722 0 stevel * reliable TSC. This crud has to be here in order to sift through all the 1723 0 stevel * variants. 1724 0 stevel */ 1725 0 stevel 1726 0 stevel /*ARGSUSED*/ 1727 0 stevel uint64_t 1728 0 stevel freq_tsc(uint32_t *pit_counter) 1729 0 stevel { 1730 0 stevel return (0); 1731 0 stevel } 1732 0 stevel 1733 0 stevel #else /* __lint */ 1734 0 stevel 1735 0 stevel #if defined(__amd64) 1736 0 stevel 1737 0 stevel /* 1738 0 stevel * XX64 quick and dirty port from the i386 version. Since we 1739 0 stevel * believe the amd64 tsc is more reliable, could this code be 1740 0 stevel * simpler? 1741 0 stevel */ 1742 0 stevel ENTRY_NP(freq_tsc) 1743 0 stevel pushq %rbp 1744 0 stevel movq %rsp, %rbp 1745 0 stevel movq %rdi, %r9 /* save pit_counter */ 1746 0 stevel pushq %rbx 1747 0 stevel 1748 0 stevel / We have a TSC, but we have no way in general to know how reliable it is. 1749 0 stevel / Usually a marginal TSC behaves appropriately unless not enough time 1750 0 stevel / elapses between reads. A reliable TSC can be read as often and as rapidly 1751 0 stevel / as desired. The simplistic approach of reading the TSC counter and 1752 0 stevel / correlating to the PIT counter cannot be naively followed. Instead estimates 1753 0 stevel / have to be taken to successively refine a guess at the speed of the cpu 1754 0 stevel / and then the TSC and PIT counter are correlated. In practice very rarely 1755 0 stevel / is more than one quick loop required for an estimate. Measures have to be 1756 0 stevel / taken to prevent the PIT counter from wrapping beyond its resolution and for 1757 0 stevel / measuring the clock rate of very fast processors. 1758 0 stevel / 1759 0 stevel / The following constant can be tuned. It should be such that the loop does 1760 0 stevel / not take too many nor too few PIT counts to execute. If this value is too 1761 0 stevel / large, then on slow machines the loop will take a long time, or the PIT 1762 0 stevel / counter may even wrap. If this value is too small, then on fast machines 1763 0 stevel / the PIT counter may count so few ticks that the resolution of the PIT 1764 0 stevel / itself causes a bad guess. Because this code is used in machines with 1765 0 stevel / marginal TSC's and/or IO, if this value is too small on those, it may 1766 0 stevel / cause the calculated cpu frequency to vary slightly from boot to boot. 1767 0 stevel / 1768 0 stevel / In all cases even if this constant is set inappropriately, the algorithm 1769 0 stevel / will still work and the caller should be able to handle variances in the 1770 0 stevel / calculation of cpu frequency, but the calculation will be inefficient and 1771 0 stevel / take a disproportionate amount of time relative to a well selected value. 1772 0 stevel / As the slowest supported cpu becomes faster, this constant should be 1773 0 stevel / carefully increased. 1774 0 stevel 1775 0 stevel movl $0x8000, %ecx 1776 0 stevel 1777 0 stevel / to make sure the instruction cache has been warmed 1778 0 stevel clc 1779 0 stevel 1780 0 stevel jmp freq_tsc_loop 1781 0 stevel 1782 0 stevel / The following block of code up to and including the latching of the PIT 1783 0 stevel / counter after freq_tsc_perf_loop is very critical and very carefully 1784 0 stevel / written, it should only be modified with great care. freq_tsc_loop to 1785 0 stevel / freq_tsc_perf_loop fits exactly in 16 bytes as do the instructions in 1786 0 stevel / freq_tsc_perf_loop up to the unlatching of the PIT counter. 1787 0 stevel 1788 0 stevel .align 32 1789 0 stevel freq_tsc_loop: 1790 0 stevel / save the loop count in %ebx 1791 0 stevel movl %ecx, %ebx 1792 0 stevel 1793 0 stevel / initialize the PIT counter and start a count down 1794 0 stevel movb $PIT_LOADMODE, %al 1795 0 stevel outb $PITCTL_PORT 1796 0 stevel movb $0xff, %al 1797 0 stevel outb $PITCTR0_PORT 1798 0 stevel outb $PITCTR0_PORT 1799 0 stevel 1800 0 stevel / read the TSC and store the TS in %edi:%esi 1801 0 stevel rdtsc 1802 0 stevel movl %eax, %esi 1803 0 stevel 1804 0 stevel freq_tsc_perf_loop: 1805 0 stevel movl %edx, %edi 1806 0 stevel movl %eax, %esi 1807 0 stevel movl %edx, %edi 1808 0 stevel loop freq_tsc_perf_loop 1809 0 stevel 1810 0 stevel / read the TSC and store the LSW in %ecx 1811 0 stevel rdtsc 1812 0 stevel movl %eax, %ecx 1813 0 stevel 1814 0 stevel / latch the PIT counter and status 1815 0 stevel movb $_CONST(PIT_READBACK|PIT_READBACKC0), %al 1816 0 stevel outb $PITCTL_PORT 1817 0 stevel 1818 0 stevel / remember if the icache has been warmed 1819 0 stevel setc %ah 1820 0 stevel 1821 0 stevel / read the PIT status 1822 0 stevel inb $PITCTR0_PORT 1823 0 stevel shll $8, %eax 1824 0 stevel 1825 0 stevel / read PIT count 1826 0 stevel inb $PITCTR0_PORT 1827 0 stevel shll $8, %eax 1828 0 stevel inb $PITCTR0_PORT 1829 0 stevel bswap %eax 1830 0 stevel 1831 0 stevel / check to see if the PIT count was loaded into the CE 1832 0 stevel btw $_CONST(PITSTAT_NULLCNT+8), %ax 1833 0 stevel jc freq_tsc_increase_count 1834 0 stevel 1835 0 stevel / check to see if PIT counter wrapped 1836 0 stevel btw $_CONST(PITSTAT_OUTPUT+8), %ax 1837 0 stevel jnc freq_tsc_pit_did_not_wrap 1838 0 stevel 1839 0 stevel / halve count 1840 0 stevel shrl $1, %ebx 1841 0 stevel movl %ebx, %ecx 1842 0 stevel 1843 0 stevel / the instruction cache has been warmed 1844 0 stevel stc 1845 0 stevel 1846 0 stevel jmp freq_tsc_loop 1847 0 stevel 1848 0 stevel freq_tsc_increase_count: 1849 0 stevel shll $1, %ebx 1850 0 stevel jc freq_tsc_too_fast 1851 0 stevel 1852 0 stevel movl %ebx, %ecx 1853 0 stevel 1854 0 stevel / the instruction cache has been warmed 1855 0 stevel stc 1856 0 stevel 1857 0 stevel jmp freq_tsc_loop 1858 0 stevel 1859 0 stevel freq_tsc_pit_did_not_wrap: 1860 0 stevel roll $16, %eax 1861 0 stevel 1862 0 stevel cmpw $0x2000, %ax 1863 0 stevel notw %ax 1864 0 stevel jb freq_tsc_sufficient_duration 1865 0 stevel 1866 0 stevel freq_tsc_calculate: 1867 0 stevel / in mode 0, the PIT loads the count into the CE on the first CLK pulse, 1868 0 stevel / then on the second CLK pulse the CE is decremented, therefore mode 0 1869 0 stevel / is really a (count + 1) counter, ugh 1870 0 stevel xorl %esi, %esi 1871 0 stevel movw %ax, %si 1872 0 stevel incl %esi 1873 0 stevel 1874 0 stevel movl $0xf000, %eax 1875 0 stevel mull %ebx 1876 0 stevel 1877 0 stevel / tuck away (target_pit_count * loop_count) 1878 0 stevel movl %edx, %ecx 1879 0 stevel movl %eax, %ebx 1880 0 stevel 1881 0 stevel movl %esi, %eax 1882 0 stevel movl $0xffffffff, %edx 1883 0 stevel mull %edx 1884 0 stevel 1885 0 stevel addl %esi, %eax 1886 0 stevel adcl $0, %edx 1887 0 stevel 1888 0 stevel cmpl %ecx, %edx 1889 0 stevel ja freq_tsc_div_safe 1890 0 stevel jb freq_tsc_too_fast 1891 0 stevel 1892 0 stevel cmpl %ebx, %eax 1893 0 stevel jbe freq_tsc_too_fast 1894 0 stevel 1895 0 stevel freq_tsc_div_safe: 1896 0 stevel movl %ecx, %edx 1897 0 stevel movl %ebx, %eax 1898 0 stevel 1899 0 stevel movl %esi, %ecx 1900 0 stevel divl %ecx 1901 0 stevel 1902 0 stevel movl %eax, %ecx 1903 0 stevel 1904 0 stevel / the instruction cache has been warmed 1905 0 stevel stc 1906 0 stevel 1907 0 stevel jmp freq_tsc_loop 1908 0 stevel 1909 0 stevel freq_tsc_sufficient_duration: 1910 0 stevel / test to see if the icache has been warmed 1911 0 stevel btl $16, %eax 1912 0 stevel jnc freq_tsc_calculate 1913 0 stevel 1914 0 stevel / recall mode 0 is a (count + 1) counter 1915 0 stevel andl $0xffff, %eax 1916 0 stevel incl %eax 1917 0 stevel 1918 0 stevel / save the number of PIT counts 1919 0 stevel movl %eax, (%r9) 1920 0 stevel 1921 0 stevel / calculate the number of TS's that elapsed 1922 0 stevel movl %ecx, %eax 1923 0 stevel subl %esi, %eax 1924 0 stevel sbbl %edi, %edx 1925 0 stevel 1926 0 stevel jmp freq_tsc_end 1927 0 stevel 1928 0 stevel freq_tsc_too_fast: 1929 0 stevel / return 0 as a 64 bit quantity 1930 0 stevel xorl %eax, %eax 1931 0 stevel xorl %edx, %edx 1932 0 stevel 1933 0 stevel freq_tsc_end: 1934 0 stevel shlq $32, %rdx 1935 0 stevel orq %rdx, %rax 1936 0 stevel 1937 0 stevel popq %rbx 1938 0 stevel leaveq 1939 0 stevel ret 1940 0 stevel SET_SIZE(freq_tsc) 1941 0 stevel 1942 0 stevel #elif defined(__i386) 1943 0 stevel 1944 0 stevel ENTRY_NP(freq_tsc) 1945 0 stevel pushl %ebp 1946 0 stevel movl %esp, %ebp 1947 0 stevel pushl %edi 1948 0 stevel pushl %esi 1949 0 stevel pushl %ebx 1950 0 stevel 1951 0 stevel / We have a TSC, but we have no way in general to know how reliable it is. 1952 0 stevel / Usually a marginal TSC behaves appropriately unless not enough time 1953 0 stevel / elapses between reads. A reliable TSC can be read as often and as rapidly 1954 0 stevel / as desired. The simplistic approach of reading the TSC counter and 1955 0 stevel / correlating to the PIT counter cannot be naively followed. Instead estimates 1956 0 stevel / have to be taken to successively refine a guess at the speed of the cpu 1957 0 stevel / and then the TSC and PIT counter are correlated. In practice very rarely 1958 0 stevel / is more than one quick loop required for an estimate. Measures have to be 1959 0 stevel / taken to prevent the PIT counter from wrapping beyond its resolution and for 1960 0 stevel / measuring the clock rate of very fast processors. 1961 0 stevel / 1962 0 stevel / The following constant can be tuned. It should be such that the loop does 1963 0 stevel / not take too many nor too few PIT counts to execute. If this value is too 1964 0 stevel / large, then on slow machines the loop will take a long time, or the PIT 1965 0 stevel / counter may even wrap. If this value is too small, then on fast machines 1966 0 stevel / the PIT counter may count so few ticks that the resolution of the PIT 1967 0 stevel / itself causes a bad guess. Because this code is used in machines with 1968 0 stevel / marginal TSC's and/or IO, if this value is too small on those, it may 1969 0 stevel / cause the calculated cpu frequency to vary slightly from boot to boot. 1970 0 stevel / 1971 0 stevel / In all cases even if this constant is set inappropriately, the algorithm 1972 0 stevel / will still work and the caller should be able to handle variances in the 1973 0 stevel / calculation of cpu frequency, but the calculation will be inefficient and 1974 0 stevel / take a disproportionate amount of time relative to a well selected value. 1975 0 stevel / As the slowest supported cpu becomes faster, this constant should be 1976 0 stevel / carefully increased. 1977 0 stevel 1978 0 stevel movl $0x8000, %ecx 1979 0 stevel 1980 0 stevel / to make sure the instruction cache has been warmed 1981 0 stevel clc 1982 0 stevel 1983 0 stevel jmp freq_tsc_loop 1984 0 stevel 1985 0 stevel / The following block of code up to and including the latching of the PIT 1986 0 stevel / counter after freq_tsc_perf_loop is very critical and very carefully 1987 0 stevel / written, it should only be modified with great care. freq_tsc_loop to 1988 0 stevel / freq_tsc_perf_loop fits exactly in 16 bytes as do the instructions in 1989 0 stevel / freq_tsc_perf_loop up to the unlatching of the PIT counter. 1990 0 stevel 1991 0 stevel .align 32 1992 0 stevel freq_tsc_loop: 1993 0 stevel / save the loop count in %ebx 1994 0 stevel movl %ecx, %ebx 1995 0 stevel 1996 0 stevel / initialize the PIT counter and start a count down 1997 0 stevel movb $PIT_LOADMODE, %al 1998 0 stevel outb $PITCTL_PORT 1999 0 stevel movb $0xff, %al 2000 0 stevel outb $PITCTR0_PORT 2001 0 stevel outb $PITCTR0_PORT 2002 0 stevel 2003 0 stevel / read the TSC and store the TS in %edi:%esi 2004 0 stevel rdtsc 2005 0 stevel movl %eax, %esi 2006 0 stevel 2007 0 stevel freq_tsc_perf_loop: 2008 0 stevel movl %edx, %edi 2009 0 stevel movl %eax, %esi 2010 0 stevel movl %edx, %edi 2011 0 stevel loop freq_tsc_perf_loop 2012 0 stevel 2013 0 stevel / read the TSC and store the LSW in %ecx 2014 0 stevel rdtsc 2015 0 stevel movl %eax, %ecx 2016 0 stevel 2017 0 stevel / latch the PIT counter and status 2018 0 stevel movb $_CONST(PIT_READBACK|PIT_READBACKC0), %al 2019 0 stevel outb $PITCTL_PORT 2020 0 stevel 2021 0 stevel / remember if the icache has been warmed 2022 0 stevel setc %ah 2023 0 stevel 2024 0 stevel / read the PIT status 2025 0 stevel inb $PITCTR0_PORT 2026 0 stevel shll $8, %eax 2027 0 stevel 2028 0 stevel / read PIT count 2029 0 stevel inb $PITCTR0_PORT 2030 0 stevel shll $8, %eax 2031 0 stevel inb $PITCTR0_PORT 2032 0 stevel bswap %eax 2033 0 stevel 2034 0 stevel / check to see if the PIT count was loaded into the CE 2035 0 stevel btw $_CONST(PITSTAT_NULLCNT+8), %ax 2036 0 stevel jc freq_tsc_increase_count 2037 0 stevel 2038 0 stevel / check to see if PIT counter wrapped 2039 0 stevel btw $_CONST(PITSTAT_OUTPUT+8), %ax 2040 0 stevel jnc freq_tsc_pit_did_not_wrap 2041 0 stevel 2042 0 stevel / halve count 2043 0 stevel shrl $1, %ebx 2044 0 stevel movl %ebx, %ecx 2045 0 stevel 2046 0 stevel / the instruction cache has been warmed 2047 0 stevel stc 2048 0 stevel 2049 0 stevel jmp freq_tsc_loop 2050 0 stevel 2051 0 stevel freq_tsc_increase_count: 2052 0 stevel shll $1, %ebx 2053 0 stevel jc freq_tsc_too_fast 2054 0 stevel 2055 0 stevel movl %ebx, %ecx 2056 0 stevel 2057 0 stevel / the instruction cache has been warmed 2058 0 stevel stc 2059 0 stevel 2060 0 stevel jmp freq_tsc_loop 2061 0 stevel 2062 0 stevel freq_tsc_pit_did_not_wrap: 2063 0 stevel roll $16, %eax 2064 0 stevel 2065 0 stevel cmpw $0x2000, %ax 2066 0 stevel notw %ax 2067 0 stevel jb freq_tsc_sufficient_duration 2068 0 stevel 2069 0 stevel freq_tsc_calculate: 2070 0 stevel / in mode 0, the PIT loads the count into the CE on the first CLK pulse, 2071 0 stevel / then on the second CLK pulse the CE is decremented, therefore mode 0 2072 0 stevel / is really a (count + 1) counter, ugh 2073 0 stevel xorl %esi, %esi 2074 0 stevel movw %ax, %si 2075 0 stevel incl %esi 2076 0 stevel 2077 0 stevel movl $0xf000, %eax 2078 0 stevel mull %ebx 2079 0 stevel 2080 0 stevel / tuck away (target_pit_count * loop_count) 2081 0 stevel movl %edx, %ecx 2082 0 stevel movl %eax, %ebx 2083 0 stevel 2084 0 stevel movl %esi, %eax 2085 0 stevel movl $0xffffffff, %edx 2086 0 stevel mull %edx 2087 0 stevel 2088 0 stevel addl %esi, %eax 2089 0 stevel adcl $0, %edx 2090 0 stevel 2091 0 stevel cmpl %ecx, %edx 2092 0 stevel ja freq_tsc_div_safe 2093 0 stevel jb freq_tsc_too_fast 2094 0 stevel 2095 0 stevel cmpl %ebx, %eax 2096 0 stevel jbe freq_tsc_too_fast 2097 0 stevel 2098 0 stevel freq_tsc_div_safe: 2099 0 stevel movl %ecx, %edx 2100 0 stevel movl %ebx, %eax 2101 0 stevel 2102 0 stevel movl %esi, %ecx 2103 0 stevel divl %ecx 2104 0 stevel 2105 0 stevel movl %eax, %ecx 2106 0 stevel 2107 0 stevel / the instruction cache has been warmed 2108 0 stevel stc 2109 0 stevel 2110 0 stevel jmp freq_tsc_loop 2111 0 stevel 2112 0 stevel freq_tsc_sufficient_duration: 2113 0 stevel / test to see if the icache has been warmed 2114 0 stevel btl $16, %eax 2115 0 stevel jnc freq_tsc_calculate 2116 0 stevel 2117 0 stevel / recall mode 0 is a (count + 1) counter 2118 0 stevel andl $0xffff, %eax 2119 0 stevel incl %eax 2120 0 stevel 2121 0 stevel / save the number of PIT counts 2122 0 stevel movl 8(%ebp), %ebx 2123 0 stevel movl %eax, (%ebx) 2124 0 stevel 2125 0 stevel / calculate the number of TS's that elapsed 2126 0 stevel movl %ecx, %eax 2127 0 stevel subl %esi, %eax 2128 0 stevel sbbl %edi, %edx 2129 0 stevel 2130 0 stevel jmp freq_tsc_end 2131 0 stevel 2132 0 stevel freq_tsc_too_fast: 2133 0 stevel / return 0 as a 64 bit quantity 2134 0 stevel xorl %eax, %eax 2135 0 stevel xorl %edx, %edx 2136 0 stevel 2137 0 stevel freq_tsc_end: 2138 0 stevel popl %ebx 2139 0 stevel popl %esi 2140 0 stevel popl %edi 2141 0 stevel popl %ebp 2142 0 stevel ret 2143 0 stevel SET_SIZE(freq_tsc) 2144 0 stevel 2145 0 stevel #endif /* __i386 */ 2146 0 stevel #endif /* __lint */ 2147 0 stevel 2148 0 stevel #if !defined(__amd64) 2149 0 stevel #if defined(__lint) 2150 0 stevel 2151 0 stevel /* 2152 0 stevel * We do not have a TSC so we use a block of instructions with well known 2153 0 stevel * timings. 2154 0 stevel */ 2155 0 stevel 2156 0 stevel /*ARGSUSED*/ 2157 0 stevel uint64_t 2158 0 stevel freq_notsc(uint32_t *pit_counter) 2159 0 stevel { 2160 0 stevel return (0); 2161 0 stevel } 2162 0 stevel 2163 0 stevel #else /* __lint */ 2164 0 stevel ENTRY_NP(freq_notsc) 2165 0 stevel pushl %ebp 2166 0 stevel movl %esp, %ebp 2167 0 stevel pushl %edi 2168 0 stevel pushl %esi 2169 0 stevel pushl %ebx 2170 0 stevel 2171 0 stevel / initial count for the idivl loop 2172 0 stevel movl $0x1000, %ecx 2173 0 stevel 2174 0 stevel / load the divisor 2175 0 stevel movl $1, %ebx 2176 0 stevel 2177 0 stevel jmp freq_notsc_loop 2178 0 stevel 2179 0 stevel .align 16 2180 0 stevel freq_notsc_loop: 2181 0 stevel / set high 32 bits of dividend to zero 2182 0 stevel xorl %edx, %edx 2183 0 stevel 2184 0 stevel / save the loop count in %edi 2185 0 stevel movl %ecx, %edi 2186 0 stevel 2187 0 stevel / initialize the PIT counter and start a count down 2188 0 stevel movb $PIT_LOADMODE, %al 2189 0 stevel outb $PITCTL_PORT 2190 0 stevel movb $0xff, %al 2191 0 stevel outb $PITCTR0_PORT 2192 0 stevel outb $PITCTR0_PORT 2193 0 stevel 2194 0 stevel / set low 32 bits of dividend to zero 2195 0 stevel xorl %eax, %eax 2196 0 stevel 2197 0 stevel / It is vital that the arguments to idivl be set appropriately because on some 2198 0 stevel / cpu's this instruction takes more or less clock ticks depending on its 2199 0 stevel / arguments. 2200 0 stevel freq_notsc_perf_loop: 2201 0 stevel idivl %ebx 2202 0 stevel idivl %ebx 2203 0 stevel idivl %ebx 2204 0 stevel idivl %ebx 2205 0 stevel idivl %ebx 2206 0 stevel loop freq_notsc_perf_loop 2207 0 stevel 2208 0 stevel / latch the PIT counter and status 2209 0 stevel movb $_CONST(PIT_READBACK|PIT_READBACKC0), %al 2210 0 stevel outb $PITCTL_PORT 2211 0 stevel 2212 0 stevel / read the PIT status 2213 0 stevel inb $PITCTR0_PORT 2214 0 stevel shll $8, %eax 2215 0 stevel 2216 0 stevel / read PIT count 2217 0 stevel inb $PITCTR0_PORT 2218 0 stevel shll $8, %eax 2219 0 stevel inb $PITCTR0_PORT 2220 0 stevel bswap %eax 2221 0 stevel 2222 0 stevel / check to see if the PIT count was loaded into the CE 2223 0 stevel btw $_CONST(PITSTAT_NULLCNT+8), %ax 2224 0 stevel jc freq_notsc_increase_count 2225 0 stevel 2226 0 stevel / check to see if PIT counter wrapped 2227 0 stevel btw $_CONST(PITSTAT_OUTPUT+8), %ax 2228 0 stevel jnc freq_notsc_pit_did_not_wrap 2229 0 stevel 2230 0 stevel / halve count 2231 0 stevel shrl $1, %edi 2232 0 stevel movl %edi, %ecx 2233 0 stevel 2234 0 stevel jmp freq_notsc_loop 2235 0 stevel 2236 0 stevel freq_notsc_increase_count: 2237 0 stevel shll $1, %edi 2238 0 stevel jc freq_notsc_too_fast 2239 0 stevel 2240 0 stevel movl %edi, %ecx 2241 0 stevel 2242 0 stevel jmp freq_notsc_loop 2243 0 stevel 2244 0 stevel freq_notsc_pit_did_not_wrap: 2245 0 stevel shrl $16, %eax 2246 0 stevel 2247 0 stevel cmpw $0x2000, %ax 2248 0 stevel notw %ax 2249 0 stevel jb freq_notsc_sufficient_duration 2250 0 stevel 2251 0 stevel freq_notsc_calculate: 2252 0 stevel / in mode 0, the PIT loads the count into the CE on the first CLK pulse, 2253 0 stevel / then on the second CLK pulse the CE is decremented, therefore mode 0 2254 0 stevel / is really a (count + 1) counter, ugh 2255 0 stevel xorl %esi, %esi 2256 0 stevel movw %ax, %si 2257 0 stevel incl %esi 2258 0 stevel 2259 0 stevel movl %edi, %eax 2260 0 stevel movl $0xf000, %ecx 2261 0 stevel mull %ecx 2262 0 stevel 2263 0 stevel / tuck away (target_pit_count * loop_count) 2264 0 stevel movl %edx, %edi 2265 0 stevel movl %eax, %ecx 2266 0 stevel 2267 0 stevel movl %esi, %eax 2268 0 stevel movl $0xffffffff, %edx 2269 0 stevel mull %edx 2270 0 stevel 2271 0 stevel addl %esi, %eax 2272 0 stevel adcl $0, %edx 2273 0 stevel 2274 0 stevel cmpl %edi, %edx 2275 0 stevel ja freq_notsc_div_safe 2276 0 stevel jb freq_notsc_too_fast 2277 0 stevel 2278 0 stevel cmpl %ecx, %eax 2279 0 stevel jbe freq_notsc_too_fast 2280 0 stevel 2281 0 stevel freq_notsc_div_safe: 2282 0 stevel movl %edi, %edx 2283 0 stevel movl %ecx, %eax 2284 0 stevel 2285 0 stevel movl %esi, %ecx 2286 0 stevel divl %ecx 2287 0 stevel 2288 0 stevel movl %eax, %ecx 2289 0 stevel 2290 0 stevel jmp freq_notsc_loop 2291 0 stevel 2292 0 stevel freq_notsc_sufficient_duration: 2293 0 stevel / recall mode 0 is a (count + 1) counter 2294 0 stevel incl %eax 2295 0 stevel 2296 0 stevel / save the number of PIT counts 2297 0 stevel movl 8(%ebp), %ebx 2298 0 stevel movl %eax, (%ebx) 2299 0 stevel 2300 0 stevel / calculate the number of cpu clock ticks that elapsed 2301 0 stevel cmpl $X86_VENDOR_Cyrix, x86_vendor 2302 0 stevel jz freq_notsc_notcyrix 2303 0 stevel 2304 0 stevel / freq_notsc_perf_loop takes 86 clock cycles on Cyrix 6x86 cores 2305 0 stevel movl $86, %eax 2306 0 stevel jmp freq_notsc_calculate_tsc 2307 0 stevel 2308 0 stevel freq_notsc_notcyrix: 2309 0 stevel / freq_notsc_perf_loop takes 237 clock cycles on Intel Pentiums 2310 0 stevel movl $237, %eax 2311 0 stevel 2312 0 stevel freq_notsc_calculate_tsc: 2313 0 stevel mull %edi 2314 0 stevel 2315 0 stevel jmp freq_notsc_end 2316 0 stevel 2317 0 stevel freq_notsc_too_fast: 2318 0 stevel / return 0 as a 64 bit quantity 2319 0 stevel xorl %eax, %eax 2320 0 stevel xorl %edx, %edx 2321 0 stevel 2322 0 stevel freq_notsc_end: 2323 0 stevel popl %ebx 2324 0 stevel popl %esi 2325 0 stevel popl %edi 2326 0 stevel popl %ebp 2327 0 stevel 2328 0 stevel ret 2329 0 stevel SET_SIZE(freq_notsc) 2330 0 stevel 2331 0 stevel #endif /* __lint */ 2332 0 stevel #endif /* !__amd64 */ 2333 0 stevel 2334 0 stevel #if !defined(__lint) 2335 0 stevel .data 2336 0 stevel #if !defined(__amd64) 2337 0 stevel .align 4 2338 0 stevel cpu_vendor: 2339 0 stevel .long 0, 0, 0 /* Vendor ID string returned */ 2340 0 stevel 2341 0 stevel .globl CyrixInstead 2342 0 stevel 2343 0 stevel .globl x86_feature 2344 0 stevel .globl x86_type 2345 0 stevel .globl x86_vendor 2346 0 stevel #endif 2347 0 stevel 2348 0 stevel #endif /* __lint */ 2349