From b854a45660ff763cd5f1d324dc86937d374c9ba3 Mon Sep 17 00:00:00 2001 From: Josef 'Jeff' Sipek Date: Sun, 27 Nov 2011 13:43:19 -0500 Subject: [PATCH] cp: guest layer revamp, part 1 NOTE: The code compiles but does not run. The guest handling code and the shell code are *too* intertwined. They are separate logically and so the implementation should be too. This commit moves a lot of the guest handling code out of the shell source tree and into the guest tree where it belongs. Additionally, it is the beginning of a nice interface (function names guest_*) that the shell can use to control the guest. Additionally, this commit "breaks" the console layer in preparation for the new console handling scheme. This scheme will allow for guests to login, logout, disconnect, and reconnect. The main idea is to have a service guest (called *LOGIN) that is responsible for displaying the login screens, getting user credentials, and then informing the CP that a user is at a particular terminal. CP will then remove the device from *LOGIN's control and assign it to a newly allocated virt_sys. In order for this scheme to work, several pieces of code need to be written: - dynamic virt_device attach / detach (in libguest) - *LOGIN guest code - dedicated 3215 device handling - DIAG mechanism to inform CP that a logon occured Lastly, this commit moves the IPL-from-device helper into a separate NSS. This will mean that *all* IPL commands at the shell end up being NSS IPLs. Signed-off-by: Josef 'Jeff' Sipek --- cp/drivers/3215.c | 4 +- cp/drivers/console.c | 52 ---- cp/drivers/device.c | 6 +- cp/drivers/objs.cmake | 2 +- cp/drivers/vdevice.c | 4 +- cp/guest/init.c | 147 ++++++++- cp/guest/ipl.c | 183 +++++++++++ cp/guest/objs.cmake | 4 +- cp/guest/{guest.c => run.c} | 0 cp/guest/system.c | 32 ++ cp/include/console.h | 11 - cp/include/device.h | 3 +- cp/include/guest.h | 17 ++ cp/include/nucleus.h | 10 +- cp/include/shell.h | 9 +- cp/include/vcpu.h | 18 +- cp/include/vdevice.h | 1 + cp/nucleus/init.c | 35 ++- cp/nucleus/printf.c | 10 +- cp/shell/cmd_beginstop.c | 6 +- cp/shell/cmd_display.c | 2 +- cp/shell/cmd_enable.c | 20 +- cp/shell/cmd_logon.c | 19 +- cp/shell/cmd_query.c | 18 +- cp/shell/cmd_system.c | 473 +++++++---------------------- cp/shell/cmds.c | 25 +- cp/shell/init.c | 400 +++++++----------------- include/errno.h | 1 + lib/errno.c | 1 + nss/CMakeLists.txt | 1 + nss/ipldev/.gitignore | 1 + nss/ipldev/CMakeLists.txt | 4 + cp/guest/guest_ipl.s => nss/ipldev/guest.s | 0 nss/ipldev/linker.script | 8 + 34 files changed, 716 insertions(+), 811 deletions(-) create mode 100644 cp/guest/ipl.c rename cp/guest/{guest.c => run.c} (100%) create mode 100644 cp/guest/system.c create mode 100644 cp/include/guest.h rewrite cp/shell/cmd_system.c (71%) rewrite cp/shell/init.c (63%) create mode 100644 nss/ipldev/.gitignore create mode 100644 nss/ipldev/CMakeLists.txt rename cp/guest/guest_ipl.s => nss/ipldev/guest.s (100%) create mode 100644 nss/ipldev/linker.script diff --git a/cp/drivers/3215.c b/cp/drivers/3215.c index 292c4a6..6e8637d 100644 --- a/cp/drivers/3215.c +++ b/cp/drivers/3215.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2007-2010 Josef 'Jeff' Sipek + * (C) Copyright 2007-2011 Josef 'Jeff' Sipek * * This file is released under the GPLv2. See the COPYING file for more * details. @@ -15,7 +15,7 @@ static struct device_type d3215 = { .types = LIST_HEAD_INIT(d3215.types), .reg = NULL, .interrupt = NULL, - .enable = console_enable, + .enable = NULL, .snprintf = NULL, .type = 0x3215, .model = 0, diff --git a/cp/drivers/console.c b/cp/drivers/console.c index 342f5f0..6152a0f 100644 --- a/cp/drivers/console.c +++ b/cp/drivers/console.c @@ -112,58 +112,6 @@ static int console_flusher(void *data) return 0; } -/** - * register_console - generic device registration callback - * @dev: console device to register - */ -static int register_console(struct device *dev) -{ - struct console *con; - struct page *page; - int ret = 0; - - dev_get(dev); - - con = malloc(sizeof(struct console), ZONE_NORMAL); - BUG_ON(!con); - - con->sys = NULL; - con->dev = dev; - - con->wlines = alloc_spool(); - if (IS_ERR(con->wlines)) { - ret = PTR_ERR(con->wlines); - goto out; - } - - con->rlines = alloc_spool(); - if (IS_ERR(con->rlines)) { - ret = PTR_ERR(con->rlines); - goto out_free; - } - - page = alloc_pages(0, ZONE_NORMAL); - if (!page) { - ret = -ENOMEM; - goto out_free2; - } - - con->bigbuf = page_to_addr(page); - - spin_lock(&consoles_lock); - list_add_tail(&con->consoles, &consoles); - spin_unlock(&consoles_lock); - -out: - return ret; - -out_free2: - free_spool(con->rlines); -out_free: - free_spool(con->wlines); - goto out; -} - static void print_splash(struct console *con) { struct logo_rec *rec; diff --git a/cp/drivers/device.c b/cp/drivers/device.c index 1b130ff..d803e46 100644 --- a/cp/drivers/device.c +++ b/cp/drivers/device.c @@ -13,6 +13,8 @@ #include #include +static LOCK_CLASS(device_lock_lc); + struct static_device { u16 dev_num; struct senseid_struct sense; @@ -180,7 +182,9 @@ found: spin_double_unlock(&devs_lock, &dev_types_lock); atomic_set(&dev->refcnt, 1); - atomic_set(&dev->in_use, 0); + + mutex_init(&dev->lock, &device_lock_lc); + dev->in_use = 0; dev->dev = type; diff --git a/cp/drivers/objs.cmake b/cp/drivers/objs.cmake index 837d2bd..b2da2ec 100644 --- a/cp/drivers/objs.cmake +++ b/cp/drivers/objs.cmake @@ -1,2 +1,2 @@ -set(FILES device.c console.c 3215.c dasd.c vdevice.c spooldev.c +set(FILES device.c 3215.c dasd.c vdevice.c spooldev.c spooldev_cons.c) diff --git a/cp/drivers/vdevice.c b/cp/drivers/vdevice.c index 4cd261d..f956ca5 100644 --- a/cp/drivers/vdevice.c +++ b/cp/drivers/vdevice.c @@ -20,7 +20,9 @@ static int __setup_vdev_ded(struct virt_sys *sys, if (IS_ERR(rdev)) return PTR_ERR(rdev); - atomic_inc(&rdev->in_use); + mutex_lock(&rdev->lock); + rdev->in_use = 1; + mutex_unlock(&rdev->lock); vdev->u.dedicate.rdev = rdev; vdev->type = rdev->type; diff --git a/cp/guest/init.c b/cp/guest/init.c index d3d828f..f5487af 100644 --- a/cp/guest/init.c +++ b/cp/guest/init.c @@ -19,10 +19,16 @@ #include #include #include +#include +#include + +static LOCK_CLASS(online_users_lc); +static LIST_HEAD(online_users); +static UNLOCKED_MUTEX(online_users_lock, &online_users_lc); static LOCK_CLASS(guest_interrupt_queue_lc); -void alloc_guest_devices(struct virt_sys *sys) +static void alloc_guest_devices(struct virt_sys *sys) { struct directory_vdev *cur; int ret; @@ -41,7 +47,7 @@ void alloc_guest_devices(struct virt_sys *sys) } } -int alloc_guest_storage(struct virt_sys *sys) +static int alloc_guest_storage(struct virt_sys *sys) { u64 pages = sys->directory->storage_size >> PAGE_SHIFT; struct page *p; @@ -64,7 +70,7 @@ int alloc_guest_storage(struct virt_sys *sys) return 0; } -int alloc_vcpu(struct virt_sys *sys) +static int alloc_vcpu(struct virt_sys *sys) { struct virt_cpu *cpu; struct page *page; @@ -101,20 +107,137 @@ int alloc_vcpu(struct virt_sys *sys) return 0; } -void free_vcpu(struct virt_sys *sys) +static void free_vcpu(struct virt_sys *sys) { struct virt_cpu *cpu = sys->task->cpu; - BUG_ON(!list_empty(&cpu->int_io[0])); - BUG_ON(!list_empty(&cpu->int_io[1])); - BUG_ON(!list_empty(&cpu->int_io[2])); - BUG_ON(!list_empty(&cpu->int_io[3])); - BUG_ON(!list_empty(&cpu->int_io[4])); - BUG_ON(!list_empty(&cpu->int_io[5])); - BUG_ON(!list_empty(&cpu->int_io[6])); - BUG_ON(!list_empty(&cpu->int_io[7])); + assert(list_empty(&cpu->int_io[0])); + assert(list_empty(&cpu->int_io[1])); + assert(list_empty(&cpu->int_io[2])); + assert(list_empty(&cpu->int_io[3])); + assert(list_empty(&cpu->int_io[4])); + assert(list_empty(&cpu->int_io[5])); + assert(list_empty(&cpu->int_io[6])); + assert(list_empty(&cpu->int_io[7])); free_pages(cpu, 0); sys->task->cpu = NULL; } + +static int alloc_console(struct virt_cons *con) +{ + struct page *page; + int ret; + + con->wlines = alloc_spool(); + if (IS_ERR(con->wlines)) { + ret = PTR_ERR(con->wlines); + goto out; + } + + con->rlines = alloc_spool(); + if (IS_ERR(con->rlines)) { + ret = PTR_ERR(con->rlines); + goto out_free; + } + + page = alloc_pages(0, ZONE_NORMAL); + if (!page) { + ret = -ENOMEM; + goto out_free2; + } + + con->bigbuf = page_to_addr(page); + + return 0; + +out_free2: + free_spool(con->rlines); +out_free: + free_spool(con->wlines); +out: + return ret; +} + +static void free_console(struct virt_cons *con) +{ + free_spool(con->rlines); + free_spool(con->wlines); + free_pages(con->bigbuf, 0); +} + +struct virt_sys *guest_create(char *name, struct device *rcon) +{ + char tname[TASK_NAME_LEN+1]; + struct virt_sys *sys; + int already_online = 0; + int ret; + + /* first, check that we're not already online */ + mutex_lock(&online_users_lock); + list_for_each_entry(sys, &online_users, online_users) { + if (!strcmp(sys->directory->userid, name)) { + already_online = 1; + break; + } + } + mutex_unlock(&online_users_lock); + + if (already_online) + return NULL; + + sys = malloc(sizeof(struct virt_sys), ZONE_NORMAL); + if (!sys) + return NULL; + + sys->con = &sys->console; + if (alloc_console(&sys->console)) + goto free; + + sys->directory = find_user_by_id(name); + if (IS_ERR(sys->directory)) + goto free_cons; + + alloc_guest_devices(sys); + + ret = alloc_guest_storage(sys); + assert(!ret); + + ret = alloc_vcpu(sys); + assert(!ret); + + sys->console.dev = rcon; + + sys->print_ts = 1; /* print timestamps */ + + snprintf(tname, 32, "%s-vcpu0", sysconf.oper_userid); + sys->task = create_task(tname, shell_start, sys); + assert(!IS_ERR(sys->task)); + + mutex_lock(&online_users_lock); + list_add_tail(&sys->online_users, &online_users); + mutex_unlock(&online_users_lock); + + return sys; + +free_cons: + free_console(&sys->console); +free: + free(sys); + return NULL; +} + +void list_users(struct virt_cons *con, void (*f)(struct virt_cons *con, + struct virt_sys *sys)) +{ + struct virt_sys *sys; + + if (!f) + return; + + mutex_lock(&online_users_lock); + list_for_each_entry(sys, &online_users, online_users) + f(con, sys); + mutex_unlock(&online_users_lock); +} diff --git a/cp/guest/ipl.c b/cp/guest/ipl.c new file mode 100644 index 0000000..0314ad3 --- /dev/null +++ b/cp/guest/ipl.c @@ -0,0 +1,183 @@ +/* + * (C) Copyright 2007-2011 Josef 'Jeff' Sipek + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include +#include +#include +#include +#include +#include +#include + +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; + + /* 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); + + 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); + + glen = len; + ret = memcpy_to_guest(gaddr, (void*) zeropage, &glen); + if (ret) + return ret; + BUG_ON(glen != len); + + memlen -= len; + gaddr += len; + } + + return 0; +} + + +int guest_ipl_nss(struct virt_sys *sys, char *nssname) +{ + char fn[8]; + Elf_Ehdr *hdr; + Elf_Phdr *phdr; + struct file *file; + char *buf; + int fmt; + int len; + int ret; + int i; + + len = strnlen(nssname, sizeof(fn)+1); + + if (len > 8) + goto not_found; + + /* munge the system name */ + memcpy(fn, nssname, 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; + } + + assert((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); + + /* FIXME: 31 bits systems aren't supported */ + if (fmt) + goto out; + + /* reset the system */ + guest_load_clear(sys); + + sys->task->cpu->state = GUEST_LOAD; + + for(i=0; is390.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_CHECKSTOP; + return -EIO; + +corrupt: + sys->task->cpu->state = GUEST_CHECKSTOP; + return -ECORRUPT; + +not_found: + sys->task->cpu->state = GUEST_CHECKSTOP; + return -ENOENT; +} diff --git a/cp/guest/objs.cmake b/cp/guest/objs.cmake index c4a8cdf..b690457 100644 --- a/cp/guest/objs.cmake +++ b/cp/guest/objs.cmake @@ -1,2 +1,2 @@ -set(FILES init.c guest.c reset.c intercept.c guest_ipl.s exception.c - instruction.c instruction_priv.c) +set(FILES init.c run.c ipl.c system.c reset.c intercept.c exception.c instruction.c + instruction_priv.c) diff --git a/cp/guest/guest.c b/cp/guest/run.c similarity index 100% rename from cp/guest/guest.c rename to cp/guest/run.c diff --git a/cp/guest/system.c b/cp/guest/system.c new file mode 100644 index 0000000..880c08b --- /dev/null +++ b/cp/guest/system.c @@ -0,0 +1,32 @@ +/* + * (C) Copyright 2007-2011 Josef 'Jeff' Sipek + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include + +int guest_begin(struct virt_sys *sys) +{ + switch(sys->task->cpu->state) { + case GUEST_STOPPED: + case GUEST_OPERATING: + sys->task->cpu->state = GUEST_OPERATING; + return 0; + default: + return -EINVAL; + } +} + +int guest_stop(struct virt_sys *sys) +{ + switch(sys->task->cpu->state) { + case GUEST_STOPPED: + case GUEST_OPERATING: + sys->task->cpu->state = GUEST_STOPPED; + return 0; + default: + return -EINVAL; + } +} diff --git a/cp/include/console.h b/cp/include/console.h index d2facb2..6ad83df 100644 --- a/cp/include/console.h +++ b/cp/include/console.h @@ -14,17 +14,6 @@ #define CONSOLE_LINE_LEN 160 -struct console { - struct list_head consoles; - struct virt_sys *sys; - struct device *dev; - - struct spool_file *wlines; - struct spool_file *rlines; - - u8 *bigbuf; -}; - extern int console_interrupt(struct device *dev, struct irb *irb); extern struct console* start_oper_console(void); extern void* console_enable(struct device *dev); diff --git a/cp/include/device.h b/cp/include/device.h index 1fdfd5e..13d8ec7 100644 --- a/cp/include/device.h +++ b/cp/include/device.h @@ -43,7 +43,8 @@ struct device { struct list_head q_out; atomic_t attention; - atomic_t in_use; /* is the device in use by someone? */ + mutex_t lock; + int in_use; /* is the device in use by someone? */ atomic_t refcnt; /* internal reference counter */ diff --git a/cp/include/guest.h b/cp/include/guest.h new file mode 100644 index 0000000..3098f9c --- /dev/null +++ b/cp/include/guest.h @@ -0,0 +1,17 @@ +#ifndef __GUEST_H +#define __GUEST_H + +#include +#include + +struct virt_sys *guest_create(char *name, struct device *rcon); +int guest_ipl_nss(struct virt_sys *sys, char *nssname); +int guest_begin(struct virt_sys *sys); +int guest_stop(struct virt_sys *sys); + +extern void list_users(struct virt_cons *con, void (*f)(struct virt_cons *con, + struct virt_sys *sys)); + +extern int spool_exec(struct virt_sys *sys, struct virt_device *vdev); + +#endif diff --git a/cp/include/nucleus.h b/cp/include/nucleus.h index 78fc7a0..9d8f759 100644 --- a/cp/include/nucleus.h +++ b/cp/include/nucleus.h @@ -51,17 +51,21 @@ static inline void lpswe(void *psw) if (unlikely(!(cond))) \ BUG(); \ } while(0) +#define assert(cond) do { \ + if (unlikely(!(cond))) \ + BUG(); \ + } while(0) #include /* * stdio.h equivalents */ -struct console; +struct virt_cons; -extern int vprintf(struct console *con, const char *fmt, va_list args) +extern int vprintf(struct virt_cons *con, const char *fmt, va_list args) __attribute__ ((format (printf, 2, 0))); -extern int con_printf(struct console *con, const char *fmt, ...) +extern int con_printf(struct virt_cons *con, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); #endif diff --git a/cp/include/shell.h b/cp/include/shell.h index 96c1800..302ff9a 100644 --- a/cp/include/shell.h +++ b/cp/include/shell.h @@ -20,16 +20,11 @@ */ extern struct console *oper_con; -extern void spawn_oper_shell(struct console *con); -extern void spawn_user_shell(struct console *con, struct user *u); +extern int shell_start(void *data); + extern int invoke_shell_cmd(struct virt_sys *sys, char *cmd, int len); extern int invoke_shell_logon(struct console *con, char *cmd, int len); -extern void list_users(struct console *con, void (*f)(struct console *con, - struct virt_sys *sys)); - -extern int spool_exec(struct virt_sys *sys, struct virt_device *vdev); - #define SHELL_CMD_AUTH(s,a) do { \ if (!((s)->directory->auth & AUTH_##a)) \ return -EPERM; \ diff --git a/cp/include/vcpu.h b/cp/include/vcpu.h index 9ff68ad..585a9a2 100644 --- a/cp/include/vcpu.h +++ b/cp/include/vcpu.h @@ -57,11 +57,22 @@ struct virt_cpu { struct list_head int_io[8]; /* I/O interrupts */ }; +struct virt_cons { + struct device *dev; /* the real device */ + + struct spool_file *wlines; + struct spool_file *rlines; + + u8 *bigbuf; +}; + struct virt_sys { struct task *task; /* the virtual CPU task */ struct user *directory; /* the directory information */ - struct console *con; /* the login console */ + struct virt_cons console; /* the console */ + struct virt_cons *con; /* convenience pointer to the + console struct */ int print_ts; /* print timestamps */ struct list_head guest_pages; /* list of guest pages */ @@ -147,11 +158,6 @@ extern void guest_system_reset_clear(struct virt_sys *sys); extern void guest_load_normal(struct virt_sys *sys); extern void guest_load_clear(struct virt_sys *sys); -extern void alloc_guest_devices(struct virt_sys *sys); -extern int alloc_guest_storage(struct virt_sys *sys); -extern int alloc_vcpu(struct virt_sys *sys); -extern void free_vcpu(struct virt_sys *sys); - extern void run_guest(struct virt_sys *sys); extern void handle_interception(struct virt_sys *sys); diff --git a/cp/include/vdevice.h b/cp/include/vdevice.h index cf7735d..ac435c0 100644 --- a/cp/include/vdevice.h +++ b/cp/include/vdevice.h @@ -13,6 +13,7 @@ #include #include #include +#include /* * VDEV_SPOOL and VDEV_CONS related definitions diff --git a/cp/nucleus/init.c b/cp/nucleus/init.c index 8101acb..7d2060e 100644 --- a/cp/nucleus/init.c +++ b/cp/nucleus/init.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include static struct psw new_io_psw = { @@ -61,7 +61,7 @@ static void init_int_stack(void) struct page *page; page = alloc_pages(0, ZONE_NORMAL); - BUG_ON(!page); + assert(page); int_stack_ptr = PAGE_SIZE + (u8*)page_to_addr(page); } @@ -85,8 +85,9 @@ static void idle_task_body(void) static int __finish_loading(void *data) { - struct console *opcon; /* operator's console */ + struct virt_sys *login; u32 iplsch; + int ret; iplsch = (u32) (u64) data; @@ -98,6 +99,20 @@ static int __finish_loading(void *data) BUG(); /* + * Alright, we have the config, we now need to set up the *LOGIN + * guest and attach the operator console rdev to it + */ + login = guest_create("*LOGIN", NULL); + if (!login) + goto die; + + ret = guest_ipl_nss(login, "login"); + if (ret) + goto die; + + /* FIXME: attach the operator rdev to login */ + + /* * IPL is more or less done */ get_parsed_tod(&ipltime); @@ -106,14 +121,16 @@ static int __finish_loading(void *data) ipltime.th, ipltime.tm, ipltime.ts, ipltime.dy, ipltime.dm, ipltime.dd); - opcon = start_oper_console(); + /* start *LOGIN */ + ret = guest_begin(login); + if (ret) + goto die; - con_printf(opcon, "NOW %02d:%02d:%02d UTC %04d-%02d-%02d\n\n", - ipltime.th, ipltime.tm, ipltime.ts, ipltime.dy, - ipltime.dm, ipltime.dd); - - spawn_oper_shell(opcon); + return 0; +die: + sclp_msg("Failed to initialize '*LOGIN' guest\n"); + BUG(); return 0; } diff --git a/cp/nucleus/printf.c b/cp/nucleus/printf.c index a862c3d..c54234b 100644 --- a/cp/nucleus/printf.c +++ b/cp/nucleus/printf.c @@ -16,14 +16,15 @@ #include #include -int vprintf(struct console *con, const char *fmt, va_list args) +int vprintf(struct virt_cons *con, const char *fmt, va_list args) { + struct virt_sys *sys = container_of(con, struct virt_sys, console); struct datetime dt; char buf[128]; int off = 0; int ret; - if (!con->sys || (con->sys && con->sys->print_ts)) { + if (sys->print_ts) { memset(&dt, 0, sizeof(dt)); ret = get_parsed_tod(&dt); off = snprintf(buf, 128, "%02d:%02d:%02d ", dt.th, dt.tm, @@ -33,13 +34,14 @@ int vprintf(struct console *con, const char *fmt, va_list args) ret = vsnprintf(buf+off, 128-off, fmt, args); if (ret) { ascii2ebcdic((u8 *) buf, off+ret); - con_write(con, (u8 *) buf, off+ret); + BUG(); + //con_write(con, (u8 *) buf, off+ret); } return ret; } -int con_printf(struct console *con, const char *fmt, ...) +int con_printf(struct virt_cons *con, const char *fmt, ...) { va_list args; int r; diff --git a/cp/shell/cmd_beginstop.c b/cp/shell/cmd_beginstop.c index 0c5d4db..fa2797b 100644 --- a/cp/shell/cmd_beginstop.c +++ b/cp/shell/cmd_beginstop.c @@ -18,8 +18,7 @@ static int cmd_begin(struct virt_sys *sys, char *cmd, int len) { SHELL_CMD_AUTH(sys, G); - sys->task->cpu->state = GUEST_OPERATING; - return 0; + return guest_begin(sys); } /* @@ -35,6 +34,5 @@ static int cmd_stop(struct virt_sys *sys, char *cmd, int len) { SHELL_CMD_AUTH(sys, G); - sys->task->cpu->state = GUEST_STOPPED; - return 0; + return guest_stop(sys); } diff --git a/cp/shell/cmd_display.c b/cp/shell/cmd_display.c index 52ae4f2..7d1ebfd 100644 --- a/cp/shell/cmd_display.c +++ b/cp/shell/cmd_display.c @@ -563,7 +563,7 @@ static int cmd_display_psw(struct virt_sys *sys, char *cmd, int len) return 0; } -static void __do_display_schib(struct console *con, struct virt_device *vdev) +static void __do_display_schib(struct virt_cons *con, struct virt_device *vdev) { con_printf(con, "%05X %04X %08X %d %02X %02X %02X %02X %02X " "---- %02X %02X %02X%02X%02X%02X %02X%02X%02X%02X\n", diff --git a/cp/shell/cmd_enable.c b/cp/shell/cmd_enable.c index 91f370c..a46f4a9 100644 --- a/cp/shell/cmd_enable.c +++ b/cp/shell/cmd_enable.c @@ -42,23 +42,31 @@ static int cmd_enable(struct virt_sys *sys, char *cmd, int len) return 0; } - if (atomic_read(&dev->in_use)) { + mutex_lock(&dev->lock); + + if (dev->in_use) { con_printf(sys->con, "Device %04llX is already in use\n", devnum); - dev_put(dev); - return 0; + goto out_err; } if (!dev->dev->enable) { con_printf(sys->con, "Device type %-4s cannot be enabled\n", type2name(dev->type)); - return 0; + goto out_err; } con = dev->dev->enable(dev); if (IS_ERR(con)) { - con_printf(sys->con, "Failed to enable %04llX\n", devnum); - return PTR_ERR(con); + con_printf(sys->con, "Failed to enable %04llX: %s\n", + devnum, errstrings[-PTR_ERR(con)]); + goto out_err; } + mutex_unlock(&dev->lock); + return 0; + +out_err: + mutex_unlock(&dev->lock); + dev_put(dev); return 0; } diff --git a/cp/shell/cmd_logon.c b/cp/shell/cmd_logon.c index 84d98fd..1345564 100644 --- a/cp/shell/cmd_logon.c +++ b/cp/shell/cmd_logon.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2007-2010 Josef 'Jeff' Sipek + * (C) Copyright 2007-2011 Josef 'Jeff' Sipek * * This file is released under the GPLv2. See the COPYING file for more * details. @@ -14,23 +14,6 @@ *!! PURPOSE *! Log on to a virtual machine. */ -static int cmd_logon(struct virt_sys *data, char *cmd, int len) -{ - struct console *con = (struct console*) data; /* BEWARE */ - struct user *u; - - u = find_user_by_id(cmd); - if (IS_ERR(u)) { - con_printf(con, "INVALID USERID\n"); - return 0; - } - - spawn_user_shell(con, u); - con_printf(oper_con, "%s %04X LOGON AS %-8s\n", - type2name(con->dev->type), con->dev->ccuu, u->userid); - - return 0; -} static int cmd_logon_fail(struct virt_sys *sys, char *cmd, int len) { diff --git a/cp/shell/cmd_query.c b/cp/shell/cmd_query.c index 803ccea..7ad2bde 100644 --- a/cp/shell/cmd_query.c +++ b/cp/shell/cmd_query.c @@ -19,22 +19,28 @@ static char *__guest_state_to_str(enum virt_cpustate st) static void display_rdev(struct device *dev, void *priv) { - struct console *con = priv; + struct virt_cons *con = priv; char buf[40]; buf[0] = '\0'; + mutex_lock(&dev->lock); + if (dev->dev && dev->dev->snprintf) dev->dev->snprintf(dev, buf, 40); con_printf(con, "%-4s %04X %04X %s%sSCH = %05X\n", type2name(dev->type), dev->ccuu, dev->type, buf, - atomic_read(&dev->in_use) ? "" : "FREE ", + dev->in_use ? "" : "FREE ", dev->sch); + + mutex_unlock(&dev->lock); } -static void display_vdev(struct console *con, struct virt_device *vdev) +static void display_vdev(struct virt_cons *con, struct virt_device *vdev) { + struct virt_sys *sys = container_of(con, struct virt_sys, console); + mutex_lock(&vdev->lock); switch (vdev->vtype) { @@ -43,7 +49,7 @@ static void display_vdev(struct console *con, struct virt_device *vdev) vdev->pmcw.dev_num, type2name(con->dev->type), // FIXME? con->dev->ccuu, - con->sys->print_ts ? "TS" : "NOTS", + sys->print_ts ? "TS" : "NOTS", vdev->sch); break; case VDEV_DED: @@ -85,7 +91,7 @@ static void display_vdev(struct console *con, struct virt_device *vdev) static void display_task(struct task *task, void *priv) { - struct console *con = priv; + struct virt_cons *con = priv; char state; switch(task->state) { @@ -299,7 +305,7 @@ static int cmd_query_task(struct virt_sys *sys, char *cmd, int len) return 0; } -static void display_names(struct console *con, struct virt_sys *sys) +static void display_names(struct virt_cons *con, struct virt_sys *sys) { con_printf(con, "%s %04X %-8s\n", type2name(sys->con->dev->type), sys->con->dev->ccuu, sys->directory->userid); diff --git a/cp/shell/cmd_system.c b/cp/shell/cmd_system.c dissimilarity index 71% index bc31828..ac9eedc 100644 --- a/cp/shell/cmd_system.c +++ b/cp/shell/cmd_system.c @@ -1,355 +1,118 @@ -/* - * (C) Copyright 2007-2011 Josef 'Jeff' Sipek - * - * This file is released under the GPLv2. See the COPYING file for more - * details. - */ - -#include -#include -#include -#include - -extern u32 GUEST_IPL_CODE[]; -extern u32 GUEST_IPL_REGSAVE[]; - -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) -{ - 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; - } - - /* reset the system */ - guest_load_clear(sys); - - sys->task->cpu->state = GUEST_LOAD; - - for(i=0; is390.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; - - /* - * alright, we got the device... now set up IPL helper - */ - - bytes = sizeof(u32)*(GUEST_IPL_REGSAVE-GUEST_IPL_CODE); - - con_printf(sys->con, "WARNING: IPLDEV command is work-in-progress\n"); - - /* - * FIXME: this should be conditional based whether or not we were - * told to clear - */ - guest_load_normal(sys); - - sys->task->cpu->state = GUEST_LOAD; - - ret = virt2phy_current(GUEST_IPL_BASE, &host_addr); - if (ret) - goto fail; - - /* we can't go over a page! */ - BUG_ON((bytes+(16*32)) > PAGE_SIZE); - - /* copy the helper into the guest storage */ - memcpy((void*) host_addr, GUEST_IPL_CODE, bytes); - - /* save the current guest regs */ - for (i=0; i<16; i++) { - u32 *ptr = (u32*) ((u8*) host_addr + bytes); - - ptr[i] = (u32) sys->task->cpu->regs.gpr[i]; - } - - sys->task->cpu->regs.gpr[1] = vdev->sch; - sys->task->cpu->regs.gpr[2] = vdev->pmcw.dev_num; - sys->task->cpu->regs.gpr[12] = GUEST_IPL_BASE; - - *((u64*) &sys->task->cpu->sie_cb.gpsw) = 0x0008000080000000ULL | - GUEST_IPL_BASE; - - sys->task->cpu->state = GUEST_STOPPED; - - con_printf(sys->con, "GUEST IPL HELPER LOADED; ENTERED STOPPED STATE\n"); - - return 0; - -fail: - sys->task->cpu->state = GUEST_STOPPED; - return ret; -} - -/* - *!!! IPL - *!! SYNTAX - *! \tok{\sc IPL} - *!! 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; - - SHELL_CMD_AUTH(sys, G); - - /* 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 */ - - for_each_vdev(sys, vdev) - 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} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Identical to reset-clear button on a real mainframe. - * - *!!! SYSTEM RESET - *!p >>--SYSTEM--RESET------------------------------------------------------------->< - *!! SYNTAX - *! \tok{\sc SYStem} \tok{\sc RESET} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Identical to reset-normal button on a real mainframe. - * - *!!! SYSTEM RESTART - *!! SYNTAX - *! \tok{\sc SYStem} \tok{\sc RESTART} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Perform a restart operation. - *!! NOTES - *! \item Not yet implemented. - *!! SETON - * - *!!! SYSTEM STORE - *!! SYNTAX - *! \tok{\sc SYStem} \tok{\sc STORE} - *!! XATNYS - *!! AUTH G - *!! PURPOSE - *! Perform a ... - *!! NOTES - *! \item Not yet implemented. - *!! SETON - */ -static int cmd_system(struct virt_sys *sys, char *cmd, int len) -{ - SHELL_CMD_AUTH(sys, G); - - if (!strcasecmp(cmd, "CLEAR")) { - guest_system_reset_clear(sys); - con_printf(sys->con, "STORAGE CLEARED - SYSTEM RESET\n"); - } else if (!strcasecmp(cmd, "RESET")) { - guest_system_reset_normal(sys); - con_printf(sys->con, "SYSTEM RESET\n"); - } else if (!strcasecmp(cmd, "RESTART")) { - con_printf(sys->con, "SYSTEM RESTART is not yet supported\n"); - } else if (!strcasecmp(cmd, "STORE")) { - con_printf(sys->con, "SYSTEM STORE is not yet supported\n"); - } else - con_printf(sys->con, "SYSTEM: Unknown variable '%s'\n", cmd); - - return 0; -} +/* + * (C) Copyright 2007-2011 Josef 'Jeff' Sipek + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include +#include +#include +#include + +/* + *!!! IPL + *!! SYNTAX + *! \tok{\sc IPL} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Perform a ... + *!! NOTES + *! \item Not yet implemented. + *!! SETON + */ +static int cmd_ipl(struct virt_sys *sys, char *cmd, int len) +{ + u64 vdevnum = 0; + char *c; + + SHELL_CMD_AUTH(sys, G); + + /* 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 */ + +#if 0 + for_each_vdev(sys, vdev) + if (vdev->pmcw.dev_num == (u16) vdevnum) { + ret = guest_ipl_nss(sys, "ipldev"); + if (ret) + return ret; + + assert(0); + + return -EINVAL; + } +#endif + +nss: + /* device not found */ + return guest_ipl_nss(sys, cmd); +} + +/*!!! SYSTEM CLEAR + *!! SYNTAX + *! \tok{\sc SYStem} \tok{\sc CLEAR} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Identical to reset-clear button on a real mainframe. + * + *!!! SYSTEM RESET + *!p >>--SYSTEM--RESET------------------------------------------------------------->< + *!! SYNTAX + *! \tok{\sc SYStem} \tok{\sc RESET} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Identical to reset-normal button on a real mainframe. + * + *!!! SYSTEM RESTART + *!! SYNTAX + *! \tok{\sc SYStem} \tok{\sc RESTART} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Perform a restart operation. + *!! NOTES + *! \item Not yet implemented. + *!! SETON + * + *!!! SYSTEM STORE + *!! SYNTAX + *! \tok{\sc SYStem} \tok{\sc STORE} + *!! XATNYS + *!! AUTH G + *!! PURPOSE + *! Perform a ... + *!! NOTES + *! \item Not yet implemented. + *!! SETON + */ +static int cmd_system(struct virt_sys *sys, char *cmd, int len) +{ + SHELL_CMD_AUTH(sys, G); + + if (!strcasecmp(cmd, "CLEAR")) { + guest_system_reset_clear(sys); + con_printf(sys->con, "STORAGE CLEARED - SYSTEM RESET\n"); + } else if (!strcasecmp(cmd, "RESET")) { + guest_system_reset_normal(sys); + con_printf(sys->con, "SYSTEM RESET\n"); + } else if (!strcasecmp(cmd, "RESTART")) { + con_printf(sys->con, "SYSTEM RESTART is not yet supported\n"); + } else if (!strcasecmp(cmd, "STORE")) { + con_printf(sys->con, "SYSTEM STORE is not yet supported\n"); + } else + con_printf(sys->con, "SYSTEM: Unknown variable '%s'\n", cmd); + + return 0; +} diff --git a/cp/shell/cmds.c b/cp/shell/cmds.c index 2cda853..d3a24d7 100644 --- a/cp/shell/cmds.c +++ b/cp/shell/cmds.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include struct cpcmd { const char name[SHELL_CMD_MAX_LEN]; @@ -58,14 +60,15 @@ static char* type2name(u16 type) * handler functions */ #include "cmd_helpers.c" + #include "cmd_beginstop.c" #include "cmd_display.c" #include "cmd_enable.c" -#include "cmd_system.c" -#include "cmd_query.c" -#include "cmd_store.c" #include "cmd_logon.c" +#include "cmd_query.c" #include "cmd_set.c" +#include "cmd_store.c" +#include "cmd_system.c" static struct cpcmd commands[] = { {"BEGIN", cmd_begin, NULL}, @@ -119,17 +122,6 @@ static struct cpcmd commands[] = { {"", NULL, NULL}, }; -static struct cpcmd logon_commands[] = { - {"LOGIN", cmd_logon, NULL}, - {"LOGON", cmd_logon, NULL}, - {"LOGI", cmd_logon, NULL}, - {"LOGO", cmd_logon, NULL}, - {"LOG", cmd_logon, NULL}, - {"LO", cmd_logon, NULL}, - {"L", cmd_logon, NULL}, - {"", NULL, NULL}, -}; - static int __invoke_shell_cmd(struct cpcmd *t, struct virt_sys *sys, char *cmd, int len) { char *orig = cmd; @@ -160,8 +152,3 @@ int invoke_shell_cmd(struct virt_sys *sys, char *cmd, int len) { return __invoke_shell_cmd(commands, sys, cmd, len); } - -int invoke_shell_logon(struct console *con, char *cmd, int len) -{ - return __invoke_shell_cmd(logon_commands, (struct virt_sys*) con, cmd, len); -} diff --git a/cp/shell/init.c b/cp/shell/init.c dissimilarity index 63% index 74c7614..14db0bd 100644 --- a/cp/shell/init.c +++ b/cp/shell/init.c @@ -1,290 +1,110 @@ -/* - * (C) Copyright 2007-2011 Josef 'Jeff' Sipek - * - * This file is released under the GPLv2. See the COPYING file for more - * details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* This is used to con_printf to the operator about various async events - - * e.g., user logon - */ -struct console *oper_con; - -static LOCK_CLASS(online_users_lc); -static LIST_HEAD(online_users); -static UNLOCKED_MUTEX(online_users_lock, &online_users_lc); - -static void process_logon_cmd(struct console *con) -{ - u8 cmd[128]; - int ret; - - ret = con_read(con, cmd, 128); - - if (ret == -1) - return; /* no lines to read */ - - if (!ret) - return; /* empty line */ - - ebcdic2ascii(cmd, ret); - - /* - * we got a command to process! - */ - - ret = invoke_shell_logon(con, (char*) cmd, ret); - if (!ret) - return; - - con_printf(con, "NOT LOGGED ON\n"); -} - -static void process_cmd(struct virt_sys *sys) -{ - u8 cmd[128]; - int ret; - - ret = con_read(sys->con, cmd, 128); - - if (ret == -1) - return; /* no lines to read */ - - if (!ret) { - con_printf(sys->con, "CP\n"); - return; /* empty line */ - } - - ebcdic2ascii(cmd, ret); - - /* - * we got a command to process! - */ - ret = invoke_shell_cmd(sys, (char*) cmd, ret); - switch (ret) { - case 0: - /* all fine */ - break; - case -ENOENT: - con_printf(sys->con, "Invalid CP command: %s\n", cmd); - break; - case -ESUBENOENT: - con_printf(sys->con, "Invalid CP sub-command: %s\n", cmd); - break; - case -EINVAL: - con_printf(sys->con, "Operand missing or invalid\n"); - break; - case -EPERM: - con_printf(sys->con, "Not authorized\n"); - break; - default: - con_printf(sys->con, "RC=%d (%s)\n", ret, - errstrings[ret]); - break; - } -} - -static int shell_init(void *data) -{ - struct virt_sys *sys = data; - struct virt_cpu *cpu; - struct datetime dt; - int ret; - - ret = alloc_vcpu(sys); - if (ret) { - con_printf(sys->con, "Failed to allocate virtual CPU: %d (%s)\n", - ret, errstrings[-ret]); - goto out; - } - - cpu = sys->task->cpu; - - ret = alloc_guest_storage(sys); - if (ret) { - con_printf(sys->con, "Failed to allocate guest storage: %d (%s)\n", - ret, errstrings[-ret]); - goto out_free; - } - - alloc_guest_devices(sys); - - /* - * load guest's address space into the host's PASCE - */ - load_as(&sys->as); - - guest_power_on_reset(sys); - - get_parsed_tod(&dt); - con_printf(sys->con, "LOGON FOR %s AT %02d:%02d:%02d UTC %04d-%02d-%02d\n", - sys->directory->userid, dt.th, dt.tm, dt.ts, dt.dy, dt.dm, dt.dd); - - for (;;) { - /* - * - process any console input - * - if the guest is running - * - issue any pending interruptions - * - continue executing it - * - process any intercepts from SIE - * - else, schedule() - */ - - process_cmd(sys); - - if (cpu->state == GUEST_OPERATING) - run_guest(sys); - else - schedule(); - } - -out_free: - free_vcpu(sys); -out: - return 0; -} - -static void __con_attn(struct console *con) -{ - if (con->sys) { - /* There's already a user on this console */ - - if (!con->sys->task->cpu || - con->sys->task->cpu->state == GUEST_STOPPED) - return; - - if (!con_read_pending(con)) - return; - - /* - * There's a read pending. Generate an interception. - */ - atomic_set_mask(CPUSTAT_STOP_INT, &con->sys->task->cpu->sie_cb.cpuflags); - } else { - if (!con_read_pending(con)) - return; - - /* - * There's a read pending. MUST be a command - */ - process_logon_cmd(con); - } -} - -static int shell_con_attn(void *data) -{ - for(;;) { - schedule(); - - for_each_console(__con_attn); - } - - return 0; -} - -void spawn_oper_shell(struct console *con) -{ - struct virt_sys *sys; - char tn[32]; - - oper_con = con; - - sys = malloc(sizeof(struct virt_sys), ZONE_NORMAL); - BUG_ON(!sys); - - sys->con = con; - con->sys = sys; - - sys->directory = find_user_by_id(sysconf.oper_userid); - BUG_ON(IS_ERR(sys->directory)); - - sys->print_ts = 1; /* print timestamps */ - - snprintf(tn, 32, "%s-vcpu0", sysconf.oper_userid); - sys->task = create_task(tn, shell_init, sys); - BUG_ON(IS_ERR(sys->task)); - - BUG_ON(IS_ERR(create_task("console-attn", shell_con_attn, NULL))); - - mutex_lock(&online_users_lock); - list_add_tail(&sys->online_users, &online_users); - mutex_unlock(&online_users_lock); -} - -void spawn_user_shell(struct console *con, struct user *u) -{ - char tname[TASK_NAME_LEN+1]; - struct virt_sys *sys; - int already_online = 0; - - mutex_lock(&online_users_lock); - list_for_each_entry(sys, &online_users, online_users) { - if (sys->directory == u) { - already_online = 1; - break; - } - } - mutex_unlock(&online_users_lock); - - if (already_online) { - con_printf(con, "ALREADY LOGGED ON\n"); - return; - } - - sys = malloc(sizeof(struct virt_sys), ZONE_NORMAL); - if (!sys) - goto err; - - sys->con = con; - con->sys = sys; - - sys->directory = u; - - sys->print_ts = 1; /* print timestamps */ - - snprintf(tname, TASK_NAME_LEN, "%s-vcpu0", u->userid); - sys->task = create_task(tname, shell_init, sys); - if (IS_ERR(sys->task)) - goto err_free; - - mutex_lock(&online_users_lock); - list_add_tail(&sys->online_users, &online_users); - mutex_unlock(&online_users_lock); - return; - -err_free: - free(sys); - con->sys = NULL; -err: - con_printf(con, "INTERNAL ERROR DURING LOGON\n"); -} - -void list_users(struct console *con, void (*f)(struct console *con, - struct virt_sys *sys)) -{ - struct virt_sys *sys; - - if (!f) - return; - - mutex_lock(&online_users_lock); - list_for_each_entry(sys, &online_users, online_users) - f(con, sys); - mutex_unlock(&online_users_lock); -} +/* + * (C) Copyright 2007-2011 Josef 'Jeff' Sipek + * + * This file is released under the GPLv2. See the COPYING file for more + * details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* This is used to con_printf to the operator about various async events - + * e.g., user logon + */ +struct console *oper_con; + +static void process_cmd(struct virt_sys *sys) +{ + u8 cmd[128]; + int ret; + + // FIXME: read a line from the + // ret = con_read(sys->con, cmd, 128); + ret = -1; + + if (ret == -1) + return; /* no lines to read */ + + if (!ret) { + con_printf(sys->con, "CP\n"); + return; /* empty line */ + } + + ebcdic2ascii(cmd, ret); + + /* + * we got a command to process! + */ + ret = invoke_shell_cmd(sys, (char*) cmd, ret); + switch (ret) { + case 0: + /* all fine */ + break; + case -ENOENT: + con_printf(sys->con, "Invalid CP command: %s\n", cmd); + break; + case -ESUBENOENT: + con_printf(sys->con, "Invalid CP sub-command: %s\n", cmd); + break; + case -EINVAL: + con_printf(sys->con, "Operand missing or invalid\n"); + break; + case -EPERM: + con_printf(sys->con, "Not authorized\n"); + break; + default: + con_printf(sys->con, "RC=%d (%s)\n", ret, + errstrings[ret]); + break; + } +} + +int shell_start(void *data) +{ + struct virt_sys *sys = data; + struct virt_cpu *cpu = sys->task->cpu; + struct datetime dt; + + /* + * load guest's address space into the host's PASCE + */ + load_as(&sys->as); + + get_parsed_tod(&dt); + con_printf(sys->con, "LOGON FOR %s AT %02d:%02d:%02d UTC %04d-%02d-%02d\n", + sys->directory->userid, dt.th, dt.tm, dt.ts, dt.dy, dt.dm, dt.dd); + + for (;;) { + /* + * - process any console input + * - if the guest is running + * - issue any pending interruptions + * - continue executing it + * - process any intercepts from SIE + * - else, schedule() + */ + + process_cmd(sys); + + if (cpu->state == GUEST_OPERATING) + run_guest(sys); + else + schedule(); + } + + return 0; +} + diff --git a/include/errno.h b/include/errno.h index 45596ab..73481d5 100644 --- a/include/errno.h +++ b/include/errno.h @@ -20,6 +20,7 @@ #define EFAULT 9 #define EPERM 10 #define ECORRUPT 11 +#define EIO 12 #define PTR_ERR(ptr) ((s64) ptr) #define ERR_PTR(err) ((void*) (long) err) diff --git a/lib/errno.c b/lib/errno.c index b83b583..64cb1dc 100644 --- a/lib/errno.c +++ b/lib/errno.c @@ -13,4 +13,5 @@ char *errstrings[] = { [EFAULT] = "Invalid memory reference", [EPERM] = "Permission denied", [ECORRUPT] = "Curruption detected", + [EIO] = "I/O error", }; diff --git a/nss/CMakeLists.txt b/nss/CMakeLists.txt index 5001649..cefd67e 100644 --- a/nss/CMakeLists.txt +++ b/nss/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(8ball) +add_subdirectory(ipldev) diff --git a/nss/ipldev/.gitignore b/nss/ipldev/.gitignore new file mode 100644 index 0000000..4f45c3e --- /dev/null +++ b/nss/ipldev/.gitignore @@ -0,0 +1 @@ +ipldev diff --git a/nss/ipldev/CMakeLists.txt b/nss/ipldev/CMakeLists.txt new file mode 100644 index 0000000..2ead775 --- /dev/null +++ b/nss/ipldev/CMakeLists.txt @@ -0,0 +1,4 @@ +set(CMAKE_EXE_LINKER_FLAGS "-melf_s390 -T ${CMAKE_CURRENT_SOURCE_DIR}/linker.script") +set(CMAKE_ASM-ATT_FLAGS "-m31") + +add_executable(ipldev guest.s) diff --git a/cp/guest/guest_ipl.s b/nss/ipldev/guest.s similarity index 100% rename from cp/guest/guest_ipl.s rename to nss/ipldev/guest.s diff --git a/nss/ipldev/linker.script b/nss/ipldev/linker.script new file mode 100644 index 0000000..3174864 --- /dev/null +++ b/nss/ipldev/linker.script @@ -0,0 +1,8 @@ +SECTIONS +{ + ENTRY(START) + . = 0x0; + .text : { *(.text) } + .data : { *(.data) } + .bss : { *(.bss) } +} -- 2.11.4.GIT