linux-stable/arch/s390/boot/ipl_parm.c
Linus Torvalds d590284419 s390 updates for the 5.4 merge window
- Add support for IBM z15 machines.
 
 - Add SHA3 and CCA AES cipher key support in zcrypt and pkey refactoring.
 
 - Move to arch_stack_walk infrastructure for the stack unwinder.
 
 - Various kasan fixes and improvements.
 
 - Various command line parsing fixes.
 
 - Improve decompressor phase debuggability.
 
 - Lift no bss usage restriction for the early code.
 
 - Use refcount_t for reference counters for couple of places in
   mm code.
 
 - Logging improvements and return code fix in vfio-ccw code.
 
 - Couple of zpci fixes and minor refactoring.
 
 - Remove some outdated documentation.
 
 - Fix secure boot detection.
 
 - Other various minor code clean ups.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEE3QHqV+H2a8xAv27vjYWKoQLXFBgFAl1/pRoACgkQjYWKoQLX
 FBjxLQf/Y1nlmoc8URLqaqfNTczIvUzdfXuahI7L75RoIIiqHtcHBrVwauSr7Lma
 XVRzK/+6q0UPISrOIZEEtQKsMMM7rGuUv/+XTyrOB/Tsc31kN2EIRXltfXI/lkb8
 BZdgch4Xs2rOD7y6TvqpYJsXYXsnLMWwCk8V+48V/pok4sEgMDgh0bTQRHPHYmZ6
 1cv8ZQ0AeuVxC6ChM30LhajGRPkYd8RQ82K7fU7jxT0Tjzu66SyrW3pTwA5empBD
 RI2yBZJ8EXwJyTCpvN8NKiBgihDs9oUZl61Dyq3j64Mb1OuNUhxXA/8jmtnGn0ok
 O9vtImCWzExhjSMkvotuhHEC05nEEQ==
 =LCgE
 -----END PGP SIGNATURE-----

Merge tag 's390-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 updates from Vasily Gorbik:

 - Add support for IBM z15 machines.

 - Add SHA3 and CCA AES cipher key support in zcrypt and pkey
   refactoring.

 - Move to arch_stack_walk infrastructure for the stack unwinder.

 - Various kasan fixes and improvements.

 - Various command line parsing fixes.

 - Improve decompressor phase debuggability.

 - Lift no bss usage restriction for the early code.

 - Use refcount_t for reference counters for couple of places in mm
   code.

 - Logging improvements and return code fix in vfio-ccw code.

 - Couple of zpci fixes and minor refactoring.

 - Remove some outdated documentation.

 - Fix secure boot detection.

 - Other various minor code clean ups.

* tag 's390-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (48 commits)
  s390: remove pointless drivers-y in drivers/s390/Makefile
  s390/cpum_sf: Fix line length and format string
  s390/pci: fix MSI message data
  s390: add support for IBM z15 machines
  s390/crypto: Support for SHA3 via CPACF (MSA6)
  s390/startup: add pgm check info printing
  s390/crypto: xts-aes-s390 fix extra run-time crypto self tests finding
  vfio-ccw: fix error return code in vfio_ccw_sch_init()
  s390: vfio-ap: fix warning reset not completed
  s390/base: remove unused s390_base_mcck_handler
  s390/sclp: Fix bit checked for has_sipl
  s390/zcrypt: fix wrong handling of cca cipher keygenflags
  s390/kasan: add kdump support
  s390/setup: avoid using strncmp with hardcoded length
  s390/sclp: avoid using strncmp with hardcoded length
  s390/module: avoid using strncmp with hardcoded length
  s390/pci: avoid using strncmp with hardcoded length
  s390/kaslr: reserve memory for kasan usage
  s390/mem_detect: provide single get_mem_detect_end
  s390/cmma: reuse kstrtobool for option value parsing
  ...
2019-09-17 14:04:43 -07:00

