Files
s390-tools/zipl/src/zipl.c
T
Alexander Egorenkov 2b015183aa zipl: Implement NGDump
This commit finalizes the implementation of the new stand-alone dump -
Next Gen Dump (NGDump).

NGDump stand-alone dump is a universal stand-alone dump which works for both
SCSI and NVMe disks. But currently can be used only with NVMe disks
and SCSI stand-alone dump remains the default for SCSI disks.

Currently, this stand-alone dump can be used only on IBM z15 or newer
machine generations because it requires larger amount of HSA memory offered
by firmware only on IBM z15 machines. Whereas SCSI stand-alone dump is able
to work with HSA memory of 32M, the new stand-alone dump requires 512M HSA
memory at the moment.

NGDump stand-alone dump installation is initiated by passing a path to
a NVMe disk partition to zipl via the command-line -d, similar to SCSI
stand-alone dump. zipl will then:
- build a dumper initramfs with either dracut (Fedora/RHEL/SLES) or
  initramfs-tools (Ubuntu/Debian)
- format the given NVMe partition with ext4 file system
- create a bootmap file on the newly created file system using the built
  initramfs and the currently active kernel image
- install a boot loader on the disk the given dump partition belongs to

The operations described above are destructive for the given NVMe dump
partition and the boot record(s) of its disk.

After the installation step, users can configure the dumpconf to IPL
the dumper automatically on panic or trigger a dump manually via HMC
interface.

When activated, the dumper will create a dump ELF file named "dump.elf"
on the given NVMe dump partition by using the makedumpfile tool. The kdump
compressed file format is not supported yet due to zgetdump not being able
to read such a file format. Therefore, the dumper is restricted to write
the dump only in ELF format but only kernel pages which are in use.
This will usually make the dump smaller than the original size of
/proc/vmcore and the whole dump process faster as well.

Example configuration for dumpconf:

ON_PANIC=dump   # or dump_reipl
DUMP_TYPE=nvme
FID=0x00000001
NSID=0x00000001
BOOTPROG=0
BR_LBA=0

$ systemctl enable --now dumpconf

To install the dracut support on Fedora/RHEL/SUSE:

$ make -C zipl/dracut HAVE_DRACUT=1 install

To install the initramfs-tools support on Ubuntu/Debian:

$ make -C zipl/initramfs-tools HAVE_INITRAMFS=1 install

Example of NGDump console output on SLES during dump
----------------------------------------------------

         Starting NGDump...
[    8.932343] ngdump.sh[327]: NGDump started
[    8.934739] ngdump.sh[336]: Checking for memory holes                         : [  0.0 %] /
[    8.967536] ngdump.sh[336]: Checking for memory holes                         : [100.0 %] |
[    9.076976] ngdump.sh[336]: Excluding unnecessary pages                       : [100.0 %] \
[   11.721157] ngdump.sh[336]: Copying data                                      : [  0.0 %] -
[   12.317319] ngdump.sh[336]: Copying data                                      : [ 22.5 %] /           eta: 2s
[   13.273000] ngdump.sh[336]: Copying data                                      : [100.0 %] |           eta: 0s
[   13.273244] ngdump.sh[336]: The kernel version is not supported.
[   13.273263] ngdump.sh[336]: The makedumpfile operation may be incomplete.
[   13.273281] ngdump.sh[336]: The dumpfile is saved to /ngdump/dump.elf.
[   13.273299] ngdump.sh[336]: makedumpfile Completed.

Example of NGDump console output on Ubuntu during dump
-------------------------------------------------------

[    3.240078] zdump: The dump process started for a 64-bit operating system
Loading, please wait...
Starting version 245.4-4ubuntu3.17
Begin: Starting firmware auto-configuration ... done.
Begin: Loading essential drivers ... done.
Begin: Running /scripts/init-premount ...
Begin: NGDump ...
Checking for memory holes                         : [  0.0 %] /
Checking for memory holes                         : [100.0 %] |
Excluding unnecessary pages                       : [100.0 %] \
Copying data                                      : [  0.0 %] -
Copying data                                      : [ 40.7 %] /           eta: 1s
Copying data                                      : [100.0 %] |           eta: 0s
The kernel version is not supported.
The makedumpfile operation may be incomplete.
The dumpfile is saved to /ngdump/dump.elf.
makedumpfile Completed.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Tested-by: Alexander Gordeev <agordeev@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Tested-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00

254 lines
7.4 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 disk_info* info;
disk_blockptr_t program_table, scsi_dump_sb_blockptr, *stage1b_list;
blocknum_t stage1b_count;
struct job_data* job;
char* device;
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:
/* Create bootmap */
stage1b_list = NULL;
rc = bootmap_create(job, &program_table, &scsi_dump_sb_blockptr,
&stage1b_list, &stage1b_count, &device,
&info);
if (rc)
break;
/* Install boot loader */
rc = install_bootloader(device, &program_table,
&scsi_dump_sb_blockptr, stage1b_list,
stage1b_count, info, job);
if (stage1b_list != NULL)
free(stage1b_list);
misc_free_temp_dev(device);
disk_free_info(info);
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);
}