blob: 512e55b078a23d1b5ce1b00cb4bba374e79f1edf [file]
/* **********************************************************
* Copyright (c) 2013-2014 Google, Inc. All rights reserved.
* Copyright (c) 2000-2008 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* Copyright (c) 2003-2007 Determina Corp. */
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
/* Copyright (c) 2000-2001 Hewlett-Packard Company */
/*
* proc_shared.c - processor-specific shared routines
*/
#include "../globals.h"
#include "proc.h"
#include "instr.h" /* for dr_insert_{save,restore}_fpstate */
#include "instrument.h" /* for dr_insert_{save,restore}_fpstate */
#include "instr_create.h" /* for dr_insert_{save,restore}_fpstate */
#ifdef DEBUG
/* case 10450: give messages to clients */
/* we can't undef ASSERT b/c of DYNAMO_OPTION */
# undef ASSERT_TRUNCATE
# undef ASSERT_BITFIELD_TRUNCATE
# undef ASSERT_NOT_REACHED
# define ASSERT_TRUNCATE DO_NOT_USE_ASSERT_USE_CLIENT_ASSERT_INSTEAD
# define ASSERT_BITFIELD_TRUNCATE DO_NOT_USE_ASSERT_USE_CLIENT_ASSERT_INSTEAD
# define ASSERT_NOT_REACHED DO_NOT_USE_ASSERT_USE_CLIENT_ASSERT_INSTEAD
#endif
/* cache_line_size is exported for efficient access.
* FIXME: In case the processor doesn't support the
* cpuid instruction, use a default value of 32.
* (see case 463 for discussion)
*/
size_t cache_line_size = 32;
static ptr_uint_t mask; /* bits that should be 0 to be cache-line-aligned */
cpu_info_t cpu_info = { VENDOR_UNKNOWN, 0, 0, 0, 0,
CACHE_SIZE_UNKNOWN,
CACHE_SIZE_UNKNOWN,
CACHE_SIZE_UNKNOWN,
{0, 0, 0, 0},
{0x6e6b6e75, 0x006e776f} };
void
set_cache_size(uint val, uint *dst)
{
CLIENT_ASSERT(dst != NULL, "invalid internal param");
switch (val) {
case 8: *dst = CACHE_SIZE_8_KB; break;
case 16: *dst = CACHE_SIZE_16_KB; break;
case 32: *dst = CACHE_SIZE_32_KB; break;
case 64: *dst = CACHE_SIZE_64_KB; break;
case 128: *dst = CACHE_SIZE_128_KB; break;
case 256: *dst = CACHE_SIZE_256_KB; break;
case 512: *dst = CACHE_SIZE_512_KB; break;
case 1024: *dst = CACHE_SIZE_1_MB; break;
case 2048: *dst = CACHE_SIZE_2_MB; break;
default: SYSLOG_INTERNAL_ERROR("Unknown processor cache size"); break;
}
}
void
proc_init(void)
{
LOG(GLOBAL, LOG_TOP, 1, "Running on a %d CPU machine\n", get_num_processors());
proc_init_arch();
CLIENT_ASSERT(cache_line_size > 0, "invalid cache line size");
mask = (cache_line_size - 1);
LOG(GLOBAL, LOG_TOP, 1, "Cache line size is %d bytes\n", cache_line_size);
LOG(GLOBAL, LOG_TOP, 1, "L1 icache=%s, L1 dcache=%s, L2 cache=%s\n",
proc_get_cache_size_str(proc_get_L1_icache_size()),
proc_get_cache_size_str(proc_get_L1_dcache_size()),
proc_get_cache_size_str(proc_get_L2_cache_size()));
LOG(GLOBAL, LOG_TOP, 1, "Processor brand string = %s\n",
cpu_info.brand_string);
LOG(GLOBAL, LOG_TOP, 1, "Type=0x%x, Family=0x%x, Model=0x%x, Stepping=0x%x\n",
cpu_info.type, cpu_info.family,
cpu_info.model, cpu_info.stepping);
}
uint
proc_get_vendor(void)
{
return cpu_info.vendor;
}
DR_API
int
proc_set_vendor(uint new_vendor)
{
if (new_vendor == VENDOR_INTEL ||
new_vendor == VENDOR_AMD ||
new_vendor == VENDOR_ARM) {
uint old_vendor = cpu_info.vendor;
SELF_UNPROTECT_DATASEC(DATASEC_RARELY_PROT);
cpu_info.vendor = new_vendor;
SELF_PROTECT_DATASEC(DATASEC_RARELY_PROT);
return old_vendor;
} else {
CLIENT_ASSERT(false, "invalid vendor");
return -1;
}
}
uint
proc_get_family(void)
{
return cpu_info.family;
}
uint proc_get_type(void)
{
return cpu_info.type;
}
/* FIXME: Add MODEL_ constants to proc.h?? */
uint proc_get_model(void)
{
return cpu_info.model;
}
uint proc_get_stepping(void)
{
return cpu_info.stepping;
}
features_t *
proc_get_all_feature_bits(void)
{
return &cpu_info.features;
}
char *
proc_get_brand_string(void)
{
return (char *)cpu_info.brand_string;
}
cache_size_t
proc_get_L1_icache_size(void)
{
return cpu_info.L1_icache_size;
}
cache_size_t
proc_get_L1_dcache_size(void)
{
return cpu_info.L1_dcache_size;
}
cache_size_t
proc_get_L2_cache_size(void)
{
return cpu_info.L2_cache_size;
}
const char *
proc_get_cache_size_str(cache_size_t size)
{
static const char *strings[] = {
"8 KB",
"16 KB",
"32 KB",
"64 KB",
"128 KB",
"256 KB",
"512 KB",
"1 MB",
"2 MB",
"unknown"
};
CLIENT_ASSERT(size <= CACHE_SIZE_UNKNOWN, "proc_get_cache_size_str: invalid size");
return strings[size];
}
size_t
proc_get_cache_line_size(void)
{
return cache_line_size;
}
/* check to see if addr is cache aligned */
bool
proc_is_cache_aligned(void *addr)
{
return (((ptr_uint_t)addr & mask) == 0x0);
}
/* Given an address or number of bytes sz, return a number >= sz that is divisible
by the cache line size. */
ptr_uint_t
proc_bump_to_end_of_cache_line(ptr_uint_t sz)
{
if ((sz & mask) == 0x0)
return sz; /* sz already a multiple of the line size */
return ((sz + cache_line_size) & ~mask);
}
/* yes same result as PAGE_START...FIXME: get rid of one of them? */
void *
proc_get_containing_page(void *addr)
{
return (void *) (((ptr_uint_t)addr) & ~(PAGE_SIZE-1));
}