Mercurial > hvf > hvf-old
changeset 526:eb49ee3e562d
cp: allow nss ipl of 31bit systems
Note: the manual needs to get updated!
Fixme: 64-bit nss ipl will not work.
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Mon, 25 Apr 2011 21:32:29 -0400 |
parents | 42f3a76e6535 |
children | 06ba1772ee9c |
files | cp/Makefile cp/include/config.h cp/shell/cmd_system.c |
diffstat | 3 files changed, 236 insertions(+), 36 deletions(-) [+] |
line wrap: on
line diff
--- a/cp/Makefile Mon Apr 25 21:32:22 2011 -0400 +++ b/cp/Makefile Mon Apr 25 21:32:29 2011 -0400 @@ -24,7 +24,7 @@ NUCLEUSCFLAGS=-include include/nucleus.h LDFLAGS=-m elf64_s390 -LIBS=clock digest string ebcdic +LIBS=clock digest string ebcdic errno export AS CC LD OBJCOPY export MAKEFLAGS CFLAGS NUCLEUSCFLAGS LDFLAGS
--- a/cp/include/config.h Mon Apr 25 21:32:22 2011 -0400 +++ b/cp/include/config.h Mon Apr 25 21:32:29 2011 -0400 @@ -23,6 +23,8 @@ #define CONFIG_FILE_NAME "SYSTEM " #define CONFIG_FILE_TYPE "CONFIG " +#define NSS_FILE_TYPE "NSS " + struct sysconf { u16 oper_con; char oper_userid[9];
--- a/cp/shell/cmd_system.c Mon Apr 25 21:32:22 2011 -0400 +++ b/cp/shell/cmd_system.c Mon Apr 25 21:32:29 2011 -0400 @@ -1,59 +1,219 @@ /* - * (C) Copyright 2007-2010 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> + * (C) Copyright 2007-2011 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * This file is released under the GPLv2. See the COPYING file for more * details. */ +#include <ebcdic.h> +#include <binfmt_elf.h> +#include <bcache.h> +#include <edf.h> + extern u32 GUEST_IPL_CODE[]; extern u32 GUEST_IPL_REGSAVE[]; -/* - *!!! IPL - *!! SYNTAX - *! \tok{\sc IPL} <vdev> - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Perform a ... - *!! NOTES - *! \item Not yet implemented. - *!! SETON - */ -static int cmd_ipl(struct virt_sys *sys, char *cmd, int len) +static int __copy_segment(struct virt_sys *sys, struct file *nss, u64 foff, + u64 fslen, u64 gaddr, u64 memlen) +{ + u32 blk, off, len; + u64 glen; + char *buf; + int ret; + + con_printf(sys->con, "LOAD (%llx, %llx) -> (%llx, %llx)\n", + foff, fslen, gaddr, memlen); + + /* memcpy the in-file guest storage into the guest's address space */ + while(fslen) { + blk = foff / sysfs->ADT.DBSIZ; + off = foff % sysfs->ADT.DBSIZ; + len = min_t(u64, sysfs->ADT.DBSIZ - off, fslen); + + con_printf(sys->con, "-> (%llx, %x) -> (%llx, %x)\n", + foff, len, gaddr, len); + + buf = bcache_read(nss, 0, blk); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + glen = len; + ret = memcpy_to_guest(gaddr, buf + off, &glen); + if (ret) + return ret; + BUG_ON(glen != len); + + foff += len; + fslen -= len; + gaddr += len; + memlen -= len; + } + + /* memset guest storage to 0 */ + while(memlen) { + len = min_t(u64, PAGE_SIZE, memlen); + + con_printf(sys->con, "-> 0(%llx, %x)\n", gaddr, len); + + glen = len; + ret = memcpy_to_guest(gaddr, (void*) zeropage, &glen); + if (ret) + return ret; + BUG_ON(glen != len); + + memlen -= len; + gaddr += len; + } + + return 0; +} + +static int __nss_ipl(struct virt_sys *sys, char *cmd, int len) { - struct virt_device *vdev; - u64 vdevnum = 0; + char fn[8]; + Elf_Ehdr *hdr; + Elf_Phdr *phdr; + struct file *file; + char *buf; + int fmt; + int ret; + int i; + + con_printf(sys->con, "WARNING: IPLNSS command is work-in-progress\n"); + + if (len > 8) + goto not_found; + + /* munge the system name */ + memcpy(fn, cmd, 8); + if (len < 8) + memset(fn + len, ' ', 8 - len); + ascii2upper((u8*) fn, 8); + + /* look up system name on the system fs */ + file = edf_lookup(sysfs, fn, NSS_FILE_TYPE); + if (IS_ERR(file)) { + ret = PTR_ERR(file); + if (ret == -ENOENT) + goto not_found; + goto err_load; + } + + BUG_ON((file->FST.LRECL != PAGE_SIZE) || (file->FST.RECFM != FSTDFIX)); + + hdr = bcache_read(file, 0, 0); + if (IS_ERR(hdr)) { + ret = PTR_ERR(hdr); + goto err_load; + } + + if ((hdr->s390.e_ident[EI_MAG0] != ELFMAG0) || + (hdr->s390.e_ident[EI_MAG1] != ELFMAG1) || + (hdr->s390.e_ident[EI_MAG2] != ELFMAG2) || + (hdr->s390.e_ident[EI_MAG3] != ELFMAG3) || + (hdr->s390.e_ident[EI_DATA] != ELFDATA2MSB) || + (hdr->s390.e_ident[EI_VERSION] != EV_CURRENT) || + (hdr->s390.e_type != ET_EXEC) || + (hdr->s390.e_machine != EM_S390)) + goto corrupt; + + fmt = hdr->s390.e_ident[EI_CLASS]; + if ((fmt != ELFCLASS32) && (fmt != ELFCLASS64)) + goto corrupt; + + /* convert the fmt into a 'is this 64 bit system' */ + fmt = (fmt == ELFCLASS64); + + con_printf(sys->con, "NSSIPL: %s-bit system\n", + fmt ? "64" : "31"); + + if (fmt) { + con_printf(sys->con, "NSSIPL: '%s' is a 64-bit system - not supported\n", + cmd); + goto out; + } + + /* + * FIXME: this should be conditional based whether or not we were + * told to clear + */ + guest_load_normal(sys); + + sys->task->cpu->state = GUEST_LOAD; + + for(i=0; i<hdr->s390.e_phnum; i++) { + u32 blk, off; + u64 foff, fslen, gaddr, memlen; + + foff = hdr->s390.e_phoff + + (hdr->s390.e_phentsize * i); + blk = foff / sysfs->ADT.DBSIZ; + off = foff % sysfs->ADT.DBSIZ; + + BUG_ON((sysfs->ADT.DBSIZ - off) < hdr->s390.e_phentsize); + + buf = bcache_read(file, 0, blk); + if (IS_ERR(file)) + goto corrupt; + + phdr = (void*) (buf + off); + + /* skip all program headers that aren't PT_LOAD */ + if (phdr->s390.p_type != PT_LOAD) + continue; + + if (phdr->s390.p_align != PAGE_SIZE) + goto corrupt; + + foff = phdr->s390.p_offset; + fslen = phdr->s390.p_filesz; + gaddr = phdr->s390.p_vaddr; + memlen = phdr->s390.p_memsz; + + ret = __copy_segment(sys, file, foff, fslen, gaddr, memlen); + if (ret) + goto corrupt; + } + + memset(&sys->task->cpu->sie_cb.gpsw, 0, sizeof(struct psw)); + sys->task->cpu->sie_cb.gpsw.fmt = 1; + sys->task->cpu->sie_cb.gpsw.ptr31 = hdr->s390.e_entry; + +out: + sys->task->cpu->state = GUEST_STOPPED; + return 0; + +err_load: + sys->task->cpu->state = GUEST_STOPPED; + con_printf(sys->con, "Error while loading NSS: %s\n", + errstrings[-ret]); + return 0; + +corrupt: + sys->task->cpu->state = GUEST_STOPPED; + con_printf(sys->con, "NSS '%s' found, but is malformed/corrupt\n", cmd); + return 0; + +not_found: + sys->task->cpu->state = GUEST_STOPPED; + con_printf(sys->con, "NSS '%s' does not exist\n", cmd); + return 0; +} + +static int __dev_ipl(struct virt_sys *sys, struct virt_device *vdev) +{ u64 host_addr; int bytes; int ret; int i; - /* get IPL vdev # */ - cmd = __extract_hex(cmd, &vdevnum); - if (IS_ERR(cmd)) - return PTR_ERR(cmd); - - /* device numbers are 16-bits */ - if (vdevnum & ~0xffff) - return -EINVAL; - - /* find the virtual device */ - - list_for_each_entry(vdev, &sys->virt_devs, devices) - if (vdev->pmcw.dev_num == (u16) vdevnum) - goto found; - - return -EINVAL; /* device not found */ - -found: /* * alright, we got the device... now set up IPL helper */ bytes = sizeof(u32)*(GUEST_IPL_REGSAVE-GUEST_IPL_CODE); - con_printf(sys->con, "WARNING: IPL command is work-in-progress\n"); + con_printf(sys->con, "WARNING: IPLDEV command is work-in-progress\n"); /* * FIXME: this should be conditional based whether or not we were @@ -98,6 +258,44 @@ return ret; } +/* + *!!! IPL + *!! SYNTAX + *! \tok{\sc IPL} <vdev> + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Perform a ... + *!! NOTES + *! \item Not yet implemented. + *!! SETON + */ +static int cmd_ipl(struct virt_sys *sys, char *cmd, int len) +{ + struct virt_device *vdev; + u64 vdevnum = 0; + char *c; + + /* get IPL vdev # */ + c = __extract_hex(cmd, &vdevnum); + if (IS_ERR(c)) + goto nss; + + /* device numbers are 16-bits */ + if (vdevnum & ~0xffff) + goto nss; + + /* find the virtual device */ + + list_for_each_entry(vdev, &sys->virt_devs, devices) + if (vdev->pmcw.dev_num == (u16) vdevnum) + return __dev_ipl(sys, vdev); + +nss: + /* device not found */ + return __nss_ipl(sys, cmd, len); +} + /*!!! SYSTEM CLEAR *!! SYNTAX *! \tok{\sc SYStem} \tok{\sc CLEAR}