/* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ package compiler.runtime; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import jdk.test.whitebox.WhiteBox; import jtreg.SkippedException; /* * @test * @bug 8370947 * @summary Test command-line options for UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation * @library /test/lib * @requires os.arch == "aarch64" * @requires os.family == "linux" * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI compiler.runtime.TestDeferredICacheInvalidationCmdOptions */ public class TestDeferredICacheInvalidationCmdOptions { // CPU identifiers private static final int CPU_ARM = 0x41; private static final int NEOVERSE_N1_MODEL = 0xd0c; private static boolean isAffected; public static void main(String[] args) throws Exception { // Parse CPU features and print CPU info parseCPUFeatures(); System.out.println("Testing UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation command-line options..."); // Test case 1: Check defaults on Neoverse N1 pre-r4p1 (if applicable) testCase1_DefaultsOnNeoverseN1(); // Test case 2: Check NeoverseN1ICacheErratumMitigation is false on unaffected CPUs testCase2_DefaultsOnUnaffectedCPUs(); // Test case 3: Check if NeoverseN1ICacheErratumMitigation is set to false on affected CPUs, // UseSingleICacheInvalidation is also set to false testCase3_ExplicitlyDisableErrataAffectsDeferred(); // Test case 4: Check JVM error if UseSingleICacheInvalidation=true // but NeoverseN1ICacheErratumMitigation=false on affected CPUs testCase4_ConflictingFlagsOnAffectedCPUs(); // Test case 5: Check explicit NeoverseN1ICacheErratumMitigation=true enables UseSingleICacheInvalidation testCase5_ExplicitlyEnableErrataEnablesDeferred(); // Test case 6: Check both flags can be explicitly set to false testCase6_ExplicitlyDisableBothFlags(); // Test case 7: Check UseSingleICacheInvalidation=false with NeoverseN1ICacheErratumMitigation=true testCase7_ConflictingErrataWithoutDeferred(); // Test case 8: Check setting NeoverseN1ICacheErratumMitigation=true on unaffected CPU causes an error testCase8_EnablingErrataOnUnaffectedCPU(); System.out.println("All test cases passed!"); } /** * Parse CPU features string from WhiteBox.getCPUFeatures() to extract: * - cpuFamily: 0x41 for ARM * - cpuVariant: major revision * - cpuModel: e.g., 0xd0c for Neoverse N1 * - cpuRevision: minor revision * - cpuModel2: secondary model (if present, in parentheses) * * Sets the static field isAffected and prints CPU info. * * Format: 0x%02x:0x%x:0x%03x:%d[(0x%03x)] * Example: "0x41:0x3:0xd0c:0" or "0x41:0x3:0xd0c:0(0xd0c)" * * @throws SkippedException if not running on ARM CPU */ private static void parseCPUFeatures() { WhiteBox wb = WhiteBox.getWhiteBox(); String cpuFeatures = wb.getCPUFeatures(); System.out.println("CPU Features string: " + cpuFeatures); if (cpuFeatures == null || cpuFeatures.isEmpty()) { throw new RuntimeException("No CPU features available"); } int commaIndex = cpuFeatures.indexOf(","); if (commaIndex == -1) { throw new RuntimeException("Unexpected CPU features format (no comma): " + cpuFeatures); } String cpuPart = cpuFeatures.substring(0, commaIndex).trim(); String[] parts = cpuPart.split(":"); if (parts.length < 4) { throw new RuntimeException("Unexpected CPU features format: " + cpuPart); } int cpuFamily = Integer.parseInt(parts[0].substring(2), 16); if (cpuFamily != CPU_ARM) { throw new SkippedException("Not running on ARM CPU (cpuFamily=0x" + Integer.toHexString(cpuFamily) + ")"); } int cpuVariant = Integer.parseInt(parts[1].substring(2), 16); int cpuModel = Integer.parseInt(parts[2].substring(2), 16); int cpuModel2 = 0; int model2Start = parts[3].indexOf("("); String revisionStr = parts[3]; if (model2Start != -1) { if (!parts[3].endsWith(")")) { throw new RuntimeException("Unexpected CPU features format (missing closing parenthesis): " + parts[3]); } String model2Str = parts[3].substring(model2Start + 1, parts[3].length() - 1); cpuModel2 = Integer.parseInt(model2Str.substring(2), 16); revisionStr = parts[3].substring(0, model2Start); } int cpuRevision = Integer.parseInt(revisionStr); // Neoverse N1 errata 1542419 affects r3p0, r3p1 and r4p0. // It is fixed in r4p1 and later revisions. if (cpuModel == NEOVERSE_N1_MODEL || cpuModel2 == NEOVERSE_N1_MODEL) { isAffected = (cpuVariant == 3 && cpuRevision == 0) || (cpuVariant == 3 && cpuRevision == 1) || (cpuVariant == 4 && cpuRevision == 0); } printCPUInfo(cpuFamily, cpuVariant, cpuModel, cpuModel2, cpuRevision); } private static void printCPUInfo(int cpuFamily, int cpuVariant, int cpuModel, int cpuModel2, int cpuRevision) { boolean isNeoverseN1 = (cpuFamily == CPU_ARM) && (cpuModel == NEOVERSE_N1_MODEL || cpuModel2 == NEOVERSE_N1_MODEL); System.out.println("\n=== CPU Information ==="); System.out.println("CPU Family: 0x" + Integer.toHexString(cpuFamily)); System.out.println("CPU Variant: 0x" + Integer.toHexString(cpuVariant)); System.out.println("CPU Model: 0x" + Integer.toHexString(cpuModel)); if (cpuModel2 != 0) { System.out.println("CPU Model2: 0x" + Integer.toHexString(cpuModel2)); } System.out.println("CPU Revision: " + cpuRevision); System.out.println("Is Neoverse N1: " + isNeoverseN1); System.out.println("Is affected by errata 1542419: " + isAffected); System.out.println("======================\n"); } /** * Test case 1: Check the UseSingleICacheInvalidation and NeoverseN1ICacheErratumMitigation * are set to true for Neoverse N1 pre-r4p1. */ private static void testCase1_DefaultsOnNeoverseN1() throws Exception { if (!isAffected) { System.out.println("\nTest case 1: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); return; } System.out.println("\nTest case 1: Check defaults on Neoverse N1 affected revisions"); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintFlagsFinal", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); String output_str = output.getOutput(); boolean hasSingleEnabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*true.*"); boolean hasErrataEnabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*true.*"); System.out.println("UseSingleICacheInvalidation enabled: " + hasSingleEnabled); System.out.println("NeoverseN1ICacheErratumMitigation enabled: " + hasErrataEnabled); // If running on affected Neoverse N1, both should be true if (!hasSingleEnabled || !hasErrataEnabled) { throw new RuntimeException("On affected Neoverse N1, both flags should be enabled by default"); } System.out.println("Correctly enabled on affected Neoverse N1"); } /** * Test case 2: Check NeoverseN1ICacheErratumMitigation is false on unaffected CPUs. */ private static void testCase2_DefaultsOnUnaffectedCPUs() throws Exception { if (isAffected) { System.out.println("\nTest case 2: Skipping since CPU is affected by Neoverse N1 errata 1542419"); return; } System.out.println("\nTest case 2: Check NeoverseN1ICacheErratumMitigation is false on unaffected CPUs"); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintFlagsFinal", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); String output_str = output.getOutput(); boolean hasErrataEnabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*true.*"); System.out.println("NeoverseN1ICacheErratumMitigation enabled: " + hasErrataEnabled); // On non-Neoverse N1 or unaffected Neoverse N1 CPUs, NeoverseN1ICacheErratumMitigation should be false if (hasErrataEnabled) { throw new RuntimeException("On unaffected CPUs, NeoverseN1ICacheErratumMitigation should be disabled"); } System.out.println("Correctly disabled on unaffected CPU"); } /** * Test case 3: Check if NeoverseN1ICacheErratumMitigation is set to false via cmd on affected CPUs, * UseSingleICacheInvalidation is set to false. */ private static void testCase3_ExplicitlyDisableErrataAffectsDeferred() throws Exception { if (!isAffected) { System.out.println("\nTest case 3: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); return; } System.out.println("\nTest case 3: Explicitly disable NeoverseN1ICacheErratumMitigation, check UseSingleICacheInvalidation"); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-XX:-NeoverseN1ICacheErratumMitigation", "-XX:+PrintFlagsFinal", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); String output_str = output.getOutput(); boolean hasSingleDisabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*false.*"); boolean hasErrataDisabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*false.*"); System.out.println("NeoverseN1ICacheErratumMitigation disabled: " + hasErrataDisabled); System.out.println("UseSingleICacheInvalidation disabled: " + hasSingleDisabled); if (!hasErrataDisabled) { throw new RuntimeException("Failed to disable NeoverseN1ICacheErratumMitigation via command line"); } // On affected CPUs, disabling errata should also disable UseSingleICacheInvalidation if (!hasSingleDisabled) { throw new RuntimeException("On affected CPU, disabling NeoverseN1ICacheErratumMitigation should also disable UseSingleICacheInvalidation"); } System.out.println("Correctly synchronized on affected CPU"); } /** * Test case 4: Check JVM reports an error if UseSingleICacheInvalidation is set to true * but NeoverseN1ICacheErratumMitigation is set to false on affected CPUs. */ private static void testCase4_ConflictingFlagsOnAffectedCPUs() throws Exception { if (!isAffected) { System.out.println("\nTest case 4: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); return; } System.out.println("\nTest case 4: Try to set UseSingleICacheInvalidation=true with NeoverseN1ICacheErratumMitigation=false"); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSingleICacheInvalidation", "-XX:-NeoverseN1ICacheErratumMitigation", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); if (output.getExitValue() == 0) { throw new RuntimeException("On affected CPU, conflicting flags should cause error"); } output.shouldContain("Error"); System.out.println("JVM correctly rejected conflicting flags on affected CPU"); } /** * Test case 5: Check explicit NeoverseN1ICacheErratumMitigation=true enables UseSingleICacheInvalidation. */ private static void testCase5_ExplicitlyEnableErrataEnablesDeferred() throws Exception { if (!isAffected) { System.out.println("\nTest case 5: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); return; } System.out.println("\nTest case 5: Explicitly enable NeoverseN1ICacheErratumMitigation, check UseSingleICacheInvalidation"); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-XX:+NeoverseN1ICacheErratumMitigation", "-XX:+PrintFlagsFinal", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); String output_str = output.getOutput(); boolean hasSingleEnabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*true.*"); boolean hasErrataEnabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*true.*"); System.out.println("NeoverseN1ICacheErratumMitigation enabled: " + hasErrataEnabled); System.out.println("UseSingleICacheInvalidation enabled: " + hasSingleEnabled); if (!hasErrataEnabled) { throw new RuntimeException("Failed to enable NeoverseN1ICacheErratumMitigation via command line"); } if (!hasSingleEnabled) { throw new RuntimeException("On affected CPU, enabling NeoverseN1ICacheErratumMitigation should also enable UseSingleICacheInvalidation"); } System.out.println("Correctly synchronized on affected CPU"); } /** * Test case 6: Check both flags can be explicitly set to false. */ private static void testCase6_ExplicitlyDisableBothFlags() throws Exception { System.out.println("\nTest case 6: Explicitly disable both flags"); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSingleICacheInvalidation", "-XX:-NeoverseN1ICacheErratumMitigation", "-XX:+PrintFlagsFinal", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); String output_str = output.getOutput(); boolean hasSingleDisabled = output_str.matches("(?s).*bool\\s+UseSingleICacheInvalidation\\s*=\\s*false.*"); boolean hasErrataDisabled = output_str.matches("(?s).*bool\\s+NeoverseN1ICacheErratumMitigation\\s*=\\s*false.*"); System.out.println("UseSingleICacheInvalidation disabled: " + hasSingleDisabled); System.out.println("NeoverseN1ICacheErratumMitigation disabled: " + hasErrataDisabled); if (!hasErrataDisabled) { throw new RuntimeException("Failed to disable NeoverseN1ICacheErratumMitigation via command line"); } if (!hasSingleDisabled) { throw new RuntimeException("Failed to disable UseSingleICacheInvalidation via command line"); } System.out.println("Successfully disabled both flags"); } /** * Test case 7: Check UseSingleICacheInvalidation=false with NeoverseN1ICacheErratumMitigation=true. * On affected CPUs, this should error (conflicting requirement). */ private static void testCase7_ConflictingErrataWithoutDeferred() throws Exception { if (!isAffected) { System.out.println("\nTest case 7: Skipping since CPU is not affected by Neoverse N1 errata 1542419"); return; } System.out.println("\nTest case 7: Try to set NeoverseN1ICacheErratumMitigation=true with UseSingleICacheInvalidation=false"); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSingleICacheInvalidation", "-XX:+NeoverseN1ICacheErratumMitigation", "-XX:+PrintFlagsFinal", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); // This should fail on affected CPUs (conflicting requirement) if (output.getExitValue() == 0) { throw new RuntimeException("On affected CPU, setting NeoverseN1ICacheErratumMitigation=true with UseSingleICacheInvalidation=false should cause an error"); } output.shouldContain("Error"); System.out.println("JVM correctly rejected conflicting flags on affected CPU"); } /** * Test case 8: Check setting NeoverseN1ICacheErratumMitigation=true on unaffected CPU causes an error. */ private static void testCase8_EnablingErrataOnUnaffectedCPU() throws Exception { if (isAffected) { System.out.println("\nTest case 8: Skipping since CPU is affected by Neoverse N1 errata 1542419"); return; } System.out.println("\nTest case 8: Try to set NeoverseN1ICacheErratumMitigation=true on unaffected CPU"); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", "-XX:+NeoverseN1ICacheErratumMitigation", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); // This should fail on unaffected CPUs (errata not present) if (output.getExitValue() == 0) { throw new RuntimeException("On unaffected CPU, setting NeoverseN1ICacheErratumMitigation=true should cause error"); } output.shouldContain("Error"); System.out.println("JVM correctly rejected enabling errata flag on unaffected CPU"); } }