s390: move ipl block and cmd line handling to early boot phase
To distinguish zfcpdump case and to be able to parse some of the kernel command line arguments early (e.g. mem=) ipl block retrieval and command line construction code is moved to the early boot phase. "memory_end" is set up correctly respecting "mem=" and hsa_size in case of the zfcpdump. arch/s390/boot/string.c is introduced to provide string handling and command line parsing functions to early boot phase code for the compressed kernel image case. Signed-off-by: Vasily Gorbik <gor@linux.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:

committed by
Martin Schwidefsky

parent
b09decfd99
commit
49698745e5
@@ -47,7 +47,7 @@ obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o early_nobss.o
|
||||
obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
|
||||
obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o
|
||||
obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o
|
||||
obj-y += nospec-branch.o
|
||||
obj-y += nospec-branch.o ipl_vmparm.o
|
||||
|
||||
extra-y += head64.o vmlinux.lds
|
||||
|
||||
|
@@ -29,10 +29,9 @@
|
||||
#include <asm/cpcmd.h>
|
||||
#include <asm/sclp.h>
|
||||
#include <asm/facility.h>
|
||||
#include <asm/boot_data.h>
|
||||
#include "entry.h"
|
||||
|
||||
static void __init setup_boot_command_line(void);
|
||||
|
||||
/*
|
||||
* Initialize storage key for kernel pages
|
||||
*/
|
||||
@@ -284,51 +283,11 @@ static int __init cad_setup(char *str)
|
||||
}
|
||||
early_param("cad", cad_setup);
|
||||
|
||||
/* Set up boot command line */
|
||||
static void __init append_to_cmdline(size_t (*ipl_data)(char *, size_t))
|
||||
{
|
||||
char *parm, *delim;
|
||||
size_t rc, len;
|
||||
|
||||
len = strlen(boot_command_line);
|
||||
|
||||
delim = boot_command_line + len; /* '\0' character position */
|
||||
parm = boot_command_line + len + 1; /* append right after '\0' */
|
||||
|
||||
rc = ipl_data(parm, COMMAND_LINE_SIZE - len - 1);
|
||||
if (rc) {
|
||||
if (*parm == '=')
|
||||
memmove(boot_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;
|
||||
}
|
||||
|
||||
char __bootdata(early_command_line)[COMMAND_LINE_SIZE];
|
||||
static void __init 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 */
|
||||
strlcpy(boot_command_line, strstrip(COMMAND_LINE),
|
||||
ARCH_COMMAND_LINE_SIZE);
|
||||
|
||||
/* append IPL PARM data to the boot command line */
|
||||
if (MACHINE_IS_VM)
|
||||
append_to_cmdline(append_ipl_vmparm);
|
||||
|
||||
append_to_cmdline(append_ipl_scpdata);
|
||||
strlcpy(boot_command_line, early_command_line, ARCH_COMMAND_LINE_SIZE);
|
||||
}
|
||||
|
||||
static void __init check_image_bootable(void)
|
||||
|
@@ -29,6 +29,8 @@
|
||||
#include <asm/checksum.h>
|
||||
#include <asm/debug.h>
|
||||
#include <asm/os_info.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/boot_data.h>
|
||||
#include "entry.h"
|
||||
|
||||
#define IPL_PARM_BLOCK_VERSION 0
|
||||
@@ -117,6 +119,9 @@ static char *dump_type_str(enum dump_type type)
|
||||
}
|
||||
}
|
||||
|
||||
struct ipl_parameter_block __bootdata(early_ipl_block);
|
||||
int __bootdata(early_ipl_block_valid);
|
||||
|
||||
static int ipl_block_valid;
|
||||
static struct ipl_parameter_block ipl_block;
|
||||
|
||||
@@ -262,115 +267,16 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
|
||||
static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
|
||||
|
||||
/* VM IPL PARM routines */
|
||||
static size_t reipl_get_ascii_vmparm(char *dest, size_t size,
|
||||
const struct ipl_parameter_block *ipb)
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
char has_lowercase = 0;
|
||||
|
||||
len = 0;
|
||||
if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) &&
|
||||
(ipb->ipl_info.ccw.vm_parm_len > 0)) {
|
||||
|
||||
len = min_t(size_t, size - 1, ipb->ipl_info.ccw.vm_parm_len);
|
||||
memcpy(dest, ipb->ipl_info.ccw.vm_parm, len);
|
||||
/* If at least one character is lowercase, we assume mixed
|
||||
* case; otherwise we convert everything to lowercase.
|
||||
*/
|
||||
for (i = 0; i < len; i++)
|
||||
if ((dest[i] > 0x80 && dest[i] < 0x8a) || /* a-i */
|
||||
(dest[i] > 0x90 && dest[i] < 0x9a) || /* j-r */
|
||||
(dest[i] > 0xa1 && dest[i] < 0xaa)) { /* s-z */
|
||||
has_lowercase = 1;
|
||||
break;
|
||||
}
|
||||
if (!has_lowercase)
|
||||
EBC_TOLOWER(dest, len);
|
||||
EBCASC(dest, len);
|
||||
}
|
||||
dest[len] = 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t append_ipl_vmparm(char *dest, size_t size)
|
||||
{
|
||||
size_t rc;
|
||||
|
||||
rc = 0;
|
||||
if (ipl_block_valid && ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW)
|
||||
rc = reipl_get_ascii_vmparm(dest, size, &ipl_block);
|
||||
else
|
||||
dest[0] = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t ipl_vm_parm_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *page)
|
||||
{
|
||||
char parm[DIAG308_VMPARM_SIZE + 1] = {};
|
||||
|
||||
append_ipl_vmparm(parm, sizeof(parm));
|
||||
if (ipl_block_valid && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW))
|
||||
ipl_block_get_ascii_vmparm(parm, sizeof(parm), &ipl_block);
|
||||
return sprintf(page, "%s\n", parm);
|
||||
}
|
||||
|
||||
static size_t scpdata_length(const char* buf, size_t count)
|
||||
{
|
||||
while (count) {
|
||||
if (buf[count - 1] != '\0' && buf[count - 1] != ' ')
|
||||
break;
|
||||
count--;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static size_t reipl_append_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->ipl_info.fcp.scp_data,
|
||||
ipb->ipl_info.fcp.scp_data_len));
|
||||
if (!count)
|
||||
goto out;
|
||||
|
||||
has_lowercase = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (!isascii(ipb->ipl_info.fcp.scp_data[i])) {
|
||||
count = 0;
|
||||
goto out;
|
||||
}
|
||||
if (!has_lowercase && islower(ipb->ipl_info.fcp.scp_data[i]))
|
||||
has_lowercase = 1;
|
||||
}
|
||||
|
||||
if (has_lowercase)
|
||||
memcpy(dest, ipb->ipl_info.fcp.scp_data, count);
|
||||
else
|
||||
for (i = 0; i < count; i++)
|
||||
dest[i] = tolower(ipb->ipl_info.fcp.scp_data[i]);
|
||||
out:
|
||||
dest[count] = '\0';
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t append_ipl_scpdata(char *dest, size_t len)
|
||||
{
|
||||
size_t rc;
|
||||
|
||||
rc = 0;
|
||||
if (ipl_block_valid && ipl_block.hdr.pbt == DIAG308_IPL_TYPE_FCP)
|
||||
rc = reipl_append_ascii_scpdata(dest, len, &ipl_block);
|
||||
else
|
||||
dest[0] = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static struct kobj_attribute sys_ipl_vm_parm_attr =
|
||||
__ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL);
|
||||
|
||||
@@ -564,7 +470,7 @@ static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb,
|
||||
{
|
||||
char vmparm[DIAG308_VMPARM_SIZE + 1] = {};
|
||||
|
||||
reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb);
|
||||
ipl_block_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb);
|
||||
return sprintf(page, "%s\n", vmparm);
|
||||
}
|
||||
|
||||
@@ -1769,11 +1675,10 @@ void __init setup_ipl(void)
|
||||
|
||||
void __init ipl_store_parameters(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = diag308(DIAG308_STORE, &ipl_block);
|
||||
if (rc == DIAG308_RC_OK && ipl_block.hdr.version <= IPL_MAX_SUPPORTED_VERSION)
|
||||
if (early_ipl_block_valid) {
|
||||
memcpy(&ipl_block, &early_ipl_block, sizeof(ipl_block));
|
||||
ipl_block_valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void s390_reset_system(void)
|
||||
|
36
arch/s390/kernel/ipl_vmparm.c
Normal file
36
arch/s390/kernel/ipl_vmparm.c
Normal file
@@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/ipl.h>
|
||||
|
||||
/* VM IPL PARM routines */
|
||||
size_t ipl_block_get_ascii_vmparm(char *dest, size_t size,
|
||||
const struct ipl_parameter_block *ipb)
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
char has_lowercase = 0;
|
||||
|
||||
len = 0;
|
||||
if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) &&
|
||||
(ipb->ipl_info.ccw.vm_parm_len > 0)) {
|
||||
|
||||
len = min_t(size_t, size - 1, ipb->ipl_info.ccw.vm_parm_len);
|
||||
memcpy(dest, ipb->ipl_info.ccw.vm_parm, len);
|
||||
/* If at least one character is lowercase, we assume mixed
|
||||
* case; otherwise we convert everything to lowercase.
|
||||
*/
|
||||
for (i = 0; i < len; i++)
|
||||
if ((dest[i] > 0x80 && dest[i] < 0x8a) || /* a-i */
|
||||
(dest[i] > 0x90 && dest[i] < 0x9a) || /* j-r */
|
||||
(dest[i] > 0xa1 && dest[i] < 0xaa)) { /* s-z */
|
||||
has_lowercase = 1;
|
||||
break;
|
||||
}
|
||||
if (!has_lowercase)
|
||||
EBC_TOLOWER(dest, len);
|
||||
EBCASC(dest, len);
|
||||
}
|
||||
dest[len] = 0;
|
||||
|
||||
return len;
|
||||
}
|
@@ -90,8 +90,8 @@ char elf_platform[ELF_PLATFORM_SIZE];
|
||||
|
||||
unsigned long int_hwcap = 0;
|
||||
|
||||
int __initdata memory_end_set;
|
||||
unsigned long __initdata memory_end;
|
||||
int __bootdata(memory_end_set);
|
||||
unsigned long __bootdata(memory_end);
|
||||
unsigned long __bootdata(max_physmem_end);
|
||||
struct mem_detect_info __bootdata(mem_detect);
|
||||
|
||||
@@ -286,15 +286,6 @@ void machine_power_off(void)
|
||||
void (*pm_power_off)(void) = machine_power_off;
|
||||
EXPORT_SYMBOL_GPL(pm_power_off);
|
||||
|
||||
static int __init early_parse_mem(char *p)
|
||||
{
|
||||
memory_end = memparse(p, &p);
|
||||
memory_end &= PAGE_MASK;
|
||||
memory_end_set = 1;
|
||||
return 0;
|
||||
}
|
||||
early_param("mem", early_parse_mem);
|
||||
|
||||
static int __init parse_vmalloc(char *arg)
|
||||
{
|
||||
if (!arg)
|
||||
@@ -605,17 +596,8 @@ static struct notifier_block kdump_mem_nb = {
|
||||
*/
|
||||
static void reserve_memory_end(void)
|
||||
{
|
||||
#ifdef CONFIG_CRASH_DUMP
|
||||
if (ipl_info.type == IPL_TYPE_FCP_DUMP &&
|
||||
!OLDMEM_BASE && sclp.hsa_size) {
|
||||
memory_end = sclp.hsa_size;
|
||||
memory_end &= PAGE_MASK;
|
||||
memory_end_set = 1;
|
||||
}
|
||||
#endif
|
||||
if (!memory_end_set)
|
||||
return;
|
||||
memblock_reserve(memory_end, ULONG_MAX);
|
||||
if (memory_end_set)
|
||||
memblock_reserve(memory_end, ULONG_MAX);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user