mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
The binary Linux kernel image is built to be loaded to memory address 0x0 but the first 64 kbyte contain an IPL header that is not used for disk IPL. zIPL strips away this IPL header when writing IPL records to disk, loads the remaining data to memory address 0x10000 and uses the memory area below that for its own boot loader code. The Secure Boot firmware feature checks the integrity of an installed image during IPL using a checksum that was generated for the full image. Since the checksum becomes invalid if the IPL header is removed, zIPL must be changed to write the full image to disk. This patch modifies the zIPL logic to no longer strip away the IPL header. Instead the full image is loaded to a higher memory address and relocated by the stage 3 boot loader code to its final location. Signed-off-by: Stefan Haberland <sth@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
315 lines
12 KiB
C
315 lines
12 KiB
C
/*
|
|
* zipl - zSeries Initial Program Loader tool
|
|
*
|
|
* Main program for stage3 bootloader
|
|
*
|
|
* Copyright IBM Corp. 2013, 2018
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include "libc.h"
|
|
#include "s390.h"
|
|
#include "stage3.h"
|
|
|
|
/*
|
|
* 64 Byte dummy space for external symbols
|
|
* _parm_addr; address of parmline
|
|
* _initrd_addr; address of initrd
|
|
* _initrd_len; length of initrd
|
|
* _load_psw; load psw of kernel
|
|
* _extra_parm; use extra parm line mechanism?
|
|
* stage3_flags; flags (e.g. STAGE3_FLAG_KDUMP)
|
|
* _image_len; length of kernel
|
|
* _image_addr; target address of kernel
|
|
*
|
|
* needed to blow up the binary and leave room
|
|
*/
|
|
__attribute__ ((section(".text.dummy"))) void _dummy(void)
|
|
{
|
|
asm volatile(
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
".long 0x00000000\n"
|
|
);
|
|
}
|
|
|
|
static unsigned char ebc_037[256] = {
|
|
/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
|
|
0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
|
|
/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
|
|
0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
|
/* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
|
|
-ENP ->LF */
|
|
0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
|
|
/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
|
|
-IUS */
|
|
0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
|
|
-INP */
|
|
0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
|
|
/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
|
|
-SW */
|
|
0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
|
|
/* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
|
|
0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
|
|
/* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
|
|
0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
|
|
/* 0x40 SP RSP ä ---- */
|
|
0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
|
|
/* 0x48 . < ( + | */
|
|
0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
|
|
/* 0x50 & ---- */
|
|
0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
|
|
/* 0x58 ß ! $ * ) ; */
|
|
0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
|
|
/* 0x60 - / ---- Ä ---- ---- ---- */
|
|
0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
|
|
/* 0x68 ---- , % _ > ? */
|
|
0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
|
|
/* 0x70 --- ---- ---- ---- ---- ---- ---- */
|
|
0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
/* 0x78 * ` : # @ ' = " */
|
|
0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
|
|
/* 0x80 * a b c d e f g */
|
|
0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
|
/* 0x88 h i ---- ---- ---- */
|
|
0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
|
|
/* 0x90 ° j k l m n o p */
|
|
0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
|
|
/* 0x98 q r ---- ---- */
|
|
0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
|
|
/* 0xA0 ~ s t u v w x */
|
|
0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
|
/* 0xA8 y z ---- ---- ---- ---- */
|
|
0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
|
|
/* 0xB0 ^ ---- § ---- */
|
|
0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
|
|
/* 0xB8 ---- [ ] ---- ---- ---- ---- */
|
|
0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
|
|
/* 0xC0 { A B C D E F G */
|
|
0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
|
/* 0xC8 H I ---- ö ---- */
|
|
0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
|
|
/* 0xD0 } J K L M N O P */
|
|
0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
|
|
/* 0xD8 Q R ---- ü */
|
|
0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
|
|
/* 0xE0 \ S T U V W X */
|
|
0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
|
/* 0xE8 Y Z ---- Ö ---- ---- ---- */
|
|
0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
|
|
/* 0xF0 0 1 2 3 4 5 6 7 */
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
/* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
|
|
0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
|
|
};
|
|
|
|
static unsigned char ebc_500[256] = {
|
|
/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
|
|
0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
|
|
/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
|
|
0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
|
/* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
|
|
-ENP ->LF */
|
|
0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
|
|
/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
|
|
-IUS */
|
|
0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
|
|
-INP */
|
|
0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
|
|
/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
|
|
-SW */
|
|
0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
|
|
/* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
|
|
0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
|
|
/* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
|
|
0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
|
|
/* 0x40 SP RSP ä ---- */
|
|
0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
|
|
/* 0x48 . < ( + | */
|
|
0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
|
|
/* 0x50 & ---- */
|
|
0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
|
|
/* 0x58 ß ! $ * ) ; */
|
|
0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
|
|
/* 0x60 - / ---- Ä ---- ---- ---- */
|
|
0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
|
|
/* 0x68 ---- , % _ > ? */
|
|
0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
|
|
/* 0x70 --- ---- ---- ---- ---- ---- ---- */
|
|
0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
|
/* 0x78 * ` : # @ ' = " */
|
|
0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
|
|
/* 0x80 * a b c d e f g */
|
|
0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
|
/* 0x88 h i ---- ---- ---- */
|
|
0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
|
|
/* 0x90 ° j k l m n o p */
|
|
0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
|
|
/* 0x98 q r ---- ---- */
|
|
0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
|
|
/* 0xA0 ~ s t u v w x */
|
|
0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
|
/* 0xA8 y z ---- ---- ---- ---- */
|
|
0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
|
|
/* 0xB0 ^ ---- § ---- */
|
|
0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
|
|
/* 0xB8 ---- [ ] ---- ---- ---- ---- */
|
|
0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
|
|
/* 0xC0 { A B C D E F G */
|
|
0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
|
/* 0xC8 H I ---- ö ---- */
|
|
0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
|
|
/* 0xD0 } J K L M N O P */
|
|
0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
|
|
/* 0xD8 Q R ---- ü */
|
|
0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
|
|
/* 0xE0 \ S T U V W X */
|
|
0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
|
/* 0xE8 Y Z ---- Ö ---- ---- ---- */
|
|
0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
|
|
/* 0xF0 0 1 2 3 4 5 6 7 */
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
/* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
|
|
0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
|
|
};
|
|
|
|
static void ebcdic_to_ascii(unsigned char *target, unsigned char *source,
|
|
unsigned int l)
|
|
{
|
|
unsigned char *ebc;
|
|
unsigned int i;
|
|
|
|
ebc = is_zvm() ? ebc_037 : ebc_500;
|
|
for (i = 0; i < l; i++)
|
|
target[i] = ebc[source[i]];
|
|
}
|
|
|
|
static void
|
|
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,0x12\n"
|
|
" lpsw 0\n"
|
|
: [addr] "=&d" (addr),
|
|
[code] "+&d" (code)
|
|
: [psw] "a" (psw) );
|
|
}
|
|
|
|
void start(void)
|
|
{
|
|
unsigned int subchannel_id;
|
|
unsigned char *cextra = (unsigned char *)COMMAND_LINE_EXTRA;
|
|
unsigned char *command_line = (unsigned char *)COMMAND_LINE;
|
|
unsigned int begin = 0, end = 0, length = 0;
|
|
|
|
/*
|
|
* Relocate the kernel image to its actual load address while stripping
|
|
* away the kernel IPL header to not overwrite the stage3 loader.
|
|
*/
|
|
memmove((void *)_image_addr,
|
|
(void *)_image_addr + KERNEL_HEADER_SIZE,
|
|
_image_len - KERNEL_HEADER_SIZE);
|
|
|
|
/* store subchannel ID into low core and into new kernel space */
|
|
subchannel_id = S390_lowcore.subchannel_id;
|
|
*(unsigned int *)__LC_IPLDEV = subchannel_id;
|
|
*(unsigned int *)IPL_DEVICE = subchannel_id;
|
|
|
|
/* if valid command line is given, copy it into new kernel space */
|
|
if (_parm_addr != UNSPECIFIED_ADDRESS) {
|
|
memcpy((void *)COMMAND_LINE,
|
|
(void *)(unsigned long *)_parm_addr, COMMAND_LINE_SIZE);
|
|
/* terminate \0 */
|
|
*(char *)(COMMAND_LINE + COMMAND_LINE_SIZE - 1) = 0;
|
|
}
|
|
|
|
/* convert extra parameter to ascii */
|
|
if (!_extra_parm || !*cextra)
|
|
goto noextra;
|
|
|
|
/* Handle extra kernel parameters specified in DASD boot menu. */
|
|
ebcdic_to_ascii(cextra, cextra, COMMAND_LINE_SIZE);
|
|
|
|
/* remove leading whitespace */
|
|
while (begin <= COMMAND_LINE_SIZE && cextra[begin] == 0x20)
|
|
begin++;
|
|
|
|
/* determine length of extra parameter */
|
|
while (length <= COMMAND_LINE_SIZE && cextra[length] != 0)
|
|
length++;
|
|
|
|
/* find end of original parm line */
|
|
while (command_line[end] != 0)
|
|
end++;
|
|
|
|
/*
|
|
* if extra parm string starts with '=' replace original string,
|
|
* else append
|
|
*/
|
|
if (cextra[begin] == 0x3d) {
|
|
memcpy((void *)COMMAND_LINE, (void *)(cextra + begin),
|
|
length);
|
|
} else {
|
|
/* check if length is within max value */
|
|
length = (end + 1 + length <= COMMAND_LINE_SIZE) ? length :
|
|
(COMMAND_LINE_SIZE - end - 1);
|
|
/* add blank */
|
|
command_line[end] = 0x20;
|
|
end++;
|
|
/* append string */
|
|
memcpy((void *)(command_line + end),
|
|
(void *)(cextra + begin), length);
|
|
/* terminate 0 */
|
|
command_line[end + length] = 0;
|
|
}
|
|
|
|
noextra:
|
|
/* copy initrd start address and size intop new kernle space */
|
|
*(unsigned long long *)INITRD_START = _initrd_addr;
|
|
*(unsigned long long *)INITRD_SIZE = _initrd_len;
|
|
|
|
/* store address of new kernel to 0 to be able to start it */
|
|
*(unsigned long long *)0 = _load_psw;
|
|
|
|
kdump_stage3();
|
|
|
|
/* start new kernel */
|
|
start_kernel();
|
|
}
|
|
|
|
void panic_notify(unsigned long UNUSED(rc))
|
|
{
|
|
}
|