Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[S390] kernel: Append scpdata to kernel boot command line

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 <brueckner@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Hendrik Brueckner and committed by
Martin Schwidefsky
684d2fd4 6292b9ef

+172 -27
+4 -1
arch/s390/include/asm/ipl.h
··· 57 57 } __attribute__((packed)); 58 58 59 59 #define DIAG308_VMPARM_SIZE 64 60 + #define DIAG308_SCPDATA_SIZE (PAGE_SIZE - (sizeof(struct ipl_list_hdr) + \ 61 + offsetof(struct ipl_block_fcp, scp_data))) 60 62 61 63 struct ipl_block_ccw { 62 64 u8 load_parm[8]; ··· 93 91 extern void do_poff(void); 94 92 extern void ipl_save_parameters(void); 95 93 extern void ipl_update_parameters(void); 96 - extern void get_ipl_vmparm(char *); 94 + extern size_t append_ipl_vmparm(char *, size_t); 95 + extern size_t append_ipl_scpdata(char *, size_t); 97 96 98 97 enum { 99 98 IPL_DEVNO_VALID = 1,
+1 -1
arch/s390/include/asm/setup.h
··· 8 8 #ifndef _ASM_S390_SETUP_H 9 9 #define _ASM_S390_SETUP_H 10 10 11 - #define COMMAND_LINE_SIZE 1024 11 + #define COMMAND_LINE_SIZE 4096 12 12 13 13 #define ARCH_COMMAND_LINE_SIZE 896 14 14
+25 -10
arch/s390/kernel/early.c
··· 81 81 " br 14\n" 82 82 " .size savesys_ipl_nss, .-savesys_ipl_nss\n"); 83 83 84 + static __initdata char upper_command_line[COMMAND_LINE_SIZE]; 85 + 84 86 static noinline __init void create_kernel_nss(void) 85 87 { 86 88 unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; ··· 92 90 int response; 93 91 size_t len; 94 92 char *savesys_ptr; 95 - char upper_command_line[COMMAND_LINE_SIZE]; 96 93 char defsys_cmd[DEFSYS_CMD_SIZE]; 97 94 char savesys_cmd[SAVESYS_CMD_SIZE]; 98 95 ··· 368 367 } 369 368 370 369 /* Set up boot command line */ 370 + static void __init append_to_cmdline(size_t (*ipl_data)(char *, size_t)) 371 + { 372 + char *parm, *delim; 373 + size_t rc, len; 374 + 375 + len = strlen(boot_command_line); 376 + 377 + delim = boot_command_line + len; /* '\0' character position */ 378 + parm = boot_command_line + len + 1; /* append right after '\0' */ 379 + 380 + rc = ipl_data(parm, COMMAND_LINE_SIZE - len - 1); 381 + if (rc) { 382 + if (*parm == '=') 383 + memmove(boot_command_line, parm + 1, rc); 384 + else 385 + *delim = ' '; /* replace '\0' with space */ 386 + } 387 + } 388 + 371 389 static void __init setup_boot_command_line(void) 372 390 { 373 - char *parm = NULL; 374 - 375 391 /* copy arch command line */ 376 392 strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); 377 393 378 394 /* append IPL PARM data to the boot command line */ 379 - if (MACHINE_IS_VM) { 380 - parm = boot_command_line + strlen(boot_command_line); 381 - *parm++ = ' '; 382 - get_ipl_vmparm(parm); 383 - if (parm[0] == '=') 384 - memmove(boot_command_line, parm + 1, strlen(parm)); 385 - } 395 + if (MACHINE_IS_VM) 396 + append_to_cmdline(append_ipl_vmparm); 397 + 398 + append_to_cmdline(append_ipl_scpdata); 386 399 } 387 400 388 401
+142 -15
arch/s390/kernel/ipl.c
··· 272 272 static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); 273 273 274 274 /* VM IPL PARM routines */ 275 - static void reipl_get_ascii_vmparm(char *dest, 275 + size_t reipl_get_ascii_vmparm(char *dest, size_t size, 276 276 const struct ipl_parameter_block *ipb) 277 277 { 278 278 int i; 279 - int len = 0; 279 + size_t len; 280 280 char has_lowercase = 0; 281 281 282 + len = 0; 282 283 if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) && 283 284 (ipb->ipl_info.ccw.vm_parm_len > 0)) { 284 285 285 - len = ipb->ipl_info.ccw.vm_parm_len; 286 + len = min_t(size_t, size - 1, ipb->ipl_info.ccw.vm_parm_len); 286 287 memcpy(dest, ipb->ipl_info.ccw.vm_parm, len); 287 288 /* If at least one character is lowercase, we assume mixed 288 289 * case; otherwise we convert everything to lowercase. ··· 300 299 EBCASC(dest, len); 301 300 } 302 301 dest[len] = 0; 302 + 303 + return len; 303 304 } 304 305 305 - void get_ipl_vmparm(char *dest) 306 + size_t append_ipl_vmparm(char *dest, size_t size) 306 307 { 308 + size_t rc; 309 + 310 + rc = 0; 307 311 if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW)) 308 - reipl_get_ascii_vmparm(dest, &ipl_block); 312 + rc = reipl_get_ascii_vmparm(dest, size, &ipl_block); 309 313 else 310 314 dest[0] = 0; 315 + return rc; 311 316 } 312 317 313 318 static ssize_t ipl_vm_parm_show(struct kobject *kobj, ··· 321 314 { 322 315 char parm[DIAG308_VMPARM_SIZE + 1] = {}; 323 316 324 - get_ipl_vmparm(parm); 317 + append_ipl_vmparm(parm, sizeof(parm)); 325 318 return sprintf(page, "%s\n", parm); 326 319 } 320 + 321 + static size_t scpdata_length(const char* buf, size_t count) 322 + { 323 + while (count) { 324 + if (buf[count - 1] != '\0' && buf[count - 1] != ' ') 325 + break; 326 + count--; 327 + } 328 + return count; 329 + } 330 + 331 + size_t reipl_append_ascii_scpdata(char *dest, size_t size, 332 + const struct ipl_parameter_block *ipb) 333 + { 334 + size_t count; 335 + size_t i; 336 + 337 + count = min(size - 1, scpdata_length(ipb->ipl_info.fcp.scp_data, 338 + ipb->ipl_info.fcp.scp_data_len)); 339 + if (!count) 340 + goto out; 341 + 342 + for (i = 0; i < count; i++) 343 + if (!isascii(ipb->ipl_info.fcp.scp_data[i])) { 344 + count = 0; 345 + goto out; 346 + } 347 + 348 + memcpy(dest, ipb->ipl_info.fcp.scp_data, count); 349 + out: 350 + dest[count] = '\0'; 351 + return count; 352 + } 353 + 354 + size_t append_ipl_scpdata(char *dest, size_t len) 355 + { 356 + size_t rc; 357 + 358 + rc = 0; 359 + if (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_FCP) 360 + rc = reipl_append_ascii_scpdata(dest, len, &ipl_block); 361 + else 362 + dest[0] = 0; 363 + return rc; 364 + } 365 + 327 366 328 367 static struct kobj_attribute sys_ipl_vm_parm_attr = 329 368 __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL); ··· 606 553 { 607 554 char vmparm[DIAG308_VMPARM_SIZE + 1] = {}; 608 555 609 - reipl_get_ascii_vmparm(vmparm, ipb); 556 + reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb); 610 557 return sprintf(page, "%s\n", vmparm); 611 558 } 612 559 ··· 679 626 680 627 /* FCP reipl device attributes */ 681 628 629 + static ssize_t reipl_fcp_scpdata_read(struct kobject *kobj, 630 + struct bin_attribute *attr, 631 + char *buf, loff_t off, size_t count) 632 + { 633 + size_t size = reipl_block_fcp->ipl_info.fcp.scp_data_len; 634 + void *scp_data = reipl_block_fcp->ipl_info.fcp.scp_data; 635 + 636 + return memory_read_from_buffer(buf, count, &off, scp_data, size); 637 + } 638 + 639 + static ssize_t reipl_fcp_scpdata_write(struct kobject *kobj, 640 + struct bin_attribute *attr, 641 + char *buf, loff_t off, size_t count) 642 + { 643 + size_t padding; 644 + size_t scpdata_len; 645 + 646 + if (off < 0) 647 + return -EINVAL; 648 + 649 + if (off >= DIAG308_SCPDATA_SIZE) 650 + return -ENOSPC; 651 + 652 + if (count > DIAG308_SCPDATA_SIZE - off) 653 + count = DIAG308_SCPDATA_SIZE - off; 654 + 655 + memcpy(reipl_block_fcp->ipl_info.fcp.scp_data, buf + off, count); 656 + scpdata_len = off + count; 657 + 658 + if (scpdata_len % 8) { 659 + padding = 8 - (scpdata_len % 8); 660 + memset(reipl_block_fcp->ipl_info.fcp.scp_data + scpdata_len, 661 + 0, padding); 662 + scpdata_len += padding; 663 + } 664 + 665 + reipl_block_fcp->ipl_info.fcp.scp_data_len = scpdata_len; 666 + reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN + scpdata_len; 667 + reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN + scpdata_len; 668 + 669 + return count; 670 + } 671 + 672 + static struct bin_attribute sys_reipl_fcp_scp_data_attr = { 673 + .attr = { 674 + .name = "scp_data", 675 + .mode = S_IRUGO | S_IWUSR, 676 + }, 677 + .size = PAGE_SIZE, 678 + .read = reipl_fcp_scpdata_read, 679 + .write = reipl_fcp_scpdata_write, 680 + }; 681 + 682 682 DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n", 683 683 reipl_block_fcp->ipl_info.fcp.wwpn); 684 684 DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n", ··· 753 647 }; 754 648 755 649 static struct attribute_group reipl_fcp_attr_group = { 756 - .name = IPL_FCP_STR, 757 650 .attrs = reipl_fcp_attrs, 758 651 }; 759 652 ··· 1000 895 __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store); 1001 896 1002 897 static struct kset *reipl_kset; 898 + static struct kset *reipl_fcp_kset; 1003 899 1004 900 static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb, 1005 901 const enum ipl_method m) ··· 1012 906 1013 907 reipl_get_ascii_loadparm(loadparm, ipb); 1014 908 reipl_get_ascii_nss_name(nss_name, ipb); 1015 - reipl_get_ascii_vmparm(vmparm, ipb); 909 + reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb); 1016 910 1017 911 switch (m) { 1018 912 case REIPL_METHOD_CCW_VM: ··· 1182 1076 int rc; 1183 1077 1184 1078 if (!diag308_set_works) { 1185 - if (ipl_info.type == IPL_TYPE_FCP) 1079 + if (ipl_info.type == IPL_TYPE_FCP) { 1186 1080 make_attrs_ro(reipl_fcp_attrs); 1187 - else 1081 + sys_reipl_fcp_scp_data_attr.attr.mode = S_IRUGO; 1082 + } else 1188 1083 return 0; 1189 1084 } 1190 1085 1191 1086 reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); 1192 1087 if (!reipl_block_fcp) 1193 1088 return -ENOMEM; 1194 - rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group); 1089 + 1090 + /* sysfs: create fcp kset for mixing attr group and bin attrs */ 1091 + reipl_fcp_kset = kset_create_and_add(IPL_FCP_STR, NULL, 1092 + &reipl_kset->kobj); 1093 + if (!reipl_kset) { 1094 + free_page((unsigned long) reipl_block_fcp); 1095 + return -ENOMEM; 1096 + } 1097 + 1098 + rc = sysfs_create_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group); 1195 1099 if (rc) { 1196 - free_page((unsigned long)reipl_block_fcp); 1100 + kset_unregister(reipl_fcp_kset); 1101 + free_page((unsigned long) reipl_block_fcp); 1197 1102 return rc; 1198 1103 } 1199 - if (ipl_info.type == IPL_TYPE_FCP) { 1104 + 1105 + rc = sysfs_create_bin_file(&reipl_fcp_kset->kobj, 1106 + &sys_reipl_fcp_scp_data_attr); 1107 + if (rc) { 1108 + sysfs_remove_group(&reipl_fcp_kset->kobj, &reipl_fcp_attr_group); 1109 + kset_unregister(reipl_fcp_kset); 1110 + free_page((unsigned long) reipl_block_fcp); 1111 + return rc; 1112 + } 1113 + 1114 + if (ipl_info.type == IPL_TYPE_FCP) 1200 1115 memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE); 1201 - } else { 1116 + else { 1202 1117 reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN; 1203 1118 reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION; 1204 1119 reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN;