mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
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:
committed by
Jan Höppner
parent
e764f460c4
commit
6825645a21
+5
-5
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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, ¶ms, sizeof(struct boot_stage3_params));
|
||||
memcpy(data, ¶ms, sizeof(params));
|
||||
*buffer = data;
|
||||
*bytecount = DATA_SIZE(stage3);
|
||||
*bytecount = sizeof(params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+34
-18
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user