Files
s390-tools/zipl/src/zipl.c
Eduard Shishkin f7d2339c6a zipl: List-Directed IPL from ECKD DASD
Make zipl tool prepare ECKD DASD for booting by different IPL
programs (with the same boot record installed).

Besides standard CCW-type IPL, user gets an ability to trigger
(with the same boot record installed!) List-Directed IPL. This
allows to use the feature of secure boot from ECKD DASD (which
is not available for CCW-type IPL).

When using the old boot interfaces, the usual CCW-type IPL is
triggered for DASD. Also for compatibility reasons zipl(8) tool
is modified to create and install one, or two "similar" program
tables per boot partition, depending on job and disk type. The
"similar" program tables differ only in block pointers format.
The old IPL programs (CCW-type IPL) use program table based on the
old format.

All program tables are packed to the same bootmap file. Their
order and logical offsets in the file are not significant (not
used by anyone).

The picture below shows which program table is used for IPL of
specified type from disk of specified type. Here "0" and "1" are
identifiers of program tables based on the old and new block
pointers format respectively. E.g. program table "0" is used for
CCW-type IPL from ECKD DASD. LD-IPL from DASD FBA is unsupported
(respectively, only one program table "0" is used), etc.

                            CCW-IPL   LD-IPL

 SCSI                          X        0
 DASD FBA                      0        X
 ECKD DASD LDL                 0        X
 ECKD DASD CDL                 0        1

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-29 17:03:57 +01:00

295 lines
8.2 KiB
C

