Skip to content

Commit

Permalink
Merge pull request #8769 from unknownbrackets/cpuinfo
Browse files Browse the repository at this point in the history
Add ugly invalidation workaround for SGS7s
  • Loading branch information
hrydgard committed May 24, 2016
2 parents 01d3cb3 + 4113fd9 commit 9b63a44
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 32 deletions.
8 changes: 8 additions & 0 deletions Common/Arm64Emitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "Arm64Emitter.h"
#include "MathUtil.h"
#include "CommonTypes.h"
#include "CPUDetect.h"

namespace Arm64Gen
{
Expand Down Expand Up @@ -312,6 +313,13 @@ void ARM64XEmitter::FlushIcache()

void ARM64XEmitter::FlushIcacheSection(u8* start, u8* end)
{
if (cpu_info.sBugs.bExynos8890Invalidation)
{
// Over invalidate to force this CPU to listen.
start = m_startcode + 4096 < start ? start - 4096 : m_startcode;
end += 4096;
}

#if defined(IOS)
// Header file says this is equivalent to: sys_icache_invalidate(start, end - start);
sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start);
Expand Down
88 changes: 56 additions & 32 deletions Common/ArmCPUDetect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,58 +23,80 @@
#ifdef BLACKBERRY
#include <bps/deviceinfo.h>
#endif
#ifdef ANDROID
#include <sys/system_properties.h>
#endif

// Only Linux platforms have /proc/cpuinfo
#if defined(__linux__)
const char procfile[] = "/proc/cpuinfo";
// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu
const char syscpupresentfile[] = "/sys/devices/system/cpu/present";

std::string GetCPUString()
{
std::string line, marker = "Hardware\t: ";
std::string cpu_string = "Unknown";
std::string GetCPUString() {
std::string cpu_string;
std::fstream file;
if (!File::OpenCPPFile(file, procfile, std::ios::in))
return cpu_string;

while (std::getline(file, line))
{
if (line.find(marker) != std::string::npos)
{
cpu_string = line.substr(marker.length());
if (cpu_string.back() == '\n')
cpu_string.pop_back(); // Drop the new-line character

if (File::OpenCPPFile(file, procfile, std::ios::in)) {
std::string line, marker = "Hardware\t: ";
while (std::getline(file, line)) {
if (line.find(marker) != std::string::npos) {
cpu_string = line.substr(marker.length());
}
}
}

#ifdef ANDROID
if (cpu_string.empty()) {
char temp[PROP_VALUE_MAX];
if (__system_property_get("ro.product.board", temp) != 0) {
cpu_string = temp;
} else if (__system_property_get("ro.product.name", temp) != 0) {
cpu_string = temp;
}
}
#endif

if (cpu_string.empty())
cpu_string = "Unknown";
else if (cpu_string.back() == '\n')
cpu_string.pop_back(); // Drop the new-line character

return cpu_string;
}

std::string GetCPUBrandString()
{
std::string line, marker = "Processor\t: ";
std::string brand_string = "Unknown";
std::string GetCPUBrandString() {
std::string brand_string;
std::fstream file;
if (!File::OpenCPPFile(file, procfile, std::ios::in))
return brand_string;

while (std::getline(file, line))
{
if (line.find(marker) != std::string::npos)
{
brand_string = line.substr(marker.length());
if (brand_string.back() == '\n')
brand_string.pop_back(); // Drop the new-line character

if (brand_string.length() == 0 || isdigit(brand_string[0])) {
brand_string = "Unknown";
continue;
if (File::OpenCPPFile(file, procfile, std::ios::in)) {
std::string line, marker = "Processor\t: ";
while (std::getline(file, line)) {
if (line.find(marker) != std::string::npos) {
brand_string = line.substr(marker.length());
if (brand_string.length() != 0 && !isdigit(brand_string[0])) {
break;
}
}
break;
}
}

#ifdef ANDROID
if (brand_string.empty()) {
char temp[PROP_VALUE_MAX];
if (__system_property_get("ro.product.model", temp) != 0) {
brand_string = temp;
} else if (__system_property_get("ro.product.name", temp) != 0) {
brand_string = temp;
}
}
#endif

if (brand_string.empty())
brand_string = "Unknown";
else if (brand_string.back() == '\n')
brand_string.pop_back(); // Drop the new-line character

return brand_string;
}

Expand Down Expand Up @@ -274,6 +296,8 @@ void CPUInfo::Detect()
// Whether the above detection failed or not, on ARM64 we do have ASIMD/NEON.
bNEON = true;
bASIMD = true;

sBugs.bExynos8890Invalidation = strcmp(cpu_string, "universal8890") == 0;
#endif
}

Expand Down
9 changes: 9 additions & 0 deletions Common/CPUDetect.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ struct CPUInfo {
bool bXBurst1;
bool bXBurst2;

// Bugs
struct {
// Samsung Galaxy S7 devices (Exynos 8890) have a bug that causes invalidation to work incorrectly.
// This may be caused by interaction between the separate CPU cores.
// Padding jit blocks and over-invalidating seems to "solve" it.
// Only affects ARM64.
bool bExynos8890Invalidation;
} sBugs;

// Call Detect()
explicit CPUInfo();

Expand Down
8 changes: 8 additions & 0 deletions Core/MIPS/ARM64/Arm64Jit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,14 @@ const u8 *Arm64Jit::DoJit(u32 em_address, JitBlock *b) {
if (dontLogBlocks > 0)
dontLogBlocks--;

if (cpu_info.sBugs.bExynos8890Invalidation) {
// What a waste. If we don't do both this and over-invalidate, the device crashes.
// This space won't ever get run, but it's wasted jit cache space.
for (int i = 0; i < 32; ++i) {
HINT(HINT_NOP);
}
}

// Don't forget to zap the newly written instructions in the instruction cache!
FlushIcache();

Expand Down
8 changes: 8 additions & 0 deletions GPU/Common/VertexDecoderArm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,14 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int

RET();

if (cpu_info.sBugs.bExynos8890Invalidation) {
// Apparently the vertex cache hasn't been the problem, but adding this here for the same
// reasons as the standard jit.
for (int i = 0; i < 32; ++i) {
HINT(HINT_NOP);
}
}

FlushIcache();

if (log) {
Expand Down

0 comments on commit 9b63a44

Please sign in to comment.