@@ -88,12 +88,23 @@ static void expect_invalid_psw(struct psw psw)
invalid_psw_expected = true;
}
+static void clear_invalid_psw(void)
+{
+ expected_psw = PSW(0, 0);
+ invalid_psw_expected = false;
+}
+
static int check_invalid_psw(void)
{
/* Since the fixup sets this to false we check for false here. */
if (!invalid_psw_expected) {
+ /*
+ * Early exception recognition: pgm_int_id == 0.
+ * Late exception recognition: psw address has been
+ * incremented by pgm_int_id (unpredictable value)
+ */
if (expected_psw.mask == invalid_psw.mask &&
- expected_psw.addr == invalid_psw.addr)
+ expected_psw.addr == invalid_psw.addr - lowcore.pgm_int_id)
return 0;
report_fail("Wrong invalid PSW");
} else {
@@ -112,6 +123,42 @@ static int psw_bit_12_is_1(void)
return check_invalid_psw();
}
+extern char misaligned_code[];
+asm ( ".balign 2\n"
+" . = . + 1\n"
+"misaligned_code:\n"
+" larl %r0,0\n"
+" br %r1\n"
+);
+
+static int psw_odd_address(void)
+{
+ struct psw odd = PSW_WITH_CUR_MASK((uint64_t)&misaligned_code);
+ uint64_t executed_addr;
+
+ expect_invalid_psw(odd);
+ fixup_psw.mask = extract_psw_mask();
+ asm volatile ( "xgr %%r0,%%r0\n"
+ " larl %%r1,0f\n"
+ " stg %%r1,%[fixup_addr]\n"
+ " lpswe %[odd_psw]\n"
+ "0: lr %[executed_addr],%%r0\n"
+ : [fixup_addr] "=&T" (fixup_psw.addr),
+ [executed_addr] "=d" (executed_addr)
+ : [odd_psw] "Q" (odd)
+ : "cc", "%r0", "%r1"
+ );
+
+ if (!executed_addr) {
+ return check_invalid_psw();
+ } else {
+ assert(executed_addr == odd.addr);
+ clear_invalid_psw();
+ report_fail("did not execute unaligned instructions");
+ return 1;
+ }
+}
+
/* A short PSW needs to have bit 12 set to be valid. */
static int short_psw_bit_12_is_0(void)
{
@@ -170,6 +217,7 @@ struct spec_ex_trigger {
static const struct spec_ex_trigger spec_ex_triggers[] = {
{ "psw_bit_12_is_1", &psw_bit_12_is_1, false, &fixup_invalid_psw },
{ "short_psw_bit_12_is_0", &short_psw_bit_12_is_0, false, &fixup_invalid_psw },
+ { "psw_odd_address", &psw_odd_address, false, &fixup_invalid_psw },
{ "bad_alignment", &bad_alignment, true, NULL },
{ "not_even", ¬_even, true, NULL },
{ NULL, NULL, false, NULL },