/*
* zipl - zSeries Initial Program Loader tool
*
* Main function
*
* Copyright IBM Corp. 2001, 2017
*
* 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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "lib/zt_common.h"
#include "boot.h"
#include "bootmap.h"
#include "disk.h"
#include "error.h"
#include "install.h"
#include "job.h"
#include "misc.h"
#include "zipl.h"
/* Flag deciding the level of verbosity */
int verbose = 0;
/* Flag deciding whether confirmation questions are asked */
int interactive = 1;
/* Flag deciding whether actions should only be simulated */
int dry_run = 1;
/* Full tool name */
static const char tool_name[] = "zipl: zSeries Initial Program Loader";
/* Copyright notice */
static const char copyright_notice[] = "Copyright IBM Corp. 2001, 2017";
/* Usage information */
static const char* usage_text[] = {
"Usage: zipl [OPTIONS] [SECTION]",
"",
"Prepare a device for initial program load. Use OPTIONS described below or ",
"provide the name of a SECTION defined in the zIPL configuration file.",
"",
"-h, --help Print this help, then exit",
"-v, --version Print version information, then exit",
"-c, --config CONFIGFILE Read configuration from CONFIGFILE",
"-b, --blsdir BLSDIR Parse BootLoaderSpec files from BLSDIR",
"-t, --target TARGETDIR Write bootmap file to TARGETDIR and install",
" bootloader on device containing TARGETDIR",
" --targetbase BASEDEVICE Install bootloader on BASEDEVICE",
" --targettype TYPE Use device type: CDL, LDL, FBA, SCSI",
" --targetgeometry C,H,S Use disk geometry: cylinders,heads,sectors",
" --targetblocksize SIZE Use number of bytes per block",
" --targetoffset OFFSET Use offset between logical and physical disk",
"-i, --image IMAGEFILE[,ADDR] Install Linux kernel image from IMAGEFILE",
"-r, --ramdisk RAMDISK[,ADDR] Install initial ramdisk from file RAMDISK",
"-p, --parmfile PARMFILE[,ADDR] Use kernel parmline stored in PARMFILE",
"-P, --parameters PARMLINE Use specified kernel PARMLINE",
"-T, --tape TAPEDEV Install bootloader on tape device TAPEDEV",
"-s, --segment SEGMENT,ADDR Install a segment from file SEGMENT",
"-k, --kdump=auto Install a kdump kernel that can be used as a",
" stand-alone dump tool",
"-d, --dumpto DUMPDEV[,SIZE] Install a system dump record on tape device",
" or disk partition DUMPDEV",
"-M, --mvdump DEVLIST[,SIZE] Install a multi-volume dump record on each",
" disk partition listed in file DEVLIST",
"-f, --force Disable sanity check while producing a",
" multi-volume dump",
"-m, --menu MENU Install multi-boot configuration MENU",
"-n, --noninteractive Answer all confirmation questions with 'yes'",
"-V, --verbose Provide more verbose output",
"-a, --add-files Add all referenced files to bootmap file",
" --dry-run Simulate run but don't modify IPL records",
"-S, --secure SWITCH Control the zIPL secure boot support.",
" auto (default):",
" Write signatures if available and supported",
" 1: Write signatures regardless of support",
" 0: Do not write signatures"
};
/* Print usage information. */
static void
print_usage(void)
{
unsigned int i;
for (i=0; i < ARRAY_SIZE(usage_text); i++)
printf("%s\n", usage_text[i]);
}
/* Print version information. */
static void
print_version(void)
{
printf("%s version %s\n", tool_name, RELEASE_STRING);
printf("%s\n", copyright_notice);
}
/* Check whether calling user is root. Return 0 if user is root, non-zero
* otherwise. */
static int
check_for_root(void)
{
if (geteuid() != 0) {
error_clear_text();
error_reason("Must be root to perform this operation");
return -1;
} else
return 0;
}
int
main(int argc, char* argv[])
{
struct install_set bis;
struct job_data* job;
int rc;
/* Check internals */
rc = boot_check_data();
if (rc) {
error_text("Internal error");
error_print();
return 1;
}
/* Find out what we're supposed to do */
rc = job_get(argc, argv, &job);
if (rc) {
error_print();
return 1;
}
/* Check for priority options --help and --version */
if (job->id == job_print_usage) {
print_usage();
job_free(job);
return 0;
} else if (job->id == job_print_version) {
print_version();
job_free(job);
return 0;
}
/* Make sure we're running as root */
if (check_for_root()) {
job_free(job);
error_print();
return 1;
}
/* Set global option variables */
verbose = job->verbose;
interactive = !job->noninteractive;
dry_run = job->dry_run;
if (dry_run)
printf("Starting dry-run, target device contents will NOT be "
"modified\n");
/* Make sure new files are only user-accessible */
umask(077);
/* Do it */
switch (job->id) {
case job_dump_partition:
if (disk_is_tape(job->data.dump.device) ||
!disk_is_scsi(job->data.dump.device, &job->target)) {
rc = install_dump(job->data.dump.device, &job->target,
job->data.dump.mem);
break;
}
/* Dump to a raw SCSI partition */
if (job->data.dump.mem != -1uLL) {
error_reason("Dump size can not be limited for "
"partition dump on a SCSI disk");
rc = -1;
break;
}
if (is_ngdump_enabled(job->data.dump.device, &job->target))
rc = check_job_images_ngdump(&job->data.dump, job->name);
else
rc = check_job_dump_images(&job->data.dump, job->name);
if (rc != 0)
break;
/* Fall through. */
case job_ipl:
case job_segment:
case job_menu:
rc = prepare_bootloader(job, &bis);
if (rc)
break;
rc = install_bootloader(job, &bis);
free_bootloader(&bis);
break;
case job_ipl_tape:
rc = install_tapeloader(job->data.ipl_tape.device,
job->data.ipl_tape.common.image,
job->data.ipl_tape.common.parmline,
job->data.ipl_tape.common.ramdisk,
job->data.ipl_tape.common.image_addr,
job->data.ipl_tape.common.parm_addr,
job->data.ipl_tape.common.ramdisk_addr);
break;
case job_mvdump:
rc = install_mvdump(job->data.mvdump.device,
&job->target,
job->data.mvdump.device_count,
job->data.mvdump.mem,
job->data.mvdump.force);
break;
case job_print_usage:
case job_print_version:
/* Should not happen */
break;
}
switch (rc) {
case 0: /* Operation completed successfully */
if (verbose)
printf("Syncing disks...\n");
if (!dry_run)
sync();
printf("Done.\n");
break;
case -2: /* Operation canceled by user */
break;
default: /* An error occurred */
error_print();
break;
}
job_free(job);
return abs(rc);
}
/**
* Program Component Footers
*/
struct component_footer component_footers[NR_PROGRAM_COMPONENTS] = {
[COMPONENT_ID_HEAP_AREA] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "heap area"
},
[COMPONENT_ID_STACK_AREA] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "stack area"
},
[COMPONENT_ID_LOADER_SIGNATURE] = {
.type = COMPONENT_TYPE_SIGNATURE,
.desc = "loader signature"
},
[COMPONENT_ID_LOADER] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "internal loader"
},
[COMPONENT_ID_PARAMETERS] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "parameters"
},
[COMPONENT_ID_IMAGE_SIGNATURE] = {
.type = COMPONENT_TYPE_SIGNATURE,
.desc = "image signature"
},
[COMPONENT_ID_KERNEL_IMAGE] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "kernel image"
},
[COMPONENT_ID_PARMLINE] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "parmline"
},
[COMPONENT_ID_RAMDISK_SIGNATURE] = {
.type = COMPONENT_TYPE_SIGNATURE,
.desc = "ramdisk signature"
},
[COMPONENT_ID_RAMDISK] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "initial ramdisk"
},
[COMPONENT_ID_ENVBLK] = {
.type = COMPONENT_TYPE_LOAD,
.desc = "environment blk"
},
[COMPONENT_ID_SEGMENT_FILE] = {
.type = COMPONENT_TYPE_EXECUTE,
.desc = "segment file"
}
};