zipl/stage3: Always use diag308 LOAD_NORMAL_RESET

stage3 still contains a legacy fallback path that transfers control to
the new kernel via LPSW 0 when diag 0x308 is not available.

The current start_kernel() inline asm issues "diag %[code],%[code],0x308"
without enforcing the required even/odd register pairing for the first
operand. With recent distro toolchains (e.g. GCC 15.x as shipped by Fedora
43 and Ubuntu 25.10), register allocation picks an odd register for the
first diag operand in start_kernel(), which triggers a specification
exception. That exception is then caught by the program-check handler
and stage3 silently takes the fallback, booting the kernel via LPSW 0
instead of performing diag308 LOAD_NORMAL_RESET.

All supported environments are expected to provide diag308, and the rest
of the code already relies on it. Drop start_kernel() and the obsolete
LPSW fallback and always reset into the new kernel via the properly
coded diag308() helper. Mark start() as __noreturn.

Reviewed-by: Eduard Shishkin <edward6@linux.ibm.com>
Tested-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Vasily Gorbik
2026-02-07 03:00:23 +01:00
committed by Jan Höppner
parent d7ba322d69
commit 3358a30dae

View File

@@ -32,33 +32,6 @@ static const char *msg_sipl_inval = "Secure boot failure: invalid load address";
static const char *msg_sipl_unverified = "Secure boot failure: unverified load address";
static const char *msg_sipl_noparm = "Secure boot failure: unable to load ipl parameter";
static inline void __noreturn start_kernel(void)
{
struct psw_t *psw = &S390_lowcore.program_new_psw;
unsigned long addr, code;
/* Setup program check handler */
psw->mask = 0x000000180000000ULL;
code = 1;
asm volatile(
/* Setup program check handler */
" larl %[addr],.no_diag308\n"
" stg %[addr],8(%[psw])\n"
" diag %[code],%[code],0x308\n"
".no_diag308:\n"
" sam31\n"
" sr %%r1,%%r1\n"
" sr %%r2,%%r2\n"
" sigp %%r1,%%r2,%[order]\n"
" lpsw 0\n"
: [addr] "=&d" (addr),
[code] "+&d" (code)
: [psw] "a" (psw),
[order] "L" (SIGP_SET_ARCHITECTURE));
while (1);
}
unsigned int
is_verified_address(unsigned long image_addr)
{
@@ -500,7 +473,7 @@ noextra:
handle_environment(strlen(cmdline), max_cmdline_len);
}
void start(void)
void __noreturn start(void)
{
unsigned int subchannel_id;
@@ -537,7 +510,8 @@ void start(void)
kdump_stage3();
/* start new kernel */
start_kernel();
diag308(DIAG308_LOAD_NORMAL_RESET, NULL);
__builtin_unreachable();
}
void panic_notify(unsigned long UNUSED(rc))