1*cc401b37SPatrick Mooney/* 2*cc401b37SPatrick Mooney * This file and its contents are supplied under the terms of the 3*cc401b37SPatrick Mooney * Common Development and Distribution License ("CDDL"), version 1.0. 4*cc401b37SPatrick Mooney * You may only use this file in accordance with the terms of version 5*cc401b37SPatrick Mooney * 1.0 of the CDDL. 6*cc401b37SPatrick Mooney * 7*cc401b37SPatrick Mooney * A full copy of the text of the CDDL should have accompanied this 8*cc401b37SPatrick Mooney * source. A copy of the CDDL is also available via the Internet at 9*cc401b37SPatrick Mooney * http://www.illumos.org/license/CDDL. 10*cc401b37SPatrick Mooney */ 11*cc401b37SPatrick Mooney 12*cc401b37SPatrick Mooney/* 13*cc401b37SPatrick Mooney * Copyright 2016 Joyent, Inc. 14*cc401b37SPatrick Mooney */ 15*cc401b37SPatrick Mooney 16*cc401b37SPatrick Mooney#include <sys/asm_linkage.h> 17*cc401b37SPatrick Mooney#include <sys/segments.h> 18*cc401b37SPatrick Mooney#include <sys/time_impl.h> 19*cc401b37SPatrick Mooney#include <sys/tsc.h> 20*cc401b37SPatrick Mooney#include <cp_offsets.h> 21*cc401b37SPatrick Mooney 22*cc401b37SPatrick Mooney#define GETCPU_GDT_OFFSET SEL_GDT(GDT_CPUID, SEL_UPL) 23*cc401b37SPatrick Mooney 24*cc401b37SPatrick Mooney .file "cp_subr.s" 25*cc401b37SPatrick Mooney 26*cc401b37SPatrick Mooney/* 27*cc401b37SPatrick Mooney * hrtime_t 28*cc401b37SPatrick Mooney * __cp_tsc_read(uint_t cp_tsc_type) 29*cc401b37SPatrick Mooney * 30*cc401b37SPatrick Mooney * Stack usage: 0x18 bytes 31*cc401b37SPatrick Mooney */ 32*cc401b37SPatrick Mooney ENTRY_NP(__cp_tsc_read) 33*cc401b37SPatrick Mooney pushl %ebp 34*cc401b37SPatrick Mooney movl %esp, %ebp 35*cc401b37SPatrick Mooney pushl %edi 36*cc401b37SPatrick Mooney pushl %esi 37*cc401b37SPatrick Mooney subl $0x4, %esp 38*cc401b37SPatrick Mooney 39*cc401b37SPatrick Mooney movl 0x8(%ebp), %edi 40*cc401b37SPatrick Mooney movl CP_TSC_TYPE(%edi), %eax 41*cc401b37SPatrick Mooney movl CP_TSC_NCPU(%edi), %esi 42*cc401b37SPatrick Mooney cmpl $TSC_TSCP, %eax 43*cc401b37SPatrick Mooney jne 3f 44*cc401b37SPatrick Mooney rdtscp 45*cc401b37SPatrick Mooney cmpl $0, %esi 46*cc401b37SPatrick Mooney jne 2f 47*cc401b37SPatrick Mooney1: 48*cc401b37SPatrick Mooney addl $0x4, %esp 49*cc401b37SPatrick Mooney popl %esi 50*cc401b37SPatrick Mooney popl %edi 51*cc401b37SPatrick Mooney leave 52*cc401b37SPatrick Mooney ret 53*cc401b37SPatrick Mooney2: 54*cc401b37SPatrick Mooney /* 55*cc401b37SPatrick Mooney * When cp_tsc_ncpu is non-zero, it indicates the length of the 56*cc401b37SPatrick Mooney * cp_tsc_sync_tick_delta array, which contains per-CPU offsets for the 57*cc401b37SPatrick Mooney * TSC. The CPU ID furnished by the IA32_TSC_AUX register via rdtscp 58*cc401b37SPatrick Mooney * is used to look up an offset value in that array and apply it to the 59*cc401b37SPatrick Mooney * TSC reading. 60*cc401b37SPatrick Mooney */ 61*cc401b37SPatrick Mooney leal CP_TSC_SYNC_TICK_DELTA(%edi), %esi 62*cc401b37SPatrick Mooney leal (%esi, %ecx, 8), %ecx 63*cc401b37SPatrick Mooney addl (%ecx), %eax 64*cc401b37SPatrick Mooney adcl 0x4(%ecx), %edx 65*cc401b37SPatrick Mooney jmp 1b 66*cc401b37SPatrick Mooney 67*cc401b37SPatrick Mooney3: 68*cc401b37SPatrick Mooney cmpl $0, %esi 69*cc401b37SPatrick Mooney je 4f 70*cc401b37SPatrick Mooney mov $GETCPU_GDT_OFFSET, %eax 71*cc401b37SPatrick Mooney lsl %ax, %eax 72*cc401b37SPatrick Mooney movl %eax, (%esp) 73*cc401b37SPatrick Mooney movl CP_TSC_TYPE(%edi), %eax 74*cc401b37SPatrick Mooney 75*cc401b37SPatrick Mooney4: 76*cc401b37SPatrick Mooney cmpl $TSC_RDTSC_MFENCE, %eax 77*cc401b37SPatrick Mooney jne 5f 78*cc401b37SPatrick Mooney mfence 79*cc401b37SPatrick Mooney rdtsc 80*cc401b37SPatrick Mooney jmp 8f 81*cc401b37SPatrick Mooney 82*cc401b37SPatrick Mooney5: 83*cc401b37SPatrick Mooney cmpl $TSC_RDTSC_LFENCE, %eax 84*cc401b37SPatrick Mooney jne 6f 85*cc401b37SPatrick Mooney lfence 86*cc401b37SPatrick Mooney rdtsc 87*cc401b37SPatrick Mooney jmp 8f 88*cc401b37SPatrick Mooney 89*cc401b37SPatrick Mooney6: 90*cc401b37SPatrick Mooney cmpl $TSC_RDTSC_CPUID, %eax 91*cc401b37SPatrick Mooney jne 7f 92*cc401b37SPatrick Mooney pushl %ebx 93*cc401b37SPatrick Mooney xorl %eax, %eax 94*cc401b37SPatrick Mooney cpuid 95*cc401b37SPatrick Mooney rdtsc 96*cc401b37SPatrick Mooney popl %ebx 97*cc401b37SPatrick Mooney jmp 8f 98*cc401b37SPatrick Mooney 99*cc401b37SPatrick Mooney7: 100*cc401b37SPatrick Mooney /* 101*cc401b37SPatrick Mooney * Other protections should have prevented this function from being 102*cc401b37SPatrick Mooney * called in the first place. The only sane action is to abort. 103*cc401b37SPatrick Mooney * The easiest means in this context is via SIGILL. 104*cc401b37SPatrick Mooney */ 105*cc401b37SPatrick Mooney ud2a 106*cc401b37SPatrick Mooney 107*cc401b37SPatrick Mooney8: 108*cc401b37SPatrick Mooney 109*cc401b37SPatrick Mooney cmpl $0, %esi 110*cc401b37SPatrick Mooney je 1b 111*cc401b37SPatrick Mooney /* 112*cc401b37SPatrick Mooney * With a TSC reading in-hand, confirm that the thread has not migrated 113*cc401b37SPatrick Mooney * since the cpu_id was first checked. 114*cc401b37SPatrick Mooney */ 115*cc401b37SPatrick Mooney movl $GETCPU_GDT_OFFSET, %ecx 116*cc401b37SPatrick Mooney lsl %cx, %ecx 117*cc401b37SPatrick Mooney movl (%esp), %esi 118*cc401b37SPatrick Mooney cmpl %ecx, %esi 119*cc401b37SPatrick Mooney je 9f 120*cc401b37SPatrick Mooney /* 121*cc401b37SPatrick Mooney * There was a CPU migration, perform another reading. 122*cc401b37SPatrick Mooney */ 123*cc401b37SPatrick Mooney movl %eax, (%esp) 124*cc401b37SPatrick Mooney movl CP_TSC_NCPU(%edi), %esi 125*cc401b37SPatrick Mooney movl CP_TSC_TYPE(%edi), %eax 126*cc401b37SPatrick Mooney jmp 4b 127*cc401b37SPatrick Mooney 128*cc401b37SPatrick Mooney9: 129*cc401b37SPatrick Mooney /* Grab the per-cpu offset and add it to the TSC result */ 130*cc401b37SPatrick Mooney leal CP_TSC_SYNC_TICK_DELTA(%edi), %esi 131*cc401b37SPatrick Mooney leal (%esi, %ecx, 8), %ecx 132*cc401b37SPatrick Mooney addl (%ecx), %eax 133*cc401b37SPatrick Mooney adcl 0x4(%ecx), %edx 134*cc401b37SPatrick Mooney jmp 1b 135*cc401b37SPatrick Mooney SET_SIZE(__cp_tsc_read) 136*cc401b37SPatrick Mooney 137*cc401b37SPatrick Mooney/* 138*cc401b37SPatrick Mooney * uint_t 139*cc401b37SPatrick Mooney * __cp_getcpu(uint_t cp_tsc_type) 140*cc401b37SPatrick Mooney */ 141*cc401b37SPatrick Mooney ENTRY_NP(__cp_getcpu) 142*cc401b37SPatrick Mooney /* 143*cc401b37SPatrick Mooney * If RDTSCP is available, it is a quick way to grab the cpu_id which 144*cc401b37SPatrick Mooney * is stored in the TSC_AUX MSR by the kernel. 145*cc401b37SPatrick Mooney */ 146*cc401b37SPatrick Mooney movl 4(%esp), %eax 147*cc401b37SPatrick Mooney movl CP_TSC_TYPE(%eax), %eax 148*cc401b37SPatrick Mooney cmpl $TSC_TSCP, %eax 149*cc401b37SPatrick Mooney jne 1f 150*cc401b37SPatrick Mooney rdtscp 151*cc401b37SPatrick Mooney movl %ecx, %eax 152*cc401b37SPatrick Mooney ret 153*cc401b37SPatrick Mooney1: 154*cc401b37SPatrick Mooney mov $GETCPU_GDT_OFFSET, %eax 155*cc401b37SPatrick Mooney lsl %ax, %eax 156*cc401b37SPatrick Mooney ret 157*cc401b37SPatrick Mooney SET_SIZE(__cp_getcpu) 158