int main(void) { NaClCPUFeaturesX86 fv; NaClCPUData cpu_data; int feature_id; NaClCPUDataGet(&cpu_data); NaClGetCurrentCPUFeaturesX86((NaClCPUFeatures *) &fv); if (NaClArchSupportedX86(&fv)) { printf("This is a native client %d-bit %s compatible computer\n", NACL_TARGET_SUBARCH, GetCPUIDString(&cpu_data)); } else { if (!NaClGetCPUFeatureX86(&fv, NaClCPUFeatureX86_CPUIDSupported)) { printf("Computer doesn't support CPUID\n"); } if (!NaClGetCPUFeatureX86(&fv, NaClCPUFeatureX86_CPUSupported)) { printf("Computer id %s is not supported\n", GetCPUIDString(&cpu_data)); } } printf("This processor has:\n"); for (feature_id = 0; feature_id < NaClCPUFeatureX86_Max; ++feature_id) { if (NaClGetCPUFeatureX86(&fv, feature_id)) printf(" %s\n", NaClGetCPUFeatureX86Name(feature_id)); } return 0; }
void NaClInitSwitchToApp(struct NaClApp *nap) { /* TODO(jfb) Use a safe cast here. */ NaClCPUFeaturesX86 *features = (NaClCPUFeaturesX86 *) nap->cpu_features; if (NaClGetCPUFeatureX86(features, NaClCPUFeatureX86_AVX)) { NaClSwitch = NaClSwitchAVX; } else if (NaClGetCPUFeatureX86(features, NaClCPUFeatureX86_SSE)) { NaClSwitch = NaClSwitchSSE; } else { NaClSwitch = NaClSwitchNoSSE; } }
/* Helper function to report unsupported features */ static INLINE void NaClCheckFeature(NaClCPUFeatureX86ID feature, struct NaClValidatorState* vstate, Bool* squash_me) { if (!NaClGetCPUFeatureX86(&vstate->cpu_features, feature)) { if (!NaClGetCPUFeatureX86(&vstate->cpu_checks.cpu_features, feature)) { NaClValidatorInstMessage( LOG_WARNING, vstate, vstate->cur_inst_state, "CPU model does not support %s instructions.\n", NaClGetCPUFeatureX86Name(feature)); NaClSetCPUFeatureX86(&vstate->cpu_checks.cpu_features, feature, TRUE); } *squash_me = TRUE; } }
/* 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 (NaClGetCPUFeatureX86(&vstate->cpufeatures, NaClCPUFeatureX86_FXSR)) return 0; return 1; } else { /* this is an clflush */ if (NaClGetCPUFeatureX86(&vstate->cpufeatures, NaClCPUFeatureX86_CLFLUSH)) return 0; return 1; } }
static int32_t TestSyscall(struct NaClAppThread *natp) { /* TODO(mcgrathr): Use a safe cast here. */ NaClCPUFeaturesX86 *features = (NaClCPUFeaturesX86 *) natp->nap->cpu_features; if (NaClGetCPUFeatureX86(features, NaClCPUFeatureX86_SSE)) { g_nacl_syscall_thread_capture_fault_addr = (uintptr_t) &NaClSyscallThreadCaptureFaultSSE; } else { g_nacl_syscall_thread_capture_fault_addr = (uintptr_t) &NaClSyscallThreadCaptureFaultNoSSE; } natp->user.gs = natp->user.trusted_gs; return 0; }
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 = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_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 = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_CX8); break; case NACLi_CMOV: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_CMOV); break; case NACLi_FCMOV: squashme = !(NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_CMOV) && NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_x87)); break; case NACLi_RDTSC: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_TSC); break; case NACLi_MMX: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_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 = !(NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_MMX) || NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE2)); break; case NACLi_SSE: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE); break; case NACLi_SSE2: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE2); break; case NACLi_SSE3: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE3); break; case NACLi_SSE4A: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE4A); break; case NACLi_SSE41: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE41); break; case NACLi_SSE42: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSE42); break; case NACLi_MOVBE: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_MOVBE); break; case NACLi_POPCNT: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_POPCNT); break; case NACLi_LZCNT: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_LZCNT); break; case NACLi_SSSE3: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_SSSE3); break; case NACLi_3DNOW: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_3DNOW); break; case NACLi_E3DNOW: squashme = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_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 = !NaClGetCPUFeatureX86(cpufeatures, NaClCPUFeatureX86_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; }
void NaClCpuCheck(struct NaClValidatorState* state, struct NaClInstIter* iter) { Bool squash_me = FALSE; switch (state->cur_inst->insttype) { case NACLi_X87: case NACLi_X87_FSINCOS: NaClCheckFeature(NaClCPUFeatureX86_x87, state, &squash_me); break; case NACLi_SFENCE_CLFLUSH: /* TODO(bradchen): distinguish between SFENCE and CLFLUSH */ NaClCheckFeature(NaClCPUFeatureX86_CLFLUSH, state, &squash_me); NaClCheckFeature(NaClCPUFeatureX86_FXSR, state, &squash_me); break; case NACLi_CMPXCHG8B: NaClCheckFeature(NaClCPUFeatureX86_CX8, state, &squash_me); break; case NACLi_CMPXCHG16B: NaClCheckFeature(NaClCPUFeatureX86_CX16, state, &squash_me); break; case NACLi_CMOV: NaClCheckFeature(NaClCPUFeatureX86_CMOV, state, &squash_me); break; case NACLi_FCMOV: if (!(NaClGetCPUFeatureX86(&state->cpu_features, NaClCPUFeatureX86_CMOV) && NaClGetCPUFeatureX86(&state->cpu_features, NaClCPUFeatureX86_x87))) { if (!state->cpu_checks.f_CMOV_and_x87) { NaClValidatorInstMessage( LOG_WARNING, state, state->cur_inst_state, "CPU model does not support CMOV and x87 instructions.\n"); state->cpu_checks.f_CMOV_and_x87 = TRUE; } squash_me = TRUE; } break; case NACLi_RDTSC: NaClCheckFeature(NaClCPUFeatureX86_TSC, state, &squash_me); break; case NACLi_MMX: NaClCheckFeature(NaClCPUFeatureX86_MMX, state, &squash_me); break; case NACLi_MMXSSE2: /* Note: We accept these instructions if either MMX or SSE2 bits */ /* are set, in case MMX instructions go away someday... */ if (!(NaClGetCPUFeatureX86(&state->cpu_features, NaClCPUFeatureX86_MMX) || NaClGetCPUFeatureX86(&state->cpu_features, NaClCPUFeatureX86_SSE2))) { if (!state->cpu_checks.f_MMX_or_SSE2) { NaClValidatorInstMessage( LOG_WARNING, state, state->cur_inst_state, "CPU model does not support MMX or SSE2 instructions.\n"); state->cpu_checks.f_MMX_or_SSE2 = TRUE; } } squash_me = TRUE; break; case NACLi_SSE: NaClCheckFeature(NaClCPUFeatureX86_SSE, state, &squash_me); break; case NACLi_SSE2: NaClCheckFeature(NaClCPUFeatureX86_SSE2, state, &squash_me); break; case NACLi_SSE3: NaClCheckFeature(NaClCPUFeatureX86_SSE3, state, &squash_me); break; case NACLi_SSE4A: NaClCheckFeature(NaClCPUFeatureX86_SSE4A, state, &squash_me); break; case NACLi_SSE41: NaClCheckFeature(NaClCPUFeatureX86_SSE41, state, &squash_me); break; case NACLi_SSE42: NaClCheckFeature(NaClCPUFeatureX86_SSE42, state, &squash_me); break; case NACLi_MOVBE: NaClCheckFeature(NaClCPUFeatureX86_MOVBE, state, &squash_me); break; case NACLi_POPCNT: NaClCheckFeature(NaClCPUFeatureX86_POPCNT, state, &squash_me); break; case NACLi_LZCNT: NaClCheckFeature(NaClCPUFeatureX86_LZCNT, state, &squash_me); break; case NACLi_SSSE3: NaClCheckFeature(NaClCPUFeatureX86_SSSE3, state, &squash_me); break; case NACLi_3DNOW: NaClCheckFeature(NaClCPUFeatureX86_3DNOW, state, &squash_me); break; case NACLi_E3DNOW: NaClCheckFeature(NaClCPUFeatureX86_E3DNOW, state, &squash_me); break; case NACLi_LONGMODE: /* TODO(karl): Remove this when NACLi_LONGMODE is no longer needed */ NaClCheckFeature(NaClCPUFeatureX86_LM, state, &squash_me); break; case NACLi_SSE2x: /* This case requires CPUID checking code */ /* DATA16 prefix required */ if (!(state->cur_inst_state->prefix_mask & kPrefixDATA16)) { NaClValidatorInstMessage( LOG_ERROR, state, state->cur_inst_state, "SSEx instruction must use prefix 0x66.\n"); } NaClCheckFeature(NaClCPUFeatureX86_SSE2, state, &squash_me); break; default: /* This instruction could be either legal or illegal, but if we * get here it is not CPU-dependent. */ break; } if (state->cur_inst->flags & NACL_IFLAG(LongMode)) { NaClCheckFeature(NaClCPUFeatureX86_LM, state, &squash_me); } if (squash_me) { if (state->readonly_text) { NaClValidatorInstMessage( LOG_ERROR, state, state->cur_inst_state, "Read-only text: cannot squash unsupported instruction.\n"); } else { /* Replace all bytes of the instruction with the HLT instruction. */ NCStubOutMem(state, NaClInstIterGetInstMemoryInline(iter), NaClInstStateLength(state->cur_inst_state)); } } }