Skip to content

Commit

Permalink
[S390] kernel: Append scpdata to kernel boot command line
Browse files Browse the repository at this point in the history
Append scpdata to the kernel boot command line. If scpdata starts
with the equal sign (=), the kernel boot command line is replaced.
(For consistency with zIPL and IPL PARM parameters.)

To use scpdata for the kernel boot command line, scpdata must consist
of ascii characters only. If scpdata contains other characters,
scpdata is not appended to the kernel boot command line.
In addition, re-IPL is extended for setting scpdata for the next
Linux reboot.

Signed-off-by: Hendrik Brueckner <[email protected]>
Signed-off-by: Martin Schwidefsky <[email protected]>
  • Loading branch information
hbrueckner authored and Martin Schwidefsky committed Sep 11, 2009
1 parent 6292b9e commit 684d2fd
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 27 deletions.
5 changes: 4 additions & 1 deletion arch/s390/include/asm/ipl.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ struct ipl_block_fcp {
} __attribute__((packed));

#define DIAG308_VMPARM_SIZE 64
#define DIAG308_SCPDATA_SIZE (PAGE_SIZE - (sizeof(struct ipl_list_hdr) + \
offsetof(struct ipl_block_fcp, scp_data)))

struct ipl_block_ccw {
u8 load_parm[8];
Expand Down Expand Up @@ -91,7 +93,8 @@ extern void do_halt(void);
extern void do_poff(void);
extern void ipl_save_parameters(void);
extern void ipl_update_parameters(void);
extern void get_ipl_vmparm(char *);
extern size_t append_ipl_vmparm(char *, size_t);
extern size_t append_ipl_scpdata(char *, size_t);

enum {
IPL_DEVNO_VALID = 1,
Expand Down
2 changes: 1 addition & 1 deletion arch/s390/include/asm/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#ifndef _ASM_S390_SETUP_H
#define _ASM_S390_SETUP_H

#define COMMAND_LINE_SIZE 1024
#define COMMAND_LINE_SIZE 4096

#define ARCH_COMMAND_LINE_SIZE 896

Expand Down
35 changes: 25 additions & 10 deletions arch/s390/kernel/early.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ asm(
" br 14\n"
" .size savesys_ipl_nss, .-savesys_ipl_nss\n");

static __initdata char upper_command_line[COMMAND_LINE_SIZE];

static noinline __init void create_kernel_nss(void)
{
unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
Expand All @@ -90,7 +92,6 @@ static noinline __init void create_kernel_nss(void)
int response;
size_t len;
char *savesys_ptr;
char upper_command_line[COMMAND_LINE_SIZE];
char defsys_cmd[DEFSYS_CMD_SIZE];
char savesys_cmd[SAVESYS_CMD_SIZE];

Expand Down Expand Up @@ -367,21 +368,35 @@ static __init void rescue_initrd(void)
}

/* Set up boot command line */
static void __init setup_boot_command_line(void)
static void __init append_to_cmdline(size_t (*ipl_data)(char *, size_t))
{
char *parm = NULL;
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 void __init setup_boot_command_line(void)
{
/* copy arch command line */
strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE);

/* append IPL PARM data to the boot command line */
if (MACHINE_IS_VM) {
parm = boot_command_line + strlen(boot_command_line);
*parm++ = ' ';
get_ipl_vmparm(parm);
if (parm[0] == '=')
memmove(boot_command_line, parm + 1, strlen(parm));
}
if (MACHINE_IS_VM)
append_to_cmdline(append_ipl_vmparm);

append_to_cmdline(append_ipl_scpdata);
}


Expand Down
157 changes: 142 additions & 15 deletions arch/s390/kernel/ipl.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,17 +272,18 @@ 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 void reipl_get_ascii_vmparm(char *dest,
size_t reipl_get_ascii_vmparm(char *dest, size_t size,
const struct ipl_parameter_block *ipb)
{
int i;
int len = 0;
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 = ipb->ipl_info.ccw.vm_parm_len;
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.
Expand All @@ -299,25 +300,77 @@ static void reipl_get_ascii_vmparm(char *dest,
EBCASC(dest, len);
}
dest[len] = 0;

return len;
}

void get_ipl_vmparm(char *dest)
size_t append_ipl_vmparm(char *dest, size_t size)
{
size_t rc;

rc = 0;
if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW))
reipl_get_ascii_vmparm(dest, &ipl_block);
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] = {};

get_ipl_vmparm(parm);
append_ipl_vmparm(parm, sizeof(parm));
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;
}

size_t reipl_append_ascii_scpdata(char *dest, size_t size,
const struct ipl_parameter_block *ipb)
{
size_t count;
size_t i;

count = min(size - 1, scpdata_length(ipb->ipl_info.fcp.scp_data,
ipb->ipl_info.fcp.scp_data_len));
if (!count)
goto out;

for (i = 0; i < count; i++)
if (!isascii(ipb->ipl_info.fcp.scp_data[i])) {
count = 0;
goto out;
}

memcpy(dest, ipb->ipl_info.fcp.scp_data, count);
out:
dest[count] = '\0';
return count;
}

