zipl: Move stage 3 loader to external file

The first component that gets control after IPL is the zIPL-provided
stage 3 boot loader. This boot loader is based on a binary image linked
into the zIPL executable. When preparing a disk for IPL, zIPL updates
runtime parameters in the boot loader image and writes the resulting
data to disk.

To support the Secure Boot firmware feature, the stage 3 code must be
signed, and can therefore no longer contain variable parameter portions.
Also the boot loader image should be accessible as a separate file to
enable the use of external programs for creating the signature.

This patch moves the stage 3 boot loader code to an external file
location and splits out the parameter portion into a separate, unsigned
on-disk component.

The new memory layout of the stage 3 loader during its execution looks
as follows:

 * 0x0000-0x1fff        Lowcore
 * 0x2000-0x5fff        Memory allocation (heap)
 * 0x7000-0x8fff        free
 * 0x9000-0x9fff        Stage3 parameter
 * 0xa000-0xcfff        Stage3 code
 * 0xd000-0xefff        Section: bss, rodata, data
 * 0xf000-0xffff        Stack

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>
This commit is contained in:
Stefan Haberland
2019-04-15 18:08:44 +02:00
committed by Jan Höppner
parent e764f460c4
commit 6825645a21
9 changed files with 93 additions and 100 deletions
+5 -5
View File
@@ -13,10 +13,9 @@ FILES = fba0.bin fba1b.bin fba2.bin \
eckd0_ldl.bin eckd0_cdl.bin \
eckd1.bin eckd1b.bin eckd2.bin \
tape0.bin \
eckd2dump_sv.bin tape2dump.bin fba2dump.bin eckd2dump_mv.bin \
stage3.bin
eckd2dump_sv.bin tape2dump.bin fba2dump.bin eckd2dump_mv.bin
all: data.o data.h tape0.bin
all: data.o data.h tape0.bin stage3.bin
# Prevent make from using some default rules...
%: %.S
@@ -44,7 +43,7 @@ eckd2.exec: head.o stage2.o cio.o eckd2.o libc.o menu.o sclp.o \
fba2.exec: head.o stage2.o cio.o fba2.o libc.o menu.o sclp.o \
kdump2.o kdump.o entry.o
stage3.exec: head.o stage3.o kdump3.o libc.o sclp.o sclp_stage3.o \
kdump.o entry.o
kdump.o entry.o stage3.lds
%.exec: %.o
@STAGE=$$( \
@@ -87,6 +86,7 @@ data.h: data.o
echo "extern char $$SYMBOL;" >>data.h; done
clean:
rm -f *.o *.exec *.bin $(FILES) data.o data.h tape0.bin *.xxx *.yyy
rm -f *.o *.exec *.bin $(FILES) data.o data.h tape0.bin *.xxx *.yyy \
stage3.bin
.PHONY: all clean
+3 -2
View File
@@ -9,7 +9,8 @@
* 0x2000-0x4fff Sections (load): head, text, data, rodata, rodata.str
* 0x5000-0x51ff eckd2dump_mv parameter block (426 bytes)
* 0x5200-0x5fff Sections: bss
* 0x6000-0x9fff Memory allocation (heap)
* 0x6000-0x8fff Memory allocation (heap)
* 0x9000-0x9fff Memory to load stage3 parameter to
* 0xa000-0xdfff Memory to load stage3 to
* 0xe000-0xffff Stack
*
@@ -52,7 +53,7 @@ SECTIONS
. = 0x6000;
__heap_start = .;
. = 0xa000;
. = 0x9000;
__heap_stop = .;
. = 0xf000;
-35
View File
@@ -13,41 +13,6 @@
#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,
+23 -16
View File
@@ -1,38 +1,47 @@
/*
* Memory layout for stage 3
* =========================
*
* General memory layout
* ---------------------
*
* 0x0000-0x1fff Lowcore
* 0x2000-0x5fff Memory allocation (heap)
* 0x6000-0x8fff free
* 0x9000-0x9fff Stage3 parameter
* 0xa000-0xdfff Stage3 code + data
* 0xe000-0xffff Stack
*/
SECTIONS
{
. = 0x0;
. = 0x7000;
. = 0x2000;
__heap_start = .;
. = 0xa000;
. = 0x6000;
__heap_stop = .;
. = 0xa000;
/* stage 3 parameter */
. = 0x9000;
_parm_addr = .;
. = 0xa008;
. = 0x9008;
_initrd_addr = .;
. = 0xa010;
. = 0x9010;
_initrd_len = .;
. = 0xa018;
. = 0x9018;
_load_psw = .;
. = 0xa020;
. = 0x9020;
_extra_parm = .;
. = 0xa028;
. = 0x9028;
stage3_flags =.;
. = 0xa030;
. = 0x9030;
_image_len = .;
. = 0xa038;
. = 0x9038;
_image_addr = .;
. = 0xa000;
.text.dummy : { *(.text.dummy) }
. = 0xa050;
.text.start : { *(.text.start) }
.text : { *(.text) }
__ex_table_start = .;
@@ -40,11 +49,9 @@ SECTIONS
__ex_table_stop = .;
.eh_frame : { *(.eh_frame) }
. = 0xc000;
__bss_start = .;
.bss : { *(.bss) }
__bss_stop = .;
.rodata : {*(.rodata) }
.data : { *(.data) }
}
+4 -5
View File
@@ -308,11 +308,10 @@ int boot_init_fba_stage1b(struct boot_fba_stage1b *stage1b,
disk_blockptr_t *stage2_list,
blocknum_t stage2_count);
int boot_get_eckd_stage2(void** data, size_t* size, struct job_data* job);
size_t get_stage3_size();
int boot_get_stage3(void** buffer, size_t* bytecount, address_t parm_addr,
address_t initrd_addr, size_t initrd_len,
address_t image_addr, int extra_parm, uint16_t flags,
size_t image_len);
int boot_get_stage3_parms(void **buffer, size_t *bytecount, address_t parm_addr,
address_t initrd_addr, size_t initrd_len,
address_t load_addr, int extra_parm, uint16_t flags,
size_t image_len);
int boot_get_tape_ipl(void** data, size_t* size, address_t parm_addr,
address_t initrd_addr, address_t image_addr);
int boot_get_tape_dump(void** data, size_t* size, uint64_t mem);
+3 -1
View File
@@ -20,10 +20,11 @@
#define DISK_LAYOUT_ID 0x00000001
#define ZIPL_STAGE2_LOAD_ADDRESS 0x2000
#define ZIPL_STAGE3_ENTRY_ADDRESS 0xa050LL
#define ZIPL_STAGE3_ENTRY_ADDRESS 0xa000LL
#define DEFAULT_IMAGE_ADDRESS 0x10000LL
#define KDUMP_IMAGE_ADDRESS 0x10010LL
#define DEFAULT_STAGE3_ADDRESS 0xa000LL
#define DEFAULT_STAGE3_PARAMS_ADDRESS 0x9000LL
#define MINIMUM_ADDRESS 0x10000LL
#define ADDRESS_LIMIT 0x80000000LL
#define ADDRESS_LIMIT_KDUMP 0x2000000UL /* HSA size: 32 MiB */
@@ -43,6 +44,7 @@
#define ZIPL_CONF_VAR "ZIPLCONF"
#define ZIPL_DEFAULT_CONF "/etc/zipl.conf"
#define ZIPL_DEFAULT_BLSDIR "/boot/loader/entries"
#define ZIPL_STAGE3_PATH TOOLS_LIBDIR "/stage3.bin"
#define MENU_DEFAULT_PROMPT 0
#define MENU_DEFAULT_TIMEOUT 0
+6 -1
View File
@@ -15,8 +15,9 @@ objects = misc.o error.o scan.o job.o boot.o bootmap.o disk.o \
zipl_helpers = $(basename $(wildcard zipl_helper.*.c))
chreipl_helpers = $(subst zipl_,chreipl_, $(zipl_helpers))
zipl_stage3 = ../boot/stage3.bin
all: zipl $(chreipl_helpers)
all: zipl $(chreipl_helpers) $(zipl_stage3)
zipl: $(objects) $(libs)
@@ -33,6 +34,7 @@ install: all
$(INSTALL) -m 755 $(zipl_helpers) $(chreipl_helpers) \
$(DESTDIR)$(TOOLS_LIBDIR)
$(CP) --no-dereference $(chreipl_helpers) $(DESTDIR)$(TOOLS_LIBDIR)
$(CP) --no-dereference $(zipl_stage3) $(DESTDIR)$(TOOLS_LIBDIR)
clean:
rm -f *.o $(zipl_helpers) $(chreipl_helpers) zipl
@@ -48,3 +50,6 @@ clean:
../boot/data.o:
make -C ../boot data.o
../boot/stage3.bin:
make -C ../boot stage3.bin
+15 -17
View File
@@ -14,6 +14,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "../boot/data.h"
#include "boot.h"
@@ -68,20 +70,17 @@ boot_check_data(void)
return 0;
}
/* Export stage 3 size for partition dump with dump kernel */
size_t
get_stage3_size()
{
return DATA_SIZE(stage3);
}
/* Create a stage 3 loader in memory.
/*
* Create a stage 3 parameter block in memory.
* Upon success, return 0 and set BUFFER to point to the data buffer and set
* BYTECOUNT to contain the loader size in bytes. Return non-zero otherwise. */
* BYTECOUNT to contain the parameter block size in bytes.
* Return non-zero otherwise.
*/
int
boot_get_stage3(void** buffer, size_t* bytecount, address_t parm_addr,
address_t initrd_addr, size_t initrd_len, address_t image_addr,
int extra_parm, uint16_t flags, size_t image_len)
boot_get_stage3_parms(void **buffer, size_t *bytecount, address_t parm_addr,
address_t initrd_addr, size_t initrd_len,
address_t image_addr, int extra_parm, uint16_t flags,
size_t image_len)
{
struct boot_stage3_params params;
void* data;
@@ -92,10 +91,10 @@ boot_get_stage3(void** buffer, size_t* bytecount, address_t parm_addr,
return -1;
}
/* Get memory */
data = misc_malloc(DATA_SIZE(stage3));
data = misc_malloc(sizeof(params));
if (data == NULL)
return -1;
memset(data, 0, DATA_SIZE(stage3));
memset(data, 0, sizeof(params));
/* Prepare params section */
params.parm_addr = (uint64_t) parm_addr;
params.initrd_addr = (uint64_t) initrd_addr;
@@ -106,10 +105,9 @@ boot_get_stage3(void** buffer, size_t* bytecount, address_t parm_addr,
params.image_len = (uint64_t) image_len;
params.image_addr = (uint64_t) image_addr;
/* Initialize buffer */
memcpy(data, DATA_ADDR(stage3), DATA_SIZE(stage3));
memcpy(data, &params, sizeof(struct boot_stage3_params));
memcpy(data, &params, sizeof(params));
*buffer = data;
*bytecount = DATA_SIZE(stage3);
*bytecount = sizeof(params);
return 0;
}
+34 -18
View File
@@ -416,11 +416,12 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
{
struct stat stats;
void* table;
void* stage3;
size_t stage3_size;
const char *comp_name[4] = {"kernel image", "parmline",
"initial ramdisk", "internal loader"};
struct component_loc comp_loc[4];
void *stage3_params;
size_t stage3_params_size;
const char *comp_name[5] = {"kernel image", "parmline",
"initial ramdisk", "internal loader",
"parameters"};
struct component_loc comp_loc[5];
int rc;
int offset, flags = 0;
size_t ramdisk_size, image_size;
@@ -473,22 +474,35 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
image_size = stats.st_size;
/* Add stage 3 loader to bootmap */
rc = boot_get_stage3(&stage3, &stage3_size, ipl->parm_addr,
ipl->ramdisk_addr, ramdisk_size,
ipl->is_kdump ? ipl->image_addr + 0x10 :
ipl->image_addr,
(info->type == disk_type_scsi) ? 0 : 1,
flags, image_size);
rc = add_component_file(fd, ZIPL_STAGE3_PATH, DEFAULT_STAGE3_ADDRESS, 0,
VOID_ADD(table, offset), 1, info, target,
&comp_loc[3]);
if (rc) {
error_text("Could not add internal loader file '%s'",
ZIPL_STAGE3_PATH);
free(table);
return rc;
}
offset += sizeof(struct component_entry);
/* Add stage 3 parameter to bootmap */
rc = boot_get_stage3_parms(&stage3_params, &stage3_params_size,
ipl->parm_addr, ipl->ramdisk_addr,
ramdisk_size,
ipl->is_kdump ? ipl->image_addr + 0x10 :
ipl->image_addr,
(info->type == disk_type_scsi) ? 0 : 1,
flags, image_size);
if (rc) {
free(table);
return rc;
}
rc = add_component_buffer(fd, stage3, stage3_size,
DEFAULT_STAGE3_ADDRESS,
VOID_ADD(table, offset), info, &comp_loc[3]);
free(stage3);
rc = add_component_buffer(fd, stage3_params, stage3_params_size,
DEFAULT_STAGE3_PARAMS_ADDRESS,
VOID_ADD(table, offset), info, &comp_loc[4]);
free(stage3_params);
if (rc) {
error_text("Could not add stage 3 boot loader");
error_text("Could not add parameters");
free(table);
return -1;
}
@@ -540,7 +554,7 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program,
offset += sizeof(struct component_entry);
}
if (verbose)
print_components(comp_name, comp_loc, 4);
print_components(comp_name, comp_loc, ARRAY_SIZE(comp_name));
/* Terminate component table */
create_component_entry(VOID_ADD(table, offset), NULL,
component_execute,
@@ -924,7 +938,9 @@ bootmap_create(struct job_data *job, disk_blockptr_t *program_table,
ulong size;
ulong unused_size;
size = DIV_ROUND_UP(get_stage3_size(), info->phy_block_size);
/* Use approximated stage 3 size as starting point */
size = MINIMUM_ADDRESS;
/* Ramdisk */
if (job->data.dump.ramdisk != NULL) {
if (stat(job->data.dump.ramdisk, &st))