259 lines
5.7 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ctype.h>
#include <asm/ebcdic.h>
#include <asm/sclp.h>
#include <asm/sections.h>
#include <asm/boot_data.h>
#include <asm/facility.h>
#include <asm/pgtable.h>
#include <asm/uv.h>
#include "boot.h"
char __bootdata(early_command_line)[COMMAND_LINE_SIZE];
struct ipl_parameter_block __bootdata_preserved(ipl_block);
int __bootdata_preserved(ipl_block_valid);
unsigned long __bootdata(vmalloc_size) = VMALLOC_DEFAULT_SIZE;
unsigned long __bootdata(memory_end);
int __bootdata(memory_end_set);
int __bootdata(noexec_disabled);
int kaslr_enabled __section(.data);
static inline int __diag308(unsigned long subcode, void *addr)
{
register unsigned long _addr asm("0") = (unsigned long)addr;
register unsigned long _rc asm("1") = 0;
unsigned long reg1, reg2;
psw_t old = S390_lowcore.program_new_psw;
asm volatile(
" epsw %0,%1\n"
" st %0,%[psw_pgm]\n"
" st %1,%[psw_pgm]+4\n"
" larl %0,1f\n"
" stg %0,%[psw_pgm]+8\n"
" diag %[addr],%[subcode],0x308\n"
"1: nopr %%r7\n"
: "=&d" (reg1), "=&a" (reg2),
[psw_pgm] "=Q" (S390_lowcore.program_new_psw),
[addr] "+d" (_addr), "+d" (_rc)
: [subcode] "d" (subcode)
: "cc", "memory");
S390_lowcore.program_new_psw = old;
return _rc;
}
void store_ipl_parmblock(void)
{
int rc;
rc = __diag308(DIAG308_STORE, &ipl_block);
if (rc == DIAG308_RC_OK &&
ipl_block.hdr.version <= IPL_MAX_SUPPORTED_VERSION)
ipl_block_valid = 1;
}
static size_t scpdata_length(const u8 *buf, size_t count)
{
while (count) {
if (buf[count - 1] != '\0' && buf[count - 1] != ' ')
break;
count--;
}
return count;
}
static size_t ipl_block_get_ascii_scpdata(char *dest, size_t size,
const struct ipl_parameter_block *ipb)
{
size_t count;
size_t i;
int has_lowercase;
count = min(size - 1, scpdata_length(ipb->fcp.scp_data,
ipb->fcp.scp_data_len));
if (!count)
goto out;
has_lowercase = 0;
for (i = 0; i < count; i++) {
if (!isascii(ipb->fcp.scp_data[i])) {
count = 0;
goto out;
}
if (!has_lowercase && islower(ipb->fcp.scp_data[i]))
has_lowercase = 1;
}
if (has_lowercase)
memcpy(dest, ipb->fcp.scp_data, count);
else
for (i = 0; i < count; i++)
dest[i] = tolower(ipb->fcp.scp_data[i]);
out:
dest[count] = '\0';
return count;
}
static void append_ipl_block_parm(void)
{
char *parm, *delim;
size_t len, rc = 0;
len = strlen(early_command_line);
delim = early_command_line + len; /* '\0' character position */
parm = early_command_line + len + 1; /* append right after '\0' */
switch (ipl_block.pb0_hdr.pbt) {
case IPL_PBT_CCW:
rc = ipl_block_get_ascii_vmparm(
parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
break;
case IPL_PBT_FCP:
rc = ipl_block_get_ascii_scpdata(
parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
break;
}
if (rc) {
if (*parm == '=')
memmove(early_command_line, parm + 1, rc);
else
*delim = ' '; /* replace '\0' with space */
}
}
static inline int has_ebcdic_char(const char *str)
{
int i;
for (i = 0; str[i]; i++)
if (str[i] & 0x80)
return 1;
return 0;
}
void setup_boot_command_line(void)
{
COMMAND_LINE[ARCH_COMMAND_LINE_SIZE - 1] = 0;
/* convert arch command line to ascii if necessary */
if (has_ebcdic_char(COMMAND_LINE))
EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE);
/* copy arch command line */
strcpy(early_command_line, strim(COMMAND_LINE));
/* append IPL PARM data to the boot command line */
if (!is_prot_virt_guest() && ipl_block_valid)
append_ipl_block_parm();
}
static void modify_facility(unsigned long nr, bool clear)
{
if (clear)
__clear_facility(nr, S390_lowcore.stfle_fac_list);
else
__set_facility(nr, S390_lowcore.stfle_fac_list);
}
static void check_cleared_facilities(void)
{
unsigned long als[] = { FACILITIES_ALS };
int i;
for (i = 0; i < ARRAY_SIZE(als); i++) {
if ((S390_lowcore.stfle_fac_list[i] & als[i]) != als[i]) {
sclp_early_printk("Warning: The Linux kernel requires facilities cleared via command line option\n");
print_missing_facilities();
break;
}
}
}
static void modify_fac_list(char *str)
{
unsigned long val, endval;
char *endp;
bool clear;
while (*str) {
clear = false;
if (*str == '!') {
clear = true;
str++;
}
val = simple_strtoull(str, &endp, 0);
if (str == endp)
break;
str = endp;
if (*str == '-') {
str++;
endval = simple_strtoull(str, &endp, 0);
if (str == endp)
break;
str = endp;
while (val <= endval) {
modify_facility(val, clear);
val++;
}
} else {
modify_facility(val, clear);
}
if (*str != ',')
break;
str++;
}
check_cleared_facilities();
}
static char command_line_buf[COMMAND_LINE_SIZE] __section(.data);
void parse_boot_command_line(void)
{
char *param, *val;
bool enabled;
char *args;
int rc;
kaslr_enabled = IS_ENABLED(CONFIG_RANDOMIZE_BASE);
args = strcpy(command_line_buf, early_command_line);
while (*args) {
args = next_arg(args, &param, &val);
if (!strcmp(param, "mem") && val) {
memory_end = round_down(memparse(val, NULL), PAGE_SIZE);
memory_end_set = 1;
}
if (!strcmp(param, "vmalloc") && val)
vmalloc_size = round_up(memparse(val, NULL), PAGE_SIZE);
if (!strcmp(param, "noexec")) {
rc = kstrtobool(val, &enabled);
if (!rc && !enabled)
noexec_disabled = 1;
}
if (!strcmp(param, "facilities") && val)
modify_fac_list(val);
if (!strcmp(param, "nokaslr"))
kaslr_enabled = 0;
}
}
void setup_memory_end(void)
{
#ifdef CONFIG_CRASH_DUMP
if (OLDMEM_BASE) {
kaslr_enabled = 0;
} else if (ipl_block_valid &&
ipl_block.pb0_hdr.pbt == IPL_PBT_FCP &&
ipl_block.fcp.opt == IPL_PB0_FCP_OPT_DUMP) {
kaslr_enabled = 0;
if (!sclp_early_get_hsa_size(&memory_end) && memory_end)
memory_end_set = 1;
}
#endif
}