size_t append_ipl_scpdata(char *dest, size_t len)
{
size_t rc;

rc = 0;
if (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);

Expand Down Expand Up @@ -553,7 +606,7 @@ static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb,
{
char vmparm[DIAG308_VMPARM_SIZE + 1] = {};

reipl_get_ascii_vmparm(vmparm, ipb);
reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb);
return sprintf(page, "%s\n", vmparm);
}

Expand Down Expand Up @@ -626,6 +679,59 @@ static struct kobj_attribute sys_reipl_ccw_vmparm_attr =

/* FCP reipl device attributes */

static ssize_t reipl_fcp_scpdata_read(struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
size_t size = reipl_block_fcp->ipl_info.fcp.scp_data_len;
void *scp_data = reipl_block_fcp->ipl_info.fcp.scp_data;

return memory_read_from_buffer(buf, count, &off, scp_data, size);
}

static ssize_t reipl_fcp_scpdata_write(struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
size_t padding;
size_t scpdata_len;

if (off < 0)
return -EINVAL;

if (off >= DIAG308_SCPDATA_SIZE)
return -ENOSPC;

if (count > DIAG308_SCPDATA_SIZE - off)
count = DIAG308_SCPDATA_SIZE - off;

memcpy(reipl_block_fcp->ipl_info.fcp.scp_data, buf + off, count);
scpdata_len = off + count;

if (scpdata_len % 8) {
padding = 8 - (scpdata_len % 8);
memset(reipl_block_fcp->ipl_info.fcp.scp_data + scpdata_len,
0, padding);
scpdata_len += padding;
}

reipl_block_fcp->ipl_info.fcp.scp_data_len = scpdata_len;
reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN + scpdata_len;
reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN + scpdata_len;

return count;
}

static struct bin_attribute sys_reipl_fcp_scp_data_attr = {
.attr = {
.name = "scp_data",
.mode = S_IRUGO | S_IWUSR,
},
.size = PAGE_SIZE,
.read = reipl_fcp_scpdata_read,
.write = reipl_fcp_scpdata_write,
};

DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
reipl_block_fcp->ipl_info.fcp.wwpn);
DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n",
Expand All @@ -647,7 +753,6 @@ static struct attribute *reipl_fcp_attrs[] = {
};

static struct attribute_group reipl_fcp_attr_group = {
.name = IPL_FCP_STR,
.attrs = reipl_fcp_attrs,
};

Expand Down Expand Up @@ -895,6 +1000,7 @@ static struct kobj_attribute reipl_type_attr =
__ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);

static struct kset *reipl_kset;
static struct kset *reipl_fcp_kset;

static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb,
const enum ipl_method m)
Expand All @@ -906,7 +1012,7 @@ static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb,

reipl_get_ascii_loadparm(loadparm, ipb);
reipl_get_ascii_nss_name(nss_name, ipb);
reipl_get_ascii_vmparm(vmparm, ipb);
reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb);

switch (m) {
case REIPL_METHOD_CCW_VM:
Expand Down Expand Up @@ -1076,23 +1182,44 @@ static int __init reipl_fcp_init(void)
int rc;

if (!diag308_set_works) {
if (ipl_info.type == IPL_TYPE_FCP)
if (ipl_info.type == IPL_TYPE_FCP) {
make_attrs_ro(reipl_fcp_attrs);
else
sys_reipl_fcp_scp_data_attr.attr.mode = S_IRUGO;
} else
return 0;
}

reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
if (!reipl_block_fcp)
return -ENOMEM;
rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group);

/* sysfs: create fcp kset for mixing attr group and bin attrs */
reipl_fcp_kset = kset_create_and_add(IPL_FCP_STR, NULL,
&reipl_kset->kobj);
if (!reipl_kset) {
free_page((unsigned long) reipl_block_fcp);
return -ENOMEM;
}

rc = sysfs_create_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
if (rc) {
free_page((unsigned long)reipl_block_fcp);
kset_unregister(reipl_fcp_kset);
free_page((unsigned long) reipl_block_fcp);
return rc;
}
if (ipl_info.type == IPL_TYPE_FCP) {

rc = sysfs_create_bin_file(&reipl_fcp_kset->kobj,
&sys_reipl_fcp_scp_data_attr);
if (rc) {
sysfs_remove_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group);
kset_unregister(reipl_fcp_kset);
free_page((unsigned long) reipl_block_fcp);
return rc;
}

if (ipl_info.type == IPL_TYPE_FCP)
memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
} else {
else {
reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN;
Expand Down

0 comments on commit 684d2fd

Please sign in to comment.