#include "tests.h"
#include <unistd.h>
#include <stdint.h>
#include <err.h>
#include <sys/param.h>
#include <System/machine/cpu_capabilities.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <mach/bootstrap.h>
#ifdef _COMM_PAGE_ACTIVE_CPUS
int active_cpu_test(void);
#endif
int get_sys_uint64(const char *sel, uint64_t *val);
int get_sys_int32(const char *sel, int32_t *val);
#define getcommptr(var, commpageaddr) do { \
var = (typeof(var))(uintptr_t)(commpageaddr); \
} while(0)
int commpage_data_tests( void * the_argp )
{
int ret;
uint64_t sys_u64;
int32_t sys_i32;
volatile uint64_t *comm_u64;
volatile uint32_t *comm_u32;
volatile uint16_t *comm_u16;
volatile uint8_t *comm_u8;
getcommptr(comm_u32, _COMM_PAGE_CPU_CAPABILITIES);
ret = get_sys_int32("hw.ncpu", &sys_i32);
if (ret) goto fail;
if (sys_i32 != ((*comm_u32 & kNumCPUs) >> kNumCPUsShift)) {
warnx("kNumCPUs does not match hw.ncpu");
ret = -1;
goto fail;
}
getcommptr(comm_u8, _COMM_PAGE_NCPUS);
if (sys_i32 != (*comm_u8)) {
warnx("_COMM_PAGE_NCPUS does not match hw.ncpu");
ret = -1;
goto fail;
}
ret = get_sys_int32("hw.logicalcpu", &sys_i32);
if (ret) goto fail;
if (sys_i32 != ((*comm_u32 & kNumCPUs) >> kNumCPUsShift)) {
warnx("kNumCPUs does not match hw.logicalcpu");
ret = -1;
goto fail;
}
#if defined(__i386__) || defined(__x86_64__)
ret = get_sys_int32("hw.optional.mmx", &sys_i32);
if (ret) goto fail;
if (!(sys_i32) ^ !(*comm_u32 & kHasMMX)) {
warnx("kHasMMX does not match hw.optional.mmx");
ret = -1;
goto fail;
}
ret = get_sys_int32("hw.optional.sse", &sys_i32);
if (ret) goto fail;
if (!(sys_i32) ^ !(*comm_u32 & kHasSSE)) {
warnx("kHasSSE does not match hw.optional.sse");
ret = -1;
goto fail;
}
ret = get_sys_int32("hw.optional.sse2", &sys_i32);
if (ret) goto fail;
if (!(sys_i32) ^ !(*comm_u32 & kHasSSE2)) {
warnx("kHasSSE2 does not match hw.optional.sse2");
ret = -1;
goto fail;
}
ret = get_sys_int32("hw.optional.sse3", &sys_i32);
if (ret) goto fail;
if (!(sys_i32) ^ !(*comm_u32 & kHasSSE3)) {
warnx("kHasSSE3 does not match hw.optional.sse3");
ret = -1;
goto fail;
}
ret = get_sys_int32("hw.optional.supplementalsse3", &sys_i32);
if (ret) goto fail;
if (!(sys_i32) ^ !(*comm_u32 & kHasSupplementalSSE3)) {
warnx("kHasSupplementalSSE3 does not match hw.optional.supplementalsse3");
ret = -1;
goto fail;
}
ret = get_sys_int32("hw.optional.sse4_1", &sys_i32);
if (ret) goto fail;
if (!(sys_i32) ^ !(*comm_u32 & kHasSSE4_1)) {
warnx("kHasSSE4_1 does not match hw.optional.sse4_1");
ret = -1;
goto fail;
}
ret = get_sys_int32("hw.optional.sse4_2", &sys_i32);
if (ret) goto fail;
if (!(sys_i32) ^ !(*comm_u32 & kHasSSE4_2)) {
warnx("kHasSSE4_2 does not match hw.optional.sse4_2");
ret = -1;
goto fail;
}
ret = get_sys_int32("hw.optional.aes", &sys_i32);
if (ret) goto fail;
if (!(sys_i32) ^ !(*comm_u32 & kHasAES)) {
warnx("kHasAES does not match hw.optional.aes");
ret = -1;
goto fail;
}
ret = get_sys_int32("hw.optional.x86_64", &sys_i32);
if (ret) goto fail;
if (!(sys_i32) ^ !(*comm_u32 & k64Bit)) {
warnx("k64Bit does not match hw.optional.x86_64");
ret = -1;
goto fail;
}
#endif
#ifdef _COMM_PAGE_SCHED_GEN
uint32_t preempt_count1, preempt_count2;
uint64_t count;
ret = get_sys_uint64("hw.cpufrequency_max", &sys_u64);
if (ret) goto fail;
getcommptr(comm_u32, _COMM_PAGE_SCHED_GEN);
preempt_count1 = *comm_u32;
for(count = MAX(10000000ULL, sys_u64/64); count > 0; count--) {
asm volatile("");
}
preempt_count2 = *comm_u32;
if (preempt_count1 >= preempt_count2) {
warnx("_COMM_PAGE_SCHED_GEN not incrementing (%u => %u)",
preempt_count1, preempt_count2);
ret = -1;
goto fail;
}
#endif
#ifdef _COMM_PAGE_ACTIVE_CPUS
ret = get_sys_int32("hw.activecpu", &sys_i32);
if (ret) goto fail;
getcommptr(comm_u8, _COMM_PAGE_ACTIVE_CPUS);
if (sys_i32 != (*comm_u8)) {
warnx("_COMM_PAGE_ACTIVE_CPUS does not match hw.activecpu");
ret = -1;
goto fail;
}
ret = active_cpu_test();
if (ret) goto fail;
#endif
#ifdef _COMM_PAGE_PHYSICAL_CPUS
ret = get_sys_int32("hw.physicalcpu_max", &sys_i32);
if (ret) goto fail;
getcommptr(comm_u8, _COMM_PAGE_PHYSICAL_CPUS);
if (sys_i32 != (*comm_u8)) {
warnx("_COMM_PAGE_PHYSICAL_CPUS does not match hw.physicalcpu_max");
ret = -1;
goto fail;
}
#endif
#ifdef _COMM_PAGE_LOGICAL_CPUS
ret = get_sys_int32("hw.logicalcpu_max", &sys_i32);
if (ret) goto fail;
getcommptr(comm_u8, _COMM_PAGE_LOGICAL_CPUS);
if (sys_i32 != (*comm_u8)) {
warnx("_COMM_PAGE_LOGICAL_CPUS does not match hw.logicalcpu_max");
ret = -1;
goto fail;
}
#endif
#if 0
#ifdef _COMM_PAGE_MEMORY_SIZE
ret = get_sys_uint64("hw.memsize", &sys_u64);
if (ret) goto fail;
getcommptr(comm_u64, _COMM_PAGE_MEMORY_SIZE);
if (sys_u64 != (*comm_u64)) {
warnx("_COMM_PAGE_MEMORY_SIZE does not match hw.memsize");
ret = -1;
goto fail;
}
#endif
#endif
ret = 0;
fail:
return ret;
}
int get_sys_uint64(const char *sel, uint64_t *val)
{
size_t size = sizeof(*val);
int ret;
ret = sysctlbyname(sel, val, &size, NULL, 0);
if (ret == -1) {
warn("sysctlbyname(%s)", sel);
return ret;
}
return 0;
}
int get_sys_int32(const char *sel, int32_t *val)
{
size_t size = sizeof(*val);
int ret;
ret = sysctlbyname(sel, val, &size, NULL, 0);
if (ret == -1) {
warn("sysctlbyname(%s)", sel);
return ret;
}
return 0;
}
#ifdef _COMM_PAGE_ACTIVE_CPUS
int active_cpu_test(void)
{
volatile uint8_t *activeaddr;
uint8_t original_activecpu;
boolean_t test_failed = FALSE;
kern_return_t ret;
processor_t *processor_list;
host_name_port_t host;
struct processor_basic_info processor_basic_info;
int cpu_count;
int data_count;
int i;
getcommptr(activeaddr, _COMM_PAGE_ACTIVE_CPUS);
original_activecpu = *activeaddr;
host = mach_host_self();
ret = host_processors(host,
(processor_array_t *) &processor_list, &cpu_count);
if (ret != KERN_SUCCESS) {
mach_error("host_processors()", ret);
return ret;
}
for (i = 1; i < cpu_count; i++) {
data_count = PROCESSOR_BASIC_INFO_COUNT;
ret = processor_info(processor_list[i], PROCESSOR_BASIC_INFO,
&host,
(processor_info_t) &processor_basic_info,
&data_count);
if (ret != KERN_SUCCESS) {
if (ret == MACH_SEND_INVALID_DEST) {
continue;
}
mach_error("processor_info", ret);
return ret;
}
if (processor_basic_info.running) {
ret = processor_exit(processor_list[i]);
if (ret != KERN_SUCCESS) {
mach_error("processor_exit()", ret);
return ret;
}
sleep(1);
if (*activeaddr != (original_activecpu - 1)) {
test_failed = TRUE;
}
ret = processor_start(processor_list[i]);
if (ret != KERN_SUCCESS) {
mach_error("processor_exit()", ret);
return ret;
}
sleep(1);
break;
}
}
if (test_failed) {
warnx("_COMM_PAGE_ACTIVE_CPUS not updated after disabling a CPU");
return -1;
}
if (*activeaddr != original_activecpu) {
warnx("_COMM_PAGE_ACTIVE_CPUS not restored to original value");
return -1;
}
return 0;
}
#endif