#include <pexpert/pexpert.h>
#include <arm/cpuid.h>
#include <arm/cpuid_internal.h>
#include <vm/vm_page.h>
#include "proc_reg.h"
#include <libkern/section_keywords.h>
typedef struct {
uint32_t
Ctype1:3,
Ctype2:3,
Ctype3:3,
Ctypes:15,
LoC:3,
LoU:3,
RAZ:2;
} arm_cache_clidr_t;
typedef union {
arm_cache_clidr_t bits;
uint32_t value;
} arm_cache_clidr_info_t;
typedef struct {
uint32_t
LineSize:3,
Assoc:10,
NumSets:15,
c_type:4;
} arm_cache_ccsidr_t;
typedef union {
arm_cache_ccsidr_t bits;
uint32_t value;
} arm_cache_ccsidr_info_t;
static SECURITY_READ_ONLY_LATE(arm_cpu_info_t) cpuid_cpu_info;
static SECURITY_READ_ONLY_LATE(cache_info_t) cpuid_cache_info;
__private_extern__
void
do_cpuid(void)
{
cpuid_cpu_info.value = machine_read_midr();
#if (__ARM_ARCH__ == 8)
cpuid_cpu_info.arm_info.arm_arch = CPU_ARCH_ARMv8;
#elif (__ARM_ARCH__ == 7)
#ifdef __ARM_SUB_ARCH__
cpuid_cpu_info.arm_info.arm_arch = __ARM_SUB_ARCH__;
#else
cpuid_cpu_info.arm_info.arm_arch = CPU_ARCH_ARMv7;
#endif
#else
if (cpuid_cpu_info.arm_info.arm_arch == CPU_ARCH_EXTENDED) {
arm_isa_feat1_reg isa = machine_read_isa_feat1();
if (isa.field.sign_zero_ext_support == 0x2) {
cpuid_cpu_info.arm_info.arm_arch = CPU_ARCH_ARMv6;
}
}
#endif
}
arm_cpu_info_t *
cpuid_info(void)
{
return &cpuid_cpu_info;
}
int
cpuid_get_cpufamily(void)
{
int cpufamily = 0;
switch (cpuid_info()->arm_info.arm_implementor) {
case CPU_VID_ARM:
switch (cpuid_info()->arm_info.arm_part) {
case CPU_PART_CORTEXA9:
cpufamily = CPUFAMILY_ARM_14;
break;
case CPU_PART_CORTEXA8:
cpufamily = CPUFAMILY_ARM_13;
break;
case CPU_PART_CORTEXA7:
cpufamily = CPUFAMILY_ARM_15;
break;
case CPU_PART_1136JFS:
case CPU_PART_1176JZFS:
cpufamily = CPUFAMILY_ARM_11;
break;
case CPU_PART_926EJS:
case CPU_PART_920T:
cpufamily = CPUFAMILY_ARM_9;
break;
default:
cpufamily = CPUFAMILY_UNKNOWN;
break;
}
break;
case CPU_VID_INTEL:
cpufamily = CPUFAMILY_ARM_XSCALE;
break;
case CPU_VID_APPLE:
switch (cpuid_info()->arm_info.arm_part) {
case CPU_PART_SWIFT:
cpufamily = CPUFAMILY_ARM_SWIFT;
break;
case CPU_PART_CYCLONE:
cpufamily = CPUFAMILY_ARM_CYCLONE;
break;
case CPU_PART_TYPHOON:
case CPU_PART_TYPHOON_CAPRI:
cpufamily = CPUFAMILY_ARM_TYPHOON;
break;
case CPU_PART_TWISTER:
case CPU_PART_TWISTER_ELBA_MALTA:
cpufamily = CPUFAMILY_ARM_TWISTER;
break;
case CPU_PART_HURRICANE:
case CPU_PART_HURRICANE_MYST:
cpufamily = CPUFAMILY_ARM_HURRICANE;
break;
default:
cpufamily = CPUFAMILY_UNKNOWN;
break;
}
break;
default:
cpufamily = CPUFAMILY_UNKNOWN;
break;
}
return cpufamily;
}
void
do_debugid(void)
{
machine_do_debugid();
}
arm_debug_info_t *
arm_debug_info(void)
{
return machine_arm_debug_info();
}
void
do_mvfpid(void)
{
return machine_do_mvfpid();
}
arm_mvfp_info_t
*arm_mvfp_info(void)
{
return machine_arm_mvfp_info();
}
void
do_cacheid(void)
{
arm_cache_clidr_info_t arm_cache_clidr_info;
arm_cache_ccsidr_info_t arm_cache_ccsidr_info;
arm_cache_clidr_info.value = machine_read_clidr();
machine_write_csselr(CSSELR_L1, CSSELR_DATA_UNIFIED);
arm_cache_ccsidr_info.value = machine_read_ccsidr();
cpuid_cache_info.c_unified = (arm_cache_clidr_info.bits.Ctype1 == 0x4) ? 1 : 0;
switch (arm_cache_ccsidr_info.bits.c_type) {
case 0x1:
cpuid_cache_info.c_type = CACHE_WRITE_ALLOCATION;
break;
case 0x2:
cpuid_cache_info.c_type = CACHE_READ_ALLOCATION;
break;
case 0x4:
cpuid_cache_info.c_type = CACHE_WRITE_BACK;
break;
case 0x8:
cpuid_cache_info.c_type = CACHE_WRITE_THROUGH;
break;
default:
cpuid_cache_info.c_type = CACHE_UNKNOWN;
}
cpuid_cache_info.c_linesz = 4 * (1<<(arm_cache_ccsidr_info.bits.LineSize + 2));
cpuid_cache_info.c_assoc = (arm_cache_ccsidr_info.bits.Assoc + 1);
cpuid_cache_info.c_isize = (arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info.c_linesz * cpuid_cache_info.c_assoc;
cpuid_cache_info.c_dsize = (arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info.c_linesz * cpuid_cache_info.c_assoc;
if ((arm_cache_clidr_info.bits.Ctype3 == 0x4) ||
(arm_cache_clidr_info.bits.Ctype2 == 0x4) || (arm_cache_clidr_info.bits.Ctype2 == 0x2)) {
if (arm_cache_clidr_info.bits.Ctype3 == 0x4) {
machine_write_csselr(CSSELR_L3, CSSELR_DATA_UNIFIED);
} else {
machine_write_csselr(CSSELR_L2, CSSELR_DATA_UNIFIED);
}
arm_cache_ccsidr_info.value = machine_read_ccsidr();
cpuid_cache_info.c_linesz = 4 * (1<<(arm_cache_ccsidr_info.bits.LineSize + 2));
cpuid_cache_info.c_assoc = (arm_cache_ccsidr_info.bits.Assoc + 1);
cpuid_cache_info.c_l2size = (arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info.c_linesz * cpuid_cache_info.c_assoc;
cpuid_cache_info.c_inner_cache_size = cpuid_cache_info.c_dsize;
cpuid_cache_info.c_bulksize_op = cpuid_cache_info.c_l2size;
vm_cache_geometry_colors = ((arm_cache_ccsidr_info.bits.NumSets + 1) * cpuid_cache_info.c_linesz) / PAGE_SIZE;
kprintf(" vm_cache_geometry_colors: %d\n", vm_cache_geometry_colors);
} else {
cpuid_cache_info.c_l2size = 0;
cpuid_cache_info.c_inner_cache_size = cpuid_cache_info.c_dsize;
cpuid_cache_info.c_bulksize_op = cpuid_cache_info.c_dsize;
}
kprintf("%s() - %u bytes %s cache (I:%u D:%u (%s)), %u-way assoc, %u bytes/line\n",
__FUNCTION__,
cpuid_cache_info.c_dsize + cpuid_cache_info.c_isize,
((cpuid_cache_info.c_type == CACHE_WRITE_BACK) ? "WB" :
(cpuid_cache_info.c_type == CACHE_WRITE_THROUGH ? "WT" : "Unknown")),
cpuid_cache_info.c_isize,
cpuid_cache_info.c_dsize,
(cpuid_cache_info.c_unified) ? "unified" : "separate",
cpuid_cache_info.c_assoc,
cpuid_cache_info.c_linesz);
}
cache_info_t *
cache_info(void)
{
return &cpuid_cache_info;
}