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