int main(int argc, char *argv[]) { NaClCPUFeaturesX86 fv; NaClCPUData cpu_data; int feature_id; NaClCPUDataGet(&cpu_data); NaClGetCurrentCPUFeatures(&fv); if (NaClArchSupported(&fv)) { printf("This is a native client %d-bit %s compatible computer\n", NACL_TARGET_SUBARCH, GetCPUIDString(&cpu_data)); } else { if (!fv.arch_features.f_cpuid_supported) { printf("Computer doesn't support CPUID\n"); } if (!fv.arch_features.f_cpu_supported) { printf("Computer id %s is not supported\n", GetCPUIDString(&cpu_data)); } } printf("This processor has:\n"); for (feature_id = 0; feature_id < NaClCPUFeature_Max; ++feature_id) { if (NaClGetCPUFeature(&fv, feature_id)) printf(" %s\n", NaClGetCPUFeatureName(feature_id)); } return 0; }
/* It returns 0 if the current instruction is implemented, and 1 if not. */ static int ValidateSFenceClFlush(const NCDecoderInst *dinst) { NCValidatorState* vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate); uint8_t mrm = NCInstBytesByteInline(&dinst->inst_bytes, 2); if (modrm_modInline(mrm) == 3) { /* this is an sfence */ if (NaClGetCPUFeature(&vstate->cpufeatures, NaClCPUFeature_FXSR)) return 0; return 1; } else { /* this is an clflush */ if (NaClGetCPUFeature(&vstate->cpufeatures, NaClCPUFeature_CLFLUSH)) return 0; return 1; } }
void NaClInitSwitchToApp(struct NaClApp *nap) { NaClCPUFeaturesX86 cpu_features; UNREFERENCED_PARAMETER(nap); /* * TODO(mcgrathr): This call is repeated in platform qualification and * in every application of the validator. It would be more efficient * to do it once and then reuse the same data. */ NaClGetCurrentCPUFeatures(&cpu_features); if (NaClGetCPUFeature(&cpu_features, NaClCPUFeature_AVX)) { NaClSwitch = NaClSwitchAVX; } else { NaClSwitch = NaClSwitchSSE; } }
static Bool ValidateInst(const NCDecoderInst *dinst) { NaClCPUFeaturesX86 *cpufeatures; int squashme = 0; NCValidatorState* vstate; if (dinst == NULL) return TRUE; vstate = NCVALIDATOR_STATE_DOWNCAST(dinst->dstate); OpcodeHisto(NCInstBytesByteInline(&dinst->inst_bytes, dinst->inst.prefixbytes), vstate); /* For testing only, this mode disables inter-instruction checks. */ if (!NACL_FLAG_unsafe_single_inst32_mode) { RememberInstructionBoundary(dinst, vstate); } cpufeatures = &(vstate->cpufeatures); if (!ValidatePrefixes(dinst)) { NCBadInstructionError(dinst, "Bad prefix usage"); NCStatsBadPrefix(vstate); } if ((dinst->opinfo->insttype != NACLi_NOP) && ((size_t) (dinst->inst.bytes.length - dinst->inst.prefixbytes) > kMaxValidInstLength)) { NCBadInstructionError(dinst, "Instruction too long"); NCStatsBadInstLength(vstate); } switch (dinst->opinfo->insttype) { case NACLi_NOP: case NACLi_386: case NACLi_386L: case NACLi_386R: case NACLi_386RE: break; case NACLi_JMP8: ValidateJmp8(dinst); break; case NACLi_JMPZ: ValidateJmpz(dinst); break; case NACLi_INDIRECT: ValidateIndirect5(dinst); break; case NACLi_X87: case NACLi_X87_FSINCOS: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_x87); break; case NACLi_SFENCE_CLFLUSH: squashme = ValidateSFenceClFlush(dinst); break; case NACLi_CMPXCHG8B: /* Only allow if the modrm mod field accesses memory. * This stops us from accepting f00f on multiple bytes. * http://en.wikipedia.org/wiki/Pentium_F00F_bug */ if (modrm_modInline(dinst->inst.mrm) == kModRmModFieldDefinesRegisterRef) { NCBadInstructionError(dinst, "Illegal instruction"); NCStatsIllegalInst(vstate); } squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_CX8); break; case NACLi_CMOV: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_CMOV); break; case NACLi_FCMOV: squashme = !(NaClGetCPUFeature(cpufeatures, NaClCPUFeature_CMOV) && NaClGetCPUFeature(cpufeatures, NaClCPUFeature_x87)); break; case NACLi_RDTSC: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_TSC); break; case NACLi_MMX: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_MMX); break; case NACLi_MMXSSE2: /* Note: We accept these instructions if either MMX or SSE2 bits */ /* are set, in case MMX instructions go away someday... */ squashme = !(NaClGetCPUFeature(cpufeatures, NaClCPUFeature_MMX) || NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE2)); break; case NACLi_SSE: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE); break; case NACLi_SSE2: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE2); break; case NACLi_SSE3: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE3); break; case NACLi_SSE4A: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE4A); break; case NACLi_SSE41: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE41); break; case NACLi_SSE42: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE42); break; case NACLi_MOVBE: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_MOVBE); break; case NACLi_POPCNT: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_POPCNT); break; case NACLi_LZCNT: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_LZCNT); break; case NACLi_SSSE3: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSSE3); break; case NACLi_3DNOW: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_3DNOW); break; case NACLi_E3DNOW: squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_E3DNOW); break; case NACLi_SSE2x: /* This case requires CPUID checking code */ /* Note: DATA16 prefix required. The generated table * for group 14 (which the only 2 SSE2x instructions are in), * allows instructions with and without a 66 prefix. However, * the SSE2x instructions psrldq and pslldq are only allowed * with the 66 prefix. Hence, this code has been added to * do this check. */ if (!(dinst->inst.opcode_prefixmask & kPrefixDATA16)) { NCBadInstructionError(dinst, "Bad prefix usage"); NCStatsBadPrefix(vstate); } squashme = !NaClGetCPUFeature(cpufeatures, NaClCPUFeature_SSE2); break; case NACLi_RETURN: NCBadInstructionError(dinst, "ret instruction (not allowed)"); NCStatsReturn(vstate); /* ... and fall through to illegal instruction code */ case NACLi_EMMX: /* EMMX needs to be supported someday but isn't ready yet. */ case NACLi_INVALID: case NACLi_ILLEGAL: case NACLi_SYSTEM: case NACLi_RDMSR: case NACLi_RDTSCP: case NACLi_SYSCALL: case NACLi_SYSENTER: case NACLi_LONGMODE: case NACLi_SVM: case NACLi_OPINMRM: case NACLi_3BYTE: case NACLi_CMPXCHG16B: { NCBadInstructionError(dinst, "Illegal instruction"); NCStatsIllegalInst(vstate); break; } case NACLi_UNDEFINED: { NCBadInstructionError(dinst, "Undefined instruction"); NCStatsIllegalInst(vstate); NCStatsInternalError(vstate); break; } default: NCBadInstructionError(dinst, "Undefined instruction type"); NCStatsInternalError(vstate); break; } if (squashme) { if (vstate->readonly_text) { NCBadInstructionError(dinst, "Illegal instruction for fixed-feature CPU mode"); NCStatsIllegalInst(vstate); } else { NCStubOutMem(vstate, dinst->dstate->memory.mpc, dinst->dstate->memory.read_length); } } return TRUE; }